From 130181614a8265d0307e1fda4512c9ee4893838a Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 27 Mar 2023 23:10:45 +0300 Subject: [PATCH] Aprimatic emulation support testing thats was hard! --- lib/subghz/protocols/keeloq.c | 68 ++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 13 deletions(-) diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index d08352e78..c5d8fe343 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -88,7 +88,7 @@ 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 uint8_t klq_prog_mode; static uint16_t temp_counter; void keeloq_set_btn(uint8_t b) { @@ -106,7 +106,7 @@ uint8_t keeloq_get_custom_btn() { void keeloq_reset_original_btn() { btn_temp_id_original = 0; temp_counter = 0; - bft_prog_mode = false; + klq_prog_mode = 0; } void keeloq_reset_mfname() { @@ -173,16 +173,27 @@ static bool subghz_protocol_keeloq_gen_data( // BFT programming mode on / off conditions if((strcmp(instance->manufacture_name, "BFT") == 0) && (btn == 0xF)) { - bft_prog_mode = true; + klq_prog_mode = 1; } - if((strcmp(instance->manufacture_name, "BFT") == 0) && (btn != 0xF) && bft_prog_mode) { - bft_prog_mode = false; + if((strcmp(instance->manufacture_name, "BFT") == 0) && (btn != 0xF) && (klq_prog_mode == 1)) { + klq_prog_mode = 0; + } + // Aprimatic programming mode on / off conditions + if((strcmp(instance->manufacture_name, "Aprimatic") == 0) && (btn == 0xF)) { + klq_prog_mode = 2; + } + if((strcmp(instance->manufacture_name, "Aprimatic") == 0) && (btn != 0xF) && + (klq_prog_mode == 2)) { + klq_prog_mode = 0; } // If we using BFT programming mode we will trasmit its seed in hop part like original remote - if(bft_prog_mode) { + if(klq_prog_mode == 1) { hop = instance->generic.seed; + } else if(klq_prog_mode == 2) { + // If we using Aprimatic programming mode we will trasmit some strange looking hop value, why? cuz manufacturer did it this way :) + hop = 0x1A2B3C4D; } - if(counter_up && !bft_prog_mode) { + if(counter_up && klq_prog_mode == 0) { if(instance->generic.cnt < 0xFFFF) { if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) { instance->generic.cnt = 0; @@ -193,11 +204,28 @@ static bool subghz_protocol_keeloq_gen_data( instance->generic.cnt = 0; } } - if(!bft_prog_mode) { + if(klq_prog_mode == 0) { uint32_t decrypt = (uint32_t)btn << 28 | (instance->generic.serial & 0x3FF) << 16 | //ToDo in some protocols the discriminator is 0 instance->generic.cnt; + + if(strcmp(instance->manufacture_name, "Aprimatic") == 0) { + // Aprimatic uses 12bit serial number + 2bit APR1 "parity" bit in front of it replacing first 2 bits of serial + // Thats in theory! We need to check if this is true for all Aprimatic remotes but we got only 3 recordings to test + // For now lets assume that this is true for all Aprimatic remotes, if not we will need to add some more code here + uint32_t apri_serial = instance->generic.serial; + uint8_t apr1 = 0; + for(uint16_t i = 1; i != 0b10000000000; i <<= 1) { + if(apri_serial & i) apr1++; + } + apri_serial &= 0b00001111111111; + if(apr1 % 2 == 0) { + apri_serial |= 0b110000000000; + } + decrypt = btn << 28 | (apri_serial & 0xFFF) << 16 | instance->generic.cnt; + } + // DTM Neo, Came_Space uses 12bit -> simple learning -- FAAC_RC,XT , Mutanco_Mutancode, Stilmatic(Schellenberg) -> 12bit normal learning if((strcmp(instance->manufacture_name, "DTM_Neo") == 0) || (strcmp(instance->manufacture_name, "FAAC_RC,XT") == 0) || @@ -363,11 +391,14 @@ static bool if(instance->manufacture_name == 0x0) { instance->manufacture_name = ""; } - if(bft_prog_mode) { + if(klq_prog_mode == 1) { instance->manufacture_name = "BFT"; + } else if(klq_prog_mode == 2) { + instance->manufacture_name = "Aprimatic"; } uint8_t klq_last_custom_btn = 0xA; - if(strcmp(instance->manufacture_name, "BFT") == 0) { + if((strcmp(instance->manufacture_name, "BFT") == 0) || + (strcmp(instance->manufacture_name, "Aprimatic") == 0)) { klq_last_custom_btn = 0xF; } @@ -649,7 +680,7 @@ 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; + klq_prog_mode = 0; return instance; } @@ -781,6 +812,13 @@ static inline bool subghz_protocol_keeloq_check_decrypt( if((decrypt >> 28 == btn) && (((((uint16_t)(decrypt >> 16)) & 0xFF) == end_serial) || ((((uint16_t)(decrypt >> 16)) & 0xFF) == 0))) { instance->cnt = decrypt & 0x0000FFFF; + FURI_LOG_I( + "DED", + "btn: %d, decrypt: %lx, end_serial: %lx, serial: %lx", + btn, + decrypt, + end_serial, + instance->serial); return true; } return false; @@ -1151,7 +1189,7 @@ static void subghz_protocol_keeloq_check_remote_controller( uint32_t key_hop = key & 0x00000000ffffffff; // If we are in BFT programming mode we will set previous remembered counter and skip mf keys check - if(!bft_prog_mode) { + if(klq_prog_mode == 0) { // Check key AN-Motors if((key_hop >> 24) == ((key_hop >> 16) & 0x00ff) && (key_fix >> 28) == ((key_hop >> 12) & 0x0f) && (key_hop & 0xFFF) == 0x404) { @@ -1168,10 +1206,14 @@ static void subghz_protocol_keeloq_check_remote_controller( } temp_counter = instance->cnt; - } else { + } else if(klq_prog_mode == 1) { *manufacture_name = "BFT"; mfname = *manufacture_name; instance->cnt = temp_counter; + } else if(klq_prog_mode == 2) { + *manufacture_name = "Aprimatic"; + mfname = *manufacture_name; + instance->cnt = temp_counter; } instance->serial = key_fix & 0x0FFFFFFF;