implemented furi from flipper zero

added cmsis_core, furi, mlib and nanobake
implemented basic app structure from furi
implemented basic placeholder apps
This commit is contained in:
Ken Van Hoeylandt
2023-12-26 21:47:27 +01:00
parent 0cf7829a2d
commit 5dc2599e55
114 changed files with 53069 additions and 297 deletions
@@ -1,33 +1,40 @@
#include "system_info.h"
#include "nanobake.h"
#include <core_defines.h>
#include <thread.h>
#include <esp_lvgl_port.h>
#include <nb_platform.h>
static int32_t system_info_entry_point(void* param) {
UNUSED(param);
static void prv_on_create(nb_platform_t _Nonnull* platform, lv_obj_t _Nonnull* lv_parent) {
lvgl_port_lock(0);
// Wait for all apps to start
vTaskDelay(1000 / portTICK_PERIOD_MS);
lv_obj_t* cpu_label = lv_label_create(lv_parent);
lv_label_set_recolor(cpu_label, true);
lv_obj_set_width(cpu_label, (lv_coord_t)platform->display->horizontal_resolution);
lv_obj_set_style_text_align(cpu_label, LV_TEXT_ALIGN_LEFT, 0);
lv_label_set_text(cpu_label, "CPU usage: ?");
lv_obj_align(cpu_label, LV_ALIGN_TOP_LEFT, 0, 0);
size_t system_service_count = nanobake_get_app_thread_count();
printf("Running apps:\n");
for (int i = 0; i < system_service_count; ++i) {
FuriThreadId thread_id = nanobake_get_app_thread_id(i);
const char* appid = furi_thread_get_appid(thread_id);
const char* name = furi_thread_get_name(thread_id);
bool is_suspended = furi_thread_is_suspended(thread_id);
const char* status = is_suspended ? "suspended" : "active";
bool is_service = furi_thread_mark_is_service(thread_id);
const char* type = is_service ? "service" : "app";
printf(" - [%s, %s] %s (%s)\n", type, status, name, appid);
}
lv_obj_t* mem_free_label = lv_label_create(lv_parent);
lv_label_set_recolor(mem_free_label, true);
lv_obj_set_width(mem_free_label, (lv_coord_t)platform->display->horizontal_resolution);
lv_obj_set_style_text_align(mem_free_label, LV_TEXT_ALIGN_LEFT, 0);
lv_label_set_text(mem_free_label, "Memory: ?");
lv_obj_align(mem_free_label, LV_ALIGN_TOP_LEFT, 0, 15);
printf("Heap memory available: %d / %d\n",
heap_caps_get_free_size(MALLOC_CAP_DEFAULT),
heap_caps_get_total_size(MALLOC_CAP_DEFAULT)
);
lvgl_port_unlock();
return 0;
}
nb_app_t system_info_app = {
.id = "systeminfo",
.name = "System Info",
.type = SYSTEM,
.on_create = &prv_on_create,
.on_update = NULL,
.on_destroy = NULL
.entry_point = &system_info_entry_point,
.stack_size = 2048,
.priority = 10
};
@@ -1,8 +1,13 @@
#ifndef NANOBAKE_SYSTEM_INFO_H
#define NANOBAKE_SYSTEM_INFO_H
#pragma once
#include "nb_app.h"
#ifdef __cplusplus
extern "C" {
#endif
extern nb_app_t system_info_app;
#endif // NANOBAKE_SYSTEM_INFO_H
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,28 @@
#include "nb_applications.h"
// System services
extern const nb_app_t desktop_app;
extern const nb_app_t gui_app;
extern const nb_app_t loader_app;
// System apps
extern const nb_app_t system_info_app;
const nb_app_t* const FLIPPER_SERVICES[] = {
&desktop_app,
&gui_app,
&loader_app
};
const size_t FLIPPER_SERVICES_COUNT = sizeof(FLIPPER_SERVICES) / sizeof(nb_app_t*);
const nb_app_t* const FLIPPER_SYSTEM_APPS[] = {
&system_info_app
};
const size_t FLIPPER_SYSTEM_APPS_COUNT = sizeof(FLIPPER_SYSTEM_APPS) / sizeof(nb_app_t*);
const FlipperInternalOnStartHook FLIPPER_ON_SYSTEM_START[] = {
};
const size_t FLIPPER_ON_SYSTEM_START_COUNT = sizeof(FLIPPER_ON_SYSTEM_START) / sizeof(FlipperInternalOnStartHook);
@@ -0,0 +1,22 @@
#pragma once
#include "nb_app.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*FlipperInternalOnStartHook)(void);
extern const nb_app_t* const FLIPPER_SERVICES[];
extern const size_t FLIPPER_SERVICES_COUNT;
extern const nb_app_t* const FLIPPER_SYSTEM_APPS[];
extern const size_t FLIPPER_SYSTEM_APPS_COUNT;
extern const FlipperInternalOnStartHook FLIPPER_ON_SYSTEM_START[];
extern const size_t FLIPPER_ON_SYSTEM_START_COUNT;
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,35 @@
#include "desktop.h"
#include "nb_hardware.h"
#include <esp_lvgl_port.h>
#include "core_defines.h"
#include <esp_log.h>
//nb_desktop_t* shared_desktop = NULL;
static int32_t prv_desktop_main(void* param) {
UNUSED(param);
printf("desktop app init\n");
// nb_desktop_t* desktop = desktop_alloc();
// shared_desktop = desktop;
// lvgl_port_lock(0);
//
// lv_obj_t* label = lv_label_create(lv_parent);
// lv_label_set_recolor(label, true);
// lv_obj_set_width(label, (lv_coord_t)platform->display->horizontal_resolution);
// lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_LEFT, 0);
// lv_label_set_text(label, "Desktop app");
// lv_obj_align(label, LV_ALIGN_TOP_LEFT, 0, 0);
//
// lvgl_port_unlock();
return 0;
}
const nb_app_t desktop_app = {
.id = "desktop",
.name = "Desktop",
.type = SERVICE,
.entry_point = &prv_desktop_main,
.stack_size = 2048,
.priority = 10
};
@@ -0,0 +1,13 @@
#pragma once
#include "nb_app.h"
#ifdef __cplusplus
extern "C" {
#endif
extern const nb_app_t desktop_app;
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,18 @@
#include "gui.h"
#include "core_defines.h"
#include "check.h"
static int32_t prv_gui_main(void* param) {
UNUSED(param);
printf("gui app init\n");
return 0;
}
const nb_app_t gui_app = {
.id = "gui",
.name = "GUI",
.type = STARTUP,
.entry_point = &prv_gui_main,
.stack_size = 2048,
.priority = 10
};
@@ -0,0 +1,13 @@
#pragma once
#include "nb_app.h"
#ifdef __cplusplus
extern "C" {
#endif
extern const nb_app_t gui_app;
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,17 @@
#include "loader.h"
#include "core_defines.h"
static int32_t prv_loader_main(void* param) {
UNUSED(param);
printf("loader app init\n");
return 0;
}
const nb_app_t loader_app = {
.id = "loader",
.name = "Loader",
.type = STARTUP,
.entry_point = &prv_loader_main,
.stack_size = 2048,
.priority = 10
};
@@ -0,0 +1,13 @@
#pragma once
#include "nb_app.h"
#ifdef __cplusplus
extern "C" {
#endif
extern const nb_app_t loader_app;
#ifdef __cplusplus
}
#endif
+98 -9
View File
@@ -1,15 +1,104 @@
#include "nanobake.h"
#include "applications/main/system_info/system_info.h"
#include "nb_hardware.h"
#include "nb_lvgl.h"
#include "applications/nb_applications.h"
#include <esp_log.h>
#include <m-list.h>
// Furi
#include <thread.h>
#include <kernel.h>
#include <record.h>
#include <check.h>
void nb_app_start(nb_platform_t _Nonnull* platform, nb_app_t _Nonnull* config) {
lv_obj_t* scr = lv_scr_act();
ESP_ERROR_CHECK(nb_app_validate(config));
config->on_create(platform, scr);
static const char* TAG = "nanobake";
M_LIST_DEF(thread_ids, FuriThreadId);
static void prv_furi_init() {
// TODO: can we remove the suspend-resume logic?
if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) {
vTaskSuspendAll();
}
furi_record_init();
xTaskResumeAll();
}
extern void nanobake_run(nb_platform_config_t _Nonnull* config) {
nb_platform_t _Nonnull* platform = nb_platform_create(config);
thread_ids_t prv_thread_ids;
nb_app_start(platform, config->apps[0]);
// nb_app_start(platform, &system_info_app);
FuriThreadId nanobake_get_app_thread_id(size_t index) {
return *thread_ids_get(prv_thread_ids, index);
}
size_t nanobake_get_app_thread_count() {
return thread_ids_size(prv_thread_ids);
}
extern void nanobake_start(nb_config_t _Nonnull* config) {
prv_furi_init();
nb_hardware_t _Nonnull* hardware = nb_hardware_alloc(config);
nb_lvgl_init(hardware);
thread_ids_init(prv_thread_ids);
ESP_LOGI(TAG, "Starting services");
for(size_t i = 0; i < FLIPPER_SERVICES_COUNT; i++) {
ESP_LOGI(TAG, "Starting system service \"%s\"", FLIPPER_SERVICES[i]->name);
FuriThread* thread = furi_thread_alloc_ex(
FLIPPER_SERVICES[i]->name,
FLIPPER_SERVICES[i]->stack_size,
FLIPPER_SERVICES[i]->entry_point,
NULL
);
furi_thread_mark_as_service(thread);
furi_thread_set_appid(thread, FLIPPER_SERVICES[i]->id);
furi_thread_start(thread);
FuriThreadId thread_id = furi_thread_get_id(thread);
thread_ids_push_back(prv_thread_ids, thread_id);
}
ESP_LOGI(TAG, "Starting system apps");
for(size_t i = 0; i < FLIPPER_SYSTEM_APPS_COUNT; i++) {
ESP_LOGI(TAG, "Starting system app \"%s\"", FLIPPER_SYSTEM_APPS[i]->name);
FuriThread* thread = furi_thread_alloc_ex(
FLIPPER_SYSTEM_APPS[i]->name,
FLIPPER_SYSTEM_APPS[i]->stack_size,
FLIPPER_SYSTEM_APPS[i]->entry_point,
NULL
);
furi_thread_mark_as_service(thread);
furi_thread_set_appid(thread, FLIPPER_SYSTEM_APPS[i]->id);
furi_thread_start(thread);
FuriThreadId thread_id = furi_thread_get_id(thread);
thread_ids_push_back(prv_thread_ids, thread_id);
}
// ESP_LOGI(TAG, "Starting external apps");
//
// size_t external_apps_count = sizeof(*config->apps);
// for(size_t i = 0; i < FLIPPER_SERVICES_COUNT; i++) {
// ESP_LOGI(TAG, "Starting external app \"%s\"", FLIPPER_[i]->name);
//
// FuriThread* thread = furi_thread_alloc_ex(
// FLIPPER_SERVICES[i]->name,
// FLIPPER_SERVICES[i]->stack_size,
// FLIPPER_SERVICES[i]->entry_point,
// NULL
// );
// furi_thread_set_appid(thread, FLIPPER_SERVICES[i]->id);
// furi_thread_start(thread);
//
// FuriThreadId thread_id = furi_thread_get_id(thread);
// thread_ids_push_back(prv_thread_ids, thread_id);
// }
ESP_LOGI(TAG, "Startup complete");
}
-32
View File
@@ -1,32 +0,0 @@
#include "nb_app.h"
#include <esp_check.h>
#include <string.h>
static const char* TAG = "nb_app";
esp_err_t nb_app_validate(nb_app_t* _Nonnull app) {
ESP_RETURN_ON_FALSE(
strlen(app->id) < NB_APP_ID_LENGTH,
ESP_FAIL,
TAG,
"app id cannot be larger than %d characters",
NB_APP_ID_LENGTH - 1
);
ESP_RETURN_ON_FALSE(
strlen(app->name) < NB_APP_NAME_LENGTH,
ESP_FAIL,
TAG,
"app name cannot be larger than %d characters",
NB_APP_NAME_LENGTH - 1
);
ESP_RETURN_ON_FALSE(
(app->on_update == NULL) == (app->update_task_priority == 0 && app->update_task_priority == 0),
ESP_FAIL,
TAG,
"app update is inconsistently configured"
);
return ESP_OK;
}
-20
View File
@@ -1,20 +0,0 @@
#ifndef NANOBAKE_NB_ASSERT_H
#define NANOBAKE_NB_ASSERT_H
#include <assert.h>
#include <esp_log.h>
#define NB_ASSERT(x, message) do { \
if (!(x)) { \
ESP_LOGE("assert", message); \
_esp_error_check_failed( \
x, \
__FILE__, \
__LINE__, \
__ASSERT_FUNC, \
#x \
); \
} \
} while(0)
#endif //NANOBAKE_NB_ASSERT_H
+3 -3
View File
@@ -1,8 +1,8 @@
#include "nb_display.h"
#include "nb_assert.h"
#include <check.h>
nb_display_t _Nonnull* nb_display_create(nb_display_driver_t _Nonnull* driver) {
nb_display_t _Nonnull* nb_display_alloc(nb_display_driver_t _Nonnull* driver) {
nb_display_t _Nonnull* display = malloc(sizeof(nb_display_t));
NB_ASSERT(driver->create_display(display), "failed to create display");
furi_check(driver->create_display(display), "failed to create display");
return display;
}
+32
View File
@@ -0,0 +1,32 @@
#include "nb_hardware.h"
#include "nb_display.h"
#include "nb_touch.h"
#include <esp_check.h>
#include <esp_err.h>
#include <esp_lvgl_port.h>
#include <check.h>
static const char* TAG = "nb_hardware";
nb_hardware_t _Nonnull* nb_hardware_alloc(nb_config_t _Nonnull* config) {
nb_hardware_t* platform = malloc(sizeof(nb_hardware_t));
furi_check(config->display_driver != NULL, "no display driver configured");
nb_display_driver_t display_driver = config->display_driver();
ESP_LOGI(TAG, "display with driver %s", display_driver.name);
platform->display = nb_display_alloc(&display_driver);
if (config->touch_driver != NULL) {
nb_touch_driver_t touch_driver = config->touch_driver();
ESP_LOGI(TAG, "touch with driver %s", touch_driver.name);
platform->touch = nb_touch_alloc(&touch_driver);
} else {
ESP_LOGI(TAG, "no touch configured");
platform->touch = NULL;
}
return platform;
}
-3
View File
@@ -1,3 +0,0 @@
#include "nb_internal.h"
const char* nbi_tag = "nanobake";
-6
View File
@@ -1,6 +0,0 @@
#ifndef NANOBAKE_NB_INTERNAL_H
#define NANOBAKE_NB_INTERNAL_H
extern const char* nbi_tag;
#endif // NANOBAKE_NB_INTERNAL_H
+54
View File
@@ -0,0 +1,54 @@
#include "nb_lvgl.h"
#include "nb_hardware.h"
#include <esp_check.h>
#include <check.h>
static const char* TAG = "nb_lvgl";
nb_lvgl_t nb_lvgl_init(nb_hardware_t* platform) {
nb_lvgl_t lvgl;
const lvgl_port_cfg_t lvgl_cfg = {
.task_priority = 4,
.task_stack = 4096,
.task_affinity = -1, // core pinning
.task_max_sleep_ms = 500,
.timer_period_ms = 5
};
furi_check(lvgl_port_init(&lvgl_cfg) == ESP_OK, "lvgl port init failed");
nb_display_t _Nonnull* display = platform->display;
// Add display
ESP_LOGD(TAG, "lvgl add display");
const lvgl_port_display_cfg_t disp_cfg = {
.io_handle = display->io_handle,
.panel_handle = display->display_handle,
.buffer_size = display->horizontal_resolution * display->draw_buffer_height * (display->bits_per_pixel / 8),
.double_buffer = 0,
.hres = display->horizontal_resolution,
.vres = display->vertical_resolution,
.monochrome = false,
/* Rotation values must be same as defined in driver */
// TODO: expose data from driver
.rotation = {
.swap_xy = false,
.mirror_x = true,
.mirror_y = false,
},
.flags = {
.buff_dma = true,
}
};
lvgl.disp = lvgl_port_add_disp(&disp_cfg);
// Add touch
if (platform->touch != NULL) {
const lvgl_port_touch_cfg_t touch_cfg = {
.disp = lvgl.disp,
.handle = platform->touch->touch_handle,
};
lvgl.touch_indev = lvgl_port_add_touch(&touch_cfg);
furi_check(lvgl.touch_indev != NULL, "failed to add touch to lvgl");
}
return lvgl;
}
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include <esp_lvgl_port.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct nb_lvgl nb_lvgl_t;
struct nb_lvgl {
lv_disp_t* _Nonnull disp;
lv_indev_t* _Nullable touch_indev;
};
typedef struct nb_hardware nb_hardware_t;
extern nb_lvgl_t nb_lvgl_init(nb_hardware_t* platform);
#ifdef __cplusplus
}
#endif
-81
View File
@@ -1,81 +0,0 @@
#include "nb_platform.h"
#include "nb_display.h"
#include "nb_touch.h"
#include <esp_check.h>
#include <esp_err.h>
#include <esp_lvgl_port.h>
#include <nb_assert.h>
static const char* TAG = "nb_platform";
static esp_err_t prv_lvgl_init(
nb_platform_t* platform
) {
const lvgl_port_cfg_t lvgl_cfg = {
.task_priority = 4,
.task_stack = 4096,
.task_affinity = -1, // core pinning
.task_max_sleep_ms = 500,
.timer_period_ms = 5
};
ESP_RETURN_ON_ERROR(lvgl_port_init(&lvgl_cfg), TAG, "lvgl port init failed");
nb_display_t _Nonnull* display = platform->display;
// Add display
ESP_LOGD(TAG, "lvgl add display");
const lvgl_port_display_cfg_t disp_cfg = {
.io_handle = display->io_handle,
.panel_handle = display->display_handle,
.buffer_size = display->horizontal_resolution * display->draw_buffer_height * (display->bits_per_pixel / 8),
.double_buffer = 1,
.hres = display->horizontal_resolution,
.vres = display->vertical_resolution,
.monochrome = false,
/* Rotation values must be same as defined in driver */
// TODO: expose data from driver
.rotation = {
.swap_xy = false,
.mirror_x = true,
.mirror_y = false,
},
.flags = {
.buff_dma = true,
}
};
platform->lvgl->disp = lvgl_port_add_disp(&disp_cfg);
// Add touch
if (platform->touch != NULL) {
const lvgl_port_touch_cfg_t touch_cfg = {
.disp = platform->lvgl->disp,
.handle = platform->touch->touch_handle,
};
platform->lvgl->touch_indev = lvgl_port_add_touch(&touch_cfg);
ESP_RETURN_ON_FALSE(platform->lvgl->touch_indev != NULL, ESP_FAIL, TAG, "failed to add touch to lvgl");
}
return ESP_OK;
}
nb_platform_t _Nonnull* nb_platform_create(nb_platform_config_t _Nonnull* config) {
nb_platform_t* platform = malloc(sizeof(nb_platform_t));
NB_ASSERT(config->display_driver != NULL, "no display driver configured");
nb_display_driver_t display_driver = config->display_driver();
ESP_LOGI(TAG, "display with driver %s", display_driver.name);
platform->display = nb_display_create(&display_driver);
if (config->touch_driver != NULL) {
nb_touch_driver_t touch_driver = config->touch_driver();
ESP_LOGI(TAG, "touch with driver %s", touch_driver.name);
platform->touch = nb_touch_create(&touch_driver);
} else {
ESP_LOGI(TAG, "no touch configured");
platform->touch = NULL;
}
NB_ASSERT(prv_lvgl_init(platform) == ESP_OK, "failed to init lvgl");
return platform;
}
+3 -4
View File
@@ -1,13 +1,12 @@
#include "nb_touch.h"
#include "nb_assert.h"
#include <esp_check.h>
#include "check.h"
nb_touch_t _Nonnull* nb_touch_create(nb_touch_driver_t _Nonnull* driver) {
nb_touch_t _Nonnull* nb_touch_alloc(nb_touch_driver_t _Nonnull* driver) {
nb_touch_t _Nonnull* touch = malloc(sizeof(nb_touch_t));
bool success = driver->create_touch(
&(touch->io_handle),
&(touch->touch_handle)
);
NB_ASSERT(success, "touch driver failed");
furi_check(success, "touch driver failed");
return touch;
}