[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,30 @@
#include "desktop_scene.h"
// Generate scene on_enter handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
void (*const desktop_on_enter_handlers[])(void*) = {
#include "desktop_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_event handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
bool (*const desktop_on_event_handlers[])(void* context, SceneManagerEvent event) = {
#include "desktop_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_exit handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
void (*const desktop_on_exit_handlers[])(void* context) = {
#include "desktop_scene_config.h"
};
#undef ADD_SCENE
// Initialize scene handlers configuration structure
const SceneManagerHandlers desktop_scene_handlers = {
.on_enter_handlers = desktop_on_enter_handlers,
.on_event_handlers = desktop_on_event_handlers,
.on_exit_handlers = desktop_on_exit_handlers,
.scene_num = DesktopSceneNum,
};

View File

@@ -0,0 +1,29 @@
#pragma once
#include <gui/scene_manager.h>
// Generate scene id and total number
#define ADD_SCENE(prefix, name, id) DesktopScene##id,
typedef enum {
#include "desktop_scene_config.h"
DesktopSceneNum,
} DesktopScene;
#undef ADD_SCENE
extern const SceneManagerHandlers desktop_scene_handlers;
// Generate scene on_enter handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
#include "desktop_scene_config.h"
#undef ADD_SCENE
// Generate scene on_event handlers declaration
#define ADD_SCENE(prefix, name, id) \
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
#include "desktop_scene_config.h"
#undef ADD_SCENE
// Generate scene on_exit handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
#include "desktop_scene_config.h"
#undef ADD_SCENE

View File

@@ -0,0 +1,9 @@
ADD_SCENE(desktop, main, Main)
ADD_SCENE(desktop, lock_menu, LockMenu)
ADD_SCENE(desktop, debug, Debug)
ADD_SCENE(desktop, hw_mismatch, HwMismatch)
ADD_SCENE(desktop, fault, Fault)
ADD_SCENE(desktop, locked, Locked)
ADD_SCENE(desktop, pin_input, PinInput)
ADD_SCENE(desktop, pin_timeout, PinTimeout)
ADD_SCENE(desktop, slideshow, Slideshow)

View File

@@ -0,0 +1,65 @@
#include <dolphin/dolphin.h>
#include <dolphin/helpers/dolphin_deed.h>
#include "../desktop_i.h"
#include "../views/desktop_view_debug.h"
#include "desktop_scene.h"
void desktop_scene_debug_callback(DesktopEvent event, void* context) {
Desktop* desktop = (Desktop*)context;
view_dispatcher_send_custom_event(desktop->view_dispatcher, event);
}
void desktop_scene_debug_on_enter(void* context) {
Desktop* desktop = (Desktop*)context;
desktop_debug_get_dolphin_data(desktop->debug_view);
desktop_debug_set_callback(desktop->debug_view, desktop_scene_debug_callback, desktop);
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdDebug);
}
bool desktop_scene_debug_on_event(void* context, SceneManagerEvent event) {
Desktop* desktop = (Desktop*)context;
Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case DesktopDebugEventExit:
scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain);
dolphin_flush(dolphin);
consumed = true;
break;
case DesktopDebugEventDeed:
dolphin_deed(dolphin, DolphinDeedTestRight);
desktop_debug_get_dolphin_data(desktop->debug_view);
consumed = true;
break;
case DesktopDebugEventWrongDeed:
dolphin_deed(dolphin, DolphinDeedTestLeft);
desktop_debug_get_dolphin_data(desktop->debug_view);
consumed = true;
break;
case DesktopDebugEventSaveState:
dolphin_flush(dolphin);
consumed = true;
break;
default:
break;
}
}
furi_record_close(RECORD_DOLPHIN);
return consumed;
}
void desktop_scene_debug_on_exit(void* context) {
Desktop* desktop = (Desktop*)context;
desktop_debug_reset_screen_idx(desktop->debug_view);
}

View File

