mirror of
https://github.com/pascallanger/DIY-Multiprotocol-TX-Module.git
synced 2026-10-30 21:44:24 +00:00
* 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.
976 lines
29 KiB
Arduino
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
|