diff --git a/.gitignore b/.gitignore index e33c10125..d6a2dc470 100644 --- a/.gitignore +++ b/.gitignore @@ -30,7 +30,7 @@ bindings/ Brewfile.lock.json # Visual Studio Code -.vscode/ +/.vscode/ # Visual Studio .vs/ diff --git a/applications/debug/uart_echo/application.fam b/applications/debug/uart_echo/application.fam index c4079c6c1..ecdc847cd 100644 --- a/applications/debug/uart_echo/application.fam +++ b/applications/debug/uart_echo/application.fam @@ -1,12 +1,12 @@ App( appid="UART_Echo", name="[GPIO] UART Echo", - apptype=FlipperAppType.EXTERNAL, + apptype=FlipperAppType.DEBUG, entry_point="uart_echo_app", cdefines=["APP_UART_ECHO"], requires=["gui"], stack_size=2 * 1024, order=70, fap_icon="uart_10px.png", - fap_category="GPIO", + fap_category="Debug", ) diff --git a/applications/debug/unit_tests/rpc/rpc_test.c b/applications/debug/unit_tests/rpc/rpc_test.c index 329f3b741..167266a84 100644 --- a/applications/debug/unit_tests/rpc/rpc_test.c +++ b/applications/debug/unit_tests/rpc/rpc_test.c @@ -84,7 +84,7 @@ static void test_rpc_setup(void) { rpc = furi_record_open(RECORD_RPC); for(int i = 0; !(rpc_session[0].session) && (i < 10000); ++i) { - rpc_session[0].session = rpc_session_open(rpc); + rpc_session[0].session = rpc_session_open(rpc, RpcOwnerUnknown); furi_delay_tick(1); } furi_check(rpc_session[0].session); @@ -104,7 +104,7 @@ static void test_rpc_setup_second_session(void) { furi_check(!(rpc_session[1].session)); for(int i = 0; !(rpc_session[1].session) && (i < 10000); ++i) { - rpc_session[1].session = rpc_session_open(rpc); + rpc_session[1].session = rpc_session_open(rpc, RpcOwnerUnknown); furi_delay_tick(1); } furi_check(rpc_session[1].session); diff --git a/applications/external/avr_isp_programmer/helpers/avr_isp.c b/applications/external/avr_isp_programmer/helpers/avr_isp.c index 51b4f8846..283c17bfd 100644 --- a/applications/external/avr_isp_programmer/helpers/avr_isp.c +++ b/applications/external/avr_isp_programmer/helpers/avr_isp.c @@ -152,7 +152,12 @@ bool avr_isp_auto_set_spi_speed_start_pmode(AvrIsp* instance) { } } } - if(instance->spi) avr_isp_spi_sw_free(instance->spi); + + if(instance->spi) { + avr_isp_spi_sw_free(instance->spi); + instance->spi = NULL; + } + return false; } diff --git a/applications/external/avr_isp_programmer/lib/driver/avr_isp_prog.c b/applications/external/avr_isp_programmer/lib/driver/avr_isp_prog.c index b3c81f3b1..0f46872dd 100644 --- a/applications/external/avr_isp_programmer/lib/driver/avr_isp_prog.c +++ b/applications/external/avr_isp_programmer/lib/driver/avr_isp_prog.c @@ -196,7 +196,7 @@ static void avr_isp_prog_set_cfg(AvrIspProg* instance) { instance->cfg->lockbytes = instance->buff[6]; instance->cfg->fusebytes = instance->buff[7]; instance->cfg->flashpoll = instance->buff[8]; - // ignore (instance->buff[9] == instance->buff[8]) //FLASH polling value. Same as “flashpoll” + // ignore (instance->buff[9] == instance->buff[8]) //FLASH polling value. Same as �flashpoll� instance->cfg->eeprompoll = instance->buff[10] << 8 | instance->buff[11]; instance->cfg->pagesize = instance->buff[12] << 8 | instance->buff[13]; instance->cfg->eepromsize = instance->buff[14] << 8 | instance->buff[15]; @@ -317,7 +317,12 @@ static bool avr_isp_prog_auto_set_spi_speed_start_pmode(AvrIspProg* instance) { } } } - if(instance->spi) avr_isp_spi_sw_free(instance->spi); + + if(instance->spi) { + avr_isp_spi_sw_free(instance->spi); + instance->spi = NULL; + } + return false; } diff --git a/applications/external/flipfrid/application.fam b/applications/external/flipfrid/application.fam index e2482e0d1..f66cc7b73 100644 --- a/applications/external/flipfrid/application.fam +++ b/applications/external/flipfrid/application.fam @@ -4,7 +4,7 @@ App( apptype=FlipperAppType.EXTERNAL, entry_point="flipfrid_start", requires=["gui", "storage", "dialogs", "input", "notification"], - stack_size=1 * 1024, + stack_size=2 * 1024, order=180, fap_icon="rfid_10px.png", fap_category="Tools", diff --git a/applications/external/flipfrid/flipfrid.c b/applications/external/flipfrid/flipfrid.c index ff52ab160..25bdac024 100644 --- a/applications/external/flipfrid/flipfrid.c +++ b/applications/external/flipfrid/flipfrid.c @@ -61,6 +61,16 @@ FlipFridState* flipfrid_alloc() { flipfrid->proto_name = furi_string_alloc(); flipfrid->data_str = furi_string_alloc(); + flipfrid->main_menu_items[0] = furi_string_alloc_set("Default Values"); + flipfrid->main_menu_items[1] = furi_string_alloc_set("BF Customer ID"); + flipfrid->main_menu_items[2] = furi_string_alloc_set("Load File"); + flipfrid->main_menu_items[3] = furi_string_alloc_set("Load UIDs from file"); + + flipfrid->main_menu_proto_items[0] = furi_string_alloc_set("EM4100"); + flipfrid->main_menu_proto_items[1] = furi_string_alloc_set("HIDProx"); + flipfrid->main_menu_proto_items[2] = furi_string_alloc_set("PAC/Stanley"); + flipfrid->main_menu_proto_items[3] = furi_string_alloc_set("H10301"); + flipfrid->previous_scene = NoneScene; flipfrid->current_scene = SceneEntryPoint; flipfrid->is_running = true; @@ -103,6 +113,14 @@ void flipfrid_free(FlipFridState* flipfrid) { furi_string_free(flipfrid->proto_name); furi_string_free(flipfrid->data_str); + for(uint32_t i = 0; i < 4; i++) { + furi_string_free(flipfrid->main_menu_items[i]); + } + + for(uint32_t i = 0; i < 4; i++) { + furi_string_free(flipfrid->main_menu_proto_items[i]); + } + free(flipfrid->data); free(flipfrid->payload); diff --git a/applications/external/flipfrid/flipfrid.h b/applications/external/flipfrid/flipfrid.h index e4122054b..0ee8aa320 100644 --- a/applications/external/flipfrid/flipfrid.h +++ b/applications/external/flipfrid/flipfrid.h @@ -75,6 +75,8 @@ typedef struct { FlipFridProtos proto; FuriString* attack_name; FuriString* proto_name; + FuriString* main_menu_items[4]; + FuriString* main_menu_proto_items[4]; DialogsApp* dialogs; FuriString* notification_msg; diff --git a/applications/external/flipfrid/scene/flipfrid_scene_entrypoint.c b/applications/external/flipfrid/scene/flipfrid_scene_entrypoint.c index 24c19dc4c..f4b39aa66 100644 --- a/applications/external/flipfrid/scene/flipfrid_scene_entrypoint.c +++ b/applications/external/flipfrid/scene/flipfrid_scene_entrypoint.c @@ -1,8 +1,5 @@ #include "flipfrid_scene_entrypoint.h" -FuriString* main_menu_items[4]; -FuriString* main_menu_proto_items[4]; - void flipfrid_scene_entrypoint_menu_callback( FlipFridState* context, uint32_t index, @@ -68,31 +65,14 @@ void flipfrid_scene_entrypoint_on_enter(FlipFridState* context) { menu_items[i] = furi_string_alloc(); }*/ - main_menu_items[0] = furi_string_alloc_set("Default Values"); - main_menu_items[1] = furi_string_alloc_set("BF Customer ID"); - main_menu_items[2] = furi_string_alloc_set("Load File"); - main_menu_items[3] = furi_string_alloc_set("Load UIDs from file"); - context->menu_proto_index = 0; /*for(uint32_t i = 0; i < 4; i++) { menu_proto_items[i] = furi_string_alloc(); }*/ - - main_menu_proto_items[0] = furi_string_alloc_set("EM4100"); - main_menu_proto_items[1] = furi_string_alloc_set("HIDProx"); - main_menu_proto_items[2] = furi_string_alloc_set("PAC/Stanley"); - main_menu_proto_items[3] = furi_string_alloc_set("H10301"); } void flipfrid_scene_entrypoint_on_exit(FlipFridState* context) { UNUSED(context); - for(uint32_t i = 0; i < 4; i++) { - furi_string_free(main_menu_items[i]); - } - - for(uint32_t i = 0; i < 4; i++) { - furi_string_free(main_menu_proto_items[i]); - } } void flipfrid_scene_entrypoint_on_tick(FlipFridState* context) { @@ -145,73 +125,77 @@ void flipfrid_scene_entrypoint_on_draw(Canvas* canvas, FlipFridState* context) { canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); - if(main_menu_items[context->menu_index] != NULL) { - if(context->menu_index > FlipFridAttackDefaultValues) { - canvas_set_font(canvas, FontSecondary); + if(context->main_menu_items != NULL) { + if(context->main_menu_items[context->menu_index] != NULL) { + if(context->menu_index > FlipFridAttackDefaultValues) { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned( + canvas, + 64, + 24, + AlignCenter, + AlignTop, + furi_string_get_cstr(context->main_menu_items[context->menu_index - 1])); + } + + canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned( canvas, 64, - 24, + 36, AlignCenter, AlignTop, - furi_string_get_cstr(main_menu_items[context->menu_index - 1])); - } + furi_string_get_cstr(context->main_menu_items[context->menu_index])); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned( - canvas, - 64, - 36, - AlignCenter, - AlignTop, - furi_string_get_cstr(main_menu_items[context->menu_index])); + if(context->menu_index < FlipFridAttackLoadFileCustomUids) { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned( + canvas, + 64, + 48, + AlignCenter, + AlignTop, + furi_string_get_cstr(context->main_menu_items[context->menu_index + 1])); + } - if(context->menu_index < FlipFridAttackLoadFileCustomUids) { - canvas_set_font(canvas, FontSecondary); + if(context->menu_proto_index > EM4100) { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned( + canvas, + 64, + -12, + AlignCenter, + AlignTop, + furi_string_get_cstr( + context->main_menu_proto_items[context->menu_proto_index - 1])); + } + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 27, 4, AlignCenter, AlignTop, "<"); + + canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned( canvas, 64, - 48, + 4, AlignCenter, AlignTop, - furi_string_get_cstr(main_menu_items[context->menu_index + 1])); - } + furi_string_get_cstr(context->main_menu_proto_items[context->menu_proto_index])); - if(context->menu_proto_index > EM4100) { - canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned( - canvas, - 64, - -12, - AlignCenter, - AlignTop, - furi_string_get_cstr(main_menu_proto_items[context->menu_proto_index - 1])); - } + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 101, 4, AlignCenter, AlignTop, ">"); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 27, 4, AlignCenter, AlignTop, "<"); - - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned( - canvas, - 64, - 4, - AlignCenter, - AlignTop, - furi_string_get_cstr(main_menu_proto_items[context->menu_proto_index])); - - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 101, 4, AlignCenter, AlignTop, ">"); - - if(context->menu_proto_index < H10301) { - canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned( - canvas, - 64, - -12, - AlignCenter, - AlignTop, - furi_string_get_cstr(main_menu_proto_items[context->menu_proto_index + 1])); + if(context->menu_proto_index < H10301) { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned( + canvas, + 64, + -12, + AlignCenter, + AlignTop, + furi_string_get_cstr( + context->main_menu_proto_items[context->menu_proto_index + 1])); + } } } } \ No newline at end of file diff --git a/applications/external/gps_nmea_uart/gps.c b/applications/external/gps_nmea_uart/gps.c index 0f4a7a1d5..a0c6ead03 100644 --- a/applications/external/gps_nmea_uart/gps.c +++ b/applications/external/gps_nmea_uart/gps.c @@ -139,20 +139,14 @@ int32_t gps_app(void* p) { switch(event.input.key) { case InputKeyUp: gps_uart_deinit_thread(gps_uart); - switch(gps_uart->baudrate) { - case GPS_BAUDRATE_9k: - gps_uart->baudrate = GPS_BAUDRATE_57k; - break; - case GPS_BAUDRATE_57k: - gps_uart->baudrate = GPS_BAUDRATE_115k; - break; - case GPS_BAUDRATE_115k: - gps_uart->baudrate = GPS_BAUDRATE_9k; - break; - - default: - break; + const int baudrate_length = + sizeof(gps_baudrates) / sizeof(gps_baudrates[0]); + current_gps_baudrate++; + if(current_gps_baudrate >= baudrate_length) { + current_gps_baudrate = 0; } + gps_uart->baudrate = gps_baudrates[current_gps_baudrate]; + gps_uart_init_thread(gps_uart); gps_uart->changing_baudrate = true; view_port_update(view_port); diff --git a/applications/external/gps_nmea_uart/gps_uart.c b/applications/external/gps_nmea_uart/gps_uart.c index 39538b74b..4e66aa284 100644 --- a/applications/external/gps_nmea_uart/gps_uart.c +++ b/applications/external/gps_nmea_uart/gps_uart.c @@ -169,7 +169,7 @@ GpsUart* gps_uart_enable() { gps_uart->notifications = furi_record_open(RECORD_NOTIFICATION); - gps_uart->baudrate = GPS_BAUDRATE_57k; + gps_uart->baudrate = gps_baudrates[current_gps_baudrate]; gps_uart_init_thread(gps_uart); diff --git a/applications/external/gps_nmea_uart/gps_uart.h b/applications/external/gps_nmea_uart/gps_uart.h index 5a42b9c58..152f4cd7f 100644 --- a/applications/external/gps_nmea_uart/gps_uart.h +++ b/applications/external/gps_nmea_uart/gps_uart.h @@ -3,11 +3,11 @@ #include #include -#define GPS_BAUDRATE_9k 9600 -#define GPS_BAUDRATE_57k 57600 -#define GPS_BAUDRATE_115k 115200 #define RX_BUF_SIZE 1024 +static const int gps_baudrates[5] = {9600, 19200, 38400, 57600, 115200}; +static int current_gps_baudrate = 3; + typedef struct { bool valid; float latitude; diff --git a/applications/external/hid_app/assets/Pause_icon_9x9.png b/applications/external/hid_app/assets/Pause_icon_9x9.png new file mode 100644 index 000000000..d72d712bb Binary files /dev/null and b/applications/external/hid_app/assets/Pause_icon_9x9.png differ diff --git a/applications/external/hid_app/hid.c b/applications/external/hid_app/hid.c index 949ff63b3..c86def18f 100644 --- a/applications/external/hid_app/hid.c +++ b/applications/external/hid_app/hid.c @@ -7,9 +7,11 @@ enum HidDebugSubmenuIndex { HidSubmenuIndexKeynote, + HidSubmenuIndexKeynoteVertical, HidSubmenuIndexKeyboard, HidSubmenuIndexMedia, HidSubmenuIndexTikTok, + HidSubmenuIndexYTShorts, HidSubmenuIndexMouse, HidSubmenuIndexMouseJiggler, }; @@ -20,6 +22,9 @@ static void hid_submenu_callback(void* context, uint32_t index) { if(index == HidSubmenuIndexKeynote) { app->view_id = HidViewKeynote; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewKeynote); + } else if(index == HidSubmenuIndexKeynoteVertical) { + app->view_id = HidViewKeynoteVertical; + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewKeynoteVertical); } else if(index == HidSubmenuIndexKeyboard) { app->view_id = HidViewKeyboard; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewKeyboard); @@ -32,6 +37,9 @@ static void hid_submenu_callback(void* context, uint32_t index) { } else if(index == HidSubmenuIndexTikTok) { app->view_id = BtHidViewTikTok; view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewTikTok); + } else if(index == HidSubmenuIndexYTShorts) { + app->view_id = BtHidViewYTShorts; + view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewYTShorts); } else if(index == HidSubmenuIndexMouseJiggler) { app->view_id = HidViewMouseJiggler; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseJiggler); @@ -50,11 +58,13 @@ static void bt_hid_connection_status_changed_callback(BtStatus status, void* con } } hid_keynote_set_connected_status(hid->hid_keynote, connected); + hid_keynote_vertical_set_connected_status(hid->hid_keynote_vertical, connected); hid_keyboard_set_connected_status(hid->hid_keyboard, connected); hid_media_set_connected_status(hid->hid_media, connected); hid_mouse_set_connected_status(hid->hid_mouse, connected); hid_mouse_jiggler_set_connected_status(hid->hid_mouse_jiggler, connected); hid_tiktok_set_connected_status(hid->hid_tiktok, connected); + hid_ytshorts_set_connected_status(hid->hid_ytshorts, connected); } static void hid_dialog_callback(DialogExResult result, void* context) { @@ -100,6 +110,12 @@ Hid* hid_alloc(HidTransport transport) { app->device_type_submenu = submenu_alloc(); submenu_add_item( app->device_type_submenu, "Keynote", HidSubmenuIndexKeynote, hid_submenu_callback, app); + submenu_add_item( + app->device_type_submenu, + "Keynote Vertical", + HidSubmenuIndexKeynoteVertical, + hid_submenu_callback, + app); submenu_add_item( app->device_type_submenu, "Keyboard", HidSubmenuIndexKeyboard, hid_submenu_callback, app); submenu_add_item( @@ -113,6 +129,12 @@ Hid* hid_alloc(HidTransport transport) { HidSubmenuIndexTikTok, hid_submenu_callback, app); + submenu_add_item( + app->device_type_submenu, + "[Beta]YT Shorts Controller", + HidSubmenuIndexYTShorts, + hid_submenu_callback, + app); } submenu_add_item( app->device_type_submenu, @@ -148,6 +170,15 @@ Hid* hid_app_alloc_view(void* context) { view_dispatcher_add_view( app->view_dispatcher, HidViewKeynote, hid_keynote_get_view(app->hid_keynote)); + // Keynote Vertical view + app->hid_keynote_vertical = hid_keynote_vertical_alloc(app); + view_set_previous_callback( + hid_keynote_vertical_get_view(app->hid_keynote_vertical), hid_exit_confirm_view); + view_dispatcher_add_view( + app->view_dispatcher, + HidViewKeynoteVertical, + hid_keynote_vertical_get_view(app->hid_keynote_vertical)); + // Keyboard view app->hid_keyboard = hid_keyboard_alloc(app); view_set_previous_callback(hid_keyboard_get_view(app->hid_keyboard), hid_exit_confirm_view); @@ -166,6 +197,12 @@ Hid* hid_app_alloc_view(void* context) { view_dispatcher_add_view( app->view_dispatcher, BtHidViewTikTok, hid_tiktok_get_view(app->hid_tiktok)); + // YTShorts view + app->hid_ytshorts = hid_ytshorts_alloc(app); + view_set_previous_callback(hid_ytshorts_get_view(app->hid_ytshorts), hid_exit_confirm_view); + view_dispatcher_add_view( + app->view_dispatcher, BtHidViewYTShorts, hid_ytshorts_get_view(app->hid_ytshorts)); + // Mouse view app->hid_mouse = hid_mouse_alloc(app); view_set_previous_callback(hid_mouse_get_view(app->hid_mouse), hid_exit_confirm_view); @@ -199,6 +236,8 @@ void hid_free(Hid* app) { dialog_ex_free(app->dialog); view_dispatcher_remove_view(app->view_dispatcher, HidViewKeynote); hid_keynote_free(app->hid_keynote); + view_dispatcher_remove_view(app->view_dispatcher, HidViewKeynoteVertical); + hid_keynote_vertical_free(app->hid_keynote_vertical); view_dispatcher_remove_view(app->view_dispatcher, HidViewKeyboard); hid_keyboard_free(app->hid_keyboard); view_dispatcher_remove_view(app->view_dispatcher, HidViewMedia); @@ -209,6 +248,8 @@ void hid_free(Hid* app) { hid_mouse_jiggler_free(app->hid_mouse_jiggler); view_dispatcher_remove_view(app->view_dispatcher, BtHidViewTikTok); hid_tiktok_free(app->hid_tiktok); + view_dispatcher_remove_view(app->view_dispatcher, BtHidViewYTShorts); + hid_ytshorts_free(app->hid_ytshorts); view_dispatcher_free(app->view_dispatcher); // Close records diff --git a/applications/external/hid_app/hid.h b/applications/external/hid_app/hid.h index 8ed1664a3..be9176a28 100644 --- a/applications/external/hid_app/hid.h +++ b/applications/external/hid_app/hid.h @@ -17,11 +17,13 @@ #include #include #include "views/hid_keynote.h" +#include "views/hid_keynote_vertical.h" #include "views/hid_keyboard.h" #include "views/hid_media.h" #include "views/hid_mouse.h" #include "views/hid_mouse_jiggler.h" #include "views/hid_tiktok.h" +#include "views/hid_ytshorts.h" #define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys" @@ -40,11 +42,13 @@ struct Hid { Submenu* device_type_submenu; DialogEx* dialog; HidKeynote* hid_keynote; + HidKeynoteVertical* hid_keynote_vertical; HidKeyboard* hid_keyboard; HidMedia* hid_media; HidMouse* hid_mouse; HidMouseJiggler* hid_mouse_jiggler; HidTikTok* hid_tiktok; + HidYTShorts* hid_ytshorts; HidTransport transport; uint32_t view_id; @@ -62,4 +66,4 @@ void hid_hal_mouse_move(Hid* instance, int8_t dx, int8_t dy); void hid_hal_mouse_scroll(Hid* instance, int8_t delta); void hid_hal_mouse_press(Hid* instance, uint16_t event); void hid_hal_mouse_release(Hid* instance, uint16_t event); -void hid_hal_mouse_release_all(Hid* instance); \ No newline at end of file +void hid_hal_mouse_release_all(Hid* instance); diff --git a/applications/external/hid_app/views.h b/applications/external/hid_app/views.h index 2a44832e1..81e8d6dbe 100644 --- a/applications/external/hid_app/views.h +++ b/applications/external/hid_app/views.h @@ -1,10 +1,12 @@ typedef enum { HidViewSubmenu, HidViewKeynote, + HidViewKeynoteVertical, HidViewKeyboard, HidViewMedia, HidViewMouse, HidViewMouseJiggler, BtHidViewTikTok, + BtHidViewYTShorts, HidViewExitConfirm, -} HidView; \ No newline at end of file +} HidView; diff --git a/applications/external/hid_app/views/hid_keynote_vertical.c b/applications/external/hid_app/views/hid_keynote_vertical.c new file mode 100644 index 000000000..7d2303813 --- /dev/null +++ b/applications/external/hid_app/views/hid_keynote_vertical.c @@ -0,0 +1,228 @@ +#include "hid_keynote_vertical.h" +#include +#include "../hid.h" + +#include "hid_icons.h" + +#define TAG "HidKeynoteVertical" + +struct HidKeynoteVertical { + View* view; + Hid* hid; +}; + +typedef struct { + bool left_pressed; + bool up_pressed; + bool right_pressed; + bool down_pressed; + bool ok_pressed; + bool back_pressed; + bool connected; + HidTransport transport; +} HidKeynoteVerticalModel; + +static void + hid_keynote_vertical_draw_arrow(Canvas* canvas, uint8_t x, uint8_t y, CanvasDirection dir) { + canvas_draw_triangle(canvas, x, y, 5, 3, dir); + if(dir == CanvasDirectionBottomToTop) { + canvas_draw_line(canvas, x, y + 6, x, y - 1); + } else if(dir == CanvasDirectionTopToBottom) { + canvas_draw_line(canvas, x, y - 6, x, y + 1); + } else if(dir == CanvasDirectionRightToLeft) { + canvas_draw_line(canvas, x + 6, y, x - 1, y); + } else if(dir == CanvasDirectionLeftToRight) { + canvas_draw_line(canvas, x - 6, y, x + 1, y); + } +} + +static void hid_keynote_vertical_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + HidKeynoteVerticalModel* model = context; + + // Header + if(model->transport == HidTransportBle) { + if(model->connected) { + canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); + } else { + canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); + } + } + + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Keynote"); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text_aligned( + canvas, 24, 14, AlignLeft, AlignTop, "Vertical Up --->"); + + canvas_draw_icon(canvas, 68, 2, &I_Pin_back_arrow_10x8); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text_aligned(canvas, 127, 3, AlignRight, AlignTop, "Hold to exit"); + + // Up + canvas_draw_icon(canvas, 21, 24, &I_Button_18x18); + if(model->up_pressed) { + elements_slightly_rounded_box(canvas, 24, 26, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + hid_keynote_vertical_draw_arrow(canvas, 30, 30, CanvasDirectionBottomToTop); + canvas_set_color(canvas, ColorBlack); + + // Down + canvas_draw_icon(canvas, 21, 45, &I_Button_18x18); + if(model->down_pressed) { + elements_slightly_rounded_box(canvas, 24, 47, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + hid_keynote_vertical_draw_arrow(canvas, 30, 55, CanvasDirectionTopToBottom); + canvas_set_color(canvas, ColorBlack); + + // Left + canvas_draw_icon(canvas, 0, 35, &I_Button_18x18); + if(model->left_pressed) { + elements_slightly_rounded_box(canvas, 3, 37, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + hid_keynote_vertical_draw_arrow(canvas, 7, 43, CanvasDirectionRightToLeft); + canvas_set_color(canvas, ColorBlack); + + // Right + canvas_draw_icon(canvas, 42, 35, &I_Button_18x18); + if(model->right_pressed) { + elements_slightly_rounded_box(canvas, 45, 37, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + hid_keynote_vertical_draw_arrow(canvas, 53, 43, CanvasDirectionLeftToRight); + canvas_set_color(canvas, ColorBlack); + + // Ok + canvas_draw_icon(canvas, 63, 25, &I_Space_65x18); + if(model->ok_pressed) { + elements_slightly_rounded_box(canvas, 66, 27, 60, 13); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 74, 29, &I_Ok_btn_9x9); + elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Space"); + canvas_set_color(canvas, ColorBlack); + + // Back + canvas_draw_icon(canvas, 63, 45, &I_Space_65x18); + if(model->back_pressed) { + elements_slightly_rounded_box(canvas, 66, 47, 60, 13); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 74, 49, &I_Pin_back_arrow_10x8); + elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Back"); +} + +static void + hid_keynote_vertical_process(HidKeynoteVertical* hid_keynote_vertical, InputEvent* event) { + with_view_model( + hid_keynote_vertical->view, + HidKeynoteVerticalModel * model, + { + if(event->type == InputTypePress) { + if(event->key == InputKeyUp) { + model->up_pressed = true; + hid_hal_keyboard_press(hid_keynote_vertical->hid, HID_KEYBOARD_LEFT_ARROW); + } else if(event->key == InputKeyDown) { + model->down_pressed = true; + hid_hal_keyboard_press(hid_keynote_vertical->hid, HID_KEYBOARD_RIGHT_ARROW); + } else if(event->key == InputKeyLeft) { + model->left_pressed = true; + hid_hal_keyboard_press(hid_keynote_vertical->hid, HID_KEYBOARD_DOWN_ARROW); + } else if(event->key == InputKeyRight) { + model->right_pressed = true; + hid_hal_keyboard_press(hid_keynote_vertical->hid, HID_KEYBOARD_UP_ARROW); + } else if(event->key == InputKeyOk) { + model->ok_pressed = true; + hid_hal_keyboard_press(hid_keynote_vertical->hid, HID_KEYBOARD_SPACEBAR); + } else if(event->key == InputKeyBack) { + model->back_pressed = true; + } + } else if(event->type == InputTypeRelease) { + if(event->key == InputKeyUp) { + model->up_pressed = false; + hid_hal_keyboard_release(hid_keynote_vertical->hid, HID_KEYBOARD_LEFT_ARROW); + } else if(event->key == InputKeyDown) { + model->down_pressed = false; + hid_hal_keyboard_release(hid_keynote_vertical->hid, HID_KEYBOARD_RIGHT_ARROW); + } else if(event->key == InputKeyLeft) { + model->left_pressed = false; + hid_hal_keyboard_release(hid_keynote_vertical->hid, HID_KEYBOARD_DOWN_ARROW); + } else if(event->key == InputKeyRight) { + model->right_pressed = false; + hid_hal_keyboard_release(hid_keynote_vertical->hid, HID_KEYBOARD_UP_ARROW); + } else if(event->key == InputKeyOk) { + model->ok_pressed = false; + hid_hal_keyboard_release(hid_keynote_vertical->hid, HID_KEYBOARD_SPACEBAR); + } else if(event->key == InputKeyBack) { + model->back_pressed = false; + } + } else if(event->type == InputTypeShort) { + if(event->key == InputKeyBack) { + hid_hal_keyboard_press(hid_keynote_vertical->hid, HID_KEYBOARD_DELETE); + hid_hal_keyboard_release(hid_keynote_vertical->hid, HID_KEYBOARD_DELETE); + hid_hal_consumer_key_press(hid_keynote_vertical->hid, HID_CONSUMER_AC_BACK); + hid_hal_consumer_key_release(hid_keynote_vertical->hid, HID_CONSUMER_AC_BACK); + } + } + }, + true); +} + +static bool hid_keynote_vertical_input_callback(InputEvent* event, void* context) { + furi_assert(context); + HidKeynoteVertical* hid_keynote_vertical = context; + bool consumed = false; + + if(event->type == InputTypeLong && event->key == InputKeyBack) { + hid_hal_keyboard_release_all(hid_keynote_vertical->hid); + } else { + hid_keynote_vertical_process(hid_keynote_vertical, event); + consumed = true; + } + + return consumed; +} + +HidKeynoteVertical* hid_keynote_vertical_alloc(Hid* hid) { + HidKeynoteVertical* hid_keynote_vertical = malloc(sizeof(HidKeynoteVertical)); + hid_keynote_vertical->view = view_alloc(); + hid_keynote_vertical->hid = hid; + view_set_context(hid_keynote_vertical->view, hid_keynote_vertical); + view_allocate_model( + hid_keynote_vertical->view, ViewModelTypeLocking, sizeof(HidKeynoteVerticalModel)); + view_set_draw_callback(hid_keynote_vertical->view, hid_keynote_vertical_draw_callback); + view_set_input_callback(hid_keynote_vertical->view, hid_keynote_vertical_input_callback); + + with_view_model( + hid_keynote_vertical->view, + HidKeynoteVerticalModel * model, + { model->transport = hid->transport; }, + true); + + return hid_keynote_vertical; +} + +void hid_keynote_vertical_free(HidKeynoteVertical* hid_keynote_vertical) { + furi_assert(hid_keynote_vertical); + view_free(hid_keynote_vertical->view); + free(hid_keynote_vertical); +} + +View* hid_keynote_vertical_get_view(HidKeynoteVertical* hid_keynote_vertical) { + furi_assert(hid_keynote_vertical); + return hid_keynote_vertical->view; +} + +void hid_keynote_vertical_set_connected_status( + HidKeynoteVertical* hid_keynote_vertical, + bool connected) { + furi_assert(hid_keynote_vertical); + with_view_model( + hid_keynote_vertical->view, + HidKeynoteVerticalModel * model, + { model->connected = connected; }, + true); +} diff --git a/applications/external/hid_app/views/hid_keynote_vertical.h b/applications/external/hid_app/views/hid_keynote_vertical.h new file mode 100644 index 000000000..bb7134adb --- /dev/null +++ b/applications/external/hid_app/views/hid_keynote_vertical.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +typedef struct Hid Hid; +typedef struct HidKeynoteVertical HidKeynoteVertical; + +HidKeynoteVertical* hid_keynote_vertical_alloc(Hid* bt_hid); + +void hid_keynote_vertical_free(HidKeynoteVertical* hid_keynote_vertical); + +View* hid_keynote_vertical_get_view(HidKeynoteVertical* hid_keynote_vertical); + +void hid_keynote_vertical_set_connected_status( + HidKeynoteVertical* hid_keynote_vertical, + bool connected); diff --git a/applications/external/hid_app/views/hid_mouse.c b/applications/external/hid_app/views/hid_mouse.c index 30a9d9d06..ca299c463 100644 --- a/applications/external/hid_app/views/hid_mouse.c +++ b/applications/external/hid_app/views/hid_mouse.c @@ -93,17 +93,23 @@ static void hid_mouse_draw_callback(Canvas* canvas, void* context) { // Ok if(model->left_mouse_pressed) { - canvas_draw_icon(canvas, 81, 25, &I_Ok_btn_pressed_13x13); - } else { - canvas_draw_icon(canvas, 83, 27, &I_Left_mouse_icon_9x9); + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 81, 25, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); } + canvas_draw_icon(canvas, 83, 27, &I_Left_mouse_icon_9x9); + canvas_set_color(canvas, ColorBlack); // Back if(model->right_mouse_pressed) { - canvas_draw_icon(canvas, 108, 48, &I_Ok_btn_pressed_13x13); - } else { - canvas_draw_icon(canvas, 110, 50, &I_Right_mouse_icon_9x9); + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 108, 48, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); } + canvas_draw_icon(canvas, 110, 50, &I_Right_mouse_icon_9x9); + canvas_set_color(canvas, ColorBlack); } static void hid_mouse_process(HidMouse* hid_mouse, InputEvent* event) { diff --git a/applications/external/hid_app/views/hid_tiktok.c b/applications/external/hid_app/views/hid_tiktok.c index e1f9f4bed..9b15d812b 100644 --- a/applications/external/hid_app/views/hid_tiktok.c +++ b/applications/external/hid_app/views/hid_tiktok.c @@ -19,6 +19,7 @@ typedef struct { bool ok_pressed; bool connected; bool is_cursor_set; + bool back_mouse_pressed; HidTransport transport; } HidTikTokModel; @@ -40,53 +41,63 @@ static void hid_tiktok_draw_callback(Canvas* canvas, void* context) { canvas_set_font(canvas, FontSecondary); // Keypad circles - canvas_draw_icon(canvas, 76, 8, &I_Circles_47x47); + canvas_draw_icon(canvas, 66, 8, &I_Circles_47x47); + + // Pause + if(model->back_mouse_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 106, 46, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 108, 48, &I_Pause_icon_9x9); + canvas_set_color(canvas, ColorBlack); // Up if(model->up_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 93, 9, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 83, 9, &I_Pressed_Button_13x13); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 96, 11, &I_Arr_up_7x9); + canvas_draw_icon(canvas, 86, 11, &I_Arr_up_7x9); canvas_set_color(canvas, ColorBlack); // Down if(model->down_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 93, 41, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 83, 41, &I_Pressed_Button_13x13); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 96, 44, &I_Arr_dwn_7x9); + canvas_draw_icon(canvas, 86, 44, &I_Arr_dwn_7x9); canvas_set_color(canvas, ColorBlack); // Left if(model->left_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 77, 25, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 67, 25, &I_Pressed_Button_13x13); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 81, 29, &I_Voldwn_6x6); + canvas_draw_icon(canvas, 71, 29, &I_Voldwn_6x6); canvas_set_color(canvas, ColorBlack); // Right if(model->right_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 109, 25, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 99, 25, &I_Pressed_Button_13x13); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 111, 29, &I_Volup_8x6); + canvas_draw_icon(canvas, 101, 29, &I_Volup_8x6); canvas_set_color(canvas, ColorBlack); // Ok if(model->ok_pressed) { - canvas_draw_icon(canvas, 91, 23, &I_Like_pressed_17x17); + canvas_draw_icon(canvas, 81, 23, &I_Like_pressed_17x17); } else { - canvas_draw_icon(canvas, 94, 27, &I_Like_def_11x9); + canvas_draw_icon(canvas, 84, 27, &I_Like_def_11x9); } // Exit canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8); @@ -102,7 +113,8 @@ static void hid_tiktok_reset_cursor(HidTikTok* hid_tiktok) { furi_delay_ms(50); } // Move cursor from the corner - hid_hal_mouse_move(hid_tiktok->hid, 20, 120); + hid_hal_mouse_move(hid_tiktok->hid, 40, 120); + hid_hal_mouse_move(hid_tiktok->hid, 0, 120); furi_delay_ms(50); } @@ -120,6 +132,8 @@ static void hid_hal_consumer_key_press(hid_tiktok->hid, HID_CONSUMER_VOLUME_INCREMENT); } else if(event->key == InputKeyOk) { model->ok_pressed = true; + } else if(event->key == InputKeyBack) { + model->back_mouse_pressed = true; } } @@ -137,6 +151,8 @@ static void hid_hal_consumer_key_release(hid_tiktok->hid, HID_CONSUMER_VOLUME_INCREMENT); } else if(event->key == InputKeyOk) { model->ok_pressed = false; + } else if(event->key == InputKeyBack) { + model->back_mouse_pressed = false; } } @@ -162,31 +178,26 @@ static bool hid_tiktok_input_callback(InputEvent* event, void* context) { } else if(event->type == InputTypeShort) { if(event->key == InputKeyOk) { hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); - furi_delay_ms(50); + furi_delay_ms(25); hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); - furi_delay_ms(50); + furi_delay_ms(100); hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); - furi_delay_ms(50); + furi_delay_ms(25); hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); consumed = true; - } else if(event->key == InputKeyUp) { - // Emulate up swipe - hid_hal_mouse_scroll(hid_tiktok->hid, -6); - hid_hal_mouse_scroll(hid_tiktok->hid, -12); - hid_hal_mouse_scroll(hid_tiktok->hid, -19); - hid_hal_mouse_scroll(hid_tiktok->hid, -12); - hid_hal_mouse_scroll(hid_tiktok->hid, -6); - consumed = true; } else if(event->key == InputKeyDown) { - // Emulate down swipe - hid_hal_mouse_scroll(hid_tiktok->hid, 6); - hid_hal_mouse_scroll(hid_tiktok->hid, 12); + // Swipe to new video hid_hal_mouse_scroll(hid_tiktok->hid, 19); - hid_hal_mouse_scroll(hid_tiktok->hid, 12); - hid_hal_mouse_scroll(hid_tiktok->hid, 6); + consumed = true; + } else if(event->key == InputKeyUp) { + // Swipe to previous video + hid_hal_mouse_scroll(hid_tiktok->hid, -19); consumed = true; } else if(event->key == InputKeyBack) { - hid_hal_consumer_key_release_all(hid_tiktok->hid); + // Pause + hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_RIGHT); + furi_delay_ms(25); + hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_RIGHT); consumed = true; } } else if(event->type == InputTypeLong) { diff --git a/applications/external/hid_app/views/hid_ytshorts.c b/applications/external/hid_app/views/hid_ytshorts.c new file mode 100644 index 000000000..44ad02ff0 --- /dev/null +++ b/applications/external/hid_app/views/hid_ytshorts.c @@ -0,0 +1,268 @@ +#include "hid_ytshorts.h" +#include "../hid.h" +#include + +#include "hid_icons.h" + +#define TAG "HidYTShorts" + +struct HidYTShorts { + View* view; + Hid* hid; +}; + +typedef struct { + bool left_pressed; + bool up_pressed; + bool right_pressed; + bool down_pressed; + bool ok_pressed; + bool connected; + bool is_cursor_set; + bool back_mouse_pressed; + HidTransport transport; +} HidYTShortsModel; + +static void hid_ytshorts_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + HidYTShortsModel* model = context; + + // Header + if(model->transport == HidTransportBle) { + if(model->connected) { + canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); + } else { + canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); + } + } + + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Shorts"); + canvas_set_font(canvas, FontSecondary); + + // Keypad circles + canvas_draw_icon(canvas, 66, 8, &I_Circles_47x47); + + // Pause + if(model->back_mouse_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 106, 46, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 108, 48, &I_Pause_icon_9x9); + canvas_set_color(canvas, ColorBlack); + + // Up + if(model->up_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 83, 9, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 86, 11, &I_Arr_up_7x9); + canvas_set_color(canvas, ColorBlack); + + // Down + if(model->down_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 83, 41, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 86, 44, &I_Arr_dwn_7x9); + canvas_set_color(canvas, ColorBlack); + + // Left + if(model->left_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 67, 25, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 71, 29, &I_Voldwn_6x6); + canvas_set_color(canvas, ColorBlack); + + // Right + if(model->right_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 99, 25, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 101, 29, &I_Volup_8x6); + canvas_set_color(canvas, ColorBlack); + + // Ok + if(model->ok_pressed) { + canvas_draw_icon(canvas, 81, 23, &I_Like_pressed_17x17); + } else { + canvas_draw_icon(canvas, 84, 27, &I_Like_def_11x9); + } + // Exit + canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit"); +} + +static void hid_ytshorts_reset_cursor(HidYTShorts* hid_ytshorts) { + // Set cursor to the phone's left up corner + // Delays to guarantee one packet per connection interval + for(size_t i = 0; i < 8; i++) { + hid_hal_mouse_move(hid_ytshorts->hid, -127, -127); + furi_delay_ms(50); + } + // Move cursor from the corner + hid_hal_mouse_move(hid_ytshorts->hid, 40, 120); + hid_hal_mouse_move(hid_ytshorts->hid, 0, 120); + furi_delay_ms(50); +} + +static void hid_ytshorts_process_press( + HidYTShorts* hid_ytshorts, + HidYTShortsModel* model, + InputEvent* event) { + if(event->key == InputKeyUp) { + model->up_pressed = true; + } else if(event->key == InputKeyDown) { + model->down_pressed = true; + } else if(event->key == InputKeyLeft) { + model->left_pressed = true; + hid_hal_consumer_key_press(hid_ytshorts->hid, HID_CONSUMER_VOLUME_DECREMENT); + } else if(event->key == InputKeyRight) { + model->right_pressed = true; + hid_hal_consumer_key_press(hid_ytshorts->hid, HID_CONSUMER_VOLUME_INCREMENT); + } else if(event->key == InputKeyOk) { + model->ok_pressed = true; + } else if(event->key == InputKeyBack) { + model->back_mouse_pressed = true; + } +} + +static void hid_ytshorts_process_release( + HidYTShorts* hid_ytshorts, + HidYTShortsModel* model, + InputEvent* event) { + if(event->key == InputKeyUp) { + model->up_pressed = false; + } else if(event->key == InputKeyDown) { + model->down_pressed = false; + } else if(event->key == InputKeyLeft) { + model->left_pressed = false; + hid_hal_consumer_key_release(hid_ytshorts->hid, HID_CONSUMER_VOLUME_DECREMENT); + } else if(event->key == InputKeyRight) { + model->right_pressed = false; + hid_hal_consumer_key_release(hid_ytshorts->hid, HID_CONSUMER_VOLUME_INCREMENT); + } else if(event->key == InputKeyOk) { + model->ok_pressed = false; + } else if(event->key == InputKeyBack) { + model->back_mouse_pressed = false; + } +} + +static bool hid_ytshorts_input_callback(InputEvent* event, void* context) { + furi_assert(context); + HidYTShorts* hid_ytshorts = context; + bool consumed = false; + + with_view_model( + hid_ytshorts->view, + HidYTShortsModel * model, + { + if(event->type == InputTypePress) { + hid_ytshorts_process_press(hid_ytshorts, model, event); + if(model->connected && !model->is_cursor_set) { + hid_ytshorts_reset_cursor(hid_ytshorts); + model->is_cursor_set = true; + } + consumed = true; + } else if(event->type == InputTypeRelease) { + hid_ytshorts_process_release(hid_ytshorts, model, event); + consumed = true; + } else if(event->type == InputTypeShort) { + if(event->key == InputKeyOk) { + hid_hal_mouse_press(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT); + furi_delay_ms(50); + hid_hal_mouse_release(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT); + furi_delay_ms(50); + hid_hal_mouse_press(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT); + furi_delay_ms(50); + hid_hal_mouse_release(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT); + consumed = true; + } else if(event->key == InputKeyDown) { + // Swipe to new video + hid_hal_mouse_scroll(hid_ytshorts->hid, 6); + hid_hal_mouse_scroll(hid_ytshorts->hid, 8); + hid_hal_mouse_scroll(hid_ytshorts->hid, 10); + hid_hal_mouse_scroll(hid_ytshorts->hid, 8); + hid_hal_mouse_scroll(hid_ytshorts->hid, 6); + consumed = true; + } else if(event->key == InputKeyUp) { + // Swipe to previous video + hid_hal_mouse_scroll(hid_ytshorts->hid, -6); + hid_hal_mouse_scroll(hid_ytshorts->hid, -8); + hid_hal_mouse_scroll(hid_ytshorts->hid, -10); + hid_hal_mouse_scroll(hid_ytshorts->hid, -8); + hid_hal_mouse_scroll(hid_ytshorts->hid, -6); + consumed = true; + } else if(event->key == InputKeyBack) { + // Pause + hid_hal_mouse_press(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT); + furi_delay_ms(50); + hid_hal_mouse_release(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT); + furi_delay_ms(50); + consumed = true; + } + } else if(event->type == InputTypeLong) { + if(event->key == InputKeyBack) { + hid_hal_consumer_key_release_all(hid_ytshorts->hid); + model->is_cursor_set = false; + consumed = false; + } + } + }, + true); + + return consumed; +} + +HidYTShorts* hid_ytshorts_alloc(Hid* bt_hid) { + HidYTShorts* hid_ytshorts = malloc(sizeof(HidYTShorts)); + hid_ytshorts->hid = bt_hid; + hid_ytshorts->view = view_alloc(); + view_set_context(hid_ytshorts->view, hid_ytshorts); + view_allocate_model(hid_ytshorts->view, ViewModelTypeLocking, sizeof(HidYTShortsModel)); + view_set_draw_callback(hid_ytshorts->view, hid_ytshorts_draw_callback); + view_set_input_callback(hid_ytshorts->view, hid_ytshorts_input_callback); + + with_view_model( + hid_ytshorts->view, + HidYTShortsModel * model, + { model->transport = bt_hid->transport; }, + true); + + return hid_ytshorts; +} + +void hid_ytshorts_free(HidYTShorts* hid_ytshorts) { + furi_assert(hid_ytshorts); + view_free(hid_ytshorts->view); + free(hid_ytshorts); +} + +View* hid_ytshorts_get_view(HidYTShorts* hid_ytshorts) { + furi_assert(hid_ytshorts); + return hid_ytshorts->view; +} + +void hid_ytshorts_set_connected_status(HidYTShorts* hid_ytshorts, bool connected) { + furi_assert(hid_ytshorts); + with_view_model( + hid_ytshorts->view, + HidYTShortsModel * model, + { + model->connected = connected; + model->is_cursor_set = false; + }, + true); +} diff --git a/applications/external/hid_app/views/hid_ytshorts.h b/applications/external/hid_app/views/hid_ytshorts.h new file mode 100644 index 000000000..03264dd36 --- /dev/null +++ b/applications/external/hid_app/views/hid_ytshorts.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +typedef struct Hid Hid; +typedef struct HidYTShorts HidYTShorts; + +HidYTShorts* hid_ytshorts_alloc(Hid* bt_hid); + +void hid_ytshorts_free(HidYTShorts* hid_ytshorts); + +View* hid_ytshorts_get_view(HidYTShorts* hid_ytshorts); + +void hid_ytshorts_set_connected_status(HidYTShorts* hid_ytshorts, bool connected); diff --git a/applications/external/ibtn_fuzzer/ibtnfuzzer.c b/applications/external/ibtn_fuzzer/ibtnfuzzer.c index 04d18886f..880d3983b 100644 --- a/applications/external/ibtn_fuzzer/ibtnfuzzer.c +++ b/applications/external/ibtn_fuzzer/ibtnfuzzer.c @@ -59,6 +59,14 @@ iBtnFuzzerState* ibtnfuzzer_alloc() { ibtnfuzzer->proto_name = furi_string_alloc(); ibtnfuzzer->data_str = furi_string_alloc(); + ibtnfuzzer->main_menu_items[0] = furi_string_alloc_set("Default Values"); + ibtnfuzzer->main_menu_items[1] = furi_string_alloc_set("Load File"); + ibtnfuzzer->main_menu_items[2] = furi_string_alloc_set("Load UIDs from file"); + + ibtnfuzzer->main_menu_proto_items[0] = furi_string_alloc_set("DS1990"); + ibtnfuzzer->main_menu_proto_items[1] = furi_string_alloc_set("Metakom"); + ibtnfuzzer->main_menu_proto_items[2] = furi_string_alloc_set("Cyfral"); + ibtnfuzzer->previous_scene = NoneScene; ibtnfuzzer->current_scene = SceneEntryPoint; ibtnfuzzer->is_running = true; @@ -105,6 +113,14 @@ void ibtnfuzzer_free(iBtnFuzzerState* ibtnfuzzer) { furi_string_free(ibtnfuzzer->proto_name); furi_string_free(ibtnfuzzer->data_str); + for(uint32_t i = 0; i < 3; i++) { + furi_string_free(ibtnfuzzer->main_menu_items[i]); + } + + for(uint32_t i = 0; i < 3; i++) { + furi_string_free(ibtnfuzzer->main_menu_proto_items[i]); + } + free(ibtnfuzzer->data); free(ibtnfuzzer->payload); diff --git a/applications/external/ibtn_fuzzer/ibtnfuzzer.h b/applications/external/ibtn_fuzzer/ibtnfuzzer.h index ed42cc541..3a3a1d21f 100644 --- a/applications/external/ibtn_fuzzer/ibtnfuzzer.h +++ b/applications/external/ibtn_fuzzer/ibtnfuzzer.h @@ -73,6 +73,8 @@ typedef struct { iBtnFuzzerProtos proto; FuriString* attack_name; FuriString* proto_name; + FuriString* main_menu_items[3]; + FuriString* main_menu_proto_items[3]; DialogsApp* dialogs; FuriString* notification_msg; diff --git a/applications/external/ibtn_fuzzer/scene/ibtnfuzzer_scene_entrypoint.c b/applications/external/ibtn_fuzzer/scene/ibtnfuzzer_scene_entrypoint.c index 3ea7e49e6..1dd239c3b 100644 --- a/applications/external/ibtn_fuzzer/scene/ibtnfuzzer_scene_entrypoint.c +++ b/applications/external/ibtn_fuzzer/scene/ibtnfuzzer_scene_entrypoint.c @@ -1,8 +1,5 @@ #include "ibtnfuzzer_scene_entrypoint.h" -FuriString* main_menu_items[3]; -FuriString* main_menu_proto_items[3]; - void ibtnfuzzer_scene_entrypoint_menu_callback( iBtnFuzzerState* context, uint32_t index, @@ -61,30 +58,14 @@ void ibtnfuzzer_scene_entrypoint_on_enter(iBtnFuzzerState* context) { menu_items[i] = furi_string_alloc(); }*/ - main_menu_items[0] = furi_string_alloc_set("Default Values"); - main_menu_items[1] = furi_string_alloc_set("Load File"); - main_menu_items[2] = furi_string_alloc_set("Load UIDs from file"); - context->menu_proto_index = 0; /*for(uint32_t i = 0; i < 4; i++) { menu_proto_items[i] = furi_string_alloc(); }*/ - - main_menu_proto_items[0] = furi_string_alloc_set("DS1990"); - main_menu_proto_items[1] = furi_string_alloc_set("Metakom"); - main_menu_proto_items[2] = furi_string_alloc_set("Cyfral"); } void ibtnfuzzer_scene_entrypoint_on_exit(iBtnFuzzerState* context) { context->enter_rerun = false; - - for(uint32_t i = 0; i < 3; i++) { - furi_string_free(main_menu_items[i]); - } - - for(uint32_t i = 0; i < 3; i++) { - furi_string_free(main_menu_proto_items[i]); - } } void ibtnfuzzer_scene_entrypoint_on_tick(iBtnFuzzerState* context) { @@ -142,74 +123,79 @@ void ibtnfuzzer_scene_entrypoint_on_draw(Canvas* canvas, iBtnFuzzerState* contex canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); - if(main_menu_items[context->menu_index] != NULL) { - if(context->menu_index > iBtnFuzzerAttackDefaultValues) { - canvas_set_font(canvas, FontSecondary); + if(context->main_menu_items != NULL) { + if(context->main_menu_items[context->menu_index] != NULL) { + if(context->menu_index > iBtnFuzzerAttackDefaultValues) { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned( + canvas, + 64, + 24, + AlignCenter, + AlignTop, + furi_string_get_cstr(context->main_menu_items[context->menu_index - 1])); + } + + canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned( canvas, 64, - 24, + 36, AlignCenter, AlignTop, - furi_string_get_cstr(main_menu_items[context->menu_index - 1])); - } + furi_string_get_cstr(context->main_menu_items[context->menu_index])); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned( - canvas, - 64, - 36, - AlignCenter, - AlignTop, - furi_string_get_cstr(main_menu_items[context->menu_index])); + if(context->menu_index < iBtnFuzzerAttackLoadFileCustomUids) { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned( + canvas, + 64, + 48, + AlignCenter, + AlignTop, + furi_string_get_cstr(context->main_menu_items[context->menu_index + 1])); + } - if(context->menu_index < iBtnFuzzerAttackLoadFileCustomUids) { - canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned( - canvas, - 64, - 48, - AlignCenter, - AlignTop, - furi_string_get_cstr(main_menu_items[context->menu_index + 1])); - } + if(context->menu_proto_index > DS1990) { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned( + canvas, + 64, + -12, + AlignCenter, + AlignTop, + furi_string_get_cstr( + context->main_menu_proto_items[context->menu_proto_index - 1])); + } - if(context->menu_proto_index > DS1990) { - canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned( - canvas, - 64, - -12, - AlignCenter, - AlignTop, - furi_string_get_cstr(main_menu_proto_items[context->menu_proto_index - 1])); - } + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 27, 4, AlignCenter, AlignTop, "<"); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 27, 4, AlignCenter, AlignTop, "<"); + canvas_set_font(canvas, FontPrimary); + if(context->main_menu_proto_items[context->menu_proto_index] != NULL) { + canvas_draw_str_aligned( + canvas, + 64, + 4, + AlignCenter, + AlignTop, + furi_string_get_cstr( + context->main_menu_proto_items[context->menu_proto_index])); + } + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 101, 4, AlignCenter, AlignTop, ">"); - canvas_set_font(canvas, FontPrimary); - if(main_menu_proto_items[context->menu_proto_index] != NULL) { - canvas_draw_str_aligned( - canvas, - 64, - 4, - AlignCenter, - AlignTop, - furi_string_get_cstr(main_menu_proto_items[context->menu_proto_index])); - } - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 101, 4, AlignCenter, AlignTop, ">"); - - if(context->menu_proto_index < Cyfral) { - canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned( - canvas, - 64, - -12, - AlignCenter, - AlignTop, - furi_string_get_cstr(main_menu_proto_items[context->menu_proto_index + 1])); + if(context->menu_proto_index < Cyfral) { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned( + canvas, + 64, + -12, + AlignCenter, + AlignTop, + furi_string_get_cstr( + context->main_menu_proto_items[context->menu_proto_index + 1])); + } } } } \ No newline at end of file diff --git a/applications/external/picopass/picopass_worker.c b/applications/external/picopass/picopass_worker.c index 06d361fb5..5e85e6eda 100644 --- a/applications/external/picopass/picopass_worker.c +++ b/applications/external/picopass/picopass_worker.c @@ -570,7 +570,7 @@ void picopass_worker_elite_dict_attack(PicopassWorker* picopass_worker) { picopass_worker->callback(PicopassWorkerEventFail, picopass_worker->context); break; } - picopass_worker->callback(PicopassWorkerEventSuccess, picopass_worker->context); + picopass_worker->callback(PicopassWorkerEventAborted, picopass_worker->context); break; } @@ -596,6 +596,9 @@ int32_t picopass_worker_task(void* context) { picopass_worker_write_key(picopass_worker); } else if(picopass_worker->state == PicopassWorkerStateEliteDictAttack) { picopass_worker_elite_dict_attack(picopass_worker); + } else if(picopass_worker->state == PicopassWorkerStateStop) { + FURI_LOG_D(TAG, "Worker state stop"); + // no-op } else { FURI_LOG_W(TAG, "Unknown state %d", picopass_worker->state); } diff --git a/applications/external/picopass/scenes/picopass_scene_elite_dict_attack.c b/applications/external/picopass/scenes/picopass_scene_elite_dict_attack.c index c76a8ffae..e6191d5ba 100644 --- a/applications/external/picopass/scenes/picopass_scene_elite_dict_attack.c +++ b/applications/external/picopass/scenes/picopass_scene_elite_dict_attack.c @@ -116,8 +116,7 @@ bool picopass_scene_elite_dict_attack_on_event(void* context, SceneManagerEvent uint32_t state = scene_manager_get_scene_state(picopass->scene_manager, PicopassSceneEliteDictAttack); if(event.type == SceneManagerEventTypeCustom) { - if(event.event == PicopassWorkerEventSuccess || - event.event == PicopassWorkerEventAborted) { + if(event.event == PicopassWorkerEventSuccess) { if(state == DictAttackStateUserDictInProgress || state == DictAttackStateStandardDictInProgress) { picopass_worker_stop(picopass->worker); @@ -127,6 +126,9 @@ bool picopass_scene_elite_dict_attack_on_event(void* context, SceneManagerEvent scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCardSuccess); consumed = true; } + } else if(event.event == PicopassWorkerEventAborted) { + scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCardSuccess); + consumed = true; } else if(event.event == PicopassWorkerEventCardDetected) { dict_attack_set_card_detected(picopass->dict_attack); consumed = true; diff --git a/applications/external/subghz_remote/subghz_remote_app.c b/applications/external/subghz_remote/subghz_remote_app.c index 940968592..a0daddc12 100644 --- a/applications/external/subghz_remote/subghz_remote_app.c +++ b/applications/external/subghz_remote/subghz_remote_app.c @@ -136,7 +136,7 @@ static void cfg_read_file_path( *is_enabled = 0; } else { *text_file_label = extract_filename(furi_string_get_cstr(text_file_path), 16); - FURI_LOG_D(TAG, "%s file: %s", read_key, furi_string_get_cstr(text_file_path)); + //FURI_LOG_D(TAG, "%s file: %s", read_key, furi_string_get_cstr(text_file_path)); *is_enabled = 1; } flipper_format_rewind(fff_file); @@ -155,7 +155,7 @@ static void cfg_read_file_label( if(is_enabled == 1) { *text_file_label = char_to_str((char*)furi_string_get_cstr(temp_label), 16); } - FURI_LOG_D(TAG, "%s label: %s", read_key, *text_file_label); + //FURI_LOG_D(TAG, "%s label: %s", read_key, *text_file_label); } flipper_format_rewind(fff_file); furi_string_free(temp_label); @@ -355,6 +355,10 @@ bool subghz_remote_key_load( bool res = false; + subghz_custom_btn_set(0); + keeloq_reset_original_btn(); + subghz_custom_btns_reset(); + do { // load frequency from file if(!flipper_format_read_uint32(fff_file, "Frequency", &preset->frequency, 1)) { @@ -386,6 +390,10 @@ bool subghz_remote_key_load( FURI_LOG_E(TAG, "Could not read Protocol."); break; } + if(!flipper_format_rewind(fff_data)) { + FURI_LOG_E(TAG, "Rewind error"); + return false; + } if(!furi_string_cmp_str(preset->protocol, "RAW")) { subghz_protocol_raw_gen_fff_data(fff_data, path); @@ -394,10 +402,7 @@ bool subghz_remote_key_load( FURI_LOG_E(TAG, "Unable to insert or update Repeat"); break; } - if(!flipper_format_rewind(fff_data)) { - FURI_LOG_E(TAG, "Rewind error"); - return false; - } + } else { stream_copy_full( flipper_format_get_raw_stream(fff_file), flipper_format_get_raw_stream(fff_data)); @@ -406,10 +411,6 @@ bool subghz_remote_key_load( FURI_LOG_E(TAG, "Unable to insert or update Repeat"); break; } - if(!flipper_format_rewind(fff_data)) { - FURI_LOG_E(TAG, "Rewind error"); - return false; - } } if(!flipper_format_rewind(fff_file)) { @@ -467,7 +468,7 @@ bool subghz_remote_save_protocol_to_file(FlipperFormat* fff_file, const char* de stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS); saved = true; - FURI_LOG_D(TAG, "(save) OK Save"); + //FURI_LOG_D(TAG, "(save) OK Save"); } while(0); furi_string_free(file_dir); furi_record_close(RECORD_STORAGE); @@ -527,7 +528,8 @@ static bool subghz_remote_send_sub(SubGHzRemote* app, FlipperFormat* fff_data) { bool res = false; do { if(!furi_hal_subghz_is_tx_allowed(app->txpreset->frequency)) { - printf( + FURI_LOG_E( + TAG, "In your settings, only reception on this frequency (%lu) is allowed,\r\n" "the actual operation of the subghz remote app is not possible\r\n ", app->txpreset->frequency); @@ -544,7 +546,11 @@ static bool subghz_remote_send_sub(SubGHzRemote* app, FlipperFormat* fff_data) { break; } - subghz_transmitter_deserialize(app->tx_transmitter, fff_data); + if(subghz_transmitter_deserialize(app->tx_transmitter, fff_data) != + SubGhzProtocolStatusOk) { + FURI_LOG_E(TAG, "Deserialize error!"); + break; + } furi_hal_subghz_reset(); furi_hal_subghz_idle(); @@ -575,7 +581,7 @@ static bool subghz_remote_send_sub(SubGHzRemote* app, FlipperFormat* fff_data) { } static void subghz_remote_send_signal(SubGHzRemote* app, Storage* storage, const char* path) { - FURI_LOG_D(TAG, "Sending: %s", path); + //FURI_LOG_D(TAG, "Sending: %s", path); app->tx_file_path = path; @@ -615,7 +621,7 @@ static void subghz_remote_send_signal(SubGHzRemote* app, Storage* storage, const static void subghz_remote_process_signal(SubGHzRemote* app, FuriString* signal) { view_port_update(app->view_port); - FURI_LOG_D(TAG, "signal = %s", furi_string_get_cstr(signal)); + //FURI_LOG_D(TAG, "signal = %s", furi_string_get_cstr(signal)); if(strlen(furi_string_get_cstr(signal)) > 12) { Storage* storage = furi_record_open(RECORD_STORAGE); @@ -745,6 +751,8 @@ void subghz_remote_subghz_alloc(SubGHzRemote* app) { app->environment, EXT_PATH("subghz/assets/came_atomo")); subghz_environment_set_nice_flor_s_rainbow_table_file_name( app->environment, EXT_PATH("subghz/assets/nice_flor_s")); + subghz_environment_set_alutech_at_4n_rainbow_table_file_name( + app->environment, EXT_PATH("subghz/assets/alutech_at_4n")); subghz_environment_set_protocol_registry(app->environment, (void*)&subghz_protocol_registry); app->subghz_receiver = subghz_receiver_alloc_init(app->environment); @@ -867,14 +875,14 @@ int32_t subghz_remote_app(void* p) { bool exit_loop = false; if(app->file_result == 2) { - FURI_LOG_D( - TAG, - "U: %s - D: %s - L: %s - R: %s - O: %s ", - furi_string_get_cstr(app->up_file), - furi_string_get_cstr(app->down_file), - furi_string_get_cstr(app->left_file), - furi_string_get_cstr(app->right_file), - furi_string_get_cstr(app->ok_file)); + //FURI_LOG_D( + //TAG, + //"U: %s - D: %s - L: %s - R: %s - O: %s ", + //furi_string_get_cstr(app->up_file), + //furi_string_get_cstr(app->down_file), + //furi_string_get_cstr(app->left_file), + //furi_string_get_cstr(app->right_file), + //furi_string_get_cstr(app->ok_file)); //variables to control multiple button presses and status updates app->send_status = "Idle"; @@ -892,11 +900,11 @@ int32_t subghz_remote_app(void* p) { while(1) { furi_check( furi_message_queue_get(app->input_queue, &input, FuriWaitForever) == FuriStatusOk); - FURI_LOG_D( - TAG, - "key: %s type: %s", - input_get_key_name(input.key), - input_get_type_name(input.type)); + //FURI_LOG_D( + //TAG, + //"key: %s type: %s", + //input_get_key_name(input.key), + //input_get_type_name(input.type)); switch(input.key) { case InputKeyUp: @@ -998,12 +1006,12 @@ int32_t subghz_remote_app(void* p) { } if(app->processing == 0) { - FURI_LOG_D(TAG, "processing 0"); + //FURI_LOG_D(TAG, "processing 0"); app->send_status = "Idle"; app->send_status_c = 0; app->button = 0; } else if(app->processing == 1) { - FURI_LOG_D(TAG, "processing 1"); + //FURI_LOG_D(TAG, "processing 1"); app->send_status = "Send"; @@ -1046,11 +1054,11 @@ int32_t subghz_remote_app(void* p) { while(1) { furi_check( furi_message_queue_get(app->input_queue, &input, FuriWaitForever) == FuriStatusOk); - FURI_LOG_D( - TAG, - "key: %s type: %s", - input_get_key_name(input.key), - input_get_type_name(input.type)); + //FURI_LOG_D( + //TAG, + //"key: %s type: %s", + //input_get_key_name(input.key), + //input_get_type_name(input.type)); switch(input.key) { case InputKeyRight: diff --git a/applications/external/totp/cli/commands/reset/reset.c b/applications/external/totp/cli/commands/reset/reset.c index c7928db31..cd2d1bf46 100644 --- a/applications/external/totp/cli/commands/reset/reset.c +++ b/applications/external/totp/cli/commands/reset/reset.c @@ -1,7 +1,7 @@ #include "reset.h" #include -#include +#include #include "../../cli_helpers.h" #include "../../../services/config/config.h" diff --git a/applications/external/totp/lib/polyfills/strnlen.h b/applications/external/totp/lib/polyfills/strnlen.h index 7dcef3a18..4fe0d540c 100644 --- a/applications/external/totp/lib/polyfills/strnlen.h +++ b/applications/external/totp/lib/polyfills/strnlen.h @@ -1,3 +1,6 @@ +#pragma once +#pragma weak strnlen + #include size_t strnlen(const char* s, size_t maxlen); \ No newline at end of file diff --git a/applications/external/totp/services/config/config.c b/applications/external/totp/services/config/config.c index 6d5838b28..5ef04af79 100644 --- a/applications/external/totp/services/config/config.c +++ b/applications/external/totp/services/config/config.c @@ -57,7 +57,7 @@ static char* totp_config_file_backup_i(Storage* storage) { } if(backup_file_exists || - !storage_common_copy(storage, CONFIG_FILE_PATH, backup_path) == FSE_OK) { + storage_common_copy(storage, CONFIG_FILE_PATH, backup_path) != FSE_OK) { FURI_LOG_E(LOGGING_TAG, "Unable to take a backup"); free(backup_path); return NULL; diff --git a/applications/external/totp/services/config/config.h b/applications/external/totp/services/config/config.h index dabeb373a..5bd169525 100644 --- a/applications/external/totp/services/config/config.h +++ b/applications/external/totp/services/config/config.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include "../../types/plugin_state.h" #include "../../types/token_info.h" #include "constants.h" diff --git a/applications/external/totp/services/crypto/crypto.c b/applications/external/totp/services/crypto/crypto.c index 55fb1df6a..00f5ab0a8 100644 --- a/applications/external/totp/services/crypto/crypto.c +++ b/applications/external/totp/services/crypto/crypto.c @@ -1,6 +1,7 @@ #include "crypto.h" -#include -#include +#include +#include +#include #include "../config/config.h" #include "../../types/common.h" #include "memset_s.h" diff --git a/applications/external/totp/services/totp/totp.c b/applications/external/totp/services/totp/totp.c index f6e0401e6..45a283b06 100644 --- a/applications/external/totp/services/totp/totp.c +++ b/applications/external/totp/services/totp/totp.c @@ -1,15 +1,13 @@ #include "totp.h" -#include #include #include -#include #include +#include #include "../hmac/hmac_sha1.h" #include "../hmac/hmac_sha256.h" #include "../hmac/hmac_sha512.h" #include "../hmac/byteswap.h" -#include "../../lib/timezone_utils/timezone_utils.h" #define HMAC_MAX_RESULT_SIZE HMAC_SHA512_RESULT_SIZE diff --git a/applications/external/totp/totp_app.c b/applications/external/totp/totp_app.c index 8a014628d..e8fa4b1e4 100644 --- a/applications/external/totp/totp_app.c +++ b/applications/external/totp/totp_app.c @@ -1,10 +1,7 @@ -#include -#include #include #include #include #include -#include #include #include #include "features_config.h" @@ -104,10 +101,6 @@ static bool totp_plugin_state_init(PluginState* const plugin_state) { } plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(plugin_state->mutex == NULL) { - FURI_LOG_E(LOGGING_TAG, "Cannot create mutex\r\n"); - return false; - } #ifdef TOTP_BADBT_TYPE_ENABLED if(plugin_state->automation_method & AutomationMethodBadBt) { diff --git a/applications/external/totp/types/token_info.c b/applications/external/totp/types/token_info.c index b8196c56b..5b85de719 100644 --- a/applications/external/totp/types/token_info.c +++ b/applications/external/totp/types/token_info.c @@ -1,9 +1,7 @@ #include "token_info.h" -#include #include #include #include -#include #include "common.h" #include "../services/crypto/crypto.h" diff --git a/applications/external/totp/types/token_info.h b/applications/external/totp/types/token_info.h index 9ca3528dc..21968553f 100644 --- a/applications/external/totp/types/token_info.h +++ b/applications/external/totp/types/token_info.h @@ -2,7 +2,7 @@ #include #include -#include +#include #define TOTP_TOKEN_DURATION_DEFAULT (30) diff --git a/applications/external/totp/ui/scenes/add_new_token/totp_input_text.c b/applications/external/totp/ui/scenes/add_new_token/totp_input_text.c index 6956ec1ad..bbe0b7726 100644 --- a/applications/external/totp/ui/scenes/add_new_token/totp_input_text.c +++ b/applications/external/totp/ui/scenes/add_new_token/totp_input_text.c @@ -1,6 +1,5 @@ #include "totp_input_text.h" #include -#include "../../../lib/polyfills/strnlen.h" void view_draw(View* view, Canvas* canvas) { furi_assert(view); diff --git a/applications/external/totp/ui/scenes/add_new_token/totp_scene_add_new_token.h b/applications/external/totp/ui/scenes/add_new_token/totp_scene_add_new_token.h index 07098111a..e05a95dbd 100644 --- a/applications/external/totp/ui/scenes/add_new_token/totp_scene_add_new_token.h +++ b/applications/external/totp/ui/scenes/add_new_token/totp_scene_add_new_token.h @@ -1,8 +1,6 @@ #pragma once #include -#include -#include #include "../../../types/plugin_state.h" #include "../../../types/plugin_event.h" diff --git a/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c b/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c index 22e6ebc33..5e885b302 100644 --- a/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c +++ b/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c @@ -2,19 +2,16 @@ #include #include #include +#include #include "totp_scene_generate_token.h" #include "../../../types/token_info.h" #include "../../../types/common.h" #include "../../constants.h" -#include "../../../services/totp/totp.h" #include "../../../services/config/config.h" -#include "../../../services/crypto/crypto.h" -#include "../../../services/convert/convert.h" -#include "../../../lib/polyfills/memset_s.h" -#include "../../../lib/roll_value/roll_value.h" #include "../../scene_director.h" #include "../token_menu/totp_scene_token_menu.h" #include "../../../features_config.h" +#include "../../../workers/generate_totp_code/generate_totp_code.h" #include "../../../workers/usb_type_code/usb_type_code.h" #ifdef TOTP_BADBT_TYPE_ENABLED #include "../../../workers/bt_type_code/bt_type_code.h" @@ -23,18 +20,26 @@ #define PROGRESS_BAR_MARGIN (3) #define PROGRESS_BAR_HEIGHT (4) -static const char* STEAM_ALGO_ALPHABET = "23456789BCDFGHJKMNPQRTVWXY"; + +typedef struct { + uint8_t progress_bar_x; + uint8_t progress_bar_width; + uint8_t code_total_length; + uint8_t code_offset_x; + uint8_t code_offset_x_inc; + uint8_t code_offset_y; +} UiPrecalculatedDimensions; typedef struct { uint16_t current_token_index; char last_code[TOTP_TOKEN_DIGITS_MAX_COUNT + 1]; - bool need_token_update; TokenInfo* current_token; - uint32_t last_token_gen_time; TotpUsbTypeCodeWorkerContext* usb_type_code_worker_context; NotificationMessage const** notification_sequence_new_token; - NotificationMessage const** notification_sequence_badusb; + NotificationMessage const** notification_sequence_automation; FuriMutex* last_code_update_sync; + TotpGenerateCodeWorkerContext* generate_code_worker_context; + UiPrecalculatedDimensions ui_precalculated_dimensions; } SceneState; static const NotificationSequence* @@ -80,7 +85,7 @@ static const NotificationSequence* static const NotificationSequence* get_notification_sequence_automation(const PluginState* plugin_state, SceneState* scene_state) { - if(scene_state->notification_sequence_badusb == NULL) { + if(scene_state->notification_sequence_automation == NULL) { uint8_t i = 0; uint8_t length = 3; if(plugin_state->notification_method & NotificationMethodVibro) { @@ -91,109 +96,102 @@ static const NotificationSequence* length += 6; } - scene_state->notification_sequence_badusb = malloc(sizeof(void*) * length); - furi_check(scene_state->notification_sequence_badusb != NULL); + scene_state->notification_sequence_automation = malloc(sizeof(void*) * length); + furi_check(scene_state->notification_sequence_automation != NULL); - scene_state->notification_sequence_badusb[i++] = &message_blue_255; + scene_state->notification_sequence_automation[i++] = &message_blue_255; if(plugin_state->notification_method & NotificationMethodVibro) { - scene_state->notification_sequence_badusb[i++] = &message_vibro_on; + scene_state->notification_sequence_automation[i++] = &message_vibro_on; } if(plugin_state->notification_method & NotificationMethodSound) { - scene_state->notification_sequence_badusb[i++] = &message_note_d5; //-V525 - scene_state->notification_sequence_badusb[i++] = &message_delay_50; - scene_state->notification_sequence_badusb[i++] = &message_note_e4; - scene_state->notification_sequence_badusb[i++] = &message_delay_50; - scene_state->notification_sequence_badusb[i++] = &message_note_f3; + scene_state->notification_sequence_automation[i++] = &message_note_d5; //-V525 + scene_state->notification_sequence_automation[i++] = &message_delay_50; + scene_state->notification_sequence_automation[i++] = &message_note_e4; + scene_state->notification_sequence_automation[i++] = &message_delay_50; + scene_state->notification_sequence_automation[i++] = &message_note_f3; } - scene_state->notification_sequence_badusb[i++] = &message_delay_50; + scene_state->notification_sequence_automation[i++] = &message_delay_50; if(plugin_state->notification_method & NotificationMethodVibro) { - scene_state->notification_sequence_badusb[i++] = &message_vibro_off; + scene_state->notification_sequence_automation[i++] = &message_vibro_off; } if(plugin_state->notification_method & NotificationMethodSound) { - scene_state->notification_sequence_badusb[i++] = &message_sound_off; + scene_state->notification_sequence_automation[i++] = &message_sound_off; } - scene_state->notification_sequence_badusb[i++] = NULL; + scene_state->notification_sequence_automation[i++] = NULL; } - return (NotificationSequence*)scene_state->notification_sequence_badusb; -} - -static void - int_token_to_str(uint64_t i_token_code, char* str, TokenDigitsCount len, TokenHashAlgo algo) { - if(i_token_code == OTP_ERROR) { - memset(&str[0], '-', len); - } else { - if(algo == STEAM) { - for(uint8_t i = 0; i < len; i++) { - str[i] = STEAM_ALGO_ALPHABET[i_token_code % 26]; - i_token_code = i_token_code / 26; - } - } else { - for(int8_t i = len - 1; i >= 0; i--) { - str[i] = CONVERT_DIGIT_TO_CHAR(i_token_code % 10); - i_token_code = i_token_code / 10; - } - } - } - - str[len] = '\0'; -} - -static TOTP_ALGO get_totp_algo_impl(TokenHashAlgo algo) { - switch(algo) { - case SHA1: - case STEAM: - return TOTP_ALGO_SHA1; - case SHA256: - return TOTP_ALGO_SHA256; - case SHA512: - return TOTP_ALGO_SHA512; - default: - break; - } - - return NULL; + return (NotificationSequence*)scene_state->notification_sequence_automation; } static void update_totp_params(PluginState* const plugin_state) { SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; if(scene_state->current_token_index < plugin_state->tokens_count) { - TokenInfo* tokenInfo = + scene_state->current_token = list_element_at(plugin_state->tokens_list, scene_state->current_token_index)->data; - - scene_state->need_token_update = true; - scene_state->current_token = tokenInfo; + totp_generate_code_worker_notify( + scene_state->generate_code_worker_context, TotpGenerateCodeWorkerEventForceUpdate); } } static void draw_totp_code(Canvas* const canvas, const SceneState* const scene_state) { uint8_t code_length = scene_state->current_token->digits; + uint8_t offset_x = scene_state->ui_precalculated_dimensions.code_offset_x; uint8_t char_width = modeNine_15ptFontInfo.charInfo[0].width; - uint8_t total_length = code_length * (char_width + modeNine_15ptFontInfo.spacePixels); - uint8_t offset_x = (SCREEN_WIDTH - total_length) >> 1; - uint8_t offset_x_inc = char_width + modeNine_15ptFontInfo.spacePixels; - uint8_t offset_y = SCREEN_HEIGHT_CENTER - (modeNine_15ptFontInfo.height >> 1); + uint8_t offset_x_inc = scene_state->ui_precalculated_dimensions.code_offset_x_inc; for(uint8_t i = 0; i < code_length; i++) { char ch = scene_state->last_code[i]; - uint8_t char_index = ch - modeNine_15ptFontInfo.startChar; - canvas_draw_xbm( - canvas, - offset_x, - offset_y, - char_width, - modeNine_15ptFontInfo.height, - &modeNine_15ptFontInfo.data[modeNine_15ptFontInfo.charInfo[char_index].offset]); + if(ch >= modeNine_15ptFontInfo.startChar && ch <= modeNine_15ptFontInfo.endChar) { + uint8_t char_index = ch - modeNine_15ptFontInfo.startChar; + canvas_draw_xbm( + canvas, + offset_x, + scene_state->ui_precalculated_dimensions.code_offset_y, + char_width, + modeNine_15ptFontInfo.height, + &modeNine_15ptFontInfo.data[modeNine_15ptFontInfo.charInfo[char_index].offset]); + } offset_x += offset_x_inc; } } +static void on_new_token_code_generated(bool time_left, void* context) { + const PluginState* plugin_state = context; + SceneState* scene_state = plugin_state->current_scene_state; + uint8_t char_width = modeNine_15ptFontInfo.charInfo[0].width; + scene_state->ui_precalculated_dimensions.code_total_length = + scene_state->current_token->digits * (char_width + modeNine_15ptFontInfo.spacePixels); + scene_state->ui_precalculated_dimensions.code_offset_x = + (SCREEN_WIDTH - scene_state->ui_precalculated_dimensions.code_total_length) >> 1; + scene_state->ui_precalculated_dimensions.code_offset_x_inc = + char_width + modeNine_15ptFontInfo.spacePixels; + scene_state->ui_precalculated_dimensions.code_offset_y = + SCREEN_HEIGHT_CENTER - (modeNine_15ptFontInfo.height >> 1); + + if(time_left) { + notification_message( + plugin_state->notification_app, + get_notification_sequence_new_token(plugin_state, plugin_state->current_scene_state)); + } +} + +static void on_code_lifetime_updated_generated(float code_lifetime_percent, void* context) { + SceneState* scene_state = context; + scene_state->ui_precalculated_dimensions.progress_bar_width = + (uint8_t)((float)(SCREEN_WIDTH - (PROGRESS_BAR_MARGIN << 1)) * code_lifetime_percent); + scene_state->ui_precalculated_dimensions.progress_bar_x = + ((SCREEN_WIDTH - (PROGRESS_BAR_MARGIN << 1) - + scene_state->ui_precalculated_dimensions.progress_bar_width) >> + 1) + + PROGRESS_BAR_MARGIN; +} + void totp_scene_generate_token_activate( PluginState* plugin_state, const GenerateTokenSceneContext* context) { @@ -231,15 +229,14 @@ void totp_scene_generate_token_activate( } else { scene_state->current_token_index = context->current_token_index; } - scene_state->need_token_update = true; + plugin_state->current_scene_state = scene_state; FURI_LOG_D(LOGGING_TAG, "Timezone set to: %f", (double)plugin_state->timezone_offset); - update_totp_params(plugin_state); scene_state->last_code_update_sync = furi_mutex_alloc(FuriMutexTypeNormal); if(plugin_state->automation_method & AutomationMethodBadUsb) { scene_state->usb_type_code_worker_context = totp_usb_type_code_worker_start( - &scene_state->last_code[0], + scene_state->last_code, TOTP_TOKEN_DIGITS_MAX_COUNT + 1, scene_state->last_code_update_sync); } @@ -252,11 +249,28 @@ void totp_scene_generate_token_activate( } totp_bt_type_code_worker_start( plugin_state->bt_type_code_worker_context, - &scene_state->last_code[0], + scene_state->last_code, TOTP_TOKEN_DIGITS_MAX_COUNT + 1, scene_state->last_code_update_sync); } #endif + + scene_state->generate_code_worker_context = totp_generate_code_worker_start( + scene_state->last_code, + &scene_state->current_token, + scene_state->last_code_update_sync, + plugin_state->timezone_offset, + plugin_state->iv); + + totp_generate_code_worker_set_code_generated_handler( + scene_state->generate_code_worker_context, &on_new_token_code_generated, plugin_state); + + totp_generate_code_worker_set_lifetime_changed_handler( + scene_state->generate_code_worker_context, + &on_code_lifetime_updated_generated, + scene_state); + + update_totp_params(plugin_state); } void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_state) { @@ -278,54 +292,7 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_ return; } - SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; - FuriHalRtcDateTime curr_dt; - furi_hal_rtc_get_datetime(&curr_dt); - uint32_t curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt); - - bool is_new_token_time = curr_ts % scene_state->current_token->duration == 0; - if(is_new_token_time && scene_state->last_token_gen_time != curr_ts) { - scene_state->need_token_update = true; - } - - if(scene_state->need_token_update) { - scene_state->need_token_update = false; - scene_state->last_token_gen_time = curr_ts; - - const TokenInfo* tokenInfo = scene_state->current_token; - - if(tokenInfo->token != NULL && tokenInfo->token_length > 0) { - furi_mutex_acquire(scene_state->last_code_update_sync, FuriWaitForever); - size_t key_length; - uint8_t* key = totp_crypto_decrypt( - tokenInfo->token, tokenInfo->token_length, &plugin_state->iv[0], &key_length); - - int_token_to_str( - totp_at( - get_totp_algo_impl(tokenInfo->algo), - key, - key_length, - curr_ts, - plugin_state->timezone_offset, - tokenInfo->duration), - scene_state->last_code, - tokenInfo->digits, - tokenInfo->algo); - memset_s(key, key_length, 0, key_length); - free(key); - } else { - furi_mutex_acquire(scene_state->last_code_update_sync, FuriWaitForever); - int_token_to_str(0, scene_state->last_code, tokenInfo->digits, tokenInfo->algo); - } - - furi_mutex_release(scene_state->last_code_update_sync); - - if(is_new_token_time) { - notification_message( - plugin_state->notification_app, - get_notification_sequence_new_token(plugin_state, scene_state)); - } - } + const SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; canvas_set_font(canvas, FontPrimary); uint16_t token_name_width = canvas_string_width(canvas, scene_state->current_token->name); @@ -353,17 +320,11 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_ draw_totp_code(canvas, scene_state); - const uint8_t TOKEN_LIFETIME = scene_state->current_token->duration; - float percentDone = (float)(TOKEN_LIFETIME - curr_ts % TOKEN_LIFETIME) / (float)TOKEN_LIFETIME; - uint8_t barWidth = (uint8_t)((float)(SCREEN_WIDTH - (PROGRESS_BAR_MARGIN << 1)) * percentDone); - uint8_t barX = - ((SCREEN_WIDTH - (PROGRESS_BAR_MARGIN << 1) - barWidth) >> 1) + PROGRESS_BAR_MARGIN; - canvas_draw_box( canvas, - barX, + scene_state->ui_precalculated_dimensions.progress_bar_x, SCREEN_HEIGHT - PROGRESS_BAR_MARGIN - PROGRESS_BAR_HEIGHT, - barWidth, + scene_state->ui_precalculated_dimensions.progress_bar_width, PROGRESS_BAR_HEIGHT); if(plugin_state->tokens_count > 1) { @@ -493,6 +454,8 @@ void totp_scene_generate_token_deactivate(PluginState* plugin_state) { if(plugin_state->current_scene_state == NULL) return; SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; + totp_generate_code_worker_stop(scene_state->generate_code_worker_context); + if(plugin_state->automation_method & AutomationMethodBadUsb) { totp_usb_type_code_worker_stop(scene_state->usb_type_code_worker_context); } @@ -506,8 +469,8 @@ void totp_scene_generate_token_deactivate(PluginState* plugin_state) { free(scene_state->notification_sequence_new_token); } - if(scene_state->notification_sequence_badusb != NULL) { - free(scene_state->notification_sequence_badusb); + if(scene_state->notification_sequence_automation != NULL) { + free(scene_state->notification_sequence_automation); } furi_mutex_free(scene_state->last_code_update_sync); diff --git a/applications/external/totp/workers/bt_type_code/bt_type_code.c b/applications/external/totp/workers/bt_type_code/bt_type_code.c index ec4c1619d..5a1f56298 100644 --- a/applications/external/totp/workers/bt_type_code/bt_type_code.c +++ b/applications/external/totp/workers/bt_type_code/bt_type_code.c @@ -1,10 +1,11 @@ #include "bt_type_code.h" #include +#include #include #include #include "../../types/common.h" #include "../../types/token_info.h" -#include "../common.h" +#include "../type_code_common.h" #define HID_BT_KEYS_STORAGE_PATH EXT_PATH("authenticator/.bt_hid.keys") @@ -16,15 +17,15 @@ static inline bool totp_type_code_worker_stop_requested() { static void totp_type_code_worker_bt_set_app_mac(uint8_t* mac) { uint8_t max_i; size_t uid_size = furi_hal_version_uid_size(); - if(uid_size < 6) { + if(uid_size < TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN) { max_i = uid_size; } else { - max_i = 6; + max_i = TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN; } const uint8_t* uid = furi_hal_version_uid(); memcpy(mac, uid, max_i); - for(uint8_t i = max_i; i < 6; i++) { + for(uint8_t i = max_i; i < TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN; i++) { mac[i] = 0; } @@ -39,23 +40,21 @@ static void totp_type_code_worker_type_code(TotpBtTypeCodeWorkerContext* context i++; } while(!context->is_connected && i < 100 && !totp_type_code_worker_stop_requested()); - if(context->is_connected && furi_mutex_acquire(context->string_sync, 500) == FuriStatusOk) { + if(context->is_connected && + furi_mutex_acquire(context->code_buffer_sync, 500) == FuriStatusOk) { totp_type_code_worker_execute_automation( &furi_hal_bt_hid_kb_press, &furi_hal_bt_hid_kb_release, - context->string, - context->string_length, + context->code_buffer, + context->code_buffer_size, context->flags); - furi_mutex_release(context->string_sync); + furi_mutex_release(context->code_buffer_sync); } } static int32_t totp_type_code_worker_callback(void* context) { furi_check(context); FuriMutex* context_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(context_mutex == NULL) { - return 251; - } TotpBtTypeCodeWorkerContext* bt_context = context; @@ -92,13 +91,13 @@ static void connection_status_changed_callback(BtStatus status, void* context) { void totp_bt_type_code_worker_start( TotpBtTypeCodeWorkerContext* context, - char* code_buf, - uint8_t code_buf_length, - FuriMutex* code_buf_update_sync) { + char* code_buffer, + uint8_t code_buffer_size, + FuriMutex* code_buffer_sync) { furi_check(context != NULL); - context->string = code_buf; - context->string_length = code_buf_length; - context->string_sync = code_buf_update_sync; + context->code_buffer = code_buffer; + context->code_buffer_size = code_buffer_size; + context->code_buffer_sync = code_buffer_sync; context->thread = furi_thread_alloc(); furi_thread_set_name(context->thread, "TOTPBtHidWorker"); furi_thread_set_stack_size(context->thread, 1024); @@ -137,7 +136,6 @@ TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init() { bt_keys_storage_set_storage_path(context->bt, HID_BT_KEYS_STORAGE_PATH); #if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME - totp_type_code_worker_bt_set_app_mac(&context->bt_mac[0]); memcpy( &context->previous_bt_name[0], furi_hal_bt_get_profile_adv_name(FuriHalBtProfileHidKeyboard), @@ -148,8 +146,10 @@ TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init() { TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN); char new_name[TOTP_BT_WORKER_BT_ADV_NAME_MAX_LEN]; snprintf(new_name, sizeof(new_name), "%s TOTP Auth", furi_hal_version_get_name_ptr()); + uint8_t new_bt_mac[TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN]; + totp_type_code_worker_bt_set_app_mac(new_bt_mac); furi_hal_bt_set_profile_adv_name(FuriHalBtProfileHidKeyboard, new_name); - furi_hal_bt_set_profile_mac_addr(FuriHalBtProfileHidKeyboard, context->bt_mac); + furi_hal_bt_set_profile_mac_addr(FuriHalBtProfileHidKeyboard, new_bt_mac); #endif if(!bt_set_profile(context->bt, BtProfileHidKeyboard)) { diff --git a/applications/external/totp/workers/bt_type_code/bt_type_code.h b/applications/external/totp/workers/bt_type_code/bt_type_code.h index 1c59ea3e9..6c7e502c6 100644 --- a/applications/external/totp/workers/bt_type_code/bt_type_code.h +++ b/applications/external/totp/workers/bt_type_code/bt_type_code.h @@ -1,8 +1,10 @@ #pragma once #include -#include -#include +#include +#include +#include +#include #include #include "../../features_config.h" @@ -14,34 +16,33 @@ typedef uint8_t TotpBtTypeCodeWorkerEvent; typedef struct { - char* string; - uint8_t string_length; + char* code_buffer; + uint8_t code_buffer_size; uint8_t flags; FuriThread* thread; - FuriMutex* string_sync; + FuriMutex* code_buffer_sync; Bt* bt; bool is_advertising; bool is_connected; #if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME - uint8_t bt_mac[TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN]; char previous_bt_name[TOTP_BT_WORKER_BT_ADV_NAME_MAX_LEN]; uint8_t previous_bt_mac[TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN]; #endif } TotpBtTypeCodeWorkerContext; enum TotpBtTypeCodeWorkerEvents { - TotpBtTypeCodeWorkerEventReserved = 0b0000, - TotpBtTypeCodeWorkerEventStop = 0b0100, - TotpBtTypeCodeWorkerEventType = 0b1000 + TotpBtTypeCodeWorkerEventReserved = 0b00, + TotpBtTypeCodeWorkerEventStop = 0b01, + TotpBtTypeCodeWorkerEventType = 0b10 }; TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init(); void totp_bt_type_code_worker_free(TotpBtTypeCodeWorkerContext* context); void totp_bt_type_code_worker_start( TotpBtTypeCodeWorkerContext* context, - char* code_buf, - uint8_t code_buf_length, - FuriMutex* code_buf_update_sync); + char* code_buffer, + uint8_t code_buffer_size, + FuriMutex* code_buffer_sync); void totp_bt_type_code_worker_stop(TotpBtTypeCodeWorkerContext* context); void totp_bt_type_code_worker_notify( TotpBtTypeCodeWorkerContext* context, diff --git a/applications/external/totp/workers/generate_totp_code/generate_totp_code.c b/applications/external/totp/workers/generate_totp_code/generate_totp_code.c new file mode 100644 index 000000000..4919cf942 --- /dev/null +++ b/applications/external/totp/workers/generate_totp_code/generate_totp_code.c @@ -0,0 +1,181 @@ +#include "generate_totp_code.h" +#include "../../services/crypto/crypto.h" +#include "../../services/totp/totp.h" +#include "../../services/convert/convert.h" +#include +#include + +#define ONE_SEC_MS (1000) + +static const char* STEAM_ALGO_ALPHABET = "23456789BCDFGHJKMNPQRTVWXY"; + +static void + int_token_to_str(uint64_t i_token_code, char* str, TokenDigitsCount len, TokenHashAlgo algo) { + str[len] = '\0'; + if(i_token_code == OTP_ERROR) { + memset(&str[0], '-', len); + } else { + if(algo == STEAM) { + for(uint8_t i = 0; i < len; i++) { + str[i] = STEAM_ALGO_ALPHABET[i_token_code % 26]; + i_token_code = i_token_code / 26; + } + } else { + for(int8_t i = len - 1; i >= 0; i--) { + str[i] = CONVERT_DIGIT_TO_CHAR(i_token_code % 10); + i_token_code = i_token_code / 10; + } + } + } +} + +static TOTP_ALGO get_totp_algo_impl(TokenHashAlgo algo) { + switch(algo) { + case SHA1: + case STEAM: + return TOTP_ALGO_SHA1; + case SHA256: + return TOTP_ALGO_SHA256; + case SHA512: + return TOTP_ALGO_SHA512; + default: + break; + } + + return NULL; +} + +static void generate_totp_code( + TotpGenerateCodeWorkerContext* context, + const TokenInfo* token_info, + uint32_t current_ts) { + if(token_info->token != NULL && token_info->token_length > 0) { + size_t key_length; + uint8_t* key = totp_crypto_decrypt( + token_info->token, token_info->token_length, context->iv, &key_length); + + int_token_to_str( + totp_at( + get_totp_algo_impl(token_info->algo), + key, + key_length, + current_ts, + context->timezone_offset, + token_info->duration), + context->code_buffer, + token_info->digits, + token_info->algo); + memset_s(key, key_length, 0, key_length); + free(key); + } else { + int_token_to_str(0, context->code_buffer, token_info->digits, token_info->algo); + } +} + +static int32_t totp_generate_worker_callback(void* context) { + furi_check(context); + + TotpGenerateCodeWorkerContext* t_context = context; + + while(true) { + uint32_t flags = furi_thread_flags_wait( + TotpGenerateCodeWorkerEventStop | TotpGenerateCodeWorkerEventForceUpdate, + FuriFlagWaitAny, + ONE_SEC_MS); + + if(flags == + (uint32_t) + FuriFlagErrorTimeout) { // If timeout, consider as no error, as we expect this and can handle gracefully + flags = 0; + } + + furi_check((flags & FuriFlagError) == 0); //-V562 + + if(flags & TotpGenerateCodeWorkerEventStop) break; + + const TokenInfo* token_info = *(t_context->token_info); + if(token_info == NULL) { + continue; + } + + uint32_t curr_ts = furi_hal_rtc_get_timestamp(); + + bool time_left = false; + if(flags & TotpGenerateCodeWorkerEventForceUpdate || + (time_left = (curr_ts % token_info->duration) == 0)) { + if(furi_mutex_acquire(t_context->code_buffer_sync, FuriWaitForever) == FuriStatusOk) { + generate_totp_code(t_context, token_info, curr_ts); + curr_ts = furi_hal_rtc_get_timestamp(); + furi_mutex_release(t_context->code_buffer_sync); + if(t_context->on_new_code_generated_handler != NULL) { + (*(t_context->on_new_code_generated_handler))( + time_left, t_context->on_new_code_generated_handler_context); + } + } + } + + if(t_context->on_code_lifetime_changed_handler != NULL) { + (*(t_context->on_code_lifetime_changed_handler))( + (float)(token_info->duration - curr_ts % token_info->duration) / + (float)token_info->duration, + t_context->on_code_lifetime_changed_handler_context); + } + } + + return 0; +} + +TotpGenerateCodeWorkerContext* totp_generate_code_worker_start( + char* code_buffer, + TokenInfo** token_info, + FuriMutex* code_buffer_sync, + float timezone_offset, + uint8_t* iv) { + TotpGenerateCodeWorkerContext* context = malloc(sizeof(TotpGenerateCodeWorkerContext)); + furi_check(context != NULL); + context->code_buffer = code_buffer; + context->token_info = token_info; + context->code_buffer_sync = code_buffer_sync; + context->timezone_offset = timezone_offset; + context->iv = iv; + context->thread = furi_thread_alloc(); + furi_thread_set_name(context->thread, "TOTPGenerateWorker"); + furi_thread_set_stack_size(context->thread, 2048); + furi_thread_set_context(context->thread, context); + furi_thread_set_callback(context->thread, totp_generate_worker_callback); + furi_thread_start(context->thread); + return context; +} + +void totp_generate_code_worker_stop(TotpGenerateCodeWorkerContext* context) { + furi_check(context != NULL); + furi_thread_flags_set(furi_thread_get_id(context->thread), TotpGenerateCodeWorkerEventStop); + furi_thread_join(context->thread); + furi_thread_free(context->thread); + free(context); +} + +void totp_generate_code_worker_notify( + TotpGenerateCodeWorkerContext* context, + TotpGenerateCodeWorkerEvent event) { + furi_check(context != NULL); + furi_thread_flags_set(furi_thread_get_id(context->thread), event); +} + +void totp_generate_code_worker_set_code_generated_handler( + TotpGenerateCodeWorkerContext* context, + TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler, + void* on_new_code_generated_handler_context) { + furi_check(context != NULL); + context->on_new_code_generated_handler = on_new_code_generated_handler; + context->on_new_code_generated_handler_context = on_new_code_generated_handler_context; +} + +void totp_generate_code_worker_set_lifetime_changed_handler( + TotpGenerateCodeWorkerContext* context, + TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler, + void* on_code_lifetime_changed_handler_context) { + furi_check(context != NULL); + context->on_code_lifetime_changed_handler = on_code_lifetime_changed_handler; + context->on_code_lifetime_changed_handler_context = on_code_lifetime_changed_handler_context; +} \ No newline at end of file diff --git a/applications/external/totp/workers/generate_totp_code/generate_totp_code.h b/applications/external/totp/workers/generate_totp_code/generate_totp_code.h new file mode 100644 index 000000000..c7a93dc95 --- /dev/null +++ b/applications/external/totp/workers/generate_totp_code/generate_totp_code.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include +#include +#include "../../types/token_info.h" + +typedef uint8_t TotpGenerateCodeWorkerEvent; + +typedef void (*TOTP_NEW_CODE_GENERATED_HANDLER)(bool time_left, void* context); +typedef void (*TOTP_CODE_LIFETIME_CHANGED_HANDLER)(float code_lifetime_percent, void* context); + +typedef struct { + char* code_buffer; + FuriThread* thread; + FuriMutex* code_buffer_sync; + TokenInfo** token_info; + float timezone_offset; + uint8_t* iv; + TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler; + void* on_new_code_generated_handler_context; + TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler; + void* on_code_lifetime_changed_handler_context; +} TotpGenerateCodeWorkerContext; + +enum TotGenerateCodeWorkerEvents { + TotpGenerateCodeWorkerEventReserved = 0b00, + TotpGenerateCodeWorkerEventStop = 0b01, + TotpGenerateCodeWorkerEventForceUpdate = 0b10 +}; + +TotpGenerateCodeWorkerContext* totp_generate_code_worker_start( + char* code_buffer, + TokenInfo** token_info, + FuriMutex* code_buffer_sync, + float timezone_offset, + uint8_t* iv); +void totp_generate_code_worker_stop(TotpGenerateCodeWorkerContext* context); +void totp_generate_code_worker_notify( + TotpGenerateCodeWorkerContext* context, + TotpGenerateCodeWorkerEvent event); +void totp_generate_code_worker_set_code_generated_handler( + TotpGenerateCodeWorkerContext* context, + TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler, + void* on_new_code_generated_handler_context); +void totp_generate_code_worker_set_lifetime_changed_handler( + TotpGenerateCodeWorkerContext* context, + TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler, + void* on_code_lifetime_changed_handler_context); \ No newline at end of file diff --git a/applications/external/totp/workers/common.c b/applications/external/totp/workers/type_code_common.c similarity index 88% rename from applications/external/totp/workers/common.c rename to applications/external/totp/workers/type_code_common.c index 8ad0c2b46..fa5e7290f 100644 --- a/applications/external/totp/workers/common.c +++ b/applications/external/totp/workers/type_code_common.c @@ -1,6 +1,6 @@ -#include "common.h" -#include -#include +#include "type_code_common.h" +#include +#include #include "../../services/convert/convert.h" static const uint8_t hid_number_keys[] = { @@ -42,18 +42,18 @@ static void totp_type_code_worker_press_key( void totp_type_code_worker_execute_automation( TOTP_AUTOMATION_KEY_HANDLER key_press_fn, TOTP_AUTOMATION_KEY_HANDLER key_release_fn, - const char* string, - uint8_t string_length, + const char* code_buffer, + uint8_t code_buffer_size, TokenAutomationFeature features) { furi_delay_ms(500); uint8_t i = 0; totp_type_code_worker_press_key( HID_KEYBOARD_CAPS_LOCK, key_press_fn, key_release_fn, features); - while(i < string_length && string[i] != 0) { - uint8_t char_index = CONVERT_CHAR_TO_DIGIT(string[i]); + while(i < code_buffer_size && code_buffer[i] != 0) { + uint8_t char_index = CONVERT_CHAR_TO_DIGIT(code_buffer[i]); if(char_index > 9) { - char_index = string[i] - 0x41 + 10; + char_index = code_buffer[i] - 0x41 + 10; } if(char_index > 35) break; diff --git a/applications/external/totp/workers/common.h b/applications/external/totp/workers/type_code_common.h similarity index 83% rename from applications/external/totp/workers/common.h rename to applications/external/totp/workers/type_code_common.h index 5e3a2006e..1516928cf 100644 --- a/applications/external/totp/workers/common.h +++ b/applications/external/totp/workers/type_code_common.h @@ -7,6 +7,6 @@ typedef bool (*TOTP_AUTOMATION_KEY_HANDLER)(uint16_t key); void totp_type_code_worker_execute_automation( TOTP_AUTOMATION_KEY_HANDLER key_press_fn, TOTP_AUTOMATION_KEY_HANDLER key_release_fn, - const char* string, - uint8_t string_length, + const char* code_buffer, + uint8_t code_buffer_size, TokenAutomationFeature features); \ No newline at end of file diff --git a/applications/external/totp/workers/usb_type_code/usb_type_code.c b/applications/external/totp/workers/usb_type_code/usb_type_code.c index 5f7ccddf8..10034907d 100644 --- a/applications/external/totp/workers/usb_type_code/usb_type_code.c +++ b/applications/external/totp/workers/usb_type_code/usb_type_code.c @@ -1,7 +1,8 @@ #include "usb_type_code.h" +#include #include "../../services/convert/convert.h" #include "../../types/token_info.h" -#include "../common.h" +#include "../type_code_common.h" static void totp_type_code_worker_restore_usb_mode(TotpUsbTypeCodeWorkerContext* context) { if(context->usb_mode_prev != NULL) { @@ -25,14 +26,14 @@ static void totp_type_code_worker_type_code(TotpUsbTypeCodeWorkerContext* contex } while(!furi_hal_hid_is_connected() && i < 100 && !totp_type_code_worker_stop_requested()); if(furi_hal_hid_is_connected() && - furi_mutex_acquire(context->string_sync, 500) == FuriStatusOk) { + furi_mutex_acquire(context->code_buffer_sync, 500) == FuriStatusOk) { totp_type_code_worker_execute_automation( &furi_hal_hid_kb_press, &furi_hal_hid_kb_release, - context->string, - context->string_length, + context->code_buffer, + context->code_buffer_size, context->flags); - furi_mutex_release(context->string_sync); + furi_mutex_release(context->code_buffer_sync); furi_delay_ms(100); } @@ -43,9 +44,6 @@ static void totp_type_code_worker_type_code(TotpUsbTypeCodeWorkerContext* contex static int32_t totp_type_code_worker_callback(void* context) { furi_check(context); FuriMutex* context_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(context_mutex == NULL) { - return 251; - } while(true) { uint32_t flags = furi_thread_flags_wait( @@ -70,14 +68,14 @@ static int32_t totp_type_code_worker_callback(void* context) { } TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start( - char* code_buf, - uint8_t code_buf_length, - FuriMutex* code_buf_update_sync) { + char* code_buffer, + uint8_t code_buffer_size, + FuriMutex* code_buffer_sync) { TotpUsbTypeCodeWorkerContext* context = malloc(sizeof(TotpUsbTypeCodeWorkerContext)); furi_check(context != NULL); - context->string = code_buf; - context->string_length = code_buf_length; - context->string_sync = code_buf_update_sync; + context->code_buffer = code_buffer; + context->code_buffer_size = code_buffer_size; + context->code_buffer_sync = code_buffer_sync; context->thread = furi_thread_alloc(); context->usb_mode_prev = NULL; furi_thread_set_name(context->thread, "TOTPUsbHidWorker"); diff --git a/applications/external/totp/workers/usb_type_code/usb_type_code.h b/applications/external/totp/workers/usb_type_code/usb_type_code.h index d0ea600ce..21213f4d4 100644 --- a/applications/external/totp/workers/usb_type_code/usb_type_code.h +++ b/applications/external/totp/workers/usb_type_code/usb_type_code.h @@ -1,17 +1,20 @@ #pragma once #include -#include -#include +#include +#include +#include +#include +#include typedef uint8_t TotpUsbTypeCodeWorkerEvent; typedef struct { - char* string; - uint8_t string_length; + char* code_buffer; + uint8_t code_buffer_size; uint8_t flags; FuriThread* thread; - FuriMutex* string_sync; + FuriMutex* code_buffer_sync; FuriHalUsbInterface* usb_mode_prev; } TotpUsbTypeCodeWorkerContext; @@ -22,9 +25,9 @@ enum TotpUsbTypeCodeWorkerEvents { }; TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start( - char* code_buf, - uint8_t code_buf_length, - FuriMutex* code_buf_update_sync); + char* code_buffer, + uint8_t code_buffer_size, + FuriMutex* code_buffer_sync); void totp_usb_type_code_worker_stop(TotpUsbTypeCodeWorkerContext* context); void totp_usb_type_code_worker_notify( TotpUsbTypeCodeWorkerContext* context, diff --git a/applications/external/uart_terminal/scenes/uart_terminal_scene_console_output.c b/applications/external/uart_terminal/scenes/uart_terminal_scene_console_output.c index 38a5a20e4..6988c42de 100644 --- a/applications/external/uart_terminal/scenes/uart_terminal_scene_console_output.c +++ b/applications/external/uart_terminal/scenes/uart_terminal_scene_console_output.c @@ -114,13 +114,9 @@ void uart_terminal_scene_console_output_on_enter(void* context) { // Send command with CR+LF or newline '\n' if(app->is_command && app->selected_tx_string) { if(app->TERMINAL_MODE == 1) { - // char buffer[240]; - // snprintf(buffer, 240, "%s\r\n", (app->selected_tx_string)); - // uart_terminal_uart_tx((unsigned char *)buffer, strlen(buffer)); uart_terminal_uart_tx( (uint8_t*)(app->selected_tx_string), strlen(app->selected_tx_string)); - uart_terminal_uart_tx((uint8_t*)("\r"), 1); - uart_terminal_uart_tx((uint8_t*)("\n"), 1); + uart_terminal_uart_tx((uint8_t*)("\r\n"), 2); } else { uart_terminal_uart_tx( (uint8_t*)(app->selected_tx_string), strlen(app->selected_tx_string)); @@ -149,9 +145,4 @@ void uart_terminal_scene_console_output_on_exit(void* context) { // Unregister rx callback uart_terminal_uart_set_handle_rx_data_cb(app->uart, NULL); - - // Automatically logut when exiting view - //if(app->is_command) { - // uart_terminal_uart_tx((uint8_t*)("exit\n"), strlen("exit\n")); - //} } \ No newline at end of file diff --git a/applications/external/wifi_marauder_companion/application.fam b/applications/external/wifi_marauder_companion/application.fam index 5fe303b00..1764ac706 100644 --- a/applications/external/wifi_marauder_companion/application.fam +++ b/applications/external/wifi_marauder_companion/application.fam @@ -8,4 +8,5 @@ App( order=90, fap_icon="wifi_10px.png", fap_category="WiFi", + fap_libs=["assets"], ) diff --git a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_text_input.c b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_text_input.c index b721e868d..e6091a410 100644 --- a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_text_input.c +++ b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_text_input.c @@ -44,24 +44,24 @@ void wifi_marauder_scene_text_input_on_enter(void* context) { } // Setup view - TextInput* text_input = app->text_input; + WIFI_TextInput* text_input = app->text_input; // Add help message to header if(app->special_case_input_step == 1) { - text_input_set_header_text(text_input, "Enter source MAC"); + wifi_text_input_set_header_text(text_input, "Enter source MAC"); } else if(0 == strncmp("ssid -a -g", app->selected_tx_string, strlen("ssid -a -g"))) { - text_input_set_header_text(text_input, "Enter # SSIDs to generate"); + wifi_text_input_set_header_text(text_input, "Enter # SSIDs to generate"); } else if(0 == strncmp("ssid -a -n", app->selected_tx_string, strlen("ssid -a -n"))) { - text_input_set_header_text(text_input, "Enter SSID name to add"); + wifi_text_input_set_header_text(text_input, "Enter SSID name to add"); } else if(0 == strncmp("ssid -r", app->selected_tx_string, strlen("ssid -r"))) { - text_input_set_header_text(text_input, "Remove target from SSID list"); + wifi_text_input_set_header_text(text_input, "Remove target from SSID list"); } else if(0 == strncmp("select -a", app->selected_tx_string, strlen("select -a"))) { - text_input_set_header_text(text_input, "Add target from AP list"); + wifi_text_input_set_header_text(text_input, "Add target from AP list"); } else if(0 == strncmp("select -s", app->selected_tx_string, strlen("select -s"))) { - text_input_set_header_text(text_input, "Add target from SSID list"); + wifi_text_input_set_header_text(text_input, "Add target from SSID list"); } else { - text_input_set_header_text(text_input, "Add command arguments"); + wifi_text_input_set_header_text(text_input, "Add command arguments"); } - text_input_set_result_callback( + wifi_text_input_set_result_callback( text_input, wifi_marauder_scene_text_input_callback, app, @@ -84,7 +84,7 @@ bool wifi_marauder_scene_text_input_on_event(void* context, SceneManagerEvent ev consumed = true; } else if(event.event == WifiMarauderEventSaveSourceMac) { if(12 != strlen(app->text_input_store)) { - text_input_set_header_text(app->text_input, "MAC must be 12 hex chars!"); + wifi_text_input_set_header_text(app->text_input, "MAC must be 12 hex chars!"); } else { snprintf( app->special_case_input_src_addr, @@ -106,12 +106,12 @@ bool wifi_marauder_scene_text_input_on_event(void* context, SceneManagerEvent ev // Advance scene to input destination MAC, clear text input app->special_case_input_step = 2; bzero(app->text_input_store, WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE); - text_input_set_header_text(app->text_input, "Enter destination MAC"); + wifi_text_input_set_header_text(app->text_input, "Enter destination MAC"); } consumed = true; } else if(event.event == WifiMarauderEventSaveDestinationMac) { if(12 != strlen(app->text_input_store)) { - text_input_set_header_text(app->text_input, "MAC must be 12 hex chars!"); + wifi_text_input_set_header_text(app->text_input, "MAC must be 12 hex chars!"); } else { snprintf( app->special_case_input_dst_addr, @@ -150,5 +150,5 @@ bool wifi_marauder_scene_text_input_on_event(void* context, SceneManagerEvent ev void wifi_marauder_scene_text_input_on_exit(void* context) { WifiMarauderApp* app = context; - text_input_reset(app->text_input); + wifi_text_input_reset(app->text_input); } diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_app.c b/applications/external/wifi_marauder_companion/wifi_marauder_app.c index 42e94a8b8..67d016df8 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_app.c +++ b/applications/external/wifi_marauder_companion/wifi_marauder_app.c @@ -66,9 +66,11 @@ WifiMarauderApp* wifi_marauder_app_alloc() { app->text_box_store = furi_string_alloc(); furi_string_reserve(app->text_box_store, WIFI_MARAUDER_TEXT_BOX_STORE_SIZE); - app->text_input = text_input_alloc(); + app->text_input = wifi_text_input_alloc(); view_dispatcher_add_view( - app->view_dispatcher, WifiMarauderAppViewTextInput, text_input_get_view(app->text_input)); + app->view_dispatcher, + WifiMarauderAppViewTextInput, + wifi_text_input_get_view(app->text_input)); app->widget = widget_alloc(); view_dispatcher_add_view( @@ -137,7 +139,7 @@ void wifi_marauder_app_free(WifiMarauderApp* app) { widget_free(app->widget); text_box_free(app->text_box); furi_string_free(app->text_box_store); - text_input_free(app->text_input); + wifi_text_input_free(app->text_input); storage_file_free(app->capture_file); storage_file_free(app->log_file); storage_file_free(app->save_pcap_setting_file); diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h b/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h index 39b48fae3..1bc8f78fe 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h +++ b/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h @@ -12,9 +12,9 @@ #include #include #include -#include #include #include +#include "wifi_marauder_text_input.h" #include #include @@ -42,7 +42,7 @@ struct WifiMarauderApp { FuriString* text_box_store; size_t text_box_store_strlen; TextBox* text_box; - TextInput* text_input; + WIFI_TextInput* text_input; Storage* storage; File* capture_file; File* log_file; diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_text_input.c b/applications/external/wifi_marauder_companion/wifi_marauder_text_input.c new file mode 100644 index 000000000..1ea473458 --- /dev/null +++ b/applications/external/wifi_marauder_companion/wifi_marauder_text_input.c @@ -0,0 +1,625 @@ +#include "wifi_marauder_text_input.h" +#include +#include "assets_icons.h" +#include "wifi_marauder_app_i.h" +#include + +struct WIFI_TextInput { + View* view; + FuriTimer* timer; +}; + +typedef struct { + const char text; + const uint8_t x; + const uint8_t y; +} WIFI_TextInputKey; + +typedef struct { + const char* header; + char* text_buffer; + size_t text_buffer_size; + bool clear_default_text; + + WIFI_TextInputCallback callback; + void* callback_context; + + uint8_t selected_row; + uint8_t selected_column; + + WIFI_TextInputValidatorCallback validator_callback; + void* validator_callback_context; + FuriString* validator_text; + bool valadator_message_visible; +} WIFI_TextInputModel; + +static const uint8_t keyboard_origin_x = 1; +static const uint8_t keyboard_origin_y = 29; +static const uint8_t keyboard_row_count = 4; + +#define ENTER_KEY '\r' +#define BACKSPACE_KEY '\b' + +static const WIFI_TextInputKey keyboard_keys_row_1[] = { + {'{', 1, 0}, + {'(', 9, 0}, + {'[', 17, 0}, + {'|', 25, 0}, + {'@', 33, 0}, + {'&', 41, 0}, + {'#', 49, 0}, + {';', 57, 0}, + {'^', 65, 0}, + {'*', 73, 0}, + {'`', 81, 0}, + {'"', 89, 0}, + {'~', 97, 0}, + {'\'', 105, 0}, + {'.', 113, 0}, + {'/', 120, 0}, +}; + +static const WIFI_TextInputKey keyboard_keys_row_2[] = { + {'q', 1, 10}, + {'w', 9, 10}, + {'e', 17, 10}, + {'r', 25, 10}, + {'t', 33, 10}, + {'y', 41, 10}, + {'u', 49, 10}, + {'i', 57, 10}, + {'o', 65, 10}, + {'p', 73, 10}, + {'0', 81, 10}, + {'1', 89, 10}, + {'2', 97, 10}, + {'3', 105, 10}, + {'=', 113, 10}, + {'-', 120, 10}, +}; + +static const WIFI_TextInputKey keyboard_keys_row_3[] = { + {'a', 1, 21}, + {'s', 9, 21}, + {'d', 18, 21}, + {'f', 25, 21}, + {'g', 33, 21}, + {'h', 41, 21}, + {'j', 49, 21}, + {'k', 57, 21}, + {'l', 65, 21}, + {BACKSPACE_KEY, 72, 13}, + {'4', 89, 21}, + {'5', 97, 21}, + {'6', 105, 21}, + {'$', 113, 21}, + {'%', 120, 21}, + +}; + +static const WIFI_TextInputKey keyboard_keys_row_4[] = { + {'z', 1, 33}, + {'x', 9, 33}, + {'c', 18, 33}, + {'v', 25, 33}, + {'b', 33, 33}, + {'n', 41, 33}, + {'m', 49, 33}, + {'_', 57, 33}, + {ENTER_KEY, 64, 24}, + {'7', 89, 33}, + {'8', 97, 33}, + {'9', 105, 33}, + {'!', 113, 33}, + {'+', 120, 33}, +}; + +static uint8_t get_row_size(uint8_t row_index) { + uint8_t row_size = 0; + + switch(row_index + 1) { + case 1: + row_size = sizeof(keyboard_keys_row_1) / sizeof(WIFI_TextInputKey); + break; + case 2: + row_size = sizeof(keyboard_keys_row_2) / sizeof(WIFI_TextInputKey); + break; + case 3: + row_size = sizeof(keyboard_keys_row_3) / sizeof(WIFI_TextInputKey); + break; + case 4: + row_size = sizeof(keyboard_keys_row_4) / sizeof(WIFI_TextInputKey); + break; + } + + return row_size; +} + +static const WIFI_TextInputKey* get_row(uint8_t row_index) { + const WIFI_TextInputKey* row = NULL; + + switch(row_index + 1) { + case 1: + row = keyboard_keys_row_1; + break; + case 2: + row = keyboard_keys_row_2; + break; + case 3: + row = keyboard_keys_row_3; + break; + case 4: + row = keyboard_keys_row_4; + break; + } + + return row; +} + +static char get_selected_char(WIFI_TextInputModel* model) { + return get_row(model->selected_row)[model->selected_column].text; +} + +static bool char_is_lowercase(char letter) { + return (letter >= 0x61 && letter <= 0x7A); +} + +static char char_to_uppercase(const char letter) { + switch(letter) { + case '_': + return 0x20; + break; + case '(': + return 0x29; + break; + case '{': + return 0x7d; + break; + case '[': + return 0x5d; + break; + case '/': + return 0x5c; + break; + case ';': + return 0x3a; + break; + case '.': + return 0x2c; + break; + case '!': + return 0x3f; + break; + case '<': + return 0x3e; + break; + } + if(char_is_lowercase(letter)) { + return (letter - 0x20); + } else { + return letter; + } +} + +static void wifi_text_input_backspace_cb(WIFI_TextInputModel* model) { + uint8_t text_length = model->clear_default_text ? 1 : strlen(model->text_buffer); + if(text_length > 0) { + model->text_buffer[text_length - 1] = 0; + } +} + +static void wifi_text_input_view_draw_callback(Canvas* canvas, void* _model) { + WIFI_TextInputModel* model = _model; + //uint8_t text_length = model->text_buffer ? strlen(model->text_buffer) : 0; + uint8_t needed_string_width = canvas_width(canvas) - 8; + uint8_t start_pos = 4; + + const char* text = model->text_buffer; + + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); + + canvas_draw_str(canvas, 2, 7, model->header); + elements_slightly_rounded_frame(canvas, 1, 8, 126, 12); + + if(canvas_string_width(canvas, text) > needed_string_width) { + canvas_draw_str(canvas, start_pos, 17, "..."); + start_pos += 6; + needed_string_width -= 8; + } + + while(text != 0 && canvas_string_width(canvas, text) > needed_string_width) { + text++; + } + + if(model->clear_default_text) { + elements_slightly_rounded_box( + canvas, start_pos - 1, 14, canvas_string_width(canvas, text) + 2, 10); + canvas_set_color(canvas, ColorWhite); + } else { + canvas_draw_str(canvas, start_pos + canvas_string_width(canvas, text) + 1, 18, "|"); + canvas_draw_str(canvas, start_pos + canvas_string_width(canvas, text) + 2, 18, "|"); + } + canvas_draw_str(canvas, start_pos, 17, text); + + canvas_set_font(canvas, FontKeyboard); + + for(uint8_t row = 0; row <= keyboard_row_count; row++) { + const uint8_t column_count = get_row_size(row); + const WIFI_TextInputKey* keys = get_row(row); + + for(size_t column = 0; column < column_count; column++) { + if(keys[column].text == ENTER_KEY) { + canvas_set_color(canvas, ColorBlack); + if(model->selected_row == row && model->selected_column == column) { + canvas_draw_icon( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + &I_KeySaveSelected_24x11); + } else { + canvas_draw_icon( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + &I_KeySave_24x11); + } + } else if(keys[column].text == BACKSPACE_KEY) { + canvas_set_color(canvas, ColorBlack); + if(model->selected_row == row && model->selected_column == column) { + canvas_draw_icon( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + &I_KeyBackspaceSelected_16x9); + } else { + canvas_draw_icon( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + &I_KeyBackspace_16x9); + } + } else { + if(model->selected_row == row && model->selected_column == column) { + canvas_set_color(canvas, ColorBlack); + canvas_draw_box( + canvas, + keyboard_origin_x + keys[column].x - 1, + keyboard_origin_y + keys[column].y - 8, + 7, + 10); + canvas_set_color(canvas, ColorWhite); + } else { + canvas_set_color(canvas, ColorBlack); + } + + canvas_draw_glyph( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + keys[column].text); + } + } + } + if(model->valadator_message_visible) { + canvas_set_font(canvas, FontSecondary); + canvas_set_color(canvas, ColorWhite); + canvas_draw_box(canvas, 8, 10, 110, 48); + canvas_set_color(canvas, ColorBlack); + canvas_draw_icon(canvas, 10, 14, &I_WarningDolphin_45x42); + canvas_draw_rframe(canvas, 8, 8, 112, 50, 3); + canvas_draw_rframe(canvas, 9, 9, 110, 48, 2); + elements_multiline_text(canvas, 62, 20, furi_string_get_cstr(model->validator_text)); + canvas_set_font(canvas, FontKeyboard); + } +} + +static void + wifi_text_input_handle_up(WIFI_TextInput* wifi_text_input, WIFI_TextInputModel* model) { + UNUSED(wifi_text_input); + if(model->selected_row > 0) { + model->selected_row--; + if(model->selected_column > get_row_size(model->selected_row) - 6) { + model->selected_column = model->selected_column + 1; + } + } +} + +static void + wifi_text_input_handle_down(WIFI_TextInput* wifi_text_input, WIFI_TextInputModel* model) { + UNUSED(wifi_text_input); + if(model->selected_row < keyboard_row_count - 1) { + model->selected_row++; + if(model->selected_column > get_row_size(model->selected_row) - 4) { + model->selected_column = model->selected_column - 1; + } + } +} + +static void + wifi_text_input_handle_left(WIFI_TextInput* wifi_text_input, WIFI_TextInputModel* model) { + UNUSED(wifi_text_input); + if(model->selected_column > 0) { + model->selected_column--; + } else { + model->selected_column = get_row_size(model->selected_row) - 1; + } +} + +static void + wifi_text_input_handle_right(WIFI_TextInput* wifi_text_input, WIFI_TextInputModel* model) { + UNUSED(wifi_text_input); + if(model->selected_column < get_row_size(model->selected_row) - 1) { + model->selected_column++; + } else { + model->selected_column = 0; + } +} + +static void wifi_text_input_handle_ok( + WIFI_TextInput* wifi_text_input, + WIFI_TextInputModel* model, + bool shift) { + char selected = get_selected_char(model); + uint8_t text_length = strlen(model->text_buffer); + + if(shift) { + selected = char_to_uppercase(selected); + } + + if(selected == ENTER_KEY) { + if(model->validator_callback && + (!model->validator_callback( + model->text_buffer, model->validator_text, model->validator_callback_context))) { + model->valadator_message_visible = true; + furi_timer_start(wifi_text_input->timer, furi_kernel_get_tick_frequency() * 4); + } else if(model->callback != 0 && text_length > 0) { + model->callback(model->callback_context); + } + } else if(selected == BACKSPACE_KEY) { + wifi_text_input_backspace_cb(model); + } else { + if(model->clear_default_text) { + text_length = 0; + } + if(text_length < (model->text_buffer_size - 1)) { + model->text_buffer[text_length] = selected; + model->text_buffer[text_length + 1] = 0; + } + } + model->clear_default_text = false; +} + +static bool wifi_text_input_view_input_callback(InputEvent* event, void* context) { + WIFI_TextInput* wifi_text_input = context; + furi_assert(wifi_text_input); + + bool consumed = false; + + // Acquire model + WIFI_TextInputModel* model = view_get_model(wifi_text_input->view); + + if((!(event->type == InputTypePress) && !(event->type == InputTypeRelease)) && + model->valadator_message_visible) { + model->valadator_message_visible = false; + consumed = true; + } else if(event->type == InputTypeShort) { + consumed = true; + switch(event->key) { + case InputKeyUp: + wifi_text_input_handle_up(wifi_text_input, model); + break; + case InputKeyDown: + wifi_text_input_handle_down(wifi_text_input, model); + break; + case InputKeyLeft: + wifi_text_input_handle_left(wifi_text_input, model); + break; + case InputKeyRight: + wifi_text_input_handle_right(wifi_text_input, model); + break; + case InputKeyOk: + wifi_text_input_handle_ok(wifi_text_input, model, false); + break; + default: + consumed = false; + break; + } + } else if(event->type == InputTypeLong) { + consumed = true; + switch(event->key) { + case InputKeyUp: + wifi_text_input_handle_up(wifi_text_input, model); + break; + case InputKeyDown: + wifi_text_input_handle_down(wifi_text_input, model); + break; + case InputKeyLeft: + wifi_text_input_handle_left(wifi_text_input, model); + break; + case InputKeyRight: + wifi_text_input_handle_right(wifi_text_input, model); + break; + case InputKeyOk: + wifi_text_input_handle_ok(wifi_text_input, model, true); + break; + case InputKeyBack: + wifi_text_input_backspace_cb(model); + break; + default: + consumed = false; + break; + } + } else if(event->type == InputTypeRepeat) { + consumed = true; + switch(event->key) { + case InputKeyUp: + wifi_text_input_handle_up(wifi_text_input, model); + break; + case InputKeyDown: + wifi_text_input_handle_down(wifi_text_input, model); + break; + case InputKeyLeft: + wifi_text_input_handle_left(wifi_text_input, model); + break; + case InputKeyRight: + wifi_text_input_handle_right(wifi_text_input, model); + break; + case InputKeyBack: + wifi_text_input_backspace_cb(model); + break; + default: + consumed = false; + break; + } + } + + // Commit model + view_commit_model(wifi_text_input->view, consumed); + + return consumed; +} + +void wifi_text_input_timer_callback(void* context) { + furi_assert(context); + WIFI_TextInput* wifi_text_input = context; + + with_view_model( + wifi_text_input->view, + WIFI_TextInputModel * model, + { model->valadator_message_visible = false; }, + true); +} + +WIFI_TextInput* wifi_text_input_alloc() { + WIFI_TextInput* wifi_text_input = malloc(sizeof(WIFI_TextInput)); + wifi_text_input->view = view_alloc(); + view_set_context(wifi_text_input->view, wifi_text_input); + view_allocate_model(wifi_text_input->view, ViewModelTypeLocking, sizeof(WIFI_TextInputModel)); + view_set_draw_callback(wifi_text_input->view, wifi_text_input_view_draw_callback); + view_set_input_callback(wifi_text_input->view, wifi_text_input_view_input_callback); + + wifi_text_input->timer = + furi_timer_alloc(wifi_text_input_timer_callback, FuriTimerTypeOnce, wifi_text_input); + + with_view_model( + wifi_text_input->view, + WIFI_TextInputModel * model, + { model->validator_text = furi_string_alloc(); }, + false); + + wifi_text_input_reset(wifi_text_input); + + return wifi_text_input; +} + +void wifi_text_input_free(WIFI_TextInput* wifi_text_input) { + furi_assert(wifi_text_input); + with_view_model( + wifi_text_input->view, + WIFI_TextInputModel * model, + { furi_string_free(model->validator_text); }, + false); + + // Send stop command + furi_timer_stop(wifi_text_input->timer); + // Release allocated memory + furi_timer_free(wifi_text_input->timer); + + view_free(wifi_text_input->view); + + free(wifi_text_input); +} + +void wifi_text_input_reset(WIFI_TextInput* wifi_text_input) { + furi_assert(wifi_text_input); + with_view_model( + wifi_text_input->view, + WIFI_TextInputModel * model, + { + model->text_buffer_size = 0; + model->header = ""; + model->selected_row = 0; + model->selected_column = 0; + model->clear_default_text = false; + model->text_buffer = NULL; + model->text_buffer_size = 0; + model->callback = NULL; + model->callback_context = NULL; + model->validator_callback = NULL; + model->validator_callback_context = NULL; + furi_string_reset(model->validator_text); + model->valadator_message_visible = false; + }, + true); +} + +View* wifi_text_input_get_view(WIFI_TextInput* wifi_text_input) { + furi_assert(wifi_text_input); + return wifi_text_input->view; +} + +void wifi_text_input_set_result_callback( + WIFI_TextInput* wifi_text_input, + WIFI_TextInputCallback callback, + void* callback_context, + char* text_buffer, + size_t text_buffer_size, + bool clear_default_text) { + with_view_model( + wifi_text_input->view, + WIFI_TextInputModel * model, + { + model->callback = callback; + model->callback_context = callback_context; + model->text_buffer = text_buffer; + model->text_buffer_size = text_buffer_size; + model->clear_default_text = clear_default_text; + if(text_buffer && text_buffer[0] != '\0') { + // Set focus on Save + model->selected_row = 2; + model->selected_column = 8; + } + }, + true); +} + +void wifi_text_input_set_validator( + WIFI_TextInput* wifi_text_input, + WIFI_TextInputValidatorCallback callback, + void* callback_context) { + with_view_model( + wifi_text_input->view, + WIFI_TextInputModel * model, + { + model->validator_callback = callback; + model->validator_callback_context = callback_context; + }, + true); +} + +WIFI_TextInputValidatorCallback + wifi_text_input_get_validator_callback(WIFI_TextInput* wifi_text_input) { + WIFI_TextInputValidatorCallback validator_callback = NULL; + with_view_model( + wifi_text_input->view, + WIFI_TextInputModel * model, + { validator_callback = model->validator_callback; }, + false); + return validator_callback; +} + +void* wifi_text_input_get_validator_callback_context(WIFI_TextInput* wifi_text_input) { + void* validator_callback_context = NULL; + with_view_model( + wifi_text_input->view, + WIFI_TextInputModel * model, + { validator_callback_context = model->validator_callback_context; }, + false); + return validator_callback_context; +} + +void wifi_text_input_set_header_text(WIFI_TextInput* wifi_text_input, const char* text) { + with_view_model( + wifi_text_input->view, WIFI_TextInputModel * model, { model->header = text; }, true); +} diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_text_input.h b/applications/external/wifi_marauder_companion/wifi_marauder_text_input.h new file mode 100644 index 000000000..b6b1f7bdf --- /dev/null +++ b/applications/external/wifi_marauder_companion/wifi_marauder_text_input.h @@ -0,0 +1,82 @@ +#pragma once + +#include +#include "wifi_marauder_validators.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Text input anonymous structure */ +typedef struct WIFI_TextInput WIFI_TextInput; +typedef void (*WIFI_TextInputCallback)(void* context); +typedef bool (*WIFI_TextInputValidatorCallback)(const char* text, FuriString* error, void* context); + +/** Allocate and initialize text input + * + * This text input is used to enter string + * + * @return WIFI_TextInput instance + */ +WIFI_TextInput* wifi_text_input_alloc(); + +/** Deinitialize and free text input + * + * @param wifi_text_input WIFI_TextInput instance + */ +void wifi_text_input_free(WIFI_TextInput* wifi_text_input); + +/** Clean text input view Note: this function does not free memory + * + * @param wifi_text_input Text input instance + */ +void wifi_text_input_reset(WIFI_TextInput* wifi_text_input); + +/** Get text input view + * + * @param wifi_text_input WIFI_TextInput instance + * + * @return View instance that can be used for embedding + */ +View* wifi_text_input_get_view(WIFI_TextInput* wifi_text_input); + +/** Set text input result callback + * + * @param wifi_text_input WIFI_TextInput instance + * @param callback callback fn + * @param callback_context callback context + * @param text_buffer pointer to YOUR text buffer, that we going + * to modify + * @param text_buffer_size YOUR text buffer size in bytes. Max string + * length will be text_buffer_size-1. + * @param clear_default_text clear text from text_buffer on first OK + * event + */ +void wifi_text_input_set_result_callback( + WIFI_TextInput* wifi_text_input, + WIFI_TextInputCallback callback, + void* callback_context, + char* text_buffer, + size_t text_buffer_size, + bool clear_default_text); + +void wifi_text_input_set_validator( + WIFI_TextInput* wifi_text_input, + WIFI_TextInputValidatorCallback callback, + void* callback_context); + +WIFI_TextInputValidatorCallback + wifi_text_input_get_validator_callback(WIFI_TextInput* wifi_text_input); + +void* wifi_text_input_get_validator_callback_context(WIFI_TextInput* wifi_text_input); + +/** Set text input header text + * + * @param wifi_text_input WIFI_TextInput instance + * @param text text to be shown + */ +void wifi_text_input_set_header_text(WIFI_TextInput* wifi_text_input, const char* text); + +#ifdef __cplusplus +} +#endif diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_validators.c b/applications/external/wifi_marauder_companion/wifi_marauder_validators.c new file mode 100644 index 000000000..5bec88269 --- /dev/null +++ b/applications/external/wifi_marauder_companion/wifi_marauder_validators.c @@ -0,0 +1,57 @@ +#include +#include "wifi_marauder_validators.h" +#include + +struct ValidatorIsFile { + char* app_path_folder; + const char* app_extension; + char* current_name; +}; + +bool validator_is_file_callback(const char* text, FuriString* error, void* context) { + furi_assert(context); + ValidatorIsFile* instance = context; + + if(instance->current_name != NULL) { + if(strcmp(instance->current_name, text) == 0) { + return true; + } + } + + bool ret = true; + FuriString* path = furi_string_alloc_printf( + "%s/%s%s", instance->app_path_folder, text, instance->app_extension); + Storage* storage = furi_record_open(RECORD_STORAGE); + if(storage_common_stat(storage, furi_string_get_cstr(path), NULL) == FSE_OK) { + ret = false; + furi_string_printf(error, "This name\nexists!\nChoose\nanother one."); + } else { + ret = true; + } + furi_string_free(path); + furi_record_close(RECORD_STORAGE); + + return ret; +} + +ValidatorIsFile* validator_is_file_alloc_init( + const char* app_path_folder, + const char* app_extension, + const char* current_name) { + ValidatorIsFile* instance = malloc(sizeof(ValidatorIsFile)); + + instance->app_path_folder = strdup(app_path_folder); + instance->app_extension = app_extension; + if(current_name != NULL) { + instance->current_name = strdup(current_name); + } + + return instance; +} + +void validator_is_file_free(ValidatorIsFile* instance) { + furi_assert(instance); + free(instance->app_path_folder); + free(instance->current_name); + free(instance); +} diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_validators.h b/applications/external/wifi_marauder_companion/wifi_marauder_validators.h new file mode 100644 index 000000000..d9200b6db --- /dev/null +++ b/applications/external/wifi_marauder_companion/wifi_marauder_validators.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif +typedef struct ValidatorIsFile ValidatorIsFile; + +ValidatorIsFile* validator_is_file_alloc_init( + const char* app_path_folder, + const char* app_extension, + const char* current_name); + +void validator_is_file_free(ValidatorIsFile* instance); + +bool validator_is_file_callback(const char* text, FuriString* error, void* context); + +#ifdef __cplusplus +} +#endif diff --git a/applications/main/fap_loader/fap_loader_app.c b/applications/main/fap_loader/fap_loader_app.c index 391efa80c..b313d67ad 100644 --- a/applications/main/fap_loader/fap_loader_app.c +++ b/applications/main/fap_loader/fap_loader_app.c @@ -1,6 +1,7 @@ #include "fap_loader_app.h" #include +#include #include #include @@ -24,8 +25,6 @@ struct FapLoader { Loading* loading; }; -volatile bool fap_loader_debug_active = false; - bool fap_loader_load_name_and_icon( FuriString* path, Storage* storage, @@ -154,7 +153,7 @@ static bool fap_loader_run_selected_app(FapLoader* loader, bool ignore_mismatch) FuriThread* thread = flipper_application_spawn(loader->app, NULL); /* This flag is set by the debugger - to break on app start */ - if(fap_loader_debug_active) { + if(furi_hal_debug_is_gdb_session_active()) { FURI_LOG_W(TAG, "Triggering BP for debugger"); /* After hitting this, you can set breakpoints in your .fap's code * Note that you have to toggle breakpoints that were set before */ diff --git a/applications/main/subghz/helpers/subghz_types.h b/applications/main/subghz/helpers/subghz_types.h index 270fd7a21..3c5982427 100644 --- a/applications/main/subghz/helpers/subghz_types.h +++ b/applications/main/subghz/helpers/subghz_types.h @@ -35,12 +35,6 @@ typedef enum { SubGhzSpeakerStateEnable, } SubGhzSpeakerState; -/** SubGhzStarLineIgnore state */ -typedef enum { - SubGhzStarLineIgnoreDisable, - SubGhzStarLineIgnoreEnable, -} SubGhzStarLineIgnoreState; - /** SubGhzRxKeyState state */ typedef enum { SubGhzRxKeyStateIDLE, diff --git a/applications/main/subghz/scenes/subghz_scene_config.h b/applications/main/subghz/scenes/subghz_scene_config.h index 5acd534dc..6fb183d60 100644 --- a/applications/main/subghz/scenes/subghz_scene_config.h +++ b/applications/main/subghz/scenes/subghz_scene_config.h @@ -19,12 +19,9 @@ ADD_SCENE(subghz, test_static, TestStatic) ADD_SCENE(subghz, test_packet, TestPacket) #endif ADD_SCENE(subghz, set_type, SetType) -ADD_SCENE(subghz, set_fix_faac, SetFixFaac) -ADD_SCENE(subghz, set_cnt_faac, SetCntFaac) -ADD_SCENE(subghz, set_seed_faac, SetSeedFaac) -ADD_SCENE(subghz, set_fix_bft, SetFixBft) -ADD_SCENE(subghz, set_cnt_bft, SetCntBft) -ADD_SCENE(subghz, set_seed_bft, SetSeedBft) +ADD_SCENE(subghz, set_fix, SetFix) +ADD_SCENE(subghz, set_cnt, SetCnt) +ADD_SCENE(subghz, set_seed, SetSeed) ADD_SCENE(subghz, frequency_analyzer, FrequencyAnalyzer) ADD_SCENE(subghz, ext_module_settings, ExtModuleSettings) ADD_SCENE(subghz, read_raw, ReadRAW) diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index 5746efbed..5ac4fcccd 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -62,26 +62,31 @@ static void subghz_scene_add_to_history_callback( void* context) { furi_assert(context); SubGhz* subghz = context; - FuriString* str_buff; - str_buff = furi_string_alloc(); + FuriString* item_name; + FuriString* item_time; + uint16_t idx = subghz_history_get_item(subghz->txrx->history); + item_name = furi_string_alloc(); + item_time = furi_string_alloc(); if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) { - furi_string_reset(str_buff); + furi_string_reset(item_name); + furi_string_reset(item_time); subghz->state_notifications = SubGhzNotificationStateRxDone; - subghz_history_get_text_item_menu( - subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1); + subghz_history_get_text_item_menu(subghz->txrx->history, item_name, idx); + subghz_history_get_time_item_menu(subghz->txrx->history, item_time, idx); subghz_view_receiver_add_item_to_menu( subghz->subghz_receiver, - furi_string_get_cstr(str_buff), - subghz_history_get_type_protocol( - subghz->txrx->history, subghz_history_get_item(subghz->txrx->history) - 1)); + furi_string_get_cstr(item_name), + furi_string_get_cstr(item_time), + subghz_history_get_type_protocol(subghz->txrx->history, idx)); subghz_scene_receiver_update_statusbar(subghz); } subghz_receiver_reset(receiver); - furi_string_free(str_buff); + furi_string_free(item_name); + furi_string_free(item_time); } bool subghz_scene_decode_raw_start(SubGhz* subghz) { @@ -159,8 +164,10 @@ bool subghz_scene_decode_raw_next(SubGhz* subghz) { void subghz_scene_decode_raw_on_enter(void* context) { SubGhz* subghz = context; - FuriString* str_buff; - str_buff = furi_string_alloc(); + FuriString* item_name; + FuriString* item_time; + item_name = furi_string_alloc(); + item_time = furi_string_alloc(); subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz->lock); subghz_view_receiver_set_mode(subghz->subghz_receiver, SubGhzViewReceiverModeFile); @@ -183,14 +190,18 @@ void subghz_scene_decode_raw_on_enter(void* context) { //Load history to receiver subghz_view_receiver_exit(subghz->subghz_receiver); for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) { - furi_string_reset(str_buff); - subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i); + furi_string_reset(item_name); + furi_string_reset(item_time); + subghz_history_get_text_item_menu(subghz->txrx->history, item_name, i); + subghz_history_get_time_item_menu(subghz->txrx->history, item_time, i); subghz_view_receiver_add_item_to_menu( subghz->subghz_receiver, - furi_string_get_cstr(str_buff), + furi_string_get_cstr(item_name), + furi_string_get_cstr(item_time), subghz_history_get_type_protocol(subghz->txrx->history, i)); } - furi_string_free(str_buff); + furi_string_free(item_name); + furi_string_free(item_time); subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen); } diff --git a/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c b/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c index 6bd97c805..767589693 100644 --- a/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c @@ -1,10 +1,11 @@ #include "../subghz_i.h" #include "../helpers/subghz_custom_event.h" -uint8_t value_index_exm; -uint8_t value_index_dpin; -uint8_t value_index_cnt; -uint8_t value_index_pwr; +static uint8_t value_index_exm; +static uint8_t value_index_dpin; +static uint8_t value_index_cnt; +static uint8_t value_index_pwr; +static uint8_t value_index_time; #define EXT_MODULES_COUNT (sizeof(radio_modules_variables_text) / sizeof(char* const)) const char* const radio_modules_variables_text[] = { @@ -18,6 +19,12 @@ const char* const ext_mod_power_text[EXT_MOD_POWER_COUNT] = { "OFF", }; +#define TIMESTAMP_NAMES_COUNT 2 +const char* const timestamp_names_text[TIMESTAMP_NAMES_COUNT] = { + "OFF", + "ON", +}; + #define DEBUG_P_COUNT 2 const char* const debug_pin_text[DEBUG_P_COUNT] = { "OFF", @@ -104,6 +111,17 @@ static void subghz_scene_receiver_config_set_ext_mod_power(VariableItem* item) { subghz_last_settings_save(subghz->last_settings); } +static void subghz_scene_receiver_config_set_timestamp_file_names(VariableItem* item) { + SubGhz* subghz = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, timestamp_names_text[index]); + + furi_hal_subghz_set_timestamp_file_names((index == 1)); + subghz->last_settings->timestamp_file_names = (index == 1); + subghz_last_settings_save(subghz->last_settings); +} + void subghz_scene_ext_module_settings_on_enter(void* context) { SubGhz* subghz = context; @@ -129,6 +147,16 @@ void subghz_scene_ext_module_settings_on_enter(void* context) { variable_item_set_current_value_index(item, value_index_pwr); variable_item_set_current_value_text(item, ext_mod_power_text[value_index_pwr]); + item = variable_item_list_add( + subghz->variable_item_list, + "Time in names", + TIMESTAMP_NAMES_COUNT, + subghz_scene_receiver_config_set_timestamp_file_names, + subghz); + value_index_time = furi_hal_subghz_get_timestamp_file_names(); + variable_item_set_current_value_index(item, value_index_time); + variable_item_set_current_value_text(item, timestamp_names_text[value_index_time]); + item = variable_item_list_add( subghz->variable_item_list, "Debug Pin", diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 1e3d6a9c0..0c692e000 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -239,7 +239,11 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) { subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); + subghz_read_raw_set_status( + subghz->subghz_read_raw, + SubGhzReadRAWStatusIDLE, + "", + subghz->txrx->raw_threshold_rssi); } else { if(scene_manager_has_previous_scene( subghz->scene_manager, SubGhzSceneSaved) || diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 08fed3aa4..b17a0700b 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -91,34 +91,41 @@ static void subghz_scene_add_to_history_callback( void* context) { furi_assert(context); SubGhz* subghz = context; - FuriString* str_buff; - str_buff = furi_string_alloc(); + FuriString* item_name; + FuriString* item_time; + uint16_t idx = subghz_history_get_item(subghz->txrx->history); + item_name = furi_string_alloc(); + item_time = furi_string_alloc(); if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) { - furi_string_reset(str_buff); + furi_string_reset(item_name); + furi_string_reset(item_time); subghz->state_notifications = SubGhzNotificationStateRxDone; - subghz_history_get_text_item_menu( - subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1); + subghz_history_get_text_item_menu(subghz->txrx->history, item_name, idx); + subghz_history_get_time_item_menu(subghz->txrx->history, item_time, idx); subghz_view_receiver_add_item_to_menu( subghz->subghz_receiver, - furi_string_get_cstr(str_buff), - subghz_history_get_type_protocol( - subghz->txrx->history, subghz_history_get_item(subghz->txrx->history) - 1)); + furi_string_get_cstr(item_name), + furi_string_get_cstr(item_time), + subghz_history_get_type_protocol(subghz->txrx->history, idx)); subghz_scene_receiver_update_statusbar(subghz); } subghz_receiver_reset(receiver); - furi_string_free(str_buff); + furi_string_free(item_name); + furi_string_free(item_time); subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; } void subghz_scene_receiver_on_enter(void* context) { SubGhz* subghz = context; - FuriString* str_buff; - str_buff = furi_string_alloc(); + FuriString* item_name; + FuriString* item_time; + item_name = furi_string_alloc(); + item_time = furi_string_alloc(); if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) { subghz_preset_init(subghz, "AM650", subghz->last_settings->frequency, NULL, 0); @@ -132,22 +139,28 @@ void subghz_scene_receiver_on_enter(void* context) { //Load history to receiver subghz_view_receiver_exit(subghz->subghz_receiver); for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) { - furi_string_reset(str_buff); - subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i); + furi_string_reset(item_name); + furi_string_reset(item_time); + subghz_history_get_text_item_menu(subghz->txrx->history, item_name, i); + subghz_history_get_time_item_menu(subghz->txrx->history, item_time, i); subghz_view_receiver_add_item_to_menu( subghz->subghz_receiver, - furi_string_get_cstr(str_buff), + furi_string_get_cstr(item_name), + furi_string_get_cstr(item_time), subghz_history_get_type_protocol(subghz->txrx->history, i)); subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; } - furi_string_free(str_buff); + furi_string_free(item_name); + furi_string_free(item_time); subghz_scene_receiver_update_statusbar(subghz); subghz_view_receiver_set_callback( subghz->subghz_receiver, subghz_scene_receiver_callback, subghz); subghz_receiver_set_rx_callback( subghz->txrx->receiver, subghz_scene_add_to_history_callback, subghz); - if(subghz->txrx->starline_state == SubGhzStarLineIgnoreEnable) { + // TODO: Replace with proper solution based on protocol flags, remove kostily and velosipedy from here + // Needs to be done after subghz refactoring merge!!! + if(subghz->txrx->ignore_starline == true) { SubGhzProtocolDecoderBase* protocoldecoderbase = NULL; protocoldecoderbase = subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, "Star Line"); @@ -156,6 +169,31 @@ void subghz_scene_receiver_on_enter(void* context) { protocoldecoderbase, NULL, subghz->txrx->receiver); } } + if(subghz->txrx->ignore_auto_alarms == true) { + SubGhzProtocolDecoderBase* protocoldecoderbase = NULL; + protocoldecoderbase = + subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, "KIA Seed"); + if(protocoldecoderbase) { + subghz_protocol_decoder_base_set_decoder_callback( + protocoldecoderbase, NULL, subghz->txrx->receiver); + } + protocoldecoderbase = NULL; + protocoldecoderbase = + subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, "Scher-Khan"); + if(protocoldecoderbase) { + subghz_protocol_decoder_base_set_decoder_callback( + protocoldecoderbase, NULL, subghz->txrx->receiver); + } + } + if(subghz->txrx->ignore_magellan == true) { + SubGhzProtocolDecoderBase* protocoldecoderbase = NULL; + protocoldecoderbase = + subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, "Magellan"); + if(protocoldecoderbase) { + subghz_protocol_decoder_base_set_decoder_callback( + protocoldecoderbase, NULL, subghz->txrx->receiver); + } + } subghz->state_notifications = SubGhzNotificationStateRx; if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index 6a6cf860b..68c5b4b7a 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -7,6 +7,8 @@ enum SubGhzSettingIndex { SubGhzSettingIndexModulation, SubGhzSettingIndexBinRAW, SubGhzSettingIndexIgnoreStarline, + SubGhzSettingIndexIgnoreCars, + SubGhzSettingIndexIgnoreMagellan, SubGhzSettingIndexSound, SubGhzSettingIndexLock, SubGhzSettingIndexRAWThresholdRSSI, @@ -69,14 +71,22 @@ const uint32_t bin_raw_value[BIN_RAW_COUNT] = { SubGhzProtocolFlag_Decodable, SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_BinRAW, }; -#define STAR_LINE_COUNT 2 -const char* const star_line_text[STAR_LINE_COUNT] = { +#define STARLINE_COUNT 2 +const char* const starline_text[STARLINE_COUNT] = { "OFF", "ON", }; -const uint32_t star_line_value[STAR_LINE_COUNT] = { - SubGhzStarLineIgnoreDisable, - SubGhzStarLineIgnoreEnable, + +#define AUTO_ALARMS_COUNT 2 +const char* const auto_alarms_text[AUTO_ALARMS_COUNT] = { + "OFF", + "ON", +}; + +#define MAGELLAN_COUNT 2 +const char* const magellan_text[MAGELLAN_COUNT] = { + "OFF", + "ON", }; uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) { @@ -231,8 +241,24 @@ static void subghz_scene_receiver_config_set_starline(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, star_line_text[index]); - subghz->txrx->starline_state = star_line_value[index]; + variable_item_set_current_value_text(item, starline_text[index]); + subghz->txrx->ignore_starline = (index == 1); +} + +static void subghz_scene_receiver_config_set_auto_alarms(VariableItem* item) { + SubGhz* subghz = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, auto_alarms_text[index]); + subghz->txrx->ignore_auto_alarms = (index == 1); +} + +static void subghz_scene_receiver_config_set_magellan(VariableItem* item) { + SubGhz* subghz = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, magellan_text[index]); + subghz->txrx->ignore_magellan = (index == 1); } static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) { @@ -313,15 +339,36 @@ void subghz_scene_receiver_config_on_enter(void* context) { SubGhzCustomEventManagerSet) { item = variable_item_list_add( subghz->variable_item_list, - "Ignore StarLine:", - STAR_LINE_COUNT, + "Ignore Starline:", + STARLINE_COUNT, subghz_scene_receiver_config_set_starline, subghz); - value_index = - value_index_uint32(subghz->txrx->starline_state, star_line_value, STAR_LINE_COUNT); + value_index = subghz->txrx->ignore_starline; variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, star_line_text[value_index]); + variable_item_set_current_value_text(item, starline_text[value_index]); + + item = variable_item_list_add( + subghz->variable_item_list, + "Ignore Cars:", + AUTO_ALARMS_COUNT, + subghz_scene_receiver_config_set_auto_alarms, + subghz); + + value_index = subghz->txrx->ignore_auto_alarms; + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, auto_alarms_text[value_index]); + + item = variable_item_list_add( + subghz->variable_item_list, + "Ignore Magellan:", + MAGELLAN_COUNT, + subghz_scene_receiver_config_set_magellan, + subghz); + + value_index = subghz->txrx->ignore_magellan; + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, magellan_text[value_index]); } // Enable speaker, will send all incoming noises and signals to speaker so you can listen how your remote sounds like :) diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 99765ee16..58e428785 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -115,6 +115,9 @@ void subghz_scene_receiver_info_draw_widget(SubGhz* subghz) { void subghz_scene_receiver_info_on_enter(void* context) { SubGhz* subghz = context; + keeloq_reset_original_btn(); + subghz_custom_btns_reset(); + subghz_scene_receiver_info_draw_widget(subghz); } diff --git a/applications/main/subghz/scenes/subghz_scene_save_name.c b/applications/main/subghz/scenes/subghz_scene_save_name.c index 4f37ebc0b..d3f5474be 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_name.c +++ b/applications/main/subghz/scenes/subghz_scene_save_name.c @@ -14,18 +14,34 @@ void subghz_scene_save_name_text_input_callback(void* context) { view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneSaveName); } -void subghz_scene_save_name_get_timefilename(FuriString* name) { +void subghz_scene_save_name_get_timefilename( + FuriString* name, + const char* proto_name, + bool fulldate) { FuriHalRtcDateTime datetime = {0}; furi_hal_rtc_get_datetime(&datetime); - furi_string_printf( - name, - "RAW_%.4d%.2d%.2d-%.2d%.2d%.2d", - datetime.year, - datetime.month, - datetime.day, - datetime.hour, - datetime.minute, - datetime.second); + if(fulldate) { + furi_string_printf( + name, + "%s_%.4d%.2d%.2d-%.2d%.2d%.2d", + proto_name, + datetime.year, + datetime.month, + datetime.day, + datetime.hour, + datetime.minute, + datetime.second); + } else { + furi_string_printf( + name, + "%s_%.2d%.2d-%.2d%.2d%.2d", + proto_name, + datetime.month, + datetime.day, + datetime.hour, + datetime.minute, + datetime.second); + } } void subghz_scene_save_name_on_enter(void* context) { @@ -42,8 +58,31 @@ void subghz_scene_save_name_on_enter(void* context) { if(!subghz_path_is_file(subghz->file_path)) { char file_name_buf[SUBGHZ_MAX_LEN_NAME] = {0}; - set_random_name(file_name_buf, SUBGHZ_MAX_LEN_NAME); - furi_string_set(file_name, file_name_buf); + if(furi_hal_subghz_get_timestamp_file_names()) { + if(subghz->txrx->decoder_result != 0x0) { + if(subghz->txrx->decoder_result != NULL) { + if(strlen(subghz->txrx->decoder_result->protocol->name) != 0) { + if(scene_manager_has_previous_scene( + subghz->scene_manager, SubGhzSceneSetType)) { + subghz_scene_save_name_get_timefilename(file_name, "S", true); + } else { + subghz_scene_save_name_get_timefilename( + file_name, subghz->txrx->decoder_result->protocol->name, false); + } + + } else { + subghz_scene_save_name_get_timefilename(file_name, "S", true); + } + } else { + subghz_scene_save_name_get_timefilename(file_name, "S", true); + } + } else { + subghz_scene_save_name_get_timefilename(file_name, "S", true); + } + } else { + set_random_name(file_name_buf, SUBGHZ_MAX_LEN_NAME); + furi_string_set(file_name, file_name_buf); + } furi_string_set(subghz->file_path, SUBGHZ_APP_FOLDER); //highlighting the entire filename by default dev_name_empty = true; @@ -57,7 +96,7 @@ void subghz_scene_save_name_on_enter(void* context) { if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) == SubGhzCustomEventManagerSetRAW) { dev_name_empty = true; - subghz_scene_save_name_get_timefilename(file_name); + subghz_scene_save_name_get_timefilename(file_name, "RAW", true); } } furi_string_set(subghz->file_path, dir_name); diff --git a/applications/main/subghz/scenes/subghz_scene_set_cnt.c b/applications/main/subghz/scenes/subghz_scene_set_cnt.c new file mode 100644 index 000000000..62ef581ff --- /dev/null +++ b/applications/main/subghz/scenes/subghz_scene_set_cnt.c @@ -0,0 +1,66 @@ +#include "../subghz_i.h" + +#define TAG "SubGhzSetCnt" + +void subghz_scene_set_cnt_byte_input_callback(void* context) { + SubGhz* subghz = context; + + view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone); +} + +void subghz_scene_set_cnt_on_enter(void* context) { + SubGhz* subghz = context; + + // Setup view + ByteInput* byte_input = subghz->byte_input; + SubGhzCustomEvent state = + scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType); + + switch(state) { + case SubmenuIndexBFTClone: + byte_input_set_header_text(byte_input, "Enter COUNTER in hex"); + byte_input_set_result_callback( + byte_input, + subghz_scene_set_cnt_byte_input_callback, + NULL, + subghz, + subghz->txrx->secure_data->cnt, + 2); + break; + case SubmenuIndexFaacSLH_433: + case SubmenuIndexFaacSLH_868: + byte_input_set_header_text(byte_input, "Enter COUNTER in hex, 20bits"); + byte_input_set_result_callback( + byte_input, + subghz_scene_set_cnt_byte_input_callback, + NULL, + subghz, + subghz->txrx->secure_data->cnt, + 3); + break; + default: + break; + } + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); +} + +bool subghz_scene_set_cnt_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubGhzCustomEventByteInputDone) { + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetSeed); + consumed = true; + } + } + return consumed; +} + +void subghz_scene_set_cnt_on_exit(void* context) { + SubGhz* subghz = context; + + // Clear view + byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(subghz->byte_input, ""); +} diff --git a/applications/main/subghz/scenes/subghz_scene_set_cnt_bft.c b/applications/main/subghz/scenes/subghz_scene_set_cnt_bft.c deleted file mode 100644 index d58409a7e..000000000 --- a/applications/main/subghz/scenes/subghz_scene_set_cnt_bft.c +++ /dev/null @@ -1,46 +0,0 @@ -#include "../subghz_i.h" - -#define TAG "SubGhzSetCntBft" - -void subghz_scene_set_cnt_bft_byte_input_callback(void* context) { - SubGhz* subghz = context; - - view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone); -} - -void subghz_scene_set_cnt_bft_on_enter(void* context) { - SubGhz* subghz = context; - - // Setup view - ByteInput* byte_input = subghz->byte_input; - byte_input_set_header_text(byte_input, "Enter COUNTER in hex"); - byte_input_set_result_callback( - byte_input, - subghz_scene_set_cnt_bft_byte_input_callback, - NULL, - subghz, - subghz->txrx->secure_data->cnt, - 2); - view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); -} - -bool subghz_scene_set_cnt_bft_on_event(void* context, SceneManagerEvent event) { - SubGhz* subghz = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubGhzCustomEventByteInputDone) { - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetSeedBft); - consumed = true; - } - } - return consumed; -} - -void subghz_scene_set_cnt_bft_on_exit(void* context) { - SubGhz* subghz = context; - - // Clear view - byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0); - byte_input_set_header_text(subghz->byte_input, ""); -} diff --git a/applications/main/subghz/scenes/subghz_scene_set_cnt_faac.c b/applications/main/subghz/scenes/subghz_scene_set_cnt_faac.c deleted file mode 100644 index 6002dea74..000000000 --- a/applications/main/subghz/scenes/subghz_scene_set_cnt_faac.c +++ /dev/null @@ -1,46 +0,0 @@ -#include "../subghz_i.h" - -#define TAG "SubGhzSetCntFaac" - -void subghz_scene_set_cnt_faac_byte_input_callback(void* context) { - SubGhz* subghz = context; - - view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone); -} - -void subghz_scene_set_cnt_faac_on_enter(void* context) { - SubGhz* subghz = context; - - // Setup view - ByteInput* byte_input = subghz->byte_input; - byte_input_set_header_text(byte_input, "Enter COUNTER in hex, 20bits"); - byte_input_set_result_callback( - byte_input, - subghz_scene_set_cnt_faac_byte_input_callback, - NULL, - subghz, - subghz->txrx->secure_data->cnt, - 3); - view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); -} - -bool subghz_scene_set_cnt_faac_on_event(void* context, SceneManagerEvent event) { - SubGhz* subghz = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubGhzCustomEventByteInputDone) { - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetSeedFaac); - consumed = true; - } - } - return consumed; -} - -void subghz_scene_set_cnt_faac_on_exit(void* context) { - SubGhz* subghz = context; - - // Clear view - byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0); - byte_input_set_header_text(subghz->byte_input, ""); -} diff --git a/applications/main/subghz/scenes/subghz_scene_set_fix_bft.c b/applications/main/subghz/scenes/subghz_scene_set_fix.c similarity index 74% rename from applications/main/subghz/scenes/subghz_scene_set_fix_bft.c rename to applications/main/subghz/scenes/subghz_scene_set_fix.c index 8153fa2a0..01431dac6 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_fix_bft.c +++ b/applications/main/subghz/scenes/subghz_scene_set_fix.c @@ -1,14 +1,14 @@ #include "../subghz_i.h" -#define TAG "SubGhzSetFixBft" +#define TAG "SubGhzSetFix" -void subghz_scene_set_fix_bft_byte_input_callback(void* context) { +void subghz_scene_set_fix_byte_input_callback(void* context) { SubGhz* subghz = context; view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone); } -void subghz_scene_set_fix_bft_on_enter(void* context) { +void subghz_scene_set_fix_on_enter(void* context) { SubGhz* subghz = context; // Setup view @@ -16,7 +16,7 @@ void subghz_scene_set_fix_bft_on_enter(void* context) { byte_input_set_header_text(byte_input, "Enter FIX in hex"); byte_input_set_result_callback( byte_input, - subghz_scene_set_fix_bft_byte_input_callback, + subghz_scene_set_fix_byte_input_callback, NULL, subghz, subghz->txrx->secure_data->fix, @@ -24,20 +24,20 @@ void subghz_scene_set_fix_bft_on_enter(void* context) { view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); } -bool subghz_scene_set_fix_bft_on_event(void* context, SceneManagerEvent event) { +bool subghz_scene_set_fix_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventByteInputDone) { - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetCntBft); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetCnt); consumed = true; } } return consumed; } -void subghz_scene_set_fix_bft_on_exit(void* context) { +void subghz_scene_set_fix_on_exit(void* context) { SubGhz* subghz = context; // Clear view diff --git a/applications/main/subghz/scenes/subghz_scene_set_fix_faac.c b/applications/main/subghz/scenes/subghz_scene_set_fix_faac.c deleted file mode 100644 index 333062c38..000000000 --- a/applications/main/subghz/scenes/subghz_scene_set_fix_faac.c +++ /dev/null @@ -1,46 +0,0 @@ -#include "../subghz_i.h" - -#define TAG "SubGhzSetFixFaac" - -void subghz_scene_set_fix_faac_byte_input_callback(void* context) { - SubGhz* subghz = context; - - view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone); -} - -void subghz_scene_set_fix_faac_on_enter(void* context) { - SubGhz* subghz = context; - - // Setup view - ByteInput* byte_input = subghz->byte_input; - byte_input_set_header_text(byte_input, "Enter FIX in hex"); - byte_input_set_result_callback( - byte_input, - subghz_scene_set_fix_faac_byte_input_callback, - NULL, - subghz, - subghz->txrx->secure_data->fix, - 4); - view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); -} - -bool subghz_scene_set_fix_faac_on_event(void* context, SceneManagerEvent event) { - SubGhz* subghz = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubGhzCustomEventByteInputDone) { - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetCntFaac); - consumed = true; - } - } - return consumed; -} - -void subghz_scene_set_fix_faac_on_exit(void* context) { - SubGhz* subghz = context; - - // Clear view - byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0); - byte_input_set_header_text(subghz->byte_input, ""); -} diff --git a/applications/main/subghz/scenes/subghz_scene_set_seed.c b/applications/main/subghz/scenes/subghz_scene_set_seed.c new file mode 100644 index 000000000..aa2a270f3 --- /dev/null +++ b/applications/main/subghz/scenes/subghz_scene_set_seed.c @@ -0,0 +1,168 @@ +#include "../subghz_i.h" +#include +#include + +#define TAG "SubGhzSetSeed" + +void subghz_scene_set_seed_byte_input_callback(void* context) { + SubGhz* subghz = context; + + view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone); +} + +void subghz_scene_set_seed_on_enter(void* context) { + SubGhz* subghz = context; + + // Setup view + ByteInput* byte_input = subghz->byte_input; + byte_input_set_header_text(byte_input, "Enter SEED in hex"); + byte_input_set_result_callback( + byte_input, + subghz_scene_set_seed_byte_input_callback, + NULL, + subghz, + subghz->txrx->secure_data->seed, + 4); + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); +} + +bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + bool consumed = false; + bool generated_protocol = false; + uint32_t fix_part, cnt, seed; + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubGhzCustomEventByteInputDone) { + SubGhzCustomEvent state = + scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType); + + switch(state) { + case SubmenuIndexBFTClone: + fix_part = subghz->txrx->secure_data->fix[0] << 24 | + subghz->txrx->secure_data->fix[1] << 16 | + subghz->txrx->secure_data->fix[2] << 8 | + subghz->txrx->secure_data->fix[3]; + + cnt = subghz->txrx->secure_data->cnt[0] << 8 | subghz->txrx->secure_data->cnt[1]; + + seed = subghz->txrx->secure_data->seed[0] << 24 | + subghz->txrx->secure_data->seed[1] << 16 | + subghz->txrx->secure_data->seed[2] << 8 | + subghz->txrx->secure_data->seed[3]; + + subghz->txrx->transmitter = + subghz_transmitter_alloc_init(subghz->txrx->environment, "KeeLoq"); + if(subghz->txrx->transmitter) { + subghz_preset_init(subghz, "AM650", 433920000, NULL, 0); + subghz_protocol_keeloq_bft_create_data( + subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), + subghz->txrx->fff_data, + fix_part & 0x0FFFFFFF, + fix_part >> 28, + cnt, + seed, + "BFT", + subghz->txrx->preset); + + uint8_t seed_data[sizeof(uint32_t)] = {0}; + for(size_t i = 0; i < sizeof(uint32_t); i++) { + seed_data[sizeof(uint32_t) - i - 1] = (seed >> i * 8) & 0xFF; + } + + flipper_format_write_hex( + subghz->txrx->fff_data, "Seed", seed_data, sizeof(uint32_t)); + + flipper_format_write_string_cstr(subghz->txrx->fff_data, "Manufacture", "BFT"); + + generated_protocol = true; + } + + subghz_transmitter_free(subghz->txrx->transmitter); + + if(!generated_protocol) { + furi_string_set( + subghz->error_str, "Function requires\nan SD card with\nfresh databases."); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + } + consumed = true; + break; + case SubmenuIndexFaacSLH_433: + case SubmenuIndexFaacSLH_868: + fix_part = subghz->txrx->secure_data->fix[0] << 24 | + subghz->txrx->secure_data->fix[1] << 16 | + subghz->txrx->secure_data->fix[2] << 8 | + subghz->txrx->secure_data->fix[3]; + + cnt = subghz->txrx->secure_data->cnt[0] << 16 | + subghz->txrx->secure_data->cnt[1] << 8 | subghz->txrx->secure_data->cnt[2]; + + seed = subghz->txrx->secure_data->seed[0] << 24 | + subghz->txrx->secure_data->seed[1] << 16 | + subghz->txrx->secure_data->seed[2] << 8 | + subghz->txrx->secure_data->seed[3]; + + subghz->txrx->transmitter = + subghz_transmitter_alloc_init(subghz->txrx->environment, "Faac SLH"); + if(subghz->txrx->transmitter) { + SubGhzCustomEvent state = + scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType); + + if(state == SubmenuIndexFaacSLH_433) { + subghz_preset_init(subghz, "AM650", 433920000, NULL, 0); + } else if(state == SubmenuIndexFaacSLH_868) { + subghz_preset_init(subghz, "AM650", 868350000, NULL, 0); + } + subghz_protocol_faac_slh_create_data( + subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), + subghz->txrx->fff_data, + fix_part >> 4, + fix_part & 0xf, + (cnt & 0xFFFFF), + seed, + "FAAC_SLH", + subghz->txrx->preset); + // RogueMaster dont steal! + uint8_t seed_data[sizeof(uint32_t)] = {0}; + for(size_t i = 0; i < sizeof(uint32_t); i++) { + seed_data[sizeof(uint32_t) - i - 1] = (seed >> i * 8) & 0xFF; + } + + flipper_format_write_hex( + subghz->txrx->fff_data, "Seed", seed_data, sizeof(uint32_t)); + + generated_protocol = true; + } + + subghz_transmitter_free(subghz->txrx->transmitter); + + if(!generated_protocol) { + furi_string_set( + subghz->error_str, "Function requires\nan SD card with\nfresh databases."); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + } + consumed = true; + break; + + default: + break; + } + } + + if(generated_protocol) { + subghz_file_name_clear(subghz); + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneSetType, SubGhzCustomEventManagerSet); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); + return true; + } + } + return consumed; +} + +void subghz_scene_set_seed_on_exit(void* context) { + SubGhz* subghz = context; + + // Clear view + byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(subghz->byte_input, ""); +} diff --git a/applications/main/subghz/scenes/subghz_scene_set_seed_bft.c b/applications/main/subghz/scenes/subghz_scene_set_seed_bft.c deleted file mode 100644 index 2c48462ef..000000000 --- a/applications/main/subghz/scenes/subghz_scene_set_seed_bft.c +++ /dev/null @@ -1,105 +0,0 @@ -#include "../subghz_i.h" -#include -#include - -#define TAG "SubGhzSetSeedBft" - -void subghz_scene_set_seed_bft_byte_input_callback(void* context) { - SubGhz* subghz = context; - - view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone); -} - -void subghz_scene_set_seed_bft_on_enter(void* context) { - SubGhz* subghz = context; - - // Setup view - // RogueMaster don't steal!!! - ByteInput* byte_input = subghz->byte_input; - byte_input_set_header_text(byte_input, "Enter SEED in hex"); - byte_input_set_result_callback( - byte_input, - subghz_scene_set_seed_bft_byte_input_callback, - NULL, - subghz, - subghz->txrx->secure_data->seed, - 4); - view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); -} - -bool subghz_scene_set_seed_bft_on_event(void* context, SceneManagerEvent event) { - SubGhz* subghz = context; - bool consumed = false; - bool generated_protocol = false; - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubGhzCustomEventByteInputDone) { - uint32_t fix_part = - subghz->txrx->secure_data->fix[0] << 24 | subghz->txrx->secure_data->fix[1] << 16 | - subghz->txrx->secure_data->fix[2] << 8 | subghz->txrx->secure_data->fix[3]; - - uint16_t cnt = subghz->txrx->secure_data->cnt[0] << 8 | - subghz->txrx->secure_data->cnt[1]; - - uint32_t seed = subghz->txrx->secure_data->seed[0] << 24 | - subghz->txrx->secure_data->seed[1] << 16 | - subghz->txrx->secure_data->seed[2] << 8 | - subghz->txrx->secure_data->seed[3]; - - subghz->txrx->transmitter = - subghz_transmitter_alloc_init(subghz->txrx->environment, "KeeLoq"); - if(subghz->txrx->transmitter) { - subghz_preset_init(subghz, "AM650", 433920000, NULL, 0); - subghz_protocol_keeloq_bft_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - fix_part & 0x0FFFFFFF, - fix_part >> 28, - cnt, - seed, - "BFT", - subghz->txrx->preset); - - uint8_t seed_data[sizeof(uint32_t)] = {0}; - for(size_t i = 0; i < sizeof(uint32_t); i++) { - seed_data[sizeof(uint32_t) - i - 1] = (seed >> i * 8) & 0xFF; - } - - flipper_format_write_hex( - subghz->txrx->fff_data, "Seed", seed_data, sizeof(uint32_t)); - - flipper_format_write_string_cstr(subghz->txrx->fff_data, "Manufacture", "BFT"); - - generated_protocol = true; - } else { - generated_protocol = false; - } - - subghz_transmitter_free(subghz->txrx->transmitter); - - if(!generated_protocol) { - furi_string_set( - subghz->error_str, "Function requires\nan SD card with\nfresh databases."); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); - } - consumed = true; - } - - if(generated_protocol) { - subghz_file_name_clear(subghz); - DOLPHIN_DEED(DolphinDeedSubGhzAddManually); - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneSetType, SubGhzCustomEventManagerSet); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); - return true; - } - } - return consumed; -} - -void subghz_scene_set_seed_bft_on_exit(void* context) { - SubGhz* subghz = context; - - // Clear view - byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0); - byte_input_set_header_text(subghz->byte_input, ""); -} diff --git a/applications/main/subghz/scenes/subghz_scene_set_seed_faac.c b/applications/main/subghz/scenes/subghz_scene_set_seed_faac.c deleted file mode 100644 index 55387a0a5..000000000 --- a/applications/main/subghz/scenes/subghz_scene_set_seed_faac.c +++ /dev/null @@ -1,110 +0,0 @@ -#include "../subghz_i.h" -#include -#include - -#define TAG "SubGhzSetSeedFaac" - -void subghz_scene_set_seed_faac_byte_input_callback(void* context) { - SubGhz* subghz = context; - - view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone); -} - -void subghz_scene_set_seed_faac_on_enter(void* context) { - SubGhz* subghz = context; - - // Setup view - ByteInput* byte_input = subghz->byte_input; - byte_input_set_header_text(byte_input, "Enter SEED in hex"); - byte_input_set_result_callback( - byte_input, - subghz_scene_set_seed_faac_byte_input_callback, - NULL, - subghz, - subghz->txrx->secure_data->seed, - 4); - view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); -} - -bool subghz_scene_set_seed_faac_on_event(void* context, SceneManagerEvent event) { - SubGhz* subghz = context; - bool consumed = false; - bool generated_protocol = false; - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubGhzCustomEventByteInputDone) { - uint32_t fix_part = - subghz->txrx->secure_data->fix[0] << 24 | subghz->txrx->secure_data->fix[1] << 16 | - subghz->txrx->secure_data->fix[2] << 8 | subghz->txrx->secure_data->fix[3]; - - uint32_t cnt = subghz->txrx->secure_data->cnt[0] << 16 | - subghz->txrx->secure_data->cnt[1] << 8 | - subghz->txrx->secure_data->cnt[2]; - - uint32_t seed = subghz->txrx->secure_data->seed[0] << 24 | - subghz->txrx->secure_data->seed[1] << 16 | - subghz->txrx->secure_data->seed[2] << 8 | - subghz->txrx->secure_data->seed[3]; - - subghz->txrx->transmitter = - subghz_transmitter_alloc_init(subghz->txrx->environment, "Faac SLH"); - if(subghz->txrx->transmitter) { - SubGhzCustomEvent state = - scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType); - - if(state == SubmenuIndexFaacSLH_433) { - subghz_preset_init(subghz, "AM650", 433920000, NULL, 0); - } else if(state == SubmenuIndexFaacSLH_868) { - subghz_preset_init(subghz, "AM650", 868350000, NULL, 0); - } - subghz_protocol_faac_slh_create_data( - subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), - subghz->txrx->fff_data, - fix_part >> 4, - fix_part & 0xf, - (cnt & 0xFFFFF), - seed, - "FAAC_SLH", - subghz->txrx->preset); - // RogueMaster dont steal! - uint8_t seed_data[sizeof(uint32_t)] = {0}; - for(size_t i = 0; i < sizeof(uint32_t); i++) { - seed_data[sizeof(uint32_t) - i - 1] = (seed >> i * 8) & 0xFF; - } - - flipper_format_write_hex( - subghz->txrx->fff_data, "Seed", seed_data, sizeof(uint32_t)); - - generated_protocol = true; - } else { - generated_protocol = false; - } - - subghz_transmitter_free(subghz->txrx->transmitter); - - if(!generated_protocol) { - furi_string_set( - subghz->error_str, "Function requires\nan SD card with\nfresh databases."); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); - } - consumed = true; - } - - if(generated_protocol) { - subghz_file_name_clear(subghz); - DOLPHIN_DEED(DolphinDeedSubGhzAddManually); - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneSetType, SubGhzCustomEventManagerSet); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); - return true; - } - } - return consumed; -} - -void subghz_scene_set_seed_faac_on_exit(void* context) { - SubGhz* subghz = context; - - // Clear view - byte_input_set_result_callback(subghz->byte_input, NULL, NULL, NULL, NULL, 0); - byte_input_set_header_text(subghz->byte_input, ""); -} diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 431d5d2d7..e871a6439 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -389,13 +389,13 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { uint32_t key = subghz_random_serial(); switch(event.event) { case SubmenuIndexFaacSLH_868: - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFixFaac); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFix); break; case SubmenuIndexFaacSLH_433: - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFixFaac); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFix); break; case SubmenuIndexBFTClone: - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFixBft); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFix); break; case SubmenuIndexPricenton: key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8 diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 7895d8bc3..ab9155fb7 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -52,6 +52,10 @@ bool subghz_scene_transmitter_update_data_show(void* context) { void subghz_scene_transmitter_on_enter(void* context) { SubGhz* subghz = context; + + keeloq_reset_original_btn(); + subghz_custom_btns_reset(); + if(!subghz_scene_transmitter_update_data_show(subghz)) { view_dispatcher_send_custom_event( subghz->view_dispatcher, SubGhzCustomEventViewTransmitterError); @@ -74,9 +78,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { } if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { - if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) { - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); - } else { + if(subghz_tx_start(subghz, subghz->txrx->fff_data)) { subghz->state_notifications = SubGhzNotificationStateTx; subghz_scene_transmitter_update_data_show(subghz); DOLPHIN_DEED(DolphinDeedSubGhzSend); diff --git a/applications/main/subghz/subghz_history.c b/applications/main/subghz/subghz_history.c index f6530238e..51d5ada7d 100644 --- a/applications/main/subghz/subghz_history.c +++ b/applications/main/subghz/subghz_history.c @@ -12,6 +12,7 @@ typedef struct { FlipperFormat* flipper_string; uint8_t type; SubGhzRadioPreset* preset; + FuriHalRtcDateTime datetime; } SubGhzHistoryItem; ARRAY_DEF(SubGhzHistoryItemArray, SubGhzHistoryItem, M_POD_OPLIST) @@ -164,6 +165,12 @@ void subghz_history_get_text_item_menu(SubGhzHistory* instance, FuriString* outp furi_string_set(output, item->item_str); } +void subghz_history_get_time_item_menu(SubGhzHistory* instance, FuriString* output, uint16_t idx) { + SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx); + FuriHalRtcDateTime* t = &item->datetime; + furi_string_printf(output, "%.2d:%.2d:%.2d ", t->hour, t->minute, t->second); +} + bool subghz_history_add_to_history( SubGhzHistory* instance, void* context, @@ -195,6 +202,7 @@ bool subghz_history_add_to_history( furi_string_set(item->preset->name, preset->name); item->preset->data = preset->data; item->preset->data_size = preset->data_size; + furi_hal_rtc_get_datetime(&item->datetime); item->item_str = furi_string_alloc(); item->flipper_string = flipper_format_string_alloc(); diff --git a/applications/main/subghz/subghz_history.h b/applications/main/subghz/subghz_history.h index 1f2f8d246..1b27d52ad 100644 --- a/applications/main/subghz/subghz_history.h +++ b/applications/main/subghz/subghz_history.h @@ -78,6 +78,14 @@ const char* subghz_history_get_protocol_name(SubGhzHistory* instance, uint16_t i */ void subghz_history_get_text_item_menu(SubGhzHistory* instance, FuriString* output, uint16_t idx); +/** Get time item menu to history[idx] + * + * @param instance - SubGhzHistory instance + * @param output - FuriString* output + * @param idx - record index + */ +void subghz_history_get_time_item_menu(SubGhzHistory* instance, FuriString* output, uint16_t idx); + /** Get string the remaining number of records to history * * @param instance - SubGhzHistory instance diff --git a/applications/main/subghz/subghz_history_private.h b/applications/main/subghz/subghz_history_private.h deleted file mode 100644 index 12ce28fff..000000000 --- a/applications/main/subghz/subghz_history_private.h +++ /dev/null @@ -1,163 +0,0 @@ -#pragma once - -#include "subghz_history.h" -#include - -/** - * @brief Generate filename like 000.tmp - * - * @param index - index of file, timestamp doesn't accepted! - */ -FuriString* subghz_history_generate_temp_filename(uint32_t index); - -/** - * @brief Check if directory for temporary files is exists - * - * @param instance SubGhzHistory* - * @return true - * @return false - */ -bool subghz_history_is_tmp_dir_exists(SubGhzHistory* instance); - -/** - * @brief Check SD card and create temporary dir if not exists, - * Result write_tmp_files without this unstable work is GUARANTEED - * - * @param instance - SubGhzHistory* - * @return - true all ok - * @return - false we have a problems - */ -bool subghz_history_check_sdcard(SubGhzHistory* instance); - -/** - * @brief Recursive delete dir and files and create new temp dir - * - * @param instance - SubGhzHistory* - * @return true - if all ok - * @return false - if something failed - */ -void subghz_history_clear_tmp_dir(SubGhzHistory* instance); - -/** - * @brief Free item and free all resources - * - * @param current_item - SubGhzHistoryItem* - */ -void subghz_history_item_free(void* current_item); - -/** - * @brief free all items in array - * - * @param instance - */ -void subghz_history_clean_item_array(SubGhzHistory* instance); - -/** - * @brief Write temp file fully, without splitting - * - * @param instance - SubGhzHistory* - * @param current_item - SubGhzHistoryItem* - * @param dir_path - full path to file - */ -void subghz_history_tmp_write_file_full( - SubGhzHistory* instance, - void* current_item, - FuriString* dir_path); - -/** - * @brief Write temp spited to lines - * - * @param instance - SubGhzHistory* - * @param current_item - SubGhzHistoryItem* - * @param dir_path - full path to file - * @return true - file saved - * @return false - error occurred - */ -bool subghz_history_tmp_write_file_split( - SubGhzHistory* instance, - void* current_item, - const char* dir_path); - -/** - * @brief generate random value - * - * @param min - min value - * @param max - max value - * @return uint32_t - */ -uint32_t subghz_history_rand_range(uint32_t min, uint32_t max); - -/** - * @brief write random noise signals to file applying to max line value - * - * @param file - Stream* - * @param is_negative_start - first value is negative or positive? - * @param current_position - 0 if started from beginning - * @param empty_line - add RAW_Data to this line - * @return true - * @return false - */ -bool subghz_history_write_file_noise( - Stream* file, - bool is_negative_start, - size_t current_position, - bool empty_line); - -/** - * @brief taken from flipper_format_stream_read_value_line but takes only one int32 value - * - * @param stream - Stream* - * @param _data - int32_t* output data - * @param data_size - size of data - * @return true - * @return false - */ -bool subghz_history_read_int32(Stream* stream, int32_t* _data, const uint16_t data_size); - -/** - * @brief write payload to file spliting by lines - * - * @param src - Stream* of source - * @param file - Stream* of file - * @param is_negative_start - first value is negative or positive? - * @param current_position - by default is 0 but in this value returned last position of payload - * @return true - * @return false - */ -bool subghz_history_write_file_data( - Stream* src, - Stream* file, - bool* is_negative_start, - size_t* current_position); - -/** - * @brief taken from flipper_format_stream_read_valid_key - * - * @param stream - Stream* - * @param key - FuriString* output value - * @return true - * @return false - */ -bool subghz_history_stream_read_valid_key(Stream* stream, FuriString* key); - -/** - * @brief taken from flipper_format_stream_seek_to_key - * - * @param stream - Stream* - * @param key - key - * @param strict_mode - false - * @return true - * @return false - */ -bool subghz_history_stream_seek_to_key(Stream* stream, const char* key, bool strict_mode); - -/** - * @brief taken from flipper_format_stream_read_value - * - * @param stream - Stream* - * @param value - FuriString* output value - * @param last - return position is last flag - * @return true - * @return false - */ -bool subghz_history_stream_read_value(Stream* stream, FuriString* value, bool* last); diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index c1c17c374..dd0160213 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -106,9 +106,11 @@ static bool subghz_tx(SubGhz* subghz, uint32_t frequency) { furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false); furi_hal_gpio_init( furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - subghz_speaker_on(subghz); bool ret = furi_hal_subghz_tx(); - subghz->txrx->txrx_state = SubGhzTxRxStateTx; + if(ret) { + subghz_speaker_on(subghz); + subghz->txrx->txrx_state = SubGhzTxRxStateTx; + } return ret; } @@ -116,6 +118,7 @@ void subghz_idle(SubGhz* subghz) { furi_assert(subghz); furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep); furi_hal_subghz_idle(); + subghz_speaker_off(subghz); subghz->txrx->txrx_state = SubGhzTxRxStateIDLE; } diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index adabe4aad..faae35fa2 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -73,7 +73,9 @@ struct SubGhzTxRx { SubGhzTxRxState txrx_state; SubGhzHopperState hopper_state; SubGhzSpeakerState speaker_state; - SubGhzStarLineIgnoreState starline_state; + bool ignore_starline; + bool ignore_auto_alarms; + bool ignore_magellan; uint8_t hopper_timeout; uint8_t hopper_idx_frequency; SubGhzRxKeyState rx_key_state; diff --git a/applications/main/subghz/subghz_last_settings.c b/applications/main/subghz/subghz_last_settings.c index 6fc51554d..2f4445a42 100644 --- a/applications/main/subghz/subghz_last_settings.c +++ b/applications/main/subghz/subghz_last_settings.c @@ -19,6 +19,7 @@ #define SUBGHZ_LAST_SETTING_FIELD_FREQUENCY_ANALYZER_TRIGGER "FATrigger" #define SUBGHZ_LAST_SETTING_FIELD_EXTERNAL_MODULE_ENABLED "External" #define SUBGHZ_LAST_SETTING_FIELD_EXTERNAL_MODULE_POWER "ExtPower" +#define SUBGHZ_LAST_SETTING_FIELD_TIMESTAMP_FILE_NAMES "TimestampNames" SubGhzLastSettings* subghz_last_settings_alloc(void) { SubGhzLastSettings* instance = malloc(sizeof(SubGhzLastSettings)); @@ -45,6 +46,7 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count float temp_frequency_analyzer_trigger = 0; bool temp_external_module_enabled = false; bool temp_external_module_power_5v_disable = false; + bool temp_timestamp_file_names = false; //int32_t temp_preset = 0; bool frequency_analyzer_feedback_level_was_read = false; bool frequency_analyzer_trigger_was_read = false; @@ -76,6 +78,11 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count SUBGHZ_LAST_SETTING_FIELD_EXTERNAL_MODULE_POWER, (bool*)&temp_external_module_power_5v_disable, 1); + flipper_format_read_bool( + fff_data_file, + SUBGHZ_LAST_SETTING_FIELD_TIMESTAMP_FILE_NAMES, + (bool*)&temp_timestamp_file_names, + 1); } else { FURI_LOG_E(TAG, "Error open file %s", SUBGHZ_LAST_SETTINGS_PATH); @@ -89,6 +96,7 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_FEEDBACK_LEVEL; instance->frequency_analyzer_trigger = SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_TRIGGER; instance->external_module_enabled = false; + instance->timestamp_file_names = false; } else { instance->frequency = temp_frequency; @@ -109,6 +117,11 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count instance->external_module_power_5v_disable = temp_external_module_power_5v_disable; + instance->timestamp_file_names = temp_timestamp_file_names; + + // Set globally + furi_hal_subghz_set_timestamp_file_names(instance->timestamp_file_names); + if(instance->external_module_power_5v_disable) { furi_hal_subghz_set_external_power_disable(true); furi_hal_subghz_disable_ext_power(); @@ -189,6 +202,13 @@ bool subghz_last_settings_save(SubGhzLastSettings* instance) { 1)) { break; } + if(!flipper_format_insert_or_update_bool( + file, + SUBGHZ_LAST_SETTING_FIELD_TIMESTAMP_FILE_NAMES, + &instance->timestamp_file_names, + 1)) { + break; + } saved = true; } while(0); diff --git a/applications/main/subghz/subghz_last_settings.h b/applications/main/subghz/subghz_last_settings.h index 5e3630468..260c879f4 100644 --- a/applications/main/subghz/subghz_last_settings.h +++ b/applications/main/subghz/subghz_last_settings.h @@ -12,6 +12,7 @@ typedef struct { float frequency_analyzer_trigger; bool external_module_enabled; bool external_module_power_5v_disable; + bool timestamp_file_names; } SubGhzLastSettings; SubGhzLastSettings* subghz_last_settings_alloc(void); diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index 2a432deb5..4e2a1e6e6 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -16,8 +16,12 @@ #define SUBGHZ_RAW_THRESHOLD_MIN -90.0f +#define SCROLL_INTERVAL (606) +#define SCROLL_DELAY (2) + typedef struct { FuriString* item_str; + FuriString* time; uint8_t type; } SubGhzReceiverMenuItem; @@ -53,6 +57,7 @@ struct SubGhzViewReceiver { View* view; SubGhzViewReceiverCallback callback; void* context; + FuriTimer* scroll_timer; }; typedef struct { @@ -67,6 +72,7 @@ typedef struct { SubGhzViewReceiverBarShow bar_show; SubGhzViewReceiverMode mode; uint8_t u_rssi; + size_t scroll_counter; } SubGhzViewReceiverModel; void subghz_view_receiver_set_mode( @@ -146,6 +152,7 @@ static void subghz_view_receiver_update_offset(SubGhzViewReceiver* subghz_receiv void subghz_view_receiver_add_item_to_menu( SubGhzViewReceiver* subghz_receiver, const char* name, + const char* time, uint8_t type) { furi_assert(subghz_receiver); with_view_model( @@ -154,6 +161,7 @@ void subghz_view_receiver_add_item_to_menu( { SubGhzReceiverMenuItem* item_menu = SubGhzReceiverMenuItemArray_push_raw(model->history->data); + item_menu->time = furi_string_alloc_set(time); item_menu->item_str = furi_string_alloc_set(name); item_menu->type = type; if((model->idx == model->history_item - 1)) { @@ -242,14 +250,30 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { size_t idx = CLAMP((uint16_t)(i + model->list_offset), model->history_item, 0); item_menu = SubGhzReceiverMenuItemArray_get(model->history->data, idx); furi_string_set(str_buff, item_menu->item_str); - elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 7 : MAX_LEN_PX); + size_t scroll_counter = model->scroll_counter; if(model->idx == idx) { subghz_view_receiver_draw_frame(canvas, i, scrollbar); + if(scroll_counter < SCROLL_DELAY) { + // Show time of signal one moment + furi_string_set(str_buff, item_menu->time); + scroll_counter = 0; + } else { + scroll_counter -= SCROLL_DELAY; + } } else { canvas_set_color(canvas, ColorBlack); + scroll_counter = 0; } canvas_draw_icon(canvas, 4, 2 + i * FRAME_HEIGHT, ReceiverItemIcons[item_menu->type]); - canvas_draw_str(canvas, 15, 9 + i * FRAME_HEIGHT, furi_string_get_cstr(str_buff)); + elements_scrollable_text_line( + canvas, + 15, + 9 + i * FRAME_HEIGHT, + (scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX), + str_buff, + scroll_counter, + (model->idx != idx), + false); furi_string_reset(str_buff); } if(scrollbar) { @@ -357,6 +381,13 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { } } +static void subghz_view_receiver_scroll_timer_callback(void* context) { + furi_assert(context); + SubGhzViewReceiver* subghz_receiver = context; + with_view_model( + subghz_receiver->view, SubGhzViewReceiverModel * model, { model->scroll_counter++; }, true); +} + static void subghz_view_receiver_timer_callback(void* context) { furi_assert(context); SubGhzViewReceiver* subghz_receiver = context; @@ -416,6 +447,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { SubGhzViewReceiverModel * model, { if(model->idx != 0) model->idx--; + model->scroll_counter = 0; }, true); } else if( @@ -427,6 +459,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { { if((model->history_item != 0) && (model->idx != model->history_item - 1)) model->idx++; + model->scroll_counter = 0; }, true); } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { @@ -446,6 +479,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { if(it->index == (size_t)(model->idx)) { furi_string_free(item->item_str); + furi_string_free(item->time); item->type = 0; SubGhzReceiverMenuItemArray_remove(model->history->data, it); } @@ -479,6 +513,13 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { void subghz_view_receiver_enter(void* context) { furi_assert(context); + SubGhzViewReceiver* subghz_receiver = context; + with_view_model( + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { model->scroll_counter = 0; }, + true); + furi_timer_start(subghz_receiver->scroll_timer, SCROLL_INTERVAL); } void subghz_view_receiver_exit(void* context) { @@ -495,6 +536,7 @@ void subghz_view_receiver_exit(void* context) { for M_EACH(item_menu, model->history->data, SubGhzReceiverMenuItemArray_t) { furi_string_free(item_menu->item_str); + furi_string_free(item_menu->time); item_menu->type = 0; } SubGhzReceiverMenuItemArray_reset(model->history->data); @@ -504,6 +546,7 @@ void subghz_view_receiver_exit(void* context) { }, false); furi_timer_stop(subghz_receiver->timer); + furi_timer_stop(subghz_receiver->scroll_timer); } SubGhzViewReceiver* subghz_view_receiver_alloc() { @@ -522,6 +565,9 @@ SubGhzViewReceiver* subghz_view_receiver_alloc() { view_set_enter_callback(subghz_receiver->view, subghz_view_receiver_enter); view_set_exit_callback(subghz_receiver->view, subghz_view_receiver_exit); + subghz_receiver->scroll_timer = furi_timer_alloc( + subghz_view_receiver_scroll_timer_callback, FuriTimerTypePeriodic, subghz_receiver); + with_view_model( subghz_receiver->view, SubGhzViewReceiverModel * model, @@ -543,6 +589,8 @@ SubGhzViewReceiver* subghz_view_receiver_alloc() { void subghz_view_receiver_free(SubGhzViewReceiver* subghz_receiver) { furi_assert(subghz_receiver); + furi_timer_free(subghz_receiver->scroll_timer); + with_view_model( subghz_receiver->view, SubGhzViewReceiverModel * model, @@ -554,6 +602,7 @@ void subghz_view_receiver_free(SubGhzViewReceiver* subghz_receiver) { for M_EACH(item_menu, model->history->data, SubGhzReceiverMenuItemArray_t) { furi_string_free(item_menu->item_str); + furi_string_free(item_menu->time); item_menu->type = 0; } SubGhzReceiverMenuItemArray_clear(model->history->data); diff --git a/applications/main/subghz/views/receiver.h b/applications/main/subghz/views/receiver.h index ad8c31eda..f5ec86b4b 100644 --- a/applications/main/subghz/views/receiver.h +++ b/applications/main/subghz/views/receiver.h @@ -40,6 +40,7 @@ void subghz_view_receiver_add_data_progress( void subghz_view_receiver_add_item_to_menu( SubGhzViewReceiver* subghz_receiver, const char* name, + const char* time, uint8_t type); uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver); diff --git a/applications/main/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c index e8c53d1ed..2bec77690 100644 --- a/applications/main/subghz/views/transmitter.c +++ b/applications/main/subghz/views/transmitter.c @@ -137,6 +137,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { true); if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) { + subghz_custom_btn_set(0); with_view_model( subghz_transmitter->view, SubGhzViewTransmitterModel * model, diff --git a/applications/services/bt/bt_service/bt.c b/applications/services/bt/bt_service/bt.c index ddf3b1544..22c62eff1 100644 --- a/applications/services/bt/bt_service/bt.c +++ b/applications/services/bt/bt_service/bt.c @@ -240,7 +240,7 @@ static bool bt_on_gap_event_callback(GapEvent event, void* context) { furi_event_flag_clear(bt->rpc_event, BT_RPC_EVENT_DISCONNECTED); if(bt->profile == BtProfileSerial) { // Open RPC session - bt->rpc_session = rpc_session_open(bt->rpc); + bt->rpc_session = rpc_session_open(bt->rpc, RpcOwnerBle); if(bt->rpc_session) { FURI_LOG_I(TAG, "Open RPC connection"); rpc_session_set_send_bytes_callback(bt->rpc_session, bt_rpc_send_bytes_callback); diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 89e4f6105..dfed41dbb 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -39,6 +39,12 @@ static void desktop_lock_icon_draw_callback(Canvas* canvas, void* context) { canvas_draw_icon(canvas, 0, 0, &I_Lock_7x8); } +static void desktop_stealth_mode_icon_draw_callback(Canvas* canvas, void* context) { + UNUSED(context); + furi_assert(canvas); + canvas_draw_icon(canvas, 0, 0, &I_Muted_8x8); +} + static bool desktop_custom_event_callback(void* context, uint32_t event) { furi_assert(context); Desktop* desktop = (Desktop*)context; @@ -139,6 +145,18 @@ void desktop_unlock(Desktop* desktop) { desktop_auto_lock_arm(desktop); } +void desktop_set_stealth_mode_state(Desktop* desktop, bool enabled) { + desktop->in_transition = true; + if(enabled) { + furi_hal_rtc_set_flag(FuriHalRtcFlagStealthMode); + } else { + furi_hal_rtc_reset_flag(FuriHalRtcFlagStealthMode); + } + desktop_lock_menu_set_stealth_mode_state(desktop->lock_menu, enabled); + view_port_enabled_set(desktop->stealth_mode_icon_viewport, enabled); + desktop->in_transition = false; +} + Desktop* desktop_alloc() { Desktop* desktop = malloc(sizeof(Desktop)); @@ -222,6 +240,18 @@ Desktop* desktop_alloc() { view_port_enabled_set(desktop->lock_icon_viewport, false); gui_add_view_port(desktop->gui, desktop->lock_icon_viewport, GuiLayerStatusBarLeft); + // Stealth mode icon + desktop->stealth_mode_icon_viewport = view_port_alloc(); + view_port_set_width(desktop->stealth_mode_icon_viewport, icon_get_width(&I_Muted_8x8)); + view_port_draw_callback_set( + desktop->stealth_mode_icon_viewport, desktop_stealth_mode_icon_draw_callback, desktop); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)) { + view_port_enabled_set(desktop->stealth_mode_icon_viewport, true); + } else { + view_port_enabled_set(desktop->stealth_mode_icon_viewport, false); + } + gui_add_view_port(desktop->gui, desktop->stealth_mode_icon_viewport, GuiLayerStatusBarLeft); + // Special case: autostart application is already running desktop->loader = furi_record_open(RECORD_LOADER); if(loader_is_locked(desktop->loader) && diff --git a/applications/services/desktop/desktop_i.h b/applications/services/desktop/desktop_i.h index 822eecc76..988092f0e 100644 --- a/applications/services/desktop/desktop_i.h +++ b/applications/services/desktop/desktop_i.h @@ -58,6 +58,7 @@ struct Desktop { DesktopViewPinInput* pin_input_view; ViewPort* lock_icon_viewport; + ViewPort* stealth_mode_icon_viewport; AnimationManager* animation_manager; @@ -77,3 +78,4 @@ Desktop* desktop_alloc(); void desktop_free(Desktop* desktop); void desktop_lock(Desktop* desktop); void desktop_unlock(Desktop* desktop); +void desktop_set_stealth_mode_state(Desktop* desktop, bool enabled); diff --git a/applications/services/desktop/scenes/desktop_scene_lock_menu.c b/applications/services/desktop/scenes/desktop_scene_lock_menu.c index 3b2309844..ac529b779 100644 --- a/applications/services/desktop/scenes/desktop_scene_lock_menu.c +++ b/applications/services/desktop/scenes/desktop_scene_lock_menu.c @@ -28,6 +28,8 @@ void desktop_scene_lock_menu_on_enter(void* context) { scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); desktop_lock_menu_set_callback(desktop->lock_menu, desktop_scene_lock_menu_callback, desktop); desktop_lock_menu_set_pin_state(desktop->lock_menu, desktop->settings.pin_code.length > 0); + desktop_lock_menu_set_stealth_mode_state( + desktop->lock_menu, furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)); desktop_lock_menu_set_idx(desktop->lock_menu, 3); Gui* gui = furi_record_open(RECORD_GUI); @@ -129,6 +131,12 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { desktop->loader, FAP_LOADER_APP_NAME, EXT_PATH("apps/.Main/xtreme_app.fap")); consumed = true; break; + case DesktopLockMenuEventStealthModeOn: + desktop_set_stealth_mode_state(desktop, true); + break; + case DesktopLockMenuEventStealthModeOff: + desktop_set_stealth_mode_state(desktop, false); + break; default: break; } diff --git a/applications/services/desktop/views/desktop_events.h b/applications/services/desktop/views/desktop_events.h index 9e4a3bb4d..af7597012 100644 --- a/applications/services/desktop/views/desktop_events.h +++ b/applications/services/desktop/views/desktop_events.h @@ -44,6 +44,8 @@ typedef enum { DesktopLockMenuEventLockPin, DesktopLockMenuEventLockPinOff, DesktopLockMenuEventXtreme, + DesktopLockMenuEventStealthModeOn, + DesktopLockMenuEventStealthModeOff, DesktopAnimationEventCheckAnimation, DesktopAnimationEventNewIdleAnimation, diff --git a/applications/services/desktop/views/desktop_view_lock_menu.c b/applications/services/desktop/views/desktop_view_lock_menu.c index 0ccc4f326..23079bcae 100644 --- a/applications/services/desktop/views/desktop_view_lock_menu.c +++ b/applications/services/desktop/views/desktop_view_lock_menu.c @@ -48,6 +48,14 @@ void desktop_lock_menu_set_pin_state(DesktopLockMenuView* lock_menu, bool pin_is true); } +void desktop_lock_menu_set_stealth_mode_state(DesktopLockMenuView* lock_menu, bool stealth_mode) { + with_view_model( + lock_menu->view, + DesktopLockMenuViewModel * model, + { model->stealth_mode = stealth_mode; }, + true); +} + void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx) { furi_assert(idx < DesktopLockMenuIndexTotalCount); with_view_model( @@ -110,7 +118,7 @@ void desktop_lock_menu_draw_callback(Canvas* canvas, void* model) { value = total - m->lock_menu->notification->settings.display_brightness * total; break; case DesktopLockMenuIndexVolume: - icon = &I_Volup_8x6; + icon = m->stealth_mode ? &I_Muted_8x8 : &I_Volup_8x6; value = total - m->lock_menu->notification->settings.speaker_volume * total; break; default: @@ -181,6 +189,7 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) { uint8_t idx = 0; int pin_lock = 0; bool show_lock_menu = false; + bool stealth_mode = false; bool consumed = true; with_view_model( @@ -188,6 +197,7 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) { DesktopLockMenuViewModel * model, { show_lock_menu = model->show_lock_menu; + stealth_mode = model->stealth_mode; if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) { if(model->show_lock_menu) { if(event->key == InputKeyUp) { @@ -292,6 +302,9 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) { case DesktopLockMenuIndexXtreme: desktop_event = DesktopLockMenuEventXtreme; break; + case DesktopLockMenuIndexVolume: + desktop_event = stealth_mode ? DesktopLockMenuEventStealthModeOff : DesktopLockMenuEventStealthModeOn; + break; default: break; } diff --git a/applications/services/desktop/views/desktop_view_lock_menu.h b/applications/services/desktop/views/desktop_view_lock_menu.h index 957551b36..67d0f6f67 100644 --- a/applications/services/desktop/views/desktop_view_lock_menu.h +++ b/applications/services/desktop/views/desktop_view_lock_menu.h @@ -28,6 +28,7 @@ typedef struct { int pin_lock; bool show_lock_menu; DesktopLockMenuView* lock_menu; + bool stealth_mode; } DesktopLockMenuViewModel; void desktop_lock_menu_set_callback( @@ -37,6 +38,7 @@ void desktop_lock_menu_set_callback( View* desktop_lock_menu_get_view(DesktopLockMenuView* lock_menu); void desktop_lock_menu_set_pin_state(DesktopLockMenuView* lock_menu, bool pin_is_set); +void desktop_lock_menu_set_stealth_mode_state(DesktopLockMenuView* lock_menu, bool stealth_mode); void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx); DesktopLockMenuView* desktop_lock_menu_alloc(); void desktop_lock_menu_free(DesktopLockMenuView* lock_menu); diff --git a/applications/services/gui/modules/menu.c b/applications/services/gui/modules/menu.c index d259caaba..191c0e874 100644 --- a/applications/services/gui/modules/menu.c +++ b/applications/services/gui/modules/menu.c @@ -273,6 +273,8 @@ Menu* menu_alloc() { void menu_free(Menu* menu) { furi_assert(menu); menu_reset(menu); + with_view_model( + menu->view, MenuModel * model, { MenuItemArray_clear(model->items); }, false); view_free(menu->view); furi_timer_free(menu->scroll_timer); free(menu); diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index 2e170f547..f91a73f32 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -20,9 +20,9 @@ static const uint8_t reset_sound_mask = 1 << 4; static const uint8_t reset_display_mask = 1 << 5; static const uint8_t reset_blink_mask = 1 << 6; -void notification_vibro_on(); +void notification_vibro_on(bool force); void notification_vibro_off(); -void notification_sound_on(float freq, float volume); +void notification_sound_on(float freq, float volume, bool force); void notification_sound_off(); uint8_t notification_settings_get_display_brightness(NotificationApp* app, uint8_t value); @@ -141,17 +141,21 @@ uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app) { } // generics -void notification_vibro_on() { - furi_hal_vibro_on(true); +void notification_vibro_on(bool force) { + if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) { + furi_hal_vibro_on(true); + } } void notification_vibro_off() { furi_hal_vibro_on(false); } -void notification_sound_on(float freq, float volume) { - if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) { - furi_hal_speaker_start(freq, volume); +void notification_sound_on(float freq, float volume, bool force) { + if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) { + if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) { + furi_hal_speaker_start(freq, volume); + } } } @@ -174,6 +178,8 @@ void notification_process_notification_message( NotificationApp* app, NotificationAppMessage* message) { uint32_t notification_message_index = 0; + bool force_volume = false; + bool force_vibro = false; const NotificationMessage* notification_message; notification_message = (*message->sequence)[notification_message_index]; @@ -269,7 +275,7 @@ void notification_process_notification_message( break; case NotificationMessageTypeVibro: if(notification_message->data.vibro.on) { - if(vibro_setting) notification_vibro_on(); + if(vibro_setting) notification_vibro_on(force_vibro); } else { notification_vibro_off(); } @@ -278,7 +284,8 @@ void notification_process_notification_message( case NotificationMessageTypeSoundOn: notification_sound_on( notification_message->data.sound.frequency, - notification_message->data.sound.volume * speaker_volume_setting); + notification_message->data.sound.volume * speaker_volume_setting, + force_volume); reset_mask |= reset_sound_mask; break; case NotificationMessageTypeSoundOff: @@ -307,9 +314,11 @@ void notification_process_notification_message( break; case NotificationMessageTypeForceSpeakerVolumeSetting: speaker_volume_setting = notification_message->data.forced_settings.speaker_volume; + force_volume = true; break; case NotificationMessageTypeForceVibroSetting: vibro_setting = notification_message->data.forced_settings.vibro; + force_vibro = true; break; case NotificationMessageTypeForceDisplayBrightnessSetting: display_brightness_setting = diff --git a/applications/services/power/power_service/power.c b/applications/services/power/power_service/power.c index 4c4e1404e..9b9a2356f 100644 --- a/applications/services/power/power_service/power.c +++ b/applications/services/power/power_service/power.c @@ -512,6 +512,10 @@ static void power_check_battery_level_change(Power* power) { } } +void power_trigger_ui_update(Power* power) { + view_port_update(power->battery_view_port); +} + int32_t power_srv(void* p) { UNUSED(p); @@ -543,7 +547,9 @@ int32_t power_srv(void* p) { power_check_battery_level_change(power); // Update battery view port - if(need_refresh) view_port_update(power->battery_view_port); + if(need_refresh) { + view_port_update(power->battery_view_port); + } // Check OTG status and disable it in case of fault if(furi_hal_power_is_otg_enabled()) { diff --git a/applications/services/power/power_service/power.h b/applications/services/power/power_service/power.h index cb2fc8fad..4a8f07a89 100644 --- a/applications/services/power/power_service/power.h +++ b/applications/services/power/power_service/power.h @@ -113,6 +113,12 @@ bool power_is_battery_healthy(Power* power); */ void power_enable_low_battery_level_notification(Power* power, bool enable); +/** Trigger UI update for changing battery layout + * + * @param power Power instance + */ +void power_trigger_ui_update(Power* power); + #ifdef __cplusplus } #endif diff --git a/applications/services/rpc/rpc.c b/applications/services/rpc/rpc.c index 2326e7d2f..62428d79d 100644 --- a/applications/services/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -76,6 +76,7 @@ struct RpcSession { RpcBufferIsEmptyCallback buffer_is_empty_callback; RpcSessionClosedCallback closed_callback; RpcSessionTerminatedCallback terminated_callback; + RpcOwner owner; void* context; }; @@ -83,6 +84,11 @@ struct Rpc { FuriMutex* busy_mutex; }; +RpcOwner rpc_session_get_owner(RpcSession* session) { + furi_assert(session); + return session->owner; +} + static void rpc_close_session_process(const PB_Main* request, void* context) { furi_assert(request); furi_assert(context); @@ -348,7 +354,7 @@ static void rpc_session_free_callback(FuriThreadState thread_state, void* contex } } -RpcSession* rpc_session_open(Rpc* rpc) { +RpcSession* rpc_session_open(Rpc* rpc, RpcOwner owner) { furi_assert(rpc); RpcSession* session = malloc(sizeof(RpcSession)); @@ -357,6 +363,7 @@ RpcSession* rpc_session_open(Rpc* rpc) { session->rpc = rpc; session->terminate = false; session->decode_error = false; + session->owner = owner; RpcHandlerDict_init(session->handlers); session->decoded_message = malloc(sizeof(PB_Main)); diff --git a/applications/services/rpc/rpc.h b/applications/services/rpc/rpc.h index ec290e083..d11fdc162 100644 --- a/applications/services/rpc/rpc.h +++ b/applications/services/rpc/rpc.h @@ -30,6 +30,21 @@ typedef void (*RpcSessionClosedCallback)(void* context); * and all operations were finished */ typedef void (*RpcSessionTerminatedCallback)(void* context); +/** RPC owner */ +typedef enum { + RpcOwnerUnknown = 0, + RpcOwnerBle, + RpcOwnerUsb, + RpcOwnerCount, +} RpcOwner; + +/** Get RPC session owner + * + * @param session pointer to RpcSession descriptor + * @return session owner + */ +RpcOwner rpc_session_get_owner(RpcSession* session); + /** Open RPC session * * USAGE: @@ -44,10 +59,11 @@ typedef void (*RpcSessionTerminatedCallback)(void* context); * * * @param rpc instance + * @param owner owner of session * @return pointer to RpcSession descriptor, or * NULL if RPC is busy and can't open session now */ -RpcSession* rpc_session_open(Rpc* rpc); +RpcSession* rpc_session_open(Rpc* rpc, RpcOwner owner); /** Close RPC session * It is guaranteed that no callbacks will be called diff --git a/applications/services/rpc/rpc_cli.c b/applications/services/rpc/rpc_cli.c index d14b8eee2..f1c139b5f 100644 --- a/applications/services/rpc/rpc_cli.c +++ b/applications/services/rpc/rpc_cli.c @@ -47,7 +47,7 @@ void rpc_cli_command_start_session(Cli* cli, FuriString* args, void* context) { FURI_LOG_D(TAG, "Free memory %lu", mem_before); furi_hal_usb_lock(); - RpcSession* rpc_session = rpc_session_open(rpc); + RpcSession* rpc_session = rpc_session_open(rpc, RpcOwnerUsb); if(rpc_session == NULL) { printf("Session start error\r\n"); furi_hal_usb_unlock(); diff --git a/applications/services/rpc/rpc_gui.c b/applications/services/rpc/rpc_gui.c index 0c70702cf..9ba20a832 100644 --- a/applications/services/rpc/rpc_gui.c +++ b/applications/services/rpc/rpc_gui.c @@ -2,6 +2,7 @@ #include "rpc_i.h" #include "gui.pb.h" #include +#include #define TAG "RpcGui" @@ -31,6 +32,8 @@ typedef struct { uint32_t input_key_counter[InputKeyMAX]; uint32_t input_counter; + + ViewPort* rpc_session_active_viewport; } RpcGuiSystem; static const PB_Gui_ScreenOrientation rpc_system_gui_screen_orientation_map[] = { @@ -352,6 +355,12 @@ static void rpc_system_gui_virtual_display_frame_process(const PB_Main* request, (void)session; } +static void rpc_active_session_icon_draw_callback(Canvas* canvas, void* context) { + UNUSED(context); + furi_assert(canvas); + canvas_draw_icon(canvas, 0, 0, &I_Rpc_active_7x8); +} + void* rpc_system_gui_alloc(RpcSession* session) { furi_assert(session); @@ -359,6 +368,18 @@ void* rpc_system_gui_alloc(RpcSession* session) { rpc_gui->gui = furi_record_open(RECORD_GUI); rpc_gui->session = session; + // Active session icon + rpc_gui->rpc_session_active_viewport = view_port_alloc(); + view_port_set_width(rpc_gui->rpc_session_active_viewport, icon_get_width(&I_Rpc_active_7x8)); + view_port_draw_callback_set( + rpc_gui->rpc_session_active_viewport, rpc_active_session_icon_draw_callback, session); + if(rpc_session_get_owner(rpc_gui->session) != RpcOwnerBle) { + view_port_enabled_set(rpc_gui->rpc_session_active_viewport, true); + } else { + view_port_enabled_set(rpc_gui->rpc_session_active_viewport, false); + } + gui_add_view_port(rpc_gui->gui, rpc_gui->rpc_session_active_viewport, GuiLayerStatusBarLeft); + RpcHandler rpc_handler = { .message_handler = NULL, .decode_submessage = NULL, @@ -399,6 +420,9 @@ void rpc_system_gui_free(void* context) { rpc_gui->virtual_display_not_empty = false; } + gui_remove_view_port(rpc_gui->gui, rpc_gui->rpc_session_active_viewport); + view_port_free(rpc_gui->rpc_session_active_viewport); + if(rpc_gui->is_streaming) { rpc_gui->is_streaming = false; // Remove GUI framebuffer callback @@ -415,4 +439,4 @@ void rpc_system_gui_free(void* context) { } furi_record_close(RECORD_GUI); free(rpc_gui); -} +} \ No newline at end of file diff --git a/applications/settings/about/about.c b/applications/settings/about/about.c index bf0b8acfc..e932b58ce 100644 --- a/applications/settings/about/about.c +++ b/applications/settings/about/about.c @@ -169,8 +169,8 @@ static DialogMessageButton fw_version_screen(DialogsApp* dialogs, DialogMessage* #include #include -#define LOW_CHARGE_THRESHOLD 10 -#define HIGH_DRAIN_CURRENT_THRESHOLD 100 +#define LOW_CHARGE_THRESHOLD (10) +#define HIGH_DRAIN_CURRENT_THRESHOLD (-100) static void draw_stat(Canvas* canvas, int x, int y, const Icon* icon, char* val) { canvas_draw_frame(canvas, x - 7, y + 7, 30, 13); @@ -185,14 +185,13 @@ static void draw_battery(Canvas* canvas, PowerInfo* info, int x, int y) { char header[20] = {}; char value[20] = {}; - int32_t drain_current = info->current_gauge * (-1000); - uint32_t charge_current = info->current_gauge * 1000; + int32_t current = 1000.0f * info->current_gauge; // Draw battery canvas_draw_icon(canvas, x, y, &I_BatteryBody_52x28); - if(charge_current > 0) { + if(current > 0) { canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceCharging_29x14); - } else if(drain_current > HIGH_DRAIN_CURRENT_THRESHOLD) { + } else if(current < HIGH_DRAIN_CURRENT_THRESHOLD) { canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceConfused_29x14); } else if(info->charge < LOW_CHARGE_THRESHOLD) { canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceNopower_29x14); @@ -204,7 +203,7 @@ static void draw_battery(Canvas* canvas, PowerInfo* info, int x, int y) { elements_bubble(canvas, x + 53, y + 0, 71, 28); // Set text - if(charge_current > 0) { + if(current > 0) { snprintf(header, sizeof(header), "%s", "Charging at"); snprintf( value, @@ -212,28 +211,30 @@ static void draw_battery(Canvas* canvas, PowerInfo* info, int x, int y) { "%lu.%luV %lumA", (uint32_t)(info->voltage_vbus), (uint32_t)(info->voltage_vbus * 10) % 10, - charge_current); - } else if(drain_current > 0) { + current); + } else if(current < 0) { snprintf(header, sizeof(header), "%s", "Consumption is"); snprintf( value, sizeof(value), "%ld %s", - drain_current, - drain_current > HIGH_DRAIN_CURRENT_THRESHOLD ? "mA!" : "mA"); - } else if(drain_current != 0) { - snprintf(header, 20, "..."); - } else if(info->voltage_battery_charge_limit < 4.2) { - // Non-default battery charging limit, mention it - snprintf(header, sizeof(header), "Limited to"); - snprintf( - value, - sizeof(value), - "%lu.%luV", - (uint32_t)(info->voltage_battery_charge_limit), - (uint32_t)(info->voltage_battery_charge_limit * 10) % 10); + ABS(current), + current < HIGH_DRAIN_CURRENT_THRESHOLD ? "mA!" : "mA"); + } else if(info->voltage_vbus > 0) { + if(info->voltage_battery_charge_limit < 4.2) { + // Non-default battery charging limit, mention it + snprintf(header, sizeof(header), "Limited to"); + snprintf( + value, + sizeof(value), + "%lu.%luV", + (uint32_t)(info->voltage_battery_charge_limit), + (uint32_t)(info->voltage_battery_charge_limit * 10) % 10); + } else { + snprintf(header, sizeof(header), "Charged!"); + } } else { - snprintf(header, sizeof(header), "Charged!"); + snprintf(header, sizeof(header), "Napping..."); } if(!strcmp(value, "")) { diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c index 4ec90d097..bcf8eaf12 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c @@ -3,6 +3,7 @@ #include "../desktop_settings_app.h" #include "desktop_settings_scene.h" +#include #define SCENE_EVENT_SELECT_FAVORITE_PRIMARY 0 #define SCENE_EVENT_SELECT_FAVORITE_SECONDARY 1 @@ -132,4 +133,9 @@ void desktop_settings_scene_start_on_exit(void* context) { DesktopSettingsApp* app = context; variable_item_list_reset(app->variable_item_list); DESKTOP_SETTINGS_SAVE(&app->settings); + + // Trigger UI update in case we changed battery layout + Power* power = furi_record_open(RECORD_POWER); + power_trigger_ui_update(power); + furi_record_close(RECORD_POWER); } diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 01ab6bd86..364734a62 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -157,18 +157,33 @@ static NotificationAppSettings* alloc_settings() { variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, backlight_text[value_index]); - item = variable_item_list_add( - app->variable_item_list, "Volume", VOLUME_COUNT, volume_changed, app); - value_index = - value_index_float(app->notification->settings.speaker_volume, volume_value, VOLUME_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, volume_text[value_index]); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)) { + item = variable_item_list_add(app->variable_item_list, "Volume", 1, NULL, app); + value_index = 0; + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, "Stealth"); + } else { + item = variable_item_list_add( + app->variable_item_list, "Volume", VOLUME_COUNT, volume_changed, app); + value_index = value_index_float( + app->notification->settings.speaker_volume, volume_value, VOLUME_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, volume_text[value_index]); + } - item = - variable_item_list_add(app->variable_item_list, "Vibro", VIBRO_COUNT, vibro_changed, app); - value_index = value_index_bool(app->notification->settings.vibro_on, vibro_value, VIBRO_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, vibro_text[value_index]); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)) { + item = variable_item_list_add(app->variable_item_list, "Vibro", 1, NULL, app); + value_index = 0; + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, "Stealth"); + } else { + item = variable_item_list_add( + app->variable_item_list, "Vibro", VIBRO_COUNT, vibro_changed, app); + value_index = + value_index_bool(app->notification->settings.vibro_on, vibro_value, VIBRO_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, vibro_text[value_index]); + } app->view_dispatcher = view_dispatcher_alloc(); view_dispatcher_enable_queue(app->view_dispatcher); diff --git a/applications/settings/power_settings_app/views/battery_info.c b/applications/settings/power_settings_app/views/battery_info.c index 7394fd3c5..0956cae4f 100644 --- a/applications/settings/power_settings_app/views/battery_info.c +++ b/applications/settings/power_settings_app/views/battery_info.c @@ -4,8 +4,8 @@ #include #include -#define LOW_CHARGE_THRESHOLD 10 -#define HIGH_DRAIN_CURRENT_THRESHOLD 100 +#define LOW_CHARGE_THRESHOLD (10) +#define HIGH_DRAIN_CURRENT_THRESHOLD (-100) struct BatteryInfo { View* view; @@ -25,14 +25,13 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { char header[20] = {}; char value[20] = {}; - int32_t drain_current = data->gauge_current * (-1000); - uint32_t charge_current = data->gauge_current * 1000; + int32_t current = 1000.0f * data->gauge_current; // Draw battery canvas_draw_icon(canvas, x, y, &I_BatteryBody_52x28); - if(charge_current > 0) { + if(current > 0) { canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceCharging_29x14); - } else if(drain_current > HIGH_DRAIN_CURRENT_THRESHOLD) { + } else if(current < HIGH_DRAIN_CURRENT_THRESHOLD) { canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceConfused_29x14); } else if(data->charge < LOW_CHARGE_THRESHOLD) { canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceNopower_29x14); @@ -44,7 +43,7 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { elements_bubble(canvas, 53, 0, 71, 39); // Set text - if(charge_current > 0) { + if(current > 0) { snprintf(emote, sizeof(emote), "%s", "Yummy!"); snprintf(header, sizeof(header), "%s", "Charging at"); snprintf( @@ -53,34 +52,36 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { "%lu.%luV %lumA", (uint32_t)(data->vbus_voltage), (uint32_t)(data->vbus_voltage * 10) % 10, - charge_current); - } else if(drain_current > 0) { + current); + } else if(current < 0) { snprintf( emote, sizeof(emote), "%s", - drain_current > HIGH_DRAIN_CURRENT_THRESHOLD ? "Oh no!" : "Om-nom-nom!"); + current < HIGH_DRAIN_CURRENT_THRESHOLD ? "Oh no!" : "Om-nom-nom!"); snprintf(header, sizeof(header), "%s", "Consumption is"); snprintf( value, sizeof(value), "%ld %s", - drain_current, - drain_current > HIGH_DRAIN_CURRENT_THRESHOLD ? "mA!" : "mA"); - } else if(drain_current != 0) { - snprintf(header, 20, "..."); - } else if(data->charge_voltage_limit < 4.2) { - // Non-default battery charging limit, mention it - snprintf(emote, sizeof(emote), "Charged!"); - snprintf(header, sizeof(header), "Limited to"); - snprintf( - value, - sizeof(value), - "%lu.%luV", - (uint32_t)(data->charge_voltage_limit), - (uint32_t)(data->charge_voltage_limit * 10) % 10); + ABS(current), + current < HIGH_DRAIN_CURRENT_THRESHOLD ? "mA!" : "mA"); + } else if(data->vbus_voltage > 0) { + if(data->charge_voltage_limit < 4.2) { + // Non-default battery charging limit, mention it + snprintf(emote, sizeof(emote), "Charged!"); + snprintf(header, sizeof(header), "Limited to"); + snprintf( + value, + sizeof(value), + "%lu.%luV", + (uint32_t)(data->charge_voltage_limit), + (uint32_t)(data->charge_voltage_limit * 10) % 10); + } else { + snprintf(header, sizeof(header), "Charged!"); + } } else { - snprintf(header, sizeof(header), "Charged!"); + snprintf(header, sizeof(header), "Napping..."); } canvas_draw_str_aligned(canvas, 92, y + 3, AlignCenter, AlignCenter, emote); diff --git a/applications/settings/system/system_settings.c b/applications/settings/system/system_settings.c index f9abdb693..655541be5 100644 --- a/applications/settings/system/system_settings.c +++ b/applications/settings/system/system_settings.c @@ -124,6 +124,21 @@ static void date_format_changed(VariableItem* item) { locale_set_date_format(date_format_value[index]); } +const char* const sleep_method[] = { + "Default", + "Legacy", +}; + +static void sleep_method_changed(VariableItem* item) { + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, sleep_method[index]); + if(index) { + furi_hal_rtc_set_flag(FuriHalRtcFlagLegacySleep); + } else { + furi_hal_rtc_reset_flag(FuriHalRtcFlagLegacySleep); + } +} + static uint32_t system_settings_exit(void* context) { UNUSED(context); return VIEW_NONE; @@ -195,6 +210,12 @@ SystemSettings* system_settings_alloc() { variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, heap_trace_mode_text[value_index]); + item = variable_item_list_add( + app->var_item_list, "Sleep Method", COUNT_OF(sleep_method), sleep_method_changed, app); + value_index = furi_hal_rtc_is_flag_set(FuriHalRtcFlagLegacySleep) ? 1 : 0; + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, sleep_method[value_index]); + view_set_previous_callback( variable_item_list_get_view(app->var_item_list), system_settings_exit); view_dispatcher_add_view( diff --git a/assets/icons/StatusBar/Muted_8x8.png b/assets/icons/StatusBar/Muted_8x8.png new file mode 100644 index 000000000..fee4e09f5 Binary files /dev/null and b/assets/icons/StatusBar/Muted_8x8.png differ diff --git a/assets/icons/StatusBar/Rpc_active_7x8.png b/assets/icons/StatusBar/Rpc_active_7x8.png new file mode 100644 index 000000000..f643a82aa Binary files /dev/null and b/assets/icons/StatusBar/Rpc_active_7x8.png differ diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index edddec899..bf047c5e7 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 21st Mar, 2023 -# Last Checked 29th Mar, 2023 +# Last Updated 14th Apr, 2023 +# Last Checked 14th Apr, 2023 # name: POWER type: raw @@ -1686,3 +1686,57 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 1373 348 1310 376 463 1190 1318 400 1286 401 439 1244 442 1244 1288 400 465 1218 468 1218 468 1219 467 7970 1307 404 1281 405 435 1252 1281 406 1280 406 434 1252 434 1252 1281 406 434 1253 434 1252 434 1252 434 8000 1280 406 1281 406 434 1252 1281 406 1280 406 434 1252 434 1252 1281 406 434 1253 433 1253 433 1253 434 8000 1280 406 1280 406 434 1253 1280 406 1280 406 434 1253 433 1253 1280 406 434 1253 433 1253 433 1253 433 8001 1279 406 1280 406 434 1253 1280 407 1279 407 433 1253 434 1253 1280 407 433 1253 433 1253 433 1253 433 8001 1279 407 1279 407 433 1253 1280 407 1280 407 433 1253 433 1253 1280 407 433 1253 433 1253 434 1253 433 +# OFF +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3827 1854 505 433 507 1382 506 434 506 1383 505 434 506 1410 478 433 507 1381 507 433 507 1383 505 435 505 1382 505 1383 505 435 505 1382 506 435 505 1383 505 1382 506 1384 504 1381 507 434 506 434 506 1382 506 1382 506 432 508 434 506 436 504 433 507 1382 506 435 505 434 506 436 504 1381 507 1383 505 434 506 1382 506 1381 507 434 506 1381 507 1381 507 1383 505 435 505 434 506 435 505 433 507 1383 505 435 505 435 505 434 506 1381 507 433 507 435 505 434 506 1382 506 433 507 434 506 433 507 438 502 434 506 433 507 434 506 434 506 432 508 435 505 434 506 433 507 433 507 1387 501 435 505 436 504 433 507 433 507 435 505 433 507 434 506 434 506 435 505 435 505 432 508 1410 478 461 479 432 508 435 505 434 506 433 507 436 504 434 506 434 506 433 507 435 505 1383 505 435 505 1381 507 1381 507 1382 506 1382 506 1381 507 435 505 433 507 433 507 461 478 1383 505 433 507 434 506 +# +name: TEMP- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3778 1905 506 434 506 1381 507 436 504 1381 507 435 505 1382 506 432 508 1380 508 433 507 1381 507 432 508 1380 508 1381 507 432 508 1380 508 432 508 1380 508 1380 508 1380 508 1380 508 433 507 432 508 1380 508 1380 508 432 508 431 509 432 508 433 507 1380 508 432 508 432 508 431 509 433 507 1380 508 434 506 1380 508 1380 508 434 506 1381 507 1380 508 1380 508 433 507 431 509 433 507 1381 507 1381 507 432 508 431 509 431 509 1381 507 431 509 432 508 432 508 1381 507 431 509 432 508 432 508 432 508 432 508 432 508 435 505 432 508 432 508 431 509 432 508 432 508 434 506 1379 509 432 508 432 508 433 507 431 509 433 507 432 508 433 507 432 508 432 508 432 508 431 509 1380 508 432 508 432 508 1380 508 431 509 433 507 432 508 432 508 432 508 431 509 432 508 1381 507 431 509 1382 506 1380 508 1380 508 1380 508 1380 507 434 506 433 507 433 507 431 509 1380 508 1380 508 432 508 +# +name: TEMP+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3828 1855 504 431 508 1382 506 434 506 1382 506 434 506 1381 507 432 508 1381 507 434 506 1381 560 381 506 1381 507 1410 478 433 507 1382 506 436 504 1381 507 1382 506 1409 479 1382 506 433 507 433 507 1381 507 1383 505 435 505 434 506 432 508 433 507 1381 507 433 507 435 505 432 508 1381 507 1382 506 433 507 1382 506 1380 508 433 507 1382 506 1379 509 1381 507 432 508 433 507 433 507 1381 507 1380 508 433 507 433 507 432 508 1380 508 432 508 432 508 434 506 1380 508 432 508 432 508 432 508 432 508 434 506 434 506 433 507 433 507 434 506 432 508 433 507 432 508 435 505 1383 505 433 507 433 507 434 506 433 507 433 507 432 508 433 507 434 506 433 507 433 507 432 508 1382 506 432 508 431 509 1381 507 433 507 434 506 434 506 432 508 433 507 434 506 433 507 1380 508 431 509 1381 507 1409 479 1382 506 1383 505 1381 507 435 505 433 507 433 507 1382 506 1380 508 1382 506 433 507 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3778 1903 508 432 508 1380 508 431 509 1379 509 430 510 1379 509 431 509 1382 506 432 508 1378 510 431 509 1379 509 1381 507 431 509 1379 509 432 508 1379 509 1379 509 1380 508 1381 507 431 509 431 509 1380 508 1379 509 430 510 431 509 431 509 432 508 1379 509 430 510 432 508 431 508 1379 509 430 510 1379 509 1381 507 430 509 432 508 431 509 431 509 1378 510 431 509 431 509 431 509 1380 508 1378 510 432 508 430 510 1379 509 1380 508 431 509 432 508 432 508 1379 509 432 508 431 509 431 509 432 508 431 509 431 509 431 508 431 509 432 508 431 509 431 509 431 509 431 509 1381 507 430 510 431 509 431 509 431 509 431 509 431 509 431 509 430 510 431 509 431 509 432 508 1378 510 431 509 431 509 430 510 431 509 432 508 431 509 431 509 430 510 431 509 431 509 1379 509 431 509 1379 509 1380 508 1379 509 1379 509 1379 509 432 508 431 509 431 509 1379 509 431 509 431 509 1379 509 +# +name: POWER +type: parsed +protocol: NEC +address: 04 00 00 00 +command: 04 00 00 00 +# +name: TEMP+ +type: parsed +protocol: NEC +address: 04 00 00 00 +command: 05 00 00 00 +# +name: TEMP- +type: parsed +protocol: NEC +address: 04 00 00 00 +command: 01 00 00 00 +# +name: MODE +type: parsed +protocol: NEC +address: 04 00 00 00 +command: 0D 00 00 00 +# +name: TIMER +type: parsed +protocol: NEC +address: 04 00 00 00 +command: 00 00 00 00 diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index 0adb61efb..7e93cb3b8 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 29th Mar, 2023 -# Last Checked 29th Mar, 2023 +# Last Updated 14th Apr, 2023 +# Last Checked 14th Apr, 2023 # name: POWER type: parsed @@ -2134,3 +2134,45 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 2701 861 496 420 445 444 444 885 446 871 892 441 444 441 444 441 471 415 471 415 470 417 467 444 440 446 883 891 436 449 437 449 437 450 436 450 436 449 883 448 437 451 436 894 436 450 436 450 436 450 436 450 436 450 882 449 436 894 883 116552 2698 862 469 448 438 449 438 894 437 880 884 448 437 449 437 448 438 449 437 449 437 449 437 449 437 449 884 890 437 449 437 449 437 449 437 449 437 449 884 448 437 450 437 893 437 449 437 449 437 449 437 449 437 449 884 448 436 894 883 +# +name: VOL+ +type: parsed +protocol: NECext +address: 10 E7 00 00 +command: 3C C3 00 00 +# +name: VOL- +type: parsed +protocol: NECext +address: 10 E7 00 00 +command: 4D B2 00 00 +# +name: POWER +type: parsed +protocol: Kaseikyo +address: 52 54 32 00 +command: 83 00 00 00 +# +name: MUTE +type: parsed +protocol: Kaseikyo +address: 52 54 32 00 +command: 86 00 00 00 +# +name: VOL+ +type: parsed +protocol: Kaseikyo +address: 52 54 32 00 +command: 84 00 00 00 +# +name: VOL- +type: parsed +protocol: Kaseikyo +address: 52 54 32 00 +command: 85 00 00 00 +# +name: POWER +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 46 00 00 00 diff --git a/assets/resources/infrared/assets/fans.ir b/assets/resources/infrared/assets/fans.ir index f451ba483..134133e17 100644 --- a/assets/resources/infrared/assets/fans.ir +++ b/assets/resources/infrared/assets/fans.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 15th Feb, 2023 -# Last Checked 29th Mar, 2023 +# Last Updated 14th Apr, 2023 +# Last Checked 14th Apr, 2023 # name: POWER type: raw @@ -1419,3 +1419,81 @@ type: parsed protocol: NECext address: 80 DE 00 00 command: 10 EF 00 00 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4640 4393 562 1442 562 1443 562 1443 537 1470 535 1468 562 1444 562 2398 562 1444 562 1446 560 2424 535 1470 535 2425 534 1472 533 1473 533 2427 533 1474 531 1473 4577 4456 531 1473 531 1474 532 1474 531 1474 532 1474 531 1474 531 2429 531 1474 531 1474 531 2429 531 1474 531 2429 531 1474 531 1474 531 2429 531 1474 531 14007 9125 2259 530 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4609 4425 563 1441 563 1442 563 1442 538 1469 537 1469 561 1444 562 2400 560 1470 535 1470 536 1470 536 2424 536 1470 535 1471 534 1472 533 2427 533 2427 533 1472 4580 4454 531 1472 533 1474 532 1474 531 1474 532 1474 532 1474 532 2428 532 1474 532 1474 532 1474 532 2428 532 1474 532 1474 532 1474 532 2428 532 2429 532 14008 9127 2258 528 50213 9131 2253 532 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4607 4424 563 1441 563 1443 563 1444 536 1469 537 1469 537 1496 534 2399 561 1470 535 2424 536 1470 536 1470 535 2424 535 1471 534 1472 534 1472 533 2427 533 1472 4579 4455 531 1472 532 1474 532 1474 532 1474 532 1474 532 1474 532 2429 531 1474 532 2428 532 1474 532 1474 532 2429 532 1474 532 1474 532 1474 532 2428 532 14007 9125 2258 530 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4604 4427 561 1442 562 1443 561 1444 537 1469 536 1469 562 1445 561 2399 560 1446 559 2424 534 1472 533 2426 533 1473 532 2428 531 1475 531 1474 531 1474 531 1473 4575 4457 530 1473 531 1475 531 1475 530 1475 531 1475 531 1475 530 2429 531 1475 530 2429 530 1475 530 2430 530 1475 530 2429 531 1475 531 1475 531 1475 530 14008 9122 2260 530 +# +name: ROTATE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4582 4424 562 1442 562 1471 534 1471 509 1496 510 1496 534 1472 534 2424 536 1470 536 1470 536 1470 536 1470 535 2424 535 2425 534 2426 534 1472 533 1473 533 1472 4581 4453 532 1472 532 1473 533 1473 533 1473 533 1473 533 1473 533 2428 532 1473 532 1473 532 1474 532 1474 532 2428 533 2428 532 2428 532 1474 532 1474 532 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1369 311 1327 312 498 1162 1286 355 1285 362 457 1221 458 1221 458 1221 458 1222 457 1221 458 1219 1312 6796 1310 330 1282 356 454 1219 1281 360 1280 367 452 1227 452 1227 452 1227 452 1227 452 1227 452 1225 1280 6815 1280 359 1279 359 451 1220 1280 361 1279 368 451 1228 451 1228 451 1228 451 1228 451 1228 451 1226 1279 6827 1279 382 1256 382 428 1245 1255 384 1256 391 427 1251 428 1252 426 1252 427 1252 427 1252 427 1250 1255 6838 1255 383 1255 383 426 1245 1255 385 1255 392 426 1252 427 1252 426 1252 426 1252 427 1252 426 1250 1255 6849 1255 383 1255 383 426 1245 1255 385 1254 392 426 1252 426 1252 426 1252 426 1252 426 1252 426 1250 1254 6835 1254 383 1254 383 426 1245 1254 385 1254 392 426 1252 426 1252 426 1252 426 1252 426 1252 426 1250 1254 6852 1254 383 1254 384 425 1245 1254 386 1253 392 426 1253 425 1252 426 1252 426 1253 425 1253 425 1251 1253 6835 1253 384 1253 384 425 1245 1253 386 1253 393 425 1252 425 1253 425 1253 425 1253 425 1253 425 1251 1253 6852 1252 384 1253 384 425 1246 1252 386 1253 393 425 1253 424 1253 425 1253 425 1254 424 1253 425 1252 1252 6835 1253 385 1252 385 424 1247 1252 387 1252 394 424 1254 424 1254 424 1254 424 1254 424 1254 424 1252 1251 6850 1251 386 1251 386 423 1248 1251 388 1250 395 423 1255 422 1256 422 1279 399 1280 398 1279 399 1277 1227 6862 1226 411 1226 411 398 1273 1226 413 1226 420 397 1280 398 1279 398 1280 397 1280 398 1280 398 1278 1226 6892 1226 411 1225 411 397 1273 1225 413 1225 420 397 1280 397 1280 398 1280 397 1280 397 1280 397 1279 1224 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1308 332 1305 332 479 1190 1309 333 1307 364 455 1199 479 1198 481 1198 480 1198 480 1197 1331 339 480 7657 1306 332 1305 332 479 1194 1304 335 1305 342 478 1201 477 1201 478 1201 477 1201 478 1199 1305 342 478 7647 1305 333 1304 333 478 1194 1304 335 1304 342 477 1201 477 1201 478 1201 477 1201 477 1199 1305 342 478 7660 1303 334 1304 333 478 1194 1304 336 1303 343 477 1202 477 1202 476 1202 477 1202 476 1200 1304 343 477 7647 1303 334 1304 334 476 1195 1303 336 1303 343 476 1202 476 1202 476 1202 476 1202 476 1200 1303 343 476 7659 1302 335 1302 335 476 1196 1302 337 1302 344 475 1203 475 1203 475 1203 475 1203 475 1201 1302 344 476 7646 1302 335 1300 338 474 1197 1300 338 1301 345 474 1204 474 1204 474 1204 449 1229 449 1227 1275 370 449 7690 1275 362 1275 361 449 1222 1275 364 1275 371 448 1230 448 1230 448 1231 447 1232 446 1229 1274 372 447 +# +name: ROTATE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1338 312 1380 310 446 1133 1313 356 1284 362 457 1221 457 1219 1285 363 456 1221 457 1222 482 1196 482 7655 1282 356 1281 357 453 1219 1279 360 1279 367 452 1226 452 1224 1280 367 452 1226 452 1226 452 1226 452 7671 1279 358 1279 358 452 1219 1279 360 1279 367 452 1227 451 1225 1279 367 451 1227 451 1227 451 1227 451 7682 1279 359 1278 359 451 1220 1278 361 1278 368 451 1227 450 1225 1278 368 451 1227 451 1228 450 1228 450 7691 1277 360 1277 360 450 1221 1277 362 1277 368 450 1228 449 1226 1277 369 449 1229 449 1252 426 1252 426 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1338 311 1326 312 497 1134 1364 311 1276 361 457 1221 457 1220 457 1218 1283 361 456 1221 456 1221 457 7676 1285 351 1285 351 457 1213 1286 353 1285 360 457 1220 457 1220 457 1219 1285 361 456 1221 456 1222 481 7639 1283 353 1284 353 455 1216 1283 356 1282 363 454 1223 455 1223 454 1221 1283 363 454 1223 454 1223 454 7676 1282 354 1282 354 454 1217 1282 356 1282 364 453 1223 454 1223 454 1221 1282 363 454 1224 453 1224 454 7681 1281 355 1281 355 453 1217 1281 357 1281 364 453 1225 452 1225 452 1222 1281 365 452 1225 452 1225 452 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3565 3379 984 2506 984 2505 985 797 900 2590 900 2590 926 2572 926 826 925 829 922 858 894 859 894 858 895 2604 894 859 894 859 894 2596 894 859 894 859 894 867 894 2596 894 2596 894 2596 894 2596 894 2596 894 867 894 40343 3530 3468 895 2596 894 2596 894 859 894 2596 894 2596 894 2604 894 859 894 859 894 859 894 859 894 859 894 2604 894 859 894 859 894 2596 894 859 894 859 894 867 894 2596 894 2596 894 2596 894 2596 895 2596 894 866 895 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3595 3377 930 2561 929 2561 929 853 900 2591 899 2590 900 2597 901 2590 925 2565 924 2567 922 2570 920 2596 894 866 895 858 895 858 895 2596 894 858 895 859 894 866 895 858 895 858 895 858 895 859 894 858 895 2604 894 40343 3533 3467 895 2595 895 2596 894 858 895 2596 894 2596 894 2604 895 2596 894 2596 894 2596 894 2596 894 2596 894 867 894 859 894 859 894 2596 894 859 894 859 894 867 894 859 894 859 894 859 894 859 894 859 894 2605 893 40319 3533 3442 920 2595 895 2596 894 858 895 2596 894 2596 894 2604 894 2596 894 2596 894 2596 894 2596 894 2596 894 867 894 859 894 859 894 2596 894 859 894 859 894 867 894 859 894 859 894 859 894 859 894 859 894 2604 894 +# +name: ROTATE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3594 3380 981 2505 930 2560 930 853 900 2590 900 2590 900 2598 900 2589 900 853 924 2568 921 2571 919 2596 894 867 894 859 894 859 894 2596 894 859 894 859 894 867 894 859 894 2596 894 859 894 859 894 859 894 2604 894 40335 3532 3467 895 2596 894 2596 895 859 894 2596 894 2596 894 2605 894 2596 894 859 894 2596 894 2597 894 2596 894 867 894 859 894 859 894 2596 894 859 894 859 894 867 894 859 894 2597 894 859 894 859 894 859 894 2605 893 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3534 3439 954 2505 985 2535 955 798 954 2535 899 2591 899 2599 899 853 925 2566 924 2567 922 2596 894 2596 894 867 894 859 894 860 893 2597 894 859 894 859 894 867 894 2597 893 859 894 859 894 860 893 859 894 2605 894 40336 3531 3469 894 2597 893 2597 893 859 894 2597 893 2597 893 2605 893 860 893 2597 893 2597 893 2597 894 2597 893 868 893 860 893 860 893 2597 893 860 893 860 893 868 893 2597 893 860 893 860 893 860 893 860 893 2605 893 diff --git a/assets/resources/infrared/assets/projectors.ir b/assets/resources/infrared/assets/projectors.ir index 92f5a8eeb..c039f2389 100644 --- a/assets/resources/infrared/assets/projectors.ir +++ b/assets/resources/infrared/assets/projectors.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 07th Mar, 2023 -# Last Checked 29th Mar, 2023 +# Last Updated 14th Apr, 2023 +# Last Checked 14th Apr, 2023 # # ON name: POWER @@ -874,3 +874,15 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 9035 4437 563 548 563 548 563 522 594 1645 591 1639 592 518 593 548 563 552 563 1640 592 548 563 553 562 1668 564 524 592 1642 594 1674 562 1673 563 1639 593 548 563 552 564 1669 562 548 563 520 615 529 586 1645 587 529 587 1650 586 1646 586 529 586 1650 586 1649 587 1646 586 524 587 524 587 524 587 524 587 525 643 467 644 440 671 467 644 472 643 1592 644 1593 643 1593 642 1594 641 1594 587 1649 585 1651 563 1682 562 14430 9008 2205 562 +# +name: VOL+ +type: parsed +protocol: NECext +address: 84 F4 00 00 +command: 2C D3 00 00 +# +name: VOL- +type: parsed +protocol: NECext +address: 84 F4 00 00 +command: 2F D0 00 00 diff --git a/assets/resources/infrared/assets/tv.ir b/assets/resources/infrared/assets/tv.ir index fe2108537..4d9c38f98 100644 --- a/assets/resources/infrared/assets/tv.ir +++ b/assets/resources/infrared/assets/tv.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 # Last Updated 07th Mar, 2023 -# Last Checked 29th Mar, 2023 +# Last Checked 14th Apr, 2023 # name: POWER type: parsed diff --git a/debug/flipperapps.py b/debug/flipperapps.py index 1dc5ebd04..90582c1e4 100644 --- a/debug/flipperapps.py +++ b/debug/flipperapps.py @@ -135,6 +135,7 @@ class FlipperAppStateHelper: self.app_list_ptr = None self.app_list_entry_type = None self._current_apps: list[AppState] = [] + self.set_debug_mode(True) def _walk_app_list(self, list_head): while list_head: @@ -195,7 +196,7 @@ class FlipperAppStateHelper: self.set_debug_mode(False) def set_debug_mode(self, mode: bool) -> None: - gdb.execute(f"set variable fap_loader_debug_active = {int(mode)}") + gdb.execute(f"set variable furi_hal_debug_gdb_session_active = {int(mode)}") # Init additional 'fap-set-debug-elf-root' command and set up hooks diff --git a/fbt_options.py b/fbt_options.py index 0e87521a1..8edd30758 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -20,7 +20,7 @@ DIST_SUFFIX = "XFW-0044_09042023" COPRO_OB_DATA = "scripts/ob.data" # Must match lib/STM32CubeWB version -COPRO_CUBE_VERSION = "1.13.3" +COPRO_CUBE_VERSION = "1.15.0" COPRO_CUBE_DIR = "lib/STM32CubeWB" diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index df4401aab..0852b9243 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,21.0,, +Version,+,23.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -176,17 +176,17 @@ Header,+,lib/toolbox/tar/tar_archive.h,, Header,+,lib/toolbox/value_index.h,, Header,+,lib/toolbox/version.h,, Function,-,LL_ADC_CommonDeInit,ErrorStatus,ADC_Common_TypeDef* -Function,-,LL_ADC_CommonInit,ErrorStatus,"ADC_Common_TypeDef*, LL_ADC_CommonInitTypeDef*" +Function,-,LL_ADC_CommonInit,ErrorStatus,"ADC_Common_TypeDef*, const LL_ADC_CommonInitTypeDef*" Function,-,LL_ADC_CommonStructInit,void,LL_ADC_CommonInitTypeDef* Function,-,LL_ADC_DeInit,ErrorStatus,ADC_TypeDef* -Function,-,LL_ADC_INJ_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_INJ_InitTypeDef*" +Function,-,LL_ADC_INJ_Init,ErrorStatus,"ADC_TypeDef*, const LL_ADC_INJ_InitTypeDef*" Function,-,LL_ADC_INJ_StructInit,void,LL_ADC_INJ_InitTypeDef* -Function,-,LL_ADC_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_InitTypeDef*" -Function,-,LL_ADC_REG_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_REG_InitTypeDef*" +Function,-,LL_ADC_Init,ErrorStatus,"ADC_TypeDef*, const LL_ADC_InitTypeDef*" +Function,-,LL_ADC_REG_Init,ErrorStatus,"ADC_TypeDef*, const LL_ADC_REG_InitTypeDef*" Function,-,LL_ADC_REG_StructInit,void,LL_ADC_REG_InitTypeDef* Function,-,LL_ADC_StructInit,void,LL_ADC_InitTypeDef* Function,-,LL_COMP_DeInit,ErrorStatus,COMP_TypeDef* -Function,+,LL_COMP_Init,ErrorStatus,"COMP_TypeDef*, LL_COMP_InitTypeDef*" +Function,+,LL_COMP_Init,ErrorStatus,"COMP_TypeDef*, const LL_COMP_InitTypeDef*" Function,-,LL_COMP_StructInit,void,LL_COMP_InitTypeDef* Function,-,LL_CRC_DeInit,ErrorStatus,CRC_TypeDef* Function,-,LL_CRS_DeInit,ErrorStatus, @@ -205,10 +205,10 @@ Function,-,LL_I2C_StructInit,void,LL_I2C_InitTypeDef* Function,-,LL_Init1msTick,void,uint32_t Function,+,LL_LPTIM_DeInit,ErrorStatus,LPTIM_TypeDef* Function,-,LL_LPTIM_Disable,void,LPTIM_TypeDef* -Function,+,LL_LPTIM_Init,ErrorStatus,"LPTIM_TypeDef*, LL_LPTIM_InitTypeDef*" +Function,+,LL_LPTIM_Init,ErrorStatus,"LPTIM_TypeDef*, const LL_LPTIM_InitTypeDef*" Function,-,LL_LPTIM_StructInit,void,LL_LPTIM_InitTypeDef* -Function,-,LL_LPUART_DeInit,ErrorStatus,USART_TypeDef* -Function,+,LL_LPUART_Init,ErrorStatus,"USART_TypeDef*, LL_LPUART_InitTypeDef*" +Function,-,LL_LPUART_DeInit,ErrorStatus,const USART_TypeDef* +Function,+,LL_LPUART_Init,ErrorStatus,"USART_TypeDef*, const LL_LPUART_InitTypeDef*" Function,-,LL_LPUART_StructInit,void,LL_LPUART_InitTypeDef* Function,-,LL_PKA_DeInit,ErrorStatus,PKA_TypeDef* Function,-,LL_PKA_Init,ErrorStatus,"PKA_TypeDef*, LL_PKA_InitTypeDef*" @@ -253,23 +253,23 @@ Function,+,LL_SPI_Init,ErrorStatus,"SPI_TypeDef*, LL_SPI_InitTypeDef*" Function,-,LL_SPI_StructInit,void,LL_SPI_InitTypeDef* Function,-,LL_SetFlashLatency,ErrorStatus,uint32_t Function,+,LL_SetSystemCoreClock,void,uint32_t -Function,-,LL_TIM_BDTR_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_BDTR_InitTypeDef*" +Function,-,LL_TIM_BDTR_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_BDTR_InitTypeDef*" Function,-,LL_TIM_BDTR_StructInit,void,LL_TIM_BDTR_InitTypeDef* -Function,+,LL_TIM_DeInit,ErrorStatus,TIM_TypeDef* -Function,-,LL_TIM_ENCODER_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_ENCODER_InitTypeDef*" +Function,-,LL_TIM_DeInit,ErrorStatus,TIM_TypeDef* +Function,-,LL_TIM_ENCODER_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_ENCODER_InitTypeDef*" Function,-,LL_TIM_ENCODER_StructInit,void,LL_TIM_ENCODER_InitTypeDef* -Function,-,LL_TIM_HALLSENSOR_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_HALLSENSOR_InitTypeDef*" +Function,-,LL_TIM_HALLSENSOR_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_HALLSENSOR_InitTypeDef*" Function,-,LL_TIM_HALLSENSOR_StructInit,void,LL_TIM_HALLSENSOR_InitTypeDef* -Function,-,LL_TIM_IC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, LL_TIM_IC_InitTypeDef*" +Function,-,LL_TIM_IC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, const LL_TIM_IC_InitTypeDef*" Function,-,LL_TIM_IC_StructInit,void,LL_TIM_IC_InitTypeDef* -Function,+,LL_TIM_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_InitTypeDef*" -Function,+,LL_TIM_OC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, LL_TIM_OC_InitTypeDef*" +Function,+,LL_TIM_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_InitTypeDef*" +Function,+,LL_TIM_OC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, const LL_TIM_OC_InitTypeDef*" Function,-,LL_TIM_OC_StructInit,void,LL_TIM_OC_InitTypeDef* Function,-,LL_TIM_StructInit,void,LL_TIM_InitTypeDef* -Function,-,LL_USART_ClockInit,ErrorStatus,"USART_TypeDef*, LL_USART_ClockInitTypeDef*" +Function,-,LL_USART_ClockInit,ErrorStatus,"USART_TypeDef*, const LL_USART_ClockInitTypeDef*" Function,-,LL_USART_ClockStructInit,void,LL_USART_ClockInitTypeDef* -Function,-,LL_USART_DeInit,ErrorStatus,USART_TypeDef* -Function,+,LL_USART_Init,ErrorStatus,"USART_TypeDef*, LL_USART_InitTypeDef*" +Function,-,LL_USART_DeInit,ErrorStatus,const USART_TypeDef* +Function,+,LL_USART_Init,ErrorStatus,"USART_TypeDef*, const LL_USART_InitTypeDef*" Function,-,LL_USART_StructInit,void,LL_USART_InitTypeDef* Function,-,LL_mDelay,void,uint32_t Function,-,SystemCoreClockUpdate,void, @@ -901,6 +901,7 @@ Function,+,furi_hal_crypto_verify_enclave,_Bool,"uint8_t*, uint8_t*" Function,+,furi_hal_crypto_verify_key,_Bool,uint8_t Function,+,furi_hal_debug_disable,void, Function,+,furi_hal_debug_enable,void, +Function,+,furi_hal_debug_is_gdb_session_active,_Bool, Function,-,furi_hal_deinit_early,void, Function,-,furi_hal_flash_erase,void,uint8_t Function,-,furi_hal_flash_get_base,size_t, @@ -983,7 +984,6 @@ Function,-,furi_hal_os_init,void, Function,+,furi_hal_os_tick,void, Function,+,furi_hal_power_check_otg_status,void, Function,+,furi_hal_power_debug_get,void,"PropertyValueCallback, void*" -Function,+,furi_hal_power_deep_sleep_available,_Bool, Function,+,furi_hal_power_disable_external_3_3v,void, Function,+,furi_hal_power_disable_otg,void, Function,+,furi_hal_power_enable_external_3_3v,void, @@ -1059,6 +1059,7 @@ Function,+,furi_hal_rtc_set_locale_units,void,FuriHalRtcLocaleUnits Function,+,furi_hal_rtc_set_log_level,void,uint8_t Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t" +Function,+,furi_hal_rtc_sync_shadow,void, Function,+,furi_hal_rtc_validate_datetime,_Bool,FuriHalRtcDateTime* Function,+,furi_hal_speaker_acquire,_Bool,uint32_t Function,-,furi_hal_speaker_deinit,void, @@ -1596,7 +1597,8 @@ Function,-,rindex,char*,"const char*, int" Function,+,rpc_session_close,void,RpcSession* Function,+,rpc_session_feed,size_t,"RpcSession*, uint8_t*, size_t, TickType_t" Function,+,rpc_session_get_available_size,size_t,RpcSession* -Function,+,rpc_session_open,RpcSession*,Rpc* +Function,+,rpc_session_get_owner,RpcOwner,RpcSession* +Function,+,rpc_session_open,RpcSession*,"Rpc*, RpcOwner" Function,+,rpc_session_set_buffer_is_empty_callback,void,"RpcSession*, RpcBufferIsEmptyCallback" Function,+,rpc_session_set_close_callback,void,"RpcSession*, RpcSessionClosedCallback" Function,+,rpc_session_set_context,void,"RpcSession*, void*" @@ -2150,6 +2152,8 @@ Variable,+,gpio_ext_pd0,const GpioPin, Variable,+,gpio_ext_pe4,const GpioPin, Variable,+,gpio_i2c_power_scl,const GpioPin, Variable,+,gpio_i2c_power_sda,const GpioPin, +Variable,+,gpio_ibutton,const GpioPin, +Variable,+,gpio_periph_power,const GpioPin, Variable,+,gpio_pins,const GpioPinRecord[], Variable,+,gpio_pins_count,const size_t, Variable,+,gpio_sdcard_cd,const GpioPin, @@ -2158,11 +2162,13 @@ Variable,+,gpio_speaker,const GpioPin, Variable,+,gpio_spi_d_miso,const GpioPin, Variable,+,gpio_spi_d_mosi,const GpioPin, Variable,+,gpio_spi_d_sck,const GpioPin, +Variable,+,gpio_swclk,const GpioPin, +Variable,+,gpio_swdio,const GpioPin, Variable,+,gpio_usart_rx,const GpioPin, Variable,+,gpio_usart_tx,const GpioPin, Variable,+,gpio_usb_dm,const GpioPin, Variable,+,gpio_usb_dp,const GpioPin, -Variable,+,gpio_ibutton,const GpioPin, +Variable,+,gpio_vibro,const GpioPin, Variable,+,input_pins,const InputPin[], Variable,+,input_pins_count,const size_t, Variable,+,message_blink_set_color_blue,const NotificationMessage, @@ -2310,7 +2316,6 @@ Variable,+,message_red_255,const NotificationMessage, Variable,+,message_sound_off,const NotificationMessage, Variable,+,message_vibro_off,const NotificationMessage, Variable,+,message_vibro_on,const NotificationMessage, -Variable,+,gpio_periph_power,const GpioPin, Variable,+,sequence_audiovisual_alert,const NotificationSequence, Variable,+,sequence_blink_blue_10,const NotificationSequence, Variable,+,sequence_blink_blue_100,const NotificationSequence, @@ -2365,4 +2370,3 @@ Variable,+,usb_cdc_single,FuriHalUsbInterface, Variable,+,usb_hid,FuriHalUsbInterface, Variable,+,usb_hid_u2f,FuriHalUsbInterface, Variable,+,usbd_devfs,const usbd_driver, -Variable,+,gpio_vibro,const GpioPin, diff --git a/firmware/targets/f18/furi_hal/furi_hal_resources.c b/firmware/targets/f18/furi_hal/furi_hal_resources.c index 19bc9f998..6db483dbc 100644 --- a/firmware/targets/f18/furi_hal/furi_hal_resources.c +++ b/firmware/targets/f18/furi_hal/furi_hal_resources.c @@ -6,6 +6,9 @@ #define TAG "FuriHalResources" +const GpioPin gpio_swdio = {.port = GPIOA, .pin = LL_GPIO_PIN_13}; +const GpioPin gpio_swclk = {.port = GPIOA, .pin = LL_GPIO_PIN_14}; + const GpioPin gpio_vibro = {.port = GPIOA, .pin = LL_GPIO_PIN_8}; const GpioPin gpio_ibutton = {.port = GPIOB, .pin = LL_GPIO_PIN_14}; @@ -166,8 +169,9 @@ void furi_hal_resources_init() { furi_hal_resources_init_input_pins(GpioModeInterruptRiseFall); // Explicit pulls pins - furi_hal_gpio_init(&gpio_speaker, GpioModeAnalog, GpioPullDown, GpioSpeedLow); - furi_hal_gpio_init(&gpio_vibro, GpioModeAnalog, GpioPullDown, GpioSpeedLow); + LL_PWR_EnablePUPDCfg(); + LL_PWR_EnableGPIOPullDown(LL_PWR_GPIO_B, LL_PWR_GPIO_BIT_8); // gpio_speaker + LL_PWR_EnableGPIOPullDown(LL_PWR_GPIO_A, LL_PWR_GPIO_BIT_8); // gpio_vibro // Display pins furi_hal_gpio_init(&gpio_display_rst_n, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); diff --git a/firmware/targets/f18/furi_hal/furi_hal_resources.h b/firmware/targets/f18/furi_hal/furi_hal_resources.h index 3c4708d15..7d2caab36 100644 --- a/firmware/targets/f18/furi_hal/furi_hal_resources.h +++ b/firmware/targets/f18/furi_hal/furi_hal_resources.h @@ -50,6 +50,9 @@ extern const size_t input_pins_count; extern const GpioPinRecord gpio_pins[]; extern const size_t gpio_pins_count; +extern const GpioPin gpio_swdio; +extern const GpioPin gpio_swclk; + extern const GpioPin gpio_vibro; extern const GpioPin gpio_ibutton; diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 62c3516be..80e81923f 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,21.0,, +Version,+,23.0,, Header,+,applications/main/fap_loader/fap_loader_app.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -219,17 +219,17 @@ Header,+,lib/toolbox/value_index.h,, Header,+,lib/toolbox/version.h,, Header,+,lib/u8g2/u8g2.h,, Function,-,LL_ADC_CommonDeInit,ErrorStatus,ADC_Common_TypeDef* -Function,-,LL_ADC_CommonInit,ErrorStatus,"ADC_Common_TypeDef*, LL_ADC_CommonInitTypeDef*" +Function,-,LL_ADC_CommonInit,ErrorStatus,"ADC_Common_TypeDef*, const LL_ADC_CommonInitTypeDef*" Function,-,LL_ADC_CommonStructInit,void,LL_ADC_CommonInitTypeDef* Function,-,LL_ADC_DeInit,ErrorStatus,ADC_TypeDef* -Function,-,LL_ADC_INJ_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_INJ_InitTypeDef*" +Function,-,LL_ADC_INJ_Init,ErrorStatus,"ADC_TypeDef*, const LL_ADC_INJ_InitTypeDef*" Function,-,LL_ADC_INJ_StructInit,void,LL_ADC_INJ_InitTypeDef* -Function,-,LL_ADC_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_InitTypeDef*" -Function,-,LL_ADC_REG_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_REG_InitTypeDef*" +Function,-,LL_ADC_Init,ErrorStatus,"ADC_TypeDef*, const LL_ADC_InitTypeDef*" +Function,-,LL_ADC_REG_Init,ErrorStatus,"ADC_TypeDef*, const LL_ADC_REG_InitTypeDef*" Function,-,LL_ADC_REG_StructInit,void,LL_ADC_REG_InitTypeDef* Function,-,LL_ADC_StructInit,void,LL_ADC_InitTypeDef* Function,-,LL_COMP_DeInit,ErrorStatus,COMP_TypeDef* -Function,+,LL_COMP_Init,ErrorStatus,"COMP_TypeDef*, LL_COMP_InitTypeDef*" +Function,+,LL_COMP_Init,ErrorStatus,"COMP_TypeDef*, const LL_COMP_InitTypeDef*" Function,-,LL_COMP_StructInit,void,LL_COMP_InitTypeDef* Function,-,LL_CRC_DeInit,ErrorStatus,CRC_TypeDef* Function,-,LL_CRS_DeInit,ErrorStatus, @@ -248,10 +248,10 @@ Function,-,LL_I2C_StructInit,void,LL_I2C_InitTypeDef* Function,-,LL_Init1msTick,void,uint32_t Function,+,LL_LPTIM_DeInit,ErrorStatus,LPTIM_TypeDef* Function,-,LL_LPTIM_Disable,void,LPTIM_TypeDef* -Function,+,LL_LPTIM_Init,ErrorStatus,"LPTIM_TypeDef*, LL_LPTIM_InitTypeDef*" +Function,+,LL_LPTIM_Init,ErrorStatus,"LPTIM_TypeDef*, const LL_LPTIM_InitTypeDef*" Function,-,LL_LPTIM_StructInit,void,LL_LPTIM_InitTypeDef* -Function,-,LL_LPUART_DeInit,ErrorStatus,USART_TypeDef* -Function,+,LL_LPUART_Init,ErrorStatus,"USART_TypeDef*, LL_LPUART_InitTypeDef*" +Function,-,LL_LPUART_DeInit,ErrorStatus,const USART_TypeDef* +Function,+,LL_LPUART_Init,ErrorStatus,"USART_TypeDef*, const LL_LPUART_InitTypeDef*" Function,-,LL_LPUART_StructInit,void,LL_LPUART_InitTypeDef* Function,-,LL_PKA_DeInit,ErrorStatus,PKA_TypeDef* Function,-,LL_PKA_Init,ErrorStatus,"PKA_TypeDef*, LL_PKA_InitTypeDef*" @@ -296,23 +296,23 @@ Function,+,LL_SPI_Init,ErrorStatus,"SPI_TypeDef*, LL_SPI_InitTypeDef*" Function,-,LL_SPI_StructInit,void,LL_SPI_InitTypeDef* Function,-,LL_SetFlashLatency,ErrorStatus,uint32_t Function,+,LL_SetSystemCoreClock,void,uint32_t -Function,-,LL_TIM_BDTR_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_BDTR_InitTypeDef*" +Function,-,LL_TIM_BDTR_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_BDTR_InitTypeDef*" Function,-,LL_TIM_BDTR_StructInit,void,LL_TIM_BDTR_InitTypeDef* Function,+,LL_TIM_DeInit,ErrorStatus,TIM_TypeDef* -Function,-,LL_TIM_ENCODER_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_ENCODER_InitTypeDef*" +Function,-,LL_TIM_ENCODER_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_ENCODER_InitTypeDef*" Function,-,LL_TIM_ENCODER_StructInit,void,LL_TIM_ENCODER_InitTypeDef* -Function,-,LL_TIM_HALLSENSOR_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_HALLSENSOR_InitTypeDef*" +Function,-,LL_TIM_HALLSENSOR_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_HALLSENSOR_InitTypeDef*" Function,-,LL_TIM_HALLSENSOR_StructInit,void,LL_TIM_HALLSENSOR_InitTypeDef* -Function,-,LL_TIM_IC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, LL_TIM_IC_InitTypeDef*" +Function,-,LL_TIM_IC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, const LL_TIM_IC_InitTypeDef*" Function,-,LL_TIM_IC_StructInit,void,LL_TIM_IC_InitTypeDef* -Function,+,LL_TIM_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_InitTypeDef*" -Function,+,LL_TIM_OC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, LL_TIM_OC_InitTypeDef*" +Function,+,LL_TIM_Init,ErrorStatus,"TIM_TypeDef*, const LL_TIM_InitTypeDef*" +Function,+,LL_TIM_OC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, const LL_TIM_OC_InitTypeDef*" Function,-,LL_TIM_OC_StructInit,void,LL_TIM_OC_InitTypeDef* Function,-,LL_TIM_StructInit,void,LL_TIM_InitTypeDef* -Function,-,LL_USART_ClockInit,ErrorStatus,"USART_TypeDef*, LL_USART_ClockInitTypeDef*" +Function,-,LL_USART_ClockInit,ErrorStatus,"USART_TypeDef*, const LL_USART_ClockInitTypeDef*" Function,-,LL_USART_ClockStructInit,void,LL_USART_ClockInitTypeDef* -Function,-,LL_USART_DeInit,ErrorStatus,USART_TypeDef* -Function,+,LL_USART_Init,ErrorStatus,"USART_TypeDef*, LL_USART_InitTypeDef*" +Function,-,LL_USART_DeInit,ErrorStatus,const USART_TypeDef* +Function,+,LL_USART_Init,ErrorStatus,"USART_TypeDef*, const LL_USART_InitTypeDef*" Function,-,LL_USART_StructInit,void,LL_USART_InitTypeDef* Function,-,LL_mDelay,void,uint32_t Function,-,SK6805_get_led_count,uint8_t, @@ -1179,6 +1179,7 @@ Function,+,furi_hal_crypto_verify_enclave,_Bool,"uint8_t*, uint8_t*" Function,+,furi_hal_crypto_verify_key,_Bool,uint8_t Function,+,furi_hal_debug_disable,void, Function,+,furi_hal_debug_enable,void, +Function,+,furi_hal_debug_is_gdb_session_active,_Bool, Function,-,furi_hal_deinit_early,void, Function,-,furi_hal_flash_erase,void,uint8_t Function,-,furi_hal_flash_get_base,size_t, @@ -1312,7 +1313,6 @@ Function,-,furi_hal_os_init,void, Function,+,furi_hal_os_tick,void, Function,+,furi_hal_power_check_otg_status,void, Function,+,furi_hal_power_debug_get,void,"PropertyValueCallback, void*" -Function,+,furi_hal_power_deep_sleep_available,_Bool, Function,+,furi_hal_power_disable_external_3_3v,void, Function,+,furi_hal_power_disable_otg,void, Function,+,furi_hal_power_enable_external_3_3v,void, @@ -1413,6 +1413,7 @@ Function,+,furi_hal_rtc_set_locale_units,void,FuriHalRtcLocaleUnits Function,+,furi_hal_rtc_set_log_level,void,uint8_t Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t" +Function,+,furi_hal_rtc_sync_shadow,void, Function,+,furi_hal_rtc_validate_datetime,_Bool,FuriHalRtcDateTime* Function,+,furi_hal_speaker_acquire,_Bool,uint32_t Function,-,furi_hal_speaker_deinit,void, @@ -1448,6 +1449,7 @@ Function,+,furi_hal_subghz_get_lqi,uint8_t, Function,+,furi_hal_subghz_get_radio_type,SubGhzRadioType, Function,+,furi_hal_subghz_get_rolling_counter_mult,uint8_t, Function,+,furi_hal_subghz_get_rssi,float, +Function,+,furi_hal_subghz_get_timestamp_file_names,_Bool, Function,+,furi_hal_subghz_idle,void, Function,-,furi_hal_subghz_init,void, Function,+,furi_hal_subghz_init_check,_Bool, @@ -1471,6 +1473,7 @@ Function,+,furi_hal_subghz_set_frequency_and_path,uint32_t,uint32_t Function,+,furi_hal_subghz_set_path,void,FuriHalSubGhzPath Function,+,furi_hal_subghz_set_radio_type,_Bool,SubGhzRadioType Function,+,furi_hal_subghz_set_rolling_counter_mult,void,uint8_t +Function,+,furi_hal_subghz_set_timestamp_file_names,void,_Bool Function,-,furi_hal_subghz_shutdown,void, Function,+,furi_hal_subghz_sleep,void, Function,+,furi_hal_subghz_start_async_rx,void,"FuriHalSubGhzCaptureCallback, void*" @@ -2265,6 +2268,7 @@ Function,+,power_get_settings_events_pubsub,FuriPubSub*,Power* Function,+,power_is_battery_healthy,_Bool,Power* Function,+,power_off,void,Power* Function,+,power_reboot,void,PowerBootMode +Function,+,power_trigger_ui_update,void,Power* Function,+,powf,float,"float, float" Function,-,powl,long double,"long double, long double" Function,+,pretty_format_bytes_hex_canonical,void,"FuriString*, size_t, const char*, const uint8_t*, size_t" @@ -2523,7 +2527,8 @@ Function,-,roundl,long double,long double Function,+,rpc_session_close,void,RpcSession* Function,+,rpc_session_feed,size_t,"RpcSession*, uint8_t*, size_t, TickType_t" Function,+,rpc_session_get_available_size,size_t,RpcSession* -Function,+,rpc_session_open,RpcSession*,Rpc* +Function,+,rpc_session_get_owner,RpcOwner,RpcSession* +Function,+,rpc_session_open,RpcSession*,"Rpc*, RpcOwner" Function,+,rpc_session_set_buffer_is_empty_callback,void,"RpcSession*, RpcBufferIsEmptyCallback" Function,+,rpc_session_set_close_callback,void,"RpcSession*, RpcSessionClosedCallback" Function,+,rpc_session_set_context,void,"RpcSession*, void*" @@ -2758,7 +2763,7 @@ Function,+,subghz_block_generic_get_preset_name,void,"const char*, FuriString*" Function,+,subghz_block_generic_serialize,SubGhzProtocolStatus,"SubGhzBlockGeneric*, FlipperFormat*, SubGhzRadioPreset*" Function,-,subghz_custom_btn_get,uint8_t, Function,-,subghz_custom_btn_get_original,uint8_t, -Function,-,subghz_custom_btn_set,void,uint8_t +Function,+,subghz_custom_btn_set,void,uint8_t Function,-,subghz_custom_btn_set_max,void,uint8_t Function,-,subghz_custom_btn_set_original,void,uint8_t Function,+,subghz_custom_btns_reset,void, @@ -4876,6 +4881,8 @@ Variable,+,gpio_spi_r_sck,const GpioPin, Variable,+,gpio_spi_r_sck_ext,const GpioPin, Variable,+,gpio_subghz_cs,const GpioPin, Variable,+,gpio_subghz_cs_ext,const GpioPin, +Variable,+,gpio_swclk,const GpioPin, +Variable,+,gpio_swdio,const GpioPin, Variable,+,gpio_usart_rx,const GpioPin, Variable,+,gpio_usart_tx,const GpioPin, Variable,+,gpio_usb_dm,const GpioPin, diff --git a/firmware/targets/f7/ble_glue/app_common.h b/firmware/targets/f7/ble_glue/app_common.h index 214c85acd..8eaf23085 100644 --- a/firmware/targets/f7/ble_glue/app_common.h +++ b/firmware/targets/f7/ble_glue/app_common.h @@ -33,6 +33,7 @@ extern "C" { #include #include +#include #include "app_conf.h" diff --git a/firmware/targets/f7/ble_glue/app_conf.h b/firmware/targets/f7/ble_glue/app_conf.h index aaa755a36..ee5115cfe 100644 --- a/firmware/targets/f7/ble_glue/app_conf.h +++ b/firmware/targets/f7/ble_glue/app_conf.h @@ -8,6 +8,8 @@ #define CFG_TX_POWER (0x19) /* +0dBm */ +#define CFG_IDENTITY_ADDRESS GAP_PUBLIC_ADDR + /** * Define Advertising parameters */ diff --git a/firmware/targets/f7/ble_glue/app_debug.c b/firmware/targets/f7/ble_glue/app_debug.c index d84588540..b443bee21 100644 --- a/firmware/targets/f7/ble_glue/app_debug.c +++ b/firmware/targets/f7/ble_glue/app_debug.c @@ -33,7 +33,8 @@ PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static SHCI_C2_DEBUG_TracesConfig_t APPD_TracesConfig = {0, 0, 0, 0}; PLACE_IN_SECTION("MB_MEM2") ALIGN(4) -static SHCI_C2_DEBUG_GeneralConfig_t APPD_GeneralConfig = {BLE_DTB_CFG, SYS_DBG_CFG1, {0, 0}}; +static SHCI_C2_DEBUG_GeneralConfig_t APPD_GeneralConfig = + {BLE_DTB_CFG, SYS_DBG_CFG1, {0, 0}, 0, 0, 0, 0, 0}; /** * THE DEBUG ON GPIO FOR CPU2 IS INTENDED TO BE USED ONLY ON REQUEST FROM ST SUPPORT @@ -68,7 +69,7 @@ static const APPD_GpioConfig_t aGpioConfigList[GPIO_CFG_NBR_OF_FEATURES] = { {GPIOA, LL_GPIO_PIN_0, 0, 0}, /* END_OF_CONNECTION_EVENT - Set on Entry / Reset on Exit */ {GPIOA, LL_GPIO_PIN_0, 0, 0}, /* TIMER_SERVER_CALLBACK - Toggle on Entry */ {GPIOA, LL_GPIO_PIN_4, 1, 0}, /* PES_ACTIVITY - Set on Entry / Reset on Exit */ - {GPIOB, LL_GPIO_PIN_2, 1, 0}, /* MB_BLE_SEND_EVT - Set on Entry / Reset on Exit */ + {GPIOC, LL_GPIO_PIN_0, 1, 0}, /* MB_BLE_SEND_EVT - Set on Entry / Reset on Exit */ /* From v1.3.0 */ {GPIOA, LL_GPIO_PIN_0, 0, 0}, /* BLE_NO_DELAY - Set on Entry / Reset on Exit */ {GPIOA, LL_GPIO_PIN_0, 0, 0}, /* BLE_STACK_STORE_NVM_CB - Set on Entry / Reset on Exit */ diff --git a/firmware/targets/f7/ble_glue/ble_app.c b/firmware/targets/f7/ble_glue/ble_app.c index 30be3c7ce..a325830cf 100644 --- a/firmware/targets/f7/ble_glue/ble_app.c +++ b/firmware/targets/f7/ble_glue/ble_app.c @@ -18,8 +18,8 @@ PLACE_IN_SECTION("MB_MEM1") ALIGN(4) static TL_CmdPacket_t ble_app_cmd_buffer; PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint32_t ble_app_nvm[BLE_NVM_SRAM_SIZE]; _Static_assert( - sizeof(SHCI_C2_Ble_Init_Cmd_Packet_t) == 49, - "Ble stack config structure size mismatch"); + sizeof(SHCI_C2_Ble_Init_Cmd_Packet_t) == 57, + "Ble stack config structure size mismatch (check new config options - last updated for v.1.15.0)"); typedef struct { FuriMutex* hci_mtx; @@ -88,6 +88,12 @@ bool ble_app_init() { .min_tx_power = 0, .max_tx_power = 0, .rx_model_config = 1, + /* New stack (13.3->16.0)*/ + .max_adv_set_nbr = 1, // Only used if SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV is set + .max_adv_data_len = 31, // Only used if SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV is set + .tx_path_compens = 0, // RF TX Path Compensation, * 0.1 dB + .rx_path_compens = 0, // RF RX Path Compensation, * 0.1 dB + .ble_core_version = 11, // BLE Core Version: 11(5.2), 12(5.3) }}; status = SHCI_C2_BLE_Init(&ble_init_cmd_packet); if(status) { @@ -137,38 +143,33 @@ static int32_t ble_app_hci_thread(void* arg) { // Called by WPAN lib void hci_notify_asynch_evt(void* pdata) { UNUSED(pdata); - if(ble_app) { - FuriThreadId thread_id = furi_thread_get_id(ble_app->thread); - furi_assert(thread_id); - furi_thread_flags_set(thread_id, BLE_APP_FLAG_HCI_EVENT); - } + furi_check(ble_app); + FuriThreadId thread_id = furi_thread_get_id(ble_app->thread); + furi_assert(thread_id); + furi_thread_flags_set(thread_id, BLE_APP_FLAG_HCI_EVENT); } void hci_cmd_resp_release(uint32_t flag) { UNUSED(flag); - if(ble_app) { - furi_semaphore_release(ble_app->hci_sem); - } + furi_check(ble_app); + furi_check(furi_semaphore_release(ble_app->hci_sem) == FuriStatusOk); } void hci_cmd_resp_wait(uint32_t timeout) { - UNUSED(timeout); - if(ble_app) { - furi_semaphore_acquire(ble_app->hci_sem, FuriWaitForever); - } + furi_check(ble_app); + furi_check(furi_semaphore_acquire(ble_app->hci_sem, timeout) == FuriStatusOk); } static void ble_app_hci_event_handler(void* pPayload) { SVCCTL_UserEvtFlowStatus_t svctl_return_status; tHCI_UserEvtRxParam* pParam = (tHCI_UserEvtRxParam*)pPayload; - if(ble_app) { - svctl_return_status = SVCCTL_UserEvtRx((void*)&(pParam->pckt->evtserial)); - if(svctl_return_status != SVCCTL_UserEvtFlowDisable) { - pParam->status = HCI_TL_UserEventFlow_Enable; - } else { - pParam->status = HCI_TL_UserEventFlow_Disable; - } + furi_check(ble_app); + svctl_return_status = SVCCTL_UserEvtRx((void*)&(pParam->pckt->evtserial)); + if(svctl_return_status != SVCCTL_UserEvtFlowDisable) { + pParam->status = HCI_TL_UserEventFlow_Enable; + } else { + pParam->status = HCI_TL_UserEventFlow_Disable; } } diff --git a/firmware/targets/f7/ble_glue/ble_const.h b/firmware/targets/f7/ble_glue/ble_const.h index 0e4c8b398..85f734b62 100644 --- a/firmware/targets/f7/ble_glue/ble_const.h +++ b/firmware/targets/f7/ble_glue/ble_const.h @@ -23,6 +23,7 @@ #include #include #include "osal.h" +#include "compiler.h" /* Default BLE variant */ #ifndef BASIC_FEATURES @@ -34,6 +35,9 @@ #ifndef LL_ONLY #define LL_ONLY 0 #endif +#ifndef LL_ONLY_BASIC +#define LL_ONLY_BASIC 0 +#endif #ifndef BEACON_ONLY #define BEACON_ONLY 0 #endif diff --git a/firmware/targets/f7/ble_glue/ble_glue.c b/firmware/targets/f7/ble_glue/ble_glue.c index 83562c73e..c73bbd866 100644 --- a/firmware/targets/f7/ble_glue/ble_glue.c +++ b/firmware/targets/f7/ble_glue/ble_glue.c @@ -58,12 +58,6 @@ void ble_glue_init() { ble_glue = malloc(sizeof(BleGlue)); ble_glue->status = BleGlueStatusStartup; - // Configure the system Power Mode - // Select HSI as system clock source after Wake Up from Stop mode - LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI); - /* Initialize the CPU2 reset value before starting CPU2 with C2BOOT */ - LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN); - #ifdef BLE_GLUE_DEBUG APPD_Init(); #endif @@ -409,7 +403,9 @@ void shci_cmd_resp_release(uint32_t flag) { void shci_cmd_resp_wait(uint32_t timeout) { UNUSED(timeout); if(ble_glue) { + furi_hal_power_insomnia_enter(); furi_semaphore_acquire(ble_glue->shci_sem, FuriWaitForever); + furi_hal_power_insomnia_exit(); } } diff --git a/firmware/targets/f7/ble_glue/compiler.h b/firmware/targets/f7/ble_glue/compiler.h index 1c3962819..98a93d712 100644 --- a/firmware/targets/f7/ble_glue/compiler.h +++ b/firmware/targets/f7/ble_glue/compiler.h @@ -5,7 +5,7 @@ ***************************************************************************** * @attention * - * Copyright (c) 2018-2022 STMicroelectronics. + * Copyright (c) 2018-2023 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file @@ -18,6 +18,14 @@ #ifndef COMPILER_H__ #define COMPILER_H__ +#ifndef __PACKED_STRUCT +#define __PACKED_STRUCT PACKED(struct) +#endif + +#ifndef __PACKED_UNION +#define __PACKED_UNION PACKED(union) +#endif + /** * @brief This is the section dedicated to IAR toolchain */ diff --git a/firmware/targets/f7/ble_glue/gap.c b/firmware/targets/f7/ble_glue/gap.c index ebf27b369..2eaedc28f 100644 --- a/firmware/targets/f7/ble_glue/gap.c +++ b/firmware/targets/f7/ble_glue/gap.c @@ -1,5 +1,6 @@ #include "gap.h" +#include "app_common.h" #include #include @@ -100,7 +101,7 @@ static void gap_verify_connection_parameters(Gap* gap) { SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { hci_event_pckt* event_pckt; evt_le_meta_event* meta_evt; - evt_blue_aci* blue_evt; + evt_blecore_aci* blue_evt; hci_le_phy_update_complete_event_rp0* evt_le_phy_update_complete; uint8_t tx_phy; uint8_t rx_phy; @@ -112,7 +113,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { furi_mutex_acquire(gap->state_mutex, FuriWaitForever); } switch(event_pckt->evt) { - case EVT_DISCONN_COMPLETE: { + case HCI_DISCONNECTION_COMPLETE_EVT_CODE: { hci_disconnection_complete_event_rp0* disconnection_complete_event = (hci_disconnection_complete_event_rp0*)event_pckt->data; if(disconnection_complete_event->Connection_Handle == gap->service.connection_handle) { @@ -121,6 +122,8 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { FURI_LOG_I( TAG, "Disconnect from client. Reason: %02X", disconnection_complete_event->Reason); } + // Enterprise sleep + furi_delay_us(666 + 666); if(gap->enable_adv) { // Restart advertising gap_advertise_start(GapStateAdvFast); @@ -129,10 +132,10 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { gap->on_event_cb(event, gap->context); } break; - case EVT_LE_META_EVENT: + case HCI_LE_META_EVT_CODE: meta_evt = (evt_le_meta_event*)event_pckt->data; switch(meta_evt->subevent) { - case EVT_LE_CONN_UPDATE_COMPLETE: { + case HCI_LE_CONNECTION_UPDATE_COMPLETE_SUBEVT_CODE: { hci_le_connection_update_complete_event_rp0* event = (hci_le_connection_update_complete_event_rp0*)meta_evt->data; gap->connection_params.conn_interval = event->Conn_Interval; @@ -146,7 +149,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { break; } - case EVT_LE_PHY_UPDATE_COMPLETE: + case HCI_LE_PHY_UPDATE_COMPLETE_SUBEVT_CODE: evt_le_phy_update_complete = (hci_le_phy_update_complete_event_rp0*)meta_evt->data; if(evt_le_phy_update_complete->Status) { FURI_LOG_E( @@ -162,7 +165,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { } break; - case EVT_LE_CONN_COMPLETE: { + case HCI_LE_CONNECTION_COMPLETE_SUBEVT_CODE: { hci_le_connection_complete_event_rp0* event = (hci_le_connection_complete_event_rp0*)meta_evt->data; gap->connection_params.conn_interval = event->Conn_Interval; @@ -189,16 +192,16 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { } break; - case EVT_VENDOR: - blue_evt = (evt_blue_aci*)event_pckt->data; + case HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE: + blue_evt = (evt_blecore_aci*)event_pckt->data; switch(blue_evt->ecode) { aci_gap_pairing_complete_event_rp0* pairing_complete; - case EVT_BLUE_GAP_LIMITED_DISCOVERABLE: + case ACI_GAP_LIMITED_DISCOVERABLE_VSEVT_CODE: FURI_LOG_I(TAG, "Limited discoverable event"); break; - case EVT_BLUE_GAP_PASS_KEY_REQUEST: { + case ACI_GAP_PASS_KEY_REQ_VSEVT_CODE: { // Generate random PIN code uint32_t pin = rand() % 999999; //-V1064 aci_gap_pass_key_resp(gap->service.connection_handle, pin); @@ -211,7 +214,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { gap->on_event_cb(event, gap->context); } break; - case EVT_BLUE_ATT_EXCHANGE_MTU_RESP: { + case ACI_ATT_EXCHANGE_MTU_RESP_VSEVT_CODE: { aci_att_exchange_mtu_resp_event_rp0* pr = (void*)blue_evt->data; FURI_LOG_I(TAG, "Rx MTU size: %d", pr->Server_RX_MTU); // Set maximum packet size given header size is 3 bytes @@ -220,32 +223,28 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { gap->on_event_cb(event, gap->context); } break; - case EVT_BLUE_GAP_AUTHORIZATION_REQUEST: + case ACI_GAP_AUTHORIZATION_REQ_VSEVT_CODE: FURI_LOG_D(TAG, "Authorization request event"); break; - case EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED: + case ACI_GAP_SLAVE_SECURITY_INITIATED_VSEVT_CODE: FURI_LOG_D(TAG, "Slave security initiated"); break; - case EVT_BLUE_GAP_BOND_LOST: + case ACI_GAP_BOND_LOST_VSEVT_CODE: FURI_LOG_D(TAG, "Bond lost event. Start rebonding"); aci_gap_allow_rebond(gap->service.connection_handle); break; - case EVT_BLUE_GAP_DEVICE_FOUND: - FURI_LOG_D(TAG, "Device found event"); - break; - - case EVT_BLUE_GAP_ADDR_NOT_RESOLVED: + case ACI_GAP_ADDR_NOT_RESOLVED_VSEVT_CODE: FURI_LOG_D(TAG, "Address not resolved event"); break; - case EVT_BLUE_GAP_KEYPRESS_NOTIFICATION: + case ACI_GAP_KEYPRESS_NOTIFICATION_VSEVT_CODE: FURI_LOG_D(TAG, "Key press notification event"); break; - case EVT_BLUE_GAP_NUMERIC_COMPARISON_VALUE: { + case ACI_GAP_NUMERIC_COMPARISON_VALUE_VSEVT_CODE: { uint32_t pin = ((aci_gap_numeric_comparison_value_event_rp0*)(blue_evt->data))->Numeric_Value; FURI_LOG_I(TAG, "Verify numeric comparison: %06lu", pin); @@ -255,7 +254,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { break; } - case EVT_BLUE_GAP_PAIRING_CMPLT: + case ACI_GAP_PAIRING_COMPLETE_VSEVT_CODE: pairing_complete = (aci_gap_pairing_complete_event_rp0*)blue_evt->data; if(pairing_complete->Status) { FURI_LOG_E( @@ -272,11 +271,11 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { } break; - case EVT_BLUE_GAP_PROCEDURE_COMPLETE: + case ACI_L2CAP_CONNECTION_UPDATE_RESP_VSEVT_CODE: FURI_LOG_D(TAG, "Procedure complete event"); break; - case EVT_BLUE_L2CAP_CONNECTION_UPDATE_RESP: { + case ACI_L2CAP_CONNECTION_UPDATE_REQ_VSEVT_CODE: { uint16_t result = ((aci_l2cap_connection_update_resp_event_rp0*)(blue_evt->data))->Result; if(result == 0) { @@ -312,8 +311,6 @@ static void gap_init_svc(Gap* gap) { tBleStatus status; uint32_t srd_bd_addr[2]; - // HCI Reset to synchronise BLE Stack - hci_reset(); // Configure mac address aci_hal_write_config_data( CONFIG_DATA_PUBADDR_OFFSET, CONFIG_DATA_PUBADDR_LEN, gap->config->mac_address); @@ -399,7 +396,7 @@ static void gap_init_svc(Gap* gap) { CFG_ENCRYPTION_KEY_SIZE_MAX, conf_used_fixed_pin, // 0x0 for no pin 0, - PUBLIC_ADDR); + CFG_IDENTITY_ADDRESS); // Configure whitelist aci_gap_configure_whitelist(); } @@ -434,7 +431,7 @@ static void gap_advertise_start(GapState new_state) { ADV_IND, min_interval, max_interval, - PUBLIC_ADDR, + CFG_IDENTITY_ADDRESS, 0, strlen(gap->service.adv_name), (uint8_t*)gap->service.adv_name, diff --git a/firmware/targets/f7/furi_hal/furi_hal_clock.c b/firmware/targets/f7/furi_hal/furi_hal_clock.c index cf19451ec..d85524ce4 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_clock.c +++ b/firmware/targets/f7/furi_hal/furi_hal_clock.c @@ -63,6 +63,10 @@ void furi_hal_clock_init() { LL_RCC_HSI_Enable(); while(!HS_CLOCK_IS_READY()) ; + /* Select HSI as system clock source after Wake Up from Stop mode + * Must be set before enabling CSS */ + LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI); + LL_RCC_HSE_EnableCSS(); /* LSE and LSI1 configuration and activation */ @@ -215,11 +219,14 @@ void furi_hal_clock_switch_to_hsi() { void furi_hal_clock_switch_to_pll() { LL_RCC_HSE_Enable(); LL_RCC_PLL_Enable(); + LL_RCC_PLLSAI1_Enable(); while(!LL_RCC_HSE_IsReady()) ; while(!LL_RCC_PLL_IsReady()) ; + while(!LL_RCC_PLLSAI1_IsReady()) + ; LL_FLASH_SetLatency(LL_FLASH_LATENCY_3); @@ -296,4 +303,4 @@ void furi_hal_clock_mco_disable() { LL_RCC_MSI_Disable(); while(LL_RCC_MSI_IsReady() != 0) ; -} \ No newline at end of file +} diff --git a/firmware/targets/f7/furi_hal/furi_hal_debug.c b/firmware/targets/f7/furi_hal/furi_hal_debug.c index 3b5dfe622..3dc03ea69 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_debug.c +++ b/firmware/targets/f7/furi_hal/furi_hal_debug.c @@ -3,12 +3,26 @@ #include #include +#include +#include + +volatile bool furi_hal_debug_gdb_session_active = false; + void furi_hal_debug_enable() { // Low power mode debug LL_DBGMCU_EnableDBGSleepMode(); LL_DBGMCU_EnableDBGStopMode(); LL_DBGMCU_EnableDBGStandbyMode(); LL_EXTI_EnableIT_32_63(LL_EXTI_LINE_48); + // SWD GPIO + furi_hal_gpio_init_ex( + &gpio_swdio, + GpioModeAltFunctionPushPull, + GpioPullUp, + GpioSpeedVeryHigh, + GpioAltFn0JTMS_SWDIO); + furi_hal_gpio_init_ex( + &gpio_swclk, GpioModeAltFunctionPushPull, GpioPullDown, GpioSpeedLow, GpioAltFn0JTCK_SWCLK); } void furi_hal_debug_disable() { @@ -17,4 +31,11 @@ void furi_hal_debug_disable() { LL_DBGMCU_DisableDBGStopMode(); LL_DBGMCU_DisableDBGStandbyMode(); LL_EXTI_DisableIT_32_63(LL_EXTI_LINE_48); + // SWD GPIO + furi_hal_gpio_init_simple(&gpio_swdio, GpioModeAnalog); + furi_hal_gpio_init_simple(&gpio_swclk, GpioModeAnalog); } + +bool furi_hal_debug_is_gdb_session_active() { + return furi_hal_debug_gdb_session_active; +} \ No newline at end of file diff --git a/firmware/targets/f7/furi_hal/furi_hal_flash.c b/firmware/targets/f7/furi_hal/furi_hal_flash.c index fc021d969..464d88d95 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_flash.c +++ b/firmware/targets/f7/furi_hal/furi_hal_flash.c @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include #include @@ -25,6 +27,16 @@ #define FURI_HAL_FLASH_OPT_KEY2 0x4C5D6E7F #define FURI_HAL_FLASH_OB_TOTAL_WORDS (0x80 / (sizeof(uint32_t) * 2)) +/* lib/STM32CubeWB/Projects/P-NUCLEO-WB55.Nucleo/Applications/BLE/BLE_RfWithFlash/Core/Src/flash_driver.c + * ProcessSingleFlashOperation, quote: + > In most BLE application, the flash should not be blocked by the CPU2 longer than FLASH_TIMEOUT_VALUE (1000ms) + > However, it could be that for some marginal application, this time is longer. + > ... there is no other way than waiting the operation to be completed. + > If for any reason this test is never passed, this means there is a failure in the system and there is no other + > way to recover than applying a device reset. + */ +#define FURI_HAL_FLASH_C2_LOCK_TIMEOUT_MS 3000u /* 3 seconds */ + #define IS_ADDR_ALIGNED_64BITS(__VALUE__) (((__VALUE__)&0x7U) == (0x00UL)) #define IS_FLASH_PROGRAM_ADDRESS(__VALUE__) \ (((__VALUE__) >= FLASH_BASE) && ((__VALUE__) <= (FLASH_BASE + FLASH_SIZE - 8UL)) && \ @@ -114,6 +126,7 @@ static void furi_hal_flash_lock(void) { } static void furi_hal_flash_begin_with_core2(bool erase_flag) { + furi_hal_power_insomnia_enter(); /* Take flash controller ownership */ while(LL_HSEM_1StepLock(HSEM, CFG_HW_FLASH_SEMID) != 0) { furi_thread_yield(); @@ -129,9 +142,11 @@ static void furi_hal_flash_begin_with_core2(bool erase_flag) { for(volatile uint32_t i = 0; i < 35; i++) ; + FuriHalCortexTimer timer = furi_hal_cortex_timer_get(FURI_HAL_FLASH_C2_LOCK_TIMEOUT_MS * 1000); while(true) { /* Wait till flash controller become usable */ while(LL_FLASH_IsActiveFlag_OperationSuspended()) { + furi_check(!furi_hal_cortex_timer_is_expired(timer)); furi_thread_yield(); }; @@ -141,6 +156,7 @@ static void furi_hal_flash_begin_with_core2(bool erase_flag) { /* Actually we already have mutex for it, but specification is specification */ if(LL_HSEM_IsSemaphoreLocked(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID)) { taskEXIT_CRITICAL(); + furi_check(!furi_hal_cortex_timer_is_expired(timer)); furi_thread_yield(); continue; } @@ -148,6 +164,7 @@ static void furi_hal_flash_begin_with_core2(bool erase_flag) { /* Take sempahopre and prevent core2 from anything funky */ if(LL_HSEM_1StepLock(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID) != 0) { taskEXIT_CRITICAL(); + furi_check(!furi_hal_cortex_timer_is_expired(timer)); furi_thread_yield(); continue; } @@ -188,6 +205,7 @@ static void furi_hal_flash_end_with_core2(bool erase_flag) { /* Release flash controller ownership */ LL_HSEM_ReleaseLock(HSEM, CFG_HW_FLASH_SEMID, 0); + furi_hal_power_insomnia_exit(); } static void furi_hal_flash_end(bool erase_flag) { @@ -228,17 +246,13 @@ static void furi_hal_flush_cache(void) { bool furi_hal_flash_wait_last_operation(uint32_t timeout) { uint32_t error = 0; - uint32_t countdown = 0; /* Wait for the FLASH operation to complete by polling on BUSY flag to be reset. Even if the FLASH operation fails, the BUSY flag will be reset and an error flag will be set */ - countdown = timeout; + FuriHalCortexTimer timer = furi_hal_cortex_timer_get(timeout * 1000); while(READ_BIT(FLASH->SR, FLASH_SR_BSY)) { - if(LL_SYSTICK_IsActiveCounterFlag()) { - countdown--; - } - if(countdown == 0) { + if(furi_hal_cortex_timer_is_expired(timer)) { return false; } } @@ -261,12 +275,9 @@ bool furi_hal_flash_wait_last_operation(uint32_t timeout) { CLEAR_BIT(FLASH->SR, error); /* Wait for control register to be written */ - countdown = timeout; + timer = furi_hal_cortex_timer_get(timeout * 1000); while(READ_BIT(FLASH->SR, FLASH_SR_CFGBSY)) { - if(LL_SYSTICK_IsActiveCounterFlag()) { - countdown--; - } - if(countdown == 0) { + if(furi_hal_cortex_timer_is_expired(timer)) { return false; } } diff --git a/firmware/targets/f7/furi_hal/furi_hal_gpio.c b/firmware/targets/f7/furi_hal/furi_hal_gpio.c index e8318afcf..c0e409775 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_gpio.c +++ b/firmware/targets/f7/furi_hal/furi_hal_gpio.c @@ -178,10 +178,13 @@ void furi_hal_gpio_add_int_callback(const GpioPin* gpio, GpioExtiCallback cb, vo FURI_CRITICAL_ENTER(); uint8_t pin_num = furi_hal_gpio_get_pin_num(gpio); - furi_assert(gpio_interrupt[pin_num].callback == NULL); - gpio_interrupt[pin_num].callback = cb; - gpio_interrupt[pin_num].context = ctx; - gpio_interrupt[pin_num].ready = true; + volatile GpioInterrupt* interrupt = &gpio_interrupt[pin_num]; + furi_check( + (interrupt->callback == NULL) || + ((interrupt->callback == cb) && (interrupt->context == ctx))); + interrupt->callback = cb; + interrupt->context = ctx; + interrupt->ready = true; FURI_CRITICAL_EXIT(); } diff --git a/firmware/targets/f7/furi_hal/furi_hal_infrared.c b/firmware/targets/f7/furi_hal/furi_hal_infrared.c index b65ea42e1..8098f8bd0 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_infrared.c +++ b/firmware/targets/f7/furi_hal/furi_hal_infrared.c @@ -570,9 +570,9 @@ static void furi_hal_infrared_async_tx_free_resources(void) { (furi_hal_infrared_state == InfraredStateAsyncTxStopped)); if(infrared_external_output) { - furi_hal_gpio_init(&gpio_ext_pa7, GpioModeOutputOpenDrain, GpioPullDown, GpioSpeedLow); + furi_hal_gpio_init(&gpio_ext_pa7, GpioModeAnalog, GpioPullDown, GpioSpeedLow); } else { - furi_hal_gpio_init(&gpio_infrared_tx, GpioModeOutputOpenDrain, GpioPullDown, GpioSpeedLow); + furi_hal_gpio_init(&gpio_infrared_tx, GpioModeAnalog, GpioPullDown, GpioSpeedLow); } furi_hal_interrupt_set_isr(IR_DMA_CH1_IRQ, NULL, NULL); furi_hal_interrupt_set_isr(IR_DMA_CH2_IRQ, NULL, NULL); diff --git a/firmware/targets/f7/furi_hal/furi_hal_os.c b/firmware/targets/f7/furi_hal/furi_hal_os.c index ee9743e62..3fc1fbea8 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_os.c +++ b/firmware/targets/f7/furi_hal/furi_hal_os.c @@ -28,11 +28,24 @@ // Arbitrary (but small) number for better tick consistency #define FURI_HAL_OS_EXTRA_CNT 3 +#ifndef FURI_HAL_OS_DEBUG_AWAKE_GPIO +#define FURI_HAL_OS_DEBUG_AWAKE_GPIO (&gpio_ext_pa7) +#endif + +#ifndef FURI_HAL_OS_DEBUG_TICK_GPIO +#define FURI_HAL_OS_DEBUG_TICK_GPIO (&gpio_ext_pa6) +#endif + +#ifndef FURI_HAL_OS_DEBUG_SECOND_GPIO +#define FURI_HAL_OS_DEBUG_SECOND_GPIO (&gpio_ext_pa4) +#endif + #ifdef FURI_HAL_OS_DEBUG #include void furi_hal_os_timer_callback() { - furi_hal_gpio_write(&gpio_ext_pa4, !furi_hal_gpio_read(&gpio_ext_pa4)); + furi_hal_gpio_write( + FURI_HAL_OS_DEBUG_SECOND_GPIO, !furi_hal_gpio_read(FURI_HAL_OS_DEBUG_SECOND_GPIO)); } #endif @@ -44,9 +57,11 @@ void furi_hal_os_init() { furi_hal_idle_timer_init(); #ifdef FURI_HAL_OS_DEBUG - furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeOutputPushPull); - furi_hal_gpio_init_simple(&gpio_ext_pa6, GpioModeOutputPushPull); - furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeOutputPushPull); + furi_hal_gpio_init_simple(FURI_HAL_OS_DEBUG_AWAKE_GPIO, GpioModeOutputPushPull); + furi_hal_gpio_init_simple(FURI_HAL_OS_DEBUG_TICK_GPIO, GpioModeOutputPushPull); + furi_hal_gpio_init_simple(FURI_HAL_OS_DEBUG_SECOND_GPIO, GpioModeOutputPushPull); + furi_hal_gpio_write(FURI_HAL_OS_DEBUG_AWAKE_GPIO, 1); + FuriTimer* second_timer = furi_timer_alloc(furi_hal_os_timer_callback, FuriTimerTypePeriodic, NULL); furi_timer_start(second_timer, FURI_HAL_OS_TICK_HZ); @@ -58,7 +73,8 @@ void furi_hal_os_init() { void furi_hal_os_tick() { if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { #ifdef FURI_HAL_OS_DEBUG - furi_hal_gpio_write(&gpio_ext_pa6, !furi_hal_gpio_read(&gpio_ext_pa6)); + furi_hal_gpio_write( + FURI_HAL_OS_DEBUG_TICK_GPIO, !furi_hal_gpio_read(FURI_HAL_OS_DEBUG_TICK_GPIO)); #endif xPortSysTickHandler(); } @@ -121,14 +137,14 @@ static inline uint32_t furi_hal_os_sleep(TickType_t expected_idle_ticks) { furi_hal_idle_timer_start(FURI_HAL_OS_TICKS_TO_IDLE_CNT(expected_idle_ticks)); #ifdef FURI_HAL_OS_DEBUG - furi_hal_gpio_write(&gpio_ext_pa7, 0); + furi_hal_gpio_write(FURI_HAL_OS_DEBUG_AWAKE_GPIO, 0); #endif // Go to sleep mode furi_hal_power_sleep(); #ifdef FURI_HAL_OS_DEBUG - furi_hal_gpio_write(&gpio_ext_pa7, 1); + furi_hal_gpio_write(FURI_HAL_OS_DEBUG_AWAKE_GPIO, 1); #endif // Calculate how much time we spent in the sleep diff --git a/firmware/targets/f7/furi_hal/furi_hal_power.c b/firmware/targets/f7/furi_hal/furi_hal_power.c index fd601ec7e..3e4e3f48b 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_power.c +++ b/firmware/targets/f7/furi_hal/furi_hal_power.c @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include @@ -19,15 +21,24 @@ #define TAG "FuriHalPower" -#ifdef FURI_HAL_POWER_DEEP_SLEEP_ENABLED -#define FURI_HAL_POWER_DEEP_INSOMNIA 0 -#else -#define FURI_HAL_POWER_DEEP_INSOMNIA 1 +#ifndef FURI_HAL_POWER_DEBUG_WFI_GPIO +#define FURI_HAL_POWER_DEBUG_WFI_GPIO (&gpio_ext_pb2) +#endif + +#ifndef FURI_HAL_POWER_DEBUG_STOP_GPIO +#define FURI_HAL_POWER_DEBUG_STOP_GPIO (&gpio_ext_pc3) +#endif + +#ifndef FURI_HAL_POWER_DEBUG_ABNORMAL_GPIO +#define FURI_HAL_POWER_DEBUG_ABNORMAL_GPIO (&gpio_ext_pb3) +#endif + +#ifndef FURI_HAL_POWER_STOP_MODE +#define FURI_HAL_POWER_STOP_MODE (LL_PWR_MODE_STOP2) #endif typedef struct { volatile uint8_t insomnia; - volatile uint8_t deep_insomnia; volatile uint8_t suppress_charge; uint8_t gauge_initialized; @@ -36,7 +47,6 @@ typedef struct { static volatile FuriHalPower furi_hal_power = { .insomnia = 0, - .deep_insomnia = FURI_HAL_POWER_DEEP_INSOMNIA, .suppress_charge = 0, }; @@ -79,19 +89,25 @@ const ParamCEDV cedv = { }; void furi_hal_power_init() { +#ifdef FURI_HAL_POWER_DEBUG + furi_hal_gpio_init_simple(FURI_HAL_POWER_DEBUG_WFI_GPIO, GpioModeOutputPushPull); + furi_hal_gpio_init_simple(FURI_HAL_POWER_DEBUG_STOP_GPIO, GpioModeOutputPushPull); + furi_hal_gpio_init_simple(FURI_HAL_POWER_DEBUG_ABNORMAL_GPIO, GpioModeOutputPushPull); + furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_WFI_GPIO, 0); + furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_STOP_GPIO, 0); + furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_ABNORMAL_GPIO, 0); +#endif + LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); LL_PWR_SMPS_SetMode(LL_PWR_SMPS_STEP_DOWN); + LL_PWR_SetPowerMode(FURI_HAL_POWER_STOP_MODE); + LL_C2_PWR_SetPowerMode(FURI_HAL_POWER_STOP_MODE); furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); bq27220_init(&furi_hal_i2c_handle_power, &cedv); bq25896_init(&furi_hal_i2c_handle_power); furi_hal_i2c_release(&furi_hal_i2c_handle_power); -#ifdef FURI_HAL_OS_DEBUG - furi_hal_gpio_init_simple(&gpio_ext_pb2, GpioModeOutputPushPull); - furi_hal_gpio_init_simple(&gpio_ext_pc3, GpioModeOutputPushPull); -#endif - FURI_LOG_I(TAG, "Init OK"); } @@ -140,11 +156,14 @@ bool furi_hal_power_sleep_available() { return furi_hal_power.insomnia == 0; } -bool furi_hal_power_deep_sleep_available() { - return furi_hal_bt_is_alive() && furi_hal_power.deep_insomnia == 0; +static inline bool furi_hal_power_deep_sleep_available() { + return furi_hal_bt_is_alive() && !furi_hal_rtc_is_flag_set(FuriHalRtcFlagLegacySleep) && + !furi_hal_debug_is_gdb_session_active() && !LL_PWR_IsActiveFlag_CRPE() && + !LL_PWR_IsActiveFlag_CRP() && !LL_PWR_IsActiveFlag_BLEA() && + !LL_PWR_IsActiveFlag_BLEWU(); } -void furi_hal_power_light_sleep() { +static inline void furi_hal_power_light_sleep() { __WFI(); } @@ -152,17 +171,15 @@ static inline void furi_hal_power_suspend_aux_periphs() { // Disable USART furi_hal_uart_suspend(FuriHalUartIdUSART1); furi_hal_uart_suspend(FuriHalUartIdLPUART1); - // TODO: Disable USB } static inline void furi_hal_power_resume_aux_periphs() { // Re-enable USART furi_hal_uart_resume(FuriHalUartIdUSART1); furi_hal_uart_resume(FuriHalUartIdLPUART1); - // TODO: Re-enable USB } -void furi_hal_power_deep_sleep() { +static inline void furi_hal_power_deep_sleep() { furi_hal_power_suspend_aux_periphs(); while(LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID)) @@ -187,8 +204,6 @@ void furi_hal_power_deep_sleep() { LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0); // Prepare deep sleep - LL_PWR_SetPowerMode(LL_PWR_MODE_STOP2); - LL_C2_PWR_SetPowerMode(LL_PWR_MODE_STOP2); LL_LPM_EnableDeepSleep(); #if defined(__CC_ARM) @@ -196,17 +211,19 @@ void furi_hal_power_deep_sleep() { __force_stores(); #endif - __WFI(); + bool should_abort_sleep = LL_PWR_IsActiveFlag_CRPE() || LL_PWR_IsActiveFlag_CRP() || + LL_PWR_IsActiveFlag_BLEA() || LL_PWR_IsActiveFlag_BLEWU(); + + if(should_abort_sleep) { +#ifdef FURI_HAL_POWER_DEBUG + furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_ABNORMAL_GPIO, 1); +#endif + } else { + __WFI(); + } LL_LPM_EnableSleep(); - // Make sure that values differ to prevent disaster on wfi - LL_PWR_SetPowerMode(LL_PWR_MODE_STOP0); - LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN); - - LL_PWR_ClearFlag_C1STOP_C1STB(); - LL_PWR_ClearFlag_C2STOP_C2STB(); - /* Release ENTRY_STOP_MODE semaphore */ LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0); @@ -220,28 +237,25 @@ void furi_hal_power_deep_sleep() { LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0); furi_hal_power_resume_aux_periphs(); + furi_hal_rtc_sync_shadow(); } void furi_hal_power_sleep() { if(furi_hal_power_deep_sleep_available()) { -#ifdef FURI_HAL_OS_DEBUG - furi_hal_gpio_write(&gpio_ext_pc3, 1); +#ifdef FURI_HAL_POWER_DEBUG + furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_STOP_GPIO, 1); #endif - furi_hal_power_deep_sleep(); - -#ifdef FURI_HAL_OS_DEBUG - furi_hal_gpio_write(&gpio_ext_pc3, 0); +#ifdef FURI_HAL_POWER_DEBUG + furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_STOP_GPIO, 0); #endif } else { -#ifdef FURI_HAL_OS_DEBUG - furi_hal_gpio_write(&gpio_ext_pb2, 1); +#ifdef FURI_HAL_POWER_DEBUG + furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_WFI_GPIO, 1); #endif - furi_hal_power_light_sleep(); - -#ifdef FURI_HAL_OS_DEBUG - furi_hal_gpio_write(&gpio_ext_pb2, 0); +#ifdef FURI_HAL_POWER_DEBUG + furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_WFI_GPIO, 0); #endif } } diff --git a/firmware/targets/f7/furi_hal/furi_hal_random.c b/firmware/targets/f7/furi_hal/furi_hal_random.c index f36407cc1..d3461c4d1 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_random.c +++ b/firmware/targets/f7/furi_hal/furi_hal_random.c @@ -9,19 +9,35 @@ #define TAG "FuriHalRandom" +static uint32_t furi_hal_random_read_rng() { + while(LL_RNG_IsActiveFlag_CECS(RNG) && LL_RNG_IsActiveFlag_SECS(RNG) && + !LL_RNG_IsActiveFlag_DRDY(RNG)) { + /* Error handling as described in RM0434, pg. 582-583 */ + if(LL_RNG_IsActiveFlag_CECS(RNG)) { + /* Clock error occurred */ + LL_RNG_ClearFlag_CEIS(RNG); + } + + if(LL_RNG_IsActiveFlag_SECS(RNG)) { + /* Noise source error occurred */ + LL_RNG_ClearFlag_SEIS(RNG); + + for(uint32_t i = 0; i < 12; ++i) { + const volatile uint32_t discard = LL_RNG_ReadRandData32(RNG); + UNUSED(discard); + } + } + } + + return LL_RNG_ReadRandData32(RNG); +} + uint32_t furi_hal_random_get() { while(LL_HSEM_1StepLock(HSEM, CFG_HW_RNG_SEMID)) ; LL_RNG_Enable(RNG); - while(!LL_RNG_IsActiveFlag_DRDY(RNG)) - ; - - if((LL_RNG_IsActiveFlag_CECS(RNG)) || (LL_RNG_IsActiveFlag_SECS(RNG))) { - furi_crash("TRNG error"); - } - - uint32_t random_val = LL_RNG_ReadRandData32(RNG); + const uint32_t random_val = furi_hal_random_read_rng(); LL_RNG_Disable(RNG); LL_HSEM_ReleaseLock(HSEM, CFG_HW_RNG_SEMID, 0); @@ -35,15 +51,7 @@ void furi_hal_random_fill_buf(uint8_t* buf, uint32_t len) { LL_RNG_Enable(RNG); for(uint32_t i = 0; i < len; i += 4) { - while(!LL_RNG_IsActiveFlag_DRDY(RNG)) - ; - - if((LL_RNG_IsActiveFlag_CECS(RNG)) || (LL_RNG_IsActiveFlag_SECS(RNG))) { - furi_crash("TRNG error"); - } - - uint32_t random_val = LL_RNG_ReadRandData32(RNG); - + const uint32_t random_val = furi_hal_random_read_rng(); uint8_t len_cur = ((i + 4) < len) ? (4) : (len - i); memcpy(&buf[i], &random_val, len_cur); } diff --git a/firmware/targets/f7/furi_hal/furi_hal_resources.c b/firmware/targets/f7/furi_hal/furi_hal_resources.c index a6c72fd5a..f87f2a31a 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_resources.c +++ b/firmware/targets/f7/furi_hal/furi_hal_resources.c @@ -6,6 +6,9 @@ #define TAG "FuriHalResources" +const GpioPin gpio_swdio = {.port = GPIOA, .pin = LL_GPIO_PIN_13}; +const GpioPin gpio_swclk = {.port = GPIOA, .pin = LL_GPIO_PIN_14}; + const GpioPin gpio_vibro = {.port = VIBRO_GPIO_Port, .pin = VIBRO_Pin}; const GpioPin gpio_ibutton = {.port = iBTN_GPIO_Port, .pin = iBTN_Pin}; @@ -158,10 +161,11 @@ void furi_hal_resources_init() { // Button pins furi_hal_resources_init_input_pins(GpioModeInterruptRiseFall); - // Explicit pulls pins - furi_hal_gpio_init(&gpio_infrared_tx, GpioModeAnalog, GpioPullDown, GpioSpeedLow); - furi_hal_gpio_init(&gpio_speaker, GpioModeAnalog, GpioPullDown, GpioSpeedLow); - furi_hal_gpio_init(&gpio_vibro, GpioModeAnalog, GpioPullDown, GpioSpeedLow); + // Explicit, surviving reset, pulls + LL_PWR_EnablePUPDCfg(); + LL_PWR_EnableGPIOPullDown(LL_PWR_GPIO_B, LL_PWR_GPIO_BIT_9); // gpio_infrared_tx + LL_PWR_EnableGPIOPullDown(LL_PWR_GPIO_B, LL_PWR_GPIO_BIT_8); // gpio_speaker + LL_PWR_EnableGPIOPullDown(LL_PWR_GPIO_A, LL_PWR_GPIO_BIT_8); // gpio_vibro // Display pins furi_hal_gpio_init(&gpio_display_rst_n, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); diff --git a/firmware/targets/f7/furi_hal/furi_hal_resources.h b/firmware/targets/f7/furi_hal/furi_hal_resources.h index c0e32c313..391f8f4ff 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_resources.h +++ b/firmware/targets/f7/furi_hal/furi_hal_resources.h @@ -50,6 +50,9 @@ extern const size_t input_pins_count; extern const GpioPinRecord gpio_pins[]; extern const size_t gpio_pins_count; +extern const GpioPin gpio_swdio; +extern const GpioPin gpio_swclk; + extern const GpioPin gpio_vibro; extern const GpioPin gpio_ibutton; diff --git a/firmware/targets/f7/furi_hal/furi_hal_rtc.c b/firmware/targets/f7/furi_hal/furi_hal_rtc.c index 84e7fe395..7bd45c35d 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rtc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_rtc.c @@ -165,6 +165,14 @@ void furi_hal_rtc_init() { FURI_LOG_I(TAG, "Init OK"); } +void furi_hal_rtc_sync_shadow() { + if(!LL_RTC_IsShadowRegBypassEnabled(RTC)) { + LL_RTC_ClearFlag_RS(RTC); + while(!LL_RTC_IsActiveFlag_RS(RTC)) { + }; + } +} + uint32_t furi_hal_rtc_get_register(FuriHalRtcRegister reg) { return LL_RTC_BAK_GetRegister(RTC, reg); } @@ -312,12 +320,7 @@ void furi_hal_rtc_set_datetime(FuriHalRtcDateTime* datetime) { /* Exit Initialization mode */ LL_RTC_DisableInitMode(RTC); - /* If RTC_CR_BYPSHAD bit = 0, wait for synchro else this check is not needed */ - if(!LL_RTC_IsShadowRegBypassEnabled(RTC)) { - LL_RTC_ClearFlag_RS(RTC); - while(!LL_RTC_IsActiveFlag_RS(RTC)) { - }; - } + furi_hal_rtc_sync_shadow(); /* Enable write protection */ LL_RTC_EnableWriteProtection(RTC); diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.c b/firmware/targets/f7/furi_hal/furi_hal_subghz.c index ce4b8f0db..35ea2e36a 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.c +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.c @@ -40,6 +40,7 @@ volatile FuriHalSubGhz furi_hal_subghz = { .cc1101_g0_pin = &gpio_cc1101_g0, .rolling_counter_mult = 1, .ext_module_power_disabled = false, + .timestamp_file_names = false, }; bool furi_hal_subghz_set_radio_type(SubGhzRadioType state) { @@ -79,6 +80,14 @@ bool furi_hal_subghz_get_external_power_disable(void) { return furi_hal_subghz.ext_module_power_disabled; } +void furi_hal_subghz_set_timestamp_file_names(bool state) { + furi_hal_subghz.timestamp_file_names = state; +} + +bool furi_hal_subghz_get_timestamp_file_names(void) { + return furi_hal_subghz.timestamp_file_names; +} + void furi_hal_subghz_set_async_mirror_pin(const GpioPin* pin) { furi_hal_subghz.async_mirror_pin = pin; } @@ -702,11 +711,12 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void* GpioModeInterruptRiseFall, GpioPullUp, GpioSpeedVeryHigh); + furi_hal_gpio_disable_int_callback(furi_hal_subghz.cc1101_g0_pin); + furi_hal_gpio_remove_int_callback(furi_hal_subghz.cc1101_g0_pin); furi_hal_gpio_add_int_callback( furi_hal_subghz.cc1101_g0_pin, furi_hal_subghz_capture_ext_ISR, furi_hal_subghz_capture_callback); - furi_hal_gpio_enable_int_callback(furi_hal_subghz.cc1101_g0_pin); } // Start timer diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.h b/firmware/targets/f7/furi_hal/furi_hal_subghz.h index 1a42d84ff..a6a5e20de 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.h +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.h @@ -79,6 +79,7 @@ typedef struct { const GpioPin* cc1101_g0_pin; uint8_t rolling_counter_mult; bool ext_module_power_disabled; + bool timestamp_file_names; } FuriHalSubGhz; extern volatile FuriHalSubGhz furi_hal_subghz; @@ -344,6 +345,14 @@ void furi_hal_subghz_set_external_power_disable(bool state); */ bool furi_hal_subghz_get_external_power_disable(void); +/** If true - disable generation of random name and add timestamp to filenames instead + */ +void furi_hal_subghz_set_timestamp_file_names(bool state); + +/** Get the current state of the timestamp instead of random name flag + */ +bool furi_hal_subghz_get_timestamp_file_names(void); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/f7/src/main.c b/firmware/targets/f7/src/main.c index 1f2b5d6e4..2c353f52b 100644 --- a/firmware/targets/f7/src/main.c +++ b/firmware/targets/f7/src/main.c @@ -29,6 +29,8 @@ int main() { FuriThread* main_thread = furi_thread_alloc_ex("Init", 4096, init_task, NULL); #ifdef FURI_RAM_EXEC + // Prevent entering sleep mode when executed from RAM + furi_hal_power_insomnia_enter(); furi_thread_start(main_thread); #else furi_hal_light_sequence("RGB"); @@ -44,6 +46,7 @@ int main() { furi_hal_power_reset(); } else if(boot_mode == FuriHalRtcBootModeUpdate) { furi_hal_light_sequence("rgb BR"); + // Do update flipper_boot_update_exec(); // if things go nice, we shouldn't reach this point. // But if we do, abandon to avoid bootloops diff --git a/firmware/targets/furi_hal_include/furi_hal_debug.h b/firmware/targets/furi_hal_include/furi_hal_debug.h index 88397bbba..befbb4f40 100644 --- a/firmware/targets/furi_hal_include/furi_hal_debug.h +++ b/firmware/targets/furi_hal_include/furi_hal_debug.h @@ -18,6 +18,9 @@ void furi_hal_debug_enable(); /** Disable MCU debug */ void furi_hal_debug_disable(); +/** Check if GDB debug session is active */ +bool furi_hal_debug_is_gdb_session_active(); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/furi_hal_include/furi_hal_power.h b/firmware/targets/furi_hal_include/furi_hal_power.h index 462e20e41..00182fa28 100644 --- a/firmware/targets/furi_hal_include/furi_hal_power.h +++ b/firmware/targets/furi_hal_include/furi_hal_power.h @@ -58,12 +58,6 @@ void furi_hal_power_insomnia_exit(); */ bool furi_hal_power_sleep_available(); -/** Check if deep sleep availble - * - * @return true if available - */ -bool furi_hal_power_deep_sleep_available(); - /** Go to sleep */ void furi_hal_power_sleep(); diff --git a/firmware/targets/furi_hal_include/furi_hal_rtc.h b/firmware/targets/furi_hal_include/furi_hal_rtc.h index 96acb5848..5babfdc59 100644 --- a/firmware/targets/furi_hal_include/furi_hal_rtc.h +++ b/firmware/targets/furi_hal_include/furi_hal_rtc.h @@ -31,6 +31,8 @@ typedef enum { FuriHalRtcFlagC2Update = (1 << 3), FuriHalRtcFlagHandOrient = (1 << 4), FuriHalRtcFlagResetPin = (1 << 5), + FuriHalRtcFlagLegacySleep = (1 << 6), + FuriHalRtcFlagStealthMode = (1 << 7), } FuriHalRtcFlag; typedef enum { @@ -86,6 +88,9 @@ void furi_hal_rtc_deinit_early(); /** Initialize RTC subsystem */ void furi_hal_rtc_init(); +/** Force sync shadow registers */ +void furi_hal_rtc_sync_shadow(); + /** Get RTC register content * * @param[in] reg The register identifier diff --git a/furi/core/check.c b/furi/core/check.c index 910527cee..64f9f72f1 100644 --- a/furi/core/check.c +++ b/furi/core/check.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -117,6 +118,8 @@ FURI_NORETURN void __furi_crash() { if(debug) { furi_hal_console_puts("\r\nSystem halted. Connect debugger for more info\r\n"); furi_hal_console_puts("\033[0m\r\n"); + furi_hal_debug_enable(); + RESTORE_REGISTERS_AND_HALT_MCU(true); } else { furi_hal_rtc_set_fault_data((uint32_t)__furi_check_message); diff --git a/furi/core/core_defines.h b/furi/core/core_defines.h index 03a364abd..830bb191c 100644 --- a/furi/core/core_defines.h +++ b/furi/core/core_defines.h @@ -24,6 +24,10 @@ extern "C" { }) #endif +#ifndef ABS +#define ABS(a) ({ (a) < 0 ? -(a) : (a); }) +#endif + #ifndef ROUND_UP_TO #define ROUND_UP_TO(a, b) \ ({ \ diff --git a/lib/ST25RFAL002/platform.c b/lib/ST25RFAL002/platform.c index 754e25650..a97be1c75 100644 --- a/lib/ST25RFAL002/platform.c +++ b/lib/ST25RFAL002/platform.c @@ -45,11 +45,14 @@ void platformDisableIrqCallback() { void platformSetIrqCallback(PlatformIrqCallback callback) { rfal_platform.callback = callback; - rfal_platform.thread = - furi_thread_alloc_ex("RfalIrqDriver", 1024, rfal_platform_irq_thread, NULL); - furi_thread_mark_as_service(rfal_platform.thread); - furi_thread_set_priority(rfal_platform.thread, FuriThreadPriorityIsr); - furi_thread_start(rfal_platform.thread); + + if(!rfal_platform.thread) { + rfal_platform.thread = + furi_thread_alloc_ex("RfalIrqDriver", 1024, rfal_platform_irq_thread, NULL); + furi_thread_mark_as_service(rfal_platform.thread); + furi_thread_set_priority(rfal_platform.thread, FuriThreadPriorityIsr); + furi_thread_start(rfal_platform.thread); + } furi_hal_gpio_add_int_callback(&gpio_nfc_irq_rfid_pull, nfc_isr, NULL); // Disable interrupt callback as the pin is shared between 2 apps diff --git a/lib/STM32CubeWB b/lib/STM32CubeWB index a9e29b431..c4cec8ae5 160000 --- a/lib/STM32CubeWB +++ b/lib/STM32CubeWB @@ -1 +1 @@ -Subproject commit a9e29b431f6dac95b6fc860a717834f35b7f78e5 +Subproject commit c4cec8ae57a79e949a184cd0b4117a008a0a25a7 diff --git a/lib/subghz/blocks/custom_btn.c b/lib/subghz/blocks/custom_btn.c index dd1436798..3023e09ea 100644 --- a/lib/subghz/blocks/custom_btn.c +++ b/lib/subghz/blocks/custom_btn.c @@ -1,7 +1,7 @@ #include "custom_btn.h" -static uint8_t custom_btn_id; -static uint8_t custom_btn_original; +static uint8_t custom_btn_id = 0; +static uint8_t custom_btn_original = 0; static uint8_t custom_btn_max_btns = 0; void subghz_custom_btn_set(uint8_t b) { diff --git a/lib/subghz/blocks/generic.c b/lib/subghz/blocks/generic.c index 331606fe5..1827388af 100644 --- a/lib/subghz/blocks/generic.c +++ b/lib/subghz/blocks/generic.c @@ -152,7 +152,7 @@ SubGhzProtocolStatus subghz_block_generic_deserialize_check_count_bit( break; } if(instance->data_count_bit != count_bit) { - FURI_LOG_E(TAG, "Wrong number of bits in key"); + FURI_LOG_D(TAG, "Wrong number of bits in key"); ret = SubGhzProtocolStatusErrorValueBitCount; break; } diff --git a/lib/subghz/environment.c b/lib/subghz/environment.c index b39b259d4..5ded243c4 100644 --- a/lib/subghz/environment.c +++ b/lib/subghz/environment.c @@ -16,6 +16,7 @@ SubGhzEnvironment* subghz_environment_alloc() { instance->protocol_registry = NULL; instance->came_atomo_rainbow_table_file_name = NULL; instance->nice_flor_s_rainbow_table_file_name = NULL; + instance->alutech_at_4n_rainbow_table_file_name = NULL; return instance; } @@ -26,6 +27,7 @@ void subghz_environment_free(SubGhzEnvironment* instance) { instance->protocol_registry = NULL; instance->came_atomo_rainbow_table_file_name = NULL; instance->nice_flor_s_rainbow_table_file_name = NULL; + instance->alutech_at_4n_rainbow_table_file_name = NULL; subghz_keystore_free(instance->keystore); free(instance); diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 04e10adf5..20dae49c1 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -79,6 +79,11 @@ const SubGhzProtocol subghz_protocol_alutech_at_4n = { .encoder = &subghz_protocol_alutech_at_4n_encoder, }; +static void subghz_protocol_alutech_at_4n_remote_controller( + SubGhzBlockGeneric* instance, + uint8_t crc, + const char* file_name); + void* subghz_protocol_encoder_alutech_at_4n_alloc(SubGhzEnvironment* environment) { UNUSED(environment); SubGhzProtocolEncoderAlutech_at_4n* instance = @@ -503,10 +508,18 @@ SubGhzProtocolStatus subghz_protocol_encoder_alutech_at_4n_deserialize( break; } + if(!flipper_format_read_uint32(flipper_format, "CRC", (uint32_t*)&instance->crc, 1)) { + FURI_LOG_E(TAG, "Missing CRC"); + break; + } + //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + subghz_protocol_alutech_at_4n_remote_controller( + &instance->generic, instance->crc, instance->alutech_at_4n_rainbow_table_file_name); + subghz_protocol_encoder_alutech_at_4n_get_upload(instance, instance->generic.btn); if(!flipper_format_rewind(flipper_format)) { diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 6698f54fe..4900e7e49 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -393,7 +393,6 @@ static bool uint8_t custom_btn_id = subghz_custom_btn_get(); uint8_t original_btn_num = subghz_custom_btn_get_original(); - // Set custom button if(custom_btn_id == 1) { switch(original_btn_num) { @@ -499,11 +498,9 @@ static bool break; } } - if((custom_btn_id == 0) && (original_btn_num != 0)) { btn = original_btn_num; } - // Generate new key if(subghz_protocol_keeloq_gen_data(instance, btn, true)) { diff --git a/lib/subghz/protocols/nero_radio.c b/lib/subghz/protocols/nero_radio.c index d7731dca6..7e787ffd0 100644 --- a/lib/subghz/protocols/nero_radio.c +++ b/lib/subghz/protocols/nero_radio.c @@ -117,8 +117,7 @@ static bool } //Send start bit - instance->encoder.upload[index++] = - level_duration_make(true, (uint32_t)subghz_protocol_nero_radio_const.te_short * 4); + instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)830); instance->encoder.upload[index++] = level_duration_make(false, (uint32_t)subghz_protocol_nero_radio_const.te_short); @@ -142,14 +141,22 @@ static bool //send bit 1 instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)subghz_protocol_nero_radio_const.te_long); - instance->encoder.upload[index++] = - level_duration_make(false, (uint32_t)subghz_protocol_nero_radio_const.te_short * 37); + if(instance->generic.data_count_bit == 57) { + instance->encoder.upload[index++] = level_duration_make(false, (uint32_t)1300); + } else { + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_nero_radio_const.te_short * 23); + } } else { //send bit 0 instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)subghz_protocol_nero_radio_const.te_short); - instance->encoder.upload[index++] = - level_duration_make(false, (uint32_t)subghz_protocol_nero_radio_const.te_short * 37); + if(instance->generic.data_count_bit == 57) { + instance->encoder.upload[index++] = level_duration_make(false, (uint32_t)1300); + } else { + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_nero_radio_const.te_short * 23); + } } return true; } @@ -164,8 +171,14 @@ SubGhzProtocolStatus &instance->generic, flipper_format, subghz_protocol_nero_radio_const.min_count_bit_for_found); - if(ret != SubGhzProtocolStatusOk) { - break; + + if((ret == SubGhzProtocolStatusErrorValueBitCount) && + (instance->generic.data_count_bit == 57)) { + ret = SubGhzProtocolStatusOk; + } else { + if(ret != SubGhzProtocolStatusOk) { + break; + } } //optional parameter parameter flipper_format_read_uint32( @@ -284,8 +297,7 @@ void subghz_protocol_decoder_nero_radio_feed(void* context, bool level, uint32_t break; case NeroRadioDecoderStepCheckDuration: if(!level) { - if(duration >= ((uint32_t)subghz_protocol_nero_radio_const.te_short * 10 + - subghz_protocol_nero_radio_const.te_delta * 2)) { + if(duration >= ((uint32_t)1250)) { //Found stop bit if(DURATION_DIFF( instance->decoder.te_last, subghz_protocol_nero_radio_const.te_short) < @@ -298,8 +310,10 @@ void subghz_protocol_decoder_nero_radio_feed(void* context, bool level, uint32_t subghz_protocol_blocks_add_bit(&instance->decoder, 1); } instance->decoder.parser_step = NeroRadioDecoderStepReset; - if(instance->decoder.decode_count_bit == - subghz_protocol_nero_radio_const.min_count_bit_for_found) { + if((instance->decoder.decode_count_bit == + subghz_protocol_nero_radio_const.min_count_bit_for_found) || + (instance->decoder.decode_count_bit == + subghz_protocol_nero_radio_const.min_count_bit_for_found + 1)) { instance->generic.data = instance->decoder.decode_data; instance->generic.data_count_bit = instance->decoder.decode_count_bit; @@ -356,10 +370,19 @@ SubGhzProtocolStatus subghz_protocol_decoder_nero_radio_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolDecoderNeroRadio* instance = context; - return subghz_block_generic_deserialize_check_count_bit( + SubGhzProtocolStatus stat; + + stat = subghz_block_generic_deserialize_check_count_bit( &instance->generic, flipper_format, subghz_protocol_nero_radio_const.min_count_bit_for_found); + + if((stat == SubGhzProtocolStatusErrorValueBitCount) && + (instance->generic.data_count_bit == 57)) { + return SubGhzProtocolStatusOk; + } else { + return stat; + } } void subghz_protocol_decoder_nero_radio_get_string(void* context, FuriString* output) { diff --git a/lib/subghz/protocols/raw.c b/lib/subghz/protocols/raw.c index eaad78b91..a82c9cf83 100644 --- a/lib/subghz/protocols/raw.c +++ b/lib/subghz/protocols/raw.c @@ -244,8 +244,8 @@ void subghz_protocol_decoder_raw_reset(void* context) { void subghz_protocol_decoder_raw_feed(void* context, bool level, uint32_t duration) { furi_assert(context); SubGhzProtocolDecoderRAW* instance = context; - - if(!instance->pause && (instance->upload_raw != NULL)) { + // Add check if we got duration higher than 1 second, we skipping it, temp fix + if((!instance->pause && (instance->upload_raw != NULL)) && (duration < ((uint32_t)1000000))) { if(duration > subghz_protocol_raw_const.te_short) { if(instance->last_level != level) { instance->last_level = (level ? true : false); diff --git a/lib/subghz/subghz_file_encoder_worker.c b/lib/subghz/subghz_file_encoder_worker.c index 8bc6e8446..fce4e8592 100644 --- a/lib/subghz/subghz_file_encoder_worker.c +++ b/lib/subghz/subghz_file_encoder_worker.c @@ -56,6 +56,7 @@ void subghz_file_encoder_worker_add_level_duration( bool subghz_file_encoder_worker_data_parse(SubGhzFileEncoderWorker* instance, const char* strStart) { char* str1; + int32_t temp_ds = 0; bool res = false; // Line sample: "RAW_Data: -1, 2, -2..." @@ -72,7 +73,18 @@ bool subghz_file_encoder_worker_data_parse(SubGhzFileEncoderWorker* instance, co // Skip space str1 += 1; - subghz_file_encoder_worker_add_level_duration(instance, atoi(str1)); + // + temp_ds = atoi(str1); + if((temp_ds < -1000000) || (temp_ds > 1000000)) { + if(temp_ds > 0) { + subghz_file_encoder_worker_add_level_duration(instance, (int32_t)100); + } else { + subghz_file_encoder_worker_add_level_duration(instance, (int32_t)-100); + } + //FURI_LOG_I("PARSE", "Number overflow - %d", atoi(str1)); + } else { + subghz_file_encoder_worker_add_level_duration(instance, temp_ds); + } } res = true; } diff --git a/scripts/fbt_tools/fbt_dist.py b/scripts/fbt_tools/fbt_dist.py index c0eca0d2a..a5669c488 100644 --- a/scripts/fbt_tools/fbt_dist.py +++ b/scripts/fbt_tools/fbt_dist.py @@ -112,6 +112,8 @@ def DistCommand(env, name, source, **kw): def generate(env): + if not env["VERBOSE"]: + env.SetDefault(COPROCOMSTR="\tCOPRO\t${TARGET}") env.AddMethod(AddFwProject) env.AddMethod(DistCommand) env.AddMethod(AddOpenOCDFlashTarget) @@ -147,7 +149,7 @@ def generate(env): '--stack_file="${COPRO_STACK_BIN}" ' "--stack_addr=${COPRO_STACK_ADDR} ", ], - "\tCOPRO\t${TARGET}", + "$COPROCOMSTR", ) ), } diff --git a/scripts/flipper/assets/copro.py b/scripts/flipper/assets/copro.py index b61ac0329..e0375b51f 100644 --- a/scripts/flipper/assets/copro.py +++ b/scripts/flipper/assets/copro.py @@ -34,7 +34,7 @@ class Copro: self.mcu_copro = None self.logger = logging.getLogger(self.__class__.__name__) - def loadCubeInfo(self, cube_dir, cube_version): + def loadCubeInfo(self, cube_dir, reference_cube_version): if not os.path.isdir(cube_dir): raise Exception(f'"{cube_dir}" doesn\'t exists') self.cube_dir = cube_dir @@ -50,7 +50,7 @@ class Copro: if not cube_version or not cube_version.startswith("FW.WB"): raise Exception(f"Incorrect Cube package or version info") cube_version = cube_version.replace("FW.WB.", "", 1) - if cube_version != cube_version: + if cube_version != reference_cube_version: raise Exception(f"Unsupported cube version") self.version = cube_version diff --git a/scripts/ob.data b/scripts/ob.data index 5276a5103..605faccbf 100644 --- a/scripts/ob.data +++ b/scripts/ob.data @@ -14,7 +14,7 @@ IWDGSTOP:0x1:rw IWDGSW:0x1:rw IPCCDBA:0x0:rw ESE:0x1:r -SFSA:0xD7:r +SFSA:0xD5:r FSD:0x0:r DDS:0x1:r C2OPT:0x1:r @@ -22,7 +22,7 @@ NBRSD:0x0:r SNBRSA:0xD:r BRSD:0x0:r SBRSA:0x12:r -SBRV:0x35C00:r +SBRV:0x35400:r PCROP1A_STRT:0x1FF:r PCROP1A_END:0x0:r PCROP_RDP:0x1:rw diff --git a/scripts/sconsdist.py b/scripts/sconsdist.py index 01e9794f4..5cbd2a703 100644 --- a/scripts/sconsdist.py +++ b/scripts/sconsdist.py @@ -181,9 +181,9 @@ class Main(App): ) as zf: for component_key in sdk_components_keys: component_path = self._dist_components.get(component_key) - components_paths[component_key] = basename(component_path) if component_key.endswith(".dir"): + components_paths[component_key] = basename(component_path) for root, dirnames, files in walk(component_path): if "__pycache__" in dirnames: dirnames.remove("__pycache__") @@ -199,7 +199,9 @@ class Main(App): ), ) else: - zf.write(component_path, basename(component_path)) + # We use fixed names for files to avoid having to regenerate VSCode project + components_paths[component_key] = component_key + zf.write(component_path, component_key) zf.writestr( "components.json", diff --git a/scripts/ufbt/SConstruct b/scripts/ufbt/SConstruct index a82189c14..ce7c8b978 100644 --- a/scripts/ufbt/SConstruct +++ b/scripts/ufbt/SConstruct @@ -1,6 +1,8 @@ from SCons.Platform import TempFileMunge from SCons.Node import FS from SCons.Errors import UserError +from SCons.Warnings import warn, WarningOnByDefault + import os import multiprocessing @@ -163,6 +165,18 @@ dist_env.Alias("flash", openocd_target) if env["FORCE"]: env.AlwaysBuild(openocd_target) + +firmware_jflash = dist_env.JFlash( + dist_env["UFBT_STATE_DIR"].File("jflash"), + dist_env["FW_BIN"], + JFLASHADDR="0x20000000", +) +dist_env.Alias("firmware_jflash", firmware_jflash) +dist_env.Alias("jflash", firmware_jflash) +if env["FORCE"]: + env.AlwaysBuild(firmware_jflash) + + firmware_debug = dist_env.PhonyTarget( "debug", "${GDBPYCOM}", @@ -234,7 +248,12 @@ known_extapps = [ for apptype in apps_to_build_as_faps for app in appenv["APPBUILD"].get_apps_of_type(apptype, True) ] +incompatible_apps = [] for app in known_extapps: + if not app.supports_hardware_target(appenv.subst("f${TARGET_HW}")): + incompatible_apps.append(app) + continue + app_artifacts = appenv.BuildAppElf(app) app_src_dir = extract_abs_dir(app_artifacts.app._appdir) app_artifacts.installer = [ @@ -242,6 +261,13 @@ for app in known_extapps: appenv.Install(app_src_dir.Dir("dist").Dir("debug"), app_artifacts.debug), ] +if len(incompatible_apps): + print( + "WARNING: The following apps are not compatible with the current target hardware and will not be built: {}".format( + ", ".join([app.name for app in incompatible_apps]) + ) + ) + if appenv["FORCE"]: appenv.AlwaysBuild([extapp.compact for extapp in apps_artifacts.values()]) @@ -391,3 +417,13 @@ AddPostAction( dist_env.Precious(app_template_dist) dist_env.NoClean(app_template_dist) dist_env.Alias("create", app_template_dist) + +dist_env.PhonyTarget( + "get_blackmagic", + "@echo $( ${BLACKMAGIC_ADDR} $)", +) + +dist_env.PhonyTarget( + "get_apiversion", + "@echo $( ${UFBT_API_VERSION} $)", +) diff --git a/scripts/ufbt/project_template/.vscode/launch.json b/scripts/ufbt/project_template/.vscode/launch.json index d9c98dcc1..697de9a49 100644 --- a/scripts/ufbt/project_template/.vscode/launch.json +++ b/scripts/ufbt/project_template/.vscode/launch.json @@ -2,19 +2,16 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "inputs": [ - // { - // "id": "BLACKMAGIC", - // "type": "command", - // "command": "shellCommand.execute", - // "args": { - // "useSingleResult": true, - // "env": { - // "PATH": "${workspaceFolder};${env:PATH}" - // }, - // "command": "./fbt get_blackmagic", - // "description": "Get Blackmagic device", - // } - // }, + { + "id": "BLACKMAGIC", + "type": "command", + "command": "shellCommand.execute", + "args": { + "description": "Get Blackmagic device", + "useSingleResult": true, + "command": "ufbt -s get_blackmagic", + } + }, ], "configurations": [ { @@ -57,26 +54,26 @@ ], // "showDevDebugOutput": "raw", }, - // { - // "name": "Attach FW (blackmagic)", - // "cwd": "${workspaceFolder}", - // "executable": "@UFBT_FIRMWARE_ELF@", - // "request": "attach", - // "type": "cortex-debug", - // "servertype": "external", - // "gdbTarget": "${input:BLACKMAGIC}", - // "svdFile": "@UFBT_DEBUG_DIR@/STM32WB55_CM4.svd", - // "rtos": "FreeRTOS", - // "postAttachCommands": [ - // "monitor swdp_scan", - // "attach 1", - // "set confirm off", - // "set mem inaccessible-by-default off", - // "source @UFBT_DEBUG_DIR@/flipperapps.py", - // "fap-set-debug-elf-root @UFBT_DEBUG_ELF_DIR@" - // ] - // // "showDevDebugOutput": "raw", - // }, + { + "name": "Attach FW (blackmagic)", + "cwd": "${workspaceFolder}", + "executable": "@UFBT_FIRMWARE_ELF@", + "request": "attach", + "type": "cortex-debug", + "servertype": "external", + "gdbTarget": "${input:BLACKMAGIC}", + "svdFile": "@UFBT_DEBUG_DIR@/STM32WB55_CM4.svd", + "rtos": "FreeRTOS", + "postAttachCommands": [ + "monitor swdp_scan", + "attach 1", + "set confirm off", + "set mem inaccessible-by-default off", + "source @UFBT_DEBUG_DIR@/flipperapps.py", + "fap-set-debug-elf-root @UFBT_DEBUG_ELF_DIR@" + ] + // "showDevDebugOutput": "raw", + }, { "name": "Attach FW (JLink)", "cwd": "${workspaceFolder}", diff --git a/scripts/ufbt/project_template/.vscode/tasks.json b/scripts/ufbt/project_template/.vscode/tasks.json index 6343bba7b..4b3f4bda5 100644 --- a/scripts/ufbt/project_template/.vscode/tasks.json +++ b/scripts/ufbt/project_template/.vscode/tasks.json @@ -20,24 +20,30 @@ "type": "shell", "command": "ufbt" }, + { + "label": "Clean", + "group": "build", + "type": "shell", + "command": "ufbt -c" + }, { "label": "Flash FW (ST-Link)", "group": "build", "type": "shell", "command": "ufbt FORCE=1 flash" }, - // { - // "label": "[NOTIMPL] Flash FW (blackmagic)", - // "group": "build", - // "type": "shell", - // "command": "ufbt flash_blackmagic" - // }, - // { - // "label": "[NOTIMPL] Flash FW (JLink)", - // "group": "build", - // "type": "shell", - // "command": "ufbt FORCE=1 jflash" - // }, + { + "label": "Flash FW (blackmagic)", + "group": "build", + "type": "shell", + "command": "ufbt flash_blackmagic" + }, + { + "label": "Flash FW (JLink)", + "group": "build", + "type": "shell", + "command": "ufbt FORCE=1 jflash" + }, { "label": "Flash FW (USB, with resources)", "group": "build", @@ -49,6 +55,12 @@ "group": "build", "type": "shell", "command": "ufbt update" + }, + { + "label": "Update VSCode config for current SDK", + "group": "build", + "type": "shell", + "command": "ufbt vscode_dist" } ] } \ No newline at end of file diff --git a/scripts/ufbt/project_template/app_template/application.fam b/scripts/ufbt/project_template/app_template/application.fam index 31fadb207..37a4ce665 100644 --- a/scripts/ufbt/project_template/app_template/application.fam +++ b/scripts/ufbt/project_template/app_template/application.fam @@ -6,7 +6,7 @@ App( apptype=FlipperAppType.EXTERNAL, entry_point="@FBT_APPID@_app", stack_size=2 * 1024, - fap_category="Misc", + fap_category="Examples", # Optional values # fap_version=(0, 1), # (major, minor) fap_icon="@FBT_APPID@.png", # 10x10 1-bit PNG diff --git a/scripts/ufbt/site_tools/ufbt_state.py b/scripts/ufbt/site_tools/ufbt_state.py index 6ba8c6962..76c6e9acf 100644 --- a/scripts/ufbt/site_tools/ufbt_state.py +++ b/scripts/ufbt/site_tools/ufbt_state.py @@ -75,12 +75,6 @@ def generate(env, **kw): if not sdk_state["meta"]["hw_target"].endswith(sdk_data["hardware"]): raise StopError("SDK state file doesn't match hardware target") - if sdk_state["meta"]["version"] != ufbt_state["version"]: - warn( - WarningOnByDefault, - f"Version mismatch: SDK state vs uFBT: {sdk_state['meta']['version']} vs {ufbt_state['version']}", - ) - scripts_dir = sdk_current_sdk_dir_node.Dir(sdk_components["scripts.dir"]) env.SetDefault( # Paths diff --git a/scripts/version.py b/scripts/version.py index 2527105d1..4fd5fd3f9 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -152,6 +152,7 @@ class Main(App): "firmware_commit": current_info["GIT_COMMIT"], "firmware_branch": current_info["GIT_BRANCH"], "firmware_target": current_info["TARGET"], + "firmware_version": current_info["VERSION"], } with open(version_json_name, "w", newline="\n") as file: json.dump(version_json, file, indent=4) diff --git a/site_scons/cc.scons b/site_scons/cc.scons index 1eb6a3376..55ab72ba6 100644 --- a/site_scons/cc.scons +++ b/site_scons/cc.scons @@ -36,6 +36,7 @@ ENV.AppendUnique( ], CPPDEFINES=[ "_GNU_SOURCE", + *GetOption("extra_defines"), ], LINKFLAGS=[ "-mcpu=cortex-m4", diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index 5610478cb..84ef6ce19 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -26,6 +26,14 @@ AddOption( help="List of applications to add to firmware's built-ins. Also see FIRMWARE_APP_SET and FIRMWARE_APPS", ) +AddOption( + "--extra-define", + action="append", + dest="extra_defines", + default=[], + help="Extra global define that will be passed to C/C++ compiler, can be specified multiple times", +) + AddOption( "--extra-ext-apps", action="store", diff --git a/site_scons/extapps.scons b/site_scons/extapps.scons index 7789f95b1..707132dc8 100644 --- a/site_scons/extapps.scons +++ b/site_scons/extapps.scons @@ -1,5 +1,4 @@ from dataclasses import dataclass, field -from os.path import dirname from SCons.Node import NodeList from SCons.Warnings import warn, WarningOnByDefault @@ -132,6 +131,7 @@ Depends(sdk_source, appenv.ProcessSdkDepends(f"{amalgamated_api}.d")) appenv["SDK_DIR"] = appenv.Dir("${BUILD_DIR}/sdk_headers") sdk_header_tree = appenv.SDKHeaderTreeExtractor(appenv["SDK_DIR"], amalgamated_api) +Depends(sdk_header_tree, appenv["SDK_DEFINITION"]) # AlwaysBuild(sdk_tree) Alias("sdk_tree", sdk_header_tree) extapps.sdk_tree = sdk_header_tree