Files
ProtoPirate/protocols/ford_v0.c
T
2026-02-03 17:09:09 +03:00

985 lines
32 KiB
C

#include "ford_v0.h"
#include "../protopirate_app_i.h"
#define TAG "FordProtocolV0"
// =============================================================================
// PROTOCOL CONSTANTS
// =============================================================================
// Uncomment to enable bit-level debug logging (WARNING: 80 log calls per signal)
// #define FORD_V0_DEBUG_BITS
static const SubGhzBlockConst subghz_protocol_ford_v0_const = {
.te_short = 250,
.te_long = 500,
.te_delta = 100,
.min_count_bit_for_found = 64,
};
#define FORD_V0_PREAMBLE_PAIRS 4
#define FORD_V0_GAP_US 3500
#define FORD_V0_TOTAL_BURSTS 6
// =============================================================================
// CRC MATRIX
// Ford V0 uses matrix multiplication in GF(2) for CRC calculation
// =============================================================================
static const uint8_t ford_v0_crc_matrix[64] = {
0xDA, 0xB5, 0x55, 0x6A, 0xAA, 0xAA, 0xAA, 0xD5, 0xB6, 0x6C, 0xCC, 0xD9, 0x99, 0x99, 0x99, 0xB3,
0x71, 0xE3, 0xC3, 0xC7, 0x87, 0x87, 0x87, 0x8F, 0x0F, 0xE0, 0x3F, 0xC0, 0x7F, 0x80, 0x7F, 0x80,
0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x23, 0x12, 0x94, 0x84, 0x35, 0xF4, 0x55, 0x84,
};
// =============================================================================
// STRUCT DEFINITIONS
// =============================================================================
typedef struct SubGhzProtocolDecoderFordV0 {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
ManchesterState manchester_state;
uint64_t data_low;
uint64_t data_high;
uint8_t bit_count;
uint16_t header_count;
uint64_t key1;
uint16_t key2;
uint32_t serial;
uint8_t button;
uint32_t count;
uint8_t bs_magic;
} SubGhzProtocolDecoderFordV0;
typedef struct SubGhzProtocolEncoderFordV0 {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
uint64_t key1;
uint16_t key2;
uint32_t serial;
uint8_t button;
uint32_t count;
uint8_t bs;
uint8_t bs_magic;
} SubGhzProtocolEncoderFordV0;
typedef enum {
FordV0DecoderStepReset = 0,
FordV0DecoderStepPreamble,
FordV0DecoderStepPreambleCheck,
FordV0DecoderStepGap,
FordV0DecoderStepData,
} FordV0DecoderStep;
// =============================================================================
// FUNCTION PROTOTYPES
// =============================================================================
static void ford_v0_add_bit(SubGhzProtocolDecoderFordV0* instance, bool bit);
static void decode_ford_v0(
uint64_t key1,
uint16_t key2,
uint32_t* serial,
uint8_t* button,
uint32_t* count,
uint8_t* bs_magic);
static void encode_ford_v0(
uint8_t header_byte,
uint32_t serial,
uint8_t button,
uint32_t count,
uint8_t bs,
uint64_t* key1);
static bool ford_v0_process_data(SubGhzProtocolDecoderFordV0* instance);
// =============================================================================
// PROTOCOL INTERFACE DEFINITIONS
// =============================================================================
const SubGhzProtocolDecoder subghz_protocol_ford_v0_decoder = {
.alloc = subghz_protocol_decoder_ford_v0_alloc,
.free = subghz_protocol_decoder_ford_v0_free,
.feed = subghz_protocol_decoder_ford_v0_feed,
.reset = subghz_protocol_decoder_ford_v0_reset,
.get_hash_data = subghz_protocol_decoder_ford_v0_get_hash_data,
.serialize = subghz_protocol_decoder_ford_v0_serialize,
.deserialize = subghz_protocol_decoder_ford_v0_deserialize,
.get_string = subghz_protocol_decoder_ford_v0_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_ford_v0_encoder = {
.alloc = subghz_protocol_encoder_ford_v0_alloc,
.free = subghz_protocol_encoder_ford_v0_free,
.deserialize = subghz_protocol_encoder_ford_v0_deserialize,
.stop = subghz_protocol_encoder_ford_v0_stop,
.yield = subghz_protocol_encoder_ford_v0_yield,
};
const SubGhzProtocol ford_protocol_v0 = {
.name = FORD_PROTOCOL_V0_NAME,
.type = SubGhzProtocolTypeDynamic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_FM | SubGhzProtocolFlag_Decodable |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
.decoder = &subghz_protocol_ford_v0_decoder,
.encoder = &subghz_protocol_ford_v0_encoder,
};
// =============================================================================
// BS CALCULATION
// BS = (counter_low_byte + 0x6F + (button << 4)) & 0xFF
// =============================================================================
static uint8_t ford_v0_calculate_bs(uint32_t count, uint8_t button, uint8_t bs_magic) {
//Do the BS calculation, move right the overflow bit if neccesary
uint16_t result = ((uint16_t)count & 0xFF) + bs_magic + (button << 4);
return (uint8_t)(result - ((result & 0xFF00) ? 0x80 : 0));
}
// =============================================================================
// CRC FUNCTIONS
// =============================================================================
static uint8_t ford_v0_popcount8(uint8_t x) {
uint8_t count = 0;
while(x) {
count += x & 1;
x >>= 1;
}
return count;
}
static uint8_t ford_v0_calculate_crc(uint8_t* buf) {
uint8_t crc = 0;
for(int row = 0; row < 8; row++) {
uint8_t xor_sum = 0;
for(int col = 0; col < 8; col++) {
xor_sum ^= (ford_v0_crc_matrix[row * 8 + col] & buf[col + 1]);
}
uint8_t parity = ford_v0_popcount8(xor_sum) & 1;
if(parity) {
crc |= (1 << row);
}
}
return crc;
}
static uint8_t ford_v0_calculate_crc_for_tx(uint64_t key1, uint8_t bs) {
uint8_t buf[16] = {0};
for(int i = 0; i < 8; ++i) {
buf[i] = (uint8_t)(key1 >> (56 - i * 8));
}
buf[8] = bs;
uint8_t crc = ford_v0_calculate_crc(buf);
return crc ^ 0x80;
}
static bool ford_v0_verify_crc(uint64_t key1, uint16_t key2) {
uint8_t buf[16] = {0};
for(int i = 0; i < 8; ++i) {
buf[i] = (uint8_t)(key1 >> (56 - i * 8));
}
buf[8] = (uint8_t)(key2 >> 8);
uint8_t calculated_crc = ford_v0_calculate_crc(buf);
uint8_t received_crc = (uint8_t)(key2 & 0xFF) ^ 0x80;
return (calculated_crc == received_crc);
}
// =============================================================================
// DECODE FUNCTION
// =============================================================================
static void decode_ford_v0(
uint64_t key1,
uint16_t key2,
uint32_t* serial,
uint8_t* button,
uint32_t* count,
uint8_t* bs_magic) {
uint8_t buf[13] = {0};
for(int i = 0; i < 8; ++i) {
buf[i] = (uint8_t)(key1 >> (56 - i * 8));
}
buf[8] = (uint8_t)(key2 >> 8);
buf[9] = (uint8_t)(key2 & 0xFF);
uint8_t tmp = buf[8];
uint8_t bs = tmp;
uint8_t parity = 0;
uint8_t parity_any = (tmp != 0);
while(tmp) {
parity ^= (tmp & 1);
tmp >>= 1;
}
buf[11] = parity_any ? parity : 0;
uint8_t xor_byte;
uint8_t limit;
if(buf[11]) {
xor_byte = buf[7];
limit = 7;
} else {
xor_byte = buf[6];
limit = 6;
}
for(int idx = 1; idx < limit; ++idx) {
buf[idx] ^= xor_byte;
}
if(buf[11] == 0) {
buf[7] ^= xor_byte;
}
uint8_t orig_b7 = buf[7];
buf[7] = (orig_b7 & 0xAA) | (buf[6] & 0x55);
uint8_t mixed = (buf[6] & 0xAA) | (orig_b7 & 0x55);
buf[12] = mixed;
buf[6] = mixed;
uint32_t serial_le = ((uint32_t)buf[1]) | ((uint32_t)buf[2] << 8) | ((uint32_t)buf[3] << 16) |
((uint32_t)buf[4] << 24);
*serial = ((serial_le & 0xFF) << 24) | (((serial_le >> 8) & 0xFF) << 16) |
(((serial_le >> 16) & 0xFF) << 8) | ((serial_le >> 24) & 0xFF);
*button = (buf[5] >> 4) & 0x0F;
*count = ((buf[5] & 0x0F) << 16) | (buf[6] << 8) | buf[7];
//Build the BS Magic number for this fob.
*bs_magic = bs + ((bs & 0x80) ? 0x80 : 0) - (*button << 4) - (uint8_t)(*count & 0xFF);
}
// =============================================================================
// ENCODE FUNCTION
// =============================================================================
static void encode_ford_v0(
uint8_t header_byte,
uint32_t serial,
uint8_t button,
uint32_t count,
uint8_t bs,
uint64_t* key1) {
if(!key1) {
FURI_LOG_E(TAG, "encode_ford_v0: NULL key1 pointer");
return;
}
uint8_t buf[8] = {0};
buf[0] = header_byte;
buf[1] = (serial >> 24) & 0xFF;
buf[2] = (serial >> 16) & 0xFF;
buf[3] = (serial >> 8) & 0xFF;
buf[4] = serial & 0xFF;
buf[5] = ((button & 0x0F) << 4) | ((count >> 16) & 0x0F);
uint8_t count_mid = (count >> 8) & 0xFF;
uint8_t count_low = count & 0xFF;
uint8_t post_xor_6 = (count_mid & 0xAA) | (count_low & 0x55);
uint8_t post_xor_7 = (count_low & 0xAA) | (count_mid & 0x55);
uint8_t parity = 0;
uint8_t tmp = bs;
while(tmp) {
parity ^= (tmp & 1);
tmp >>= 1;
}
bool parity_bit = (bs != 0) ? (parity != 0) : false;
if(parity_bit) {
uint8_t xor_byte = post_xor_7;
buf[1] ^= xor_byte;
buf[2] ^= xor_byte;
buf[3] ^= xor_byte;
buf[4] ^= xor_byte;
buf[5] ^= xor_byte;
buf[6] = post_xor_6 ^ xor_byte;
buf[7] = post_xor_7;
} else {
uint8_t xor_byte = post_xor_6;
buf[1] ^= xor_byte;
buf[2] ^= xor_byte;
buf[3] ^= xor_byte;
buf[4] ^= xor_byte;
buf[5] ^= xor_byte;
buf[6] = post_xor_6;
buf[7] = post_xor_7 ^ xor_byte;
}
*key1 = 0;
for(int i = 0; i < 8; i++) {
*key1 = (*key1 << 8) | buf[i];
}
FURI_LOG_I(
TAG,
"Encode: Sn=%08lX Btn=%d Cnt=%05lX BS=%02X",
(unsigned long)serial,
button,
(unsigned long)count,
bs);
FURI_LOG_I(
TAG,
"Encode key1: %08lX%08lX",
(unsigned long)(*key1 >> 32),
(unsigned long)(*key1 & 0xFFFFFFFF));
}
// =============================================================================
// ENCODER IMPLEMENTATION
// =============================================================================
void* subghz_protocol_encoder_ford_v0_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
SubGhzProtocolEncoderFordV0* instance = malloc(sizeof(SubGhzProtocolEncoderFordV0));
instance->base.protocol = &ford_protocol_v0;
instance->generic.protocol_name = instance->base.protocol->name;
instance->encoder.repeat = 10;
instance->encoder.size_upload = 1024;
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
instance->encoder.is_running = false;
instance->encoder.front = 0;
instance->key1 = 0;
instance->key2 = 0;
instance->serial = 0;
instance->button = 0;
instance->count = 0;
instance->bs = 0;
instance->bs_magic = 0;
FURI_LOG_I(TAG, "Encoder allocated");
return instance;
}
void subghz_protocol_encoder_ford_v0_free(void* context) {
furi_assert(context);
SubGhzProtocolEncoderFordV0* instance = context;
if(instance->encoder.upload) {
free(instance->encoder.upload);
}
free(instance);
}
static void subghz_protocol_encoder_ford_v0_get_upload(SubGhzProtocolEncoderFordV0* instance) {
furi_assert(instance);
size_t index = 0;
uint64_t tx_key1 = ~instance->key1;
uint16_t tx_key2 = ~instance->key2;
FURI_LOG_I(
TAG,
"Building upload: key1=%08lX%08lX key2=%04X",
(unsigned long)(instance->key1 >> 32),
(unsigned long)(instance->key1 & 0xFFFFFFFF),
instance->key2);
uint32_t te_short = subghz_protocol_ford_v0_const.te_short;
uint32_t te_long = subghz_protocol_ford_v0_const.te_long;
#define ADD_LEVEL(lvl, dur) \
do { \
if(index > 0 && level_duration_get_level(instance->encoder.upload[index - 1]) == (lvl)) { \
uint32_t prev = level_duration_get_duration(instance->encoder.upload[index - 1]); \
instance->encoder.upload[index - 1] = level_duration_make((lvl), prev + (dur)); \
} else { \
instance->encoder.upload[index++] = level_duration_make((lvl), (dur)); \
} \
} while(0)
for(uint8_t burst = 0; burst < FORD_V0_TOTAL_BURSTS; burst++) {
ADD_LEVEL(true, te_short);
ADD_LEVEL(false, te_long);
for(int i = 0; i < FORD_V0_PREAMBLE_PAIRS; i++) {
ADD_LEVEL(true, te_long);
ADD_LEVEL(false, te_long);
}
ADD_LEVEL(true, te_short);
ADD_LEVEL(false, FORD_V0_GAP_US);
bool first_bit = (tx_key1 >> 62) & 1;
if(first_bit) {
ADD_LEVEL(true, te_long);
} else {
ADD_LEVEL(true, te_short);
ADD_LEVEL(false, te_long);
}
bool prev_bit = first_bit;
for(int bit = 61; bit >= 0; bit--) {
bool curr_bit = (tx_key1 >> bit) & 1;
if(!prev_bit && !curr_bit) {
ADD_LEVEL(true, te_short);
ADD_LEVEL(false, te_short);
} else if(!prev_bit && curr_bit) {
ADD_LEVEL(true, te_long);
} else if(prev_bit && !curr_bit) {
ADD_LEVEL(false, te_long);
} else {
ADD_LEVEL(false, te_short);
ADD_LEVEL(true, te_short);
}
prev_bit = curr_bit;
}
for(int bit = 15; bit >= 0; bit--) {
bool curr_bit = (tx_key2 >> bit) & 1;
if(!prev_bit && !curr_bit) {
ADD_LEVEL(true, te_short);
ADD_LEVEL(false, te_short);
} else if(!prev_bit && curr_bit) {
ADD_LEVEL(true, te_long);
} else if(prev_bit && !curr_bit) {
ADD_LEVEL(false, te_long);
} else {
ADD_LEVEL(false, te_short);
ADD_LEVEL(true, te_short);
}
prev_bit = curr_bit;
}
if(burst < FORD_V0_TOTAL_BURSTS - 1) {
ADD_LEVEL(false, te_long * 100);
}
}
#undef ADD_LEVEL
instance->encoder.size_upload = index;
instance->encoder.front = 0;
FURI_LOG_I(TAG, "Upload built: %d bursts, size=%zu", FORD_V0_TOTAL_BURSTS, index);
}
SubGhzProtocolStatus
subghz_protocol_encoder_ford_v0_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolEncoderFordV0* instance = context;
SubGhzProtocolStatus ret = SubGhzProtocolStatusError;
FURI_LOG_I(TAG, "Encoder deserialize started");
instance->encoder.is_running = false;
instance->encoder.front = 0;
instance->encoder.repeat = 10;
do {
FuriString* temp_str = furi_string_alloc();
if(!temp_str) {
FURI_LOG_E(TAG, "Failed to allocate temp string");
break;
}
flipper_format_rewind(flipper_format);
if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) {
FURI_LOG_E(TAG, "Missing Protocol field");
furi_string_free(temp_str);
break;
}
if(!furi_string_equal(temp_str, instance->base.protocol->name)) {
FURI_LOG_E(TAG, "Protocol mismatch: %s", furi_string_get_cstr(temp_str));
furi_string_free(temp_str);
break;
}
flipper_format_rewind(flipper_format);
if(!flipper_format_read_string(flipper_format, "Key", temp_str)) {
FURI_LOG_E(TAG, "Missing Key field");
furi_string_free(temp_str);
break;
}
const char* key_str = furi_string_get_cstr(temp_str);
uint64_t original_key1 = 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
break;
original_key1 = (original_key1 << 4) | nibble;
hex_pos++;
}
furi_string_free(temp_str);
uint8_t header_byte = (uint8_t)(original_key1 >> 56);
FURI_LOG_I(
TAG,
"Original key1: %08lX%08lX, header=0x%02X",
(unsigned long)(original_key1 >> 32),
(unsigned long)(original_key1 & 0xFFFFFFFF),
header_byte);
flipper_format_rewind(flipper_format);
if(!flipper_format_read_uint32(flipper_format, "Serial", &instance->serial, 1)) {
FURI_LOG_E(TAG, "Missing Serial field");
break;
}
instance->generic.serial = instance->serial;
FURI_LOG_I(TAG, "Serial: 0x%08lX", (unsigned long)instance->serial);
flipper_format_rewind(flipper_format);
uint32_t btn_temp = 0;
if(!flipper_format_read_uint32(flipper_format, "Btn", &btn_temp, 1)) {
FURI_LOG_E(TAG, "Missing Btn field");
break;
}
instance->button = (uint8_t)btn_temp;
instance->generic.btn = instance->button;
FURI_LOG_I(TAG, "Button: 0x%02X", instance->button);
flipper_format_rewind(flipper_format);
if(!flipper_format_read_uint32(flipper_format, "Cnt", &instance->count, 1)) {
FURI_LOG_E(TAG, "Missing Cnt field");
break;
}
instance->generic.cnt = instance->count;
FURI_LOG_I(TAG, "Counter: 0x%05lX", (unsigned long)instance->count);
flipper_format_rewind(flipper_format);
uint32_t bs_magic_temp = 0;
if(!flipper_format_read_uint32(flipper_format, "BSMagic", &bs_magic_temp, 1))
instance->bs_magic = 0x6F; //For Backward compatibility
else
instance->bs_magic = (uint8_t)bs_magic_temp;
// Calculate BS from counter and button, as well as the BS Magic Number we pulled on decode.
instance->bs = ford_v0_calculate_bs(instance->count, instance->button, instance->bs_magic);
FURI_LOG_I(
TAG,
"Calculated BS: 0x%02X (from Cnt=0x%05lX, Btn=0x%02X, BSMagic=0x%02X))",
instance->bs,
(unsigned long)instance->count,
instance->button,
instance->bs_magic);
encode_ford_v0(
header_byte,
instance->serial,
instance->button,
instance->count,
instance->bs,
&instance->key1);
instance->generic.data = instance->key1;
instance->generic.data_count_bit = 64;
uint8_t calculated_crc = ford_v0_calculate_crc_for_tx(instance->key1, instance->bs);
instance->key2 = ((uint16_t)instance->bs << 8) | calculated_crc;
FURI_LOG_I(
TAG,
"Final key2: 0x%04X (BS=0x%02X, CRC=0x%02X)",
instance->key2,
instance->bs,
calculated_crc);
flipper_format_rewind(flipper_format);
if(!flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1)) {
instance->encoder.repeat = 10;
}
subghz_protocol_encoder_ford_v0_get_upload(instance);
if(instance->encoder.size_upload == 0) {
FURI_LOG_E(TAG, "Upload build failed");
break;
}
//Update the PSF file, since we have overwritten the COUNTER and BUTTON
//This makes the file's nummers wrong, and fails tests. It wasnt causing a TX bug, but manual tests failed.
flipper_format_rewind(flipper_format);
uint32_t temp = calculated_crc;
flipper_format_insert_or_update_uint32(flipper_format, "CRC", &temp, 1);
temp = instance->bs;
flipper_format_insert_or_update_uint32(flipper_format, "BS", &temp, 1);
instance->encoder.is_running = true;
FURI_LOG_I(
TAG,
"Encoder ready: size=%zu repeat=%u",
instance->encoder.size_upload,
instance->encoder.repeat);
ret = SubGhzProtocolStatusOk;
} while(false);
FURI_LOG_I(TAG, "Encoder deserialize finished, status=%d", ret);
return ret;
}
void subghz_protocol_encoder_ford_v0_stop(void* context) {
furi_assert(context);
SubGhzProtocolEncoderFordV0* instance = context;
instance->encoder.is_running = false;
}
LevelDuration subghz_protocol_encoder_ford_v0_yield(void* context) {
furi_assert(context);
SubGhzProtocolEncoderFordV0* instance = context;
if(!instance->encoder.is_running || instance->encoder.repeat == 0) {
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;
}
// =============================================================================
// DECODER IMPLEMENTATION
// =============================================================================
static void ford_v0_add_bit(SubGhzProtocolDecoderFordV0* instance, bool bit) {
#ifdef FORD_V0_DEBUG_BITS
FURI_LOG_D(TAG, "Bit %d: %d", instance->bit_count, bit);
#endif
uint32_t low = (uint32_t)instance->data_low;
instance->data_low = (instance->data_low << 1) | (bit ? 1 : 0);
instance->data_high = (instance->data_high << 1) | ((low >> 31) & 1);
instance->bit_count++;
}
static bool ford_v0_process_data(SubGhzProtocolDecoderFordV0* instance) {
if(instance->bit_count == 64) {
uint64_t combined = ((uint64_t)instance->data_high << 32) | instance->data_low;
instance->key1 = ~combined;
instance->data_low = 0;
instance->data_high = 0;
return false;
}
if(instance->bit_count == 80) {
uint16_t key2_raw = (uint16_t)(instance->data_low & 0xFFFF);
uint16_t key2 = ~key2_raw;
decode_ford_v0(
instance->key1,
key2,
&instance->serial,
&instance->button,
&instance->count,
&instance->bs_magic);
instance->key2 = key2;
return true;
}
return false;
}
void* subghz_protocol_decoder_ford_v0_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
SubGhzProtocolDecoderFordV0* instance = malloc(sizeof(SubGhzProtocolDecoderFordV0));
instance->base.protocol = &ford_protocol_v0;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void subghz_protocol_decoder_ford_v0_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderFordV0* instance = context;
free(instance);
}
void subghz_protocol_decoder_ford_v0_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderFordV0* instance = context;
instance->decoder.parser_step = FordV0DecoderStepReset;
instance->decoder.te_last = 0;
instance->manchester_state = ManchesterStateMid1;
instance->data_low = 0;
instance->data_high = 0;
instance->bit_count = 0;
instance->header_count = 0;
instance->key1 = 0;
instance->key2 = 0;
instance->serial = 0;
instance->button = 0;
instance->count = 0;
instance->bs_magic = 0;
}
void subghz_protocol_decoder_ford_v0_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderFordV0* instance = context;
uint32_t te_short = subghz_protocol_ford_v0_const.te_short;
uint32_t te_long = subghz_protocol_ford_v0_const.te_long;
uint32_t te_delta = subghz_protocol_ford_v0_const.te_delta;
uint32_t gap_threshold = 3500;
switch(instance->decoder.parser_step) {
case FordV0DecoderStepReset:
if(level && (DURATION_DIFF(duration, te_short) < te_delta)) {
instance->data_low = 0;
instance->data_high = 0;
instance->decoder.parser_step = FordV0DecoderStepPreamble;
instance->decoder.te_last = duration;
instance->header_count = 0;
instance->bit_count = 0;
manchester_advance(
instance->manchester_state,
ManchesterEventReset,
&instance->manchester_state,
NULL);
}
break;
case FordV0DecoderStepPreamble:
if(!level) {
if(DURATION_DIFF(duration, te_long) < te_delta) {
instance->decoder.te_last = duration;
instance->decoder.parser_step = FordV0DecoderStepPreambleCheck;
} else {
instance->decoder.parser_step = FordV0DecoderStepReset;
}
}
break;
case FordV0DecoderStepPreambleCheck:
if(level) {
if(DURATION_DIFF(duration, te_long) < te_delta) {
instance->header_count++;
instance->decoder.te_last = duration;
instance->decoder.parser_step = FordV0DecoderStepPreamble;
} else if(DURATION_DIFF(duration, te_short) < te_delta) {
instance->decoder.parser_step = FordV0DecoderStepGap;
} else {
instance->decoder.parser_step = FordV0DecoderStepReset;
}
}
break;
case FordV0DecoderStepGap:
if(!level && (DURATION_DIFF(duration, gap_threshold) < 250)) {
instance->data_low = 1;
instance->data_high = 0;
instance->bit_count = 1;
instance->decoder.parser_step = FordV0DecoderStepData;
} else if(!level && duration > gap_threshold + 250) {
instance->decoder.parser_step = FordV0DecoderStepReset;
}
break;
case FordV0DecoderStepData: {
ManchesterEvent event;
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;
} else {
instance->decoder.parser_step = FordV0DecoderStepReset;
break;
}
bool data_bit;
if(manchester_advance(
instance->manchester_state, event, &instance->manchester_state, &data_bit)) {
ford_v0_add_bit(instance, data_bit);
if(ford_v0_process_data(instance)) {
instance->generic.data = instance->key1;
instance->generic.data_count_bit = 64;
instance->generic.serial = instance->serial;
instance->generic.btn = instance->button;
instance->generic.cnt = instance->count;
if(instance->base.callback) {
instance->base.callback(&instance->base, instance->base.context);
}
instance->data_low = 0;
instance->data_high = 0;
instance->bit_count = 0;
instance->decoder.parser_step = FordV0DecoderStepReset;
}
}
instance->decoder.te_last = duration;
break;
}
}
}
uint8_t subghz_protocol_decoder_ford_v0_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderFordV0* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
SubGhzProtocolStatus subghz_protocol_decoder_ford_v0_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) {
furi_assert(context);
SubGhzProtocolDecoderFordV0* instance = context;
SubGhzProtocolStatus ret =
subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
if(ret == SubGhzProtocolStatusOk) {
uint32_t temp = (instance->key2 >> 8) & 0xFF;
flipper_format_write_uint32(flipper_format, "BS", &temp, 1);
temp = instance->key2 & 0xFF;
flipper_format_write_uint32(flipper_format, "CRC", &temp, 1);
flipper_format_write_uint32(flipper_format, "Serial", &instance->serial, 1);
temp = instance->button;
flipper_format_write_uint32(flipper_format, "Btn", &temp, 1);
flipper_format_write_uint32(flipper_format, "Cnt", &instance->count, 1);
temp = (uint32_t)instance->bs_magic;
flipper_format_write_uint32(flipper_format, "BSMagic", &temp, 1);
}
return ret;
}
SubGhzProtocolStatus
subghz_protocol_decoder_ford_v0_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderFordV0* instance = context;
SubGhzProtocolStatus ret = subghz_block_generic_deserialize_check_count_bit(
&instance->generic, flipper_format, subghz_protocol_ford_v0_const.min_count_bit_for_found);
if(ret == SubGhzProtocolStatusOk) {
instance->key1 = instance->generic.data;
flipper_format_rewind(flipper_format);
uint32_t bs_temp = 0;
uint32_t crc_temp = 0;
flipper_format_read_uint32(flipper_format, "BS", &bs_temp, 1);
flipper_format_read_uint32(flipper_format, "CRC", &crc_temp, 1);
instance->key2 = ((bs_temp & 0xFF) << 8) | (crc_temp & 0xFF);
flipper_format_read_uint32(flipper_format, "Serial", &instance->serial, 1);
instance->generic.serial = instance->serial;
uint32_t btn_temp = 0;
flipper_format_read_uint32(flipper_format, "Btn", &btn_temp, 1);
instance->button = (uint8_t)btn_temp;
instance->generic.btn = instance->button;
flipper_format_read_uint32(flipper_format, "Cnt", &instance->count, 1);
instance->generic.cnt = instance->count;
uint32_t bs_magic_temp = 0;
if(flipper_format_read_uint32(flipper_format, "BSMagic", &bs_magic_temp, 1))
instance->bs_magic = bs_magic_temp;
else
instance->bs_magic = 0x6F; //For backward psf file compatibiility.
}
return ret;
}
void subghz_protocol_decoder_ford_v0_get_string(void* context, FuriString* output) {
furi_assert(context);
SubGhzProtocolDecoderFordV0* instance = context;
uint32_t code_found_hi = (uint32_t)(instance->key1 >> 32);
uint32_t code_found_lo = (uint32_t)(instance->key1 & 0xFFFFFFFF);
bool crc_ok = ford_v0_verify_crc(instance->key1, instance->key2);
const char* button_name = "??";
if(instance->button == 0x01)
button_name = "Lock";
else if(instance->button == 0x02)
button_name = "Unlock";
else if(instance->button == 0x04)
button_name = "Boot";
furi_string_cat_printf(
output,
"%s %dbit CRC:%s\r\n"
"Key1: %08lX%08lX\r\n"
"Key2: %04X"
" Sn: %08lX\r\n"
"Cnt: %05lX"
" BS: %02X"
" CRC: %02X\r\n"
"BS Magic: %02X"
" Btn: %02X - %s\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
crc_ok ? "OK" : "BAD",
(unsigned long)code_found_hi,
(unsigned long)code_found_lo,
instance->key2,
(unsigned long)instance->serial,
(unsigned long)instance->count,
(instance->key2 >> 8) & 0xFF,
instance->key2 & 0xFF,
instance->bs_magic,
instance->button,
button_name);
}