Skip to content
Snippets Groups Projects
epicardium.h 63 KiB
Newer Older
  • Learn to ignore specific revisions
  • #ifndef _EPICARDIUM_H
    #define _EPICARDIUM_H
    
    #include <stdint.h>
    
    #include <errno.h>
    
    #ifndef __SPHINX_DOC
    
    fleur's avatar
    fleur committed
    /* Some headers are not recognized by hawkmoth for some odd reason */
    
    #include <stddef.h>
    
    fleur's avatar
    fleur committed
    #include <stdbool.h>
    
    #else
    typedef unsigned int size_t;
    
    fleur's avatar
    fleur committed
    typedef _Bool bool;
    
    #endif /* __SPHINX_DOC */
    
    /*
     * These definitions are required for the code-generator.  Please don't touch!
     */
    
    #ifndef API
    
    rahix's avatar
    rahix committed
    #define API(id, def) def
    
    #endif
    
    #ifndef API_ISR
    #define API_ISR(id, isr) void isr(void);
    #endif
    
    /*
     * IDs for all defined API calls.  These IDs should not be needed in application
     * code on any side.
     */
    
    /* clang-format off */
    
    #define API_SYSTEM_EXIT             0x1
    #define API_SYSTEM_EXEC             0x2
    
    #define API_SYSTEM_RESET            0x3
    
    #define API_BATTERY_VOLTAGE         0x4
    
    
    #define API_INTERRUPT_ENABLE        0xA
    #define API_INTERRUPT_DISABLE       0xB
    
    #define API_INTERRUPT_IS_ENABLED    0xC
    
    
    #define API_UART_WRITE_STR         0x10
    #define API_UART_READ_CHAR         0x11
    #define API_UART_READ_STR          0x12
    
    #define API_STREAM_READ            0x1F
    
    
    #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
    
    #define API_DISP_BACKLIGHT         0x2a
    
    #define API_DISP_PRINT_ADV         0x2b
    
    Stefan Haun's avatar
    Stefan Haun committed
    /* 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
    
    
    #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
    
    #define API_FILE_OPENDIR           0x49
    #define API_FILE_READDIR           0x4a
    #define API_FILE_UNLINK            0x4b
    
    #define API_FILE_RENAME            0x4c
    #define API_FILE_MKDIR             0x4d
    
    
    #define API_RTC_GET_SECONDS        0x50
    #define API_RTC_SCHEDULE_ALARM     0x51
    
    #define API_RTC_SET_MILLISECONDS   0x52
    
    #define API_RTC_GET_MILLISECONDS   0x53
    
    #define API_RTC_GET_MONOTONIC_SECONDS      0x54
    #define API_RTC_GET_MONOTONIC_MILLISECONDS 0x55
    
    
    #define API_LEDS_SET               0x60
    
    fleur's avatar
    fleur committed
    #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
    
    #define API_LEDS_CLEAR_ALL         0x6d
    
    #define API_LEDS_GET_ROCKET        0x6e
    
    #define API_LEDS_GET               0x6f
    
    
    #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
    
    #define API_LIGHT_SENSOR_READ	   0x83
    
    
    #define API_BUTTONS_READ           0x90
    
    
    #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
    
    
    #define API_TRNG_READ              0xB0
    
    
    #define API_PERSONAL_STATE_SET     0xc0
    #define API_PERSONAL_STATE_GET     0xc1
    #define API_PERSONAL_STATE_IS_PERSISTENT 0xc2
    
    
    #define API_BME680_INIT            0xD0
    #define API_BME680_DEINIT          0xD1
    #define API_BME680_GET_DATA        0xD2
    
    
    #define API_BHI160_ENABLE          0xe0
    #define API_BHI160_DISABLE         0xe1
    
    #define API_BHI160_DISABLE_ALL     0xe2
    
    #define API_MAX30001_ENABLE        0xf0
    #define API_MAX30001_DISABLE       0xf1
    
    
    #define API_MAX86150_ENABLE        0x0100
    #define API_MAX86150_DISABLE       0x0101
    
    swym's avatar
    swym committed
    #define API_USB_SHUTDOWN           0x110
    #define API_USB_STORAGE            0x111
    #define API_USB_CDCACM             0x112
    
    
    #define API_WS2812_WRITE           0x0120
    
    
    #define API_CONFIG_GET_STRING      0x130
    #define API_CONFIG_GET_INTEGER     0x131
    #define API_CONFIG_GET_BOOLEAN     0x132
    
    #define API_CONFIG_SET_STRING      0x133
    
    
    #define API_BLE_GET_COMPARE_VALUE  0x140
    #define API_BLE_COMPARE_RESPONSE   0x141
    #define API_BLE_SET_BONDABLE       0x142
    #define API_BLE_GET_EVENT          0x143
    
    
    /* 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`.
    
     * These interrupts work similar to hardware interrupts:  You will only get a
     * single interrupt, even if multiple events occured since the ISR last ran
     * (*this behavior is new since version 1.16*).
     *
    
     * .. 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.
    
     */
    
    /**
     * 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));
    
    
    /**
     * Check if an API interrupt is enabled.
     *
     * :param int int_id: The interrupt to be checked
     * :param bool* enabled: ``true`` will be stored here if the interrupt is enabled.
     *   ``false`` otherwise.
     *
     * :return: 0 on success, ``-EINVAL`` if the interrupt is unknown.
     *
     * .. versionadded:: 1.16
     */
    API(API_INTERRUPT_IS_ENABLED, int epic_interrupt_is_enabled(api_int_id_t int_id, bool *enabled));
    
    
    /**
     * The following interrupts are defined:
     */
    
    /* clang-format off */
    
    /** Reset Handler */
    
    #define EPIC_INT_RESET                  0
    /** ``^C`` interrupt. See :c:func:`epic_isr_ctrl_c` for details.  */
    #define EPIC_INT_CTRL_C                 1
    
    /** UART Receive interrupt.  See :c:func:`epic_isr_uart_rx`. */
    
    #define EPIC_INT_UART_RX                2
    
    /** RTC Alarm interrupt.  See :c:func:`epic_isr_rtc_alarm`. */
    
    #define EPIC_INT_RTC_ALARM              3
    
    /** BHI160 Accelerometer.  See :c:func:`epic_isr_bhi160_accelerometer`. */
    
    #define EPIC_INT_BHI160_ACCELEROMETER	4
    
    /** BHI160 Orientation Sensor.  See :c:func:`epic_isr_bhi160_orientation`. */
    
    #define EPIC_INT_BHI160_ORIENTATION	5
    
    /** BHI160 Gyroscope.  See :c:func:`epic_isr_bhi160_gyroscope`. */
    
    #define EPIC_INT_BHI160_GYROSCOPE	6
    
    /** MAX30001 ECG.  See :c:func:`epic_isr_max30001_ecg`. */
    
    #define EPIC_INT_MAX30001_ECG		7
    
    /** BHI160 Magnetometer.  See :c:func:`epic_isr_bhi160_magnetometer`. */
    #define EPIC_INT_BHI160_MAGNETOMETER    8
    
    /** MAX86150 ECG and PPG sensor.  See :c:func:`epic_isr_max86150`. */
    #define EPIC_INT_MAX86150		9
    
    /** Bluetooth Low Energy event.  See :c:func:`epic_isr_ble`. */
    #define EPIC_INT_BLE                    10
    
    /* Number of defined interrupts. */
    
    #define EPIC_INT_NUM                    11
    
    /* clang-format on */
    
    
    /*
     * "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));
    
    /**
     * 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));
    
    /**
     * Reset/Restart card10
     */
    API(API_SYSTEM_RESET, void epic_system_reset(void));
    
    
    Stefan Haun's avatar
    Stefan Haun committed
     * PMIC API
    
    /**
     * Read the current battery voltage.
     */
    API(API_BATTERY_VOLTAGE, int epic_read_battery_voltage(float *result));
    
    
    Stefan Haun's avatar
    Stefan Haun committed
    /**
     * 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));
    
    
    
    /**
     * 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.
     */
    
    API(API_UART_WRITE_STR, void epic_uart_write_str(
    
    	const char *str, size_t length
    
     * Try reading a single character from any connected serial device.
    
     * If nothing is available, :c:func:`epic_uart_read_char` returns ``(-1)``.
    
     * :return:  The byte or ``(-1)`` if no byte was available.
     */
    API(API_UART_READ_CHAR, int epic_uart_read_char(void));
    
    
    /**
     * 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));
    
    
     * **Interrupt Service Routine** for :c:data:`EPIC_INT_UART_RX`
    
     *
     * 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);
    
     *            while (1) {
     *                    __WFI();
     *            }
     *    }
    
    API_ISR(EPIC_INT_UART_RX, epic_isr_uart_rx);
    
     * **Interrupt Service Routine** for :c:data:`EPIC_INT_CTRL_C`
    
     *
     * 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);
    
    
    /**
     * 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));
    
    
    /**
     * Wristband GPIO
     * ==============
     */
    
    /** GPIO pins IDs */
    enum gpio_pin {
        /** ``1``, Wristband connector 1 */
    
        /** ``2``, Wristband connector 2 */
    
        /** ``3``, Wristband connector 3 */
    
        /** ``4``, Wristband connector 4 */
    
    };
    
    /** GPIO pin modes */
    enum gpio_mode {
        /** Configure the pin as input */
    
        /** Configure the pin as output */
    
        EPIC_GPIO_MODE_ADC = (1<<2),
    
    
        /** Enable the internal pull-up resistor */
    
        /** Enable the internal pull-down resistor */
    
        EPIC_GPIO_PULL_DOWN = (1<<7),
    
    };
    
    /**
     * 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.
     */
    
    API(API_GPIO_SET_PIN_MODE, int epic_gpio_set_pin_mode(
    	uint8_t pin, uint8_t mode
    ));
    
    
    /**
     * 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.
     */
    
    API(API_GPIO_READ_PIN, int epic_gpio_read_pin(uint8_t pin));
    
    fleur's avatar
    fleur committed
     * Set one of card10's RGB LEDs to a certain color in RGB format.
    
    fleur's avatar
    fleur committed
     * 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.
    
    fleur's avatar
    fleur committed
     * :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.
    
    API(API_LEDS_SET, void epic_leds_set(int led, uint8_t r, uint8_t g, uint8_t b));
    
    
    
    /**
     * 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
     *
     * .. versionadded:: 1.10
    
     */
    API(API_LEDS_GET, int epic_leds_get_rgb(int led, uint8_t * rgb));
    
    
    fleur's avatar
    fleur committed
    /**
     * 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)
     */
    
    API(API_LEDS_SET_HSV, void epic_leds_set_hsv(
    	int led, float h, float s, float v
    ));
    
    fleur's avatar
    fleur committed
    
    /**
     * 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.
     */
    
    API(API_LEDS_SET_ALL_HSV, void epic_leds_set_all_hsv(
    	float *pattern, uint8_t len
    ));
    
    fleur's avatar
    fleur committed
    
    /**
     * 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.
     */
    
    API(API_LEDS_PREP, void epic_leds_prep(
    	int led, uint8_t r, uint8_t g, uint8_t b
    ));
    
    fleur's avatar
    fleur committed
    
    /**
     * 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)
     */
    
    API(API_LEDS_PREP_HSV, void epic_leds_prep_hsv(
    	int led, float h, float s, float v
    ));
    
    fleur's avatar
    fleur committed
    
    /**
     * 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    |
     *    +-------+--------+----------+
    
     * :param uint8_t value:  Brightness of LED (value between 0 and 31).
    
    fleur's avatar
    fleur committed
     */
    API(API_LEDS_SET_ROCKET, void epic_leds_set_rocket(int led, uint8_t value));
    
    
    /**
     * 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
     *
     * .. versionadded:: 1.10
    
     */
    API(API_LEDS_GET_ROCKET, int epic_leds_get_rocket(int led));
    
    
    fleur's avatar
    fleur committed
    /**
     * 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(
    
    	uint8_t rgb_channel, uint8_t *gamma_table
    
    /**
     * 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.
     */
    
    API(API_LEDS_CLEAR_ALL, void epic_leds_clear_all(
    	uint8_t r, uint8_t g, uint8_t b
    ));
    
    /**
     * BME680
     * ======
    
     *
     * .. versionadded:: 1.4
    
     */
    
    /**
     * 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.
     *
    
     * .. versionadded:: 1.4
     *
    
     * :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.
     *
    
     * .. versionadded:: 1.4
     *
    
     * :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.
     *
    
     * .. versionadded:: 1.4
     *
    
     * :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.
     */
    
    API(API_BME680_GET_DATA, int epic_bme680_read_sensors(
    	struct bme680_sensor_data *data
    ));
    
    /**
     * 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);
    
    
    /**
     * 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,