epicardium.h 58.4 KB
Newer Older
Rahix's avatar
Rahix committed
1
2
#ifndef _EPICARDIUM_H
#define _EPICARDIUM_H
Rahix's avatar
Rahix committed
3

Rahix's avatar
Rahix committed
4
#include <stdint.h>
5
#include <errno.h>
Rahix's avatar
Rahix committed
6

Rahix's avatar
Rahix committed
7
#ifndef __SPHINX_DOC
fleur's avatar
fleur committed
8
/* Some headers are not recognized by hawkmoth for some odd reason */
Rahix's avatar
Rahix committed
9
#include <stddef.h>
fleur's avatar
fleur committed
10
#include <stdbool.h>
Rahix's avatar
Rahix committed
11
12
#else
typedef unsigned int size_t;
fleur's avatar
fleur committed
13
typedef _Bool bool;
Rahix's avatar
Rahix committed
14
15
16
17
18
#endif /* __SPHINX_DOC */

/*
 * These definitions are required for the code-generator.  Please don't touch!
 */
Rahix's avatar
Rahix committed
19
#ifndef API
Rahix's avatar
Rahix committed
20
#define API(id, def) def
Rahix's avatar
Rahix committed
21
#endif
22
23
24
#ifndef API_ISR
#define API_ISR(id, isr) void isr(void);
#endif
Rahix's avatar
Rahix committed
25

26
27
28
29
30
31
/*
 * IDs for all defined API calls.  These IDs should not be needed in application
 * code on any side.
 */

/* clang-format off */
Rahix's avatar
Rahix committed
32
33
#define API_SYSTEM_EXIT             0x1
#define API_SYSTEM_EXEC             0x2
Rahix's avatar
Rahix committed
34
#define API_SYSTEM_RESET            0x3
35
#define API_BATTERY_VOLTAGE         0x4
36
37
38
39
40
41
42
43
44

#define API_INTERRUPT_ENABLE        0xA
#define API_INTERRUPT_DISABLE       0xB

#define API_UART_WRITE_STR         0x10
#define API_UART_READ_CHAR         0x11
#define API_UART_READ_STR          0x12

#define API_STREAM_READ            0x1F
Rahix's avatar
Rahix committed
45
46
47
48
49
50
51
52
53
54
55

#define API_DISP_OPEN              0x20
#define API_DISP_CLOSE             0x21
#define API_DISP_PRINT             0x22
#define API_DISP_CLEAR             0x23
#define API_DISP_UPDATE            0x24
#define API_DISP_LINE              0x25
#define API_DISP_RECT              0x26
#define API_DISP_CIRC              0x27
#define API_DISP_PIXEL             0x28
#define API_DISP_FRAMEBUFFER       0x29
56
#define API_DISP_BACKLIGHT         0x2a
57
#define API_DISP_PRINT_ADV         0x2b
Rahix's avatar
Rahix committed
58

Stefan Haun's avatar
Stefan Haun committed
59
60
61
62
63
64
65
/* API_BATTERY_VOLTAGE              0x30 */
#define API_BATTERY_CURRENT        0x31
#define API_CHARGEIN_VOLTAGE       0x32
#define API_CHARGEIN_CURRENT       0x33
#define API_SYSTEM_VOLTAGE         0x34
#define API_THERMISTOR_VOLTAGE     0x35

Rahix's avatar
Rahix committed
66
67
68
69
70
71
72
73
#define API_FILE_OPEN              0x40
#define API_FILE_CLOSE             0x41
#define API_FILE_READ              0x42
#define API_FILE_WRITE             0x44
#define API_FILE_FLUSH             0x45
#define API_FILE_SEEK              0x46
#define API_FILE_TELL              0x47
#define API_FILE_STAT              0x48
74
75
76
#define API_FILE_OPENDIR           0x49
#define API_FILE_READDIR           0x4a
#define API_FILE_UNLINK            0x4b
swym's avatar
swym committed
77
78
#define API_FILE_RENAME            0x4c
#define API_FILE_MKDIR             0x4d
Rahix's avatar
Rahix committed
79
80
81

#define API_RTC_GET_SECONDS        0x50
#define API_RTC_SCHEDULE_ALARM     0x51
Hauke Mehrtens's avatar
Hauke Mehrtens committed
82
#define API_RTC_SET_MILLISECONDS   0x52
83
#define API_RTC_GET_MILLISECONDS   0x53
84
85
#define API_RTC_GET_MONOTONIC_SECONDS      0x54
#define API_RTC_GET_MONOTONIC_MILLISECONDS 0x55
Rahix's avatar
Rahix committed
86
87

#define API_LEDS_SET               0x60
fleur's avatar
fleur committed
88
89
90
91
92
93
94
95
96
97
98
99
#define API_LEDS_SET_HSV           0x61
#define API_LEDS_PREP              0x62
#define API_LEDS_PREP_HSV          0x63
#define API_LEDS_UPDATE            0x64
#define API_LEDS_SET_POWERSAVE     0x65
#define API_LEDS_SET_ROCKET        0x66
#define API_LEDS_SET_FLASHLIGHT    0x67
#define API_LEDS_DIM_TOP           0x68
#define API_LEDS_DIM_BOTTOM        0x69
#define API_LEDS_SET_ALL           0x6a
#define API_LEDS_SET_ALL_HSV       0x6b
#define API_LEDS_SET_GAMMA_TABLE   0x6c
100
#define API_LEDS_CLEAR_ALL         0x6d
101
#define API_LEDS_GET_ROCKET        0x6e
102
#define API_LEDS_GET               0x6f
Rahix's avatar
Rahix committed
103
104
105
106
107
108
109

#define API_VIBRA_SET              0x70
#define API_VIBRA_VIBRATE          0x71

#define API_LIGHT_SENSOR_RUN       0x80
#define API_LIGHT_SENSOR_GET       0x81
#define API_LIGHT_SENSOR_STOP      0x82
110
#define API_LIGHT_SENSOR_READ	   0x83
Rahix's avatar
Rahix committed
111
112

#define API_BUTTONS_READ           0x90
113
114
115
116
117

#define API_GPIO_SET_PIN_MODE      0xA0
#define API_GPIO_GET_PIN_MODE      0xA1
#define API_GPIO_WRITE_PIN         0xA2
#define API_GPIO_READ_PIN          0xA3
118
119
120

#define API_TRNG_READ              0xB0

121
122
123
124
#define API_PERSONAL_STATE_SET     0xc0
#define API_PERSONAL_STATE_GET     0xc1
#define API_PERSONAL_STATE_IS_PERSISTENT 0xc2

chris007's avatar
chris007 committed
125
126
127
128
#define API_BME680_INIT            0xD0
#define API_BME680_DEINIT          0xD1
#define API_BME680_GET_DATA        0xD2

129
130
#define API_BHI160_ENABLE          0xe0
#define API_BHI160_DISABLE         0xe1
131
#define API_BHI160_DISABLE_ALL     0xe2
132

schneider's avatar
schneider committed
133
134
135
#define API_MAX30001_ENABLE        0xf0
#define API_MAX30001_DISABLE       0xf1

136
137
#define API_MAX86150_ENABLE        0x0100
#define API_MAX86150_DISABLE       0x0101
138

swym's avatar
swym committed
139
140
141
142
#define API_USB_SHUTDOWN           0x110
#define API_USB_STORAGE            0x111
#define API_USB_CDCACM             0x112

143
144
#define API_WS2812_WRITE           0x0120

145
146
147
#define API_CONFIG_GET_STRING      0x130
#define API_CONFIG_GET_INTEGER     0x131
#define API_CONFIG_GET_BOOLEAN     0x132
148
149
150
151
152
153
154
155
156
157
158
/* clang-format on */

typedef uint32_t api_int_id_t;

/**
 * Interrupts
 * ==========
 * Next to API calls, Epicardium API also has an interrupt mechanism to serve
 * the other direction.  These interrupts can be enabled/disabled
 * (masked/unmasked) using :c:func:`epic_interrupt_enable` and
 * :c:func:`epic_interrupt_disable`.
159
160
161
162
163
164
165
 *
 * .. warning::
 *
 *    Never attempt to call the API from inside an ISR.  This might trigger an
 *    assertion if a call is already being made from thread context.  We plan to
 *    lift this restriction at some point, but for the time being, this is how
 *    it is.
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
 */

/**
 * Enable/unmask an API interrupt.
 *
 * :param int_id: The interrupt to be enabled
 */
API(API_INTERRUPT_ENABLE, int epic_interrupt_enable(api_int_id_t int_id));

/**
 * Disable/mask an API interrupt.
 *
 * :param int_id: The interrupt to be disabled
 */