@@ -0,0 +1,52 @@
#include <furi_hal.h>
#include "../desktop_i.h"
#define DesktopFaultEventExit 0x00FF00FF
void desktop_scene_fault_callback(void* context) {
Desktop* desktop = (Desktop*)context;
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopFaultEventExit);
}
void desktop_scene_fault_on_enter(void* context) {
Desktop* desktop = (Desktop*)context;
Popup* popup = desktop->hw_mismatch_popup;
popup_set_context(popup, desktop);
popup_set_header(
popup,
"Flipper crashed\n and was rebooted",
60,
14 + STATUS_BAR_Y_SHIFT,
AlignCenter,
AlignCenter);
char* message = (char*)furi_hal_rtc_get_fault_data();
popup_set_text(popup, message, 60, 37 + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter);
popup_set_callback(popup, desktop_scene_fault_callback);
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdHwMismatch);
}
bool desktop_scene_fault_on_event(void* context, SceneManagerEvent event) {
Desktop* desktop = (Desktop*)context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case DesktopFaultEventExit:
scene_manager_previous_scene(desktop->scene_manager);
consumed = true;
break;
default:
break;
}
}
return consumed;
}
void desktop_scene_fault_on_exit(void* context) {
UNUSED(context);
furi_hal_rtc_set_fault_data(0);
}

View File

@@ -0,0 +1,67 @@
#include <gui/scene_manager.h>
#include <furi_hal.h>
#include "desktop_scene.h"
#include "../desktop_i.h"
#define HW_MISMATCH_BACK_EVENT (0UL)
void desktop_scene_hw_mismatch_callback(void* context) {
Desktop* desktop = (Desktop*)context;
view_dispatcher_send_custom_event(desktop->view_dispatcher, HW_MISMATCH_BACK_EVENT);
}
void desktop_scene_hw_mismatch_on_enter(void* context) {
Desktop* desktop = (Desktop*)context;
furi_assert(desktop);
Popup* popup = desktop->hw_mismatch_popup;
char* text_buffer = malloc(256);
scene_manager_set_scene_state(
desktop->scene_manager, DesktopSceneHwMismatch, (uint32_t)text_buffer);
snprintf(
text_buffer,
256,
"HW target: %d\nFW target: %d",
furi_hal_version_get_hw_target(),
version_get_target(NULL));
popup_set_context(popup, desktop);
popup_set_header(
popup, "!!!! HW Mismatch !!!!", 60, 14 + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter);
popup_set_text(popup, text_buffer, 60, 37 + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter);
popup_set_callback(popup, desktop_scene_hw_mismatch_callback);
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdHwMismatch);
}
bool desktop_scene_hw_mismatch_on_event(void* context, SceneManagerEvent event) {
Desktop* desktop = (Desktop*)context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case HW_MISMATCH_BACK_EVENT:
scene_manager_previous_scene(desktop->scene_manager);
consumed = true;
break;
default:
break;
}
}
return consumed;
}
void desktop_scene_hw_mismatch_on_exit(void* context) {
Desktop* desktop = (Desktop*)context;
furi_assert(desktop);
Popup* popup = desktop->hw_mismatch_popup;
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_callback(popup, NULL);
popup_set_context(popup, NULL);
char* text_buffer =
(char*)scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneHwMismatch);
free(text_buffer);
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneHwMismatch, 0);
}

View File

@@ -0,0 +1,4 @@
#pragma once
#define SCENE_LOCKED_FIRST_ENTER 0
#define SCENE_LOCKED_REPEAT_ENTER 1

View File

