[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 "lfrfid_scene.h"
// Generate scene on_enter handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
void (*const lfrfid_on_enter_handlers[])(void*) = {
#include "lfrfid_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 lfrfid_on_event_handlers[])(void* context, SceneManagerEvent event) = {
#include "lfrfid_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 lfrfid_on_exit_handlers[])(void* context) = {
#include "lfrfid_scene_config.h"
};
#undef ADD_SCENE
// Initialize scene handlers configuration structure
const SceneManagerHandlers lfrfid_scene_handlers = {
.on_enter_handlers = lfrfid_on_enter_handlers,
.on_event_handlers = lfrfid_on_event_handlers,
.on_exit_handlers = lfrfid_on_exit_handlers,
.scene_num = LfRfidSceneNum,
};

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) LfRfidScene##id,
typedef enum {
#include "lfrfid_scene_config.h"
LfRfidSceneNum,
} LfRfidScene;
#undef ADD_SCENE
extern const SceneManagerHandlers lfrfid_scene_handlers;
// Generate scene on_enter handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
#include "lfrfid_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 "lfrfid_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 "lfrfid_scene_config.h"
#undef ADD_SCENE

View File

@@ -0,0 +1,24 @@
ADD_SCENE(lfrfid, start, Start)
ADD_SCENE(lfrfid, read, Read)
ADD_SCENE(lfrfid, read_success, ReadSuccess)
ADD_SCENE(lfrfid, retry_confirm, RetryConfirm)
ADD_SCENE(lfrfid, exit_confirm, ExitConfirm)
ADD_SCENE(lfrfid, delete_confirm, DeleteConfirm)
ADD_SCENE(lfrfid, read_key_menu, ReadKeyMenu)
ADD_SCENE(lfrfid, write, Write)
ADD_SCENE(lfrfid, write_success, WriteSuccess)
ADD_SCENE(lfrfid, emulate, Emulate)
ADD_SCENE(lfrfid, save_name, SaveName)
ADD_SCENE(lfrfid, save_success, SaveSuccess)
ADD_SCENE(lfrfid, select_key, SelectKey)
ADD_SCENE(lfrfid, saved_key_menu, SavedKeyMenu)
ADD_SCENE(lfrfid, save_data, SaveData)
ADD_SCENE(lfrfid, save_type, SaveType)
ADD_SCENE(lfrfid, saved_info, SavedInfo)
ADD_SCENE(lfrfid, delete_success, DeleteSuccess)
ADD_SCENE(lfrfid, extra_actions, ExtraActions)
ADD_SCENE(lfrfid, raw_info, RawInfo)
ADD_SCENE(lfrfid, raw_name, RawName)
ADD_SCENE(lfrfid, raw_read, RawRead)
ADD_SCENE(lfrfid, raw_success, RawSuccess)
ADD_SCENE(lfrfid, rpc, Rpc)

View File

@@ -0,0 +1,68 @@
#include "../lfrfid_i.h"
void lfrfid_scene_delete_confirm_on_enter(void* context) {
LfRfid* app = context;
Widget* widget = app->widget;
string_t tmp_string;
string_init(tmp_string);
widget_add_button_element(widget, GuiButtonTypeLeft, "Back", lfrfid_widget_callback, app);
widget_add_button_element(widget, GuiButtonTypeRight, "Delete", lfrfid_widget_callback, app);
string_printf(tmp_string, "Delete %s?", string_get_cstr(app->file_name));
widget_add_string_element(
widget, 64, 0, AlignCenter, AlignTop, FontPrimary, string_get_cstr(tmp_string));
string_reset(tmp_string);
size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
uint8_t* data = (uint8_t*)malloc(size);
protocol_dict_get_data(app->dict, app->protocol_id, data, size);
for(uint8_t i = 0; i < MIN(size, (size_t)8); i++) {
if(i != 0) {
string_cat_printf(tmp_string, " ");
}
string_cat_printf(tmp_string, "%02X", data[i]);
}
free(data);
widget_add_string_element(
widget, 64, 19, AlignCenter, AlignTop, FontSecondary, string_get_cstr(tmp_string));
widget_add_string_element(
widget,
64,
49,
AlignCenter,
AlignBottom,
FontSecondary,
protocol_dict_get_name(app->dict, app->protocol_id));
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget);
string_clear(tmp_string);
}
bool lfrfid_scene_delete_confirm_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
SceneManager* scene_manager = app->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
consumed = true; // Ignore Back button presses
} else if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == GuiButtonTypeLeft) {
scene_manager_previous_scene(scene_manager);
} else if(event.event == GuiButtonTypeRight) {
lfrfid_delete_key(app);
scene_manager_next_scene(scene_manager, LfRfidSceneDeleteSuccess);
}
}
return consumed;
}
void lfrfid_scene_delete_confirm_on_exit(void* context) {
LfRfid* app = context;
widget_reset(app->widget);
}

View File

@@ -0,0 +1,35 @@
#include "../lfrfid_i.h"
void lfrfid_scene_delete_success_on_enter(void* context) {
LfRfid* app = context;
Popup* popup = app->popup;
popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62);
popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom);
popup_set_context(popup, app);
popup_set_callback(popup, lfrfid_popup_timeout_callback);
popup_set_timeout(popup, 1500);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup);
}
bool lfrfid_scene_delete_success_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
bool consumed = false;
if((event.type == SceneManagerEventTypeBack) ||
((event.type == SceneManagerEventTypeCustom) && (event.event == LfRfidEventPopupClosed))) {
scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, LfRfidSceneSelectKey);
consumed = true;
}
return consumed;
}
void lfrfid_scene_delete_success_on_exit(void* context) {
LfRfid* app = context;
popup_reset(app->popup);
}

View File

