Rework for new eismulitplexer pcb

add documentation
add pkg-config files
This commit is contained in:
Carl Philipp Klemm 2023-06-19 15:54:11 +02:00
parent dbbf1068dc
commit e4af92276c
9 changed files with 329 additions and 267 deletions

View file

@ -1,29 +1,33 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.0)
project(uvosled) project(eismultiplexer)
set(SRC_FILES uvosled.c usbshm.c) find_package(PkgConfig REQUIRED)
set(LIBS -pthread -lusb-1.0 ) pkg_check_modules(LIBUSB REQUIRED libusb-1.0)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "..." FORCE)
endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(SRC_FILES eismultiplexer.c usbshm.c)
add_library(${PROJECT_NAME} SHARED ${SRC_FILES}) add_library(${PROJECT_NAME} SHARED ${SRC_FILES})
target_link_libraries( ${PROJECT_NAME} ${LIBS}) target_link_libraries(${PROJECT_NAME} ${LIBUSB_LIBRARIES} -pthread)
target_include_directories(${PROJECT_NAME} PUBLIC ${LIBUSB_INCLUDE_DIRS})
add_definitions("-std=c17 -Wall -O2 -fno-strict-aliasing") add_definitions("-std=c17 -Wall -O2 -fno-strict-aliasing")
set(CMAKE_INSTALL_PREFIX "/usr")
install(TARGETS ${PROJECT_NAME} DESTINATION lib) install(TARGETS ${PROJECT_NAME} DESTINATION lib)
install(FILES ./uvosled.h DESTINATION include) install(FILES ./eismultiplexer.h DESTINATION include)
link_directories(${CMAKE_CURRENT_BINARY_DIR}) link_directories(${CMAKE_CURRENT_BINARY_DIR})
set(SRC_FILES_TEST_APP main.c) add_executable(${PROJECT_NAME}_test main.c)
set(LIBS_TEST -l${PROJECT_NAME})
add_executable(${PROJECT_NAME}_test ${SRC_FILES_TEST_APP})
add_dependencies(${PROJECT_NAME}_test ${PROJECT_NAME}) add_dependencies(${PROJECT_NAME}_test ${PROJECT_NAME})
target_link_libraries( ${PROJECT_NAME}_test ${LIBS_TEST}) target_link_libraries( ${PROJECT_NAME}_test -l${PROJECT_NAME})
add_definitions("-std=c17 -Wall -O2 -fno-strict-aliasing") add_definitions("-std=c17 -Wall -O2 -fno-strict-aliasing")
install(TARGETS ${PROJECT_NAME}_test DESTINATION bin) install(TARGETS ${PROJECT_NAME}_test DESTINATION bin)
configure_file(pkgconfig/eismuliplexer.pc.in pkgconfig/eismuliplexer.pc @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/eismuliplexer.pc DESTINATION lib/pkgconfig)
if(CMAKE_SYSTEM_NAME MATCHES "^Linux") if(CMAKE_SYSTEM_NAME MATCHES "^Linux")
set(UDEV_RULES_INSTALL_DIR /lib/udev/rules.d CACHE PATH "install directory for linux udev config") 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}) install(FILES 90-eismultiplexer.rules DESTINATION ${UDEV_RULES_INSTALL_DIR})
endif() endif()

113
eismultiplexer.c Normal file
View file

