From 8887cbff8842c7118e62eeccc9d685f539f335ec Mon Sep 17 00:00:00 2001 From: Louis D Date: Sun, 13 Jul 2025 02:56:04 +0200 Subject: [PATCH 01/31] feat: add option for custom button when creating a new Nice Flor-S or Nice One remote --- .../main/subghz/scenes/subghz_scene_config.h | 1 + .../subghz/scenes/subghz_scene_set_button.c | 88 +++++++++++++++++++ .../subghz/scenes/subghz_scene_set_seed.c | 3 +- .../subghz/scenes/subghz_scene_set_type.c | 36 ++------ applications/main/subghz/subghz_i.h | 1 + 5 files changed, 97 insertions(+), 32 deletions(-) create mode 100644 applications/main/subghz/scenes/subghz_scene_set_button.c diff --git a/applications/main/subghz/scenes/subghz_scene_config.h b/applications/main/subghz/scenes/subghz_scene_config.h index b9480b349..f682ac7e4 100644 --- a/applications/main/subghz/scenes/subghz_scene_config.h +++ b/applications/main/subghz/scenes/subghz_scene_config.h @@ -13,6 +13,7 @@ ADD_SCENE(subghz, delete, Delete) ADD_SCENE(subghz, delete_success, DeleteSuccess) ADD_SCENE(subghz, set_type, SetType) ADD_SCENE(subghz, set_fix, SetFix) +ADD_SCENE(subghz, set_button, SetButton) ADD_SCENE(subghz, set_cnt, SetCnt) ADD_SCENE(subghz, set_seed, SetSeed) ADD_SCENE(subghz, frequency_analyzer, FrequencyAnalyzer) diff --git a/applications/main/subghz/scenes/subghz_scene_set_button.c b/applications/main/subghz/scenes/subghz_scene_set_button.c new file mode 100644 index 000000000..89a47197d --- /dev/null +++ b/applications/main/subghz/scenes/subghz_scene_set_button.c @@ -0,0 +1,88 @@ +#include "../subghz_i.h" +#include "../helpers/subghz_txrx_create_protocol_key.h" + +#define TAG "SubGhzSetButton" + +void subghz_scene_set_button_byte_input_callback(void* context) { + SubGhz* subghz = context; + + view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone); +} + +void subghz_scene_set_button_on_enter(void* context) { + SubGhz* subghz = context; + // Set default value (button 1) for first use + subghz->secure_data->btn = 0x01; + + // Setup view + ByteInput* byte_input = subghz->byte_input; + byte_input_set_header_text(byte_input, "Enter BUTTON in hex"); + byte_input_set_result_callback( + byte_input, + subghz_scene_set_button_byte_input_callback, + NULL, + subghz, + &subghz->secure_data->btn, + 1); + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); +} + +bool subghz_scene_set_button_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + bool consumed = false; + bool generated_protocol = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubGhzCustomEventByteInputDone) { + SetType state = + scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType); + + if (state == SetTypeNiceFlorS_433_92 || state == SetTypeNiceOne_433_92) { + uint64_t key = (uint64_t)rand(); + + generated_protocol = subghz_txrx_gen_nice_flor_s_protocol( + subghz->txrx, + "AM650", + 433920000, + key & 0x0FFFFFFF, + subghz->secure_data->btn, + 0x03, + state == SetTypeNiceOne_433_92 + ); + + 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; + } + } + + // Reset Seed, Fix, Cnt, Btn in secure data after successful or unsuccessful generation + memset(subghz->secure_data->seed, 0, sizeof(subghz->secure_data->seed)); + memset(subghz->secure_data->cnt, 0, sizeof(subghz->secure_data->cnt)); + memset(subghz->secure_data->fix, 0, sizeof(subghz->secure_data->fix)); + subghz->secure_data->btn = 0x01; + + + 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_button_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 index c8301745f..01406371d 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_seed.c +++ b/applications/main/subghz/scenes/subghz_scene_set_seed.c @@ -108,10 +108,11 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) { } } - // Reset Seed, Fix, Cnt in secure data after successful or unsuccessful generation + // Reset Seed, Fix, Cnt, Btn in secure data after successful or unsuccessful generation memset(subghz->secure_data->seed, 0, sizeof(subghz->secure_data->seed)); memset(subghz->secure_data->cnt, 0, sizeof(subghz->secure_data->cnt)); memset(subghz->secure_data->fix, 0, sizeof(subghz->secure_data->fix)); + subghz->secure_data->btn = 0x01; if(generated_protocol) { subghz_file_name_clear(subghz); diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index b986c2c5d..33177b7de 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -112,7 +112,6 @@ typedef enum { GenKeeloqBFT, GenAlutechAt4n, GenSomfyTelis, - GenNiceFlorS, GenSecPlus1, GenSecPlus2, GenPhoenixV2, @@ -197,6 +196,11 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { return true; } + if (event.event == SetTypeNiceFlorS_433_92 || event.event == SetTypeNiceOne_433_92) { + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetButton); + return true; + } + uint64_t key = (uint64_t)rand(); uint64_t gangqi_key; @@ -722,26 +726,6 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { .keeloq.cnt = 0x03, .keeloq.manuf = "DoorHan"}; break; - case SetTypeNiceFlorS_433_92: - gen_info = (GenInfo){ - .type = GenNiceFlorS, - .mod = "AM650", - .freq = 433920000, - .nice_flor_s.serial = key & 0x0FFFFFFF, - .nice_flor_s.btn = 0x01, - .nice_flor_s.cnt = 0x03, - .nice_flor_s.nice_one = false}; - break; - case SetTypeNiceOne_433_92: - gen_info = (GenInfo){ - .type = GenNiceFlorS, - .mod = "AM650", - .freq = 433920000, - .nice_flor_s.serial = key & 0x0FFFFFFF, - .nice_flor_s.btn = 0x01, - .nice_flor_s.cnt = 0x03, - .nice_flor_s.nice_one = true}; - break; case SetTypeNiceSmilo_433_92: gen_info = (GenInfo){ .type = GenKeeloq, @@ -989,16 +973,6 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { gen_info.somfy_telis.btn, gen_info.somfy_telis.cnt); break; - case GenNiceFlorS: - generated_protocol = subghz_txrx_gen_nice_flor_s_protocol( - subghz->txrx, - gen_info.mod, - gen_info.freq, - gen_info.nice_flor_s.serial, - gen_info.nice_flor_s.btn, - gen_info.nice_flor_s.cnt, - gen_info.nice_flor_s.nice_one); - break; case GenSecPlus1: generated_protocol = subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, gen_info.mod, gen_info.freq); diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index b9fc47f79..6160c48c3 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -48,6 +48,7 @@ typedef struct { uint8_t fix[4]; uint8_t cnt[4]; uint8_t seed[4]; + uint8_t btn; } SecureData; struct SubGhz { From e6cc2852fda66388b685af41e8e031cb6a736054 Mon Sep 17 00:00:00 2001 From: Louis D Date: Tue, 15 Jul 2025 16:53:35 +0200 Subject: [PATCH 02/31] WIP: add sub-menu for all manual additions --- applications/main/subghz/scenes/subghz_scene_start.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/applications/main/subghz/scenes/subghz_scene_start.c b/applications/main/subghz/scenes/subghz_scene_start.c index fd5ce9990..fd59f48a4 100644 --- a/applications/main/subghz/scenes/subghz_scene_start.c +++ b/applications/main/subghz/scenes/subghz_scene_start.c @@ -40,6 +40,12 @@ void subghz_scene_start_on_enter(void* context) { SubmenuIndexAddManually, subghz_scene_start_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, + "Add Manually [Advanced]", + SubmenuIndexAddManually, + subghz_scene_start_submenu_callback, + subghz); submenu_add_item( subghz->submenu, "Frequency Analyzer", From 93d7005743be2776069d3d2c097ba85058d798d1 Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Wed, 23 Jul 2025 14:19:25 +0400 Subject: [PATCH 03/31] cli_shell: waste even less time Co-Authored-By: WillyJL --- lib/toolbox/cli/shell/cli_shell.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/toolbox/cli/shell/cli_shell.c b/lib/toolbox/cli/shell/cli_shell.c index f97daeb03..b2648d127 100644 --- a/lib/toolbox/cli/shell/cli_shell.c +++ b/lib/toolbox/cli/shell/cli_shell.c @@ -16,7 +16,8 @@ #define TAG "CliShell" -#define ANSI_TIMEOUT_MS 10 +#define ANSI_TIMEOUT_MS 10 +#define TRANSIENT_SESSION_WINDOW_MS 100 typedef enum { CliShellComponentCompletions, @@ -415,13 +416,15 @@ static void cli_shell_deinit(CliShell* shell) { static int32_t cli_shell_thread(void* context) { CliShell* shell = context; - // Give qFlipper a chance to close and re-open the session - furi_delay_ms(100); - - // Sometimes, the other side closes the pipe even before our thread is started. Although the - // rest of the code will eventually find this out if this check is removed, there's no point in - // wasting time. - if(pipe_state(shell->pipe) == PipeStateBroken) return 0; + // Sometimes, the other side (e.g. qFlipper) closes the pipe even before our thread is started. + // Although the rest of the code will eventually find this out if this check is removed, + // there's no point in wasting time. This gives qFlipper a chance to quickly close and re-open + // the session. + const size_t delay_step = 10; + for(size_t i = 0; i < TRANSIENT_SESSION_WINDOW_MS / delay_step; i++) { + furi_delay_ms(delay_step); + if(pipe_state(shell->pipe) == PipeStateBroken) return 0; + } cli_shell_init(shell); FURI_LOG_D(TAG, "Started"); From 115734373b86416ba334c07f1e56271762f6816e Mon Sep 17 00:00:00 2001 From: Louis D Date: Wed, 23 Jul 2025 23:24:03 +0200 Subject: [PATCH 04/31] feat: add variation of 'Add Manually' menu with manual value selection for all entries --- .../main/subghz/helpers/subghz_custom_event.h | 3 - .../main/subghz/helpers/subghz_gen_info.c | 725 +++++++++++++++ .../main/subghz/helpers/subghz_gen_info.h | 84 ++ .../main/subghz/scenes/subghz_scene_config.h | 5 +- .../subghz/scenes/subghz_scene_save_name.c | 8 +- .../subghz/scenes/subghz_scene_set_button.c | 109 ++- .../main/subghz/scenes/subghz_scene_set_cnt.c | 66 -- .../subghz/scenes/subghz_scene_set_counter.c | 189 ++++ .../main/subghz/scenes/subghz_scene_set_fix.c | 46 - .../main/subghz/scenes/subghz_scene_set_key.c | 95 ++ .../subghz/scenes/subghz_scene_set_seed.c | 161 ++-- .../subghz/scenes/subghz_scene_set_serial.c | 119 +++ .../subghz/scenes/subghz_scene_set_type.c | 864 ++---------------- .../main/subghz/scenes/subghz_scene_start.c | 18 +- .../main/subghz/scenes/subghz_scene_start.h | 12 + applications/main/subghz/subghz.c | 4 +- applications/main/subghz/subghz_i.h | 10 +- 17 files changed, 1445 insertions(+), 1073 deletions(-) create mode 100644 applications/main/subghz/helpers/subghz_gen_info.c create mode 100644 applications/main/subghz/helpers/subghz_gen_info.h delete mode 100644 applications/main/subghz/scenes/subghz_scene_set_cnt.c create mode 100644 applications/main/subghz/scenes/subghz_scene_set_counter.c delete mode 100644 applications/main/subghz/scenes/subghz_scene_set_fix.c create mode 100644 applications/main/subghz/scenes/subghz_scene_set_key.c create mode 100644 applications/main/subghz/scenes/subghz_scene_set_serial.c create mode 100644 applications/main/subghz/scenes/subghz_scene_start.h diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index 9fc607889..dffc6d193 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -65,9 +65,6 @@ typedef enum { } SubGhzCustomEvent; typedef enum { - SetTypeFaacSLH_Manual_868, - SetTypeFaacSLH_Manual_433, - SetTypeBFTClone, SetTypeFaacSLH_868, SetTypeFaacSLH_433, SetTypeBFTMitto, diff --git a/applications/main/subghz/helpers/subghz_gen_info.c b/applications/main/subghz/helpers/subghz_gen_info.c new file mode 100644 index 000000000..00ff43abc --- /dev/null +++ b/applications/main/subghz/helpers/subghz_gen_info.c @@ -0,0 +1,725 @@ +#include "subghz_gen_info.h" +#include "../helpers/subghz_txrx_create_protocol_key.h" +#include + + +void subghz_gen_info_reset(GenInfo *gen_info) { + furi_assert(gen_info); + memset(gen_info, 0, sizeof(GenInfo)); +} + +void subghz_scene_set_type_fill_generation_infos(GenInfo* infos_dest, SetType type) { + GenInfo gen_info = { 0 }; + uint64_t key = (uint64_t)rand(); + + uint64_t gangqi_key; + subghz_txrx_gen_serial_gangqi(&gangqi_key); + + uint64_t marantec_key; + subghz_txrx_gen_key_marantec(&marantec_key); + + switch(type) { + case SetTypePricenton433: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_PRINCETON_NAME, + .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 + .data.bits = 24, + .data.te = 400}; + break; + case SetTypePricenton315: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 315000000, + .data.name = SUBGHZ_PROTOCOL_PRINCETON_NAME, + .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 + .data.bits = 24, + .data.te = 400}; + break; + case SetTypeNiceFlo12bit: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_NICE_FLO_NAME, + .data.key = (key & 0x00000FF0) | 0x1, // btn 0x1, 0x2, 0x4 + .data.bits = 12, + .data.te = 0}; + break; + case SetTypeNiceFlo24bit: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_NICE_FLO_NAME, + .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 + .data.bits = 24, + .data.te = 0}; + break; + case SetTypeCAME12bit: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_CAME_NAME, + .data.key = (key & 0x00000FF0) | 0x1, // btn 0x1, 0x2, 0x4 + .data.bits = 12, + .data.te = 0}; + break; + case SetTypeCAME24bit: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_CAME_NAME, + .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 + .data.bits = 24, + .data.te = 0}; + break; + case SetTypeCAME12bit868: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 868350000, + .data.name = SUBGHZ_PROTOCOL_CAME_NAME, + .data.key = (key & 0x00000FF0) | 0x1, // btn 0x1, 0x2, 0x4 + .data.bits = 12, + .data.te = 0}; + break; + case SetTypeCAME24bit868: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 868350000, + .data.name = SUBGHZ_PROTOCOL_CAME_NAME, + .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 + .data.bits = 24, + .data.te = 0}; + break; + case SetTypeRoger_433: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_ROGER_NAME, + .data.key = (key & 0xFFFF000) | 0x0000101, // button code 0x1 and (crc?) is 0x01 + .data.bits = 28, + .data.te = 0}; + break; + case SetTypeLinear_300_00: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 300000000, + .data.name = SUBGHZ_PROTOCOL_LINEAR_NAME, + .data.key = (key & 0x3FF), + .data.bits = 10, + .data.te = 0}; + break; + case SetTypeBETT_433: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_BETT_NAME, + .data.key = (key & 0x0000FFF0), + .data.bits = 18, + .data.te = 0}; + break; + case SetTypeCAMETwee: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_CAME_TWEE_NAME, + .data.key = 0x003FFF7200000000 | ((key & 0x0FFFFFF0) ^ 0xE0E0E0EE), // ???? + .data.bits = 54, + .data.te = 0}; + break; + case SetTypeGateTX: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_GATE_TX_NAME, // btn 0xF, 0xC, 0xA, 0x6 (?) + .data.key = subghz_protocol_blocks_reverse_key((key & 0x00F0FF00) | 0xF0040, 24), + .data.bits = 24, + .data.te = 0}; + break; + case SetTypeGangQi_433: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = + SUBGHZ_PROTOCOL_GANGQI_NAME, // Add button 0xD arm and crc sum to the end + .data.key = gangqi_key, + .data.bits = 34, + .data.te = 0}; + break; + case SetTypeHollarm_433: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_HOLLARM_NAME, // Add button 0x2 and crc sum to the end + .data.key = (key & 0x000FFF0000) | 0xF0B0002200 | + ((((((key & 0x000FFF0000) | 0xF0B0002200) >> 32) & 0xFF) + + ((((key & 0x000FFF0000) | 0xF0B0002200) >> 24) & 0xFF) + + ((((key & 0x000FFF0000) | 0xF0B0002200) >> 16) & 0xFF) + + ((((key & 0x000FFF0000) | 0xF0B0002200) >> 8) & 0xFF)) & + 0xFF), + .data.bits = 42, + .data.te = 0}; + break; + case SetTypeReversRB2_433: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_REVERSRB2_NAME, // 64bits no buttons + .data.key = (key & 0x00000FFFFFFFF000) | 0xFFFFF00000000000 | 0x0000000000000A00, + .data.bits = 64, + .data.te = 0}; + break; + case SetTypeMarantec24_868: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 868350000, + .data.name = SUBGHZ_PROTOCOL_MARANTEC24_NAME, // Add button code 0x8 to the end + .data.key = (key & 0xFFFFF0) | 0x000008, + .data.bits = 24, + .data.te = 0}; + break; + case SetTypeMarantec_433: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = + SUBGHZ_PROTOCOL_MARANTEC_NAME, // Button code is 0x4 and crc sum to the end + .data.key = marantec_key, + .data.bits = 49, + .data.te = 0}; + break; + case SetTypeMarantec_868: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 868350000, + .data.name = + SUBGHZ_PROTOCOL_MARANTEC_NAME, // Button code is 0x4 and crc sum to the end + .data.key = marantec_key, + .data.bits = 49, + .data.te = 0}; + break; + case SetTypeFaacSLH_433: + gen_info = (GenInfo){ + .type = GenFaacSLH, + .mod = "AM650", + .freq = 433920000, + .faac_slh.serial = ((key & 0x00FFFFF0) | 0xA0000006) >> 4, + .faac_slh.btn = 0x06, + .faac_slh.cnt = 0x02, + .faac_slh.seed = key, + .faac_slh.manuf = "FAAC_SLH"}; + break; + case SetTypeFaacSLH_868: + gen_info = (GenInfo){ + .type = GenFaacSLH, + .mod = "AM650", + .freq = 868350000, + .faac_slh.serial = ((key & 0x00FFFFF0) | 0xA0000006) >> 4, + .faac_slh.btn = 0x06, + .faac_slh.cnt = 0x02, + .faac_slh.seed = (key & 0x0FFFFFFF), + .faac_slh.manuf = "FAAC_SLH"}; + break; + case SetTypeBeninca433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x000FFF00) | 0x00800080, + .keeloq.btn = 0x01, + .keeloq.cnt = 0x05, + .keeloq.manuf = "Beninca"}; + break; + case SetTypeBeninca868: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 868350000, + .keeloq.serial = (key & 0x000FFF00) | 0x00800080, + .keeloq.btn = 0x01, + .keeloq.cnt = 0x05, + .keeloq.manuf = "Beninca"}; + break; + case SetTypeComunello433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x08, + .keeloq.cnt = 0x05, + .keeloq.manuf = "Comunello"}; + break; + case SetTypeComunello868: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 868460000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x08, + .keeloq.cnt = 0x05, + .keeloq.manuf = "Comunello"}; + break; + case SetTypeAllmatic433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x00FFFF00) | 0x01000011, + .keeloq.btn = 0x0C, + .keeloq.cnt = 0x05, + .keeloq.manuf = "Beninca"}; + break; + case SetTypeAllmatic868: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 868350000, + .keeloq.serial = (key & 0x00FFFF00) | 0x01000011, + .keeloq.btn = 0x0C, + .keeloq.cnt = 0x05, + .keeloq.manuf = "Beninca"}; + break; + case SetTypeCenturion433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x0000FFFF), + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Centurion"}; + break; + case SetTypeMonarch433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x0000FFFF), + .keeloq.btn = 0x0A, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Monarch"}; + break; + case SetTypeJollyMotors433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x000FFFFF), + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Jolly_Motors"}; + break; + case SetTypeElmesElectronic: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x00FFFFFF) | 0x02000000, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Elmes_Poland"}; + break; + case SetTypeANMotorsAT4: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x000FFFFF) | 0x04700000, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x21, + .keeloq.manuf = "AN-Motors"}; + break; + case SetTypeAprimatic: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x000FFFFF) | 0x00600000, + .keeloq.btn = 0x08, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Aprimatic"}; + break; + case SetTypeGibidi433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Gibidi"}; + break; + case SetTypeGSN: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x0FFFFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "GSN"}; + break; + case SetTypeIronLogic: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFF0, + .keeloq.btn = 0x04, + .keeloq.cnt = 0x05, + .keeloq.manuf = "IronLogic"}; + break; + case SetTypeStilmatic: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x0FFFFFFF, + .keeloq.btn = 0x01, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Stilmatic"}; + break; + case SetTypeSommer_FM_434: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "FM476", + .freq = 434420000, + .keeloq.serial = (key & 0x0000FFFF) | 0x01700000, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Sommer(fsk476)"}; + break; + case SetTypeSommer_FM_868: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "FM476", + .freq = 868800000, + .keeloq.serial = (key & 0x0000FFFF) | 0x01700000, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Sommer(fsk476)"}; + break; + case SetTypeSommer_FM238_434: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "FM238", + .freq = 434420000, + .keeloq.serial = key & 0x0000FFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Sommer(fsk476)"}; + break; + case SetTypeSommer_FM238_868: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "FM238", + .freq = 868800000, + .keeloq.serial = key & 0x0000FFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Sommer(fsk476)"}; + break; + case SetTypeDTMNeo433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x000FFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x05, + .keeloq.manuf = "DTM_Neo"}; + break; + case SetTypeCAMESpace: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x04, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Came_Space"}; + break; + case SetTypeCameAtomo433: + gen_info = (GenInfo){ + .type = GenCameAtomo, + .mod = "AM650", + .freq = 433920000, + .came_atomo.serial = (key & 0x0FFFFFFF) | 0x10000000, + .came_atomo.cnt = 0x03}; + break; + case SetTypeCameAtomo868: + gen_info = (GenInfo){ + .type = GenCameAtomo, + .mod = "AM650", + .freq = 868350000, + .came_atomo.serial = (key & 0x0FFFFFFF) | 0x10000000, + .came_atomo.cnt = 0x03}; + break; + case SetTypeBFTMitto: + gen_info = (GenInfo){ + .type = GenKeeloqBFT, + .mod = "AM650", + .freq = 433920000, + .keeloq_bft.serial = key & 0x000FFFFF, + .keeloq_bft.btn = 0x02, + .keeloq_bft.cnt = 0x02, + .keeloq_bft.seed = key & 0x000FFFFF, + .keeloq_bft.manuf = "BFT"}; + break; + case SetTypeAlutechAT4N: + gen_info = (GenInfo){ + .type = GenAlutechAt4n, + .mod = "AM650", + .freq = 433920000, + .alutech_at_4n.serial = (key & 0x000FFFFF) | 0x00100000, + .alutech_at_4n.btn = 0x44, + .alutech_at_4n.cnt = 0x03}; + break; + case SetTypeSomfyTelis: + gen_info = (GenInfo){ + .type = GenSomfyTelis, + .mod = "AM650", + .freq = 433420000, + .somfy_telis.serial = key & 0x00FFFFFF, + .somfy_telis.btn = 0x02, + .somfy_telis.cnt = 0x03}; + break; + case SetTypeMotorline433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x0FFFFFFF, + .keeloq.btn = 0x01, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Motorline"}; + break; + case SetTypeDoorHan_433_92: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x0FFFFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "DoorHan"}; + break; + case SetTypeDoorHan_315_00: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 315000000, + .keeloq.serial = key & 0x0FFFFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "DoorHan"}; + break; + case SetTypeNiceFlorS_433_92: + gen_info = (GenInfo){ + .type = GenNiceFlorS, + .mod = "AM650", + .freq = 433920000, + .nice_flor_s.serial = key & 0x0FFFFFFF, + .nice_flor_s.btn = 0x01, + .nice_flor_s.cnt = 0x03, + .nice_flor_s.nice_one = false}; + break; + case SetTypeNiceOne_433_92: + gen_info = (GenInfo){ + .type = GenNiceFlorS, + .mod = "AM650", + .freq = 433920000, + .nice_flor_s.serial = key & 0x0FFFFFFF, + .nice_flor_s.btn = 0x01, + .nice_flor_s.cnt = 0x03, + .nice_flor_s.nice_one = true}; + break; + case SetTypeNiceSmilo_433_92: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "NICE_Smilo"}; + break; + case SetTypeNiceMHouse_433_92: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x09, + .keeloq.cnt = 0x03, + .keeloq.manuf = "NICE_MHOUSE"}; + break; + case SetTypeDeaMio433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x0FFFF000) | 0x00000869, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Dea_Mio"}; + break; + case SetTypeGeniusBravo433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x06, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Genius_Bravo"}; + break; + case SetTypeJCM_433_92: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "JCM_Tech"}; + break; + case SetTypeNovoferm_433_92: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x0000FFFF) | 0x018F0000, + .keeloq.btn = 0x01, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Novoferm"}; + break; + case SetTypeHormannEcoStar_433_92: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x000FFFFF) | 0x02200000, + .keeloq.btn = 0x04, + .keeloq.cnt = 0x03, + .keeloq.manuf = "EcoStar"}; + break; + case SetTypeFAACRCXT_433_92: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x0000FFFF) | 0x00100000, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "FAAC_RC,XT"}; + break; + case SetTypeFAACRCXT_868: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 868350000, + .keeloq.serial = (key & 0x0000FFFF) | 0x00100000, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "FAAC_RC,XT"}; + break; + case SetTypeNormstahl_433_92: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x0000FFFF, + .keeloq.btn = 0x04, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Normstahl"}; + break; + case SetTypeHCS101_433_92: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x000FFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "HCS101"}; + break; + case SetTypeSecPlus_v1_315_00: + gen_info = (GenInfo){.type = GenSecPlus1, .mod = "AM650", .freq = 315000000}; + break; + case SetTypeSecPlus_v1_390_00: + gen_info = (GenInfo){.type = GenSecPlus1, .mod = "AM650", .freq = 390000000}; + break; + case SetTypeSecPlus_v1_433_00: + gen_info = (GenInfo){.type = GenSecPlus1, .mod = "AM650", .freq = 433920000}; + break; + case SetTypeSecPlus_v2_310_00: + gen_info = (GenInfo){ + .type = GenSecPlus2, + .mod = "AM650", + .freq = 310000000, + .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing + .sec_plus_2.btn = 0x68, + .sec_plus_2.cnt = 0xE500000}; + break; + case SetTypeSecPlus_v2_315_00: + gen_info = (GenInfo){ + .type = GenSecPlus2, + .mod = "AM650", + .freq = 315000000, + .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing + .sec_plus_2.btn = 0x68, + .sec_plus_2.cnt = 0xE500000}; + break; + case SetTypeSecPlus_v2_390_00: + gen_info = (GenInfo){ + .type = GenSecPlus2, + .mod = "AM650", + .freq = 390000000, + .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing + .sec_plus_2.btn = 0x68, + .sec_plus_2.cnt = 0xE500000}; + break; + case SetTypeSecPlus_v2_433_00: + gen_info = (GenInfo){ + .type = GenSecPlus2, + .mod = "AM650", + .freq = 433920000, + .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing + .sec_plus_2.btn = 0x68, + .sec_plus_2.cnt = 0xE500000}; + break; + case SetTypePhoenix_V2_433: + gen_info = (GenInfo){ + .type = GenPhoenixV2, + .mod = "AM650", + .freq = 433920000, + .phoenix_v2.serial = (key & 0x0FFFFFFF) | 0xB0000000, + .phoenix_v2.cnt = 0x025D}; + break; + default: + furi_crash("Not implemented"); + break; + } + *infos_dest = gen_info; +} diff --git a/applications/main/subghz/helpers/subghz_gen_info.h b/applications/main/subghz/helpers/subghz_gen_info.h new file mode 100644 index 000000000..938c6d27a --- /dev/null +++ b/applications/main/subghz/helpers/subghz_gen_info.h @@ -0,0 +1,84 @@ +#pragma once +#include "subghz_types.h" +#include "subghz_custom_event.h" + +typedef enum { + GenData, + GenFaacSLH, + GenKeeloq, + GenCameAtomo, + GenKeeloqBFT, + GenAlutechAt4n, + GenSomfyTelis, + GenNiceFlorS, + GenSecPlus1, + GenSecPlus2, + GenPhoenixV2, +} GenType; + +typedef struct { + GenType type; + const char* mod; + uint32_t freq; + union { + struct { + const char* name; + uint64_t key; + uint8_t bits; + uint16_t te; + } data; + struct { + uint32_t serial; + uint8_t btn; + uint8_t cnt; + uint32_t seed; + const char* manuf; + } faac_slh; + struct { + uint32_t serial; + uint8_t btn; + uint8_t cnt; + const char* manuf; + } keeloq; + struct { + uint32_t serial; + uint8_t cnt; + } came_atomo; + struct { + uint32_t serial; + uint8_t btn; + uint8_t cnt; + uint32_t seed; + const char* manuf; + } keeloq_bft; + struct { + uint32_t serial; + uint8_t btn; + uint8_t cnt; + } alutech_at_4n; + struct { + uint32_t serial; + uint8_t btn; + uint8_t cnt; + } somfy_telis; + struct { + uint32_t serial; + uint8_t btn; + uint8_t cnt; + bool nice_one; + } nice_flor_s; + struct { + uint32_t serial; + uint8_t btn; + uint32_t cnt; + } sec_plus_2; + struct { + uint32_t serial; + uint16_t cnt; + } phoenix_v2; + }; +} GenInfo; + +void subghz_gen_info_reset(GenInfo *gen_info); + +void subghz_scene_set_type_fill_generation_infos(GenInfo* infos_dest, SetType type); diff --git a/applications/main/subghz/scenes/subghz_scene_config.h b/applications/main/subghz/scenes/subghz_scene_config.h index f682ac7e4..a23a12a2b 100644 --- a/applications/main/subghz/scenes/subghz_scene_config.h +++ b/applications/main/subghz/scenes/subghz_scene_config.h @@ -12,9 +12,10 @@ ADD_SCENE(subghz, saved_menu, SavedMenu) ADD_SCENE(subghz, delete, Delete) ADD_SCENE(subghz, delete_success, DeleteSuccess) ADD_SCENE(subghz, set_type, SetType) -ADD_SCENE(subghz, set_fix, SetFix) +ADD_SCENE(subghz, set_key, SetKey) +ADD_SCENE(subghz, set_serial, SetSerial) ADD_SCENE(subghz, set_button, SetButton) -ADD_SCENE(subghz, set_cnt, SetCnt) +ADD_SCENE(subghz, set_counter, SetCounter) ADD_SCENE(subghz, set_seed, SetSeed) ADD_SCENE(subghz, frequency_analyzer, FrequencyAnalyzer) ADD_SCENE(subghz, radio_settings, ExtModuleSettings) diff --git a/applications/main/subghz/scenes/subghz_scene_save_name.c b/applications/main/subghz/scenes/subghz_scene_save_name.c index d31f1ce25..66121545d 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_name.c +++ b/applications/main/subghz/scenes/subghz_scene_save_name.c @@ -103,12 +103,8 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { furi_string_set(subghz->file_path, subghz->file_path_tmp); } } - if(scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneSetSeed)) { - scene_manager_search_and_switch_to_previous_scene( - subghz->scene_manager, SubGhzSceneSetType); - } else { - scene_manager_previous_scene(subghz->scene_manager); - } + + scene_manager_previous_scene(subghz->scene_manager); return true; } else if(event.type == SceneManagerEventTypeCustom) { diff --git a/applications/main/subghz/scenes/subghz_scene_set_button.c b/applications/main/subghz/scenes/subghz_scene_set_button.c index 89a47197d..cd5e11f47 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_button.c +++ b/applications/main/subghz/scenes/subghz_scene_set_button.c @@ -11,8 +11,51 @@ void subghz_scene_set_button_byte_input_callback(void* context) { void subghz_scene_set_button_on_enter(void* context) { SubGhz* subghz = context; - // Set default value (button 1) for first use - subghz->secure_data->btn = 0x01; + + uint8_t* byte_ptr = NULL; + uint8_t byte_count = 0; + + switch(subghz->gen_info->type) { + case GenFaacSLH: + byte_ptr = &subghz->gen_info->faac_slh.btn; + byte_count = sizeof(subghz->gen_info->faac_slh.btn); + break; + case GenKeeloq: + byte_ptr = &subghz->gen_info->keeloq.btn; + byte_count = sizeof(subghz->gen_info->keeloq.btn); + break; + case GenKeeloqBFT: + byte_ptr = &subghz->gen_info->keeloq_bft.btn; + byte_count = sizeof(subghz->gen_info->keeloq_bft.btn); + break; + case GenAlutechAt4n: + byte_ptr = &subghz->gen_info->alutech_at_4n.btn; + byte_count = sizeof(subghz->gen_info->alutech_at_4n.btn); + break; + case GenSomfyTelis: + byte_ptr = &subghz->gen_info->somfy_telis.btn; + byte_count = sizeof(subghz->gen_info->somfy_telis.btn); + break; + case GenNiceFlorS: + byte_ptr = &subghz->gen_info->nice_flor_s.btn; + byte_count = sizeof(subghz->gen_info->nice_flor_s.btn); + break; + case GenSecPlus2: + byte_ptr = &subghz->gen_info->sec_plus_2.btn; + byte_count = sizeof(subghz->gen_info->sec_plus_2.btn); + break; + // Not needed for these types + case GenPhoenixV2: + case GenData: + case GenSecPlus1: + case GenCameAtomo: + default: + furi_crash("Not implemented"); + break; + } + + furi_assert(byte_ptr); + furi_assert(byte_count > 0); // Setup view ByteInput* byte_input = subghz->byte_input; @@ -22,58 +65,38 @@ void subghz_scene_set_button_on_enter(void* context) { subghz_scene_set_button_byte_input_callback, NULL, subghz, - &subghz->secure_data->btn, - 1); + byte_ptr, + byte_count); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); } bool subghz_scene_set_button_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; bool consumed = false; - bool generated_protocol = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventByteInputDone) { - SetType state = - scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType); - - if (state == SetTypeNiceFlorS_433_92 || state == SetTypeNiceOne_433_92) { - uint64_t key = (uint64_t)rand(); - - generated_protocol = subghz_txrx_gen_nice_flor_s_protocol( - subghz->txrx, - "AM650", - 433920000, - key & 0x0FFFFFFF, - subghz->secure_data->btn, - 0x03, - state == SetTypeNiceOne_433_92 - ); - - 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; + switch(subghz->gen_info->type) { + case GenFaacSLH: + case GenKeeloq: + case GenKeeloqBFT: + case GenAlutechAt4n: + case GenSomfyTelis: + case GenNiceFlorS: + case GenSecPlus2: + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetCounter); + break; + // Not needed for these types + case GenCameAtomo: + case GenPhoenixV2: + case GenData: + case GenSecPlus1: + default: + furi_crash("Not implemented"); + break; } - } - // Reset Seed, Fix, Cnt, Btn in secure data after successful or unsuccessful generation - memset(subghz->secure_data->seed, 0, sizeof(subghz->secure_data->seed)); - memset(subghz->secure_data->cnt, 0, sizeof(subghz->secure_data->cnt)); - memset(subghz->secure_data->fix, 0, sizeof(subghz->secure_data->fix)); - subghz->secure_data->btn = 0x01; - - - 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; + consumed = true; } } return consumed; diff --git a/applications/main/subghz/scenes/subghz_scene_set_cnt.c b/applications/main/subghz/scenes/subghz_scene_set_cnt.c deleted file mode 100644 index b202d6d91..000000000 --- a/applications/main/subghz/scenes/subghz_scene_set_cnt.c +++ /dev/null @@ -1,66 +0,0 @@ -#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 SetTypeBFTClone: - 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->secure_data->cnt, - 2); - break; - case SetTypeFaacSLH_Manual_433: - case SetTypeFaacSLH_Manual_868: - byte_input_set_header_text(byte_input, "Enter COUNTER in hex 20 bits"); - byte_input_set_result_callback( - byte_input, - subghz_scene_set_cnt_byte_input_callback, - NULL, - subghz, - subghz->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_counter.c b/applications/main/subghz/scenes/subghz_scene_set_counter.c new file mode 100644 index 000000000..b9f241258 --- /dev/null +++ b/applications/main/subghz/scenes/subghz_scene_set_counter.c @@ -0,0 +1,189 @@ +#include "../subghz_i.h" +#include "../helpers/subghz_txrx_create_protocol_key.h" + +#define TAG "SubGhzSetCounter" + +void subghz_scene_set_counter_byte_input_callback(void* context) { + SubGhz* subghz = context; + + view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone); +} + +void subghz_scene_set_counter_on_enter(void* context) { + SubGhz* subghz = context; + + uint8_t* byte_ptr = NULL; + uint8_t byte_count = 0; + + switch(subghz->gen_info->type) { + case GenFaacSLH: + byte_ptr = &subghz->gen_info->faac_slh.cnt; + byte_count = sizeof(subghz->gen_info->faac_slh.cnt); + break; + case GenKeeloq: + byte_ptr = &subghz->gen_info->keeloq.cnt; + byte_count = sizeof(subghz->gen_info->keeloq.cnt); + break; + case GenCameAtomo: + byte_ptr = &subghz->gen_info->came_atomo.cnt; + byte_count = sizeof(subghz->gen_info->came_atomo.cnt); + break; + case GenKeeloqBFT: + byte_ptr = &subghz->gen_info->keeloq_bft.cnt; + byte_count = sizeof(subghz->gen_info->keeloq_bft.cnt); + break; + case GenAlutechAt4n: + byte_ptr = &subghz->gen_info->alutech_at_4n.cnt; + byte_count = sizeof(subghz->gen_info->alutech_at_4n.cnt); + break; + case GenSomfyTelis: + byte_ptr = &subghz->gen_info->somfy_telis.cnt; + byte_count = sizeof(subghz->gen_info->somfy_telis.cnt); + break; + case GenNiceFlorS: + byte_ptr = &subghz->gen_info->nice_flor_s.cnt; + byte_count = sizeof(subghz->gen_info->nice_flor_s.cnt); + break; + case GenSecPlus2: + byte_ptr = (uint8_t*)&subghz->gen_info->sec_plus_2.cnt; + byte_count = sizeof(subghz->gen_info->sec_plus_2.cnt); + break; + case GenPhoenixV2: + byte_ptr = (uint8_t*)&subghz->gen_info->phoenix_v2.cnt; + byte_count = sizeof(subghz->gen_info->phoenix_v2.cnt); + break; + // Not needed for these types + case GenData: + case GenSecPlus1: + default: + furi_crash("Not implemented"); + break; + } + + furi_assert(byte_ptr); + furi_assert(byte_count > 0); + + // 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_counter_byte_input_callback, + NULL, + subghz, + byte_ptr, + byte_count); + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); +} + +bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + bool consumed = false; + bool generated_protocol = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubGhzCustomEventByteInputDone) { + GenInfo gen_info = *subghz->gen_info; + + switch(gen_info.type) { + case GenFaacSLH: + case GenKeeloqBFT: + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetSeed); + return true; + case GenKeeloq: + generated_protocol = subghz_txrx_gen_keeloq_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.keeloq.serial, + gen_info.keeloq.btn, + gen_info.keeloq.cnt, + gen_info.keeloq.manuf); + break; + case GenCameAtomo: + generated_protocol = subghz_txrx_gen_came_atomo_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.came_atomo.serial, + gen_info.came_atomo.cnt); + break; + case GenAlutechAt4n: + generated_protocol = subghz_txrx_gen_alutech_at_4n_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.alutech_at_4n.serial, + gen_info.alutech_at_4n.btn, + gen_info.alutech_at_4n.cnt); + break; + case GenSomfyTelis: + generated_protocol = subghz_txrx_gen_somfy_telis_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.somfy_telis.serial, + gen_info.somfy_telis.btn, + gen_info.somfy_telis.cnt); + break; + case GenNiceFlorS: + generated_protocol = subghz_txrx_gen_nice_flor_s_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.nice_flor_s.serial, + gen_info.nice_flor_s.btn, + gen_info.nice_flor_s.cnt, + gen_info.nice_flor_s.nice_one); + break; + case GenSecPlus2: + generated_protocol = subghz_txrx_gen_secplus_v2_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.sec_plus_2.serial, + gen_info.sec_plus_2.btn, + gen_info.sec_plus_2.cnt); + break; + case GenPhoenixV2: + generated_protocol = subghz_txrx_gen_phoenix_v2_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.phoenix_v2.serial, + gen_info.phoenix_v2.cnt); + break; + // Not needed for these types + case GenData: + case GenSecPlus1: + default: + furi_crash("Not implemented"); + break; + } + + consumed = true; + + 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); + } else { + subghz_file_name_clear(subghz); + + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneSetType, SubGhzCustomEventManagerSet); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); + } + } + } + return consumed; +} + +void subghz_scene_set_counter_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.c b/applications/main/subghz/scenes/subghz_scene_set_fix.c deleted file mode 100644 index 93df4e54d..000000000 --- a/applications/main/subghz/scenes/subghz_scene_set_fix.c +++ /dev/null @@ -1,46 +0,0 @@ -#include "../subghz_i.h" - -#define TAG "SubGhzSetFix" - -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_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_byte_input_callback, - NULL, - subghz, - subghz->secure_data->fix, - 4); - view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); -} - -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, SubGhzSceneSetCnt); - consumed = true; - } - } - return consumed; -} - -void subghz_scene_set_fix_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_key.c b/applications/main/subghz/scenes/subghz_scene_set_key.c new file mode 100644 index 000000000..f9872fb11 --- /dev/null +++ b/applications/main/subghz/scenes/subghz_scene_set_key.c @@ -0,0 +1,95 @@ +#include "../subghz_i.h" +#include "../helpers/subghz_txrx_create_protocol_key.h" + +#define TAG "SubGhzSetKey" + +void subghz_scene_set_key_byte_input_callback(void* context) { + SubGhz* subghz = context; + + view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone); +} + +void subghz_scene_set_key_on_enter(void* context) { + SubGhz* subghz = context; + + uint8_t* byte_ptr = NULL; + uint8_t byte_count = 0; + + if(subghz->gen_info->type == GenData) { + byte_ptr = (uint8_t*)&subghz->gen_info->data.key; + byte_count = sizeof(subghz->gen_info->data.key); + } else { + furi_crash("Not implemented"); + } + + furi_assert(byte_ptr); + furi_assert(byte_count > 0); + + // Setup view + ByteInput* byte_input = subghz->byte_input; + byte_input_set_header_text(byte_input, "Enter KEY in hex"); + byte_input_set_result_callback( + byte_input, + subghz_scene_set_key_byte_input_callback, + NULL, + subghz, + byte_ptr, + byte_count); + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); +} + +bool subghz_scene_set_key_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + bool consumed = false; + bool generated_protocol = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubGhzCustomEventByteInputDone) { + GenInfo gen_info = *subghz->gen_info; + + if(gen_info.type == GenData) { + if(gen_info.data.te) { + generated_protocol = subghz_txrx_gen_data_protocol_and_te( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.data.name, + gen_info.data.key, + gen_info.data.bits, + gen_info.data.te); + } else { + generated_protocol = subghz_txrx_gen_data_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.data.name, + gen_info.data.key, + gen_info.data.bits); + } + } + + consumed = true; + + 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); + } else { + subghz_file_name_clear(subghz); + + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneSetType, SubGhzCustomEventManagerSet); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); + } + } + } + return consumed; +} + +void subghz_scene_set_key_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 index 01406371d..408460518 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_seed.c +++ b/applications/main/subghz/scenes/subghz_scene_set_seed.c @@ -12,6 +12,36 @@ void subghz_scene_set_seed_byte_input_callback(void* context) { void subghz_scene_set_seed_on_enter(void* context) { SubGhz* subghz = context; + uint8_t* byte_ptr = NULL; + uint8_t byte_count = 0; + + switch(subghz->gen_info->type) { + case GenFaacSLH: + byte_ptr = (uint8_t*)&subghz->gen_info->faac_slh.seed; + byte_count = sizeof(subghz->gen_info->faac_slh.seed); + break; + case GenKeeloqBFT: + byte_ptr = (uint8_t*)&subghz->gen_info->keeloq_bft.seed; + byte_count = sizeof(subghz->gen_info->keeloq_bft.seed); + break; + // Not needed for these types + case GenKeeloq: + case GenAlutechAt4n: + case GenSomfyTelis: + case GenNiceFlorS: + case GenSecPlus2: + case GenPhoenixV2: + case GenData: + case GenSecPlus1: + case GenCameAtomo: + default: + furi_crash("Not implemented"); + break; + } + + furi_assert(byte_ptr); + furi_assert(byte_count > 0); + // Setup view ByteInput* byte_input = subghz->byte_input; byte_input_set_header_text(byte_input, "Enter SEED in hex"); @@ -20,8 +50,8 @@ void subghz_scene_set_seed_on_enter(void* context) { subghz_scene_set_seed_byte_input_callback, NULL, subghz, - subghz->secure_data->seed, - 4); + byte_ptr, + byte_count); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); } @@ -29,98 +59,61 @@ 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) { - SetType state = - scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType); + GenInfo gen_info = *subghz->gen_info; - switch(state) { - case SetTypeBFTClone: - fix_part = subghz->secure_data->fix[0] << 24 | subghz->secure_data->fix[1] << 16 | - subghz->secure_data->fix[2] << 8 | subghz->secure_data->fix[3]; - - cnt = subghz->secure_data->cnt[0] << 8 | subghz->secure_data->cnt[1]; - - seed = subghz->secure_data->seed[0] << 24 | subghz->secure_data->seed[1] << 16 | - subghz->secure_data->seed[2] << 8 | subghz->secure_data->seed[3]; - - generated_protocol = subghz_txrx_gen_keeloq_bft_protocol( - subghz->txrx, - "AM650", - 433920000, - fix_part & 0x0FFFFFFF, - fix_part >> 28, - cnt, - seed, - "BFT"); - - 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 SetTypeFaacSLH_Manual_433: - case SetTypeFaacSLH_Manual_868: - fix_part = subghz->secure_data->fix[0] << 24 | subghz->secure_data->fix[1] << 16 | - subghz->secure_data->fix[2] << 8 | subghz->secure_data->fix[3]; - - cnt = subghz->secure_data->cnt[0] << 16 | subghz->secure_data->cnt[1] << 8 | - subghz->secure_data->cnt[2]; - - seed = subghz->secure_data->seed[0] << 24 | subghz->secure_data->seed[1] << 16 | - subghz->secure_data->seed[2] << 8 | subghz->secure_data->seed[3]; - - if(state == SetTypeFaacSLH_Manual_433) { + switch(gen_info.type) { + case GenFaacSLH: generated_protocol = subghz_txrx_gen_faac_slh_protocol( subghz->txrx, - "AM650", - 433920000, - fix_part >> 4, - fix_part & 0xf, - (cnt & 0xFFFFF), - seed, - "FAAC_SLH"); - } else if(state == SetTypeFaacSLH_Manual_868) { - generated_protocol = subghz_txrx_gen_faac_slh_protocol( + gen_info.mod, + gen_info.freq, + gen_info.faac_slh.serial, + gen_info.faac_slh.btn, + gen_info.faac_slh.cnt, + gen_info.faac_slh.seed, + gen_info.faac_slh.manuf); + break; + case GenKeeloqBFT: + generated_protocol = subghz_txrx_gen_keeloq_bft_protocol( subghz->txrx, - "AM650", - 868350000, - fix_part >> 4, - fix_part & 0xf, - (cnt & 0xFFFFF), - seed, - "FAAC_SLH"); - } - - 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; + gen_info.mod, + gen_info.freq, + gen_info.keeloq_bft.serial, + gen_info.keeloq_bft.btn, + gen_info.keeloq_bft.cnt, + gen_info.keeloq_bft.seed, + gen_info.keeloq_bft.manuf); + break; + // Not needed for these types + case GenKeeloq: + case GenAlutechAt4n: + case GenSomfyTelis: + case GenNiceFlorS: + case GenSecPlus2: + case GenPhoenixV2: + case GenData: + case GenSecPlus1: + case GenCameAtomo: + default: + furi_crash("Not implemented"); + break; } - } - // Reset Seed, Fix, Cnt, Btn in secure data after successful or unsuccessful generation - memset(subghz->secure_data->seed, 0, sizeof(subghz->secure_data->seed)); - memset(subghz->secure_data->cnt, 0, sizeof(subghz->secure_data->cnt)); - memset(subghz->secure_data->fix, 0, sizeof(subghz->secure_data->fix)); - subghz->secure_data->btn = 0x01; + consumed = true; - if(generated_protocol) { - subghz_file_name_clear(subghz); + 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); + } else { + 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; + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneSetType, SubGhzCustomEventManagerSet); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); + } } } return consumed; diff --git a/applications/main/subghz/scenes/subghz_scene_set_serial.c b/applications/main/subghz/scenes/subghz_scene_set_serial.c new file mode 100644 index 000000000..42d815dd7 --- /dev/null +++ b/applications/main/subghz/scenes/subghz_scene_set_serial.c @@ -0,0 +1,119 @@ +#include "../subghz_i.h" +#include "../helpers/subghz_txrx_create_protocol_key.h" + +#define TAG "SubGhzSetSerial" + +void subghz_scene_set_serial_byte_input_callback(void* context) { + SubGhz* subghz = context; + + view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventByteInputDone); +} + +void subghz_scene_set_serial_on_enter(void* context) { + SubGhz* subghz = context; + + uint8_t* byte_ptr = NULL; + uint8_t byte_count = 0; + + switch(subghz->gen_info->type) { + case GenFaacSLH: + byte_ptr = (uint8_t*)&subghz->gen_info->faac_slh.serial; + byte_count = sizeof(subghz->gen_info->faac_slh.serial); + break; + case GenKeeloq: + byte_ptr = (uint8_t*)&subghz->gen_info->keeloq.serial; + byte_count = sizeof(subghz->gen_info->keeloq.serial); + break; + case GenCameAtomo: + byte_ptr = (uint8_t*)&subghz->gen_info->came_atomo.serial; + byte_count = sizeof(subghz->gen_info->came_atomo.serial); + break; + case GenKeeloqBFT: + byte_ptr = (uint8_t*)&subghz->gen_info->keeloq_bft.serial; + byte_count = sizeof(subghz->gen_info->keeloq_bft.serial); + break; + case GenAlutechAt4n: + byte_ptr = (uint8_t*)&subghz->gen_info->alutech_at_4n.serial; + byte_count = sizeof(subghz->gen_info->alutech_at_4n.serial); + break; + case GenSomfyTelis: + byte_ptr = (uint8_t*)&subghz->gen_info->somfy_telis.serial; + byte_count = sizeof(subghz->gen_info->somfy_telis.serial); + break; + case GenNiceFlorS: + byte_ptr = (uint8_t*)&subghz->gen_info->nice_flor_s.serial; + byte_count = sizeof(subghz->gen_info->nice_flor_s.serial); + break; + case GenSecPlus2: + byte_ptr = (uint8_t*)&subghz->gen_info->sec_plus_2.serial; + byte_count = sizeof(subghz->gen_info->sec_plus_2.serial); + break; + case GenPhoenixV2: + byte_ptr = (uint8_t*)&subghz->gen_info->phoenix_v2.serial; + byte_count = sizeof(subghz->gen_info->phoenix_v2.serial); + break; + // Not needed for these types + case GenData: + case GenSecPlus1: + default: + furi_crash("Not implemented"); + break; + } + + furi_assert(byte_ptr); + furi_assert(byte_count > 0); + + // Setup view + ByteInput* byte_input = subghz->byte_input; + byte_input_set_header_text(byte_input, "Enter SERIAL in hex"); + byte_input_set_result_callback( + byte_input, + subghz_scene_set_serial_byte_input_callback, + NULL, + subghz, + byte_ptr, + byte_count); + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); +} + +bool subghz_scene_set_serial_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubGhzCustomEventByteInputDone) { + switch(subghz->gen_info->type) { + case GenFaacSLH: + case GenKeeloq: + case GenKeeloqBFT: + case GenAlutechAt4n: + case GenSomfyTelis: + case GenNiceFlorS: + case GenSecPlus2: + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetButton); + break; + case GenCameAtomo: + case GenPhoenixV2: + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetCounter); + break; + // Not needed for these types + case GenData: + case GenSecPlus1: + default: + furi_crash("Not implemented"); + break; + } + + consumed = true; + } + } + return consumed; +} + +void subghz_scene_set_serial_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 33177b7de..61e5148de 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -1,7 +1,8 @@ #include "../subghz_i.h" #include "../helpers/subghz_txrx_create_protocol_key.h" +#include "../helpers/subghz_gen_info.h" +#include "subghz_scene_start.h" #include -#include #define TAG "SubGhzSetType" @@ -11,9 +12,6 @@ void subghz_scene_set_type_submenu_callback(void* context, uint32_t index) { } static const char* submenu_names[SetTypeMAX] = { - [SetTypeFaacSLH_Manual_868] = "FAAC SLH [Man.] 868MHz", - [SetTypeFaacSLH_Manual_433] = "FAAC SLH [Man.] 433MHz", - [SetTypeBFTClone] = "BFT [Manual] 433MHz", [SetTypeFaacSLH_868] = "FAAC SLH 868MHz", [SetTypeFaacSLH_433] = "FAAC SLH 433MHz", [SetTypeBFTMitto] = "BFT Mitto 433MHz", @@ -104,797 +102,10 @@ void subghz_scene_set_type_on_enter(void* context) { view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdMenu); } -typedef enum { - GenData, - GenFaacSLH, - GenKeeloq, - GenCameAtomo, - GenKeeloqBFT, - GenAlutechAt4n, - GenSomfyTelis, - GenSecPlus1, - GenSecPlus2, - GenPhoenixV2, -} GenType; - -typedef struct { - GenType type; - const char* mod; - uint32_t freq; - union { - struct { - const char* name; - uint64_t key; - uint8_t bits; - uint16_t te; - } data; - struct { - uint32_t serial; - uint8_t btn; - uint8_t cnt; - uint32_t seed; - const char* manuf; - } faac_slh; - struct { - uint32_t serial; - uint8_t btn; - uint8_t cnt; - const char* manuf; - } keeloq; - struct { - uint32_t serial; - uint8_t cnt; - } came_atomo; - struct { - uint32_t serial; - uint8_t btn; - uint8_t cnt; - uint32_t seed; - const char* manuf; - } keeloq_bft; - struct { - uint32_t serial; - uint8_t btn; - uint8_t cnt; - } alutech_at_4n; - struct { - uint32_t serial; - uint8_t btn; - uint8_t cnt; - } somfy_telis; - struct { - uint32_t serial; - uint8_t btn; - uint8_t cnt; - bool nice_one; - } nice_flor_s; - struct { - uint32_t serial; - uint8_t btn; - uint32_t cnt; - } sec_plus_2; - struct { - uint32_t serial; - uint16_t cnt; - } phoenix_v2; - }; -} GenInfo; - -bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { - SubGhz* subghz = context; +bool subghz_scene_set_type_generate_protocol_from_infos(SubGhz* subghz) { + GenInfo gen_info = *subghz->gen_info; bool generated_protocol = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event >= SetTypeMAX) { - return false; - } - scene_manager_set_scene_state(subghz->scene_manager, SubGhzSceneSetType, event.event); - - if(event.event == SetTypeFaacSLH_Manual_868 || event.event == SetTypeFaacSLH_Manual_433 || - event.event == SetTypeBFTClone) { - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFix); - return true; - } - - if (event.event == SetTypeNiceFlorS_433_92 || event.event == SetTypeNiceOne_433_92) { - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetButton); - return true; - } - - uint64_t key = (uint64_t)rand(); - - uint64_t gangqi_key; - subghz_txrx_gen_serial_gangqi(&gangqi_key); - - uint64_t marantec_key; - subghz_txrx_gen_key_marantec(&marantec_key); - - GenInfo gen_info = {0}; - switch(event.event) { - case SetTypePricenton433: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_PRINCETON_NAME, - .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 - .data.bits = 24, - .data.te = 400}; - break; - case SetTypePricenton315: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 315000000, - .data.name = SUBGHZ_PROTOCOL_PRINCETON_NAME, - .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 - .data.bits = 24, - .data.te = 400}; - break; - case SetTypeNiceFlo12bit: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_NICE_FLO_NAME, - .data.key = (key & 0x00000FF0) | 0x1, // btn 0x1, 0x2, 0x4 - .data.bits = 12, - .data.te = 0}; - break; - case SetTypeNiceFlo24bit: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_NICE_FLO_NAME, - .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 - .data.bits = 24, - .data.te = 0}; - break; - case SetTypeCAME12bit: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_CAME_NAME, - .data.key = (key & 0x00000FF0) | 0x1, // btn 0x1, 0x2, 0x4 - .data.bits = 12, - .data.te = 0}; - break; - case SetTypeCAME24bit: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_CAME_NAME, - .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 - .data.bits = 24, - .data.te = 0}; - break; - case SetTypeCAME12bit868: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 868350000, - .data.name = SUBGHZ_PROTOCOL_CAME_NAME, - .data.key = (key & 0x00000FF0) | 0x1, // btn 0x1, 0x2, 0x4 - .data.bits = 12, - .data.te = 0}; - break; - case SetTypeCAME24bit868: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 868350000, - .data.name = SUBGHZ_PROTOCOL_CAME_NAME, - .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 - .data.bits = 24, - .data.te = 0}; - break; - case SetTypeRoger_433: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_ROGER_NAME, - .data.key = (key & 0xFFFF000) | 0x0000101, // button code 0x1 and (crc?) is 0x01 - .data.bits = 28, - .data.te = 0}; - break; - case SetTypeLinear_300_00: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 300000000, - .data.name = SUBGHZ_PROTOCOL_LINEAR_NAME, - .data.key = (key & 0x3FF), - .data.bits = 10, - .data.te = 0}; - break; - case SetTypeBETT_433: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_BETT_NAME, - .data.key = (key & 0x0000FFF0), - .data.bits = 18, - .data.te = 0}; - break; - case SetTypeCAMETwee: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_CAME_TWEE_NAME, - .data.key = 0x003FFF7200000000 | ((key & 0x0FFFFFF0) ^ 0xE0E0E0EE), // ???? - .data.bits = 54, - .data.te = 0}; - break; - case SetTypeGateTX: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_GATE_TX_NAME, // btn 0xF, 0xC, 0xA, 0x6 (?) - .data.key = subghz_protocol_blocks_reverse_key((key & 0x00F0FF00) | 0xF0040, 24), - .data.bits = 24, - .data.te = 0}; - break; - case SetTypeGangQi_433: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = - SUBGHZ_PROTOCOL_GANGQI_NAME, // Add button 0xD arm and crc sum to the end - .data.key = gangqi_key, - .data.bits = 34, - .data.te = 0}; - break; - case SetTypeHollarm_433: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_HOLLARM_NAME, // Add button 0x2 and crc sum to the end - .data.key = (key & 0x000FFF0000) | 0xF0B0002200 | - ((((((key & 0x000FFF0000) | 0xF0B0002200) >> 32) & 0xFF) + - ((((key & 0x000FFF0000) | 0xF0B0002200) >> 24) & 0xFF) + - ((((key & 0x000FFF0000) | 0xF0B0002200) >> 16) & 0xFF) + - ((((key & 0x000FFF0000) | 0xF0B0002200) >> 8) & 0xFF)) & - 0xFF), - .data.bits = 42, - .data.te = 0}; - break; - case SetTypeReversRB2_433: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_REVERSRB2_NAME, // 64bits no buttons - .data.key = (key & 0x00000FFFFFFFF000) | 0xFFFFF00000000000 | 0x0000000000000A00, - .data.bits = 64, - .data.te = 0}; - break; - case SetTypeMarantec24_868: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 868350000, - .data.name = SUBGHZ_PROTOCOL_MARANTEC24_NAME, // Add button code 0x8 to the end - .data.key = (key & 0xFFFFF0) | 0x000008, - .data.bits = 24, - .data.te = 0}; - break; - case SetTypeMarantec_433: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = - SUBGHZ_PROTOCOL_MARANTEC_NAME, // Button code is 0x4 and crc sum to the end - .data.key = marantec_key, - .data.bits = 49, - .data.te = 0}; - break; - case SetTypeMarantec_868: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 868350000, - .data.name = - SUBGHZ_PROTOCOL_MARANTEC_NAME, // Button code is 0x4 and crc sum to the end - .data.key = marantec_key, - .data.bits = 49, - .data.te = 0}; - break; - case SetTypeFaacSLH_433: - gen_info = (GenInfo){ - .type = GenFaacSLH, - .mod = "AM650", - .freq = 433920000, - .faac_slh.serial = ((key & 0x00FFFFF0) | 0xA0000006) >> 4, - .faac_slh.btn = 0x06, - .faac_slh.cnt = 0x02, - .faac_slh.seed = key, - .faac_slh.manuf = "FAAC_SLH"}; - break; - case SetTypeFaacSLH_868: - gen_info = (GenInfo){ - .type = GenFaacSLH, - .mod = "AM650", - .freq = 868350000, - .faac_slh.serial = ((key & 0x00FFFFF0) | 0xA0000006) >> 4, - .faac_slh.btn = 0x06, - .faac_slh.cnt = 0x02, - .faac_slh.seed = (key & 0x0FFFFFFF), - .faac_slh.manuf = "FAAC_SLH"}; - break; - case SetTypeBeninca433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x000FFF00) | 0x00800080, - .keeloq.btn = 0x01, - .keeloq.cnt = 0x05, - .keeloq.manuf = "Beninca"}; - break; - case SetTypeBeninca868: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 868350000, - .keeloq.serial = (key & 0x000FFF00) | 0x00800080, - .keeloq.btn = 0x01, - .keeloq.cnt = 0x05, - .keeloq.manuf = "Beninca"}; - break; - case SetTypeComunello433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x08, - .keeloq.cnt = 0x05, - .keeloq.manuf = "Comunello"}; - break; - case SetTypeComunello868: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 868460000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x08, - .keeloq.cnt = 0x05, - .keeloq.manuf = "Comunello"}; - break; - case SetTypeAllmatic433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x00FFFF00) | 0x01000011, - .keeloq.btn = 0x0C, - .keeloq.cnt = 0x05, - .keeloq.manuf = "Beninca"}; - break; - case SetTypeAllmatic868: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 868350000, - .keeloq.serial = (key & 0x00FFFF00) | 0x01000011, - .keeloq.btn = 0x0C, - .keeloq.cnt = 0x05, - .keeloq.manuf = "Beninca"}; - break; - case SetTypeCenturion433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x0000FFFF), - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Centurion"}; - break; - case SetTypeMonarch433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x0000FFFF), - .keeloq.btn = 0x0A, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Monarch"}; - break; - case SetTypeJollyMotors433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x000FFFFF), - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Jolly_Motors"}; - break; - case SetTypeElmesElectronic: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x00FFFFFF) | 0x02000000, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Elmes_Poland"}; - break; - case SetTypeANMotorsAT4: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x000FFFFF) | 0x04700000, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x21, - .keeloq.manuf = "AN-Motors"}; - break; - case SetTypeAprimatic: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x000FFFFF) | 0x00600000, - .keeloq.btn = 0x08, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Aprimatic"}; - break; - case SetTypeGibidi433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Gibidi"}; - break; - case SetTypeGSN: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x0FFFFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "GSN"}; - break; - case SetTypeIronLogic: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFF0, - .keeloq.btn = 0x04, - .keeloq.cnt = 0x05, - .keeloq.manuf = "IronLogic"}; - break; - case SetTypeStilmatic: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x0FFFFFFF, - .keeloq.btn = 0x01, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Stilmatic"}; - break; - case SetTypeSommer_FM_434: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "FM476", - .freq = 434420000, - .keeloq.serial = (key & 0x0000FFFF) | 0x01700000, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Sommer(fsk476)"}; - break; - case SetTypeSommer_FM_868: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "FM476", - .freq = 868800000, - .keeloq.serial = (key & 0x0000FFFF) | 0x01700000, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Sommer(fsk476)"}; - break; - case SetTypeSommer_FM238_434: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "FM238", - .freq = 434420000, - .keeloq.serial = key & 0x0000FFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Sommer(fsk476)"}; - break; - case SetTypeSommer_FM238_868: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "FM238", - .freq = 868800000, - .keeloq.serial = key & 0x0000FFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Sommer(fsk476)"}; - break; - case SetTypeDTMNeo433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x000FFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x05, - .keeloq.manuf = "DTM_Neo"}; - break; - case SetTypeCAMESpace: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x04, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Came_Space"}; - break; - case SetTypeCameAtomo433: - gen_info = (GenInfo){ - .type = GenCameAtomo, - .mod = "AM650", - .freq = 433920000, - .came_atomo.serial = (key & 0x0FFFFFFF) | 0x10000000, - .came_atomo.cnt = 0x03}; - break; - case SetTypeCameAtomo868: - gen_info = (GenInfo){ - .type = GenCameAtomo, - .mod = "AM650", - .freq = 868350000, - .came_atomo.serial = (key & 0x0FFFFFFF) | 0x10000000, - .came_atomo.cnt = 0x03}; - break; - case SetTypeBFTMitto: - gen_info = (GenInfo){ - .type = GenKeeloqBFT, - .mod = "AM650", - .freq = 433920000, - .keeloq_bft.serial = key & 0x000FFFFF, - .keeloq_bft.btn = 0x02, - .keeloq_bft.cnt = 0x02, - .keeloq_bft.seed = key & 0x000FFFFF, - .keeloq_bft.manuf = "BFT"}; - break; - case SetTypeAlutechAT4N: - gen_info = (GenInfo){ - .type = GenAlutechAt4n, - .mod = "AM650", - .freq = 433920000, - .alutech_at_4n.serial = (key & 0x000FFFFF) | 0x00100000, - .alutech_at_4n.btn = 0x44, - .alutech_at_4n.cnt = 0x03}; - break; - case SetTypeSomfyTelis: - gen_info = (GenInfo){ - .type = GenSomfyTelis, - .mod = "AM650", - .freq = 433420000, - .somfy_telis.serial = key & 0x00FFFFFF, - .somfy_telis.btn = 0x02, - .somfy_telis.cnt = 0x03}; - break; - case SetTypeMotorline433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x0FFFFFFF, - .keeloq.btn = 0x01, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Motorline"}; - break; - case SetTypeDoorHan_433_92: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x0FFFFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "DoorHan"}; - break; - case SetTypeDoorHan_315_00: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 315000000, - .keeloq.serial = key & 0x0FFFFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "DoorHan"}; - break; - case SetTypeNiceSmilo_433_92: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "NICE_Smilo"}; - break; - case SetTypeNiceMHouse_433_92: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x09, - .keeloq.cnt = 0x03, - .keeloq.manuf = "NICE_MHOUSE"}; - break; - case SetTypeDeaMio433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x0FFFF000) | 0x00000869, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Dea_Mio"}; - break; - case SetTypeGeniusBravo433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x06, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Genius_Bravo"}; - break; - case SetTypeJCM_433_92: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "JCM_Tech"}; - break; - case SetTypeNovoferm_433_92: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x0000FFFF) | 0x018F0000, - .keeloq.btn = 0x01, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Novoferm"}; - break; - case SetTypeHormannEcoStar_433_92: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x000FFFFF) | 0x02200000, - .keeloq.btn = 0x04, - .keeloq.cnt = 0x03, - .keeloq.manuf = "EcoStar"}; - break; - case SetTypeFAACRCXT_433_92: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x0000FFFF) | 0x00100000, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "FAAC_RC,XT"}; - break; - case SetTypeFAACRCXT_868: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 868350000, - .keeloq.serial = (key & 0x0000FFFF) | 0x00100000, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "FAAC_RC,XT"}; - break; - case SetTypeNormstahl_433_92: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x0000FFFF, - .keeloq.btn = 0x04, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Normstahl"}; - break; - case SetTypeHCS101_433_92: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x000FFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "HCS101"}; - break; - case SetTypeSecPlus_v1_315_00: - gen_info = (GenInfo){.type = GenSecPlus1, .mod = "AM650", .freq = 315000000}; - break; - case SetTypeSecPlus_v1_390_00: - gen_info = (GenInfo){.type = GenSecPlus1, .mod = "AM650", .freq = 390000000}; - break; - case SetTypeSecPlus_v1_433_00: - gen_info = (GenInfo){.type = GenSecPlus1, .mod = "AM650", .freq = 433920000}; - break; - case SetTypeSecPlus_v2_310_00: - gen_info = (GenInfo){ - .type = GenSecPlus2, - .mod = "AM650", - .freq = 310000000, - .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing - .sec_plus_2.btn = 0x68, - .sec_plus_2.cnt = 0xE500000}; - break; - case SetTypeSecPlus_v2_315_00: - gen_info = (GenInfo){ - .type = GenSecPlus2, - .mod = "AM650", - .freq = 315000000, - .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing - .sec_plus_2.btn = 0x68, - .sec_plus_2.cnt = 0xE500000}; - break; - case SetTypeSecPlus_v2_390_00: - gen_info = (GenInfo){ - .type = GenSecPlus2, - .mod = "AM650", - .freq = 390000000, - .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing - .sec_plus_2.btn = 0x68, - .sec_plus_2.cnt = 0xE500000}; - break; - case SetTypeSecPlus_v2_433_00: - gen_info = (GenInfo){ - .type = GenSecPlus2, - .mod = "AM650", - .freq = 433920000, - .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing - .sec_plus_2.btn = 0x68, - .sec_plus_2.cnt = 0xE500000}; - break; - case SetTypePhoenix_V2_433: - gen_info = (GenInfo){ - .type = GenPhoenixV2, - .mod = "AM650", - .freq = 433920000, - .phoenix_v2.serial = (key & 0x0FFFFFFF) | 0xB0000000, - .phoenix_v2.cnt = 0x025D}; - break; - default: - furi_crash("Not implemented"); - break; - } - - switch(gen_info.type) { + switch(gen_info.type) { case GenData: if(gen_info.data.te) { generated_protocol = subghz_txrx_gen_data_protocol_and_te( @@ -973,6 +184,16 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { gen_info.somfy_telis.btn, gen_info.somfy_telis.cnt); break; + case GenNiceFlorS: + generated_protocol = subghz_txrx_gen_nice_flor_s_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.nice_flor_s.serial, + gen_info.nice_flor_s.btn, + gen_info.nice_flor_s.cnt, + gen_info.nice_flor_s.nice_one); + break; case GenSecPlus1: generated_protocol = subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, gen_info.mod, gen_info.freq); @@ -997,15 +218,54 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { default: furi_crash("Not implemented"); break; - } + } - if(generated_protocol) { - subghz_file_name_clear(subghz); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); - } else { - furi_string_set( - subghz->error_str, "Function requires\nan SD card with\nfresh databases."); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + if(generated_protocol) { + subghz_file_name_clear(subghz); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); + } else { + furi_string_set( + subghz->error_str, "Function requires\nan SD card with\nfresh databases."); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + } + return generated_protocol; +} + +bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + bool generated_protocol = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event >= SetTypeMAX) { + return false; + } + scene_manager_set_scene_state(subghz->scene_manager, SubGhzSceneSetType, event.event); + + subghz_gen_info_reset(subghz->gen_info); + subghz_scene_set_type_fill_generation_infos(subghz->gen_info, event.event); + + if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneStart) == SubmenuIndexAddManually) { + generated_protocol = subghz_scene_set_type_generate_protocol_from_infos(subghz); + } else if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneStart) == SubmenuIndexAddManuallyAdvanced) { + switch(subghz->gen_info->type) { + case GenData: // Key (u64) + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetKey); + break; + case GenSecPlus1: // None + return subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, subghz->gen_info->mod, subghz->gen_info->freq); + case GenFaacSLH: // Serial (u32), Button (u8), Counter (u8), Seed (u32) + case GenKeeloq: // Serial (u32), Button (u8), Counter (u8) + case GenCameAtomo: // Serial (u32), Counter (u8) + case GenKeeloqBFT: // Serial (u32), Button (u8), Counter (u8), Seed (u32) + case GenAlutechAt4n: // Serial (u32), Button (u8), Counter (u8) + case GenSomfyTelis: // Serial (u32), Button (u8), Counter (u8) + case GenNiceFlorS: // Serial (u32), Button (u8), Counter (u8) + case GenSecPlus2: // Serial (u32), Button (u8), Counter (u32) + case GenPhoenixV2: // Serial (u32), Counter (u16) + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetSerial); + break; + } + return true; } } diff --git a/applications/main/subghz/scenes/subghz_scene_start.c b/applications/main/subghz/scenes/subghz_scene_start.c index fd59f48a4..6046b2c6d 100644 --- a/applications/main/subghz/scenes/subghz_scene_start.c +++ b/applications/main/subghz/scenes/subghz_scene_start.c @@ -1,18 +1,9 @@ #include "../subghz_i.h" +#include "subghz_scene_start.h" #include #include -enum SubmenuIndex { - SubmenuIndexRead = 10, - SubmenuIndexSaved, - SubmenuIndexAddManually, - SubmenuIndexFrequencyAnalyzer, - SubmenuIndexReadRAW, - SubmenuIndexExtSettings, - SubmenuIndexRadioSetting, -}; - void subghz_scene_start_submenu_callback(void* context, uint32_t index) { SubGhz* subghz = context; view_dispatcher_send_custom_event(subghz->view_dispatcher, index); @@ -43,7 +34,7 @@ void subghz_scene_start_on_enter(void* context) { submenu_add_item( subghz->submenu, "Add Manually [Advanced]", - SubmenuIndexAddManually, + SubmenuIndexAddManuallyAdvanced, subghz_scene_start_submenu_callback, subghz); submenu_add_item( @@ -94,6 +85,11 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { subghz->scene_manager, SubGhzSceneStart, SubmenuIndexAddManually); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetType); return true; + } else if(event.event == SubmenuIndexAddManuallyAdvanced) { + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneStart, SubmenuIndexAddManuallyAdvanced); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetType); + return true; } else if(event.event == SubmenuIndexFrequencyAnalyzer) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneStart, SubmenuIndexFrequencyAnalyzer); diff --git a/applications/main/subghz/scenes/subghz_scene_start.h b/applications/main/subghz/scenes/subghz_scene_start.h new file mode 100644 index 000000000..8e446f0c0 --- /dev/null +++ b/applications/main/subghz/scenes/subghz_scene_start.h @@ -0,0 +1,12 @@ +#pragma once + +enum SubmenuIndex { + SubmenuIndexRead = 10, + SubmenuIndexSaved, + SubmenuIndexAddManually, + SubmenuIndexAddManuallyAdvanced, + SubmenuIndexFrequencyAnalyzer, + SubmenuIndexReadRAW, + SubmenuIndexExtSettings, + SubmenuIndexRadioSetting, +}; diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 83e68229b..f8877551d 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -213,7 +213,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE); - subghz->secure_data = malloc(sizeof(SecureData)); + subghz->gen_info = malloc(sizeof(GenInfo)); if(!alloc_for_tx_only) { subghz->ignore_filter = subghz->last_settings->ignore_filter; @@ -319,7 +319,7 @@ void subghz_free(SubGhz* subghz, bool alloc_for_tx_only) { subghz_history_free(subghz->history); } - free(subghz->secure_data); + free(subghz->gen_info); //TxRx subghz_txrx_free(subghz->txrx); diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index 6160c48c3..10a2ce9f8 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -1,6 +1,7 @@ #pragma once #include "helpers/subghz_types.h" +#include "helpers/subghz_gen_info.h" #include #include "subghz.h" #include "views/receiver.h" @@ -44,13 +45,6 @@ #define SUBGHZ_RAW_THRESHOLD_MIN (-90.0f) #define SUBGHZ_MEASURE_LOADING false -typedef struct { - uint8_t fix[4]; - uint8_t cnt[4]; - uint8_t seed[4]; - uint8_t btn; -} SecureData; - struct SubGhz { Gui* gui; NotificationApp* notifications; @@ -89,7 +83,7 @@ struct SubGhz { FuriString* error_str; SubGhzLock lock; - SecureData* secure_data; + GenInfo* gen_info; SubGhzFileEncoderWorker* decode_raw_file_worker_encoder; From 6a2f0622346d384465d19c7ff423aac227b66814 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 30 Jul 2025 03:43:36 +0300 Subject: [PATCH 05/31] OFW PR. 4251 CLI: Fix long delay with quick connect/disconnect by WillyJL --- applications/services/cli/cli_vcp.c | 13 +++++-------- lib/toolbox/cli/shell/cli_shell.c | 16 +++++++++++----- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/applications/services/cli/cli_vcp.c b/applications/services/cli/cli_vcp.c index 1f9c77b08..9db1bec43 100644 --- a/applications/services/cli/cli_vcp.c +++ b/applications/services/cli/cli_vcp.c @@ -218,6 +218,11 @@ static void cli_vcp_internal_event_happened(FuriEventLoopObject* object, void* c pipe_detach_from_event_loop(cli_vcp->own_pipe); pipe_free(cli_vcp->own_pipe); cli_vcp->own_pipe = NULL; + + // wait for shell to stop + cli_shell_join(cli_vcp->shell); + cli_shell_free(cli_vcp->shell); + pipe_free(cli_vcp->shell_pipe); break; } @@ -226,14 +231,6 @@ static void cli_vcp_internal_event_happened(FuriEventLoopObject* object, void* c FURI_LOG_D(TAG, "Connected"); cli_vcp->is_connected = true; - // wait for previous shell to stop - furi_check(!cli_vcp->own_pipe); - if(cli_vcp->shell) { - cli_shell_join(cli_vcp->shell); - cli_shell_free(cli_vcp->shell); - pipe_free(cli_vcp->shell_pipe); - } - // start shell thread PipeSideBundle bundle = pipe_alloc(VCP_BUF_SIZE, 1); cli_vcp->own_pipe = bundle.alices_side; diff --git a/lib/toolbox/cli/shell/cli_shell.c b/lib/toolbox/cli/shell/cli_shell.c index 7a4c7ec1f..b2648d127 100644 --- a/lib/toolbox/cli/shell/cli_shell.c +++ b/lib/toolbox/cli/shell/cli_shell.c @@ -16,7 +16,8 @@ #define TAG "CliShell" -#define ANSI_TIMEOUT_MS 10 +#define ANSI_TIMEOUT_MS 10 +#define TRANSIENT_SESSION_WINDOW_MS 100 typedef enum { CliShellComponentCompletions, @@ -415,10 +416,15 @@ static void cli_shell_deinit(CliShell* shell) { static int32_t cli_shell_thread(void* context) { CliShell* shell = context; - // Sometimes, the other side closes the pipe even before our thread is started. Although the - // rest of the code will eventually find this out if this check is removed, there's no point in - // wasting time. - if(pipe_state(shell->pipe) == PipeStateBroken) return 0; + // Sometimes, the other side (e.g. qFlipper) closes the pipe even before our thread is started. + // Although the rest of the code will eventually find this out if this check is removed, + // there's no point in wasting time. This gives qFlipper a chance to quickly close and re-open + // the session. + const size_t delay_step = 10; + for(size_t i = 0; i < TRANSIENT_SESSION_WINDOW_MS / delay_step; i++) { + furi_delay_ms(delay_step); + if(pipe_state(shell->pipe) == PipeStateBroken) return 0; + } cli_shell_init(shell); FURI_LOG_D(TAG, "Started"); From fb41c6c20c4e79838557e88bd542ad09515d6ab7 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 30 Jul 2025 04:28:22 +0300 Subject: [PATCH 06/31] Input Settings: Add Vibro Trigger option by 956MB & WillyJL --- applications/services/input/input.c | 5 +- applications/services/input/input_settings.c | 21 ++++++++- applications/services/input/input_settings.h | 1 + .../input_settings_app/input_settings_app.c | 46 +++++++++++++++++-- 4 files changed, 66 insertions(+), 7 deletions(-) diff --git a/applications/services/input/input.c b/applications/services/input/input.c index c3f7c264f..a054f852a 100644 --- a/applications/services/input/input.c +++ b/applications/services/input/input.c @@ -162,13 +162,14 @@ int32_t input_srv(void* p) { event.type = pin_states[i].state ? InputTypePress : InputTypeRelease; furi_pubsub_publish(event_pubsub, &event); // vibro signal if user setup vibro touch level in Settings-Input. - if(settings->vibro_touch_level) { + if(settings->vibro_touch_level && + ((1 << event.type) & settings->vibro_touch_trigger_mask)) { //delay 1 ticks for compatibility with rgb_backlight_mod furi_delay_tick(1); furi_hal_vibro_on(true); furi_delay_tick(settings->vibro_touch_level); furi_hal_vibro_on(false); - }; + } } } diff --git a/applications/services/input/input_settings.c b/applications/services/input/input_settings.c index f1f18ba3d..1b63b62c8 100644 --- a/applications/services/input/input_settings.c +++ b/applications/services/input/input_settings.c @@ -1,16 +1,20 @@ #include "input_settings.h" #include "input_settings_filename.h" +#include "input.h" #include #include #define TAG "InputSettings" -#define INPUT_SETTINGS_VER (1) // version nnumber +#define INPUT_SETTINGS_VER (2) // version number #define INPUT_SETTINGS_PATH INT_PATH(INPUT_SETTINGS_FILE_NAME) #define INPUT_SETTINGS_MAGIC (0x29) +#define INPUT_SETTINGS_VIBRO_TOUCH_TRIGGER_MASK_DEFAULT \ + ((1 << InputTypePress) | (1 << InputTypeRelease)) + void input_settings_load(InputSettings* settings) { furi_assert(settings); @@ -22,6 +26,18 @@ void input_settings_load(InputSettings* settings) { uint8_t version; if(!saved_struct_get_metadata(INPUT_SETTINGS_PATH, NULL, &version, NULL)) break; + if(version == 1) { + struct { + uint8_t vibro_touch_level; + } v1; + if(!saved_struct_load(INPUT_SETTINGS_PATH, &v1, sizeof(v1), INPUT_SETTINGS_MAGIC, 1)) + break; + settings->vibro_touch_level = v1.vibro_touch_level; + settings->vibro_touch_trigger_mask = INPUT_SETTINGS_VIBRO_TOUCH_TRIGGER_MASK_DEFAULT; + success = true; + break; + } + // if config actual version - load it directly if(version == INPUT_SETTINGS_VER) { success = saved_struct_load( @@ -38,7 +54,8 @@ void input_settings_load(InputSettings* settings) { if(!success) { FURI_LOG_W(TAG, "Failed to load file, using defaults"); memset(settings, 0, sizeof(InputSettings)); - input_settings_save(settings); + settings->vibro_touch_trigger_mask = INPUT_SETTINGS_VIBRO_TOUCH_TRIGGER_MASK_DEFAULT; + // input_settings_save(settings); } } diff --git a/applications/services/input/input_settings.h b/applications/services/input/input_settings.h index 376e8e226..87ebca5ea 100644 --- a/applications/services/input/input_settings.h +++ b/applications/services/input/input_settings.h @@ -4,6 +4,7 @@ typedef struct { uint8_t vibro_touch_level; + uint8_t vibro_touch_trigger_mask; } InputSettings; #ifdef __cplusplus diff --git a/applications/settings/input_settings_app/input_settings_app.c b/applications/settings/input_settings_app/input_settings_app.c index 4f3e101da..035a84e79 100644 --- a/applications/settings/input_settings_app/input_settings_app.c +++ b/applications/settings/input_settings_app/input_settings_app.c @@ -3,7 +3,9 @@ #define TAG "InputSettingsApp" -#define VIBRO_TOUCH_LEVEL_COUNT 10 +#define VIBRO_TOUCH_LEVEL_COUNT 10 +#define VIBRO_TOUCH_TRIGGER_MASK_COUNT 3 + // vibro touch human readable levels const char* const vibro_touch_level_text[VIBRO_TOUCH_LEVEL_COUNT] = { "OFF", @@ -20,21 +22,45 @@ const char* const vibro_touch_level_text[VIBRO_TOUCH_LEVEL_COUNT] = { // vibro touch levels tick valies delay const uint32_t vibro_touch_level_value[VIBRO_TOUCH_LEVEL_COUNT] = {0, 13, 16, 19, 21, 24, 27, 30, 33, 36}; +// vibro touch trigger mask human readable values +const char* const vibro_touch_trigger_mask_text[VIBRO_TOUCH_TRIGGER_MASK_COUNT] = { + "Press", + "Release", + "Both", +}; +// vibro touch trigger mask values +const uint32_t vibro_touch_trigger_mask_value[VIBRO_TOUCH_TRIGGER_MASK_COUNT] = { + (1 << InputTypePress), + (1 << InputTypeRelease), + (1 << InputTypePress) | (1 << InputTypeRelease), +}; static void input_settings_vibro_touch_level_changed(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, vibro_touch_level_text[index]); - //change settings to selected InputSettingsApp* app = variable_item_get_context(item); app->settings->vibro_touch_level = vibro_touch_level_value[index]; - // use RECORD for acces to input service instance and set settings + // use RECORD for access to input service instance and set settings InputSettings* service_settings = furi_record_open(RECORD_INPUT_SETTINGS); service_settings->vibro_touch_level = vibro_touch_level_value[index]; furi_record_close(RECORD_INPUT_SETTINGS); } +static void input_settings_vibro_touch_trigger_mask_changed(VariableItem* item) { + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, vibro_touch_trigger_mask_text[index]); + + InputSettingsApp* app = variable_item_get_context(item); + app->settings->vibro_touch_trigger_mask = vibro_touch_trigger_mask_value[index]; + + // use RECORD for access to input service instance and set settings + InputSettings* service_settings = furi_record_open(RECORD_INPUT_SETTINGS); + service_settings->vibro_touch_trigger_mask = vibro_touch_trigger_mask_value[index]; + furi_record_close(RECORD_INPUT_SETTINGS); +} + static uint32_t input_settings_app_exit(void* context) { UNUSED(context); return VIEW_NONE; @@ -66,6 +92,20 @@ InputSettingsApp* input_settings_app_alloc(void) { variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, vibro_touch_level_text[value_index]); + item = variable_item_list_add( + app->variable_item_list, + "Vibro Trigger", + VIBRO_TOUCH_TRIGGER_MASK_COUNT, + input_settings_vibro_touch_trigger_mask_changed, + app); + + value_index = value_index_uint32( + app->settings->vibro_touch_trigger_mask, + vibro_touch_trigger_mask_value, + VIBRO_TOUCH_TRIGGER_MASK_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, vibro_touch_trigger_mask_text[value_index]); + // create and setup view and view dispatcher app->view_dispatcher = view_dispatcher_alloc(); view_dispatcher_set_event_callback_context(app->view_dispatcher, app); From 3b7d837e48d6e01cb14f791f6b5234de935bb85e Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 30 Jul 2025 04:30:01 +0300 Subject: [PATCH 07/31] fmt --- applications/services/input/input_settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/services/input/input_settings.c b/applications/services/input/input_settings.c index 1b63b62c8..67f5ac608 100644 --- a/applications/services/input/input_settings.c +++ b/applications/services/input/input_settings.c @@ -55,7 +55,7 @@ void input_settings_load(InputSettings* settings) { FURI_LOG_W(TAG, "Failed to load file, using defaults"); memset(settings, 0, sizeof(InputSettings)); settings->vibro_touch_trigger_mask = INPUT_SETTINGS_VIBRO_TOUCH_TRIGGER_MASK_DEFAULT; - // input_settings_save(settings); + //input_settings_save(settings); } } From 59a823cbcd14a65027a5efc767790c2ac14190b1 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 30 Jul 2025 04:32:54 +0300 Subject: [PATCH 08/31] BT Remote: Add Rename Option by aaronjamt & WillyJL --- .../hid_app/helpers/ble_hid_ext_profile.c | 36 ++++++++ .../hid_app/helpers/ble_hid_ext_profile.h | 14 ++++ applications/system/hid_app/hid.c | 70 +++++++++++++++- applications/system/hid_app/hid.h | 6 +- .../system/hid_app/scenes/hid_scene_config.h | 1 + .../system/hid_app/scenes/hid_scene_rename.c | 82 +++++++++++++++++++ .../system/hid_app/scenes/hid_scene_start.c | 9 ++ applications/system/hid_app/views.h | 1 + .../system/hid_app/views/hid_music_macos.h | 3 +- applications/system/hid_app/views/hid_ptt.c | 58 ++++++++++++- 10 files changed, 274 insertions(+), 6 deletions(-) create mode 100644 applications/system/hid_app/helpers/ble_hid_ext_profile.c create mode 100644 applications/system/hid_app/helpers/ble_hid_ext_profile.h create mode 100644 applications/system/hid_app/scenes/hid_scene_rename.c diff --git a/applications/system/hid_app/helpers/ble_hid_ext_profile.c b/applications/system/hid_app/helpers/ble_hid_ext_profile.c new file mode 100644 index 000000000..f1858318e --- /dev/null +++ b/applications/system/hid_app/helpers/ble_hid_ext_profile.c @@ -0,0 +1,36 @@ +#include "ble_hid_ext_profile.h" + +#include + +static FuriHalBleProfileBase* ble_profile_hid_ext_start(FuriHalBleProfileParams profile_params) { + UNUSED(profile_params); + + return ble_profile_hid->start(NULL); +} + +static void ble_profile_hid_ext_stop(FuriHalBleProfileBase* profile) { + ble_profile_hid->stop(profile); +} + +static void + ble_profile_hid_ext_get_config(GapConfig* config, FuriHalBleProfileParams profile_params) { + furi_check(config); + furi_check(profile_params); + BleProfileHidExtParams* hid_ext_profile_params = profile_params; + + // Setup config with basic profile + ble_profile_hid->get_gap_config(config, NULL); + + if(hid_ext_profile_params->name[0] != '\0') { + // Set advertise name (skip first byte which is the ADV type) + strlcpy(config->adv_name + 1, hid_ext_profile_params->name, sizeof(config->adv_name) - 1); + } +} + +static const FuriHalBleProfileTemplate profile_callbacks = { + .start = ble_profile_hid_ext_start, + .stop = ble_profile_hid_ext_stop, + .get_gap_config = ble_profile_hid_ext_get_config, +}; + +const FuriHalBleProfileTemplate* ble_profile_hid_ext = &profile_callbacks; diff --git a/applications/system/hid_app/helpers/ble_hid_ext_profile.h b/applications/system/hid_app/helpers/ble_hid_ext_profile.h new file mode 100644 index 000000000..fc0bdbb89 --- /dev/null +++ b/applications/system/hid_app/helpers/ble_hid_ext_profile.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +/** + * Optional arguments to pass along with profile template as + * FuriHalBleProfileParams for tuning profile behavior + **/ +typedef struct { + char name[FURI_HAL_BT_ADV_NAME_LENGTH]; /**< Full device name */ +} BleProfileHidExtParams; + +/** Hid Keyboard Profile descriptor */ +extern const FuriHalBleProfileTemplate* ble_profile_hid_ext; diff --git a/applications/system/hid_app/hid.c b/applications/system/hid_app/hid.c index e297e0738..00c4ee666 100644 --- a/applications/system/hid_app/hid.c +++ b/applications/system/hid_app/hid.c @@ -4,9 +4,14 @@ #include "views.h" #include #include +#include #define TAG "HidApp" +#define HID_BT_CFG_PATH APP_DATA_PATH(".bt_hid.cfg") +#define HID_BT_CFG_FILE_TYPE "Flipper BT Remote Settings File" +#define HID_BT_CFG_VERSION 1 + bool hid_custom_event_callback(void* context, uint32_t event) { furi_assert(context); Hid* app = context; @@ -33,6 +38,60 @@ void bt_hid_remove_pairing(Hid* app) { furi_hal_bt_start_advertising(); } +static void bt_hid_load_cfg(Hid* app) { + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* fff = flipper_format_file_alloc(storage); + bool loaded = false; + + FuriString* temp_str = furi_string_alloc(); + uint32_t temp_uint = 0; + + do { + if(!flipper_format_file_open_existing(fff, HID_BT_CFG_PATH)) break; + + if(!flipper_format_read_header(fff, temp_str, &temp_uint)) break; + if((strcmp(furi_string_get_cstr(temp_str), HID_BT_CFG_FILE_TYPE) != 0) || + (temp_uint != HID_BT_CFG_VERSION)) + break; + + if(flipper_format_read_string(fff, "name", temp_str)) { + strlcpy( + app->ble_hid_cfg.name, + furi_string_get_cstr(temp_str), + sizeof(app->ble_hid_cfg.name)); + } else { + flipper_format_rewind(fff); + } + + loaded = true; + } while(0); + + furi_string_free(temp_str); + + flipper_format_free(fff); + furi_record_close(RECORD_STORAGE); + + if(!loaded) { + app->ble_hid_cfg.name[0] = '\0'; + } +} + +void bt_hid_save_cfg(Hid* app) { + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* fff = flipper_format_file_alloc(storage); + + if(flipper_format_file_open_always(fff, HID_BT_CFG_PATH)) { + do { + if(!flipper_format_write_header_cstr(fff, HID_BT_CFG_FILE_TYPE, HID_BT_CFG_VERSION)) + break; + if(!flipper_format_write_string_cstr(fff, "name", app->ble_hid_cfg.name)) break; + } while(0); + } + + flipper_format_free(fff); + furi_record_close(RECORD_STORAGE); +} + static void bt_hid_connection_status_changed_callback(BtStatus status, void* context) { furi_assert(context); Hid* hid = context; @@ -89,6 +148,11 @@ Hid* hid_alloc() { app->dialog = dialog_ex_alloc(); view_dispatcher_add_view(app->view_dispatcher, HidViewDialog, dialog_ex_get_view(app->dialog)); + // Text input + app->text_input = text_input_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, HidViewTextInput, text_input_get_view(app->text_input)); + // Popup view app->popup = popup_alloc(); view_dispatcher_add_view(app->view_dispatcher, HidViewPopup, popup_get_view(app->popup)); @@ -177,6 +241,8 @@ void hid_free(Hid* app) { submenu_free(app->submenu); view_dispatcher_remove_view(app->view_dispatcher, HidViewDialog); dialog_ex_free(app->dialog); + view_dispatcher_remove_view(app->view_dispatcher, HidViewTextInput); + text_input_free(app->text_input); view_dispatcher_remove_view(app->view_dispatcher, HidViewPopup); popup_free(app->popup); view_dispatcher_remove_view(app->view_dispatcher, HidViewKeynote); @@ -266,7 +332,9 @@ int32_t hid_ble_app(void* p) { furi_record_close(RECORD_STORAGE); - app->ble_hid_profile = bt_profile_start(app->bt, ble_profile_hid, NULL); + bt_hid_load_cfg(app); + + app->ble_hid_profile = bt_profile_start(app->bt, ble_profile_hid_ext, &app->ble_hid_cfg); furi_check(app->ble_hid_profile); diff --git a/applications/system/hid_app/hid.h b/applications/system/hid_app/hid.h index ac565217a..e314c005c 100644 --- a/applications/system/hid_app/hid.h +++ b/applications/system/hid_app/hid.h @@ -5,7 +5,7 @@ #include #include -#include +#include "helpers/ble_hid_ext_profile.h" #include #include @@ -18,6 +18,7 @@ #include #include #include +#include #include "views/hid_keynote.h" #include "views/hid_keyboard.h" #include "views/hid_numpad.h" @@ -40,6 +41,7 @@ typedef struct Hid Hid; struct Hid { FuriHalBleProfileBase* ble_hid_profile; + BleProfileHidExtParams ble_hid_cfg; Bt* bt; Gui* gui; NotificationApp* notifications; @@ -47,6 +49,7 @@ struct Hid { SceneManager* scene_manager; Submenu* submenu; DialogEx* dialog; + TextInput* text_input; Popup* popup; HidKeynote* hid_keynote; HidKeyboard* hid_keyboard; @@ -64,6 +67,7 @@ struct Hid { }; void bt_hid_remove_pairing(Hid* app); +void bt_hid_save_cfg(Hid* app); void hid_hal_keyboard_press(Hid* instance, uint16_t event); void hid_hal_keyboard_release(Hid* instance, uint16_t event); diff --git a/applications/system/hid_app/scenes/hid_scene_config.h b/applications/system/hid_app/scenes/hid_scene_config.h index d18b15558..2064c65b1 100644 --- a/applications/system/hid_app/scenes/hid_scene_config.h +++ b/applications/system/hid_app/scenes/hid_scene_config.h @@ -1,3 +1,4 @@ ADD_SCENE(hid, start, Start) ADD_SCENE(hid, main, Main) ADD_SCENE(hid, unpair, Unpair) +ADD_SCENE(hid, rename, Rename) diff --git a/applications/system/hid_app/scenes/hid_scene_rename.c b/applications/system/hid_app/scenes/hid_scene_rename.c new file mode 100644 index 000000000..983c7d927 --- /dev/null +++ b/applications/system/hid_app/scenes/hid_scene_rename.c @@ -0,0 +1,82 @@ +#include "../hid.h" +#include "../views.h" +#include "hid_icons.h" + +enum HidSceneRenameEvent { + HidSceneRenameEventTextInput, + HidSceneRenameEventPopup, +}; + +static void hid_scene_rename_text_input_callback(void* context) { + Hid* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, HidSceneRenameEventTextInput); +} + +void hid_scene_rename_popup_callback(void* context) { + Hid* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, HidSceneRenameEventPopup); +} + +void hid_scene_rename_on_enter(void* context) { + Hid* app = context; + + // Rename text input view + text_input_reset(app->text_input); + text_input_set_result_callback( + app->text_input, + hid_scene_rename_text_input_callback, + app, + app->ble_hid_cfg.name, + sizeof(app->ble_hid_cfg.name), + true); + text_input_set_header_text(app->text_input, "Bluetooth Name"); + + // Rename success popup view + popup_set_icon(app->popup, 48, 6, &I_DolphinDone_80x58); + popup_set_header(app->popup, "Done", 14, 15, AlignLeft, AlignTop); + popup_set_timeout(app->popup, 1500); + popup_set_context(app->popup, app); + popup_set_callback(app->popup, hid_scene_rename_popup_callback); + popup_enable_timeout(app->popup); + + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewTextInput); +} + +bool hid_scene_rename_on_event(void* context, SceneManagerEvent event) { + Hid* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == HidSceneRenameEventTextInput) { +#ifdef HID_TRANSPORT_BLE + furi_hal_bt_stop_advertising(); + + app->ble_hid_profile = + bt_profile_start(app->bt, ble_profile_hid_ext, &app->ble_hid_cfg); + furi_check(app->ble_hid_profile); + + furi_hal_bt_start_advertising(); +#endif + + bt_hid_save_cfg(app); + + // Show popup + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewPopup); + + } else if(event.event == HidSceneRenameEventPopup) { + scene_manager_previous_scene(app->scene_manager); + } + } + + return consumed; +} + +void hid_scene_rename_on_exit(void* context) { + Hid* app = context; + + text_input_reset(app->text_input); + popup_reset(app->popup); +} diff --git a/applications/system/hid_app/scenes/hid_scene_start.c b/applications/system/hid_app/scenes/hid_scene_start.c index 61d340eec..167b967e6 100644 --- a/applications/system/hid_app/scenes/hid_scene_start.c +++ b/applications/system/hid_app/scenes/hid_scene_start.c @@ -15,6 +15,7 @@ enum HidSubmenuIndex { HidSubmenuIndexMouseJiggler, HidSubmenuIndexMouseJigglerStealth, HidSubmenuIndexPushToTalk, + HidSubmenuIndexRename, HidSubmenuIndexRemovePairing, }; @@ -81,6 +82,12 @@ void hid_scene_start_on_enter(void* context) { hid_scene_start_submenu_callback, app); #ifdef HID_TRANSPORT_BLE + submenu_add_item( + app->submenu, + "Bluetooth Remote Name", + HidSubmenuIndexRename, + hid_scene_start_submenu_callback, + app); submenu_add_item( app->submenu, "Bluetooth Unpairing", @@ -101,6 +108,8 @@ bool hid_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == HidSubmenuIndexRemovePairing) { scene_manager_next_scene(app->scene_manager, HidSceneUnpair); + } else if(event.event == HidSubmenuIndexRename) { + scene_manager_next_scene(app->scene_manager, HidSceneRename); } else { HidView view_id; diff --git a/applications/system/hid_app/views.h b/applications/system/hid_app/views.h index 606a48daf..e27d3ecf0 100644 --- a/applications/system/hid_app/views.h +++ b/applications/system/hid_app/views.h @@ -16,4 +16,5 @@ typedef enum { HidViewPushToTalkHelp, HidViewDialog, HidViewPopup, + HidViewTextInput, } HidView; diff --git a/applications/system/hid_app/views/hid_music_macos.h b/applications/system/hid_app/views/hid_music_macos.h index 9deac32eb..f185276f3 100644 --- a/applications/system/hid_app/views/hid_music_macos.h +++ b/applications/system/hid_app/views/hid_music_macos.h @@ -2,9 +2,10 @@ #include +typedef struct Hid Hid; typedef struct HidMusicMacos HidMusicMacos; -HidMusicMacos* hid_music_macos_alloc(); +HidMusicMacos* hid_music_macos_alloc(Hid* hid); void hid_music_macos_free(HidMusicMacos* hid_music_macos); diff --git a/applications/system/hid_app/views/hid_ptt.c b/applications/system/hid_app/views/hid_ptt.c index 59643abac..58599eb51 100644 --- a/applications/system/hid_app/views/hid_ptt.c +++ b/applications/system/hid_app/views/hid_ptt.c @@ -42,6 +42,7 @@ typedef struct { enum HidPushToTalkAppIndex { HidPushToTalkAppIndexDiscord, HidPushToTalkAppIndexFaceTime, + HidPushToTalkAppIndexGather, HidPushToTalkAppIndexGoogleMeet, HidPushToTalkAppIndexGoogleHangouts, HidPushToTalkAppIndexJamulus, @@ -308,7 +309,6 @@ static void hid_ptt_trigger_mute_jamulus(HidPushToTalk* hid_ptt) { } // webex - static void hid_ptt_trigger_camera_webex(HidPushToTalk* hid_ptt) { hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_V); hid_hal_keyboard_release( @@ -325,6 +325,30 @@ static void hid_ptt_trigger_hand_linux_webex(HidPushToTalk* hid_ptt) { hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_RIGHT_SHIFT | HID_KEYBOARD_R); } +// Gather +static void hid_ptt_trigger_hand_gather(HidPushToTalk* hid_ptt) { + hid_hal_keyboard_press(hid_ptt->hid, HID_KEYBOARD_H); + hid_hal_keyboard_release(hid_ptt->hid, HID_KEYBOARD_H); +} +static void hid_ptt_trigger_camera_macos_gather(HidPushToTalk* hid_ptt) { + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_V); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_V); +} +static void hid_ptt_trigger_mute_macos_gather(HidPushToTalk* hid_ptt) { + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_A); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_A); +} +static void hid_ptt_trigger_camera_linux_gather(HidPushToTalk* hid_ptt) { + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_V); + hid_hal_keyboard_release( + hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_V); +} +static void hid_ptt_trigger_mute_linux_gather(HidPushToTalk* hid_ptt) { + hid_hal_keyboard_press(hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_A); + hid_hal_keyboard_release( + hid_ptt->hid, KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_A); +} + static void hid_ptt_menu_callback( void* context, uint32_t osIndex, @@ -359,6 +383,13 @@ static void hid_ptt_menu_callback( model->callback_start_ptt = hid_ptt_trigger_cmd_shift_m; model->callback_stop_ptt = hid_ptt_trigger_cmd_shift_m; break; + case HidPushToTalkAppIndexGather: + model->callback_trigger_mute = hid_ptt_trigger_mute_macos_gather; + model->callback_trigger_camera = hid_ptt_trigger_camera_macos_gather; + model->callback_trigger_hand = hid_ptt_trigger_hand_gather; + model->callback_start_ptt = hid_ptt_trigger_mute_macos_gather; + model->callback_stop_ptt = hid_ptt_trigger_mute_macos_gather; + break; case HidPushToTalkAppIndexGoogleHangouts: model->callback_trigger_mute = hid_ptt_trigger_mute_macos_hangouts; model->callback_trigger_camera = hid_ptt_trigger_camera_macos_hangouts; @@ -434,6 +465,13 @@ static void hid_ptt_menu_callback( model->callback_start_ptt = hid_ptt_start_ptt_linux_discord; model->callback_stop_ptt = hid_ptt_stop_ptt_linux_discord; break; + case HidPushToTalkAppIndexGather: + model->callback_trigger_mute = hid_ptt_trigger_mute_linux_gather; + model->callback_trigger_camera = hid_ptt_trigger_camera_linux_gather; + model->callback_trigger_hand = hid_ptt_trigger_hand_gather; + model->callback_start_ptt = hid_ptt_trigger_mute_linux_gather; + model->callback_stop_ptt = hid_ptt_trigger_mute_linux_gather; + break; case HidPushToTalkAppIndexGoogleHangouts: model->callback_trigger_mute = hid_ptt_trigger_mute_linux_hangouts; model->callback_trigger_camera = hid_ptt_trigger_camera_linux_hangouts; @@ -873,6 +911,20 @@ HidPushToTalk* hid_ptt_alloc(Hid* hid) { HidPushToTalkAppIndexFaceTime, hid_ptt_menu_callback, hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkMacOS, + "Gather", + HidPushToTalkAppIndexGather, + hid_ptt_menu_callback, + hid_ptt); + ptt_menu_add_item_to_list( + hid->hid_ptt_menu, + HidPushToTalkLinux, + "Gather", + HidPushToTalkAppIndexGather, + hid_ptt_menu_callback, + hid_ptt); ptt_menu_add_item_to_list( hid->hid_ptt_menu, HidPushToTalkMacOS, @@ -932,14 +984,14 @@ HidPushToTalk* hid_ptt_alloc(Hid* hid) { ptt_menu_add_item_to_list( hid->hid_ptt_menu, HidPushToTalkMacOS, - "Slack Hubble", + "Slack Huddle", HidPushToTalkAppIndexSlackHubble, hid_ptt_menu_callback, hid_ptt); ptt_menu_add_item_to_list( hid->hid_ptt_menu, HidPushToTalkLinux, - "Slack Hubble", + "Slack Huddle", HidPushToTalkAppIndexSlackHubble, hid_ptt_menu_callback, hid_ptt); From c189283329a150f990d5bc715ef5b9892b6bac68 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 30 Jul 2025 04:37:49 +0300 Subject: [PATCH 09/31] simplify Bad USB BLE profile by aaronjamt & WillyJL --- applications/main/bad_usb/application.fam | 2 +- .../main/bad_usb/helpers/bad_usb_hid.c | 7 +- .../main/bad_usb/helpers/bad_usb_hid.h | 4 +- .../bad_usb/helpers/ble_hid_ext_profile.c | 43 ++ .../bad_usb/helpers/ble_hid_ext_profile.h | 17 + .../main/bad_usb/helpers/ble_hid_profile.c | 429 ------------------ .../main/bad_usb/helpers/ble_hid_profile.h | 109 ----- .../main/bad_usb/helpers/ble_hid_service.c | 325 ------------- .../main/bad_usb/helpers/ble_hid_service.h | 31 -- .../main/bad_usb/helpers/ducky_script.c | 2 +- .../bad_usb/scenes/bad_usb_scene_config.c | 2 +- .../main/bad_usb/views/bad_usb_view.c | 14 +- 12 files changed, 82 insertions(+), 903 deletions(-) create mode 100644 applications/main/bad_usb/helpers/ble_hid_ext_profile.c create mode 100644 applications/main/bad_usb/helpers/ble_hid_ext_profile.h delete mode 100644 applications/main/bad_usb/helpers/ble_hid_profile.c delete mode 100644 applications/main/bad_usb/helpers/ble_hid_profile.h delete mode 100644 applications/main/bad_usb/helpers/ble_hid_service.c delete mode 100644 applications/main/bad_usb/helpers/ble_hid_service.h diff --git a/applications/main/bad_usb/application.fam b/applications/main/bad_usb/application.fam index 9844e248d..8d3909fcc 100644 --- a/applications/main/bad_usb/application.fam +++ b/applications/main/bad_usb/application.fam @@ -7,7 +7,7 @@ App( icon="A_BadUsb_14", order=70, resources="resources", - fap_libs=["assets"], + fap_libs=["assets", "ble_profile"], fap_icon="icon.png", fap_category="USB", ) diff --git a/applications/main/bad_usb/helpers/bad_usb_hid.c b/applications/main/bad_usb/helpers/bad_usb_hid.c index 5ae4146e8..cab84173d 100644 --- a/applications/main/bad_usb/helpers/bad_usb_hid.c +++ b/applications/main/bad_usb/helpers/bad_usb_hid.c @@ -1,6 +1,7 @@ #include "bad_usb_hid.h" -#include "ble_hid_profile.h" +#include "ble_hid_ext_profile.h" #include +#include #include #define TAG "BadUSB HID" @@ -161,6 +162,7 @@ void hid_ble_adjust_config(BadUsbHidConfig* hid_cfg) { void* hid_ble_init(BadUsbHidConfig* hid_cfg) { BleHidInstance* ble_hid = malloc(sizeof(BleHidInstance)); ble_hid->bt = furi_record_open(RECORD_BT); + ble_hid->bt->suppress_pin_screen = true; bt_disconnect(ble_hid->bt); // Wait 2nd core to update nvm storage @@ -169,7 +171,7 @@ void* hid_ble_init(BadUsbHidConfig* hid_cfg) { bt_keys_storage_set_storage_path(ble_hid->bt, APP_DATA_PATH(HID_BT_KEYS_STORAGE_NAME)); hid_ble_adjust_config(hid_cfg); - ble_hid->profile = bt_profile_start(ble_hid->bt, ble_profile_hid, &hid_cfg->ble); + ble_hid->profile = bt_profile_start(ble_hid->bt, ble_profile_hid_ext, &hid_cfg->ble); furi_check(ble_hid->profile); furi_hal_bt_start_advertising(); @@ -191,6 +193,7 @@ void hid_ble_deinit(void* inst) { bt_keys_storage_set_default_path(ble_hid->bt); furi_check(bt_profile_restore_default(ble_hid->bt)); + ble_hid->bt->suppress_pin_screen = false; furi_record_close(RECORD_BT); free(ble_hid); } diff --git a/applications/main/bad_usb/helpers/bad_usb_hid.h b/applications/main/bad_usb/helpers/bad_usb_hid.h index 8749bdc3b..8a96ad7f3 100644 --- a/applications/main/bad_usb/helpers/bad_usb_hid.h +++ b/applications/main/bad_usb/helpers/bad_usb_hid.h @@ -7,7 +7,7 @@ extern "C" { #include #include -#include "ble_hid_profile.h" +#include "ble_hid_ext_profile.h" typedef enum { BadUsbHidInterfaceUsb, @@ -16,7 +16,7 @@ typedef enum { } BadUsbHidInterface; typedef struct { - BleProfileHidParams ble; + BleProfileHidExtParams ble; FuriHalUsbHidConfig usb; } BadUsbHidConfig; diff --git a/applications/main/bad_usb/helpers/ble_hid_ext_profile.c b/applications/main/bad_usb/helpers/ble_hid_ext_profile.c new file mode 100644 index 000000000..f77d6ba13 --- /dev/null +++ b/applications/main/bad_usb/helpers/ble_hid_ext_profile.c @@ -0,0 +1,43 @@ +#include "ble_hid_ext_profile.h" + +#include + +static FuriHalBleProfileBase* ble_profile_hid_ext_start(FuriHalBleProfileParams profile_params) { + UNUSED(profile_params); + + return ble_profile_hid->start(NULL); +} + +static void ble_profile_hid_ext_stop(FuriHalBleProfileBase* profile) { + ble_profile_hid->stop(profile); +} + +static void + ble_profile_hid_ext_get_config(GapConfig* config, FuriHalBleProfileParams profile_params) { + furi_check(config); + furi_check(profile_params); + BleProfileHidExtParams* hid_ext_profile_params = profile_params; + + // Setup config with basic profile + ble_profile_hid->get_gap_config(config, NULL); + + // Set MAC address + memcpy(config->mac_address, hid_ext_profile_params->mac, sizeof(config->mac_address)); + + // Set advertise name (skip first byte which is the ADV type) + strlcpy(config->adv_name + 1, hid_ext_profile_params->name, sizeof(config->adv_name) - 1); + + // Set bonding mode + config->bonding_mode = hid_ext_profile_params->bonding; + + // Set pairing method + config->pairing_method = hid_ext_profile_params->pairing; +} + +static const FuriHalBleProfileTemplate profile_callbacks = { + .start = ble_profile_hid_ext_start, + .stop = ble_profile_hid_ext_stop, + .get_gap_config = ble_profile_hid_ext_get_config, +}; + +const FuriHalBleProfileTemplate* ble_profile_hid_ext = &profile_callbacks; diff --git a/applications/main/bad_usb/helpers/ble_hid_ext_profile.h b/applications/main/bad_usb/helpers/ble_hid_ext_profile.h new file mode 100644 index 000000000..cc52f0ee7 --- /dev/null +++ b/applications/main/bad_usb/helpers/ble_hid_ext_profile.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +/** + * Optional arguments to pass along with profile template as + * FuriHalBleProfileParams for tuning profile behavior + **/ +typedef struct { + char name[FURI_HAL_BT_ADV_NAME_LENGTH]; /**< Full device name */ + uint8_t mac[GAP_MAC_ADDR_SIZE]; /**< Full device address */ + bool bonding; /**< Save paired devices */ + GapPairing pairing; /**< Pairing security method */ +} BleProfileHidExtParams; + +/** Hid Keyboard Profile descriptor */ +extern const FuriHalBleProfileTemplate* ble_profile_hid_ext; diff --git a/applications/main/bad_usb/helpers/ble_hid_profile.c b/applications/main/bad_usb/helpers/ble_hid_profile.c deleted file mode 100644 index a4f32159e..000000000 --- a/applications/main/bad_usb/helpers/ble_hid_profile.c +++ /dev/null @@ -1,429 +0,0 @@ -#include "ble_hid_profile.h" - -// Based on - -#include -#include -#include -#include "ble_hid_service.h" - -#include -#include -#include - -#define HID_INFO_BASE_USB_SPECIFICATION (0x0101) -#define HID_INFO_COUNTRY_CODE (0x00) -#define BLE_PROFILE_HID_INFO_FLAG_REMOTE_WAKE_MSK (0x01) -#define BLE_PROFILE_HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK (0x02) - -#define BLE_PROFILE_HID_KB_MAX_KEYS (6) -#define BLE_PROFILE_CONSUMER_MAX_KEYS (1) - -// Report ids cant be 0 -enum HidReportId { - ReportIdKeyboard = 1, - ReportIdMouse = 2, - ReportIdConsumer = 3, -}; -// Report numbers corresponded to the report id with an offset of 1 -enum HidInputNumber { - ReportNumberKeyboard = 0, - ReportNumberMouse = 1, - ReportNumberConsumer = 2, -}; - -typedef struct { - uint8_t mods; - uint8_t reserved; - uint8_t key[BLE_PROFILE_HID_KB_MAX_KEYS]; -} FURI_PACKED FuriHalBtHidKbReport; - -typedef struct { - uint8_t btn; - int8_t x; - int8_t y; - int8_t wheel; -} FURI_PACKED FuriHalBtHidMouseReport; - -typedef struct { - uint16_t key[BLE_PROFILE_CONSUMER_MAX_KEYS]; -} FURI_PACKED FuriHalBtHidConsumerReport; - -// keyboard+mouse+consumer hid report -static const uint8_t ble_profile_hid_report_map_data[] = { - // Keyboard Report - HID_USAGE_PAGE(HID_PAGE_DESKTOP), - HID_USAGE(HID_DESKTOP_KEYBOARD), - HID_COLLECTION(HID_APPLICATION_COLLECTION), - HID_REPORT_ID(ReportIdKeyboard), - HID_USAGE_PAGE(HID_DESKTOP_KEYPAD), - HID_USAGE_MINIMUM(HID_KEYBOARD_L_CTRL), - HID_USAGE_MAXIMUM(HID_KEYBOARD_R_GUI), - HID_LOGICAL_MINIMUM(0), - HID_LOGICAL_MAXIMUM(1), - HID_REPORT_SIZE(1), - HID_REPORT_COUNT(8), - HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), - HID_REPORT_COUNT(1), - HID_REPORT_SIZE(8), - HID_INPUT(HID_IOF_CONSTANT | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), - HID_USAGE_PAGE(HID_PAGE_LED), - HID_REPORT_COUNT(8), - HID_REPORT_SIZE(1), - HID_USAGE_MINIMUM(1), - HID_USAGE_MAXIMUM(8), - HID_OUTPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), - HID_REPORT_COUNT(BLE_PROFILE_HID_KB_MAX_KEYS), - HID_REPORT_SIZE(8), - HID_LOGICAL_MINIMUM(0), - HID_LOGICAL_MAXIMUM(101), - HID_USAGE_PAGE(HID_DESKTOP_KEYPAD), - HID_USAGE_MINIMUM(0), - HID_USAGE_MAXIMUM(101), - HID_INPUT(HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE), - HID_END_COLLECTION, - // Mouse Report - HID_USAGE_PAGE(HID_PAGE_DESKTOP), - HID_USAGE(HID_DESKTOP_MOUSE), - HID_COLLECTION(HID_APPLICATION_COLLECTION), - HID_USAGE(HID_DESKTOP_POINTER), - HID_COLLECTION(HID_PHYSICAL_COLLECTION), - HID_REPORT_ID(ReportIdMouse), - HID_USAGE_PAGE(HID_PAGE_BUTTON), - HID_USAGE_MINIMUM(1), - HID_USAGE_MAXIMUM(3), - HID_LOGICAL_MINIMUM(0), - HID_LOGICAL_MAXIMUM(1), - HID_REPORT_COUNT(3), - HID_REPORT_SIZE(1), - HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), - HID_REPORT_SIZE(1), - HID_REPORT_COUNT(5), - HID_INPUT(HID_IOF_CONSTANT | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), - HID_USAGE_PAGE(HID_PAGE_DESKTOP), - HID_USAGE(HID_DESKTOP_X), - HID_USAGE(HID_DESKTOP_Y), - HID_USAGE(HID_DESKTOP_WHEEL), - HID_LOGICAL_MINIMUM(-127), - HID_LOGICAL_MAXIMUM(127), - HID_REPORT_SIZE(8), - HID_REPORT_COUNT(3), - HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE), - HID_END_COLLECTION, - HID_END_COLLECTION, - // Consumer Report - HID_USAGE_PAGE(HID_PAGE_CONSUMER), - HID_USAGE(HID_CONSUMER_CONTROL), - HID_COLLECTION(HID_APPLICATION_COLLECTION), - HID_REPORT_ID(ReportIdConsumer), - HID_LOGICAL_MINIMUM(0), - HID_RI_LOGICAL_MAXIMUM(16, 0x3FF), - HID_USAGE_MINIMUM(0), - HID_RI_USAGE_MAXIMUM(16, 0x3FF), - HID_REPORT_COUNT(BLE_PROFILE_CONSUMER_MAX_KEYS), - HID_REPORT_SIZE(16), - HID_INPUT(HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE), - HID_END_COLLECTION, -}; - -typedef struct { - FuriHalBleProfileBase base; - - FuriHalBtHidKbReport* kb_report; - FuriHalBtHidMouseReport* mouse_report; - FuriHalBtHidConsumerReport* consumer_report; - - BleServiceBattery* battery_svc; - BleServiceDevInfo* dev_info_svc; - BleServiceHid* hid_svc; -} BleProfileHid; -_Static_assert(offsetof(BleProfileHid, base) == 0, "Wrong layout"); - -static FuriHalBleProfileBase* ble_profile_hid_start(FuriHalBleProfileParams profile_params) { - UNUSED(profile_params); - - BleProfileHid* profile = malloc(sizeof(BleProfileHid)); - - profile->base.config = ble_profile_hid; - - profile->battery_svc = ble_svc_battery_start(true); - profile->dev_info_svc = ble_svc_dev_info_start(); - profile->hid_svc = ble_svc_hid_start(); - - // Configure HID Keyboard - profile->kb_report = malloc(sizeof(FuriHalBtHidKbReport)); - profile->mouse_report = malloc(sizeof(FuriHalBtHidMouseReport)); - profile->consumer_report = malloc(sizeof(FuriHalBtHidConsumerReport)); - - // Configure Report Map characteristic - ble_svc_hid_update_report_map( - profile->hid_svc, - ble_profile_hid_report_map_data, - sizeof(ble_profile_hid_report_map_data)); - // Configure HID Information characteristic - uint8_t hid_info_val[4] = { - HID_INFO_BASE_USB_SPECIFICATION & 0x00ff, - (HID_INFO_BASE_USB_SPECIFICATION & 0xff00) >> 8, - HID_INFO_COUNTRY_CODE, - BLE_PROFILE_HID_INFO_FLAG_REMOTE_WAKE_MSK | - BLE_PROFILE_HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK, - }; - ble_svc_hid_update_info(profile->hid_svc, hid_info_val); - - return &profile->base; -} - -static void ble_profile_hid_stop(FuriHalBleProfileBase* profile) { - furi_check(profile); - furi_check(profile->config == ble_profile_hid); - - BleProfileHid* hid_profile = (BleProfileHid*)profile; - ble_svc_battery_stop(hid_profile->battery_svc); - ble_svc_dev_info_stop(hid_profile->dev_info_svc); - ble_svc_hid_stop(hid_profile->hid_svc); - - free(hid_profile->kb_report); - free(hid_profile->mouse_report); - free(hid_profile->consumer_report); -} - -bool ble_profile_hid_kb_press(FuriHalBleProfileBase* profile, uint16_t button) { - furi_check(profile); - furi_check(profile->config == ble_profile_hid); - - BleProfileHid* hid_profile = (BleProfileHid*)profile; - FuriHalBtHidKbReport* kb_report = hid_profile->kb_report; - for(uint8_t i = 0; i < BLE_PROFILE_HID_KB_MAX_KEYS; i++) { - if(kb_report->key[i] == 0) { - kb_report->key[i] = button & 0xFF; - break; - } - } - kb_report->mods |= (button >> 8); - return ble_svc_hid_update_input_report( - hid_profile->hid_svc, - ReportNumberKeyboard, - (uint8_t*)kb_report, - sizeof(FuriHalBtHidKbReport)); -} - -bool ble_profile_hid_kb_release(FuriHalBleProfileBase* profile, uint16_t button) { - furi_check(profile); - furi_check(profile->config == ble_profile_hid); - - BleProfileHid* hid_profile = (BleProfileHid*)profile; - - FuriHalBtHidKbReport* kb_report = hid_profile->kb_report; - for(uint8_t i = 0; i < BLE_PROFILE_HID_KB_MAX_KEYS; i++) { - if(kb_report->key[i] == (button & 0xFF)) { - kb_report->key[i] = 0; - break; - } - } - kb_report->mods &= ~(button >> 8); - return ble_svc_hid_update_input_report( - hid_profile->hid_svc, - ReportNumberKeyboard, - (uint8_t*)kb_report, - sizeof(FuriHalBtHidKbReport)); -} - -bool ble_profile_hid_kb_release_all(FuriHalBleProfileBase* profile) { - furi_check(profile); - furi_check(profile->config == ble_profile_hid); - - BleProfileHid* hid_profile = (BleProfileHid*)profile; - FuriHalBtHidKbReport* kb_report = hid_profile->kb_report; - for(uint8_t i = 0; i < BLE_PROFILE_HID_KB_MAX_KEYS; i++) { - kb_report->key[i] = 0; - } - kb_report->mods = 0; - return ble_svc_hid_update_input_report( - hid_profile->hid_svc, - ReportNumberKeyboard, - (uint8_t*)kb_report, - sizeof(FuriHalBtHidKbReport)); -} - -bool ble_profile_hid_consumer_key_press(FuriHalBleProfileBase* profile, uint16_t button) { - furi_check(profile); - furi_check(profile->config == ble_profile_hid); - - BleProfileHid* hid_profile = (BleProfileHid*)profile; - FuriHalBtHidConsumerReport* consumer_report = hid_profile->consumer_report; - for(uint8_t i = 0; i < BLE_PROFILE_CONSUMER_MAX_KEYS; i++) { //-V1008 - if(consumer_report->key[i] == 0) { - consumer_report->key[i] = button; - break; - } - } - return ble_svc_hid_update_input_report( - hid_profile->hid_svc, - ReportNumberConsumer, - (uint8_t*)consumer_report, - sizeof(FuriHalBtHidConsumerReport)); -} - -bool ble_profile_hid_consumer_key_release(FuriHalBleProfileBase* profile, uint16_t button) { - furi_check(profile); - furi_check(profile->config == ble_profile_hid); - - BleProfileHid* hid_profile = (BleProfileHid*)profile; - FuriHalBtHidConsumerReport* consumer_report = hid_profile->consumer_report; - for(uint8_t i = 0; i < BLE_PROFILE_CONSUMER_MAX_KEYS; i++) { //-V1008 - if(consumer_report->key[i] == button) { - consumer_report->key[i] = 0; - break; - } - } - return ble_svc_hid_update_input_report( - hid_profile->hid_svc, - ReportNumberConsumer, - (uint8_t*)consumer_report, - sizeof(FuriHalBtHidConsumerReport)); -} - -bool ble_profile_hid_consumer_key_release_all(FuriHalBleProfileBase* profile) { - furi_check(profile); - furi_check(profile->config == ble_profile_hid); - - BleProfileHid* hid_profile = (BleProfileHid*)profile; - FuriHalBtHidConsumerReport* consumer_report = hid_profile->consumer_report; - for(uint8_t i = 0; i < BLE_PROFILE_CONSUMER_MAX_KEYS; i++) { //-V1008 - consumer_report->key[i] = 0; - } - return ble_svc_hid_update_input_report( - hid_profile->hid_svc, - ReportNumberConsumer, - (uint8_t*)consumer_report, - sizeof(FuriHalBtHidConsumerReport)); -} - -bool ble_profile_hid_mouse_move(FuriHalBleProfileBase* profile, int8_t dx, int8_t dy) { - furi_check(profile); - furi_check(profile->config == ble_profile_hid); - - BleProfileHid* hid_profile = (BleProfileHid*)profile; - FuriHalBtHidMouseReport* mouse_report = hid_profile->mouse_report; - mouse_report->x = dx; - mouse_report->y = dy; - bool state = ble_svc_hid_update_input_report( - hid_profile->hid_svc, - ReportNumberMouse, - (uint8_t*)mouse_report, - sizeof(FuriHalBtHidMouseReport)); - mouse_report->x = 0; - mouse_report->y = 0; - return state; -} - -bool ble_profile_hid_mouse_press(FuriHalBleProfileBase* profile, uint8_t button) { - furi_check(profile); - furi_check(profile->config == ble_profile_hid); - - BleProfileHid* hid_profile = (BleProfileHid*)profile; - FuriHalBtHidMouseReport* mouse_report = hid_profile->mouse_report; - mouse_report->btn |= button; - return ble_svc_hid_update_input_report( - hid_profile->hid_svc, - ReportNumberMouse, - (uint8_t*)mouse_report, - sizeof(FuriHalBtHidMouseReport)); -} - -bool ble_profile_hid_mouse_release(FuriHalBleProfileBase* profile, uint8_t button) { - furi_check(profile); - furi_check(profile->config == ble_profile_hid); - - BleProfileHid* hid_profile = (BleProfileHid*)profile; - FuriHalBtHidMouseReport* mouse_report = hid_profile->mouse_report; - mouse_report->btn &= ~button; - return ble_svc_hid_update_input_report( - hid_profile->hid_svc, - ReportNumberMouse, - (uint8_t*)mouse_report, - sizeof(FuriHalBtHidMouseReport)); -} - -bool ble_profile_hid_mouse_release_all(FuriHalBleProfileBase* profile) { - furi_check(profile); - furi_check(profile->config == ble_profile_hid); - - BleProfileHid* hid_profile = (BleProfileHid*)profile; - FuriHalBtHidMouseReport* mouse_report = hid_profile->mouse_report; - mouse_report->btn = 0; - return ble_svc_hid_update_input_report( - hid_profile->hid_svc, - ReportNumberMouse, - (uint8_t*)mouse_report, - sizeof(FuriHalBtHidMouseReport)); -} - -bool ble_profile_hid_mouse_scroll(FuriHalBleProfileBase* profile, int8_t delta) { - furi_check(profile); - furi_check(profile->config == ble_profile_hid); - - BleProfileHid* hid_profile = (BleProfileHid*)profile; - FuriHalBtHidMouseReport* mouse_report = hid_profile->mouse_report; - mouse_report->wheel = delta; - bool state = ble_svc_hid_update_input_report( - hid_profile->hid_svc, - ReportNumberMouse, - (uint8_t*)mouse_report, - sizeof(FuriHalBtHidMouseReport)); - mouse_report->wheel = 0; - return state; -} - -// AN5289: 4.7, in order to use flash controller interval must be at least 25ms + advertisement, which is 30 ms -// Since we don't use flash controller anymore interval can be lowered to 7.5ms -#define CONNECTION_INTERVAL_MIN (0x0006) -// Up to 45 ms -#define CONNECTION_INTERVAL_MAX (0x24) - -static GapConfig template_config = { - .adv_service = - { - .UUID_Type = UUID_TYPE_16, - .Service_UUID_16 = HUMAN_INTERFACE_DEVICE_SERVICE_UUID, - }, - .appearance_char = GAP_APPEARANCE_KEYBOARD, - .bonding_mode = true, - .pairing_method = GapPairingPinCodeVerifyYesNo, - .conn_param = - { - .conn_int_min = CONNECTION_INTERVAL_MIN, - .conn_int_max = CONNECTION_INTERVAL_MAX, - .slave_latency = 0, - .supervisor_timeout = 0, - }, -}; - -static void ble_profile_hid_get_config(GapConfig* config, FuriHalBleProfileParams profile_params) { - furi_check(profile_params); - BleProfileHidParams* hid_profile_params = profile_params; - - furi_check(config); - memcpy(config, &template_config, sizeof(GapConfig)); - - // Set MAC address - memcpy(config->mac_address, hid_profile_params->mac, sizeof(config->mac_address)); - - // Set advertise name - config->adv_name[0] = furi_hal_version_get_ble_local_device_name_ptr()[0]; - strlcpy(config->adv_name + 1, hid_profile_params->name, sizeof(config->adv_name) - 1); - - // Set bonding mode - config->bonding_mode = hid_profile_params->bonding; - - // Set pairing method - config->pairing_method = hid_profile_params->pairing; -} - -static const FuriHalBleProfileTemplate profile_callbacks = { - .start = ble_profile_hid_start, - .stop = ble_profile_hid_stop, - .get_gap_config = ble_profile_hid_get_config, -}; - -const FuriHalBleProfileTemplate* ble_profile_hid = &profile_callbacks; diff --git a/applications/main/bad_usb/helpers/ble_hid_profile.h b/applications/main/bad_usb/helpers/ble_hid_profile.h deleted file mode 100644 index 2302aa581..000000000 --- a/applications/main/bad_usb/helpers/ble_hid_profile.h +++ /dev/null @@ -1,109 +0,0 @@ -#pragma once - -// Based on - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Optional arguments to pass along with profile template as - * FuriHalBleProfileParams for tuning profile behavior - **/ -typedef struct { - char name[FURI_HAL_BT_ADV_NAME_LENGTH]; /**< Full device name */ - uint8_t mac[GAP_MAC_ADDR_SIZE]; /**< Full device address */ - bool bonding; /**< Save paired devices */ - GapPairing pairing; /**< Pairing security method */ -} BleProfileHidParams; - -/** Hid Keyboard Profile descriptor */ -extern const FuriHalBleProfileTemplate* ble_profile_hid; - -/** Press keyboard button - * - * @param profile profile instance - * @param button button code from HID specification - * - * @return true on success - */ -bool ble_profile_hid_kb_press(FuriHalBleProfileBase* profile, uint16_t button); - -/** Release keyboard button - * - * @param profile profile instance - * @param button button code from HID specification - * - * @return true on success - */ -bool ble_profile_hid_kb_release(FuriHalBleProfileBase* profile, uint16_t button); - -/** Release all keyboard buttons - * - * @param profile profile instance - * @return true on success - */ -bool ble_profile_hid_kb_release_all(FuriHalBleProfileBase* profile); - -/** Set the following consumer key to pressed state and send HID report - * - * @param profile profile instance - * @param button key code - */ -bool ble_profile_hid_consumer_key_press(FuriHalBleProfileBase* profile, uint16_t button); - -/** Set the following consumer key to released state and send HID report - * - * @param profile profile instance - * @param button key code - */ -bool ble_profile_hid_consumer_key_release(FuriHalBleProfileBase* profile, uint16_t button); - -/** Set consumer key to released state and send HID report - * - * @param profile profile instance - * @param button key code - */ -bool ble_profile_hid_consumer_key_release_all(FuriHalBleProfileBase* profile); - -/** Set mouse movement and send HID report - * - * @param profile profile instance - * @param dx x coordinate delta - * @param dy y coordinate delta - */ -bool ble_profile_hid_mouse_move(FuriHalBleProfileBase* profile, int8_t dx, int8_t dy); - -/** Set mouse button to pressed state and send HID report - * - * @param profile profile instance - * @param button key code - */ -bool ble_profile_hid_mouse_press(FuriHalBleProfileBase* profile, uint8_t button); - -/** Set mouse button to released state and send HID report - * - * @param profile profile instance - * @param button key code - */ -bool ble_profile_hid_mouse_release(FuriHalBleProfileBase* profile, uint8_t button); - -/** Set mouse button to released state and send HID report - * - * @param profile profile instance - * @param button key code - */ -bool ble_profile_hid_mouse_release_all(FuriHalBleProfileBase* profile); - -/** Set mouse wheel position and send HID report - * - * @param profile profile instance - * @param delta number of scroll steps - */ -bool ble_profile_hid_mouse_scroll(FuriHalBleProfileBase* profile, int8_t delta); - -#ifdef __cplusplus -} -#endif diff --git a/applications/main/bad_usb/helpers/ble_hid_service.c b/applications/main/bad_usb/helpers/ble_hid_service.c deleted file mode 100644 index b546368dd..000000000 --- a/applications/main/bad_usb/helpers/ble_hid_service.c +++ /dev/null @@ -1,325 +0,0 @@ -#include "ble_hid_service.h" - -// Based on - -#include "app_common.h" // IWYU pragma: keep -#include -#include -#include - -#include -#include - -#define TAG "BleHid" - -#define BLE_SVC_HID_REPORT_MAP_MAX_LEN (255) -#define BLE_SVC_HID_REPORT_MAX_LEN (255) -#define BLE_SVC_HID_REPORT_REF_LEN (2) -#define BLE_SVC_HID_INFO_LEN (4) -#define BLE_SVC_HID_CONTROL_POINT_LEN (1) - -#define BLE_SVC_HID_INPUT_REPORT_COUNT (3) -#define BLE_SVC_HID_OUTPUT_REPORT_COUNT (0) -#define BLE_SVC_HID_FEATURE_REPORT_COUNT (0) -#define BLE_SVC_HID_REPORT_COUNT \ - (BLE_SVC_HID_INPUT_REPORT_COUNT + BLE_SVC_HID_OUTPUT_REPORT_COUNT + \ - BLE_SVC_HID_FEATURE_REPORT_COUNT) - -typedef enum { - HidSvcGattCharacteristicProtocolMode = 0, - HidSvcGattCharacteristicReportMap, - HidSvcGattCharacteristicInfo, - HidSvcGattCharacteristicCtrlPoint, - HidSvcGattCharacteristicCount, -} HidSvcGattCharacteristicId; - -typedef struct { - uint8_t report_idx; - uint8_t report_type; -} HidSvcReportId; - -static_assert(sizeof(HidSvcReportId) == sizeof(uint16_t), "HidSvcReportId must be 2 bytes"); - -static const Service_UUID_t ble_svc_hid_uuid = { - .Service_UUID_16 = HUMAN_INTERFACE_DEVICE_SERVICE_UUID, -}; - -static bool ble_svc_hid_char_desc_data_callback( - const void* context, - const uint8_t** data, - uint16_t* data_len) { - const HidSvcReportId* report_id = context; - *data_len = sizeof(HidSvcReportId); - if(data) { - *data = (const uint8_t*)report_id; - } - return false; -} - -typedef struct { - const void* data_ptr; - uint16_t data_len; -} HidSvcDataWrapper; - -static bool ble_svc_hid_report_data_callback( - const void* context, - const uint8_t** data, - uint16_t* data_len) { - const HidSvcDataWrapper* report_data = context; - if(data) { - *data = report_data->data_ptr; - *data_len = report_data->data_len; - } else { - *data_len = BLE_SVC_HID_REPORT_MAP_MAX_LEN; - } - return false; -} - -static const BleGattCharacteristicParams ble_svc_hid_chars[HidSvcGattCharacteristicCount] = { - [HidSvcGattCharacteristicProtocolMode] = - {.name = "Protocol Mode", - .data_prop_type = FlipperGattCharacteristicDataFixed, - .data.fixed.length = 1, - .uuid.Char_UUID_16 = PROTOCOL_MODE_CHAR_UUID, - .uuid_type = UUID_TYPE_16, - .char_properties = CHAR_PROP_READ | CHAR_PROP_WRITE_WITHOUT_RESP, - .security_permissions = ATTR_PERMISSION_NONE, - .gatt_evt_mask = GATT_NOTIFY_ATTRIBUTE_WRITE, - .is_variable = CHAR_VALUE_LEN_CONSTANT}, - [HidSvcGattCharacteristicReportMap] = - {.name = "Report Map", - .data_prop_type = FlipperGattCharacteristicDataCallback, - .data.callback.fn = ble_svc_hid_report_data_callback, - .data.callback.context = NULL, - .uuid.Char_UUID_16 = REPORT_MAP_CHAR_UUID, - .uuid_type = UUID_TYPE_16, - .char_properties = CHAR_PROP_READ, - .security_permissions = ATTR_PERMISSION_NONE, - .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, - .is_variable = CHAR_VALUE_LEN_VARIABLE}, - [HidSvcGattCharacteristicInfo] = - {.name = "HID Information", - .data_prop_type = FlipperGattCharacteristicDataFixed, - .data.fixed.length = BLE_SVC_HID_INFO_LEN, - .data.fixed.ptr = NULL, - .uuid.Char_UUID_16 = HID_INFORMATION_CHAR_UUID, - .uuid_type = UUID_TYPE_16, - .char_properties = CHAR_PROP_READ, - .security_permissions = ATTR_PERMISSION_NONE, - .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, - .is_variable = CHAR_VALUE_LEN_CONSTANT}, - [HidSvcGattCharacteristicCtrlPoint] = - {.name = "HID Control Point", - .data_prop_type = FlipperGattCharacteristicDataFixed, - .data.fixed.length = BLE_SVC_HID_CONTROL_POINT_LEN, - .uuid.Char_UUID_16 = HID_CONTROL_POINT_CHAR_UUID, - .uuid_type = UUID_TYPE_16, - .char_properties = CHAR_PROP_WRITE_WITHOUT_RESP, - .security_permissions = ATTR_PERMISSION_NONE, - .gatt_evt_mask = GATT_NOTIFY_ATTRIBUTE_WRITE, - .is_variable = CHAR_VALUE_LEN_CONSTANT}, -}; - -static const BleGattCharacteristicDescriptorParams ble_svc_hid_char_descr_template = { - .uuid_type = UUID_TYPE_16, - .uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID, - .max_length = BLE_SVC_HID_REPORT_REF_LEN, - .data_callback.fn = ble_svc_hid_char_desc_data_callback, - .security_permissions = ATTR_PERMISSION_NONE, - .access_permissions = ATTR_ACCESS_READ_WRITE, - .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, - .is_variable = CHAR_VALUE_LEN_CONSTANT, -}; - -static const BleGattCharacteristicParams ble_svc_hid_report_template = { - .name = "Report", - .data_prop_type = FlipperGattCharacteristicDataCallback, - .data.callback.fn = ble_svc_hid_report_data_callback, - .data.callback.context = NULL, - .uuid.Char_UUID_16 = REPORT_CHAR_UUID, - .uuid_type = UUID_TYPE_16, - .char_properties = CHAR_PROP_READ | CHAR_PROP_NOTIFY, - .security_permissions = ATTR_PERMISSION_NONE, - .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, - .is_variable = CHAR_VALUE_LEN_VARIABLE, -}; - -struct BleServiceHid { - uint16_t svc_handle; - BleGattCharacteristicInstance chars[HidSvcGattCharacteristicCount]; - BleGattCharacteristicInstance input_report_chars[BLE_SVC_HID_INPUT_REPORT_COUNT]; - BleGattCharacteristicInstance output_report_chars[BLE_SVC_HID_OUTPUT_REPORT_COUNT]; - BleGattCharacteristicInstance feature_report_chars[BLE_SVC_HID_FEATURE_REPORT_COUNT]; - GapSvcEventHandler* event_handler; -}; - -static BleEventAckStatus ble_svc_hid_event_handler(void* event, void* context) { - UNUSED(context); - - BleEventAckStatus ret = BleEventNotAck; - hci_event_pckt* event_pckt = (hci_event_pckt*)(((hci_uart_pckt*)event)->data); - evt_blecore_aci* blecore_evt = (evt_blecore_aci*)event_pckt->data; - // aci_gatt_attribute_modified_event_rp0* attribute_modified; - - if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) { - if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) { - // Process modification events - ret = BleEventAckFlowEnable; - } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) { - // Process notification confirmation - ret = BleEventAckFlowEnable; - } - } - return ret; -} - -BleServiceHid* ble_svc_hid_start(void) { - BleServiceHid* hid_svc = malloc(sizeof(BleServiceHid)); - - // Register event handler - hid_svc->event_handler = - ble_event_dispatcher_register_svc_handler(ble_svc_hid_event_handler, hid_svc); - /** - * Add Human Interface Device Service - */ - if(!ble_gatt_service_add( - UUID_TYPE_16, - &ble_svc_hid_uuid, - PRIMARY_SERVICE, - 2 + /* protocol mode */ - (4 * BLE_SVC_HID_INPUT_REPORT_COUNT) + (3 * BLE_SVC_HID_OUTPUT_REPORT_COUNT) + - (3 * BLE_SVC_HID_FEATURE_REPORT_COUNT) + 1 + 2 + 2 + - 2, /* Service + Report Map + HID Information + HID Control Point */ - &hid_svc->svc_handle)) { - free(hid_svc); - return NULL; - } - - // Maintain previously defined characteristic order - ble_gatt_characteristic_init( - hid_svc->svc_handle, - &ble_svc_hid_chars[HidSvcGattCharacteristicProtocolMode], - &hid_svc->chars[HidSvcGattCharacteristicProtocolMode]); - - uint8_t protocol_mode = 1; - ble_gatt_characteristic_update( - hid_svc->svc_handle, - &hid_svc->chars[HidSvcGattCharacteristicProtocolMode], - &protocol_mode); - - // reports - BleGattCharacteristicDescriptorParams ble_svc_hid_char_descr; - BleGattCharacteristicParams report_char; - HidSvcReportId report_id; - - memcpy( - &ble_svc_hid_char_descr, &ble_svc_hid_char_descr_template, sizeof(ble_svc_hid_char_descr)); - memcpy(&report_char, &ble_svc_hid_report_template, sizeof(report_char)); - - ble_svc_hid_char_descr.data_callback.context = &report_id; - report_char.descriptor_params = &ble_svc_hid_char_descr; - - typedef struct { - uint8_t report_type; - uint8_t report_count; - BleGattCharacteristicInstance* chars; - } HidSvcReportCharProps; - - HidSvcReportCharProps hid_report_chars[] = { - {0x01, BLE_SVC_HID_INPUT_REPORT_COUNT, hid_svc->input_report_chars}, - {0x02, BLE_SVC_HID_OUTPUT_REPORT_COUNT, hid_svc->output_report_chars}, - {0x03, BLE_SVC_HID_FEATURE_REPORT_COUNT, hid_svc->feature_report_chars}, - }; - - for(size_t report_type_idx = 0; report_type_idx < COUNT_OF(hid_report_chars); - report_type_idx++) { - report_id.report_type = hid_report_chars[report_type_idx].report_type; - for(size_t report_idx = 0; report_idx < hid_report_chars[report_type_idx].report_count; - report_idx++) { - report_id.report_idx = report_idx + 1; - ble_gatt_characteristic_init( - hid_svc->svc_handle, - &report_char, - &hid_report_chars[report_type_idx].chars[report_idx]); - } - } - - // Setup remaining characteristics - for(size_t i = HidSvcGattCharacteristicReportMap; i < HidSvcGattCharacteristicCount; i++) { - ble_gatt_characteristic_init( - hid_svc->svc_handle, &ble_svc_hid_chars[i], &hid_svc->chars[i]); - } - - return hid_svc; -} - -bool ble_svc_hid_update_report_map(BleServiceHid* hid_svc, const uint8_t* data, uint16_t len) { - furi_assert(data); - furi_assert(hid_svc); - - HidSvcDataWrapper report_data = { - .data_ptr = data, - .data_len = len, - }; - return ble_gatt_characteristic_update( - hid_svc->svc_handle, &hid_svc->chars[HidSvcGattCharacteristicReportMap], &report_data); -} - -bool ble_svc_hid_update_input_report( - BleServiceHid* hid_svc, - uint8_t input_report_num, - uint8_t* data, - uint16_t len) { - furi_assert(data); - furi_assert(hid_svc); - furi_assert(input_report_num < BLE_SVC_HID_INPUT_REPORT_COUNT); - - HidSvcDataWrapper report_data = { - .data_ptr = data, - .data_len = len, - }; - - return ble_gatt_characteristic_update( - hid_svc->svc_handle, &hid_svc->input_report_chars[input_report_num], &report_data); -} - -bool ble_svc_hid_update_info(BleServiceHid* hid_svc, uint8_t* data) { - furi_assert(data); - furi_assert(hid_svc); - - return ble_gatt_characteristic_update( - hid_svc->svc_handle, &hid_svc->chars[HidSvcGattCharacteristicInfo], &data); -} - -void ble_svc_hid_stop(BleServiceHid* hid_svc) { - furi_assert(hid_svc); - ble_event_dispatcher_unregister_svc_handler(hid_svc->event_handler); - // Delete characteristics - for(size_t i = 0; i < HidSvcGattCharacteristicCount; i++) { - ble_gatt_characteristic_delete(hid_svc->svc_handle, &hid_svc->chars[i]); - } - - typedef struct { - uint8_t report_count; - BleGattCharacteristicInstance* chars; - } HidSvcReportCharProps; - - HidSvcReportCharProps hid_report_chars[] = { - {BLE_SVC_HID_INPUT_REPORT_COUNT, hid_svc->input_report_chars}, - {BLE_SVC_HID_OUTPUT_REPORT_COUNT, hid_svc->output_report_chars}, - {BLE_SVC_HID_FEATURE_REPORT_COUNT, hid_svc->feature_report_chars}, - }; - - for(size_t report_type_idx = 0; report_type_idx < COUNT_OF(hid_report_chars); - report_type_idx++) { - for(size_t report_idx = 0; report_idx < hid_report_chars[report_type_idx].report_count; - report_idx++) { - ble_gatt_characteristic_delete( - hid_svc->svc_handle, &hid_report_chars[report_type_idx].chars[report_idx]); - } - } - - // Delete service - ble_gatt_service_delete(hid_svc->svc_handle); - free(hid_svc); -} diff --git a/applications/main/bad_usb/helpers/ble_hid_service.h b/applications/main/bad_usb/helpers/ble_hid_service.h deleted file mode 100644 index e1ac3b0be..000000000 --- a/applications/main/bad_usb/helpers/ble_hid_service.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -// Based on - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct BleServiceHid BleServiceHid; - -BleServiceHid* ble_svc_hid_start(void); - -void ble_svc_hid_stop(BleServiceHid* service); - -bool ble_svc_hid_update_report_map(BleServiceHid* service, const uint8_t* data, uint16_t len); - -bool ble_svc_hid_update_input_report( - BleServiceHid* service, - uint8_t input_report_num, - uint8_t* data, - uint16_t len); - -// Expects data to be of length BLE_SVC_HID_INFO_LEN (4 bytes) -bool ble_svc_hid_update_info(BleServiceHid* service, uint8_t* data); - -#ifdef __cplusplus -} -#endif diff --git a/applications/main/bad_usb/helpers/ducky_script.c b/applications/main/bad_usb/helpers/ducky_script.c index 4b427b759..2c8b31e1d 100644 --- a/applications/main/bad_usb/helpers/ducky_script.c +++ b/applications/main/bad_usb/helpers/ducky_script.c @@ -257,7 +257,7 @@ static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) { } static bool ducky_set_ble_id(BadUsbScript* bad_usb, const char* line) { - BleProfileHidParams* ble_hid_cfg = &bad_usb->hid_cfg->ble; + BleProfileHidExtParams* ble_hid_cfg = &bad_usb->hid_cfg->ble; size_t line_len = strlen(line); size_t mac_len = sizeof(ble_hid_cfg->mac) * 3; // 2 hex chars + separator per byte diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_config.c b/applications/main/bad_usb/scenes/bad_usb_scene_config.c index 5c59fe6b9..adf989dfc 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene_config.c +++ b/applications/main/bad_usb/scenes/bad_usb_scene_config.c @@ -84,7 +84,7 @@ static void draw_menu(BadUsbApp* bad_usb) { item, bad_usb->interface == BadUsbHidInterfaceBle ? "BLE" : "USB"); if(bad_usb->interface == BadUsbHidInterfaceBle) { - BleProfileHidParams* ble_hid_cfg = &bad_usb->script_hid_cfg.ble; + BleProfileHidExtParams* ble_hid_cfg = &bad_usb->script_hid_cfg.ble; item = variable_item_list_add( var_item_list, diff --git a/applications/main/bad_usb/views/bad_usb_view.c b/applications/main/bad_usb/views/bad_usb_view.c index 4032ea974..d6f6683ec 100644 --- a/applications/main/bad_usb/views/bad_usb_view.c +++ b/applications/main/bad_usb/views/bad_usb_view.c @@ -3,6 +3,7 @@ #include #include #include +#include #define MAX_NAME_LEN 64 @@ -19,6 +20,7 @@ typedef struct { bool pause_wait; uint8_t anim_frame; BadUsbHidInterface interface; + Bt* bt; } BadUsbModel; static void bad_usb_draw_callback(Canvas* canvas, void* _model) { @@ -34,8 +36,12 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { } else { furi_string_printf(disp_str, "(%s)", model->layout); } - uint32_t e = model->state.elapsed; - furi_string_cat_printf(disp_str, " %02lu:%02lu.%ld", e / 60 / 1000, e / 1000, e % 1000); + if(model->interface == BadUsbHidInterfaceBle && model->bt->pin_code) { + furi_string_cat_printf(disp_str, " PIN: %ld", model->bt->pin_code); + } else { + uint32_t e = model->state.elapsed; + furi_string_cat_printf(disp_str, " %02lu:%02lu.%ld", e / 60 / 1000, e / 1000, e % 1000); + } elements_string_fit_width(canvas, disp_str, 128 - 2); canvas_draw_str( canvas, 2, 8 + canvas_current_font_height(canvas), furi_string_get_cstr(disp_str)); @@ -217,11 +223,15 @@ BadUsb* bad_usb_view_alloc(void) { view_set_draw_callback(bad_usb->view, bad_usb_draw_callback); view_set_input_callback(bad_usb->view, bad_usb_input_callback); + with_view_model( + bad_usb->view, BadUsbModel * model, { model->bt = furi_record_open(RECORD_BT); }, true); + return bad_usb; } void bad_usb_view_free(BadUsb* bad_usb) { furi_assert(bad_usb); + furi_record_close(RECORD_BT); view_free(bad_usb->view); free(bad_usb); } From 3aa75341d68d3cbedf7de483d15fd320ab8fef73 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 30 Jul 2025 04:39:04 +0300 Subject: [PATCH 10/31] NFC: Fix incorrect Saflok year formula by Eltrick --- applications/main/nfc/plugins/supported_cards/saflok.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/saflok.c b/applications/main/nfc/plugins/supported_cards/saflok.c index 9940b7cb1..9cab61ee5 100644 --- a/applications/main/nfc/plugins/supported_cards/saflok.c +++ b/applications/main/nfc/plugins/supported_cards/saflok.c @@ -347,8 +347,8 @@ bool saflok_parse(const NfcDevice* device, FuriString* parsed_data) { uint8_t interval_minute = decodedBA[10] & 0x3F; // Bytes 11-13: Creation date since 1980 Jan 1st - uint16_t creation_year = (((decodedBA[11] & 0xF0) >> 4) + SAFLOK_YEAR_OFFSET) | - creation_year_bits; + uint16_t creation_year = + (creation_year_bits | ((decodedBA[11] & 0xF0) >> 4)) + SAFLOK_YEAR_OFFSET; uint8_t creation_month = decodedBA[11] & 0x0F; uint8_t creation_day = (decodedBA[12] >> 3) & 0x1F; uint8_t creation_hour = ((decodedBA[12] & 0x07) << 2) | (decodedBA[13] >> 6); From 610fd68b7572cd502d385c5f84d8ad2ae02b585e Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 30 Jul 2025 04:59:05 +0300 Subject: [PATCH 11/31] RFID: Add additional procotols supported by EM4305 chipset by jamisonderek --- lib/lfrfid/protocols/protocol_electra.c | 3 +-- lib/lfrfid/protocols/protocol_fdx_b.c | 15 ++++++++++++ lib/lfrfid/protocols/protocol_gproxii.c | 14 +++++++++++ lib/lfrfid/protocols/protocol_jablotron.c | 13 ++++++++++ lib/lfrfid/protocols/protocol_securakey.c | 29 +++++++++++++++++++++++ 5 files changed, 72 insertions(+), 2 deletions(-) diff --git a/lib/lfrfid/protocols/protocol_electra.c b/lib/lfrfid/protocols/protocol_electra.c index 50d82c8f1..d107cd6e3 100644 --- a/lib/lfrfid/protocols/protocol_electra.c +++ b/lib/lfrfid/protocols/protocol_electra.c @@ -406,8 +406,7 @@ bool protocol_electra_write_data(ProtocolElectra* protocol, void* data) { request->t5577.block[4] = protocol->encoded_epilogue & 0xFFFFFFFF; request->t5577.blocks_to_write = 5; result = true; - } - if(request->write_type == LFRFIDWriteTypeEM4305) { + } else if(request->write_type == LFRFIDWriteTypeEM4305) { request->em4305.word[4] = (EM4x05_MODULATION_MANCHESTER | EM4x05_SET_BITRATE(64) | (8 << EM4x05_MAXBLOCK_SHIFT)); uint64_t encoded_data_reversed = 0; diff --git a/lib/lfrfid/protocols/protocol_fdx_b.c b/lib/lfrfid/protocols/protocol_fdx_b.c index 3de2b661b..df37a7e0f 100644 --- a/lib/lfrfid/protocols/protocol_fdx_b.c +++ b/lib/lfrfid/protocols/protocol_fdx_b.c @@ -369,6 +369,21 @@ bool protocol_fdx_b_write_data(ProtocolFDXB* protocol, void* data) { request->t5577.block[4] = bit_lib_get_bits_32(protocol->encoded_data, 96, 32); request->t5577.blocks_to_write = 5; result = true; + } else if(request->write_type == LFRFIDWriteTypeEM4305) { + request->em4305.word[4] = + (EM4x05_MODULATION_BIPHASE | EM4x05_SET_BITRATE(32) | (8 << EM4x05_MAXBLOCK_SHIFT)); + uint32_t encoded_data_reversed[4] = {0}; + for(uint8_t i = 0; i < 128; i++) { + encoded_data_reversed[i / 32] = + (encoded_data_reversed[i / 32] << 1) | + (bit_lib_get_bit(protocol->encoded_data, (127 - i)) & 1); + } + request->em4305.word[5] = encoded_data_reversed[3]; + request->em4305.word[6] = encoded_data_reversed[2]; + request->em4305.word[7] = encoded_data_reversed[1]; + request->em4305.word[8] = encoded_data_reversed[0]; + request->em4305.mask = 0x1F0; + result = true; } return result; } diff --git a/lib/lfrfid/protocols/protocol_gproxii.c b/lib/lfrfid/protocols/protocol_gproxii.c index 341d092e9..18d20ee75 100644 --- a/lib/lfrfid/protocols/protocol_gproxii.c +++ b/lib/lfrfid/protocols/protocol_gproxii.c @@ -287,6 +287,20 @@ bool protocol_gproxii_write_data(ProtocolGProxII* protocol, void* data) { request->t5577.block[3] = bit_lib_get_bits_32(protocol->data, 64, 32); request->t5577.blocks_to_write = 4; result = true; + } else if(request->write_type == LFRFIDWriteTypeEM4305) { + request->em4305.word[4] = + (EM4x05_MODULATION_BIPHASE | EM4x05_SET_BITRATE(64) | (7 << EM4x05_MAXBLOCK_SHIFT)); + uint32_t encoded_data_reversed[3] = {0}; + for(uint8_t i = 0; i < 96; i++) { + encoded_data_reversed[i / 32] = (encoded_data_reversed[i / 32] << 1) | + (bit_lib_get_bit(protocol->data, (95 - i)) & 1); + encoded_data_reversed[i / 32] ^= 1; // Invert to make DIPHASE/BIPHASE. + } + request->em4305.word[5] = encoded_data_reversed[2]; + request->em4305.word[6] = encoded_data_reversed[1]; + request->em4305.word[7] = encoded_data_reversed[0]; + request->em4305.mask = 0xF0; + result = true; } return result; } diff --git a/lib/lfrfid/protocols/protocol_jablotron.c b/lib/lfrfid/protocols/protocol_jablotron.c index 643bb1be6..8e3628a3b 100644 --- a/lib/lfrfid/protocols/protocol_jablotron.c +++ b/lib/lfrfid/protocols/protocol_jablotron.c @@ -182,6 +182,19 @@ bool protocol_jablotron_write_data(ProtocolJablotron* protocol, void* data) { request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); request->t5577.blocks_to_write = 3; result = true; + } else if(request->write_type == LFRFIDWriteTypeEM4305) { + request->em4305.word[4] = + (EM4x05_MODULATION_BIPHASE | EM4x05_SET_BITRATE(64) | (6 << EM4x05_MAXBLOCK_SHIFT)); + uint32_t encoded_data_reversed[2] = {0}; + for(uint8_t i = 0; i < 64; i++) { + encoded_data_reversed[i / 32] = + (encoded_data_reversed[i / 32] << 1) | + (bit_lib_get_bit(protocol->encoded_data, (63 - i)) & 1); + } + request->em4305.word[5] = encoded_data_reversed[1]; + request->em4305.word[6] = encoded_data_reversed[0]; + request->em4305.mask = 0x70; + result = true; } return result; } diff --git a/lib/lfrfid/protocols/protocol_securakey.c b/lib/lfrfid/protocols/protocol_securakey.c index 947b68e72..9c9fb8ab1 100644 --- a/lib/lfrfid/protocols/protocol_securakey.c +++ b/lib/lfrfid/protocols/protocol_securakey.c @@ -328,6 +328,20 @@ bool protocol_securakey_write_data(ProtocolSecurakey* protocol, void* data) { request->t5577.block[2] = bit_lib_get_bits_32(protocol->RKKTH_encoded_data, 32, 32); request->t5577.blocks_to_write = 3; result = true; + } else if(request->write_type == LFRFIDWriteTypeEM4305) { + request->em4305.word[4] = + (EM4x05_MODULATION_MANCHESTER | EM4x05_SET_BITRATE(40) | // requires 330pF card + (6 << EM4x05_MAXBLOCK_SHIFT)); + uint32_t encoded_data_reversed[2] = {0}; + for(uint8_t i = 0; i < 64; i++) { + encoded_data_reversed[i / 32] = + (encoded_data_reversed[i / 32] << 1) | + (bit_lib_get_bit(protocol->RKKTH_encoded_data, (63 - i)) & 1); + } + request->em4305.word[5] = encoded_data_reversed[1]; + request->em4305.word[6] = encoded_data_reversed[0]; + request->em4305.mask = 0x70; + result = true; } } else { if(request->write_type == LFRFIDWriteTypeT5577) { @@ -340,6 +354,21 @@ bool protocol_securakey_write_data(ProtocolSecurakey* protocol, void* data) { request->t5577.block[3] = bit_lib_get_bits_32(protocol->RKKT_encoded_data, 64, 32); request->t5577.blocks_to_write = 4; result = true; + } else if(request->write_type == LFRFIDWriteTypeEM4305) { + request->em4305.word[4] = + (EM4x05_MODULATION_MANCHESTER | EM4x05_SET_BITRATE(40) | // requires 330pF card + (7 << EM4x05_MAXBLOCK_SHIFT)); + uint32_t encoded_data_reversed[3] = {0}; + for(uint8_t i = 0; i < 96; i++) { + encoded_data_reversed[i / 32] = + (encoded_data_reversed[i / 32] << 1) | + (bit_lib_get_bit(protocol->RKKT_encoded_data, (95 - i)) & 1); + } + request->em4305.word[5] = encoded_data_reversed[2]; + request->em4305.word[6] = encoded_data_reversed[1]; + request->em4305.word[7] = encoded_data_reversed[0]; + request->em4305.mask = 0xF0; + result = true; } } return result; From 7646902fdc9fda2d9080affa28240053aefe0bb3 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 30 Jul 2025 05:04:02 +0300 Subject: [PATCH 12/31] JS: Expose button event type in gui/widget button callback by WillyJL --- .../examples/apps/Scripts/js_examples/gui.js | 10 +++- .../{ => js_examples}/uart_echo_8e1.js | 0 .../system/js_app/modules/js_gui/widget.c | 53 ++++++++++++++----- .../create-fz-app/template/package.json | 2 +- .../js_app/packages/fz-sdk/gui/widget.d.ts | 6 ++- documentation/js/js_gui__widget.md | 17 ++++++ documentation/js/js_serial.md | 1 + 7 files changed, 72 insertions(+), 17 deletions(-) rename applications/system/js_app/examples/apps/Scripts/{ => js_examples}/uart_echo_8e1.js (100%) diff --git a/applications/system/js_app/examples/apps/Scripts/js_examples/gui.js b/applications/system/js_app/examples/apps/Scripts/js_examples/gui.js index bc63a7ef6..9b7042848 100644 --- a/applications/system/js_app/examples/apps/Scripts/js_examples/gui.js +++ b/applications/system/js_app/examples/apps/Scripts/js_examples/gui.js @@ -62,6 +62,12 @@ let views = { }), }; +// Enable illegal filename symbols since we're not choosing filenames, gives more flexibility +// Not available in all firmwares, good idea to check if it is supported +if (doesSdkSupport(["gui-textinput-illegalsymbols"])) { + views.keyboard.set("illegalSymbols", true); +} + // demo selector eventLoop.subscribe(views.demos.chosen, function (_sub, index, gui, eventLoop, views) { if (index === 0) { @@ -131,8 +137,8 @@ eventLoop.subscribe(gui.viewDispatcher.navigation, function (_sub, _, gui, views }, gui, views, eventLoop); // go to the demo chooser screen when the right key is pressed on the widget screen -eventLoop.subscribe(views.stopwatchWidget.button, function (_sub, buttonId, gui, views) { - if (buttonId === "right") +eventLoop.subscribe(views.stopwatchWidget.button, function (_sub, buttonEvent, gui, views) { + if (buttonEvent.key === "right" && buttonEvent.type === "short") gui.viewDispatcher.switchTo(views.demos); }, gui, views); diff --git a/applications/system/js_app/examples/apps/Scripts/uart_echo_8e1.js b/applications/system/js_app/examples/apps/Scripts/js_examples/uart_echo_8e1.js similarity index 100% rename from applications/system/js_app/examples/apps/Scripts/uart_echo_8e1.js rename to applications/system/js_app/examples/apps/Scripts/js_examples/uart_echo_8e1.js diff --git a/applications/system/js_app/modules/js_gui/widget.c b/applications/system/js_app/modules/js_gui/widget.c index bb2898030..47149b4ac 100644 --- a/applications/system/js_app/modules/js_gui/widget.c +++ b/applications/system/js_app/modules/js_gui/widget.c @@ -10,6 +10,11 @@ typedef struct { #define QUEUE_LEN 2 +typedef struct { + GuiButtonType key; + InputType type; +} JsWidgetButtonEvent; + /** * @brief Parses position (X and Y) from an element declaration object */ @@ -101,8 +106,11 @@ static bool element_get_text(struct mjs* mjs, mjs_val_t element, mjs_val_t* text * @brief Widget button element callback */ static void js_widget_button_callback(GuiButtonType result, InputType type, JsWidgetCtx* context) { - UNUSED(type); - furi_check(furi_message_queue_put(context->queue, &result, 0) == FuriStatusOk); + JsWidgetButtonEvent event = { + .key = result, + .type = type, + }; + furi_check(furi_message_queue_put(context->queue, &event, 0) == FuriStatusOk); } #define DESTRUCTURE_OR_RETURN(mjs, child_obj, part, ...) \ @@ -263,25 +271,44 @@ static mjs_val_t js_widget_button_event_transformer( FuriMessageQueue* queue, JsWidgetCtx* context) { UNUSED(context); - GuiButtonType btn_type; - furi_check(furi_message_queue_get(queue, &btn_type, 0) == FuriStatusOk); - const char* btn_name; - if(btn_type == GuiButtonTypeLeft) { - btn_name = "left"; - } else if(btn_type == GuiButtonTypeCenter) { - btn_name = "center"; - } else if(btn_type == GuiButtonTypeRight) { - btn_name = "right"; + JsWidgetButtonEvent event; + furi_check(furi_message_queue_get(queue, &event, 0) == FuriStatusOk); + const char* event_key; + if(event.key == GuiButtonTypeLeft) { + event_key = "left"; + } else if(event.key == GuiButtonTypeCenter) { + event_key = "center"; + } else if(event.key == GuiButtonTypeRight) { + event_key = "right"; } else { furi_crash(); } - return mjs_mk_string(mjs, btn_name, ~0, false); + const char* event_type; + if(event.type == InputTypePress) { + event_type = "press"; + } else if(event.type == InputTypeRelease) { + event_type = "release"; + } else if(event.type == InputTypeShort) { + event_type = "short"; + } else if(event.type == InputTypeLong) { + event_type = "long"; + } else if(event.type == InputTypeRepeat) { + event_type = "repeat"; + } else { + furi_crash(); + } + mjs_val_t obj = mjs_mk_object(mjs); + JS_ASSIGN_MULTI(mjs, obj) { + JS_FIELD("key", mjs_mk_string(mjs, event_key, ~0, true)); + JS_FIELD("type", mjs_mk_string(mjs, event_type, ~0, true)); + } + return obj; } static void* js_widget_custom_make(struct mjs* mjs, Widget* widget, mjs_val_t view_obj) { UNUSED(widget); JsWidgetCtx* context = malloc(sizeof(JsWidgetCtx)); - context->queue = furi_message_queue_alloc(QUEUE_LEN, sizeof(GuiButtonType)); + context->queue = furi_message_queue_alloc(QUEUE_LEN, sizeof(JsWidgetButtonEvent)); context->contract = (JsEventLoopContract){ .magic = JsForeignMagic_JsEventLoopContract, .object_type = JsEventLoopObjectTypeQueue, diff --git a/applications/system/js_app/packages/create-fz-app/template/package.json b/applications/system/js_app/packages/create-fz-app/template/package.json index 211411c73..a7f69cf22 100644 --- a/applications/system/js_app/packages/create-fz-app/template/package.json +++ b/applications/system/js_app/packages/create-fz-app/template/package.json @@ -6,7 +6,7 @@ "start": "npm run build && node node_modules/@darkflippers/fz-sdk-ul/sdk.js upload" }, "devDependencies": { - "@darkflippers/fz-sdk-ul": "^0.1", + "@next-flip/fz-sdk-mntm": "^0.3", "typescript": "^5.6.3" } } \ No newline at end of file diff --git a/applications/system/js_app/packages/fz-sdk/gui/widget.d.ts b/applications/system/js_app/packages/fz-sdk/gui/widget.d.ts index bf4aab22b..c524c53cb 100644 --- a/applications/system/js_app/packages/fz-sdk/gui/widget.d.ts +++ b/applications/system/js_app/packages/fz-sdk/gui/widget.d.ts @@ -58,12 +58,16 @@ type Element = StringMultilineElement type Props = {}; type Child = Element; +declare class ButtonEvent { + key: "left" | "center" | "right"; + type: "press" | "release" | "short" | "long" | "repeat"; +} declare class Widget extends View { /** * Event source for buttons. Only gets fired if there's a corresponding * button element. */ - button: Contract<"left" | "center" | "right">; + button: Contract; } declare class WidgetFactory extends ViewFactory { } declare const factory: WidgetFactory; diff --git a/documentation/js/js_gui__widget.md b/documentation/js/js_gui__widget.md index 9ea3e4dfa..4c922a67c 100644 --- a/documentation/js/js_gui__widget.md +++ b/documentation/js/js_gui__widget.md @@ -35,3 +35,20 @@ Elements are objects with properties to define them, in the form `{ element: "ty | `rect` | `x` (number), `y` (number)
`w` (number), `h` (number)
`radius` (number), `fill` (boolean) | Draw a rectangle, optionally rounded and filled. | | `circle` | `x` (number), `y` (number)
`radius` (number), `fill` (boolean) | Draw a circle, optionally filled. | | `line` | `x1` (number), `y1` (number)
`x2` (number), `y2` (number) | Draw a line between 2 points. | + +## Structures + +### ButtonEvent + +Button event information structure. + +**Fields** + +- key: The key that was pressed (`"left" | "center" | "right"`) +- type: The type of the event (`"press" | "release" | "short" | "long" | "repeat"`) + +## View events + +| Item | Type | Description | +|----------|--------|-----------------------------------------------------------------------------| +| `button` | `ButtonEvent`| Fires when the user presses on one of the three possible buttons if there's a corresponding button element. Refer to the `ButtonEvent` structure above for possible values. | diff --git a/documentation/js/js_serial.md b/documentation/js/js_serial.md index d06c799ac..c45ae5f74 100644 --- a/documentation/js/js_serial.md +++ b/documentation/js/js_serial.md @@ -7,6 +7,7 @@ let serial = require("serial"); ## setup() Configure serial port. Should be called before all other methods. +Automatically disables Expansion module service to prevent interference. **Parameters** From 979e428ad8b7ed381e69d0a8239019edba903e79 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 30 Jul 2025 06:01:45 +0300 Subject: [PATCH 13/31] upd changelog --- CHANGELOG.md | 66 +++++++--------------------------------------------- 1 file changed, 8 insertions(+), 58 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e33b7843f..18454fba1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,65 +1,15 @@ ## Main changes - Current API: 86.0 -* SubGHz: **Roger (static 28 bit) with add manually support** (by @xMasterX & @mishamyte) -* SubGHz: **V2 Phoenix full support** (button switch, add manually, counter decrypt/encrypt) (by @xMasterX & @RocketGod-git, original code by @Skorpionm) -* SubGHz: **Keeloq: Add support for - Motorline (with add manually support), Rosh, Pecinin, Rossi, Merlin, Steelmate** (by @xMasterX & @RocketGod-git) -* SubGHz: **Nero Radio static parse** and display more data -* SubGHz: Reduce less popular freqs in default hopper preset, **make it faster** -* SubGHz: **Marantec protocol implement CRC verification display and Add manually support** (by @xMasterX & @li0ard, original code by @Skorpionm) -* SubGHz: **Keeloq: Comunello - add manually support** -* iButton: **TM01x Dallas write support** (PR #899 | by @Leptopt1los) -* SubGHz: Rename and **extend Alarms, Sensors, Cars ignore options** (Alarms: Hollarm, GangQi | Cars: Kia, Starline, ScherKhan | Sensors: Magellan, Honeywell, Honeywell WDB (doorbells), Legrand (doorbells), Feron (RGB lights)) -* SubGHz: V2 Phoenix show counter value (upd: see above, now decrypted) -* SubGHz: **Add Keeloq IronLogic (aka IL100) smart clone remote copiers support** (thanks to Vitaly for RAWs) -* SubGHz: **Fix CAME 24bit decoder** -* SubGHz: Add 462.750 MHz & 868.46 MHz to default subghz freqs list -* SubGHz: **Tune Holtek HT12x to decode Holtek only** and not conflict with came 12bit -* SubGHz: Fix Rename scene bug, that was replacing file name with random name when Rename is opened then closed then opened again -* Display: Backlight option "always on" and RGB bug removed (PR #900 | by @Dmitry422) -* NFC: Ultralight C - Attempt of authentication with default key (PR #898 | by @mishamyte) -* System: Loader - Fix misplaced ApplicationBeforeLoad events (PR #905 | by @WillyJL) -* OFW PR 4210: Infrared: Add text scroll to remote buttons (by @956MB) -* NFC: - - **NFC Type 4 support + many other improvements** (by @WillyJL) - - New Type 4 Tag (NDEF on NTAG4xx / MIFARE DESFire) protocol, full support - - New NTAG4xx (NTAG413 DNA / NTAG424 DNA) protocol, only detection and basic info support - - NDEF parsing plugin supports Type 4 Tag protocol - - Show more version info for MIFARE Plus cards - - Improve detection/verification of MIFARE DESFire and MIFARE Plus SE - - Improve navigation for MIFARE Classic Update from / Write to Initial Card - - Refactor Write code for MIFARE Ultralight/Classic in NFC app helpers - - Cleanup event handling in NFC app - - NFC app uses a bit less RAM because of previous 2 points - - Refactor NXP Native Commands to share between protocols (used by MIFARE DESFire, MIFARE Plus, NTAG4xx) - - MIFARE DESFire poller API can now switch between native and ISO7816-wrapped commands - - Expand ISO14443-4A API with listener (emulation) support for sending responses to reader (except I-block chaining) - - Exposed some APIs for apps to use that were meant to be public: - - ISO14443-3A listener (emulation) - - ISO15693-3 device (data), poller (reading), listener (emulation) - - Cleanup/reorder protocol definitions for tidyness - - Ventra ULEV1 parser (by @hazardousvoltage) - - CSC Service Works parser (by @zinongli) - - Philips Sonicare parser (by @Sil333033) - - SmartRider parser (by @jaylikesbunda) +* SubGHz: Add variant of 'Add Manually' menu with manual editing for each value (PR #909 | by @MrLego8-9) +* OFW PR 4251: CLI: Fix long delay with quick connect/disconnect (by @WillyJL) +* LFRFID: Add additional procotols supported by EM4305 chipset (by @jamisonderek) * Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) ## Other changes -* BadUSB: Fix modifier keys with HOLD/RELEASE commands (by @WillyJL) -* Docs: Update doorhan programming instructions (by @li0ard) -* FuriHalSerial: Fix RXFNE interrupt hang, aka freezing with UART output when Expansion Modules are enabled (by @WillyJL) -* Expansion: add is_connected api (by @HaxSam & @WillyJL) -* RFID 125khz: Fix strange bug with LCD backlight going off after doing "Write" -* GUI: Added `submenu_remove_item()` to API, was needed for NFC Type 4 related changes (by @WillyJL) -* SubGHz: Fix possible frequency analyzer deadlock when holding Ok (by @WillyJL) -* RFID 125khz: Add DEZ10 representation to EM410X (by @realcatgirly) -* OFW PR 4205: fix sample durations when using external CC1101 (by @Aerosnail) -* OFW PR 4206: Stop JS PWM on exit (by @portasynthinca3) -* OFW PR 4212: Fixed inverted logic condition in subghz chat cli (by @GameLord2011) -* NFC: Fix clipper date timestamp (PR #903 | by @luu176) -* Desktop: DEBUG - fix desktop anim switch override by favourite apps -* CLI: Various fixes (by @WillyJL) -* BadUSB: Fix key combos main keys being case sensitive (by @WillyJL) -* System: log level none after update -* Docs: Some updates on subghz remotes programming +* Input Settings: Add Vibro Trigger option (by @956MB & @WillyJL) +* BT Remote: Add Rename Option (by @aaronjamt & @WillyJL) +* Simplify Bad USB BLE profile (by @aaronjamt & @WillyJL) +* NFC: Fix incorrect Saflok year formula (by @Eltrick) +* JS: Expose button event type in gui/widget button callback (by @WillyJL)

