Verified Commit 5459eead authored by Rahix's avatar Rahix
Browse files

feat(epicardium): Add sensor stream API



Signed-off-by: Rahix's avatarRahix <rahix@rahix.de>
parent 6fe49323
#ifndef _EPICARDIUM_H
#define _EPICARDIUM_H
#include <stdint.h>
#include <stddef.h>
#include <errno.h>
#ifndef API
#define API(id, def) def
......@@ -12,6 +14,7 @@
#define API_LEDS_SET 0x3
#define API_VIBRA_SET 0x4
#define API_VIBRA_VIBRATE 0x5
#define API_STREAM_READ 0x6
/* clang-format on */
/**
......@@ -55,6 +58,61 @@ API(API_UART_READ, char epic_uart_read_chr(void));
*/
API(API_LEDS_SET, void epic_leds_set(int led, uint8_t r, uint8_t g, uint8_t b));
/**
* Sensor Data Streams
* ===================
* A few of card10's sensors can do continuous measurements. To allow
* performant access to their data, the following function is made for generic
* access to streams.
*/
/**
* Read sensor data into a buffer. ``epic_stream_read()`` will read as many
* sensor data packets as possible into ``buf`` and return as soon as possible.
* It will poke the sensor driver once to check whether new data can be fetched.
* If there is no new sensor data, ``epic_stream_read()`` will return ``0`` and
* not touch ``buf``. Otherwise it will return the number of data packets which
* were read into ``buf``.
*
* :param int sd: Sensor Descriptor. You get sensor descriptors as return
* values when activating the respective sensors.
* :param void* buf: Buffer where sensor data should be read into.
* :param size_t count: How many bytes to read at max. Note that fewer bytes
* might be read. In most cases, this should be ``sizeof(buf)``.
* :return: Number of data packets read (**not** number of bytes) or a negative
* error value. Possible errors:
*
* - ``-ENODEV``: Sensor is not currently available.
* - ``-EBADF``: The given sensor descriptor is unknown.
* - ``-EINVAL``: If ``count`` is not a multiple of the sensor data packet
* size.
*
* **Example**:
*
* .. code-block:: cpp
*
* #include "epicardium.h"
*
* struct foo_measurement sensor_data[16];
* int foo_sd, n;
*
* foo_sd = epic_foo_sensor_enable(9001);
*
* while (1) {
* n = epic_stream_read(
* foo_sd,
* &sensor_data,
* sizeof(sensor_data)
* );
*
* // Print out the measured sensor samples
* for (int i = 0; i < n; i++) {
* printf("Measured: %?\n", sensor_data[i]);
* }
* }
*/
API(API_STREAM_READ, int epic_stream_read(int sd, void *buf, size_t count));
/**
* Misc
* ====
......
......@@ -11,6 +11,7 @@
#include "api/dispatcher.h"
#include "modules/modules.h"
#include "modules/log.h"
#include "modules/stream.h"
#include <Heart.h>
#include "GUI_Paint.h"
......@@ -53,6 +54,7 @@ int main(void)
}
fatfs_init();
stream_init();
LOG_INFO("startup", "Initializing tasks ...");
......
......@@ -4,5 +4,6 @@ module_sources = files(
'log.c',
'pmic.c',
'serial.c',
'stream.c',
'vibra.c',
)
......@@ -15,4 +15,3 @@ void vSerialTask(void *pvParameters);
void vPmicTask(void *pvParameters);
#endif /* MODULES_H */
#include <string.h>
#include "epicardium.h"
#include "stream.h"
static struct stream_info *stream_table[SD_MAX];
int stream_init()
{
memset(stream_table, 0x00, sizeof(stream_table));
return 0;
}
int stream_register(int sd, struct stream_info *stream)
{
if (sd < 0 || sd >= SD_MAX) {
return -EINVAL;
}
if (stream_table[sd] != NULL) {
/* Stream already registered */
return -EACCES;
}
stream_table[sd] = stream;
return 0;
}
int stream_deregister(int sd, struct stream_info *stream)
{
if (sd < 0 || sd >= SD_MAX) {
return -EINVAL;
}
if (stream_table[sd] != stream) {
/* Stream registered by someone else */
return -EACCES;
}
stream_table[sd] = NULL;
return 0;
}
int epic_stream_read(int sd, void *buf, size_t count)
{
if (sd < 0 || sd >= SD_MAX) {
return -EBADF;
}
struct stream_info *stream = stream_table[sd];
if (stream == NULL) {
return -ENODEV;
}
/* Poll the stream */
int ret = stream->poll_stream();
if (ret < 0) {
return ret;
}
/* Check buffer sizing */
if (count % stream->item_size != 0) {
return -EINVAL;
}
size_t i;
for (i = 0; i < count; i += stream->item_size) {
if (!xQueueReceive(stream->queue, buf + i, 10)) {
break;
}
}
return i / stream->item_size;
}
#ifndef STREAM_H
#define STREAM_H
#include <stddef.h>
#include <stdint.h>
#include "FreeRTOS.h"
#include "queue.h"
/**
* **Stream Descriptors**:
*
* All supported streams have to have a unique ID in this list. ``SD_MAX``
* must be greater than or equal to the highest defined ID. Please keep IDs
* in sequential order.
*/
enum stream_descriptor {
/** Highest descriptor must always be ``SD_MAX``. */
SD_MAX,
};
struct stream_info {
QueueHandle_t queue;
size_t item_size;
int (*poll_stream)();
};
/**
* Register a stream so it can be read from Epicardium API.
*
* :param int sd: Stream Descriptor. Must be from the above enum.
* :param stream_info stream: Stream info.
* :returns: ``0`` on success or a negative value on error. Possible errors:
*
* - ``-EINVAL``: Out of range sensor descriptor.
* - ``-EACCES``: Stream already registered.
*/
int stream_register(int sd, struct stream_info *stream);
/**
* Deregister a stream.
*
* :param int sd: Stream Descriptor.
* :param stream_info stream: The stream which should be registered for the
* stream ``sd``. If a different stream is registered, this function
* will return an error.
* :returns: ``0`` on success or a negative value on error. Possible errors:
*
* - ``-EINVAL``: Out of range sensor descriptor.
* - ``-EACCES``: Stream ``stream`` was not registered for ``sd``.
*/
int stream_deregister(int sd, struct stream_info *stream);
/*
* Initialize stream interface. Called by main().
*/
int stream_init();
#endif /* STREAM_H */
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment