commit ed43fb747a29e9d009d94e792044604dd80176b2 Author: uvos Date: Sat Jun 12 12:53:02 2021 +0200 Inital commit diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..152d0a4 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.0) + +project(uvosled) + +set(SRC_FILES uvosled.c usbshm.c) +set(LIBS -pthread -lusb-1.0 ) + +add_library(${PROJECT_NAME} SHARED ${SRC_FILES}) +target_link_libraries( ${PROJECT_NAME} ${LIBS}) +add_definitions("-std=c17 -Wall -O2 -fno-strict-aliasing") + +set(CMAKE_INSTALL_PREFIX "/usr") +install(TARGETS ${PROJECT_NAME} DESTINATION lib) +install(FILES ./uvosled.h DESTINATION include) + +link_directories(${CMAKE_CURRENT_BINARY_DIR}) +set(SRC_FILES_TEST_APP main.c) +set(LIBS_TEST -l${PROJECT_NAME}) +add_executable(${PROJECT_NAME}_test ${SRC_FILES_TEST_APP}) +add_dependencies(${PROJECT_NAME}_test ${PROJECT_NAME}) +target_link_libraries( ${PROJECT_NAME}_test ${LIBS_TEST}) +add_definitions("-std=c17 -Wall -O2 -fno-strict-aliasing") + + diff --git a/main.c b/main.c new file mode 100644 index 0000000..724fbec --- /dev/null +++ b/main.c @@ -0,0 +1,33 @@ +#include +#include +#include "uvosled.h" + +int main(int argc, char* argv[]) +{ + struct uvosled led; + + if(uvosled_connect(&led)) + { + printf("cant connect \n"); + return -1; + } + if(uvosled_poweron(&led)) + { + printf("cant power on \n"); + return -2; + } + if(uvosled_set_current(&led, CHANNEL_A | CHANNEL_B , 0.5)) + { + printf("cant set current \n"); + return -3; + } + sleep(30); + if(uvosled_set_current(&led, CHANNEL_A | CHANNEL_B , 0)) + { + printf("cant set current \n"); + return -3; + } + uvosled_poweroff(&led); + uvosled_disconnect(&led); + return 0; +} diff --git a/usbshm.c b/usbshm.c new file mode 100644 index 0000000..0b17bb9 --- /dev/null +++ b/usbshm.c @@ -0,0 +1,239 @@ +#include "usbshm.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +struct usbshm_priv +{ + libusb_device_handle* handle; + struct libusb_transfer* transfer; + unsigned char* buffer; +}; + +static unsigned objectCounter = 0; +static struct timeval timeout = {1, 0}; +static pthread_mutex_t *libusbDataMutex; +static pthread_t libusbThread; +static atomic_bool threadStop; + +static void usbshm_transferCallBack(struct libusb_transfer *transfer); + +void usbshm_distroy(struct usbshm* instance) +{ + while(!usbshm_ready(instance)) + sleep(1); + free(instance->priv->transfer); + libusb_close(instance->priv->handle); + free(instance->priv->buffer); + free(instance->productName); + free(instance->priv); + if(--objectCounter == 0) + { + threadStop = true; + pthread_join(libusbThread, NULL); + libusb_exit(NULL); + pthread_mutex_destroy(libusbDataMutex); + } + +} + +static void* usbshm_libusbPoll(void* arg) +{ + while(!threadStop) + { + libusb_handle_events_timeout_completed(NULL, &timeout, NULL); + } + return NULL; +} + +bool usbshm_isOpen(struct usbshm* instance) +{ + return instance->priv->handle != NULL; +} + +int usbshm_init(struct usbshm* instance, void (*dataCallback)(uint8_t request, unsigned char* data, size_t length)) +{ + int ret=0; + instance->priv = malloc(sizeof(*instance->priv)); + instance->priv->handle = NULL; + instance->priv->transfer = NULL; + instance->priv->buffer = NULL; + instance->vendorID = 0; + instance->productID = 0; + instance->productName = NULL; + instance->dataCallback = dataCallback; + if(objectCounter == 0) + { + printf("Usb Init\n"); + ret = libusb_init(NULL) < 0 ? USBSHM_ERROR_ERR : 0; + libusbDataMutex = malloc(sizeof(*libusbDataMutex)); + pthread_mutex_init(libusbDataMutex, NULL); + //libusb_set_option(NULL, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_DEBUG); + pthread_create(&libusbThread, NULL, &usbshm_libusbPoll, NULL); + } + if(ret == 0) objectCounter++; + return ret; +} + +bool usbshm_ready(struct usbshm* instance) +{ + return instance->priv->transfer == NULL; +} + +int usbshm_open(struct usbshm* instance, int vendorID, int productID, const char* productName) +{ + instance->priv->handle = NULL; + pthread_mutex_lock(libusbDataMutex); + printf("Listing Devices\n"); + libusb_device** list; + int count = libusb_get_device_list(NULL, &list); + int errorCode = 0; + if( count > 0) + { + struct libusb_device_descriptor desc = {0}; + for(int i = 0; i < count; ++i) + { + libusb_get_device_descriptor(list[i], &desc); + if(desc.idVendor == vendorID && desc.idProduct == productID) + { + errorCode = libusb_open(list[i], &instance->priv->handle) < 0 ? USBSHM_ERROR_ERR : 0; + break; + } + } + } + else + { + printf("Can not list devices\n"); + pthread_mutex_unlock(libusbDataMutex); + return USBSHM_ERROR_ERR; + } + + if(usbshm_isOpen(instance)) + { + instance->vendorID = vendorID; + instance->productID = productID; + if(productName) + { + instance->productName = malloc(strlen(productName)+1); + strcpy(instance->productName, productName); + } + else + { + instance->productName = NULL; + } + libusb_set_auto_detach_kernel_driver(instance->priv->handle, true); + } + else + { + printf("Opening usb device failed\n"); + errorCode = USBSHM_ERROR_ERR; + } + + + libusb_free_device_list(list, count); + pthread_mutex_unlock(libusbDataMutex); + return errorCode; +} + +bool usbshm_usbshm_isOpen(struct usbshm* instance) +{ + return instance->priv->handle != NULL; +} + +void usbshm_reset(struct usbshm* instance) +{ + printf("Usb transfer failed with %u\n", instance->priv->transfer->status); + libusb_reset_device(instance->priv->handle); +} + +void usbshm_reopen(struct usbshm* instance) +{ + libusb_close(instance->priv->handle); + usbshm_open(instance, instance->vendorID, instance->productID, instance->productName); +} + +int usbshm_writeControlTransfer(struct usbshm* instance, const uint8_t request, + char* buffer, const uint8_t length, + const uint16_t wValue, const uint16_t wIndex) +{ + if(!usbshm_isOpen(instance)) + return USBSHM_ERROR_NOT_CONNECTED; + if(length > 8) + return USBSHM_ERROR_PARAM; + if(instance->priv->transfer == NULL) + { + pthread_mutex_lock(libusbDataMutex); + instance->priv->buffer = malloc(length+8); + libusb_fill_control_setup(instance->priv->buffer, + LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, + request, wValue, wIndex, length ); + for(uint8_t i = 0; i < length; ++i) + instance->priv->buffer[i+8] = buffer[i]; + instance->priv->transfer = libusb_alloc_transfer(0); + libusb_fill_control_transfer(instance->priv->transfer, instance->priv->handle, instance->priv->buffer, + &usbshm_transferCallBack, instance, 100); + int ret = libusb_submit_transfer(instance->priv->transfer); + pthread_mutex_unlock(libusbDataMutex); + if(ret < 0) + { + free(buffer); + libusb_free_transfer(instance->priv->transfer); + instance->priv->transfer = NULL; + if(ret == LIBUSB_ERROR_NO_DEVICE) + usbshm_reopen(instance); + } + return ret < 0 ? USBSHM_ERROR_ERR : 0; + } + else return USBSHM_ERROR_AGAIN; +} + +int usbshm_readControlTransfer(struct usbshm* instance, const uint8_t request, const uint8_t length) +{ + if(!usbshm_isOpen(instance)) + return USBSHM_ERROR_NOT_CONNECTED; + if(length > 8) + return USBSHM_ERROR_PARAM; + if(instance->priv->transfer == NULL) + { + pthread_mutex_lock(libusbDataMutex); + instance->priv->buffer = malloc(length+8); + libusb_fill_control_setup(instance->priv->buffer, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, request, request,request,length); + instance->priv->transfer = libusb_alloc_transfer(0); + libusb_fill_control_transfer(instance->priv->transfer, instance->priv->handle, instance->priv->buffer, &usbshm_transferCallBack, instance, 100); + int ret = libusb_submit_transfer(instance->priv->transfer); + pthread_mutex_unlock(libusbDataMutex); + if(ret < 0) + { + free(instance->priv->buffer); + libusb_free_transfer(instance->priv->transfer); + instance->priv->transfer = NULL; + if(ret == LIBUSB_ERROR_NO_DEVICE) + usbshm_reopen(instance); + } + return ret < 0 ? USBSHM_ERROR_ERR : 0; + } + else return USBSHM_ERROR_AGAIN; +} + +static void usbshm_transferCallBack(struct libusb_transfer *transfer) +{ + struct usbshm* context = (struct usbshm*)transfer->user_data; + if(transfer->status != LIBUSB_TRANSFER_COMPLETED) + { + printf("Usb transfer failed with %d\n", transfer->status); + } + else if(transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL) + { + if(context->dataCallback && transfer->length-8 >= transfer->actual_length) + context->dataCallback(transfer->buffer[1], transfer->buffer+8, transfer->actual_length); + } + free(context->priv->buffer); + libusb_free_transfer(context->priv->transfer); + context->priv->transfer = NULL; +} diff --git a/usbshm.h b/usbshm.h new file mode 100644 index 0000000..191c6ce --- /dev/null +++ b/usbshm.h @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include + +struct usbshm_priv; + +enum { + USBSHM_ERROR_AGAIN = -1, + USBSHM_ERROR_PARAM = -2, + USBSHM_ERROR_ERR = -3, + USBSHM_ERROR_NOT_CONNECTED = -4, +}; + +struct usbshm { + struct usbshm_priv* priv; + int vendorID; + int productID; + char* productName; + void (*dataCallback)(uint8_t request, unsigned char* data, size_t length); +}; + +void usbshm_distroy(struct usbshm* instance); + +int usbshm_init(struct usbshm* instance, void (*dataCallback)(uint8_t request, unsigned char* data, size_t length)); + +bool usbshm_ready(struct usbshm* instance); + +int usbshm_open(struct usbshm* instance, int vendorID, int productID, const char* productName); + +bool usbshm_isOpen(struct usbshm* instance); + +void usbshm_reset(struct usbshm* instance); + +void usbshm_reopen(struct usbshm* instance); + +int usbshm_writeControlTransfer(struct usbshm* instance, const uint8_t request, + char* buffer, const uint8_t length, + const uint16_t wValue, const uint16_t wIndex); + +int usbshm_readControlTransfer(struct usbshm* instance, const uint8_t request, const uint8_t length); + diff --git a/uvosled.c b/uvosled.c new file mode 100644 index 0000000..6eed917 --- /dev/null +++ b/uvosled.c @@ -0,0 +1,106 @@ +#define _POSIX_C_SOURCE 199309L +#include "uvosled.h" +#include "usbshm.h" +#include +#include + +void usleep(uint64_t microseconds) +{ + struct timespec ts; + ts.tv_sec = microseconds / 1000000; + ts.tv_nsec = (microseconds % 1000000) * 1000; + nanosleep(&ts, NULL); +} + +int uvosled_connect(struct uvosled* led) +{ + int ret; + led->priv = malloc(sizeof(*led->priv)); + if(!led->priv) + return -1; + + ret = usbshm_init(led->priv, NULL); + if(ret) + return -2; + + ret = usbshm_open(led->priv, 0xfe17, 0x06dc , NULL); + if(ret) + return -3; + return 0; +} + +int uvosled_poweron(struct uvosled* led) +{ + int ret; + while((ret = usbshm_writeControlTransfer(led->priv, 0, NULL, 0, 0, 0)) == USBSHM_ERROR_AGAIN) + usleep(1000000); + return ret; +} + +int uvosled_poweroff(struct uvosled* led) +{ + int ret; + while((ret = usbshm_writeControlTransfer(led->priv, 1, NULL, 0, 0, 0)) == USBSHM_ERROR_AGAIN) + usleep(1000000); + return ret; +} + +int uvosled_set_current(struct uvosled* led, uint8_t channels, float current) +{ + if(current < 0) + return -1; + else if(current > 1) + return -2; + uint8_t currentU = current * 255; + // TODO: implment endianess + uint16_t wValue; + // we compile with fno-strict-aliasing + uint8_t* wValChar = (uint8_t*)&wValue; + wValChar[0] = channels; + wValChar[1] = currentU; + int ret; + while((ret = usbshm_writeControlTransfer(led->priv, 2, NULL, 0, wValue, 0)) == USBSHM_ERROR_AGAIN) + usleep(1000000); + return ret; +} + +int uvosled_trigger(struct uvosled* led) +{ + int ret; + while((ret = usbshm_writeControlTransfer(led->priv, 1, NULL, 0, 0, 0)) == USBSHM_ERROR_AGAIN) + usleep(1000000); + return ret; +} + +int uvosled_capture(struct uvosled* led, int channels, float current, double time, double cameraOffset) +{ + if(current < 0 || current > 1 || time > 1 || cameraOffset < -1 || cameraOffset > 1) + return USBSHM_ERROR_PARAM; + + uint8_t currentU = current * 255; + uint16_t timeU = time * 1000; + int16_t cameraOffsetU = cameraOffset * 1000; + int ret; + + while((ret = usbshm_writeControlTransfer(led->priv, 5, NULL, 0, *((uint16_t*)&cameraOffsetU), 0)) == USBSHM_ERROR_AGAIN) + usleep(1000000); + if(ret < 0) + return ret; + + // TODO: implment endianess + uint16_t wValue; + // we compile with fno-strict-aliasing + uint8_t* wValChar = (uint8_t*)&wValue; + wValChar[0] = channels; + wValChar[1] = currentU; + while((ret = usbshm_writeControlTransfer(led->priv, 1, NULL, 0, wValue, timeU)) == USBSHM_ERROR_AGAIN) + usleep(1000000); + return ret; +} + +void uvosled_disconnect(struct uvosled* led) +{ + usbshm_distroy(led->priv); + free(led->priv); + led->priv = NULL; +} diff --git a/uvosled.h b/uvosled.h new file mode 100644 index 0000000..d4bfe83 --- /dev/null +++ b/uvosled.h @@ -0,0 +1,41 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define CHANNEL_A 1 +#define CHANNEL_B (1 << 1) +#define CHANNEL_C (1 << 2) +#define CHANNEL_D (1 << 3) + +struct uvosled { + struct usbshm* priv; +}; + +int uvosled_connect(struct uvosled* led); + +// power on cameras +int uvosled_poweron(struct uvosled* led); + +// power off cameras +int uvosled_poweroff(struct uvosled* led); + +// channels is a mask of bits, you can set it like this: CHANNEL_A | CHANNEL_C to activate channels A and C +// current is in Ampere +int uvosled_set_current(struct uvosled* led, uint8_t channels, float current); + +// causes the cameras to take an image +int uvosled_trigger(struct uvosled* led); + +// leds are lit for time seconds and the camera is activated cameraOffset seconds after they are lit +// real time guarenteed by microcontroller +int uvosled_capture(struct uvosled* led, int channels, float current, double time, double cameraOffset); + +void uvosled_disconnect(struct uvosled* led); + +#ifdef __cplusplus +} +#endif