[FL-2753] RFID app port to plain C (#1710)

* LF RFID: port to plain C
* LFRFID debug port to C, new reading screen
* LFRFID debug: fix pvs-studio warnings
* RFID read view: remove unused input callback
* RFID read view: animation update
This commit is contained in:
Nikolay Minaylov 2022-09-08 19:40:33 +03:00 committed by GitHub
parent e9ab581771
commit 0f6f9ad52e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
117 changed files with 2674 additions and 2914 deletions

View File

@ -42,7 +42,9 @@ ValidatorIsFile* validator_is_file_alloc_init(
instance->app_path_folder = strdup(app_path_folder);
instance->app_extension = app_extension;
instance->current_name = strdup(current_name);
if(current_name != NULL) {
instance->current_name = strdup(current_name);
}
return instance;
}

View File

@ -0,0 +1,316 @@
#include "lfrfid_i.h"
static bool lfrfid_debug_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
LfRfid* app = context;
return scene_manager_handle_custom_event(app->scene_manager, event);
}
static bool lfrfid_debug_back_event_callback(void* context) {
furi_assert(context);
LfRfid* app = context;
return scene_manager_handle_back_event(app->scene_manager);
}
static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) {
furi_assert(context);
LfRfid* app = (LfRfid*)context;
if(rpc_event == RpcAppEventSessionClose) {
view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventRpcSessionClose);
// Detach RPC
rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL);
app->rpc_ctx = NULL;
} else if(rpc_event == RpcAppEventAppExit) {
view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventExit);
} else if(rpc_event == RpcAppEventLoadFile) {
view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventRpcLoadFile);
} else {
rpc_system_app_confirm(app->rpc_ctx, rpc_event, false);
}
}
static LfRfid* lfrfid_alloc() {
LfRfid* lfrfid = malloc(sizeof(LfRfid));
lfrfid->storage = furi_record_open(RECORD_STORAGE);
lfrfid->dialogs = furi_record_open(RECORD_DIALOGS);
string_init(lfrfid->file_name);
string_init(lfrfid->raw_file_name);
string_init_set_str(lfrfid->file_path, LFRFID_APP_FOLDER);
lfrfid->dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
size_t size = protocol_dict_get_max_data_size(lfrfid->dict);
lfrfid->new_key_data = (uint8_t*)malloc(size);
lfrfid->old_key_data = (uint8_t*)malloc(size);
lfrfid->lfworker = lfrfid_worker_alloc(lfrfid->dict);
lfrfid->view_dispatcher = view_dispatcher_alloc();
lfrfid->scene_manager = scene_manager_alloc(&lfrfid_scene_handlers, lfrfid);
view_dispatcher_enable_queue(lfrfid->view_dispatcher);
view_dispatcher_set_event_callback_context(lfrfid->view_dispatcher, lfrfid);
view_dispatcher_set_custom_event_callback(
lfrfid->view_dispatcher, lfrfid_debug_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
lfrfid->view_dispatcher, lfrfid_debug_back_event_callback);
// Open GUI record
lfrfid->gui = furi_record_open(RECORD_GUI);
// Open Notification record
lfrfid->notifications = furi_record_open(RECORD_NOTIFICATION);
// Submenu
lfrfid->submenu = submenu_alloc();
view_dispatcher_add_view(
lfrfid->view_dispatcher, LfRfidViewSubmenu, submenu_get_view(lfrfid->submenu));
// Dialog
lfrfid->dialog_ex = dialog_ex_alloc();
view_dispatcher_add_view(
lfrfid->view_dispatcher, LfRfidViewDialogEx, dialog_ex_get_view(lfrfid->dialog_ex));
// Popup
lfrfid->popup = popup_alloc();
view_dispatcher_add_view(
lfrfid->view_dispatcher, LfRfidViewPopup, popup_get_view(lfrfid->popup));
// Widget
lfrfid->widget = widget_alloc();
view_dispatcher_add_view(
lfrfid->view_dispatcher, LfRfidViewWidget, widget_get_view(lfrfid->widget));
// Text Input
lfrfid->text_input = text_input_alloc();
view_dispatcher_add_view(
lfrfid->view_dispatcher, LfRfidViewTextInput, text_input_get_view(lfrfid->text_input));
// Byte Input
lfrfid->byte_input = byte_input_alloc();
view_dispatcher_add_view(
lfrfid->view_dispatcher, LfRfidViewByteInput, byte_input_get_view(lfrfid->byte_input));
// Read custom view
lfrfid->read_view = lfrfid_view_read_alloc();
view_dispatcher_add_view(
lfrfid->view_dispatcher, LfRfidViewRead, lfrfid_view_read_get_view(lfrfid->read_view));
return lfrfid;
}
static void lfrfid_free(LfRfid* lfrfid) {
furi_assert(lfrfid);
string_clear(lfrfid->raw_file_name);
string_clear(lfrfid->file_name);
string_clear(lfrfid->file_path);
protocol_dict_free(lfrfid->dict);
lfrfid_worker_free(lfrfid->lfworker);
if(lfrfid->rpc_ctx) {
rpc_system_app_set_callback(lfrfid->rpc_ctx, NULL, NULL);
rpc_system_app_send_exited(lfrfid->rpc_ctx);
}
free(lfrfid->new_key_data);
free(lfrfid->old_key_data);
// Submenu
view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewSubmenu);
submenu_free(lfrfid->submenu);
// DialogEx
view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewDialogEx);
dialog_ex_free(lfrfid->dialog_ex);
// Popup
view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewPopup);
popup_free(lfrfid->popup);
// Widget
view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewWidget);
widget_free(lfrfid->widget);
// TextInput
view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewTextInput);
text_input_free(lfrfid->text_input);
// ByteInput
view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewByteInput);
byte_input_free(lfrfid->byte_input);
// Read custom view
view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewRead);
lfrfid_view_read_free(lfrfid->read_view);
// View Dispatcher
view_dispatcher_free(lfrfid->view_dispatcher);
// Scene Manager
scene_manager_free(lfrfid->scene_manager);
// GUI
furi_record_close(RECORD_GUI);
lfrfid->gui = NULL;
// Notifications
furi_record_close(RECORD_NOTIFICATION);
lfrfid->notifications = NULL;
furi_record_close(RECORD_STORAGE);
furi_record_close(RECORD_DIALOGS);
free(lfrfid);
}
int32_t lfrfid_app(void* p) {
LfRfid* app = lfrfid_alloc();
char* args = p;
lfrfid_make_app_folder(app);
if(args && strlen(args)) {
uint32_t rpc_ctx_ptr = 0;
if(sscanf(args, "RPC %lX", &rpc_ctx_ptr) == 1) {
app->rpc_ctx = (RpcAppSystem*)rpc_ctx_ptr;
rpc_system_app_set_callback(app->rpc_ctx, rpc_command_callback, app);
rpc_system_app_send_started(app->rpc_ctx);
view_dispatcher_attach_to_gui(
app->view_dispatcher, app->gui, ViewDispatcherTypeDesktop);
scene_manager_next_scene(app->scene_manager, LfRfidSceneRpc);
} else {
string_set_str(app->file_path, args);
lfrfid_load_key_data(app, app->file_path, true);
view_dispatcher_attach_to_gui(
app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate);
}
} else {
view_dispatcher_attach_to_gui(
app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
scene_manager_next_scene(app->scene_manager, LfRfidSceneStart);
}
view_dispatcher_run(app->view_dispatcher);
lfrfid_free(app);
return 0;
}
bool lfrfid_save_key(LfRfid* app) {
furi_assert(app);
bool result = false;
lfrfid_make_app_folder(app);
if(string_end_with_str_p(app->file_path, LFRFID_APP_EXTENSION)) {
size_t filename_start = string_search_rchar(app->file_path, '/');
string_left(app->file_path, filename_start);
}
string_cat_printf(
app->file_path, "/%s%s", string_get_cstr(app->file_name), LFRFID_APP_EXTENSION);
result = lfrfid_save_key_data(app, app->file_path);
return result;
}
bool lfrfid_load_key_from_file_select(LfRfid* app) {
furi_assert(app);
bool result = dialog_file_browser_show(
app->dialogs,
app->file_path,
app->file_path,
LFRFID_APP_EXTENSION,
true,
&I_125_10px,
true);
if(result) {
result = lfrfid_load_key_data(app, app->file_path, true);
}
return result;
}
bool lfrfid_delete_key(LfRfid* app) {
furi_assert(app);
return storage_simply_remove(app->storage, string_get_cstr(app->file_path));
}
bool lfrfid_load_key_data(LfRfid* app, string_t path, bool show_dialog) {
bool result = false;
do {
app->protocol_id = lfrfid_dict_file_load(app->dict, string_get_cstr(path));
if(app->protocol_id == PROTOCOL_NO) break;
path_extract_filename(path, app->file_name, true);
result = true;
} while(0);
if((!result) && (show_dialog)) {
dialog_message_show_storage_error(app->dialogs, "Cannot load\nkey file");
}
return result;
}
bool lfrfid_save_key_data(LfRfid* app, string_t path) {
bool result = lfrfid_dict_file_save(app->dict, app->protocol_id, string_get_cstr(path));
if(!result) {
dialog_message_show_storage_error(app->dialogs, "Cannot save\nkey file");
}
return result;
}
void lfrfid_make_app_folder(LfRfid* app) {
furi_assert(app);
if(!storage_simply_mkdir(app->storage, LFRFID_APP_FOLDER)) {
dialog_message_show_storage_error(app->dialogs, "Cannot create\napp folder");
}
}
void lfrfid_text_store_set(LfRfid* app, const char* text, ...) {
furi_assert(app);
va_list args;
va_start(args, text);
vsnprintf(app->text_store, LFRFID_TEXT_STORE_SIZE, text, args);
va_end(args);
}
void lfrfid_text_store_clear(LfRfid* app) {
furi_assert(app);
memset(app->text_store, 0, sizeof(app->text_store));
}
void lfrfid_popup_timeout_callback(void* context) {
LfRfid* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventPopupClosed);
}
void lfrfid_widget_callback(GuiButtonType result, InputType type, void* context) {
LfRfid* app = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(app->view_dispatcher, result);
}
}
void lfrfid_text_input_callback(void* context) {
LfRfid* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventNext);
}

View File

