QuakeGod
2022-01-16 326d3e312c74726814c39c9d112faab03c4a167c
提交 | 用户 | age
4b03ae 1 #pragma once
Q 2 /*
3 *    
4 *    串口通讯头文件
5 *
6 * Version: V1.01
7 * Date: 2015-06-30
8 * Description: 
9 *  2015-07-10  Add Speed Function;
10 *  2015-07-24  优化速度计算,每1秒一次改为每半秒一次
11 */
12 inline double GetTimeMs()
13 {
14     LARGE_INTEGER perfreq;
15     LARGE_INTEGER percounter1;
16     QueryPerformanceFrequency(&perfreq);
17     QueryPerformanceCounter(&percounter1);
18
19     double time1=(double)percounter1.QuadPart/perfreq.QuadPart;
20     return (time1*1000);
21 };
22
23 class CSerialCom
24 {
25 public:
26     enum Results {
27         R_OK,
28         R_ERR,
29     };
30     HANDLE hCom1;
31     int IsOpened;
32
33     int Port;
34     int BaudRate;
35     CString Settings;
36     
37     DWORD dwError;
38     CString strResult;
39     int m_nCountToTry = 2;
40     int m_nCountToWait = 0;
41
42     volatile    DWORD TotalSendBytes,TotalRecvBytes;
43     volatile    DWORD SendBytes,RecvBytes;
44     volatile    DWORD LastSendBytes,LastRecvBytes;
45     volatile     DWORD SendSpeed,RecvSpeed;
46     volatile    double LastTime;
47     CSerialCom(void)
48     {
49         this->hCom1=INVALID_HANDLE_VALUE;
50         this->IsOpened=0;
51
52         this->Port=0;
53         this->BaudRate=0;
54         this->Settings.Empty();
55
56         this->dwError=0;
57     };
58     ~CSerialCom(void)
59     {
60         if (this->IsOpened) {this->Close();}
61         this->hCom1=INVALID_HANDLE_VALUE;
62     };
63
64     int Open()
65     {
66         int j;
67         CString s1,s2;
68         CString ComPortName;
69         if (this->Port==0) {return 0;}
70         if (this->IsOpened) {return -1;}
71         ComPortName.Format(_T("\\\\.\\COM%d"),this->Port);
72         hCom1=CreateFile(ComPortName,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);//FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED
73         if (hCom1==INVALID_HANDLE_VALUE)
74         {
75             dwError=GetLastError();
76             IsOpened=false;
77             FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,dwError,0,s1.GetBuffer(2048),2048,NULL);
78             s1.ReleaseBuffer();
79
80             strResult.Format(_T("Open COM%d Err %d ,%s "),this->Port,this->dwError,s1);
81             return 0;
82         }
83         else
84         {
85             dwError=GetLastError();
86
87             strResult.Format(_T("COM%d OK."),this->Port);
88             LastTime = GetTimeMs();
89             TotalSendBytes = 0; TotalRecvBytes = 0;
90             LastSendBytes = 0; SendBytes = 0; RecvBytes = 0;
91             LastRecvBytes = 0; SendSpeed = 0; RecvSpeed = 0;
92         }
93
94         j=SetupComm(hCom1,256,256);
95
96         DCB dcb1;
97         j=GetCommState(hCom1,&dcb1);
98         BuildCommDCB(Settings,&dcb1);
99
100         dcb1.BaudRate=BaudRate;
101
102         if (Settings.Find(_T("8")) != -1)        {    dcb1.ByteSize = 8; }
103         else if (Settings.Find(_T("7")) != -1)     {    dcb1.ByteSize = 8; }
104         else if (Settings.Find(_T("6")) != -1)     {    dcb1.ByteSize = 8; }
105         else if (Settings.Find(_T("5")) != -1)     {    dcb1.ByteSize = 8; }
106
107         if (Settings.Find(_T("N")) != -1)         {    dcb1.fParity = FALSE;    dcb1.Parity = NOPARITY;}
108         else if (Settings.Find(_T("O")) != -1)     {    dcb1.fParity = TRUE;    dcb1.Parity = ODDPARITY;}
109         else if (Settings.Find(_T("E")) != -1)     {    dcb1.fParity = TRUE;    dcb1.Parity = EVENPARITY;}
110         else if (Settings.Find(_T("M")) != -1)     {    dcb1.fParity = TRUE;    dcb1.Parity = MARKPARITY;}
111         else if (Settings.Find(_T("S")) != -1)     {    dcb1.fParity = TRUE;    dcb1.Parity = SPACEPARITY;}
112
113         if (Settings.Find(_T("1.5")) != -1)        {    dcb1.StopBits = ONE5STOPBITS;}
114         else if (Settings.Find(_T("1")) != -1)     {    dcb1.StopBits = ONESTOPBIT; }
115         else if (Settings.Find(_T("2")) != -1)     {    dcb1.StopBits = TWOSTOPBITS; }
116
117         dcb1.fDtrControl=0;
118         dcb1.fDsrSensitivity=false;
119         dcb1.fBinary=1;
120         dcb1.fOutxCtsFlow=false;
121         dcb1.fOutxDsrFlow=false;
122         dcb1.fRtsControl=RTS_CONTROL_DISABLE;
123
124         j=SetCommState(hCom1,&dcb1);
125         if (j == 0)
126         {
127             strResult.Format(_T("SetCommState Fail  %d %s \r\n"),BaudRate,Settings);
128             CloseHandle(hCom1);
129             IsOpened = false;
130             return 0;
131         }
132         j=GetCommState(hCom1,&dcb1);
133
134         CString strParity;
135         CString strStopBit;
136
137         if (dcb1.Parity == NOPARITY)            {    strParity = _T("N");    }
138         else if (dcb1.Parity == EVENPARITY)        {    strParity = _T("E");    }
139         else if (dcb1.Parity == ODDPARITY)        {    strParity = _T("O");    }
140         else if (dcb1.Parity == MARKPARITY)        {    strParity = _T("M");    }
141         else if (dcb1.Parity == SPACEPARITY)    {    strParity = _T("S");    }
142         else                                    {    strParity = _T("X");    }
143
144         if (dcb1.StopBits == ONESTOPBIT)        {    strStopBit = _T("1");    }
145         else if (dcb1.StopBits == ONE5STOPBITS)    {    strStopBit = _T("1.5");    }
146         else if (dcb1.StopBits == TWOSTOPBITS)    {    strStopBit = _T("2");    }
147         else                                    {    strStopBit = _T("3");    }
148
149         s1.Format(_T("%d %d-%s-%s"), dcb1.BaudRate,dcb1.ByteSize, strParity, strStopBit);
150         strResult += s1;
151
152         COMMTIMEOUTS comtimeout1;
153         COMSTAT comstat1;
154         GetCommTimeouts(hCom1,&comtimeout1);
155
156         comtimeout1.ReadIntervalTimeout=1;    //两个字符之间的时间
157         comtimeout1.ReadTotalTimeoutMultiplier=0;    //每个字符等待的时间,读多个字符则等待时间为单个时间乘以字符个数
158         comtimeout1.ReadTotalTimeoutConstant=1;        //读取时,再另外多等待的时间。
159         comtimeout1.WriteTotalTimeoutMultiplier=0;    //写入时,每个字符等待的时间,写入多个字符则等待时间为单个时间乘以字符个数。
160         comtimeout1.WriteTotalTimeoutConstant=0;    //写入时,再另外多等待的时间。
161
162         SetCommTimeouts(hCom1,&comtimeout1);
163         j=ClearCommError(hCom1,&dwError,&comstat1);
164         s1.Format(_T("ClearCommError  j %d  errors %d "),j,dwError);
165         s2=s1;
166         s1.Format(_T("cbInQue %d "),comstat1.cbInQue);
167         s2+=s1;
168         s1.Format(_T("cbOutQue %d "),comstat1.cbOutQue );
169         s2+=s1;
170
171         PurgeComm(hCom1,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_TXCLEAR);
172
173         IsOpened = true;
174         return 1;
175     };
176     int Purge()
177     {
178         return    PurgeComm(hCom1,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_TXCLEAR);
179     }
180     void Close()
181     {
182         LastSendBytes=0;
183         LastRecvBytes=0;
184         SendBytes=0;
185         RecvBytes=0;
186         SendSpeed=0;
187         RecvSpeed=0;
188
189         if (IsOpened)
190         {
191             IsOpened=false;
192             CString s1;
193             strResult.Format(_T("Close COM %d "),this->Port);
194             CloseHandle(hCom1);
195         }
196     };
197     int CSerialCom::CalSpeed()
198     {
199         double thistime = GetTimeMs();
200         double diftime = thistime - LastTime;
201         if (diftime >= 500)
202         {
203             SendSpeed = (DWORD)(SendBytes * 1000 / diftime);
204             RecvSpeed = static_cast<DWORD> (RecvBytes * 1000 / diftime);
205             LastSendBytes = SendBytes; SendBytes = 0;
206             LastRecvBytes = RecvBytes; RecvBytes = 0;
207             LastTime = thistime;
208         }
209         return 0;
210     }
211     int CSerialCom::Send(const char * buffer, int n)
212     {
213         CString s1;
214         int i,j;
215         DWORD numsent;
216
217         if (!IsOpened) {return 0;}
218
219         j=WriteFile(hCom1,buffer,n,&numsent,NULL);
220
221         if (j!=0)
222         {
223             strResult.Format(_T("Send To COM%d OK %dB : "),this->Port,numsent);
224             for (i=0;(unsigned )i<numsent;i++)
225             {
226                 strResult.AppendFormat(_T("%c"),buffer[i]);
227             }
228             strResult.AppendFormat(_T("\r\n"));
229         }
230         else
231         {
232             dwError=GetLastError();
233             strResult.Format(_T("Send To COM%d fail. Error:%d  SentBytes:%d "),this->Port,dwError,numsent);
234         }
235         SendBytes+=numsent;
236         TotalSendBytes+=numsent;
237         return numsent;
238     };
239     int CSerialCom::Read(char * buffer, int numToRead)
240     {
241         CString s1;
242         int i,j;
243         DWORD numreaded;
244         if (!IsOpened) {return 0;}
245         int len2=0;
246         //Sleep(n/10);
247         int nTryCount2 = 0;
248         for (int i = 0; i < m_nCountToTry; i++)
249         {
250             j = ReadFile(hCom1, buffer+len2, numToRead-len2, &numreaded, NULL);
251             if (j != 0){
252                 len2 += numreaded;
253                 buffer[len2] = 0;
254                 if (len2 >= numToRead) break;
255                 nTryCount2 = 0;
256             }
257             else{
258                 if (len2 > 0) {
259                     nTryCount2++;
260                     if (nTryCount2 >= m_nCountToWait) break;
261                 }
262             }
263             if (len2 > 0 && nTryCount2 >= m_nCountToWait) break;
264         }
265         numreaded = len2;
266         if (numreaded > 0){
267             strResult.Format(_T("Read From COM%d OK %dB "), this->Port, numreaded);
268             for (i = 0; (unsigned)i < numreaded; i++)
269             {
270                 strResult.AppendFormat(_T("%c"), buffer[i]);
271             }
272             strResult.AppendFormat(_T("\r\n"));
273         }
274         else{
275             strResult.Format(_T("Read From COM failed \r\n"));
276         }
277
278         RecvBytes+=numreaded;
279         TotalRecvBytes+=numreaded;
280
281         return numreaded;
282     };
283 };
284 /*
285 与以往DOS下串行通信程序不同的是,Windows不提倡应用程序直接控制硬件,而是通过Windows操作系统提供的设备驱动程序来进行数据传递。
286 串行口在Win 32中是作为文件来进行处理的,而不是直接对端口进行操作,对于串行通信,Win 32 提供了相应的文件I/O函数与通信函数,
287 通过了解这些函数的使用,可以编制出符合不同需要的通信程序。
288 与通信设备相关的结构有COMMCONFIG ,COMMPROP,COMMTIMEOUTS,COMSTAT,DCB,MODEMDEVCAPS,MODEMSETTINGS共7个,
289 与通信有关的Windows API函数共有26个,详细说明可参考MSDN帮助文件。以下将结合实例,给出实现串行通信的三种方法。
290
291 */
292