Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
Loading items

Target

Select target project
  • card10/firmware
  • annejan/firmware
  • astro/firmware
  • fpletz/firmware
  • gerd/firmware
  • fleur/firmware
  • swym/firmware
  • l/firmware
  • uberardy/firmware
  • wink/firmware
  • madonius/firmware
  • mot/firmware
  • filid/firmware
  • q3k/firmware
  • hauke/firmware
  • Woazboat/firmware
  • pink/firmware
  • mossmann/firmware
  • omniskop/firmware
  • zenox/firmware
  • trilader/firmware
  • Danukeru/firmware
  • shoragan/firmware
  • zlatko/firmware
  • sistason/firmware
  • datenwolf/firmware
  • bene/firmware
  • amedee/firmware
  • martinling/firmware
  • griffon/firmware
  • chris007/firmware
  • adisbladis/firmware
  • dbrgn/firmware
  • jelly/firmware
  • rnestler/firmware
  • mh/firmware
  • ln/firmware
  • penguineer/firmware
  • monkeydom/firmware
  • jens/firmware
  • jnaulty/firmware
  • jeffmakes/firmware
  • marekventur/firmware
  • pete/firmware
  • h2obrain/firmware
  • DooMMasteR/firmware
  • jackie/firmware
  • prof_r/firmware
  • Draradech/firmware
  • Kartoffel/firmware
  • hinerk/firmware
  • abbradar/firmware
  • JustTB/firmware
  • LuKaRo/firmware
  • iggy/firmware
  • ente/firmware
  • flgr/firmware
  • Lorphos/firmware
  • matejo/firmware
  • ceddral7/firmware
  • danb/firmware
  • joshi/firmware
  • melle/firmware
  • fitch/firmware
  • deurknop/firmware
  • sargon/firmware
  • markus/firmware
  • kloenk/firmware
  • lucaswerkmeister/firmware
  • derf/firmware
  • meh/firmware
  • dx/card10-firmware
  • torben/firmware
  • yuvadm/firmware
  • AndyBS/firmware
  • klausdieter1/firmware
  • katzenparadoxon/firmware
  • xiretza/firmware
  • ole/firmware
  • techy/firmware
  • thor77/firmware
  • TilCreator/firmware
  • fuchsi/firmware
  • dos/firmware
  • yrlf/firmware
  • PetePriority/firmware
  • SuperVirus/firmware
  • sur5r/firmware
  • tazz/firmware
  • Alienmaster/firmware
  • flo_h/firmware
  • baldo/firmware
  • mmu_man/firmware
  • Foaly/firmware
  • sodoku/firmware
  • Guinness/firmware
  • ssp/firmware
  • led02/firmware
  • Stormwind/firmware
  • arist/firmware
  • coon/firmware
  • mdik/firmware
  • pippin/firmware
  • royrobotiks/firmware
  • zigot83/firmware
  • mo_k/firmware
