Skip to content
Snippets Groups Projects
Commit dbbf1068 authored by uvos's avatar uvos
Browse files

inial commit

parents
No related branches found
No related tags found
No related merge requests found
SUBSYSTEM=="usb", ATTRS{idVendor}=="fe17", GROUP="uucp"
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")
install(TARGETS ${PROJECT_NAME}_test DESTINATION bin)
if(CMAKE_SYSTEM_NAME MATCHES "^Linux")
set(UDEV_RULES_INSTALL_DIR /lib/udev/rules.d CACHE PATH "install directory for linux udev config")
install(FILES 90-usbled.rules DESTINATION ${UDEV_RULES_INSTALL_DIR})
endif()
main.c 0 → 100644
/**
* libeismultiplexer
* Copyright (C) 2023 Carl Klemm
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 3 as published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "uvosled.h"
void print_help(const char* progname)
{
printf("usage: %s [OPERATION] [CHANNEL] [VALUE]\n", progname);
printf("available operations: set on off help\n");
}
int main(int argc, char* argv[])
{
if(argc < 2 || strcmp (argv[1], "help") == 0)
{
print_help(argv[0]);
return 0;
}
struct uvosled led;
if(uvosled_connect(&led))
{
printf("Can not connect to UVOS usbled device\n");
return -1;
}
if(strcmp(argv[1], "on") == 0)
{
if(uvosled_poweron(&led))
printf("cant power on \n");
}
else if(strcmp(argv[1], "off") == 0)
{
uvosled_set_current(&led, 0xff , 0);
uvosled_poweroff(&led);
}
else if(strcmp(argv[1], "set") == 0)
{
if(argc != 4)
{
printf("usage: %s set [CHANNEL] [VALUE]\n", argv[0]);
uvosled_poweroff(&led);
return 0;
}
uint8_t mask = 0;
switch(argv[2][0])
{
case 'a':
case 'A':
case '1':
mask = CHANNEL_A;
break;
case 'b':
case 'B':
case '2':
mask = CHANNEL_B;
break;
case 'c':
case 'C':
case '3':
mask = CHANNEL_C;
break;
case 'd':
case 'D':
case '4':
mask = CHANNEL_D;
break;
default:
printf("A channel must be selected out of A, B, C or D\n");
}
if(mask)
{
char* end;
float value = strtof(argv[3], &end);
if(isnan(value) || value < 0 || value > 1.0f)
printf("A channel value between 0 and 1.0 must be supplied\n");
else if(uvosled_set_current(&led, mask, value))
printf("Failed to set current\n");
}
}
uvosled_disconnect(&led);
return 0;
}
usbshm.c 0 → 100644
/**
* Copyright (C) 2023 Carl Klemm
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 3 as published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "usbshm.h"
#include <stdio.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <libusb-1.0/libusb.h>
#include <errno.h>
#include <unistd.h>
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;
}
usbshm.h 0 → 100644
/**
* Copyright (C) 2023 Carl Klemm
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 3 as published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <libusb-1.0/libusb.h>
#include <pthread.h>
#include <stdatomic.h>
#include <time.h>
#include <stdbool.h>
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);
uvosled.c 0 → 100644
/**
* Copyright (C) 2023 Carl Klemm
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 3 as published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#define _POSIX_C_SOURCE 199309L
#include "uvosled.h"
#include "usbshm.h"
#include <stdlib.h>
#include <time.h>
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;
}
/**
* Copyright (C) 2023 Carl Klemm
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 3 as published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include <stdint.h>
#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;
};
// returns 0 on sucess and < 0 on failure
int uvosled_connect(struct uvosled* led);
// power on cameras
// returns 0 on sucess and < 0 on failure
int uvosled_poweron(struct uvosled* led);
// power off cameras
// returns 0 on sucess and < 0 on failure
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 percent of the values selected by the linear regulator resistors
// returns 0 on sucess and < 0 on failure
int uvosled_set_current(struct uvosled* led, uint8_t channels, float current);
// causes the cameras to take an image
// returns 0 on sucess and < 0 on failure
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
// returns 0 on sucess and < 0 on failure
int uvosled_capture(struct uvosled* led, int channels, float current, double time, double cameraOffset);
void uvosled_disconnect(struct uvosled* led);
#ifdef __cplusplus
}
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment