@@ -15,18 +15,18 @@ static const SubGhzBlockConst subghz_protocol_ford_v0_const = {
1515
1616// Ford V0 CRC Matrix (8x8 bytes) - extracted from firmware
1717static const uint8_t ford_v0_crc_matrix [64 ] = {
18- 0xDA , 0xB5 , 0x55 , 0x6A , 0xAA , 0xAA , 0xAA , 0xD5 , // Row 0
19- 0xB6 , 0x6C , 0xCC , 0xD9 , 0x99 , 0x99 , 0x99 , 0xB3 , // Row 1
20- 0x71 , 0xE3 , 0xC3 , 0xC7 , 0x87 , 0x87 , 0x87 , 0x8F , // Row 2
21- 0x0F , 0xE0 , 0x3F , 0xC0 , 0x7F , 0x80 , 0x7F , 0x80 , // Row 3
22- 0x00 , 0x1F , 0xFF , 0xC0 , 0x00 , 0x7F , 0xFF , 0x80 , // Row 4
23- 0x00 , 0x00 , 0x00 , 0x3F , 0xFF , 0xFF , 0xFF , 0x80 , // Row 5
24- 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x7F , // Row 6
25- 0x23 , 0x12 , 0x94 , 0x84 , 0x35 , 0xF4 , 0x55 , 0x84 , // Row 7
18+ 0xDA , 0xB5 , 0x55 , 0x6A , 0xAA , 0xAA , 0xAA , 0xD5 , // Row 0
19+ 0xB6 , 0x6C , 0xCC , 0xD9 , 0x99 , 0x99 , 0x99 , 0xB3 , // Row 1
20+ 0x71 , 0xE3 , 0xC3 , 0xC7 , 0x87 , 0x87 , 0x87 , 0x8F , // Row 2
21+ 0x0F , 0xE0 , 0x3F , 0xC0 , 0x7F , 0x80 , 0x7F , 0x80 , // Row 3
22+ 0x00 , 0x1F , 0xFF , 0xC0 , 0x00 , 0x7F , 0xFF , 0x80 , // Row 4
23+ 0x00 , 0x00 , 0x00 , 0x3F , 0xFF , 0xFF , 0xFF , 0x80 , // Row 5
24+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x7F , // Row 6
25+ 0x23 , 0x12 , 0x94 , 0x84 , 0x35 , 0xF4 , 0x55 , 0x84 , // Row 7
2626};
2727
2828// ============================================================================
29- // CRC FUNCTIONS (for decoder verification)
29+ // CRC FUNCTIONS
3030// ============================================================================
3131
3232static uint8_t ford_v0_popcount8 (uint8_t x ) {
@@ -42,18 +42,6 @@ static uint8_t ford_v0_popcount8(uint8_t x) {
4242static uint8_t ford_v0_calculate_crc (uint8_t * buf ) {
4343 uint8_t crc = 0 ;
4444
45- FURI_LOG_D (
46- TAG ,
47- "CRC calc input: buf[1-8] = %02X %02X %02X %02X %02X %02X %02X %02X" ,
48- buf [1 ],
49- buf [2 ],
50- buf [3 ],
51- buf [4 ],
52- buf [5 ],
53- buf [6 ],
54- buf [7 ],
55- buf [8 ]);
56-
5745 for (int row = 0 ; row < 8 ; row ++ ) {
5846 uint8_t xor_sum = 0 ;
5947 for (int col = 0 ; col < 8 ; col ++ ) {
@@ -63,23 +51,29 @@ static uint8_t ford_v0_calculate_crc(uint8_t* buf) {
6351 if (parity ) {
6452 crc |= (1 << row );
6553 }
66- FURI_LOG_D (
67- TAG ,
68- "CRC row %d: xor_sum=0x%02X popcount=%d parity=%d crc_so_far=0x%02X" ,
69- row ,
70- xor_sum ,
71- ford_v0_popcount8 (xor_sum ),
72- parity ,
73- crc );
7454 }
7555
76- // XOR with 0x80 - Ford appears to invert bit 7
77- crc ^= 0x80 ;
78-
79- FURI_LOG_D (TAG , "CRC calculated: 0x%02X" , crc );
8056 return crc ;
8157}
8258
59+ // Calculate CRC for encoding: returns the value to transmit
60+ static uint8_t ford_v0_calculate_crc_for_tx (uint64_t key1 , uint8_t bs ) {
61+ uint8_t buf [16 ] = {0 };
62+
63+ // Extract bytes from key1 into buf[0..7]
64+ for (int i = 0 ; i < 8 ; ++ i ) {
65+ buf [i ] = (uint8_t )(key1 >> (56 - i * 8 ));
66+ }
67+
68+ // BS goes into buf[8]
69+ buf [8 ] = bs ;
70+
71+ // Calculate CRC and XOR with 0x80 for transmission
72+ uint8_t crc = ford_v0_calculate_crc (buf );
73+ return crc ^ 0x80 ;
74+ }
75+
76+ // Verify received CRC
8377static bool ford_v0_verify_crc (uint64_t key1 , uint16_t key2 ) {
8478 uint8_t buf [16 ] = {0 };
8579
@@ -91,34 +85,9 @@ static bool ford_v0_verify_crc(uint64_t key1, uint16_t key2) {
9185 // BS is high byte of key2, goes into buf[8]
9286 buf [8 ] = (uint8_t )(key2 >> 8 );
9387
94- FURI_LOG_I (
95- TAG ,
96- "CRC verify: key1=0x%08lX%08lX key2=0x%04X" ,
97- (uint32_t )(key1 >> 32 ),
98- (uint32_t )(key1 & 0xFFFFFFFF ),
99- key2 );
100- FURI_LOG_I (
101- TAG ,
102- "CRC verify: buf[0-8] = %02X %02X %02X %02X %02X %02X %02X %02X %02X" ,
103- buf [0 ],
104- buf [1 ],
105- buf [2 ],
106- buf [3 ],
107- buf [4 ],
108- buf [5 ],
109- buf [6 ],
110- buf [7 ],
111- buf [8 ]);
112-
11388 uint8_t calculated_crc = ford_v0_calculate_crc (buf );
114- uint8_t received_crc = (uint8_t )(key2 & 0xFF );
115-
116- FURI_LOG_I (
117- TAG ,
118- "CRC compare: calculated=0x%02X received=0x%02X match=%s" ,
119- calculated_crc ,
120- received_crc ,
121- (calculated_crc == received_crc ) ? "YES" : "NO" );
89+ // Received CRC has bit 7 inverted
90+ uint8_t received_crc = (uint8_t )(key2 & 0xFF ) ^ 0x80 ;
12291
12392 return (calculated_crc == received_crc );
12493}
@@ -437,19 +406,23 @@ SubGhzProtocolStatus
437406 }
438407 instance -> generic .cnt = instance -> count ;
439408
409+ // Read BS from file
440410 uint32_t bs_temp = 0 ;
441411 flipper_format_read_uint32 (flipper_format , "BS" , & bs_temp , 1 );
412+ uint8_t bs = (uint8_t )(bs_temp & 0xFF );
442413
443- uint32_t crc_temp = 0 ;
444- flipper_format_read_uint32 (flipper_format , "CRC" , & crc_temp , 1 );
414+ // Calculate CRC from key1 and BS
415+ uint8_t calculated_crc = ford_v0_calculate_crc_for_tx (instance -> key1 , bs );
416+
417+ // Build key2 from BS and calculated CRC
418+ instance -> key2 = ((uint16_t )bs << 8 ) | calculated_crc ;
445419
446- instance -> key2 = ((bs_temp & 0xFF ) << 8 ) | (crc_temp & 0xFF );
447420 FURI_LOG_I (
448421 TAG ,
449- "Reconstructed key2: 0x%04X (BS=0x%02X, CRC=0x%02X)" ,
422+ "Encoder key2: 0x%04X (BS=0x%02X, CRC=0x%02X calculated )" ,
450423 instance -> key2 ,
451- ( uint8_t ) bs_temp ,
452- ( uint8_t ) crc_temp );
424+ bs ,
425+ calculated_crc );
453426
454427 if (!flipper_format_read_uint32 (
455428 flipper_format , "Repeat" , (uint32_t * )& instance -> encoder .repeat , 1 )) {
@@ -581,42 +554,15 @@ static bool ford_v0_process_data(SubGhzProtocolDecoderFordV0* instance) {
581554 instance -> key1 = ~combined ;
582555 instance -> data_low = 0 ;
583556 instance -> data_high = 0 ;
584- FURI_LOG_I (
585- TAG ,
586- "Got 64 bits, key1=0x%08lX%08lX" ,
587- (uint32_t )(instance -> key1 >> 32 ),
588- (uint32_t )(instance -> key1 & 0xFFFFFFFF ));
589557 return false;
590558 }
591559
592560 if (instance -> bit_count == 80 ) {
593561 uint16_t key2_raw = (uint16_t )(instance -> data_low & 0xFFFF );
594562 uint16_t key2 = ~key2_raw ;
595-
596- FURI_LOG_I (TAG , "Got 80 bits, key2_raw=0x%04X key2=0x%04X" , key2_raw , key2 );
597-
598- // Verify CRC
599- bool crc_ok = ford_v0_verify_crc (instance -> key1 , key2 );
600-
601- FURI_LOG_I (
602- TAG ,
603- "Received: key1=0x%08lX%08lX key2=0x%04X CRC=%s" ,
604- (uint32_t )(instance -> key1 >> 32 ),
605- (uint32_t )(instance -> key1 & 0xFFFFFFFF ),
606- key2 ,
607- crc_ok ? "OK" : "BAD" );
608-
609563 decode_ford_v0 (
610564 instance -> key1 , key2 , & instance -> serial , & instance -> button , & instance -> count );
611565 instance -> key2 = key2 ;
612-
613- FURI_LOG_I (
614- TAG ,
615- "Decoded: Sn=0x%08lX Btn=%d Cnt=0x%05lX" ,
616- instance -> serial ,
617- instance -> button ,
618- instance -> count );
619-
620566 return true;
621567 }
622568
@@ -819,7 +765,7 @@ SubGhzProtocolStatus
819765 if (ret == SubGhzProtocolStatusOk ) {
820766 instance -> key1 = instance -> generic .data ;
821767
822- // Rewind and read all custom fields
768+ // Rewind and read custom fields
823769 flipper_format_rewind (flipper_format );
824770
825771 uint32_t bs_temp = 0 ;
@@ -828,15 +774,6 @@ SubGhzProtocolStatus
828774 flipper_format_read_uint32 (flipper_format , "CRC" , & crc_temp , 1 );
829775 instance -> key2 = ((bs_temp & 0xFF ) << 8 ) | (crc_temp & 0xFF );
830776
831- FURI_LOG_I (
832- TAG ,
833- "Deserialize: key1=0x%08lX%08lX key2=0x%04X (BS=%02X CRC=%02X)" ,
834- (uint32_t )(instance -> key1 >> 32 ),
835- (uint32_t )(instance -> key1 & 0xFFFFFFFF ),
836- instance -> key2 ,
837- (uint8_t )bs_temp ,
838- (uint8_t )crc_temp );
839-
840777 flipper_format_read_uint32 (flipper_format , "Serial" , & instance -> serial , 1 );
841778 instance -> generic .serial = instance -> serial ;
842779
@@ -888,4 +825,4 @@ void subghz_protocol_decoder_ford_v0_get_string(void* context, FuriString* outpu
888825 instance -> count ,
889826 (instance -> key2 >> 8 ) & 0xFF ,
890827 instance -> key2 & 0xFF );
891- }
828+ }
0 commit comments