Add BS Magic Number calculation to Ford V0

* The Code uses 6f, all my remotes use different numbers.
* So, I am getting the required Magic Number on decode,
* and saving that to the psf.
* Then on Encode, I grab that number and use that instead of 6f
* This works with the 2 remotes I have, and I dont have to patch
* the Magic Number from Calulator anymore!

*** I noticed my Chinese Fob with Magic of 0 said CRC BAD, but Car Unlocked as it captured!
*** It also works when Emulated, car unlocks.
*** The CRC check will have to be looked at!
This commit is contained in:
Leeroy
2026-01-20 13:21:51 +11:00
parent 1408ee09a8
commit eabbff45d3
2 changed files with 110 additions and 47 deletions
+9 -5
View File
@@ -30,8 +30,8 @@ static void sanitize_filename(const char* input, char* output, size_t output_siz
while(input[i] != '\0' && j < output_size - 1) {
char c = input[i];
// Replace problematic characters AND spaces with underscore
if(c == '/' || c == '\\' || c == ':' || c == '*' || c == '?' || c == '"' ||
c == '<' || c == '>' || c == '|' || c == ' ') {
if(c == '/' || c == '\\' || c == ':' || c == '*' || c == '?' || c == '"' || c == '<' ||
c == '>' || c == '|' || c == ' ') {
output[j] = '_';
} else {
output[j] = c;
@@ -124,8 +124,7 @@ static bool protopirate_storage_write_capture_data(
// Custom preset module
flipper_format_rewind(flipper_format);
if(flipper_format_get_value_count(
flipper_format, "Custom_preset_module", &uint32_array_size) &&
if(flipper_format_get_value_count(flipper_format, "Custom_preset_module", &uint32_array_size) &&
uint32_array_size > 0) {
if(flipper_format_read_string(flipper_format, "Custom_preset_module", string_value))
flipper_format_write_string(save_file, "Custom_preset_module", string_value);
@@ -165,6 +164,11 @@ static bool protopirate_storage_write_capture_data(
if(flipper_format_read_uint32(flipper_format, "Cnt", &uint32_value, 1))
flipper_format_write_uint32(save_file, "Cnt", &uint32_value, 1);
// BS Magic
flipper_format_rewind(flipper_format);
if(flipper_format_read_uint32(flipper_format, "BSMagic", &uint32_value, 1))
flipper_format_write_uint32(save_file, "BSMagic", &uint32_value, 1);
// CRC
flipper_format_rewind(flipper_format);
if(flipper_format_read_uint32(flipper_format, "CRC", &uint32_value, 1))
@@ -521,4 +525,4 @@ void protopirate_storage_free_file_list(void) {
}
g_file_count = 0;
g_file_list_valid = false;
}
}
+101 -42
View File
@@ -23,14 +23,10 @@ static const SubGhzBlockConst subghz_protocol_ford_v0_const = {
// =============================================================================
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,
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,
};
// =============================================================================
@@ -55,6 +51,7 @@ typedef struct SubGhzProtocolDecoderFordV0 {
uint32_t serial;
uint8_t button;
uint32_t count;
uint8_t bs_magic;
} SubGhzProtocolDecoderFordV0;
typedef struct SubGhzProtocolEncoderFordV0 {
@@ -68,6 +65,7 @@ typedef struct SubGhzProtocolEncoderFordV0 {
uint8_t button;
uint32_t count;
uint8_t bs;
uint8_t bs_magic;
} SubGhzProtocolEncoderFordV0;
typedef enum {
@@ -88,7 +86,8 @@ static void decode_ford_v0(
uint16_t key2,
uint32_t* serial,
uint8_t* button,
uint32_t* count);
uint32_t* count,
uint8_t* bs_magic);
static void encode_ford_v0(
uint8_t header_byte,
uint32_t serial,
@@ -135,8 +134,19 @@ const SubGhzProtocol ford_protocol_v0 = {
// BS = (counter_low_byte + 0x6F + (button << 4)) & 0xFF
// =============================================================================
static uint8_t ford_v0_calculate_bs(uint32_t count, uint8_t button) {
return ((count & 0xFF) + 0x6F + (button << 4)) & 0xFF;
static uint8_t ford_v0_calculate_bs(uint32_t count, uint8_t button, uint8_t bs_magic) {
uint16_t result;
//Do the BS calculation
result = ((uint16_t)count & 0xFF) + bs_magic + (button << 4);
//Handle the OVerflow
if(result & 0xFF00) {
result -= 128;
}
//Return the last byte of result
return (uint8_t)(result & 0xFF);
}
// =============================================================================
@@ -206,8 +216,8 @@ static void decode_ford_v0(
uint16_t key2,
uint32_t* serial,
uint8_t* button,
uint32_t* count) {
uint32_t* count,
uint8_t* bs_magic) {
uint8_t buf[13] = {0};
for(int i = 0; i < 8; ++i) {
@@ -218,6 +228,7 @@ static void decode_ford_v0(
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) {
@@ -250,19 +261,20 @@ static void decode_ford_v0(
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 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);
*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);
*bs_magic -= (*button << 4);
*bs_magic -= (uint8_t)(*count & 0xFF);
}
// =============================================================================
@@ -276,7 +288,6 @@ static void encode_ford_v0(
uint32_t count,
uint8_t bs,
uint64_t* key1) {
if(!key1) {
FURI_LOG_E(TAG, "encode_ford_v0: NULL key1 pointer");
return;
@@ -332,10 +343,18 @@ static void encode_ford_v0(
*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));
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));
}
// =============================================================================
@@ -361,6 +380,7 @@ void* subghz_protocol_encoder_ford_v0_alloc(SubGhzEnvironment* environment) {
instance->button = 0;
instance->count = 0;
instance->bs = 0;
instance->bs_magic = 0;
FURI_LOG_I(TAG, "Encoder allocated");
return instance;
@@ -382,7 +402,9 @@ static void subghz_protocol_encoder_ford_v0_get_upload(SubGhzProtocolEncoderFord
uint64_t tx_key1 = ~instance->key1;
uint16_t tx_key2 = ~instance->key2;
FURI_LOG_I(TAG, "Building upload: key1=%08lX%08lX key2=%04X",
FURI_LOG_I(
TAG,
"Building upload: key1=%08lX%08lX key2=%04X",
(unsigned long)(instance->key1 >> 32),
(unsigned long)(instance->key1 & 0xFFFFFFFF),
instance->key2);
@@ -535,7 +557,9 @@ SubGhzProtocolStatus
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",
FURI_LOG_I(
TAG,
"Original key1: %08lX%08lX, header=0x%02X",
(unsigned long)(original_key1 >> 32),
(unsigned long)(original_key1 & 0xFFFFFFFF),
header_byte);
@@ -566,10 +590,23 @@ SubGhzProtocolStatus
instance->generic.cnt = instance->count;
FURI_LOG_I(TAG, "Counter: 0x%05lX", (unsigned long)instance->count);
// Calculate BS from counter and button (not from saved file!)
instance->bs = ford_v0_calculate_bs(instance->count, instance->button);
FURI_LOG_I(TAG, "Calculated BS: 0x%02X (from Cnt=0x%05lX, Btn=0x%02X)",
instance->bs, (unsigned long)instance->count, instance->button);
flipper_format_rewind(flipper_format);
uint32_t bs_magic_temp = 0;
if(!flipper_format_read_uint32(flipper_format, "BSMagic", &bs_magic_temp, 1)) {
FURI_LOG_E(TAG, "Missing BSMagic field");
break;
}
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,
@@ -585,8 +622,12 @@ SubGhzProtocolStatus
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);
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(
@@ -603,8 +644,11 @@ SubGhzProtocolStatus
instance->encoder.is_running = true;
FURI_LOG_I(TAG, "Encoder ready: size=%zu repeat=%u",
instance->encoder.size_upload, instance->encoder.repeat);
FURI_LOG_I(
TAG,
"Encoder ready: size=%zu repeat=%u",
instance->encoder.size_upload,
instance->encoder.repeat);
ret = SubGhzProtocolStatusOk;
} while(false);
@@ -663,10 +707,15 @@ static bool ford_v0_process_data(SubGhzProtocolDecoderFordV0* instance) {
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->key1,
key2,
&instance->serial,
&instance->button,
&instance->count,
&instance->bs_magic);
instance->key2 = key2;
return true;
}
@@ -691,7 +740,7 @@ void subghz_protocol_decoder_ford_v0_free(void* context) {
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;
@@ -704,6 +753,7 @@ void subghz_protocol_decoder_ford_v0_reset(void* context) {
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) {
@@ -839,6 +889,9 @@ SubGhzProtocolStatus subghz_protocol_decoder_ford_v0_serialize(
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;
@@ -873,6 +926,10 @@ SubGhzProtocolStatus
flipper_format_read_uint32(flipper_format, "Cnt", &instance->count, 1);
instance->generic.cnt = instance->count;
uint32_t bs_magic_temp = 0;
flipper_format_read_uint32(flipper_format, "BSMagic", &bs_magic_temp, 1);
instance->bs_magic = bs_magic_temp;
}
return ret;
@@ -901,7 +958,8 @@ void subghz_protocol_decoder_ford_v0_get_string(void* context, FuriString* outpu
"Key1:%08lX%08lX\r\n"
"Key2:%04X\r\n"
"Sn:%08lX Btn:%02X:%s\r\n"
"Cnt:%05lX BS:%02X CRC:%02X\r\n",
"Cnt:%05lX BS:%02X CRC:%02X\r\n"
"BSMagic:%02X\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
crc_ok ? "OK" : "BAD",
@@ -913,5 +971,6 @@ void subghz_protocol_decoder_ford_v0_get_string(void* context, FuriString* outpu
button_name,
(unsigned long)instance->count,
(instance->key2 >> 8) & 0xFF,
instance->key2 & 0xFF);
}
instance->key2 & 0xFF,
instance->bs_magic);
}