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