From e7449897f90dbb32b7e8e67007132e7f434b7d61 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Tue, 28 Aug 2018 16:13:28 +0200 Subject: [PATCH 001/111] BUGS new protocol BUGS new protocol (number 41) Models: Bugs 3, 6 and 8 Autobind protocol Telemetry: TX & RX RSSI, Battery voltage good/bad ARM CH5 LED CH6 FLIP CH7 PICTURE CH8 VIDEO CH9 --- Multiprotocol/A7105_SPI.ino | 76 +++++- Multiprotocol/Bugs_a7105.ino | 458 ++++++++++++++++++++++++++++++++ Multiprotocol/Multi.txt | 1 + Multiprotocol/Multiprotocol.h | 11 +- Multiprotocol/Multiprotocol.ino | 12 +- Multiprotocol/Telemetry.ino | 4 +- Multiprotocol/Validate.h | 4 +- Multiprotocol/_Config.h | 5 + 8 files changed, 549 insertions(+), 22 deletions(-) create mode 100644 Multiprotocol/Bugs_a7105.ino diff --git a/Multiprotocol/A7105_SPI.ino b/Multiprotocol/A7105_SPI.ino index 07d2330..a678f80 100644 --- a/Multiprotocol/A7105_SPI.ino +++ b/Multiprotocol/A7105_SPI.ino @@ -182,6 +182,11 @@ void A7105_AdjustLOBaseFreq(uint8_t cmd) offset=(int16_t)FORCE_HUBSAN_TUNING; #endif break; + case PROTO_BUGS: + #ifdef FORCE_HUBSAN_TUNING + offset=(int16_t)FORCE_HUBSAN_TUNING; + #endif + break; case PROTO_FLYSKY: #ifdef FORCE_FLYSKY_TUNING offset=(int16_t)FORCE_FLYSKY_TUNING; @@ -222,21 +227,40 @@ void A7105_AdjustLOBaseFreq(uint8_t cmd) //debugln("Channel: %d, offset: %d, bip: %2x, bfp: %4x", Channel_data[14], offset, bip, bfp); } +static void __attribute__((unused)) A7105_SetVCOBand(uint8_t vb1, uint8_t vb2) +{ // Set calibration band value to best match + uint8_t diff1, diff2; + + if (vb1 >= 4) + diff1 = vb1 - 4; + else + diff1 = 4 - vb1; + + if (vb2 >= 4) + diff2 = vb2 - 4; + else + diff2 = 4 - vb2; + + if (diff1 == diff2 || diff1 > diff2) + A7105_WriteReg(A7105_25_VCO_SBCAL_I, vb1 | 0x08); + else + A7105_WriteReg(A7105_25_VCO_SBCAL_I, vb2 | 0x08); +} #ifdef HUBSAN_A7105_INO const uint8_t PROGMEM HUBSAN_A7105_regs[] = { - 0xFF, 0x63, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF ,0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x04, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2B, 0xFF, 0xFF, 0x62, 0x80, 0xFF, 0xFF, 0x0A, 0xFF, 0xFF, 0x07, - 0x17, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x47, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF + 0xFF, 0x63, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF ,0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x04, 0xFF, // 00 - 0f + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2B, 0xFF, 0xFF, 0x62, 0x80, 0xFF, 0xFF, 0x0A, 0xFF, 0xFF, 0x07, // 10 - 1f + 0x17, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x47, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 20 - 2f + 0xFF, 0xFF // 30 - 31 }; #endif #ifdef FLYSKY_A7105_INO const uint8_t PROGMEM FLYSKY_A7105_regs[] = { - 0xff, 0x42, 0x00, 0x14, 0x00, 0xff, 0xff ,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, 0xff, 0x00, 0x00, 0x3b, 0x00, 0x17, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, - 0x01, 0x0f + 0xff, 0x42, 0x00, 0x14, 0x00, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x05, 0x00, 0x50, // 00 - 0f + 0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x00, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x0f, // 10 - 1f + 0x13, 0xc3, 0x00, 0xff, 0x00, 0x00, 0x3b, 0x00, 0x17, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f + 0x01, 0x0f // 30 - 31 }; #endif #ifdef AFHDS2A_A7105_INO @@ -247,13 +271,37 @@ const uint8_t PROGMEM AFHDS2A_A7105_regs[] = { 0x01, 0x0f // 30 - 31 }; #endif +#ifdef BUGS_A7105_INO +const uint8_t PROGMEM BUGS_A7105_regs[] = { + 0xFF, 0x42, 0x00, 0x15, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x05, 0x01, 0x50, // 00 - 0f + 0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x40, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x0f, // 10 - 1f + 0x16, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x3b, 0x00, 0x0b, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f + 0x01, 0x0f // 30 - 31 +}; +#endif #define ID_NORMAL 0x55201041 #define ID_PLUS 0xAA201041 void A7105_Init(void) { uint8_t *A7105_Regs=0; + uint8_t vco_calibration0, vco_calibration1; + #ifdef BUGS_A7105_INO + if(protocol==PROTO_BUGS) + { + if(IS_BIND_DONE) + { // Read radio_id from EEPROM + radio_id=0; + uint8_t base_adr=BUGS_EEPROM_OFFSET+RX_num*4; + for(uint8_t i=0; i<4; i++) + radio_id|=eeprom_read_byte((EE_ADDR)(base_adr+i))<. + */ + +#ifdef BUGS_A7105_INO + +//////////// rxid -> radioid algorithm ////////////////////////////// +// Hex digit 1 is periodic with length 2, and hex digit 2 is periodic +// with length 16. However, storing the byte of those 2 digits +// instead of manipulating bits results simpler code and smaller binary. +const uint8_t PROGMEM BUGS_most_popular_67_cycle[]= { + 0x34, 0xc5, 0x6a, 0xb4, 0x29, 0xd5, 0x2c, 0xd3, 0x91, 0xb3, 0x6c, 0x49, + 0x52, 0x9c, 0x4d, 0x65, 0xc3, 0x4a, 0x5b, 0xd6, 0x92, 0x6d, 0x94, 0xa6, + 0x55, 0xcd, 0x2b, 0x9a, 0x36, 0x95, 0x4b, 0xd4, 0x35, 0x8d, 0x96, 0xb2, + 0xa3 }; + +static uint8_t __attribute__((unused)) BUGS_most_popular_67(uint8_t i) +{ + uint8_t ii; + if (i == 0) + return 0xd2; + else if (i == 1) + return 0xda; + else if (i % 16 < 2) + { + ii = 2 * (i / 16) + i % 16 - 2; + if (ii % 2 == 0) + ii += 7; + } + else + ii=2 * (i / 16) + (i % 16 - 2) % 7; + return pgm_read_byte_near( &BUGS_most_popular_67_cycle[ii]); +} + +static uint8_t __attribute__((unused)) BUGS_most_popular_45(uint8_t i) +{ + if (i == 0) + return 0xa3; + else if (i == 1) + return 0x86; + else + { + if (i % 8 == 1) + i -= 8; + else + i--; + return BUGS_most_popular_67(i); + } +} + +static uint8_t __attribute__((unused)) BUGS_most_popular_23(uint8_t i) +{ + if (i == 0) + return 0xb2; + else if (i == 1) + return 0xcb; + else + { + if (i % 8 == 1) + i -= 8; + else + i--; + return BUGS_most_popular_45(i); + } +} + +const uint8_t PROGMEM BUGS_most_popular_01[] = { + 0x52, 0xac, 0x59, 0xa4, 0x53, 0xab, 0x57, 0xa9, + 0x56, 0xa5, 0x5b, 0xa7, 0x5d, 0xa6, 0x58, 0xad}; + +static uint32_t __attribute__((unused)) BUGS_most_popular(uint8_t i) +{ + i += !(i <= 127); + uint8_t mp01=pgm_read_byte_near( &BUGS_most_popular_01[i % 16] ); + return (uint32_t) mp01 << 24 | + (uint32_t) BUGS_most_popular_23(i) << 16 | + (uint32_t) BUGS_most_popular_45(i) << 8 | + BUGS_most_popular_67(i); +} + +static uint32_t __attribute__((unused)) BUGS_second_most_popular(uint8_t i) +{ + if (i < 127) + return BUGS_most_popular(i + 1); + else if (i > 128) + return BUGS_most_popular(i - 1); + else + return 0x52d6926d; +} + +// The 22 irregular values do not match the above periodicities. They might be +// errors from the readout, but let us try them here as long as it is not +// proven. +#define BUGS_NBR_IRREGULAR 22 +const uint16_t PROGMEM BUGS_irregular_keys[BUGS_NBR_IRREGULAR] = { + 1131, 1287, 2842, 4668, 5311, 11594, 13122, 13813, + 20655, 22975, 25007, 25068, 28252, 33309, 35364, 35765, + 37731, 40296, 43668, 46540, 49868, 65535 }; + +const uint32_t PROGMEM BUGS_irregular_values[BUGS_NBR_IRREGULAR] = { + 0x52d6926d, 0xa586da34, 0x5329d52c, 0xa66c4952, + 0x536c4952, 0x524a5bd6, 0x534d65c3, 0xa9d391b3, + 0x5249529c, 0xa555cd2b, 0xac9a3695, 0x58d391b3, + 0xa791b36c, 0x53926d94, 0xa7926d94, 0xa72cd391, + 0xa9b429d5, 0x5629d52c, 0xad2b9a36, 0xa74d65c3, + 0x526d94a6, 0xad96b2a3 }; + +static uint32_t __attribute__((unused)) BUGS_is_irregular(uint16_t i) +{ + for (uint8_t j = 0; j < BUGS_NBR_IRREGULAR; ++j) + if (pgm_read_word_near( &BUGS_irregular_keys[j]) == i) + return pgm_read_dword_near( &BUGS_irregular_values[j]); + return 0; +} + +static uint32_t __attribute__((unused)) BUGS_rxid_to_radioid(uint16_t rxid) +{ + uint8_t block = rxid / 256; + uint8_t second_seq_size; + bool use_most_popular; + + if (rxid < 32768) + { + second_seq_size = 128 - block; + use_most_popular = rxid % 256 >= second_seq_size; + } + else + { + second_seq_size = block - 127; + use_most_popular = 255 - rxid % 256 >= second_seq_size; + } + uint32_t v = BUGS_is_irregular(rxid); + if (!v) + { + if (use_most_popular) + v = BUGS_most_popular(rxid % 255); + else + v = BUGS_second_most_popular(rxid % 255); + } + return v; +} +//////////// rxid -> radioid algorithm ////////////////////////////// + +// For code readability +#define BUGS_CH_SW_ARM CH5_SW +#define BUGS_CH_SW_LED CH6_SW +#define BUGS_CH_SW_FLIP CH7_SW +#define BUGS_CH_SW_PICTURE CH8_SW +#define BUGS_CH_SW_VIDEO CH9_SW + +// flags packet byte 4 +#define BUGS_FLAG_FLIP 0x08 // automatic flip +#define BUGS_FLAG_MODE 0x04 // low/high speed select (set is high speed) +#define BUGS_FLAG_VIDEO 0x02 // toggle video +#define BUGS_FLAG_PICTURE 0x01 // toggle picture + +// flags packet byte 5 +#define BUGS_FLAG_LED 0x80 // enable LEDs +#define BUGS_FLAG_ARM 0x40 // arm (toggle to turn on motors) +#define BUGS_FLAG_DISARM 0x20 // disarm (toggle to turn off motors) + +#define BUGS_PACKET_SIZE 22 +#define BUGS_NUM_RFCHAN 16 + +static uint8_t BUGS_armed, BUGS_arm_flags; +static uint8_t BUGS_arm_channel_previous; + +enum { + BUGS_BIND_1, + BUGS_BIND_2, + BUGS_BIND_3, + BUGS_DATA_1, + BUGS_DATA_2, + BUGS_DATA_3, +}; + +static void __attribute__((unused)) BUGS_check_arming() +{ + uint8_t arm_channel = BUGS_CH_SW_ARM; + + if (arm_channel != BUGS_arm_channel_previous) + { + BUGS_arm_channel_previous = arm_channel; + if (arm_channel) + { + BUGS_armed = 1; + BUGS_arm_flags ^= BUGS_FLAG_ARM; + } + else + { + BUGS_armed = 0; + BUGS_arm_flags ^= BUGS_FLAG_DISARM; + } + } +} + +static void __attribute__((unused)) BUGS_build_packet(uint8_t bind) +{ + uint8_t force_values = bind | !BUGS_armed; + uint8_t change_channel = ((packet_count & 0x1) << 6); + uint16_t aileron = convert_channel_16b_limit(AILERON,800,0); + uint16_t elevator = convert_channel_16b_limit(ELEVATOR,800,0); + uint16_t throttle = convert_channel_16b_limit(THROTTLE,0,800); + uint16_t rudder = convert_channel_16b_limit(RUDDER,800,0); + + memset(packet, 0, BUGS_PACKET_SIZE); + packet[1] = 0x76; // txid (rx uses to know hopping frequencies) + packet[2] = 0x71; + packet[3] = 0x94; + + BUGS_check_arming(); // sets globals arm_flags and armed + if(bind) + { + packet[4] = change_channel | 0x80; + packet[5] = 0x06 | BUGS_arm_flags; + } + else + { + packet[4] = change_channel | BUGS_FLAG_MODE + | GET_FLAG(BUGS_CH_SW_FLIP, BUGS_FLAG_FLIP) + | GET_FLAG(BUGS_CH_SW_PICTURE, BUGS_FLAG_PICTURE) + | GET_FLAG(BUGS_CH_SW_VIDEO, BUGS_FLAG_VIDEO); + packet[5] = 0x06 | BUGS_arm_flags + | GET_FLAG(BUGS_CH_SW_LED, BUGS_FLAG_LED); + } + + packet[6] = force_values ? 100 : (aileron >> 2); + packet[7] = force_values ? 100 : (elevator >> 2); + packet[8] = force_values ? 0 : (throttle >> 2); + packet[9] = force_values ? 100 : (rudder >> 2); + packet[10] = 100; + packet[11] = 100; + packet[12] = 100; + packet[13] = 100; + + packet[14] = ((aileron << 6) & 0xc0) + | ((elevator << 4) & 0x30) + | ((throttle << 2) & 0x0c) + | ((rudder ) & 0x03); + + // packet[15] = 0; + + // driven trims + packet[16] = aileron / 8 + 14; + packet[17] = elevator / 8 + 14; + packet[18] = 64; + packet[19] = rudder / 8 + 14; + + // packet[20] = 0; + // packet[21] = 0; + + uint8_t check = 0x6d; + for (uint8_t i=1; i < BUGS_PACKET_SIZE; i++) + check ^= packet[i]; + packet[0] = check; +} + +const uint8_t PROGMEM BUGS_hop []= { + 0x1d, 0x3b, 0x4d, 0x29, 0x11, 0x2d, 0x0b, 0x3d, 0x59, 0x48, 0x17, 0x41, 0x23, 0x4e, 0x2a, 0x63, // bind phase ID=0xac59a453 + 0x4b, 0x19, 0x35, 0x1e, 0x63, 0x0f, 0x45, 0x21, 0x51, 0x3a, 0x5d, 0x25, 0x0a, 0x44, 0x61, 0x27, // data phase ID=0xA4C56AB4 for txid 767194 if rx responds C6 BB 57 7F 00 00 00 00 00 00 FF 87 40 00 00 00 + }; + +static void __attribute__((unused))BUGS_set_radio_data(uint8_t index) +{ // captured radio data for bugs rx/tx version A2 + // it appears that the hopping frequencies are determined by the txid + // and the data phase radio id is determined by the first 2 bytes of the + // rx bind packet + if(index==0) + radio_id=0xac59a453; // bind phase ID=0xac59a453 + else // 1 + radio_id=0xA4C56AB4; // data phase ID=0xA4C56AB4 for txid 767194 if rx responds C6 BB 57 7F 00 00 00 00 00 00 FF 87 40 00 00 00 + + uint8_t offset=index*BUGS_NUM_RFCHAN; + for(uint8_t i=0; i>i); // Save radio_id in EEPROM + BUGS_set_radio_data(1); + A7105_WriteID(radio_id); + BIND_DONE; + phase = BUGS_DATA_1; + packet_count = 0; + hopping_frequency_no = 0; + packet_period = BUGS_DELAY_POST_RX; + break; + + case BUGS_DATA_1: + A7105_SetPower(); + BUGS_build_packet(0); + A7105_WriteReg(A7105_03_FIFOI, BUGS_FIFO_SIZE_TX); + A7105_WriteData(BUGS_PACKET_SIZE, hopping_frequency[hopping_frequency_no]); + phase = BUGS_DATA_2; + packet_period = BUGS_DELAY_POST_TX; + break; + + case BUGS_DATA_2: + // wait here a bit for tx complete because + // need to start rx immediately to catch return packet + timeout = 20; + while (A7105_ReadReg(A7105_00_MODE) & 0x01) + if (timeout-- == 0) + { + packet_period = BUGS_DELAY_WAIT_TX; // don't proceed until transmission complete + break; + } + A7105_SetTxRxMode(RX_EN); + A7105_WriteReg(A7105_0F_PLL_I, hopping_frequency[hopping_frequency_no] - 2); + A7105_WriteReg(A7105_03_FIFOI, BUGS_FIFO_SIZE_RX); + A7105_Strobe(A7105_RX); + + BUGS_increment_counts(); + phase = BUGS_DATA_3; + packet_period = BUGS_DELAY_WAIT_RX; + break; + + case BUGS_DATA_3: + mode = A7105_ReadReg(A7105_00_MODE); + A7105_Strobe(A7105_STANDBY); + A7105_SetTxRxMode(TX_EN); + if (!(mode & 0x01)) + { + A7105_ReadData(16); + v_lipo1=packet[10] == 0xff ? 0xff : 0x00; // Voltage in this case is only an alert on level good or bad. + RX_RSSI=packet[3]; + // Read TX RSSI + int16_t temp=256-(A7105_ReadReg(A7105_1D_RSSI_THOLD)*8)/5; // Value from A7105 is between 8 for maximum signal strength to 160 or less + if(temp<0) temp=0; + else if(temp>255) temp=255; + TX_RSSI=temp; + telemetry_link=1; + } + phase = BUGS_DATA_1; + packet_period = BUGS_DELAY_POST_RX; + break; + } + return packet_period; +} + +uint16_t initBUGS(void) +{ + if (IS_BIND_IN_PROGRESS) + { + BUGS_set_radio_data(0); + phase = BUGS_BIND_1; + } + else + { + BUGS_set_radio_data(1); + phase = BUGS_DATA_1; + } + + A7105_Init(); + + hopping_frequency_no = 0; + packet_count = 0; + BUGS_armed = 0; + BUGS_arm_flags = BUGS_FLAG_DISARM; // initial value from captures + BUGS_arm_channel_previous = BUGS_CH_SW_ARM; + + return 10000; +} + +#endif diff --git a/Multiprotocol/Multi.txt b/Multiprotocol/Multi.txt index c0741c2..db4f455 100644 --- a/Multiprotocol/Multi.txt +++ b/Multiprotocol/Multi.txt @@ -38,3 +38,4 @@ 38,CFlie 39,Hitec,OPT_FW,OPT_HUB,MINIMA 40,WFLY +41,BUGS diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index b0eb649..13f29d4 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 0 -#define VERSION_PATCH_LEVEL 32 +#define VERSION_PATCH_LEVEL 33 //****************** // Protocols @@ -67,6 +67,7 @@ enum PROTOCOLS PROTO_CFLIE = 38, // =>NRF24L01 PROTO_HITEC = 39, // =>CC2500 PROTO_WFLY = 40, // =>CYRF6936 + PROTO_BUGS = 41, // =>A7105 }; enum Flysky @@ -510,9 +511,10 @@ enum { #define EEPROM_ID_OFFSET 10 // Module ID (4 bytes) #define EEPROM_BANK_OFFSET 15 // Current bank number (1 byte) #define EEPROM_ID_VALID_OFFSET 20 // 1 byte flag that ID is valid -#define MODELMODE_EEPROM_OFFSET 30 // Autobind mode, 1 byte per model, end is 46 -#define AFHDS2A_EEPROM_OFFSET 50 // RX ID, 4 byte per model id, end is 114 -#define CONFIG_EEPROM_OFFSET 120 // Current configuration of the multimodule +#define MODELMODE_EEPROM_OFFSET 30 // Autobind mode, 1 byte per model, end is 30+16=46 +#define AFHDS2A_EEPROM_OFFSET 50 // RX ID, 4 byte per model id, end is 50+64=114 +#define BUGS_EEPROM_OFFSET 114 // RX ID, 4 byte per model id, end is 114+64=178 +//#define CONFIG_EEPROM_OFFSET 178 // Current configuration of the multimodule //**************************************** //*** MULTI protocol serial definition *** @@ -571,6 +573,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- CFlie 38 Hitec 39 WFLY 40 + BUGS 41 BindBit=> 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index daa6541..5628373 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -110,6 +110,7 @@ uint16_t seed; uint16_t failsafe_count; uint16_t state; uint8_t len; +uint32_t radio_id; #if defined(FRSKYX_CC2500_INO) || defined(SFHSS_CC2500_INO) uint8_t calData[48]; @@ -614,7 +615,7 @@ uint8_t Update_All() update_led_status(); #if defined(TELEMETRY) #if ( !( defined(MULTI_TELEMETRY) || defined(MULTI_STATUS) ) ) - if( (protocol==PROTO_FRSKYD) || (protocol==PROTO_BAYANG) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_FRSKYX) || (protocol==PROTO_DSM) || (protocol==PROTO_CABELL) || (protocol==PROTO_HITEC)) + if( (protocol==PROTO_FRSKYD) || (protocol==PROTO_BAYANG) || (protocol==PROTO_BUGS) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_BUGS) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_FRSKYX) || (protocol==PROTO_DSM) || (protocol==PROTO_CABELL) || (protocol==PROTO_HITEC)) #endif TelemetryUpdate(); #endif @@ -915,6 +916,13 @@ static void protocol_init() remote_callback = ReadHubsan; break; #endif + #if defined(BUGS_A7105_INO) + case PROTO_BUGS: + PE1_off; //antenna RF1 + next_callback = initBUGS(); + remote_callback = ReadBUGS; + break; + #endif #endif #ifdef CC2500_INSTALLED #if defined(FRSKYD_CC2500_INO) @@ -1569,7 +1577,7 @@ void pollBoot() #if defined(TELEMETRY) void PPM_Telemetry_serial_init() { - if( (protocol==PROTO_FRSKYD) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_BAYANG) || (protocol==PROTO_CABELL) ) + if( (protocol==PROTO_FRSKYD) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_BAYANG) || (protocol==PROTO_CABELL) || (protocol==PROTO_HITEC) || (protocol==PROTO_BUGS)) initTXSerial( SPEED_9600 ) ; if(protocol==PROTO_FRSKYX) initTXSerial( SPEED_57600 ) ; diff --git a/Multiprotocol/Telemetry.ino b/Multiprotocol/Telemetry.ino index 06ad339..a879719 100644 --- a/Multiprotocol/Telemetry.ino +++ b/Multiprotocol/Telemetry.ino @@ -367,7 +367,7 @@ void frsky_link_frame() telemetry_link |= 2 ; // Send hub if available } else - if (protocol==PROTO_HUBSAN||protocol==PROTO_AFHDS2A||protocol==PROTO_BAYANG||protocol==PROTO_CABELL||protocol==PROTO_HITEC) + if (protocol==PROTO_HUBSAN||protocol==PROTO_AFHDS2A||protocol==PROTO_BAYANG||protocol==PROTO_CABELL||protocol==PROTO_HITEC||protocol==PROTO_BUGS) { frame[1] = v_lipo1; frame[2] = v_lipo2; @@ -997,7 +997,7 @@ void TelemetryUpdate() #endif if((telemetry_link & 1 )&& protocol != PROTO_FRSKYX) - { // FrSkyD + Hubsan + AFHDS2A + Bayang + Cabell + Hitec + { // FrSkyD + Hubsan + AFHDS2A + Bayang + Cabell + Hitec + Bugs frsky_link_frame(); return; } diff --git a/Multiprotocol/Validate.h b/Multiprotocol/Validate.h index aec20da..4d21bd5 100644 --- a/Multiprotocol/Validate.h +++ b/Multiprotocol/Validate.h @@ -138,6 +138,7 @@ #undef FLYSKY_A7105_INO #undef HUBSAN_A7105_INO #undef AFHDS2A_A7105_INO + #undef BUGS_A7105_INO #endif #ifndef CYRF6936_INSTALLED #undef DEVO_CYRF6936_INO @@ -191,6 +192,7 @@ #undef BAYANG_HUB_TELEMETRY #undef CABELL_HUB_TELEMETRY #undef HUBSAN_HUB_TELEMETRY + #undef BUGS_HUB_TELEMETRY #undef HUB_TELEMETRY #undef SPORT_TELEMETRY #undef SPORT_POLLING @@ -234,7 +236,7 @@ #if not defined(DSM_CYRF6936_INO) #undef DSM_TELEMETRY #endif - #if not defined(DSM_TELEMETRY) && not defined(SPORT_TELEMETRY) && not defined(HUB_TELEMETRY) && not defined(HUBSAN_HUB_TELEMETRY) && not defined(BAYANG_HUB_TELEMETRY) && not defined(CABELL_HUB_TELEMETRY) && not defined(AFHDS2A_HUB_TELEMETRY) && not defined(AFHDS2A_FW_TELEMETRY) && not defined(MULTI_TELEMETRY) && not defined(MULTI_STATUS) && not defined(HITEC_HUB_TELEMETRY) && not defined(HITEC_FW_TELEMETRY) + #if not defined(DSM_TELEMETRY) && not defined(SPORT_TELEMETRY) && not defined(HUB_TELEMETRY) && not defined(HUBSAN_HUB_TELEMETRY) && not defined(BUGS_HUB_TELEMETRY) && not defined(BAYANG_HUB_TELEMETRY) && not defined(CABELL_HUB_TELEMETRY) && not defined(AFHDS2A_HUB_TELEMETRY) && not defined(AFHDS2A_FW_TELEMETRY) && not defined(MULTI_TELEMETRY) && not defined(MULTI_STATUS) && not defined(HITEC_HUB_TELEMETRY) && not defined(HITEC_FW_TELEMETRY) #undef TELEMETRY #undef INVERT_TELEMETRY #undef SPORT_POLLING diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 3fbcfa0..10c10b6 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -112,6 +112,7 @@ //#define FORCE_FLYSKY_TUNING 0 //#define FORCE_HUBSAN_TUNING 0 //#define FORCE_AFHDS2A_TUNING 0 +//#define FORCE_BUGS_TUNING 0 /** Low Power **/ //Low power is reducing the transmit power of the multi module. This setting is configurable per model in PPM (table below) or Serial mode (radio GUI). @@ -151,6 +152,7 @@ #define AFHDS2A_A7105_INO #define FLYSKY_A7105_INO #define HUBSAN_A7105_INO +#define BUGS_A7105_INO //The protocols below need a CYRF6936 to be installed #define DEVO_CYRF6936_INO @@ -247,6 +249,7 @@ #define AFHDS2A_HUB_TELEMETRY // Use FrSkyD Hub format to send basic telemetry to TX like er9x #define HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX #define BAYANG_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX +#define BUGS_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX #define HUBSAN_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX #define CABELL_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX #define HITEC_HUB_TELEMETRY // Use FrSkyD Hub format to send basic telemetry to the radios which can decode it like er9x, ersky9x and OpenTX @@ -557,6 +560,8 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= { MINIMA PROTO_WFLY NONE + PROTO_BUGS + NONE */ // RX_Num is used for TX & RX match. Using different RX_Num values for each receiver will prevent starting a model with the false config loaded... From e047a768556b2d0db3b79882fa117f8667cbb300 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 28 Aug 2018 16:40:10 +0200 Subject: [PATCH 002/111] Update Protocols_Details.md --- Protocols_Details.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index 16acde9..1193451 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -57,6 +57,23 @@ Serial mode is selected by placing the rotary switch to position 0 before power # A7105 RF Module +## BUGS - *41* +Models: MJX Bugs 3, 6 and 8 + +Autobind protocol + +Telemetry enabled for RX & TX RSSI, Battery voltage good/bad + +ARM CH5 +LED CH6 +FLIP CH7 +PICTURE CH8 +VIDEO CH9 + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R|ARM|LED|FLIP|PICTURE|VIDEO + ## FLYSKY - *1* Extended limits supported From 64c79626b43607e7c8e13dd646e9203c1076bb24 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 28 Aug 2018 16:41:04 +0200 Subject: [PATCH 003/111] Update Protocols_Details.md --- Protocols_Details.md | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 1193451..5fa8bd0 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -57,23 +57,6 @@ Serial mode is selected by placing the rotary switch to position 0 before power # A7105 RF Module -## BUGS - *41* -Models: MJX Bugs 3, 6 and 8 - -Autobind protocol - -Telemetry enabled for RX & TX RSSI, Battery voltage good/bad - -ARM CH5 -LED CH6 -FLIP CH7 -PICTURE CH8 -VIDEO CH9 - -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 ----|---|---|---|---|---|---|---|--- -A|E|T|R|ARM|LED|FLIP|PICTURE|VIDEO - ## FLYSKY - *1* Extended limits supported @@ -159,6 +142,17 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 ---|---|---|---|---|---|---|---|---|---|---|--- A|E|T|R|RTH|LIGHT|PICTURE|VIDEO|HEADLESS1|HEADLESS2|GPS_HOLD|ALT_HOLD +## BUGS - *41* +Models: MJX Bugs 3, 6 and 8 + +Autobind protocol + +Telemetry enabled for RX & TX RSSI, Battery voltage good/bad + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R|ARM|LED|FLIP|PICTURE|VIDEO + *** # CC2500 RF Module From d9914e95d9324a8f1cba4256d2906199313c6cbc Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 29 Aug 2018 12:58:54 +0200 Subject: [PATCH 004/111] Update Protocols_Details.md --- Protocols_Details.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index 5fa8bd0..42eef35 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -149,6 +149,8 @@ Autobind protocol Telemetry enabled for RX & TX RSSI, Battery voltage good/bad +**RX_Num is used to give a number to a given model. You must use a different RX_Num per MJX Bugs. A maximum of 16 Bugs are supported.** + CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 ---|---|---|---|---|---|---|---|--- A|E|T|R|ARM|LED|FLIP|PICTURE|VIDEO From b3576b71624ed0c3ebed0278d077f0b45ea627d9 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Wed, 29 Aug 2018 14:44:10 +0200 Subject: [PATCH 005/111] BUGS protocol Add channel for ANGLE/ACRO mode. Angle is +100%, acro is -100%. Channels mapping: ARM CH5 ANGLE CH6 FLIP CH7 PICTURE CH8 VIDEO CH9 LED CH10 --- Multiprotocol/Bugs_a7105.ino | 10 +++++++--- Multiprotocol/Multiprotocol.h | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Multiprotocol/Bugs_a7105.ino b/Multiprotocol/Bugs_a7105.ino index cb37b3e..cea86c4 100644 --- a/Multiprotocol/Bugs_a7105.ino +++ b/Multiprotocol/Bugs_a7105.ino @@ -154,10 +154,11 @@ static uint32_t __attribute__((unused)) BUGS_rxid_to_radioid(uint16_t rxid) // For code readability #define BUGS_CH_SW_ARM CH5_SW -#define BUGS_CH_SW_LED CH6_SW +#define BUGS_CH_SW_ANGLE CH6_SW #define BUGS_CH_SW_FLIP CH7_SW #define BUGS_CH_SW_PICTURE CH8_SW #define BUGS_CH_SW_VIDEO CH9_SW +#define BUGS_CH_SW_LED CH10_SW // flags packet byte 4 #define BUGS_FLAG_FLIP 0x08 // automatic flip @@ -169,6 +170,7 @@ static uint32_t __attribute__((unused)) BUGS_rxid_to_radioid(uint16_t rxid) #define BUGS_FLAG_LED 0x80 // enable LEDs #define BUGS_FLAG_ARM 0x40 // arm (toggle to turn on motors) #define BUGS_FLAG_DISARM 0x20 // disarm (toggle to turn off motors) +#define BUGS_FLAG_ANGLE 0x04 // angle/acro mode (set is angle mode) #define BUGS_PACKET_SIZE 22 #define BUGS_NUM_RFCHAN 16 @@ -223,7 +225,8 @@ static void __attribute__((unused)) BUGS_build_packet(uint8_t bind) if(bind) { packet[4] = change_channel | 0x80; - packet[5] = 0x06 | BUGS_arm_flags; + packet[5] = 0x02 | BUGS_arm_flags + | GET_FLAG(BUGS_CH_SW_ANGLE, BUGS_FLAG_ANGLE); } else { @@ -231,7 +234,8 @@ static void __attribute__((unused)) BUGS_build_packet(uint8_t bind) | GET_FLAG(BUGS_CH_SW_FLIP, BUGS_FLAG_FLIP) | GET_FLAG(BUGS_CH_SW_PICTURE, BUGS_FLAG_PICTURE) | GET_FLAG(BUGS_CH_SW_VIDEO, BUGS_FLAG_VIDEO); - packet[5] = 0x06 | BUGS_arm_flags + packet[5] = 0x02 | BUGS_arm_flags + | GET_FLAG(BUGS_CH_SW_ANGLE, BUGS_FLAG_ANGLE) | GET_FLAG(BUGS_CH_SW_LED, BUGS_FLAG_LED); } diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 13f29d4..6255442 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 0 -#define VERSION_PATCH_LEVEL 33 +#define VERSION_PATCH_LEVEL 34 //****************** // Protocols From f38e7c35dabe9bf38fb9e3007bad9187e95b0326 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 29 Aug 2018 14:54:24 +0200 Subject: [PATCH 006/111] Bugs angle/acro mode --- Protocols_Details.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 42eef35..f5f9b15 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -151,9 +151,11 @@ Telemetry enabled for RX & TX RSSI, Battery voltage good/bad **RX_Num is used to give a number to a given model. You must use a different RX_Num per MJX Bugs. A maximum of 16 Bugs are supported.** -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 ----|---|---|---|---|---|---|---|--- -A|E|T|R|ARM|LED|FLIP|PICTURE|VIDEO +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10 +---|---|---|---|---|---|---|---|---|--- +A|E|T|R|ARM|ANGLE|FLIP|PICTURE|VIDEO|LED + +Angle is +100%, Acro is -100% *** # CC2500 RF Module From e6f16700e427f009ad266afbbc30e167e6479dcc Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 29 Aug 2018 14:56:24 +0200 Subject: [PATCH 007/111] Update Protocols_Details.md --- Protocols_Details.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index f5f9b15..16bf268 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -155,7 +155,7 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10 ---|---|---|---|---|---|---|---|---|--- A|E|T|R|ARM|ANGLE|FLIP|PICTURE|VIDEO|LED -Angle is +100%, Acro is -100% +ANGLE: angle is +100%, acro is -100% *** # CC2500 RF Module From f515ba79af57033fdec11092df8d4112938fee64 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Wed, 29 Aug 2018 17:29:50 +0200 Subject: [PATCH 008/111] Hubsan sub_protocol 501 features sub_protocol H501 Model H122D: add flip on ch13 and OSD on ch14 Model H123D: add flight modes on ch16 -> -100% Sport mode 1,0% Sport mode 2, +100% Acro --- Multiprotocol/Hubsan_a7105.ino | 22 +++++++++++++++++++++- Multiprotocol/Multiprotocol.h | 2 +- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Multiprotocol/Hubsan_a7105.ino b/Multiprotocol/Hubsan_a7105.ino index 5f94855..f017c3e 100644 --- a/Multiprotocol/Hubsan_a7105.ino +++ b/Multiprotocol/Hubsan_a7105.ino @@ -49,12 +49,19 @@ enum{ // flags going to packet[9] (H501S) FLAG_H501_VIDEO = 0x01, FLAG_H501_LED = 0x04, + FLAG_H122D_FLIP = 0x08, //H122D FLAG_H501_RTH = 0x20, FLAG_H501_HEADLESS1 = 0x40, FLAG_H501_GPS_HOLD = 0x80, }; - enum{ +enum{ + // flags going to packet[11] (H122D & H123D) + FLAG_H123D_FMODES = 0x03, //H123D 3 FMODES: Sport mode 1, Sport mode 2, Acro + FLAG_H122D_OSD = 0x20, //H122D OSD +}; + +enum{ // flags going to packet[13] (H501S) FLAG_H501_SNAPSHOT = 0x01, FLAG_H501_HEADLESS2 = 0x02, @@ -203,10 +210,23 @@ static void __attribute__((unused)) hubsan_build_packet() packet[9] = 0x02 | GET_FLAG(CH6_SW, FLAG_H501_LED) | GET_FLAG(CH8_SW, FLAG_H501_VIDEO) + | GET_FLAG(CH13_SW, FLAG_H122D_FLIP) | GET_FLAG(CH5_SW, FLAG_H501_RTH) | GET_FLAG(CH11_SW, FLAG_H501_GPS_HOLD) | GET_FLAG(CH9_SW, FLAG_H501_HEADLESS1); //packet[10]= 0x1A; + + //packet[11] content 0x00 is default + //H123D specific -> Flight modes => Does this needs to be a sub_protocol to work? + packet[11] = 0x41; // Sport mode 1 + if(Channel_data[CH16]>CHANNEL_MIN_COMMAND) + packet[11]++; // 0x42 Sport mode 2 + if(Channel_data[CH16]>CHANNEL_MAX_COMMAND) + packet[11]++; // 0x43 Acro + //H122D specific -> OSD => Does this needs to be a sub_protocol to work? + packet[11]|= 0x80 + | GET_FLAG(CH14_SW,FLAG_H122D_OSD); + packet[13] = GET_FLAG(CH10_SW, FLAG_H501_HEADLESS2) | GET_FLAG(CH12_SW, FLAG_H501_ALT_HOLD) | GET_FLAG(CH7_SW, FLAG_H501_SNAPSHOT); diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 6255442..a06f69e 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 0 -#define VERSION_PATCH_LEVEL 34 +#define VERSION_PATCH_LEVEL 35 //****************** // Protocols From 814e28b86aff374ae1a869d27705d32b1a5315ca Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 29 Aug 2018 17:36:18 +0200 Subject: [PATCH 009/111] Update Protocols_Details.md --- Protocols_Details.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 16bf268..7755e75 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -136,11 +136,15 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 A|E|T|R|RTH|LIGHT|STAB|VIDEO ### Sub_protocol H501 - *1* -Models: Hubsan H501S +Models: Hubsan H501S, H122D, H123D -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 ----|---|---|---|---|---|---|---|---|---|---|--- -A|E|T|R|RTH|LIGHT|PICTURE|VIDEO|HEADLESS1|HEADLESS2|GPS_HOLD|ALT_HOLD +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16 +---|---|---|---|---|---|---|---|---|---|---|---|---|---|--- +A|E|T|R|RTH|LIGHT|PICTURE|VIDEO|HEADLESS1|HEADLESS2|GPS_HOLD|ALT_HOLD|FLIP|OSD|-|FMODES + +H122D: FLIP and OSD + +H123D: FMODES -> -100%=Sport mode 1,0%=Sport mode 2,+100%=Acro ## BUGS - *41* Models: MJX Bugs 3, 6 and 8 From cd26c2d8e67559bf2f93fbdaec5b591238fd007a Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 29 Aug 2018 18:16:23 +0200 Subject: [PATCH 010/111] Update Protocols_Details.md --- Protocols_Details.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 7755e75..a55f13d 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -139,7 +139,7 @@ A|E|T|R|RTH|LIGHT|STAB|VIDEO Models: Hubsan H501S, H122D, H123D CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16 ----|---|---|---|---|---|---|---|---|---|---|---|---|---|--- +---|---|---|---|---|---|---|---|---|----|----|----|----|----|----|---- A|E|T|R|RTH|LIGHT|PICTURE|VIDEO|HEADLESS1|HEADLESS2|GPS_HOLD|ALT_HOLD|FLIP|OSD|-|FMODES H122D: FLIP and OSD From 238260612ceb25ce427804a638f6d82dcb57809b Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 30 Aug 2018 23:58:21 +0200 Subject: [PATCH 011/111] Update Protocols_Details.md --- Protocols_Details.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index a55f13d..73d4bd6 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -138,11 +138,11 @@ A|E|T|R|RTH|LIGHT|STAB|VIDEO ### Sub_protocol H501 - *1* Models: Hubsan H501S, H122D, H123D -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16 ----|---|---|---|---|---|---|---|---|----|----|----|----|----|----|---- -A|E|T|R|RTH|LIGHT|PICTURE|VIDEO|HEADLESS1|HEADLESS2|GPS_HOLD|ALT_HOLD|FLIP|OSD|-|FMODES +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13 +---|---|---|---|---|---|---|---|---|----|----|----|---- +A|E|T|R|RTH|LIGHT|PICTURE|VIDEO|HEADLESS|GPS_HOLD|ALT_HOLD|FLIP|FMODES -H122D: FLIP and OSD +H122D: FLIP H123D: FMODES -> -100%=Sport mode 1,0%=Sport mode 2,+100%=Acro From 655ea98bf12b435e8ff764a4d0d0cdfdd3bfb186 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Fri, 31 Aug 2018 00:01:05 +0200 Subject: [PATCH 012/111] Hubsan/H501: removed useless channels headless2 and osd --- Multiprotocol/Hubsan_a7105.ino | 24 ++++++++++++------------ Multiprotocol/Multiprotocol.h | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Multiprotocol/Hubsan_a7105.ino b/Multiprotocol/Hubsan_a7105.ino index f017c3e..d454076 100644 --- a/Multiprotocol/Hubsan_a7105.ino +++ b/Multiprotocol/Hubsan_a7105.ino @@ -210,25 +210,25 @@ static void __attribute__((unused)) hubsan_build_packet() packet[9] = 0x02 | GET_FLAG(CH6_SW, FLAG_H501_LED) | GET_FLAG(CH8_SW, FLAG_H501_VIDEO) - | GET_FLAG(CH13_SW, FLAG_H122D_FLIP) + | GET_FLAG(CH12_SW, FLAG_H122D_FLIP) // H122D specific -> flip | GET_FLAG(CH5_SW, FLAG_H501_RTH) - | GET_FLAG(CH11_SW, FLAG_H501_GPS_HOLD) + | GET_FLAG(CH10_SW, FLAG_H501_GPS_HOLD) | GET_FLAG(CH9_SW, FLAG_H501_HEADLESS1); //packet[10]= 0x1A; //packet[11] content 0x00 is default - //H123D specific -> Flight modes => Does this needs to be a sub_protocol to work? + //H123D specific -> Flight modes packet[11] = 0x41; // Sport mode 1 - if(Channel_data[CH16]>CHANNEL_MIN_COMMAND) - packet[11]++; // 0x42 Sport mode 2 - if(Channel_data[CH16]>CHANNEL_MAX_COMMAND) - packet[11]++; // 0x43 Acro - //H122D specific -> OSD => Does this needs to be a sub_protocol to work? - packet[11]|= 0x80 - | GET_FLAG(CH14_SW,FLAG_H122D_OSD); + if(Channel_data[CH13]>CHANNEL_MAX_COMMAND) + packet[11]=0x43; // Acro + else if(Channel_data[CH13]>CHANNEL_MIN_COMMAND) + packet[11]=0x42; // Sport mode 2 + //H122D specific -> OSD but useless... + //packet[11]|= 0x80 + // | GET_FLAG(CHXX_SW,FLAG_H122D_OSD); - packet[13] = GET_FLAG(CH10_SW, FLAG_H501_HEADLESS2) - | GET_FLAG(CH12_SW, FLAG_H501_ALT_HOLD) + packet[13] = GET_FLAG(CH9_SW, FLAG_H501_HEADLESS2) + | GET_FLAG(CH11_SW, FLAG_H501_ALT_HOLD) | GET_FLAG(CH7_SW, FLAG_H501_SNAPSHOT); } else diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index a06f69e..9906167 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 0 -#define VERSION_PATCH_LEVEL 35 +#define VERSION_PATCH_LEVEL 36 //****************** // Protocols From 3f33e5b2a845666e109e6a3a4ad4690caea72af2 Mon Sep 17 00:00:00 2001 From: Ben Lye Date: Fri, 31 Aug 2018 19:36:46 +0100 Subject: [PATCH 013/111] Created EEPROM doc (#189) --- docs/EEPROM.md | 255 +++++++++++++++++++++++++++++++++++++++++++++++++ docs/erase.hex | 33 +++++++ 2 files changed, 288 insertions(+) create mode 100644 docs/EEPROM.md create mode 100644 docs/erase.hex diff --git a/docs/EEPROM.md b/docs/EEPROM.md new file mode 100644 index 0000000..426872d --- /dev/null +++ b/docs/EEPROM.md @@ -0,0 +1,255 @@ +# Multi-Module EEPROM + +The EEPROM is used to store the Multiprotocol Modules's global ID as well as details of bound receivers for certain protocols (AFHDS2A, Bugs, Devo, Walkera). + +On an Atmega328p module the EEPROM is a dedicated and persistent data store, separate from the 32KB of flash memory. On the STM32 module there is no dedicated EEPROM, so EEPROM functionality is emulated in the last 2KB of flash memory. + +This makes it relatively easy for the STM32 EEPROM data to be accidentally erased. + +If the EEPROM is erased a new global ID will be generated (random for Atmega modules; the MCU UUID for STM32 modules) and models will need to be re-bound. + +Backups of the EEPROM data can be made so that configuration such as module ID and bound receivers can be moved between modules. + +**Note:** Backups can only restored to a module with same MCU type - i.e. an Atmega backup cannot be restored to an STM32 module. + +The remainder of this doc is separated into sections for the STM32 and Atmega328p modules. + +## STM32 Module +The EEPROM data is stored in the last 2KB of flash memory. It is read using stm32flash with the module in BOOT0 mode. +#### Tools Needed +* stm32flash (Download: [Windows](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/source/stm32/tools/win/stm32flash.exe), [Linux 32-bit](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/source/stm32/tools/linux/stm32flash/stm32flash), [Linux 64-bit](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/source/stm32/tools/linux64/stm32flash/stm32flash), [macOS](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/source/stm32/tools/macosx/stm32flash/stm32flash)) +* Working USB-to-Serial (FTDI) adapter + +#### Preparation +Ensure that the `BOOT0` jumper is installed and the module is connected via a USB-to-Serial adapter. + +### Backing up the STM32 EEPROM +The syntax of the backup command is: +`stm32flash -r [file name] -S 0x801F800:2048 [serial port]` + +The `-S 0x801F800:2048` option tells stm32flash to read 2048 bytes starting at 0x801F800. + +Windows example: + +`stm32flash.exe -r C:\Temp\eeprom.bin -S 0x801F800:2048 COM4` + +Linux and macOS example: + +`stm32flash -r /tmp/eeprom.bin -S 0x801F800:2048 /dev/ttyUSB0` + +Output will look similar to this: +``` +stm32flash 0.4 + +http://stm32flash.googlecode.com/ + +Interface serial_w32: 57600 8E1 +Version : 0x22 +Option 1 : 0x00 +Option 2 : 0x00 +Device ID : 0x0410 (Medium-density) +- RAM : 20KiB (512b reserved by bootloader) +- Flash : 128KiB (sector size: 4x1024) +- Option RAM : 16b +- System RAM : 2KiB +Memory read +Read address 0x08020000 (100.00%) Done. +``` +### Restoring the STM32 EEPROM +The syntax of the restore command is: +`stm32flash -w [file name] -e 0 -v -S 0x801F800:2048 [serial port]` + +Again, the `-S 0x801F800:2048` option tells stm32flash to write 2048 bytes starting at 0x801F800. Additionally `-e 0` tells the tool not to erase any other blocks, which will preserve the rest of the data in the module's memory. + +Windows example: + +`stm32flash.exe -w C:\Temp\eeprom.bin -e 0 -v -S 0x801F800:2048 COM4` + +Linux and macOS example: + +`stm32flash -w /tmp/eeprom.bin -e 0 -v -S 0x801F800:2048 /dev/ttyUSB0` + +Output will look similar to this: +``` +stm32flash 0.4 + +http://stm32flash.googlecode.com/ + +Interface serial_w32: 57600 8E1 +Version : 0x22 +Option 1 : 0x00 +Option 2 : 0x00 +Device ID : 0x0410 (Medium-density) +- RAM : 20KiB (512b reserved by bootloader) +- Flash : 128KiB (sector size: 4x1024) +- Option RAM : 16b +- System RAM : 2KiB +Write to memory +Wrote and verified address 0x08020000 (100.00%) Done. +``` + +### Erasing the STM32 EEPROM +The syntax of the erase command is: +`stm32flash -o -S 0x801F800:2048 [serial port]` + +Again, the `-S 0x801F800:2048` option tells stm32flash to erase 2048 bytes starting at 0x801F800. + +Windows example: + +`stm32flash.exe -o -S 0x801F800:2048 COM4` + +Linux and macOS example: + +`stm32flash -o -S 0x801F800:2048 /dev/ttyUSB0` + +Output will look similar to this: +``` +stm32flash 0.4 + +http://stm32flash.googlecode.com/ + +Interface serial_w32: 57600 8E1 +Version : 0x22 +Option 1 : 0x00 +Option 2 : 0x00 +Device ID : 0x0410 (Medium-density) +- RAM : 20KiB (512b reserved by bootloader) +- Flash : 128KiB (sector size: 4x1024) +- Option RAM : 16b +- System RAM : 2KiB +Erasing flash +``` + +## Atmega328p Module +The EEPROM on the Atmega328p module is a dedicated 1KB data space, separate from the main flash memory. + +By default the EEPROM would be erased every time the module is flashed, but we configure the `EESAVE` bit so that the EEPROM is not erased during flashes. This is one reason why it is crucial to set the 'fuses' on a new module using the **Burn Bootloader** command in the Arduino IDE, as described in the [documentation](Compiling.md#burn-bootloader-and-set-fuses). + +The module's EEPROM can be read, written, and erased using the avrdude tool. + +#### Tools needed +* A USBasp device, or another Arduino programmed to function as a USBasp +* avrdude - installed as part of the Arduino IDE installation, or [downloaded separately](http://savannah.nongnu.org/projects/avrdude) + +With a default Arduino IDE installation, the path to avrdude will be: +* Windows - `C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avrdude.exe` +* Linux - `[Arduino IDE path]/hardware/tools/avr/bin/avrdude` +* macOS - TBD + +You will also need to know the path to the avrdude configuration file. Default locations are: +* Windows - `C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf` +* Linux - `[Arduino IDE path]/hardware/tools/avr/etc/avrdude.conf` +* macOS - TBD + +#### Preparation +Connect the module using the USBasp. + +### Backing up the Atmega328p EEPROM +The syntax of the backup command is: +`avrdude -C [config file] -c usbasp -p atmega328p -U eeprom:r:[filename]:i` + +Windows example: + +`"C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avrdude.exe" -C "C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf" -c usbasp -p atmega328p -U eeprom:r:C:\Temp\eeprom.hex:i` + +Linux and macOS example: + +`~/Downloads/arduino-1.8.5/hardware/tools/avr/bin/avrdude -C ~/Downloads/arduino-1.8.5/hardware/tools/avr/etc/avrdude.conf -c usbasp -p atmega328p -U eeprom:r:/tmp/eeprom.hex:i` + +Output will look similar to this: +``` +avrdude.exe: AVR device initialized and ready to accept instructions + +Reading | ################################################## | 100% 0.10s + +avrdude.exe: Device signature = 0x1e950f (probably m328p) +avrdude.exe: reading eeprom memory: + +Reading | ################################################## | 100% 7.51s + +avrdude.exe: writing output file "C:\Temp\eeprom.hex" + +avrdude.exe: safemode: Fuses OK (E:FD, H:D6, L:FF) + +avrdude.exe done. Thank you. +``` +### Restoring the Atmega328p EEPROM +The syntax of the restore command is: +`avrdude -C [config file] -c usbasp -p atmega328p -U eeprom:w:[filename]:i` + +Windows example: + +`"C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avrdude.exe" -C "C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf" -c usbasp -p atmega328p -U eeprom:w:C:\Temp\eeprom.hex:i` + +Linux and macOS example: + +`~/Downloads/arduino-1.8.5/hardware/tools/avr/bin/avrdude -C ~/Downloads/arduino-1.8.5/hardware/tools/avr/etc/avrdude.conf -c usbasp -p atmega328p -U eeprom:w:/tmp/eeprom.hex:i` + +Output will look similar to this: +``` +avrdude.exe: AVR device initialized and ready to accept instructions + +Reading | ################################################## | 100% 0.04s + +avrdude.exe: Device signature = 0x1e950f (probably m328p) +avrdude.exe: reading input file "C:\Temp\eeprom.hex" +avrdude.exe: writing eeprom (1024 bytes): + +Writing | ################################################## | 100% 17.17s + +avrdude.exe: 1024 bytes of eeprom written +avrdude.exe: verifying eeprom memory against C:\Temp\eeprom.hex: +avrdude.exe: load data eeprom data from input file C:\Temp\eeprom.hex: +avrdude.exe: input file C:\Temp\eeprom.hex contains 1024 bytes +avrdude.exe: reading on-chip eeprom data: + +Reading | ################################################## | 100% 6.51s + +avrdude.exe: verifying ... +avrdude.exe: 1024 bytes of eeprom verified + +avrdude.exe: safemode: Fuses OK (E:FD, H:D6, L:FF) + +avrdude.exe done. Thank you. +``` + +### Erasing the Atmega328p EEPROM +It's not possible to simply erase the EEPROM so instead we write a file which overwrites all of the content with `0xFF`. Download the 'erase.hex' file [here](https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module/master/docs/erase.hex). + +The syntax of the 'erase' command is the same as the restore command. + +Windows example: + +`"C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avrdude.exe" -C "C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf" -c usbasp -p atmega328p -U eeprom:w:C:\Temp\erase.hex:i` + +Linux and macOS example: + +`~/Downloads/arduino-1.8.5/hardware/tools/avr/bin/avrdude -C ~/Downloads/arduino-1.8.5/hardware/tools/avr/etc/avrdude.conf -c usbasp -p atmega328p -U eeprom:r:/tmp/erase.hex:i` + +Output will look similar to this: +``` +avrdude.exe: AVR device initialized and ready to accept instructions + +Reading | ################################################## | 100% 0.04s + +avrdude.exe: Device signature = 0x1e950f (probably m328p) +avrdude.exe: reading input file "C:\Temp\erase.hex" +avrdude.exe: writing eeprom (1024 bytes): + +Writing | ################################################## | 100% 17.17s + +avrdude.exe: 1024 bytes of eeprom written +avrdude.exe: verifying eeprom memory against C:\Temp\erase.hex: +avrdude.exe: load data eeprom data from input file C:\Temp\erase.hex: +avrdude.exe: input file C:\Temp\erase.hex contains 1024 bytes +avrdude.exe: reading on-chip eeprom data: + +Reading | ################################################## | 100% 6.51s + +avrdude.exe: verifying ... +avrdude.exe: 1024 bytes of eeprom verified + +avrdude.exe: safemode: Fuses OK (E:FD, H:D6, L:FF) + +avrdude.exe done. Thank you. +``` diff --git a/docs/erase.hex b/docs/erase.hex new file mode 100644 index 0000000..0b93da9 --- /dev/null +++ b/docs/erase.hex @@ -0,0 +1,33 @@ +:20000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +:20002000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 +:20004000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 +:20006000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0 +:20008000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80 +:2000A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60 +:2000C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40 +:2000E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20 +:20010000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +:20012000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDF +:20014000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF +:20016000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F +:20018000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F +:2001A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F +:2001C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F +:2001E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1F +:20020000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE +:20022000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE +:20024000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE +:20026000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E +:20028000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E +:2002A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E +:2002C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E +:2002E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E +:20030000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD +:20032000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDD +:20034000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD +:20036000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9D +:20038000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7D +:2003A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D +:2003C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3D +:2003E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1D +:00000001FF From 2ac20cb575998db27ec1ab578c22b1c7b2b7f581 Mon Sep 17 00:00:00 2001 From: Ben Lye Date: Fri, 31 Aug 2018 19:39:53 +0100 Subject: [PATCH 014/111] Update Advanced_Topics.md --- docs/Advanced_Topics.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/Advanced_Topics.md b/docs/Advanced_Topics.md index e593267..edd1523 100644 --- a/docs/Advanced_Topics.md +++ b/docs/Advanced_Topics.md @@ -6,3 +6,6 @@ It is possible to access the telemetry stream coming from the receiver through t # Manually setting fuses on ATmega328 This document describes a relatively simple process to set the fuses on ATmega328. See the [Advanced Manually Setting ATmega328 Fuses](Advanced_Manually_Setting_ATmega328_Fuses.md) page for more details. + +# EEPROM Backup and Restore +This document describes how to back up and restore the EEPROM for both Atmega328p and STM32 MULTI-modules. This can be useful if cloning a module, or to preserve settings. See the [MULTI-Module EEPROM](EEPROM.md) page for more details. From 82fb5dd0da79fe8455343021728fbac1aeeec4ae Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Mon, 3 Sep 2018 16:02:43 +0200 Subject: [PATCH 015/111] SLT: added sub_protocols SLT (11) sub_protocols are now - V1 (0): original 6 channels - V2 (1): 6 channels, might be able to add channel 7 and 8 but need testing - Q200 (2): 5 channels + switches: CH9=FMODE, CH10=FLIP, CH11=VIDON, CH12=VIDOFF --- Multiprotocol/Multi.txt | 2 +- Multiprotocol/Multiprotocol.h | 29 ++++---- Multiprotocol/SLT_nrf24l01.ino | 115 +++++++++++++++++++++++++------- Multiprotocol/WFLY_cyrf6936.ino | 4 +- Multiprotocol/_Config.h | 4 ++ 5 files changed, 115 insertions(+), 39 deletions(-) diff --git a/Multiprotocol/Multi.txt b/Multiprotocol/Multi.txt index db4f455..402b378 100644 --- a/Multiprotocol/Multi.txt +++ b/Multiprotocol/Multi.txt @@ -8,7 +8,7 @@ 8,YD717,YD717,SKYWLKR,SYMAX4,XINXUN,NIHUI 9,KN,WLTOYS,FEILUN 10,SymaX,SYMAX,SYMAX5C -11,SLT,SLT,VISTA +11,SLT,SLT_V1,SLT_V2,Q200 12,CX10,GREEN,BLUE,DM007,---,J3015_1,J3015_2,MK33041 13,CG023,CG023,YD829 14,Bayang,Bayang,H8S3D,X16_AH,IRDRONE diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 9906167..763525b 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 0 -#define VERSION_PATCH_LEVEL 36 +#define VERSION_PATCH_LEVEL 38 //****************** // Protocols @@ -76,7 +76,7 @@ enum Flysky V9X9 = 1, V6X6 = 2, V912 = 3, - CX20 = 4 + CX20 = 4, }; enum Hubsan { @@ -94,7 +94,7 @@ enum AFHDS2A enum Hisky { Hisky = 0, - HK310 = 1 + HK310 = 1, }; enum DSM { @@ -102,7 +102,7 @@ enum DSM DSM2_11 = 1, DSMX_22 = 2, DSMX_11 = 3, - DSM_AUTO = 4 + DSM_AUTO = 4, }; enum YD717 { @@ -110,22 +110,23 @@ enum YD717 SKYWLKR = 1, SYMAX4 = 2, XINXUN = 3, - NIHUI = 4 + NIHUI = 4, }; enum KN { WLTOYS = 0, - FEILUN = 1 + FEILUN = 1, }; enum SYMAX { SYMAX = 0, - SYMAX5C = 1 + SYMAX5C = 1, }; enum SLT { - SLT = 0, - VISTA = 1 + SLT_V1 = 0, + SLT_V2 = 1, + Q200 = 2, }; enum CX10 { @@ -163,7 +164,7 @@ enum MT99XX H7 = 1, YZ = 2, LS = 3, - FY805 = 4 + FY805 = 4, }; enum MJXQ { @@ -185,8 +186,8 @@ enum HONTAI { HONTAI = 0, JJRCX1 = 1, - X5C1 = 2, - FQ777_951 =3 + X5C1 = 2, + FQ777_951 =3, }; enum V2X2 { @@ -698,6 +699,10 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- OPT_FW 0 OPT_HUB 1 MINIMA 2 + sub_protocol==SLT + SLT_V1 0 + SLT_V2 1 + Q200 2 Power value => 0x80 0=High/1=Low Stream[3] = option_protocol; diff --git a/Multiprotocol/SLT_nrf24l01.ino b/Multiprotocol/SLT_nrf24l01.ino index 7e8affb..9850873 100644 --- a/Multiprotocol/SLT_nrf24l01.ino +++ b/Multiprotocol/SLT_nrf24l01.ino @@ -19,16 +19,26 @@ #include "iface_nrf24l01.h" // For code readability -#define SLT_PAYLOADSIZE 7 +#define SLT_PAYLOADSIZE_V1 7 +#define SLT_PAYLOADSIZE_V2 11 #define SLT_NFREQCHANNELS 15 #define SLT_TXID_SIZE 4 +enum{ + // flags going to packet[6] (Q200) + FLAG_Q200_FMODE = 0x20, + FLAG_Q200_VIDON = 0x10, + FLAG_Q200_FLIP = 0x08, + FLAG_Q200_VIDOFF= 0x04, +}; + enum { SLT_BUILD=0, SLT_DATA1, SLT_DATA2, SLT_DATA3, - SLT_BIND + SLT_BIND1, + SLT_BIND2 }; static void __attribute__((unused)) SLT_init() @@ -43,7 +53,10 @@ static void __attribute__((unused)) SLT_init() NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 4); // bytes of data payload for pipe 1 NRF24L01_SetBitrate(NRF24L01_BR_250K); // 256kbps NRF24L01_SetPower(); - NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\xC3\xC3\xAA\x55", 4); + if(sub_protocol==SLT_V1) + NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\xC3\xC3\xAA\x55", 4); + else // V2 + NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\x7E\xB8\x63\xA9", 4); NRF24L01_FlushRx(); NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, SLT_TXID_SIZE); NRF24L01_FlushTx(); @@ -53,6 +66,9 @@ static void __attribute__((unused)) SLT_init() static void __attribute__((unused)) SLT_set_freq(void) { + // Use adress 1-3 for model match + for (uint8_t i = 0; i < SLT_TXID_SIZE; ++i) + rx_tx_addr[i]=rx_tx_addr[i+1]; // Frequency hopping sequence generation for (uint8_t i = 0; i < SLT_TXID_SIZE; ++i) { @@ -91,12 +107,12 @@ static void __attribute__((unused)) SLT_wait_radio() packet_sent = 0; } -static void __attribute__((unused)) SLT_send_data(uint8_t *data, uint8_t len) +static void __attribute__((unused)) SLT_send_packet(uint8_t len) { SLT_wait_radio(); NRF24L01_FlushTx(); NRF24L01_WriteReg(NRF24L01_07_STATUS, _BV(NRF24L01_07_TX_DS) | _BV(NRF24L01_07_RX_DR) | _BV(NRF24L01_07_MAX_RT)); - NRF24L01_WritePayload(data, len); + NRF24L01_WritePayload(packet, len); //NRF24L01_PulseCE(); packet_sent = 1; } @@ -108,7 +124,7 @@ static void __attribute__((unused)) SLT_build_packet() if (++hopping_frequency_no >= SLT_NFREQCHANNELS) hopping_frequency_no = 0; - // aileron, elevator, throttle, rudder, gear, pitch + // aileron, elevator, throttle, rudder, gear, pitch uint8_t e = 0; // byte where extension 2 bits for every 10-bit channel are packed for (uint8_t i = 0; i < 4; ++i) { @@ -121,6 +137,20 @@ static void __attribute__((unused)) SLT_build_packet() // 8-bit channels packet[5] = convert_channel_8b(CH5); packet[6] = convert_channel_8b(CH6); + if(sub_protocol!=SLT_V1) + { + if(sub_protocol==Q200) + { + packet[6] = GET_FLAG(CH9_SW, FLAG_Q200_FMODE) + |GET_FLAG(CH10_SW, FLAG_Q200_FLIP) + |GET_FLAG(CH11_SW, FLAG_Q200_VIDON) + |GET_FLAG(CH12_SW, FLAG_Q200_VIDOFF); + } + packet[7]=0x00; //unknown, ch7?? To try : = convert_channel_8b(CH7); + packet[8]=0x7F; //unknown, ch8?? To try : = convert_channel_8b(CH8); + packet[9]=0xAA; //unknown + packet[10]=0x00; //unknown + } } static void __attribute__((unused)) SLT_send_bind_packet() @@ -132,14 +162,25 @@ static void __attribute__((unused)) SLT_send_bind_packet() NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x7E\xB8\x63\xA9", SLT_TXID_SIZE); NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x50); - SLT_send_data(rx_tx_addr, SLT_TXID_SIZE); + memcpy((void*)packet,(void*)rx_tx_addr,SLT_TXID_SIZE); + if(phase==SLT_BIND2) + SLT_send_packet(SLT_TXID_SIZE); + else // SLT_BIND1 + SLT_send_packet(SLT_PAYLOADSIZE_V2); SLT_wait_radio(); //Wait until the packet's sent before changing TX address! NRF24L01_SetPower(); //Change power back to normal level - NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, SLT_TXID_SIZE); + if(phase==SLT_BIND2) // after V1 bind and V2 second bind packet + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, SLT_TXID_SIZE); } +#define SLT_TIMING_BUILD 1000 +#define SLT_V1_TIMING_PACKET 1000 +#define SLT_V2_TIMING_PACKET 2042 +#define SLT_V1_TIMING_BIND2 1000 +#define SLT_V2_TIMING_BIND1 6507 +#define SLT_V2_TIMING_BIND2 2112 uint16_t SLT_callback() { switch (phase) @@ -147,33 +188,59 @@ uint16_t SLT_callback() case SLT_BUILD: SLT_build_packet(); phase++; - return 1000; + return SLT_TIMING_BUILD; case SLT_DATA1: - SLT_send_data(packet, SLT_PAYLOADSIZE); - phase++; - return 1000; case SLT_DATA2: - SLT_send_data(packet, SLT_PAYLOADSIZE); phase++; - return 1000; - case SLT_DATA3: - SLT_send_data(packet, SLT_PAYLOADSIZE); - if (++packet_count >= 100) + if(sub_protocol==SLT_V1) { + SLT_send_packet(SLT_PAYLOADSIZE_V1); + return SLT_V1_TIMING_PACKET; + } + else //V2 + { + SLT_send_packet(SLT_PAYLOADSIZE_V2); + return SLT_V2_TIMING_PACKET; + } + case SLT_DATA3: + if(sub_protocol==SLT_V1) + SLT_send_packet(SLT_PAYLOADSIZE_V1); + else //V2 + SLT_send_packet(SLT_PAYLOADSIZE_V2); + if (++packet_count >= 100) + {// Send bind packet packet_count = 0; - phase++; - return 1000; + if(sub_protocol==SLT_V1) + { + phase=SLT_BIND2; + return SLT_V1_TIMING_BIND2; + } + else //V2 + { + phase=SLT_BIND1; + return SLT_V2_TIMING_BIND1; + } } else - { + {// Continue to send normal packets NRF24L01_SetPower(); // Set tx_power phase = SLT_BUILD; - return 19000; + if(sub_protocol==SLT_V1) + return 20000-SLT_TIMING_BUILD; + else //V2 + return 13730-SLT_TIMING_BUILD; } - case SLT_BIND: + case SLT_BIND1: + SLT_send_bind_packet(); + phase++; + return SLT_V2_TIMING_BIND2; + case SLT_BIND2: SLT_send_bind_packet(); phase = SLT_BUILD; - return 18000; + if(sub_protocol==SLT_V1) + return 20000-SLT_TIMING_BUILD-SLT_V1_TIMING_BIND2; + else //V2 + return 13730-SLT_TIMING_BUILD-SLT_V2_TIMING_BIND1-SLT_V2_TIMING_BIND2; } return 19000; } @@ -185,7 +252,7 @@ uint16_t initSLT() hopping_frequency_no = 0; SLT_set_freq(); SLT_init(); - phase = SLT_BIND; + phase = SLT_BUILD; return 50000; } diff --git a/Multiprotocol/WFLY_cyrf6936.ino b/Multiprotocol/WFLY_cyrf6936.ino index c4bf9e6..ddc59d2 100644 --- a/Multiprotocol/WFLY_cyrf6936.ino +++ b/Multiprotocol/WFLY_cyrf6936.ino @@ -57,7 +57,7 @@ const uint8_t PROGMEM WFLY_init_vals[][2] = { static void __attribute__((unused)) WFLY_cyrf_bind_config() { - for(uint8_t i = 0; i < sizeof(init_vals) / 2; i++) + for(uint8_t i = 0; i < sizeof(WFLY_init_vals) / 2; i++) CYRF_WriteRegister(pgm_read_byte_near(&WFLY_init_vals[i][0]), pgm_read_byte_near(&WFLY_init_vals[i][1])); CYRF_PROGMEM_ConfigSOPCode(WFLY_sop_bind); @@ -67,7 +67,7 @@ static void __attribute__((unused)) WFLY_cyrf_bind_config() static void __attribute__((unused)) WFLY_cyrf_data_config() { - for(uint8_t i = 0; i < (sizeof(init_vals) / 2)-3; i++) + for(uint8_t i = 0; i < (sizeof(WFLY_init_vals) / 2)-3; i++) CYRF_WriteRegister(pgm_read_byte_near(&WFLY_init_vals[i][0]), pgm_read_byte_near(&WFLY_init_vals[i][1])); //CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x08); // Do not accept CRC with 0 seed but not needed since the RX is not sending any data... diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 10c10b6..2afee9a 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -562,6 +562,10 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= { NONE PROTO_BUGS NONE + PROTO_SLT + SLT_V1 + SLT_V2 + Q200 */ // RX_Num is used for TX & RX match. Using different RX_Num values for each receiver will prevent starting a model with the false config loaded... From 51ba7cf75cf0a932d558510b6ff0d1dde11cccab Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Mon, 3 Sep 2018 17:30:53 +0200 Subject: [PATCH 016/111] Update SLT/Q200 hopping freq --- Multiprotocol/Multiprotocol.h | 2 +- Multiprotocol/SLT_nrf24l01.ino | 31 ++++++++++++++++++++----------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 763525b..1b45ae6 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 0 -#define VERSION_PATCH_LEVEL 38 +#define VERSION_PATCH_LEVEL 39 //****************** // Protocols diff --git a/Multiprotocol/SLT_nrf24l01.ino b/Multiprotocol/SLT_nrf24l01.ino index 9850873..db7912d 100644 --- a/Multiprotocol/SLT_nrf24l01.ino +++ b/Multiprotocol/SLT_nrf24l01.ino @@ -18,6 +18,8 @@ #include "iface_nrf24l01.h" +//#define SLT_Q200_FORCE_ID + // For code readability #define SLT_PAYLOADSIZE_V1 7 #define SLT_PAYLOADSIZE_V2 11 @@ -66,7 +68,7 @@ static void __attribute__((unused)) SLT_init() static void __attribute__((unused)) SLT_set_freq(void) { - // Use adress 1-3 for model match + // Make use of address 1-3 for model match for (uint8_t i = 0; i < SLT_TXID_SIZE; ++i) rx_tx_addr[i]=rx_tx_addr[i+1]; // Frequency hopping sequence generation @@ -77,11 +79,14 @@ static void __attribute__((unused)) SLT_set_freq(void) hopping_frequency[i*4 + 0] = (rx_tx_addr[i] & 0x3f) + base; hopping_frequency[i*4 + 1] = (rx_tx_addr[i] >> 2) + base; hopping_frequency[i*4 + 2] = (rx_tx_addr[i] >> 4) + (rx_tx_addr[next_i] & 0x03)*0x10 + base; - if (i*4 + 3 < SLT_NFREQCHANNELS) // guard for 16 channel + //if (i*4 + 3 < SLT_NFREQCHANNELS) // do not generate channel 15. 15 channels: 0-14. But not needed since hopping freq table is large... hopping_frequency[i*4 + 3] = (rx_tx_addr[i] >> 6) + (rx_tx_addr[next_i] & 0x0f)*0x04 + base; } - // unique + // Unique freq + uint8_t max_freq=0x50; //V1 and V2? + if(sub_protocol==Q200) + max_freq=45; // unsure about the right value... It could be anything between 44 and 48 but 45 keeps the +3 rule intact. for (uint8_t i = 0; i < SLT_NFREQCHANNELS; ++i) { uint8_t done = 0; @@ -93,8 +98,8 @@ static void __attribute__((unused)) SLT_set_freq(void) { done = 0; hopping_frequency[i] += 7; - if (hopping_frequency[i] >= 0x50) - hopping_frequency[i] = hopping_frequency[i] - 0x50 + 0x03; + if (hopping_frequency[i] >= max_freq) + hopping_frequency[i] = hopping_frequency[i] - max_freq + 0x03; } } } @@ -113,7 +118,6 @@ static void __attribute__((unused)) SLT_send_packet(uint8_t len) NRF24L01_FlushTx(); NRF24L01_WriteReg(NRF24L01_07_STATUS, _BV(NRF24L01_07_TX_DS) | _BV(NRF24L01_07_RX_DR) | _BV(NRF24L01_07_MAX_RT)); NRF24L01_WritePayload(packet, len); - //NRF24L01_PulseCE(); packet_sent = 1; } @@ -140,14 +144,12 @@ static void __attribute__((unused)) SLT_build_packet() if(sub_protocol!=SLT_V1) { if(sub_protocol==Q200) - { - packet[6] = GET_FLAG(CH9_SW, FLAG_Q200_FMODE) + packet[6] = GET_FLAG(CH9_SW , FLAG_Q200_FMODE) |GET_FLAG(CH10_SW, FLAG_Q200_FLIP) |GET_FLAG(CH11_SW, FLAG_Q200_VIDON) |GET_FLAG(CH12_SW, FLAG_Q200_VIDOFF); - } - packet[7]=0x00; //unknown, ch7?? To try : = convert_channel_8b(CH7); - packet[8]=0x7F; //unknown, ch8?? To try : = convert_channel_8b(CH8); + packet[7]=0x00; //unknown, ch7?? To try: = convert_channel_8b(CH7); + packet[8]=0x7F; //unknown, ch8?? To try: = convert_channel_8b(CH8); packet[9]=0xAA; //unknown packet[10]=0x00; //unknown } @@ -251,6 +253,13 @@ uint16_t initSLT() packet_sent = 0; hopping_frequency_no = 0; SLT_set_freq(); + #ifdef SLT_Q200_FORCE_ID // ID and channels taken from dump + rx_tx_addr[0]=0x01; + rx_tx_addr[1]=0x02; + rx_tx_addr[2]=0x6A; + rx_tx_addr[3]=0x31; + memcpy((void *)hopping_frequency,(void *)"\x04\x03\x23\x0B\x05\x0A\x2A\x2B\x10\x07\x26\x15\x17\x1C\x0E",SLT_NFREQCHANNELS); + #endif SLT_init(); phase = SLT_BUILD; return 50000; From 3902ed19b70aff987c7c81b0df61bcf64a677c43 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 3 Sep 2018 19:11:33 +0200 Subject: [PATCH 017/111] Update Compiling_STM32.md --- docs/Compiling_STM32.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Compiling_STM32.md b/docs/Compiling_STM32.md index 1b080ce..1e18af6 100644 --- a/docs/Compiling_STM32.md +++ b/docs/Compiling_STM32.md @@ -132,6 +132,7 @@ In order to flash the bootloader the **BOOT0** jumper must be installed connecti 1. Verify that you have selected the upload method **Upload via Serial inc. Bootloader (FTDI)** under **Tools -> Upload Method** 1. Verify that you have selected **stm32flash (FTDI)** as the programmer under **Tools -> Programmer** 1. Verify that the USB-to-TTL adapter is correctly connected to your module and you have selected the correct port under **Tools -> Port** +1. In the Arduino IDE click **Sketch -> Upload**, or press **Ctrl+U** Output will look similar to this: ``` From b7447f055ab32c9f86fb1752320743449797ade1 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Wed, 5 Sep 2018 15:38:36 +0200 Subject: [PATCH 018/111] SLT/Q200 subprotocol changes --- Multiprotocol/Multiprotocol.h | 2 +- Multiprotocol/SLT_nrf24l01.ino | 34 ++++++++++++++++------------------ 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 1b45ae6..7a4ffc3 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 0 -#define VERSION_PATCH_LEVEL 39 +#define VERSION_PATCH_LEVEL 40 //****************** // Protocols diff --git a/Multiprotocol/SLT_nrf24l01.ino b/Multiprotocol/SLT_nrf24l01.ino index db7912d..96b6f2a 100644 --- a/Multiprotocol/SLT_nrf24l01.ino +++ b/Multiprotocol/SLT_nrf24l01.ino @@ -56,9 +56,9 @@ static void __attribute__((unused)) SLT_init() NRF24L01_SetBitrate(NRF24L01_BR_250K); // 256kbps NRF24L01_SetPower(); if(sub_protocol==SLT_V1) - NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\xC3\xC3\xAA\x55", 4); + NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\xC3\xC3\xAA\x55", SLT_TXID_SIZE); else // V2 - NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\x7E\xB8\x63\xA9", 4); + NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\x7E\xB8\x63\xA9", SLT_TXID_SIZE); NRF24L01_FlushRx(); NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, SLT_TXID_SIZE); NRF24L01_FlushTx(); @@ -68,9 +68,6 @@ static void __attribute__((unused)) SLT_init() static void __attribute__((unused)) SLT_set_freq(void) { - // Make use of address 1-3 for model match - for (uint8_t i = 0; i < SLT_TXID_SIZE; ++i) - rx_tx_addr[i]=rx_tx_addr[i+1]; // Frequency hopping sequence generation for (uint8_t i = 0; i < SLT_TXID_SIZE; ++i) { @@ -79,14 +76,13 @@ static void __attribute__((unused)) SLT_set_freq(void) hopping_frequency[i*4 + 0] = (rx_tx_addr[i] & 0x3f) + base; hopping_frequency[i*4 + 1] = (rx_tx_addr[i] >> 2) + base; hopping_frequency[i*4 + 2] = (rx_tx_addr[i] >> 4) + (rx_tx_addr[next_i] & 0x03)*0x10 + base; - //if (i*4 + 3 < SLT_NFREQCHANNELS) // do not generate channel 15. 15 channels: 0-14. But not needed since hopping freq table is large... - hopping_frequency[i*4 + 3] = (rx_tx_addr[i] >> 6) + (rx_tx_addr[next_i] & 0x0f)*0x04 + base; + hopping_frequency[i*4 + 3] = (rx_tx_addr[i] >> 6) + (rx_tx_addr[next_i] & 0x0f)*0x04 + base; } // Unique freq - uint8_t max_freq=0x50; //V1 and V2? + uint8_t max_freq=0x50; //V1 sure, V2? if(sub_protocol==Q200) - max_freq=45; // unsure about the right value... It could be anything between 44 and 48 but 45 keeps the +3 rule intact. + max_freq=45; for (uint8_t i = 0; i < SLT_NFREQCHANNELS; ++i) { uint8_t done = 0; @@ -148,8 +144,8 @@ static void __attribute__((unused)) SLT_build_packet() |GET_FLAG(CH10_SW, FLAG_Q200_FLIP) |GET_FLAG(CH11_SW, FLAG_Q200_VIDON) |GET_FLAG(CH12_SW, FLAG_Q200_VIDOFF); - packet[7]=0x00; //unknown, ch7?? To try: = convert_channel_8b(CH7); - packet[8]=0x7F; //unknown, ch8?? To try: = convert_channel_8b(CH8); + packet[7]=convert_channel_8b(CH7); + packet[8]=convert_channel_8b(CH8); packet[9]=0xAA; //unknown packet[10]=0x00; //unknown } @@ -252,14 +248,16 @@ uint16_t initSLT() packet_count = 0; packet_sent = 0; hopping_frequency_no = 0; - SLT_set_freq(); - #ifdef SLT_Q200_FORCE_ID // ID and channels taken from dump - rx_tx_addr[0]=0x01; - rx_tx_addr[1]=0x02; - rx_tx_addr[2]=0x6A; - rx_tx_addr[3]=0x31; - memcpy((void *)hopping_frequency,(void *)"\x04\x03\x23\x0B\x05\x0A\x2A\x2B\x10\x07\x26\x15\x17\x1C\x0E",SLT_NFREQCHANNELS); + if(sub_protocol==Q200) + { //looks like the Q200 is expecting a special ID to bind + rx_tx_addr[0]=0x01; // This is common between the 2 Dumps so assuming this is what is required... + rx_tx_addr[1]=0x02; // This is common between the 2 Dumps so assuming this is what is required... + } + #ifdef SLT_Q200_FORCE_ID // ID taken from TX dumps + rx_tx_addr[0]=0x01;rx_tx_addr[1]=0x02;rx_tx_addr[2]=0x6A;rx_tx_addr[3]=0x31; + /* rx_tx_addr[0]=0x01;rx_tx_addr[1]=0x02;rx_tx_addr[2]=0x0B;rx_tx_addr[3]=0x57;*/ #endif + SLT_set_freq(); SLT_init(); phase = SLT_BUILD; return 50000; From d67108fa8bf163ffa436491ad49f7e68fd798ef6 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Thu, 6 Sep 2018 10:57:36 +0200 Subject: [PATCH 019/111] SLT/Q200: Fix frequencies calculation --- Multiprotocol/Multiprotocol.h | 2 +- Multiprotocol/SLT_nrf24l01.ino | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 7a4ffc3..9459afe 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 0 -#define VERSION_PATCH_LEVEL 40 +#define VERSION_PATCH_LEVEL 41 //****************** // Protocols diff --git a/Multiprotocol/SLT_nrf24l01.ino b/Multiprotocol/SLT_nrf24l01.ino index 96b6f2a..f5d4345 100644 --- a/Multiprotocol/SLT_nrf24l01.ino +++ b/Multiprotocol/SLT_nrf24l01.ino @@ -85,6 +85,8 @@ static void __attribute__((unused)) SLT_set_freq(void) max_freq=45; for (uint8_t i = 0; i < SLT_NFREQCHANNELS; ++i) { + if(sub_protocol==Q200 && hopping_frequency[i] >= max_freq) + hopping_frequency[i] = hopping_frequency[i] - max_freq + 0x03; uint8_t done = 0; while (!done) { @@ -249,14 +251,14 @@ uint16_t initSLT() packet_sent = 0; hopping_frequency_no = 0; if(sub_protocol==Q200) - { //looks like the Q200 is expecting a special ID to bind - rx_tx_addr[0]=0x01; // This is common between the 2 Dumps so assuming this is what is required... - rx_tx_addr[1]=0x02; // This is common between the 2 Dumps so assuming this is what is required... + { //Q200: Force high part of the ID otherwise it won't bind + rx_tx_addr[0]=0x01; + rx_tx_addr[1]=0x02; + #ifdef SLT_Q200_FORCE_ID // ID taken from TX dumps + rx_tx_addr[0]=0x01;rx_tx_addr[1]=0x02;rx_tx_addr[2]=0x6A;rx_tx_addr[3]=0x31; + /* rx_tx_addr[0]=0x01;rx_tx_addr[1]=0x02;rx_tx_addr[2]=0x0B;rx_tx_addr[3]=0x57;*/ + #endif } - #ifdef SLT_Q200_FORCE_ID // ID taken from TX dumps - rx_tx_addr[0]=0x01;rx_tx_addr[1]=0x02;rx_tx_addr[2]=0x6A;rx_tx_addr[3]=0x31; - /* rx_tx_addr[0]=0x01;rx_tx_addr[1]=0x02;rx_tx_addr[2]=0x0B;rx_tx_addr[3]=0x57;*/ - #endif SLT_set_freq(); SLT_init(); phase = SLT_BUILD; From c6cb13b332133da81b69f4467e304a7c90854517 Mon Sep 17 00:00:00 2001 From: Ben Lye Date: Thu, 6 Sep 2018 10:44:16 +0100 Subject: [PATCH 020/111] Initial go at Travis CI (#191) --- .travis.yml | 136 ++++++++++++++++++++++++++++++++++++++ buildroot/bin/opt_add | 3 + buildroot/bin/opt_disable | 7 ++ buildroot/bin/opt_enable | 7 ++ buildroot/bin/opt_set | 5 ++ 5 files changed, 158 insertions(+) create mode 100644 .travis.yml create mode 100755 buildroot/bin/opt_add create mode 100755 buildroot/bin/opt_disable create mode 100755 buildroot/bin/opt_enable create mode 100755 buildroot/bin/opt_set diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..d282c22 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,136 @@ +dist: trusty +sudo: true + # +language: c + # +env: + global: + - IDE_VERSION=1.8.1 + matrix: + - BOARD="multi4in1:STM32F1:multistm32f103c:upload_method=serialMethod" + - BOARD="multi4in1:STM32F1:multistm32f103c:upload_method=TxFlashMethod" + - BOARD="multi4in1:avr:multixmega32d4" + - BOARD="multi4in1:avr:multiatmega328p:bootloader=none" + - BOARD="multi4in1:avr:multiatmega328p:bootloader=optiboot" + # +notifications: + email: false + # +before_install: + # + # Fetch the tag information for the current branch + - git fetch origin --tags + # + # Publish the buildroot script folder + - chmod +x ${TRAVIS_BUILD_DIR}/buildroot/bin/* + - export PATH=${TRAVIS_BUILD_DIR}/buildroot/bin/:${PATH} + # + # Install Arduino IDE + - wget http://downloads.arduino.cc/arduino-$IDE_VERSION-linux64.tar.xz + - tar xf arduino-$IDE_VERSION-linux64.tar.xz + - mv arduino-$IDE_VERSION $HOME/arduino-ide + - export PATH=$PATH:$HOME/arduino-ide + # Set the Multi boards package URL + - arduino --pref "boardsmanager.additional.urls=https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/master/package_multi_4in1_board_index.json" --save-prefs + # + - if [[ "$BOARD" =~ "multi4in1:STM32F1:" ]]; then + arduino --install-boards multi4in1:STM32F1; + fi + # + - if [[ "$BOARD" =~ "multi4in1:avr:" ]]; then + arduino --install-boards multi4in1:avr; + fi + # + - buildMulti() { arduino --verify --board $BOARD Multiprotocol/Multiprotocol.ino; } + - buildProtocol() { opt_disable $ALL_PROTOCOLS; opt_enable $1; buildMulti; } + # +install: true +before_script: + # + # Change current working directory to the build dir + - cd ${TRAVIS_BUILD_DIR} + # Log the initial Multi config + - cat Multiprotocol/_Config.h + # Derive the Multi protocols from the Multi source + - A7105_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]]*_A7105_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h) + - CC2500_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]]*_CC2500_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h) + - CYRF6936_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]]*_CYRF6936_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h) + - NRF24L01_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]]*_NRF24L01_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h) + - ALL_PROTOCOLS=$(echo $A7105_PROTOCOLS $CC2500_PROTOCOLS $CYRF6936_PROTOCOLS $NRF24L01_PROTOCOLS) + - echo $ALL_PROTOCOLS + # + # Enable CHECK_FOR_BOOTLOADER when needed + - if [[ "$BOARD" =~ ":upload_method=TxFlashMethod" ]] || [[ "$BOARD" =~ ":bootloader=optiboot" ]]; then + opt_enable CHECK_FOR_BOOTLOADER; + fi + # + # Trim the build down for the Atmega328p board + - if [[ "$BOARD" =~ "multi4in1:avr:multiatmega328p:" ]]; then + opt_disable $ALL_PROTOCOLS; + opt_enable FRSKYX_CC2500_INO AFHDS2A_A7105_INO MJXQ_NRF24L01_INO DSM_CYRF6936_INO; + fi + # +script: + # Build with all protocols enabled for STM32; a subset of protocols for Atmega + - buildMulti + # + # Serial only + - opt_disable ENABLE_PPM + - opt_enable ENABLE_SERIAL + - buildMulti + # + # PPM only + - opt_enable ENABLE_PPM + - opt_disable ENABLE_SERIAL + - buildMulti + # + # Re-enable PPM and serial + - opt_enable ENABLE_SERIAL + - opt_enable ENABLE_PPM + # + # Build each A7150 protocol + - buildProtocol AFHDS2A_A7105_INO + - buildProtocol FLYSKY_A7105_INO + - buildProtocol HUBSAN_A7105_INO + - buildProtocol BUGS_A7105_INO + # + # Build each CC2500 protocol + - buildProtocol CORONA_CC2500_INO + - buildProtocol FRSKYD_CC2500_INO + - buildProtocol FRSKYV_CC2500_INO + - buildProtocol FRSKYX_CC2500_INO + - buildProtocol HITEC_CC2500_INO + - buildProtocol SFHSS_CC2500_INO + # + # Build each CYRF6936 protocol + - buildProtocol DEVO_CYRF6936_INO + - buildProtocol DSM_CYRF6936_INO + - buildProtocol J6PRO_CYRF6936_INO + - buildProtocol WFLY_CYRF6936_INO + - buildProtocol WK2x01_CYRF6936_INO + # + # Build each NRF24L01 protocol + - buildProtocol ASSAN_NRF24L01_INO + - buildProtocol BAYANG_NRF24L01_INO + - buildProtocol CABELL_NRF24L01_INO + - buildProtocol CFLIE_NRF24L01_INO + - buildProtocol CG023_NRF24L01_INO + - buildProtocol CX10_NRF24L01_INO + - buildProtocol DM002_NRF24L01_INO + - buildProtocol ESKY_NRF24L01_INO + - buildProtocol ESKY150_NRF24L01_INO + - buildProtocol FQ777_NRF24L01_INO + - buildProtocol FY326_NRF24L01_INO + - buildProtocol GW008_NRF24L01_INO + - buildProtocol HISKY_NRF24L01_INO + - buildProtocol HONTAI_NRF24L01_INO + - buildProtocol H8_3D_NRF24L01_INO + - buildProtocol KN_NRF24L01_INO + - buildProtocol MJXQ_NRF24L01_INO + - buildProtocol MT99XX_NRF24L01_INO + - buildProtocol Q303_NRF24L01_INO + - buildProtocol SHENQI_NRF24L01_INO + - buildProtocol SLT_NRF24L01_INO + - buildProtocol SYMAX_NRF24L01_INO + - buildProtocol V2X2_NRF24L01_INO + - buildProtocol YD717_NRF24L01_INO diff --git a/buildroot/bin/opt_add b/buildroot/bin/opt_add new file mode 100755 index 0000000..3a70bed --- /dev/null +++ b/buildroot/bin/opt_add @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +eval "echo \"#define ${1} ${2}\" >>Multiprotocol/_Config.h" diff --git a/buildroot/bin/opt_disable b/buildroot/bin/opt_disable new file mode 100755 index 0000000..26ead15 --- /dev/null +++ b/buildroot/bin/opt_disable @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +SED=$(which gsed || which sed) + +for opt in "$@" ; do + eval "${SED} -i 's/\([[:blank:]]*\)\(#define[[:blank:]]*\b${opt}\b\)/\1\/\/\2/g' Multiprotocol/_Config.h" +done diff --git a/buildroot/bin/opt_enable b/buildroot/bin/opt_enable new file mode 100755 index 0000000..f1a5b81 --- /dev/null +++ b/buildroot/bin/opt_enable @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +SED=$(which gsed || which sed) + +for opt in "$@" ; do + eval "${SED} -i 's/\/\/[[:blank:]]*\(#define[[:blank:]]*\b${opt}\b\)/\1/g' Multiprotocol/_Config.h" +done diff --git a/buildroot/bin/opt_set b/buildroot/bin/opt_set new file mode 100755 index 0000000..06d244c --- /dev/null +++ b/buildroot/bin/opt_set @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +SED=$(which gsed || which sed) + +eval "${SED} -i 's/\(#define \b${1}\b\).*$/\1 ${2}/g' Multiprotocol/_Config.h" From 77d248df0b7273bd1f6853d13d0c14342e462d18 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 6 Sep 2018 17:24:56 +0200 Subject: [PATCH 021/111] Add Travis status --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index f8d13a6..70e6474 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,13 @@ If you like this project and want to support further development please consider +## Development status + +Current Multiprotocol code check status: [![Travis Build Status for Multi](https://api.travis-ci.org/pascallanger/DIY-Multiprotocol-TX-Module.svg)](https://travis-ci.org/pascallanger/DIY-Multiprotocol-TX-Module) + +Current Multiprotocol boards check status: [![Travis Build Status for Multi Boards](https://api.travis-ci.org/pascallanger/DIY-Multiprotocol-TX-Module-Boards.svg)](https://travis-ci.org/pascallanger/DIY-Multiprotocol-TX-Module-Boards) + + ## Quicklinks * [Download latest releases of the firmware](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases) and [instructions to upload .hex files](docs/Advanced_Manually_Setting_ATmega328_Fuses.md) * [Forum on rcgroups](http://www.rcgroups.com/forums/showthread.php?t=2165676) @@ -120,6 +127,7 @@ Visit the [Troubleshooting](docs/Troubleshooting.md) page. Please bear in mind # A final word A very big thanks to all the people who have shared their time so graciously to create this great project. If you come across them on RC Groups, please be kind and show appreciation. In no particular order: * Pascal Langer (rcgroups: hpnuts) +* Ben Lye (rcgroups: benzo99) * Midelic (rcgroups: midelic) * Mike Blandford (rcgroups: Mike Blandford) * PhracturedBlue – from Deviation-tx From 41528ae7b6e67feee1e25d670a8afe46c8872f58 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 6 Sep 2018 18:56:14 +0200 Subject: [PATCH 022/111] Update README.md --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 70e6474..84d4cf3 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ The **Multiprotocol Tx Module** (or **MULTI-Module**) is a 2.4GHz transmitter module which enables almost any transmitter to control many different receivers and models, including many popular helicopters, planes, quadcopters, and miniquads. -The source code is partly based on the [Deviation TX project](http://www.deviationtx.com), thanks to all the developers for their great job on protocols. +The main forum is on [RCGroups.com](https://www.rcgroups.com/forums/showthread.php?2165676-DIY-Multiprotocol-TX-Module/page10000). If you like this project and want to support further development please consider making a [donation](docs/Donations.md). @@ -130,10 +130,11 @@ A very big thanks to all the people who have shared their time so graciously to * Ben Lye (rcgroups: benzo99) * Midelic (rcgroups: midelic) * Mike Blandford (rcgroups: Mike Blandford) -* PhracturedBlue – from Deviation-tx -* goebish – from Deviation-tx -* victzh – from Deviation-tx -* hexfet – from Deviation-tx +* schwabe - from OpenTX +* PhracturedBlue – from [Deviation TX project](http://www.deviationtx.com) +* goebish – from [Deviation TX project](http://www.deviationtx.com) +* victzh – from [Deviation TX project](http://www.deviationtx.com) +* hexfet – from [Deviation TX project](http://www.deviationtx.com) Your help would be greatly appreciated. If protocol reverse-engineering and dev is not your thing then any help with testing and contributing to the documentation would be amazing. Given the number of different Tx/module hardware/RF module/protocol/model combinations the process of testing and documenting is a major bottleneck for the developers. Anything you can do to help will free them up to do even greater things. From 1ec817c96c2e6d682595e355bcffe3e615b7a37f Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 6 Sep 2018 19:09:10 +0200 Subject: [PATCH 023/111] SLT sub protocols V1, V2, Q200 --- Protocols_Details.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index 73d4bd6..2bdcee2 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -826,10 +826,25 @@ Throttle +100%=full forward,0%=stop,-100%=full backward. ## SLT - *11* Autobind protocol +### Sub_protocol V1 - *0* + CH1|CH2|CH3|CH4|CH5|CH6 ---|---|---|---|---|--- A|E|T|R|GEAR|PITCH +### Sub_protocol V2 - *1* + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +---|---|---|---|---|---|---|--- +A|E|T|R|CH5|CH6|CH7|CH8 + +### Sub_protocol Q200 - *2* +Models: Ominus Quadcopter FPV, the Nine Eagles - FENG FPV and may be others + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 +---|---|---|---|---|---|---|---|---|---|---|--- +A|E|T|R|CH5|-|CH7|CH8|MODE|FLIP|VID_ON|VID_OFF + ## Symax - *10* Autobind protocol From 4f9c30505ace9568f295e2b9f7820474bd6c04d7 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 6 Sep 2018 20:49:28 +0200 Subject: [PATCH 024/111] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 84d4cf3..b3a7265 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ The **Multiprotocol Tx Module** (or **MULTI-Module**) is a 2.4GHz transmitter module which enables almost any transmitter to control many different receivers and models, including many popular helicopters, planes, quadcopters, and miniquads. -The main forum is on [RCGroups.com](https://www.rcgroups.com/forums/showthread.php?2165676-DIY-Multiprotocol-TX-Module/page10000). +The main forum for protocol requests and questions is on [RCGroups.com](https://www.rcgroups.com/forums/showthread.php?2165676-DIY-Multiprotocol-TX-Module/page10000). If you like this project and want to support further development please consider making a [donation](docs/Donations.md). From e2a66bdd1fc48ba0b739ebfaad3be9fc8690bd35 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Fri, 7 Sep 2018 10:38:22 +0200 Subject: [PATCH 025/111] SLT/Q200: gyro calibration on CH13 --- Multiprotocol/Multiprotocol.h | 2 +- Multiprotocol/SLT_nrf24l01.ino | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 9459afe..848abdb 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 0 -#define VERSION_PATCH_LEVEL 41 +#define VERSION_PATCH_LEVEL 42 //****************** // Protocols diff --git a/Multiprotocol/SLT_nrf24l01.ino b/Multiprotocol/SLT_nrf24l01.ino index f5d4345..469533c 100644 --- a/Multiprotocol/SLT_nrf24l01.ino +++ b/Multiprotocol/SLT_nrf24l01.ino @@ -121,6 +121,8 @@ static void __attribute__((unused)) SLT_send_packet(uint8_t len) static void __attribute__((unused)) SLT_build_packet() { + static uint8_t calib_counter=0; + // Set radio channel - once per packet batch NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]); if (++hopping_frequency_no >= SLT_NFREQCHANNELS) @@ -148,8 +150,18 @@ static void __attribute__((unused)) SLT_build_packet() |GET_FLAG(CH12_SW, FLAG_Q200_VIDOFF); packet[7]=convert_channel_8b(CH7); packet[8]=convert_channel_8b(CH8); - packet[9]=0xAA; //unknown - packet[10]=0x00; //unknown + packet[9]=0xAA; //normal mode for Q200, unknown for V2 + packet[10]=0x00; //normal mode for Q200, unknown for V2 + if(sub_protocol==Q200 && CH13_SW) + {//Calibrate + packet[9]=0x77; //enter calibration + if(calib_counter>=20 && calib_counter<=23) // 3 packets + packet[10]=0x20; //launch calibration + calib_counter++; + if(calib_counter>250) calib_counter=250; + } + else + calib_counter=0; } } From 1e65d58113e60710eae7f9c37fce80281a87c8c0 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 7 Sep 2018 10:52:07 +0200 Subject: [PATCH 026/111] SLT Q200 channels --- Protocols_Details.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 2bdcee2..a39c1a3 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -841,9 +841,15 @@ A|E|T|R|CH5|CH6|CH7|CH8 ### Sub_protocol Q200 - *2* Models: Ominus Quadcopter FPV, the Nine Eagles - FENG FPV and may be others -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 ----|---|---|---|---|---|---|---|---|---|---|--- -A|E|T|R|CH5|-|CH7|CH8|MODE|FLIP|VID_ON|VID_OFF +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13 +---|---|---|---|---|---|---|---|---|---|---|---|--- +A|E|T|R|RATES|-|CH7|CH8|MODE|FLIP|VID_ON|VID_OFF|CALIB + +RATES: +50%=min rates, 0%=mid rates (stock setting), -50%=max rates + +CH7 and CH8 have no effect on the Ominus + +CALIB: -100% normal mode, +100% gyro calibration ## Symax - *10* Autobind protocol From 5aa4936c0e04aee0a7350f6f02487d5a868cc868 Mon Sep 17 00:00:00 2001 From: Ben Lye Date: Fri, 7 Sep 2018 10:27:43 +0100 Subject: [PATCH 027/111] Add stm32 board v1.0.9 (#192) --- .../package_multi_4in1_board_index.json | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/BootLoaders/package_multi_4in1_board_index.json b/BootLoaders/package_multi_4in1_board_index.json index f29b5bd..d39a836 100644 --- a/BootLoaders/package_multi_4in1_board_index.json +++ b/BootLoaders/package_multi_4in1_board_index.json @@ -266,6 +266,27 @@ "version": "4.8.3-2014q1" }] }, + { + "name": "Multi 4-in-1 STM32 Board", + "architecture": "STM32F1", + "version": "1.0.9", + "category": "Contributed", + "help": { + "online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module" + }, + "url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.9.tar.gz", + "archiveFileName": "package_multi_4in1_stm32_board_v1.0.9.tar.gz", + "checksum": "SHA-256:c3621d1cf6580ca5c943a67dc14dc15a60e2797a4b985548abe1919486bf4a8b", + "size": "10324251", + "boards": [{ + "name": "Multi 4-in-1 (STM32F103C)" + }], + "toolsDependencies": [{ + "packager": "arduino", + "name": "arm-none-eabi-gcc", + "version": "4.8.3-2014q1" + }] + }, { "name": "Multi 4-in-1 OrangeRX Board - DEPRECATED, USE MULTI 4-IN-1 AVR BOARDS PACKAGE INSTEAD", "architecture": "orangerx", From 3b9aa79201154712adc206d7d880b1d19ebd23e2 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Sun, 9 Sep 2018 11:26:01 +0200 Subject: [PATCH 028/111] SLT sub protocol MR100 for Vista CH9: MODE CH10: FLIP CH11: VIDEO CH12:PICTURE --- Multiprotocol/Multiprotocol.h | 4 +++- Multiprotocol/SLT_nrf24l01.ino | 15 ++++++++++++++- Multiprotocol/_Config.h | 1 + 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 848abdb..015eb0a 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 0 -#define VERSION_PATCH_LEVEL 42 +#define VERSION_PATCH_LEVEL 44 //****************** // Protocols @@ -127,6 +127,7 @@ enum SLT SLT_V1 = 0, SLT_V2 = 1, Q200 = 2, + MR100 = 3, }; enum CX10 { @@ -703,6 +704,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- SLT_V1 0 SLT_V2 1 Q200 2 + MR100 3 Power value => 0x80 0=High/1=Low Stream[3] = option_protocol; diff --git a/Multiprotocol/SLT_nrf24l01.ino b/Multiprotocol/SLT_nrf24l01.ino index 469533c..396f02b 100644 --- a/Multiprotocol/SLT_nrf24l01.ino +++ b/Multiprotocol/SLT_nrf24l01.ino @@ -34,6 +34,14 @@ enum{ FLAG_Q200_VIDOFF= 0x04, }; +enum{ + // flags going to packet[6] (MR100) + FLAG_MR100_FMODE = 0x20, + FLAG_MR100_FLIP = 0x04, + FLAG_MR100_VIDEO = 0x02, + FLAG_MR100_PICTURE = 0x01, +}; + enum { SLT_BUILD=0, SLT_DATA1, @@ -80,7 +88,7 @@ static void __attribute__((unused)) SLT_set_freq(void) } // Unique freq - uint8_t max_freq=0x50; //V1 sure, V2? + uint8_t max_freq=0x50; //V1 and V2 if(sub_protocol==Q200) max_freq=45; for (uint8_t i = 0; i < SLT_NFREQCHANNELS; ++i) @@ -148,6 +156,11 @@ static void __attribute__((unused)) SLT_build_packet() |GET_FLAG(CH10_SW, FLAG_Q200_FLIP) |GET_FLAG(CH11_SW, FLAG_Q200_VIDON) |GET_FLAG(CH12_SW, FLAG_Q200_VIDOFF); + if(sub_protocol==MR100) + packet[6] = GET_FLAG(CH9_SW , FLAG_MR100_FMODE) + |GET_FLAG(CH10_SW, FLAG_MR100_FLIP) + |GET_FLAG(CH11_SW, FLAG_MR100_VIDEO) + |GET_FLAG(CH12_SW, FLAG_MR100_PICTURE); packet[7]=convert_channel_8b(CH7); packet[8]=convert_channel_8b(CH8); packet[9]=0xAA; //normal mode for Q200, unknown for V2 diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 2afee9a..28d546c 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -566,6 +566,7 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= { SLT_V1 SLT_V2 Q200 + MR100 */ // RX_Num is used for TX & RX match. Using different RX_Num values for each receiver will prevent starting a model with the false config loaded... From 03f417546e015482e6c800bf76022acd9195bd50 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Sun, 9 Sep 2018 11:29:25 +0200 Subject: [PATCH 029/111] Multi.txt update --- Multiprotocol/Multi.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Multiprotocol/Multi.txt b/Multiprotocol/Multi.txt index 402b378..3f10f69 100644 --- a/Multiprotocol/Multi.txt +++ b/Multiprotocol/Multi.txt @@ -8,7 +8,7 @@ 8,YD717,YD717,SKYWLKR,SYMAX4,XINXUN,NIHUI 9,KN,WLTOYS,FEILUN 10,SymaX,SYMAX,SYMAX5C -11,SLT,SLT_V1,SLT_V2,Q200 +11,SLT,SLT_V1,SLT_V2,Q200,MR100 12,CX10,GREEN,BLUE,DM007,---,J3015_1,J3015_2,MK33041 13,CG023,CG023,YD829 14,Bayang,Bayang,H8S3D,X16_AH,IRDRONE From 27dc02fdec464c703acb5a034d1cdc7424bd8d39 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Mon, 10 Sep 2018 08:11:56 +0200 Subject: [PATCH 030/111] SLT sub protocol Q100 CH9 FMODE CH10 FLIP CH13 Gyro calib --- Multiprotocol/Multi.txt | 2 +- Multiprotocol/Multiprotocol.h | 12 +++++++----- Multiprotocol/SLT_nrf24l01.ino | 16 ++++++++-------- Multiprotocol/_Config.h | 1 + 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/Multiprotocol/Multi.txt b/Multiprotocol/Multi.txt index 3f10f69..f6ae1fe 100644 --- a/Multiprotocol/Multi.txt +++ b/Multiprotocol/Multi.txt @@ -8,7 +8,7 @@ 8,YD717,YD717,SKYWLKR,SYMAX4,XINXUN,NIHUI 9,KN,WLTOYS,FEILUN 10,SymaX,SYMAX,SYMAX5C -11,SLT,SLT_V1,SLT_V2,Q200,MR100 +11,SLT,SLT_V1,SLT_V2,Q100,Q200,MR100 12,CX10,GREEN,BLUE,DM007,---,J3015_1,J3015_2,MK33041 13,CG023,CG023,YD829 14,Bayang,Bayang,H8S3D,X16_AH,IRDRONE diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 015eb0a..f3261ea 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 0 -#define VERSION_PATCH_LEVEL 44 +#define VERSION_PATCH_LEVEL 45 //****************** // Protocols @@ -126,8 +126,9 @@ enum SLT { SLT_V1 = 0, SLT_V2 = 1, - Q200 = 2, - MR100 = 3, + Q100 = 2, + Q200 = 3, + MR100 = 4, }; enum CX10 { @@ -703,8 +704,9 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- sub_protocol==SLT SLT_V1 0 SLT_V2 1 - Q200 2 - MR100 3 + Q100 2 + Q200 3 + MR100 4 Power value => 0x80 0=High/1=Low Stream[3] = option_protocol; diff --git a/Multiprotocol/SLT_nrf24l01.ino b/Multiprotocol/SLT_nrf24l01.ino index 396f02b..7cacbc1 100644 --- a/Multiprotocol/SLT_nrf24l01.ino +++ b/Multiprotocol/SLT_nrf24l01.ino @@ -35,7 +35,7 @@ enum{ }; enum{ - // flags going to packet[6] (MR100) + // flags going to packet[6] (MR100 & Q100) FLAG_MR100_FMODE = 0x20, FLAG_MR100_FLIP = 0x04, FLAG_MR100_VIDEO = 0x02, @@ -156,19 +156,19 @@ static void __attribute__((unused)) SLT_build_packet() |GET_FLAG(CH10_SW, FLAG_Q200_FLIP) |GET_FLAG(CH11_SW, FLAG_Q200_VIDON) |GET_FLAG(CH12_SW, FLAG_Q200_VIDOFF); - if(sub_protocol==MR100) + else if(sub_protocol==MR100 || sub_protocol==Q100) packet[6] = GET_FLAG(CH9_SW , FLAG_MR100_FMODE) |GET_FLAG(CH10_SW, FLAG_MR100_FLIP) - |GET_FLAG(CH11_SW, FLAG_MR100_VIDEO) - |GET_FLAG(CH12_SW, FLAG_MR100_PICTURE); + |GET_FLAG(CH11_SW, FLAG_MR100_VIDEO) // Does not exist on the Q100 but... + |GET_FLAG(CH12_SW, FLAG_MR100_PICTURE); // Does not exist on the Q100 but... packet[7]=convert_channel_8b(CH7); packet[8]=convert_channel_8b(CH8); - packet[9]=0xAA; //normal mode for Q200, unknown for V2 - packet[10]=0x00; //normal mode for Q200, unknown for V2 - if(sub_protocol==Q200 && CH13_SW) + packet[9]=0xAA; //normal mode for Q100/Q200, unknown for V2/MR100 + packet[10]=0x00; //normal mode for Q100/Q200, unknown for V2/MR100 + if((sub_protocol==Q100 || sub_protocol==Q200) && CH13_SW) {//Calibrate packet[9]=0x77; //enter calibration - if(calib_counter>=20 && calib_counter<=23) // 3 packets + if(calib_counter>=20 && calib_counter<=25) // 7 packets for Q100 / 3 packets for Q200 packet[10]=0x20; //launch calibration calib_counter++; if(calib_counter>250) calib_counter=250; diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 28d546c..75f6e3c 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -565,6 +565,7 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= { PROTO_SLT SLT_V1 SLT_V2 + Q100 Q200 MR100 */ From 601116bd595a883e8b8e247df94733dfb942a3e8 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 10 Sep 2018 08:34:30 +0200 Subject: [PATCH 031/111] SLT sub protocols Q100/Q200/MR100 --- Protocols_Details.md | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index a39c1a3..0cc9f04 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -838,19 +838,43 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- A|E|T|R|CH5|CH6|CH7|CH8 -### Sub_protocol Q200 - *2* +### Sub_protocol Q100 - *2* +Models: Dromida Ominus UAV + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13 +---|---|---|---|---|---|---|---|---|---|---|---|--- +A|E|T|R|RATES|-|CH7|CH8|MODE|FLIP|-|-|CALIB + +RATES takes any value between +50..-50%: +50%=min rates, 0%=mid rates (stock setting), -50%=max rates + +CH7 and CH8 have no visible effect + +CALIB: -100% normal mode, +100% gyro calibration + +### Sub_protocol Q200 - *3* Models: Ominus Quadcopter FPV, the Nine Eagles - FENG FPV and may be others CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13 ---|---|---|---|---|---|---|---|---|---|---|---|--- A|E|T|R|RATES|-|CH7|CH8|MODE|FLIP|VID_ON|VID_OFF|CALIB -RATES: +50%=min rates, 0%=mid rates (stock setting), -50%=max rates +RATES takes any value between +50..-50%: +50%=min rates, 0%=mid rates (stock setting), -50%=max rates -CH7 and CH8 have no effect on the Ominus +CH7 and CH8 have no visible effect CALIB: -100% normal mode, +100% gyro calibration +### Sub_protocol MR100 - *4* +Models: Vista UAV, FPV, FPV v2 + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 +---|---|---|---|---|---|---|---|---|---|---|--- +A|E|T|R|RATES|-|CH7|CH8|MODE|FLIP|VIDEO|PICTURE + +RATES takes any value between +50..-50%: +50%=min rates, 0%=mid rates (stock setting), -50%=max rates + +CH7 and CH8 have no visible effect + ## Symax - *10* Autobind protocol From 5fe1e9674e94763c709623eb33a975aba99b0106 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Mon, 10 Sep 2018 09:58:31 +0200 Subject: [PATCH 032/111] DSM functions and variables renamed --- Multiprotocol/DSM_cyrf6936.ino | 34 +++++++++++++++++----------------- Multiprotocol/Multiprotocol.h | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Multiprotocol/DSM_cyrf6936.ino b/Multiprotocol/DSM_cyrf6936.ino index 5586227..dfe0cc6 100644 --- a/Multiprotocol/DSM_cyrf6936.ino +++ b/Multiprotocol/DSM_cyrf6936.ino @@ -44,7 +44,7 @@ enum { uint8_t sop_col; uint8_t DSM_num_ch=0; uint8_t ch_map[14]; -const uint8_t PROGMEM ch_map_progmem[][14] = { +const uint8_t PROGMEM DSM_ch_map_progmem[][14] = { //22+11ms for 4..7 channels {1, 0, 2, 3, 0xff, 0xff, 0xff, 1, 0, 2, 3, 0xff, 0xff, 0xff}, //4ch - Guess {1, 0, 2, 3, 4, 0xff, 0xff, 1, 0, 2, 3, 4, 0xff, 0xff}, //5ch - Guess @@ -62,7 +62,7 @@ const uint8_t PROGMEM ch_map_progmem[][14] = { {1, 5, 2, 3, 4, 8, 9, 1, 5, 2, 3, 0, 7, 6 }, //10ch - DX18 }; -const uint8_t PROGMEM pncodes[5][8][8] = { +const uint8_t PROGMEM DSM_pncodes[5][8][8] = { /* Note these are in order transmitted (LSB 1st) */ { /* Row 0 */ /* Col 0 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8}, @@ -123,18 +123,18 @@ const uint8_t PROGMEM pncodes[5][8][8] = { }, }; -static void __attribute__((unused)) read_code(uint8_t *buf, uint8_t row, uint8_t col, uint8_t len) +static void __attribute__((unused)) DSM_read_code(uint8_t *buf, uint8_t row, uint8_t col, uint8_t len) { for(uint8_t i=0;i7 && DSM_num_ch<11 && (sub_protocol==DSM2_11 || sub_protocol==DSMX_11)) idx+=5; // In 11ms mode change index only for channels 8..10 for(uint8_t i=0;i<14;i++) - ch_map[i]=pgm_read_byte_near(&ch_map_progmem[idx][i]); + ch_map[i]=pgm_read_byte_near(&DSM_ch_map_progmem[idx][i]); } static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper) @@ -294,12 +294,12 @@ static void __attribute__((unused)) DSM_set_sop_data_crc() else CYRF_ConfigCRCSeed(~crc); //CH1 - uint8_t pn_row = get_pn_row(hopping_frequency[hopping_frequency_no]); + uint8_t pn_row = DSM_get_pn_row(hopping_frequency[hopping_frequency_no]); uint8_t code[16]; - read_code(code,pn_row,sop_col,8); // pn_row between 0 and 4, sop_col between 1 and 7 + DSM_read_code(code,pn_row,sop_col,8); // pn_row between 0 and 4, sop_col between 1 and 7 CYRF_ConfigSOPCode(code); - read_code(code,pn_row,7 - sop_col,8); // 7-sop_col between 0 and 6 - read_code(code+8,pn_row,7 - sop_col + 1,8); // 7-sop_col+1 between 1 and 7 + DSM_read_code(code,pn_row,7 - sop_col,8); // 7-sop_col between 0 and 6 + DSM_read_code(code+8,pn_row,7 - sop_col + 1,8); // 7-sop_col+1 between 1 and 7 CYRF_ConfigDataCode(code, 16); CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]); @@ -536,7 +536,7 @@ uint16_t initDsm() cyrfmfg_id[3]^=RX_num; //Calc sop_col sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07; - //Fix for OrangeRX using wrong pncodes by preventing access to "Col 8" + //Fix for OrangeRX using wrong DSM_pncodes by preventing access to "Col 8" if(sop_col==0) { cyrfmfg_id[rx_tx_addr[0]%3]^=0x01; //Change a bit so sop_col will be different from 0 diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index f3261ea..6d48c35 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 0 -#define VERSION_PATCH_LEVEL 45 +#define VERSION_PATCH_LEVEL 46 //****************** // Protocols From 09c6adaa952cf23bbff1dc0962132b3c9e01ef9e Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Mon, 10 Sep 2018 21:28:37 -0400 Subject: [PATCH 033/111] BUGS: fix --- Multiprotocol/A7105_SPI.ino | 10 ---------- Multiprotocol/Bugs_a7105.ino | 35 ++++++++++++++++++--------------- Multiprotocol/Multiprotocol.h | 2 +- Multiprotocol/Multiprotocol.ino | 1 - 4 files changed, 20 insertions(+), 28 deletions(-) diff --git a/Multiprotocol/A7105_SPI.ino b/Multiprotocol/A7105_SPI.ino index a678f80..6483886 100644 --- a/Multiprotocol/A7105_SPI.ino +++ b/Multiprotocol/A7105_SPI.ino @@ -289,17 +289,7 @@ void A7105_Init(void) #ifdef BUGS_A7105_INO if(protocol==PROTO_BUGS) - { - if(IS_BIND_DONE) - { // Read radio_id from EEPROM - radio_id=0; - uint8_t base_adr=BUGS_EEPROM_OFFSET+RX_num*4; - for(uint8_t i=0; i<4; i++) - radio_id|=eeprom_read_byte((EE_ADDR)(base_adr+i))<>i); // Save radio_id in EEPROM - BUGS_set_radio_data(1); - A7105_WriteID(radio_id); - BIND_DONE; + BUGS_set_radio_data(); phase = BUGS_DATA_1; packet_count = 0; hopping_frequency_no = 0; @@ -437,16 +445,11 @@ uint16_t ReadBUGS(void) uint16_t initBUGS(void) { + BUGS_set_radio_data(); if (IS_BIND_IN_PROGRESS) - { - BUGS_set_radio_data(0); phase = BUGS_BIND_1; - } else - { - BUGS_set_radio_data(1); phase = BUGS_DATA_1; - } A7105_Init(); diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 6d48c35..d496f39 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 0 -#define VERSION_PATCH_LEVEL 46 +#define VERSION_PATCH_LEVEL 47 //****************** // Protocols diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 5628373..4b1cc2d 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -110,7 +110,6 @@ uint16_t seed; uint16_t failsafe_count; uint16_t state; uint8_t len; -uint32_t radio_id; #if defined(FRSKYX_CC2500_INO) || defined(SFHSS_CC2500_INO) uint8_t calData[48]; From 8901310ed46d8a43d801210b35df7c21e1478866 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Tue, 11 Sep 2018 04:59:07 -0400 Subject: [PATCH 034/111] BUGS: fix? --- Multiprotocol/Bugs_a7105.ino | 4 ++-- Multiprotocol/Multiprotocol.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Multiprotocol/Bugs_a7105.ino b/Multiprotocol/Bugs_a7105.ino index 5b1c8ee..a7d1d30 100644 --- a/Multiprotocol/Bugs_a7105.ino +++ b/Multiprotocol/Bugs_a7105.ino @@ -290,7 +290,7 @@ static void __attribute__((unused))BUGS_set_radio_data() radio_id=0; uint8_t base_adr=BUGS_EEPROM_OFFSET+RX_num*4; for(uint8_t i=0; i<4; i++) - radio_id|=eeprom_read_byte((EE_ADDR)(base_adr+i))<>i); // Save radio_id in EEPROM + eeprom_write_byte((EE_ADDR)(base_adr+i),radio_id>>(i*8)); // Save radio_id in EEPROM BUGS_set_radio_data(); phase = BUGS_DATA_1; packet_count = 0; diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index d496f39..73b844a 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 0 -#define VERSION_PATCH_LEVEL 47 +#define VERSION_PATCH_LEVEL 48 //****************** // Protocols From b2194790eb56f339c79e14114ad642eccd8a5fef Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 11 Sep 2018 05:20:45 -0400 Subject: [PATCH 035/111] SLT changes --- Protocols_Details.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 0cc9f04..6023b41 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -845,20 +845,28 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13 ---|---|---|---|---|---|---|---|---|---|---|---|--- A|E|T|R|RATES|-|CH7|CH8|MODE|FLIP|-|-|CALIB -RATES takes any value between +50..-50%: +50%=min rates, 0%=mid rates (stock setting), -50%=max rates +RATES takes any value between -50..+50%: -50%=min rates, 0%=mid rates (stock setting), +50%=max rates CH7 and CH8 have no visible effect CALIB: -100% normal mode, +100% gyro calibration ### Sub_protocol Q200 - *3* -Models: Ominus Quadcopter FPV, the Nine Eagles - FENG FPV and may be others +Model: Ominus Quadcopter FPV, the Nine Eagles - FENG FPV and may be others + +Omnius channels mapping: CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13 ---|---|---|---|---|---|---|---|---|---|---|---|--- A|E|T|R|RATES|-|CH7|CH8|MODE|FLIP|VID_ON|VID_OFF|CALIB -RATES takes any value between +50..-50%: +50%=min rates, 0%=mid rates (stock setting), -50%=max rates +FENG FPV: channels mapping: + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13 +---|---|---|---|---|---|---|---|---|---|---|---|--- +A|E|T|R|RATES|-|CH7|CH8|FLIP|MODE|VID_ON|VID_OFF|CALIB + +RATES takes any value between -50..+50%: -50%=min rates, 0%=mid rates (stock setting), +50%=max rates CH7 and CH8 have no visible effect @@ -871,7 +879,7 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 ---|---|---|---|---|---|---|---|---|---|---|--- A|E|T|R|RATES|-|CH7|CH8|MODE|FLIP|VIDEO|PICTURE -RATES takes any value between +50..-50%: +50%=min rates, 0%=mid rates (stock setting), -50%=max rates +RATES takes any value between -50..+50%: -50%=min rates, 0%=mid rates (stock setting), +50%=max rates CH7 and CH8 have no visible effect From b1fb3a547013463ff605fe60fec724f8a55a9686 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 11 Sep 2018 05:24:21 -0400 Subject: [PATCH 036/111] Update Protocols_Details.md --- Protocols_Details.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index 6023b41..32fb804 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -849,6 +849,8 @@ RATES takes any value between -50..+50%: -50%=min rates, 0%=mid rates (stock set CH7 and CH8 have no visible effect +MODE: -100% level, +100% acro + CALIB: -100% normal mode, +100% gyro calibration ### Sub_protocol Q200 - *3* @@ -870,6 +872,8 @@ RATES takes any value between -50..+50%: -50%=min rates, 0%=mid rates (stock set CH7 and CH8 have no visible effect +MODE: -100% level, +100% acro + CALIB: -100% normal mode, +100% gyro calibration ### Sub_protocol MR100 - *4* @@ -883,6 +887,8 @@ RATES takes any value between -50..+50%: -50%=min rates, 0%=mid rates (stock set CH7 and CH8 have no visible effect +MODE: -100% level, +100% acro + ## Symax - *10* Autobind protocol From ab9525c50753210b1b3aa74c7a635d8336882c26 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 11 Sep 2018 06:06:34 -0400 Subject: [PATCH 037/111] Update Compiling_STM32.md --- docs/Compiling_STM32.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/Compiling_STM32.md b/docs/Compiling_STM32.md index 1e18af6..f87045e 100644 --- a/docs/Compiling_STM32.md +++ b/docs/Compiling_STM32.md @@ -60,6 +60,7 @@ The 4-pin header needs to be soldered onto the board as indicated by the red rec ### Configure the Arduino IDE 1. Under **Tools -> Board** select **Multi 4-in-1 (STM32FC103)** +1. Under **Tools -> Upload method** select **Auto Detect (USB or Serial)** <- more details on this subject later on 1. Under **Tools -> Programmer** select **stm32flash (FTDI)** ## Configure the firmware @@ -67,7 +68,7 @@ The STM32 module has more than enough flash space for all the available protocol You can still disable protocols if you wish, and you may also enable or disable other optional Multiprotocol features. ## Verify the firmware -To check that the program will compile correctly and fit in the Atmega click **Sketch -> Verify/Compile**, or press **Ctrl+R**. +To check that the program will compile correctly and fit in the STM32 click **Sketch -> Verify/Compile**, or press **Ctrl+R**. If there are errors, carefully read it, go to the line number indicated and correct your typo. From e5d9471b330f32893fc02e7aa98cb564459081b7 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 11 Sep 2018 09:33:54 -0400 Subject: [PATCH 038/111] Update Protocols_Details.md --- Protocols_Details.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index 32fb804..876bbe6 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -851,6 +851,8 @@ CH7 and CH8 have no visible effect MODE: -100% level, +100% acro +FLIP: sets model into flip mode for approx 5 seconds at each throw of switch (rear red LED goes out while active) -100%..+100% or +100%..-100% + CALIB: -100% normal mode, +100% gyro calibration ### Sub_protocol Q200 - *3* @@ -874,6 +876,8 @@ CH7 and CH8 have no visible effect MODE: -100% level, +100% acro +FLIP: sets model into flip mode for approx 5 seconds at each throw of switch (rear red LED goes out while active) -100%..+100% or +100%..-100% + CALIB: -100% normal mode, +100% gyro calibration ### Sub_protocol MR100 - *4* @@ -887,6 +891,8 @@ RATES takes any value between -50..+50%: -50%=min rates, 0%=mid rates (stock set CH7 and CH8 have no visible effect +FLIP: sets model into flip mode for approx 5 seconds at each throw of switch (rear red LED goes out while active) -100%..+100% or +100%..-100% + MODE: -100% level, +100% acro ## Symax - *10* From f4691d08cca870a7cf2c9a13694343e7fbfffc85 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Tue, 11 Sep 2018 15:51:28 -0400 Subject: [PATCH 039/111] SLT Q100/Q200/MRT100: reverse throttle --- Multiprotocol/Multiprotocol.h | 2 +- Multiprotocol/SLT_nrf24l01.ino | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 73b844a..d0764f9 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 0 -#define VERSION_PATCH_LEVEL 48 +#define VERSION_PATCH_LEVEL 49 //****************** // Protocols diff --git a/Multiprotocol/SLT_nrf24l01.ino b/Multiprotocol/SLT_nrf24l01.ino index 7cacbc1..75d855f 100644 --- a/Multiprotocol/SLT_nrf24l01.ino +++ b/Multiprotocol/SLT_nrf24l01.ino @@ -141,6 +141,8 @@ static void __attribute__((unused)) SLT_build_packet() for (uint8_t i = 0; i < 4; ++i) { uint16_t v = convert_channel_10b(CH_AETR[i]); + if(sub_protocol>SLT_V2 && CH_AETR[i]==THROTTLE) + v=1023-v; // reverse throttle channel for Q100/Q200/MR100 protocols packet[i] = v; e = (e >> 2) | (uint8_t) ((v >> 2) & 0xC0); } From 3b3a3c275cfdeed24a393a20a2686da789383fca Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 12 Sep 2018 06:45:09 -0400 Subject: [PATCH 040/111] Update Protocols_Details.md --- Protocols_Details.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 876bbe6..4373077 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -856,9 +856,9 @@ FLIP: sets model into flip mode for approx 5 seconds at each throw of switch (re CALIB: -100% normal mode, +100% gyro calibration ### Sub_protocol Q200 - *3* -Model: Ominus Quadcopter FPV, the Nine Eagles - FENG FPV and may be others +Model: Dromida Ominus Quadcopter FPV, the Nine Eagles - FENG FPV and may be others -Omnius channels mapping: +Dromida Ominus FPV channels mapping: CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13 ---|---|---|---|---|---|---|---|---|---|---|---|--- From c153d236f2b4847abdfa92c2bf242880252b1209 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Wed, 12 Sep 2018 06:49:40 -0400 Subject: [PATCH 041/111] SLT Q100/Q200/MR100: reverse elevator --- Multiprotocol/Multiprotocol.h | 4 ++-- Multiprotocol/SLT_nrf24l01.ino | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index d0764f9..938ce86 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -18,8 +18,8 @@ //****************** #define VERSION_MAJOR 1 #define VERSION_MINOR 2 -#define VERSION_REVISION 0 -#define VERSION_PATCH_LEVEL 49 +#define VERSION_REVISION 1 +#define VERSION_PATCH_LEVEL 0 //****************** // Protocols diff --git a/Multiprotocol/SLT_nrf24l01.ino b/Multiprotocol/SLT_nrf24l01.ino index 75d855f..3ce909f 100644 --- a/Multiprotocol/SLT_nrf24l01.ino +++ b/Multiprotocol/SLT_nrf24l01.ino @@ -141,8 +141,8 @@ static void __attribute__((unused)) SLT_build_packet() for (uint8_t i = 0; i < 4; ++i) { uint16_t v = convert_channel_10b(CH_AETR[i]); - if(sub_protocol>SLT_V2 && CH_AETR[i]==THROTTLE) - v=1023-v; // reverse throttle channel for Q100/Q200/MR100 protocols + if(sub_protocol>SLT_V2 && (CH_AETR[i]==THROTTLE || CH_AETR[i]==ELEVATOR) ) + v=1023-v; // reverse throttle and elevator channels for Q100/Q200/MR100 protocols packet[i] = v; e = (e >> 2) | (uint8_t) ((v >> 2) & 0xC0); } From 63fb1b1f36081daef24736eb26f5d18e0fcafe49 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Wed, 12 Sep 2018 14:24:30 -0400 Subject: [PATCH 042/111] Removed old SLT sub protocols --- Multiprotocol/Multiprotocol.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 938ce86..3ca1e6e 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -626,9 +626,6 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- Q222 0 Q242 1 Q282 2 - sub_protocol==SLT - SLT 0 - VISTA 1 sub_protocol==CG023 CG023 0 YD829 1 From 058e09c413eaa40d7c1820b3761ce7f63dce5d96 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Thu, 13 Sep 2018 17:25:49 -0400 Subject: [PATCH 043/111] _config.h descriptions update --- Multiprotocol/_Config.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 75f6e3c..38a2bf7 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -53,20 +53,19 @@ //For more throw, 1024..1976us @100% and 904..2096us @125%, remove the "//" on the line below. Be aware that too much throw can damage some UMX servos. To achieve standard throw in this mode use a channel weight of 84%. //#define DSM_MAX_THROW -/*************************/ -/*** BIND FROM CHANNEL ***/ -/*************************/ + +/*****************/ +/*** AUTO BIND ***/ // Also referred as "Bind on powerup" +/*****************/ //Bind from channel enables you to bind when a specified channel is going from low to high. This feature is only active // if you specify AUTOBIND in PPM mode or set AutoBind to YES for serial mode. It also requires that the throttle channel is low. - //Comment to globaly disable the bind feature from a channel. #define ENABLE_BIND_CH - //Set the channel number used for bind. Default is 16. #define BIND_CH 16 -//Comment to disable the wait for bind feature. This feature will not activate the selected -// protocol unless a bind is requested using bind from channel or the GUI "Bind" button. +//Comment to disable the wait for bind feature. If Autobind is enabled in the model config, this feature will not activate +// the selected protocol unless a bind is requested using bind from channel or the GUI "Bind" button. //The goal is to prevent binding other people's model when powering up the TX, changing model or scanning through protocols. #define WAIT_FOR_BIND @@ -75,7 +74,7 @@ /*** RF CHIPS ***/ /****************/ //There are 4 RF components supported. If one of them is not installed you must comment it using "//". -//If a chip is not installed all associated protocols are disabled. +//If a chip is not installed all associated protocols are automatically disabled. //4-in-1 modules have all RF chips installed //!!!If a RF chip is present it MUST be marked as installed!!! or weird things will happen you have been warned. #define A7105_INSTALLED @@ -209,7 +208,7 @@ //Value between -125% and +125%. Default -100. #define FAILSAFE_THROTTLE_LOW -100 -//The radio using serial protocol can set failsafe data (ersky9x only for now). +//The radio using serial protocol can set failsafe data. // Two options are available: // a. replace the default failsafe data with serial failsafe data when they are received. // b. wait for the radio to provide failsafe before sending it. Enable advanced settings like "FAILSAFE NOT SET" or "FAILSAFE RX". @@ -249,7 +248,7 @@ #define AFHDS2A_HUB_TELEMETRY // Use FrSkyD Hub format to send basic telemetry to TX like er9x #define HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX #define BAYANG_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX -#define BUGS_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX +#define BUGS_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX #define HUBSAN_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX #define CABELL_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX #define HITEC_HUB_TELEMETRY // Use FrSkyD Hub format to send basic telemetry to the radios which can decode it like er9x, ersky9x and OpenTX @@ -258,6 +257,7 @@ //SPORT_POLLING is an implementation of the same polling routine as XJT module for sport telemetry bidirectional communication. //This is useful for passing sport control frames from TX to RX(ex: changing Betaflight PID or VTX channels on the fly using LUA scripts with OpentX). //Using this feature requires to uncomment INVERT_TELEMETRY as this TX output on telemetry pin only inverted signal. +//!!!! This is a work in progress!!! Do not enable unless you want to test and report //#define SPORT_POLLING @@ -266,7 +266,7 @@ /****************************/ //In this section you can configure the serial mode. //The serial mode enables full editing of all the parameters in the GUI of the radio. It is enabled by placing the rotary switch on position 0. -//This is available natively for ER9X and ERSKY9X. It is available for OpenTX on Taranis with a special version. +//This is available natively for ER9X, ERSKY9X and OpenTX. //If you do not plan to use the Serial mode comment this line using "//" to save Flash space #define ENABLE_SERIAL From 5cf8d8d2634b08af6ff7c32f106b09bb4c636772 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Sat, 15 Sep 2018 08:02:05 -0400 Subject: [PATCH 044/111] ESKY protocol code review --- Multiprotocol/ESky_nrf24l01.ino | 20 +++++--------------- Multiprotocol/Multiprotocol.h | 2 +- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/Multiprotocol/ESky_nrf24l01.ino b/Multiprotocol/ESky_nrf24l01.ino index 9a72c94..82cbda2 100644 --- a/Multiprotocol/ESky_nrf24l01.ino +++ b/Multiprotocol/ESky_nrf24l01.ino @@ -30,7 +30,7 @@ static void __attribute__((unused)) ESKY_set_data_address() NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 4); } -static void __attribute__((unused)) ESKY_init(uint8_t bind) +static void __attribute__((unused)) ESKY_init() { NRF24L01_Initialize(); @@ -38,7 +38,7 @@ static void __attribute__((unused)) ESKY_init(uint8_t bind) NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO)); NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgement NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 - if (bind) + if (IS_BIND_IN_PROGRESS) { NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // 3-byte RX/TX address for bind packets NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\x00\x00\x00", 3); @@ -63,7 +63,6 @@ static void __attribute__((unused)) ESKY_init(uint8_t bind) static void __attribute__((unused)) ESKY_init2() { NRF24L01_FlushTx(); - packet_sent = 0; hopping_frequency_no = 0; uint16_t channel_ord = rx_tx_addr[0] % 74; hopping_frequency[12] = 10 + (uint8_t)channel_ord; //channel_code @@ -116,14 +115,12 @@ static void __attribute__((unused)) ESKY_send_packet(uint8_t bind) // Each data packet is repeated 3 times on one channel, and 3 times on another channel // For arithmetic simplicity, channels are repeated in rf_channels array if (hopping_frequency_no == 0) - { for (uint8_t i = 0; i < 6; i++) { uint16_t val=convert_channel_ppm(CH_AETR[i]); packet[i*2] = val>>8; //high byte of servo timing(1000-2000us) packet[i*2+1] = val&0xFF; //low byte of servo timing(1000-2000us) } - } rf_ch = hopping_frequency[hopping_frequency_no]; packet[12] = hopping_frequency[hopping_frequency_no+6]; // end_bytes hopping_frequency_no++; @@ -132,23 +129,15 @@ static void __attribute__((unused)) ESKY_send_packet(uint8_t bind) NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch); NRF24L01_FlushTx(); NRF24L01_WritePayload(packet, ESKY_PAYLOAD_SIZE); - packet_sent = 1; - if (! rf_ch_num) - NRF24L01_SetPower(); //Keep transmit power updated + NRF24L01_SetPower(); //Keep transmit power updated } uint16_t ESKY_callback() { if(IS_BIND_DONE) - { - if (packet_sent && NRF24L01_packet_ack() != PKT_ACKED) - return ESKY_PACKET_CHKTIME; ESKY_send_packet(0); - } else { - if (packet_sent && NRF24L01_packet_ack() != PKT_ACKED) - return ESKY_PACKET_CHKTIME; ESKY_send_packet(1); if (--bind_counter == 0) { @@ -162,8 +151,9 @@ uint16_t ESKY_callback() uint16_t initESKY(void) { bind_counter = ESKY_BIND_COUNT; + rx_tx_addr[2] = rx_tx_addr[3]; // Model match rx_tx_addr[3] = 0xBB; - ESKY_init(IS_BIND_IN_PROGRESS); + ESKY_init(); ESKY_init2(); return 50000; } diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 3ca1e6e..e96fc13 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 1 -#define VERSION_PATCH_LEVEL 0 +#define VERSION_PATCH_LEVEL 1 //****************** // Protocols From 75ba6401a4afade1c402a761cbd81fdb6a9c7462 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 19 Sep 2018 17:19:58 -0400 Subject: [PATCH 045/111] Hubsan typo --- Protocols_Details.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 4373077..4b7a1a6 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -135,7 +135,7 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- A|E|T|R|RTH|LIGHT|STAB|VIDEO -### Sub_protocol H501 - *1* +### Sub_protocol H501 - *2* Models: Hubsan H501S, H122D, H123D CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13 From 97dd90a71826b1ee34e378692e9ed07fd9649a0a Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 24 Sep 2018 10:30:26 +0200 Subject: [PATCH 046/111] OpenLRSng --- Protocols_Details.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index 4b7a1a6..767dda6 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -942,3 +942,8 @@ A|E|T|R|FLIP|LIGHT|PICTURE|VIDEO|HEADLESS ### Sub_protocol XINXUN - *3* ### Sub_protocol NIHUI - *4* Same channels assignement as above. + +# OpenLRS module + +## OpenLRS - *27* +This is a reservation for OpenLRSng which is using Multi's serial protocol for their modules: https://openlrsng.org/. On the Multi side there is no protocol affected on 27 so it's just ignored. From b40e7d6e970275e1c2309d665340e8effaac1a82 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Thu, 11 Oct 2018 17:58:07 +0200 Subject: [PATCH 047/111] Bugs: fixed telemetry disable compilation error --- Multiprotocol/Bugs_a7105.ino | 18 ++++++++++-------- Multiprotocol/CX10_nrf24l01.ino | 2 +- Multiprotocol/Multiprotocol.h | 3 ++- Multiprotocol/Multiprotocol.ino | 6 ++++++ 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Multiprotocol/Bugs_a7105.ino b/Multiprotocol/Bugs_a7105.ino index a7d1d30..60098fe 100644 --- a/Multiprotocol/Bugs_a7105.ino +++ b/Multiprotocol/Bugs_a7105.ino @@ -427,14 +427,16 @@ uint16_t ReadBUGS(void) if (!(mode & 0x01)) { A7105_ReadData(16); - v_lipo1=packet[10] == 0xff ? 0xff : 0x00; // Voltage in this case is only an alert on level good or bad. - RX_RSSI=packet[3]; - // Read TX RSSI - int16_t temp=256-(A7105_ReadReg(A7105_1D_RSSI_THOLD)*8)/5; // Value from A7105 is between 8 for maximum signal strength to 160 or less - if(temp<0) temp=0; - else if(temp>255) temp=255; - TX_RSSI=temp; - telemetry_link=1; + #if defined(BUGS_HUB_TELEMETRY) + v_lipo1=packet[10] == 0xff ? 0xff : 0x00; // Voltage in this case is only an alert on level good or bad. + RX_RSSI=packet[3]; + // Read TX RSSI + int16_t temp=256-(A7105_ReadReg(A7105_1D_RSSI_THOLD)*8)/5; // Value from A7105 is between 8 for maximum signal strength to 160 or less + if(temp<0) temp=0; + else if(temp>255) temp=255; + TX_RSSI=temp; + telemetry_link=1; + #endif } phase = BUGS_DATA_1; packet_period = BUGS_DELAY_POST_RX; diff --git a/Multiprotocol/CX10_nrf24l01.ino b/Multiprotocol/CX10_nrf24l01.ino index 328d04b..4f98d44 100644 --- a/Multiprotocol/CX10_nrf24l01.ino +++ b/Multiprotocol/CX10_nrf24l01.ino @@ -259,6 +259,7 @@ static void __attribute__((unused)) CX10_initialize_txid() uint16_t initCX10(void) { + BIND_IN_PROGRESS; // autobind protocol if(sub_protocol==CX10_BLUE) { packet_length = CX10A_PACKET_SIZE; @@ -282,7 +283,6 @@ uint16_t initCX10(void) } CX10_initialize_txid(); CX10_init(); - BIND_IN_PROGRESS; // autobind protocol return CX10_INITIAL_WAIT+packet_period; } diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index e96fc13..727abc2 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 1 -#define VERSION_PATCH_LEVEL 1 +#define VERSION_PATCH_LEVEL 2 //****************** // Protocols @@ -68,6 +68,7 @@ enum PROTOCOLS PROTO_HITEC = 39, // =>CC2500 PROTO_WFLY = 40, // =>CYRF6936 PROTO_BUGS = 41, // =>A7105 + PROTO_TEST = 63, // =>NRF24L01 }; enum Flysky diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 4b1cc2d..1234f5a 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -1187,6 +1187,12 @@ static void protocol_init() remote_callback = cflie_callback; break; #endif + #if defined(TEST_NRF24L01_INO) + case PROTO_TEST: + next_callback=initTest(); + remote_callback = Test_callback; + break; + #endif #endif } } From 567d26a3851ecbded2d5108244ee40865a416485 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 17 Oct 2018 13:21:22 +0200 Subject: [PATCH 048/111] New protocol BUGSMINI --- Protocols_Details.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 767dda6..e7b3b44 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -149,8 +149,6 @@ H123D: FMODES -> -100%=Sport mode 1,0%=Sport mode 2,+100%=Acro ## BUGS - *41* Models: MJX Bugs 3, 6 and 8 -Autobind protocol - Telemetry enabled for RX & TX RSSI, Battery voltage good/bad **RX_Num is used to give a number to a given model. You must use a different RX_Num per MJX Bugs. A maximum of 16 Bugs are supported.** @@ -497,6 +495,19 @@ CH12|CH13 ----|---- TAKE_OFF|EMG_STOP +## BUGSMINI - *42* +Models: MJX Bugs 3 Mini and 3H + +Telemetry enabled for RX RSSI, Battery voltage good/warning/bad + +**RX_Num is used to give a number to a given model. You must use a different RX_Num per MJX Bugs Mini. A maximum of 16 Bugs Mini are supported.** + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10 +---|---|---|---|---|---|---|---|---|--- +A|E|T|R|ARM|ANGLE|FLIP|PICTURE|VIDEO|LED + +ANGLE: angle is +100%, acro is -100% + ## Cabell - *34* Homegrown protocol with variable number of channels (4-16) and telemetry (RSSI, V1, V2). From 10788976b6adfc1b75a067e41222132155c5f46d Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Wed, 17 Oct 2018 13:23:27 +0200 Subject: [PATCH 049/111] New protocol BUGSMINI Models: MJX Bugs 3 Mini and 3H Protocol BUGSMINI = 42 No sub_protocol Telemetry = RX RSSI and battery voltage good/warning/bad RX_Num is used to give a number to a given model. You must use a different RX_Num per MJX Bugs Mini. A maximum of 16 Bugs Mini are supported. Channels: ARM CH5 ANGLE CH6 FLIP CH7 PICTURE CH8 VIDEO CH9 LED CH10 --- Multiprotocol/BUGSMINI_nrf24l01.ino | 364 ++++++++++++++++++++++++++++ Multiprotocol/Multi.txt | 2 + Multiprotocol/Multiprotocol.h | 11 +- Multiprotocol/Multiprotocol.ino | 10 +- Multiprotocol/Telemetry.ino | 4 +- Multiprotocol/Validate.h | 4 + Multiprotocol/_Config.h | 3 + 7 files changed, 390 insertions(+), 8 deletions(-) create mode 100644 Multiprotocol/BUGSMINI_nrf24l01.ino diff --git a/Multiprotocol/BUGSMINI_nrf24l01.ino b/Multiprotocol/BUGSMINI_nrf24l01.ino new file mode 100644 index 0000000..170ef46 --- /dev/null +++ b/Multiprotocol/BUGSMINI_nrf24l01.ino @@ -0,0 +1,364 @@ +/* + 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 . + */ +// compatible with MJX Bugs 3 Mini and Bugs 3H + +#if defined(BUGSMINI_NRF24L01_INO) + +#include "iface_nrf24l01.h" + +#define BUGSMINI_INITIAL_WAIT 500 +#define BUGSMINI_PACKET_INTERVAL 6840 +#define BUGSMINI_WRITE_WAIT 2000 +#define BUGSMINI_TX_PAYLOAD_SIZE 24 +#define BUGSMINI_RX_PAYLOAD_SIZE 16 +#define BUGSMINI_NUM_RF_CHANNELS 15 +#define BUGSMINI_ADDRESS_SIZE 5 + +static uint8_t BUGSMINI_armed, BUGSMINI_arm_flags; +static uint8_t BUGSMINI_arm_channel_previous; +static uint8_t BUGSMINI_txid[3]; +static uint8_t BUGSMINI_txhash; + +enum { + BUGSMINI_BIND1, + BUGSMINI_BIND2, + BUGSMINI_DATA1, + BUGSMINI_DATA2 +}; + +#define BUGSMINI_CH_SW_ARM CH5_SW +#define BUGSMINI_CH_SW_ANGLE CH6_SW +#define BUGSMINI_CH_SW_FLIP CH7_SW +#define BUGSMINI_CH_SW_PICTURE CH8_SW +#define BUGSMINI_CH_SW_VIDEO CH9_SW +#define BUGSMINI_CH_SW_LED CH10_SW + +// flags packet[12] +#define BUGSMINI_FLAG_FLIP 0x08 // automatic flip +#define BUGSMINI_FLAG_MODE 0x04 // low/high speed select (set is high speed) +#define BUGSMINI_FLAG_VIDEO 0x02 // toggle video +#define BUGSMINI_FLAG_PICTURE 0x01 // toggle picture + +// flags packet[13] +#define BUGSMINI_FLAG_LED 0x80 // enable LEDs +#define BUGSMINI_FLAG_ARM 0x40 // arm (toggle to turn on motors) +#define BUGSMINI_FLAG_DISARM 0x20 // disarm (toggle to turn off motors) +#define BUGSMINI_FLAG_ANGLE 0x02 // angle/acro mode (set is angle mode) + +static void __attribute__((unused)) BUGSMINI_init() +{ + NRF24L01_Initialize(); + NRF24L01_SetTxRxMode(TX_EN); + NRF24L01_FlushTx(); + NRF24L01_FlushRx(); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit + NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only + NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, BUGSMINI_RX_PAYLOAD_SIZE); // bytes of data payload for rx pipe 1 + NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, 0x07); + NRF24L01_SetBitrate(NRF24L01_BR_1M); + NRF24L01_SetPower(); + NRF24L01_Activate(0x73); // Activate feature register + NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes + NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x00); // Set feature bits on +} + +static void __attribute__((unused)) BUGSMINI_check_arming() +{ + uint8_t arm_channel = BUGSMINI_CH_SW_ARM; + + if (arm_channel != BUGSMINI_arm_channel_previous) + { + BUGSMINI_arm_channel_previous = arm_channel; + if (arm_channel) + { + BUGSMINI_armed = 1; + BUGSMINI_arm_flags ^= BUGSMINI_FLAG_ARM; + } + else + { + BUGSMINI_armed = 0; + BUGSMINI_arm_flags ^= BUGSMINI_FLAG_DISARM; + } + } +} + +static void __attribute__((unused)) BUGSMINI_send_packet(uint8_t bind) +{ + BUGSMINI_check_arming(); // sets globals arm_flags and armed + + uint16_t aileron = convert_channel_16b_limit(AILERON,500,0); + uint16_t elevator = convert_channel_16b_limit(ELEVATOR,0,500); + uint16_t throttle = BUGSMINI_armed ? convert_channel_16b_limit(THROTTLE,0,500) : 0; + uint16_t rudder = convert_channel_16b_limit(RUDDER,500,0); + + packet[1] = BUGSMINI_txid[0]; + packet[2] = BUGSMINI_txid[1]; + packet[3] = BUGSMINI_txid[2]; + if(bind) + { + packet[4] = 0x00; + packet[5] = 0x7d; + packet[6] = 0x7d; + packet[7] = 0x7d; + packet[8] = 0x20; + packet[9] = 0x20; + packet[10]= 0x20; + packet[11]= 0x40; + packet[12]^= 0x40; // alternating freq hopping flag + packet[13]= 0x60; + packet[14]= 0x00; + packet[15]= 0x00; + } + else + { + packet[4] = throttle >> 1; + packet[5] = rudder >> 1; + packet[6] = elevator >> 1; + packet[7] = aileron >> 1; + packet[8] = 0x20 | (aileron << 7); + packet[9] = 0x20 | (elevator << 7); + packet[10]= 0x20 | (rudder << 7); + packet[11]= 0x40 | (throttle << 7); + packet[12]= 0x80 | (packet[12] ^ 0x40) // bugs 3 H doesn't have 0x80 ? + | BUGSMINI_FLAG_MODE + | GET_FLAG(BUGSMINI_CH_SW_PICTURE, BUGSMINI_FLAG_PICTURE) + | GET_FLAG(BUGSMINI_CH_SW_VIDEO, BUGSMINI_FLAG_VIDEO); + if(BUGSMINI_armed) + packet[12] |= GET_FLAG(BUGSMINI_CH_SW_FLIP, BUGSMINI_FLAG_FLIP); + packet[13] = BUGSMINI_arm_flags + | GET_FLAG(BUGSMINI_CH_SW_LED, BUGSMINI_FLAG_LED) + | GET_FLAG(BUGSMINI_CH_SW_ANGLE, BUGSMINI_FLAG_ANGLE); + + packet[14] = 0; + packet[15] = 0; // 0x53 on bugs 3 H ? + } + uint8_t checksum = 0x6d; + for(uint8_t i=1; i < BUGSMINI_TX_PAYLOAD_SIZE; i++) + checksum ^= packet[i]; + packet[0] = checksum; + + if(!(packet[12]&0x40)) + { + hopping_frequency_no++; + if(hopping_frequency_no >= BUGSMINI_NUM_RF_CHANNELS) + hopping_frequency_no = 0; + NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? hopping_frequency[hopping_frequency_no+BUGSMINI_NUM_RF_CHANNELS] : hopping_frequency[hopping_frequency_no]); + } + + // Power on, TX mode, 2byte CRC + XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP)); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); + NRF24L01_FlushTx(); + XN297_WritePayload(packet, BUGSMINI_TX_PAYLOAD_SIZE); + NRF24L01_SetPower(); +} + +// compute final address for the rxid received during bind +// thanks to Pascal for the function! +const uint8_t PROGMEM BUGSMINI_end []= { + 0x2d,0x9e ,0x95,0xa4 ,0x9c,0x5c ,0xb4,0xa6 ,0xa9,0xce ,0x56,0x2b ,0x3e,0x73 ,0xb8,0x95 ,0x6a,0x82, + 0x94,0x37 ,0x3d,0x5a ,0x4b,0xb2 ,0x69,0x49 ,0xc2,0x24 ,0x6b,0x3d ,0x23,0xc6 ,0x9e,0xa3 ,0xa4,0x98, + 0x5c,0x9e ,0xa6,0x52 ,0xce,0x76 ,0x2b,0x4b ,0x73,0x3a }; +static void __attribute__((unused)) BUGSMINI_make_address() +{ + uint8_t start, length, index; + + //read rxid + uint8_t base_adr=BUGSMINI_EEPROM_OFFSET+RX_num*2; + uint8_t rxid_high = eeprom_read_byte((EE_ADDR)(base_adr+0)); + uint8_t rxid_low = eeprom_read_byte((EE_ADDR)(base_adr+1)); + + if(rxid_high==0x00 || rxid_high==0xFF) + rx_tx_addr[0]=0x52; + else + rx_tx_addr[0]=rxid_high; + + rx_tx_addr[1]=BUGSMINI_txhash; + + if(rxid_low==0x00 || rxid_low==0xFF) + rx_tx_addr[2]=0x66; + else + rx_tx_addr[2]=rxid_low; + + for(uint8_t end_idx=0;end_idx<23;end_idx++) + { + //calculate sequence start + if(end_idx<=7) + start=end_idx; + else + start=(end_idx-7)*16+7; + //calculate sequence length + if(end_idx>6) + { + if(end_idx>15) + length=(23-end_idx)<<1; + else + length=16; + } + else + length=(end_idx+1)<<1; + //calculate first index + index=start-rxid_high; + //scan for a possible match using the current end + for(uint8_t i=0;i read only 12 bytes to not overwrite channel change flag + XN297_ReadPayload(packet, 12); + BUGSMINI_update_telemetry(); + } + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_SetTxRxMode(TX_EN); + BUGSMINI_send_packet(0); + phase = BUGSMINI_DATA2; + return BUGSMINI_WRITE_WAIT; + case BUGSMINI_DATA2: + // switch to RX mode + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_SetTxRxMode(RX_EN); + NRF24L01_FlushRx(); + XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) + | _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX)); + phase = BUGSMINI_DATA1; + return BUGSMINI_PACKET_INTERVAL - BUGSMINI_WRITE_WAIT; + } + return BUGSMINI_PACKET_INTERVAL; +} + +#define BUGSMINI_NUM_TX_RF_MAPS 4 +// haven't figured out BUGSMINI_txid<-->rf channel mapping yet +const uint8_t PROGMEM BUGSMINI_RF_chans[BUGSMINI_NUM_TX_RF_MAPS][BUGSMINI_NUM_RF_CHANNELS] = { + {0x22,0x2f,0x3a,0x14,0x20,0x2d,0x38,0x18,0x26,0x32,0x11,0x1d,0x29,0x35,0x17}, + {0x3d,0x34,0x2b,0x22,0x19,0x40,0x37,0x2e,0x25,0x1c,0x3a,0x31,0x28,0x1f,0x16}, + {0x12,0x20,0x2f,0x1a,0x28,0x38,0x14,0x23,0x32,0x1c,0x2c,0x3b,0x17,0x26,0x34}, + {0x13,0x25,0x37,0x1F,0x31,0x17,0x28,0x3A,0x1C,0x2E,0x22,0x33,0x19,0x2B,0x3D} }; +const uint8_t PROGMEM BUGSMINI_bind_chans[BUGSMINI_NUM_RF_CHANNELS] = { + 0x1A,0x23,0x2C,0x35,0x3E,0x17,0x20,0x29,0x32,0x3B,0x14,0x1D,0x26,0x2F,0x38}; // bugs 3 mini bind channels +const uint8_t PROGMEM BUGSMINI_tx_id[BUGSMINI_NUM_TX_RF_MAPS][3] = { + {0xA8,0xE6,0x32}, + {0xdd,0xab,0xfd}, + {0x90,0x9e,0x4a}, + {0x20,0x28,0xBA} }; +const uint8_t PROGMEM BUGSMINI_tx_hash[BUGSMINI_NUM_TX_RF_MAPS] = { // 2nd byte of final address + 0x6c,0x9e,0x3d,0xb3}; + +static void __attribute__((unused)) BUGSMINI_initialize_txid() +{ + // load hopping_frequency with tx channels in low part and bind channels in high part + for(uint8_t i=0; iCC2500 PROTO_WFLY = 40, // =>CYRF6936 PROTO_BUGS = 41, // =>A7105 + PROTO_BUGSMINI = 42, // =>NRF24L01 PROTO_TEST = 63, // =>NRF24L01 }; @@ -516,9 +517,10 @@ enum { #define EEPROM_BANK_OFFSET 15 // Current bank number (1 byte) #define EEPROM_ID_VALID_OFFSET 20 // 1 byte flag that ID is valid #define MODELMODE_EEPROM_OFFSET 30 // Autobind mode, 1 byte per model, end is 30+16=46 -#define AFHDS2A_EEPROM_OFFSET 50 // RX ID, 4 byte per model id, end is 50+64=114 -#define BUGS_EEPROM_OFFSET 114 // RX ID, 4 byte per model id, end is 114+64=178 -//#define CONFIG_EEPROM_OFFSET 178 // Current configuration of the multimodule +#define AFHDS2A_EEPROM_OFFSET 50 // RX ID, 4 bytes per model id, end is 50+64=114 +#define BUGS_EEPROM_OFFSET 114 // TX ID, 4 bytes per model id, end is 114+64=178 +#define BUGSMINI_EEPROM_OFFSET 178 // RX ID, 2 bytes per model id, end is 178+32=210 +//#define CONFIG_EEPROM_OFFSET 210 // Current configuration of the multimodule //**************************************** //*** MULTI protocol serial definition *** @@ -578,6 +580,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- Hitec 39 WFLY 40 BUGS 41 + BUGSMINI 42 BindBit=> 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 1234f5a..d74a131 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -614,7 +614,7 @@ uint8_t Update_All() update_led_status(); #if defined(TELEMETRY) #if ( !( defined(MULTI_TELEMETRY) || defined(MULTI_STATUS) ) ) - if( (protocol==PROTO_FRSKYD) || (protocol==PROTO_BAYANG) || (protocol==PROTO_BUGS) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_BUGS) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_FRSKYX) || (protocol==PROTO_DSM) || (protocol==PROTO_CABELL) || (protocol==PROTO_HITEC)) + if( (protocol==PROTO_FRSKYD) || (protocol==PROTO_BAYANG) || (protocol==PROTO_BUGS) || (protocol==PROTO_BUGSMINI) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_FRSKYX) || (protocol==PROTO_DSM) || (protocol==PROTO_CABELL) || (protocol==PROTO_HITEC)) #endif TelemetryUpdate(); #endif @@ -1187,6 +1187,12 @@ static void protocol_init() remote_callback = cflie_callback; break; #endif + #if defined(BUGSMINI_NRF24L01_INO) + case PROTO_BUGSMINI: + next_callback=initBUGSMINI(); + remote_callback = BUGSMINI_callback; + break; + #endif #if defined(TEST_NRF24L01_INO) case PROTO_TEST: next_callback=initTest(); @@ -1582,7 +1588,7 @@ void pollBoot() #if defined(TELEMETRY) void PPM_Telemetry_serial_init() { - if( (protocol==PROTO_FRSKYD) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_BAYANG) || (protocol==PROTO_CABELL) || (protocol==PROTO_HITEC) || (protocol==PROTO_BUGS)) + if( (protocol==PROTO_FRSKYD) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_BAYANG) || (protocol==PROTO_CABELL) || (protocol==PROTO_HITEC) || (protocol==PROTO_BUGS) || (protocol==PROTO_BUGSMINI)) initTXSerial( SPEED_9600 ) ; if(protocol==PROTO_FRSKYX) initTXSerial( SPEED_57600 ) ; diff --git a/Multiprotocol/Telemetry.ino b/Multiprotocol/Telemetry.ino index a879719..2d15684 100644 --- a/Multiprotocol/Telemetry.ino +++ b/Multiprotocol/Telemetry.ino @@ -367,7 +367,7 @@ void frsky_link_frame() telemetry_link |= 2 ; // Send hub if available } else - if (protocol==PROTO_HUBSAN||protocol==PROTO_AFHDS2A||protocol==PROTO_BAYANG||protocol==PROTO_CABELL||protocol==PROTO_HITEC||protocol==PROTO_BUGS) + if (protocol==PROTO_HUBSAN||protocol==PROTO_AFHDS2A||protocol==PROTO_BAYANG||protocol==PROTO_CABELL||protocol==PROTO_HITEC||protocol==PROTO_BUGS||protocol==PROTO_BUGSMINI) { frame[1] = v_lipo1; frame[2] = v_lipo2; @@ -997,7 +997,7 @@ void TelemetryUpdate() #endif if((telemetry_link & 1 )&& protocol != PROTO_FRSKYX) - { // FrSkyD + Hubsan + AFHDS2A + Bayang + Cabell + Hitec + Bugs + { // FrSkyD + Hubsan + AFHDS2A + Bayang + Cabell + Hitec + Bugs + BugsMini frsky_link_frame(); return; } diff --git a/Multiprotocol/Validate.h b/Multiprotocol/Validate.h index 4d21bd5..c18b023 100644 --- a/Multiprotocol/Validate.h +++ b/Multiprotocol/Validate.h @@ -180,6 +180,7 @@ #undef ESKY150_NRF24L01_INO #undef H8_3D_NRF24L01_INO #undef CFLIE_NRF24L01_INO + #undef BUGSMINI_NRF24L01_INO #endif //Make sure telemetry is selected correctly @@ -206,6 +207,9 @@ #if not defined(BAYANG_NRF24L01_INO) #undef BAYANG_HUB_TELEMETRY #endif + #if not ( defined(BUGS_A7105_INO) || defined(BUGSMINI_NRF24L01_INO) ) + #undef BUGS_HUB_TELEMETRY + #endif #if not defined(CABELL_NRF24L01_INO) #undef CABELL_HUB_TELEMETRY #endif diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 38a2bf7..6a8d910 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -171,6 +171,7 @@ //The protocols below need a NRF24L01 to be installed #define ASSAN_NRF24L01_INO #define BAYANG_NRF24L01_INO +#define BUGSMINI_NRF24L01_INO #define CABELL_NRF24L01_INO #define CFLIE_NRF24L01_INO #define CG023_NRF24L01_INO @@ -562,6 +563,8 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= { NONE PROTO_BUGS NONE + PROTO_BUGSMINI + NONE PROTO_SLT SLT_V1 SLT_V2 From 21491497233597dbec8cf8f0574c02737f95dc32 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 2 Nov 2018 21:17:51 +0100 Subject: [PATCH 050/111] New Protocol NCC1701 --- Protocols_Details.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index e7b3b44..9008b7c 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -773,6 +773,17 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 ---|---|---|---|---|---|---|---|--- A|E|T|R|FLIP||||HEADLESS +## NCC1701 - *44* +Model: Air Hogs Star Trek USS Enterprise NCC-1701-A + +Autobind protocol + +Only 9 IDs available, cycle through them using RX_Num. + +CH1|CH2|CH3|CH4 +---|---|---|--- +A|E|T|R + ## Q2X2 - *29* ### Sub_protocol Q222 - *0* Models: Q222 v1 and V686 v2 From f42da144130134865d6ce60a739f459a51a0f834 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Fri, 2 Nov 2018 21:20:57 +0100 Subject: [PATCH 051/111] New NCC1701 protocol NCC1701 - 44 Model: Air Hogs Star Trek USS Enterprise NCC-1701-A Autobind protocol Only 9 IDs available, cycle through them using RX_Num. --- Multiprotocol/Multi.txt | 2 + Multiprotocol/Multiprotocol.h | 6 +- Multiprotocol/Multiprotocol.ino | 8 +- Multiprotocol/NCC1701_nrf24l01.ino | 243 +++++++++++++++++++++++++++++ Multiprotocol/Validate.h | 2 + Multiprotocol/_Config.h | 6 + 6 files changed, 265 insertions(+), 2 deletions(-) create mode 100644 Multiprotocol/NCC1701_nrf24l01.ino diff --git a/Multiprotocol/Multi.txt b/Multiprotocol/Multi.txt index 3b1b8f1..b416a3b 100644 --- a/Multiprotocol/Multi.txt +++ b/Multiprotocol/Multi.txt @@ -40,4 +40,6 @@ 40,WFLY 41,BUGS 42,BUGSMINI +43,Traxxas +44,NCC1701 63,Test diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index f0f1717..a05fb0e 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 1 -#define VERSION_PATCH_LEVEL 3 +#define VERSION_PATCH_LEVEL 4 //****************** // Protocols @@ -69,6 +69,8 @@ enum PROTOCOLS PROTO_WFLY = 40, // =>CYRF6936 PROTO_BUGS = 41, // =>A7105 PROTO_BUGSMINI = 42, // =>NRF24L01 + PROTO_TRAXXAS = 43, // =>CYRF6936 + PROTO_NCC1701 = 44, // =>NRF24L01 PROTO_TEST = 63, // =>NRF24L01 }; @@ -581,6 +583,8 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- WFLY 40 BUGS 41 BUGSMINI 42 + TRAXXAS 43 + NCC1701 44 BindBit=> 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index d74a131..0072d44 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -89,7 +89,7 @@ uint8_t Channel_AUX; // Protocol variables uint8_t cyrfmfg_id[6];//for dsm2 and devo uint8_t rx_tx_addr[5]; -uint8_t rx_id[4]; +uint8_t rx_id[5]; uint8_t phase; uint16_t bind_counter; uint8_t bind_phase; @@ -1193,6 +1193,12 @@ static void protocol_init() remote_callback = BUGSMINI_callback; break; #endif + #if defined(NCC1701_NRF24L01_INO) + case PROTO_NCC1701: + next_callback=initNCC(); + remote_callback = NCC_callback; + break; + #endif #if defined(TEST_NRF24L01_INO) case PROTO_TEST: next_callback=initTest(); diff --git a/Multiprotocol/NCC1701_nrf24l01.ino b/Multiprotocol/NCC1701_nrf24l01.ino new file mode 100644 index 0000000..abb6164 --- /dev/null +++ b/Multiprotocol/NCC1701_nrf24l01.ino @@ -0,0 +1,243 @@ +/* + 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 . + */ + +#if defined(NCC1701_NRF24L01_INO) + +#include "iface_nrf24l01.h" + +#define NCC_WRITE_WAIT 2000 +#define NCC_PACKET_INTERVAL 10333 +#define NCC_TX_PACKET_LEN 16 +#define NCC_RX_PACKET_LEN 13 + +enum { + NCC_BIND_TX1=0, + NCC_BIND_RX1, + NCC_BIND_TX2, + NCC_BIND_RX2, + NCC_DATA, +}; + +static void __attribute__((unused)) NCC_init() +{ + NRF24L01_Initialize(); + NRF24L01_SetTxRxMode(TX_EN); + + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address + NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\xE7\xE7\xC7\xD7\x67",5); + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\xE7\xE7\xC7\xD7\x67",5); + + NRF24L01_FlushTx(); + NRF24L01_FlushRx(); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit + NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgment on all data pipes + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only + NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, NCC_RX_PACKET_LEN); // Enable rx pipe 0 + NRF24L01_SetBitrate(NRF24L01_BR_250K); // NRF24L01_BR_1M, NRF24L01_BR_2M, NRF24L01_BR_250K + NRF24L01_SetPower(); + NRF24L01_FlushRx(); + NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC) // switch to TX mode and disable CRC + | (1 << NRF24L01_00_CRCO) + | (1 << NRF24L01_00_PWR_UP) + | (0 << NRF24L01_00_PRIM_RX)); +} + +uint8_t NCC_xorout[]={0x80, 0x44, 0x64, 0x75, 0x6C, 0x71, 0x2A, 0x36, 0x7C, 0xF1, 0x6E, 0x52, 0x09, 0x9D}; +static void __attribute__((unused)) NCC_Crypt_Packet() +{ + uint16_t crc=0; + for(uint8_t i=0; i< NCC_TX_PACKET_LEN-2; i++) + { + packet[i]^=NCC_xorout[i]; + crc=crc16_update(crc, packet[i], 8); + } + crc^=0x60DE; + packet[NCC_TX_PACKET_LEN-2]=crc>>8; + packet[NCC_TX_PACKET_LEN-1]=crc; +} +static boolean __attribute__((unused)) NCC_Decrypt_Packet() +{ + uint16_t crc=0; + debug("RX: "); + for(uint8_t i=0; i< NCC_RX_PACKET_LEN-2; i++) + { + crc=crc16_update(crc, packet[i], 8); + packet[i]^=NCC_xorout[i]; + debug("%02X ",packet[i]); + } + crc^=0xA950; + if( (crc>>8)==packet[NCC_RX_PACKET_LEN-2] && (crc&0xFF)==packet[NCC_RX_PACKET_LEN-1] ) + {// CRC match + debugln("OK"); + return true; + } + debugln("NOK"); + return false; +} + +static void __attribute__((unused)) NCC_Write_Packet() +{ + packet[0]=0xAA; + packet[1]=rx_tx_addr[0]; + packet[2]=rx_tx_addr[1]; + packet[3]=rx_id[0]; + packet[4]=rx_id[1]; + packet[5]=convert_channel_8b(THROTTLE)>>2; // 00-3D + packet[6]=convert_channel_8b(ELEVATOR); // original: 61-80-9F but works with 00-80-FF + packet[7]=convert_channel_8b(AILERON ); // original: 61-80-9F but works with 00-80-FF + packet[8]=convert_channel_8b(RUDDER ); // original: 61-80-9F but works with 00-80-FF + packet[9]=rx_id[2]; + packet[10]=rx_id[3]; + packet[11]=rx_id[4]; + packet[12]=0x02; // default:0x00 -> Warp:0x02 ?? + packet[13]=packet[5]+packet[6]+packet[7]+packet[8]+packet[12]; + if(phase==NCC_BIND_TX1) + { + packet[0]=0xBB; + packet[5]=0x01; + packet[6]=rx_tx_addr[2]; + memset((void *)(packet+7),0x55,7); + hopping_frequency_no^=1; + } + else + { + hopping_frequency_no++; + if(hopping_frequency_no>2) hopping_frequency_no=0; + } + // change frequency + NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]); + // switch to TX mode and disable CRC + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_SetTxRxMode(TX_EN); + NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC) + | (1 << NRF24L01_00_CRCO) + | (1 << NRF24L01_00_PWR_UP) + | (0 << NRF24L01_00_PRIM_RX)); + // clear packet status bits and TX FIFO + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); + NRF24L01_FlushTx(); + // send packet + NCC_Crypt_Packet(); + NRF24L01_WritePayload(packet,NCC_TX_PACKET_LEN); + NRF24L01_SetPower(); +} + +uint16_t NCC_callback() +{ + switch(phase) + { + case NCC_BIND_TX1: + if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR)) + { // RX fifo data ready + NRF24L01_ReadPayload(packet, NCC_RX_PACKET_LEN); + if(NCC_Decrypt_Packet()) + { + rx_id[0]=packet[3]; + rx_id[1]=packet[4]; + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit + phase=NCC_BIND_TX2; + return NCC_PACKET_INTERVAL; + } + } + NCC_Write_Packet(); + phase = NCC_BIND_RX1; + return NCC_WRITE_WAIT; + case NCC_BIND_RX1: + // switch to RX mode and disable CRC + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_SetTxRxMode(RX_EN); + NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC) + | (1 << NRF24L01_00_CRCO) + | (1 << NRF24L01_00_PWR_UP) + | (1 << NRF24L01_00_PRIM_RX)); + NRF24L01_FlushRx(); + phase = NCC_BIND_TX1; + return NCC_PACKET_INTERVAL - NCC_WRITE_WAIT; + case NCC_BIND_TX2: + if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR)) + { // RX fifo data ready + NRF24L01_ReadPayload(packet, NCC_RX_PACKET_LEN); + if(NCC_Decrypt_Packet()) + { + rx_id[2]=packet[8]; + rx_id[3]=packet[9]; + rx_id[4]=packet[10]; + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit + BIND_DONE; + phase=NCC_DATA; + return NCC_PACKET_INTERVAL; + } + } + NCC_Write_Packet(); + phase = NCC_BIND_RX2; + return NCC_WRITE_WAIT; + case NCC_BIND_RX2: + // switch to RX mode and disable CRC + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_SetTxRxMode(RX_EN); + NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC) + | (1 << NRF24L01_00_CRCO) + | (1 << NRF24L01_00_PWR_UP) + | (1 << NRF24L01_00_PRIM_RX)); + NRF24L01_FlushRx(); + phase = NCC_BIND_TX2; + return NCC_PACKET_INTERVAL - NCC_WRITE_WAIT; + case NCC_DATA: + NCC_Write_Packet(); + return NCC_PACKET_INTERVAL; + } + return 0; +} + +const uint8_t PROGMEM NCC_TX_DATA[][6]= { + { 0x6D, 0x97, 0x04, 0x48, 0x43, 0x26 }, + { 0x35, 0x4B, 0x80, 0x44, 0x4C, 0x0B }, + { 0x50, 0xE2, 0x32, 0x2D, 0x4B, 0x0A }, + { 0xBF, 0x34, 0xF3, 0x45, 0x4D, 0x0D }, + { 0xDD, 0x7D, 0x5A, 0x46, 0x28, 0x23 }, + { 0xED, 0x19, 0x06, 0x2C, 0x4A, 0x09 }, + { 0xE9, 0xA8, 0x91, 0x2B, 0x49, 0x07 }, + { 0x66, 0x17, 0x7D, 0x48, 0x43, 0x26 }, + { 0xC2, 0x93, 0x55, 0x44, 0x4C, 0x0B }, +}; + +uint16_t initNCC(void) +{ + BIND_IN_PROGRESS; // autobind protocol + + // Load TX data + uint8_t rand=rx_tx_addr[3]%9; + for(uint8_t i=0; i<3; i++) + { + rx_tx_addr[i]=pgm_read_byte_near(&NCC_TX_DATA[rand][i]); + hopping_frequency[i]=pgm_read_byte_near(&NCC_TX_DATA[rand][i+3]); + } + + // RX data is acquired during bind + rx_id[0]=0x00; + rx_id[1]=0x00; + rx_id[2]=0x20; + rx_id[3]=0x20; + rx_id[4]=0x20; + + hopping_frequency[4]=0x08; // bind channel 1 + hopping_frequency[5]=0x2A; // bind channel 2 + hopping_frequency_no=4; // start with bind + NCC_init(); + phase=NCC_BIND_TX1; + return 10000; +} + +#endif diff --git a/Multiprotocol/Validate.h b/Multiprotocol/Validate.h index c18b023..eff35ee 100644 --- a/Multiprotocol/Validate.h +++ b/Multiprotocol/Validate.h @@ -146,6 +146,7 @@ #undef J6PRO_CYRF6936_INO #undef WFLY_CYRF6936_INO #undef WK2x01_CYRF6936_INO + #undef TRAXXAS_CYRF6936_INO #endif #ifndef CC2500_INSTALLED #undef FRSKYD_CC2500_INO @@ -181,6 +182,7 @@ #undef H8_3D_NRF24L01_INO #undef CFLIE_NRF24L01_INO #undef BUGSMINI_NRF24L01_INO + #undef NCC1701_NRF24L01_INO #endif //Make sure telemetry is selected correctly diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 6a8d910..04c66f4 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -159,6 +159,7 @@ #define J6PRO_CYRF6936_INO #define WFLY_CYRF6936_INO #define WK2x01_CYRF6936_INO +//#define TRAXXAS_CYRF6936_INO //The protocols below need a CC2500 to be installed #define CORONA_CC2500_INO @@ -188,6 +189,7 @@ #define KN_NRF24L01_INO #define MJXQ_NRF24L01_INO #define MT99XX_NRF24L01_INO +#define NCC1701_NRF24L01_INO #define Q303_NRF24L01_INO #define SHENQI_NRF24L01_INO #define SLT_NRF24L01_INO @@ -571,6 +573,10 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= { Q100 Q200 MR100 + PROTO_TRAXXAS + NONE + PROTO_NCC1701 + NONE */ // RX_Num is used for TX & RX match. Using different RX_Num values for each receiver will prevent starting a model with the false config loaded... From ea96c328fcb716677ce93ff045b7db0d741147b5 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Sat, 3 Nov 2018 17:24:47 +0100 Subject: [PATCH 052/111] Protocol NCC1701 CH5: Warp Telemetry: A1 voltage is used for crash detection. In case of a crash A1=0V. You can be assign a sound to the crash. --- Multiprotocol/Multiprotocol.h | 2 +- Multiprotocol/Multiprotocol.ino | 4 +-- Multiprotocol/NCC1701_nrf24l01.ino | 49 +++++++++++++++++++++++++----- Multiprotocol/Telemetry.ino | 4 +-- Multiprotocol/Validate.h | 6 +++- Multiprotocol/_Config.h | 3 +- 6 files changed, 53 insertions(+), 15 deletions(-) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index a05fb0e..7a9ca23 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 1 -#define VERSION_PATCH_LEVEL 4 +#define VERSION_PATCH_LEVEL 5 //****************** // Protocols diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 0072d44..48b9b55 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -614,7 +614,7 @@ uint8_t Update_All() update_led_status(); #if defined(TELEMETRY) #if ( !( defined(MULTI_TELEMETRY) || defined(MULTI_STATUS) ) ) - if( (protocol==PROTO_FRSKYD) || (protocol==PROTO_BAYANG) || (protocol==PROTO_BUGS) || (protocol==PROTO_BUGSMINI) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_FRSKYX) || (protocol==PROTO_DSM) || (protocol==PROTO_CABELL) || (protocol==PROTO_HITEC)) + if( (protocol==PROTO_FRSKYD) || (protocol==PROTO_BAYANG) || (protocol==PROTO_NCC1701) || (protocol==PROTO_BUGS) || (protocol==PROTO_BUGSMINI) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_FRSKYX) || (protocol==PROTO_DSM) || (protocol==PROTO_CABELL) || (protocol==PROTO_HITEC)) #endif TelemetryUpdate(); #endif @@ -1594,7 +1594,7 @@ void pollBoot() #if defined(TELEMETRY) void PPM_Telemetry_serial_init() { - if( (protocol==PROTO_FRSKYD) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_BAYANG) || (protocol==PROTO_CABELL) || (protocol==PROTO_HITEC) || (protocol==PROTO_BUGS) || (protocol==PROTO_BUGSMINI)) + if( (protocol==PROTO_FRSKYD) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_BAYANG)|| (protocol==PROTO_NCC1701) || (protocol==PROTO_CABELL) || (protocol==PROTO_HITEC) || (protocol==PROTO_BUGS) || (protocol==PROTO_BUGSMINI)) initTXSerial( SPEED_9600 ) ; if(protocol==PROTO_FRSKYX) initTXSerial( SPEED_57600 ) ; diff --git a/Multiprotocol/NCC1701_nrf24l01.ino b/Multiprotocol/NCC1701_nrf24l01.ino index abb6164..cff7b61 100644 --- a/Multiprotocol/NCC1701_nrf24l01.ino +++ b/Multiprotocol/NCC1701_nrf24l01.ino @@ -27,7 +27,8 @@ enum { NCC_BIND_RX1, NCC_BIND_TX2, NCC_BIND_RX2, - NCC_DATA, + NCC_BIND_TX3, + NCC_BIND_RX3, }; static void __attribute__((unused)) NCC_init() @@ -54,13 +55,13 @@ static void __attribute__((unused)) NCC_init() | (0 << NRF24L01_00_PRIM_RX)); } -uint8_t NCC_xorout[]={0x80, 0x44, 0x64, 0x75, 0x6C, 0x71, 0x2A, 0x36, 0x7C, 0xF1, 0x6E, 0x52, 0x09, 0x9D}; +uint8_t NCC_xor[]={0x80, 0x44, 0x64, 0x75, 0x6C, 0x71, 0x2A, 0x36, 0x7C, 0xF1, 0x6E, 0x52, 0x09, 0x9D}; static void __attribute__((unused)) NCC_Crypt_Packet() { uint16_t crc=0; for(uint8_t i=0; i< NCC_TX_PACKET_LEN-2; i++) { - packet[i]^=NCC_xorout[i]; + packet[i]^=NCC_xor[i]; crc=crc16_update(crc, packet[i], 8); } crc^=0x60DE; @@ -74,7 +75,7 @@ static boolean __attribute__((unused)) NCC_Decrypt_Packet() for(uint8_t i=0; i< NCC_RX_PACKET_LEN-2; i++) { crc=crc16_update(crc, packet[i], 8); - packet[i]^=NCC_xorout[i]; + packet[i]^=NCC_xor[i]; debug("%02X ",packet[i]); } crc^=0xA950; @@ -101,7 +102,7 @@ static void __attribute__((unused)) NCC_Write_Packet() packet[9]=rx_id[2]; packet[10]=rx_id[3]; packet[11]=rx_id[4]; - packet[12]=0x02; // default:0x00 -> Warp:0x02 ?? + packet[12]=GET_FLAG(CH5_SW, 0x02); // Warp:0x00 -> 0x02 packet[13]=packet[5]+packet[6]+packet[7]+packet[8]+packet[12]; if(phase==NCC_BIND_TX1) { @@ -176,7 +177,7 @@ uint16_t NCC_callback() rx_id[4]=packet[10]; NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit BIND_DONE; - phase=NCC_DATA; + phase=NCC_BIND_TX3; return NCC_PACKET_INTERVAL; } } @@ -194,9 +195,38 @@ uint16_t NCC_callback() NRF24L01_FlushRx(); phase = NCC_BIND_TX2; return NCC_PACKET_INTERVAL - NCC_WRITE_WAIT; - case NCC_DATA: + case NCC_BIND_TX3: + if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR)) + { // RX fifo data ready + NRF24L01_ReadPayload(packet, NCC_RX_PACKET_LEN); + if(NCC_Decrypt_Packet()) + { + //Telemetry + //packet[5] and packet[7] roll angle + //packet[6] crash detect: 0x00 no crash, 0x02 crash + #ifdef NCC1701_HUB_TELEMETRY + v_lipo1 = packet[6]?0x00:0xFF; // Crash indication + v_lipo2 = 0x00; + RX_RSSI = 0x7F; // Dummy RSSI + TX_RSSI = 0x7F; // Dummy RSSI + telemetry_link=1; + #endif + } + } NCC_Write_Packet(); - return NCC_PACKET_INTERVAL; + phase = NCC_BIND_RX3; + return NCC_WRITE_WAIT; + case NCC_BIND_RX3: + // switch to RX mode and disable CRC + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_SetTxRxMode(RX_EN); + NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC) + | (1 << NRF24L01_00_CRCO) + | (1 << NRF24L01_00_PWR_UP) + | (1 << NRF24L01_00_PRIM_RX)); + NRF24L01_FlushRx(); + phase = NCC_BIND_TX3; + return NCC_PACKET_INTERVAL - NCC_WRITE_WAIT; } return 0; } @@ -237,6 +267,9 @@ uint16_t initNCC(void) hopping_frequency_no=4; // start with bind NCC_init(); phase=NCC_BIND_TX1; + #ifdef NCC1701_HUB_TELEMETRY + init_frskyd_link_telemetry(); + #endif return 10000; } diff --git a/Multiprotocol/Telemetry.ino b/Multiprotocol/Telemetry.ino index 2d15684..3c281b5 100644 --- a/Multiprotocol/Telemetry.ino +++ b/Multiprotocol/Telemetry.ino @@ -367,7 +367,7 @@ void frsky_link_frame() telemetry_link |= 2 ; // Send hub if available } else - if (protocol==PROTO_HUBSAN||protocol==PROTO_AFHDS2A||protocol==PROTO_BAYANG||protocol==PROTO_CABELL||protocol==PROTO_HITEC||protocol==PROTO_BUGS||protocol==PROTO_BUGSMINI) + if (protocol==PROTO_HUBSAN||protocol==PROTO_AFHDS2A||protocol==PROTO_BAYANG||protocol==PROTO_NCC1701||protocol==PROTO_CABELL||protocol==PROTO_HITEC||protocol==PROTO_BUGS||protocol==PROTO_BUGSMINI) { frame[1] = v_lipo1; frame[2] = v_lipo2; @@ -997,7 +997,7 @@ void TelemetryUpdate() #endif if((telemetry_link & 1 )&& protocol != PROTO_FRSKYX) - { // FrSkyD + Hubsan + AFHDS2A + Bayang + Cabell + Hitec + Bugs + BugsMini + { // FrSkyD + Hubsan + AFHDS2A + Bayang + Cabell + Hitec + Bugs + BugsMini + NCC1701 frsky_link_frame(); return; } diff --git a/Multiprotocol/Validate.h b/Multiprotocol/Validate.h index eff35ee..af530a7 100644 --- a/Multiprotocol/Validate.h +++ b/Multiprotocol/Validate.h @@ -196,6 +196,7 @@ #undef CABELL_HUB_TELEMETRY #undef HUBSAN_HUB_TELEMETRY #undef BUGS_HUB_TELEMETRY + #undef NCC1701_HUB_TELEMETRY #undef HUB_TELEMETRY #undef SPORT_TELEMETRY #undef SPORT_POLLING @@ -209,6 +210,9 @@ #if not defined(BAYANG_NRF24L01_INO) #undef BAYANG_HUB_TELEMETRY #endif + #if not defined(NCC1701_NRF24L01_INO) + #undef NCC1701_HUB_TELEMETRY + #endif #if not ( defined(BUGS_A7105_INO) || defined(BUGSMINI_NRF24L01_INO) ) #undef BUGS_HUB_TELEMETRY #endif @@ -242,7 +246,7 @@ #if not defined(DSM_CYRF6936_INO) #undef DSM_TELEMETRY #endif - #if not defined(DSM_TELEMETRY) && not defined(SPORT_TELEMETRY) && not defined(HUB_TELEMETRY) && not defined(HUBSAN_HUB_TELEMETRY) && not defined(BUGS_HUB_TELEMETRY) && not defined(BAYANG_HUB_TELEMETRY) && not defined(CABELL_HUB_TELEMETRY) && not defined(AFHDS2A_HUB_TELEMETRY) && not defined(AFHDS2A_FW_TELEMETRY) && not defined(MULTI_TELEMETRY) && not defined(MULTI_STATUS) && not defined(HITEC_HUB_TELEMETRY) && not defined(HITEC_FW_TELEMETRY) + #if not defined(DSM_TELEMETRY) && not defined(SPORT_TELEMETRY) && not defined(HUB_TELEMETRY) && not defined(HUBSAN_HUB_TELEMETRY) && not defined(BUGS_HUB_TELEMETRY) && not defined(NCC1701_HUB_TELEMETRY) && not defined(BAYANG_HUB_TELEMETRY) && not defined(CABELL_HUB_TELEMETRY) && not defined(AFHDS2A_HUB_TELEMETRY) && not defined(AFHDS2A_FW_TELEMETRY) && not defined(MULTI_TELEMETRY) && not defined(MULTI_STATUS) && not defined(HITEC_HUB_TELEMETRY) && not defined(HITEC_FW_TELEMETRY) #undef TELEMETRY #undef INVERT_TELEMETRY #undef SPORT_POLLING diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 04c66f4..c21c081 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -176,7 +176,7 @@ #define CABELL_NRF24L01_INO #define CFLIE_NRF24L01_INO #define CG023_NRF24L01_INO -#define CX10_NRF24L01_INO // Include Q2X2 protocol +#define CX10_NRF24L01_INO //Include Q2X2 protocol #define DM002_NRF24L01_INO #define ESKY_NRF24L01_INO #define ESKY150_NRF24L01_INO @@ -253,6 +253,7 @@ #define BAYANG_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX #define BUGS_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX #define HUBSAN_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX +#define NCC1701_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX #define CABELL_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX #define HITEC_HUB_TELEMETRY // Use FrSkyD Hub format to send basic telemetry to the radios which can decode it like er9x, ersky9x and OpenTX #define HITEC_FW_TELEMETRY // Under development: Forward received telemetry packets to be decoded by ersky9x and OpenTX From b3ed7563dc67887e7a85de9fac82c376fd74214d Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sat, 3 Nov 2018 17:28:40 +0100 Subject: [PATCH 053/111] NCC1701 --- Protocols_Details.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 9008b7c..fffe074 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -778,11 +778,13 @@ Model: Air Hogs Star Trek USS Enterprise NCC-1701-A Autobind protocol +Telemetry: RSSI is a dummy value. A1 voltage is dummy but used for crash detection. In case of a crash event A1=0V, you can assign a sound to be played on the TX in that case (siren on the original transmitter). + Only 9 IDs available, cycle through them using RX_Num. -CH1|CH2|CH3|CH4 ----|---|---|--- -A|E|T|R +CH1|CH2|CH3|CH4|CH5 +---|---|---|---|--- +A|E|T|R|Warp ## Q2X2 - *29* ### Sub_protocol Q222 - *0* From 2f4f19b52bb19b91c207ff919e3a693765d44351 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 5 Nov 2018 20:02:48 +0100 Subject: [PATCH 054/111] Update Protocols_Details.md --- Protocols_Details.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index fffe074..36ef400 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -778,7 +778,7 @@ Model: Air Hogs Star Trek USS Enterprise NCC-1701-A Autobind protocol -Telemetry: RSSI is a dummy value. A1 voltage is dummy but used for crash detection. In case of a crash event A1=0V, you can assign a sound to be played on the TX in that case (siren on the original transmitter). +Telemetry: RSSI is a dummy value. A1 voltage is dummy but used for crash detection. In case of a crash event A1>0V, you can assign a sound to be played on the TX in that case (siren on the original transmitter). Only 9 IDs available, cycle through them using RX_Num. From 2589c67f6c0161246043b7d4ffe0f5c42588e6f9 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Mon, 5 Nov 2018 20:03:39 +0100 Subject: [PATCH 055/111] NCC1701 fix --- Multiprotocol/Multiprotocol.h | 2 +- Multiprotocol/NCC1701_nrf24l01.ino | 25 +++++++++++++------------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 7a9ca23..9422433 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 1 -#define VERSION_PATCH_LEVEL 5 +#define VERSION_PATCH_LEVEL 6 //****************** // Protocols diff --git a/Multiprotocol/NCC1701_nrf24l01.ino b/Multiprotocol/NCC1701_nrf24l01.ino index cff7b61..814bb99 100644 --- a/Multiprotocol/NCC1701_nrf24l01.ino +++ b/Multiprotocol/NCC1701_nrf24l01.ino @@ -27,8 +27,8 @@ enum { NCC_BIND_RX1, NCC_BIND_TX2, NCC_BIND_RX2, - NCC_BIND_TX3, - NCC_BIND_RX3, + NCC_TX3, + NCC_RX3, }; static void __attribute__((unused)) NCC_init() @@ -55,7 +55,7 @@ static void __attribute__((unused)) NCC_init() | (0 << NRF24L01_00_PRIM_RX)); } -uint8_t NCC_xor[]={0x80, 0x44, 0x64, 0x75, 0x6C, 0x71, 0x2A, 0x36, 0x7C, 0xF1, 0x6E, 0x52, 0x09, 0x9D}; +const uint8_t NCC_xor[]={0x80, 0x44, 0x64, 0x75, 0x6C, 0x71, 0x2A, 0x36, 0x7C, 0xF1, 0x6E, 0x52, 0x09, 0x9D}; static void __attribute__((unused)) NCC_Crypt_Packet() { uint16_t crc=0; @@ -143,7 +143,8 @@ uint16_t NCC_callback() if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR)) { // RX fifo data ready NRF24L01_ReadPayload(packet, NCC_RX_PACKET_LEN); - if(NCC_Decrypt_Packet()) + if(NCC_Decrypt_Packet() && packet[1]==rx_tx_addr[0] && packet[2]==rx_tx_addr[1]) + { rx_id[0]=packet[3]; rx_id[1]=packet[4]; @@ -170,14 +171,14 @@ uint16_t NCC_callback() if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR)) { // RX fifo data ready NRF24L01_ReadPayload(packet, NCC_RX_PACKET_LEN); - if(NCC_Decrypt_Packet()) + if(NCC_Decrypt_Packet() && packet[1]==rx_tx_addr[0] && packet[2]==rx_tx_addr[1] && packet[3]==rx_id[0] && packet[4]==rx_id[1]) { rx_id[2]=packet[8]; rx_id[3]=packet[9]; rx_id[4]=packet[10]; NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit BIND_DONE; - phase=NCC_BIND_TX3; + phase=NCC_TX3; return NCC_PACKET_INTERVAL; } } @@ -195,17 +196,17 @@ uint16_t NCC_callback() NRF24L01_FlushRx(); phase = NCC_BIND_TX2; return NCC_PACKET_INTERVAL - NCC_WRITE_WAIT; - case NCC_BIND_TX3: + case NCC_TX3: if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR)) { // RX fifo data ready NRF24L01_ReadPayload(packet, NCC_RX_PACKET_LEN); - if(NCC_Decrypt_Packet()) + if(NCC_Decrypt_Packet() && packet[1]==rx_tx_addr[0] && packet[2]==rx_tx_addr[1] && packet[3]==rx_id[0] && packet[4]==rx_id[1]) { //Telemetry //packet[5] and packet[7] roll angle //packet[6] crash detect: 0x00 no crash, 0x02 crash #ifdef NCC1701_HUB_TELEMETRY - v_lipo1 = packet[6]?0x00:0xFF; // Crash indication + v_lipo1 = packet[6]?0xFF:0x00; // Crash indication v_lipo2 = 0x00; RX_RSSI = 0x7F; // Dummy RSSI TX_RSSI = 0x7F; // Dummy RSSI @@ -214,9 +215,9 @@ uint16_t NCC_callback() } } NCC_Write_Packet(); - phase = NCC_BIND_RX3; + phase = NCC_RX3; return NCC_WRITE_WAIT; - case NCC_BIND_RX3: + case NCC_RX3: // switch to RX mode and disable CRC NRF24L01_SetTxRxMode(TXRX_OFF); NRF24L01_SetTxRxMode(RX_EN); @@ -225,7 +226,7 @@ uint16_t NCC_callback() | (1 << NRF24L01_00_PWR_UP) | (1 << NRF24L01_00_PRIM_RX)); NRF24L01_FlushRx(); - phase = NCC_BIND_TX3; + phase = NCC_TX3; return NCC_PACKET_INTERVAL - NCC_WRITE_WAIT; } return 0; From e51f91f041b3dd60b871f05a0d64a9007645e9b0 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Tue, 6 Nov 2018 21:43:55 +0100 Subject: [PATCH 056/111] Bugs protocol fix? --- Multiprotocol/BUGSMINI_nrf24l01.ino | 29 ++++++----- Multiprotocol/Bugs_a7105.ino | 80 ++++++++++++++--------------- Multiprotocol/Multiprotocol.h | 14 ++++- 3 files changed, 67 insertions(+), 56 deletions(-) diff --git a/Multiprotocol/BUGSMINI_nrf24l01.ino b/Multiprotocol/BUGSMINI_nrf24l01.ino index 170ef46..46026b7 100644 --- a/Multiprotocol/BUGSMINI_nrf24l01.ino +++ b/Multiprotocol/BUGSMINI_nrf24l01.ino @@ -26,8 +26,6 @@ #define BUGSMINI_NUM_RF_CHANNELS 15 #define BUGSMINI_ADDRESS_SIZE 5 -static uint8_t BUGSMINI_armed, BUGSMINI_arm_flags; -static uint8_t BUGSMINI_arm_channel_previous; static uint8_t BUGSMINI_txid[3]; static uint8_t BUGSMINI_txhash; @@ -79,18 +77,18 @@ static void __attribute__((unused)) BUGSMINI_check_arming() { uint8_t arm_channel = BUGSMINI_CH_SW_ARM; - if (arm_channel != BUGSMINI_arm_channel_previous) + if (arm_channel != arm_channel_previous) { - BUGSMINI_arm_channel_previous = arm_channel; + arm_channel_previous = arm_channel; if (arm_channel) { - BUGSMINI_armed = 1; - BUGSMINI_arm_flags ^= BUGSMINI_FLAG_ARM; + armed = 1; + arm_flags ^= BUGSMINI_FLAG_ARM; } else { - BUGSMINI_armed = 0; - BUGSMINI_arm_flags ^= BUGSMINI_FLAG_DISARM; + armed = 0; + arm_flags ^= BUGSMINI_FLAG_DISARM; } } } @@ -101,7 +99,7 @@ static void __attribute__((unused)) BUGSMINI_send_packet(uint8_t bind) uint16_t aileron = convert_channel_16b_limit(AILERON,500,0); uint16_t elevator = convert_channel_16b_limit(ELEVATOR,0,500); - uint16_t throttle = BUGSMINI_armed ? convert_channel_16b_limit(THROTTLE,0,500) : 0; + uint16_t throttle = armed ? convert_channel_16b_limit(THROTTLE,0,500) : 0; uint16_t rudder = convert_channel_16b_limit(RUDDER,500,0); packet[1] = BUGSMINI_txid[0]; @@ -136,9 +134,9 @@ static void __attribute__((unused)) BUGSMINI_send_packet(uint8_t bind) | BUGSMINI_FLAG_MODE | GET_FLAG(BUGSMINI_CH_SW_PICTURE, BUGSMINI_FLAG_PICTURE) | GET_FLAG(BUGSMINI_CH_SW_VIDEO, BUGSMINI_FLAG_VIDEO); - if(BUGSMINI_armed) + if(armed) packet[12] |= GET_FLAG(BUGSMINI_CH_SW_FLIP, BUGSMINI_FLAG_FLIP); - packet[13] = BUGSMINI_arm_flags + packet[13] = arm_flags | GET_FLAG(BUGSMINI_CH_SW_LED, BUGSMINI_FLAG_LED) | GET_FLAG(BUGSMINI_CH_SW_ANGLE, BUGSMINI_FLAG_ANGLE); @@ -355,9 +353,12 @@ uint16_t initBUGSMINI() XN297_SetRXAddr(rx_tx_addr, 5); phase = BUGSMINI_DATA1; } - BUGSMINI_armed = 0; - BUGSMINI_arm_flags = BUGSMINI_FLAG_DISARM; // initial value from captures - BUGSMINI_arm_channel_previous = BUGSMINI_CH_SW_ARM; + armed = 0; + arm_flags = BUGSMINI_FLAG_DISARM; // initial value from captures + arm_channel_previous = BUGSMINI_CH_SW_ARM; + #ifdef BUGS_HUB_TELEMETRY + init_frskyd_link_telemetry(); + #endif return BUGSMINI_INITIAL_WAIT; } diff --git a/Multiprotocol/Bugs_a7105.ino b/Multiprotocol/Bugs_a7105.ino index 60098fe..b99bc18 100644 --- a/Multiprotocol/Bugs_a7105.ino +++ b/Multiprotocol/Bugs_a7105.ino @@ -175,9 +175,6 @@ static uint32_t __attribute__((unused)) BUGS_rxid_to_radioid(uint16_t rxid) #define BUGS_PACKET_SIZE 22 #define BUGS_NUM_RFCHAN 16 -static uint8_t BUGS_armed, BUGS_arm_flags; -static uint8_t BUGS_arm_channel_previous; - enum { BUGS_BIND_1, BUGS_BIND_2, @@ -191,25 +188,25 @@ static void __attribute__((unused)) BUGS_check_arming() { uint8_t arm_channel = BUGS_CH_SW_ARM; - if (arm_channel != BUGS_arm_channel_previous) + if (arm_channel != arm_channel_previous) { - BUGS_arm_channel_previous = arm_channel; + arm_channel_previous = arm_channel; if (arm_channel) { - BUGS_armed = 1; - BUGS_arm_flags ^= BUGS_FLAG_ARM; + armed = 1; + arm_flags ^= BUGS_FLAG_ARM; } else { - BUGS_armed = 0; - BUGS_arm_flags ^= BUGS_FLAG_DISARM; + armed = 0; + arm_flags ^= BUGS_FLAG_DISARM; } } } static void __attribute__((unused)) BUGS_build_packet(uint8_t bind) { - uint8_t force_values = bind | !BUGS_armed; + uint8_t force_values = bind | !armed; uint8_t change_channel = ((packet_count & 0x1) << 6); uint16_t aileron = convert_channel_16b_limit(AILERON,800,0); uint16_t elevator = convert_channel_16b_limit(ELEVATOR,800,0); @@ -225,7 +222,7 @@ static void __attribute__((unused)) BUGS_build_packet(uint8_t bind) if(bind) { packet[4] = change_channel | 0x80; - packet[5] = 0x02 | BUGS_arm_flags + packet[5] = 0x02 | arm_flags | GET_FLAG(BUGS_CH_SW_ANGLE, BUGS_FLAG_ANGLE); } else @@ -234,7 +231,7 @@ static void __attribute__((unused)) BUGS_build_packet(uint8_t bind) | GET_FLAG(BUGS_CH_SW_FLIP, BUGS_FLAG_FLIP) | GET_FLAG(BUGS_CH_SW_PICTURE, BUGS_FLAG_PICTURE) | GET_FLAG(BUGS_CH_SW_VIDEO, BUGS_FLAG_VIDEO); - packet[5] = 0x02 | BUGS_arm_flags + packet[5] = 0x02 | arm_flags | GET_FLAG(BUGS_CH_SW_ANGLE, BUGS_FLAG_ANGLE) | GET_FLAG(BUGS_CH_SW_LED, BUGS_FLAG_LED); } @@ -309,19 +306,20 @@ static void __attribute__((unused)) BUGS_increment_counts() } } -#define BUGS_DELAY_POST_TX 1100 -#define BUGS_DELAY_WAIT_TX 500 -#define BUGS_DELAY_WAIT_RX 2000 -#define BUGS_DELAY_POST_RX 2000 +#define BUGS_PACKET_PERIOD 6100 +#define BUGS_DELAY_TX 2000 +#define BUGS_DELAY_POST_RX 1500 #define BUGS_DELAY_BIND_RST 200 + // FIFO config is one less than desired value #define BUGS_FIFO_SIZE_RX 15 #define BUGS_FIFO_SIZE_TX 21 uint16_t ReadBUGS(void) { - uint8_t mode, timeout, base_adr; + uint8_t mode, base_adr; uint16_t rxid; uint32_t radio_id; + uint16_t start; // keep frequency tuning updated #ifndef FORCE_FLYSKY_TUNING @@ -336,19 +334,15 @@ uint16_t ReadBUGS(void) A7105_WriteReg(A7105_03_FIFOI, BUGS_FIFO_SIZE_TX); A7105_WriteData(BUGS_PACKET_SIZE, hopping_frequency[hopping_frequency_no]); phase = BUGS_BIND_2; - packet_period = BUGS_DELAY_POST_TX; + packet_period = BUGS_DELAY_TX; break; case BUGS_BIND_2: - // wait here a bit for tx complete because - // need to start rx immediately to catch return packet - timeout = 20; - while (A7105_ReadReg(A7105_00_MODE) & 0x01) - if (timeout-- == 0) - { - packet_period = BUGS_DELAY_WAIT_TX; // don't proceed until transmission complete + //Wait for TX completion + start=micros(); + while ((uint16_t)micros()-start < 500) // Wait max 500µs, using serial+telemetry exit in about 60µs + if(!(A7105_ReadReg(A7105_00_MODE) & 0x01)) break; - } A7105_SetTxRxMode(RX_EN); A7105_WriteReg(A7105_0F_PLL_I, hopping_frequency[hopping_frequency_no] - 2); A7105_WriteReg(A7105_03_FIFOI, BUGS_FIFO_SIZE_RX); @@ -356,7 +350,7 @@ uint16_t ReadBUGS(void) BUGS_increment_counts(); phase = BUGS_BIND_3; - packet_period = BUGS_DELAY_WAIT_RX; + packet_period = BUGS_PACKET_PERIOD-BUGS_DELAY_TX-BUGS_DELAY_POST_RX; break; case BUGS_BIND_3: @@ -397,19 +391,15 @@ uint16_t ReadBUGS(void) A7105_WriteReg(A7105_03_FIFOI, BUGS_FIFO_SIZE_TX); A7105_WriteData(BUGS_PACKET_SIZE, hopping_frequency[hopping_frequency_no]); phase = BUGS_DATA_2; - packet_period = BUGS_DELAY_POST_TX; + packet_period = BUGS_DELAY_TX; break; case BUGS_DATA_2: - // wait here a bit for tx complete because - // need to start rx immediately to catch return packet - timeout = 20; - while (A7105_ReadReg(A7105_00_MODE) & 0x01) - if (timeout-- == 0) - { - packet_period = BUGS_DELAY_WAIT_TX; // don't proceed until transmission complete + //Wait for TX completion + start=micros(); + while ((uint16_t)micros()-start < 500) // Wait max 500µs, using serial+telemetry exit in about 60µs + if(!(A7105_ReadReg(A7105_00_MODE) & 0x01)) break; - } A7105_SetTxRxMode(RX_EN); A7105_WriteReg(A7105_0F_PLL_I, hopping_frequency[hopping_frequency_no] - 2); A7105_WriteReg(A7105_03_FIFOI, BUGS_FIFO_SIZE_RX); @@ -417,7 +407,7 @@ uint16_t ReadBUGS(void) BUGS_increment_counts(); phase = BUGS_DATA_3; - packet_period = BUGS_DELAY_WAIT_RX; + packet_period = BUGS_PACKET_PERIOD-BUGS_DELAY_TX-BUGS_DELAY_POST_RX; break; case BUGS_DATA_3: @@ -447,6 +437,13 @@ uint16_t ReadBUGS(void) uint16_t initBUGS(void) { + uint32_t radio_id=0; + uint8_t base_adr=BUGS_EEPROM_OFFSET+RX_num*4; + for(uint8_t i=0; i<4; i++) + radio_id|=eeprom_read_byte((EE_ADDR)(base_adr+i))<<(i*8); + if(radio_id==0xffffffff) + BIND_IN_PROGRESS; + BUGS_set_radio_data(); if (IS_BIND_IN_PROGRESS) phase = BUGS_BIND_1; @@ -457,9 +454,12 @@ uint16_t initBUGS(void) hopping_frequency_no = 0; packet_count = 0; - BUGS_armed = 0; - BUGS_arm_flags = BUGS_FLAG_DISARM; // initial value from captures - BUGS_arm_channel_previous = BUGS_CH_SW_ARM; + armed = 0; + arm_flags = BUGS_FLAG_DISARM; // initial value from captures + arm_channel_previous = BUGS_CH_SW_ARM; + #ifdef BUGS_HUB_TELEMETRY + init_frskyd_link_telemetry(); + #endif return 10000; } diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 9422433..cbe3d3f 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 1 -#define VERSION_PATCH_LEVEL 6 +#define VERSION_PATCH_LEVEL 7 //****************** // Protocols @@ -71,6 +71,7 @@ enum PROTOCOLS PROTO_BUGSMINI = 42, // =>NRF24L01 PROTO_TRAXXAS = 43, // =>CYRF6936 PROTO_NCC1701 = 44, // =>NRF24L01 + PROTO_E01X = 45, // =>NRF24L01 PROTO_TEST = 63, // =>NRF24L01 }; @@ -247,6 +248,11 @@ enum HITEC OPT_HUB = 1, MINIMA = 2, }; +enum E01X +{ + E012 = 0, + E015 = 1, +}; #define NONE 0 #define P_HIGH 1 @@ -365,7 +371,7 @@ enum MultiPacketTypes uint16_t debug_time=0; #define debug(msg, ...) {char buf[64]; sprintf(buf, msg, ##__VA_ARGS__); Serial.write(buf);} #define debugln(msg, ...) {char buf[64]; sprintf(buf, msg "\r\n", ##__VA_ARGS__); Serial.write(buf);} - #define debug_time(msg) { uint16_t debug_time_TCNT1=TCNT1; debug_time=debug_time_TCNT1-debug_time; debugln(msg "%u", debug_time); debug_time=debug_time_TCNT1; } + #define debug_time(msg) { uint16_t debug_time_TCNT1=TCNT1; debug_time=debug_time_TCNT1-debug_time; debugln(msg "%u", debug_time>>1); debug_time=debug_time_TCNT1; } #else #define debug(...) { } #define debugln(...) { } @@ -585,6 +591,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- BUGSMINI 42 TRAXXAS 43 NCC1701 44 + E01X 45 BindBit=> 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No @@ -712,6 +719,9 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- Q100 2 Q200 3 MR100 4 + sub_protocol==E01X + E012 0 + E015 1 Power value => 0x80 0=High/1=Low Stream[3] = option_protocol; From c3ff49e86e83e83afb276d2815cd6f287fb76799 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Tue, 6 Nov 2018 22:06:19 +0100 Subject: [PATCH 057/111] E01X new protocol New protocol E01X number 45 Sub protocol E012 number 0 Sub protocol E015 number 1 Channels: ARM_SW CH5 FLIP_SW CH6 LED_SW CH7 HEADLESS_SW CH8 RTH_SW CH9 --- Multiprotocol/E01X_nrf24l01.ino | 248 ++++++++++++++++++++++++++++++++ Multiprotocol/Multi.txt | 1 + Multiprotocol/Multiprotocol.h | 2 +- Multiprotocol/Multiprotocol.ino | 7 + Multiprotocol/NRF24l01_SPI.ino | 103 +++++++++++++ Multiprotocol/Validate.h | 1 + Multiprotocol/_Config.h | 5 +- 7 files changed, 365 insertions(+), 2 deletions(-) create mode 100644 Multiprotocol/E01X_nrf24l01.ino diff --git a/Multiprotocol/E01X_nrf24l01.ino b/Multiprotocol/E01X_nrf24l01.ino new file mode 100644 index 0000000..1b87832 --- /dev/null +++ b/Multiprotocol/E01X_nrf24l01.ino @@ -0,0 +1,248 @@ +/* + 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 . + */ +// compatible with E012 and E015 + +#if defined(E01X_NRF24L01_INO) + +#include "iface_nrf24l01.h" + +//Protocols constants +#define E01X_BIND_COUNT 500 +#define E01X_INITIAL_WAIT 500 +#define E01X_ADDRESS_LENGTH 5 + +#define E012_PACKET_PERIOD 4525 +#define E012_RF_BIND_CHANNEL 0x3c +#define E012_NUM_RF_CHANNELS 4 +#define E012_PACKET_SIZE 15 + +#define E015_PACKET_PERIOD 4500 // stock Tx=9000, but let's send more packets ... +#define E015_RF_CHANNEL 0x2d // 2445 MHz +#define E015_PACKET_SIZE 10 +#define E015_BIND_PACKET_SIZE 9 + +//Channels +#define E01X_ARM_SW CH5_SW +#define E01X_FLIP_SW CH6_SW +#define E01X_LED_SW CH7_SW +#define E01X_HEADLESS_SW CH8_SW +#define E01X_RTH_SW CH9_SW + +// E012 flags packet[1] +#define E012_FLAG_FLIP 0x40 +#define E012_FLAG_HEADLESS 0x10 +#define E012_FLAG_RTH 0x04 +// E012 flags packet[7] +#define E012_FLAG_EXPERT 0x02 + +// E015 flags packet[6] +#define E015_FLAG_DISARM 0x80 +#define E015_FLAG_ARM 0x40 +// E015 flags packet[7] +#define E015_FLAG_FLIP 0x80 +#define E015_FLAG_HEADLESS 0x10 +#define E015_FLAG_RTH 0x08 +#define E015_FLAG_LED 0x04 +#define E015_FLAG_EXPERT 0x02 +#define E015_FLAG_INTERMEDIATE 0x01 + +static void __attribute__((unused)) E015_check_arming() +{ + uint8_t arm_channel = E01X_ARM_SW; + + if (arm_channel != arm_channel_previous) + { + arm_channel_previous = arm_channel; + if (arm_channel) + { + armed = 1; + arm_flags ^= E015_FLAG_ARM; + } + else + { + armed = 0; + arm_flags ^= E015_FLAG_DISARM; + } + } +} + +static void __attribute__((unused)) E01X_send_packet(uint8_t bind) +{ + if(sub_protocol==E012) + { + packet_length=E012_PACKET_SIZE; + packet[0] = rx_tx_addr[1]; + if(bind) + { + packet[1] = 0xaa; + memcpy(&packet[2], hopping_frequency, E012_NUM_RF_CHANNELS); + memcpy(&packet[6], rx_tx_addr, E01X_ADDRESS_LENGTH); + rf_ch_num=E012_RF_BIND_CHANNEL; + } + else + { + packet[1] = 0x01 + | GET_FLAG(E01X_RTH_SW, E012_FLAG_RTH) + | GET_FLAG(E01X_HEADLESS_SW, E012_FLAG_HEADLESS) + | GET_FLAG(E01X_FLIP_SW, E012_FLAG_FLIP); + packet[2] = convert_channel_16b_limit(AILERON, 0xc8, 0x00); // aileron + packet[3] = convert_channel_16b_limit(ELEVATOR, 0x00, 0xc8); // elevator + packet[4] = convert_channel_16b_limit(RUDDER, 0xc8, 0x00); // rudder + packet[5] = convert_channel_16b_limit(THROTTLE, 0x00, 0xc8); // throttle + packet[6] = 0xaa; + packet[7] = E012_FLAG_EXPERT; // rate (0-2) + packet[8] = 0x00; + packet[9] = 0x00; + packet[10]= 0x00; + rf_ch_num=hopping_frequency[hopping_frequency_no++]; + hopping_frequency_no %= E012_NUM_RF_CHANNELS; + } + packet[11] = 0x00; + packet[12] = 0x00; + packet[13] = 0x56; + packet[14] = rx_tx_addr[2]; + } + else + { // E015 + if(bind) + { + packet[0] = 0x18; + packet[1] = 0x04; + packet[2] = 0x06; + // data phase address + memcpy(&packet[3], rx_tx_addr, E01X_ADDRESS_LENGTH); + // checksum + packet[8] = packet[3]; + for(uint8_t i=4; i<8; i++) + packet[8] += packet[i]; + packet_length=E015_BIND_PACKET_SIZE; + } + else + { + E015_check_arming(); + packet[0] = convert_channel_16b_limit(THROTTLE, 0, 225); // throttle + packet[1] = convert_channel_16b_limit(RUDDER, 225, 0); // rudder + packet[2] = convert_channel_16b_limit(AILERON, 0, 225); // aileron + packet[3] = convert_channel_16b_limit(ELEVATOR, 225, 0); // elevator + packet[4] = 0x20; // elevator trim + packet[5] = 0x20; // aileron trim + packet[6] = arm_flags; + packet[7] = E015_FLAG_EXPERT + | GET_FLAG(E01X_FLIP_SW, E015_FLAG_FLIP) + | GET_FLAG(E01X_LED_SW, E015_FLAG_LED) + | GET_FLAG(E01X_HEADLESS_SW,E015_FLAG_HEADLESS) + | GET_FLAG(E01X_RTH_SW, E015_FLAG_RTH); + packet[8] = 0; + // checksum + packet[9] = packet[0]; + for(uint8_t i=1; i<9; i++) + packet[9] += packet[i]; + packet_length=E015_PACKET_SIZE; + } + } + + // Power on, TX mode, CRC enabled + HS6200_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP)); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch_num); + + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); + NRF24L01_FlushTx(); + + // transmit packet twice in a row without waiting for + // the first one to complete, seems to help the hs6200 + // demodulator to start decoding. + HS6200_WritePayload(packet, packet_length); + HS6200_WritePayload(packet, packet_length); + + // Check and adjust transmission power. We do this after + // transmission to not bother with timeout after power + // settings change - we have plenty of time until next + // packet. + NRF24L01_SetPower(); +} + +static void __attribute__((unused)) E01X_init() +{ + NRF24L01_Initialize(); + NRF24L01_SetTxRxMode(TX_EN); + if(sub_protocol==E012) + HS6200_SetTXAddr((uint8_t *)"\x55\x42\x9C\x8F\xC9", E01X_ADDRESS_LENGTH); + else // E015 + HS6200_SetTXAddr((uint8_t *)"\x62\x54\x79\x38\x53", E01X_ADDRESS_LENGTH); + NRF24L01_FlushTx(); + NRF24L01_FlushRx(); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit + NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); + NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits + NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1 Mbps + NRF24L01_SetPower(); + NRF24L01_Activate(0x73); // Activate feature register + NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes + NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01); // Set feature bits on + NRF24L01_Activate(0x73); +} + +uint16_t E01X_callback() +{ + if(IS_BIND_IN_PROGRESS) + { + if (bind_counter == 0) + { + HS6200_SetTXAddr(rx_tx_addr, 5); + BIND_DONE; + } + else + { + E01X_send_packet(1); + bind_counter--; + } + } + else + E01X_send_packet(0); + return packet_period; +} + +static void __attribute__((unused)) E012_initialize_txid() +{ + // rf channels + uint32_t lfsr=random(0xfefefefe); + for(uint8_t i=0; i> (i*8)) & 0xff) % 0x32); +} + +uint16_t initE01X() +{ + BIND_IN_PROGRESS; + if(sub_protocol==E012) + { + E012_initialize_txid(); + packet_period=E012_PACKET_PERIOD; + } + else + { // E015 + packet_period=E015_PACKET_PERIOD; + rf_ch_num=E015_RF_CHANNEL; + armed = 0; + arm_flags = 0; + arm_channel_previous = E01X_ARM_SW; + } + E01X_init(); + bind_counter = E01X_BIND_COUNT; + hopping_frequency_no = 0; + return E01X_INITIAL_WAIT; +} + +#endif diff --git a/Multiprotocol/Multi.txt b/Multiprotocol/Multi.txt index b416a3b..8363a4c 100644 --- a/Multiprotocol/Multi.txt +++ b/Multiprotocol/Multi.txt @@ -42,4 +42,5 @@ 42,BUGSMINI 43,Traxxas 44,NCC1701 +45,E01X,E012,E015 63,Test diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index cbe3d3f..d8e8767 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 1 -#define VERSION_PATCH_LEVEL 7 +#define VERSION_PATCH_LEVEL 8 //****************** // Protocols diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 48b9b55..4cfa344 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -110,6 +110,7 @@ uint16_t seed; uint16_t failsafe_count; uint16_t state; uint8_t len; +uint8_t armed, arm_flags, arm_channel_previous; #if defined(FRSKYX_CC2500_INO) || defined(SFHSS_CC2500_INO) uint8_t calData[48]; @@ -1199,6 +1200,12 @@ static void protocol_init() remote_callback = NCC_callback; break; #endif + #if defined(E01X_NRF24L01_INO) + case PROTO_E01X: + next_callback=initE01X(); + remote_callback = E01X_callback; + break; + #endif #if defined(TEST_NRF24L01_INO) case PROTO_TEST: next_callback=initTest(); diff --git a/Multiprotocol/NRF24l01_SPI.ino b/Multiprotocol/NRF24l01_SPI.ino index 881e0a9..8c5f12c 100644 --- a/Multiprotocol/NRF24l01_SPI.ino +++ b/Multiprotocol/NRF24l01_SPI.ino @@ -490,6 +490,109 @@ uint8_t XN297_ReadEnhancedPayload(uint8_t* msg, uint8_t len) // End of XN297 emulation +// +// HS6200 emulation layer +/////////////////////////// +static uint8_t hs6200_crc; +static uint16_t hs6200_crc_init; +static uint8_t hs6200_tx_addr[5]; +static uint8_t hs6200_address_length; + +static const uint8_t hs6200_scramble[] = { + 0x80,0xf5,0x3b,0x0d,0x6d,0x2a,0xf9,0xbc, + 0x51,0x8e,0x4c,0xfd,0xc1,0x65,0xd0 }; // todo: find all 32 bytes ... + +void HS6200_SetTXAddr(const uint8_t* addr, uint8_t len) +{ + if(len < 4) + len = 4; + else if(len > 5) + len = 5; + + // use nrf24 address field as a longer preamble + if(addr[len-1] & 0x80) + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\x55\x55\x55\x55\x55", 5); + else + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\xaa\xaa\xaa\xaa\xaa", 5); + + // precompute address crc + hs6200_crc_init = 0xffff; + for(int i=0; i 0) + crc = crc16_update(crc, msg[pos+1], 1); + return crc; +} + +void HS6200_Configure(uint8_t flags) +{ + hs6200_crc = !!(flags & BV(NRF24L01_00_EN_CRC)); + flags &= ~(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO)); + NRF24L01_WriteReg(NRF24L01_00_CONFIG, flags & 0xff); +} + +void HS6200_WritePayload(uint8_t* msg, uint8_t len) +{ + uint8_t payload[32]; + const uint8_t no_ack = 1; // never ask for an ack + static uint8_t pid; + uint8_t pos = 0; + + if(len > sizeof(hs6200_scramble)) + len = sizeof(hs6200_scramble); + + // address + for(int i=hs6200_address_length-1; i>=0; i--) + payload[pos++] = hs6200_tx_addr[i]; + + // guard bytes + payload[pos++] = hs6200_tx_addr[0]; + payload[pos++] = hs6200_tx_addr[0]; + + // packet control field + payload[pos++] = ((len & 0x3f) << 2) | (pid & 0x03); + payload[pos] = (no_ack & 0x01) << 7; + pid++; + + // scrambled payload + if(len > 0) + { + payload[pos++] |= (msg[0] ^ hs6200_scramble[0]) >> 1; + for(uint8_t i=1; i> 1); + payload[pos] = (msg[len-1] ^ hs6200_scramble[len-1]) << 7; + } + + // crc + if(hs6200_crc) + { + uint16_t crc = hs6200_calc_crc(&payload[hs6200_address_length+2], len+2); + uint8_t hcrc = crc >> 8; + uint8_t lcrc = crc & 0xff; + payload[pos++] |= (hcrc >> 1); + payload[pos++] = (hcrc << 7) | (lcrc >> 1); + payload[pos++] = lcrc << 7; + } + + NRF24L01_WritePayload(payload, pos); +} +// +// End of HS6200 emulation +//////////////////////////// + /////////////// // LT8900 emulation layer uint8_t LT8900_buffer[64]; diff --git a/Multiprotocol/Validate.h b/Multiprotocol/Validate.h index af530a7..92ce4bc 100644 --- a/Multiprotocol/Validate.h +++ b/Multiprotocol/Validate.h @@ -183,6 +183,7 @@ #undef CFLIE_NRF24L01_INO #undef BUGSMINI_NRF24L01_INO #undef NCC1701_NRF24L01_INO + #undef E01X_NRF24L01_INO #endif //Make sure telemetry is selected correctly diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index c21c081..720b861 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -196,7 +196,7 @@ #define SYMAX_NRF24L01_INO #define V2X2_NRF24L01_INO #define YD717_NRF24L01_INO - +#define E01X_NRF24L01_INO /**************************/ /*** FAILSAFE SETTINGS ***/ @@ -578,6 +578,9 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= { NONE PROTO_NCC1701 NONE + PROTO_E01X + E012 + E015 */ // RX_Num is used for TX & RX match. Using different RX_Num values for each receiver will prevent starting a model with the false config loaded... From cf6d980b8bb93d571fd96ab1d928947b25b28807 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 6 Nov 2018 22:16:34 +0100 Subject: [PATCH 058/111] Update Protocols_Details.md --- Protocols_Details.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index 36ef400..2234247 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -604,6 +604,23 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11 ---|---|---|---|---|---|---|---|---|----|---- A|E|T|R|FLIP|LED|CAMERA1|CAMERA2|HEADLESS|RTH|RATE_LOW +## E01X - *45* +Autobind protocol + +### Sub_protocol E012 - *0* +Models: Eachine E012 + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R||FLIP||HEADLESS|RTH + +### Sub_protocol E015 - *1* +Models: Eachine E015 + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R|ARM|FLIP|LED|HEADLESS|RTH + ## ESKY - *16* CH1|CH2|CH3|CH4|CH5|CH6 From 3f0d6cfcf1c861a603f6c962b93432b03f39d72e Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Wed, 7 Nov 2018 10:48:11 +0100 Subject: [PATCH 059/111] Typo fix --- Multiprotocol/Multiprotocol.h | 2 +- Multiprotocol/Multiprotocol.ino | 2 +- Multiprotocol/NRF24l01_SPI.ino | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index d8e8767..b0b193c 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 1 -#define VERSION_PATCH_LEVEL 8 +#define VERSION_PATCH_LEVEL 9 //****************** // Protocols diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 4cfa344..fe597bf 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -110,7 +110,7 @@ uint16_t seed; uint16_t failsafe_count; uint16_t state; uint8_t len; -uint8_t armed, arm_flags, arm_channel_previous; +uint8_t armed, arm_flags, arm_channel_previous; #if defined(FRSKYX_CC2500_INO) || defined(SFHSS_CC2500_INO) uint8_t calData[48]; diff --git a/Multiprotocol/NRF24l01_SPI.ino b/Multiprotocol/NRF24l01_SPI.ino index 8c5f12c..7e71858 100644 --- a/Multiprotocol/NRF24l01_SPI.ino +++ b/Multiprotocol/NRF24l01_SPI.ino @@ -539,8 +539,8 @@ static uint16_t hs6200_calc_crc(uint8_t* msg, uint8_t len) void HS6200_Configure(uint8_t flags) { - hs6200_crc = !!(flags & BV(NRF24L01_00_EN_CRC)); - flags &= ~(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO)); + hs6200_crc = !!(flags & _BV(NRF24L01_00_EN_CRC)); + flags &= ~(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO)); NRF24L01_WriteReg(NRF24L01_00_CONFIG, flags & 0xff); } From c658a892f24dc8bbc2f0ea231d3993bd6a344847 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Wed, 7 Nov 2018 15:52:39 +0100 Subject: [PATCH 060/111] Fix some compilation issues --- Multiprotocol/E01X_nrf24l01.ino | 2 +- Multiprotocol/Multiprotocol.h | 4 ++-- Multiprotocol/Multiprotocol.ino | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Multiprotocol/E01X_nrf24l01.ino b/Multiprotocol/E01X_nrf24l01.ino index 1b87832..8cd341a 100644 --- a/Multiprotocol/E01X_nrf24l01.ino +++ b/Multiprotocol/E01X_nrf24l01.ino @@ -154,7 +154,7 @@ static void __attribute__((unused)) E01X_send_packet(uint8_t bind) } // Power on, TX mode, CRC enabled - HS6200_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP)); + HS6200_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP)); NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch_num); NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index b0b193c..4c855a1 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 1 -#define VERSION_PATCH_LEVEL 9 +#define VERSION_PATCH_LEVEL 10 //****************** // Protocols @@ -371,7 +371,7 @@ enum MultiPacketTypes uint16_t debug_time=0; #define debug(msg, ...) {char buf[64]; sprintf(buf, msg, ##__VA_ARGS__); Serial.write(buf);} #define debugln(msg, ...) {char buf[64]; sprintf(buf, msg "\r\n", ##__VA_ARGS__); Serial.write(buf);} - #define debug_time(msg) { uint16_t debug_time_TCNT1=TCNT1; debug_time=debug_time_TCNT1-debug_time; debugln(msg "%u", debug_time>>1); debug_time=debug_time_TCNT1; } + #define debug_time(msg) { uint16_t debug_time_TCNT1=TCNT1; debug_time=debug_time_TCNT1-debug_time; debug(msg "%u", debug_time>>1); debug_time=debug_time_TCNT1; } #else #define debug(...) { } #define debugln(...) { } diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index fe597bf..a336ae0 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -112,7 +112,7 @@ uint16_t state; uint8_t len; uint8_t armed, arm_flags, arm_channel_previous; -#if defined(FRSKYX_CC2500_INO) || defined(SFHSS_CC2500_INO) +#if defined(FRSKYX_CC2500_INO) || defined(SFHSS_CC2500_INO) || defined(HITEC_CC2500_INO) uint8_t calData[48]; #endif From 8bea5b125b12d91a74f1d592299c861143fb555b Mon Sep 17 00:00:00 2001 From: Ben Lye Date: Wed, 7 Nov 2018 14:54:17 +0000 Subject: [PATCH 061/111] Tweak protocol builds (#199) --- .travis.yml | 63 ++++++++------------------------------- buildroot/bin/opt_disable | 2 +- buildroot/bin/opt_enable | 2 +- 3 files changed, 14 insertions(+), 53 deletions(-) diff --git a/.travis.yml b/.travis.yml index d282c22..59989fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,6 +43,7 @@ before_install: # - buildMulti() { arduino --verify --board $BOARD Multiprotocol/Multiprotocol.ino; } - buildProtocol() { opt_disable $ALL_PROTOCOLS; opt_enable $1; buildMulti; } + - buildEachProtocol() { exitcode=0; for PROTOCOL in $ALL_PROTOCOLS ; do echo Building $PROTOCOL; buildProtocol $PROTOCOL; if [ $? -ne 0 ]; then exitcode=1; fi; echo; done; return $exitcode; } # install: true before_script: @@ -52,11 +53,15 @@ before_script: # Log the initial Multi config - cat Multiprotocol/_Config.h # Derive the Multi protocols from the Multi source - - A7105_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]]*_A7105_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h) - - CC2500_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]]*_CC2500_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h) - - CYRF6936_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]]*_CYRF6936_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h) - - NRF24L01_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]]*_NRF24L01_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h) - - ALL_PROTOCOLS=$(echo $A7105_PROTOCOLS $CC2500_PROTOCOLS $CYRF6936_PROTOCOLS $NRF24L01_PROTOCOLS) + - A7105_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_A7105_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h) + - CC2500_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_CC2500_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h) + - CYRF6936_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_CYRF6936_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h) + - NRF24L01_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_NRF24L01_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h) + - if [[ "$BOARD" =~ "multi4in1:avr:multixmega32d4" ]]; then + ALL_PROTOCOLS=$(echo $CYRF6936_PROTOCOLS); + else + ALL_PROTOCOLS=$(echo $A7105_PROTOCOLS $CC2500_PROTOCOLS $CYRF6936_PROTOCOLS $NRF24L01_PROTOCOLS); + fi - echo $ALL_PROTOCOLS # # Enable CHECK_FOR_BOOTLOADER when needed @@ -88,49 +93,5 @@ script: - opt_enable ENABLE_SERIAL - opt_enable ENABLE_PPM # - # Build each A7150 protocol - - buildProtocol AFHDS2A_A7105_INO - - buildProtocol FLYSKY_A7105_INO - - buildProtocol HUBSAN_A7105_INO - - buildProtocol BUGS_A7105_INO - # - # Build each CC2500 protocol - - buildProtocol CORONA_CC2500_INO - - buildProtocol FRSKYD_CC2500_INO - - buildProtocol FRSKYV_CC2500_INO - - buildProtocol FRSKYX_CC2500_INO - - buildProtocol HITEC_CC2500_INO - - buildProtocol SFHSS_CC2500_INO - # - # Build each CYRF6936 protocol - - buildProtocol DEVO_CYRF6936_INO - - buildProtocol DSM_CYRF6936_INO - - buildProtocol J6PRO_CYRF6936_INO - - buildProtocol WFLY_CYRF6936_INO - - buildProtocol WK2x01_CYRF6936_INO - # - # Build each NRF24L01 protocol - - buildProtocol ASSAN_NRF24L01_INO - - buildProtocol BAYANG_NRF24L01_INO - - buildProtocol CABELL_NRF24L01_INO - - buildProtocol CFLIE_NRF24L01_INO - - buildProtocol CG023_NRF24L01_INO - - buildProtocol CX10_NRF24L01_INO - - buildProtocol DM002_NRF24L01_INO - - buildProtocol ESKY_NRF24L01_INO - - buildProtocol ESKY150_NRF24L01_INO - - buildProtocol FQ777_NRF24L01_INO - - buildProtocol FY326_NRF24L01_INO - - buildProtocol GW008_NRF24L01_INO - - buildProtocol HISKY_NRF24L01_INO - - buildProtocol HONTAI_NRF24L01_INO - - buildProtocol H8_3D_NRF24L01_INO - - buildProtocol KN_NRF24L01_INO - - buildProtocol MJXQ_NRF24L01_INO - - buildProtocol MT99XX_NRF24L01_INO - - buildProtocol Q303_NRF24L01_INO - - buildProtocol SHENQI_NRF24L01_INO - - buildProtocol SLT_NRF24L01_INO - - buildProtocol SYMAX_NRF24L01_INO - - buildProtocol V2X2_NRF24L01_INO - - buildProtocol YD717_NRF24L01_INO + # Build each protocol individually + - buildEachProtocol diff --git a/buildroot/bin/opt_disable b/buildroot/bin/opt_disable index 26ead15..9a2515a 100755 --- a/buildroot/bin/opt_disable +++ b/buildroot/bin/opt_disable @@ -3,5 +3,5 @@ SED=$(which gsed || which sed) for opt in "$@" ; do - eval "${SED} -i 's/\([[:blank:]]*\)\(#define[[:blank:]]*\b${opt}\b\)/\1\/\/\2/g' Multiprotocol/_Config.h" + eval "${SED} -i 's/^\([[:blank:]]*\)\(#define[[:blank:]]*\b${opt}\b\)/\1\/\/\2/g' Multiprotocol/_Config.h" done diff --git a/buildroot/bin/opt_enable b/buildroot/bin/opt_enable index f1a5b81..6dacbb1 100755 --- a/buildroot/bin/opt_enable +++ b/buildroot/bin/opt_enable @@ -3,5 +3,5 @@ SED=$(which gsed || which sed) for opt in "$@" ; do - eval "${SED} -i 's/\/\/[[:blank:]]*\(#define[[:blank:]]*\b${opt}\b\)/\1/g' Multiprotocol/_Config.h" + eval "${SED} -i 's/\/\{2,\}[[:blank:]]*\(#define[[:blank:]]*\b${opt}\b\)/\1/g' Multiprotocol/_Config.h" done From 903982afb7b6f6f2a7a905b76ab868d171976477 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Fri, 9 Nov 2018 00:31:26 +0100 Subject: [PATCH 062/111] V911S protocol Protocol number 46 No sub protocol CH5: yaw calib --- Multiprotocol/Multi.txt | 1 + Multiprotocol/Multiprotocol.h | 9 +- Multiprotocol/Multiprotocol.ino | 6 ++ Multiprotocol/NRF24l01_SPI.ino | 42 ++++++-- Multiprotocol/V911S_nrf24l01.ino | 175 +++++++++++++++++++++++++++++++ Multiprotocol/Validate.h | 1 + Multiprotocol/_Config.h | 5 +- 7 files changed, 229 insertions(+), 10 deletions(-) create mode 100644 Multiprotocol/V911S_nrf24l01.ino diff --git a/Multiprotocol/Multi.txt b/Multiprotocol/Multi.txt index 8363a4c..2dd2b2e 100644 --- a/Multiprotocol/Multi.txt +++ b/Multiprotocol/Multi.txt @@ -43,4 +43,5 @@ 43,Traxxas 44,NCC1701 45,E01X,E012,E015 +46,V911S 63,Test diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 4c855a1..10bc929 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 1 -#define VERSION_PATCH_LEVEL 10 +#define VERSION_PATCH_LEVEL 11 //****************** // Protocols @@ -72,6 +72,7 @@ enum PROTOCOLS PROTO_TRAXXAS = 43, // =>CYRF6936 PROTO_NCC1701 = 44, // =>NRF24L01 PROTO_E01X = 45, // =>NRF24L01 + PROTO_V911S = 46, // =>NRF24L01 PROTO_TEST = 63, // =>NRF24L01 }; @@ -369,12 +370,13 @@ enum MultiPacketTypes //******************** #if defined(STM32_BOARD) && defined (DEBUG_SERIAL) uint16_t debug_time=0; - #define debug(msg, ...) {char buf[64]; sprintf(buf, msg, ##__VA_ARGS__); Serial.write(buf);} - #define debugln(msg, ...) {char buf[64]; sprintf(buf, msg "\r\n", ##__VA_ARGS__); Serial.write(buf);} + #define debug(msg, ...) {char debug_buf[64]; sprintf(debug_buf, msg, ##__VA_ARGS__); Serial.write(debug_buf);} + #define debugln(msg, ...) {char debug_buf[64]; sprintf(debug_buf, msg "\r\n", ##__VA_ARGS__); Serial.write(debug_buf);} #define debug_time(msg) { uint16_t debug_time_TCNT1=TCNT1; debug_time=debug_time_TCNT1-debug_time; debug(msg "%u", debug_time>>1); debug_time=debug_time_TCNT1; } #else #define debug(...) { } #define debugln(...) { } + #define debug_time(...) { } #undef DEBUG_SERIAL #endif @@ -592,6 +594,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- TRAXXAS 43 NCC1701 44 E01X 45 + V911S 46 BindBit=> 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index a336ae0..1a34ab6 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -1206,6 +1206,12 @@ static void protocol_init() remote_callback = E01X_callback; break; #endif + #if defined(V911S_NRF24L01_INO) + case PROTO_V911S: + next_callback=initV911S(); + remote_callback = V911S_callback; + break; + #endif #if defined(TEST_NRF24L01_INO) case PROTO_TEST: next_callback=initTest(); diff --git a/Multiprotocol/NRF24l01_SPI.ino b/Multiprotocol/NRF24l01_SPI.ino index 7e71858..22c64a0 100644 --- a/Multiprotocol/NRF24l01_SPI.ino +++ b/Multiprotocol/NRF24l01_SPI.ino @@ -457,16 +457,46 @@ void XN297_WriteEnhancedPayload(uint8_t* msg, uint8_t len, uint8_t noack, uint16 pid=0; } -void XN297_ReadPayload(uint8_t* msg, uint8_t len) -{ - // TODO: if xn297_crc==1, check CRC before filling *msg - NRF24L01_ReadPayload(msg, len); +boolean XN297_ReadPayload(uint8_t* msg, uint8_t len) +{ //!!! Don't forget if using CRC to do a +2 on any of the used NRF24L01_11_RX_PW_Px !!! + uint8_t buf[32]; + if (xn297_crc) + NRF24L01_ReadPayload(buf, len+2); // Read payload + CRC + else + NRF24L01_ReadPayload(buf, len); + // Decode payload for(uint8_t i=0; i> 8) == buf[len] && (crc & 0xff) == buf[len+1]) + return true; // CRC OK + return false; // CRC NOK } uint8_t XN297_ReadEnhancedPayload(uint8_t* msg, uint8_t len) diff --git a/Multiprotocol/V911S_nrf24l01.ino b/Multiprotocol/V911S_nrf24l01.ino new file mode 100644 index 0000000..9ca917b --- /dev/null +++ b/Multiprotocol/V911S_nrf24l01.ino @@ -0,0 +1,175 @@ +/* + 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 . + */ +// compatible with V911S + +#if defined(V911S_NRF24L01_INO) + +#include "iface_nrf24l01.h" + +//#define V911S_ORIGINAL_ID + +#define V911S_PACKET_PERIOD 5000 +#define V911S_BIND_PACKET_PERIOD 3300 +#define V911S_INITIAL_WAIT 500 +#define V911S_PACKET_SIZE 16 +#define V911S_RF_BIND_CHANNEL 35 +#define V911S_NUM_RF_CHANNELS 8 +#define V911S_BIND_COUNT 200 + +// flags going to packet[1] +#define V911S_FLAG_EXPERT 0x04 +// flags going to packet[2] +#define V911S_FLAG_CALIB 0x01 + +static void __attribute__((unused)) V911S_send_packet(uint8_t bind) +{ + if(bind) + { + packet[0] = 0x42; + packet[1] = 0x4E; + packet[2] = 0x44; + for(uint8_t i=0;i<5;i++) + packet[i+3] = rx_tx_addr[i]; + for(uint8_t i=0;i<8;i++) + packet[i+8] = hopping_frequency[i]; + } + else + { + uint8_t channel=hopping_frequency_no; + if(rf_ch_num&1) + { + if((hopping_frequency_no&1)==0) + channel+=8; + channel>>=1; + } + if(rf_ch_num&2) + channel=7-channel; + packet[ 0]=(rf_ch_num<<3)|channel; + packet[ 1]=V911S_FLAG_EXPERT; // short press on left button + packet[ 2]=GET_FLAG(CH5_SW,V911S_FLAG_CALIB); // long press on right button + memset(packet+3,0x00,14); + //packet[3..6]=trims TAER signed + uint16_t ch=convert_channel_16b_limit(THROTTLE ,0,0x7FF); + packet[ 7] = ch; + packet[ 8] = ch>>8; + ch=convert_channel_16b_limit(AILERON ,0,0x7FF); + packet[ 8]|= ch<<3; + packet[ 9] = ch>>5; + ch=convert_channel_16b_limit(ELEVATOR,0,0x7FF); + packet[10] = ch; + packet[11] = ch>>8; + ch=convert_channel_16b_limit(RUDDER ,0,0x7FF); + packet[11]|= ch<<3; + packet[12] = ch>>5; + } + + // Power on, TX mode, 2byte CRC + XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP)); + if (!bind) + { + NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[channel]); + hopping_frequency_no++; + hopping_frequency_no&=7; // 8 RF channels + } + // clear packet status bits and TX FIFO + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); + NRF24L01_FlushTx(); + XN297_WritePayload(packet, V911S_PACKET_SIZE); + + NRF24L01_SetPower(); // Set tx_power +} + +static void __attribute__((unused)) V911S_init() +{ + NRF24L01_Initialize(); + NRF24L01_SetTxRxMode(TX_EN); + XN297_SetTXAddr((uint8_t *)"\x4B\x4E\x42\x4E\x44", 5); // Bind address + NRF24L01_WriteReg(NRF24L01_05_RF_CH, V911S_RF_BIND_CHANNEL); // Bind channel + NRF24L01_FlushTx(); + NRF24L01_FlushRx(); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit + NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only + NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250Kbps + NRF24L01_SetPower(); +} + +static void __attribute__((unused)) V911S_initialize_txid() +{ + //channels + uint8_t offset=rx_tx_addr[3]%5; // 0-4 + for(uint8_t i=0;i Date: Fri, 9 Nov 2018 10:19:36 +0100 Subject: [PATCH 063/111] V911S mod Change AIL and RUD directions. --- Multiprotocol/Multiprotocol.h | 2 +- Multiprotocol/V911S_nrf24l01.ino | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 10bc929..183956c 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 1 -#define VERSION_PATCH_LEVEL 11 +#define VERSION_PATCH_LEVEL 12 //****************** // Protocols diff --git a/Multiprotocol/V911S_nrf24l01.ino b/Multiprotocol/V911S_nrf24l01.ino index 9ca917b..cda76aa 100644 --- a/Multiprotocol/V911S_nrf24l01.ino +++ b/Multiprotocol/V911S_nrf24l01.ino @@ -64,13 +64,13 @@ static void __attribute__((unused)) V911S_send_packet(uint8_t bind) uint16_t ch=convert_channel_16b_limit(THROTTLE ,0,0x7FF); packet[ 7] = ch; packet[ 8] = ch>>8; - ch=convert_channel_16b_limit(AILERON ,0,0x7FF); + ch=convert_channel_16b_limit(AILERON ,0x7FF,0); packet[ 8]|= ch<<3; packet[ 9] = ch>>5; ch=convert_channel_16b_limit(ELEVATOR,0,0x7FF); packet[10] = ch; packet[11] = ch>>8; - ch=convert_channel_16b_limit(RUDDER ,0,0x7FF); + ch=convert_channel_16b_limit(RUDDER ,0x7FF,0); packet[11]|= ch<<3; packet[12] = ch>>5; } From fb9f094365b6f4b5819874fae3e154d1e597965c Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sun, 11 Nov 2018 17:10:06 +0100 Subject: [PATCH 064/111] Update Protocols_Details.md --- Protocols_Details.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index 2234247..4777097 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -970,6 +970,13 @@ CH10|CH11|CH12 ---|---|--- Start/Stop|EMERGENCY|CAMERA_UP/DN +## V911S - *46* +Model: WLtoys V911S + +CH1|CH2|CH3|CH4|CH5 +---|---|---|---|--- +A|E|T|R|CALIB + ## YD717 - *8* Autobind protocol From b910ad33867ddfa29b340c4b87cd35332cca40a3 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Thu, 15 Nov 2018 11:08:07 +0100 Subject: [PATCH 065/111] New protocol GD00X Protocol number: 47 No sub protocol !!!! ONLY 1 ID AT THIS TIME !!!! CH1 AILERON CH3 THROTTLE CH5 TRIM CH6 LIGHT --- Multiprotocol/GD00X_nrf24l01.ino | 108 +++++++++++++++++++++++++++++++ Multiprotocol/Multi.txt | 1 + Multiprotocol/Multiprotocol.h | 4 +- Multiprotocol/Validate.h | 1 + Multiprotocol/_Config.h | 3 + 5 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 Multiprotocol/GD00X_nrf24l01.ino diff --git a/Multiprotocol/GD00X_nrf24l01.ino b/Multiprotocol/GD00X_nrf24l01.ino new file mode 100644 index 0000000..069437b --- /dev/null +++ b/Multiprotocol/GD00X_nrf24l01.ino @@ -0,0 +1,108 @@ +/* + 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 . + */ +// Compatible with GD005 C-17 and GD006 DA62 planes. + +#if defined(GD00X_NRF24L01_INO) + +#include "iface_nrf24l01.h" + +#define GD00X_ORIGINAL_ID + +#define GD00X_INITIAL_WAIT 500 +#define GD00X_PACKET_PERIOD 3500 +#define GD00X_RF_BIND_CHANNEL 2 +#define GD00X_PAYLOAD_SIZE 15 + +// flags going to packet[11] +#define GD00X_FLAG_DR 0x08 +#define GD00X_FLAG_LIGHT 0x04 + +static void __attribute__((unused)) GD00X_send_packet() +{ + packet[0] = IS_BIND_IN_PROGRESS?0xAA:0x55; + memcpy(void *(packet+1),rx_tx_addr,4); + uint16_t channel=convert_channel_ppm(AILERON); + packet[5 ] = channel; + packet[6 ] = channel>>8; + uint16_t channel=convert_channel_ppm(THROTTLE); + packet[7 ] = channel; + packet[8 ] = channel>>8; + uint16_t channel=convert_channel_ppm(CH5); // TRIM + packet[9 ] = channel; + packet[10] = channel>>8; + packet[11] = GD00X_FLAG_DR // Force high rate + | GETFLAG(CH6_SW, GD00X_FLAG_LIGHT); + packet[12] = 0x00; + packet[13] = 0x00; + packet[14] = 0x00; + + // Power on, TX mode, CRC enabled + XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP)); + if(IS_BIND_DONE) + { + NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]); + hopping_frequency_no &= 3; // 4 RF channels + } + + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); + NRF24L01_FlushTx(); + XN297_WritePayload(packet, GD00X_PAYLOAD_SIZE); + + NRF24L01_SetPower(); // Set tx_power +} + +static void __attribute__((unused)) GD00X_init() +{ + NRF24L01_Initialize(); + NRF24L01_SetTxRxMode(TX_EN); + XN297_SetTXAddr((uint8_t*)"\xcc\xcc\xcc\xcc\xcc", 5); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, GD00X_RF_BIND_CHANNEL); // Bind channel + NRF24L01_FlushTx(); + NRF24L01_FlushRx(); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit + NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only + NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250Kbps + NRF24L01_SetPower(); +} + +static void __attribute__((unused)) GD00X_initialize_txid() +{ + #ifdef GD00X_ORIGINAL_ID + rx_tx_addr[0]=0x1F; + rx_tx_addr[1]=0x39: + rx_tx_addr[2]=0x12; + rx_tx_addr[3]=0x13; + for(uint8_t i=0; i<4;i++) + hopping_frequency[0]=79-(i<<1); + #endif +} + +uint16_t GD00X_callback() +{ + GD00X_send_packet(); + return GD00X_PACKET_PERIOD; +} + +uint16_t initGD00X() +{ + BIND_IN_PROGRESS; // autobind protocol + GD00X_initialize_txid(); + GD00X_init(); + hopping_frequency_no = 0; + return GD00X_INITIAL_WAIT; +} + +#endif diff --git a/Multiprotocol/Multi.txt b/Multiprotocol/Multi.txt index 2dd2b2e..6674260 100644 --- a/Multiprotocol/Multi.txt +++ b/Multiprotocol/Multi.txt @@ -44,4 +44,5 @@ 44,NCC1701 45,E01X,E012,E015 46,V911S +47,GD00X 63,Test diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 183956c..f12946e 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 1 -#define VERSION_PATCH_LEVEL 12 +#define VERSION_PATCH_LEVEL 13 //****************** // Protocols @@ -73,6 +73,7 @@ enum PROTOCOLS PROTO_NCC1701 = 44, // =>NRF24L01 PROTO_E01X = 45, // =>NRF24L01 PROTO_V911S = 46, // =>NRF24L01 + PROTO_GD00X = 47, // =>NRF24L01 PROTO_TEST = 63, // =>NRF24L01 }; @@ -595,6 +596,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- NCC1701 44 E01X 45 V911S 46 + GD00X 47 BindBit=> 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No diff --git a/Multiprotocol/Validate.h b/Multiprotocol/Validate.h index 0f71ddb..b5d3f22 100644 --- a/Multiprotocol/Validate.h +++ b/Multiprotocol/Validate.h @@ -176,6 +176,7 @@ #undef HONTAI_NRF24L01_INO #undef Q303_NRF24L01_INO #undef GW008_NRF24L01_INO + #undef GD00X_NRF24L01_INO #undef DM002_NRF24L01_INO #undef CABELL_NRF24L01_INO #undef ESKY150_NRF24L01_INO diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 7a1f975..ca8f0ff 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -183,6 +183,7 @@ #define ESKY150_NRF24L01_INO #define FQ777_NRF24L01_INO #define FY326_NRF24L01_INO +#define GD00X_NRF24L01_INO #define GW008_NRF24L01_INO #define HISKY_NRF24L01_INO #define HONTAI_NRF24L01_INO @@ -584,6 +585,8 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= { E015 PROTO_V911S NONE + PROTO_GD00X + NONE */ // RX_Num is used for TX & RX match. Using different RX_Num values for each receiver will prevent starting a model with the false config loaded... From fd65550f8de7a5e8a28b237b6ef356b9d9805226 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Thu, 15 Nov 2018 22:32:50 +0100 Subject: [PATCH 066/111] Fix typos... --- Multiprotocol/GD00X_nrf24l01.ino | 14 +++++++------- Multiprotocol/GW008_nrf24l01.ino | 6 +++--- Multiprotocol/Multiprotocol.h | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Multiprotocol/GD00X_nrf24l01.ino b/Multiprotocol/GD00X_nrf24l01.ino index 069437b..8e65f06 100644 --- a/Multiprotocol/GD00X_nrf24l01.ino +++ b/Multiprotocol/GD00X_nrf24l01.ino @@ -18,7 +18,7 @@ Multiprotocol is distributed in the hope that it will be useful, #include "iface_nrf24l01.h" -#define GD00X_ORIGINAL_ID +#define FORCE_GD00X_ORIGINAL_ID #define GD00X_INITIAL_WAIT 500 #define GD00X_PACKET_PERIOD 3500 @@ -32,18 +32,18 @@ Multiprotocol is distributed in the hope that it will be useful, static void __attribute__((unused)) GD00X_send_packet() { packet[0] = IS_BIND_IN_PROGRESS?0xAA:0x55; - memcpy(void *(packet+1),rx_tx_addr,4); + memcpy(packet+1,rx_tx_addr,4); uint16_t channel=convert_channel_ppm(AILERON); packet[5 ] = channel; packet[6 ] = channel>>8; - uint16_t channel=convert_channel_ppm(THROTTLE); + channel=convert_channel_ppm(THROTTLE); packet[7 ] = channel; packet[8 ] = channel>>8; - uint16_t channel=convert_channel_ppm(CH5); // TRIM + channel=convert_channel_ppm(CH5); // TRIM packet[9 ] = channel; packet[10] = channel>>8; packet[11] = GD00X_FLAG_DR // Force high rate - | GETFLAG(CH6_SW, GD00X_FLAG_LIGHT); + | GET_FLAG(CH6_SW, GD00X_FLAG_LIGHT); packet[12] = 0x00; packet[13] = 0x00; packet[14] = 0x00; @@ -80,9 +80,9 @@ static void __attribute__((unused)) GD00X_init() static void __attribute__((unused)) GD00X_initialize_txid() { - #ifdef GD00X_ORIGINAL_ID + #ifdef FORCE_GD00X_ORIGINAL_ID rx_tx_addr[0]=0x1F; - rx_tx_addr[1]=0x39: + rx_tx_addr[1]=0x39; rx_tx_addr[2]=0x12; rx_tx_addr[3]=0x13; for(uint8_t i=0; i<4;i++) diff --git a/Multiprotocol/GW008_nrf24l01.ino b/Multiprotocol/GW008_nrf24l01.ino index 2296730..4824a90 100644 --- a/Multiprotocol/GW008_nrf24l01.ino +++ b/Multiprotocol/GW008_nrf24l01.ino @@ -32,7 +32,7 @@ enum { GW008_DATA }; -static void __attribute__((unused)) send_packet(uint8_t bind) +static void __attribute__((unused)) GW008_send_packet(uint8_t bind) { packet[0] = rx_tx_addr[0]; if(bind) @@ -123,7 +123,7 @@ uint16_t GW008_callback() { NRF24L01_SetTxRxMode(TXRX_OFF); NRF24L01_SetTxRxMode(TX_EN); - send_packet(1); + GW008_send_packet(1); phase = GW008_BIND2; return 300; } @@ -139,7 +139,7 @@ uint16_t GW008_callback() return 5000; break; case GW008_DATA: - send_packet(0); + GW008_send_packet(0); break; } return GW008_PACKET_PERIOD; diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index f12946e..6b9c8a4 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 1 -#define VERSION_PATCH_LEVEL 13 +#define VERSION_PATCH_LEVEL 14 //****************** // Protocols From a9df0abed3f8008326a0907b7eb72145e851eecc Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Thu, 15 Nov 2018 23:16:15 +0100 Subject: [PATCH 067/111] Update Multiprotocol/GD00X_nrf24l01.ino --- Multiprotocol/GD00X_nrf24l01.ino | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Multiprotocol/GD00X_nrf24l01.ino b/Multiprotocol/GD00X_nrf24l01.ino index 8e65f06..6c21ec6 100644 --- a/Multiprotocol/GD00X_nrf24l01.ino +++ b/Multiprotocol/GD00X_nrf24l01.ino @@ -24,6 +24,7 @@ Multiprotocol is distributed in the hope that it will be useful, #define GD00X_PACKET_PERIOD 3500 #define GD00X_RF_BIND_CHANNEL 2 #define GD00X_PAYLOAD_SIZE 15 +#define GD00X_BIND_COUNT 857 //3sec // flags going to packet[11] #define GD00X_FLAG_DR 0x08 @@ -92,6 +93,9 @@ static void __attribute__((unused)) GD00X_initialize_txid() uint16_t GD00X_callback() { + if(IS_BIND_IN_PROGRESS) + if(--bind_counter==0) + BIND_DONE; GD00X_send_packet(); return GD00X_PACKET_PERIOD; } @@ -102,6 +106,7 @@ uint16_t initGD00X() GD00X_initialize_txid(); GD00X_init(); hopping_frequency_no = 0; + bind_counter=GD00X_BIND_COUNT; return GD00X_INITIAL_WAIT; } From 22711fad289d4d1417fd9e916190951ddd159c06 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Thu, 15 Nov 2018 23:49:26 +0100 Subject: [PATCH 068/111] Update GD00X --- Multiprotocol/Multiprotocol.ino | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 1a34ab6..5a2b93f 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -1212,6 +1212,12 @@ static void protocol_init() remote_callback = V911S_callback; break; #endif + #if defined(GD00X_NRF24L01_INO) + case PROTO_GD00X: + next_callback=initGD00X(); + remote_callback = GD00X_callback; + break; + #endif #if defined(TEST_NRF24L01_INO) case PROTO_TEST: next_callback=initTest(); From b992cbd92e0320631ca87614c45e39276880d6b0 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 16 Nov 2018 00:36:52 +0100 Subject: [PATCH 069/111] New GD00X protocol --- Protocols_Details.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index 4777097..9a4e8f4 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -651,6 +651,15 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- A|E|T|R|FLIP|RTH|HEADLESS|EXPERT +## GD00X - *47* +Model: GD005 C-17 Transport and GD006 DA62 + +**Only 1 TX ID avaialble for now** + +CH1|CH2|CH3|CH4|CH5|CH6 +---|---|---|---|---|--- +A||T||TRIM|LED + ## GW008 - *32* Model: Global Drone GW008 from Banggood From dc902b7a614ebede361ae0996039fcde079999ed Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Fri, 16 Nov 2018 09:13:45 +0100 Subject: [PATCH 070/111] E01X test --- Multiprotocol/E01X_nrf24l01.ino | 4 ---- Multiprotocol/Multiprotocol.h | 2 +- Multiprotocol/NRF24l01_SPI.ino | 2 ++ 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Multiprotocol/E01X_nrf24l01.ino b/Multiprotocol/E01X_nrf24l01.ino index 8cd341a..ba348ca 100644 --- a/Multiprotocol/E01X_nrf24l01.ino +++ b/Multiprotocol/E01X_nrf24l01.ino @@ -160,10 +160,6 @@ static void __attribute__((unused)) E01X_send_packet(uint8_t bind) NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); NRF24L01_FlushTx(); - // transmit packet twice in a row without waiting for - // the first one to complete, seems to help the hs6200 - // demodulator to start decoding. - HS6200_WritePayload(packet, packet_length); HS6200_WritePayload(packet, packet_length); // Check and adjust transmission power. We do this after diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 6b9c8a4..c13d817 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 1 -#define VERSION_PATCH_LEVEL 14 +#define VERSION_PATCH_LEVEL 15 //****************** // Protocols diff --git a/Multiprotocol/NRF24l01_SPI.ino b/Multiprotocol/NRF24l01_SPI.ino index 22c64a0..40cb67e 100644 --- a/Multiprotocol/NRF24l01_SPI.ino +++ b/Multiprotocol/NRF24l01_SPI.ino @@ -618,6 +618,8 @@ void HS6200_WritePayload(uint8_t* msg, uint8_t len) } NRF24L01_WritePayload(payload, pos); + delayMicroseconds(option); + NRF24L01_WritePayload(payload, pos); } // // End of HS6200 emulation From 7fb4bbbf3c73edc05157c9dc8f9a15bc8ecbab4a Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Sat, 17 Nov 2018 09:08:23 +0100 Subject: [PATCH 071/111] GD00X fix --- Multiprotocol/GD00X_nrf24l01.ino | 2 +- Multiprotocol/Multiprotocol.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Multiprotocol/GD00X_nrf24l01.ino b/Multiprotocol/GD00X_nrf24l01.ino index 6c21ec6..7415ba2 100644 --- a/Multiprotocol/GD00X_nrf24l01.ino +++ b/Multiprotocol/GD00X_nrf24l01.ino @@ -87,7 +87,7 @@ static void __attribute__((unused)) GD00X_initialize_txid() rx_tx_addr[2]=0x12; rx_tx_addr[3]=0x13; for(uint8_t i=0; i<4;i++) - hopping_frequency[0]=79-(i<<1); + hopping_frequency[i]=79-(i<<1); #endif } diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index c13d817..cf538ce 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 1 -#define VERSION_PATCH_LEVEL 15 +#define VERSION_PATCH_LEVEL 16 //****************** // Protocols From 1525e564cbb96eb380ec19dc6d85bfa70558de67 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 20 Nov 2018 13:17:09 +0100 Subject: [PATCH 072/111] Update Protocols_Details.md --- Protocols_Details.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 9a4e8f4..ce1ce38 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -414,7 +414,7 @@ Notes: - model/type/number of channels indicated on the RX can be different from what the RX is in fact wanting to see. So don't hesitate to test different combinations until you have something working. Using Auto is the best way to find these settings. - RX output will match the Spektrum standard TAER independently of the input configuration AETR, RETA... - RX output will match the Spektrum standard throw (1500µs +/- 400µs -> 1100..1900µs) for a 100% input. This is true for both Serial and PPM input. For PPM, make sure the end points PPM_MIN_100 and PPM_MAX_100 in _config.h are matching your TX ouput. The maximum ouput is 1000..2000µs based on an input of 125%. - - If you want to override the above and get maximum throw (old way) uncomment in _config.h the line #define DSM_FULL_THROW . In this mode to achieve standard throw use a channel weight of 84%. + - If you want to override the above and get maximum throw (old way) uncomment in _config.h the line #define DSM_MAX_THROW . In this mode to achieve standard throw use a channel weight of 84%. ### Sub_protocol DSM2_22 - *0* DSM2, Resolution 1024, refresh rate 22ms From 6c7312a09c56f5e778ab30b5ec2560b8de7b919e Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Tue, 20 Nov 2018 16:54:55 +0100 Subject: [PATCH 073/111] DSM: Throttle Kill option --- Multiprotocol/DSM_cyrf6936.ino | 23 ++++++++++++++++++----- Multiprotocol/Multiprotocol.h | 2 +- Multiprotocol/Validate.h | 9 +++++++++ Multiprotocol/_Config.h | 23 +++++++++++++++++++---- 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/Multiprotocol/DSM_cyrf6936.ino b/Multiprotocol/DSM_cyrf6936.ino index dfe0cc6..ee8b654 100644 --- a/Multiprotocol/DSM_cyrf6936.ino +++ b/Multiprotocol/DSM_cyrf6936.ino @@ -262,7 +262,9 @@ static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper) if(sub_protocol==DSM2_22) bits=10; // Only DSM_22 is using a resolution of 1024 } - + #ifdef DSM_THROTTLE_KILL_CH + uint32_t kill_ch=Channel_data[DSM_THROTTLE_KILL_CH]; + #endif for (uint8_t i = 0; i < 7; i++) { uint8_t idx = ch_map[(upper?7:0) + i];//1,5,2,3,0,4 @@ -271,11 +273,22 @@ static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper) { /* Spektrum own remotes transmit normal values during bind and actually use this (e.g. Nano CP X) to select the transmitter mode (e.g. computer vs non-computer radio), so always send normal output */ - #ifdef DSM_MAX_THROW - value=Channel_data[CH_TAER[idx]]; // -100%..+100% => 1024..1976us and -125%..+125% => 904..2096us based on Redcon 6 channel DSM2 RX - #else - value=convert_channel_16b_nolimit(CH_TAER[idx],0x150,0x6B0); // -100%..+100% => 1100..1900us and -125%..+125% => 1000..2000us based on Redcon 6 channel DSM2 RX + #ifdef DSM_THROTTLE_KILL_CH + if(CH_TAER[idx]==THROTTLE && kill_ch<=604) + {//Activate throttle kill only if DSM_THROTTLE_KILL_CH below -50% + if(kill_ch904us ... -50%->1100us + } + else #endif + #ifdef DSM_MAX_THROW + value=Channel_data[CH_TAER[idx]]; // -100%..+100% => 1024..1976us and -125%..+125% => 904..2096us based on Redcon 6 channel DSM2 RX + #else + value=convert_channel_16b_nolimit(CH_TAER[idx],0x150,0x6B0); // -100%..+100% => 1100..1900us and -125%..+125% => 1000..2000us based on Redcon 6 channel DSM2 RX + #endif if(bits==10) value>>=1; value |= (upper && i==0 ? 0x8000 : 0) | (idx << bits); } diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index cf538ce..91c1f0b 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 1 -#define VERSION_PATCH_LEVEL 16 +#define VERSION_PATCH_LEVEL 17 //****************** // Protocols diff --git a/Multiprotocol/Validate.h b/Multiprotocol/Validate.h index b5d3f22..55e026a 100644 --- a/Multiprotocol/Validate.h +++ b/Multiprotocol/Validate.h @@ -273,6 +273,15 @@ #endif #endif +#if defined(DSM_THROTTLE_KILL_CH) + #if DSM_THROTTLE_KILL_CH<4 + #error DSM_THROTTLE_KILL_CH must be above 4. + #endif + #if DSM_THROTTLE_KILL_CH>16 + #error DSM_THROTTLE_KILL_CH must be below or equal to 16. + #endif +#endif + #if MIN_PPM_CHANNELS>16 #error MIN_PPM_CHANNELS must be below or equal to 16. The default for this value is 4. #endif diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index ca8f0ff..ba90828 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -49,10 +49,6 @@ //#define REVERSE_THROTTLE //#define REVERSE_RUDDER -//DSM protocol is using by default the Spektrum throw of 1100..1900us @100% and 1000..2000us @125%. -//For more throw, 1024..1976us @100% and 904..2096us @125%, remove the "//" on the line below. Be aware that too much throw can damage some UMX servos. To achieve standard throw in this mode use a channel weight of 84%. -//#define DSM_MAX_THROW - /*****************/ /*** AUTO BIND ***/ // Also referred as "Bind on powerup" @@ -200,6 +196,25 @@ #define V911S_NRF24L01_INO #define YD717_NRF24L01_INO + +/***************************/ +/*** PROTOCOLS SETTINGS ***/ +/***************************/ + +//DSM specific settings +//--------------------- +//The DSM protocol is using by default the Spektrum throw of 1100..1900us @100% and 1000..2000us @125%. +// For more throw, 1024..1976us @100% and 904..2096us @125%, remove the "//" on the line below. Be aware that too much throw can damage some UMX servos. To achieve standard throw in this mode use a channel weight of 84%. +//#define DSM_MAX_THROW +//Some models (X-Vert, Balde 230S...) require a special value to instant stop the motor(s). +// You can disable this feature by adding "//" on the line below. You have to specify which channel (15 by default) will be used to kill the throttle channel. +// If the channel is between -50% and -100%, the throttle output will be forced between -100% and -150%. If the channel is above -50%, the throttle is untouched. +#define DSM_THROTTLE_KILL_CH 15 + +//AFHDS2A specific settings +//------------------------- +//TODO: make LQI available on RX channel + /**************************/ /*** FAILSAFE SETTINGS ***/ /**************************/ From bd78739217338d1016c4220785625d535c8febe5 Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Tue, 20 Nov 2018 21:04:29 +0100 Subject: [PATCH 074/111] AFHDS2A: LQI to RX channel --- Multiprotocol/AFHDS2A_a7105.ino | 119 ++++++++++++++++++-------------- Multiprotocol/Multiprotocol.h | 2 +- Multiprotocol/Validate.h | 9 +++ Multiprotocol/_Config.h | 32 +++++---- 4 files changed, 94 insertions(+), 68 deletions(-) diff --git a/Multiprotocol/AFHDS2A_a7105.ino b/Multiprotocol/AFHDS2A_a7105.ino index 407045b..46a3838 100644 --- a/Multiprotocol/AFHDS2A_a7105.ino +++ b/Multiprotocol/AFHDS2A_a7105.ino @@ -86,50 +86,55 @@ enum{ static void AFHDS2A_update_telemetry() { + // Read TX RSSI + int16_t temp=256-(A7105_ReadReg(A7105_1D_RSSI_THOLD)*8)/5; // value from A7105 is between 8 for maximum signal strength to 160 or less + if(temp<0) temp=0; + else if(temp>255) temp=255; + TX_RSSI=temp; // AA | TXID | rx_id | sensor id | sensor # | value 16 bit big endian | sensor id ...... // max 7 sensors per packet -#ifdef AFHDS2A_FW_TELEMETRY - if (option & 0x80) - { - // forward telemetry to TX, skip rx and tx id to save space - pkt[0]= TX_RSSI; - for(int i=9;i < AFHDS2A_RXPACKET_SIZE; i++) - pkt[i-8]=packet[i]; - - telemetry_link=2; - return; - } -#endif -#ifdef AFHDS2A_HUB_TELEMETRY - for(uint8_t sensor=0; sensor<7; sensor++) - { - // Send FrSkyD telemetry to TX - uint8_t index = 9+(4*sensor); - switch(packet[index]) + #ifdef AFHDS2A_FW_TELEMETRY + if (option & 0x80) { - case AFHDS2A_SENSOR_RX_VOLTAGE: - //v_lipo1 = packet[index+3]<<8 | packet[index+2]; - v_lipo1 = packet[index+2]; - telemetry_link=1; - break; - case AFHDS2A_SENSOR_A3_VOLTAGE: - v_lipo2 = (packet[index+3]<<5) | (packet[index+2]>>3); // allows to read voltage up to 4S - telemetry_link=1; - break; - case AFHDS2A_SENSOR_RX_ERR_RATE: - RX_LQI=packet[index+2]; - break; - case AFHDS2A_SENSOR_RX_RSSI: - RX_RSSI = -packet[index+2]; - break; - case 0xff: - return; - /*default: - // unknown sensor ID - break;*/ + // forward telemetry to TX, skip rx and tx id to save space + pkt[0]= TX_RSSI; + for(int i=9;i < AFHDS2A_RXPACKET_SIZE; i++) + pkt[i-8]=packet[i]; + + telemetry_link=2; + return; } - } -#endif + #endif + #ifdef AFHDS2A_HUB_TELEMETRY + for(uint8_t sensor=0; sensor<7; sensor++) + { + // Send FrSkyD telemetry to TX + uint8_t index = 9+(4*sensor); + switch(packet[index]) + { + case AFHDS2A_SENSOR_RX_VOLTAGE: + //v_lipo1 = packet[index+3]<<8 | packet[index+2]; + v_lipo1 = packet[index+2]; + telemetry_link=1; + break; + case AFHDS2A_SENSOR_A3_VOLTAGE: + v_lipo2 = (packet[index+3]<<5) | (packet[index+2]>>3); // allows to read voltage up to 4S + telemetry_link=1; + break; + case AFHDS2A_SENSOR_RX_ERR_RATE: + RX_LQI=packet[index+2]; + break; + case AFHDS2A_SENSOR_RX_RSSI: + RX_RSSI = -packet[index+2]; + break; + case 0xff: + return; + /*default: + // unknown sensor ID + break;*/ + } + } + #endif } #endif @@ -169,6 +174,7 @@ static void AFHDS2A_build_bind_packet() static void AFHDS2A_build_packet(uint8_t type) { + uint16_t val; memcpy( &packet[1], rx_tx_addr, 4); memcpy( &packet[5], rx_id, 4); switch(type) @@ -181,6 +187,12 @@ static void AFHDS2A_build_packet(uint8_t type) packet[9 + ch*2] = channelMicros&0xFF; packet[10 + ch*2] = (channelMicros>>8)&0xFF; } + #ifdef AFHDS2A_LQI_CH + // override channel with LQI + val = 2000 - 10*RX_LQI; + packet[9+((AFHDS2A_LQI_CH-1)*2)] = val & 0xff; + packet[10+((AFHDS2A_LQI_CH-1)*2)] = (val >> 8) & 0xff; + #endif break; case AFHDS2A_PACKET_FAILSAFE: packet[0] = 0x56; @@ -206,10 +218,10 @@ static void AFHDS2A_build_packet(uint8_t type) packet[0] = 0xaa; packet[9] = 0xfd; packet[10]= 0xff; - uint16_t val_hz=5*(option & 0x7f)+50; // option value should be between 0 and 70 which gives a value between 50 and 400Hz - if(val_hz<50 || val_hz>400) val_hz=50; // default is 50Hz - packet[11]= val_hz; - packet[12]= val_hz >> 8; + val=5*(option & 0x7f)+50; // option value should be between 0 and 70 which gives a value between 50 and 400Hz + if(val<50 || val>400) val=50; // default is 50Hz + packet[11]= val; + packet[12]= val >> 8; if(sub_protocol == PPM_IBUS || sub_protocol == PPM_SBUS) packet[13] = 0x01; // PPM output enabled else @@ -324,17 +336,20 @@ uint16_t ReadAFHDS2A() { if(packet[9] == 0xfc) packet_type=AFHDS2A_PACKET_SETTINGS; // RX is asking for settings - #if defined(AFHDS2A_FW_TELEMETRY) || defined(AFHDS2A_HUB_TELEMETRY) else { - // Read TX RSSI - int16_t temp=256-(A7105_ReadReg(A7105_1D_RSSI_THOLD)*8)/5; // value from A7105 is between 8 for maximum signal strength to 160 or less - if(temp<0) temp=0; - else if(temp>255) temp=255; - TX_RSSI=temp; - AFHDS2A_update_telemetry(); + #ifdef AFHDS2A_LQI_CH + for(uint8_t sensor=0; sensor<7; sensor++) + {//read LQI value for RX output + uint8_t index = 9+(4*sensor); + if(packet[index]==AFHDS2A_SENSOR_RX_ERR_RATE) + RX_LQI=packet[index+2]; + } + #endif + #if defined(AFHDS2A_FW_TELEMETRY) || defined(AFHDS2A_HUB_TELEMETRY) + AFHDS2A_update_telemetry(); + #endif } - #endif } } packet_counter++; diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 91c1f0b..ee4a7e0 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 1 -#define VERSION_PATCH_LEVEL 17 +#define VERSION_PATCH_LEVEL 18 //****************** // Protocols diff --git a/Multiprotocol/Validate.h b/Multiprotocol/Validate.h index 55e026a..2dfc763 100644 --- a/Multiprotocol/Validate.h +++ b/Multiprotocol/Validate.h @@ -282,6 +282,15 @@ #endif #endif +#if defined(AFHDS2A_LQI_CH) + #if AFHDS2A_LQI_CH<4 + #error AFHDS2A_LQI_CH must be above 4. + #endif + #if AFHDS2A_LQI_CH>14 + #error AFHDS2A_LQI_CH must be below or equal to 14. + #endif +#endif + #if MIN_PPM_CHANNELS>16 #error MIN_PPM_CHANNELS must be below or equal to 16. The default for this value is 4. #endif diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index ba90828..ab7893e 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -213,7 +213,9 @@ //AFHDS2A specific settings //------------------------- -//TODO: make LQI available on RX channel +//When enabled (remove the "//"), the below setting makes LQI (Link Quality Indicator) available on one of the RX ouput channel (5-14). +//#define AFHDS2A_LQI_CH 14 + /**************************/ /*** FAILSAFE SETTINGS ***/ @@ -435,6 +437,20 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= { /* 14 */ {PROTO_MT99XX, MT99 , 0 , P_HIGH , NO_AUTOBIND , 0 }, #endif }; +// RX_Num is used for TX & RX match. Using different RX_Num values for each receiver will prevent starting a model with the false config loaded... +// RX_Num value is between 0 and 15. + +// Power P_HIGH or P_LOW: High or low power setting for the transmission. +// For indoor P_LOW is more than enough. + +// Auto Bind AUTOBIND or NO_AUTOBIND +// For protocols which does not require binding at each power up (like Flysky, FrSky...), you might still want a bind to be initiated each time you power up the TX. +// As an example, it's usefull for the WLTOYS F929/F939/F949/F959 (all using the Flysky protocol) which requires a bind at each power up. +// It also enables the Bind from channel feature, allowing to execute a bind by toggling a designated channel. + +// Option: the value is between -128 and +127. +// The option value is only valid for some protocols, read this page for more information: https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Protocols_Details.md + /* Available protocols and associated sub protocols to pick and choose from PROTO_FLYSKY Flysky @@ -603,17 +619,3 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= { PROTO_GD00X NONE */ - -// RX_Num is used for TX & RX match. Using different RX_Num values for each receiver will prevent starting a model with the false config loaded... -// RX_Num value is between 0 and 15. - -// Power P_HIGH or P_LOW: High or low power setting for the transmission. -// For indoor P_LOW is more than enough. - -// Auto Bind AUTOBIND or NO_AUTOBIND -// For protocols which does not require binding at each power up (like Flysky, FrSky...), you might still want a bind to be initiated each time you power up the TX. -// As an example, it's usefull for the WLTOYS F929/F939/F949/F959 (all using the Flysky protocol) which requires a bind at each power up. -// It also enables the Bind from channel feature, allowing to execute a bind by toggling a designated channel. - -// Option: the value is between -128 and +127. -// The option value is only valid for some protocols, read this page for more information: https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Protocols_Details.md From d990ebe49ef88565c8a9856257c1796c89e33e6f Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Tue, 20 Nov 2018 21:15:31 +0100 Subject: [PATCH 075/111] _Config.h file update --- Multiprotocol/Multiprotocol.h | 2 +- Multiprotocol/_Config.h | 258 +++++++++++++++++----------------- 2 files changed, 128 insertions(+), 132 deletions(-) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index ee4a7e0..d132933 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 1 -#define VERSION_PATCH_LEVEL 18 +#define VERSION_PATCH_LEVEL 19 //****************** // Protocols diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index ab7893e..1b95374 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -375,11 +375,11 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= { /* 6 */ {PROTO_DSM , DSM2_22 , 0 , P_HIGH , NO_AUTOBIND , 8 }, // option=number of channels /* 7 */ {PROTO_DSM , DSMX_11 , 0 , P_HIGH , NO_AUTOBIND , 8 }, // option=number of channels /* 8 */ {PROTO_DSM , DSMX_22 , 0 , P_HIGH , NO_AUTOBIND , 8 }, // option=number of channels -/* 9 */ {PROTO_SLT , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 9 */ {PROTO_SLT , SLT_V1 , 0 , P_HIGH , NO_AUTOBIND , 6 }, /* 10 */ {PROTO_HUBSAN, H107 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 11 */ {PROTO_HUBSAN, H301 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 12 */ {PROTO_HUBSAN, H501 , 0 , P_HIGH , NO_AUTOBIND , 0 }, -/* 13 */ {PROTO_HISKY , Hisky , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 13 */ {PROTO_HISKY, Hisky , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 14 */ {PROTO_V2X2 , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, #endif #if NBR_BANKS > 2 @@ -389,7 +389,7 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= { /* 2 */ {PROTO_ESKY150, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 3 */ {PROTO_ASSAN, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 4 */ {PROTO_CORONA, COR_V2 , 0 , P_HIGH , NO_AUTOBIND , 0 }, -/* 5 */ {PROTO_SYMAX , SYMAX , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 5 */ {PROTO_SYMAX, SYMAX , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 6 */ {PROTO_KN , WLTOYS , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 7 */ {PROTO_BAYANG, BAYANG , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 8 */ {PROTO_BAYANG, H8S3D , 0 , P_HIGH , NO_AUTOBIND , 0 }, @@ -451,53 +451,37 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= { // Option: the value is between -128 and +127. // The option value is only valid for some protocols, read this page for more information: https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Protocols_Details.md -/* Available protocols and associated sub protocols to pick and choose from - PROTO_FLYSKY - Flysky - V9X9 - V6X6 - V912 - CX20 - PROTO_HUBSAN - H107 - H301 - H501 - PROTO_FRSKYV +/* Available protocols and associated sub protocols to pick and choose from (Listed in alphabetical order) + PROTO_AFHDS2A + PWM_IBUS + PPM_IBUS + PWM_SBUS + PPM_SBUS + PROTO_ASSAN NONE - PROTO_FRSKYD + PROTO_BAYANG + BAYANG + H8S3D + X16_AH + IRDRONE + PROTO_BUGS NONE - PROTO_FRSKYX - CH_16 - CH_8 - EU_16 - EU_8 - PROTO_HISKY - Hisky - HK310 - PROTO_V2X2 - V2X2 - JXD506 - PROTO_DSM - DSM2_22 - DSM2_11 - DSMX_22 - DSMX_11 - PROTO_DEVO + PROTO_BUGSMINI NONE - PROTO_YD717 - YD717 - SKYWLKR - SYMAX4 - XINXUN - NIHUI - PROTO_KN - WLTOYS - FEILUN - PROTO_SYMAX - SYMAX - SYMAX5C - PROTO_SLT + PROTO_CABELL + CABELL_V3 + CABELL_V3_TELEMETRY + CABELL_SET_FAIL_SAFE + CABELL_UNBIND + PROTO_CFLIE NONE + PROTO_CG023 + CG023 + YD829 + PROTO_CORONA + COR_V1 + COR_V2 + FD_V3 PROTO_CX10 CX10_GREEN CX10_BLUE @@ -505,29 +489,72 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= { JC3015_1 JC3015_2 MK33041 - PROTO_Q2X2 - Q222 - Q242 - Q282 - PROTO_SLT - SLT - VISTA - PROTO_CG023 - CG023 - YD829 - PROTO_BAYANG - BAYANG - H8S3D - X16_AH - IRDRONE + PROTO_DEVO + NONE + PROTO_DM002 + NONE + PROTO_DSM + DSM2_22 + DSM2_11 + DSMX_22 + DSMX_11 + PROTO_E01X + E012 + E015 PROTO_ESKY NONE - PROTO_MT99XX - MT99 - H7 - YZ - LS - FY805 + PROTO_ESKY150 + NONE + PROTO_FLYSKY + Flysky + V9X9 + V6X6 + V912 + CX20 + PROTO_FQ777 + NONE + PROTO_FRSKYD + NONE + PROTO_FRSKYV + NONE + PROTO_FRSKYX + CH_16 + CH_8 + EU_16 + EU_8 + PROTO_FY326 + FY326 + FY319 + PROTO_GD00X + NONE + PROTO_GW008 + NONE + PROTO_H8_3D + H8_3D + H20H + H20MINI + H30MINI + PROTO_HISKY + Hisky + HK310 + PROTO_HITEC + OPT_FW + OPT_HUB + MINIMA + PROTO_HONTAI + HONTAI + JJRCX1 + X5C1 + FQ777_951 + PROTO_HUBSAN + H107 + H301 + H501 + PROTO_J6PRO + NONE + PROTO_KN + WLTOYS + FEILUN PROTO_MJXQ WLH08 X600 @@ -535,71 +562,26 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= { H26D E010 H26WH - PROTO_SHENQI + PROTO_MT99XX + MT99 + H7 + YZ + LS + FY805 + PROTO_NCC1701 NONE - PROTO_FY326 - FY326 - FY319 - PROTO_SFHSS - NONE - PROTO_J6PRO - NONE - PROTO_FQ777 - NONE - PROTO_ASSAN - NONE - PROTO_HONTAI - HONTAI - JJRCX1 - X5C1 - FQ777_951 - PROTO_AFHDS2A - PWM_IBUS - PPM_IBUS - PWM_SBUS - PPM_SBUS - PROTO_WK2x01 - WK2801 - WK2401 - W6_5_1 - W6_6_1 - W6_HEL - W6_HEL_I + PROTO_Q2X2 + Q222 + Q242 + Q282 PROTO_Q303 Q303 CX35 CX10D CX10WD - PROTO_GW008 + PROTO_SFHSS NONE - PROTO_DM002 - NONE - PROTO_CABELL - CABELL_V3 - CABELL_V3_TELEMETRY - CABELL_SET_FAIL_SAFE - CABELL_UNBIND - PROTO_ESKY150 - PROTO_H8_3D - H8_3D - H20H - H20MINI - H30MINI - PROTO_CORONA - COR_V1 - COR_V2 - FD_V3 - PROTO_CFLIE - NONE - PROTO_HITEC - OPT_FW - OPT_HUB - MINIMA - PROTO_WFLY - NONE - PROTO_BUGS - NONE - PROTO_BUGSMINI + PROTO_SHENQI NONE PROTO_SLT SLT_V1 @@ -607,15 +589,29 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= { Q100 Q200 MR100 + PROTO_SYMAX + SYMAX + SYMAX5C PROTO_TRAXXAS NONE - PROTO_NCC1701 - NONE - PROTO_E01X - E012 - E015 + PROTO_V2X2 + V2X2 + JXD506 PROTO_V911S NONE - PROTO_GD00X + PROTO_WFLY NONE + PROTO_WK2x01 + WK2801 + WK2401 + W6_5_1 + W6_6_1 + W6_HEL + W6_HEL_I + PROTO_YD717 + YD717 + SKYWLKR + SYMAX4 + XINXUN + NIHUI */ From 3a7ffe62b0ea7ffe82e5198a7ca11a0863bd06f0 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 21 Nov 2018 12:02:49 +0100 Subject: [PATCH 076/111] Update Compiling.md --- docs/Compiling.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/Compiling.md b/docs/Compiling.md index 31e3c32..34a5e77 100644 --- a/docs/Compiling.md +++ b/docs/Compiling.md @@ -122,14 +122,12 @@ There are two bootloader options: ### Upload the firmware You are now ready to upload the firmware to the multiprotocol module. There are two methods for uploading the firmware: -* **Flash from TX** uses the maintenance mode in radios running ersky9x to upload the firmware +* **Flash from TX** - uses the bootloader mode of radios running ersky9x or OpenTX to upload the firmware. The radio needs to run the latest bootloader with the Multi Flash app. * **Upload using Arduino IDE** uses the Arduino IDE and the USBasp programmer to upload the firmware -**Note:** 'Flash from TX' is only available with radios running ersky9x r221e2 or newer. - #### Flash from TX 1. In the Arduino IDE click **Sketch -> Export compiled Binary**, or press **Ctrl+Alt+S** -1. Locate the file named **multifw.hex** in the **Multiprotocol** folder +1. Locate the file named **multi-avr-x.x.x.x.hex** in the **Multiprotocol** folder (x.x.x.x is the multi version) 1. Follow the instructions [here](/docs/Flash_from_Tx.md) to upload the firmware using your radio You can disconnect the programmer now as it is not needed any more. From 300b3582a6c45744b7a1978bfb84f90dbfd69054 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 21 Nov 2018 12:03:20 +0100 Subject: [PATCH 077/111] Update Compiling.md --- docs/Compiling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Compiling.md b/docs/Compiling.md index 34a5e77..48af976 100644 --- a/docs/Compiling.md +++ b/docs/Compiling.md @@ -127,7 +127,7 @@ You are now ready to upload the firmware to the multiprotocol module. There are #### Flash from TX 1. In the Arduino IDE click **Sketch -> Export compiled Binary**, or press **Ctrl+Alt+S** -1. Locate the file named **multi-avr-x.x.x.x.hex** in the **Multiprotocol** folder (x.x.x.x is the multi version) +1. Locate the file named **multi-avr-x.x.x.x.hex** in the **Multiprotocol source folder** (x.x.x.x is the multi version) 1. Follow the instructions [here](/docs/Flash_from_Tx.md) to upload the firmware using your radio You can disconnect the programmer now as it is not needed any more. From e846ce7e988e33802f1472606496e301945f211d Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 21 Nov 2018 13:08:27 +0100 Subject: [PATCH 078/111] Update Compiling_STM32.md --- docs/Compiling_STM32.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/docs/Compiling_STM32.md b/docs/Compiling_STM32.md index f87045e..5209be2 100644 --- a/docs/Compiling_STM32.md +++ b/docs/Compiling_STM32.md @@ -88,14 +88,10 @@ The latest Jumper 4-in-1 modules come with a USB port but it's in fact a built i ### Select an Upload Method There are three methods to upload firmware to an STM32 module: -* **Flash from TX** - highly recommended, uses maintenance mode in radios running ersky9x or OpenTX to upload the firmware * **Upload via USB** - uses the USB port on the module +* **Flash from TX** - uses the bootloader mode of radios running ersky9x or OpenTX to upload the firmware. The radio needs to run the latest bootloader with the Multi Flash app. * **Upload via Serial inc. Bootloader (FTDI)** - uses the serial interface on the module via a USB-to-TTL adapter -**Note:** 'Flash from TX' is available with radios supporting ersky9x or OpenTX and running the latest bootloader with the Multi Flash app. - -**Flash from TX** is highly recommended if your transmitter supports it, **Upload via USB** is recommended for all others. **Upload via Serial inc. Bootloader** can be used if your module does not have a USB port and your transmitter does not run ersky9x or OpenTX. - 1. Under **Tools -> Upload Method** select an upload method The rest of this process will vary depending on the upload method you selected. @@ -172,7 +168,7 @@ Assuming the process is successful: ## Flash from TX 1. Click **Sketch -> Export compiled Binary**, or press **Ctrl+Alt+S** -1. Locate the file named **multifw.bin** in the **Multiprotocol** folder +1. Locate the file named **multi-stm-x.x.x.x.bin** in the **Multiprotocol source folder** folder (x.x.x.x is the multi version) 1. Follow the instructions [here](/docs/Flash_from_Tx.md) to upload the firmware using your radio ## Upload via USB From 5d1baa89e4415798874735a9bf2c985e05312a81 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 21 Nov 2018 14:11:24 +0100 Subject: [PATCH 079/111] Update Compiling_STM32.md --- docs/Compiling_STM32.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/docs/Compiling_STM32.md b/docs/Compiling_STM32.md index 5209be2..70a64cb 100644 --- a/docs/Compiling_STM32.md +++ b/docs/Compiling_STM32.md @@ -87,10 +87,14 @@ STM modules, until now, do not come with a preloaded bootloader which makes the The latest Jumper 4-in-1 modules come with a USB port but it's in fact a built in FTDI appearing on the computer as a CP2102 serial device. You should use the method **Upload via Serial inc. Bootloader** instead of Upload via USB. 'Flash from TX' is supported once the bootloader is installed. ### Select an Upload Method -There are three methods to upload firmware to an STM32 module: -* **Upload via USB** - uses the USB port on the module +There are a total of five firmware upload methods to an STM32 module: * **Flash from TX** - uses the bootloader mode of radios running ersky9x or OpenTX to upload the firmware. The radio needs to run the latest bootloader with the Multi Flash app. -* **Upload via Serial inc. Bootloader (FTDI)** - uses the serial interface on the module via a USB-to-TTL adapter +* **Auto Detect (USB or Serial)** - Detects automatically if the upload method is USB or Serial. You need to configure the correct COM port in the IDE which is created when plugging the module. +* **Upload via USB** - uses the USB upload method through the USB plug of the module. It requires the presence of a bootloader in the module. +* **Upload via Serial inc. Bootloader (FTDI)** - uses the serial interface of the module via a USB-to-TTL adapter to install the bootloader and firmware. +* **Upload via Serial (FTDI)** - uses the serial interface of the module via a USB-to-TTL adapter to install the firmware. + +You will most likely use only once on a brand new module the **Upload via Serial inc. Bootloader (FTDI)** method to load the bootloader+firmware. Any successive updates will be done using either **Auto Detect (USB or Serial)** or **Flash from TX** depending on your preference. 1. Under **Tools -> Upload Method** select an upload method @@ -226,14 +230,12 @@ After adding yourself to the groups as above and installing and running the udev **Note:** Some modules require external power in order for the USB port to work. If your module does not power on with USB power alone, install it in the transmitter and switch the transmitter on. It is generally safe for the module to recieve power from both USB and the transmitter. 1. Connect the USB cable to the Multiprotocol module -1. Verify that a Maple device appears (**Maple DFU** for a module with only a bootloader, **Maple Serial** for a module with a bootloader and firmware) - 1. On Windows look for the USB device in the Windows Device Manager - 1. On Mac OSX look in the System Information which is accessed by holding option and selecting the first item under the Apple Menu. Select the USB list on the left and look for the USB device. - 1. On Linux execute the command ```lsusb``` and examine the output. -1. select the correct COM port, which should be labelled **COMx (Multi 4-in-1 (STM32F103CB))**. If the device is in "DFU" mode, the module COM port will not appear, select any available COM port to continue the upload procedure. +1. Select the correct COM port, which should be labelled **COMx (Multi 4-in-1 (STM32F103CB))**..