@ -1,218 +0,0 @@
#include "lfrfid_app.h"
#include "assets_icons.h"
#include <core/common_defines.h>
#include "m-string.h"
#include "scene/lfrfid_app_scene_start.h"
#include "scene/lfrfid_app_scene_read.h"
#include "scene/lfrfid_app_scene_read_success.h"
#include "scene/lfrfid_app_scene_retry_confirm.h"
#include "scene/lfrfid_app_scene_exit_confirm.h"
#include "scene/lfrfid_app_scene_read_menu.h"
#include "scene/lfrfid_app_scene_write.h"
#include "scene/lfrfid_app_scene_write_success.h"
#include "scene/lfrfid_app_scene_emulate.h"
#include "scene/lfrfid_app_scene_save_name.h"
#include "scene/lfrfid_app_scene_save_success.h"
#include "scene/lfrfid_app_scene_select_key.h"
#include "scene/lfrfid_app_scene_saved_key_menu.h"
#include "scene/lfrfid_app_scene_save_data.h"
#include "scene/lfrfid_app_scene_save_type.h"
#include "scene/lfrfid_app_scene_saved_info.h"
#include "scene/lfrfid_app_scene_delete_confirm.h"
#include "scene/lfrfid_app_scene_delete_success.h"
#include "scene/lfrfid_app_scene_rpc.h"
#include "scene/lfrfid_app_scene_extra_actions.h"
#include "scene/lfrfid_app_scene_raw_info.h"
#include "scene/lfrfid_app_scene_raw_name.h"
#include "scene/lfrfid_app_scene_raw_read.h"
#include "scene/lfrfid_app_scene_raw_success.h"
#include <toolbox/path.h>
#include <flipper_format/flipper_format.h>
#include <rpc/rpc_app.h>
const char* LfRfidApp::app_folder = ANY_PATH("lfrfid");
const char* LfRfidApp::app_sd_folder = EXT_PATH("lfrfid");
const char* LfRfidApp::app_extension = ".rfid";
const char* LfRfidApp::app_filetype = "Flipper RFID key";
LfRfidApp::LfRfidApp()
: scene_controller{this}
, notification{RECORD_NOTIFICATION}
, storage{RECORD_STORAGE}
, dialogs{RECORD_DIALOGS}
, text_store(40) {
string_init(file_name);
string_init(raw_file_name);
string_init_set_str(file_path, app_folder);
dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
size_t size = protocol_dict_get_max_data_size(dict);
new_key_data = (uint8_t*)malloc(size);
old_key_data = (uint8_t*)malloc(size);
lfworker = lfrfid_worker_alloc(dict);
}
LfRfidApp::~LfRfidApp() {
string_clear(raw_file_name);
string_clear(file_name);
string_clear(file_path);
protocol_dict_free(dict);
lfrfid_worker_free(lfworker);
if(rpc_ctx) {
rpc_system_app_set_callback(rpc_ctx, NULL, NULL);
rpc_system_app_send_exited(rpc_ctx);
}
free(new_key_data);
free(old_key_data);
}
static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) {
furi_assert(context);
LfRfidApp* app = static_cast<LfRfidApp*>(context);
if(rpc_event == RpcAppEventSessionClose) {
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::RpcSessionClose;
app->view_controller.send_event(&event);
// Detach RPC
rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL);
app->rpc_ctx = NULL;
} else if(rpc_event == RpcAppEventAppExit) {
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Exit;
app->view_controller.send_event(&event);
} else if(rpc_event == RpcAppEventLoadFile) {
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::RpcLoadFile;
app->view_controller.send_event(&event);
} else {
rpc_system_app_confirm(app->rpc_ctx, rpc_event, false);
}
}
void LfRfidApp::run(void* _args) {
const char* args = reinterpret_cast<const char*>(_args);
make_app_folder();
if(args && strlen(args)) {
uint32_t rpc_ctx_ptr = 0;
if(sscanf(args, "RPC %lX", &rpc_ctx_ptr) == 1) {
rpc_ctx = (RpcAppSystem*)rpc_ctx_ptr;
rpc_system_app_set_callback(rpc_ctx, rpc_command_callback, this);
rpc_system_app_send_started(rpc_ctx);
view_controller.attach_to_gui(ViewDispatcherTypeDesktop);
scene_controller.add_scene(SceneType::Rpc, new LfRfidAppSceneRpc());
scene_controller.process(100, SceneType::Rpc);
} else {
string_set_str(file_path, args);
load_key_data(file_path, true);
view_controller.attach_to_gui(ViewDispatcherTypeFullscreen);
scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate());
scene_controller.process(100, SceneType::Emulate);
}
} else {
view_controller.attach_to_gui(ViewDispatcherTypeFullscreen);
scene_controller.add_scene(SceneType::Start, new LfRfidAppSceneStart());
scene_controller.add_scene(SceneType::Read, new LfRfidAppSceneRead());
scene_controller.add_scene(SceneType::RetryConfirm, new LfRfidAppSceneRetryConfirm());
scene_controller.add_scene(SceneType::ExitConfirm, new LfRfidAppSceneExitConfirm());
scene_controller.add_scene(SceneType::ReadSuccess, new LfRfidAppSceneReadSuccess());
scene_controller.add_scene(SceneType::ReadKeyMenu, new LfRfidAppSceneReadKeyMenu());
scene_controller.add_scene(SceneType::Write, new LfRfidAppSceneWrite());
scene_controller.add_scene(SceneType::WriteSuccess, new LfRfidAppSceneWriteSuccess());
scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate());
scene_controller.add_scene(SceneType::SaveName, new LfRfidAppSceneSaveName());
scene_controller.add_scene(SceneType::SaveSuccess, new LfRfidAppSceneSaveSuccess());
scene_controller.add_scene(SceneType::SelectKey, new LfRfidAppSceneSelectKey());
scene_controller.add_scene(SceneType::SavedKeyMenu, new LfRfidAppSceneSavedKeyMenu());
scene_controller.add_scene(SceneType::SaveData, new LfRfidAppSceneSaveData());
scene_controller.add_scene(SceneType::SaveType, new LfRfidAppSceneSaveType());
scene_controller.add_scene(SceneType::SavedInfo, new LfRfidAppSceneSavedInfo());
scene_controller.add_scene(SceneType::DeleteConfirm, new LfRfidAppSceneDeleteConfirm());
scene_controller.add_scene(SceneType::DeleteSuccess, new LfRfidAppSceneDeleteSuccess());
scene_controller.add_scene(SceneType::ExtraActions, new LfRfidAppSceneExtraActions());
scene_controller.add_scene(SceneType::RawInfo, new LfRfidAppSceneRawInfo());
scene_controller.add_scene(SceneType::RawName, new LfRfidAppSceneRawName());
scene_controller.add_scene(SceneType::RawRead, new LfRfidAppSceneRawRead());
scene_controller.add_scene(SceneType::RawSuccess, new LfRfidAppSceneRawSuccess());
scene_controller.process(100);
}
}
bool LfRfidApp::save_key() {
bool result = false;
make_app_folder();
if(string_end_with_str_p(file_path, app_extension)) {
size_t filename_start = string_search_rchar(file_path, '/');
string_left(file_path, filename_start);
}
string_cat_printf(file_path, "/%s%s", string_get_cstr(file_name), app_extension);
result = save_key_data(file_path);
return result;
}
bool LfRfidApp::load_key_from_file_select(bool need_restore) {
if(!need_restore) {
string_set_str(file_path, app_folder);
}
bool result = dialog_file_browser_show(
dialogs, file_path, file_path, app_extension, true, &I_125_10px, true);
if(result) {
result = load_key_data(file_path, true);
}
return result;
}
bool LfRfidApp::delete_key() {
return storage_simply_remove(storage, string_get_cstr(file_path));
}
bool LfRfidApp::load_key_data(string_t path, bool show_dialog) {
bool result = false;
do {
protocol_id = lfrfid_dict_file_load(dict, string_get_cstr(path));
if(protocol_id == PROTOCOL_NO) break;
path_extract_filename(path, file_name, true);
result = true;
} while(0);
if((!result) && (show_dialog)) {
dialog_message_show_storage_error(dialogs, "Cannot load\nkey file");
}
return result;
}
bool LfRfidApp::save_key_data(string_t path) {
bool result = lfrfid_dict_file_save(dict, protocol_id, string_get_cstr(path));
if(!result) {
dialog_message_show_storage_error(dialogs, "Cannot save\nkey file");
}
return result;
}
void LfRfidApp::make_app_folder() {
if(!storage_simply_mkdir(storage, app_folder)) {
dialog_message_show_storage_error(dialogs, "Cannot create\napp folder");
}
}

View File

@ -1,137 +0,0 @@
#pragma once
#include "m-string.h"
#include <furi.h>
#include <furi_hal.h>
#include <generic_scene.hpp>
#include <scene_controller.hpp>
#include <view_controller.hpp>
#include <record_controller.hpp>
#include <text_store.h>
#include <view_modules/submenu_vm.h>
#include <view_modules/popup_vm.h>
#include <view_modules/dialog_ex_vm.h>
#include <view_modules/text_input_vm.h>
#include <view_modules/byte_input_vm.h>
#include "view/container_vm.h"
#include <notification/notification_messages.h>
#include <storage/storage.h>
#include <dialogs/dialogs.h>
#include "rpc/rpc_app.h"
#include <toolbox/protocols/protocol_dict.h>
#include <lfrfid/lfrfid_dict_file.h>
#include <lfrfid/protocols/lfrfid_protocols.h>
#include <lfrfid/lfrfid_worker.h>
#define LFRFID_KEY_NAME_SIZE 22
class LfRfidApp {
public:
enum class EventType : uint8_t {
GENERIC_EVENT_ENUM_VALUES,
Next,
MenuSelected,
Stay,
Retry,
Exit,
ReadEventSenseStart,
ReadEventSenseEnd,
ReadEventSenseCardStart,
ReadEventSenseCardEnd,
ReadEventStartASK,
ReadEventStartPSK,
ReadEventDone,
ReadEventOverrun,
ReadEventError,
WriteEventOK,
WriteEventProtocolCannotBeWritten,
WriteEventFobCannotBeWritten,
WriteEventTooLongToWrite,
RpcLoadFile,
RpcSessionClose,
};
enum class SceneType : uint8_t {
GENERIC_SCENE_ENUM_VALUES,
Read,
ReadSuccess,
RetryConfirm,
ExitConfirm,
ReadKeyMenu,
Write,
WriteSuccess,
Emulate,
SaveName,
SaveSuccess,
SelectKey,
SavedKeyMenu,
SaveData,
SaveType,
SavedInfo,
DeleteConfirm,
DeleteSuccess,
Rpc,
ExtraActions,
RawInfo,
RawName,
RawRead,
RawSuccess,
};
class Event {
public:
union {
int32_t signed_int;
} payload;
EventType type;
};
SceneController<GenericScene<LfRfidApp>, LfRfidApp> scene_controller;
ViewController<LfRfidApp, SubmenuVM, PopupVM, DialogExVM, TextInputVM, ByteInputVM, ContainerVM>
view_controller;
~LfRfidApp();
LfRfidApp();
RecordController<NotificationApp> notification;
RecordController<Storage> storage;
RecordController<DialogsApp> dialogs;
TextStore text_store;
string_t file_path;
RpcAppSystem* rpc_ctx;
void run(void* args);
static const char* app_folder;
static const char* app_sd_folder;
static const char* app_extension;
static const char* app_filetype;
bool save_key();
bool load_key_from_file_select(bool need_restore);
bool delete_key();
bool load_key_data(string_t path, bool show_dialog);
bool save_key_data(string_t path);
void make_app_folder();
ProtocolDict* dict;
LFRFIDWorker* lfworker;
string_t file_name;
ProtocolId protocol_id;
LFRFIDWorkerReadType read_type;
uint8_t* old_key_data;
uint8_t* new_key_data;
string_t raw_file_name;
};

View File

@ -1,10 +0,0 @@
#include "lfrfid_app.h"
// app enter function
extern "C" int32_t lfrfid_app(void* args) {
LfRfidApp* app = new LfRfidApp();
app->run(args);
delete app;
return 0;
}

View File

