[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

@@ -0,0 +1,140 @@
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include <stddef.h>
#include <furi.h>
#include <furi_hal.h>
#include <gui/gui.h>
#include "../helpers/pin_lock.h"
#include "../desktop_i.h"
#include <cli/cli.h>
#include <cli/cli_vcp.h>
static const NotificationSequence sequence_pin_fail = {
&message_display_backlight_on,
&message_red_255,
&message_vibro_on,
&message_delay_100,
&message_vibro_off,
&message_red_0,
&message_delay_250,
&message_red_255,
&message_vibro_on,
&message_delay_100,
&message_vibro_off,
&message_red_0,
NULL,
};
static const uint8_t desktop_helpers_fails_timeout[] = {
0,
0,
0,
0,
30,
60,
90,
120,
150,
180,
/* +60 for every next fail */
};
void desktop_pin_lock_error_notify() {
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
notification_message(notification, &sequence_pin_fail);
furi_record_close(RECORD_NOTIFICATION);
}
uint32_t desktop_pin_lock_get_fail_timeout() {
uint32_t pin_fails = furi_hal_rtc_get_pin_fails();
uint32_t pin_timeout = 0;
uint32_t max_index = COUNT_OF(desktop_helpers_fails_timeout) - 1;
if(pin_fails <= max_index) {
pin_timeout = desktop_helpers_fails_timeout[pin_fails];
} else {
pin_timeout = desktop_helpers_fails_timeout[max_index] + (pin_fails - max_index) * 60;
}
return pin_timeout;
}
void desktop_pin_lock(DesktopSettings* settings) {
furi_assert(settings);
furi_hal_rtc_set_pin_fails(0);
furi_hal_rtc_set_flag(FuriHalRtcFlagLock);
Cli* cli = furi_record_open(RECORD_CLI);
cli_session_close(cli);
furi_record_close(RECORD_CLI);
settings->is_locked = 1;
SAVE_DESKTOP_SETTINGS(settings);
}
void desktop_pin_unlock(DesktopSettings* settings) {
furi_assert(settings);
furi_hal_rtc_reset_flag(FuriHalRtcFlagLock);
Cli* cli = furi_record_open(RECORD_CLI);
cli_session_open(cli, &cli_vcp);
furi_record_close(RECORD_CLI);
settings->is_locked = 0;
SAVE_DESKTOP_SETTINGS(settings);
}
void desktop_pin_lock_init(DesktopSettings* settings) {
furi_assert(settings);
if(settings->pin_code.length > 0) {
if(settings->is_locked == 1) {
furi_hal_rtc_set_flag(FuriHalRtcFlagLock);
} else {
if(desktop_pin_lock_is_locked()) {
settings->is_locked = 1;
SAVE_DESKTOP_SETTINGS(settings);
}
}
} else {
furi_hal_rtc_set_pin_fails(0);
furi_hal_rtc_reset_flag(FuriHalRtcFlagLock);
}
if(desktop_pin_lock_is_locked()) {
Cli* cli = furi_record_open(RECORD_CLI);
cli_session_close(cli);
furi_record_close(RECORD_CLI);
}
}
bool desktop_pin_lock_verify(const PinCode* pin_set, const PinCode* pin_entered) {
bool result = false;
if(desktop_pins_are_equal(pin_set, pin_entered)) {
furi_hal_rtc_set_pin_fails(0);
result = true;
} else {
uint32_t pin_fails = furi_hal_rtc_get_pin_fails();
furi_hal_rtc_set_pin_fails(pin_fails + 1);
result = false;
}
return result;
}
bool desktop_pin_lock_is_locked() {
return furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock);
}
bool desktop_pins_are_equal(const PinCode* pin_code1, const PinCode* pin_code2) {
furi_assert(pin_code1);
furi_assert(pin_code2);
bool result = false;
if(pin_code1->length == pin_code2->length) {
result = !memcmp(pin_code1->data, pin_code2->data, pin_code1->length);
}
return result;
}

View File

@@ -0,0 +1,21 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "../desktop.h"
#include <desktop/desktop_settings.h>
void desktop_pin_lock_error_notify();
uint32_t desktop_pin_lock_get_fail_timeout();
void desktop_pin_lock(DesktopSettings* settings);
void desktop_pin_unlock(DesktopSettings* settings);
bool desktop_pin_lock_is_locked();
void desktop_pin_lock_init(DesktopSettings* settings);
bool desktop_pin_lock_verify(const PinCode* pin_set, const PinCode* pin_entered);
bool desktop_pins_are_equal(const PinCode* pin_code1, const PinCode* pin_code2);

View File

