[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:
parent
6c4983c6b6
commit
8f9b2513ff
4
.github/CODEOWNERS
vendored
4
.github/CODEOWNERS
vendored
@ -19,10 +19,6 @@ firmware/targets/f4/api-hal/api-hal-boot.c @skotopes
|
|||||||
|
|
||||||
debug/** @skotopes
|
debug/** @skotopes
|
||||||
|
|
||||||
# local target
|
|
||||||
|
|
||||||
firmware/targets/local/** @glitchcore
|
|
||||||
|
|
||||||
# BLE
|
# BLE
|
||||||
|
|
||||||
firmware/targets/f4/ble-glue/** @skotopes
|
firmware/targets/f4/ble-glue/** @skotopes
|
||||||
|
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
@ -32,16 +32,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
run: /syntax_check.sh
|
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
|
- name: Build F4 bootloader in docker
|
||||||
uses: ./.github/actions/docker
|
uses: ./.github/actions/docker
|
||||||
with:
|
with:
|
||||||
|
@ -25,14 +25,7 @@ Flipper Zero's firmware consists of two components: Bootloader and main firmware
|
|||||||
|
|
||||||
## Build from source
|
## Build from source
|
||||||
|
|
||||||
You can run firmware locally (with HAL stub):
|
`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)
|
||||||
|
|
||||||
* `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)
|
|
||||||
|
|
||||||
# Links
|
# Links
|
||||||
* Task tracker: [Jira](https://flipperzero.atlassian.net/)
|
* Task tracker: [Jira](https://flipperzero.atlassian.net/)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "flipper_v2.h"
|
#include <furi.h>
|
||||||
#include <cli/cli.h>
|
#include <cli/cli.h>
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include "menu/menu.h"
|
#include "menu/menu.h"
|
||||||
@ -8,14 +8,15 @@
|
|||||||
#include <api-hal.h>
|
#include <api-hal.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FuriApp* handler;
|
osThreadAttr_t app_thread_attr;
|
||||||
|
osThreadId_t app_thread_id;
|
||||||
Widget* widget;
|
Widget* widget;
|
||||||
const FlipperStartupApp* current_app;
|
const FuriApplication* current_app;
|
||||||
} AppLoaderState;
|
} AppLoaderState;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
AppLoaderState* state;
|
AppLoaderState* state;
|
||||||
const FlipperStartupApp* app;
|
const FuriApplication* app;
|
||||||
} AppLoaderContext;
|
} AppLoaderContext;
|
||||||
|
|
||||||
// TODO add mutex for contex
|
// TODO add mutex for contex
|
||||||
@ -36,7 +37,7 @@ static void input_callback(InputEvent* input_event, void* _ctx) {
|
|||||||
AppLoaderState* ctx = (AppLoaderState*)_ctx;
|
AppLoaderState* ctx = (AppLoaderState*)_ctx;
|
||||||
|
|
||||||
if(input_event->state && input_event->input == InputBack) {
|
if(input_event->state && input_event->input == InputBack) {
|
||||||
furiac_kill(ctx->handler);
|
osThreadTerminate(ctx->app_thread_id);
|
||||||
widget_enabled_set(ctx->widget, false);
|
widget_enabled_set(ctx->widget, false);
|
||||||
api_hal_timebase_insomnia_exit();
|
api_hal_timebase_insomnia_exit();
|
||||||
}
|
}
|
||||||
@ -54,7 +55,16 @@ static void handle_menu(void* _ctx) {
|
|||||||
api_hal_timebase_insomnia_enter();
|
api_hal_timebase_insomnia_enter();
|
||||||
|
|
||||||
ctx->state->current_app = ctx->app;
|
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) {
|
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");
|
cli_print("Starting furi application\r\n");
|
||||||
|
|
||||||
ctx->state->current_app = ctx->app;
|
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");
|
cli_print("Press any key to kill application");
|
||||||
|
|
||||||
char c;
|
char c;
|
||||||
cli_read(&c, 1);
|
cli_read(&c, 1);
|
||||||
furiac_kill(ctx->state->handler);
|
osThreadTerminate(ctx->state->app_thread_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void app_loader(void* p) {
|
void app_loader(void* p) {
|
||||||
@ -79,37 +98,23 @@ void app_loader(void* p) {
|
|||||||
furi_check(self_id);
|
furi_check(self_id);
|
||||||
|
|
||||||
AppLoaderState state;
|
AppLoaderState state;
|
||||||
state.handler = NULL;
|
state.app_thread_id = NULL;
|
||||||
|
|
||||||
state.widget = widget_alloc();
|
state.widget = widget_alloc();
|
||||||
widget_enabled_set(state.widget, false);
|
widget_enabled_set(state.widget, false);
|
||||||
widget_draw_callback_set(state.widget, render_callback, &state);
|
widget_draw_callback_set(state.widget, render_callback, &state);
|
||||||
widget_input_callback_set(state.widget, input_callback, &state);
|
widget_input_callback_set(state.widget, input_callback, &state);
|
||||||
|
|
||||||
ValueMutex* menu_mutex = furi_open("menu");
|
ValueMutex* menu_mutex = furi_record_open("menu");
|
||||||
if(menu_mutex == NULL) {
|
Cli* cli = furi_record_open("cli");
|
||||||
printf("menu is not available\n");
|
Gui* gui = furi_record_open("gui");
|
||||||
furiac_exit(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
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
|
// Main menu
|
||||||
with_value_mutex(
|
with_value_mutex(
|
||||||
menu_mutex, (Menu * menu) {
|
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));
|
AppLoaderContext* ctx = furi_alloc(sizeof(AppLoaderContext));
|
||||||
ctx->state = &state;
|
ctx->state = &state;
|
||||||
ctx->app = &FLIPPER_APPS[i];
|
ctx->app = &FLIPPER_APPS[i];
|
||||||
@ -123,13 +128,11 @@ void app_loader(void* p) {
|
|||||||
ctx));
|
ctx));
|
||||||
|
|
||||||
// Add cli command
|
// Add cli command
|
||||||
if(cli) {
|
string_t cli_name;
|
||||||
string_t cli_name;
|
string_init_set_str(cli_name, "app_");
|
||||||
string_init_set_str(cli_name, "app_");
|
string_cat_str(cli_name, FLIPPER_APPS[i].name);
|
||||||
string_cat_str(cli_name, FLIPPER_APPS[i].name);
|
cli_add_command(cli, string_get_cstr(cli_name), handle_cli, ctx);
|
||||||
cli_add_command(cli, string_get_cstr(cli_name), handle_cli, ctx);
|
string_clear(cli_name);
|
||||||
string_clear(cli_name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -157,7 +160,7 @@ void app_loader(void* p) {
|
|||||||
MenuItem* menu_plugins =
|
MenuItem* menu_plugins =
|
||||||
menu_item_alloc_menu("Plugins", assets_icons_get(A_Plugins_14));
|
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));
|
AppLoaderContext* ctx = furi_alloc(sizeof(AppLoaderContext));
|
||||||
ctx->state = &state;
|
ctx->state = &state;
|
||||||
ctx->app = &FLIPPER_PLUGINS[i];
|
ctx->app = &FLIPPER_PLUGINS[i];
|
||||||
@ -171,13 +174,11 @@ void app_loader(void* p) {
|
|||||||
ctx));
|
ctx));
|
||||||
|
|
||||||
// Add cli command
|
// Add cli command
|
||||||
if(cli) {
|
string_t cli_name;
|
||||||
string_t cli_name;
|
string_init_set_str(cli_name, "app_");
|
||||||
string_init_set_str(cli_name, "app_");
|
string_cat_str(cli_name, FLIPPER_PLUGINS[i].name);
|
||||||
string_cat_str(cli_name, FLIPPER_PLUGINS[i].name);
|
cli_add_command(cli, string_get_cstr(cli_name), handle_cli, ctx);
|
||||||
cli_add_command(cli, string_get_cstr(cli_name), handle_cli, ctx);
|
string_clear(cli_name);
|
||||||
string_clear(cli_name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
menu_item_add(menu, menu_plugins);
|
menu_item_add(menu, menu_plugins);
|
||||||
@ -186,4 +187,4 @@ void app_loader(void* p) {
|
|||||||
printf("[app loader] start\n");
|
printf("[app loader] start\n");
|
||||||
|
|
||||||
osThreadSuspend(self_id);
|
osThreadSuspend(self_id);
|
||||||
}
|
}
|
||||||
|
220
applications/applications.c
Normal file
220
applications/applications.c
Normal 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);
|
||||||
|
}
|
@ -1,296 +1,21 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "flipper.h"
|
#include <furi.h>
|
||||||
|
#include <assets_icons.h>
|
||||||
|
|
||||||
#ifdef APP_TEST
|
typedef void (*FlipperApplication)(void*);
|
||||||
void flipper_test_app(void* p);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void application_blink(void* p);
|
typedef struct {
|
||||||
void application_uart_write(void* p);
|
const FlipperApplication app;
|
||||||
void application_ipc_display(void* p);
|
const char* name;
|
||||||
void application_ipc_widget(void* p);
|
const IconName icon;
|
||||||
void application_input_dump(void* p);
|
} 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);
|
extern const FuriApplication FLIPPER_PLUGINS[];
|
||||||
void menu_task(void* p);
|
size_t FLIPPER_PLUGINS_size();
|
||||||
|
|
||||||
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
|
|
||||||
};
|
|
||||||
|
@ -2,6 +2,7 @@ APP_DIR = $(PROJECT_ROOT)/applications
|
|||||||
LIB_DIR = $(PROJECT_ROOT)/lib
|
LIB_DIR = $(PROJECT_ROOT)/lib
|
||||||
|
|
||||||
CFLAGS += -I$(APP_DIR)
|
CFLAGS += -I$(APP_DIR)
|
||||||
|
C_SOURCES += $(APP_DIR)/applications.c
|
||||||
|
|
||||||
# Use APP_* for autostart app
|
# Use APP_* for autostart app
|
||||||
# Use BUILD_* for add app to build
|
# Use BUILD_* for add app to build
|
||||||
|
@ -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) {
|
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) {
|
void backlight_control(void* p) {
|
||||||
// TODO open record
|
// TODO open record
|
||||||
const GpioPin* backlight_record = &backlight_gpio;
|
const GpioPin* backlight_record = &backlight_gpio;
|
||||||
@ -14,20 +15,14 @@ void backlight_control(void* p) {
|
|||||||
gpio_init(backlight_record, GpioModeOutputPushPull);
|
gpio_init(backlight_record, GpioModeOutputPushPull);
|
||||||
gpio_write(backlight_record, true);
|
gpio_write(backlight_record, true);
|
||||||
|
|
||||||
StaticSemaphore_t event_descriptor;
|
|
||||||
SemaphoreHandle_t update = xSemaphoreCreateCountingStatic(255, 0, &event_descriptor);
|
|
||||||
|
|
||||||
// open record
|
// open record
|
||||||
PubSub* event_record = furi_open("input_events");
|
PubSub* event_record = furi_record_open("input_events");
|
||||||
furi_check(event_record);
|
subscribe_pubsub(event_record, event_cb, (void*)osThreadGetId());
|
||||||
subscribe_pubsub(event_record, event_cb, (void*)update);
|
|
||||||
|
|
||||||
// we ready to work
|
|
||||||
furiac_ready();
|
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
// wait for event
|
// 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);
|
gpio_write(backlight_record, true);
|
||||||
} else {
|
} else {
|
||||||
gpio_write(backlight_record, false);
|
gpio_write(backlight_record, false);
|
||||||
|
@ -2,16 +2,23 @@
|
|||||||
|
|
||||||
Bt* bt_alloc() {
|
Bt* bt_alloc() {
|
||||||
Bt* bt = furi_alloc(sizeof(Bt));
|
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_icon = assets_icons_get(I_Bluetooth_5x8);
|
||||||
bt->statusbar_widget = widget_alloc();
|
bt->statusbar_widget = widget_alloc();
|
||||||
widget_set_width(bt->statusbar_widget, icon_get_width(bt->statusbar_icon));
|
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_draw_callback_set(bt->statusbar_widget, bt_draw_statusbar_callback, bt);
|
||||||
widget_enabled_set(bt->statusbar_widget, false);
|
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_icon = assets_icons_get(A_Bluetooth_14);
|
||||||
bt->menu_item = menu_item_alloc_menu("Bluetooth", bt->menu_icon);
|
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;
|
return bt;
|
||||||
}
|
}
|
||||||
@ -33,23 +40,7 @@ void bt_cli_info(string_t args, void* context) {
|
|||||||
void bt_task() {
|
void bt_task() {
|
||||||
Bt* bt = bt_alloc();
|
Bt* bt = bt_alloc();
|
||||||
|
|
||||||
if(bt->cli) {
|
furi_record_create("bt", bt);
|
||||||
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();
|
|
||||||
|
|
||||||
api_hal_bt_init();
|
api_hal_bt_init();
|
||||||
|
|
||||||
|
@ -2,10 +2,9 @@
|
|||||||
|
|
||||||
#include "bt.h"
|
#include "bt.h"
|
||||||
|
|
||||||
#include <cli/cli.h>
|
#include <furi.h>
|
||||||
|
|
||||||
#include <flipper.h>
|
#include <cli/cli.h>
|
||||||
#include <flipper_v2.h>
|
|
||||||
|
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <gui/widget.h>
|
#include <gui/widget.h>
|
||||||
@ -15,6 +14,8 @@
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Cli* cli;
|
Cli* cli;
|
||||||
|
Gui* gui;
|
||||||
|
ValueMutex* menu;
|
||||||
// Status bar
|
// Status bar
|
||||||
Icon* statusbar_icon;
|
Icon* statusbar_icon;
|
||||||
Widget* statusbar_widget;
|
Widget* statusbar_widget;
|
||||||
@ -26,3 +27,7 @@ typedef struct {
|
|||||||
Bt* bt_alloc();
|
Bt* bt_alloc();
|
||||||
|
|
||||||
void bt_draw_statusbar_callback(Canvas* canvas, void* context);
|
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);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "flipper.h"
|
#include "cc1101.h"
|
||||||
|
#include <furi.h>
|
||||||
#include "cc1101-workaround/cc1101.h"
|
#include <gui/gui.h>
|
||||||
|
#include <input/input.h>
|
||||||
|
|
||||||
extern "C" void cli_print(const char* str);
|
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) {
|
static void input_callback(InputEvent* input_event, void* ctx) {
|
||||||
osMessageQueueId_t event_queue = (QueueHandle_t)ctx;
|
osMessageQueueId_t event_queue = ctx;
|
||||||
|
|
||||||
AppEvent event;
|
AppEvent event;
|
||||||
event.type = EventTypeKey;
|
event.type = EventTypeKey;
|
||||||
@ -370,7 +371,7 @@ extern "C" void cc1101_workaround(void* p) {
|
|||||||
widget_input_callback_set(widget, input_callback, event_queue);
|
widget_input_callback_set(widget, input_callback, event_queue);
|
||||||
|
|
||||||
// Open GUI and register widget
|
// Open GUI and register widget
|
||||||
Gui* gui = (Gui*)furi_open("gui");
|
Gui* gui = (Gui*)furi_record_open("gui");
|
||||||
if(gui == NULL) {
|
if(gui == NULL) {
|
||||||
printf("[cc1101] gui is not available\n");
|
printf("[cc1101] gui is not available\n");
|
||||||
furiac_exit(NULL);
|
furiac_exit(NULL);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "flipper_v2.h"
|
#include <furi.h>
|
||||||
#include "cc1101-workaround/cc1101.h"
|
#include "cc1101-workaround/cc1101.h"
|
||||||
#include "spi.h"
|
#include "spi.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "flipper_v2.h"
|
#include <furi.h>
|
||||||
|
|
||||||
#define F_OSC 26e6
|
#define F_OSC 26e6
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
#include "cli_i.h"
|
#include "cli_i.h"
|
||||||
#include "cli_commands.h"
|
#include "cli_commands.h"
|
||||||
|
|
||||||
#include <api-hal-vcp.h>
|
|
||||||
|
|
||||||
Cli* cli_alloc() {
|
Cli* cli_alloc() {
|
||||||
Cli* cli = furi_alloc(sizeof(Cli));
|
Cli* cli = furi_alloc(sizeof(Cli));
|
||||||
CliCommandDict_init(cli->commands);
|
CliCommandDict_init(cli->commands);
|
||||||
@ -175,12 +173,7 @@ void cli_task(void* p) {
|
|||||||
// Init basic cli commands
|
// Init basic cli commands
|
||||||
cli_commands_init(cli);
|
cli_commands_init(cli);
|
||||||
|
|
||||||
if(!furi_create("cli", cli)) {
|
furi_record_create("cli", cli);
|
||||||
printf("[cli_task] cannot create the cli record\n");
|
|
||||||
furiac_exit(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
furiac_ready();
|
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
cli_process_input(cli);
|
cli_process_input(cli);
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
#include "cli.h"
|
#include "cli.h"
|
||||||
|
|
||||||
#include <flipper.h>
|
#include <furi.h>
|
||||||
#include <flipper_v2.h>
|
|
||||||
|
|
||||||
#include <m-dict.h>
|
#include <m-dict.h>
|
||||||
|
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
#include "flipper.h"
|
#include <furi.h>
|
||||||
#include "u8g2/u8g2.h"
|
#include "u8g2/u8g2.h"
|
||||||
|
|
||||||
extern TIM_HandleTypeDef SPEAKER_TIM;
|
extern TIM_HandleTypeDef SPEAKER_TIM;
|
||||||
|
|
||||||
void coreglitch_demo_0(void* p) {
|
void coreglitch_demo_0(void* p) {
|
||||||
FuriRecordSubscriber* log = get_default_log();
|
printf("coreglitch demo!\n");
|
||||||
|
|
||||||
fuprintf(log, "coreglitch demo!\n");
|
|
||||||
|
|
||||||
float notes[] = {
|
float notes[] = {
|
||||||
0.0,
|
0.0,
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -67,8 +67,7 @@ Dolphin* dolphin_alloc() {
|
|||||||
// State
|
// State
|
||||||
dolphin->state = dolphin_state_alloc();
|
dolphin->state = dolphin_state_alloc();
|
||||||
// Menu
|
// Menu
|
||||||
dolphin->menu_vm = furi_open("menu");
|
dolphin->menu_vm = furi_record_open("menu");
|
||||||
furi_check(dolphin->menu_vm);
|
|
||||||
// GUI
|
// GUI
|
||||||
dolphin->idle_view_dispatcher = view_dispatcher_alloc();
|
dolphin->idle_view_dispatcher = view_dispatcher_alloc();
|
||||||
// First start View
|
// First start View
|
||||||
@ -125,7 +124,7 @@ void dolphin_deed(Dolphin* dolphin, DolphinDeed deed) {
|
|||||||
void dolphin_task() {
|
void dolphin_task() {
|
||||||
Dolphin* dolphin = dolphin_alloc();
|
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);
|
view_dispatcher_attach_to_gui(dolphin->idle_view_dispatcher, gui, ViewDispatcherTypeWindow);
|
||||||
if(dolphin_state_load(dolphin->state)) {
|
if(dolphin_state_load(dolphin->state)) {
|
||||||
view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain);
|
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);
|
model->butthurt = dolphin_state_get_butthurt(dolphin->state);
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!furi_create("dolphin", dolphin)) {
|
furi_record_create("dolphin", dolphin);
|
||||||
printf("[dolphin_task] cannot create the dolphin record\n");
|
|
||||||
furiac_exit(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
furiac_ready();
|
|
||||||
|
|
||||||
DolphinEvent event;
|
DolphinEvent event;
|
||||||
while(1) {
|
while(1) {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include "dolphin_state.h"
|
#include "dolphin_state.h"
|
||||||
#include "dolphin_views.h"
|
#include "dolphin_views.h"
|
||||||
|
|
||||||
#include <flipper_v2.h>
|
#include <furi.h>
|
||||||
|
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <gui/view_dispatcher.h>
|
#include <gui/view_dispatcher.h>
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include "dolphin_state.h"
|
#include "dolphin_state.h"
|
||||||
#include <api-hal-flash.h>
|
#include <furi.h>
|
||||||
#include <flipper_v2.h>
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t magic;
|
uint8_t magic;
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <gui/canvas.h>
|
#include <gui/canvas.h>
|
||||||
#include <flipper_v2.h>
|
#include <input/input.h>
|
||||||
|
#include <furi.h>
|
||||||
|
|
||||||
// Idle scree
|
// Idle scree
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "flipper_v2.h"
|
#include <furi.h>
|
||||||
|
|
||||||
void rgb_set(
|
void rgb_set(
|
||||||
bool r,
|
bool r,
|
||||||
|
@ -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);
|
|
||||||
}
|
|
@ -1,5 +1,6 @@
|
|||||||
#include "flipper_v2.h"
|
#include <furi.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <input/input.h>
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
unsigned int packed;
|
unsigned int packed;
|
||||||
@ -21,12 +22,10 @@ static void event_cb(const void* value, void* ctx) {
|
|||||||
|
|
||||||
void application_input_dump(void* p) {
|
void application_input_dump(void* p) {
|
||||||
// open record
|
// open record
|
||||||
ValueManager* state_record = furi_open("input_state");
|
ValueManager* state_record = furi_record_open("input_state");
|
||||||
furi_check(state_record);
|
|
||||||
subscribe_pubsub(&state_record->pubsub, state_cb, NULL);
|
subscribe_pubsub(&state_record->pubsub, state_cb, NULL);
|
||||||
|
|
||||||
PubSub* event_record = furi_open("input_events");
|
PubSub* event_record = furi_record_open("input_events");
|
||||||
furi_check(event_record);
|
|
||||||
subscribe_pubsub(event_record, event_cb, NULL);
|
subscribe_pubsub(event_record, event_cb, NULL);
|
||||||
|
|
||||||
printf("Example app [input dump]\n");
|
printf("Example app [input dump]\n");
|
||||||
|
@ -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++;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,5 @@
|
|||||||
#include "flipper_v2.h"
|
#include <furi.h>
|
||||||
|
#include <input.h>
|
||||||
|
|
||||||
static void event_cb(const void* value, void* ctx) {
|
static void event_cb(const void* value, void* ctx) {
|
||||||
const InputEvent* event = value;
|
const InputEvent* event = value;
|
||||||
@ -38,8 +39,7 @@ void application_strobe(void* p) {
|
|||||||
ValueMutex delay_mutex;
|
ValueMutex delay_mutex;
|
||||||
init_mutex(&delay_mutex, &delay_time_holder, sizeof(delay_time_holder));
|
init_mutex(&delay_mutex, &delay_time_holder, sizeof(delay_time_holder));
|
||||||
|
|
||||||
PubSub* event_record = furi_open("input_events");
|
PubSub* event_record = furi_record_open("input_events");
|
||||||
furi_check(event_record);
|
|
||||||
subscribe_pubsub(event_record, event_cb, &delay_mutex);
|
subscribe_pubsub(event_record, event_cb, &delay_mutex);
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
|
@ -1,32 +1,14 @@
|
|||||||
#include "u8g2/u8g2.h"
|
#include "u8g2/u8g2.h"
|
||||||
#include "flipper.h"
|
#include <furi.h>
|
||||||
|
|
||||||
void u8g2_example(void* p) {
|
void u8g2_example(void* p) {
|
||||||
FuriRecordSubscriber* log = get_default_log();
|
|
||||||
|
|
||||||
// open record
|
// open record
|
||||||
FuriRecordSubscriber* fb_record =
|
u8g2_t* fb = furi_record_open("u8g2_fb");
|
||||||
furi_open_deprecated("u8g2_fb", false, false, NULL, NULL, NULL);
|
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) {
|
furiac_exit(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);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,6 +1,9 @@
|
|||||||
#include "u8g2/u8g2.h"
|
#include "u8g2/u8g2.h"
|
||||||
#include "qrcode/qrcode.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) {
|
void u8g2_DrawPixelSize(u8g2_t* u8g2, uint8_t x, uint8_t y, uint8_t size) {
|
||||||
for(uint8_t px = 0; px < size; px++) {
|
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) {
|
void u8g2_qrcode(void* p) {
|
||||||
FuriRecordSubscriber* log = get_default_log();
|
|
||||||
|
|
||||||
// open record
|
// open record
|
||||||
FuriRecordSubscriber* fb_record =
|
FuriRecordSubscriber* fb_record =
|
||||||
furi_open_deprecated("u8g2_fb", false, false, NULL, NULL, NULL);
|
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");
|
qrcode_initText(&qrcode, qrcodeBytes, qr_version, qr_error_correction, "HELLO FLIPPER");
|
||||||
|
|
||||||
if(fb_record == NULL) {
|
if(fb_record == NULL) {
|
||||||
fuprintf(log, "[widget] cannot create fb record\n");
|
printf("[widget] cannot create fb record\n");
|
||||||
furiac_exit(NULL);
|
furiac_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,4 +70,5 @@ void u8g2_qrcode(void* p) {
|
|||||||
|
|
||||||
delay(1);
|
delay(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
@ -1,7 +1,5 @@
|
|||||||
#include "flipper.h"
|
#include <furi.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "log.h"
|
|
||||||
#include "flipper_v2.h"
|
|
||||||
|
|
||||||
void application_uart_write(void* p) {
|
void application_uart_write(void* p) {
|
||||||
// Red led for showing progress
|
// Red led for showing progress
|
||||||
@ -11,12 +9,9 @@ void application_uart_write(void* p) {
|
|||||||
|
|
||||||
gpio_init(led_record, GpioModeOutputOpenDrain);
|
gpio_init(led_record, GpioModeOutputOpenDrain);
|
||||||
|
|
||||||
// get_default_log open "tty" record
|
|
||||||
FuriRecordSubscriber* log = get_default_log();
|
|
||||||
|
|
||||||
// create buffer
|
// create buffer
|
||||||
const char test_string[] = "test\n";
|
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
|
// for example, create counter and show its value
|
||||||
uint8_t counter = 0;
|
uint8_t counter = 0;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "flipper_v2.h"
|
#include <furi.h>
|
||||||
|
#include <input/input.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
GpioPin* led;
|
GpioPin* led;
|
||||||
@ -24,7 +25,7 @@ void application_vibro(void* p) {
|
|||||||
gpio_write(ctx.vibro, false);
|
gpio_write(ctx.vibro, false);
|
||||||
|
|
||||||
// subscribe on buttons
|
// subscribe on buttons
|
||||||
PubSub* event_record = furi_open("input_events");
|
PubSub* event_record = furi_record_open("input_events");
|
||||||
furi_check(event_record);
|
furi_check(event_record);
|
||||||
subscribe_pubsub(event_record, button_handler, &ctx);
|
subscribe_pubsub(event_record, button_handler, &ctx);
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 25a2cc076c3162aad721e0d92009cfa7b9100c7a
|
Subproject commit 621044255a8be4d2c3f342e2b22178a342ccbfe8
|
@ -1,4 +1,6 @@
|
|||||||
#include "flipper_v2.h"
|
#include <furi.h>
|
||||||
|
#include <gui/gui.h>
|
||||||
|
#include <input/input.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char* name;
|
const char* name;
|
||||||
@ -47,7 +49,7 @@ static void render_callback(Canvas* canvas, void* ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void input_callback(InputEvent* input_event, 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;
|
AppEvent event;
|
||||||
event.type = EventTypeKey;
|
event.type = EventTypeKey;
|
||||||
@ -74,11 +76,7 @@ void app_gpio_test(void* p) {
|
|||||||
widget_input_callback_set(widget, input_callback, event_queue);
|
widget_input_callback_set(widget, input_callback, event_queue);
|
||||||
|
|
||||||
// Open GUI and register widget
|
// Open GUI and register widget
|
||||||
Gui* gui = (Gui*)furi_open("gui");
|
Gui* gui = furi_record_open("gui");
|
||||||
if(gui == NULL) {
|
|
||||||
printf("[gpio-tester] gui is not available\n");
|
|
||||||
furiac_exit(NULL);
|
|
||||||
}
|
|
||||||
gui_add_widget(gui, widget, GuiLayerFullscreen);
|
gui_add_widget(gui, widget, GuiLayerFullscreen);
|
||||||
|
|
||||||
// configure pin
|
// configure pin
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
#include "canvas_i.h"
|
#include "canvas_i.h"
|
||||||
#include "icon_i.h"
|
#include "icon_i.h"
|
||||||
|
|
||||||
#include <flipper.h>
|
#include <furi.h>
|
||||||
#include <flipper_v2.h>
|
|
||||||
|
|
||||||
struct Canvas {
|
struct Canvas {
|
||||||
u8g2_t fb;
|
u8g2_t fb;
|
||||||
|
@ -5,6 +5,10 @@
|
|||||||
#include <gui/icon.h>
|
#include <gui/icon.h>
|
||||||
#include <assets_icons_i.h>
|
#include <assets_icons_i.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ColorWhite = 0x00,
|
ColorWhite = 0x00,
|
||||||
ColorBlack = 0x01,
|
ColorBlack = 0x01,
|
||||||
@ -91,3 +95,7 @@ void canvas_draw_line(Canvas* canvas, uint8_t x1, uint8_t y1, uint8_t x2, uint8_
|
|||||||
* Draw glyph
|
* Draw glyph
|
||||||
*/
|
*/
|
||||||
void canvas_draw_glyph(Canvas* canvas, uint8_t x, uint8_t y, uint16_t ch);
|
void canvas_draw_glyph(Canvas* canvas, uint8_t x, uint8_t y, uint16_t ch);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "canvas.h"
|
#include "canvas.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Draw scrollbar on canvas.
|
* Draw scrollbar on canvas.
|
||||||
* width 3px, height equal to canvas height
|
* 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
|
* @param width, height - frame width and height
|
||||||
*/
|
*/
|
||||||
void elements_frame(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width, uint8_t height);
|
void elements_frame(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width, uint8_t height);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
#include "gui_i.h"
|
#include "gui_i.h"
|
||||||
|
|
||||||
#include <flipper.h>
|
#include <furi.h>
|
||||||
#include <flipper_v2.h>
|
|
||||||
#include <m-array.h>
|
#include <m-array.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
@ -207,13 +206,9 @@ Gui* gui_alloc() {
|
|||||||
|
|
||||||
void gui_task(void* p) {
|
void gui_task(void* p) {
|
||||||
Gui* gui = gui_alloc();
|
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
|
// Forever dispatch
|
||||||
while(1) {
|
while(1) {
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
#include "widget.h"
|
#include "widget.h"
|
||||||
#include "canvas.h"
|
#include "canvas.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#define GUI_DISPLAY_WIDTH 128
|
#define GUI_DISPLAY_WIDTH 128
|
||||||
#define GUI_DISPLAY_HEIGHT 64
|
#define GUI_DISPLAY_HEIGHT 64
|
||||||
|
|
||||||
@ -40,3 +44,7 @@ void gui_add_widget(Gui* gui, Widget* widget, GuiLayer layer);
|
|||||||
* @remarks thread safe
|
* @remarks thread safe
|
||||||
*/
|
*/
|
||||||
void gui_remove_widget(Gui* gui, Widget* widget);
|
void gui_remove_widget(Gui* gui, Widget* widget);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include "gui_event.h"
|
#include "gui_event.h"
|
||||||
|
|
||||||
#include <flipper_v2.h>
|
#include <furi.h>
|
||||||
|
|
||||||
#define GUI_EVENT_MQUEUE_SIZE 8
|
#define GUI_EVENT_MQUEUE_SIZE 8
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ GuiEvent* gui_event_alloc() {
|
|||||||
// osTimerStart(gui_event->timer, 1024 / 4);
|
// osTimerStart(gui_event->timer, 1024 / 4);
|
||||||
|
|
||||||
// Input
|
// 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);
|
furi_check(gui_event->input_event_record != NULL);
|
||||||
subscribe_pubsub(gui_event->input_event_record, gui_event_input_events_callback, gui_event);
|
subscribe_pubsub(gui_event->input_event_record, gui_event_input_events_callback, gui_event);
|
||||||
|
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <input/input.h>
|
#include <input/input.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GuiMessageTypeRedraw = 0x00,
|
GuiMessageTypeRedraw = 0x00,
|
||||||
GuiMessageTypeInput = 0x01,
|
GuiMessageTypeInput = 0x01,
|
||||||
@ -23,3 +27,7 @@ void gui_event_free(GuiEvent* gui_event);
|
|||||||
void gui_event_messsage_send(GuiEvent* gui_event, GuiMessage* message);
|
void gui_event_messsage_send(GuiEvent* gui_event, GuiMessage* message);
|
||||||
|
|
||||||
GuiMessage gui_event_message_next(GuiEvent* gui_event);
|
GuiMessage gui_event_message_next(GuiEvent* gui_event);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
#include "icon_i.h"
|
#include "icon_i.h"
|
||||||
|
|
||||||
#include <cmsis_os2.h>
|
#include <furi.h>
|
||||||
#include <flipper.h>
|
|
||||||
#include <flipper_v2.h>
|
|
||||||
|
|
||||||
Icon* icon_alloc(const IconData* data) {
|
Icon* icon_alloc(const IconData* data) {
|
||||||
Icon* icon = furi_alloc(sizeof(Icon));
|
Icon* icon = furi_alloc(sizeof(Icon));
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct IconData IconData;
|
typedef struct IconData IconData;
|
||||||
typedef struct Icon Icon;
|
typedef struct Icon Icon;
|
||||||
|
|
||||||
@ -41,3 +45,7 @@ void icon_start_animation(Icon* icon);
|
|||||||
* Stop icon animation
|
* Stop icon animation
|
||||||
*/
|
*/
|
||||||
void icon_stop_animation(Icon* icon);
|
void icon_stop_animation(Icon* icon);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include "u8g2/u8g2.h"
|
#include "u8g2/u8g2.h"
|
||||||
#include "flipper.h"
|
#include <furi.h>
|
||||||
#include <main.h>
|
#include <main.h>
|
||||||
|
|
||||||
extern SPI_HandleTypeDef SPI_D;
|
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
|
// Function to define the logic level of the RESET line
|
||||||
case U8X8_MSG_GPIO_RESET:
|
case U8X8_MSG_GPIO_RESET:
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fuprintf(log, "[u8g2] rst %d\n", arg_int);
|
printf("[u8g2] rst %d\n", arg_int);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// TODO change it to FuriRecord pin
|
// 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:
|
default:
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fufuprintf(log, "[u8g2] unknown io %d\n", msg);
|
printf("[u8g2] unknown io %d\n", msg);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0; //A message was received which is not implemented, return 0 to indicate an error
|
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) {
|
switch(msg) {
|
||||||
case U8X8_MSG_BYTE_SEND:
|
case U8X8_MSG_BYTE_SEND:
|
||||||
#ifdef DEBUG
|
#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
|
#endif
|
||||||
|
|
||||||
// TODO change it to FuriRecord SPI
|
// 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:
|
case U8X8_MSG_BYTE_SET_DC:
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fuprintf(log, "[u8g2] dc %d\n", arg_int);
|
printf("[u8g2] dc %d\n", arg_int);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// TODO change it to FuriRecord pin
|
// 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:
|
case U8X8_MSG_BYTE_INIT:
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fuprintf(log, "[u8g2] init\n");
|
printf("[u8g2] init\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// TODO change it to FuriRecord pin
|
// 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:
|
case U8X8_MSG_BYTE_START_TRANSFER:
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fuprintf(log, "[u8g2] start\n");
|
printf("[u8g2] start\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// TODO: SPI manager
|
// 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:
|
case U8X8_MSG_BYTE_END_TRANSFER:
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fuprintf(log, "[u8g2] end\n");
|
printf("[u8g2] end\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
asm("nop");
|
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:
|
default:
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fuprintf(log, "[u8g2] unknown xfer %d\n", msg);
|
printf("[u8g2] unknown xfer %d\n", msg);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
#include <input/input.h>
|
#include <input/input.h>
|
||||||
#include "canvas.h"
|
#include "canvas.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Hides drawing widget */
|
/* Hides drawing widget */
|
||||||
#define VIEW_NONE 0xFFFFFFFF
|
#define VIEW_NONE 0xFFFFFFFF
|
||||||
/* Ignore navigation event */
|
/* Ignore navigation event */
|
||||||
@ -127,3 +131,7 @@ void view_commit_model(View* view);
|
|||||||
({ void __fn__ function_body __fn__; })(p); \
|
({ void __fn__ function_body __fn__; })(p); \
|
||||||
view_commit_model(view); \
|
view_commit_model(view); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
#include "view.h"
|
#include "view.h"
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/* ViewDispatcher widget placement */
|
/* ViewDispatcher widget placement */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ViewDispatcherTypeNone, /* Special layer for internal use only */
|
ViewDispatcherTypeNone, /* Special layer for internal use only */
|
||||||
@ -43,3 +47,7 @@ void view_dispatcher_attach_to_gui(
|
|||||||
ViewDispatcher* view_dispatcher,
|
ViewDispatcher* view_dispatcher,
|
||||||
Gui* gui,
|
Gui* gui,
|
||||||
ViewDispatcherType type);
|
ViewDispatcherType type);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "view_dispatcher.h"
|
#include "view_dispatcher.h"
|
||||||
#include "view_i.h"
|
#include "view_i.h"
|
||||||
#include <flipper_v2.h>
|
#include <furi.h>
|
||||||
#include <m-dict.h>
|
#include <m-dict.h>
|
||||||
|
|
||||||
DICT_DEF2(ViewDict, uint32_t, M_DEFAULT_OPLIST, View*, M_PTR_OPLIST)
|
DICT_DEF2(ViewDict, uint32_t, M_DEFAULT_OPLIST, View*, M_PTR_OPLIST)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "view.h"
|
#include "view.h"
|
||||||
#include "view_dispatcher_i.h"
|
#include "view_dispatcher_i.h"
|
||||||
#include <flipper_v2.h>
|
#include <furi.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void* data;
|
void* data;
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
#include "widget_i.h"
|
#include "widget_i.h"
|
||||||
|
|
||||||
#include <cmsis_os.h>
|
#include <furi.h>
|
||||||
#include <flipper.h>
|
|
||||||
#include <flipper_v2.h>
|
|
||||||
|
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
#include "gui_i.h"
|
#include "gui_i.h"
|
||||||
@ -73,8 +71,6 @@ void widget_update(Widget* widget) {
|
|||||||
|
|
||||||
void widget_gui_set(Widget* widget, Gui* gui) {
|
void widget_gui_set(Widget* widget, Gui* gui) {
|
||||||
furi_assert(widget);
|
furi_assert(widget);
|
||||||
furi_assert(gui);
|
|
||||||
|
|
||||||
widget->gui = gui;
|
widget->gui = gui;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
#include <input/input.h>
|
#include <input/input.h>
|
||||||
#include "canvas.h"
|
#include "canvas.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct Widget Widget;
|
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.
|
* Rendering will happen later after GUI system process signal.
|
||||||
*/
|
*/
|
||||||
void widget_update(Widget* widget);
|
void widget_update(Widget* widget);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -32,7 +32,7 @@ void AppiButton::run() {
|
|||||||
printf("[ibutton] bye!\n");
|
printf("[ibutton] bye!\n");
|
||||||
// TODO remove all widgets create by app
|
// TODO remove all widgets create by app
|
||||||
widget_enabled_set(widget, false);
|
widget_enabled_set(widget, false);
|
||||||
furiac_exit(NULL);
|
osThreadExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(event.value.input.state && event.value.input.input == InputLeft) {
|
if(event.value.input.state && event.value.input.input == InputLeft) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include <input/input.h>
|
#include <input/input.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <flipper_v2.h>
|
#include <furi.h>
|
||||||
|
|
||||||
#ifdef APP_NFC
|
#ifdef APP_NFC
|
||||||
void nfc_isr(void);
|
void nfc_isr(void);
|
||||||
@ -35,18 +35,10 @@ void input_task(void* p) {
|
|||||||
furiac_exit(NULL);
|
furiac_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!furi_create("input_state", &input_state_record)) {
|
furi_record_create("input_state", &input_state_record);
|
||||||
printf("[input_task] cannot create the input_state record\n");
|
furi_record_create("input_events", &input_events_record);
|
||||||
furiac_exit(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!furi_create("input_events", &input_events_record)) {
|
|
||||||
printf("[input_task] cannot create the input_events record\n");
|
|
||||||
furiac_exit(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// we ready to work
|
// we ready to work
|
||||||
furiac_ready();
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
|
||||||
// Force state update
|
// Force state update
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "flipper.h"
|
#include <furi.h>
|
||||||
#include "flipper_v2.h"
|
|
||||||
#include "irda-decoder-nec.h"
|
#include "irda-decoder-nec.h"
|
||||||
#include "irda-decoder-types.h"
|
#include "irda-decoder-types.h"
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include "flipper.h"
|
#include <furi.h>
|
||||||
#include "flipper_v2.h"
|
#include <gui/gui.h>
|
||||||
|
#include <input/input.h>
|
||||||
|
|
||||||
#include "irda_nec.h"
|
#include "irda_nec.h"
|
||||||
#include "irda_samsung.h"
|
#include "irda_samsung.h"
|
||||||
#include "irda_protocols.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) {
|
static void input_callback(InputEvent* input_event, void* ctx) {
|
||||||
osMessageQueueId_t event_queue = (QueueHandle_t)ctx;
|
osMessageQueueId_t event_queue = ctx;
|
||||||
|
|
||||||
AppEvent event;
|
AppEvent event;
|
||||||
event.type = EventTypeKey;
|
event.type = EventTypeKey;
|
||||||
@ -271,11 +273,7 @@ void irda(void* p) {
|
|||||||
widget_input_callback_set(widget, input_callback, event_queue);
|
widget_input_callback_set(widget, input_callback, event_queue);
|
||||||
|
|
||||||
// Open GUI and register widget
|
// 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);
|
|
||||||
}
|
|
||||||
gui_add_widget(gui, widget, GuiLayerFullscreen);
|
gui_add_widget(gui, widget, GuiLayerFullscreen);
|
||||||
|
|
||||||
// Red LED
|
// Red LED
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "flipper.h"
|
#include <furi.h>
|
||||||
#include "irda_nec.h"
|
#include "irda_nec.h"
|
||||||
#include "irda_protocols.h"
|
#include "irda_protocols.h"
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "flipper.h"
|
#include <furi.h>
|
||||||
|
|
||||||
void ir_nec_send(uint16_t addr, uint8_t data);
|
void ir_nec_send(uint16_t addr, uint8_t data);
|
@ -1,4 +1,4 @@
|
|||||||
#include "flipper.h"
|
#include <furi.h>
|
||||||
#include "irda_samsung.h"
|
#include "irda_samsung.h"
|
||||||
#include "irda_protocols.h"
|
#include "irda_protocols.h"
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "flipper.h"
|
#include <furi.h>
|
||||||
|
|
||||||
void ir_samsung_send(uint16_t addr, uint16_t data);
|
void ir_samsung_send(uint16_t addr, uint16_t data);
|
@ -1,4 +1,4 @@
|
|||||||
#include "flipper_v2.h"
|
#include <furi.h>
|
||||||
|
|
||||||
void prepare_data(uint32_t ID, uint32_t VENDOR, uint8_t* data) {
|
void prepare_data(uint32_t ID, uint32_t VENDOR, uint8_t* data) {
|
||||||
uint8_t value[10];
|
uint8_t value[10];
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "flipper_v2.h"
|
#include <furi.h>
|
||||||
|
#include <gui/gui.h>
|
||||||
|
|
||||||
typedef enum { EventTypeTick, EventTypeKey, EventTypeRx } EventType;
|
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) {
|
static void input_callback(InputEvent* input_event, void* ctx) {
|
||||||
osMessageQueueId_t event_queue = (QueueHandle_t)ctx;
|
osMessageQueueId_t event_queue = ctx;
|
||||||
|
|
||||||
AppEvent event;
|
AppEvent event;
|
||||||
event.type = EventTypeKey;
|
event.type = EventTypeKey;
|
||||||
@ -67,7 +68,7 @@ void comparator_trigger_callback(void* hcomp, void* comp_ctx) {
|
|||||||
|
|
||||||
// gpio_write(&debug_0, true);
|
// gpio_write(&debug_0, true);
|
||||||
|
|
||||||
osMessageQueueId_t event_queue = (QueueHandle_t)comp_ctx;
|
osMessageQueueId_t event_queue = comp_ctx;
|
||||||
|
|
||||||
AppEvent event;
|
AppEvent event;
|
||||||
event.type = EventTypeRx;
|
event.type = EventTypeRx;
|
||||||
@ -202,11 +203,7 @@ void lf_rfid_workaround(void* p) {
|
|||||||
widget_input_callback_set(widget, input_callback, event_queue);
|
widget_input_callback_set(widget, input_callback, event_queue);
|
||||||
|
|
||||||
// Open GUI and register widget
|
// 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);
|
|
||||||
}
|
|
||||||
gui_add_widget(gui, widget, GuiLayerFullscreen);
|
gui_add_widget(gui, widget, GuiLayerFullscreen);
|
||||||
|
|
||||||
AppEvent event;
|
AppEvent event;
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
#include <cmsis_os.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <flipper_v2.h>
|
#include <furi.h>
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <gui/elements.h>
|
#include <gui/elements.h>
|
||||||
|
|
||||||
@ -42,8 +41,7 @@ ValueMutex* menu_init() {
|
|||||||
menu->widget = widget_alloc();
|
menu->widget = widget_alloc();
|
||||||
|
|
||||||
// Open GUI and register fullscreen widget
|
// Open GUI and register fullscreen widget
|
||||||
Gui* gui = furi_open("gui");
|
Gui* gui = furi_record_open("gui");
|
||||||
furi_check(gui);
|
|
||||||
gui_add_widget(gui, menu->widget, GuiLayerFullscreen);
|
gui_add_widget(gui, menu->widget, GuiLayerFullscreen);
|
||||||
|
|
||||||
widget_enabled_set(menu->widget, false);
|
widget_enabled_set(menu->widget, false);
|
||||||
@ -237,12 +235,7 @@ void menu_task(void* p) {
|
|||||||
release_mutex(menu_mutex, menu);
|
release_mutex(menu_mutex, menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!furi_create("menu", menu_mutex)) {
|
furi_record_create("menu", menu_mutex);
|
||||||
printf("[menu_task] cannot create the menu record\n");
|
|
||||||
furiac_exit(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
furiac_ready();
|
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
MenuMessage m = menu_event_next(menu_event);
|
MenuMessage m = menu_event_next(menu_event);
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
#include "menu_event.h"
|
#include "menu_event.h"
|
||||||
|
|
||||||
#include <cmsis_os.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include <flipper.h>
|
#include <furi.h>
|
||||||
#include <flipper_v2.h>
|
|
||||||
|
|
||||||
#define MENU_MESSAGE_MQUEUE_SIZE 8
|
#define MENU_MESSAGE_MQUEUE_SIZE 8
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
#include "menu_item.h"
|
#include "menu_item.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <flipper.h>
|
#include <furi.h>
|
||||||
#include <flipper_v2.h>
|
|
||||||
|
|
||||||
struct MenuItem {
|
struct MenuItem {
|
||||||
MenuItemType type;
|
MenuItemType type;
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
#include "flipper_v2.h"
|
#include <furi.h>
|
||||||
|
#include <gui/gui.h>
|
||||||
|
#include <input/input.h>
|
||||||
|
|
||||||
// TODO float note freq
|
// TODO float note freq
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -302,7 +304,7 @@ static void render_callback(Canvas* canvas, void* ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void input_callback(InputEvent* input_event, 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;
|
MusicDemoEvent event;
|
||||||
event.type = EventTypeKey;
|
event.type = EventTypeKey;
|
||||||
@ -376,15 +378,11 @@ void music_player(void* p) {
|
|||||||
widget_input_callback_set(widget, input_callback, event_queue);
|
widget_input_callback_set(widget, input_callback, event_queue);
|
||||||
|
|
||||||
// Open GUI and register widget
|
// 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);
|
|
||||||
}
|
|
||||||
gui_add_widget(gui, widget, GuiLayerFullscreen);
|
gui_add_widget(gui, widget, GuiLayerFullscreen);
|
||||||
|
|
||||||
// open input record
|
// open input record
|
||||||
PubSub* input_events_record = furi_open("input_events");
|
PubSub* input_events_record = furi_record_open("input_events");
|
||||||
// prepare "do nothing" event
|
// prepare "do nothing" event
|
||||||
InputEvent input_event = {InputRight, true};
|
InputEvent input_event = {InputRight, true};
|
||||||
|
|
||||||
|
@ -16,8 +16,7 @@ Nfc* nfc_alloc() {
|
|||||||
nfc->worker = nfc_worker_alloc(nfc->message_queue);
|
nfc->worker = nfc_worker_alloc(nfc->message_queue);
|
||||||
|
|
||||||
nfc->icon = assets_icons_get(A_NFC_14);
|
nfc->icon = assets_icons_get(A_NFC_14);
|
||||||
nfc->menu_vm = furi_open("menu");
|
nfc->menu_vm = furi_record_open("menu");
|
||||||
furi_check(nfc->menu_vm);
|
|
||||||
|
|
||||||
nfc->menu = menu_item_alloc_menu("NFC", nfc->icon);
|
nfc->menu = menu_item_alloc_menu("NFC", nfc->icon);
|
||||||
menu_item_subitem_add(
|
menu_item_subitem_add(
|
||||||
@ -102,18 +101,13 @@ void nfc_start(Nfc* nfc, NfcView view_id, NfcWorkerState worker_state) {
|
|||||||
void nfc_task(void* p) {
|
void nfc_task(void* p) {
|
||||||
Nfc* nfc = nfc_alloc();
|
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);
|
view_dispatcher_attach_to_gui(nfc->view_dispatcher, gui, ViewDispatcherTypeFullscreen);
|
||||||
|
|
||||||
with_value_mutex(
|
with_value_mutex(
|
||||||
nfc->menu_vm, (Menu * menu) { menu_item_add(menu, nfc->menu); });
|
nfc->menu_vm, (Menu * menu) { menu_item_add(menu, nfc->menu); });
|
||||||
|
|
||||||
if(!furi_create("nfc", nfc)) {
|
furi_record_create("nfc", nfc);
|
||||||
printf("[nfc_task] cannot create nfc record\n");
|
|
||||||
furiac_exit(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
furiac_ready();
|
|
||||||
|
|
||||||
NfcMessage message;
|
NfcMessage message;
|
||||||
while(1) {
|
while(1) {
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#include "nfc_views.h"
|
#include "nfc_views.h"
|
||||||
#include "nfc_worker.h"
|
#include "nfc_worker.h"
|
||||||
|
|
||||||
#include <flipper_v2.h>
|
#include <furi.h>
|
||||||
|
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <gui/view.h>
|
#include <gui/view.h>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <gui/canvas.h>
|
#include <gui/canvas.h>
|
||||||
#include <flipper_v2.h>
|
#include <furi.h>
|
||||||
|
|
||||||
#include "nfc_types.h"
|
#include "nfc_types.h"
|
||||||
|
|
||||||
|
@ -3,8 +3,7 @@
|
|||||||
#include "nfc_types.h"
|
#include "nfc_types.h"
|
||||||
#include "nfc_worker.h"
|
#include "nfc_worker.h"
|
||||||
|
|
||||||
#include <flipper_v2.h>
|
#include <furi.h>
|
||||||
#include <cmsis_os2.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <rfal_analogConfig.h>
|
#include <rfal_analogConfig.h>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include "power.h"
|
#include "power.h"
|
||||||
#include "power_views.h"
|
#include "power_views.h"
|
||||||
|
|
||||||
#include <flipper_v2.h>
|
#include <furi.h>
|
||||||
|
|
||||||
#include <menu/menu.h>
|
#include <menu/menu.h>
|
||||||
#include <menu/menu_item.h>
|
#include <menu/menu_item.h>
|
||||||
@ -12,8 +12,8 @@
|
|||||||
#include <gui/view_dispatcher.h>
|
#include <gui/view_dispatcher.h>
|
||||||
|
|
||||||
#include <assets_icons.h>
|
#include <assets_icons.h>
|
||||||
#include <api-hal-power.h>
|
|
||||||
#include <cli/cli.h>
|
#include <cli/cli.h>
|
||||||
|
#include <stm32wbxx.h>
|
||||||
|
|
||||||
struct Power {
|
struct Power {
|
||||||
ViewDispatcher* view_dispatcher;
|
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) {
|
void power_menu_off_callback(void* context) {
|
||||||
api_hal_power_off();
|
api_hal_power_off();
|
||||||
}
|
}
|
||||||
@ -71,10 +75,9 @@ void power_menu_info_callback(void* context) {
|
|||||||
Power* power_alloc() {
|
Power* power_alloc() {
|
||||||
Power* power = furi_alloc(sizeof(Power));
|
Power* power = furi_alloc(sizeof(Power));
|
||||||
|
|
||||||
power->menu_vm = furi_open("menu");
|
power->menu_vm = furi_record_open("menu");
|
||||||
furi_check(power->menu_vm);
|
|
||||||
|
|
||||||
power->cli = furi_open("cli");
|
power->cli = furi_record_open("cli");
|
||||||
|
|
||||||
power->menu = menu_item_alloc_menu("Power", NULL);
|
power->menu = menu_item_alloc_menu("Power", NULL);
|
||||||
menu_item_subitem_add(
|
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);
|
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->usb_widget, GuiLayerStatusBarLeft);
|
||||||
gui_add_widget(gui, power->battery_widget, GuiLayerStatusBarRight);
|
gui_add_widget(gui, power->battery_widget, GuiLayerStatusBarRight);
|
||||||
view_dispatcher_attach_to_gui(power->view_dispatcher, gui, ViewDispatcherTypeFullscreen);
|
view_dispatcher_attach_to_gui(power->view_dispatcher, gui, ViewDispatcherTypeFullscreen);
|
||||||
@ -171,14 +174,9 @@ void power_task(void* p) {
|
|||||||
with_value_mutex(
|
with_value_mutex(
|
||||||
power->menu_vm, (Menu * menu) { menu_item_add(menu, power->menu); });
|
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();
|
api_hal_power_init();
|
||||||
|
|
||||||
furiac_ready();
|
furi_record_create("power", power);
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
with_view_model(
|
with_view_model(
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <furi.h>
|
||||||
#include <gui/canvas.h>
|
#include <gui/canvas.h>
|
||||||
#include <flipper_v2.h>
|
|
||||||
#include <gui/view.h>
|
#include <gui/view.h>
|
||||||
|
|
||||||
typedef enum { PowerViewInfo } PowerView;
|
typedef enum { PowerViewInfo } PowerView;
|
||||||
@ -24,8 +24,4 @@ typedef struct {
|
|||||||
uint8_t charge;
|
uint8_t charge;
|
||||||
} PowerInfoModel;
|
} PowerInfoModel;
|
||||||
|
|
||||||
static uint32_t power_info_back_callback(void* context) {
|
|
||||||
return VIEW_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void power_info_draw_callback(Canvas* canvas, void* context);
|
void power_info_draw_callback(Canvas* canvas, void* context);
|
||||||
|
@ -104,23 +104,21 @@ void SdTest::run() {
|
|||||||
|
|
||||||
app_ready();
|
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) {
|
if(fs_api == NULL) {
|
||||||
set_error({"cannot get sdcard api"});
|
set_error({"cannot get sdcard api"});
|
||||||
exit();
|
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
|
||||||
// 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);
|
||||||
auto cli_read_cb = cbc::obtain_connector<0>(this, &SdTest::cli_read_benchmark);
|
cli_add_command(cli, "sd_read_test", cli_read_cb, this);
|
||||||
cli_add_command(cli, "sd_read_test", cli_read_cb, this);
|
|
||||||
|
|
||||||
auto cli_write_cb = cbc::obtain_connector<1>(this, &SdTest::cli_write_benchmark);
|
auto cli_write_cb = cbc::obtain_connector<1>(this, &SdTest::cli_write_benchmark);
|
||||||
cli_add_command(cli, "sd_write_test", cli_write_cb, this);
|
cli_add_command(cli, "sd_write_test", cli_write_cb, this);
|
||||||
}
|
|
||||||
|
|
||||||
detect_sd_card();
|
detect_sd_card();
|
||||||
get_sd_card_info();
|
get_sd_card_info();
|
||||||
@ -893,6 +891,7 @@ template <class T> void SdTest::set_text(std::initializer_list<T> list) {
|
|||||||
|
|
||||||
printf("------------------------\n");
|
printf("------------------------\n");
|
||||||
release_state();
|
release_state();
|
||||||
|
update_gui();
|
||||||
}
|
}
|
||||||
|
|
||||||
// render app
|
// render app
|
||||||
|
@ -480,22 +480,19 @@ void sd_filesystem(void* p) {
|
|||||||
SdApp* sd_app = sd_app_alloc();
|
SdApp* sd_app = sd_app_alloc();
|
||||||
FS_Api* fs_api = fs_api_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->widget, GuiLayerFullscreen);
|
||||||
gui_add_widget(gui, sd_app->icon.widget, GuiLayerStatusBarLeft);
|
gui_add_widget(gui, sd_app->icon.widget, GuiLayerStatusBarLeft);
|
||||||
|
|
||||||
Cli* cli = furi_open("cli");
|
cli_add_command(cli, "sd_status", cli_sd_status, sd_app);
|
||||||
|
cli_add_command(cli, "sd_format", cli_sd_format, sd_app);
|
||||||
if(cli != NULL) {
|
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
|
// add api record
|
||||||
if(!furi_create("sdcard", fs_api)) {
|
furi_record_create("sdcard", fs_api);
|
||||||
furiac_exit(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// init menu
|
// init menu
|
||||||
// TODO menu icon
|
// 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));
|
menu_item, menu_item_alloc_function("Eject", NULL, app_sd_eject_callback, sd_app));
|
||||||
|
|
||||||
// add item to menu
|
// add item to menu
|
||||||
ValueMutex* menu_vm = furi_open("menu");
|
|
||||||
furi_check(menu_vm);
|
furi_check(menu_vm);
|
||||||
with_value_mutex(
|
with_value_mutex(
|
||||||
menu_vm, (Menu * menu) { menu_item_add(menu, menu_item); });
|
menu_vm, (Menu * menu) { menu_item_add(menu, menu_item); });
|
||||||
|
|
||||||
furiac_ready();
|
|
||||||
|
|
||||||
printf("[sd_filesystem] start\n");
|
printf("[sd_filesystem] start\n");
|
||||||
|
|
||||||
|
// add api record
|
||||||
|
furi_record_create("sdcard", fs_api);
|
||||||
|
|
||||||
// sd card cycle
|
// sd card cycle
|
||||||
bool sd_was_present = true;
|
bool sd_was_present = true;
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#pragma once
|
#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_FS_MAX_FILES _FS_LOCK
|
||||||
#define SD_STATE_LINES_COUNT 6
|
#define SD_STATE_LINES_COUNT 6
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "flipper_v2.h"
|
#include <furi.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
EventTypeTick,
|
EventTypeTick,
|
||||||
@ -54,7 +54,7 @@ void template_app(void* p) {
|
|||||||
widget_input_callback_set(widget, input_callback, event_queue);
|
widget_input_callback_set(widget, input_callback, event_queue);
|
||||||
|
|
||||||
// Open GUI and register widget
|
// Open GUI and register widget
|
||||||
Gui* gui = (Gui*)furi_open("gui");
|
Gui* gui = furi_record_open("gui");
|
||||||
if(gui == NULL) {
|
if(gui == NULL) {
|
||||||
printf("gui is not available\n");
|
printf("gui is not available\n");
|
||||||
furiac_exit(NULL);
|
furiac_exit(NULL);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "flipper_v2.h"
|
#include <furi.h>
|
||||||
#include "minunit.h"
|
#include "minunit.h"
|
||||||
|
|
||||||
static void furi_concurent_app(void* p) {
|
static void furi_concurent_app(void* p) {
|
||||||
@ -10,7 +10,9 @@ static void furi_concurent_app(void* p) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void test_furi_event() {
|
void test_furi_event() {
|
||||||
Event event;
|
mu_assert(false, "please reimplement or delete test");
|
||||||
|
|
||||||
|
/*Event event;
|
||||||
|
|
||||||
mu_check(init_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
|
// The event should not be signalled once it's processed
|
||||||
mu_check(!wait_event_with_timeout(&event, 100));
|
mu_check(!wait_event_with_timeout(&event, 100));
|
||||||
|
|
||||||
mu_check(delete_event(&event));
|
mu_check(delete_event(&event));*/
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "flipper_v2.h"
|
#include <furi.h>
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
#include "minunit.h"
|
#include "minunit.h"
|
||||||
|
|
||||||
const uint32_t context_value = 0xdeadbeef;
|
const uint32_t context_value = 0xdeadbeef;
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "flipper.h"
|
#include <furi.h>
|
||||||
#include "flipper_v2.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "minunit.h"
|
#include "minunit.h"
|
||||||
|
|
||||||
void test_furi_create_open() {
|
void test_furi_create_open() {
|
||||||
// 1. Create record
|
// 1. Create record
|
||||||
uint8_t test_data = 0;
|
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
|
// 2. Open it
|
||||||
void* record = furi_open("test/holding");
|
void* record = furi_record_open("test/holding");
|
||||||
mu_assert_pointers_eq(record, &test_data);
|
mu_assert_pointers_eq(record, &test_data);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "flipper_v2.h"
|
#include <furi.h>
|
||||||
#include "minunit.h"
|
#include "minunit.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "flipper_v2.h"
|
#include <furi.h>
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
#include "minunit.h"
|
#include "minunit.h"
|
||||||
|
|
||||||
@ -88,6 +87,8 @@ void furi_concurent_app(void* p) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void test_furi_concurrent_access() {
|
void test_furi_concurrent_access() {
|
||||||
|
mu_assert(false, "please reimplement or delete test");
|
||||||
|
/*
|
||||||
// 1. Create holding record
|
// 1. Create holding record
|
||||||
ConcurrentValue value = {.a = 0, .b = 0};
|
ConcurrentValue value = {.a = 0, .b = 0};
|
||||||
ValueMutex mutex;
|
ValueMutex mutex;
|
||||||
@ -123,4 +124,5 @@ void test_furi_concurrent_access() {
|
|||||||
mu_assert_int_eq(value.a, value.b);
|
mu_assert_int_eq(value.a, value.b);
|
||||||
|
|
||||||
mu_check(delete_mutex(&mutex));
|
mu_check(delete_mutex(&mutex));
|
||||||
|
*/
|
||||||
}
|
}
|
@ -1,7 +1,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "flipper.h"
|
#include <furi.h>
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Test: creating and killing task
|
Test: creating and killing task
|
||||||
@ -24,6 +23,8 @@ void create_kill_app(void* p) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool test_furi_ac_create_kill() {
|
bool test_furi_ac_create_kill() {
|
||||||
|
mu_assert(false, "please reimplement or delete test");
|
||||||
|
/*
|
||||||
uint8_t counter = 0;
|
uint8_t counter = 0;
|
||||||
|
|
||||||
uint8_t value_a = counter;
|
uint8_t value_a = counter;
|
||||||
@ -56,6 +57,7 @@ bool test_furi_ac_create_kill() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "flipper.h"
|
#include <furi.h>
|
||||||
#include "log.h"
|
|
||||||
#include "minunit_vars.h"
|
#include "minunit_vars.h"
|
||||||
#include "minunit.h"
|
#include "minunit.h"
|
||||||
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "flipper.h"
|
#include <furi.h>
|
||||||
#include "flipper_v2.h"
|
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
// #include "flipper-core.h" TODO: Rust build disabled
|
// #include "flipper-core.h" TODO: Rust build disabled
|
||||||
|
|
||||||
|
@ -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);
|
|
@ -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;
|
|
||||||
}
|
|
@ -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);
|
|
@ -1,4 +1,6 @@
|
|||||||
#include "api-gpio.h"
|
#include "api-gpio.h"
|
||||||
|
#include <cmsis_os2.h>
|
||||||
|
#include <furi/record.h>
|
||||||
|
|
||||||
osMutexId_t gpioInitMutex;
|
osMutexId_t gpioInitMutex;
|
||||||
|
|
||||||
@ -37,7 +39,7 @@ void gpio_disable(GpioDisableRecord* gpio_record) {
|
|||||||
|
|
||||||
// get GPIO record
|
// get GPIO record
|
||||||
ValueMutex* gpio_open_mutex(const char* name) {
|
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
|
// TODO disable gpio on app exit
|
||||||
//if(gpio_mutex != NULL) flapp_on_exit(gpio_disable, gpio_mutex);
|
//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
|
// get GPIO record and acquire mutex
|
||||||
GpioPin* gpio_open(const char* name) {
|
GpioPin* gpio_open(const char* name) {
|
||||||
ValueMutex* gpio_mutex = gpio_open_mutex(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;
|
return gpio_pin;
|
||||||
}
|
}
|
@ -1,7 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "flipper.h"
|
|
||||||
#include "flipper_v2.h"
|
|
||||||
#include "api-hal-gpio.h"
|
#include "api-hal-gpio.h"
|
||||||
|
#include <furi/valuemutex.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ValueMutex* gpio_mutex;
|
ValueMutex* gpio_mutex;
|
||||||
@ -38,4 +42,8 @@ void gpio_disable(GpioDisableRecord* gpio_record);
|
|||||||
ValueMutex* gpio_open_mutex(const char* name);
|
ValueMutex* gpio_open_mutex(const char* name);
|
||||||
|
|
||||||
// get GPIO record and acquire mutex
|
// get GPIO record and acquire mutex
|
||||||
GpioPin* gpio_open(const char* name);
|
GpioPin* gpio_open(const char* name);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
#include "api-interrupt-mgr.h"
|
#include "api-interrupt-mgr.h"
|
||||||
|
|
||||||
|
#include <m-list.h>
|
||||||
|
#include <cmsis_os2.h>
|
||||||
|
|
||||||
LIST_DEF(list_interrupt, InterruptCallbackItem, M_POD_OPLIST);
|
LIST_DEF(list_interrupt, InterruptCallbackItem, M_POD_OPLIST);
|
||||||
list_interrupt_t interrupts;
|
list_interrupt_t interrupts;
|
||||||
osMutexId_t interrupt_list_mutex;
|
osMutexId_t interrupt_list_mutex;
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "flipper_v2.h"
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef void (*InterruptCallback)(void*, void*);
|
typedef void (*InterruptCallback)(void*, void*);
|
||||||
|
|
||||||
@ -18,4 +23,8 @@ typedef struct {
|
|||||||
bool api_interrupt_init();
|
bool api_interrupt_init();
|
||||||
void api_interrupt_add(InterruptCallback callback, InterruptType type, void* context);
|
void api_interrupt_add(InterruptCallback callback, InterruptType type, void* context);
|
||||||
void api_interrupt_remove(InterruptCallback callback);
|
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
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
#include "flipper_v2.h"
|
#include <furi.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
struct used for handling SPI info.
|
struct used for handling SPI info.
|
||||||
@ -133,4 +137,8 @@ void cc1101_example() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
48
core/app.cpp
48
core/app.cpp
@ -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;
|
|
||||||
}
|
|
@ -1,8 +1,8 @@
|
|||||||
CORE_DIR = $(PROJECT_ROOT)/core
|
CORE_DIR = $(PROJECT_ROOT)/core
|
||||||
|
|
||||||
CFLAGS += -I$(CORE_DIR)
|
CFLAGS += -I$(CORE_DIR) -D_GNU_SOURCE
|
||||||
ASM_SOURCES += $(wildcard $(CORE_DIR)/*.s)
|
ASM_SOURCES += $(wildcard $(CORE_DIR)/*.s)
|
||||||
C_SOURCES += $(wildcard $(CORE_DIR)/*.c)
|
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)
|
C_SOURCES += $(wildcard $(CORE_DIR)/api-hal/*.c)
|
||||||
CPP_SOURCES += $(wildcard $(CORE_DIR)/*.cpp)
|
CPP_SOURCES += $(wildcard $(CORE_DIR)/*.cpp)
|
||||||
|
@ -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
|
|
@ -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;
|
|
@ -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;
|
|
||||||
}
|
|
@ -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
|
|
@ -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;
|
|
||||||
}
|
|
@ -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
36
core/furi.c
Normal 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
28
core/furi.h
Normal 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
|
@ -1,5 +1,6 @@
|
|||||||
#include "check.h"
|
#include "check.h"
|
||||||
#include "api-hal-task.h"
|
#include "api-hal-task.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
void __furi_abort(void);
|
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()) {
|
if(task_is_isr_context()) {
|
||||||
printf(" in [ISR] context");
|
printf(" in [ISR] context");
|
||||||
} else {
|
} else {
|
||||||
FuriApp* app = find_task(xTaskGetCurrentTaskHandle());
|
// FuriApp* app = find_task(xTaskGetCurrentTaskHandle());
|
||||||
|
|
||||||
if(app == NULL) {
|
// if(app == NULL) {
|
||||||
printf(", in [main] context");
|
// printf(", in [main] context");
|
||||||
} else {
|
// } else {
|
||||||
printf(", in [%s] app context", app->name);
|
// printf(", in [%s] app context", app->name);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
__furi_abort();
|
__furi_abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
void __furi_abort(void) {
|
void __furi_abort(void) {
|
||||||
taskDISABLE_INTERRUPTS();
|
__disable_irq();
|
||||||
|
asm("bkpt 1");
|
||||||
while(1) {
|
while(1) {
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "flipper.h"
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
// Find how to how get function's pretty name
|
// Find how to how get function's pretty name
|
||||||
#ifndef __FURI_CHECK_FUNC
|
#ifndef __FURI_CHECK_FUNC
|
||||||
@ -38,4 +40,8 @@
|
|||||||
// !NDEBUG
|
// !NDEBUG
|
||||||
|
|
||||||
void __furi_check(void);
|
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
Loading…
Reference in New Issue
Block a user