Merge branch 'release-candidate' into release

This commit is contained in:
Aleksandr Kutuzov 2022-08-13 18:21:46 +09:00
commit 7a6720384f
221 changed files with 6695 additions and 922 deletions

View File

@ -113,7 +113,7 @@ jobs:
run: |
echo "${{ secrets.RSYNC_DEPLOY_KEY }}" > deploy_key;
chmod 600 ./deploy_key;
rsync -avzP --mkpath \
rsync -avzP --delete --mkpath \
-e 'ssh -p ${{ secrets.RSYNC_DEPLOY_PORT }} -i ./deploy_key' \
artifacts/ ${{ secrets.RSYNC_DEPLOY_USER }}@${{ secrets.RSYNC_DEPLOY_HOST }}:"${{ secrets.RSYNC_DEPLOY_BASE_PATH }}${{steps.names.outputs.artifacts-path}}/";
rm ./deploy_key;

4
.vscode/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
./c_cpp_properties.json
./launch.json
./settings.json
./tasks.json

17
.vscode/ReadMe.md vendored Normal file
View File

@ -0,0 +1,17 @@
# Visual Studio Code workspace for Flipper Zero
## Setup
* To start developing with VSCode, run `./fbt vscode_dist` in project root. _That should only be done once_
* After that, open firmware folder in VSCode: "File" > "Open folder"
For more details on fbt, see [fbt docs](../documentation/fbt.md).
## Workflow
Commands for building firmware are invoked through Build menu: Ctrl+Shift+B.
To attach a debugging session, first build and flash firmware, then choose your debug probe in Debug menu (Ctrl+Shift+D).
Note that you have to detach debugging session before rebuilding and re-flashing firmware.

32
.vscode/example/c_cpp_properties.json vendored Normal file
View File

@ -0,0 +1,32 @@
{
"configurations": [
{
"name": "Win32",
"compilerPath": "${workspaceFolder}/toolchain/i686-windows/bin/arm-none-eabi-gcc.exe",
"intelliSenseMode": "gcc-arm",
"compileCommands": "${workspaceFolder}/build/latest/compile_commands.json",
"configurationProvider": "ms-vscode.cpptools",
"cStandard": "gnu17",
"cppStandard": "c++17"
},
{
"name": "Linux",
"compilerPath": "${workspaceFolder}/toolchain/x86_64-linux/bin/arm-none-eabi-gcc",
"intelliSenseMode": "gcc-arm",
"compileCommands": "${workspaceFolder}/build/latest/compile_commands.json",
"configurationProvider": "ms-vscode.cpptools",
"cStandard": "gnu17",
"cppStandard": "c++17"
},
{
"name": "Mac",
"compilerPath": "${workspaceFolder}/toolchain/x86_64-darwin/bin/arm-none-eabi-gcc",
"intelliSenseMode": "gcc-arm",
"compileCommands": "${workspaceFolder}/build/latest/compile_commands.json",
"configurationProvider": "ms-vscode.cpptools",
"cStandard": "gnu17",
"cppStandard": "c++17"
}
],
"version": 4
}

87
.vscode/example/launch.json vendored Normal file
View File

@ -0,0 +1,87 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"inputs": [
{
"id": "BLACKMAGIC",
"type": "command",
"command": "shellCommand.execute",
"args": {
"command": "./fbt get_blackmagic",
"description": "Get Blackmagic device",
}
}
],
"configurations": [
{
"name": "Attach FW (ST-Link)",
"cwd": "${workspaceFolder}",
"executable": "./build/latest/firmware.elf",
"request": "attach",
"type": "cortex-debug",
"servertype": "openocd",
"device": "stlink",
"svdFile": "./debug/STM32WB55_CM4.svd",
"rtos": "FreeRTOS",
"configFiles": [
"interface/stlink.cfg",
"./debug/stm32wbx.cfg",
],
"postAttachCommands": [
// "attach 1",
"compare-sections",
]
// "showDevDebugOutput": "raw",
},
{
"name": "Attach FW (blackmagic)",
"cwd": "${workspaceFolder}",
"executable": "./build/latest/firmware.elf",
"request": "attach",
"type": "cortex-debug",
"servertype": "external",
"gdbTarget": "${input:BLACKMAGIC}",
"svdFile": "./debug/STM32WB55_CM4.svd",
"rtos": "FreeRTOS",
"postAttachCommands": [
"monitor swdp_scan",
"attach 1",
"set confirm off",
"set mem inaccessible-by-default off",
"compare-sections",
]
// "showDevDebugOutput": "raw",
},
{
"name": "Attach FW (JLink)",
"cwd": "${workspaceFolder}",
"executable": "./build/latest/firmware.elf",
"request": "attach",
"type": "cortex-debug",
"servertype": "jlink",
"interface": "swd",
"device": "STM32WB55RG",
"svdFile": "./debug/STM32WB55_CM4.svd",
"rtos": "FreeRTOS",
// "showDevDebugOutput": "raw",
},
{
"name": "fbt debug",
"type": "python",
"request": "launch",
"program": "./lib/scons/scripts/scons.py",
"args": [
"sdk"
]
},
{
"name": "python debug",
"type": "python",
"request": "launch",
"program": "${file}",
"args": []
}
]
}

22
.vscode/example/settings.json vendored Normal file
View File

@ -0,0 +1,22 @@
{
"C_Cpp.default.cStandard": "gnu17",
"C_Cpp.default.cppStandard": "c++17",
"python.formatting.provider": "black",
"workbench.tree.indent": 12,
"cortex-debug.enableTelemetry": false,
"cortex-debug.variableUseNaturalFormat": true,
"cortex-debug.showRTOS": true,
"cortex-debug.armToolchainPath.windows": "${workspaceFolder}/toolchain/i686-windows/bin",
"cortex-debug.armToolchainPath.linux": "${workspaceFolder}/toolchain/x86_64-linux/bin",
"cortex-debug.armToolchainPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/bin",
"cortex-debug.openocdPath.windows": "${workspaceFolder}/toolchain/i686-windows/openocd/bin/openocd.exe",
"cortex-debug.openocdPath.linux": "${workspaceFolder}/toolchain/x86_64-linux/openocd/bin/openocd",
"cortex-debug.openocdPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/openocd/bin/openocd",
"editor.formatOnSave": true,
"files.associations": {
"*.scons": "python",
"SConscript": "python",
"SConstruct": "python",
"*.fam": "python",
}
}

103
.vscode/example/tasks.json vendored Normal file
View File

@ -0,0 +1,103 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "[Release] Build",
"group": "build",
"type": "shell",
"command": "./fbt COMPACT=1 DEBUG=0"
},
{
"label": "[Debug] Build",
"group": "build",
"type": "shell",
"command": "./fbt"
},
{
"label": "[Release] Flash (ST-Link)",
"group": "build",
"type": "shell",
"command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash"
},
{
"label": "[Debug] Flash (ST-Link)",
"group": "build",
"type": "shell",
"command": "./fbt FORCE=1 flash"
},
{
"label": "[Release] Flash (blackmagic)",
"group": "build",
"type": "shell",
"command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash_blackmagic"
},
{
"label": "[Debug] Flash (blackmagic)",
"group": "build",
"type": "shell",
"command": "./fbt FORCE=1 flash_blackmagic"
},
{
"label": "[Release] Flash (JLink)",
"group": "build",
"type": "shell",
"command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 jflash"
},
{
"label": "[Debug] Flash (JLink)",
"group": "build",
"type": "shell",
"command": "./fbt FORCE=1 jflash"
},
{
"label": "[Release] Build update bundle",
"group": "build",
"type": "shell",
"command": "./fbt updater_package COMPACT=1 DEBUG=0"
},
{
"label": "[Debug] Build update bundle",
"group": "build",
"type": "shell",
"command": "./fbt updater_package"
},
{
"label": "[Release] Build updater",
"group": "build",
"type": "shell",
"command": "./fbt updater_all COMPACT=1 DEBUG=0"
},
{
"label": "[Debug] Build updater",
"group": "build",
"type": "shell",
"command": "./fbt updater_all"
},
{
"label": "[Debug] Flash (USB, w/o resources)",
"group": "build",
"type": "shell",
"command": "./fbt FORCE=1 flash_usb"
},
{
"label": "[Release] Flash (USB, w/o resources)",
"group": "build",
"type": "shell",
"command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash_usb"
},
{
"label": "[Debug:unit_tests] Flash (USB)",
"group": "build",
"type": "shell",
"command": "./fbt FIRMWARE_APP_SET=unit_tests FORCE=1 flash_usb"
},
{
"label": "[Release] Flash (USB, with resources)",
"group": "build",
"type": "shell",
"command": "./fbt COMPACT=1 DEBUG=0 FORCE=1 flash_usb_full"
},
]
}

15
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,15 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"ms-python.black-formatter",
"ms-vscode.cpptools",
"amiralizadeh9480.cpp-helper",
"marus25.cortex-debug",
"zxh404.vscode-proto3",
"augustocdias.tasks-shell-input"
],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": []
}

View File

@ -274,8 +274,13 @@ distenv.PhonyTarget("cli", "${PYTHON3} scripts/serial_cli.py")
# Find blackmagic probe
distenv.PhonyTarget(
"get_blackmagic",
"@echo $( ${BLACKMAGIC_ADDR} $)",
)
# Prepare vscode environment
vscode_dist = distenv.Install("#.vscode", distenv.Glob("#.vscode/example/*"))
distenv.Precious(vscode_dist)
distenv.NoClean(vscode_dist)
distenv.Alias("vscode_dist", vscode_dist)

View File

@ -5,6 +5,7 @@
#include <gui/modules/empty_screen.h>
#include <m-string.h>
#include <furi_hal_version.h>
#include <furi_hal_region.h>
#include <furi_hal_bt.h>
typedef DialogMessageButton (*AboutDialogScreen)(DialogsApp* dialogs, DialogMessage* message);
@ -45,7 +46,7 @@ static DialogMessageButton compliance_screen(DialogsApp* dialogs, DialogMessage*
DialogMessageButton result;
const char* screen_text = "For all compliance\n"
"certificates please visit\n"
"certificates please visit:\n"
"www.flipp.dev/compliance";
dialog_message_set_text(message, screen_text, 0, 0, AlignLeft, AlignTop);
@ -83,21 +84,22 @@ static DialogMessageButton hw_version_screen(DialogsApp* dialogs, DialogMessage*
string_cat_printf(
buffer,
"%d.F%dB%dC%d %s %s\n",
"%d.F%dB%dC%d %s:%s %s\n",
furi_hal_version_get_hw_version(),
furi_hal_version_get_hw_target(),
furi_hal_version_get_hw_body(),
furi_hal_version_get_hw_connect(),
furi_hal_version_get_hw_region_name(),
furi_hal_region_get_name(),
my_name ? my_name : "Unknown");
string_cat_printf(buffer, "Serial number:\n");
string_cat_printf(buffer, "Serial Number:\n");
const uint8_t* uid = furi_hal_version_uid();
for(size_t i = 0; i < furi_hal_version_uid_size(); i++) {
string_cat_printf(buffer, "%02X", uid[i]);
}
dialog_message_set_header(message, "HW Version info:", 0, 0, AlignLeft, AlignTop);
dialog_message_set_header(message, "HW Version Info:", 0, 0, AlignLeft, AlignTop);
dialog_message_set_text(message, string_get_cstr(buffer), 0, 13, AlignLeft, AlignTop);
result = dialog_message_show(dialogs, message);
dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop);
@ -133,7 +135,7 @@ static DialogMessageButton fw_version_screen(DialogsApp* dialogs, DialogMessage*
version_get_gitbranch(ver));
}
dialog_message_set_header(message, "FW Version info:", 0, 0, AlignLeft, AlignTop);
dialog_message_set_header(message, "FW Version Info:", 0, 0, AlignLeft, AlignTop);
dialog_message_set_text(message, string_get_cstr(buffer), 0, 13, AlignLeft, AlignTop);
result = dialog_message_show(dialogs, message);
dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop);

View File

@ -32,14 +32,14 @@ void AccessorApp::run(void) {
}
AccessorApp::AccessorApp() {
notification = static_cast<NotificationApp*>(furi_record_open("notification"));
notification = static_cast<NotificationApp*>(furi_record_open(RECORD_NOTIFICATION));
onewire_host = onewire_host_alloc();
furi_hal_power_enable_otg();
}
AccessorApp::~AccessorApp() {
furi_hal_power_disable_otg();
furi_record_close("notification");
furi_record_close(RECORD_NOTIFICATION);
onewire_host_free(onewire_host);
}

View File

@ -15,7 +15,7 @@ AccessorAppViewManager::AccessorAppViewManager() {
popup = popup_alloc();
add_view(ViewType::Popup, popup_get_view(popup));
gui = static_cast<Gui*>(furi_record_open("gui"));
gui = static_cast<Gui*>(furi_record_open(RECORD_GUI));
view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen);
// set previous view callback for all views
@ -31,6 +31,7 @@ AccessorAppViewManager::~AccessorAppViewManager() {
view_dispatcher, static_cast<uint32_t>(AccessorAppViewManager::ViewType::Popup));
// free view modules
furi_record_close(RECORD_GUI);
submenu_free(submenu);
popup_free(popup);

View File