@ -0,0 +1,113 @@
/**
* 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 "eismultiplexer.h"
#include "usbshm.h"
#include <stdlib.h>
#include <time.h>
static void usleep(uint64_t microseconds)
{
struct timespec ts;
ts.tv_sec = microseconds / 1000000;
ts.tv_nsec = (microseconds % 1000000) * 1000;
nanosleep(&ts, NULL);
}
static void dataCallback(uint8_t request, unsigned char* data, size_t length, void* user_data)
{
struct eismulitplexer* muliplexer = user_data;
if(length >= 1)
muliplexer->activeChannels = data[0];
sem_post(&muliplexer->readSem);
}
int eismulitplexer_connect(struct eismulitplexer* muliplexer, int serial)
{
int ret;
muliplexer->priv = malloc(sizeof(*muliplexer->priv));
if(!muliplexer->priv)
return -1;
ret = usbshm_init(muliplexer->priv, &dataCallback, muliplexer);
if(ret)
return -2;
ret = usbshm_open(muliplexer->priv, 0xfe17, 0x07dc , NULL);
if(ret)
return -3;
ret = sem_init(&muliplexer->readSem, 0, 0);
if(ret)
return -4;
return 0;
}
int eismulitplexer_connect_channel_exclusive(struct eismulitplexer* muliplexer, channel_t channel)
{
uint16_t wValue;
// we compile with fno-strict-aliasing
uint8_t* wValChar = (uint8_t*)&wValue;
wValChar[0] = channel;
wValChar[1] = 0;
int ret;
while((ret = usbshm_writeControlTransfer(muliplexer->priv, 2, NULL, 0, wValue, 0)) == USBSHM_ERROR_AGAIN)
usleep(1000000);
return ret;
}
int eismulitplexer_connect_channel(struct eismulitplexer* muliplexer, channel_t channel)
{
channel_t channels = eismulitplexer_get_connected(muliplexer);
channels |= channel;
return eismulitplexer_connect_channel_exclusive(muliplexer, channels);
}
int eismulitplexer_disconnect_channel(struct eismulitplexer* muliplexer, channel_t channel)
{
channel_t channels = eismulitplexer_get_connected(muliplexer);
channels &= ~channel;
return eismulitplexer_connect_channel_exclusive(muliplexer, channels);
}
channel_t eismulitplexer_get_connected(struct eismulitplexer* muliplexer)
{
usbshm_readControlTransfer(muliplexer->priv, 3, 1);
sem_wait(&muliplexer->readSem);
return muliplexer->activeChannels;
}
int eismulitplexer_set_led(struct eismulitplexer* muliplexer, bool on)
{
int ret;
while((ret = usbshm_writeControlTransfer(muliplexer->priv, on, NULL, 0, 0, 0)) == USBSHM_ERROR_AGAIN)
usleep(1000000);
return ret;
}
void eismulitplexer_disconnect(struct eismulitplexer* muliplexer)
{
usbshm_distroy(muliplexer->priv);
free(muliplexer->priv);
muliplexer->priv = NULL;
sem_destroy(&muliplexer->readSem);
}

113
eismultiplexer.h Normal file
View file

@ -0,0 +1,113 @@
/**
* 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>
#include <semaphore.h>
#include <stdbool.h>
/**
Api for use by libscipaper eismulitplexer.
* @defgroup API User API
* This api allows you to controll the EISmulitplexer device.
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
CHANNEL_A = (1 << 1),
CHANNEL_B = (1 << 2),
CHANNEL_C = (1 << 3),
CHANNEL_D = (1 << 4),
CHANNEL_E = (1 << 5),
CHANNEL_F = (1 << 6),
CHANNEL_G = (1 << 7),
CHANNEL_NONE = 0,
} channel_t;
struct eismulitplexer {
struct usbshm* priv;
sem_t readSem;
channel_t activeChannels;
};
/**
* @brief Attempts to connect to a EISmulitplexer device and initalizes a eismulitplexer struct
* @param muliplexer pointer to a eismulitplexer struct to initalize
* @param serial The serial number of the device to connect to, or 0 for any
* @return 0 on sucess and < 0 on failure
*/
int eismulitplexer_connect(struct eismulitplexer* muliplexer, int serial);
/**
* @brief Conects the given channel(s) to the common inputs
* @param muliplexer pointer to a eismulitplexer struct
* @param channel A channel to connect, multiple channels can be specified by or'ing together the chanel flags e.g. (CHANNEL_A | CHANNEL_B)
* @return 0 on sucess and < 0 on failure
*/
int eismulitplexer_connect_channel(struct eismulitplexer* muliplexer, channel_t channel);
/**
* @brief Conects the given channel(s) to the common inputs disconnecting all others
* @param muliplexer pointer to a eismulitplexer struct
* @param channel A channel to connect, multiple channels can be specified by or'ing together the chanel flags e.g. (CHANNEL_A | CHANNEL_B)
* @return 0 on sucess and < 0 on failure
*/
int eismulitplexer_connect_channel_exclusive(struct eismulitplexer* muliplexer, channel_t channel);
/**
* @brief Disconnect the given channel(s) to the common inputs disconnecting all others
* @param muliplexer pointer to a eismulitplexer struct
* @param channel A channel to connect, multiple channels can be specified by or'ing together the chanel flags e.g. (CHANNEL_A | CHANNEL_B)
* All channels can be dissconnected by passing CHANNEL_NONE
* @return 0 on sucess and < 0 on failure
*/
int eismulitplexer_disconnect_channel(struct eismulitplexer* muliplexer, channel_t channel);
/**
* @brief Returns the channels currently connected
* @param muliplexer pointer to a eismulitplexer struct
* @return channels connected as a bitfield
*/
channel_t eismulitplexer_get_connected(struct eismulitplexer* muliplexer);
/**
* @brief Turns the led on the pcb on or off
* @param muliplexer pointer to a eismulitplexer struct
* @param on true to turn the led on, false to turn it off
* @return 0 on sucess and < 0 on failure
*/
int eismulitplexer_set_led(struct eismulitplexer* muliplexer, bool on);
/**
* @brief Disconnects from the eismulitplexer
*/
void eismulitplexer_disconnect(struct eismulitplexer* muliplexer);
#ifdef __cplusplus
}
#endif
/**
....
* @}
*/

