Files
DIY-Multiprotocol-TX-Module/Multiprotocol/XN297Dump_nrf24l01.ino
T
Raphael Coeffic d3293afdab 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.
2026-10-23 12:02:20 +02:00

976 lines
29 KiB
Arduino

/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
// sub_protocol: 0=250Kbps, 1=1Mbps, 2=2Mbps. Other values default to 1Mbps.
// RX_num = address length 3 or 4 or 5. Other values default to 5.
// option = RF channel number 0..84 and -1 = scan all channels. Other values default to RF channel 0.
#ifdef XN297DUMP_NRF24L01_INO
#include "iface_xn297.h"
// Parameters which can be modified
#define XN297DUMP_PERIOD_FAST_SCAN 50000 // 50000
#define XN297DUMP_PERIOD_SLOW_SCAN 100000 // 75000
#define XN297DUMP_MAX_PACKET 50 // 20
#define XN297DUMP_MAX_RF_CHANNEL 84 // Default 84
// Do not touch from there
#define XN297DUMP_INITIAL_WAIT 500
#define XN297DUMP_MAX_PACKET_LEN 32
#define XN297DUMP_CRC_LENGTH 2
uint8_t address_length;
uint16_t timeH=0;
boolean scramble;
boolean enhanced;
boolean ack;
uint8_t pid;
uint8_t bitrate;
uint8_t old_option;
uint32_t scan_counter;
static void __attribute__((unused)) XN297Dump_RF_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // 3 bytes RX/TX address
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\x55\x0F\x71", 3); // set up RX address to xn297 preamble
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, XN297DUMP_MAX_PACKET_LEN); // Enable rx pipe 0
debug("XN297 dump, address length=%d, bitrate=",address_length);
switch(bitrate)
{
case XN297DUMP_250K:
NRF24L01_SetBitrate(NRF24L01_BR_250K);
debugln("250K");
break;
case XN297DUMP_2M:
NRF24L01_SetBitrate(NRF24L01_BR_2M);
debugln("2M");
break;
default:
NRF24L01_SetBitrate(NRF24L01_BR_1M);
debugln("1M");
break;
}
}
extern const uint8_t xn297_scramble[];
static boolean __attribute__((unused)) XN297Dump_process_packet(void)
{
uint16_t crcxored;
uint8_t packet_sc[XN297DUMP_MAX_PACKET_LEN], packet_un[XN297DUMP_MAX_PACKET_LEN];
enhanced=false;
// init crc
crc = 0xb5d2;
/*debug("P: 71 0F 55 ");
for(uint8_t i=0; i<XN297DUMP_MAX_PACKET_LEN; i++)
debug("%02X ",packet[i]);
debugln("");*/
//Try normal payload
// address
for (uint8_t i = 0; i < address_length; i++)
{
crc16_update( packet[i], 8);
packet_un[address_length-1-i]=packet[i];
packet_sc[address_length-1-i]=packet[i] ^ xn297_scramble[i];
}
// payload
for (uint8_t i = address_length; i < XN297DUMP_MAX_PACKET_LEN-XN297DUMP_CRC_LENGTH; i++)
{
crc16_update( packet[i], 8);
packet_sc[i] = bit_reverse(packet[i]^xn297_scramble[i]);
packet_un[i] = bit_reverse(packet[i]);
// check crc
crcxored = crc ^ XN297_crc_xorout(false, 8 * (i+1));
if( (crcxored >> 8) == packet[i + 1] && (crcxored & 0xff) == packet[i + 2])
{
packet_length=i+1;
memcpy(packet,packet_un,packet_length);
scramble=false;
return true;
}
crcxored = crc ^ XN297_crc_xorout(true, 8 * (i+1));
if( (crcxored >> 8) == packet[i + 1] && (crcxored & 0xff) == packet[i + 2])
{
packet_length=i+1;
memcpy(packet,packet_sc,packet_length);
scramble=true;
return true;
}
}
//Try enhanced payload
uint16_t crc_save = 0xb5d2;
packet_length=0;
for (uint8_t i = 0; i < XN297DUMP_MAX_PACKET_LEN-XN297DUMP_CRC_LENGTH; i++)
{
packet_sc[i]=packet[i]^xn297_scramble[i];
crc = crc_save;
crc16_update( packet[i], 8);
crc_save = crc;
crc16_update( packet[i+1] & 0xC0, 2);
crcxored=(packet[i+1]<<10)|(packet[i+2]<<2)|(packet[i+3]>>6) ;
if(i>=3)
{
if((crc ^ XN297_crc_xorout(true, 8 * i + 10)) == crcxored)
{ // Found a valid CRC for the enhanced payload mode
packet_length=i;
scramble=true;
i++;
packet_sc[i]=packet[i]^xn297_scramble[i];
memcpy(packet_un,packet_sc,packet_length+2); // unscramble packet
break;
}
if((crc ^ XN297_crc_xorout(false, 8 * i + 10)) == crcxored)
{ // Found a valid CRC for the enhanced payload mode
packet_length=i;
scramble=false;
memcpy(packet_un,packet,packet_length+2); // packet is unscrambled
break;
}
}
}
if(packet_length!=0)
{ // Found a valid CRC for the enhanced payload mode
enhanced=true;
//check selected address length
if((packet_un[address_length]>>1)!=packet_length-address_length)
{
for(uint8_t i=3;i<=5;i++)
if((packet_un[i]>>1)==packet_length-i)
address_length=i;
debugln("Detected wrong address length, using %d intead", address_length );
}
pid=((packet_un[address_length]&0x01)<<1)|(packet_un[address_length+1]>>7);
ack=(packet_un[address_length+1]>>6)&0x01;
// address
for (uint8_t i = 0; i < address_length; i++)
packet[address_length-1-i]=packet_un[i];
// payload
for (uint8_t i = address_length; i < packet_length; i++)
packet[i] = bit_reverse((packet_un[i+1]<<2)|(packet_un[i+2]>>6));
return true;
}
return false;
}
static void __attribute__((unused)) XN297Dump_overflow()
{
if(TIMER2_BASE->SR & TIMER_SR_UIF)
{ // timer overflow
timeH++;
TIMER2_BASE->SR = 0x1E5F & ~TIMER_SR_UIF; // Clear Timer2 overflow flag
}
}
static uint16_t XN297Dump_callback()
{
static uint32_t time=0,*time_rf;
static uint8_t *nbr_rf,compare_channel;
//!!!Blocking mode protocol!!!
TX_MAIN_PAUSE_off;
tx_resume();
while(1)
{
if(sub_protocol<XN297DUMP_AUTO)
{
if(option==0xFF && scan_counter>XN297DUMP_PERIOD_SLOW_SCAN)
{ // Scan frequencies
hopping_frequency_no++;
scan_counter=0;
}
if(hopping_frequency_no!=rf_ch_num)
{ // Channel has changed
if(hopping_frequency_no>XN297DUMP_MAX_RF_CHANNEL)
hopping_frequency_no=0; // Invalid channel 0 by default
rf_ch_num=hopping_frequency_no;
debugln("Channel=%d,0x%02X",hopping_frequency_no,hopping_frequency_no);
NRF24L01_WriteReg(NRF24L01_05_RF_CH,hopping_frequency_no);
// switch to RX mode
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC) // switch to RX mode and disable CRC
| (1 << NRF24L01_00_CRCO)
| (1 << NRF24L01_00_PWR_UP)
| (1 << NRF24L01_00_PRIM_RX));
phase=0; // init timer
}
XN297Dump_overflow();
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
{ // RX fifo data ready
if(NRF24L01_ReadReg(NRF24L01_09_CD) || option != 0xFF)
{
NRF24L01_ReadPayload(packet,XN297DUMP_MAX_PACKET_LEN);
XN297Dump_overflow();
uint16_t timeL=TCNT1;
if(TIMER2_BASE->SR & TIMER_SR_UIF)
{//timer just rolled over...
XN297Dump_overflow();
timeL=0;
}
if((phase&0x01)==0)
{
phase=1;
time=0;
}
else
time=(timeH<<16)+timeL-time;
if(XN297Dump_process_packet())
{ // valid crc found
debug("RX: %5luus C=%d ", time>>1 , hopping_frequency_no);
time=(timeH<<16)+timeL;
if(enhanced)
{
debug("Enhanced ");
debug("pid=%d ",pid);
if(ack) debug("ack ");
}
debug("S=%c A=",scramble?'Y':'N');
for(uint8_t i=0; i<address_length; i++)
{
debug(" %02X",packet[i]);
}
debug(" P(%d)=",packet_length-address_length);
for(uint8_t i=address_length; i<packet_length; i++)
{
debug(" %02X",packet[i]);
}
debugln("");
}
else
{
debugln("RX: %5luus C=%d Bad CRC", time>>1 , hopping_frequency_no);
}
}
XN297Dump_overflow();
// restart RX mode
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC) // switch to RX mode and disable CRC
| (1 << NRF24L01_00_CRCO)
| (1 << NRF24L01_00_PWR_UP)
| (1 << NRF24L01_00_PRIM_RX));
XN297Dump_overflow();
}
}
else if(sub_protocol==XN297DUMP_AUTO)
{
switch(phase)
{
case 0:
debugln("------------------------");
debugln("Detecting XN297 packets.");
XN297Dump_RF_init();
debug("Trying RF channel: 0");
hopping_frequency_no=0;
bitrate=0;
phase++;
break;
case 1:
if(scan_counter>XN297DUMP_PERIOD_FAST_SCAN)
{ // Scan frequencies
hopping_frequency_no++;
scan_counter=0;
if(hopping_frequency_no>XN297DUMP_MAX_RF_CHANNEL)
{
hopping_frequency_no=0;
bitrate++;
bitrate%=3;
debugln("");
XN297Dump_RF_init();
debug("Trying RF channel: 0");
}
if(hopping_frequency_no)
debug(",%d",hopping_frequency_no);
NRF24L01_WriteReg(NRF24L01_05_RF_CH,hopping_frequency_no);
// switch to RX mode
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC) // switch to RX mode and disable CRC
| (1 << NRF24L01_00_CRCO)
| (1 << NRF24L01_00_PWR_UP)
| (1 << NRF24L01_00_PRIM_RX));
}
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
{ // RX fifo data ready
if(NRF24L01_ReadReg(NRF24L01_09_CD))
{
NRF24L01_ReadPayload(packet,XN297DUMP_MAX_PACKET_LEN);
if(XN297Dump_process_packet())
{ // valid crc found
debug("\r\n\r\nPacket detected: bitrate=");
switch(bitrate)
{
case XN297DUMP_250K:
XN297_Configure(XN297_CRCEN, scramble?XN297_SCRAMBLED:XN297_UNSCRAMBLED, XN297_250K, true);
debug("250K");
break;
case XN297DUMP_2M:
XN297_Configure(XN297_CRCEN, scramble?XN297_SCRAMBLED:XN297_UNSCRAMBLED, XN297_1M);
NRF24L01_SetBitrate(NRF24L01_BR_2M);
debug("2M");
break;
default:
XN297_Configure(XN297_CRCEN, scramble?XN297_SCRAMBLED:XN297_UNSCRAMBLED, XN297_1M);
debug("1M");
break;
}
debug(" C=%d ", hopping_frequency_no);
if(enhanced)
{
debug("Enhanced ");
debug("pid=%d ",pid);
if(ack) debug("ack ");
}
debug("S=%c A=",scramble?'Y':'N');
for(uint8_t i=0; i<address_length; i++)
{
debug(" %02X",packet[i]);
rx_tx_addr[i]=packet[i];
}
debug(" P(%d)=",packet_length-address_length);
for(uint8_t i=address_length; i<packet_length; i++)
{
debug(" %02X",packet[i]);
}
packet_length=packet_length-address_length;
debugln("\r\n--------------------------------");
phase=2;
debugln("Identifying all RF channels in use.");
scan_counter=0;
hopping_frequency_no=0;
rf_ch_num=0;
packet_count=0;
nbr_rf=(uint8_t*)malloc(XN297DUMP_MAX_RF_CHANNEL*sizeof(uint8_t));
if(nbr_rf==NULL)
{
debugln("\r\nCan't allocate memory for next phase!!!");
phase=0;
break;
}
debug("Trying RF channel: 0");
XN297_SetTXAddr(rx_tx_addr,address_length);
XN297_SetRXAddr(rx_tx_addr,packet_length);
XN297_RFChannel(0);
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(RX_EN);
}
}
}
break;
case 2:
if(scan_counter>XN297DUMP_PERIOD_SLOW_SCAN)
{ // Scan frequencies
hopping_frequency_no++;
scan_counter=0;
if(packet_count && packet_count<=XN297DUMP_MAX_PACKET)
debug("\r\nTrying RF channel: ");
packet_count=0;
if(hopping_frequency_no>XN297DUMP_MAX_RF_CHANNEL)
{
uint8_t nbr_max=0,j=0;
debug("\r\n\r\n%d RF channels identified:",rf_ch_num);
compare_channel=0;
for(uint8_t i=0;i<rf_ch_num;i++)
{
debug(" %d[%d]",hopping_frequency[i],nbr_rf[i]);
if(nbr_rf[i]>nbr_max)
{
nbr_max=nbr_rf[i];
compare_channel=i;
}
}
nbr_max = (nbr_max*2)/3;
debug("\r\nKeeping only RF channels with more than %d packets:", nbr_max);
for(uint8_t i=0;i<rf_ch_num;i++)
if(nbr_rf[i]>=nbr_max)
{
hopping_frequency[j]=hopping_frequency[i];
debug(" %d",hopping_frequency[j]);
if(compare_channel==i)
{
compare_channel=j;
debug("*");
}
j++;
}
rf_ch_num = j;
free(nbr_rf);
time_rf=(uint32_t*)malloc(rf_ch_num*sizeof(time));
if(time_rf==NULL)
{
debugln("\r\nCan't allocate memory for next phase!!!");
phase=0;
break;
}
debugln("\r\n--------------------------------");
debugln("Identifying RF channels order.");
hopping_frequency_no=0;
phase=3;
packet_count=0;
scan_counter=0;
debugln("Time between CH:%d and CH:%d",hopping_frequency[compare_channel],hopping_frequency[hopping_frequency_no]);
time_rf[hopping_frequency_no]=0xFFFFFFFF;
XN297_RFChannel(hopping_frequency[compare_channel]);
uint16_t timeL=TCNT1;
if(TIMER2_BASE->SR & TIMER_SR_UIF)
{//timer just rolled over...
XN297Dump_overflow();
timeL=0;
}
time=(timeH<<16)+timeL;
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(RX_EN);
XN297Dump_overflow();
break;
}
debug(",%d",hopping_frequency_no);
XN297_RFChannel(hopping_frequency_no);
// switch to RX mode
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(RX_EN);
}
if( XN297_IsRX() )
{ // RX fifo data ready
if(NRF24L01_ReadReg(NRF24L01_09_CD))
{
uint8_t res;
if(enhanced)
{
res=XN297_ReadEnhancedPayload(packet, packet_length);
res++;
}
else
res=XN297_ReadPayload(packet, packet_length);
if(res)
{ // valid crc found
XN297Dump_overflow();
uint16_t timeL=TCNT1;
if(TIMER2_BASE->SR & TIMER_SR_UIF)
{//timer just rolled over...
XN297Dump_overflow();
timeL=0;
}
if(packet_count==0)
{//save channel
hopping_frequency[rf_ch_num]=hopping_frequency_no;
rf_ch_num++;
time=0;
}
else
time=(timeH<<16)+timeL-time;
debug("\r\nRX on channel: %d, Time: %5luus P:",hopping_frequency_no, time>>1);
time=(timeH<<16)+timeL;
for(uint8_t i=0;i<packet_length;i++)
debug(" %02X",packet[i]);
packet_count++;
nbr_rf[rf_ch_num-1]=packet_count;
if(packet_count>XN297DUMP_MAX_PACKET)
{//change channel
scan_counter=XN297DUMP_PERIOD_SLOW_SCAN+1;
debug("\r\nTrying RF channel: ");
}
}
}
// restart RX mode
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(RX_EN);
}
XN297Dump_overflow();
break;
case 3:
if(scan_counter>XN297DUMP_PERIOD_SLOW_SCAN)
{ // Scan frequencies
hopping_frequency_no++;
scan_counter=0;
if(hopping_frequency_no>=rf_ch_num)
{
uint8_t next=0;
debugln("\r\n\r\nChannel order:");
debugln("%d: 0us",hopping_frequency[compare_channel]);
uint8_t i=0;
do
{
time=time_rf[i];
if(time!=0xFFFFFFFF)
{
next=i;
for(uint8_t j=1;j<rf_ch_num;j++)
if(time>time_rf[j])
{
next=j;
time=time_rf[j];
}
time_rf[next]=-1;
debugln("%d: %5luus",hopping_frequency[next],time);
i=0;
}
i++;
}
while(i<rf_ch_num);
free(time_rf);
debugln("\r\n--------------------------------");
debugln("Identifying Sticks and features.");
phase=4;
hopping_frequency_no=0;
break;
}
debugln("Time between CH:%d and CH:%d",hopping_frequency[compare_channel],hopping_frequency[hopping_frequency_no]);
time_rf[hopping_frequency_no]=-1;
XN297_RFChannel(hopping_frequency[compare_channel]);
uint16_t timeL=TCNT1;
if(TIMER2_BASE->SR & TIMER_SR_UIF)
{//timer just rolled over...
XN297Dump_overflow();
timeL=0;
}
time=(timeH<<16)+timeL;
// switch to RX mode
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(RX_EN);
}
if( XN297_IsRX() )
{ // RX fifo data ready
if(NRF24L01_ReadReg(NRF24L01_09_CD))
{
uint8_t res;
if(enhanced)
{
res=XN297_ReadEnhancedPayload(packet, packet_length);
res++;
}
else
res=XN297_ReadPayload(packet, packet_length);
if(res)
{ // valid crc found
XN297Dump_overflow();
uint16_t timeL=TCNT1;
if(TIMER2_BASE->SR & TIMER_SR_UIF)
{//timer just rolled over...
XN297Dump_overflow();
timeL=0;
}
if(packet_count&1)
{
time=(timeH<<16)+timeL-time;
if(time_rf[hopping_frequency_no] > (time>>1))
time_rf[hopping_frequency_no]=time>>1;
debugln("Time: %5luus", time>>1);
XN297_RFChannel(hopping_frequency[compare_channel]);
}
else
{
time=(timeH<<16)+timeL;
XN297_RFChannel(hopping_frequency[hopping_frequency_no]);
}
packet_count++;
if(packet_count>24)
{
scan_counter=XN297DUMP_PERIOD_SLOW_SCAN+1;
packet_count=0;
}
}
}
// restart RX mode
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(RX_EN);
}
XN297Dump_overflow();
break;
case 4:
if( XN297_IsRX() )
{ // RX fifo data ready
//if(NRF24L01_ReadReg(NRF24L01_09_CD))
{
uint8_t res;
if(enhanced)
{
res=XN297_ReadEnhancedPayload(packet, packet_length);
res++;
}
else
res=XN297_ReadPayload(packet, packet_length);
if(res)
{ // valid crc found
if(memcmp(packet_in,packet,packet_length))
{
debug("P:");
for(uint8_t i=0;i<packet_length;i++)
debug(" %02X",packet[i]);
debugln("");
memcpy(packet_in,packet,packet_length);
}
}
}
// restart RX mode
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(RX_EN);
}
break;
}
}
else if(sub_protocol == XN297DUMP_NRF)
{
if(phase==0)
{
address_length=5;
memcpy(rx_tx_addr, (uint8_t *)"\xCC\xCC\xCC\xCC\xCC", address_length); // bind \x7E\xB8\x63\xA9
bitrate=XN297DUMP_250K;
packet_length=9;
hopping_frequency_no=71; //bind 71, normal ??
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, address_length-2); // RX/TX address length
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, address_length); // set up RX address
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, packet_length); // Enable rx pipe 0
NRF24L01_WriteReg(NRF24L01_05_RF_CH, option); //hopping_frequency_no);
old_option = option;
debug("NRF dump, len=%d, rf=%d, address length=%d, bitrate=",packet_length,option,address_length); //hopping_frequency_no,address_length);
switch(bitrate)
{
case XN297DUMP_250K:
NRF24L01_SetBitrate(NRF24L01_BR_250K);
debugln("250K");
break;
case XN297DUMP_2M:
NRF24L01_SetBitrate(NRF24L01_BR_2M);
debugln("2M");
break;
default:
NRF24L01_SetBitrate(NRF24L01_BR_1M);
debugln("1M");
break;
}
NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX)); //_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) |
phase++;
time=0;
}
else
{
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
{ // RX fifo data ready
if(NRF24L01_ReadReg(NRF24L01_09_CD))
{
XN297Dump_overflow();
uint16_t timeL=TCNT1;
if(TIMER2_BASE->SR & TIMER_SR_UIF)
{//timer just rolled over...
XN297Dump_overflow();
timeL=0;
}
time=(timeH<<16)+timeL-time;
debug("RX: %5luus ", time>>1);
time=(timeH<<16)+timeL;
NRF24L01_ReadPayload(packet, packet_length);
//bool ok=true;
uint8_t buffer[40];
memcpy(buffer,packet,packet_length);
//if(memcmp(&packet_in[0],&packet[0],packet_length))
{
debug("C: %02X P:", option);
for(uint8_t i=0;i<packet_length;i++)
debug(" %02X",packet[i]);
debugln("");
memcpy(packet_in,packet,packet_length);
}
/*//realign bits
for(uint8_t i=0; i<packet_length; i++)
buffer[i]=buffer[i+2];
//for(uint8_t i=0; i<packet_length; i++)
// buffer[i]=(buffer[i]<<4)+(buffer[i+1]>>4);
//check for validity and decode
memset(packet_in,0,packet_length);
for(uint8_t i=0; i<packet_length-2; i++)
{
for(uint8_t j=0;j<2;j++)
{
packet_in[i>>2] >>= 1;
if( (buffer[i]&0xC0) == 0xC0 && (buffer[i]&0x30) == 0x00 )
packet_in[i>>2] |= 0x80;
else if( (buffer[i]&0xC0) == 0x00 && (buffer[i]&0x30) == 0x30 )
packet_in[i>>2] |= 0x00;
else
ok=false; // error
buffer[i] <<= 4;
}
}
if(ok)
{
debug("P:(%02X,%02X):",packet[0],packet[1]);
for(uint8_t i=0;i<packet_length/4;i++)
debug(" %02X",packet_in[i]);
debugln("");
memcpy(packet_in,packet,packet_length);
}
}*/
/*crc=0;
for (uint8_t i = 1; i < 12; ++i)
crc16_update( packet[i], 8);
if(packet[12]==((crc>>8)&0xFF) && packet[13]==(crc&0xFF))
if(memcmp(&packet_in[1],&packet[1],packet_length-1))
{
debug("P:");
for(uint8_t i=0;i<packet_length;i++)
debug(" %02X",packet[i]);
debug(" CRC: %04X",crc);
debugln("");
debug("P(%02X):",packet[0]);
for(uint8_t i=1;i<packet_length-2;i++)
debug(" %02X",((bit_reverse(packet[i])<<1)|(bit_reverse(packet[i-1])>>7))&0xFF);
debugln("");
memcpy(packet_in,packet,packet_length);
}*/
}
// restart RX mode
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX)); // _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) |
}
XN297Dump_overflow();
if(old_option != option)
{
NRF24L01_WriteReg(NRF24L01_05_RF_CH, option); //hopping_frequency_no);
old_option = option;
}
}
}
else if(sub_protocol == XN297DUMP_CC2500)
{
#if defined (CC2500_INSTALLED)
if(phase==0)
{
address_length=5;
switch(RX_num)
{
case 0:
memcpy(rx_tx_addr, (uint8_t *)"\xAE\xD2\x71\x79\x46", address_length);
break;
case 1:
memcpy(rx_tx_addr, (uint8_t *)"\x5D\xA4\xE2\xF2\x8C", address_length);
break;
case 2:
memcpy(rx_tx_addr, (uint8_t *)"\xBB\x49\xC5\xE5\x18", address_length);
break;
case 3:
memcpy(rx_tx_addr, (uint8_t *)"\x76\x93\x8B\xCA\x30", address_length);
break;
case 4:
memcpy(rx_tx_addr, (uint8_t *)"\xED\x27\x17\x94\x61", address_length);
break;
case 5:
memcpy(rx_tx_addr, (uint8_t *)"\xDA\x4E\x2F\x28\xC2", address_length);
break;
case 6:
memcpy(rx_tx_addr, (uint8_t *)"\xAB\xB4\x9C\x5E\x51", address_length);
break;
case 7:
memcpy(rx_tx_addr, (uint8_t *)"\x57\x69\x38\xBC\xA3", address_length);
break;
}
packet_length=38;
hopping_frequency_no=54; //bind 30, normal 54
debugln("CC2500 dump, len=%d, rf=%d, address length=%d, bitrate=250K",packet_length,hopping_frequency_no,address_length);
//Config CC2500
CC2500_250K_Init();
CC2500_SetFreqOffset();
CC2500_WriteReg(CC2500_04_SYNC1, rx_tx_addr[0]); // Sync word, high byte
CC2500_WriteReg(CC2500_05_SYNC0, rx_tx_addr[1]); // Sync word, low byte
CC2500_WriteReg(CC2500_09_ADDR, rx_tx_addr[2]); // Set addr
CC2500_WriteReg(CC2500_12_MDMCFG2, 0x12); // Modem Configuration, GFSK, 16/16 Sync Word TX&RX
CC2500_WriteReg(CC2500_06_PKTLEN, packet_length); // Packet len
//2.4001GHz: offfset of 100KHz
CC2500_WriteReg(CC2500_0D_FREQ2, 0x5C); // Frequency Control Word, High Byte
CC2500_WriteReg(CC2500_0E_FREQ1, 0x4F); // Frequency Control Word, Middle Byte
CC2500_WriteReg(CC2500_0F_FREQ0, 0xC1); // Frequency Control Word, Low Byte
CC2500_250K_RFChannel(hopping_frequency_no);
CC2500_SetTxRxMode(RX_EN);
CC2500_Strobe(CC2500_SFRX);
CC2500_Strobe(CC2500_SRX);
phase++;
}
else
{
CC2500_SetFreqOffset();
if((CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F) == packet_length + 2) // 2 = RSSI + LQI
{ // RX fifo data ready
//debugln("f_off=%02X", CC2500_ReadReg(0x32 | CC2500_READ_BURST));
CC2500_ReadData(packet, packet_length+2);
bool ok=true;
//filter address
if(rx_tx_addr[2]!=packet[0] || rx_tx_addr[3]!=packet[1] || rx_tx_addr[4]!=packet[2] )
ok=false;
//filter constants
if(RX_num == 0 && ok)
{
if (packet[3] != 0x10 || (packet[4] & 0xFC) != 0x54 || packet[5] != 0x64)
ok=false;
else if(packet[6] != 0x10 && packet[6] != 0x25)
ok=false;
else if(memcmp(&packet[9],"\xC6\xE7\x50\x02\xAA\x49",6)!=0)
ok=false;
}
else if(RX_num == 4 && ok)
{
if (packet[3] != 0x05 || (packet[4] & 0xCF) != 0x46)
ok=false;
else if(packet[5] != 0x41 && packet[5] != 0x42)
ok=false;
else if((packet[6]&0xF0) != 0x50 && (packet[6]&0xF0) != 0x00)
ok=false;
else if((packet[8]&0x0F) != 0x0C)
ok=false;
else if(memcmp(&packet[9],"\x6E\x75\x00\x2A\xA4\x94\xA4\x6F",8)!=0)
ok=false;
}
if(ok)
{
//uint8_t buffer[100];
//memcpy(buffer,packet,packet_length);
//if(memcmp(&packet_in[0],&packet[0],packet_length))
{
debug("P:");
for(uint8_t i=0;i<packet_length;i++)
debug(" %02X",packet[i]);
debugln("");
memcpy(packet_in,packet,packet_length);
}
}
CC2500_SetTxRxMode(TXRX_OFF);
CC2500_SetTxRxMode(RX_EN);
CC2500_Strobe(CC2500_SFRX);
CC2500_Strobe(CC2500_SRX);
}
}
#endif
}
else if(sub_protocol == XN297DUMP_XN297)
{
if(phase==0)
{
address_length=5;
memcpy(rx_tx_addr, (uint8_t *)"\x00\x00\x00\x00\x00", address_length); // bind \x7E\xB8\x63\xA9
packet_length=9;
hopping_frequency_no=0x30;
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTXAddr(rx_tx_addr, address_length);
XN297_SetRXAddr(rx_tx_addr, packet_length);
XN297_Hopping(option);
old_option = option;
XN297_SetTxRxMode(RX_EN);
debugln("XN297 dump, len=%d, rf=%d, address length=%d",packet_length,option,address_length); //hopping_frequency_no,address_length);
phase = 1;
}
else
{
bool rx = XN297_IsRX(); // Needed for the NRF24L01 since otherwise the bit gets cleared
if(rx)
{ // RX fifo data ready
XN297_SetTxRxMode(TXRX_OFF);
XN297Dump_overflow();
uint16_t timeL=TCNT1;
if(TIMER2_BASE->SR & TIMER_SR_UIF)
{//timer just rolled over...
XN297Dump_overflow();
timeL=0;
}
time=(timeH<<16)+timeL-time;
debug("RX: %5luus ", time>>1);
time=(timeH<<16)+timeL;
if(XN297_ReadPayload(packet_in, packet_length))
{
debug("OK:");
for(uint8_t i=0;i<packet_length;i++)
debug(" %02X",packet_in[i]);
}
else // Bad packet
debug(" NOK");
debugln("");
// restart RX mode
XN297_SetTxRxMode(RX_EN);
}
XN297Dump_overflow();
if(old_option != option)
{
debugln("C=%d(%02X)",option,option);
XN297_Hopping(option);
old_option = option;
}
}
}
scan_counter++;
if(IS_RX_FLAG_on) // Let the radio update the protocol
{
if(Update_All()) return 10000; // New protocol selected
if(prev_option!=option && sub_protocol<XN297DUMP_AUTO)
{ // option has changed
hopping_frequency_no=option;
prev_option=option;
}
}
XN297Dump_overflow();
}
return 100;
}
void XN297Dump_init(void)
{
BIND_DONE;
if(sub_protocol<XN297DUMP_AUTO)
bitrate=sub_protocol;
else
bitrate=0;
address_length=RX_num;
if(address_length<3||address_length>5)
address_length=5; //default
XN297Dump_RF_init();
scan_counter=0;
rf_ch_num=0xFF;
prev_option=option^0x55;
phase=0; // init
}
#endif