Suit du projet, ajout de la sélection PPM, ajout protocole H7

This commit is contained in:
tipouic 2016-01-27 19:40:24 +01:00
parent 3fcaf93788
commit ab5f4e9194
30 changed files with 1901 additions and 1053 deletions

View File

@ -196,8 +196,19 @@ const uint8_t PROGMEM FLYSKY_A7105_regs[] = {
0x13, 0xc3, 0x00, 0xff, 0x00, 0x00, 0x3b, 0x00, 0x17, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00,
0x01, 0x0f, 0xff
};
#define ID_NORMAL 0x55201041
#define ID_PLUS 0xAA201041
/*
static const uint8_t a7105Regs[] = {
-1, 0x42, 0x00, 0x14, 0x00, -1 , -1 , 0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x05, 0x00, 0x50,
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x00, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x0f,
0x13, 0xc3, 0x00, -1, 0x00, 0x00, 0x3b, 0x00, 0x17, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00,
0x01, 0x0f, -1,
};
*/
void A7105_Init(uint8_t protocol)
{
void *A7105_Regs;

View File

@ -38,7 +38,7 @@ enum BAYANG_FLAGS {
BAYANG_FLAG_INVERTED = 0x80 // inverted flight on Floureon H101
};
static void BAYANG_send_packet(uint8_t bind)
static void __attribute__((unused)) BAYANG_send_packet(uint8_t bind)
{
uint8_t i;
if (bind)
@ -112,7 +112,7 @@ static void BAYANG_send_packet(uint8_t bind)
NRF24L01_SetPower(); // Set tx_power
}
static void BAYANG_init()
static void __attribute__((unused)) BAYANG_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
@ -148,7 +148,7 @@ uint16_t BAYANG_callback()
return BAYANG_PACKET_PERIOD;
}
static void BAYANG_initialize_txid()
static void __attribute__((unused)) BAYANG_initialize_txid()
{
//Could be using txid[0..2] but using rx_tx_addr everywhere instead...
hopping_frequency[0]=0;

View File

@ -70,7 +70,7 @@ enum H8_3D_FLAGS_2 {
H8_3D_FLAG_CALIBRATE = 0x20, // accelerometer calibration
};
static void CG023_send_packet(uint8_t bind)
static void __attribute__((unused)) CG023_send_packet(uint8_t bind)
{
// throttle : 0x00 - 0xFF
throttle=convert_channel_8b(THROTTLE);
@ -205,7 +205,7 @@ static void CG023_send_packet(uint8_t bind)
NRF24L01_SetPower(); // Set tx_power
}
static void CG023_init()
static void __attribute__((unused)) CG023_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
@ -246,7 +246,7 @@ uint16_t CG023_callback()
return H8_3D_PACKET_PERIOD;
}
static void CG023_initialize_txid()
static void __attribute__((unused)) CG023_initialize_txid()
{
if(sub_protocol==H8_3D)
{
@ -255,10 +255,10 @@ static void CG023_initialize_txid()
rx_tx_addr[2] = rx_tx_addr[2] % 0x20;
rx_tx_addr[3] = rx_tx_addr[3] % 0x11;
hopping_frequency[0] = 0x06 + (rx_tx_addr[0]&0x0f);
hopping_frequency[1] = 0x15 + (rx_tx_addr[1]&0x0f);
hopping_frequency[2] = 0x24 + (rx_tx_addr[2]&0x0f);
hopping_frequency[3] = 0x33 + (rx_tx_addr[3]&0x0f);
hopping_frequency[0] = 0x06 + ((rx_tx_addr[0]&0x0f) % 0x0f);
hopping_frequency[1] = 0x15 + ((rx_tx_addr[1]&0x0f) % 0x0f);
hopping_frequency[2] = 0x24 + ((rx_tx_addr[2]&0x0f) % 0x0f);
hopping_frequency[3] = 0x33 + ((rx_tx_addr[3]&0x0f) % 0x0f);
}
else
{ // CG023 and YD829

View File

@ -46,7 +46,7 @@ enum {
CX10_DATA
};
static void CX10_Write_Packet(uint8_t bind)
static void __attribute__((unused)) CX10_Write_Packet(uint8_t bind)
{
uint8_t offset = 0;
if(sub_protocol == CX10_BLUE)
@ -90,24 +90,36 @@ static void CX10_Write_Packet(uint8_t bind)
if(Servo_AUX4) flags |= 0x08; // Channel 8 - video
break;
case Q282:
case Q242:
memcpy(&packet[15], "\x10\x10\xaa\xaa\x00\x00", 6);
//FLIP|LED|PICTURE|VIDEO|HEADLESS|RTH|XCAL|YCAL
if(Servo_AUX1) flags2 =0x80; // Channel 5 - FLIP
if(Servo_AUX2) flags2|=0x40; // Channel 6 - LED
if(Servo_AUX3) flags2|=0x10; // Channel 7 - picture
if(Servo_AUX4) // Channel 8 - video
{
if (!(video_state & 0x20)) video_state ^= 0x21;
}
else
if (video_state & 0x20) video_state &= 0x01;
flags2 |= video_state;
if(Servo_AUX5) flags2|=0x08; // Channel 9 - HEADLESS
flags=3;
if(sub_protocol==Q282)
{
if(Servo_AUX3) flags2|=0x10; // Channel 7 - picture
if(Servo_AUX4) // Channel 8 - video
{
if (!(video_state & 0x20)) video_state ^= 0x21;
}
else
if (video_state & 0x20) video_state &= 0x01;
flags2 |= video_state;
flags=3;
}
else
{
if(Servo_AUX3) flags2|=0x01; // Channel 7 - picture
if(Servo_AUX4) flags2|=0x10; // Channel 8 - video
flags=2;
packet[17]=0x00;
packet[18]=0x00;
}
if(Servo_AUX6) flags |=0x80; // Channel 10 - RTH
if(Servo_AUX7) flags2|=0x04; // Channel 11 - XCAL
if(Servo_AUX8) flags2|=0x02; // Channel 12 - YCAL
memcpy(&packet[15], "\x10\x10\xaa\xaa\x00\x00", 6);
break;
case DM007:
//FLIP|MODE|PICTURE|VIDEO|HEADLESS
@ -154,7 +166,7 @@ static void CX10_Write_Packet(uint8_t bind)
NRF24L01_SetPower();
}
static void CX10_init()
static void __attribute__((unused)) CX10_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
@ -199,7 +211,7 @@ uint16_t CX10_callback() {
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(TX_EN);
CX10_Write_Packet(1);
delay(1); // used to be 300µs in deviation but not working so 1ms now
delayMicroseconds(400); // 300µs in deviation but not working so using 400µs instead
// switch to RX mode
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_FlushRx();
@ -214,7 +226,7 @@ uint16_t CX10_callback() {
return packet_period;
}
static void initialize_txid()
static void __attribute__((unused)) initialize_txid()
{
rx_tx_addr[1]%= 0x30;
if(sub_protocol==Q282)
@ -225,12 +237,20 @@ static void initialize_txid()
hopping_frequency[3] = 0x4c;
}
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);
}
if(sub_protocol==Q242)
{
hopping_frequency[0] = 0x48;
hopping_frequency[1] = 0x4a;
hopping_frequency[2] = 0x4c;
hopping_frequency[3] = 0x4e;
}
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);
}
}
uint16_t initCX10(void)
@ -247,7 +267,7 @@ uint16_t initCX10(void)
}
else
{
if(sub_protocol==Q282)
if(sub_protocol==Q282||sub_protocol==Q242)
packet_length = Q282_PACKET_SIZE;
else
packet_length = CX10_PACKET_SIZE;

View File

@ -110,7 +110,6 @@ uint16_t cyrf_state;
uint8_t crcidx;
uint8_t binding;
uint16_t crc;
uint8_t model;
/*
#ifdef USE_FIXED_MFGID
@ -121,14 +120,14 @@ const uint8_t cyrfmfg_id[6] = {0xd4, 0x62, 0xd6, 0xad, 0xd3, 0xff}; //dx6i
#endif
*/
static void build_bind_packet()
static void __attribute__((unused)) build_bind_packet()
{
uint8_t i;
uint16_t sum = 384 - 0x10;//
packet[0] = crc >> 8;
packet[1] = crc & 0xff;
packet[2] = 0xff ^ cyrfmfg_id[2];
packet[3] = (0xff ^ cyrfmfg_id[3]) + model;
packet[3] = (0xff ^ cyrfmfg_id[3]) + RX_num;
packet[4] = packet[0];
packet[5] = packet[1];
packet[6] = packet[2];
@ -154,7 +153,23 @@ static void build_bind_packet()
packet[15] = sum & 0xff;
}
static void build_data_packet(uint8_t upper)//
static uint8_t __attribute__((unused)) PROTOCOL_SticksMoved(uint8_t init)
{
#define STICK_MOVEMENT 15*(PPM_MAX-PPM_MIN)/100 // defines when the bind dialog should be interrupted (stick movement STICK_MOVEMENT %)
static uint16_t ele_start, ail_start;
uint16_t ele = Servo_data[ELEVATOR];//CHAN_ReadInput(MIXER_MapChannel(INP_ELEVATOR));
uint16_t ail = Servo_data[AILERON];//CHAN_ReadInput(MIXER_MapChannel(INP_AILERON));
if(init) {
ele_start = ele;
ail_start = ail;
return 0;
}
uint16_t ele_diff = ele_start - ele;//abs(ele_start - ele);
uint16_t ail_diff = ail_start - ail;//abs(ail_start - ail);
return ((ele_diff + ail_diff) > STICK_MOVEMENT);//
}
static void __attribute__((unused)) build_data_packet(uint8_t upper)//
{
#if DSM2_NUM_CHANNELS==4
const uint8_t ch_map[] = {0, 1, 2, 3, 0xff, 0xff, 0xff}; //Guess
@ -187,13 +202,13 @@ static void build_data_packet(uint8_t upper)//
if (sub_protocol==DSMX)
{
packet[0] = cyrfmfg_id[2];
packet[1] = cyrfmfg_id[3] + model;
packet[1] = cyrfmfg_id[3] + RX_num;
bits=11;
}
else
{
packet[0] = (0xff ^ cyrfmfg_id[2]);
packet[1] = (0xff ^ cyrfmfg_id[3]) + model;
packet[1] = (0xff ^ cyrfmfg_id[3]) + RX_num;
bits=10;
}
//
@ -252,23 +267,7 @@ static void build_data_packet(uint8_t upper)//
}
}
static uint8_t PROTOCOL_SticksMoved(uint8_t init)
{
#define STICK_MOVEMENT 15*(PPM_MAX-PPM_MIN)/100 // defines when the bind dialog should be interrupted (stick movement STICK_MOVEMENT %)
static uint16_t ele_start, ail_start;
uint16_t ele = Servo_data[ELEVATOR];//CHAN_ReadInput(MIXER_MapChannel(INP_ELEVATOR));
uint16_t ail = Servo_data[AILERON];//CHAN_ReadInput(MIXER_MapChannel(INP_AILERON));
if(init) {
ele_start = ele;
ail_start = ail;
return 0;
}
uint16_t ele_diff = ele_start - ele;//abs(ele_start - ele);
uint16_t ail_diff = ail_start - ail;//abs(ail_start - ail);
return ((ele_diff + ail_diff) > STICK_MOVEMENT);//
}
static uint8_t get_pn_row(uint8_t channel)
static uint8_t __attribute__((unused)) get_pn_row(uint8_t channel)
{
return (sub_protocol == DSMX ? (channel - 2) % 5 : channel % 5);
}
@ -300,7 +299,7 @@ const uint8_t init_vals[][2] = {
{CYRF_01_TX_LENGTH, 0x10}, //16byte packet
};
static void cyrf_config()
static void __attribute__((unused)) cyrf_config()
{
for(uint8_t i = 0; i < sizeof(init_vals) / 2; i++)
CYRF_WriteRegister(init_vals[i][0], init_vals[i][1]);
@ -308,7 +307,7 @@ static void cyrf_config()
CYRF_ConfigRFChannel(0x61);
}
static void initialize_bind_state()
static void __attribute__((unused)) initialize_bind_state()
{
const uint8_t pn_bind[] = { 0xc6,0x94,0x22,0xfe,0x48,0xe6,0x57,0x4e };
uint8_t data_code[32];
@ -342,13 +341,13 @@ const uint8_t data_vals[][2] = {
{CYRF_10_FRAMING_CFG, 0xea},
};
static void cyrf_configdata()
static void __attribute__((unused)) cyrf_configdata()
{
for(uint8_t i = 0; i < sizeof(data_vals) / 2; i++)
CYRF_WriteRegister(data_vals[i][0], data_vals[i][1]);
}
static void set_sop_data_crc()
static void __attribute__((unused)) set_sop_data_crc()
{
uint8_t pn_row = get_pn_row(hopping_frequency[chidx]);
//printf("Ch: %d Row: %d SOP: %d Data: %d\n", ch[chidx], pn_row, sop_col, data_col);
@ -363,7 +362,7 @@ static void set_sop_data_crc()
crcidx = !crcidx;
}
static void calc_dsmx_channel()
static void __attribute__((unused)) calc_dsmx_channel()
{
uint8_t idx = 0;
uint32_t id = ~(((uint32_t)cyrfmfg_id[0] << 24) | ((uint32_t)cyrfmfg_id[1] << 16) | ((uint32_t)cyrfmfg_id[2] << 8) | (cyrfmfg_id[3] << 0));
@ -513,8 +512,6 @@ uint16_t initDsm2()
sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;//Ok
data_col = 7 - sop_col;//ok
model=MProtocol_id-MProtocol_id_master; // RxNum for serial or 0 for ppm
CYRF_SetTxRxMode(TX_EN);
//
if(IS_AUTOBIND_FLAG_on)

View File

@ -66,7 +66,7 @@ uint8_t ch_idx;
uint8_t use_fixed_id;
uint8_t failsafe_pkt;
static void scramble_pkt()
static void __attribute__((unused)) scramble_pkt()
{
#ifdef NO_SCRAMBLE
return;
@ -77,7 +77,7 @@ static void scramble_pkt()
#endif
}
static void add_pkt_suffix()
static void __attribute__((unused)) add_pkt_suffix()
{
uint8_t bind_state;
if (use_fixed_id)
@ -97,7 +97,7 @@ static void add_pkt_suffix()
packet[15] = (fixed_id >> 16) & 0xff;
}
static void build_beacon_pkt(uint8_t upper)
static void __attribute__((unused)) build_beacon_pkt(uint8_t upper)
{
packet[0] = ((DEVO_NUM_CHANNELS << 4) | 0x07);
// uint8_t enable = 0;
@ -116,7 +116,7 @@ static void build_beacon_pkt(uint8_t upper)
add_pkt_suffix();
}
static void build_bind_pkt()
static void __attribute__((unused)) build_bind_pkt()
{
packet[0] = (DEVO_NUM_CHANNELS << 4) | 0x0a;
packet[1] = bind_counter & 0xff;
@ -136,7 +136,7 @@ static void build_bind_pkt()
packet[15] ^= cyrfmfg_id[2];
}
static void build_data_pkt()
static void __attribute__((unused)) build_data_pkt()
{
uint8_t i;
packet[0] = (DEVO_NUM_CHANNELS << 4) | (0x0b + ch_idx);
@ -161,7 +161,7 @@ static void build_data_pkt()
add_pkt_suffix();
}
static void cyrf_set_bound_sop_code()
static void __attribute__((unused)) cyrf_set_bound_sop_code()
{
/* crc == 0 isn't allowed, so use 1 if the math results in 0 */
uint8_t crc = (cyrfmfg_id[0] + (cyrfmfg_id[1] >> 6) + cyrfmfg_id[2]);
@ -174,7 +174,7 @@ static void cyrf_set_bound_sop_code()
CYRF_SetPower(0x08);
}
static void cyrf_init()
static void __attribute__((unused)) cyrf_init()
{
/* Initialise CYRF chip */
CYRF_WriteRegister(CYRF_1D_MODE_OVERRIDE, 0x39);
@ -201,7 +201,7 @@ static void cyrf_init()
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x28);
}
static void set_radio_channels()
static void __attribute__((unused)) set_radio_channels()
{
//int i;
CYRF_FindBestChannels(hopping_frequency, 3, 4, 4, 80);
@ -217,7 +217,7 @@ static void set_radio_channels()
hopping_frequency[4] = hopping_frequency[1];
}
static void DEVO_BuildPacket()
static void __attribute__((unused)) DEVO_BuildPacket()
{
switch(phase)
{
@ -302,7 +302,7 @@ uint16_t devo_callback()
return 1200;
}
/*static void devo_bind()
/*static void __attribute__((unused)) devo_bind()
{
fixed_id = Model_fixed_id;
bind_counter = DEVO_BIND_COUNT;
@ -311,7 +311,7 @@ uint16_t devo_callback()
}
static void generate_fixed_id_bind(){
static void __attribute__((unused)) generate_fixed_id_bind(){
if(BIND_0){
//randomSeed((uint32_t)analogRead(A6)<<10|analogRead(A7));//seed
uint8_t txid[4];

View File

@ -23,14 +23,14 @@
#define ESKY_PAYLOAD_SIZE 13
#define ESKY_PACKET_CHKTIME 100 // Time to wait for packet to be sent (no ACK, so very short)
static void ESKY_set_data_address()
static void __attribute__((unused)) ESKY_set_data_address()
{
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x02); // 4-byte RX/TX address for regular packets
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 4);
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 4);
}
static void ESKY_init(uint8_t bind)
static void __attribute__((unused)) ESKY_init(uint8_t bind)
{
NRF24L01_Initialize();
@ -41,8 +41,8 @@ static void ESKY_init(uint8_t bind)
if (bind)
{
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // 3-byte RX/TX address for bind packets
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"x00x00x00", 3);
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"x00x00x00", 3);
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\x00\x00\x00", 3);
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\x00\x00\x00", 3);
}
else
ESKY_set_data_address();
@ -60,7 +60,7 @@ static void ESKY_init(uint8_t bind)
NRF24L01_WriteReg(NRF24L01_17_FIFO_STATUS, 0x00); // Just in case, no real bits to write here
}
static void ESKY_init2()
static void __attribute__((unused)) ESKY_init2()
{
NRF24L01_FlushTx();
packet_sent = 0;
@ -90,7 +90,7 @@ static void ESKY_init2()
NRF24L01_SetTxRxMode(TX_EN);
}
static void ESKY_send_packet(uint8_t bind)
static void __attribute__((unused)) ESKY_send_packet(uint8_t bind)
{
uint8_t rf_ch = 50; // bind channel
if (bind)

View File

@ -73,7 +73,7 @@ uint8_t chanrow;
uint8_t chancol;
uint8_t chanoffset;
static void flysky_apply_extension_flags()
static void __attribute__((unused)) flysky_apply_extension_flags()
{
const uint8_t V912_X17_SEQ[10] = { 0x14, 0x31, 0x40, 0x49, 0x49, // sometime first byte is 0x15 ?
0x49, 0x49, 0x49, 0x49, 0x49, };
@ -148,7 +148,7 @@ static void flysky_apply_extension_flags()
}
}
static void flysky_build_packet(uint8_t init)
static void __attribute__((unused)) flysky_build_packet(uint8_t init)
{
uint8_t i;
//servodata timing range for flysky.

View File

@ -18,9 +18,11 @@
#include "iface_cc2500.h"
//##########Variables########
uint32_t state;
uint8_t len;
//uint32_t state;
//uint8_t len;
uint8_t telemetry_counter=0;
/*
enum {
FRSKY_BIND = 0,
FRSKY_BIND_DONE = 1000,
@ -30,114 +32,9 @@ enum {
FRSKY_DATA4,
FRSKY_DATA5
};
*/
uint16_t initFrSky_2way()
{
if(IS_AUTOBIND_FLAG_on)
{
frsky2way_init(1);
state = FRSKY_BIND;//
}
else
{
frsky2way_init(0);
state = FRSKY_DATA2;
}
return 10000;
}
uint16_t ReadFrSky_2way()
{
if (state < FRSKY_BIND_DONE)
{
frsky2way_build_bind_packet();
cc2500_strobe(CC2500_SIDLE);
cc2500_writeReg(CC2500_0A_CHANNR, 0x00);
cc2500_writeReg(CC2500_23_FSCAL3, 0x89);
cc2500_strobe(CC2500_SFRX);//0x3A
cc2500_writeFifo(packet, packet[0]+1);
state++;
return 9000;
}
if (state == FRSKY_BIND_DONE)
{
state = FRSKY_DATA2;
frsky2way_init(0);
counter = 0;
BIND_DONE;
}
else
if (state == FRSKY_DATA5)
{
cc2500_strobe(CC2500_SRX);//0x34 RX enable
state = FRSKY_DATA1;
return 9200;
}
counter = (counter + 1) % 188;
if (state == FRSKY_DATA4)
{ //telemetry receive
CC2500_SetTxRxMode(RX_EN);
cc2500_strobe(CC2500_SIDLE);
cc2500_writeReg(CC2500_0A_CHANNR, get_chan_num(counter % 47));
cc2500_writeReg(CC2500_23_FSCAL3, 0x89);
state++;
return 1300;
}
else
{
if (state == FRSKY_DATA1)
{
len = cc2500_readReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
if (len)//20 bytes
{
cc2500_readFifo(pkt, len); //received telemetry packets
#if defined(TELEMETRY)
//parse telemetry packet here
check_telemetry(pkt,len); //check if valid telemetry packets and buffer them.
#endif
}
CC2500_SetTxRxMode(TX_EN);
CC2500_SetPower(); // Set tx_power
}
cc2500_strobe(CC2500_SIDLE);
cc2500_writeReg(CC2500_0A_CHANNR, get_chan_num(counter % 47));
cc2500_writeReg(CC2500_23_FSCAL3, 0x89);
cc2500_strobe(CC2500_SFRX);
frsky2way_data_frame();
cc2500_writeFifo(packet, packet[0]+1);
state++;
}
return state == FRSKY_DATA4 ? 7500 : 9000;
}
#if defined(TELEMETRY)
static void check_telemetry(uint8_t *pkt,uint8_t len)
{
if(pkt[1] != rx_tx_addr[3] || pkt[2] != rx_tx_addr[2] || len != pkt[0] + 3)
{//only packets with the required id and packet length
for(uint8_t i=3;i<6;i++)
pktt[i]=0;
return;
}
else
{
for (uint8_t i=3;i<len;i++)
pktt[i]=pkt[i];
telemetry_link=1;
}
}
void compute_RSSIdbm(){
RSSI_dBm = (((uint16_t)(pktt[len-2])*18)>>5);
if(pktt[len-2] >=128)
RSSI_dBm -= 82;
else
RSSI_dBm += 65;
}
#endif
static void frsky2way_init(uint8_t bind)
static void __attribute__((unused)) frsky2way_init(uint8_t bind)
{
// Configure cc2500 for tx mode
CC2500_Reset();
@ -151,7 +48,7 @@ static void frsky2way_init(uint8_t bind)
cc2500_writeReg(CC2500_08_PKTCTRL0, 0x05);
cc2500_writeReg(CC2500_3E_PATABLE, 0xff);
cc2500_writeReg(CC2500_0B_FSCTRL1, 0x08);
cc2500_writeReg(CC2500_0C_FSCTRL0, fine);
cc2500_writeReg(CC2500_0C_FSCTRL0, option);
//base freq FREQ = 0x5C7627 (F = 2404MHz)
cc2500_writeReg(CC2500_0D_FREQ2, 0x5c);
cc2500_writeReg(CC2500_0E_FREQ1, 0x76);
@ -196,7 +93,7 @@ static void frsky2way_init(uint8_t bind)
//#######END INIT########
}
static uint8_t get_chan_num(uint16_t idx)
static uint8_t __attribute__((unused)) get_chan_num(uint16_t idx)
{
uint8_t ret = (idx * 0x1e) % 0xeb;
if(idx == 3 || idx == 23 || idx == 47)
@ -206,7 +103,7 @@ static uint8_t get_chan_num(uint16_t idx)
return ret;
}
static void frsky2way_build_bind_packet()
static void __attribute__((unused)) frsky2way_build_bind_packet()
{
//11 03 01 d7 2d 00 00 1e 3c 5b 78 00 00 00 00 00 00 01
//11 03 01 19 3e 00 02 8e 2f bb 5c 00 00 00 00 00 00 01
@ -231,9 +128,9 @@ static void frsky2way_build_bind_packet()
packet[17] = 0x01;
}
uint8_t telemetry_counter=0;
static void frsky2way_data_frame()
static void __attribute__((unused)) frsky2way_data_frame()
{//pachet[4] is telemetry user frame counter(hub)
//11 d7 2d 22 00 01 c9 c9 ca ca 88 88 ca ca c9 ca 88 88
//11 57 12 00 00 01 f2 f2 f2 f2 06 06 ca ca ca ca 18 18
@ -241,7 +138,8 @@ static void frsky2way_data_frame()
packet[1] = rx_tx_addr[3];
packet[2] = rx_tx_addr[2];
packet[3] = counter;//
packet[4] = pkt[6]?(telemetry_counter++)%32:0;
packet[4]=telemetry_counter;
packet[5] = 0x01;
//
packet[10] = 0;
@ -265,4 +163,102 @@ static void frsky2way_data_frame()
}
}
uint16_t initFrSky_2way()
{
if(IS_AUTOBIND_FLAG_on)
{
frsky2way_init(1);
state = FRSKY_BIND;//
}
else
{
frsky2way_init(0);
state = FRSKY_DATA2;
}
return 10000;
}
#if defined(TELEMETRY)
static void __attribute__((unused)) check_telemetry(uint8_t *pkt,uint8_t len)
{
if(pkt[1] != rx_tx_addr[3] || pkt[2] != rx_tx_addr[2] || len != pkt[0] + 3)
{//only packets with the required id and packet length
for(uint8_t i=3;i<6;i++)
pktt[i]=0;
return;
}
else
{
for (uint8_t i=3;i<len;i++)
pktt[i]=pkt[i];
telemetry_link=1;
if(pktt[6]>0)
telemetry_counter=(telemetry_counter+1)%32;
}
}
#endif
uint16_t ReadFrSky_2way()
{
if (state < FRSKY_BIND_DONE)
{
frsky2way_build_bind_packet();
cc2500_strobe(CC2500_SIDLE);
cc2500_writeReg(CC2500_0A_CHANNR, 0x00);
cc2500_writeReg(CC2500_23_FSCAL3, 0x89);
cc2500_strobe(CC2500_SFRX);//0x3A
cc2500_writeFifo(packet, packet[0]+1);
state++;
return 9000;
}
if (state == FRSKY_BIND_DONE)
{
state = FRSKY_DATA2;
frsky2way_init(0);
counter = 0;
BIND_DONE;
}
else
if (state == FRSKY_DATA5)
{
cc2500_strobe(CC2500_SRX);//0x34 RX enable
state = FRSKY_DATA1;
return 9200;
}
counter = (counter + 1) % 188;
if (state == FRSKY_DATA4)
{ //telemetry receive
CC2500_SetTxRxMode(RX_EN);
cc2500_strobe(CC2500_SIDLE);
cc2500_writeReg(CC2500_0A_CHANNR, get_chan_num(counter % 47));
cc2500_writeReg(CC2500_23_FSCAL3, 0x89);
state++;
return 1300;
}
else
{
if (state == FRSKY_DATA1)
{
len = cc2500_readReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
if (len<=MAX_PKT)//27 bytes
{
cc2500_readFifo(pkt, len); //received telemetry packets
#if defined(TELEMETRY)
//parse telemetry packet here
check_telemetry(pkt,len); //check if valid telemetry packets and buffer them.
#endif
}
CC2500_SetTxRxMode(TX_EN);
CC2500_SetPower(); // Set tx_power
}
cc2500_strobe(CC2500_SIDLE);
cc2500_writeReg(CC2500_0A_CHANNR, get_chan_num(counter % 47));
cc2500_writeReg(CC2500_23_FSCAL3, 0x89);
cc2500_strobe(CC2500_SFRX);
frsky2way_data_frame();
cc2500_writeFifo(packet, packet[0]+1);
state++;
}
return state == FRSKY_DATA4 ? 7500 : 9000;
}
#endif

View File

@ -18,21 +18,21 @@
#include "iface_nrf24l01.h"
#define BIND_COUNT 1000
#define TXID_SIZE 5
#define FREQUENCE_NUM 20
#define HISKY_BIND_COUNT 1000
#define HISKY_TXID_SIZE 5
#define HISKY_FREQUENCE_NUM 20
//
uint8_t bind_buf_arry[4][10];
// HiSky protocol uses TX id as an address for nRF24L01, and uses frequency hopping sequence
// which does not depend on this id and is passed explicitly in binding sequence. So we are free
// to generate this sequence as we wish. It should be in the range [02..77]
static void calc_fh_channels(uint32_t seed)
static void __attribute__((unused)) calc_fh_channels()
{
uint8_t idx = 0;
uint32_t rnd = seed;
uint32_t rnd = MProtocol_id;
while (idx < FREQUENCE_NUM)
while (idx < HISKY_FREQUENCE_NUM)
{
uint8_t i;
uint8_t count_2_26 = 0, count_27_50 = 0, count_51_74 = 0;
@ -41,7 +41,7 @@ static void calc_fh_channels(uint32_t seed)
// Use least-significant byte. 73 is prime, so channels 76..77 are unused
uint8_t next_ch = ((rnd >> 8) % 73) + 2;
// Keep the distance 2 between the channels - either odd or even
if (((next_ch ^ (uint8_t)seed) & 0x01 )== 0)
if (((next_ch ^ (uint8_t)rx_tx_addr[3]) & 0x01 )== 0)
continue;
// Check that it's not duplicated and spread uniformly
for (i = 0; i < idx; i++) {
@ -61,7 +61,7 @@ static void calc_fh_channels(uint32_t seed)
}
}
static void build_binding_packet(void)
static void __attribute__((unused)) build_binding_packet(void)
{
uint8_t i;
uint16_t sum=0;
@ -95,7 +95,7 @@ static void build_binding_packet(void)
}
}
static void hisky_init()
static void __attribute__((unused)) hisky_init()
{
NRF24L01_Initialize();
@ -116,7 +116,7 @@ static void hisky_init()
// HiSky channel sequence: AILE ELEV THRO RUDD GEAR PITCH, channel data value is from 0 to 1000
// Channel 7 - Gyro mode, 0 - 6 axis, 3 - 3 axis
static void build_ch_data()
static void __attribute__((unused)) build_ch_data()
{
uint16_t temp;
uint8_t i,j;
@ -144,10 +144,14 @@ uint16_t hisky_cb()
NRF24L01_SetPower();
phase=2;
break;
case 3:
if (! bind_counter)
NRF24L01_WritePayload(packet,10); // 2 packets per 5ms
break;
case 4:
phase=6;
break;
case 7: // build packet and send failsafe every 100ms
case 7: // build packet with failsafe every 100ms
convert_channel_HK310(hopping_frequency_no!=0?RUDDER:AUX2,&packet[0],&packet[1]);
convert_channel_HK310(hopping_frequency_no!=0?THROTTLE:AUX3,&packet[2],&packet[3]);
convert_channel_HK310(hopping_frequency_no!=0?AUX1:AUX4,&packet[4],&packet[5]);
@ -195,7 +199,7 @@ uint16_t hisky_cb()
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
hopping_frequency_no++;
if (hopping_frequency_no >= FREQUENCE_NUM)
if (hopping_frequency_no >= HISKY_FREQUENCE_NUM)
hopping_frequency_no = 0;
break;
case 7:
@ -213,15 +217,19 @@ uint16_t hisky_cb()
return 1000; // send 1 binding packet and 1 data packet per 9ms
}
// Generate internal id from TX id and manufacturer id (STM32 unique id)
static void initialize_tx_id()
static void __attribute__((unused)) initialize_tx_id()
{
//Generate frequency hopping table
if(sub_protocol==HK310)
for(uint8_t i=0;i<FREQUENCE_NUM;i++)
hopping_frequency[i]=i; // Sequential order hop channels...
{
// for HiSky surface protocol, the transmitter always generates hop channels in sequential order.
// The transmitter only generates the first hop channel between 0 and 49. So the channel range is from 0 to 69.
hopping_frequency_no=rx_tx_addr[0]%50;
for(uint8_t i=0;i<HISKY_FREQUENCE_NUM;i++)
hopping_frequency[i]=hopping_frequency_no++; // Sequential order hop channels...
}
else
calc_fh_channels(MProtocol_id);
calc_fh_channels();
}
uint16_t initHiSky()
@ -234,7 +242,7 @@ uint16_t initHiSky()
binding_idx = 0;
if(IS_AUTOBIND_FLAG_on)
bind_counter = BIND_COUNT;
bind_counter = HISKY_BIND_COUNT;
else
bind_counter = 0;
return 1000;

View File

@ -12,6 +12,7 @@
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 Hubsan H102D, H107/L/C/D and H107P/C+/D+
// Last sync with hexfet new_protocols/hubsan_a7105.c dated 2015-12-11
#if defined(HUBSAN_A7105_INO)
@ -55,7 +56,7 @@ enum {
};
#define WAIT_WRITE 0x80
static void update_crc()
static void __attribute__((unused)) hubsan_update_crc()
{
uint8_t sum = 0;
for(uint8_t i = 0; i < 15; i++)
@ -63,7 +64,7 @@ static void update_crc()
packet[15] = (256 - (sum % 256)) & 0xFF;
}
static void hubsan_build_bind_packet(uint8_t bind_state)
static void __attribute__((unused)) hubsan_build_bind_packet(uint8_t bind_state)
{
static uint8_t handshake_counter;
if(phase < BIND_7)
@ -98,14 +99,14 @@ static void hubsan_build_bind_packet(uint8_t bind_state)
if(phase == BIND_7)
packet[2] = handshake_counter++;
}
update_crc();
hubsan_update_crc();
}
//cc : throttle observed range: 0x00 - 0xFF (smaller is down)
//ee : rudder observed range: 0x34 - 0xcc (smaller is right)52-204-60%
//gg : elevator observed range: 0x3e - 0xbc (smaller is up)62-188 -50%
//ii : aileron observed range: 0x45 - 0xc3 (smaller is right)69-195-50%
static void hubsan_build_packet()
static void __attribute__((unused)) hubsan_build_packet()
{
static uint8_t vtx_freq = 0;
memset(packet, 0, 16);
@ -176,7 +177,7 @@ static void hubsan_build_packet()
packet_count++;
}
}
update_crc();
hubsan_update_crc();
}
#if defined(TELEMETRY)
@ -192,8 +193,10 @@ static void hubsan_build_packet()
uint16_t ReadHubsan()
{
static uint8_t txState=0;
#if defined(TELEMETRY)
static uint8_t rfMode=0;
#endif
static uint8_t txState=0;
static uint8_t bind_count=0;
uint16_t delay;
uint8_t i;
@ -276,7 +279,9 @@ uint16_t ReadHubsan()
case DATA_4:
case DATA_5:
if( txState == 0) { // send packet
#if defined(TELEMETRY)
rfMode = A7105_TX;
#endif
if( phase == DATA_1)
A7105_SetPower(); //Keep transmit power in sync
hubsan_build_packet();

View File

@ -70,6 +70,205 @@ enum {
KN_FLAG_GYROR = 0x80 // Always 0 so far
};
//-------------------------------------------------------------------------------------------------
// This function init 24L01 regs and packet data for binding
// Send tx address, hopping table (for Wl Toys), and data rate to the KN receiver during binding.
// It seems that KN can remember these parameters, no binding needed after power up.
// Bind uses fixed TX address "KNDZK", 1 Mbps data rate and channel 83
//-------------------------------------------------------------------------------------------------
static void __attribute__((unused)) kn_bind_init()
{
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"KNDZK", 5);
packet[0] = 'K';
packet[1] = 'N';
packet[2] = 'D';
packet[3] = 'Z';
//Use first four bytes of tx_addr
packet[4] = rx_tx_addr[0];
packet[5] = rx_tx_addr[1];
packet[6] = rx_tx_addr[2];
packet[7] = rx_tx_addr[3];
if(sub_protocol==WLTOYS)
{
packet[8] = hopping_frequency[0];
packet[9] = hopping_frequency[1];
packet[10] = hopping_frequency[2];
packet[11] = hopping_frequency[3];
}
else
{
packet[8] = 0x00;
packet[9] = 0x00;
packet[10] = 0x00;
packet[11] = 0x00;
}
packet[12] = 0x00;
packet[13] = 0x00;
packet[14] = 0x00;
packet[15] = 0x01; //(USE1MBPS_YES) ? 0x01 : 0x00;
//Set RF channel
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 83);
}
//-------------------------------------------------------------------------------------------------
// Update control data to be sent
// Do it once per frequency, so the same values will be sent 4 times
// KN uses 4 10-bit data channels plus a 8-bit switch channel
//
// The packet[0] is used for pitch/throttle, the relation is hard coded, not changeable.
// We can change the throttle/pitch range though.
//
// How to use trim? V977 stock controller can trim 6-axis mode to eliminate the drift.
//-------------------------------------------------------------------------------------------------
static void __attribute__((unused)) kn_update_packet_control_data()
{
uint16_t value;
value = convert_channel_10b(THROTTLE);
packet[0] = (value >> 8) & 0xFF;
packet[1] = value & 0xFF;
value = convert_channel_10b(AILERON);
packet[2] = (value >> 8) & 0xFF;
packet[3] = value & 0xFF;
value = convert_channel_10b(ELEVATOR);
packet[4] = (value >> 8) & 0xFF;
packet[5] = value & 0xFF;
value = convert_channel_10b(RUDDER);
packet[6] = (value >> 8) & 0xFF;
packet[7] = value & 0xFF;
// Trims, middle is 0x64 (100) range 0-200
packet[8] = convert_channel_8b_scale(AUX5,0,200); // 0x64; // T
packet[9] = convert_channel_8b_scale(AUX6,0,200); // 0x64; // A
packet[10] = convert_channel_8b_scale(AUX7,0,200); // 0x64; // E
packet[11] = 0x64; // R
flags=0;
if (Servo_data[AUX1] > PPM_SWITCH)
flags = KN_FLAG_DR;
if (Servo_data[AUX2] > PPM_SWITCH)
flags |= KN_FLAG_TH;
if (Servo_data[AUX3] > PPM_SWITCH)
flags |= KN_FLAG_IDLEUP;
if (Servo_data[AUX4] > PPM_SWITCH)
flags |= KN_FLAG_GYRO3;
packet[12] = flags;
packet[13] = 0x00;
if(sub_protocol==WLTOYS)
packet[13] = (packet_sent << 5) | (hopping_frequency_no << 2);
packet[14] = 0x00;
packet[15] = 0x00;
NRF24L01_SetPower();
}
//-------------------------------------------------------------------------------------------------
// This function generate RF TX packet address
// V977 can remember the binding parameters; we do not need rebind when power up.
// This requires the address must be repeatable for a specific RF ID at power up.
//-------------------------------------------------------------------------------------------------
static void __attribute__((unused)) kn_calculate_tx_addr()
{
if(sub_protocol==FEILUN)
{
uint8_t addr2;
// Generate TXID with sum of minimum 256 and maximum 256+MAX_RF_CHANNEL-32
rx_tx_addr[1] = 1 + rx_tx_addr[0] % (KN_MAX_RF_CHANNEL-33);
addr2 = 1 + rx_tx_addr[2] % (KN_MAX_RF_CHANNEL-33);
if ((uint16_t)(rx_tx_addr[0] + rx_tx_addr[1]) < 256)
rx_tx_addr[2] = addr2;
else
rx_tx_addr[2] = 0x00;
rx_tx_addr[3] = 0x00;
while((uint16_t)(rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2] + rx_tx_addr[3]) < 257)
rx_tx_addr[3] += addr2;
}
//The 5th byte is a constant, must be 'K'
rx_tx_addr[4] = 'K';
}
//-------------------------------------------------------------------------------------------------
// This function generates "random" RF hopping frequency channel numbers.
// These numbers must be repeatable for a specific seed
// The generated number range is from 0 to MAX_RF_CHANNEL. No repeat or adjacent numbers
//
// For Feilun variant, the channels are calculated from TXID, and since only 2 channels are used
// we copy them to fill up to MAX_RF_CHANNEL
//-------------------------------------------------------------------------------------------------
static void __attribute__((unused)) kn_calculate_freqency_hopping_channels()
{
if(sub_protocol==WLTOYS)
{
uint8_t idx = 0;
uint32_t rnd = MProtocol_id;
while (idx < KN_RF_CH_COUNT)
{
uint8_t i;
rnd = rnd * 0x0019660D + 0x3C6EF35F; // Randomization
// Use least-significant byte. 73 is prime, so channels 76..77 are unused
uint8_t next_ch = ((rnd >> 8) % KN_MAX_RF_CHANNEL) + 2;
// Keep the distance 2 between the channels - either odd or even
if (((next_ch ^ MProtocol_id) & 0x01 )== 0)
continue;
// Check that it's not duplicate and spread uniformly
for (i = 0; i < idx; i++)
if(hopping_frequency[i] == next_ch)
break;
if (i != idx)
continue;
hopping_frequency[idx++] = next_ch;
}
}
else
{//FEILUN
hopping_frequency[0] = rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2] + rx_tx_addr[3]; // - 256; ???
hopping_frequency[1] = hopping_frequency[0] + 32;
hopping_frequency[2] = hopping_frequency[0];
hopping_frequency[3] = hopping_frequency[1];
}
}
//-------------------------------------------------------------------------------------------------
// This function setup 24L01
// V977 uses one way communication, receiving only. 24L01 RX is never enabled.
// V977 needs payload length in the packet. We should configure 24L01 to enable Packet Control Field(PCF)
// Some RX reg settings are actually for enable PCF
//-------------------------------------------------------------------------------------------------
static void __attribute__((unused)) kn_init()
{
kn_calculate_tx_addr();
kn_calculate_freqency_hopping_channels();
NRF24L01_Initialize();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO));
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknoledgement
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0); // Disable retransmit
NRF24L01_SetPower();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 0x20); // bytes of data payload for pipe 0
NRF24L01_Activate(0x73);
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 1); // Dynamic payload for data pipe 0
// Enable: Dynamic Payload Length to enable PCF
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, BV(NRF2401_1D_EN_DPL));
NRF24L01_SetPower();
NRF24L01_FlushTx();
// Turn radio power on
NRF24L01_SetTxRxMode(TX_EN);
NRF24L01_SetBitrate(NRF24L01_BR_1M); //USE1MBPS_YES ? NRF24L01_BR_1M : NRF24L01_BR_250K;
}
//================================================================================================
// Private Functions
//================================================================================================
@ -145,202 +344,4 @@ uint16_t kn_callback()
return packet_period;
}
//-------------------------------------------------------------------------------------------------
// This function init 24L01 regs and packet data for binding
// Send tx address, hopping table (for Wl Toys), and data rate to the KN receiver during binding.
// It seems that KN can remember these parameters, no binding needed after power up.
// Bind uses fixed TX address "KNDZK", 1 Mbps data rate and channel 83
//-------------------------------------------------------------------------------------------------
static void kn_bind_init()
{
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"KNDZK", 5);
packet[0] = 'K';
packet[1] = 'N';
packet[2] = 'D';
packet[3] = 'Z';
//Use first four bytes of tx_addr
packet[4] = rx_tx_addr[0];
packet[5] = rx_tx_addr[1];
packet[6] = rx_tx_addr[2];
packet[7] = rx_tx_addr[3];
if(sub_protocol==WLTOYS)
{
packet[8] = hopping_frequency[0];
packet[9] = hopping_frequency[1];
packet[10] = hopping_frequency[2];
packet[11] = hopping_frequency[3];
}
else
{
packet[8] = 0x00;
packet[9] = 0x00;
packet[10] = 0x00;
packet[11] = 0x00;
}
packet[12] = 0x00;
packet[13] = 0x00;
packet[14] = 0x00;
packet[15] = 0x01; //(USE1MBPS_YES) ? 0x01 : 0x00;
//Set RF channel
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 83);
}
//-------------------------------------------------------------------------------------------------
// Update control data to be sent
// Do it once per frequency, so the same values will be sent 4 times
// KN uses 4 10-bit data channels plus a 8-bit switch channel
//
// The packet[0] is used for pitch/throttle, the relation is hard coded, not changeable.
// We can change the throttle/pitch range though.
//
// How to use trim? V977 stock controller can trim 6-axis mode to eliminate the drift.
//-------------------------------------------------------------------------------------------------
static void kn_update_packet_control_data()
{
uint16_t value;
value = convert_channel_10b(THROTTLE);
packet[0] = (value >> 8) & 0xFF;
packet[1] = value & 0xFF;
value = convert_channel_10b(AILERON);
packet[2] = (value >> 8) & 0xFF;
packet[3] = value & 0xFF;
value = convert_channel_10b(ELEVATOR);
packet[4] = (value >> 8) & 0xFF;
packet[5] = value & 0xFF;
value = convert_channel_10b(RUDDER);
packet[6] = (value >> 8) & 0xFF;
packet[7] = value & 0xFF;
// Trims, middle is 0x64 (100) range 0-200
packet[8] = convert_channel_8b_scale(AUX5,0,200); // 0x64; // T
packet[9] = convert_channel_8b_scale(AUX6,0,200); // 0x64; // A
packet[10] = convert_channel_8b_scale(AUX7,0,200); // 0x64; // E
packet[11] = 0x64; // R
flags=0;
if (Servo_data[AUX1] > PPM_SWITCH)
flags = KN_FLAG_DR;
if (Servo_data[AUX2] > PPM_SWITCH)
flags |= KN_FLAG_TH;
if (Servo_data[AUX3] > PPM_SWITCH)
flags |= KN_FLAG_IDLEUP;
if (Servo_data[AUX4] > PPM_SWITCH)
flags |= KN_FLAG_GYRO3;
packet[12] = flags;
packet[13] = 0x00;
if(sub_protocol==WLTOYS)
packet[13] = (packet_sent << 5) | (hopping_frequency_no << 2);
packet[14] = 0x00;
packet[15] = 0x00;
NRF24L01_SetPower();
}
//-------------------------------------------------------------------------------------------------
// This function setup 24L01
// V977 uses one way communication, receiving only. 24L01 RX is never enabled.
// V977 needs payload length in the packet. We should configure 24L01 to enable Packet Control Field(PCF)
// Some RX reg settings are actually for enable PCF
//-------------------------------------------------------------------------------------------------
static void kn_init()
{
kn_calculate_tx_addr();
kn_calculate_freqency_hopping_channels();
NRF24L01_Initialize();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO));
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknoledgement
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0); // Disable retransmit
NRF24L01_SetPower();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 0x20); // bytes of data payload for pipe 0
NRF24L01_Activate(0x73);
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 1); // Dynamic payload for data pipe 0
// Enable: Dynamic Payload Length to enable PCF
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, BV(NRF2401_1D_EN_DPL));
NRF24L01_SetPower();
NRF24L01_FlushTx();
// Turn radio power on
NRF24L01_SetTxRxMode(TX_EN);
NRF24L01_SetBitrate(NRF24L01_BR_1M); //USE1MBPS_YES ? NRF24L01_BR_1M : NRF24L01_BR_250K;
}
//-------------------------------------------------------------------------------------------------
// This function generate RF TX packet address
// V977 can remember the binding parameters; we do not need rebind when power up.
// This requires the address must be repeatable for a specific RF ID at power up.
//-------------------------------------------------------------------------------------------------
static void kn_calculate_tx_addr()
{
if(sub_protocol==FEILUN)
{
uint8_t addr2;
// Generate TXID with sum of minimum 256 and maximum 256+MAX_RF_CHANNEL-32
rx_tx_addr[1] = 1 + rx_tx_addr[0] % (KN_MAX_RF_CHANNEL-33);
addr2 = 1 + rx_tx_addr[2] % (KN_MAX_RF_CHANNEL-33);
if ((uint16_t)(rx_tx_addr[0] + rx_tx_addr[1]) < 256)
rx_tx_addr[2] = addr2;
else
rx_tx_addr[2] = 0x00;
rx_tx_addr[3] = 0x00;
while((uint16_t)(rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2] + rx_tx_addr[3]) < 257)
rx_tx_addr[3] += addr2;
}
//The 5th byte is a constant, must be 'K'
rx_tx_addr[4] = 'K';
}
//-------------------------------------------------------------------------------------------------
// This function generates "random" RF hopping frequency channel numbers.
// These numbers must be repeatable for a specific seed
// The generated number range is from 0 to MAX_RF_CHANNEL. No repeat or adjacent numbers
//
// For Feilun variant, the channels are calculated from TXID, and since only 2 channels are used
// we copy them to fill up to MAX_RF_CHANNEL
//-------------------------------------------------------------------------------------------------
static void kn_calculate_freqency_hopping_channels()
{
if(sub_protocol==WLTOYS)
{
uint8_t idx = 0;
uint32_t rnd = MProtocol_id;
while (idx < KN_RF_CH_COUNT)
{
uint8_t i;
rnd = rnd * 0x0019660D + 0x3C6EF35F; // Randomization
// Use least-significant byte. 73 is prime, so channels 76..77 are unused
uint8_t next_ch = ((rnd >> 8) % KN_MAX_RF_CHANNEL) + 2;
// Keep the distance 2 between the channels - either odd or even
if (((next_ch ^ MProtocol_id) & 0x01 )== 0)
continue;
// Check that it's not duplicate and spread uniformly
for (i = 0; i < idx; i++)
if(hopping_frequency[i] == next_ch)
break;
if (i != idx)
continue;
hopping_frequency[idx++] = next_ch;
}
}
else
{//FEILUN
hopping_frequency[0] = rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2] + rx_tx_addr[3]; // - 256; ???
hopping_frequency[1] = hopping_frequency[0] + 32;
hopping_frequency[2] = hopping_frequency[0];
hopping_frequency[3] = hopping_frequency[1];
}
}
#endif