126
main.c
View file

@ -18,92 +18,104 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "uvosled.h" #include "eismultiplexer.h"
void print_help(const char* progname) void print_help(const char* progname)
{ {
printf("usage: %s [OPERATION] [CHANNEL] [VALUE]\n", progname); printf("usage: %s [OPERATION] [CHANNEL] [VALUE]\n", progname);
printf("available operations: set on off help\n"); printf("available operations: connect disconnect help\n");
} }
channel_t char_to_channel(char ch)
{
switch(ch)
{
case 'a':
case 'A':
case '1':
return CHANNEL_A;
case 'b':
case 'B':
case '2':
return CHANNEL_B;
case 'c':
case 'C':
case '3':
return CHANNEL_C;
case 'd':
case 'D':
case '4':
return CHANNEL_D;
case 'e':
case 'E':
case '5':
return CHANNEL_E;
case 'f':
case 'F':
case '6':
return CHANNEL_F;
case 'g':
case 'G':
case '7':
return CHANNEL_NONE;
default:
return CHANNEL_NONE;
}
}
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
if(argc < 2 || strcmp (argv[1], "help") == 0) if(argc < 2 || strcmp(argv[1], "help") == 0)
{ {
print_help(argv[0]); print_help(argv[0]);
return 0; return 0;
} }
struct uvosled led; struct eismulitplexer multiplexer;
if(uvosled_connect(&led)) if(eismulitplexer_connect(&multiplexer, 0))
{ {
printf("Can not connect to UVOS usbled device\n"); printf("Can not connect to EISmultiplexer device\n");
return -1; 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) if(argc != 4)
{ {
printf("usage: %s set [CHANNEL] [VALUE]\n", argv[0]); print_help(argv[0]);
uvosled_poweroff(&led); eismulitplexer_disconnect(&multiplexer);
return 0; return 2;
} }
uint8_t mask = 0; channel_t channel = char_to_channel(argv[2][0]);
if(channel == CHANNEL_NONE)
switch(argv[2][0])
{ {
case 'a': printf("%c is not a valid channel", argv[2][0]);
case 'A': eismulitplexer_disconnect(&multiplexer);
case '1': return 2;
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) if(strcmp(argv[1], "connect") == 0)
{ {
char* end; if(eismulitplexer_connect_channel(&multiplexer, channel))
float value = strtof(argv[3], &end); {
if(isnan(value) || value < 0 || value > 1.0f) printf("could not connect channel %c", argv[2][0]);
printf("A channel value between 0 and 1.0 must be supplied\n"); eismulitplexer_disconnect(&multiplexer);
else if(uvosled_set_current(&led, mask, value)) return 3;
printf("Failed to set current\n"); }
}
else if(strcmp(argv[1], "disconnect") == 0)
{
if(eismulitplexer_disconnect_channel(&multiplexer, channel))
{
printf("could not connect channel %c", argv[2][0]);
eismulitplexer_disconnect(&multiplexer);
return 3;
} }
} }
uvosled_disconnect(&led); eismulitplexer_disconnect(&multiplexer);
return 0; return 0;
} }