API(API_INTERRUPT_DISABLE, int epic_interrupt_disable(api_int_id_t int_id));

/**
 * The following interrupts are defined:
 */
185

186
/* clang-format off */
Rahix's avatar
Rahix committed
187
/** Reset Handler */
188
189
190
#define EPIC_INT_RESET                  0
/** ``^C`` interrupt. See :c:func:`epic_isr_ctrl_c` for details.  */
#define EPIC_INT_CTRL_C                 1
191
/** UART Receive interrupt.  See :c:func:`epic_isr_uart_rx`. */
Rahix's avatar
Rahix committed
192
#define EPIC_INT_UART_RX                2
193
/** RTC Alarm interrupt.  See :c:func:`epic_isr_rtc_alarm`. */
Rahix's avatar
Rahix committed
194
#define EPIC_INT_RTC_ALARM              3
195
/** BHI160 Accelerometer.  See :c:func:`epic_isr_bhi160_accelerometer`. */
196
#define EPIC_INT_BHI160_ACCELEROMETER	4
197
/** BHI160 Orientation Sensor.  See :c:func:`epic_isr_bhi160_orientation`. */
198
#define EPIC_INT_BHI160_ORIENTATION	5
199
/** BHI160 Gyroscope.  See :c:func:`epic_isr_bhi160_gyroscope`. */
200
#define EPIC_INT_BHI160_GYROSCOPE	6
201
/** MAX30001 ECG.  See :c:func:`epic_isr_max30001_ecg`. */
202
#define EPIC_INT_MAX30001_ECG		7
203
204
/** BHI160 Magnetometer.  See :c:func:`epic_isr_bhi160_magnetometer`. */
#define EPIC_INT_BHI160_MAGNETOMETER    8
205
206
/** MAX86150 ECG and PPG sensor.  See :c:func:`epic_isr_max86150`. */
#define EPIC_INT_MAX86150		9
Rahix's avatar
Rahix committed
207

208
/* Number of defined interrupts. */
209
#define EPIC_INT_NUM                    10
Rahix's avatar
Rahix committed
210
211
/* clang-format on */

Rahix's avatar
Rahix committed
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
/*
 * "Reset Handler*.  This isr is implemented by the API caller and is used to
 * reset the core for loading a new payload.
 *
 * Just listed here for completeness.  You don't need to implement this yourself.
 */
API_ISR(EPIC_INT_RESET, __epic_isr_reset);

/**
 * Core API
 * ========
 * The following functions control execution of code on core 1.
 */

/**
 * Stop execution of the current payload and return to the menu.
 *
 * :param int ret:  Return code.
 * :return: :c:func:`epic_exit` will never return.
 */
void epic_exit(int ret) __attribute__((noreturn));

/*
 * The actual epic_exit() function is not an API call because it needs special
 * behavior.  The underlying call is __epic_exit() which returns.  After calling
 * this API function, epic_exit() will enter the reset handler.
 */
API(API_SYSTEM_EXIT, void __epic_exit(int ret));
240

Rahix's avatar
Rahix committed
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
/**
 * Stop execution of the current payload and immediately start another payload.
 *
 * :param char* name: Name (path) of the new payload to start.  This can either
 *    be:
 *
 *    - A path to an ``.elf`` file (l0dable).
 *    - A path to a ``.py`` file (will be loaded using Pycardium).
 *    - A path to a directory (assumed to be a Python module, execution starts
 *      with ``__init__.py`` in this folder).
 *
 * :return: :c:func:`epic_exec` will only return in case loading went wrong.
 *    The following error codes can be returned:
 *
 *    - ``-ENOENT``: File not found.
 *    - ``-ENOEXEC``: File not a loadable format.
 */
int epic_exec(char *name);

/*
 * Underlying API call for epic_exec().  The function is not an API call itself
 * because it needs special behavior when loading a new payload.
 */
API(API_SYSTEM_EXEC, int __epic_exec(char *name));
265

Rahix's avatar
Rahix committed
266
267
268
269
270
/**
 * Reset/Restart card10
 */
API(API_SYSTEM_RESET, void epic_system_reset(void));

271
/**
Stefan Haun's avatar
Stefan Haun committed
272
 * PMIC API
273
274
275
 * ===============
 */

Stefan Haun's avatar
Stefan Haun committed
276

277
278
279
280
281
/**
 * Read the current battery voltage.
 */
API(API_BATTERY_VOLTAGE, int epic_read_battery_voltage(float *result));

Stefan Haun's avatar
Stefan Haun committed
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
/**
 * Read the current battery current.
 */
API(API_BATTERY_CURRENT, int epic_read_battery_current(float *result));

/**
 * Read the current charge voltage.
 */
API(API_CHARGEIN_VOLTAGE, int epic_read_chargein_voltage(float *result));

/**
 * Read the current charge current.
 */
API(API_CHARGEIN_CURRENT, int epic_read_chargein_current(float *result));

/**
 * Read the current system voltage.
 */
API(API_SYSTEM_VOLTAGE, int epic_read_system_voltage(float *result));

/**
 * Read the current thermistor voltage.
 */
API(API_THERMISTOR_VOLTAGE, int epic_read_thermistor_voltage(float *result));


Rahix's avatar
Rahix committed
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
/**
 * UART/Serial Interface
 * =====================
 */

/**
 * Write a string to all connected serial devices.  This includes:
 *
 * - Real UART, whose pins are mapped onto USB-C pins.  Accessible via the HW-debugger.
 * - A CDC-ACM device available via USB.
 * - Maybe, in the future, bluetooth serial?
 *
 * :param str:  String to write.  Does not necessarily have to be NULL-terminated.
 * :param length:  Amount of bytes to print.
 */
323
API(API_UART_WRITE_STR, void epic_uart_write_str(
324
	const char *str, size_t length
325
));
Rahix's avatar
Rahix committed
326

Rahix's avatar
Rahix committed
327
/**
328
 * Try reading a single character from any connected serial device.
329
 *
330
 * If nothing is available, :c:func:`epic_uart_read_char` returns ``(-1)``.
331
 *
332
333
334
335
 * :return:  The byte or ``(-1)`` if no byte was available.
 */
API(API_UART_READ_CHAR, int epic_uart_read_char(void));

336
337
338
339
340
341
342
343
344
345
346
347
348
/**
 * Read as many characters as possible from the UART queue.
 *
 * :c:func:`epic_uart_read_str` will not block if no new data is available.  For
 * an example, see :c:func:`epic_isr_uart_rx`.
 *
 * :param char* buf: Buffer to be filled with incoming data.
 * :param size_t cnt: Size of ``buf``.
 * :returns: Number of bytes read.  Can be ``0`` if no data was available.
 *    Might be a negative value if an error occured.
 */
API(API_UART_READ_STR, int epic_uart_read_str(char *buf, size_t cnt));

349
/**
350
 * **Interrupt Service Routine** for :c:data:`EPIC_INT_UART_RX`
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
 *
 * UART receive interrupt.  This interrupt is triggered whenever a new character
 * becomes available on any connected UART device.  This function is weakly
 * aliased to :c:func:`epic_isr_default` by default.
 *
 * **Example**:
 *
 * .. code-block:: cpp
 *
 *    void epic_isr_uart_rx(void)
 *    {
 *            char buffer[33];
 *            int n = epic_uart_read_str(&buffer, sizeof(buffer) - 1);
 *            buffer[n] = '\0';
 *            printf("Got: %s\n", buffer);
 *    }
 *
 *    int main(void)
 *    {
 *            epic_interrupt_enable(EPIC_INT_UART_RX);
Rahix's avatar
Rahix committed
371
 *
372
373
374
375
 *            while (1) {
 *                    __WFI();
 *            }
 *    }
Rahix's avatar
Rahix committed
376
 */
377
API_ISR(EPIC_INT_UART_RX, epic_isr_uart_rx);
Rahix's avatar
Rahix committed
378

379
/**
380
 * **Interrupt Service Routine** for :c:data:`EPIC_INT_CTRL_C`
381
382
383
384
385
386
387
388
389
390
391
392
393
 *
 * A user-defineable ISR which is triggered when a ``^C`` (``0x04``) is received
 * on any serial input device.  This function is weakly aliased to
 * :c:func:`epic_isr_default` by default.
 *
 * To enable this interrupt, you need to enable :c:data:`EPIC_INT_CTRL_C`:
 *
 * .. code-block:: cpp
 *
 *    epic_interrupt_enable(EPIC_INT_CTRL_C);
 */
API_ISR(EPIC_INT_CTRL_C, epic_isr_ctrl_c);

