From 266d90a600676b9e0de4351a1bf0eb18eb5058a8 Mon Sep 17 00:00:00 2001 From: Totoo Date: Sat, 10 Jan 2026 14:47:33 +0100 Subject: [PATCH] Updated subcar processors (#2913) --- .../external/subcarrx/ui_subcar.cpp | 82 +++++++- firmware/baseband/fprotos/c-fiat_v0.hpp | 8 +- firmware/baseband/fprotos/c-kia_v0.hpp | 33 ++-- firmware/baseband/fprotos/c-kia_v1.hpp | 186 ++++-------------- firmware/baseband/fprotos/c-kia_v2.hpp | 169 ++++++---------- firmware/baseband/fprotos/c-kia_v3v4.hpp | 24 +-- firmware/baseband/fprotos/c-kia_v5.hpp | 146 ++++---------- firmware/baseband/fprotos/c-subaru.hpp | 1 + firmware/baseband/fprotos/c-suzuki.hpp | 115 ++++++----- 9 files changed, 304 insertions(+), 460 deletions(-) diff --git a/firmware/application/external/subcarrx/ui_subcar.cpp b/firmware/application/external/subcarrx/ui_subcar.cpp index cfd6bdef0..8d075c9d9 100644 --- a/firmware/application/external/subcarrx/ui_subcar.cpp +++ b/firmware/application/external/subcarrx/ui_subcar.cpp @@ -266,10 +266,11 @@ void SubCarRecentEntryDetailView::parseProtocol() { if (entry_.sensorType == FPC_Invalid) return; if (entry_.sensorType == FPC_SUZUKI) { - uint32_t serial_button = (((entry_.data >> 32) & 0xFFF) << 20) | (entry_.data >> 12); - serial = serial_button >> 4; - uint8_t buttonid = serial_button & 0xF; - cnt = (entry_.data >> 44) & 0xFFFF; + uint32_t data_high = (uint32_t)(entry_.data >> 32); + uint32_t data_low = (uint32_t)entry_.data; + serial = ((data_high & 0xFFF) << 16) | (data_low >> 16); + uint8_t buttonid = (data_low >> 12) & 0xF; + cnt = (data_high << 4) >> 16; btn = to_string_dec_uint(buttonid); return; } @@ -320,15 +321,78 @@ void SubCarRecentEntryDetailView::parseProtocol() { } if (entry_.sensorType == FPC_KIAV5) { - serial = (uint32_t)(((entry_.data >> 32) & 0x0FFFFFFF) >> 1); - uint8_t button = (entry_.data >> 61) & 0x07; + uint64_t yek = 0; + for (int i = 0; i < 8; i++) { + uint8_t byte = (entry_.data2 >> (i * 8)) & 0xFF; + uint8_t reversed = 0; + for (int b = 0; b < 8; b++) { + if (byte & (1 << b)) + reversed |= (1 << (7 - b)); + } + yek |= ((uint64_t)reversed << ((7 - i) * 8)); + } + serial = (uint32_t)((yek >> 32) & 0x0FFFFFFF); + uint8_t button = (uint8_t)((yek >> 60) & 0x0F); + uint32_t encrypted = (uint32_t)(yek & 0xFFFFFFFF); btn = to_string_dec_uint(button); - cnt = (uint16_t)(entry_.data & 0xFFFF); + // decode + uint8_t keystore_bytes[] = {0x53, 0x54, 0x46, 0x52, 0x4b, 0x45, 0x30, 0x30}; + uint8_t s0 = (encrypted & 0xFF); + uint8_t s1 = (encrypted >> 8) & 0xFF; + uint8_t s2 = (encrypted >> 16) & 0xFF; + uint8_t s3 = (encrypted >> 24) & 0xFF; + int round_index = 1; + for (size_t i = 0; i < 18; i++) { + uint8_t r = keystore_bytes[round_index] & 0xFF; + int steps = 8; + while (steps > 0) { + uint8_t base; + if ((s3 & 0x40) == 0) { + base = (s3 & 0x02) == 0 ? 0x74 : 0x2E; + } else { + base = (s3 & 0x02) == 0 ? 0x3A : 0x5C; + } + + if (s2 & 0x08) { + base = (((base >> 4) & 0x0F) | ((base & 0x0F) << 4)) & 0xFF; + } + if (s1 & 0x01) { + base = ((base & 0x3F) << 2) & 0xFF; + } + if (s0 & 0x01) { + base = (base << 1) & 0xFF; + } + + uint8_t temp = (s3 ^ s1) & 0xFF; + s3 = ((s3 & 0x7F) << 1) & 0xFF; + if (s2 & 0x80) { + s3 |= 0x01; + } + s2 = ((s2 & 0x7F) << 1) & 0xFF; + if (s1 & 0x80) { + s2 |= 0x01; + } + s1 = ((s1 & 0x7F) << 1) & 0xFF; + if (s0 & 0x80) { + s1 |= 0x01; + } + s0 = ((s0 & 0x7F) << 1) & 0xFF; + + uint8_t chk = (base ^ (r ^ temp)) & 0xFF; + if (chk & 0x80) { + s0 |= 0x01; + } + r = ((r & 0x7F) << 1) & 0xFF; + steps--; + } + round_index = (round_index - 1) & 0x7; + } + cnt = (s0 + (s1 << 8)) & 0xFFFF; } if (entry_.sensorType == FPC_KIAV3V4) { // not decrypted! - serial = SD_NO_SERIAL; //(uint32_t)entry_.data; + serial = (uint32_t)entry_.data; // uint8_t button = entry_.data2 & 0xFF; btn = "?"; // to_string_dec_uint(button); } @@ -344,7 +408,7 @@ void SubCarRecentEntryDetailView::parseProtocol() { if (entry_.sensorType == FPC_KIAV1) { serial = (uint32_t)((entry_.data >> 24) & 0xFFFFFFFF); uint8_t button = (uint8_t)((entry_.data >> 16) & 0xFF); - cnt = (uint8_t)((entry_.data >> 8) & 0xFF); + cnt = (uint8_t)((entry_.data >> 4) & 0xF) << 8 | ((entry_.data >> 8) & 0xFF); btn = to_string_dec_uint(button); } diff --git a/firmware/baseband/fprotos/c-fiat_v0.hpp b/firmware/baseband/fprotos/c-fiat_v0.hpp index 589cfff79..b68311700 100644 --- a/firmware/baseband/fprotos/c-fiat_v0.hpp +++ b/firmware/baseband/fprotos/c-fiat_v0.hpp @@ -161,8 +161,6 @@ class FProtoSubCarFiatV0 : public FProtoSubCarBase { } if (bit_count > 0x46) { - final_count = bit_count; - endbyte = (uint8_t)data_low; /* generic.data = ((uint64_t)hop << 32) | fix; @@ -192,13 +190,11 @@ class FProtoSubCarFiatV0 : public FProtoSubCarBase { ManchesterState manchester_state = ManchesterStateMid1; uint8_t decoder_state = 0; + uint8_t bit_count = 0; + uint8_t endbyte = 0; uint16_t preamble_count = 0; uint32_t data_low = 0; uint32_t data_high = 0; - uint8_t bit_count = 0; uint32_t hop = 0; uint32_t fix = 0; - uint8_t endbyte = 0; - uint8_t final_count = 0; - uint32_t te_last = 0; }; diff --git a/firmware/baseband/fprotos/c-kia_v0.hpp b/firmware/baseband/fprotos/c-kia_v0.hpp index 7b2bf1a1b..5b17a1a6d 100644 --- a/firmware/baseband/fprotos/c-kia_v0.hpp +++ b/firmware/baseband/fprotos/c-kia_v0.hpp @@ -59,20 +59,26 @@ class FProtoSubCarKiaV0 : public FProtoSubCarBase { break; case KIADecoderStepSaveDuration: if (level) { - if (duration >= - (te_long + te_delta * 2UL)) { - // Signal ended too early! - // FURI_LOG_W(TAG, "Signal ended at %u bits (expected 61). Duration: %lu", decode_count_bit, duration); - + if (duration >= (te_long + te_delta * 2UL)) { + // End of transmission detected parser_step = KIADecoderStepReset; + if (decode_count_bit == min_count_bit_for_found) { - // instance->generic.data = decode_data; + // data = decode_data; data_count_bit = decode_count_bit; + // just used for log yet, so skip + // if (kia_verify_crc()) { + // FURI_LOG_I(TAG, "Valid signal received with correct CRC"); + // } else { + // FURI_LOG_W(TAG, "Signal received but CRC mismatch!"); + // } + if (callback) callback(this); } else { - // FURI_LOG_E(TAG, "Incomplete signal: only %u bits", decode_count_bit); + // FURI_LOG_E(TAG, "Incomplete signal: only %u bits", instance->decoder.decode_count_bit); } + decode_data = 0; decode_count_bit = 0; break; @@ -80,26 +86,19 @@ class FProtoSubCarKiaV0 : public FProtoSubCarBase { te_last = duration; parser_step = KIADecoderStepCheckDuration; } + } else { parser_step = KIADecoderStepReset; } break; case KIADecoderStepCheckDuration: if (!level) { - if ((DURATION_DIFF(te_last, te_short) < te_delta) && - (DURATION_DIFF(duration, te_short) < te_delta)) { + if ((DURATION_DIFF(te_last, te_short) < te_delta) && (DURATION_DIFF(duration, te_short) < te_delta)) { subghz_protocol_blocks_add_bit(0); - if (decode_count_bit % 10 == 0) { - // FURI_LOG_D(TAG, "Decoded %u bits so far", decode_count_bit); - } parser_step = KIADecoderStepSaveDuration; } else if ( - (DURATION_DIFF(te_last, te_long) < te_delta) && - (DURATION_DIFF(duration, te_long) < te_delta)) { + (DURATION_DIFF(te_last, te_long) < te_delta) && (DURATION_DIFF(duration, te_long) < te_delta)) { subghz_protocol_blocks_add_bit(1); - if (decode_count_bit % 10 == 0) { - // FURI_LOG_D(TAG, "Decoded %u bits so far", decode_count_bit); - } parser_step = KIADecoderStepSaveDuration; } else { // FURI_LOG_W(TAG, "Timing mismatch at bit %u. Last: %lu, Current: %lu", decode_count_bit, te_last, duration); diff --git a/firmware/baseband/fprotos/c-kia_v1.hpp b/firmware/baseband/fprotos/c-kia_v1.hpp index 7a0202d18..dd28d1290 100644 --- a/firmware/baseband/fprotos/c-kia_v1.hpp +++ b/firmware/baseband/fprotos/c-kia_v1.hpp @@ -5,8 +5,7 @@ typedef enum { KiaV1DecoderStepReset = 0, KiaV1DecoderStepCheckPreamble, - KiaV1DecoderStepFoundShortLow, - KiaV1DecoderStepCollectRawBits, + KiaV1DecoderStepDecodeData, } KiaV1DecoderStep; class FProtoSubCarKiaV1 : public FProtoSubCarBase { @@ -16,177 +15,74 @@ class FProtoSubCarKiaV1 : public FProtoSubCarBase { te_short = 800; te_long = 1600; te_delta = 200; - min_count_bit_for_found = 56; - } - void kia_v1_add_raw_bit(bool bit) { - if (raw_bit_count < 192) { - uint16_t byte_idx = raw_bit_count / 8; - uint8_t bit_idx = 7 - (raw_bit_count % 8); - if (bit) { - raw_bits[byte_idx] |= (1 << bit_idx); - } else { - raw_bits[byte_idx] &= ~(1 << bit_idx); - } - raw_bit_count++; - } - } - inline bool kia_v1_get_raw_bit(uint16_t idx) { - uint16_t byte_idx = idx / 8; - uint8_t bit_idx = 7 - (idx % 8); - return (raw_bits[byte_idx] >> bit_idx) & 1; - } - bool kia_v1_manchester_decode() { - if (raw_bit_count < 113) { - // FURI_LOG_D(TAG, "Not enough raw bits: %u", raw_bit_count); - return false; - } - // Try different offsets to find best alignment (RTL-433 uses -1 bit offset) - uint16_t best_bits = 0; - uint64_t best_data = 0; - // uint16_t best_offset = 0; - - for (uint16_t offset = 0; offset < 8; offset++) { - uint64_t data = 0; - uint16_t decoded_bits = 0; - - for (uint16_t i = offset; i + 1 < raw_bit_count && decoded_bits < 56; i += 2) { - bool bit1 = kia_v1_get_raw_bit(i); - bool bit2 = kia_v1_get_raw_bit(i + 1); - - uint8_t two_bits = (bit1 << 1) | bit2; - - // V1 uses: 10=1, 01=0 - if (two_bits == 0x02) { // 10 = decoded 1 - data = (data << 1) | 1; - decoded_bits++; - } else if (two_bits == 0x01) { // 01 = decoded 0 - data = (data << 1); - decoded_bits++; - } else { - break; - } - } - - if (decoded_bits > best_bits) { - best_bits = decoded_bits; - best_data = data; - // best_offset = offset; - } - } - - // FURI_LOG_I(TAG, "Best: offset=%u bits=%u data=%014llX", best_offset, best_bits, best_data); - - decode_data = best_data; - decode_count_bit = best_bits; - - return best_bits >= min_count_bit_for_found; + min_count_bit_for_found = 57; } void feed(bool level, uint32_t duration) { + ManchesterEvent event = ManchesterEventReset; + switch (parser_step) { case KiaV1DecoderStepReset: - // Preamble 0xCCCCCCCD produces alternating LONG pulses - if ((level) && (DURATION_DIFF(duration, te_long) < - te_delta)) { + if ((level) && (DURATION_DIFF(duration, te_long) < te_delta)) { parser_step = KiaV1DecoderStepCheckPreamble; te_last = duration; - header_count = 1; + header_count = 0; + decode_data = 0; + decode_count_bit = 0; + FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL); } break; case KiaV1DecoderStepCheckPreamble: - if (level) { - if (DURATION_DIFF(duration, te_long) < - te_delta) { - te_last = duration; + if (!level) { + if ((DURATION_DIFF(duration, te_long) < te_delta) && (DURATION_DIFF(te_last, te_long) < te_delta)) { header_count++; - } else if ( - DURATION_DIFF(duration, te_short) < - te_delta) { te_last = duration; } else { parser_step = KiaV1DecoderStepReset; } - } else { - // LOW pulse - if (DURATION_DIFF(duration, te_long) < - te_delta) { - header_count++; - } else if ( - DURATION_DIFF(duration, te_short) < - te_delta) { - // Short LOW - this is the start of sync (0xCD ends: ...long H, short L, short H) - if (header_count > 12) { - parser_step = KiaV1DecoderStepFoundShortLow; - } - } else { - parser_step = KiaV1DecoderStepReset; + } + if (header_count > 70) { + if ((!level) && (DURATION_DIFF(duration, te_short) < te_delta) && (DURATION_DIFF(te_last, te_long) < te_delta)) { + decode_count_bit = 1; + subghz_protocol_blocks_add_bit(1); + header_count = 0; + parser_step = KiaV1DecoderStepDecodeData; } } break; - case KiaV1DecoderStepFoundShortLow: - // Expecting SHORT HIGH to complete sync - if (level && (DURATION_DIFF(duration, te_short) < - te_delta)) { - // FURI_LOG_I(TAG, "Sync! hdr=%u", header_count); - parser_step = KiaV1DecoderStepCollectRawBits; - raw_bit_count = 0; - memset(raw_bits, 0, sizeof(raw_bits)); - // Add the sync short HIGH as first raw bit - kia_v1_add_raw_bit(true); - } else { - parser_step = KiaV1DecoderStepReset; + case KiaV1DecoderStepDecodeData: + if ((DURATION_DIFF(duration, te_short) < te_delta)) { + event = level ? ManchesterEventShortLow : ManchesterEventShortHigh; + } else if ((DURATION_DIFF(duration, te_long) < + te_delta)) { + event = level ? ManchesterEventLongLow : ManchesterEventLongHigh; } - break; - case KiaV1DecoderStepCollectRawBits: - if (duration > 2400) { - // FURI_LOG_I(TAG, "End! raw_bits=%u", raw_bit_count); - - if (kia_v1_manchester_decode()) { - // instance->generic.data = decode_data; - data_count_bit = raw_bit_count / 8; - - // Extract fields from 56-bit data per RTL-433: - // Serial: bits 55-24 (32 bits) - // Btn: bits 23-16 (8 bits) - // Count: bits 15-8 (8 bits) - // CRC: bits 7-0 (8 bits) - // instance->generic.serial = (uint32_t)((instance->generic.data >> 24) & 0xFFFFFFFF); - // instance->generic.btn = (uint8_t)((instance->generic.data >> 16) & 0xFF); - // instance->generic.cnt = (uint8_t)((instance->generic.data >> 8) & 0xFF); - - if (callback) - callback(this); + if (event != ManchesterEventReset) { + bool data; + bool data_ok = FProtoGeneral::manchester_advance(manchester_saved_state, event, &manchester_saved_state, &data); + if (data_ok) { + decode_data = (decode_data << 1) | data; + decode_count_bit++; } + } + if (decode_count_bit == min_count_bit_for_found) { + // instance->generic.data = decode_data; + data_count_bit = decode_count_bit; + if (callback) + callback(this); + + decode_data = 0; + decode_count_bit = 0; parser_step = KiaV1DecoderStepReset; - break; } - - int num_bits = 0; - if (DURATION_DIFF(duration, te_short) < - te_delta) { - num_bits = 1; - } else if ( - DURATION_DIFF(duration, te_long) < - te_delta) { - num_bits = 2; - } else { - parser_step = KiaV1DecoderStepReset; - break; - } - - for (int i = 0; i < num_bits; i++) { - kia_v1_add_raw_bit(level); - } - break; } } - uint8_t raw_bits[24]{0}; - uint16_t raw_bit_count = 0; - uint16_t header_count = 0; + uint8_t header_count = 0; + ManchesterState manchester_saved_state = ManchesterStateStart1; }; diff --git a/firmware/baseband/fprotos/c-kia_v2.hpp b/firmware/baseband/fprotos/c-kia_v2.hpp index 2f86d5013..82682f45a 100644 --- a/firmware/baseband/fprotos/c-kia_v2.hpp +++ b/firmware/baseband/fprotos/c-kia_v2.hpp @@ -15,65 +15,7 @@ class FProtoSubCarKiaV2 : public FProtoSubCarBase { te_short = 500; te_long = 1000; te_delta = 160; - min_count_bit_for_found = 51; - } - - void kia_v2_add_raw_bit(bool bit) { - if (raw_bit_count < 160) { - uint16_t byte_idx = raw_bit_count / 8; - uint8_t bit_idx = 7 - (raw_bit_count % 8); - if (bit) { - raw_bits[byte_idx] |= (1 << bit_idx); - } else { - raw_bits[byte_idx] &= ~(1 << bit_idx); - } - raw_bit_count++; - } - } - inline bool kia_v2_get_raw_bit(uint16_t idx) { - uint16_t byte_idx = idx / 8; - uint8_t bit_idx = 7 - (idx % 8); - return (raw_bits[byte_idx] >> bit_idx) & 1; - } - bool kia_v2_manchester_decode() { - if (raw_bit_count < 100) { - return false; - } - - uint16_t best_bits = 0; - uint64_t best_data = 0; - - for (uint16_t offset = 0; offset < 8; offset++) { - uint64_t data = 0; - uint16_t decoded_bits = 0; - - for (uint16_t i = offset; i + 1 < raw_bit_count && decoded_bits < 53; i += 2) { - bool bit1 = kia_v2_get_raw_bit(i); - bool bit2 = kia_v2_get_raw_bit(i + 1); - - uint8_t two_bits = (bit1 << 1) | bit2; - - if (two_bits == 0x02) { - data = (data << 1) | 1; - decoded_bits++; - } else if (two_bits == 0x01) { - data = (data << 1); - decoded_bits++; - } else { - break; - } - } - - if (decoded_bits > best_bits) { - best_bits = decoded_bits; - best_data = data; - } - } - - decode_data = best_data; - decode_count_bit = best_bits; - - return best_bits >= min_count_bit_for_found; + min_count_bit_for_found = 53; } void feed(bool level, uint32_t duration) { @@ -82,86 +24,85 @@ class FProtoSubCarKiaV2 : public FProtoSubCarBase { if ((level) && (DURATION_DIFF(duration, te_long) < te_delta)) { parser_step = KiaV2DecoderStepCheckPreamble; te_last = duration; - header_count = 1; + header_count = 0; + FProtoGeneral::manchester_advance(manchester_state, ManchesterEventReset, &manchester_state, NULL); } break; - case KiaV2DecoderStepCheckPreamble: - if (level) { - if (DURATION_DIFF(duration, te_long) < - te_delta) { + if (level) // HIGH pulse + { + if (DURATION_DIFF(duration, te_long) < te_delta) { te_last = duration; header_count++; } else if ( - DURATION_DIFF(duration, te_short) < - te_delta) { - te_last = duration; - } else { - parser_step = KiaV2DecoderStepReset; - } - } else { - if (DURATION_DIFF(duration, te_long) < - te_delta) { - header_count++; - } else if ( - DURATION_DIFF(duration, te_short) < - te_delta) { - if (header_count > 10 && - DURATION_DIFF(te_last, te_short) < - te_delta) { + DURATION_DIFF(duration, te_short) < te_delta) { + if (header_count >= 100) { + header_count = 0; + decode_data = 0; + decode_count_bit = 1; parser_step = KiaV2DecoderStepCollectRawBits; - raw_bit_count = 0; - memset(raw_bits, 0, sizeof(raw_bits)); + subghz_protocol_blocks_add_bit(1); + } else { + te_last = duration; } } else { parser_step = KiaV2DecoderStepReset; } + } else { + if (DURATION_DIFF(duration, te_long) < te_delta) { + header_count++; + te_last = duration; + } else if ( + DURATION_DIFF(duration, te_short) < te_delta) { + te_last = duration; + } else { + parser_step = KiaV2DecoderStepReset; + } } break; - case KiaV2DecoderStepCollectRawBits: - if (duration > 1500) { - if (kia_v2_manchester_decode()) { - /*data = decode_data; - data_count_bit = decode_count_bit; + case KiaV2DecoderStepCollectRawBits: { + ManchesterEvent event; - serial = (uint32_t)((data >> 20) & 0xFFFFFFFF); - btn = (uint8_t)((data >> 16) & 0x0F); - - uint16_t raw_count = (uint16_t)((data >> 4) & 0xFFF); - cnt = ((raw_count >> 4) | (raw_count << 8)) & 0xFFF; - */ - data_count_bit = decode_count_bit; - if (callback) - callback(this); - } - - parser_step = KiaV2DecoderStepReset; - break; - } - - int num_bits = 0; - if (DURATION_DIFF(duration, te_short) < - te_delta) { - num_bits = 1; + if (DURATION_DIFF(duration, te_short) < te_delta) { + event = level ? ManchesterEventShortLow : ManchesterEventShortHigh; } else if ( - DURATION_DIFF(duration, te_long) < - te_delta) { - num_bits = 2; + DURATION_DIFF(duration, te_long) < te_delta) { + event = level ? ManchesterEventLongLow : ManchesterEventLongHigh; } else { parser_step = KiaV2DecoderStepReset; break; } - for (int i = 0; i < num_bits; i++) { - kia_v2_add_raw_bit(level); - } + bool data_bit; + if (FProtoGeneral::manchester_advance(manchester_state, event, &manchester_state, &data_bit)) { + decode_data = (decode_data << 1) | data_bit; + decode_count_bit++; + if (decode_count_bit == 53) { + // instance->generic.data = decode_data; + data_count_bit = decode_count_bit; + + // 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 (callback) + callback(this); + + decode_data = 0; + decode_count_bit = 0; + header_count = 0; + parser_step = KiaV2DecoderStepReset; + } + } break; + } } } - uint8_t raw_bits[20]{0}; - uint16_t raw_bit_count = 0; uint16_t header_count = 0; + ManchesterState manchester_state = ManchesterStateMid1; }; diff --git a/firmware/baseband/fprotos/c-kia_v3v4.hpp b/firmware/baseband/fprotos/c-kia_v3v4.hpp index bede831c1..68b2ba918 100644 --- a/firmware/baseband/fprotos/c-kia_v3v4.hpp +++ b/firmware/baseband/fprotos/c-kia_v3v4.hpp @@ -15,7 +15,7 @@ class FProtoSubCarKiaV3V4 : public FProtoSubCarBase { te_short = 400; te_long = 800; te_delta = 150; - min_count_bit_for_found = 64; + min_count_bit_for_found = 68; } uint8_t reverse8(uint8_t byte) { byte = (byte & 0xF0) >> 4 | (byte & 0x0F) << 4; @@ -36,7 +36,7 @@ class FProtoSubCarKiaV3V4 : public FProtoSubCarBase { } } bool kia_v3_v4_process_buffer() { - if (raw_bit_count < 64) { + if (raw_bit_count < 68) { return false; } @@ -56,7 +56,7 @@ class FProtoSubCarKiaV3V4 : public FProtoSubCarBase { uint8_t btn = (reverse8(b[7]) & 0xF0) >> 4; decode_data = serial; - decode_count_bit = 64; + decode_count_bit = 68; decode_data2 = btn; data_count_bit = decode_count_bit; if (callback) @@ -93,8 +93,7 @@ class FProtoSubCarKiaV3V4 : public FProtoSubCarBase { void feed(bool level, uint32_t duration) { switch (parser_step) { case KiaV3V4DecoderStepReset: - if (level && DURATION_DIFF(duration, te_short) < - te_delta) { + if (level && DURATION_DIFF(duration, te_short) < te_delta) { parser_step = KiaV3V4DecoderStepCheckPreamble; te_last = duration; header_count = 1; @@ -103,8 +102,7 @@ class FProtoSubCarKiaV3V4 : public FProtoSubCarBase { case KiaV3V4DecoderStepCheckPreamble: if (level) { - if (DURATION_DIFF(duration, te_short) < - te_delta) { + if (DURATION_DIFF(duration, te_short) < te_delta) { te_last = duration; } else if (duration > 1000 && duration < 1500) { // V4 style: Sync is LONG HIGH @@ -130,11 +128,7 @@ class FProtoSubCarKiaV3V4 : public FProtoSubCarBase { } else { parser_step = KiaV3V4DecoderStepReset; } - } else if ( - DURATION_DIFF(duration, te_short) < - te_delta && - DURATION_DIFF(te_last, te_short) < - te_delta) { + } else if (DURATION_DIFF(duration, te_short) < te_delta && DURATION_DIFF(te_last, te_short) < te_delta) { header_count++; } else if (duration > 1500) { parser_step = KiaV3V4DecoderStepReset; @@ -149,12 +143,10 @@ class FProtoSubCarKiaV3V4 : public FProtoSubCarBase { kia_v3_v4_process_buffer(); parser_step = KiaV3V4DecoderStepReset; } else if ( - DURATION_DIFF(duration, te_short) < - te_delta) { + DURATION_DIFF(duration, te_short) < te_delta) { kia_v3_v4_add_raw_bit(false); } else if ( - DURATION_DIFF(duration, te_long) < - te_delta) { + DURATION_DIFF(duration, te_long) < te_delta) { kia_v3_v4_add_raw_bit(true); } else { parser_step = KiaV3V4DecoderStepReset; diff --git a/firmware/baseband/fprotos/c-kia_v5.hpp b/firmware/baseband/fprotos/c-kia_v5.hpp index d62d70dc6..c3d3234c3 100644 --- a/firmware/baseband/fprotos/c-kia_v5.hpp +++ b/firmware/baseband/fprotos/c-kia_v5.hpp @@ -1,10 +1,11 @@ #pragma once #include "subcarbase.hpp" #include + typedef enum { KiaV5DecoderStepReset = 0, KiaV5DecoderStepCheckPreamble, - KiaV5DecoderStepCollectRawBits, + KiaV5DecoderStepData, } KiaV5DecoderStep; class FProtoSubCarKiaV5 : public FProtoSubCarBase { @@ -17,74 +18,37 @@ class FProtoSubCarKiaV5 : public FProtoSubCarBase { min_count_bit_for_found = 64; } - inline bool kia_v5_get_raw_bit(uint16_t idx) { - uint16_t byte_idx = idx / 8; - uint8_t bit_idx = 7 - (idx % 8); - return (raw_bits[byte_idx] >> bit_idx) & 1; - } - - void kia_v5_add_raw_bit(bool bit) { - if (raw_bit_count < 256) { - uint16_t byte_idx = raw_bit_count / 8; - uint8_t bit_idx = 7 - (raw_bit_count % 8); - if (bit) { - raw_bits[byte_idx] |= (1 << bit_idx); - } else { - raw_bits[byte_idx] &= ~(1 << bit_idx); - } - raw_bit_count++; - } - } - - bool kia_v5_manchester_decode() { - if (raw_bit_count < 130) { - return false; - } - - decode_data = 0; - decode_count_bit = 0; - - // Start at offset 2 for proper Manchester alignment - const uint16_t start_bit = 2; - - for (uint16_t i = start_bit; - i + 1 < raw_bit_count && decode_count_bit < 64; - i += 2) { - bool bit1 = kia_v5_get_raw_bit(i); - bool bit2 = kia_v5_get_raw_bit(i + 1); - - uint8_t two_bits = (bit1 << 1) | bit2; - - if (two_bits == 0x01) { // 01 = decoded 1 - decode_data = (decode_data << 1) | 1; - decode_count_bit++; - } else if (two_bits == 0x02) { // 10 = decoded 0 - decode_data = (decode_data << 1); - decode_count_bit++; - } else { - break; - } - } - return decode_count_bit >= min_count_bit_for_found; + void kia_v5_add_bit(bool bit) { + decode_data = (decode_data << 1) | (bit ? 1 : 0); + decode_count_bit++; } void feed(bool level, uint32_t duration) { switch (parser_step) { case KiaV5DecoderStepReset: - if ((level) && (DURATION_DIFF(duration, te_short) < - te_delta)) { + if ((level) && (DURATION_DIFF(duration, te_short) < te_delta)) { parser_step = KiaV5DecoderStepCheckPreamble; te_last = duration; header_count = 1; + decode_count_bit = 0; + decode_data = 0; + FProtoGeneral::manchester_advance(manchester_state, ManchesterEventReset, &manchester_state, NULL); } break; case KiaV5DecoderStepCheckPreamble: if (level) { - if ((DURATION_DIFF(duration, te_short) < - te_delta) || - (DURATION_DIFF(duration, te_long) < - te_delta)) { + if (DURATION_DIFF(duration, te_long) < te_delta) { + if (header_count > 40) { + parser_step = KiaV5DecoderStepData; + decode_count_bit = 0; + decode_data = 0; + decode_data2 = 0; + header_count = 0; + } else { + te_last = duration; + } + } else if (DURATION_DIFF(duration, te_short) < te_delta) { te_last = duration; } else { parser_step = KiaV5DecoderStepReset; @@ -100,13 +64,7 @@ class FProtoSubCarKiaV5 : public FProtoSubCarBase { te_delta) && (DURATION_DIFF(te_last, te_short) < te_delta)) { - if (header_count > 40) { - parser_step = KiaV5DecoderStepCollectRawBits; - raw_bit_count = 0; - memset(raw_bits, 0, sizeof(raw_bits)); - } else { - header_count++; - } + header_count++; } else if ( DURATION_DIFF(te_last, te_long) < te_delta) { @@ -114,33 +72,21 @@ class FProtoSubCarKiaV5 : public FProtoSubCarBase { } else { parser_step = KiaV5DecoderStepReset; } + te_last = duration; } break; - case KiaV5DecoderStepCollectRawBits: - if (duration > 1200) { - if (kia_v5_manchester_decode()) { - // generic.data = decode_data; - // generic.data_count_bit = decode_count_bit; - data_count_bit = decode_count_bit; - // Compute yek (bit-reverse each byte) - uint64_t yek = 0; - for (int i = 0; i < 8; i++) { - uint8_t byte = (decode_data >> (i * 8)) & 0xFF; - uint8_t reversed = 0; - for (int b = 0; b < 8; b++) { - if (byte & (1 << b)) - reversed |= (1 << (7 - b)); - } - yek |= ((uint64_t)reversed << ((7 - i) * 8)); - } - decode_data = yek; - - // Shift serial right by 1 to correct alignment - // generic.serial = (uint32_t)(((yek >> 32) & 0x0FFFFFFF) >> 1); - // generic.btn = (uint8_t)((yek >> 61) & 0x07); // Shift btn too - // generic.cnt = (uint16_t)(yek & 0xFFFF); + case KiaV5DecoderStepData: { + ManchesterEvent event; + if (DURATION_DIFF(duration, te_short) < te_delta) { + event = level ? ManchesterEventShortHigh : ManchesterEventShortLow; + } else if (DURATION_DIFF(duration, te_long) < te_delta) { + event = level ? ManchesterEventLongHigh : ManchesterEventLongLow; + } else { + if (decode_count_bit >= min_count_bit_for_found) { + // instance->generic.data = instance->decode_data2; + data_count_bit = (decode_count_bit > 67) ? 67 : decode_count_bit; if (callback) callback(this); } @@ -149,28 +95,22 @@ class FProtoSubCarKiaV5 : public FProtoSubCarBase { break; } - int num_bits = 0; - if (DURATION_DIFF(duration, te_short) < - te_delta) { - num_bits = 1; - } else if ( - DURATION_DIFF(duration, te_long) < - te_delta) { - num_bits = 2; - } else { - parser_step = KiaV5DecoderStepReset; - break; - } - - for (int i = 0; i < num_bits; i++) { - kia_v5_add_raw_bit(level); + bool data_bit; + if (decode_count_bit <= 66 && FProtoGeneral::manchester_advance(manchester_state, event, &manchester_state, &data_bit)) { + kia_v5_add_bit(data_bit); + + if (decode_count_bit == 64) { + decode_data2 = decode_data; + decode_data = 0; + } } + te_last = duration; break; + } } } - uint8_t raw_bits[32]{}; - uint16_t raw_bit_count = 0; uint16_t header_count = 0; + ManchesterState manchester_state = ManchesterStateMid1; }; diff --git a/firmware/baseband/fprotos/c-subaru.hpp b/firmware/baseband/fprotos/c-subaru.hpp index 6e1b3a5e0..dffc29f26 100644 --- a/firmware/baseband/fprotos/c-subaru.hpp +++ b/firmware/baseband/fprotos/c-subaru.hpp @@ -20,6 +20,7 @@ class FProtoSubCarSubaru : public FProtoSubCarBase { te_delta = 260; min_count_bit_for_found = 64; } + void subghz_protocol_decoder_subaru_reset() { parser_step = SubaruDecoderStepReset; te_last = 0; diff --git a/firmware/baseband/fprotos/c-suzuki.hpp b/firmware/baseband/fprotos/c-suzuki.hpp index 93340df01..08ab1535f 100644 --- a/firmware/baseband/fprotos/c-suzuki.hpp +++ b/firmware/baseband/fprotos/c-suzuki.hpp @@ -6,8 +6,8 @@ typedef enum { SuzukiDecoderStepReset = 0, - SuzukiDecoderStepFoundStartPulse, - SuzukiDecoderStepSaveDuration, + SuzukiDecoderStepCountPreamble = 1, + SuzukiDecoderStepDecodeData = 2, } SuzukiDecoderStep; class FProtoSubCarSuzuki : public FProtoSubCarBase { @@ -20,54 +20,45 @@ class FProtoSubCarSuzuki : public FProtoSubCarBase { min_count_bit_for_found = 64; } void suzuki_add_bit(uint32_t bit) { - uint32_t carry = data_low >> 31; - data_low = (data_low << 1) | bit; - data_high = (data_high << 1) | carry; - data_count_bit++; + decode_data = (decode_data << 1) | bit; + decode_count_bit++; } void subghz_protocol_decoder_suzuki_reset() { parser_step = SuzukiDecoderStepReset; header_count = 0; data_count_bit = 0; - data_low = 0; - data_high = 0; + decode_data = 0; } void feed(bool level, uint32_t duration) { switch (parser_step) { case SuzukiDecoderStepReset: - // Wait for short HIGH pulse (~250µs) to start preamble - if (!level) + // Wait for HIGH pulse (~250µs) to start preamble + if (!level) { return; - + } if (DURATION_DIFF(duration, te_short) > te_delta) { return; } - data_low = 0; - data_high = 0; - parser_step = SuzukiDecoderStepFoundStartPulse; + decode_data = 0; + decode_count_bit = 0; + parser_step = SuzukiDecoderStepCountPreamble; header_count = 0; - data_count_bit = 0; break; - case SuzukiDecoderStepFoundStartPulse: + case SuzukiDecoderStepCountPreamble: if (level) { // HIGH pulse - if (header_count < 257) { - // Still in preamble - just count - return; - } - // After preamble, look for long HIGH to start data - if (DURATION_DIFF(duration, te_long) < te_delta) { - parser_step = SuzukiDecoderStepSaveDuration; - suzuki_add_bit(1); + if (header_count >= 300) { + if (DURATION_DIFF(duration, te_long) <= te_delta) { + parser_step = SuzukiDecoderStepDecodeData; + suzuki_add_bit(1); + } } - // Ignore short HIGHs after preamble until we see a long one } else { - // LOW pulse - count as header if short - if (DURATION_DIFF(duration, te_short) < te_delta) { + if (DURATION_DIFF(duration, te_short) <= te_delta) { te_last = duration; header_count++; } else { @@ -76,45 +67,69 @@ class FProtoSubCarSuzuki : public FProtoSubCarBase { } break; - case SuzukiDecoderStepSaveDuration: + case SuzukiDecoderStepDecodeData: + if (level) { // HIGH pulse - determines bit value - // Long HIGH (~500µs) = 1, Short HIGH (~250µs) = 0 - if (DURATION_DIFF(duration, te_long) < te_delta) { - suzuki_add_bit(1); - } else if (DURATION_DIFF(duration, te_short) < te_delta) { - suzuki_add_bit(0); + if (duration < te_long) { + uint32_t diff_long = 500 - duration; + if (diff_long > 99) { + uint32_t diff_short; + if (duration < 250) { + diff_short = 250 - duration; + } else { + diff_short = duration - 250; + } + + if (diff_short <= 99) { + suzuki_add_bit(0); + } + } else { + suzuki_add_bit(1); + } } else { - parser_step = SuzukiDecoderStepReset; + uint32_t diff_long = duration - 500; + if (diff_long <= 99) { + suzuki_add_bit(1); + } } - // Stay in this state for next bit } else { // LOW pulse - check for gap (end of transmission) - if (DURATION_DIFF(duration, SUZUKI_GAP_TIME) < SUZUKI_GAP_DELTA) { - // Gap found - end of transmission - if (data_count_bit == 64) { + uint32_t diff_gap; + if (duration < SUZUKI_GAP_TIME) { + diff_gap = SUZUKI_GAP_TIME - duration; + } else { + diff_gap = duration - SUZUKI_GAP_TIME; + } + + if (diff_gap <= SUZUKI_GAP_DELTA) { + if (decode_count_bit == 64) { + // instance->generic.data = decode_data; data_count_bit = 64; - decode_data = ((uint64_t)data_high << 32) | (uint64_t)data_low; - // Check manufacturer nibble (should be 0xF) - uint8_t manufacturer = (data_high >> 28) & 0xF; - if (manufacturer == 0xF) { - // Extract fields - decode_data2 = 0; // Not used - if (callback) { - callback(this); - } + + /*uint64_t data = instance->generic.data; + uint32_t data_high = (uint32_t)(data >> 32); + uint32_t data_low = (uint32_t)data; + + instance->generic.serial = ((data_high & 0xFFF) << 16) | (data_low >> 16); + + instance->generic.btn = (data_low >> 12) & 0xF; + instance->generic.cnt = (data_high << 4) >> 16; +*/ + if (callback) { + callback(this); } } + + decode_data = 0; + decode_count_bit = 0; parser_step = SuzukiDecoderStepReset; } - // Short LOW pulses are ignored - stay in this state } break; } } uint16_t header_count = 0; - uint32_t data_high = 0; - uint32_t data_low = 0; uint8_t data_count_bit = 0; };