@ -114,7 +114,7 @@ static void lfrfid_cli_read(Cli* cli, string_t args) {
string_t info;
string_init(info);
protocol_dict_render_data(dict, info, context.protocol);
if(string_size(info) > 0) {
if(!string_empty_p(info)) {
printf("%s\r\n", string_get_cstr(info));
}
string_clear(info);

View File

@ -0,0 +1,145 @@
#pragma once
#include "m-string.h"
#include <furi.h>
#include <furi_hal.h>
#include <gui/gui.h>
#include <gui/view.h>
#include <gui/view_dispatcher.h>
#include <gui/scene_manager.h>
#include <cli/cli.h>
#include <notification/notification_messages.h>
#include <gui/modules/submenu.h>
#include <gui/modules/dialog_ex.h>
#include <gui/modules/popup.h>
#include <gui/modules/text_input.h>
#include <gui/modules/byte_input.h>
#include <gui/modules/widget.h>
#include <lfrfid/views/lfrfid_view_read.h>
#include <notification/notification_messages.h>
#include <dialogs/dialogs.h>
#include <storage/storage.h>
#include <flipper_format/flipper_format.h>
#include <rpc/rpc_app.h>
#include <toolbox/protocols/protocol_dict.h>
#include <toolbox/path.h>
#include <lfrfid/lfrfid_dict_file.h>
#include <lfrfid/protocols/lfrfid_protocols.h>
#include <lfrfid/lfrfid_worker.h>
#include <lfrfid/scenes/lfrfid_scene.h>
#define LFRFID_KEY_NAME_SIZE 22
#define LFRFID_TEXT_STORE_SIZE 40
#define LFRFID_APP_FOLDER ANY_PATH("lfrfid")
#define LFRFID_SD_FOLDER EXT_PATH("lfrfid")
#define LFRFID_APP_EXTENSION ".rfid"
#define LFRFID_APP_SHADOW_EXTENSION ".shd"
#define LFRFID_APP_RAW_ASK_EXTENSION ".ask.raw"
#define LFRFID_APP_RAW_PSK_EXTENSION ".psk.raw"
enum LfRfidCustomEvent {
LfRfidEventNext = 100,
LfRfidEventExit,
LfRfidEventPopupClosed,
LfRfidEventReadSenseStart,
LfRfidEventReadSenseEnd,
LfRfidEventReadSenseCardStart,
LfRfidEventReadSenseCardEnd,
LfRfidEventReadStartASK,
LfRfidEventReadStartPSK,
LfRfidEventReadDone,
LfRfidEventReadOverrun,
LfRfidEventReadError,
LfRfidEventWriteOK,
LfRfidEventWriteProtocolCannotBeWritten,
LfRfidEventWriteFobCannotBeWritten,
LfRfidEventWriteTooLongToWrite,
LfRfidEventRpcLoadFile,
LfRfidEventRpcSessionClose,
};
typedef enum {
LfRfidRpcStateIdle,
LfRfidRpcStateEmulating,
} LfRfidRpcState;
typedef struct LfRfid LfRfid;
struct LfRfid {
LFRFIDWorker* lfworker;
ViewDispatcher* view_dispatcher;
Gui* gui;
NotificationApp* notifications;
SceneManager* scene_manager;
Storage* storage;
DialogsApp* dialogs;
Widget* widget;
char text_store[LFRFID_TEXT_STORE_SIZE + 1];
string_t file_path;
string_t file_name;
string_t raw_file_name;
ProtocolDict* dict;
ProtocolId protocol_id;
ProtocolId protocol_id_next;
LFRFIDWorkerReadType read_type;
uint8_t* old_key_data;
uint8_t* new_key_data;
RpcAppSystem* rpc_ctx;
LfRfidRpcState rpc_state;
// Common Views
Submenu* submenu;
DialogEx* dialog_ex;
Popup* popup;
TextInput* text_input;
ByteInput* byte_input;
// Custom views
LfRfidReadView* read_view;
};
typedef enum {
LfRfidViewSubmenu,
LfRfidViewDialogEx,
LfRfidViewPopup,
LfRfidViewWidget,
LfRfidViewTextInput,
LfRfidViewByteInput,
LfRfidViewRead,
} LfRfidView;
bool lfrfid_save_key(LfRfid* app);
bool lfrfid_load_key_from_file_select(LfRfid* app);
bool lfrfid_delete_key(LfRfid* app);
bool lfrfid_load_key_data(LfRfid* app, string_t path, bool show_dialog);
bool lfrfid_save_key_data(LfRfid* app, string_t path);
void lfrfid_make_app_folder(LfRfid* app);
void lfrfid_text_store_set(LfRfid* app, const char* text, ...);
void lfrfid_text_store_clear(LfRfid* app);
void lfrfid_popup_timeout_callback(void* context);
void lfrfid_widget_callback(GuiButtonType result, InputType type, void* context);
void lfrfid_text_input_callback(void* context);

View File

@ -1,88 +0,0 @@
#include "lfrfid_app_scene_delete_confirm.h"
#include "../view/elements/button_element.h"
#include "../view/elements/icon_element.h"
#include "../view/elements/string_element.h"
void LfRfidAppSceneDeleteConfirm::on_enter(LfRfidApp* app, bool /* need_restore */) {
string_init(string_data);
string_init(string_header);
auto container = app->view_controller.get<ContainerVM>();
auto button = container->add<ButtonElement>();
button->set_type(ButtonElement::Type::Left, "Back");
button->set_callback(app, LfRfidAppSceneDeleteConfirm::back_callback);
button = container->add<ButtonElement>();
button->set_type(ButtonElement::Type::Right, "Delete");
button->set_callback(app, LfRfidAppSceneDeleteConfirm::delete_callback);
auto line_1 = container->add<StringElement>();
auto line_2 = container->add<StringElement>();
auto line_3 = container->add<StringElement>();
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(string_data, " ");
}
string_cat_printf(string_data, "%02X", data[i]);
}
free(data);
string_printf(string_header, "Delete %s?", string_get_cstr(app->file_name));
line_1->set_text(
string_get_cstr(string_header), 64, 0, 128 - 2, AlignCenter, AlignTop, FontPrimary);
line_2->set_text(
string_get_cstr(string_data), 64, 19, 0, AlignCenter, AlignTop, FontSecondary);
line_3->set_text(
protocol_dict_get_name(app->dict, app->protocol_id),
64,
49,
0,
AlignCenter,
AlignBottom,
FontSecondary);
app->view_controller.switch_to<ContainerVM>();
}
bool LfRfidAppSceneDeleteConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = false;
if(event->type == LfRfidApp::EventType::Next) {
app->delete_key();
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::DeleteSuccess);
consumed = true;
} else if(event->type == LfRfidApp::EventType::Stay) {
app->scene_controller.switch_to_previous_scene();
consumed = true;
} else if(event->type == LfRfidApp::EventType::Back) {
consumed = true;
}
return consumed;
}
void LfRfidAppSceneDeleteConfirm::on_exit(LfRfidApp* app) {
app->view_controller.get<ContainerVM>()->clean();
string_clear(string_data);
string_clear(string_header);
}
void LfRfidAppSceneDeleteConfirm::back_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Stay;
app->view_controller.send_event(&event);
}
void LfRfidAppSceneDeleteConfirm::delete_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Next;
app->view_controller.send_event(&event);
}

View File

@ -1,16 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneDeleteConfirm : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
static void back_callback(void* context);
static void delete_callback(void* context);
string_t string_header;
string_t string_data;
};

View File

@ -1,38 +0,0 @@
#include "lfrfid_app_scene_delete_success.h"
void LfRfidAppSceneDeleteSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) {
auto popup = app->view_controller.get<PopupVM>();
popup->set_icon(0, 2, &I_DolphinMafia_115x62);
popup->set_header("Deleted", 83, 19, AlignLeft, AlignBottom);
popup->set_context(app);
popup->set_callback(LfRfidAppSceneDeleteSuccess::timeout_callback);
popup->set_timeout(1500);
popup->enable_timeout();
app->view_controller.switch_to<PopupVM>();
}
bool LfRfidAppSceneDeleteSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = false;
if(event->type == LfRfidApp::EventType::Back) {
app->scene_controller.search_and_switch_to_previous_scene(
{LfRfidApp::SceneType::SelectKey});
consumed = true;
}
return consumed;
}
void LfRfidAppSceneDeleteSuccess::on_exit(LfRfidApp* app) {
app->view_controller.get<PopupVM>()->clean();
}
void LfRfidAppSceneDeleteSuccess::timeout_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Back;
app->view_controller.send_event(&event);
}

View File

@ -1,12 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneDeleteSuccess : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
static void timeout_callback(void* context);
};

View File

@ -1,36 +0,0 @@
#include "lfrfid_app_scene_emulate.h"
#include <core/common_defines.h>
#include <dolphin/dolphin.h>
void LfRfidAppSceneEmulate::on_enter(LfRfidApp* app, bool /* need_restore */) {
DOLPHIN_DEED(DolphinDeedRfidEmulate);
auto popup = app->view_controller.get<PopupVM>();
popup->set_header("Emulating", 89, 30, AlignCenter, AlignTop);
if(string_size(app->file_name)) {
popup->set_text(string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop);
} else {
popup->set_text(
protocol_dict_get_name(app->dict, app->protocol_id), 89, 43, AlignCenter, AlignTop);
}
popup->set_icon(0, 3, &I_RFIDDolphinSend_97x61);
app->view_controller.switch_to<PopupVM>();
lfrfid_worker_start_thread(app->lfworker);
lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id);
notification_message(app->notification, &sequence_blink_start_magenta);
}
bool LfRfidAppSceneEmulate::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
UNUSED(app);
UNUSED(event);
bool consumed = false;
return consumed;
}
void LfRfidAppSceneEmulate::on_exit(LfRfidApp* app) {
app->view_controller.get<PopupVM>()->clean();
lfrfid_worker_stop(app->lfworker);
lfrfid_worker_stop_thread(app->lfworker);
notification_message(app->notification, &sequence_blink_stop);
}

View File

@ -1,9 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneEmulate : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
};

View File

@ -1,59 +0,0 @@
#include "lfrfid_app_scene_exit_confirm.h"
#include "../view/elements/button_element.h"
#include "../view/elements/icon_element.h"
#include "../view/elements/string_element.h"
void LfRfidAppSceneExitConfirm::on_enter(LfRfidApp* app, bool /* need_restore */) {
auto container = app->view_controller.get<ContainerVM>();
auto button = container->add<ButtonElement>();
button->set_type(ButtonElement::Type::Left, "Exit");
button->set_callback(app, LfRfidAppSceneExitConfirm::exit_callback);
button = container->add<ButtonElement>();
button->set_type(ButtonElement::Type::Right, "Stay");
button->set_callback(app, LfRfidAppSceneExitConfirm::stay_callback);
auto line_1 = container->add<StringElement>();
auto line_2 = container->add<StringElement>();
line_1->set_text("Exit to RFID Menu?", 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary);
line_2->set_text(
"All unsaved data will be lost!", 64, 31, 0, AlignCenter, AlignBottom, FontSecondary);
app->view_controller.switch_to<ContainerVM>();
}
bool LfRfidAppSceneExitConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = false;
if(event->type == LfRfidApp::EventType::Next) {
app->scene_controller.search_and_switch_to_previous_scene({LfRfidApp::SceneType::Start});
consumed = true;
} else if(event->type == LfRfidApp::EventType::Stay) {
app->scene_controller.switch_to_previous_scene();
consumed = true;
} else if(event->type == LfRfidApp::EventType::Back) {
consumed = true;
}
return consumed;
}
void LfRfidAppSceneExitConfirm::on_exit(LfRfidApp* app) {
app->view_controller.get<ContainerVM>()->clean();
}
void LfRfidAppSceneExitConfirm::exit_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Next;
app->view_controller.send_event(&event);
}
void LfRfidAppSceneExitConfirm::stay_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Stay;
app->view_controller.send_event(&event);
}

View File

@ -1,13 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneExitConfirm : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
static void exit_callback(void* context);
static void stay_callback(void* context);
};

View File

@ -1,63 +0,0 @@
#include "lfrfid_app_scene_extra_actions.h"
typedef enum {
SubmenuASK,
SubmenuPSK,
SubmenuRAW,
} SubmenuIndex;
void LfRfidAppSceneExtraActions::on_enter(LfRfidApp* app, bool need_restore) {
auto submenu = app->view_controller.get<SubmenuVM>();
submenu->add_item("Read ASK (Animal, Ordinary Card)", SubmenuASK, submenu_callback, app);
submenu->add_item("Read PSK (Indala)", SubmenuPSK, submenu_callback, app);
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
submenu->add_item("Read RAW RFID data", SubmenuRAW, submenu_callback, app);
}
if(need_restore) {
submenu->set_selected_item(submenu_item_selected);
}
app->view_controller.switch_to<SubmenuVM>();
}
bool LfRfidAppSceneExtraActions::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = false;
if(event->type == LfRfidApp::EventType::MenuSelected) {
submenu_item_selected = event->payload.signed_int;
switch(event->payload.signed_int) {
case SubmenuASK:
app->read_type = LFRFIDWorkerReadTypeASKOnly;
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Read);
break;
case SubmenuPSK:
app->read_type = LFRFIDWorkerReadTypePSKOnly;
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Read);
break;
case SubmenuRAW:
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::RawName);
break;
}
consumed = true;
}
return consumed;
}
void LfRfidAppSceneExtraActions::on_exit(LfRfidApp* app) {
app->view_controller.get<SubmenuVM>()->clean();
}
void LfRfidAppSceneExtraActions::submenu_callback(void* context, uint32_t index) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::MenuSelected;
event.payload.signed_int = index;
app->view_controller.send_event(&event);
}