@ -18,6 +18,8 @@ typedef struct {
typedef void (*FlipperOnStartHook)(void);
extern const char* FLIPPER_AUTORUN_APP_NAME;
/* Services list
* Spawned on startup
*/

View File

@ -64,7 +64,7 @@ uint16_t archive_favorites_count(void* context) {
break;
}
if(!string_size(buffer)) {
break;
continue; // Skip empty lines
}
++lines;
}
@ -93,7 +93,7 @@ static bool archive_favourites_rescan() {
break;
}
if(!string_size(buffer)) {
break;
continue;
}
if(string_search(buffer, "/app:") == 0) {
@ -152,7 +152,7 @@ bool archive_favorites_read(void* context) {
break;
}
if(!string_size(buffer)) {
break;
continue;
}
if(string_search(buffer, "/app:") == 0) {
@ -215,7 +215,7 @@ bool archive_favorites_delete(const char* format, ...) {
break;
}
if(!string_size(buffer)) {
break;
continue;
}
if(string_search(buffer, filename)) {
@ -259,7 +259,7 @@ bool archive_is_favorite(const char* format, ...) {
break;
}
if(!string_size(buffer)) {
break;
continue;
}
if(!string_search(buffer, filename)) {
found = true;
@ -299,7 +299,7 @@ bool archive_favorites_rename(const char* src, const char* dst) {
break;
}
if(!string_size(buffer)) {
break;
continue;
}
archive_file_append(

View File

@ -92,8 +92,6 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
ArchiveBrowserView* browser = archive->browser;
ArchiveFile_t* selected = archive_get_current_file(browser);
const char* name = archive_get_name(browser);
bool known_app = archive_is_known_app(selected->type);
bool favorites = archive_get_tab(browser) == ArchiveTabFavorites;
bool consumed = false;
@ -108,18 +106,19 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
consumed = true;
break;
case ArchiveBrowserEventFileMenuRun:
if(known_app) {
if(archive_is_known_app(selected->type)) {
archive_run_in_app(browser, selected);
archive_show_file_menu(browser, false);
}
consumed = true;
break;
case ArchiveBrowserEventFileMenuPin:
case ArchiveBrowserEventFileMenuPin: {
const char* name = archive_get_name(browser);
if(favorites) {
archive_favorites_delete(name);
archive_file_array_rm_selected(browser);
archive_show_file_menu(browser, false);
} else if(known_app) {
} else if(archive_is_known_app(selected->type)) {
if(archive_is_favorite("%s", name)) {
archive_favorites_delete("%s", name);
} else {
@ -128,12 +127,12 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
archive_show_file_menu(browser, false);
}
consumed = true;
break;
} break;
case ArchiveBrowserEventFileMenuRename:
if(favorites) {
browser->callback(ArchiveBrowserEventEnterFavMove, browser->context);
} else if((known_app) && (selected->is_app == false)) {
} else if((archive_is_known_app(selected->type)) && (selected->is_app == false)) {
archive_show_file_menu(browser, false);
scene_manager_set_scene_state(
archive->scene_manager, ArchiveAppSceneBrowser, SCENE_STATE_NEED_REFRESH);

View File

@ -37,7 +37,7 @@ void archive_scene_rename_on_enter(void* context) {
false);
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
string_get_cstr(archive->browser->path), archive->file_extension, NULL);
string_get_cstr(archive->browser->path), archive->file_extension, "");
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
string_clear(filename);

View File

@ -28,7 +28,7 @@ BadUsbApp* bad_usb_app_alloc(char* arg) {
string_init(app->file_path);
if(arg != NULL) {
if(arg && strlen(arg)) {
string_set_str(app->file_path, arg);
}
@ -79,7 +79,6 @@ void bad_usb_app_free(BadUsbApp* app) {
furi_assert(app);
// Views
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewFileSelect);
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork);
bad_usb_free(app->bad_usb_view);

View File

@ -38,6 +38,5 @@ struct BadUsbApp {
typedef enum {
BadUsbAppViewError,
BadUsbAppViewFileSelect,
BadUsbAppViewWork,
} BadUsbAppView;

View File

@ -90,7 +90,7 @@ BtHid* bt_hid_app_alloc() {
submenu_add_item(
app->submenu, "Keyboard", BtHidSubmenuIndexKeyboard, bt_hid_submenu_callback, app);
submenu_add_item(
app->submenu, "Media player", BtHidSubmenuIndexMedia, bt_hid_submenu_callback, app);
app->submenu, "Media Player", BtHidSubmenuIndexMedia, bt_hid_submenu_callback, app);
submenu_add_item(app->submenu, "Mouse", BtHidSubmenuIndexMouse, bt_hid_submenu_callback, app);
view_set_previous_callback(submenu_get_view(app->submenu), bt_hid_exit);
view_dispatcher_add_view(
@ -103,7 +103,7 @@ BtHid* bt_hid_app_alloc() {
dialog_ex_set_left_button_text(app->dialog, "Exit");
dialog_ex_set_right_button_text(app->dialog, "Stay");
dialog_ex_set_center_button_text(app->dialog, "Menu");
dialog_ex_set_header(app->dialog, "Close current app?", 16, 12, AlignLeft, AlignTop);
dialog_ex_set_header(app->dialog, "Close Current App?", 16, 12, AlignLeft, AlignTop);
view_dispatcher_add_view(
app->view_dispatcher, BtHidViewExitConfirm, dialog_ex_get_view(app->dialog));

View File

@ -347,7 +347,8 @@ static void bt_close_connection(Bt* bt) {
furi_event_flag_set(bt->api_event, BT_API_UNLOCK_EVENT);
}
int32_t bt_srv() {
int32_t bt_srv(void* p) {
UNUSED(p);
Bt* bt = bt_alloc();
if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) {

View File

@ -10,9 +10,9 @@ void bt_settings_scene_forget_dev_confirm_dialog_callback(DialogExResult result,
void bt_settings_scene_forget_dev_confirm_on_enter(void* context) {
BtSettingsApp* app = context;
DialogEx* dialog = app->dialog;
dialog_ex_set_header(dialog, "Unpair all devices?", 64, 3, AlignCenter, AlignTop);
dialog_ex_set_header(dialog, "Unpair All Devices?", 64, 3, AlignCenter, AlignTop);
dialog_ex_set_text(
dialog, "All previous pairings\nwill be lost.", 64, 22, AlignCenter, AlignTop);
dialog, "All previous pairings\nwill be lost!", 64, 22, AlignCenter, AlignTop);
dialog_ex_set_left_button_text(dialog, "Back");
dialog_ex_set_right_button_text(dialog, "Unpair");
dialog_ex_set_context(dialog, app);

View File

@ -439,9 +439,9 @@ void cli_session_open(Cli* cli, void* session) {
cli->session = session;
if(cli->session != NULL) {
cli->session->init();
furi_stdglue_set_thread_stdout_callback(cli->session->tx_stdout);
furi_thread_set_stdout_callback(cli->session->tx_stdout);
} else {
furi_stdglue_set_thread_stdout_callback(NULL);
furi_thread_set_stdout_callback(NULL);
}
furi_semaphore_release(cli->idle_sem);
furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk);
@ -455,7 +455,7 @@ void cli_session_close(Cli* cli) {
cli->session->deinit();
}
cli->session = NULL;
furi_stdglue_set_thread_stdout_callback(NULL);
furi_thread_set_stdout_callback(NULL);
furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk);
}
@ -469,9 +469,9 @@ int32_t cli_srv(void* p) {
furi_record_create(RECORD_CLI, cli);
if(cli->session != NULL) {
furi_stdglue_set_thread_stdout_callback(cli->session->tx_stdout);
furi_thread_set_stdout_callback(cli->session->tx_stdout);
} else {
furi_stdglue_set_thread_stdout_callback(NULL);
furi_thread_set_stdout_callback(NULL);
}
if(furi_hal_rtc_get_boot_mode() == FuriHalRtcBootModeNormal) {

View File

@ -15,7 +15,7 @@
void cli_command_device_info_callback(const char* key, const char* value, bool last, void* context) {
UNUSED(context);
UNUSED(last);
printf("%-24s: %s\r\n", key, value);
printf("%-30s: %s\r\n", key, value);
}
/*

View File

@ -25,7 +25,7 @@ struct CliSession {
void (*deinit)(void);
size_t (*rx)(uint8_t* buffer, size_t size, uint32_t timeout);
void (*tx)(const uint8_t* buffer, size_t size);
void (*tx_stdout)(void* _cookie, const char* data, size_t size);
void (*tx_stdout)(const char* data, size_t size);
bool (*is_connected)(void);
};

View File

@ -277,8 +277,7 @@ static void cli_vcp_tx(const uint8_t* buffer, size_t size) {
#endif
}
static void cli_vcp_tx_stdout(void* _cookie, const char* data, size_t size) {
UNUSED(_cookie);
static void cli_vcp_tx_stdout(const char* data, size_t size) {
cli_vcp_tx((const uint8_t*)data, size);
}

View File

@ -26,11 +26,11 @@ static void keypad_test_render_callback(Canvas* canvas, void* ctx) {
canvas_clear(canvas);
char strings[5][20];
sprintf(strings[0], "Ok: %d", state->ok);
sprintf(strings[1], "L: %d", state->left);
sprintf(strings[2], "R: %d", state->right);
sprintf(strings[3], "U: %d", state->up);
sprintf(strings[4], "D: %d", state->down);
snprintf(strings[0], 20, "Ok: %d", state->ok);
snprintf(strings[1], 20, "L: %d", state->left);
snprintf(strings[2], 20, "R: %d", state->right);
snprintf(strings[3], 20, "U: %d", state->up);
snprintf(strings[4], 20, "D: %d", state->down);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 0, 10, "Keypad test");

View File

@ -143,7 +143,7 @@ static void bubble_animation_activate(BubbleAnimationView* view, bool force) {
furi_assert(view);
bool activate = true;
BubbleAnimationViewModel* model = view_get_model(view->view);
if(!model->current) {
if(model->current == NULL) {
activate = false;
} else if(model->freeze_frame) {
activate = false;
@ -151,14 +151,16 @@ static void bubble_animation_activate(BubbleAnimationView* view, bool force) {
activate = false;
}
if(!force) {
if((model->active_ended_at + model->current->active_cooldown * 1000) >
xTaskGetTickCount()) {
activate = false;
} else if(model->active_shift) {
activate = false;
} else if(model->current_frame >= model->current->passive_frames) {
activate = false;
if(model->current != NULL) {
if(!force) {
if((model->active_ended_at + model->current->active_cooldown * 1000) >
xTaskGetTickCount()) {
activate = false;
} else if(model->active_shift) {
activate = false;
} else if(model->current_frame >= model->current->passive_frames) {
activate = false;
}
}
}
view_commit_model(view->view, false);
@ -288,7 +290,10 @@ static void bubble_animation_enter(void* context) {
bubble_animation_activate(view, false);
BubbleAnimationViewModel* model = view_get_model(view->view);
uint8_t frame_rate = model->current->icon_animation.frame_rate;
uint8_t frame_rate = 0;
if(model->current != NULL) {
frame_rate = model->current->icon_animation.frame_rate;
}
view_commit_model(view->view, false);
if(frame_rate) {

View File

@ -90,7 +90,7 @@ void desktop_settings_app_free(DesktopSettingsApp* app) {
extern int32_t desktop_settings_app(void* p) {
DesktopSettingsApp* app = desktop_settings_app_alloc();
LOAD_DESKTOP_SETTINGS(&app->settings);
if(!strcmp(p, DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG)) {
if(p && (strcmp(p, DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG) == 0)) {
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto);
} else {
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneStart);

View File

@ -23,7 +23,7 @@ void desktop_debug_render(Canvas* canvas, void* model) {
const Version* ver;
char buffer[64];
static const char* headers[] = {"FW Version info:", "Dolphin info:"};
static const char* headers[] = {"FW Version Info:", "Dolphin Info:"};
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontPrimary);
@ -36,12 +36,13 @@ void desktop_debug_render(Canvas* canvas, void* model) {
snprintf(
buffer,
sizeof(buffer),
"%d.F%dB%dC%d %s %s",
"%d.F%dB%dC%d %s:%s %s",
furi_hal_version_get_hw_version(),
furi_hal_version_get_hw_target(),
furi_hal_version_get_hw_body(),
furi_hal_version_get_hw_connect(),
furi_hal_version_get_hw_region_name(),
furi_hal_region_get_name(),
my_name ? my_name : "Unknown");
canvas_draw_str(canvas, 5, 19 + STATUS_BAR_Y_SHIFT, buffer);
@ -78,7 +79,6 @@ void desktop_debug_render(Canvas* canvas, void* model) {
canvas_draw_str(canvas, 5, 50 + STATUS_BAR_Y_SHIFT, buffer);
} else {
char buffer[64];
Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
DolphinStats stats = dolphin_stats(dolphin);
furi_record_close(RECORD_DOLPHIN);
@ -87,18 +87,20 @@ void desktop_debug_render(Canvas* canvas, void* model) {
uint32_t remaining = dolphin_state_xp_to_levelup(m->icounter);
canvas_set_font(canvas, FontSecondary);
snprintf(buffer, 64, "Icounter: %ld Butthurt %ld", m->icounter, m->butthurt);
snprintf(buffer, sizeof(buffer), "Icounter: %ld Butthurt %ld", m->icounter, m->butthurt);
canvas_draw_str(canvas, 5, 19 + STATUS_BAR_Y_SHIFT, buffer);
snprintf(
buffer,
64,
sizeof(buffer),
"Level: %ld To level up: %ld",
current_lvl,
(remaining == (uint32_t)(-1) ? remaining : 0));
canvas_draw_str(canvas, 5, 29 + STATUS_BAR_Y_SHIFT, buffer);
snprintf(buffer, 64, "%s", asctime(localtime((const time_t*)&m->timestamp)));
// even if timestamp is uint64_t, it's safe to cast it to uint32_t, because furi_hal_rtc_datetime_to_timestamp only returns uint32_t
snprintf(buffer, sizeof(buffer), "%ld", (uint32_t)m->timestamp);
canvas_draw_str(canvas, 5, 39 + STATUS_BAR_Y_SHIFT, buffer);
canvas_draw_str(canvas, 0, 49 + STATUS_BAR_Y_SHIFT, "[< >] icounter value [ok] save");
}

View File

@ -67,7 +67,7 @@ void desktop_lock_menu_render(Canvas* canvas, void* model) {
const char* str = Lockmenu_Items[i];
if(i == 1 && !m->pin_set) str = "Set PIN";
if(m->hint_timeout && m->idx == 2 && m->idx == i) str = "Not implemented";
if(m->hint_timeout && m->idx == 2 && m->idx == i) str = "Not Implemented";
if(str != NULL)
canvas_draw_str_aligned(

View File

@ -20,7 +20,7 @@ static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event);
static void gpio_test_draw_callback(Canvas* canvas, void* _model) {
GpioTestModel* model = _model;
canvas_set_font(canvas, FontPrimary);
elements_multiline_text_aligned(canvas, 64, 2, AlignCenter, AlignTop, "Gpio Output mode test");
elements_multiline_text_aligned(canvas, 64, 2, AlignCenter, AlignTop, "GPIO Output Mode Test");
canvas_set_font(canvas, FontSecondary);
elements_multiline_text_aligned(
canvas, 64, 16, AlignCenter, AlignTop, "Press < or > to change pin");

View File

@ -185,17 +185,19 @@ static void button_menu_process_ok(ButtonMenu* button_menu, InputType type) {
return false;
});
if(item->type == ButtonMenuItemTypeControl) {
if(type == InputTypeShort) {
if(item && item->callback) {
item->callback(item->callback_context, item->index, type);
if(item) {
if(item->type == ButtonMenuItemTypeControl) {
if(type == InputTypeShort) {
if(item && item->callback) {
item->callback(item->callback_context, item->index, type);
}
}
}
}
if(item->type == ButtonMenuItemTypeCommon) {
if((type == InputTypePress) || (type == InputTypeRelease)) {
if(item && item->callback) {
item->callback(item->callback_context, item->index, type);
if(item->type == ButtonMenuItemTypeCommon) {
if((type == InputTypePress) || (type == InputTypeRelease)) {
if(item && item->callback) {
item->callback(item->callback_context, item->index, type);
}
}
}
}

View File

@ -131,7 +131,9 @@ static bool char_is_lowercase(char letter) {
}
static char char_to_uppercase(const char letter) {
if(isalpha(letter)) {
if(letter == '_') {
return 0x20;
} else if(isalpha(letter)) {
return (letter - 0x20);
} else {
return letter;
@ -147,7 +149,7 @@ static void text_input_backspace_cb(TextInputModel* model) {
static void text_input_view_draw_callback(Canvas* canvas, void* _model) {
TextInputModel* model = _model;
uint8_t text_length = strlen(model->text_buffer);
uint8_t text_length = model->text_buffer ? strlen(model->text_buffer) : 0;
uint8_t needed_string_width = canvas_width(canvas) - 8;
uint8_t start_pos = 4;

View File

@ -1,7 +1,7 @@
#pragma once
// #include <gui/view.h>
#include <m-string.h>
#include <core/common_defines.h>
#ifdef __cplusplus
extern "C" {

View File

@ -9,20 +9,6 @@
#define TAG "iButtonApp"
static const NotificationSequence sequence_blink_start_cyan = {
&message_blink_start_10,
&message_blink_set_color_cyan,
&message_do_not_reset,
NULL,
};
static const NotificationSequence sequence_blink_start_magenta = {
&message_blink_start_10,
&message_blink_set_color_magenta,
&message_do_not_reset,
NULL,
};
static const NotificationSequence sequence_blink_set_yellow = {
&message_blink_set_color_yellow,
NULL,
@ -33,11 +19,6 @@ static const NotificationSequence sequence_blink_set_magenta = {
NULL,
};
static const NotificationSequence sequence_blink_stop = {
&message_blink_stop,
NULL,
};
static const NotificationSequence* ibutton_notification_sequences[] = {
&sequence_error,
&sequence_success,
@ -106,6 +87,8 @@ static void ibutton_rpc_command_callback(RpcAppSystemEvent event, void* context)
if(event == RpcAppEventSessionClose) {
view_dispatcher_send_custom_event(
ibutton->view_dispatcher, iButtonCustomEventRpcSessionClose);
rpc_system_app_set_callback(ibutton->rpc_ctx, NULL, NULL);
ibutton->rpc_ctx = NULL;
} else if(event == RpcAppEventAppExit) {
view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcExit);
} else if(event == RpcAppEventLoadFile) {
@ -324,22 +307,6 @@ void ibutton_text_store_clear(iButton* ibutton) {
memset(ibutton->text_store, 0, IBUTTON_TEXT_STORE_SIZE);
}
void ibutton_switch_to_previous_scene_one_of(
iButton* ibutton,
const uint32_t* scene_ids,
size_t scene_ids_size) {
furi_assert(scene_ids_size);
SceneManager* scene_manager = ibutton->scene_manager;
for(size_t i = 0; i < scene_ids_size; ++i) {
const uint32_t scene_id = scene_ids[i];
if(scene_manager_has_previous_scene(scene_manager, scene_id)) {
scene_manager_search_and_switch_to_previous_scene(scene_manager, scene_id);
return;
}
}
}
void ibutton_notification_message(iButton* ibutton, uint32_t message) {
furi_assert(message < sizeof(ibutton_notification_sequences) / sizeof(NotificationSequence*));
notification_message(ibutton->notifications, ibutton_notification_sequences[message]);
@ -353,7 +320,7 @@ int32_t ibutton_app(void* p) {
bool key_loaded = false;
bool rpc_mode = false;
if(p) {
if(p && strlen(p)) {
uint32_t rpc_ctx = 0;
if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) {
FURI_LOG_D(TAG, "Running in RPC mode");

View File

@ -83,8 +83,4 @@ bool ibutton_save_key(iButton* ibutton, const char* key_name);
bool ibutton_delete_key(iButton* ibutton);
void ibutton_text_store_set(iButton* ibutton, const char* text, ...);
void ibutton_text_store_clear(iButton* ibutton);
void ibutton_switch_to_previous_scene_one_of(
iButton* ibutton,
const uint32_t* scene_ids,
size_t scene_ids_size);
void ibutton_notification_message(iButton* ibutton, uint32_t message);

View File

@ -21,7 +21,7 @@ void ibutton_scene_exit_confirm_on_enter(void* context) {
widget_add_string_element(
widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Exit to iButton menu?");
widget_add_string_element(
widget, 64, 31, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost.");
widget, 64, 31, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!");
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
}

View File

@ -14,7 +14,7 @@ void ibutton_scene_read_on_enter(void* context) {
DOLPHIN_DEED(DolphinDeedIbuttonRead);
popup_set_header(popup, "iButton", 95, 26, AlignCenter, AlignBottom);
popup_set_text(popup, "waiting\nfor key ...", 95, 30, AlignCenter, AlignTop);
popup_set_text(popup, "Waiting\nfor key ...", 95, 30, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 5, &I_DolphinWait_61x59);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);

View File

@ -21,7 +21,7 @@ void ibutton_scene_retry_confirm_on_enter(void* context) {
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.");
widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!");
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
}

View File

@ -29,7 +29,7 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) {
if(event.event == iButtonCustomEventRpcLoad) {
const char* arg = rpc_system_app_get_data(ibutton->rpc_ctx);
bool result = false;
if(arg) {
if(arg && (string_empty_p(ibutton->file_path))) {
string_set_str(ibutton->file_path, arg);
if(ibutton_load_key_data(ibutton, ibutton->file_path, false)) {
ibutton_worker_emulate_start(ibutton->key_worker, ibutton->key);
@ -51,17 +51,17 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) {
string_clear(key_name);
result = true;
} else {
string_reset(ibutton->file_path);
}
}
rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventLoadFile, result);
} else if(event.event == iButtonCustomEventRpcExit) {
rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventAppExit, true);
ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop);
scene_manager_stop(ibutton->scene_manager);
view_dispatcher_stop(ibutton->view_dispatcher);
} else if(event.event == iButtonCustomEventRpcSessionClose) {
rpc_system_app_set_callback(ibutton->rpc_ctx, NULL, NULL);
ibutton->rpc_ctx = NULL;
ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop);
scene_manager_stop(ibutton->scene_manager);
view_dispatcher_stop(ibutton->view_dispatcher);
}
}

View File

@ -61,8 +61,8 @@ bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) {
} else {
const uint32_t possible_scenes[] = {
iButtonSceneReadKeyMenu, iButtonSceneSavedKeyMenu, iButtonSceneAddType};
ibutton_switch_to_previous_scene_one_of(
ibutton, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t));
scene_manager_search_and_switch_to_previous_scene_one_of(
ibutton->scene_manager, possible_scenes, COUNT_OF(possible_scenes));
}
}
}

View File

@ -31,8 +31,8 @@ bool ibutton_scene_save_success_on_event(void* context, SceneManagerEvent event)
if(event.event == iButtonCustomEventBack) {
const uint32_t possible_scenes[] = {
iButtonSceneReadKeyMenu, iButtonSceneSavedKeyMenu, iButtonSceneAddType};
ibutton_switch_to_previous_scene_one_of(
ibutton, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t));
scene_manager_search_and_switch_to_previous_scene_one_of(
ibutton->scene_manager, possible_scenes, COUNT_OF(possible_scenes));
}
}

View File

@ -31,8 +31,8 @@ bool ibutton_scene_write_success_on_event(void* context, SceneManagerEvent event
consumed = true;
if(event.event == iButtonCustomEventBack) {
const uint32_t possible_scenes[] = {iButtonSceneReadKeyMenu, iButtonSceneStart};
ibutton_switch_to_previous_scene_one_of(
ibutton, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t));
scene_manager_search_and_switch_to_previous_scene_one_of(
ibutton->scene_manager, possible_scenes, COUNT_OF(possible_scenes));
}
}

View File

@ -7,10 +7,12 @@ static const NotificationSequence* infrared_notification_sequences[] = {
&sequence_success,
&sequence_set_only_green_255,
&sequence_reset_green,
&sequence_blink_cyan_10,
&sequence_blink_magenta_10,
&sequence_solid_yellow,
&sequence_reset_rgb};
&sequence_reset_rgb,
&sequence_blink_start_cyan,
&sequence_blink_start_magenta,
&sequence_blink_stop,
};
static void infrared_make_app_folder(Infrared* infrared) {
if(!storage_simply_mkdir(infrared->storage, INFRARED_APP_FOLDER)) {
@ -44,6 +46,8 @@ static void infrared_rpc_command_callback(RpcAppSystemEvent event, void* context
if(event == RpcAppEventSessionClose) {
view_dispatcher_send_custom_event(
infrared->view_dispatcher, InfraredCustomEventTypeRpcSessionClose);
rpc_system_app_set_callback(infrared->rpc_ctx, NULL, NULL);
infrared->rpc_ctx = NULL;
} else if(event == RpcAppEventAppExit) {
view_dispatcher_send_custom_event(
infrared->view_dispatcher, InfraredCustomEventTypeRpcExit);
@ -291,6 +295,13 @@ bool infrared_rename_current_remote(Infrared* infrared, const char* name) {
}
void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) {
if(infrared->app_state.is_transmitting) {
FURI_LOG_D(INFRARED_LOG_TAG, "Transmitter is already active");
return;
} else {
infrared->app_state.is_transmitting = true;
}
if(infrared_signal_is_raw(signal)) {
InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal);
infrared_worker_set_raw_signal(infrared->worker, raw->timings, raw->timings_size);
@ -300,6 +311,10 @@ void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) {
}
DOLPHIN_DEED(DolphinDeedIrSend);
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend);
infrared_worker_tx_set_get_signal_callback(
infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared);
infrared_worker_tx_start(infrared->worker);
}
@ -310,14 +325,26 @@ void infrared_tx_start_button_index(Infrared* infrared, size_t button_index) {
InfraredSignal* signal = infrared_remote_button_get_signal(button);
infrared_tx_start_signal(infrared, signal);
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend);
}
void infrared_tx_start_received(Infrared* infrared) {
infrared_tx_start_signal(infrared, infrared->received_signal);
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend);
}
void infrared_tx_stop(Infrared* infrared) {
if(!infrared->app_state.is_transmitting) {
FURI_LOG_D(INFRARED_LOG_TAG, "Transmitter is already stopped");
return;
} else {
infrared->app_state.is_transmitting = false;
}
infrared_worker_tx_stop(infrared->worker);
infrared_worker_tx_set_get_signal_callback(infrared->worker, NULL, NULL);
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop);
}
void infrared_text_store_set(Infrared* infrared, uint32_t bank, const char* text, ...) {
@ -354,12 +381,6 @@ void infrared_show_loading_popup(Infrared* infrared, bool show) {
}
}
void infrared_signal_sent_callback(void* context) {
furi_assert(context);
Infrared* infrared = context;
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkSend);
}
void infrared_signal_received_callback(void* context, InfraredWorkerSignal* received_signal) {
furi_assert(context);
Infrared* infrared = context;
@ -405,7 +426,7 @@ int32_t infrared_app(void* p) {
bool is_remote_loaded = false;
bool is_rpc_mode = false;
if(p) {
if(p && strlen(p)) {
uint32_t rpc_ctx = 0;
if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) {
infrared->rpc_ctx = (void*)rpc_ctx;

View File

@ -27,7 +27,7 @@ static void signal_received_callback(void* context, InfraredWorkerSignal* receiv
if(infrared_worker_signal_is_decoded(received_signal)) {
const InfraredMessage* message = infrared_worker_get_decoded_signal(received_signal);
buf_cnt = sniprintf(
buf_cnt = snprintf(
buf,
sizeof(buf),
"%s, A:0x%0*lX, C:0x%0*lX%s\r\n",
@ -43,13 +43,13 @@ static void signal_received_callback(void* context, InfraredWorkerSignal* receiv
size_t timings_cnt;
infrared_worker_get_raw_signal(received_signal, &timings, &timings_cnt);
buf_cnt = sniprintf(buf, sizeof(buf), "RAW, %d samples:\r\n", timings_cnt);
buf_cnt = snprintf(buf, sizeof(buf), "RAW, %d samples:\r\n", timings_cnt);
cli_write(cli, (uint8_t*)buf, buf_cnt);
for(size_t i = 0; i < timings_cnt; ++i) {
buf_cnt = sniprintf(buf, sizeof(buf), "%lu ", timings[i]);
buf_cnt = snprintf(buf, sizeof(buf), "%lu ", timings[i]);
cli_write(cli, (uint8_t*)buf, buf_cnt);
}
buf_cnt = sniprintf(buf, sizeof(buf), "\r\n");
buf_cnt = snprintf(buf, sizeof(buf), "\r\n");
cli_write(cli, (uint8_t*)buf, buf_cnt);
}
}

View File

@ -43,6 +43,7 @@
#define INFRARED_APP_EXTENSION ".ir"
#define INFRARED_DEFAULT_REMOTE_NAME "Remote"
#define INFRARED_LOG_TAG "InfraredApp"
typedef enum {
InfraredButtonIndexNone = -1,
@ -63,6 +64,7 @@ typedef enum {
typedef struct {
bool is_learning_new_remote;
bool is_debug_enabled;
bool is_transmitting;
InfraredEditTarget edit_target : 8;
InfraredEditMode edit_mode : 8;
int32_t current_button_index;
@ -115,10 +117,11 @@ typedef enum {
InfraredNotificationMessageSuccess,
InfraredNotificationMessageGreenOn,
InfraredNotificationMessageGreenOff,
InfraredNotificationMessageBlinkRead,
InfraredNotificationMessageBlinkSend,
InfraredNotificationMessageYellowOn,
InfraredNotificationMessageYellowOff,
InfraredNotificationMessageBlinkStartRead,
InfraredNotificationMessageBlinkStartSend,
InfraredNotificationMessageBlinkStop,
} InfraredNotificationMessage;
bool infrared_add_remote_with_button(Infrared* infrared, const char* name, InfraredSignal* signal);
@ -132,7 +135,6 @@ void infrared_text_store_clear(Infrared* infrared, uint32_t bank);
void infrared_play_notification_message(Infrared* infrared, uint32_t message);
void infrared_show_loading_popup(Infrared* infrared, bool show);
void infrared_signal_sent_callback(void* context);
void infrared_signal_received_callback(void* context, InfraredWorkerSignal* received_signal);
void infrared_text_input_callback(void* context);
void infrared_popup_closed_callback(void* context);

View File

@ -21,12 +21,14 @@ static void infrared_scene_universal_common_show_popup(Infrared* infrared, uint3
infrared_progress_view_set_back_callback(
progress, infrared_scene_universal_common_progress_back_callback, infrared);
view_stack_add_view(view_stack, infrared_progress_view_get_view(progress));
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend);
}
static void infrared_scene_universal_common_hide_popup(Infrared* infrared) {
ViewStack* view_stack = infrared->view_stack;
InfraredProgressView* progress = infrared->progress;
view_stack_remove_view(view_stack, infrared_progress_view_get_view(progress));
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop);
}
void infrared_scene_universal_common_on_enter(void* context) {
@ -42,7 +44,6 @@ bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent e
if(infrared_brute_force_is_started(brute_force)) {
if(event.type == SceneManagerEventTypeTick) {
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkSend);
bool success = infrared_brute_force_send_next(brute_force);
if(success) {
success = infrared_progress_view_increase_progress(infrared->progress);
@ -71,8 +72,6 @@ bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent e
brute_force, infrared_custom_event_get_value(event.event), &record_count)) {
DOLPHIN_DEED(DolphinDeedIrBruteForce);
infrared_scene_universal_common_show_popup(infrared, record_count);
infrared_play_notification_message(
infrared, InfraredNotificationMessageBlinkSend);
} else {
scene_manager_next_scene(scene_manager, InfraredSceneErrorDatabases);
}

View File

@ -10,13 +10,13 @@ void infrared_scene_ask_back_on_enter(void* context) {
DialogEx* dialog_ex = infrared->dialog_ex;
if(infrared->app_state.is_learning_new_remote) {
dialog_ex_set_header(dialog_ex, "Exit to Infrared menu?", 64, 0, AlignCenter, AlignTop);
dialog_ex_set_header(dialog_ex, "Exit to Infrared Menu?", 64, 0, AlignCenter, AlignTop);
} else {
dialog_ex_set_header(dialog_ex, "Exit to remote menu?", 64, 0, AlignCenter, AlignTop);
dialog_ex_set_header(dialog_ex, "Exit to Remote Menu?", 64, 0, AlignCenter, AlignTop);
}
dialog_ex_set_text(
dialog_ex, "All unsaved data\nwill be lost.", 64, 31, AlignCenter, AlignCenter);
dialog_ex, "All unsaved data\nwill be lost!", 64, 31, AlignCenter, AlignCenter);
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
dialog_ex_set_left_button_text(dialog_ex, "Exit");
dialog_ex_set_center_button_text(dialog_ex, NULL);

View File

@ -9,9 +9,9 @@ void infrared_scene_ask_retry_on_enter(void* context) {
Infrared* infrared = context;
DialogEx* dialog_ex = infrared->dialog_ex;
dialog_ex_set_header(dialog_ex, "Return to reading?", 64, 0, AlignCenter, AlignTop);
dialog_ex_set_header(dialog_ex, "Return to Reading?", 64, 0, AlignCenter, AlignTop);
dialog_ex_set_text(
dialog_ex, "All unsaved data\nwill be lost.", 64, 31, AlignCenter, AlignCenter);
dialog_ex, "All unsaved data\nwill be lost!", 64, 31, AlignCenter, AlignCenter);
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
dialog_ex_set_left_button_text(dialog_ex, "Exit");
dialog_ex_set_center_button_text(dialog_ex, NULL);

View File

@ -65,4 +65,5 @@ void infrared_scene_debug_on_exit(void* context) {
InfraredWorker* worker = infrared->worker;
infrared_worker_rx_stop(worker);
infrared_worker_rx_enable_blink_on_receiving(worker, false);
infrared_worker_rx_set_received_signal_callback(worker, NULL, NULL);
}

View File

@ -16,7 +16,7 @@ void infrared_scene_edit_delete_on_enter(void* context) {
int32_t current_button_index = infrared->app_state.current_button_index;
furi_assert(current_button_index != InfraredButtonIndexNone);
dialog_ex_set_header(dialog_ex, "Delete button?", 64, 0, AlignCenter, AlignTop);
dialog_ex_set_header(dialog_ex, "Delete Button?", 64, 0, AlignCenter, AlignTop);
InfraredRemoteButton* current_button =
infrared_remote_get_button(remote, current_button_index);
InfraredSignal* signal = infrared_remote_button_get_signal(current_button);
@ -45,7 +45,7 @@ void infrared_scene_edit_delete_on_enter(void* context) {
}
} else if(edit_target == InfraredEditTargetRemote) {
dialog_ex_set_header(dialog_ex, "Delete remote?", 64, 0, AlignCenter, AlignTop);
dialog_ex_set_header(dialog_ex, "Delete Remote?", 64, 0, AlignCenter, AlignTop);
infrared_text_store_set(
infrared,
0,
@ -97,7 +97,7 @@ bool infrared_scene_edit_delete_on_event(void* context, SceneManagerEvent event)
} else {
const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart};
scene_manager_search_and_switch_to_previous_scene_one_of(
scene_manager, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t));
scene_manager, possible_scenes, COUNT_OF(possible_scenes));
}
consumed = true;
}

View File

@ -28,8 +28,10 @@ bool infrared_scene_edit_delete_done_on_event(void* context, SceneManagerEvent e
scene_manager, InfraredSceneRemote);
} else if(edit_target == InfraredEditTargetRemote) {
const uint32_t possible_scenes[] = {InfraredSceneStart, InfraredSceneRemoteList};
scene_manager_search_and_switch_to_previous_scene_one_of(
scene_manager, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t));
if(!scene_manager_search_and_switch_to_previous_scene_one_of(
scene_manager, possible_scenes, COUNT_OF(possible_scenes))) {
view_dispatcher_stop(infrared->view_dispatcher);
}
} else {
furi_assert(0);
}

View File

@ -21,7 +21,10 @@ bool infrared_scene_edit_rename_done_on_event(void* context, SceneManagerEvent e
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == InfraredCustomEventTypePopupClosed) {
scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote);
if(!scene_manager_search_and_switch_to_previous_scene(
infrared->scene_manager, InfraredSceneRemote)) {
scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote);
}
consumed = true;
}
}

View File

@ -8,6 +8,7 @@ void infrared_scene_learn_on_enter(void* context) {
infrared_worker_rx_set_received_signal_callback(
worker, infrared_signal_received_callback, context);
infrared_worker_rx_start(worker);
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartRead);
popup_set_icon(popup, 0, 32, &I_InfraredLearnShort_128x31);
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignCenter);
@ -22,10 +23,7 @@ bool infrared_scene_learn_on_event(void* context, SceneManagerEvent event) {
Infrared* infrared = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeTick) {
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkRead);
consumed = true;
} else if(event.type == SceneManagerEventTypeCustom) {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == InfraredCustomEventTypeSignalReceived) {
infrared_worker_rx_set_received_signal_callback(infrared->worker, NULL, NULL);
infrared_play_notification_message(infrared, InfraredNotificationMessageSuccess);
@ -41,6 +39,7 @@ void infrared_scene_learn_on_exit(void* context) {
Infrared* infrared = context;
Popup* popup = infrared->popup;
infrared_worker_rx_stop(infrared->worker);
infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop);
popup_set_icon(popup, 0, 0, NULL);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignCenter);
}

View File

@ -29,7 +29,10 @@ bool infrared_scene_learn_done_on_event(void* context, SceneManagerEvent event)
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == InfraredCustomEventTypePopupClosed) {
scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote);
if(!scene_manager_search_and_switch_to_previous_scene(
infrared->scene_manager, InfraredSceneRemote)) {
scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote);
}
consumed = true;
}
}

View File

@ -2,11 +2,6 @@
#include <dolphin/dolphin.h>
typedef enum {
InfraredSceneLearnSuccessStateIdle = 0,
InfraredSceneLearnSuccessStateSending = 1,
} InfraredSceneLearnSuccessState;
static void
infrared_scene_learn_success_dialog_result_callback(DialogExResult result, void* context) {
Infrared* infrared = context;
@ -21,11 +16,6 @@ void infrared_scene_learn_success_on_enter(void* context) {
DOLPHIN_DEED(DolphinDeedIrLearnSuccess);
infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOn);
infrared_worker_tx_set_get_signal_callback(
infrared->worker, infrared_worker_tx_get_signal_steady_callback, context);
infrared_worker_tx_set_signal_sent_callback(
infrared->worker, infrared_signal_sent_callback, context);
if(infrared_signal_is_raw(signal)) {
InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal);
dialog_ex_set_header(dialog_ex, "Unknown", 95, 10, AlignCenter, AlignCenter);
@ -65,54 +55,42 @@ void infrared_scene_learn_success_on_enter(void* context) {
dialog_ex_set_context(dialog_ex, context);
dialog_ex_enable_extended_events(dialog_ex);
scene_manager_set_scene_state(
infrared->scene_manager, InfraredSceneLearnSuccess, InfraredSceneLearnSuccessStateIdle);
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewDialogEx);
}
bool infrared_scene_learn_success_on_event(void* context, SceneManagerEvent event) {
Infrared* infrared = context;
SceneManager* scene_manager = infrared->scene_manager;
uint32_t scene_state = scene_manager_get_scene_state(scene_manager, InfraredSceneLearnSuccess);
const bool is_transmitter_idle = !infrared->app_state.is_transmitting;
bool consumed = false;
if(event.type == SceneManagerEventTypeTick) {
if(scene_state == InfraredSceneLearnSuccessStateIdle) {
if(is_transmitter_idle) {
infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOn);
}
consumed = true;
} else if(event.type == SceneManagerEventTypeBack) {
if(scene_state == InfraredSceneLearnSuccessStateIdle) {
if(is_transmitter_idle) {
scene_manager_next_scene(scene_manager, InfraredSceneAskBack);
}
consumed = true;
} else if(event.type == SceneManagerEventTypeCustom) {
if(event.event == DialogExResultLeft) {
if(scene_state == InfraredSceneLearnSuccessStateIdle) {
if(is_transmitter_idle) {
scene_manager_next_scene(scene_manager, InfraredSceneAskRetry);
}
consumed = true;
} else if(event.event == DialogExResultRight) {
if(scene_state == InfraredSceneLearnSuccessStateIdle) {
if(is_transmitter_idle) {
scene_manager_next_scene(scene_manager, InfraredSceneLearnEnterName);
}
consumed = true;
} else if(event.event == DialogExPressCenter) {
if(scene_state == InfraredSceneLearnSuccessStateIdle) {
scene_manager_set_scene_state(
scene_manager,
InfraredSceneLearnSuccess,
InfraredSceneLearnSuccessStateSending);
infrared_tx_start_received(infrared);
}
infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff);
infrared_tx_start_received(infrared);
consumed = true;
} else if(event.event == DialogExReleaseCenter) {
if(scene_state == InfraredSceneLearnSuccessStateSending) {
scene_manager_set_scene_state(
scene_manager, InfraredSceneLearnSuccess, InfraredSceneLearnSuccessStateIdle);
infrared_tx_stop(infrared);
infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff);
}
infrared_tx_stop(infrared);
consumed = true;
}
}
@ -122,9 +100,6 @@ bool infrared_scene_learn_success_on_event(void* context, SceneManagerEvent even
void infrared_scene_learn_success_on_exit(void* context) {
Infrared* infrared = context;
InfraredWorker* worker = infrared->worker;
dialog_ex_reset(infrared->dialog_ex);
infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff);
infrared_worker_tx_set_get_signal_callback(worker, NULL, NULL);
infrared_worker_tx_set_signal_sent_callback(worker, NULL, NULL);
}

View File

@ -31,11 +31,6 @@ void infrared_scene_remote_on_enter(void* context) {
ButtonMenu* button_menu = infrared->button_menu;
SceneManager* scene_manager = infrared->scene_manager;
infrared_worker_tx_set_get_signal_callback(
infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared);
infrared_worker_tx_set_signal_sent_callback(
infrared->worker, infrared_signal_sent_callback, infrared);
size_t button_count = infrared_remote_get_button_count(remote);
for(size_t i = 0; i < button_count; ++i) {
InfraredRemoteButton* button = infrared_remote_get_button(remote, i);
@ -75,12 +70,17 @@ void infrared_scene_remote_on_enter(void* context) {
bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) {
Infrared* infrared = context;
SceneManager* scene_manager = infrared->scene_manager;
const bool is_transmitter_idle = !infrared->app_state.is_transmitting;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart};
consumed = scene_manager_search_and_switch_to_previous_scene_one_of(
scene_manager, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t));
if(is_transmitter_idle) {
const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart};
consumed = scene_manager_search_and_switch_to_previous_scene_one_of(
scene_manager, possible_scenes, COUNT_OF(possible_scenes));
} else {
consumed = true;
}
} else if(event.type == SceneManagerEventTypeCustom) {
const uint16_t custom_type = infrared_custom_event_get_type(event.event);
const int16_t button_index = infrared_custom_event_get_value(event.event);
@ -94,14 +94,19 @@ bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) {
consumed = true;
} else if(custom_type == InfraredCustomEventTypeMenuSelected) {
furi_assert(button_index < 0);
scene_manager_set_scene_state(
scene_manager, InfraredSceneRemote, (unsigned)button_index);
if(button_index == ButtonIndexPlus) {
infrared->app_state.is_learning_new_remote = false;
scene_manager_next_scene(scene_manager, InfraredSceneLearn);
consumed = true;
} else if(button_index == ButtonIndexEdit) {
scene_manager_next_scene(scene_manager, InfraredSceneEdit);
if(is_transmitter_idle) {
scene_manager_set_scene_state(
scene_manager, InfraredSceneRemote, (unsigned)button_index);
if(button_index == ButtonIndexPlus) {
infrared->app_state.is_learning_new_remote = false;
scene_manager_next_scene(scene_manager, InfraredSceneLearn);
consumed = true;
} else if(button_index == ButtonIndexEdit) {
scene_manager_next_scene(scene_manager, InfraredSceneEdit);
consumed = true;
}
} else {
consumed = true;
}
}
@ -112,7 +117,5 @@ bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) {
void infrared_scene_remote_on_exit(void* context) {
Infrared* infrared = context;
infrared_worker_tx_set_get_signal_callback(infrared->worker, NULL, NULL);
infrared_worker_tx_set_signal_sent_callback(infrared->worker, NULL, NULL);
button_menu_reset(infrared->button_menu);
}

View File

@ -1,20 +1,28 @@
#include "../infrared_i.h"
#include "gui/canvas.h"
typedef enum {
InfraredRpcStateIdle,
InfraredRpcStateLoaded,
InfraredRpcStateSending,
} InfraredRpcState;
void infrared_scene_rpc_on_enter(void* context) {
Infrared* infrared = context;
Popup* popup = infrared->popup;
popup_set_header(popup, "Infrared", 82, 28, AlignCenter, AlignBottom);
popup_set_text(popup, "RPC mode", 82, 32, AlignCenter, AlignTop);
popup_set_header(popup, "Infrared", 89, 42, AlignCenter, AlignBottom);
popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop);
popup_set_icon(popup, 2, 14, &I_Warning_30x23); // TODO: icon
popup_set_icon(popup, 0, 12, &I_RFIDDolphinSend_97x61);
popup_set_context(popup, context);
popup_set_callback(popup, infrared_popup_closed_callback);
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup);
scene_manager_set_scene_state(infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateIdle);
notification_message(infrared->notifications, &sequence_display_backlight_on);
}
@ -24,6 +32,8 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
InfraredRpcState state =
scene_manager_get_scene_state(infrared->scene_manager, InfraredSceneRpc);
if(event.event == InfraredCustomEventTypeBackPressed) {
view_dispatcher_stop(infrared->view_dispatcher);
} else if(event.event == InfraredCustomEventTypePopupClosed) {
@ -31,41 +41,49 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) {
} else if(event.event == InfraredCustomEventTypeRpcLoad) {
bool result = false;
const char* arg = rpc_system_app_get_data(infrared->rpc_ctx);
if(arg) {
if(arg && (state == InfraredRpcStateIdle)) {
string_set_str(infrared->file_path, arg);
result = infrared_remote_load(infrared->remote, infrared->file_path);
infrared_worker_tx_set_get_signal_callback(
infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared);
infrared_worker_tx_set_signal_sent_callback(
infrared->worker, infrared_signal_sent_callback, infrared);
if(result) {
scene_manager_set_scene_state(
infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateLoaded);
}
}
const char* remote_name = infrared_remote_get_name(infrared->remote);
infrared_text_store_set(infrared, 0, "loaded\n%s", remote_name);
popup_set_text(
infrared->popup, infrared->text_store[0], 82, 32, AlignCenter, AlignTop);
infrared->popup, infrared->text_store[0], 89, 44, AlignCenter, AlignTop);
rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventLoadFile, result);
} else if(event.event == InfraredCustomEventTypeRpcButtonPress) {
bool result = false;
const char* arg = rpc_system_app_get_data(infrared->rpc_ctx);
if(arg) {
if(arg && (state == InfraredRpcStateLoaded)) {
size_t button_index = 0;
if(infrared_remote_find_button_by_name(infrared->remote, arg, &button_index)) {
infrared_tx_start_button_index(infrared, button_index);
result = true;
scene_manager_set_scene_state(
infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateSending);
}
}
rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventButtonRelease, result);
} else if(event.event == InfraredCustomEventTypeRpcButtonRelease) {
infrared_tx_stop(infrared);
rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventButtonRelease, true);
bool result = false;
if(state == InfraredRpcStateSending) {
infrared_tx_stop(infrared);
result = true;
scene_manager_set_scene_state(
infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateLoaded);
}
rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventButtonRelease, result);
} else if(event.event == InfraredCustomEventTypeRpcExit) {
scene_manager_stop(infrared->scene_manager);
view_dispatcher_stop(infrared->view_dispatcher);
rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventAppExit, true);
} else if(event.event == InfraredCustomEventTypeRpcSessionClose) {
rpc_system_app_set_callback(infrared->rpc_ctx, NULL, NULL);
infrared->rpc_ctx = NULL;
scene_manager_stop(infrared->scene_manager);
view_dispatcher_stop(infrared->view_dispatcher);
}
}
@ -74,5 +92,9 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) {
void infrared_scene_rpc_on_exit(void* context) {
Infrared* infrared = context;
if(scene_manager_get_scene_state(infrared->scene_manager, InfraredSceneRpc) ==
InfraredRpcStateSending) {
infrared_tx_stop(infrared);
}
popup_reset(infrared->popup);
}

View File

@ -64,7 +64,8 @@ const char* input_get_type_name(InputType type) {
return "Unknown";
}
int32_t input_srv() {
int32_t input_srv(void* p) {
UNUSED(p);
input = malloc(sizeof(Input));
input->thread_id = furi_thread_get_current_id();
input->event_pubsub = furi_pubsub_alloc();

View File

@ -56,6 +56,9 @@ static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) {
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;
@ -74,22 +77,25 @@ void LfRfidApp::run(void* _args) {
make_app_folder();
if(strlen(args)) {
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, &worker.key, 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());

View File

@ -101,5 +101,4 @@ public:
bool save_key_data(string_t path, RfidKey* key);
void make_app_folder();
//bool rpc_command_callback(RpcAppSystemEvent event, const char* arg, void* context);
};

View File

@ -107,7 +107,7 @@ static void lfrfid_cli_write(Cli* cli, string_t args) {
UNUSED(cli);
UNUSED(args);
// TODO implement rfid write
printf("Not implemented :(\r\n");
printf("Not Implemented :(\r\n");
}
static void lfrfid_cli_emulate(Cli* cli, string_t args) {

View File

@ -2,18 +2,6 @@
#include <core/common_defines.h>
#include <dolphin/dolphin.h>
static const NotificationSequence sequence_blink_start_magenta = {
&message_blink_start_10,
&message_blink_set_color_magenta,
&message_do_not_reset,
NULL,
};
static const NotificationSequence sequence_blink_stop = {
&message_blink_stop,
NULL,
};
void LfRfidAppSceneEmulate::on_enter(LfRfidApp* app, bool /* need_restore */) {
string_init(data_string);

View File

@ -17,9 +17,9 @@ void LfRfidAppSceneExitConfirm::on_enter(LfRfidApp* app, bool /* need_restore */
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_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);
"All unsaved data will be lost!", 64, 31, 0, AlignCenter, AlignBottom, FontSecondary);
app->view_controller.switch_to<ContainerVM>();
}

View File

@ -17,9 +17,9 @@ void LfRfidAppSceneRetryConfirm::on_enter(LfRfidApp* app, bool /* need_restore *
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_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);
"All unsaved data will be lost!", 64, 29, 0, AlignCenter, AlignBottom, FontSecondary);
app->view_controller.switch_to<ContainerVM>();
}

View File

@ -3,24 +3,12 @@
#include <dolphin/dolphin.h>
#include <rpc/rpc_app.h>
static const NotificationSequence sequence_blink_start_magenta = {
&message_blink_start_10,
&message_blink_set_color_magenta,
&message_do_not_reset,
NULL,
};
static const NotificationSequence sequence_blink_stop = {
&message_blink_stop,
NULL,
};
void LfRfidAppSceneRpc::on_enter(LfRfidApp* app, bool /* need_restore */) {
auto popup = app->view_controller.get<PopupVM>();
popup->set_header("LF RFID", 89, 30, AlignCenter, AlignTop);
popup->set_text("RPC mode", 89, 43, AlignCenter, AlignTop);
popup->set_icon(0, 3, &I_RFIDDolphinSend_97x61);
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>();
@ -39,33 +27,25 @@ bool LfRfidAppSceneRpc::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
app->view_controller.send_event(&view_event);
rpc_system_app_confirm(app->rpc_ctx, RpcAppEventAppExit, true);
} else if(event->type == LfRfidApp::EventType::RpcSessionClose) {
// Detach RPC
rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL);
app->rpc_ctx = NULL;
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::EmulateStart) {
auto popup = app->view_controller.get<PopupVM>();
consumed = true;
emulating = true;
app->text_store.set("emulating\n%s", app->worker.key.get_name());
popup->set_text(app->text_store.text, 89, 43, AlignCenter, AlignTop);
notification_message(app->notification, &sequence_blink_start_magenta);
} 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) {
if(arg && !emulating) {
string_set_str(app->file_path, arg);
if(app->load_key_data(app->file_path, &(app->worker.key), false)) {
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::EmulateStart;
app->view_controller.send_event(&event);
app->worker.start_emulate();
emulating = true;
auto popup = app->view_controller.get<PopupVM>();
app->text_store.set("emulating\n%s", app->worker.key.get_name());
popup->set_text(app->text_store.text, 89, 44, AlignCenter, AlignTop);
notification_message(app->notification, &sequence_blink_start_magenta);
result = true;
}
}

View File

@ -10,6 +10,7 @@ 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

@ -5,6 +5,6 @@ App(
entry_point="loader_srv",
cdefines=["SRV_LOADER"],
requires=["gui"],
stack_size=1 * 1024,
stack_size=2 * 1024,
order=90,
)

View File

@ -466,9 +466,9 @@ int32_t loader_srv(void* p) {
furi_record_create(RECORD_LOADER, loader_instance);
#ifdef LOADER_AUTOSTART
loader_start(loader_instance, LOADER_AUTOSTART, NULL);
#endif
if(FLIPPER_AUTORUN_APP_NAME && strlen(FLIPPER_AUTORUN_APP_NAME)) {
loader_start(loader_instance, FLIPPER_AUTORUN_APP_NAME, NULL);
}
while(1) {
uint32_t flags =

View File

@ -300,7 +300,7 @@ int32_t music_player_app(void* p) {
string_init(file_path);
do {
if(p) {
if(p && strlen(p)) {
string_cat_str(file_path, p);
} else {
string_set_str(file_path, MUSIC_PLAYER_APP_PATH_FOLDER);

View File

@ -10,7 +10,7 @@ App(
],
provides=["nfc_start"],
icon="A_NFC_14",
stack_size=4 * 1024,
stack_size=5 * 1024,
order=30,
)

View File

@ -55,6 +55,7 @@ static void nfc_generate_mf_ul_orig(NfcDeviceData* data) {
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeUnknown;
mful->data_size = 16 * 4;
mful->data_read = mful->data_size;
nfc_generate_mf_ul_copy_uid_with_bcc(data);
// TODO: what's internal byte on page 2?
memset(&mful->data[4 * 4], 0xFF, 4);
@ -67,6 +68,7 @@ static void nfc_generate_mf_ul_ntag203(NfcDeviceData* data) {
MfUltralightData* mful = &data->mf_ul_data;
mful->type = MfUltralightTypeNTAG203;
mful->data_size = 42 * 4;
mful->data_read = mful->data_size;
nfc_generate_mf_ul_copy_uid_with_bcc(data);
mful->data[9] = 0x48; // Internal byte
memcpy(&mful->data[3 * 4], default_data_ntag203, sizeof(default_data_ntag203));
@ -78,6 +80,7 @@ static void nfc_generate_mf_ul_with_config_common(NfcDeviceData* data, uint8_t n
MfUltralightData* mful = &data->mf_ul_data;
mful->data_size = num_pages * 4;
mful->data_read = mful->data_size;
nfc_generate_mf_ul_copy_uid_with_bcc(data);
uint16_t config_index = (num_pages - 4) * 4;
mful->data[config_index] = 0x04; // STRG_MOD_EN
@ -180,6 +183,7 @@ static void
mful->type = type;
memcpy(&mful->version, version_bytes_ntag_i2c, sizeof(version_bytes_ntag_i2c));
mful->data_size = num_pages * 4;
mful->data_read = mful->data_size;
memcpy(mful->data, data->nfc_data.uid, data->nfc_data.uid_len);
mful->data[7] = data->nfc_data.sak;
mful->data[8] = data->nfc_data.atqa[0];

View File

@ -21,6 +21,8 @@ static void nfc_rpc_command_callback(RpcAppSystemEvent event, void* context) {
if(event == RpcAppEventSessionClose) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcSessionClose);
rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL);
nfc->rpc_ctx = NULL;
} else if(event == RpcAppEventAppExit) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
} else if(event == RpcAppEventLoadFile) {
@ -199,18 +201,6 @@ void nfc_text_store_clear(Nfc* nfc) {
memset(nfc->text_store, 0, sizeof(nfc->text_store));
}
static const NotificationSequence sequence_blink_start_blue = {
&message_blink_start_10,
&message_blink_set_color_blue,
&message_do_not_reset,
NULL,
};
static const NotificationSequence sequence_blink_stop = {
&message_blink_stop,
NULL,
};
void nfc_blink_start(Nfc* nfc) {
notification_message(nfc->notifications, &sequence_blink_start_blue);
}
@ -238,7 +228,7 @@ int32_t nfc_app(void* p) {
char* args = p;
// Check argument and run corresponding scene
if((*args != '\0')) {
if(args && strlen(args)) {
nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc);
uint32_t rpc_ctx = 0;
if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) {

0
applications/nfc/nfc_i.h Executable file → Normal file
View File

View File

@ -15,11 +15,17 @@ ADD_SCENE(nfc, emulate_uid, EmulateUid)
ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess)
ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu)
ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate)
ADD_SCENE(nfc, mf_ultralight_read_auth, MfUltralightReadAuth)
ADD_SCENE(nfc, mf_ultralight_read_auth_result, MfUltralightReadAuthResult)
ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput)
ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu)
ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn)
ADD_SCENE(nfc, mf_desfire_read_success, MfDesfireReadSuccess)
ADD_SCENE(nfc, mf_desfire_menu, MfDesfireMenu)
ADD_SCENE(nfc, mf_desfire_data, MfDesfireData)
ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp)
ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess)
ADD_SCENE(nfc, mf_classic_info, MfClassicInfo)
ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu)
ADD_SCENE(nfc, mf_classic_emulate, MfClassicEmulate)
ADD_SCENE(nfc, mf_classic_keys, MfClassicKeys)

View File

@ -37,7 +37,7 @@ static void nfc_scene_detect_reader_widget_config(Nfc* nfc, bool data_received)
widget_add_icon_element(widget, 0, 14, &I_Reader_detect);
widget_add_string_element(
widget, 64, 3, AlignCenter, AlignTop, FontSecondary, "Hold near reader");
widget, 64, 3, AlignCenter, AlignTop, FontSecondary, "Hold Near Reader");
widget_add_string_element(widget, 55, 22, AlignLeft, AlignTop, FontPrimary, "Emulating...");
if(data_received) {

View File

@ -12,9 +12,9 @@ void nfc_scene_exit_confirm_on_enter(void* context) {
dialog_ex_set_left_button_text(dialog_ex, "Exit");
dialog_ex_set_right_button_text(dialog_ex, "Stay");
dialog_ex_set_header(dialog_ex, "Exit to NFC menu?", 64, 11, AlignCenter, AlignTop);
dialog_ex_set_header(dialog_ex, "Exit to NFC Menu?", 64, 11, AlignCenter, AlignTop);
dialog_ex_set_text(
dialog_ex, "All unsaved data\nwill be lost.", 64, 25, AlignCenter, AlignTop);
dialog_ex, "All unsaved data\nwill be lost!", 64, 25, AlignCenter, AlignTop);
dialog_ex_set_context(dialog_ex, nfc);
dialog_ex_set_result_callback(dialog_ex, nfc_scene_exit_confirm_dialog_callback);

View File

@ -2,6 +2,7 @@
enum SubmenuIndex {
SubmenuIndexMfClassicKeys,
SubmenuIndexMfUltralightUnlock,
};
void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) {
@ -20,6 +21,12 @@ void nfc_scene_extra_actions_on_enter(void* context) {
SubmenuIndexMfClassicKeys,
nfc_scene_extra_actions_submenu_callback,
nfc);
submenu_add_item(
submenu,
"Unlock NTAG/Ultralight",
SubmenuIndexMfUltralightUnlock,
nfc_scene_extra_actions_submenu_callback,
nfc);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
}
@ -35,6 +42,8 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound);
}
consumed = true;
} else if(event.event == SubmenuIndexMfUltralightUnlock) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
}
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event);
}

View File

@ -1,5 +1,7 @@
#include "../nfc_i.h"
#define TAG "NfcMfClassicDictAttack"
typedef enum {
DictAttackStateIdle,
DictAttackStateUserDictInProgress,
@ -32,7 +34,9 @@ static void nfc_scene_mf_classic_dict_attack_update_view(Nfc* nfc) {
static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackState state) {
MfClassicData* data = &nfc->dev->dev_data.mf_classic_data;
NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data;
NfcWorkerState worker_state = NfcWorkerStateReady;
MfClassicDict* dict = NULL;
// Identify scene state
if(state == DictAttackStateIdle) {
@ -47,16 +51,36 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackSt
// Setup view
if(state == DictAttackStateUserDictInProgress) {
worker_state = NfcWorkerStateMfClassicUserDictAttack;
worker_state = NfcWorkerStateMfClassicDictAttack;
dict_attack_set_header(nfc->dict_attack, "Mf Classic User Dict.");
} else if(state == DictAttackStateFlipperDictInProgress) {
worker_state = NfcWorkerStateMfClassicFlipperDictAttack;
dict_attack_set_header(nfc->dict_attack, "Mf Classic Flipper Dict.");
dict = mf_classic_dict_alloc(MfClassicDictTypeUser);
// If failed to load user dictionary - try flipper dictionary
if(!dict) {
FURI_LOG_E(TAG, "User dictionary not found");
state = DictAttackStateFlipperDictInProgress;
}
}
if(state == DictAttackStateFlipperDictInProgress) {
worker_state = NfcWorkerStateMfClassicDictAttack;
dict_attack_set_header(nfc->dict_attack, "Mf Classic Flipper Dict.");
dict = mf_classic_dict_alloc(MfClassicDictTypeFlipper);
if(!dict) {
FURI_LOG_E(TAG, "Flipper dictionary not found");
// Pass through to let worker handle the failure
}
}
// Free previous dictionary
if(dict_attack_data->dict) {
mf_classic_dict_free(dict_attack_data->dict);
}
dict_attack_data->dict = dict;
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack, state);
dict_attack_set_callback(nfc->dict_attack, nfc_dict_attack_dict_attack_result_callback, nfc);
dict_attack_set_current_sector(nfc->dict_attack, 0);
dict_attack_set_card_detected(nfc->dict_attack, data->type);
dict_attack_set_total_dict_keys(
nfc->dict_attack, dict ? mf_classic_dict_get_total_keys(dict) : 0);
nfc_scene_mf_classic_dict_attack_update_view(nfc);
nfc_worker_start(
nfc->worker, worker_state, &nfc->dev->dev_data, nfc_dict_attack_worker_callback, nfc);
@ -112,6 +136,10 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent
nfc_scene_mf_classic_dict_attack_update_view(nfc);
dict_attack_inc_current_sector(nfc->dict_attack);
consumed = true;
} else if(event.event == NfcWorkerEventNewDictKeyBatch) {
nfc_scene_mf_classic_dict_attack_update_view(nfc);
dict_attack_inc_current_dict_key(nfc->dict_attack, NFC_DICT_KEY_BATCH_SIZE);
consumed = true;
} else if(event.event == NfcCustomEventDictAttackSkip) {
if(state == DictAttackStateUserDictInProgress) {
nfc_worker_stop(nfc->worker);
@ -130,8 +158,13 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent
void nfc_scene_mf_classic_dict_attack_on_exit(void* context) {
Nfc* nfc = context;
NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data;
// Stop worker
nfc_worker_stop(nfc->worker);
if(dict_attack_data->dict) {
mf_classic_dict_free(dict_attack_data->dict);
dict_attack_data->dict = NULL;
}
dict_attack_reset(nfc->dict_attack);
nfc_blink_stop(nfc);
}

View File

@ -0,0 +1,72 @@
#include "../nfc_i.h"
void nfc_scene_mf_classic_info_widget_callback(GuiButtonType result, InputType type, void* context) {
furi_assert(context);
Nfc* nfc = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
}
void nfc_scene_mf_classic_info_on_enter(void* context) {
Nfc* nfc = context;
NfcDeviceData* dev_data = &nfc->dev->dev_data;
MfClassicData* mf_data = &dev_data->mf_classic_data;
string_t str_tmp;
string_init(str_tmp);
// Setup view
Widget* widget = nfc->widget;
widget_add_string_element(
widget, 0, 0, AlignLeft, AlignTop, FontSecondary, mf_classic_get_type_str(mf_data->type));
widget_add_string_element(
widget, 0, 11, AlignLeft, AlignTop, FontSecondary, "ISO 14443-3 (Type A)");
string_printf(str_tmp, "UID:");
for(size_t i = 0; i < dev_data->nfc_data.uid_len; i++) {
string_cat_printf(str_tmp, " %02X", dev_data->nfc_data.uid[i]);
}
widget_add_string_element(
widget, 0, 22, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp));
string_printf(
str_tmp,
"ATQA: %02X %02X SAK: %02X",
dev_data->nfc_data.atqa[0],
dev_data->nfc_data.atqa[1],
dev_data->nfc_data.sak);
widget_add_string_element(
widget, 0, 33, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp));
uint8_t sectors_total = mf_classic_get_total_sectors_num(mf_data->type);
uint8_t keys_total = sectors_total * 2;
uint8_t keys_found = 0;
uint8_t sectors_read = 0;
mf_classic_get_read_sectors_and_keys(mf_data, &sectors_read, &keys_found);
string_printf(str_tmp, "Keys Found: %d/%d", keys_found, keys_total);
widget_add_string_element(
widget, 0, 44, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp));
string_printf(str_tmp, "Sectors Read: %d/%d", sectors_read, sectors_total);
widget_add_string_element(
widget, 0, 55, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp));
string_clear(str_tmp);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
}
bool nfc_scene_mf_classic_info_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
consumed = scene_manager_previous_scene(nfc->scene_manager);
}
return consumed;
}
void nfc_scene_mf_classic_info_on_exit(void* context) {
Nfc* nfc = context;
// Clear view
widget_reset(nfc->widget);
}

