dsi_serial_vcp.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. /*
  2. This software is subject to the license described in the License.txt file
  3. included with this software distribution. You may not use this file except
  4. in compliance with this license.
  5. Copyright (c) Dynastream Innovations Inc. 2016
  6. All rights reserved.
  7. */
  8. #include "types.h"
  9. #if defined(DSI_TYPES_WINDOWS)
  10. #include "defines.h"
  11. #include "dsi_serial_vcp.hpp"
  12. #include "macros.h"
  13. //#include "usb_device_handle_si.hpp"
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include <windows.h>
  17. #if defined(_MSC_VER)
  18. #include "WinDevice.h"
  19. #endif
  20. #include <vector>
  21. using namespace std;
  22. //#define NUMBER_OF_DEVICES_CHECK_THREAD_KILL //Only include this if we are sure we want to terminate the Rx thread if the number of devices are ever reduced.
  23. //////////////////////////////////////////////////////////////////////////////////
  24. // Private Definitions
  25. //////////////////////////////////////////////////////////////////////////////////
  26. //////////////////////////////////////////////////////////////////////////////////
  27. // Public Methods
  28. //////////////////////////////////////////////////////////////////////////////////
  29. ///////////////////////////////////////////////////////////////////////
  30. // Constructor
  31. ///////////////////////////////////////////////////////////////////////
  32. DSISerialVCP::DSISerialVCP()
  33. {
  34. hReceiveThread = NULL;
  35. hComm = INVALID_HANDLE_VALUE;
  36. }
  37. ///////////////////////////////////////////////////////////////////////
  38. // Destructor
  39. ///////////////////////////////////////////////////////////////////////
  40. DSISerialVCP::~DSISerialVCP()
  41. {
  42. Close();
  43. }
  44. ///////////////////////////////////////////////////////////////////////
  45. // Initializes and opens the object.
  46. ///////////////////////////////////////////////////////////////////////
  47. BOOL DSISerialVCP::AutoInit()
  48. {
  49. return FALSE; // unsupported
  50. }
  51. ///////////////////////////////////////////////////////////////////////
  52. // Initializes the object.
  53. ///////////////////////////////////////////////////////////////////////
  54. BOOL DSISerialVCP::Init(ULONG ulBaud_, UCHAR ucDeviceNumber_)
  55. {
  56. ulBaud = ulBaud_;
  57. ucDeviceNumber = ucDeviceNumber_; // make sure device number is in acceptable range for COM number translation
  58. return TRUE;
  59. }
  60. ///////////////////////////////////////////////////////////////////////
  61. // Opens port, starts receive thread.
  62. ///////////////////////////////////////////////////////////////////////
  63. BOOL DSISerialVCP::Open(void)
  64. {
  65. // Make sure all handles are reset before opening again.
  66. Close();
  67. if (pclCallback == NULL)
  68. return FALSE;
  69. bStopReceiveThread = FALSE;
  70. if(DSIThread_MutexInit(&stMutexCriticalSection) != DSI_THREAD_ENONE)
  71. {
  72. Close();
  73. return FALSE;
  74. }
  75. if(DSIThread_CondInit(&stEventReceiveThreadExit) != DSI_THREAD_ENONE)
  76. {
  77. DSIThread_MutexDestroy(&stMutexCriticalSection);
  78. Close();
  79. return FALSE;
  80. }
  81. //long enough to hold '\\.\COM255' and a null
  82. LPSTR lpstrComPort = new CHAR[11];
  83. SNPRINTF(lpstrComPort, 11, "\\\\.\\COM%u", ucDeviceNumber);
  84. hComm = CreateFile( lpstrComPort,
  85. GENERIC_READ | GENERIC_WRITE,
  86. 0,
  87. 0,
  88. OPEN_EXISTING,
  89. FILE_FLAG_OVERLAPPED,
  90. 0);
  91. //clean up after ourselves
  92. delete lpstrComPort;
  93. if (hComm == INVALID_HANDLE_VALUE)
  94. {
  95. DSIThread_CondDestroy(&stEventReceiveThreadExit);
  96. DSIThread_MutexDestroy(&stMutexCriticalSection);
  97. Close();
  98. return FALSE;
  99. }
  100. FillMemory(&dcb, sizeof(dcb), 0);
  101. dcb.DCBlength = sizeof(dcb);
  102. if (!GetCommState(hComm, &dcb))
  103. {
  104. DSIThread_CondDestroy(&stEventReceiveThreadExit);
  105. DSIThread_MutexDestroy(&stMutexCriticalSection);
  106. Close();
  107. return FALSE;
  108. }
  109. //if (!BuildCommDCB("57600,n,8,1", &dcb)) {
  110. // Couldn't build the DCB. Usually a problem
  111. // with the communications specification string.
  112. // return FALSE;
  113. //}
  114. dcb.BaudRate = ulBaud;
  115. dcb.ByteSize = 8;
  116. dcb.fParity = 0;
  117. dcb.Parity = 0;//NOPARITY; // no parity
  118. dcb.StopBits = 0;//ONESTOPBIT; // one stop bit
  119. dcb.fOutxCtsFlow = FALSE;
  120. dcb.fOutxDsrFlow = FALSE;
  121. dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
  122. if (!SetCommState(hComm, &dcb))
  123. {
  124. DSIThread_CondDestroy(&stEventReceiveThreadExit);
  125. DSIThread_MutexDestroy(&stMutexCriticalSection);
  126. Close();
  127. return FALSE;
  128. }
  129. COMMTIMEOUTS commTimeout;
  130. if (!GetCommTimeouts(hComm, &commTimeout))
  131. {
  132. DSIThread_CondDestroy(&stEventReceiveThreadExit);
  133. DSIThread_MutexDestroy(&stMutexCriticalSection);
  134. Close();
  135. return FALSE;
  136. }
  137. commTimeout.ReadIntervalTimeout = 0;
  138. commTimeout.ReadTotalTimeoutMultiplier = 0;
  139. commTimeout.ReadTotalTimeoutConstant = 0;
  140. if (!SetCommTimeouts(hComm, &commTimeout))
  141. {
  142. DSIThread_CondDestroy(&stEventReceiveThreadExit);
  143. DSIThread_MutexDestroy(&stMutexCriticalSection);
  144. Close();
  145. return FALSE;
  146. }
  147. hReceiveThread = DSIThread_CreateThread(&DSISerialVCP::ProcessThread, this);
  148. if(hReceiveThread == NULL)
  149. {
  150. DSIThread_MutexDestroy(&stMutexCriticalSection);
  151. DSIThread_CondDestroy(&stEventReceiveThreadExit);
  152. Close();
  153. return FALSE;
  154. }
  155. return TRUE;
  156. }
  157. ///////////////////////////////////////////////////////////////////////
  158. // Closes the USB connection, kills receive thread.
  159. ///////////////////////////////////////////////////////////////////////
  160. void DSISerialVCP::Close(BOOL /*bReset*/) //Commented to avoid compiler warning about unreferenced formal parameter.
  161. {
  162. if(hReceiveThread)
  163. {
  164. DSIThread_MutexLock(&stMutexCriticalSection);
  165. if(bStopReceiveThread == FALSE)
  166. {
  167. bStopReceiveThread = TRUE;
  168. if (DSIThread_CondTimedWait(&stEventReceiveThreadExit, &stMutexCriticalSection, 3000) != DSI_THREAD_ENONE)
  169. {
  170. // We were unable to stop the thread normally.
  171. DSIThread_DestroyThread(hReceiveThread);
  172. }
  173. }
  174. DSIThread_MutexUnlock(&stMutexCriticalSection);
  175. DSIThread_ReleaseThreadID(hReceiveThread);
  176. hReceiveThread = NULL;
  177. DSIThread_MutexDestroy(&stMutexCriticalSection);
  178. DSIThread_CondDestroy(&stEventReceiveThreadExit);
  179. }
  180. if (hComm != INVALID_HANDLE_VALUE)
  181. {
  182. // lower DTR
  183. //
  184. if (!EscapeCommFunction(hComm, CLRDTR))
  185. pclCallback->Error(255);
  186. //
  187. // restore original comm timeouts
  188. //
  189. //if (!SetCommTimeouts(COMDEV(TTYInfo), &(TIMEOUTSORIG(TTYInfo))))
  190. // pclCallback->Error(255);
  191. //
  192. // Purge reads/writes, input buffer and output buffer
  193. //
  194. if (!PurgeComm(hComm, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR))
  195. pclCallback->Error(255);
  196. CloseHandle(hComm);
  197. hComm = INVALID_HANDLE_VALUE;
  198. }
  199. return;
  200. }
  201. ///////////////////////////////////////////////////////////////////////
  202. // Writes ucSize_ bytes to USB, returns number of bytes not written.
  203. ///////////////////////////////////////////////////////////////////////
  204. BOOL DSISerialVCP::WriteBytes(void *pvData_, USHORT usSize_)
  205. {
  206. DWORD dwWritten;
  207. BOOL fRes;
  208. OVERLAPPED osWrite = {0};
  209. if(hComm == INVALID_HANDLE_VALUE || pvData_ == NULL)
  210. return FALSE;
  211. // Create this writes OVERLAPPED structure hEvent.
  212. osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  213. if (osWrite.hEvent == NULL)
  214. // Error creating overlapped event handle.
  215. return FALSE;
  216. // Issue write.
  217. if (!WriteFile(hComm, pvData_, (DWORD)usSize_, &dwWritten, &osWrite)) {
  218. if (GetLastError() != ERROR_IO_PENDING) {
  219. // WriteFile failed, but it isn't delayed. Report error and abort.
  220. fRes = FALSE;
  221. }
  222. else {
  223. // Write is pending.
  224. if (!GetOverlappedResult(hComm, &osWrite, &dwWritten, TRUE))
  225. fRes = FALSE;
  226. else
  227. // Write operation completed successfully.
  228. fRes = TRUE;
  229. }
  230. }
  231. else
  232. // WriteFile completed immediately.
  233. fRes = TRUE;
  234. CloseHandle(osWrite.hEvent);
  235. if (!fRes)
  236. pclCallback->Error(DSI_SERIAL_EWRITE);
  237. return fRes;
  238. }
  239. ///////////////////////////////////////////////////////////////////////
  240. // Returns the device serial number.
  241. ///////////////////////////////////////////////////////////////////////
  242. ULONG DSISerialVCP::GetDeviceSerialNumber()
  243. {
  244. return 0xFFFFFFFF; // unsupported
  245. }
  246. ///////////////////////////////////////////////////////////////////////
  247. // Returns the device port number.
  248. ///////////////////////////////////////////////////////////////////////
  249. UCHAR DSISerialVCP::GetDeviceNumber()
  250. {
  251. return ucDeviceNumber;
  252. }
  253. //////////////////////////////////////////////////////////////////////////////////
  254. // Private Methods
  255. //////////////////////////////////////////////////////////////////////////////////
  256. ///////////////////////////////////////////////////////////////////////
  257. void DSISerialVCP::ReceiveThread(void)
  258. {
  259. UCHAR ucRxByte;
  260. DWORD ulRxBytesRead;
  261. DWORD dwCommEvent;
  262. OVERLAPPED osRead = {0};
  263. // while (hComm == INVALID_HANDLE_VALUE);
  264. if (!SetCommMask(hComm, EV_RXCHAR))
  265. pclCallback->Error(DSI_SERIAL_EREAD);
  266. while(!bStopReceiveThread)
  267. {
  268. if (WaitCommEvent(hComm, &dwCommEvent, NULL))
  269. {
  270. do
  271. {
  272. osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  273. if (osRead.hEvent == NULL) // Error creating overlapped event handle.
  274. break;
  275. if (ReadFile(hComm, &ucRxByte, 1, &ulRxBytesRead, &osRead))
  276. {
  277. pclCallback->ProcessByte(ucRxByte);
  278. }
  279. else
  280. {
  281. if (GetLastError() != ERROR_IO_PENDING)
  282. pclCallback->Error(DSI_SERIAL_EREAD);
  283. else
  284. {
  285. DWORD hRes;
  286. do
  287. {
  288. hRes = WaitForSingleObject(osRead.hEvent, 999);
  289. } while (hRes == WAIT_TIMEOUT);
  290. if (hRes == WAIT_OBJECT_0)
  291. {
  292. if (!GetOverlappedResult(hComm, &osRead, &ulRxBytesRead, TRUE))
  293. pclCallback->Error(DSI_SERIAL_EREAD);
  294. else
  295. pclCallback->ProcessByte(ucRxByte);
  296. }
  297. }
  298. }
  299. CloseHandle(osRead.hEvent);
  300. } while (ulRxBytesRead);
  301. }
  302. else
  303. {
  304. pclCallback->Error(DSI_SERIAL_EREAD);
  305. }
  306. }
  307. DSIThread_MutexLock(&stMutexCriticalSection);
  308. bStopReceiveThread = TRUE;
  309. DSIThread_CondSignal(&stEventReceiveThreadExit); // Set an event to alert the main process that Rx thread is finished and can be closed.
  310. DSIThread_MutexUnlock(&stMutexCriticalSection);
  311. }
  312. ///////////////////////////////////////////////////////////////////////
  313. DSI_THREAD_RETURN DSISerialVCP::ProcessThread(void *pvParameter_)
  314. {
  315. DSISerialVCP *This = (DSISerialVCP *) pvParameter_;
  316. This->ReceiveThread();
  317. return 0;
  318. }
  319. #endif //defined(DSI_TYPES_WINDOWS)