@@ -0,0 +1,85 @@
#include <gui/scene_manager.h>
#include <applications.h>
#include <furi_hal.h>
#include <toolbox/saved_struct.h>
#include <stdbool.h>
#include <loader/loader.h>
#include "../desktop_i.h"
#include <desktop/desktop_settings.h>
#include "../views/desktop_view_lock_menu.h"
#include "desktop_scene_i.h"
#include "desktop_scene.h"
#include "../helpers/pin_lock.h"
#define TAG "DesktopSceneLock"
void desktop_scene_lock_menu_callback(DesktopEvent event, void* context) {
Desktop* desktop = (Desktop*)context;
view_dispatcher_send_custom_event(desktop->view_dispatcher, event);
}
void desktop_scene_lock_menu_on_enter(void* context) {
Desktop* desktop = (Desktop*)context;
LOAD_DESKTOP_SETTINGS(&desktop->settings);
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0);
desktop_lock_menu_set_callback(desktop->lock_menu, desktop_scene_lock_menu_callback, desktop);
desktop_lock_menu_pin_set(desktop->lock_menu, desktop->settings.pin_code.length > 0);
desktop_lock_menu_set_idx(desktop->lock_menu, 0);
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdLockMenu);
}
bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) {
Desktop* desktop = (Desktop*)context;
bool consumed = false;
if(event.type == SceneManagerEventTypeTick) {
bool check_pin_changed =
scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneLockMenu);
if(check_pin_changed) {
LOAD_DESKTOP_SETTINGS(&desktop->settings);
if(desktop->settings.pin_code.length > 0) {
desktop_lock_menu_pin_set(desktop->lock_menu, 1);
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0);
}
}
} else if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case DesktopLockMenuEventLock:
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0);
desktop_lock(desktop);
consumed = true;
break;
case DesktopLockMenuEventPinLock:
if(desktop->settings.pin_code.length > 0) {
desktop_pin_lock(&desktop->settings);
desktop_lock(desktop);
} else {
LoaderStatus status =
loader_start(desktop->loader, "Desktop", DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG);
if(status == LoaderStatusOk) {
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 1);
} else {
FURI_LOG_E(TAG, "Unable to start desktop settings");
}
}
consumed = true;
break;
case DesktopLockMenuEventExit:
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0);
scene_manager_search_and_switch_to_previous_scene(
desktop->scene_manager, DesktopSceneMain);
consumed = true;
break;
default:
break;
}
}
return consumed;
}
void desktop_scene_lock_menu_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -0,0 +1,113 @@
#include <furi.h>
#include <furi_hal.h>
#include <gui/scene_manager.h>
#include <gui/view_stack.h>
#include <stdint.h>
#include <portmacro.h>
#include "../desktop.h"
#include "../desktop_i.h"
#include "../helpers/pin_lock.h"
#include "../animations/animation_manager.h"
#include "../views/desktop_events.h"
#include "../views/desktop_view_pin_input.h"
#include "../views/desktop_view_locked.h"
#include "desktop_scene.h"
#include "desktop_scene_i.h"
#define WRONG_PIN_HEADER_TIMEOUT 3000
#define INPUT_PIN_VIEW_TIMEOUT 15000
static void desktop_scene_locked_callback(DesktopEvent event, void* context) {
Desktop* desktop = (Desktop*)context;
view_dispatcher_send_custom_event(desktop->view_dispatcher, event);
}
static void desktop_scene_locked_new_idle_animation_callback(void* context) {
furi_assert(context);
Desktop* desktop = context;
view_dispatcher_send_custom_event(
desktop->view_dispatcher, DesktopAnimationEventNewIdleAnimation);
}
void desktop_scene_locked_on_enter(void* context) {
Desktop* desktop = (Desktop*)context;
// callbacks for 1-st layer
animation_manager_set_new_idle_callback(
desktop->animation_manager, desktop_scene_locked_new_idle_animation_callback);
animation_manager_set_check_callback(desktop->animation_manager, NULL);
animation_manager_set_interact_callback(desktop->animation_manager, NULL);
// callbacks for 2-nd layer
desktop_view_locked_set_callback(desktop->locked_view, desktop_scene_locked_callback, desktop);
bool switch_to_timeout_scene = false;
uint32_t state = scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneLocked);
if(state == SCENE_LOCKED_FIRST_ENTER) {
bool pin_locked = desktop_pin_lock_is_locked();
view_port_enabled_set(desktop->lock_viewport, true);
Gui* gui = furi_record_open(RECORD_GUI);
gui_set_lockdown(gui, true);
furi_record_close(RECORD_GUI);
if(pin_locked) {
LOAD_DESKTOP_SETTINGS(&desktop->settings);
desktop_view_locked_lock(desktop->locked_view, true);
uint32_t pin_timeout = desktop_pin_lock_get_fail_timeout();
if(pin_timeout > 0) {
scene_manager_set_scene_state(
desktop->scene_manager, DesktopScenePinTimeout, pin_timeout);
switch_to_timeout_scene = true;
} else {
desktop_view_locked_close_doors(desktop->locked_view);
}
} else {
desktop_view_locked_lock(desktop->locked_view, false);
desktop_view_locked_close_doors(desktop->locked_view);
}
scene_manager_set_scene_state(
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_REPEAT_ENTER);
}
if(switch_to_timeout_scene) {
scene_manager_next_scene(desktop->scene_manager, DesktopScenePinTimeout);
} else {
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdLocked);
}
}
bool desktop_scene_locked_on_event(void* context, SceneManagerEvent event) {
Desktop* desktop = (Desktop*)context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case DesktopLockedEventUnlocked:
desktop_unlock(desktop);
consumed = true;
break;
case DesktopLockedEventUpdate:
if(desktop_view_locked_is_locked_hint_visible(desktop->locked_view)) {
notification_message(desktop->notification, &sequence_display_backlight_off);
}
desktop_view_locked_update(desktop->locked_view);
consumed = true;
break;
case DesktopLockedEventShowPinInput:
scene_manager_next_scene(desktop->scene_manager, DesktopScenePinInput);
consumed = true;
break;
case DesktopAnimationEventNewIdleAnimation:
animation_manager_new_idle_process(desktop->animation_manager);
consumed = true;
break;
}
}
return consumed;
}
void desktop_scene_locked_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -0,0 +1,180 @@
#include <furi.h>
#include <furi_hal.h>
#include <applications.h>
#include <assets_icons.h>
#include <loader/loader.h>
#include "../desktop_i.h"
#include "../views/desktop_events.h"
#include "../views/desktop_view_main.h"
#include "desktop_scene.h"
#include "desktop_scene_i.h"
#define TAG "DesktopSrv"
static void desktop_scene_main_new_idle_animation_callback(void* context) {
furi_assert(context);
Desktop* desktop = context;
view_dispatcher_send_custom_event(
desktop->view_dispatcher, DesktopAnimationEventNewIdleAnimation);
}
static void desktop_scene_main_check_animation_callback(void* context) {
furi_assert(context);
Desktop* desktop = context;
view_dispatcher_send_custom_event(
desktop->view_dispatcher, DesktopAnimationEventCheckAnimation);
}
static void desktop_scene_main_interact_animation_callback(void* context) {
furi_assert(context);
Desktop* desktop = context;
view_dispatcher_send_custom_event(
desktop->view_dispatcher, DesktopAnimationEventInteractAnimation);
}
#ifdef APP_ARCHIVE
static void desktop_switch_to_app(Desktop* desktop, const FlipperApplication* flipper_app) {
furi_assert(desktop);
furi_assert(flipper_app);
furi_assert(flipper_app->app);
furi_assert(flipper_app->name);
if(furi_thread_get_state(desktop->scene_thread) != FuriThreadStateStopped) {
FURI_LOG_E("Desktop", "Thread is already running");
return;
}
furi_thread_set_name(desktop->scene_thread, flipper_app->name);
furi_thread_set_stack_size(desktop->scene_thread, flipper_app->stack_size);
furi_thread_set_callback(desktop->scene_thread, flipper_app->app);
furi_thread_start(desktop->scene_thread);
}
#endif
void desktop_scene_main_callback(DesktopEvent event, void* context) {
Desktop* desktop = (Desktop*)context;
view_dispatcher_send_custom_event(desktop->view_dispatcher, event);
}
void desktop_scene_main_on_enter(void* context) {
Desktop* desktop = (Desktop*)context;
DesktopMainView* main_view = desktop->main_view;
animation_manager_set_context(desktop->animation_manager, desktop);
animation_manager_set_new_idle_callback(
desktop->animation_manager, desktop_scene_main_new_idle_animation_callback);
animation_manager_set_check_callback(
desktop->animation_manager, desktop_scene_main_check_animation_callback);
animation_manager_set_interact_callback(
desktop->animation_manager, desktop_scene_main_interact_animation_callback);
desktop_main_set_callback(main_view, desktop_scene_main_callback, desktop);
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdMain);
}
bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) {
Desktop* desktop = (Desktop*)context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case DesktopMainEventOpenMenu:
loader_show_menu();
consumed = true;
break;
case DesktopMainEventOpenLockMenu:
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLockMenu);
consumed = true;
break;
case DesktopMainEventOpenDebug:
scene_manager_next_scene(desktop->scene_manager, DesktopSceneDebug);
consumed = true;
break;
case DesktopMainEventOpenArchive:
#ifdef APP_ARCHIVE
desktop_switch_to_app(desktop, &FLIPPER_ARCHIVE);
#endif
consumed = true;
break;
case DesktopMainEventOpenPowerOff: {
LoaderStatus status = loader_start(desktop->loader, "Power", "off");
if(status != LoaderStatusOk) {
FURI_LOG_E(TAG, "loader_start failed: %d", status);
}
consumed = true;
break;
}
case DesktopMainEventOpenFavoritePrimary:
LOAD_DESKTOP_SETTINGS(&desktop->settings);
if(desktop->settings.favorite_primary < FLIPPER_APPS_COUNT) {
LoaderStatus status = loader_start(
desktop->loader, FLIPPER_APPS[desktop->settings.favorite_primary].name, NULL);
if(status != LoaderStatusOk) {
FURI_LOG_E(TAG, "loader_start failed: %d", status);
}
} else {
FURI_LOG_E(TAG, "Can't find primary favorite application");
}
consumed = true;
break;
case DesktopMainEventOpenFavoriteSecondary:
LOAD_DESKTOP_SETTINGS(&desktop->settings);
if(desktop->settings.favorite_secondary < FLIPPER_APPS_COUNT) {
LoaderStatus status = loader_start(
desktop->loader,
FLIPPER_APPS[desktop->settings.favorite_secondary].name,
NULL);
if(status != LoaderStatusOk) {
FURI_LOG_E(TAG, "loader_start failed: %d", status);
}
} else {
FURI_LOG_E(TAG, "Can't find secondary favorite application");
}
consumed = true;
break;
case DesktopAnimationEventCheckAnimation:
animation_manager_check_blocking_process(desktop->animation_manager);
consumed = true;
break;
case DesktopAnimationEventNewIdleAnimation:
animation_manager_new_idle_process(desktop->animation_manager);
consumed = true;
break;
case DesktopAnimationEventInteractAnimation:
if(!animation_manager_interact_process(desktop->animation_manager)) {
LoaderStatus status = loader_start(desktop->loader, "Passport", NULL);
if(status != LoaderStatusOk) {
FURI_LOG_E(TAG, "loader_start failed: %d", status);
}
}
consumed = true;
break;
case DesktopLockedEventUpdate:
desktop_view_locked_update(desktop->locked_view);
consumed = true;
break;
default:
break;
}
}
return consumed;
}
void desktop_scene_main_on_exit(void* context) {
Desktop* desktop = (Desktop*)context;
animation_manager_set_new_idle_callback(desktop->animation_manager, NULL);
animation_manager_set_check_callback(desktop->animation_manager, NULL);
animation_manager_set_interact_callback(desktop->animation_manager, NULL);
animation_manager_set_context(desktop->animation_manager, desktop);
}

