From 1c02cb46f529d6be58683e525096a75dfc7ec04b Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Mon, 13 Apr 2020 22:10:58 +0200 Subject: [PATCH] FrSky Clone mode Check documentation for full details: https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Protocols_Details.md#FRSKY_RX---55 --- Multiprotocol/FrSkyDVX_common.ino | 39 +- Multiprotocol/FrSkyD_cc2500.ino | 2 +- Multiprotocol/FrSkyX_cc2500.ino | 26 +- Multiprotocol/FrSky_Rx_cc2500.ino | 575 ++++++++++++++++++------------ Multiprotocol/Multi.txt | 6 +- Multiprotocol/Multi_Names.ino | 9 +- Multiprotocol/Multiprotocol.h | 23 +- Multiprotocol/_Config.h | 8 +- Protocols_Details.md | 39 +- 9 files changed, 455 insertions(+), 272 deletions(-) diff --git a/Multiprotocol/FrSkyDVX_common.ino b/Multiprotocol/FrSkyDVX_common.ino index 0a07ad7..d8f68d7 100644 --- a/Multiprotocol/FrSkyDVX_common.ino +++ b/Multiprotocol/FrSkyDVX_common.ino @@ -50,6 +50,8 @@ enum { FRSKY_DATA5, }; +uint8_t FrSkyFormat=0; + void Frsky_init_hop(void) { uint8_t val; @@ -86,15 +88,14 @@ void FrSkyX2_init_hop(void) { channel = 5 * (uint16_t(inc * i) % 47) + offset; //Exception list from dumps - if(sub_protocol & 2 )// LBT or FCC - { - //LBT + if(FrSkyFormat & 2 )// LBT or FCC + {//LBT if( channel <=1 || channel == 43 || channel == 44 || channel == 87 || channel == 88 || channel == 129 || channel == 130 || channel == 173 || channel == 174) channel += 2; else if( channel == 216 || channel == 217 || channel == 218) channel += 3; } - else // FCC + else //FCC if ( channel == 3 || channel == 4 || channel == 46 || channel == 47 || channel == 90 || channel == 91 || channel == 133 || channel == 134 || channel == 176 || channel == 177 || channel == 220 || channel == 221 ) channel += 2; //Store @@ -107,15 +108,29 @@ void FrSkyX2_init_hop(void) void Frsky_init_clone(void) { - uint16_t temp = FRSKY_RX_EEPROM_OFFSET; - temp++; + debugln("Clone mode"); + uint16_t temp = FRSKYD_CLONE_EEPROM_OFFSET; + if(protocol==PROTO_FRSKYX) + temp=FRSKYX_CLONE_EEPROM_OFFSET; + else if(protocol==PROTO_FRSKYX2) + temp=FRSKYX2_CLONE_EEPROM_OFFSET; + FrSkyFormat=eeprom_read_byte((EE_ADDR)temp++); + if(protocol==PROTO_FRSKYX) + FrSkyFormat >>= 1; + else + FrSkyFormat >>= 2; + FrSkyFormat <<= 1; //FCC_16/LBT_16 rx_tx_addr[3] = eeprom_read_byte((EE_ADDR)temp++); rx_tx_addr[2] = eeprom_read_byte((EE_ADDR)temp++); rx_tx_addr[1] = eeprom_read_byte((EE_ADDR)temp++); - temp++; - for (uint8_t ch = 0; ch < 47; ch++) - hopping_frequency[ch] = eeprom_read_byte((EE_ADDR)temp++); - debugln("Clone mode"); + memset(hopping_frequency,0x00,50); + if(protocol!=PROTO_FRSKYX2) + {//D8 and D16v1 + for (uint8_t ch = 0; ch < 47; ch++) + hopping_frequency[ch] = eeprom_read_byte((EE_ADDR)temp++); + } + else + FrSkyX2_init_hop(); } #endif @@ -325,11 +340,11 @@ static void __attribute__((unused)) FrSkyX_init() if(protocol==PROTO_FRSKYL) FRSKY_init_cc2500(FRSKYL_cc2500_conf); else - FRSKY_init_cc2500((sub_protocol&2)?FRSKYXEU_cc2500_conf:FRSKYX_cc2500_conf); // LBT or FCC + FRSKY_init_cc2500((FrSkyFormat&2)?FRSKYXEU_cc2500_conf:FRSKYX_cc2500_conf); // LBT or FCC if(protocol==PROTO_FRSKYX2) { CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x05); // Enable CRC - if(!(sub_protocol&2)) + if(!(FrSkyFormat&2)) { // FCC CC2500_WriteReg(CC2500_17_MCSM1, 0x0E); // Go/Stay in RX mode CC2500_WriteReg(CC2500_11_MDMCFG3, 0x84); // bitrate 70K->77K diff --git a/Multiprotocol/FrSkyD_cc2500.ino b/Multiprotocol/FrSkyD_cc2500.ino index fcbddb3..342a268 100644 --- a/Multiprotocol/FrSkyD_cc2500.ino +++ b/Multiprotocol/FrSkyD_cc2500.ino @@ -97,7 +97,7 @@ static void __attribute__((unused)) frsky2way_data_frame() uint16_t initFrSky_2way() { //FrskyD init hop - if (eeprom_read_byte((EE_ADDR)FRSKY_RX_EEPROM_OFFSET+4)==127 && eeprom_read_byte((EE_ADDR)FRSKY_RX_EEPROM_OFFSET)==2)// bound in FRSKY-RX CloneTX -> use clone mode + if (sub_protocol==DCLONE) Frsky_init_clone(); else for(uint8_t i=0;i<50;i++) diff --git a/Multiprotocol/FrSkyX_cc2500.ino b/Multiprotocol/FrSkyX_cc2500.ino index b5ff111..89f06ff 100644 --- a/Multiprotocol/FrSkyX_cc2500.ino +++ b/Multiprotocol/FrSkyX_cc2500.ino @@ -20,7 +20,7 @@ static void __attribute__((unused)) FrSkyX_build_bind_packet() { uint8_t packet_size = 0x1D; - if(protocol==PROTO_FRSKYX && (sub_protocol & 2 )) + if(protocol==PROTO_FRSKYX && (FrSkyFormat & 2 )) packet_size=0x20; // FrSkyX V1 LBT //Header packet[0] = packet_size; // Number of bytes in the packet (after this one) @@ -97,7 +97,7 @@ static void __attribute__((unused)) FrSkyX_build_packet() { FS_flag = 0x10; failsafe_chan = 0; - } else if (FS_flag & 0x10 && failsafe_chan < (sub_protocol & 0x01 ? 8-1:16-1)) + } else if (FS_flag & 0x10 && failsafe_chan < (FrSkyFormat & 0x01 ? 8-1:16-1)) { FS_flag = 0x10 | ((FS_flag + 2) & 0x0F); //10, 12, 14, 16, 18, 1A, 1C, 1E - failsafe packet failsafe_chan ++; @@ -111,7 +111,7 @@ static void __attribute__((unused)) FrSkyX_build_packet() #endif uint8_t packet_size = 0x1D; - if(protocol==PROTO_FRSKYX && (sub_protocol & 2 )) + if(protocol==PROTO_FRSKYX && (FrSkyFormat & 2 )) packet_size=0x20; // FrSkyX V1 LBT //Header packet[0] = packet_size; // Number of bytes in the packet (after this one) @@ -155,7 +155,7 @@ static void __attribute__((unused)) FrSkyX_build_packet() packet[9+i+1]=(((chan_0>>8) & 0x0F)|(chan_1 << 4)); packet[9+i+2]=chan_1>>4; } - if(sub_protocol & 0x01 ) //In X8 mode send only 8ch every 9ms + if(FrSkyFormat & 0x01 ) //In X8 mode send only 8ch every 9ms chan_offset = 0 ; else chan_offset^=0x08; @@ -285,14 +285,14 @@ uint16_t ReadFrSkyX() } FrSkyX_set_start(hopping_frequency_no); FrSkyX_build_packet(); - if(sub_protocol & 2) + if(FrSkyFormat & 2) {// LBT CC2500_Strobe(CC2500_SRX); //Acquire RSSI state++; return 400; // LBT v2.1 } case FRSKY_DATA2: - if(sub_protocol & 2) + if(FrSkyFormat & 2) { uint16_t rssi=0; for(uint8_t i=0;i<4;i++) @@ -316,7 +316,7 @@ uint16_t ReadFrSkyX() hopping_frequency_no = (hopping_frequency_no+FrSkyX_chanskip)%47; CC2500_WriteData(packet, packet[0]+1); state=FRSKY_DATA3; - if(sub_protocol & 2) + if(FrSkyFormat & 2) return 4000; // LBT v2.1 else return 5200; // FCC v2.1 @@ -325,7 +325,7 @@ uint16_t ReadFrSkyX() CC2500_SetTxRxMode(RX_EN); CC2500_Strobe(CC2500_SRX); state++; - if(sub_protocol & 2) + if(FrSkyFormat & 2) return 4100; // LBT v2.1 else return 3300; // FCC v2.1 @@ -383,12 +383,15 @@ uint16_t ReadFrSkyX() uint16_t initFrSkyX() { set_rx_tx_addr(MProtocol_id_master); - rx_tx_addr[1]=0x02; // ID related, hw version? - - if (eeprom_read_byte((EE_ADDR)FRSKY_RX_EEPROM_OFFSET+4)==127 && eeprom_read_byte((EE_ADDR)FRSKY_RX_EEPROM_OFFSET)<2)// bound in FRSKY-RX CloneTX -> use clone mode + FrSkyFormat = sub_protocol; + + if (sub_protocol==XCLONE) Frsky_init_clone(); else if(protocol==PROTO_FRSKYX) + { Frsky_init_hop(); + rx_tx_addr[1]=0x02; // ID related, hw version? + } else { #ifdef FRSKYX2_FORCE_ID @@ -396,6 +399,7 @@ uint16_t initFrSkyX() rx_tx_addr[2]=0x1C; FrSkyX_chanskip=18; #endif + rx_tx_addr[1]=0x02; // ID related, hw version? FrSkyX2_init_hop(); } diff --git a/Multiprotocol/FrSky_Rx_cc2500.ino b/Multiprotocol/FrSky_Rx_cc2500.ino index 6b397f4..27cfdd9 100644 --- a/Multiprotocol/FrSky_Rx_cc2500.ino +++ b/Multiprotocol/FrSky_Rx_cc2500.ino @@ -17,17 +17,19 @@ #include "iface_cc2500.h" - #define FRSKY_RX_D16FCC_LENGTH 32 - #define FRSKY_RX_D16LBT_LENGTH 35 - #define FRSKY2_RX_D16_LENGTH 32 - #define FRSKY_RX_D8_LENGTH 20 - #define FRSKY_RX_FORMATS 3 + #define FRSKY_RX_D16FCC_LENGTH 0x1D+1 + #define FRSKY_RX_D16LBT_LENGTH 0x20+1 + #define FRSKY_RX_D16v2_LENGTH 0x1D+1 + #define FRSKY_RX_D8_LENGTH 0x11+1 + #define FRSKY_RX_FORMATS 5 enum { - FRSKY_RX_D16FCC = 0, - FRSKY_RX_D16LBT, - FRSKY_RX_D8 + FRSKY_RX_D8 =0, + FRSKY_RX_D16FCC =1, + FRSKY_RX_D16LBT =2, + FRSKY_RX_D16v2FCC =3, + FRSKY_RX_D16v2LBT =4, }; enum { @@ -41,7 +43,7 @@ enum { const PROGMEM uint8_t frsky_rx_common_reg[][2] = { {CC2500_02_IOCFG0, 0x01}, {CC2500_18_MCSM0, 0x18}, - {CC2500_07_PKTCTRL1, 0x04}, + {CC2500_07_PKTCTRL1, 0x05}, {CC2500_3E_PATABLE, 0xFF}, {CC2500_0C_FSCTRL0, 0}, {CC2500_0D_FREQ2, 0x5C}, @@ -63,7 +65,7 @@ const PROGMEM uint8_t frsky_rx_common_reg[][2] = { {CC2500_2D_TEST1, 0x31}, {CC2500_2E_TEST0, 0x0B}, {CC2500_03_FIFOTHR, 0x07}, - {CC2500_09_ADDR, 0x00}, + {CC2500_09_ADDR, 0x03}, }; const PROGMEM uint8_t frsky_rx_d16fcc_reg[][2] = { @@ -117,29 +119,38 @@ static void __attribute__((unused)) frsky_rx_strobe_rx() } static void __attribute__((unused)) frsky_rx_initialise_cc2500() { - const uint8_t frsky_rx_length[] = { FRSKY_RX_D16FCC_LENGTH, FRSKY_RX_D16LBT_LENGTH, FRSKY_RX_D8_LENGTH }; + const uint8_t frsky_rx_length[] = { FRSKY_RX_D8_LENGTH, FRSKY_RX_D16FCC_LENGTH, FRSKY_RX_D16LBT_LENGTH, FRSKY_RX_D16v2_LENGTH, FRSKY_RX_D16v2_LENGTH }; packet_length = frsky_rx_length[frsky_rx_format]; CC2500_Reset(); CC2500_Strobe(CC2500_SIDLE); for (uint8_t i = 0; i < sizeof(frsky_rx_common_reg) / 2; i++) CC2500_WriteReg(pgm_read_byte_near(&frsky_rx_common_reg[i][0]), pgm_read_byte_near(&frsky_rx_common_reg[i][1])); - switch (frsky_rx_format) { - case FRSKY_RX_D16FCC: - for (uint8_t i = 0; i < sizeof(frsky_rx_d16fcc_reg) / 2; i++) - CC2500_WriteReg(pgm_read_byte_near(&frsky_rx_d16fcc_reg[i][0]), pgm_read_byte_near(&frsky_rx_d16fcc_reg[i][1])); - break; - case FRSKY_RX_D16LBT: - for (uint8_t i = 0; i < sizeof(frsky_rx_d16lbt_reg) / 2; i++) - CC2500_WriteReg(pgm_read_byte_near(&frsky_rx_d16lbt_reg[i][0]), pgm_read_byte_near(&frsky_rx_d16lbt_reg[i][1])); - break; - case FRSKY_RX_D8: - for (uint8_t i = 0; i < sizeof(frsky_rx_d8_reg) / 2; i++) - CC2500_WriteReg(pgm_read_byte_near(&frsky_rx_d8_reg[i][0]), pgm_read_byte_near(&frsky_rx_d8_reg[i][1])); - CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x05); // always check address - CC2500_WriteReg(CC2500_09_ADDR, 0x03); // bind address - CC2500_WriteReg(CC2500_23_FSCAL3, 0x89); - break; + switch (frsky_rx_format) + { + case FRSKY_RX_D16v2FCC: + case FRSKY_RX_D16FCC: + for (uint8_t i = 0; i < sizeof(frsky_rx_d16fcc_reg) / 2; i++) + CC2500_WriteReg(pgm_read_byte_near(&frsky_rx_d16fcc_reg[i][0]), pgm_read_byte_near(&frsky_rx_d16fcc_reg[i][1])); + if(frsky_rx_format==FRSKY_RX_D16v2FCC) + { + CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x05); // Enable CRC + CC2500_WriteReg(CC2500_17_MCSM1, 0x0E); // Go/Stay in RX mode + CC2500_WriteReg(CC2500_11_MDMCFG3, 0x84); // bitrate 70K->77K + } + break; + case FRSKY_RX_D16v2LBT: + case FRSKY_RX_D16LBT: + for (uint8_t i = 0; i < sizeof(frsky_rx_d16lbt_reg) / 2; i++) + CC2500_WriteReg(pgm_read_byte_near(&frsky_rx_d16lbt_reg[i][0]), pgm_read_byte_near(&frsky_rx_d16lbt_reg[i][1])); + if(frsky_rx_format==FRSKY_RX_D16v2LBT) + CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x05); // Enable CRC + break; + case FRSKY_RX_D8: + for (uint8_t i = 0; i < sizeof(frsky_rx_d8_reg) / 2; i++) + CC2500_WriteReg(pgm_read_byte_near(&frsky_rx_d8_reg[i][0]), pgm_read_byte_near(&frsky_rx_d8_reg[i][1])); + CC2500_WriteReg(CC2500_23_FSCAL3, 0x89); + break; } CC2500_WriteReg(CC2500_0A_CHANNR, 0); // bind channel rx_disable_lna = IS_POWER_FLAG_on; @@ -170,16 +181,70 @@ static void __attribute__((unused)) frsky_rx_calibrate() } } -static uint8_t __attribute__((unused)) frskyx_rx_check_crc() +static uint8_t __attribute__((unused)) frskyx_rx_check_crc_id(bool bind,bool init) { - // check D8 checksum + /*debugln("RX"); + for(uint8_t i=0; i> 4); raw_channel[2] = ((packet[13] << 8) & 0xF00) | packet[12]; @@ -212,22 +293,6 @@ static void __attribute__((unused)) frsky_rx_build_telemetry_packet() } } } - else { - // decode D8 channels - raw_channel[0] = ((packet[10] & 0x0F) << 8 | packet[6]); - raw_channel[1] = ((packet[10] & 0xF0) << 4 | packet[7]); - raw_channel[2] = ((packet[11] & 0x0F) << 8 | packet[8]); - raw_channel[3] = ((packet[11] & 0xF0) << 4 | packet[9]); - raw_channel[4] = ((packet[16] & 0x0F) << 8 | packet[12]); - raw_channel[5] = ((packet[16] & 0xF0) << 4 | packet[13]); - raw_channel[6] = ((packet[17] & 0x0F) << 8 | packet[14]); - raw_channel[7] = ((packet[17] & 0xF0) << 4 | packet[15]); - for (i = 0; i < 8; i++) { - if (raw_channel[i] < 1290) - raw_channel[i] = 1290; - rx_rc_chan[i] = min(((raw_channel[i] - 1290) << 4) / 15, 2047); - } - } // buid telemetry packet packet_in[idx++] = RX_LQI; @@ -247,6 +312,49 @@ static void __attribute__((unused)) frsky_rx_build_telemetry_packet() } } +static void __attribute__((unused)) frsky_rx_data() +{ + uint16_t temp = FRSKY_RX_EEPROM_OFFSET; + frsky_rx_format = eeprom_read_byte((EE_ADDR)temp++) % FRSKY_RX_FORMATS; + rx_tx_addr[3] = eeprom_read_byte((EE_ADDR)temp++); + rx_tx_addr[2] = eeprom_read_byte((EE_ADDR)temp++); + rx_tx_addr[1] = eeprom_read_byte((EE_ADDR)temp++); + rx_tx_addr[0] = RX_num; + frsky_rx_finetune = eeprom_read_byte((EE_ADDR)temp++); + debug("format=%d, ", frsky_rx_format); + debug("addr[3]=%02X, ", rx_tx_addr[3]); + debug("addr[2]=%02X, ", rx_tx_addr[2]); + debug("addr[1]=%02X, ", rx_tx_addr[1]); + debug("rx_num=%02X, ", rx_tx_addr[0]); + debugln("tune=%d", (int8_t)frsky_rx_finetune); + if(frsky_rx_format != FRSKY_RX_D16v2LBT && frsky_rx_format != FRSKY_RX_D16v2FCC) + {//D8 & D16v1 + for (uint8_t ch = 0; ch < 47; ch++) + hopping_frequency[ch] = eeprom_read_byte((EE_ADDR)temp++); + } + else + { + FrSkyFormat=frsky_rx_format == FRSKY_RX_D16v2FCC?0:2; + FrSkyX2_init_hop(); + } + debug("ch:"); + for (uint8_t ch = 0; ch < 47; ch++) + debug(" %02X", hopping_frequency[ch]); + debugln(""); + + frsky_rx_initialise_cc2500(); + frsky_rx_calibrate(); + CC2500_WriteReg(CC2500_18_MCSM0, 0x08); // FS_AUTOCAL = manual + CC2500_WriteReg(CC2500_09_ADDR, rx_tx_addr[3]); // set address + CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x05); // check address + if (option == 0) + CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune); + else + CC2500_WriteReg(CC2500_0C_FSCTRL0, option); + frsky_rx_set_channel(hopping_frequency_no); + phase = FRSKY_RX_DATA; +} + uint16_t initFrSky_Rx() { state = 0; @@ -255,32 +363,16 @@ uint16_t initFrSky_Rx() rx_data_started = false; frsky_rx_finetune = 0; telemetry_link = 0; - if (IS_BIND_IN_PROGRESS) { + packet_count = 0; + if (IS_BIND_IN_PROGRESS) + { frsky_rx_format = FRSKY_RX_D8; frsky_rx_initialise_cc2500(); phase = FRSKY_RX_TUNE_START; + debugln("FRSKY_RX_TUNE_START"); } - else { - uint16_t temp = FRSKY_RX_EEPROM_OFFSET; - frsky_rx_format = eeprom_read_byte((EE_ADDR)temp++) % FRSKY_RX_FORMATS; - rx_tx_addr[0] = eeprom_read_byte((EE_ADDR)temp++); - rx_tx_addr[1] = eeprom_read_byte((EE_ADDR)temp++); - rx_tx_addr[2] = eeprom_read_byte((EE_ADDR)temp++); - frsky_rx_finetune = eeprom_read_byte((EE_ADDR)temp++); - for (uint8_t ch = 0; ch < 47; ch++) - hopping_frequency[ch] = eeprom_read_byte((EE_ADDR)temp++); - frsky_rx_initialise_cc2500(); - frsky_rx_calibrate(); - CC2500_WriteReg(CC2500_18_MCSM0, 0x08); // FS_AUTOCAL = manual - CC2500_WriteReg(CC2500_09_ADDR, rx_tx_addr[0]); // set address - CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x05); // check address - if (option == 0) - CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune); - else - CC2500_WriteReg(CC2500_0C_FSCTRL0, option); - frsky_rx_set_channel(hopping_frequency_no); - phase = FRSKY_RX_DATA; - } + else + frsky_rx_data(); return 1000; } @@ -292,7 +384,8 @@ uint16_t FrSky_Rx_callback() static int8_t tune_low, tune_high; uint8_t len, ch; - if ((prev_option != option) && (phase >= FRSKY_RX_DATA)) { + if ((prev_option != option) && (phase >= FRSKY_RX_DATA)) + { if (option == 0) CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune); else @@ -300,169 +393,199 @@ uint16_t FrSky_Rx_callback() prev_option = option; } - if (rx_disable_lna != IS_POWER_FLAG_on) { + if (rx_disable_lna != IS_POWER_FLAG_on) + { rx_disable_lna = IS_POWER_FLAG_on; CC2500_SetTxRxMode(rx_disable_lna ? TXRX_OFF : RX_EN); } len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F; - - switch(phase) { - case FRSKY_RX_TUNE_START: - if (len >= packet_length) { - CC2500_ReadData(packet, packet_length); - if(packet[1] == 0x03 && packet[2] == 0x01 && frskyx_rx_check_crc()) { - rx_tx_addr[0] = packet[3]; // TXID - rx_tx_addr[1] = packet[4]; // TXID - rx_tx_addr[2] = packet[11]; // TXID - frsky_rx_finetune = -127; - CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune); - phase = FRSKY_RX_TUNE_LOW; - frsky_rx_strobe_rx(); - return 1000; - } - } - frsky_rx_format = (frsky_rx_format + 1) % FRSKY_RX_FORMATS; // switch to next format (D16FCC, D16LBT, D8) - frsky_rx_initialise_cc2500(); - frsky_rx_finetune += 10; - CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune); - frsky_rx_strobe_rx(); - return 18000; - - case FRSKY_RX_TUNE_LOW: - if (len >= packet_length) { - CC2500_ReadData(packet, packet_length); - if(packet[1] == 0x03 && packet[2] == 0x01 && frskyx_rx_check_crc() && packet[3] == rx_tx_addr[0] && packet[4] == rx_tx_addr[1] && (frsky_rx_format == FRSKY_RX_D8 || packet[11] == rx_tx_addr[2])) { - tune_low = frsky_rx_finetune; - frsky_rx_finetune = 127; - CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune); - phase = FRSKY_RX_TUNE_HIGH; - frsky_rx_strobe_rx(); - return 1000; - } - } - frsky_rx_finetune += 1; - CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune); - frsky_rx_strobe_rx(); - return 18000; - - case FRSKY_RX_TUNE_HIGH: - if (len >= packet_length) { - CC2500_ReadData(packet, packet_length); - if(packet[1] == 0x03 && packet[2] == 0x01 && frskyx_rx_check_crc() && packet[3] == rx_tx_addr[0] && packet[4] == rx_tx_addr[1] && (frsky_rx_format == FRSKY_RX_D8 || packet[11] == rx_tx_addr[2])) { - tune_high = frsky_rx_finetune; - frsky_rx_finetune = (tune_low + tune_high) / 2; - CC2500_WriteReg(CC2500_0C_FSCTRL0, (int8_t)frsky_rx_finetune); - if(tune_low < tune_high) - phase = FRSKY_RX_BIND; - else - phase = FRSKY_RX_TUNE_START; - frsky_rx_strobe_rx(); - return 1000; - } - } - frsky_rx_finetune -= 1; - CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune); - frsky_rx_strobe_rx(); - return 18000; - - case FRSKY_RX_BIND: - if(len >= packet_length) { - CC2500_ReadData(packet, packet_length); - if(packet[1] == 0x03 && packet[2] == 0x01 && frskyx_rx_check_crc() && packet[3] == rx_tx_addr[0] && packet[4] == rx_tx_addr[1] && (frsky_rx_format == FRSKY_RX_D8 || packet[11] == rx_tx_addr[2]) && packet[5] <= 0x2D) { - for (ch = 0; ch < 5; ch++) - hopping_frequency[packet[5]+ch] = packet[6+ch]; - state |= 1 << (packet[5] / 5); - if (state == 0x3ff) { - debug("Bind complete: "); - frsky_rx_calibrate(); - CC2500_WriteReg(CC2500_18_MCSM0, 0x08); // FS_AUTOCAL = manual - CC2500_WriteReg(CC2500_09_ADDR, rx_tx_addr[0]); // set address - CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x05); // check address - phase = FRSKY_RX_DATA; - frsky_rx_set_channel(hopping_frequency_no); - // store format, finetune setting, txid, channel list - uint16_t temp = FRSKY_RX_EEPROM_OFFSET; - eeprom_write_byte((EE_ADDR)temp++, frsky_rx_format); - debug("format=%d, ", frsky_rx_format); - eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[0]); - debug("addr[0]=%02X, ", rx_tx_addr[0]); - eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[1]); - debug("addr[1]=%02X, ", rx_tx_addr[1]); - eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[2]); - debug("addr[2]=%02X, ", rx_tx_addr[2]); - debug("rx_num=%02X, ", packet[12]); // RX # (D16) - if (sub_protocol==FRSKY_CLONE) - eeprom_write_byte((EE_ADDR)temp++, 127); - else - { - eeprom_write_byte((EE_ADDR)temp++, frsky_rx_finetune); - debugln("tune=%d", (int8_t)frsky_rx_finetune); - } - for (ch = 0; ch < 47; ch++) - { - eeprom_write_byte((EE_ADDR)temp++, hopping_frequency[ch]); - debug("%02X ", hopping_frequency[ch]); - } - debugln(""); - BIND_DONE; - } - } - frsky_rx_strobe_rx(); - } - return 1000; - - case FRSKY_RX_DATA: - if (len >= packet_length) { - CC2500_ReadData(packet, packet_length); - if (packet[1] == rx_tx_addr[0] && packet[2] == rx_tx_addr[1] && frskyx_rx_check_crc() && (frsky_rx_format == FRSKY_RX_D8 || (packet[6] == RX_num && packet[3] == rx_tx_addr[2]))) { - RX_RSSI = packet[packet_length-2]; - if(RX_RSSI >= 128) - RX_RSSI -= 128; - else - RX_RSSI += 128; - bool chanskip_valid=true; - // hop to next channel - if (frsky_rx_format == FRSKY_RX_D16FCC || frsky_rx_format == FRSKY_RX_D16LBT) + switch(phase) + { + case FRSKY_RX_TUNE_START: + if (len == packet_length + 2) //+2=RSSI+LQI+CRC + { + CC2500_ReadData(packet, len); + if(frskyx_rx_check_crc_id(true,true)) { - if(rx_data_started) + frsky_rx_finetune = -127; + CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune); + phase = FRSKY_RX_TUNE_LOW; + debugln("FRSKY_RX_TUNE_LOW"); + frsky_rx_strobe_rx(); + return 1000; + } + } + frsky_rx_format = (frsky_rx_format + 1) % FRSKY_RX_FORMATS; // switch to next format (D8, D16FCC, D16LBT, D16v2FCC, D16v2LBT) + frsky_rx_initialise_cc2500(); + frsky_rx_finetune += 10; + CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune); + frsky_rx_strobe_rx(); + return 18000; + + case FRSKY_RX_TUNE_LOW: + if (len == packet_length + 2) //+2=RSSI+LQI+CRC + { + CC2500_ReadData(packet, len); + if(frskyx_rx_check_crc_id(true,false)) { + tune_low = frsky_rx_finetune; + frsky_rx_finetune = 127; + CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune); + phase = FRSKY_RX_TUNE_HIGH; + debugln("FRSKY_RX_TUNE_HIGH"); + frsky_rx_strobe_rx(); + return 1000; + } + } + frsky_rx_finetune += 1; + CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune); + frsky_rx_strobe_rx(); + return 18000; + + case FRSKY_RX_TUNE_HIGH: + if (len == packet_length + 2) //+2=RSSI+LQI+CRC + { + CC2500_ReadData(packet, len); + if(frskyx_rx_check_crc_id(true,false)) { + tune_high = frsky_rx_finetune; + frsky_rx_finetune = (tune_low + tune_high) / 2; + CC2500_WriteReg(CC2500_0C_FSCTRL0, (int8_t)frsky_rx_finetune); + if(tune_low < tune_high) { - if(frsky_rx_chanskip != (((packet[4] & 0xC0) >> 6) | ((packet[5] & 0x3F) << 2))) - chanskip_valid=false; // chanskip value has changed which surely indicates a bad frame + phase = FRSKY_RX_BIND; + debugln("FRSKY_RX_TUNE_HIGH"); } else - frsky_rx_chanskip = ((packet[4] & 0xC0) >> 6) | ((packet[5] & 0x3F) << 2); // chanskip init + { + phase = FRSKY_RX_TUNE_START; + debugln("FRSKY_RX_TUNE_START"); + } + frsky_rx_strobe_rx(); + return 1000; } + } + frsky_rx_finetune -= 1; + CC2500_WriteReg(CC2500_0C_FSCTRL0, frsky_rx_finetune); + frsky_rx_strobe_rx(); + return 18000; + + case FRSKY_RX_BIND: + if (len == packet_length + 2) //+2=RSSI+LQI+CRC + { + CC2500_ReadData(packet, len); + if(frskyx_rx_check_crc_id(true,false)) { + if(frsky_rx_format != FRSKY_RX_D16v2LBT && frsky_rx_format != FRSKY_RX_D16v2FCC) + {// D8 & D16v1 + if(packet[5] <= 0x2D) + { + for (ch = 0; ch < 5; ch++) + hopping_frequency[packet[5]+ch] = packet[6+ch]; + state |= 1 << (packet[5] / 5); + } + } + else + state=0x3FF; //No hop table for D16v2 + if (state == 0x3FF) + { + debugln("Bind complete"); + BIND_DONE; + // store format, finetune setting, txid, channel list + uint16_t temp = FRSKY_RX_EEPROM_OFFSET; + if(sub_protocol==FRSKY_CLONE) + { + if(frsky_rx_format==FRSKY_RX_D8) + temp=FRSKYD_CLONE_EEPROM_OFFSET; + else if(frsky_rx_format == FRSKY_RX_D16FCC || frsky_rx_format == FRSKY_RX_D16LBT) + temp=FRSKYX_CLONE_EEPROM_OFFSET; + else + temp=FRSKYX2_CLONE_EEPROM_OFFSET; + } + eeprom_write_byte((EE_ADDR)temp++, frsky_rx_format); + eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[3]); + eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[2]); + eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[1]); + if(sub_protocol==FRSKY_RX) + eeprom_write_byte((EE_ADDR)temp++, frsky_rx_finetune); + if(frsky_rx_format != FRSKY_RX_D16v2FCC && frsky_rx_format != FRSKY_RX_D16v2LBT) + for (ch = 0; ch < 47; ch++) + eeprom_write_byte((EE_ADDR)temp++, hopping_frequency[ch]); + frsky_rx_data(); + debugln("FRSKY_RX_DATA"); + } + } + frsky_rx_strobe_rx(); + } + return 1000; + + case FRSKY_RX_DATA: + if (len == packet_length + 2) //+2=RSSI+LQI+CRC + { + CC2500_ReadData(packet, len); + if(frskyx_rx_check_crc_id(false,false)) + { + RX_RSSI = packet[len-2]; + if(RX_RSSI >= 128) + RX_RSSI -= 128; + else + RX_RSSI += 128; + bool chanskip_valid=true; + // hop to next channel + if (frsky_rx_format != FRSKY_RX_D8) + {//D16v1 & D16v2 + if(rx_data_started) + { + if(frsky_rx_chanskip != (((packet[4] & 0xC0) >> 6) | ((packet[5] & 0x3F) << 2))) + { + chanskip_valid=false; // chanskip value has changed which surely indicates a bad frame + packet_count++; + if(packet_count>5) // the TX must have changed chanskip... + frsky_rx_chanskip = ((packet[4] & 0xC0) >> 6) | ((packet[5] & 0x3F) << 2); // chanskip init + } + else + packet_count=0; + } + else + frsky_rx_chanskip = ((packet[4] & 0xC0) >> 6) | ((packet[5] & 0x3F) << 2); // chanskip init + } + hopping_frequency_no = (hopping_frequency_no + frsky_rx_chanskip) % 47; + frsky_rx_set_channel(hopping_frequency_no); + if(chanskip_valid) + { + if (telemetry_link == 0) + { // send channels to TX + frsky_rx_build_telemetry_packet(); + telemetry_link = 1; + } + pps_counter++; + } + rx_data_started = true; + read_retry = 0; + } + } + + // packets per second + if (millis() - pps_timer >= 1000) { + pps_timer = millis(); + debugln("%d pps", pps_counter); + RX_LQI = pps_counter; + if(pps_counter==0) // no packets for 1 sec or more... + {// restart the search + rx_data_started=false; + packet_count=0; + } + pps_counter = 0; + } + + // skip channel if no packet received in time + if (read_retry++ >= 9) { hopping_frequency_no = (hopping_frequency_no + frsky_rx_chanskip) % 47; frsky_rx_set_channel(hopping_frequency_no); - if (telemetry_link == 0 && chanskip_valid) { // send channels to TX - frsky_rx_build_telemetry_packet(); - telemetry_link = 1; - } - rx_data_started = true; - read_retry = 0; - pps_counter++; + if(rx_data_started) + read_retry = 0; + else + read_retry = -50; // retry longer until first packet is catched } - } - - // packets per second - if (millis() - pps_timer >= 1000) { - pps_timer = millis(); - debugln("%d pps", pps_counter); - RX_LQI = pps_counter; - pps_counter = 0; - } - - // skip channel if no packet received in time - if (read_retry++ >= 9) { - hopping_frequency_no = (hopping_frequency_no + frsky_rx_chanskip) % 47; - frsky_rx_set_channel(hopping_frequency_no); - if(rx_data_started) - read_retry = 0; - else - read_retry = -50; // retry longer until first packet is catched - } - break; + break; } return 1000; } diff --git a/Multiprotocol/Multi.txt b/Multiprotocol/Multi.txt index 9aa150a..e439e6c 100644 --- a/Multiprotocol/Multi.txt +++ b/Multiprotocol/Multi.txt @@ -1,6 +1,6 @@ 1,Flysky,Flysky,V9x9,V6x6,V912,CX20 2,Hubsan,H107,H301,H501 -3,FrskyD +3,FrskyD,D8,Cloned 4,Hisky,Hisky,HK310 5,V2x2,V2x2,JXD506 6,DSM,DSM2-22,DSM2-11,DSMX-22,DSMX-11,AUTO @@ -12,7 +12,7 @@ 12,CX10,GREEN,BLUE,DM007,---,J3015_1,J3015_2,MK33041 13,CG023,CG023,YD829 14,Bayang,Bayang,H8S3D,X16_AH,IRDRONE,DHD_D4 -15,FrskyX,CH_16,CH_8,EU_16,EU_8 +15,FrskyX,CH_16,CH_8,EU_16,EU_8,Cloned 16,ESky,Std,ET4 17,MT99xx,MT,H7,YZ,LS,FY805 18,MJXq,WLH08,X600,X800,H26D,E010,H26WH,PHOENIX @@ -61,7 +61,7 @@ 61,Tiger 62,XK,X450,X420 63,XN_DUMP,250K,1M,2M,AUTO -64,FrskyX2,CH_16,CH_8,EU_16,EU_8 +64,FrskyX2,CH_16,CH_8,EU_16,EU_8,Cloned 65,FrSkyR9,915MHz,868MHz,915_8ch,868_8ch 66,PROPEL,74-Z 67,LR12,LR12,LR12_6ch diff --git a/Multiprotocol/Multi_Names.ino b/Multiprotocol/Multi_Names.ino index 60cf6e8..c799fe2 100644 --- a/Multiprotocol/Multi_Names.ino +++ b/Multiprotocol/Multi_Names.ino @@ -84,7 +84,8 @@ const char STR_PROPEL[] ="PROPEL"; const char STR_SUBTYPE_FLYSKY[] = "\x04""Std\0""V9x9""V6x6""V912""CX20"; const char STR_SUBTYPE_HUBSAN[] = "\x04""H107""H301""H501"; -const char STR_SUBTYPE_FRSKYX[] = "\x07""D16\0 ""D16 8ch""LBT(EU)""LBT 8ch"; +const char STR_SUBTYPE_FRSKYD[] = "\x06""D8\0 ""Cloned"; +const char STR_SUBTYPE_FRSKYX[] = "\x07""D16\0 ""D16 8ch""LBT(EU)""LBT 8ch""Cloned\0"; const char STR_SUBTYPE_HISKY[] = "\x05""Std\0 ""HK310"; const char STR_SUBTYPE_V2X2[] = "\x06""Std\0 ""JXD506"; const char STR_SUBTYPE_DSM[] = "\x06""2 22ms""2 11ms""X 22ms""X 11ms"; @@ -151,7 +152,7 @@ const mm_protocol_definition multi_protocols[] = { {PROTO_HUBSAN, STR_HUBSAN, 3, STR_SUBTYPE_HUBSAN, OPTION_VIDFREQ }, #endif #if defined(FRSKYD_CC2500_INO) - {PROTO_FRSKYD, STR_FRSKYD, 0, NO_SUBTYPE, OPTION_RFTUNE }, + {PROTO_FRSKYD, STR_FRSKYD, 2, STR_SUBTYPE_FRSKYD, OPTION_RFTUNE }, #endif #if defined(HISKY_NRF24L01_INO) {PROTO_HISKY, STR_HISKY, 2, STR_SUBTYPE_HISKY, OPTION_NONE }, @@ -187,8 +188,8 @@ const mm_protocol_definition multi_protocols[] = { {PROTO_BAYANG, STR_BAYANG, 5, STR_SUBTYPE_BAYANG, OPTION_TELEM }, #endif #if defined(FRSKYX_CC2500_INO) - {PROTO_FRSKYX, STR_FRSKYX, 4, STR_SUBTYPE_FRSKYX, OPTION_RFTUNE }, - {PROTO_FRSKYX2, STR_FRSKYX2, 4, STR_SUBTYPE_FRSKYX, OPTION_RFTUNE }, + {PROTO_FRSKYX, STR_FRSKYX, 5, STR_SUBTYPE_FRSKYX, OPTION_RFTUNE }, + {PROTO_FRSKYX2, STR_FRSKYX2, 5, STR_SUBTYPE_FRSKYX, OPTION_RFTUNE }, #endif #if defined(ESKY_NRF24L01_INO) {PROTO_ESKY, STR_ESKY, 2, STR_SUBTYPE_ESKY, OPTION_NONE }, diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index a94a37f..bd28934 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 3 #define VERSION_REVISION 0 -#define VERSION_PATCH_LEVEL 86 +#define VERSION_PATCH_LEVEL 87 //****************** // Protocols @@ -209,12 +209,18 @@ enum MJXQ H26WH = 5, PHOENIX = 6, }; +enum FRSKYD +{ + FRSKYD = 0, + DCLONE = 1, +}; enum FRSKYX { CH_16 = 0, CH_8 = 1, EU_16 = 2, EU_8 = 3, + XCLONE = 4, }; enum HONTAI { @@ -657,7 +663,10 @@ enum { #define AFHDS2A_EEPROM_OFFSET2 250 // RX ID, 4 bytes per model id, end is 250+192=442 #define HOTT_EEPROM_OFFSET 442 // RX ID, 5 bytes per model id, end is 320+442=762 #define BAYANG_RX_EEPROM_OFFSET 762 // (5) TX ID + (4) channels, 9 bytes, end is 771 -//#define CONFIG_EEPROM_OFFSET 771 // Current configuration of the multimodule +#define FRSKYD_CLONE_EEPROM_OFFSET 771 // (1) format + (3) TX ID + (47) channels, 51 bytes, end is 822 +#define FRSKYX_CLONE_EEPROM_OFFSET 822 // (1) format + (3) TX ID + (47) channels, 51 bytes, end is 873 +#define FRSKYX2_CLONE_EEPROM_OFFSET 873 // (1) format + (3) TX ID, 4 bytes, end is 877 +//#define CONFIG_EEPROM_OFFSET 877 // Current configuration of the multimodule //**************************************** //*** MULTI protocol serial definition *** @@ -814,11 +823,21 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- E010 4 H26WH 5 PHOENIX 6 + sub_protocol==FRSKYD + FRSKYD 0 + DCLONE 1 sub_protocol==FRSKYX CH_16 0 CH_8 1 EU_16 2 EU_8 3 + XCLONE 4 + sub_protocol==FRSKYX2 + CH_16 0 + CH_8 1 + EU_16 2 + EU_8 3 + XCLONE 4 sub_protocol==HONTAI HONTAI 0 JJRCX1 1 diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 3fdaa67..b767443 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -564,7 +564,8 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= { FRSKY_RX FRSKY_CLONE PROTO_FRSKYD - NONE + FRSKYD + DCLONE PROTO_FRSKYL LR12 LR12_6CH @@ -580,13 +581,16 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= { CH_8 EU_16 EU_8 + XCLONE PROTO_FRSKYX2 CH_16 CH_8 EU_16 EU_8 + XCLONE PROTO_FRSKY_RX - NONE + FRSKY_RX + FRSKY_CLONE PROTO_FX816 NONE PROTO_FY326 diff --git a/Protocols_Details.md b/Protocols_Details.md index 80cd98b..e1dfe8f 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -87,12 +87,12 @@ CFlie|38|CFlie||||||||NRF24L01| [Flysky AFHDS2A RX](Protocols_Details.md#FLYSKY-AFHDS2A-RX---56)|56|||||||||A7105| [Flyzone](Protocols_Details.md#FLYZONE---53)|53|FZ410||||||||A7105| [FQ777](Protocols_Details.md#FQ777---23)|23|||||||||NRF24L01|SSV7241 -[FrskyD](Protocols_Details.md#FRSKYD---3)|3|||||||||CC2500| +[FrskyD](Protocols_Details.md#FRSKYD---3)|3|D8|Cloned|||||||CC2500| [FrskyL](Protocols_Details.md#FRSKYL---67)|67|LR12|LR12 6CH|||||||CC2500| [FrskyR9](Protocols_Details.md#FRSKYR9---65)|65|FrskyR9|R9_915|R9_868||||||SX1276| [FrskyV](Protocols_Details.md#FRSKYV---25)|25|FrskyV||||||||CC2500| -[FrskyX](Protocols_Details.md#FRSKYX---15)|15|CH_16|CH_8|EU_16|EU_8|||||CC2500| -[FrskyX2](Protocols_Details.md#FRSKYX2---64)|64|CH_16|CH_8|EU_16|EU_8|||||CC2500| +[FrskyX](Protocols_Details.md#FRSKYX---15)|15|CH_16|CH_8|EU_16|EU_8|Cloned||||CC2500| +[FrskyX2](Protocols_Details.md#FRSKYX2---64)|64|CH_16|CH_8|EU_16|EU_8|Cloned||||CC2500| [Frsky_RX](Protocols_Details.md#FRSKY_RX---55)|55|RX|CloneTX|||||||CC2500| [FX816](Protocols_Details.md#FX816---58)|28|FX816|P38|||||||NRF24L01| [FY326](Protocols_Details.md#FY326---20)|20|FY326|FY319|||||||NRF24L01| @@ -336,6 +336,14 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +### Sub_protocol D8 - *0* +Use the internal multi module Identifier. + +### Sub_protocol Cloned - *1* +Use the identifier learnt from another FrSky radio when binding with the FrSkyRX/CloneTX mode. + +RX number can't be used anymore and is ignored. + ## FRSKYL - *67* Models: FrSky receivers L9R. Also known as LR12. @@ -396,15 +404,18 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +### Sub_protocol Cloned - *4* +Use the identifier learnt from another FrSky radio when binding with the FrSkyRX/CloneTX mode. + ## FRSKYX2 - *64* -Same as FrSkyX but for v2.1.0. +Same as FrSkyX but for D16 v2.1.0 FCC/LBT. ## FRSKY_RX - *55* ### Sub_protocol RX - *0* The FrSky receiver protocol enables master/slave trainning, separate access from 2 different radios to the same model,... -Auto selection of FrSkyD/D8 and FrSkyX/D16 v1.xxx FCC/LBT at bind time. +Auto selection of the protocol being used by the FrSky TX: FrSkyD/D8, FrSkyX/D16 v1.xxx FCC/LBT and FrSkyX/D16 v2.1.0 FCC/LBT at bind time. Available in OpenTX 2.3.3, Trainer Mode Master/Multi @@ -420,18 +431,24 @@ Check the [Frequency Tuning page](/docs/Frequency_Tuning.md) to determine it. Low power: enable/disable the LNA stage on the RF component to use depending on the distance with the TX. ### Sub_protocol CloneTX - *1* -Enables to clone a FrSky TX in FrSkyD/D8 or FrSkyX/D16 v1.xxx FCC/LBT mode. +This subprotocol makes a clone of a FrSky TX identifier based on the protocol. + +There are 3 slots available, 1 slot for D8 cloning, 1 slot for FrSkyX (D16v1) cloning and 1 slot for FrSkyX2 (D16v2.1.0) cloning. +The same TX or different TXs can be used for each slot but a maximum of 1 per slot. +If you launch the FrSky_RX/CloneTX protocol and do a bind with a FrSky TX (genuine or not) on with the protocol D8 it will be saved in the slot D8. Same for D16v1 and D16v2.1 . +Then the system will alow you to enable cloning as you whish for each model using the FrSkyD/X/X2 "Cloned" subprotocol. This way you can have models working with the original MPM indetifier and models which are shared by both the cloned TX and MPM. Clone mode operation: -- Select the FrSkyRX protocol, subprotocol CloneTX -- Place both the orginal TX and multi in bind mode +- Select the FrSky_RX protocol, subprotocol CloneTX +- Select on the TX to be cloned the protocol you want to clone the identifier from: FrSkyD/D8 or FrSkyX/D16 v1.xxx FCC/LBT or FrSkyX/D16 v2.1.0 FCC/LBT +- Place both the TX and MPM in bind mode - Wait for the bind to complete -- From there the FrSkyD or FrSkyX protocol will now clone the original TX depending on which protocol it was using +- To use the cloned TX identifier, open a new model select the protocol you just cloned/binded and select the subprotocol "Cloned" Notes: +- OpenTX 2.3.8 latest nightly is needed to have access to the "D8Cloned" and "D16Cloned" subprotocols - For FrSkyD, only the RX number used during bind is cloned -> you can't use RX num anymore -- For FrSkyX, RX number has to be adjusted on each model to match the original TX model -- Once CloneTX is activated the FrSkyD or FrSkyX protocol will always clone the original TX. If you want to disable CloneTX, you must do a bind with the FrSkyRX protocol and subprotocol RX (even if dummy). +- For FrSkyX and FrSkyX2, RX number has to be adjusted on each model to match the original TX model ## HITEC - *39* Models: OPTIMA, MINIMA and MICRO receivers.