AsynSerial.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. /************************************************************************/
  2. /* Copyright (C), 2016-2020, [Home], 保留所有权利;
  3. /* 模 块 名:异步串口模块;
  4. /* 描 述:;
  5. /*
  6. /* 版 本:[V];
  7. /* 作 者:[Home];
  8. /* 日 期:[12/20/2017];
  9. /*
  10. /*
  11. /* 注 意:;
  12. /*
  13. /* 修改记录:[Home];
  14. /* 修改日期:;
  15. /* 修改版本:;
  16. /* 修改内容:;
  17. /************************************************************************/
  18. #ifndef __ASYN_SERIAL__
  19. #define __ASYN_SERIAL__
  20. #pragma once
  21. class CAsynSerial
  22. {
  23. public:
  24. //Enums
  25. enum FlowControl
  26. {
  27. NoFlowControl,
  28. CtsRtsFlowControl,
  29. CtsDtrFlowControl,
  30. DsrRtsFlowControl,
  31. DsrDtrFlowControl,
  32. XonXoffFlowControl
  33. };
  34. enum Parity
  35. {
  36. NoParity = 0,
  37. OddParity = 1,
  38. EvenParity = 2,
  39. MarkParity = 3,
  40. SpaceParity = 4
  41. };
  42. enum StopBits
  43. {
  44. OneStopBit,
  45. OnePointFiveStopBits,
  46. TwoStopBits
  47. };
  48. protected:
  49. HANDLE m_hComm;
  50. OVERLAPPED m_ovWait;
  51. OVERLAPPED m_ovRead;
  52. OVERLAPPED m_ovWrite;
  53. public:
  54. CAsynSerial(void);
  55. virtual ~CAsynSerial(void);
  56. BOOL IsOpen() const throw() // noexcept
  57. {
  58. return m_hComm != INVALID_HANDLE_VALUE;
  59. }
  60. void Close() throw() // noexcept
  61. {
  62. if (IsOpen())
  63. {
  64. CloseHandle(m_hComm);
  65. m_hComm = INVALID_HANDLE_VALUE;
  66. }
  67. }
  68. BOOL Open(LPCTSTR pszPort, BOOL bOverlapped = FALSE) throw(); // noexcept
  69. BOOL Open(int nPort, DWORD dwBaud = 9600, int parity = NoParity, BYTE DataBits = 8, int stopBits = OneStopBit, int fc = NoFlowControl, BOOL bOverlapped = FALSE);
  70. BOOL Open(LPCTSTR pszPort, DWORD dwBaud = 9600, int parity = NoParity, BYTE DataBits = 8, int stopBits = OneStopBit, int fc = NoFlowControl, BOOL bOverlapped = FALSE) throw(); // noexcept
  71. //////////////////////////////////////////////////////////////////////////
  72. //Reading / Writing Methods
  73. BOOL Read(void* lpBuffer, DWORD dwNumberOfBytesToRead, DWORD& dwBytesRead) throw()
  74. {
  75. ATLASSERT(IsOpen());
  76. dwBytesRead = 0;
  77. return ReadFile(m_hComm, lpBuffer, dwNumberOfBytesToRead, &dwBytesRead, NULL);
  78. }
  79. BOOL Read(void* lpBuffer, DWORD dwNumberOfBytesToRead, OVERLAPPED& overlapped, DWORD* lpNumberOfBytesRead = NULL) throw()
  80. {
  81. ATLASSERT(IsOpen());
  82. return ReadFile(m_hComm, lpBuffer, dwNumberOfBytesToRead, lpNumberOfBytesRead, &overlapped);
  83. }
  84. BOOL ReadEx(LPVOID lpBuffer, DWORD dwNumberOfBytesToRead, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) throw()
  85. {
  86. ATLASSERT(IsOpen());
  87. return ReadFileEx(m_hComm, lpBuffer, dwNumberOfBytesToRead, lpOverlapped, lpCompletionRoutine);
  88. }
  89. // 必须先启用:SetMask(EV_ERR | EV_RXCHAR),才能使用WaitCommEvent;
  90. BOOL ReadAsyn(void* lpBuffer, DWORD dwNumberOfBytesToRead, DWORD &dwNumberOfBytesRead) throw()
  91. {
  92. ATLASSERT(IsOpen());
  93. COMSTAT cs = { 0 };
  94. DWORD dwErrors = 0;
  95. DWORD dwEvtMask = 0;
  96. DWORD dwNumberOfBytesTransferred;
  97. m_ovWait.Offset = 0;
  98. m_ovRead.Offset = 0;
  99. BOOL Status = WaitCommEvent(m_hComm, &dwEvtMask, &m_ovWait);
  100. // WaitCommEvent也是一个异步命令,所以需要等待
  101. if (!Status && GetLastError() == ERROR_IO_PENDING)
  102. {
  103. // 如果缓存中无数据线程会停在此,如果hCom关闭会立即返回False
  104. Status = ::GetOverlappedResult(m_hComm, &m_ovWait, &dwNumberOfBytesTransferred, TRUE);
  105. }
  106. ClearCommError(m_hComm, &dwErrors, &cs);
  107. if (Status && dwEvtMask & EV_RXCHAR && cs.cbInQue > 0) //有数据
  108. {
  109. dwNumberOfBytesTransferred = 0;
  110. memset(lpBuffer, 0, dwNumberOfBytesToRead);
  111. // 数据已经到达缓存区,ReadFile不会当成异步命令,而是立即读取并返回True
  112. Status = ReadFile(m_hComm, lpBuffer, dwNumberOfBytesToRead, &dwNumberOfBytesRead, &m_ovRead);
  113. PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_RXABORT);
  114. }
  115. return Status;
  116. }
  117. BOOL Write(const void* lpBuffer, DWORD dwNumberOfBytesToWrite, DWORD& dwBytesWritten) throw()
  118. {
  119. ATLASSERT(IsOpen());
  120. dwBytesWritten = 0;
  121. return WriteFile(m_hComm, lpBuffer, dwNumberOfBytesToWrite, &dwBytesWritten, NULL);
  122. }
  123. BOOL Write(const void* lpBuffer, DWORD dwNumberOfBytesToWrite, OVERLAPPED& overlapped, DWORD* lpNumberOfBytesWritten = NULL) throw()
  124. {
  125. ATLASSERT(IsOpen());
  126. return WriteFile(m_hComm, lpBuffer, dwNumberOfBytesToWrite, lpNumberOfBytesWritten, &overlapped);
  127. }
  128. // SetMask(EV_ERR | EV_RXCHAR);
  129. BOOL WriteAsyn(const void* lpBuffer, DWORD dwNumberOfBytesToWrite, DWORD &dwNumberOfBytesWritten) throw()
  130. {
  131. ATLASSERT(IsOpen());
  132. PurgeComm(m_hComm, PURGE_TXCLEAR|PURGE_TXABORT);
  133. m_ovWait.Offset = 0;
  134. BOOL bRet = WriteFile(m_hComm, lpBuffer, dwNumberOfBytesToWrite, &dwNumberOfBytesWritten, &m_ovWrite);
  135. if (!bRet && GetLastError() == ERROR_IO_PENDING)//后台读取
  136. {
  137. //等待数据写入完成
  138. if (FALSE == ::GetOverlappedResult(m_hComm, &m_ovWrite, &dwNumberOfBytesWritten, TRUE))
  139. {
  140. return FALSE;
  141. }
  142. }
  143. return bRet;
  144. }
  145. BOOL WriteEx(LPCVOID lpBuffer, DWORD dwNumberOfBytesToWrite, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) throw()
  146. {
  147. ATLASSERT(IsOpen());
  148. return WriteFileEx(m_hComm, lpBuffer, dwNumberOfBytesToWrite, lpOverlapped, lpCompletionRoutine);
  149. }
  150. BOOL TransmitChar(char cChar) throw()
  151. {
  152. ATLASSERT(IsOpen());
  153. return TransmitCommChar(m_hComm, cChar);
  154. }
  155. BOOL GetOverlappedResult(OVERLAPPED& overlapped, DWORD& dwBytesTransferred, BOOL bWait) throw()
  156. {
  157. ATLASSERT(IsOpen());
  158. return ::GetOverlappedResult(m_hComm, &overlapped, &dwBytesTransferred, bWait);
  159. }
  160. __if_exists(::GetOverlappedResultEx)
  161. {
  162. BOOL GetOverlappedResultEx(OVERLAPPED& overlapped, DWORD& dwBytesTransferred, DWORD dwMilliseconds, _In_ BOOL bAlertable) throw()
  163. {
  164. ATLASSERT(IsOpen());
  165. return ::GetOverlappedResultEx(m_hComm, &overlapped, &dwBytesTransferred, dwMilliseconds, bAlertable);
  166. }
  167. }
  168. BOOL CancelIo() throw()
  169. {
  170. ATLASSERT(IsOpen());
  171. return ::CancelIo(m_hComm);
  172. }
  173. __if_exists(::CancelIoEx)
  174. {
  175. BOOL CancelIoEx(LPOVERLAPPED lpOverlapped = NULL) throw()
  176. {
  177. ATLASSERT(IsOpen());
  178. return ::CancelIoEx(m_hComm, lpOverlapped);
  179. }
  180. }
  181. BOOL BytesWaiting(DWORD& dwBytesWaiting) throw()
  182. {
  183. ATLASSERT(IsOpen());
  184. //Check to see how many characters are unread
  185. dwBytesWaiting = 0;
  186. COMSTAT stat;
  187. if (!GetStatus(stat))
  188. return FALSE;
  189. dwBytesWaiting = stat.cbInQue;
  190. return TRUE;
  191. }
  192. //Configuration Methods
  193. BOOL GetConfig(COMMCONFIG& config) throw()
  194. {
  195. ATLASSERT(IsOpen());
  196. DWORD dwSize = sizeof(COMMCONFIG);
  197. return GetCommConfig(m_hComm, &config, &dwSize);
  198. }
  199. static BOOL GetDefaultConfig(int nPort, COMMCONFIG& config)
  200. {
  201. CString sPort;
  202. sPort.Format(_T("COM%d"), nPort);
  203. //Delegate to the other version of the method
  204. return GetDefaultConfig(sPort, config);
  205. }
  206. static BOOL GetDefaultConfig(LPCTSTR pszPort, COMMCONFIG& config) throw()
  207. {
  208. DWORD dwSize = sizeof(COMMCONFIG);
  209. return GetDefaultCommConfig(pszPort, &config, &dwSize);
  210. }
  211. BOOL SetConfig(COMMCONFIG& config) throw()
  212. {
  213. ATLASSERT(IsOpen());
  214. const DWORD dwSize = sizeof(COMMCONFIG);
  215. return SetCommConfig(m_hComm, &config, dwSize);
  216. }
  217. static BOOL SetDefaultConfig(int nPort, COMMCONFIG& config)
  218. {
  219. CString sPort;
  220. sPort.Format(_T("COM%d"), nPort);
  221. //Delegate to the other version of the method
  222. return SetDefaultConfig(sPort, config);
  223. }
  224. static BOOL SetDefaultConfig(LPCTSTR pszPort, COMMCONFIG& config) throw()
  225. {
  226. const DWORD dwSize = sizeof(COMMCONFIG);
  227. return SetDefaultCommConfig(pszPort, &config, dwSize);
  228. }
  229. //Misc RS232 Methods
  230. BOOL ClearBreak() throw()
  231. {
  232. ATLASSERT(IsOpen());
  233. return ClearCommBreak(m_hComm);
  234. }
  235. BOOL SetBreak() throw()
  236. {
  237. ATLASSERT(IsOpen());
  238. return SetCommBreak(m_hComm);
  239. }
  240. BOOL ClearError(DWORD& dwErrors) throw()
  241. {
  242. ATLASSERT(IsOpen());
  243. return ClearCommError(m_hComm, &dwErrors, NULL);
  244. }
  245. BOOL GetStatus(COMSTAT& stat) throw()
  246. {
  247. ATLASSERT(IsOpen());
  248. DWORD dwErrors = 0;
  249. return ClearCommError(m_hComm, &dwErrors, &stat);
  250. }
  251. BOOL GetState(DCB& dcb) throw()
  252. {
  253. ATLASSERT(IsOpen());
  254. return GetCommState(m_hComm, &dcb);
  255. }
  256. BOOL SetState(DCB& dcb) throw()
  257. {
  258. ATLASSERT(IsOpen());
  259. return SetCommState(m_hComm, &dcb);
  260. }
  261. BOOL Escape(DWORD dwFunc) throw()
  262. {
  263. ATLASSERT(IsOpen());
  264. return EscapeCommFunction(m_hComm, dwFunc);
  265. }
  266. BOOL ClearDTR() throw()
  267. {
  268. return Escape(CLRDTR);
  269. }
  270. BOOL ClearRTS() throw()
  271. {
  272. return Escape(CLRRTS);
  273. }
  274. BOOL SetDTR() throw()
  275. {
  276. return Escape(SETDTR);
  277. }
  278. BOOL SetRTS() throw()
  279. {
  280. return Escape(SETRTS);
  281. }
  282. BOOL SetXOFF() throw()
  283. {
  284. return Escape(SETXOFF);
  285. }
  286. BOOL SetXON() throw()
  287. {
  288. return Escape(SETXON);
  289. }
  290. BOOL GetProperties(COMMPROP& properties) throw()
  291. {
  292. ATLASSERT(IsOpen());
  293. return GetCommProperties(m_hComm, &properties);
  294. }
  295. BOOL GetModemStatus(DWORD& dwModemStatus) throw()
  296. {
  297. ATLASSERT(IsOpen());
  298. return GetCommModemStatus(m_hComm, &dwModemStatus);
  299. }
  300. //Timeouts
  301. BOOL SetTimeouts(COMMTIMEOUTS& timeouts) throw()
  302. {
  303. ATLASSERT(IsOpen());
  304. return SetCommTimeouts(m_hComm, &timeouts);
  305. }
  306. BOOL GetTimeouts(COMMTIMEOUTS& timeouts) throw()
  307. {
  308. ATLASSERT(IsOpen());
  309. return GetCommTimeouts(m_hComm, &timeouts);
  310. }
  311. BOOL Set0Timeout() throw()
  312. {
  313. COMMTIMEOUTS Timeouts;
  314. memset(&Timeouts, 0, sizeof(Timeouts));
  315. Timeouts.ReadIntervalTimeout = MAXDWORD;
  316. return SetTimeouts(Timeouts);
  317. }
  318. BOOL Set0WriteTimeout() throw()
  319. {
  320. COMMTIMEOUTS Timeouts;
  321. GetTimeouts(Timeouts);
  322. Timeouts.WriteTotalTimeoutMultiplier = 0;
  323. Timeouts.WriteTotalTimeoutConstant = 0;
  324. return SetTimeouts(Timeouts);
  325. }
  326. BOOL Set0ReadTimeout() throw()
  327. {
  328. COMMTIMEOUTS Timeouts;
  329. GetTimeouts(Timeouts);
  330. Timeouts.ReadIntervalTimeout = MAXDWORD;
  331. Timeouts.ReadTotalTimeoutMultiplier = 0;
  332. Timeouts.ReadTotalTimeoutConstant = 0;
  333. return SetTimeouts(Timeouts);
  334. }
  335. //Event Methods
  336. BOOL SetMask(DWORD dwMask) throw()
  337. {
  338. ATLASSERT(IsOpen());
  339. return SetCommMask(m_hComm, dwMask);
  340. }
  341. BOOL GetMask(DWORD& dwMask) throw()
  342. {
  343. ATLASSERT(IsOpen());
  344. return GetCommMask(m_hComm, &dwMask);
  345. }
  346. BOOL WaitEvent(DWORD& dwMask) throw()
  347. {
  348. ATLASSERT(IsOpen());
  349. return WaitCommEvent(m_hComm, &dwMask, NULL);
  350. }
  351. BOOL WaitEvent(DWORD& dwMask, OVERLAPPED& overlapped) throw()
  352. {
  353. ATLASSERT(IsOpen());
  354. ATLASSERT(overlapped.hEvent != NULL);
  355. return WaitCommEvent(m_hComm, &dwMask, &overlapped);
  356. }
  357. //Queue Methods
  358. BOOL Flush() throw()
  359. {
  360. ATLASSERT(IsOpen());
  361. return FlushFileBuffers(m_hComm);
  362. }
  363. BOOL Purge(DWORD dwFlags) throw()
  364. {
  365. ATLASSERT(IsOpen());
  366. return PurgeComm(m_hComm, dwFlags);
  367. }
  368. BOOL TerminateOutstandingWrites() throw()
  369. {
  370. return Purge(PURGE_TXABORT);
  371. }
  372. BOOL TerminateOutstandingReads() throw()
  373. {
  374. return Purge(PURGE_RXABORT);
  375. }
  376. BOOL ClearWriteBuffer() throw()
  377. {
  378. return Purge(PURGE_TXCLEAR);
  379. }
  380. BOOL ClearReadBuffer() throw()
  381. {
  382. return Purge(PURGE_RXCLEAR);
  383. }
  384. BOOL Setup(DWORD dwInQueue, DWORD dwOutQueue) throw()
  385. {
  386. ATLASSERT(IsOpen());
  387. return SetupComm(m_hComm, dwInQueue, dwOutQueue);
  388. }
  389. };
  390. #endif // __ASYN_SERIAL__