@@ -0,0 +1,44 @@
#include "../lfrfid_i.h"
#include <dolphin/dolphin.h>
void lfrfid_scene_emulate_on_enter(void* context) {
LfRfid* app = context;
Popup* popup = app->popup;
DOLPHIN_DEED(DolphinDeedRfidEmulate);
popup_set_header(popup, "Emulating", 89, 30, AlignCenter, AlignTop);
if(!string_empty_p(app->file_name)) {
popup_set_text(popup, string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop);
} else {
popup_set_text(
popup,
protocol_dict_get_name(app->dict, app->protocol_id),
89,
43,
AlignCenter,
AlignTop);
}
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
lfrfid_worker_start_thread(app->lfworker);
lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id);
notification_message(app->notifications, &sequence_blink_start_magenta);
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup);
}
bool lfrfid_scene_emulate_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
bool consumed = false;
return consumed;
}
void lfrfid_scene_emulate_on_exit(void* context) {
LfRfid* app = context;
notification_message(app->notifications, &sequence_blink_stop);
popup_reset(app->popup);
lfrfid_worker_stop(app->lfworker);
lfrfid_worker_stop_thread(app->lfworker);
}

View File

@@ -0,0 +1,39 @@
#include "../lfrfid_i.h"
void lfrfid_scene_exit_confirm_on_enter(void* context) {
LfRfid* app = context;
Widget* widget = app->widget;
widget_add_button_element(widget, GuiButtonTypeLeft, "Exit", lfrfid_widget_callback, app);
widget_add_button_element(widget, GuiButtonTypeRight, "Stay", lfrfid_widget_callback, app);
widget_add_string_element(
widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Exit to RFID Menu?");
widget_add_string_element(
widget, 64, 31, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!");
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget);
}
bool lfrfid_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
SceneManager* scene_manager = app->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
consumed = true; // Ignore Back button presses
} else if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == GuiButtonTypeLeft) {
scene_manager_search_and_switch_to_previous_scene(scene_manager, LfRfidSceneStart);
} else if(event.event == GuiButtonTypeRight) {
scene_manager_previous_scene(scene_manager);
}
}
return consumed;
}
void lfrfid_scene_exit_confirm_on_exit(void* context) {
LfRfid* app = context;
widget_reset(app->widget);
}

View File

@@ -0,0 +1,79 @@
#include "../lfrfid_i.h"
typedef enum {
SubmenuIndexASK,
SubmenuIndexPSK,
SubmenuIndexRAW,
} SubmenuIndex;
static void lfrfid_scene_extra_actions_submenu_callback(void* context, uint32_t index) {
LfRfid* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, index);
}
void lfrfid_scene_extra_actions_on_enter(void* context) {
LfRfid* app = context;
Submenu* submenu = app->submenu;
submenu_add_item(
submenu,
"Read ASK (Animal, Ordinary Card)",
SubmenuIndexASK,
lfrfid_scene_extra_actions_submenu_callback,
app);
submenu_add_item(
submenu,
"Read PSK (Indala)",
SubmenuIndexPSK,
lfrfid_scene_extra_actions_submenu_callback,
app);
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
submenu_add_item(
submenu,
"Read RAW RFID data",
SubmenuIndexRAW,
lfrfid_scene_extra_actions_submenu_callback,
app);
}
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneExtraActions));
// clear key
string_reset(app->file_name);
app->protocol_id = PROTOCOL_NO;
app->read_type = LFRFIDWorkerReadTypeAuto;
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewSubmenu);
}
bool lfrfid_scene_extra_actions_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexASK) {
app->read_type = LFRFIDWorkerReadTypeASKOnly;
scene_manager_next_scene(app->scene_manager, LfRfidSceneRead);
consumed = true;
} else if(event.event == SubmenuIndexPSK) {
app->read_type = LFRFIDWorkerReadTypePSKOnly;
scene_manager_next_scene(app->scene_manager, LfRfidSceneRead);
consumed = true;
} else if(event.event == SubmenuIndexRAW) {
scene_manager_next_scene(app->scene_manager, LfRfidSceneRawName);
consumed = true;
}
scene_manager_set_scene_state(app->scene_manager, LfRfidSceneExtraActions, event.event);
}
return consumed;
}
void lfrfid_scene_extra_actions_on_exit(void* context) {
LfRfid* app = context;
submenu_reset(app->submenu);
}

View File

@@ -0,0 +1,64 @@
#include "../lfrfid_i.h"
void lfrfid_scene_raw_info_on_enter(void* context) {
LfRfid* app = context;
Widget* widget = app->widget;
// string_t tmp_string;
// string_init(tmp_string);
bool sd_exist = storage_sd_status(app->storage) == FSE_OK;
if(!sd_exist) {
widget_add_icon_element(widget, 0, 0, &I_SDQuestion_35x43);
widget_add_string_multiline_element(
widget,
81,
4,
AlignCenter,
AlignTop,
FontSecondary,
"No SD card found.\nThis function will not\nwork without\nSD card.");
widget_add_button_element(widget, GuiButtonTypeLeft, "Back", lfrfid_widget_callback, app);
} else {
widget_add_string_multiline_element(
widget,
0,
1,
AlignLeft,
AlignTop,
FontSecondary,
"RAW RFID data reader\n1) Put the Flipper on your card\n2) Press OK\n3) Wait until data is read");
widget_add_button_element(widget, GuiButtonTypeCenter, "OK", lfrfid_widget_callback, app);
}
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget);
//string_clear(tmp_string);
}
bool lfrfid_scene_raw_info_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
SceneManager* scene_manager = app->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
consumed = true;
scene_manager_search_and_switch_to_previous_scene(scene_manager, LfRfidSceneExtraActions);
} else if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == GuiButtonTypeCenter) {
scene_manager_next_scene(scene_manager, LfRfidSceneRawRead);
} else if(event.event == GuiButtonTypeLeft) {
scene_manager_search_and_switch_to_previous_scene(
scene_manager, LfRfidSceneExtraActions);
}
}
return consumed;
}
void lfrfid_scene_raw_info_on_exit(void* context) {
LfRfid* app = context;
widget_reset(app->widget);
}

View File