View File

@ -3,6 +3,7 @@
enum SubmenuIndex {
SubmenuIndexSave,
SubmenuIndexEmulate,
SubmenuIndexInfo,
};
void nfc_scene_mf_classic_menu_submenu_callback(void* context, uint32_t index) {
@ -19,6 +20,9 @@ void nfc_scene_mf_classic_menu_on_enter(void* context) {
submenu, "Save", SubmenuIndexSave, nfc_scene_mf_classic_menu_submenu_callback, nfc);
submenu_add_item(
submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mf_classic_menu_submenu_callback, nfc);
submenu_add_item(
submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_classic_menu_submenu_callback, nfc);
submenu_set_selected_item(
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicMenu));
@ -43,6 +47,11 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event)
nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexEmulate);
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate);
consumed = true;
} else if(event.event == SubmenuIndexInfo) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexInfo);
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicInfo);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeBack) {
consumed = scene_manager_previous_scene(nfc->scene_manager);

View File

@ -0,0 +1,44 @@
#include "../nfc_i.h"
void nfc_scene_mf_ultralight_key_input_byte_input_callback(void* context) {
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
}
void nfc_scene_mf_ultralight_key_input_on_enter(void* context) {
Nfc* nfc = context;
// Setup view
ByteInput* byte_input = nfc->byte_input;
byte_input_set_header_text(byte_input, "Enter the password in hex");
byte_input_set_result_callback(
byte_input,
nfc_scene_mf_ultralight_key_input_byte_input_callback,
NULL,
nfc,
nfc->byte_input_store,
4);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput);
}
bool nfc_scene_mf_ultralight_key_input_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventByteInputDone) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn);
consumed = true;
}
}
return consumed;
}
void nfc_scene_mf_ultralight_key_input_on_exit(void* context) {
Nfc* nfc = context;
// Clear view
byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);
byte_input_set_header_text(nfc->byte_input, "");
}