View File

@ -1,11 +1,11 @@
/*********************************************************
Multiprotocol Tx code
by Midelic and Pascal Langer(hpnuts)
http://www.rcgroups.com/forums/showthread.php?t=2165676
Multiprotocol Tx code
by Midelic and Pascal Langer(hpnuts)
http://www.rcgroups.com/forums/showthread.php?t=2165676
https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/edit/master/README.md
Thanks to PhracturedBlue
Ported from deviation firmware
Thanks to PhracturedBlue, Hexfet, Goebish and all protocol developers
Ported from deviation firmware
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
@ -23,71 +23,10 @@
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
//******************************************************
//******************************************************
// Multiprotocol module configuration starts here
//Uncomment the type of TX
#define TX_ER9X //ER9X AETR (988<->2012µs)
//#define TX_DEVO7 //DEVO7 EATR (1120<->1920µs)
//#define TX_SPEKTRUM //Spektrum TAER (1100<->1900µs)
//#define TX_HISKY //HISKY AETR (1100<->1900µs)
#include "multiprotocol.h"
//Uncomment to enable 8 channels serial protocol, 16 otherwise
//#define NUM_SERIAL_CH_8
//Uncomment to enable telemetry
#define TELEMETRY
//Comment protocols to exclude from compilation
#define BAYANG_NRF24L01_INO
#define CG023_NRF24L01_INO
#define CX10_NRF24L01_INO
#define DEVO_CYRF6936_INO
#define DSM2_CYRF6936_INO
#define ESKY_NRF24L01_INO
#define FLYSKY_A7105_INO
#define FRSKY_CC2500_INO
#define HISKY_NRF24L01_INO
#define HUBSAN_A7105_INO
#define KN_NRF24L01_INO
#define SLT_NRF24L01_INO
#define SYMAX_NRF24L01_INO
#define V2X2_NRF24L01_INO
#define YD717_NRF24L01_INO
//#define FRSKYX_CC2500_INO
//Update this table to set which protocol/sub_protocol is called for the corresponding dial number
static const uint8_t PPM_prot[15][2]= { {MODE_FLYSKY , Flysky }, //Dial=1
{MODE_HUBSAN , 0 }, //Dial=2
{MODE_FRSKY , 0 }, //Dial=3
{MODE_HISKY , Hisky }, //Dial=4
{MODE_V2X2 , 0 }, //Dial=5
{MODE_DSM2 , DSM2 }, //Dial=6
{MODE_DEVO , 0 }, //Dial=7
{MODE_YD717 , YD717 }, //Dial=8
{MODE_KN , WLTOYS }, //Dial=9
{MODE_SYMAX , SYMAX }, //Dial=10
{MODE_SLT , 0 }, //Dial=11
{MODE_CX10 , CX10_BLUE }, //Dial=12
{MODE_CG023 , CG023 }, //Dial=13
{MODE_BAYANG , 0 }, //Dial=14
{MODE_SYMAX , SYMAX5C } //Dial=15
};
//CC2500 RF module frequency adjustment, use in case you cannot bind with Frsky RX
//Note: this is set via Option when serial protocol is used
//values from 0-127 offset increase frequency, values from 255 to 127 decrease base frequency
//uint8_t fine = 0x00;
uint8_t fine = 0xd7; //* 215=-41 *
// Multiprotocol module configuration ends here
//******************************************************
//******************************************************
//Multiprotocol module configuration file
#include "_Config.h"
//Global constants/variables
@ -126,17 +65,18 @@ uint8_t hopping_frequency_no=0;
uint8_t rf_ch_num;
uint8_t throttle, rudder, elevator, aileron;
uint8_t flags;
//
uint32_t state;
uint8_t len;
uint8_t RX_num;
// Mode_select variables
uint8_t mode_select;
uint8_t ppm_select;
uint8_t protocol_flags=0,protocol_flags2=0;
// Serial variables
#if defined(NUM_SERIAL_CH_8) //8 channels serial protocol
#define RXBUFFER_SIZE 14
#else //16 channels serial protocol
#define RXBUFFER_SIZE 25
#endif
#define TXBUFFER_SIZE 12
volatile uint8_t rx_buff[RXBUFFER_SIZE];
volatile uint8_t rx_ok_buff[RXBUFFER_SIZE];
@ -150,16 +90,17 @@ uint8_t cur_protocol[2];
uint8_t prev_protocol=0;
// Telemetry
#define MAX_PKT 27
uint8_t pkt[MAX_PKT];//telemetry receiving packets
#if defined(TELEMETRY)
uint8_t pkt[27];//telemetry receiving packets
uint8_t pktt[27];//telemetry receiving packets
volatile uint8_t tx_head;
volatile uint8_t tx_tail;
uint8_t v_lipo;
int16_t RSSI_dBm;
//const uint8_t RSSI_offset=72;//69 71.72 values db
uint8_t telemetry_link=0;
#include "telemetry.h"
uint8_t pktt[MAX_PKT];//telemetry receiving packets
volatile uint8_t tx_head;
volatile uint8_t tx_tail;
uint8_t v_lipo;
int16_t RSSI_dBm;
//const uint8_t RSSI_offset=72;//69 71.72 values db
uint8_t telemetry_link=0;
#include "telemetry.h"
#endif
// Callback
@ -183,91 +124,96 @@ void setup()
CC25_CSN_on;
NRF_CSN_on;
CYRF_CSN_on;
// Set SPI lines
// Set SPI lines
SDI_on;
SCK_off;
// Timer1 config
TCCR1A = 0;
TCCR1B = (1 << CS11); //prescaler8, set timer1 to increment every 0.5us(16Mhz) and start timer
TCCR1B = (1 << CS11); //prescaler8, set timer1 to increment every 0.5us(16Mhz) and start timer
// Set servos positions
for(uint8_t i=0;i<NUM_CHN;i++)
Servo_data[i]=1500;
Servo_data[THROTTLE]=PPM_MIN_100;
memcpy((void *)PPM_data,Servo_data, sizeof(Servo_data));
// Read status of bind button
if( (PINB & _BV(5)) == 0x00 )
BIND_BUTTON_FLAG_on; // If bind button pressed save the status for protocol id reset under hubsan
BIND_BUTTON_FLAG_on; // If bind button pressed save the status for protocol id reset under hubsan
// Read status of mode select binary switch
// after this mode_select will be one of {0000, 0001, ..., 1111}
mode_select=0x0F - ( ( (PINB>>2)&0x07 ) | ( (PINC<<3)&0x08) );//encoder dip switches 1,2,4,8=>B2,B3,B4,C0
//**********************************
//mode_select=14; // here to test PPM
//**********************************
//**********************************
//mode_select=14; // here to test PPM
//**********************************
// Update LED
LED_OFF;
LED_OFF;
LED_SET_OUTPUT;
// Read or create protocol id
MProtocol_id=random_id(10,false);
MProtocol_id_master=MProtocol_id;
//Set power transmission flags
POWER_FLAG_on; //By default high power for everything
MProtocol_id_master=random_id(10,false);
//Init RF modules
CC2500_Reset();
//Protocol and interrupts initialization
if(mode_select != MODE_SERIAL)
{ // PPM
cur_protocol[0]= PPM_prot[mode_select-1][0];
sub_protocol = PPM_prot[mode_select-1][1];
protocol_init(cur_protocol[0]);
//Configure PPM interrupt
EICRA |=(1<<ISC11); // The rising edge of INT1 pin D3 generates an interrupt request
EIMSK |= (1<<INT1); // INT1 interrupt enable
}
else
#if !defined(POTAR_SELECT)
if(mode_select == MODE_SERIAL)
{ // Serial
cur_protocol[0]=0;
cur_protocol[1]=0;
prev_protocol=0;
Mprotocol_serial_init(); // Configure serial and enable RX interrupt
}
else
#endif
{ // PPM
prev_protocol=0;
CHANGE_PROTOCOL_FLAG_on;
update_ppm_data();
//Configure PPM interrupt
EICRA |=(1<<ISC11); // The rising edge of INT1 pin D3 generates an interrupt request
EIMSK |= (1<<INT1); // INT1 interrupt enable
#if defined(TELEMETRY)
PPM_Telemetry_serial_init(); // Configure serial for telemetry
#endif
}
}
// Main
void loop()
{
#if !defined(POTAR_SELECT)
if(mode_select==MODE_SERIAL && IS_RX_FLAG_on) // Serial mode and something has been received
{
update_serial_data(); // Update protocol and data
update_serial_data(); // Update protocol and data
update_aux_flags();
if(IS_CHANGE_PROTOCOL_FLAG_on)
{ // Protocol needs to be changed
LED_OFF; //led off during protocol init
module_reset(); //reset previous module
protocol_init(cur_protocol[0]&0x1F); //init new protocol
CHANGE_PROTOCOL_FLAG_off; //done
}
}
#endif
if(mode_select!=MODE_SERIAL && IS_PPM_FLAG_on) // PPM mode and a full frame has been received
{
for(uint8_t i=0;i<NUM_CHN;i++)
{ // update servo data without interrupts to prevent bad read in protocols
cli(); // disable global int
cli(); // disable global int
Servo_data[i]=PPM_data[i];
sei(); // enable global int
update_aux_flags();
sei(); // enable global int
}
PPM_FLAG_off; // wait for next frame before update
update_aux_flags();
PPM_FLAG_off; // wait for next frame before update
}
if(IS_CHANGE_PROTOCOL_FLAG_on) { // Protocol needs to be changed
LED_OFF; //led off during protocol init
module_reset(); //reset previous module
protocol_init(); //init new protocol
CHANGE_PROTOCOL_FLAG_off; //done
}
update_led_status();
#if defined(TELEMETRY)
if(((cur_protocol[0]&0x1F)==MODE_FRSKY)||((cur_protocol[0]&0x1F)==MODE_HUBSAN))
if( ((cur_protocol[0]&0x1F)==MODE_FRSKY) || ((cur_protocol[0]&0x1F)==MODE_HUBSAN) || ((cur_protocol[0]&0x1F)==MODE_FRSKYX) )
frskyUpdate();
#endif
if (remote_callback != 0)
@ -279,7 +225,11 @@ static void update_aux_flags(void)
{
Servo_AUX=0;
for(uint8_t i=0;i<8;i++)
if(Servo_data[AUX1+i]>PPM_SWITCH)
#if defined(POTAR_SELECT)
if(Servo_data[AUX2+i]>PPM_SWITCH)
#else
if(Servo_data[AUX1+i]>PPM_SWITCH)
#endif
Servo_AUX|=1<<i;
}
@ -288,21 +238,21 @@ static void update_led_status(void)
{
if(blink<millis())
{
if(cur_protocol[0]==0) // No valid serial received at least once
blink+=BLINK_SERIAL_TIME; //blink slowly while waiting a valid serial input
if(cur_protocol[0]==0) // No valid serial received at least once
blink+=BLINK_SERIAL_TIME; //blink slowly while waiting a valid serial input
else
if(remote_callback == 0)
{ // Invalid protocol
if(IS_LED_on) //flash to indicate invalid protocol
blink+=BLINK_BAD_PROTO_TIME_LOW;
else
blink+=BLINK_BAD_PROTO_TIME_HIGH;
}
if(IS_LED_on) //flash to indicate invalid protocol
blink+=BLINK_BAD_PROTO_TIME_LOW;
else
blink+=BLINK_BAD_PROTO_TIME_HIGH;
}
else
if(IS_BIND_DONE_on)
LED_OFF; //bind completed -> led on
else
blink+=BLINK_BIND_TIME; //blink fastly during binding
LED_OFF; //bind completed -> led on
else
blink+=BLINK_BIND_TIME; //blink fastly during binding
LED_TOGGLE;
}
}
@ -314,34 +264,35 @@ static void CheckTimer(uint16_t (*cb)(void))
uint32_t prev;
if( (TIFR1 & (1<<OCF1A)) != 0)
{
cli(); // disable global int
OCR1A=TCNT1; // Callback should already have been called... Use "now" as new sync point.
sei(); // enable global int
cli(); // disable global int
OCR1A=TCNT1; // Callback should already have been called... Use "now" as new sync point.
sei(); // enable global int
}
else
while((TIFR1 & (1<<OCF1A)) == 0); // wait before callback
prev=micros();
while((TIFR1 & (1<<OCF1A)) == 0); // wait before callback
prev=micros();
next_callback=cb();
if(prev+next_callback+50 > micros())
{ // Callback did not took more than requested time for next callback
if(next_callback>32000)
{ // next_callback should not be more than 32767 so we will wait here...
delayMicroseconds(next_callback-2000);
cli(); // disable global int
cli(); // disable global int
OCR1A=TCNT1+4000;
sei(); // enable global int
sei(); // enable global int
}
else
{
cli(); // disable global int
OCR1A+=next_callback*2; // set compare A for callback
sei(); // enable global int
cli(); // disable global int
OCR1A+=next_callback*2; // set compare A for callback
sei(); // enable global int
}
TIFR1=(1<<OCF1A); // clear compare A=callback flag
TIFR1=(1<<OCF1A); // clear compare A=callback flag
}
}
static void protocol_init(uint8_t protocol)
// Protocol start
static void protocol_init()
{
uint16_t next_callback=0; // Default is immediate call back
remote_callback = 0;
@ -351,218 +302,265 @@ static void protocol_init(uint8_t protocol)
if(IS_BIND_BUTTON_FLAG_on)
AUTOBIND_FLAG_on;
if(IS_AUTOBIND_FLAG_on)
BIND_IN_PROGRESS; // Indicates bind in progress for blinking bind led
BIND_IN_PROGRESS; // Indicates bind in progress for blinking bind led
else
BIND_DONE;
CTRL1_on; //NRF24L01 antenna RF3 by default
CTRL2_off; //NRF24L01 antenna RF3 by default
switch(protocol) // Init the requested protocol
CTRL1_on; //NRF24L01 antenna RF3 by default
CTRL2_off; //NRF24L01 antenna RF3 by default
switch(cur_protocol[0]&0x1F) // Init the requested protocol
{
#if defined(FLYSKY_A7105_INO)
case MODE_FLYSKY:
CTRL1_off; //antenna RF1
next_callback = initFlySky();
remote_callback = ReadFlySky;
break;
case MODE_FLYSKY:
CTRL1_off; //antenna RF1
next_callback = initFlySky();
remote_callback = ReadFlySky;
break;
#endif
#if defined(HUBSAN_A7105_INO)
case MODE_HUBSAN:
CTRL1_off; //antenna RF1
if(IS_BIND_BUTTON_FLAG_on) random_id(10,true); // Generate new ID if bind button is pressed.
next_callback = initHubsan();
remote_callback = ReadHubsan;
break;
case MODE_HUBSAN:
CTRL1_off; //antenna RF1
if(IS_BIND_BUTTON_FLAG_on) random_id(10,true); // Generate new ID if bind button is pressed.
next_callback = initHubsan();
remote_callback = ReadHubsan;
break;
#endif
#if defined(FRSKY_CC2500_INO)
case MODE_FRSKY:
CTRL1_off; //antenna RF2
CTRL2_on;
next_callback = initFrSky_2way();
remote_callback = ReadFrSky_2way;
break;
case MODE_FRSKY:
CTRL1_off; //antenna RF2
CTRL2_on;
next_callback = initFrSky_2way();
remote_callback = ReadFrSky_2way;
break;
#endif
#if defined(FRSKYX_CC2500_INO)
case MODE_FRSKYX:
CTRL1_off; //antenna RF2
CTRL2_on;
next_callback = initFrSkyX();
remote_callback = ReadFrSkyX;
break;
case MODE_FRSKYX:
CTRL1_off; //antenna RF2
CTRL2_on;
next_callback = initFrSkyX();
remote_callback = ReadFrSkyX;
break;
#endif
#if defined(DSM2_CYRF6936_INO)
case MODE_DSM2:
CTRL2_on; //antenna RF4
next_callback = initDsm2();
//Servo_data[2]=1500;//before binding
remote_callback = ReadDsm2;
break;
case MODE_DSM2:
CTRL2_on; //antenna RF4
next_callback = initDsm2();
//Servo_data[2]=1500;//before binding
remote_callback = ReadDsm2;
break;
#endif
#if defined(DEVO_CYRF6936_INO)
case MODE_DEVO:
CTRL2_on; //antenna RF4
next_callback = DevoInit();
remote_callback = devo_callback;
break;
case MODE_DEVO:
CTRL2_on; //antenna RF4
next_callback = DevoInit();
remote_callback = devo_callback;
break;
#endif
#if defined(HISKY_NRF24L01_INO)
case MODE_HISKY:
next_callback=initHiSky();
remote_callback = hisky_cb;
break;
case MODE_HISKY:
next_callback=initHiSky();
remote_callback = hisky_cb;
break;
#endif
#if defined(V2X2_NRF24L01_INO)
case MODE_V2X2:
next_callback = initV2x2();
remote_callback = ReadV2x2;
break;
case MODE_V2X2:
next_callback = initV2x2();
remote_callback = ReadV2x2;
break;
#endif
#if defined(YD717_NRF24L01_INO)
case MODE_YD717:
next_callback=initYD717();
remote_callback = yd717_callback;
break;
case MODE_YD717:
next_callback=initYD717();
remote_callback = yd717_callback;
break;
#endif
#if defined(KN_NRF24L01_INO)
case MODE_KN:
next_callback = initKN();
remote_callback = kn_callback;
break;
case MODE_KN:
next_callback = initKN();
remote_callback = kn_callback;
break;
#endif
#if defined(SYMAX_NRF24L01_INO)
case MODE_SYMAX:
next_callback = initSymax();
remote_callback = symax_callback;
break;
case MODE_SYMAX:
next_callback = initSymax();
remote_callback = symax_callback;
break;
#endif
#if defined(SLT_NRF24L01_INO)
case MODE_SLT:
next_callback=initSLT();
remote_callback = SLT_callback;
break;
case MODE_SLT:
next_callback=initSLT();
remote_callback = SLT_callback;
break;
#endif
#if defined(CX10_NRF24L01_INO)
case MODE_CX10:
next_callback=initCX10();
remote_callback = CX10_callback;
break;
case MODE_CX10:
next_callback=initCX10();
remote_callback = CX10_callback;
break;
#endif
#if defined(CG023_NRF24L01_INO)
case MODE_CG023:
next_callback=initCG023();
remote_callback = CG023_callback;
break;
case MODE_CG023:
next_callback=initCG023();
remote_callback = CG023_callback;
break;
#endif
#if defined(BAYANG_NRF24L01_INO)
case MODE_BAYANG:
next_callback=initBAYANG();
remote_callback = BAYANG_callback;
break;
case MODE_BAYANG:
next_callback=initBAYANG();
remote_callback = BAYANG_callback;
break;
#endif
#if defined(ESKY_NRF24L01_INO)
case MODE_ESKY:
next_callback=initESKY();
remote_callback = ESKY_callback;
break;
case MODE_ESKY:
next_callback=initESKY();
remote_callback = ESKY_callback;
break;
#endif
}
// Ajout protocol
#if defined(H7_NRF24L01_INO)
case MODE_H7:
next_callback=H7_init();
remote_callback = process_H7;
break;
#endif
#if defined(HM830_NRF24L01_INO)
case MODE_HM830:
next_callback=HM830_setup();
remote_callback = HM830_callback;
break;
#endif
}
if(next_callback>32000)
{ // next_callback should not be more than 32767 so we will wait here...
delayMicroseconds(next_callback-2000);
next_callback=2000;
}
cli(); // disable global int
OCR1A=TCNT1+next_callback*2; // set compare A for callback
sei(); // enable global int
TIFR1=(1<<OCF1A); // clear compare A flag
BIND_BUTTON_FLAG_off; // do not bind/reset id anymore even if protocol change
cli(); // disable global int
OCR1A=TCNT1+next_callback*2; // set compare A for callback
sei(); // enable global int
TIFR1=(1<<OCF1A); // clear compare A flag
BIND_BUTTON_FLAG_off; // do not bind/reset id anymore even if protocol change
}
static void update_ppm_data() {
#if defined(POTAR_SELECT)
if(Servo_data[AUX1+i]>PPM_SWITCH) { CHANGE_PROTOCOL_FLAG_on; }
#endif
if(IS_CHANGE_PROTOCOL_FLAG_on) {
prev_protocol = ppm_select;
ppm_select = 0;
// protocol selection
// THROTTLE up
if(Servo_data[POTAR_SELECT_M] > PPM_MAX_COMMAND) { ppm_select += 18; }
// THROTTLE down
else if(Servo_data[POTAR_SELECT_M] < PPM_MIN_COMMAND) { ppm_select += 9; }
// THROTTLE middle
else { ppm_select += 0; }
// Elevator up
if(Servo_data[POTAR_SELECT_V] > PPM_MAX_COMMAND) { ppm_select += 7; }
// Elevator down
else if(Servo_data[POTAR_SELECT_V] < PPM_MIN_COMMAND) { ppm_select += 1; }
// Elevator middle
else { ppm_select += 4; }
// Aileron right
if(Servo_data[POTAR_SELECT_H] > PPM_MAX_COMMAND) { ppm_select += 2; }
// Aileron left
else if(Servo_data[POTAR_SELECT_H] < PPM_MIN_COMMAND) { ppm_select += 0; }
// Aileron middle
else { ppm_select += 1; }
// if(ppm_select == 5) { ppm_select = eeprom_read_byte(30); } else { eeprom_update_byte(30, ppm_select); }
if(ppm_select > 5) { ppm_select--; }
if(mode_select > MODE_SERIAL) {
ppm_select--;
cur_protocol[0] = PPM_prot[ppm_select].protocol;
sub_protocol = PPM_prot[ppm_select].sub_proto;
MProtocol_id = PPM_prot[ppm_select].rx_num + MProtocol_id_master;
option = PPM_prot[ppm_select].option;
if(PPM_prot[ppm_select].power) POWER_FLAG_on;
if(PPM_prot[ppm_select].autobind) AUTOBIND_FLAG_on;
ppm_select++;
}
}
}
static void update_serial_data()
{
if(rx_ok_buff[0]&0x20) //check range
RANGE_FLAG_on;
else
RANGE_FLAG_off;
if(rx_ok_buff[0]&0xC0) //check autobind(0x40) & bind(0x80) together
AUTOBIND_FLAG_on;
else
AUTOBIND_FLAG_off;
if(rx_ok_buff[1]&0x80) //if rx_ok_buff[1] ==1,power is low ,0-power high
POWER_FLAG_off; //power low
else
POWER_FLAG_on; //power high
option=rx_ok_buff[2];
fine=option; // Update FrSky fine tuning
if(rx_ok_buff[0]&0x20) //check range
RANGE_FLAG_on;
else
RANGE_FLAG_off;
if(rx_ok_buff[0]&0xC0) //check autobind(0x40) & bind(0x80) together
AUTOBIND_FLAG_on;
else
AUTOBIND_FLAG_off;
if(rx_ok_buff[1]&0x80) //if rx_ok_buff[1] ==1,power is low ,0-power high
POWER_FLAG_off; //power low
else
POWER_FLAG_on; //power high
option=rx_ok_buff[2];
if( ((rx_ok_buff[0]&0x5F) != (cur_protocol[0]&0x5F)) || ( (rx_ok_buff[1]&0x7F) != cur_protocol[1] ) )
{ // New model has been selected
prev_protocol=cur_protocol[0]&0x1F; //store previous protocol so we can reset the module
cur_protocol[1] = rx_ok_buff[1]&0x7F; //store current protocol
CHANGE_PROTOCOL_FLAG_on; //change protocol
sub_protocol=(rx_ok_buff[1]>>4)& 0x07; //subprotocol no (0-7) bits 4-6
MProtocol_id=MProtocol_id_master+(rx_ok_buff[1]& 0x0F); //personalized RX bind + rx num // rx_num bits 0---3
}
prev_protocol=cur_protocol[0]&0x1F; //store previous protocol so we can reset the module
cur_protocol[1] = rx_ok_buff[1]&0x7F; //store current protocol
CHANGE_PROTOCOL_FLAG_on; //change protocol
sub_protocol=(rx_ok_buff[1]>>4)& 0x07; //subprotocol no (0-7) bits 4-6
RX_num=rx_ok_buff[1]& 0x0F;
MProtocol_id=MProtocol_id_master+RX_num; //personalized RX bind + rx num // rx_num bits 0---3
}
else
if( ((rx_ok_buff[0]&0x80)!=0) && ((cur_protocol[0]&0x80)==0) ) // Bind flag has been set
CHANGE_PROTOCOL_FLAG_on; //restart protocol with bind
cur_protocol[0] = rx_ok_buff[0]; //store current protocol
if( ((rx_ok_buff[0]&0x80)!=0) && ((cur_protocol[0]&0x80)==0) ) // Bind flag has been set
CHANGE_PROTOCOL_FLAG_on; //restart protocol with bind
cur_protocol[0] = rx_ok_buff[0]; //store current protocol
// decode channel values
#if defined(NUM_SERIAL_CH_8) //8 channels serial protocol
Servo_data[0]=rx_ok_buff[3]+((rx_ok_buff[11]&0xC0)<<2);
Servo_data[1]=rx_ok_buff[4]+((rx_ok_buff[11]&0x30)<<4);
Servo_data[2]=rx_ok_buff[5]+((rx_ok_buff[11]&0x0C)<<6);
Servo_data[3]=rx_ok_buff[6]+((rx_ok_buff[11]&0x03)<<8);
Servo_data[4]=rx_ok_buff[7]+((rx_ok_buff[12]&0xC0)<<2);
Servo_data[5]=rx_ok_buff[8]+((rx_ok_buff[12]&0x30)<<4);
Servo_data[6]=rx_ok_buff[9]+((rx_ok_buff[12]&0x0C)<<6);
Servo_data[7]=rx_ok_buff[10]+((rx_ok_buff[12]&0x03)<<8);
for(uint8_t i=0;i<8;i++)
Servo_data[i]=((Servo_data[i]*5)>>2)+860; //range 860-2140;
#else //16 channels serial protocol
volatile uint8_t *p=rx_ok_buff+2;
uint8_t dec=-3;
volatile uint8_t *p=rx_ok_buff+2;
uint8_t dec=-3;
for(uint8_t i=0;i<NUM_CHN;i++)
{
dec+=3;
dec+=3;
if(dec>=8)
{
dec-=8;
p++;
}
p++;
Servo_data[i]=((((*((uint32_t *)p))>>dec)&0x7FF)*5)/8+860; //value range 860<->2140 -125%<->+125%
}
#endif
RX_FLAG_off; //data has been processed
dec-=8;
p++;
}
p++;
Servo_data[i]=((((*((uint32_t *)p))>>dec)&0x7FF)*5)/8+860; //value range 860<->2140 -125%<->+125%
}
RX_FLAG_off; //data has been processed
}
static void module_reset()
{
remote_callback = 0;
switch(prev_protocol)
{
case MODE_FLYSKY:
case MODE_HUBSAN:
A7105_Reset();
break;
case MODE_FRSKY:
case MODE_FRSKYX:
CC2500_Reset();
break;
break;
case MODE_DSM2:
case MODE_DEVO:
CYRF_Reset();
break;
default:
// MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY
NRF24L01_Reset();
break;
if(remote_callback)
{ // previous protocol loaded
remote_callback = 0;
switch(prev_protocol)
{
case MODE_FLYSKY:
case MODE_HUBSAN:
A7105_Reset();
break;
case MODE_FRSKY:
case MODE_FRSKYX:
CC2500_Reset();
break;
case MODE_DSM2:
case MODE_DEVO:
CYRF_Reset();
break;
default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY
NRF24L01_Reset();
break;
}
}
}
@ -612,21 +610,11 @@ uint16_t limit_channel_100(uint8_t ch)
if(Servo_data[ch]>PPM_MAX_100)
return PPM_MAX_100;
else
if (Servo_data[ch]<PPM_MIN_100)
return PPM_MIN_100;
if (Servo_data[ch]<PPM_MIN_100)
return PPM_MIN_100;
return Servo_data[ch];
}
// Convert 32b id to rx_tx_addr
static void set_rx_tx_addr(uint32_t id)
{ // Used by almost all protocols
rx_tx_addr[0] = (id >> 24) & 0xFF;
rx_tx_addr[1] = (id >> 16) & 0xFF;
rx_tx_addr[2] = (id >> 8) & 0xFF;
rx_tx_addr[3] = (id >> 0) & 0xFF;
rx_tx_addr[4] = 0xC1; // for YD717: always uses first data port
}
#if defined(TELEMETRY)
void Serial_write(uint8_t data)
{
@ -641,21 +629,12 @@ void Serial_write(uint8_t data)
static void Mprotocol_serial_init()
{
#if defined(NUM_SERIAL_CH_8) //8 channels serial protocol
#define BAUD 125000
#include <util/setbaud.h>
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
//Set frame format to 8 data bits, no parity, 1 stop bit
UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00);
#else //16 channels serial protocol
#define BAUD 100000
#include <util/setbaud.h>
#include <util/setbaud.h>
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
//Set frame format to 8 data bits, even parity, 2 stop bits
UCSR0C |= (1<<UPM01)|(1<<USBS0)|(1<<UCSZ01)|(1<<UCSZ00);
#endif
while ( UCSR0A & (1 << RXC0) )//flush receive buffer
UDR0;
//enable reception and RC complete interrupt
@ -663,6 +642,26 @@ static void Mprotocol_serial_init()
UCSR0B |= (1<<TXEN0);//tx enable
}
static void PPM_Telemetry_serial_init()
{
//9600 bauds
UBRR0H = 0x00;
UBRR0L = 0x67;
//Set frame format to 8 data bits, none, 1 stop bit
UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00);
UCSR0B |= (1<<TXEN0);//tx enable
}
// Convert 32b id to rx_tx_addr
static void set_rx_tx_addr(uint32_t id)
{ // Used by almost all protocols
rx_tx_addr[0] = (id >> 24) & 0xFF;
rx_tx_addr[1] = (id >> 16) & 0xFF;
rx_tx_addr[2] = (id >> 8) & 0xFF;
rx_tx_addr[3] = (id >> 0) & 0xFF;
rx_tx_addr[4] = 0xC1; // for YD717: always uses first data port
}
static uint32_t random_id(uint16_t adress, uint8_t create_new)
{
uint32_t id;
@ -694,6 +693,7 @@ static uint32_t random_id(uint16_t adress, uint8_t create_new)
/**************************/
/**************************/
//PPM
ISR(INT1_vect)
{ // Interrupt on PPM pin
static int8_t chan=-1;
@ -722,53 +722,8 @@ ISR(INT1_vect)
Prev_TCNT1+=Cur_TCNT1;
}
#if defined(TELEMETRY)
ISR(USART_UDRE_vect)
{ // Transmit interrupt
uint8_t t = tx_tail;
if(tx_head!=t)
{
if(++t>=TXBUFFER_SIZE)//head
t=0;
UDR0=tx_buff[t];
tx_tail=t;
}
if (t == tx_head)
UCSR0B &= ~(1<<UDRIE0); // Check if all data is transmitted . if yes disable transmitter UDRE interrupt
}
#endif
#if defined(NUM_SERIAL_CH_8) //8 channels serial protocol
ISR(USART_RX_vect)
{ // RX interrupt
static uint16_t crc = 0;
if(idx==0)
{ // Let's try to sync at this point
OCR1B=TCNT1+5000L; // timer for 2500us
TIFR1=(1<<OCF1B); // clear OCR1B match flag
TIMSK1 |=(1<<OCIE1B); // enable interrupt on compare B match
crc=0;
}
if(idx<RXBUFFER_SIZE-1)
{ // Store bytes in buffer and calculate crc as we go
rx_buff[idx]=UDR0;
crc = (crc<<8) ^ pgm_read_word(&CRCTable[((uint8_t)(crc>>8) ^ rx_buff[idx++]) & 0xFF]);
}
else
{ // A frame has been received and needs to be checked before giving it to main
TIMSK1 &=~(1<<OCIE1B); // disable interrupt on compare B match
if(UDR0==(uint8_t)(crc & 0xFF) && !IS_RX_FLAG_on)
{ //Good frame received and main has finished with previous buffer
for(idx=0;idx<RXBUFFER_SIZE;idx++)
rx_ok_buff[idx]=rx_buff[idx]; // Duplicate the buffer
RX_FLAG_on; //flag for main to process servo data
LED_ON;
}
idx=0;
}
}
#else //16 channels serial protocol
//Serial RX
#if !defined(POTAR_SELECT)
ISR(USART_RX_vect)
{ // RX interrupt
if((UCSR0A&0x1C)==0) // Check frame error, data overrun and parity error
@ -807,7 +762,25 @@ ISR(USART_RX_vect)
}
#endif
//Serial timer
ISR(TIMER1_COMPB_vect)
{ // Timer1 compare B interrupt
idx=0;
}
#if defined(TELEMETRY)
//Serial TX
ISR(USART_UDRE_vect)
{ // Transmit interrupt
uint8_t t = tx_tail;
if(tx_head!=t)
{
if(++t>=TXBUFFER_SIZE)//head
t=0;
UDR0=tx_buff[t];
tx_tail=t;
}
if (t == tx_head)
UCSR0B &= ~(1<<UDRIE0); // Check if all data is transmitted . if yes disable transmitter UDRE interrupt
}
#endif