Rahix's avatar
Rahix committed
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
/**
 * Buttons
 * =======
 *
 */

/** Button IDs */
enum epic_button {
	/** ``1``, Bottom left button (bit 0). */
	BUTTON_LEFT_BOTTOM   = 1,
	/** ``2``, Bottom right button (bit 1). */
	BUTTON_RIGHT_BOTTOM  = 2,
	/** ``4``, Top right button (bit 2). */
	BUTTON_RIGHT_TOP     = 4,
	/** ``8``, Top left (power) button (bit 3). */
	BUTTON_LEFT_TOP      = 8,
	/** ``8``, Top left (power) button (bit 3). */
	BUTTON_RESET         = 8,
};

/**
 * Read buttons.
 *
 * :c:func:`epic_buttons_read` will read all buttons specified in ``mask`` and
 * return set bits for each button which was reported as pressed.
 *
 * .. note::
 *
 *    The reset button cannot be unmapped from reset functionality.  So, while
 *    you can read it, it cannot be used for app control.
 *
 * **Example**:
 *
 * .. code-block:: cpp
 *
 *    #include "epicardium.h"
 *
 *    uint8_t pressed = epic_buttons_read(BUTTON_LEFT_BOTTOM | BUTTON_RIGHT_BOTTOM);
 *
 *    if (pressed & BUTTON_LEFT_BOTTOM) {
 *            // Bottom left button is pressed
 *    }
 *
 *    if (pressed & BUTTON_RIGHT_BOTTOM) {
 *            // Bottom right button is pressed
 *    }
 *
 * :param uint8_t mask: Mask of buttons to read.  The 4 LSBs correspond to the 4
 *     buttons:
 *
 *     ===== ========= ============ ===========
 *     ``3`` ``2``     ``1``        ``0``
 *     ----- --------- ------------ -----------
 *     Reset Right Top Right Bottom Left Bottom
 *     ===== ========= ============ ===========
 *
 *     Use the values defined in :c:type:`epic_button` for masking, as shown in
 *     the example above.
 * :return: Returns nonzero value if unmasked buttons are pushed.
 */
API(API_BUTTONS_READ, uint8_t epic_buttons_read(uint8_t mask));

456
457
458
459
460
461
462
463
/**
 * Wristband GPIO
 * ==============
 */

/** GPIO pins IDs */
enum gpio_pin {
    /** ``1``, Wristband connector 1 */
464
    EPIC_GPIO_WRISTBAND_1 = 1,
465
    /** ``2``, Wristband connector 2 */
466
    EPIC_GPIO_WRISTBAND_2 = 2,
467
    /** ``3``, Wristband connector 3 */
468
    EPIC_GPIO_WRISTBAND_3 = 3,
469
    /** ``4``, Wristband connector 4 */
470
    EPIC_GPIO_WRISTBAND_4 = 4,
471
472
473
474
475
};

/** GPIO pin modes */
enum gpio_mode {
    /** Configure the pin as input */
476
    EPIC_GPIO_MODE_IN = (1<<0),
477
    /** Configure the pin as output */
478
    EPIC_GPIO_MODE_OUT = (1<<1),
479
    EPIC_GPIO_MODE_ADC = (1<<2),
480
481

    /** Enable the internal pull-up resistor */
482
    EPIC_GPIO_PULL_UP = (1<<6),
483
    /** Enable the internal pull-down resistor */
484
    EPIC_GPIO_PULL_DOWN = (1<<7),
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
};

/**
 * Set the mode of a card10 GPIO pin.
 *
 * :c:func:`epic_gpio_set_pin_mode` will set the pin specified by ``pin`` to the mode ``mode``.
 * If the specified pin ID is not valid this function will do nothing.
 *
 * **Example:**
 *
 * .. code-block:: cpp
 *
 *    #include "epicardium.h"
 *
 *    // Configure wristband pin 1 as output.
 *    if (epic_gpio_set_pin_mode(GPIO_WRISTBAND_1, GPIO_MODE_OUT)) {
 *        // Do your error handling here...
 *    }
 *
 * :param uint8_t pin: ID of the pin to configure. Use on of the IDs defined in :c:type:`gpio_pin`.
 * :param uint8_t mode: Mode to be configured. Use a combination of the :c:type:`gpio_mode` flags.
 * :returns: ``0`` if the mode was set, ``-EINVAL`` if ``pin`` is not valid or the mode could not be set.
 */
508
509
510
API(API_GPIO_SET_PIN_MODE, int epic_gpio_set_pin_mode(
	uint8_t pin, uint8_t mode
));
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582

/**
 * Get the mode of a card10 GPIO pin.
 *
 * :c:func:`epic_gpio_get_pin_mode` will get the current mode of the GPIO pin specified by ``pin``.
 *
 * **Example:**
 *
 * .. code-block:: cpp
 *
 *    #include "epicardium.h"
 *
 *    // Get the mode of wristband pin 1.
 *    int mode = epic_gpio_get_pin_mode(GPIO_WRISTBAND_1);
 *    if (mode < 0) {
 *        // Do your error handling here...
 *    } else {
 *        // Do something with the queried mode information
 *    }
 *
 * :param uint8_t pin: ID of the pin to get the configuration of. Use on of the IDs defined in :c:type:`gpio_pin`.
 * :returns: Configuration byte for the specified pin or ``-EINVAL`` if the pin is not valid.
 */
API(API_GPIO_GET_PIN_MODE, int epic_gpio_get_pin_mode(uint8_t pin));

/**
 * Write value to a card10 GPIO pin,
 *
 * :c:func:`epic_gpio_write_pin` will set the value of the GPIO pin described by ``pin`` to either on or off depending on ``on``.
 *
 * **Example:**
 *
 * .. code-block:: cpp
 *
 *    #include "epicardium.h"
 *
 *    // Get the mode of wristband pin 1.
 *    int mode = epic_gpio_get_pin_mode(GPIO_WRISTBAND_1);
 *    if (mode < 0) {
 *        // Do your error handling here...
 *    } else {
 *        // Do something with the queried mode information
 *    }
 *
 * :param uint8_t pin: ID of the pin to get the configuration of. Use on of the IDs defined in :c:type:`gpio_pin`.
 * :param bool on: Sets the pin to either true (on/high) or false (off/low).
 * :returns: ``0`` on succcess, ``-EINVAL`` if ``pin`` is not valid or is not configured as an output.
 */
API(API_GPIO_WRITE_PIN, int epic_gpio_write_pin(uint8_t pin, bool on));

/**
 * Read value of a card10 GPIO pin.
 *
 * :c:func:`epic_gpio_read_pin` will get the value of the GPIO pin described by ``pin``.
 *
 * **Example:**
 *
 * .. code-block:: cpp
 *
 *    #include "epicardium.h"
 *
 *    // Get the current value of wristband pin 1.
 *    uint32_t value = epic_gpio_read_pin(GPIO_WRISTBAND_1);
 *    if (mode == -EINVAL) {
 *        // Do your error handling here...
 *    } else {
 *        // Do something with the current value
 *    }
 *
 * :param uint8_t pin: ID of the pin to get the configuration of. Use on of the IDs defined in :c:type:`gpio_pin`.
 * :returns: ``-EINVAL`` if ``pin`` is not valid, an integer value otherwise.
 */
583
API(API_GPIO_READ_PIN, int epic_gpio_read_pin(uint8_t pin));
584

Rahix's avatar
Rahix committed
585
586
587
588
589
590
/**
 * LEDs
 * ====
 */

/**
fleur's avatar
fleur committed
591
 * Set one of card10's RGB LEDs to a certain color in RGB format.
Rahix's avatar
Rahix committed
592
 *
fleur's avatar
fleur committed
593
594
595
 * This function is rather slow when setting multiple LEDs, use
 * :c:func:`leds_set_all` or :c:func:`leds_prep` + :c:func:`leds_update`
 * instead.
596
 *
fleur's avatar
fleur committed
597
598
599
600
601
 * :param int led:  Which LED to set.  0-10 are the LEDs on the top and 11-14
 *    are the 4 "ambient" LEDs.
 * :param uint8_t r:  Red component of the color.
 * :param uint8_t g:  Green component of the color.
 * :param uint8_t b:  Blue component of the color.
Rahix's avatar
Rahix committed
602
 */
603
604
API(API_LEDS_SET, void epic_leds_set(int led, uint8_t r, uint8_t g, uint8_t b));

605
606
607
608
609
610
611
612
613
614