View File

@ -1,13 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneExtraActions : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
static void submenu_callback(void* context, uint32_t index);
uint32_t submenu_item_selected = 0;
};

View File

@ -1,77 +0,0 @@
#include "lfrfid_app_scene_raw_info.h"
#include "../view/elements/button_element.h"
#include "../view/elements/icon_element.h"
#include "../view/elements/string_element.h"
static void ok_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Next;
app->view_controller.send_event(&event);
}
static void back_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Back;
app->view_controller.send_event(&event);
}
void LfRfidAppSceneRawInfo::on_enter(LfRfidApp* app, bool /* need_restore */) {
string_init(string_info);
auto container = app->view_controller.get<ContainerVM>();
bool sd_exist = storage_sd_status(app->storage) == FSE_OK;
if(!sd_exist) {
auto icon = container->add<IconElement>();
icon->set_icon(0, 0, &I_SDQuestion_35x43);
auto line = container->add<StringElement>();
line->set_text(
"No SD card found.\nThis function will not\nwork without\nSD card.",
81,
4,
0,
AlignCenter,
AlignTop,
FontSecondary);
auto button = container->add<ButtonElement>();
button->set_type(ButtonElement::Type::Left, "Back");
button->set_callback(app, back_callback);
} else {
string_printf(
string_info,
"RAW RFID data reader\r\n"
"1) Put the Flipper on your card\r\n"
"2) Press OK\r\n"
"3) Wait until data is read");
auto line = container->add<StringElement>();
line->set_text(string_get_cstr(string_info), 0, 1, 0, AlignLeft, AlignTop, FontSecondary);
auto button = container->add<ButtonElement>();
button->set_type(ButtonElement::Type::Center, "OK");
button->set_callback(app, ok_callback);
}
app->view_controller.switch_to<ContainerVM>();
}
bool LfRfidAppSceneRawInfo::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = false;
if(event->type == LfRfidApp::EventType::Next) {
app->scene_controller.switch_to_scene({LfRfidApp::SceneType::RawRead});
consumed = true;
} else if(event->type == LfRfidApp::EventType::Back) {
app->scene_controller.search_and_switch_to_previous_scene(
{LfRfidApp::SceneType::ExtraActions});
consumed = true;
}
return consumed;
}
void LfRfidAppSceneRawInfo::on_exit(LfRfidApp* app) {
app->view_controller.get<ContainerVM>()->clean();
string_clear(string_info);
}

View File

@ -1,12 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneRawInfo : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
string_t string_info;
};

View File

@ -1,46 +0,0 @@
#include "lfrfid_app_scene_raw_name.h"
#include "m-string.h"
#include <lib/toolbox/random_name.h>
#include <lib/toolbox/path.h>
void LfRfidAppSceneRawName::on_enter(LfRfidApp* app, bool /* need_restore */) {
const char* key_name = string_get_cstr(app->raw_file_name);
bool key_name_empty = (string_size(app->raw_file_name) == 0);
if(key_name_empty) {
app->text_store.set("RfidRecord");
} else {
app->text_store.set("%s", key_name);
}
auto text_input = app->view_controller.get<TextInputVM>();
text_input->set_header_text("Name the raw file");
text_input->set_result_callback(
save_callback, app, app->text_store.text, LFRFID_KEY_NAME_SIZE, key_name_empty);
app->view_controller.switch_to<TextInputVM>();
}
bool LfRfidAppSceneRawName::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = false;
if(event->type == LfRfidApp::EventType::Next) {
string_set_str(app->raw_file_name, app->text_store.text);
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::RawInfo);
}
return consumed;
}
void LfRfidAppSceneRawName::on_exit(LfRfidApp* app) {
app->view_controller.get<TextInputVM>()->clean();
}
void LfRfidAppSceneRawName::save_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Next;
app->view_controller.send_event(&event);
}

View File

@ -1,12 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneRawName : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
static void save_callback(void* context);
};

View File

@ -1,107 +0,0 @@
#include "lfrfid_app_scene_raw_read.h"
#include <dolphin/dolphin.h>
#define RAW_READ_TIME 5000
static void lfrfid_read_callback(LFRFIDWorkerReadRawResult result, void* ctx) {
LfRfidApp* app = static_cast<LfRfidApp*>(ctx);
LfRfidApp::Event event;
switch(result) {
case LFRFIDWorkerReadRawFileError:
event.type = LfRfidApp::EventType::ReadEventError;
break;
case LFRFIDWorkerReadRawOverrun:
event.type = LfRfidApp::EventType::ReadEventOverrun;
break;
}
app->view_controller.send_event(&event);
}
static void timer_callback(void* ctx) {
LfRfidApp* app = static_cast<LfRfidApp*>(ctx);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::ReadEventDone;
app->view_controller.send_event(&event);
}
void LfRfidAppSceneRawRead::on_enter(LfRfidApp* app, bool /* need_restore */) {
string_init(string_file_name);
auto popup = app->view_controller.get<PopupVM>();
popup->set_icon(0, 3, &I_RFIDDolphinReceive_97x61);
app->view_controller.switch_to<PopupVM>();
lfrfid_worker_start_thread(app->lfworker);
app->make_app_folder();
timer = furi_timer_alloc(timer_callback, FuriTimerTypeOnce, app);
furi_timer_start(timer, RAW_READ_TIME);
string_printf(
string_file_name, "%s/%s.ask.raw", app->app_sd_folder, string_get_cstr(app->raw_file_name));
popup->set_header("Reading\nRAW RFID\nASK", 89, 30, AlignCenter, AlignTop);
lfrfid_worker_read_raw_start(
app->lfworker,
string_get_cstr(string_file_name),
LFRFIDWorkerReadTypeASKOnly,
lfrfid_read_callback,
app);
notification_message(app->notification, &sequence_blink_start_cyan);
is_psk = false;
error = false;
}
bool LfRfidAppSceneRawRead::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
UNUSED(app);
bool consumed = true;
auto popup = app->view_controller.get<PopupVM>();
switch(event->type) {
case LfRfidApp::EventType::ReadEventError:
error = true;
popup->set_header("Reading\nRAW RFID\nFile error", 89, 30, AlignCenter, AlignTop);
notification_message(app->notification, &sequence_blink_start_red);
furi_timer_stop(timer);
break;
case LfRfidApp::EventType::ReadEventDone:
if(!error) {
if(is_psk) {
notification_message(app->notification, &sequence_success);
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::RawSuccess);
} else {
popup->set_header("Reading\nRAW RFID\nPSK", 89, 30, AlignCenter, AlignTop);
notification_message(app->notification, &sequence_blink_start_yellow);
lfrfid_worker_stop(app->lfworker);
string_printf(
string_file_name,
"%s/%s.psk.raw",
app->app_sd_folder,
string_get_cstr(app->raw_file_name));
lfrfid_worker_read_raw_start(
app->lfworker,
string_get_cstr(string_file_name),
LFRFIDWorkerReadTypePSKOnly,
lfrfid_read_callback,
app);
furi_timer_start(timer, RAW_READ_TIME);
is_psk = true;
}
}
break;
default:
consumed = false;
break;
}
return consumed;
}
void LfRfidAppSceneRawRead::on_exit(LfRfidApp* app) {
notification_message(app->notification, &sequence_blink_stop);
app->view_controller.get<PopupVM>()->clean();
lfrfid_worker_stop(app->lfworker);
lfrfid_worker_stop_thread(app->lfworker);
furi_timer_free(timer);
string_clear(string_file_name);
}

View File

@ -1,15 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneRawRead : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
string_t string_file_name;
FuriTimer* timer;
bool is_psk;
bool error;
};

View File

@ -1,45 +0,0 @@
#include "lfrfid_app_scene_raw_success.h"
#include "../view/elements/button_element.h"
#include "../view/elements/icon_element.h"
#include "../view/elements/string_element.h"
void LfRfidAppSceneRawSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) {
string_init(string_info);
string_printf(string_info, "RAW RFID read success!\r\n");
string_cat_printf(string_info, "Now you can analyze files\r\n");
string_cat_printf(string_info, "Or send them to developers");
auto container = app->view_controller.get<ContainerVM>();
auto line = container->add<StringElement>();
line->set_text(string_get_cstr(string_info), 0, 1, 0, AlignLeft, AlignTop, FontSecondary);
auto button = container->add<ButtonElement>();
button->set_type(ButtonElement::Type::Center, "OK");
button->set_callback(app, LfRfidAppSceneRawSuccess::ok_callback);
app->view_controller.switch_to<ContainerVM>();
}
bool LfRfidAppSceneRawSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = false;
if(event->type == LfRfidApp::EventType::Next) {
app->scene_controller.search_and_switch_to_previous_scene(
{LfRfidApp::SceneType::ExtraActions});
consumed = true;
}
return consumed;
}
void LfRfidAppSceneRawSuccess::on_exit(LfRfidApp* app) {
app->view_controller.get<ContainerVM>()->clean();
string_clear(string_info);
}
void LfRfidAppSceneRawSuccess::ok_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Next;
app->view_controller.send_event(&event);
}

View File

@ -1,13 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneRawSuccess : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
string_t string_info;
static void ok_callback(void* context);
};

View File

