From c22d66590e86ba27f99b79332f0ea1fd46e8ec83 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Mon, 25 Jul 2022 14:23:47 +0300 Subject: [PATCH 1/9] [FL-2682] Allow spaces in file names #1444 --- lib/toolbox/path.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/toolbox/path.c b/lib/toolbox/path.c index 607671fb9..767742acc 100644 --- a/lib/toolbox/path.c +++ b/lib/toolbox/path.c @@ -102,7 +102,7 @@ bool path_contains_only_ascii(const char* path) { } else if((*name_pos >= 'a') && (*name_pos <= 'z')) { name_pos++; continue; - } else if(strchr(".!#\\$%&'()-@^_`{}~", *name_pos) != NULL) { + } else if(strchr(" .!#\\$%&'()-@^_`{}~", *name_pos) != NULL) { name_pos++; continue; } @@ -111,4 +111,4 @@ bool path_contains_only_ascii(const char* path) { } return true; -} \ No newline at end of file +} From 3ee592cae724ca2823c96be4070cbc8ae0001e4f Mon Sep 17 00:00:00 2001 From: Ruben van Baarle Date: Mon, 25 Jul 2022 13:48:06 +0200 Subject: [PATCH 2/9] Fix SubGHz chat immediately closing #1440 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's just an if condition which should've been inverted Co-authored-by: あく --- applications/subghz/subghz_cli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/subghz/subghz_cli.c b/applications/subghz/subghz_cli.c index 3944fc5b5..eadef9f46 100644 --- a/applications/subghz/subghz_cli.c +++ b/applications/subghz/subghz_cli.c @@ -676,7 +676,7 @@ static void subghz_cli_command_chat(Cli* cli, string_t args) { break; } } - if(cli_is_connected(cli)) { + if(!cli_is_connected(cli)) { printf("\r\n"); chat_event.event = SubGhzChatEventUserExit; subghz_chat_worker_put_event_chat(subghz_chat, &chat_event); From f5d6a8084b2ff90608cf9fee65185b31f2080993 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Mon, 25 Jul 2022 15:11:34 +0300 Subject: [PATCH 3/9] [FL-2668] GUI message screens update #1428 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SG Co-authored-by: あく --- .../bad_usb/scenes/bad_usb_scene_error.c | 16 ++++++----- .../scenes/gpio_scene_usb_uart_close_rpc.c | 26 +++++------------- .../lfrfid/scene/lfrfid_app_scene_write.cpp | 12 ++++---- .../scenes/storage_settings_scene_benchmark.c | 10 ++----- .../storage_settings_scene_format_confirm.c | 10 ++----- .../storage_settings_scene_formatting.c | 3 +- .../scenes/storage_settings_scene_sd_info.c | 10 ++----- .../storage_settings_scene_unmount_confirm.c | 12 +++----- .../scenes/storage_settings_scene_unmounted.c | 12 ++++---- .../subghz/scenes/subghz_scene_set_type.c | 2 +- .../scenes/subghz_scene_show_error_sub.c | 4 +-- .../subghz/scenes/subghz_scene_transmitter.c | 2 +- applications/subghz/subghz_i.c | 18 +++++++----- applications/u2f/scenes/u2f_scene_error.c | 16 ++++++----- .../icons/Common/ActiveConnection_50x64.png | Bin 0 -> 3842 bytes 15 files changed, 66 insertions(+), 87 deletions(-) mode change 100755 => 100644 applications/storage_settings/scenes/storage_settings_scene_unmounted.c create mode 100644 assets/icons/Common/ActiveConnection_50x64.png diff --git a/applications/bad_usb/scenes/bad_usb_scene_error.c b/applications/bad_usb/scenes/bad_usb_scene_error.c index c8e1c361f..abd7b38b9 100644 --- a/applications/bad_usb/scenes/bad_usb_scene_error.c +++ b/applications/bad_usb/scenes/bad_usb_scene_error.c @@ -27,20 +27,22 @@ void bad_usb_scene_error_on_enter(void* context) { AlignTop, FontSecondary, "No SD card or\napp data found.\nThis app will not\nwork without\nrequired files."); + widget_add_button_element( + app->widget, GuiButtonTypeLeft, "Back", bad_usb_scene_error_event_callback, app); } else if(app->error == BadUsbAppErrorCloseRpc) { + widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64); + widget_add_string_multiline_element( + app->widget, 3, 2, AlignLeft, AlignTop, FontPrimary, "Connection\nis active!"); widget_add_string_multiline_element( app->widget, - 63, - 10, - AlignCenter, + 3, + 30, + AlignLeft, AlignTop, FontSecondary, - "Disconnect from\ncompanion app\nto use this function"); + "Disconnect from\nPC or phone to\nuse this function."); } - widget_add_button_element( - app->widget, GuiButtonTypeLeft, "Back", bad_usb_scene_error_event_callback, app); - view_dispatcher_switch_to_view(app->view_dispatcher, BadUsbAppViewError); } diff --git a/applications/gpio/scenes/gpio_scene_usb_uart_close_rpc.c b/applications/gpio/scenes/gpio_scene_usb_uart_close_rpc.c index e09f2fd36..2cb53cab2 100644 --- a/applications/gpio/scenes/gpio_scene_usb_uart_close_rpc.c +++ b/applications/gpio/scenes/gpio_scene_usb_uart_close_rpc.c @@ -1,32 +1,20 @@ #include "../gpio_app_i.h" #include "../gpio_custom_event.h" -static void gpio_scene_usb_uart_close_rpc_event_callback( - GuiButtonType result, - InputType type, - void* context) { - furi_assert(context); - GpioApp* app = context; - - if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) { - view_dispatcher_send_custom_event(app->view_dispatcher, GpioCustomEventErrorBack); - } -} - void gpio_scene_usb_uart_close_rpc_on_enter(void* context) { GpioApp* app = context; + widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64); + widget_add_string_multiline_element( + app->widget, 3, 2, AlignLeft, AlignTop, FontPrimary, "Connection\nis active!"); widget_add_string_multiline_element( app->widget, - 63, - 10, - AlignCenter, + 3, + 30, + AlignLeft, AlignTop, FontSecondary, - "Disconnect from\ncompanion app\nto use this function"); - - widget_add_button_element( - app->widget, GuiButtonTypeLeft, "Back", gpio_scene_usb_uart_close_rpc_event_callback, app); + "Disconnect from\nPC or phone to\nuse this function."); view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewUsbUartCloseRpc); } diff --git a/applications/lfrfid/scene/lfrfid_app_scene_write.cpp b/applications/lfrfid/scene/lfrfid_app_scene_write.cpp index d6c9e9f4f..ff7b49a4d 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_write.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_write.cpp @@ -41,13 +41,13 @@ bool LfRfidAppSceneWrite::on_event(LfRfidApp* app, LfRfidApp::Event* event) { case RfidWorker::WriteResult::NotWritable: if(!card_not_supported) { auto popup = app->view_controller.get(); - popup->set_icon(0, 0, NULL); - popup->set_header("Still trying to write", 64, 7, AlignCenter, AlignTop); + popup->set_icon(72, 14, &I_DolphinFirstStart8_56x51); + popup->set_header("Still trying to write...", 64, 3, AlignCenter, AlignTop); popup->set_text( - "This card may be protected\nor does not support this\ntype of writing", - 64, - 23, - AlignCenter, + "Make sure this\ncard is writable\nand not\nprotected.", + 3, + 17, + AlignLeft, AlignTop); card_not_supported = true; } diff --git a/applications/storage_settings/scenes/storage_settings_scene_benchmark.c b/applications/storage_settings/scenes/storage_settings_scene_benchmark.c index e7c55ad17..947bb4e58 100644 --- a/applications/storage_settings/scenes/storage_settings_scene_benchmark.c +++ b/applications/storage_settings/scenes/storage_settings_scene_benchmark.c @@ -122,14 +122,10 @@ void storage_settings_scene_benchmark_on_enter(void* context) { view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx); if(sd_status != FSE_OK) { - dialog_ex_set_header(dialog_ex, "SD card not mounted", 64, 10, AlignCenter, AlignCenter); + dialog_ex_set_icon(dialog_ex, 72, 14, &I_DolphinFirstStart8_56x51); + dialog_ex_set_header(dialog_ex, "SD card not mounted", 64, 3, AlignCenter, AlignTop); dialog_ex_set_text( - dialog_ex, - "If an SD card is inserted,\r\npull it out and reinsert it", - 64, - 32, - AlignCenter, - AlignCenter); + dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop); dialog_ex_set_center_button_text(dialog_ex, "Ok"); } else { storage_settings_scene_benchmark(app); diff --git a/applications/storage_settings/scenes/storage_settings_scene_format_confirm.c b/applications/storage_settings/scenes/storage_settings_scene_format_confirm.c index 1ebe8dfbd..6388a6826 100644 --- a/applications/storage_settings/scenes/storage_settings_scene_format_confirm.c +++ b/applications/storage_settings/scenes/storage_settings_scene_format_confirm.c @@ -14,14 +14,10 @@ void storage_settings_scene_format_confirm_on_enter(void* context) { FS_Error sd_status = storage_sd_status(app->fs_api); if(sd_status == FSE_NOT_READY) { - dialog_ex_set_header(dialog_ex, "SD card not mounted", 64, 10, AlignCenter, AlignCenter); + dialog_ex_set_icon(dialog_ex, 72, 14, &I_DolphinFirstStart8_56x51); + dialog_ex_set_header(dialog_ex, "SD card not mounted", 64, 3, AlignCenter, AlignTop); dialog_ex_set_text( - dialog_ex, - "If an SD card is inserted,\r\npull it out and reinsert it", - 64, - 32, - AlignCenter, - AlignCenter); + dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop); dialog_ex_set_center_button_text(dialog_ex, "Ok"); } else { dialog_ex_set_header(dialog_ex, "Format SD card?", 64, 10, AlignCenter, AlignCenter); diff --git a/applications/storage_settings/scenes/storage_settings_scene_formatting.c b/applications/storage_settings/scenes/storage_settings_scene_formatting.c index 2cbf97eea..c4e15b261 100755 --- a/applications/storage_settings/scenes/storage_settings_scene_formatting.c +++ b/applications/storage_settings/scenes/storage_settings_scene_formatting.c @@ -47,7 +47,8 @@ void storage_settings_scene_formatting_on_enter(void* context) { dialog_ex_set_text( dialog_ex, storage_error_get_desc(error), 64, 32, AlignCenter, AlignCenter); } else { - dialog_ex_set_header(dialog_ex, "Format complete!", 64, 32, AlignCenter, AlignCenter); + dialog_ex_set_icon(dialog_ex, 72, 14, &I_DolphinFirstStart8_56x51); + dialog_ex_set_header(dialog_ex, "Format\ncomplete!", 14, 15, AlignLeft, AlignTop); } dialog_ex_set_center_button_text(dialog_ex, "OK"); } diff --git a/applications/storage_settings/scenes/storage_settings_scene_sd_info.c b/applications/storage_settings/scenes/storage_settings_scene_sd_info.c index 69ad1ea57..1c861538a 100644 --- a/applications/storage_settings/scenes/storage_settings_scene_sd_info.c +++ b/applications/storage_settings/scenes/storage_settings_scene_sd_info.c @@ -18,14 +18,10 @@ void storage_settings_scene_sd_info_on_enter(void* context) { dialog_ex_set_result_callback(dialog_ex, storage_settings_scene_sd_info_dialog_callback); if(sd_status != FSE_OK) { - dialog_ex_set_header(dialog_ex, "SD card not mounted", 64, 10, AlignCenter, AlignCenter); + dialog_ex_set_icon(dialog_ex, 72, 14, &I_DolphinFirstStart8_56x51); + dialog_ex_set_header(dialog_ex, "SD card not mounted", 64, 3, AlignCenter, AlignTop); dialog_ex_set_text( - dialog_ex, - "If an SD card is inserted,\r\npull it out and reinsert it", - 64, - 32, - AlignCenter, - AlignCenter); + dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop); dialog_ex_set_center_button_text(dialog_ex, "Ok"); } else { string_printf( diff --git a/applications/storage_settings/scenes/storage_settings_scene_unmount_confirm.c b/applications/storage_settings/scenes/storage_settings_scene_unmount_confirm.c index 001ce7684..27f55251f 100644 --- a/applications/storage_settings/scenes/storage_settings_scene_unmount_confirm.c +++ b/applications/storage_settings/scenes/storage_settings_scene_unmount_confirm.c @@ -14,15 +14,11 @@ void storage_settings_scene_unmount_confirm_on_enter(void* context) { FS_Error sd_status = storage_sd_status(app->fs_api); if(sd_status == FSE_NOT_READY) { - dialog_ex_set_header(dialog_ex, "SD card not mounted", 64, 10, AlignCenter, AlignCenter); + dialog_ex_set_icon(dialog_ex, 72, 14, &I_DolphinFirstStart8_56x51); + dialog_ex_set_header(dialog_ex, "SD card not mounted", 64, 3, AlignCenter, AlignTop); dialog_ex_set_text( - dialog_ex, - "If an SD card is inserted,\r\npull it out and reinsert it", - 64, - 32, - AlignCenter, - AlignCenter); - dialog_ex_set_center_button_text(dialog_ex, "OK"); + dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop); + dialog_ex_set_center_button_text(dialog_ex, "Ok"); } else { dialog_ex_set_header(dialog_ex, "Unmount SD card?", 64, 10, AlignCenter, AlignCenter); dialog_ex_set_text( diff --git a/applications/storage_settings/scenes/storage_settings_scene_unmounted.c b/applications/storage_settings/scenes/storage_settings_scene_unmounted.c old mode 100755 new mode 100644 index ddd70d055..e5f69d45a --- a/applications/storage_settings/scenes/storage_settings_scene_unmounted.c +++ b/applications/storage_settings/scenes/storage_settings_scene_unmounted.c @@ -13,17 +13,15 @@ void storage_settings_scene_unmounted_on_enter(void* context) { DialogEx* dialog_ex = app->dialog_ex; dialog_ex_set_center_button_text(dialog_ex, "OK"); + dialog_ex_set_icon(dialog_ex, 72, 14, &I_DolphinFirstStart8_56x51); if(error == FSE_OK) { - dialog_ex_set_header(dialog_ex, "SD card unmounted", 64, 10, AlignCenter, AlignCenter); - dialog_ex_set_text( - dialog_ex, "Now the SD card\ncan be removed.", 64, 32, AlignCenter, AlignCenter); + dialog_ex_set_header(dialog_ex, "SD card unmounted", 64, 3, AlignCenter, AlignTop); + dialog_ex_set_text(dialog_ex, "You can remove\nSD card now.", 3, 22, AlignLeft, AlignTop); notification_message(app->notification, &sequence_blink_green_100); } else { - dialog_ex_set_header( - dialog_ex, "Cannot unmount SD Card", 64, 10, AlignCenter, AlignCenter); - dialog_ex_set_text( - dialog_ex, storage_error_get_desc(error), 64, 32, AlignCenter, AlignCenter); + dialog_ex_set_header(dialog_ex, "Cannot unmount SD Card", 64, 3, AlignCenter, AlignTop); + dialog_ex_set_text(dialog_ex, storage_error_get_desc(error), 3, 22, AlignLeft, AlignTop); notification_message(app->notification, &sequence_blink_red_100); } diff --git a/applications/subghz/scenes/subghz_scene_set_type.c b/applications/subghz/scenes/subghz_scene_set_type.c index a7a4491e1..55db80114 100644 --- a/applications/subghz/scenes/subghz_scene_set_type.c +++ b/applications/subghz/scenes/subghz_scene_set_type.c @@ -26,7 +26,7 @@ bool subghz_scene_set_type_submenu_gen_data_protocol( subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, protocol_name); if(subghz->txrx->decoder_result == NULL) { - string_set_str(subghz->error_str, "Protocol not found"); + string_set_str(subghz->error_str, "Protocol not\nfound!"); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub); return false; } diff --git a/applications/subghz/scenes/subghz_scene_show_error_sub.c b/applications/subghz/scenes/subghz_scene_show_error_sub.c index 64cd5b5a6..697588d0e 100644 --- a/applications/subghz/scenes/subghz_scene_show_error_sub.c +++ b/applications/subghz/scenes/subghz_scene_show_error_sub.c @@ -11,8 +11,8 @@ void subghz_scene_show_error_sub_on_enter(void* context) { // Setup view Popup* popup = subghz->popup; - popup_set_icon(popup, 32, 12, &I_DolphinFirstStart7_61x51); - popup_set_header(popup, string_get_cstr(subghz->error_str), 64, 8, AlignCenter, AlignBottom); + popup_set_icon(popup, 72, 14, &I_DolphinFirstStart8_56x51); + popup_set_header(popup, string_get_cstr(subghz->error_str), 14, 15, AlignLeft, AlignTop); popup_set_timeout(popup, 1500); popup_set_context(popup, subghz); popup_set_callback(popup, subghz_scene_show_error_sub_popup_callback); diff --git a/applications/subghz/scenes/subghz_scene_transmitter.c b/applications/subghz/scenes/subghz_scene_transmitter.c index b8b22749c..b3f8d0799 100644 --- a/applications/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/subghz/scenes/subghz_scene_transmitter.c @@ -94,7 +94,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { subghz->scene_manager, SubGhzSceneStart); return true; } else if(event.event == SubGhzCustomEventViewTransmitterError) { - string_set_str(subghz->error_str, "Protocol not found"); + string_set_str(subghz->error_str, "Protocol not\nfound!"); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub); } } else if(event.type == SceneManagerEventTypeTick) { diff --git a/applications/subghz/subghz_i.c b/applications/subghz/subghz_i.c index 0593cc6f7..f6e4d4f50 100644 --- a/applications/subghz/subghz_i.c +++ b/applications/subghz/subghz_i.c @@ -205,15 +205,19 @@ void subghz_tx_stop(SubGhz* subghz) { void subghz_dialog_message_show_only_rx(SubGhz* subghz) { DialogsApp* dialogs = subghz->dialogs; DialogMessage* message = dialog_message_alloc(); + + dialog_message_set_header(message, "Transmission is blocked", 63, 3, AlignCenter, AlignTop); + dialog_message_set_text( message, - "This frequency can\nonly be used for RX\nin your region", - 38, - 23, - AlignCenter, - AlignCenter); - dialog_message_set_icon(message, &I_DolphinFirstStart7_61x51, 67, 12); - dialog_message_set_buttons(message, "Back", NULL, NULL); + "This frequency\nis restricted to\nreceiving only\nin your region.", + 3, + 17, + AlignLeft, + AlignTop); + + dialog_message_set_icon(message, &I_DolphinFirstStart8_56x51, 72, 14); + dialog_message_show(dialogs, message); dialog_message_free(message); } diff --git a/applications/u2f/scenes/u2f_scene_error.c b/applications/u2f/scenes/u2f_scene_error.c index d40183678..e10e9c098 100644 --- a/applications/u2f/scenes/u2f_scene_error.c +++ b/applications/u2f/scenes/u2f_scene_error.c @@ -22,20 +22,22 @@ void u2f_scene_error_on_enter(void* context) { AlignTop, FontSecondary, "No SD card or\napp data found.\nThis app will not\nwork without\nrequired files."); + widget_add_button_element( + app->widget, GuiButtonTypeLeft, "Back", u2f_scene_error_event_callback, app); } else if(app->error == U2fAppErrorCloseRpc) { + widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64); + widget_add_string_multiline_element( + app->widget, 3, 2, AlignLeft, AlignTop, FontPrimary, "Connection\nis active!"); widget_add_string_multiline_element( app->widget, - 63, - 10, - AlignCenter, + 3, + 30, + AlignLeft, AlignTop, FontSecondary, - "Disconnect from\ncompanion app\nto use this function"); + "Disconnect from\nPC or phone to\nuse this function."); } - widget_add_button_element( - app->widget, GuiButtonTypeLeft, "Back", u2f_scene_error_event_callback, app); - view_dispatcher_switch_to_view(app->view_dispatcher, U2fAppViewError); } diff --git a/assets/icons/Common/ActiveConnection_50x64.png b/assets/icons/Common/ActiveConnection_50x64.png new file mode 100644 index 0000000000000000000000000000000000000000..1d7686dddf8a33b724c7528ed36435514b7518b2 GIT binary patch literal 3842 zcmaJ@c|278_rI3PzAvFNMm&{e7)wmXzKj~%*ehv_!7y86EF(lkN?EdHO(@h*N=UY3 zZ7fkFOO`ANjU^;YzwvyZp6~CEU%&f$-FwgH-1qx^&gYzS@9SQ-wYK2rk>&vafZq~f zielZNtkaN-gLNhGzPAJb9uu62iLIrH35ZM~dExL_00Y=T+{c5+j+w|kQsr%QBj$9h<5`_= zvcrYX!$Oz~3!5J{Yi6=$wz_EDf)T3YU<@oW!^@U{0@_p^+Qfji z{lF9ZXP!JjG63Ldp~hg~AwMwx-BN!KFi@N{EC~$c9Vq4kZm|LBM=TDr8@>e2J4T|E z*&7;xT)H7xm9wFgEyA?|YQY{+y9Wr2b4d_1JP$;q8!LAJARTtVV==bq+y8?q5g)7dgSlylFvP4D0V9$wxB1&@2RYM*2Ee`$=9#$v)`Zg50U)VMn4d_fO_zVCwU-q9ZN|r>nZ~=g6Zsf5iM*H|)iP0MbvR)mm zX^><`?=>~#JKUfrWW0AW;sDRR{i#M$4h^sY&gV}!q;rKc#)ZmXsq661jES6$oFhx_ zJ-Xh>mnd2e79;EtHvsP9l1z`|1fvm}w<8KbvoT_J;N~_;0ei8rZ=xGQ zep!VgrhDtG;m?GjHW2j2){Pnq_2kH>b{y~70}Njj$x7d7$@TA{Y6`kVq~`hcNS7ai zM^xk$_MG|>Kn22X#9<o9w4gy=lixvN5r_{#|i7A{B^lOlzA`ErqJE@$p5SJfN;0w)#Olq-aYY%~RXz{(O_ z%;}2X6~bj973UHN?Vl#O zo<`6?X^E8yf(bUaH``xNR*J!zV(3vS=!YEM5?|Ykp^Tw_FKxV1c+#^>GnWeo=>-GDxZ+2$( z%J(2X{%HOytq6}JQhrhwr3&{~Nf`v8?m_r4=|hvevTZ0%U6c;Xw8 z6j+K=N_fi5LkCBHM}t1vLtckRj)ITQIfXqicYJ31xtROC#G}6AgN`qYwM)BDL8y4! zZaeq~S?sF6{&Z&Ub^0AAeJ7gJs?!I$W&hbZ9FmdU6nD#^1-PDhDcgqnxs9U@J1o=ZU`e~ zO8Q%M@AG%7`I#>>hf6*Z-j8&^o5LP$TB&Brw7b2AGmXA4uDeWJ==hvnm|57kk}v}~ z7kJL~+-B_|n`c>yIsIycwxOmoW3`Nn=VAJA?9Z-Q4*eE=_PZf>uhl)M1CPS%J z)5G^|{Z0d8l7FF1nj*R4APEU;{bZQNa~6 zW`U2XlEq1-OKyaT9X$qpsQT5e+@5-Yx~|+$pLE^yu8muYFTVNW#E@?VCD5Dhi$~!x z^O;o}ep6z1f z1nIeIxh90_MBNcddulLs1!Qas*>5vdNVGaAx_mV=%EqiN?^d2&S!LBpz1!2-PAO|T zBPYU4e)>e)mliGPwdO?V@dbnVUhr2K~e%8)od3fYrijw-bkkU&C;l!DLfKNDPqs70K9uQBSi z^L0a>_p(H2ZNd}Vswd9|s)AjY#=!MvFD2w-?InX$)!k6lp24`q-Y|v_<7w))?Su=; zaoLwPyc~zR(tH2DiPB|f&6MKgb_TKZ`{@@Lade8OBhxpn?~K!>W0EQEbTYlD^v4tP zs_6-5Yxlm;RT^P%@YBi4Hw$x!xq>+&eciSG@yS|WqrSJ%i~J=rOSh(E+zBT?QSXKL zuEuqicfRT5&_Zi1oav~b4=vx*&R+}3zU0Pm+AeuiS@%(Ku)lsJ=;DgNm4o6ZJ~5N$ zYo03wJNwm|g{=~Mzg-@Qm-djUuAdGcsj>*NY0inic>m(QH8bX%FO`HJeq3Mwl$(Ik zzI6xzBTr>UkOngsGJ>9yPahL#G@5$#*XV=Li=S=3-0ONh{JL{A{Zi#B*BpYT)C;Q* zpsVB)a^d%CnO|<^XCFLw(4wyLS2$DsGbW%_E8aOLH~R>DX=Czo(&s|Y!klbt1Ni&& zVcI%!E8Wk{&aKwlq&vqzlKKr<>Av2+@@XdCZLx;@9lY)_q)>UP1YQca2q$lkBOae2 z&0*IW3(k6_)bCbvCwiFgF8%av==1;Z{W#xnzWcSSAX9+*TFy@LuXoqRdo4OF`sB^! zZ^dWJ%F6Id*DiZ@C5;z8Efnp36YlhjHs}9nW^{XE^HjIX*1#g~Mr?O|DXn;g!hBTx z7}hG^DqGVVN>R;RsP-f;Y7m-&1&lmN9$1hi0qu=NVbPwn3+-4v0N^-+b8w-$SRr8;5deQ<~n3f4Zv+5r>d zhtc%}8|Z`df?+HH0+xyf1rzW@e^@Xa{I@QQW$(HnV9?(XsvjKupQK!@Y(XX@3Kn!+ z6{>|JenB{I4w0|DQ^+Y6b~LlOgJ=YP-Ao4YacQ|DgoJzi59d z3j5!D|4(6m2O1d*L1Fz#0Tc|YcV6~A`jDt3e;*PV1l3U0 z1Rb$LV{pV>&(XgrR#q@eqCXW)#9%E=;b4}CDh}rf(>5`OnnI83nw#sGsH>Zq7@2Dr znVK4znQH22Le)*pe{)Sqm;eHnNd3+A{4dw&kKEmXAdp#+O|cYQAlB2ILLz|v-Zc#O z=Uk5eQSTqF=bv-Y`6Cy?N(Qpq+yB+;-!9ew?VA4%FKhAd_+yEznWwOZTSahmj`d>f zwM9CZ{rdHbWjZ##3kLu;K}%C3hv32CR3nMkATHDNP50`@*G0JbZdhsG&#ag}kt-x* zbi6EjpiYUf^utT&I-ggwTw)8K9Wu<#NjKCWviOGnxNwI<3!$qd0;#|wTaC0<=DJ&4 z-o}fdK$^-X*DQay#`Ty87;GIAW(;r{nhujLM{vr&Ry`!wB1~-L(Uq&iu{k>R-V8os2N6zY@I0ry5ZRP(0CFwaUqp$rweNmLEX}M Date: Mon, 25 Jul 2022 15:11:24 +0200 Subject: [PATCH 4/9] Port over Issue templates to new YML format (#1433) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * WIP Push * Add feature request label to template * Punctuation helps * rename feature request and add in enhancement * wording * Add in extra markdown explanations Co-authored-by: SG Co-authored-by: あく --- .github/ISSUE_TEMPLATE/01_bug_report.yml | 46 +++++++++++++++++++ .github/ISSUE_TEMPLATE/02_enhancements.yml | 21 +++++++++ .github/ISSUE_TEMPLATE/03_feature_request.yml | 24 ++++++++++ .github/ISSUE_TEMPLATE/bug_report.md | 30 ------------ .github/ISSUE_TEMPLATE/config.yml | 5 ++ .github/ISSUE_TEMPLATE/discuss-issue.md | 12 ----- .github/ISSUE_TEMPLATE/feature_request.md | 20 -------- .github/ISSUE_TEMPLATE/in-progress.md | 10 ---- .github/ISSUE_TEMPLATE/need-help.md | 10 ---- 9 files changed, 96 insertions(+), 82 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/01_bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/02_enhancements.yml create mode 100644 .github/ISSUE_TEMPLATE/03_feature_request.yml delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/config.yml delete mode 100644 .github/ISSUE_TEMPLATE/discuss-issue.md delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md delete mode 100644 .github/ISSUE_TEMPLATE/in-progress.md delete mode 100644 .github/ISSUE_TEMPLATE/need-help.md diff --git a/.github/ISSUE_TEMPLATE/01_bug_report.yml b/.github/ISSUE_TEMPLATE/01_bug_report.yml new file mode 100644 index 000000000..4697c0837 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/01_bug_report.yml @@ -0,0 +1,46 @@ +name: Bug report +description: File a bug reports regarding the firmware. +labels: ['bug'] +body: +- type: markdown + attributes: + value: | + Thank you for taking the time to fill out an issue, this template is meant for any issues related to the Flipper Zero firmware. + If you require help with the Flipper zero and its firmware, we ask that you join [our forum](https://forum.flipperzero.one) +- type: textarea + id: description + attributes: + label: Desctibe the bug. + description: "A clear and concise description of what the bug is." + validations: + required: true +- type: textarea + id: repro + attributes: + label: Reproduction + description: "How can this bug be reproduced?" + placeholder: | + 1. Switch on... + 2. Press button '....' + 3. Wait for the moon phase + 4. It burns + validations: + required: true +- type: input + id: target + attributes: + label: Target + description: Specify the target + # Target seems to be largely ignored by outside sources. +- type: textarea + id: logs + attributes: + label: Logs + description: Attach your debug logs here + render: Text + # Avoid rendering as Markdown here. +- type: textarea + id: anything-else + attributes: + label: Anything else? + description: Let us know if you have anything else to share. diff --git a/.github/ISSUE_TEMPLATE/02_enhancements.yml b/.github/ISSUE_TEMPLATE/02_enhancements.yml new file mode 100644 index 000000000..1768e193c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/02_enhancements.yml @@ -0,0 +1,21 @@ +name: Enhancements +description: Suggest improvements for any existing functionality within the firmware. +body: +- type: markdown + attributes: + value: | + Thank you for taking the time to fill out an issue. This template is meant for feature requests and improvements to already existing functionality. + If you require help with the Flipper zero and its firmware, we ask that you join [our forum](https://forum.flipperzero.one) +- type: textarea + id: proposal + attributes: + label: "Describe the enhancement you're suggesting." + description: | + Feel free to describe in as much detail as you wish. + validations: + required: true +- type: textarea + id: anything-else + attributes: + label: Anything else? + description: Let us know if you have anything else to share. diff --git a/.github/ISSUE_TEMPLATE/03_feature_request.yml b/.github/ISSUE_TEMPLATE/03_feature_request.yml new file mode 100644 index 000000000..2af114547 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/03_feature_request.yml @@ -0,0 +1,24 @@ +name: Feature Request +description: For feature requests regarding the firmware. +labels: ['feature request'] +body: +- type: markdown + attributes: + value: | + Thank you for taking the time to fill out an issue, this template is meant for any feature suggestions. + If you require help with the Flipper zero and its firmware, we ask that you join [our forum](https://forum.flipperzero.one) +- type: textarea + id: proposal + attributes: + label: "Description of the feature you're suggesting." + description: | + Please describe your feature request in as many details as possible. + - Describe what it should do. + - Note whetever it is to extend existing functionality or introduce new functionality. + validations: + required: true +- type: textarea + id: anything-else + attributes: + label: Anything else? + description: Let us know if you have anything else to share. diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index cf337499e..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: bug -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Switch on... -2. Press button '....' -3. Wait for the moon phase -4. It burns - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Logs** -Add debug logs - -**Target** -Specify the target - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..55ff9d29e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: Need help? + url: https://forum.flipperzero.one + about: For any question regarding on how to use the Flipper Zero and its firmware. diff --git a/.github/ISSUE_TEMPLATE/discuss-issue.md b/.github/ISSUE_TEMPLATE/discuss-issue.md deleted file mode 100644 index d036533d0..000000000 --- a/.github/ISSUE_TEMPLATE/discuss-issue.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -name: Discuss issue -about: Start discussion about improvements -title: '' -labels: discussion -assignees: '' - ---- - -# What are you want to add or change - -# What questions do you have diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index e301d68ce..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: feature request -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/in-progress.md b/.github/ISSUE_TEMPLATE/in-progress.md deleted file mode 100644 index e8cf0332c..000000000 --- a/.github/ISSUE_TEMPLATE/in-progress.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: In progress -about: When you start doing your big deal -title: '' -labels: in progress -assignees: '' - ---- - -Shortly (or not) describe what are you will do diff --git a/.github/ISSUE_TEMPLATE/need-help.md b/.github/ISSUE_TEMPLATE/need-help.md deleted file mode 100644 index c7b1e2863..000000000 --- a/.github/ISSUE_TEMPLATE/need-help.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: Need help -about: Ask the community for help if you confused and can't figure out something -title: '' -labels: need help -assignees: '' - ---- - -# Describe you problem here From d80edba8916210248cb2f0107f872cddc1dceb95 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Mon, 25 Jul 2022 17:16:45 +0300 Subject: [PATCH 5/9] RPC App: state message and GUI update (#1423) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * RPC App: state message and GUI update * Protobuf submodule update Co-authored-by: SG Co-authored-by: あく --- applications/ibutton/ibutton.c | 18 ++++-- applications/ibutton/ibutton_custom_event.h | 1 + .../ibutton/scenes/ibutton_scene_rpc.c | 39 +++++++++++-- applications/infrared/infrared.c | 17 ++++-- applications/infrared/infrared_custom_event.h | 1 + .../infrared/scenes/infrared_scene_rpc.c | 12 +++- applications/lfrfid/lfrfid_app.cpp | 2 + .../lfrfid/scene/lfrfid_app_scene_rpc.cpp | 23 +++++++- applications/nfc/helpers/nfc_custom_event.h | 1 + applications/nfc/nfc.c | 32 ++++++---- applications/nfc/scenes/nfc_scene_rpc.c | 25 ++++++-- applications/rpc/rpc_app.c | 29 +++++++++- applications/rpc/rpc_app.h | 4 ++ .../subghz/helpers/subghz_custom_event.h | 2 + applications/subghz/scenes/subghz_scene_rpc.c | 33 ++++++++--- applications/subghz/subghz.c | 58 ++++++++++++++----- assets/protobuf | 2 +- 17 files changed, 237 insertions(+), 62 deletions(-) diff --git a/applications/ibutton/ibutton.c b/applications/ibutton/ibutton.c index 0f54dc3ee..0f14137c0 100644 --- a/applications/ibutton/ibutton.c +++ b/applications/ibutton/ibutton.c @@ -118,6 +118,8 @@ static bool ibutton_rpc_command_callback(RpcAppSystemEvent event, const char* ar 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); + view_dispatcher_send_custom_event( + ibutton->view_dispatcher, iButtonCustomEventRpcLoad); result = true; } } @@ -162,8 +164,6 @@ iButton* ibutton_alloc() { ibutton->view_dispatcher, ibutton_tick_event_callback, 100); ibutton->gui = furi_record_open("gui"); - view_dispatcher_attach_to_gui( - ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen); ibutton->storage = furi_record_open("storage"); ibutton->dialogs = furi_record_open("dialogs"); @@ -373,6 +373,7 @@ int32_t ibutton_app(void* p) { ibutton->rpc_ctx = (void*)rpc_ctx; rpc_mode = true; rpc_system_app_set_callback(ibutton->rpc_ctx, ibutton_rpc_command_callback, ibutton); + rpc_system_app_send_started(ibutton->rpc_ctx); } else { string_set_str(ibutton->file_path, (const char*)p); if(ibutton_load_key_data(ibutton, ibutton->file_path, true)) { @@ -383,17 +384,24 @@ int32_t ibutton_app(void* p) { } if(rpc_mode) { + view_dispatcher_attach_to_gui( + ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeDesktop); scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRpc); - } else if(key_loaded) { - scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); } else { - scene_manager_next_scene(ibutton->scene_manager, iButtonSceneStart); + view_dispatcher_attach_to_gui( + ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen); + if(key_loaded) { + scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); + } else { + scene_manager_next_scene(ibutton->scene_manager, iButtonSceneStart); + } } view_dispatcher_run(ibutton->view_dispatcher); if(ibutton->rpc_ctx) { rpc_system_app_set_callback(ibutton->rpc_ctx, NULL, NULL); + rpc_system_app_send_exited(ibutton->rpc_ctx); } ibutton_free(ibutton); return 0; diff --git a/applications/ibutton/ibutton_custom_event.h b/applications/ibutton/ibutton_custom_event.h index 1706e00fa..25dfc31d9 100644 --- a/applications/ibutton/ibutton_custom_event.h +++ b/applications/ibutton/ibutton_custom_event.h @@ -10,5 +10,6 @@ enum iButtonCustomEvent { iButtonCustomEventWorkerEmulated, iButtonCustomEventWorkerRead, + iButtonCustomEventRpcLoad, iButtonCustomEventRpcExit, }; diff --git a/applications/ibutton/scenes/ibutton_scene_rpc.c b/applications/ibutton/scenes/ibutton_scene_rpc.c index ceeca0179..14f7df638 100644 --- a/applications/ibutton/scenes/ibutton_scene_rpc.c +++ b/applications/ibutton/scenes/ibutton_scene_rpc.c @@ -3,12 +3,14 @@ void ibutton_scene_rpc_on_enter(void* context) { iButton* ibutton = context; - Widget* widget = ibutton->widget; + Popup* popup = ibutton->popup; - widget_add_text_box_element( - widget, 0, 0, 128, 28, AlignCenter, AlignCenter, "RPC mode", false); + popup_set_header(popup, "iButton", 82, 28, AlignCenter, AlignBottom); + popup_set_text(popup, "RPC mode", 82, 32, AlignCenter, AlignTop); - view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget); + popup_set_icon(popup, 2, 14, &I_iButtonKey_49x44); + + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup); notification_message(ibutton->notifications, &sequence_display_backlight_on); } @@ -17,12 +19,31 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) { UNUSED(context); UNUSED(event); iButton* ibutton = context; + Popup* popup = ibutton->popup; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { consumed = true; - if(event.event == iButtonCustomEventRpcExit) { + if(event.event == iButtonCustomEventRpcLoad) { + string_t key_name; + string_init(key_name); + if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) { + path_extract_filename(ibutton->file_path, key_name, true); + } + + if(!string_empty_p(key_name)) { + ibutton_text_store_set(ibutton, "emulating\n%s", string_get_cstr(key_name)); + } else { + ibutton_text_store_set(ibutton, "emulating"); + } + popup_set_text(popup, ibutton->text_store, 82, 32, AlignCenter, AlignTop); + + ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart); + + string_clear(key_name); + } else if(event.event == iButtonCustomEventRpcExit) { + ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop); view_dispatcher_stop(ibutton->view_dispatcher); } } @@ -32,5 +53,11 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) { void ibutton_scene_rpc_on_exit(void* context) { iButton* ibutton = context; - widget_reset(ibutton->widget); + Popup* popup = ibutton->popup; + + popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 0, NULL); + + ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop); } diff --git a/applications/infrared/infrared.c b/applications/infrared/infrared.c index 622061165..1dd0dfa6c 100644 --- a/applications/infrared/infrared.c +++ b/applications/infrared/infrared.c @@ -65,6 +65,8 @@ static bool infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared); infrared_worker_tx_set_signal_sent_callback( infrared->worker, infrared_signal_sent_callback, infrared); + view_dispatcher_send_custom_event( + infrared->view_dispatcher, InfraredCustomEventTypeRpcLoaded); } } else if(event == RpcAppEventButtonPress) { if(arg) { @@ -141,7 +143,6 @@ static Infrared* infrared_alloc() { infrared->gui = furi_record_open("gui"); ViewDispatcher* view_dispatcher = infrared->view_dispatcher; - view_dispatcher_attach_to_gui(view_dispatcher, infrared->gui, ViewDispatcherTypeFullscreen); view_dispatcher_enable_queue(view_dispatcher); view_dispatcher_set_event_callback_context(view_dispatcher, infrared); view_dispatcher_set_custom_event_callback(view_dispatcher, infrared_custom_event_callback); @@ -202,6 +203,7 @@ static void infrared_free(Infrared* infrared) { if(infrared->rpc_ctx) { rpc_system_app_set_callback(infrared->rpc_ctx, NULL, NULL); + rpc_system_app_send_exited(infrared->rpc_ctx); infrared->rpc_ctx = NULL; } @@ -434,6 +436,7 @@ int32_t infrared_app(void* p) { infrared->rpc_ctx = (void*)rpc_ctx; rpc_system_app_set_callback( infrared->rpc_ctx, infrared_rpc_command_callback, infrared); + rpc_system_app_send_started(infrared->rpc_ctx); is_rpc_mode = true; } else { string_set_str(infrared->file_path, (const char*)p); @@ -447,11 +450,17 @@ int32_t infrared_app(void* p) { } if(is_rpc_mode) { + view_dispatcher_attach_to_gui( + infrared->view_dispatcher, infrared->gui, ViewDispatcherTypeDesktop); scene_manager_next_scene(infrared->scene_manager, InfraredSceneRpc); - } else if(is_remote_loaded) { - scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote); } else { - scene_manager_next_scene(infrared->scene_manager, InfraredSceneStart); + view_dispatcher_attach_to_gui( + infrared->view_dispatcher, infrared->gui, ViewDispatcherTypeFullscreen); + if(is_remote_loaded) { + scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote); + } else { + scene_manager_next_scene(infrared->scene_manager, InfraredSceneStart); + } } view_dispatcher_run(infrared->view_dispatcher); diff --git a/applications/infrared/infrared_custom_event.h b/applications/infrared/infrared_custom_event.h index 46d75a9e9..29bd61f11 100644 --- a/applications/infrared/infrared_custom_event.h +++ b/applications/infrared/infrared_custom_event.h @@ -14,6 +14,7 @@ enum InfraredCustomEventType { InfraredCustomEventTypePopupClosed, InfraredCustomEventTypeButtonSelected, InfraredCustomEventTypeBackPressed, + InfraredCustomEventTypeRpcLoaded, }; #pragma pack(push, 1) diff --git a/applications/infrared/scenes/infrared_scene_rpc.c b/applications/infrared/scenes/infrared_scene_rpc.c index 3cab9f80e..e31e7fb61 100644 --- a/applications/infrared/scenes/infrared_scene_rpc.c +++ b/applications/infrared/scenes/infrared_scene_rpc.c @@ -5,12 +5,14 @@ void infrared_scene_rpc_on_enter(void* context) { Infrared* infrared = context; Popup* popup = infrared->popup; - popup_set_text(popup, "Rpc mode", 64, 28, AlignCenter, AlignCenter); + popup_set_header(popup, "Infrared", 82, 28, AlignCenter, AlignBottom); + popup_set_text(popup, "RPC mode", 82, 32, AlignCenter, AlignTop); + + popup_set_icon(popup, 2, 14, &I_Warning_30x23); // TODO: icon popup_set_context(popup, context); popup_set_callback(popup, infrared_popup_closed_callback); - infrared_play_notification_message(infrared, InfraredNotificationMessageYellowOn); view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup); notification_message(infrared->notifications, &sequence_display_backlight_on); @@ -26,6 +28,12 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) { view_dispatcher_stop(infrared->view_dispatcher); } else if(event.event == InfraredCustomEventTypePopupClosed) { view_dispatcher_stop(infrared->view_dispatcher); + } else if(event.event == InfraredCustomEventTypeRpcLoaded) { + 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); } } return consumed; diff --git a/applications/lfrfid/lfrfid_app.cpp b/applications/lfrfid/lfrfid_app.cpp index c491cf40b..2ba36ea31 100644 --- a/applications/lfrfid/lfrfid_app.cpp +++ b/applications/lfrfid/lfrfid_app.cpp @@ -44,6 +44,7 @@ LfRfidApp::~LfRfidApp() { string_clear(file_path); if(rpc_ctx) { rpc_system_app_set_callback(rpc_ctx, NULL, NULL); + rpc_system_app_send_exited(rpc_ctx); } } @@ -91,6 +92,7 @@ void LfRfidApp::run(void* _args) { 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); scene_controller.add_scene(SceneType::Rpc, new LfRfidAppSceneRpc()); scene_controller.process(100, SceneType::Rpc); } else { diff --git a/applications/lfrfid/scene/lfrfid_app_scene_rpc.cpp b/applications/lfrfid/scene/lfrfid_app_scene_rpc.cpp index 80d479345..bc070ce61 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_rpc.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_rpc.cpp @@ -2,10 +2,24 @@ #include #include +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(); - popup->set_header("RPC Mode", 64, 30, AlignCenter, AlignTop); + 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); app->view_controller.switch_to(); @@ -23,8 +37,14 @@ bool LfRfidAppSceneRpc::on_event(LfRfidApp* app, LfRfidApp::Event* 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(); 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); } return consumed; } @@ -32,6 +52,7 @@ bool LfRfidAppSceneRpc::on_event(LfRfidApp* app, LfRfidApp::Event* event) { void LfRfidAppSceneRpc::on_exit(LfRfidApp* app) { if(emulating) { app->worker.stop_emulate(); + notification_message(app->notification, &sequence_blink_stop); } app->view_controller.get()->clean(); } diff --git a/applications/nfc/helpers/nfc_custom_event.h b/applications/nfc/helpers/nfc_custom_event.h index 5de440017..b877732a9 100644 --- a/applications/nfc/helpers/nfc_custom_event.h +++ b/applications/nfc/helpers/nfc_custom_event.h @@ -9,4 +9,5 @@ enum NfcCustomEvent { NfcCustomEventByteInputDone, NfcCustomEventTextInputDone, NfcCustomEventDictAttackDone, + NfcCustomEventRpcLoad, }; diff --git a/applications/nfc/nfc.c b/applications/nfc/nfc.c index 0dc4b3ae1..fb739c618 100644 --- a/applications/nfc/nfc.c +++ b/applications/nfc/nfc.c @@ -31,6 +31,7 @@ void nfc_rpc_exit_callback(Nfc* nfc) { } if(nfc->rpc_ctx) { rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL); + rpc_system_app_send_exited(nfc->rpc_ctx); nfc->rpc_ctx = NULL; } } @@ -82,6 +83,7 @@ static bool nfc_rpc_command_callback(RpcAppSystemEvent event, const char* arg, v nfc->worker, NfcWorkerStateEmulate, &nfc->dev->dev_data, NULL, nfc); } nfc->rpc_state = NfcRpcStateEmulating; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcLoad); result = true; } } @@ -107,7 +109,6 @@ Nfc* nfc_alloc() { // Open GUI record nfc->gui = furi_record_open("gui"); - view_dispatcher_attach_to_gui(nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); // Open Notification record nfc->notifications = furi_record_open("notification"); @@ -291,21 +292,30 @@ int32_t nfc_app(void* p) { if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) { nfc->rpc_ctx = (void*)rpc_ctx; rpc_system_app_set_callback(nfc->rpc_ctx, nfc_rpc_command_callback, nfc); + rpc_system_app_send_started(nfc->rpc_ctx); + view_dispatcher_attach_to_gui( + nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeDesktop); scene_manager_next_scene(nfc->scene_manager, NfcSceneRpc); - } else if(nfc_device_load(nfc->dev, p, true)) { - if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); - } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareClassic); - } else { - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); - } } else { - // Exit app - view_dispatcher_stop(nfc->view_dispatcher); + view_dispatcher_attach_to_gui( + nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); + if(nfc_device_load(nfc->dev, p, true)) { + if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); + } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareClassic); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); + } + } else { + // Exit app + view_dispatcher_stop(nfc->view_dispatcher); + } } nfc_device_set_loading_callback(nfc->dev, NULL, nfc); } else { + view_dispatcher_attach_to_gui( + nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); scene_manager_next_scene(nfc->scene_manager, NfcSceneStart); } diff --git a/applications/nfc/scenes/nfc_scene_rpc.c b/applications/nfc/scenes/nfc_scene_rpc.c index b94bf424e..582dff8e6 100644 --- a/applications/nfc/scenes/nfc_scene_rpc.c +++ b/applications/nfc/scenes/nfc_scene_rpc.c @@ -2,24 +2,33 @@ void nfc_scene_rpc_on_enter(void* context) { Nfc* nfc = context; - Widget* widget = nfc->widget; + Popup* popup = nfc->popup; - widget_add_text_box_element( - widget, 0, 0, 128, 28, AlignCenter, AlignCenter, "RPC mode", false); + popup_set_header(popup, "NFC", 82, 28, AlignCenter, AlignBottom); + popup_set_text(popup, "RPC mode", 82, 32, AlignCenter, AlignTop); + + popup_set_icon(popup, 2, 14, &I_Warning_30x23); // TODO: icon + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); notification_message(nfc->notifications, &sequence_display_backlight_on); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = context; + Popup* popup = nfc->popup; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { consumed = true; if(event.event == NfcCustomEventViewExit) { view_dispatcher_stop(nfc->view_dispatcher); + nfc_blink_stop(nfc); + } else if(event.event == NfcCustomEventRpcLoad) { + 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); } } return consumed; @@ -27,8 +36,12 @@ bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) { void nfc_scene_rpc_on_exit(void* context) { Nfc* nfc = context; + Popup* popup = nfc->popup; nfc_rpc_exit_callback(nfc); + nfc_blink_stop(nfc); - widget_reset(nfc->widget); + popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 0, NULL); } diff --git a/applications/rpc/rpc_app.c b/applications/rpc/rpc_app.c index 84cb54107..525eedcfe 100644 --- a/applications/rpc/rpc_app.c +++ b/applications/rpc/rpc_app.c @@ -12,6 +12,7 @@ struct RpcAppSystem { RpcSession* session; RpcAppSystemCallback app_callback; void* app_context; + PB_Main* state_msg; FuriTimer* timer; }; @@ -96,7 +97,7 @@ static void rpc_system_app_lock_status_process(const PB_Main* request, void* con pb_release(&PB_Main_msg, &response); } -static void rpc_system_app_exit(const PB_Main* request, void* context) { +static void rpc_system_app_exit_request(const PB_Main* request, void* context) { furi_assert(request); furi_assert(context); @@ -194,6 +195,24 @@ static void rpc_system_app_button_release(const PB_Main* request, void* context) rpc_send_and_release_empty(session, request->command_id, status); } +void rpc_system_app_send_started(RpcAppSystem* rpc_app) { + furi_assert(rpc_app); + RpcSession* session = rpc_app->session; + furi_assert(session); + + rpc_app->state_msg->content.app_state_response.state = PB_App_AppState_APP_STARTED; + rpc_send(session, rpc_app->state_msg); +} + +void rpc_system_app_send_exited(RpcAppSystem* rpc_app) { + furi_assert(rpc_app); + RpcSession* session = rpc_app->session; + furi_assert(session); + + rpc_app->state_msg->content.app_state_response.state = PB_App_AppState_APP_CLOSED; + rpc_send(session, rpc_app->state_msg); +} + void rpc_system_app_set_callback(RpcAppSystem* rpc_app, RpcAppSystemCallback callback, void* ctx) { furi_assert(rpc_app); @@ -209,6 +228,11 @@ void* rpc_system_app_alloc(RpcSession* session) { rpc_app->timer = furi_timer_alloc(rpc_system_app_timer_callback, FuriTimerTypeOnce, rpc_app); + // App exit message + rpc_app->state_msg = malloc(sizeof(PB_Main)); + rpc_app->state_msg->which_content = PB_Main_app_state_response_tag; + rpc_app->state_msg->command_status = PB_CommandStatus_OK; + RpcHandler rpc_handler = { .message_handler = NULL, .decode_submessage = NULL, @@ -221,7 +245,7 @@ void* rpc_system_app_alloc(RpcSession* session) { rpc_handler.message_handler = rpc_system_app_lock_status_process; rpc_add_handler(session, PB_Main_app_lock_status_request_tag, &rpc_handler); - rpc_handler.message_handler = rpc_system_app_exit; + rpc_handler.message_handler = rpc_system_app_exit_request; rpc_add_handler(session, PB_Main_app_exit_request_tag, &rpc_handler); rpc_handler.message_handler = rpc_system_app_load_file; @@ -247,5 +271,6 @@ void rpc_system_app_free(void* context) { rpc_app->app_callback(RpcAppEventSessionClose, NULL, rpc_app->app_context); } + free(rpc_app->state_msg); free(rpc_app); } diff --git a/applications/rpc/rpc_app.h b/applications/rpc/rpc_app.h index 396eef1a3..4e00922ff 100644 --- a/applications/rpc/rpc_app.h +++ b/applications/rpc/rpc_app.h @@ -19,6 +19,10 @@ typedef struct RpcAppSystem RpcAppSystem; void rpc_system_app_set_callback(RpcAppSystem* rpc_app, RpcAppSystemCallback callback, void* ctx); +void rpc_system_app_send_started(RpcAppSystem* rpc_app); + +void rpc_system_app_send_exited(RpcAppSystem* rpc_app); + #ifdef __cplusplus } #endif diff --git a/applications/subghz/helpers/subghz_custom_event.h b/applications/subghz/helpers/subghz_custom_event.h index 05f0f4924..801a8ae9d 100644 --- a/applications/subghz/helpers/subghz_custom_event.h +++ b/applications/subghz/helpers/subghz_custom_event.h @@ -46,6 +46,8 @@ typedef enum { SubGhzCustomEventSceneExit, SubGhzCustomEventSceneStay, + SubGhzCustomEventSceneRpcLoad, + SubGhzCustomEventViewReceiverOK, SubGhzCustomEventViewReceiverConfig, SubGhzCustomEventViewReceiverBack, diff --git a/applications/subghz/scenes/subghz_scene_rpc.c b/applications/subghz/scenes/subghz_scene_rpc.c index c7573fda1..844f5c167 100644 --- a/applications/subghz/scenes/subghz_scene_rpc.c +++ b/applications/subghz/scenes/subghz_scene_rpc.c @@ -2,24 +2,40 @@ void subghz_scene_rpc_on_enter(void* context) { SubGhz* subghz = context; - Widget* widget = subghz->widget; + Popup* popup = subghz->popup; - widget_add_text_box_element( - widget, 0, 0, 128, 28, AlignCenter, AlignCenter, "RPC mode", false); + popup_set_header(popup, "Sub-GHz", 82, 28, AlignCenter, AlignBottom); + popup_set_text(popup, "RPC mode", 82, 32, AlignCenter, AlignTop); + + popup_set_icon(popup, 2, 14, &I_Warning_30x23); // TODO: icon + + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdPopup); notification_message(subghz->notifications, &sequence_display_backlight_on); - - view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdWidget); } bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; + Popup* popup = subghz->popup; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { consumed = true; if(event.event == SubGhzCustomEventSceneExit) { view_dispatcher_stop(subghz->view_dispatcher); + } else if(event.event == SubGhzCustomEventSceneRpcLoad) { + string_t file_name; + string_init(file_name); + path_extract_filename(subghz->file_path, file_name, true); + + snprintf( + subghz->file_name_tmp, + SUBGHZ_MAX_LEN_NAME, + "loaded\n%s", + string_get_cstr(file_name)); + popup_set_text(popup, subghz->file_name_tmp, 82, 32, AlignCenter, AlignTop); + + string_clear(file_name); } } return consumed; @@ -27,8 +43,9 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { void subghz_scene_rpc_on_exit(void* context) { SubGhz* subghz = context; + Popup* popup = subghz->popup; - //subghz_rpc_exit_callback(subghz); - - widget_reset(subghz->widget); + popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 0, NULL); } diff --git a/applications/subghz/subghz.c b/applications/subghz/subghz.c index 984ce4728..76998eb0a 100644 --- a/applications/subghz/subghz.c +++ b/applications/subghz/subghz.c @@ -5,6 +5,18 @@ #include "subghz_i.h" #include +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, +}; + bool subghz_custom_event_callback(void* context, uint32_t event) { furi_assert(context); SubGhz* subghz = context; @@ -36,6 +48,7 @@ static bool subghz_rpc_command_callback(RpcAppSystemEvent event, const char* arg if(event == RpcAppEventSessionClose) { rpc_system_app_set_callback(subghz->rpc_ctx, NULL, NULL); subghz->rpc_ctx = NULL; + notification_message(subghz->notifications, &sequence_blink_stop); view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneExit); if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { subghz_tx_stop(subghz); @@ -53,15 +66,19 @@ static bool subghz_rpc_command_callback(RpcAppSystemEvent event, const char* arg if(arg) { if(subghz_key_load(subghz, arg, false)) { string_set_str(subghz->file_path, arg); + view_dispatcher_send_custom_event( + subghz->view_dispatcher, SubGhzCustomEventSceneRpcLoad); result = true; } } } else if(event == RpcAppEventButtonPress) { if(subghz->txrx->txrx_state == SubGhzTxRxStateSleep) { + notification_message(subghz->notifications, &sequence_blink_start_magenta); result = subghz_tx_start(subghz, subghz->txrx->fff_data); } } else if(event == RpcAppEventButtonRelease) { if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { + notification_message(subghz->notifications, &sequence_blink_stop); subghz_tx_stop(subghz); subghz_sleep(subghz); result = true; @@ -83,8 +100,6 @@ SubGhz* subghz_alloc() { // View Dispatcher subghz->view_dispatcher = view_dispatcher_alloc(); view_dispatcher_enable_queue(subghz->view_dispatcher); - view_dispatcher_attach_to_gui( - subghz->view_dispatcher, subghz->gui, ViewDispatcherTypeFullscreen); subghz->scene_manager = scene_manager_alloc(&subghz_scene_handlers, subghz); view_dispatcher_set_event_callback_context(subghz->view_dispatcher, subghz); @@ -218,6 +233,8 @@ void subghz_free(SubGhz* subghz) { if(subghz->rpc_ctx) { rpc_system_app_set_callback(subghz->rpc_ctx, NULL, NULL); + rpc_system_app_send_exited(subghz->rpc_ctx); + notification_message(subghz->notifications, &sequence_blink_stop); subghz->rpc_ctx = NULL; } @@ -322,24 +339,33 @@ int32_t subghz_app(void* p) { if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) { subghz->rpc_ctx = (void*)rpc_ctx; rpc_system_app_set_callback(subghz->rpc_ctx, subghz_rpc_command_callback, subghz); + rpc_system_app_send_started(subghz->rpc_ctx); + view_dispatcher_attach_to_gui( + subghz->view_dispatcher, subghz->gui, ViewDispatcherTypeDesktop); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneRpc); - } else if(subghz_key_load(subghz, p, true)) { - string_set_str(subghz->file_path, p); - - if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) { - //Load Raw TX - subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); - } else { - //Load transmitter TX - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter); - } } else { - //exit app - scene_manager_stop(subghz->scene_manager); - view_dispatcher_stop(subghz->view_dispatcher); + view_dispatcher_attach_to_gui( + subghz->view_dispatcher, subghz->gui, ViewDispatcherTypeFullscreen); + if(subghz_key_load(subghz, p, true)) { + string_set_str(subghz->file_path, p); + + if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) { + //Load Raw TX + subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); + } else { + //Load transmitter TX + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter); + } + } else { + //exit app + scene_manager_stop(subghz->scene_manager); + view_dispatcher_stop(subghz->view_dispatcher); + } } } else { + view_dispatcher_attach_to_gui( + subghz->view_dispatcher, subghz->gui, ViewDispatcherTypeFullscreen); string_set_str(subghz->file_path, SUBGHZ_APP_FOLDER); if(load_database) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); diff --git a/assets/protobuf b/assets/protobuf index d9e343661..cc5918dc4 160000 --- a/assets/protobuf +++ b/assets/protobuf @@ -1 +1 @@ -Subproject commit d9e343661dd36cfab792b78be1dea4e5950cb4dd +Subproject commit cc5918dc488ac3617012ce5377114e086b447324 From ac60d1808a055be65ca42ad64f89d3c721de8772 Mon Sep 17 00:00:00 2001 From: Wyatt Neal Date: Mon, 25 Jul 2022 10:35:02 -0400 Subject: [PATCH 6/9] fixing typos, satus -> status (#1422) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/subghz/views/subghz_read_raw.c | 78 +++++++++---------- applications/subghz/views/subghz_read_raw.h | 2 +- .../subghz/views/subghz_test_static.c | 10 +-- 3 files changed, 45 insertions(+), 45 deletions(-) diff --git a/applications/subghz/views/subghz_read_raw.c b/applications/subghz/views/subghz_read_raw.c index a4807d775..de8f371b7 100644 --- a/applications/subghz/views/subghz_read_raw.c +++ b/applications/subghz/views/subghz_read_raw.c @@ -26,7 +26,7 @@ typedef struct { bool rssi_history_end; uint8_t ind_write; uint8_t ind_sin; - SubGhzReadRAWStatus satus; + SubGhzReadRAWStatus status; } SubGhzReadRAWModel; void subghz_read_raw_set_callback( @@ -88,21 +88,21 @@ void subghz_read_raw_stop_send(SubGhzReadRAW* instance) { with_view_model( instance->view, (SubGhzReadRAWModel * model) { - switch(model->satus) { + switch(model->status) { case SubGhzReadRAWStatusTXRepeat: case SubGhzReadRAWStatusLoadKeyTXRepeat: instance->callback(SubGhzCustomEventViewReadRAWSendStart, instance->context); break; case SubGhzReadRAWStatusTX: - model->satus = SubGhzReadRAWStatusIDLE; + model->status = SubGhzReadRAWStatusIDLE; break; case SubGhzReadRAWStatusLoadKeyTX: - model->satus = SubGhzReadRAWStatusLoadKeyIDLE; + model->status = SubGhzReadRAWStatusLoadKeyIDLE; break; default: FURI_LOG_W(TAG, "unknown status"); - model->satus = SubGhzReadRAWStatusIDLE; + model->status = SubGhzReadRAWStatusIDLE; break; } return true; @@ -225,7 +225,7 @@ void subghz_read_raw_draw(Canvas* canvas, SubGhzReadRAWModel* model) { canvas_draw_line(canvas, 0, 48, 115, 48); canvas_draw_line(canvas, 115, 14, 115, 48); - switch(model->satus) { + switch(model->status) { case SubGhzReadRAWStatusIDLE: elements_button_left(canvas, "Erase"); elements_button_center(canvas, "Send"); @@ -289,26 +289,26 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { with_view_model( instance->view, (SubGhzReadRAWModel * model) { uint8_t ret = false; - switch(model->satus) { + switch(model->status) { case SubGhzReadRAWStatusIDLE: // Start TX instance->callback(SubGhzCustomEventViewReadRAWSendStart, instance->context); - model->satus = SubGhzReadRAWStatusTXRepeat; + model->status = SubGhzReadRAWStatusTXRepeat; ret = true; break; case SubGhzReadRAWStatusTX: // Start TXRepeat - model->satus = SubGhzReadRAWStatusTXRepeat; + model->status = SubGhzReadRAWStatusTXRepeat; break; case SubGhzReadRAWStatusLoadKeyIDLE: // Start Load Key TX instance->callback(SubGhzCustomEventViewReadRAWSendStart, instance->context); - model->satus = SubGhzReadRAWStatusLoadKeyTXRepeat; + model->status = SubGhzReadRAWStatusLoadKeyTXRepeat; ret = true; break; case SubGhzReadRAWStatusLoadKeyTX: // Start Load Key TXRepeat - model->satus = SubGhzReadRAWStatusLoadKeyTXRepeat; + model->status = SubGhzReadRAWStatusLoadKeyTXRepeat; break; default: @@ -319,33 +319,33 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { } else if(event->key == InputKeyOk && event->type == InputTypeRelease) { with_view_model( instance->view, (SubGhzReadRAWModel * model) { - if(model->satus == SubGhzReadRAWStatusTXRepeat) { + if(model->status == SubGhzReadRAWStatusTXRepeat) { // Stop repeat TX - model->satus = SubGhzReadRAWStatusTX; - } else if(model->satus == SubGhzReadRAWStatusLoadKeyTXRepeat) { + model->status = SubGhzReadRAWStatusTX; + } else if(model->status == SubGhzReadRAWStatusLoadKeyTXRepeat) { // Stop repeat TX - model->satus = SubGhzReadRAWStatusLoadKeyTX; + model->status = SubGhzReadRAWStatusLoadKeyTX; } return false; }); } else if(event->key == InputKeyBack && event->type == InputTypeShort) { with_view_model( instance->view, (SubGhzReadRAWModel * model) { - switch(model->satus) { + switch(model->status) { case SubGhzReadRAWStatusREC: //Stop REC instance->callback(SubGhzCustomEventViewReadRAWIDLE, instance->context); - model->satus = SubGhzReadRAWStatusIDLE; + model->status = SubGhzReadRAWStatusIDLE; break; case SubGhzReadRAWStatusLoadKeyTX: //Stop TxRx instance->callback(SubGhzCustomEventViewReadRAWTXRXStop, instance->context); - model->satus = SubGhzReadRAWStatusLoadKeyIDLE; + model->status = SubGhzReadRAWStatusLoadKeyIDLE; break; case SubGhzReadRAWStatusTX: //Stop TxRx instance->callback(SubGhzCustomEventViewReadRAWTXRXStop, instance->context); - model->satus = SubGhzReadRAWStatusIDLE; + model->status = SubGhzReadRAWStatusIDLE; break; case SubGhzReadRAWStatusLoadKeyIDLE: //Exit @@ -362,14 +362,14 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { with_view_model( instance->view, (SubGhzReadRAWModel * model) { - if(model->satus == SubGhzReadRAWStatusStart) { + if(model->status == SubGhzReadRAWStatusStart) { //Config instance->callback(SubGhzCustomEventViewReadRAWConfig, instance->context); } else if( - (model->satus == SubGhzReadRAWStatusIDLE) || - (model->satus == SubGhzReadRAWStatusLoadKeyIDLE)) { + (model->status == SubGhzReadRAWStatusIDLE) || + (model->status == SubGhzReadRAWStatusLoadKeyIDLE)) { //Erase - model->satus = SubGhzReadRAWStatusStart; + model->status = SubGhzReadRAWStatusStart; model->rssi_history_end = false; model->ind_write = 0; string_set_str(model->sample_write, "0 spl."); @@ -381,10 +381,10 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { } else if(event->key == InputKeyRight && event->type == InputTypeShort) { with_view_model( instance->view, (SubGhzReadRAWModel * model) { - if(model->satus == SubGhzReadRAWStatusIDLE) { + if(model->status == SubGhzReadRAWStatusIDLE) { //Save instance->callback(SubGhzCustomEventViewReadRAWSave, instance->context); - } else if(model->satus == SubGhzReadRAWStatusLoadKeyIDLE) { + } else if(model->status == SubGhzReadRAWStatusLoadKeyIDLE) { //More instance->callback(SubGhzCustomEventViewReadRAWMore, instance->context); } @@ -393,16 +393,16 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { } else if(event->key == InputKeyOk && event->type == InputTypeShort) { with_view_model( instance->view, (SubGhzReadRAWModel * model) { - if(model->satus == SubGhzReadRAWStatusStart) { + if(model->status == SubGhzReadRAWStatusStart) { //Record instance->callback(SubGhzCustomEventViewReadRAWREC, instance->context); - model->satus = SubGhzReadRAWStatusREC; + model->status = SubGhzReadRAWStatusREC; model->ind_write = 0; model->rssi_history_end = false; - } else if(model->satus == SubGhzReadRAWStatusREC) { + } else if(model->status == SubGhzReadRAWStatusREC) { //Stop instance->callback(SubGhzCustomEventViewReadRAWIDLE, instance->context); - model->satus = SubGhzReadRAWStatusIDLE; + model->status = SubGhzReadRAWStatusIDLE; } return true; }); @@ -412,15 +412,15 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { void subghz_read_raw_set_status( SubGhzReadRAW* instance, - SubGhzReadRAWStatus satus, + SubGhzReadRAWStatus status, const char* file_name) { furi_assert(instance); - switch(satus) { + switch(status) { case SubGhzReadRAWStatusStart: with_view_model( instance->view, (SubGhzReadRAWModel * model) { - model->satus = SubGhzReadRAWStatusStart; + model->status = SubGhzReadRAWStatusStart; model->rssi_history_end = false; model->ind_write = 0; string_reset(model->file_name); @@ -431,14 +431,14 @@ void subghz_read_raw_set_status( case SubGhzReadRAWStatusIDLE: with_view_model( instance->view, (SubGhzReadRAWModel * model) { - model->satus = SubGhzReadRAWStatusIDLE; + model->status = SubGhzReadRAWStatusIDLE; return true; }); break; case SubGhzReadRAWStatusLoadKeyTX: with_view_model( instance->view, (SubGhzReadRAWModel * model) { - model->satus = SubGhzReadRAWStatusLoadKeyIDLE; + model->status = SubGhzReadRAWStatusLoadKeyIDLE; model->rssi_history_end = false; model->ind_write = 0; string_set_str(model->file_name, file_name); @@ -449,7 +449,7 @@ void subghz_read_raw_set_status( case SubGhzReadRAWStatusSaveKey: with_view_model( instance->view, (SubGhzReadRAWModel * model) { - model->satus = SubGhzReadRAWStatusLoadKeyIDLE; + model->status = SubGhzReadRAWStatusLoadKeyIDLE; if(!model->ind_write) { string_set_str(model->file_name, file_name); string_set_str(model->sample_write, "RAW"); @@ -477,11 +477,11 @@ void subghz_read_raw_exit(void* context) { with_view_model( instance->view, (SubGhzReadRAWModel * model) { - if(model->satus != SubGhzReadRAWStatusIDLE && - model->satus != SubGhzReadRAWStatusStart && - model->satus != SubGhzReadRAWStatusLoadKeyIDLE) { + if(model->status != SubGhzReadRAWStatusIDLE && + model->status != SubGhzReadRAWStatusStart && + model->status != SubGhzReadRAWStatusLoadKeyIDLE) { instance->callback(SubGhzCustomEventViewReadRAWIDLE, instance->context); - model->satus = SubGhzReadRAWStatusStart; + model->status = SubGhzReadRAWStatusStart; } return true; }); diff --git a/applications/subghz/views/subghz_read_raw.h b/applications/subghz/views/subghz_read_raw.h index db75f1b48..1d4bb7dc0 100644 --- a/applications/subghz/views/subghz_read_raw.h +++ b/applications/subghz/views/subghz_read_raw.h @@ -44,7 +44,7 @@ void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi); void subghz_read_raw_set_status( SubGhzReadRAW* instance, - SubGhzReadRAWStatus satus, + SubGhzReadRAWStatus status, const char* file_name); View* subghz_read_raw_get_view(SubGhzReadRAW* subghz_static); diff --git a/applications/subghz/views/subghz_test_static.c b/applications/subghz/views/subghz_test_static.c index 26cf9b484..41de72628 100644 --- a/applications/subghz/views/subghz_test_static.c +++ b/applications/subghz/views/subghz_test_static.c @@ -25,7 +25,7 @@ static const uint32_t subghz_test_static_keys[] = { struct SubGhzTestStatic { View* view; - SubGhzTestStaticStatus satus_tx; + SubGhzTestStaticStatus status_tx; SubGhzEncoderPrinceton* encoder; SubGhzTestStaticCallback callback; void* context; @@ -113,10 +113,10 @@ bool subghz_test_static_input(InputEvent* event, void* context) { furi_hal_subghz_start_async_tx( subghz_encoder_princeton_for_testing_yield, instance->encoder); - instance->satus_tx = SubGhzTestStaticStatusTX; + instance->status_tx = SubGhzTestStaticStatusTX; } } else if(event->type == InputTypeRelease) { - if(instance->satus_tx == SubGhzTestStaticStatusTX) { + if(instance->status_tx == SubGhzTestStaticStatusTX) { FURI_LOG_I(TAG, "TX Stop"); subghz_encoder_princeton_for_testing_stop( instance->encoder, furi_get_tick()); @@ -124,7 +124,7 @@ bool subghz_test_static_input(InputEvent* event, void* context) { furi_hal_subghz_stop_async_tx(); notification_message(notification, &sequence_reset_red); } - instance->satus_tx = SubGhzTestStaticStatusIDLE; + instance->status_tx = SubGhzTestStaticStatusIDLE; } furi_record_close("notification"); } @@ -144,7 +144,7 @@ void subghz_test_static_enter(void* context) { furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); furi_hal_gpio_write(&gpio_cc1101_g0, false); - instance->satus_tx = SubGhzTestStaticStatusIDLE; + instance->status_tx = SubGhzTestStaticStatusIDLE; with_view_model( instance->view, (SubGhzTestStaticModel * model) { From 30820b83b5d6738c0867b11860ccbf92f8530183 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Mon, 25 Jul 2022 17:46:42 +0300 Subject: [PATCH 7/9] [FL-2464, FL-2466] RFID, ibutton text fix #1413 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/ibutton/scenes/ibutton_scene_retry_confirm.c | 2 +- applications/infrared/scenes/infrared_scene_ask_back.c | 2 +- applications/infrared/scenes/infrared_scene_ask_retry.c | 2 +- applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/applications/ibutton/scenes/ibutton_scene_retry_confirm.c b/applications/ibutton/scenes/ibutton_scene_retry_confirm.c index d2778ac15..fa2e1dec9 100644 --- a/applications/ibutton/scenes/ibutton_scene_retry_confirm.c +++ b/applications/ibutton/scenes/ibutton_scene_retry_confirm.c @@ -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); } diff --git a/applications/infrared/scenes/infrared_scene_ask_back.c b/applications/infrared/scenes/infrared_scene_ask_back.c index 11cfcb04d..c9c23684f 100644 --- a/applications/infrared/scenes/infrared_scene_ask_back.c +++ b/applications/infrared/scenes/infrared_scene_ask_back.c @@ -16,7 +16,7 @@ void infrared_scene_ask_back_on_enter(void* context) { } 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); diff --git a/applications/infrared/scenes/infrared_scene_ask_retry.c b/applications/infrared/scenes/infrared_scene_ask_retry.c index 48a5cfcde..5157ee882 100644 --- a/applications/infrared/scenes/infrared_scene_ask_retry.c +++ b/applications/infrared/scenes/infrared_scene_ask_retry.c @@ -11,7 +11,7 @@ void infrared_scene_ask_retry_on_enter(void* context) { 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); diff --git a/applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.cpp b/applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.cpp index e62b91bd4..39430b974 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.cpp @@ -19,7 +19,7 @@ void LfRfidAppSceneRetryConfirm::on_enter(LfRfidApp* app, bool /* need_restore * 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(); } From f8e0ec42c53b7b0710d17f5efcd264c8b4c94927 Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Mon, 25 Jul 2022 09:21:05 -0600 Subject: [PATCH 8/9] nfc: NTAG203 support (#1383) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * nfc: Fix original MFUL feature flags * nfc: Add NTAG203 read support * nfc: Update emulation lock byte handling for NTAG203 * nfc: Add NTAG203 counter emulation support * nfc: Add NTAG203 tag generator * nfc: Fix NTAG203 emulating GET_VERSION * nfc: Fix MFUL version reading * nfc: Complete NTAG203 counter emulation behavior * nfc: Complete NTAG203 emulation * nfc: Remove unnecessary init in MFUL emulation * nfc: Add notes about MFUL type enum Co-authored-by: gornekich Co-authored-by: あく --- applications/nfc/helpers/nfc_generators.c | 20 ++ applications/nfc/nfc_types.c | 2 + lib/nfc_protocols/mifare_ultralight.c | 257 +++++++++++++++++----- lib/nfc_protocols/mifare_ultralight.h | 15 ++ 4 files changed, 237 insertions(+), 57 deletions(-) diff --git a/applications/nfc/helpers/nfc_generators.c b/applications/nfc/helpers/nfc_generators.c index 67d9be7a0..4121daf4f 100644 --- a/applications/nfc/helpers/nfc_generators.c +++ b/applications/nfc/helpers/nfc_generators.c @@ -6,6 +6,8 @@ static const uint8_t version_bytes_mf0ulx1[] = {0x00, 0x04, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03}; static const uint8_t version_bytes_ntag21x[] = {0x00, 0x04, 0x04, 0x02, 0x01, 0x00, 0x00, 0x03}; static const uint8_t version_bytes_ntag_i2c[] = {0x00, 0x04, 0x04, 0x05, 0x02, 0x00, 0x00, 0x03}; +static const uint8_t default_data_ntag203[] = + {0xE1, 0x10, 0x12, 0x00, 0x01, 0x03, 0xA0, 0x10, 0x44, 0x03, 0x00, 0xFE}; static const uint8_t default_data_ntag213[] = {0x01, 0x03, 0xA0, 0x0C, 0x34, 0x03, 0x00, 0xFE}; static const uint8_t default_data_ntag215_216[] = {0x03, 0x00, 0xFE}; static const uint8_t default_data_ntag_i2c[] = {0xE1, 0x10, 0x00, 0x00, 0x03, 0x00, 0xFE}; @@ -58,6 +60,18 @@ static void nfc_generate_mf_ul_orig(NfcDeviceData* data) { memset(&mful->data[4 * 4], 0xFF, 4); } +static void nfc_generate_mf_ul_ntag203(NfcDeviceData* data) { + nfc_generate_common_start(data); + nfc_generate_mf_ul_common(data); + + MfUltralightData* mful = &data->mf_ul_data; + mful->type = MfUltralightTypeNTAG203; + mful->data_size = 42 * 4; + 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)); +} + static void nfc_generate_mf_ul_with_config_common(NfcDeviceData* data, uint8_t num_pages) { nfc_generate_common_start(data); nfc_generate_mf_ul_common(data); @@ -275,6 +289,11 @@ static const NfcGenerator mf_ul_h21_generator = { .generator_func = nfc_generate_mf_ul_h21, .next_scene = NfcSceneMifareUlMenu}; +static const NfcGenerator ntag203_generator = { + .name = "NTAG203", + .generator_func = nfc_generate_mf_ul_ntag203, + .next_scene = NfcSceneMifareUlMenu}; + static const NfcGenerator ntag213_generator = { .name = "NTAG213", .generator_func = nfc_generate_ntag213, @@ -316,6 +335,7 @@ const NfcGenerator* const nfc_generators[] = { &mf_ul_h11_generator, &mf_ul_21_generator, &mf_ul_h21_generator, + &ntag203_generator, &ntag213_generator, &ntag215_generator, &ntag216_generator, diff --git a/applications/nfc/nfc_types.c b/applications/nfc/nfc_types.c index 2d11c3397..427628769 100644 --- a/applications/nfc/nfc_types.c +++ b/applications/nfc/nfc_types.c @@ -43,6 +43,8 @@ const char* nfc_mf_ul_type(MfUltralightType type, bool full_name) { return "NTAG I2C Plus 1K"; } else if(type == MfUltralightTypeNTAGI2CPlus2K) { return "NTAG I2C Plus 2K"; + } else if(type == MfUltralightTypeNTAG203) { + return "NTAG203"; } else if(type == MfUltralightTypeUL11 && full_name) { return "Mifare Ultralight 11"; } else if(type == MfUltralightTypeUL21 && full_name) { diff --git a/lib/nfc_protocols/mifare_ultralight.c b/lib/nfc_protocols/mifare_ultralight.c index 21dbd9c4c..9dcd1d6aa 100644 --- a/lib/nfc_protocols/mifare_ultralight.c +++ b/lib/nfc_protocols/mifare_ultralight.c @@ -35,9 +35,11 @@ static MfUltralightFeatures mf_ul_get_features(MfUltralightType type) { return MfUltralightSupportFastRead | MfUltralightSupportAuth | MfUltralightSupportFastWrite | MfUltralightSupportSignature | MfUltralightSupportSectorSelect; + case MfUltralightTypeNTAG203: + return MfUltralightSupportCompatWrite | MfUltralightSupportCounterInMemory; default: // Assumed original MFUL 512-bit - return MfUltralightSupportNone; + return MfUltralightSupportCompatWrite; } } @@ -46,6 +48,11 @@ static void mf_ul_set_default_version(MfUltralightReader* reader, MfUltralightDa reader->pages_to_read = 16; } +static void mf_ul_set_version_ntag203(MfUltralightReader* reader, MfUltralightData* data) { + data->type = MfUltralightTypeNTAG203; + reader->pages_to_read = 42; +} + bool mf_ultralight_read_version( FuriHalNfcTxRxContext* tx_rx, MfUltralightReader* reader, @@ -57,7 +64,7 @@ bool mf_ultralight_read_version( tx_rx->tx_data[0] = MF_UL_GET_VERSION_CMD; tx_rx->tx_bits = 8; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; - if(!furi_hal_nfc_tx_rx(tx_rx, 50)) { + if(!furi_hal_nfc_tx_rx(tx_rx, 50) || tx_rx->rx_bits != 64) { FURI_LOG_D(TAG, "Failed reading version"); mf_ul_set_default_version(reader, data); furi_hal_nfc_sleep(); @@ -468,6 +475,23 @@ static bool mf_ultralight_sector_select(FuriHalNfcTxRxContext* tx_rx, uint8_t se return true; } +bool mf_ultralight_read_pages_direct( + FuriHalNfcTxRxContext* tx_rx, + uint8_t start_index, + uint8_t* data) { + FURI_LOG_D(TAG, "Reading pages %d - %d", start_index, start_index + 3); + tx_rx->tx_data[0] = MF_UL_READ_CMD; + tx_rx->tx_data[1] = start_index; + tx_rx->tx_bits = 16; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + if(!furi_hal_nfc_tx_rx(tx_rx, 50) || tx_rx->rx_bits < 16 * 8) { + FURI_LOG_D(TAG, "Failed to read pages %d - %d", start_index, start_index + 3); + return false; + } + memcpy(data, tx_rx->rx_data, 16); + return true; +} + bool mf_ultralight_read_pages( FuriHalNfcTxRxContext* tx_rx, MfUltralightReader* reader, @@ -632,6 +656,17 @@ bool mf_ul_read_card( // Read Signature mf_ultralight_read_signature(tx_rx, data); } + } else { + // No GET_VERSION command, check for NTAG203 by reading last page (41) + uint8_t dummy[16]; + if(mf_ultralight_read_pages_direct(tx_rx, 41, dummy)) { + mf_ul_set_version_ntag203(reader, data); + reader->supported_features = mf_ul_get_features(data->type); + } else { + // We're really an original Mifare Ultralight, reset tag for safety + furi_hal_nfc_sleep(); + furi_hal_nfc_activate_nfca(300, NULL); + } } card_read = mf_ultralight_read_pages(tx_rx, reader, data); @@ -772,6 +807,8 @@ static bool mf_ul_ntag_i2c_plus_check_auth( static int16_t mf_ul_get_dynamic_lock_page_addr(MfUltralightData* data) { switch(data->type) { + case MfUltralightTypeNTAG203: + return 0x28; case MfUltralightTypeUL21: case MfUltralightTypeNTAG213: case MfUltralightTypeNTAG215: @@ -804,6 +841,10 @@ static bool mf_ul_check_lock(MfUltralightEmulator* emulator, int16_t write_page) // Check max page switch(emulator->data.type) { + case MfUltralightTypeNTAG203: + // Counter page can be locked and is after dynamic locks + if(write_page == 40) return true; + break; case MfUltralightTypeUL21: case MfUltralightTypeNTAG213: case MfUltralightTypeNTAG215: @@ -841,6 +882,19 @@ static bool mf_ul_check_lock(MfUltralightEmulator* emulator, int16_t write_page) switch(emulator->data.type) { // low byte LSB range, MSB range + case MfUltralightTypeNTAG203: + if(write_page >= 16 && write_page <= 27) + shift = (write_page - 16) / 4 + 1; + else if(write_page >= 28 && write_page <= 39) + shift = (write_page - 28) / 4 + 5; + else if(write_page == 41) + shift = 12; + else { + furi_assert(false); + shift = 0; + } + + break; case MfUltralightTypeUL21: case MfUltralightTypeNTAG213: // 16-17, 30-31 @@ -937,6 +991,42 @@ static void mf_ul_increment_single_counter(MfUltralightEmulator* emulator) { } } +static bool + mf_ul_emulate_ntag203_counter_write(MfUltralightEmulator* emulator, uint8_t* page_buff) { + // We'll reuse the existing counters for other NTAGs as staging + // Counter 0 stores original value, data is new value + uint32_t counter_value; + if(emulator->data.tearing[0] == MF_UL_TEARING_FLAG_DEFAULT) { + counter_value = emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4] | + (emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4 + 1] << 8); + } else { + // We've had a reset here, so load from original value + counter_value = emulator->data.counter[0]; + } + // Although the datasheet says increment by 0 is always possible, this is not the case on + // an actual tag. If the counter is at 0xFFFF, any writes are locked out. + if(counter_value == 0xFFFF) return false; + uint32_t increment = page_buff[0] | (page_buff[1] << 8); + if(counter_value == 0) { + counter_value = increment; + } else { + // Per datasheet specifying > 0x000F is supposed to NAK, but actual tag doesn't + increment &= 0x000F; + if(counter_value + increment > 0xFFFF) return false; + counter_value += increment; + } + // Commit to new value counter + emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4] = (uint8_t)counter_value; + emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4 + 1] = (uint8_t)(counter_value >> 8); + emulator->data.tearing[0] = MF_UL_TEARING_FLAG_DEFAULT; + if(counter_value == 0xFFFF) { + // Tag will lock out counter if final number is 0xFFFF, even if you try to roll it back + emulator->data.counter[1] = 0xFFFF; + } + emulator->data_changed = true; + return true; +} + static void mf_ul_emulate_write( MfUltralightEmulator* emulator, int16_t tag_addr, @@ -962,53 +1052,75 @@ static void mf_ul_emulate_write( *(uint32_t*)page_buff |= *(uint32_t*)&emulator->data.data[write_page * 4]; } else if(tag_addr == mf_ul_get_dynamic_lock_page_addr(&emulator->data)) { // Handle dynamic locks - uint16_t orig_locks = emulator->data.data[write_page * 4] | - (emulator->data.data[write_page * 4 + 1] << 8); - uint8_t orig_block_locks = emulator->data.data[write_page * 4 + 2]; - uint16_t new_locks = page_buff[0] | (page_buff[1] << 8); - uint8_t new_block_locks = page_buff[2]; + if(emulator->data.type == MfUltralightTypeNTAG203) { + // NTAG203 lock bytes are a bit different from the others + uint8_t orig_page_lock_byte = emulator->data.data[write_page * 4]; + uint8_t orig_cnt_lock_byte = emulator->data.data[write_page * 4 + 1]; + uint8_t new_page_lock_byte = page_buff[0]; + uint8_t new_cnt_lock_byte = page_buff[1]; - int block_lock_count; - switch(emulator->data.type) { - case MfUltralightTypeUL21: - block_lock_count = 5; - break; - case MfUltralightTypeNTAG213: - block_lock_count = 6; - break; - case MfUltralightTypeNTAG215: - block_lock_count = 4; - break; - case MfUltralightTypeNTAG216: - case MfUltralightTypeNTAGI2C1K: - case MfUltralightTypeNTAGI2CPlus1K: - block_lock_count = 7; - break; - case MfUltralightTypeNTAGI2C2K: - case MfUltralightTypeNTAGI2CPlus2K: - block_lock_count = 8; - break; - default: - furi_assert(false); - block_lock_count = 0; - break; + if(orig_page_lock_byte & 0x01) // Block lock bits 1-3 + new_page_lock_byte &= ~0x0E; + if(orig_page_lock_byte & 0x10) // Block lock bits 5-7 + new_page_lock_byte &= ~0xE0; + for(uint8_t i = 0; i < 4; ++i) { + if(orig_cnt_lock_byte & (1 << i)) // Block lock counter bit + new_cnt_lock_byte &= ~(1 << (4 + i)); + } + + new_page_lock_byte |= orig_page_lock_byte; + new_cnt_lock_byte |= orig_cnt_lock_byte; + page_buff[0] = new_page_lock_byte; + page_buff[1] = new_cnt_lock_byte; + } else { + uint16_t orig_locks = emulator->data.data[write_page * 4] | + (emulator->data.data[write_page * 4 + 1] << 8); + uint8_t orig_block_locks = emulator->data.data[write_page * 4 + 2]; + uint16_t new_locks = page_buff[0] | (page_buff[1] << 8); + uint8_t new_block_locks = page_buff[2]; + + int block_lock_count; + switch(emulator->data.type) { + case MfUltralightTypeUL21: + block_lock_count = 5; + break; + case MfUltralightTypeNTAG213: + block_lock_count = 6; + break; + case MfUltralightTypeNTAG215: + block_lock_count = 4; + break; + case MfUltralightTypeNTAG216: + case MfUltralightTypeNTAGI2C1K: + case MfUltralightTypeNTAGI2CPlus1K: + block_lock_count = 7; + break; + case MfUltralightTypeNTAGI2C2K: + case MfUltralightTypeNTAGI2CPlus2K: + block_lock_count = 8; + break; + default: + furi_assert(false); + block_lock_count = 0; + break; + } + + for(int i = 0; i < block_lock_count; ++i) { + if(orig_block_locks & (1 << i)) new_locks &= ~(3 << (2 * i)); + } + + new_locks |= orig_locks; + new_block_locks |= orig_block_locks; + + page_buff[0] = new_locks & 0xff; + page_buff[1] = new_locks >> 8; + page_buff[2] = new_block_locks; + if(emulator->data.type >= MfUltralightTypeUL21 && + emulator->data.type <= MfUltralightTypeNTAG216) + page_buff[3] = MF_UL_TEARING_FLAG_DEFAULT; + else + page_buff[3] = 0; } - - for(int i = 0; i < block_lock_count; ++i) { - if(orig_block_locks & (1 << i)) new_locks &= ~(3 << (2 * i)); - } - - new_locks |= orig_locks; - new_block_locks |= orig_block_locks; - - page_buff[0] = new_locks & 0xff; - page_buff[1] = new_locks >> 8; - page_buff[2] = new_block_locks; - if(emulator->data.type >= MfUltralightTypeUL21 && - emulator->data.type <= MfUltralightTypeNTAG216) - page_buff[3] = MF_UL_TEARING_FLAG_DEFAULT; - else - page_buff[3] = 0; } memcpy(&emulator->data.data[write_page * 4], page_buff, 4); @@ -1025,6 +1137,18 @@ void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle) if(emulator->supported_features & MfUltralightSupportSingleCounter) { emulator->read_counter_incremented = false; } + + if(emulator->data.type == MfUltralightTypeNTAG203) { + // Apply lockout if counter ever reached 0xFFFF + if(emulator->data.counter[1] == 0xFFFF) { + emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4] = 0xFF; + emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4 + 1] = 0xFF; + } + // Copy original counter value from data + emulator->data.counter[0] = + emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4] | + (emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4 + 1] << 8); + } } else { if(emulator->config != NULL) { // ACCESS (less CFGLCK) and AUTH0 are updated when reactivated @@ -1034,6 +1158,10 @@ void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle) emulator->config_cache.auth0 = emulator->config->auth0; } } + if(emulator->data.type == MfUltralightTypeNTAG203) { + // Mark counter as dirty + emulator->data.tearing[0] = 0; + } } void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data) { @@ -1077,12 +1205,20 @@ bool mf_ul_prepare_emulation_response( // Check composite commands if(emulator->comp_write_cmd_started) { - // Compatibility write is the only one composit command if(buff_rx_len == 16 * 8) { - mf_ul_emulate_write( - emulator, emulator->comp_write_page_addr, emulator->comp_write_page_addr, buff_rx); - send_ack = true; - command_parsed = true; + if(emulator->data.type == MfUltralightTypeNTAG203 && + emulator->comp_write_page_addr == MF_UL_NTAG203_COUNTER_PAGE) { + send_ack = mf_ul_emulate_ntag203_counter_write(emulator, buff_rx); + command_parsed = send_ack; + } else { + mf_ul_emulate_write( + emulator, + emulator->comp_write_page_addr, + emulator->comp_write_page_addr, + buff_rx); + send_ack = true; + command_parsed = true; + } } emulator->comp_write_cmd_started = false; } else if(emulator->sector_select_cmd_started) { @@ -1099,7 +1235,7 @@ bool mf_ul_prepare_emulation_response( } else if(buff_rx_len >= 8) { uint8_t cmd = buff_rx[0]; if(cmd == MF_UL_GET_VERSION_CMD) { - if(emulator->data.type != MfUltralightTypeUnknown) { + if(emulator->data.type >= MfUltralightTypeUL11) { if(buff_rx_len == 1 * 8) { tx_bytes = sizeof(emulator->data.version); memcpy(buff_tx, &emulator->data.version, tx_bytes); @@ -1409,9 +1545,15 @@ bool mf_ul_prepare_emulation_response( int16_t tag_addr = mf_ultralight_page_addr_to_tag_addr( emulator->curr_sector, orig_write_page); if(!mf_ul_check_lock(emulator, tag_addr)) break; - mf_ul_emulate_write(emulator, tag_addr, write_page, &buff_rx[2]); - send_ack = true; - command_parsed = true; + if(emulator->data.type == MfUltralightTypeNTAG203 && + orig_write_page == MF_UL_NTAG203_COUNTER_PAGE) { + send_ack = mf_ul_emulate_ntag203_counter_write(emulator, &buff_rx[2]); + command_parsed = send_ack; + } else { + mf_ul_emulate_write(emulator, tag_addr, write_page, &buff_rx[2]); + send_ack = true; + command_parsed = true; + } } while(false); } } else if(cmd == MF_UL_FAST_WRITE) { @@ -1590,7 +1732,8 @@ bool mf_ul_prepare_emulation_response( } } } else { - reset_idle = true; + // NTAG203 appears to NAK instead of just falling off on invalid commands + if(emulator->data.type != MfUltralightTypeNTAG203) reset_idle = true; FURI_LOG_D(TAG, "Received invalid command"); } } else { diff --git a/lib/nfc_protocols/mifare_ultralight.h b/lib/nfc_protocols/mifare_ultralight.h index 36b81fdf1..77dbd1e4e 100644 --- a/lib/nfc_protocols/mifare_ultralight.h +++ b/lib/nfc_protocols/mifare_ultralight.h @@ -26,15 +26,23 @@ #define MF_UL_NAK_INVALID_ARGUMENT (0x0) #define MF_UL_NAK_AUTHLIM_REACHED (0x4) +#define MF_UL_NTAG203_COUNTER_PAGE (41) + +// Important: order matters; some features are based on positioning in this enum typedef enum { MfUltralightTypeUnknown, + MfUltralightTypeNTAG203, + // Below have config pages and GET_VERSION support MfUltralightTypeUL11, MfUltralightTypeUL21, MfUltralightTypeNTAG213, MfUltralightTypeNTAG215, MfUltralightTypeNTAG216, + // Below also have sector select + // NTAG I2C's *does not* have regular config pages, so it's a bit of an odd duck MfUltralightTypeNTAGI2C1K, MfUltralightTypeNTAGI2C2K, + // NTAG I2C Plus has stucture expected from NTAG21x MfUltralightTypeNTAGI2CPlus1K, MfUltralightTypeNTAGI2CPlus2K, @@ -58,6 +66,8 @@ typedef enum { MfUltralightSupportSingleCounter = 1 << 10, // ASCII mirror is not a command, but handy to have as a flag MfUltralightSupportAsciiMirror = 1 << 11, + // NTAG203 counter that's in memory rather than through a command + MfUltralightSupportCounterInMemory = 1 << 12, } MfUltralightFeatures; typedef enum { @@ -173,6 +183,11 @@ bool mf_ultralight_read_version( MfUltralightReader* reader, MfUltralightData* data); +bool mf_ultralight_read_pages_direct( + FuriHalNfcTxRxContext* tx_rx, + uint8_t start_index, + uint8_t* data); + bool mf_ultralight_read_pages( FuriHalNfcTxRxContext* tx_rx, MfUltralightReader* reader, From cd77b93f26fd05996dc0a2381eaf23c37ef5e394 Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Mon, 25 Jul 2022 08:36:38 -0700 Subject: [PATCH 9/9] Picopass: dump full card, extract some details (#1408) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Dump entire picopass card * Capture more iClass details * facility code bugfix Co-authored-by: あく --- applications/picopass/picopass_device.c | 60 +++++++++++-------- applications/picopass/picopass_device.h | 14 ++++- applications/picopass/picopass_worker.c | 54 ++++++++++------- .../scenes/picopass_scene_read_card_success.c | 13 ++-- lib/ST25RFAL002/include/rfal_picopass.h | 4 -- 5 files changed, 88 insertions(+), 57 deletions(-) diff --git a/applications/picopass/picopass_device.c b/applications/picopass/picopass_device.c index 8cce52880..75d9e2907 100644 --- a/applications/picopass/picopass_device.c +++ b/applications/picopass/picopass_device.c @@ -10,6 +10,9 @@ static const uint32_t picopass_file_version = 1; PicopassDevice* picopass_device_alloc() { PicopassDevice* picopass_dev = malloc(sizeof(PicopassDevice)); + picopass_dev->dev_data.pacs.legacy = false; + picopass_dev->dev_data.pacs.se_enabled = false; + picopass_dev->dev_data.pacs.pin_length = 0; picopass_dev->storage = furi_record_open("storage"); picopass_dev->dialogs = furi_record_open("dialogs"); return picopass_dev; @@ -32,7 +35,7 @@ static bool picopass_device_save_file( bool saved = false; FlipperFormat* file = flipper_format_file_alloc(dev->storage); PicopassPacs* pacs = &dev->dev_data.pacs; - ApplicationArea* AA1 = &dev->dev_data.AA1; + PicopassBlock* AA1 = dev->dev_data.AA1; string_t temp_str; string_init(temp_str); @@ -54,40 +57,40 @@ static bool picopass_device_save_file( if(!flipper_format_file_open_always(file, string_get_cstr(temp_str))) break; if(dev->format == PicopassDeviceSaveFormatHF) { + uint32_t fc = pacs->record.FacilityCode; + uint32_t cn = pacs->record.CardNumber; // Write header if(!flipper_format_write_header_cstr(file, picopass_file_header, picopass_file_version)) break; if(pacs->record.valid) { - if(!flipper_format_write_uint32( - file, "Facility Code", (uint32_t*)&pacs->record.FacilityCode, 1)) - break; - if(!flipper_format_write_uint32( - file, "Card Number", (uint32_t*)&pacs->record.CardNumber, 1)) - break; + if(!flipper_format_write_uint32(file, "Facility Code", &fc, 1)) break; + if(!flipper_format_write_uint32(file, "Card Number", &cn, 1)) break; if(!flipper_format_write_hex( file, "Credential", pacs->credential, PICOPASS_BLOCK_LEN)) break; - if(!flipper_format_write_hex(file, "PIN", pacs->pin0, PICOPASS_BLOCK_LEN)) break; - if(!flipper_format_write_hex(file, "PIN(cont.)", pacs->pin1, PICOPASS_BLOCK_LEN)) - break; - - if(!flipper_format_write_comment_cstr(file, "Picopass blocks")) break; - // TODO: Save CSN, CFG, AA1, etc - bool block_saved = true; - for(size_t i = 0; i < 4; i++) { - string_printf(temp_str, "Block %d", i + 6); - if(!flipper_format_write_hex( - file, - string_get_cstr(temp_str), - AA1->block[i].data, - PICOPASS_BLOCK_LEN)) { - block_saved = false; + if(pacs->pin_length > 0) { + if(!flipper_format_write_hex(file, "PIN\t\t", pacs->pin0, PICOPASS_BLOCK_LEN)) + break; + if(!flipper_format_write_hex( + file, "PIN(cont.)\t", pacs->pin1, PICOPASS_BLOCK_LEN)) break; - } } - if(!block_saved) break; - if(!flipper_format_write_comment_cstr(file, "This is currently incomplete")) break; } + if(!flipper_format_write_comment_cstr(file, "Picopass blocks")) break; + bool block_saved = true; + + size_t app_limit = AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0] < PICOPASS_MAX_APP_LIMIT ? + AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0] : + PICOPASS_MAX_APP_LIMIT; + for(size_t i = 0; i < app_limit; i++) { + string_printf(temp_str, "Block %d", i); + if(!flipper_format_write_hex( + file, string_get_cstr(temp_str), AA1[i].data, PICOPASS_BLOCK_LEN)) { + block_saved = false; + break; + } + } + if(!block_saved) break; } else if(dev->format == PicopassDeviceSaveFormatLF) { const char* lf_header = "Flipper RFID key"; // Write header @@ -142,5 +145,10 @@ void picopass_device_free(PicopassDevice* picopass_dev) { } void picopass_device_data_clear(PicopassDeviceData* dev_data) { - memset(&dev_data->AA1, 0, sizeof(ApplicationArea)); + for(size_t i = 0; i < PICOPASS_MAX_APP_LIMIT; i++) { + memset(dev_data->AA1[i].data, 0, sizeof(dev_data->AA1[i].data)); + } + dev_data->pacs.legacy = false; + dev_data->pacs.se_enabled = false; + dev_data->pacs.pin_length = 0; } diff --git a/applications/picopass/picopass_device.h b/applications/picopass/picopass_device.h index a0f7a667e..326e58e66 100644 --- a/applications/picopass/picopass_device.h +++ b/applications/picopass/picopass_device.h @@ -10,6 +10,11 @@ #define PICOPASS_DEV_NAME_MAX_LEN 22 #define PICOPASS_READER_DATA_MAX_SIZE 64 #define PICOPASS_BLOCK_LEN 8 +#define PICOPASS_MAX_APP_LIMIT 32 + +#define PICOPASS_CSN_BLOCK_INDEX 0 +#define PICOPASS_CONFIG_BLOCK_INDEX 1 +#define PICOPASS_AIA_BLOCK_INDEX 5 #define PICOPASS_APP_FOLDER "/any/picopass" #define PICOPASS_APP_EXTENSION ".picopass" @@ -35,7 +40,10 @@ typedef struct { } PicopassWiegandRecord; typedef struct { + bool legacy; + bool se_enabled; bool biometrics; + uint8_t pin_length; PicopassEncryption encryption; uint8_t credential[8]; uint8_t pin0[8]; @@ -44,7 +52,11 @@ typedef struct { } PicopassPacs; typedef struct { - ApplicationArea AA1; + uint8_t data[PICOPASS_BLOCK_LEN]; +} PicopassBlock; + +typedef struct { + PicopassBlock AA1[PICOPASS_MAX_APP_LIMIT]; PicopassPacs pacs; } PicopassDeviceData; diff --git a/applications/picopass/picopass_worker.c b/applications/picopass/picopass_worker.c index 645a1bce9..7ecfbc3be 100644 --- a/applications/picopass/picopass_worker.c +++ b/applications/picopass/picopass_worker.c @@ -55,12 +55,11 @@ static ReturnCode picopass_worker_parse_wiegand(uint8_t* data, PicopassWiegandRe if(record->bitLength == 26) { uint8_t* v4 = data + 4; - v4[0] = 0; - uint32_t bot = v4[3] | (v4[2] << 8) | (v4[1] << 16) | (v4[0] << 24); record->CardNumber = (bot >> 1) & 0xFFFF; record->FacilityCode = (bot >> 17) & 0xFF; + FURI_LOG_D(TAG, "FC:%u CN: %u\n", record->FacilityCode, record->CardNumber); record->valid = true; } else { record->CardNumber = 0; @@ -165,7 +164,7 @@ ReturnCode picopass_detect_card(int timeout) { return ERR_NONE; } -ReturnCode picopass_read_card(ApplicationArea* AA1) { +ReturnCode picopass_read_card(PicopassBlock* AA1) { rfalPicoPassIdentifyRes idRes; rfalPicoPassSelectRes selRes; rfalPicoPassReadCheckRes rcRes; @@ -205,10 +204,20 @@ ReturnCode picopass_read_card(ApplicationArea* AA1) { return err; } - for(size_t i = 0; i < 4; i++) { - FURI_LOG_D(TAG, "rfalPicoPassPollerReadBlock block %d", i + 6); + rfalPicoPassReadBlockRes csn; + err = rfalPicoPassPollerReadBlock(PICOPASS_CSN_BLOCK_INDEX, &csn); + memcpy(AA1[PICOPASS_CSN_BLOCK_INDEX].data, csn.data, sizeof(csn.data)); + + rfalPicoPassReadBlockRes cfg; + err = rfalPicoPassPollerReadBlock(PICOPASS_CONFIG_BLOCK_INDEX, &cfg); + memcpy(AA1[PICOPASS_CONFIG_BLOCK_INDEX].data, cfg.data, sizeof(cfg.data)); + + size_t app_limit = cfg.data[0] < PICOPASS_MAX_APP_LIMIT ? cfg.data[0] : PICOPASS_MAX_APP_LIMIT; + + for(size_t i = 2; i < app_limit; i++) { + FURI_LOG_D(TAG, "rfalPicoPassPollerReadBlock block %d", i); rfalPicoPassReadBlockRes block; - err = rfalPicoPassPollerReadBlock(i + 6, &block); + err = rfalPicoPassPollerReadBlock(i, &block); if(err != ERR_NONE) { FURI_LOG_E(TAG, "rfalPicoPassPollerReadBlock error %d", err); return err; @@ -217,7 +226,7 @@ ReturnCode picopass_read_card(ApplicationArea* AA1) { FURI_LOG_D( TAG, "rfalPicoPassPollerReadBlock %d %02x%02x%02x%02x%02x%02x%02x%02x", - i + 6, + i, block.data[0], block.data[1], block.data[2], @@ -227,7 +236,7 @@ ReturnCode picopass_read_card(ApplicationArea* AA1) { block.data[6], block.data[7]); - memcpy(&(AA1->block[i]), &block, sizeof(block)); + memcpy(AA1[i].data, block.data, sizeof(block.data)); } return ERR_NONE; @@ -251,7 +260,7 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) { picopass_device_data_clear(picopass_worker->dev_data); PicopassDeviceData* dev_data = picopass_worker->dev_data; - ApplicationArea* AA1 = &dev_data->AA1; + PicopassBlock* AA1 = dev_data->AA1; PicopassPacs* pacs = &dev_data->pacs; ReturnCode err; @@ -263,34 +272,39 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) { FURI_LOG_E(TAG, "picopass_read_card error %d", err); } - pacs->biometrics = AA1->block[0].data[4]; - pacs->encryption = AA1->block[0].data[7]; + // Thank you proxmark! + pacs->legacy = (memcmp(AA1[5].data, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0); + pacs->se_enabled = (memcmp(AA1[5].data, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0); - if(pacs->encryption == 0x17) { + pacs->biometrics = AA1[6].data[4]; + pacs->pin_length = AA1[6].data[6] & 0x0F; + pacs->encryption = AA1[6].data[7]; + + if(pacs->encryption == PicopassDeviceEncryption3DES) { FURI_LOG_D(TAG, "3DES Encrypted"); - err = picopass_worker_decrypt(AA1->block[1].data, pacs->credential); + err = picopass_worker_decrypt(AA1[7].data, pacs->credential); if(err != ERR_NONE) { FURI_LOG_E(TAG, "decrypt error %d", err); break; } - err = picopass_worker_decrypt(AA1->block[2].data, pacs->pin0); + err = picopass_worker_decrypt(AA1[8].data, pacs->pin0); if(err != ERR_NONE) { FURI_LOG_E(TAG, "decrypt error %d", err); break; } - err = picopass_worker_decrypt(AA1->block[3].data, pacs->pin1); + err = picopass_worker_decrypt(AA1[9].data, pacs->pin1); if(err != ERR_NONE) { FURI_LOG_E(TAG, "decrypt error %d", err); break; } - } else if(pacs->encryption == 0x14) { + } else if(pacs->encryption == PicopassDeviceEncryptionNone) { FURI_LOG_D(TAG, "No Encryption"); - memcpy(pacs->credential, AA1->block[1].data, RFAL_PICOPASS_MAX_BLOCK_LEN); - memcpy(pacs->pin0, AA1->block[2].data, RFAL_PICOPASS_MAX_BLOCK_LEN); - memcpy(pacs->pin1, AA1->block[3].data, RFAL_PICOPASS_MAX_BLOCK_LEN); - } else if(pacs->encryption == 0x15) { + memcpy(pacs->credential, AA1[7].data, PICOPASS_BLOCK_LEN); + memcpy(pacs->pin0, AA1[8].data, PICOPASS_BLOCK_LEN); + memcpy(pacs->pin1, AA1[9].data, PICOPASS_BLOCK_LEN); + } else if(pacs->encryption == PicopassDeviceEncryptionDES) { FURI_LOG_D(TAG, "DES Encrypted"); } else { FURI_LOG_D(TAG, "Unknown encryption"); diff --git a/applications/picopass/scenes/picopass_scene_read_card_success.c b/applications/picopass/scenes/picopass_scene_read_card_success.c index 96a080310..3866d201c 100644 --- a/applications/picopass/scenes/picopass_scene_read_card_success.c +++ b/applications/picopass/scenes/picopass_scene_read_card_success.c @@ -29,14 +29,17 @@ void picopass_scene_read_card_success_on_enter(void* context) { PicopassPacs* pacs = &picopass->dev->dev_data.pacs; Widget* widget = picopass->widget; + size_t bytesLength = 1 + pacs->record.bitLength / 8; string_set_str(credential_str, ""); - for(uint8_t i = 0; i < RFAL_PICOPASS_MAX_BLOCK_LEN; i++) { + for(uint8_t i = PICOPASS_BLOCK_LEN - bytesLength; i < PICOPASS_BLOCK_LEN; i++) { string_cat_printf(credential_str, " %02X", pacs->credential[i]); } if(pacs->record.valid) { string_cat_printf( - wiegand_str, "FC: %03u CN: %05u", pacs->record.FacilityCode, pacs->record.CardNumber); + wiegand_str, "FC: %u CN: %u", pacs->record.FacilityCode, pacs->record.CardNumber); + } else { + string_cat_printf(wiegand_str, "%d bits", pacs->record.bitLength); } widget_add_button_element( @@ -53,10 +56,8 @@ void picopass_scene_read_card_success_on_enter(void* context) { picopass_scene_read_card_success_widget_callback, picopass); - if(pacs->record.valid) { - widget_add_string_element( - widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, string_get_cstr(wiegand_str)); - } + widget_add_string_element( + widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, string_get_cstr(wiegand_str)); widget_add_string_element( widget, 64, 32, AlignCenter, AlignCenter, FontSecondary, string_get_cstr(credential_str)); diff --git a/lib/ST25RFAL002/include/rfal_picopass.h b/lib/ST25RFAL002/include/rfal_picopass.h index baa8ea6f1..5b8150251 100644 --- a/lib/ST25RFAL002/include/rfal_picopass.h +++ b/lib/ST25RFAL002/include/rfal_picopass.h @@ -51,10 +51,6 @@ typedef struct { uint8_t crc[2]; } rfalPicoPassReadBlockRes; -typedef struct { - rfalPicoPassReadBlockRes block[4]; -} ApplicationArea; - ReturnCode rfalPicoPassPollerInitialize(void); ReturnCode rfalPicoPassPollerCheckPresence(void); ReturnCode rfalPicoPassPollerIdentify(rfalPicoPassIdentifyRes* idRes);