/**
 * Get one of card10's RGB LEDs in format of RGB.
 *
 * :c:func:`epic_leds_get_rgb` will get the value of a RGB  LED described by ``led``.
 *
 * :param int led:  Which LED to get.  0-10 are the LEDs on the top and 11-14
 *    are the 4 "ambient" LEDs.
 * :param uint8_t * rgb:  need tree byte array to get the value of red, green and blue.
 * :returns: ``0`` on success or ``-EPERM`` if the LED is blocked by personal-state.
Rahix's avatar
Rahix committed
615
616
 *
 * .. versionadded:: 1.10
617
618
619
 */
API(API_LEDS_GET, int epic_leds_get_rgb(int led, uint8_t * rgb));

fleur's avatar
fleur committed
620
621
622
623
624
625
626
627
628
629
630
631
/**
 * Set one of card10's RGB LEDs to a certain color in HSV format.
 *
 * This function is rather slow when setting multiple LEDs, use
 * :c:func:`leds_set_all_hsv` or :c:func:`leds_prep_hsv` + :c:func:`leds_update`
 * instead.
 *
 * :param int led:  Which LED to set.  0-10 are the LEDs on the top and 11-14 are the 4 "ambient" LEDs.
 * :param float h:  Hue component of the color. (0 <= h < 360)
 * :param float s:  Saturation component of the color. (0 <= s <= 1)
 * :param float v:  Value/Brightness component of the color. (0 <= v <= 0)
 */
632
633
634
API(API_LEDS_SET_HSV, void epic_leds_set_hsv(
	int led, float h, float s, float v
));
fleur's avatar
fleur committed
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656

/**
 * Set multiple of card10's RGB LEDs to a certain color in RGB format.
 *
 * The first ``len`` leds are set, the remaining ones are not modified.
 *
 * :param uint8_t[len][r,g,b] pattern:  Array with RGB Values with 0 <= len <=
 *    15. 0-10 are the LEDs on the top and 11-14 are the 4 "ambient" LEDs.
 * :param uint8_t len: Length of 1st dimension of ``pattern``, see above.
 */
API(API_LEDS_SET_ALL, void epic_leds_set_all(uint8_t *pattern, uint8_t len));

/**
 * Set multiple of card10's RGB LEDs to a certain color in HSV format.
 *
 * The first ``len`` led are set, the remaining ones are not modified.
 *
 * :param uint8_t[len][h,s,v] pattern:  Array of format with HSV Values with 0
 *    <= len <= 15.  0-10 are the LEDs on the top and 11-14 are the 4 "ambient"
 *    LEDs. (0 <= h < 360, 0 <= s <= 1, 0 <= v <= 1)
 * :param uint8_t len: Length of 1st dimension of ``pattern``, see above.
 */
657
658
659
API(API_LEDS_SET_ALL_HSV, void epic_leds_set_all_hsv(
	float *pattern, uint8_t len
));
fleur's avatar
fleur committed
660
661
662
663
664
665
666
667
668
669
670
671

/**
 * Prepare one of card10's RGB LEDs to be set to a certain color in RGB format.
 *
 * Use :c:func:`leds_update` to apply changes.
 *
 * :param int led:  Which LED to set.  0-10 are the LEDs on the top and 11-14
 *    are the 4 "ambient" LEDs.
 * :param uint8_t r:  Red component of the color.
 * :param uint8_t g:  Green component of the color.
 * :param uint8_t b:  Blue component of the color.
 */
672
673
674
API(API_LEDS_PREP, void epic_leds_prep(
	int led, uint8_t r, uint8_t g, uint8_t b
));
fleur's avatar
fleur committed
675
676
677
678
679
680
681
682
683
684
685
686

/**
 * Prepare one of card10's RGB LEDs to be set to a certain color in HSV format.
 *
 * Use :c:func:`leds_update` to apply changes.
 *
 * :param int led:  Which LED to set.  0-10 are the LEDs on the top and 11-14
 *    are the 4 "ambient" LEDs.
 * :param uint8_t h:  Hue component of the color. (float, 0 <= h < 360)
 * :param uint8_t s:  Saturation component of the color. (float, 0 <= s <= 1)
 * :param uint8_t v:  Value/Brightness component of the color. (float, 0 <= v <= 0)
 */
687
688
689
API(API_LEDS_PREP_HSV, void epic_leds_prep_hsv(
	int led, float h, float s, float v
));
fleur's avatar
fleur committed
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748

/**
 * Set global brightness for top RGB LEDs.
 *
 * Aside from PWM, the RGB LEDs' overall brightness can be controlled with a
 * current limiter independently to achieve a higher resolution at low
 * brightness which can be set with this function.
 *
 * :param uint8_t value:  Global brightness of top LEDs. (1 <= value <= 8, default = 1)
 */
API(API_LEDS_DIM_BOTTOM, void epic_leds_dim_bottom(uint8_t value));

/**
 * Set global brightness for bottom RGB LEDs.
 *
 * Aside from PWM, the RGB LEDs' overall brightness can be controlled with a
 * current limiter independently to achieve a higher resolution at low
 * brightness which can be set with this function.
 *
 * :param uint8_t value:  Global brightness of bottom LEDs. (1 <= value <= 8, default = 8)
 */
API(API_LEDS_DIM_TOP, void epic_leds_dim_top(uint8_t value));

/**
 * Enables or disables powersave mode.
 *
 * Even when set to zero, the RGB LEDs still individually consume ~1mA.
 * Powersave intelligently switches the supply power in groups. This introduces
 * delays in the magnitude of ~10µs, so it can be disabled for high speed
 * applications such as POV.
 *
 * :param bool eco:  Activates powersave if true, disables it when false. (default = True)
 */
API(API_LEDS_SET_POWERSAVE, void epic_leds_set_powersave(bool eco));

/**
 * Updates the RGB LEDs with changes that have been set with :c:func:`leds_prep`
 * or :c:func:`leds_prep_hsv`.
 *
 * The LEDs can be only updated in bulk, so using this approach instead of
 * :c:func:`leds_set` or :c:func:`leds_set_hsv` significantly reduces the load
 * on the corresponding hardware bus.
 */
API(API_LEDS_UPDATE, void epic_leds_update(void));

/**
 * Set the brightness of one of the rocket LEDs.
 *
 * :param int led:  Which LED to set.
 *
 *    +-------+--------+----------+
 *    |   ID  | Color  | Location |
 *    +=======+========+==========+
 *    | ``0`` | Blue   | Left     |
 *    +-------+--------+----------+
 *    | ``1`` | Yellow | Top      |
 *    +-------+--------+----------+
 *    | ``2`` | Green  | Right    |
 *    +-------+--------+----------+
Rahix's avatar
Rahix committed
749
 * :param uint8_t value:  Brightness of LED (value between 0 and 31).
fleur's avatar
fleur committed
750
751
752
 */
API(API_LEDS_SET_ROCKET, void epic_leds_set_rocket(int led, uint8_t value));

753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
/**
 * Get the brightness of one of the rocket LEDs.
 *
 * :param int led:  Which LED to get.
 *
 *    +-------+--------+----------+
 *    |   ID  | Color  | Location |
 *    +=======+========+==========+
 *    | ``0`` | Blue   | Left     |
 *    +-------+--------+----------+
 *    | ``1`` | Yellow | Top      |
 *    +-------+--------+----------+
 *    | ``2`` | Green  | Right    |
 *    +-------+--------+----------+
 * :returns value:  Brightness of LED (value between 0 and 31)  or ``-EINVAL`` if the LED/rocket does not exists.
Rahix's avatar
Rahix committed
768
769
 *
 * .. versionadded:: 1.10
770
771
772
 */
API(API_LEDS_GET_ROCKET, int epic_leds_get_rocket(int led));

fleur's avatar
fleur committed
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
/**
 * Turn on the bright side LED which can serve as a flashlight if worn on the left wrist or as a rad tattoo illuminator if worn on the right wrist.
 *
 *:param bool power:  Side LED on if true.
 */
API(API_LEDS_SET_FLASHLIGHT, void epic_set_flashlight(bool power));

/**
 * Set gamma lookup table for individual rgb channels.
 *
 * Since the RGB LEDs' subcolor LEDs have different peak brightness and the
 * linear scaling introduced by PWM is not desireable for color accurate work,
 * custom lookup tables for each individual color channel can be loaded into the
 * Epicardium's memory with this function.
 *
 * :param uint8_t rgb_channel:  Color whose gamma table is to be updated, 0->Red, 1->Green, 2->Blue.
 * :param uint8_t[256] gamma_table: Gamma lookup table. (default = 4th order power function rounded up)
 */
API(API_LEDS_SET_GAMMA_TABLE, void epic_leds_set_gamma_table(
792
	uint8_t rgb_channel, uint8_t *gamma_table
fleur's avatar
fleur committed
793
794
));