@ -1,100 +0,0 @@
#include "lfrfid_app_scene_read.h"
#include <dolphin/dolphin.h>
static void lfrfid_read_callback(LFRFIDWorkerReadResult result, ProtocolId protocol, void* ctx) {
LfRfidApp* app = static_cast<LfRfidApp*>(ctx);
LfRfidApp::Event event;
switch(result) {
case LFRFIDWorkerReadSenseStart:
event.type = LfRfidApp::EventType::ReadEventSenseStart;
break;
case LFRFIDWorkerReadSenseEnd:
event.type = LfRfidApp::EventType::ReadEventSenseEnd;
break;
case LFRFIDWorkerReadSenseCardStart:
event.type = LfRfidApp::EventType::ReadEventSenseCardStart;
break;
case LFRFIDWorkerReadSenseCardEnd:
event.type = LfRfidApp::EventType::ReadEventSenseCardEnd;
break;
case LFRFIDWorkerReadDone:
event.type = LfRfidApp::EventType::ReadEventDone;
break;
case LFRFIDWorkerReadStartASK:
event.type = LfRfidApp::EventType::ReadEventStartASK;
break;
case LFRFIDWorkerReadStartPSK:
event.type = LfRfidApp::EventType::ReadEventStartPSK;
break;
}
event.payload.signed_int = protocol;
app->view_controller.send_event(&event);
}
void LfRfidAppSceneRead::on_enter(LfRfidApp* app, bool /* need_restore */) {
auto popup = app->view_controller.get<PopupVM>();
DOLPHIN_DEED(DolphinDeedRfidRead);
if(app->read_type == LFRFIDWorkerReadTypePSKOnly) {
popup->set_header("Reading\nLF RFID\nPSK", 89, 30, AlignCenter, AlignTop);
} else {
popup->set_header("Reading\nLF RFID\nASK", 89, 30, AlignCenter, AlignTop);
}
popup->set_icon(0, 3, &I_RFIDDolphinReceive_97x61);
app->view_controller.switch_to<PopupVM>();
lfrfid_worker_start_thread(app->lfworker);
lfrfid_worker_read_start(app->lfworker, app->read_type, lfrfid_read_callback, app);
notification_message(app->notification, &sequence_blink_start_cyan);
}
bool LfRfidAppSceneRead::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = true;
auto popup = app->view_controller.get<PopupVM>();
switch(event->type) {
case LfRfidApp::EventType::ReadEventSenseStart:
notification_message(app->notification, &sequence_blink_stop);
notification_message(app->notification, &sequence_blink_start_yellow);
break;
case LfRfidApp::EventType::ReadEventSenseCardStart:
notification_message(app->notification, &sequence_blink_stop);
notification_message(app->notification, &sequence_blink_start_green);
break;
case LfRfidApp::EventType::ReadEventSenseEnd:
case LfRfidApp::EventType::ReadEventSenseCardEnd:
notification_message(app->notification, &sequence_blink_stop);
notification_message(app->notification, &sequence_blink_start_cyan);
break;
case LfRfidApp::EventType::ReadEventDone:
app->protocol_id = event->payload.signed_int;
DOLPHIN_DEED(DolphinDeedRfidReadSuccess);
notification_message(app->notification, &sequence_success);
string_reset(app->file_name);
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadSuccess);
break;
case LfRfidApp::EventType::ReadEventStartPSK:
popup->set_header("Reading\nLF RFID\nPSK", 89, 30, AlignCenter, AlignTop);
break;
case LfRfidApp::EventType::ReadEventStartASK:
popup->set_header("Reading\nLF RFID\nASK", 89, 30, AlignCenter, AlignTop);
break;
default:
consumed = false;
break;
}
return consumed;
}
void LfRfidAppSceneRead::on_exit(LfRfidApp* app) {
notification_message(app->notification, &sequence_blink_stop);
app->view_controller.get<PopupVM>()->clean();
lfrfid_worker_stop(app->lfworker);
lfrfid_worker_stop_thread(app->lfworker);
}

View File

@ -1,9 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneRead : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
};

View File

@ -1,60 +0,0 @@
#include "lfrfid_app_scene_read_menu.h"
typedef enum {
SubmenuSave,
SubmenuEmulate,
SubmenuWrite,
} SubmenuIndex;
void LfRfidAppSceneReadKeyMenu::on_enter(LfRfidApp* app, bool need_restore) {
auto submenu = app->view_controller.get<SubmenuVM>();
submenu->add_item("Save", SubmenuSave, submenu_callback, app);
submenu->add_item("Emulate", SubmenuEmulate, submenu_callback, app);
submenu->add_item("Write", SubmenuWrite, submenu_callback, app);
if(need_restore) {
submenu->set_selected_item(submenu_item_selected);
}
app->view_controller.switch_to<SubmenuVM>();
}
bool LfRfidAppSceneReadKeyMenu::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = false;
if(event->type == LfRfidApp::EventType::MenuSelected) {
submenu_item_selected = event->payload.signed_int;
switch(event->payload.signed_int) {
case SubmenuWrite:
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Write);
break;
case SubmenuSave:
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveName);
break;
case SubmenuEmulate:
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Emulate);
break;
}
consumed = true;
} else if(event->type == LfRfidApp::EventType::Back) {
app->scene_controller.switch_to_previous_scene();
consumed = true;
}
return consumed;
}
void LfRfidAppSceneReadKeyMenu::on_exit(LfRfidApp* app) {
app->view_controller.get<SubmenuVM>()->clean();
}
void LfRfidAppSceneReadKeyMenu::submenu_callback(void* context, uint32_t index) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::MenuSelected;
event.payload.signed_int = index;
app->view_controller.send_event(&event);
}

View File

@ -1,13 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneReadKeyMenu : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
static void submenu_callback(void* context, uint32_t index);
uint32_t submenu_item_selected = 0;
};

View File

@ -1,96 +0,0 @@
#include "lfrfid_app_scene_read_success.h"
#include "../view/elements/button_element.h"
#include "../view/elements/icon_element.h"
#include "../view/elements/string_element.h"
void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) {
string_init(string_info);
string_init(string_header);
string_init_printf(
string_header,
"%s[%s]",
protocol_dict_get_name(app->dict, app->protocol_id),
protocol_dict_get_manufacturer(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(string_info, " ");
}
if(i >= 9) {
string_cat_printf(string_info, "...");
break;
} else {
string_cat_printf(string_info, "%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(string_info, "\r\n%s", string_get_cstr(render_data));
string_clear(render_data);
auto container = app->view_controller.get<ContainerVM>();
auto button = container->add<ButtonElement>();
button->set_type(ButtonElement::Type::Left, "Retry");
button->set_callback(app, LfRfidAppSceneReadSuccess::back_callback);
button = container->add<ButtonElement>();
button->set_type(ButtonElement::Type::Right, "More");
button->set_callback(app, LfRfidAppSceneReadSuccess::more_callback);
auto header = container->add<StringElement>();
header->set_text(string_get_cstr(string_header), 0, 2, 0, AlignLeft, AlignTop, FontPrimary);
auto text = container->add<StringElement>();
text->set_text(string_get_cstr(string_info), 0, 16, 0, AlignLeft, AlignTop, FontSecondary);
app->view_controller.switch_to<ContainerVM>();
notification_message_block(app->notification, &sequence_set_green_255);
}
bool LfRfidAppSceneReadSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = false;
if(event->type == LfRfidApp::EventType::Next) {
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadKeyMenu);
consumed = true;
} else if(event->type == LfRfidApp::EventType::Retry) {
app->scene_controller.switch_to_next_scene({LfRfidApp::SceneType::RetryConfirm});
consumed = true;
} else if(event->type == LfRfidApp::EventType::Back) {
app->scene_controller.switch_to_next_scene({LfRfidApp::SceneType::ExitConfirm});
consumed = true;
}
return consumed;
}
void LfRfidAppSceneReadSuccess::on_exit(LfRfidApp* app) {
notification_message_block(app->notification, &sequence_reset_green);
app->view_controller.get<ContainerVM>()->clean();
string_clear(string_info);
string_clear(string_header);
}
void LfRfidAppSceneReadSuccess::back_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Retry;
app->view_controller.send_event(&event);
}
void LfRfidAppSceneReadSuccess::more_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Next;
app->view_controller.send_event(&event);
}

View File

@ -1,16 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneReadSuccess : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
static void back_callback(void* context);
static void more_callback(void* context);
string_t string_header;
string_t string_info;
};

View File

@ -1,59 +0,0 @@
#include "lfrfid_app_scene_retry_confirm.h"
#include "../view/elements/button_element.h"
#include "../view/elements/icon_element.h"
#include "../view/elements/string_element.h"
void LfRfidAppSceneRetryConfirm::on_enter(LfRfidApp* app, bool /* need_restore */) {
auto container = app->view_controller.get<ContainerVM>();
auto button = container->add<ButtonElement>();
button->set_type(ButtonElement::Type::Left, "Exit");
button->set_callback(app, LfRfidAppSceneRetryConfirm::exit_callback);
button = container->add<ButtonElement>();
button->set_type(ButtonElement::Type::Right, "Stay");
button->set_callback(app, LfRfidAppSceneRetryConfirm::stay_callback);
auto line_1 = container->add<StringElement>();
auto line_2 = container->add<StringElement>();
line_1->set_text("Return to Reading?", 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary);
line_2->set_text(
"All unsaved data will be lost!", 64, 29, 0, AlignCenter, AlignBottom, FontSecondary);
app->view_controller.switch_to<ContainerVM>();
}
bool LfRfidAppSceneRetryConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = false;
if(event->type == LfRfidApp::EventType::Next) {
app->scene_controller.search_and_switch_to_previous_scene({LfRfidApp::SceneType::Read});
consumed = true;
} else if(event->type == LfRfidApp::EventType::Stay) {
app->scene_controller.switch_to_previous_scene();
consumed = true;
} else if(event->type == LfRfidApp::EventType::Back) {
consumed = true;
}
return consumed;
}
void LfRfidAppSceneRetryConfirm::on_exit(LfRfidApp* app) {
app->view_controller.get<ContainerVM>()->clean();
}
void LfRfidAppSceneRetryConfirm::exit_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Next;
app->view_controller.send_event(&event);
}
void LfRfidAppSceneRetryConfirm::stay_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Stay;
app->view_controller.send_event(&event);
}

View File

@ -1,13 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneRetryConfirm : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
static void exit_callback(void* context);
static void stay_callback(void* context);
};

View File

@ -1,66 +0,0 @@
#include "lfrfid_app_scene_rpc.h"
#include <core/common_defines.h>
#include <dolphin/dolphin.h>
#include <rpc/rpc_app.h>
void LfRfidAppSceneRpc::on_enter(LfRfidApp* app, bool /* need_restore */) {
auto popup = app->view_controller.get<PopupVM>();
popup->set_header("LF RFID", 89, 42, AlignCenter, AlignBottom);
popup->set_text("RPC mode", 89, 44, AlignCenter, AlignTop);
popup->set_icon(0, 12, &I_RFIDDolphinSend_97x61);
app->view_controller.switch_to<PopupVM>();
notification_message(app->notification, &sequence_display_backlight_on);
}
bool LfRfidAppSceneRpc::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
UNUSED(app);
UNUSED(event);
bool consumed = false;
if(event->type == LfRfidApp::EventType::Exit) {
consumed = true;
LfRfidApp::Event view_event;
view_event.type = LfRfidApp::EventType::Back;
app->view_controller.send_event(&view_event);
rpc_system_app_confirm(app->rpc_ctx, RpcAppEventAppExit, true);
} else if(event->type == LfRfidApp::EventType::RpcSessionClose) {
consumed = true;
LfRfidApp::Event view_event;
view_event.type = LfRfidApp::EventType::Back;
app->view_controller.send_event(&view_event);
} else if(event->type == LfRfidApp::EventType::RpcLoadFile) {
const char* arg = rpc_system_app_get_data(app->rpc_ctx);
consumed = true;
bool result = false;
if(arg && !emulating) {
string_set_str(app->file_path, arg);
if(app->load_key_data(app->file_path, false)) {
lfrfid_worker_start_thread(app->lfworker);
lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id);
emulating = true;
auto popup = app->view_controller.get<PopupVM>();
app->text_store.set("emulating\n%s", string_get_cstr(app->file_name));
popup->set_text(app->text_store.text, 89, 44, AlignCenter, AlignTop);
notification_message(app->notification, &sequence_blink_start_magenta);
result = true;
}
}
rpc_system_app_confirm(app->rpc_ctx, RpcAppEventLoadFile, result);
}
return consumed;
}
void LfRfidAppSceneRpc::on_exit(LfRfidApp* app) {
if(emulating) {
lfrfid_worker_stop(app->lfworker);
lfrfid_worker_stop_thread(app->lfworker);
notification_message(app->notification, &sequence_blink_stop);
}
app->view_controller.get<PopupVM>()->clean();
}

View File

@ -1,12 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneRpc : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
bool emulating = false;
};

View File

@ -1,45 +0,0 @@
#include "lfrfid_app_scene_save_data.h"
#include <dolphin/dolphin.h>
void LfRfidAppSceneSaveData::on_enter(LfRfidApp* app, bool need_restore) {
auto byte_input = app->view_controller.get<ByteInputVM>();
size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
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("Enter the data in hex");
byte_input->set_result_callback(save_callback, NULL, app, app->new_key_data, size);
app->view_controller.switch_to<ByteInputVM>();
}
bool LfRfidAppSceneSaveData::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = false;
if(event->type == LfRfidApp::EventType::Next) {
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);
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveName);
}
return consumed;
}
void LfRfidAppSceneSaveData::on_exit(LfRfidApp* app) {
app->view_controller.get<ByteInputVM>()->clean();
}
void LfRfidAppSceneSaveData::save_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Next;
app->view_controller.send_event(&event);
}