View File

@ -271,7 +271,7 @@ static const uint8_t xn297_scramble[] = {
static const uint16_t xn297_crc_xorout[] = {
0x0000, 0x3448, 0x9BA7, 0x8BBB, 0x85E1, 0x3E8C, // 1st entry is missing, probably never needed
0x451E, 0x18E6, 0x6B24, 0xE7AB, 0x3828, 0x8148, // it's used for 3-byte address w/ 0 byte payload only
0x451E, 0x18E6, 0x6B24, 0xE7AB, 0x3828, 0x814B, // it's used for 3-byte address w/ 0 byte payload only
0xD461, 0xF494, 0x2503, 0x691D, 0xFE8B, 0x9BA7,
0x8B17, 0x2920, 0x8B5F, 0x61B1, 0xD391, 0x7401,
0x2138, 0x129F, 0xB3A0, 0x2988};

View File

@ -31,7 +31,7 @@ enum {
SLT_DATA3
};
static void SLT_init()
static void __attribute__((unused)) SLT_init()
{
NRF24L01_Initialize();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO)); // 2-bytes CRC, radio off
@ -47,7 +47,7 @@ static void SLT_init()
NRF24L01_FlushRx();
}
static void SLT_init2()
static void __attribute__((unused)) SLT_init2()
{
NRF24L01_FlushTx();
packet_sent = 0;
@ -57,7 +57,7 @@ static void SLT_init2()
NRF24L01_SetTxRxMode(TX_EN);
}
static void SLT_set_tx_id(void)
static void __attribute__((unused)) SLT_set_tx_id(void)
{
// Frequency hopping sequence generation
for (uint8_t i = 0; i < 4; ++i)
@ -90,14 +90,14 @@ static void SLT_set_tx_id(void)
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 4);
}
static void SLT_wait_radio()
static void __attribute__((unused)) SLT_wait_radio()
{
if (packet_sent)
while (!(NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_TX_DS))) ;
packet_sent = 0;
}
static void SLT_send_data(uint8_t *data, uint8_t len)
static void __attribute__((unused)) SLT_send_data(uint8_t *data, uint8_t len)
{
SLT_wait_radio();
NRF24L01_FlushTx();
@ -107,7 +107,7 @@ static void SLT_send_data(uint8_t *data, uint8_t len)
packet_sent = 1;
}
static void SLT_build_packet()
static void __attribute__((unused)) SLT_build_packet()
{
// aileron, elevator, throttle, rudder, gear, pitch
uint8_t e = 0; // byte where extension 2 bits for every 10-bit channel are packed
@ -129,7 +129,7 @@ static void SLT_build_packet()
hopping_frequency_no = 0;
}
static void SLT_send_bind_packet()
static void __attribute__((unused)) SLT_send_bind_packet()
{
SLT_wait_radio();
BIND_IN_PROGRESS; // autobind protocol

View File

@ -41,7 +41,7 @@ enum {
SYMAX_DATA
};
static uint8_t SYMAX_checksum(uint8_t *data)
static uint8_t __attribute__((unused)) SYMAX_checksum(uint8_t *data)
{
uint8_t sum = data[0];
@ -54,7 +54,7 @@ static uint8_t SYMAX_checksum(uint8_t *data)
return sum + ( sub_protocol==SYMAX5C ? 0 : 0x55 );
}
static void SYMAX_read_controls()
static void __attribute__((unused)) SYMAX_read_controls()
{
// Protocol is registered AETRF, that is
// Aileron is channel 1, Elevator - 2, Throttle - 3, Rudder - 4, Flip control - 5
@ -80,7 +80,7 @@ static void SYMAX_read_controls()
#define X5C_CHAN2TRIM(X) ((((X) & 0x80 ? 0xff - (X) : 0x80 + (X)) >> 2) + 0x20)
static void SYMAX_build_packet_x5c(uint8_t bind)
static void __attribute__((unused)) SYMAX_build_packet_x5c(uint8_t bind)
{
if (bind)
{
@ -116,7 +116,7 @@ static void SYMAX_build_packet_x5c(uint8_t bind)
}
}
static void SYMAX_build_packet(uint8_t bind)
static void __attribute__((unused)) SYMAX_build_packet(uint8_t bind)
{
if (bind)
{
@ -146,7 +146,7 @@ static void SYMAX_build_packet(uint8_t bind)
packet[9] = SYMAX_checksum(packet);
}
static void SYMAX_send_packet(uint8_t bind)
static void __attribute__((unused)) SYMAX_send_packet(uint8_t bind)
{
if (sub_protocol==SYMAX5C)
SYMAX_build_packet_x5c(bind);
@ -167,7 +167,7 @@ static void SYMAX_send_packet(uint8_t bind)
NRF24L01_SetPower(); // Set tx_power
}
static void symax_init()
static void __attribute__((unused)) symax_init()
{
NRF24L01_Initialize();
//
@ -219,7 +219,7 @@ static void symax_init()
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0e); // power on
}
static void symax_init1()
static void __attribute__((unused)) symax_init1()
{
// duplicate stock tx sending strange packet (effect unknown)
uint8_t first_packet[] = {0xf9, 0x96, 0x82, 0x1b, 0x20, 0x08, 0x08, 0xf2, 0x7d, 0xef, 0xff, 0x00, 0x00, 0x00, 0x00};
@ -247,7 +247,7 @@ static void symax_init1()
}
// channels determined by last byte of tx address
static void symax_set_channels(uint8_t address)
static void __attribute__((unused)) symax_set_channels(uint8_t address)
{
static const uint8_t start_chans_1[] = {0x0a, 0x1a, 0x2a, 0x3a};
static const uint8_t start_chans_2[] = {0x2a, 0x0a, 0x42, 0x22};
@ -290,7 +290,7 @@ static void symax_set_channels(uint8_t address)
*pchans = 0x39194121;
}
static void symax_init2()
static void __attribute__((unused)) symax_init2()
{
uint8_t chans_data_x5c[] = {0x1d, 0x2f, 0x26, 0x3d, 0x15, 0x2b, 0x25, 0x24,
0x27, 0x2c, 0x1c, 0x3e, 0x39, 0x2d, 0x22};

View File

@ -75,7 +75,7 @@ static const uint8_t freq_hopping[][16] = {
0x18, 0x2A, 0x21, 0x38, 0x10, 0x26, 0x20, 0x1F } // 03
};
static void v202_init()
static void __attribute__((unused)) v202_init()
{
NRF24L01_Initialize();
@ -108,7 +108,7 @@ static void v202_init()
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x66\x88\x68\x68\x68", 5);
}
static void V202_init2()
static void __attribute__((unused)) V202_init2()
{
NRF24L01_FlushTx();
packet_sent = 0;
@ -119,7 +119,7 @@ static void V202_init2()
//Done by TX_EN??? => NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP));
}
static void V2X2_set_tx_id(void)
static void __attribute__((unused)) V2X2_set_tx_id(void)
{
uint8_t sum;
sum = rx_tx_addr[1] + rx_tx_addr[2] + rx_tx_addr[3];
@ -134,7 +134,7 @@ static void V2X2_set_tx_id(void)
}
}
static void V2X2_add_pkt_checksum()
static void __attribute__((unused)) V2X2_add_pkt_checksum()
{
uint8_t sum = 0;
for (uint8_t i = 0; i < 15; ++i)
@ -142,7 +142,7 @@ static void V2X2_add_pkt_checksum()
packet[15] = sum;
}
static void V2X2_send_packet(uint8_t bind)
static void __attribute__((unused)) V2X2_send_packet(uint8_t bind)
{
uint8_t flags2=0;
if (bind)

View File

@ -41,7 +41,7 @@ enum {
YD717_DATA
};
static void yd717_send_packet(uint8_t bind)
static void __attribute__((unused)) yd717_send_packet(uint8_t bind)
{
uint8_t rudder_trim, elevator_trim, aileron_trim;
if (bind)
@ -125,7 +125,7 @@ static void yd717_send_packet(uint8_t bind)
NRF24L01_SetPower(); // Set tx_power
}
static void yd717_init()
static void __attribute__((unused)) yd717_init()
{
NRF24L01_Initialize();
@ -162,7 +162,7 @@ static void yd717_init()
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
}
static void YD717_init1()
static void __attribute__((unused)) YD717_init1()
{
// for bind packets set address to prearranged value known to receiver
uint8_t bind_rx_tx_addr[] = {0x65, 0x65, 0x65, 0x65, 0x65};
@ -179,7 +179,7 @@ static void YD717_init1()
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, bind_rx_tx_addr, 5);
}
static void YD717_init2()
static void __attribute__((unused)) YD717_init2()
{
// set rx/tx address for data phase
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5);

234
Multiprotocol/_Config.h Normal file
View File

@ -0,0 +1,234 @@
/*
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/>.
*/
/** Multiprotocol module configuration file ***/
//Uncomment your TX type
#define TARANIS //TARANIS TAER (1100<->1900µs)
//#define TX_ER9X //ER9X AETR (988<->2012µs)
//#define TX_DEVO7 //DEVO7 EATR (1120<->1920µs)
//#define TX_SPEKTRUM //Spektrum TAER (1100<->1900µs)
//#define TX_HISKY //HISKY AETR (1100<->1900µs)
//Uncomment to enable telemetry
#define TELEMETRY
#define HUB_TELEMETRY
//Uncomment to enable potar select
#define POTAR_SELECT
#define POTAR_SELECT_V ELEVATOR
#define POTAR_SELECT_H RUDDER
#define POTAR_SELECT_M AILERON
//Comment a protocol to exclude it from compilation
#define BAYANG_NRF24L01_INO
#define CG023_NRF24L01_INO
#define CX10_NRF24L01_INO
#define DEVO_CYRF6936_INO
#define DSM2_CYRF6936_INO
#define ESKY_NRF24L01_INO
#define FLYSKY_A7105_INO
#define FRSKY_CC2500_INO // FRSKY2way
//#define FRSKYX_CC2500_INO
#define HISKY_NRF24L01_INO
#define HUBSAN_A7105_INO
#define KN_NRF24L01_INO
#define SLT_NRF24L01_INO
#define SYMAX_NRF24L01_INO
#define V2X2_NRF24L01_INO
#define YD717_NRF24L01_INO
#define H7_NRF24L01_INO
//#define HM830_NRF24L01_INO
//#define CFlie_NRF24L01_INO
//Update this table to set which protocol and all associated settings are called for the corresponding dial number
static const PPM_Parameters PPM_prot[15]=
{
// Protocol , Sub protocol , RX_Num , Power , Auto Bind , Option
{MODE_DSM2 , DSM2 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=1
{MODE_FLYSKY, Flysky , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=2
{MODE_HUBSAN, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=3
{MODE_DEVO , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=4
{MODE_CG023 , CG023 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=5
{MODE_CX10 , CX10_BLUE , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=6
{MODE_HISKY , Hisky , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=7
{MODE_V2X2 , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=8
{MODE_YD717 , YD717 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=9
{MODE_KN , WLTOYS , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=10
{MODE_SYMAX , SYMAX , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=11
{MODE_SLT , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=12
{MODE_BAYANG, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=13
{MODE_SYMAX , SYMAX5C , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=14
{MODE_FRSKY , 0 , 0 , P_HIGH , NO_AUTOBIND , 0xD7 }, //Dial=15
};
/* Available protocols and associated sub protocols:
MODE_FLYSKY
Flysky
V9X9
V6X6
V912
MODE_HUBSAN
NONE
MODE_FRSKY
NONE
MODE_HISKY
Hisky
HK310
MODE_V2X2
NONE
MODE_DSM2
DSM2
DSMX
MODE_DEVO
NONE
MODE_YD717
YD717
SKYWLKR
SYMAX4
XINXUN
NIHUI
MODE_KN
WLTOYS
FEILUN
MODE_SYMAX
SYMAX
SYMAX5C
MODE_SLT
NONE
MODE_CX10
CX10_GREEN
CX10_BLUE
DM007
Q282
JC3015_1
JC3015_2
MK33041
Q242
MODE_CG023
CG023
YD829
H8_3D
MODE_BAYANG
NONE
MODE_FRSKYX
NONE
MODE_ESKY
NONE
RX_Num value between 0 and 15
Power P_HIGH or P_LOW
Auto Bind AUTOBIND or NO_AUTOBIND
Option value between 0 and 255. 0xD7 or 0x00 for Frsky fine tuning.
*/
//******************
//TX definitions with timing endpoints and channels order
// Turnigy PPM and channels
#if defined(TX_ER9X)
#define PPM_MAX 2140
#define PPM_MIN 860
#define PPM_MAX_100 2012
#define PPM_MIN_100 988
#define AETR
#endif
// Devo PPM and channels
#if defined(TX_DEVO7)
#define PPM_MAX 2100
#define PPM_MIN 900
#define PPM_MAX_100 1920
#define PPM_MIN_100 1120
#define EATR
#endif
// SPEKTRUM PPM and channels
#if defined(TX_SPEKTRUM) | defined(TARANIS)
#define PPM_MAX 2000
#define PPM_MIN 1000
#define PPM_MAX_100 1900
#define PPM_MIN_100 1100
#define TAER
#endif
// HISKY
#if defined(TX_HISKY)
#define PPM_MAX 2000
#define PPM_MIN 1000
#define PPM_MAX_100 1900
#define PPM_MIN_100 1100
#define AETR
#endif
#if defined(EATR)
enum chan_order{
ELEVATOR=0,
AILERON,
THROTTLE,
RUDDER,
AUX1,
AUX2,
AUX3,
AUX4,
AUX5,
AUX6,
AUX7,
AUX8
};
#endif
#if defined(TAER)
enum chan_order{
THROTTLE=0,
AILERON,
ELEVATOR,
RUDDER,
AUX1,
AUX2,
AUX3,
AUX4,
AUX5,
AUX6,
AUX7,
AUX8
};
#endif
#if defined(AETR)
enum chan_order{
AILERON =0,
ELEVATOR,
THROTTLE,
RUDDER,
AUX1,
AUX2,
AUX3,
AUX4,
AUX5,
AUX6,
AUX7,
AUX8
};
#endif
#define PPM_MIN_COMMAND 1250
#define PPM_SWITCH 1550
#define PPM_MAX_COMMAND 1750

View File

@ -16,6 +16,16 @@
#ifndef _IFACE_CC2500_H_
#define _IFACE_CC2500_H_
enum {
FRSKY_BIND = 0,
FRSKY_BIND_DONE = 1000,
FRSKY_DATA1,
FRSKY_DATA2,
FRSKY_DATA3,
FRSKY_DATA4,
FRSKY_DATA5
};
enum {
CC2500_00_IOCFG2 = 0x00, // GDO2 output pin configuration
CC2500_01_IOCFG1 = 0x01, // GDO1 output pin configuration

65
Multiprotocol/liste.txt Normal file
View File

@ -0,0 +1,65 @@
MODE_SERIAL = 0, // Serial / Manche commands
MODE_FLYSKY = 1, // =>A7105 { Flysky=0, V9X9=1, V6X6=2, V912=3 };
MODE_HUBSAN = 2, // =>A7105
MODE_CG023 = 3, // =>NRF24L01 { CG023 = 0, YD829 = 1, H8_3D = 2 };
MODE_CX10 = 4, // =>NRF24L01 { CX10_GREEN = 0, DM007=2, CX10_BLUE=1, // also compatible with CX10-A, CX12 };
MODE_HISKY = 6, // =>NRF24L01 { Hisky=0, HK310=1 };
MODE_DSM2 = 6, // =>CYRF6936 { DSM2=0, DSMX=1};
MODE_DEVO =7, // =>CYRF6936
MODE_YD717 = 8, // =>NRF24L01 { YD717=0, SKYWLKR=1, SYMAX2=2, XINXUN=3, NIHUI=4 };
MODE_KN = 9, // =>NRF24L01
MODE_SYMAX = 10, // =>NRF24L01 { SYMAX=0, SYMAX5C=1, };
MODE_SLT = 11, // =>NRF24L01
MODE_V2X2 = 12, // =>NRF24L01
MODE_BAYANG = 13, // =>NRF24L01
MODE_FRSKY = 14, // =>CC2500
= 15, // =>
BAYANG
AUX1 FLIP
AUX2 HEADLESS
AUX3 RTH
AUX4 SNAPSHOT
AUX5 VIDEO
CG023
AUX1 FLIP
AUX2 LED
AUX3 STILL
AUX4 VIDEO
AUX5 EASY
CX10
AUX1 FLIP
AUX2 mode 1-2-3 (headless on CX-10A)
AUX3 SNAPSHOT
AUX4 VIDEO
AUX5 HEADLESS
HUBSAN
AUX1 FLIP
AUX2 LED
AUX3 VIDEO
KN
AUX1 Dual rate
AUX2 Throttle Hold
AUX3 Idle up
AUX4 Gyro
V2X2
AUX1 FLIP
AUX2 LED
AUX3 CAMERA
AUX4 VIDEO
AUX5 HEADLESS
AUX6 MAG_CAL_X
AUX7 MAG_CAL_Y
YD717
AUX1 FLIP
AUX2 LED
AUX3 PICTURE
AUX4 VIDEO
AUX5 HEADLESS

91
Multiprotocol/multi.lua Normal file
View File

@ -0,0 +1,91 @@
-- Multiprotocole Midelic et Pascallanger
local debut = 0
local tps = 0
local tpsact = 1024
local mix, mixe
local channel
local inp = {
{ "Protocole", VALUE, 1, 26, 2 },
{ "Switch", SOURCE }
}
-- 6 7 8 15 16 17 24 25 26
-- 4 5 12 13 14 21 22 23
-- 1 2 3 9 10 11 18 19 20
local out = { "Bind", "Gaz", "Aile", "Prof", "Dir" }
local function run_func(proto, sw)
-- test mixage lua
if debut == 0 then
-- passage en lua
for channel = 0, 3, 1 do
local mix = model.getMix(channel, 0)
mix_source = mix["source"]
if mix_source < 33 or 1 then
model.deleteMix(channel, 0)
mix["source"] = channel + 34
mix["name"] = "Lua "
model.insertMix(channel, 0, mix)
end
end
end
-- inter install
channel = 4
mix = { name="Raz Bind", source=33, weight=100, switch=0, multiplex=REPLACE }
count = model.getMixesCount(channel + 0)
if count == 0 and inter == 1 then
model.insertMix(channel + 0, 0, mix)
elseif count == 1 and inter == 0 then
mixe = model.getMix(channel, 0)
if mixe["name"] == mix["name"] then
model.deleteMix(channel, 0)
end
end
-- delais init
if proto ~= debut then
tps = getTime() + 500 -- delai pour mini 12 cycle PPM
tpsact = 1024
debut = proto
end
local gaz = 1024
local ail = 0
local dir = 0
local pro = 0
if tpsact == 0 and sw < 200 then
-- reprise valeur input
pro = getValue(1)
ail = getValue(2)
gaz = getValue(3)
dir = getValue(4)
elseif tpsact ~= 0 then
-- decallage pour position memo (centre)
if proto > 4 then proto = proto + 1 end
-- calcul position
-- decallage pour > 18
if proto > 18 then
ail = 1024
proto = proto - 18
end
-- decallage pour > 9
if proto > 9 then
ail = -1024
proto = proto - 9
end
if proto < 4 then pro = -1024 end
if proto > 6 then pro = 1024 end
if proto % 3 == 1 then dir = -1024 end
if proto % 3 == 0 then dir = 1024 end
if tps < getTime() then tpsact = 0 end
sw = tpsact
end
return sw, gaz, ail, pro, dir
end
return { run=run_func, input=inp, output=out}

View File

@ -21,20 +21,24 @@ enum PROTOCOLS
MODE_SERIAL = 0, // Serial commands
MODE_FLYSKY = 1, // =>A7105 / FLYSKY protocol
MODE_HUBSAN = 2, // =>A7105 / HUBSAN protocol
MODE_FRSKY = 3, // =>CC2500 / FRSKY protocol
MODE_FRSKY = 3, // =>CC2500 / FRSKY protocol
MODE_HISKY = 4, // =>NRF24L01 / HISKY protocol
MODE_V2X2 = 5, // =>NRF24L01 / V2x2 protocol
MODE_DSM2 = 6, // =>CYRF6936 / DSM2 protocol
MODE_DEVO =7, // =>CYRF6936 / DEVO protocol
MODE_YD717 = 8, // =>NRF24L01 / YD717 protocol (CX10 red pcb)
MODE_KN = 9, // =>NRF24L01 / KN protocol
MODE_SYMAX = 10, // =>NRF24L01 / SYMAX protocol (SYMAX4 working)
MODE_SYMAX = 10, // =>NRF24L01 / SYMAX protocol
MODE_SLT = 11, // =>NRF24L01 / SLT protocol
MODE_CX10 = 12, // =>NRF24L01 / CX-10 protocol
MODE_CG023 = 13, // =>NRF24L01 / CG023 protocol
MODE_BAYANG = 14, // =>NRF24L01 / BAYANG protocol
MODE_FRSKYX = 15, // =>CC2500 / FRSKYX protocol
MODE_FRSKYX = 15, // =>CC2500 / FRSKYX protocol
MODE_ESKY = 16, // =>NRF24L01 / ESKY protocol
// Ajout
MODE_H7 = 21, // =>NRF24L01 / EAchine MT99xx (H7, MT9916 ...)
// MODE_HM830 =22, // =>NRF24L01 / HM830
MODE_CFLIE =23, // =>NRF24L01 / CFlie
};
enum Flysky
{
@ -78,7 +82,8 @@ enum CX10
Q282=3,
JC3015_1=4,
JC3015_2=5,
MK33041=6
MK33041=6,
Q242=7
};
enum CG023
{
@ -87,101 +92,22 @@ enum CG023
H8_3D = 2
};
//******************
//TX definitions with timing endpoints and channels order
//******************
// Turnigy PPM and channels
#if defined(TX_ER9X)
#define PPM_MAX 2140
#define PPM_MIN 860
#define PPM_MAX_100 2012
#define PPM_MIN_100 988
enum chan_order{
AILERON =0,
ELEVATOR,
THROTTLE,
RUDDER,
AUX1,
AUX2,
AUX3,
AUX4,
AUX5,
AUX6,
AUX7,
AUX8
#define NONE 0
#define P_HIGH 1
#define P_LOW 0
#define AUTOBIND 1
#define NO_AUTOBIND 0
struct PPM_Parameters
{
uint8_t protocol : 5;
uint8_t sub_proto : 3;
uint8_t rx_num : 4;
uint8_t power : 1;
uint8_t autobind : 1;
uint8_t option;
};
#endif
// Devo PPM and channels
#if defined(TX_DEVO7)
#define PPM_MAX 2100
#define PPM_MIN 900
#define PPM_MAX_100 1920
#define PPM_MIN_100 1120
enum chan_order{
ELEVATOR=0,
AILERON,
THROTTLE,
RUDDER,
AUX1,
AUX2,
AUX3,
AUX4,
AUX5,
AUX6,
AUX7,
AUX8
};
#endif
// SPEKTRUM PPM and channels
#if defined(TX_SPEKTRUM)
#define PPM_MAX 2000
#define PPM_MIN 1000
#define PPM_MAX_100 1900
#define PPM_MIN_100 1100
enum chan_order{
THROTTLE=0,
AILERON,
ELEVATOR,
RUDDER,
AUX1,
AUX2,
AUX3,
AUX4,
AUX5,
AUX6,
AUX7,
AUX8
};
#endif
// HISKY
#if defined(TX_HISKY)
#define PPM_MAX 2000
#define PPM_MIN 1000
#define PPM_MAX_100 1900
#define PPM_MIN_100 1100
enum chan_order{
AILERON =0,
ELEVATOR,
THROTTLE,
RUDDER,
AUX1,
AUX2,
AUX3,
AUX4,
AUX5,
AUX6,
AUX7,
AUX8
};
#endif
#define PPM_MIN_COMMAND 1250
#define PPM_SWITCH 1550
#define PPM_MAX_COMMAND 1750
//*******************
//*** Pinouts ***
@ -508,6 +434,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
JC3015_1 4
JC3015_2 5
MK33041 6
Q242 7
sub_protocol==CG023
CG023 0
YD829 1
@ -523,86 +450,5 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
1843 +100%
2047 +125%
Channels bits are concatenated to fit in 22 bytes like in SBUS protocol
**************************
8 channels serial protocol
**************************
Serial: 125000 Baud 8n1 _ xxxx xxxx - ---
Channels:
Nbr=8
10bits=0..1023
0 -125%
96 -100%
512 0%
928 +100%
1023 +125%
Stream[0] = sub_protocol|BindBit|RangeCheckBit|AutoBindBit;
sub_protocol is 0..31 (bits 0..4)
=> Reserved 0
Flysky 1
Hubsan 2
Frsky 3
Hisky 4
V2x2 5
DSM2 6
Devo 7
YD717 8
KN 9
SymaX 10
SLT 11
CX10 12
CG023 13
Bayang 14
FrskyX 15
ESky 16
BindBit=> 0x80 1=Bind/0=No
AutoBindBit=> 0x40 1=Yes /0=No
RangeCheck=> 0x20 1=Yes /0=No
Stream[1] = RxNum | Power | Type;
RxNum value is 0..15 (bits 0..3)
Type is 0..7 <<4 (bit 4..6)
sub_protocol==Flysky
Flysky 0
V9x9 1
V6x6 2
V912 3
sub_protocol==Hisky
Hisky 0
HK310 1
sub_protocol==DSM2
DSM2 0
DSMX 1
sub_protocol==YD717
YD717 0
SKYWLKR 1
SYMAX4 2
XINXUN 3
NIHUI 4
sub_protocol==KN
WLTOYS 0
FEILUN 1
sub_protocol==SYMAX
SYMAX 0
SYMAX5C 1
sub_protocol==CX10
CX10_GREEN 0
CX10_BLUE 1 // also compatible with CX10-A, CX12
DM007 2
Q282 3
JC3015_1 4
JC3015_2 5
MK33041 6
sub_protocol==CG023
CG023 0
YD829 1
H8_3D 2
Power value => 0x80 0=High/1=Low
Stream[2] = option_protocol;
option_protocol value is -127..127
Stream[i+3] = lowByte(channel[i]) // with i[0..7]
Stream[11] = highByte(channel[0])<<6 | highByte(channel[1])<<4 | highByte(channel[2])<<2 | highByte(channel[3])
Stream[12] = highByte(channel[4])<<6 | highByte(channel[5])<<4 | highByte(channel[6])<<2 | highByte(channel[7])
Stream[13] = lowByte(CRC16(Stream[0..12])
*/

View File

@ -0,0 +1,151 @@
/*
This program 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.
This program 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. If not, see <http://www.gnu.org/licenses/>.
*/
// EAchine MT99xx (H7, MT9916 ...) TX protocol
// Auxiliary channels:
// CH5: rate (3 pos)
// CH6: flip flag
// CH7: still camera
// CH8: video camera
// CH10: elevator trim
// CH11: aileron trim
#if defined(H7_NRF24L01_INO)
#include "iface_nrf24l01.h"
static const uint8_t H7_freq[] = {
0x02, 0x48, 0x0C, 0x3e, 0x16, 0x34, 0x20, 0x2A,
0x2A, 0x20, 0x34, 0x16, 0x3e, 0x0c, 0x48, 0x02
};
static const uint8_t H7_mys_byte[] = {
0x01, 0x11, 0x02, 0x12, 0x03, 0x13, 0x04, 0x14,
0x05, 0x15, 0x06, 0x16, 0x07, 0x17, 0x00, 0x10
};
// flags going to packet[6]
// H7_FLAG_RATE0, // default rate, no flag
#define H7_FLAG_RATE1 0x01
#define H7_FLAG_RATE2 0x02
#define H7_FLAG_VIDEO 0x10
#define H7_FLAG_SNAPSHOT 0x20
#define H7_FLAG_FLIP 0x80
uint8_t H7_tx_addr[5];
uint8_t checksum_offset;
uint8_t channel_offset;
#define H7_PACKET_PERIOD 2625
#define H7_PAYPLOAD_SIZE 9
void H7_initTXID() {
checksum_offset = (rx_tx_addr[0] + rx_tx_addr[1]) & 0xff;
channel_offset = (((checksum_offset & 0xf0)>>4) + (checksum_offset & 0x0f)) % 8;
}
uint16_t H7_init() {
H7_initTXID();
NRF24L01_Reset();
NRF24L01_Initialize();
delay(10);
NRF24L01_FlushTx();
for(u8 i=0; i<5; i++) { H7_tx_addr[i] = 0xCC; }
XN297_SetTXAddr(H7_tx_addr, 5);
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // no AA
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // enable data pipe 0 only
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5 bytes address
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x2D); // set RF channel
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00);// no auto retransmit
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 0x09); // rx payload size (unused ?)
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
NRF24L01_SetPower();
NRF24L01_Activate(0x73);
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00);
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x00);
NRF24L01_ReadReg(NRF24L01_1D_FEATURE); // read reg 1D back ?
delay(150);
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
delay(100);
H7_bind();
return H7_PACKET_PERIOD;
}
void H7_bind() {
BIND_IN_PROGRESS;
uint8_t counter = 58;
packet[0] = 0x20; // fixed (firmware date 2014-03-25 ?)
packet[1] = 0x14; // fixed
packet[2] = 0x03; // fixed
packet[3] = 0x25; // fixed
packet[4] = rx_tx_addr[0]; // 1st byte for data phase tx address
packet[5] = rx_tx_addr[1]; // 2nd byte for data phase tx address
packet[6] = 0x00; // 3rd byte for data phase tx address (always 0x00 ?)
packet[7] = checksum_offset; // checksum offset
packet[8] = 0xAA; // fixed
while(counter--) {
for (uint8_t ch = 0; ch < 16; ch++) {
delayMicroseconds(5);
NRF24L01_WriteReg(NRF24L01_07_STATUS,0x70);
NRF24L01_FlushTx();
NRF24L01_WriteReg(NRF24L01_05_RF_CH,H7_freq[ch]);
XN297_WritePayload(packet, H7_PAYPLOAD_SIZE); //(bind packet)
delayMicroseconds(H7_PACKET_PERIOD);
}
}
delay(15);
H7_tx_addr[0] = rx_tx_addr[0];
H7_tx_addr[1] = rx_tx_addr[1];
H7_tx_addr[2] = 0;
XN297_SetTXAddr(H7_tx_addr, 5);
BIND_DONE;
}
uint8_t H7_calcChecksum() {
uint8_t result=checksum_offset;
for(uint8_t i=0; i<8; i++) { result += packet[i]; }
return result & 0xFF;
}
void H7_WritePacket() {
static uint8_t channel=0;
packet[0] = map(Servo_data[THROTTLE], PPM_MIN, PPM_MAX, 0xE1, 0x00);
packet[1] = map(Servo_data[RUDDER], PPM_MIN, PPM_MAX, 0xE1, 0x00);
packet[2] = map(Servo_data[AILERON], PPM_MIN, PPM_MAX, 0x00, 0xE1);
packet[3] = map(Servo_data[ELEVATOR], PPM_MIN, PPM_MAX, 0x00, 0xE1);
packet[4] = map(Servo_data[AUX7], PPM_MIN, PPM_MAX, 0x3f, 0x00); // elevator trim 0x3f - 0x00
packet[5] = map(Servo_data[AUX8], PPM_MIN, PPM_MAX, 0x3f, 0x00); // aileron trim 0x3f - 0x00
packet[6] = 0x40; // flags (default is 0x00 on H7, 0x40 on MT9916 stock TX)
if(Servo_data[AUX2] > PPM_MAX_COMMAND) { packet[6] |= H7_FLAG_FLIP; }
if(Servo_data[AUX1] > PPM_MAX_COMMAND) { packet[6] |= H7_FLAG_RATE2; }
else if(Servo_data[AUX1] > PPM_MIN_COMMAND) { packet[6] |= H7_FLAG_RATE1; }
if(Servo_data[AUX5] > PPM_MAX_COMMAND) { packet[6] |= H7_FLAG_SNAPSHOT; }
if(Servo_data[AUX6] > PPM_MAX_COMMAND) { packet[6] |= H7_FLAG_VIDEO; }
packet[7] = H7_mys_byte[channel]; // looks like this byte has no importance actually
packet[8] = H7_calcChecksum();
NRF24L01_WriteReg(NRF24L01_05_RF_CH, H7_freq[channel]+channel_offset);
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
XN297_WritePayload(packet, H7_PAYPLOAD_SIZE);
channel++;
if(channel > 15) { channel = 0; }
}
uint16_t process_H7() {
H7_WritePacket();
return H7_PACKET_PERIOD;
}
#endif

View File

@ -0,0 +1,321 @@
/*
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.
Deviation 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 Deviation. If not, see <http://www.gnu.org/licenses/>.
*/
/* This protocol is for the HM Hobby HM830 RC Paper Airplane
Protocol spec:
Channel data:
AA BB CC DD EE FF GG
AA : Throttle Min=0x00 max =0x64
BB :
bit 0,1,2: Left/Right magnitude, bit 5 Polarity (set = right)
bit 6: Accelerate
bit 7: Right button (also the ABC Button)
CC : bit 0 seems to be impacted by the Right button
DD
EE
FF : Trim (bit 0-5: Magnitude, bit 6 polarity (set = right)
GG : Checksum (CRC8 on bytes AA-FF), init = 0xa5, poly = 0x01
*/
#ifdef HM830_NRF24L01_INO
#include "iface_nrf24l01.h"
enum {
HM830_BIND1A = 0,
HM830_BIND2A,
HM830_BIND3A,
HM830_BIND4A,
HM830_BIND5A,
HM830_BIND6A,
HM830_BIND7A,
HM830_DATA1,
HM830_DATA2,
HM830_DATA3,
HM830_DATA4,
HM830_DATA5,
HM830_DATA6,
HM830_DATA7,
HM830_BIND1B = 0x80,
HM830_BIND2B,
HM830_BIND3B,
HM830_BIND4B,
HM830_BIND5B,
HM830_BIND6B,
HM830_BIND7B,
};
static const uint8_t init_vals[][2] = {
{NRF24L01_17_FIFO_STATUS, 0x00},
{NRF24L01_16_RX_PW_P5, 0x07},
{NRF24L01_15_RX_PW_P4, 0x07},
{NRF24L01_14_RX_PW_P3, 0x07},
{NRF24L01_13_RX_PW_P2, 0x07},
{NRF24L01_12_RX_PW_P1, 0x07},
{NRF24L01_11_RX_PW_P0, 0x07},
{NRF24L01_0F_RX_ADDR_P5, 0xC6},
{NRF24L01_0E_RX_ADDR_P4, 0xC5},
{NRF24L01_0D_RX_ADDR_P3, 0xC4},
{NRF24L01_0C_RX_ADDR_P2, 0xC3},
{NRF24L01_09_CD, 0x00},
{NRF24L01_08_OBSERVE_TX, 0x00},
{NRF24L01_07_STATUS, 0x07},
// {NRF24L01_06_RF_SETUP, 0x07},
{NRF24L01_05_RF_CH, 0x18},
{NRF24L01_04_SETUP_RETR, 0x3F},
{NRF24L01_03_SETUP_AW, 0x03},
{NRF24L01_02_EN_RXADDR, 0x3F},
{NRF24L01_01_EN_AA, 0x3F},
{NRF24L01_00_CONFIG, 0x0E},
};
static uint8_t count;
static const uint8_t rf_ch[] = {0x08, 0x35, 0x12, 0x3f, 0x1c, 0x49, 0x26};
static const uint8_t bind_addr[] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xc2};
static uint8_t crc8(uint32_t result, uint8_t *data, int len) {
int polynomial = 0x01;
for(int i = 0; i < len; i++) {
result = result ^ data[i];
for(int j = 0; j < 8; j++) {
if(result & 0x80) { result = (result << 1) ^ polynomial; }
else { result = result << 1; }
}
}
return result & 0xff;
}
static void HM830_init() {
NRF24L01_Initialize();
for (uint32_t i = 0; i < sizeof(init_vals) / sizeof(init_vals[0]); i++) { NRF24L01_WriteReg(init_vals[i][0], init_vals[i][1]); }
NRF24L01_SetTxRxMode(TX_EN);
NRF24L01_SetBitrate(0);
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, bind_addr, 5);
NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, bind_addr+1, 5);
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, bind_addr, 5);
NRF24L01_Activate(0x73); //Enable FEATURE
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07);
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3F);
//NRF24L01_ReadReg(NRF24L01_07_STATUS) ==> 0x07
// Check for Beken BK2421/BK2423 chip
// It is done by using Beken specific activate code, 0x53 and checking that status register changed appropriately
// There is no harm to run it on nRF24L01 because following closing activate command changes state back even if it does something on nRF24L01
// For detailed description of what's happening here see : http://www.inhaos.com/uploadfile/otherpic/AN0008-BK2423%20Communication%20In%20250Kbps%20Air%20Rate.pdf
NRF24L01_Activate(0x53); // magic for BK2421 bank switch
// printf("=>H377 : Trying to switch banks\n");
if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & 0x80) {
// printf("=>H377 : BK2421 detected\n");
long nul = 0;
// Beken registers don't have such nice names, so we just mention them by their numbers
// It's all magic, eavesdropped from real transfer and not even from the data sheet - it has slightly different values
NRF24L01_WriteRegisterMulti(0x00, (uint8_t *) "\x40\x4B\x01\xE2", 4);
NRF24L01_WriteRegisterMulti(0x01, (uint8_t *) "\xC0\x4B\x00\x00", 4);
NRF24L01_WriteRegisterMulti(0x02, (uint8_t *) "\xD0\xFC\x8C\x02", 4);
NRF24L01_WriteRegisterMulti(0x03, (uint8_t *) "\xF9\x00\x39\x21", 4);
NRF24L01_WriteRegisterMulti(0x04, (uint8_t *) "\xC1\x96\x9A\x1B", 4);
NRF24L01_WriteRegisterMulti(0x05, (uint8_t *) "\x24\x06\x7F\xA6", 4);
NRF24L01_WriteRegisterMulti(0x06, (uint8_t *) &nul, 4);
NRF24L01_WriteRegisterMulti(0x07, (uint8_t *) &nul, 4);
NRF24L01_WriteRegisterMulti(0x08, (uint8_t *) &nul, 4);
NRF24L01_WriteRegisterMulti(0x09, (uint8_t *) &nul, 4);
NRF24L01_WriteRegisterMulti(0x0A, (uint8_t *) &nul, 4);
NRF24L01_WriteRegisterMulti(0x0B, (uint8_t *) &nul, 4);
NRF24L01_WriteRegisterMulti(0x0C, (uint8_t *) "\x00\x12\x73\x00", 4);
NRF24L01_WriteRegisterMulti(0x0D, (uint8_t *) "\x46\xB4\x80\x00", 4);
//NRF24L01_WriteRegisterMulti(0x0E, (uint8_t *) "\x41\x10\x04\x82\x20\x08\x08\xF2\x7D\xEF\xFF", 11);
NRF24L01_WriteRegisterMulti(0x04, (uint8_t *) "\xC7\x96\x9A\x1B", 4);
NRF24L01_WriteRegisterMulti(0x04, (uint8_t *) "\xC1\x96\x9A\x1B", 4);
} else { } // printf("=>H377 : nRF24L01 detected\n");
//NRF24L01_ReadReg(NRF24L01_07_STATUS) ==> 0x07
NRF24L01_Activate(0x53); // switch bank back
NRF24L01_FlushTx();
//NRF24L01_ReadReg(NRF24L01_07_STATUS) ==> 0x0e
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x0e);
//NRF24L01_ReadReg(NRF24L01_00_CONFIG); ==> 0x0e
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0e);
NRF24L01_ReadReg(NRF24L01_01_EN_AA); // No Auto Acknoledgement
}
static void build_bind_packet() {
for(int i = 0; i < 6; i++) { packet[i] = rx_tx_addr[i]; }
packet[6] = crc8(0xa5, packet, 6);
}
static void build_data_packet() {
uint8_t ail_sign = 0, trim_sign = 0;
throttle = (uint32_t)Servo_data[2] * 50 / PPM_MAX + 50;
if (throttle < 0) { throttle = 0; }
aileron = (uint32_t)Servo_data[0] * 8 / PPM_MAX;
if (aileron < 0) { aileron = -aileron; ail_sign = 1; }
if (aileron > 7) { aileron = 7; }
uint8_t turbo = (uint32_t)Servo_data[1] > 0 ? 1 : 0;
uint8_t trim = ((uint32_t)Servo_data[3] * 0x1f / PPM_MAX);
if (trim < 0) { trim = -trim; trim_sign = 1; }
if (trim > 0x1f) { trim = 0x1f; }
uint8_t rbutton = (uint32_t)Channels[4] > 0 ? 1 : 0;
packet[0] = throttle;
packet[1] = aileron;
if (ail_sign) { packet[1] |= 0x20; }
if (turbo) { packet[1] |= 0x40; }
if (rbutton) { packet[1] |= 0x80; }
packet[5] = trim;
if (trim_sign) { packet[5] |= 0x20;}
packet[6] = crc8(0xa5, packet, 6);
}
static void send_packet_hm830() {
NRF24L01_ReadReg(NRF24L01_17_FIFO_STATUS);
NRF24L01_WritePayload(packet, 7);
}
static uint16_t handle_binding() {
uint8_t status = NRF24L01_ReadReg(NRF24L01_07_STATUS);
if (status & 0x20) {
//Binding complete
phase = HM830_DATA1 + ((phase&0x7F)-HM830_BIND1A);
count = 0;
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5);
NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, rx_tx_addr+1, 5);
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
NRF24L01_FlushTx();
build_data_packet();
uint8_t rb = NRF24L01_ReadReg(NRF24L01_07_STATUS); //==> 0x0E
NRF24L01_WriteReg(NRF24L01_07_STATUS, rb);
rb = NRF24L01_ReadReg(NRF24L01_00_CONFIG); //==> 0x0E
NRF24L01_WriteReg(NRF24L01_00_CONFIG, rb);
send_packet_hm830();
return 14000;
}
switch (phase) {
case HM830_BIND1A:
//Look for a Rx that is already bound
NRF24L01_SetPower();
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5);
NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, rx_tx_addr+1, 5);
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch[0]);
build_bind_packet();
break;
case HM830_BIND1B:
//Look for a Rx that is not yet bound
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, bind_addr, 5);
NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, bind_addr+1, 5);
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, bind_addr, 5);
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch[0]);
break;
case HM830_BIND2A:
case HM830_BIND3A:
case HM830_BIND4A:
case HM830_BIND5A:
case HM830_BIND6A:
case HM830_BIND7A:
case HM830_BIND2B:
case HM830_BIND3B:
case HM830_BIND4B:
case HM830_BIND5B:
case HM830_BIND6B:
case HM830_BIND7B:
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch[(phase&0x7F)-HM830_BIND1A]);
break;
}
NRF24L01_FlushTx();
uint8_t rb = NRF24L01_ReadReg(NRF24L01_07_STATUS); //==> 0x0E
NRF24L01_WriteReg(NRF24L01_07_STATUS, rb);
rb = NRF24L01_ReadReg(NRF24L01_00_CONFIG); //==> 0x0E
NRF24L01_WriteReg(NRF24L01_00_CONFIG, rb);
send_packet_hm830();
phase++;
if (phase == HM830_BIND7B+1) { phase = HM830_BIND1A; }
else if (phase == HM830_BIND7A+1) { phase = HM830_BIND1B; }
return 20000;
}
static uint16_t handle_data() {
uint8_t status = NRF24L01_ReadReg(NRF24L01_07_STATUS);
if (count <= 0 || !(status & 0x20)) {
if(count < 0 || ! (status & 0x20)) {
count = 0;
//We didn't get a response on this channel, try the next one
phase++;
if (phase-HM830_DATA1 > 6) { phase = HM830_DATA1; }
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch[0]);
NRF24L01_FlushTx();
build_data_packet();
uint8_t rb = NRF24L01_ReadReg(NRF24L01_07_STATUS); //==> 0x0E
NRF24L01_WriteReg(NRF24L01_07_STATUS, rb);
rb = NRF24L01_ReadReg(NRF24L01_00_CONFIG); //==> 0x0E
NRF24L01_WriteReg(NRF24L01_00_CONFIG, rb);
send_packet_hm830();
return 14000;
}
}
build_data_packet();
count++;
if(count == 98) {
count = -1;
NRF24L01_SetPower();
}
uint8_t rb = NRF24L01_ReadReg(NRF24L01_07_STATUS); //==> 0x0E
NRF24L01_WriteReg(NRF24L01_07_STATUS, rb);
rb = NRF24L01_ReadReg(NRF24L01_00_CONFIG); //==> 0x0E
NRF24L01_WriteReg(NRF24L01_00_CONFIG, rb);
send_packet_hm830();
return 20000;
}
static uint32_t HM830_callback() {
if ((phase & 0x7F) < HM830_DATA1) { return handle_binding(); }
else { return handle_data(); }
}
static uint32_t HM830_setup(){
count = 0;
// initialize_tx_id
rx_tx_addr[4] = 0xee;
rx_tx_addr[5] = 0xc2;
HM830_init();
phase = HM830_BIND1A;
return 500;
// CLOCK_StartTimer(50000, HM830_callback);
}
/*
const void *HM830_Cmds(enum ProtoCmds cmd)
{
switch(cmd) {
case PROTOCMD_INIT: initialize(); return 0;
case PROTOCMD_DEINIT:
case PROTOCMD_RESET:
CLOCK_StopTimer();
return (void *)(NRF24L01_Reset() ? 1L : -1L);
case PROTOCMD_CHECK_AUTOBIND: return (void *)1L; // Always Autobind
case PROTOCMD_BIND: initialize(); return 0;
case PROTOCMD_NUMCHAN: return (void *) 5L; // T, A, E, R, G
case PROTOCMD_DEFAULT_NUMCHAN: return (void *)5L;
// TODO: return id correctly
case PROTOCMD_CURRENT_ID: return Model.fixed_id ? (void *)((unsigned long)Model.fixed_id) : 0;
case PROTOCMD_TELEMETRYSTATE: return (void *)(long)PROTO_TELEM_UNSUPPORTED;
default: break;
}
return 0;
}
*/
#endif //PROTO_HAS_NRF24L01