795
796
797
798
799
800
801
/**
 * Set all LEDs to a certain RGB color.
 *
 * :param uint8_t r: Value for the red color channel.
 * :param uint8_t g: Value for the green color channel.
 * :param uint8_t b: Value for the blue color channel.
 */
802
803
804
API(API_LEDS_CLEAR_ALL, void epic_leds_clear_all(
	uint8_t r, uint8_t g, uint8_t b
));
805

chris007's avatar
chris007 committed
806
807
808
/**
 * BME680
 * ======
809
810
 *
 * .. versionadded:: 1.4
chris007's avatar
chris007 committed
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
 */

/**
 * BME680 Sensor Data
 */
struct bme680_sensor_data {
	/** Temperature in degree celsius */
	float temperature;
	/** Humidity in % relative humidity */
	float humidity;
	/** Pressure in hPa */
	float pressure;
	/** Gas resistance in Ohms */
	float gas_resistance;
};

/**
 * Initialize the BM680 sensor.
 *
830
831
 * .. versionadded:: 1.4
 *
chris007's avatar
chris007 committed
832
833
834
835
836
837
838
839
840
841
842
843
844
 * :return: 0 on success or ``-Exxx`` on error.  The following
 *     errors might occur:
 *
 *     - ``-EFAULT``:  On NULL-pointer.
 *     - ``-EINVAL``:  Invalid configuration.
 *     - ``-EIO``:  Communication with the device failed.
 *     - ``-ENODEV``:  Device was not found.
 */
API(API_BME680_INIT, int epic_bme680_init());

/**
 * De-Initialize the BM680 sensor.
 *
845
846
 * .. versionadded:: 1.4
 *
chris007's avatar
chris007 committed
847
848
849
850
851
852
853
854
855
856
857
858
859
 * :return: 0 on success or ``-Exxx`` on error.  The following
 *     errors might occur:
 *
 *     - ``-EFAULT``:  On NULL-pointer.
 *     - ``-EINVAL``:  Invalid configuration.
 *     - ``-EIO``:  Communication with the device failed.
 *     - ``-ENODEV``:  Device was not found.
 */
API(API_BME680_DEINIT, int epic_bme680_deinit());

/**
 * Get the current BME680 data.
 *
860
861
 * .. versionadded:: 1.4
 *
chris007's avatar
chris007 committed
862
863
864
865
866
867
868
869
870
 * :param data: Where to store the environmental data.
 * :return: 0 on success or ``-Exxx`` on error.  The following
 *     errors might occur:
 *
 *     - ``-EFAULT``:  On NULL-pointer.
 *     - ``-EINVAL``:  Sensor not initialized.
 *     - ``-EIO``:  Communication with the device failed.
 *     - ``-ENODEV``:  Device was not found.
 */
871
872
873
API(API_BME680_GET_DATA, int epic_bme680_read_sensors(
	struct bme680_sensor_data *data
));
chris007's avatar
chris007 committed
874

875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
/**
 * MAX86150
 * ======
 */

/**
 * Configuration for a MAX86150 sensor.
 *
 * This struct is used when enabling a sensor using
 * :c:func:`epic_max86150_enable_sensor`.
 */
struct max86150_sensor_config {
    /**
     * Number of samples Epicardium should keep for this sensor.  Do not set
     * this number too high as the sample buffer will eat RAM.
     */
    size_t sample_buffer_len;
    /**
     * Sample rate for PPG from the sensor in Hz.  Maximum data rate is limited
     * to 200 Hz for all sensors though some might be limited at a lower
     * rate.
     *
     * Possible values are 10, 20, 50, 84, 100, 200.
     */
    uint16_t ppg_sample_rate;
};

/**
 * MAX86150 Sensor Data
 */
struct max86150_sensor_data {
	/** Red LED data */
	uint32_t red;
	/** IR LED data */
	uint32_t ir;
	/** ECG data */
	int32_t ecg;
};

/**
 * Enable a MAX86150 PPG and ECG sensor.
 * 
 * Calling this function will instruct the MAX86150 to collect a 
 * data from the sensor.  You can then retrieve the samples using 
 * :c:func:`epic_stream_read`.
 *
 * :param max86150_sensor_config* config: Configuration for this sensor.
 * :param size_t config_size: Size of ``config``.
 * :returns: A sensor descriptor which can be used with
 *    :c:func:`epic_stream_read` or a negative error value:
 *
 *    - ``-ENOMEM``:  The MAX86150 driver failed to create a stream queue.
 *    - ``-ENODEV``:  The MAX86150 driver failed due to physical connectivity problem
 *      (broken wire, unpowered, etc).
 *    - ``-EINVAL``:  config->ppg_sample_rate is not one of 10, 20, 50, 84, 100, 200
 *      or config_size is not size of config.
 *
 * .. versionadded:: 1.13
 */
API(API_MAX86150_ENABLE, int epic_max86150_enable_sensor(struct max86150_sensor_config *config, size_t config_size));

/**
 * Disable the MAX86150 sensor.
 *
 * :returns: 0 in case of success or forward negative error value from stream_deregister.
 *
 * .. versionadded:: 1.13
 */
API(API_MAX86150_DISABLE, int epic_max86150_disable_sensor());

/**
 * **Interrupt Service Routine** for :c:data:`EPIC_INT_MAX86150`
 *
 * :c:func:`epic_isr_max86150` is called whenever the MAX86150
 * PPG sensor has new data available.
 */
API_ISR(EPIC_INT_MAX86150, epic_isr_max86150);

953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
/**
 * Personal State
 * ==============
 * Card10 can display your personal state.
 *
 * If a personal state is set the top-left LED on the bottom side of the
 * harmonics board is directly controlled by epicardium and it can't be
 * controlled by pycardium.
 *
 * To re-enable pycardium control the personal state has to be cleared. To do
 * that simply set it to ``STATE_NONE``.
 *
 * The personal state can be set to be persistent which means it won't get reset
 * on pycardium application change/restart.
 */

/** Possible personal states. */
enum personal_state {
    /** ``0``, No personal state - LED is under regular application control. */
    STATE_NONE = 0,
    /** ``1``, "no contact, please!" - I am overloaded. Please leave me be - red led, continuously on. */
    STATE_NO_CONTACT = 1,
    /** ``2``, "chaos" - Adventure time - blue led, short blink, long blink. */
    STATE_CHAOS = 2,
977
    /** ``3``, "communication" - want to learn something or have a nice conversation - yellow led, long blinks. */
978
    STATE_COMMUNICATION = 3,
979
    /** ``4``, "camp" - I am focussed on self-, camp-, or community maintenance - green led, fade on and off. */
980
    STATE_CAMP = 4,
genofire's avatar
genofire committed
981
982
    /** STATE_MAX gives latest value and count of possible STATEs**/
    STATE_MAX = 5,
983
984
985
986
987
988
989
990
991
992
993
};

/**
 * Set the users personal state.
 *
 * Using :c:func:`epic_personal_state_set` an application can set the users personal state.
 *
 * :param uint8_t state: The users personal state. Must be one of :c:type:`personal_state`.
 * :param bool persistent: Indicates whether the configured personal state will remain set and active on pycardium application restart/change.
 * :returns: ``0`` on success, ``-EINVAL`` if an invalid state was requested.
 */
994
995
996
API(API_PERSONAL_STATE_SET, int epic_personal_state_set(
	uint8_t state, bool persistent
));
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015

/**
 * Get the users personal state.
 *
 * Using :c:func:`epic_personal_state_get` an application can get the currently set personal state of the user.
 *
 * :returns: A value with exactly one value of :c:type:`personal_state` set.
 */
API(API_PERSONAL_STATE_GET, int epic_personal_state_get());

/**
 * Get whether the users personal state is persistent.
 *
 * Using :c:func:`epic_personal_state_is_persistent` an app can find out whether the users personal state is persistent or transient.
 *
 * :returns: ``1`` if the state is persistent, ``0`` otherwise.
 */
API(API_PERSONAL_STATE_IS_PERSISTENT, int epic_personal_state_is_persistent());