View File

@ -1,12 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneSaveData : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
static void save_callback(void* context);
};

View File

@ -1,72 +0,0 @@
#include "lfrfid_app_scene_save_name.h"
#include "m-string.h"
#include <lib/toolbox/random_name.h>
#include <lib/toolbox/path.h>
void LfRfidAppSceneSaveName::on_enter(LfRfidApp* app, bool /* need_restore */) {
const char* key_name = string_get_cstr(app->file_name);
bool key_name_empty = (string_size(app->file_name) == 0);
if(key_name_empty) {
string_set_str(app->file_path, app->app_folder);
set_random_name(app->text_store.text, app->text_store.text_size);
} else {
app->text_store.set("%s", key_name);
}
auto text_input = app->view_controller.get<TextInputVM>();
text_input->set_header_text("Name the card");
text_input->set_result_callback(
save_callback, app, app->text_store.text, LFRFID_KEY_NAME_SIZE, key_name_empty);
string_t folder_path;
string_init(folder_path);
path_extract_dirname(string_get_cstr(app->file_path), folder_path);
ValidatorIsFile* validator_is_file =
validator_is_file_alloc_init(string_get_cstr(folder_path), app->app_extension, key_name);
text_input->set_validator(validator_is_file_callback, validator_is_file);
string_clear(folder_path);
app->view_controller.switch_to<TextInputVM>();
}
bool LfRfidAppSceneSaveName::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = false;
if(event->type == LfRfidApp::EventType::Next) {
if(string_size(app->file_name) > 0) {
app->delete_key();
}
string_set_str(app->file_name, app->text_store.text);
if(app->save_key()) {
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveSuccess);
} else {
app->scene_controller.search_and_switch_to_previous_scene(
{LfRfidApp::SceneType::ReadKeyMenu});
}
}
return consumed;
}
void LfRfidAppSceneSaveName::on_exit(LfRfidApp* app) {
void* validator_context =
app->view_controller.get<TextInputVM>()->get_validator_callback_context();
app->view_controller.get<TextInputVM>()->set_validator(NULL, NULL);
validator_is_file_free((ValidatorIsFile*)validator_context);
app->view_controller.get<TextInputVM>()->clean();
}
void LfRfidAppSceneSaveName::save_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Next;
app->view_controller.send_event(&event);
}

View File

@ -1,12 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneSaveName : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
static void save_callback(void* context);
};

View File

@ -1,50 +0,0 @@
#include "lfrfid_app_scene_save_success.h"
#include <gui/scene_manager.h>
#include <dolphin/dolphin.h>
#include <stdint.h>
void LfRfidAppSceneSaveSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) {
auto popup = app->view_controller.get<PopupVM>();
DOLPHIN_DEED(DolphinDeedRfidSave);
popup->set_icon(32, 5, &I_DolphinNice_96x59);
popup->set_header("Saved!", 5, 7, AlignLeft, AlignTop);
popup->set_context(app);
popup->set_callback(LfRfidAppSceneSaveSuccess::timeout_callback);
popup->set_timeout(1500);
popup->enable_timeout();
app->view_controller.switch_to<PopupVM>();
}
bool LfRfidAppSceneSaveSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = false;
if(event->type == LfRfidApp::EventType::Back) {
bool result = app->scene_controller.has_previous_scene(
{LfRfidApp::SceneType::ReadKeyMenu, LfRfidApp::SceneType::SelectKey});
if(result) {
app->scene_controller.search_and_switch_to_previous_scene(
{LfRfidApp::SceneType::ReadKeyMenu, LfRfidApp::SceneType::SelectKey});
} else {
app->scene_controller.search_and_switch_to_another_scene(
{LfRfidApp::SceneType::SaveType}, LfRfidApp::SceneType::SelectKey);
}
consumed = true;
}
return consumed;
}
void LfRfidAppSceneSaveSuccess::on_exit(LfRfidApp* app) {
app->view_controller.get<PopupVM>()->clean();
}
void LfRfidAppSceneSaveSuccess::timeout_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Back;
app->view_controller.send_event(&event);
}

View File

@ -1,12 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneSaveSuccess : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
static void timeout_callback(void* context);
};

View File

@ -1,53 +0,0 @@
#include "lfrfid_app_scene_save_type.h"
void LfRfidAppSceneSaveType::on_enter(LfRfidApp* app, bool need_restore) {
auto submenu = app->view_controller.get<SubmenuVM>();
for(uint8_t i = 0; i < keys_count; i++) {
string_init_printf(
submenu_name[i],
"%s %s",
protocol_dict_get_manufacturer(app->dict, i),
protocol_dict_get_name(app->dict, i));
submenu->add_item(string_get_cstr(submenu_name[i]), i, submenu_callback, app);
}
if(need_restore) {
submenu->set_selected_item(submenu_item_selected);
}
app->view_controller.switch_to<SubmenuVM>();
// clear key name
string_reset(app->file_name);
}
bool LfRfidAppSceneSaveType::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = false;
if(event->type == LfRfidApp::EventType::MenuSelected) {
submenu_item_selected = event->payload.signed_int;
app->protocol_id = event->payload.signed_int;
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveData);
consumed = true;
}
return consumed;
}
void LfRfidAppSceneSaveType::on_exit(LfRfidApp* app) {
app->view_controller.get<SubmenuVM>()->clean();
for(uint8_t i = 0; i < keys_count; i++) {
string_clear(submenu_name[i]);
}
}
void LfRfidAppSceneSaveType::submenu_callback(void* context, uint32_t index) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::MenuSelected;
event.payload.signed_int = index;
app->view_controller.send_event(&event);
}

View File

@ -1,15 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneSaveType : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
static void submenu_callback(void* context, uint32_t index);
uint32_t submenu_item_selected = 0;
static const uint8_t keys_count = static_cast<uint8_t>(LFRFIDProtocol::LFRFIDProtocolMax);
string_t submenu_name[keys_count];
};

View File

@ -1,48 +0,0 @@
#include "lfrfid_app_scene_saved_info.h"
#include "../view/elements/button_element.h"
#include "../view/elements/icon_element.h"
#include "../view/elements/string_element.h"
void LfRfidAppSceneSavedInfo::on_enter(LfRfidApp* app, bool /* need_restore */) {
string_init(string_info);
string_printf(
string_info,
"%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(string_info, " ");
}
string_cat_printf(string_info, "%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(string_info, "\r\n%s", string_get_cstr(render_data));
string_clear(render_data);
auto container = app->view_controller.get<ContainerVM>();
auto line_1 = container->add<StringElement>();
line_1->set_text(string_get_cstr(string_info), 0, 1, 0, AlignLeft, AlignTop, FontSecondary);
app->view_controller.switch_to<ContainerVM>();
}
bool LfRfidAppSceneSavedInfo::on_event(LfRfidApp* /* app */, LfRfidApp::Event* /* event */) {
return false;
}
void LfRfidAppSceneSavedInfo::on_exit(LfRfidApp* app) {
app->view_controller.get<ContainerVM>()->clean();
string_clear(string_info);
}

View File

@ -1,12 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneSavedInfo : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
string_t string_info;
};

View File

@ -1,67 +0,0 @@
#include "lfrfid_app_scene_saved_key_menu.h"
typedef enum {
SubmenuEmulate,
SubmenuWrite,
SubmenuEdit,
SubmenuDelete,
SubmenuInfo,
} SubmenuIndex;
void LfRfidAppSceneSavedKeyMenu::on_enter(LfRfidApp* app, bool need_restore) {
auto submenu = app->view_controller.get<SubmenuVM>();
submenu->add_item("Emulate", SubmenuEmulate, submenu_callback, app);
submenu->add_item("Write", SubmenuWrite, submenu_callback, app);
submenu->add_item("Edit", SubmenuEdit, submenu_callback, app);
submenu->add_item("Delete", SubmenuDelete, submenu_callback, app);
submenu->add_item("Info", SubmenuInfo, submenu_callback, app);
if(need_restore) {
submenu->set_selected_item(submenu_item_selected);
}
app->view_controller.switch_to<SubmenuVM>();
}
bool LfRfidAppSceneSavedKeyMenu::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = false;
if(event->type == LfRfidApp::EventType::MenuSelected) {
submenu_item_selected = event->payload.signed_int;
switch(event->payload.signed_int) {
case SubmenuEmulate:
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Emulate);
break;
case SubmenuWrite:
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Write);
break;
case SubmenuEdit:
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveData);
break;
case SubmenuDelete:
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::DeleteConfirm);
break;
case SubmenuInfo:
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SavedInfo);
break;
}
consumed = true;
}
return consumed;
}
void LfRfidAppSceneSavedKeyMenu::on_exit(LfRfidApp* app) {
app->view_controller.get<SubmenuVM>()->clean();
}
void LfRfidAppSceneSavedKeyMenu::submenu_callback(void* context, uint32_t index) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::MenuSelected;
event.payload.signed_int = index;
app->view_controller.send_event(&event);
}

View File

@ -1,13 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneSavedKeyMenu : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
static void submenu_callback(void* context, uint32_t index);
uint32_t submenu_item_selected = 0;
};

View File

@ -1,16 +0,0 @@
#include "lfrfid_app_scene_select_key.h"
void LfRfidAppSceneSelectKey::on_enter(LfRfidApp* app, bool need_restore) {
if(app->load_key_from_file_select(need_restore)) {
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SavedKeyMenu);
} else {
app->scene_controller.switch_to_previous_scene();
}
}
bool LfRfidAppSceneSelectKey::on_event(LfRfidApp* /* app */, LfRfidApp::Event* /* event */) {
return false;
}
void LfRfidAppSceneSelectKey::on_exit(LfRfidApp* /* app */) {
}

View File

@ -1,9 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneSelectKey : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
};

View File

@ -1,67 +0,0 @@
#include "lfrfid_app_scene_start.h"
typedef enum {
SubmenuRead,
SubmenuSaved,
SubmenuAddManually,
SubmenuExtraActions,
} SubmenuIndex;
void LfRfidAppSceneStart::on_enter(LfRfidApp* app, bool need_restore) {
auto submenu = app->view_controller.get<SubmenuVM>();
submenu->add_item("Read", SubmenuRead, submenu_callback, app);
submenu->add_item("Saved", SubmenuSaved, submenu_callback, app);
submenu->add_item("Add Manually", SubmenuAddManually, submenu_callback, app);
submenu->add_item("Extra Actions", SubmenuExtraActions, submenu_callback, app);
if(need_restore) {
submenu->set_selected_item(submenu_item_selected);
}
app->view_controller.switch_to<SubmenuVM>();
// clear key
string_reset(app->file_name);
app->protocol_id = PROTOCOL_NO;
app->read_type = LFRFIDWorkerReadTypeAuto;
}
bool LfRfidAppSceneStart::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = false;
if(event->type == LfRfidApp::EventType::MenuSelected) {
submenu_item_selected = event->payload.signed_int;
switch(event->payload.signed_int) {
case SubmenuRead:
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Read);
break;
case SubmenuSaved:
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SelectKey);
break;
case SubmenuAddManually:
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveType);
break;
case SubmenuExtraActions:
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ExtraActions);
break;
}
consumed = true;
}
return consumed;
}
void LfRfidAppSceneStart::on_exit(LfRfidApp* app) {
app->view_controller.get<SubmenuVM>()->clean();
}
void LfRfidAppSceneStart::submenu_callback(void* context, uint32_t index) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::MenuSelected;
event.payload.signed_int = index;
app->view_controller.send_event(&event);
}

View File

@ -1,13 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneStart : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
static void submenu_callback(void* context, uint32_t index);
uint32_t submenu_item_selected = 0;
};

View File

