Updated subcar processors (#2913)

This commit is contained in:
Totoo
2026-01-10 14:47:33 +01:00
committed by GitHub
parent 2884bb9ab7
commit 266d90a600
9 changed files with 304 additions and 460 deletions
+73 -9
View File
@@ -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);
}
+2 -6
View File
@@ -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;
};
+16 -17
View File
@@ -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);
+41 -145
View File
@@ -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;
};
+55 -114
View File
@@ -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;
};
+8 -16
View File
@@ -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;
+43 -103
View File
@@ -1,10 +1,11 @@
#pragma once
#include "subcarbase.hpp"
#include <cstring>
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;
};
+1
View File
@@ -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;
+65 -50
View File
@@ -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;
};