SerialCommHelper.cpp
上传用户:chineseart
上传日期:2022-06-24
资源大小:52k
文件大小:13k
源码类别:

串口编程

开发平台:

Visual C++

  1. // RCSerial.cpp: implementation of the CSerialCommHelper class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "SerialCommHelper.h"
  6. #include <Process.h>
  7. #include <string>
  8. #ifdef _DEBUG
  9. #undef THIS_FILE
  10. static char THIS_FILE[]=__FILE__;
  11. #define new DEBUG_NEW
  12. #endif
  13. CDebugDump m_DebugFile;
  14. //////////////////////////////////////////////////////////////////////
  15. // Construction/Destruction
  16. //////////////////////////////////////////////////////////////////////
  17. #define ATLTRACE6 m_DebugFile.Dump
  18. void CSerialCommHelper::InvalidateHandle(HANDLE& hHandle )
  19. {
  20. hHandle = INVALID_HANDLE_VALUE;
  21. }
  22. void CSerialCommHelper::CloseAndCleanHandle(HANDLE& hHandle)
  23. {
  24. BOOL abRet  = CloseHandle( hHandle ) ;
  25. if ( !abRet )
  26. {
  27. ASSERT(0);
  28. ATLTRACE6 ( "CSerialCommHelper : Failed to open Close Handle %d :Last Error: %d",hHandle,GetLastError());
  29. }
  30. InvalidateHandle ( hHandle );
  31. }
  32. CSerialCommHelper::CSerialCommHelper()
  33. {
  34. InvalidateHandle( m_hThreadTerm );
  35. InvalidateHandle( m_hThread );
  36. InvalidateHandle( m_hThreadStarted );
  37. InvalidateHandle( m_hCommPort );
  38. InvalidateHandle( m_hDataRx );
  39.  
  40. InitLock();
  41. m_eState = SS_UnInit;
  42. m_DebugFile.Init(_T("c:\Temp\") ,_T("SerialIO"),_T("RCSERIAL:"));
  43. }
  44. CSerialCommHelper::~CSerialCommHelper()
  45. {
  46. m_eState = SS_Unknown;
  47. DelLock();
  48. }
  49. HRESULT CSerialCommHelper:: Init(std::string szPortName, DWORD dwBaudRate,BYTE byParity,BYTE byStopBits,BYTE byByteSize)
  50. {
  51. HRESULT hr = S_OK;
  52. try
  53. {
  54. m_hDataRx  = CreateEvent(0,0,0,0);
  55. //open the COM Port
  56. m_hCommPort = ::CreateFile(szPortName.c_str (),
  57. GENERIC_READ|GENERIC_WRITE,//access ( read and write)
  58. 0, //(share) 0:cannot share the COM port
  59. 0, //security  (None)
  60. OPEN_EXISTING,// creation : open_existing
  61. FILE_FLAG_OVERLAPPED,// we want overlapped operation
  62. 0// no templates file for COM port...
  63. );
  64. if ( m_hCommPort == INVALID_HANDLE_VALUE )
  65. {
  66. ATLTRACE6 ( "CSerialCommHelper : Failed to open COM Port Reason: %d",GetLastError());
  67. ASSERT ( 0 );
  68. return E_FAIL;
  69. }
  70. ATLTRACE6 ( "CSerialCommHelper : COM port opened successfully" );
  71. //now start to read but first we need to set the COM port settings and the timeouts
  72. if (! ::SetCommMask(m_hCommPort,EV_RXCHAR|EV_TXEMPTY) )
  73. {
  74. ASSERT(0);
  75. ATLTRACE6 ( "CSerialCommHelper : Failed to Set Comm Mask Reason: %d",GetLastError());
  76. return E_FAIL;
  77. }
  78. ATLTRACE6 ( "CSerialCommHelper : SetCommMask() success");
  79. //now we need to set baud rate etc,
  80. DCB dcb = {0};
  81. dcb.DCBlength = sizeof(DCB);
  82. if (!::GetCommState (m_hCommPort,&dcb))
  83. {
  84. ATLTRACE6 ( "CSerialCommHelper : Failed to Get Comm State Reason: %d",GetLastError());
  85. return E_FAIL;
  86. }
  87. dcb.BaudRate = dwBaudRate;
  88. dcb.ByteSize = byByteSize;
  89. dcb.Parity = byParity;
  90. if ( byStopBits == 1 )
  91. dcb.StopBits = ONESTOPBIT;
  92. else if (byStopBits == 2 ) 
  93. dcb.StopBits = TWOSTOPBITS;
  94. else 
  95. dcb.StopBits = ONE5STOPBITS;
  96. dcb.fDsrSensitivity = 0;
  97. dcb.fDtrControl = DTR_CONTROL_ENABLE;
  98. dcb.fOutxDsrFlow = 0;
  99. if (!::SetCommState (m_hCommPort,&dcb))
  100. {
  101. ASSERT(0);
  102. ATLTRACE6 ( "CSerialCommHelper : Failed to Set Comm State Reason: %d",GetLastError());
  103. return E_FAIL;
  104. }
  105. ATLTRACE6 ( "CSerialCommHelper : Current Settings, (Baud Rate %d; Parity %d; Byte Size %d; Stop Bits %d", dcb.BaudRate, 
  106. dcb.Parity,dcb.ByteSize,dcb.StopBits);
  107. //now set the timeouts ( we control the timeout overselves using WaitForXXX()
  108. COMMTIMEOUTS timeouts;
  109. timeouts.ReadIntervalTimeout = MAXDWORD; 
  110. timeouts.ReadTotalTimeoutMultiplier = 0;
  111. timeouts.ReadTotalTimeoutConstant = 0;
  112. timeouts.WriteTotalTimeoutMultiplier = 0;
  113. timeouts.WriteTotalTimeoutConstant = 0;
  114. if (!SetCommTimeouts(m_hCommPort, &timeouts))
  115. {
  116. ASSERT(0);
  117. ATLTRACE6 ( "CSerialCommHelper :  Error setting time-outs. %d",GetLastError());
  118. return E_FAIL;
  119. }
  120. //create thread terminator event...
  121. m_hThreadTerm = CreateEvent(0,0,0,0);
  122. m_hThreadStarted = CreateEvent(0,0,0,0);
  123. m_hThread =  (HANDLE)_beginthreadex(0,0,CSerialCommHelper::ThreadFn,(void*)this,0,0 );
  124. DWORD dwWait = WaitForSingleObject ( m_hThreadStarted , INFINITE );
  125. ASSERT ( dwWait == WAIT_OBJECT_0 );
  126. CloseHandle(m_hThreadStarted);
  127. InvalidateHandle(m_hThreadStarted );
  128. m_abIsConnected = true;
  129. }
  130. catch(...)
  131. {
  132. ASSERT(0);
  133. hr = E_FAIL;
  134. }
  135. if ( SUCCEEDED(hr) ) 
  136. {
  137. m_eState = SS_Init;
  138. }
  139. return hr;
  140.  
  141. }
  142.  
  143. HRESULT CSerialCommHelper:: Start()
  144. {
  145. m_eState = SS_Started;
  146. return S_OK;
  147. }
  148. HRESULT CSerialCommHelper:: Stop()
  149. {
  150. m_eState = SS_Stopped;
  151. return S_OK;
  152. }
  153. HRESULT CSerialCommHelper:: UnInit()
  154. {
  155. HRESULT hr = S_OK;
  156. try
  157. {
  158. m_abIsConnected = false;
  159. SignalObjectAndWait(m_hThreadTerm,m_hThread,INFINITE,FALSE);
  160. CloseAndCleanHandle( m_hThreadTerm);
  161. CloseAndCleanHandle( m_hThread);
  162. CloseAndCleanHandle( m_hDataRx );
  163. CloseAndCleanHandle( m_hCommPort );
  164. }
  165. catch(...)
  166. {
  167. ASSERT(0);
  168. hr = E_FAIL;
  169. }
  170. if ( SUCCEEDED(hr)) 
  171. m_eState = SS_UnInit;
  172. return hr;
  173. }
  174. unsigned __stdcall CSerialCommHelper::ThreadFn(void*pvParam)
  175. {
  176. CSerialCommHelper* apThis = (CSerialCommHelper*) pvParam ;
  177. bool abContinue = true;
  178. DWORD dwEventMask=0;
  179. OVERLAPPED ov;
  180. memset(&ov,0,sizeof(ov));
  181. ov.hEvent = CreateEvent( 0,true,0,0);
  182. HANDLE arHandles[2];
  183. arHandles[0] = apThis->m_hThreadTerm;
  184. DWORD dwWait;
  185. SetEvent(apThis->m_hThreadStarted);
  186. while (  abContinue )
  187. {
  188. BOOL abRet = ::WaitCommEvent(apThis->m_hCommPort,&dwEventMask, &ov) ;
  189. if ( !abRet )
  190. {
  191. ASSERT( GetLastError () == ERROR_IO_PENDING);
  192. }
  193. arHandles[1] = ov.hEvent ;
  194. dwWait = WaitForMultipleObjects (2,arHandles,FALSE,INFINITE);
  195. switch ( dwWait )
  196. {
  197. case WAIT_OBJECT_0:
  198. {
  199. _endthreadex(1);
  200. }
  201. break;
  202. case WAIT_OBJECT_0 + 1:
  203. {
  204. DWORD dwMask;
  205. if (GetCommMask(apThis->m_hCommPort,&dwMask) )
  206. {
  207. if ( dwMask == EV_TXEMPTY )
  208. {
  209. AfxMessageBox("Data sent");
  210. ResetEvent ( ov.hEvent );
  211. continue;
  212. }
  213. }
  214. //read data here...
  215. int iAccum = 0;
  216. apThis->m_theSerialBuffer.LockBuffer();
  217. try 
  218. {
  219. std::string szDebug;
  220. BOOL abRet = false;
  221. DWORD dwBytesRead = 0;
  222. OVERLAPPED ovRead;
  223. memset(&ovRead,0,sizeof(ovRead));
  224. ovRead.hEvent = CreateEvent( 0,true,0,0);
  225. do
  226. {
  227. ResetEvent( ovRead.hEvent  );
  228. char szTmp[1];
  229. int iSize  = sizeof ( szTmp );
  230. memset(szTmp,0,sizeof szTmp);
  231. abRet = ::ReadFile(apThis->m_hCommPort,szTmp,sizeof(szTmp),&dwBytesRead,&ovRead);
  232. if (!abRet ) 
  233. {
  234. abContinue = FALSE;
  235. break;
  236. }
  237. if ( dwBytesRead > 0 )
  238. {
  239. apThis->m_theSerialBuffer.AddData ( szTmp,dwBytesRead );
  240. iAccum += dwBytesRead;
  241. }
  242. }while (0);// dwBytesRead > 0 );
  243. CloseHandle(ovRead.hEvent );
  244. }
  245. catch(...)
  246. {
  247. ASSERT(0);
  248. }
  249. //if we are not in started state then we should flush the queue...( we would still read the data)
  250. if (apThis->GetCurrentState() != SS_Started ) 
  251. {
  252. iAccum  = 0;
  253. apThis->m_theSerialBuffer.Flush ();
  254. }
  255. apThis->m_theSerialBuffer.UnLockBuffer();
  256. ATLTRACE6(_T("RCSerial: Q Unlocked:"));
  257. if ( iAccum > 0 )
  258. {
  259. ATLTRACE6(_T("CSerialCommHelper(worker thread):  SetDataReadEvent() len:{%d} data:{%s}"),iAccum,(apThis->m_theSerialBuffer.GetData()).c_str ()  );
  260. apThis->SetDataReadEvent(); 
  261. }
  262. ResetEvent ( ov.hEvent );
  263. }
  264. break;
  265. }//switch
  266. }
  267. return 0;
  268. }
  269. HRESULT  CSerialCommHelper::CanProcess ()
  270. {
  271. switch ( m_eState  ) 
  272. {
  273. case SS_Unknown :ASSERT(0);return E_FAIL;
  274. case SS_UnInit :return E_FAIL;
  275. case SS_Started :return S_OK;
  276. case SS_Init :
  277. case SS_Stopped :
  278. return E_FAIL;
  279. default:ASSERT(0);
  280. }
  281. return E_FAIL;
  282. }
  283. HRESULT CSerialCommHelper::Write (const char* data,DWORD dwSize)
  284. {
  285. HRESULT hr = CanProcess();
  286. if ( FAILED(hr)) return hr;
  287. int iRet = 0 ;
  288. OVERLAPPED ov;
  289. memset(&ov,0,sizeof(ov));
  290. ov.hEvent = CreateEvent( 0,true,0,0);
  291. DWORD dwBytesWritten = 0;
  292. //do
  293. {
  294. iRet = WriteFile (m_hCommPort,data,dwSize,&dwBytesWritten  ,&ov);
  295. if ( iRet == 0 )
  296. {
  297. WaitForSingleObject(ov.hEvent ,INFINITE);
  298. }
  299.  
  300. }// while ( ov.InternalHigh != dwSize ) ;
  301. CloseHandle(ov.hEvent);
  302. std::string szData(data);
  303. ATLTRACE6(_T("RCSerial:Writing:{%s} len:{%d}"),(szData).c_str(),szData.size());
  304. return S_OK;
  305. }
  306. HRESULT CSerialCommHelper::Read_Upto (std::string& data,char chTerminator ,long* alCount,long alTimeOut)
  307. {
  308. HRESULT hr = CanProcess();
  309. if ( FAILED(hr)) return hr;
  310. ATLTRACE6("CSerialCommHelper : CSerialCommHelper: Read_Upto called  ");
  311. try
  312. {
  313.  
  314. std::string szTmp;
  315. szTmp.erase ();
  316. long alBytesRead;
  317. bool abFound =  m_theSerialBuffer.Read_Upto(szTmp ,chTerminator,alBytesRead,m_hDataRx );
  318. if ( abFound ) 
  319. {
  320. data = szTmp ;
  321. }
  322. else
  323. {//there are either none or less bytes...
  324. long iRead = 0;
  325. bool abContinue =  true;
  326. while (  abContinue )
  327. {
  328. ATLTRACE6("CSerialCommHelper : CSerialCommHelper : Read_Upto () making blocking read call  ");
  329. DWORD dwWait  = ::WaitForSingleObject ( m_hDataRx , alTimeOut ) ;
  330. if  ( dwWait == WAIT_TIMEOUT) 
  331. {
  332. ATLTRACE6("CSerialCommHelper : CSerialCommHelper : Read_Upto () timed out in blocking read");
  333. data.erase ();
  334. hr = E_FAIL;
  335. return hr;
  336. }
  337.    
  338. bool abFound =  m_theSerialBuffer.Read_Upto(szTmp ,chTerminator,alBytesRead,m_hDataRx );
  339. if ( abFound ) 
  340. {
  341. data = szTmp;
  342. ATLTRACE6("CSerialCommHelper : CSerialCommHelper: Read_Upto WaitForSingleObject  data:{%s}len:{%d}",((szTmp)).c_str(),szTmp.size ());
  343. return S_OK;
  344. }
  345. ATLTRACE6("CSerialCommHelper : CSerialCommHelper: Read_Upto WaitForSingleObject  not FOUND ");
  346. }
  347. }
  348. }
  349. catch(...)
  350. {
  351. ATLTRACE6(_T("CSerialCommHelperUnhandled exception"));
  352. ASSERT ( 0  ) ;
  353. }
  354. return hr;
  355. }
  356. HRESULT CSerialCommHelper::Read_N (std::string& data,long alCount,long  alTimeOut )
  357. {
  358. HRESULT hr = CanProcess();
  359. if ( FAILED(hr)) 
  360. {
  361. ASSERT(0);
  362. return hr;
  363. }
  364. ATLTRACE6("CSerialCommHelper : CSerialCommHelper : Read_N called for %d bytes",alCount);
  365. try
  366. {
  367.  
  368. std::string szTmp ;
  369. szTmp.erase();
  370. ATLTRACE6("CSerialCommHelper : CSerialCommHelper : Read_N (%d) locking the queue  ",alCount);
  371. int iLocal =  m_theSerialBuffer.Read_N(szTmp ,alCount ,m_hDataRx );
  372. if ( iLocal == alCount ) 
  373. {
  374. data = szTmp;
  375. }
  376. else
  377. {//there are either none or less bytes...
  378. long iRead = 0;
  379. int iRemaining = alCount - iLocal;
  380. while (  1 )
  381. {
  382. ATLTRACE6("CSerialCommHelper : CSerialCommHelper : Read_N (%d) making blocking read() ",alCount);
  383. DWORD dwWait  = WaitForSingleObject ( m_hDataRx , alTimeOut ) ;
  384. if  ( dwWait == WAIT_TIMEOUT ) 
  385. {
  386. ATLTRACE6("CSerialCommHelper : CSerialCommHelper : Read_N (%d) timed out in blocking read",alCount);
  387. data.erase ();
  388. hr = E_FAIL;
  389. return hr;
  390. }
  391. ASSERT ( dwWait == WAIT_OBJECT_0 );
  392. ATLTRACE6("CSerialCommHelper : CSerialCommHelper : Read_N (%d) Woke Up from WaitXXX() locking Q",alCount);
  393.  
  394. iRead =  m_theSerialBuffer.Read_N(szTmp , iRemaining  ,m_hDataRx);
  395. iRemaining -= iRead ;
  396. ATLTRACE6("CSerialCommHelper : CSerialCommHelper : Read_N (%d) Woke Up from WaitXXX() Unlocking Q",alCount);
  397. if (  iRemaining  == 0) 
  398. {
  399. ATLTRACE6("CSerialCommHelper : CSerialCommHelper : Read_N (%d) Woke Up from WaitXXX() Done reading ",alCount);
  400. data = szTmp;
  401. return S_OK;
  402. }
  403. }
  404. }
  405. }
  406. catch(...)
  407. {
  408. ATLTRACE6(_T("CSerialCommHelper Unhandled exception"));
  409. ASSERT ( 0  ) ;
  410. }
  411. return hr;
  412. }
  413. /*-----------------------------------------------------------------------
  414. -- Reads all the data that is available in the local buffer.. 
  415. does NOT make any blocking calls in case the local buffer is empty
  416. -----------------------------------------------------------------------*/
  417. HRESULT CSerialCommHelper::ReadAvailable(std::string& data)
  418. {
  419. HRESULT hr = CanProcess();
  420. if ( FAILED(hr)) return hr;
  421. try
  422. {
  423. std::string szTemp;
  424. bool abRet = m_theSerialBuffer.Read_Available (szTemp,m_hDataRx);
  425. data = szTemp;
  426. }
  427. catch(...)
  428. {
  429. ATLTRACE6(_T("CSerialCommHelper Unhandled exception in ReadAvailable()"));
  430. ASSERT ( 0  ) ;
  431. hr = E_FAIL;
  432. }
  433. return hr;
  434. }