#### Known NFC post-refactor regressions list: - Mifare Mini clones reading is broken (original mini working fine) (OFW) From 9ab4fcb256ddda31d572c467e9c33623e01394a8 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 30 Jul 2025 06:03:25 +0300 Subject: [PATCH 14/31] fmt --- .../main/subghz/helpers/subghz_gen_info.c | 1408 ++++++++--------- .../main/subghz/helpers/subghz_gen_info.h | 2 +- .../subghz/scenes/subghz_scene_set_button.c | 72 +- .../subghz/scenes/subghz_scene_set_counter.c | 230 +-- .../main/subghz/scenes/subghz_scene_set_key.c | 7 +- .../subghz/scenes/subghz_scene_set_seed.c | 119 +- .../subghz/scenes/subghz_scene_set_serial.c | 122 +- .../subghz/scenes/subghz_scene_set_type.c | 225 +-- 8 files changed, 1088 insertions(+), 1097 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_gen_info.c b/applications/main/subghz/helpers/subghz_gen_info.c index 00ff43abc..f6abec0c6 100644 --- a/applications/main/subghz/helpers/subghz_gen_info.c +++ b/applications/main/subghz/helpers/subghz_gen_info.c @@ -2,14 +2,13 @@ #include "../helpers/subghz_txrx_create_protocol_key.h" #include - -void subghz_gen_info_reset(GenInfo *gen_info) { +void subghz_gen_info_reset(GenInfo* gen_info) { furi_assert(gen_info); memset(gen_info, 0, sizeof(GenInfo)); } void subghz_scene_set_type_fill_generation_infos(GenInfo* infos_dest, SetType type) { - GenInfo gen_info = { 0 }; + GenInfo gen_info = {0}; uint64_t key = (uint64_t)rand(); uint64_t gangqi_key; @@ -19,707 +18,706 @@ void subghz_scene_set_type_fill_generation_infos(GenInfo* infos_dest, SetType ty subghz_txrx_gen_key_marantec(&marantec_key); switch(type) { - case SetTypePricenton433: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_PRINCETON_NAME, - .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 - .data.bits = 24, - .data.te = 400}; - break; - case SetTypePricenton315: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 315000000, - .data.name = SUBGHZ_PROTOCOL_PRINCETON_NAME, - .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 - .data.bits = 24, - .data.te = 400}; - break; - case SetTypeNiceFlo12bit: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_NICE_FLO_NAME, - .data.key = (key & 0x00000FF0) | 0x1, // btn 0x1, 0x2, 0x4 - .data.bits = 12, - .data.te = 0}; - break; - case SetTypeNiceFlo24bit: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_NICE_FLO_NAME, - .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 - .data.bits = 24, - .data.te = 0}; - break; - case SetTypeCAME12bit: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_CAME_NAME, - .data.key = (key & 0x00000FF0) | 0x1, // btn 0x1, 0x2, 0x4 - .data.bits = 12, - .data.te = 0}; - break; - case SetTypeCAME24bit: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_CAME_NAME, - .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 - .data.bits = 24, - .data.te = 0}; - break; - case SetTypeCAME12bit868: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 868350000, - .data.name = SUBGHZ_PROTOCOL_CAME_NAME, - .data.key = (key & 0x00000FF0) | 0x1, // btn 0x1, 0x2, 0x4 - .data.bits = 12, - .data.te = 0}; - break; - case SetTypeCAME24bit868: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 868350000, - .data.name = SUBGHZ_PROTOCOL_CAME_NAME, - .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 - .data.bits = 24, - .data.te = 0}; - break; - case SetTypeRoger_433: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_ROGER_NAME, - .data.key = (key & 0xFFFF000) | 0x0000101, // button code 0x1 and (crc?) is 0x01 - .data.bits = 28, - .data.te = 0}; - break; - case SetTypeLinear_300_00: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 300000000, - .data.name = SUBGHZ_PROTOCOL_LINEAR_NAME, - .data.key = (key & 0x3FF), - .data.bits = 10, - .data.te = 0}; - break; - case SetTypeBETT_433: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_BETT_NAME, - .data.key = (key & 0x0000FFF0), - .data.bits = 18, - .data.te = 0}; - break; - case SetTypeCAMETwee: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_CAME_TWEE_NAME, - .data.key = 0x003FFF7200000000 | ((key & 0x0FFFFFF0) ^ 0xE0E0E0EE), // ???? - .data.bits = 54, - .data.te = 0}; - break; - case SetTypeGateTX: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_GATE_TX_NAME, // btn 0xF, 0xC, 0xA, 0x6 (?) - .data.key = subghz_protocol_blocks_reverse_key((key & 0x00F0FF00) | 0xF0040, 24), - .data.bits = 24, - .data.te = 0}; - break; - case SetTypeGangQi_433: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = - SUBGHZ_PROTOCOL_GANGQI_NAME, // Add button 0xD arm and crc sum to the end - .data.key = gangqi_key, - .data.bits = 34, - .data.te = 0}; - break; - case SetTypeHollarm_433: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_HOLLARM_NAME, // Add button 0x2 and crc sum to the end - .data.key = (key & 0x000FFF0000) | 0xF0B0002200 | - ((((((key & 0x000FFF0000) | 0xF0B0002200) >> 32) & 0xFF) + - ((((key & 0x000FFF0000) | 0xF0B0002200) >> 24) & 0xFF) + - ((((key & 0x000FFF0000) | 0xF0B0002200) >> 16) & 0xFF) + - ((((key & 0x000FFF0000) | 0xF0B0002200) >> 8) & 0xFF)) & - 0xFF), - .data.bits = 42, - .data.te = 0}; - break; - case SetTypeReversRB2_433: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = SUBGHZ_PROTOCOL_REVERSRB2_NAME, // 64bits no buttons - .data.key = (key & 0x00000FFFFFFFF000) | 0xFFFFF00000000000 | 0x0000000000000A00, - .data.bits = 64, - .data.te = 0}; - break; - case SetTypeMarantec24_868: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 868350000, - .data.name = SUBGHZ_PROTOCOL_MARANTEC24_NAME, // Add button code 0x8 to the end - .data.key = (key & 0xFFFFF0) | 0x000008, - .data.bits = 24, - .data.te = 0}; - break; - case SetTypeMarantec_433: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 433920000, - .data.name = - SUBGHZ_PROTOCOL_MARANTEC_NAME, // Button code is 0x4 and crc sum to the end - .data.key = marantec_key, - .data.bits = 49, - .data.te = 0}; - break; - case SetTypeMarantec_868: - gen_info = (GenInfo){ - .type = GenData, - .mod = "AM650", - .freq = 868350000, - .data.name = - SUBGHZ_PROTOCOL_MARANTEC_NAME, // Button code is 0x4 and crc sum to the end - .data.key = marantec_key, - .data.bits = 49, - .data.te = 0}; - break; - case SetTypeFaacSLH_433: - gen_info = (GenInfo){ - .type = GenFaacSLH, - .mod = "AM650", - .freq = 433920000, - .faac_slh.serial = ((key & 0x00FFFFF0) | 0xA0000006) >> 4, - .faac_slh.btn = 0x06, - .faac_slh.cnt = 0x02, - .faac_slh.seed = key, - .faac_slh.manuf = "FAAC_SLH"}; - break; - case SetTypeFaacSLH_868: - gen_info = (GenInfo){ - .type = GenFaacSLH, - .mod = "AM650", - .freq = 868350000, - .faac_slh.serial = ((key & 0x00FFFFF0) | 0xA0000006) >> 4, - .faac_slh.btn = 0x06, - .faac_slh.cnt = 0x02, - .faac_slh.seed = (key & 0x0FFFFFFF), - .faac_slh.manuf = "FAAC_SLH"}; - break; - case SetTypeBeninca433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x000FFF00) | 0x00800080, - .keeloq.btn = 0x01, - .keeloq.cnt = 0x05, - .keeloq.manuf = "Beninca"}; - break; - case SetTypeBeninca868: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 868350000, - .keeloq.serial = (key & 0x000FFF00) | 0x00800080, - .keeloq.btn = 0x01, - .keeloq.cnt = 0x05, - .keeloq.manuf = "Beninca"}; - break; - case SetTypeComunello433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x08, - .keeloq.cnt = 0x05, - .keeloq.manuf = "Comunello"}; - break; - case SetTypeComunello868: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 868460000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x08, - .keeloq.cnt = 0x05, - .keeloq.manuf = "Comunello"}; - break; - case SetTypeAllmatic433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x00FFFF00) | 0x01000011, - .keeloq.btn = 0x0C, - .keeloq.cnt = 0x05, - .keeloq.manuf = "Beninca"}; - break; - case SetTypeAllmatic868: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 868350000, - .keeloq.serial = (key & 0x00FFFF00) | 0x01000011, - .keeloq.btn = 0x0C, - .keeloq.cnt = 0x05, - .keeloq.manuf = "Beninca"}; - break; - case SetTypeCenturion433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x0000FFFF), - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Centurion"}; - break; - case SetTypeMonarch433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x0000FFFF), - .keeloq.btn = 0x0A, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Monarch"}; - break; - case SetTypeJollyMotors433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x000FFFFF), - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Jolly_Motors"}; - break; - case SetTypeElmesElectronic: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x00FFFFFF) | 0x02000000, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Elmes_Poland"}; - break; - case SetTypeANMotorsAT4: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x000FFFFF) | 0x04700000, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x21, - .keeloq.manuf = "AN-Motors"}; - break; - case SetTypeAprimatic: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x000FFFFF) | 0x00600000, - .keeloq.btn = 0x08, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Aprimatic"}; - break; - case SetTypeGibidi433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Gibidi"}; - break; - case SetTypeGSN: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x0FFFFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "GSN"}; - break; - case SetTypeIronLogic: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFF0, - .keeloq.btn = 0x04, - .keeloq.cnt = 0x05, - .keeloq.manuf = "IronLogic"}; - break; - case SetTypeStilmatic: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x0FFFFFFF, - .keeloq.btn = 0x01, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Stilmatic"}; - break; - case SetTypeSommer_FM_434: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "FM476", - .freq = 434420000, - .keeloq.serial = (key & 0x0000FFFF) | 0x01700000, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Sommer(fsk476)"}; - break; - case SetTypeSommer_FM_868: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "FM476", - .freq = 868800000, - .keeloq.serial = (key & 0x0000FFFF) | 0x01700000, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Sommer(fsk476)"}; - break; - case SetTypeSommer_FM238_434: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "FM238", - .freq = 434420000, - .keeloq.serial = key & 0x0000FFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Sommer(fsk476)"}; - break; - case SetTypeSommer_FM238_868: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "FM238", - .freq = 868800000, - .keeloq.serial = key & 0x0000FFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Sommer(fsk476)"}; - break; - case SetTypeDTMNeo433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x000FFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x05, - .keeloq.manuf = "DTM_Neo"}; - break; - case SetTypeCAMESpace: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x04, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Came_Space"}; - break; - case SetTypeCameAtomo433: - gen_info = (GenInfo){ - .type = GenCameAtomo, - .mod = "AM650", - .freq = 433920000, - .came_atomo.serial = (key & 0x0FFFFFFF) | 0x10000000, - .came_atomo.cnt = 0x03}; - break; - case SetTypeCameAtomo868: - gen_info = (GenInfo){ - .type = GenCameAtomo, - .mod = "AM650", - .freq = 868350000, - .came_atomo.serial = (key & 0x0FFFFFFF) | 0x10000000, - .came_atomo.cnt = 0x03}; - break; - case SetTypeBFTMitto: - gen_info = (GenInfo){ - .type = GenKeeloqBFT, - .mod = "AM650", - .freq = 433920000, - .keeloq_bft.serial = key & 0x000FFFFF, - .keeloq_bft.btn = 0x02, - .keeloq_bft.cnt = 0x02, - .keeloq_bft.seed = key & 0x000FFFFF, - .keeloq_bft.manuf = "BFT"}; - break; - case SetTypeAlutechAT4N: - gen_info = (GenInfo){ - .type = GenAlutechAt4n, - .mod = "AM650", - .freq = 433920000, - .alutech_at_4n.serial = (key & 0x000FFFFF) | 0x00100000, - .alutech_at_4n.btn = 0x44, - .alutech_at_4n.cnt = 0x03}; - break; - case SetTypeSomfyTelis: - gen_info = (GenInfo){ - .type = GenSomfyTelis, - .mod = "AM650", - .freq = 433420000, - .somfy_telis.serial = key & 0x00FFFFFF, - .somfy_telis.btn = 0x02, - .somfy_telis.cnt = 0x03}; - break; - case SetTypeMotorline433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x0FFFFFFF, - .keeloq.btn = 0x01, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Motorline"}; - break; - case SetTypeDoorHan_433_92: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x0FFFFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "DoorHan"}; - break; - case SetTypeDoorHan_315_00: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 315000000, - .keeloq.serial = key & 0x0FFFFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "DoorHan"}; - break; - case SetTypeNiceFlorS_433_92: - gen_info = (GenInfo){ - .type = GenNiceFlorS, - .mod = "AM650", - .freq = 433920000, - .nice_flor_s.serial = key & 0x0FFFFFFF, - .nice_flor_s.btn = 0x01, - .nice_flor_s.cnt = 0x03, - .nice_flor_s.nice_one = false}; - break; - case SetTypeNiceOne_433_92: - gen_info = (GenInfo){ - .type = GenNiceFlorS, - .mod = "AM650", - .freq = 433920000, - .nice_flor_s.serial = key & 0x0FFFFFFF, - .nice_flor_s.btn = 0x01, - .nice_flor_s.cnt = 0x03, - .nice_flor_s.nice_one = true}; - break; - case SetTypeNiceSmilo_433_92: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "NICE_Smilo"}; - break; - case SetTypeNiceMHouse_433_92: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x09, - .keeloq.cnt = 0x03, - .keeloq.manuf = "NICE_MHOUSE"}; - break; - case SetTypeDeaMio433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x0FFFF000) | 0x00000869, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Dea_Mio"}; - break; - case SetTypeGeniusBravo433: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x06, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Genius_Bravo"}; - break; - case SetTypeJCM_433_92: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x00FFFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "JCM_Tech"}; - break; - case SetTypeNovoferm_433_92: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x0000FFFF) | 0x018F0000, - .keeloq.btn = 0x01, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Novoferm"}; - break; - case SetTypeHormannEcoStar_433_92: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x000FFFFF) | 0x02200000, - .keeloq.btn = 0x04, - .keeloq.cnt = 0x03, - .keeloq.manuf = "EcoStar"}; - break; - case SetTypeFAACRCXT_433_92: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = (key & 0x0000FFFF) | 0x00100000, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "FAAC_RC,XT"}; - break; - case SetTypeFAACRCXT_868: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 868350000, - .keeloq.serial = (key & 0x0000FFFF) | 0x00100000, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "FAAC_RC,XT"}; - break; - case SetTypeNormstahl_433_92: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x0000FFFF, - .keeloq.btn = 0x04, - .keeloq.cnt = 0x03, - .keeloq.manuf = "Normstahl"}; - break; - case SetTypeHCS101_433_92: - gen_info = (GenInfo){ - .type = GenKeeloq, - .mod = "AM650", - .freq = 433920000, - .keeloq.serial = key & 0x000FFFFF, - .keeloq.btn = 0x02, - .keeloq.cnt = 0x03, - .keeloq.manuf = "HCS101"}; - break; - case SetTypeSecPlus_v1_315_00: - gen_info = (GenInfo){.type = GenSecPlus1, .mod = "AM650", .freq = 315000000}; - break; - case SetTypeSecPlus_v1_390_00: - gen_info = (GenInfo){.type = GenSecPlus1, .mod = "AM650", .freq = 390000000}; - break; - case SetTypeSecPlus_v1_433_00: - gen_info = (GenInfo){.type = GenSecPlus1, .mod = "AM650", .freq = 433920000}; - break; - case SetTypeSecPlus_v2_310_00: - gen_info = (GenInfo){ - .type = GenSecPlus2, - .mod = "AM650", - .freq = 310000000, - .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing - .sec_plus_2.btn = 0x68, - .sec_plus_2.cnt = 0xE500000}; - break; - case SetTypeSecPlus_v2_315_00: - gen_info = (GenInfo){ - .type = GenSecPlus2, - .mod = "AM650", - .freq = 315000000, - .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing - .sec_plus_2.btn = 0x68, - .sec_plus_2.cnt = 0xE500000}; - break; - case SetTypeSecPlus_v2_390_00: - gen_info = (GenInfo){ - .type = GenSecPlus2, - .mod = "AM650", - .freq = 390000000, - .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing - .sec_plus_2.btn = 0x68, - .sec_plus_2.cnt = 0xE500000}; - break; - case SetTypeSecPlus_v2_433_00: - gen_info = (GenInfo){ - .type = GenSecPlus2, - .mod = "AM650", - .freq = 433920000, - .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing - .sec_plus_2.btn = 0x68, - .sec_plus_2.cnt = 0xE500000}; - break; - case SetTypePhoenix_V2_433: - gen_info = (GenInfo){ - .type = GenPhoenixV2, - .mod = "AM650", - .freq = 433920000, - .phoenix_v2.serial = (key & 0x0FFFFFFF) | 0xB0000000, - .phoenix_v2.cnt = 0x025D}; - break; - default: - furi_crash("Not implemented"); - break; - } + case SetTypePricenton433: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_PRINCETON_NAME, + .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 + .data.bits = 24, + .data.te = 400}; + break; + case SetTypePricenton315: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 315000000, + .data.name = SUBGHZ_PROTOCOL_PRINCETON_NAME, + .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 + .data.bits = 24, + .data.te = 400}; + break; + case SetTypeNiceFlo12bit: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_NICE_FLO_NAME, + .data.key = (key & 0x00000FF0) | 0x1, // btn 0x1, 0x2, 0x4 + .data.bits = 12, + .data.te = 0}; + break; + case SetTypeNiceFlo24bit: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_NICE_FLO_NAME, + .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 + .data.bits = 24, + .data.te = 0}; + break; + case SetTypeCAME12bit: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_CAME_NAME, + .data.key = (key & 0x00000FF0) | 0x1, // btn 0x1, 0x2, 0x4 + .data.bits = 12, + .data.te = 0}; + break; + case SetTypeCAME24bit: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_CAME_NAME, + .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 + .data.bits = 24, + .data.te = 0}; + break; + case SetTypeCAME12bit868: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 868350000, + .data.name = SUBGHZ_PROTOCOL_CAME_NAME, + .data.key = (key & 0x00000FF0) | 0x1, // btn 0x1, 0x2, 0x4 + .data.bits = 12, + .data.te = 0}; + break; + case SetTypeCAME24bit868: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 868350000, + .data.name = SUBGHZ_PROTOCOL_CAME_NAME, + .data.key = (key & 0x00FFFFF0) | 0x4, // btn 0x1, 0x2, 0x4, 0x8 + .data.bits = 24, + .data.te = 0}; + break; + case SetTypeRoger_433: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_ROGER_NAME, + .data.key = (key & 0xFFFF000) | 0x0000101, // button code 0x1 and (crc?) is 0x01 + .data.bits = 28, + .data.te = 0}; + break; + case SetTypeLinear_300_00: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 300000000, + .data.name = SUBGHZ_PROTOCOL_LINEAR_NAME, + .data.key = (key & 0x3FF), + .data.bits = 10, + .data.te = 0}; + break; + case SetTypeBETT_433: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_BETT_NAME, + .data.key = (key & 0x0000FFF0), + .data.bits = 18, + .data.te = 0}; + break; + case SetTypeCAMETwee: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_CAME_TWEE_NAME, + .data.key = 0x003FFF7200000000 | ((key & 0x0FFFFFF0) ^ 0xE0E0E0EE), // ???? + .data.bits = 54, + .data.te = 0}; + break; + case SetTypeGateTX: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_GATE_TX_NAME, // btn 0xF, 0xC, 0xA, 0x6 (?) + .data.key = subghz_protocol_blocks_reverse_key((key & 0x00F0FF00) | 0xF0040, 24), + .data.bits = 24, + .data.te = 0}; + break; + case SetTypeGangQi_433: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_GANGQI_NAME, // Add button 0xD arm and crc sum to the end + .data.key = gangqi_key, + .data.bits = 34, + .data.te = 0}; + break; + case SetTypeHollarm_433: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_HOLLARM_NAME, // Add button 0x2 and crc sum to the end + .data.key = (key & 0x000FFF0000) | 0xF0B0002200 | + ((((((key & 0x000FFF0000) | 0xF0B0002200) >> 32) & 0xFF) + + ((((key & 0x000FFF0000) | 0xF0B0002200) >> 24) & 0xFF) + + ((((key & 0x000FFF0000) | 0xF0B0002200) >> 16) & 0xFF) + + ((((key & 0x000FFF0000) | 0xF0B0002200) >> 8) & 0xFF)) & + 0xFF), + .data.bits = 42, + .data.te = 0}; + break; + case SetTypeReversRB2_433: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = SUBGHZ_PROTOCOL_REVERSRB2_NAME, // 64bits no buttons + .data.key = (key & 0x00000FFFFFFFF000) | 0xFFFFF00000000000 | 0x0000000000000A00, + .data.bits = 64, + .data.te = 0}; + break; + case SetTypeMarantec24_868: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 868350000, + .data.name = SUBGHZ_PROTOCOL_MARANTEC24_NAME, // Add button code 0x8 to the end + .data.key = (key & 0xFFFFF0) | 0x000008, + .data.bits = 24, + .data.te = 0}; + break; + case SetTypeMarantec_433: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 433920000, + .data.name = + SUBGHZ_PROTOCOL_MARANTEC_NAME, // Button code is 0x4 and crc sum to the end + .data.key = marantec_key, + .data.bits = 49, + .data.te = 0}; + break; + case SetTypeMarantec_868: + gen_info = (GenInfo){ + .type = GenData, + .mod = "AM650", + .freq = 868350000, + .data.name = + SUBGHZ_PROTOCOL_MARANTEC_NAME, // Button code is 0x4 and crc sum to the end + .data.key = marantec_key, + .data.bits = 49, + .data.te = 0}; + break; + case SetTypeFaacSLH_433: + gen_info = (GenInfo){ + .type = GenFaacSLH, + .mod = "AM650", + .freq = 433920000, + .faac_slh.serial = ((key & 0x00FFFFF0) | 0xA0000006) >> 4, + .faac_slh.btn = 0x06, + .faac_slh.cnt = 0x02, + .faac_slh.seed = key, + .faac_slh.manuf = "FAAC_SLH"}; + break; + case SetTypeFaacSLH_868: + gen_info = (GenInfo){ + .type = GenFaacSLH, + .mod = "AM650", + .freq = 868350000, + .faac_slh.serial = ((key & 0x00FFFFF0) | 0xA0000006) >> 4, + .faac_slh.btn = 0x06, + .faac_slh.cnt = 0x02, + .faac_slh.seed = (key & 0x0FFFFFFF), + .faac_slh.manuf = "FAAC_SLH"}; + break; + case SetTypeBeninca433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x000FFF00) | 0x00800080, + .keeloq.btn = 0x01, + .keeloq.cnt = 0x05, + .keeloq.manuf = "Beninca"}; + break; + case SetTypeBeninca868: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 868350000, + .keeloq.serial = (key & 0x000FFF00) | 0x00800080, + .keeloq.btn = 0x01, + .keeloq.cnt = 0x05, + .keeloq.manuf = "Beninca"}; + break; + case SetTypeComunello433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x08, + .keeloq.cnt = 0x05, + .keeloq.manuf = "Comunello"}; + break; + case SetTypeComunello868: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 868460000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x08, + .keeloq.cnt = 0x05, + .keeloq.manuf = "Comunello"}; + break; + case SetTypeAllmatic433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x00FFFF00) | 0x01000011, + .keeloq.btn = 0x0C, + .keeloq.cnt = 0x05, + .keeloq.manuf = "Beninca"}; + break; + case SetTypeAllmatic868: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 868350000, + .keeloq.serial = (key & 0x00FFFF00) | 0x01000011, + .keeloq.btn = 0x0C, + .keeloq.cnt = 0x05, + .keeloq.manuf = "Beninca"}; + break; + case SetTypeCenturion433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x0000FFFF), + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Centurion"}; + break; + case SetTypeMonarch433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x0000FFFF), + .keeloq.btn = 0x0A, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Monarch"}; + break; + case SetTypeJollyMotors433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x000FFFFF), + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Jolly_Motors"}; + break; + case SetTypeElmesElectronic: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x00FFFFFF) | 0x02000000, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Elmes_Poland"}; + break; + case SetTypeANMotorsAT4: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x000FFFFF) | 0x04700000, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x21, + .keeloq.manuf = "AN-Motors"}; + break; + case SetTypeAprimatic: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x000FFFFF) | 0x00600000, + .keeloq.btn = 0x08, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Aprimatic"}; + break; + case SetTypeGibidi433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Gibidi"}; + break; + case SetTypeGSN: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x0FFFFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "GSN"}; + break; + case SetTypeIronLogic: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFF0, + .keeloq.btn = 0x04, + .keeloq.cnt = 0x05, + .keeloq.manuf = "IronLogic"}; + break; + case SetTypeStilmatic: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x0FFFFFFF, + .keeloq.btn = 0x01, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Stilmatic"}; + break; + case SetTypeSommer_FM_434: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "FM476", + .freq = 434420000, + .keeloq.serial = (key & 0x0000FFFF) | 0x01700000, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Sommer(fsk476)"}; + break; + case SetTypeSommer_FM_868: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "FM476", + .freq = 868800000, + .keeloq.serial = (key & 0x0000FFFF) | 0x01700000, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Sommer(fsk476)"}; + break; + case SetTypeSommer_FM238_434: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "FM238", + .freq = 434420000, + .keeloq.serial = key & 0x0000FFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Sommer(fsk476)"}; + break; + case SetTypeSommer_FM238_868: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "FM238", + .freq = 868800000, + .keeloq.serial = key & 0x0000FFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Sommer(fsk476)"}; + break; + case SetTypeDTMNeo433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x000FFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x05, + .keeloq.manuf = "DTM_Neo"}; + break; + case SetTypeCAMESpace: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x04, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Came_Space"}; + break; + case SetTypeCameAtomo433: + gen_info = (GenInfo){ + .type = GenCameAtomo, + .mod = "AM650", + .freq = 433920000, + .came_atomo.serial = (key & 0x0FFFFFFF) | 0x10000000, + .came_atomo.cnt = 0x03}; + break; + case SetTypeCameAtomo868: + gen_info = (GenInfo){ + .type = GenCameAtomo, + .mod = "AM650", + .freq = 868350000, + .came_atomo.serial = (key & 0x0FFFFFFF) | 0x10000000, + .came_atomo.cnt = 0x03}; + break; + case SetTypeBFTMitto: + gen_info = (GenInfo){ + .type = GenKeeloqBFT, + .mod = "AM650", + .freq = 433920000, + .keeloq_bft.serial = key & 0x000FFFFF, + .keeloq_bft.btn = 0x02, + .keeloq_bft.cnt = 0x02, + .keeloq_bft.seed = key & 0x000FFFFF, + .keeloq_bft.manuf = "BFT"}; + break; + case SetTypeAlutechAT4N: + gen_info = (GenInfo){ + .type = GenAlutechAt4n, + .mod = "AM650", + .freq = 433920000, + .alutech_at_4n.serial = (key & 0x000FFFFF) | 0x00100000, + .alutech_at_4n.btn = 0x44, + .alutech_at_4n.cnt = 0x03}; + break; + case SetTypeSomfyTelis: + gen_info = (GenInfo){ + .type = GenSomfyTelis, + .mod = "AM650", + .freq = 433420000, + .somfy_telis.serial = key & 0x00FFFFFF, + .somfy_telis.btn = 0x02, + .somfy_telis.cnt = 0x03}; + break; + case SetTypeMotorline433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x0FFFFFFF, + .keeloq.btn = 0x01, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Motorline"}; + break; + case SetTypeDoorHan_433_92: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x0FFFFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "DoorHan"}; + break; + case SetTypeDoorHan_315_00: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 315000000, + .keeloq.serial = key & 0x0FFFFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "DoorHan"}; + break; + case SetTypeNiceFlorS_433_92: + gen_info = (GenInfo){ + .type = GenNiceFlorS, + .mod = "AM650", + .freq = 433920000, + .nice_flor_s.serial = key & 0x0FFFFFFF, + .nice_flor_s.btn = 0x01, + .nice_flor_s.cnt = 0x03, + .nice_flor_s.nice_one = false}; + break; + case SetTypeNiceOne_433_92: + gen_info = (GenInfo){ + .type = GenNiceFlorS, + .mod = "AM650", + .freq = 433920000, + .nice_flor_s.serial = key & 0x0FFFFFFF, + .nice_flor_s.btn = 0x01, + .nice_flor_s.cnt = 0x03, + .nice_flor_s.nice_one = true}; + break; + case SetTypeNiceSmilo_433_92: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "NICE_Smilo"}; + break; + case SetTypeNiceMHouse_433_92: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x09, + .keeloq.cnt = 0x03, + .keeloq.manuf = "NICE_MHOUSE"}; + break; + case SetTypeDeaMio433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x0FFFF000) | 0x00000869, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Dea_Mio"}; + break; + case SetTypeGeniusBravo433: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x06, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Genius_Bravo"}; + break; + case SetTypeJCM_433_92: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x00FFFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "JCM_Tech"}; + break; + case SetTypeNovoferm_433_92: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x0000FFFF) | 0x018F0000, + .keeloq.btn = 0x01, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Novoferm"}; + break; + case SetTypeHormannEcoStar_433_92: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x000FFFFF) | 0x02200000, + .keeloq.btn = 0x04, + .keeloq.cnt = 0x03, + .keeloq.manuf = "EcoStar"}; + break; + case SetTypeFAACRCXT_433_92: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = (key & 0x0000FFFF) | 0x00100000, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "FAAC_RC,XT"}; + break; + case SetTypeFAACRCXT_868: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 868350000, + .keeloq.serial = (key & 0x0000FFFF) | 0x00100000, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "FAAC_RC,XT"}; + break; + case SetTypeNormstahl_433_92: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x0000FFFF, + .keeloq.btn = 0x04, + .keeloq.cnt = 0x03, + .keeloq.manuf = "Normstahl"}; + break; + case SetTypeHCS101_433_92: + gen_info = (GenInfo){ + .type = GenKeeloq, + .mod = "AM650", + .freq = 433920000, + .keeloq.serial = key & 0x000FFFFF, + .keeloq.btn = 0x02, + .keeloq.cnt = 0x03, + .keeloq.manuf = "HCS101"}; + break; + case SetTypeSecPlus_v1_315_00: + gen_info = (GenInfo){.type = GenSecPlus1, .mod = "AM650", .freq = 315000000}; + break; + case SetTypeSecPlus_v1_390_00: + gen_info = (GenInfo){.type = GenSecPlus1, .mod = "AM650", .freq = 390000000}; + break; + case SetTypeSecPlus_v1_433_00: + gen_info = (GenInfo){.type = GenSecPlus1, .mod = "AM650", .freq = 433920000}; + break; + case SetTypeSecPlus_v2_310_00: + gen_info = (GenInfo){ + .type = GenSecPlus2, + .mod = "AM650", + .freq = 310000000, + .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing + .sec_plus_2.btn = 0x68, + .sec_plus_2.cnt = 0xE500000}; + break; + case SetTypeSecPlus_v2_315_00: + gen_info = (GenInfo){ + .type = GenSecPlus2, + .mod = "AM650", + .freq = 315000000, + .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing + .sec_plus_2.btn = 0x68, + .sec_plus_2.cnt = 0xE500000}; + break; + case SetTypeSecPlus_v2_390_00: + gen_info = (GenInfo){ + .type = GenSecPlus2, + .mod = "AM650", + .freq = 390000000, + .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing + .sec_plus_2.btn = 0x68, + .sec_plus_2.cnt = 0xE500000}; + break; + case SetTypeSecPlus_v2_433_00: + gen_info = (GenInfo){ + .type = GenSecPlus2, + .mod = "AM650", + .freq = 433920000, + .sec_plus_2.serial = (key & 0x7FFFF3FC), // 850LM pairing + .sec_plus_2.btn = 0x68, + .sec_plus_2.cnt = 0xE500000}; + break; + case SetTypePhoenix_V2_433: + gen_info = (GenInfo){ + .type = GenPhoenixV2, + .mod = "AM650", + .freq = 433920000, + .phoenix_v2.serial = (key & 0x0FFFFFFF) | 0xB0000000, + .phoenix_v2.cnt = 0x025D}; + break; + default: + furi_crash("Not implemented"); + break; + } *infos_dest = gen_info; } diff --git a/applications/main/subghz/helpers/subghz_gen_info.h b/applications/main/subghz/helpers/subghz_gen_info.h index 938c6d27a..003ab871a 100644 --- a/applications/main/subghz/helpers/subghz_gen_info.h +++ b/applications/main/subghz/helpers/subghz_gen_info.h @@ -79,6 +79,6 @@ typedef struct { }; } GenInfo; -void subghz_gen_info_reset(GenInfo *gen_info); +void subghz_gen_info_reset(GenInfo* gen_info); void subghz_scene_set_type_fill_generation_infos(GenInfo* infos_dest, SetType type); diff --git a/applications/main/subghz/scenes/subghz_scene_set_button.c b/applications/main/subghz/scenes/subghz_scene_set_button.c index cd5e11f47..c07b793e4 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_button.c +++ b/applications/main/subghz/scenes/subghz_scene_set_button.c @@ -16,42 +16,42 @@ void subghz_scene_set_button_on_enter(void* context) { uint8_t byte_count = 0; switch(subghz->gen_info->type) { - case GenFaacSLH: - byte_ptr = &subghz->gen_info->faac_slh.btn; - byte_count = sizeof(subghz->gen_info->faac_slh.btn); - break; - case GenKeeloq: - byte_ptr = &subghz->gen_info->keeloq.btn; - byte_count = sizeof(subghz->gen_info->keeloq.btn); - break; - case GenKeeloqBFT: - byte_ptr = &subghz->gen_info->keeloq_bft.btn; - byte_count = sizeof(subghz->gen_info->keeloq_bft.btn); - break; - case GenAlutechAt4n: - byte_ptr = &subghz->gen_info->alutech_at_4n.btn; - byte_count = sizeof(subghz->gen_info->alutech_at_4n.btn); - break; - case GenSomfyTelis: - byte_ptr = &subghz->gen_info->somfy_telis.btn; - byte_count = sizeof(subghz->gen_info->somfy_telis.btn); - break; - case GenNiceFlorS: - byte_ptr = &subghz->gen_info->nice_flor_s.btn; - byte_count = sizeof(subghz->gen_info->nice_flor_s.btn); - break; - case GenSecPlus2: - byte_ptr = &subghz->gen_info->sec_plus_2.btn; - byte_count = sizeof(subghz->gen_info->sec_plus_2.btn); - break; - // Not needed for these types - case GenPhoenixV2: - case GenData: - case GenSecPlus1: - case GenCameAtomo: - default: - furi_crash("Not implemented"); - break; + case GenFaacSLH: + byte_ptr = &subghz->gen_info->faac_slh.btn; + byte_count = sizeof(subghz->gen_info->faac_slh.btn); + break; + case GenKeeloq: + byte_ptr = &subghz->gen_info->keeloq.btn; + byte_count = sizeof(subghz->gen_info->keeloq.btn); + break; + case GenKeeloqBFT: + byte_ptr = &subghz->gen_info->keeloq_bft.btn; + byte_count = sizeof(subghz->gen_info->keeloq_bft.btn); + break; + case GenAlutechAt4n: + byte_ptr = &subghz->gen_info->alutech_at_4n.btn; + byte_count = sizeof(subghz->gen_info->alutech_at_4n.btn); + break; + case GenSomfyTelis: + byte_ptr = &subghz->gen_info->somfy_telis.btn; + byte_count = sizeof(subghz->gen_info->somfy_telis.btn); + break; + case GenNiceFlorS: + byte_ptr = &subghz->gen_info->nice_flor_s.btn; + byte_count = sizeof(subghz->gen_info->nice_flor_s.btn); + break; + case GenSecPlus2: + byte_ptr = &subghz->gen_info->sec_plus_2.btn; + byte_count = sizeof(subghz->gen_info->sec_plus_2.btn); + break; + // Not needed for these types + case GenPhoenixV2: + case GenData: + case GenSecPlus1: + case GenCameAtomo: + default: + furi_crash("Not implemented"); + break; } furi_assert(byte_ptr); diff --git a/applications/main/subghz/scenes/subghz_scene_set_counter.c b/applications/main/subghz/scenes/subghz_scene_set_counter.c index b9f241258..561c108eb 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_counter.c +++ b/applications/main/subghz/scenes/subghz_scene_set_counter.c @@ -16,48 +16,48 @@ void subghz_scene_set_counter_on_enter(void* context) { uint8_t byte_count = 0; switch(subghz->gen_info->type) { - case GenFaacSLH: - byte_ptr = &subghz->gen_info->faac_slh.cnt; - byte_count = sizeof(subghz->gen_info->faac_slh.cnt); - break; - case GenKeeloq: - byte_ptr = &subghz->gen_info->keeloq.cnt; - byte_count = sizeof(subghz->gen_info->keeloq.cnt); - break; - case GenCameAtomo: - byte_ptr = &subghz->gen_info->came_atomo.cnt; - byte_count = sizeof(subghz->gen_info->came_atomo.cnt); - break; - case GenKeeloqBFT: - byte_ptr = &subghz->gen_info->keeloq_bft.cnt; - byte_count = sizeof(subghz->gen_info->keeloq_bft.cnt); - break; - case GenAlutechAt4n: - byte_ptr = &subghz->gen_info->alutech_at_4n.cnt; - byte_count = sizeof(subghz->gen_info->alutech_at_4n.cnt); - break; - case GenSomfyTelis: - byte_ptr = &subghz->gen_info->somfy_telis.cnt; - byte_count = sizeof(subghz->gen_info->somfy_telis.cnt); - break; - case GenNiceFlorS: - byte_ptr = &subghz->gen_info->nice_flor_s.cnt; - byte_count = sizeof(subghz->gen_info->nice_flor_s.cnt); - break; - case GenSecPlus2: - byte_ptr = (uint8_t*)&subghz->gen_info->sec_plus_2.cnt; - byte_count = sizeof(subghz->gen_info->sec_plus_2.cnt); - break; - case GenPhoenixV2: - byte_ptr = (uint8_t*)&subghz->gen_info->phoenix_v2.cnt; - byte_count = sizeof(subghz->gen_info->phoenix_v2.cnt); - break; - // Not needed for these types - case GenData: - case GenSecPlus1: - default: - furi_crash("Not implemented"); - break; + case GenFaacSLH: + byte_ptr = &subghz->gen_info->faac_slh.cnt; + byte_count = sizeof(subghz->gen_info->faac_slh.cnt); + break; + case GenKeeloq: + byte_ptr = &subghz->gen_info->keeloq.cnt; + byte_count = sizeof(subghz->gen_info->keeloq.cnt); + break; + case GenCameAtomo: + byte_ptr = &subghz->gen_info->came_atomo.cnt; + byte_count = sizeof(subghz->gen_info->came_atomo.cnt); + break; + case GenKeeloqBFT: + byte_ptr = &subghz->gen_info->keeloq_bft.cnt; + byte_count = sizeof(subghz->gen_info->keeloq_bft.cnt); + break; + case GenAlutechAt4n: + byte_ptr = &subghz->gen_info->alutech_at_4n.cnt; + byte_count = sizeof(subghz->gen_info->alutech_at_4n.cnt); + break; + case GenSomfyTelis: + byte_ptr = &subghz->gen_info->somfy_telis.cnt; + byte_count = sizeof(subghz->gen_info->somfy_telis.cnt); + break; + case GenNiceFlorS: + byte_ptr = &subghz->gen_info->nice_flor_s.cnt; + byte_count = sizeof(subghz->gen_info->nice_flor_s.cnt); + break; + case GenSecPlus2: + byte_ptr = (uint8_t*)&subghz->gen_info->sec_plus_2.cnt; + byte_count = sizeof(subghz->gen_info->sec_plus_2.cnt); + break; + case GenPhoenixV2: + byte_ptr = (uint8_t*)&subghz->gen_info->phoenix_v2.cnt; + byte_count = sizeof(subghz->gen_info->phoenix_v2.cnt); + break; + // Not needed for these types + case GenData: + case GenSecPlus1: + default: + furi_crash("Not implemented"); + break; } furi_assert(byte_ptr); @@ -87,79 +87,79 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { GenInfo gen_info = *subghz->gen_info; switch(gen_info.type) { - case GenFaacSLH: - case GenKeeloqBFT: - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetSeed); - return true; - case GenKeeloq: - generated_protocol = subghz_txrx_gen_keeloq_protocol( - subghz->txrx, - gen_info.mod, - gen_info.freq, - gen_info.keeloq.serial, - gen_info.keeloq.btn, - gen_info.keeloq.cnt, - gen_info.keeloq.manuf); - break; - case GenCameAtomo: - generated_protocol = subghz_txrx_gen_came_atomo_protocol( - subghz->txrx, - gen_info.mod, - gen_info.freq, - gen_info.came_atomo.serial, - gen_info.came_atomo.cnt); - break; - case GenAlutechAt4n: - generated_protocol = subghz_txrx_gen_alutech_at_4n_protocol( - subghz->txrx, - gen_info.mod, - gen_info.freq, - gen_info.alutech_at_4n.serial, - gen_info.alutech_at_4n.btn, - gen_info.alutech_at_4n.cnt); - break; - case GenSomfyTelis: - generated_protocol = subghz_txrx_gen_somfy_telis_protocol( - subghz->txrx, - gen_info.mod, - gen_info.freq, - gen_info.somfy_telis.serial, - gen_info.somfy_telis.btn, - gen_info.somfy_telis.cnt); - break; - case GenNiceFlorS: - generated_protocol = subghz_txrx_gen_nice_flor_s_protocol( - subghz->txrx, - gen_info.mod, - gen_info.freq, - gen_info.nice_flor_s.serial, - gen_info.nice_flor_s.btn, - gen_info.nice_flor_s.cnt, - gen_info.nice_flor_s.nice_one); - break; - case GenSecPlus2: - generated_protocol = subghz_txrx_gen_secplus_v2_protocol( - subghz->txrx, - gen_info.mod, - gen_info.freq, - gen_info.sec_plus_2.serial, - gen_info.sec_plus_2.btn, - gen_info.sec_plus_2.cnt); - break; - case GenPhoenixV2: - generated_protocol = subghz_txrx_gen_phoenix_v2_protocol( - subghz->txrx, - gen_info.mod, - gen_info.freq, - gen_info.phoenix_v2.serial, - gen_info.phoenix_v2.cnt); - break; - // Not needed for these types - case GenData: - case GenSecPlus1: - default: - furi_crash("Not implemented"); - break; + case GenFaacSLH: + case GenKeeloqBFT: + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetSeed); + return true; + case GenKeeloq: + generated_protocol = subghz_txrx_gen_keeloq_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.keeloq.serial, + gen_info.keeloq.btn, + gen_info.keeloq.cnt, + gen_info.keeloq.manuf); + break; + case GenCameAtomo: + generated_protocol = subghz_txrx_gen_came_atomo_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.came_atomo.serial, + gen_info.came_atomo.cnt); + break; + case GenAlutechAt4n: + generated_protocol = subghz_txrx_gen_alutech_at_4n_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.alutech_at_4n.serial, + gen_info.alutech_at_4n.btn, + gen_info.alutech_at_4n.cnt); + break; + case GenSomfyTelis: + generated_protocol = subghz_txrx_gen_somfy_telis_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.somfy_telis.serial, + gen_info.somfy_telis.btn, + gen_info.somfy_telis.cnt); + break; + case GenNiceFlorS: + generated_protocol = subghz_txrx_gen_nice_flor_s_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.nice_flor_s.serial, + gen_info.nice_flor_s.btn, + gen_info.nice_flor_s.cnt, + gen_info.nice_flor_s.nice_one); + break; + case GenSecPlus2: + generated_protocol = subghz_txrx_gen_secplus_v2_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.sec_plus_2.serial, + gen_info.sec_plus_2.btn, + gen_info.sec_plus_2.cnt); + break; + case GenPhoenixV2: + generated_protocol = subghz_txrx_gen_phoenix_v2_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.phoenix_v2.serial, + gen_info.phoenix_v2.cnt); + break; + // Not needed for these types + case GenData: + case GenSecPlus1: + default: + furi_crash("Not implemented"); + break; } consumed = true; diff --git a/applications/main/subghz/scenes/subghz_scene_set_key.c b/applications/main/subghz/scenes/subghz_scene_set_key.c index f9872fb11..1cb2b6b21 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_key.c +++ b/applications/main/subghz/scenes/subghz_scene_set_key.c @@ -29,12 +29,7 @@ void subghz_scene_set_key_on_enter(void* context) { ByteInput* byte_input = subghz->byte_input; byte_input_set_header_text(byte_input, "Enter KEY in hex"); byte_input_set_result_callback( - byte_input, - subghz_scene_set_key_byte_input_callback, - NULL, - subghz, - byte_ptr, - byte_count); + byte_input, subghz_scene_set_key_byte_input_callback, NULL, subghz, byte_ptr, byte_count); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); } diff --git a/applications/main/subghz/scenes/subghz_scene_set_seed.c b/applications/main/subghz/scenes/subghz_scene_set_seed.c index 408460518..d52e4b674 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_seed.c +++ b/applications/main/subghz/scenes/subghz_scene_set_seed.c @@ -16,27 +16,27 @@ void subghz_scene_set_seed_on_enter(void* context) { uint8_t byte_count = 0; switch(subghz->gen_info->type) { - case GenFaacSLH: - byte_ptr = (uint8_t*)&subghz->gen_info->faac_slh.seed; - byte_count = sizeof(subghz->gen_info->faac_slh.seed); - break; - case GenKeeloqBFT: - byte_ptr = (uint8_t*)&subghz->gen_info->keeloq_bft.seed; - byte_count = sizeof(subghz->gen_info->keeloq_bft.seed); - break; - // Not needed for these types - case GenKeeloq: - case GenAlutechAt4n: - case GenSomfyTelis: - case GenNiceFlorS: - case GenSecPlus2: - case GenPhoenixV2: - case GenData: - case GenSecPlus1: - case GenCameAtomo: - default: - furi_crash("Not implemented"); - break; + case GenFaacSLH: + byte_ptr = (uint8_t*)&subghz->gen_info->faac_slh.seed; + byte_count = sizeof(subghz->gen_info->faac_slh.seed); + break; + case GenKeeloqBFT: + byte_ptr = (uint8_t*)&subghz->gen_info->keeloq_bft.seed; + byte_count = sizeof(subghz->gen_info->keeloq_bft.seed); + break; + // Not needed for these types + case GenKeeloq: + case GenAlutechAt4n: + case GenSomfyTelis: + case GenNiceFlorS: + case GenSecPlus2: + case GenPhoenixV2: + case GenData: + case GenSecPlus1: + case GenCameAtomo: + default: + furi_crash("Not implemented"); + break; } furi_assert(byte_ptr); @@ -46,12 +46,7 @@ void subghz_scene_set_seed_on_enter(void* context) { 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, - byte_ptr, - byte_count); + byte_input, subghz_scene_set_seed_byte_input_callback, NULL, subghz, byte_ptr, byte_count); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdByteInput); } @@ -64,41 +59,41 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) { GenInfo gen_info = *subghz->gen_info; switch(gen_info.type) { - case GenFaacSLH: - generated_protocol = subghz_txrx_gen_faac_slh_protocol( - subghz->txrx, - gen_info.mod, - gen_info.freq, - gen_info.faac_slh.serial, - gen_info.faac_slh.btn, - gen_info.faac_slh.cnt, - gen_info.faac_slh.seed, - gen_info.faac_slh.manuf); - break; - case GenKeeloqBFT: - generated_protocol = subghz_txrx_gen_keeloq_bft_protocol( - subghz->txrx, - gen_info.mod, - gen_info.freq, - gen_info.keeloq_bft.serial, - gen_info.keeloq_bft.btn, - gen_info.keeloq_bft.cnt, - gen_info.keeloq_bft.seed, - gen_info.keeloq_bft.manuf); - break; - // Not needed for these types - case GenKeeloq: - case GenAlutechAt4n: - case GenSomfyTelis: - case GenNiceFlorS: - case GenSecPlus2: - case GenPhoenixV2: - case GenData: - case GenSecPlus1: - case GenCameAtomo: - default: - furi_crash("Not implemented"); - break; + case GenFaacSLH: + generated_protocol = subghz_txrx_gen_faac_slh_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.faac_slh.serial, + gen_info.faac_slh.btn, + gen_info.faac_slh.cnt, + gen_info.faac_slh.seed, + gen_info.faac_slh.manuf); + break; + case GenKeeloqBFT: + generated_protocol = subghz_txrx_gen_keeloq_bft_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.keeloq_bft.serial, + gen_info.keeloq_bft.btn, + gen_info.keeloq_bft.cnt, + gen_info.keeloq_bft.seed, + gen_info.keeloq_bft.manuf); + break; + // Not needed for these types + case GenKeeloq: + case GenAlutechAt4n: + case GenSomfyTelis: + case GenNiceFlorS: + case GenSecPlus2: + case GenPhoenixV2: + case GenData: + case GenSecPlus1: + case GenCameAtomo: + default: + furi_crash("Not implemented"); + break; } consumed = true; diff --git a/applications/main/subghz/scenes/subghz_scene_set_serial.c b/applications/main/subghz/scenes/subghz_scene_set_serial.c index 42d815dd7..2168d2df1 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_serial.c +++ b/applications/main/subghz/scenes/subghz_scene_set_serial.c @@ -16,48 +16,48 @@ void subghz_scene_set_serial_on_enter(void* context) { uint8_t byte_count = 0; switch(subghz->gen_info->type) { - case GenFaacSLH: - byte_ptr = (uint8_t*)&subghz->gen_info->faac_slh.serial; - byte_count = sizeof(subghz->gen_info->faac_slh.serial); - break; - case GenKeeloq: - byte_ptr = (uint8_t*)&subghz->gen_info->keeloq.serial; - byte_count = sizeof(subghz->gen_info->keeloq.serial); - break; - case GenCameAtomo: - byte_ptr = (uint8_t*)&subghz->gen_info->came_atomo.serial; - byte_count = sizeof(subghz->gen_info->came_atomo.serial); - break; - case GenKeeloqBFT: - byte_ptr = (uint8_t*)&subghz->gen_info->keeloq_bft.serial; - byte_count = sizeof(subghz->gen_info->keeloq_bft.serial); - break; - case GenAlutechAt4n: - byte_ptr = (uint8_t*)&subghz->gen_info->alutech_at_4n.serial; - byte_count = sizeof(subghz->gen_info->alutech_at_4n.serial); - break; - case GenSomfyTelis: - byte_ptr = (uint8_t*)&subghz->gen_info->somfy_telis.serial; - byte_count = sizeof(subghz->gen_info->somfy_telis.serial); - break; - case GenNiceFlorS: - byte_ptr = (uint8_t*)&subghz->gen_info->nice_flor_s.serial; - byte_count = sizeof(subghz->gen_info->nice_flor_s.serial); - break; - case GenSecPlus2: - byte_ptr = (uint8_t*)&subghz->gen_info->sec_plus_2.serial; - byte_count = sizeof(subghz->gen_info->sec_plus_2.serial); - break; - case GenPhoenixV2: - byte_ptr = (uint8_t*)&subghz->gen_info->phoenix_v2.serial; - byte_count = sizeof(subghz->gen_info->phoenix_v2.serial); - break; - // Not needed for these types - case GenData: - case GenSecPlus1: - default: - furi_crash("Not implemented"); - break; + case GenFaacSLH: + byte_ptr = (uint8_t*)&subghz->gen_info->faac_slh.serial; + byte_count = sizeof(subghz->gen_info->faac_slh.serial); + break; + case GenKeeloq: + byte_ptr = (uint8_t*)&subghz->gen_info->keeloq.serial; + byte_count = sizeof(subghz->gen_info->keeloq.serial); + break; + case GenCameAtomo: + byte_ptr = (uint8_t*)&subghz->gen_info->came_atomo.serial; + byte_count = sizeof(subghz->gen_info->came_atomo.serial); + break; + case GenKeeloqBFT: + byte_ptr = (uint8_t*)&subghz->gen_info->keeloq_bft.serial; + byte_count = sizeof(subghz->gen_info->keeloq_bft.serial); + break; + case GenAlutechAt4n: + byte_ptr = (uint8_t*)&subghz->gen_info->alutech_at_4n.serial; + byte_count = sizeof(subghz->gen_info->alutech_at_4n.serial); + break; + case GenSomfyTelis: + byte_ptr = (uint8_t*)&subghz->gen_info->somfy_telis.serial; + byte_count = sizeof(subghz->gen_info->somfy_telis.serial); + break; + case GenNiceFlorS: + byte_ptr = (uint8_t*)&subghz->gen_info->nice_flor_s.serial; + byte_count = sizeof(subghz->gen_info->nice_flor_s.serial); + break; + case GenSecPlus2: + byte_ptr = (uint8_t*)&subghz->gen_info->sec_plus_2.serial; + byte_count = sizeof(subghz->gen_info->sec_plus_2.serial); + break; + case GenPhoenixV2: + byte_ptr = (uint8_t*)&subghz->gen_info->phoenix_v2.serial; + byte_count = sizeof(subghz->gen_info->phoenix_v2.serial); + break; + // Not needed for these types + case GenData: + case GenSecPlus1: + default: + furi_crash("Not implemented"); + break; } furi_assert(byte_ptr); @@ -83,25 +83,25 @@ bool subghz_scene_set_serial_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventByteInputDone) { switch(subghz->gen_info->type) { - case GenFaacSLH: - case GenKeeloq: - case GenKeeloqBFT: - case GenAlutechAt4n: - case GenSomfyTelis: - case GenNiceFlorS: - case GenSecPlus2: - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetButton); - break; - case GenCameAtomo: - case GenPhoenixV2: - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetCounter); - break; - // Not needed for these types - case GenData: - case GenSecPlus1: - default: - furi_crash("Not implemented"); - break; + case GenFaacSLH: + case GenKeeloq: + case GenKeeloqBFT: + case GenAlutechAt4n: + case GenSomfyTelis: + case GenNiceFlorS: + case GenSecPlus2: + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetButton); + break; + case GenCameAtomo: + case GenPhoenixV2: + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetCounter); + break; + // Not needed for these types + case GenData: + case GenSecPlus1: + default: + furi_crash("Not implemented"); + break; } consumed = true; diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 61e5148de..446c46a83 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -106,126 +106,125 @@ bool subghz_scene_set_type_generate_protocol_from_infos(SubGhz* subghz) { GenInfo gen_info = *subghz->gen_info; bool generated_protocol = false; switch(gen_info.type) { - case GenData: - if(gen_info.data.te) { - generated_protocol = subghz_txrx_gen_data_protocol_and_te( - subghz->txrx, - gen_info.mod, - gen_info.freq, - gen_info.data.name, - gen_info.data.key, - gen_info.data.bits, - gen_info.data.te); - } else { - generated_protocol = subghz_txrx_gen_data_protocol( - subghz->txrx, - gen_info.mod, - gen_info.freq, - gen_info.data.name, - gen_info.data.key, - gen_info.data.bits); - } - break; - case GenFaacSLH: - generated_protocol = subghz_txrx_gen_faac_slh_protocol( + case GenData: + if(gen_info.data.te) { + generated_protocol = subghz_txrx_gen_data_protocol_and_te( subghz->txrx, gen_info.mod, gen_info.freq, - gen_info.faac_slh.serial, - gen_info.faac_slh.btn, - gen_info.faac_slh.cnt, - gen_info.faac_slh.seed, - gen_info.faac_slh.manuf); - break; - case GenKeeloq: - generated_protocol = subghz_txrx_gen_keeloq_protocol( + gen_info.data.name, + gen_info.data.key, + gen_info.data.bits, + gen_info.data.te); + } else { + generated_protocol = subghz_txrx_gen_data_protocol( subghz->txrx, gen_info.mod, gen_info.freq, - gen_info.keeloq.serial, - gen_info.keeloq.btn, - gen_info.keeloq.cnt, - gen_info.keeloq.manuf); - break; - case GenCameAtomo: - generated_protocol = subghz_txrx_gen_came_atomo_protocol( - subghz->txrx, - gen_info.mod, - gen_info.freq, - gen_info.came_atomo.serial, - gen_info.came_atomo.cnt); - break; - case GenKeeloqBFT: - generated_protocol = subghz_txrx_gen_keeloq_bft_protocol( - subghz->txrx, - gen_info.mod, - gen_info.freq, - gen_info.keeloq_bft.serial, - gen_info.keeloq_bft.btn, - gen_info.keeloq_bft.cnt, - gen_info.keeloq_bft.seed, - gen_info.keeloq_bft.manuf); - break; - case GenAlutechAt4n: - generated_protocol = subghz_txrx_gen_alutech_at_4n_protocol( - subghz->txrx, - gen_info.mod, - gen_info.freq, - gen_info.alutech_at_4n.serial, - gen_info.alutech_at_4n.btn, - gen_info.alutech_at_4n.cnt); - break; - case GenSomfyTelis: - generated_protocol = subghz_txrx_gen_somfy_telis_protocol( - subghz->txrx, - gen_info.mod, - gen_info.freq, - gen_info.somfy_telis.serial, - gen_info.somfy_telis.btn, - gen_info.somfy_telis.cnt); - break; - case GenNiceFlorS: - generated_protocol = subghz_txrx_gen_nice_flor_s_protocol( - subghz->txrx, - gen_info.mod, - gen_info.freq, - gen_info.nice_flor_s.serial, - gen_info.nice_flor_s.btn, - gen_info.nice_flor_s.cnt, - gen_info.nice_flor_s.nice_one); - break; - case GenSecPlus1: - generated_protocol = - subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, gen_info.mod, gen_info.freq); - break; - case GenSecPlus2: - generated_protocol = subghz_txrx_gen_secplus_v2_protocol( - subghz->txrx, - gen_info.mod, - gen_info.freq, - gen_info.sec_plus_2.serial, - gen_info.sec_plus_2.btn, - gen_info.sec_plus_2.cnt); - break; - case GenPhoenixV2: - generated_protocol = subghz_txrx_gen_phoenix_v2_protocol( - subghz->txrx, - gen_info.mod, - gen_info.freq, - gen_info.phoenix_v2.serial, - gen_info.phoenix_v2.cnt); - break; - default: - furi_crash("Not implemented"); - break; + gen_info.data.name, + gen_info.data.key, + gen_info.data.bits); + } + break; + case GenFaacSLH: + generated_protocol = subghz_txrx_gen_faac_slh_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.faac_slh.serial, + gen_info.faac_slh.btn, + gen_info.faac_slh.cnt, + gen_info.faac_slh.seed, + gen_info.faac_slh.manuf); + break; + case GenKeeloq: + generated_protocol = subghz_txrx_gen_keeloq_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.keeloq.serial, + gen_info.keeloq.btn, + gen_info.keeloq.cnt, + gen_info.keeloq.manuf); + break; + case GenCameAtomo: + generated_protocol = subghz_txrx_gen_came_atomo_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.came_atomo.serial, + gen_info.came_atomo.cnt); + break; + case GenKeeloqBFT: + generated_protocol = subghz_txrx_gen_keeloq_bft_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.keeloq_bft.serial, + gen_info.keeloq_bft.btn, + gen_info.keeloq_bft.cnt, + gen_info.keeloq_bft.seed, + gen_info.keeloq_bft.manuf); + break; + case GenAlutechAt4n: + generated_protocol = subghz_txrx_gen_alutech_at_4n_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.alutech_at_4n.serial, + gen_info.alutech_at_4n.btn, + gen_info.alutech_at_4n.cnt); + break; + case GenSomfyTelis: + generated_protocol = subghz_txrx_gen_somfy_telis_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.somfy_telis.serial, + gen_info.somfy_telis.btn, + gen_info.somfy_telis.cnt); + break; + case GenNiceFlorS: + generated_protocol = subghz_txrx_gen_nice_flor_s_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.nice_flor_s.serial, + gen_info.nice_flor_s.btn, + gen_info.nice_flor_s.cnt, + gen_info.nice_flor_s.nice_one); + break; + case GenSecPlus1: + generated_protocol = + subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, gen_info.mod, gen_info.freq); + break; + case GenSecPlus2: + generated_protocol = subghz_txrx_gen_secplus_v2_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.sec_plus_2.serial, + gen_info.sec_plus_2.btn, + gen_info.sec_plus_2.cnt); + break; + case GenPhoenixV2: + generated_protocol = subghz_txrx_gen_phoenix_v2_protocol( + subghz->txrx, + gen_info.mod, + gen_info.freq, + gen_info.phoenix_v2.serial, + gen_info.phoenix_v2.cnt); + break; + default: + furi_crash("Not implemented"); + break; } if(generated_protocol) { subghz_file_name_clear(subghz); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); } else { - furi_string_set( - subghz->error_str, "Function requires\nan SD card with\nfresh databases."); + furi_string_set(subghz->error_str, "Function requires\nan SD card with\nfresh databases."); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); } return generated_protocol; @@ -244,15 +243,19 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { subghz_gen_info_reset(subghz->gen_info); subghz_scene_set_type_fill_generation_infos(subghz->gen_info, event.event); - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneStart) == SubmenuIndexAddManually) { + if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneStart) == + SubmenuIndexAddManually) { generated_protocol = subghz_scene_set_type_generate_protocol_from_infos(subghz); - } else if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneStart) == SubmenuIndexAddManuallyAdvanced) { + } else if( + scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneStart) == + SubmenuIndexAddManuallyAdvanced) { switch(subghz->gen_info->type) { case GenData: // Key (u64) scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetKey); break; case GenSecPlus1: // None - return subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, subghz->gen_info->mod, subghz->gen_info->freq); + return subghz_txrx_gen_secplus_v1_protocol( + subghz->txrx, subghz->gen_info->mod, subghz->gen_info->freq); case GenFaacSLH: // Serial (u32), Button (u8), Counter (u8), Seed (u32) case GenKeeloq: // Serial (u32), Button (u8), Counter (u8) case GenCameAtomo: // Serial (u32), Counter (u8) From 2c0b7caf55f57916991a4a74c5c5bf8b16abbd85 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 31 Jul 2025 00:26:31 +0300 Subject: [PATCH 15/31] Better add manually advanced --- .../subghz/scenes/subghz_scene_set_counter.c | 26 ++++++++++++------- .../main/subghz/scenes/subghz_scene_set_key.c | 8 ++++-- .../subghz/scenes/subghz_scene_set_seed.c | 12 ++++++--- .../subghz/scenes/subghz_scene_set_serial.c | 4 +++ .../subghz/scenes/subghz_scene_set_type.c | 4 +-- 5 files changed, 37 insertions(+), 17 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_set_counter.c b/applications/main/subghz/scenes/subghz_scene_set_counter.c index 561c108eb..8f61c2285 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_counter.c +++ b/applications/main/subghz/scenes/subghz_scene_set_counter.c @@ -1,6 +1,8 @@ #include "../subghz_i.h" #include "../helpers/subghz_txrx_create_protocol_key.h" +#include + #define TAG "SubGhzSetCounter" void subghz_scene_set_counter_byte_input_callback(void* context) { @@ -63,6 +65,12 @@ void subghz_scene_set_counter_on_enter(void* context) { furi_assert(byte_ptr); furi_assert(byte_count > 0); + if(byte_count == 2) { + *((uint16_t*)byte_ptr) = __bswap16(*((uint16_t*)byte_ptr)); // Convert + } else if(byte_count == 4) { + *((uint32_t*)byte_ptr) = __bswap32(*((uint32_t*)byte_ptr)); // Convert + } + // Setup view ByteInput* byte_input = subghz->byte_input; byte_input_set_header_text(byte_input, "Enter COUNTER in hex"); @@ -96,7 +104,7 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { subghz->txrx, gen_info.mod, gen_info.freq, - gen_info.keeloq.serial, + __bswap32(gen_info.keeloq.serial), gen_info.keeloq.btn, gen_info.keeloq.cnt, gen_info.keeloq.manuf); @@ -106,7 +114,7 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { subghz->txrx, gen_info.mod, gen_info.freq, - gen_info.came_atomo.serial, + __bswap32(gen_info.came_atomo.serial), gen_info.came_atomo.cnt); break; case GenAlutechAt4n: @@ -114,7 +122,7 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { subghz->txrx, gen_info.mod, gen_info.freq, - gen_info.alutech_at_4n.serial, + __bswap32(gen_info.alutech_at_4n.serial), gen_info.alutech_at_4n.btn, gen_info.alutech_at_4n.cnt); break; @@ -123,7 +131,7 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { subghz->txrx, gen_info.mod, gen_info.freq, - gen_info.somfy_telis.serial, + __bswap32(gen_info.somfy_telis.serial), gen_info.somfy_telis.btn, gen_info.somfy_telis.cnt); break; @@ -132,7 +140,7 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { subghz->txrx, gen_info.mod, gen_info.freq, - gen_info.nice_flor_s.serial, + __bswap32(gen_info.nice_flor_s.serial), gen_info.nice_flor_s.btn, gen_info.nice_flor_s.cnt, gen_info.nice_flor_s.nice_one); @@ -142,17 +150,17 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { subghz->txrx, gen_info.mod, gen_info.freq, - gen_info.sec_plus_2.serial, + __bswap32(gen_info.sec_plus_2.serial), gen_info.sec_plus_2.btn, - gen_info.sec_plus_2.cnt); + __bswap32(gen_info.sec_plus_2.cnt)); break; case GenPhoenixV2: generated_protocol = subghz_txrx_gen_phoenix_v2_protocol( subghz->txrx, gen_info.mod, gen_info.freq, - gen_info.phoenix_v2.serial, - gen_info.phoenix_v2.cnt); + __bswap32(gen_info.phoenix_v2.serial), + __bswap16(gen_info.phoenix_v2.cnt)); break; // Not needed for these types case GenData: diff --git a/applications/main/subghz/scenes/subghz_scene_set_key.c b/applications/main/subghz/scenes/subghz_scene_set_key.c index 1cb2b6b21..71c57c5f9 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_key.c +++ b/applications/main/subghz/scenes/subghz_scene_set_key.c @@ -1,6 +1,8 @@ #include "../subghz_i.h" #include "../helpers/subghz_txrx_create_protocol_key.h" +#include + #define TAG "SubGhzSetKey" void subghz_scene_set_key_byte_input_callback(void* context) { @@ -25,6 +27,8 @@ void subghz_scene_set_key_on_enter(void* context) { furi_assert(byte_ptr); furi_assert(byte_count > 0); + *((uint64_t*)byte_ptr) = __bswap64(*((uint64_t*)byte_ptr)); // Convert + // Setup view ByteInput* byte_input = subghz->byte_input; byte_input_set_header_text(byte_input, "Enter KEY in hex"); @@ -49,7 +53,7 @@ bool subghz_scene_set_key_on_event(void* context, SceneManagerEvent event) { gen_info.mod, gen_info.freq, gen_info.data.name, - gen_info.data.key, + __bswap64(gen_info.data.key), gen_info.data.bits, gen_info.data.te); } else { @@ -58,7 +62,7 @@ bool subghz_scene_set_key_on_event(void* context, SceneManagerEvent event) { gen_info.mod, gen_info.freq, gen_info.data.name, - gen_info.data.key, + __bswap64(gen_info.data.key), gen_info.data.bits); } } diff --git a/applications/main/subghz/scenes/subghz_scene_set_seed.c b/applications/main/subghz/scenes/subghz_scene_set_seed.c index d52e4b674..bebab6c27 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_seed.c +++ b/applications/main/subghz/scenes/subghz_scene_set_seed.c @@ -1,6 +1,8 @@ #include "../subghz_i.h" #include "../helpers/subghz_txrx_create_protocol_key.h" +#include + #define TAG "SubGhzSetSeed" void subghz_scene_set_seed_byte_input_callback(void* context) { @@ -42,6 +44,8 @@ void subghz_scene_set_seed_on_enter(void* context) { furi_assert(byte_ptr); furi_assert(byte_count > 0); + *((uint32_t*)byte_ptr) = __bswap32(*((uint32_t*)byte_ptr)); // Convert + // Setup view ByteInput* byte_input = subghz->byte_input; byte_input_set_header_text(byte_input, "Enter SEED in hex"); @@ -64,10 +68,10 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) { subghz->txrx, gen_info.mod, gen_info.freq, - gen_info.faac_slh.serial, + __bswap32(gen_info.faac_slh.serial), gen_info.faac_slh.btn, gen_info.faac_slh.cnt, - gen_info.faac_slh.seed, + __bswap32(gen_info.faac_slh.seed), gen_info.faac_slh.manuf); break; case GenKeeloqBFT: @@ -75,10 +79,10 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) { subghz->txrx, gen_info.mod, gen_info.freq, - gen_info.keeloq_bft.serial, + __bswap32(gen_info.keeloq_bft.serial), gen_info.keeloq_bft.btn, gen_info.keeloq_bft.cnt, - gen_info.keeloq_bft.seed, + __bswap32(gen_info.keeloq_bft.seed), gen_info.keeloq_bft.manuf); break; // Not needed for these types diff --git a/applications/main/subghz/scenes/subghz_scene_set_serial.c b/applications/main/subghz/scenes/subghz_scene_set_serial.c index 2168d2df1..6684e35a4 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_serial.c +++ b/applications/main/subghz/scenes/subghz_scene_set_serial.c @@ -1,6 +1,8 @@ #include "../subghz_i.h" #include "../helpers/subghz_txrx_create_protocol_key.h" +#include + #define TAG "SubGhzSetSerial" void subghz_scene_set_serial_byte_input_callback(void* context) { @@ -63,6 +65,8 @@ void subghz_scene_set_serial_on_enter(void* context) { furi_assert(byte_ptr); furi_assert(byte_count > 0); + *((uint32_t*)byte_ptr) = __bswap32(*((uint32_t*)byte_ptr)); // Convert + // Setup view ByteInput* byte_input = subghz->byte_input; byte_input_set_header_text(byte_input, "Enter SERIAL in hex"); diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 446c46a83..e4faead62 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -254,8 +254,8 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetKey); break; case GenSecPlus1: // None - return subghz_txrx_gen_secplus_v1_protocol( - subghz->txrx, subghz->gen_info->mod, subghz->gen_info->freq); + generated_protocol = subghz_scene_set_type_generate_protocol_from_infos(subghz); + break; case GenFaacSLH: // Serial (u32), Button (u8), Counter (u8), Seed (u32) case GenKeeloq: // Serial (u32), Button (u8), Counter (u8) case GenCameAtomo: // Serial (u32), Counter (u8) From 53bbe2b29e7b1803a0f51730865d9ed4a357b25a Mon Sep 17 00:00:00 2001 From: WillyJL Date: Thu, 31 Jul 2025 20:42:49 +0200 Subject: [PATCH 16/31] Update apps - ESP Flasher: Bump Marauder 1.8.3 (by justcallmekoko) - Metroflip: Fix unsupported card crash, RENFE Suma 10 support, GEG Connect AID added, Top Up log parsing and animations, 16 new rail lines, support for parsing area codes, saving function for Suica/Japan Rail IC, bugfixes (by luu176) - WiFi Marauder: Support for ESP32Marauder 1.8.x (by justcallmekoko) --- CHANGELOG.md | 3 +++ applications/external | 2 +- scripts/fbt_tools/fbt_extapps.py | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e5111417..c9a62d6ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,11 +19,14 @@ - Apps: - Asteroids: Bugfixes, title screen, Drone Buddy power-up (by @SimplyMinimal) - Combo Cracker: Allow press and hold to change values, add tutorial (by @TAxelAnderson) + - ESP Flasher: Bump Marauder 1.8.3 (by @justcallmekoko) - FlipDownloader: Added a new option to download GitHub repositories (by @jblanked) - Flipper Blackhat: Add Deauth Broadcast command (by @o7-machinehum) - KeyCopier: Added Weiser WR3 key format (by @lightos) + - Metroflip: Fix unsupported card crash, RENFE Suma 10 support, GEG Connect AID added, Top Up log parsing and animations, 16 new rail lines, support for parsing area codes, saving function for Suica/Japan Rail IC, bugfixes (by @luu176) - NFC Playlist: Refactor playlist worker, new settings layout, loop setting, controls to move between items (by @acegoal07) - Sentry Safe: New interface, settings & help page (by @H4ckd4ddy) + - WiFi Marauder: Support for ESP32Marauder 1.8.x (by @justcallmekoko) - Sub-GHz: - UL: Add 868.46 MHz to default subghz freqs list (by @xMasterX) - UL: Reduce less popular freqs in default hopper preset, make it faster (by @xMasterX) diff --git a/applications/external b/applications/external index 65ff6249a..02c4bf3ff 160000 --- a/applications/external +++ b/applications/external @@ -1 +1 @@ -Subproject commit 65ff6249aaff9db45eddf814f54939d251c0b4a3 +Subproject commit 02c4bf3fffa3f02dcc971927441b2d28afa12b3c diff --git a/scripts/fbt_tools/fbt_extapps.py b/scripts/fbt_tools/fbt_extapps.py index 3cbda0bfe..6ff592a85 100644 --- a/scripts/fbt_tools/fbt_extapps.py +++ b/scripts/fbt_tools/fbt_extapps.py @@ -322,6 +322,7 @@ def _validate_app_imports(target, source, env): "metromoney_plugin", "myki_plugin", "opal_plugin", + "renfe_sum10_plugin", "smartrider_plugin", "suica_plugin", "troika_plugin", From 975ef2b944659e9023922953ac73c4392f2fe64c Mon Sep 17 00:00:00 2001 From: WillyJL Date: Thu, 31 Jul 2025 21:52:57 +0200 Subject: [PATCH 17/31] Apps: Add Sub Analyzer (by RocketGod-git) --- CHANGELOG.md | 2 ++ applications/external | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9a62d6ac..7a309ee08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ ### Added: +- Apps: + - Sub-GHz: Sub Analyzer (by @RocketGod-git) - SubGHz: - UL: Roger (static 28 bit) with add manually support (by @xMasterX & @mishamyte) - UL: V2 Phoenix full support (button switch, add manually, counter decrypt/encrypt) (by @xMasterX & @RocketGod-git, original code by @Skorpionm) diff --git a/applications/external b/applications/external index 02c4bf3ff..a89c68a31 160000 --- a/applications/external +++ b/applications/external @@ -1 +1 @@ -Subproject commit 02c4bf3fffa3f02dcc971927441b2d28afa12b3c +Subproject commit a89c68a31bf6d15c3bfe358ce7edda5c22c2ea83 From df8e256a01c1c1b662adc157f92f32fc39a7af00 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Thu, 31 Jul 2025 21:53:17 +0200 Subject: [PATCH 18/31] Apps: Add Nearby Files (by Stichoza) --- CHANGELOG.md | 1 + applications/external | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a309ee08..ec0e6b1d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ### Added: - Apps: + - GPIO/GPS: [NMEA] Nearby Files (by @Stichoza) - Sub-GHz: Sub Analyzer (by @RocketGod-git) - SubGHz: - UL: Roger (static 28 bit) with add manually support (by @xMasterX & @mishamyte) diff --git a/applications/external b/applications/external index a89c68a31..85d8a4c4c 160000 --- a/applications/external +++ b/applications/external @@ -1 +1 @@ -Subproject commit a89c68a31bf6d15c3bfe358ce7edda5c22c2ea83 +Subproject commit 85d8a4c4cde0a2e7a2ce1959f85ea9a8ee81c61b From ecb7bc881fecceae660c0d2f727b11abc0de75fd Mon Sep 17 00:00:00 2001 From: WillyJL Date: Thu, 31 Jul 2025 22:05:35 +0200 Subject: [PATCH 19/31] FBT: Fix redundant decl for apps using an icon disabled in API --- CHANGELOG.md | 1 + scripts/assets.py | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec0e6b1d1..cf41d19d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ - Bad KB: Fix modifier keys with HOLD/RELEASE commands (by @WillyJL) - Desktop: Fix lock screen hang (#438 by @aaronjamt) - NFC: Fix incorrect Saflok year formula (#433 by @Eltrick) +- FBT: Fix redundant decl for apps using an icon disabled in API (by @WillyJL) ### Removed: - Nothing diff --git a/scripts/assets.py b/scripts/assets.py index 6eb83b66f..a26940f1a 100755 --- a/scripts/assets.py +++ b/scripts/assets.py @@ -177,6 +177,7 @@ class Main(App): symbols /= "sdk_headers/f7_sdk" symbols = (symbols / "targets/f7/api_symbols.csv").read_text() api_has_icon = lambda name: f"Variable,+,{name},const Icon," in symbols + api_has_icon_disabled = lambda name: f"Variable,-,{name},const Icon," in symbols # Traverse icons tree, append image data to source file for dirpath, dirnames, filenames in os.walk(self.args.input_directory): self.logger.debug(f"Processing directory {dirpath}") @@ -294,6 +295,11 @@ class Main(App): ) icons_h.write(ICONS_TEMPLATE_H_HEADER) for name, width, height, frame_rate, frame_count in icons: + if self.args.add_include and api_has_icon_disabled(name): + self.logger.info( + f"{self.args.filename}: skipping duplicate decl {icon_name}" + ) + continue icons_h.write(ICONS_TEMPLATE_H_ICON_NAME.format(name=name)) if self.args.fw_bundle: icons_h.write(ICONS_TEMPLATE_H_ICON_PATHS) From 955309e01379df8523862aa378f01a3624c4088a Mon Sep 17 00:00:00 2001 From: WillyJL Date: Thu, 31 Jul 2025 22:06:51 +0200 Subject: [PATCH 20/31] Apps: Add NFC-Eink (by RebornedBrain) --- CHANGELOG.md | 1 + applications/external | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf41d19d5..ba4f3dd7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ### Added: - Apps: - GPIO/GPS: [NMEA] Nearby Files (by @Stichoza) + - NFC: NFC-Eink (by @RebornedBrain) - Sub-GHz: Sub Analyzer (by @RocketGod-git) - SubGHz: - UL: Roger (static 28 bit) with add manually support (by @xMasterX & @mishamyte) diff --git a/applications/external b/applications/external index 85d8a4c4c..947317338 160000 --- a/applications/external +++ b/applications/external @@ -1 +1 @@ -Subproject commit 85d8a4c4cde0a2e7a2ce1959f85ea9a8ee81c61b +Subproject commit 94731733870d21dd0e5a00830d33a35909905c26 From 4ecfd63759743a181d7ee03982d4dd4d2afe4585 Mon Sep 17 00:00:00 2001 From: Louis D Date: Thu, 31 Jul 2025 22:39:53 +0200 Subject: [PATCH 21/31] fix: restore the original byte order in the GenData struct --- .../subghz/scenes/subghz_scene_set_counter.c | 76 +++++++++---------- .../main/subghz/scenes/subghz_scene_set_key.c | 29 +++---- .../subghz/scenes/subghz_scene_set_seed.c | 33 ++++---- .../subghz/scenes/subghz_scene_set_serial.c | 37 +++++++++ 4 files changed, 107 insertions(+), 68 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_set_counter.c b/applications/main/subghz/scenes/subghz_scene_set_counter.c index 8f61c2285..462535759 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_counter.c +++ b/applications/main/subghz/scenes/subghz_scene_set_counter.c @@ -92,9 +92,7 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventByteInputDone) { - GenInfo gen_info = *subghz->gen_info; - - switch(gen_info.type) { + switch(subghz->gen_info->type) { case GenFaacSLH: case GenKeeloqBFT: scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetSeed); @@ -102,65 +100,67 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { case GenKeeloq: generated_protocol = subghz_txrx_gen_keeloq_protocol( subghz->txrx, - gen_info.mod, - gen_info.freq, - __bswap32(gen_info.keeloq.serial), - gen_info.keeloq.btn, - gen_info.keeloq.cnt, - gen_info.keeloq.manuf); + subghz->gen_info->mod, + subghz->gen_info->freq, + subghz->gen_info->keeloq.serial, + subghz->gen_info->keeloq.btn, + subghz->gen_info->keeloq.cnt, + subghz->gen_info->keeloq.manuf); break; case GenCameAtomo: generated_protocol = subghz_txrx_gen_came_atomo_protocol( subghz->txrx, - gen_info.mod, - gen_info.freq, - __bswap32(gen_info.came_atomo.serial), - gen_info.came_atomo.cnt); + subghz->gen_info->mod, + subghz->gen_info->freq, + subghz->gen_info->came_atomo.serial, + subghz->gen_info->came_atomo.cnt); break; case GenAlutechAt4n: generated_protocol = subghz_txrx_gen_alutech_at_4n_protocol( subghz->txrx, - gen_info.mod, - gen_info.freq, - __bswap32(gen_info.alutech_at_4n.serial), - gen_info.alutech_at_4n.btn, - gen_info.alutech_at_4n.cnt); + subghz->gen_info->mod, + subghz->gen_info->freq, + subghz->gen_info->alutech_at_4n.serial, + subghz->gen_info->alutech_at_4n.btn, + subghz->gen_info->alutech_at_4n.cnt); break; case GenSomfyTelis: generated_protocol = subghz_txrx_gen_somfy_telis_protocol( subghz->txrx, - gen_info.mod, - gen_info.freq, - __bswap32(gen_info.somfy_telis.serial), - gen_info.somfy_telis.btn, - gen_info.somfy_telis.cnt); + subghz->gen_info->mod, + subghz->gen_info->freq, + subghz->gen_info->somfy_telis.serial, + subghz->gen_info->somfy_telis.btn, + subghz->gen_info->somfy_telis.cnt); break; case GenNiceFlorS: generated_protocol = subghz_txrx_gen_nice_flor_s_protocol( subghz->txrx, - gen_info.mod, - gen_info.freq, - __bswap32(gen_info.nice_flor_s.serial), - gen_info.nice_flor_s.btn, - gen_info.nice_flor_s.cnt, - gen_info.nice_flor_s.nice_one); + subghz->gen_info->mod, + subghz->gen_info->freq, + subghz->gen_info->nice_flor_s.serial, + subghz->gen_info->nice_flor_s.btn, + subghz->gen_info->nice_flor_s.cnt, + subghz->gen_info->nice_flor_s.nice_one); break; case GenSecPlus2: + subghz->gen_info->sec_plus_2.cnt = __bswap32(subghz->gen_info->sec_plus_2.cnt); generated_protocol = subghz_txrx_gen_secplus_v2_protocol( subghz->txrx, - gen_info.mod, - gen_info.freq, - __bswap32(gen_info.sec_plus_2.serial), - gen_info.sec_plus_2.btn, - __bswap32(gen_info.sec_plus_2.cnt)); + subghz->gen_info->mod, + subghz->gen_info->freq, + subghz->gen_info->sec_plus_2.serial, + subghz->gen_info->sec_plus_2.btn, + subghz->gen_info->sec_plus_2.cnt); break; case GenPhoenixV2: + subghz->gen_info->phoenix_v2.cnt = __bswap16(subghz->gen_info->phoenix_v2.cnt); generated_protocol = subghz_txrx_gen_phoenix_v2_protocol( subghz->txrx, - gen_info.mod, - gen_info.freq, - __bswap32(gen_info.phoenix_v2.serial), - __bswap16(gen_info.phoenix_v2.cnt)); + subghz->gen_info->mod, + subghz->gen_info->freq, + subghz->gen_info->phoenix_v2.serial, + subghz->gen_info->phoenix_v2.cnt); break; // Not needed for these types case GenData: diff --git a/applications/main/subghz/scenes/subghz_scene_set_key.c b/applications/main/subghz/scenes/subghz_scene_set_key.c index 71c57c5f9..b617b1a0f 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_key.c +++ b/applications/main/subghz/scenes/subghz_scene_set_key.c @@ -44,26 +44,27 @@ bool subghz_scene_set_key_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventByteInputDone) { - GenInfo gen_info = *subghz->gen_info; - if(gen_info.type == GenData) { - if(gen_info.data.te) { + if(subghz->gen_info->type == GenData) { + subghz->gen_info->data.key = __bswap64(subghz->gen_info->data.key); + + if(subghz->gen_info->data.te) { generated_protocol = subghz_txrx_gen_data_protocol_and_te( subghz->txrx, - gen_info.mod, - gen_info.freq, - gen_info.data.name, - __bswap64(gen_info.data.key), - gen_info.data.bits, - gen_info.data.te); + subghz->gen_info->mod, + subghz->gen_info->freq, + subghz->gen_info->data.name, + subghz->gen_info->data.key, + subghz->gen_info->data.bits, + subghz->gen_info->data.te); } else { generated_protocol = subghz_txrx_gen_data_protocol( subghz->txrx, - gen_info.mod, - gen_info.freq, - gen_info.data.name, - __bswap64(gen_info.data.key), - gen_info.data.bits); + subghz->gen_info->mod, + subghz->gen_info->freq, + subghz->gen_info->data.name, + subghz->gen_info->data.key, + subghz->gen_info->data.bits); } } diff --git a/applications/main/subghz/scenes/subghz_scene_set_seed.c b/applications/main/subghz/scenes/subghz_scene_set_seed.c index bebab6c27..3e4a33536 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_seed.c +++ b/applications/main/subghz/scenes/subghz_scene_set_seed.c @@ -60,30 +60,31 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) { bool generated_protocol = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventByteInputDone) { - GenInfo gen_info = *subghz->gen_info; - switch(gen_info.type) { + switch(subghz->gen_info->type) { case GenFaacSLH: + subghz->gen_info->faac_slh.seed = __bswap32(subghz->gen_info->faac_slh.seed); generated_protocol = subghz_txrx_gen_faac_slh_protocol( subghz->txrx, - gen_info.mod, - gen_info.freq, - __bswap32(gen_info.faac_slh.serial), - gen_info.faac_slh.btn, - gen_info.faac_slh.cnt, - __bswap32(gen_info.faac_slh.seed), - gen_info.faac_slh.manuf); + subghz->gen_info->mod, + subghz->gen_info->freq, + subghz->gen_info->faac_slh.serial, + subghz->gen_info->faac_slh.btn, + subghz->gen_info->faac_slh.cnt, + subghz->gen_info->faac_slh.seed, + subghz->gen_info->faac_slh.manuf); break; case GenKeeloqBFT: + subghz->gen_info->keeloq_bft.seed = __bswap32(subghz->gen_info->keeloq_bft.seed); generated_protocol = subghz_txrx_gen_keeloq_bft_protocol( subghz->txrx, - gen_info.mod, - gen_info.freq, - __bswap32(gen_info.keeloq_bft.serial), - gen_info.keeloq_bft.btn, - gen_info.keeloq_bft.cnt, - __bswap32(gen_info.keeloq_bft.seed), - gen_info.keeloq_bft.manuf); + subghz->gen_info->mod, + subghz->gen_info->freq, + subghz->gen_info->keeloq_bft.serial, + subghz->gen_info->keeloq_bft.btn, + subghz->gen_info->keeloq_bft.cnt, + subghz->gen_info->keeloq_bft.seed, + subghz->gen_info->keeloq_bft.manuf); break; // Not needed for these types case GenKeeloq: diff --git a/applications/main/subghz/scenes/subghz_scene_set_serial.c b/applications/main/subghz/scenes/subghz_scene_set_serial.c index 6684e35a4..bedb0d1cc 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_serial.c +++ b/applications/main/subghz/scenes/subghz_scene_set_serial.c @@ -86,6 +86,43 @@ bool subghz_scene_set_serial_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventByteInputDone) { + // Swap bytes + switch(subghz->gen_info->type) { + case GenFaacSLH: + subghz->gen_info->faac_slh.serial = __bswap32(subghz->gen_info->faac_slh.serial); + break; + case GenKeeloq: + subghz->gen_info->keeloq.serial = __bswap32(subghz->gen_info->keeloq.serial); + break; + case GenCameAtomo: + subghz->gen_info->came_atomo.serial = __bswap32(subghz->gen_info->came_atomo.serial); + break; + case GenKeeloqBFT: + subghz->gen_info->keeloq_bft.serial = __bswap32(subghz->gen_info->keeloq_bft.serial); + break; + case GenAlutechAt4n: + subghz->gen_info->alutech_at_4n.serial = __bswap32(subghz->gen_info->alutech_at_4n.serial); + break; + case GenSomfyTelis: + subghz->gen_info->somfy_telis.serial = __bswap32(subghz->gen_info->somfy_telis.serial); + break; + case GenNiceFlorS: + subghz->gen_info->nice_flor_s.serial = __bswap32(subghz->gen_info->nice_flor_s.serial); + break; + case GenSecPlus2: + subghz->gen_info->sec_plus_2.serial = __bswap32(subghz->gen_info->sec_plus_2.serial); + break; + case GenPhoenixV2: + subghz->gen_info->phoenix_v2.serial = __bswap32(subghz->gen_info->phoenix_v2.serial); + break; + // Not needed for these types + case GenData: + case GenSecPlus1: + default: + furi_crash("Not implemented"); + break; + } + switch(subghz->gen_info->type) { case GenFaacSLH: case GenKeeloq: From b376e6db971ee7b4c18f19e2bc48337f0655862a Mon Sep 17 00:00:00 2001 From: WillyJL Date: Thu, 31 Jul 2025 22:41:14 +0200 Subject: [PATCH 22/31] Archive: Support Picopass files open/favorite --nobuild --- CHANGELOG.md | 1 + applications/external | 2 +- applications/main/archive/helpers/archive_browser.h | 3 +++ applications/main/archive/helpers/archive_files.h | 1 + applications/main/archive/scenes/archive_scene_browser.c | 2 ++ applications/main/archive/views/archive_browser_view.c | 1 + 6 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba4f3dd7f..4c56c9fd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Add Skip Sliding Animations option for Lockscreen (#436 by @aaronjamt) - Desktop: Add Keybinds support for directories (#331 by @956MB & @WillyJL) - Input Settings: Add Vibro Trigger option (#429 by @956MB) +- Archive: Support opening and favoriting Picopass files (by @WillyJL) ### Updated: - Apps: diff --git a/applications/external b/applications/external index 947317338..cb422faee 160000 --- a/applications/external +++ b/applications/external @@ -1 +1 @@ -Subproject commit 94731733870d21dd0e5a00830d33a35909905c26 +Subproject commit cb422faee74bcca3c8e1167b0331ce7766669e51 diff --git a/applications/main/archive/helpers/archive_browser.h b/applications/main/archive/helpers/archive_browser.h index 9d3c760c6..2b020ed1c 100644 --- a/applications/main/archive/helpers/archive_browser.h +++ b/applications/main/archive/helpers/archive_browser.h @@ -24,6 +24,7 @@ static const char* const tab_default_paths[] = { }; static const char* const known_ext[] = { + // clang-format off [ArchiveFileTypeIButton] = ".ibtn", [ArchiveFileTypeNFC] = ".nfc", [ArchiveFileTypeSubGhz] = ".sub", @@ -36,6 +37,7 @@ static const char* const known_ext[] = { [ArchiveFileTypeWAV] = ".wav", [ArchiveFileTypeMag] = ".mag", [ArchiveFileTypeCrossRemote] = ".xr", + [ArchiveFileTypePicopass] = ".picopass", [ArchiveFileTypeU2f] = "?", [ArchiveFileTypeApplication] = ".fap", [ArchiveFileTypeJS] = ".js", @@ -46,6 +48,7 @@ static const char* const known_ext[] = { [ArchiveFileTypeUnknown] = "*", [ArchiveFileTypeAppOrJs] = ".fap|.js", [ArchiveFileTypeSetting] = "?", + // clang-format on }; static const ArchiveFileTypeEnum known_type[] = { diff --git a/applications/main/archive/helpers/archive_files.h b/applications/main/archive/helpers/archive_files.h index eb11ae4a1..a33313284 100644 --- a/applications/main/archive/helpers/archive_files.h +++ b/applications/main/archive/helpers/archive_files.h @@ -22,6 +22,7 @@ typedef enum { ArchiveFileTypeWAV, ArchiveFileTypeMag, ArchiveFileTypeCrossRemote, + ArchiveFileTypePicopass, ArchiveFileTypeU2f, ArchiveFileTypeUpdateManifest, ArchiveFileTypeApplication, diff --git a/applications/main/archive/scenes/archive_scene_browser.c b/applications/main/archive/scenes/archive_scene_browser.c index b6d51c1a9..6042c8f32 100644 --- a/applications/main/archive/scenes/archive_scene_browser.c +++ b/applications/main/archive/scenes/archive_scene_browser.c @@ -39,6 +39,8 @@ const char* archive_get_flipper_app_name(ArchiveFileTypeEnum file_type) { return EXT_PATH("apps/GPIO/magspoof.fap"); case ArchiveFileTypeCrossRemote: return EXT_PATH("apps/Infrared/xremote.fap"); + case ArchiveFileTypePicopass: + return EXT_PATH("apps/NFC/picopass.fap"); case ArchiveFileTypeU2f: return "U2F"; case ArchiveFileTypeUpdateManifest: diff --git a/applications/main/archive/views/archive_browser_view.c b/applications/main/archive/views/archive_browser_view.c index eaa7e0cc0..98462d86a 100644 --- a/applications/main/archive/views/archive_browser_view.c +++ b/applications/main/archive/views/archive_browser_view.c @@ -37,6 +37,7 @@ static const Icon* ArchiveItemIcons[] = { [ArchiveFileTypeWAV] = &I_music_10px, [ArchiveFileTypeMag] = &I_mag_card_10px, [ArchiveFileTypeCrossRemote] = &I_xremote_10px, + [ArchiveFileTypePicopass] = &I_125_10px, [ArchiveFileTypeU2f] = &I_u2f_10px, [ArchiveFileTypeSetting] = &I_settings_10px, [ArchiveFileTypeApplication] = &I_Apps_10px, From 7c3e8747166a1039d70e15e5ef4824daba5ae928 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 1 Aug 2025 01:08:40 +0300 Subject: [PATCH 23/31] upd changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18454fba1..3ae635aab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ## Main changes - Current API: 86.0 -* SubGHz: Add variant of 'Add Manually' menu with manual editing for each value (PR #909 | by @MrLego8-9) +* SubGHz: Add variant of 'Add Manually' menu with manual editing for each value (PR #909 #911 | by @MrLego8-9) * OFW PR 4251: CLI: Fix long delay with quick connect/disconnect (by @WillyJL) * LFRFID: Add additional procotols supported by EM4305 chipset (by @jamisonderek) * Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) From 273432acf9174796411203985032676d1a4d70e4 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Fri, 1 Aug 2025 01:22:08 +0200 Subject: [PATCH 24/31] Refactor build workflow checks --- .github/workflows/build.yml | 49 +++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3f4b3d84f..d4b219ada 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -76,6 +76,29 @@ jobs: exit 1 fi + - name: "Configure for Devbuild/PR/Upload" + run: | + if ${{ secrets.INDEXER_URL == '' }} ; then + exit + fi + if ${{ github.event_name == 'push' }} ; then + if ${{ github.ref_name == 'dev' }} ; then + SHOULD_DEVBUILD=${{ !contains(github.event.head_commit.message, '--nobuild') }} + SHOULD_UPLOAD=SHOULD_DEVBUILD + elif ${{ startsWith(github.ref, 'refs/tags/') }} ; then + SHOULD_UPLOAD=true + fi + elif ${{ !!github.event.pull_request }} ; then + SHOULD_PRCOMMENT=${{ matrix.target == env.DEFAULT_TARGET }} + SHOULD_UPLOAD=true + else + echo "What?" + exit 1 + fi + echo "SHOULD_DEVBUILD=$SHOULD_DEVBUILD" >> $GITHUB_ENV + echo "SHOULD_PRCOMMENT=$SHOULD_PRCOMMENT" >> $GITHUB_ENV + echo "SHOULD_UPLOAD=$SHOULD_UPLOAD" >> $GITHUB_ENV + - name: "Build the firmware and apps" id: build-fw run: | @@ -94,9 +117,7 @@ jobs: dist/${{ env.TARGET }}-*/flipper-z-${{ env.TARGET }}-sdk-* - name: "Copy build output" - env: - INDEXER_URL: ${{ secrets.INDEXER_URL }} - if: ${{ env.INDEXER_URL != '' && (github.event.pull_request || (github.event_name == 'push' && ((github.ref_name == 'dev' && !contains(github.event.head_commit.message, '--nobuild')) || startsWith(github.ref, 'refs/tags/')))) }} + if: ${{ env.SHOULD_UPLOAD == 'true' }} run: | set -e rm -rf artifacts || true @@ -112,17 +133,13 @@ jobs: echo "VERSION_TAG=$VERSION_TAG" >> $GITHUB_ENV - name: "Copy universal artifacts" - env: - INDEXER_URL: ${{ secrets.INDEXER_URL }} - if: ${{ env.INDEXER_URL != '' && (github.event.pull_request || (github.event_name == 'push' && ((github.ref_name == 'dev' && !contains(github.event.head_commit.message, '--nobuild')) || startsWith(github.ref, 'refs/tags/')))) }} + if: ${{ env.SHOULD_UPLOAD == 'true' }} run: | tar czpf "artifacts/flipper-z-any-scripts-${SUFFIX}.tgz" scripts cp build/core2_firmware.tgz "artifacts/flipper-z-any-core2_firmware-${SUFFIX}.tgz" - name: "Calculate DFU sizes" - env: - INDEXER_URL: ${{ secrets.INDEXER_URL }} - if: ${{ env.INDEXER_URL != '' && github.event.pull_request && matrix.target == env.DEFAULT_TARGET }} + if: ${{ env.SHOULD_PRCOMMENT == 'true' }} run: | curl -L "${{ secrets.INDEXER_URL }}"/firmware/development/f7/full_dfu -o dev.dfu dfu_size_new=$(du --apparent-size -B 1 artifacts/flipper-z-${TARGET}-full-*.dfu | cut -f1) @@ -145,9 +162,7 @@ jobs: echo "FLASH_USABLE=$FLASH_USABLE" >> $GITHUB_ENV - name: "Upload artifacts to update server" - env: - INDEXER_URL: ${{ secrets.INDEXER_URL }} - if: ${{ env.INDEXER_URL != '' && (github.event.pull_request || (github.event_name == 'push' && ((github.ref_name == 'dev' && !contains(github.event.head_commit.message, '--nobuild')) || startsWith(github.ref, 'refs/tags/')))) }} + if: ${{ env.SHOULD_UPLOAD == 'true' }} run: | curl "${{ secrets.INDEXER_URL }}"/firmware/directory.json > previndex.json FILES=$(for ARTIFACT in $(find artifacts -maxdepth 1 -not -type d); do echo "-F files=@${ARTIFACT}"; done) @@ -158,9 +173,7 @@ jobs: "${{ secrets.INDEXER_URL }}"/firmware/uploadfiles - name: "Find previous comment" - env: - INDEXER_URL: ${{ secrets.INDEXER_URL }} - if: ${{ env.INDEXER_URL != '' && github.event.pull_request && matrix.target == env.DEFAULT_TARGET }} + if: ${{ env.SHOULD_PRCOMMENT == 'true' }} uses: peter-evans/find-comment@v3 id: find-comment with: @@ -169,9 +182,7 @@ jobs: body-includes: "Compiled ${{ matrix.target }} firmware for commit" - name: "Create or update comment" - env: - INDEXER_URL: ${{ secrets.INDEXER_URL }} - if: ${{ env.INDEXER_URL != '' && github.event.pull_request && matrix.target == env.DEFAULT_TARGET }} + if: ${{ env.SHOULD_PRCOMMENT == 'true' }} uses: peter-evans/create-or-update-comment@v4 with: comment-id: ${{ steps.find-comment.outputs.comment-id }} @@ -188,6 +199,6 @@ jobs: env: INDEXER_URL: ${{ secrets.INDEXER_URL }} BUILD_WEBHOOK: ${{ secrets.BUILD_WEBHOOK }} - if: ${{ env.INDEXER_URL != '' && github.event_name == 'push' && github.ref_name == 'dev' && !contains(github.event.head_commit.message, '--nobuild') }} + if: ${{ env.SHOULD_DEVBUILD == 'true' }} run: | python .github/workflow_data/devbuild.py From 1466a585060acdb01182e8c9a867d30ccabe8c39 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Fri, 1 Aug 2025 02:46:45 +0200 Subject: [PATCH 25/31] Force deploy to v2 website after devbuild --- .github/workflows/build.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d4b219ada..7ede2e1a3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -172,6 +172,14 @@ jobs: ${FILES[@]} \ "${{ secrets.INDEXER_URL }}"/firmware/uploadfiles + - name: "Force deploy website to refresh devbuilds" + if: ${{ env.SHOULD_DEVBUILD == 'true' }} + uses: peter-evans/repository-dispatch@v3 + with: + token: ${{ secrets.REPO_DISPATCH_TOKEN }} + repository: Next-Flip/v2.momentum-fw.dev + event-type: force-deploy + - name: "Find previous comment" if: ${{ env.SHOULD_PRCOMMENT == 'true' }} uses: peter-evans/find-comment@v3 @@ -195,7 +203,7 @@ jobs: - Free Flash: `${{ env.FLASH_FREE }}` (`${{ env.FLASH_USABLE }}` usable) edit-mode: replace - - name: Send devbuild webhook + - name: "Send devbuild webhook" env: INDEXER_URL: ${{ secrets.INDEXER_URL }} BUILD_WEBHOOK: ${{ secrets.BUILD_WEBHOOK }} From c02169556b13eb02ec629e81deef72020f8d55a7 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Fri, 1 Aug 2025 02:59:37 +0200 Subject: [PATCH 26/31] Oops --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7ede2e1a3..dbc147a0a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -84,7 +84,7 @@ jobs: if ${{ github.event_name == 'push' }} ; then if ${{ github.ref_name == 'dev' }} ; then SHOULD_DEVBUILD=${{ !contains(github.event.head_commit.message, '--nobuild') }} - SHOULD_UPLOAD=SHOULD_DEVBUILD + SHOULD_UPLOAD=$SHOULD_DEVBUILD elif ${{ startsWith(github.ref, 'refs/tags/') }} ; then SHOULD_UPLOAD=true fi From 71eafcdd6cdf54f9a16a8818ca73eb4e1659e655 Mon Sep 17 00:00:00 2001 From: Louis D Date: Fri, 1 Aug 2025 14:44:42 +0200 Subject: [PATCH 27/31] fix: use the datasize of the generation functions in the protocols geninfo struct --- .../main/subghz/helpers/subghz_gen_info.h | 16 +++--- .../subghz/scenes/subghz_scene_set_counter.c | 53 +++++++++++++++---- .../subghz/scenes/subghz_scene_set_type.c | 17 +++--- 3 files changed, 60 insertions(+), 26 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_gen_info.h b/applications/main/subghz/helpers/subghz_gen_info.h index 003ab871a..88ccdec75 100644 --- a/applications/main/subghz/helpers/subghz_gen_info.h +++ b/applications/main/subghz/helpers/subghz_gen_info.h @@ -25,46 +25,46 @@ typedef struct { const char* name; uint64_t key; uint8_t bits; - uint16_t te; + uint32_t te; } data; struct { uint32_t serial; uint8_t btn; - uint8_t cnt; + uint32_t cnt; uint32_t seed; const char* manuf; } faac_slh; struct { uint32_t serial; uint8_t btn; - uint8_t cnt; + uint16_t cnt; const char* manuf; } keeloq; struct { uint32_t serial; - uint8_t cnt; + uint16_t cnt; } came_atomo; struct { uint32_t serial; uint8_t btn; - uint8_t cnt; + uint16_t cnt; uint32_t seed; const char* manuf; } keeloq_bft; struct { uint32_t serial; uint8_t btn; - uint8_t cnt; + uint16_t cnt; } alutech_at_4n; struct { uint32_t serial; uint8_t btn; - uint8_t cnt; + uint16_t cnt; } somfy_telis; struct { uint32_t serial; uint8_t btn; - uint8_t cnt; + uint16_t cnt; bool nice_one; } nice_flor_s; struct { diff --git a/applications/main/subghz/scenes/subghz_scene_set_counter.c b/applications/main/subghz/scenes/subghz_scene_set_counter.c index 462535759..f66152a7c 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_counter.c +++ b/applications/main/subghz/scenes/subghz_scene_set_counter.c @@ -19,31 +19,31 @@ void subghz_scene_set_counter_on_enter(void* context) { switch(subghz->gen_info->type) { case GenFaacSLH: - byte_ptr = &subghz->gen_info->faac_slh.cnt; + byte_ptr = (uint8_t*)&subghz->gen_info->faac_slh.cnt; byte_count = sizeof(subghz->gen_info->faac_slh.cnt); break; case GenKeeloq: - byte_ptr = &subghz->gen_info->keeloq.cnt; + byte_ptr = (uint8_t*)&subghz->gen_info->keeloq.cnt; byte_count = sizeof(subghz->gen_info->keeloq.cnt); break; case GenCameAtomo: - byte_ptr = &subghz->gen_info->came_atomo.cnt; + byte_ptr = (uint8_t*)&subghz->gen_info->came_atomo.cnt; byte_count = sizeof(subghz->gen_info->came_atomo.cnt); break; case GenKeeloqBFT: - byte_ptr = &subghz->gen_info->keeloq_bft.cnt; + byte_ptr = (uint8_t*)&subghz->gen_info->keeloq_bft.cnt; byte_count = sizeof(subghz->gen_info->keeloq_bft.cnt); break; case GenAlutechAt4n: - byte_ptr = &subghz->gen_info->alutech_at_4n.cnt; + byte_ptr = (uint8_t*)&subghz->gen_info->alutech_at_4n.cnt; byte_count = sizeof(subghz->gen_info->alutech_at_4n.cnt); break; case GenSomfyTelis: - byte_ptr = &subghz->gen_info->somfy_telis.cnt; + byte_ptr = (uint8_t*)&subghz->gen_info->somfy_telis.cnt; byte_count = sizeof(subghz->gen_info->somfy_telis.cnt); break; case GenNiceFlorS: - byte_ptr = &subghz->gen_info->nice_flor_s.cnt; + byte_ptr = (uint8_t*)&subghz->gen_info->nice_flor_s.cnt; byte_count = sizeof(subghz->gen_info->nice_flor_s.cnt); break; case GenSecPlus2: @@ -92,6 +92,43 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventByteInputDone) { + // Swap bytes + switch(subghz->gen_info->type) { + case GenFaacSLH: + subghz->gen_info->faac_slh.cnt = __bswap32(subghz->gen_info->faac_slh.cnt); + break; + case GenKeeloq: + subghz->gen_info->keeloq.cnt = __bswap16(subghz->gen_info->keeloq.cnt); + break; + case GenCameAtomo: + subghz->gen_info->came_atomo.cnt = __bswap16(subghz->gen_info->came_atomo.cnt); + break; + case GenKeeloqBFT: + subghz->gen_info->keeloq_bft.cnt = __bswap16(subghz->gen_info->keeloq_bft.cnt); + break; + case GenAlutechAt4n: + subghz->gen_info->alutech_at_4n.cnt = __bswap16(subghz->gen_info->alutech_at_4n.cnt); + break; + case GenSomfyTelis: + subghz->gen_info->somfy_telis.cnt = __bswap16(subghz->gen_info->somfy_telis.cnt); + break; + case GenNiceFlorS: + subghz->gen_info->nice_flor_s.cnt = __bswap16(subghz->gen_info->nice_flor_s.cnt); + break; + case GenSecPlus2: + subghz->gen_info->sec_plus_2.cnt = __bswap32(subghz->gen_info->sec_plus_2.cnt); + break; + case GenPhoenixV2: + subghz->gen_info->phoenix_v2.cnt = __bswap16(subghz->gen_info->phoenix_v2.cnt); + break; + // Not needed for these types + case GenData: + case GenSecPlus1: + default: + furi_crash("Not implemented"); + break; + } + switch(subghz->gen_info->type) { case GenFaacSLH: case GenKeeloqBFT: @@ -144,7 +181,6 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { subghz->gen_info->nice_flor_s.nice_one); break; case GenSecPlus2: - subghz->gen_info->sec_plus_2.cnt = __bswap32(subghz->gen_info->sec_plus_2.cnt); generated_protocol = subghz_txrx_gen_secplus_v2_protocol( subghz->txrx, subghz->gen_info->mod, @@ -154,7 +190,6 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) { subghz->gen_info->sec_plus_2.cnt); break; case GenPhoenixV2: - subghz->gen_info->phoenix_v2.cnt = __bswap16(subghz->gen_info->phoenix_v2.cnt); generated_protocol = subghz_txrx_gen_phoenix_v2_protocol( subghz->txrx, subghz->gen_info->mod, diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index e4faead62..f493954bc 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -254,15 +254,14 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetKey); break; case GenSecPlus1: // None - generated_protocol = subghz_scene_set_type_generate_protocol_from_infos(subghz); - break; - case GenFaacSLH: // Serial (u32), Button (u8), Counter (u8), Seed (u32) - case GenKeeloq: // Serial (u32), Button (u8), Counter (u8) - case GenCameAtomo: // Serial (u32), Counter (u8) - case GenKeeloqBFT: // Serial (u32), Button (u8), Counter (u8), Seed (u32) - case GenAlutechAt4n: // Serial (u32), Button (u8), Counter (u8) - case GenSomfyTelis: // Serial (u32), Button (u8), Counter (u8) - case GenNiceFlorS: // Serial (u32), Button (u8), Counter (u8) + return subghz_scene_set_type_generate_protocol_from_infos(subghz); + case GenFaacSLH: // Serial (u32), Button (u8), Counter (u32), Seed (u32) + case GenKeeloq: // Serial (u32), Button (u8), Counter (u16) + case GenCameAtomo: // Serial (u32), Counter (u16) + case GenKeeloqBFT: // Serial (u32), Button (u8), Counter (u16), Seed (u32) + case GenAlutechAt4n: // Serial (u32), Button (u8), Counter (u16) + case GenSomfyTelis: // Serial (u32), Button (u8), Counter (u16) + case GenNiceFlorS: // Serial (u32), Button (u8), Counter (u16) case GenSecPlus2: // Serial (u32), Button (u8), Counter (u32) case GenPhoenixV2: // Serial (u32), Counter (u16) scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetSerial); From 0acb014719d5b05fa79ea46aa621378b304eabe2 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 1 Aug 2025 17:25:58 +0300 Subject: [PATCH 28/31] oops fix merge artifact [ci skip] --- .../system/js_app/packages/create-fz-app/template/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/system/js_app/packages/create-fz-app/template/package.json b/applications/system/js_app/packages/create-fz-app/template/package.json index a7f69cf22..393e41840 100644 --- a/applications/system/js_app/packages/create-fz-app/template/package.json +++ b/applications/system/js_app/packages/create-fz-app/template/package.json @@ -6,7 +6,7 @@ "start": "npm run build && node node_modules/@darkflippers/fz-sdk-ul/sdk.js upload" }, "devDependencies": { - "@next-flip/fz-sdk-mntm": "^0.3", + "@darkflippers/fz-sdk-ul": "^0.3", "typescript": "^5.6.3" } } \ No newline at end of file From 27a572d45cf2c2b9bfecda03e16bf40f1826a41e Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 1 Aug 2025 17:26:48 +0300 Subject: [PATCH 29/31] upd changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ae635aab..1acadf0aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ## Main changes - Current API: 86.0 -* SubGHz: Add variant of 'Add Manually' menu with manual editing for each value (PR #909 #911 | by @MrLego8-9) +* SubGHz: Add variant of 'Add Manually' menu with manual editing for each value (PR #909 #911 #914 | by @MrLego8-9) * OFW PR 4251: CLI: Fix long delay with quick connect/disconnect (by @WillyJL) * LFRFID: Add additional procotols supported by EM4305 chipset (by @jamisonderek) * Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) From ed1bcc03b680c8f9d1476a0703167bb790070e65 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Mon, 4 Aug 2025 03:33:53 +0200 Subject: [PATCH 30/31] Updates for new website --nobuild --- .github/workflow_data/devbuild.py | 2 +- .github/workflow_data/release.md | 2 +- .github/workflow_data/webhook.py | 41 +++++++++++++++++++++---------- .github/workflows/release.yml | 7 ++++++ ReadMe.md | 5 ++-- 5 files changed, 40 insertions(+), 17 deletions(-) diff --git a/.github/workflow_data/devbuild.py b/.github/workflow_data/devbuild.py index 4a082d958..4044069e3 100644 --- a/.github/workflow_data/devbuild.py +++ b/.github/workflow_data/devbuild.py @@ -61,7 +61,7 @@ if __name__ == "__main__": "name": "Firmware Artifacts:", "value": "\n".join( [ - f"- [🖥️ Install with Web Updater](https://momentum-fw.dev/update)", + f"- [🖥️ Install with Web Updater](https://momentum-fw.dev/update?version={os.environ['VERSION_TAG'].removeprefix('mntm-dev-')})", f"- [☁️ Open in Flipper Lab/App]({artifact_lab})", f"- [🐬 Download Firmware TGZ]({artifact_tgz})", f"- [🛠️ SDK (for development)]({artifact_sdk})", diff --git a/.github/workflow_data/release.md b/.github/workflow_data/release.md index 441896d20..1ebe13765 100644 --- a/.github/workflow_data/release.md +++ b/.github/workflow_data/release.md @@ -1,5 +1,5 @@ ## ⬇️ Download ->### [🖥️ Web Updater (chrome)](https://momentum-fw.dev/update) [recommended] +>### [🖥️ Web Updater (chrome)](https://momentum-fw.dev/update?version={VERSION_TAG}) [recommended] >### [☁️ Flipper Lab/App (chrome/mobile)](https://lab.flipper.net/?url=https://up.momentum-fw.dev/builds/firmware/{VERSION_TAG}/flipper-z-f7-update-{VERSION_TAG}.tgz&channel=release-cfw&version={VERSION_TAG}) diff --git a/.github/workflow_data/webhook.py b/.github/workflow_data/webhook.py index e173ccb7b..70bda300b 100644 --- a/.github/workflow_data/webhook.py +++ b/.github/workflow_data/webhook.py @@ -20,13 +20,15 @@ if __name__ == "__main__": webhook = "BUILD_WEBHOOK" count = len(event["commits"]) if count == 20: - count = int(requests.get( - event["compare"].replace("github.com", "api.github.com/repos"), - headers={ - "Accept": "application/vnd.github.v3+json", - "Authorization": f"token {os.environ['GITHUB_TOKEN']}" - } - ).json()["total_commits"]) + count = int( + requests.get( + event["compare"].replace("github.com", "api.github.com/repos"), + headers={ + "Accept": "application/vnd.github.v3+json", + "Authorization": f"token {os.environ['GITHUB_TOKEN']}", + }, + ).json()["total_commits"] + ) branch = event["ref"].removeprefix("refs/heads/") change = ( "Force Push" @@ -35,7 +37,12 @@ if __name__ == "__main__": ) desc = f"[**{change}**]({event['compare']}) | [{branch}]({event['repository']['html_url']}/tree/{branch})\n" for i, commit in enumerate(event["commits"]): - msg = commit['message'].splitlines()[0].replace("`", "").replace("_", "\_") + msg = ( + commit["message"] + .splitlines()[0] + .replace("`", "") + .replace("_", "\_") + ) msg = msg[:50] + ("..." if len(msg) > 50 else "") desc += f"\n[`{commit['id'][:8]}`]({commit['url']}): {msg} - [__{commit['author'].get('username')}__](https://github.com/{commit['author'].get('username')})" if len(desc) > 2020: @@ -47,9 +54,9 @@ if __name__ == "__main__": case "release": webhook = "RELEASE_WEBHOOK" color = 9471191 - version_tag = event['release']['tag_name'] + version_tag = event["release"]["tag_name"] title = f"New Release: `{version_tag}`!" - desc += f"> 💻 [**Web Installer**](https://momentum-fw.dev/update)\n\n" + desc += f"> 💻 [**Web Installer**](https://momentum-fw.dev/update?version={version_tag})\n\n" desc += f"> 🐬 [**Changelog & Download**](https://github.com/Next-Flip/Momentum-Firmware/releases/tag/{version_tag})\n\n" desc += f"> 🛞 [**Project Page**](https://github.com/Next-Flip/Momentum-Firmware)" @@ -75,7 +82,11 @@ if __name__ == "__main__": title = f"Issue {event['action'].title()}: {name}" match event["action"]: case "opened": - desc = (issue["body"][:2045] + "...") if len(issue["body"]) > 2048 else issue["body"] + desc = ( + (issue["body"][:2045] + "...") + if len(issue["body"]) > 2048 + else issue["body"] + ) color = 3669797 case "closed": color = 16723712 @@ -90,7 +101,11 @@ if __name__ == "__main__": url = comment["html_url"] title = f"New Comment on Issue: {issue['title']}" color = 3669797 - desc = (comment["body"][:2045] + "...") if len(comment["body"]) > 2048 else comment["body"] + desc = ( + (comment["body"][:2045] + "...") + if len(comment["body"]) > 2048 + else comment["body"] + ) case _: sys.exit(1) @@ -112,7 +127,7 @@ if __name__ == "__main__": "url": event["sender"]["html_url"], "icon_url": event["sender"]["avatar_url"], }, - "timestamp": dt.datetime.utcnow().isoformat() + "timestamp": dt.datetime.utcnow().isoformat(), } ], "attachments": [], diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 03c3b0236..65a353298 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -45,6 +45,13 @@ jobs: curl --fail -L -H "Token: ${{ secrets.INDEXER_TOKEN }}" \ "${{ secrets.INDEXER_URL }}"/firmware/reindex; + - name: "Force deploy website to refresh releases" + uses: peter-evans/repository-dispatch@v3 + with: + token: ${{ secrets.REPO_DISPATCH_TOKEN }} + repository: Next-Flip/v2.momentum-fw.dev + event-type: force-deploy + - name: "Send release notification" env: RELEASE_WEBHOOK: ${{ secrets.RELEASE_WEBHOOK }} diff --git a/ReadMe.md b/ReadMe.md index 46fc2f7f8..5c15a535b 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -86,7 +86,7 @@ In USB mode it also enables additional functionality to spoof the manufacturer a