View file

@ -0,0 +1,7 @@
includedir=@CMAKE_INSTALL_PREFIX@/include
Name: libeismuliplexer
Description: C lib to control EISmultiplexer devices
Version: 1.0
Libs: -L${libdir} -leismultiplexer
Cflags: -I${includedir}

View file

@ -75,7 +75,7 @@ bool usbshm_isOpen(struct usbshm* instance)
return instance->priv->handle != NULL; return instance->priv->handle != NULL;
} }
int usbshm_init(struct usbshm* instance, void (*dataCallback)(uint8_t request, unsigned char* data, size_t length)) int usbshm_init(struct usbshm* instance, void (*dataCallback)(uint8_t request, unsigned char* data, size_t length, void* user_data), void* user_data)
{ {
int ret=0; int ret=0;
instance->priv = malloc(sizeof(*instance->priv)); instance->priv = malloc(sizeof(*instance->priv));
@ -86,6 +86,7 @@ int usbshm_init(struct usbshm* instance, void (*dataCallback)(uint8_t request, u
instance->productID = 0; instance->productID = 0;
instance->productName = NULL; instance->productName = NULL;
instance->dataCallback = dataCallback; instance->dataCallback = dataCallback;
instance->user_data = user_data;
if(objectCounter == 0) if(objectCounter == 0)
{ {
printf("Usb Init\n"); printf("Usb Init\n");
@ -249,7 +250,7 @@ static void usbshm_transferCallBack(struct libusb_transfer *transfer)
else if(transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL) else if(transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL)
{ {
if(context->dataCallback && transfer->length-8 >= transfer->actual_length) if(context->dataCallback && transfer->length-8 >= transfer->actual_length)
context->dataCallback(transfer->buffer[1], transfer->buffer+8, transfer->actual_length); context->dataCallback(transfer->buffer[1], transfer->buffer+8, transfer->actual_length, context->user_data);
} }
free(context->priv->buffer); free(context->priv->buffer);
libusb_free_transfer(context->priv->transfer); libusb_free_transfer(context->priv->transfer);

View file

@ -36,12 +36,13 @@ struct usbshm {
int vendorID; int vendorID;
int productID; int productID;
char* productName; char* productName;
void (*dataCallback)(uint8_t request, unsigned char* data, size_t length); void* user_data;
void (*dataCallback)(uint8_t request, unsigned char* data, size_t length, void* user_data);
}; };
void usbshm_distroy(struct usbshm* instance); void usbshm_distroy(struct usbshm* instance);
int usbshm_init(struct usbshm* instance, void (*dataCallback)(uint8_t request, unsigned char* data, size_t length)); int usbshm_init(struct usbshm* instance, void (*dataCallback)(uint8_t request, unsigned char* data, size_t length, void* user_data), void* user_data);
bool usbshm_ready(struct usbshm* instance); bool usbshm_ready(struct usbshm* instance);

124
uvosled.c
View file

@ -1,124 +0,0 @@
/**
* 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;
}

View file

@ -1,65 +0,0 @@
/**
* 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