From 57dafbc76dcbf622be18ca3ef9120895896e2a56 Mon Sep 17 00:00:00 2001 From: DACI <65663517+daci5455@users.noreply.github.com> Date: Wed, 11 Mar 2026 21:32:25 +0100 Subject: [PATCH] protocol updates --- lib/subghz/protocols/kia_v0.c | 709 +++++++++++++--------------------- lib/subghz/protocols/kia_v0.h | 131 ++++++- lib/subghz/protocols/kia_v1.c | 561 +++++++++++---------------- lib/subghz/protocols/kia_v1.h | 45 +-- lib/subghz/protocols/kia_v2.c | 531 ++++++++++--------------- lib/subghz/protocols/kia_v2.h | 36 +- 6 files changed, 858 insertions(+), 1155 deletions(-) diff --git a/lib/subghz/protocols/kia_v0.c b/lib/subghz/protocols/kia_v0.c index 66ff17bb..473377af 100644 --- a/lib/subghz/protocols/kia_v0.c +++ b/lib/subghz/protocols/kia_v0.c @@ -1,27 +1,13 @@ #include "kia_v0.h" + +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" #include "../blocks/custom_btn_i.h" -static const char* kia_v0_btn_name(uint8_t btn) { - if(btn == 0x01) return "Lock"; - if(btn == 0x02) return "Unlock"; - if(btn == 0x03) return "Boot"; - return "?"; -} - -static uint8_t kia_v0_get_btn_code() { - uint8_t custom_btn = subghz_custom_btn_get(); - uint8_t original_btn = subghz_custom_btn_get_original(); - if(custom_btn == SUBGHZ_CUSTOM_BTN_OK) return original_btn; - if(custom_btn == SUBGHZ_CUSTOM_BTN_UP) return 0x01; // Lock - if(custom_btn == SUBGHZ_CUSTOM_BTN_DOWN) return 0x02; // Unlock - if(custom_btn == SUBGHZ_CUSTOM_BTN_LEFT) return 0x03; // Boot/Trunk - if(custom_btn == SUBGHZ_CUSTOM_BTN_RIGHT) return 0x03; // Boot/Trunk - return original_btn; -} - - - -#define TAG "KiaProtocolV0" +#define TAG "SubGhzProtocolKiaV0" static const SubGhzBlockConst subghz_protocol_kia_const = { .te_short = 250, @@ -30,25 +16,20 @@ static const SubGhzBlockConst subghz_protocol_kia_const = { .min_count_bit_for_found = 61, }; -// Multi-burst configuration -#define KIA_TOTAL_BURSTS 2 -#define KIA_INTER_BURST_GAP_US 25000 - struct SubGhzProtocolDecoderKIA { SubGhzProtocolDecoderBase base; + SubGhzBlockDecoder decoder; SubGhzBlockGeneric generic; + uint16_t header_count; }; struct SubGhzProtocolEncoderKIA { SubGhzProtocolEncoderBase base; + SubGhzProtocolBlockEncoder encoder; SubGhzBlockGeneric generic; - - uint32_t serial; - uint8_t button; - uint16_t counter; }; typedef enum { @@ -58,19 +39,13 @@ typedef enum { KIADecoderStepCheckDuration, } KIADecoderStep; -// Forward declarations for encoder -void* subghz_protocol_encoder_kia_alloc(SubGhzEnvironment* environment); -void subghz_protocol_encoder_kia_free(void* context); -SubGhzProtocolStatus - subghz_protocol_encoder_kia_deserialize(void* context, FlipperFormat* flipper_format); -void subghz_protocol_encoder_kia_stop(void* context); -LevelDuration subghz_protocol_encoder_kia_yield(void* context); - const SubGhzProtocolDecoder subghz_protocol_kia_decoder = { .alloc = subghz_protocol_decoder_kia_alloc, .free = subghz_protocol_decoder_kia_free, + .feed = subghz_protocol_decoder_kia_feed, .reset = subghz_protocol_decoder_kia_reset, + .get_hash_data = subghz_protocol_decoder_kia_get_hash_data, .serialize = subghz_protocol_decoder_kia_serialize, .deserialize = subghz_protocol_decoder_kia_deserialize, @@ -80,16 +55,17 @@ const SubGhzProtocolDecoder subghz_protocol_kia_decoder = { const SubGhzProtocolEncoder subghz_protocol_kia_encoder = { .alloc = subghz_protocol_encoder_kia_alloc, .free = subghz_protocol_encoder_kia_free, + .deserialize = subghz_protocol_encoder_kia_deserialize, .stop = subghz_protocol_encoder_kia_stop, .yield = subghz_protocol_encoder_kia_yield, }; const SubGhzProtocol subghz_protocol_kia_v0 = { - .name = KIA_PROTOCOL_V0_NAME, + .name = SUBGHZ_PROTOCOL_KIA_V0_NAME, .type = SubGhzProtocolTypeDynamic, - .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_FM | SubGhzProtocolFlag_Decodable | - SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + .flag = SubGhzProtocolFlag_315 | SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_FM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + .decoder = &subghz_protocol_kia_decoder, .encoder = &subghz_protocol_kia_encoder, }; @@ -101,7 +77,7 @@ const SubGhzProtocol subghz_protocol_kia_v0 = { * MSB-first processing */ static uint8_t kia_crc8(uint8_t* data, size_t len) { - uint8_t crc = 0; + uint8_t crc = 0x00; for(size_t i = 0; i < len; i++) { crc ^= data[i]; for(size_t j = 0; j < 8; j++) { @@ -126,7 +102,7 @@ static uint8_t kia_calculate_crc(uint64_t data) { crc_data[3] = (data >> 24) & 0xFF; crc_data[4] = (data >> 16) & 0xFF; crc_data[5] = (data >> 8) & 0xFF; - + return kia_crc8(crc_data, 6); } @@ -136,14 +112,6 @@ static uint8_t kia_calculate_crc(uint64_t data) { static bool kia_verify_crc(uint64_t data) { uint8_t received_crc = data & 0xFF; uint8_t calculated_crc = kia_calculate_crc(data); - - FURI_LOG_D( - TAG, - "CRC Check - Received: 0x%02X, Calculated: 0x%02X, Match: %s", - received_crc, - calculated_crc, - (received_crc == calculated_crc) ? "YES" : "NO"); - return (received_crc == calculated_crc); } @@ -155,386 +123,250 @@ void* subghz_protocol_encoder_kia_alloc(SubGhzEnvironment* environment) { UNUSED(environment); SubGhzProtocolEncoderKIA* instance = malloc(sizeof(SubGhzProtocolEncoderKIA)); instance->base.protocol = &subghz_protocol_kia_v0; - instance->serial = 0; - instance->button = 0; - instance->counter = 0; - - instance->encoder.size_upload = (32 + 2 + 118 + 1) * KIA_TOTAL_BURSTS + (KIA_TOTAL_BURSTS - 1); + instance->generic.protocol_name = instance->base.protocol->name; + instance->encoder.size_upload = 848; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.repeat = - 10; // High repeat count for continuous transmission while button is held - instance->encoder.front = 0; + instance->encoder.repeat = 1; instance->encoder.is_running = false; - FURI_LOG_I(TAG, "Encoder allocated at %p", instance); return instance; } void subghz_protocol_encoder_kia_free(void* context) { - furi_check(context); + furi_assert(context); SubGhzProtocolEncoderKIA* instance = context; - if(instance->encoder.upload) { - free(instance->encoder.upload); - } + free(instance->encoder.upload); free(instance); } -/** - * Rebuild the 61-bit data packet with current button/counter values and recalculate CRC - */ -static void subghz_protocol_encoder_kia_update_data(SubGhzProtocolEncoderKIA* instance) { - uint64_t data = 0; - - // Bits 56-59: Preserve from original capture - data |= (instance->generic.data & 0x0F00000000000000ULL); - - // Bits 40-55: Counter (16 bits) - data |= ((uint64_t)(instance->counter & 0xFFFF) << 40); - - // Bits 12-39: Serial (28 bits) - data |= ((uint64_t)(instance->serial & 0x0FFFFFFF) << 12); - - // Bits 8-11: Button (4 bits) - data |= ((uint64_t)(instance->button & 0x0F) << 8); - - // Bits 0-7: Calculate and set CRC - uint8_t crc = kia_calculate_crc(data); - data |= crc; - - instance->generic.data = data; - - FURI_LOG_I( - TAG, - "Data updated - Serial: 0x%07lX, Btn: 0x%X, Cnt: 0x%04X, CRC: 0x%02X", - instance->serial, - instance->button, - instance->counter, - crc); - FURI_LOG_I(TAG, "Full data: 0x%016llX", instance->generic.data); -} - -static void subghz_protocol_encoder_kia_get_upload(SubGhzProtocolEncoderKIA* instance) { - furi_check(instance); - size_t index = 0; - - for(uint8_t burst = 0; burst < KIA_TOTAL_BURSTS; burst++) { - if(burst > 0) { - instance->encoder.upload[index++] = level_duration_make(false, KIA_INTER_BURST_GAP_US); - } - - for(int i = 0; i < 32; i++) { - bool is_high = (i % 2) == 0; - instance->encoder.upload[index++] = - level_duration_make(is_high, subghz_protocol_kia_const.te_short); - } - - instance->encoder.upload[index++] = - level_duration_make(true, subghz_protocol_kia_const.te_long); - - instance->encoder.upload[index++] = - level_duration_make(false, subghz_protocol_kia_const.te_long); - - for(uint8_t bit_num = 0; bit_num < 59; bit_num++) { - uint64_t bit_mask = 1ULL << (58 - bit_num); - uint8_t current_bit = (instance->generic.data & bit_mask) ? 1 : 0; - - uint32_t duration = current_bit ? subghz_protocol_kia_const.te_long : - subghz_protocol_kia_const.te_short; - - instance->encoder.upload[index++] = level_duration_make(true, duration); - instance->encoder.upload[index++] = level_duration_make(false, duration); - } - - instance->encoder.upload[index++] = - level_duration_make(true, subghz_protocol_kia_const.te_long * 2); - } - - instance->encoder.size_upload = index; - instance->encoder.front = 0; - - FURI_LOG_I( - TAG, - "Upload built: %d bursts, size_upload=%zu, data_count_bit=%u, data=0x%016llX", - KIA_TOTAL_BURSTS, - instance->encoder.size_upload, - instance->generic.data_count_bit, - instance->generic.data); -} - -SubGhzProtocolStatus - subghz_protocol_encoder_kia_deserialize(void* context, FlipperFormat* flipper_format) { - furi_check(context); - SubGhzProtocolEncoderKIA* instance = context; - - flipper_format_rewind(flipper_format); - instance->encoder.is_running = false; - instance->encoder.front = 0; - instance->encoder.repeat = 10; - - SubGhzProtocolStatus res = SubGhzProtocolStatusError; - do { - // Read protocol name and validate - FuriString* temp_str = furi_string_alloc(); - if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) { - FURI_LOG_E(TAG, "Missing Protocol"); - furi_string_free(temp_str); - break; - } - - FURI_LOG_I(TAG, "Protocol: %s", furi_string_get_cstr(temp_str)); - - if(!furi_string_equal(temp_str, instance->base.protocol->name)) { - FURI_LOG_E( - TAG, - "Wrong protocol %s != %s", - furi_string_get_cstr(temp_str), - instance->base.protocol->name); - furi_string_free(temp_str); - break; - } - furi_string_free(temp_str); - - // Read bit count - uint32_t bit_count_temp; - if(!flipper_format_read_uint32(flipper_format, "Bit", &bit_count_temp, 1)) { - FURI_LOG_E(TAG, "Missing Bit"); - break; - } - - FURI_LOG_I(TAG, "Bit count read: %lu", bit_count_temp); - - // Always use 61 bits for Kia V0 - instance->generic.data_count_bit = 61; - - // Read key data - temp_str = furi_string_alloc(); - if(!flipper_format_read_string(flipper_format, "Key", temp_str)) { - FURI_LOG_E(TAG, "Missing Key"); - furi_string_free(temp_str); - break; - } - - const char* key_str = furi_string_get_cstr(temp_str); - FURI_LOG_I(TAG, "Key string: %s", key_str); - - // Manual hex parsing - uint64_t key = 0; - size_t str_len = strlen(key_str); - - size_t hex_pos = 0; - for(size_t i = 0; i < str_len && hex_pos < 16; i++) { - char c = key_str[i]; - if(c == ' ') continue; - - uint8_t nibble; - if(c >= '0' && c <= '9') { - nibble = c - '0'; - } else if(c >= 'A' && c <= 'F') { - nibble = c - 'A' + 10; - } else if(c >= 'a' && c <= 'f') { - nibble = c - 'a' + 10; - } else { - FURI_LOG_E(TAG, "Invalid hex character: %c", c); - furi_string_free(temp_str); - break; - } - - key = (key << 4) | nibble; - hex_pos++; - } - - furi_string_free(temp_str); - - if(hex_pos != 16) { - FURI_LOG_E(TAG, "Invalid key length: %zu nibbles (expected 16)", hex_pos); - break; - } - - instance->generic.data = key; - FURI_LOG_I(TAG, "Parsed key: 0x%016llX", instance->generic.data); - - if(instance->generic.data == 0) { - FURI_LOG_E(TAG, "Key is zero after parsing!"); - break; - } - - // Verify CRC of the captured data - if(!kia_verify_crc(key)) { - FURI_LOG_W(TAG, "CRC mismatch in captured data - signal may be corrupted"); - } - - // Read or extract serial - if(!flipper_format_read_uint32(flipper_format, "Serial", &instance->serial, 1)) { - instance->serial = (uint32_t)((key >> 12) & 0x0FFFFFFF); - FURI_LOG_I(TAG, "Extracted serial: 0x%08lX", instance->serial); - } else { - FURI_LOG_I(TAG, "Read serial: 0x%08lX", instance->serial); - } - - // Read or extract button - uint32_t btn_temp; - if(flipper_format_read_uint32(flipper_format, "Btn", &btn_temp, 1)) { - instance->button = (uint8_t)btn_temp; - } else { - instance->button = (key >> 8) & 0x0F; - } - subghz_custom_btn_set_original(instance->button); - subghz_custom_btn_set_max(4); - instance->button = kia_v0_get_btn_code(); - - // Read or extract counter - uint32_t cnt_temp; - if(flipper_format_read_uint32(flipper_format, "Cnt", &cnt_temp, 1)) { - instance->counter = (uint16_t)cnt_temp; - FURI_LOG_I(TAG, "Read counter: 0x%04X", instance->counter); - } else { - instance->counter = (key >> 40) & 0xFFFF; - FURI_LOG_I(TAG, "Extracted counter: 0x%04X", instance->counter); - } - - // Rebuild data with CRC recalculation - subghz_protocol_encoder_kia_update_data(instance); - - if(!flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1)) { - instance->encoder.repeat = 10; - FURI_LOG_D( - TAG, "Repeat not found in file, using default 10 for continuous transmission"); - } - - subghz_protocol_encoder_kia_get_upload(instance); - - instance->encoder.is_running = true; - instance->encoder.front = 0; - - if(instance->generic.data == 0) { - FURI_LOG_E(TAG, "Warning: data is 0!"); - } - - FURI_LOG_I( - TAG, - "Encoder initialized - will send %d bursts, repeat=%u, front=%zu", - KIA_TOTAL_BURSTS, - instance->encoder.repeat, - instance->encoder.front); - FURI_LOG_I(TAG, "Final data to transmit: 0x%016llX", instance->generic.data); - res = SubGhzProtocolStatusOk; - } while(false); - - return res; -} - void subghz_protocol_encoder_kia_stop(void* context) { - if(!context) return; SubGhzProtocolEncoderKIA* instance = context; instance->encoder.is_running = false; - instance->encoder.front = 0; } LevelDuration subghz_protocol_encoder_kia_yield(void* context) { SubGhzProtocolEncoderKIA* instance = context; - if(!instance || !instance->encoder.upload || instance->encoder.repeat == 0 || - !instance->encoder.is_running) { - if(instance) { - FURI_LOG_D( - TAG, - "Encoder yield stopped: repeat=%u, is_running=%d, upload=%p", - instance->encoder.repeat, - instance->encoder.is_running, - instance->encoder.upload); - instance->encoder.is_running = false; - } - return level_duration_reset(); - } - - if(instance->encoder.front >= instance->encoder.size_upload) { - FURI_LOG_E( - TAG, - "Encoder front out of bounds: %zu >= %zu", - instance->encoder.front, - instance->encoder.size_upload); + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { instance->encoder.is_running = false; - instance->encoder.front = 0; return level_duration_reset(); } LevelDuration ret = instance->encoder.upload[instance->encoder.front]; - - if(instance->encoder.front < 5 || instance->encoder.front == 0) { - FURI_LOG_D( - TAG, - "Encoder yield[%zu]: repeat=%u, size=%zu, level=%d, duration=%lu", - instance->encoder.front, - instance->encoder.repeat, - instance->encoder.size_upload, - level_duration_get_level(ret), - level_duration_get_duration(ret)); - } - if(++instance->encoder.front == instance->encoder.size_upload) { instance->encoder.repeat--; instance->encoder.front = 0; - FURI_LOG_I( - TAG, "Encoder completed one cycle, remaining repeat=%u", instance->encoder.repeat); } return ret; } -/** - * Set button value and recalculate CRC +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance */ +static void subghz_protocol_kia_check_remote_controller(SubGhzBlockGeneric* instance); + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderKIA instance + * @return true On success + */ +static bool subghz_protocol_encoder_kia_get_upload(SubGhzProtocolEncoderKIA* instance) { + furi_assert(instance); + + // Save original button + if(subghz_custom_btn_get_original() == 0) { + subghz_custom_btn_set_original(instance->generic.btn); + } + subghz_custom_btn_set_max(4); + + size_t index = 0; + size_t size_upload = (instance->generic.data_count_bit * 2 + 32) * 2 + 540; + if(size_upload > instance->encoder.size_upload) { + FURI_LOG_E( + TAG, + "Size upload exceeds allocated encoder buffer. %i", + instance->generic.data_count_bit); + return false; + } else { + instance->encoder.size_upload = size_upload; + } + + // Counter increment logic + if(instance->generic.cnt < 0xFFFF) { + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } + } else if(instance->generic.cnt >= 0xFFFF) { + instance->generic.cnt = 0; + } + + // Get button (custom or original) + // This allows button changing with directional keys in SubGhz app + uint8_t btn = subghz_custom_btn_get() == SUBGHZ_CUSTOM_BTN_OK ? + subghz_custom_btn_get_original() : + subghz_custom_btn_get(); + + // Update the generic button value for potential button changes + instance->generic.btn = btn; + + // Build data packet + uint64_t data = 0; + + // Bits 56-59: Fixed preamble (0x0F) + data |= ((uint64_t)(0x0F) << 56); + + // Bits 40-55: Counter (16 bits) + data |= ((uint64_t)(instance->generic.cnt & 0xFFFF) << 40); + + // Bits 12-39: Serial (28 bits) + data |= ((uint64_t)(instance->generic.serial & 0x0FFFFFFF) << 12); + + // Bits 8-11: Button (4 bits) + data |= ((uint64_t)(btn & 0x0F) << 8); + + // Bits 0-7: CRC + uint8_t crc = kia_calculate_crc(data); + data |= crc; + + instance->generic.data = data; + + // Send header (270 pulses of te_short) + for(uint16_t i = 270; i > 0; i--) { + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_kia_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_kia_const.te_short); + } + + // Send 2 data bursts + for(uint8_t h = 2; h > 0; h--) { + // Send sync bits (15 pulses of te_short) + for(uint8_t i = 15; i > 0; i--) { + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_kia_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_kia_const.te_short); + } + + // Send data bits (PWM encoding) + for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { + if(bit_read(instance->generic.data, i - 1)) { + // Send bit 1: long pulse + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_kia_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_kia_const.te_long); + } else { + // Send bit 0: short pulse + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_kia_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_kia_const.te_short); + } + } + + // Send stop bit (3x te_long) + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_kia_const.te_long * 3); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_kia_const.te_long * 3); + } + + return true; +} + +SubGhzProtocolStatus subghz_protocol_encoder_kia_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderKIA* instance = context; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; + + do { + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_kia_const.min_count_bit_for_found); + + if(ret != SubGhzProtocolStatusOk) { + break; + } + + // Extract serial, button, counter from data + subghz_protocol_kia_check_remote_controller(&instance->generic); + + // Verify CRC + if(!kia_verify_crc(instance->generic.data)) { + FURI_LOG_W(TAG, "CRC mismatch in loaded file"); + ret = SubGhzProtocolStatusErrorParserOthers; + break; + } + + if(!subghz_protocol_encoder_kia_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } + + // Update the Key in the file with the new counter/button/CRC + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + ret = SubGhzProtocolStatusErrorParserOthers; + break; + } + uint8_t key_data[sizeof(uint64_t)] = {0}; + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data >> i * 8) & 0xFF; + } + if(!flipper_format_update_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to update Key"); + ret = SubGhzProtocolStatusErrorParserKey; + break; + } + + instance->encoder.is_running = true; + } while(false); + + return ret; +} + +// ============================================================================ +// ENCODER HELPER FUNCTIONS +// ============================================================================ + void subghz_protocol_encoder_kia_set_button(void* context, uint8_t button) { - furi_check(context); + furi_assert(context); SubGhzProtocolEncoderKIA* instance = context; - instance->button = button & 0x0F; - subghz_protocol_encoder_kia_update_data(instance); - subghz_protocol_encoder_kia_get_upload(instance); - FURI_LOG_I(TAG, "Button set to 0x%X, upload rebuilt with new CRC", instance->button); + instance->generic.btn = button & 0x0F; } -/** - * Set counter value and recalculate CRC - */ void subghz_protocol_encoder_kia_set_counter(void* context, uint16_t counter) { - furi_check(context); + furi_assert(context); SubGhzProtocolEncoderKIA* instance = context; - instance->counter = counter; - subghz_protocol_encoder_kia_update_data(instance); - subghz_protocol_encoder_kia_get_upload(instance); - FURI_LOG_I(TAG, "Counter set to 0x%04X, upload rebuilt with new CRC", instance->counter); + instance->generic.cnt = counter; } -/** - * Increment counter and recalculate CRC - */ void subghz_protocol_encoder_kia_increment_counter(void* context) { - furi_check(context); + furi_assert(context); SubGhzProtocolEncoderKIA* instance = context; - instance->counter++; - subghz_protocol_encoder_kia_update_data(instance); - subghz_protocol_encoder_kia_get_upload(instance); - FURI_LOG_I( - TAG, "Counter incremented to 0x%04X, upload rebuilt with new CRC", instance->counter); + if(instance->generic.cnt < 0xFFFF) { + instance->generic.cnt++; + } else { + instance->generic.cnt = 0; + } } -/** - * Get current counter value - */ uint16_t subghz_protocol_encoder_kia_get_counter(void* context) { - furi_check(context); + furi_assert(context); SubGhzProtocolEncoderKIA* instance = context; - return instance->counter; + return instance->generic.cnt; } -/** - * Get current button value - */ uint8_t subghz_protocol_encoder_kia_get_button(void* context) { - furi_check(context); + furi_assert(context); SubGhzProtocolEncoderKIA* instance = context; - return instance->button; + return instance->generic.btn; } // ============================================================================ @@ -546,23 +378,24 @@ void* subghz_protocol_decoder_kia_alloc(SubGhzEnvironment* environment) { SubGhzProtocolDecoderKIA* instance = malloc(sizeof(SubGhzProtocolDecoderKIA)); instance->base.protocol = &subghz_protocol_kia_v0; instance->generic.protocol_name = instance->base.protocol->name; + return instance; } void subghz_protocol_decoder_kia_free(void* context) { - furi_check(context); + furi_assert(context); SubGhzProtocolDecoderKIA* instance = context; free(instance); } void subghz_protocol_decoder_kia_reset(void* context) { - furi_check(context); + furi_assert(context); SubGhzProtocolDecoderKIA* instance = context; instance->decoder.parser_step = KIADecoderStepReset; } void subghz_protocol_decoder_kia_feed(void* context, bool level, uint32_t duration) { - furi_check(context); + furi_assert(context); SubGhzProtocolDecoderKIA* instance = context; switch(instance->decoder.parser_step) { @@ -574,7 +407,7 @@ void subghz_protocol_decoder_kia_feed(void* context, bool level, uint32_t durati instance->header_count = 0; } break; - + case KIADecoderStepCheckPreambula: if(level) { if((DURATION_DIFF(duration, subghz_protocol_kia_const.te_short) < @@ -590,6 +423,7 @@ void subghz_protocol_decoder_kia_feed(void* context, bool level, uint32_t durati subghz_protocol_kia_const.te_delta) && (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_short) < subghz_protocol_kia_const.te_delta)) { + // Found header instance->header_count++; break; } else if( @@ -597,13 +431,12 @@ void subghz_protocol_decoder_kia_feed(void* context, bool level, uint32_t durati subghz_protocol_kia_const.te_delta) && (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_long) < subghz_protocol_kia_const.te_delta)) { + // Found start bit if(instance->header_count > 15) { instance->decoder.parser_step = KIADecoderStepSaveDuration; instance->decoder.decode_data = 0; instance->decoder.decode_count_bit = 1; subghz_protocol_blocks_add_bit(&instance->decoder, 1); - FURI_LOG_I( - TAG, "Starting data decode after %u header pulses", instance->header_count); } else { instance->decoder.parser_step = KIADecoderStepReset; } @@ -611,34 +444,26 @@ void subghz_protocol_decoder_kia_feed(void* context, bool level, uint32_t durati instance->decoder.parser_step = KIADecoderStepReset; } break; - + case KIADecoderStepSaveDuration: if(level) { if(duration >= (subghz_protocol_kia_const.te_long + subghz_protocol_kia_const.te_delta * 2UL)) { - // End of transmission detected + // Found stop bit instance->decoder.parser_step = KIADecoderStepReset; - if(instance->decoder.decode_count_bit == subghz_protocol_kia_const.min_count_bit_for_found) { instance->generic.data = instance->decoder.decode_data; instance->generic.data_count_bit = instance->decoder.decode_count_bit; - + + // Verify CRC before accepting the packet if(kia_verify_crc(instance->generic.data)) { - FURI_LOG_I(TAG, "Valid signal received with correct CRC"); + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); } else { - FURI_LOG_W(TAG, "Signal received but CRC mismatch!"); + FURI_LOG_W(TAG, "CRC verification failed, packet rejected"); } - - if(instance->base.callback) - instance->base.callback(&instance->base, instance->base.context); - } else { - FURI_LOG_E( - TAG, - "Incomplete signal: only %u bits", - instance->decoder.decode_count_bit); } - instance->decoder.decode_data = 0; instance->decoder.decode_count_bit = 0; break; @@ -646,11 +471,12 @@ void subghz_protocol_decoder_kia_feed(void* context, bool level, uint32_t durati instance->decoder.te_last = duration; instance->decoder.parser_step = KIADecoderStepCheckDuration; } + } else { instance->decoder.parser_step = KIADecoderStepReset; } break; - + case KIADecoderStepCheckDuration: if(!level) { if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_short) < @@ -667,12 +493,6 @@ void subghz_protocol_decoder_kia_feed(void* context, bool level, uint32_t durati subghz_protocol_blocks_add_bit(&instance->decoder, 1); instance->decoder.parser_step = KIADecoderStepSaveDuration; } else { - FURI_LOG_W( - TAG, - "Timing mismatch at bit %u. Last: %lu, Current: %lu", - instance->decoder.decode_count_bit, - instance->decoder.te_last, - duration); instance->decoder.parser_step = KIADecoderStepReset; } } else { @@ -682,14 +502,33 @@ void subghz_protocol_decoder_kia_feed(void* context, bool level, uint32_t durati } } +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ static void subghz_protocol_kia_check_remote_controller(SubGhzBlockGeneric* instance) { + /* + * 0x0F 0112 43B04EC 1 7D + * 0x0F 0113 43B04EC 1 DF + * 0x0F 0114 43B04EC 1 30 + * 0x0F 0115 43B04EC 2 13 + * 0x0F 0116 43B04EC 3 F5 + * CNT Serial K CRC8 Kia + */ + instance->serial = (uint32_t)((instance->data >> 12) & 0x0FFFFFFF); instance->btn = (instance->data >> 8) & 0x0F; instance->cnt = (instance->data >> 40) & 0xFFFF; + + if(subghz_custom_btn_get_original() == 0) { + subghz_custom_btn_set_original(instance->btn); + } + + subghz_custom_btn_set_max(4); } uint8_t subghz_protocol_decoder_kia_get_hash_data(void* context) { - furi_check(context); + furi_assert(context); SubGhzProtocolDecoderKIA* instance = context; return subghz_protocol_blocks_get_hash_data( &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); @@ -699,45 +538,40 @@ SubGhzProtocolStatus subghz_protocol_decoder_kia_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { - furi_check(context); + furi_assert(context); SubGhzProtocolDecoderKIA* instance = context; - - subghz_protocol_kia_check_remote_controller(&instance->generic); - - instance->generic.data_count_bit = 61; - SubGhzProtocolStatus ret = - subghz_block_generic_serialize(&instance->generic, flipper_format, preset); - - if(ret == SubGhzProtocolStatusOk) { - flipper_format_write_uint32(flipper_format, "Serial", &instance->generic.serial, 1); - uint32_t temp = instance->generic.btn; - flipper_format_write_uint32(flipper_format, "Btn", &temp, 1); - flipper_format_write_uint32(flipper_format, "Cnt", &instance->generic.cnt, 1); - uint32_t crc_temp = instance->generic.data & 0xFF; - flipper_format_write_uint32(flipper_format, "CRC", &crc_temp, 1); - } - - return ret; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } SubGhzProtocolStatus subghz_protocol_decoder_kia_deserialize(void* context, FlipperFormat* flipper_format) { - furi_check(context); + furi_assert(context); SubGhzProtocolDecoderKIA* instance = context; - return subghz_block_generic_deserialize_check_count_bit( - &instance->generic, flipper_format, subghz_protocol_kia_const.min_count_bit_for_found); + + SubGhzProtocolStatus ret = subghz_block_generic_deserialize(&instance->generic, flipper_format); + + if(ret == SubGhzProtocolStatusOk) { + if(instance->generic.data_count_bit < subghz_protocol_kia_const.min_count_bit_for_found) { + ret = SubGhzProtocolStatusErrorParserBitCount; + } + } + + return ret; +} + +static const char* subghz_protocol_kia_get_name_button(uint8_t btn) { + const char* name_btn[5] = {"Unknown", "Lock", "Unlock", "Trunk", "Horn"}; + return name_btn[btn < 5 ? btn : 0]; } void subghz_protocol_decoder_kia_get_string(void* context, FuriString* output) { - furi_check(context); + furi_assert(context); SubGhzProtocolDecoderKIA* instance = context; subghz_protocol_kia_check_remote_controller(&instance->generic); - subghz_custom_btn_set_original(instance->generic.btn); - subghz_custom_btn_set_max(4); uint32_t code_found_hi = instance->generic.data >> 32; uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; - + uint8_t received_crc = instance->generic.data & 0xFF; uint8_t calculated_crc = kia_calculate_crc(instance->generic.data); bool crc_valid = (received_crc == calculated_crc); @@ -746,15 +580,18 @@ void subghz_protocol_decoder_kia_get_string(void* context, FuriString* output) { output, "%s %dbit\r\n" "Key:%08lX%08lX\r\n" - "Sn:%07lX Btn:[%s] Cnt:%04lX\r\n" - "CRC:%02X %s\r\n", + "Sn:%07lX Cnt:%04lX\r\n" + "Btn:%02X:[%s]\r\n" + "CRC:%02X %s", instance->generic.protocol_name, instance->generic.data_count_bit, code_found_hi, code_found_lo, instance->generic.serial, - kia_v0_btn_name(kia_v0_get_btn_code()), instance->generic.cnt, + instance->generic.btn, + subghz_protocol_kia_get_name_button(instance->generic.btn), received_crc, crc_valid ? "(OK)" : "(FAIL)"); } + diff --git a/lib/subghz/protocols/kia_v0.h b/lib/subghz/protocols/kia_v0.h index 67ef2cde..cbbc7749 100644 --- a/lib/subghz/protocols/kia_v0.h +++ b/lib/subghz/protocols/kia_v0.h @@ -1,9 +1,8 @@ #pragma once -#include "kia_generic.h" +#include "base.h" - -#define KIA_PROTOCOL_V0_NAME "KIA/HYU V0" +#define SUBGHZ_PROTOCOL_KIA_V0_NAME "KIA/HYU V0" typedef struct SubGhzProtocolDecoderKIA SubGhzProtocolDecoderKIA; typedef struct SubGhzProtocolEncoderKIA SubGhzProtocolEncoderKIA; @@ -12,23 +11,133 @@ extern const SubGhzProtocolDecoder subghz_protocol_kia_decoder; extern const SubGhzProtocolEncoder subghz_protocol_kia_encoder; extern const SubGhzProtocol subghz_protocol_kia_v0; -// Decoder functions +/** + * Allocate SubGhzProtocolEncoderKIA. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderKIA* pointer to a SubGhzProtocolEncoderKIA instance + */ +void* subghz_protocol_encoder_kia_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderKIA. + * @param context Pointer to a SubGhzProtocolEncoderKIA instance + */ +void subghz_protocol_encoder_kia_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderKIA instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return status + */ +SubGhzProtocolStatus + subghz_protocol_encoder_kia_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderKIA instance + */ +void subghz_protocol_encoder_kia_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderKIA instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_kia_yield(void* context); + +/** + * Set button value for encoding. + * @param context Pointer to a SubGhzProtocolEncoderKIA instance + * @param button Button value (0-4) + */ +void subghz_protocol_encoder_kia_set_button(void* context, uint8_t button); + +/** + * Set counter value for encoding. + * @param context Pointer to a SubGhzProtocolEncoderKIA instance + * @param counter Counter value (0-65535) + */ +void subghz_protocol_encoder_kia_set_counter(void* context, uint16_t counter); + +/** + * Increment counter by 1. + * @param context Pointer to a SubGhzProtocolEncoderKIA instance + */ +void subghz_protocol_encoder_kia_increment_counter(void* context); + +/** + * Get current counter value. + * @param context Pointer to a SubGhzProtocolEncoderKIA instance + * @return Current counter value + */ +uint16_t subghz_protocol_encoder_kia_get_counter(void* context); + +/** + * Get current button value. + * @param context Pointer to a SubGhzProtocolEncoderKIA instance + * @return Current button value + */ +uint8_t subghz_protocol_encoder_kia_get_button(void* context); + +/** + * Allocate SubGhzProtocolDecoderKIA. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderKIA* pointer to a SubGhzProtocolDecoderKIA instance + */ void* subghz_protocol_decoder_kia_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderKIA. + * @param context Pointer to a SubGhzProtocolDecoderKIA instance + */ void subghz_protocol_decoder_kia_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderKIA. + * @param context Pointer to a SubGhzProtocolDecoderKIA instance + */ void subghz_protocol_decoder_kia_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderKIA instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ void subghz_protocol_decoder_kia_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderKIA instance + * @return hash Hash sum (uint8_t) + */ uint8_t subghz_protocol_decoder_kia_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderKIA. + * @param context Pointer to a SubGhzProtocolDecoderKIA instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return status + */ SubGhzProtocolStatus subghz_protocol_decoder_kia_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); + +/** + * Deserialize data SubGhzProtocolDecoderKIA. + * @param context Pointer to a SubGhzProtocolDecoderKIA instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return status + */ SubGhzProtocolStatus subghz_protocol_decoder_kia_deserialize(void* context, FlipperFormat* flipper_format); -void subghz_protocol_decoder_kia_get_string(void* context, FuriString* output); -// Encoder helper functions -void subghz_protocol_encoder_kia_set_button(void* context, uint8_t button); -void subghz_protocol_encoder_kia_set_counter(void* context, uint16_t counter); -void subghz_protocol_encoder_kia_increment_counter(void* context); -uint16_t subghz_protocol_encoder_kia_get_counter(void* context); -uint8_t subghz_protocol_encoder_kia_get_button(void* context); +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderKIA instance + * @param output Resulting text + */ +void subghz_protocol_decoder_kia_get_string(void* context, FuriString* output); diff --git a/lib/subghz/protocols/kia_v1.c b/lib/subghz/protocols/kia_v1.c index 11c4dcf4..ef6eaac0 100644 --- a/lib/subghz/protocols/kia_v1.c +++ b/lib/subghz/protocols/kia_v1.c @@ -1,57 +1,39 @@ #include "kia_v1.h" + +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" #include "../blocks/custom_btn_i.h" - -static uint8_t kia_v1_get_btn_code() { - uint8_t custom_btn = subghz_custom_btn_get(); - uint8_t original_btn = subghz_custom_btn_get_original(); - if(custom_btn == SUBGHZ_CUSTOM_BTN_OK) return original_btn; - if(custom_btn == SUBGHZ_CUSTOM_BTN_UP) return 0x01; // Lock - if(custom_btn == SUBGHZ_CUSTOM_BTN_DOWN) return 0x02; // Unlock - if(custom_btn == SUBGHZ_CUSTOM_BTN_LEFT) return 0x03; // Boot/Trunk - if(custom_btn == SUBGHZ_CUSTOM_BTN_RIGHT) return 0x03; // Boot/Trunk - return original_btn; -} - -static const char* kia_v1_btn_name(uint8_t btn) { - if(btn == 0x01) return "Lock"; - if(btn == 0x02) return "Unlock"; - if(btn == 0x03) return "Boot"; - return "??"; -} - - - - #include -#define TAG "KiaV1" +#define TAG "SubGhzProtocolKiaV1" -#define KIA_V1_TOTAL_BURSTS 3 +// Costanti esattamente come ProtoP irate +#define KIA_V1_TOTAL_BURSTS 3 #define KIA_V1_INTER_BURST_GAP_US 25000 -#define KIA_V1_HEADER_PULSES 90 +#define KIA_V1_HEADER_PULSES 90 -static const SubGhzBlockConst kia_protocol_v1_const = { +static const SubGhzBlockConst subghz_protocol_kia_v1_const = { .te_short = 800, .te_long = 1600, .te_delta = 200, - .min_count_bit_for_found = 57, + .min_count_bit_for_found = 57, // Come ProtoP irate }; struct SubGhzProtocolDecoderKiaV1 { SubGhzProtocolDecoderBase base; - SubGhzBlockDecoder decoder; SubGhzBlockGeneric generic; - uint16_t header_count; - ManchesterState manchester_saved_state; + ManchesterState manchester_saved_state; // Come ProtoP irate uint8_t crc; bool crc_check; }; struct SubGhzProtocolEncoderKiaV1 { SubGhzProtocolEncoderBase base; - SubGhzProtocolBlockEncoder encoder; SubGhzBlockGeneric generic; }; @@ -59,60 +41,56 @@ struct SubGhzProtocolEncoderKiaV1 { typedef enum { KiaV1DecoderStepReset = 0, KiaV1DecoderStepCheckPreamble, - KiaV1DecoderStepDecodeData, + KiaV1DecoderStepDecodeData, // Come ProtoP irate } KiaV1DecoderStep; -const SubGhzProtocolDecoder kia_protocol_v1_decoder = { - .alloc = kia_protocol_decoder_v1_alloc, - .free = kia_protocol_decoder_v1_free, - - .feed = kia_protocol_decoder_v1_feed, - .reset = kia_protocol_decoder_v1_reset, - - .get_hash_data = kia_protocol_decoder_v1_get_hash_data, - .serialize = kia_protocol_decoder_v1_serialize, - .deserialize = kia_protocol_decoder_v1_deserialize, - .get_string = kia_protocol_decoder_v1_get_string, +const SubGhzProtocolDecoder subghz_protocol_kia_v1_decoder = { + .alloc = subghz_protocol_decoder_kia_v1_alloc, + .free = subghz_protocol_decoder_kia_v1_free, + .feed = subghz_protocol_decoder_kia_v1_feed, + .reset = subghz_protocol_decoder_kia_v1_reset, + .get_hash_data = subghz_protocol_decoder_kia_v1_get_hash_data, + .serialize = subghz_protocol_decoder_kia_v1_serialize, + .deserialize = subghz_protocol_decoder_kia_v1_deserialize, + .get_string = subghz_protocol_decoder_kia_v1_get_string, }; -const SubGhzProtocolEncoder kia_protocol_v1_encoder = { - .alloc = kia_protocol_encoder_v1_alloc, - .free = kia_protocol_encoder_v1_free, - - .deserialize = kia_protocol_encoder_v1_deserialize, - .stop = kia_protocol_encoder_v1_stop, - .yield = kia_protocol_encoder_v1_yield, +const SubGhzProtocolEncoder subghz_protocol_kia_v1_encoder = { + .alloc = subghz_protocol_encoder_kia_v1_alloc, + .free = subghz_protocol_encoder_kia_v1_free, + .deserialize = subghz_protocol_encoder_kia_v1_deserialize, + .stop = subghz_protocol_encoder_kia_v1_stop, + .yield = subghz_protocol_encoder_kia_v1_yield, }; const SubGhzProtocol subghz_protocol_kia_v1 = { - .name = KIA_PROTOCOL_V1_NAME, + .name = SUBGHZ_PROTOCOL_KIA_V1_NAME, .type = SubGhzProtocolTypeDynamic, - .flag = SubGhzProtocolFlag_315 | SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | + .flag = SubGhzProtocolFlag_315 | SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, - - .decoder = &kia_protocol_v1_decoder, - .encoder = &kia_protocol_v1_encoder, + .decoder = &subghz_protocol_kia_v1_decoder, + .encoder = &subghz_protocol_kia_v1_encoder, }; -static void kia_v1_check_remote_controller(SubGhzProtocolDecoderKiaV1* instance); static uint8_t kia_v1_crc4(const uint8_t* bytes, int count, uint8_t offset) { uint8_t crc = 0; - for(int i = 0; i < count; i++) { uint8_t b = bytes[i]; crc ^= ((b & 0x0F) ^ (b >> 4)); } - crc = (crc + offset) & 0x0F; return crc; } -static void kia_v1_check_remote_controller(SubGhzProtocolDecoderKiaV1* instance) { + + +static void subghz_protocol_kia_v1_check_remote_controller(SubGhzProtocolDecoderKiaV1* instance) { + // Estrazione campi esattamente come ProtoP irate instance->generic.serial = instance->generic.data >> 24; instance->generic.btn = (instance->generic.data >> 16) & 0xFF; - instance->generic.cnt = ((instance->generic.data >> 4) & 0xF) << 8 | + instance->generic.cnt = ((instance->generic.data >> 4) & 0xF) << 8 | ((instance->generic.data >> 8) & 0xFF); uint8_t cnt_high = (instance->generic.cnt >> 8) & 0xF; @@ -123,7 +101,7 @@ static void kia_v1_check_remote_controller(SubGhzProtocolDecoderKiaV1* instance) char_data[3] = instance->generic.serial & 0xFF; char_data[4] = instance->generic.btn; char_data[5] = instance->generic.cnt & 0xFF; - + uint8_t crc; if(cnt_high == 0) { uint8_t offset = (instance->generic.cnt >= 0x098) ? instance->generic.btn : 1; @@ -137,34 +115,78 @@ static void kia_v1_check_remote_controller(SubGhzProtocolDecoderKiaV1* instance) instance->crc = cnt_high << 4 | crc; instance->crc_check = (crc == (instance->generic.data & 0xF)); + + // Imposta bottoni custom + if(subghz_custom_btn_get_original() == 0) { + subghz_custom_btn_set_original(instance->generic.btn); + } + subghz_custom_btn_set_max(4); } -void* kia_protocol_encoder_v1_alloc(SubGhzEnvironment* environment) { +static const char* subghz_protocol_kia_v1_get_name_button(uint8_t btn) { + switch(btn) { + case 0x1: return "Lock"; + case 0x2: return "Unlock"; + case 0x3: return "Trunk"; + case 0x4: return "Panic"; + default: return "Unknown"; + } +} + + + +void* subghz_protocol_encoder_kia_v1_alloc(SubGhzEnvironment* environment) { UNUSED(environment); SubGhzProtocolEncoderKiaV1* instance = malloc(sizeof(SubGhzProtocolEncoderKiaV1)); - + instance->base.protocol = &subghz_protocol_kia_v1; instance->generic.protocol_name = instance->base.protocol->name; - + instance->encoder.repeat = 10; instance->encoder.size_upload = 1200; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; instance->encoder.front = 0; + return instance; } -void kia_protocol_encoder_v1_free(void* context) { - furi_check(context); +void subghz_protocol_encoder_kia_v1_free(void* context) { + furi_assert(context); SubGhzProtocolEncoderKiaV1* instance = context; free(instance->encoder.upload); free(instance); } -static void kia_protocol_encoder_v1_get_upload(SubGhzProtocolEncoderKiaV1* instance) { - furi_check(instance); +void subghz_protocol_encoder_kia_v1_stop(void* context) { + SubGhzProtocolEncoderKiaV1* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_kia_v1_yield(void* context) { + SubGhzProtocolEncoderKiaV1* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +// ENCODER GET_UPLOAD +static void subghz_protocol_encoder_kia_v1_get_upload(SubGhzProtocolEncoderKiaV1* instance) { + furi_assert(instance); size_t index = 0; + // Calcolo CRC come ProtoP irate uint8_t cnt_high = (instance->generic.cnt >> 8) & 0xF; uint8_t char_data[7]; char_data[0] = (instance->generic.serial >> 24) & 0xFF; @@ -173,7 +195,7 @@ static void kia_protocol_encoder_v1_get_upload(SubGhzProtocolEncoderKiaV1* insta char_data[3] = instance->generic.serial & 0xFF; char_data[4] = instance->generic.btn; char_data[5] = instance->generic.cnt & 0xFF; - + uint8_t crc; if(cnt_high == 0) { uint8_t offset = (instance->generic.cnt >= 0x098) ? instance->generic.btn : 1; @@ -185,271 +207,135 @@ static void kia_protocol_encoder_v1_get_upload(SubGhzProtocolEncoderKiaV1* insta crc = kia_v1_crc4(char_data, 6, 1); } + // Costruisci data esattamente come ProtoP irate instance->generic.data = (uint64_t)instance->generic.serial << 24 | - instance->generic.btn << 16 | (instance->generic.cnt & 0xFF) << 8 | - ((instance->generic.cnt >> 8) & 0xF) << 4 | crc; + (uint64_t)instance->generic.btn << 16 | + (uint64_t)(instance->generic.cnt & 0xFF) << 8 | + (uint64_t)((instance->generic.cnt >> 8) & 0xF) << 4 | + crc; + // 3 burst come ProtoP irate for(uint8_t burst = 0; burst < KIA_V1_TOTAL_BURSTS; burst++) { + // Gap tra burst if(burst > 0) { instance->encoder.upload[index++] = level_duration_make(false, KIA_V1_INTER_BURST_GAP_US); } + // 90 header pulses: LOW-HIGH con te_long for(int i = 0; i < KIA_V1_HEADER_PULSES; i++) { instance->encoder.upload[index++] = - level_duration_make(false, (uint32_t)kia_protocol_v1_const.te_long); + level_duration_make(false, (uint32_t)subghz_protocol_kia_v1_const.te_long); instance->encoder.upload[index++] = - level_duration_make(true, (uint32_t)kia_protocol_v1_const.te_long); + level_duration_make(true, (uint32_t)subghz_protocol_kia_v1_const.te_long); } + // SHORT_LOW prima dei dati instance->encoder.upload[index++] = - level_duration_make(false, (uint32_t)kia_protocol_v1_const.te_short); + level_duration_make(false, (uint32_t)subghz_protocol_kia_v1_const.te_short); + // Manchester encoding dei dati for(uint8_t i = instance->generic.data_count_bit; i > 1; i--) { if(bit_read(instance->generic.data, i - 2)) { + // Bit 1: HIGH-LOW instance->encoder.upload[index++] = - level_duration_make(true, (uint32_t)kia_protocol_v1_const.te_short); + level_duration_make(true, (uint32_t)subghz_protocol_kia_v1_const.te_short); instance->encoder.upload[index++] = - level_duration_make(false, (uint32_t)kia_protocol_v1_const.te_short); + level_duration_make(false, (uint32_t)subghz_protocol_kia_v1_const.te_short); } else { + // Bit 0: LOW-HIGH instance->encoder.upload[index++] = - level_duration_make(false, (uint32_t)kia_protocol_v1_const.te_short); + level_duration_make(false, (uint32_t)subghz_protocol_kia_v1_const.te_short); instance->encoder.upload[index++] = - level_duration_make(true, (uint32_t)kia_protocol_v1_const.te_short); + level_duration_make(true, (uint32_t)subghz_protocol_kia_v1_const.te_short); } } } instance->encoder.size_upload = index; instance->encoder.front = 0; - - FURI_LOG_I( - TAG, - "Upload built: %d bursts, size_upload=%zu, data_count_bit=%u, data=0x%016llX", - KIA_V1_TOTAL_BURSTS, - instance->encoder.size_upload, - instance->generic.data_count_bit, - instance->generic.data); + + FURI_LOG_I(TAG, "Upload built: size=%zu, data=0x%014llX", index, instance->generic.data); } -SubGhzProtocolStatus - kia_protocol_encoder_v1_deserialize(void* context, FlipperFormat* flipper_format) { - furi_check(context); +SubGhzProtocolStatus subghz_protocol_encoder_kia_v1_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); SubGhzProtocolEncoderKiaV1* instance = context; SubGhzProtocolStatus ret = SubGhzProtocolStatusError; - - flipper_format_rewind(flipper_format); - + do { - FuriString* temp_str = furi_string_alloc(); - if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) { - FURI_LOG_E(TAG, "Missing Protocol"); - furi_string_free(temp_str); + ret = subghz_block_generic_deserialize(&instance->generic, flipper_format); + if(ret != SubGhzProtocolStatusOk) { + FURI_LOG_E(TAG, "Deserialize failed"); break; } - - if(!furi_string_equal(temp_str, instance->base.protocol->name)) { - FURI_LOG_E( - TAG, - "Wrong protocol %s != %s", - furi_string_get_cstr(temp_str), - instance->base.protocol->name); - furi_string_free(temp_str); - break; + + // Imposta data_count_bit + instance->generic.data_count_bit = subghz_protocol_kia_v1_const.min_count_bit_for_found; + + // Estrai serial, btn, cnt dalla data (come ProtoP irate) + instance->generic.serial = instance->generic.data >> 24; + instance->generic.btn = (instance->generic.data >> 16) & 0xFF; + instance->generic.cnt = ((instance->generic.data >> 4) & 0xF) << 8 | + ((instance->generic.data >> 8) & 0xFF); + + FURI_LOG_I(TAG, "Deserialized: data=%014llX, serial=%08lX, btn=%02X, cnt=%03lX", + instance->generic.data, instance->generic.serial, + instance->generic.btn, instance->generic.cnt); + + // Imposta bottone originale per custom buttons + if(subghz_custom_btn_get_original() == 0) { + subghz_custom_btn_set_original(instance->generic.btn); } - furi_string_free(temp_str); - - uint32_t bit_count_temp; - if(!flipper_format_read_uint32(flipper_format, "Bit", &bit_count_temp, 1)) { - FURI_LOG_E(TAG, "Missing Bit"); - break; - } - - instance->generic.data_count_bit = kia_protocol_v1_const.min_count_bit_for_found; - - temp_str = furi_string_alloc(); - if(!flipper_format_read_string(flipper_format, "Key", temp_str)) { - FURI_LOG_E(TAG, "Missing Key"); - furi_string_free(temp_str); - break; - } - - const char* key_str = furi_string_get_cstr(temp_str); - uint64_t key = 0; - size_t str_len = strlen(key_str); - size_t hex_pos = 0; - for(size_t i = 0; i < str_len && hex_pos < 16; i++) { - char c = key_str[i]; - if(c == ' ') continue; - - uint8_t nibble; - if(c >= '0' && c <= '9') { - nibble = c - '0'; - } else if(c >= 'A' && c <= 'F') { - nibble = c - 'A' + 10; - } else if(c >= 'a' && c <= 'f') { - nibble = c - 'a' + 10; - } else { - FURI_LOG_E(TAG, "Invalid hex character: %c", c); - furi_string_free(temp_str); - break; - } - - key = (key << 4) | nibble; - hex_pos++; - } - - furi_string_free(temp_str); - - if(hex_pos != 16) { - FURI_LOG_E(TAG, "Invalid key length: %zu nibbles (expected 16)", hex_pos); - break; - } - - instance->generic.data = key; - FURI_LOG_I(TAG, "Parsed key: 0x%016llX", instance->generic.data); - - if(instance->generic.data == 0) { - FURI_LOG_E(TAG, "Key is zero after parsing!"); - break; - } - - if(!flipper_format_read_uint32(flipper_format, "Serial", &instance->generic.serial, 1)) { - instance->generic.serial = instance->generic.data >> 24; - FURI_LOG_I(TAG, "Extracted serial: 0x%08lX", instance->generic.serial); - } else { - FURI_LOG_I(TAG, "Read serial: 0x%08lX", instance->generic.serial); - } - - uint32_t btn_temp; - if(flipper_format_read_uint32(flipper_format, "Btn", &btn_temp, 1)) { - instance->generic.btn = (uint8_t)btn_temp; - } else { - instance->generic.btn = (instance->generic.data >> 16) & 0xFF; - } - subghz_custom_btn_set_original(instance->generic.btn); subghz_custom_btn_set_max(4); - instance->generic.btn = kia_v1_get_btn_code(); - - uint32_t cnt_temp; - if(flipper_format_read_uint32(flipper_format, "Cnt", &cnt_temp, 1)) { - instance->generic.cnt = (uint16_t)cnt_temp; - FURI_LOG_I(TAG, "Read counter: 0x%03lX", (unsigned long)instance->generic.cnt); + + // Incrementa counter + if(instance->generic.cnt < 0xFFF) { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + if(instance->generic.cnt > 0xFFF) { + instance->generic.cnt = 0; + } } else { - instance->generic.cnt = ((instance->generic.data >> 4) & 0xF) << 8 | - ((instance->generic.data >> 8) & 0xFF); - FURI_LOG_I(TAG, "Extracted counter: 0x%03lX", (unsigned long)instance->generic.cnt); + instance->generic.cnt = 0; } - - if(!flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1)) { - instance->encoder.repeat = 10; - FURI_LOG_D( - TAG, "Repeat not found in file, using default 10 for continuous transmission"); + + // Gestione bottoni custom + uint8_t btn = subghz_custom_btn_get(); + if(btn != SUBGHZ_CUSTOM_BTN_OK) { + instance->generic.btn = btn; } - - kia_protocol_encoder_v1_get_upload(instance); - + + // Costruisci upload + subghz_protocol_encoder_kia_v1_get_upload(instance); + + // Aggiorna file con nuova key + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + ret = SubGhzProtocolStatusErrorParserOthers; + break; + } + + uint8_t key_data[sizeof(uint64_t)] = {0}; + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data >> (i * 8)) & 0xFF; + } + if(!flipper_format_update_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to update Key"); + ret = SubGhzProtocolStatusErrorParserKey; + break; + } + instance->encoder.is_running = true; - - FURI_LOG_I( - TAG, - "Encoder deserialized: repeat=%u, size_upload=%zu, is_running=%d, front=%zu", - instance->encoder.repeat, - instance->encoder.size_upload, - instance->encoder.is_running, - instance->encoder.front); - ret = SubGhzProtocolStatusOk; + } while(false); - + return ret; } -void kia_protocol_encoder_v1_stop(void* context) { - SubGhzProtocolEncoderKiaV1* instance = context; - instance->encoder.is_running = false; -} -LevelDuration kia_protocol_encoder_v1_yield(void* context) { - SubGhzProtocolEncoderKiaV1* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { - FURI_LOG_D( - TAG, - "Encoder yield stopped: repeat=%u, is_running=%d", - instance->encoder.repeat, - instance->encoder.is_running); - instance->encoder.is_running = false; - return level_duration_reset(); - } - - LevelDuration ret = instance->encoder.upload[instance->encoder.front]; - - if(instance->encoder.front < 5 || instance->encoder.front == 0) { - FURI_LOG_D( - TAG, - "Encoder yield[%zu]: repeat=%u, size=%zu, level=%d, duration=%lu", - instance->encoder.front, - instance->encoder.repeat, - instance->encoder.size_upload, - level_duration_get_level(ret), - level_duration_get_duration(ret)); - } - - if(++instance->encoder.front == instance->encoder.size_upload) { - instance->encoder.repeat--; - instance->encoder.front = 0; - FURI_LOG_I( - TAG, "Encoder completed one cycle, remaining repeat=%u", instance->encoder.repeat); - } - - return ret; -} - -void kia_protocol_encoder_v1_set_button(void* context, uint8_t button) { - furi_check(context); - SubGhzProtocolEncoderKiaV1* instance = context; - instance->generic.btn = button & 0xFF; - kia_protocol_encoder_v1_get_upload(instance); - FURI_LOG_I(TAG, "Button set to 0x%02X, upload rebuilt with new CRC", instance->generic.btn); -} - -void kia_protocol_encoder_v1_set_counter(void* context, uint16_t counter) { - furi_check(context); - SubGhzProtocolEncoderKiaV1* instance = context; - instance->generic.cnt = counter & 0xFFF; - kia_protocol_encoder_v1_get_upload(instance); - FURI_LOG_I( - TAG, - "Counter set to 0x%03X, upload rebuilt with new CRC", - (uint16_t)instance->generic.cnt); -} - -void kia_protocol_encoder_v1_increment_counter(void* context) { - furi_check(context); - SubGhzProtocolEncoderKiaV1* instance = context; - instance->generic.cnt = (instance->generic.cnt + 1) & 0xFFF; - kia_protocol_encoder_v1_get_upload(instance); - FURI_LOG_I( - TAG, - "Counter incremented to 0x%03X, upload rebuilt with new CRC", - (uint16_t)instance->generic.cnt); -} - -uint16_t kia_protocol_encoder_v1_get_counter(void* context) { - furi_check(context); - SubGhzProtocolEncoderKiaV1* instance = context; - return instance->generic.cnt; -} - -uint8_t kia_protocol_encoder_v1_get_button(void* context) { - furi_check(context); - SubGhzProtocolEncoderKiaV1* instance = context; - return instance->generic.btn; -} - -void* kia_protocol_decoder_v1_alloc(SubGhzEnvironment* environment) { +void* subghz_protocol_decoder_kia_v1_alloc(SubGhzEnvironment* environment) { UNUSED(environment); SubGhzProtocolDecoderKiaV1* instance = malloc(sizeof(SubGhzProtocolDecoderKiaV1)); instance->base.protocol = &subghz_protocol_kia_v1; @@ -457,28 +343,29 @@ void* kia_protocol_decoder_v1_alloc(SubGhzEnvironment* environment) { return instance; } -void kia_protocol_decoder_v1_free(void* context) { - furi_check(context); +void subghz_protocol_decoder_kia_v1_free(void* context) { + furi_assert(context); SubGhzProtocolDecoderKiaV1* instance = context; free(instance); } -void kia_protocol_decoder_v1_reset(void* context) { - furi_check(context); +void subghz_protocol_decoder_kia_v1_reset(void* context) { + furi_assert(context); SubGhzProtocolDecoderKiaV1* instance = context; instance->decoder.parser_step = KiaV1DecoderStepReset; } -void kia_protocol_decoder_v1_feed(void* context, bool level, uint32_t duration) { - furi_check(context); +// FEED +void subghz_protocol_decoder_kia_v1_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); SubGhzProtocolDecoderKiaV1* instance = context; ManchesterEvent event = ManchesterEventReset; switch(instance->decoder.parser_step) { case KiaV1DecoderStepReset: - if((level) && (DURATION_DIFF(duration, kia_protocol_v1_const.te_long) < - kia_protocol_v1_const.te_delta)) { + if((level) && (DURATION_DIFF(duration, subghz_protocol_kia_v1_const.te_long) < + subghz_protocol_kia_v1_const.te_delta)) { instance->decoder.parser_step = KiaV1DecoderStepCheckPreamble; instance->decoder.te_last = duration; instance->header_count = 0; @@ -494,10 +381,10 @@ void kia_protocol_decoder_v1_feed(void* context, bool level, uint32_t duration) case KiaV1DecoderStepCheckPreamble: if(!level) { - if((DURATION_DIFF(duration, kia_protocol_v1_const.te_long) < - kia_protocol_v1_const.te_delta) && - (DURATION_DIFF(instance->decoder.te_last, kia_protocol_v1_const.te_long) < - kia_protocol_v1_const.te_delta)) { + if((DURATION_DIFF(duration, subghz_protocol_kia_v1_const.te_long) < + subghz_protocol_kia_v1_const.te_delta) && + (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_v1_const.te_long) < + subghz_protocol_kia_v1_const.te_delta)) { instance->header_count++; instance->decoder.te_last = duration; } else { @@ -506,10 +393,10 @@ void kia_protocol_decoder_v1_feed(void* context, bool level, uint32_t duration) } if(instance->header_count > 70) { if((!level) && - (DURATION_DIFF(duration, kia_protocol_v1_const.te_short) < - kia_protocol_v1_const.te_delta) && - (DURATION_DIFF(instance->decoder.te_last, kia_protocol_v1_const.te_long) < - kia_protocol_v1_const.te_delta)) { + (DURATION_DIFF(duration, subghz_protocol_kia_v1_const.te_short) < + subghz_protocol_kia_v1_const.te_delta) && + (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_v1_const.te_long) < + subghz_protocol_kia_v1_const.te_delta)) { instance->decoder.decode_count_bit = 1; subghz_protocol_blocks_add_bit(&instance->decoder, 1); instance->header_count = 0; @@ -519,12 +406,18 @@ void kia_protocol_decoder_v1_feed(void* context, bool level, uint32_t duration) break; case KiaV1DecoderStepDecodeData: - if((DURATION_DIFF(duration, kia_protocol_v1_const.te_short) < - kia_protocol_v1_const.te_delta)) { + if((DURATION_DIFF(duration, subghz_protocol_kia_v1_const.te_short) < + subghz_protocol_kia_v1_const.te_delta)) { event = level ? ManchesterEventShortLow : ManchesterEventShortHigh; - } else if((DURATION_DIFF(duration, kia_protocol_v1_const.te_long) < - kia_protocol_v1_const.te_delta)) { + } else if((DURATION_DIFF(duration, subghz_protocol_kia_v1_const.te_long) < + subghz_protocol_kia_v1_const.te_delta)) { event = level ? ManchesterEventLongLow : ManchesterEventLongHigh; + } else { + // Durata non valida - reset completo + instance->decoder.parser_step = KiaV1DecoderStepReset; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + break; } if(event != ManchesterEventReset) { @@ -537,7 +430,8 @@ void kia_protocol_decoder_v1_feed(void* context, bool level, uint32_t duration) } } - if(instance->decoder.decode_count_bit == kia_protocol_v1_const.min_count_bit_for_found) { + if(instance->decoder.decode_count_bit == + subghz_protocol_kia_v1_const.min_count_bit_for_found) { instance->generic.data = instance->decoder.decode_data; instance->generic.data_count_bit = instance->decoder.decode_count_bit; if(instance->base.callback) @@ -551,52 +445,35 @@ void kia_protocol_decoder_v1_feed(void* context, bool level, uint32_t duration) } } -uint8_t kia_protocol_decoder_v1_get_hash_data(void* context) { - furi_check(context); +uint8_t subghz_protocol_decoder_kia_v1_get_hash_data(void* context) { + furi_assert(context); SubGhzProtocolDecoderKiaV1* instance = context; return subghz_protocol_blocks_get_hash_data( &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); } -SubGhzProtocolStatus kia_protocol_decoder_v1_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_kia_v1_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { - furi_check(context); + furi_assert(context); SubGhzProtocolDecoderKiaV1* instance = context; - - kia_v1_check_remote_controller(instance); - - SubGhzProtocolStatus ret = - subghz_block_generic_serialize(&instance->generic, flipper_format, preset); - - if(ret == SubGhzProtocolStatusOk) { - flipper_format_write_uint32(flipper_format, "Serial", &instance->generic.serial, 1); - uint32_t temp = instance->generic.btn; - flipper_format_write_uint32(flipper_format, "Btn", &temp, 1); - temp = instance->generic.cnt; - flipper_format_write_uint32(flipper_format, "Cnt", &temp, 1); - } - - return ret; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -SubGhzProtocolStatus - kia_protocol_decoder_v1_deserialize(void* context, FlipperFormat* flipper_format) { - furi_check(context); +SubGhzProtocolStatus subghz_protocol_decoder_kia_v1_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); SubGhzProtocolDecoderKiaV1* instance = context; - flipper_format_rewind(flipper_format); return subghz_block_generic_deserialize_check_count_bit( - &instance->generic, flipper_format, kia_protocol_v1_const.min_count_bit_for_found); + &instance->generic, flipper_format, subghz_protocol_kia_v1_const.min_count_bit_for_found); } -void kia_protocol_decoder_v1_get_string(void* context, FuriString* output) { - furi_check(context); +void subghz_protocol_decoder_kia_v1_get_string(void* context, FuriString* output) { + furi_assert(context); SubGhzProtocolDecoderKiaV1* instance = context; - kia_v1_check_remote_controller(instance); - subghz_custom_btn_set_original(instance->generic.btn); - subghz_custom_btn_set_max(4); + subghz_protocol_kia_v1_check_remote_controller(instance); + uint32_t code_found_hi = instance->generic.data >> 32; uint32_t code_found_lo = instance->generic.data & 0xFFFFFFFF; @@ -604,17 +481,17 @@ void kia_protocol_decoder_v1_get_string(void* context, FuriString* output) { output, "%s %dbit\r\n" "Key:%06lX%08lX\r\n" - "Serial:%08lX\r\n" - "Cnt:%03lX CRC:%01X %s\r\n" - "Btn:%02X:%s\r\n", + "Sn:%08lX Cnt:%03lX\r\n" + "Btn:%02X:[%s]\r\n" + "CRC:%02X %s\r\n", instance->generic.protocol_name, instance->generic.data_count_bit, code_found_hi, code_found_lo, instance->generic.serial, instance->generic.cnt, - instance->crc, - instance->crc_check ? "OK" : "WRONG", instance->generic.btn, - kia_v1_btn_name(kia_v1_get_btn_code())); + subghz_protocol_kia_v1_get_name_button(instance->generic.btn), + instance->crc, + instance->crc_check ? "(OK)" : "(FAIL)"); } diff --git a/lib/subghz/protocols/kia_v1.h b/lib/subghz/protocols/kia_v1.h index fa1d6519..a3b0939c 100644 --- a/lib/subghz/protocols/kia_v1.h +++ b/lib/subghz/protocols/kia_v1.h @@ -1,42 +1,39 @@ #pragma once -#include "kia_generic.h" +#include "base.h" +#include "../blocks/math.h" - -#define KIA_PROTOCOL_V1_NAME "KIA/HYU V1" +#define SUBGHZ_PROTOCOL_KIA_V1_NAME "KIA/HYU V1" typedef struct SubGhzProtocolDecoderKiaV1 SubGhzProtocolDecoderKiaV1; typedef struct SubGhzProtocolEncoderKiaV1 SubGhzProtocolEncoderKiaV1; -extern const SubGhzProtocolDecoder kia_protocol_v1_decoder; -extern const SubGhzProtocolEncoder kia_protocol_v1_encoder; extern const SubGhzProtocol subghz_protocol_kia_v1; // Decoder functions -void* kia_protocol_decoder_v1_alloc(SubGhzEnvironment* environment); -void kia_protocol_decoder_v1_free(void* context); -void kia_protocol_decoder_v1_reset(void* context); -void kia_protocol_decoder_v1_feed(void* context, bool level, uint32_t duration); -uint8_t kia_protocol_decoder_v1_get_hash_data(void* context); -SubGhzProtocolStatus kia_protocol_decoder_v1_serialize( +void* subghz_protocol_decoder_kia_v1_alloc(SubGhzEnvironment* environment); +void subghz_protocol_decoder_kia_v1_free(void* context); +void subghz_protocol_decoder_kia_v1_reset(void* context); +void subghz_protocol_decoder_kia_v1_feed(void* context, bool level, uint32_t duration); +uint8_t subghz_protocol_decoder_kia_v1_get_hash_data(void* context); +SubGhzProtocolStatus subghz_protocol_decoder_kia_v1_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); SubGhzProtocolStatus - kia_protocol_decoder_v1_deserialize(void* context, FlipperFormat* flipper_format); -void kia_protocol_decoder_v1_get_string(void* context, FuriString* output); + subghz_protocol_decoder_kia_v1_deserialize(void* context, FlipperFormat* flipper_format); +void subghz_protocol_decoder_kia_v1_get_string(void* context, FuriString* output); // Encoder functions -void* kia_protocol_encoder_v1_alloc(SubGhzEnvironment* environment); -void kia_protocol_encoder_v1_free(void* context); -SubGhzProtocolStatus - kia_protocol_encoder_v1_deserialize(void* context, FlipperFormat* flipper_format); -void kia_protocol_encoder_v1_stop(void* context); -LevelDuration kia_protocol_encoder_v1_yield(void* context); +void* subghz_protocol_encoder_kia_v1_alloc(SubGhzEnvironment* environment); +void subghz_protocol_encoder_kia_v1_free(void* context); +SubGhzProtocolStatus subghz_protocol_encoder_kia_v1_deserialize(void* context, FlipperFormat* flipper_format); +void subghz_protocol_encoder_kia_v1_stop(void* context); +LevelDuration subghz_protocol_encoder_kia_v1_yield(void* context); // Encoder helper functions for UI -void kia_protocol_encoder_v1_set_button(void* context, uint8_t button); -void kia_protocol_encoder_v1_set_counter(void* context, uint16_t counter); -void kia_protocol_encoder_v1_increment_counter(void* context); -uint16_t kia_protocol_encoder_v1_get_counter(void* context); -uint8_t kia_protocol_encoder_v1_get_button(void* context); +void subghz_protocol_encoder_kia_v1_set_button(void* context, uint8_t button); +void subghz_protocol_encoder_kia_v1_set_counter(void* context, uint16_t counter); +void subghz_protocol_encoder_kia_v1_increment_counter(void* context); +uint16_t subghz_protocol_encoder_kia_v1_get_counter(void* context); +uint8_t subghz_protocol_encoder_kia_v1_get_button(void* context); diff --git a/lib/subghz/protocols/kia_v2.c b/lib/subghz/protocols/kia_v2.c index 18215e84..10d80c7d 100644 --- a/lib/subghz/protocols/kia_v2.c +++ b/lib/subghz/protocols/kia_v2.c @@ -1,28 +1,21 @@ #include "kia_v2.h" + +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" #include "../blocks/custom_btn_i.h" - -static uint8_t kia_v2_get_btn_code() { - uint8_t custom_btn = subghz_custom_btn_get(); - uint8_t original_btn = subghz_custom_btn_get_original(); - if(custom_btn == SUBGHZ_CUSTOM_BTN_OK) return original_btn; - if(custom_btn == SUBGHZ_CUSTOM_BTN_UP) return 0x01; // Lock - if(custom_btn == SUBGHZ_CUSTOM_BTN_DOWN) return 0x02; // Unlock - if(custom_btn == SUBGHZ_CUSTOM_BTN_LEFT) return 0x03; // Boot/Trunk - if(custom_btn == SUBGHZ_CUSTOM_BTN_RIGHT) return 0x03; // Boot/Trunk - return original_btn; -} - - +#include #include -#include +#include -#define TAG "KiaV2" +#define TAG "SubGhzProtocolKiaV2" #define KIA_V2_HEADER_PAIRS 252 #define KIA_V2_TOTAL_BURSTS 2 - -static const SubGhzBlockConst kia_protocol_v2_const = { +static const SubGhzBlockConst subghz_protocol_kia_v2_const = { .te_short = 500, .te_long = 1000, .te_delta = 150, @@ -34,7 +27,6 @@ struct SubGhzProtocolDecoderKiaV2 { SubGhzBlockDecoder decoder; SubGhzBlockGeneric generic; uint16_t header_count; - ManchesterState manchester_state; }; @@ -50,40 +42,38 @@ typedef enum { KiaV2DecoderStepCollectRawBits, } KiaV2DecoderStep; -const SubGhzProtocolDecoder kia_protocol_v2_decoder = { - .alloc = kia_protocol_decoder_v2_alloc, - .free = kia_protocol_decoder_v2_free, - .feed = kia_protocol_decoder_v2_feed, - .reset = kia_protocol_decoder_v2_reset, - .get_hash_data = kia_protocol_decoder_v2_get_hash_data, - .serialize = kia_protocol_decoder_v2_serialize, - .deserialize = kia_protocol_decoder_v2_deserialize, - .get_string = kia_protocol_decoder_v2_get_string, +const SubGhzProtocolDecoder subghz_protocol_kia_v2_decoder = { + .alloc = subghz_protocol_decoder_kia_v2_alloc, + .free = subghz_protocol_decoder_kia_v2_free, + .feed = subghz_protocol_decoder_kia_v2_feed, + .reset = subghz_protocol_decoder_kia_v2_reset, + .get_hash_data = subghz_protocol_decoder_kia_v2_get_hash_data, + .serialize = subghz_protocol_decoder_kia_v2_serialize, + .deserialize = subghz_protocol_decoder_kia_v2_deserialize, + .get_string = subghz_protocol_decoder_kia_v2_get_string, }; -const SubGhzProtocolEncoder kia_protocol_v2_encoder = { - .alloc = kia_protocol_encoder_v2_alloc, - .free = kia_protocol_encoder_v2_free, - .deserialize = kia_protocol_encoder_v2_deserialize, - .stop = kia_protocol_encoder_v2_stop, - .yield = kia_protocol_encoder_v2_yield, +const SubGhzProtocolEncoder subghz_protocol_kia_v2_encoder = { + .alloc = subghz_protocol_encoder_kia_v2_alloc, + .free = subghz_protocol_encoder_kia_v2_free, + .deserialize = subghz_protocol_encoder_kia_v2_deserialize, + .stop = subghz_protocol_encoder_kia_v2_stop, + .yield = subghz_protocol_encoder_kia_v2_yield, }; const SubGhzProtocol subghz_protocol_kia_v2 = { - .name = KIA_PROTOCOL_V2_NAME, + .name = SUBGHZ_PROTOCOL_KIA_V2_NAME, .type = SubGhzProtocolTypeDynamic, .flag = SubGhzProtocolFlag_315 | SubGhzProtocolFlag_433 | SubGhzProtocolFlag_FM | - SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | + SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, - .decoder = &kia_protocol_v2_decoder, - .encoder = &kia_protocol_v2_encoder, + .decoder = &subghz_protocol_kia_v2_decoder, + .encoder = &subghz_protocol_kia_v2_encoder, }; static uint8_t kia_v2_calculate_crc(uint64_t data) { - // Remove the CRC nibble (last 4 bits) to get the actual data uint64_t data_without_crc = data >> 4; - // Extract 6 bytes from the data uint8_t bytes[6]; bytes[0] = (uint8_t)(data_without_crc); bytes[1] = (uint8_t)(data_without_crc >> 8); @@ -100,277 +90,183 @@ static uint8_t kia_v2_calculate_crc(uint64_t data) { return (crc + 1) & 0x0F; } -static void kia_protocol_encoder_v2_get_upload(SubGhzProtocolEncoderKiaV2* instance) { - furi_check(instance); - size_t index = 0; +static void subghz_protocol_kia_v2_check_remote_controller(SubGhzProtocolDecoderKiaV2* instance) { + instance->generic.serial = (uint32_t)((instance->generic.data >> 20) & 0xFFFFFFFF); + instance->generic.btn = (uint8_t)((instance->generic.data >> 16) & 0x0F); + + uint16_t raw_count = (uint16_t)((instance->generic.data >> 4) & 0xFFF); + instance->generic.cnt = ((raw_count >> 4) | (raw_count << 8)) & 0xFFF; + + if(subghz_custom_btn_get_original() == 0) { + subghz_custom_btn_set_original(instance->generic.btn); + } + subghz_custom_btn_set_max(4); +} +static void subghz_protocol_encoder_kia_v2_get_upload(SubGhzProtocolEncoderKiaV2* instance) { + furi_assert(instance); + size_t index = 0; + uint8_t crc = kia_v2_calculate_crc(instance->generic.data); instance->generic.data = (instance->generic.data & ~0x0FULL) | crc; - + for(uint8_t burst = 0; burst < KIA_V2_TOTAL_BURSTS; burst++) { for(int i = 0; i < KIA_V2_HEADER_PAIRS; i++) { instance->encoder.upload[index++] = - level_duration_make(false, (uint32_t)kia_protocol_v2_const.te_long); + level_duration_make(false, (uint32_t)subghz_protocol_kia_v2_const.te_long); instance->encoder.upload[index++] = - level_duration_make(true, (uint32_t)kia_protocol_v2_const.te_long); + level_duration_make(true, (uint32_t)subghz_protocol_kia_v2_const.te_long); } - + instance->encoder.upload[index++] = - level_duration_make(false, (uint32_t)kia_protocol_v2_const.te_short); + level_duration_make(false, (uint32_t)subghz_protocol_kia_v2_const.te_short); for(uint8_t i = instance->generic.data_count_bit; i > 1; i--) { bool bit = bit_read(instance->generic.data, i - 2); if(bit) { instance->encoder.upload[index++] = - level_duration_make(true, (uint32_t)kia_protocol_v2_const.te_short); + level_duration_make(true, (uint32_t)subghz_protocol_kia_v2_const.te_short); instance->encoder.upload[index++] = - level_duration_make(false, (uint32_t)kia_protocol_v2_const.te_short); + level_duration_make(false, (uint32_t)subghz_protocol_kia_v2_const.te_short); } else { instance->encoder.upload[index++] = - level_duration_make(false, (uint32_t)kia_protocol_v2_const.te_short); + level_duration_make(false, (uint32_t)subghz_protocol_kia_v2_const.te_short); instance->encoder.upload[index++] = - level_duration_make(true, (uint32_t)kia_protocol_v2_const.te_short); + level_duration_make(true, (uint32_t)subghz_protocol_kia_v2_const.te_short); } } } - + instance->encoder.size_upload = index; instance->encoder.front = 0; - - FURI_LOG_I( - TAG, - "Upload built: %d bursts, size_upload=%zu, data_count_bit=%u, data=0x%016llX", - KIA_V2_TOTAL_BURSTS, - instance->encoder.size_upload, - instance->generic.data_count_bit, - instance->generic.data); } -void* kia_protocol_encoder_v2_alloc(SubGhzEnvironment* environment) { +void* subghz_protocol_encoder_kia_v2_alloc(SubGhzEnvironment* environment) { UNUSED(environment); SubGhzProtocolEncoderKiaV2* instance = malloc(sizeof(SubGhzProtocolEncoderKiaV2)); - + instance->base.protocol = &subghz_protocol_kia_v2; instance->generic.protocol_name = instance->base.protocol->name; - + instance->encoder.repeat = 10; instance->encoder.size_upload = 1300; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; instance->encoder.front = 0; - + return instance; } -void kia_protocol_encoder_v2_free(void* context) { - furi_check(context); +void subghz_protocol_encoder_kia_v2_free(void* context) { + furi_assert(context); SubGhzProtocolEncoderKiaV2* instance = context; free(instance->encoder.upload); free(instance); } -SubGhzProtocolStatus - kia_protocol_encoder_v2_deserialize(void* context, FlipperFormat* flipper_format) { - furi_check(context); - SubGhzProtocolEncoderKiaV2* instance = context; - SubGhzProtocolStatus ret = SubGhzProtocolStatusError; - - flipper_format_rewind(flipper_format); - - do { - FuriString* temp_str = furi_string_alloc(); - if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) { - FURI_LOG_E(TAG, "Missing Protocol"); - furi_string_free(temp_str); - break; - } - - if(!furi_string_equal(temp_str, instance->base.protocol->name)) { - FURI_LOG_E( - TAG, - "Wrong protocol %s != %s", - furi_string_get_cstr(temp_str), - instance->base.protocol->name); - furi_string_free(temp_str); - break; - } - furi_string_free(temp_str); - - uint32_t bit_count_temp; - if(!flipper_format_read_uint32(flipper_format, "Bit", &bit_count_temp, 1)) { - FURI_LOG_E(TAG, "Missing Bit"); - break; - } - - instance->generic.data_count_bit = kia_protocol_v2_const.min_count_bit_for_found; - - temp_str = furi_string_alloc(); - if(!flipper_format_read_string(flipper_format, "Key", temp_str)) { - FURI_LOG_E(TAG, "Missing Key"); - furi_string_free(temp_str); - break; - } - - const char* key_str = furi_string_get_cstr(temp_str); - uint64_t key = 0; - size_t str_len = strlen(key_str); - size_t hex_pos = 0; - for(size_t i = 0; i < str_len && hex_pos < 16; i++) { - char c = key_str[i]; - if(c == ' ') continue; - - uint8_t nibble; - if(c >= '0' && c <= '9') { - nibble = c - '0'; - } else if(c >= 'A' && c <= 'F') { - nibble = c - 'A' + 10; - } else if(c >= 'a' && c <= 'f') { - nibble = c - 'a' + 10; - } else { - FURI_LOG_E(TAG, "Invalid hex character: %c", c); - furi_string_free(temp_str); - break; - } - - key = (key << 4) | nibble; - hex_pos++; - } - - furi_string_free(temp_str); - - if(hex_pos != 16) { - FURI_LOG_E(TAG, "Invalid key length: %zu nibbles (expected 16)", hex_pos); - break; - } - - instance->generic.data = key; - FURI_LOG_I(TAG, "Parsed key: 0x%016llX", instance->generic.data); - - if(instance->generic.data == 0) { - FURI_LOG_E(TAG, "Key is zero after parsing!"); - break; - } - - if(!flipper_format_read_uint32(flipper_format, "Serial", &instance->generic.serial, 1)) { - instance->generic.serial = (uint32_t)((instance->generic.data >> 20) & 0xFFFFFFFF); - FURI_LOG_I(TAG, "Extracted serial: 0x%08lX", instance->generic.serial); - } else { - FURI_LOG_I(TAG, "Read serial: 0x%08lX", instance->generic.serial); - } - - uint32_t btn_temp; - if(flipper_format_read_uint32(flipper_format, "Btn", &btn_temp, 1)) { - instance->generic.btn = (uint8_t)btn_temp; - } else { - instance->generic.btn = (uint8_t)((instance->generic.data >> 16) & 0x0F); - } - subghz_custom_btn_set_original(instance->generic.btn); - subghz_custom_btn_set_max(4); - instance->generic.btn = kia_v2_get_btn_code(); - - uint32_t cnt_temp; - if(flipper_format_read_uint32(flipper_format, "Cnt", &cnt_temp, 1)) { - instance->generic.cnt = (uint16_t)cnt_temp; - FURI_LOG_I(TAG, "Read counter: 0x%03lX", (unsigned long)instance->generic.cnt); - } else { - uint16_t raw_count = (uint16_t)((instance->generic.data >> 4) & 0xFFF); - instance->generic.cnt = ((raw_count >> 4) | (raw_count << 8)) & 0xFFF; - FURI_LOG_I(TAG, "Extracted counter: 0x%03lX", (unsigned long)instance->generic.cnt); - } - - uint64_t new_data = 0; - - new_data |= 1ULL << 52; - - new_data |= ((uint64_t)instance->generic.serial << 20) & 0xFFFFFFFFF00000ULL; - - uint32_t uVar6 = ((uint32_t)(instance->generic.cnt & 0xFF) << 8) | - ((uint32_t)(instance->generic.btn & 0x0F) << 16) | - ((uint32_t)(instance->generic.cnt >> 4) & 0xF0); - - new_data |= (uint64_t)uVar6; - - instance->generic.data = new_data; - instance->generic.data_count_bit = 53; - - FURI_LOG_I( - TAG, - "Encoder reconstruct: serial=0x%08lX, btn=0x%X, cnt=0x%03lX, uVar6=0x%05lX, data=0x%016llX", - (unsigned long)instance->generic.serial, - (unsigned int)instance->generic.btn, - (unsigned long)instance->generic.cnt, - (unsigned long)uVar6, - (unsigned long long)instance->generic.data); - - if(!flipper_format_read_uint32( - flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1)) { - instance->encoder.repeat = 10; - FURI_LOG_D(TAG, "Repeat not found in file, using default 10"); - } - - kia_protocol_encoder_v2_get_upload(instance); - - instance->encoder.is_running = true; - - FURI_LOG_I( - TAG, - "Encoder deserialized: repeat=%u, size_upload=%zu, is_running=%d, front=%zu", - instance->encoder.repeat, - instance->encoder.size_upload, - instance->encoder.is_running, - instance->encoder.front); - - ret = SubGhzProtocolStatusOk; - } while(false); - - return ret; -} - -void kia_protocol_encoder_v2_stop(void* context) { - furi_check(context); +void subghz_protocol_encoder_kia_v2_stop(void* context) { + furi_assert(context); SubGhzProtocolEncoderKiaV2* instance = context; instance->encoder.is_running = false; } -LevelDuration kia_protocol_encoder_v2_yield(void* context) { - furi_check(context); +LevelDuration subghz_protocol_encoder_kia_v2_yield(void* context) { + furi_assert(context); SubGhzProtocolEncoderKiaV2* instance = context; - + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { - FURI_LOG_D( - TAG, - "Encoder yield stopped: repeat=%u, is_running=%d", - instance->encoder.repeat, - instance->encoder.is_running); instance->encoder.is_running = false; return level_duration_reset(); } - + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; - - if(instance->encoder.front < 5 || instance->encoder.front == 0) { - FURI_LOG_D( - TAG, - "Encoder yield[%zu]: repeat=%u, size=%zu, level=%d, duration=%lu", - instance->encoder.front, - instance->encoder.repeat, - instance->encoder.size_upload, - level_duration_get_level(ret), - level_duration_get_duration(ret)); - } - + if(++instance->encoder.front == instance->encoder.size_upload) { instance->encoder.repeat--; instance->encoder.front = 0; - FURI_LOG_I( - TAG, "Encoder completed one cycle, remaining repeat=%u", instance->encoder.repeat); } - + return ret; } -void* kia_protocol_decoder_v2_alloc(SubGhzEnvironment* environment) { +SubGhzProtocolStatus subghz_protocol_encoder_kia_v2_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderKiaV2* instance = context; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; + + do { + ret = subghz_block_generic_deserialize(&instance->generic, flipper_format); + if(ret != SubGhzProtocolStatusOk) { + break; + } + + instance->generic.data_count_bit = subghz_protocol_kia_v2_const.min_count_bit_for_found; + + instance->generic.serial = (uint32_t)((instance->generic.data >> 20) & 0xFFFFFFFF); + instance->generic.btn = (uint8_t)((instance->generic.data >> 16) & 0x0F); + + uint16_t raw_count = (uint16_t)((instance->generic.data >> 4) & 0xFFF); + instance->generic.cnt = ((raw_count >> 4) | (raw_count << 8)) & 0xFFF; + + if(subghz_custom_btn_get_original() == 0) { + subghz_custom_btn_set_original(instance->generic.btn); + } + subghz_custom_btn_set_max(4); + + if(instance->generic.cnt < 0xFFF) { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + if(instance->generic.cnt > 0xFFF) { + instance->generic.cnt = 0; + } + } else { + instance->generic.cnt = 0; + } + + uint8_t btn = subghz_custom_btn_get(); + if(btn != SUBGHZ_CUSTOM_BTN_OK) { + instance->generic.btn = btn; + } + + uint64_t bit52 = instance->generic.data & (1ULL << 52); + + uint64_t new_data = 0; + new_data |= bit52; + new_data |= ((uint64_t)instance->generic.serial << 20) & 0x000FFFFFFFF00000ULL; + + uint32_t uVar6 = ((uint32_t)(instance->generic.cnt & 0xFF) << 8) | + ((uint32_t)(instance->generic.btn & 0x0F) << 16) | + ((uint32_t)(instance->generic.cnt >> 4) & 0xF0); + new_data |= (uint64_t)uVar6; + + instance->generic.data = new_data; + instance->generic.data_count_bit = 53; + + subghz_protocol_encoder_kia_v2_get_upload(instance); + + if(!flipper_format_rewind(flipper_format)) { + ret = SubGhzProtocolStatusErrorParserOthers; + break; + } + + uint8_t key_data[sizeof(uint64_t)] = {0}; + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data >> (i * 8)) & 0xFF; + } + if(!flipper_format_update_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { + ret = SubGhzProtocolStatusErrorParserKey; + break; + } + + instance->encoder.is_running = true; + ret = SubGhzProtocolStatusOk; + + } while(false); + + return ret; +} + +void* subghz_protocol_decoder_kia_v2_alloc(SubGhzEnvironment* environment) { UNUSED(environment); SubGhzProtocolDecoderKiaV2* instance = malloc(sizeof(SubGhzProtocolDecoderKiaV2)); instance->base.protocol = &subghz_protocol_kia_v2; @@ -378,14 +274,14 @@ void* kia_protocol_decoder_v2_alloc(SubGhzEnvironment* environment) { return instance; } -void kia_protocol_decoder_v2_free(void* context) { - furi_check(context); +void subghz_protocol_decoder_kia_v2_free(void* context) { + furi_assert(context); SubGhzProtocolDecoderKiaV2* instance = context; free(instance); } -void kia_protocol_decoder_v2_reset(void* context) { - furi_check(context); +void subghz_protocol_decoder_kia_v2_reset(void* context) { + furi_assert(context); SubGhzProtocolDecoderKiaV2* instance = context; instance->decoder.parser_step = KiaV2DecoderStepReset; instance->header_count = 0; @@ -394,35 +290,28 @@ void kia_protocol_decoder_v2_reset(void* context) { instance->decoder.decode_count_bit = 0; } -void kia_protocol_decoder_v2_feed(void* context, bool level, uint32_t duration) { - furi_check(context); +void subghz_protocol_decoder_kia_v2_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); SubGhzProtocolDecoderKiaV2* instance = context; switch(instance->decoder.parser_step) { case KiaV2DecoderStepReset: - if((level) && (DURATION_DIFF(duration, kia_protocol_v2_const.te_long) < - kia_protocol_v2_const.te_delta)) { + if(DURATION_DIFF(duration, subghz_protocol_kia_v2_const.te_long) < subghz_protocol_kia_v2_const.te_delta) { instance->decoder.parser_step = KiaV2DecoderStepCheckPreamble; instance->decoder.te_last = duration; instance->header_count = 0; - manchester_advance( - instance->manchester_state, - ManchesterEventReset, - &instance->manchester_state, - NULL); + manchester_advance(instance->manchester_state, ManchesterEventReset, + &instance->manchester_state, NULL); } break; - case KiaV2DecoderStepCheckPreamble: - if(level) // HIGH pulse - { - if(DURATION_DIFF(duration, kia_protocol_v2_const.te_long) < - kia_protocol_v2_const.te_delta) { + if(level) { + if(DURATION_DIFF(duration, subghz_protocol_kia_v2_const.te_long) < + subghz_protocol_kia_v2_const.te_delta) { instance->decoder.te_last = duration; instance->header_count++; - } else if( - DURATION_DIFF(duration, kia_protocol_v2_const.te_short) < - kia_protocol_v2_const.te_delta) { + } else if(DURATION_DIFF(duration, subghz_protocol_kia_v2_const.te_short) < + subghz_protocol_kia_v2_const.te_delta) { if(instance->header_count >= 100) { instance->header_count = 0; instance->decoder.decode_data = 0; @@ -436,13 +325,12 @@ void kia_protocol_decoder_v2_feed(void* context, bool level, uint32_t duration) instance->decoder.parser_step = KiaV2DecoderStepReset; } } else { - if(DURATION_DIFF(duration, kia_protocol_v2_const.te_long) < - kia_protocol_v2_const.te_delta) { + if(DURATION_DIFF(duration, subghz_protocol_kia_v2_const.te_long) < + subghz_protocol_kia_v2_const.te_delta) { instance->header_count++; instance->decoder.te_last = duration; - } else if( - DURATION_DIFF(duration, kia_protocol_v2_const.te_short) < - kia_protocol_v2_const.te_delta) { + } else if(DURATION_DIFF(duration, subghz_protocol_kia_v2_const.te_short) < + subghz_protocol_kia_v2_const.te_delta) { instance->decoder.te_last = duration; } else { instance->decoder.parser_step = KiaV2DecoderStepReset; @@ -452,13 +340,12 @@ void kia_protocol_decoder_v2_feed(void* context, bool level, uint32_t duration) case KiaV2DecoderStepCollectRawBits: { ManchesterEvent event; - - if(DURATION_DIFF(duration, kia_protocol_v2_const.te_short) < - kia_protocol_v2_const.te_delta) { + + if(DURATION_DIFF(duration, subghz_protocol_kia_v2_const.te_short) < + subghz_protocol_kia_v2_const.te_delta) { event = level ? ManchesterEventShortLow : ManchesterEventShortHigh; - } else if( - DURATION_DIFF(duration, kia_protocol_v2_const.te_long) < - kia_protocol_v2_const.te_delta) { + } else if(DURATION_DIFF(duration, subghz_protocol_kia_v2_const.te_long) < + subghz_protocol_kia_v2_const.te_delta) { event = level ? ManchesterEventLongLow : ManchesterEventLongHigh; } else { instance->decoder.parser_step = KiaV2DecoderStepReset; @@ -466,8 +353,8 @@ void kia_protocol_decoder_v2_feed(void* context, bool level, uint32_t duration) } bool data_bit; - if(manchester_advance( - instance->manchester_state, event, &instance->manchester_state, &data_bit)) { + if(manchester_advance(instance->manchester_state, event, + &instance->manchester_state, &data_bit)) { instance->decoder.decode_data = (instance->decoder.decode_data << 1) | data_bit; instance->decoder.decode_count_bit++; @@ -488,6 +375,7 @@ void kia_protocol_decoder_v2_feed(void* context, bool level, uint32_t duration) instance->decoder.decode_count_bit = 0; instance->header_count = 0; instance->decoder.parser_step = KiaV2DecoderStepReset; + manchester_advance(instance->manchester_state, ManchesterEventReset, &instance->manchester_state, NULL); } } break; @@ -495,67 +383,66 @@ void kia_protocol_decoder_v2_feed(void* context, bool level, uint32_t duration) } } -uint8_t kia_protocol_decoder_v2_get_hash_data(void* context) { - furi_check(context); +uint8_t subghz_protocol_decoder_kia_v2_get_hash_data(void* context) { + furi_assert(context); SubGhzProtocolDecoderKiaV2* instance = context; - return subghz_protocol_blocks_get_hash_data( - &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); + + uint32_t hash = instance->generic.serial; + hash ^= (instance->generic.btn << 24); + hash ^= (instance->generic.cnt << 12); + + return (uint8_t)(hash ^ (hash >> 8) ^ (hash >> 16) ^ (hash >> 24)); } -SubGhzProtocolStatus kia_protocol_decoder_v2_serialize( +SubGhzProtocolStatus subghz_protocol_decoder_kia_v2_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset) { - furi_check(context); + furi_assert(context); SubGhzProtocolDecoderKiaV2* instance = context; - - SubGhzProtocolStatus ret = - subghz_block_generic_serialize(&instance->generic, flipper_format, preset); - - if(ret == SubGhzProtocolStatusOk) { - uint32_t crc = instance->generic.data & 0x0F; - flipper_format_write_uint32(flipper_format, "CRC", &crc, 1); - flipper_format_write_uint32(flipper_format, "Serial", &instance->generic.serial, 1); - uint32_t temp = instance->generic.btn; - flipper_format_write_uint32(flipper_format, "Btn", &temp, 1); - flipper_format_write_uint32(flipper_format, "Cnt", &instance->generic.cnt, 1); - uint32_t raw_count = (uint32_t)((instance->generic.data >> 4) & 0xFFF); - flipper_format_write_uint32(flipper_format, "RawCnt", &raw_count, 1); - } - - return ret; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } -SubGhzProtocolStatus - kia_protocol_decoder_v2_deserialize(void* context, FlipperFormat* flipper_format) { - furi_check(context); +SubGhzProtocolStatus subghz_protocol_decoder_kia_v2_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); SubGhzProtocolDecoderKiaV2* instance = context; return subghz_block_generic_deserialize_check_count_bit( - &instance->generic, flipper_format, kia_protocol_v2_const.min_count_bit_for_found); + &instance->generic, flipper_format, subghz_protocol_kia_v2_const.min_count_bit_for_found); } -void kia_protocol_decoder_v2_get_string(void* context, FuriString* output) { - furi_check(context); +static const char* subghz_protocol_kia_v2_get_name_button(uint8_t btn) { + switch(btn) { + case 0x1: return "Lock"; + case 0x2: return "Unlock"; + case 0x3: return "Trunk"; + case 0x4: return "Panic"; + default: return "Unknown"; + } +} + +void subghz_protocol_decoder_kia_v2_get_string(void* context, FuriString* output) { + furi_assert(context); SubGhzProtocolDecoderKiaV2* instance = context; - subghz_custom_btn_set_original(instance->generic.btn); - subghz_custom_btn_set_max(4); - uint8_t crc = instance->generic.data & 0x0F; - - bool crc_valid = crc == kia_v2_calculate_crc(instance->generic.data); + subghz_protocol_kia_v2_check_remote_controller(instance); + uint8_t crc_received = instance->generic.data & 0x0F; + uint8_t crc_calculated = kia_v2_calculate_crc(instance->generic.data); + bool crc_ok = (crc_received == crc_calculated); furi_string_cat_printf( output, "%s %dbit\r\n" "Key:%013llX\r\n" - "Sn:%08lX Btn:%X\r\n" - "Cnt:%03lX CRC:%X - %s\r\n", + "Sn:%08lX Cnt:%03lX\r\n" + "Btn:%02X:[%s]\r\n" + "CRC:%X %s", instance->generic.protocol_name, instance->generic.data_count_bit, instance->generic.data, instance->generic.serial, - kia_v2_get_btn_code(), instance->generic.cnt, - crc, - crc_valid ? "OK" : "BAD"); + instance->generic.btn, + subghz_protocol_kia_v2_get_name_button(instance->generic.btn), + crc_received, + crc_ok ? "(OK)" : "(FAIL)"); } diff --git a/lib/subghz/protocols/kia_v2.h b/lib/subghz/protocols/kia_v2.h index 990248db..9fb9c50c 100644 --- a/lib/subghz/protocols/kia_v2.h +++ b/lib/subghz/protocols/kia_v2.h @@ -1,34 +1,30 @@ #pragma once -#include "kia_generic.h" +#include "base.h" +#include "../blocks/math.h" #include - -#define KIA_PROTOCOL_V2_NAME "KIA/HYU V2" +#define SUBGHZ_PROTOCOL_KIA_V2_NAME "KIA/HYU V2" typedef struct SubGhzProtocolDecoderKiaV2 SubGhzProtocolDecoderKiaV2; typedef struct SubGhzProtocolEncoderKiaV2 SubGhzProtocolEncoderKiaV2; -extern const SubGhzProtocolDecoder kia_protocol_v2_decoder; -extern const SubGhzProtocolEncoder kia_protocol_v2_encoder; extern const SubGhzProtocol subghz_protocol_kia_v2; -void* kia_protocol_decoder_v2_alloc(SubGhzEnvironment* environment); -void kia_protocol_decoder_v2_free(void* context); -void kia_protocol_decoder_v2_reset(void* context); -void kia_protocol_decoder_v2_feed(void* context, bool level, uint32_t duration); -uint8_t kia_protocol_decoder_v2_get_hash_data(void* context); -SubGhzProtocolStatus kia_protocol_decoder_v2_serialize( +void* subghz_protocol_decoder_kia_v2_alloc(SubGhzEnvironment* environment); +void subghz_protocol_decoder_kia_v2_free(void* context); +void subghz_protocol_decoder_kia_v2_reset(void* context); +void subghz_protocol_decoder_kia_v2_feed(void* context, bool level, uint32_t duration); +uint8_t subghz_protocol_decoder_kia_v2_get_hash_data(void* context); +SubGhzProtocolStatus subghz_protocol_decoder_kia_v2_serialize( void* context, FlipperFormat* flipper_format, SubGhzRadioPreset* preset); -SubGhzProtocolStatus - kia_protocol_decoder_v2_deserialize(void* context, FlipperFormat* flipper_format); -void kia_protocol_decoder_v2_get_string(void* context, FuriString* output); +SubGhzProtocolStatus subghz_protocol_decoder_kia_v2_deserialize(void* context, FlipperFormat* flipper_format); +void subghz_protocol_decoder_kia_v2_get_string(void* context, FuriString* output); -void* kia_protocol_encoder_v2_alloc(SubGhzEnvironment* environment); -void kia_protocol_encoder_v2_free(void* context); -SubGhzProtocolStatus - kia_protocol_encoder_v2_deserialize(void* context, FlipperFormat* flipper_format); -void kia_protocol_encoder_v2_stop(void* context); -LevelDuration kia_protocol_encoder_v2_yield(void* context); +void* subghz_protocol_encoder_kia_v2_alloc(SubGhzEnvironment* environment); +void subghz_protocol_encoder_kia_v2_free(void* context); +SubGhzProtocolStatus subghz_protocol_encoder_kia_v2_deserialize(void* context, FlipperFormat* flipper_format); +void subghz_protocol_encoder_kia_v2_stop(void* context); +LevelDuration subghz_protocol_encoder_kia_v2_yield(void* context);