From 2c97fd59538dddf8b9c47cfba43839d797611677 Mon Sep 17 00:00:00 2001 From: Brendan Le Foll Date: Fri, 2 Oct 2015 16:48:47 +0100 Subject: [PATCH] iio: initial pass at getting channel information from scan_elements This commit creates a new structure inside each _iio device when used and can then be used to understand the data being read after a trigger is run/executed Signed-off-by: Brendan Le Foll --- api/mraa/iio.h | 31 ++++++-- examples/iio_driver.c | 54 ++++++++++++-- include/mraa_internal_types.h | 10 ++- src/iio/iio.c | 169 +++++++++++++++++++++++++++++++++++++++++- src/mraa.c | 2 +- 5 files changed, 251 insertions(+), 15 deletions(-) diff --git a/api/mraa/iio.h b/api/mraa/iio.h index 4811916..f0b42a3 100644 --- a/api/mraa/iio.h +++ b/api/mraa/iio.h @@ -24,6 +24,23 @@ #pragma once +#include "common.h" + +typedef struct { + int index; + int enabled; + char* type; + mraa_boolean_t lendian; + int signedd; + unsigned int offset; + uint64_t mask; + unsigned int bits_used; + unsigned int bytes; + unsigned int shift; + unsigned int location; + float scale; +} mraa_iio_channel; + /** * @file * @brief iio @@ -57,14 +74,16 @@ typedef struct _iio* mraa_iio_context; */ mraa_iio_context mraa_iio_init(int device); -/** - */ -int mraa_iio_get_channel_count(mraa_iio_context dev); - -int mraa_iio_get_attr_count(mraa_iio_context dev, int channel); +mraa_result_t mraa_iio_trigger_buffer(mraa_iio_context dev, void (*fptr)(char* data), void* args); const char* mraa_iio_get_device_name(mraa_iio_context dev); +int mraa_iio_read_size(mraa_iio_context dev); + +mraa_iio_channel* mraa_iio_get_channels(mraa_iio_context dev); + +int mraa_iio_get_channel_count(mraa_iio_context dev); + /** */ mraa_result_t mraa_iio_read(mraa_iio_context dev, const char* attribute, float* data); @@ -74,6 +93,8 @@ mraa_result_t mraa_iio_read(mraa_iio_context dev, const char* attribute, float* */ mraa_result_t mraa_iio_write(mraa_iio_context dev, const char* attribute); +mraa_result_t mraa_iio_get_channel_data(mraa_iio_context dev); + /** * De-inits an mraa_iio_context device * diff --git a/examples/iio_driver.c b/examples/iio_driver.c index 8f8197c..4c88add 100644 --- a/examples/iio_driver.c +++ b/examples/iio_driver.c @@ -23,14 +23,53 @@ */ #include -//! [Interesting] #include "mraa/iio.h" +static void +printword(uint16_t input, mraa_iio_channel *chan) +{ + int16_t res; + if (!chan->lendian) { + input = be16toh(input); + } else { + input = le16toh(input); + } + + // currently we don't treat scales + chan->scale = 1.0f; + + input >>= chan->shift; + input &= chan->mask; + if (chan->signedd) { + res = (int16_t)(input << (16 - chan->bits_used)) >> (16 - chan->bits_used); + } else { + res = input; + } + printf("chan %d == %05f\n", chan->index, ((float)res + chan->offset) * chan->scale); +} + +mraa_iio_context iio_device0; + +void +interrupt(char* data) +{ + mraa_iio_channel* channels = mraa_iio_get_channels(iio_device0); + int i = 0; + + for (i; i < mraa_iio_get_channel_count(iio_device0); i++) { + printf("channel bytes %d\n", channels[i].bytes); + switch (channels[i].bytes) { + case 2: + printword(*(uint16_t *)(data + channels[i].location), &channels[i]); + } + } + printf("data %s\n", (char*) data); +} + int main() { - mraa_iio_context iio_device0; - + //! [Interesting] iio_device0 = mraa_iio_init(0); if (iio_device0 == NULL) { return EXIT_FAILURE; @@ -42,6 +81,11 @@ main() fprintf(stdout, "IIO read %f\n", iio_value); } - return EXIT_SUCCESS; + if (mraa_iio_trigger_buffer(iio_device0, interrupt, NULL) == MRAA_SUCCESS) { + sleep(100); + return EXIT_SUCCESS; + } + + //! [Interesting] + return EXIT_FAILURE; } -//! [Interesting] diff --git a/include/mraa_internal_types.h b/include/mraa_internal_types.h index 06bc7d8..844509f 100644 --- a/include/mraa_internal_types.h +++ b/include/mraa_internal_types.h @@ -29,6 +29,7 @@ #include "mraa.h" #include "mraa_func.h" #include "mraa_adv_func.h" +#include "iio.h" // Bionic does not implement pthread cancellation API #ifndef __BIONIC__ @@ -135,8 +136,13 @@ struct _uart { struct _iio { int num; /**< IIO device number */ char* name; /**< IIO device name */ - int channum; - int attrnum; + int fp; /**< IIO device in /dev */ + void (* isr)(char* data); /**< the interupt service request */ + void *isr_args; /**< args return when interupt service request triggered */ + int chan_num; + pthread_t thread_id; /**< the isr handler thread id */ + mraa_iio_channel* channels; + int datasize; }; /** diff --git a/src/iio/iio.c b/src/iio/iio.c index d26159f..7be318f 100644 --- a/src/iio/iio.c +++ b/src/iio/iio.c @@ -26,8 +26,13 @@ #include "mraa_internal.h" #include "dirent.h" #include +#include -#define IIO_SYSFS_DEVICE "/sys/bus/iio/devices/iio:device" +#define MAX_SIZE 128 +#define IIO_DEVICE "iio:device" +#define IIO_SCAN_ELEM "scan_elements" +#define IIO_SLASH_DEV "/dev/"IIO_DEVICE +#define IIO_SYSFS_DEVICE "/sys/bus/iio/devices/"IIO_DEVICE mraa_iio_context mraa_iio_init(int device) @@ -36,9 +41,107 @@ mraa_iio_init(int device) return NULL; } + mraa_iio_get_channel_data(&plat->iio_devices[device]); return &plat->iio_devices[device]; } +int +mraa_iio_read_size(mraa_iio_context dev) +{ + return dev->datasize; +} + +mraa_iio_channel* +mraa_iio_get_channels(mraa_iio_context dev) +{ + return dev->channels; +} + +int +mraa_iio_get_channel_count(mraa_iio_context dev) +{ + return dev->chan_num; +} + +mraa_result_t +mraa_iio_get_channel_data(mraa_iio_context dev) +{ + const struct dirent *ent; + DIR* dir; + int chan_num = 0; + char buf[MAX_SIZE]; + char readbuf[32]; + int fd; + int ret = 0; + int padint = 0; + int curr_bytes = 0; + char shortbuf, signchar; + memset(buf, 0, MAX_SIZE); + snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/" IIO_SCAN_ELEM, dev->num); + dir = opendir(buf); + if (dir != NULL) { + while ((ent = readdir(dir)) != NULL) { + if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), "_en") == 0) { + chan_num++; + } + } + } + dev->chan_num = chan_num; + mraa_iio_channel* chan; + dev->channels = calloc(chan_num, sizeof(mraa_iio_channel)); + seekdir(dir, 0); + while ((ent = readdir(dir)) != NULL) { + if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_index"), "_index") == 0) { + snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/" IIO_SCAN_ELEM "/%s", dev->num, ent->d_name); + fd = open(buf, O_RDONLY); + if (fd > 0) { + if (read(fd, readbuf, 2 * sizeof(char)) != 2) { + break; + } + chan_num = ((int) strtol(readbuf, NULL, 10)); + chan = &dev->channels[chan_num]; + chan->index = chan_num; + close(fd); + + buf[(strlen(buf)-5)] = '\0'; + char* str = strdup(buf); + snprintf(buf, MAX_SIZE, "%stype", str); + fd = open(buf, O_RDONLY); + if (fd > 0) { + read(fd, readbuf, 31 * sizeof(char)); + ret = sscanf(readbuf, "%ce:%c%u/%u>>%u", &shortbuf, + &signchar, &chan->bits_used, + &padint, &chan->shift); + chan->bytes = padint / 8; + if (curr_bytes % chan->bytes == 0) { + chan->location = curr_bytes; + } else { + chan->location = curr_bytes - curr_bytes%chan->bytes + chan->bytes; + } + curr_bytes = chan->location + chan->bytes; + if (ret < 0) { + // probably should be 5? + return MRAA_IO_SETUP_FAILURE; + } + chan->signedd = (signchar == 's'); + chan->lendian = (shortbuf == 'l'); + if (chan->bits_used == 64) { + chan->mask = ~0; + } else { + chan->mask = (1 << chan->bits_used) - 1; + } + + close(fd); + } + // todo - read scale & _en attributes + } + } + } + dev->datasize = curr_bytes; + + return MRAA_SUCCESS; +} + const char* mraa_iio_get_device_name(mraa_iio_context dev) { @@ -49,7 +152,7 @@ mraa_result_t mraa_iio_read(mraa_iio_context dev, const char* attr_chan, float* data) { char buf[64]; - snprintf(buf, 64, IIO_SYSFS_DEVICE, "%d/%s", dev->num, attr_chan); + snprintf(buf, 64, IIO_SYSFS_DEVICE "%d/%s", dev->num, attr_chan); int fd = open(buf, O_RDONLY); if (fd != -1) { int len = read(fd, &buf, 64); @@ -65,7 +168,69 @@ mraa_iio_write(mraa_iio_context dev, const char* attr_chan) return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; } +static mraa_result_t +mraa_iio_wait_event(int fd, char* data) +{ + struct pollfd pfd; + + if (fd < 0) { + return MRAA_ERROR_INVALID_RESOURCE; + } + + pfd.fd = fd; + pfd.events = POLLIN; + + // Wait for it forever or until pthread_cancel + // poll is a cancelable point like sleep() + int x = poll(&pfd, 1, -1); + + memset(data, 0, 100); + read(fd, data, 100); + + return MRAA_SUCCESS; +} + +static void* +mraa_iio_trigger_handler(void* arg) +{ + mraa_iio_context dev = (mraa_iio_context) arg; + char data[MAX_SIZE*100]; + + for (;;) { + if (mraa_iio_wait_event(dev->fp, &data[0]) == MRAA_SUCCESS) { + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + dev->isr(&data); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + } else { + // we must have got an error code so die nicely + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + return NULL; + } + } +} + +mraa_result_t +mraa_iio_trigger_buffer(mraa_iio_context dev, void (*fptr)(char* data), void* args) +{ + char bu[MAX_SIZE]; + if (dev->thread_id != 0) { + return MRAA_ERROR_NO_RESOURCES; + } + + sprintf(bu, IIO_SLASH_DEV "%d", dev->num); + dev->fp = open(bu, O_RDONLY | O_NONBLOCK); + if (dev->fp == -1) { + return MRAA_ERROR_INVALID_RESOURCE; + } + + dev->isr = fptr; + pthread_create(&dev->thread_id, NULL, mraa_iio_trigger_handler, (void*) dev); + + return MRAA_SUCCESS; +} + #if 0 +// does stop make any sense on iio devices? mraa_result_t mraa_iio_stop(mraa_iio_context dev) { diff --git a/src/mraa.c b/src/mraa.c index e0ec89d..bdc91bc 100644 --- a/src/mraa.c +++ b/src/mraa.c @@ -132,7 +132,6 @@ mraa_init() if (plat != NULL) plat->platform_type = platform_type; -#if defined(USBPLAT) // This is a platform extender so create null base platform if one doesn't already exist if (plat == NULL) { plat = (mraa_board_t*) calloc(1, sizeof(mraa_board_t)); @@ -141,6 +140,7 @@ mraa_init() plat->platform_name = "Null platform"; } } +#if defined(USBPLAT) // Now detect sub platform if (plat != NULL) { mraa_platform_t usb_platform_type = mraa_usb_platform_extender(plat); -- 2.7.4