mirror of
https://github.com/pascallanger/DIY-Multiprotocol-TX-Module.git
synced 2025-02-04 19:58:13 +00:00
4f1e5d2452
No one has reported an issue but from the look of the code it was broken since some time...
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_no+BUGSMINI_NUM_RF_CHANNELS : 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
|