123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589 |
- /*
- Copyright (c) 2016 Hubert Denkmair <hubert@denkmair.de>
- This file is part of the candle windows API.
-
- This library is free software: you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation, either
- version 3 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
- #include "candle.h"
- #include <stdlib.h>
- #include "candle_defs.h"
- #include "candle_ctrl_req.h"
- #include "ch_9.h"
- static bool candle_dev_interal_open(candle_handle hdev);
- static bool candle_read_di(HDEVINFO hdi, SP_DEVICE_INTERFACE_DATA interfaceData, candle_device_t *dev)
- {
- /* get required length first (this call always fails with an error) */
- ULONG requiredLength=0;
- SetupDiGetDeviceInterfaceDetail(hdi, &interfaceData, NULL, 0, &requiredLength, NULL);
- if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
- dev->last_error = CANDLE_ERR_SETUPDI_IF_DETAILS;
- return false;
- }
- PSP_DEVICE_INTERFACE_DETAIL_DATA detail_data =
- (PSP_DEVICE_INTERFACE_DETAIL_DATA) LocalAlloc(LMEM_FIXED, requiredLength);
- if (detail_data != NULL) {
- detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
- } else {
- dev->last_error = CANDLE_ERR_MALLOC;
- return false;
- }
- bool retval = true;
- ULONG length = requiredLength;
- if (!SetupDiGetDeviceInterfaceDetail(hdi, &interfaceData, detail_data, length, &requiredLength, NULL) ) {
- dev->last_error = CANDLE_ERR_SETUPDI_IF_DETAILS2;
- retval = false;
- } else if (FAILED(StringCchCopy(dev->path, sizeof(dev->path), detail_data->DevicePath))) {
- dev->last_error = CANDLE_ERR_PATH_LEN;
- retval = false;
- }
- LocalFree(detail_data);
- if (!retval) {
- return false;
- }
- /* try to open to read device infos and see if it is avail */
- if (candle_dev_interal_open(dev)) {
- dev->state = CANDLE_DEVSTATE_AVAIL;
- candle_dev_close(dev);
- } else {
- dev->state = CANDLE_DEVSTATE_INUSE;
- }
- dev->last_error = CANDLE_ERR_OK;
- return true;
- }
- bool __stdcall candle_list_scan(candle_list_handle *list)
- {
- if (list==NULL) {
- return false;
- }
- candle_list_t *l = (candle_list_t *)calloc(1, sizeof(candle_list_t));
- *list = l;
- if (l==NULL) {
- return false;
- }
- GUID guid;
- if (CLSIDFromString(L"{c15b4308-04d3-11e6-b3ea-6057189e6443}", &guid) != NOERROR) {
- l->last_error = CANDLE_ERR_CLSID;
- return false;
- }
- HDEVINFO hdi = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
- if (hdi == INVALID_HANDLE_VALUE) {
- l->last_error = CANDLE_ERR_GET_DEVICES;
- return false;
- }
- bool rv = false;
- for (unsigned i=0; i<CANDLE_MAX_DEVICES; i++) {
- SP_DEVICE_INTERFACE_DATA interfaceData;
- interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
- if (SetupDiEnumDeviceInterfaces(hdi, NULL, &guid, i, &interfaceData)) {
- if (!candle_read_di(hdi, interfaceData, &l->dev[i])) {
- l->last_error = l->dev[i].last_error;
- rv = false;
- break;
- }
- } else {
- DWORD err = GetLastError();
- if (err==ERROR_NO_MORE_ITEMS) {
- l->num_devices = i;
- l->last_error = CANDLE_ERR_OK;
- rv = true;
- } else {
- l->last_error = CANDLE_ERR_SETUPDI_IF_ENUM;
- rv = false;
- }
- break;
- }
- }
- SetupDiDestroyDeviceInfoList(hdi);
- return rv;
- }
- bool __stdcall DLL candle_list_free(candle_list_handle list)
- {
- free(list);
- return true;
- }
- bool __stdcall DLL candle_list_length(candle_list_handle list, uint8_t *len)
- {
- candle_list_t *l = (candle_list_t *)list;
- *len = l->num_devices;
- return true;
- }
- bool __stdcall DLL candle_dev_get(candle_list_handle list, uint8_t dev_num, candle_handle *hdev)
- {
- candle_list_t *l = (candle_list_t *)list;
- if (l==NULL) {
- return false;
- }
- if (dev_num >= CANDLE_MAX_DEVICES) {
- l->last_error = CANDLE_ERR_DEV_OUT_OF_RANGE;
- return false;
- }
- candle_device_t *dev = calloc(1, sizeof(candle_device_t));
- *hdev = dev;
- if (dev==NULL) {
- l->last_error = CANDLE_ERR_MALLOC;
- return false;
- }
- memcpy(dev, &l->dev[dev_num], sizeof(candle_device_t));
- l->last_error = CANDLE_ERR_OK;
- dev->last_error = CANDLE_ERR_OK;
- return true;
- }
- bool __stdcall DLL candle_dev_get_state(candle_handle hdev, candle_devstate_t *state)
- {
- if (hdev==NULL) {
- return false;
- } else {
- candle_device_t *dev = (candle_device_t*)hdev;
- *state = dev->state;
- return true;
- }
- }
- wchar_t __stdcall DLL *candle_dev_get_path(candle_handle hdev)
- {
- if (hdev==NULL) {
- return NULL;
- } else {
- candle_device_t *dev = (candle_device_t*)hdev;
- return dev->path;
- }
- }
- static bool candle_dev_interal_open(candle_handle hdev)
- {
- candle_device_t *dev = (candle_device_t*)hdev;
- memset(dev->rxevents, 0, sizeof(dev->rxevents));
- memset(dev->rxurbs, 0, sizeof(dev->rxurbs));
- dev->deviceHandle = CreateFile(
- dev->path,
- GENERIC_WRITE | GENERIC_READ,
- FILE_SHARE_WRITE | FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
- NULL
- );
- if (dev->deviceHandle == INVALID_HANDLE_VALUE) {
- dev->last_error = CANDLE_ERR_CREATE_FILE;
- return false;
- }
- if (!WinUsb_Initialize(dev->deviceHandle, &dev->winUSBHandle)) {
- dev->last_error = CANDLE_ERR_WINUSB_INITIALIZE;
- goto close_handle;
- }
- USB_INTERFACE_DESCRIPTOR ifaceDescriptor;
- if (!WinUsb_QueryInterfaceSettings(dev->winUSBHandle, 0, &ifaceDescriptor)) {
- dev->last_error = CANDLE_ERR_QUERY_INTERFACE;
- goto winusb_free;
- }
- dev->interfaceNumber = ifaceDescriptor.bInterfaceNumber;
- unsigned pipes_found = 0;
- for (uint8_t i=0; i<ifaceDescriptor.bNumEndpoints; i++) {
- WINUSB_PIPE_INFORMATION pipeInfo;
- if (!WinUsb_QueryPipe(dev->winUSBHandle, 0, i, &pipeInfo)) {
- dev->last_error = CANDLE_ERR_QUERY_PIPE;
- goto winusb_free;
- }
- if (pipeInfo.PipeType == UsbdPipeTypeBulk && USB_ENDPOINT_DIRECTION_IN(pipeInfo.PipeId)) {
- dev->bulkInPipe = pipeInfo.PipeId;
- pipes_found++;
- } else if (pipeInfo.PipeType == UsbdPipeTypeBulk && USB_ENDPOINT_DIRECTION_OUT(pipeInfo.PipeId)) {
- dev->bulkOutPipe = pipeInfo.PipeId;
- pipes_found++;
- } else {
- dev->last_error = CANDLE_ERR_PARSE_IF_DESCR;
- goto winusb_free;
- }
- }
- if (pipes_found != 2) {
- dev->last_error = CANDLE_ERR_PARSE_IF_DESCR;
- goto winusb_free;
- }
- char use_raw_io = 1;
- if (!WinUsb_SetPipePolicy(dev->winUSBHandle, dev->bulkInPipe, RAW_IO, sizeof(use_raw_io), &use_raw_io)) {
- dev->last_error = CANDLE_ERR_SET_PIPE_RAW_IO;
- goto winusb_free;
- }
- if (!candle_ctrl_set_host_format(dev)) {
- goto winusb_free;
- }
- if (!candle_ctrl_get_config(dev, &dev->dconf)) {
- goto winusb_free;
- }
- if (!candle_ctrl_get_capability(dev, 0, &dev->bt_const)) {
- dev->last_error = CANDLE_ERR_GET_BITTIMING_CONST;
- goto winusb_free;
- }
- dev->last_error = CANDLE_ERR_OK;
- return true;
- winusb_free:
- WinUsb_Free(dev->winUSBHandle);
- close_handle:
- CloseHandle(dev->deviceHandle);
- return false;
- }
- static bool candle_prepare_read(candle_device_t *dev, unsigned urb_num)
- {
- bool rc = WinUsb_ReadPipe(
- dev->winUSBHandle,
- dev->bulkInPipe,
- dev->rxurbs[urb_num].buf,
- sizeof(dev->rxurbs[urb_num].buf),
- NULL,
- &dev->rxurbs[urb_num].ovl
- );
- if (rc || (GetLastError()!=ERROR_IO_PENDING)) {
- dev->last_error = CANDLE_ERR_PREPARE_READ;
- return false;
- } else {
- dev->last_error = CANDLE_ERR_OK;
- return true;
- }
- }
- static bool candle_close_rxurbs(candle_device_t *dev)
- {
- for (unsigned i=0; i<CANDLE_URB_COUNT; i++) {
- if (dev->rxevents[i] != NULL) {
- CloseHandle(dev->rxevents[i]);
- }
- }
- return true;
- }
- bool __stdcall DLL candle_dev_open(candle_handle hdev)
- {
- candle_device_t *dev = (candle_device_t*)hdev;
- if (candle_dev_interal_open(dev)) {
- for (unsigned i=0; i<CANDLE_URB_COUNT; i++) {
- HANDLE ev = CreateEvent(NULL, true, false, NULL);
- dev->rxevents[i] = ev;
- dev->rxurbs[i].ovl.hEvent = ev;
- if (!candle_prepare_read(dev, i)) {
- candle_close_rxurbs(dev);
- return false; // keep last_error from prepare_read call
- }
- }
- dev->last_error = CANDLE_ERR_OK;
- return true;
- } else {
- return false; // keep last_error from open_device call
- }
- }
- bool __stdcall DLL candle_dev_get_timestamp_us(candle_handle hdev, uint32_t *timestamp_us)
- {
- return candle_ctrl_get_timestamp(hdev, timestamp_us);
- }
- bool __stdcall DLL candle_dev_close(candle_handle hdev)
- {
- candle_device_t *dev = (candle_device_t*)hdev;
- candle_close_rxurbs(dev);
- WinUsb_Free(dev->winUSBHandle);
- dev->winUSBHandle = NULL;
- CloseHandle(dev->deviceHandle);
- dev->deviceHandle = NULL;
- dev->last_error = CANDLE_ERR_OK;
- return true;
- }
- bool __stdcall DLL candle_dev_free(candle_handle hdev)
- {
- free(hdev);
- return true;
- }
- candle_err_t __stdcall DLL candle_dev_last_error(candle_handle hdev)
- {
- candle_device_t *dev = (candle_device_t*)hdev;
- return dev->last_error;
- }
- bool __stdcall DLL candle_channel_count(candle_handle hdev, uint8_t *num_channels)
- {
- // TODO check if info was already read from device; try to do so; throw error...
- candle_device_t *dev = (candle_device_t*)hdev;
- *num_channels = dev->dconf.icount+1;
- return true;
- }
- bool __stdcall DLL candle_channel_get_capabilities(candle_handle hdev, uint8_t ch, candle_capability_t *cap)
- {
- // TODO check if info was already read from device; try to do so; throw error...
- candle_device_t *dev = (candle_device_t*)hdev;
- memcpy(cap, &dev->bt_const.feature, sizeof(candle_capability_t));
- return true;
- }
- bool __stdcall DLL candle_channel_set_timing(candle_handle hdev, uint8_t ch, candle_bittiming_t *data)
- {
- // TODO ensure device is open, check channel count..
- candle_device_t *dev = (candle_device_t*)hdev;
- return candle_ctrl_set_bittiming(dev, ch, data);
- }
- bool __stdcall DLL candle_channel_set_bitrate(candle_handle hdev, uint8_t ch, uint32_t bitrate)
- {
- // TODO ensure device is open, check channel count..
- candle_device_t *dev = (candle_device_t*)hdev;
- if (dev->bt_const.fclk_can != 48000000) {
- /* this function only works for the candleLight base clock of 48MHz */
- dev->last_error = CANDLE_ERR_BITRATE_FCLK;
- return false;
- }
- candle_bittiming_t t;
- t.prop_seg = 1;
- t.sjw = 1;
- t.phase_seg1 = 13 - t.prop_seg;
- t.phase_seg2 = 2;
- switch (bitrate) {
- case 10000:
- t.brp = 300;
- break;
- case 20000:
- t.brp = 150;
- break;
- case 50000:
- t.brp = 60;
- break;
- case 83333:
- t.brp = 36;
- break;
- case 100000:
- t.brp = 30;
- break;
- case 125000:
- t.brp = 24;
- break;
- case 250000:
- t.brp = 12;
- break;
- case 500000:
- t.brp = 6;
- break;
- case 800000:
- t.brp = 4;
- t.phase_seg1 = 12 - t.prop_seg;
- t.phase_seg2 = 2;
- break;
- case 1000000:
- t.brp = 3;
- break;
- default:
- dev->last_error = CANDLE_ERR_BITRATE_UNSUPPORTED;
- return false;
- }
- return candle_ctrl_set_bittiming(dev, ch, &t);
- }
- bool __stdcall DLL candle_channel_start(candle_handle hdev, uint8_t ch, uint32_t flags)
- {
- // TODO ensure device is open, check channel count..
- candle_device_t *dev = (candle_device_t*)hdev;
- flags |= CANDLE_MODE_HW_TIMESTAMP;
- return candle_ctrl_set_device_mode(dev, ch, CANDLE_DEVMODE_START, flags);
- }
- bool __stdcall DLL candle_channel_stop(candle_handle hdev, uint8_t ch)
- {
- // TODO ensure device is open, check channel count..
- candle_device_t *dev = (candle_device_t*)hdev;
- return candle_ctrl_set_device_mode(dev, ch, CANDLE_DEVMODE_RESET, 0);
- }
- bool __stdcall DLL candle_frame_send(candle_handle hdev, uint8_t ch, candle_frame_t *frame)
- {
- // TODO ensure device is open, check channel count..
- candle_device_t *dev = (candle_device_t*)hdev;
- unsigned long bytes_sent = 0;
- frame->echo_id = 0;
- frame->channel = ch;
- bool rc = WinUsb_WritePipe(
- dev->winUSBHandle,
- dev->bulkOutPipe,
- (uint8_t*)frame,
- sizeof(*frame),
- &bytes_sent,
- 0
- );
- dev->last_error = rc ? CANDLE_ERR_OK : CANDLE_ERR_SEND_FRAME;
- return rc;
- }
- bool __stdcall DLL candle_frame_read(candle_handle hdev, candle_frame_t *frame, uint32_t timeout_ms)
- {
- // TODO ensure device is open..
- candle_device_t *dev = (candle_device_t*)hdev;
- DWORD wait_result = WaitForMultipleObjects(CANDLE_URB_COUNT, dev->rxevents, false, timeout_ms);
- if (wait_result == WAIT_TIMEOUT) {
- dev->last_error = CANDLE_ERR_READ_TIMEOUT;
- return false;
- }
- if ( (wait_result < WAIT_OBJECT_0) || (wait_result >= WAIT_OBJECT_0 + CANDLE_URB_COUNT) ) {
- dev->last_error = CANDLE_ERR_READ_WAIT;
- return false;
- }
- DWORD urb_num = wait_result - WAIT_OBJECT_0;
- DWORD bytes_transfered;
- if (!WinUsb_GetOverlappedResult(dev->winUSBHandle, &dev->rxurbs[urb_num].ovl, &bytes_transfered, false)) {
- candle_prepare_read(dev, urb_num);
- dev->last_error = CANDLE_ERR_READ_RESULT;
- return false;
- }
- if (bytes_transfered < sizeof(*frame)-4) {
- candle_prepare_read(dev, urb_num);
- dev->last_error = CANDLE_ERR_READ_SIZE;
- return false;
- }
- if (bytes_transfered < sizeof(*frame)) {
- frame->timestamp_us = 0;
- }
- memcpy(frame, dev->rxurbs[urb_num].buf, sizeof(*frame));
- return candle_prepare_read(dev, urb_num);
- }
- candle_frametype_t __stdcall DLL candle_frame_type(candle_frame_t *frame)
- {
- if (frame->echo_id != 0xFFFFFFFF) {
- return CANDLE_FRAMETYPE_ECHO;
- };
- if (frame->can_id & CANDLE_ID_ERR) {
- return CANDLE_FRAMETYPE_ERROR;
- }
- return CANDLE_FRAMETYPE_RECEIVE;
- }
- uint32_t __stdcall DLL candle_frame_id(candle_frame_t *frame)
- {
- return frame->can_id & 0x1FFFFFFF;
- }
- bool __stdcall DLL candle_frame_is_extended_id(candle_frame_t *frame)
- {
- return (frame->can_id & CANDLE_ID_EXTENDED) != 0;
- }
- bool __stdcall DLL candle_frame_is_rtr(candle_frame_t *frame)
- {
- return (frame->can_id & CANDLE_ID_RTR) != 0;
- }
- uint8_t __stdcall DLL candle_frame_dlc(candle_frame_t *frame)
- {
- return frame->can_dlc;
- }
- uint8_t __stdcall DLL *candle_frame_data(candle_frame_t *frame)
- {
- return frame->data;
- }
- uint32_t __stdcall DLL candle_frame_timestamp_us(candle_frame_t *frame)
- {
- return frame->timestamp_us;
- }
|