1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
/**
 * 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
Rahix's avatar
Rahix committed
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
 * sensor samples into the provided buffer as possible and return the number of
 * samples written.  If no samples are available, ``epic_stream_read()`` will
 * return ``0`` immediately.
 *
 * ``epic_stream_read()`` expects the provided buffer to have a size which is a
 * multiple of the sample size for the given stream.  For the sample-format and
 * size, please consult the sensors documentation.
 *
 * Before reading the internal sensor sample queue, ``epic_stream_read()`` will
 * call a sensor specific *poll* function to allow the sensor driver to fetch
 * new samples from its hardware.  This should, however, never take a long
 * amount of time.
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
 *
 * :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.
Rahix's avatar
Rahix committed
1049
 *    - ``-EINVAL``:  ``count`` is not a multiple of the sensor's sample size.
1050
 *    - ``-EBUSY``: The descriptor table lock could not be acquired.
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
 *
 * **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));

1078
1079
1080
1081
1082
1083
/**
 * BHI160 Sensor Fusion
 * ====================
 * card10 has a BHI160 onboard which is used as an IMU.  BHI160 exposes a few
 * different sensors which can be accessed using Epicardium API.
 *
1084
1085
 * .. versionadded:: 1.4
 *
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
 * **Example**:
 *
 * .. code-block:: cpp
 *
 *    #include "epicardium.h"
 *
 *    // Configure a sensor & enable it
 *    struct bhi160_sensor_config cfg = {0};
 *    cfg.sample_buffer_len = 40;
 *    cfg.sample_rate = 4;   // Hz
 *    cfg.dynamic_range = 2; // g
 *
 *    int sd = epic_bhi160_enable_sensor(BHI160_ACCELEROMETER, &cfg);
 *
 *    // Read sensor data
 *    while (1) {
 *            struct bhi160_data_vector buf[10];
 *
 *            int n = epic_stream_read(sd, buf, sizeof(buf));
 *
 *            for (int i = 0; i < n; i++) {
 *                    printf("X: %6d Y: %6d Z: %6d\n",
 *                           buf[i].x,
 *                           buf[i].y,
 *                           buf[i].z);
 *            }
 *    }
 *
 *    // Disable the sensor
 *    epic_bhi160_disable_sensor(BHI160_ACCELEROMETER);
 */

/**
 * BHI160 Sensor Types
 * -------------------
 */

/**
 * BHI160 virtual sensor type.
 */
enum bhi160_sensor_type {
	/**
	 * Accelerometer
	 *
	 * - Data type: :c:type:`bhi160_data_vector`
	 * - Dynamic range: g's (1x Earth Gravity, ~9.81m*s^-2)
	 */
	BHI160_ACCELEROMETER               = 0,
1134
1135
1136
1137
1138
1139
	/**
	 * Magnetometer
	 *
	 * - Data type: :c:type:`bhi160_data_vector`
	 * - Dynamic range: -1000 to 1000 microtesla
	 */
1140
	BHI160_MAGNETOMETER                = 1,
koalo's avatar
koalo committed
1141
	/** Orientation */
1142
	BHI160_ORIENTATION                 = 2,
koalo's avatar
koalo committed
1143
	/** Gyroscope */
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
	BHI160_GYROSCOPE                   = 3,
	/** Gravity (**Unimplemented**) */
	BHI160_GRAVITY                     = 4,
	/** Linear acceleration (**Unimplemented**) */
	BHI160_LINEAR_ACCELERATION         = 5,
	/** Rotation vector (**Unimplemented**) */
	BHI160_ROTATION_VECTOR             = 6,
	/** Uncalibrated magnetometer (**Unimplemented**) */
	BHI160_UNCALIBRATED_MAGNETOMETER   = 7,
	/** Game rotation vector (whatever that is supposed to be) */
	BHI160_GAME_ROTATION_VECTOR        = 8,
	/** Uncalibrated gyroscrope (**Unimplemented**) */
	BHI160_UNCALIBRATED_GYROSCOPE      = 9,
	/** Geomagnetic rotation vector (**Unimplemented**) */
	BHI160_GEOMAGNETIC_ROTATION_VECTOR = 10,
};

1161
1162
1163
1164
enum bhi160_data_type {
	BHI160_DATA_TYPE_VECTOR
};

1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
/**
 * BHI160 Sensor Data Types
 * ------------------------
 */

/**
 * Vector Data.  The scaling of these values is dependent on the chosen dynamic
 * range.  See the individual sensor's documentation for details.
 */
struct bhi160_data_vector {
1175
1176
	enum bhi160_data_type data_type;

1177
1178
1179
1180
1181
1182
	/** X */
	int16_t x;
	/** Y */
	int16_t y;
	/** Z */
	int16_t z;
koalo's avatar
koalo committed
1183
1184
	/** Status */
	uint8_t status;
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
};

/**
 * BHI160 API
 * ----------
 */

/**
 * Configuration for a BHI160 sensor.
 *
 * This struct is used when enabling a sensor using
 * :c:func:`epic_bhi160_enable_sensor`.
 */
struct bhi160_sensor_config {
	/**
	 * Number of samples Epicardium should keep for this sensor.  Do not set
	 * this number too high as the sample buffer will eat RAM.
	 */
	size_t sample_buffer_len;
	/**
	 * Sample rate for the sensor in Hz.  Maximum data rate is limited
	 * to 200 Hz for all sensors though some might be limited at a lower
	 * rate.
	 */
	uint16_t sample_rate;
	/**
	 * Dynamic range.  Interpretation of this value depends on
	 * the sensor type.  Please refer to the specific sensor in
	 * :c:type:`bhi160_sensor_type` for details.
	 */
	uint16_t dynamic_range;
	/** Always zero. Reserved for future parameters. */
	uint8_t _padding[8];
};

/**
1221
 * Enable a BHI160 virtual sensor.  Calling this function will instruct the
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
 * BHI160 to collect data for this specific virtual sensor.  You can then
 * retrieve the samples using :c:func:`epic_stream_read`.
 *
 * :param bhi160_sensor_type sensor_type: Which sensor to enable.
 * :param bhi160_sensor_config* config: Configuration for this sensor.
 * :returns: A sensor descriptor which can be used with
 *    :c:func:`epic_stream_read` or a negative error value:
 *
 *    - ``-EBUSY``:  The BHI160 driver is currently busy with other tasks and
 *      could not be acquired for enabling a sensor.
1232
1233
 *
 * .. versionadded:: 1.4
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
 */
API(API_BHI160_ENABLE, int epic_bhi160_enable_sensor(
	enum bhi160_sensor_type sensor_type,
	struct bhi160_sensor_config *config
));

/**
 * Disable a BHI160 sensor.
 *
 * :param bhi160_sensor_type sensor_type: Which sensor to disable.
1244
1245
 *
 * .. versionadded:: 1.4
1246
1247
1248
1249
1250
 */
API(API_BHI160_DISABLE, int epic_bhi160_disable_sensor(
	enum bhi160_sensor_type sensor_type
));

1251
1252
/**
 * Disable all BHI160 sensors.
1253
1254
 *
 * .. versionadded:: 1.4
1255
1256
1257
 */
API(API_BHI160_DISABLE_ALL, void epic_bhi160_disable_all_sensors());

1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
/**
 * BHI160 Interrupt Handlers
 * -------------------------
 */

/**
 * **Interrupt Service Routine** for :c:data:`EPIC_INT_BHI160_ACCELEROMETER`
 *
 * :c:func:`epic_isr_bhi160_accelerometer` is called whenever the BHI160
 * accelerometer has new data available.
 */
API_ISR(EPIC_INT_BHI160_ACCELEROMETER, epic_isr_bhi160_accelerometer);

1271
1272
1273
1274
1275
1276
1277
1278
/**
 * **Interrupt Service Routine** for :c:data:`EPIC_INT_BHI160_MAGNETOMETER`
 *
 * :c:func:`epic_isr_bhi160_magnetometer` is called whenever the BHI160
 * magnetometer has new data available.
 */
API_ISR(EPIC_INT_BHI160_MAGNETOMETER, epic_isr_bhi160_magnetometer);

1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
/**
 * **Interrupt Service Routine** for :c:data:`EPIC_INT_BHI160_ORIENTATION`
 *
 * :c:func:`epic_isr_bhi160_orientation` is called whenever the BHI160
 * orientation sensor has new data available.
 */
API_ISR(EPIC_INT_BHI160_ORIENTATION, epic_isr_bhi160_orientation);

/**
 * **Interrupt Service Routine** for :c:data:`EPIC_INT_BHI160_GYROSCOPE`
 *
 * :c:func:`epic_isr_bhi160_orientation` is called whenever the BHI160
 * gyroscrope has new data available.
 */
API_ISR(EPIC_INT_BHI160_GYROSCOPE, epic_isr_bhi160_gyroscope);


Rahix's avatar
Rahix committed
1296
/**
Rahix's avatar
Rahix committed
1297
1298
 * Vibration Motor
 * ===============
Rahix's avatar
Rahix committed
1299
1300
1301
1302
1303
1304
1305
 */

/**
 * Turn vibration motor on or off
 *
 * :param status: 1 to turn on, 0 to turn off.
 */