View File

@ -1,6 +1,7 @@
#include "../nfc_i.h"
enum SubmenuIndex {
SubmenuIndexUnlock,
SubmenuIndexSave,
SubmenuIndexEmulate,
};
@ -14,7 +15,16 @@ void nfc_scene_mf_ultralight_menu_submenu_callback(void* context, uint32_t index
void nfc_scene_mf_ultralight_menu_on_enter(void* context) {
Nfc* nfc = context;
Submenu* submenu = nfc->submenu;
MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data;
if(data->data_read != data->data_size) {
submenu_add_item(
submenu,
"Unlock With Password",
SubmenuIndexUnlock,
nfc_scene_mf_ultralight_menu_submenu_callback,
nfc);
}
submenu_add_item(
submenu, "Save", SubmenuIndexSave, nfc_scene_mf_ultralight_menu_submenu_callback, nfc);
submenu_add_item(
@ -35,19 +45,20 @@ bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent even
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexSave) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfUltralightMenu, SubmenuIndexSave);
nfc->dev->format = NfcDeviceSaveFormatMifareUl;
// Clear device name
nfc_device_set_name(nfc->dev, "");
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
consumed = true;
} else if(event.event == SubmenuIndexEmulate) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfUltralightMenu, SubmenuIndexEmulate);
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate);
consumed = true;
} else if(event.event == SubmenuIndexUnlock) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
consumed = true;
}
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu, event.event);
} else if(event.type == SceneManagerEventTypeBack) {
consumed = scene_manager_previous_scene(nfc->scene_manager);
}