@@ -0,0 +1,58 @@
#include "../lfrfid_i.h"
void lfrfid_scene_raw_name_on_enter(void* context) {
LfRfid* app = context;
TextInput* text_input = app->text_input;
const char* key_name = string_get_cstr(app->raw_file_name);
bool key_name_is_empty = string_empty_p(app->file_name);
if(key_name_is_empty) {
lfrfid_text_store_set(app, "RfidRecord");
} else {
lfrfid_text_store_set(app, "%s", key_name);
}
text_input_set_header_text(text_input, "Name the raw file");
text_input_set_result_callback(
text_input,
lfrfid_text_input_callback,
app,
app->text_store,
LFRFID_KEY_NAME_SIZE,
key_name_is_empty);
ValidatorIsFile* validator_is_file =
validator_is_file_alloc_init(LFRFID_SD_FOLDER, LFRFID_APP_RAW_ASK_EXTENSION, NULL);
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewTextInput);
}
bool lfrfid_scene_raw_name_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
SceneManager* scene_manager = app->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == LfRfidEventNext) {
consumed = true;
string_set_str(app->raw_file_name, app->text_store);
scene_manager_next_scene(scene_manager, LfRfidSceneRawInfo);
}
}
return consumed;
}
void lfrfid_scene_raw_name_on_exit(void* context) {
LfRfid* app = context;
TextInput* text_input = app->text_input;
void* validator_context = text_input_get_validator_callback_context(text_input);
text_input_set_validator(text_input, NULL, NULL);
validator_is_file_free((ValidatorIsFile*)validator_context);
text_input_reset(text_input);
}

View File

@@ -0,0 +1,126 @@
#include "../lfrfid_i.h"
#define RAW_READ_TIME 5000
typedef struct {
string_t string_file_name;
FuriTimer* timer;
bool is_psk;
bool error;
} LfRfidReadRawState;
static void lfrfid_read_callback(LFRFIDWorkerReadRawResult result, void* context) {
LfRfid* app = context;
if(result == LFRFIDWorkerReadRawFileError) {
view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventReadError);
} else if(result == LFRFIDWorkerReadRawOverrun) {
view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventReadOverrun);
}
}
static void timer_callback(void* context) {
LfRfid* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventReadDone);
}
void lfrfid_scene_raw_read_on_enter(void* context) {
LfRfid* app = context;
Popup* popup = app->popup;
LfRfidReadRawState* state = malloc(sizeof(LfRfidReadRawState));
scene_manager_set_scene_state(app->scene_manager, LfRfidSceneRawRead, (uint32_t)state);
string_init(state->string_file_name);
popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup);
lfrfid_worker_start_thread(app->lfworker);
lfrfid_make_app_folder(app);
state->timer = furi_timer_alloc(timer_callback, FuriTimerTypeOnce, app);
furi_timer_start(state->timer, RAW_READ_TIME);
string_printf(
state->string_file_name,
"%s/%s%s",
LFRFID_SD_FOLDER,
string_get_cstr(app->raw_file_name),
LFRFID_APP_RAW_ASK_EXTENSION);
popup_set_header(popup, "Reading\nRAW RFID\nASK", 89, 30, AlignCenter, AlignTop);
lfrfid_worker_read_raw_start(
app->lfworker,
string_get_cstr(state->string_file_name),
LFRFIDWorkerReadTypeASKOnly,
lfrfid_read_callback,
app);
notification_message(app->notifications, &sequence_blink_start_cyan);
state->is_psk = false;
state->error = false;
}
bool lfrfid_scene_raw_read_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
Popup* popup = app->popup;
LfRfidReadRawState* state =
(LfRfidReadRawState*)scene_manager_get_scene_state(app->scene_manager, LfRfidSceneRawRead);
bool consumed = false;
furi_assert(state);
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == LfRfidEventReadError) {
consumed = true;
state->error = true;
popup_set_header(
popup, "Reading\nRAW RFID\nFile error", 89, 30, AlignCenter, AlignTop);
notification_message(app->notifications, &sequence_blink_start_red);
furi_timer_stop(state->timer);
} else if(event.event == LfRfidEventReadDone) {
consumed = true;
if(!state->error) {
if(state->is_psk) {
notification_message(app->notifications, &sequence_success);
scene_manager_next_scene(app->scene_manager, LfRfidSceneRawSuccess);
} else {
popup_set_header(
popup, "Reading\nRAW RFID\nPSK", 89, 30, AlignCenter, AlignTop);
notification_message(app->notifications, &sequence_blink_start_yellow);
lfrfid_worker_stop(app->lfworker);
string_printf(
state->string_file_name,
"%s/%s%s",
LFRFID_SD_FOLDER,
string_get_cstr(app->raw_file_name),
LFRFID_APP_RAW_PSK_EXTENSION);
lfrfid_worker_read_raw_start(
app->lfworker,
string_get_cstr(state->string_file_name),
LFRFIDWorkerReadTypePSKOnly,
lfrfid_read_callback,
app);
furi_timer_start(state->timer, RAW_READ_TIME);
state->is_psk = true;
}
}
}
}
return consumed;
}
void lfrfid_scene_raw_read_on_exit(void* context) {
LfRfid* app = context;
LfRfidReadRawState* state =
(LfRfidReadRawState*)scene_manager_get_scene_state(app->scene_manager, LfRfidSceneRawRead);
notification_message(app->notifications, &sequence_blink_stop);
popup_reset(app->popup);
lfrfid_worker_stop(app->lfworker);
lfrfid_worker_stop_thread(app->lfworker);
furi_timer_free(state->timer);
string_clear(state->string_file_name);
free(state);
}

View File