Gerd's avatar
Gerd committed
1306
1307
API(API_VIBRA_SET, void epic_vibra_set(int status));

1308
1309
1310
1311
1312
1313
1314
/**
 * Turn vibration motor on for a given time
 *
 * :param millis: number of milliseconds to run the vibration motor.
 */
API(API_VIBRA_VIBRATE, void epic_vibra_vibrate(int millis));

Gerd's avatar
Gerd committed
1315
1316
1317
/**
 * Display
 * =======
1318
1319
 * The card10 has an LCD screen that can be accessed from user code.
 *
Rahix's avatar
Rahix committed
1320
1321
1322
1323
1324
1325
1326
1327
 * There are two ways to access the display:
 *
 *  - *immediate mode*, where you ask Epicardium to draw shapes and text for
 *    you.  Most functions in this subsection are related to *immediate mode*.
 *  - *framebuffer mode*, where you provide Epicardium with a memory range where
 *    you already drew graphics whichever way you wanted and Epicardium will
 *    copy them to the display.  To use *framebuffer mode*, use the
 *    :c:func:`epic_disp_framebuffer` function.
Gerd's avatar
Gerd committed
1328
1329
 */

Rahix's avatar
Rahix committed
1330
/** Line-Style */
Rahix's avatar
Rahix committed
1331
enum disp_linestyle {
Rahix's avatar
Rahix committed
1332
  /** */
Gerd's avatar
Gerd committed
1333
  LINESTYLE_FULL = 0,
Rahix's avatar
Rahix committed
1334
  /** */
Gerd's avatar
Gerd committed
1335
1336
1337
  LINESTYLE_DOTTED = 1
};

Rahix's avatar
Rahix committed
1338
/** Fill-Style */
Rahix's avatar
Rahix committed
1339
enum disp_fillstyle {
Rahix's avatar
Rahix committed
1340
  /** */
Gerd's avatar
Gerd committed
1341
  FILLSTYLE_EMPTY = 0,
Rahix's avatar
Rahix committed
1342
  /** */
Gerd's avatar
Gerd committed
1343
1344
1345
  FILLSTYLE_FILLED = 1
};

1346
1347
1348
1349
1350
1351
/** Width of display in pixels */
#define DISP_WIDTH 160

/** Height of display in pixels */
#define DISP_HEIGHT 80

Rahix's avatar
Rahix committed
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
/**
 * Framebuffer
 *
 * The frambuffer stores pixels as RGB565, but byte swapped.  That is, for every ``(x, y)`` coordinate, there are two ``uint8_t``\ s storing 16 bits of pixel data.
 *
 * .. todo::
 *
 *    Document (x, y) in relation to chirality.
 *
 * **Example**: Fill framebuffer with red
 *
 * .. code-block:: cpp
 *
 * 	union disp_framebuffer fb;
 * 	uint16_t red = 0b1111100000000000;
 * 	for (int y = 0; y < DISP_HEIGHT; y++) {
 * 		for (int x = 0; x < DISP_WIDTH; x++) {
 * 			fb.fb[y][x][0] = red >> 8;
 * 			fb.fb[y][x][1] = red & 0xFF;
 * 		}
 * 	}
 * 	epic_disp_framebuffer(&fb);
 */
1375
union disp_framebuffer {
Rahix's avatar
Rahix committed
1376
  /** Coordinate based access (as shown in the example above). */
1377
  uint8_t fb[DISP_HEIGHT][DISP_WIDTH][2];
Rahix's avatar
Rahix committed
1378
  /** Raw byte-indexed access. */
1379
1380
1381
  uint8_t raw[DISP_HEIGHT*DISP_WIDTH*2];
};

Gerd's avatar
Gerd committed
1382
1383
1384
1385
/**
 * Locks the display.
 *
 * :return: ``0`` on success or a negative value in case of an error:
Rahix's avatar
Rahix committed
1386
1387
 *
 *    - ``-EBUSY``: Display was already locked from another task.
Gerd's avatar
Gerd committed
1388
1389
1390
1391
1392
1393
1394
 */
API(API_DISP_OPEN, int epic_disp_open());

/**
 * Unlocks the display again.
 *
 * :return: ``0`` on success or a negative value in case of an error:
Rahix's avatar
Rahix committed
1395
1396
 *
 *    - ``-EBUSY``: Display was already locked from another task.
Gerd's avatar
Gerd committed
1397
1398
1399
1400
1401
1402
 */
API(API_DISP_CLOSE, int epic_disp_close());

/**
 * Causes the changes that have been written to the framebuffer
 * to be shown on the display
1403
1404
1405
 * :return: ``0`` on success or a negative value in case of an error:
 *
 *    - ``-EBUSY``: Display was already locked from another task.
Gerd's avatar
Gerd committed
1406
1407
1408
1409
1410
1411
 */
API(API_DISP_UPDATE, int epic_disp_update());

/**
 * Prints a string into the display framebuffer
 *
1412
1413
 * :param posx: x position to print to.
 * :param posy: y position to print to.
Gerd's avatar
Gerd committed
1414
1415
1416
1417
 * :param pString: string to print
 * :param fg: foreground color in rgb565
 * :param bg: background color in rgb565
 * :return: ``0`` on success or a negative value in case of an error:
Rahix's avatar
Rahix committed
1418
1419
 *
 *    - ``-EBUSY``: Display was already locked from another task.
Gerd's avatar
Gerd committed
1420
1421
1422
 */
API(API_DISP_PRINT,
    int epic_disp_print(
1423
1424
	    int16_t posx,
	    int16_t posy,
Gerd's avatar
Gerd committed
1425
1426
1427
1428
1429
	    const char *pString,
	    uint16_t fg,
	    uint16_t bg)
    );

1430
1431
1432
1433
/*
 * Font Selection
 */
enum disp_font_name {
1434
	DISP_FONT8  = 0,
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
	DISP_FONT12 = 1,
	DISP_FONT16 = 2,
	DISP_FONT20 = 3,
	DISP_FONT24 = 4,
};

/**
 * Prints a string into the display framebuffer with font type selectable
 *
 * :param fontName: number of font, use FontName enum
1445
1446
 * :param posx: x position to print to.
 * :param posy: y position to print to.
1447
1448
 * :param pString: string to print
 * :param fg: foreground color in rgb565
1449
 * :param bg: background color in rgb565, no background is drawn if bg==fg
1450
1451
1452
1453
 * :return: ``0`` on success or a negative value in case of an error:
 *
 *    - ``-EBUSY``: Display was already locked from another task.
 */
1454
1455
API(API_DISP_PRINT_ADV, int epic_disp_print_adv(
	uint8_t font,
1456
1457
	int16_t posx,
	int16_t posy,
1458
1459
1460
1461
	const char *pString,
	uint16_t fg,
	uint16_t bg
));
1462

Gerd's avatar
Gerd committed
1463
1464
1465
1466
1467
/**
 * Fills the whole screen with one color
 *
 * :param color: fill color in rgb565
 * :return: ``0`` on success or a negative value in case of an error:
Rahix's avatar
Rahix committed
1468
1469
 *
 *    - ``-EBUSY``: Display was already locked from another task.
Gerd's avatar
Gerd committed
1470
1471
1472
 */
API(API_DISP_CLEAR, int epic_disp_clear(uint16_t color));

1473
1474
1475
/**
 * Draws a pixel on the display
 *
1476
1477
 * :param x: x position;
 * :param y: y position;
1478
1479
1480
1481
1482
 * :param color: pixel color in rgb565
 * :return: ``0`` on success or a negative value in case of an error:
 *
 *    - ``-EBUSY``: Display was already locked from another task.
 */
1483
API(API_DISP_PIXEL, int epic_disp_pixel(
1484
	int16_t x, int16_t y, uint16_t color
1485
));
1486

Gerd's avatar
Gerd committed
1487
1488
1489
/**
 * Draws a line on the display
 *
1490
1491
1492
1493
 * :param xstart: x starting position
 * :param ystart: y starting position
 * :param xend: x ending position
 * :param yend: y ending position
Gerd's avatar
Gerd committed
1494
1495
1496
1497
 * :param color: line color in rgb565
 * :param linestyle: 0 for solid, 1 for dottet (almost no visual difference)
 * :param pixelsize: thickness of the line; 1 <= pixelsize <= 8
 * :return: ``0`` on success or a negative value in case of an error:
Rahix's avatar
Rahix committed
1498
1499
 *
 *    - ``-EBUSY``: Display was already locked from another task.
Gerd's avatar
Gerd committed
1500
 */
