candle.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. /*
  2. Copyright (c) 2016 Hubert Denkmair <hubert@denkmair.de>
  3. This file is part of the candle windows API.
  4. This library is free software: you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation, either
  7. version 3 of the License, or (at your option) any later version.
  8. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with this library. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #include "candle.h"
  16. #include <stdlib.h>
  17. #include "candle_defs.h"
  18. #include "candle_ctrl_req.h"
  19. #include "ch_9.h"
  20. static bool candle_dev_interal_open(candle_handle hdev);
  21. static bool candle_read_di(HDEVINFO hdi, SP_DEVICE_INTERFACE_DATA interfaceData, candle_device_t *dev)
  22. {
  23. /* get required length first (this call always fails with an error) */
  24. ULONG requiredLength=0;
  25. SetupDiGetDeviceInterfaceDetail(hdi, &interfaceData, NULL, 0, &requiredLength, NULL);
  26. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  27. dev->last_error = CANDLE_ERR_SETUPDI_IF_DETAILS;
  28. return false;
  29. }
  30. PSP_DEVICE_INTERFACE_DETAIL_DATA detail_data =
  31. (PSP_DEVICE_INTERFACE_DETAIL_DATA) LocalAlloc(LMEM_FIXED, requiredLength);
  32. if (detail_data != NULL) {
  33. detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
  34. } else {
  35. dev->last_error = CANDLE_ERR_MALLOC;
  36. return false;
  37. }
  38. bool retval = true;
  39. ULONG length = requiredLength;
  40. if (!SetupDiGetDeviceInterfaceDetail(hdi, &interfaceData, detail_data, length, &requiredLength, NULL) ) {
  41. dev->last_error = CANDLE_ERR_SETUPDI_IF_DETAILS2;
  42. retval = false;
  43. } else if (FAILED(StringCchCopy(dev->path, sizeof(dev->path), detail_data->DevicePath))) {
  44. dev->last_error = CANDLE_ERR_PATH_LEN;
  45. retval = false;
  46. }
  47. LocalFree(detail_data);
  48. if (!retval) {
  49. return false;
  50. }
  51. /* try to open to read device infos and see if it is avail */
  52. if (candle_dev_interal_open(dev)) {
  53. dev->state = CANDLE_DEVSTATE_AVAIL;
  54. candle_dev_close(dev);
  55. } else {
  56. dev->state = CANDLE_DEVSTATE_INUSE;
  57. }
  58. dev->last_error = CANDLE_ERR_OK;
  59. return true;
  60. }
  61. bool __stdcall candle_list_scan(candle_list_handle *list)
  62. {
  63. if (list==NULL) {
  64. return false;
  65. }
  66. candle_list_t *l = (candle_list_t *)calloc(1, sizeof(candle_list_t));
  67. *list = l;
  68. if (l==NULL) {
  69. return false;
  70. }
  71. GUID guid;
  72. if (CLSIDFromString(L"{c15b4308-04d3-11e6-b3ea-6057189e6443}", &guid) != NOERROR) {
  73. l->last_error = CANDLE_ERR_CLSID;
  74. return false;
  75. }
  76. HDEVINFO hdi = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
  77. if (hdi == INVALID_HANDLE_VALUE) {
  78. l->last_error = CANDLE_ERR_GET_DEVICES;
  79. return false;
  80. }
  81. bool rv = false;
  82. for (unsigned i=0; i<CANDLE_MAX_DEVICES; i++) {
  83. SP_DEVICE_INTERFACE_DATA interfaceData;
  84. interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  85. if (SetupDiEnumDeviceInterfaces(hdi, NULL, &guid, i, &interfaceData)) {
  86. if (!candle_read_di(hdi, interfaceData, &l->dev[i])) {
  87. l->last_error = l->dev[i].last_error;
  88. rv = false;
  89. break;
  90. }
  91. } else {
  92. DWORD err = GetLastError();
  93. if (err==ERROR_NO_MORE_ITEMS) {
  94. l->num_devices = i;
  95. l->last_error = CANDLE_ERR_OK;
  96. rv = true;
  97. } else {
  98. l->last_error = CANDLE_ERR_SETUPDI_IF_ENUM;
  99. rv = false;
  100. }
  101. break;
  102. }
  103. }
  104. SetupDiDestroyDeviceInfoList(hdi);
  105. return rv;
  106. }
  107. bool __stdcall DLL candle_list_free(candle_list_handle list)
  108. {
  109. free(list);
  110. return true;
  111. }
  112. bool __stdcall DLL candle_list_length(candle_list_handle list, uint8_t *len)
  113. {
  114. candle_list_t *l = (candle_list_t *)list;
  115. *len = l->num_devices;
  116. return true;
  117. }
  118. bool __stdcall DLL candle_dev_get(candle_list_handle list, uint8_t dev_num, candle_handle *hdev)
  119. {
  120. candle_list_t *l = (candle_list_t *)list;
  121. if (l==NULL) {
  122. return false;
  123. }
  124. if (dev_num >= CANDLE_MAX_DEVICES) {
  125. l->last_error = CANDLE_ERR_DEV_OUT_OF_RANGE;
  126. return false;
  127. }
  128. candle_device_t *dev = calloc(1, sizeof(candle_device_t));
  129. *hdev = dev;
  130. if (dev==NULL) {
  131. l->last_error = CANDLE_ERR_MALLOC;
  132. return false;
  133. }
  134. memcpy(dev, &l->dev[dev_num], sizeof(candle_device_t));
  135. l->last_error = CANDLE_ERR_OK;
  136. dev->last_error = CANDLE_ERR_OK;
  137. return true;
  138. }
  139. bool __stdcall DLL candle_dev_get_state(candle_handle hdev, candle_devstate_t *state)
  140. {
  141. if (hdev==NULL) {
  142. return false;
  143. } else {
  144. candle_device_t *dev = (candle_device_t*)hdev;
  145. *state = dev->state;
  146. return true;
  147. }
  148. }
  149. wchar_t __stdcall DLL *candle_dev_get_path(candle_handle hdev)
  150. {
  151. if (hdev==NULL) {
  152. return NULL;
  153. } else {
  154. candle_device_t *dev = (candle_device_t*)hdev;
  155. return dev->path;
  156. }
  157. }
  158. static bool candle_dev_interal_open(candle_handle hdev)
  159. {
  160. candle_device_t *dev = (candle_device_t*)hdev;
  161. memset(dev->rxevents, 0, sizeof(dev->rxevents));
  162. memset(dev->rxurbs, 0, sizeof(dev->rxurbs));
  163. dev->deviceHandle = CreateFile(
  164. dev->path,
  165. GENERIC_WRITE | GENERIC_READ,
  166. FILE_SHARE_WRITE | FILE_SHARE_READ,
  167. NULL,
  168. OPEN_EXISTING,
  169. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
  170. NULL
  171. );
  172. if (dev->deviceHandle == INVALID_HANDLE_VALUE) {
  173. dev->last_error = CANDLE_ERR_CREATE_FILE;
  174. return false;
  175. }
  176. if (!WinUsb_Initialize(dev->deviceHandle, &dev->winUSBHandle)) {
  177. dev->last_error = CANDLE_ERR_WINUSB_INITIALIZE;
  178. goto close_handle;
  179. }
  180. USB_INTERFACE_DESCRIPTOR ifaceDescriptor;
  181. if (!WinUsb_QueryInterfaceSettings(dev->winUSBHandle, 0, &ifaceDescriptor)) {
  182. dev->last_error = CANDLE_ERR_QUERY_INTERFACE;
  183. goto winusb_free;
  184. }
  185. dev->interfaceNumber = ifaceDescriptor.bInterfaceNumber;
  186. unsigned pipes_found = 0;
  187. for (uint8_t i=0; i<ifaceDescriptor.bNumEndpoints; i++) {
  188. WINUSB_PIPE_INFORMATION pipeInfo;
  189. if (!WinUsb_QueryPipe(dev->winUSBHandle, 0, i, &pipeInfo)) {
  190. dev->last_error = CANDLE_ERR_QUERY_PIPE;
  191. goto winusb_free;
  192. }
  193. if (pipeInfo.PipeType == UsbdPipeTypeBulk && USB_ENDPOINT_DIRECTION_IN(pipeInfo.PipeId)) {
  194. dev->bulkInPipe = pipeInfo.PipeId;
  195. pipes_found++;
  196. } else if (pipeInfo.PipeType == UsbdPipeTypeBulk && USB_ENDPOINT_DIRECTION_OUT(pipeInfo.PipeId)) {
  197. dev->bulkOutPipe = pipeInfo.PipeId;
  198. pipes_found++;
  199. } else {
  200. dev->last_error = CANDLE_ERR_PARSE_IF_DESCR;
  201. goto winusb_free;
  202. }
  203. }
  204. if (pipes_found != 2) {
  205. dev->last_error = CANDLE_ERR_PARSE_IF_DESCR;
  206. goto winusb_free;
  207. }
  208. char use_raw_io = 1;
  209. if (!WinUsb_SetPipePolicy(dev->winUSBHandle, dev->bulkInPipe, RAW_IO, sizeof(use_raw_io), &use_raw_io)) {
  210. dev->last_error = CANDLE_ERR_SET_PIPE_RAW_IO;
  211. goto winusb_free;
  212. }
  213. if (!candle_ctrl_set_host_format(dev)) {
  214. goto winusb_free;
  215. }
  216. if (!candle_ctrl_get_config(dev, &dev->dconf)) {
  217. goto winusb_free;
  218. }
  219. if (!candle_ctrl_get_capability(dev, 0, &dev->bt_const)) {
  220. dev->last_error = CANDLE_ERR_GET_BITTIMING_CONST;
  221. goto winusb_free;
  222. }
  223. dev->last_error = CANDLE_ERR_OK;
  224. return true;
  225. winusb_free:
  226. WinUsb_Free(dev->winUSBHandle);
  227. close_handle:
  228. CloseHandle(dev->deviceHandle);
  229. return false;
  230. }
  231. static bool candle_prepare_read(candle_device_t *dev, unsigned urb_num)
  232. {
  233. bool rc = WinUsb_ReadPipe(
  234. dev->winUSBHandle,
  235. dev->bulkInPipe,
  236. dev->rxurbs[urb_num].buf,
  237. sizeof(dev->rxurbs[urb_num].buf),
  238. NULL,
  239. &dev->rxurbs[urb_num].ovl
  240. );
  241. if (rc || (GetLastError()!=ERROR_IO_PENDING)) {
  242. dev->last_error = CANDLE_ERR_PREPARE_READ;
  243. return false;
  244. } else {
  245. dev->last_error = CANDLE_ERR_OK;
  246. return true;
  247. }
  248. }
  249. static bool candle_close_rxurbs(candle_device_t *dev)
  250. {
  251. for (unsigned i=0; i<CANDLE_URB_COUNT; i++) {
  252. if (dev->rxevents[i] != NULL) {
  253. CloseHandle(dev->rxevents[i]);
  254. }
  255. }
  256. return true;
  257. }
  258. bool __stdcall DLL candle_dev_open(candle_handle hdev)
  259. {
  260. candle_device_t *dev = (candle_device_t*)hdev;
  261. if (candle_dev_interal_open(dev)) {
  262. for (unsigned i=0; i<CANDLE_URB_COUNT; i++) {
  263. HANDLE ev = CreateEvent(NULL, true, false, NULL);
  264. dev->rxevents[i] = ev;
  265. dev->rxurbs[i].ovl.hEvent = ev;
  266. if (!candle_prepare_read(dev, i)) {
  267. candle_close_rxurbs(dev);
  268. return false; // keep last_error from prepare_read call
  269. }
  270. }
  271. dev->last_error = CANDLE_ERR_OK;
  272. return true;
  273. } else {
  274. return false; // keep last_error from open_device call
  275. }
  276. }
  277. bool __stdcall DLL candle_dev_get_timestamp_us(candle_handle hdev, uint32_t *timestamp_us)
  278. {
  279. return candle_ctrl_get_timestamp(hdev, timestamp_us);
  280. }
  281. bool __stdcall DLL candle_dev_close(candle_handle hdev)
  282. {
  283. candle_device_t *dev = (candle_device_t*)hdev;
  284. candle_close_rxurbs(dev);
  285. WinUsb_Free(dev->winUSBHandle);
  286. dev->winUSBHandle = NULL;
  287. CloseHandle(dev->deviceHandle);
  288. dev->deviceHandle = NULL;
  289. dev->last_error = CANDLE_ERR_OK;
  290. return true;
  291. }
  292. bool __stdcall DLL candle_dev_free(candle_handle hdev)
  293. {
  294. free(hdev);
  295. return true;
  296. }
  297. candle_err_t __stdcall DLL candle_dev_last_error(candle_handle hdev)
  298. {
  299. candle_device_t *dev = (candle_device_t*)hdev;
  300. return dev->last_error;
  301. }
  302. bool __stdcall DLL candle_channel_count(candle_handle hdev, uint8_t *num_channels)
  303. {
  304. // TODO check if info was already read from device; try to do so; throw error...
  305. candle_device_t *dev = (candle_device_t*)hdev;
  306. *num_channels = dev->dconf.icount+1;
  307. return true;
  308. }
  309. bool __stdcall DLL candle_channel_get_capabilities(candle_handle hdev, uint8_t ch, candle_capability_t *cap)
  310. {
  311. // TODO check if info was already read from device; try to do so; throw error...
  312. candle_device_t *dev = (candle_device_t*)hdev;
  313. memcpy(cap, &dev->bt_const.feature, sizeof(candle_capability_t));
  314. return true;
  315. }
  316. bool __stdcall DLL candle_channel_set_timing(candle_handle hdev, uint8_t ch, candle_bittiming_t *data)
  317. {
  318. // TODO ensure device is open, check channel count..
  319. candle_device_t *dev = (candle_device_t*)hdev;
  320. return candle_ctrl_set_bittiming(dev, ch, data);
  321. }
  322. bool __stdcall DLL candle_channel_set_bitrate(candle_handle hdev, uint8_t ch, uint32_t bitrate)
  323. {
  324. // TODO ensure device is open, check channel count..
  325. candle_device_t *dev = (candle_device_t*)hdev;
  326. if (dev->bt_const.fclk_can != 48000000) {
  327. /* this function only works for the candleLight base clock of 48MHz */
  328. dev->last_error = CANDLE_ERR_BITRATE_FCLK;
  329. return false;
  330. }
  331. candle_bittiming_t t;
  332. t.prop_seg = 1;
  333. t.sjw = 1;
  334. t.phase_seg1 = 13 - t.prop_seg;
  335. t.phase_seg2 = 2;
  336. switch (bitrate) {
  337. case 10000:
  338. t.brp = 300;
  339. break;
  340. case 20000:
  341. t.brp = 150;
  342. break;
  343. case 50000:
  344. t.brp = 60;
  345. break;
  346. case 83333:
  347. t.brp = 36;
  348. break;
  349. case 100000:
  350. t.brp = 30;
  351. break;
  352. case 125000:
  353. t.brp = 24;
  354. break;
  355. case 250000:
  356. t.brp = 12;
  357. break;
  358. case 500000:
  359. t.brp = 6;
  360. break;
  361. case 800000:
  362. t.brp = 4;
  363. t.phase_seg1 = 12 - t.prop_seg;
  364. t.phase_seg2 = 2;
  365. break;
  366. case 1000000:
  367. t.brp = 3;
  368. break;
  369. default:
  370. dev->last_error = CANDLE_ERR_BITRATE_UNSUPPORTED;
  371. return false;
  372. }
  373. return candle_ctrl_set_bittiming(dev, ch, &t);
  374. }
  375. bool __stdcall DLL candle_channel_start(candle_handle hdev, uint8_t ch, uint32_t flags)
  376. {
  377. // TODO ensure device is open, check channel count..
  378. candle_device_t *dev = (candle_device_t*)hdev;
  379. flags |= CANDLE_MODE_HW_TIMESTAMP;
  380. return candle_ctrl_set_device_mode(dev, ch, CANDLE_DEVMODE_START, flags);
  381. }
  382. bool __stdcall DLL candle_channel_stop(candle_handle hdev, uint8_t ch)
  383. {
  384. // TODO ensure device is open, check channel count..
  385. candle_device_t *dev = (candle_device_t*)hdev;
  386. return candle_ctrl_set_device_mode(dev, ch, CANDLE_DEVMODE_RESET, 0);
  387. }
  388. bool __stdcall DLL candle_frame_send(candle_handle hdev, uint8_t ch, candle_frame_t *frame)
  389. {
  390. // TODO ensure device is open, check channel count..
  391. candle_device_t *dev = (candle_device_t*)hdev;
  392. unsigned long bytes_sent = 0;
  393. frame->echo_id = 0;
  394. frame->channel = ch;
  395. bool rc = WinUsb_WritePipe(
  396. dev->winUSBHandle,
  397. dev->bulkOutPipe,
  398. (uint8_t*)frame,
  399. sizeof(*frame),
  400. &bytes_sent,
  401. 0
  402. );
  403. dev->last_error = rc ? CANDLE_ERR_OK : CANDLE_ERR_SEND_FRAME;
  404. return rc;
  405. }
  406. bool __stdcall DLL candle_frame_read(candle_handle hdev, candle_frame_t *frame, uint32_t timeout_ms)
  407. {
  408. // TODO ensure device is open..
  409. candle_device_t *dev = (candle_device_t*)hdev;
  410. DWORD wait_result = WaitForMultipleObjects(CANDLE_URB_COUNT, dev->rxevents, false, timeout_ms);
  411. if (wait_result == WAIT_TIMEOUT) {
  412. dev->last_error = CANDLE_ERR_READ_TIMEOUT;
  413. return false;
  414. }
  415. if ( (wait_result < WAIT_OBJECT_0) || (wait_result >= WAIT_OBJECT_0 + CANDLE_URB_COUNT) ) {
  416. dev->last_error = CANDLE_ERR_READ_WAIT;
  417. return false;
  418. }
  419. DWORD urb_num = wait_result - WAIT_OBJECT_0;
  420. DWORD bytes_transfered;
  421. if (!WinUsb_GetOverlappedResult(dev->winUSBHandle, &dev->rxurbs[urb_num].ovl, &bytes_transfered, false)) {
  422. candle_prepare_read(dev, urb_num);
  423. dev->last_error = CANDLE_ERR_READ_RESULT;
  424. return false;
  425. }
  426. if (bytes_transfered < sizeof(*frame)-4) {
  427. candle_prepare_read(dev, urb_num);
  428. dev->last_error = CANDLE_ERR_READ_SIZE;
  429. return false;
  430. }
  431. if (bytes_transfered < sizeof(*frame)) {
  432. frame->timestamp_us = 0;
  433. }
  434. memcpy(frame, dev->rxurbs[urb_num].buf, sizeof(*frame));
  435. return candle_prepare_read(dev, urb_num);
  436. }
  437. candle_frametype_t __stdcall DLL candle_frame_type(candle_frame_t *frame)
  438. {
  439. if (frame->echo_id != 0xFFFFFFFF) {
  440. return CANDLE_FRAMETYPE_ECHO;
  441. };
  442. if (frame->can_id & CANDLE_ID_ERR) {
  443. return CANDLE_FRAMETYPE_ERROR;
  444. }
  445. return CANDLE_FRAMETYPE_RECEIVE;
  446. }
  447. uint32_t __stdcall DLL candle_frame_id(candle_frame_t *frame)
  448. {
  449. return frame->can_id & 0x1FFFFFFF;
  450. }
  451. bool __stdcall DLL candle_frame_is_extended_id(candle_frame_t *frame)
  452. {
  453. return (frame->can_id & CANDLE_ID_EXTENDED) != 0;
  454. }
  455. bool __stdcall DLL candle_frame_is_rtr(candle_frame_t *frame)
  456. {
  457. return (frame->can_id & CANDLE_ID_RTR) != 0;
  458. }
  459. uint8_t __stdcall DLL candle_frame_dlc(candle_frame_t *frame)
  460. {
  461. return frame->can_dlc;
  462. }
  463. uint8_t __stdcall DLL *candle_frame_data(candle_frame_t *frame)
  464. {
  465. return frame->data;
  466. }
  467. uint32_t __stdcall DLL candle_frame_timestamp_us(candle_frame_t *frame)
  468. {
  469. return frame->timestamp_us;
  470. }