@ -1,88 +0,0 @@
#include "lfrfid_app_scene_write.h"
static void lfrfid_write_callback(LFRFIDWorkerWriteResult result, void* ctx) {
LfRfidApp* app = static_cast<LfRfidApp*>(ctx);
LfRfidApp::Event event;
switch(result) {
case LFRFIDWorkerWriteOK:
event.type = LfRfidApp::EventType::WriteEventOK;
break;
case LFRFIDWorkerWriteProtocolCannotBeWritten:
event.type = LfRfidApp::EventType::WriteEventProtocolCannotBeWritten;
break;
case LFRFIDWorkerWriteFobCannotBeWritten:
event.type = LfRfidApp::EventType::WriteEventFobCannotBeWritten;
break;
case LFRFIDWorkerWriteTooLongToWrite:
event.type = LfRfidApp::EventType::WriteEventTooLongToWrite;
break;
}
app->view_controller.send_event(&event);
}
void LfRfidAppSceneWrite::on_enter(LfRfidApp* app, bool /* need_restore */) {
auto popup = app->view_controller.get<PopupVM>();
popup->set_header("Writing", 89, 30, AlignCenter, AlignTop);
if(string_size(app->file_name)) {
popup->set_text(string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop);
} else {
popup->set_text(
protocol_dict_get_name(app->dict, app->protocol_id), 89, 43, AlignCenter, AlignTop);
}
popup->set_icon(0, 3, &I_RFIDDolphinSend_97x61);
app->view_controller.switch_to<PopupVM>();
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->notification, &sequence_blink_start_magenta);
}
bool LfRfidAppSceneWrite::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = true;
auto popup = app->view_controller.get<PopupVM>();
switch(event->type) {
case LfRfidApp::EventType::WriteEventOK:
notification_message(app->notification, &sequence_success);
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::WriteSuccess);
break;
case LfRfidApp::EventType::WriteEventProtocolCannotBeWritten:
popup->set_icon(72, 17, &I_DolphinCommon_56x48);
popup->set_header("Error", 64, 3, AlignCenter, AlignTop);
popup->set_text("This protocol\ncannot be written", 3, 17, AlignLeft, AlignTop);
notification_message(app->notification, &sequence_blink_start_red);
break;
case LfRfidApp::EventType::WriteEventFobCannotBeWritten:
case LfRfidApp::EventType::WriteEventTooLongToWrite:
popup->set_icon(72, 17, &I_DolphinCommon_56x48);
popup->set_header("Still trying to write...", 64, 3, AlignCenter, AlignTop);
popup->set_text(
"Make sure this\ncard is writable\nand not\nprotected.", 3, 17, AlignLeft, AlignTop);
notification_message(app->notification, &sequence_blink_start_yellow);
break;
default:
consumed = false;
}
return consumed;
}
void LfRfidAppSceneWrite::on_exit(LfRfidApp* app) {
notification_message(app->notification, &sequence_blink_stop);
app->view_controller.get<PopupVM>()->clean();
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

@ -1,9 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneWrite : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
};

View File

@ -1,38 +0,0 @@
#include "lfrfid_app_scene_write_success.h"
void LfRfidAppSceneWriteSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) {
auto popup = app->view_controller.get<PopupVM>();
popup->set_header("Successfully\nwritten!", 94, 3, AlignCenter, AlignTop);
popup->set_icon(0, 6, &I_RFIDDolphinSuccess_108x57);
popup->set_context(app);
popup->set_callback(LfRfidAppSceneWriteSuccess::timeout_callback);
popup->set_timeout(1500);
popup->enable_timeout();
app->view_controller.switch_to<PopupVM>();
notification_message_block(app->notification, &sequence_set_green_255);
}
bool LfRfidAppSceneWriteSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = false;
if(event->type == LfRfidApp::EventType::Back) {
app->scene_controller.search_and_switch_to_previous_scene(
{LfRfidApp::SceneType::ReadKeyMenu, LfRfidApp::SceneType::SelectKey});
consumed = true;
}
return consumed;
}
void LfRfidAppSceneWriteSuccess::on_exit(LfRfidApp* app) {
notification_message_block(app->notification, &sequence_reset_green);
app->view_controller.get<PopupVM>()->clean();
}
void LfRfidAppSceneWriteSuccess::timeout_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Back;
app->view_controller.send_event(&event);
}

View File

@ -1,12 +0,0 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneWriteSuccess : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
static void timeout_callback(void* context);
};

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);
}

View File

@ -1,115 +0,0 @@
#include "container_vm.h"
#include "elements/generic_element.h"
#include "elements/string_element.h"
#include "elements/icon_element.h"
#include "elements/button_element.h"
#include <list>
class ContainerVMData {
public:
ContainerVMData(){};
~ContainerVMData() {
for(auto& it : elements) delete it;
};
std::list<GenericElement*> elements;
template <typename T> T add(const T element, View* view) {
elements.push_back(element);
element->set_parent_view(view);
return element;
}
void clean() {
for(auto& it : elements) delete it;
elements.clear();
}
};
struct ContainerVMModel {
ContainerVMData* data;
};
ContainerVM::ContainerVM() {
view = view_alloc();
view_set_context(view, this);
view_allocate_model(view, ViewModelTypeLocking, sizeof(ContainerVMModel));
with_view_model_cpp(view, ContainerVMModel, model, {
model->data = new ContainerVMData();
return true;
});
view_set_draw_callback(view, view_draw_callback);
view_set_input_callback(view, view_input_callback);
}
ContainerVM::~ContainerVM() {
with_view_model_cpp(view, ContainerVMModel, model, {
delete model->data;
model->data = NULL;
return false;
});
view_free(view);
}
View* ContainerVM::get_view() {
return view;
}
void ContainerVM::clean() {
with_view_model_cpp(view, ContainerVMModel, model, {
model->data->clean();
return true;
});
}
template <typename T> T* ContainerVM::add() {
T* element = new T();
with_view_model_cpp(view, ContainerVMModel, model, {
model->data->add(element, view);
return true;
});
return element;
}
void ContainerVM::view_draw_callback(Canvas* canvas, void* model) {
ContainerVMData* data = static_cast<ContainerVMModel*>(model)->data;
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontPrimary);
for(const auto& element : data->elements) {
element->draw(canvas);
}
}
bool ContainerVM::view_input_callback(InputEvent* event, void* context) {
bool consumed = false;
View* view = static_cast<ContainerVM*>(context)->view;
with_view_model_cpp(view, ContainerVMModel, model, {
for(const auto& element : model->data->elements) {
if(element->input(event)) {
consumed = true;
}
if(consumed) {
break;
}
}
return consumed;
});
return consumed;
}
template StringElement* ContainerVM::add<StringElement>();
template IconElement* ContainerVM::add<IconElement>();
template ButtonElement* ContainerVM::add<ButtonElement>();

View File

@ -1,17 +0,0 @@
#pragma once
#include <view_modules/generic_view_module.h>
class ContainerVM : public GenericViewModule {
public:
ContainerVM();
~ContainerVM() final;
View* get_view() final;
void clean() final;
template <typename T> T* add();
private:
View* view;
static void view_draw_callback(Canvas* canvas, void* model);
static bool view_input_callback(InputEvent* event, void* context);
};

View File

@ -1,65 +0,0 @@
#include "button_element.h"
#include <gui/elements.h>
ButtonElement::ButtonElement() {
}
ButtonElement::~ButtonElement() {
}
void ButtonElement::draw(Canvas* canvas) {
if(text != nullptr) {
canvas_set_font(canvas, FontSecondary);
switch(type) {
case Type::Left:
elements_button_left(canvas, text);
break;
case Type::Center:
elements_button_center(canvas, text);
break;
case Type::Right:
elements_button_right(canvas, text);
break;
}
}
}
bool ButtonElement::input(InputEvent* event) {
bool consumed = false;
if(event->type == InputTypeShort && callback != nullptr) {
switch(type) {
case Type::Left:
if(event->key == InputKeyLeft) {
callback(context);
consumed = true;
}
break;
case Type::Center:
if(event->key == InputKeyOk) {
callback(context);
consumed = true;
}
break;
case Type::Right:
if(event->key == InputKeyRight) {
callback(context);
consumed = true;
}
break;
}
}
return consumed;
}
void ButtonElement::set_type(Type _type, const char* _text) {
lock_model();
type = _type;
text = _text;
unlock_model(true);
}
void ButtonElement::set_callback(void* _context, ButtonElementCallback _callback) {
context = _context;
callback = _callback;
}

View File

@ -1,28 +0,0 @@
#pragma once
#include "generic_element.h"
typedef void (*ButtonElementCallback)(void* context);
class ButtonElement : public GenericElement {
public:
ButtonElement();
~ButtonElement() final;
void draw(Canvas* canvas) final;
bool input(InputEvent* event) final;
enum class Type : uint8_t {
Left,
Center,
Right,
};
void set_type(Type type, const char* text);
void set_callback(void* context, ButtonElementCallback callback);
private:
Type type = Type::Left;
const char* text = nullptr;
void* context = nullptr;
ButtonElementCallback callback = nullptr;
};

View File

@ -1,15 +0,0 @@
#include "generic_element.h"
void GenericElement::lock_model() {
furi_assert(view != nullptr);
view_get_model(view);
}
void GenericElement::unlock_model(bool need_redraw) {
furi_assert(view != nullptr);
view_commit_model(view, need_redraw);
}
void GenericElement::set_parent_view(View* _view) {
view = _view;
}

View File

@ -1,21 +0,0 @@
#pragma once
#include <gui/gui.h>
#include <gui/view.h>
class GenericElement {
public:
GenericElement(){};
virtual ~GenericElement(){};
virtual void draw(Canvas* canvas) = 0;
virtual bool input(InputEvent* event) = 0;
// TODO that must be accessible only to ContainerVMData
void set_parent_view(View* view);
// TODO that must be accessible only to inheritors
void lock_model();
void unlock_model(bool need_redraw);
private:
View* view = nullptr;
};

View File

@ -1,25 +0,0 @@
#include "icon_element.h"
IconElement::IconElement() {
}
IconElement::~IconElement() {
}
void IconElement::draw(Canvas* canvas) {
if(icon != NULL) {
canvas_draw_icon(canvas, x, y, icon);
}
}
bool IconElement::input(InputEvent* /* event */) {
return false;
}
void IconElement::set_icon(uint8_t _x, uint8_t _y, const Icon* _icon) {
lock_model();
icon = _icon;
x = _x;
y = _y;
unlock_model(true);
}

View File

@ -1,17 +0,0 @@
#pragma once
#include "generic_element.h"
class IconElement : public GenericElement {
public:
IconElement();
~IconElement() final;
void draw(Canvas* canvas) final;
bool input(InputEvent* event) final;
void set_icon(uint8_t x = 0, uint8_t y = 0, const Icon* icon = NULL);
private:
const Icon* icon = NULL;
uint8_t x = 0;
uint8_t y = 0;
};

View File

@ -1,47 +0,0 @@
#include "string_element.h"
#include <gui/elements.h>
StringElement::StringElement() {
}
StringElement::~StringElement() {
}
void StringElement::draw(Canvas* canvas) {
if(text) {
string_t line;
string_init(line);
string_set_str(line, text);
canvas_set_font(canvas, font);
if(fit_width != 0) {
elements_string_fit_width(canvas, line, fit_width);
}
elements_multiline_text_aligned(canvas, x, y, horizontal, vertical, string_get_cstr(line));
string_clear(line);
}
}
bool StringElement::input(InputEvent* /* event */) {
return false;
}
void StringElement::set_text(
const char* _text,
uint8_t _x,
uint8_t _y,
uint8_t _fit_w,
Align _horizontal,
Align _vertical,
Font _font) {
lock_model();
text = _text;
x = _x;
y = _y;
fit_width = _fit_w;
horizontal = _horizontal;
vertical = _vertical;
font = _font;
unlock_model(true);
}