1501
API(API_DISP_LINE, int epic_disp_line(
1502
1503
1504
1505
	int16_t xstart,
	int16_t ystart,
	int16_t xend,
	int16_t yend,
1506
1507
1508
1509
	uint16_t color,
	enum disp_linestyle linestyle,
	uint16_t pixelsize
));
Gerd's avatar
Gerd committed
1510
1511
1512
1513

/**
 * Draws a rectangle on the display
 *
1514
1515
1516
1517
 * :param xstart: x coordinate of top left corner
 * :param ystart: y coordinate of top left corner
 * :param xend: x coordinate of bottom right corner
 * :param yend: y coordinate of bottom right corner
Gerd's avatar
Gerd committed
1518
1519
1520
1521
 * :param color: line color in rgb565
 * :param fillstyle: 0 for empty, 1 for filled
 * :param pixelsize: thickness of the rectangle outline; 1 <= pixelsize <= 8
 * :return: ``0`` on success or a negative value in case of an error:
Rahix's avatar
Rahix committed
1522
1523
 *
 *    - ``-EBUSY``: Display was already locked from another task.
Gerd's avatar
Gerd committed
1524
 */
1525
API(API_DISP_RECT, int epic_disp_rect(
1526
1527
1528
1529
	int16_t xstart,
	int16_t ystart,
	int16_t xend,
	int16_t yend,
1530
1531
1532
1533
	uint16_t color,
	enum disp_fillstyle fillstyle,
	uint16_t pixelsize
));
Gerd's avatar
Gerd committed
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544

/**
 * Draws a circle on the display
 *
 * :param x: x coordinate of the center; 0 <= x <= 160
 * :param y: y coordinate of the center; 0 <= y <= 80
 * :param rad: radius of the circle
 * :param color: fill and outline color of the circle (rgb565)
 * :param fillstyle: 0 for empty, 1 for filled
 * :param pixelsize: thickness of the circle outline; 1 <= pixelsize <= 8
 * :return: ``0`` on success or a negative value in case of an error:
Rahix's avatar
Rahix committed
1545
1546
 *
 *    - ``-EBUSY``: Display was already locked from another task.
Gerd's avatar
Gerd committed
1547
 */
1548
API(API_DISP_CIRC, int epic_disp_circ(
1549
1550
	int16_t x,
	int16_t y,
1551
1552
1553
1554
1555
	uint16_t rad,
	uint16_t color,
	enum disp_fillstyle fillstyle,
	uint16_t pixelsize
));
1556

1557
1558
1559
1560
1561
1562
1563
1564
1565
/**
 * Immediately send the contents of a framebuffer to the display. This overrides
 * anything drawn by immediate mode graphics and displayed using ``epic_disp_update``.
 *
 * :param fb: framebuffer to display
 * :return: ``0`` on success or negative value in case of an error:
 *
 *    - ``-EBUSY``: Display was already locked from another task.
 */
1566
1567
1568
API(API_DISP_FRAMEBUFFER, int epic_disp_framebuffer(
	union disp_framebuffer *fb
));
1569
1570


1571
/**
1572
 * Set the backlight brightness.
1573
 *
1574
 * Note that this function does not require acquiring the display.
1575
 *
1576
1577
 * :param brightness: brightness from 0 - 100
 * :return: ``0`` on success or negative value in case of an error
1578
1579
1580
1581
 */
API(API_DISP_BACKLIGHT, int epic_disp_backlight(uint16_t brightness));


1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
/**
 * Start continuous readout of the light sensor. Will read light level
 * at preconfigured interval and make it available via `epic_light_sensor_get()`.
 *
 * If the continuous readout was already running, this function will silently pass.
 *
 *
 * :return: `0` if the start was successful or a negative error value
 *      if an error occured. Possible errors:
 *
 *      - ``-EBUSY``: The timer could not be scheduled.
 */
API(API_LIGHT_SENSOR_RUN, int epic_light_sensor_run());

/**
 * Get the last light level measured by the continuous readout.
 *
 * :param uint16_t* value: where the last light level should be written.
 * :return: `0` if the readout was successful or a negative error
 *      value. Possible errors:
 *
 *      - ``-ENODATA``: Continuous readout not currently running.
 */
API(API_LIGHT_SENSOR_GET, int epic_light_sensor_get(uint16_t* value));


/**
 * Stop continuous readout of the light sensor.
 *
 * If the continuous readout wasn't running, this function will silently pass.
 *
 * :return: `0` if the stop was sucessful or a negative error value
 *      if an error occured. Possible errors:
 *
 *      - ``-EBUSY``: The timer stop could not be scheduled.
 */
API(API_LIGHT_SENSOR_STOP, int epic_light_sensor_stop());

1620
/**
Rahix's avatar
Rahix committed
1621
1622
1623
1624
1625
 * Get the light level directly.
 *
 * Each call has an intrinsic delay of about 240us, I recommend another
 * 100-300us delay  between calls. Whether or not the IR LED is fast enough is
 * another issue.
1626
1627
 *
 * :return: Light level
Rahix's avatar
Rahix committed
1628
1629
 *
 * .. versionadded:: 1.8
1630
1631
1632
1633
 */
API(API_LIGHT_SENSOR_READ, uint16_t epic_light_sensor_read(void));


1634
1635
1636
/**
 * File
 * ====
1637
1638
 * Except for :c:func:`epic_file_open`, which models C stdio's ``fopen``
 * function, ``close``, ``read`` and ``write`` model `close(2)`_, `read(2)`_ and
Rahix's avatar
Rahix committed
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
 * `write(2)`_.  All file-related functions return >= ``0`` on success and
 * ``-Exyz`` on failure, with error codes from errno.h (``EIO``, ``EINVAL``
 * etc.)
 *
 * .. _close(2): http://man7.org/linux/man-pages/man2/close.2.html
 * .. _read(2): http://man7.org/linux/man-pages/man2/read.2.html
 * .. _write(2): http://man7.org/linux/man-pages/man2/write.2.html
 */

/** */
1649
1650
1651
API(API_FILE_OPEN, int epic_file_open(
	const char* filename, const char* modeString
));
Rahix's avatar
Rahix committed
1652

1653
/** */
Rahix's avatar
Rahix committed
1654
API(API_FILE_CLOSE, int epic_file_close(int fd));
Rahix's avatar
Rahix committed
1655
1656

/** */
Rahix's avatar
Rahix committed
1657
API(API_FILE_READ, int epic_file_read(int fd, void* buf, size_t nbytes));
Rahix's avatar
Rahix committed
1658

1659
/**
1660
 * Write bytes to a file.
1661
 *
1662
1663
1664
 * :param int fd: Descriptor returned by :c:func:`epic_file_open`.
 * :param void* buf: Data to write.
 * :param size_t nbytes: Number of bytes to write.
1665
1666
1667
1668
 *
 * :return: ``< 0`` on error, ``nbytes`` on success. (Partial writes don't occur on success!)
 *
*/
1669
1670
1671
API(API_FILE_WRITE, int epic_file_write(
	int fd, const void* buf, size_t nbytes
));
Rahix's avatar
Rahix committed
1672
1673

/** */
Rahix's avatar
Rahix committed
1674
API(API_FILE_FLUSH, int epic_file_flush(int fd));
1675

1676
1677
1678
1679
1680
1681
/** */
API(API_FILE_SEEK, int epic_file_seek(int fd, long offset, int whence));

/** */
API(API_FILE_TELL, int epic_file_tell(int fd));

Rahix's avatar
Rahix committed
1682
/** */
1683
enum epic_stat_type {
Rahix's avatar
Rahix committed
1684
1685
1686
1687
1688
1689
	/**
	 * Basically ``ENOENT``. Although :c:func:`epic_file_stat` returns an
	 * error for 'none', the type will still be set to none additionally.
	 *
	 * This is also used internally to track open FS objects, where we use
	 * ``EPICSTAT_NONE`` to mark free objects.
1690
1691
1692
	 */
	EPICSTAT_NONE,
	/** normal file */
Rahix's avatar
Rahix committed
1693
	EPICSTAT_FILE,
1694
	/** directory */
Rahix's avatar
Rahix committed
1695
	EPICSTAT_DIR,
1696
1697
};

1698
1699
1700
1701
1702
/**
 * Maximum length of a path string (=255).
 */
#define EPICSTAT_MAX_PATH        255
/* conveniently the same as FF_MAX_LFN */
1703

Rahix's avatar
Rahix committed
1704
/** */
1705
1706
struct epic_stat {
	/** Entity Type: file, directory or none */
Rahix's avatar
Rahix committed
1707
	enum epic_stat_type type;
Rahix's avatar
Rahix committed
1708
1709
1710
1711
1712
1713
1714
1715
1716