[FL-140] Core api dynamic records (#296)

* SYSTEM: tickless mode with deep sleep.
* Move FreeRTOS ticks to lptim2
* API: move all sumbodules init routines to one place. Timebase: working lptim2 at tick source.
* API Timebase: lp-timer routines, timer access safe zones prediction and synchronization. FreeRTOS: adjust configuration for tickless mode.
* NFC: support for tickless mode.
* API Timebase: improve tick error handling in IRQ. Apploader: use insomnia mode to run applications.
* BLE: prevent sleep while core2 starting
* HAL: nap while in insomnia mode
* init records work
* try to implement record delete
* tests and flapp
* flapp subsystem
* new core functions to get app stat, simplify core code
* fix thread termination
* add strdup to core
* fix tests
* Refactoring: remove all unusued parts, update API usage, aggreagate API sources and headers, new record storage
* Refactoring: update furi record api usage, cleanup code
* Fix broken merge for freertos apps
* Core, Target: fix compilation warnings
* Drop firmware target local
* HAL Timebase, Power, Clock: semaphore guarded access to clock and power modes, better sleep mode.
* SD-Filesystem: wait for all deps to arrive before adding widget. Core, BLE: disable debug dump to serial.
* delete old app example-ipc
* delete old app fatfs list
* fix strobe app, add input header
* delete old display driver
* comment old app qr-code
* fix sd-card test, add forced widget update
* remove unused new core test
* increase heap to 128k
* comment and assert old core tests
* fix syntax

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
DrZlo13 2021-01-21 02:09:26 +10:00 committed by GitHub
parent 6c4983c6b6
commit 8f9b2513ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
169 changed files with 1009 additions and 4535 deletions

4
.github/CODEOWNERS vendored
View File

@ -19,10 +19,6 @@ firmware/targets/f4/api-hal/api-hal-boot.c @skotopes
debug/** @skotopes
# local target
firmware/targets/local/** @glitchcore
# BLE
firmware/targets/f4/ble-glue/** @skotopes

View File

@ -32,16 +32,6 @@ jobs:
with:
run: /syntax_check.sh
- name: Build local testing firmware in docker
uses: ./.github/actions/docker
with:
run: make -C firmware TARGET=local
- name: Run local tests
uses: ./.github/actions/docker
with:
run: make -C firmware TARGET=local APP_TEST=1 run
- name: Build F4 bootloader in docker
uses: ./.github/actions/docker
with:

View File

@ -25,14 +25,7 @@ Flipper Zero's firmware consists of two components: Bootloader and main firmware
## Build from source
You can run firmware locally (with HAL stub):
* `docker-compose exec dev make -C firmware TARGET=local APP_TEST=1 run` for running tests
* `docker-compose exec dev make -C firmware TARGET=local APP_*=1 run` for running examples (see `applications/applications.mk` for list of applications/examples)
Or on your flipper:
`docker-compose exec dev make -C firmware TARGET=f4 APP_*=1 flash` for build and flash dev board (see `applications/applications.mk` for list of applications/examples)
`docker-compose exec dev make -C firmware TARGET=f4 APP_RELEASE=1 flash` for build and flash dev board (see `applications/applications.mk` for list of applications/examples)
# Links
* Task tracker: [Jira](https://flipperzero.atlassian.net/)

View File

@ -1,4 +1,4 @@
#include "flipper_v2.h"
#include <furi.h>
#include <cli/cli.h>
#include <gui/gui.h>
#include "menu/menu.h"
@ -8,14 +8,15 @@
#include <api-hal.h>
typedef struct {
FuriApp* handler;
osThreadAttr_t app_thread_attr;
osThreadId_t app_thread_id;
Widget* widget;
const FlipperStartupApp* current_app;
const FuriApplication* current_app;
} AppLoaderState;
typedef struct {
AppLoaderState* state;
const FlipperStartupApp* app;
const FuriApplication* app;
} AppLoaderContext;
// TODO add mutex for contex
@ -36,7 +37,7 @@ static void input_callback(InputEvent* input_event, void* _ctx) {
AppLoaderState* ctx = (AppLoaderState*)_ctx;
if(input_event->state && input_event->input == InputBack) {
furiac_kill(ctx->handler);
osThreadTerminate(ctx->app_thread_id);
widget_enabled_set(ctx->widget, false);
api_hal_timebase_insomnia_exit();
}
@ -54,7 +55,16 @@ static void handle_menu(void* _ctx) {
api_hal_timebase_insomnia_enter();
ctx->state->current_app = ctx->app;
ctx->state->handler = furiac_start(ctx->app->app, ctx->app->name, NULL);
ctx->state->app_thread_attr.name = ctx->app->name;
ctx->state->app_thread_attr.attr_bits = osThreadDetached;
ctx->state->app_thread_attr.cb_mem = NULL;
ctx->state->app_thread_attr.cb_size = 0;
ctx->state->app_thread_attr.stack_mem = NULL;
ctx->state->app_thread_attr.stack_size = 1024;
ctx->state->app_thread_attr.priority = osPriorityNormal;
ctx->state->app_thread_attr.tz_module = 0;
ctx->state->app_thread_attr.reserved = 0;
ctx->state->app_thread_id = osThreadNew(ctx->app->app, NULL, &ctx->state->app_thread_attr);
}
static void handle_cli(string_t args, void* _ctx) {
@ -65,13 +75,22 @@ static void handle_cli(string_t args, void* _ctx) {
cli_print("Starting furi application\r\n");
ctx->state->current_app = ctx->app;
ctx->state->handler = furiac_start(ctx->app->app, ctx->app->name, NULL);
ctx->state->app_thread_attr.name = ctx->app->name;
ctx->state->app_thread_attr.attr_bits = osThreadDetached;
ctx->state->app_thread_attr.cb_mem = NULL;
ctx->state->app_thread_attr.cb_size = 0;
ctx->state->app_thread_attr.stack_mem = NULL;
ctx->state->app_thread_attr.stack_size = 1024;
ctx->state->app_thread_attr.priority = osPriorityNormal;
ctx->state->app_thread_attr.tz_module = 0;
ctx->state->app_thread_attr.reserved = 0;
ctx->state->app_thread_id = osThreadNew(ctx->app->app, NULL, &ctx->state->app_thread_attr);
cli_print("Press any key to kill application");
char c;
cli_read(&c, 1);
furiac_kill(ctx->state->handler);
osThreadTerminate(ctx->state->app_thread_id);
}
void app_loader(void* p) {
@ -79,37 +98,23 @@ void app_loader(void* p) {
furi_check(self_id);
AppLoaderState state;
state.handler = NULL;
state.app_thread_id = NULL;
state.widget = widget_alloc();
widget_enabled_set(state.widget, false);
widget_draw_callback_set(state.widget, render_callback, &state);
widget_input_callback_set(state.widget, input_callback, &state);
ValueMutex* menu_mutex = furi_open("menu");
if(menu_mutex == NULL) {
printf("menu is not available\n");
furiac_exit(NULL);
}
ValueMutex* menu_mutex = furi_record_open("menu");
Cli* cli = furi_record_open("cli");
Gui* gui = furi_record_open("gui");
Cli* cli = furi_open("cli");
// Open GUI and register widget
Gui* gui = furi_open("gui");
if(gui == NULL) {
printf("gui is not available\n");
furiac_exit(NULL);
}
gui_add_widget(gui, state.widget, GuiLayerFullscreen);
// FURI startup
const size_t flipper_app_count = sizeof(FLIPPER_APPS) / sizeof(FLIPPER_APPS[0]);
const size_t flipper_plugins_count = sizeof(FLIPPER_PLUGINS) / sizeof(FLIPPER_PLUGINS[0]);
// Main menu
with_value_mutex(
menu_mutex, (Menu * menu) {
for(size_t i = 0; i < flipper_app_count; i++) {
for(size_t i = 0; i < FLIPPER_APPS_size(); i++) {
AppLoaderContext* ctx = furi_alloc(sizeof(AppLoaderContext));
ctx->state = &state;
ctx->app = &FLIPPER_APPS[i];
@ -123,13 +128,11 @@ void app_loader(void* p) {
ctx));
// Add cli command
if(cli) {
string_t cli_name;
string_init_set_str(cli_name, "app_");
string_cat_str(cli_name, FLIPPER_APPS[i].name);
cli_add_command(cli, string_get_cstr(cli_name), handle_cli, ctx);
string_clear(cli_name);
}
string_t cli_name;
string_init_set_str(cli_name, "app_");
string_cat_str(cli_name, FLIPPER_APPS[i].name);
cli_add_command(cli, string_get_cstr(cli_name), handle_cli, ctx);
string_clear(cli_name);
}
});
@ -157,7 +160,7 @@ void app_loader(void* p) {
MenuItem* menu_plugins =
menu_item_alloc_menu("Plugins", assets_icons_get(A_Plugins_14));
for(size_t i = 0; i < flipper_plugins_count; i++) {
for(size_t i = 0; i < FLIPPER_PLUGINS_size(); i++) {
AppLoaderContext* ctx = furi_alloc(sizeof(AppLoaderContext));
ctx->state = &state;
ctx->app = &FLIPPER_PLUGINS[i];
@ -171,13 +174,11 @@ void app_loader(void* p) {
ctx));
// Add cli command
if(cli) {
string_t cli_name;
string_init_set_str(cli_name, "app_");
string_cat_str(cli_name, FLIPPER_PLUGINS[i].name);
cli_add_command(cli, string_get_cstr(cli_name), handle_cli, ctx);
string_clear(cli_name);
}
string_t cli_name;
string_init_set_str(cli_name, "app_");
string_cat_str(cli_name, FLIPPER_PLUGINS[i].name);
cli_add_command(cli, string_get_cstr(cli_name), handle_cli, ctx);
string_clear(cli_name);
}
menu_item_add(menu, menu_plugins);
@ -186,4 +187,4 @@ void app_loader(void* p) {
printf("[app loader] start\n");
osThreadSuspend(self_id);
}
}

220
applications/applications.c Normal file
View File

@ -0,0 +1,220 @@
#include "applications.h"
#ifdef APP_TEST
void flipper_test_app(void* p);
#endif
void application_blink(void* p);
void application_uart_write(void* p);
void application_ipc_display(void* p);
void application_ipc_widget(void* p);
void application_input_dump(void* p);
void display_u8g2(void* p);
void u8g2_example(void* p);
void input_task(void* p);
void menu_task(void* p);
void coreglitch_demo_0(void* p);
void u8g2_qrcode(void* p);
void fatfs_list(void* p);
void gui_task(void* p);
void backlight_control(void* p);
void irda(void* p);
void app_loader(void* p);
void cc1101_workaround(void* p);
void lf_rfid_workaround(void* p);
void nfc_task(void* p);
void dolphin_task(void* p);
void power_task(void* p);
void bt_task(void* p);
void sd_card_test(void* p);
void application_vibro(void* p);
void app_gpio_test(void* p);
void app_ibutton(void* p);
void cli_task(void* p);
void music_player(void* p);
void sdnfc(void* p);
void floopper_bloopper(void* p);
void sd_filesystem(void* p);
const FuriApplication FLIPPER_SERVICES[] = {
#ifdef APP_DISPLAY
{.app = display_u8g2, .name = "display_u8g2", .icon = A_Plugins_14},
#endif
#ifdef APP_CLI
{.app = cli_task, .name = "cli_task", .icon = A_Plugins_14},
#endif
#ifdef APP_EXAMPLE_BLINK
{.app = application_blink, .name = "blink", .icon = A_Plugins_14},
#endif
#ifdef APP_INPUT
{.app = input_task, .name = "input_task", .icon = A_Plugins_14},
#endif
#ifdef APP_EXAMPLE_INPUT_DUMP
{.app = application_input_dump, .name = "input dump", .icon = A_Plugins_14},
#endif
#ifdef APP_GUI
{.app = backlight_control, .name = "backlight_control", .icon = A_Plugins_14},
{.app = gui_task, .name = "gui_task", .icon = A_Plugins_14},
#endif
#ifdef APP_MENU
{.app = menu_task, .name = "menu_task", .icon = A_Plugins_14},
{.app = app_loader, .name = "app_loader", .icon = A_Plugins_14},
#endif
#ifdef APP_SD_FILESYSTEM
{.app = sd_filesystem, .name = "sd_filesystem", .icon = A_Plugins_14},
#endif
#ifdef APP_DOLPHIN
{.app = dolphin_task, .name = "dolphin_task", .icon = A_Plugins_14},
#endif
#ifdef APP_POWER
{.app = power_task, .name = "power_task", .icon = A_Plugins_14},
#endif
#ifdef APP_BT
{.app = bt_task, .name = "bt_task", .icon = A_Plugins_14},
#endif
#ifdef APP_CC1101
{.app = cc1101_workaround, .name = "cc1101 workaround", .icon = A_Plugins_14},
#endif
#ifdef APP_LF_RFID
{.app = lf_rfid_workaround, .name = "lf rfid workaround", .icon = A_Plugins_14},
#endif
#ifdef APP_IRDA
{.app = irda, .name = "irda", .icon = A_Plugins_14},
#endif
#ifdef APP_NFC
{.app = nfc_task, .name = "nfc_task", .icon = A_Plugins_14},
#endif
#ifdef APP_TEST
{.app = flipper_test_app, .name = "test app", .icon = A_Plugins_14},
#endif
#ifdef APP_EXAMPLE_IPC
{.app = application_ipc_display, .name = "ipc display", .icon = A_Plugins_14},
{.app = application_ipc_widget, .name = "ipc widget", .icon = A_Plugins_14},
#endif
#ifdef APP_EXAMPLE_QRCODE
{.app = u8g2_qrcode, .name = "u8g2_qrcode", .icon = A_Plugins_14},
#endif
#ifdef APP_EXAMPLE_FATFS
{.app = fatfs_list, .name = "fatfs_list", .icon = A_Plugins_14},
#endif
#ifdef APP_EXAMPLE_DISPLAY
{.app = u8g2_example, .name = "u8g2_example", .icon = A_Plugins_14},
#endif
#ifdef APP_SPEAKER_DEMO
{.app = coreglitch_demo_0, .name = "coreglitch_demo_0", .icon = A_Plugins_14},
#endif
#ifdef APP_SD_TEST
{.app = sd_card_test, .name = "sd_card_test", .icon = A_Plugins_14},
#endif
#ifdef APP_MUSIC_PLAYER
{.app = music_player, .name = "music player", .icon = A_Plugins_14},
#endif
#ifdef APP_IBUTTON
{.app = app_ibutton, .name = "ibutton", .icon = A_Plugins_14},
#endif
#ifdef APP_GPIO_DEMO
{.app = app_gpio_test, .name = "gpio test", .icon = A_Plugins_14},
#endif
#ifdef APP_FLOOPPER_BLOOPPER
{.app = floopper_bloopper, .name = "Floopper Bloopper", .icon = A_Games_14},
#endif
#ifdef APP_SDNFC
{.app = sdnfc, .name = "sdnfc", .icon = A_Plugins_14},
#endif
};
size_t FLIPPER_SERVICES_size() {
return sizeof(FLIPPER_SERVICES) / sizeof(FuriApplication);
}
// Main menu APP
const FuriApplication FLIPPER_APPS[] = {
#ifdef BUILD_CC1101
{.app = cc1101_workaround, .name = "Sub-1 GHz", .icon = A_Sub1ghz_14},
#endif
#ifdef BUILD_LF_RFID
{.app = lf_rfid_workaround, .name = "125 kHz RFID", .icon = A_125khz_14},
#endif
#ifdef BUILD_IRDA
{.app = irda, .name = "Infrared", .icon = A_Infrared_14},
#endif
#ifdef BUILD_IBUTTON
{.app = app_ibutton, .name = "iButton", .icon = A_iButton_14},
#endif
#ifdef BUILD_GPIO_DEMO
{.app = app_gpio_test, .name = "GPIO", .icon = A_GPIO_14},
#endif
};
size_t FLIPPER_APPS_size() {
return sizeof(FLIPPER_APPS) / sizeof(FuriApplication);
}
// Plugin menu
const FuriApplication FLIPPER_PLUGINS[] = {
#ifdef BUILD_EXAMPLE_BLINK
{.app = application_blink, .name = "blink", .icon = A_Plugins_14},
#endif
#ifdef BUILD_EXAMPLE_INPUT_DUMP
{.app = application_input_dump, .name = "input dump", .icon = A_Plugins_14},
#endif
#ifdef BUILD_SPEAKER_DEMO
{.app = coreglitch_demo_0, .name = "coreglitch_demo_0", .icon = A_Plugins_14},
#endif
#ifdef BUILD_SD_TEST
{.app = sd_card_test, .name = "sd_card_test", .icon = A_Plugins_14},
#endif
#ifdef BUILD_VIBRO_DEMO
{.app = application_vibro, .name = "application_vibro", .icon = A_Plugins_14},
#endif
#ifdef BUILD_MUSIC_PLAYER
{.app = music_player, .name = "music player", .icon = A_Plugins_14},
#endif
#ifdef BUILD_FLOOPPER_BLOOPPER
{.app = floopper_bloopper, .name = "Floopper Bloopper", .icon = A_Games_14},
#endif
#ifdef BUILD_SDNFC
{.app = sdnfc, .name = "sdnfc", .icon = A_Plugins_14},
#endif
};
size_t FLIPPER_PLUGINS_size() {
return sizeof(FLIPPER_PLUGINS) / sizeof(FuriApplication);
}

View File

@ -1,296 +1,21 @@
#pragma once
#include "flipper.h"
#include <furi.h>
#include <assets_icons.h>
#ifdef APP_TEST
void flipper_test_app(void* p);
#endif
typedef void (*FlipperApplication)(void*);
void application_blink(void* p);
void application_uart_write(void* p);
void application_ipc_display(void* p);
void application_ipc_widget(void* p);
void application_input_dump(void* p);
typedef struct {
const FlipperApplication app;
const char* name;
const IconName icon;
} FuriApplication;
void display_u8g2(void* p);
extern const FuriApplication FLIPPER_SERVICES[];
size_t FLIPPER_SERVICES_size();
void u8g2_example(void* p);
extern const FuriApplication FLIPPER_APPS[];
size_t FLIPPER_APPS_size();
void input_task(void* p);
void menu_task(void* p);
void coreglitch_demo_0(void* p);
void u8g2_qrcode(void* p);
void fatfs_list(void* p);
void gui_task(void* p);
void backlight_control(void* p);
void irda(void* p);
void app_loader(void* p);
void cc1101_workaround(void* p);
void lf_rfid_workaround(void* p);
void nfc_task(void* p);
void dolphin_task(void* p);
void power_task(void* p);
void bt_task(void* p);
void sd_card_test(void* p);
void application_vibro(void* p);
void app_gpio_test(void* p);
void app_ibutton(void* p);
void cli_task(void* p);
void music_player(void* p);
void sdnfc(void* p);
void floopper_bloopper(void* p);
void sd_filesystem(void* p);
const FlipperStartupApp FLIPPER_STARTUP[] = {
#ifdef APP_DISPLAY
{.app = display_u8g2, .name = "display_u8g2", .libs = {0}, .icon = A_Plugins_14},
#endif
#ifdef APP_CLI
{.app = cli_task, .name = "cli_task", .libs = {0}, .icon = A_Plugins_14},
#endif
#ifdef APP_EXAMPLE_BLINK
{.app = application_blink,
.name = "blink",
.libs = {1, FURI_LIB{"input_task"}},
.icon = A_Plugins_14},
#endif
#ifdef APP_INPUT
{.app = input_task, .name = "input_task", .libs = {0}, .icon = A_Plugins_14},
#endif
#ifdef APP_EXAMPLE_INPUT_DUMP
{.app = application_input_dump,
.name = "input dump",
.libs = {1, FURI_LIB{"input_task"}},
.icon = A_Plugins_14},
#endif
#ifdef APP_GUI
{.app = backlight_control,
.name = "backlight_control",
.libs = {1, FURI_LIB{"input_task"}},
.icon = A_Plugins_14},
{.app = gui_task, .name = "gui_task", .libs = {0}, .icon = A_Plugins_14},
#endif
#ifdef APP_MENU
{.app = menu_task,
.name = "menu_task",
.libs = {1, FURI_LIB{"gui_task"}},
.icon = A_Plugins_14},
{.app = app_loader,
.name = "app_loader",
.libs = {2, FURI_LIB{"menu_task", "cli_task"}},
.icon = A_Plugins_14},
#endif
#ifdef APP_SD_FILESYSTEM
{.app = sd_filesystem,
.name = "sd_filesystem",
.libs = {1, FURI_LIB{"menu_task"}},
.icon = A_Plugins_14},
#endif
#ifdef APP_DOLPHIN
{.app = dolphin_task,
.name = "dolphin_task",
.libs = {1, FURI_LIB{"menu_task"}},
.icon = A_Plugins_14},
#endif
#ifdef APP_POWER
{.app = power_task,
.name = "power_task",
.libs = {2, FURI_LIB{"cli_task", "gui_task"}},
.icon = A_Plugins_14},
#endif
#ifdef APP_BT
{.app = bt_task, .name = "bt_task", .libs = {1, FURI_LIB{"cli_task"}}, .icon = A_Plugins_14},
#endif
#ifdef APP_CC1101
{.app = cc1101_workaround,
.name = "cc1101 workaround",
.libs = {1, FURI_LIB{"gui_task"}},
.icon = A_Plugins_14},
#endif
#ifdef APP_LF_RFID
{.app = lf_rfid_workaround,
.name = "lf rfid workaround",
.libs = {1, FURI_LIB{"gui_task"}},
.icon = A_Plugins_14},
#endif
#ifdef APP_IRDA
{.app = irda, .name = "irda", .libs = {1, FURI_LIB{"gui_task"}}, .icon = A_Plugins_14},
#endif
#ifdef APP_NFC
{.app = nfc_task, .name = "nfc_task", .libs = {1, FURI_LIB{"menu_task"}}, .icon = A_Plugins_14},
#endif
#ifdef APP_TEST
{.app = flipper_test_app, .name = "test app", .libs = {0}, .icon = A_Plugins_14},
#endif
#ifdef APP_EXAMPLE_IPC
{.app = application_ipc_display, .name = "ipc display", .libs = {0}, .icon = A_Plugins_14},
{.app = application_ipc_widget, .name = "ipc widget", .libs = {0}, .icon = A_Plugins_14},
#endif
#ifdef APP_EXAMPLE_QRCODE
{.app = u8g2_qrcode,
.name = "u8g2_qrcode",
.libs = {1, FURI_LIB{"display_u8g2"}},
.icon = A_Plugins_14},
#endif
#ifdef APP_EXAMPLE_FATFS
{.app = fatfs_list,
.name = "fatfs_list",
.libs = {2, FURI_LIB{"display_u8g2", "input_task"}},
.icon = A_Plugins_14},
#endif
#ifdef APP_EXAMPLE_DISPLAY
{.app = u8g2_example,
.name = "u8g2_example",
.libs = {1, FURI_LIB{"display_u8g2"}},
.icon = A_Plugins_14},
#endif
#ifdef APP_SPEAKER_DEMO
{.app = coreglitch_demo_0, .name = "coreglitch_demo_0", .libs = {0}, .icon = A_Plugins_14},
#endif
#ifdef APP_SD_TEST
{.app = sd_card_test,
.name = "sd_card_test",
.libs = {2, FURI_LIB{"gui_task", "sd_filesystem"}},
.icon = A_Plugins_14},
#endif
#ifdef APP_MUSIC_PLAYER
{.app = music_player,
.name = "music player",
.libs = {1, FURI_LIB{"gui_task"}},
.icon = A_Plugins_14},
#endif
#ifdef APP_IBUTTON
{.app = app_ibutton,
.name = "ibutton",
.libs = {1, FURI_LIB{"gui_task"}},
.icon = A_Plugins_14},
#endif
#ifdef APP_GPIO_DEMO
{.app = app_gpio_test,
.name = "gpio test",
.libs = {1, FURI_LIB{"gui_task"}},
.icon = A_Plugins_14},
#endif
#ifdef APP_FLOOPPER_BLOOPPER
{.app = floopper_bloopper,
.name = "Floopper Bloopper",
.libs = {1, FURI_LIB{"gui_task"}},
.icon = A_Games_14},
#endif
#ifdef APP_SDNFC
{.app = sdnfc, .name = "sdnfc", .libs = {1, FURI_LIB{"gui_task"}}, .icon = A_Plugins_14},
#endif
};
// Main menu APP
const FlipperStartupApp FLIPPER_APPS[] = {
#ifdef BUILD_CC1101
{.app = cc1101_workaround,
.name = "Sub-1 GHz",
.libs = {1, FURI_LIB{"gui_task"}},
.icon = A_Sub1ghz_14},
#endif
#ifdef BUILD_LF_RFID
{.app = lf_rfid_workaround,
.name = "125 kHz RFID",
.libs = {1, FURI_LIB{"gui_task"}},
.icon = A_125khz_14},
#endif
#ifdef BUILD_IRDA
{.app = irda, .name = "Infrared", .libs = {1, FURI_LIB{"gui_task"}}, .icon = A_Infrared_14},
#endif
#ifdef BUILD_IBUTTON
{.app = app_ibutton,
.name = "iButton",
.libs = {1, FURI_LIB{"gui_task"}},
.icon = A_iButton_14},
#endif
#ifdef BUILD_GPIO_DEMO
{.app = app_gpio_test, .name = "GPIO", .libs = {1, FURI_LIB{"gui_task"}}, .icon = A_GPIO_14},
#endif
};
// Plugin menu
const FlipperStartupApp FLIPPER_PLUGINS[] = {
#ifdef BUILD_EXAMPLE_BLINK
{.app = application_blink,
.name = "blink",
.libs = {1, FURI_LIB{"input_task"}},
.icon = A_Plugins_14},
#endif
#ifdef BUILD_EXAMPLE_INPUT_DUMP
{.app = application_input_dump,
.name = "input dump",
.libs = {1, FURI_LIB{"input_task"}},
.icon = A_Plugins_14},
#endif
#ifdef BUILD_SPEAKER_DEMO
{.app = coreglitch_demo_0, .name = "coreglitch_demo_0", .libs = {0}, .icon = A_Plugins_14},
#endif
#ifdef BUILD_SD_TEST
{.app = sd_card_test,
.name = "sd_card_test",
.libs = {2, FURI_LIB{"gui_task", "sd_filesystem"}},
.icon = A_Plugins_14},
#endif
#ifdef BUILD_VIBRO_DEMO
{.app = application_vibro,
.name = "application_vibro",
.libs = {1, FURI_LIB{"input_task"}},
.icon = A_Plugins_14},
#endif
#ifdef BUILD_MUSIC_PLAYER
{.app = music_player,
.name = "music player",
.libs = {1, FURI_LIB{"gui_task"}},
.icon = A_Plugins_14},
#endif
#ifdef BUILD_FLOOPPER_BLOOPPER
{.app = floopper_bloopper,
.name = "Floopper Bloopper",
.libs = {1, FURI_LIB{"gui_task"}},
.icon = A_Games_14},
#endif
#ifdef BUILD_SDNFC
{.app = sdnfc, .name = "sdnfc", .libs = {1, FURI_LIB{"gui_task"}}, .icon = A_Plugins_14},
#endif
};
extern const FuriApplication FLIPPER_PLUGINS[];
size_t FLIPPER_PLUGINS_size();

View File

@ -2,6 +2,7 @@ APP_DIR = $(PROJECT_ROOT)/applications
LIB_DIR = $(PROJECT_ROOT)/lib
CFLAGS += -I$(APP_DIR)
C_SOURCES += $(APP_DIR)/applications.c
# Use APP_* for autostart app
# Use BUILD_* for add app to build

View File

@ -1,11 +1,12 @@
#include "flipper_v2.h"
#include <furi.h>
#define BACKLIGHT_TIME 10000
#define BACKLIGHT_FLAG_ACTIVITY 0x00000001U
static void event_cb(const void* value, void* ctx) {
xSemaphoreGive((SemaphoreHandle_t*)ctx);
osThreadFlagsSet((osThreadId_t)ctx, BACKLIGHT_FLAG_ACTIVITY);
}
const uint32_t BACKLIGHT_TIME = 10000;
void backlight_control(void* p) {
// TODO open record
const GpioPin* backlight_record = &backlight_gpio;
@ -14,20 +15,14 @@ void backlight_control(void* p) {
gpio_init(backlight_record, GpioModeOutputPushPull);
gpio_write(backlight_record, true);
StaticSemaphore_t event_descriptor;
SemaphoreHandle_t update = xSemaphoreCreateCountingStatic(255, 0, &event_descriptor);
// open record
PubSub* event_record = furi_open("input_events");
furi_check(event_record);
subscribe_pubsub(event_record, event_cb, (void*)update);
// we ready to work
furiac_ready();
PubSub* event_record = furi_record_open("input_events");
subscribe_pubsub(event_record, event_cb, (void*)osThreadGetId());
while(1) {
// wait for event
if(xSemaphoreTake(update, BACKLIGHT_TIME) == pdTRUE) {
if(osThreadFlagsWait(BACKLIGHT_FLAG_ACTIVITY, osFlagsWaitAny, BACKLIGHT_TIME) ==
BACKLIGHT_FLAG_ACTIVITY) {
gpio_write(backlight_record, true);
} else {
gpio_write(backlight_record, false);

View File

@ -2,16 +2,23 @@
Bt* bt_alloc() {
Bt* bt = furi_alloc(sizeof(Bt));
bt->cli = furi_open("cli");
bt->cli = furi_record_open("cli");
cli_add_command(bt->cli, "bt_info", bt_cli_info, bt);
bt->gui = furi_record_open("gui");
bt->menu = furi_record_open("menu");
bt->statusbar_icon = assets_icons_get(I_Bluetooth_5x8);
bt->statusbar_widget = widget_alloc();
widget_set_width(bt->statusbar_widget, icon_get_width(bt->statusbar_icon));
widget_draw_callback_set(bt->statusbar_widget, bt_draw_statusbar_callback, bt);
widget_enabled_set(bt->statusbar_widget, false);
gui_add_widget(bt->gui, bt->statusbar_widget, GuiLayerStatusBarLeft);
bt->menu_icon = assets_icons_get(A_Bluetooth_14);
bt->menu_item = menu_item_alloc_menu("Bluetooth", bt->menu_icon);
with_value_mutex(
bt->menu, (Menu * menu) { menu_item_add(menu, bt->menu_item); });
return bt;
}
@ -33,23 +40,7 @@ void bt_cli_info(string_t args, void* context) {
void bt_task() {
Bt* bt = bt_alloc();
if(bt->cli) {
cli_add_command(bt->cli, "bt_info", bt_cli_info, bt);
}
// TODO: add ValueMutex(bt) to "bt" record
if(!furi_create("bt", bt)) {
printf("[bt_task] unable to create bt record\n");
furiac_exit(NULL);
}
Gui* gui = furi_open("gui");
gui_add_widget(gui, bt->statusbar_widget, GuiLayerStatusBarLeft);
with_value_mutex(
furi_open("menu"), (Menu * menu) { menu_item_add(menu, bt->menu_item); });
furiac_ready();
furi_record_create("bt", bt);
api_hal_bt_init();

View File

@ -2,10 +2,9 @@
#include "bt.h"
#include <cli/cli.h>
#include <furi.h>
#include <flipper.h>
#include <flipper_v2.h>
#include <cli/cli.h>
#include <gui/gui.h>
#include <gui/widget.h>
@ -15,6 +14,8 @@
typedef struct {
Cli* cli;
Gui* gui;
ValueMutex* menu;
// Status bar
Icon* statusbar_icon;
Widget* statusbar_widget;
@ -26,3 +27,7 @@ typedef struct {
Bt* bt_alloc();
void bt_draw_statusbar_callback(Canvas* canvas, void* context);
void bt_cli_info(string_t args, void* context);
void bt_draw_statusbar_callback(Canvas* canvas, void* context);

View File

@ -1,6 +1,7 @@
#include "flipper.h"
#include "cc1101-workaround/cc1101.h"
#include "cc1101.h"
#include <furi.h>
#include <gui/gui.h>
#include <input/input.h>
extern "C" void cli_print(const char* str);
@ -335,7 +336,7 @@ static void render_callback(Canvas* canvas, void* ctx) {
}
static void input_callback(InputEvent* input_event, void* ctx) {
osMessageQueueId_t event_queue = (QueueHandle_t)ctx;
osMessageQueueId_t event_queue = ctx;
AppEvent event;
event.type = EventTypeKey;
@ -370,7 +371,7 @@ extern "C" void cc1101_workaround(void* p) {
widget_input_callback_set(widget, input_callback, event_queue);
// Open GUI and register widget
Gui* gui = (Gui*)furi_open("gui");
Gui* gui = (Gui*)furi_record_open("gui");
if(gui == NULL) {
printf("[cc1101] gui is not available\n");
furiac_exit(NULL);

View File

@ -1,4 +1,4 @@
#include "flipper_v2.h"
#include <furi.h>
#include "cc1101-workaround/cc1101.h"
#include "spi.h"
#include <math.h>

View File

@ -1,6 +1,6 @@
#pragma once
#include "flipper_v2.h"
#include <furi.h>
#define F_OSC 26e6

View File

@ -1,8 +1,6 @@
#include "cli_i.h"
#include "cli_commands.h"
#include <api-hal-vcp.h>
Cli* cli_alloc() {
Cli* cli = furi_alloc(sizeof(Cli));
CliCommandDict_init(cli->commands);
@ -175,12 +173,7 @@ void cli_task(void* p) {
// Init basic cli commands
cli_commands_init(cli);
if(!furi_create("cli", cli)) {
printf("[cli_task] cannot create the cli record\n");
furiac_exit(NULL);
}
furiac_ready();
furi_record_create("cli", cli);
while(1) {
cli_process_input(cli);

View File

@ -2,8 +2,7 @@
#include "cli.h"
#include <flipper.h>
#include <flipper_v2.h>
#include <furi.h>
#include <m-dict.h>

View File

@ -1,12 +1,10 @@
#include "flipper.h"
#include <furi.h>
#include "u8g2/u8g2.h"
extern TIM_HandleTypeDef SPEAKER_TIM;
void coreglitch_demo_0(void* p) {
FuriRecordSubscriber* log = get_default_log();
fuprintf(log, "coreglitch demo!\n");
printf("coreglitch demo!\n");
float notes[] = {
0.0,

View File

@ -1,195 +0,0 @@
#include "u8g2/u8g2.h"
#include "flipper.h"
#include "main.h"
extern SPI_HandleTypeDef SPI_D;
// TODO: fix log
#ifdef DEBUG
#undef DEBUG
#endif
// TODO rewrite u8g2 to pass thread-local context in this handlers
static uint8_t
u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) {
switch(msg) {
//Initialize SPI peripheral
case U8X8_MSG_GPIO_AND_DELAY_INIT:
/* HAL initialization contains all what we need so we can skip this part. */
break;
//Function which implements a delay, arg_int contains the amount of ms
case U8X8_MSG_DELAY_MILLI:
osDelay(arg_int);
break;
//Function which delays 10us
case U8X8_MSG_DELAY_10MICRO:
delay_us(10);
break;
//Function which delays 100ns
case U8X8_MSG_DELAY_100NANO:
asm("nop");
break;
// Function to define the logic level of the RESET line
case U8X8_MSG_GPIO_RESET:
#ifdef DEBUG
fuprintf(log, "[u8g2] rst %d\n", arg_int);
#endif
// TODO change it to FuriRecord pin
HAL_GPIO_WritePin(
DISPLAY_RST_GPIO_Port, DISPLAY_RST_Pin, arg_int ? GPIO_PIN_SET : GPIO_PIN_RESET);
break;
default:
#ifdef DEBUG
fufuprintf(log, "[u8g2] unknown io %d\n", msg);
#endif
return 0; //A message was received which is not implemented, return 0 to indicate an error
}
return 1; // command processed successfully.
}
static uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) {
switch(msg) {
case U8X8_MSG_BYTE_SEND:
#ifdef DEBUG
fuprintf(log, "[u8g2] send %d bytes %02X\n", arg_int, ((uint8_t*)arg_ptr)[0]);
#endif
// TODO change it to FuriRecord SPI
HAL_SPI_Transmit(&SPI_D, (uint8_t*)arg_ptr, arg_int, 10000);
break;
case U8X8_MSG_BYTE_SET_DC:
#ifdef DEBUG
fuprintf(log, "[u8g2] dc %d\n", arg_int);
#endif
// TODO change it to FuriRecord pin
HAL_GPIO_WritePin(
DISPLAY_DI_GPIO_Port, DISPLAY_DI_Pin, arg_int ? GPIO_PIN_SET : GPIO_PIN_RESET);
break;
case U8X8_MSG_BYTE_INIT:
#ifdef DEBUG
fuprintf(log, "[u8g2] init\n");
#endif
// TODO change it to FuriRecord pin
HAL_GPIO_WritePin(DISPLAY_CS_GPIO_Port, DISPLAY_CS_Pin, GPIO_PIN_RESET);
break;
case U8X8_MSG_BYTE_START_TRANSFER:
#ifdef DEBUG
fuprintf(log, "[u8g2] start\n");
#endif
// TODO change it to FuriRecord pin
HAL_GPIO_WritePin(DISPLAY_CS_GPIO_Port, DISPLAY_CS_Pin, GPIO_PIN_RESET);
asm("nop");
break;
case U8X8_MSG_BYTE_END_TRANSFER:
#ifdef DEBUG
fuprintf(log, "[u8g2] end\n");
#endif
asm("nop");
// TODO change it to FuriRecord pin
HAL_GPIO_WritePin(DISPLAY_CS_GPIO_Port, DISPLAY_CS_Pin, GPIO_PIN_SET);
break;
default:
#ifdef DEBUG
fuprintf(log, "[u8g2] unknown xfer %d\n", msg);
#endif
return 0;
}
return 1;
}
typedef struct {
SemaphoreHandle_t update; // queue to pass events from callback to app thread
FuriRecordSubscriber* log; // app logger
} DisplayCtx;
static void handle_fb_change(const void* fb, size_t fb_size, void* raw_ctx) {
DisplayCtx* ctx = (DisplayCtx*)raw_ctx; // make right type
// fuprintf(ctx->log, "[display_u8g2] change fb\n");
// send update to app thread
xSemaphoreGive(ctx->update);
}
void display_u8g2(void* p) {
FuriRecordSubscriber* log = get_default_log();
// TODO we need different app to contol backlight
HAL_GPIO_WritePin(DISPLAY_BACKLIGHT_GPIO_Port, DISPLAY_BACKLIGHT_Pin, GPIO_PIN_SET);
u8g2_t _u8g2;
u8g2_Setup_st7565_erc12864_alt_f(
&_u8g2, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32);
u8g2_InitDisplay(
&_u8g2); // send init sequence to the display, display is in sleep mode after this
u8g2_SetContrast(&_u8g2, 36);
if(!furi_create_deprecated("u8g2_fb", (void*)&_u8g2, sizeof(_u8g2))) {
fuprintf(log, "[display_u8g2] cannot create fb record\n");
furiac_exit(NULL);
}
StaticSemaphore_t event_descriptor;
// create stack-based counting semaphore
SemaphoreHandle_t update = xSemaphoreCreateCountingStatic(255, 0, &event_descriptor);
if(update == NULL) {
fuprintf(log, "[display_u8g2] cannot create update semaphore\n");
furiac_exit(NULL);
}
// save log and event queue in context structure
DisplayCtx ctx = {.update = update, .log = log};
// subscribe to record. ctx will be passed to handle_fb_change
FuriRecordSubscriber* fb_record =
furi_open_deprecated("u8g2_fb", false, false, handle_fb_change, NULL, &ctx);
if(fb_record == NULL) {
fuprintf(log, "[display] cannot open fb record\n");
furiac_exit(NULL);
}
u8g2_t* u8g2 = (u8g2_t*)furi_take(fb_record);
u8g2_SetPowerSave(u8g2, 0); // wake up display
u8g2_SendBuffer(u8g2);
furi_give(fb_record);
// we ready to work
furiac_ready();
while(1) {
// wait for event
if(xSemaphoreTake(update, 10000) == pdTRUE) {
HAL_GPIO_WritePin(DISPLAY_BACKLIGHT_GPIO_Port, DISPLAY_BACKLIGHT_Pin, GPIO_PIN_SET);
u8g2_t* u8g2 = (u8g2_t*)furi_take(fb_record);
u8g2_SetPowerSave(u8g2, 0); // wake up display
u8g2_SendBuffer(u8g2);
furi_give(fb_record);
} else {
// TODO we need different app to contol backlight
HAL_GPIO_WritePin(DISPLAY_BACKLIGHT_GPIO_Port, DISPLAY_BACKLIGHT_Pin, GPIO_PIN_RESET);
}
}
}

