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 404 additions and 1455 deletions
......@@ -29,6 +29,17 @@ int epic_file_open(const char *filename, const char *mode)
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)
{
EpicFileSystem *fs;
......
......@@ -19,21 +19,19 @@
#include <timers.h>
#include "fs/internal.h"
#include "modules/filesystem.h"
#include "fs/filesystem.h"
#include "user_core/user_core.h"
#include "epicardium.h"
#include "card10.h"
#include "modules/log.h"
#include "os/core.h"
#include "modules/modules.h"
#include "api/common.h"
#include "os/mutex.h"
#define SSLOG_DEBUG(...) LOG_DEBUG("fatfs", __VA_ARGS__)
#define SSLOG_INFO(...) LOG_INFO("fatfs", __VA_ARGS__)
#define SSLOG_ERR(...) LOG_ERR("fatfs", __VA_ARGS__)
#ifndef EPIC_FAT_STATIC_SEMAPHORE
#define EPIC_FAT_STATIC_SEMAPHORE 0
#endif
/* clang-format off */
#define EPIC_FAT_MAX_OPENED (1 << (EPIC_FAT_FD_INDEX_BITS))
#define EPIC_FAT_FD_GENERATION_BITS (31 - (EPIC_FAT_FD_INDEX_BITS))
......@@ -67,8 +65,6 @@ struct EpicFileSystem {
static const int s_libffToErrno[20];
static const char *f_get_rc_string(FRESULT rc);
static bool globalLockAccquire();
static void globalLockRelease();
static void efs_close_all(EpicFileSystem *fs, int coreMask);
/**
......@@ -97,11 +93,7 @@ static void efs_init_stat(struct epic_stat *stat, FILINFO *finfo);
static EpicFileSystem s_globalFileSystem;
#if (EPIC_FAT_STATIC_SEMAPHORE == 1)
static StaticSemaphore_t s_globalLockBuffer;
#endif
static SemaphoreHandle_t s_globalLock = NULL;
static struct mutex fatfs_lock = { 0 };
static void cb_attachTimer(void *a, uint32_t b)
{
......@@ -118,11 +110,7 @@ void fatfs_init()
assert(!s_initCalled);
s_initCalled = true;
#if (EPIC_FAT_STATIC_SEMAPHORE == 1)
s_globalLock = xSemaphoreCreateMutexStatic(&s_globalLockBuffer);
#else
s_globalLock = xSemaphoreCreateMutex();
#endif
mutex_create(&fatfs_lock);
s_globalFileSystem.generationCount = 1;
fatfs_attach();
......@@ -142,7 +130,9 @@ int fatfs_attach()
{
FRESULT ff_res;
int rc = 0;
if (globalLockAccquire()) {
mutex_lock(&fatfs_lock);
EpicFileSystem *fs = &s_globalFileSystem;
if (!fs->attached) {
ff_res = f_mount(&fs->FatFs, "/", 0);
......@@ -151,17 +141,13 @@ int fatfs_attach()
SSLOG_INFO("attached\n");
} else {
SSLOG_ERR(
"f_mount error %s\n",
f_get_rc_string(ff_res)
"f_mount error %s\n", f_get_rc_string(ff_res)
);
rc = -s_libffToErrno[ff_res];
}
}
globalLockRelease();
} else {
SSLOG_ERR("Failed to lock\n");
}
mutex_unlock(&fatfs_lock);
return rc;
}
......@@ -227,24 +213,12 @@ static const char *f_get_rc_string(FRESULT rc)
return p;
}
static bool globalLockAccquire()
{
return (int)(xSemaphoreTake(s_globalLock, FF_FS_TIMEOUT) == pdTRUE);
}
static void globalLockRelease()
{
xSemaphoreGive(s_globalLock);
}
int efs_lock_global(EpicFileSystem **fs)
{
*fs = NULL;
if (!globalLockAccquire()) {
return -EBUSY;
}
mutex_lock(&fatfs_lock);
if (!s_globalFileSystem.attached) {
globalLockRelease();
mutex_unlock(&fatfs_lock);
return -ENODEV;
}
*fs = &s_globalFileSystem;
......@@ -259,7 +233,7 @@ int efs_lock_global(EpicFileSystem **fs)
void efs_unlock_global(EpicFileSystem *fs)
{
(void)fs;
globalLockRelease();
mutex_unlock(&fatfs_lock);
}
static bool efs_get_opened(
......@@ -312,6 +286,7 @@ efs_get_new(EpicFileSystem *fs, uint32_t *idx, struct FatObject **obj, int *rc)
}
*obj = &fs->pool[index];
*idx = index;
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 @@
#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 "modules/modules.h"
#include "modules/log.h"
#include "modules/filesystem.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"
......@@ -9,6 +18,9 @@
#include <stdlib.h>
#include <string.h>
#include <machine/endian.h>
#include "epic_boot.c"
int main(void)
{
......@@ -20,16 +32,75 @@ int main(void)
LOG_DEBUG("startup", "Initializing hardware ...");
hardware_early_init();
/*
* Version Splash
*/
const char *version_buf = CARD10_VERSION;
const int offset = (160 - (int)strlen(version_buf) * 14) / 2;
epic_disp_clear(0x3b7);
epic_disp_print(10, 20, "Epicardium", 0x290, 0x3b7);
epic_disp_print(offset > 0 ? offset : 0, 40, version_buf, 0x290, 0x3b7);
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: 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");
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;
}
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 ...");
......@@ -41,20 +112,18 @@ int main(void)
NULL,
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) {
LOG_CRIT("startup", "Failed to create %s task!", "PMIC");
abort();
panic("Failed to create %s task!", "PMIC");
}
/* BHI160 */
......@@ -65,8 +134,7 @@ int main(void)
NULL,
tskIDLE_PRIORITY + 1,
NULL) != pdPASS) {
LOG_CRIT("startup", "Failed to create %s task!", "BHI160");
abort();
panic("Failed to create %s task!", "BHI160");
}
/* MAX30001 */
......@@ -77,9 +145,36 @@ int main(void)
NULL,
tskIDLE_PRIORITY + 1,
NULL) != pdPASS) {
LOG_CRIT("startup", "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 */
if (xTaskCreate(
vApiDispatcher,
......@@ -88,51 +183,54 @@ 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_shall_start()) {
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");
}
}
/* LEDs */
/* Lifecycle */
if (xTaskCreate(
vLedTask,
(const char *)"LED",
configMINIMAL_STACK_SIZE,
vLifecycleTask,
(const char *)"Lifecycle",
configMINIMAL_STACK_SIZE * 4,
NULL,
tskIDLE_PRIORITY + 1,
tskIDLE_PRIORITY + 3,
NULL) != pdPASS) {
LOG_CRIT("startup", "Failed to create %s task!", "LED");
abort();
panic("Failed to create %s task!", "Lifecycle");
}
/* Lifecycle */
/* Work Queue */
if (xTaskCreate(
vLifecycleTask,
(const char *)"Lifecycle",
vWorkQueueTask,
(const char *)"Work Queue",
configMINIMAL_STACK_SIZE * 4,
NULL,
tskIDLE_PRIORITY + 3,
tskIDLE_PRIORITY + 1,
NULL) != pdPASS) {
LOG_CRIT("startup", "Failed to create %s task!", "Lifecycle");
abort();
panic("Failed to create %s task!", "Work Queue");
}
workqueue_init();
/*
* Initialize serial driver data structures.
......@@ -142,6 +240,5 @@ int main(void)
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!");
}
......@@ -66,17 +66,32 @@ freertos = static_library(
##########################################################################
subdir('modules/')
subdir('drivers/')
subdir('user_core/')
subdir('ble/')
subdir('os/')
subdir('fs/')
subdir('l0der/')
epicardium_cargs = []
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',
......@@ -85,12 +100,16 @@ elf = executable(
'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, bhy1],
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],
......
#include <stdio.h>
#include <string.h>
#include "gpio.h"
#include "bhy_uc_driver.h"
#include "bhy.h"
#include "pmic.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "queue.h"
#include "api/interrupt-sender.h"
#include "epicardium.h"
#include "modules/log.h"
#include "modules/modules.h"
#include "modules/stream.h"
/* Ticks to wait when trying to acquire lock */
#define LOCK_WAIT pdMS_TO_TICKS(BHI160_MUTEX_WAIT_MS)
/* BHI160 Firmware Blob. Contents are defined in libcard10. */
extern uint8_t bhy1_fw[];
/* Interrupt Pin */
static const gpio_cfg_t bhi160_interrupt_pin = {
PORT_0, PIN_13, GPIO_FUNC_IN, GPIO_PAD_PULL_UP
};
/* Axis remapping matrices */
static int8_t bhi160_mapping_matrix[3 * 3] = { 0, -1, 0, 1, 0, 0, 0, 0, 1 };
static int8_t bmm150_mapping_matrix[3 * 3] = { -1, 0, 0, 0, 1, 0, 0, 0, -1 };
/*
* From the official docs:
*
* The sic matrix should be calculated for customer platform by logging
* uncalibrated magnetometer data. The sic matrix here is only an example
* array (identity matrix). Customer should generate their own matrix. This
* affects magnetometer fusion performance.
*
* TODO: Get data for card10
*/
/* clang-format off */
static float bhi160_sic_array[3 * 3] = { 1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0 };
/* clang-format on */
/* BHI160 Fifo */
static uint8_t bhi160_fifo[BHI160_FIFO_SIZE];
static size_t start_index = 0;
/* BHI160 Task ID */
static TaskHandle_t bhi160_task_id = NULL;
/* BHI160 Mutex */
static StaticSemaphore_t bhi160_mutex_data;
static SemaphoreHandle_t bhi160_mutex = NULL;
/* Streams */
static struct stream_info bhi160_streams[10];
/* Active */
static bool bhi160_sensor_active[10] = { 0 };
/* -- Utilities -------------------------------------------------------- {{{ */
/*
* Retrieve the data size for a sensor. This value is needed for the creation
* of the sensor's sample queue.
*/
static size_t bhi160_lookup_data_size(enum bhi160_sensor_type type)
{
switch (type) {
case BHI160_ACCELEROMETER:
case BHI160_MAGNETOMETER:
case BHI160_ORIENTATION:
case BHI160_GYROSCOPE:
return sizeof(struct bhi160_data_vector);
default:
return 0;
}
}
/*
* Map a sensor type to the virtual sensor ID used by BHy1.
*/
static bhy_virtual_sensor_t bhi160_lookup_vs_id(enum bhi160_sensor_type type)
{
switch (type) {
case BHI160_ACCELEROMETER:
return VS_ID_ACCELEROMETER;
case BHI160_ORIENTATION:
return VS_ID_ORIENTATION;
case BHI160_GYROSCOPE:
return VS_ID_GYROSCOPE;
default:
return -1;
}
}
/*
* Map a sensor type to its stream descriptor.
*/
static int bhi160_lookup_sd(enum bhi160_sensor_type type)
{
switch (type) {
case BHI160_ACCELEROMETER:
return SD_BHI160_ACCELEROMETER;
case BHI160_ORIENTATION:
return SD_BHI160_ORIENTATION;
case BHI160_GYROSCOPE:
return SD_BHI160_GYROSCOPE;
default:
return -1;
}
}
/* }}} */
/* -- API -------------------------------------------------------------- {{{ */
int epic_bhi160_enable_sensor(
enum bhi160_sensor_type sensor_type,
struct bhi160_sensor_config *config
) {
int result = 0;
bhy_virtual_sensor_t vs_id = bhi160_lookup_vs_id(sensor_type);
if (vs_id < 0) {
return -ENODEV;
}
result = hwlock_acquire(HWLOCK_I2C, pdMS_TO_TICKS(100));
if (result < 0) {
return result;
}
if (xSemaphoreTake(bhi160_mutex, LOCK_WAIT) != pdTRUE) {
result = -EBUSY;
goto out_free_i2c;
}
struct stream_info *stream = &bhi160_streams[sensor_type];
stream->item_size = bhi160_lookup_data_size(sensor_type);
/* TODO: Sanity check length */
stream->queue =
xQueueCreate(config->sample_buffer_len, stream->item_size);
if (stream->queue == NULL) {
result = -ENOMEM;
goto out_free_both;
}
result = stream_register(bhi160_lookup_sd(sensor_type), stream);
if (result < 0) {
goto out_free_both;
}
result = bhy_enable_virtual_sensor(
vs_id,
VS_WAKEUP,
config->sample_rate,
0,
VS_FLUSH_NONE,
0,
config->dynamic_range /* dynamic range is sensor dependent */
);
if (result != BHY_SUCCESS) {
goto out_free_both;
}
bhi160_sensor_active[sensor_type] = true;
result = bhi160_lookup_sd(sensor_type);
out_free_both:
xSemaphoreGive(bhi160_mutex);
out_free_i2c:
hwlock_release(HWLOCK_I2C);
return result;
}
int epic_bhi160_disable_sensor(enum bhi160_sensor_type sensor_type)
{
int result = 0;
bhy_virtual_sensor_t vs_id = bhi160_lookup_vs_id(sensor_type);
if (vs_id < 0) {
return -ENODEV;
}
result = hwlock_acquire(HWLOCK_I2C, pdMS_TO_TICKS(100));
if (result < 0) {
return result;
}
if (xSemaphoreTake(bhi160_mutex, LOCK_WAIT) != pdTRUE) {
result = -EBUSY;
goto out_free_i2c;
}
struct stream_info *stream = &bhi160_streams[sensor_type];
result = stream_deregister(bhi160_lookup_sd(sensor_type), stream);
if (result < 0) {
goto out_free_both;
}
vQueueDelete(stream->queue);
stream->queue = NULL;
result = bhy_disable_virtual_sensor(vs_id, VS_WAKEUP);
if (result < 0) {
goto out_free_both;
}
bhi160_sensor_active[sensor_type] = false;
result = 0;
out_free_both:
xSemaphoreGive(bhi160_mutex);
out_free_i2c:
hwlock_release(HWLOCK_I2C);
return result;
}
void epic_bhi160_disable_all_sensors()
{
for (int i = 0; i < sizeof(bhi160_sensor_active); i++) {
if (bhi160_sensor_active[i]) {
epic_bhi160_disable_sensor(i);
}
}
}
/* }}} */
/* -- Driver ----------------------------------------------------------- {{{ */
/*
* Handle a single packet from the FIFO. For most sensors this means pushing
* the sample into its sample queue.
*/
static void
bhi160_handle_packet(bhy_data_type_t data_type, bhy_data_generic_t *sensor_data)
{
uint8_t sensor_id = sensor_data->data_vector.sensor_id;
struct bhi160_data_vector data_vector;
/*
* Timestamp of the next samples, counting at 32 kHz.
* Currently unused.
*/
static uint32_t timestamp = 0;
enum bhi160_sensor_type sensor_type = 0;
int epic_int = 0;
bool wakeup = false;
switch (sensor_id) {
case VS_ID_TIMESTAMP_MSW_WAKEUP:
wakeup = true;
/* fall through */
case VS_ID_TIMESTAMP_MSW:
MXC_ASSERT(data_type == BHY_DATA_TYPE_SCALAR_U16);
timestamp = sensor_data->data_scalar_u16.data << 16;
break;
case VS_ID_TIMESTAMP_LSW_WAKEUP:
wakeup = true;
/* fall through */
case VS_ID_TIMESTAMP_LSW:
MXC_ASSERT(data_type == BHY_DATA_TYPE_SCALAR_U16);
timestamp = (timestamp & 0xFFFF0000) |
sensor_data->data_scalar_u16.data;
break;
case VS_ID_ACCELEROMETER_WAKEUP:
case VS_ID_ORIENTATION_WAKEUP:
case VS_ID_GYROSCOPE_WAKEUP:
wakeup = true;
/* fall through */
case VS_ID_ACCELEROMETER:
case VS_ID_ORIENTATION:
case VS_ID_GYROSCOPE:
switch (sensor_id) {
case VS_ID_ACCELEROMETER_WAKEUP:
case VS_ID_ACCELEROMETER:
sensor_type = BHI160_ACCELEROMETER;
epic_int = EPIC_INT_BHI160_ACCELEROMETER;
break;
case VS_ID_ORIENTATION_WAKEUP:
case VS_ID_ORIENTATION:
sensor_type = BHI160_ORIENTATION;
epic_int = EPIC_INT_BHI160_ORIENTATION;
break;
case VS_ID_GYROSCOPE_WAKEUP:
case VS_ID_GYROSCOPE:
sensor_type = BHI160_GYROSCOPE;
epic_int = EPIC_INT_BHI160_GYROSCOPE;
break;
}
MXC_ASSERT(data_type == BHY_DATA_TYPE_VECTOR);
if (bhi160_streams[sensor_type].queue == NULL) {
break;
}
data_vector.data_type = BHI160_DATA_TYPE_VECTOR;
data_vector.x = sensor_data->data_vector.x;
data_vector.y = sensor_data->data_vector.y;
data_vector.z = sensor_data->data_vector.z;
data_vector.status = sensor_data->data_vector.status;
xQueueSend(
bhi160_streams[sensor_type].queue,
&data_vector,
BHI160_MUTEX_WAIT_MS
);
if (wakeup) {
api_interrupt_trigger(epic_int);
}
break;
default:
break;
}
}
/*
* Fetch all data available from BHI160's FIFO buffer and handle all packets
* contained in it.
*/
static int bhi160_fetch_fifo(void)
{
/*
* Warning: The code from the BHy1 docs has some issues. This
* implementation looks similar, but has a few important differences.
* You'll probably be best of leaving it as it is ...
*/
int result = 0;
/* Number of bytes left in BHI160's FIFO buffer */
uint16_t bytes_left_in_fifo = 1;
result = hwlock_acquire(HWLOCK_I2C, pdMS_TO_TICKS(100));
if (result < 0) {
return result;
}
if (xSemaphoreTake(bhi160_mutex, LOCK_WAIT) != pdTRUE) {
result = -EBUSY;
goto out_free_i2c;
}
while (bytes_left_in_fifo) {
/* Fill local FIFO buffer with as many bytes as possible */
uint16_t bytes_read;
bhy_read_fifo(
&bhi160_fifo[start_index],
BHI160_FIFO_SIZE - start_index,
&bytes_read,
&bytes_left_in_fifo
);
/* Add the bytes left from the last transfer on top */
bytes_read += start_index;
/* Handle all full packets received in this transfer */
uint8_t *fifo_ptr = bhi160_fifo;
uint16_t bytes_left = bytes_read;
while (bytes_left > 0) {
bhy_data_generic_t sensor_data;
bhy_data_type_t data_type;
result = bhy_parse_next_fifo_packet(
&fifo_ptr,
&bytes_left,
&sensor_data,
&data_type
);
if (result == BHY_SUCCESS) {
bhi160_handle_packet(data_type, &sensor_data);
} else {
break;
}
}
/* Shift the remaining bytes to the beginning */
for (int i = 0; i < bytes_left; i++) {
bhi160_fifo[i] =
bhi160_fifo[bytes_read - bytes_left + i];
}
start_index = bytes_left;
}
xSemaphoreGive(bhi160_mutex);
out_free_i2c:
hwlock_release(HWLOCK_I2C);
return result;
}
/*
* Callback for the BHI160 interrupt pin. This callback is called from the
* SDK's GPIO interrupt driver, in interrupt context.
*/
static void bhi160_interrupt_callback(void *_)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if (bhi160_task_id != NULL) {
vTaskNotifyGiveFromISR(
bhi160_task_id, &xHigherPriorityTaskWoken
);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
/* }}} */
void vBhi160Task(void *pvParameters)
{
int ret;
bhi160_task_id = xTaskGetCurrentTaskHandle();
bhi160_mutex = xSemaphoreCreateMutexStatic(&bhi160_mutex_data);
/*
* Wait a little before initializing BHI160.
*/
vTaskDelay(pdMS_TO_TICKS(3));
int lockret = hwlock_acquire(HWLOCK_I2C, pdMS_TO_TICKS(100));
if (lockret < 0) {
LOG_CRIT("bhi160", "Failed to acquire I2C lock!");
vTaskDelay(portMAX_DELAY);
}
/* Take Mutex during initialization, just in case */
if (xSemaphoreTake(bhi160_mutex, 0) != pdTRUE) {
LOG_CRIT("bhi160", "Failed to acquire BHI160 mutex!");
vTaskDelay(portMAX_DELAY);
}
memset(bhi160_streams, 0x00, sizeof(bhi160_streams));
/* Install interrupt callback */
GPIO_Config(&bhi160_interrupt_pin);
GPIO_RegisterCallback(
&bhi160_interrupt_pin, bhi160_interrupt_callback, NULL
);
GPIO_IntConfig(&bhi160_interrupt_pin, GPIO_INT_EDGE, GPIO_INT_RISING);
GPIO_IntEnable(&bhi160_interrupt_pin);
NVIC_SetPriority(
(IRQn_Type)MXC_GPIO_GET_IRQ(bhi160_interrupt_pin.port), 2
);
NVIC_EnableIRQ((IRQn_Type)MXC_GPIO_GET_IRQ(bhi160_interrupt_pin.port));
/* Upload firmware */
ret = bhy_driver_init(bhy1_fw);
if (ret) {
LOG_CRIT("bhi160", "BHy1 init failed!");
vTaskDelay(portMAX_DELAY);
}
/* Wait for first interrupt */
hwlock_release(HWLOCK_I2C);
ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(100));
lockret = hwlock_acquire(HWLOCK_I2C, pdMS_TO_TICKS(100));
if (lockret < 0) {
LOG_CRIT("bhi160", "Failed to acquire I2C lock!");
vTaskDelay(portMAX_DELAY);
}
/* Remap axes to match card10 layout */
bhy_mapping_matrix_set(
PHYSICAL_SENSOR_INDEX_ACC, bhi160_mapping_matrix
);
bhy_mapping_matrix_set(
PHYSICAL_SENSOR_INDEX_MAG, bmm150_mapping_matrix
);
bhy_mapping_matrix_set(
PHYSICAL_SENSOR_INDEX_GYRO, bhi160_mapping_matrix
);
/* Set "SIC" matrix. TODO: Find out what this is about */
bhy_set_sic_matrix(bhi160_sic_array);
xSemaphoreGive(bhi160_mutex);
hwlock_release(HWLOCK_I2C);
/* ----------------------------------------- */
while (1) {
int ret = bhi160_fetch_fifo();
if (ret == -EBUSY) {
LOG_WARN("bhi160", "Could not acquire mutex for FIFO?");
continue;
} else if (ret < 0) {
LOG_ERR("bhi160", "Unknown error: %d", -ret);
}
/*
* Wait for interrupt. After two seconds, fetch FIFO anyway in
* case there are any diagnostics or errors.
*
* In the future, reads using epic_stream_read() might also
* trigger a FIFO fetch, from outside this task.
*/
ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(2000));
}
}
#include "epicardium.h"
#include "modules/modules.h"
#include "modules/log.h"
#include "card10.h"
#include "bme680.h"
#include "bosch.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#define HEATR_TEMP 320
#define HEATR_DUR 150
static bool initialized;
static struct bme680_dev bme;
static int convert_error(int8_t error)
{
switch (error) {
case BME680_OK:
return 0;
case BME680_E_NULL_PTR:
return EFAULT;
case BME680_E_COM_FAIL:
return EIO;
case BME680_E_DEV_NOT_FOUND:
return ENODEV;
case BME680_E_INVALID_LENGTH:
return EINVAL;
default:
return 1;
}
}
int epic_bme680_init()
{
int8_t result = BME680_OK;
if (initialized) {
return 0;
}
if (hwlock_acquire(HWLOCK_I2C, pdMS_TO_TICKS(100)) < 0) {
return -EBUSY;
}
bme.dev_id = BME680_I2C_ADDR_PRIMARY;
bme.intf = BME680_I2C_INTF;
bme.read = card10_bosch_i2c_read;
bme.write = card10_bosch_i2c_write;
bme.delay_ms = card10_bosch_delay;
/*
* amb_temp can be set to 25 prior to configuring the gas sensor
* or by performing a few temperature readings without operating
* the gas sensor.
*/
bme.amb_temp = 25;
result = bme680_init(&bme);
if (result != BME680_OK) {
LOG_ERR("bme680", "bme680_init error: %d\n", result);
goto err;
}
/*
* Select the power mode. Must be set before writing the sensor
* configuration
*/
bme.power_mode = BME680_FORCED_MODE;
/* Set the temperature, pressure and humidity settings */
bme.tph_sett.os_hum = BME680_OS_2X;
bme.tph_sett.os_pres = BME680_OS_4X;
bme.tph_sett.os_temp = BME680_OS_8X;
bme.tph_sett.filter = BME680_FILTER_SIZE_3;
/* Set the remaining gas sensor settings and link the heating profile */
bme.gas_sett.run_gas = BME680_ENABLE_GAS_MEAS;
/* Create a ramp heat waveform in 3 steps */
bme.gas_sett.heatr_temp = HEATR_TEMP; /* degree Celsius */
bme.gas_sett.heatr_dur = HEATR_DUR; /* milliseconds */
/* Set the required sensor settings needed */
uint16_t settings_sel = BME680_OST_SEL | BME680_OSP_SEL |
BME680_OSH_SEL | BME680_FILTER_SEL |
BME680_GAS_SENSOR_SEL;
result = bme680_set_sensor_settings(settings_sel, &bme);
if (result != BME680_OK) {
LOG_ERR("bme680",
"bme680_set_sensor_settings error: %d\n",
result);
goto err;
}
initialized = true;
result = BME680_OK;
err:
hwlock_release(HWLOCK_I2C);
return -convert_error(result);
}
int epic_bme680_deinit()
{
if (!initialized) {
return 0;
}
if (hwlock_acquire(HWLOCK_I2C, pdMS_TO_TICKS(100)) < 0) {
return -EBUSY;
}
int8_t result = bme680_soft_reset(&bme);
if (result != BME680_OK) {
LOG_ERR("bme680", "bme680_soft_reset error: %d\n", result);
}
hwlock_release(HWLOCK_I2C);
initialized = false;
return 0;
}
int epic_bme680_read_sensors(struct bme680_sensor_data *data)
{
int8_t result = BME680_OK;
if (!initialized) {
LOG_ERR("bme680", "bme680 sensor not initialized");
return -EINVAL;
}
if (hwlock_acquire(HWLOCK_I2C, pdMS_TO_TICKS(100)) < 0) {
return -EBUSY;
}
uint16_t profile_dur = 0;
bme680_get_profile_dur(&profile_dur, &bme);
result = bme680_set_sensor_mode(&bme); /* Trigger a measurement */
if (result != BME680_OK) {
LOG_ERR("bme680", "bme680_set_sensor_mode error: %d\n", result);
goto err;
}
/*
* Wait for the measurement to complete. Release the I2C lock in the
* meantime.
*/
hwlock_release(HWLOCK_I2C);
vTaskDelay(pdMS_TO_TICKS(profile_dur));
if (hwlock_acquire(HWLOCK_I2C, pdMS_TO_TICKS(100)) < 0) {
return -EBUSY;
}
struct bme680_field_data raw_data;
result = bme680_get_sensor_data(&raw_data, &bme);
if (result != BME680_OK) {
LOG_ERR("bme680", "bme680_get_sensor_data error: %d\n", result);
goto err;
}
data->temperature = (float)raw_data.temperature / 100.0f;
data->humidity = raw_data.humidity / 1000.0f;
data->pressure = raw_data.pressure / 100.0f;
data->gas_resistance = raw_data.gas_resistance;
result = BME680_OK;
err:
hwlock_release(HWLOCK_I2C);
return -convert_error(result);
}
#include "modules/log.h"
#include "api/dispatcher.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#define TIMEOUT pdMS_TO_TICKS(2000)
TaskHandle_t dispatcher_task_id;
static StaticSemaphore_t api_mutex_data;
SemaphoreHandle_t api_mutex = NULL;
void dispatcher_mutex_init(void)
{
api_mutex = xSemaphoreCreateMutexStatic(&api_mutex_data);
}
/*
* 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()) {
if (xSemaphoreTake(api_mutex, TIMEOUT) != pdTRUE) {
LOG_ERR("dispatcher", "API mutex blocked");
continue;
}
api_dispatcher_exec();
xSemaphoreGive(api_mutex);
}
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
}
}
#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_backlight(uint16_t brightness)
{
int cl = check_lock();
if (cl < 0) {
return cl;
}
LCD_SetBacklight(brightness);
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;
}
#include "epicardium.h"
#include "gpio.h"
#include "max32665.h"
#include "mxc_errors.h"
/*
* Despite what the schematic (currently, 2019-08-18) says these are the correct
* pins for wristband GPIO 1-4 (not 0-3 as the schematic states)
*/
static gpio_cfg_t gpio_configs[] = {
[EPIC_GPIO_WRISTBAND_1] = { PORT_0,
PIN_21,
GPIO_FUNC_OUT,
GPIO_PAD_NONE },
[EPIC_GPIO_WRISTBAND_2] = { PORT_0,
PIN_22,
GPIO_FUNC_OUT,
GPIO_PAD_NONE },
[EPIC_GPIO_WRISTBAND_3] = { PORT_0,
PIN_29,
GPIO_FUNC_OUT,
GPIO_PAD_NONE },
[EPIC_GPIO_WRISTBAND_4] = { PORT_0,
PIN_20,
GPIO_FUNC_OUT,
GPIO_PAD_NONE },
};
int epic_gpio_set_pin_mode(uint8_t pin, uint8_t mode)
{
if (pin < EPIC_GPIO_WRISTBAND_1 || pin > EPIC_GPIO_WRISTBAND_4)
return -EINVAL;
gpio_cfg_t *cfg = &gpio_configs[pin];
if (mode & EPIC_GPIO_MODE_IN) {
cfg->func = GPIO_FUNC_IN;
if (mode & EPIC_GPIO_MODE_OUT) {
return -EINVAL;
}
} else if (mode & EPIC_GPIO_MODE_OUT) {
cfg->func = GPIO_FUNC_OUT;
if (mode & EPIC_GPIO_MODE_IN) {
return -EINVAL;
}
} else {
return -EINVAL;
}
if (mode & EPIC_GPIO_PULL_UP) {
cfg->pad = GPIO_PAD_PULL_UP;
} else if (mode & EPIC_GPIO_PULL_DOWN) {
cfg->pad = GPIO_PAD_PULL_DOWN;
} else {
cfg->pad = GPIO_PAD_NONE;
}
if (GPIO_Config(cfg) != E_NO_ERROR)
return -EINVAL;
return 0;
}
int epic_gpio_get_pin_mode(uint8_t pin)
{
if (pin < EPIC_GPIO_WRISTBAND_1 || pin > EPIC_GPIO_WRISTBAND_4)
return -EINVAL;
gpio_cfg_t *cfg = &gpio_configs[pin];
int res = 0;
if (cfg->func == GPIO_FUNC_IN)
res |= EPIC_GPIO_MODE_IN;
else if (cfg->func == GPIO_FUNC_OUT)
res |= EPIC_GPIO_MODE_OUT;
if (cfg->pad == GPIO_PAD_PULL_UP)
res |= EPIC_GPIO_PULL_UP;
else if (cfg->pad == GPIO_PAD_PULL_DOWN)
res |= EPIC_GPIO_PULL_DOWN;
return res;
}
int epic_gpio_write_pin(uint8_t pin, bool on)
{
if (pin < EPIC_GPIO_WRISTBAND_1 || pin > EPIC_GPIO_WRISTBAND_4)
return -EINVAL;
gpio_cfg_t *cfg = &gpio_configs[pin];
if (cfg->func == GPIO_FUNC_IN)
return -EINVAL;
if (on)
GPIO_OutSet(cfg);
else
GPIO_OutClr(cfg);
return 0;
}
int epic_gpio_read_pin(uint8_t pin)
{
if (pin < EPIC_GPIO_WRISTBAND_1 || pin > EPIC_GPIO_WRISTBAND_4)
return -EINVAL;
gpio_cfg_t *cfg = &gpio_configs[pin];
if (cfg->func == GPIO_FUNC_OUT) {
return GPIO_OutGet(cfg) != 0;
} else if (cfg->func == GPIO_FUNC_IN) {
return GPIO_InGet(cfg) != 0;
} else {
return -EINVAL;
}
}
#include "epicardium.h"
#include "api/dispatcher.h"
#include "api/interrupt-sender.h"
#include "usb/epc_usb.h"
#include "modules/filesystem.h"
#include "modules/log.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 "display.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 "trng.h"
#include "wdt.h"
/*
......@@ -54,6 +56,13 @@ int hardware_early_init(void)
*/
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)
*/
......@@ -67,40 +76,34 @@ int hardware_early_init(void)
*/
portexpander_init();
/*
* RNG
*/
TRNG_Init(NULL);
/*
* Buttons
*/
PB_Init();
/* Enable 32 kHz output */
while (RTC_SquareWave(
MXC_RTC,
SQUARE_WAVE_ENABLED,
F_32KHZ,
NOISE_IMMUNE_MODE,
NULL) == E_BUSY
)
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() < 1546300800UL) {
if (RTC_GetSecond() < 1546300800L) {
epic_rtc_set_milliseconds(1546300800UL * 1000);
}
/*
* SPI for ECG
*/
const sys_cfg_spi_t spi17y_master_cfg = {
.map = MAP_A,
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");
......@@ -109,10 +112,9 @@ int hardware_early_init(void)
}
/*
* The bootloader has already initialized the display, so we only need
* to do the bare minimum here (mostly the gfx datastructures).
* Display
*/
display_init_slim();
disp_init();
/*
* RGB LEDs
......@@ -164,7 +166,7 @@ int hardware_early_init(void)
/*
* API Dispatcher & API Interrupts
*/
api_interrupt_init();
interrupt_init();
api_dispatcher_init();
/*
......@@ -187,6 +189,21 @@ int hardware_early_init(void)
*/
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;
}
......@@ -222,7 +239,7 @@ int hardware_reset(void)
/*
* API Dispatcher & API Interrupts
*/
api_interrupt_init();
interrupt_init();
api_dispatcher_init();
/*
......@@ -253,19 +270,32 @@ int hardware_reset(void)
/*
* Display
*/
display_init_slim();
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();
/*
* BME680 Sensor
* BLE
*/
epic_bme680_deinit();
epic_max30001_disable_sensor();
/* Reset advertisement data */
ble_adv_setup();
/* Start advertising again if needed */
epic_ble_set_mode(false, false);
return 0;
}
#include "modules/log.h"
#include "os/core.h"
#include "modules/modules.h"
#include "os/mutex.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include <errno.h>
static StaticSemaphore_t hwlock_mutex_data[_HWLOCK_MAX];
static SemaphoreHandle_t hwlock_mutex[_HWLOCK_MAX];
/* Which task is holding the lock */
static TaskHandle_t hwlock_tasks[_HWLOCK_MAX];
static struct mutex hwlock_mutex[_HWLOCK_MAX] = { { 0 } };
void hwlock_init(void)
{
for (int i = 0; i < _HWLOCK_MAX; i++) {
hwlock_mutex[i] =
xSemaphoreCreateMutexStatic(&hwlock_mutex_data[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]);
}
}
int hwlock_acquire(enum hwlock_periph p, TickType_t wait)
void hwlock_acquire(enum hwlock_periph p)
{
if (p >= _HWLOCK_MAX) {
return -EINVAL;
assert(p < _HWLOCK_MAX);
mutex_lock(&hwlock_mutex[p]);
}
TaskHandle_t task = xTaskGetCurrentTaskHandle();
if (xSemaphoreTake(hwlock_mutex[p], wait) != pdTRUE) {
/* Don't print warnings for 0 wait acquires */
if (wait == 0) {
return -EBUSY;
}
LOG_WARN(
"hwlock",
"Lock %u is busy! Held by \"%s\" and attempted to accquire by \"%s\"",
p,
pcTaskGetName(hwlock_tasks[p]),
pcTaskGetName(task)
);
LOG_DEBUG(
"hwlock",
"...attempted to lock from pc %p",
__builtin_return_address(0)
);
int hwlock_acquire_nonblock(enum hwlock_periph p)
{
assert(p < _HWLOCK_MAX);
if (mutex_trylock(&hwlock_mutex[p])) {
return 0;
} else {
return -EBUSY;
}
hwlock_tasks[p] = task;
return 0;
}
int hwlock_release(enum hwlock_periph p)
void hwlock_release(enum hwlock_periph p)
{
int ret = 0;
if (p >= _HWLOCK_MAX) {
return -EINVAL;
}
if (hwlock_tasks[p] != xTaskGetCurrentTaskHandle()) {
LOG_ERR("hwlock",
"Lock %u is released by task \"%s\" while it was acquired by \"%s\"",
p,
pcTaskGetName(NULL),
pcTaskGetName(hwlock_tasks[p]));
ret = -EACCES;
}
if (xSemaphoreGive(hwlock_mutex[p]) != pdTRUE) {
LOG_ERR("hwlock", "Lock %u not released correctly.", p);
ret = -EINVAL;
}
return ret;
assert(p < _HWLOCK_MAX);
mutex_unlock(&hwlock_mutex[p]);
}
#include "leds.h"
#include "pmic.h"
#include "FreeRTOS.h"
#include "task.h"
#include "epicardium.h"
#include "modules.h"
#include <stdbool.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
#define NUM_LEDS 15 /* Take from lib/card10/leds.c */
static void do_update()
{
while (hwlock_acquire(HWLOCK_LED, pdMS_TO_TICKS(1)) < 0) {
vTaskDelay(pdMS_TO_TICKS(1));
}
leds_update_power();
leds_update();
hwlock_release(HWLOCK_LED);
}
void epic_leds_set(int led, uint8_t r, uint8_t g, uint8_t b)
{
if (led == PERSONAL_STATE_LED && personal_state_enabled())
return;
leds_prep(led, r, g, b);
do_update();
}
void epic_leds_set_hsv(int led, float h, float s, float v)
{
if (led == PERSONAL_STATE_LED && personal_state_enabled())
return;
leds_prep_hsv(led, h, s, v);
do_update();
}
void epic_leds_prep(int led, uint8_t r, uint8_t g, uint8_t b)
{
if (led == PERSONAL_STATE_LED && personal_state_enabled())
return;
leds_prep(led, r, g, b);
}
void epic_leds_prep_hsv(int led, float h, float s, float v)
{
if (led == PERSONAL_STATE_LED && personal_state_enabled())
return;
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++) {
if (i == PERSONAL_STATE_LED && personal_state_enabled())
continue;
leds_prep(i, pattern[i][0], pattern[i][1], pattern[i][2]);
}
do_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++) {
if (i == PERSONAL_STATE_LED && personal_state_enabled())
continue;
leds_prep_hsv(i, pattern[i][0], pattern[i][1], pattern[i][2]);
}
do_update();
}
void epic_leds_dim_top(uint8_t value)
{
leds_set_dim_top(value);
if (personal_state_enabled() == 0)
leds_update();
}
void epic_leds_dim_bottom(uint8_t value)
{
leds_set_dim_bottom(value);
if (personal_state_enabled() == 0)
leds_update();
}
void epic_leds_set_rocket(int led, uint8_t value)
{
value = value > 31 ? 31 : value;
pmic_set_led(led, value);
}
void epic_set_flashlight(bool power)
{
leds_flashlight(power);
}
void epic_leds_update(void)
{
do_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);
}
void epic_leds_clear_all(uint8_t r, uint8_t g, uint8_t b)
{
for (int i = 0; i < NUM_LEDS; i++) {
if (i == PERSONAL_STATE_LED && personal_state_enabled())
continue;
leds_prep(i, r, g, b);
}
do_update();
}
#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(
'bhi.c',
'bme680.c',
'buttons.c',
'dispatcher.c',
'display.c',
'fileops.c',
'gpio.c',
'hardware.c',
'hw-lock.c',
'leds.c',
'lifecycle.c',
'light_sensor.c',
'log.c',
'max30001.c',
'personal_state.c',
'pmic.c',
'rtc.c',
'serial.c',
'stream.c',
'trng.c',
'vibra.c',
'watchdog.c',
'usb.c'
)