@@ -0,0 +1,125 @@
#include "slideshow.h"
#include <stddef.h>
#include <storage/storage.h>
#include <gui/icon.h>
#include <gui/icon_i.h>
#include <core/dangerous_defines.h>
#define SLIDESHOW_MAGIC 0x72676468
#define SLIDESHOW_MAX_SUPPORTED_VERSION 1
struct Slideshow {
Icon icon;
uint32_t current_frame;
bool loaded;
};
#pragma pack(push, 1)
typedef struct {
uint32_t magic;
uint8_t version;
uint8_t width;
uint8_t height;
uint8_t frame_count;
} SlideshowFileHeader;
_Static_assert(sizeof(SlideshowFileHeader) == 8, "Incorrect SlideshowFileHeader size");
typedef struct {
uint16_t size;
} SlideshowFrameHeader;
_Static_assert(sizeof(SlideshowFrameHeader) == 2, "Incorrect SlideshowFrameHeader size");
#pragma pack(pop)
Slideshow* slideshow_alloc() {
Slideshow* ret = malloc(sizeof(Slideshow));
ret->loaded = false;
return ret;
}
void slideshow_free(Slideshow* slideshow) {
Icon* icon = &slideshow->icon;
if(icon) {
for(int frame_idx = 0; frame_idx < icon->frame_count; ++frame_idx) {
uint8_t* frame_data = (uint8_t*)icon->frames[frame_idx];
free(frame_data);
}
free((uint8_t**)icon->frames);
}
free(slideshow);
}
bool slideshow_load(Slideshow* slideshow, const char* fspath) {
Storage* storage = furi_record_open(RECORD_STORAGE);
File* slideshow_file = storage_file_alloc(storage);
slideshow->loaded = false;
do {
if(!storage_file_open(slideshow_file, fspath, FSAM_READ, FSOM_OPEN_EXISTING)) {
break;
}
SlideshowFileHeader header;
if((storage_file_read(slideshow_file, &header, sizeof(header)) != sizeof(header)) ||
(header.magic != SLIDESHOW_MAGIC) ||
(header.version > SLIDESHOW_MAX_SUPPORTED_VERSION)) {
break;
}
Icon* icon = &slideshow->icon;
FURI_CONST_ASSIGN(icon->frame_count, header.frame_count);
FURI_CONST_ASSIGN(icon->width, header.width);
FURI_CONST_ASSIGN(icon->height, header.height);
icon->frames = malloc(header.frame_count * sizeof(uint8_t*));
for(int frame_idx = 0; frame_idx < header.frame_count; ++frame_idx) {
SlideshowFrameHeader frame_header;
if(storage_file_read(slideshow_file, &frame_header, sizeof(frame_header)) !=
sizeof(frame_header)) {
break;
}
FURI_CONST_ASSIGN_PTR(icon->frames[frame_idx], malloc(frame_header.size));
uint8_t* frame_data = (uint8_t*)icon->frames[frame_idx];
if(storage_file_read(slideshow_file, frame_data, frame_header.size) !=
frame_header.size) {
break;
}
slideshow->loaded = (frame_idx + 1) == header.frame_count;
}
} while(false);
storage_file_free(slideshow_file);
furi_record_close(RECORD_STORAGE);
return slideshow->loaded;
}
bool slideshow_is_loaded(Slideshow* slideshow) {
return slideshow->loaded;
}
bool slideshow_is_one_page(Slideshow* slideshow) {
return slideshow->loaded && (slideshow->icon.frame_count == 1);
}
bool slideshow_advance(Slideshow* slideshow) {
uint8_t next_frame = slideshow->current_frame + 1;
if(next_frame < slideshow->icon.frame_count) {
slideshow->current_frame = next_frame;
return true;
}
return false;
}
void slideshow_goback(Slideshow* slideshow) {
if(slideshow->current_frame > 0) {
slideshow->current_frame--;
}
}
void slideshow_draw(Slideshow* slideshow, Canvas* canvas, uint8_t x, uint8_t y) {
furi_assert(slideshow->current_frame < slideshow->icon.frame_count);
canvas_draw_bitmap(
canvas,
x,
y,
slideshow->icon.width,
slideshow->icon.height,
slideshow->icon.frames[slideshow->current_frame]);
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include <gui/canvas.h>
typedef struct Slideshow Slideshow;
Slideshow* slideshow_alloc();
void slideshow_free(Slideshow* slideshow);
bool slideshow_load(Slideshow* slideshow, const char* fspath);
bool slideshow_is_loaded(Slideshow* slideshow);
bool slideshow_is_one_page(Slideshow* slideshow);
void slideshow_goback(Slideshow* slideshow);
bool slideshow_advance(Slideshow* slideshow);
void slideshow_draw(Slideshow* slideshow, Canvas* canvas, uint8_t x, uint8_t y);

View File

@@ -0,0 +1,3 @@
#pragma once
#define SLIDESHOW_FILE_NAME ".slideshow"