106 results
Select Git revision
Loading items
Show changes
Showing
with 1400 additions and 128 deletions
#include "epicardium.h"
#include "modules/modules.h"
#include "drivers/drivers.h"
#include "MAX77650-Arduino-Library.h"
#include "tiny-AES-c/aes.h"
#include "SHA256/mark2/sha256.h"
#include "mxc_sys.h"
#include "adc.h"
#include "mxc_delay.h"
#include "rtc.h"
#include "trng.h"
#include <string.h>
static struct AES_ctx aes_ctx;
int epic_trng_read(uint8_t *dest, size_t size)
{
if (dest == NULL)
return -EFAULT;
TRNG_Init(NULL);
TRNG_Read(MXC_TRNG, dest, size);
return 0;
}
int epic_csprng_read(uint8_t *dest, size_t size)
{
if (size >= AES_BLOCKLEN) {
int block_count = size / AES_BLOCKLEN;
AES_CTR_xcrypt_buffer(
&aes_ctx, dest, block_count * AES_BLOCKLEN
);
size -= block_count * AES_BLOCKLEN;
dest += block_count * AES_BLOCKLEN;
}
if (size > 0) {
uint8_t out[AES_BLOCKLEN];
AES_CTR_xcrypt_buffer(&aes_ctx, out, sizeof(out));
memcpy(dest, out, size);
}
return 0;
}
void rng_init(void)
{
uint8_t key[AES_BLOCKLEN];
uint8_t iv[AES_BLOCKLEN];
uint8_t hash[32];
sha256_context ctx;
int i;
sha256_init(&ctx);
/* Seed from TRNG.
* Takes about 10 ms. */
for (i = 0; i < 256; i++) {
uint8_t entropy[AES_BLOCKLEN];
epic_trng_read(entropy, AES_BLOCKLEN);
sha256_hash(&ctx, entropy, AES_BLOCKLEN);
}
// Seed from RTC
uint32_t sec, subsec;
while (RTC_GetTime(&sec, &subsec) == E_BUSY) {
mxc_delay(4000);
}
sha256_hash(&ctx, &sec, sizeof(sec));
sha256_hash(&ctx, &subsec, sizeof(subsec));
// Seed from SysTick
uint32_t systick = SysTick->VAL;
sha256_hash(&ctx, &systick, sizeof(systick));
/* Seed from ADC.
* Takes about 50 ms */
ADC_Init(0x9, NULL);
GPIO_Config(&gpio_cfg_adc0);
MAX77650_setMUX_SEL(PMIC_AMUX_BATT_U);
for (i = 0; i < 256; i++) {
uint16_t adc_data;
ADC_StartConvert(ADC_CH_0, 0, 0);
ADC_GetData(&adc_data);
sha256_hash(&ctx, &adc_data, sizeof(adc_data));
}
MAX77650_setMUX_SEL(PMIC_AMUX_DISABLED);
sha256_done(&ctx, hash);
memcpy(key, hash, AES_BLOCKLEN);
memcpy(iv, hash + AES_BLOCKLEN, AES_BLOCKLEN);
AES_init_ctx_iv(&aes_ctx, key, iv);
}
#include "epicardium.h" #include "epicardium.h"
#include "modules/log.h" #include "os/core.h"
#include "api/interrupt-sender.h" #include "modules/modules.h"
#include "user_core/interrupts.h"
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "task.h" #include "task.h"
...@@ -84,19 +85,23 @@ void epic_rtc_set_milliseconds(uint64_t milliseconds) ...@@ -84,19 +85,23 @@ void epic_rtc_set_milliseconds(uint64_t milliseconds)
monotonic_offset += diff; monotonic_offset += diff;
} }
/* We need to use interrupt_trigger_unsafe() here */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
void RTC_IRQHandler(void) void RTC_IRQHandler(void)
{ {
int flags = RTC_GetFlags(); int flags = RTC_GetFlags();
if (flags & MXC_F_RTC_CTRL_ALDF) { if (flags & MXC_F_RTC_CTRL_ALDF) {
RTC_ClearFlags(MXC_F_RTC_CTRL_ALDF); RTC_ClearFlags(MXC_F_RTC_CTRL_ALDF);
api_interrupt_trigger(EPIC_INT_RTC_ALARM); interrupt_trigger_unsafe(EPIC_INT_RTC_ALARM);
} else { } else {
LOG_WARN("rtc", "Unknown IRQ caught!"); LOG_WARN("rtc", "Unknown IRQ caught!");
/* Disable IRQ so it does not retrigger */ /* Disable IRQ so it does not retrigger */
NVIC_DisableIRQ(RTC_IRQn); NVIC_DisableIRQ(RTC_IRQn);
} }
} }
#pragma GCC diagnostic pop
int epic_rtc_schedule_alarm(uint32_t timestamp) int epic_rtc_schedule_alarm(uint32_t timestamp)
{ {
...@@ -107,7 +112,7 @@ int epic_rtc_schedule_alarm(uint32_t timestamp) ...@@ -107,7 +112,7 @@ int epic_rtc_schedule_alarm(uint32_t timestamp)
* immediately. * immediately.
*/ */
if (epic_rtc_get_seconds() >= timestamp) { if (epic_rtc_get_seconds() >= timestamp) {
api_interrupt_trigger(EPIC_INT_RTC_ALARM); interrupt_trigger(EPIC_INT_RTC_ALARM);
return 0; return 0;
} }
......
#include "epicardium.h" #include "epicardium.h"
#include "api/interrupt-sender.h" #include "os/core.h"
#include "modules/log.h"
#include "modules/modules.h" #include "modules/modules.h"
#include "drivers/drivers.h"
#include "user_core/interrupts.h"
#include "max32665.h" #include "max32665.h"
#include "usb/cdcacm.h" #include "usb/cdcacm.h"
...@@ -51,10 +52,7 @@ void serial_return_to_synchronous() ...@@ -51,10 +52,7 @@ void serial_return_to_synchronous()
write_stream_buffer = NULL; write_stream_buffer = NULL;
} }
/* static void write_str_(const char *str, size_t length)
* API-call to write a string. Output goes to both CDCACM and UART
*/
void epic_uart_write_str(const char *str, intptr_t length)
{ {
if (length == 0) { if (length == 0) {
return; return;
...@@ -120,12 +118,32 @@ void epic_uart_write_str(const char *str, intptr_t length) ...@@ -120,12 +118,32 @@ void epic_uart_write_str(const char *str, intptr_t length)
SERIAL_WRITE_NOTIFY, SERIAL_WRITE_NOTIFY,
eSetBits eSetBits
); );
if (bytes_sent == 0) {
vTaskDelay(1);
} else {
portYIELD(); portYIELD();
} }
}
} while (index < length); } while (index < length);
} }
} }
/*
* API-call to write a string. Output goes to CDCACM, UART and BLE
*
* This is user data from core 1.
*/
void epic_uart_write_str(const char *str, size_t length)
{
/* Make sure that we are not in an interrupt when talking to BLE.
* Should not be the case if this is called from core 1
* anyways. */
if (!xPortIsInsideInterrupt()) {
ble_uart_write((uint8_t *)str, length);
}
write_str_(str, length);
}
static void serial_flush_from_isr(void) static void serial_flush_from_isr(void)
{ {
uint8_t rx_data[32]; uint8_t rx_data[32];
...@@ -161,7 +179,7 @@ static void serial_flush_from_isr(void) ...@@ -161,7 +179,7 @@ static void serial_flush_from_isr(void)
taskEXIT_CRITICAL_FROM_ISR(basepri); taskEXIT_CRITICAL_FROM_ISR(basepri);
portYIELD_FROM_ISR(&resched); portYIELD_FROM_ISR(resched);
} }
static void serial_flush_from_thread(void) static void serial_flush_from_thread(void)
...@@ -193,7 +211,6 @@ static void serial_flush_from_thread(void) ...@@ -193,7 +211,6 @@ static void serial_flush_from_thread(void)
taskEXIT_CRITICAL(); taskEXIT_CRITICAL();
cdcacm_write((uint8_t *)&rx_data, received_bytes); cdcacm_write((uint8_t *)&rx_data, received_bytes);
ble_uart_write((uint8_t *)&rx_data, received_bytes);
} while (received_bytes > 0); } while (received_bytes > 0);
} }
...@@ -240,6 +257,11 @@ int epic_uart_read_str(char *buf, size_t cnt) ...@@ -240,6 +257,11 @@ int epic_uart_read_str(char *buf, size_t cnt)
return i; return i;
} }
/*
* Write a string from epicardium. Output goes to CDCACM and UART
*
* This mainly log data from epicardium, not user date from core 1.
*/
long _write_epicardium(int fd, const char *buf, size_t cnt) long _write_epicardium(int fd, const char *buf, size_t cnt)
{ {
/* /*
...@@ -249,12 +271,12 @@ long _write_epicardium(int fd, const char *buf, size_t cnt) ...@@ -249,12 +271,12 @@ long _write_epicardium(int fd, const char *buf, size_t cnt)
size_t i, last = 0; size_t i, last = 0;
for (i = 0; i < cnt; i++) { for (i = 0; i < cnt; i++) {
if (buf[i] == '\n') { if (buf[i] == '\n') {
epic_uart_write_str(&buf[last], i - last); write_str_(&buf[last], i - last);
epic_uart_write_str("\r", 1); write_str_("\r", 1);
last = i; last = i;
} }
} }
epic_uart_write_str(&buf[last], cnt - last); write_str_(&buf[last], cnt - last);
return cnt; return cnt;
} }
...@@ -280,7 +302,7 @@ void serial_enqueue_char(char chr) ...@@ -280,7 +302,7 @@ void serial_enqueue_char(char chr)
{ {
if (chr == 0x3) { if (chr == 0x3) {
/* Control-C */ /* Control-C */
api_interrupt_trigger(EPIC_INT_CTRL_C); interrupt_trigger(EPIC_INT_CTRL_C);
} }
if (xQueueSend(read_queue, &chr, 100) == errQUEUE_FULL) { if (xQueueSend(read_queue, &chr, 100) == errQUEUE_FULL) {
...@@ -288,7 +310,7 @@ void serial_enqueue_char(char chr) ...@@ -288,7 +310,7 @@ void serial_enqueue_char(char chr)
vTaskDelay(portTICK_PERIOD_MS * 50); vTaskDelay(portTICK_PERIOD_MS * 50);
} }
api_interrupt_trigger(EPIC_INT_UART_RX); interrupt_trigger(EPIC_INT_UART_RX);
} }
void vSerialTask(void *pvParameters) void vSerialTask(void *pvParameters)
......
#include "epicardium.h" #include "epicardium.h"
#include "modules/modules.h" #include "modules/modules.h"
#include "modules/log.h" #include "os/core.h"
#include "card10.h" #include "card10.h"
#include "simo.h" #include "simo.h"
...@@ -8,11 +8,14 @@ ...@@ -8,11 +8,14 @@
#include "max86150.h" #include "max86150.h"
#include "MAX77650-Arduino-Library.h" #include "MAX77650-Arduino-Library.h"
#include "bb_drv.h"
#include "max32665.h" #include "max32665.h"
#include "mxc_sys.h" #include "mxc_sys.h"
#include "mxc_pins.h" #include "mxc_pins.h"
#include <stdint.h> #include <stdint.h>
#include <limits.h>
/* Most code is taken and adapted rom EvKitExamples/LP/main.c */ /* Most code is taken and adapted rom EvKitExamples/LP/main.c */
...@@ -142,8 +145,7 @@ static void gpio_low_power(void) ...@@ -142,8 +145,7 @@ static void gpio_low_power(void)
const unsigned int num_pins = const unsigned int num_pins =
(sizeof(pins_low_power) / sizeof(gpio_cfg_t)); (sizeof(pins_low_power) / sizeof(gpio_cfg_t));
int i; for (size_t i = 0; i < num_pins; i++) {
for (i = 0; i < num_pins; i++) {
GPIO_OutClr(&pins_low_power[i]); GPIO_OutClr(&pins_low_power[i]);
GPIO_Config(&pins_low_power[i]); GPIO_Config(&pins_low_power[i]);
} }
...@@ -177,16 +179,24 @@ void sleep_deepsleep(void) ...@@ -177,16 +179,24 @@ void sleep_deepsleep(void)
/* This will fail if there is no /* This will fail if there is no
* harmonic board attached */ * harmonic board attached */
max86150_begin(); max86150_begin();
max86150_getINT1(); max86150_get_int1();
max86150_getINT2(); max86150_get_int2();
max86150_shutDown(); max86150_shut_down();
#endif #endif
epic_bhi160_disable_all_sensors();
epic_bme680_deinit();
epic_max30001_disable_sensor();
MAX77650_setEN_SBB2(0b100); MAX77650_setEN_SBB2(0b100);
MAX77650_setSBIA_LPM(true); MAX77650_setSBIA_LPM(true);
core1_stop(); core1_stop();
MAX77650_getINT_GLBL(); MAX77650_getINT_GLBL();
gpio_low_power(); gpio_low_power();
if (ble_is_enabled()) {
BbDrvDisable();
}
turnOffClocks(); turnOffClocks();
SYS_ClockSourceEnable(SYS_CLOCK_HIRC);
old_clkcn = MXC_GCR->clkcn; old_clkcn = MXC_GCR->clkcn;
switchToHIRC(); switchToHIRC();
deepsleep(); deepsleep();
...@@ -200,3 +210,16 @@ void sleep_deepsleep(void) ...@@ -200,3 +210,16 @@ void sleep_deepsleep(void)
SystemCoreClockUpdate(); SystemCoreClockUpdate();
MAX77650_setEN_SBB2(0b110); MAX77650_setEN_SBB2(0b110);
} }
int epic_sleep(uint32_t ms)
{
/* Allow the interrupt module to break us out of a call to
* epic_sleep() */
uint32_t count = ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(ms));
if (count == 0) {
return 0;
} else {
return INT_MAX;
}
}
...@@ -11,18 +11,22 @@ ...@@ -11,18 +11,22 @@
#include "epicardium.h" #include "epicardium.h"
#include "modules/filesystem.h" #include "fs/filesystem.h"
#include "os/config.h"
#include "usb/cdcacm.h" #include "usb/cdcacm.h"
#include "usb/mass_storage.h" #include "usb/mass_storage.h"
#include "usb/descriptors.h" #include "usb/descriptors.h"
#include "usb/epc_usb.h" #include "usb/epc_usb.h"
#include "modules/log.h" #include "os/core.h"
#include "mx25lba.h" #include "mx25lba.h"
#include "msc.h" #include "msc.h"
#include "mxc_sys.h"
#include "wdt.h"
/* memory access callbacks for the mass storage (FLASH) device */ /* memory access callbacks for the mass storage (FLASH) device */
static int mscmem_init(); static int mscmem_init();
static uint32_t mscmem_size(void); static uint32_t mscmem_size(void);
...@@ -95,6 +99,9 @@ static uint32_t mscmem_size(void) ...@@ -95,6 +99,9 @@ static uint32_t mscmem_size(void)
static int mscmem_read(uint32_t lba, uint8_t *buffer) static int mscmem_read(uint32_t lba, uint8_t *buffer)
{ {
/* Reset the watchdog as this interrupt might be
* firing back to back for a few seconds. */
WDT_ResetTimer(MXC_WDT0);
return mx25_read(lba, buffer); return mx25_read(lba, buffer);
} }
...@@ -104,6 +111,9 @@ static int mscmem_write(uint32_t lba, uint8_t *buffer) ...@@ -104,6 +111,9 @@ static int mscmem_write(uint32_t lba, uint8_t *buffer)
//bootloader_dirty(); //bootloader_dirty();
} }
dirty = 2; dirty = 2;
/* Reset the watchdog as this interrupt might be
* firing back to back for a few seconds. */
WDT_ResetTimer(MXC_WDT0);
return mx25_write(lba, buffer); return mx25_write(lba, buffer);
} }
...@@ -139,6 +149,7 @@ int epic_usb_shutdown(void) ...@@ -139,6 +149,7 @@ int epic_usb_shutdown(void)
esb_deinit(); esb_deinit();
if (s_fsDetached) { if (s_fsDetached) {
fatfs_attach(); fatfs_attach();
load_config();
} }
return 0; return 0;
} }
...@@ -155,6 +166,7 @@ int epic_usb_cdcacm(void) ...@@ -155,6 +166,7 @@ int epic_usb_cdcacm(void)
esb_deinit(); esb_deinit();
if (s_fsDetached) { if (s_fsDetached) {
fatfs_attach(); fatfs_attach();
load_config();
} }
return esb_init(&s_cfg_cdcacm); return esb_init(&s_cfg_cdcacm);
} }
......
...@@ -30,13 +30,21 @@ void epic_vibra_vibrate(int millis) ...@@ -30,13 +30,21 @@ void epic_vibra_vibrate(int millis)
if (vibra_timer == NULL) { if (vibra_timer == NULL) {
vibra_timer = xTimerCreateStatic( vibra_timer = xTimerCreateStatic(
"vibratimer", "vibratimer",
ticks, 1,
pdFALSE, pdFALSE, /* one-shot */
0, 0,
vTimerCallback, vTimerCallback,
&vibra_timer_data &vibra_timer_data);
);
} }
/* Make sure the duration is valid */
if (ticks < 1) {
/* Disable a potentially running motor / timer */
epic_vibra_set(0);
xTimerStop(vibra_timer, 0);
return;
}
if (vibra_timer != NULL) { if (vibra_timer != NULL) {
epic_vibra_set(1); epic_vibra_set(1);
xTimerChangePeriod(vibra_timer, ticks, 0); xTimerChangePeriod(vibra_timer, ticks, 0);
......
#include "modules/log.h" #include "os/core.h"
#include "modules/modules.h" #include "modules/modules.h"
#include "timers.h" #include "timers.h"
......
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
#include "epicardium.h" #include "epicardium.h"
#include "max32665.h" #include "max32665.h"
#include "gpio.h" #include "gpio.h"
#include "modules.h" #include "modules/modules.h"
#include "drivers/drivers.h"
#include <stdbool.h> #include <stdbool.h>
...@@ -63,14 +64,22 @@ void epic_ws2812_write(uint8_t pin, uint8_t *pixels, uint32_t n_bytes) ...@@ -63,14 +64,22 @@ void epic_ws2812_write(uint8_t pin, uint8_t *pixels, uint32_t n_bytes)
taskENTER_CRITICAL(); taskENTER_CRITICAL();
/*
* If the pin was not previously configured as an output, the
* `epic_gpio_set_pin_mode()` call will pull it down which the first
* neopixel interprets as the color `0x008000`. To fix this, wait a bit
* after mode-setting and then write the new values.
*/
if ((epic_gpio_get_pin_mode(pin) & EPIC_GPIO_MODE_OUT) == 0) {
epic_gpio_set_pin_mode(pin, EPIC_GPIO_MODE_OUT); epic_gpio_set_pin_mode(pin, EPIC_GPIO_MODE_OUT);
}
GPIO_OutClr(pin_cfg);
epic_ws2812_delay_ticks(EPIC_WS2812_RESET_TCKS);
do { do {
epic_ws2812_transmit_byte(pin_cfg, *pixels); epic_ws2812_transmit_byte(pin_cfg, *pixels);
} while (++pixels != pixels_end); } while (++pixels != pixels_end);
GPIO_OutClr(pin_cfg);
epic_ws2812_delay_ticks(EPIC_WS2812_RESET_TCKS);
taskEXIT_CRITICAL(); taskEXIT_CRITICAL();
} }
#include <math.h>
static const uint8_t pride_colors[6][3] = {
{ 0xe4, 0x02, 0x02 }, { 0xff, 0x8c, 0x00 }, { 0xff, 0xed, 0x00 },
{ 0x00, 0x80, 0x26 }, { 0x00, 0x4d, 0xff }, { 0x75, 0x06, 0x87 },
};
static void epic_frame(Ctx *epicardium_ctx, float frame)
{
int num_colors = sizeof(pride_colors) / sizeof(pride_colors[0]);
for (int color = 0; color < num_colors; color++) {
ctx_rgba8_stroke(
epicardium_ctx,
pride_colors[color][0],
pride_colors[color][1],
pride_colors[color][2],
0xff
);
ctx_line_width(epicardium_ctx, 10.0);
ctx_line_cap(epicardium_ctx, CTX_CAP_ROUND);
float width =
expf(-pow(frame / 2.0 - 5 + color / 2.0, 2)) * 55.0 +
5.0;
float ypos = color * 10.0 + 40.0 - (num_colors - 1) * 5.0;
ctx_move_to(epicardium_ctx, 80.0 - width, ypos);
ctx_line_to(epicardium_ctx, 80.0 + width, ypos);
ctx_stroke(epicardium_ctx);
}
ctx_save(epicardium_ctx);
ctx_font_size(epicardium_ctx, 20.0f);
ctx_text_baseline(epicardium_ctx, CTX_TEXT_BASELINE_BOTTOM);
ctx_rgba8(epicardium_ctx, 0xff, 0xff, 0xff, 0xff);
ctx_text_align(epicardium_ctx, CTX_TEXT_ALIGN_CENTER);
ctx_move_to(epicardium_ctx, 80.0f, 58.0f);
ctx_text(epicardium_ctx, "Epicardium");
if (strcmp(CARD10_VERSION, "v1.18") != 0) {
ctx_text_align(epicardium_ctx, CTX_TEXT_ALIGN_LEFT);
ctx_move_to(epicardium_ctx, 2.0f, 78.0f);
ctx_text(epicardium_ctx, CARD10_VERSION);
} else {
ctx_move_to(epicardium_ctx, 80.0f, 78.0f);
ctx_text(epicardium_ctx, "Queer Quinoa");
}
ctx_restore(epicardium_ctx);
}
...@@ -33,9 +33,11 @@ typedef _Bool bool; ...@@ -33,9 +33,11 @@ typedef _Bool bool;
#define API_SYSTEM_EXEC 0x2 #define API_SYSTEM_EXEC 0x2
#define API_SYSTEM_RESET 0x3 #define API_SYSTEM_RESET 0x3
#define API_BATTERY_VOLTAGE 0x4 #define API_BATTERY_VOLTAGE 0x4
#define API_SLEEP 0x5
#define API_INTERRUPT_ENABLE 0xA #define API_INTERRUPT_ENABLE 0xA
#define API_INTERRUPT_DISABLE 0xB #define API_INTERRUPT_DISABLE 0xB
#define API_INTERRUPT_IS_ENABLED 0xC
#define API_UART_WRITE_STR 0x10 #define API_UART_WRITE_STR 0x10
#define API_UART_READ_CHAR 0x11 #define API_UART_READ_CHAR 0x11
...@@ -55,6 +57,7 @@ typedef _Bool bool; ...@@ -55,6 +57,7 @@ typedef _Bool bool;
#define API_DISP_FRAMEBUFFER 0x29 #define API_DISP_FRAMEBUFFER 0x29
#define API_DISP_BACKLIGHT 0x2a #define API_DISP_BACKLIGHT 0x2a
#define API_DISP_PRINT_ADV 0x2b #define API_DISP_PRINT_ADV 0x2b
#define API_DISP_BLIT 0x2d
/* API_BATTERY_VOLTAGE 0x30 */ /* API_BATTERY_VOLTAGE 0x30 */
#define API_BATTERY_CURRENT 0x31 #define API_BATTERY_CURRENT 0x31
...@@ -76,6 +79,7 @@ typedef _Bool bool; ...@@ -76,6 +79,7 @@ typedef _Bool bool;
#define API_FILE_UNLINK 0x4b #define API_FILE_UNLINK 0x4b
#define API_FILE_RENAME 0x4c #define API_FILE_RENAME 0x4c
#define API_FILE_MKDIR 0x4d #define API_FILE_MKDIR 0x4d
#define API_FILE_FS_ATTACHED 0x4e
#define API_RTC_GET_SECONDS 0x50 #define API_RTC_GET_SECONDS 0x50
#define API_RTC_SCHEDULE_ALARM 0x51 #define API_RTC_SCHEDULE_ALARM 0x51
...@@ -100,6 +104,7 @@ typedef _Bool bool; ...@@ -100,6 +104,7 @@ typedef _Bool bool;
#define API_LEDS_CLEAR_ALL 0x6d #define API_LEDS_CLEAR_ALL 0x6d
#define API_LEDS_GET_ROCKET 0x6e #define API_LEDS_GET_ROCKET 0x6e
#define API_LEDS_GET 0x6f #define API_LEDS_GET 0x6f
#define API_LEDS_FLASH_ROCKET 0x72
#define API_VIBRA_SET 0x70 #define API_VIBRA_SET 0x70
#define API_VIBRA_VIBRATE 0x71 #define API_VIBRA_VIBRATE 0x71
...@@ -117,6 +122,7 @@ typedef _Bool bool; ...@@ -117,6 +122,7 @@ typedef _Bool bool;
#define API_GPIO_READ_PIN 0xA3 #define API_GPIO_READ_PIN 0xA3
#define API_TRNG_READ 0xB0 #define API_TRNG_READ 0xB0
#define API_CSPRNG_READ 0XB1
#define API_PERSONAL_STATE_SET 0xc0 #define API_PERSONAL_STATE_SET 0xc0
#define API_PERSONAL_STATE_GET 0xc1 #define API_PERSONAL_STATE_GET 0xc1
...@@ -125,6 +131,7 @@ typedef _Bool bool; ...@@ -125,6 +131,7 @@ typedef _Bool bool;
#define API_BME680_INIT 0xD0 #define API_BME680_INIT 0xD0
#define API_BME680_DEINIT 0xD1 #define API_BME680_DEINIT 0xD1
#define API_BME680_GET_DATA 0xD2 #define API_BME680_GET_DATA 0xD2
#define API_BSEC_GET_DATA 0xD3
#define API_BHI160_ENABLE 0xe0 #define API_BHI160_ENABLE 0xe0
#define API_BHI160_DISABLE 0xe1 #define API_BHI160_DISABLE 0xe1
...@@ -133,9 +140,8 @@ typedef _Bool bool; ...@@ -133,9 +140,8 @@ typedef _Bool bool;
#define API_MAX30001_ENABLE 0xf0 #define API_MAX30001_ENABLE 0xf0
#define API_MAX30001_DISABLE 0xf1 #define API_MAX30001_DISABLE 0xf1
#define API_MAX86150_INIT 0x0100 #define API_MAX86150_ENABLE 0x0100
#define API_MAX86150_GET_DATA 0x0101 #define API_MAX86150_DISABLE 0x0101
#define API_MAX86150_SET_LED_AMPLITUDE 0x0102
#define API_USB_SHUTDOWN 0x110 #define API_USB_SHUTDOWN 0x110
#define API_USB_STORAGE 0x111 #define API_USB_STORAGE 0x111
...@@ -143,6 +149,51 @@ typedef _Bool bool; ...@@ -143,6 +149,51 @@ typedef _Bool bool;
#define API_WS2812_WRITE 0x0120 #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_MODE 0x142
#define API_BLE_GET_EVENT 0x143
#define API_BLE_GET_SCAN_REPORT 0x144
#define API_BLE_GET_LAST_PAIRING_NAME 0x145
#define API_BLE_GET_PEER_DEVICE_NAME 0x146
#define API_BLE_FREE_EVENT 0x147
#define API_BLE_HID_SEND_REPORT 0x150
#define API_BLE_ATTS_DYN_CREATE_GROUP 0x160
#define API_BLE_ATTS_DYN_DELETE_GROUP 0x161
#define API_BLE_ATTS_DYN_DELETE_GROUPS 0x169
#define API_BLE_ATTS_DYN_ADD_CHARACTERISTIC 0x16B
#define API_BLE_ATTS_DYN_ADD_DESCRIPTOR 0x163
#define API_BLE_ATTS_SET_BUFFER 0x16A
#define API_BLE_ATTS_SEND_SERVICE_CHANGED_IND 0x168
#define API_BLE_ATTS_SET_ATTR 0x170
#define API_BLE_ATTS_HANDLE_VALUE_NTF 0x171
#define API_BLE_ATTS_HANDLE_VALUE_IND 0x172
#define API_BLE_CLOSE_CONNECTION 0x180
#define API_BLE_IS_CONNECTION_OPEN 0x181
#define API_BLE_SET_DEVICE_NAME 0x182
#define API_BLE_GET_DEVICE_NAME 0x183
#define API_BLE_GET_ADDRESS 0x184
#define API_BLE_ADVERTISE 0x185
#define API_BLE_ADVERTISE_STOP 0x186
#define API_BLE_DISCOVER_PRIMARY_SERVICES 0x187
#define API_BLE_DISCOVER_CHARACTERISTICS 0x188
#define API_BLE_DISCOVER_DESCRIPTORS 0x189
#define API_BLE_ATTC_READ 0x18A
#define API_BLE_ATTC_WRITE_NO_RSP 0x18B
#define API_BLE_ATTC_WRITE 0x18C
#define API_BLE_INIT 0x190
#define API_BLE_DEINIT 0x191
/* clang-format on */ /* clang-format on */
typedef uint32_t api_int_id_t; typedef uint32_t api_int_id_t;
...@@ -155,6 +206,10 @@ typedef uint32_t api_int_id_t; ...@@ -155,6 +206,10 @@ typedef uint32_t api_int_id_t;
* (masked/unmasked) using :c:func:`epic_interrupt_enable` and * (masked/unmasked) using :c:func:`epic_interrupt_enable` and
* :c:func:`epic_interrupt_disable`. * :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:: * .. warning::
* *
* Never attempt to call the API from inside an ISR. This might trigger an * Never attempt to call the API from inside an ISR. This might trigger an
...@@ -177,6 +232,19 @@ API(API_INTERRUPT_ENABLE, int epic_interrupt_enable(api_int_id_t int_id)); ...@@ -177,6 +232,19 @@ API(API_INTERRUPT_ENABLE, int epic_interrupt_enable(api_int_id_t int_id));
*/ */
API(API_INTERRUPT_DISABLE, int epic_interrupt_disable(api_int_id_t int_id)); 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: * The following interrupts are defined:
*/ */
...@@ -200,9 +268,13 @@ API(API_INTERRUPT_DISABLE, int epic_interrupt_disable(api_int_id_t int_id)); ...@@ -200,9 +268,13 @@ API(API_INTERRUPT_DISABLE, int epic_interrupt_disable(api_int_id_t int_id));
#define EPIC_INT_MAX30001_ECG 7 #define EPIC_INT_MAX30001_ECG 7
/** BHI160 Magnetometer. See :c:func:`epic_isr_bhi160_magnetometer`. */ /** BHI160 Magnetometer. See :c:func:`epic_isr_bhi160_magnetometer`. */
#define EPIC_INT_BHI160_MAGNETOMETER 8 #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
#define EPIC_INT_MAX86150_PROX 11
/* Number of defined interrupts. */ /* Number of defined interrupts. */
#define EPIC_INT_NUM 9 #define EPIC_INT_NUM 12
/* clang-format on */ /* clang-format on */
/* /*
...@@ -264,6 +336,25 @@ API(API_SYSTEM_EXEC, int __epic_exec(char *name)); ...@@ -264,6 +336,25 @@ API(API_SYSTEM_EXEC, int __epic_exec(char *name));
*/ */
API(API_SYSTEM_RESET, void epic_system_reset(void)); API(API_SYSTEM_RESET, void epic_system_reset(void));
/**
* Sleep for the specified amount of time.
*
* This call will block for at most the specified amount of time. It allows epicardium to
* reduce clock speed of the system until this call is finished.
*
* This call returns early if an interrupt is signaled from epicardium.
*
* The clock source of epicardium has a limited amount of accuracy. Tolerances
* of +- 10% have been observed. This means that the sleep time also has a
* tolarance of at least +- 10%. The exact amount varies from device to device and
* also with temperature. You should take this into consideration when selecting
* the time you want to sleep.
*
* :param ms: Time to wait in milliseconds
* :returns: 0 if no interrupt happened, ``INT_MAX`` if an interrupt happened and the sleep ended early.
*/
API(API_SLEEP, int epic_sleep(uint32_t ms));
/** /**
* PMIC API * PMIC API
* =============== * ===============
...@@ -317,7 +408,7 @@ API(API_THERMISTOR_VOLTAGE, int epic_read_thermistor_voltage(float *result)); ...@@ -317,7 +408,7 @@ API(API_THERMISTOR_VOLTAGE, int epic_read_thermistor_voltage(float *result));
* :param length: Amount of bytes to print. * :param length: Amount of bytes to print.
*/ */
API(API_UART_WRITE_STR, void epic_uart_write_str( API(API_UART_WRITE_STR, void epic_uart_write_str(
const char *str, intptr_t length const char *str, size_t length
)); ));
/** /**
...@@ -613,6 +704,19 @@ API(API_LEDS_SET, void epic_leds_set(int led, uint8_t r, uint8_t g, uint8_t b)); ...@@ -613,6 +704,19 @@ API(API_LEDS_SET, void epic_leds_set(int led, uint8_t r, uint8_t g, uint8_t b));
*/ */
API(API_LEDS_GET, int epic_leds_get_rgb(int led, uint8_t * rgb)); API(API_LEDS_GET, int epic_leds_get_rgb(int led, uint8_t * rgb));
/**
* Set one of the rockets to flash for a certain time.
*
* :c:func:`epic_leds_flash_rocket` will set a timer for the flash of a rocket.
*
* :param int led: Number of the rocket that sould flash
* :param uint8_t value: brightness of the 'on'-state of this rocket ( 0 < value < 32)
* :param int millis: time in milliseconds defining the duration of the flash (i.e. how long is the rocket 'on')
*
* .. versionadded:: 1.16
*/
API(API_LEDS_FLASH_ROCKET, void epic_leds_flash_rocket(int led, uint8_t valiue, int millis));
/** /**
* Set one of card10's RGB LEDs to a certain color in HSV format. * Set one of card10's RGB LEDs to a certain color in HSV format.
* *
...@@ -868,6 +972,222 @@ API(API_BME680_GET_DATA, int epic_bme680_read_sensors( ...@@ -868,6 +972,222 @@ API(API_BME680_GET_DATA, int epic_bme680_read_sensors(
struct bme680_sensor_data *data struct bme680_sensor_data *data
)); ));
/**
* .. _bsec_api:
*
* BSEC
* ----
* The Bosch Sensortec Environmental Cluster (BSEC) library
* allows to estimate an indoor air qualtiy (IAQ) metric as
* well as CO2 and VOC content equivalents using the gas sensor
* of the BME680.
*
* As it is a proprietary binary blob, it has to be enabled using
* the ``bsec_enable`` configuration option (see :ref:`card10_cfg`).
*
* Please also have a look at the BME680 datasheet and some of
* the BSEC documentation:
*
* https://git.card10.badge.events.ccc.de/card10/hardware/-/blob/master/datasheets/bosch/BST-BME680-DS001.pdf
*
* https://git.card10.badge.events.ccc.de/card10/firmware/-/blob/master/lib/vendor/Bosch/BSEC/integration_guide/BST-BME680-Integration-Guide-AN008-48.pdf
*/
/**
* BSEC Sensor Data
*/
struct bsec_sensor_data {
/** Compensated temperature in degree celsius */
float temperature;
/** Compensated humidity in % relative humidity */
float humidity;
/** Pressure in hPa */
float pressure;
/** Gas resistance in Ohms */
float gas_resistance;
/** Timestamp in of the measurement in UNIX time (seconds since
* 1970-01-01 00:00:00 UTC)*/
uint32_t timestamp;
/** Accuracy of IAQ, CO2 equivalent and breath VOC equivalent:
*
* 0: Stabilization / run-in ongoing:
* This means that the sensor still needs to warm up. Takes about
* 5 min after activation of BSEC / reboot.
*
* 1: Low accuracy:
* The sensor has not yet been calibrated. BSEC needs to collect
* more data to calibrate the sensor. This can take multiple
* hours.
*
* BSEC documentation: To reach high accuracy(3) please expose
* sensor once to good air (e.g. outdoor air) and bad air (e.g.
* box with exhaled breath) for auto-trimming
*
* 2: Medium accuracy: auto-trimming ongoing
* BSEC has detected that it needs to recalibrate the sensor.
* This is an automatic process and usally finishes after tens
* of minutes. Can happen every now and then.
*
* 3: High accuracy:
* The sensor has warmed up and is calibrated.
*
* From BSEC documentation:
* IAQ accuracy indicator will notify the user when they should
* initiate a calibration process. Calibration is performed automatically
* in the background if the sensor is exposed to clean and polluted air
* for approximately 30 minutes each.
*
* See also:
* https://community.bosch-sensortec.com/t5/MEMS-sensors-forum/BME680-IAQ-accuracy-definition/m-p/5931/highlight/true#M10
*/
uint8_t accuracy;
/** Indoor Air Quality with range 0 to 500
*
* Statement from the Bosch BSEC library:
*
* Indoor-air-quality (IAQ) gives an indication of the relative change
* in ambient TVOCs detected by BME680.
*
* The IAQ scale ranges from 0 (clean air) to 500 (heavily polluted air).
* During operation, algorithms automatically calibrate and adapt
* themselves to the typical environments where the sensor is operated
* (e.g., home, workplace, inside a car, etc.).This automatic background
* calibration ensures that users experience consistent IAQ performance.
* The calibration process considers the recent measurement history (typ.
* up to four days) to ensure that IAQ=25 corresponds to typical good air
* and IAQ=250 indicates typical polluted air.
*
* Please also consult the BME680 datsheet (pages 9 and 21) as well:
* https://git.card10.badge.events.ccc.de/card10/hardware/-/blob/master/datasheets/bosch/BST-BME680-DS001.pdf
*
*/
int32_t indoor_air_quality;
/** Unscaled IAQ value.
*
* See this post for details:
* https://community.bosch-sensortec.com/t5/MEMS-sensors-forum/BME680-strange-IAQ-and-CO2-values/m-p/9667/highlight/true#M1505
*/
int32_t static_indoor_air_quality;
/** Estimation of equivalant CO2 content in the air in ppm. */
float co2_equivalent;
/** Estimation of equivalant breath VOC content in the air in ppm. */
float breath_voc_equivalent;
};
/**
*
* Get the current BME680 data filtered by Bosch BSEC library
*
* As it is a proprietary binary blob, it has to be enabled using
* the ``bsec_enable`` configuration option (see :ref:`card10_cfg`).
*
* The sample rate is currently fixed to one sample every 3 seconds.
* Querying the sensor more often will return cached data.
*
* After the libary has been activated it starts to calibrate the
* sensor. This can take multiple hours.
* After a reset/power on it takes about 5 minutes to stabilize
* the sensor if it was calibrated before.
*
* The BSEC library regularly recalibrates the sensor during operation.
* The ``accuracy`` field of the return data indicates the calibration
* status of the sensor. Please take it into consideration when
* using / displaying the IAQ.
*
* Please refer to the description of :c:type:`bsec_sensor_data` for more
* information about how to interpret its content.
*
* .. versionadded:: 1.x
*
* :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``: No data available from the sensor.
* - ``-ENODEV``: BSEC libray is not running.
*/
API(API_BSEC_GET_DATA, int epic_bsec_read_sensors(
struct bsec_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.16
*/
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.16
*/
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 * Personal State
* ============== * ==============
...@@ -1136,7 +1456,7 @@ struct bhi160_sensor_config { ...@@ -1136,7 +1456,7 @@ struct bhi160_sensor_config {
}; };
/** /**
* Enable a BHI160 virtual sensor. Calling this funciton will instruct the * Enable a BHI160 virtual sensor. Calling this function will instruct the
* BHI160 to collect data for this specific virtual sensor. You can then * BHI160 to collect data for this specific virtual sensor. You can then
* retrieve the samples using :c:func:`epic_stream_read`. * retrieve the samples using :c:func:`epic_stream_read`.
* *
...@@ -1356,6 +1676,16 @@ enum disp_font_name { ...@@ -1356,6 +1676,16 @@ enum disp_font_name {
DISP_FONT24 = 4, DISP_FONT24 = 4,
}; };
/*
* Image data type
*/
enum epic_rgb_format {
EPIC_RGB8 = 0,
EPIC_RGBA8 = 1,
EPIC_RGB565 = 2,
EPIC_RGBA5551 = 3,
};
/** /**
* Prints a string into the display framebuffer with font type selectable * Prints a string into the display framebuffer with font type selectable
* *
...@@ -1402,6 +1732,25 @@ API(API_DISP_PIXEL, int epic_disp_pixel( ...@@ -1402,6 +1732,25 @@ API(API_DISP_PIXEL, int epic_disp_pixel(
int16_t x, int16_t y, uint16_t color int16_t x, int16_t y, uint16_t color
)); ));
/**
* Blits an image buffer to the display
*
* :param x: x position
* :param y: y position
* :param w: Image width
* :param h: Image height
* :param img: Image data
* :param format: Format of the image data. One of :c:type:`epic_rgb_format`.
*/
API(API_DISP_BLIT, int epic_disp_blit(
int16_t x,
int16_t y,
int16_t w,
int16_t h,
void *img,
enum epic_rgb_format format
));
/** /**
* Draws a line on the display * Draws a line on the display
* *
...@@ -1486,6 +1835,12 @@ API(API_DISP_FRAMEBUFFER, int epic_disp_framebuffer( ...@@ -1486,6 +1835,12 @@ API(API_DISP_FRAMEBUFFER, int epic_disp_framebuffer(
)); ));
/**
* Light Sensor
* ============
*/
/** /**
* Set the backlight brightness. * Set the backlight brightness.
* *
...@@ -1499,12 +1854,12 @@ API(API_DISP_BACKLIGHT, int epic_disp_backlight(uint16_t brightness)); ...@@ -1499,12 +1854,12 @@ API(API_DISP_BACKLIGHT, int epic_disp_backlight(uint16_t brightness));
/** /**
* Start continuous readout of the light sensor. Will read light level * Start continuous readout of the light sensor. Will read light level
* at preconfigured interval and make it available via `epic_light_sensor_get()`. * at preconfigured interval and make it available via :c:func:`epic_light_sensor_get`.
* *
* If the continuous readout was already running, this function will silently pass. * If the continuous readout was already running, this function will silently pass.
* *
* *
* :return: `0` if the start was successful or a negative error value * :return: ``0`` if the start was successful or a negative error value
* if an error occured. Possible errors: * if an error occured. Possible errors:
* *
* - ``-EBUSY``: The timer could not be scheduled. * - ``-EBUSY``: The timer could not be scheduled.
...@@ -1515,7 +1870,7 @@ API(API_LIGHT_SENSOR_RUN, int epic_light_sensor_run()); ...@@ -1515,7 +1870,7 @@ API(API_LIGHT_SENSOR_RUN, int epic_light_sensor_run());
* Get the last light level measured by the continuous readout. * Get the last light level measured by the continuous readout.
* *
* :param uint16_t* value: where the last light level should be written. * :param uint16_t* value: where the last light level should be written.
* :return: `0` if the readout was successful or a negative error * :return: ``0`` if the readout was successful or a negative error
* value. Possible errors: * value. Possible errors:
* *
* - ``-ENODATA``: Continuous readout not currently running. * - ``-ENODATA``: Continuous readout not currently running.
...@@ -1528,7 +1883,7 @@ API(API_LIGHT_SENSOR_GET, int epic_light_sensor_get(uint16_t* value)); ...@@ -1528,7 +1883,7 @@ API(API_LIGHT_SENSOR_GET, int epic_light_sensor_get(uint16_t* value));
* *
* If the continuous readout wasn't running, this function will silently pass. * If the continuous readout wasn't running, this function will silently pass.
* *
* :return: `0` if the stop was sucessful or a negative error value * :return: ``0`` if the stop was sucessful or a negative error value
* if an error occured. Possible errors: * if an error occured. Possible errors:
* *
* - ``-EBUSY``: The timer stop could not be scheduled. * - ``-EBUSY``: The timer stop could not be scheduled.
...@@ -1730,6 +2085,15 @@ API(API_FILE_RENAME, int epic_file_rename(const char *oldp, const char* newp)); ...@@ -1730,6 +2085,15 @@ API(API_FILE_RENAME, int epic_file_rename(const char *oldp, const char* newp));
*/ */
API(API_FILE_MKDIR, int epic_file_mkdir(const char *dirname)); API(API_FILE_MKDIR, int epic_file_mkdir(const char *dirname));
/**
* Check whether the filesystem is currently attached and a call like
* :c:func:`epic_file_open` has a chance to succeed.
*
* :return: ``true`` if the filesystem is attached and ``false`` if the
* filesystem is not attached.
*/
API(API_FILE_FS_ATTACHED, bool epic_fs_is_attached(void));
/** /**
* RTC * RTC
* === * ===
...@@ -1782,7 +2146,7 @@ API(API_RTC_SET_MILLISECONDS, void epic_rtc_set_milliseconds( ...@@ -1782,7 +2146,7 @@ API(API_RTC_SET_MILLISECONDS, void epic_rtc_set_milliseconds(
* Schedule the RTC alarm for the given timestamp. * Schedule the RTC alarm for the given timestamp.
* *
* :param uint32_t timestamp: When to schedule the IRQ * :param uint32_t timestamp: When to schedule the IRQ
* :return: `0` on success or a negative value if an error occured. Possible * :return: ``0`` on success or a negative value if an error occured. Possible
* errors: * errors:
* *
* - ``-EINVAL``: RTC is in a bad state * - ``-EINVAL``: RTC is in a bad state
...@@ -1798,22 +2162,49 @@ API(API_RTC_SCHEDULE_ALARM, int epic_rtc_schedule_alarm(uint32_t timestamp)); ...@@ -1798,22 +2162,49 @@ API(API_RTC_SCHEDULE_ALARM, int epic_rtc_schedule_alarm(uint32_t timestamp));
API_ISR(EPIC_INT_RTC_ALARM, epic_isr_rtc_alarm); API_ISR(EPIC_INT_RTC_ALARM, epic_isr_rtc_alarm);
/** /**
* TRNG * RNG
* ==== * ====
*/ */
/** /**
* Read random bytes from the TRNG. * Read random bytes from the TRNG.
* *
* Be aware that this function returns raw unprocessed bytes from
* the TRNG. They might be biased or have other kinds of imperfections.
*
* Use :c:func:`epic_csprng_read` for cryptographically safe random
* numbers instead.
*
* .. warning::
*
* The exact behaviour of the TRNG is not well understood. Its
* distribution and other parameters are unknown. Only use this
* function if you really want the unmodified values from the
* hardware TRNG to experiment with it.
*
* :param uint8_t * dest: Destination buffer * :param uint8_t * dest: Destination buffer
* :param size: Number of bytes to read. * :param size: Number of bytes to read.
* :return: `0` on success or a negative value if an error occured. Possible * :return: ``0`` on success or a negative value if an error occured. Possible
* errors: * errors:
* *
* - ``-EFAULT``: Invalid destination address. * - ``-EFAULT``: Invalid destination address.
*/ */
API(API_TRNG_READ, int epic_trng_read(uint8_t *dest, size_t size)); API(API_TRNG_READ, int epic_trng_read(uint8_t *dest, size_t size));
/**
* Read random bytes from the CSPRNG.
*
* The random bytes returned are safe to be used for cryptography.
*
* :param uint8_t * dest: Destination buffer
* :param size: Number of bytes to read.
* :return: ``0`` on success or a negative value if an error occured. Possible
* errors:
*
* - ``-EFAULT``: Invalid destination address.
*/
API(API_CSPRNG_READ, int epic_csprng_read(uint8_t *dest, size_t size));
/** /**
* MAX30001 * MAX30001
* ======== * ========
...@@ -1851,9 +2242,9 @@ struct max30001_sensor_config { ...@@ -1851,9 +2242,9 @@ struct max30001_sensor_config {
}; };
/** /**
* Enable a MAX30001 ecg sensor. * Enable a MAX30001 ECG sensor.
* *
* Calling this funciton will instruct the MAX30001 to collect data for this * Calling this function will instruct the MAX30001 to collect data for this
* sensor. You can then retrieve the samples using :c:func:`epic_stream_read`. * sensor. You can then retrieve the samples using :c:func:`epic_stream_read`.
* *
* :param max30001_sensor_config* config: Configuration for this sensor. * :param max30001_sensor_config* config: Configuration for this sensor.
...@@ -1914,7 +2305,7 @@ API(API_USB_CDCACM, int epic_usb_cdcacm(void)); ...@@ -1914,7 +2305,7 @@ API(API_USB_CDCACM, int epic_usb_cdcacm(void));
/** /**
* Takes a gpio pin specified with the gpio module and transmits * Takes a gpio pin specified with the gpio module and transmits
* the led data. The format `GG:RR:BB` is expected. * the led data. The format ``GG:RR:BB`` is expected.
* *
* :param uint8_t pin: The gpio pin to be used for data. * :param uint8_t pin: The gpio pin to be used for data.
* :param uint8_t * pixels: The buffer, in which the pixel data is stored. * :param uint8_t * pixels: The buffer, in which the pixel data is stored.
...@@ -1924,5 +2315,452 @@ API(API_USB_CDCACM, int epic_usb_cdcacm(void)); ...@@ -1924,5 +2315,452 @@ API(API_USB_CDCACM, int epic_usb_cdcacm(void));
*/ */
API(API_WS2812_WRITE, void epic_ws2812_write(uint8_t pin, uint8_t *pixels, uint32_t n_bytes)); API(API_WS2812_WRITE, void epic_ws2812_write(uint8_t pin, uint8_t *pixels, uint32_t n_bytes));
/**
* Configuration
* =============
*/
/**
* Read an integer from the configuration file
*
* :param char* key: Name of the option to read
* :param int* value: Place to read the value into
* :return: ``0`` on success or a negative value if an error occured. Possible
* errors:
*
* - ``-ENOENT``: Value can not be read
*
* .. versionadded:: 1.13
*/
API(API_CONFIG_GET_INTEGER, int epic_config_get_integer(const char *key, int *value));
/**
* Read a boolean from the configuration file
*
* :param char* key: Name of the option to read
* :param bool* value: Place to read the value into
* :return: ``0`` on success or a negative value if an error occured. Possible
* errors:
*
* - ``-ENOENT``: Value can not be read
*
* .. versionadded:: 1.13
*/
API(API_CONFIG_GET_BOOLEAN, int epic_config_get_boolean(const char *key, bool *value));
/**
* Read a string from the configuration file.
*
* If the buffer supplied is too small for the config option,
* no error is reported and the first ``buf_len - 1`` characters
* are returned (0 terminated).
*
* :param char* key: Name of the option to read
* :param char* buf: Place to read the string into
* :param size_t buf_len: Size of the provided buffer
* :return: ``0`` on success or a negative value if an error occured. Possible
* errors:
*
* - ``-ENOENT``: Value can not be read
*
* .. versionadded:: 1.13
*/
API(API_CONFIG_GET_STRING, int epic_config_get_string(const char *key, char *buf, size_t buf_len));
/**
* Write a string to the configuration file.
*
* :param char* key: Name of the option to write
* :param char* value: The value to write
* :return: ``0`` on success or a negative value if an error occured. Possivle
* errors:
*
* - ``-EINVAL``: Parameters out of range
* - ``-ENOENT``: Key already exists but can not be read
* - ``-EIO`` : Unspecified I/O error
* - Any fopen/fread/fwrite/fclose related error code
*
* .. versionadded:: 1.16
*/
API(API_CONFIG_SET_STRING, int epic_config_set_string(const char *key, const char *value));
/**
* Bluetooth Low Energy (BLE)
* ==========================
*/
/**
* BLE event type
*/
enum epic_ble_event_type {
/** No event pending */
BLE_EVENT_NONE = 0,
/** Numeric comparison requested */
BLE_EVENT_HANDLE_NUMERIC_COMPARISON = 1,
/** A pairing procedure has failed */
BLE_EVENT_PAIRING_FAILED = 2,
/** A pairing procedure has successfully completed */
BLE_EVENT_PAIRING_COMPLETE = 3,
/** New scan data is available */
BLE_EVENT_SCAN_REPORT = 4,
BLE_EVENT_ATT_EVENT = 5,
BLE_EVENT_ATT_WRITE = 6,
BLE_EVENT_DM_EVENT = 7,
};
/**
* MicroPython Bluetooth support data types. Please
* do not use them until they are stabilized.
*/
typedef uint8_t bdAddr_t[6];
struct epic_wsf_header
{
/** General purpose parameter passed to event handler */
uint16_t param;
/** General purpose event value passed to event handler */
uint8_t event;
/** General purpose status value passed to event handler */
uint8_t status;
};
struct epic_att_event
{
/** Header structure */
struct epic_wsf_header hdr;
/** Value */
uint8_t *pValue;
/** Value length */
uint16_t valueLen;
/** Attribute handle */
uint16_t handle;
/** TRUE if more response packets expected */
uint8_t continuing;
/** Negotiated MTU value */
uint16_t mtu;
};
struct epic_hciLeConnCmpl_event
{ /** Event header */
struct epic_wsf_header hdr;
/** Status. */
uint8_t status;
/** Connection handle. */
uint16_t handle;
/** Local connection role. */
uint8_t role;
/** Peer address type. */
uint8_t addrType;
/** Peer address. */
bdAddr_t peerAddr;
/** Connection interval */
uint16_t connInterval;
/** Connection latency. */
uint16_t connLatency;
/** Supervision timeout. */
uint16_t supTimeout;
/** Clock accuracy. */
uint8_t clockAccuracy;
/** enhanced fields */
/** Local RPA. */
bdAddr_t localRpa;
/** Peer RPA. */
bdAddr_t peerRpa;
};
/*! \brief Disconnect complete event */
struct epic_hciDisconnectCmpl_event
{
/** Event header */
struct epic_wsf_header hdr;
/** Disconnect complete status. */
uint8_t status;
/** Connect handle. */
uint16_t handle;
/** Reason. */
uint8_t reason;
};
struct epic_dm_event
{
union {
/** LE connection complete. */
struct epic_hciLeConnCmpl_event leConnCmpl;
/** Disconnect complete. */
struct epic_hciDisconnectCmpl_event disconnectCmpl;
};
};
struct epic_att_write
{
/** Header structure */
struct epic_wsf_header hdr;
/** Value length */
uint16_t valueLen;
/** Attribute handle */
uint16_t handle;
uint8_t operation;
uint16_t offset;
void *buffer;
};
struct epic_ble_event {
enum epic_ble_event_type type;
union {
void *data;
struct epic_att_event *att_event;
struct epic_dm_event *dm_event;
struct epic_att_write *att_write;
};
};
/**
* Scan report data. Based on ``hciLeAdvReportEvt_t`` from BLE stack.
*
* TODO: 64 bytes for data is an arbitrary number ATM */
struct epic_scan_report
{
/** advertising or scan response data. */
uint8_t data[64];
/** length of advertising or scan response data. */
uint8_t len;
/** RSSI. */
int8_t rssi;
/** Advertising event type. */
uint8_t eventType;
/** Address type. */
uint8_t addrType;
/** Device address. */
uint8_t addr[6];
/** direct fields */
/** Direct advertising address type. */
uint8_t directAddrType;
/** Direct advertising address. */
uint8_t directAddr[6];
};
/**
* **Interrupt Service Routine** for :c:data:`EPIC_INT_BLE`
*
* :c:func:`epic_isr_ble` is called when the BLE stack wants to signal an
* event to the application. You can use :c:func:`epic_ble_get_event` to obtain
* the event which triggered this interrupt.
*
* Currently supported events:
*
* :c:data:`BLE_EVENT_HANDLE_NUMERIC_COMPARISON`:
* An ongoing pairing procedure requires a numeric comparison to complete.
* The compare value can be retreived using :c:func:`epic_ble_get_compare_value`.
*
* :c:data:`BLE_EVENT_PAIRING_FAILED`:
* A pairing procedure failed. The stack automatically went back advertising
* and accepting new pairings.
*
* :c:data:`BLE_EVENT_PAIRING_COMPLETE`:
* A pairing procedure has completed sucessfully.
* The stack automatically persists the pairing information, creating a bond.
*
* .. versionadded:: 1.16
*/
API_ISR(EPIC_INT_BLE, epic_isr_ble);
/**
* Retreive the event which triggered :c:func:`epic_isr_ble`
*
* .. versionadded:: 1.16
* .. versionchanged:: 1.17
*/
API(API_BLE_GET_EVENT, int epic_ble_get_event(struct epic_ble_event *e));
/**
* Retrieve the compare value of an ongoing pairing procedure.
*
* If no pairing procedure is ongoing, the returned value is undefined.
*
* :return: 6 digit long compare value
*
* .. versionadded:: 1.16
*/
API(API_BLE_GET_COMPARE_VALUE, uint32_t epic_ble_get_compare_value(void));
/**
* Retrieve the (file) name of the last pairing which was successful.
*
* :return: ``0`` on success or a negative value if an error occured. Possible
* errors:
*
* - ``-ENOENT``: There was no successful pairing yet.
*
* .. versionadded:: 1.16
*/
API(API_BLE_GET_LAST_PAIRING_NAME, int epic_ble_get_last_pairing_name(char *buf, size_t buf_size));
/**
* Retrieve the name of the peer to which we are connected
*
* The name might be empty if the peer device does not expose it or
* if it has not yet been read from it.
*
* :return: ``0`` on success or a negative value if an error occured. Possible
* errors:
*
* - ``-ENOENT``: There is no active connection at the moment.
*
* .. versionadded:: 1.16
*/
API(API_BLE_GET_PEER_DEVICE_NAME, int epic_ble_get_peer_device_name(char *buf, size_t buf_size));
/**
* Indicate wether the user confirmed the compare value.
*
* If a pariring procedure involving a compare value is ongoing and this
* function is called with confirmed set to ``true``, it will try to
* proceed and complete the pairing process. If called with ``false``, the
* pairing procedure will be aborted.
*
* :param bool confirmed: ``true`` if the user confirmed the compare value.
*
* .. versionadded:: 1.16
*/
API(API_BLE_COMPARE_RESPONSE, void epic_ble_compare_response(bool confirmed));
/**
* Set the desired mode of the BLE stack.
*
* There are three allowed modes:
*
* - Peripheral which is not bondable (bondable = ``false``, scanner = ``false``).
* - Peripheral which is bondable (bondable = ``true``, scanner = ``false``).
* - Observer which scans for advertisements (bondable = ``false``, scanner = ``true``).
*
* By default the card10 will not allow new bondings to be made. New
* bondings have to explicitly allowed by calling this function.
*
* While bondable the card10 will change its advertisements to
* indicate to scanning hosts that it is available for discovery.
*
* When scanning is active, :c:data:`BLE_EVENT_SCAN_REPORT` events will be sent
* and the scan reports can be fetched using :c:func:`epic_ble_get_scan_report`.
*
* When switching applications new bondings are automatically
* disallowed and scanning is stopped.
*
* :param bool bondable: ``true`` if new bondings should be allowed.
* :param bool scanner: ``true`` if scanning should be turned on.
*
* .. versionadded:: 1.16
*/
API(API_BLE_SET_MODE, void epic_ble_set_mode(bool bondable, bool scanner));
/**
* Retrieve a scan report from the queue of scan reports.
*
* :param struct\ epic_scan_report* rpt: Pointer where the report will be stored.
*
* :return: ``0`` on success or a negative value if an error occured. Possible
* errors:
*
* - ``-ENOENT``: No scan report available
*
*/
API(API_BLE_GET_SCAN_REPORT, int epic_ble_get_scan_report(struct epic_scan_report *rpt));
/**
* Send an input report to the host.
*
* :param uint8_t report_id: The id of the report to use. 1: keyboard, 2: mouse, 3: consumer control
* :param uint8_t* data: Data to be reported.
* :param uint8_t len: Length in bytes of the data to be reported. Maximum length is 8 bytes.
*
* :return: ``0`` on success, ``1`` if the report is queued or a negative value
* if an error occured. Possible errors:
*
* - ``-EIO``: There is no host device connected or BLE HID is not enabled.
* - ``-EAGAIN``: There is no space in the queue available. Try again later.
* - ``-EINVAL``: Either the report_id is out of range or the data is too long.
*
*/
API(API_BLE_HID_SEND_REPORT, int epic_ble_hid_send_report(uint8_t report_id, uint8_t *data, uint8_t len));
/**
* MicroPython BLE Support API
* ---------------------------
* The following API calls are to be used for MicroPython BLE support.
*
* .. warning::
*
* The following epic-calls are **not** part of the stable public API and
* thus **no** guarantee about stability or behavior is made. Do not use
* these outside of Pycardium unless you can live with sudden breakage!!
*
* They are only documented here for completeness and as a reference for
* firmware hackers, not for common usage.
*/
/** Private API call for Pycardium BLE support. */
API(API_BLE_INIT, int epic_ble_init(void));
/** Private API call for Pycardium BLE support. */
API(API_BLE_DEINIT, int epic_ble_deinit(void));
/** Private API call for Pycardium BLE support. */
API(API_BLE_ATTS_DYN_CREATE_GROUP, int epic_atts_dyn_create_service(const uint8_t *uuid, uint8_t uuid_len, uint16_t group_size, void **pSvcHandle));
//API(API_BLE_ATTS_DYN_DELETE_GROUP, void AttsDynDeleteGroup(void *pSvcHandle));
/** Private API call for Pycardium BLE support. */
API(API_BLE_ATTS_DYN_DELETE_GROUPS, int epic_ble_atts_dyn_delete_groups(void));
/** Private API call for Pycardium BLE support. */
API(API_BLE_ATTS_DYN_ADD_CHARACTERISTIC, int epic_atts_dyn_add_characteristic(void *pSvcHandle, const uint8_t *uuid, uint8_t uuid_len, uint8_t flags, uint16_t maxLen, uint16_t *value_handle));
/** Private API call for Pycardium BLE support. */
API(API_BLE_ATTS_DYN_ADD_DESCRIPTOR, int epic_ble_atts_dyn_add_descriptor(void *pSvcHandle, const uint8_t *uuid, uint8_t uuid_len, uint8_t flags, const uint8_t *value, uint16_t value_len, uint16_t maxLen, uint16_t *descriptor_handle));
/** Private API call for Pycardium BLE support. */
API(API_BLE_ATTS_SEND_SERVICE_CHANGED_IND, int epic_atts_dyn_send_service_changed_ind(void));
/** Private API call for Pycardium BLE support. */
API(API_BLE_ATTS_SET_ATTR, int epic_ble_atts_set_attr(uint16_t handle, const uint8_t *value, uint16_t value_len));
/** Private API call for Pycardium BLE support. */
API(API_BLE_ATTS_HANDLE_VALUE_NTF, int epic_ble_atts_handle_value_ntf(uint8_t connId, uint16_t handle, uint16_t valueLen, uint8_t *pValue));
/** Private API call for Pycardium BLE support. */
API(API_BLE_ATTS_HANDLE_VALUE_IND, int epic_ble_atts_handle_value_ind(uint8_t connId, uint16_t handle, uint16_t valueLen, uint8_t *pValue));
/** Private API call for Pycardium BLE support. */
API(API_BLE_ATTS_SET_BUFFER, int epic_ble_atts_set_buffer(uint16_t value_handle, size_t len, bool append));
/** Private API call for Pycardium BLE support. */
API(API_BLE_FREE_EVENT, int epic_ble_free_event(struct epic_ble_event *e));
/** Private API call for Pycardium BLE support. */
API(API_BLE_CLOSE_CONNECTION, void epic_ble_close_connection(uint8_t connId));
/** Private API call for Pycardium BLE support. */
API(API_BLE_IS_CONNECTION_OPEN, int epic_ble_is_connection_open(void));
/** Private API call for Pycardium BLE support. */
API(API_BLE_SET_DEVICE_NAME, int epic_ble_set_device_name(const uint8_t *buf, uint16_t len));
/** Private API call for Pycardium BLE support. */
API(API_BLE_GET_DEVICE_NAME, int epic_ble_get_device_name(uint8_t **buf, uint16_t *len));
/** Private API call for Pycardium BLE support. */
API(API_BLE_GET_ADDRESS, void epic_ble_get_address(uint8_t *addr));
/** Private API call for Pycardium BLE support. */
API(API_BLE_ADVERTISE, int epic_ble_advertise(int interval_us, const uint8_t *adv_data, size_t adv_data_len, const uint8_t *sr_data, size_t sr_data_len, bool connectable));
/** Private API call for Pycardium BLE support. */
API(API_BLE_ADVERTISE_STOP, int epic_ble_advertise_stop(void));
/** Private API call for Pycardium BLE support. */
API(API_BLE_DISCOVER_PRIMARY_SERVICES, int epic_ble_attc_discover_primary_services(uint8_t connId, const uint8_t *uuid, uint8_t uuid_len));
/** Private API call for Pycardium BLE support. */
API(API_BLE_DISCOVER_CHARACTERISTICS, int epic_ble_attc_discover_characteristics(uint8_t connId, uint16_t start_handle, uint16_t end_handle));
/** Private API call for Pycardium BLE support. */
API(API_BLE_DISCOVER_DESCRIPTORS, int epic_ble_attc_discover_descriptors(uint8_t connId, uint16_t start_handle, uint16_t end_handle));
/** Private API call for Pycardium BLE support. */
API(API_BLE_ATTC_READ, int epic_ble_attc_read(uint8_t connId, uint16_t value_handle));
/** Private API call for Pycardium BLE support. */
API(API_BLE_ATTC_WRITE_NO_RSP, int epic_ble_attc_write_no_rsp(uint8_t connId, uint16_t value_handle, const uint8_t *value, uint16_t value_len));
/** Private API call for Pycardium BLE support. */
API(API_BLE_ATTC_WRITE, int epic_ble_attc_write(uint8_t connId, uint16_t value_handle, const uint8_t *value, uint16_t value_len));
#endif /* _EPICARDIUM_H */ #endif /* _EPICARDIUM_H */
...@@ -29,6 +29,17 @@ int epic_file_open(const char *filename, const char *mode) ...@@ -29,6 +29,17 @@ int epic_file_open(const char *filename, const char *mode)
return res; return res;
} }
bool epic_fs_is_attached(void)
{
EpicFileSystem *fs;
if (efs_lock_global(&fs) == 0) {
efs_unlock_global(fs);
return true;
} else {
return false;
}
}
int epic_file_close(int fd) int epic_file_close(int fd)
{ {
EpicFileSystem *fs; EpicFileSystem *fs;
......
...@@ -19,13 +19,14 @@ ...@@ -19,13 +19,14 @@
#include <timers.h> #include <timers.h>
#include "fs/internal.h" #include "fs/internal.h"
#include "modules/filesystem.h" #include "fs/filesystem.h"
#include "user_core/user_core.h"
#include "epicardium.h" #include "epicardium.h"
#include "card10.h" #include "card10.h"
#include "modules/log.h" #include "os/core.h"
#include "modules/modules.h" #include "modules/modules.h"
#include "api/common.h" #include "api/common.h"
#include "modules/mutex.h" #include "os/mutex.h"
#define SSLOG_DEBUG(...) LOG_DEBUG("fatfs", __VA_ARGS__) #define SSLOG_DEBUG(...) LOG_DEBUG("fatfs", __VA_ARGS__)
#define SSLOG_INFO(...) LOG_INFO("fatfs", __VA_ARGS__) #define SSLOG_INFO(...) LOG_INFO("fatfs", __VA_ARGS__)
...@@ -285,6 +286,7 @@ efs_get_new(EpicFileSystem *fs, uint32_t *idx, struct FatObject **obj, int *rc) ...@@ -285,6 +286,7 @@ efs_get_new(EpicFileSystem *fs, uint32_t *idx, struct FatObject **obj, int *rc)
} }
*obj = &fs->pool[index]; *obj = &fs->pool[index];
*idx = index;
return true; return true;
} }
......
#include "fs_util.h"
#include "epicardium.h"
#include <stdint.h>
#include <string.h>
int fs_read_file(char *filename, void *data, int len)
{
int fd = epic_file_open(filename, "r");
if (fd < 0) {
return fd;
}
int res = epic_file_read(fd, data, len);
epic_file_close(fd);
return res;
}
int fs_read_text_file(char *filename, char *data, int len)
{
int readbytes;
if (len < 1)
return -1;
readbytes = fs_read_file(filename, data, len - 1);
if (readbytes < 0) {
data[0] = 0;
return readbytes;
};
data[readbytes] = 0;
while (readbytes > 0 && data[readbytes - 1] < 0x20) {
data[--readbytes] = 0;
};
return readbytes;
}
int fs_write_file(char *filename, const void *data, int len)
{
int fd = epic_file_open(filename, "w");
if (fd < 0) {
return fd;
}
int res = epic_file_write(fd, data, len);
epic_file_close(fd);
return res;
}
int fs_get_file_size(char *filename)
{
struct epic_stat stat;
int res = epic_file_stat(filename, &stat);
return res < 0 ? res : (int)stat.size;
}
#if 0
#include "ff.h"
FATFS FatFs; /* File system object for logical drive */
FS_USAGE FsUsage;
/* TODO: Port functions from r0ket/rad10 libs */
int fs_info(FATFS *fs)
{
memcpy(fs, &FatFs, sizeof(FATFS));
return 0;
}
int fs_usage(FATFS *fs, FS_USAGE *fs_usage)
{
FRESULT res;
DWORD tot_clust, fre_clust, sec_size;
res = f_getfree("/", &fre_clust, &fs);
if(res != FR_OK)
return -res;
// sectore size = sectors per cluster * sector size
#if FF_MAX_SS == FF_MIN_SS
sec_size = fs->csize * FF_MAX_SS;
#else
sec_size = fs->csize * fs.ssize;
#endif
// total/free sectors * sectore size
tot_clust = fs->n_fatent - 2;
fs_usage->total = tot_clust * sec_size; //FatFs.ssize;
fs_usage->free = fre_clust * sec_size; //FatFs.ssize;
return 0;
}
#endif
File moved
fs_sources = files(
'fileops.c',
'filesystem_fat.c',
'fs_util.c',
)
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
#include "epicardium.h" #include "epicardium.h"
#include "l0der/elf.h" #include "l0der/elf.h"
#include "modules/log.h" #include "os/core.h"
/* /*
* l0der is, in reality, a boneless operating-system style ELF loader. * l0der is, in reality, a boneless operating-system style ELF loader.
...@@ -119,7 +119,7 @@ static int _seek_and_read(int fd, uint32_t address, void *data, size_t count) ...@@ -119,7 +119,7 @@ static int _seek_and_read(int fd, uint32_t address, void *data, size_t count)
return res; return res;
} }
if ((res = epic_file_read(fd, data, count)) != count) { if ((size_t)(res = epic_file_read(fd, data, count)) != count) {
LOG_ERR("l0der", "_seek_and_read: could not read: %d", res); LOG_ERR("l0der", "_seek_and_read: could not read: %d", res);
return res; return res;
} }
...@@ -149,7 +149,7 @@ static int _read_section_header(int fd, uint32_t shdr_addr, Elf32_Shdr *shdr) ...@@ -149,7 +149,7 @@ static int _read_section_header(int fd, uint32_t shdr_addr, Elf32_Shdr *shdr)
* This function ensures basic memory sanity of a program header / segment. * This function ensures basic memory sanity of a program header / segment.
* It ensures that it points to a file region that is contained within the file fully. * It ensures that it points to a file region that is contained within the file fully.
*/ */
static int _check_program_header(int fd, int size, Elf32_Phdr *phdr) static int _check_program_header(int fd, size_t size, Elf32_Phdr *phdr)
{ {
// Check file size/offset. // Check file size/offset.
uint32_t file_start = phdr->p_offset; uint32_t file_start = phdr->p_offset;
...@@ -191,7 +191,7 @@ static int _check_program_header(int fd, int size, Elf32_Phdr *phdr) ...@@ -191,7 +191,7 @@ static int _check_program_header(int fd, int size, Elf32_Phdr *phdr)
* This function ensures basic memory sanity of a section header. * This function ensures basic memory sanity of a section header.
* It ensures that it points to a file region that is contained within the file fully. * It ensures that it points to a file region that is contained within the file fully.
*/ */
static int _check_section_header(int fd, int size, Elf32_Shdr *shdr) static int _check_section_header(int fd, size_t size, Elf32_Shdr *shdr)
{ {
// Check file size/offset. // Check file size/offset.
uint32_t file_start = shdr->sh_offset; uint32_t file_start = shdr->sh_offset;
...@@ -329,7 +329,7 @@ static int _load_segment(int fd, struct _pie_load_info *li, Elf32_Phdr *phdr) ...@@ -329,7 +329,7 @@ static int _load_segment(int fd, struct _pie_load_info *li, Elf32_Phdr *phdr)
* Parse dynamic symbol sections. * Parse dynamic symbol sections.
*/ */
static int _parse_dynamic_symbols( static int _parse_dynamic_symbols(
int fd, int size, struct _pie_load_info *li, Elf32_Ehdr *hdr int fd, size_t size, struct _pie_load_info *li, Elf32_Ehdr *hdr
) { ) {
int res; int res;
Elf32_Shdr shdr; Elf32_Shdr shdr;
...@@ -366,7 +366,7 @@ static int _parse_dynamic_symbols( ...@@ -366,7 +366,7 @@ static int _parse_dynamic_symbols(
return res; return res;
} }
for (int j = 0; j < sym_count; j++) { for (uint32_t j = 0; j < sym_count; j++) {
if ((res = epic_file_read( if ((res = epic_file_read(
fd, &sym, sizeof(Elf32_Sym))) != fd, &sym, sizeof(Elf32_Sym))) !=
sizeof(Elf32_Sym)) { sizeof(Elf32_Sym)) {
...@@ -402,9 +402,9 @@ static int _parse_dynamic_symbols( ...@@ -402,9 +402,9 @@ static int _parse_dynamic_symbols(
* the only one used when making 'standard' PIE binaries on RAM. However, other * the only one used when making 'standard' PIE binaries on RAM. However, other
* kinds might have to be implemented in the future. * kinds might have to be implemented in the future.
*/ */
static int static int _run_relocations(
_run_relocations(int fd, int size, struct _pie_load_info *li, Elf32_Ehdr *hdr) int fd, size_t size, struct _pie_load_info *li, Elf32_Ehdr *hdr
{ ) {
int res; int res;
Elf32_Shdr shdr; Elf32_Shdr shdr;
Elf32_Rel rel; Elf32_Rel rel;
...@@ -447,7 +447,7 @@ _run_relocations(int fd, int size, struct _pie_load_info *li, Elf32_Ehdr *hdr) ...@@ -447,7 +447,7 @@ _run_relocations(int fd, int size, struct _pie_load_info *li, Elf32_Ehdr *hdr)
return res; return res;
} }
for (int j = 0; j < reloc_count; j++) { for (uint32_t j = 0; j < reloc_count; j++) {
if ((res = epic_file_read( if ((res = epic_file_read(
fd, &rel, sizeof(Elf32_Rel))) != fd, &rel, sizeof(Elf32_Rel))) !=
sizeof(Elf32_Rel)) { sizeof(Elf32_Rel)) {
...@@ -464,7 +464,7 @@ _run_relocations(int fd, int size, struct _pie_load_info *li, Elf32_Ehdr *hdr) ...@@ -464,7 +464,7 @@ _run_relocations(int fd, int size, struct _pie_load_info *li, Elf32_Ehdr *hdr)
// (ie., do not resolve relocation - they default to a safe NULL) // (ie., do not resolve relocation - they default to a safe NULL)
uint8_t skip = 0; uint8_t skip = 0;
if (sym != 0) { if (sym != 0) {
for (int k = 0; k < li->weak_symbol_count; for (uint32_t k = 0; k < li->weak_symbol_count;
k++) { k++) {
if (li->weak_symbols[k] == sym) { if (li->weak_symbols[k] == sym) {
skip = 1; skip = 1;
...@@ -513,7 +513,7 @@ _run_relocations(int fd, int size, struct _pie_load_info *li, Elf32_Ehdr *hdr) ...@@ -513,7 +513,7 @@ _run_relocations(int fd, int size, struct _pie_load_info *li, Elf32_Ehdr *hdr)
* Load a l0dable PIE binary. * Load a l0dable PIE binary.
*/ */
static int static int
_load_pie(int fd, int size, Elf32_Ehdr *hdr, struct l0dable_info *info) _load_pie(int fd, size_t size, Elf32_Ehdr *hdr, struct l0dable_info *info)
{ {
int res; int res;
struct _pie_load_info li = { 0 }; struct _pie_load_info li = { 0 };
...@@ -647,7 +647,10 @@ int l0der_load_path(const char *path, struct l0dable_info *info) ...@@ -647,7 +647,10 @@ int l0der_load_path(const char *path, struct l0dable_info *info)
return res; return res;
} }
int size = epic_file_tell(fd); if ((res = epic_file_tell(fd)) < 0) {
return res;
}
size_t size = res;
if ((res = epic_file_seek(fd, 0, SEEK_SET)) != 0) { if ((res = epic_file_seek(fd, 0, SEEK_SET)) != 0) {
return res; return res;
......
#include "modules/modules.h" #include "modules/modules.h"
#include "modules/log.h" #include "os/core.h"
#include "modules/filesystem.h" #include "os/work_queue.h"
#include "modules/config.h" #include "fs/filesystem.h"
#include "drivers/drivers.h"
#include "user_core/user_core.h"
#include "os/config.h"
#include "card10-version.h" #include "card10-version.h"
#include "user_core/interrupts.h"
#include "drivers/display/epic_ctx.h"
#include "gfx.h"
#include "display.h"
#include "leds.h" #include "leds.h"
#include "version-splash.h" #include "version-splash.h"
...@@ -15,6 +18,9 @@ ...@@ -15,6 +18,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <machine/endian.h>
#include "epic_boot.c"
int main(void) int main(void)
{ {
...@@ -28,45 +34,73 @@ int main(void) ...@@ -28,45 +34,73 @@ int main(void)
load_config(); load_config();
/* migration_delete_app_launchers();
* Version Splash
*/
const char *version_buf = CARD10_VERSION;
//LED feedback in case of dead display //LED feedback in case of dead display
epic_leds_set(11, 0, 0, 1); epic_leds_set(11, 0, 0, 1);
epic_leds_set(12, 0, 0, 1); epic_leds_set(12, 0, 0, 1);
epic_leds_set(13, 0, 0, 1); epic_leds_set(13, 0, 0, 1);
epic_leds_set(14, 0, 0, 1); epic_leds_set(14, 0, 0, 1);
for (int i = 0; i < 3; i++) {
epic_leds_set_rocket(i, 31);
mxc_delay(166666);
epic_leds_set_rocket(i, 0);
}
epic_leds_clear_all(0, 0, 0);
epic_disp_clear(0x0000); epic_disp_clear(0x0000);
if (strcmp(CARD10_VERSION, "v1.12") == 0) { #if 0 /* reenable for future releases */
gfx_copy_region( epic_leds_set_rocket(0, 31);
&display_screen, epic_leds_set_rocket(1, 31);
0, epic_leds_set_rocket(2, 31);
0,
160, // TODO: Use blit function here
80, #if BYTE_ORDER == LITTLE_ENDIAN
GFX_RAW, for (size_t i = 0; i < sizeof(epicardium_ctx_fb); i += 2) {
sizeof(version_splash), epicardium_ctx_fb[i] = version_splash[i + 1];
version_splash epicardium_ctx_fb[i + 1] = version_splash[i];
); }
} else { #else
const int off = (160 - (int)strlen(version_buf) * 14) / 2; memcpy(epicardium_ctx_fb, version_splash, sizeof(epicardium_ctx_fb));
epic_disp_print(10, 20, "Epicardium", 0xfe20, 0x0000); #endif
epic_disp_print(
off > 0 ? off : 0, 40, version_buf, 0xfe20, 0x0000 if (strcmp(CARD10_VERSION, "v1.17") != 0) {
); ctx_font_size(epicardium_ctx, 20.0f);
ctx_text_baseline(epicardium_ctx, CTX_TEXT_BASELINE_BOTTOM);
ctx_rgba8(epicardium_ctx, 0xff, 0xc6, 0x00, 0xff);
ctx_text_align(epicardium_ctx, CTX_TEXT_ALIGN_CENTER);
ctx_move_to(epicardium_ctx, 80.0f, 58.0f);
ctx_text(epicardium_ctx, "Epicardium");
ctx_text_align(epicardium_ctx, CTX_TEXT_ALIGN_LEFT);
ctx_move_to(epicardium_ctx, 2.0f, 78.0f);
ctx_text(epicardium_ctx, CARD10_VERSION);
/* re-init for the first app */
disp_ctx_reinit();
} }
epic_disp_update(); epic_disp_update();
mxc_delay(2000000); mxc_delay(2000000);
#else
for (uint32_t frame = 0; frame < 15; frame++) {
switch (frame) {
case 0:
epic_leds_set_rocket(0, 31);
break;
case 5:
epic_leds_set_rocket(1, 31);
break;
case 10:
epic_leds_set_rocket(2, 31);
break;
}
epic_disp_clear(0x0000);
epic_frame(epicardium_ctx, frame);
epic_disp_update();
}
/* re-init for the first app */
disp_ctx_reinit();
#endif
epic_leds_clear_all(0, 0, 0);
LOG_DEBUG("startup", "Initializing tasks ..."); LOG_DEBUG("startup", "Initializing tasks ...");
...@@ -85,7 +119,7 @@ int main(void) ...@@ -85,7 +119,7 @@ int main(void)
if (xTaskCreate( if (xTaskCreate(
vPmicTask, vPmicTask,
(const char *)"PMIC", (const char *)"PMIC",
configMINIMAL_STACK_SIZE, configMINIMAL_STACK_SIZE * 3,
NULL, NULL,
tskIDLE_PRIORITY + 4, tskIDLE_PRIORITY + 4,
NULL) != pdPASS) { NULL) != pdPASS) {
...@@ -113,6 +147,34 @@ int main(void) ...@@ -113,6 +147,34 @@ int main(void)
NULL) != pdPASS) { NULL) != pdPASS) {
panic("Failed to create %s task!", "MAX30001"); panic("Failed to create %s task!", "MAX30001");
} }
/* MAX86150 */
if (xTaskCreate(
vMAX86150Task,
(const char *)"MAX86150 Driver",
configMINIMAL_STACK_SIZE * 2,
NULL,
tskIDLE_PRIORITY + 1,
NULL) != pdPASS) {
panic("Failed to create %s task!", "MAX86150");
}
/* BSEC */
if (bsec_activate() == 0) {
if (xTaskCreate(
vBSECTask,
(const char *)"BSEC",
configMINIMAL_STACK_SIZE * 5,
NULL,
tskIDLE_PRIORITY + 1,
NULL) != pdPASS) {
LOG_CRIT(
"startup", "Failed to create %s task!", "BSEC"
);
abort();
}
}
/* API */ /* API */
if (xTaskCreate( if (xTaskCreate(
vApiDispatcher, vApiDispatcher,
...@@ -123,9 +185,19 @@ int main(void) ...@@ -123,9 +185,19 @@ int main(void)
&dispatcher_task_id) != pdPASS) { &dispatcher_task_id) != pdPASS) {
panic("Failed to create %s task!", "API Dispatcher"); panic("Failed to create %s task!", "API Dispatcher");
} }
/* Interrupts */
if (xTaskCreate(
vInterruptsTask,
(const char *)"Interrupt Dispatcher",
configMINIMAL_STACK_SIZE,
NULL,
tskIDLE_PRIORITY + 2,
NULL) != pdPASS) {
panic("Failed to create %s task!", "Interrupt Dispatcher");
}
/* BLE */ /* BLE */
if (ble_shall_start()) { if (ble_is_enabled()) {
if (xTaskCreate( if (xTaskCreate(
vBleTask, vBleTask,
(const char *)"BLE", (const char *)"BLE",
...@@ -137,17 +209,6 @@ int main(void) ...@@ -137,17 +209,6 @@ int main(void)
} }
} }
/* LEDs */
if (xTaskCreate(
vLedTask,
(const char *)"LED",
configMINIMAL_STACK_SIZE,
NULL,
tskIDLE_PRIORITY + 1,
NULL) != pdPASS) {
panic("Failed to create %s task!", "LED");
}
/* Lifecycle */ /* Lifecycle */
if (xTaskCreate( if (xTaskCreate(
vLifecycleTask, vLifecycleTask,
...@@ -159,6 +220,18 @@ int main(void) ...@@ -159,6 +220,18 @@ int main(void)
panic("Failed to create %s task!", "Lifecycle"); panic("Failed to create %s task!", "Lifecycle");
} }
/* Work Queue */
if (xTaskCreate(
vWorkQueueTask,
(const char *)"Work Queue",
configMINIMAL_STACK_SIZE * 4,
NULL,
tskIDLE_PRIORITY + 1,
NULL) != pdPASS) {
panic("Failed to create %s task!", "Work Queue");
}
workqueue_init();
/* /*
* Initialize serial driver data structures. * Initialize serial driver data structures.
*/ */
......
...@@ -66,7 +66,11 @@ freertos = static_library( ...@@ -66,7 +66,11 @@ freertos = static_library(
########################################################################## ##########################################################################
subdir('modules/') subdir('modules/')
subdir('drivers/')
subdir('user_core/')
subdir('ble/') subdir('ble/')
subdir('os/')
subdir('fs/')
subdir('l0der/') subdir('l0der/')
...@@ -77,6 +81,17 @@ if get_option('jailbreak_card10') ...@@ -77,6 +81,17 @@ if get_option('jailbreak_card10')
] ]
endif endif
version_screen = custom_target(
'version-splash.h',
input: 'version-splash.png',
output: 'version-splash.h',
command: [
python3,
meson.current_source_dir() + '../tools/version-image.py',
'@INPUT@',
'@OUTPUT@',
],
)
elf = executable( elf = executable(
name + '.elf', name + '.elf',
...@@ -85,12 +100,16 @@ elf = executable( ...@@ -85,12 +100,16 @@ elf = executable(
'usb/mass_storage.c', 'usb/mass_storage.c',
'main.c', 'main.c',
'support.c', 'support.c',
'fs/filesystem_fat.c',
module_sources, module_sources,
os_sources,
user_core_sources,
driver_sources,
fs_sources,
l0der_sources, l0der_sources,
ble_sources, ble_sources,
version_hdr, version_hdr,
dependencies: [libcard10, max32665_startup_core0, maxusb, libff13, ble, bhy1], version_screen,
dependencies: [libcard10, max32665_startup_core0, maxusb, libff13, ble, bhy1, libcrypto, bsec, libctx],
link_with: [api_dispatcher_lib, freertos], link_with: [api_dispatcher_lib, freertos],
link_whole: [max32665_startup_core0_lib, board_card10_lib, newlib_heap_lib], link_whole: [max32665_startup_core0_lib, board_card10_lib, newlib_heap_lib],
include_directories: [freertos_includes], include_directories: [freertos_includes],
......