List of changes

-There are too many to name them all, this is a **non-comprehensive** list of the **most notable from an end-user perspective**. For a more detailed list, you can read through the [**changelogs**](https://github.com/Next-Flip/Momentum-Firmware/releases) and commits/code. Also, you can find a **feature comparison with other firmwares** on [our website](https://momentum-fw.dev/#features). +There are too many to name them all, this is a **non-comprehensive** list of the **most notable from an end-user perspective**. For a more detailed list, you can read through the [**changelogs**](https://github.com/Next-Flip/Momentum-Firmware/releases) and commits/code. Also, you can find a **feature comparison with other firmwares** on [our website](https://momentum-fw.dev/). Note that this repo is always updated with the great work from our friends at [Unleashed](https://github.com/DarkFlippers/unleashed-firmware) and the latest changes from [OFW](https://github.com/flipperdevices/flipperzero-firmware). Below are mentioned only **our** changes that we can actually be credited for, so make sure to check their fantastic additions aswell. And a huge thank you to both teams! @@ -143,7 +143,8 @@ There are 4 methods to install Momentum, we recommend you use the **Web Updater* >
  • Make sure qFlipper is closed
  • >
  • Open the Web Updater
  • >
  • Click Connect and select your Flipper from the list
  • ->
  • Click Flash and wait for the update to complete
  • +>
  • Select which update Channel you prefer from the dropdown
  • +>
  • Click Install and wait for the update to complete
  • > >
    Flipper Lab/App (chrome/mobile)
      From c2a0d721beb1bd18750161b1fc10d8fbb5a72f72 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Tue, 5 Aug 2025 01:11:00 +0200 Subject: [PATCH 31/31] Update apps - FlipSocial: C++ rewrite, comments on feed posts, simpler logic and registration (by jblanked) --- CHANGELOG.md | 1 + applications/external | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c56c9fd0..519b7d7ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ - Combo Cracker: Allow press and hold to change values, add tutorial (by @TAxelAnderson) - ESP Flasher: Bump Marauder 1.8.3 (by @justcallmekoko) - FlipDownloader: Added a new option to download GitHub repositories (by @jblanked) + - FlipSocial: C++ rewrite, comments on feed posts, simpler logic and registration (by @jblanked) - Flipper Blackhat: Add Deauth Broadcast command (by @o7-machinehum) - KeyCopier: Added Weiser WR3 key format (by @lightos) - Metroflip: Fix unsupported card crash, RENFE Suma 10 support, GEG Connect AID added, Top Up log parsing and animations, 16 new rail lines, support for parsing area codes, saving function for Suica/Japan Rail IC, bugfixes (by @luu176) diff --git a/applications/external b/applications/external index cb422faee..5ee8a7ee4 160000 --- a/applications/external +++ b/applications/external @@ -1 +1 @@ -Subproject commit cb422faee74bcca3c8e1167b0331ce7766669e51 +Subproject commit 5ee8a7ee42886668bd889bd1cf1695eae5d1235b