@@ -0,0 +1,39 @@
#include "../lfrfid_i.h"
void lfrfid_scene_raw_success_on_enter(void* context) {
LfRfid* app = context;
Widget* widget = app->widget;
widget_add_button_element(widget, GuiButtonTypeCenter, "OK", lfrfid_widget_callback, app);
widget_add_string_multiline_element(
widget,
0,
1,
AlignLeft,
AlignTop,
FontSecondary,
"RAW RFID read success!\nNow you can analyze files\nOr send them to developers");
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget);
}
bool lfrfid_scene_raw_success_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
SceneManager* scene_manager = app->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == GuiButtonTypeCenter) {
scene_manager_search_and_switch_to_previous_scene(
scene_manager, LfRfidSceneExtraActions);
}
}
return consumed;
}
void lfrfid_scene_raw_success_on_exit(void* context) {
LfRfid* app = context;
widget_reset(app->widget);
}

View File

@@ -0,0 +1,109 @@
#include "../lfrfid_i.h"
#include <dolphin/dolphin.h>
static const NotificationSequence sequence_blink_set_yellow = {
&message_blink_set_color_yellow,
NULL,
};
static const NotificationSequence sequence_blink_set_green = {
&message_blink_set_color_green,
NULL,
};
static const NotificationSequence sequence_blink_set_cyan = {
&message_blink_set_color_cyan,
NULL,
};
static void
lfrfid_read_callback(LFRFIDWorkerReadResult result, ProtocolId protocol, void* context) {
LfRfid* app = context;
uint32_t event = 0;
if(result == LFRFIDWorkerReadSenseStart) {
event = LfRfidEventReadSenseStart;
} else if(result == LFRFIDWorkerReadSenseEnd) {
event = LfRfidEventReadSenseEnd;
} else if(result == LFRFIDWorkerReadSenseCardStart) {
event = LfRfidEventReadSenseCardStart;
} else if(result == LFRFIDWorkerReadSenseCardEnd) {
event = LfRfidEventReadSenseCardEnd;
} else if(result == LFRFIDWorkerReadDone) {
event = LfRfidEventReadDone;
app->protocol_id_next = protocol;
} else if(result == LFRFIDWorkerReadStartASK) {
event = LfRfidEventReadStartASK;
} else if(result == LFRFIDWorkerReadStartPSK) {
event = LfRfidEventReadStartPSK;
} else {
return;
}
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
void lfrfid_scene_read_on_enter(void* context) {
LfRfid* app = context;
DOLPHIN_DEED(DolphinDeedRfidRead);
if(app->read_type == LFRFIDWorkerReadTypePSKOnly) {
lfrfid_view_read_set_read_mode(app->read_view, LfRfidReadPskOnly);
} else if(app->read_type == LFRFIDWorkerReadTypeASKOnly) {
lfrfid_view_read_set_read_mode(app->read_view, LfRfidReadAskOnly);
}
lfrfid_worker_start_thread(app->lfworker);
lfrfid_worker_read_start(app->lfworker, app->read_type, lfrfid_read_callback, app);
notification_message(app->notifications, &sequence_blink_start_cyan);
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewRead);
}
bool lfrfid_scene_read_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == LfRfidEventReadSenseStart) {
notification_message(app->notifications, &sequence_blink_set_yellow);
consumed = true;
} else if(event.event == LfRfidEventReadSenseCardStart) {
notification_message(app->notifications, &sequence_blink_set_green);
consumed = true;
} else if(
(event.event == LfRfidEventReadSenseEnd) ||
(event.event == LfRfidEventReadSenseCardEnd)) {
notification_message(app->notifications, &sequence_blink_set_cyan);
consumed = true;
} else if(event.event == LfRfidEventReadDone) {
app->protocol_id = app->protocol_id_next;
DOLPHIN_DEED(DolphinDeedRfidReadSuccess);
notification_message(app->notifications, &sequence_success);
string_reset(app->file_name);
scene_manager_next_scene(app->scene_manager, LfRfidSceneReadSuccess);
consumed = true;
} else if(event.event == LfRfidEventReadStartPSK) {
if(app->read_type == LFRFIDWorkerReadTypeAuto) {
lfrfid_view_read_set_read_mode(app->read_view, LfRfidReadPsk);
}
consumed = true;
} else if(event.event == LfRfidEventReadStartASK) {
if(app->read_type == LFRFIDWorkerReadTypeAuto) {
lfrfid_view_read_set_read_mode(app->read_view, LfRfidReadAsk);
}
consumed = true;
}
}
return consumed;
}
void lfrfid_scene_read_on_exit(void* context) {
LfRfid* app = context;
notification_message(app->notifications, &sequence_blink_stop);
popup_reset(app->popup);
lfrfid_worker_stop(app->lfworker);
lfrfid_worker_stop_thread(app->lfworker);
}

View File

@@ -0,0 +1,58 @@
#include "../lfrfid_i.h"
typedef enum {
SubmenuIndexSave,
SubmenuIndexEmulate,
SubmenuIndexWrite,
} SubmenuIndex;
void lfrfid_scene_read_key_menu_submenu_callback(void* context, uint32_t index) {
LfRfid* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, index);
}
void lfrfid_scene_read_key_menu_on_enter(void* context) {
LfRfid* app = context;
Submenu* submenu = app->submenu;
submenu_add_item(
submenu, "Save", SubmenuIndexSave, lfrfid_scene_read_key_menu_submenu_callback, app);
submenu_add_item(
submenu, "Emulate", SubmenuIndexEmulate, lfrfid_scene_read_key_menu_submenu_callback, app);
submenu_add_item(
submenu, "Write", SubmenuIndexWrite, lfrfid_scene_read_key_menu_submenu_callback, app);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneReadKeyMenu));
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewSubmenu);
}
bool lfrfid_scene_read_key_menu_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexWrite) {
scene_manager_next_scene(app->scene_manager, LfRfidSceneWrite);
consumed = true;
} else if(event.event == SubmenuIndexSave) {
string_reset(app->file_name);
scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveName);
consumed = true;
} else if(event.event == SubmenuIndexEmulate) {
scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate);
consumed = true;
}
scene_manager_set_scene_state(app->scene_manager, LfRfidSceneReadKeyMenu, event.event);
}
return consumed;
}
void lfrfid_scene_read_key_menu_on_exit(void* context) {
LfRfid* app = context;
submenu_reset(app->submenu);
}

