Pascal Langer 4a626eaf14 Change XN297 emulation layer
Loads of protocols have been touched by this change. Some testing has been done but please test on all your models.
The XN297 emulation selects in this order:
 - the CC2500 if it is available and bitrate=250K. Configure the option field automatically for RF tune.
 - the NRF for all bitrates if it is available
 - if NRF is not available and bitrate=1M then an invalid protocol is sent automatically to the radio.
CC2500 @250K can now receive normal and enhanced payloads.
OMP protocol supports telemetry on CC2500 and is also for NRF only modules including telemetry.
Separation of E016H (new protocol) from E01X due to different structure.
MJXQ, MT99XX, Q303 and XK: some sub protocols available on CC2500 only.
2021-03-17 17:05:42 +01:00

551 lines
16 KiB
C++

#if defined(CC2500_INSTALLED) || defined(NRF24L01_INSTALLED)
#include "iface_xn297.h"
bool xn297_scramble_enabled, xn297_crc, xn297_bitrate, xn297_rf;
uint8_t xn297_addr_len, xn297_rx_packet_len;
uint8_t xn297_tx_addr[5], xn297_rx_addr[5];
// xn297 address / pcf / payload scramble table
const uint8_t xn297_scramble[] = {
0xE3, 0xB1, 0x4B, 0xEA, 0x85, 0xBC, 0xE5, 0x66,
0x0D, 0xAE, 0x8C, 0x88, 0x12, 0x69, 0xEE, 0x1F,
0xC7, 0x62, 0x97, 0xD5, 0x0B, 0x79, 0xCA, 0xCC,
0x1B, 0x5D, 0x19, 0x10, 0x24, 0xD3, 0xDC, 0x3F,
0x8E, 0xC5, 0x2F, 0xAA, 0x16, 0xF3, 0x95 };
// scrambled, standard mode crc xorout table
const uint16_t PROGMEM xn297_crc_xorout_scrambled[] = {
0x0000, 0x3448, 0x9BA7, 0x8BBB, 0x85E1, 0x3E8C,
0x451E, 0x18E6, 0x6B24, 0xE7AB, 0x3828, 0x814B,
0xD461, 0xF494, 0x2503, 0x691D, 0xFE8B, 0x9BA7,
0x8B17, 0x2920, 0x8B5F, 0x61B1, 0xD391, 0x7401,
0x2138, 0x129F, 0xB3A0, 0x2988, 0x23CA, 0xC0CB,
0x0C6C, 0xB329, 0xA0A1, 0x0A16, 0xA9D0 };
// unscrambled, standard mode crc xorout table
const uint16_t PROGMEM xn297_crc_xorout[] = {
0x0000, 0x3D5F, 0xA6F1, 0x3A23, 0xAA16, 0x1CAF,
0x62B2, 0xE0EB, 0x0821, 0xBE07, 0x5F1A, 0xAF15,
0x4F0A, 0xAD24, 0x5E48, 0xED34, 0x068C, 0xF2C9,
0x1852, 0xDF36, 0x129D, 0xB17C, 0xD5F5, 0x70D7,
0xB798, 0x5133, 0x67DB, 0xD94E, 0x0A5B, 0xE445,
0xE6A5, 0x26E7, 0xBDAB, 0xC379, 0x8E20 };
// scrambled enhanced mode crc xorout table
const uint16_t PROGMEM xn297_crc_xorout_scrambled_enhanced[] = {
0x0000, 0x7EBF, 0x3ECE, 0x07A4, 0xCA52, 0x343B,
0x53F8, 0x8CD0, 0x9EAC, 0xD0C0, 0x150D, 0x5186,
0xD251, 0xA46F, 0x8435, 0xFA2E, 0x7EBD, 0x3C7D,
0x94E0, 0x3D5F, 0xA685, 0x4E47, 0xF045, 0xB483,
0x7A1F, 0xDEA2, 0x9642, 0xBF4B, 0x032F, 0x01D2,
0xDC86, 0x92A5, 0x183A, 0xB760, 0xA953 };
// unscrambled enhanced mode crc xorout table
// unused so far
#ifdef XN297DUMP_NRF24L01_INO
const uint16_t xn297_crc_xorout_enhanced[] = {
0x0000, 0x8BE6, 0xD8EC, 0xB87A, 0x42DC, 0xAA89,
0x83AF, 0x10E4, 0xE83E, 0x5C29, 0xAC76, 0x1C69,
0xA4B2, 0x5961, 0xB4D3, 0x2A50, 0xCB27, 0x5128,
0x7CDB, 0x7A14, 0xD5D2, 0x57D7, 0xE31D, 0xCE42,
0x648D, 0xBF2D, 0x653B, 0x190C, 0x9117, 0x9A97,
0xABFC, 0xE68E, 0x0DE7, 0x28A2, 0x1965 };
#endif
static bool __attribute__((unused)) XN297_Configure(bool crc_en, bool scramble_en, bool bitrate)
{
xn297_crc = crc_en;
xn297_scramble_enabled = scramble_en;
xn297_bitrate = bitrate;
xn297_rf = XN297_NRF;
#if defined(NRF24L01_INSTALLED) and defined(CC2500_INSTALLED)
if(bitrate == XN297_1M)
xn297_rf = XN297_NRF; // Use NRF24L01
else
xn297_rf = XN297_CC2500; // Use CC2500
#elif defined(NRF24L01_INSTALLED) and not defined(CC2500_INSTALLED)
xn297_rf = XN297_NRF; // Use NRF24L01
#else //CC2500 only
xn297_rf = XN297_CC2500; // Use CC2500
if(bitrate == XN297_1M)
{
xn297_rf = XN297_NRF; // Use NRF24L01 which does not exist, nothing will happen...
SUB_PROTO_INVALID;
return false; // Can't do...
}
#endif
#if defined(NRF24L01_INSTALLED)
if(xn297_rf == XN297_NRF)
{
debugln("Using NRF");
rf_switch(SW_NRF);
NRF24L01_Initialize();
if(bitrate == XN297_250K)
NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250Kbps
}
#endif
#if defined(CC2500_INSTALLED)
if(xn297_rf == XN297_CC2500)
{
debugln("Using CC2500");
rf_switch(SW_CC2500);
CC2500_250K_Init();
option_override = 2; // OPTION_RFTUNE
}
#endif
return true;
}
static void __attribute__((unused)) XN297_SetTXAddr(const uint8_t* addr, uint8_t len)
{
if (len > 5) len = 5;
if (len < 3) len = 3;
xn297_addr_len = len;
memcpy(xn297_tx_addr, addr, len);
#ifdef NRF24L01_INSTALLED
if(xn297_rf == XN297_NRF)
{
uint8_t buf[] = { 0x55, 0x0F, 0x71, 0x0C, 0x00 }; // bytes for XN297 preamble 0xC710F55 (28 bit)
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, len-2);
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, xn297_addr_len == 3 ? buf+1 : buf, 5);
}
#endif
};
static void __attribute__((unused)) XN297_SetRXAddr(const uint8_t* addr, uint8_t rx_packet_len)
{
//Scramble address
for (uint8_t i = 0; i < xn297_addr_len; ++i)
{
xn297_rx_addr[i] = addr[i];
if(xn297_scramble_enabled)
xn297_rx_addr[i] ^= xn297_scramble[xn297_addr_len-i-1];
}
if(xn297_crc)
rx_packet_len += 2; // Include CRC
rx_packet_len += 2; // Include pcf, will this be a problem timing wise even if not enhanced?
#ifdef NRF24L01_INSTALLED
if(xn297_rf == XN297_NRF)
{
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, xn297_rx_addr, xn297_addr_len);
if(rx_packet_len >= 32)
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 32);
else
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, rx_packet_len);
}
#endif
#ifdef CC2500_INSTALLED
if(xn297_rf == XN297_CC2500)
{// TX: Sync1, Sync0, Address
CC2500_WriteReg(CC2500_04_SYNC1, xn297_rx_addr[xn297_addr_len-1]); // Sync word, high byte
CC2500_WriteReg(CC2500_05_SYNC0, xn297_rx_addr[xn297_addr_len-2]); // Sync word, low byte
CC2500_WriteReg(CC2500_09_ADDR, xn297_rx_addr[xn297_addr_len-3]); // Address
rx_packet_len += 1 + xn297_addr_len - 3; // The Address field above will be in the payload then the end of the XN297 address
}
#endif
xn297_rx_packet_len = rx_packet_len;
}
static void __attribute__((unused)) XN297_SetTxRxMode(enum TXRX_State mode)
{
static enum TXRX_State cur_mode=TXRX_OFF;
#ifdef NRF24L01_INSTALLED
if(xn297_rf == XN297_NRF)
{
NRF24L01_WriteReg(NRF24L01_07_STATUS, (1 << NRF24L01_07_RX_DR) //reset the flag(s)
| (1 << NRF24L01_07_TX_DS)
| (1 << NRF24L01_07_MAX_RT));
if(mode==TXRX_OFF)
{
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0); //PowerDown
NRF_CE_off;
return;
}
NRF_CE_off;
if(mode == TX_EN)
{
NRF24L01_FlushTx();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 1 << NRF24L01_00_PWR_UP);
}
else
{
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (1 << NRF24L01_00_PWR_UP)
| (1 << NRF24L01_00_PRIM_RX)); // RX
}
if(mode != cur_mode)
{
//delayMicroseconds(130);
cur_mode=mode;
}
NRF_CE_on;
}
#endif
#ifdef CC2500_INSTALLED
if(xn297_rf == XN297_CC2500)
{
if(mode != cur_mode)
{
CC2500_SetTxRxMode(mode);
if(mode == RX_EN)
{
CC2500_WriteReg(CC2500_12_MDMCFG2, 0x12); // Modem Configuration, GFSK, 16/16 Sync Word TX&RX
CC2500_WriteReg(CC2500_06_PKTLEN, xn297_rx_packet_len); // Packet len
CC2500_Strobe(CC2500_SFRX);
CC2500_Strobe(CC2500_SRX);
}
else
CC2500_WriteReg(CC2500_12_MDMCFG2, 0x10); // Modem Configuration, GFSK, no preambule and no sync word
cur_mode=mode;
}
}
#endif
}
static void __attribute__((unused)) XN297_SendPayload(uint8_t* msg, uint8_t len)
{
#ifdef NRF24L01_INSTALLED
if(xn297_rf == XN297_NRF)
{
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
NRF24L01_WritePayload(msg, len);
}
#endif
#ifdef CC2500_INSTALLED
if(xn297_rf == XN297_CC2500)
{
// stop TX/RX
CC2500_Strobe(CC2500_SIDLE);
// flush tx FIFO
CC2500_Strobe(CC2500_SFTX);
// packet length
CC2500_WriteReg(CC2500_06_PKTLEN, len + 4); // Packet len, fix packet len
// xn297L preamble
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, (uint8_t*)"\x0C\x71\x0F\x55", 4);
// xn297 packet
CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, msg, len);
// transmit
CC2500_Strobe(CC2500_STX);
}
#endif
}
static void __attribute__((unused)) XN297_WritePayload(uint8_t* msg, uint8_t len)
{
uint8_t buf[32];
uint8_t last = 0;
if (xn297_rf == XN297_NRF && xn297_addr_len < 4)
{ // If address length (which is defined by receiver address length) is less than 4 the TX address can't fit the preamble, so the last byte goes here
buf[last++] = 0x55;
}
// address
for (uint8_t i = 0; i < xn297_addr_len; ++i)
{
buf[last] = xn297_tx_addr[xn297_addr_len-i-1];
if(xn297_scramble_enabled)
buf[last] ^= xn297_scramble[i];
last++;
}
// payload
for (uint8_t i = 0; i < len; ++i)
{
// bit-reverse bytes in packet
buf[last] = bit_reverse(msg[i]);
if(xn297_scramble_enabled)
buf[last] ^= xn297_scramble[xn297_addr_len+i];
last++;
}
// crc
if (xn297_crc)
{
uint8_t offset = xn297_addr_len < 4 ? 1 : 0;
crc = 0xb5d2;
for (uint8_t i = offset; i < last; ++i)
crc16_update( buf[i], 8);
if(xn297_scramble_enabled)
crc ^= pgm_read_word(&xn297_crc_xorout_scrambled[xn297_addr_len - 3 + len]);
else
crc ^= pgm_read_word(&xn297_crc_xorout[xn297_addr_len - 3 + len]);
buf[last++] = crc >> 8;
buf[last++] = crc & 0xff;
}
// send packet
XN297_SendPayload(buf, last);
}
static void __attribute__((unused)) XN297_WriteEnhancedPayload(uint8_t* msg, uint8_t len, uint8_t noack)
{
uint8_t buf[32];
uint8_t scramble_index=0;
uint8_t last = 0;
static uint8_t pid=0;
if (xn297_rf == XN297_NRF && xn297_addr_len < 4)
{ // If address length (which is defined by receiver address length) is less than 4 the TX address can't fit the preamble, so the last byte goes here
buf[last++] = 0x55;
}
// address
for (uint8_t i = 0; i < xn297_addr_len; ++i)
{
buf[last] = xn297_tx_addr[xn297_addr_len-i-1];
if(xn297_scramble_enabled)
buf[last] ^= xn297_scramble[scramble_index++];
last++;
}
// pcf
buf[last] = (len << 1) | (pid>>1);
if(xn297_scramble_enabled)
buf[last] ^= xn297_scramble[scramble_index++];
last++;
buf[last] = (pid << 7) | (noack << 6);
// payload
buf[last]|= bit_reverse(msg[0]) >> 2; // first 6 bit of payload
if(xn297_scramble_enabled)
buf[last] ^= xn297_scramble[scramble_index++];
for (uint8_t i = 0; i < len-1; ++i)
{
last++;
buf[last] = (bit_reverse(msg[i]) << 6) | (bit_reverse(msg[i+1]) >> 2);
if(xn297_scramble_enabled)
buf[last] ^= xn297_scramble[scramble_index++];
}
last++;
buf[last] = bit_reverse(msg[len-1]) << 6; // last 2 bit of payload
if(xn297_scramble_enabled)
buf[last] ^= xn297_scramble[scramble_index++] & 0xc0;
// crc
if (xn297_crc)
{
uint8_t offset = xn297_addr_len < 4 ? 1 : 0;
crc = 0xb5d2;
for (uint8_t i = offset; i < last; ++i)
crc16_update( buf[i], 8);
crc16_update( buf[last] & 0xc0, 2);
if (xn297_scramble_enabled)
crc ^= pgm_read_word(&xn297_crc_xorout_scrambled_enhanced[xn297_addr_len-3+len]);
//else
// crc ^= pgm_read_word(&xn297_crc_xorout_enhanced[xn297_addr_len - 3 + len]);
buf[last++] |= (crc >> 8) >> 2;
buf[last++] = ((crc >> 8) << 6) | ((crc & 0xff) >> 2);
buf[last++] = (crc & 0xff) << 6;
}
pid++;
if(pid>3)
pid=0;
// send packet
XN297_SendPayload(buf, last);
}
static bool __attribute__((unused)) XN297_IsRX()
{
#ifdef NRF24L01_INSTALLED
if(xn297_rf == XN297_NRF)
return (NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR));
#endif
#ifdef CC2500_INSTALLED
if(xn297_rf == XN297_CC2500)
{
if((CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F) != xn297_rx_packet_len + 2) // 2 = RSSI + LQI
return false; // Buffer does not contain the expected number of bytes
// Check the address
uint8_t buf[3];
CC2500_ReadData(buf, xn297_addr_len-3 + 1);
for(uint8_t i=0; i < xn297_addr_len-3 + 1; i++)
if(buf[i] != xn297_rx_addr[xn297_addr_len-3 - i])
return false; // Bad address
return true; // Address is correct
}
#endif
return false;
}
static void __attribute__((unused)) XN297_ReceivePayload(uint8_t* msg, uint8_t len)
{
if (xn297_crc)
len += 2; // Include CRC
#ifdef NRF24L01_INSTALLED
if(xn297_rf == XN297_NRF)
NRF24L01_ReadPayload(msg, len); // Read payload and CRC
#endif
#ifdef CC2500_INSTALLED
if(xn297_rf == XN297_CC2500)
CC2500_ReadData(msg, len);
#endif
}
static bool __attribute__((unused)) XN297_ReadPayload(uint8_t* msg, uint8_t len)
{ //!!! Don't forget if using CRC to do a +2 on the received packet length (NRF24L01_11_RX_PW_Px !!! or CC2500_06_PKTLEN)
uint8_t buf[32];
// Read payload
XN297_ReceivePayload(buf, len);
// Decode payload
for(uint8_t i=0; i<len; i++)
{
uint8_t b_in=buf[i];
if(xn297_scramble_enabled)
b_in ^= xn297_scramble[i+xn297_addr_len];
msg[i] = bit_reverse(b_in);
}
if (!xn297_crc)
return true; // No CRC so OK by default...
// Calculate CRC
crc = 0xb5d2;
//process address
for (uint8_t i = 0; i < xn297_addr_len; ++i)
crc16_update( xn297_rx_addr[xn297_addr_len-i-1], 8);
//process payload
for (uint8_t i = 0; i < len; ++i)
crc16_update( buf[i], 8);
//xorout
if(xn297_scramble_enabled)
crc ^= pgm_read_word(&xn297_crc_xorout_scrambled[xn297_addr_len - 3 + len]);
else
crc ^= pgm_read_word(&xn297_crc_xorout[xn297_addr_len - 3 + len]);
//test
if( (crc >> 8) == buf[len] && (crc & 0xff) == buf[len+1])
return true; // CRC OK
return false; // CRC NOK
}
static uint8_t __attribute__((unused)) XN297_ReadEnhancedPayload(uint8_t* msg, uint8_t len)
{ //!!! Don't forget do a +2 and if using CRC add +4 on any of the used NRF24L01_11_RX_PW_Px !!!
uint8_t buffer[32];
uint8_t pcf_size; // pcf payload size
// Read payload
XN297_ReceivePayload(buffer, len+2); // Read pcf + payload + CRC
// Decode payload
pcf_size = buffer[0];
if(xn297_scramble_enabled)
pcf_size ^= xn297_scramble[xn297_addr_len];
pcf_size = pcf_size >> 1;
for(int i=0; i<len; i++)
{
msg[i] = bit_reverse((buffer[i+1] << 2) | (buffer[i+2] >> 6));
if(xn297_scramble_enabled)
msg[i] ^= bit_reverse((xn297_scramble[xn297_addr_len+i+1] << 2) |
(xn297_scramble[xn297_addr_len+i+2] >> 6));
}
if (!xn297_crc)
return pcf_size; // No CRC so OK by default...
// Calculate CRC
crc = 0xb5d2;
//process address
for (uint8_t i = 0; i < xn297_addr_len; ++i)
crc16_update( xn297_rx_addr[xn297_addr_len-i-1], 8);
//process payload
for (uint8_t i = 0; i < len+1; ++i)
crc16_update( buffer[i], 8);
crc16_update( buffer[len+1] & 0xc0, 2);
//xorout
if (xn297_scramble_enabled)
crc ^= pgm_read_word(&xn297_crc_xorout_scrambled_enhanced[xn297_addr_len-3+len]);
#ifdef XN297DUMP_NRF24L01_INO
else
crc ^= pgm_read_word(&xn297_crc_xorout_enhanced[xn297_addr_len - 3 + len]);
#endif
uint16_t crcxored=(buffer[len+1]<<10)|(buffer[len+2]<<2)|(buffer[len+3]>>6) ;
if( crc == crcxored)
return pcf_size; // CRC OK
return 0; // CRC NOK
}
static bool __attribute__((unused)) XN297_IsPacketSent()
{
#ifdef NRF24L01_INSTALLED
if(xn297_rf == XN297_NRF)
return (NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_TX_DS));
#endif
#ifdef CC2500_INSTALLED
if(xn297_rf == XN297_CC2500)
return (CC2500_ReadReg(CC2500_35_MARCSTATE | CC2500_READ_BURST) != 0x13);
#endif
return true; // packet sent to not block
}
static void __attribute__((unused)) XN297_HoppingCalib(uint8_t num_freq)
{ //calibrate hopping frequencies
#ifdef NRF24L01_INSTALLED
(void)num_freq;
#endif
#ifdef CC2500_INSTALLED
if(xn297_rf == XN297_CC2500)
CC2500_250K_HoppingCalib(num_freq);
#endif
}
static void __attribute__((unused)) XN297_Hopping(uint8_t index)
{
#ifdef NRF24L01_INSTALLED
if(xn297_rf == XN297_NRF)
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[index]);
#endif
#ifdef CC2500_INSTALLED
if(xn297_rf == XN297_CC2500)
CC2500_250K_Hopping(index);
#endif
}
static void __attribute__((unused)) XN297_RFChannel(uint8_t number)
{ //change channel
#ifdef NRF24L01_INSTALLED
if(xn297_rf == XN297_NRF)
NRF24L01_WriteReg(NRF24L01_05_RF_CH, number);
#endif
#ifdef CC2500_INSTALLED
if(xn297_rf == XN297_CC2500)
CC2500_250K_RFChannel(number);
#endif
}
static void __attribute__((unused)) XN297_SetPower()
{
#ifdef NRF24L01_INSTALLED
if(xn297_rf == XN297_NRF)
NRF24L01_SetPower();
#endif
#ifdef CC2500_INSTALLED
if(xn297_rf == XN297_CC2500)
CC2500_SetPower();
#endif
}
static void __attribute__((unused)) XN297_SetFreqOffset()
{ // Frequency offset
#ifdef CC2500_INSTALLED
if(xn297_rf == XN297_CC2500)
CC2500_SetFreqOffset();
#endif
}
// End of XN297 emulation
#endif