GW008 protocol addition

Protocol number: 32
No sub_protocol
This commit is contained in:
pascallanger 2017-02-24 11:00:02 +01:00
parent bd64bdedc3
commit 548390b0d7
8 changed files with 277 additions and 19 deletions

View File

@ -60,9 +60,9 @@ static void __attribute__((unused)) ssv_pack_dpl(uint8_t addr[], uint8_t pid, ui
crc.val=0x3c18; crc.val=0x3c18;
for (i = 0; i < 7; ++i) 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) 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 // encode payload and crc
// xor with this: // xor with this:

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
// 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

View File

@ -29,3 +29,4 @@
29,Q2X2,Q222,Q242,Q282 29,Q2X2,Q222,Q242,Q282
30,WK2x01,WK2801,WK2401,W6_5_1,W6_6_1,W6_HEL,W6_HEL_I 30,WK2x01,WK2801,WK2401,W6_5_1,W6_6_1,W6_HEL,W6_HEL_I
31,Q303,Q303,CX35,CX10D,CX10WD 31,Q303,Q303,CX35,CX10D,CX10WD
32,GW008

View File

@ -19,7 +19,7 @@
#define VERSION_MAJOR 1 #define VERSION_MAJOR 1
#define VERSION_MINOR 1 #define VERSION_MINOR 1
#define VERSION_REVISION 6 #define VERSION_REVISION 6
#define VERSION_PATCH_LEVEL 17 #define VERSION_PATCH_LEVEL 18
//****************** //******************
// Protocols // Protocols
//****************** //******************
@ -57,6 +57,7 @@ enum PROTOCOLS
MODE_Q2X2 = 29, // =>NRF24L01, extension of CX-10 protocol MODE_Q2X2 = 29, // =>NRF24L01, extension of CX-10 protocol
MODE_WK2x01 = 30, // =>CYRF6936 MODE_WK2x01 = 30, // =>CYRF6936
MODE_Q303 = 31, // =>NRF24L01 MODE_Q303 = 31, // =>NRF24L01
MODE_GW008 = 32, // =>NRF24L01
}; };
enum Flysky enum Flysky
@ -478,6 +479,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
Q2X2 29 Q2X2 29
WK2x01 30 WK2x01 30
Q303 31 Q303 31
GW008 32
BindBit=> 0x80 1=Bind/0=No BindBit=> 0x80 1=Bind/0=No
AutoBindBit=> 0x40 1=Yes /0=No AutoBindBit=> 0x40 1=Yes /0=No
RangeCheck=> 0x20 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No

View File

@ -941,6 +941,12 @@ static void protocol_init()
remote_callback = Q303_callback; remote_callback = Q303_callback;
break; break;
#endif #endif
#if defined(GW008_NRF24L01_INO)
case MODE_GW008:
next_callback=initGW008();
remote_callback = GW008_callback;
break;
#endif
#endif #endif
} }
} }

View File