Binary file not shown.

BIN
Multiprotocol/opentx.bin Normal file

Binary file not shown.

View File

@ -1,24 +1,26 @@
/*
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.
//*************************************
// FrSky Telemetry serial code *
// By Midelic on RCG *
//*************************************
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.
#if defined TELEMETRY
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
#define USER_MAX_BYTES 6
#define MAX_PKTX 10
uint8_t frame[18];
uint8_t pass = 0;
uint8_t index;
uint8_t prev_index;
uint8_t pktx[MAX_PKTX];
static void frskySendStuffed(uint8_t frame[])
void frskySendStuffed()
{
Serial_write(0x7E);
for (uint8_t i = 0; i < 9; i++) {
if ((frame[i] == 0x7e) || (frame[i] == 0x7d)) {
for (uint8_t i = 0; i < 9; i++)
{
if ((frame[i] == 0x7e) || (frame[i] == 0x7d))
{
Serial_write(0x7D);
frame[i] ^= 0x20;
}
@ -27,37 +29,121 @@ static void frskySendStuffed(uint8_t frame[])
Serial_write(0x7E);
}
static void frskySendFrame()
{
uint8_t frame[9];
void compute_RSSIdbm(){
RSSI_dBm = (((uint16_t)(pktt[len-2])*18)>>5);
if(pktt[len-2] >=128)
RSSI_dBm -= 82;
else
RSSI_dBm += 65;
}
frame[0] = 0xfe;
if ((cur_protocol[0]&0x1F)==MODE_FRSKY)
{
compute_RSSIdbm();
frame[1] = pktt[3];
frame[2] = pktt[4];
frame[3] = (uint8_t)RSSI_dBm;
frame[4] = pktt[5]*2;//txrssi
frame[5] = frame[6] = frame[7] = frame[8] = 0;
}
else
if ((cur_protocol[0]&0x1F)==MODE_HUBSAN)
{
frame[1] = v_lipo*2;
frame[2] = 0;
frame[3] = 0x5A;//dummy value
frame[4] = 2 * 0x5A;//dummy value
void frsky_link_frame()
{
frame[0] = 0xfe;
#if defined(FRSKY_CC2500_INO)
if ((cur_protocol[0]&0x1F)==MODE_FRSKY) {
compute_RSSIdbm();
frame[1] = pktt[3];
frame[2] = pktt[4];
frame[3] = (uint8_t)RSSI_dBm;
frame[4] = pktt[5]*2;//txrssi
frame[5] = frame[6] = frame[7] = frame[8] = 0;
}
#endif
#if defined(HUBSAN_A7105_INO)
if ((cur_protocol[0]&0x1F)==MODE_HUBSAN) {
frame[1] = v_lipo*2; //v_lipo; common 0x2A=42/10=4.2V
frame[2] = frame[1];
frame[3] =0X6e;
frame[4] =2*0x6e;
frame[5] = frame[6] = frame[7] = frame[8] = 0;
}
frskySendStuffed(frame);
frskySendStuffed();
}
#if defined HUB_TELEMETRY
void frsky_user_frame()
{
uint8_t indexx = 0, c=0, j=8, n=0, i;
if(pktt[6]>0 && pktt[6]<=MAX_PKTX)
{//only valid hub frames
frame[0] = 0xFD;
frame[1] = 0;
frame[2] = pktt[7];
switch(pass)
{
case 0:
indexx=pktt[6];
for(i=0;i<indexx;i++)
{
if(pktt[j]==0x5E)
{
if(c++)
{
c=0;
n++;
j++;
}
}
pktx[i]=pktt[j++];
}
indexx = indexx-n;
pass=1;
case 1:
index=indexx;
prev_index = indexx;
if(index<USER_MAX_BYTES)
{
for(i=0;i<index;i++)
frame[i+3]=pktx[i];
pktt[6]=0;
pass=0;
}
else
{
index = USER_MAX_BYTES;
for(i=0;i<index;i++)
frame[i+3]=pktx[i];
pass=2;
}
break;
case 2:
index = prev_index - index;
prev_index=0;
if(index<MAX_PKTX-USER_MAX_BYTES) //10-6=4
for(i=0;i<index;i++)
frame[i+3]=pktx[USER_MAX_BYTES+i];
pass=0;
pktt[6]=0;
break;
default:
break;
}
if(!index)
return;
frame[1] = index;
frskySendStuffed();
}
else
pass=0;
}
#endif
void frskyUpdate()
{
if(telemetry_link)
{
frskySendFrame();
frsky_link_frame();
telemetry_link=0;
return;
}
#if defined HUB_TELEMETRY
if(!telemetry_link)
frsky_user_frame();
#endif
}
#endif

View File

@ -1,4 +1,7 @@
# DIY-Multiprotocol-TX-Module
Fork for adding PPM select of project https://github.com/pascallanger/DIY-Multiprotocol-TX-Module
Multiprotocol is a 2.4GHz transmitter which enables any TX to control lot of different models available on the market.
The source code is partly based on the Deviation TX project, thanks to all the developpers for their great job on protocols.
@ -26,12 +29,23 @@ The source code is partly based on the Deviation TX project, thanks to all the d
###Using standard PPM output (trainer port)
The multiprotocol TX module can be used on any TX with a trainer port.
Channels order is AETR by default but can be changed in the source code.
Channels order is AETR by default but can be changed in the _Config.h.
The protocol selection is done via a dip switch or a rotary dip switch for access to up to 15 different protocols.
The protocol selection is done via a dip switch, rotary dip switch, scsi ID selector or PPM position.
![Screenshot](http://media.digikey.com/photos/CTS%20Photos/206-4,%20206-4ST_sml.jpg)
![Screenshot](http://media.digikey.com/photos/Grayhill%20Photos/94HBB16T_sml.jpg)
![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8637216-7-thumb-SCSI%20ID%20selector.jpg?d=1453737244)
You can access to up to 15 different protocols and associated settings.
Settings per selection are located in _Config.h:
- Protocol and type: many main protocols have variants
- RX Num: number your different RXs and make sure only one model will react to the commands
- Power: High or low, enables to lower the power setting of your TX (indoor for example).
- Option: -127..+127 allowing to set specific protocol options. Like for Hubsan to set the video frequency.
- Autobind: Yes or No. At the model selection (or power applied to the TX) a bind sequence will be initiated
###Using a serial output
The multiprotocol TX module takes full advantage of being used on a Turnigy 9X, 9XR, 9XR Pro, Taranis, 9Xtreme, AR9X, ... running [er9x or ersky9X](https://github.com/MikeBland/mbtx/tree/next). (A version for OpenTX is being looked at)
@ -50,18 +64,31 @@ Options are:
Notes:
- Using this solution does not need any modification of the TX since it uses the TX module slot PPM pin for serial transfer.
- There are 2 versions of serial protocol either 8 or 16 channels. 16 channels is the latest version. Make sure to use the right version based on your version of er9x/ersky9x.
- Channels order is AETR by default but can be changed in the source code.
- There are 2 versions of serial protocol either 8 or 16 channels. 16 channels is the latest and only available version going forward. Make sure to use the right version based on your version of er9x/ersky9x.
- Channels order is AETR by default but can be changed in _Config.h.
###Telemetry
Telemetry is available for er9x and ersky9x TXs.
There are only 2 protocols so far supporting telemetry: Hubsan and Frsky.
To enable telemetry on Turnigy 9X or 9XR you need to modify your TX following one of the Frsky mod like this [one](http://blog.oscarliang.net/turnigy-9x-advance-mod/).
Hubsan displays the battery voltage.
Enabling telemetry on 9XR PRO and may be other TXs does not require any hardware modifications. The additional required serial pin is already available on the TX back module pins.
FRSky displays full telemetry (A0, A1, RSSI, TSSI and Hub).
Once the TX is telemetry enabled, it just needs to be configured on the model as usual.
### If used in PPM mode
Telemetry is available as a serial 9600 8 n 1 output on the TX pin of the Atmega328p using the FRSky hub format.
You can connect it to your TX if it is telemetry enabled or use a bluetooth adapter along with an app on your phone to display telemetry information and setup alerts.
### If used in Serial mode
Telemetry is built in for er9x and ersky9x TXs.
To enable telemetry on a Turnigy 9X or 9XR you need to modify your TX following one of the Frsky mod like this [one](http://blog.oscarliang.net/turnigy-9x-advance-mod/).
Enabling telemetry on a 9XR PRO and may be other TXs does not require any hardware modifications. The additional required serial pin is already available on the TX back module pins.
Once the TX is telemetry enabled, it just needs to be configured on the model (see er9x/ersky9x documentation).
##Protocols
@ -85,31 +112,35 @@ Notes:
###Protocol selection
####Using the dial for PPM input
PPM is only allowing access to a subset of existing protocols & sub_protocols.
PPM is only allowing access to a subset of existing protocols.
The default association dial position / protocol is listed below.
Dial|Protocol|Sub_protocol|RF Module
----|--------|------------|---------
0|Select serial||
1|FLYSKY|Flysky|A7105
2|HUBSAN|-|A7105
3|FRSKY|-|CC2500
4|HISKY|Hisky|NRF24L01
5|V2X2|-|NRF24L01
6|DSM2|DSM2|CYRF6936
7|DEVO|-|CYRF6936
8|YD717|YD717|NRF24L01
9|KN|WLTOYS|NRF24L01
10|SYMAX|SYMAX|NRF24L01
11|SLT|-|NRF24L01
12|CX10|CX10_BLUE|NRF24L01
13|CG023|CG023|NRF24L01
14|BAYANG|-|NRF24L01
15|SYMAX|SYMAX5C|NRF24L01
Dial|Protocol|Sub_protocol|RX Num|Power|Auto Bind|Option|RF Module
----|--------|------------|------|-----|---------|------|---------
0|Select PPM||||||
1|FLYSKY|Flysky|0|High|No|0|A7105
2|HUBSAN|-|0|High|No|0|A7105
3|FRSKY|-|0|High|No|-41|CC2500
4|HISKY|Hisky|0|High|No|0|NRF24L01
5|V2X2|-|0|High|No|0|NRF24L01
6|DSM2|DSM2|0|High|No|0|CYRF6936
7|DEVO|-|0|High|No|0|CYRF6936
8|YD717|YD717|0|High|No|0|NRF24L01
9|KN|WLTOYS|0|High|No|0|NRF24L01
10|SYMAX|SYMAX|0|High|No|0|NRF24L01
11|SLT|-|0|High|No|0|NRF24L01
12|CX10|CX10_BLUE|0|High|No|0|NRF24L01
13|CG023|CG023|0|High|No|0|NRF24L01
14|BAYANG|-|0|High|No|0|NRF24L01
15|SYMAX|SYMAX5C|0|High|No|0|NRF24L01
Notes:
- The dial selection must be done before the power is applied.
- The protocols and subprotocols accessible by the dial can be personalized by modifying the source code.
- The protocols, subprotocols and all other settings can be personalized by modifying the _Config.h file.
#####Select PPM
Calculating the desired protocol with the position of the sleeves during startup or reset. This allows for a choice of 26 protocols. A path is lost in order to have a hardware reset if using "PPM selection".
To simplify the memorization, I provided a lua script for OPENTX.
####Using serial input with er9x/ersky9x
Serial is allowing access to all existing protocols & sub_protocols listed below.
@ -152,6 +183,7 @@ CX10||NRF24L01
|JC3015_1
|JC3015_2
|MK33041
|Q242
CG023||NRF24L01
|CG023
|YD829
@ -239,7 +271,7 @@ CH5|CH6|CH7|CH8|CH9
---|---|---|---|---
FLIP|MODE|PICTURE|VIDEO|HEADLESS
#####Sub_protocol CX10_Q282
#####Sub_protocol CX10_Q282 and CX10_Q242
CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12
---|---|---|---|---|---|---|---
@ -308,7 +340,7 @@ BTMBTN|TOPBTN
####FRSKY
Extended limits supported
Telemetry enabled for A0, A1, RSSI
Telemetry enabled for A0, A1, RSSI, TSSI and Hub
Option=fine frequency tuning, usually 0 or -41 based on the manufacturer boards
@ -419,11 +451,12 @@ An [Arduino pro mini](http://www.banggood.com/Wholesale-New-Ver-Pro-Mini-ATMEGA3
Using stripboard:
![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t8214655-87-thumb-uploadfromtaptalk1405598143749.jpg?d=1441459923)
![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t8214656-102-thumb-uploadfromtaptalk1405598152484.jpg?d=1441459924)
Using a [home made PCB](http://www.rcgroups.com/forums/showpost.php?p=32645328&postcount=1621):
![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8226719-72-thumb-IMG_20150715_230024065.jpg?d=1441816456)
![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8226720-197-thumb-IMG_20150715_230603155.jpg?d=1441816457)
![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8226719-72-thumb-IMG_20150715_230024065.jpg?d=1441816456)
or build your own board using [SMD components](http://www.rcgroups.com/forums/showpost.php?p=31064232&postcount=1020) and an [associated PCB](https://oshpark.com/shared_projects/MaGYDg0y):
@ -455,7 +488,7 @@ Arduino 1.6.5
Compilation of the code posted here works. So if it doesn't for you this is a problem with your setup, please double check everything before asking.
Multiprotocol.ino header can be modified to compile with/without some protocols, change protocols/sub_protocols associated with dial for PPM input, different channel orders, different channels timing, 8 or 16 channels serial protocol, Telemetry or not, ...
_Config.h file can be modified to compile with/without some protocols, change protocols/sub_protocols/settings associated with dial for PPM input, different channel orders, different channels timing, Telemetry or not, ...
###Upload the code using ISP (In System Programming)
It is recommended to use an external programmer like [USBASP](http://www.banggood.com/USBASP-USBISP-3_3-5V-AVR-Downloader-Programmer-With-ATMEGA8-ATMEGA128-p-934425.html) to upload the code in the Atmega328. The programmer should be set to 3.3V or nothing to not supply any over voltage to the multimodule and avoid any damages.

BIN
sync.ffs_db Normal file

Binary file not shown.