diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index e55ae32de..32b5fb329 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -8,7 +8,8 @@ typedef enum { //SubmenuIndex SubmenuIndexFaacSLH_433, SubmenuIndexFaacSLH_868, - SubmenuIndexBFT, + SubmenuIndexBFTClone, + SubmenuIndexBFTMitto, SubmenuIndexPricenton, SubmenuIndexNiceFlo12bit, SubmenuIndexNiceFlo24bit, diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index e209a80ea..41c22af20 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -79,10 +79,16 @@ void subghz_scene_set_type_on_enter(void* context) { SubmenuIndexFaacSLH_433, subghz_scene_set_type_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, + "BFT [Manual] 433MHz", + SubmenuIndexBFTClone, + subghz_scene_set_type_submenu_callback, + subghz); submenu_add_item( subghz->submenu, "BFT Mitto 433MHz", - SubmenuIndexBFT, + SubmenuIndexBFTMitto, subghz_scene_set_type_submenu_callback, subghz); submenu_add_item( @@ -236,7 +242,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { case SubmenuIndexFaacSLH_433: scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFixFaac); break; - case SubmenuIndexBFT: + case SubmenuIndexBFTClone: scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFixBft); break; case SubmenuIndexPricenton: @@ -312,6 +318,42 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { generated_protocol = true; } break; + case SubmenuIndexBFTMitto: + subghz->txrx->transmitter = subghz_transmitter_alloc_init( + subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); + subghz_preset_init(subghz, "AM650", 433920000, NULL, 0); + if(subghz->txrx->transmitter) { + subghz_protocol_keeloq_bft_create_data( + subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), + subghz->txrx->fff_data, + key & 0x000FFFFF, + 0x2, + 0x0002, + key & 0x000FFFFF, + "BFT", + subghz->txrx->preset); + + uint8_t seed_data[sizeof(uint32_t)] = {0}; + for(size_t i = 0; i < sizeof(uint32_t); i++) { + seed_data[sizeof(uint32_t) - i - 1] = ((key & 0x000FFFFF) >> i * 8) & 0xFF; + } + + flipper_format_write_hex( + subghz->txrx->fff_data, "Seed", seed_data, sizeof(uint32_t)); + + flipper_format_write_string_cstr(subghz->txrx->fff_data, "Manufacture", "BFT"); + + generated_protocol = true; + } else { + generated_protocol = false; + } + subghz_transmitter_free(subghz->txrx->transmitter); + if(!generated_protocol) { + furi_string_set( + subghz->error_str, "Function requires\nan SD card with\nfresh databases."); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + } + break; case SubmenuIndexDoorHan_433_92: subghz->txrx->transmitter = subghz_transmitter_alloc_init( subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 839972dca..add35c827 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -88,6 +88,8 @@ static const char* mfname; static uint8_t kl_type; static uint8_t btn_temp_id; static uint8_t btn_temp_id_original; +static bool bft_prog_mode; +static uint16_t temp_counter; void keeloq_set_btn(uint8_t b) { btn_temp_id = b; @@ -158,7 +160,27 @@ static bool subghz_protocol_keeloq_gen_data( SubGhzProtocolEncoderKeeloq* instance, uint8_t btn, bool counter_up) { - if(counter_up) { + uint32_t fix = (uint32_t)btn << 28 | instance->generic.serial; + uint32_t hop = 0; + uint64_t man = 0; + uint64_t code_found_reverse; + int res = 0; + if(instance->manufacture_name == 0x0) { + instance->manufacture_name = ""; + } + + // BFT programming mode on / off conditions + if((strcmp(instance->manufacture_name, "BFT") == 0) && (btn == 0xF)) { + bft_prog_mode = true; + } + if((strcmp(instance->manufacture_name, "BFT") == 0) && (btn != 0xF) && bft_prog_mode) { + bft_prog_mode = false; + } + // If we using BFT programming mode we will trasmit its seed in hop part like original remote + if(bft_prog_mode) { + hop = instance->generic.seed; + } + if(counter_up && !bft_prog_mode) { if(instance->generic.cnt < 0xFFFF) { if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) { instance->generic.cnt = 0; @@ -169,49 +191,41 @@ static bool subghz_protocol_keeloq_gen_data( instance->generic.cnt = 0; } } - uint32_t fix = (uint32_t)btn << 28 | instance->generic.serial; - uint32_t decrypt = (uint32_t)btn << 28 | - (instance->generic.serial & 0x3FF) - << 16 | //ToDo in some protocols the discriminator is 0 - instance->generic.cnt; - uint32_t hop = 0; - uint64_t man = 0; - uint64_t code_found_reverse; - int res = 0; - if(instance->manufacture_name == 0x0) { - instance->manufacture_name = ""; - } + if(!bft_prog_mode) { + uint32_t decrypt = (uint32_t)btn << 28 | + (instance->generic.serial & 0x3FF) + << 16 | //ToDo in some protocols the discriminator is 0 + instance->generic.cnt; + // DTM Neo uses 12bit -> simple learning -- FAAC_RC,XT , Mutanco_Mutancode -> 12bit normal learning + if((strcmp(instance->manufacture_name, "DTM_Neo") == 0) || + (strcmp(instance->manufacture_name, "FAAC_RC,XT") == 0) || + (strcmp(instance->manufacture_name, "Mutanco_Mutancode") == 0)) { + decrypt = btn << 28 | (instance->generic.serial & 0xFFF) << 16 | instance->generic.cnt; + } - // DTM Neo uses 12bit -> simple learning -- FAAC_RC,XT , Mutanco_Mutancode -> 12bit normal learning - if((strcmp(instance->manufacture_name, "DTM_Neo") == 0) || - (strcmp(instance->manufacture_name, "FAAC_RC,XT") == 0) || - (strcmp(instance->manufacture_name, "Mutanco_Mutancode") == 0)) { - decrypt = btn << 28 | (instance->generic.serial & 0xFFF) << 16 | instance->generic.cnt; - } + // Nice Smilo, MHouse, JCM, Normstahl -> 8bit serial - simple learning + if((strcmp(instance->manufacture_name, "NICE_Smilo") == 0) || + (strcmp(instance->manufacture_name, "NICE_MHOUSE") == 0) || + (strcmp(instance->manufacture_name, "JCM_Tech") == 0) || + (strcmp(instance->manufacture_name, "Normstahl") == 0)) { + decrypt = btn << 28 | (instance->generic.serial & 0xFF) << 16 | instance->generic.cnt; + } - // Nice Smilo, MHouse, JCM, Normstahl -> 8bit serial - simple learning - if((strcmp(instance->manufacture_name, "NICE_Smilo") == 0) || - (strcmp(instance->manufacture_name, "NICE_MHOUSE") == 0) || - (strcmp(instance->manufacture_name, "JCM_Tech") == 0) || - (strcmp(instance->manufacture_name, "Normstahl") == 0)) { - decrypt = btn << 28 | (instance->generic.serial & 0xFF) << 16 | instance->generic.cnt; - } + // Beninca -> 4bit serial - simple XOR + if(strcmp(instance->manufacture_name, "Beninca") == 0) { + decrypt = btn << 28 | (instance->generic.serial & 0xF) << 16 | instance->generic.cnt; + } - // Beninca -> 4bit serial - simple XOR - if(strcmp(instance->manufacture_name, "Beninca") == 0) { - decrypt = btn << 28 | (instance->generic.serial & 0xF) << 16 | instance->generic.cnt; - } - - if(strcmp(instance->manufacture_name, "Unknown") == 0) { - code_found_reverse = subghz_protocol_blocks_reverse_key( - instance->generic.data, instance->generic.data_count_bit); - hop = code_found_reverse & 0x00000000ffffffff; - } else if(strcmp(instance->manufacture_name, "AN-Motors") == 0) { - hop = (instance->generic.cnt & 0xFF) << 24 | (instance->generic.cnt & 0xFF) << 16 | - (btn & 0xF) << 12 | 0x404; - } else if(strcmp(instance->manufacture_name, "HCS101") == 0) { - hop = instance->generic.cnt << 16 | (btn & 0xF) << 12 | 0x000; - } else { + if(strcmp(instance->manufacture_name, "Unknown") == 0) { + code_found_reverse = subghz_protocol_blocks_reverse_key( + instance->generic.data, instance->generic.data_count_bit); + hop = code_found_reverse & 0x00000000ffffffff; + } else if(strcmp(instance->manufacture_name, "AN-Motors") == 0) { + hop = (instance->generic.cnt & 0xFF) << 24 | (instance->generic.cnt & 0xFF) << 16 | + (btn & 0xF) << 12 | 0x404; + } else if(strcmp(instance->manufacture_name, "HCS101") == 0) { + hop = instance->generic.cnt << 16 | (btn & 0xF) << 12 | 0x000; + } else { for M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) { res = strcmp(furi_string_get_cstr(manufacture_code->name), instance->manufacture_name); @@ -270,6 +284,7 @@ static bool subghz_protocol_keeloq_gen_data( break; } } + } } if(hop) { uint64_t yek = (uint64_t)fix << 32 | hop; @@ -339,6 +354,12 @@ static bool btn_temp_id_original = btn; } + if(instance->manufacture_name == 0x0) { + instance->manufacture_name = ""; + } + if(bft_prog_mode) { + instance->manufacture_name = "BFT"; + } uint8_t klq_last_custom_btn = 0xA; if(strcmp(instance->manufacture_name, "BFT") == 0) { klq_last_custom_btn = 0xF; @@ -450,9 +471,10 @@ static bool btn = btn_temp_id_original; } - //gen new key + // Generate new key + if(subghz_protocol_keeloq_gen_data(instance, btn, true)) { - //ToDo if you need to add a callback to automatically update the data on the display + // OK } else { return false; } @@ -607,6 +629,8 @@ void* subghz_protocol_decoder_keeloq_alloc(SubGhzEnvironment* environment) { instance->keystore = subghz_environment_get_keystore(environment); instance->manufacture_from_file = furi_string_alloc(); + bft_prog_mode = false; + return instance; } @@ -723,7 +747,7 @@ void subghz_protocol_decoder_keeloq_feed(void* context, bool level, uint32_t dur /** * Validation of decrypt data. * @param instance Pointer to a SubGhzBlockGeneric instance - * @param decrypt Decrypd data + * @param decrypt Decrypted data * @param btn Button number, 4 bit * @param end_serial decrement the last 10 bits of the serial number * @return true On success @@ -1105,19 +1129,29 @@ static void subghz_protocol_keeloq_check_remote_controller( uint64_t key = subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit); uint32_t key_fix = key >> 32; uint32_t key_hop = key & 0x00000000ffffffff; - // Check key AN-Motors - if((key_hop >> 24) == ((key_hop >> 16) & 0x00ff) && - (key_fix >> 28) == ((key_hop >> 12) & 0x0f) && (key_hop & 0xFFF) == 0x404) { - *manufacture_name = "AN-Motors"; - mfname = *manufacture_name; - instance->cnt = key_hop >> 16; - } else if((key_hop & 0xFFF) == (0x000) && (key_fix >> 28) == ((key_hop >> 12) & 0x0f)) { - *manufacture_name = "HCS101"; - mfname = *manufacture_name; - instance->cnt = key_hop >> 16; + + // If we are in BFT programming mode we will set previous remembered counter and skip mf keys check + if(!bft_prog_mode) { + // Check key AN-Motors + if((key_hop >> 24) == ((key_hop >> 16) & 0x00ff) && + (key_fix >> 28) == ((key_hop >> 12) & 0x0f) && (key_hop & 0xFFF) == 0x404) { + *manufacture_name = "AN-Motors"; + mfname = *manufacture_name; + instance->cnt = key_hop >> 16; + } else if((key_hop & 0xFFF) == (0x000) && (key_fix >> 28) == ((key_hop >> 12) & 0x0f)) { + *manufacture_name = "HCS101"; + mfname = *manufacture_name; + instance->cnt = key_hop >> 16; + } else { + subghz_protocol_keeloq_check_remote_controller_selector( + instance, key_fix, key_hop, keystore, manufacture_name); + } + temp_counter = instance->cnt; + } else { - subghz_protocol_keeloq_check_remote_controller_selector( - instance, key_fix, key_hop, keystore, manufacture_name); + *manufacture_name = "BFT"; + mfname = *manufacture_name; + instance->cnt = temp_counter; } instance->serial = key_fix & 0x0FFFFFFF;