View File

@ -0,0 +1,107 @@
#include "../nfc_i.h"
#include <dolphin/dolphin.h>
typedef enum {
NfcSceneMfUlReadStateIdle,
NfcSceneMfUlReadStateDetecting,
NfcSceneMfUlReadStateReading,
NfcSceneMfUlReadStateNotSupportedCard,
} NfcSceneMfUlReadState;
bool nfc_scene_mf_ultralight_read_auth_worker_callback(NfcWorkerEvent event, void* context) {
Nfc* nfc = context;
if(event == NfcWorkerEventMfUltralightPassKey) {
memcpy(nfc->dev->dev_data.mf_ul_data.auth_key, nfc->byte_input_store, 4);
} else {
view_dispatcher_send_custom_event(nfc->view_dispatcher, event);
}
return true;
}
void nfc_scene_mf_ultralight_read_auth_set_state(Nfc* nfc, NfcSceneMfUlReadState state) {
uint32_t curr_state =
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadAuth);
if(curr_state != state) {
if(state == NfcSceneMfUlReadStateDetecting) {
popup_reset(nfc->popup);
popup_set_text(
nfc->popup, "Apply card to\nFlipper's back", 97, 24, AlignCenter, AlignTop);
popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual);
} else if(state == NfcSceneMfUlReadStateReading) {
popup_reset(nfc->popup);
popup_set_header(
nfc->popup, "Reading card\nDon't move...", 85, 24, AlignCenter, AlignTop);
popup_set_icon(nfc->popup, 12, 23, &A_Loading_24);
} else if(state == NfcSceneMfUlReadStateNotSupportedCard) {
popup_reset(nfc->popup);
popup_set_header(nfc->popup, "Wrong type of card!", 64, 3, AlignCenter, AlignTop);
popup_set_text(
nfc->popup,
"Only MIFARE\nUltralight & NTAG\n are supported",
4,
22,
AlignLeft,
AlignTop);
popup_set_icon(nfc->popup, 73, 17, &I_DolphinFirstStart8_56x51);
}
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadAuth, state);
}
}
void nfc_scene_mf_ultralight_read_auth_on_enter(void* context) {
Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcRead);
nfc_device_clear(nfc->dev);
// Setup view
nfc_scene_mf_ultralight_read_auth_set_state(nfc, NfcSceneMfUlReadStateDetecting);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
// Start worker
nfc_worker_start(
nfc->worker,
NfcWorkerStateReadMfUltralightReadAuth,
&nfc->dev->dev_data,
nfc_scene_mf_ultralight_read_auth_worker_callback,
nfc);
nfc_blink_start(nfc);
}
bool nfc_scene_mf_ultralight_read_auth_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if((event.event == NfcWorkerEventSuccess) || (event.event == NfcWorkerEventFail)) {
notification_message(nfc->notifications, &sequence_success);
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuthResult);
consumed = true;
} else if(event.event == NfcWorkerEventCardDetected) {
nfc_scene_mf_ultralight_read_auth_set_state(nfc, NfcSceneMfUlReadStateReading);
consumed = true;
} else if(event.event == NfcWorkerEventNoCardDetected) {
nfc_scene_mf_ultralight_read_auth_set_state(nfc, NfcSceneMfUlReadStateDetecting);
consumed = true;
} else if(event.event == NfcWorkerEventWrongCardDetected) {
nfc_scene_mf_ultralight_read_auth_set_state(
nfc, NfcSceneMfUlReadStateNotSupportedCard);
}
} else if(event.type == SceneManagerEventTypeBack) {
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
}
return consumed;
}
void nfc_scene_mf_ultralight_read_auth_on_exit(void* context) {
Nfc* nfc = context;
// Stop worker
nfc_worker_stop(nfc->worker);
// Clear view
popup_reset(nfc->popup);
nfc_blink_stop(nfc);
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfUltralightReadAuth, NfcSceneMfUlReadStateIdle);
}

