dsi_serial_si.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  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_si.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. DSISerialSI::DSISerialSI()
  33. {
  34. hReceiveThread = NULL;
  35. pclDeviceHandle = NULL;
  36. }
  37. ///////////////////////////////////////////////////////////////////////
  38. // Destructor
  39. ///////////////////////////////////////////////////////////////////////
  40. DSISerialSI::~DSISerialSI()
  41. {
  42. Close();
  43. }
  44. ///////////////////////////////////////////////////////////////////////
  45. // Initializes and opens the object.
  46. ///////////////////////////////////////////////////////////////////////
  47. //defines used by AutoInit
  48. //#define USB_ANT_VID 0x0FCF
  49. //#define USB_ANT_PID 0x1004
  50. #define USB_ANT_PRODUCT_DESCRIPTION "ANT USB Stick"
  51. #define DEFAULT_BAUD_RATE ((USHORT) 50000)
  52. BOOL DSISerialSI::AutoInit()
  53. {
  54. if(Init(DEFAULT_BAUD_RATE, (void*)USB_ANT_PRODUCT_DESCRIPTION,(USHORT) strlen(USB_ANT_PRODUCT_DESCRIPTION)) == FALSE)
  55. {
  56. this->USBReset();
  57. return FALSE;
  58. }
  59. return TRUE;
  60. }
  61. ///////////////////////////////////////////////////////////////////////
  62. // Initializes the object.
  63. ///////////////////////////////////////////////////////////////////////
  64. BOOL DSISerialSI::Init(ULONG ulBaud_, UCHAR ucDeviceNumber_)
  65. {
  66. Close();
  67. ulBaud = ulBaud_;
  68. ucDeviceNumber = ucDeviceNumber_;
  69. return TRUE;
  70. }
  71. ///////////////////////////////////////////////////////////////////////
  72. // Initializes the object.
  73. ///////////////////////////////////////////////////////////////////////
  74. BOOL DSISerialSI::Init(ULONG ulBaud_, void *pvProductDescription_, USHORT usSize_)
  75. {
  76. UCHAR ucDeviceNumberTemp;
  77. Close();
  78. BOOL bSuccess = GetDeviceNumberByProductDescription(pvProductDescription_, usSize_, ucDeviceNumberTemp);
  79. if(!bSuccess)
  80. {
  81. Close();
  82. return FALSE;
  83. }
  84. ulBaud = ulBaud_;
  85. ucDeviceNumber = ucDeviceNumberTemp;
  86. return TRUE;
  87. }
  88. ///////////////////////////////////////////////////////////////////////
  89. // Initializes the object.
  90. ///////////////////////////////////////////////////////////////////////
  91. BOOL DSISerialSI::Init(ULONG ulBaud_, const USBDeviceSI& clDevice_)
  92. {
  93. Close();
  94. ulBaud = ulBaud_;
  95. ucDeviceNumber = clDevice_.GetDeviceNumber();
  96. return TRUE;
  97. }
  98. ///////////////////////////////////////////////////////////////////////
  99. // Returns the device serial number.
  100. ///////////////////////////////////////////////////////////////////////
  101. ULONG DSISerialSI::GetDeviceSerialNumber()
  102. {
  103. if(pclDeviceHandle == 0)
  104. return 0;
  105. return pclDeviceHandle->GetDevice().GetSerialNumber();
  106. }
  107. ///////////////////////////////////////////////////////////////////////
  108. // Returns the number of SILabs devices connected.
  109. // Returns 0 on error.
  110. ///////////////////////////////////////////////////////////////////////
  111. UCHAR DSISerialSI::GetNumberOfDevices()
  112. {
  113. return USBDeviceHandleSI::GetNumberOfDevices();
  114. }
  115. ///////////////////////////////////////////////////////////////////////
  116. // Get USB enumeration info. Not necessarily connected to USB.
  117. ///////////////////////////////////////////////////////////////////////
  118. BOOL DSISerialSI::GetDeviceUSBInfo(UCHAR ucDevice_, UCHAR* pucProductString_, UCHAR* pucSerialString_, USHORT usBufferSize_)
  119. {
  120. const USBDeviceListSI clDeviceList = USBDeviceHandleSI::GetAllDevices();
  121. if(clDeviceList.GetSize() <= ucDevice_)
  122. return FALSE;
  123. if(clDeviceList[ucDevice_]->GetProductDescription(pucProductString_, usBufferSize_) != TRUE)
  124. return FALSE;
  125. if(clDeviceList[ucDevice_]->GetSerialString(pucSerialString_, usBufferSize_) != TRUE)
  126. return FALSE;
  127. return TRUE;
  128. }
  129. ///////////////////////////////////////////////////////////////////////
  130. // Get USB PID. Need to be connected to USB device.
  131. ///////////////////////////////////////////////////////////////////////
  132. BOOL DSISerialSI::GetDevicePID(USHORT& usPid_)
  133. {
  134. if(pclDeviceHandle == NULL)
  135. return FALSE;
  136. usPid_ = pclDeviceHandle->GetDevice().GetPid();
  137. return TRUE;
  138. }
  139. ///////////////////////////////////////////////////////////////////////
  140. // Get USB VID. Need to be connected to USB device.
  141. ///////////////////////////////////////////////////////////////////////
  142. BOOL DSISerialSI::GetDeviceVID(USHORT& usVid_)
  143. {
  144. if(pclDeviceHandle == NULL)
  145. return FALSE;
  146. usVid_ = pclDeviceHandle->GetDevice().GetVid();
  147. return TRUE;
  148. }
  149. ///////////////////////////////////////////////////////////////////////
  150. // Opens port, starts receive thread.
  151. ///////////////////////////////////////////////////////////////////////
  152. BOOL DSISerialSI::Open(void)
  153. {
  154. // Make sure all handles are reset before opening again.
  155. Close();
  156. if (pclCallback == NULL)
  157. return FALSE;
  158. bStopReceiveThread = FALSE;
  159. const USBDeviceListSI clDeviceList = USBDeviceHandleSI::GetAllDevices();
  160. if(clDeviceList.GetSize() <= ucDeviceNumber)
  161. return FALSE;
  162. if(USBDeviceHandleSI::Open(*(clDeviceList[ucDeviceNumber]), pclDeviceHandle, ulBaud) == FALSE)
  163. {
  164. pclDeviceHandle = NULL;
  165. Close();
  166. return FALSE;
  167. }
  168. if(DSIThread_MutexInit(&stMutexCriticalSection) != DSI_THREAD_ENONE)
  169. {
  170. Close();
  171. return FALSE;
  172. }
  173. if(DSIThread_CondInit(&stEventReceiveThreadExit) != DSI_THREAD_ENONE)
  174. {
  175. DSIThread_MutexDestroy(&stMutexCriticalSection);
  176. Close();
  177. return FALSE;
  178. }
  179. hReceiveThread = DSIThread_CreateThread(&DSISerialSI::ProcessThread, this);
  180. if(hReceiveThread == NULL)
  181. {
  182. DSIThread_MutexDestroy(&stMutexCriticalSection);
  183. DSIThread_CondDestroy(&stEventReceiveThreadExit);
  184. Close();
  185. return FALSE;
  186. }
  187. return TRUE;
  188. }
  189. ///////////////////////////////////////////////////////////////////////
  190. // Closes the USB connection, kills receive thread.
  191. ///////////////////////////////////////////////////////////////////////
  192. void DSISerialSI::Close(BOOL bReset_)
  193. {
  194. if(hReceiveThread)
  195. {
  196. DSIThread_MutexLock(&stMutexCriticalSection);
  197. if(bStopReceiveThread == FALSE)
  198. {
  199. bStopReceiveThread = TRUE;
  200. if (DSIThread_CondTimedWait(&stEventReceiveThreadExit, &stMutexCriticalSection, 3000) != DSI_THREAD_ENONE)
  201. {
  202. // We were unable to stop the thread normally.
  203. DSIThread_DestroyThread(hReceiveThread);
  204. }
  205. }
  206. DSIThread_MutexUnlock(&stMutexCriticalSection);
  207. DSIThread_ReleaseThreadID(hReceiveThread);
  208. hReceiveThread = NULL;
  209. DSIThread_MutexDestroy(&stMutexCriticalSection);
  210. DSIThread_CondDestroy(&stEventReceiveThreadExit);
  211. }
  212. if(pclDeviceHandle)
  213. {
  214. USBDeviceHandleSI::Close(pclDeviceHandle, bReset_);
  215. if(bReset_)
  216. DSIThread_Sleep(1750); //Stall to allow the device to reset, trying to reopen the driver too soon can cause bad things to happen.
  217. pclDeviceHandle = NULL;
  218. }
  219. return;
  220. }
  221. ///////////////////////////////////////////////////////////////////////
  222. // Writes ucSize_ bytes to USB, returns number of bytes not written.
  223. ///////////////////////////////////////////////////////////////////////
  224. BOOL DSISerialSI::WriteBytes(void *pvData_, USHORT usSize_)
  225. {
  226. ULONG ulActualWritten = 0;
  227. if(pclDeviceHandle == NULL || pvData_ == NULL)
  228. return FALSE;
  229. if(pclDeviceHandle->Write(pvData_, usSize_, ulActualWritten) != USBError::NONE)
  230. {
  231. pclCallback->Error(DSI_SERIAL_EWRITE);
  232. return FALSE;
  233. }
  234. return TRUE;
  235. }
  236. ///////////////////////////////////////////////////////////////////////
  237. // Returns the device port number.
  238. ///////////////////////////////////////////////////////////////////////
  239. UCHAR DSISerialSI::GetDeviceNumber()
  240. {
  241. return ucDeviceNumber;
  242. }
  243. //////////////////////////////////////////////////////////////////////////////////
  244. // Private Methods
  245. //////////////////////////////////////////////////////////////////////////////////
  246. ///////////////////////////////////////////////////////////////////////
  247. void DSISerialSI::ReceiveThread(void)
  248. {
  249. UCHAR ucRxByte;
  250. ULONG ulRxBytesRead;
  251. while(!bStopReceiveThread)
  252. {
  253. USBError::Enum eStatus = pclDeviceHandle->Read(&ucRxByte, 1, ulRxBytesRead, 1000);
  254. switch(eStatus)
  255. {
  256. case USBError::NONE:
  257. pclCallback->ProcessByte(ucRxByte);
  258. break;
  259. case USBError::DEVICE_GONE:
  260. pclCallback->Error(DSI_SERIAL_DEVICE_GONE);
  261. bStopReceiveThread = TRUE;
  262. break;
  263. case USBError::TIMED_OUT:
  264. break;
  265. default:
  266. pclCallback->Error(DSI_SERIAL_EREAD);
  267. bStopReceiveThread = TRUE;
  268. break;
  269. }
  270. }
  271. DSIThread_MutexLock(&stMutexCriticalSection);
  272. bStopReceiveThread = TRUE;
  273. DSIThread_CondSignal(&stEventReceiveThreadExit); // Set an event to alert the main process that Rx thread is finished and can be closed.
  274. DSIThread_MutexUnlock(&stMutexCriticalSection);
  275. }
  276. ///////////////////////////////////////////////////////////////////////
  277. DSI_THREAD_RETURN DSISerialSI::ProcessThread(void *pvParameter_)
  278. {
  279. DSISerialSI *This = (DSISerialSI *) pvParameter_;
  280. This->ReceiveThread();
  281. return 0;
  282. }
  283. ///////////////////////////////////////////////////////////////////////
  284. // Finds the first availible device that matches the product
  285. // description and returns the device number.
  286. //
  287. // Assumes SiDLL functions are loaded.
  288. ///////////////////////////////////////////////////////////////////////
  289. BOOL DSISerialSI::GetDeviceNumberByProductDescription(void* pvProductDescription_, USHORT usSize_, UCHAR& ucDeviceNumber_)
  290. {
  291. const USBDeviceListSI clDeviceList = USBDeviceHandleSI::GetAvailableDevices();
  292. if(clDeviceList.GetSize() == 0)
  293. {
  294. Close();
  295. return FALSE;
  296. }
  297. ULONG ulNumOfDevices = clDeviceList.GetSize();
  298. BOOL bDeviceFound = FALSE;
  299. for(ULONG i=0; i<ulNumOfDevices && !bDeviceFound; i++)
  300. {
  301. const USBDeviceSI& clDevice = *(clDeviceList[i]);
  302. UCHAR aucDescription[SI_MAX_DEVICE_STRLEN];
  303. if(clDevice.GetProductDescription(aucDescription, sizeof(aucDescription)))
  304. {
  305. if(strncmp((const char*)aucDescription, (char*)pvProductDescription_, MIN(strlen((const char*)aucDescription), usSize_)) != 0)
  306. continue;
  307. }
  308. USBDeviceHandleSI* pclTempHandle;
  309. if(USBDeviceHandleSI::Open(clDevice, pclTempHandle, 0) == FALSE)
  310. continue;
  311. USBDeviceHandleSI::Close(pclTempHandle);
  312. ucDeviceNumber_ = (UCHAR)i;
  313. bDeviceFound = TRUE;
  314. }
  315. return bDeviceFound;
  316. }
  317. void DSISerialSI::USBReset(void)
  318. {
  319. #if defined(_MSC_VER)
  320. // !! Borland builder chokes on cfgmgr32
  321. TCHAR line1[64];
  322. TCHAR* argv_[2];
  323. //Only do the soft reset if we fail to open a device or it seems like theres no deivces to open (device in a "hosed" state)
  324. //The soft reset will have no effect on devices currently opened by other applications.
  325. argv_[0] = line1;
  326. SNPRINTF(&(line1[0]),sizeof(line1), "@USB\\VID_0FCF&PID_1004\\*"); //The string for all ANT USB Sticks
  327. WinDevice_Disable(1,argv_);
  328. WinDevice_Enable(1,argv_);
  329. #endif
  330. }
  331. #endif //defined(DSI_TYPES_WINDOWS)