epicardium.h 59 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
#define API_CONFIG_SET_STRING      0x133
149
150
151
152
153
154
155
156
157
158
159
/* 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`.
160
161
162
163
164
165
166
 *
 * .. 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.
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
 */

/**
 * 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:
 */
186

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

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

Rahix's avatar
Rahix committed
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
240
/*
 * "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));
241

Rahix's avatar
Rahix committed
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
/**
 * 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));
266

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

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

Stefan Haun's avatar
Stefan Haun committed
277

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

Stefan Haun's avatar
Stefan Haun committed
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
308
/**
 * 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
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
/**
 * 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.
 */
324
API(API_UART_WRITE_STR, void epic_uart_write_str(
325
	const char *str, size_t length
326
));
Rahix's avatar
Rahix committed
327

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

337
338
339
340
341
342
343
344
345
346
347
348
349
/**
 * 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));

350
/**
351
 * **Interrupt Service Routine** for :c:data:`EPIC_INT_UART_RX`
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
 *
 * 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
372
 *
373
374
375
376
 *            while (1) {
 *                    __WFI();
 *            }
 *    }
Rahix's avatar
Rahix committed
377
 */
378
API_ISR(EPIC_INT_UART_RX, epic_isr_uart_rx);
Rahix's avatar
Rahix committed
379

380
/**
381
 * **Interrupt Service Routine** for :c:data:`EPIC_INT_CTRL_C`
382
383
384
385
386
387
388
389
390
391
392
393
394
 *
 * 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
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
456
/**
 * 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));

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

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

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

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

/**
 * 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.
 */
509
510
511
API(API_GPIO_SET_PIN_MODE, int epic_gpio_set_pin_mode(
	uint8_t pin, uint8_t mode
));
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
583

/**
 * 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.
 */
584
API(API_GPIO_READ_PIN, int epic_gpio_read_pin(uint8_t pin));
585

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

/**
fleur's avatar
fleur committed
592
 * Set one of card10's RGB LEDs to a certain color in RGB format.
Rahix's avatar
Rahix committed
593
 *
fleur's avatar
fleur committed
594
595
596
 * 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.
597
 *
fleur's avatar
fleur committed
598
599
600
601
602
 * :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
603
 */
604
605
API(API_LEDS_SET, void epic_leds_set(int led, uint8_t r, uint8_t g, uint8_t b));

606
607
608
609
610
611
612
613
614
615

/**
 * 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
616
617
 *
 * .. versionadded:: 1.10
618
619
620
 */
API(API_LEDS_GET, int epic_leds_get_rgb(int led, uint8_t * rgb));

fleur's avatar
fleur committed
621
622
623
624
625
626
627
628
629
630
631
632
/**
 * 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)
 */
633
634
635
API(API_LEDS_SET_HSV, void epic_leds_set_hsv(
	int led, float h, float s, float v
));
fleur's avatar
fleur committed
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657

/**
 * 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.
 */
658
659
660
API(API_LEDS_SET_ALL_HSV, void epic_leds_set_all_hsv(
	float *pattern, uint8_t len
));
fleur's avatar
fleur committed
661
662
663
664
665
666
667
668
669
670
671
672

/**
 * 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.
 */
673
674
675
API(API_LEDS_PREP, void epic_leds_prep(
	int led, uint8_t r, uint8_t g, uint8_t b
));
fleur's avatar
fleur committed
676
677
678
679
680
681
682
683
684
685
686
687

/**
 * 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)
 */
688
689
690
API(API_LEDS_PREP_HSV, void epic_leds_prep_hsv(
	int led, float h, float s, float v
));
fleur's avatar
fleur committed
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
749

/**
 * 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
750
 * :param uint8_t value:  Brightness of LED (value between 0 and 31).
fleur's avatar
fleur committed
751
752
753
 */
API(API_LEDS_SET_ROCKET, void epic_leds_set_rocket(int led, uint8_t value));

754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
/**
 * 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
769
770
 *
 * .. versionadded:: 1.10
771
772
773
 */
API(API_LEDS_GET_ROCKET, int epic_leds_get_rocket(int led));

fleur's avatar
fleur committed
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
/**
 * 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(
793
	uint8_t rgb_channel, uint8_t *gamma_table
fleur's avatar
fleur committed
794
795
));

796
797
798
799
800
801
802
/**
 * 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.
 */
803
804
805
API(API_LEDS_CLEAR_ALL, void epic_leds_clear_all(
	uint8_t r, uint8_t g, uint8_t b
));
806

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

/**
 * 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.
 *
831
832
 * .. versionadded:: 1.4
 *
chris007's avatar
chris007 committed
833
834
835
836
837
838
839
840
841
842
843
844
845
 * :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.
 *
846
847
 * .. versionadded:: 1.4
 *
chris007's avatar
chris007 committed
848
849
850
851
852
853
854
855
856
857
858
859
860
 * :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.
 *
861
862
 * .. versionadded:: 1.4
 *
chris007's avatar
chris007 committed
863
864
865
866
867
868
869
870
871
 * :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.
 */
872
873
874
API(API_BME680_GET_DATA, int epic_bme680_read_sensors(
	struct bme680_sensor_data *data
));
chris007's avatar
chris007 committed
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
/**
 * 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.
Rahix's avatar
Rahix committed
917
918
919
 *
 * Calling this function will instruct the MAX86150 to collect a
 * data from the sensor.  You can then retrieve the samples using
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
953
 * :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);

954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
/**
 * 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,
978
    /** ``3``, "communication" - want to learn something or have a nice conversation - yellow led, long blinks. */
979
    STATE_COMMUNICATION = 3,
980
    /** ``4``, "camp" - I am focussed on self-, camp-, or community maintenance - green led, fade on and off. */
981
    STATE_CAMP = 4,
genofire's avatar
genofire committed
982
983
    /** STATE_MAX gives latest value and count of possible STATEs**/
    STATE_MAX = 5,
984
985
986
987
988
989
990
991
992
993
994
};

/**
 * 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.
 */
995
996
997
API(API_PERSONAL_STATE_SET, int epic_personal_state_set(
	uint8_t state, bool persistent
));
998
999
1000

/**
 * Get the users personal state.