View File

@@ -0,0 +1,79 @@
#include "../lfrfid_i.h"
void lfrfid_scene_read_success_on_enter(void* context) {
LfRfid* app = context;
Widget* widget = app->widget;
string_t tmp_string;
string_init(tmp_string);
widget_add_button_element(widget, GuiButtonTypeLeft, "Retry", lfrfid_widget_callback, app);
widget_add_button_element(widget, GuiButtonTypeRight, "More", lfrfid_widget_callback, app);
string_printf(
tmp_string,
"%s[%s]",
protocol_dict_get_name(app->dict, app->protocol_id),
protocol_dict_get_manufacturer(app->dict, app->protocol_id));
widget_add_string_element(
widget, 0, 2, AlignLeft, AlignTop, FontPrimary, string_get_cstr(tmp_string));
string_reset(tmp_string);
size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
uint8_t* data = (uint8_t*)malloc(size);
protocol_dict_get_data(app->dict, app->protocol_id, data, size);
for(uint8_t i = 0; i < size; i++) {
if(i != 0) {
string_cat_printf(tmp_string, " ");
}
if(i >= 9) {
string_cat_printf(tmp_string, "...");
break;
} else {
string_cat_printf(tmp_string, "%02X", data[i]);
}
}
free(data);
string_t render_data;
string_init(render_data);
protocol_dict_render_brief_data(app->dict, render_data, app->protocol_id);
string_cat_printf(tmp_string, "\r\n%s", string_get_cstr(render_data));
string_clear(render_data);
widget_add_string_element(
widget, 0, 16, AlignLeft, AlignTop, FontSecondary, string_get_cstr(tmp_string));
notification_message_block(app->notifications, &sequence_set_green_255);
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget);
string_clear(tmp_string);
}
bool lfrfid_scene_read_success_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
SceneManager* scene_manager = app->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
scene_manager_next_scene(scene_manager, LfRfidSceneExitConfirm);
consumed = true;
} else if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == GuiButtonTypeLeft) {
scene_manager_next_scene(scene_manager, LfRfidSceneRetryConfirm);
} else if(event.event == GuiButtonTypeRight) {
scene_manager_next_scene(scene_manager, LfRfidSceneReadKeyMenu);
}
}
return consumed;
}
void lfrfid_scene_read_success_on_exit(void* context) {
LfRfid* app = context;
notification_message_block(app->notifications, &sequence_reset_green);
widget_reset(app->widget);
}

View File

@@ -0,0 +1,39 @@
#include "../lfrfid_i.h"
void lfrfid_scene_retry_confirm_on_enter(void* context) {
LfRfid* app = context;
Widget* widget = app->widget;
widget_add_button_element(widget, GuiButtonTypeLeft, "Exit", lfrfid_widget_callback, app);
widget_add_button_element(widget, GuiButtonTypeRight, "Stay", lfrfid_widget_callback, app);
widget_add_string_element(
widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Return to reading?");
widget_add_string_element(
widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!");
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget);
}
bool lfrfid_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
SceneManager* scene_manager = app->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
consumed = true; // Ignore Back button presses
} else if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == GuiButtonTypeLeft) {
scene_manager_search_and_switch_to_previous_scene(scene_manager, LfRfidSceneRead);
} else if(event.event == GuiButtonTypeRight) {
scene_manager_previous_scene(scene_manager);
}
}
return consumed;
}
void lfrfid_scene_retry_confirm_on_exit(void* context) {
LfRfid* app = context;
widget_reset(app->widget);
}

View File

@@ -0,0 +1,67 @@
#include "../lfrfid_i.h"
void lfrfid_scene_rpc_on_enter(void* context) {
LfRfid* app = context;
Popup* popup = app->popup;
popup_set_header(popup, "LF RFID", 89, 42, AlignCenter, AlignBottom);
popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 12, &I_RFIDDolphinSend_97x61);
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup);
notification_message(app->notifications, &sequence_display_backlight_on);
app->rpc_state = LfRfidRpcStateIdle;
}
bool lfrfid_scene_rpc_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
Popup* popup = app->popup;
UNUSED(event);
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == LfRfidEventExit) {
rpc_system_app_confirm(app->rpc_ctx, RpcAppEventAppExit, true);
scene_manager_stop(app->scene_manager);
view_dispatcher_stop(app->view_dispatcher);
} else if(event.event == LfRfidEventRpcSessionClose) {
scene_manager_stop(app->scene_manager);
view_dispatcher_stop(app->view_dispatcher);
} else if(event.event == LfRfidEventRpcLoadFile) {
const char* arg = rpc_system_app_get_data(app->rpc_ctx);
bool result = false;
if(arg && (app->rpc_state == LfRfidRpcStateIdle)) {
string_set_str(app->file_path, arg);
if(lfrfid_load_key_data(app, app->file_path, false)) {
lfrfid_worker_start_thread(app->lfworker);
lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id);
app->rpc_state = LfRfidRpcStateEmulating;
lfrfid_text_store_set(app, "emulating\n%s", string_get_cstr(app->file_name));
popup_set_text(popup, app->text_store, 89, 44, AlignCenter, AlignTop);
notification_message(app->notifications, &sequence_blink_start_magenta);
result = true;
}
}
rpc_system_app_confirm(app->rpc_ctx, RpcAppEventLoadFile, result);
}
}
return consumed;
}
void lfrfid_scene_rpc_on_exit(void* context) {
LfRfid* app = context;
Popup* popup = app->popup;
if(app->rpc_state == LfRfidRpcStateEmulating) {
lfrfid_worker_stop(app->lfworker);
lfrfid_worker_stop_thread(app->lfworker);
notification_message(app->notifications, &sequence_blink_stop);
}
popup_reset(popup);
}

View File