View File

@@ -0,0 +1,157 @@
#include <furi.h>
#include <furi_hal.h>
#include <gui/scene_manager.h>
#include <gui/view_stack.h>
#include <stdint.h>
#include <portmacro.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include "../desktop.h"
#include "../desktop_i.h"
#include "../animations/animation_manager.h"
#include "../views/desktop_events.h"
#include "../views/desktop_view_pin_input.h"
#include "../helpers/pin_lock.h"
#include "desktop_scene.h"
#include "desktop_scene_i.h"
#define WRONG_PIN_HEADER_TIMEOUT 3000
#define INPUT_PIN_VIEW_TIMEOUT 15000
typedef struct {
TimerHandle_t timer;
} DesktopScenePinInputState;
static void desktop_scene_locked_light_red(bool value) {
NotificationApp* app = furi_record_open(RECORD_NOTIFICATION);
if(value) {
notification_message(app, &sequence_set_only_red_255);
} else {
notification_message(app, &sequence_reset_red);
}
furi_record_close(RECORD_NOTIFICATION);
}
static void
desktop_scene_pin_input_set_timer(Desktop* desktop, bool enable, TickType_t new_period) {
furi_assert(desktop);
DesktopScenePinInputState* state = (DesktopScenePinInputState*)scene_manager_get_scene_state(
desktop->scene_manager, DesktopScenePinInput);
furi_assert(state);
if(enable) {
xTimerChangePeriod(state->timer, new_period, portMAX_DELAY);
} else {
xTimerStop(state->timer, portMAX_DELAY);
}
}
static void desktop_scene_pin_input_back_callback(void* context) {
Desktop* desktop = (Desktop*)context;
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopPinInputEventBack);
}
static void desktop_scene_pin_input_done_callback(const PinCode* pin_code, void* context) {
Desktop* desktop = (Desktop*)context;
if(desktop_pin_lock_verify(&desktop->settings.pin_code, pin_code)) {
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopPinInputEventUnlocked);
} else {
view_dispatcher_send_custom_event(
desktop->view_dispatcher, DesktopPinInputEventUnlockFailed);
}
}
static void desktop_scene_pin_input_timer_callback(TimerHandle_t timer) {
Desktop* desktop = pvTimerGetTimerID(timer);
view_dispatcher_send_custom_event(
desktop->view_dispatcher, DesktopPinInputEventResetWrongPinLabel);
}
void desktop_scene_pin_input_on_enter(void* context) {
Desktop* desktop = (Desktop*)context;
desktop_view_pin_input_set_context(desktop->pin_input_view, desktop);
desktop_view_pin_input_set_back_callback(
desktop->pin_input_view, desktop_scene_pin_input_back_callback);
desktop_view_pin_input_set_timeout_callback(
desktop->pin_input_view, desktop_scene_pin_input_back_callback);
desktop_view_pin_input_set_done_callback(
desktop->pin_input_view, desktop_scene_pin_input_done_callback);
DesktopScenePinInputState* state = malloc(sizeof(DesktopScenePinInputState));
state->timer =
xTimerCreate(NULL, 10000, pdFALSE, desktop, desktop_scene_pin_input_timer_callback);
scene_manager_set_scene_state(desktop->scene_manager, DesktopScenePinInput, (uint32_t)state);
desktop_view_pin_input_hide_pin(desktop->pin_input_view, true);
desktop_view_pin_input_set_label_button(desktop->pin_input_view, "OK");
desktop_view_pin_input_set_label_secondary(desktop->pin_input_view, 44, 25, "Enter PIN:");
desktop_view_pin_input_set_pin_position(desktop->pin_input_view, 64, 37);
desktop_view_pin_input_reset_pin(desktop->pin_input_view);
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdPinInput);
}
bool desktop_scene_pin_input_on_event(void* context, SceneManagerEvent event) {
Desktop* desktop = (Desktop*)context;
bool consumed = false;
uint32_t pin_timeout = 0;
if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case DesktopPinInputEventUnlockFailed:
pin_timeout = desktop_pin_lock_get_fail_timeout();
if(pin_timeout > 0) {
desktop_pin_lock_error_notify();
scene_manager_set_scene_state(
desktop->scene_manager, DesktopScenePinTimeout, pin_timeout);
scene_manager_next_scene(desktop->scene_manager, DesktopScenePinTimeout);
} else {
desktop_scene_locked_light_red(true);
desktop_view_pin_input_set_label_primary(desktop->pin_input_view, 0, 0, NULL);
desktop_view_pin_input_set_label_secondary(
desktop->pin_input_view, 25, 25, "Wrong PIN try again:");
desktop_scene_pin_input_set_timer(desktop, true, WRONG_PIN_HEADER_TIMEOUT);
desktop_view_pin_input_reset_pin(desktop->pin_input_view);
}
consumed = true;
break;
case DesktopPinInputEventResetWrongPinLabel:
desktop_scene_locked_light_red(false);
desktop_view_pin_input_set_label_primary(desktop->pin_input_view, 0, 0, NULL);
desktop_view_pin_input_set_label_secondary(
desktop->pin_input_view, 44, 25, "Enter PIN:");
consumed = true;
break;
case DesktopPinInputEventUnlocked:
desktop_pin_unlock(&desktop->settings);
desktop_unlock(desktop);
consumed = true;
break;
case DesktopPinInputEventBack:
scene_manager_search_and_switch_to_previous_scene(
desktop->scene_manager, DesktopSceneLocked);
notification_message(desktop->notification, &sequence_display_backlight_off);
consumed = true;
break;
}
}
return consumed;
}
void desktop_scene_pin_input_on_exit(void* context) {
Desktop* desktop = (Desktop*)context;
desktop_scene_locked_light_red(false);
DesktopScenePinInputState* state = (DesktopScenePinInputState*)scene_manager_get_scene_state(
desktop->scene_manager, DesktopScenePinInput);
xTimerStop(state->timer, portMAX_DELAY);
while(xTimerIsTimerActive(state->timer)) {
furi_delay_tick(1);
}
xTimerDelete(state->timer, portMAX_DELAY);
free(state);
}