View File

@ -0,0 +1,98 @@
#include "../nfc_i.h"
#include <dolphin/dolphin.h>
void nfc_scene_mf_ultralight_read_auth_result_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
Nfc* nfc = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
}
void nfc_scene_mf_ultralight_read_auth_result_on_enter(void* context) {
Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
// Setup dialog view
FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data;
MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
MfUltralightConfigPages* config_pages = mf_ultralight_get_config_pages(mf_ul_data);
Widget* widget = nfc->widget;
string_t temp_str;
string_init(temp_str);
if((mf_ul_data->data_read == mf_ul_data->data_size) && (mf_ul_data->data_read > 0)) {
widget_add_string_element(
widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "All pages are unlocked!");
} else {
widget_add_string_element(
widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Not all pages unlocked!");
}
string_set_str(temp_str, "UID:");
for(size_t i = 0; i < nfc_data->uid_len; i++) {
string_cat_printf(temp_str, " %02X", nfc_data->uid[i]);
}
widget_add_string_element(
widget, 0, 17, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str));
if(mf_ul_data->auth_success) {
string_printf(
temp_str,
"Password: %02X %02X %02X %02X",
config_pages->auth_data.pwd.raw[0],
config_pages->auth_data.pwd.raw[1],
config_pages->auth_data.pwd.raw[2],
config_pages->auth_data.pwd.raw[3]);
widget_add_string_element(
widget, 0, 28, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str));
string_printf(
temp_str,
"PACK: %02X %02X",
config_pages->auth_data.pack.raw[0],
config_pages->auth_data.pack.raw[1]);
widget_add_string_element(
widget, 0, 39, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str));
}
string_printf(
temp_str, "Pages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4);
widget_add_string_element(
widget, 0, 50, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str));
widget_add_button_element(
widget,
GuiButtonTypeRight,
"Save",
nfc_scene_mf_ultralight_read_auth_result_widget_callback,
nfc);
string_clear(temp_str);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
}
bool nfc_scene_mf_ultralight_read_auth_result_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeRight) {
nfc->dev->format = NfcDeviceSaveFormatMifareUl;
// Clear device name
nfc_device_set_name(nfc->dev, "");
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeBack) {
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
}
return consumed;
}
void nfc_scene_mf_ultralight_read_auth_result_on_exit(void* context) {
Nfc* nfc = context;
// Clean views
widget_reset(nfc->widget);
}