@@ -0,0 +1,51 @@
#include "../lfrfid_i.h"
#include <dolphin/dolphin.h>
void lfrfid_scene_save_data_on_enter(void* context) {
LfRfid* app = context;
ByteInput* byte_input = app->byte_input;
size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
bool need_restore = scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSaveData);
if(need_restore) {
protocol_dict_set_data(app->dict, app->protocol_id, app->old_key_data, size);
} else {
protocol_dict_get_data(app->dict, app->protocol_id, app->old_key_data, size);
}
protocol_dict_get_data(app->dict, app->protocol_id, app->new_key_data, size);
byte_input_set_header_text(byte_input, "Enter the data in hex");
byte_input_set_result_callback(
byte_input, lfrfid_text_input_callback, NULL, app, app->new_key_data, size);
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewByteInput);
}
bool lfrfid_scene_save_data_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
SceneManager* scene_manager = app->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == LfRfidEventNext) {
consumed = true;
size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
protocol_dict_set_data(app->dict, app->protocol_id, app->new_key_data, size);
DOLPHIN_DEED(DolphinDeedRfidAdd);
scene_manager_next_scene(scene_manager, LfRfidSceneSaveName);
scene_manager_set_scene_state(scene_manager, LfRfidSceneSaveData, 1);
}
} else if(event.type == SceneManagerEventTypeBack) {
scene_manager_set_scene_state(scene_manager, LfRfidSceneSaveData, 0);
}
return consumed;
}
void lfrfid_scene_save_data_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -0,0 +1,76 @@
#include "m-string.h"
#include <lib/toolbox/random_name.h>
#include "../lfrfid_i.h"
void lfrfid_scene_save_name_on_enter(void* context) {
LfRfid* app = context;
TextInput* text_input = app->text_input;
string_t folder_path;
string_init(folder_path);
bool key_name_is_empty = string_empty_p(app->file_name);
if(key_name_is_empty) {
string_set_str(app->file_path, LFRFID_APP_FOLDER);
set_random_name(app->text_store, LFRFID_TEXT_STORE_SIZE);
string_set_str(folder_path, LFRFID_APP_FOLDER);
} else {
lfrfid_text_store_set(app, "%s", string_get_cstr(app->file_name));
path_extract_dirname(string_get_cstr(app->file_path), folder_path);
}
text_input_set_header_text(text_input, "Name the card");
text_input_set_result_callback(
text_input,
lfrfid_text_input_callback,
app,
app->text_store,
LFRFID_KEY_NAME_SIZE,
key_name_is_empty);
FURI_LOG_I("", "%s %s", string_get_cstr(folder_path), app->text_store);
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
string_get_cstr(folder_path), LFRFID_APP_EXTENSION, string_get_cstr(app->file_name));
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
string_clear(folder_path);
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewTextInput);
}
bool lfrfid_scene_save_name_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
SceneManager* scene_manager = app->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == LfRfidEventNext) {
consumed = true;
if(!string_empty_p(app->file_name)) {
lfrfid_delete_key(app);
}
string_set_str(app->file_name, app->text_store);
if(lfrfid_save_key(app)) {
scene_manager_next_scene(scene_manager, LfRfidSceneSaveSuccess);
} else {
scene_manager_search_and_switch_to_previous_scene(
scene_manager, LfRfidSceneReadKeyMenu);
}
}
}
return consumed;
}
void lfrfid_scene_save_name_on_exit(void* context) {
LfRfid* app = context;
TextInput* text_input = app->text_input;
void* validator_context = text_input_get_validator_callback_context(text_input);
text_input_set_validator(text_input, NULL, NULL);
validator_is_file_free((ValidatorIsFile*)validator_context);
text_input_reset(text_input);
}

View File

@@ -0,0 +1,43 @@
#include "../lfrfid_i.h"
#include <dolphin/dolphin.h>
void lfrfid_scene_save_success_on_enter(void* context) {
LfRfid* app = context;
Popup* popup = app->popup;
DOLPHIN_DEED(DolphinDeedRfidSave);
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop);
popup_set_context(popup, app);
popup_set_callback(popup, lfrfid_popup_timeout_callback);
popup_set_timeout(popup, 1500);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup);
}
bool lfrfid_scene_save_success_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
bool consumed = false;
const uint32_t prev_scenes[] = {LfRfidSceneReadKeyMenu, LfRfidSceneSelectKey};
if((event.type == SceneManagerEventTypeBack) ||
((event.type == SceneManagerEventTypeCustom) && (event.event == LfRfidEventPopupClosed))) {
bool result = scene_manager_search_and_switch_to_previous_scene_one_of(
app->scene_manager, prev_scenes, COUNT_OF(prev_scenes));
if(!result) {
scene_manager_search_and_switch_to_another_scene(
app->scene_manager, LfRfidSceneSelectKey);
}
consumed = true;
}
return consumed;
}
void lfrfid_scene_save_success_on_exit(void* context) {
LfRfid* app = context;
popup_reset(app->popup);
}

View File

@@ -0,0 +1,86 @@
#include "../lfrfid_i.h"
typedef struct {
string_t menu_item_name[LFRFIDProtocolMax];
uint32_t line_sel;
} SaveTypeCtx;
static void lfrfid_scene_save_type_submenu_callback(void* context, uint32_t index) {
LfRfid* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, index);
}
void lfrfid_scene_save_type_on_enter(void* context) {
LfRfid* app = context;
Submenu* submenu = app->submenu;
SaveTypeCtx* state = malloc(sizeof(SaveTypeCtx));
for(uint8_t i = 0; i < LFRFIDProtocolMax; i++) {
if(strcmp(
protocol_dict_get_manufacturer(app->dict, i),
protocol_dict_get_name(app->dict, i)) != 0) {
string_init_printf(
state->menu_item_name[i],
"%s %s",
protocol_dict_get_manufacturer(app->dict, i),
protocol_dict_get_name(app->dict, i));
} else {
string_init_printf(
state->menu_item_name[i], "%s", protocol_dict_get_name(app->dict, i));
}
submenu_add_item(
submenu,
string_get_cstr(state->menu_item_name[i]),
i,
lfrfid_scene_save_type_submenu_callback,
app);
}
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSaveType));
scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSaveType, (uint32_t)state);
// clear key name
string_reset(app->file_name);
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewSubmenu);
}
bool lfrfid_scene_save_type_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
bool consumed = false;
SaveTypeCtx* state =
(SaveTypeCtx*)scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSaveType);
furi_check(state);
if(event.type == SceneManagerEventTypeCustom) {
app->protocol_id = event.event;
state->line_sel = event.event;
scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveData);
consumed = true;
}
return consumed;
}
void lfrfid_scene_save_type_on_exit(void* context) {
LfRfid* app = context;
SaveTypeCtx* state =
(SaveTypeCtx*)scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSaveType);
furi_check(state);
submenu_reset(app->submenu);
for(uint8_t i = 0; i < LFRFIDProtocolMax; i++) {
string_clear(state->menu_item_name[i]);
}
uint32_t line_sel = state->line_sel;
free(state);
scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSaveType, line_sel);
}