1. In the Arduino IDE click **Sketch -> Upload**, or press **Ctrl+U** +**Note:** If the module appears as a **Maple DFU** for a module with only a bootloader, **Maple Serial** for a module with a bootloader and firmware then follow the same process by selecting any available COM port (you must select one, if you don't have one appearing plug any device that will create a com port (an Arduino board for example)). + You should see output similar to this: ``` Sketch uses 68564 bytes (52%) of program storage space. Maximum is 131072 bytes. @@ -263,7 +265,7 @@ Resetting USB to switch back to runtime mode error resetting after download: usb_reset: could not reset device, win error: The system cannot find the file specified. ``` -**Note:** The line `Reset via USB Serial Failed! Did you select the right serial port?` is expected because the uploader initially looks for a Maple Serial device, which isn't yet available, before failing back to Maple DFU. That error only appears the first time and won't appear when re-flashing firmware. The final line warning, stating that the device could not be reset, is also expected. +**Note:** The line `Reset via USB Serial Failed! Did you select the right serial port?` or a warning line stating that the device could not be reset is **not a problem**. ## Flashing pre-compiled binaries Pre-compiled binaries are available [here](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases). From 1d64cbfaa0802ca2aa71b21095f104543ddd70d2 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 21 Nov 2018 14:15:26 +0100 Subject: [PATCH 080/111] Update Compiling_STM32.md --- docs/Compiling_STM32.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Compiling_STM32.md b/docs/Compiling_STM32.md index 70a64cb..4e32e99 100644 --- a/docs/Compiling_STM32.md +++ b/docs/Compiling_STM32.md @@ -169,6 +169,7 @@ Assuming the process is successful: 1. Power off the transmitter 1. Remove the **BOOT0** jumper 1. Disconnect the USB-to-TTL adapter +1. Your module is ready to use, enjoy!!! ## Flash from TX 1. Click **Sketch -> Export compiled Binary**, or press **Ctrl+Alt+S** From c27ec2475c3a5733bb64641a6901ce4621a11122 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 21 Nov 2018 14:17:44 +0100 Subject: [PATCH 081/111] Update Compiling_STM32.md --- docs/Compiling_STM32.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Compiling_STM32.md b/docs/Compiling_STM32.md index 4e32e99..02a2568 100644 --- a/docs/Compiling_STM32.md +++ b/docs/Compiling_STM32.md @@ -177,7 +177,7 @@ Assuming the process is successful: 1. Follow the instructions [here](/docs/Flash_from_Tx.md) to upload the firmware using your radio ## Upload via USB -In order for the module to be correctly identified in Windows it is necessary to install drivers. This only needs to be done once. +In order for the module to be correctly identified it is necessary and only once to do some operations based on your operating system. ### Install the Maple USB drivers ##### Windows 7 or newer: From 866d19d6493f9d383f3adf958c003cbaa187fdaa Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 21 Nov 2018 14:23:55 +0100 Subject: [PATCH 082/111] Update Compiling_STM32.md --- docs/Compiling_STM32.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/Compiling_STM32.md b/docs/Compiling_STM32.md index 02a2568..9c0e024 100644 --- a/docs/Compiling_STM32.md +++ b/docs/Compiling_STM32.md @@ -172,6 +172,7 @@ Assuming the process is successful: 1. Your module is ready to use, enjoy!!! ## Flash from TX +1. Click **Tools -> Upload method -> Flash from TX** 1. Click **Sketch -> Export compiled Binary**, or press **Ctrl+Alt+S** 1. Locate the file named **multi-stm-x.x.x.x.bin** in the **Multiprotocol source folder** folder (x.x.x.x is the multi version) 1. Follow the instructions [here](/docs/Flash_from_Tx.md) to upload the firmware using your radio @@ -231,8 +232,8 @@ After adding yourself to the groups as above and installing and running the udev **Note:** Some modules require external power in order for the USB port to work. If your module does not power on with USB power alone, install it in the transmitter and switch the transmitter on. It is generally safe for the module to recieve power from both USB and the transmitter. 1. Connect the USB cable to the Multiprotocol module -1. Select the correct COM port, which should be labelled **COMx (Multi 4-in-1 (STM32F103CB))**.. -

+1. Click **Tools -> Upload method -> Flash from TX** +1. Select the correct COM port **Tools -> Port**, which should be labelled **COMx (Multi 4-in-1 (STM32F103CB))**.

1. In the Arduino IDE click **Sketch -> Upload**, or press **Ctrl+U** **Note:** If the module appears as a **Maple DFU** for a module with only a bootloader, **Maple Serial** for a module with a bootloader and firmware then follow the same process by selecting any available COM port (you must select one, if you don't have one appearing plug any device that will create a com port (an Arduino board for example)). From 7d4c8f7f07e85f2f745e27142c40afb7c32a0971 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 21 Nov 2018 14:26:05 +0100 Subject: [PATCH 083/111] Update Compiling_STM32.md --- docs/Compiling_STM32.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Compiling_STM32.md b/docs/Compiling_STM32.md index 9c0e024..d8f3931 100644 --- a/docs/Compiling_STM32.md +++ b/docs/Compiling_STM32.md @@ -232,7 +232,7 @@ After adding yourself to the groups as above and installing and running the udev **Note:** Some modules require external power in order for the USB port to work. If your module does not power on with USB power alone, install it in the transmitter and switch the transmitter on. It is generally safe for the module to recieve power from both USB and the transmitter. 1. Connect the USB cable to the Multiprotocol module -1. Click **Tools -> Upload method -> Flash from TX** +1. Click **Tools -> Upload method -> Auto Detect (USB or Serial)** 1. Select the correct COM port **Tools -> Port**, which should be labelled **COMx (Multi 4-in-1 (STM32F103CB))**.

1. In the Arduino IDE click **Sketch -> Upload**, or press **Ctrl+U** From 3a21bf69f15a1194a60da6dcf98e1eee60cdba18 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 21 Nov 2018 16:47:26 +0100 Subject: [PATCH 084/111] Update Flash_from_Tx.md --- docs/Flash_from_Tx.md | 49 +++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/docs/Flash_from_Tx.md b/docs/Flash_from_Tx.md index 8cf2e45..aae626a 100644 --- a/docs/Flash_from_Tx.md +++ b/docs/Flash_from_Tx.md @@ -1,33 +1,56 @@ # Flashing from the Transmitter -For radios running ersky9x r221e2 or newer, there is an option to flash a precompiled firmware file to the multiprotocol module using the transmitter's Maintenance Mode. +For radios running ersky9x and OpenTX, there is an option to flash a precompiled firmware file to the multiprotocol module using the transmitter's Bootloader mode. ## Tools required -* A compatible transmitter running ersky9x r221e2, or newer +* A compatible transmitter running an ersky9x bootloader v2.9 or newer. This is true for both OpenTX and ersky9x. * A precompiled multiprotocol firmware file (.hex for Atmega328p or .bin for STM32) * A **Flash from TX** bootloader installed on the multiprotocol module * A means to get the firmware file onto the transmitter's SD card -Consult the [ersky9x site](http://www.er9x.com/) to see if your transmitter is compatible. +## Radio bootloader and apps -The transmitter firmware can be downloaded from the [ersky9x test firmware page](http://openrcforums.com/forum/viewtopic.php?f=7&t=4676). +### How to check the bootloader version +1. Push both horizontals trims inwards (close to each others) +1. Power on the radio +1. The screen title should indicate `Boot Loader V2.9Ready` or newer +1. Launch the `FlashMulti_xxx.app` app from the `Run App` menu +1. The App version at the bottom right of the screen should be `28.Aug.18` or newer +1. If everything is correct you are ready to upgrade the Multimodule firmware -## Procedure +### Upgrade the bootloader and install app(s) +1. Download the latest zip file of the [ersky9x firmware](https://openrcforums.com/forum/viewtopic.php?f=7&t=4676) +1. Extract the .bin file corresponding to your radio in your SD card `\FIRMWARE` directory +1. Download the latest [Flash Multiprotocol Module app](http://www.er9x.com/Ersky9xapps.html) for your radio +1. Copy the .app file in a folder called `APPS` at the root of the SD card (if the directory does not exist create it) +1. For ersky9x + 1. Boot the radio in maintenance mode by pushing both horizontals trims outwards (away from each others) + 1. Select Upgrade Bootloader + 1. Select the ersky9x firmware matching your radio + 1. Long press it and select `Flash bootloader` +1. For OpenTX + 1. Boot the radio normaly + 1. Go in the RADIO SETUP menu page 2 called SD-HC CARD + 1. Open the FIRMWARE directory + 1. Select the ersky9x firmware matching your radio + 1. Long press it and select `Flash bootloader` +1. Check by rebooting the radio in bootloader mode that everything is [ok](###-How-to-check-the-bootloader-version) + +## Multimodule upgrade procedure 1. Either: 1. Connect the transmitter using a USB cable and power it on, or 1. Remove the SD card from the transmitter and mount it using a suitable reader -1. Copy the pre-compiled firmware file into the **\firmware** folder of the SD card (create the folder if it does not exist) +1. Copy the pre-compiled firmware file into the `\FIRMWARE` folder of the SD card (create the folder if it does not exist) 1. Power the transmitter off and remove the USB cable or put the SD card back in the transmitter -1. Enter the transmitter's Maintenance Menu by powering it on with the outer buttons of the two horizontal trims held down -1. Select **Update Multi**, +1. Push both horizontals trims inwards (close to each others) +1. Power on the radio +1. The screen title should indicate `Boot Loader V2.9Ready` or newer +1. Launch the `FlashMulti_xxx.app` app from the `Run App` menu 1. Choose the appropriate file type 1. **HEX** to update an Atmega328p module 1. **BIN** to update an STM32 module 1. Select **Update** 1. Choose the firmware file to flash, long press to select it 1. Long press again to flash the selected file to the module - -When flashing has finished, long press EXIT to reboot in normal mode. - -## Troubleshooting -TBD +1. When flashing has finished, long press EXIT to reboot in normal mode +1. If the flashing procedure fails try to redo with the process `Invert Com Port` enabled From 0eee1c5d1583e75665e99351dcc0a209a67dcd90 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 21 Nov 2018 16:57:17 +0100 Subject: [PATCH 085/111] Update Flash_from_Tx.md --- docs/Flash_from_Tx.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/Flash_from_Tx.md b/docs/Flash_from_Tx.md index aae626a..f0ba229 100644 --- a/docs/Flash_from_Tx.md +++ b/docs/Flash_from_Tx.md @@ -42,14 +42,13 @@ For radios running ersky9x and OpenTX, there is an option to flash a precompiled 1. Remove the SD card from the transmitter and mount it using a suitable reader 1. Copy the pre-compiled firmware file into the `\FIRMWARE` folder of the SD card (create the folder if it does not exist) 1. Power the transmitter off and remove the USB cable or put the SD card back in the transmitter -1. Push both horizontals trims inwards (close to each others) -1. Power on the radio +1. Push both horizontals trims inwards (close to each others) while powering on the radio 1. The screen title should indicate `Boot Loader V2.9Ready` or newer 1. Launch the `FlashMulti_xxx.app` app from the `Run App` menu 1. Choose the appropriate file type - 1. **HEX** to update an Atmega328p module - 1. **BIN** to update an STM32 module -1. Select **Update** + 1. `HEX` to update an Atmega328p module + 1. `BIN` to update an STM32 module +1. Select `Update` 1. Choose the firmware file to flash, long press to select it 1. Long press again to flash the selected file to the module 1. When flashing has finished, long press EXIT to reboot in normal mode From 43462757ed520eac585fbe8ad14ffbb6de92f13b Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 21 Nov 2018 16:58:44 +0100 Subject: [PATCH 086/111] Update Flash_from_Tx.md --- docs/Flash_from_Tx.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/Flash_from_Tx.md b/docs/Flash_from_Tx.md index f0ba229..899680a 100644 --- a/docs/Flash_from_Tx.md +++ b/docs/Flash_from_Tx.md @@ -11,8 +11,7 @@ For radios running ersky9x and OpenTX, there is an option to flash a precompiled ## Radio bootloader and apps ### How to check the bootloader version -1. Push both horizontals trims inwards (close to each others) -1. Power on the radio +1. Push both horizontals trims inwards (close to each others) while powering on the radio 1. The screen title should indicate `Boot Loader V2.9Ready` or newer 1. Launch the `FlashMulti_xxx.app` app from the `Run App` menu 1. The App version at the bottom right of the screen should be `28.Aug.18` or newer @@ -24,7 +23,7 @@ For radios running ersky9x and OpenTX, there is an option to flash a precompiled 1. Download the latest [Flash Multiprotocol Module app](http://www.er9x.com/Ersky9xapps.html) for your radio 1. Copy the .app file in a folder called `APPS` at the root of the SD card (if the directory does not exist create it) 1. For ersky9x - 1. Boot the radio in maintenance mode by pushing both horizontals trims outwards (away from each others) + 1. Power on the radio in maintenance mode while pushing both horizontals trims outwards (away from each others) 1. Select Upgrade Bootloader 1. Select the ersky9x firmware matching your radio 1. Long press it and select `Flash bootloader` From 42911c63b3003a24030f795d9220500425584564 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 21 Nov 2018 16:59:33 +0100 Subject: [PATCH 087/111] Update Flash_from_Tx.md --- docs/Flash_from_Tx.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Flash_from_Tx.md b/docs/Flash_from_Tx.md index 899680a..9fb3096 100644 --- a/docs/Flash_from_Tx.md +++ b/docs/Flash_from_Tx.md @@ -5,7 +5,7 @@ For radios running ersky9x and OpenTX, there is an option to flash a precompiled ## Tools required * A compatible transmitter running an ersky9x bootloader v2.9 or newer. This is true for both OpenTX and ersky9x. * A precompiled multiprotocol firmware file (.hex for Atmega328p or .bin for STM32) -* A **Flash from TX** bootloader installed on the multiprotocol module +* A **Flash from TX** bootloader installed on an Atmega328p or STM32 multiprotocol module * A means to get the firmware file onto the transmitter's SD card ## Radio bootloader and apps From b03491fdf7345c17fa652674c77ac84a1aa893ef Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 21 Nov 2018 19:20:51 +0100 Subject: [PATCH 088/111] Update Flash_from_Tx.md --- docs/Flash_from_Tx.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/Flash_from_Tx.md b/docs/Flash_from_Tx.md index 9fb3096..1fdecae 100644 --- a/docs/Flash_from_Tx.md +++ b/docs/Flash_from_Tx.md @@ -23,18 +23,20 @@ For radios running ersky9x and OpenTX, there is an option to flash a precompiled 1. Download the latest [Flash Multiprotocol Module app](http://www.er9x.com/Ersky9xapps.html) for your radio 1. Copy the .app file in a folder called `APPS` at the root of the SD card (if the directory does not exist create it) 1. For ersky9x - 1. Power on the radio in maintenance mode while pushing both horizontals trims outwards (away from each others) - 1. Select Upgrade Bootloader + 1. Power on the radio in `MAINTENANCE` mode while pushing both horizontals trims outwards (away from each others) + 1. Select `Update Bootloader` 1. Select the ersky9x firmware matching your radio 1. Long press it and select `Flash bootloader` 1. For OpenTX 1. Boot the radio normaly - 1. Go in the RADIO SETUP menu page 2 called SD-HC CARD - 1. Open the FIRMWARE directory + 1. Go in the `RADIO SETUP` menu page 2 called `SD-HC CARD` + 1. Open the `FIRMWARE` directory 1. Select the ersky9x firmware matching your radio 1. Long press it and select `Flash bootloader` 1. Check by rebooting the radio in bootloader mode that everything is [ok](###-How-to-check-the-bootloader-version) +**Note**: For OpenTX radio, this bootloader is an upgraded version of the existing bootloader shipped with OpenTX. It's providing you the exact same level of default features while adding more through apps. You can go back and forth between the 2 bootloaders without an issue. + ## Multimodule upgrade procedure 1. Either: 1. Connect the transmitter using a USB cable and power it on, or From eadfa26c3b07c6b45173ce7768712bd4719e3426 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 21 Nov 2018 20:03:13 +0100 Subject: [PATCH 089/111] Add files via upload --- docs/images/Bootloader.jpg | Bin 0 -> 266010 bytes docs/images/FlashMulti.jpg | Bin 0 -> 328230 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/images/Bootloader.jpg create mode 100644 docs/images/FlashMulti.jpg diff --git a/docs/images/Bootloader.jpg b/docs/images/Bootloader.jpg new file mode 100644 index 0000000000000000000000000000000000000000..81424bd3d7f6e8b0c85bdde38cce533337ba01e6 GIT binary patch literal 266010 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

STLCt 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