View File

@ -1,28 +0,0 @@
#pragma once
#include "generic_element.h"
class StringElement : public GenericElement {
public:
StringElement();
~StringElement() final;
void draw(Canvas* canvas) final;
bool input(InputEvent* event) final;
void set_text(
const char* text = NULL,
uint8_t x = 0,
uint8_t y = 0,
uint8_t fit_width = 0,
Align horizontal = AlignLeft,
Align vertical = AlignTop,
Font font = FontPrimary);
private:
const char* text = NULL;
uint8_t x = 0;
uint8_t y = 0;
uint8_t fit_width = 0;
Align horizontal = AlignLeft;
Align vertical = AlignTop;
Font font = FontPrimary;
};

View File

@ -0,0 +1,117 @@
#include "lfrfid_view_read.h"
#include <gui/elements.h>
#define TEMP_STR_LEN 128
struct LfRfidReadView {
View* view;
};
typedef struct {
IconAnimation* icon;
LfRfidReadViewMode read_mode;
} LfRfidReadViewModel;
static void lfrfid_view_read_draw_callback(Canvas* canvas, void* _model) {
LfRfidReadViewModel* model = _model;
canvas_set_color(canvas, ColorBlack);
canvas_draw_icon(canvas, 0, 8, &I_NFC_manual);
canvas_set_font(canvas, FontPrimary);
if(model->read_mode == LfRfidReadAsk) {
canvas_draw_str(canvas, 70, 16, "Reading 1/2");
canvas_draw_str(canvas, 77, 29, "ASK");
canvas_draw_icon(canvas, 70, 22, &I_ButtonRight_4x7);
canvas_draw_icon_animation(canvas, 102, 21, model->icon);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str(canvas, 77, 43, "PSK");
} else if(model->read_mode == LfRfidReadPsk) {
canvas_draw_str(canvas, 70, 16, "Reading 2/2");
canvas_draw_str(canvas, 77, 43, "PSK");
canvas_draw_icon(canvas, 70, 36, &I_ButtonRight_4x7);
canvas_draw_icon_animation(canvas, 102, 35, model->icon);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str(canvas, 77, 29, "ASK");
} else {
canvas_draw_str(canvas, 72, 16, "Reading");
if(model->read_mode == LfRfidReadAskOnly) {
canvas_draw_str(canvas, 77, 35, "ASK");
} else {
canvas_draw_str(canvas, 77, 35, "PSK");
}
canvas_draw_icon_animation(canvas, 102, 27, model->icon);
}
canvas_set_font(canvas, FontSecondary);
canvas_draw_str(canvas, 61, 56, "Don't move card");
}
void lfrfid_view_read_enter(void* context) {
LfRfidReadView* read_view = context;
with_view_model(
read_view->view, (LfRfidReadViewModel * model) {
icon_animation_start(model->icon);
return true;
});
}
void lfrfid_view_read_exit(void* context) {
LfRfidReadView* read_view = context;
with_view_model(
read_view->view, (LfRfidReadViewModel * model) {
icon_animation_stop(model->icon);
return false;
});
}
LfRfidReadView* lfrfid_view_read_alloc() {
LfRfidReadView* read_view = malloc(sizeof(LfRfidReadView));
read_view->view = view_alloc();
view_set_context(read_view->view, read_view);
view_allocate_model(read_view->view, ViewModelTypeLocking, sizeof(LfRfidReadViewModel));
with_view_model(
read_view->view, (LfRfidReadViewModel * model) {
model->icon = icon_animation_alloc(&A_Round_loader_8x8);
view_tie_icon_animation(read_view->view, model->icon);
return false;
});
view_set_draw_callback(read_view->view, lfrfid_view_read_draw_callback);
view_set_enter_callback(read_view->view, lfrfid_view_read_enter);
view_set_exit_callback(read_view->view, lfrfid_view_read_exit);
return read_view;
}
void lfrfid_view_read_free(LfRfidReadView* read_view) {
with_view_model(
read_view->view, (LfRfidReadViewModel * model) {
icon_animation_free(model->icon);
return false;
});
view_free(read_view->view);
free(read_view);
}
View* lfrfid_view_read_get_view(LfRfidReadView* read_view) {
return read_view->view;
}
void lfrfid_view_read_set_read_mode(LfRfidReadView* read_view, LfRfidReadViewMode mode) {
with_view_model(
read_view->view, (LfRfidReadViewModel * model) {
icon_animation_stop(model->icon);
icon_animation_start(model->icon);
model->read_mode = mode;
return true;
});
}

View File

@ -0,0 +1,19 @@
#pragma once
#include <gui/view.h>
typedef enum {
LfRfidReadAsk,
LfRfidReadPsk,
LfRfidReadAskOnly,
LfRfidReadPskOnly
} LfRfidReadViewMode;
typedef struct LfRfidReadView LfRfidReadView;
LfRfidReadView* lfrfid_view_read_alloc();
void lfrfid_view_read_free(LfRfidReadView* read_view);
View* lfrfid_view_read_get_view(LfRfidReadView* read_view);
void lfrfid_view_read_set_read_mode(LfRfidReadView* read_view, LfRfidReadViewMode mode);

View File

@ -0,0 +1,81 @@
#include "lfrfid_debug_i.h"
static bool lfrfid_debug_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
LfRfidDebug* app = context;
return scene_manager_handle_custom_event(app->scene_manager, event);
}
static bool lfrfid_debug_back_event_callback(void* context) {
furi_assert(context);
LfRfidDebug* app = context;
return scene_manager_handle_back_event(app->scene_manager);
}
static LfRfidDebug* lfrfid_debug_alloc() {
LfRfidDebug* app = malloc(sizeof(LfRfidDebug));
app->view_dispatcher = view_dispatcher_alloc();
app->scene_manager = scene_manager_alloc(&lfrfid_debug_scene_handlers, app);
view_dispatcher_enable_queue(app->view_dispatcher);
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
view_dispatcher_set_custom_event_callback(
app->view_dispatcher, lfrfid_debug_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
app->view_dispatcher, lfrfid_debug_back_event_callback);
// Open GUI record
app->gui = furi_record_open(RECORD_GUI);
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
// Submenu
app->submenu = submenu_alloc();
view_dispatcher_add_view(
app->view_dispatcher, LfRfidDebugViewSubmenu, submenu_get_view(app->submenu));
// Tune view
app->tune_view = lfrfid_debug_view_tune_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
LfRfidDebugViewTune,
lfrfid_debug_view_tune_get_view(app->tune_view));
return app;
}
static void lfrfid_debug_free(LfRfidDebug* app) {
furi_assert(app);
// Submenu
view_dispatcher_remove_view(app->view_dispatcher, LfRfidDebugViewSubmenu);
submenu_free(app->submenu);
// Tune view
view_dispatcher_remove_view(app->view_dispatcher, LfRfidDebugViewTune);
lfrfid_debug_view_tune_free(app->tune_view);
// View Dispatcher
view_dispatcher_free(app->view_dispatcher);
// Scene Manager
scene_manager_free(app->scene_manager);
// GUI
furi_record_close(RECORD_GUI);
app->gui = NULL;
free(app);
}
int32_t lfrfid_debug_app(void* p) {
UNUSED(p);
LfRfidDebug* app = lfrfid_debug_alloc();
scene_manager_next_scene(app->scene_manager, LfRfidDebugSceneStart);
view_dispatcher_run(app->view_dispatcher);
lfrfid_debug_free(app);
return 0;
}

View File

@ -1,17 +0,0 @@
#include "lfrfid_debug_app.h"
#include "scene/lfrfid_debug_app_scene_start.h"
#include "scene/lfrfid_debug_app_scene_tune.h"
LfRfidDebugApp::LfRfidDebugApp()
: scene_controller{this} {
}
LfRfidDebugApp::~LfRfidDebugApp() {
}
void LfRfidDebugApp::run() {
view_controller.attach_to_gui(ViewDispatcherTypeFullscreen);
scene_controller.add_scene(SceneType::Start, new LfRfidDebugAppSceneStart());
scene_controller.add_scene(SceneType::TuneScene, new LfRfidDebugAppSceneTune());
scene_controller.process(100);
}

View File

@ -1,40 +0,0 @@
#pragma once
#include <furi.h>
#include <furi_hal.h>
#include <generic_scene.hpp>
#include <scene_controller.hpp>
#include <view_controller.hpp>
#include <view_modules/submenu_vm.h>
#include "view_modules/lfrfid_view_tune_vm.h"
class LfRfidDebugApp {
public:
enum class EventType : uint8_t {
GENERIC_EVENT_ENUM_VALUES,
MenuSelected,
};
enum class SceneType : uint8_t {
GENERIC_SCENE_ENUM_VALUES,
TuneScene,
};
class Event {
public:
union {
int32_t menu_index;
} payload;
EventType type;
};
SceneController<GenericScene<LfRfidDebugApp>, LfRfidDebugApp> scene_controller;
ViewController<LfRfidDebugApp, SubmenuVM, LfRfidViewTuneVM> view_controller;
~LfRfidDebugApp();
LfRfidDebugApp();
void run();
};

View File

@ -1,11 +0,0 @@
#include "lfrfid_debug_app.h"
// app enter function
extern "C" int32_t lfrfid_debug_app(void* p) {
UNUSED(p);
LfRfidDebugApp* app = new LfRfidDebugApp();
app->run();
delete app;
return 0;
}

View File

@ -0,0 +1,31 @@
#pragma once
#include <furi.h>
#include <furi_hal.h>
#include <gui/gui.h>
#include <gui/view.h>
#include <gui/view_dispatcher.h>
#include <gui/scene_manager.h>
#include <gui/modules/submenu.h>
#include <lfrfid_debug/views/lfrfid_debug_view_tune.h>
#include <lfrfid_debug/scenes/lfrfid_debug_scene.h>
typedef struct LfRfidDebug LfRfidDebug;
struct LfRfidDebug {
Gui* gui;
ViewDispatcher* view_dispatcher;
SceneManager* scene_manager;
// Common Views
Submenu* submenu;
LfRfidTuneView* tune_view;
};
typedef enum {
LfRfidDebugViewSubmenu,
LfRfidDebugViewTune,
} LfRfidDebugView;

View File

@ -1,47 +0,0 @@
#include "lfrfid_debug_app_scene_start.h"
typedef enum {
SubmenuTune,
} SubmenuIndex;
void LfRfidDebugAppSceneStart::on_enter(LfRfidDebugApp* app, bool need_restore) {
auto submenu = app->view_controller.get<SubmenuVM>();
auto callback = cbc::obtain_connector(this, &LfRfidDebugAppSceneStart::submenu_callback);
submenu->add_item("Tune", SubmenuTune, callback, app);
if(need_restore) {
submenu->set_selected_item(submenu_item_selected);
}
app->view_controller.switch_to<SubmenuVM>();
}
bool LfRfidDebugAppSceneStart::on_event(LfRfidDebugApp* app, LfRfidDebugApp::Event* event) {
bool consumed = false;
if(event->type == LfRfidDebugApp::EventType::MenuSelected) {
submenu_item_selected = event->payload.menu_index;
switch(event->payload.menu_index) {
case SubmenuTune:
app->scene_controller.switch_to_next_scene(LfRfidDebugApp::SceneType::TuneScene);
break;
}
consumed = true;
}
return consumed;
}
void LfRfidDebugAppSceneStart::on_exit(LfRfidDebugApp* app) {
app->view_controller.get<SubmenuVM>()->clean();
}
void LfRfidDebugAppSceneStart::submenu_callback(void* context, uint32_t index) {
LfRfidDebugApp* app = static_cast<LfRfidDebugApp*>(context);
LfRfidDebugApp::Event event;
event.type = LfRfidDebugApp::EventType::MenuSelected;
event.payload.menu_index = index;
app->view_controller.send_event(&event);
}

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