@ -282,10 +282,10 @@ static uint8_t bit_reverse(uint8_t b_in)
} }
static const uint16_t polynomial = 0x1021; 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; crc ^= a << 8;
for (uint8_t i = 0; i < 8; ++i) while(bits--)
if (crc & 0x8000) if (crc & 0x8000)
crc = (crc << 1) ^ polynomial; crc = (crc << 1) ^ polynomial;
else else
@ -374,7 +374,7 @@ void XN297_WritePayload(uint8_t* msg, uint8_t len)
uint8_t offset = xn297_addr_len < 4 ? 1 : 0; uint8_t offset = xn297_addr_len < 4 ? 1 : 0;
uint16_t crc = 0xb5d2; uint16_t crc = 0xb5d2;
for (uint8_t i = offset; i < last; ++i) 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) if(xn297_scramble_enabled)
crc ^= pgm_read_word(&xn297_crc_xorout_scrambled[xn297_addr_len - 3 + len]); crc ^= pgm_read_word(&xn297_crc_xorout_scrambled[xn297_addr_len - 3 + len]);
else else
@ -385,6 +385,76 @@ void XN297_WritePayload(uint8_t* msg, uint8_t len)
NRF24L01_WritePayload(buf, last); 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) void XN297_ReadPayload(uint8_t* msg, uint8_t len)
{ {
// TODO: if xn297_crc==1, check CRC before filling *msg // 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<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));
}
return pcf_size;
}
// End of XN297 emulation
/////////////// ///////////////
// LT8900 emulation layer // LT8900 emulation layer
@ -531,14 +620,14 @@ uint8_t LT8900_ReadPayload(uint8_t* msg, uint8_t len)
//Check len //Check len
if(LT8900_Flags&_BV(LT8900_PACKET_LENGTH_EN)) 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++]) if(bit_reverse(len)!=buffer[pos++])
return 0; // wrong len... return 0; // wrong len...
} }
//Decode message //Decode message
for(i=0;i<len;i++) for(i=0;i<len;i++)
{ {
crc=crc16_update(crc,buffer[pos]); crc=crc16_update(crc,buffer[pos],8);
msg[i]=bit_reverse(buffer[pos++]); msg[i]=bit_reverse(buffer[pos++]);
} }
//Check CRC //Check CRC
@ -560,14 +649,14 @@ void LT8900_WritePayload(uint8_t* msg, uint8_t len)
{ {
tmp=bit_reverse(len); tmp=bit_reverse(len);
buffer[pos++]=tmp; buffer[pos++]=tmp;
crc=crc16_update(crc,tmp); crc=crc16_update(crc,tmp,8);
} }
//Add payload //Add payload
for(i=0;i<len;i++) for(i=0;i<len;i++)
{ {
tmp=bit_reverse(msg[i]); tmp=bit_reverse(msg[i]);
buffer[pos++]=tmp; buffer[pos++]=tmp;
crc=crc16_update(crc,tmp); crc=crc16_update(crc,tmp,8);
} }
//Add CRC //Add CRC
if(LT8900_Flags&_BV(LT8900_CRC_ON)) if(LT8900_Flags&_BV(LT8900_CRC_ON))

View File

@ -69,6 +69,7 @@
#undef ASSAN_NRF24L01_INO #undef ASSAN_NRF24L01_INO
#undef HONTAI_NRF24L01_INO #undef HONTAI_NRF24L01_INO
#undef Q303_NRF24L01_INO #undef Q303_NRF24L01_INO
#undef GW008_NRF24L01_INO
#endif #endif
//Make sure telemetry is selected correctly //Make sure telemetry is selected correctly

View File

@ -114,7 +114,7 @@
#define ASSAN_NRF24L01_INO #define ASSAN_NRF24L01_INO
#define HONTAI_NRF24L01_INO #define HONTAI_NRF24L01_INO
#define Q303_NRF24L01_INO #define Q303_NRF24L01_INO
#define GW008_NRF24L01_INO
/**************************/ /**************************/
/*** TELEMETRY SETTINGS ***/ /*** TELEMETRY SETTINGS ***/
@ -222,8 +222,15 @@ const PPM_Parameters PPM_prot[15]= {
CX20 CX20
MODE_HUBSAN MODE_HUBSAN
NONE NONE
MODE_FRSKYV
NONE
MODE_FRSKYD MODE_FRSKYD
NONE NONE
MODE_FRSKYX
CH_16
CH_8
EU_16
EU_8
MODE_HISKY MODE_HISKY
Hisky Hisky
HK310 HK310
@ -272,11 +279,6 @@ const PPM_Parameters PPM_prot[15]= {
MODE_BAYANG MODE_BAYANG
BAYANG BAYANG
H8S3D H8S3D
MODE_FRSKYX
CH_16
CH_8
EU_16
EU_8
MODE_ESKY MODE_ESKY
NONE NONE
MODE_MT99XX MODE_MT99XX
@ -305,8 +307,6 @@ const PPM_Parameters PPM_prot[15]= {
NONE NONE
MODE_ASSAN MODE_ASSAN
NONE NONE
MODE_FRSKYV
NONE
MODE_HONTAI MODE_HONTAI
FORMAT_HONTAI FORMAT_HONTAI
FORMAT_JJRCX1 FORMAT_JJRCX1
@ -329,6 +329,8 @@ const PPM_Parameters PPM_prot[15]= {
CX35 CX35
CX10D CX10D
CX10WD CX10WD
MODE_GW008
NONE
*/ */
// RX_Num is used for model match. Using RX_Num values different for each receiver will prevent starting a model with the false config loaded... // RX_Num is used for model match. Using RX_Num values different for each receiver will prevent starting a model with the false config loaded...