[FL-2627] Flipper applications: SDK, build and debug system (#1387)

* Added support for running applications from SD card (FAPs - Flipper Application Packages)
* Added plugin_dist target for fbt to build FAPs
* All apps of type FlipperAppType.EXTERNAL and FlipperAppType.PLUGIN are built as FAPs by default
* Updated VSCode configuration for new fbt features - re-deploy stock configuration to use them
* Added debugging support for FAPs with fbt debug & VSCode
* Added public firmware API with automated versioning

Co-authored-by: hedger <hedger@users.noreply.github.com>
Co-authored-by: SG <who.just.the.doctor@gmail.com>
Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
SG
2022-09-15 02:11:38 +10:00
committed by Aleksandr Kutuzov
parent 0f6f9ad52e
commit b9a766d909
895 changed files with 8862 additions and 1465 deletions

View File

@@ -1,38 +1,90 @@
# Structure
- `about` - Small About application that shows flipper info
- `accessor` - Wiegand server
- `application.h` - Firmware application list header
## debug
Applications for factory testing the Flipper.
- `accessor` - Wiegand server
- `battery_test_app` - Battery debug app
- `blink_test` - LED blinker
- `bt_debug_app` - BT test app. Requires full BT stack installed
- `display_test` - Various display tests & tweaks
- `file_browser_test` - Test UI for file picker
- `keypad_test` - Keypad test
- `lfrfid_debug` - LF RFID debug tool
- `text_box_test` - UI tests
- `uart_echo` - UART mode test
- `unit_tests` - Unit tests
- `usb_mouse` - USB HID test
- `usb_test` - Other USB tests
- `vibro_test` - Vibro test
## main
Applications for main Flipper menu.
- `archive` - Archive and file manager
- `bad_usb` - Bad USB application
- `fap_loader` - External applications loader
- `gpio` - GPIO application: includes USART bridge and GPIO control
- `ibutton` - iButton application, onewire keys and more
- `infrared` - Infrared application, controls your IR devices
- `lfrfid` - LF RFID application
- `nfc` - NFC application, HF rfid, EMV and etc
- `subghz` - SubGhz application, 433 fobs and etc
- `u2f` - U2F Application
## plugins
Extra apps for Plugins & App Loader menus.
- `bt_hid_app` - BT Remote controller
- `music_player` - Music player app (demo)
- `picopass` - Picopass tool
- `snake_game` - Snake game application
## services
Background services providing system APIs to applications.
- `bt` - BLE service and application
- `cli` - Console service and API
- `crypto` - Crypto cli tools
- `debug_tools` - Different tools that we use for debug
- `desktop` - Desktop service
- `dialogs` - Dialogs service: GUI Dialogs for your app
- `dolphin` - Dolphin service and supplementary apps
- `gpio` - GPIO application: includes USART bridge and GPIO control
- `gui` - GUI service and API
- `ibutton` - iButton application, onewire keys and more
- `input` - Input service
- `infrared` - Infrared application, controls your IR devices
- `lfrfid` - LF RFID application
- `lfrfid_debug` - LF RFID debug tool
- `loader` - Application loader service
- `music_player` - Music player app (demo)
- `nfc` - NFC application, HF rfid, EMV and etc
- `notification` - Notification service
- `power` - Power service
- `power_observer` - Power debug tool
- `rpc` - RPC service and API
- `scened_app_example` - C++ application example
- `snake_game` - Snake game application
- `storage` - Storage service, internal + sdcard
- `storage_settings` - Storage settings app
- `subghz` - SubGhz application, 433 fobs and etc
- `system` - System settings, tools and API
- `tests` - Unit tests and etc
- `u2f` - U2F Application
- `updater` - Update service & application
- `application.h` - Firmware application list header
## settings
Small applications providing configuration for basic firmware and its services.
- `about` - Small About application that shows flipper info
- `bt_settings_app` - Bluetooth options
- `desktop_settings` - Desktop configuration
- `dolphin_passport` - Dolphin passport app
- `notification_settings` - LCD brightness, sound volume, etc configuration
- `power_settings_app` - Basic power options
- `storage_settings` - Storage settings app
- `system` - System settings
## system
Utility apps not visible in other menus.
- `storage_move_to_sd` - Data migration tool for internal storage
- `updater` - Update service & application

View File

@@ -1,66 +0,0 @@
App(
appid="bt",
name="BtSrv",
apptype=FlipperAppType.SERVICE,
entry_point="bt_srv",
cdefines=["SRV_BT"],
requires=[
"cli",
"dialogs",
],
provides=[
"bt_start",
"bt_settings",
"bt_debug",
],
stack_size=1 * 1024,
order=20,
)
App(
appid="bt_start",
apptype=FlipperAppType.STARTUP,
entry_point="bt_on_system_start",
order=70,
)
App(
appid="bt_settings",
name="Bluetooth",
apptype=FlipperAppType.SETTINGS,
entry_point="bt_settings_app",
stack_size=1 * 1024,
requires=[
"bt",
"gui",
],
order=10,
)
App(
appid="bt_debug",
name="Bluetooth Debug",
apptype=FlipperAppType.DEBUG,
entry_point="bt_debug_app",
stack_size=1 * 1024,
requires=[
"bt",
"gui",
"dialogs",
],
order=110,
)
App(
appid="bt_hid",
name="Bluetooth Remote",
apptype=FlipperAppType.PLUGIN,
entry_point="bt_hid_app",
stack_size=1 * 1024,
cdefines=["APP_BLE_HID"],
requires=[
"bt",
"gui",
],
order=10,
)

View File

@@ -7,4 +7,5 @@ App(
requires=["gui"],
stack_size=4 * 1024,
order=40,
fap_category="Debug",
)

View File

@@ -0,0 +1,16 @@
App(
appid="debug_apps",
name="Basic debug apps bundle",
apptype=FlipperAppType.METAPACKAGE,
provides=[
"blink_test",
"vibro_test",
"keypad_test",
"usb_test",
"usb_mouse",
"uart_echo",
"display_test",
"text_box_test",
"file_browser_test",
],
)

View File

@@ -0,0 +1,14 @@
App(
appid="battery_test",
name="Battery Test",
apptype=FlipperAppType.DEBUG,
entry_point="battery_test_app",
cdefines=["APP_BATTERY_TEST"],
requires=[
"gui",
"power",
],
stack_size=1 * 1024,
order=130,
fap_category="Debug",
)

View File

@@ -27,7 +27,7 @@ static void battery_test_battery_info_update_model(void* context) {
.charge = app->info.charge,
.health = app->info.health,
};
battery_info_set_data(app->batery_info, &battery_info_data);
battery_info_set_data(app->battery_info, &battery_info_data);
notification_message(app->notifications, &sequence_display_backlight_on);
}
@@ -48,13 +48,13 @@ BatteryTestApp* battery_test_alloc() {
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
// Views
app->batery_info = battery_info_alloc();
app->battery_info = battery_info_alloc();
view_set_previous_callback(
battery_info_get_view(app->batery_info), battery_test_exit_confirm_view);
battery_info_get_view(app->battery_info), battery_test_exit_confirm_view);
view_dispatcher_add_view(
app->view_dispatcher,
BatteryTestAppViewBatteryInfo,
battery_info_get_view(app->batery_info));
battery_info_get_view(app->battery_info));
app->dialog = dialog_ex_alloc();
dialog_ex_set_header(app->dialog, "Close Battery Test?", 64, 12, AlignCenter, AlignTop);
@@ -76,7 +76,7 @@ void battery_test_free(BatteryTestApp* app) {
// Views
view_dispatcher_remove_view(app->view_dispatcher, BatteryTestAppViewBatteryInfo);
battery_info_free(app->batery_info);
battery_info_free(app->battery_info);
view_dispatcher_remove_view(app->view_dispatcher, BatteryTestAppViewExitDialog);
dialog_ex_free(app->dialog);
// View dispatcher

View File

@@ -6,14 +6,15 @@
#include <notification/notification.h>
#include <gui/modules/dialog_ex.h>
#include <power/power_settings_app/views/battery_info.h>
// FIXME
#include "../settings/power_settings_app/views/battery_info.h"
typedef struct {
Power* power;
Gui* gui;
NotificationApp* notifications;
ViewDispatcher* view_dispatcher;
BatteryInfo* batery_info;
BatteryInfo* battery_info;
DialogEx* dialog;
PowerInfo info;
} BatteryTestApp;

View File

@@ -0,0 +1,11 @@
App(
appid="blink_test",
name="Blink Test",
apptype=FlipperAppType.DEBUG,
entry_point="blink_test_app",
cdefines=["APP_BLINK"],
requires=["gui"],
stack_size=1 * 1024,
order=10,
fap_category="Debug",
)

View File

@@ -0,0 +1,18 @@
App(
appid="bt_debug",
name="Bluetooth Debug",
apptype=FlipperAppType.DEBUG,
entry_point="bt_debug_app",
cdefines=["SRV_BT"],
requires=[
"bt",
"gui",
"dialogs",
],
provides=[
"bt_debug",
],
stack_size=1 * 1024,
order=110,
fap_category="Debug",
)

View File

@@ -9,7 +9,7 @@
#include <gui/modules/submenu.h>
#include "views/bt_carrier_test.h"
#include "views/bt_packet_test.h"
#include "../bt_settings.h"
#include <bt/bt_settings.h>
typedef struct {
BtSettings settings;

View File

@@ -0,0 +1,11 @@
App(
appid="display_test",
name="Display Test",
apptype=FlipperAppType.DEBUG,
entry_point="display_test_app",
cdefines=["APP_DISPLAY_TEST"],
requires=["gui"],
stack_size=1 * 1024,
order=120,
fap_category="Debug",
)

View File

@@ -0,0 +1,11 @@
App(
appid="file_browser_test",
name="File Browser Test",
apptype=FlipperAppType.DEBUG,
entry_point="file_browser_app",
cdefines=["APP_FILE_BROWSER_TEST"],
requires=["gui"],
stack_size=2 * 1024,
order=150,
fap_category="Debug",
)

View File

@@ -0,0 +1,11 @@
App(
appid="keypad_test",
name="Keypad Test",
apptype=FlipperAppType.DEBUG,
entry_point="keypad_test_app",
cdefines=["APP_KEYPAD_TEST"],
requires=["gui"],
stack_size=1 * 1024,
order=30,
fap_category="Debug",
)

View File

@@ -5,8 +5,11 @@ App(
entry_point="lfrfid_debug_app",
requires=[
"gui",
"lfrfid",
],
provides=[
"lfrfid_debug",
],
stack_size=1 * 1024,
order=100,
fap_category="Debug",
)

View File

@@ -9,9 +9,8 @@
#include <gui/modules/submenu.h>
#include <lfrfid_debug/views/lfrfid_debug_view_tune.h>
#include <lfrfid_debug/scenes/lfrfid_debug_scene.h>
#include "views/lfrfid_debug_view_tune.h"
#include "scenes/lfrfid_debug_scene.h"
typedef struct LfRfidDebug LfRfidDebug;

View File

@@ -0,0 +1,11 @@
App(
appid="text_box_test",
name="Text Box Test",
apptype=FlipperAppType.DEBUG,
entry_point="text_box_test_app",
cdefines=["APP_TEXT_BOX_TEST"],
requires=["gui"],
stack_size=1 * 1024,
order=140,
fap_category="Debug",
)

View File

@@ -0,0 +1,11 @@
App(
appid="uart_echo",
name="UART Echo",
apptype=FlipperAppType.DEBUG,
entry_point="uart_echo_app",
cdefines=["APP_UART_ECHO"],
requires=["gui"],
stack_size=2 * 1024,
order=70,
fap_category="Debug",
)

View File

@@ -10,7 +10,7 @@ App(
App(
appid="delay_test",
name="Delay Test",
apptype=FlipperAppType.DEBUG,
apptype=FlipperAppType.SYSTEM,
entry_point="delay_test_app",
stack_size=1 * 1024,
requires=["unit_tests"],

View File

@@ -1,6 +1,6 @@
#include <furi.h>
#include <furi_hal.h>
#include <applications/storage/storage.h>
#include <storage/storage.h>
#include <lib/flipper_format/flipper_format.h>
#include <lib/nfc/protocols/nfca.h>
#include <lib/digital_signal/digital_signal.h>

View File

@@ -0,0 +1,11 @@
App(
appid="usb_mouse",
name="USB Mouse Demo",
apptype=FlipperAppType.DEBUG,
entry_point="usb_mouse_app",
cdefines=["APP_USB_MOUSE"],
requires=["gui"],
stack_size=1 * 1024,
order=60,
fap_category="Debug",
)

View File

@@ -0,0 +1,11 @@
App(
appid="usb_test",
name="USB Test",
apptype=FlipperAppType.DEBUG,
entry_point="usb_test_app",
cdefines=["APP_USB_TEST"],
requires=["gui"],
stack_size=1 * 1024,
order=50,
fap_category="Debug",
)

View File

@@ -0,0 +1,11 @@
App(
appid="vibro_test",
name="Vibro Test",
apptype=FlipperAppType.DEBUG,
entry_point="vibro_test_app",
cdefines=["APP_VIBRO_TEST"],
requires=["gui"],
stack_size=1 * 1024,
order=20,
fap_category="Debug",
)

View File

@@ -1,115 +0,0 @@
App(
appid="debug_apps",
name="Basic debug apps bundle",
apptype=FlipperAppType.METAPACKAGE,
provides=[
"blink_test",
"vibro_test",
"keypad_test",
"usb_test",
"usb_mouse",
"uart_echo",
"display_test",
"text_box_test",
"file_browser_test",
],
)
App(
appid="blink_test",
name="Blink Test",
apptype=FlipperAppType.DEBUG,
entry_point="blink_test_app",
cdefines=["APP_BLINK"],
requires=["gui"],
stack_size=1 * 1024,
order=10,
)
App(
appid="vibro_test",
name="Vibro Test",
apptype=FlipperAppType.DEBUG,
entry_point="vibro_test_app",
cdefines=["APP_VIBRO_TEST"],
requires=["gui"],
stack_size=1 * 1024,
order=20,
)
App(
appid="keypad_test",
name="Keypad Test",
apptype=FlipperAppType.DEBUG,
entry_point="keypad_test_app",
cdefines=["APP_KEYPAD_TEST"],
requires=["gui"],
stack_size=1 * 1024,
order=30,
)
App(
appid="usb_test",
name="USB Test",
apptype=FlipperAppType.DEBUG,
entry_point="usb_test_app",
cdefines=["APP_USB_TEST"],
requires=["gui"],
stack_size=1 * 1024,
order=50,
)
App(
appid="usb_mouse",
name="USB Mouse Demo",
apptype=FlipperAppType.DEBUG,
entry_point="usb_mouse_app",
cdefines=["APP_USB_MOUSE"],
requires=["gui"],
stack_size=1 * 1024,
order=60,
)
App(
appid="uart_echo",
name="UART Echo",
apptype=FlipperAppType.DEBUG,
entry_point="uart_echo_app",
cdefines=["APP_UART_ECHO"],
requires=["gui"],
stack_size=2 * 1024,
order=70,
)
App(
appid="display_test",
name="Display Test",
apptype=FlipperAppType.DEBUG,
entry_point="display_test_app",
cdefines=["APP_DISPLAY_TEST"],
requires=["gui"],
stack_size=1 * 1024,
order=120,
)
App(
appid="text_box_test",
name="Text Box Test",
apptype=FlipperAppType.DEBUG,
entry_point="text_box_test_app",
cdefines=["APP_TEXT_BOX_TEST"],
requires=["gui"],
stack_size=1 * 1024,
order=140,
)
App(
appid="file_browser_test",
name="File Browser Test",
apptype=FlipperAppType.DEBUG,
entry_point="file_browser_app",
cdefines=["APP_FILE_BROWSER_TEST"],
requires=["gui"],
stack_size=2 * 1024,
order=150,
)

View File

@@ -1,58 +0,0 @@
Import("ENV")
from fbt.appmanifest import FlipperAppType
appenv = ENV.Clone(tools=["fbt_extapps"])
appenv.Replace(
LINKER_SCRIPT="application-ext",
STRIPFLAGS=[
"--strip-debug",
"--strip-unneeded",
"-d",
"-g",
"-S",
],
)
appenv.AppendUnique(
CCFLAGS=[
"-Os",
"-ggdb3",
"-mword-relocations",
"-mlong-calls",
"-fno-common",
"-nostdlib",
"-fvisibility=hidden",
],
LINKFLAGS=[
"-r",
"-s",
# "-Bsymbolic",
"-nostartfiles",
"-mlong-calls",
"-fno-common",
"-nostdlib",
"-Wl,--gc-sections",
"-Wl,--no-export-dynamic",
"-fvisibility=hidden",
"-Wl,-e${APP_ENTRY}",
"-Xlinker",
"-Map=${TARGET}.map",
],
)
extapps = []
for apptype in (FlipperAppType.PLUGIN, FlipperAppType.EXTERNAL):
for app in appenv["APPBUILD"].get_apps_of_type(apptype):
extapps.append(appenv.BuildAppElf(app))
# Ugly access to global option
if extra_app_list := GetOption("extra_ext_apps"):
for extra_app in extra_app_list.split(","):
extapps.append(appenv.BuildAppElf(appenv["APPMGR"].get(extra_app)))
Alias(appenv["FIRMWARE_BUILD_CFG"] + "_extapps", extapps)
Return("extapps")

View File

@@ -1,13 +0,0 @@
App(
appid="gui",
name="GuiSrv",
apptype=FlipperAppType.SERVICE,
entry_point="gui_srv",
cdefines=["SRV_GUI"],
requires=[
"input",
"notification",
],
stack_size=2 * 1024,
order=70,
)

View File

@@ -1,131 +0,0 @@
#include "dialog.h"
#include <gui/elements.h>
#include <furi.h>
struct Dialog {
View* view;
void* context;
DialogResultCallback callback;
};
typedef struct {
const char* header_text;
const char* text;
const char* left_text;
const char* right_text;
} DialogModel;
static void dialog_view_draw_callback(Canvas* canvas, void* _model) {
DialogModel* model = _model;
uint8_t canvas_center = canvas_width(canvas) / 2;
// Prepare canvas
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
// Draw header
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(
canvas, canvas_center, 17, AlignCenter, AlignBottom, model->header_text);
// Draw text
canvas_set_font(canvas, FontSecondary);
elements_multiline_text_aligned(
canvas, canvas_center, 32, AlignCenter, AlignCenter, model->text);
// Draw buttons
elements_button_left(canvas, model->left_text);
elements_button_right(canvas, model->right_text);
}
static bool dialog_view_input_callback(InputEvent* event, void* context) {
Dialog* dialog = context;
bool consumed = false;
// Process key presses only
if(event->type == InputTypeShort && dialog->callback) {
if(event->key == InputKeyLeft) {
dialog->callback(DialogResultLeft, dialog->context);
consumed = true;
} else if(event->key == InputKeyRight) {
dialog->callback(DialogResultRight, dialog->context);
consumed = true;
} else if(event->key == InputKeyBack) {
dialog->callback(DialogResultBack, dialog->context);
consumed = true;
}
}
return consumed;
}
Dialog* dialog_alloc() {
Dialog* dialog = malloc(sizeof(Dialog));
dialog->view = view_alloc();
view_set_context(dialog->view, dialog);
view_allocate_model(dialog->view, ViewModelTypeLockFree, sizeof(DialogModel));
view_set_draw_callback(dialog->view, dialog_view_draw_callback);
view_set_input_callback(dialog->view, dialog_view_input_callback);
return dialog;
}
void dialog_free(Dialog* dialog) {
furi_assert(dialog);
view_free(dialog->view);
free(dialog);
}
View* dialog_get_view(Dialog* dialog) {
furi_assert(dialog);
return dialog->view;
}
void dialog_set_result_callback(Dialog* dialog, DialogResultCallback callback) {
furi_assert(dialog);
dialog->callback = callback;
}
void dialog_set_context(Dialog* dialog, void* context) {
furi_assert(dialog);
dialog->context = context;
}
void dialog_set_header_text(Dialog* dialog, const char* text) {
furi_assert(dialog);
furi_assert(text);
with_view_model(
dialog->view, (DialogModel * model) {
model->header_text = text;
return true;
});
}
void dialog_set_text(Dialog* dialog, const char* text) {
furi_assert(dialog);
furi_assert(text);
with_view_model(
dialog->view, (DialogModel * model) {
model->text = text;
return true;
});
}
void dialog_set_left_button_text(Dialog* dialog, const char* text) {
furi_assert(dialog);
furi_assert(text);
with_view_model(
dialog->view, (DialogModel * model) {
model->left_text = text;
return true;
});
}
void dialog_set_right_button_text(Dialog* dialog, const char* text) {
furi_assert(dialog);
furi_assert(text);
with_view_model(
dialog->view, (DialogModel * model) {
model->right_text = text;
return true;
});
}

View File

@@ -1,95 +0,0 @@
/**
* @file dialog.h
* GUI: Dialog view module API
*/
#pragma once
#include <gui/view.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Dialog anonymous structure */
typedef struct Dialog Dialog;
/** Dialog result */
typedef enum {
DialogResultLeft,
DialogResultRight,
DialogResultBack,
} DialogResult;
/** Dialog result callback type
* @warning comes from GUI thread
*/
typedef void (*DialogResultCallback)(DialogResult result, void* context);
/** Allocate and initialize dialog
*
* This dialog used to ask simple questions like Yes/
*
* @return Dialog instance
*/
Dialog* dialog_alloc();
/** Deinitialize and free dialog
*
* @param dialog Dialog instance
*/
void dialog_free(Dialog* dialog);
/** Get dialog view
*
* @param dialog Dialog instance
*
* @return View instance that can be used for embedding
*/
View* dialog_get_view(Dialog* dialog);
/** Set dialog result callback
*
* @param dialog Dialog instance
* @param callback result callback function
*/
void dialog_set_result_callback(Dialog* dialog, DialogResultCallback callback);
/** Set dialog context
*
* @param dialog Dialog instance
* @param context context pointer, will be passed to result callback
*/
void dialog_set_context(Dialog* dialog, void* context);
/** Set dialog header text
*
* @param dialog Dialog instance
* @param text text to be shown
*/
void dialog_set_header_text(Dialog* dialog, const char* text);
/** Set dialog text
*
* @param dialog Dialog instance
* @param text text to be shown
*/
void dialog_set_text(Dialog* dialog, const char* text);
/** Set left button text
*
* @param dialog Dialog instance
* @param text text to be shown
*/
void dialog_set_left_button_text(Dialog* dialog, const char* text);
/** Set right button text
*
* @param dialog Dialog instance
* @param text text to be shown
*/
void dialog_set_right_button_text(Dialog* dialog, const char* text);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,17 @@
App(
appid="main_apps",
name="Basic applications for main menu",
apptype=FlipperAppType.METAPACKAGE,
provides=[
"gpio",
"ibutton",
"infrared",
"lfrfid",
"nfc",
"subghz",
"bad_usb",
"u2f",
"fap_loader",
"archive",
],
)

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