From 05fb8bc742dca0dd86b6ad0e938a3c213eb92784 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 26 Feb 2016 19:02:26 +0100 Subject: [PATCH] Added Shenqi protocol and LT8910 emulation layer --- Multiprotocol/Multiprotocol.ino | 10 +- Multiprotocol/NRF24l01_SPI.ino | 193 ++++++++++++++++++++++++++++++ Multiprotocol/SHENQI_nrf24l01.ino | 108 +++++++++++++++++ Multiprotocol/_Config.h | 3 + Multiprotocol/multiprotocol.h | 4 +- 5 files changed, 315 insertions(+), 3 deletions(-) create mode 100644 Multiprotocol/SHENQI_nrf24l01.ino diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 802c8c6..f7393da 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -146,7 +146,7 @@ void setup() // after this mode_select will be one of {0000, 0001, ..., 1111} mode_select=0x0F - ( ( (PINB>>2)&0x07 ) | ( (PINC<<3)&0x08) );//encoder dip switches 1,2,4,8=>B2,B3,B4,C0 //********************************** -//mode_select=14; // here to test PPM +//mode_select=1; // here to test PPM //********************************** // Update LED @@ -431,6 +431,12 @@ static void protocol_init() next_callback=initMJXQ(); remote_callback = MJXQ_callback; break; +#endif +#if defined(SHENQI_NRF24L01_INO) + case MODE_SHENQI: + next_callback=initSHENQI(); + remote_callback = SHENQI_callback; + break; #endif } @@ -513,7 +519,7 @@ static void module_reset() case MODE_DEVO: CYRF_Reset(); break; - default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY, MODE_MT99XX, MODE_MJXQ + default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY, MODE_MT99XX, MODE_MJXQ, MODE_SHENQI NRF24L01_Reset(); break; } diff --git a/Multiprotocol/NRF24l01_SPI.ino b/Multiprotocol/NRF24l01_SPI.ino index df596e1..f95e86f 100644 --- a/Multiprotocol/NRF24l01_SPI.ino +++ b/Multiprotocol/NRF24l01_SPI.ino @@ -409,3 +409,196 @@ void XN297_ReadPayload(uint8_t* msg, uint8_t len) } // End of XN297 emulation + +/////////////// +// LT8910 emulation layer +uint8_t LT8910_buffer[64]; +uint8_t LT8910_buffer_start; +uint16_t LT8910_buffer_overhead_bits; +uint8_t LT8910_addr[8]; +uint8_t LT8910_addr_size; +uint8_t LT8910_Preamble_Len; +uint8_t LT8910_Tailer_Len; +uint8_t LT8910_CRC_Initial_Data; +uint8_t LT8910_Flags; +#define LT8910_CRC_ON 6 +#define LT8910_SCRAMBLE_ON 5 +#define LT8910_PACKET_LENGTH_EN 4 +#define LT8910_DATA_PACKET_TYPE_1 3 +#define LT8910_DATA_PACKET_TYPE_0 2 +#define LT8910_FEC_TYPE_1 1 +#define LT8910_FEC_TYPE_0 0 + +void LT8910_Config(uint8_t preamble_len, uint8_t trailer_len, uint8_t flags, uint8_t crc_init) +{ + //Preamble 1 to 8 bytes + LT8910_Preamble_Len=preamble_len; + //Trailer 4 to 18 bits + LT8910_Tailer_Len=trailer_len; + //Flags + // CRC_ON: 1 on, 0 off + // SCRAMBLE_ON: 1 on, 0 off + // PACKET_LENGTH_EN: 1 1st byte of payload is payload size + // DATA_PACKET_TYPE: 00 NRZ, 01 Manchester, 10 8bit/10bit line code, 11 interleave data type + // FEC_TYPE: 00 No FEC, 01 FEC13, 10 FEC23, 11 reserved + LT8910_Flags=flags; + //CRC init constant + LT8910_CRC_Initial_Data=crc_init; +} + +void LT8910_SetChannel(uint8_t channel) +{ + NRF24L01_WriteReg(NRF24L01_05_RF_CH, channel +2); //NRF24L01 is 2400+channel but LT8900 is 2402+channel +} + +void LT8910_SetTxRxMode(enum TXRX_State mode) +{ + if(mode == TX_EN) + { + //Switch to TX + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_SetTxRxMode(TX_EN); + //Disable CRC + NRF24L01_WriteReg(NRF24L01_00_CONFIG, (1 << NRF24L01_00_PWR_UP)); + } + else + if (mode == RX_EN) + { + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only + NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 32); + //Switch to RX + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_FlushRx(); + NRF24L01_SetTxRxMode(RX_EN); + // Disable CRC + NRF24L01_WriteReg(NRF24L01_00_CONFIG, (1 << NRF24L01_00_PWR_UP) | (1 << NRF24L01_00_PRIM_RX) ); + } + else + NRF24L01_SetTxRxMode(TXRX_OFF); +} + +void LT8910_BuildOverhead() +{ + uint8_t pos; + + //Build overhead + //preamble + memset(LT8910_buffer,LT8910_addr[0]&0x01?0xAA:0x55,LT8910_Preamble_Len-1); + pos=LT8910_Preamble_Len-1; + //address + for(uint8_t i=0;i5?5:pos; +} + +void LT8910_SetAddress(uint8_t *address,uint8_t addr_size) +{ + uint8_t addr[5]; + + //Address size (SyncWord) 2 to 8 bytes, 16/32/48/64 bits + LT8910_addr_size=addr_size; + memcpy(LT8910_addr,address,LT8910_addr_size); + + //Build overhead + LT8910_BuildOverhead(); + + //Set NRF RX&TX address based on overhead content + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, LT8910_buffer_start-2); + for(uint8_t i=0;i>8)&0xFF; + } + //Check len + if(LT8910_Flags&_BV(LT8910_PACKET_LENGTH_EN)) + { + crc=crc16_update(crc,buffer[pos]); + if(bit_reverse(len)!=buffer[pos++]) + return 0; // wrong len... + } + //Decode message + for(i=0;i>8)&0xFF)) return 0; // wrong CRC... + if(buffer[pos]!=(crc&0xFF)) return 0; // wrong CRC... + } + //Everything ok + return 1; +} + +void LT8910_WritePayload(uint8_t* msg, uint8_t len) +{ + unsigned int crc=LT8910_CRC_Initial_Data,a,mask; + uint8_t i, pos=0,tmp, buffer[64], pos_final,shift; + //Add packet len + if(LT8910_Flags&_BV(LT8910_PACKET_LENGTH_EN)) + { + tmp=bit_reverse(len); + buffer[pos++]=tmp; + crc=crc16_update(crc,tmp); + } + //Add payload + for(i=0;i>8; + buffer[pos++]=crc; + } + //Shift everything to fit behind the trailer (4 to 18 bits) + shift=LT8910_buffer_overhead_bits&0x7; + pos_final=LT8910_buffer_overhead_bits/8; + mask=~(0xFF<<(8-shift)); + LT8910_buffer[pos_final+pos]=0xFF; + for(i=pos-1;i!=0xFF;i--) + { + a=buffer[i]<<(8-shift); + LT8910_buffer[pos_final+i]=(LT8910_buffer[pos_final+i]&mask>>8)|a>>8; + LT8910_buffer[pos_final+i+1]=(LT8910_buffer[pos_final+i+1]&mask)|a; + } + if(shift) + pos++; + //Send everything + NRF24L01_WritePayload(LT8910_buffer+LT8910_buffer_start,pos_final+pos-LT8910_buffer_start); +} +// End of LT8910 emulation diff --git a/Multiprotocol/SHENQI_nrf24l01.ino b/Multiprotocol/SHENQI_nrf24l01.ino new file mode 100644 index 0000000..18d5037 --- /dev/null +++ b/Multiprotocol/SHENQI_nrf24l01.ino @@ -0,0 +1,108 @@ +#if defined(SHENQI_NRF24L01_INO) + +#include "iface_nrf24l01.h" + +const uint8_t PROGMEM SHENQI_Freq[] = { + 50,50,20,60,30,40, + 10,30,40,20,60,10, + 50,20,50,40,10,60, + 30,30,60,10,40,50, + 20,10,60,20,50,30, + 40,40,30,50,20,60, + 10,10,20,30,40,50, + 60,60,50,40,30,20, + 10,60,10,50,30,40, + 20,10,40,30,60,20 }; + +void SHENQI_init() +{ + NRF24L01_Initialize(); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit + NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes + NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps + NRF24L01_SetPower(); + + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5 bytes rx/tx address + + LT8910_Config(4, 8, _BV(LT8910_CRC_ON)|_BV(LT8910_PACKET_LENGTH_EN), 0xAA); + LT8910_SetChannel(2); + LT8910_SetAddress((uint8_t *)"\x9A\x9A\x9A\x9A",4); + LT8910_SetTxRxMode(RX_EN); +} + +void SHENQI_send_packet() +{ + packet[0]=0x00; + if(packet_count==0) + { + uint8_t bind_addr[4]; + bind_addr[0]=0x9A; + bind_addr[1]=0x9A; + bind_addr[2]=rx_tx_addr[2]; + bind_addr[3]=rx_tx_addr[3]; + LT8910_SetAddress(bind_addr,4); + LT8910_SetChannel(2); + packet[1]=rx_tx_addr[1]; + packet[2]=rx_tx_addr[0]; + packet_period=2508; + } + else + { + LT8910_SetAddress(rx_tx_addr,4); + packet[1]=255-convert_channel_8b(RUDDER); + packet[2]=255-convert_channel_8b_scale(THROTTLE,0x60,0xA0); + uint8_t freq=pgm_read_byte_near(&SHENQI_Freq[hopping_frequency_no])+(rx_tx_addr[1]&0x0F); + LT8910_SetChannel(freq); + hopping_frequency_no++; + if(hopping_frequency_no==60) + hopping_frequency_no=0; + packet_period=1750; + } + // Send packet + 1 retransmit - not sure why but needed (not present on original TX...) + LT8910_WritePayload(packet,3); + while(NRF24L01_packet_ack()!=PKT_ACKED); + LT8910_WritePayload(packet,3); + + packet_count++; + if(packet_count==7) + { + packet_count=0; + packet_period=3000; + } + // Set power + NRF24L01_SetPower(); +} + +uint16_t SHENQI_callback() +{ + if(IS_BIND_DONE_on) + SHENQI_send_packet(); + else + { + if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR)) + { + if(LT8910_ReadPayload(packet, 3)) + { + BIND_DONE; + rx_tx_addr[3]=packet[1]; + rx_tx_addr[2]=packet[2]; + LT8910_SetTxRxMode(TX_EN); + packet_period=14000; + } + NRF24L01_FlushRx(); + } + } + return packet_period; +} + +uint16_t initSHENQI() +{ + BIND_IN_PROGRESS; // autobind protocol + SHENQI_init(); + hopping_frequency_no = 0; + packet_count=0; + packet_period=100; + return 1000; +} + +#endif \ No newline at end of file diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 090fe4e..46226bc 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -56,6 +56,7 @@ #define YD717_NRF24L01_INO #define MT99XX_NRF24L01_INO #define MJXQ_NRF24L01_INO + #define SHENQI_NRF24L01_INO #endif //Update this table to set which protocol and all associated settings are called for the corresponding dial number @@ -139,6 +140,8 @@ const PPM_Parameters PPM_prot[15]= { X600 X800 H26D + MODE_SHENQI + NONE RX_Num value between 0 and 15 diff --git a/Multiprotocol/multiprotocol.h b/Multiprotocol/multiprotocol.h index ec6e437..d5a51aa 100644 --- a/Multiprotocol/multiprotocol.h +++ b/Multiprotocol/multiprotocol.h @@ -44,7 +44,8 @@ enum PROTOCOLS MODE_FRSKYX = 15, // =>CC2500 MODE_ESKY = 16, // =>NRF24L01 MODE_MT99XX=17, // =>NRF24L01 - MODE_MJXQ=18 // =>NRF24L01 + MODE_MJXQ=18, // =>NRF24L01 + MODE_SHENQI=19 // =>NRF24L01 }; enum Flysky @@ -419,6 +420,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- ESky 16 MT99XX 17 MJXQ 18 + SHENQI 19 BindBit=> 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No