ComControl.cpp
上传用户:asikq0571
上传日期:2014-07-12
资源大小:528k
文件大小:10k
源码类别:

Internet/IE编程

开发平台:

Visual C++

  1. // ComControl.cpp: implementation of the CComControl class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. //#include "MnRTU.h"
  6. #include "ComControl.h"
  7. #ifdef _DEBUG
  8. #undef THIS_FILE
  9. static char THIS_FILE[]=__FILE__;
  10. #define new DEBUG_NEW
  11. #endif
  12. //////////////////////////////////////////////////////////////////////
  13. // Construction/Destruction
  14. //////////////////////////////////////////////////////////////////////
  15. //功能 : 工作线程函数,监测串口事件,当事件发生时给出通知,para是串口对象指针
  16. UINT ComThreadProc(LPVOID para)
  17. {
  18. CComControl* pCom = (CComControl*)para;
  19. DWORD dwErrWord;
  20. COMSTAT comstat;
  21. DWORD dwEventMask;
  22. OVERLAPPED eov;
  23. memset( &eov, 0, sizeof( OVERLAPPED ) ) ;
  24. eov.hEvent = CreateEvent( NULL,   // no security attributes
  25. FALSE,  // auto reset event
  26. FALSE,  // not signaled
  27. NULL    // no name
  28. );
  29. while(true) 
  30. {
  31. if(pCom->m_bExit)
  32. break;
  33.         ClearCommError(pCom->m_hCom, &dwErrWord, &comstat);
  34. if(comstat.cbInQue) 
  35. {
  36. SendMessage( pCom->m_hOwner, WM_COMMNOTIFY, EV_RXCHAR,0);
  37. continue;
  38. }
  39. dwEventMask = 0;
  40. WaitCommEvent(pCom->m_hCom, &dwEventMask, &eov);
  41. WaitForSingleObject(eov.hEvent, 2000);
  42. ClearCommError(pCom->m_hCom, &dwErrWord, &comstat);
  43. if (dwEventMask & EV_ERR) // 线路错误CE_FRAME, CE_OVERRUN, and CE_RXPARITY.
  44. {
  45. SendMessage( pCom->m_hOwner, WM_COMMNOTIFY, EV_ERR , dwErrWord);
  46.   }
  47. if (dwEventMask & EV_TXEMPTY) // 输出缓冲区空
  48. {
  49. SendMessage( pCom->m_hOwner, WM_COMMNOTIFY, EV_TXEMPTY ,0 );
  50. }
  51. if(dwEventMask & EV_RXCHAR && comstat.cbInQue != 0)  
  52. { // 输入缓冲区接收到一字符
  53. SendMessage( pCom->m_hOwner, WM_COMMNOTIFY, EV_RXCHAR,0);
  54. }
  55. }
  56. CloseHandle(eov.hEvent);
  57. return true;
  58. }
  59. CComControl::CComControl()
  60. {
  61. m_bExit = FALSE;
  62. //m_hOwner = hOwner;
  63. InitCom();
  64. }
  65. //功能 : 初始化对象数据
  66. void CComControl::InitCom()
  67. {
  68. memset( &m_ovRead, 0, sizeof( OVERLAPPED ) ) ;
  69. memset( &m_ovWrite, 0, sizeof( OVERLAPPED ) ) ;
  70. m_ovRead.hEvent =  CreateEvent( NULL,    // no security
  71. TRUE,    // explicit reset req
  72. FALSE,   // initial event reset
  73. NULL ) ; // no name
  74. m_ovWrite.hEvent =  CreateEvent( NULL, TRUE, FALSE, NULL );  // See above
  75. m_szPortName = "COM1";
  76. m_nBaudRate = 9600;
  77. m_nParity = NOPARITY;
  78. m_nDataBits     = 8;
  79. m_nStopBits     = ONESTOPBIT;
  80. m_hCom = INVALID_HANDLE_VALUE;
  81. m_pThread = AfxBeginThread(ComThreadProc, (LPVOID)this,THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED); 
  82. }
  83. CComControl::~CComControl()
  84. {
  85.     m_bExit = TRUE;
  86. m_pThread->ResumeThread();
  87. WaitForSingleObject(m_pThread->m_hThread, INFINITE);
  88. m_pThread = NULL; //this ensure pCom->ClosePort work correct
  89. ClosePort();
  90. CloseHandle(m_ovRead.hEvent);
  91. CloseHandle(m_ovWrite.hEvent);
  92. }
  93. //功能: 返回串口中等待读取的字节数
  94. DWORD CComControl::BytesInQue()
  95. {
  96. DWORD dwErrWord;
  97. COMSTAT comstat;
  98. ClearCommError(m_hCom, &dwErrWord, &comstat);
  99. return comstat.cbInQue;
  100. }
  101. //功能: 返回串口中等待写出的字节数
  102. DWORD CComControl::BytesOutQue()
  103. {
  104. DWORD dwErrWord;
  105. COMSTAT comstat;
  106. ClearCommError(m_hCom, &dwErrWord, &comstat);
  107. return comstat.cbOutQue;
  108. }
  109. //功能: 打开串口,串口参数是对象缺省的或通过SetParam设置的
  110. bool CComControl::OpenPort()
  111. {
  112. //fill dcb
  113. DCB dcb;
  114. memset(&dcb, 0, sizeof(dcb));
  115. dcb.DCBlength = sizeof(dcb);
  116. dcb.fBinary = 1;
  117. dcb.BaudRate = m_nBaudRate;
  118. dcb.Parity = (BYTE)m_nParity;
  119. if(m_nParity   != NOPARITY) 
  120. dcb.fParity = true;
  121. dcb.ByteSize    = (BYTE)m_nDataBits;
  122. dcb.StopBits = (BYTE)m_nStopBits;
  123. dcb.fDtrControl = DTR_CONTROL_DISABLE; 
  124. dcb.fRtsControl = RTS_CONTROL_DISABLE;
  125. //fill timeout
  126. COMMTIMEOUTS timeouts;
  127. timeouts.ReadIntervalTimeout = 100*1000 / m_nBaudRate; //100bit传输时间(ms)
  128. if(timeouts.ReadIntervalTimeout < 50)
  129. timeouts.ReadIntervalTimeout = 50;
  130. timeouts.ReadTotalTimeoutConstant = 0;
  131. timeouts.ReadTotalTimeoutMultiplier = timeouts.ReadIntervalTimeout;
  132. timeouts.WriteTotalTimeoutConstant = 0;
  133. timeouts.WriteTotalTimeoutMultiplier= timeouts.ReadIntervalTimeout;
  134. CString szNo = m_szPortName.Right(m_szPortName.GetLength()-3);
  135. int PortNo = _ttoi(szNo);
  136. return OpenPort(PortNo, dcb, timeouts);
  137. }
  138. bool CComControl::OpenPort(int nPortNo, DCB& dcb, COMMTIMEOUTS& timeouts)
  139. {
  140. CString szErr;
  141. if(m_hCom != INVALID_HANDLE_VALUE) 
  142. {
  143. ClosePort();
  144. Sleep(100); // i don't know reason,if don't do this,OpenPort may fail
  145. }
  146. m_szPortName.Format(_T("COM%d"),nPortNo);
  147. //create file
  148. int nTryTime = 1;
  149. while(nTryTime < 4) 
  150. {
  151. m_hCom = CreateFile( _T("\\.\")+m_szPortName,
  152. GENERIC_READ|GENERIC_WRITE, 
  153. 0,
  154. NULL, //lpsa,
  155. OPEN_EXISTING,
  156. FILE_FLAG_OVERLAPPED,
  157. NULL
  158. );
  159. if(m_hCom != INVALID_HANDLE_VALUE)
  160. {
  161. break;
  162. }
  163. nTryTime++;
  164. Sleep(10);
  165. }
  166. if(m_hCom == INVALID_HANDLE_VALUE) 
  167. {
  168. szErr.Format(_T("CComControl::OpenPort:打开串口错误:%d"), GetLastError());
  169. //AfxMessageBox(szErr);
  170. return false;
  171. }
  172. //MOXA NPort Server Pro required
  173. dcb.XonChar = 17;
  174. dcb.XoffChar = 19;
  175. m_nBaudRate = dcb.BaudRate;
  176. m_nParity = dcb.Parity;
  177. if( !SetCommState(m_hCom, &dcb) || //dcb
  178. !SetupComm(m_hCom, 2048, 2048) || //communication buffer
  179. !SetCommTimeouts(m_hCom, &timeouts) || //time out parameter
  180. !SetCommMask(m_hCom, EV_RXCHAR | EV_TXEMPTY | EV_ERR) || //event mask
  181. !PurgeComm(m_hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR )
  182. {
  183. szErr.Format(_T("CComControl::OpenPort:打开串口错误:%d"), GetLastError());
  184. //AfxMessageBox(szErr);
  185. m_pThread->ResumeThread();
  186. ClosePort();
  187. return false;
  188. }
  189. m_pThread->ResumeThread();
  190. return true;
  191. }
  192. //功能: 关闭串口
  193. void CComControl::ClosePort()
  194. {
  195. if(m_hCom != INVALID_HANDLE_VALUE) 
  196. {
  197. if(m_pThread)
  198. m_pThread->SuspendThread();
  199. PurgeComm(m_hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR );
  200. CloseHandle(m_hCom);
  201. m_hCom = INVALID_HANDLE_VALUE;
  202. }
  203. }
  204. //设置串口参数,它显示一对话框,可以设置端口号、波特率、校验方式,它不改变串口的打开状态
  205. void CComControl::SetParam()
  206. {
  207. }
  208. //功能: 设置串口参数,包括端口号、波特率、校验方式,它不改变串口的打开状态
  209. void CComControl::SetParam(LPCTSTR szPortName, int nBaudRate, int nParity)
  210. {
  211. m_szPortName = szPortName;
  212. m_nBaudRate = nBaudRate;
  213. m_nParity = nParity;
  214. if(m_hCom != INVALID_HANDLE_VALUE) 
  215. {
  216. ClosePort();
  217. Sleep(100); // i don't know reason,if don't do this,OpenPort may fail
  218. OpenPort();
  219. }
  220. }
  221. //下面的读写函数将阻塞调用线程
  222. //如果读写成功返回TRUE,如果超时或有其他错误返回FALSE
  223. //通过串口发送数据, pBuff发送缓冲区,dwBytesToSend缓冲区中要发送的字节数
  224. BOOL CComControl::Send(BYTE* pBuff, DWORD dwBytesToSend)
  225. {
  226. DWORD dwBytesSended;
  227. return Send(pBuff,dwBytesToSend, dwBytesSended);
  228. }
  229. //通过串口发送数据, pBuff发送缓冲区,dwBytesToSend缓冲区中要发送的字节数,dwBytesSended为发送的字节数
  230. BOOL CComControl::Send(BYTE* pBuff, DWORD dwBytesToSend, DWORD& dwBytesSended)
  231. {
  232. CString szErr;
  233. dwBytesSended = 0;
  234. if(!PortOpened()) 
  235. {
  236. // RecordDAErr(_T("CComControl::Send:端口未打开"));
  237. return FALSE;
  238. }
  239. BOOL wRes;
  240. wRes = WriteFile(m_hCom, pBuff, dwBytesToSend, &dwBytesSended, &m_ovWrite);
  241. if(!wRes) { //there are some data not send
  242. if(GetLastError() == ERROR_IO_PENDING) {
  243. WaitForSingleObject(m_ovWrite.hEvent, 10*1000); //this block the calling thread
  244. wRes = GetOverlappedResult(m_hCom, &m_ovWrite,&dwBytesSended,false);
  245. if(dwBytesSended != dwBytesToSend) {
  246. wRes = FALSE;
  247. }
  248. } else { // an error occured
  249. wRes = FALSE;
  250. }
  251. }
  252. if(!wRes) {
  253. szErr.Format(_T("CComControl::Send:发送错误:%d"), GetLastError());
  254. // RecordDAErr(szErr);
  255. ClearPort();
  256. }
  257. return wRes;
  258. }
  259. //通过串口接收数据, pBuff接收缓冲区,dwBytesToRead要接收的字节数
  260. BOOL CComControl::Receive(BYTE* pBuff, DWORD dwBytesToRead)
  261. {
  262. DWORD dwBytesReaded;
  263. return Receive(pBuff,dwBytesToRead, dwBytesReaded);
  264. }
  265. //通过串口接收数据, pBuff接收缓冲区,dwBytesToRead要接收的字节数,dwBytesSended为接收的字节数
  266. BOOL CComControl::Receive(BYTE* pBuff, DWORD dwBytesToRead, DWORD& dwBytesReaded)
  267. {
  268. CString szErr;
  269. dwBytesReaded = 0;
  270. if(!PortOpened()) 
  271. {
  272. szErr.Format(_T("CComControl::Receive:端口未打开"));
  273. // RecordDAErr(szErr);
  274. return FALSE;
  275. }
  276. BOOL rRes = ReadFile(m_hCom, pBuff, dwBytesToRead, &dwBytesReaded, &m_ovRead);
  277. if(!rRes )  
  278. {
  279. if (GetLastError() == ERROR_IO_PENDING) 
  280. {
  281. WaitForSingleObject(m_ovRead.hEvent, 10*1000); //this block the calling thread,if err or timeout it return
  282. rRes = GetOverlappedResult(m_hCom, &m_ovRead, &dwBytesReaded, false);
  283. if( dwBytesReaded != dwBytesToRead) 
  284. {
  285. // an error occurred, i think it most was timeout also it return when line error
  286. //if an error occurred, we will clear it in our com thread which wait error event.
  287. rRes = FALSE;
  288. }
  289. else
  290. {
  291. rRes = FALSE;
  292. }
  293. }
  294. if(!rRes) 
  295. {
  296. szErr.Format(_T("CComControl::Receive:接收错误:%d"), GetLastError());
  297. // RecordDAErr(szErr);
  298. ClearPort();
  299. }
  300. return rRes;
  301. }
  302. //清除串口错误,放弃正在发送和接收的数据
  303. void CComControl::ClearPort()
  304. {
  305. if(m_hCom == INVALID_HANDLE_VALUE) 
  306. return;
  307. PurgeComm(m_hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR );
  308. DWORD dwErr;
  309. COMSTAT stat;
  310. ClearCommError(m_hCom, &dwErr, &stat);
  311. }
  312. //清除串口错误
  313. void CComControl::ClearErr()
  314. {
  315. DWORD dwErr;
  316. COMSTAT stat;
  317. ClearCommError(m_hCom, &dwErr, &stat);
  318. }
  319. void CComControl::Serialize(CArchive &ar)
  320. {
  321. if(ar.IsStoring())
  322. {
  323. ar << m_nStopBits; //停止位
  324. ar << m_nDataBits; //数据位
  325. ar << m_szPortName; //串口名
  326. ar << m_nBaudRate; //波特率
  327. ar << m_nParity; //校验方式
  328. }
  329. else
  330. {
  331. ar >> m_nStopBits; //停止位
  332. ar >> m_nDataBits; //数据位
  333. ar >> m_szPortName; //串口名
  334. ar >> m_nBaudRate; //波特率
  335. ar >> m_nParity; //校验方式
  336. }
  337. CObject::Serialize(ar);
  338. }