diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 0bda954ba..464f27ac5 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -138,6 +138,7 @@ static bool subghz_protocol_keeloq_gen_data( uint64_t man = 0; uint64_t code_found_reverse; int res = 0; + // No mf name set? -> set to "" if(instance->manufacture_name == 0x0) { instance->manufacture_name = ""; } @@ -169,7 +170,11 @@ static bool subghz_protocol_keeloq_gen_data( hop = 0x1A2B3C4D; } if(counter_up && prog_mode == PROG_MODE_OFF) { + // Counter increment conditions + + // If counter is 0xFFFF we will reset it to 0 if(instance->generic.cnt < 0xFFFF) { + // Increase counter with value set in global settings (mult) if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { instance->generic.cnt = 0; } else { @@ -182,13 +187,16 @@ static bool subghz_protocol_keeloq_gen_data( if(prog_mode == PROG_MODE_OFF) { // Protocols that do not use encryption if(strcmp(instance->manufacture_name, "Unknown") == 0) { + // Simple Replay of received code 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) { + // An-Motors encode hop = (instance->generic.cnt & 0xFF) << 24 | (instance->generic.cnt & 0xFF) << 16 | (btn & 0xF) << 12 | 0x404; } else if(strcmp(instance->manufacture_name, "HCS101") == 0) { + // HCS101 Encode hop = instance->generic.cnt << 16 | (btn & 0xF) << 12 | 0x000; } else { // Protocols that use encryption @@ -235,6 +243,7 @@ static bool subghz_protocol_keeloq_gen_data( decrypt = btn << 28 | (0x1CE) << 16 | instance->generic.cnt; // Centurion -> no serial in hop, uses fixed value 0x1CE - normal learning } + // Old type selector fixage for compatibilitiy with old signal files uint8_t kl_type_en = instance->keystore->kl_type; for M_EACH( @@ -302,6 +311,7 @@ static bool subghz_protocol_keeloq_gen_data( } } if(hop) { + // If we have hop - we will save it to generic data var that will be used later in transmission uint64_t yek = (uint64_t)fix << 32 | hop; instance->generic.data = subghz_protocol_blocks_reverse_key(yek, instance->generic.data_count_bit); @@ -379,15 +389,18 @@ static bool subghz_custom_btn_set_original(btn); } + // No mf name set? -> set to "" if(instance->manufacture_name == 0x0) { instance->manufacture_name = ""; } + // Prog mode checks and extra fixage of MF Names ProgMode prog_mode = subghz_custom_btn_get_prog_mode(); if(prog_mode == PROG_MODE_KEELOQ_BFT) { instance->manufacture_name = "BFT"; } else if(prog_mode == PROG_MODE_KEELOQ_APRIMATIC) { instance->manufacture_name = "Aprimatic"; } + // Custom button (programming mode button) for BFT and Aprimatic uint8_t klq_last_custom_btn = 0xA; if((strcmp(instance->manufacture_name, "BFT") == 0) || (strcmp(instance->manufacture_name, "Aprimatic") == 0)) { @@ -945,6 +958,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( } } + // MF not found *manufacture_name = "Unknown"; keystore->mfname = "Unknown"; instance->cnt = 0; @@ -956,6 +970,7 @@ static void subghz_protocol_keeloq_check_remote_controller( SubGhzBlockGeneric* instance, SubGhzKeystore* keystore, const char** manufacture_name) { + // Reverse key, split FIX and HOP parts 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; @@ -964,27 +979,54 @@ static void subghz_protocol_keeloq_check_remote_controller( // If we are in BFT / Aprimatic programming mode we will set previous remembered counter and skip mf keys check ProgMode prog_mode = subghz_custom_btn_get_prog_mode(); if(prog_mode == PROG_MODE_OFF) { - // 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"; - keystore->mfname = *manufacture_name; - instance->cnt = key_hop >> 16; - } else if((key_hop & 0xFFF) == (0x000) && (key_fix >> 28) == ((key_hop >> 12) & 0x0f)) { - *manufacture_name = "HCS101"; - keystore->mfname = *manufacture_name; - instance->cnt = key_hop >> 16; + // Case when we have no mf name means that we are checking for the first time and we have to check all conditions + if((strlen(keystore->mfname) < 1) && strlen(*manufacture_name) < 1) { + // 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"; + keystore->mfname = *manufacture_name; + instance->cnt = key_hop >> 16; + } else if((key_hop & 0xFFF) == (0x000) && (key_fix >> 28) == ((key_hop >> 12) & 0x0f)) { + *manufacture_name = "HCS101"; + keystore->mfname = *manufacture_name; + instance->cnt = key_hop >> 16; + } else { + subghz_protocol_keeloq_check_remote_controller_selector( + instance, key_fix, key_hop, keystore, manufacture_name); + } } else { - subghz_protocol_keeloq_check_remote_controller_selector( - instance, key_fix, key_hop, keystore, manufacture_name); + // If we have mfname and its one of AN-Motors or HCS101 we should preform only check for this system + if((strcmp(keystore->mfname, "AN-Motors") == 0) || + (strcmp(keystore->mfname, "HCS101") == 0)) { + // 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"; + keystore->mfname = *manufacture_name; + instance->cnt = key_hop >> 16; + } else if( + (key_hop & 0xFFF) == (0x000) && (key_fix >> 28) == ((key_hop >> 12) & 0x0f)) { + *manufacture_name = "HCS101"; + keystore->mfname = *manufacture_name; + instance->cnt = key_hop >> 16; + } + } else { + // Else we have mfname that is not AN-Motors or HCS101 we should check it via default selector + subghz_protocol_keeloq_check_remote_controller_selector( + instance, key_fix, key_hop, keystore, manufacture_name); + } } + // Save original counter as temp counter in case of later usage of prog mode temp_counter = instance->cnt; } else if(prog_mode == PROG_MODE_KEELOQ_BFT) { + // When we are in prog mode we should fix mfname and apply temp counter *manufacture_name = "BFT"; keystore->mfname = *manufacture_name; instance->cnt = temp_counter; } else if(prog_mode == PROG_MODE_KEELOQ_APRIMATIC) { + // When we are in prog mode we should fix mfname and apply temp counter *manufacture_name = "Aprimatic"; keystore->mfname = *manufacture_name; instance->cnt = temp_counter; @@ -993,6 +1035,7 @@ static void subghz_protocol_keeloq_check_remote_controller( furi_crash("Unsupported Prog Mode"); } + // Get serial and button code from FIX part of the key instance->serial = key_fix & 0x0FFFFFFF; instance->btn = key_fix >> 28; @@ -1000,6 +1043,7 @@ static void subghz_protocol_keeloq_check_remote_controller( if(subghz_custom_btn_get_original() == 0) { subghz_custom_btn_set_original(instance->btn); } + // Set max custom buttons subghz_custom_btn_set_max(4); } @@ -1265,7 +1309,7 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output code_found_reverse_hi, code_found_reverse_lo, instance->generic.btn, - instance->manufacture_name); + instance->manufacture_name); } else { furi_string_cat_printf( output,