View File

@ -1,51 +1,67 @@
#include "../nfc_i.h"
#include <dolphin/dolphin.h>
#define NFC_SCENE_READ_SUCCESS_SHIFT " "
enum {
ReadMifareUlStateShowUID,
ReadMifareUlStateShowInfo,
ReadMifareUlStateShowData,
};
void nfc_scene_mf_ultralight_read_success_dialog_callback(DialogExResult result, void* context) {
void nfc_scene_mf_ultralight_read_success_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
}
void nfc_scene_mf_ultralight_read_success_on_enter(void* context) {
Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
// Setup dialog view
// Setup widget view
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_set_left_button_text(dialog_ex, "Retry");
dialog_ex_set_right_button_text(dialog_ex, "More");
dialog_ex_set_center_button_text(dialog_ex, "Data");
dialog_ex_set_header(
dialog_ex, nfc_mf_ul_type(mf_ul_data->type, true), 64, 8, AlignCenter, AlignCenter);
dialog_ex_set_icon(dialog_ex, 8, 13, &I_Medium_chip_22x21);
// Display UID
nfc_text_store_set(
nfc,
NFC_SCENE_READ_SUCCESS_SHIFT "ATQA: %02X%02X\n" NFC_SCENE_READ_SUCCESS_SHIFT
"SAK: %02X\nUID: %02X %02X %02X %02X %02X %02X %02X",
data->atqa[0],
data->atqa[1],
data->sak,
data->uid[0],
data->uid[1],
data->uid[2],
data->uid[3],
data->uid[4],
data->uid[5],
data->uid[6]);
dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 16, AlignLeft, AlignTop);
dialog_ex_set_context(dialog_ex, nfc);
dialog_ex_set_result_callback(dialog_ex, nfc_scene_mf_ultralight_read_success_dialog_callback);
Widget* widget = nfc->widget;
widget_add_button_element(
widget,
GuiButtonTypeLeft,
"Retry",
nfc_scene_mf_ultralight_read_success_widget_callback,
nfc);
widget_add_button_element(
widget,
GuiButtonTypeCenter,
"Data",
nfc_scene_mf_ultralight_read_success_widget_callback,
nfc);
widget_add_button_element(
widget,
GuiButtonTypeRight,
"More",
nfc_scene_mf_ultralight_read_success_widget_callback,
nfc);
widget_add_string_element(
widget, 0, 0, AlignLeft, AlignTop, FontSecondary, nfc_mf_ul_type(mf_ul_data->type, true));
string_t data_str;
string_init_printf(data_str, "UID:");
for(size_t i = 0; i < data->uid_len; i++) {
string_cat_printf(data_str, " %02X", data->uid[i]);
}
widget_add_string_element(
widget, 0, 13, AlignLeft, AlignTop, FontSecondary, string_get_cstr(data_str));
string_printf(
data_str, "Pages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4);
widget_add_string_element(
widget, 0, 24, AlignLeft, AlignTop, FontSecondary, string_get_cstr(data_str));
if(mf_ul_data->data_read != mf_ul_data->data_size) {
widget_add_string_element(
widget, 0, 35, AlignLeft, AlignTop, FontSecondary, "Password-protected pages!");
}
string_clear(data_str);
// Setup TextBox view
TextBox* text_box = nfc->text_box;
@ -60,8 +76,8 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) {
text_box_set_text(text_box, string_get_cstr(nfc->text_box_store));
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowUID);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowInfo);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
}
bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEvent event) {
@ -71,13 +87,13 @@ bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEv
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadSuccess);
if(event.type == SceneManagerEventTypeCustom) {
if(state == ReadMifareUlStateShowUID && event.event == DialogExResultLeft) {
if(state == ReadMifareUlStateShowInfo && event.event == GuiButtonTypeLeft) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm);
consumed = true;
} else if(state == ReadMifareUlStateShowUID && event.event == DialogExResultRight) {
} else if(state == ReadMifareUlStateShowInfo && event.event == GuiButtonTypeRight) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu);
consumed = true;
} else if(state == ReadMifareUlStateShowUID && event.event == DialogExResultCenter) {
} else if(state == ReadMifareUlStateShowInfo && event.event == GuiButtonTypeCenter) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowData);
@ -85,9 +101,9 @@ bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEv
}
} else if(event.type == SceneManagerEventTypeBack) {
if(state == ReadMifareUlStateShowData) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowUID);
nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowInfo);
consumed = true;
} else {
scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm);
@ -102,7 +118,7 @@ void nfc_scene_mf_ultralight_read_success_on_exit(void* context) {
Nfc* nfc = context;
// Clean views
dialog_ex_reset(nfc->dialog_ex);
widget_reset(nfc->widget);
text_box_reset(nfc->text_box);
string_reset(nfc->text_box_store);
}

View File

