diff --git a/Multiprotocol/FQ777_nrf24l01.ino b/Multiprotocol/FQ777_nrf24l01.ino index 369812f..4978406 100644 --- a/Multiprotocol/FQ777_nrf24l01.ino +++ b/Multiprotocol/FQ777_nrf24l01.ino @@ -60,9 +60,9 @@ static void __attribute__((unused)) ssv_pack_dpl(uint8_t addr[], uint8_t pid, ui crc.val=0x3c18; for (i = 0; i < 7; ++i) - crc.val=crc16_update(crc.val,header[i]); + crc.val=crc16_update(crc.val,header[i],8); for (i = 0; i < *len; ++i) - crc.val=crc16_update(crc.val,payload[i]); + crc.val=crc16_update(crc.val,payload[i],8); // encode payload and crc // xor with this: diff --git a/Multiprotocol/GW008_nrf24l01.ino b/Multiprotocol/GW008_nrf24l01.ino new file mode 100644 index 0000000..4bedbed --- /dev/null +++ b/Multiprotocol/GW008_nrf24l01.ino @@ -0,0 +1,157 @@ +/* + 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 . + */ +// Compatible with Global Drone GW008 protocol. +// There are 3 versions of this small quad, this protocol is for the one with a XNS104 IC in the stock Tx and PAN159CY IC in the quad (SOCs with built-in xn297 compatible RF). +// The xn297 version is compatible with the CX10 protocol (green pcb). +// The LT8910 version is not supported yet. + +#if defined(GW008_NRF24L01_INO) + +#include "iface_nrf24l01.h" + +#define GW008_INITIAL_WAIT 500 +#define GW008_PACKET_PERIOD 2400 +#define GW008_RF_BIND_CHANNEL 2 +#define GW008_PAYLOAD_SIZE 15 + +enum { + GW008_BIND1, + GW008_BIND2, + GW008_DATA +}; + +static void __attribute__((unused)) send_packet(uint8_t bind) +{ + packet[0] = rx_tx_addr[0]; + if(bind) + { + packet[1] = 0x55; + packet[2] = hopping_frequency[0]; + packet[3] = hopping_frequency[1]; + packet[4] = hopping_frequency[2]; + packet[5] = hopping_frequency[3]; + memset(&packet[6], 0, 7); + packet[13] = 0xaa; + } + else + { + packet[1] = 0x01 | GET_FLAG(AUX1, 0x40); // flip + packet[2] = convert_channel_8b_scale(AILERON , 200, 0); // aileron + packet[3] = convert_channel_8b_scale(ELEVATOR, 0, 200); // elevator + packet[4] = convert_channel_8b_scale(RUDDER , 200, 0); // rudder + packet[5] = convert_channel_8b_scale(THROTTLE, 0, 200); // throttle + packet[6] = 0xaa; + packet[7] = 0x02; // max rate + packet[8] = 0x00; + packet[9] = 0x00; + packet[10]= 0x00; + packet[11]= 0x00; + packet[12]= 0x00; + packet[13]= rx_tx_addr[2]; + } + packet[14] = rx_tx_addr[1]; + + // Power on, TX mode, CRC enabled + XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP)); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? GW008_RF_BIND_CHANNEL : hopping_frequency[(hopping_frequency_no++)/2]); + hopping_frequency_no %= 8; + + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); + NRF24L01_FlushTx(); + XN297_WriteEnhancedPayload(packet, GW008_PAYLOAD_SIZE, 0, 0x3c7d); + + NRF24L01_SetPower(); // Set tx_power +} + +static void __attribute__((unused)) GW008_init() +{ + NRF24L01_Initialize(); + NRF24L01_SetTxRxMode(TX_EN); + XN297_SetTXAddr((uint8_t*)"\xcc\xcc\xcc\xcc\xcc", 5); + XN297_SetRXAddr((uint8_t*)"\xcc\xcc\xcc\xcc\xcc", 5); + NRF24L01_FlushTx(); + NRF24L01_FlushRx(); + 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_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); + NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, GW008_PAYLOAD_SIZE+2); // payload + 2 bytes for pcf + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); + NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits + NRF24L01_SetBitrate(NRF24L01_BR_1M); + NRF24L01_SetPower(); + NRF24L01_Activate(0x73); // Activate feature register + NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes + NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01); // Set feature bits on + NRF24L01_Activate(0x73); +} + +static void __attribute__((unused)) GW008_initialize_txid() +{ + uint32_t lfsr = random(0xfefefefe) + ((uint32_t)random(0xfefefefe) << 16); + for(uint8_t i=0; i<4; i++) + hopping_frequency[i] = 0x10 + ((lfsr >> (i*8)) % 0x37); +} + +uint16_t GW008_callback() +{ + switch(phase) + { + case GW008_BIND1: + if((NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR)) && // RX fifo data ready + XN297_ReadEnhancedPayload(packet, GW008_PAYLOAD_SIZE) == GW008_PAYLOAD_SIZE && // check payload size + packet[0] == rx_tx_addr[0] && packet[14] == rx_tx_addr[1]) // check tx id + { + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_SetTxRxMode(TX_EN); + rx_tx_addr[2] = packet[13]; + BIND_DONE; + phase = GW008_DATA; + } + else + { + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_SetTxRxMode(TX_EN); + send_packet(1); + phase = GW008_BIND2; + return 300; + } + break; + case GW008_BIND2: + // switch to RX mode + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_FlushRx(); + NRF24L01_SetTxRxMode(RX_EN); + XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) + | _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX)); + phase = GW008_BIND1; + return 5000; + break; + case GW008_DATA: + send_packet(0); + break; + } + return GW008_PACKET_PERIOD; +} + +uint16_t initGW008() +{ + GW008_initialize_txid(); + phase = GW008_BIND1; + GW008_init(); + hopping_frequency_no = 0; + return GW008_INITIAL_WAIT; +} + +#endif diff --git a/Multiprotocol/Multi.txt b/Multiprotocol/Multi.txt index b6f25a7..a52436b 100644 --- a/Multiprotocol/Multi.txt +++ b/Multiprotocol/Multi.txt @@ -29,3 +29,4 @@ 29,Q2X2,Q222,Q242,Q282 30,WK2x01,WK2801,WK2401,W6_5_1,W6_6_1,W6_HEL,W6_HEL_I 31,Q303,Q303,CX35,CX10D,CX10WD +32,GW008 \ No newline at end of file diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index ae25f32..2d87646 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 1 #define VERSION_REVISION 6 -#define VERSION_PATCH_LEVEL 17 +#define VERSION_PATCH_LEVEL 18 //****************** // Protocols //****************** @@ -57,6 +57,7 @@ enum PROTOCOLS MODE_Q2X2 = 29, // =>NRF24L01, extension of CX-10 protocol MODE_WK2x01 = 30, // =>CYRF6936 MODE_Q303 = 31, // =>NRF24L01 + MODE_GW008 = 32, // =>NRF24L01 }; enum Flysky @@ -478,6 +479,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- Q2X2 29 WK2x01 30 Q303 31 + GW008 32 BindBit=> 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 3cd32cc..ac0aafe 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -941,6 +941,12 @@ static void protocol_init() remote_callback = Q303_callback; break; #endif + #if defined(GW008_NRF24L01_INO) + case MODE_GW008: + next_callback=initGW008(); + remote_callback = GW008_callback; + break; + #endif #endif } } diff --git a/Multiprotocol/NRF24l01_SPI.ino b/Multiprotocol/NRF24l01_SPI.ino index 9906f29..32a12fc 100644 --- a/Multiprotocol/NRF24l01_SPI.ino +++ b/Multiprotocol/NRF24l01_SPI.ino @@ -282,10 +282,10 @@ static uint8_t bit_reverse(uint8_t b_in) } static const uint16_t polynomial = 0x1021; -static uint16_t crc16_update(uint16_t crc, uint8_t a) +static uint16_t crc16_update(uint16_t crc, uint8_t a, uint8_t bits) { crc ^= a << 8; - for (uint8_t i = 0; i < 8; ++i) + while(bits--) if (crc & 0x8000) crc = (crc << 1) ^ polynomial; else @@ -374,7 +374,7 @@ void XN297_WritePayload(uint8_t* msg, uint8_t len) uint8_t offset = xn297_addr_len < 4 ? 1 : 0; uint16_t crc = 0xb5d2; for (uint8_t i = offset; i < last; ++i) - crc = crc16_update(crc, buf[i]); + crc = crc16_update(crc, buf[i], 8); if(xn297_scramble_enabled) crc ^= pgm_read_word(&xn297_crc_xorout_scrambled[xn297_addr_len - 3 + len]); else @@ -385,6 +385,76 @@ void XN297_WritePayload(uint8_t* msg, uint8_t len) NRF24L01_WritePayload(buf, last); } + +void XN297_WriteEnhancedPayload(uint8_t* msg, uint8_t len, uint8_t noack, uint16_t crc_xorout) +{ + uint8_t packet[32]; + uint8_t scramble_index=0; + uint8_t last = 0; + static uint8_t pid=0; + + // address + if (xn297_addr_len < 4) + { + // If address length (which is defined by receive address length) + // is less than 4 the TX address can't fit the preamble, so the last + // byte goes here + packet[last++] = 0x55; + } + for (uint8_t i = 0; i < xn297_addr_len; ++i) + { + packet[last] = xn297_tx_addr[xn297_addr_len-i-1]; + if(xn297_scramble_enabled) + packet[last] ^= xn297_scramble[scramble_index++]; + last++; + } + + // pcf + packet[last] = (len << 1) | (pid>>1); + if(xn297_scramble_enabled) + packet[last] ^= xn297_scramble[scramble_index++]; + last++; + packet[last] = (pid << 7) | (noack << 6); + + // payload + packet[last]|= bit_reverse(msg[0]) >> 2; // first 6 bit of payload + if(xn297_scramble_enabled) + packet[last] ^= xn297_scramble[scramble_index++]; + + for (uint8_t i = 0; i < len-1; ++i) + { + last++; + packet[last] = (bit_reverse(msg[i]) << 6) | (bit_reverse(msg[i+1]) >> 2); + if(xn297_scramble_enabled) + packet[last] ^= xn297_scramble[scramble_index++]; + } + + last++; + packet[last] = bit_reverse(msg[len-1]) << 6; // last 2 bit of payload + if(xn297_scramble_enabled) + packet[last] ^= xn297_scramble[scramble_index++] & 0xc0; + + // crc + if (xn297_crc) + { + uint8_t offset = xn297_addr_len < 4 ? 1 : 0; + uint16_t crc = 0xb5d2; + for (uint8_t i = offset; i < last; ++i) + crc = crc16_update(crc, packet[i], 8); + crc = crc16_update(crc, packet[last] & 0xc0, 2); + crc ^= crc_xorout; + + packet[last++] |= (crc >> 8) >> 2; + packet[last++] = ((crc >> 8) << 6) | ((crc & 0xff) >> 2); + packet[last++] = (crc & 0xff) << 6; + } + NRF24L01_WritePayload(packet, last); + + pid++; + if(pid>3) + pid=0; +} + void XN297_ReadPayload(uint8_t* msg, uint8_t len) { // TODO: if xn297_crc==1, check CRC before filling *msg @@ -397,7 +467,26 @@ void XN297_ReadPayload(uint8_t* msg, uint8_t len) } } -// End of XN297 emulation +uint8_t XN297_ReadEnhancedPayload(uint8_t* msg, uint8_t len) +{ + uint8_t buffer[32]; + uint8_t pcf_size; // pcf payload size + NRF24L01_ReadPayload(buffer, len+2); // pcf + 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> 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)); + } + return pcf_size; +} + + // End of XN297 emulation /////////////// // LT8900 emulation layer @@ -531,14 +620,14 @@ uint8_t LT8900_ReadPayload(uint8_t* msg, uint8_t len) //Check len if(LT8900_Flags&_BV(LT8900_PACKET_LENGTH_EN)) { - crc=crc16_update(crc,buffer[pos]); + crc=crc16_update(crc,buffer[pos],8); if(bit_reverse(len)!=buffer[pos++]) return 0; // wrong len... } //Decode message for(i=0;i