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
  • add_menu_vibration
  • blinkisync-as-preload
  • ch3/api-speed-eval2
  • ch3/dual-core
  • ch3/genapi-refactor
  • ch3/leds-api
  • ch3/splashscreen
  • dualcore
  • dx/flatten-config-module
  • dx/meh-bdf-to-stm
  • freertos-btle
  • genofire/ble-follow-py
  • koalo/bhi160-works-but-dirty
  • koalo/factory-reset
  • koalo/wip/i2c-for-python
  • master
  • msgctl/faultscreen
  • msgctl/textbuffer_api
  • plaetzchen/ios-workaround
  • rahix/bhi
  • rahix/bluetooth-app-favorite
  • rahix/bma
  • rahix/user-space-ctx
  • renze/hatchery_apps
  • renze/safe_mode
  • schleicher-test
  • schneider/212-reset-hardware-when-entering-repl
  • schneider/ancs
  • schneider/ble-buffers
  • schneider/ble-central
  • schneider/ble-ecg-stream-visu
  • schneider/ble-fixes-2020-3
  • schneider/ble-mini-demo
  • schneider/ble-stability
  • schneider/ble-stability-new-phy
  • schneider/bonding
  • schneider/bonding-fail-if-full
  • schneider/bootloader-update-9a0d158
  • schneider/deepsleep
  • schneider/deepsleep2
  • schneider/deepsleep4
  • schneider/default-main
  • schneider/freertos-list-debug
  • schneider/fundamental-test
  • schneider/iaq-python
  • schneider/ir
  • schneider/max30001
  • schneider/max30001-epicaridum
  • schneider/max30001-pycardium
  • schneider/maxim-sdk-update
  • schneider/mp-exception-print
  • schneider/mp-for-old-bl
  • schneider/png
  • schneider/schleicher-test
  • schneider/sdk-0.2.1-11
  • schneider/sdk-0.2.1-7
  • schneider/sleep-display
  • schneider/spo2-playground
  • schneider/stream-locks
  • schneider/v1.17-changelog
  • bootloader-v1
  • release-1
  • v0.0
  • v1.0
  • v1.1
  • v1.10
  • v1.11
  • v1.12
  • v1.13
  • v1.14
  • v1.15
  • v1.16
  • v1.17
  • v1.18
  • v1.2
  • v1.3
  • v1.4
  • v1.5
  • v1.6
  • v1.7
  • v1.8
  • v1.9
82 results

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
  • blinkisync-as-preload
  • ch3/api-speed-eval2
  • ch3/dual-core
  • ch3/genapi-refactor
  • ch3/leds-api
  • ch3/splashscreen
  • drawcall_clipping
  • dualcore
  • faulty_unsigned_comparisons
  • freertos-btle
  • fuchsi-ecg-app
  • genofire/ble-follow-py
  • genofire/haule-ble-fs-deactive
  • genofire/leds_rgb_get_state
  • genofire/rockets-state
  • gpio_in_adc_fix
  • ios-workarounds
  • koalo/bhi160-works-but-dirty
  • koalo/factory-reset
  • koalo/wip/i2c-for-python
  • master
  • msgctl/faultscreen
  • msgctl/gfx_rle
  • msgctl/textbuffer_api
  • plaetzchen/ios-workaround
  • rahix/bhi
  • rahix/bma
  • renze/hatchery_apps
  • renze/safe_mode
  • schleicher-test
  • schneider/ble-buffers
  • schneider/bonding
  • schneider/bootloader-update-9a0d158
  • schneider/bsec
  • schneider/fundamental-test
  • schneider/max30001
  • schneider/max30001-epicaridum
  • schneider/max30001-pycardium
  • schneider/maxim-sdk-update
  • schneider/mp-for-old-bl
  • schneider/schleicher-test
  • schneider/stream-locks
  • bootloader-v1
  • release-1
  • v0.0
  • v1.0
  • v1.1
  • v1.2
  • v1.3
  • v1.4
  • v1.5
  • v1.6
  • v1.7
  • v1.8
  • v1.9