@ -0,0 +1,70 @@
#include "../nfc_i.h"
enum SubmenuIndex {
SubmenuIndexMfUlUnlockMenuManual,
SubmenuIndexMfUlUnlockMenuAmeebo,
SubmenuIndexMfUlUnlockMenuXiaomi,
};
void nfc_scene_mf_ultralight_unlock_menu_submenu_callback(void* context, uint32_t index) {
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
}
void nfc_scene_mf_ultralight_unlock_menu_on_enter(void* context) {
Nfc* nfc = context;
Submenu* submenu = nfc->submenu;
uint32_t state =
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
submenu_add_item(
submenu,
"Enter Password Manually",
SubmenuIndexMfUlUnlockMenuManual,
nfc_scene_mf_ultralight_unlock_menu_submenu_callback,
nfc);
submenu_add_item(
submenu,
"Auth As Ameebo",
SubmenuIndexMfUlUnlockMenuAmeebo,
nfc_scene_mf_ultralight_unlock_menu_submenu_callback,
nfc);
submenu_add_item(
submenu,
"Auth As Xiaomi",
SubmenuIndexMfUlUnlockMenuXiaomi,
nfc_scene_mf_ultralight_unlock_menu_submenu_callback,
nfc);
submenu_set_selected_item(submenu, state);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
}
bool nfc_scene_mf_ultralight_unlock_menu_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexMfUlUnlockMenuManual) {
nfc->dev->dev_data.mf_ul_data.auth_method = MfUltralightAuthMethodManual;
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightKeyInput);
consumed = true;
} else if(event.event == SubmenuIndexMfUlUnlockMenuAmeebo) {
nfc->dev->dev_data.mf_ul_data.auth_method = MfUltralightAuthMethodAmeebo;
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn);
consumed = true;
} else if(event.event == SubmenuIndexMfUlUnlockMenuXiaomi) {
nfc->dev->dev_data.mf_ul_data.auth_method = MfUltralightAuthMethodXiaomi;
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn);
consumed = true;
}
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event);
}
return consumed;
}
void nfc_scene_mf_ultralight_unlock_menu_on_exit(void* context) {
Nfc* nfc = context;
submenu_reset(nfc->submenu);
}

View File

@ -0,0 +1,45 @@
#include "../nfc_i.h"
void nfc_scene_mf_ultralight_unlock_warn_dialog_callback(DialogExResult result, void* context) {
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
void nfc_scene_mf_ultralight_unlock_warn_on_enter(void* context) {
Nfc* nfc = context;
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_set_context(dialog_ex, nfc);
dialog_ex_set_result_callback(dialog_ex, nfc_scene_mf_ultralight_unlock_warn_dialog_callback);
dialog_ex_set_header(dialog_ex, "Risky function!", 64, 4, AlignCenter, AlignTop);
dialog_ex_set_text(
dialog_ex, "Wrong password\ncan block your\ncard.", 4, 18, AlignLeft, AlignTop);
dialog_ex_set_icon(dialog_ex, 73, 17, &I_DolphinFirstStart8_56x51);
dialog_ex_set_center_button_text(dialog_ex, "OK");
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
}
bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == DialogExResultCenter) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth);
consumed = true;
}
}
return consumed;
}
void nfc_scene_mf_ultralight_unlock_warn_on_exit(void* context) {
Nfc* nfc = context;
dialog_ex_reset(nfc->dialog_ex);
submenu_reset(nfc->submenu);
}

View File

@ -10,7 +10,7 @@ void nfc_scene_restore_original_confirm_on_enter(void* context) {
Nfc* nfc = context;
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_set_header(dialog_ex, "Restore card data?", 64, 0, AlignCenter, AlignTop);
dialog_ex_set_header(dialog_ex, "Restore Card Data?", 64, 0, AlignCenter, AlignTop);
dialog_ex_set_icon(dialog_ex, 5, 15, &I_Restoring);
dialog_ex_set_text(
dialog_ex, "It will be returned\nto its original state.", 47, 21, AlignLeft, AlignTop);

View File

@ -12,9 +12,9 @@ void nfc_scene_retry_confirm_on_enter(void* context) {
dialog_ex_set_left_button_text(dialog_ex, "Retry");
dialog_ex_set_right_button_text(dialog_ex, "Stay");
dialog_ex_set_header(dialog_ex, "Retry reading?", 64, 11, AlignCenter, AlignTop);
dialog_ex_set_header(dialog_ex, "Retry Reading?", 64, 11, AlignCenter, AlignTop);
dialog_ex_set_text(
dialog_ex, "All unsaved data will be\nlost.", 64, 25, AlignCenter, AlignTop);
dialog_ex, "All unsaved data will be\nlost!", 64, 25, AlignCenter, AlignTop);
dialog_ex_set_context(dialog_ex, nfc);
dialog_ex_set_result_callback(dialog_ex, nfc_scene_retry_confirm_dialog_callback);

View File

@ -4,10 +4,10 @@ void nfc_scene_rpc_on_enter(void* context) {
Nfc* nfc = context;
Popup* popup = nfc->popup;
popup_set_header(popup, "NFC", 82, 28, AlignCenter, AlignBottom);
popup_set_text(popup, "RPC mode", 82, 32, AlignCenter, AlignTop);
popup_set_header(popup, "NFC", 89, 42, AlignCenter, AlignBottom);
popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop);
popup_set_icon(popup, 2, 14, &I_Warning_30x23); // TODO: icon
popup_set_icon(popup, 0, 12, &I_RFIDDolphinSend_97x61);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
@ -31,13 +31,11 @@ bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) {
consumed = true;
if(event.event == NfcCustomEventViewExit) {
rpc_system_app_confirm(nfc->rpc_ctx, RpcAppEventAppExit, true);
scene_manager_stop(nfc->scene_manager);
view_dispatcher_stop(nfc->view_dispatcher);
nfc_blink_stop(nfc);
} else if(event.event == NfcCustomEventRpcSessionClose) {
rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL);
nfc->rpc_ctx = NULL;
scene_manager_stop(nfc->scene_manager);
view_dispatcher_stop(nfc->view_dispatcher);
nfc_blink_stop(nfc);
} else if(event.event == NfcCustomEventRpcLoad) {
bool result = false;
const char* arg = rpc_system_app_get_data(nfc->rpc_ctx);
@ -66,7 +64,7 @@ bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) {
nfc_blink_start(nfc);
nfc_text_store_set(nfc, "emulating\n%s", nfc->dev->dev_name);
popup_set_text(popup, nfc->text_store, 82, 32, AlignCenter, AlignTop);
popup_set_text(popup, nfc->text_store, 89, 44, AlignCenter, AlignTop);
}
}

View File

@ -2,6 +2,7 @@
enum SubmenuIndex {
SubmenuIndexEmulate,
SubmenuIndexEditUid,
SubmenuIndexRename,
SubmenuIndexDelete,
SubmenuIndexInfo,
@ -27,6 +28,14 @@ void nfc_scene_saved_menu_on_enter(void* context) {
SubmenuIndexEmulate,
nfc_scene_saved_menu_submenu_callback,
nfc);
if(nfc->dev->dev_data.protocol == NfcDeviceProtocolUnknown) {
submenu_add_item(
submenu,
"Edit UID",
SubmenuIndexEditUid,
nfc_scene_saved_menu_submenu_callback,
nfc);
}
} else if(
nfc->dev->format == NfcDeviceSaveFormatMifareUl ||
nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
@ -71,6 +80,9 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
} else if(event.event == SubmenuIndexRename) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
consumed = true;
} else if(event.event == SubmenuIndexEditUid) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid);
consumed = true;
} else if(event.event == SubmenuIndexDelete) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneDelete);
consumed = true;

View File

@ -31,8 +31,16 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventByteInputDone) {
DOLPHIN_DEED(DolphinDeedNfcAdd);
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
consumed = true;
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) {
nfc->dev->dev_data.nfc_data = nfc->dev_edit_data;
if(nfc_device_save(nfc->dev, nfc->dev->dev_name)) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
consumed = true;
}
} else {
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
consumed = true;
}
}
}
return consumed;

View File

@ -23,6 +23,8 @@ typedef struct {
uint8_t sector_current;
uint8_t keys_total;
uint8_t keys_found;
uint16_t dict_keys_total;
uint16_t dict_keys_current;
} DictAttackViewModel;
static void dict_attack_draw_callback(Canvas* canvas, void* model) {
@ -38,8 +40,15 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) {
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, string_get_cstr(m->header));
canvas_set_font(canvas, FontSecondary);
float progress =
m->sectors_total == 0 ? 0 : (float)(m->sector_current) / (float)(m->sectors_total);
float dict_progress = m->dict_keys_total == 0 ?
0 :
(float)(m->dict_keys_current) / (float)(m->dict_keys_total);
float progress = m->sectors_total == 0 ? 0 :
((float)(m->sector_current) + dict_progress) /
(float)(m->sectors_total);
if(progress > 1.0) {
progress = 1.0;
}
elements_progress_bar(canvas, 5, 15, 120, progress);
canvas_set_font(canvas, FontSecondary);
snprintf(draw_str, sizeof(draw_str), "Keys found: %d/%d", m->keys_found, m->keys_total);
@ -100,6 +109,8 @@ void dict_attack_reset(DictAttack* dict_attack) {
model->sector_current = 0;
model->keys_total = 0;
model->keys_found = 0;
model->dict_keys_total = 0;
model->dict_keys_current = 0;
string_reset(model->header);
return false;
});
@ -171,6 +182,7 @@ void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec) {
with_view_model(
dict_attack->view, (DictAttackViewModel * model) {
model->sector_current = curr_sec;
model->dict_keys_current = 0;
return true;
});
}
@ -181,6 +193,7 @@ void dict_attack_inc_current_sector(DictAttack* dict_attack) {
dict_attack->view, (DictAttackViewModel * model) {
if(model->sector_current < model->sectors_total) {
model->sector_current++;
model->dict_keys_current = 0;
}
return true;
});
@ -196,3 +209,23 @@ void dict_attack_inc_keys_found(DictAttack* dict_attack) {
return true;
});
}
void dict_attack_set_total_dict_keys(DictAttack* dict_attack, uint16_t dict_keys_total) {
furi_assert(dict_attack);
with_view_model(
dict_attack->view, (DictAttackViewModel * model) {
model->dict_keys_total = dict_keys_total;
return true;
});
}
void dict_attack_inc_current_dict_key(DictAttack* dict_attack, uint16_t keys_tried) {
furi_assert(dict_attack);
with_view_model(
dict_attack->view, (DictAttackViewModel * model) {
if(model->dict_keys_current + keys_tried < model->dict_keys_total) {
model->dict_keys_current += keys_tried;
}
return true;
});
}

View File

@ -34,3 +34,7 @@ void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec);
void dict_attack_inc_current_sector(DictAttack* dict_attack);
void dict_attack_inc_keys_found(DictAttack* dict_attack);
void dict_attack_set_total_dict_keys(DictAttack* dict_attack, uint16_t dict_keys_total);
void dict_attack_inc_current_dict_key(DictAttack* dict_attack, uint16_t keys_tried);

View File

@ -431,6 +431,54 @@ const NotificationSequence sequence_blink_white_100 = {
NULL,
};
// Hardware blink
const NotificationSequence sequence_blink_start_blue = {
&message_blink_start_10,
&message_blink_set_color_blue,
&message_do_not_reset,
NULL,
};
const NotificationSequence sequence_blink_start_red = {
&message_blink_start_10,
&message_blink_set_color_red,
&message_do_not_reset,
NULL,
};
const NotificationSequence sequence_blink_start_green = {
&message_blink_start_10,
&message_blink_set_color_green,
&message_do_not_reset,
NULL,
};
const NotificationSequence sequence_blink_start_yellow = {
&message_blink_start_10,
&message_blink_set_color_yellow,
&message_do_not_reset,
NULL,
};
const NotificationSequence sequence_blink_start_cyan = {
&message_blink_start_10,
&message_blink_set_color_cyan,
&message_do_not_reset,
NULL,
};
const NotificationSequence sequence_blink_start_magenta = {
&message_blink_start_10,
&message_blink_set_color_magenta,
&message_do_not_reset,
NULL,
};
const NotificationSequence sequence_blink_stop = {
&message_blink_stop,
NULL,
};
//General
const NotificationSequence sequence_single_vibro = {
&message_vibro_on,

View File

@ -122,6 +122,15 @@ extern const NotificationSequence sequence_blink_cyan_100;
extern const NotificationSequence sequence_blink_magenta_100;
extern const NotificationSequence sequence_blink_white_100;
// Hardware blink
extern const NotificationSequence sequence_blink_start_blue;
extern const NotificationSequence sequence_blink_start_red;
extern const NotificationSequence sequence_blink_start_green;
extern const NotificationSequence sequence_blink_start_yellow;
extern const NotificationSequence sequence_blink_start_cyan;
extern const NotificationSequence sequence_blink_start_magenta;
extern const NotificationSequence sequence_blink_stop;
// General
extern const NotificationSequence sequence_single_vibro;
extern const NotificationSequence sequence_double_vibro;

View File

@ -13,7 +13,7 @@ void picopass_scene_read_card_on_enter(void* context) {
// Setup view
Popup* popup = picopass->popup;
popup_set_header(popup, "Detecting\npicopass card", 70, 34, AlignLeft, AlignTop);
popup_set_header(popup, "Detecting\npicopass\ncard", 68, 30, AlignLeft, AlignTop);
popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
// Start worker

View File

@ -57,7 +57,7 @@ BatteryTestApp* battery_test_alloc() {
battery_info_get_view(app->batery_info));
app->dialog = dialog_ex_alloc();
dialog_ex_set_header(app->dialog, "Close battery test?", 64, 12, AlignCenter, AlignTop);
dialog_ex_set_header(app->dialog, "Close Battery Test?", 64, 12, AlignCenter, AlignTop);
dialog_ex_set_left_button_text(app->dialog, "Exit");
dialog_ex_set_right_button_text(app->dialog, "Stay");
dialog_ex_set_result_callback(app->dialog, battery_test_dialog_callback);

View File

@ -200,7 +200,7 @@ static void power_check_battery_level_change(Power* power) {
}
int32_t power_srv(void* p) {
(void)p;
UNUSED(p);
Power* power = power_alloc();
power_update_info(power);
furi_record_create(RECORD_POWER, power);

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