View File

@ -67,8 +67,7 @@ Dolphin* dolphin_alloc() {
// State
dolphin->state = dolphin_state_alloc();
// Menu
dolphin->menu_vm = furi_open("menu");
furi_check(dolphin->menu_vm);
dolphin->menu_vm = furi_record_open("menu");
// GUI
dolphin->idle_view_dispatcher = view_dispatcher_alloc();
// First start View
@ -125,7 +124,7 @@ void dolphin_deed(Dolphin* dolphin, DolphinDeed deed) {
void dolphin_task() {
Dolphin* dolphin = dolphin_alloc();
Gui* gui = furi_open("gui");
Gui* gui = furi_record_open("gui");
view_dispatcher_attach_to_gui(dolphin->idle_view_dispatcher, gui, ViewDispatcherTypeWindow);
if(dolphin_state_load(dolphin->state)) {
view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain);
@ -138,12 +137,7 @@ void dolphin_task() {
model->butthurt = dolphin_state_get_butthurt(dolphin->state);
});
if(!furi_create("dolphin", dolphin)) {
printf("[dolphin_task] cannot create the dolphin record\n");
furiac_exit(NULL);
}
furiac_ready();
furi_record_create("dolphin", dolphin);
DolphinEvent event;
while(1) {

View File

@ -4,7 +4,7 @@
#include "dolphin_state.h"
#include "dolphin_views.h"
#include <flipper_v2.h>
#include <furi.h>
#include <gui/gui.h>
#include <gui/view_dispatcher.h>

View File

@ -1,6 +1,5 @@
#include "dolphin_state.h"
#include <api-hal-flash.h>
#include <flipper_v2.h>
#include <furi.h>
typedef struct {
uint8_t magic;

View File

@ -3,7 +3,8 @@
#include <stdint.h>
#include <stdbool.h>
#include <gui/canvas.h>
#include <flipper_v2.h>
#include <input/input.h>
#include <furi.h>
// Idle scree
typedef enum {

View File

@ -1,4 +1,4 @@
#include "flipper_v2.h"
#include <furi.h>
void rgb_set(
bool r,

View File

@ -1,155 +0,0 @@
#include "u8g2/u8g2.h"
#include "fatfs/ff.h"
#include "flipper_v2.h"
#include <stdio.h>
extern uint8_t BSP_SD_Init();
// TODO currently we have small stack, so it will be static
FuriRecordSubscriber* furi_log;
#define STR_BUFFER_SIZE 128
char str_buffer[STR_BUFFER_SIZE];
uint8_t line_current = 0;
uint16_t line_position = 0;
// TODO this should be in the target driver
FATFS SD_FatFs;
char SD_Path[4];
typedef enum {
EventTypeStart,
EventTypeKey,
} AppEventType;
typedef struct {
union {
InputEvent input;
} value;
AppEventType type;
} AppEvent;
static void event_cb(const void* value, void* ctx) {
QueueHandle_t event_queue = (QueueHandle_t)ctx;
AppEvent event;
event.type = EventTypeKey;
event.value.input = *(InputEvent*)value;
xQueueSend(event_queue, (void*)&event, 0);
}
void fatfs_list(void* p) {
const uint8_t line_size = 10;
const uint8_t lines_on_display = 6;
uint8_t bsp_result;
FRESULT result;
DIR dir;
FILINFO fno;
AppEvent event;
QueueHandle_t event_queue = xQueueCreate(2, sizeof(AppEvent));
furi_log = get_default_log();
fuprintf(furi_log, "[fatfs_list] app start\n");
fuprintf(furi_log, "[fatfs_list] wait for sd insert\n");
while(!hal_gpio_read_sd_detect()) {
delay(100);
}
fuprintf(furi_log, "[fatfs_list] sd inserted\n");
FuriRecordSubscriber* fb_record =
furi_open_deprecated("u8g2_fb", false, false, NULL, NULL, NULL);
if(fb_record == NULL) {
fuprintf(furi_log, "[fatfs_list] cannot create fb record\n");
furiac_exit(NULL);
}
PubSub* event_record = furi_open("input_events");
if(event_record == NULL) {
fuprintf(furi_log, "[fatfs_list] cannot open input_events record\n");
furiac_exit(NULL);
}
PubSubItem* subscription = subscribe_pubsub(event_record, event_cb, event_queue);
if(subscription == NULL) {
fuprintf(furi_log, "[fatfs_list] cannot register input_events callback\n");
furiac_exit(NULL);
}
bsp_result = BSP_SD_Init();
if(bsp_result != 0) {
fuprintf(furi_log, "[fatfs_list] SD card init error\n");
furiac_exit(NULL);
}
result = f_mount(&SD_FatFs, (TCHAR const*)SD_Path, 1);
if(result != FR_OK) {
fuprintf(furi_log, "[fatfs_list] SD card mount error\n");
furiac_exit(NULL);
}
// ok, now we can work with sd card
// send start event
event.type = EventTypeStart;
xQueueSend(event_queue, (void*)&event, 0);
while(1) {
if(xQueueReceive(event_queue, (void*)&event, portMAX_DELAY)) {
// process buttons event
if(event.type == EventTypeKey) {
// button pressed
if(event.value.input.state == true) {
if(event.value.input.input == InputUp && line_position > 0) {
line_position--;
}
if(event.value.input.input == InputDown) {
line_position++;
}
}
}
line_current = 1;
// open root dir
result = f_opendir(&dir, "");
while(1) {
// read a directory item
result = f_readdir(&dir, &fno);
if(result != FR_OK) {
// cannot read dir
break;
}
if(fno.fname[0] == 0) {
// Break on end of dir
break;
}
// draw files on display
if(line_current > line_position &&
line_current <= (line_position + lines_on_display)) {
if(fno.fattrib & AM_DIR) {
snprintf(str_buffer, STR_BUFFER_SIZE, "DIR %s\n", fno.fname);
} else {
snprintf(str_buffer, STR_BUFFER_SIZE, "FIL %s\n", fno.fname);
}
fuprintf(furi_log, str_buffer);
}
line_current++;
}
result = f_closedir(&dir);
furi_commit(fb_record);
}
}
furiac_exit(NULL);
}

View File

@ -1,5 +1,6 @@
#include "flipper_v2.h"
#include <furi.h>
#include <stdio.h>
#include <input/input.h>
typedef union {
unsigned int packed;
@ -21,12 +22,10 @@ static void event_cb(const void* value, void* ctx) {
void application_input_dump(void* p) {
// open record
ValueManager* state_record = furi_open("input_state");
furi_check(state_record);
ValueManager* state_record = furi_record_open("input_state");
subscribe_pubsub(&state_record->pubsub, state_cb, NULL);
PubSub* event_record = furi_open("input_events");
furi_check(event_record);
PubSub* event_record = furi_record_open("input_events");
subscribe_pubsub(event_record, event_cb, NULL);
printf("Example app [input dump]\n");

View File

@ -1,155 +0,0 @@
#include "flipper.h"
#include <string.h>
#define FB_WIDTH 10
#define FB_HEIGHT 3
#define FB_SIZE (FB_WIDTH * FB_HEIGHT)
// context structure used for pass some object from app thread to callback
typedef struct {
SemaphoreHandle_t events; // queue to pass events from callback to app thread
FuriRecordSubscriber* log; // app logger
} IpcCtx;
static void handle_fb_change(const void* fb, size_t fb_size, void* raw_ctx) {
IpcCtx* ctx = (IpcCtx*)raw_ctx; // make right type
fuprintf(ctx->log, "[cb] framebuffer updated\n");
// send event to app thread
xSemaphoreGive(ctx->events);
// Attention! Please, do not make blocking operation like IO and waits inside callback
// Remember that callback execute in calling thread/context
}
static void print_fb(char* fb, FuriRecordSubscriber* log) {
if(fb == NULL) return;
/* draw framebuffer like this:
+==========+
| |
| |
| |
+==========+
*/
char row_buffer[FB_WIDTH + 1];
row_buffer[FB_WIDTH] = '\0';
// FB layout is hardcoded here
fuprintf(log, "+==========+\n");
for(uint8_t i = 0; i < FB_HEIGHT; i++) {
strncpy(row_buffer, &fb[FB_WIDTH * i], FB_WIDTH);
fuprintf(log, "|%s|\n", row_buffer);
}
fuprintf(log, "+==========+\n");
}
void application_ipc_display(void* p) {
// get logger
FuriRecordSubscriber* log = get_default_log();
// create ASCII "framebuffer"
// FB_WIDTH x FB_HEIGHT char buffer
char _framebuffer[FB_SIZE];
// init framebuffer by spaces
for(size_t i = 0; i < FB_SIZE; i++) {
_framebuffer[i] = ' ';
}
// create record
if(!furi_create_deprecated("test_fb", (void*)_framebuffer, FB_SIZE)) {
fuprintf(log, "[display] cannot create fb record\n");
furiac_exit(NULL);
}
StaticSemaphore_t event_descriptor;
// create stack-based counting semaphore
SemaphoreHandle_t events = xSemaphoreCreateCountingStatic(255, 0, &event_descriptor);
if(events == NULL) {
fuprintf(log, "[display] cannot create event semaphore\n");
furiac_exit(NULL);
}
// save log and event queue in context structure
IpcCtx ctx = {.events = events, .log = log};
// subscribe to record. ctx will be passed to handle_fb_change
FuriRecordSubscriber* fb_record =
furi_open_deprecated("test_fb", false, false, handle_fb_change, NULL, &ctx);
if(fb_record == NULL) {
fuprintf(log, "[display] cannot open fb record\n");
furiac_exit(NULL);
}
#ifdef HW_DISPLAY
// on Flipper target -- open screen
// draw border
#else
// on Local target -- print "blank screen"
{
void* fb = furi_take(fb_record);
print_fb((char*)fb, log);
furi_give(fb_record);
}
#endif
while(1) {
// wait for event
if(xSemaphoreTake(events, portMAX_DELAY) == pdTRUE) {
fuprintf(log, "[display] get fb update\n\n");
#ifdef HW_DISPLAY
// on Flipper target draw the screen
#else
// on local target just print
{
void* fb = furi_take(fb_record);
print_fb((char*)fb, log);
furi_give(fb_record);
}
#endif
}
}
}
// Widget application
void application_ipc_widget(void* p) {
FuriRecordSubscriber* log = get_default_log();
// open record
FuriRecordSubscriber* fb_record =
furi_open_deprecated("test_fb", false, false, NULL, NULL, NULL);
if(fb_record == NULL) {
fuprintf(log, "[widget] cannot create fb record\n");
furiac_exit(NULL);
}
uint8_t counter = 0;
while(1) {
delay(120);
// write some ascii demo here: '#'' symbol run on overall screen
char* fb = (char*)furi_take(fb_record);
if(fb == NULL) furiac_exit(NULL);
for(size_t i = 0; i < FB_SIZE; i++) {
fb[i] = ' ';
}
fb[counter % FB_SIZE] = '#';
furi_commit(fb_record);
counter++;
}
}

View File

@ -1,4 +1,5 @@
#include "flipper_v2.h"
#include <furi.h>
#include <input.h>
static void event_cb(const void* value, void* ctx) {
const InputEvent* event = value;
@ -38,8 +39,7 @@ void application_strobe(void* p) {
ValueMutex delay_mutex;
init_mutex(&delay_mutex, &delay_time_holder, sizeof(delay_time_holder));
PubSub* event_record = furi_open("input_events");
furi_check(event_record);
PubSub* event_record = furi_record_open("input_events");
subscribe_pubsub(event_record, event_cb, &delay_mutex);
while(1) {

View File

@ -1,32 +1,14 @@
#include "u8g2/u8g2.h"
#include "flipper.h"
#include <furi.h>
void u8g2_example(void* p) {
FuriRecordSubscriber* log = get_default_log();
// open record
FuriRecordSubscriber* fb_record =
furi_open_deprecated("u8g2_fb", false, false, NULL, NULL, NULL);
u8g2_t* fb = furi_record_open("u8g2_fb");
u8g2_SetFont(fb, u8g2_font_6x10_mf);
u8g2_SetDrawColor(fb, 1);
u8g2_SetFontMode(fb, 1);
u8g2_DrawStr(fb, 2, 12, "hello world!");
furi_record_close("u8g2_fb");
if(fb_record == NULL) {
fuprintf(log, "[widget] cannot create fb record\n");
furiac_exit(NULL);
}
while(1) {
u8g2_t* fb = furi_take(fb_record);
if(fb != NULL) {
u8g2_SetFont(fb, u8g2_font_6x10_mf);
u8g2_SetDrawColor(fb, 1);
u8g2_SetFontMode(fb, 1);
u8g2_DrawStr(fb, 2, 12, "hello world!");
}
furi_commit(fb_record);
if(fb != NULL) {
furiac_exit(NULL);
}
delay(1);
}
furiac_exit(NULL);
}

View File

@ -1,6 +1,9 @@
#include "u8g2/u8g2.h"
#include "qrcode/qrcode.h"
#include "flipper.h"
#include <furi.h>
/*
TODO: rework with new app api
void u8g2_DrawPixelSize(u8g2_t* u8g2, uint8_t x, uint8_t y, uint8_t size) {
for(uint8_t px = 0; px < size; px++) {
@ -11,8 +14,6 @@ void u8g2_DrawPixelSize(u8g2_t* u8g2, uint8_t x, uint8_t y, uint8_t size) {
}
void u8g2_qrcode(void* p) {
FuriRecordSubscriber* log = get_default_log();
// open record
FuriRecordSubscriber* fb_record =
furi_open_deprecated("u8g2_fb", false, false, NULL, NULL, NULL);
@ -36,7 +37,7 @@ void u8g2_qrcode(void* p) {
qrcode_initText(&qrcode, qrcodeBytes, qr_version, qr_error_correction, "HELLO FLIPPER");
if(fb_record == NULL) {
fuprintf(log, "[widget] cannot create fb record\n");
printf("[widget] cannot create fb record\n");
furiac_exit(NULL);
}
@ -69,4 +70,5 @@ void u8g2_qrcode(void* p) {
delay(1);
}
}
}
*/

View File

@ -1,7 +1,5 @@
#include "flipper.h"
#include <furi.h>
#include <string.h>
#include "log.h"
#include "flipper_v2.h"
void application_uart_write(void* p) {
// Red led for showing progress
@ -11,12 +9,9 @@ void application_uart_write(void* p) {
gpio_init(led_record, GpioModeOutputOpenDrain);
// get_default_log open "tty" record
FuriRecordSubscriber* log = get_default_log();
// create buffer
const char test_string[] = "test\n";
furi_write(log, test_string, strlen(test_string));
printf(test_string);
// for example, create counter and show its value
uint8_t counter = 0;

View File

@ -1,4 +1,5 @@
#include "flipper_v2.h"
#include <furi.h>
#include <input/input.h>
typedef struct {
GpioPin* led;
@ -24,7 +25,7 @@ void application_vibro(void* p) {
gpio_write(ctx.vibro, false);
// subscribe on buttons
PubSub* event_record = furi_open("input_events");
PubSub* event_record = furi_record_open("input_events");
furi_check(event_record);
subscribe_pubsub(event_record, button_handler, &ctx);

@ -1 +1 @@
Subproject commit 25a2cc076c3162aad721e0d92009cfa7b9100c7a
Subproject commit 621044255a8be4d2c3f342e2b22178a342ccbfe8

View File

@ -1,4 +1,6 @@
#include "flipper_v2.h"
#include <furi.h>
#include <gui/gui.h>
#include <input/input.h>
typedef struct {
const char* name;
@ -47,7 +49,7 @@ static void render_callback(Canvas* canvas, void* ctx) {
}
static void input_callback(InputEvent* input_event, void* ctx) {
osMessageQueueId_t event_queue = (QueueHandle_t)ctx;
osMessageQueueId_t event_queue = ctx;
AppEvent event;
event.type = EventTypeKey;
@ -74,11 +76,7 @@ void app_gpio_test(void* p) {
widget_input_callback_set(widget, input_callback, event_queue);
// Open GUI and register widget
Gui* gui = (Gui*)furi_open("gui");
if(gui == NULL) {
printf("[gpio-tester] gui is not available\n");
furiac_exit(NULL);
}
Gui* gui = furi_record_open("gui");
gui_add_widget(gui, widget, GuiLayerFullscreen);
// configure pin

View File

@ -1,8 +1,7 @@
#include "canvas_i.h"
#include "icon_i.h"
#include <flipper.h>
#include <flipper_v2.h>
#include <furi.h>
struct Canvas {
u8g2_t fb;

View File

@ -5,6 +5,10 @@
#include <gui/icon.h>
#include <assets_icons_i.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
ColorWhite = 0x00,
ColorBlack = 0x01,
@ -91,3 +95,7 @@ void canvas_draw_line(Canvas* canvas, uint8_t x1, uint8_t y1, uint8_t x2, uint8_
* Draw glyph
*/
void canvas_draw_glyph(Canvas* canvas, uint8_t x, uint8_t y, uint16_t ch);
#ifdef __cplusplus
}
#endif

View File

@ -3,6 +3,10 @@
#include <stdint.h>
#include "canvas.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* Draw scrollbar on canvas.
* width 3px, height equal to canvas height
@ -17,3 +21,7 @@ void elements_scrollbar(Canvas* canvas, uint8_t pos, uint8_t total);
* @param width, height - frame width and height
*/
void elements_frame(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width, uint8_t height);
#ifdef __cplusplus
}
#endif

View File

@ -1,8 +1,7 @@
#include "gui.h"
#include "gui_i.h"
#include <flipper.h>
#include <flipper_v2.h>
#include <furi.h>
#include <m-array.h>
#include <stdio.h>
@ -207,13 +206,9 @@ Gui* gui_alloc() {
void gui_task(void* p) {
Gui* gui = gui_alloc();
// Create FURI record
if(!furi_create("gui", gui)) {
printf("[gui_task] cannot create the gui record\n");
furiac_exit(NULL);
}
furiac_ready();
// Create FURI record
furi_record_create("gui", gui);
// Forever dispatch
while(1) {

View File

@ -3,6 +3,10 @@
#include "widget.h"
#include "canvas.h"
#ifdef __cplusplus
extern "C" {
#endif
#define GUI_DISPLAY_WIDTH 128
#define GUI_DISPLAY_HEIGHT 64
@ -40,3 +44,7 @@ void gui_add_widget(Gui* gui, Widget* widget, GuiLayer layer);
* @remarks thread safe
*/
void gui_remove_widget(Gui* gui, Widget* widget);
#ifdef __cplusplus
}
#endif

View File

@ -1,6 +1,6 @@
#include "gui_event.h"
#include <flipper_v2.h>
#include <furi.h>
#define GUI_EVENT_MQUEUE_SIZE 8
@ -45,7 +45,7 @@ GuiEvent* gui_event_alloc() {
// osTimerStart(gui_event->timer, 1024 / 4);
// Input
gui_event->input_event_record = furi_open("input_events");
gui_event->input_event_record = furi_record_open("input_events");
furi_check(gui_event->input_event_record != NULL);
subscribe_pubsub(gui_event->input_event_record, gui_event_input_events_callback, gui_event);

View File

@ -3,6 +3,10 @@
#include <stdint.h>
#include <input/input.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
GuiMessageTypeRedraw = 0x00,
GuiMessageTypeInput = 0x01,
@ -23,3 +27,7 @@ void gui_event_free(GuiEvent* gui_event);
void gui_event_messsage_send(GuiEvent* gui_event, GuiMessage* message);
GuiMessage gui_event_message_next(GuiEvent* gui_event);
#ifdef __cplusplus
}
#endif

View File

@ -1,8 +1,6 @@
#include "icon_i.h"
#include <cmsis_os2.h>
#include <flipper.h>
#include <flipper_v2.h>
#include <furi.h>
Icon* icon_alloc(const IconData* data) {
Icon* icon = furi_alloc(sizeof(Icon));

View File

@ -3,6 +3,10 @@
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct IconData IconData;
typedef struct Icon Icon;
@ -41,3 +45,7 @@ void icon_start_animation(Icon* icon);
* Stop icon animation
*/
void icon_stop_animation(Icon* icon);
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,5 @@
#include "u8g2/u8g2.h"
#include "flipper.h"
#include <furi.h>
#include <main.h>
extern SPI_HandleTypeDef SPI_D;
@ -34,7 +34,7 @@ uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, vo
// Function to define the logic level of the RESET line
case U8X8_MSG_GPIO_RESET:
#ifdef DEBUG
fuprintf(log, "[u8g2] rst %d\n", arg_int);
printf("[u8g2] rst %d\n", arg_int);
#endif
// TODO change it to FuriRecord pin
@ -44,7 +44,7 @@ uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, vo
default:
#ifdef DEBUG
fufuprintf(log, "[u8g2] unknown io %d\n", msg);
printf("[u8g2] unknown io %d\n", msg);
#endif
return 0; //A message was received which is not implemented, return 0 to indicate an error
@ -57,7 +57,7 @@ uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_
switch(msg) {
case U8X8_MSG_BYTE_SEND:
#ifdef DEBUG
fuprintf(log, "[u8g2] send %d bytes %02X\n", arg_int, ((uint8_t*)arg_ptr)[0]);
printf("[u8g2] send %d bytes %02X\n", arg_int, ((uint8_t*)arg_ptr)[0]);
#endif
// TODO change it to FuriRecord SPI
@ -66,7 +66,7 @@ uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_
case U8X8_MSG_BYTE_SET_DC:
#ifdef DEBUG
fuprintf(log, "[u8g2] dc %d\n", arg_int);
printf("[u8g2] dc %d\n", arg_int);
#endif
// TODO change it to FuriRecord pin
@ -76,7 +76,7 @@ uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_
case U8X8_MSG_BYTE_INIT:
#ifdef DEBUG
fuprintf(log, "[u8g2] init\n");
printf("[u8g2] init\n");
#endif
// TODO change it to FuriRecord pin
@ -85,7 +85,7 @@ uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_
case U8X8_MSG_BYTE_START_TRANSFER:
#ifdef DEBUG
fuprintf(log, "[u8g2] start\n");
printf("[u8g2] start\n");
#endif
// TODO: SPI manager
@ -98,7 +98,7 @@ uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_
case U8X8_MSG_BYTE_END_TRANSFER:
#ifdef DEBUG
fuprintf(log, "[u8g2] end\n");
printf("[u8g2] end\n");
#endif
asm("nop");
@ -112,7 +112,7 @@ uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_
default:
#ifdef DEBUG
fuprintf(log, "[u8g2] unknown xfer %d\n", msg);
printf("[u8g2] unknown xfer %d\n", msg);
#endif
return 0;

View File

@ -3,6 +3,10 @@
#include <input/input.h>
#include "canvas.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Hides drawing widget */
#define VIEW_NONE 0xFFFFFFFF
/* Ignore navigation event */
@ -127,3 +131,7 @@ void view_commit_model(View* view);
({ void __fn__ function_body __fn__; })(p); \
view_commit_model(view); \
}
#ifdef __cplusplus
}
#endif

View File

@ -3,6 +3,10 @@
#include "view.h"
#include "gui.h"
#ifdef __cplusplus
extern "C" {
#endif
/* ViewDispatcher widget placement */
typedef enum {
ViewDispatcherTypeNone, /* Special layer for internal use only */
@ -43,3 +47,7 @@ void view_dispatcher_attach_to_gui(
ViewDispatcher* view_dispatcher,
Gui* gui,
ViewDispatcherType type);
#ifdef __cplusplus
}
#endif

View File

@ -2,7 +2,7 @@
#include "view_dispatcher.h"
#include "view_i.h"
#include <flipper_v2.h>
#include <furi.h>
#include <m-dict.h>
DICT_DEF2(ViewDict, uint32_t, M_DEFAULT_OPLIST, View*, M_PTR_OPLIST)

View File

@ -2,7 +2,7 @@
#include "view.h"
#include "view_dispatcher_i.h"
#include <flipper_v2.h>
#include <furi.h>
typedef struct {
void* data;

View File

@ -1,8 +1,6 @@
#include "widget_i.h"
#include <cmsis_os.h>
#include <flipper.h>
#include <flipper_v2.h>
#include <furi.h>
#include "gui.h"
#include "gui_i.h"
@ -73,8 +71,6 @@ void widget_update(Widget* widget) {
void widget_gui_set(Widget* widget, Gui* gui) {
furi_assert(widget);
furi_assert(gui);
widget->gui = gui;
}

View File

@ -3,6 +3,10 @@
#include <input/input.h>
#include "canvas.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct Widget Widget;
/*
@ -65,3 +69,7 @@ void widget_input_callback_set(Widget* widget, WidgetInputCallback callback, voi
* Rendering will happen later after GUI system process signal.
*/
void widget_update(Widget* widget);
#ifdef __cplusplus
}
#endif

View File

@ -32,7 +32,7 @@ void AppiButton::run() {
printf("[ibutton] bye!\n");
// TODO remove all widgets create by app
widget_enabled_set(widget, false);
furiac_exit(NULL);
osThreadExit();
}
if(event.value.input.state && event.value.input.input == InputLeft) {

View File

@ -1,6 +1,6 @@
#include <input/input.h>
#include <stdio.h>
#include <flipper_v2.h>
#include <furi.h>
#ifdef APP_NFC
void nfc_isr(void);
@ -35,18 +35,10 @@ void input_task(void* p) {
furiac_exit(NULL);
}
if(!furi_create("input_state", &input_state_record)) {
printf("[input_task] cannot create the input_state record\n");
furiac_exit(NULL);
}
if(!furi_create("input_events", &input_events_record)) {
printf("[input_task] cannot create the input_events record\n");
furiac_exit(NULL);
}
furi_record_create("input_state", &input_state_record);
furi_record_create("input_events", &input_events_record);
// we ready to work
furiac_ready();
initialized = true;
// Force state update

View File

@ -1,6 +1,5 @@
#pragma once
#include "flipper.h"
#include "flipper_v2.h"
#include <furi.h>
#include "irda-decoder-nec.h"
#include "irda-decoder-types.h"

View File

@ -1,5 +1,7 @@
#include "flipper.h"
#include "flipper_v2.h"
#include <furi.h>
#include <gui/gui.h>
#include <input/input.h>
#include "irda_nec.h"
#include "irda_samsung.h"
#include "irda_protocols.h"
@ -185,7 +187,7 @@ static void render_callback(Canvas* canvas, void* ctx) {
}
static void input_callback(InputEvent* input_event, void* ctx) {
osMessageQueueId_t event_queue = (QueueHandle_t)ctx;
osMessageQueueId_t event_queue = ctx;
AppEvent event;
event.type = EventTypeKey;
@ -271,11 +273,7 @@ void irda(void* p) {
widget_input_callback_set(widget, input_callback, event_queue);
// Open GUI and register widget
Gui* gui = (Gui*)furi_open("gui");
if(gui == NULL) {
printf("gui is not available\n");
furiac_exit(NULL);
}
Gui* gui = furi_record_open("gui");
gui_add_widget(gui, widget, GuiLayerFullscreen);
// Red LED

View File

@ -1,4 +1,4 @@
#include "flipper.h"
#include <furi.h>
#include "irda_nec.h"
#include "irda_protocols.h"

View File

@ -1,4 +1,4 @@
#pragma once
#include "flipper.h"
#include <furi.h>
void ir_nec_send(uint16_t addr, uint8_t data);

View File

@ -1,4 +1,4 @@
#include "flipper.h"
#include <furi.h>
#include "irda_samsung.h"
#include "irda_protocols.h"

View File

@ -1,4 +1,4 @@
#pragma once
#include "flipper.h"
#include <furi.h>
void ir_samsung_send(uint16_t addr, uint16_t data);

View File

@ -1,4 +1,4 @@
#include "flipper_v2.h"
#include <furi.h>
void prepare_data(uint32_t ID, uint32_t VENDOR, uint8_t* data) {
uint8_t value[10];

View File

@ -1,4 +1,5 @@
#include "flipper_v2.h"
#include <furi.h>
#include <gui/gui.h>
typedef enum { EventTypeTick, EventTypeKey, EventTypeRx } EventType;
@ -45,7 +46,7 @@ static void render_callback(Canvas* canvas, void* ctx) {
}
static void input_callback(InputEvent* input_event, void* ctx) {
osMessageQueueId_t event_queue = (QueueHandle_t)ctx;
osMessageQueueId_t event_queue = ctx;
AppEvent event;
event.type = EventTypeKey;
@ -67,7 +68,7 @@ void comparator_trigger_callback(void* hcomp, void* comp_ctx) {
// gpio_write(&debug_0, true);
osMessageQueueId_t event_queue = (QueueHandle_t)comp_ctx;
osMessageQueueId_t event_queue = comp_ctx;
AppEvent event;
event.type = EventTypeRx;
@ -202,11 +203,7 @@ void lf_rfid_workaround(void* p) {
widget_input_callback_set(widget, input_callback, event_queue);
// Open GUI and register widget
Gui* gui = (Gui*)furi_open("gui");
if(gui == NULL) {
printf("gui is not available\n");
furiac_exit(NULL);
}
Gui* gui = furi_record_open("gui");
gui_add_widget(gui, widget, GuiLayerFullscreen);
AppEvent event;

View File

@ -1,9 +1,8 @@
#include "menu.h"
#include <cmsis_os.h>
#include <stdio.h>
#include <stdbool.h>
#include <flipper_v2.h>
#include <furi.h>
#include <gui/gui.h>
#include <gui/elements.h>
@ -42,8 +41,7 @@ ValueMutex* menu_init() {
menu->widget = widget_alloc();
// Open GUI and register fullscreen widget
Gui* gui = furi_open("gui");
furi_check(gui);
Gui* gui = furi_record_open("gui");
gui_add_widget(gui, menu->widget, GuiLayerFullscreen);
widget_enabled_set(menu->widget, false);
@ -237,12 +235,7 @@ void menu_task(void* p) {
release_mutex(menu_mutex, menu);
}
if(!furi_create("menu", menu_mutex)) {
printf("[menu_task] cannot create the menu record\n");
furiac_exit(NULL);
}
furiac_ready();
furi_record_create("menu", menu_mutex);
while(1) {
MenuMessage m = menu_event_next(menu_event);

View File

@ -1,11 +1,9 @@
#include "menu_event.h"
#include <cmsis_os.h>
#include <string.h>
#include <stdlib.h>
#include <flipper.h>
#include <flipper_v2.h>
#include <furi.h>
#define MENU_MESSAGE_MQUEUE_SIZE 8

View File

@ -1,8 +1,7 @@
#include "menu_item.h"
#include <stdlib.h>
#include <string.h>
#include <flipper.h>
#include <flipper_v2.h>
#include <furi.h>
struct MenuItem {
MenuItemType type;

View File

@ -1,4 +1,6 @@
#include "flipper_v2.h"
#include <furi.h>
#include <gui/gui.h>
#include <input/input.h>
// TODO float note freq
typedef enum {
@ -302,7 +304,7 @@ static void render_callback(Canvas* canvas, void* ctx) {
}
static void input_callback(InputEvent* input_event, void* ctx) {
osMessageQueueId_t event_queue = (QueueHandle_t)ctx;
osMessageQueueId_t event_queue = ctx;
MusicDemoEvent event;
event.type = EventTypeKey;
@ -376,15 +378,11 @@ void music_player(void* p) {
widget_input_callback_set(widget, input_callback, event_queue);
// Open GUI and register widget
Gui* gui = (Gui*)furi_open("gui");
if(gui == NULL) {
printf("gui is not available\n");
furiac_exit(NULL);
}
Gui* gui = furi_record_open("gui");
gui_add_widget(gui, widget, GuiLayerFullscreen);
// open input record
PubSub* input_events_record = furi_open("input_events");
PubSub* input_events_record = furi_record_open("input_events");
// prepare "do nothing" event
InputEvent input_event = {InputRight, true};

View File

@ -16,8 +16,7 @@ Nfc* nfc_alloc() {
nfc->worker = nfc_worker_alloc(nfc->message_queue);
nfc->icon = assets_icons_get(A_NFC_14);
nfc->menu_vm = furi_open("menu");
furi_check(nfc->menu_vm);
nfc->menu_vm = furi_record_open("menu");
nfc->menu = menu_item_alloc_menu("NFC", nfc->icon);
menu_item_subitem_add(
@ -102,18 +101,13 @@ void nfc_start(Nfc* nfc, NfcView view_id, NfcWorkerState worker_state) {
void nfc_task(void* p) {
Nfc* nfc = nfc_alloc();
Gui* gui = furi_open("gui");
Gui* gui = furi_record_open("gui");
view_dispatcher_attach_to_gui(nfc->view_dispatcher, gui, ViewDispatcherTypeFullscreen);
with_value_mutex(
nfc->menu_vm, (Menu * menu) { menu_item_add(menu, nfc->menu); });
if(!furi_create("nfc", nfc)) {
printf("[nfc_task] cannot create nfc record\n");
furiac_exit(NULL);
}
furiac_ready();
furi_record_create("nfc", nfc);
NfcMessage message;
while(1) {

View File

@ -5,7 +5,7 @@
#include "nfc_views.h"
#include "nfc_worker.h"
#include <flipper_v2.h>
#include <furi.h>
#include <gui/gui.h>
#include <gui/view.h>

View File

@ -3,7 +3,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <gui/canvas.h>
#include <flipper_v2.h>
#include <furi.h>
#include "nfc_types.h"

View File

@ -3,8 +3,7 @@
#include "nfc_types.h"
#include "nfc_worker.h"
#include <flipper_v2.h>
#include <cmsis_os2.h>
#include <furi.h>
#include <stdbool.h>
#include <rfal_analogConfig.h>

View File

@ -1,7 +1,7 @@
#include "power.h"
#include "power_views.h"
#include <flipper_v2.h>
#include <furi.h>
#include <menu/menu.h>
#include <menu/menu_item.h>
@ -12,8 +12,8 @@
#include <gui/view_dispatcher.h>
#include <assets_icons.h>
#include <api-hal-power.h>
#include <cli/cli.h>
#include <stm32wbxx.h>
struct Power {
ViewDispatcher* view_dispatcher;
@ -47,6 +47,10 @@ void power_draw_battery_callback(Canvas* canvas, void* context) {
});
}
uint32_t power_info_back_callback(void* context) {
return VIEW_NONE;
}
void power_menu_off_callback(void* context) {
api_hal_power_off();
}
@ -71,10 +75,9 @@ void power_menu_info_callback(void* context) {
Power* power_alloc() {
Power* power = furi_alloc(sizeof(Power));
power->menu_vm = furi_open("menu");
furi_check(power->menu_vm);
power->menu_vm = furi_record_open("menu");
power->cli = furi_open("cli");
power->cli = furi_record_open("cli");
power->menu = menu_item_alloc_menu("Power", NULL);
menu_item_subitem_add(
@ -163,7 +166,7 @@ void power_task(void* p) {
cli_add_command(power->cli, "power_otg_off", power_cli_otg_off, power);
}
Gui* gui = furi_open("gui");
Gui* gui = furi_record_open("gui");
gui_add_widget(gui, power->usb_widget, GuiLayerStatusBarLeft);
gui_add_widget(gui, power->battery_widget, GuiLayerStatusBarRight);
view_dispatcher_attach_to_gui(power->view_dispatcher, gui, ViewDispatcherTypeFullscreen);
@ -171,14 +174,9 @@ void power_task(void* p) {
with_value_mutex(
power->menu_vm, (Menu * menu) { menu_item_add(menu, power->menu); });
if(!furi_create("power", power)) {
printf("[power_task] unable to create power record\n");
furiac_exit(NULL);
}
api_hal_power_init();
furiac_ready();
furi_record_create("power", power);
while(1) {
with_view_model(

View File

@ -2,8 +2,8 @@
#include <stdint.h>
#include <stdbool.h>
#include <furi.h>
#include <gui/canvas.h>
#include <flipper_v2.h>
#include <gui/view.h>
typedef enum { PowerViewInfo } PowerView;
@ -24,8 +24,4 @@ typedef struct {
uint8_t charge;
} PowerInfoModel;
static uint32_t power_info_back_callback(void* context) {
return VIEW_NONE;
}
void power_info_draw_callback(Canvas* canvas, void* context);

View File

@ -104,23 +104,21 @@ void SdTest::run() {
app_ready();
fs_api = static_cast<FS_Api*>(furi_open("sdcard"));
fs_api = static_cast<FS_Api*>(furi_record_open("sdcard"));
if(fs_api == NULL) {
set_error({"cannot get sdcard api"});
exit();
}
Cli* cli = static_cast<Cli*>(furi_open("cli"));
Cli* cli = static_cast<Cli*>(furi_record_open("cli"));
if(cli != NULL) {
// read_benchmark and write_benchmark signatures are same. so we must use tags
auto cli_read_cb = cbc::obtain_connector<0>(this, &SdTest::cli_read_benchmark);
cli_add_command(cli, "sd_read_test", cli_read_cb, this);
// read_benchmark and write_benchmark signatures are same. so we must use tags
auto cli_read_cb = cbc::obtain_connector<0>(this, &SdTest::cli_read_benchmark);
cli_add_command(cli, "sd_read_test", cli_read_cb, this);
auto cli_write_cb = cbc::obtain_connector<1>(this, &SdTest::cli_write_benchmark);
cli_add_command(cli, "sd_write_test", cli_write_cb, this);
}
auto cli_write_cb = cbc::obtain_connector<1>(this, &SdTest::cli_write_benchmark);
cli_add_command(cli, "sd_write_test", cli_write_cb, this);
detect_sd_card();
get_sd_card_info();
@ -893,6 +891,7 @@ template <class T> void SdTest::set_text(std::initializer_list<T> list) {
printf("------------------------\n");
release_state();
update_gui();
}
// render app

View File

@ -480,22 +480,19 @@ void sd_filesystem(void* p) {
SdApp* sd_app = sd_app_alloc();
FS_Api* fs_api = fs_api_alloc();
Gui* gui = furi_open("gui");
Gui* gui = furi_record_open("gui");
Cli* cli = furi_record_open("cli");
ValueMutex* menu_vm = furi_record_open("menu");
gui_add_widget(gui, sd_app->widget, GuiLayerFullscreen);
gui_add_widget(gui, sd_app->icon.widget, GuiLayerStatusBarLeft);
Cli* cli = furi_open("cli");
if(cli != NULL) {
cli_add_command(cli, "sd_status", cli_sd_status, sd_app);
cli_add_command(cli, "sd_format", cli_sd_format, sd_app);
cli_add_command(cli, "sd_info", cli_sd_info, sd_app);
}
cli_add_command(cli, "sd_status", cli_sd_status, sd_app);
cli_add_command(cli, "sd_format", cli_sd_format, sd_app);
cli_add_command(cli, "sd_info", cli_sd_info, sd_app);
// add api record
if(!furi_create("sdcard", fs_api)) {
furiac_exit(NULL);
}
furi_record_create("sdcard", fs_api);
// init menu
// TODO menu icon
@ -510,15 +507,15 @@ void sd_filesystem(void* p) {
menu_item, menu_item_alloc_function("Eject", NULL, app_sd_eject_callback, sd_app));
// add item to menu
ValueMutex* menu_vm = furi_open("menu");
furi_check(menu_vm);
with_value_mutex(
menu_vm, (Menu * menu) { menu_item_add(menu, menu_item); });
furiac_ready();
printf("[sd_filesystem] start\n");
// add api record
furi_record_create("sdcard", fs_api);
// sd card cycle
bool sd_was_present = true;

View File

@ -1,6 +1,8 @@
#pragma once
#include "flipper.h"
#include "flipper_v2.h"
#include <furi.h>
#include <gui/gui.h>
#include <input/input.h>
#define SD_FS_MAX_FILES _FS_LOCK
#define SD_STATE_LINES_COUNT 6

View File

@ -1,4 +1,4 @@
#include "flipper_v2.h"
#include <furi.h>
typedef enum {
EventTypeTick,
@ -54,7 +54,7 @@ void template_app(void* p) {
widget_input_callback_set(widget, input_callback, event_queue);
// Open GUI and register widget
Gui* gui = (Gui*)furi_open("gui");
Gui* gui = furi_record_open("gui");
if(gui == NULL) {
printf("gui is not available\n");
furiac_exit(NULL);

View File

@ -1,4 +1,4 @@
#include "flipper_v2.h"
#include <furi.h>
#include "minunit.h"
static void furi_concurent_app(void* p) {
@ -10,7 +10,9 @@ static void furi_concurent_app(void* p) {
}
void test_furi_event() {
Event event;
mu_assert(false, "please reimplement or delete test");
/*Event event;
mu_check(init_event(&event));
@ -27,5 +29,5 @@ void test_furi_event() {
// The event should not be signalled once it's processed
mu_check(!wait_event_with_timeout(&event, 100));
mu_check(delete_event(&event));
mu_check(delete_event(&event));*/
}

View File

@ -1,8 +1,6 @@
#include <stdio.h>
#include <string.h>
#include "flipper_v2.h"
#include "log.h"
#include <furi.h>
#include "minunit.h"
const uint32_t context_value = 0xdeadbeef;

View File

@ -1,16 +1,14 @@
#include <stdio.h>
#include <string.h>
#include "flipper.h"
#include "flipper_v2.h"
#include "log.h"
#include <furi.h>
#include "minunit.h"
void test_furi_create_open() {
// 1. Create record
uint8_t test_data = 0;
mu_check(furi_create("test/holding", (void*)&test_data));
furi_record_create("test/holding", (void*)&test_data);
// 2. Open it
void* record = furi_open("test/holding");
void* record = furi_record_open("test/holding");
mu_assert_pointers_eq(record, &test_data);
}

View File

@ -1,4 +1,4 @@
#include "flipper_v2.h"
#include <furi.h>
#include "minunit.h"
#include <stdint.h>

View File

@ -1,7 +1,6 @@
#include <stdio.h>
#include <string.h>
#include "flipper_v2.h"
#include "log.h"
#include <furi.h>
#include "minunit.h"
@ -88,6 +87,8 @@ void furi_concurent_app(void* p) {
}
void test_furi_concurrent_access() {
mu_assert(false, "please reimplement or delete test");
/*
// 1. Create holding record
ConcurrentValue value = {.a = 0, .b = 0};
ValueMutex mutex;
@ -123,4 +124,5 @@ void test_furi_concurrent_access() {
mu_assert_int_eq(value.a, value.b);
mu_check(delete_mutex(&mutex));
*/
}

View File

@ -1,7 +1,6 @@
#include <stdio.h>
#include <string.h>
#include "flipper.h"
#include "log.h"
#include <furi.h>
/*
Test: creating and killing task
@ -24,6 +23,8 @@ void create_kill_app(void* p) {
}
bool test_furi_ac_create_kill() {
mu_assert(false, "please reimplement or delete test");
/*
uint8_t counter = 0;
uint8_t value_a = counter;
@ -56,6 +57,7 @@ bool test_furi_ac_create_kill() {
}
return true;
*/
}
/*

View File

@ -1,6 +1,5 @@
#include <stdio.h>
#include "flipper.h"
#include "log.h"
#include <furi.h>
#include "minunit_vars.h"
#include "minunit.h"

View File

@ -1,7 +1,5 @@
#include <stdio.h>
#include "flipper.h"
#include "flipper_v2.h"
#include "log.h"
#include <furi.h>
// #include "flipper-core.h" TODO: Rust build disabled

View File

@ -1,47 +0,0 @@
#pragma once
#include "flipper.h"
// == Flipper Application control (flapp) ==
typedef FlappHandler uint32_t; // TODO
/*
simply starts application. It call `app` entrypoint with `param` passed as argument
Useful for daemon applications and pop-up.
*/
FlappHandler* flapp_start(void(app*)(void*), char* name, void* param);
/*
swtich to other application.
System **stop current app**, call `app` entrypoint with `param` passed
as argument and save current application entrypoint to `prev` field in
current application registry. Useful for UI or "active" application.
*/
FlappHandler* flapp_switch(void(app*)(void*), char* name, void* param);
/*
Exit application
stop current application (stop thread and clear application's stack),
start application from `prev` entry in current application registry,
cleanup current application registry.
*/
void flapp_exit(void* param);
/*
stop specified `app` without returning to `prev` application.
*/
bool flapp_kill(FlappHandler* app);
/*
If case one app depend on other, notify that app is ready.
*/
void flapp_ready();
/*
Register on-exit callback.
It called before app will be killed.
Not recommended to use in user scenario, only for system purpose
(unregister callbacks, release mutexes, etc.)
*/
bool flapp_on_exit(void(cb*)(void*), void* ctx);

View File

@ -1,14 +0,0 @@
#include "furi.h"
#include "furi-deprecated.h"
bool furi_create(const char* name, void* ptr) {
return furi_create_deprecated(name, ptr, sizeof(size_t));
}
void* furi_open(const char* name) {
FuriRecordSubscriber* record = furi_open_deprecated(name, false, false, NULL, NULL, NULL);
void* res = furi_take(record);
furi_give(record);
return res;
}

View File

@ -1,26 +0,0 @@
#pragma once
#include "flipper.h"
/*
== Flipper universal registry implementation (FURI) ==
## Requirements
* start daemon app
* kill app
* start child thread (kill when parent app was killed)
* switch between UI apps
*/
/*
Create record.
creates new record in registry and store pointer into it
*/
bool furi_create(const char* name, void* ptr);
/*
Open record.
get stored pointer by its name
*/
void* furi_open(const char* name);

View File

@ -1,4 +1,6 @@
#include "api-gpio.h"
#include <cmsis_os2.h>
#include <furi/record.h>
osMutexId_t gpioInitMutex;
@ -37,7 +39,7 @@ void gpio_disable(GpioDisableRecord* gpio_record) {
// get GPIO record
ValueMutex* gpio_open_mutex(const char* name) {
ValueMutex* gpio_mutex = (ValueMutex*)furi_open(name);
ValueMutex* gpio_mutex = (ValueMutex*)furi_record_open(name);
// TODO disable gpio on app exit
//if(gpio_mutex != NULL) flapp_on_exit(gpio_disable, gpio_mutex);
@ -48,6 +50,6 @@ ValueMutex* gpio_open_mutex(const char* name) {
// get GPIO record and acquire mutex
GpioPin* gpio_open(const char* name) {
ValueMutex* gpio_mutex = gpio_open_mutex(name);
GpioPin* gpio_pin = acquire_mutex(gpio_mutex, FLIPPER_HELPER_TIMEOUT);
GpioPin* gpio_pin = acquire_mutex(gpio_mutex, osWaitForever);
return gpio_pin;
}

View File

@ -1,7 +1,11 @@
#pragma once
#include "flipper.h"
#include "flipper_v2.h"
#include "api-hal-gpio.h"
#include <furi/valuemutex.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
ValueMutex* gpio_mutex;
@ -38,4 +42,8 @@ void gpio_disable(GpioDisableRecord* gpio_record);
ValueMutex* gpio_open_mutex(const char* name);
// get GPIO record and acquire mutex
GpioPin* gpio_open(const char* name);
GpioPin* gpio_open(const char* name);
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,8 @@
#include "api-interrupt-mgr.h"
#include <m-list.h>
#include <cmsis_os2.h>
LIST_DEF(list_interrupt, InterruptCallbackItem, M_POD_OPLIST);
list_interrupt_t interrupts;
osMutexId_t interrupt_list_mutex;

View File

@ -1,5 +1,10 @@
#pragma once
#include "flipper_v2.h"
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*InterruptCallback)(void*, void*);
@ -18,4 +23,8 @@ typedef struct {
bool api_interrupt_init();
void api_interrupt_add(InterruptCallback callback, InterruptType type, void* context);
void api_interrupt_remove(InterruptCallback callback);
void api_interrupt_call(InterruptType type, void* hw);
void api_interrupt_call(InterruptType type, void* hw);
#ifdef __cplusplus
}
#endif

View File

@ -1,4 +1,8 @@
#include "flipper_v2.h"
#include <furi.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
struct used for handling SPI info.
@ -133,4 +137,8 @@ void cc1101_example() {
}
}
```
*/
*/
#ifdef __cplusplus
}
#endif

View File

@ -1,48 +0,0 @@
#include <stdio.h>
#include "flipper.h"
#include "flipper_v2.h"
extern "C" {
#include "log.h"
#include "applications.h"
#include "tty_uart.h"
}
// for testing purpose
uint32_t exitcode = 0;
extern "C" void set_exitcode(uint32_t _exitcode) {
exitcode = _exitcode;
}
extern "C" int app() {
init_flipper_api();
register_tty_uart();
FuriRecordSubscriber* log = get_default_log();
fuprintf(log, "\n=== Welcome to Flipper Zero! ===\n\n");
// FURI startup
const size_t flipper_app_count = sizeof(FLIPPER_STARTUP) / sizeof(FLIPPER_STARTUP[0]);
FuriApp* handlers[flipper_app_count];
for(size_t i = 0; i < flipper_app_count; i++) {
// TODO create a dependency tree and run tasks in the desired order
furiac_wait_libs(&FLIPPER_STARTUP[i].libs);
handlers[i] = furiac_start(FLIPPER_STARTUP[i].app, FLIPPER_STARTUP[i].name, NULL);
}
bool is_alive = false;
do {
is_alive = false;
for(size_t i = 0; i < flipper_app_count; i++) {
if(handlers[i]->handler != NULL) {
is_alive = true;
}
}
delay(500);
} while(is_alive);
fuprintf(log, "\n=== Bye from Flipper Zero! ===\n\n");
return (int)exitcode;
}

View File

@ -1,8 +1,8 @@
CORE_DIR = $(PROJECT_ROOT)/core
CFLAGS += -I$(CORE_DIR)
CFLAGS += -I$(CORE_DIR) -D_GNU_SOURCE
ASM_SOURCES += $(wildcard $(CORE_DIR)/*.s)
C_SOURCES += $(wildcard $(CORE_DIR)/*.c)
C_SOURCES += $(wildcard $(CORE_DIR)/api-basic/*.c)
C_SOURCES += $(wildcard $(CORE_DIR)/furi/*.c)
C_SOURCES += $(wildcard $(CORE_DIR)/api-hal/*.c)
CPP_SOURCES += $(wildcard $(CORE_DIR)/*.cpp)

View File

@ -1,24 +0,0 @@
#pragma once
#include "api-hal.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
#include "cmsis_os.h"
#include "furi-deprecated.h"
#include "log.h"
#include "input/input.h"
#include <stdio.h>
void set_exitcode(uint32_t _exitcode);
#define FURI_LIB (const char*[])
#ifdef __cplusplus
}
#endif

View File

@ -1,16 +0,0 @@
#pragma once
#include "stdint.h"
// Arduino defines
#define pinMode gpio_init
#define digitalWrite gpio_write
#define digitalRead gpio_read
#define delayMicroseconds delay_us
#define delay osDelay
#define OUTPUT GpioModeOutputPushPull
#define INPUT GpioModeInput
#define LOW false
#define HIGH true
typedef uint8_t byte;

View File

@ -1,19 +0,0 @@
#include "flipper_v2.h"
bool init_flipper_api(void) {
bool no_errors = true;
if(!furi_init()) {
no_errors = false;
}
if(!gpio_api_init()) {
no_errors = false;
}
if(!api_interrupt_init()) {
no_errors = false;
}
return no_errors;
}

View File

@ -1,33 +0,0 @@
#pragma once
#include "flipper.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "api-basic/furi.h"
//#include "api-basic/flapp.h"
#include "cmsis_os2.h"
#include "api-basic/valuemutex.h"
#include "api-basic/pubsub.h"
#include "api-basic/value-expanders.h"
#include "api-basic/event.h"
#include "api-basic/memmgr.h"
#include "api-basic/check.h"
#include "api-hal/api-gpio.h"
#include "api-hal/api-interrupt-mgr.h"
#include "api-hal-resources.h"
#include "gui/gui.h"
// tmeout for helper functions
#define FLIPPER_HELPER_TIMEOUT 10
bool init_flipper_api(void);
#ifdef __cplusplus
}
#endif

View File

@ -1,295 +0,0 @@
#include "furi-deprecated.h"
#include <string.h>
// TODO: this file contains printf, that not implemented on uC target
#ifdef FURI_DEBUG
#include <stdio.h>
#endif
#define MAX_RECORD_COUNT 32
static FuriRecord records[MAX_RECORD_COUNT];
static size_t current_buffer_idx = 0;
osMutexId_t furi_core_mutex;
bool furi_init(void) {
furi_core_mutex = osMutexNew(NULL);
if(furi_core_mutex == NULL) return false;
return true;
}
// find record pointer by name
static FuriRecord* find_record(const char* name) {
if(name == NULL) return NULL;
FuriRecord* res = NULL;
for(size_t i = 0; i < MAX_RECORD_COUNT; i++) {
if(records[i].name != NULL && strcmp(name, records[i].name) == 0) {
res = &records[i];
}
}
return res;
}
// TODO: change open-create to only open
bool furi_create_deprecated(const char* name, void* value, size_t size) {
#ifdef FURI_DEBUG
printf("[FURI] creating %s record\n", name);
#endif
// acquire mutex to prevent simultaneous write to record with same index
if(osMutexAcquire(furi_core_mutex, osWaitForever) != osOK) {
return false;
}
FuriRecord* record = find_record(name);
if(record != NULL) {
#ifdef FURI_DEBUG
printf("[FURI] record already exist\n");
#endif
record->value = value;
record->size = size;
return true;
}
// record not exist, create new
if(current_buffer_idx >= MAX_RECORD_COUNT) {
// max record count exceed
#ifdef FURI_DEBUG
printf("[FURI] create: max record count exceed\n");
#endif
return NULL;
}
records[current_buffer_idx].mute_counter = 0;
records[current_buffer_idx].mutex =
xSemaphoreCreateMutexStatic(&records[current_buffer_idx].mutex_buffer);
records[current_buffer_idx].value = value;
records[current_buffer_idx].size = size;
records[current_buffer_idx].name = name;
for(size_t i = 0; i < MAX_RECORD_SUBSCRIBERS; i++) {
records[current_buffer_idx].subscribers[i].allocated = false;
records[current_buffer_idx].subscribers[i].ctx = NULL;
}
current_buffer_idx++;
osMutexRelease(furi_core_mutex);
return true;
}
FuriRecordSubscriber* furi_open_deprecated(
const char* name,
bool solo,
bool no_mute,
FlipperRecordCallback value_callback,
FlipperRecordStateCallback state_callback,
void* ctx) {
#ifdef FURI_DEBUG
printf("[FURI] opening %s record\n", name);
#endif
// get furi record by name
FuriRecord* record = find_record(name);
if(record == NULL) {
// cannot find record
#ifdef FURI_DEBUG
printf("[FURI] cannot find record %s\n", name);
#endif
// create record if not exist
if(!furi_create_deprecated(name, NULL, 0)) {
return NULL;
}
record = find_record(name);
if(record == NULL) {
return NULL;
}
}
// allocate subscriber
FuriRecordSubscriber* subscriber = NULL;
for(size_t i = 0; i < MAX_RECORD_SUBSCRIBERS; i++) {
if(!record->subscribers[i].allocated) {
subscriber = &record->subscribers[i];
break;
}
}
if(subscriber == NULL) {
// cannot add subscriber (full)
#ifdef FURI_DEBUG
printf("[FURI] open: cannot add subscriber (full)\n");
#endif
return NULL;
}
// increase mute_counter
if(solo) {
record->mute_counter++;
}
// set all parameters
subscriber->allocated = true;
subscriber->mute_counter = record->mute_counter;
subscriber->no_mute = no_mute;
subscriber->cb = value_callback;
subscriber->state_cb = state_callback;
subscriber->record = record;
subscriber->ctx = ctx;
// register record in application
FuriApp* current_task = find_task(xTaskGetCurrentTaskHandle());
if(current_task != NULL) {
current_task->records[current_task->records_count] = record;
current_task->records_count++;
} else {
#ifdef FURI_DEBUG
printf("[FURI] open: no current task\n");
#endif
}
return subscriber;
}
void furi_close(FuriRecordSubscriber* handler) {
#ifdef FURI_DEBUG
printf("[FURI] closing %s record\n", handler->record->name);
#endif
// deallocate subscriber
handler->allocated = false;
// set mute counter to next max value
uint8_t max_mute_counter = 0;
for(size_t i = 0; i < MAX_RECORD_SUBSCRIBERS; i++) {
if(handler->record->subscribers[i].allocated) {
if(handler->record->subscribers[i].mute_counter > max_mute_counter) {
max_mute_counter = handler->record->subscribers[i].mute_counter;
}
}
}
handler->record->mute_counter = max_mute_counter;
}
static void furi_notify(FuriRecordSubscriber* handler, const void* value, size_t size) {
for(size_t i = 0; i < MAX_RECORD_SUBSCRIBERS; i++) {
if(handler->record->subscribers[i].allocated) {
if(handler->record->subscribers[i].cb != NULL) {
handler->record->subscribers[i].cb(
value, size, handler->record->subscribers[i].ctx);
}
}
}
}
void* furi_take(FuriRecordSubscriber* handler) {
if(handler == NULL || handler->record == NULL) return NULL;
if(xSemaphoreTake(handler->record->mutex, portMAX_DELAY) == pdTRUE) {
return handler->record->value;
} else {
return NULL;
}
}
void furi_give(FuriRecordSubscriber* handler) {
if(handler == NULL || handler->record == NULL) return;
xSemaphoreGive(handler->record->mutex);
}
void furi_commit(FuriRecordSubscriber* handler) {
if(handler == NULL || handler->record == NULL) return;
furi_notify(handler, handler->record->value, handler->record->size);
furi_give(handler);
}
bool furi_read(FuriRecordSubscriber* handler, void* value, size_t size) {
#ifdef FURI_DEBUG
printf("[FURI] read from %s\n", handler->record->name);
#endif
if(handler == NULL || handler->record == NULL || value == NULL) return false;
if(size > handler->record->size) return false;
// return false if read from pipe
if(handler->record->value == NULL) return false;
furi_take(handler);
memcpy(value, handler->record->value, size);
furi_notify(handler, value, size);
furi_give(handler);
return true;
}
bool furi_write(FuriRecordSubscriber* handler, const void* value, size_t size) {
#ifdef FURI_DEBUG
printf("[FURI] write to %s\n", handler->record->name);
#endif
if(handler == NULL || handler->record == NULL || value == NULL) {
#ifdef FURI_DEBUG
printf(
"[FURI] write: null param %x %x\n",
(uint32_t)(size_t)handler,
(uint32_t)(size_t)value);
#endif
return false;
}
// check if closed
if(!handler->allocated) {
#ifdef FURI_DEBUG
printf("[FURI] write: handler closed\n");
#endif
return false;
}
if(handler->record->value != NULL && size > handler->record->size) {
#ifdef FURI_DEBUG
printf("[FURI] write: wrong size %d\n", (uint32_t)size);
#endif
return false;
}
// check mute
if(handler->record->mute_counter != handler->mute_counter && !handler->no_mute) {
#ifdef FURI_DEBUG
printf("[FURI] write: muted\n");
#endif
return false;
}
furi_take(handler);
if(handler->record->value != NULL) {
// real write to value
memcpy(handler->record->value, value, size);
// notify subscribers
furi_notify(handler, handler->record->value, handler->record->size);
} else {
furi_notify(handler, value, size);
}
furi_give(handler);
return true;
}

View File

@ -1,207 +0,0 @@
#pragma once
#include "cmsis_os.h"
#ifdef HAVE_FREERTOS
#include <semphr.h>
#endif
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include "assets_icons.h"
#define MAX_TASK_RECORDS 8
#define MAX_RECORD_SUBSCRIBERS 8
inline static void* furi_alloc(size_t size) {
void* p = malloc(size);
assert(p);
return memset(p, 0, size);
}
/// application is just a function
typedef void (*FlipperApplication)(void*);
/// pointer to value callback function
typedef void (*FlipperRecordCallback)(const void*, size_t, void*);
typedef enum {
FlipperRecordStateMute, ///< record open and mute this handler
FlipperRecordStateUnmute, ///< record unmuted
FlipperRecordStateDeleted ///< record owner halt
} FlipperRecordState;
/// pointer to state callback function
typedef void (*FlipperRecordStateCallback)(FlipperRecordState, void*);
struct _FuriRecord;
typedef struct {
bool allocated;
FlipperRecordCallback cb; ///< value cb
FlipperRecordStateCallback state_cb; ///< state cb
uint8_t mute_counter; ///< see "wiki/FURI#mute-algorithm"
bool no_mute;
struct _FuriRecord* record; ///< parent record
void* ctx;
} FuriRecordSubscriber;
/// FURI record handler
struct _FuriRecord {
const char* name;
void* value;
size_t size;
StaticSemaphore_t mutex_buffer;
SemaphoreHandle_t mutex;
uint8_t mute_counter;
FuriRecordSubscriber subscribers[MAX_RECORD_SUBSCRIBERS];
};
typedef struct _FuriRecord FuriRecord;
/// store info about active task
typedef struct {
const char* name;
FlipperApplication application;
const char* prev_name;
FlipperApplication prev;
TaskHandle_t handler;
uint8_t records_count; ///< count of records which task open
FuriRecord* records[MAX_TASK_RECORDS]; ///< list of records which task open
bool ready;
} FuriApp;
// application dependency info
typedef struct {
uint8_t count;
const char** name;
} FlipperAppLibrary;
// application startup info
typedef struct {
FlipperApplication app;
const char* name;
FlipperAppLibrary libs;
IconName icon;
} FlipperStartupApp;
// Init core
bool furi_init(void);
/*!
Simply starts application.
It call app entrypoint with param passed as argument.
Useful for daemon applications and pop-up.
*/
FuriApp* furiac_start(FlipperApplication app, const char* name, void* param);
/*!
Swtich to other application.
FURI stop current app, call app entrypoint with param passed as
argument and save current application entrypoint to prev field
in current application registry.
Useful for UI or "active" application.
*/
void furiac_switch(FlipperApplication app, char* name, void* param);
/*!
Stop current application
(stop thread and clear application's stack), start application
from prev entry in current application registry, cleanup current
application registry.
*/
void furiac_exit(void* param);
/*!
Mark application as prepared and ready to perform actions
*/
void furiac_ready();
/*
Wait for the libraries we depend on
*/
void furiac_wait_libs(const FlipperAppLibrary* libs);
/*!
Stop specified app without returning to prev application.
*/
bool furiac_kill(FuriApp* app);
// find task pointer by handle
FuriApp* find_task(TaskHandle_t handler);
/*!
Creates named FURI record.
\param[in] name you can open this record anywhere
\param[in] value pointer to data.
\param[in] size size of data.
If NULL, create FURI Pipe (only callbacks management, no data/mutex)
Returns false if registry have not enough memory for creating.
*/
bool furi_create_deprecated(const char* name, void* value, size_t size);
/*!
Opens existing FURI record by name.
Returns NULL if record does not exist.
\param[in] solo if true another applications handlers set into "muted" state.
When appication has exited or record has closed, all handlers is unmuted.
It may be useful for concurrently acces to resources like framebuffer or beeper.
\param[in] no_mute if true, another applications cannot mute this handler.
*/
FuriRecordSubscriber* furi_open_deprecated(
const char* name,
bool solo,
bool no_mute,
FlipperRecordCallback value_callback,
FlipperRecordStateCallback state_callback,
void* ctx);
/*!
*/
void furi_close(FuriRecordSubscriber* handler);
/*!
read message from record.
Returns true if success, false otherwise (closed/non-existent record)
Also return false if you try to read from FURI pipe
TODO: enum return value with execution status
*/
bool furi_read(FuriRecordSubscriber* record, void* data, size_t size);
/*!
write message to record.
Returns true if success, false otherwise (closed/non-existent record or muted).
TODO: enum return value with execution status
*/
bool furi_write(FuriRecordSubscriber* record, const void* data, size_t size);
/*!
lock value mutex.
It can be useful if records contain pointer to buffer which you want to change.
You must call furi_give after operation on data and
you shouldn't block executing between take and give calls
Returns pointer to data, NULL if closed/non-existent record or muted
TODO: enum return value with execution status
*/
void* furi_take(FuriRecordSubscriber* record);
/*!
unlock value mutex.
*/
void furi_give(FuriRecordSubscriber* record);
/*!
unlock value mutex and notify subscribers that data is chaned.
*/
void furi_commit(FuriRecordSubscriber* handler);

36
core/furi.c Normal file
View File

@ -0,0 +1,36 @@
#include "furi.h"
#include <applications.h>
// for testing purpose
uint32_t exitcode = 0;
void set_exitcode(uint32_t _exitcode) {
exitcode = _exitcode;
}
void furi_init() {
gpio_api_init();
api_interrupt_init();
furi_record_init();
furi_stdglue_init();
}
int systemd() {
furi_init();
// FURI startup
for(size_t i = 0; i < FLIPPER_SERVICES_size(); i++) {
osThreadAttr_t* attr = furi_alloc(sizeof(osThreadAttr_t));
attr->name = FLIPPER_SERVICES[i].name;
attr->stack_size = 1024;
osThreadNew(FLIPPER_SERVICES[i].app, NULL, attr);
}
while(1) {
osThreadSuspend(osThreadGetId());
}
printf("\n=== Bye from Flipper Zero! ===\n\n");
return (int)exitcode;
}

28
core/furi.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
#include <cmsis_os2.h>
#include <furi/check.h>
#include <furi/event.h>
#include <furi/memmgr.h>
#include <furi/pubsub.h>
#include <furi/record.h>
#include <furi/stdglue.h>
#include <furi/value-expanders.h>
#include <furi/valuemutex.h>
#include <api-hal/api-gpio.h>
#include <api-hal/api-interrupt-mgr.h>
#include <api-hal.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
#define furiac_exit(ptr) osThreadExit()
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,6 @@
#include "check.h"
#include "api-hal-task.h"
#include <stdio.h>
void __furi_abort(void);
@ -22,20 +23,21 @@ void __furi_check_debug(const char* file, int line, const char* function, const
if(task_is_isr_context()) {
printf(" in [ISR] context");
} else {
FuriApp* app = find_task(xTaskGetCurrentTaskHandle());
// FuriApp* app = find_task(xTaskGetCurrentTaskHandle());
if(app == NULL) {
printf(", in [main] context");
} else {
printf(", in [%s] app context", app->name);
}
// if(app == NULL) {
// printf(", in [main] context");
// } else {
// printf(", in [%s] app context", app->name);
// }
}
__furi_abort();
}
void __furi_abort(void) {
taskDISABLE_INTERRUPTS();
__disable_irq();
asm("bkpt 1");
while(1) {
}
}

View File

@ -1,6 +1,8 @@
#pragma once
#include "flipper.h"
#ifdef __cplusplus
extern "C" {
#endif
// Find how to how get function's pretty name
#ifndef __FURI_CHECK_FUNC
@ -38,4 +40,8 @@
// !NDEBUG
void __furi_check(void);
void __furi_check_debug(const char* file, int line, const char* function, const char* condition);
void __furi_check_debug(const char* file, int line, const char* function, const char* condition);
#ifdef __cplusplus
}
#endif

Some files were not shown because too many files have changed in this diff Show More