HoTT, XN297 emu: compute the hop and CRC xorout tables (-1.2 KB) (#1199)

* HoTT: compute the hop table from the hop value (-1 KB)

The 16 hop tables are generated from the 16 bit value sent in packet[0..1]:
the C library rand() LCG (low 16 bits: x = x * 0x4E6D + 0x3039) seeded with
it drives forward Fisher-Yates shuffles, first of the order of the 5 bands of
15 channels, then of the channels of each band, hop i being in the band at
position i%5. This gives back the 16 tables bit for bit, and for any seed a
75 channel permutation with the same band structure.

* XN297 emu: compute the CRC xorout instead of the 4 tables

The XN297 CRC is CRC-16/CCITT with init 0xFFFF and xorout 0xFFFF over the
unscrambled address, pcf and payload, sent scrambled. The emulation computes
it from 0xB5D2 over the bits as sent, so the xorout for a CRC over n bits is
CRC(init 0xFFFF^0xB5D2) of n scramble (or zero) bits, xor 0xFFFF, xor the 16
scramble bits at the CRC. The scramble bits come from the LFSR behind
xn297_scramble[] (1110001, then s[i] = s[i-7] ^ s[i-3]), which also covers
the last enhanced entries, past the end of that table. It is the generator
Goebish gave for the scramble sequence in a comment on
https://mcumix.blogspot.com/2016/07/reverse-engineering-24ghz-rf-chip-xn297.html
(seed 0x71, feedback bit 6 ^ bit 2, MSB first).

All the entries of the 4 tables are given back but two: entry 0 (3 byte
address, no payload) was a 0 placeholder, and scrambled entry 1 (3 byte
address, 1 byte payload) was 0x3448 where the formula gives 0xE348.
This commit is contained in:
Raphael Coeffic
2026-10-23 12:02:20 +02:00
committed by GitHub
parent ee984c403d
commit d3293afdab
4 changed files with 66 additions and 78 deletions
+31 -20
View File
@@ -117,24 +117,36 @@ static void __attribute__((unused)) HOTT_tune_freq()
}
}
const uint8_t PROGMEM HOTT_hop[][HOTT_NUM_RF_CHANNELS]=
{ { 48, 37, 16, 62, 9, 50, 42, 22, 68, 0, 55, 35, 21, 74, 1, 56, 31, 20, 70, 11, 45, 32, 24, 71, 8, 54, 38, 26, 61, 13, 53, 30, 15, 65, 7, 52, 34, 28, 60, 3, 47, 39, 18, 69, 2, 49, 44, 23, 72, 5, 51, 43, 19, 64, 12, 46, 33, 17, 67, 6, 58, 36, 29, 73, 14, 57, 41, 25, 63, 4, 59, 40, 27, 66, 10 },
{ 50, 23, 5, 34, 67, 53, 22, 12, 39, 62, 51, 21, 10, 33, 63, 59, 16, 1, 43, 66, 49, 19, 8, 30, 71, 47, 24, 2, 35, 68, 45, 25, 14, 41, 74, 55, 18, 4, 32, 61, 54, 17, 11, 31, 72, 52, 28, 6, 38, 65, 46, 15, 9, 40, 60, 48, 26, 3, 37, 70, 58, 29, 0, 36, 64, 56, 20, 7, 42, 69, 57, 27, 13, 44, 73 },
{ 73, 51, 39, 18, 9, 64, 56, 34, 16, 12, 66, 58, 36, 25, 11, 61, 47, 40, 15, 8, 71, 50, 43, 20, 6, 62, 54, 42, 19, 3, 63, 46, 44, 29, 14, 72, 49, 33, 22, 5, 69, 57, 30, 21, 10, 70, 45, 35, 26, 7, 65, 59, 31, 28, 1, 67, 48, 32, 24, 0, 60, 55, 41, 17, 2, 74, 52, 38, 27, 4, 68, 53, 37, 23, 13 },
{ 52, 60, 40, 21, 14, 50, 72, 41, 23, 13, 59, 61, 39, 16, 6, 58, 66, 33, 17, 5, 55, 64, 43, 20, 12, 54, 74, 35, 29, 3, 46, 63, 37, 22, 10, 48, 65, 31, 27, 9, 49, 73, 38, 24, 11, 56, 70, 32, 15, 1, 51, 71, 44, 18, 8, 45, 67, 36, 25, 7, 57, 62, 34, 28, 2, 53, 69, 42, 19, 4, 47, 68, 30, 26, 0 },
{ 50, 16, 34, 6, 71, 51, 24, 40, 7, 68, 57, 27, 33, 14, 70, 55, 26, 30, 5, 74, 47, 28, 44, 11, 67, 49, 15, 32, 9, 61, 52, 22, 37, 13, 66, 59, 18, 42, 3, 62, 46, 29, 31, 12, 60, 48, 19, 38, 1, 72, 58, 17, 36, 4, 64, 53, 21, 39, 0, 63, 56, 20, 41, 2, 65, 45, 25, 35, 10, 69, 54, 23, 43, 8, 73 },
{ 55, 38, 12, 62, 23, 52, 44, 3, 66, 18, 54, 36, 10, 74, 16, 56, 42, 9, 70, 17, 58, 33, 5, 69, 20, 50, 40, 1, 63, 24, 53, 37, 13, 65, 15, 48, 34, 4, 61, 22, 57, 31, 6, 64, 26, 46, 35, 11, 72, 21, 47, 30, 7, 68, 29, 45, 32, 8, 60, 19, 49, 43, 2, 67, 27, 51, 39, 0, 71, 28, 59, 41, 14, 73, 25 },
{ 70, 32, 18, 10, 58, 69, 38, 22, 2, 54, 67, 36, 19, 12, 57, 62, 34, 20, 14, 52, 63, 41, 15, 3, 51, 73, 42, 28, 6, 48, 60, 43, 29, 5, 45, 64, 31, 17, 4, 56, 65, 35, 26, 13, 53, 61, 37, 23, 1, 49, 68, 40, 16, 9, 47, 71, 39, 25, 7, 50, 66, 33, 24, 8, 59, 72, 44, 27, 11, 46, 74, 30, 21, 0, 55 },
{ 6, 45, 71, 27, 44, 10, 46, 74, 22, 32, 0, 55, 69, 21, 33, 4, 50, 66, 18, 38, 7, 57, 62, 19, 36, 1, 48, 70, 20, 40, 8, 47, 68, 15, 43, 2, 58, 61, 26, 42, 3, 56, 72, 23, 34, 14, 54, 67, 16, 37, 5, 59, 64, 24, 30, 12, 52, 65, 25, 39, 13, 49, 73, 17, 31, 9, 53, 60, 28, 35, 11, 51, 63, 29, 41 },
{ 31, 65, 50, 20, 13, 37, 66, 45, 23, 5, 32, 69, 54, 19, 7, 39, 74, 52, 27, 1, 42, 64, 53, 22, 4, 43, 70, 58, 16, 3, 40, 71, 57, 17, 0, 35, 63, 56, 18, 9, 44, 72, 51, 21, 6, 33, 67, 46, 25, 11, 30, 73, 55, 15, 8, 36, 62, 48, 24, 10, 41, 60, 49, 29, 14, 34, 61, 47, 26, 2, 38, 68, 59, 28, 12 },
{ 67, 22, 49, 36, 13, 64, 28, 57, 37, 6, 65, 29, 46, 39, 3, 70, 26, 45, 35, 1, 62, 24, 58, 34, 10, 68, 19, 53, 33, 4, 66, 21, 52, 31, 7, 74, 18, 47, 32, 5, 61, 16, 51, 38, 8, 72, 23, 55, 30, 12, 73, 17, 59, 44, 0, 60, 15, 50, 43, 14, 63, 27, 48, 42, 11, 71, 20, 54, 41, 9, 69, 25, 56, 40, 2 },
{ 19, 38, 14, 66, 57, 18, 44, 7, 74, 48, 23, 30, 6, 71, 58, 26, 32, 5, 61, 46, 20, 34, 0, 68, 45, 24, 36, 1, 70, 50, 27, 33, 10, 63, 52, 16, 42, 9, 65, 51, 15, 41, 11, 64, 53, 22, 37, 3, 60, 56, 28, 35, 4, 67, 49, 17, 39, 13, 69, 54, 25, 43, 2, 73, 55, 21, 31, 8, 62, 47, 29, 40, 12, 72, 59 },
{ 4, 52, 64, 28, 44, 14, 46, 74, 16, 32, 11, 50, 68, 27, 36, 0, 47, 70, 26, 34, 13, 57, 61, 18, 38, 6, 56, 62, 19, 40, 5, 58, 67, 17, 31, 12, 54, 63, 22, 33, 3, 53, 72, 21, 41, 10, 48, 66, 15, 35, 7, 45, 60, 20, 37, 9, 51, 69, 25, 42, 2, 59, 71, 24, 39, 1, 55, 65, 23, 30, 8, 49, 73, 29, 43 },
{ 44, 66, 19, 1, 56, 35, 62, 20, 4, 54, 39, 70, 24, 5, 55, 31, 74, 26, 12, 58, 32, 60, 17, 10, 45, 37, 63, 22, 3, 50, 33, 64, 16, 7, 51, 34, 61, 21, 8, 48, 38, 68, 29, 0, 46, 36, 72, 28, 14, 49, 42, 69, 25, 6, 57, 43, 65, 18, 2, 52, 30, 71, 23, 13, 47, 41, 67, 15, 9, 53, 40, 73, 27, 11, 59 },
{ 12, 16, 36, 46, 69, 6, 20, 44, 58, 62, 11, 19, 34, 48, 71, 1, 18, 42, 50, 74, 3, 25, 31, 47, 65, 0, 24, 33, 45, 72, 2, 23, 35, 56, 64, 10, 22, 38, 49, 63, 7, 26, 37, 51, 70, 14, 21, 30, 53, 67, 5, 15, 40, 52, 66, 9, 17, 39, 55, 60, 13, 27, 41, 54, 73, 4, 28, 32, 57, 61, 8, 29, 43, 59, 68 },
{ 63, 42, 18, 2, 57, 71, 34, 22, 10, 48, 67, 36, 25, 4, 46, 60, 31, 28, 6, 47, 74, 37, 15, 0, 55, 65, 32, 24, 12, 56, 66, 40, 27, 14, 52, 62, 38, 19, 3, 50, 73, 33, 29, 11, 53, 61, 35, 16, 7, 58, 72, 41, 26, 5, 59, 69, 30, 20, 9, 51, 68, 44, 23, 1, 49, 70, 39, 17, 8, 54, 64, 43, 21, 13, 45 },
{ 52, 1, 71, 17, 36, 47, 7, 64, 26, 32, 53, 5, 60, 20, 42, 57, 2, 66, 18, 34, 56, 4, 63, 24, 35, 46, 13, 72, 22, 30, 48, 0, 67, 21, 39, 50, 3, 74, 16, 31, 59, 14, 61, 23, 37, 45, 6, 65, 19, 44, 51, 11, 62, 27, 41, 55, 9, 68, 15, 38, 58, 8, 70, 29, 40, 54, 10, 69, 28, 33, 49, 12, 73, 25, 43 }
};
// Hop table from the value sent in packet[0..1]: the C library rand() (low 16
// bits) seeded with it drives forward Fisher-Yates shuffles, first of the order
// of the 5 bands of 15 channels, then of the channels of each band. Hop i is in
// the band at position i%5 of that order.
static uint16_t __attribute__((unused)) HOTT_rand(uint16_t *seed)
{
*seed = *seed * 0x4E6D + 0x3039;
return *seed;
}
static void __attribute__((unused)) HOTT_hop_init(uint16_t seed)
{
uint8_t order[5], tmp, j;
for(uint8_t i=0; i<5; i++)
order[i] = i;
for(uint8_t i=0; i<5; i++)
{
j = i + HOTT_rand(&seed) % (5-i);
tmp = order[i]; order[i] = order[j]; order[j] = tmp;
}
for(uint8_t i=0; i<HOTT_NUM_RF_CHANNELS; i++)
hopping_frequency[i] = order[i%5]*15 + i/5;
for(uint8_t k=0; k<15; k++) // Shuffle in place: column b of the table holds the channels of the band at position b
for(uint8_t b=0; b<5; b++)
{
j = k + HOTT_rand(&seed) % (15-k);
tmp = hopping_frequency[5*k+b]; hopping_frequency[5*k+b] = hopping_frequency[5*j+b]; hopping_frequency[5*j+b] = tmp;
}
}
const uint16_t PROGMEM HOTT_hop_val[] = { 0xC06B, 0xC34A, 0xDB24, 0x8E09, 0x272E, 0x217F, 0x155B, 0xEDE8, 0x1D31, 0x0986, 0x56F7, 0x6454, 0xC42D, 0x01D2, 0xC253, 0x1180 };
static void __attribute__((unused)) HOTT_TXID_init()
@@ -142,8 +154,7 @@ static void __attribute__((unused)) HOTT_TXID_init()
packet[0] = pgm_read_word_near( &HOTT_hop_val[num_ch] );
packet[1] = pgm_read_word_near( &HOTT_hop_val[num_ch] )>>8;
for(uint8_t i=0; i<HOTT_NUM_RF_CHANNELS; i++)
hopping_frequency[i]=pgm_read_byte_near( &HOTT_hop[num_ch][i] );
HOTT_hop_init(pgm_read_word_near( &HOTT_hop_val[num_ch] ));
#ifdef HOTT_FORCE_ID
memcpy(rx_tx_addr,"\x7C\x94\x00\x0D\x50",5); //TX1
memcpy(rx_tx_addr,"\xEA\x4D\x00\x01\x50",5); //TX2