277 lines
7.7 KiB
Arduino
Raw Normal View History

2015-12-30 01:41:12 +01:00
/*
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 Cheerson CX-10 blue & newer red pcb, CX-10A, CX11, CX-10 green pcb, DM007, Floureon FX-10, JXD 509 (Q282), Q222, Q242 and Q282
// Last sync with hexfet new_protocols/cx10_nrf24l01.c dated 2015-11-26
2015-12-30 01:41:12 +01:00
#if defined(CX10_NRF24L01_INO)
#include "iface_xn297.h"
2015-12-30 01:41:12 +01:00
2021-01-16 16:50:45 +01:00
#define CX10_BIND_COUNT 4360 // 6 seconds
2016-02-01 11:39:24 +01:00
#define CX10_PACKET_SIZE 15
2021-01-16 16:50:45 +01:00
#define CX10A_PACKET_SIZE 19 // CX10 blue board packets have 19-byte payload
#define Q2X2_PACKET_SIZE 21
2021-01-16 16:50:45 +01:00
#define CX10_PACKET_PERIOD 1316 // Timeout for callback in uSec
2016-02-01 11:39:24 +01:00
#define CX10A_PACKET_PERIOD 6000
2015-12-30 01:41:12 +01:00
2016-02-04 13:35:16 +01:00
#define CX10_INITIAL_WAIT 500
2015-12-30 01:41:12 +01:00
// flags
2021-01-16 16:50:45 +01:00
#define CX10_FLAG_FLIP 0x10 // goes to rudder channel
2015-12-30 01:41:12 +01:00
#define CX10_FLAG_MODE_MASK 0x03
#define CX10_FLAG_HEADLESS 0x04
// flags2
#define CX10_FLAG_VIDEO 0x02
#define CX10_FLAG_SNAPSHOT 0x04
// frequency channel management
2016-02-04 13:35:16 +01:00
#define CX10_RF_BIND_CHANNEL 0x02
#define CX10_NUM_RF_CHANNELS 4
2015-12-30 01:41:12 +01:00
enum {
CX10_BIND1 = 0,
2015-12-30 01:41:12 +01:00
CX10_BIND2,
CX10_DATA
};
static void __attribute__((unused)) CX10_Write_Packet()
2015-12-30 01:41:12 +01:00
{
uint8_t offset = 0;
if(sub_protocol == CX10_BLUE)
offset = 4;
packet[0] = IS_BIND_IN_PROGRESS ? 0xAA : 0x55;
2015-12-30 01:41:12 +01:00
packet[1] = rx_tx_addr[0];
packet[2] = rx_tx_addr[1];
packet[3] = rx_tx_addr[2];
packet[4] = rx_tx_addr[3];
// packet[5] to [8] (aircraft id) is filled during bind for blue board
uint16_t aileron= convert_channel_16b_limit(AILERON ,1000,2000);
uint16_t elevator=convert_channel_16b_limit(ELEVATOR,2000,1000);
uint16_t throttle=convert_channel_16b_limit(THROTTLE,1000,2000);
uint16_t rudder= convert_channel_16b_limit(RUDDER ,2000,1000);
2016-11-25 10:28:18 +01:00
// Channel 5 - flip flag
packet[12+offset] = GET_FLAG(CH5_SW,CX10_FLAG_FLIP); // flip flag applied on rudder
// Channel 6 - rate mode is 2 lsb of packet 13
if(CH6_SW) // rate 3 / headless on CX-10A
flags = 0x02;
2015-12-30 01:41:12 +01:00
else
if(Channel_data[CH6] < CHANNEL_MIN_COMMAND)
flags = 0x00; // rate 1
2015-12-30 01:41:12 +01:00
else
flags = 0x01; // rate 2
uint8_t flags2=0; // packet 14
2015-12-30 01:41:12 +01:00
uint8_t video_state=packet[14] & 0x21;
switch(sub_protocol)
2015-12-30 01:41:12 +01:00
{
case CX10_BLUE:
flags |= GET_FLAG(!CH7_SW, 0x10) // Channel 7 - picture
|GET_FLAG( CH8_SW, 0x08); // Channel 8 - video
break;
case F_Q282:
case F_Q242:
case F_Q222:
2016-01-25 18:14:56 +01:00
memcpy(&packet[15], "\x10\x10\xaa\xaa\x00\x00", 6);
//FLIP|LED|PICTURE|VIDEO|HEADLESS|RTH|XCAL|YCAL
flags2 = GET_FLAG(CH5_SW, 0x80) // Channel 5 - FLIP
|GET_FLAG(!CH6_SW, 0x40) // Channel 6 - LED
|GET_FLAG(CH9_SW, 0x08) // Channel 9 - HEADLESS
|GET_FLAG(CH11_SW, 0x04) // Channel 11 - XCAL
|GET_FLAG(CH12_SW, 0x02); // Channel 12 - YCAL or Start/Stop motors on JXD 509
2016-02-04 13:35:16 +01:00
if(sub_protocol==F_Q242)
2016-01-25 18:14:56 +01:00
{
flags=2;
flags2|= GET_FLAG(CH7_SW,0x01) // Channel 7 - picture
|GET_FLAG(CH8_SW,0x10); // Channel 8 - video
2016-01-25 18:14:56 +01:00
packet[17]=0x00;
packet[18]=0x00;
}
else
{ // F_Q282 & F_Q222
flags=3; // expert
if(CH8_SW) // Channel 8 - F_Q282 video / F_Q222 Module 1
2016-12-12 13:45:40 +01:00
{
if (!(video_state & 0x20)) video_state ^= 0x21;
}
else
if (video_state & 0x20) video_state &= 0x01;
flags2 |= video_state
|GET_FLAG(CH7_SW,0x10); // Channel 7 - F_Q282 picture / F_Q222 Module 2
}
if(CH10_SW) flags |=0x80; // Channel 10 - RTH
break;
case DM007:
2016-11-25 10:28:18 +01:00
aileron = 3000 - aileron;
//FLIP|MODE|PICTURE|VIDEO|HEADLESS
flags2= GET_FLAG(CH7_SW,CX10_FLAG_SNAPSHOT) // Channel 7 - picture
|GET_FLAG(CH8_SW,CX10_FLAG_VIDEO); // Channel 8 - video
if(CH9_SW) flags |= CX10_FLAG_HEADLESS; // Channel 9 - headless
break;
case JC3015_2:
2016-11-25 10:28:18 +01:00
aileron = 3000 - aileron;
elevator = 3000 - elevator;
//FLIP|MODE|LED|DFLIP
if(CH8_SW) packet[12] &= ~CX10_FLAG_FLIP;
2016-02-04 13:35:16 +01:00
case JC3015_1:
//FLIP|MODE|PICTURE|VIDEO
flags2= GET_FLAG(CH7_SW,_BV(3)) // Channel 7
|GET_FLAG(CH8_SW,_BV(4)); // Channel 8
break;
case MK33041:
2016-11-25 10:28:18 +01:00
elevator = 3000 - elevator;
//FLIP|MODE|PICTURE|VIDEO|HEADLESS|RTH
flags|=GET_FLAG(CH7_SW,_BV(7)) // Channel 7 - picture
|GET_FLAG(CH10_SW,_BV(2)); // Channel 10 - rth
flags2=GET_FLAG(CH8_SW,_BV(0)) // Channel 8 - video
|GET_FLAG(CH9_SW,_BV(5)); // Channel 9 - headless
break;
2015-12-30 01:41:12 +01:00
}
2016-11-25 10:28:18 +01:00
packet[5+offset] = lowByte(aileron);
2016-11-25 11:44:32 +01:00
packet[6+offset] = highByte(aileron);
packet[7+offset] = lowByte(elevator);
packet[8+offset] = highByte(elevator);
2016-12-07 19:16:09 +01:00
packet[9+offset] = lowByte(throttle);
packet[10+offset]= highByte(throttle);
2016-11-25 10:28:18 +01:00
packet[11+offset]= lowByte(rudder);
packet[12+offset]|= highByte(rudder);
packet[13+offset]=flags;
packet[14+offset]=flags2;
2016-11-25 10:28:18 +01:00
// Send
if(IS_BIND_DONE)
2015-12-30 01:41:12 +01:00
{
XN297_Hopping(hopping_frequency_no++);
2016-02-04 13:35:16 +01:00
hopping_frequency_no %= CX10_NUM_RF_CHANNELS;
2015-12-30 01:41:12 +01:00
}
XN297_SetPower();
XN297_SetTxRxMode(TX_EN);
2015-12-30 01:41:12 +01:00
XN297_WritePayload(packet, packet_length);
}
2021-02-09 18:23:33 +01:00
static void __attribute__((unused)) CX10_RF_init()
2015-12-30 01:41:12 +01:00
{
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
XN297_SetTXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc", 5);
XN297_SetRXAddr((uint8_t *)"\xcc\xcc\xcc\xcc\xcc", packet_length);
XN297_RFChannel(CX10_RF_BIND_CHANNEL);
2015-12-30 01:41:12 +01:00
}
uint16_t CX10_callback()
{
2015-12-30 01:41:12 +01:00
switch (phase) {
case CX10_BIND1:
if (bind_counter == 0)
{
phase = CX10_DATA;
BIND_DONE;
}
else
{
CX10_Write_Packet();
2015-12-30 01:41:12 +01:00
bind_counter--;
}
break;
case CX10_BIND2:
// switch to TX mode
if( XN297_IsRX() )
2015-12-30 01:41:12 +01:00
{ // RX fifo data ready
debugln("RX");
if(XN297_ReadPayload(packet, packet_length) && packet[9] == 1)
2016-02-01 11:39:24 +01:00
{
BIND_DONE;
XN297_SetTxRxMode(TXRX_OFF);
phase = CX10_DATA;
break;
2016-02-01 11:39:24 +01:00
}
2015-12-30 01:41:12 +01:00
}
else
{
XN297_SetTxRxMode(TXRX_OFF);
CX10_Write_Packet();
2021-01-16 16:50:45 +01:00
// wait for packet to be sent
while( !XN297_IsPacketSent()); //delayMicroseconds(400);
2015-12-30 01:41:12 +01:00
}
// switch to RX mode
XN297_SetTxRxMode(TXRX_OFF);
XN297_SetTxRxMode(RX_EN);
2015-12-30 01:41:12 +01:00
break;
case CX10_DATA:
2019-11-11 19:15:39 +01:00
#ifdef MULTI_SYNC
telemetry_set_input_sync(packet_period);
#endif
CX10_Write_Packet();
2015-12-30 01:41:12 +01:00
break;
}
return packet_period;
}
2016-02-04 13:35:16 +01:00
static void __attribute__((unused)) CX10_initialize_txid()
2015-12-30 01:41:12 +01:00
{
rx_tx_addr[1]%= 0x30;
if(sub_protocol&0x08) //F_Q2X2 protocols
{
uint8_t offset=0; //F_Q282
if(sub_protocol==F_Q242)
offset=2;
if(sub_protocol==F_Q222)
offset=3;
for(uint8_t i=0;i<4;i++)
hopping_frequency[i]=0x46+2*i+offset;
}
else
{
hopping_frequency[0] = 0x03 + (rx_tx_addr[0] & 0x0F);
hopping_frequency[1] = 0x16 + (rx_tx_addr[0] >> 4);
hopping_frequency[2] = 0x2D + (rx_tx_addr[1] & 0x0F);
hopping_frequency[3] = 0x40 + (rx_tx_addr[1] >> 4);
}
2015-12-30 01:41:12 +01:00
}
2021-02-09 18:23:33 +01:00
void CX10_init(void)
2015-12-30 01:41:12 +01:00
{
BIND_IN_PROGRESS; // autobind protocol
2021-02-09 18:23:33 +01:00
if(protocol == PROTO_Q2X2)
sub_protocol|=0x08; // Increase the number of sub_protocols for CX-10
if(sub_protocol==CX10_BLUE)
2015-12-30 01:41:12 +01:00
{
packet_length = CX10A_PACKET_SIZE;
packet_period = CX10A_PACKET_PERIOD;
2016-02-01 11:39:24 +01:00
phase = CX10_BIND2;
2016-02-01 11:39:24 +01:00
for(uint8_t i=0; i<4; i++)
packet[5+i] = 0xff; // clear aircraft id
packet[9] = 0;
}
else
{
if(sub_protocol&0x08) //F_Q2X2 protocols
packet_length = Q2X2_PACKET_SIZE;
else
packet_length = CX10_PACKET_SIZE;
packet_period = CX10_PACKET_PERIOD;
phase = CX10_BIND1;
bind_counter = CX10_BIND_COUNT;
2015-12-30 01:41:12 +01:00
}
2016-02-04 13:35:16 +01:00
CX10_initialize_txid();
2021-02-09 18:23:33 +01:00
CX10_RF_init();
2015-12-30 01:41:12 +01:00
}
#endif