View File

@@ -0,0 +1,51 @@
#include "../lfrfid_i.h"
void lfrfid_scene_saved_info_on_enter(void* context) {
LfRfid* app = context;
Widget* widget = app->widget;
string_t tmp_string;
string_init(tmp_string);
string_printf(
tmp_string,
"%s [%s]\r\n",
string_get_cstr(app->file_name),
protocol_dict_get_name(app->dict, app->protocol_id));
size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
uint8_t* data = (uint8_t*)malloc(size);
protocol_dict_get_data(app->dict, app->protocol_id, data, size);
for(uint8_t i = 0; i < size; i++) {
if(i != 0) {
string_cat_printf(tmp_string, " ");
}
string_cat_printf(tmp_string, "%02X", data[i]);
}
free(data);
string_t render_data;
string_init(render_data);
protocol_dict_render_data(app->dict, render_data, app->protocol_id);
string_cat_printf(tmp_string, "\r\n%s", string_get_cstr(render_data));
string_clear(render_data);
widget_add_string_multiline_element(
widget, 0, 1, AlignLeft, AlignTop, FontSecondary, string_get_cstr(tmp_string));
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget);
string_clear(tmp_string);
}
bool lfrfid_scene_saved_info_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
bool consumed = false;
return consumed;
}
void lfrfid_scene_saved_info_on_exit(void* context) {
LfRfid* app = context;
widget_reset(app->widget);
}

View File

@@ -0,0 +1,69 @@
#include "../lfrfid_i.h"
typedef enum {
SubmenuIndexEmulate,
SubmenuIndexWrite,
SubmenuIndexEdit,
SubmenuIndexDelete,
SubmenuIndexInfo,
} SubmenuIndex;
static void lfrfid_scene_saved_key_menu_submenu_callback(void* context, uint32_t index) {
LfRfid* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, index);
}
void lfrfid_scene_saved_key_menu_on_enter(void* context) {
LfRfid* app = context;
Submenu* submenu = app->submenu;
submenu_add_item(
submenu, "Emulate", SubmenuIndexEmulate, lfrfid_scene_saved_key_menu_submenu_callback, app);
submenu_add_item(
submenu, "Write", SubmenuIndexWrite, lfrfid_scene_saved_key_menu_submenu_callback, app);
submenu_add_item(
submenu, "Edit", SubmenuIndexEdit, lfrfid_scene_saved_key_menu_submenu_callback, app);
submenu_add_item(
submenu, "Delete", SubmenuIndexDelete, lfrfid_scene_saved_key_menu_submenu_callback, app);
submenu_add_item(
submenu, "Info", SubmenuIndexInfo, lfrfid_scene_saved_key_menu_submenu_callback, app);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSavedKeyMenu));
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewSubmenu);
}
bool lfrfid_scene_saved_key_menu_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexEmulate) {
scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate);
consumed = true;
} else if(event.event == SubmenuIndexWrite) {
scene_manager_next_scene(app->scene_manager, LfRfidSceneWrite);
consumed = true;
} else if(event.event == SubmenuIndexEdit) {
scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveData);
consumed = true;
} else if(event.event == SubmenuIndexDelete) {
scene_manager_next_scene(app->scene_manager, LfRfidSceneDeleteConfirm);
consumed = true;
} else if(event.event == SubmenuIndexInfo) {
scene_manager_next_scene(app->scene_manager, LfRfidSceneSavedInfo);
consumed = true;
}
scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSavedKeyMenu, event.event);
}
return consumed;
}
void lfrfid_scene_saved_key_menu_on_exit(void* context) {
LfRfid* app = context;
submenu_reset(app->submenu);
}

View File

