mirror of
https://github.com/pascallanger/DIY-Multiprotocol-TX-Module.git
synced 2025-02-04 20:48:12 +00:00
4a626eaf14
Loads of protocols have been touched by this change. Some testing has been done but please test on all your models. The XN297 emulation selects in this order: - the CC2500 if it is available and bitrate=250K. Configure the option field automatically for RF tune. - the NRF for all bitrates if it is available - if NRF is not available and bitrate=1M then an invalid protocol is sent automatically to the radio. CC2500 @250K can now receive normal and enhanced payloads. OMP protocol supports telemetry on CC2500 and is also for NRF only modules including telemetry. Separation of E016H (new protocol) from E01X due to different structure. MJXQ, MT99XX, Q303 and XK: some sub protocols available on CC2500 only.
365 lines
11 KiB
C++
365 lines
11 KiB
C++
/*
|
|
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 MJX Bugs 3 Mini and Bugs 3H
|
|
|
|
#if defined(BUGSMINI_NRF24L01_INO)
|
|
|
|
#include "iface_xn297.h"
|
|
|
|
#define BUGSMINI_INITIAL_WAIT 500
|
|
#define BUGSMINI_PACKET_INTERVAL 6840
|
|
#define BUGSMINI_WRITE_WAIT 2000
|
|
#define BUGSMINI_TX_PAYLOAD_SIZE 24
|
|
#define BUGSMINI_RX_PAYLOAD_SIZE 16
|
|
#define BUGSMINI_NUM_RF_CHANNELS 15
|
|
#define BUGSMINI_ADDRESS_SIZE 5
|
|
|
|
static uint8_t BUGSMINI_txid[3];
|
|
static uint8_t BUGSMINI_txhash;
|
|
|
|
enum {
|
|
BUGSMINI_BIND1,
|
|
BUGSMINI_BIND2,
|
|
BUGSMINI_DATA1,
|
|
BUGSMINI_DATA2
|
|
};
|
|
|
|
#define BUGSMINI_CH_SW_ARM CH5_SW
|
|
#define BUGSMINI_CH_SW_ANGLE CH6_SW
|
|
#define BUGSMINI_CH_SW_FLIP CH7_SW
|
|
#define BUGSMINI_CH_SW_PICTURE CH8_SW
|
|
#define BUGSMINI_CH_SW_VIDEO CH9_SW
|
|
#define BUGSMINI_CH_SW_LED CH10_SW
|
|
#define BUGSMINI_CH_SW_ALTHOLD CH11_SW
|
|
|
|
// flags packet[12]
|
|
#define BUGSMINI_FLAG_FLIP 0x08 // automatic flip
|
|
#define BUGSMINI_FLAG_MODE 0x04 // low/high speed select (set is high speed)
|
|
#define BUGSMINI_FLAG_VIDEO 0x02 // toggle video
|
|
#define BUGSMINI_FLAG_PICTURE 0x01 // toggle picture
|
|
|
|
// flags packet[13]
|
|
#define BUGSMINI_FLAG_LED 0x80 // enable LEDs
|
|
#define BUGSMINI_FLAG_ARM 0x40 // arm (toggle to turn on motors)
|
|
#define BUGSMINI_FLAG_DISARM 0x20 // disarm (toggle to turn off motors)
|
|
#define BUGSMINI_FLAG_ANGLE 0x02 // angle/acro mode (set is angle mode)
|
|
#define BUGSMINI_FLAG_ALTHOLD 0x04 // angle/altitude hold mode (set is altitude mode)
|
|
|
|
static void __attribute__((unused)) BUGSMINI_RF_init()
|
|
{
|
|
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_1M);
|
|
//XN297_HoppingCalib(BUGSMINI_NUM_RF_CHANNELS*2);
|
|
}
|
|
|
|
static void __attribute__((unused)) BUGSMINI_check_arming()
|
|
{
|
|
uint8_t arm_channel = BUGSMINI_CH_SW_ARM;
|
|
|
|
if (arm_channel != arm_channel_previous)
|
|
{
|
|
arm_channel_previous = arm_channel;
|
|
if (arm_channel)
|
|
{
|
|
armed = 1;
|
|
arm_flags ^= BUGSMINI_FLAG_ARM;
|
|
}
|
|
else
|
|
{
|
|
armed = 0;
|
|
arm_flags ^= BUGSMINI_FLAG_DISARM;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void __attribute__((unused)) BUGSMINI_send_packet()
|
|
{
|
|
BUGSMINI_check_arming(); // sets globals arm_flags and armed
|
|
|
|
uint16_t aileron = convert_channel_16b_limit(AILERON,500,0);
|
|
uint16_t elevator = convert_channel_16b_limit(ELEVATOR,0,500);
|
|
uint16_t throttle = armed ? convert_channel_16b_limit(THROTTLE,0,500) : 0;
|
|
uint16_t rudder = convert_channel_16b_limit(RUDDER,500,0);
|
|
|
|
packet[1] = BUGSMINI_txid[0];
|
|
packet[2] = BUGSMINI_txid[1];
|
|
packet[3] = BUGSMINI_txid[2];
|
|
if(IS_BIND_IN_PROGRESS)
|
|
{
|
|
packet[4] = 0x00;
|
|
packet[5] = 0x7d;
|
|
packet[6] = 0x7d;
|
|
packet[7] = 0x7d;
|
|
packet[8] = 0x20;
|
|
packet[9] = 0x20;
|
|
packet[10]= 0x20;
|
|
packet[11]= 0x40;
|
|
packet[12]^= 0x40; // alternating freq hopping flag
|
|
packet[13]= 0x60;
|
|
packet[14]= 0x00;
|
|
packet[15]= 0x00;
|
|
}
|
|
else
|
|
{
|
|
packet[4] = throttle >> 1;
|
|
packet[5] = rudder >> 1;
|
|
packet[6] = elevator >> 1;
|
|
packet[7] = aileron >> 1;
|
|
packet[8] = (((aileron / 5) >> 1) + 7) // dynamic trim 0x07 - 0x39
|
|
| (aileron << 7);
|
|
packet[9] = (((elevator / 5) >> 1) + 7) // dynamic trim 0x07 - 0x39
|
|
| (elevator << 7);
|
|
packet[10]= (((rudder / 5) >> 1) + 7) // dynamic trim 0x07 - 0x39
|
|
| (rudder << 7);
|
|
packet[11]= 0x40 | (throttle << 7);
|
|
packet[12]= 0x80 | ((packet[12] ^ 0x40) & 0x40)
|
|
| BUGSMINI_FLAG_MODE
|
|
| GET_FLAG(BUGSMINI_CH_SW_PICTURE, BUGSMINI_FLAG_PICTURE)
|
|
| GET_FLAG(BUGSMINI_CH_SW_VIDEO, BUGSMINI_FLAG_VIDEO);
|
|
if(armed)
|
|
packet[12] |= GET_FLAG(BUGSMINI_CH_SW_FLIP, BUGSMINI_FLAG_FLIP);
|
|
packet[13] = arm_flags
|
|
| GET_FLAG(BUGSMINI_CH_SW_LED, BUGSMINI_FLAG_LED)
|
|
| GET_FLAG(BUGSMINI_CH_SW_ALTHOLD, BUGSMINI_FLAG_ALTHOLD)
|
|
| GET_FLAG(BUGSMINI_CH_SW_ANGLE, BUGSMINI_FLAG_ANGLE);
|
|
// BUGS3H althold -> BUGSMINI_FLAG_ALTHOLD|BUGSMINI_FLAG_ANGLE , angle -> 0
|
|
packet[14] = 0;
|
|
packet[15] = 0; // a lot of 0x53 and some 0x52 on bugs 3H
|
|
}
|
|
uint8_t checksum = 0x6d;
|
|
for(uint8_t i=1; i < BUGSMINI_TX_PAYLOAD_SIZE; i++)
|
|
checksum ^= packet[i];
|
|
packet[0] = checksum;
|
|
|
|
if(!(packet[12]&0x40))
|
|
{
|
|
hopping_frequency_no++;
|
|
if(hopping_frequency_no >= BUGSMINI_NUM_RF_CHANNELS)
|
|
hopping_frequency_no = 0;
|
|
XN297_Hopping(IS_BIND_IN_PROGRESS ? hopping_frequency[hopping_frequency_no+BUGSMINI_NUM_RF_CHANNELS] : hopping_frequency[hopping_frequency_no]);
|
|
}
|
|
|
|
// Send
|
|
XN297_SetPower();
|
|
XN297_SetTxRxMode(TXRX_OFF);
|
|
XN297_SetTxRxMode(TX_EN);
|
|
XN297_WritePayload(packet, BUGSMINI_TX_PAYLOAD_SIZE);
|
|
}
|
|
|
|
// compute final address for the rxid received during bind
|
|
// thanks to Pascal for the function!
|
|
const uint8_t PROGMEM BUGSMINI_end []= {
|
|
0x2d,0x9e ,0x95,0xa4 ,0x9c,0x5c ,0xb4,0xa6 ,0xa9,0xce ,0x56,0x2b ,0x3e,0x73 ,0xb8,0x95 ,0x6a,0x82,
|
|
0x94,0x37 ,0x3d,0x5a ,0x4b,0xb2 ,0x69,0x49 ,0xc2,0x24 ,0x6b,0x3d ,0x23,0xc6 ,0x9e,0xa3 ,0xa4,0x98,
|
|
0x5c,0x9e ,0xa6,0x52 ,0xce,0x76 ,0x2b,0x4b ,0x73,0x3a };
|
|
static void __attribute__((unused)) BUGSMINI_make_address()
|
|
{
|
|
uint8_t start, length, index;
|
|
|
|
//read rxid
|
|
uint8_t base_adr=BUGSMINI_EEPROM_OFFSET+(RX_num&0x0F)*2;
|
|
uint8_t rxid_high = eeprom_read_byte((EE_ADDR)(base_adr+0));
|
|
uint8_t rxid_low = eeprom_read_byte((EE_ADDR)(base_adr+1));
|
|
|
|
if(rxid_high==0x00 || rxid_high==0xFF)
|
|
rx_tx_addr[0]=0x52;
|
|
else
|
|
rx_tx_addr[0]=rxid_high;
|
|
|
|
rx_tx_addr[1]=BUGSMINI_txhash;
|
|
|
|
if(rxid_low==0x00 || rxid_low==0xFF)
|
|
rx_tx_addr[2]=0x66;
|
|
else
|
|
rx_tx_addr[2]=rxid_low;
|
|
|
|
for(uint8_t end_idx=0;end_idx<23;end_idx++)
|
|
{
|
|
//calculate sequence start
|
|
if(end_idx<=7)
|
|
start=end_idx;
|
|
else
|
|
start=(end_idx-7)*16+7;
|
|
//calculate sequence length
|
|
if(end_idx>6)
|
|
{
|
|
if(end_idx>15)
|
|
length=(23-end_idx)<<1;
|
|
else
|
|
length=16;
|
|
}
|
|
else
|
|
length=(end_idx+1)<<1;
|
|
//calculate first index
|
|
index=start-rxid_high;
|
|
//scan for a possible match using the current end
|
|
for(uint8_t i=0;i<length;i++)
|
|
{
|
|
if(index==rxid_low)
|
|
{ //match found
|
|
rx_tx_addr[3]=pgm_read_byte_near( &BUGSMINI_end[end_idx<<1] );
|
|
rx_tx_addr[4]=pgm_read_byte_near( &BUGSMINI_end[(end_idx<<1)+1] );
|
|
return;
|
|
}
|
|
index+=i&1?7:8; //increment index
|
|
}
|
|
}
|
|
// Something wrong happened if we arrive here....
|
|
}
|
|
|
|
#if defined(BUGS_HUB_TELEMETRY)
|
|
static void __attribute__((unused)) BUGSMINI_update_telemetry()
|
|
{
|
|
uint8_t checksum = 0x6d;
|
|
for(uint8_t i=1; i<12; i++)
|
|
checksum += packet_in[i];
|
|
if(packet_in[0] == checksum)
|
|
{
|
|
RX_RSSI = packet_in[3];
|
|
if(sub_protocol==BUGS3H)
|
|
{
|
|
if(packet_in[11] & 0x40)
|
|
v_lipo1 = 0x40; // Warning
|
|
else if(packet_in[11] & 0x80)
|
|
v_lipo1 = 0x20; // Critical
|
|
else
|
|
v_lipo1 = 0x80; // Ok
|
|
}
|
|
else
|
|
{
|
|
if(packet_in[11] & 0x80)
|
|
v_lipo1 = 0x80; // Ok
|
|
else if(packet_in[11] & 0x40)
|
|
v_lipo1 = 0x40; // Warning
|
|
else
|
|
v_lipo1 = 0x20; // Critical
|
|
}
|
|
telemetry_link=1;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
uint16_t BUGSMINI_callback()
|
|
{
|
|
uint8_t base_adr;
|
|
switch(phase)
|
|
{
|
|
case BUGSMINI_BIND1:
|
|
if( XN297_IsRX() )
|
|
{ // RX fifo data ready
|
|
XN297_ReadPayload(packet, BUGSMINI_RX_PAYLOAD_SIZE); // Not checking the CRC??
|
|
base_adr=BUGSMINI_EEPROM_OFFSET+(RX_num&0x0F)*2;
|
|
eeprom_write_byte((EE_ADDR)(base_adr+0),packet[1]); // Save rxid in EEPROM
|
|
eeprom_write_byte((EE_ADDR)(base_adr+1),packet[2]); // Save rxid in EEPROM
|
|
BUGSMINI_make_address();
|
|
XN297_SetTXAddr(rx_tx_addr, 5);
|
|
XN297_SetRXAddr(rx_tx_addr, BUGSMINI_RX_PAYLOAD_SIZE);
|
|
phase = BUGSMINI_DATA1;
|
|
BIND_DONE;
|
|
break;
|
|
}
|
|
BUGSMINI_send_packet();
|
|
phase = BUGSMINI_BIND2;
|
|
return BUGSMINI_WRITE_WAIT;
|
|
case BUGSMINI_BIND2:
|
|
// switch to RX mode
|
|
XN297_SetTxRxMode(TXRX_OFF);
|
|
XN297_SetTxRxMode(RX_EN);
|
|
phase = BUGSMINI_BIND1;
|
|
return BUGSMINI_PACKET_INTERVAL - BUGSMINI_WRITE_WAIT;
|
|
case BUGSMINI_DATA1:
|
|
#ifdef MULTI_SYNC
|
|
telemetry_set_input_sync(BUGSMINI_PACKET_INTERVAL);
|
|
#endif
|
|
#if defined(BUGS_HUB_TELEMETRY)
|
|
if( XN297_IsRX() )
|
|
{
|
|
XN297_ReadPayload(packet_in, BUGSMINI_RX_PAYLOAD_SIZE); // Not checking the CRC??
|
|
BUGSMINI_update_telemetry();
|
|
}
|
|
#endif
|
|
BUGSMINI_send_packet();
|
|
#if not defined(BUGS_HUB_TELEMETRY)
|
|
break;
|
|
#else
|
|
phase = BUGSMINI_DATA2;
|
|
return BUGSMINI_WRITE_WAIT;
|
|
case BUGSMINI_DATA2:
|
|
// switch to RX mode
|
|
XN297_SetTxRxMode(TXRX_OFF);
|
|
XN297_SetTxRxMode(RX_EN);
|
|
phase = BUGSMINI_DATA1;
|
|
return BUGSMINI_PACKET_INTERVAL - BUGSMINI_WRITE_WAIT;
|
|
#endif
|
|
}
|
|
return BUGSMINI_PACKET_INTERVAL;
|
|
}
|
|
|
|
#define BUGSMINI_NUM_TX_RF_MAPS 4
|
|
// haven't figured out BUGSMINI_txid<-->rf channel mapping yet
|
|
const uint8_t PROGMEM BUGSMINI_RF_chans[BUGSMINI_NUM_TX_RF_MAPS][BUGSMINI_NUM_RF_CHANNELS] = {
|
|
{0x22,0x2f,0x3a,0x14,0x20,0x2d,0x38,0x18,0x26,0x32,0x11,0x1d,0x29,0x35,0x17},
|
|
{0x3d,0x34,0x2b,0x22,0x19,0x40,0x37,0x2e,0x25,0x1c,0x3a,0x31,0x28,0x1f,0x16},
|
|
{0x12,0x20,0x2f,0x1a,0x28,0x38,0x14,0x23,0x32,0x1c,0x2c,0x3b,0x17,0x26,0x34},
|
|
{0x13,0x25,0x37,0x1F,0x31,0x17,0x28,0x3A,0x1C,0x2E,0x22,0x33,0x19,0x2B,0x3D} };
|
|
const uint8_t PROGMEM BUGSMINI_bind_chans[BUGSMINI_NUM_RF_CHANNELS] = {
|
|
0x1A,0x23,0x2C,0x35,0x3E,0x17,0x20,0x29,0x32,0x3B,0x14,0x1D,0x26,0x2F,0x38}; // bugs 3 mini bind channels
|
|
const uint8_t PROGMEM BUGSMINI_tx_id[BUGSMINI_NUM_TX_RF_MAPS][3] = {
|
|
{0xA8,0xE6,0x32},
|
|
{0xdd,0xab,0xfd},
|
|
{0x90,0x9e,0x4a},
|
|
{0x20,0x28,0xBA} };
|
|
const uint8_t PROGMEM BUGSMINI_tx_hash[BUGSMINI_NUM_TX_RF_MAPS] = { // 2nd byte of final address
|
|
0x6c,0x9e,0x3d,0xb3};
|
|
|
|
static void __attribute__((unused)) BUGSMINI_initialize_txid()
|
|
{
|
|
// load hopping_frequency with tx channels in low part and bind channels in high part
|
|
for(uint8_t i=0; i<BUGSMINI_NUM_RF_CHANNELS;i++)
|
|
{
|
|
hopping_frequency[i]=pgm_read_byte_near( &BUGSMINI_RF_chans[rx_tx_addr[3]%BUGSMINI_NUM_TX_RF_MAPS][i] );
|
|
hopping_frequency[i+BUGSMINI_NUM_RF_CHANNELS]=pgm_read_byte_near( &BUGSMINI_bind_chans[i] );
|
|
}
|
|
// load txid
|
|
for(uint8_t i=0; i<sizeof(BUGSMINI_txid);i++)
|
|
BUGSMINI_txid[i]=pgm_read_byte_near( &BUGSMINI_tx_id[rx_tx_addr[3]%BUGSMINI_NUM_TX_RF_MAPS][i] );
|
|
//load tx_hash
|
|
BUGSMINI_txhash = pgm_read_byte_near( &BUGSMINI_tx_hash[rx_tx_addr[3]%BUGSMINI_NUM_TX_RF_MAPS] );
|
|
}
|
|
|
|
void BUGSMINI_init()
|
|
{
|
|
BUGSMINI_initialize_txid();
|
|
BUGSMINI_RF_init();
|
|
memset(packet, (uint8_t)0, BUGSMINI_TX_PAYLOAD_SIZE);
|
|
if(IS_BIND_IN_PROGRESS)
|
|
{
|
|
XN297_SetTXAddr((const uint8_t*)"mjxRC", 5);
|
|
XN297_SetRXAddr((const uint8_t*)"mjxRC", BUGSMINI_RX_PAYLOAD_SIZE);
|
|
phase = BUGSMINI_BIND1;
|
|
}
|
|
else
|
|
{
|
|
BUGSMINI_make_address();
|
|
XN297_SetTXAddr(rx_tx_addr, 5);
|
|
XN297_SetRXAddr(rx_tx_addr, BUGSMINI_RX_PAYLOAD_SIZE);
|
|
phase = BUGSMINI_DATA1;
|
|
}
|
|
armed = 0;
|
|
arm_flags = BUGSMINI_FLAG_DISARM; // initial value from captures
|
|
arm_channel_previous = BUGSMINI_CH_SW_ARM;
|
|
}
|
|
|
|
#endif
|