55 results
Show changes
Showing
with 838 additions and 947 deletions
fs_sources = files(
'fileops.c',
'filesystem_fat.c',
'fs_util.c',
)
......@@ -6,7 +6,7 @@
#include "epicardium.h"
#include "l0der/elf.h"
#include "modules/log.h"
#include "os/core.h"
/*
* 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)
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);
return res;
}
......@@ -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.
* 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.
uint32_t file_start = phdr->p_offset;
......@@ -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.
* 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.
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)
* Parse dynamic symbol sections.
*/
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;
Elf32_Shdr shdr;
......@@ -366,7 +366,7 @@ static int _parse_dynamic_symbols(
return res;
}
for (int j = 0; j < sym_count; j++) {
for (uint32_t j = 0; j < sym_count; j++) {
if ((res = epic_file_read(
fd, &sym, sizeof(Elf32_Sym))) !=
sizeof(Elf32_Sym)) {
......@@ -402,9 +402,9 @@ static int _parse_dynamic_symbols(
* the only one used when making 'standard' PIE binaries on RAM. However, other
* kinds might have to be implemented in the future.
*/
static int
_run_relocations(int fd, int size, struct _pie_load_info *li, Elf32_Ehdr *hdr)
{
static int _run_relocations(
int fd, size_t size, struct _pie_load_info *li, Elf32_Ehdr *hdr
) {
int res;
Elf32_Shdr shdr;
Elf32_Rel rel;
......@@ -447,7 +447,7 @@ _run_relocations(int fd, int size, struct _pie_load_info *li, Elf32_Ehdr *hdr)
return res;
}
for (int j = 0; j < reloc_count; j++) {
for (uint32_t j = 0; j < reloc_count; j++) {
if ((res = epic_file_read(
fd, &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)
// (ie., do not resolve relocation - they default to a safe NULL)
uint8_t skip = 0;
if (sym != 0) {
for (int k = 0; k < li->weak_symbol_count;
for (uint32_t k = 0; k < li->weak_symbol_count;
k++) {
if (li->weak_symbols[k] == sym) {
skip = 1;
......@@ -513,7 +513,7 @@ _run_relocations(int fd, int size, struct _pie_load_info *li, Elf32_Ehdr *hdr)
* Load a l0dable PIE binary.
*/
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;
struct _pie_load_info li = { 0 };
......@@ -545,7 +545,8 @@ _load_pie(int fd, int size, Elf32_Ehdr *hdr, struct l0dable_info *info)
if (phdr.p_type == PT_LOAD) {
// Check alignment request.
if ((phdr.p_vaddr % phdr.p_align) != 0) {
if ((phdr.p_offset % phdr.p_align) !=
(phdr.p_vaddr % phdr.p_align)) {
LOG_ERR("l0der",
"_load_pie: phdr %d alignment too strict",
i);
......@@ -646,7 +647,10 @@ int l0der_load_path(const char *path, struct l0dable_info *info)
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) {
return res;
......
#include <stdio.h>
#include <stdlib.h>
#include <ff.h>
#include "max32665.h"
#include "uart.h"
#include "cdcacm.h"
#include "card10.h"
#include "pmic.h"
#include "leds.h"
#include "api/dispatcher.h"
#include "l0der/l0der.h"
#include "modules/modules.h"
#include "modules/log.h"
#include "modules/stream.h"
#include "modules/filesystem.h"
#include "api/interrupt-sender.h"
#include "Heart.h"
#include "gfx.h"
#include "display.h"
#include "os/core.h"
#include "os/work_queue.h"
#include "fs/filesystem.h"
#include "drivers/drivers.h"
#include "user_core/user_core.h"
#include "os/config.h"
#include "card10-version.h"
#include "user_core/interrupts.h"
#include "drivers/display/epic_ctx.h"
#include "leds.h"
#include "version-splash.h"
#include "FreeRTOS.h"
#include "task.h"
#include "mxc_delay.h"
TaskHandle_t dispatcher_task_id;
#include <stdlib.h>
#include <string.h>
#include <machine/endian.h>
void vBleTask(void *pvParameters);
/*
* API dispatcher task. This task will sleep until an API call is issued and
* then wake up to dispatch it.
*/
void vApiDispatcher(void *pvParameters)
{
LOG_DEBUG("dispatcher", "Ready.");
while (1) {
if (api_dispatcher_poll()) {
api_dispatcher_exec();
}
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
}
}
#include "epic_boot.c"
int main(void)
{
watchdog_init();
LOG_INFO("startup", "Epicardium startup ...");
LOG_INFO("startup", "Version " CARD10_VERSION);
card10_init();
card10_diag();
LOG_DEBUG("startup", "Initializing hardware ...");
hardware_early_init();
gfx_copy_region_raw(
&display_screen, 0, 0, 160, 80, 2, (const void *)(Heart)
);
gfx_update(&display_screen);
load_config();
migration_delete_app_launchers();
//LED feedback in case of dead display
epic_leds_set(11, 0, 0, 1);
epic_leds_set(12, 0, 0, 1);
epic_leds_set(13, 0, 0, 1);
epic_leds_set(14, 0, 0, 1);
epic_disp_clear(0x0000);
#if 0 /* reenable for future releases */
epic_leds_set_rocket(0, 31);
epic_leds_set_rocket(1, 31);
epic_leds_set_rocket(2, 31);
/* TODO: Move this to its own function */
SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
// TODO: Use blit function here
#if BYTE_ORDER == LITTLE_ENDIAN
for (size_t i = 0; i < sizeof(epicardium_ctx_fb); i += 2) {
epicardium_ctx_fb[i] = version_splash[i + 1];
epicardium_ctx_fb[i + 1] = version_splash[i];
}
#else
memcpy(epicardium_ctx_fb, version_splash, sizeof(epicardium_ctx_fb));
#endif
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");
if (cdcacm_init() < 0) {
LOG_ERR("startup", "USB-Serial unavailable");
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();
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;
}
fatfs_init();
api_interrupt_init();
stream_init();
epic_disp_clear(0x0000);
epic_frame(epicardium_ctx, frame);
epic_disp_update();
}
LOG_INFO("startup", "Initializing tasks ...");
/* re-init for the first app */
disp_ctx_reinit();
#endif
epic_leds_clear_all(0, 0, 0);
LOG_DEBUG("startup", "Initializing tasks ...");
/* Serial */
if (xTaskCreate(
vSerialTask,
(const char *)"Serial",
configMINIMAL_STACK_SIZE,
configMINIMAL_STACK_SIZE * 2,
NULL,
tskIDLE_PRIORITY + 1,
tskIDLE_PRIORITY + 3,
NULL) != pdPASS) {
LOG_CRIT("startup", "Failed to create %s task!", "Serial");
abort();
panic("Failed to create %s task!", "Serial");
}
/* PMIC */
if (xTaskCreate(
vPmicTask,
(const char *)"PMIC",
configMINIMAL_STACK_SIZE,
configMINIMAL_STACK_SIZE * 3,
NULL,
tskIDLE_PRIORITY + 4,
NULL) != pdPASS) {
panic("Failed to create %s task!", "PMIC");
}
/* BHI160 */
if (xTaskCreate(
vBhi160Task,
(const char *)"BHI160 Driver",
configMINIMAL_STACK_SIZE * 2,
NULL,
tskIDLE_PRIORITY + 1,
NULL) != pdPASS) {
panic("Failed to create %s task!", "BHI160");
}
/* MAX30001 */
if (xTaskCreate(
vMAX30001Task,
(const char *)"MAX30001 Driver",
configMINIMAL_STACK_SIZE * 2,
NULL,
tskIDLE_PRIORITY + 1,
NULL) != pdPASS) {
LOG_CRIT("startup", "Failed to create %s task!", "PMIC");
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 */
if (xTaskCreate(
......@@ -103,58 +183,62 @@ int main(void)
NULL,
tskIDLE_PRIORITY + 2,
&dispatcher_task_id) != pdPASS) {
LOG_CRIT(
"startup",
"Failed to create %s task!",
"API Dispatcher"
);
abort();
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 */
if (ble_is_enabled()) {
if (xTaskCreate(
vBleTask,
(const char *)"BLE",
configMINIMAL_STACK_SIZE * 10,
NULL,
tskIDLE_PRIORITY + 1,
tskIDLE_PRIORITY + 3,
NULL) != pdPASS) {
LOG_CRIT("startup", "Failed to create %s task!", "BLE");
abort();
panic("Failed to create %s task!", "BLE");
}
}
LOG_INFO("startup", "Initializing dispatcher ...");
api_dispatcher_init();
/* Lifecycle */
if (xTaskCreate(
vLifecycleTask,
(const char *)"Lifecycle",
configMINIMAL_STACK_SIZE * 4,
NULL,
tskIDLE_PRIORITY + 3,
NULL) != pdPASS) {
panic("Failed to create %s task!", "Lifecycle");
}
/* light sensor */
LOG_INFO("startup", "starting light sensor ...");
epic_light_sensor_run();
/* 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();
/*
* See if there's a l0dable.elf to run. If not, run pycardium.
* This is temporary until epicardium gets a l0dable API from pycardium.
* Initialize serial driver data structures.
*/
const char *l0dable = "l0dable.elf";
if (f_stat(l0dable, NULL) == FR_OK) {
LOG_INFO("startup", "Running %s ...", l0dable);
struct l0dable_info info;
int res = l0der_load_path(l0dable, &info);
if (res != 0) {
LOG_ERR("startup", "l0der failed: %d\n", res);
} else {
LOG_INFO(
"startup", "Starting %s on core1 ...", l0dable
);
core1_start(info.isr_vector);
}
} else {
LOG_INFO("startup", "Starting pycardium on core1 ...");
core1_start((void *)0x10080000);
}
serial_init();
LOG_INFO("startup", "Starting FreeRTOS ...");
LOG_DEBUG("startup", "Starting FreeRTOS ...");
vTaskStartScheduler();
LOG_CRIT("startup", "FreeRTOS did not start due to unknown error!");
abort();
panic("FreeRTOS did not start due to unknown error!");
}
......@@ -37,8 +37,9 @@ api_dispatcher_lib = static_library(
'api-dispatcher',
'api/dispatcher.c',
'api/interrupt-sender.c',
'api/control.c',
api[1], # Dispatcher
dependencies: periphdriver,
dependencies: [libcard10, periphdriver],
)
##########################################################################
......@@ -65,27 +66,58 @@ freertos = static_library(
##########################################################################
subdir('modules/')
subdir('drivers/')
subdir('user_core/')
subdir('ble/')
subdir('os/')
subdir('fs/')
subdir('l0der/')
epicardium_cargs = ['-D_POSIX_C_SOURCE=200809']
if get_option('jailbreak_card10')
epicardium_cargs += [
'-DJAILBREAK_CARD10=1',
]
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(
name + '.elf',
'cdcacm.c',
'usb/epc_usb.c',
'usb/cdcacm.c',
'usb/mass_storage.c',
'main.c',
'support.c',
'fs/filesystem_fat.c',
module_sources,
os_sources,
user_core_sources,
driver_sources,
fs_sources,
l0der_sources,
ble_sources,
version_hdr,
dependencies: [libcard10, max32665_startup_core0, maxusb, libff13, ble],
version_screen,
dependencies: [libcard10, max32665_startup_core0, maxusb, libff13, ble, bhy1, libcrypto, bsec, libctx],
link_with: [api_dispatcher_lib, freertos],
link_whole: [max32665_startup_core0_lib, board_card10_lib, newlib_heap_lib],
include_directories: [freertos_includes],
link_args: [
'-Wl,-Map=' + meson.current_build_dir() + '/' + name + '.map',
'-Wl,--defsym=_write=_write_epicardium',
],
c_args: epicardium_cargs,
)
epicardium_bin = custom_target(
......
#include "display.h"
#include "Fonts/fonts.h"
#include "FreeRTOS.h"
#include "LCD_Driver.h"
#include "epicardium.h"
#include "gfx.h"
#include "gpio.h"
#include "task.h"
#include "tmr.h"
#include "tmr_utils.h"
static TaskHandle_t lock = NULL;
static int check_lock()
{
TaskHandle_t task = xTaskGetCurrentTaskHandle();
if (task != lock) {
return -EBUSY;
} else {
return 0;
}
}
int epic_disp_print(
uint16_t posx,
uint16_t posy,
const char *pString,
uint16_t fg,
uint16_t bg
) {
int cl = check_lock();
if (cl < 0) {
return cl;
} else {
gfx_puts(&Font20, &display_screen, posx, posy, pString, fg, bg);
return 0;
}
}
int epic_disp_clear(uint16_t color)
{
int cl = check_lock();
if (cl < 0) {
return cl;
} else {
gfx_clear_to_color(&display_screen, color);
return 0;
}
}
int epic_disp_pixel(uint16_t x, uint16_t y, uint16_t color)
{
int cl = check_lock();
if (cl < 0) {
return cl;
} else {
gfx_setpixel(&display_screen, x, y, color);
return 0;
}
}
int epic_disp_line(
uint16_t xstart,
uint16_t ystart,
uint16_t xend,
uint16_t yend,
uint16_t color,
enum disp_linestyle linestyle,
uint16_t pixelsize
) {
int cl = check_lock();
if (cl < 0) {
return cl;
} else {
/* TODO add linestyle support to gfx code */
gfx_line(
&display_screen,
xstart,
ystart,
xend,
yend,
pixelsize,
color
);
return 0;
}
}
int epic_disp_rect(
uint16_t xstart,
uint16_t ystart,
uint16_t xend,
uint16_t yend,
uint16_t color,
enum disp_fillstyle fillstyle,
uint16_t pixelsize
) {
int cl = check_lock();
if (cl < 0)
return cl;
switch (fillstyle) {
case FILLSTYLE_EMPTY:
gfx_rectangle(
&display_screen,
xstart,
ystart,
xend - xstart,
yend - ystart,
pixelsize,
color
);
break;
case FILLSTYLE_FILLED:
gfx_rectangle_fill(
&display_screen,
xstart,
ystart,
xend - xstart,
yend - ystart,
color
);
break;
}
return 0;
}
int epic_disp_circ(
uint16_t x,
uint16_t y,
uint16_t rad,
uint16_t color,
enum disp_fillstyle fillstyle,
uint16_t pixelsize
) {
int cl = check_lock();
if (cl < 0)
return cl;
switch (fillstyle) {
case FILLSTYLE_EMPTY:
gfx_circle(&display_screen, x, y, rad, pixelsize, color);
break;
case FILLSTYLE_FILLED:
gfx_circle_fill(&display_screen, x, y, rad, color);
break;
}
return 0;
}
int epic_disp_update()
{
int cl = check_lock();
if (cl < 0) {
return cl;
}
gfx_update(&display_screen);
return 0;
}
int epic_disp_framebuffer(union disp_framebuffer *fb)
{
int cl = check_lock();
if (cl < 0) {
return cl;
}
LCD_Set(fb->raw, sizeof(fb->raw));
return 0;
}
int epic_disp_open()
{
TaskHandle_t task = xTaskGetCurrentTaskHandle();
if (lock == task) {
return 0;
} else if (lock == NULL) {
lock = task;
return 0;
} else {
return -EBUSY;
}
}
int epic_disp_close()
{
if (check_lock() < 0 && lock != NULL) {
return -EBUSY;
} else {
lock = NULL;
return 0;
}
}
void disp_forcelock()
{
TaskHandle_t task = xTaskGetCurrentTaskHandle();
lock = task;
}
/**
* Implemention of the epicardium epic_file_ api that operates on
* the global EpicFileSystem instance
*
* All functions lock & unlock the global FS object
*
*/
#include "fs/internal.h"
int epic_file_open(const char *filename, const char *mode)
{
EpicFileSystem *fs;
int res = efs_lock_global(&fs);
if (res == 0) {
res = efs_open(fs, filename, mode);
efs_unlock_global(fs);
}
return res;
}
int epic_file_close(int fd)
{
EpicFileSystem *fs;
int res = efs_lock_global(&fs);
if (res == 0) {
res = efs_close(fs, fd);
efs_unlock_global(fs);
}
return res;
}
int epic_file_read(int fd, void *buf, size_t nbytes)
{
EpicFileSystem *fs;
int res = efs_lock_global(&fs);
if (res == 0) {
res = efs_read(fs, fd, buf, nbytes);
efs_unlock_global(fs);
}
return res;
}
int epic_file_write(int fd, const void *buf, size_t nbytes)
{
EpicFileSystem *fs;
int res = efs_lock_global(&fs);
if (res == 0) {
res = efs_write(fs, fd, buf, nbytes);
efs_unlock_global(fs);
}
return res;
}
int epic_file_flush(int fd)
{
EpicFileSystem *fs;
int res = efs_lock_global(&fs);
if (res == 0) {
res = efs_flush(fs, fd);
efs_unlock_global(fs);
}
return res;
}
int epic_file_seek(int fd, long offset, int whence)
{
EpicFileSystem *fs;
int res = efs_lock_global(&fs);
if (res == 0) {
res = efs_seek(fs, fd, offset, whence);
efs_unlock_global(fs);
}
return res;
}
int epic_file_tell(int fd)
{
EpicFileSystem *fs;
int res = efs_lock_global(&fs);
if (res == 0) {
res = efs_tell(fs, fd);
efs_unlock_global(fs);
}
return res;
}
int epic_file_stat(const char *filename, struct epic_stat *stat)
{
EpicFileSystem *fs;
int res = efs_lock_global(&fs);
if (res == 0) {
res = efs_stat(fs, filename, stat);
efs_unlock_global(fs);
}
return res;
}
#ifndef EPICARDIUM_MODULE_FILESYSTEM_INCLUDED
#define EPICARDIUM_MODULE_FILESYSTEM_INCLUDED
/* ---------- FAT fs ------------------------------------------------------ */
#include <stdbool.h>
#include "epicardium.h"
/**
* module initialization - to be called once at startup before any FreeRTOS tasks
* have been started
*
* calls fatfs_attach
*/
void fatfs_init(void);
/**
* initialize and mount the FLASH storage
*/
int fatfs_attach(void);
/** close all opened FDs, sync and deinitialize FLASH layer */
void fatfs_detach(void);
#endif//EPICARDIUM_MODULE_FILESYSTEM_INCLUDED
#include "epicardium.h"
#include "api/dispatcher.h"
#include "usb/epc_usb.h"
#include "fs/filesystem.h"
#include "os/core.h"
#include "modules/modules.h"
#include "modules/stream.h"
#include "drivers/drivers.h"
#include "user_core/interrupts.h"
#include "user_core/user_core.h"
#include "card10.h"
#include "leds.h"
#include "pb.h"
#include "pmic.h"
#include "portexpander.h"
#include "max86150.h"
#include "ble/ble_api.h"
#include "gpio.h"
#include "i2c.h"
#include "rtc.h"
#include "spi.h"
#include "wdt.h"
/*
* Early init is called at the very beginning and is meant for modules which
* absolutely need to start as soon as possible. hardware_early_init() blocks
* which means code in here should be fast.
*/
int hardware_early_init(void)
{
/*
* Watchdog timer
*/
watchdog_init();
/*
* I2C bus for onboard peripherals (ie. PMIC, BMA400, BHI160, BME680,
* ...)
*/
I2C_Shutdown(MXC_I2C1_BUS0);
I2C_Init(MXC_I2C1_BUS0, I2C_FAST_MODE, NULL);
#ifndef CARD10_DEBUG_CORE1
/*
* SAO I2C bus
*/
I2C_Shutdown(MXC_I2C0_BUS0);
I2C_Init(MXC_I2C0_BUS0, I2C_FAST_MODE, NULL);
#endif
/*
* GPIO peripheral.
*/
GPIO_Init();
/* Set the power hold pin, so the PMIC does not turn off again */
const gpio_cfg_t pwr_hold_pin = {
PORT_0, PIN_30, GPIO_FUNC_OUT, GPIO_PAD_NONE
};
GPIO_Config(&pwr_hold_pin);
GPIO_OutSet(&pwr_hold_pin);
/*
* PMIC (MAX77650)
*/
pmic_init();
pmic_set_led(0, 0);
pmic_set_led(1, 0);
pmic_set_led(2, 0);
/*
* Harmonic Board Portexpander
*/
portexpander_init();
/*
* Buttons
*/
PB_Init();
/* Enable 32 kHz output */
while (RTC_SquareWave(MXC_RTC, SQUARE_WAVE_ENABLED, F_32KHZ, NULL) ==
E_BUSY)
;
/*
* RNG
*/
rng_init();
/* If we don't have a valid time yet, set it to 2019-01-01 */
if (RTC_GetSecond() < 1546300800L) {
epic_rtc_set_milliseconds(1546300800UL * 1000);
}
/*
* SPI for ECG
*/
const sys_cfg_spi_t spi17y_master_cfg = { .map = MAP_A,
.ss0 = Enable,
.ss1 = Disable,
.ss2 = Disable,
.num_io = 2 };
if (SPI_Init(SPI0, 0, SPI_SPEED, spi17y_master_cfg) != 0) {
LOG_ERR("init", "Error configuring SPI");
while (1)
;
}
/*
* Display
*/
disp_init();
/*
* RGB LEDs
*/
leds_init();
#ifdef CARD10_DEBUG_CORE1
/*
* The SAO pins can be reconfigured for SWCLK2 and SWDIO2 which allows
* debugging core 1. This feature can optionally be enabled at
* compile-time.
*/
LOG_WARN("init", "Core 1 Debugger Mode");
static const gpio_cfg_t swclk = {
PORT_0,
PIN_7,
GPIO_FUNC_ALT3,
GPIO_PAD_NONE,
};
static const gpio_cfg_t swdio = {
PORT_0,
PIN_6,
GPIO_FUNC_ALT3,
GPIO_PAD_NONE,
};
GPIO_Config(&swclk);
GPIO_Config(&swdio);
#endif /* CARD10_DEBUG_CORE1 */
/*
* Enable SEV-ON-PEND which is needed for proper working of the FreeRTOS
* tickless idle sleep in Epicardium.
*/
SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
/*
* USB-Serial
*/
if (epic_usb_cdcacm() < 0) {
LOG_ERR("startup", "USB-Serial unavailable");
}
/*
* Flash & FatFS
*/
fatfs_init();
/*
* API Dispatcher & API Interrupts
*/
interrupt_init();
api_dispatcher_init();
/*
* Sensor streams
*/
stream_init();
/*
* Hardware/Peripheral Locks
*/
hwlock_init();
/*
* API Dispatcher Mutex
*/
dispatcher_mutex_init();
/*
* MAX30001 mutex init
*/
max30001_mutex_init();
/*
* max86150 mutex init
*/
max86150_mutex_init();
max86150_shut_down();
/*
* BME680 Sensor
*/
epic_bme680_init();
/* Allow user space to trigger interrupts.
* Used for BLE, not sure if needed. */
SCB->CCR |= SCB_CCR_USERSETMPEND_Msk;
return 0;
}
/*
* hardware_init() is called after the core has been bootstrapped and is meant
* for less critical initialization steps. Modules which initialize here should
* be robust against a l0dable using their API before initialization is done.
*
* Ideally, acquire a lock in hardware_early_init() and release it in
* hardware_init() once initialization is done.
*/
int hardware_init(void)
{
/* Watchdog clearer software timer */
watchdog_clearer_init();
/* Light Sensor */
LOG_DEBUG("init", "Starting light sensor ...");
epic_light_sensor_run();
return 0;
}
/*
* hardware_reset() is called whenever a new l0dable is started. hardware_reset()
* should bring all peripherals back into a known initial state. This does not
* necessarily mean resetting the peripheral entirely but hardware_reset()
* should at least bring the API facing part of a peripheral back into the state
* a fresh booted l0dable expects.
*/
int hardware_reset(void)
{
/*
* API Dispatcher & API Interrupts
*/
interrupt_init();
api_dispatcher_init();
/*
* close all FDs currently owned by core1
*/
fatfs_close_all(EPICARDIUM_COREMASK_1);
/* Personal State */
const int personal_state_is_persistent =
epic_personal_state_is_persistent();
if (personal_state_is_persistent == 0) {
epic_personal_state_set(STATE_NONE, 0);
}
/*
* LEDs
*/
if (personal_state_is_persistent) {
epic_leds_clear_all(0, 0, 0);
} else {
leds_init();
}
epic_leds_set_rocket(0, 0);
epic_leds_set_rocket(1, 0);
epic_leds_set_rocket(2, 0);
/*
* Display
*/
disp_init();
epic_disp_backlight(20);
/*
* Vibration Motor
*/
epic_vibra_set(false);
/*
* BHI160
*/
epic_bhi160_disable_all_sensors();
epic_max30001_disable_sensor();
epic_max86150_disable_sensor();
/*
* BLE
*/
/* Reset advertisement data */
ble_adv_setup();
/* Start advertising again if needed */
epic_ble_set_mode(false, false);
return 0;
}
#include "os/core.h"
#include "modules/modules.h"
#include "os/mutex.h"
#include "FreeRTOS.h"
#include "task.h"
#include <errno.h>
static struct mutex hwlock_mutex[_HWLOCK_MAX] = { { 0 } };
void hwlock_init(void)
{
for (int i = 0; i < _HWLOCK_MAX; i++) {
/*
* TODO: mutex_create() names these all these mutexes
* "&hwlock_mutex[i]" which is not helpful at all. We
* should somehow rename them to the actual hwlock names.
*/
mutex_create(&hwlock_mutex[i]);
}
}
void hwlock_acquire(enum hwlock_periph p)
{
assert(p < _HWLOCK_MAX);
mutex_lock(&hwlock_mutex[p]);
}
int hwlock_acquire_nonblock(enum hwlock_periph p)
{
assert(p < _HWLOCK_MAX);
if (mutex_trylock(&hwlock_mutex[p])) {
return 0;
} else {
return -EBUSY;
}
}
void hwlock_release(enum hwlock_periph p)
{
assert(p < _HWLOCK_MAX);
mutex_unlock(&hwlock_mutex[p]);
}
#include "leds.h"
#include "pmic.h"
//#include "FreeRTOS.h"
//#include "task.h"
//TODO: create smth like vTaskDelay(pdMS_TO_TICKS(//put ms here)) for us, remove blocking delay from /lib/leds.c to avoid process blocking
void epic_leds_set(int led, uint8_t r, uint8_t g, uint8_t b)
{
leds_prep(led, r, g, b);
leds_update_power();
leds_update();
}
void epic_leds_set_hsv(int led, float h, float s, float v)
{
leds_prep_hsv(led, h, s, v);
leds_update_power();
leds_update();
}
void epic_leds_prep(int led, uint8_t r, uint8_t g, uint8_t b)
{
leds_prep(led, r, g, b);
}
void epic_leds_prep_hsv(int led, float h, float s, float v)
{
leds_prep_hsv(led, h, s, v);
}
void epic_leds_set_all(uint8_t *pattern_ptr, uint8_t len)
{
uint8_t(*pattern)[3] = (uint8_t(*)[3])pattern_ptr;
for (int i = 0; i < len; i++) {
leds_prep(i, pattern[i][0], pattern[i][1], pattern[i][2]);
}
leds_update_power();
leds_update();
}
void epic_leds_set_all_hsv(float *pattern_ptr, uint8_t len)
{
float(*pattern)[3] = (float(*)[3])pattern_ptr;
for (int i = 0; i < len; i++) {
leds_prep_hsv(i, pattern[i][0], pattern[i][1], pattern[i][2]);
}
leds_update_power();
leds_update();
}
void epic_leds_dim_top(uint8_t value)
{
leds_set_dim_top(value);
leds_update();
}
void epic_leds_dim_bottom(uint8_t value)
{
leds_set_dim_bottom(value);
leds_update();
}
void epic_leds_set_rocket(int led, uint8_t value)
{
pmic_set_led(led, value);
}
void epic_set_flashlight(bool power)
{
leds_flashlight(power);
}
void epic_leds_update(void)
{
leds_update_power();
leds_update();
}
void epic_leds_set_powersave(bool eco)
{
leds_powersave(eco);
}
void epic_leds_set_gamma_table(uint8_t rgb_channel, uint8_t gamma_table[256])
{
leds_set_gamma_table(rgb_channel, gamma_table);
}
#pragma once
#define SEV_DEBUG "D"
#define SEV_INFO "I"
#define SEV_WARN "W"
#define SEV_ERR "E"
#define SEV_CRIT "C"
/* Whether to enable logging at all */
#ifndef LOG_ENABLE
#define LOG_ENABLE 1
#endif
/* Whether to enable even more verbose logging */
#ifndef LOG_ENABLE_DEBUG
#define LOG_ENABLE_DEBUG 0
#endif
/* Whether to enable colorful log */
#ifndef LOG_ENABLE_COLOR
#define LOG_ENABLE_COLOR 1
#endif
#if LOG_ENABLE
int log_msg(const char *subsys, const char *format, ...)
__attribute__((format(printf, 2, 3)));
#if LOG_ENABLE_DEBUG
#define LOG_DEBUG(subsys, format, ...) \
log_msg(subsys, SEV_DEBUG format, ##__VA_ARGS__)
#else /* LOG_ENABLE_DEBUG */
#define LOG_DEBUG(subsys, format, ...)
#endif /* LOG_ENABLE_DEBUG */
#define LOG_INFO(subsys, format, ...) \
log_msg(subsys, SEV_INFO format, ##__VA_ARGS__)
#define LOG_WARN(subsys, format, ...) \
log_msg(subsys, SEV_WARN format, ##__VA_ARGS__)
#define LOG_ERR(subsys, format, ...) \
log_msg(subsys, SEV_ERR format, ##__VA_ARGS__)
#define LOG_CRIT(subsys, format, ...) \
log_msg(subsys, SEV_CRIT format, ##__VA_ARGS__)
#else /* LOG_ENABLE_DEBUG */
inline __attribute__((format(printf, 2, 3))) int
log_msg(const char *subsys, const char *format, ...)
{
return 0;
}
#define LOG_DEBUG(subsys, format, ...)
#define LOG_INFO(subsys, format, ...)
#define LOG_WARN(subsys, format, ...)
#define LOG_ERR(subsys, format, ...)
#define LOG_CRIT(subsys, format, ...)
#endif /* LOG_ENABLE_DEBUG */
module_sources = files(
'display.c',
'fileops.c',
'leds.c',
'light_sensor.c',
'log.c',
'pmic.c',
'rtc.c',
'serial.c',
'hardware.c',
'hw-lock.c',
'personal_state.c',
'stream.c',
'vibra.c',
)
#ifndef MODULES_H
#define MODULES_H
#include <stdint.h>
#include "FreeRTOS.h"
#include "gpio.h"
#include "os/mutex.h"
#include "epicardium.h"
/* ---------- Serial ------------------------------------------------------- */
#define SERIAL_READ_BUFFER_SIZE 128
void vSerialTask(void *pvParameters);
#include <stdint.h>
#include <stdbool.h>
void serial_enqueue_char(char chr);
/* ---------- Hardware Init & Reset ---------------------------------------- */
int hardware_early_init(void);
int hardware_init(void);
int hardware_reset(void);
/* ---------- PMIC --------------------------------------------------------- */
/* In 1/10s */
#define PMIC_PRESS_SLEEP 20
#define PMIC_PRESS_POWEROFF 40
void vPmicTask(void *pvParameters);
/* ---------- LED Animation / Personal States ------------------------------ */
#define PERSONAL_STATE_LED 14
void vLedTask(void *pvParameters);
int personal_state_enabled();
/* ---------- BLE ---------------------------------------------------------- */
void vBleTask(void *pvParameters);
bool ble_is_enabled(void);
void ble_uart_write(uint8_t *pValue, uint8_t len);
// Forces an unlock of the display. Only to be used in epicardium
void disp_forcelock();
/* ---------- Hardware (Peripheral) Locks ---------------------------------- */
void hwlock_init(void);
enum hwlock_periph {
HWLOCK_I2C = 0,
HWLOCK_ADC,
HWLOCK_LED,
HWLOCK_SPI_ECG,
_HWLOCK_MAX,
};
void hwlock_acquire(enum hwlock_periph p);
int hwlock_acquire_nonblock(enum hwlock_periph p);
void hwlock_release(enum hwlock_periph p);
#endif /* MODULES_H */
#include "epicardium.h"
#include "leds.h"
#include "modules.h"
#include "os/work_queue.h"
#include "FreeRTOS.h"
#include "timers.h"
#include <math.h>
static uint8_t _personal_state_enabled = 0;
static uint8_t personal_state = STATE_NONE;
static uint8_t personal_state_persistent = 0;
static int led_animation_ticks = 0;
static int led_animation_state = 0;
static TimerHandle_t led_timer;
static StaticTimer_t led_timer_buffer;
static void worktick(void *data);
static const int led_animation_rate = 1000 / 25; /* 25Hz -> 40ms*/
int personal_state_enabled()
{
return _personal_state_enabled;
}
static void tick(TimerHandle_t xTimer)
{
workqueue_schedule(worktick, NULL);
}
int epic_personal_state_set(uint8_t state, bool persistent)
{
if (state > STATE_CAMP)
return -EINVAL;
led_animation_state = 0;
led_animation_ticks = 0;
personal_state = state;
uint8_t was_enabled = _personal_state_enabled;
_personal_state_enabled = (state != STATE_NONE);
personal_state_persistent = persistent;
if (!was_enabled && _personal_state_enabled) {
// Activate
if (!led_timer) {
led_timer = xTimerCreateStatic(
"personal state",
led_animation_rate / portTICK_PERIOD_MS,
pdTRUE,
NULL,
tick,
&led_timer_buffer
);
// since &poll_timer_buffer is not NULL, xTimerCreateStatic should allways succeed, so
// we don't need to check for poll_timer being NULL.
}
if (xTimerIsTimerActive(led_timer) == pdFALSE) {
xTimerStart(led_timer, 0);
}
} else if (was_enabled && !_personal_state_enabled) {
// Deactivate
xTimerStop(led_timer, 0);
// TODO: we might need a lock here to avoid a race condition
leds_prep(PERSONAL_STATE_LED, 0, 0, 0);
epic_leds_update();
}
return 0;
}
int epic_personal_state_get()
{
return personal_state;
}
int epic_personal_state_is_persistent()
{
return personal_state_persistent;
}
static void worktick(void *data)
{
if (_personal_state_enabled) {
led_animation_ticks++;
if (personal_state == STATE_NO_CONTACT) {
leds_prep(PERSONAL_STATE_LED, 255, 0, 0);
} else if (personal_state == STATE_CHAOS) {
if (led_animation_state == 0) {
leds_prep(PERSONAL_STATE_LED, 0, 0, 255);
if (led_animation_ticks >
(200 / led_animation_rate)) {
led_animation_ticks = 0;
led_animation_state = 1;
}
} else if (led_animation_state == 1) {
leds_prep(PERSONAL_STATE_LED, 0, 0, 0);
if (led_animation_ticks >
(300 / led_animation_rate)) {
led_animation_ticks = 0;
led_animation_state = 2;
}
} else if (led_animation_state == 2) {
leds_prep(PERSONAL_STATE_LED, 0, 0, 255);
if (led_animation_ticks >
(1000 / led_animation_rate)) {
led_animation_ticks = 0;
led_animation_state = 3;
}
} else if (led_animation_state == 3) {
leds_prep(PERSONAL_STATE_LED, 0, 0, 0);
if (led_animation_ticks >
(300 / led_animation_rate)) {
led_animation_ticks = 0;
led_animation_state = 0;
}
}
} else if (personal_state == STATE_COMMUNICATION) {
if (led_animation_state == 0) {
leds_prep(PERSONAL_STATE_LED, 255, 255, 0);
if (led_animation_ticks >
(1000 / led_animation_rate)) {
led_animation_ticks = 0;
led_animation_state = 1;
}
} else if (led_animation_state == 1) {
leds_prep(PERSONAL_STATE_LED, 0, 0, 0);
if (led_animation_ticks >
(300 / led_animation_rate)) {
led_animation_ticks = 0;
led_animation_state = 0;
}
}
} else if (personal_state == STATE_CAMP) {
leds_prep_hsv(
PERSONAL_STATE_LED,
120.0f,
1.0f,
fabs(sin(
led_animation_ticks /
(float)(1000 / led_animation_rate))));
}
epic_leds_update();
}
}
#include <stdio.h>
#include "max32665.h"
#include "gcr_regs.h"
#include "pmic.h"
#include "MAX77650-Arduino-Library.h"
#include "card10.h"
#include "FreeRTOS.h"
#include "task.h"
#include "epicardium.h"
#include "modules.h"
#include "modules/log.h"
/* Task ID for the pmic handler */
static TaskHandle_t pmic_task_id = NULL;
void pmic_interrupt_callback(void *_)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if (pmic_task_id != NULL) {
vTaskNotifyGiveFromISR(pmic_task_id, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
void vPmicTask(void *pvParameters)
{
int count = 0;
portTickType delay = portMAX_DELAY;
pmic_task_id = xTaskGetCurrentTaskHandle();
while (1) {
ulTaskNotifyTake(pdTRUE, delay);
if (count == PMIC_PRESS_SLEEP) {
LOG_ERR("pmic", "Sleep [[ Unimplemented ]]");
}
if (count == PMIC_PRESS_POWEROFF) {
LOG_INFO("pmic", "Poweroff");
MAX77650_setSFT_RST(0x2);
}
uint8_t int_flag = MAX77650_getINT_GLBL();
if (int_flag & MAX77650_INT_nEN_F) {
/* Button was pressed */
count = 0;
delay = portTICK_PERIOD_MS * 100;
}
if (int_flag & MAX77650_INT_nEN_R) {
/* Button was pressed */
if (count < PMIC_PRESS_SLEEP) {
card10_reset();
}
count = 0;
delay = portMAX_DELAY;
}
/* TODO: Remove when all interrupts are handled */
if (int_flag & ~(MAX77650_INT_nEN_F | MAX77650_INT_nEN_R)) {
LOG_WARN(
"pmic",
"Unhandled PMIC Interrupt: %x",
int_flag
);
}
if (delay != portMAX_DELAY) {
count += 1;
}
}
}
#include "epicardium.h"
#include "modules/log.h"
#include "api/interrupt-sender.h"
#include "FreeRTOS.h"
#include "task.h"
#include "rtc.h"
#include <stdint.h>
uint32_t epic_rtc_get_seconds(void)
{
uint32_t sec, subsec;
/*
* TODO: Find out what causes the weird behavior of this function. The
* time needed for this call seems to depend on the frequency at
* which it is called.
*/
while (RTC_GetTime(&sec, &subsec) == E_BUSY) {
vTaskDelay(pdMS_TO_TICKS(4));
}
return sec;
}
void RTC_IRQHandler(void)
{
int flags = RTC_GetFlags();
if (flags & MXC_F_RTC_CTRL_ALDF) {
RTC_ClearFlags(MXC_F_RTC_CTRL_ALDF);
api_interrupt_trigger(EPIC_INT_RTC_ALARM);
} else {
LOG_WARN("rtc", "Unknown IRQ caught!");
/* Disable IRQ so it does not retrigger */
NVIC_DisableIRQ(RTC_IRQn);
}
}
int epic_rtc_schedule_alarm(uint32_t timestamp)
{
int res;
NVIC_EnableIRQ(RTC_IRQn);
while ((res = RTC_SetTimeofdayAlarm(MXC_RTC, timestamp)) == E_BUSY)
;
if (res != E_SUCCESS) {
return -EINVAL;
}
return 0;
}
#include "epicardium.h"
#include "api/interrupt-sender.h"
#include "modules/log.h"
#include "modules/modules.h"
#include "max32665.h"
#include "cdcacm.h"
#include "uart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include <stdint.h>
#include <stdio.h>
/* Task ID for the serial handler */
TaskHandle_t serial_task_id = NULL;
/* The serial console in use (UART0) */
extern mxc_uart_regs_t *ConsoleUart;
/* Read queue, filled by both UART and CDCACM */
static QueueHandle_t read_queue;
/*
* API-call to write a string. Output goes to both CDCACM and UART
*/
void epic_uart_write_str(const char *str, intptr_t length)
{
UART_Write(ConsoleUart, (uint8_t *)str, length);
cdcacm_write((uint8_t *)str, length);
ble_uart_write((uint8_t *)str, length);
}
/*
* API-call to read a character from the queue.
*/
int epic_uart_read_char(void)
{
char chr;
if (xQueueReceive(read_queue, &chr, 0) == pdTRUE) {
return (int)chr;
}
return (-1);
}
/*
* API-call to read data from the queue.
*/
int epic_uart_read_str(char *buf, size_t cnt)
{
int i = 0;
for (i = 0; i < cnt; i++) {
if (xQueueReceive(read_queue, &buf[i], 0) != pdTRUE) {
break;
}
}
return i;
}
/* Interrupt handler needed for SDK UART implementation */
void UART0_IRQHandler(void)
{
UART_Handler(ConsoleUart);
}
static void uart_callback(uart_req_t *req, int error)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(serial_task_id, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void serial_enqueue_char(char chr)
{
if (chr == 0x3) {
/* Control-C */
api_interrupt_trigger(EPIC_INT_CTRL_C);
}
if (xQueueSend(read_queue, &chr, 100) == errQUEUE_FULL) {
/* Queue overran, wait a bit */
vTaskDelay(portTICK_PERIOD_MS * 50);
}
api_interrupt_trigger(EPIC_INT_UART_RX);
}
void vSerialTask(void *pvParameters)
{
static uint8_t buffer[sizeof(char) * SERIAL_READ_BUFFER_SIZE];
static StaticQueue_t read_queue_data;
serial_task_id = xTaskGetCurrentTaskHandle();
/* Setup read queue */
read_queue = xQueueCreateStatic(
SERIAL_READ_BUFFER_SIZE, sizeof(char), buffer, &read_queue_data
);
/* Setup UART interrupt */
NVIC_ClearPendingIRQ(UART0_IRQn);
NVIC_DisableIRQ(UART0_IRQn);
NVIC_SetPriority(UART0_IRQn, 6);
NVIC_EnableIRQ(UART0_IRQn);
unsigned char data;
uart_req_t read_req = {
.data = &data,
.len = 1,
.callback = uart_callback,
};
while (1) {
int ret = UART_ReadAsync(ConsoleUart, &read_req);
if (ret != E_NO_ERROR && ret != E_BUSY) {
LOG_ERR("serial", "error reading uart: %d", ret);
vTaskDelay(portMAX_DELAY);
}
ulTaskNotifyTake(pdTRUE, portTICK_PERIOD_MS * 1000);
if (read_req.num > 0) {
serial_enqueue_char(*read_req.data);
}
while (UART_NumReadAvail(ConsoleUart) > 0) {
serial_enqueue_char(UART_ReadByte(ConsoleUart));
}
while (cdcacm_num_read_avail() > 0) {
serial_enqueue_char(cdcacm_read());
}
}
}
#include <string.h>
#include "FreeRTOS.h"
#include "semphr.h"
#include "queue.h"
#include "epicardium.h"
#include "modules/log.h"
#include "os/core.h"
#include "modules/stream.h"
#include "os/mutex.h"
/* Internal buffer of registered streams */
static struct stream_info *stream_table[SD_MAX];
/* Lock for modifying the stream info table */
static StaticSemaphore_t stream_table_lock_data;
static SemaphoreHandle_t stream_table_lock;
static struct mutex stream_table_lock;
int stream_init()
{
memset(stream_table, 0x00, sizeof(stream_table));
stream_table_lock =
xSemaphoreCreateMutexStatic(&stream_table_lock_data);
mutex_create(&stream_table_lock);
return 0;
}
int stream_register(int sd, struct stream_info *stream)
{
if (xSemaphoreTake(stream_table_lock, STREAM_MUTEX_WAIT) != pdTRUE) {
LOG_WARN("stream", "Lock contention error");
return -EBUSY;
}
int ret = 0;
mutex_lock(&stream_table_lock);
if (sd < 0 || sd >= SD_MAX) {
return -EINVAL;
ret = -EINVAL;
goto out;
}
if (stream_table[sd] != NULL) {
/* Stream already registered */
return -EACCES;
ret = -EACCES;
goto out;
}
stream_table[sd] = stream;
xSemaphoreGive(stream_table_lock);
return 0;
out:
mutex_unlock(&stream_table_lock);
return ret;
}
int stream_deregister(int sd, struct stream_info *stream)
{
if (xSemaphoreTake(stream_table_lock, STREAM_MUTEX_WAIT) != pdTRUE) {
LOG_WARN("stream", "Lock contention error");
return -EBUSY;
}
int ret = 0;
mutex_lock(&stream_table_lock);
if (sd < 0 || sd >= SD_MAX) {
return -EINVAL;
ret = -EINVAL;
goto out;
}
if (stream_table[sd] != stream) {
/* Stream registered by someone else */
return -EACCES;
ret = -EACCES;
goto out;
}
stream_table[sd] = NULL;
xSemaphoreGive(stream_table_lock);
return 0;
out:
mutex_unlock(&stream_table_lock);
return ret;
}
int epic_stream_read(int sd, void *buf, size_t count)
{
int ret = 0;
/*
* TODO: In theory, multiple reads on different streams can happen
* simulaneously. I don't know what the most efficient implementation
* of this would look like.
*/
if (xSemaphoreTake(stream_table_lock, STREAM_MUTEX_WAIT) != pdTRUE) {
LOG_WARN("stream", "Lock contention error");
return -EBUSY;
}
mutex_lock(&stream_table_lock);
if (sd < 0 || sd >= SD_MAX) {
return -EBADF;
ret = -EBADF;
goto out;
}
struct stream_info *stream = stream_table[sd];
if (stream == NULL) {
return -ENODEV;
ret = -ENODEV;
goto out;
}
/* Poll the stream, if a poll_stream function exists */
if (stream->poll_stream != NULL) {
int ret = stream->poll_stream();
ret = stream->poll_stream();
if (ret < 0) {
return ret;
goto out;
}
}
/* Check buffer size is a multiple of the data packet size */
if (count % stream->item_size != 0) {
return -EINVAL;
ret = -EINVAL;
goto out;
}
size_t i;
......@@ -107,6 +111,9 @@ int epic_stream_read(int sd, void *buf, size_t count)
}
}
xSemaphoreGive(stream_table_lock);
return i / stream->item_size;
ret = i / stream->item_size;
out:
mutex_unlock(&stream_table_lock);
return ret;
}
......@@ -4,14 +4,16 @@
#include <stdint.h>
#ifndef __SPHINX_DOC
/* stddef.h is not recognized by hawkmoth for some odd reason */
/* Some headers are not recognized by hawkmoth for some odd reason */
#include <stddef.h>
#else
typedef unsigned int size_t;
#endif /* __SPHINX_DOC */
#include "FreeRTOS.h"
#include "queue.h"
#else
typedef unsigned int size_t;
typedef int bool;
typedef void *QueueHandle_t;
#endif /* __SPHINX_DOC */
/* Time to wait for the descriptor table lock to become available */
#define STREAM_MUTEX_WAIT pdMS_TO_TICKS(100)
......@@ -25,6 +27,17 @@ typedef unsigned int size_t;
* Please keep IDs in sequential order.
*/
enum stream_descriptor {
/** BHI160 Accelerometer */
SD_BHI160_ACCELEROMETER,
/** BHI160 Magnetometer */
SD_BHI160_MAGNETOMETER,
/** BHI160 Orientation Sensor */
SD_BHI160_ORIENTATION,
/** BHI160 Gyroscope */
SD_BHI160_GYROSCOPE,
/** MAX30001 ECG */
SD_MAX30001_ECG,
SD_MAX86150,
/** Highest descriptor must always be ``SD_MAX``. */
SD_MAX,
};
......@@ -55,6 +68,12 @@ struct stream_info {
* The function registered here should never block for a longer time.
*/
int (*poll_stream)();
/**
* Set to true if the last write to ``queue`` failed because
* the queue was full.
*/
bool was_full;
};
/**
......
#include "gpio.h"
#include "FreeRTOS.h"
#include "timers.h"
static const gpio_cfg_t motor_pin = {
PORT_0, PIN_8, GPIO_FUNC_OUT, GPIO_PAD_NONE
};
static TimerHandle_t vibra_timer;
void epic_vibra_set(int status)
{
if (status) {
GPIO_OutSet(&motor_pin);
} else {
GPIO_OutClr(&motor_pin);
}
}
void vTimerCallback()
{
epic_vibra_set(0);
}
void epic_vibra_vibrate(int millis)
{
int ticks = millis * (configTICK_RATE_HZ / 1000);
epic_vibra_set(1);
vibra_timer =
xTimerCreate("vibratimer", ticks, pdFALSE, 0, vTimerCallback);
xTimerStart(vibra_timer, 0);
}