diff --git a/Multiprotocol/A7105_SPI.ino b/Multiprotocol/A7105_SPI.ino index 1698725..ad8f7be 100644 --- a/Multiprotocol/A7105_SPI.ino +++ b/Multiprotocol/A7105_SPI.ino @@ -191,10 +191,16 @@ const uint8_t PROGMEM HUBSAN_A7105_regs[] = { 0xFF, 0xFF, 0xFF }; 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 +*/ + -1, 0x42, 0x00, 0x14, 0x00, -1 , -1 , 0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x05, 0x00, 0x50, + 0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x00, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x0f, + 0x13, 0xc3, 0x00, -1, 0x00, 0x00, 0x3b, 0x00, 0x17, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, + 0x01, 0x0f, -1 }; #define ID_NORMAL 0x55201041 #define ID_PLUS 0xAA201041 diff --git a/Multiprotocol/DSM2_cyrf6936.ino b/Multiprotocol/DSM2_cyrf6936.ino index 928d24e..0882d77 100644 --- a/Multiprotocol/DSM2_cyrf6936.ino +++ b/Multiprotocol/DSM2_cyrf6936.ino @@ -114,14 +114,6 @@ uint8_t data_col; uint16_t cyrf_state; uint8_t crcidx; uint8_t binding; -/* -#ifdef USE_FIXED_MFGID -const uint8_t cyrfmfg_id[6] = {0x5e, 0x28, 0xa3, 0x1b, 0x00, 0x00}; //dx8 -const uint8_t cyrfmfg_id[6] = {0xd4, 0x62, 0xd6, 0xad, 0xd3, 0xff}; //dx6i -#else -//uint8_t cyrfmfg_id[6]; -#endif -*/ static void __attribute__((unused)) build_bind_packet() { diff --git a/Multiprotocol/ESky_nrf24l01.ino b/Multiprotocol/ESky_nrf24l01.ino index 1ed7d3d..7641a9d 100644 --- a/Multiprotocol/ESky_nrf24l01.ino +++ b/Multiprotocol/ESky_nrf24l01.ino @@ -117,7 +117,6 @@ static void __attribute__((unused)) ESKY_send_packet(uint8_t bind) // For arithmetic simplicity, channels are repeated in rf_channels array if (hopping_frequency_no == 0) { - const uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2}; for (uint8_t i = 0; i < 6; i++) { packet[i*2] = Servo_data[ch[i]]>>8; //high byte of servo timing(1000-2000us) diff --git a/Multiprotocol/FlySky_a7105.ino b/Multiprotocol/FlySky_a7105.ino index 8c5f956..f32ae11 100644 --- a/Multiprotocol/FlySky_a7105.ino +++ b/Multiprotocol/FlySky_a7105.ino @@ -22,51 +22,51 @@ #define FLYSKY_BIND_COUNT 2500 const uint8_t PROGMEM tx_channels[] = { - 0x0a, 0x5a, 0x14, 0x64, 0x1e, 0x6e, 0x28, 0x78, 0x32, 0x82, 0x3c, 0x8c, 0x46, 0x96, 0x50, 0xa0, - 0xa0, 0x50, 0x96, 0x46, 0x8c, 0x3c, 0x82, 0x32, 0x78, 0x28, 0x6e, 0x1e, 0x64, 0x14, 0x5a, 0x0a, - 0x0a, 0x5a, 0x50, 0xa0, 0x14, 0x64, 0x46, 0x96, 0x1e, 0x6e, 0x3c, 0x8c, 0x28, 0x78, 0x32, 0x82, - 0x82, 0x32, 0x78, 0x28, 0x8c, 0x3c, 0x6e, 0x1e, 0x96, 0x46, 0x64, 0x14, 0xa0, 0x50, 0x5a, 0x0a, - 0x28, 0x78, 0x0a, 0x5a, 0x50, 0xa0, 0x14, 0x64, 0x1e, 0x6e, 0x3c, 0x8c, 0x32, 0x82, 0x46, 0x96, - 0x96, 0x46, 0x82, 0x32, 0x8c, 0x3c, 0x6e, 0x1e, 0x64, 0x14, 0xa0, 0x50, 0x5a, 0x0a, 0x78, 0x28, - 0x50, 0xa0, 0x28, 0x78, 0x0a, 0x5a, 0x1e, 0x6e, 0x3c, 0x8c, 0x32, 0x82, 0x46, 0x96, 0x14, 0x64, - 0x64, 0x14, 0x96, 0x46, 0x82, 0x32, 0x8c, 0x3c, 0x6e, 0x1e, 0x5a, 0x0a, 0x78, 0x28, 0xa0, 0x50, - 0x50, 0xa0, 0x46, 0x96, 0x3c, 0x8c, 0x28, 0x78, 0x0a, 0x5a, 0x32, 0x82, 0x1e, 0x6e, 0x14, 0x64, - 0x64, 0x14, 0x6e, 0x1e, 0x82, 0x32, 0x5a, 0x0a, 0x78, 0x28, 0x8c, 0x3c, 0x96, 0x46, 0xa0, 0x50, - 0x46, 0x96, 0x3c, 0x8c, 0x50, 0xa0, 0x28, 0x78, 0x0a, 0x5a, 0x1e, 0x6e, 0x32, 0x82, 0x14, 0x64, - 0x64, 0x14, 0x82, 0x32, 0x6e, 0x1e, 0x5a, 0x0a, 0x78, 0x28, 0xa0, 0x50, 0x8c, 0x3c, 0x96, 0x46, - 0x46, 0x96, 0x0a, 0x5a, 0x3c, 0x8c, 0x14, 0x64, 0x50, 0xa0, 0x28, 0x78, 0x1e, 0x6e, 0x32, 0x82, - 0x82, 0x32, 0x6e, 0x1e, 0x78, 0x28, 0xa0, 0x50, 0x64, 0x14, 0x8c, 0x3c, 0x5a, 0x0a, 0x96, 0x46, - 0x46, 0x96, 0x0a, 0x5a, 0x50, 0xa0, 0x3c, 0x8c, 0x28, 0x78, 0x1e, 0x6e, 0x32, 0x82, 0x14, 0x64, - 0x64, 0x14, 0x82, 0x32, 0x6e, 0x1e, 0x78, 0x28, 0x8c, 0x3c, 0xa0, 0x50, 0x5a, 0x0a, 0x96, 0x46 + 0x0a, 0x5a, 0x14, 0x64, 0x1e, 0x6e, 0x28, 0x78, 0x32, 0x82, 0x3c, 0x8c, 0x46, 0x96, 0x50, 0xa0, + 0xa0, 0x50, 0x96, 0x46, 0x8c, 0x3c, 0x82, 0x32, 0x78, 0x28, 0x6e, 0x1e, 0x64, 0x14, 0x5a, 0x0a, + 0x0a, 0x5a, 0x50, 0xa0, 0x14, 0x64, 0x46, 0x96, 0x1e, 0x6e, 0x3c, 0x8c, 0x28, 0x78, 0x32, 0x82, + 0x82, 0x32, 0x78, 0x28, 0x8c, 0x3c, 0x6e, 0x1e, 0x96, 0x46, 0x64, 0x14, 0xa0, 0x50, 0x5a, 0x0a, + 0x28, 0x78, 0x0a, 0x5a, 0x50, 0xa0, 0x14, 0x64, 0x1e, 0x6e, 0x3c, 0x8c, 0x32, 0x82, 0x46, 0x96, + 0x96, 0x46, 0x82, 0x32, 0x8c, 0x3c, 0x6e, 0x1e, 0x64, 0x14, 0xa0, 0x50, 0x5a, 0x0a, 0x78, 0x28, + 0x50, 0xa0, 0x28, 0x78, 0x0a, 0x5a, 0x1e, 0x6e, 0x3c, 0x8c, 0x32, 0x82, 0x46, 0x96, 0x14, 0x64, + 0x64, 0x14, 0x96, 0x46, 0x82, 0x32, 0x8c, 0x3c, 0x6e, 0x1e, 0x5a, 0x0a, 0x78, 0x28, 0xa0, 0x50, + 0x50, 0xa0, 0x46, 0x96, 0x3c, 0x8c, 0x28, 0x78, 0x0a, 0x5a, 0x32, 0x82, 0x1e, 0x6e, 0x14, 0x64, + 0x64, 0x14, 0x6e, 0x1e, 0x82, 0x32, 0x5a, 0x0a, 0x78, 0x28, 0x8c, 0x3c, 0x96, 0x46, 0xa0, 0x50, + 0x46, 0x96, 0x3c, 0x8c, 0x50, 0xa0, 0x28, 0x78, 0x0a, 0x5a, 0x1e, 0x6e, 0x32, 0x82, 0x14, 0x64, + 0x64, 0x14, 0x82, 0x32, 0x6e, 0x1e, 0x5a, 0x0a, 0x78, 0x28, 0xa0, 0x50, 0x8c, 0x3c, 0x96, 0x46, + 0x46, 0x96, 0x0a, 0x5a, 0x3c, 0x8c, 0x14, 0x64, 0x50, 0xa0, 0x28, 0x78, 0x1e, 0x6e, 0x32, 0x82, + 0x82, 0x32, 0x6e, 0x1e, 0x78, 0x28, 0xa0, 0x50, 0x64, 0x14, 0x8c, 0x3c, 0x5a, 0x0a, 0x96, 0x46, + 0x46, 0x96, 0x0a, 0x5a, 0x50, 0xa0, 0x3c, 0x8c, 0x28, 0x78, 0x1e, 0x6e, 0x32, 0x82, 0x14, 0x64, + 0x64, 0x14, 0x82, 0x32, 0x6e, 0x1e, 0x78, 0x28, 0x8c, 0x3c, 0xa0, 0x50, 0x5a, 0x0a, 0x96, 0x46 }; enum { - // flags going to byte 10 - FLAG_V9X9_VIDEO = 0x40, - FLAG_V9X9_CAMERA= 0x80, - // flags going to byte 12 - FLAG_V9X9_UNK = 0x10, // undocumented ? - FLAG_V9X9_LED = 0x20, + // flags going to byte 10 + FLAG_V9X9_VIDEO = 0x40, + FLAG_V9X9_CAMERA= 0x80, + // flags going to byte 12 + FLAG_V9X9_FLIP = 0x10, + FLAG_V9X9_LED = 0x20, }; enum { - // flags going to byte 13 - FLAG_V6X6_HLESS1= 0x80, - // flags going to byte 14 - FLAG_V6X6_VIDEO = 0x01, - FLAG_V6X6_YCAL = 0x02, - FLAG_V6X6_XCAL = 0x04, - FLAG_V6X6_RTH = 0x08, - FLAG_V6X6_CAMERA= 0x10, - FLAG_V6X6_HLESS2= 0x20, - FLAG_V6X6_LED = 0x40, - FLAG_V6X6_FLIP = 0x80, + // flags going to byte 13 + FLAG_V6X6_HLESS1= 0x80, + // flags going to byte 14 + FLAG_V6X6_VIDEO = 0x01, + FLAG_V6X6_YCAL = 0x02, + FLAG_V6X6_XCAL = 0x04, + FLAG_V6X6_RTH = 0x08, + FLAG_V6X6_CAMERA= 0x10, + FLAG_V6X6_HLESS2= 0x20, + FLAG_V6X6_LED = 0x40, + FLAG_V6X6_FLIP = 0x80, }; enum { - // flags going to byte 14 - FLAG_V912_TOPBTN= 0x40, - FLAG_V912_BTMBTN= 0x80, + // flags going to byte 14 + FLAG_V912_TOPBTN= 0x40, + FLAG_V912_BTMBTN= 0x80, }; uint8_t chanrow; @@ -75,138 +75,139 @@ uint8_t chanoffset; static void __attribute__((unused)) flysky_apply_extension_flags() { - const uint8_t V912_X17_SEQ[10] = { 0x14, 0x31, 0x40, 0x49, 0x49, // sometime first byte is 0x15 ? - 0x49, 0x49, 0x49, 0x49, 0x49, }; - static uint8_t seq_counter; - switch(sub_protocol) - { - case V9X9: - if(Servo_AUX1) - packet[12] |= FLAG_V9X9_UNK; - if(Servo_AUX2) - packet[12] |= FLAG_V9X9_LED; - if(Servo_AUX3) - packet[10] |= FLAG_V9X9_CAMERA; - if(Servo_AUX4) - packet[10] |= FLAG_V9X9_VIDEO; - break; - - case V6X6: - packet[13] = 0x03; // 3 = 100% rate (0=40%, 1=60%, 2=80%) - packet[14] = 0x00; - if(Servo_AUX1) - packet[14] |= FLAG_V6X6_FLIP; - if(Servo_AUX2) - packet[14] |= FLAG_V6X6_LED; - if(Servo_AUX3) - packet[14] |= FLAG_V6X6_CAMERA; - if(Servo_AUX4) - packet[14] |= FLAG_V6X6_VIDEO; - if(Servo_AUX5) - { - packet[13] |= FLAG_V6X6_HLESS1; - packet[14] |= FLAG_V6X6_HLESS2; - } - if(Servo_AUX6) //use option to manipulate these bytes - packet[14] |= FLAG_V6X6_RTH; - if(Servo_AUX7) - packet[14] |= FLAG_V6X6_XCAL; - if(Servo_AUX8) - packet[14] |= FLAG_V6X6_YCAL; - packet[15] = 0x10; // unknown - packet[16] = 0x10; // unknown - packet[17] = 0xAA; // unknown - packet[18] = 0xAA; // unknown - packet[19] = 0x60; // unknown, changes at irregular interval in stock TX - packet[20] = 0x02; // unknown - break; - - case V912: - seq_counter++; - if( seq_counter > 9) - seq_counter = 0; - packet[12] |= 0x20; // bit 6 is always set ? - packet[13] = 0x00; // unknown - packet[14] = 0x00; - if(Servo_AUX1) - packet[14] = FLAG_V912_BTMBTN; - if(Servo_AUX2) - packet[14] |= FLAG_V912_TOPBTN; - packet[15] = 0x27; // [15] and [16] apparently hold an analog channel with a value lower than 1000 - packet[16] = 0x03; // maybe it's there for a pitch channel for a CP copter ? - packet[17] = V912_X17_SEQ[seq_counter]; // not sure what [17] & [18] are for - if(seq_counter == 0) // V912 Rx does not even read those bytes... [17-20] - packet[18] = 0x02; - else - packet[18] = 0x00; - packet[19] = 0x00; // unknown - packet[20] = 0x00; // unknown - break; - - default: - break; - } + const uint8_t V912_X17_SEQ[10] = { 0x14, 0x31, 0x40, 0x49, 0x49, // sometime first byte is 0x15 ? + 0x49, 0x49, 0x49, 0x49, 0x49, }; + static uint8_t seq_counter; + switch(sub_protocol) + { + case V9X9: + if(Servo_AUX1) + packet[12] |= FLAG_V9X9_FLIP; + if(Servo_AUX2) + packet[12] |= FLAG_V9X9_LED; + if(Servo_AUX3) + packet[10] |= FLAG_V9X9_CAMERA; + if(Servo_AUX4) + packet[10] |= FLAG_V9X9_VIDEO; + break; + + case V6X6: + packet[13] = 0x03; // 3 = 100% rate (0=40%, 1=60%, 2=80%) + packet[14] = 0x00; + if(Servo_AUX1) + packet[14] |= FLAG_V6X6_FLIP; + if(Servo_AUX2) + packet[14] |= FLAG_V6X6_LED; + if(Servo_AUX3) + packet[14] |= FLAG_V6X6_CAMERA; + if(Servo_AUX4) + packet[14] |= FLAG_V6X6_VIDEO; + if(Servo_AUX5) + { + packet[13] |= FLAG_V6X6_HLESS1; + packet[14] |= FLAG_V6X6_HLESS2; + } + if(Servo_AUX6) //use option to manipulate these bytes + packet[14] |= FLAG_V6X6_RTH; + if(Servo_AUX7) + packet[14] |= FLAG_V6X6_XCAL; + if(Servo_AUX8) + packet[14] |= FLAG_V6X6_YCAL; + packet[15] = 0x10; // unknown + packet[16] = 0x10; // unknown + packet[17] = 0xAA; // unknown + packet[18] = 0xAA; // unknown + packet[19] = 0x60; // unknown, changes at irregular interval in stock TX + packet[20] = 0x02; // unknown + break; + + case V912: + seq_counter++; + if( seq_counter > 9) + seq_counter = 0; + packet[12] |= 0x20; // bit 6 is always set ? + packet[13] = 0x00; // unknown + packet[14] = 0x00; + if(Servo_AUX1) + packet[14] = FLAG_V912_BTMBTN; + if(Servo_AUX2) + packet[14] |= FLAG_V912_TOPBTN; + packet[15] = 0x27; // [15] and [16] apparently hold an analog channel with a value lower than 1000 + packet[16] = 0x03; // maybe it's there for a pitch channel for a CP copter ? + packet[17] = V912_X17_SEQ[seq_counter]; // not sure what [17] & [18] are for + if(seq_counter == 0) // V912 Rx does not even read those bytes... [17-20] + packet[18] = 0x02; + else + packet[18] = 0x00; + packet[19] = 0x00; // unknown + packet[20] = 0x00; // unknown + break; + + default: + break; + } } static void __attribute__((unused)) flysky_build_packet(uint8_t init) { uint8_t i; - //servodata timing range for flysky. - ////-100% =~ 0x03e8//=1000us(min) - //+100% =~ 0x07ca//=1994us(max) - //Center = 0x5d9//=1497us(center) - //channel order AIL;ELE;THR;RUD;AUX1;AUX2;AUX3;AUX4 + //servodata timing range for flysky. + ////-100% =~ 0x03e8//=1000us(min) + //+100% =~ 0x07ca//=1994us(max) + //Center = 0x5d9//=1497us(center) + //channel order AIL;ELE;THR;RUD;AUX1;AUX2;AUX3;AUX4 packet[0] = init ? 0xaa : 0x55; packet[1] = rx_tx_addr[3]; packet[2] = rx_tx_addr[2]; packet[3] = rx_tx_addr[1]; packet[4] = rx_tx_addr[0]; - const uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4}; - for(i = 0; i < 8; i++) - { - packet[5+2*i]=lowByte(Servo_data[ch[i]]); //low byte of servo timing(1000-2000us) - packet[6+2*i]=highByte(Servo_data[ch[i]]); //high byte of servo timing(1000-2000us) - } + const uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4}; + for(i = 0; i < 8; i++) + { + packet[5+2*i]=lowByte(Servo_data[ch[i]]); //low byte of servo timing(1000-2000us) + packet[6+2*i]=highByte(Servo_data[ch[i]]); //high byte of servo timing(1000-2000us) + } flysky_apply_extension_flags(); } uint16_t ReadFlySky() { if (bind_counter) - { + { flysky_build_packet(1); A7105_WriteData(21, 1); bind_counter--; if (! bind_counter) BIND_DONE; } - else - { + else + { flysky_build_packet(0); A7105_WriteData(21, pgm_read_byte_near(&tx_channels[chanrow*16+chancol])-chanoffset); chancol = (chancol + 1) % 16; if (! chancol) //Keep transmit power updated - A7105_SetPower(); + A7105_SetPower(); } - return 1460; + return 1460; } uint16_t initFlySky() { - //A7105_Reset(); - A7105_Init(INIT_FLYSKY); //flysky_init(); - - if (rx_tx_addr[3] > 0x90) // limit offset to 9 as higher values don't work with some RX (ie V912) - rx_tx_addr[3] = rx_tx_addr[3] - 0x70; - chanrow=rx_tx_addr[3] % 16; - chancol=0; - chanoffset=rx_tx_addr[3] / 16; - + //A7105_Reset(); + A7105_Init(INIT_FLYSKY); //flysky_init(); + + if (rx_tx_addr[3] > 0x90) // limit offset to 9 as higher values don't work with some RX (ie V912) + rx_tx_addr[3] = rx_tx_addr[3] - 0x70; + chanrow=rx_tx_addr[3] % 16; + chancol=0; + chanoffset=rx_tx_addr[3] / 16; + - if(IS_AUTOBIND_FLAG_on) - bind_counter = FLYSKY_BIND_COUNT; - else - bind_counter = 0; - return 2400; + if(IS_AUTOBIND_FLAG_on) + bind_counter = FLYSKY_BIND_COUNT; + else + bind_counter = 0; + return 2400; } #endif + diff --git a/Multiprotocol/FrSkyX_cc2500.ino b/Multiprotocol/FrSkyX_cc2500.ino index 19044ef..dc6e2f2 100644 --- a/Multiprotocol/FrSkyX_cc2500.ino +++ b/Multiprotocol/FrSkyX_cc2500.ino @@ -43,101 +43,12 @@ 0x34, 0x1B, 0x00, 0x1D, 0x03 }; - uint8_t hop(uint8_t byte) + static uint8_t __attribute__((unused)) hop(uint8_t byte) { return pgm_read_byte_near(&hop_data[byte]); } - uint16_t initFrSkyX() - { - while(!chanskip) - { - randomSeed((uint32_t)analogRead(A6) << 10 | analogRead(A7)); - chanskip=random(0xfefefefe)%47; - } - while((chanskip-ctr)%4) - ctr=(ctr+1)%4; - - counter_rst=(chanskip-ctr)>>2; - //for test*************** - //rx_tx_addr[3]=0xB3; - //rx_tx_addr[2]=0xFD; - //************************ - frskyX_init(); - // - if(IS_AUTOBIND_FLAG_on) - { - state = FRSKY_BIND; - initialize_data(1); - } - else - { - state = FRSKY_DATA1; - initialize_data(0); - } - return 10000; - } - - uint16_t ReadFrSkyX() - { - switch(state) - { - default: - set_start(47); - CC2500_SetPower(); - cc2500_strobe(CC2500_SFRX); - // - frskyX_build_bind_packet(); - cc2500_strobe(CC2500_SIDLE); - cc2500_writeFifo(packet, packet[0]+1); - state++; - return 9000; - case FRSKY_BIND_DONE: - initialize_data(0); - channr=0; - BIND_DONE; - state++; - break; - case FRSKY_DATA1: - LED_ON; - CC2500_SetTxRxMode(TX_EN); - set_start(channr); - CC2500_SetPower(); - cc2500_strobe(CC2500_SFRX); - channr = (channr+chanskip)%47; - cc2500_strobe(CC2500_SIDLE); - cc2500_writeFifo(packet, packet[0]+1); - // - frskyX_data_frame(); - state++; - return 5500; - case FRSKY_DATA2: - CC2500_SetTxRxMode(RX_EN); - cc2500_strobe(CC2500_SIDLE); - state++; - return 200; - case FRSKY_DATA3: - cc2500_strobe(CC2500_SRX); - state++; - return 3000; - case FRSKY_DATA4: - len = cc2500_readReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F; - if (len &&(len>8) ^ byte) & 0xFF]); + return byte; + } + + static uint16_t __attribute__((unused)) scaleForPXX( uint8_t i ) + { //mapped 860,2140(125%) range to 64,1984(PXX values); + return (uint16_t)(((Servo_data[i]-PPM_MIN)*3)>>1)+64; + } + + static void __attribute__((unused)) frskyX_build_bind_packet() { crc=0; packet[0] = 0x1D; @@ -243,7 +159,7 @@ // } - void frskyX_data_frame() + static void __attribute__((unused)) frskyX_data_frame() { //0x1D 0xB3 0xFD 0x02 0x56 0x07 0x15 0x00 0x00 0x00 0x04 0x40 0x00 0x04 0x40 0x00 0x04 0x40 0x00 0x04 0x40 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x96 0x12 // @@ -302,14 +218,92 @@ packet[29]=lowByte(crc); } - uint16_t scaleForPXX( uint8_t i ) - { //mapped 860,2140(125%) range to 64,1984(PXX values); - return (uint16_t)(((Servo_data[i]-PPM_MIN)*3)>>1)+64; - } - - uint8_t crc_Byte( uint8_t byte ) + uint16_t ReadFrSkyX() { - crc = (crc<<8) ^ pgm_read_word(&CRCTable[((uint8_t)(crc>>8) ^ byte) & 0xFF]); - return byte; + switch(state) + { + default: + set_start(47); + CC2500_SetPower(); + cc2500_strobe(CC2500_SFRX); + // + frskyX_build_bind_packet(); + cc2500_strobe(CC2500_SIDLE); + cc2500_writeFifo(packet, packet[0]+1); + state++; + return 9000; + case FRSKY_BIND_DONE: + initialize_data(0); + channr=0; + BIND_DONE; + state++; + break; + case FRSKY_DATA1: + LED_ON; + CC2500_SetTxRxMode(TX_EN); + set_start(channr); + CC2500_SetPower(); + cc2500_strobe(CC2500_SFRX); + channr = (channr+chanskip)%47; + cc2500_strobe(CC2500_SIDLE); + cc2500_writeFifo(packet, packet[0]+1); + // + frskyX_data_frame(); + state++; + return 5500; + case FRSKY_DATA2: + CC2500_SetTxRxMode(RX_EN); + cc2500_strobe(CC2500_SIDLE); + state++; + return 200; + case FRSKY_DATA3: + cc2500_strobe(CC2500_SRX); + state++; + return 3000; + case FRSKY_DATA4: + len = cc2500_readReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F; + if (len &&(len>2; + //for test*************** + //rx_tx_addr[3]=0xB3; + //rx_tx_addr[2]=0xFD; + //************************ + frskyX_init(); + // + if(IS_AUTOBIND_FLAG_on) + { + state = FRSKY_BIND; + initialize_data(1); + } + else + { + state = FRSKY_DATA1; + initialize_data(0); + } + return 10000; + } #endif \ No newline at end of file diff --git a/Multiprotocol/FrSky_cc2500.ino b/Multiprotocol/FrSky_cc2500.ino index f3c6d3c..ec17450 100644 --- a/Multiprotocol/FrSky_cc2500.ino +++ b/Multiprotocol/FrSky_cc2500.ino @@ -38,45 +38,19 @@ static void __attribute__((unused)) frsky2way_init(uint8_t bind) // Configure cc2500 for tx mode CC2500_Reset(); // - cc2500_writeReg(CC2500_02_IOCFG0, 0x06); - cc2500_writeReg(CC2500_00_IOCFG2, 0x06); - cc2500_writeReg(CC2500_17_MCSM1, 0x0c); - cc2500_writeReg(CC2500_18_MCSM0, 0x18); - cc2500_writeReg(CC2500_06_PKTLEN, 0x19); - cc2500_writeReg(CC2500_07_PKTCTRL1, 0x04); - cc2500_writeReg(CC2500_08_PKTCTRL0, 0x05); - cc2500_writeReg(CC2500_3E_PATABLE, 0xff); - cc2500_writeReg(CC2500_0B_FSCTRL1, 0x08); - cc2500_writeReg(CC2500_0C_FSCTRL0, option); - //base freq FREQ = 0x5C7627 (F = 2404MHz) - cc2500_writeReg(CC2500_0D_FREQ2, 0x5c); - cc2500_writeReg(CC2500_0E_FREQ1, 0x76); - cc2500_writeReg(CC2500_0F_FREQ0, 0x27); - // - cc2500_writeReg(CC2500_10_MDMCFG4, 0xAA); - cc2500_writeReg(CC2500_11_MDMCFG3, 0x39); - cc2500_writeReg(CC2500_12_MDMCFG2, 0x11); - cc2500_writeReg(CC2500_13_MDMCFG1, 0x23); - cc2500_writeReg(CC2500_14_MDMCFG0, 0x7a); - cc2500_writeReg(CC2500_15_DEVIATN, 0x42); - cc2500_writeReg(CC2500_19_FOCCFG, 0x16); - cc2500_writeReg(CC2500_1A_BSCFG, 0x6c); - cc2500_writeReg(CC2500_1B_AGCCTRL2, bind ? 0x43 : 0x03); - cc2500_writeReg(CC2500_1C_AGCCTRL1,0x40); - cc2500_writeReg(CC2500_1D_AGCCTRL0,0x91); - cc2500_writeReg(CC2500_21_FREND1, 0x56); - cc2500_writeReg(CC2500_22_FREND0, 0x10); - cc2500_writeReg(CC2500_23_FSCAL3, 0xa9); - cc2500_writeReg(CC2500_24_FSCAL2, 0x0A); - cc2500_writeReg(CC2500_25_FSCAL1, 0x00); - cc2500_writeReg(CC2500_26_FSCAL0, 0x11); - cc2500_writeReg(CC2500_29_FSTEST, 0x59); - cc2500_writeReg(CC2500_2C_TEST2, 0x88); - cc2500_writeReg(CC2500_2D_TEST1, 0x31); - cc2500_writeReg(CC2500_2E_TEST0, 0x0B); - cc2500_writeReg(CC2500_03_FIFOTHR, 0x07); - cc2500_writeReg(CC2500_09_ADDR, 0x00); - // + for(uint8_t i=0;i<36;i++) + { + uint8_t reg=pgm_read_byte_near(&cc2500_conf[i][0]); + uint8_t val=pgm_read_byte_near(&cc2500_conf[i][1]); + + if(reg==CC2500_0C_FSCTRL0) + val=option; + else + if(reg==CC2500_1B_AGCCTRL2) + val=bind ? 0x43 : 0x03; + cc2500_writeReg(reg,val); + } + CC2500_SetTxRxMode(TX_EN); CC2500_SetPower(); diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index b16107e..109586c 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -45,8 +45,7 @@ uint8_t packet[40]; // Servo data uint16_t Servo_data[NUM_CHN]; uint8_t Servo_AUX; -// PPM variable -volatile uint16_t PPM_data[NUM_CHN]; +const uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4}; // Protocol variables uint8_t rx_tx_addr[5]; @@ -73,9 +72,11 @@ uint8_t RX_num; // Mode_select variables uint8_t mode_select; -uint8_t ppm_select=0, flag_decal=0; uint8_t protocol_flags=0,protocol_flags2=0; +// PPM variable +volatile uint16_t PPM_data[NUM_CHN]; + // Serial variables #define RXBUFFER_SIZE 25 #define TXBUFFER_SIZE 12 @@ -158,25 +159,24 @@ void setup() MProtocol_id_master=random_id(10,false); //Init RF modules - CC2500_Reset(); + #ifdef CC2500_INSTALLED + CC2500_Reset(); + #endif //Protocol and interrupts initialization - #if !defined(POTAR_SELECT) - if(mode_select == MODE_SERIAL) - { // Serial - cur_protocol[0]=0; - cur_protocol[1]=0; - prev_protocol=0; - Mprotocol_serial_init(); // Configure serial and enable RX interrupt - } - else - #else - if(mode_select==MODE_SERIAL) { flag_decal=1; } else { flag_decal=0;} - #endif + if(mode_select != MODE_SERIAL) { // PPM - prev_protocol=0; - CHANGE_PROTOCOL_FLAG_on; - update_ppm_data(); + mode_select--; + cur_protocol[0] = PPM_prot[mode_select].protocol; + sub_protocol = PPM_prot[mode_select].sub_proto; + RX_num = PPM_prot[mode_select].rx_num; + MProtocol_id = RX_num + MProtocol_id_master; + option = PPM_prot[mode_select].option; + if(PPM_prot[mode_select].power) POWER_FLAG_on; + if(PPM_prot[mode_select].autobind) AUTOBIND_FLAG_on; + mode_select++; + + protocol_init(); //Configure PPM interrupt EICRA |=(1<PPM_SWITCH) + if(Servo_data[AUX1+i]>PPM_SWITCH) Servo_AUX|=1<PPM_SWITCH) { - CHANGE_PROTOCOL_FLAG_on; - tone(BUZZER, BUZZER_HTZ); - delay(BUZZER_TPS); - noTone(BUZZER); - } - #endif - if(IS_CHANGE_PROTOCOL_FLAG_on) { - ppm_select = 10; - - if(mode_select == 0) { - while(ppm_select) { - while(!IS_PPM_FLAG_on) {} // wait - update_PPM_servo(); - if(Servo_data[AUX1] < PPM_MAX_100) { ppm_select--; } - } // attente de la d�activation du rebind - } - prev_protocol = ppm_select; - - // protocol selection - ppm_select = 0; - if(Servo_data[POTAR_SELECT_M] > PPM_MAX_COMMAND) { ppm_select += 18; } // THROTTLE up - else if(Servo_data[POTAR_SELECT_M] < PPM_MIN_COMMAND) { ppm_select += 9; } // THROTTLE down - else { ppm_select += 0; } // THROTTLE middle - - - if(Servo_data[POTAR_SELECT_V] > PPM_MAX_COMMAND) { ppm_select += 7; } // Elevator up - else if(Servo_data[POTAR_SELECT_V] < PPM_MIN_COMMAND) { ppm_select += 1; } // Elevator down - else { ppm_select += 4; } // Elevator middle - - if(Servo_data[POTAR_SELECT_H] > PPM_MAX_COMMAND) { ppm_select += 2; } // Aileron right - else if(Servo_data[POTAR_SELECT_H] < PPM_MIN_COMMAND) { ppm_select += 0; } // Aileron left - else { ppm_select += 1; } // Aileron middle - -// if(ppm_select == 5) { ppm_select = eeprom_read_byte(30); } else { eeprom_update_byte(30, ppm_select); } - - if(ppm_select != 5) { - if(ppm_select > 5) { ppm_select--; } - ppm_select--; - cur_protocol[0] = PPM_prot[ppm_select].protocol; - sub_protocol = PPM_prot[ppm_select].sub_proto; - MProtocol_id = PPM_prot[ppm_select].rx_num + MProtocol_id_master; - option = PPM_prot[ppm_select].option; - if(PPM_prot[ppm_select].power) POWER_FLAG_on; - if(PPM_prot[ppm_select].autobind) AUTOBIND_FLAG_on; - ppm_select++; - } - - while(Servo_data[THROTTLE] > PPM_MIN_100) { delay(100); update_PPM_servo(); } // attente de la remise des gaz � z�ro (pouss� � fond avec le script lua) - } -} static void update_serial_data() { if(rx_ok_buff[0]&0x20) //check range @@ -610,7 +594,7 @@ static void module_reset() case MODE_DEVO: CYRF_Reset(); break; - default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY, MODE_MT99XX, MODE_MJXQ + default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY, MODE_MT99XX, MODE_MJXQ, MODE_SHENQI NRF24L01_Reset(); break; } @@ -682,7 +666,6 @@ void Serial_write(uint8_t data) static void Mprotocol_serial_init() { - #define BAUD 100000 #include UBRR0H = UBRRH_VALUE; UBRR0L = UBRRL_VALUE; @@ -778,7 +761,6 @@ ISR(INT1_vect) } //Serial RX -#if !defined(POTAR_SELECT) ISR(USART_RX_vect) { // RX interrupt if((UCSR0A&0x1C)==0) // Check frame error, data overrun and parity error @@ -815,7 +797,6 @@ ISR(USART_RX_vect) idx=0; // Error encountered discard full frame... } } -#endif //Serial timer ISR(TIMER1_COMPB_vect) diff --git a/Multiprotocol/NRF24l01_SPI.ino b/Multiprotocol/NRF24l01_SPI.ino index cec1439..f95e86f 100644 --- a/Multiprotocol/NRF24l01_SPI.ino +++ b/Multiprotocol/NRF24l01_SPI.ino @@ -154,7 +154,7 @@ void NRF24L01_SetBitrate(uint8_t bitrate) // Note that bitrate 250kbps (and bit RF_DR_LOW) is valid only // for nRF24L01+. There is no way to programmatically tell it from // older version, nRF24L01, but the older is practically phased out - // by Nordic, so we assume that we deal with with modern version. + // by Nordic, so we assume that we deal with modern version. // Bit 0 goes to RF_DR_HIGH, bit 1 - to RF_DR_LOW rf_setup = (rf_setup & 0xD7) | ((bitrate & 0x02) << 4) | ((bitrate & 0x01) << 3); @@ -409,3 +409,196 @@ void XN297_ReadPayload(uint8_t* msg, uint8_t len) } // End of XN297 emulation + +/////////////// +// LT8910 emulation layer +uint8_t LT8910_buffer[64]; +uint8_t LT8910_buffer_start; +uint16_t LT8910_buffer_overhead_bits; +uint8_t LT8910_addr[8]; +uint8_t LT8910_addr_size; +uint8_t LT8910_Preamble_Len; +uint8_t LT8910_Tailer_Len; +uint8_t LT8910_CRC_Initial_Data; +uint8_t LT8910_Flags; +#define LT8910_CRC_ON 6 +#define LT8910_SCRAMBLE_ON 5 +#define LT8910_PACKET_LENGTH_EN 4 +#define LT8910_DATA_PACKET_TYPE_1 3 +#define LT8910_DATA_PACKET_TYPE_0 2 +#define LT8910_FEC_TYPE_1 1 +#define LT8910_FEC_TYPE_0 0 + +void LT8910_Config(uint8_t preamble_len, uint8_t trailer_len, uint8_t flags, uint8_t crc_init) +{ + //Preamble 1 to 8 bytes + LT8910_Preamble_Len=preamble_len; + //Trailer 4 to 18 bits + LT8910_Tailer_Len=trailer_len; + //Flags + // CRC_ON: 1 on, 0 off + // SCRAMBLE_ON: 1 on, 0 off + // PACKET_LENGTH_EN: 1 1st byte of payload is payload size + // DATA_PACKET_TYPE: 00 NRZ, 01 Manchester, 10 8bit/10bit line code, 11 interleave data type + // FEC_TYPE: 00 No FEC, 01 FEC13, 10 FEC23, 11 reserved + LT8910_Flags=flags; + //CRC init constant + LT8910_CRC_Initial_Data=crc_init; +} + +void LT8910_SetChannel(uint8_t channel) +{ + NRF24L01_WriteReg(NRF24L01_05_RF_CH, channel +2); //NRF24L01 is 2400+channel but LT8900 is 2402+channel +} + +void LT8910_SetTxRxMode(enum TXRX_State mode) +{ + if(mode == TX_EN) + { + //Switch to TX + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_SetTxRxMode(TX_EN); + //Disable CRC + NRF24L01_WriteReg(NRF24L01_00_CONFIG, (1 << NRF24L01_00_PWR_UP)); + } + else + if (mode == RX_EN) + { + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only + NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 32); + //Switch to RX + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_FlushRx(); + NRF24L01_SetTxRxMode(RX_EN); + // Disable CRC + NRF24L01_WriteReg(NRF24L01_00_CONFIG, (1 << NRF24L01_00_PWR_UP) | (1 << NRF24L01_00_PRIM_RX) ); + } + else + NRF24L01_SetTxRxMode(TXRX_OFF); +} + +void LT8910_BuildOverhead() +{ + uint8_t pos; + + //Build overhead + //preamble + memset(LT8910_buffer,LT8910_addr[0]&0x01?0xAA:0x55,LT8910_Preamble_Len-1); + pos=LT8910_Preamble_Len-1; + //address + for(uint8_t i=0;i5?5:pos; +} + +void LT8910_SetAddress(uint8_t *address,uint8_t addr_size) +{ + uint8_t addr[5]; + + //Address size (SyncWord) 2 to 8 bytes, 16/32/48/64 bits + LT8910_addr_size=addr_size; + memcpy(LT8910_addr,address,LT8910_addr_size); + + //Build overhead + LT8910_BuildOverhead(); + + //Set NRF RX&TX address based on overhead content + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, LT8910_buffer_start-2); + for(uint8_t i=0;i>8)&0xFF; + } + //Check len + if(LT8910_Flags&_BV(LT8910_PACKET_LENGTH_EN)) + { + crc=crc16_update(crc,buffer[pos]); + if(bit_reverse(len)!=buffer[pos++]) + return 0; // wrong len... + } + //Decode message + for(i=0;i>8)&0xFF)) return 0; // wrong CRC... + if(buffer[pos]!=(crc&0xFF)) return 0; // wrong CRC... + } + //Everything ok + return 1; +} + +void LT8910_WritePayload(uint8_t* msg, uint8_t len) +{ + unsigned int crc=LT8910_CRC_Initial_Data,a,mask; + uint8_t i, pos=0,tmp, buffer[64], pos_final,shift; + //Add packet len + if(LT8910_Flags&_BV(LT8910_PACKET_LENGTH_EN)) + { + tmp=bit_reverse(len); + buffer[pos++]=tmp; + crc=crc16_update(crc,tmp); + } + //Add payload + for(i=0;i>8; + buffer[pos++]=crc; + } + //Shift everything to fit behind the trailer (4 to 18 bits) + shift=LT8910_buffer_overhead_bits&0x7; + pos_final=LT8910_buffer_overhead_bits/8; + mask=~(0xFF<<(8-shift)); + LT8910_buffer[pos_final+pos]=0xFF; + for(i=pos-1;i!=0xFF;i--) + { + a=buffer[i]<<(8-shift); + LT8910_buffer[pos_final+i]=(LT8910_buffer[pos_final+i]&mask>>8)|a>>8; + LT8910_buffer[pos_final+i+1]=(LT8910_buffer[pos_final+i+1]&mask)|a; + } + if(shift) + pos++; + //Send everything + NRF24L01_WritePayload(LT8910_buffer+LT8910_buffer_start,pos_final+pos-LT8910_buffer_start); +} +// End of LT8910 emulation diff --git a/Multiprotocol/Nrf24l01_bluefly.ino b/Multiprotocol/Nrf24l01_bluefly.ino new file mode 100644 index 0000000..9e7364b --- /dev/null +++ b/Multiprotocol/Nrf24l01_bluefly.ino @@ -0,0 +1,183 @@ +/* + This project is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Deviation is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Deviation. If not, see . + */ + +#if defined(BlueFly_NRF24L01_INO) +#include "iface_nrf24l01.h" + +#define BIND_BlueFly_COUNT 800 + +#define TXID_BlueFly_SIZE 5 + +#define PAYLOAD_BlueFly_SIZE 12 +// available frequency must be in between 2402 and 2477 +static uint8_t hopping_frequency_start; + +static uint8_t bluefly_binding_adr_rf[TXID_BlueFly_SIZE]={0x32,0xaa,0x45,0x45,0x78}; // fixed binding ids for all planes +// bluefly_rf_adr_buf can be used for fixed id +static uint8_t bluefly_rf_adr_buf[TXID_BlueFly_SIZE]; // ={0x13,0x88,0x46,0x57,0x76}; + +static uint8_t bind_payload[PAYLOAD_BlueFly_SIZE]; + +static unsigned int ch_data_bluefly[8]; + + +static void bluefly_binding_packet(void) +{ + int i; + for (i = 0; i < TXID_BlueFly_SIZE; ++i) + bind_payload[i] = bluefly_rf_adr_buf[i]; + bind_payload[i++] = hopping_frequency_start; + for (; i < PAYLOAD_BlueFly_SIZE; ++i) bind_payload[i] = 0x55; +} + +static void bluefly_init() { + NRF24L01_Initialize(); + + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable p0 rx + NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknoledgement + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, bluefly_rf_adr_buf, 5); + NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, bluefly_rf_adr_buf, 5); + NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, PAYLOAD_BlueFly_SIZE); // payload size = 12 + NRF24L01_WriteReg(NRF24L01_05_RF_CH, 81); // binding packet must be set in channel 81 + + // 2-bytes CRC, radio on + NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP)); + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address (byte -2) + NRF24L01_SetBitrate(NRF24L01_BR_250K); // BlueFly - 250kbps + NRF24L01_SetPower(); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit +} + +// HiSky channel sequence: AILE ELEV THRO RUDD GEAR PITCH, channel data value is from 0 to 1000 +static void bluefly_ch_data() { + uint32_t temp; + int i; + for (i = 0; i< 8; ++i) { + temp = (uint32_t)Servo_data[ch[i]] * 300/PPM_MAX + 500; // 200-800 range + if (temp < 0) + ch_data_bluefly[i] = 0; + else if (temp > 1000) + ch_data_bluefly[i] = 1000; + else + ch_data_bluefly[i] = (unsigned int)temp; + + packet[i] = (uint8_t)ch_data_bluefly[i]; + } + + packet[8] = (uint8_t)((ch_data_bluefly[0]>>8)&0x0003); + packet[8] |= (uint8_t)((ch_data_bluefly[1]>>6)&0x000c); + packet[8] |= (uint8_t)((ch_data_bluefly[2]>>4)&0x0030); + packet[8] |= (uint8_t)((ch_data_bluefly[3]>>2)&0x00c0); + + packet[9] = (uint8_t)((ch_data_bluefly[4]>>8)&0x0003); + packet[9] |= (uint8_t)((ch_data_bluefly[5]>>6)&0x000c); + packet[9] |= (uint8_t)((ch_data_bluefly[6]>>4)&0x0030); + packet[9] |= (uint8_t)((ch_data_bluefly[7]>>2)&0x00c0); + + unsigned char l, h, t; + l = h = 0xff; + for (int i=0; i<10; ++i) { + h ^= packet[i]; + h ^= h >> 4; + t = h; + h = l; + l = t; + t = (l<<4) | (l>>4); + h ^= ((t<<2) | (t>>6)) & 0x1f; + h ^= t & 0xf0; + l ^= ((t<<1) | (t>>7)) & 0xe0; + } + // Checksum + packet[10] = h; + packet[11] = l; +} + +static uint16_t bluefly_cb() { + switch(phase++) { + case 0: + bluefly_ch_data(); + break; + case 1: + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, bluefly_rf_adr_buf, 5); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency_start + hopping_frequency_no*2); + hopping_frequency_no++; + hopping_frequency_no %= 15; + NRF24L01_FlushTx(); + NRF24L01_WritePayload(packet, PAYLOAD_BlueFly_SIZE); + break; + case 2: + break; + case 3: + if (counter>0) { + counter--; + if (! counter) { BIND_DONE; } + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, bluefly_binding_adr_rf, 5); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, 81); + NRF24L01_FlushTx(); + NRF24L01_WritePayload(bind_payload, PAYLOAD_BlueFly_SIZE); + } + break; + case 4: + break; + case 5: + NRF24L01_SetPower(); + /* FALLTHROUGH */ + default: + phase = 0; + break; + } + return 1000; // send 1 binding packet and 1 data packet per 9ms +} + +// Generate internal id from TX id and manufacturer id (STM32 unique id) +static void initialize_tx_id() { + uint32_t lfsr = 0x7649eca9ul; + + if (Model.fixed_id) { + for (uint8_t i = 0, j = 0; i < sizeof(Model.fixed_id); ++i, j += 8) + rand32_r(&lfsr, (Model.fixed_id >> j) & 0xff); + } + // Pump zero bytes for LFSR to diverge more + for (int i = 0; i < TXID_BlueFly_SIZE; ++i) rand32_r(&lfsr, 0); + + for (uint8_t i = 0; i < TXID_BlueFly_SIZE; ++i) { + bluefly_rf_adr_buf[i] = lfsr & 0xff; + rand32_r(&lfsr, i); + } + + printf("Effective id: %02X%02X%02X%02X%02X\r\n", bluefly_rf_adr_buf[0], bluefly_rf_adr_buf[1], bluefly_rf_adr_buf[2], bluefly_rf_adr_buf[3], bluefly_rf_adr_buf[4]); + + // Use LFSR to seed frequency hopping sequence after another + // divergence round + for (uint8_t i = 0; i < sizeof(lfsr); ++i) rand32_r(&lfsr, 0); + hopping_frequency_start = ((lfsr >> 8) % 47) + 2; + bluefly_binding_packet(); +} + +static uint16_t BlueFly_setup() { + initialize_tx_id(); + + bluefly_init(); + + if(IS_AUTOBIND_FLAG_on) { + counter = BIND_BlueFly_COUNT; +// PROTOCOL_SetBindState(BIND_BlueFly_COUNT * 10); //8 seconds binding time + } else { + counter = 0; + } + + return 1000; +} +#endif diff --git a/Multiprotocol/Nrf24l01_esky150.ino b/Multiprotocol/Nrf24l01_esky150.ino new file mode 100644 index 0000000..b3d9c43 --- /dev/null +++ b/Multiprotocol/Nrf24l01_esky150.ino @@ -0,0 +1,172 @@ +/* + This project is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Deviation is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Deviation. If not, see . + */ + +#if defined(ESKY150_NRF24L01_INO) +#include "iface_nrf24l01.h" + + +// Timeout for callback in uSec, 4.8ms=4800us for ESky150 +#define ESKY150_PERIOD 4800 +#define ESKY150_CHKTIME 100 // Time to wait for packet to be sent (no ACK, so very short) + +#define esky150_PAYLOADSIZE 15 +#define ADDR_esky150_SIZE 4 + +static uint32_t total_packets; +enum { + ESKY150_INIT2 = 0, + ESKY150_DATA +}; + + +static uint8_t esky150_packet_ack() { + switch (NRF24L01_ReadReg(NRF24L01_07_STATUS) & (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT))) { + case BV(NRF24L01_07_TX_DS): return PKT_ACKED; + case BV(NRF24L01_07_MAX_RT): return PKT_TIMEOUT; + } + return PKT_PENDING; +} + +// 2-bytes CRC +#define CRC_CONFIG (BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO)) +static uint16_t esky150_init() { + uint8_t rx_addr[ADDR_esky150_SIZE] = { 0x73, 0x73, 0x74, 0x63 }; + uint8_t tx_addr[ADDR_esky150_SIZE] = { 0x71, 0x0A, 0x31, 0xF4 }; + NRF24L01_Initialize(); + + NRF24L01_WriteReg(NRF24L01_00_CONFIG, CRC_CONFIG); + NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknoledgement + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, ADDR_esky150_SIZE-2); // 4-byte RX/TX address + NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0); // Disable retransmit + NRF24L01_SetPower(); + NRF24L01_SetBitrate(NRF24L01_BR_2M); + NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_addr, ADDR_esky150_SIZE); + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, tx_addr, ADDR_esky150_SIZE); + + + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit + NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, esky150_PAYLOADSIZE); // bytes of data payload for pipe 0 + + + NRF24L01_Activate(0x73); + NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 1); // Dynamic payload for data pipe 0 + // Enable: Dynamic Payload Length, Payload with ACK , W_TX_PAYLOAD_NOACK + NRF24L01_WriteReg(NRF24L01_1D_FEATURE, BV(NRF2401_1D_EN_DPL) | BV(NRF2401_1D_EN_ACK_PAY) | BV(NRF2401_1D_EN_DYN_ACK)); + + // Delay 50 ms + return 50000; +} + + +static uint16_t esky150_init2() { + NRF24L01_FlushTx(); + NRF24L01_FlushRx(); + packet_sent = 0; + packet_count = 0; + rf_ch_num = 0; + + // Turn radio power on + NRF24L01_SetTxRxMode(TX_EN); + NRF24L01_WriteReg(NRF24L01_00_CONFIG, CRC_CONFIG | BV(NRF24L01_00_PWR_UP)); + // delayMicroseconds(150); + return 150; +} + + +static void calc_fh_channels(uint32_t seed) { + // Use channels 2..79 + uint8_t first = seed % 37 + 2; + uint8_t second = first + 40; + hopping_frequency[0] = first; // 0x22; + hopping_frequency[1] = second; // 0x4a; +} + + +static uint8_t convert_channel(uint8_t num) { + uint32_t ch = Servo_data[num]; + if (ch < PPM_MIN) { ch = PPM_MIN; } + else if (ch > PPM_MAX) { ch = PPM_MAX; } + return (uint8_t) ((ch * 500 / PPM_MAX) + 1500); +} +static void read_controls(uint8_t* throttle, uint8_t* aileron, uint8_t* elevator, uint8_t* rudder) { + *throttle = convert_channel(THROTTLE); + *aileron = convert_channel(AILERON); + *elevator = convert_channel(ELEVATOR); + *rudder = convert_channel(RUDDER); +} + + +static void esky150_send_packet() { + uint8_t rf_ch = hopping_frequency[rf_ch_num]; + rf_ch_num = 1 - rf_ch_num; + + read_controls(&throttle, &aileron, &elevator, &rudder); + + packet[0] = hopping_frequency[0]; + packet[1] = hopping_frequency[1]; + packet[2] = (throttle >> 8) & 0xFF; + packet[3] = throttle & 0xFF; + packet[4] = (aileron >> 8) & 0xFF; + packet[5] = aileron & 0xFF; + packet[6] = (elevator >> 8) & 0xFF; + packet[7] = elevator & 0xFF; + packet[8] = (rudder >> 8) & 0xFF; + packet[9] = rudder & 0xFF; + // Constant values 00 d8 18 f8 + packet[10] = 0x00; + packet[11] = 0xd8; + packet[12] = 0x18; + packet[13] = 0xf8; + uint8_t sum = 0; + for (int i = 0; i < 14; ++i) sum += packet[i]; + packet[14] = sum; + + packet_sent = 0; + NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch); + NRF24L01_FlushTx(); + NRF24L01_WritePayload(packet, sizeof(packet)); + ++total_packets; + packet_sent = 1; +} + +static uint16_t esky150_callback() { + uint16_t timeout = ESKY150_PERIOD; + switch (phase) { + case ESKY150_INIT2: + timeout = esky150_init2(); + phase = ESKY150_DATA; + break; + case ESKY150_DATA: + if (packet_count == 4) + packet_count = 0; + else { + if (packet_sent && esky150_packet_ack() != PKT_ACKED) { + return ESKY150_CHKTIME; + } + esky150_send_packet(); + } + break; + } + return timeout; +} + +static uint16_t esky150_setup() { + total_packets = 0; + uint16_t timeout = esky150_init(); + + return timeout; +} +#endif diff --git a/Multiprotocol/Nrf24l01_fy326.ino b/Multiprotocol/Nrf24l01_fy326.ino index 2c8f943..68234db 100644 --- a/Multiprotocol/Nrf24l01_fy326.ino +++ b/Multiprotocol/Nrf24l01_fy326.ino @@ -75,14 +75,14 @@ static void send_packet(uint8_t bind) | GET_FLAG(CHANNEL_CALIBRATE, 0x01) | GET_FLAG(CHANNEL_EXPERT, 4); } - packet[2] = 200 - scale_channel(AILERON, 0, 200); // aileron - packet[3] = scale_channel(ELEVATOR, 0, 200); // elevator - packet[4] = 200 - scale_channel(RUDDER, 0, 200); // rudder - packet[5] = scale_channel(THROTTLE, 0, 200); // throttle + packet[2] = 200 - scale_channel(AILERON, 0, 200); // aileron 1 + packet[3] = scale_channel(ELEVATOR, 0, 200); // elevator 2 + packet[4] = 200 - scale_channel(RUDDER, 0, 200); // rudder 4 + packet[5] = scale_channel(THROTTLE, 0, 200); // throttle 3 if(sub_protocol == FY319) { - packet[6] = 255 - scale_channel(CHANNEL1, 0, 255); - packet[7] = scale_channel(CHANNEL2, 0, 255); - packet[8] = 255 - scale_channel(CHANNEL4, 0, 255); + packet[6] = 255 - scale_channel(AILERON, 0, 255); + packet[7] = scale_channel(ELEVATOR, 0, 255); + packet[8] = 255 - scale_channel(RUDDER, 0, 255); } else { packet[6] = txid[0]; @@ -112,7 +112,7 @@ static void send_packet(uint8_t bind) static void fy326_init() { - uint8_t rx_tx_addr[] = {0x15, 0x59, 0x23, 0xc6, 0x29}; + uint8_t rx_tx_addr[] = {0x15, 0x59, 0x23, 0xc6, 0x29}; NRF24L01_Initialize(); NRF24L01_SetTxRxMode(TX_EN); @@ -148,7 +148,7 @@ static uint16_t fy326_callback() NRF24L01_WriteReg(NRF24L01_05_RF_CH, RF_BIND_CHANNEL); phase = FY319_BIND1; BIND_IN_PROGRESS; - return PACKET_CHKTIME; + return FY326_CHKTIME; break; case FY319_BIND1: @@ -158,7 +158,7 @@ static uint16_t fy326_callback() packet[0] = txid[3]; packet[1] = 0x80; packet[14]= txid[4]; - bind_counter = BIND_COUNT; + bind_counter = FY326_BIND_COUNT; NRF24L01_SetTxRxMode(TXRX_OFF); NRF24L01_SetTxRxMode(TX_EN); NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); @@ -168,7 +168,7 @@ static uint16_t fy326_callback() packet[i] = rf_chans[0]; phase = FY319_BIND2; } - return PACKET_CHKTIME; + return FY326_CHKTIME; break; case FY319_BIND2: @@ -243,7 +243,7 @@ static void fy_txid() rf_chans[2] = 0x20 + (txid[1] & 0x0F); rf_chans[3] = 0x30 + (txid[1] >> 4); rf_chans[4] = 0x40 + (txid[2] >> 4); - + if(sub_protocol == FY319) { for(uint8_t i=0; i<5; i++) rf_chans[i] = txid[0] & ~0x80; @@ -264,3 +264,4 @@ static uint16_t FY326_setup() return INITIAL_WAIT; } #endif + diff --git a/Multiprotocol/Nrf24l01_hontai.ino b/Multiprotocol/Nrf24l01_hontai.ino new file mode 100644 index 0000000..4408014 --- /dev/null +++ b/Multiprotocol/Nrf24l01_hontai.ino @@ -0,0 +1,272 @@ +/* + This project is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Deviation is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Deviation. If not, see . + */ + + +#if defined(HonTai_NRF24L01_INO) +#include "iface_nrf24l01.h" + +#define BIND_HT_COUNT 80 +#define PACKET_HT_PERIOD 13500 // Timeout for callback in uSec +//printf inside an interrupt handler is really dangerous +//this shouldn't be enabled even in debug builds without explicitly +//turning it on +#define dbgprintf if(0) printf + +#define INITIAL_HT_WAIT 500 +#define BIND_HT_PACKET_SIZE 10 +#define PACKET_HT_SIZE 12 +#define RF_BIND_HT_CHANNEL 0 + +enum { + FORMAT_HONTAI = 0, + FORMAT_JJRCX1, +}; + + +#define CHANNEL_LED AUX1 +#define CHANNEL_ARM AUX1 // for JJRC X1 +#define CHANNEL_FLIP AUX2 +#define CHANNEL_PICTURE AUX3 +#define CHANNEL_VIDEO AUX4 +#define CHANNEL_HEADLESS AUX5 +#define CHANNEL_RTH AUX6 +#define CHANNEL_CALIBRATE AUX7 + +enum { + HonTai_INIT1 = 0, + HonTai_BIND2, + HonTai_DATA +}; + +static uint8_t ht_txid[5]; + +static uint8_t rf_chan = 0; +static uint8_t rf_channels[][3] = {{0x05, 0x19, 0x28}, // Hontai + {0x0a, 0x1e, 0x2d}}; // JJRC X1 +static uint8_t rx_tx_ht_addr[] = {0xd2, 0xb5, 0x99, 0xb3, 0x4a}; +static uint8_t addr_vals[4][16] = { + {0x24, 0x26, 0x2a, 0x2c, 0x32, 0x34, 0x36, 0x4a, 0x4c, 0x4e, 0x54, 0x56, 0x5a, 0x64, 0x66, 0x6a}, + {0x92, 0x94, 0x96, 0x9a, 0xa4, 0xa6, 0xac, 0xb2, 0xb4, 0xb6, 0xca, 0xcc, 0xd2, 0xd4, 0xd6, 0xda}, + {0x93, 0x95, 0x99, 0x9b, 0xa5, 0xa9, 0xab, 0xad, 0xb3, 0xb5, 0xc9, 0xcb, 0xcd, 0xd3, 0xd5, 0xd9}, + {0x25, 0x29, 0x2b, 0x2d, 0x33, 0x35, 0x49, 0x4b, 0x4d, 0x59, 0x5b, 0x65, 0x69, 0x6b, 0x6d, 0x6e}}; + +// proudly swiped from http://www.drdobbs.com/implementing-the-ccitt-cyclical-redundan/199904926 +#define POLY 0x8408 +static uint16_t crc16(uint8_t *data_p, uint32_t length) +{ + uint8_t i; + uint32_t data; + uint32_t crc; + + crc = 0xffff; + + if (length == 0) return (~crc); + + length -= 2; + do { + for (i = 0, data = (uint8_t)0xff & *data_p++; + i < 8; + i++, data >>= 1) { + if ((crc & 0x0001) ^ (data & 0x0001)) + crc = (crc >> 1) ^ POLY; + else + crc >>= 1; + } + } while (--length); + + crc = ~crc; + data = crc; + crc = (crc << 8) | (data >> 8 & 0xFF); + *data_p++ = crc >> 8; + *data_p = crc & 0xff; + return crc; +} + +#define CHAN_RANGE (PPM_MAX - PPM_MIN) +static uint8_t scale_HT_channel(uint8_t ch, uint8_t start, uint8_t end) +{ + uint32_t range = end - start; + uint32_t chanval = Servo_data[ch]; + + if (chanval < PPM_MIN) chanval = PPM_MIN; + else if (chanval > PPM_MAX) chanval = PPM_MAX; + + uint32_t round = range < 0 ? 0 : CHAN_RANGE / range; // channels round up + if (start < 0) round = CHAN_RANGE / range / 2; // trims zero centered around zero + return (range * (chanval - PPM_MIN + round)) / CHAN_RANGE + start; +} + +#define GET_FLAG(ch, mask) (Servo_data[ch] > 0 ? mask : 0) +static void send_HT_packet(uint8_t bind) +{ + if (bind) { + memcpy(packet, ht_txid, 5); + memset(&packet[5], 0, 3); + } else { + if (sub_protocol == FORMAT_HONTAI) { + packet[0] = 0x0b; + } else { + packet[0] = GET_FLAG(CHANNEL_ARM, 0x02); + } + packet[1] = 0x00; + packet[2] = 0x00; + packet[3] = (scale_HT_channel(THROTTLE, 0, 127) << 1) // throttle + | GET_FLAG(CHANNEL_PICTURE, 0x01); + packet[4] = scale_HT_channel(AILERON, 63, 0); // aileron + if (sub_protocol == FORMAT_HONTAI) { + packet[4] |= GET_FLAG(CHANNEL_RTH, 0x80) + | GET_FLAG(CHANNEL_HEADLESS, 0x40); + } else { + packet[4] |= 0x80; // not sure what this bit does + } + packet[5] = scale_channel(CHANNEL2, 0, 63) // elevator + | GET_FLAG(CHANNEL_CALIBRATE, 0x80) + | GET_FLAG(CHANNEL_FLIP, 0x40); + packet[6] = scale_HT_channel(RUDDER, 0, 63) // rudder + | GET_FLAG(CHANNEL_VIDEO, 0x80); + packet[7] = scale_HT_channel(AILERON, -16, 16); // aileron trim + if (sub_protocol == FORMAT_HONTAI) { + packet[8] = scale_HT_channel(RUDDER, -16, 16); // rudder trim + } else { + packet[8] = 0xc0 // always in expert mode + | GET_FLAG(CHANNEL_RTH, 0x02) + | GET_FLAG(CHANNEL_HEADLESS, 0x01); + } + packet[9] = scale_HT_channel(ELEVATOR, -16, 16); // elevator trim + } + crc16(packet, bind ? BIND_HT_PACKET_SIZE : PACKET_HT_SIZE); + + // Power on, TX mode, 2byte CRC + if (sub_protocol == FORMAT_HONTAI) { + XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP)); + } else { + NRF24L01_SetTxRxMode(TX_EN); + } + + NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? RF_BIND_HT_CHANNEL : rf_channels[sub_protocol][rf_chan++]); + rf_chan %= sizeof(rf_channels); + + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); + NRF24L01_FlushTx(); + + if (sub_protocol == FORMAT_HONTAI) { + XN297_WritePayload(packet, bind ? BIND_HT_PACKET_SIZE : PACKET_HT_SIZE); + } else { + NRF24L01_WritePayload(packet, bind ? BIND_HT_PACKET_SIZE : PACKET_HT_SIZE); + } + + NRF24L01_SetPower(); +} + +static void ht_init() +{ + NRF24L01_Initialize(); + + NRF24L01_SetTxRxMode(TX_EN); + + // SPI trace of stock TX has these writes to registers that don't appear in + // nRF24L01 or Beken 2421 datasheets. Uncomment if you have an XN297 chip? + // NRF24L01_WriteRegisterMulti(0x3f, "\x4c\x84\x67,\x9c,\x20", 5); + // NRF24L01_WriteRegisterMulti(0x3e, "\xc9\x9a\xb0,\x61,\xbb,\xab,\x9c", 7); + // NRF24L01_WriteRegisterMulti(0x39, "\x0b\xdf\xc4,\xa7,\x03,\xab,\x9c", 7); + + if (sub_protocol == FORMAT_HONTAI) { + XN297_SetTXAddr(rx_tx_ht_addr, sizeof(rx_tx_ht_addr)); + } else { + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_ht_addr, sizeof(rx_tx_ht_addr)); + } + + 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_SetBitrate(NRF24L01_BR_1M); // 1Mbps + NRF24L01_SetPower(); + NRF24L01_Activate(0x73); // Activate feature register + if (sub_protocol == FORMAT_HONTAI) { + NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits + NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes + NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x00); + NRF24L01_Activate(0x73); // Deactivate feature register + } else { + NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0xff); // JJRC uses dynamic payload length + NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3f); // match other stock settings even though AA disabled... + NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07); + } +} + +static void ht_init2() +{ + uint8_t data_tx_addr[] = {0x2a, 0xda, 0xa5, 0x25, 0x24}; + + data_tx_addr[0] = addr_vals[0][ ht_txid[3] & 0x0f]; + data_tx_addr[1] = addr_vals[1][(ht_txid[3] >> 4) & 0x0f]; + data_tx_addr[2] = addr_vals[2][ ht_txid[4] & 0x0f]; + data_tx_addr[3] = addr_vals[3][(ht_txid[4] >> 4) & 0x0f]; + + if (sub_protocol == FORMAT_HONTAI) { + XN297_SetTXAddr(data_tx_addr, sizeof(data_tx_addr)); + } else { + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, data_tx_addr, sizeof(data_tx_addr)); + } +} + +static uint16_t ht_callback() +{ + switch (phase) { + case HonTai_INIT1: + phase = HonTai_BIND2; + break; + case HonTai_BIND2: + if (counter == 0) { + ht_init2(); + phase = HonTai_DATA; + BIND_DONE; + } else { + send_HT_packet(1); + counter -= 1; + } + break; + + case HonTai_DATA: + send_HT_packet(0); + break; + } + return PACKET_HT_PERIOD; +} + +static uint16_t ht_setup() +{ + counter = BIND_HT_COUNT; + + if (sub_protocol == FORMAT_HONTAI) { + ht_txid[0] = 0x4c; // first three bytes some kind of model id? - set same as stock tx + ht_txid[1] = 0x4b; + ht_txid[2] = 0x3a; + } else { + ht_txid[0] = 0x4b; // JJRC X1 + ht_txid[1] = 0x59; + ht_txid[2] = 0x3a; + } + ht_txid[3] = (MProtocol_id >> 8 ) & 0xff; + ht_txid[4] = MProtocol_id & 0xff; + + ht_init(); + phase = HonTai_INIT1; + + return INITIAL_HT_WAIT; +} +#endif + diff --git a/Multiprotocol/Nrf24l01_ne260.ino b/Multiprotocol/Nrf24l01_ne260.ino new file mode 100644 index 0000000..32b5345 --- /dev/null +++ b/Multiprotocol/Nrf24l01_ne260.ino @@ -0,0 +1,274 @@ +/* + This project is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Deviation is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Deviation. If not, see . + */ +/* This code is based upon code from: + http://www.rcgroups.com/forums/showthread.php?t=1564343 + Author : Ferenc Szili (kile at the rcgroups.net forum) +*/ + + +#if defined(NE260_NRF24L01_INO) +#include "iface_nrf24l01.h" + +//////////////////////////////////////////////////////////// +/////////////////////// +// register bits +/////////////////////// + +// CONFIG +#define MASK_RX_DR 6 +#define MASK_TX_DS 5 +#define MASK_MAX_RT 4 +#define EN_CRC 3 +#define CRCO 2 +#define PWR_UP 1 +#define PRIM_RX 0 + +// EN_AA +#define ENAA_P5 5 +#define ENAA_P4 4 +#define ENAA_P3 3 +#define ENAA_P2 2 +#define ENAA_P1 1 +#define ENAA_P0 0 + +// EN_RXADDR +#define ERX_P5 5 +#define ERX_P4 4 +#define ERX_P3 3 +#define ERX_P2 2 +#define ERX_P1 1 +#define ERX_P0 0 + +// RF_SETUP +#define CONT_WAVE 7 +#define RF_DR_LOW 5 +#define PLL_LOCK 4 +#define RF_DR_HIGH 3 +#define RF_PWR_HIGH 2 +#define RF_PWR_LOW 1 +#define LNA_HCURR 0 // obsolete in nRF24L01+ + +// STATUS +#define RX_DR 6 +#define TX_DS 5 +#define MAX_RT 4 +#define TX_FULL 0 + +// FIFO_STATUS +#define TX_REUSE 6 +#define FIFO_TX_FULL 5 +#define TX_EMPTY 4 +#define RX_FULL 1 +#define RX_EMPTY 0 + +/////////////////////// +// register bit values +/////////////////////// + +// CONFIG +#define vMASK_RX_DR (1<<(MASK_RX_DR)) +#define vMASK_TX_DS (1<<(MASK_TX_DS)) +#define vMASK_MAX_RT (1<<(MASK_MAX_RT)) +#define vEN_CRC (1<<(EN_CRC)) +#define vCRCO (1<<(CRCO)) +#define vPWR_UP (1<<(PWR_UP)) +#define vPRIM_RX (1<<(PRIM_RX)) + +// EN_AA +#define vENAA_P5 (1<<(ENAA_P5)) +#define vENAA_P4 (1<<(ENAA_P4)) +#define vENAA_P3 (1<<(ENAA_P3)) +#define vENAA_P2 (1<<(ENAA_P2)) +#define vENAA_P1 (1<<(ENAA_P1)) +#define vENAA_P0 (1<<(ENAA_P0)) + +// EN_RXADDR +#define vERX_P5 (1<<(ERX_P5)) +#define vERX_P4 (1<<(ERX_P4)) +#define vERX_P3 (1<<(ERX_P3)) +#define vERX_P2 (1<<(ERX_P2)) +#define vERX_P1 (1<<(ERX_P1)) +#define vERX_P0 (1<<(ERX_P0)) + +// SETUP_AW -- address widths in bytes +#define vAW_3 1 +#define vAW_4 2 +#define vAW_5 3 + +// RF_SETUP +#define vCONT_WAVE (1<<(CONT_WAVE)) +#define vRF_DR_LOW (1<<(RF_DR_LOW)) +#define vPLL_LOCK (1<<(PLL_LOCK)) +#define vRF_DR_HIGH (1<<(RF_DR_HIGH)) +#define vRF_PWR_HIGH (1<<(RF_PWR_HIGH)) +#define vRF_PWR_LOW (1<<(RF_PWR_LOW)) +#define vLNA_HCURR (1<<(LNA_HCURR)) // obsolete in nRF24L01+ + +#define vRF_DR_1MBPS 0 +#define vRF_DR_2MBPS (1<<(RF_DR_HIGH)) +#define vRF_DR_250KBPS (1<<(RF_DR_LOW)) + +#define vRF_PWR_M18DBM 0x00 +#define vRF_PWR_M12DBM 0x02 +#define vRF_PWR_M6DBM 0x04 +#define vRF_PWR_0DBM 0x06 + +#define vARD_250us 0x00 +#define vARD_500us 0x10 +#define vARD_750us 0x20 +#define vARD_1000us 0x30 +#define vARD_1250us 0x40 +#define vARD_1500us 0x50 +#define vARD_1750us 0x60 +#define vARD_2000us 0x70 +#define vARD_2250us 0x80 +#define vARD_2500us 0x90 +#define vARD_2750us 0xA0 +#define vARD_3000us 0xB0 +#define vARD_3250us 0xC0 +#define vARD_3500us 0xD0 +#define vARD_3750us 0xE0 +#define vARD_4000us 0xF0 + +// STATUS +#define vRX_DR (1<<(RX_DR)) +#define vTX_DS (1<<(TX_DS)) +#define vMAX_RT (1<<(MAX_RT)) +#define vTX_FULL (1<<(TX_FULL)) + +#define RX_P_NO(stat) ((stat >> 1) & 7) +#define HAS_RX_PAYLOAD(stat) ((stat & 0b1110) < 0b1100) + +// FIFO_STATUS +#define vTX_REUSE (1<<(TX_REUSE)) +#define vTX_FULL (1<<(TX_FULL)) +#define vTX_EMPTY (1<<(TX_EMPTY)) +#define vRX_FULL (1<<(RX_FULL)) +#define vRX_EMPTY (1<<(RX_EMPTY)) +//////////////////////////////////////////////////////////// +uint8_t neChannel = 10; +uint8_t neChannelOffset = 0; +#define PACKET_NE_LENGTH 7 + +static u32 bind_count; +static uint16_t model_id = 0xA04A; + +uint8_t NE_ch[]={THROTTLE, RUDDER, ELEVATOR, AILERON, AUX1}; +uint8_t NEAddr[] = {0x34, 0x43, 0x10, 0x10, 0x01}; +enum { + NE260_BINDTX, + NE260_BINDRX, + NE260_DATA1, + NE260_DATA2, + NE260_DATA3, +}; + + +static void ne260_init() { + NRF24L01_Initialize(); + + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, NEAddr, 5); // write the address + NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, NEAddr, 5); + + NRF24L01_WriteReg(NRF24L01_01_EN_AA, vENAA_P0); // enable auto acknoledge + NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, vARD_500us); // ARD=500us, ARC=disabled + NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, vRF_DR_250KBPS | vLNA_HCURR | vRF_PWR_0DBM); // data rate, output power and noise cancel + NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, PACKET_NE_LENGTH); // RX payload length + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, vERX_P0); // enable RX address + NRF24L01_WriteReg(NRF24L01_07_STATUS, vRX_DR | vTX_DS | vMAX_RT); // reset the IRQ flags +} + +static void send_data_packet() { + for(int i = 0; i < 4; i++) { + uint32_t value = (uint32_t)Servo_data[NE_ch[i]] * 0x40 / PPM_MAX + 0x40; + if (value > 0x7f) + value = 0x7f; + else if(value < 0) + value = 0; + packet[i] = value; + } + packet[4] = 0x55; + packet[5] = model_id & 0xff; + packet[6] = (model_id >> 8) & 0xff; + + NRF24L01_FlushTx(); + NRF24L01_WriteReg(NRF24L01_07_STATUS, vMAX_RT); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, neChannel + neChannelOffset); + NRF24L01_WriteReg(NRF24L01_00_CONFIG, vEN_CRC | vCRCO | vPWR_UP); + // send a fresh packet to the nRF + NRF24L01_WritePayload((uint8_t*) packet, PACKET_NE_LENGTH); +} + +static void send_bind_packet() { + packet[0] = 0xAA; //throttle + packet[1] = 0xAA; //rudder + packet[2] = 0xAA; //elevator + packet[3] = 0xAA; //aileron + packet[4] = 0xAA; //command + packet[5] = model_id & 0xff; + packet[6] = (model_id >> 8) & 0xff; + + NRF24L01_WriteReg(NRF24L01_07_STATUS, vRX_DR | vTX_DS | vMAX_RT); // reset the status flags + NRF24L01_WriteReg(NRF24L01_05_RF_CH, neChannel + neChannelOffset); + NRF24L01_FlushTx(); + NRF24L01_WritePayload((uint8_t*) &packet, PACKET_NE_LENGTH); // send the bind packet +} + +static uint16_t ne260_cb() { + if (state == NE260_BINDTX) { + // do we have a packet? + if ((NRF24L01_ReadReg(NRF24L01_07_STATUS) & vRX_DR) != 0) { + // read the packet contents + NRF24L01_ReadPayload(packet, PACKET_NE_LENGTH); + + // is this the bind response packet? + if (strncmp("\x55\x55\x55\x55\x55", (char*) (packet + 1), 5) == 0 && *((uint16_t*)(packet + 6)) == model_id) { + // exit the bind loop + state = NE260_DATA1; + NRF24L01_FlushTx(); + NRF24L01_FlushRx(); + NRF24L01_SetTxRxMode(TX_EN); + return 2000; + } + } + NRF24L01_SetTxRxMode(TX_EN); + send_bind_packet(); + state = NE260_BINDRX; + return 500; + } else if (state == NE260_BINDRX) { + // switch to RX mode + while (!(NRF24L01_ReadReg(NRF24L01_07_STATUS) & (vMAX_RT | vTX_DS))) ; + NRF24L01_WriteReg(NRF24L01_07_STATUS, vTX_DS); + + NRF24L01_SetTxRxMode(RX_EN); + NRF24L01_FlushRx(); + state = NE260_BINDTX; + return 2000; + } + else if (state == NE260_DATA1) { neChannel = 10; state = NE260_DATA2; } + else if (state == NE260_DATA2) { neChannel = 30; state = NE260_DATA3; } + else if (state == NE260_DATA3) { neChannel = 50; state = NE260_DATA1; } + send_data_packet(); + return 2500; +} + +static uint16_t NE260_setup() { + ne260_init(); + bind_count = 10000; + state = NE260_BINDTX; + + return 10000; +} +#endif diff --git a/Multiprotocol/Nrf24l01_udi.ino b/Multiprotocol/Nrf24l01_udi.ino new file mode 100644 index 0000000..ab8afa8 --- /dev/null +++ b/Multiprotocol/Nrf24l01_udi.ino @@ -0,0 +1,583 @@ +/* + This project is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Deviation is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Deviation. If not, see . + */ + +// Known UDI 2.4GHz protocol variants, all using BK2421 +// * UDI U819 coaxial 3ch helicoper +// * UDI U816/817/818 quadcopters +// - "V1" with orange LED on TX, U816 RX labeled '' , U817/U818 RX labeled 'UD-U817B' +// - "V2" with red LEDs on TX, U816 RX labeled '', U817/U818 RX labeled 'UD-U817OG' +// - "V3" with green LEDs on TX. Did not get my hands on yet. +// * U830 mini quadcopter with tilt steering ("Protocol 2014") +// * U839 nano quadcopter ("Protocol 2014") + +#if defined(UDI_NRF24L01_INO) +#include "iface_nrf24l01.h" + +#define BIND_UDI_COUNT 1000 + +// Timeout for callback in uSec, 4ms=4000us for UDI +// ??? +//#define PACKET_UDI_PERIOD 4000 + +#define BIND_PACKET_UDI_PERIOD 5000 +#define PACKET_UDI_PERIOD 15000 + +#define BIND_PACKETS_UDI_PER_CHANNEL 11 +#define PACKETS_UDI_PER_CHANNEL 11 + +#define NUM_UDI_RF_CHANNELS 16 + + +#define INITIAL_UDI_WAIT 50000 + +#define PACKET_UDI_CHKTIME 100 + +// For readability +enum { + UDI_CAMERA = 1, + UDI_VIDEO = 2, + UDI_MODE2 = 4, + UDI_FLIP360 = 8, + UDI_FLIP =16, + UDI_LIGHTS =32 +}; + +// This is maximum payload size used in UDI protocols +#define UDI_PAYLOADSIZE 16 + + + +static uint8_t payload_size; // Bytes in payload for selected variant +static uint8_t bind_channel; +static uint8_t packets_to_hop; +static uint8_t packets_to_check; // BIND_RX phase needs to receive/auto-ack more than one packet for RX to switch to next phase, it seems +static uint8_t packets_to_send; // Number of packets to send / check for in current bind phase +static uint8_t bind_step_success; // Indicates successfull transmission / receive of bind reply during current bind phase +static uint8_t tx_id[3]; +static uint8_t rx_id[3]; +static uint8_t randoms[3]; // 3 random bytes choosen by TX, sent in BIND packets. Lower nibble of first byte sets index in RF CH table to use for BIND2 + + +// +enum { + UDI_INIT2 = 0, + UDI_INIT2_NO_BIND, + UDI_BIND1_TX, + UDI_BIND1_RX, + UDI_BIND2_TX, + UDI_BIND2_RX, + UDI_DATA +}; + +enum { + PROTOOPTS_FORMAT = 0, + PROTOOPTS_STARTBIND, +}; +enum { + STARTBIND_NO = 0, + STARTBIND_YES = 1, +}; + +// This are frequency hopping tables for UDI protocols + +// uint8_t16 V1 (Orange LED) Bind CH 0x07 +// TX ID 0x57, 0x5A, 0x2D +static const uint8_t freq_hopping_uint8_t16_v1[NUM_UDI_RF_CHANNELS] = { + 0x07, 0x21, 0x49, 0x0B, 0x39, 0x10, 0x25, 0x42, + 0x1D, 0x31, 0x35, 0x14, 0x28, 0x3D, 0x18, 0x2D +}; + +// Protocol 2014 (uint8_t30,uint8_t39,...) BIND CH 0x23 (second entry) +// DATA: hops ~ every 0.361s (0.350 ... 0.372) +static const uint8_t freq_hopping_uint8_t39[NUM_UDI_RF_CHANNELS] = { + 0x08, 0x23, 0x48, 0x0D, 0x3B, 0x12, 0x27, 0x44, + 0x1F, 0x33, 0x37, 0x16, 0x2A, 0x3F, 0x1A, 0x2F +}; + +// Points to proper table +static const uint8_t * rf_udi_channels = NULL; + + +static uint8_t packet_udi_ack() +{ + switch (NRF24L01_ReadReg(NRF24L01_07_STATUS) & (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT))) { + case BV(NRF24L01_07_TX_DS): return PKT_ACKED; + case BV(NRF24L01_07_MAX_RT): return PKT_TIMEOUT; + } + return PKT_PENDING; +} + +static void UDI_init() +{ + NRF24L01_Initialize(); + //NRF24L01_SetTxRxMode(TX_EN); + + switch (sub_protocol) { + case U816_V1: + rf_udi_channels = freq_hopping_uint8_t16_v1; + payload_size = 8; + break; + + case U816_V2: + rf_udi_channels = NULL; // NO HOPPING ! + payload_size = 7; + break; + + case U839_2014: + // UDI 2014 Protocol (uint8_t30, uint8_t39, all other new products ?) + rf_udi_channels = freq_hopping_uint8_t39; + payload_size = 8; + break; + } + + NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, payload_size); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x07); // Clear status bits + + if ((sub_protocol == U816_V1) || (sub_protocol == U816_V2)) { + NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, 0x27); // + NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x3A); // + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // 3 byte address + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 + NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x3F); // Auto-acknowledge on all data pipers, same as YD + if (sub_protocol == U816_V1) { + NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x7F); // + } else { + NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x7A); // + } + } else + if (sub_protocol == U839_2014) { + NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, 0x0F); // 2Mbps air rate, 5dBm RF output power, high LNA gain + NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x1A); // 500uS retransmit t/o, 10 tries (same as YD) + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // 3 byte address + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 + NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x3F); // Auto-acknowledge on all data pipers, same as YD + NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0F); // Enable CRC, 2 byte CRC, PWR UP, PRIMARY RX + } + + NRF24L01_FlushTx(); + NRF24L01_FlushRx(); + uint8_t status = NRF24L01_ReadReg(NRF24L01_07_STATUS); + NRF24L01_WriteReg(NRF24L01_07_STATUS, status); + + status = NRF24L01_ReadReg(NRF24L01_07_STATUS); + NRF24L01_FlushTx(); + status = NRF24L01_ReadReg(NRF24L01_07_STATUS); + NRF24L01_WriteReg(NRF24L01_07_STATUS, status); + + // Implicit delay in callback + // delayMicroseconds(120) +} + +static void UDI_init2() +{ + NRF24L01_FlushTx(); + bind_step_success = 0; + packet_sent = 0; + + switch (sub_protocol) { + case U816_V1: + rf_ch_num = 0; + bind_channel = rf_udi_channels[rf_ch_num++]; + break; + case U816_V2: + rf_ch_num = 0x07; // This is actual channel. No hopping here + bind_channel = 0; + break; + case U839_2014: + rf_ch_num = 1; + bind_channel = rf_udi_channels[rf_ch_num++]; + break; + } + NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind_channel); + + NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t *) "\xe7\x7e\xe7", 3); + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *) "\xe7\x7e\xe7", 3); + + // Turn radio power on + NRF24L01_SetTxRxMode(TX_EN); + uint8_t config = BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP); + NRF24L01_WriteReg(NRF24L01_00_CONFIG, config); + // Implicit delay in callback + // delayMicroseconds(150); +} + +static void set_tx_id(uint32_t id) +{ + tx_id[0] = (id >> 16) & 0xFF; + tx_id[1] = (id >> 8) & 0xFF; + tx_id[2] = (id >> 0) & 0xFF; + +/* + uint32_t val = rand32(); randoms[0] = val & 0xff; randoms[1] = (val >> 8 ) & 0xff; randoms[2] = (val >> 16 ) & 0xff; +*/ + // FIXME + // This one has been observed, leads to RF CH 0x1F (#08) used for BIND2 + randoms[0] = 0x98; randoms[1] = 0x80; randoms[2] = 0x5B; +} + +static void add_pkt_checksum() +{ + // CHECKSUM was introduced with 2014 protocol + if (sub_protocol < U839_2014) return; + uint8_t sum = 0; + for (uint8_t i = 0; i < payload_size-1; ++i) sum += packet[i]; + packet[payload_size-1] = sum & 0x3f; // *sick* +} + + +static uint8_t convert_channel(uint8_t num, uint8_t chn_max, uint8_t sign_ofs) +{ + uint32_t ch = Servo_data[num]; + if (ch < PPM_MIN) { + ch = PPM_MIN; + } else if (ch > PPM_MAX) { + ch = PPM_MAX; + } + uint32_t chn_val; + if (sign_ofs) chn_val = (((ch * chn_max / PPM_MAX) + sign_ofs) >> 1); + else chn_val = (ch * chn_max / PPM_MAX); + if (chn_val < 0) chn_val = 0; + else if (chn_val > chn_max) chn_val = chn_max; + return (uint8_t) chn_val; +} + + +static void read_controls(uint8_t* throttle, uint8_t* rudder, uint8_t* elevator, uint8_t* aileron, + uint8_t* flags) +{ + // Protocol is registered AETRG, that is + // Aileron is channel 0, Elevator - 1, Throttle - 2, Rudder - 3 + // Sometimes due to imperfect calibration or mixer settings + // throttle can be less than PPM_MIN or larger than + // PPM_MAX. As we have no space here, we hard-limit + // channels values by min..max range + + // Channel 3: throttle is 0-100 + *throttle = convert_channel(THROTTLE, 0x64, 0); + + // Channel 4 + *rudder = convert_channel(RUDDER, 0x3f, 0x20); + + // Channel 2 + *elevator = convert_channel(ELEVATOR, 0x3f, 0x20); + + // Channel 1 + *aileron = convert_channel(AILERON, 0x3f, 0x20); + + // Channel 5 + if (Servo_data[AUX1] <= 0) *flags &= ~UDI_FLIP360; + else *flags |= UDI_FLIP360; + + // Channel 6 + if (Servo_data[AUX2] <= 0) *flags &= ~UDI_FLIP; + else *flags |= UDI_FLIP; + + // Channel 7 + if (Servo_data[AUX3] <= 0) *flags &= ~UDI_CAMERA; + else *flags |= UDI_CAMERA; + + // Channel 8 + if (Servo_data[AUX4] <= 0) *flags &= ~UDI_VIDEO; + else *flags |= UDI_VIDEO; + + // Channel 9 + if (Servo_data[AUX5] <= 0) *flags &= ~UDI_LIGHTS; + else *flags |= UDI_LIGHTS; + + // Channel 10 + if (Servo_data[AUX6] <= 0) *flags &= ~UDI_MODE2; + else *flags |= UDI_MODE2; +} + +static void send_udi_packet(uint8_t bind) +{ + packet[7] = 0x4A; + if (bind == 1) { + // Bind phase 1 + // MAGIC + packet[0] = 0x5A; // NOTE: Also 0xF3, when RX does not ACK packets (uint8_t39, only TX on) ... + // Current Address / TX ID + if (sub_protocol == U839_2014) { + // uint8_t39: Current RX/TX Addr + packet[1] = 0xE7; + packet[2] = 0x7E; + packet[3] = 0xE7; + } else { + // uint8_t16: ID Fixed per TX + packet[1] = tx_id[0]; + packet[2] = tx_id[1]; + packet[3] = tx_id[2]; + } + // Pseudo random values (lower nibble of packet[4] determines index of RF CH used in BIND2) + packet[4] = randoms[0]; + packet[5] = randoms[1]; + packet[6] = randoms[2]; + if (sub_protocol == U839_2014) { + packet[7] = (packet_counter < 4) ? 0x3f : 0x04; // first four packets use 0x3f here, then 0x04 + } + } else if (bind == 2) { + // Bind phase 2 + // MAGIC + packet[0] = 0xAA; + // Current Address (RX "ID", pseudorandom again) + packet[1] = rx_id[0]; + packet[2] = rx_id[1]; + packet[3] = rx_id[2]; + // Pseudo random values + packet[4] = randoms[0]; + packet[5] = randoms[1]; + packet[6] = randoms[2]; + if (sub_protocol == U839_2014) { + packet[7] = 0x04; + } + } else { + // regular packet + // Read channels (converts to required ranges) + read_controls(&throttle, &rudder, &elevator, &aileron, &flags); + // MAGIC + packet[0] = 0x55; + packet[1] = throttle; // throttle is 0-0x64 + // 3 Channels packed into 2 bytes (5bit per channel) + uint16_t encoded = (rudder << 11) | (elevator << 6) | (aileron << 1); + packet[2] = (encoded >> 8) & 0xff; + packet[3] = encoded & 0xff; + // Trims and flags (0x20 = center) + packet[4] = 0x20; // rudder trim 6bit + packet[5] = 0x20; // elev trim 6bit + packet[6] = 0x20; // ail trim 6bit + + if (flags & UDI_FLIP) packet[4] |= 0x80; // "Directional" flip + if (flags & UDI_LIGHTS) packet[4] |= 0x40; // Light on/off + + if (flags & UDI_MODE2) packet[5] |= 0x80; // High rate ("Mode2") + if (flags & UDI_FLIP360) packet[5] |= 0x40; // 360 degree flip + + if (flags & UDI_VIDEO) packet[6] |= 0x80; // Video recording on/off + if (flags & UDI_CAMERA) packet[6] |= 0x40; // Take picture + + // NOTE: Only newer protocols have this (handled by routine) + add_pkt_checksum(); + } + + uint8_t status = NRF24L01_ReadReg(NRF24L01_07_STATUS); + NRF24L01_WriteReg(NRF24L01_07_STATUS,status); + + if (packet_sent && bind && (status & BV(NRF24L01_07_TX_DS))) { + bind_step_success = 1; + } + + packet_sent = 0; + + // Check if its time to change channel + // This seems to be done by measuring time, + // not by counting packets, on UDI transmitters + // NOTE: Seems even in bind phase channels are changed + + // NOTE: Only hop in TX mode ??? + if (rf_udi_channels && (bind == 0) && (packets_to_hop-- == 0)) { + uint8_t rf_ch = rf_udi_channels[rf_ch_num]; + rf_ch_num++; + rf_ch_num %= NUM_UDI_RF_CHANNELS; + NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch); + + packets_to_hop = bind ? BIND_PACKETS_UDI_PER_CHANNEL : PACKETS_UDI_PER_CHANNEL; + } + NRF24L01_FlushTx(); + NRF24L01_WritePayload(packet, payload_size); + ++packet_counter; + packet_sent = 1; +} + + +static uint16_t UDI_callback() { + switch (phase) { + case UDI_INIT2: + UDI_init2(); + phase = UDI_BIND1_TX; + return 120; + break; + case UDI_INIT2_NO_BIND: + // Do nothing (stay forever) + // Cannot re-bind on UDI protocol since IDs are random + return 10000; // 10ms + break; + case UDI_BIND1_TX: + if (packet_sent && packet_udi_ack() == PKT_ACKED) { bind_step_success = 1; } + if (bind_step_success) { + // All fine, wait for reply of receiver + phase = UDI_BIND1_RX; + + NRF24L01_SetTxRxMode(RX_EN); + NRF24L01_FlushRx(); + + NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0F); + bind_step_success = 0; + //packets_to_check = 12; // according to SPI traces on uint8_t17B RX it receives 12 packets (and answers with 5) + packets_to_check = 3; + } else { + send_udi_packet(1); + } + return BIND_PACKET_UDI_PERIOD; + break; + case UDI_BIND1_RX: + // Check if data has been received + if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR) ) { + uint8_t data[UDI_PAYLOADSIZE]; + NRF24L01_ReadPayload(data, payload_size); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x4E); // On original TX this is done on LAST packet check only ! + NRF24L01_FlushRx(); + + // Verify MAGIC and Random ID + // (may be reply to bind packet from other TX) + if ((data[0] == 0xA5) && + (data[4] == randoms[0]) && + (data[5] == randoms[1]) && + (data[6] == randoms[2]) && + (data[7] == randoms[2])) { + rx_id[0] = data[1]; + rx_id[1] = data[2]; + rx_id[2] = data[3]; + if (sub_protocol != U816_V2) { + rf_ch_num = randoms[0] & 0x0f; + } + bind_step_success = 1; + } + } + // RX seems to need more than one ACK + if (packets_to_check) packets_to_check--; + //NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0F); + if (bind_step_success && !packets_to_check) { + // All fine, switch address and RF channel, + // send bind packets with channel hopping now + phase = UDI_BIND2_TX; + + packet_sent = 0; + packets_to_send = 4; + bind_step_success = 0; + + NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_id, 3); + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_id, 3); + + if (sub_protocol != U816_V2) { + // Switch RF channel + NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_udi_channels[rf_ch_num++]); + rf_ch_num %= NUM_UDI_RF_CHANNELS; + } + + NRF24L01_FlushTx(); + NRF24L01_FlushRx(); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x7E); + + NRF24L01_SetTxRxMode(TX_EN); + //NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0E) + + return 10; // 10 µs (start sending immediately) + } + return BIND_PACKET_UDI_PERIOD; + break; + + case UDI_BIND2_TX: + if (packet_sent && packet_udi_ack() == PKT_ACKED) { + bind_step_success = 1; + } + send_udi_packet(2); + if (packets_to_send) --packets_to_send; + if (bind_step_success || !packets_to_send) { + // Seems the original TX ignores AACK, too ! + // U816 V1: 3 packets send, U839: 4 packets send + // All fine, wait for reply of receiver + phase = UDI_BIND2_RX; + + NRF24L01_SetTxRxMode(RX_EN); + NRF24L01_FlushRx(); + + NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0F); + bind_step_success = 0; + packets_to_check = 14; // ??? + } + return bind_step_success ? 4000 : 12000; // 4ms if no packed acked yet, 12ms afterwards + // return 120; // FIXME: Varies for first three packets !!! + + break; + + case UDI_BIND2_RX: + // Check if data has been received + if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR) ) { + uint8_t data[UDI_PAYLOADSIZE]; + NRF24L01_ReadPayload(data, payload_size); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x4E); + NRF24L01_FlushRx(); + + // Verify MAGIC, RX Addr, Random ID + // (may be reply to bind packet from other TX) + if ((data[0] == 0xDD) && + (data[1] == rx_id[0]) && + (data[2] == rx_id[1]) && + (data[3] == rx_id[2]) && + (data[4] == randoms[0]) && + (data[5] == randoms[1]) && + (data[6] == randoms[2]) && + (data[7] == randoms[2])) { + bind_step_success = 1; + } + } + // RX seems to need more than one ACK + if (packets_to_check) packets_to_check--; + //NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0F); + if (bind_step_success && !packets_to_check) { + phase = UDI_DATA; + NRF24L01_SetTxRxMode(TX_EN); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x7E); + NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0E); + NRF24L01_FlushTx(); + + // Switch RF channel + if (sub_protocol == U816_V2) { + // FIXED RF Channel + NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch_num); + } else { + NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_udi_channels[rf_ch_num++]); + rf_ch_num %= NUM_UDI_RF_CHANNELS; + } + + flags = 0; + BIND_DONE; + } + return BIND_PACKET_UDI_PERIOD; + break; + case UDI_DATA: + if (packet_sent && packet_udi_ack() != PKT_ACKED) { + return PACKET_UDI_CHKTIME; + } + send_udi_packet(0); + break; + } + // Packet every 15ms + return PACKET_UDI_PERIOD; +} + +static uint16_t UDI_setup() +{ + packet_counter = 0; + UDI_init(); + phase = UDI_INIT2; + counter = BIND_UDI_COUNT; + + // observed on U839 TX + set_tx_id(0x457C27); + + return INITIAL_UDI_WAIT; +} +#endif diff --git a/Multiprotocol/SHENQI_nrf24l01.ino b/Multiprotocol/SHENQI_nrf24l01.ino new file mode 100644 index 0000000..18d5037 --- /dev/null +++ b/Multiprotocol/SHENQI_nrf24l01.ino @@ -0,0 +1,108 @@ +#if defined(SHENQI_NRF24L01_INO) + +#include "iface_nrf24l01.h" + +const uint8_t PROGMEM SHENQI_Freq[] = { + 50,50,20,60,30,40, + 10,30,40,20,60,10, + 50,20,50,40,10,60, + 30,30,60,10,40,50, + 20,10,60,20,50,30, + 40,40,30,50,20,60, + 10,10,20,30,40,50, + 60,60,50,40,30,20, + 10,60,10,50,30,40, + 20,10,40,30,60,20 }; + +void SHENQI_init() +{ + NRF24L01_Initialize(); + 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_SetBitrate(NRF24L01_BR_1M); // 1Mbps + NRF24L01_SetPower(); + + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5 bytes rx/tx address + + LT8910_Config(4, 8, _BV(LT8910_CRC_ON)|_BV(LT8910_PACKET_LENGTH_EN), 0xAA); + LT8910_SetChannel(2); + LT8910_SetAddress((uint8_t *)"\x9A\x9A\x9A\x9A",4); + LT8910_SetTxRxMode(RX_EN); +} + +void SHENQI_send_packet() +{ + packet[0]=0x00; + if(packet_count==0) + { + uint8_t bind_addr[4]; + bind_addr[0]=0x9A; + bind_addr[1]=0x9A; + bind_addr[2]=rx_tx_addr[2]; + bind_addr[3]=rx_tx_addr[3]; + LT8910_SetAddress(bind_addr,4); + LT8910_SetChannel(2); + packet[1]=rx_tx_addr[1]; + packet[2]=rx_tx_addr[0]; + packet_period=2508; + } + else + { + LT8910_SetAddress(rx_tx_addr,4); + packet[1]=255-convert_channel_8b(RUDDER); + packet[2]=255-convert_channel_8b_scale(THROTTLE,0x60,0xA0); + uint8_t freq=pgm_read_byte_near(&SHENQI_Freq[hopping_frequency_no])+(rx_tx_addr[1]&0x0F); + LT8910_SetChannel(freq); + hopping_frequency_no++; + if(hopping_frequency_no==60) + hopping_frequency_no=0; + packet_period=1750; + } + // Send packet + 1 retransmit - not sure why but needed (not present on original TX...) + LT8910_WritePayload(packet,3); + while(NRF24L01_packet_ack()!=PKT_ACKED); + LT8910_WritePayload(packet,3); + + packet_count++; + if(packet_count==7) + { + packet_count=0; + packet_period=3000; + } + // Set power + NRF24L01_SetPower(); +} + +uint16_t SHENQI_callback() +{ + if(IS_BIND_DONE_on) + SHENQI_send_packet(); + else + { + if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR)) + { + if(LT8910_ReadPayload(packet, 3)) + { + BIND_DONE; + rx_tx_addr[3]=packet[1]; + rx_tx_addr[2]=packet[2]; + LT8910_SetTxRxMode(TX_EN); + packet_period=14000; + } + NRF24L01_FlushRx(); + } + } + return packet_period; +} + +uint16_t initSHENQI() +{ + BIND_IN_PROGRESS; // autobind protocol + SHENQI_init(); + hopping_frequency_no = 0; + packet_count=0; + packet_period=100; + return 1000; +} + +#endif \ No newline at end of file diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index d39c787..5df7e3b 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -25,14 +25,6 @@ //Uncomment to enable telemetry #define TELEMETRY - -//Uncomment to enable potar select -#define POTAR_SELECT -#define POTAR_SELECT_V ELEVATOR -#define POTAR_SELECT_H RUDDER -#define POTAR_SELECT_M AILERON - - //Comment if a module is not installed #define A7105_INSTALLED #define CYRF6936_INSTALLED @@ -62,6 +54,11 @@ #define CFlie_NRF24L01_INO #define H377_NRF24L01_INO #define FY326_NRF24L01_INO + #define ESKY150_NRF24L01_INO +// #define BlueFly_NRF24L01_INO //probleme gene id + #define HonTai_NRF24L01_INO + #define UDI_NRF24L01_INO + #define NE260_NRF24L01_INO #define BAYANG_NRF24L01_INO #define CG023_NRF24L01_INO @@ -75,27 +72,27 @@ #define YD717_NRF24L01_INO #define MT99XX_NRF24L01_INO #define MJXQ_NRF24L01_INO +// #define SHENQI_NRF24L01_INO #endif //Update this table to set which protocol and all associated settings are called for the corresponding dial number -static const PPM_Parameters PPM_prot[15]= -{ -// Protocol Sub protocol RX_Num Power Auto Bind Option - {MODE_FLYSKY, Flysky , 0 , P_HIGH , AUTOBIND , 0 }, //Dial=1 - {MODE_HUBSAN, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=2 - {MODE_FRSKY , 0 , 0 , P_HIGH , NO_AUTOBIND , 0xD7 }, //Dial=3 - {MODE_HISKY , Hisky , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=4 - {MODE_V2X2 , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=5 - {MODE_DSM2 , DSM2 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=6 - {MODE_DEVO , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=7 - {MODE_YD717 , YD717 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=8 - {MODE_KN , WLTOYS , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=9 - {MODE_SYMAX , SYMAX , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=10 - {MODE_SLT , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=11 - {MODE_CX10 , CX10_BLUE , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=12 - {MODE_CG023 , CG023 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=13 - {MODE_BAYANG, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=14 - {MODE_SYMAX , SYMAX5C , 0 , P_HIGH , NO_AUTOBIND , 0 } //Dial=15 +const PPM_Parameters PPM_prot[15]= { +// Dial Protocol Sub protocol RX_Num Power Auto Bind Option +/* 1 */ {MODE_FLYSKY, Flysky , 0 , P_HIGH , AUTOBIND , 0 }, +/* 2 */ {MODE_HUBSAN, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 3 */ {MODE_FRSKY , 0 , 0 , P_HIGH , NO_AUTOBIND , 0xD7 }, +/* 4 */ {MODE_HISKY , Hisky , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 5 */ {MODE_V2X2 , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 6 */ {MODE_DSM2 , DSM2 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 7 */ {MODE_DEVO , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 8 */ {MODE_YD717 , YD717 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 9 */ {MODE_KN , FEILUN , 0 , P_HIGH , AUTOBIND , 0 }, +/* 10 */ {MODE_SYMAX , SYMAX , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 11 */ {MODE_SLT , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 12 */ {MODE_CX10 , CX10_BLUE , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 13 */ {MODE_CG023 , CG023 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 14 */ {MODE_BAYANG, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 15 */ {MODE_SYMAX , SYMAX5C , 0 , P_HIGH , NO_AUTOBIND , 0 } }; /* Available protocols and associated sub protocols: MODE_FLYSKY @@ -159,6 +156,8 @@ static const PPM_Parameters PPM_prot[15]= X600 X800 H26D + MODE_SHENQI + NONE RX_Num value between 0 and 15 @@ -191,7 +190,7 @@ Option value between 0 and 255. 0xD7 or 0x00 for Frsky fine tuning. #endif // SPEKTRUM PPM and channels -#if defined(TX_SPEKTRUM) | defined(TARANIS) +#if defined(TX_SPEKTRUM) #define PPM_MAX 2000 #define PPM_MIN 1000 #define PPM_MAX_100 1900 @@ -199,6 +198,15 @@ Option value between 0 and 255. 0xD7 or 0x00 for Frsky fine tuning. #define TAER #endif +// TARANIS PPM and channels +#if defined(TARANIS) + #define PPM_MAX 2000 + #define PPM_MIN 1000 + #define PPM_MAX_100 1900 + #define PPM_MIN_100 1100 + #define EATR +#endif + // HISKY #if defined(TX_HISKY) #define PPM_MAX 2000 @@ -249,3 +257,7 @@ enum chan_orders{ #define PPM_MIN_COMMAND 1250 #define PPM_SWITCH 1550 #define PPM_MAX_COMMAND 1750 + +//Uncoment the desired serial speed +#define BAUD 100000 +//#define BAUD 125000 diff --git a/Multiprotocol/iface_cc2500.h b/Multiprotocol/iface_cc2500.h index cb7b623..ee5242f 100644 --- a/Multiprotocol/iface_cc2500.h +++ b/Multiprotocol/iface_cc2500.h @@ -156,4 +156,43 @@ enum { //void CC2500_WriteData(u8 *packet, u8 length); //void CC2500_ReadData(u8 *dpbuffer, int len); //void CC2500_SetTxRxMode(enum TXRX_State); + +const PROGMEM uint8_t cc2500_conf[][2]={ + { CC2500_02_IOCFG0, 0x06 }, + { CC2500_00_IOCFG2, 0x06 }, + { CC2500_17_MCSM1, 0x0c }, + { CC2500_18_MCSM0, 0x18 }, + { CC2500_06_PKTLEN, 0x19 }, + { CC2500_07_PKTCTRL1, 0x04 }, + { CC2500_08_PKTCTRL0, 0x05 }, + { CC2500_3E_PATABLE, 0xff }, + { CC2500_0B_FSCTRL1, 0x08 }, + { CC2500_0C_FSCTRL0, 0x00 }, // option + { CC2500_0D_FREQ2, 0x5c }, + { CC2500_0E_FREQ1, 0x76 }, + { CC2500_0F_FREQ0, 0x27 }, + { CC2500_10_MDMCFG4, 0xAA }, + { CC2500_11_MDMCFG3, 0x39 }, + { CC2500_12_MDMCFG2, 0x11 }, + { CC2500_13_MDMCFG1, 0x23 }, + { CC2500_14_MDMCFG0, 0x7a }, + { CC2500_15_DEVIATN, 0x42 }, + { CC2500_19_FOCCFG, 0x16 }, + { CC2500_1A_BSCFG, 0x6c }, + { CC2500_1B_AGCCTRL2, 0x43 }, // bind ? 0x43 : 0x03 + { CC2500_1C_AGCCTRL1,0x40 }, + { CC2500_1D_AGCCTRL0,0x91 }, + { CC2500_21_FREND1, 0x56 }, + { CC2500_22_FREND0, 0x10 }, + { CC2500_23_FSCAL3, 0xa9 }, + { CC2500_24_FSCAL2, 0x0A }, + { CC2500_25_FSCAL1, 0x00 }, + { CC2500_26_FSCAL0, 0x11 }, + { CC2500_29_FSTEST, 0x59 }, + { CC2500_2C_TEST2, 0x88 }, + { CC2500_2D_TEST1, 0x31 }, + { CC2500_2E_TEST0, 0x0B }, + { CC2500_03_FIFOTHR, 0x07 }, + { CC2500_09_ADDR, 0x00 } +}; #endif diff --git a/Multiprotocol/multiprotocol.h b/Multiprotocol/multiprotocol.h index d731f27..b2b9e81 100644 --- a/Multiprotocol/multiprotocol.h +++ b/Multiprotocol/multiprotocol.h @@ -30,6 +30,11 @@ enum PROTOCOLS MODE_H377=44, // =>NRF24L01 MODE_WK2x01 = 45, // =>CYRF6936 MODE_FY326=46, // =>NRF24L01 + MODE_ESKY150=47, // =>NRF24L01 + MODE_BlueFly=48, // =>NRF24L01 + MODE_HonTai=49, // =>NRF24L01 + MODE_UDI=50, // =>NRF24L01 + MODE_NE260=51, // =>NRF24L01 MODE_SERIAL = 0, // Serial commands MODE_FLYSKY = 1, // =>A7105 @@ -49,7 +54,8 @@ enum PROTOCOLS MODE_FRSKYX = 15, // =>CC2500 MODE_ESKY = 16, // =>NRF24L01 MODE_MT99XX=17, // =>NRF24L01 - MODE_MJXQ=18 // =>NRF24L01 + MODE_MJXQ=18, // =>NRF24L01 + MODE_SHENQI=19 // =>NRF24L01 }; enum Flysky { @@ -127,6 +133,12 @@ enum FY326 FY326 = 0, FY319 = 1 }; +enum UDI +{ + U816_V1 = 0, + U816_V2, + U839_2014 +}; #define NONE 0 #define P_HIGH 1 @@ -147,10 +159,6 @@ struct PPM_Parameters //******************* //*** Pinouts *** //******************* -#define BUZZER 19 //A5 -#define BUZZER_HTZ 440 // La clé de sol -#define BUZZER_TPS 300 - //#define BIND_pin 13 #define LED_pin 13 //Promini original led on B5 // @@ -440,6 +448,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- ESky 16 MT99XX 17 MJXQ 18 + SHENQI 19 BindBit=> 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No diff --git a/README.md b/README.md index dc4bccd..3c27e54 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7 CH1|CH2|CH3|CH4|???|CONF|Gyro & Rudder mix CONF: Option 1 = Rate Throtle + Option 2 = Pitch @@ -76,6 +77,13 @@ CH1|CH2|CH3|CH4 A|E|T|R ##NRF24L01 RF Module +###BLUEFLY +Autobind + +CH1|CH2|CH3|CH4|CH5|CH6 +---|---|---|---|---|--- +A|E|T|R|GEAR|PITCH + ###CFLIE Modele: CrazyFlie Nano quad @@ -85,6 +93,14 @@ CH1|CH2|CH3|CH4 ---|---|---|--- A|E|T|R +###ESKY150 + +Autobind + +CH1|CH2|CH3|CH4 +---|---|---|--- +A|E|T|R + ###Fy326 Autobind @@ -107,6 +123,51 @@ Autobind CH1|CH2|CH3|CH4|CH5 ---|---|---|--- -A|Turbo|T|Trim|Bouton ??? +A|Turbo|T|Trim|Bouton + +###HONTAI +Autobind + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11 +---|---|---|---|---|---|---|---|---|---|--- +A|E|T|R|LED|FLIP|PICTURE|VIDEO|HEADLESS|RTH|Calibrate + +####Sub_protocol JJRCX1 +Modele: JJRC X1 + +CH5|CH6|CH7|CH8|CH9|CH10|CH11 +---|---|---|---|---|---|---|---|---|---|--- +ARM|FLIP|PICTURE|VIDEO|HEADLESS|RTH|Calibrate + +###NE260 +Modele: Nine Eagles SoloPro + +Autobind + +CH1|CH2|CH3|CH4 +---|---|---|--- +A|E|T|R + +###UDI +Modele: Known UDI 2.4GHz protocol variants, all using BK2421 +* UDI U819 coaxial 3ch helicoper +* UDI U816/817/818 quadcopters + - "V1" with orange LED on TX, U816 RX labeled '' , U817/U818 RX labeled 'UD-U817B' + - "V2" with red LEDs on TX, U816 RX labeled '', U817/U818 RX labeled 'UD-U817OG' + - "V3" with green LEDs on TX. Did not get my hands on yet. +* U830 mini quadcopter with tilt steering ("Protocol 2014") +* U839 nano quadcopter ("Protocol 2014") + +Autobind + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10 +---|---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP 360|FLIP|VIDEO|LED|MODE 2 + +####Sub_protocol U816 V1 (orange) +####Sub_protocol U816 V2 (red) +####Sub_protocol U816 (2014) +Same channels assignement as above. + ###D'autres à venir \ No newline at end of file