@@ -0,0 +1,22 @@
#include "../lfrfid_i.h"
void lfrfid_scene_select_key_on_enter(void* context) {
LfRfid* app = context;
if(lfrfid_load_key_from_file_select(app)) {
scene_manager_next_scene(app->scene_manager, LfRfidSceneSavedKeyMenu);
} else {
scene_manager_previous_scene(app->scene_manager);
}
}
bool lfrfid_scene_select_key_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
bool consumed = false;
return consumed;
}
void lfrfid_scene_select_key_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -0,0 +1,72 @@
#include "../lfrfid_i.h"
typedef enum {
SubmenuIndexRead,
SubmenuIndexSaved,
SubmenuIndexAddManually,
SubmenuIndexExtraActions,
} SubmenuIndex;
static void lfrfid_scene_start_submenu_callback(void* context, uint32_t index) {
LfRfid* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, index);
}
void lfrfid_scene_start_on_enter(void* context) {
LfRfid* app = context;
Submenu* submenu = app->submenu;
submenu_add_item(submenu, "Read", SubmenuIndexRead, lfrfid_scene_start_submenu_callback, app);
submenu_add_item(
submenu, "Saved", SubmenuIndexSaved, lfrfid_scene_start_submenu_callback, app);
submenu_add_item(
submenu, "Add Manually", SubmenuIndexAddManually, lfrfid_scene_start_submenu_callback, app);
submenu_add_item(
submenu,
"Extra Actions",
SubmenuIndexExtraActions,
lfrfid_scene_start_submenu_callback,
app);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneStart));
// clear key
string_reset(app->file_name);
app->protocol_id = PROTOCOL_NO;
app->read_type = LFRFIDWorkerReadTypeAuto;
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewSubmenu);
}
bool lfrfid_scene_start_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexRead) {
scene_manager_next_scene(app->scene_manager, LfRfidSceneRead);
consumed = true;
} else if(event.event == SubmenuIndexSaved) {
string_set_str(app->file_path, LFRFID_APP_FOLDER);
scene_manager_next_scene(app->scene_manager, LfRfidSceneSelectKey);
consumed = true;
} else if(event.event == SubmenuIndexAddManually) {
scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveType);
consumed = true;
} else if(event.event == SubmenuIndexExtraActions) {
scene_manager_next_scene(app->scene_manager, LfRfidSceneExtraActions);
consumed = true;
}
scene_manager_set_scene_state(app->scene_manager, LfRfidSceneStart, event.event);
}
return consumed;
}
void lfrfid_scene_start_on_exit(void* context) {
LfRfid* app = context;
submenu_reset(app->submenu);
}

View File

@@ -0,0 +1,96 @@
#include "../lfrfid_i.h"
static void lfrfid_write_callback(LFRFIDWorkerWriteResult result, void* context) {
LfRfid* app = context;
uint32_t event = 0;
if(result == LFRFIDWorkerWriteOK) {
event = LfRfidEventWriteOK;
} else if(result == LFRFIDWorkerWriteProtocolCannotBeWritten) {
event = LfRfidEventWriteProtocolCannotBeWritten;
} else if(result == LFRFIDWorkerWriteFobCannotBeWritten) {
event = LfRfidEventWriteFobCannotBeWritten;
} else if(result == LFRFIDWorkerWriteTooLongToWrite) {
event = LfRfidEventWriteTooLongToWrite;
}
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
void lfrfid_scene_write_on_enter(void* context) {
LfRfid* app = context;
Popup* popup = app->popup;
popup_set_header(popup, "Writing", 89, 30, AlignCenter, AlignTop);
if(!string_empty_p(app->file_name)) {
popup_set_text(popup, string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop);
} else {
popup_set_text(
popup,
protocol_dict_get_name(app->dict, app->protocol_id),
89,
43,
AlignCenter,
AlignTop);
}
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup);
size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
app->old_key_data = (uint8_t*)malloc(size);
protocol_dict_get_data(app->dict, app->protocol_id, app->old_key_data, size);
lfrfid_worker_start_thread(app->lfworker);
lfrfid_worker_write_start(
app->lfworker, (LFRFIDProtocol)app->protocol_id, lfrfid_write_callback, app);
notification_message(app->notifications, &sequence_blink_start_magenta);
}
bool lfrfid_scene_write_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
Popup* popup = app->popup;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == LfRfidEventWriteOK) {
notification_message(app->notifications, &sequence_success);
scene_manager_next_scene(app->scene_manager, LfRfidSceneWriteSuccess);
consumed = true;
} else if(event.event == LfRfidEventWriteProtocolCannotBeWritten) {
popup_set_icon(popup, 72, 17, &I_DolphinCommon_56x48);
popup_set_header(popup, "Error", 64, 3, AlignCenter, AlignTop);
popup_set_text(popup, "This protocol\ncannot be written", 3, 17, AlignLeft, AlignTop);
notification_message(app->notifications, &sequence_blink_start_red);
consumed = true;
} else if(
(event.event == LfRfidEventWriteFobCannotBeWritten) ||
(event.event == LfRfidEventWriteTooLongToWrite)) {
popup_set_icon(popup, 72, 17, &I_DolphinCommon_56x48);
popup_set_header(popup, "Still trying to write...", 64, 3, AlignCenter, AlignTop);
popup_set_text(
popup,
"Make sure this\ncard is writable\nand not\nprotected.",
3,
17,
AlignLeft,
AlignTop);
notification_message(app->notifications, &sequence_blink_start_yellow);
consumed = true;
}
}
return consumed;
}
void lfrfid_scene_write_on_exit(void* context) {
LfRfid* app = context;
notification_message(app->notifications, &sequence_blink_stop);
popup_reset(app->popup);
lfrfid_worker_stop(app->lfworker);
lfrfid_worker_stop_thread(app->lfworker);
size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
protocol_dict_set_data(app->dict, app->protocol_id, app->old_key_data, size);
free(app->old_key_data);
}

View File

@@ -0,0 +1,38 @@
#include "../lfrfid_i.h"
void lfrfid_scene_write_success_on_enter(void* context) {
LfRfid* app = context;
Popup* popup = app->popup;
popup_set_header(popup, "Successfully\nwritten!", 94, 3, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 6, &I_RFIDDolphinSuccess_108x57);
popup_set_context(popup, app);
popup_set_callback(popup, lfrfid_popup_timeout_callback);
popup_set_timeout(popup, 1500);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup);
notification_message_block(app->notifications, &sequence_set_green_255);
}
bool lfrfid_scene_write_success_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
bool consumed = false;
const uint32_t prev_scenes[] = {LfRfidSceneReadKeyMenu, LfRfidSceneSelectKey};
if((event.type == SceneManagerEventTypeBack) ||
((event.type == SceneManagerEventTypeCustom) && (event.event == LfRfidEventPopupClosed))) {
scene_manager_search_and_switch_to_previous_scene_one_of(
app->scene_manager, prev_scenes, COUNT_OF(prev_scenes));
consumed = true;
}
return consumed;
}
void lfrfid_scene_write_success_on_exit(void* context) {
LfRfid* app = context;
notification_message_block(app->notifications, &sequence_reset_green);
popup_reset(app->popup);
}