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
  • ch3/api-speed-eval2
  • ch3/dual-core
  • ch3/genapi-refactor
  • ch3/leds-api
  • debug-queue-handling
  • dualcore
  • fix-issue_71
  • freertos-btle
  • issue104-UIError-update-fail
  • master
  • msgctl/faultscreen
  • msgctl/gfx_rle
  • msgctl/textbuffer_api
  • rahix/bhi
  • rahix/bma
  • schleicher-test
  • schneider/bonding
  • schneider/bootloader-update-9a0d158
  • schneider/bsec
  • schneider/mp-for-old-bl
  • schneider/schleicher-test
  • unique-advert-id
  • v0.0
23 results
Show changes
Showing
with 868 additions and 59 deletions
...@@ -16,12 +16,15 @@ ...@@ -16,12 +16,15 @@
#include "usb_event.h" #include "usb_event.h"
#include "cdc_acm.h" #include "cdc_acm.h"
#include "modules/log.h" #include "os/core.h"
#include "modules/modules.h" #include "modules/modules.h"
#include "drivers/drivers.h"
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "task.h" #include "task.h"
static volatile int lockup_disable = 0;
static inline struct config_descriptor_cdcacm * static inline struct config_descriptor_cdcacm *
descriptors(struct esb_config *self) descriptors(struct esb_config *self)
{ {
...@@ -36,15 +39,24 @@ static int cb_acm_read_ready(void) ...@@ -36,15 +39,24 @@ static int cb_acm_read_ready(void)
return 0; return 0;
} }
static int cb_acm_connected(void)
{
lockup_disable = 0;
return 0;
}
int esb_cdc_init(struct esb_config *self) int esb_cdc_init(struct esb_config *self)
{ {
LOG_DEBUG("cdcacm", "init"); LOG_DEBUG("cdcacm", "init");
struct config_descriptor_cdcacm *dsc = descriptors(self); struct config_descriptor_cdcacm *dsc = descriptors(self);
usb_read_complete = 0; usb_read_complete = 0;
int ret = acm_init(&dsc->comm_interface);
acm_register_callback( acm_register_callback(
ACM_CB_READ_READY, ACM_CB_READ_READY,
cb_acm_read_ready); //SWYM: actually not needed cb_acm_read_ready); //SWYM: actually not needed
return acm_init(&dsc->comm_interface); acm_register_callback(ACM_CB_CONNECTED, cb_acm_connected);
return ret;
} }
int esb_cdc_configure(struct esb_config *self) int esb_cdc_configure(struct esb_config *self)
...@@ -96,7 +108,6 @@ uint8_t cdcacm_read(void) ...@@ -96,7 +108,6 @@ uint8_t cdcacm_read(void)
void cdcacm_write(uint8_t *data, int len) void cdcacm_write(uint8_t *data, int len)
{ {
static int lockup_disable = 0;
if (acm_present() && !lockup_disable) { if (acm_present() && !lockup_disable) {
int ret = acm_write(data, len); int ret = acm_write(data, len);
if (ret < 0) { if (ret < 0) {
......
...@@ -68,8 +68,8 @@ ...@@ -68,8 +68,8 @@
#include "cdc_acm.h" #include "cdc_acm.h"
#include "usb/descriptors.h" #include "usb/descriptors.h"
#include "modules/log.h" #include "os/core.h"
#include "modules/filesystem.h" #include "fs/filesystem.h"
//#define USE_REMOTE_WAKE_ENABLE //#define USE_REMOTE_WAKE_ENABLE
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#include "usb/epc_usb.h" #include "usb/epc_usb.h"
#include "usb/descriptors.h" #include "usb/descriptors.h"
#include "modules/log.h" #include "os/core.h"
#include "msc.h" #include "msc.h"
#include "usb.h" #include "usb.h"
......
#include "os/core.h"
#include "os/mutex.h"
#include "api/dispatcher.h"
#include "FreeRTOS.h"
#include "task.h"
#define TIMEOUT pdMS_TO_TICKS(2000)
TaskHandle_t dispatcher_task_id;
struct mutex api_mutex = { 0 };
void dispatcher_mutex_init(void)
{
mutex_create(&api_mutex);
}
/*
* 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()) {
mutex_lock(&api_mutex);
api_dispatcher_exec();
mutex_unlock(&api_mutex);
}
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
}
}
#include "os/mutex.h"
#include "os/core.h"
#include "epicardium.h"
#include "api/interrupt-sender.h"
#include "user_core/user_core.h"
#include <assert.h>
struct interrupt_priv {
/* Whether this interrupt can be triggered */
bool int_enabled[EPIC_INT_NUM];
/* Whether this interrupt is waiting to be delivered */
bool int_pending[EPIC_INT_NUM];
/* Whether any interrupts are currently waiting to be triggered */
bool has_pending;
};
static struct interrupt_priv interrupt_data;
static struct mutex interrupt_mutex;
static TaskHandle_t interrupts_task;
void interrupt_trigger(api_int_id_t id)
{
assert(id < EPIC_INT_NUM);
mutex_lock(&interrupt_mutex);
if (interrupt_data.int_enabled[id]) {
interrupt_data.int_pending[id] = true;
interrupt_data.has_pending = true;
mutex_unlock(&interrupt_mutex);
xTaskNotifyGive(interrupts_task);
} else {
mutex_unlock(&interrupt_mutex);
}
}
void interrupt_trigger_sync(api_int_id_t id)
{
assert(id < EPIC_INT_NUM);
mutex_lock(&interrupt_mutex);
if (!interrupt_data.int_enabled[id])
goto out;
while (!api_interrupt_is_ready())
;
api_interrupt_trigger(id);
/* Break the dispatcher task out of a potential call
* to epic_sleep() */
xTaskNotifyGive(dispatcher_task_id);
out:
mutex_unlock(&interrupt_mutex);
}
/*
* This function solely exists because of that one use of interrupts that breaks
* the rules: The RTC ALARM interrupt is triggered from a hardware ISR where
* interrupt_trigger_sync() won't work because it needs to lock a mutex.
*
* DO NOT USE THIS FUNCTION IN ANY NEW CODE.
*/
void __attribute__((deprecated)) interrupt_trigger_unsafe(api_int_id_t id)
{
assert(id < EPIC_INT_NUM);
if (!interrupt_data.int_enabled[id])
return;
while (!api_interrupt_is_ready())
;
api_interrupt_trigger(id);
}
static void interrupt_set_enabled(api_int_id_t id, bool enabled)
{
assert(id < EPIC_INT_NUM);
mutex_lock(&interrupt_mutex);
interrupt_data.int_enabled[id] = enabled;
mutex_unlock(&interrupt_mutex);
}
static bool interrupt_get_enabled(api_int_id_t id)
{
assert(id < EPIC_INT_NUM);
bool enabled;
mutex_lock(&interrupt_mutex);
enabled = interrupt_data.int_enabled[id];
mutex_unlock(&interrupt_mutex);
return enabled;
}
void interrupt_init(void)
{
if (interrupt_mutex.name == NULL)
mutex_create(&interrupt_mutex);
api_interrupt_init();
/* Reset all irqs to disabled */
for (size_t i = 0; i < EPIC_INT_NUM; i++) {
interrupt_set_enabled(i, false);
}
/* Reset interrupt is always enabled */
interrupt_set_enabled(EPIC_INT_RESET, true);
}
/* Epic-calls {{{ */
int epic_interrupt_enable(api_int_id_t int_id)
{
if (int_id >= EPIC_INT_NUM) {
return -EINVAL;
}
interrupt_set_enabled(int_id, true);
return 0;
}
int epic_interrupt_disable(api_int_id_t int_id)
{
if (int_id >= EPIC_INT_NUM || int_id == EPIC_INT_RESET) {
return -EINVAL;
}
interrupt_set_enabled(int_id, false);
return 0;
}
int epic_interrupt_is_enabled(api_int_id_t int_id, bool *enabled)
{
if (int_id >= EPIC_INT_NUM) {
return -EINVAL;
}
*enabled = interrupt_get_enabled(int_id);
return 0;
}
/* }}} */
void vInterruptsTask(void *pvParameters)
{
interrupts_task = xTaskGetCurrentTaskHandle();
while (true) {
mutex_lock(&interrupt_mutex);
if (!interrupt_data.has_pending) {
/* Wait for a wakeup event from interrupt_trigger() */
mutex_unlock(&interrupt_mutex);
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
mutex_lock(&interrupt_mutex);
}
while (!api_interrupt_is_ready()) {
mutex_unlock(&interrupt_mutex);
vTaskDelay(pdMS_TO_TICKS(5));
mutex_lock(&interrupt_mutex);
}
api_int_id_t current_irq = EPIC_INT_NUM;
for (size_t i = 0; i < EPIC_INT_NUM; i++) {
if (interrupt_data.int_pending[i]) {
current_irq = i;
interrupt_data.int_pending[i] = false;
break;
}
}
if (current_irq == EPIC_INT_NUM) {
interrupt_data.has_pending = false;
} else if (interrupt_data.int_enabled[current_irq]) {
api_interrupt_trigger(current_irq);
/* Break the dispatcher task out of a potential call
* to epic_sleep() */
xTaskNotifyGive(dispatcher_task_id);
}
mutex_unlock(&interrupt_mutex);
}
}
#pragma once
#include "epicardium.h"
/* ---------- Interrupts --------------------------------------------------- */
void interrupt_init(void);
void interrupt_trigger(api_int_id_t id);
void interrupt_trigger_sync(api_int_id_t id);
void interrupt_trigger_unsafe(api_int_id_t id) __attribute__((deprecated(
"interrupt_trigger_unsafe() is racy and only exists for legacy code."
)));
void vInterruptsTask(void *pvParameters);
#include "epicardium.h" #include "epicardium.h"
#include "modules/log.h" #include "os/core.h"
#include "modules/modules.h" #include "modules/modules.h"
#include "os/config.h"
#include "os/mutex.h"
#include "user_core/user_core.h"
#include "api/dispatcher.h" #include "api/dispatcher.h"
#include "api/interrupt-sender.h"
#include "l0der/l0der.h" #include "l0der/l0der.h"
#include "card10.h" #include "card10.h"
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "task.h" #include "task.h"
#include "semphr.h"
#include <assert.h>
#include <string.h> #include <string.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdbool.h> #include <stdbool.h>
#define PYCARDIUM_IVT (void *)0x10080000 #define PYCARDIUM_IVT (void *)0x100a0000
#define BLOCK_WAIT pdMS_TO_TICKS(1000) #define BLOCK_WAIT pdMS_TO_TICKS(1000)
/* /*
* Loading an empty filename into Pycardium will drop straight into the * Loading an empty filename into Pycardium will drop straight into the
...@@ -25,8 +27,7 @@ ...@@ -25,8 +27,7 @@
#define PYINTERPRETER "" #define PYINTERPRETER ""
static TaskHandle_t lifecycle_task = NULL; static TaskHandle_t lifecycle_task = NULL;
static StaticSemaphore_t core1_mutex_data; static struct mutex core1_mutex = { 0 };
static SemaphoreHandle_t core1_mutex = NULL;
enum payload_type { enum payload_type {
PL_INVALID = 0, PL_INVALID = 0,
...@@ -49,6 +50,7 @@ static volatile struct load_info async_load = { ...@@ -49,6 +50,7 @@ static volatile struct load_info async_load = {
/* Whether to write the menu script before attempting to load. */ /* Whether to write the menu script before attempting to load. */
static volatile bool write_menu = false; static volatile bool write_menu = false;
static bool execute_elfs = false;
/* Helpers {{{ */ /* Helpers {{{ */
...@@ -88,22 +90,30 @@ static int load_stat(char *name) ...@@ -88,22 +90,30 @@ static int load_stat(char *name)
*/ */
static int do_load(struct load_info *info) static int do_load(struct load_info *info)
{ {
#if defined(JAILBREAK_CARD10) && (JAILBREAK_CARD10 == 1)
struct l0dable_info l0dable; struct l0dable_info l0dable;
#endif
int res; int res;
/* Callers of do_load() must first lock the core1_mutex. */
mutex_assert_locked(&core1_mutex);
if (*info->name == '\0') { if (*info->name == '\0') {
LOG_INFO("lifecycle", "Loading Python interpreter ..."); LOG_INFO("lifecycle", "Loading Python interpreter ...");
} else { } else {
LOG_INFO("lifecycle", "Loading \"%s\" ...", info->name); LOG_INFO("lifecycle", "Loading \"%s\" ...", info->name);
} }
if (xSemaphoreTake(api_mutex, BLOCK_WAIT) != pdTRUE) { if (info->type == PL_L0DABLE && !execute_elfs) {
LOG_ERR("lifecycle", "API blocked"); LOG_WARN(
return -EBUSY; "lifecycle", "Execution of .elf l0dables is disabled."
);
return -EPERM;
} }
/* Signal the dispatcher to return early from applicable API calls. */
xTaskNotifyGive(dispatcher_task_id);
mutex_lock(&api_mutex);
if (info->do_reset) { if (info->do_reset) {
LOG_DEBUG("lifecycle", "Triggering core 1 reset."); LOG_DEBUG("lifecycle", "Triggering core 1 reset.");
...@@ -112,15 +122,33 @@ static int do_load(struct load_info *info) ...@@ -112,15 +122,33 @@ static int do_load(struct load_info *info)
/* /*
* Wait for the core to become ready to accept a new payload. * Wait for the core to become ready to accept a new payload.
*
* If it is not yet ready, hand back control of the API mutex to the
* dispatcher so it can finish dispatching a current API call. This is
* necessary for payloads which have interrupts disabled during an API
* call.
*/ */
core1_wait_ready(); while (!core1_is_ready()) {
/*
* Wake up the dispatcher task prematurely. This is needed so
* the second xTaskNotifyGive() below can then break out the
* dispatcher from e.g. an epic_sleep() call.
*/
xTaskNotifyGive(dispatcher_task_id);
mutex_unlock(&api_mutex);
/* Sleep so the dispatcher task can take the lock. */
vTaskDelay(8);
/* Signal the dispatcher to return early from applicable API calls. */
xTaskNotifyGive(dispatcher_task_id);
mutex_lock(&api_mutex);
}
/* /*
* Reinitialize Hardware & Drivers * Reinitialize Hardware & Drivers
*/ */
res = hardware_reset(); res = hardware_reset();
if (res < 0) { if (res < 0) {
return res; goto out_free_api;
} }
switch (info->type) { switch (info->type) {
...@@ -129,28 +157,30 @@ static int do_load(struct load_info *info) ...@@ -129,28 +157,30 @@ static int do_load(struct load_info *info)
case PL_PYTHON_INTERP: case PL_PYTHON_INTERP:
core1_load(PYCARDIUM_IVT, info->name); core1_load(PYCARDIUM_IVT, info->name);
break; break;
#if defined(JAILBREAK_CARD10) && (JAILBREAK_CARD10 == 1)
case PL_L0DABLE: case PL_L0DABLE:
assert(execute_elfs);
res = l0der_load_path(info->name, &l0dable); res = l0der_load_path(info->name, &l0dable);
if (res != 0) { if (res != 0) {
LOG_ERR("lifecycle", "l0der failed: %d\n", res); LOG_ERR("lifecycle", "l0der failed: %d\n", res);
xSemaphoreGive(api_mutex); res = -ENOEXEC;
return -ENOEXEC; goto out_free_api;
} }
core1_load(l0dable.isr_vector, "");
core1_load(l0dable.isr_vector, "");
break; break;
#endif
default: default:
LOG_ERR("lifecyle", LOG_ERR("lifecyle",
"Attempted to load invalid payload (%s)", "Attempted to load invalid payload (%s)",
info->name); info->name);
xSemaphoreGive(api_mutex); res = -EINVAL;
return -EINVAL; goto out_free_api;
} }
xSemaphoreGive(api_mutex); res = 0;
return 0; out_free_api:
mutex_unlock(&api_mutex);
return res;
} }
/* /*
...@@ -158,6 +188,9 @@ static int do_load(struct load_info *info) ...@@ -158,6 +188,9 @@ static int do_load(struct load_info *info)
*/ */
static int load_sync(char *name, bool reset) static int load_sync(char *name, bool reset)
{ {
/* Callers of load_sync() must first lock the core1_mutex. */
mutex_assert_locked(&core1_mutex);
int ret = load_stat(name); int ret = load_stat(name);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
...@@ -180,6 +213,9 @@ static int load_sync(char *name, bool reset) ...@@ -180,6 +213,9 @@ static int load_sync(char *name, bool reset)
*/ */
static int load_async(char *name, bool reset) static int load_async(char *name, bool reset)
{ {
/* Callers of load_async() must first lock the core1_mutex. */
mutex_assert_locked(&core1_mutex);
int ret = load_stat(name); int ret = load_stat(name);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
...@@ -250,11 +286,7 @@ static void load_menu(bool reset) ...@@ -250,11 +286,7 @@ static void load_menu(bool reset)
{ {
LOG_DEBUG("lifecycle", "Into the menu"); LOG_DEBUG("lifecycle", "Into the menu");
if (xSemaphoreTake(core1_mutex, BLOCK_WAIT) != pdTRUE) { mutex_lock(&core1_mutex);
LOG_ERR("lifecycle",
"Can't load because mutex is blocked (menu).");
return;
}
int ret = load_async("menu.py", reset); int ret = load_async("menu.py", reset);
if (ret < 0) { if (ret < 0) {
...@@ -274,7 +306,7 @@ static void load_menu(bool reset) ...@@ -274,7 +306,7 @@ static void load_menu(bool reset)
} }
} }
xSemaphoreGive(core1_mutex); mutex_unlock(&core1_mutex);
} }
/* Helpers }}} */ /* Helpers }}} */
...@@ -294,14 +326,9 @@ void epic_system_reset(void) ...@@ -294,14 +326,9 @@ void epic_system_reset(void)
*/ */
int epic_exec(char *name) int epic_exec(char *name)
{ {
if (xSemaphoreTake(core1_mutex, BLOCK_WAIT) != pdTRUE) { mutex_lock(&core1_mutex);
LOG_ERR("lifecycle",
"Can't load because mutex is blocked (epi exec).");
return -EBUSY;
}
int ret = load_sync(name, true); int ret = load_sync(name, true);
xSemaphoreGive(core1_mutex); mutex_unlock(&core1_mutex);
return ret; return ret;
} }
...@@ -314,13 +341,9 @@ int epic_exec(char *name) ...@@ -314,13 +341,9 @@ int epic_exec(char *name)
*/ */
int __epic_exec(char *name) int __epic_exec(char *name)
{ {
if (xSemaphoreTake(core1_mutex, BLOCK_WAIT) != pdTRUE) { mutex_lock(&core1_mutex);
LOG_ERR("lifecycle",
"Can't load because mutex is blocked (1 exec).");
return -EBUSY;
}
int ret = load_async(name, false); int ret = load_async(name, false);
xSemaphoreGive(core1_mutex); mutex_unlock(&core1_mutex);
return ret; return ret;
} }
...@@ -357,37 +380,37 @@ void return_to_menu(void) ...@@ -357,37 +380,37 @@ void return_to_menu(void)
void vLifecycleTask(void *pvParameters) void vLifecycleTask(void *pvParameters)
{ {
lifecycle_task = xTaskGetCurrentTaskHandle(); lifecycle_task = xTaskGetCurrentTaskHandle();
core1_mutex = xSemaphoreCreateMutexStatic(&core1_mutex_data); mutex_create(&core1_mutex);
mutex_lock(&core1_mutex);
if (xSemaphoreTake(core1_mutex, 0) != pdTRUE) {
LOG_CRIT(
"lifecycle", "Failed to acquire mutex after creation."
);
vTaskDelay(portMAX_DELAY);
}
LOG_DEBUG("lifecycle", "Booting core 1 ..."); LOG_DEBUG("lifecycle", "Booting core 1 ...");
core1_boot(); core1_boot();
vTaskDelay(pdMS_TO_TICKS(10)); vTaskDelay(pdMS_TO_TICKS(10));
xSemaphoreGive(core1_mutex); mutex_unlock(&core1_mutex);
/* If `main.py` exists, start it. Otherwise, start `menu.py`. */ /*
if (epic_exec("main.py") < 0) { * If `main.py` exists, start it. Otherwise, start `menu.py`.
return_to_menu(); *
* We are not using epic_exec() & return_to_menu() here because those
* trigger a reset which is undesirable during startup.
*/
mutex_lock(&core1_mutex);
int ret = load_sync("main.py", false);
mutex_unlock(&core1_mutex);
if (ret < 0) {
load_menu(false);
} }
hardware_init(); hardware_init();
execute_elfs = config_get_boolean_with_default("execute_elf", false);
/* When triggered, reset core 1 to menu */ /* When triggered, reset core 1 to menu */
while (1) { while (1) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY); ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
if (xSemaphoreTake(core1_mutex, BLOCK_WAIT) != pdTRUE) { mutex_lock(&core1_mutex);
LOG_ERR("lifecycle",
"Can't load because mutex is blocked (task).");
continue;
}
if (write_menu) { if (write_menu) {
write_menu = false; write_menu = false;
...@@ -401,8 +424,13 @@ void vLifecycleTask(void *pvParameters) ...@@ -401,8 +424,13 @@ void vLifecycleTask(void *pvParameters)
} }
} }
do_load((struct load_info *)&async_load); ret = do_load((struct load_info *)&async_load);
mutex_unlock(&core1_mutex);
xSemaphoreGive(core1_mutex); if (ret < 0) {
LOG_ERR("lifecycle", "Error loading payload: %d", ret);
return_to_menu();
}
} }
} }
user_core_sources = files(
'dispatcher.c',
'interrupts.c',
'lifecycle.c',
'migration.c',
)
#include "epicardium.h"
#include "os/core.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void migration_delete_app_launchers(void)
{
int fd = epic_file_opendir("/");
struct epic_stat entry;
for (;;) {
epic_file_readdir(fd, &entry);
if (entry.type == EPICSTAT_NONE) {
// End
break;
}
const char *dot = strrchr(entry.name, '.');
if (dot && !strcmp(dot, ".py")) {
const char launcher[] = "# Launcher script for ";
char launcher_buf[strlen(launcher)];
int fd = epic_file_open(entry.name, "r");
if (fd >= 0) {
int n = epic_file_read(
fd, launcher_buf, sizeof(launcher_buf)
);
epic_file_close(fd);
if (n == (int)sizeof(launcher_buf) &&
!memcmp(launcher,
launcher_buf,
sizeof(launcher_buf))) {
LOG_INFO(
"migration",
"Delete old launcher %s",
entry.name
);
epic_file_unlink(entry.name);
}
}
}
}
epic_file_close(fd);
}
#pragma once
#include "FreeRTOS.h"
#include "os/mutex.h"
/* ---------- Dispatcher --------------------------------------------------- */
void vApiDispatcher(void *pvParameters);
void dispatcher_mutex_init(void);
extern struct mutex api_mutex;
extern TaskHandle_t dispatcher_task_id;
/* ---------- Lifecycle ---------------------------------------------------- */
void vLifecycleTask(void *pvParameters);
void return_to_menu(void);
/* ---------- Migration ---------------------------------------------------- */
void migration_delete_app_launchers(void);
epicardium/version-splash.png

15 KiB

...@@ -3,27 +3,33 @@ ...@@ -3,27 +3,33 @@
******************************************************************************/ ******************************************************************************/
/***** Includes *****/ /***** Includes *****/
#include "pmic.h"
#include "leds.h"
#include "card10.h" #include "card10.h"
#include "leds.h"
#include "pmic.h"
#include "gfx.h"
#include "display.h" #include "display.h"
#include "gfx.h"
#include "tmr_utils.h" #include "tmr_utils.h"
#include <stdio.h> #include <Heart.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <Heart.h>
int main(void) int main(void)
{ {
card10_init(); card10_init();
card10_diag(); card10_diag();
gfx_copy_region_raw( gfx_copy_region(
&display_screen, 0, 0, 160, 80, 2, (const void *)(Heart) &display_screen,
0,
0,
160,
80,
GFX_RGB565,
(const void *)(Heart)
); );
gfx_update(&display_screen); gfx_update(&display_screen);
......
...@@ -401,11 +401,11 @@ int main(void) ...@@ -401,11 +401,11 @@ int main(void)
uint32_t ecgFIFO, readECGSamples, idx, ETAG[32], status; uint32_t ecgFIFO, readECGSamples, idx, ETAG[32], status;
int16_t ecgSample[32]; int16_t ecgSample[32];
const int EINT_STATUS_MASK = 1 << 23; const uint32_t EINT_STATUS_MASK = 1 << 23;
const int FIFO_OVF_MASK = 0x7; const uint32_t FIFO_OVF_MASK = 0x7;
const int FIFO_VALID_SAMPLE_MASK = 0x0; const uint32_t FIFO_VALID_SAMPLE_MASK = 0x0;
const int FIFO_FAST_SAMPLE_MASK = 0x1; const uint32_t FIFO_FAST_SAMPLE_MASK = 0x1;
const int ETAG_BITS_MASK = 0x7; const uint32_t ETAG_BITS_MASK = 0x7;
while (1) { while (1) {
#if 1 #if 1
......
...@@ -30,8 +30,14 @@ int main(void) ...@@ -30,8 +30,14 @@ int main(void)
card10_init(); card10_init();
card10_diag(); card10_diag();
gfx_copy_region_raw( gfx_copy_region(
&display_screen, 0, 0, 160, 80, 2, (const void *)(Heart) &display_screen,
0,
0,
160,
80,
GFX_RGB565,
(const void *)(Heart)
); );
gfx_update(&display_screen); gfx_update(&display_screen);
......
...@@ -37,22 +37,22 @@ int main(void) ...@@ -37,22 +37,22 @@ int main(void)
gfx_line(&display_screen, 100, 10, 70, 40, 2, yellow); gfx_line(&display_screen, 100, 10, 70, 40, 2, yellow);
gfx_circle(&display_screen, 85, 25, 22, 2, green); gfx_circle(&display_screen, 85, 25, 22, 2, green);
gfx_copy_region_raw( gfx_copy_region(
&display_screen, &display_screen,
120, 120,
0, 0,
40, 40,
40, 40,
2, GFX_RGB565,
(const void *)(gImage_40X40) (const void *)(gImage_40X40)
); );
gfx_copy_region_raw( gfx_copy_region(
&display_screen, &display_screen,
0, 0,
0, 0,
160, 160,
80, 80,
2, GFX_RGB565,
(const void *)(gImage_160X80) (const void *)(gImage_160X80)
); );
gfx_update(&display_screen); gfx_update(&display_screen);
......
...@@ -3,3 +3,33 @@ target remote localhost:3333 ...@@ -3,3 +3,33 @@ target remote localhost:3333
define reset define reset
mon mww 0x40000004 0x80000000 mon mww 0x40000004 0x80000000
end end
# usage: task_backtrace <tskTCB*>
define task_backtrace
set $taskbt_task_ptr = $arg0
set $taskbt_stack_ptr = $taskbt_task_ptr->pxTopOfStack
set $taskbt_frame_offset = 9
if ((*(uint32_t*)($taskbt_stack_ptr + 8)) & 0x10 == 0)
echo FPU is on\n
set $taskbt_frame_offset += 16
else
echo FPU is off\n
end
set $taskbt_reg_lr = $lr
set $taskbt_reg_pc = $pc
set $taskbt_reg_sp = $sp
set $lr = *($taskbt_stack_ptr + $taskbt_frame_offset + 5)
set $pc = *($taskbt_stack_ptr + $taskbt_frame_offset + 6)
set $sp = $taskbt_stack_ptr + $taskbt_frame_offset + 8
bt
set $lr = $taskbt_reg_lr
set $pc = $taskbt_reg_pc
set $sp = $taskbt_reg_sp
end
alias tbt = task_backtrace
...@@ -24,6 +24,9 @@ void fade() ...@@ -24,6 +24,9 @@ void fade()
/* /*
* main() is called when l0dable is loaded and executed. * main() is called when l0dable is loaded and executed.
*
* When main() returns, card10 goes back to the menu. A non-zero return value
* can be used to signal some kind of failure during l0dable execution.
*/ */
int main(void) int main(void)
{ {
......
...@@ -157,12 +157,9 @@ Reset_Handler: ...@@ -157,12 +157,9 @@ Reset_Handler:
ldr r0, =main ldr r0, =main
blx r0 blx r0
/* /* C code done, return to menu. Return code is what main() returned. */
* C code done, spin forever. ldr r4, =epic_exit
* TODO(q3k): let epicardium know we're done. blx r4
*/
.spin:
bl .spin
/* /*
* Used by __libc_init_array. * Used by __libc_init_array.
...@@ -190,15 +187,6 @@ DefaultHandler: ...@@ -190,15 +187,6 @@ DefaultHandler:
/* /*
* Declare all default ISRs. * Declare all default ISRs.
*/ */
def_irq_handler NMI_Handler
def_irq_handler HardFault_Handler
def_irq_handler MemManage_Handler
def_irq_handler BusFault_Handler
def_irq_handler UsageFault_Handler
def_irq_handler SVC_Handler
def_irq_handler DebugMon_Handler
def_irq_handler PendSV_Handler
def_irq_handler PF_IRQHandler def_irq_handler PF_IRQHandler
def_irq_handler WDT0_IRQHandler def_irq_handler WDT0_IRQHandler
def_irq_handler RTC_IRQHandler def_irq_handler RTC_IRQHandler
......
...@@ -128,3 +128,25 @@ uint32_t _sbrk(int incr) ...@@ -128,3 +128,25 @@ uint32_t _sbrk(int incr)
brk += incr; brk += incr;
return (uint32_t)prev_brk; return (uint32_t)prev_brk;
} }
void HardFault_Handler(void)
{
/*
* We pray that we're not currently in an API call and attempt
* returning. This is okay because a HardFault during an API call is
* extremely unlikely.
*
* In the future, we could improve this by "finishing" an ongoing API
* call before firing epic_exit().
*/
epic_exit(255);
}
/* Alias all other exception handlers to the HardFault_Handler. */
void NMI_Handler(void) __attribute__((alias("HardFault_Handler")));
void MemManage_Handler(void) __attribute__((alias("HardFault_Handler")));
void BusFault_Handler(void) __attribute__((alias("HardFault_Handler")));
void UsageFault_Handler(void) __attribute__((alias("HardFault_Handler")));
void SVC_Handler(void) __attribute__((alias("HardFault_Handler")));
void DebugMon_Handler(void) __attribute__((alias("HardFault_Handler")));
void PendSV_Handler(void) __attribute__((alias("HardFault_Handler")));