View File

@@ -0,0 +1,47 @@
#include <furi.h>
#include <FreeRTOS.h>
#include <portmacro.h>
#include <timer.h>
#include <gui/scene_manager.h>
#include "../desktop_i.h"
#include "../views/desktop_view_pin_timeout.h"
#include "desktop_scene.h"
#include "desktop_scene_i.h"
static void desktop_scene_pin_timeout_callback(void* context) {
Desktop* desktop = (Desktop*)context;
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopPinTimeoutExit);
}
void desktop_scene_pin_timeout_on_enter(void* context) {
Desktop* desktop = (Desktop*)context;
uint32_t timeout =
scene_manager_get_scene_state(desktop->scene_manager, DesktopScenePinTimeout);
desktop_view_pin_timeout_start(desktop->pin_timeout_view, timeout);
desktop_view_pin_timeout_set_callback(
desktop->pin_timeout_view, desktop_scene_pin_timeout_callback, desktop);
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdPinTimeout);
}
bool desktop_scene_pin_timeout_on_event(void* context, SceneManagerEvent event) {
Desktop* desktop = (Desktop*)context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case DesktopPinTimeoutExit:
scene_manager_previous_scene(desktop->scene_manager);
consumed = true;
break;
}
}
return consumed;
}
void desktop_scene_pin_timeout_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -0,0 +1,53 @@
#include <storage/storage.h>
#include "../desktop_i.h"
#include "../views/desktop_view_slideshow.h"
#include "../views/desktop_events.h"
#include <power/power_service/power.h>
void desktop_scene_slideshow_callback(DesktopEvent event, void* context) {
Desktop* desktop = (Desktop*)context;
view_dispatcher_send_custom_event(desktop->view_dispatcher, event);
}
void desktop_scene_slideshow_on_enter(void* context) {
Desktop* desktop = (Desktop*)context;
DesktopSlideshowView* slideshow_view = desktop->slideshow_view;
desktop_view_slideshow_set_callback(slideshow_view, desktop_scene_slideshow_callback, desktop);
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdSlideshow);
}
bool desktop_scene_slideshow_on_event(void* context, SceneManagerEvent event) {
Desktop* desktop = (Desktop*)context;
bool consumed = false;
Storage* storage = NULL;
Power* power = NULL;
if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case DesktopSlideshowCompleted:
storage = furi_record_open(RECORD_STORAGE);
storage_common_remove(storage, SLIDESHOW_FS_PATH);
furi_record_close(RECORD_STORAGE);
scene_manager_previous_scene(desktop->scene_manager);
consumed = true;
break;
case DesktopSlideshowPoweroff:
power = furi_record_open(RECORD_POWER);
power_off(power);
furi_record_close(RECORD_POWER);
consumed = true;
break;
default:
break;
}
}
return consumed;
}
void desktop_scene_slideshow_on_exit(void* context) {
UNUSED(context);
}