diff --git a/AVR8_Burn-O-Mat_2_1_2_setup.exe b/AVR8_Burn-O-Mat_2_1_2_setup.exe
new file mode 100644
index 0000000..5f9e431
Binary files /dev/null and b/AVR8_Burn-O-Mat_2_1_2_setup.exe differ
diff --git a/Multiprotocol/A7105_joysway.ino b/Multiprotocol/A7105_joysway.ino
new file mode 100644
index 0000000..1aed90d
--- /dev/null
+++ b/Multiprotocol/A7105_joysway.ino
@@ -0,0 +1,164 @@
+/*
+ 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 JOYSWAY_A7105_INO
+#include "iface_a7105.h"
+
+
+#define EVEN_ODD 0x00
+//#define EVEN_ODD 0x01
+static const uint8_t A7105_regs[] = {
+ 0x00, 0x62, -1, 0x0f, 0x00, -1 , -1 , 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0xf5, 0x00, 0x15,
+ 0x9e, 0x4b, 0x00, 0x03, 0x56, 0x2b, 0x12, 0x4a, 0x02, 0x80, 0x80, 0x00, 0x0e, 0x91, 0x03, 0x0f,
+ 0x16, 0x2a, 0x00, -1, -1, -1, 0x3a, 0x06, 0x1f, 0x47, 0x80, 0x01, 0x05, 0x45, 0x18, 0x00,
+ 0x01, 0x0f, 0x00
+};
+
+static uint8_t next_ch;
+
+static int joysway_init()
+{
+ int i;
+ uint8_t if_calibration1;
+ //uint8_t vco_calibration0;
+ //uint8_t vco_calibration1;
+
+ phase = 0;
+ next_ch = 0x30;
+
+ for (i = 0; i < 0x33; i++)
+ if((uint8_t)A7105_regs[i] != -1)
+ A7105_WriteReg(i, A7105_regs[i]);
+ A7105_WriteID(0x5475c52a);
+
+ A7105_Strobe(A7105_PLL);
+
+ //IF Filter Bank Calibration
+ A7105_WriteReg(0x02, 1);
+ A7105_ReadReg(0x02);
+ uint32_t ms = micros();
+ while(micros() - ms < 500) {
+ if(! A7105_ReadReg(0x02))
+ break;
+ }
+ if (micros() - ms >= 500)
+ return 0;
+ A7105_Strobe(A7105_STANDBY);
+ if_calibration1 = A7105_ReadReg(0x22);
+ if(if_calibration1 & A7105_MASK_FBCF) {
+ //Calibration failed...what do we do?
+ return 0;
+ }
+
+ //VCO Current Calibration
+ A7105_WriteReg(0x24, 0x13); //Recomended calibration from A7105 Datasheet
+ A7105_WriteReg(0x25, 0x09); //Recomended calibration from A7105 Datasheet
+
+ A7105_WriteID(MProtocol_id_master);
+ A7105_Strobe(A7105_PLL);
+ A7105_WriteReg(0x02, 1);
+ ms = micros();
+ while(micros() - ms < 500) {
+ if(! A7105_ReadReg(0x02))
+ break;
+ }
+ if (micros() - ms >= 500)
+ return 0;
+ A7105_Strobe(A7105_STANDBY);
+ if_calibration1 = A7105_ReadReg(0x22);
+ if(if_calibration1 & A7105_MASK_FBCF) {
+ //Calibration failed...what do we do?
+ return 0;
+ }
+ A7105_WriteReg(0x24, 0x13); //Recomended calibration from A7105 Datasheet
+ A7105_WriteReg(0x25, 0x09); //Recomended calibration from A7105 Datasheet
+
+ A7105_SetTxRxMode(TX_EN);
+ A7105_SetPower();
+
+ A7105_Strobe(A7105_STANDBY);
+ return 1;
+}
+
+static void joysway_build_packet()
+{
+ int i;
+ //-100% =~ 0x03e8
+ //+100% =~ 0x07ca
+ //Calculate:
+ //Center = 0x5d9
+ //1 % = 5
+ packet[0] = phase == 0 ? 0xdd : 0xff;
+ packet[1] = (MProtocol_id_master >> 24) & 0xff;
+ packet[2] = (MProtocol_id_master >> 16) & 0xff;
+ packet[3] = (MProtocol_id_master >> 8) & 0xff;
+ packet[4] = (MProtocol_id_master >> 0) & 0xff;
+ packet[5] = 0x00;
+ static const int chmap[4] = {6, 7, 10, 11};
+ for (i = 0; i < 4; i++) {
+// if (i >= Model.num_channels) { packet[chmap[i]] = 0x64; continue; }
+ uint32_t value = (uint32_t)Servo_data[i] * 0x66 / PPM_MAX + 0x66;
+ if (value < 0) { value = 0; }
+ if (value > 0xff) { value = 0xff; }
+ packet[chmap[i]] = value;
+ }
+ packet[8] = 0x64;
+ packet[9] = 0x64;
+ packet[12] = 0x64;
+ packet[13] = 0x64;
+ packet[14] = phase == 0 ? 0x30 : 0xaa;
+ uint8_t value = 0;
+ for (int i = 0; i < 15; i++) { value += packet[i]; }
+ packet[15] = value;
+}
+
+static uint16_t joysway_cb()
+{
+ uint8_t ch;
+ if (phase == 254) {
+ phase = 0;
+ A7105_WriteID(0x5475c52a);
+ ch = 0x0a;
+ } else if (phase == 2) {
+ A7105_WriteID(MProtocol_id_master);
+ ch = 0x30;
+ } else {
+ if ((phase & 0x01) ^ EVEN_ODD) {
+ ch = 0x30;
+ } else {
+ ch = next_ch;
+ }
+ }
+ if (! ((phase & 0x01) ^ EVEN_ODD)) {
+ next_ch++;
+ if (next_ch == 0x45)
+ next_ch = 0x30;
+ }
+ joysway_build_packet();
+ A7105_Strobe(A7105_STANDBY);
+ A7105_WriteData(16, ch);
+ phase++;
+ return 6000;
+}
+
+static uint16_t JOYSWAY_Setup() {
+ while(1) {
+ A7105_Reset();
+ if (joysway_init())
+ break;
+ }
+ return 2400;
+}
+#endif
diff --git a/Multiprotocol/CX10_nrf24l01.ino b/Multiprotocol/CX10_nrf24l01.ino
index f836e02..adc7279 100644
--- a/Multiprotocol/CX10_nrf24l01.ino
+++ b/Multiprotocol/CX10_nrf24l01.ino
@@ -25,6 +25,10 @@
#define Q282_PACKET_SIZE 21
#define CX10_PACKET_PERIOD 1316 // Timeout for callback in uSec
#define CX10A_PACKET_PERIOD 6000
+<<<<<<< HEAD
+#define CX10A_BIND_COUNT 400 // 2 seconds
+=======
+>>>>>>> refs/remotes/pascallanger/master
#define CX10_INITIAL_WAIT 500
@@ -197,15 +201,30 @@ uint16_t CX10_callback()
}
break;
case CX10_BIND2:
+<<<<<<< HEAD
+ bind_counter--;
+ if(bind_counter==0)
+ { // Needed for some CX-10A to properly finish the bind
+ CX10_init();
+ bind_counter=CX10A_BIND_COUNT;
+ }
+ if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR))
+=======
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
+>>>>>>> refs/remotes/pascallanger/master
{ // RX fifo data ready
XN297_ReadPayload(packet, packet_length);
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(TX_EN);
if(packet[9] == 1)
{
+<<<<<<< HEAD
+ phase = CX10_BIND1;
+ bind_counter=0;
+=======
BIND_DONE;
phase = CX10_DATA;
+>>>>>>> refs/remotes/pascallanger/master
}
}
else
@@ -215,7 +234,11 @@ uint16_t CX10_callback()
NRF24L01_FlushTx();
NRF24L01_SetTxRxMode(TX_EN);
CX10_Write_Packet(1);
+<<<<<<< HEAD
+ delayMicroseconds(400); // 300µs in deviation but not working so using 400µs instead
+=======
delayMicroseconds(400);
+>>>>>>> refs/remotes/pascallanger/master
// switch to RX mode
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_FlushRx();
@@ -265,6 +288,10 @@ uint16_t initCX10(void)
packet_period = CX10A_PACKET_PERIOD;
phase = CX10_BIND2;
+<<<<<<< HEAD
+ bind_counter=CX10A_BIND_COUNT;
+=======
+>>>>>>> refs/remotes/pascallanger/master
for(uint8_t i=0; i<4; i++)
packet[5+i] = 0xff; // clear aircraft id
diff --git a/Multiprotocol/CYRF6936_SPI.ino b/Multiprotocol/CYRF6936_SPI.ino
index 2b2d52a..6a3bae6 100644
--- a/Multiprotocol/CYRF6936_SPI.ino
+++ b/Multiprotocol/CYRF6936_SPI.ino
@@ -192,11 +192,18 @@ static void CYRF_StartReceive()
CYRF_ReadRegisterMulti(CYRF_21_RX_BUFFER, dpbuffer, 0x10);
}
*/
+<<<<<<< HEAD
+static void CYRF_ReadDataPacketLen(uint8_t dpbuffer[], uint8_t length)
+=======
void CYRF_ReadDataPacketLen(uint8_t dpbuffer[], uint8_t length)
+>>>>>>> refs/remotes/pascallanger/master
{
CYRF_ReadRegisterMulti(CYRF_21_RX_BUFFER, dpbuffer, length);
}
+<<<<<<< HEAD
+=======
+>>>>>>> refs/remotes/pascallanger/master
static void CYRF_WriteDataPacketLen(const uint8_t dpbuffer[], uint8_t len)
{
CYRF_WriteRegister(CYRF_01_TX_LENGTH, len);
diff --git a/Multiprotocol/CYRF6936_j6pro.ino b/Multiprotocol/CYRF6936_j6pro.ino
new file mode 100644
index 0000000..623ae5f
--- /dev/null
+++ b/Multiprotocol/CYRF6936_j6pro.ino
@@ -0,0 +1,277 @@
+/*
+ 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(J6PRO_CYRF6936_INO)
+#include "iface_cyrf6936.h"
+
+#define NUM_WAIT_LOOPS (100 / 5) //each loop is ~5us. Do not wait more than 100us
+
+//For Debug
+//#define NO_SCRAMBLE
+
+enum J6ProState {
+ J6PRO_BIND,
+ J6PRO_BIND_01,
+ J6PRO_BIND_03_START,
+ J6PRO_BIND_03_CHECK,
+ J6PRO_BIND_05_1,
+ J6PRO_BIND_05_2,
+ J6PRO_BIND_05_3,
+ J6PRO_BIND_05_4,
+ J6PRO_BIND_05_5,
+ J6PRO_BIND_05_6,
+ J6PRO_CHANSEL,
+ J6PRO_CHAN_1,
+ J6PRO_CHAN_2,
+ J6PRO_CHAN_3,
+ J6PRO_CHAN_4,
+};
+
+static const uint8_t J6Pro_sopcodes[][8] = {
+ /* Note these are in order transmitted (LSB 1st) */
+ {0x3C, 0x37, 0xCC, 0x91, 0xE2, 0xF8, 0xCC, 0x91},
+ {0x9B, 0xC5, 0xA1, 0x0F, 0xAD, 0x39, 0xA2, 0x0F},
+ {0xEF, 0x64, 0xB0, 0x2A, 0xD2, 0x8F, 0xB1, 0x2A},
+ {0x66, 0xCD, 0x7C, 0x50, 0xDD, 0x26, 0x7C, 0x50},
+ {0x5C, 0xE1, 0xF6, 0x44, 0xAD, 0x16, 0xF6, 0x44},
+ {0x5A, 0xCC, 0xAE, 0x46, 0xB6, 0x31, 0xAE, 0x46},
+ {0xA1, 0x78, 0xDC, 0x3C, 0x9E, 0x82, 0xDC, 0x3C},
+ {0xB9, 0x8E, 0x19, 0x74, 0x6F, 0x65, 0x18, 0x74},
+ {0xDF, 0xB1, 0xC0, 0x49, 0x62, 0xDF, 0xC1, 0x49},
+ {0x97, 0xE5, 0x14, 0x72, 0x7F, 0x1A, 0x14, 0x72},
+ {0x82, 0xC7, 0x90, 0x36, 0x21, 0x03, 0xFF, 0x17},
+ {0xE2, 0xF8, 0xCC, 0x91, 0x3C, 0x37, 0xCC, 0x91}, //Note: the '03' was '9E' in the Cypress recommended table
+ {0xAD, 0x39, 0xA2, 0x0F, 0x9B, 0xC5, 0xA1, 0x0F}, //The following are the same as the 1st 8 above,
+ {0xD2, 0x8F, 0xB1, 0x2A, 0xEF, 0x64, 0xB0, 0x2A}, //but with the upper and lower word swapped
+ {0xDD, 0x26, 0x7C, 0x50, 0x66, 0xCD, 0x7C, 0x50},
+ {0xAD, 0x16, 0xF6, 0x44, 0x5C, 0xE1, 0xF6, 0x44},
+ {0xB6, 0x31, 0xAE, 0x46, 0x5A, 0xCC, 0xAE, 0x46},
+ {0x9E, 0x82, 0xDC, 0x3C, 0xA1, 0x78, 0xDC, 0x3C},
+ {0x6F, 0x65, 0x18, 0x74, 0xB9, 0x8E, 0x19, 0x74},
+};
+const uint8_t bind_sop_code[] = {0x62, 0xdf, 0xc1, 0x49, 0xdf, 0xb1, 0xc0, 0x49};
+const uint8_t data_code[] = {0x02, 0xf9, 0x93, 0x97, 0x02, 0xfa, 0x5c, 0xe3, 0x01, 0x2b, 0xf1, 0xdb, 0x01, 0x32, 0xbe, 0x6f};
+
+static uint8_t stateJ6P;
+static uint8_t radio_ch[4];
+static uint8_t num_channels;
+
+void J6Pro_build_bind_packet()
+{
+ packet[0] = 0x01; //Packet type
+ packet[1] = 0x01; //FIXME: What is this? Model number maybe?
+ packet[2] = 0x56; //FIXME: What is this?
+ packet[3] = cyrfmfg_id[0];
+ packet[4] = cyrfmfg_id[1];
+ packet[5] = cyrfmfg_id[2];
+ packet[6] = cyrfmfg_id[3];
+ packet[7] = cyrfmfg_id[4];
+ packet[8] = cyrfmfg_id[5];
+}
+void J6Pro_build_data_packet()
+{
+ uint8_t i;
+ uint32_t upperbits = 0;
+ packet[0] = 0xaa; //FIXME what is this?
+ for (i = 0; i < 12; i++) {
+ if (i >= num_channels) {
+ packet[i+1] = 0xff;
+ continue;
+ }
+ uint32_t value = (uint32_t)Servo_data[i] * 0x200 / PPM_MAX + 0x200;
+ if (value < 0)
+ value = 0;
+ if (value > 0x3ff)
+ value = 0x3ff;
+ packet[i+1] = value & 0xff;
+ upperbits |= (value >> 8) << (i * 2);
+ }
+ packet[13] = upperbits & 0xff;
+ packet[14] = (upperbits >> 8) & 0xff;
+ packet[15] = (upperbits >> 16) & 0xff;
+}
+
+static void J6Pro_cyrf_init()
+{
+ /* Initialise CYRF chip */
+ CYRF_WriteRegister(CYRF_28_CLK_EN, 0x02);
+ CYRF_WriteRegister(CYRF_32_AUTO_CAL_TIME, 0x3c);
+ CYRF_WriteRegister(CYRF_35_AUTOCAL_OFFSET, 0x14);
+ CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, 0x05);
+ CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, 0x55);
+ CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25);
+ CYRF_WriteRegister(CYRF_03_TX_CFG, 0x05 | CYRF_BIND_POWER);
+ CYRF_WriteRegister(CYRF_06_RX_CFG, 0x8a);
+ CYRF_WriteRegister(CYRF_03_TX_CFG, 0x28 | CYRF_BIND_POWER);
+ CYRF_WriteRegister(CYRF_12_DATA64_THOLD, 0x0e);
+ CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0xee);
+ CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x00);
+ CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x00);
+ CYRF_ConfigDataCode(data_code, 16);
+ CYRF_WritePreamble(0x023333);
+}
+static void J6Pro_cyrf_bindinit()
+{
+/* Use when binding */
+ //0.060470# 03 2f
+ CYRF_WriteRegister(CYRF_03_TX_CFG, 0x28 | 0x07); //Use max power for binding in case there is no telem module
+
+ CYRF_ConfigRFChannel(0x52);
+ CYRF_ConfigSOPCode(bind_sop_code);
+ CYRF_ConfigCRCSeed(0x0000);
+ CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4a);
+ CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83);
+ //0.061511# 13 20
+
+ CYRF_ConfigRFChannel(0x52);
+ //0.062684# 0f 05
+ CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25);
+ //0.062792# 0f 05
+ CYRF_WriteRegister(CYRF_02_TX_CTRL, 0x40);
+ J6Pro_build_bind_packet(); //01 01 e9 49 ec a9 c4 c1 ff
+ //CYRF_WriteDataPacketLen(packet, 0x09);
+}
+static void J6Pro_cyrf_datainit()
+{
+/* Use when already bound */
+ //0.094007# 0f 05
+ uint8_t sop_idx = (0xff & (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + cyrfmfg_id[3] - cyrfmfg_id[5])) % 19;
+ uint16_t crc = (0xff & (cyrfmfg_id[1] - cyrfmfg_id[4] + cyrfmfg_id[5])) |
+ ((0xff & (cyrfmfg_id[2] + cyrfmfg_id[3] - cyrfmfg_id[4] + cyrfmfg_id[5])) << 8);
+ CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25);
+ CYRF_ConfigSOPCode(J6Pro_sopcodes[sop_idx]);
+ CYRF_ConfigCRCSeed(crc);
+}
+
+static void J6Pro_set_radio_channels()
+{
+ //FIXME: Query free channels
+ //lowest channel is 0x08, upper channel is 0x4d?
+ CYRF_FindBestChannels(radio_ch, 3, 5, 8, 77);
+ radio_ch[3] = radio_ch[0];
+}
+
+static uint16_t j6pro_cb()
+{
+ switch(stateJ6P) {
+ case J6PRO_BIND:
+ J6Pro_cyrf_bindinit();
+ stateJ6P = J6PRO_BIND_01;
+ //no break because we want to send the 1st bind packet now
+ case J6PRO_BIND_01:
+ CYRF_ConfigRFChannel(0x52);
+ CYRF_SetTxRxMode(TX_EN);
+ //0.062684# 0f 05
+ CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25);
+ //0.062684# 0f 05
+ CYRF_WriteDataPacketLen(packet, 0x09);
+ stateJ6P = J6PRO_BIND_03_START;
+ return 3000; //3msec
+ case J6PRO_BIND_03_START:
+ {
+ int i = 0;
+ while (! (CYRF_ReadRegister(0x04) & 0x06))
+ if(++i > NUM_WAIT_LOOPS)
+ break;
+ }
+ CYRF_ConfigRFChannel(0x53);
+ CYRF_SetTxRxMode(RX_EN);
+ CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4a);
+ CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83);
+ stateJ6P = J6PRO_BIND_03_CHECK;
+ return 30000; //30msec
+ case J6PRO_BIND_03_CHECK:
+ {
+ uint8_t rx = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS);
+ if((rx & 0x1a) == 0x1a) {
+ rx = CYRF_ReadRegister(CYRF_0A_RX_LENGTH);
+ if(rx == 0x0f) {
+ rx = CYRF_ReadRegister(CYRF_09_RX_COUNT);
+ if(rx == 0x0f) {
+ //Expected and actual length are both 15
+ CYRF_ReadDataPacketLen(packet, rx);
+ if (packet[0] == 0x03 &&
+ packet[3] == cyrfmfg_id[0] &&
+ packet[4] == cyrfmfg_id[1] &&
+ packet[5] == cyrfmfg_id[2] &&
+ packet[6] == cyrfmfg_id[3] &&
+ packet[7] == cyrfmfg_id[4] &&
+ packet[8] == cyrfmfg_id[5])
+ {
+ //Send back Ack
+ packet[0] = 0x05;
+ CYRF_ConfigRFChannel(0x54);
+ CYRF_SetTxRxMode(TX_EN);
+ stateJ6P = J6PRO_BIND_05_1;
+ return 2000; //2msec
+ }
+ }
+ }
+ }
+ stateJ6P = J6PRO_BIND_01;
+ return 500;
+ }
+ case J6PRO_BIND_05_1:
+ case J6PRO_BIND_05_2:
+ case J6PRO_BIND_05_3:
+ case J6PRO_BIND_05_4:
+ case J6PRO_BIND_05_5:
+ case J6PRO_BIND_05_6:
+ CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25);
+ CYRF_WriteDataPacketLen(packet, 0x0f);
+ stateJ6P = stateJ6P + 1;
+ return 4600; //4.6msec
+ case J6PRO_CHANSEL:
+ BIND_DONE;
+ J6Pro_set_radio_channels();
+ J6Pro_cyrf_datainit();
+ stateJ6P = J6PRO_CHAN_1;
+ case J6PRO_CHAN_1:
+ //Keep transmit power updated
+ CYRF_SetPower(CYRF_HIGH_POWER);
+ J6Pro_build_data_packet();
+ //return 3400;
+ case J6PRO_CHAN_2:
+ //return 3500;
+ case J6PRO_CHAN_3:
+ //return 3750
+ case J6PRO_CHAN_4:
+ CYRF_ConfigRFChannel(radio_ch[stateJ6P - J6PRO_CHAN_1]);
+ CYRF_SetTxRxMode(TX_EN);
+ CYRF_WriteDataPacket(packet);
+ if (stateJ6P == J6PRO_CHAN_4) {
+ stateJ6P = J6PRO_CHAN_1;
+ return 13900;
+ }
+ stateJ6P = stateJ6P + 1;
+ return 3550;
+ }
+ return 0;
+}
+
+static uint16_t j6pro_setup()
+{
+ CYRF_Reset();
+ J6Pro_cyrf_init();
+ num_channels = 8;
+ if (IS_AUTOBIND_FLAG_on) {
+ stateJ6P = J6PRO_BIND;
+ BIND_IN_PROGRESS;
+ } else {
+ stateJ6P = J6PRO_CHANSEL;
+ }
+ return 2400;
+}
+#endif
diff --git a/Multiprotocol/Cc2500_skyartec.ino b/Multiprotocol/Cc2500_skyartec.ino
new file mode 100644
index 0000000..7f3a932
--- /dev/null
+++ b/Multiprotocol/Cc2500_skyartec.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(SKYARTEC_CC2500_INO)
+#include "iface_cc2500.h"
+
+#define TX_ADDR ((binding_idx >> 16) & 0xff)
+#define TX_CHANNEL ((binding_idx >> 24) & 0xff)
+
+enum {
+ SKYARTEC_PKT1 = 0,
+ SKYARTEC_SLEEP1,
+ SKYARTEC_PKT2,
+ SKYARTEC_SLEEP2,
+ SKYARTEC_PKT3,
+ SKYARTEC_SLEEP3,
+ SKYARTEC_PKT4,
+ SKYARTEC_SLEEP4,
+ SKYARTEC_PKT5,
+ SKYARTEC_SLEEP5,
+ SKYARTEC_PKT6,
+ SKYARTEC_LAST,
+};
+
+static void skyartec_init() {
+ CC2500_Reset();
+
+ cc2500_writeReg(CC2500_16_MCSM2, 0x07);
+ cc2500_writeReg(CC2500_17_MCSM1, 0x30);
+ cc2500_writeReg(CC2500_1E_WOREVT1, 0x87);
+ cc2500_writeReg(CC2500_1F_WOREVT0, 0x6b);
+ cc2500_writeReg(CC2500_20_WORCTRL, 0xf8);
+ cc2500_writeReg(CC2500_2A_PTEST, 0x7f);
+ cc2500_writeReg(CC2500_2B_AGCTEST, 0x3f);
+ cc2500_writeReg(CC2500_0B_FSCTRL1, 0x09);
+ cc2500_writeReg(CC2500_0C_FSCTRL0, 0x00);
+ cc2500_writeReg(CC2500_0D_FREQ2, 0x5d);
+ cc2500_writeReg(CC2500_0E_FREQ1, 0x93);
+ cc2500_writeReg(CC2500_0F_FREQ0, 0xb1);
+ cc2500_writeReg(CC2500_10_MDMCFG4, 0x2d);
+ cc2500_writeReg(CC2500_11_MDMCFG3, 0x20);
+ cc2500_writeReg(CC2500_12_MDMCFG2, 0x73);
+ cc2500_writeReg(CC2500_13_MDMCFG1, 0x22);
+ cc2500_writeReg(CC2500_14_MDMCFG0, 0xf8);
+ cc2500_writeReg(CC2500_0A_CHANNR, 0xcd);
+ cc2500_writeReg(CC2500_15_DEVIATN, 0x50);
+ cc2500_writeReg(CC2500_21_FREND1, 0xb6);
+ cc2500_writeReg(CC2500_22_FREND0, 0x10);
+ cc2500_writeReg(CC2500_18_MCSM0, 0x18);
+ cc2500_writeReg(CC2500_19_FOCCFG, 0x1d);
+ cc2500_writeReg(CC2500_1A_BSCFG, 0x1c);
+ cc2500_writeReg(CC2500_1B_AGCCTRL2, 0xc7);
+ cc2500_writeReg(CC2500_1C_AGCCTRL1, 0x00);
+ cc2500_writeReg(CC2500_1D_AGCCTRL0, 0xb2);
+ cc2500_writeReg(CC2500_23_FSCAL3, 0xea);
+ 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_07_PKTCTRL1, 0x05);
+ cc2500_writeReg(CC2500_08_PKTCTRL0, 0x05);
+ cc2500_writeReg(CC2500_09_ADDR, 0x43);
+ cc2500_writeReg(CC2500_06_PKTLEN, 0xff);
+ cc2500_writeReg(CC2500_04_SYNC1, 0x13);
+ cc2500_writeReg(CC2500_05_SYNC0, 0x18);
+ CC2500_SetTxRxMode(TX_EN);
+ CC2500_SetPower();
+ cc2500_strobe(CC2500_SFTX);
+ cc2500_strobe(CC2500_SFRX);
+ cc2500_strobe(CC2500_SXOFF);
+ cc2500_strobe(CC2500_SIDLE);
+}
+
+static void add_pkt_suffix() {
+ int xor1 = 0;
+ int xor2 = 0;
+ for(int i = 3; i <= 16; i++) { xor1 ^= packet[i]; }
+ for(int i = 3; i <= 14; i++) { xor2 ^= packet[i]; }
+
+ int sum = packet[3] + packet[5] + packet[7] + packet[9] + packet[11] + packet[13];
+ packet[17] = xor1;
+ packet[18] = xor2;
+ packet[19] = sum & 0xff;
+}
+
+static void send_data_packet() {
+ //13 c5 01 0259 0168 0000 0259 030c 021a 0489 f3 7e 0a
+ packet[0] = 0x13; //Length
+ packet[1] = TX_ADDR; //Tx Addr?
+ packet[2] = 0x01; //???
+ for(int i = 0; i < 7; i++) {
+ uint32_t value = (uint32_t)Servo_data[i] * 0x280 / PPM_MAX + 0x280;
+ if(value < 0) { value = 0; }
+ if(value > 0x500) { value = 0x500; }
+ packet[3+2*i] = value >> 8;
+ packet[4+2*i] = value & 0xff;
+ }
+ add_pkt_suffix();
+ //for(int i = 0; i < 20; i++) printf("%02x ", packet[i]); printf("\n");
+ cc2500_writeReg(CC2500_04_SYNC1, ((binding_idx >> 0) & 0xff));
+ cc2500_writeReg(CC2500_05_SYNC0, ((binding_idx >> 8) & 0xff));
+ cc2500_writeReg(CC2500_09_ADDR, TX_ADDR);
+ cc2500_writeReg(CC2500_0A_CHANNR, TX_CHANNEL);
+ cc2500_writeFifo(packet, 20);
+}
+
+static void send_bind_packet() {
+ //0b 7d 01 01 b2 c5 4a 2f 00 00 c5 d6
+ packet[0] = 0x0b; //Length
+ packet[1] = 0x7d;
+ packet[2] = 0x01;
+ packet[3] = 0x01;
+ packet[4] = (binding_idx >> 24) & 0xff;
+ packet[5] = (binding_idx >> 16) & 0xff;
+ packet[6] = (binding_idx >> 8) & 0xff;
+ packet[7] = (binding_idx >> 0) & 0xff;
+ packet[8] = 0x00;
+ packet[9] = 0x00;
+ packet[10] = TX_ADDR;
+ uint8_t xore = 0;
+ for(int i = 3; i < 11; i++) { xore ^= packet[i]; }
+ packet[11] = xore;
+ cc2500_writeReg(CC2500_04_SYNC1, 0x7d);
+ cc2500_writeReg(CC2500_05_SYNC0, 0x7d);
+ cc2500_writeReg(CC2500_09_ADDR, 0x7d);
+ cc2500_writeReg(CC2500_0A_CHANNR, 0x7d);
+ cc2500_writeFifo(packet, 12);
+}
+
+static uint16_t skyartec_cb() {
+ if (state & 0x01) {
+ cc2500_strobe(CC2500_SIDLE);
+ if (state == SKYARTEC_LAST) { CC2500_SetPower(); state = SKYARTEC_PKT1; }
+ else { state++; }
+ return 3000;
+ }
+ if (state == SKYARTEC_PKT1 && bind_phase) {
+ send_bind_packet();
+ bind_phase--;
+ if(bind_phase == 0) { printf("Done binding\n"); }
+ } else { send_data_packet(); }
+ state++;
+ return 3000;
+}
+
+static uint8_t skyartec_setup() {
+ skyartec_init();
+/* binding_idx = 0xb2c54a2f;
+ if (Model.fixed_id) {
+ binding_idx ^= Model.binding_idx + (Model.fixed_id << 16);
+ } else {
+ int partnum = CC2500_ReadReg(0xF0);
+ int vernum = CC2500_ReadReg(0xF1);
+ binding_idx ^= partnum << 24;
+ binding_idx ^= vernum << 16;
+ binding_idx ^= (vernum << 4 | partnum >> 4) << 8;
+ binding_idx ^= (partnum << 4 | vernum >> 4) << 8;
+ }
+*/
+ binding_idx = MProtocol_id;
+ if (0 == (binding_idx & 0xff000000)) { binding_idx |= 0xb2; }
+ if (0 == (binding_idx & 0x00ff0000)) { binding_idx |= 0xc5; }
+ if (0 == (binding_idx & 0x0000ff00)) { binding_idx |= 0x4a; }
+ if (0 == (binding_idx & 0x000000ff)) { binding_idx |= 0x2f; }
+ bind_phase = 10000;
+ state = SKYARTEC_PKT1;
+}
+#endif
\ No newline at end of file
diff --git a/Multiprotocol/Cyrf6936_wk2x01.ino b/Multiprotocol/Cyrf6936_wk2x01.ino
new file mode 100644
index 0000000..58e866a
--- /dev/null
+++ b/Multiprotocol/Cyrf6936_wk2x01.ino
@@ -0,0 +1,449 @@
+/*
+ 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(WK2x01_CYRF6936_INO)
+#include "iface_cyrf6936.h"
+
+#define PKTS_PER_CHANNEL 4
+
+//Fewer bind packets in the emulator so we can get right to the important bits
+#define WK_BIND_COUNT 2980
+
+#define NUM_WAIT_LOOPS (100 / 5) //each loop is ~5us. Do not wait more than 100us
+
+
+#define WK_BIND 0
+#define WK_BOUND_1 1
+#define WK_BOUND_2 2
+#define WK_BOUND_3 3
+#define WK_BOUND_4 4
+#define WK_BOUND_5 5
+#define WK_BOUND_6 6
+#define WK_BOUND_7 7
+#define WK_BOUND_8 8
+
+static const uint8_t sopcode[8] = {
+ /* Note these are in order transmitted (LSB 1st) */
+ 0xDF,0xB1,0xC0,0x49,0x62,0xDF,0xC1,0x49 //0x49C1DF6249C0B1DF
+};
+static const uint8_t fail_map[8] = {2, 1, 0, 3, 4, 5, 6, 7};
+
+static uint8_t wk_pkt_num;
+static uint8_t *radio_ch_ptr;
+static uint16_t WK_BIND_COUNTer;
+static uint8_t last_beacon;
+/*
+static const char * const wk2601_opts[] = {
+ _tr_noop("Chan mode"), _tr_noop("5+1"), _tr_noop("Heli"), _tr_noop("6+1"), NULL,
+ _tr_noop("COL Inv"), _tr_noop("Normal"), _tr_noop("Inverted"), NULL,
+ _tr_noop("COL Limit"), "-100", "100", NULL,
+ NULL
+};
+#define WK2601_OPT_CHANMODE 0
+#define WK2601_OPT_PIT_INV 1
+#define WK2601_OPT_PIT_LIMIT 2
+#define LAST_PROTO_OPT 3
+*/
+
+static void add_pkt_crc(uint8_t init) {
+ uint8_t add = init;
+ uint8_t xou = init;
+ int i;
+ for (i = 0; i < 14; i++) { add += packet[i]; xou ^= packet[i]; }
+ packet[14] = xou;
+ packet[15] = add & 0xff;
+}
+static const char init_2801[] = {0xc5, 0x34, 0x60, 0x00, 0x25};
+static const char init_2601[] = {0xb9, 0x45, 0xb0, 0xf1, 0x3a};
+static const char init_2401[] = {0xa5, 0x23, 0xd0, 0xf0, 0x00};
+static void build_bind_pkt(const char *init) {
+ packet[0] = init[0];
+ packet[1] = init[1];
+ packet[2] = rx_tx_addr[0];
+ packet[3] = rx_tx_addr[1];
+ packet[4] = init[2];
+ packet[5] = rx_tx_addr[2];
+ packet[6] = 0xff;
+ packet[7] = 0x00;
+ packet[8] = 0x00;
+ packet[9] = 0x32;
+ if (sub_protocol == WK2401) { packet[10] = 0x10 | ((fixed_id >> 0) & 0x0e); }
+ else { packet[10] = (fixed_id >> 0) & 0xff; }
+ packet[11] = (fixed_id >> 8) & 0xff;
+ packet[12] = ((fixed_id >> 12) & 0xf0) | wk_pkt_num;
+ packet[13] = init[3];
+ add_pkt_crc(init[4]);
+}
+
+static uint16_t get_channel(uint8_t ch, uint32_t scale, uint32_t center, uint32_t range) {
+ uint32_t value = (uint32_t)Servo_data[ch] * scale / PPM_MAX + center;
+ if (value < center - range) { value = center - range; }
+ if (value > center + range) { value = center + range; }
+ return value;
+}
+
+static void build_data_pkt_2401() {
+ uint8_t i;
+ uint16_t msb = 0;
+ uint8_t offset = 0;
+ for (i = 0; i < 4; i++) {
+ if (i == 2) { offset = 1; }
+ uint16_t value = get_channel(i, 0x800, 0, 0xA00); //12 bits, allow value to go to 125%
+ uint16_t base = abs(value) >> 2; //10 bits is the base value
+ uint16_t trim = abs(value) & 0x03; //lowest 2 bits represent trim
+ if (base >= 0x200) { //if value is > 100%, remainder goes to trim
+ trim = 4 *(base - 0x200);
+ base = 0x1ff;
+ }
+ base = (value >= 0) ? 0x200 + base : 0x200 - base;
+ trim = (value >= 0) ? 0x200 + trim : 0x200 - trim;
+
+ packet[2*i+offset] = base & 0xff;
+ packet[2*i+offset+1] = trim & 0xff;
+ msb = (msb << 4) | ((base >> 6) & 0x0c) | ((trim >> 8) & 0x03);
+ }
+ packet[4] = msb >> 8; //Ele/Ail MSB
+ packet[9] = msb & 0xff; //Thr/Rud MSB
+ packet[10] = 0xe0 | ((fixed_id >> 0) & 0x0e);
+ packet[11] = (fixed_id >> 8) & 0xff;
+ packet[12] = ((fixed_id >> 12) & 0xf0) | wk_pkt_num;
+ packet[13] = 0xf0; //FIXME - What is this?
+ add_pkt_crc(0x00);
+}
+
+#define PCT(pct, max) (((max) * (pct) + 1L) / 1000)
+#define MAXTHR 426 //Measured to provide equal value at +/-0
+static void channels_6plus1_2601(int frame, int *_v1, int *_v2) {
+ uint16_t thr = get_channel(2, 1000, 0, 1000);
+ int v1;
+ int thr_rev = 0, pitch_rev = 0;
+ if(thr > 0) {
+ if(thr >= 780) { //78%
+ v1 = 0; //thr = 60% * (x - 78%) / 22% + 40%
+ thr = PCT(1000-MAXTHR,512) * (thr-PCT(780,1000)) / PCT(220,1000) + PCT(MAXTHR,512);
+ } else {
+ v1 = 1023 - 1023 * thr / 780;
+ thr = PCT(MAXTHR, 512); //40%
+ }
+ }
+ else {
+ thr = -thr;
+ thr_rev = 1;
+ if(thr >= 780) { //78%
+ v1 = 1023; //thr = 60% * (x - 78%) / 22% + 40%
+ thr = PCT(1000-MAXTHR,512) * (thr-PCT(780,1000)) / PCT(220,1000) + PCT(MAXTHR,512);
+ if (thr >= 512) { thr = 511; }
+ }
+ else {
+ v1 = 1023 * thr / 780;
+ thr = PCT(MAXTHR, 512); //40%
+ }
+ }
+ if (thr >= 512) { thr = 511; }
+ packet[2] = thr & 0xff;
+ packet[4] = (packet[4] & 0xF3) | ((thr >> 6) & 0x04);
+
+ uint16_t pitch= get_channel(5, 0x400, 0, 0x400);
+ if (pitch < 0) {
+ pitch_rev = 1;
+ pitch = -pitch;
+ }
+ if (frame == 1) {
+ //Pitch curve and range
+ if (thr > PCT(MAXTHR, 512)) { *_v2 = pitch - pitch * 16 * (thr - PCT(MAXTHR, 512)) / PCT(1000 - MAXTHR, 512) / 100; }
+ else { *_v2 = pitch; }
+ *_v1 = 0;
+ }
+ else if (frame == 2) {
+ //Throttle curve & Expo
+ *_v1 = v1;
+ *_v2 = 512;
+ }
+ packet[7] = (thr_rev << 5) | (pitch_rev << 2); //reverse bits
+ packet[8] = 0;
+}
+
+static void channels_5plus1_2601(int frame, int *v1, int *v2) {
+ (void)v1;
+ //Zero out pitch, provide ail, ele, thr, rud, gyr + gear
+ if (frame == 1) { *v2 = 0; } //Pitch curve and range
+ packet[7] = 0;
+ packet[8] = 0;
+}
+static void channels_heli_2601(int frame, int *v1, int *v2) {
+ (void)frame;
+ //pitch is controlled by rx
+ //we can only control fmode, pit-reverse and pit/thr rate
+ int pit_rev = 0;
+ if ((option/10)%10) { pit_rev = 1; }
+ uint16_t pit_rate = get_channel(5, 0x400, 0, 0x400);
+ int fmode = 1;
+ if (pit_rate < 0) { pit_rate = -pit_rate; fmode = 0; }
+ if (frame == 1) {
+ //Pitch curve and range
+ *v1 = pit_rate;
+ *v2 = ((option/100) ? -100 : 100) * 0x400 / 100 + 0x400;
+ }
+ packet[7] = (pit_rev << 2); //reverse bits
+ packet[8] = fmode ? 0x02 : 0x00;
+}
+
+static void build_data_pkt_2601() {
+ uint8_t i;
+ uint8_t msb = 0;
+ uint8_t frame = (wk_pkt_num % 3);
+ for (i = 0; i < 4; i++) {
+ uint16_t value = get_channel(i, 0x190, 0, 0x1FF);
+ uint16_t mag = value < 0 ? -value : value;
+ packet[i] = mag & 0xff;
+ msb = (msb << 2) | ((mag >> 8) & 0x01) | (value < 0 ? 0x02 : 0x00);
+ }
+ packet[4] = msb;
+ int v1 = 0x200, v2 = 0x200;
+ if (frame == 0) {
+ //Gyro & Rudder mix
+ v1 = get_channel(6, 0x200, 0x200, 0x200);
+ v2 = 0;
+ }
+ if (option%10 == 1) { channels_heli_2601(frame, &v1, &v2); }
+ else if (option%10 == 2) { channels_6plus1_2601(frame, &v1, &v2); }
+ else { channels_5plus1_2601(frame, &v1, &v2); }
+ if (v1 > 1023) { v1 = 1023; }
+ if (v2 > 1023) { v2 = 1023; }
+ packet[5] = v2 & 0xff;
+ packet[6] = v1 & 0xff;
+ //packet[7] handled by channel code
+ packet[8] |= (get_channel(4, 0x190, 0, 0x1FF) > 0 ? 1 : 0);
+ packet[9] = ((v1 >> 4) & 0x30) | ((v2 >> 2) & 0xc0) | 0x04 | frame;
+ packet[10] = (fixed_id >> 0) & 0xff;
+ packet[11] = (fixed_id >> 8) & 0xff;
+ packet[12] = ((fixed_id >> 12) & 0xf0) | wk_pkt_num;
+ packet[13] = 0xff;
+
+ add_pkt_crc(0x3A);
+}
+
+static void build_data_pkt_2801() {
+ uint8_t i;
+ uint16_t msb = 0;
+ uint8_t offset = 0;
+ uint8_t sign = 0;
+ for (i = 0; i < 8; i++) {
+ if (i == 4) { offset = 1; }
+ uint16_t value = get_channel(i, 0x190, 0, 0x3FF);
+ uint16_t mag = value < 0 ? -value : value;
+ packet[i+offset] = mag & 0xff;
+ msb = (msb << 2) | ((mag >> 8) & 0x03);
+ if (value < 0) { sign |= 1 << i; }
+ }
+ packet[4] = msb >> 8;
+ packet[9] = msb & 0xff;
+ packet[10] = (fixed_id >> 0) & 0xff;
+ packet[11] = (fixed_id >> 8) & 0xff;
+ packet[12] = ((fixed_id >> 12) & 0xf0) | wk_pkt_num;
+ packet[13] = sign;
+ add_pkt_crc(0x25);
+}
+
+static void build_beacon_pkt_2801() {
+ last_beacon ^= 1;
+ uint8_t i;
+ uint8_t en = 0;
+ uint8_t bind_state;
+ if (WK_BIND_COUNTer) { bind_state = 0xe4; }
+ else { bind_state = 0x1b; }
+ for (i = 0; i < 4; i++) {
+/* if (Model.limits[fail_map[i + last_beacon * 4]].flags & CH_FAILSAFE_EN) {
+ uint32_t value = Model.limits[fail_map[i + last_beacon * 4]].failsafe + 128;
+ if (value > 255) { value = 255; }
+ if (value < 0) { value = 0; }
+ packet[i+1] = value;
+ en |= 1 << i;
+ } else
+*/ { packet[i+1] = 0; }
+ }
+ packet[0] = en;
+ packet[5] = packet[4];
+ packet[4] = last_beacon << 6;
+ packet[6] = rx_tx_addr[0];
+ packet[7] = rx_tx_addr[1];
+ packet[8] = rx_tx_addr[2];
+ packet[9] = bind_state;
+ packet[10] = (fixed_id >> 0) & 0xff;
+ packet[11] = (fixed_id >> 8) & 0xff;
+ packet[12] = ((fixed_id >> 12) & 0xf0) | wk_pkt_num;
+ packet[13] = 0x00; //Does this matter? in the docs it is the same as the data packet
+ add_pkt_crc(0x1C);
+}
+
+static void wk2x01_cyrf_init() {
+ /* Initialise CYRF chip */
+ CYRF_WriteRegister(CYRF_03_TX_CFG, 0x28 | CYRF_HIGH_POWER);
+ CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4A);
+ CYRF_WriteRegister(CYRF_0B_PWR_CTRL, 0x00);
+ CYRF_WriteRegister(CYRF_0C_XTAL_CTRL, 0xC0);
+ CYRF_WriteRegister(CYRF_0D_IO_CFG, 0x04);
+ CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x2C);
+ CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0xEE);
+ CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, 0x55);
+ CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, 0x05);
+ CYRF_WriteRegister(CYRF_1D_MODE_OVERRIDE, 0x18);
+ CYRF_WriteRegister(CYRF_32_AUTO_CAL_TIME, 0x3C);
+ CYRF_WriteRegister(CYRF_35_AUTOCAL_OFFSET, 0x14);
+ CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x90);
+ CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x00);
+ CYRF_WriteRegister(CYRF_01_TX_LENGTH, 0x10);
+ CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x2C);
+ CYRF_WriteRegister(CYRF_28_CLK_EN, 0x02);
+ CYRF_WriteRegister(CYRF_27_CLK_OVERRIDE, 0x02);
+ CYRF_ConfigSOPCode(sopcode);
+ CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x28);
+ CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x10);
+ CYRF_WriteRegister(CYRF_0E_GPIO_CTRL, 0x20);
+ CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x2C);
+}
+
+void WK_BuildPacket_2801() {
+ switch(phase) {
+ case WK_BIND:
+ build_bind_pkt(init_2801);
+// if ((--WK_BIND_COUNTer == 0) || PROTOCOL_SticksMoved(0)) {
+ if ((--WK_BIND_COUNTer == 0)) {
+ WK_BIND_COUNTer = 0;
+ BIND_DONE;
+ phase = WK_BOUND_1;
+ }
+ break;
+ case WK_BOUND_1:
+ case WK_BOUND_2:
+ case WK_BOUND_3:
+ case WK_BOUND_4:
+ case WK_BOUND_5:
+ case WK_BOUND_6:
+ case WK_BOUND_7:
+ build_data_pkt_2801();
+ phase++;
+ break;
+ case WK_BOUND_8:
+ build_beacon_pkt_2801();
+ phase = WK_BOUND_1;
+ if (WK_BIND_COUNTer) {
+ WK_BIND_COUNTer--;
+ if (WK_BIND_COUNTer == 0) { BIND_DONE; }
+ }
+ break;
+ }
+ wk_pkt_num = (wk_pkt_num + 1) % 12;
+}
+
+void WK_BuildPacket_2601() {
+ if (WK_BIND_COUNTer) {
+ WK_BIND_COUNTer--;
+ build_bind_pkt(init_2601);
+ if ((WK_BIND_COUNTer == 0)) {
+ WK_BIND_COUNTer = 0;
+ BIND_DONE;
+ }
+ }
+ else { build_data_pkt_2601(); }
+ wk_pkt_num = (wk_pkt_num + 1) % 12;
+}
+
+void WK_BuildPacket_2401() {
+ if (WK_BIND_COUNTer) {
+ WK_BIND_COUNTer--;
+ build_bind_pkt(init_2401);
+ if ((WK_BIND_COUNTer == 0)) {
+ WK_BIND_COUNTer = 0;
+ BIND_DONE;
+ }
+ }
+ else { build_data_pkt_2401(); }
+ wk_pkt_num = (wk_pkt_num + 1) % 12;
+}
+
+static uint16_t wk_cb() {
+ if (packet_sent == 0) {
+ packet_sent = 1;
+ if(sub_protocol == WK2801) { WK_BuildPacket_2801(); }
+ else if(sub_protocol == WK2601) { WK_BuildPacket_2601(); }
+ else if(sub_protocol == WK2401) { WK_BuildPacket_2401(); }
+ CYRF_WriteDataPacket(packet);
+ return 1600;
+ }
+ packet_sent = 0;
+ int i = 0;
+ while (! (CYRF_ReadRegister(0x04) & 0x02)) { if(++i > NUM_WAIT_LOOPS) { break; } }
+ if((wk_pkt_num & 0x03) == 0) {
+ radio_ch_ptr = radio_ch_ptr == &rx_tx_addr[2] ? rx_tx_addr : radio_ch_ptr + 1;
+ CYRF_ConfigRFChannel(*radio_ch_ptr);
+ //Keep transmit power updated
+ CYRF_WriteRegister(CYRF_03_TX_CFG, 0x28 | CYRF_HIGH_POWER);
+ }
+ return 1200;
+}
+
+static void wk_bind() {
+ if((sub_protocol != WK2801)) { return; }
+ fixed_id = ((MProtocol_id_master << 2) & 0x0ffc00) | ((MProtocol_id_master >> 10) & 0x000300) | ((MProtocol_id_master) & 0x0000ff);
+ WK_BIND_COUNTer = WK_BIND_COUNT / 8 + 1;
+ BIND_IN_PROGRESS;
+}
+
+static uint16_t wk_setup() {
+ CYRF_Reset();
+ wk2x01_cyrf_init();
+ CYRF_SetTxRxMode(TX_EN);
+ CYRF_FindBestChannels(rx_tx_addr, 3, 4, 4, 80);
+
+ radio_ch_ptr = rx_tx_addr;
+ CYRF_ConfigRFChannel(*radio_ch_ptr);
+
+ wk_pkt_num = 0;
+ packet_sent = 0;
+ last_beacon = 0;
+ fixed_id = ((MProtocol_id_master << 2) & 0x0ffc00) | ((MProtocol_id_master >> 10) & 0x000300) | ((MProtocol_id_master) & 0x0000ff);
+ if (sub_protocol == WK2401) { fixed_id |= 0x01; } //Fixed ID must be odd for 2401
+ if(sub_protocol != WK2801) {
+ WK_BIND_COUNTer = WK_BIND_COUNT;
+ phase = WK_BIND;
+ BIND_IN_PROGRESS;
+ }
+ else {
+ phase = WK_BOUND_1;
+ WK_BIND_COUNTer = 0;
+ }
+ CYRF_ConfigRFChannel(*radio_ch_ptr);
+ return 2800;
+}
+/*
+const void *WK2x01_Cmds(enum ProtoCmds cmd) {
+ switch(cmd) {
+ case PROTOCMD_INIT: initialize(); return 0;
+ case PROTOCMD_DEINIT: return 0;
+ case PROTOCMD_CHECK_AUTOBIND:
+ return (Model.protocol == WK2801 && Model.fixed_id) ? 0 : (void *)1L;
+ case PROTOCMD_BIND: wk_bind(); return 0;
+ case PROTOCMD_DEFAULT_NUMCHAN: return (Model.protocol == WK2801)
+ ? (void *)8L
+ : (Model.protocol == WK2601)
+ ? (void *)6L
+ : (void *)4L;
+ case PROTOCMD_NUMCHAN: return (Model.protocol == WK2801)
+ ? (void *)8L
+ : (Model.protocol == WK2601)
+ ? (void *)7L
+ : (void *)4L;
+ case PROTOCMD_GETOPTIONS:
+ if(Model.protocol == WK2601)
+ return wk2601_opts;
+ break;
+ case PROTOCMD_TELEMETRYSTATE: return (void *)(long)PROTO_TELEM_UNSUPPORTED;
+ default: break;
+ }
+ return 0;
+}
+*/
+#endif
diff --git a/Multiprotocol/DSM2_cyrf6936.ino b/Multiprotocol/DSM2_cyrf6936.ino
new file mode 100644
index 0000000..19a969e
--- /dev/null
+++ b/Multiprotocol/DSM2_cyrf6936.ino
@@ -0,0 +1,538 @@
+/*
+ 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(DSM2_CYRF6936_INO)
+
+#include "iface_cyrf6936.h"
+
+#define RANDOM_CHANNELS 0 // disabled
+//#define RANDOM_CHANNELS 1 // enabled
+#define BIND_CHANNEL 0x0d //13 This can be any odd channel
+#define NUM_WAIT_LOOPS (100 / 5) //each loop is ~5us. Do not wait more than 100us
+
+//During binding we will send BIND_COUNT/2 packets
+//One packet each 10msec
+#define BIND_COUNT1 600
+
+enum {
+ DSM2_BIND = 0,
+ DSM2_CHANSEL = BIND_COUNT1 + 0,
+ DSM2_CH1_WRITE_A = BIND_COUNT1 + 1,
+ DSM2_CH1_CHECK_A = BIND_COUNT1 + 2,
+ DSM2_CH2_WRITE_A = BIND_COUNT1 + 3,
+ DSM2_CH2_CHECK_A = BIND_COUNT1 + 4,
+ DSM2_CH2_READ_A = BIND_COUNT1 + 5,
+ DSM2_CH1_WRITE_B = BIND_COUNT1 + 6,
+ DSM2_CH1_CHECK_B = BIND_COUNT1 + 7,
+ DSM2_CH2_WRITE_B = BIND_COUNT1 + 8,
+ DSM2_CH2_CHECK_B = BIND_COUNT1 + 9,
+ DSM2_CH2_READ_B = BIND_COUNT1 + 10,
+};
+
+const uint8_t PROGMEM pncodes[5][9][8] = {
+ /* Note these are in order transmitted (LSB 1st) */
+ { /* Row 0 */
+ /* Col 0 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8},
+ /* Col 1 */ {0x88, 0x17, 0x13, 0x3B, 0x2D, 0xBF, 0x06, 0xD6},
+ /* Col 2 */ {0xF1, 0x94, 0x30, 0x21, 0xA1, 0x1C, 0x88, 0xA9},
+ /* Col 3 */ {0xD0, 0xD2, 0x8E, 0xBC, 0x82, 0x2F, 0xE3, 0xB4},
+ /* Col 4 */ {0x8C, 0xFA, 0x47, 0x9B, 0x83, 0xA5, 0x66, 0xD0},
+ /* Col 5 */ {0x07, 0xBD, 0x9F, 0x26, 0xC8, 0x31, 0x0F, 0xB8},
+ /* Col 6 */ {0xEF, 0x03, 0x95, 0x89, 0xB4, 0x71, 0x61, 0x9D},
+ /* Col 7 */ {0x40, 0xBA, 0x97, 0xD5, 0x86, 0x4F, 0xCC, 0xD1},
+ /* Col 8 */ {0xD7, 0xA1, 0x54, 0xB1, 0x5E, 0x89, 0xAE, 0x86}
+ },
+ { /* Row 1 */
+ /* Col 0 */ {0x83, 0xF7, 0xA8, 0x2D, 0x7A, 0x44, 0x64, 0xD3},
+ /* Col 1 */ {0x3F, 0x2C, 0x4E, 0xAA, 0x71, 0x48, 0x7A, 0xC9},
+ /* Col 2 */ {0x17, 0xFF, 0x9E, 0x21, 0x36, 0x90, 0xC7, 0x82},
+ /* Col 3 */ {0xBC, 0x5D, 0x9A, 0x5B, 0xEE, 0x7F, 0x42, 0xEB},
+ /* Col 4 */ {0x24, 0xF5, 0xDD, 0xF8, 0x7A, 0x77, 0x74, 0xE7},
+ /* Col 5 */ {0x3D, 0x70, 0x7C, 0x94, 0xDC, 0x84, 0xAD, 0x95},
+ /* Col 6 */ {0x1E, 0x6A, 0xF0, 0x37, 0x52, 0x7B, 0x11, 0xD4},
+ /* Col 7 */ {0x62, 0xF5, 0x2B, 0xAA, 0xFC, 0x33, 0xBF, 0xAF},
+ /* Col 8 */ {0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97}
+ },
+ { /* Row 2 */
+ /* Col 0 */ {0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97},
+ /* Col 1 */ {0x8E, 0x4A, 0xD0, 0xA9, 0xA7, 0xFF, 0x20, 0xCA},
+ /* Col 2 */ {0x4C, 0x97, 0x9D, 0xBF, 0xB8, 0x3D, 0xB5, 0xBE},
+ /* Col 3 */ {0x0C, 0x5D, 0x24, 0x30, 0x9F, 0xCA, 0x6D, 0xBD},
+ /* Col 4 */ {0x50, 0x14, 0x33, 0xDE, 0xF1, 0x78, 0x95, 0xAD},
+ /* Col 5 */ {0x0C, 0x3C, 0xFA, 0xF9, 0xF0, 0xF2, 0x10, 0xC9},
+ /* Col 6 */ {0xF4, 0xDA, 0x06, 0xDB, 0xBF, 0x4E, 0x6F, 0xB3},
+ /* Col 7 */ {0x9E, 0x08, 0xD1, 0xAE, 0x59, 0x5E, 0xE8, 0xF0},
+ /* Col 8 */ {0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E}
+ },
+ { /* Row 3 */
+ /* Col 0 */ {0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E},
+ /* Col 1 */ {0x80, 0x69, 0x26, 0x80, 0x08, 0xF8, 0x49, 0xE7},
+ /* Col 2 */ {0x7D, 0x2D, 0x49, 0x54, 0xD0, 0x80, 0x40, 0xC1},
+ /* Col 3 */ {0xB6, 0xF2, 0xE6, 0x1B, 0x80, 0x5A, 0x36, 0xB4},
+ /* Col 4 */ {0x42, 0xAE, 0x9C, 0x1C, 0xDA, 0x67, 0x05, 0xF6},
+ /* Col 5 */ {0x9B, 0x75, 0xF7, 0xE0, 0x14, 0x8D, 0xB5, 0x80},
+ /* Col 6 */ {0xBF, 0x54, 0x98, 0xB9, 0xB7, 0x30, 0x5A, 0x88},
+ /* Col 7 */ {0x35, 0xD1, 0xFC, 0x97, 0x23, 0xD4, 0xC9, 0x88},
+ /* Col 8 */ {0x88, 0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40}
+ },
+ { /* Row 4 */
+ /* Col 0 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93},
+ /* Col 1 */ {0xDC, 0x68, 0x08, 0x99, 0x97, 0xAE, 0xAF, 0x8C},
+ /* Col 2 */ {0xC3, 0x0E, 0x01, 0x16, 0x0E, 0x32, 0x06, 0xBA},
+ /* Col 3 */ {0xE0, 0x83, 0x01, 0xFA, 0xAB, 0x3E, 0x8F, 0xAC},
+ /* Col 4 */ {0x5C, 0xD5, 0x9C, 0xB8, 0x46, 0x9C, 0x7D, 0x84},
+ /* Col 5 */ {0xF1, 0xC6, 0xFE, 0x5C, 0x9D, 0xA5, 0x4F, 0xB7},
+ /* Col 6 */ {0x58, 0xB5, 0xB3, 0xDD, 0x0E, 0x28, 0xF1, 0xB0},
+ /* Col 7 */ {0x5F, 0x30, 0x3B, 0x56, 0x96, 0x45, 0xF4, 0xA1},
+ /* Col 8 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8}
+ },
+};
+
+static void __attribute__((unused)) read_code(uint8_t *buf, uint8_t row, uint8_t col, uint8_t len)
+{
+ for(uint8_t i=0;i> 8;
+ packet[1] = crc & 0xff;
+ packet[2] = 0xff ^ cyrfmfg_id[2];
+ packet[3] = (0xff ^ cyrfmfg_id[3]) + RX_num;
+ packet[4] = packet[0];
+ packet[5] = packet[1];
+ packet[6] = packet[2];
+ packet[7] = packet[3];
+ for(i = 0; i < 8; i++)
+ sum += packet[i];
+ packet[8] = sum >> 8;
+ packet[9] = sum & 0xff;
+ packet[10] = 0x01; //???
+ packet[11] = option>3?option:option+4;
+ if(sub_protocol==DSMX) //DSMX type
+ packet[12] = 0xb2; // Telemetry off: packet[12] = num_channels < 8 && Model.proto_opts[PROTOOPTS_TELEMETRY] == TELEM_OFF ? 0xa2 : 0xb2;
+ else
+ packet[12] = option<8?0x01:0x02;
+ packet[13] = 0x00; //???
+ for(i = 8; i < 14; i++)
+ sum += packet[i];
+ packet[14] = sum >> 8;
+ packet[15] = sum & 0xff;
+}
+
+static uint8_t __attribute__((unused)) PROTOCOL_SticksMoved(uint8_t init)
+{
+#define STICK_MOVEMENT 15*(PPM_MAX-PPM_MIN)/100 // defines when the bind dialog should be interrupted (stick movement STICK_MOVEMENT %)
+ static uint16_t ele_start, ail_start;
+ uint16_t ele = Servo_data[ELEVATOR];//CHAN_ReadInput(MIXER_MapChannel(INP_ELEVATOR));
+ uint16_t ail = Servo_data[AILERON];//CHAN_ReadInput(MIXER_MapChannel(INP_AILERON));
+ if(init) {
+ ele_start = ele;
+ ail_start = ail;
+ return 0;
+ }
+ uint16_t ele_diff = ele_start - ele;//abs(ele_start - ele);
+ uint16_t ail_diff = ail_start - ail;//abs(ail_start - ail);
+ return ((ele_diff + ail_diff) > STICK_MOVEMENT);//
+}
+
+static void __attribute__((unused)) build_data_packet(uint8_t upper)//
+{
+ uint8_t i;
+ uint8_t bits;
+
+ uint8_t ch_map[] = {3, 2, 1, 5, 0, 4, 6, 7, 8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //9 Channels - DM9 TX
+ switch(option>3?option:option+4) // Create channel map based on number of channels
+ {
+ case 12:
+ ch_map[11]=11; // 12 channels
+ case 11:
+ ch_map[10]=10; // 11 channels
+ case 10:
+ ch_map[9]=9; // 10 channels
+ break;
+ case 8:
+ memcpy(ch_map,"\x01\x05\x02\x03\x06\xFF\xFF\x04\x00\x07",10); // 8 channels - DX8 TX
+ break;
+ case 7:
+ memcpy(ch_map,"\x01\x05\x02\x04\x03\x06\x00",7); // 7 channels - DX6i TX
+ break;
+ case 6:
+ memcpy(ch_map,"\x01\x05\x02\x03\x00\x04\xFF",7); // 6 channels - HP6DSM TX
+ break;
+ case 4:
+ case 5:
+ memcpy(ch_map,"\x00\x01\x02\x03\xFF\xFF\xFF",7); // 4 channels - Guess
+ if(option&0x01)
+ ch_map[4]=4; // 5 channels - Guess
+ break;
+ }
+ //
+ if( binding && PROTOCOL_SticksMoved(0) )
+ binding = 0;
+ if (sub_protocol==DSMX)
+ {
+ packet[0] = cyrfmfg_id[2];
+ packet[1] = cyrfmfg_id[3] + RX_num;
+ bits=11;
+ }
+ else
+ {
+ packet[0] = (0xff ^ cyrfmfg_id[2]);
+ packet[1] = (0xff ^ cyrfmfg_id[3]) + RX_num;
+ bits=10;
+ }
+ //
+ uint16_t max = 1 << bits;//max=2048 for DSMX & 1024 for DSM2 less than 8 ch and 2048 otherwise
+ //uint16_t pct_100 = (uint32_t)max * 100 / 150;//682 1024*100/150
+ //
+ for (i = 0; i < 7; i++)
+ {
+ uint8_t idx = ch_map[upper * 7 + i];//1,5,2,3,0,4
+ uint16_t value;
+ if (idx == 0xff)
+ value = 0xffff;
+ else
+ {
+ if (binding)
+ { // Failsafe position during binding
+ value=max/2; //all channels to middle
+ if(idx==0)
+ value=1; //except throttle
+ }
+ else
+ {
+ switch(idx)
+ {
+ case 0:
+ value=Servo_data[THROTTLE];//85.75-938.25=125%//171-853=100%
+ break;
+ case 1:
+ value=Servo_data[AILERON];
+ break;
+ case 2:
+ value=Servo_data[ELEVATOR];
+ break;
+ case 3:
+ value=Servo_data[RUDDER];
+ break;
+ case 4:
+ value=Servo_data[AUX1];
+ break;
+ case 5:
+ value=Servo_data[AUX2];
+ break;
+ case 6:
+ value=Servo_data[AUX3];
+ break;
+ case 7:
+ value=Servo_data[AUX4];
+ break;
+ }
+ value=map(value,PPM_MIN,PPM_MAX,0,max-1);
+ }
+ value |= (upper && i == 0 ? 0x8000 : 0) | (idx << bits);
+ }
+ packet[i*2+2] = (value >> 8) & 0xff;
+ packet[i*2+3] = (value >> 0) & 0xff;
+ }
+}
+
+static uint8_t __attribute__((unused)) get_pn_row(uint8_t channel)
+{
+ return (sub_protocol == DSMX ? (channel - 2) % 5 : channel % 5);
+}
+
+const uint8_t init_vals[][2] = {
+ {CYRF_02_TX_CTRL, 0x00},
+ {CYRF_05_RX_CTRL, 0x00},
+ {CYRF_28_CLK_EN, 0x02},
+ {CYRF_32_AUTO_CAL_TIME, 0x3c},
+ {CYRF_35_AUTOCAL_OFFSET, 0x14},
+ {CYRF_06_RX_CFG, 0x4A},
+ {CYRF_1B_TX_OFFSET_LSB, 0x55},
+ {CYRF_1C_TX_OFFSET_MSB, 0x05},
+ {CYRF_0F_XACT_CFG, 0x24}, // Force Idle
+ {CYRF_03_TX_CFG, 0x38 | CYRF_BIND_POWER}, //Set 64chip, SDR mode
+ {CYRF_12_DATA64_THOLD, 0x0a},
+ {CYRF_0F_XACT_CFG, 0x04}, // Idle
+ {CYRF_39_ANALOG_CTRL, 0x01},
+ {CYRF_0F_XACT_CFG, 0x24}, //Force IDLE
+ {CYRF_29_RX_ABORT, 0x00}, //Clear RX abort
+ {CYRF_12_DATA64_THOLD, 0x0a}, //set pn correlation threshold
+ {CYRF_10_FRAMING_CFG, 0x4a}, //set sop len and threshold
+ {CYRF_29_RX_ABORT, 0x0f}, //Clear RX abort?
+ {CYRF_03_TX_CFG, 0x38 | CYRF_BIND_POWER}, //Set 64chip, SDR mode
+ {CYRF_10_FRAMING_CFG, 0x4a}, //set sop len and threshold
+ {CYRF_1F_TX_OVERRIDE, 0x04}, //disable tx CRC
+ {CYRF_1E_RX_OVERRIDE, 0x14}, //disable rx crc
+ {CYRF_14_EOP_CTRL, 0x02}, //set EOP sync == 2
+ {CYRF_01_TX_LENGTH, 0x10}, //16byte packet
+};
+
+static void __attribute__((unused)) cyrf_config()
+{
+ for(uint8_t i = 0; i < sizeof(init_vals) / 2; i++)
+ CYRF_WriteRegister(init_vals[i][0], init_vals[i][1]);
+ CYRF_WritePreamble(0x333304);
+ CYRF_ConfigRFChannel(0x61);
+}
+
+static void __attribute__((unused)) initialize_bind_state()
+{
+ uint8_t code[32];
+
+ CYRF_ConfigRFChannel(BIND_CHANNEL); //This seems to be random?
+ uint8_t pn_row = get_pn_row(BIND_CHANNEL);
+ //printf("Ch: %d Row: %d SOP: %d Data: %d\n", BIND_CHANNEL, pn_row, sop_col, data_col);
+ CYRF_ConfigCRCSeed(crc);
+
+ read_code(code,pn_row,sop_col,8);
+ CYRF_ConfigSOPCode(code);
+ read_code(code,pn_row,data_col,16);
+ read_code(code+16,0,8,8);
+ memcpy(code + 24, "\xc6\x94\x22\xfe\x48\xe6\x57\x4e", 8);
+ CYRF_ConfigDataCode(code, 32);
+
+ build_bind_packet();
+}
+
+const uint8_t data_vals[][2] = {
+ {CYRF_05_RX_CTRL, 0x83}, //Initialize for reading RSSI
+ {CYRF_29_RX_ABORT, 0x20},
+ {CYRF_0F_XACT_CFG, 0x24},
+ {CYRF_29_RX_ABORT, 0x00},
+ {CYRF_03_TX_CFG, 0x08 | CYRF_HIGH_POWER},
+ {CYRF_10_FRAMING_CFG, 0xea},
+ {CYRF_1F_TX_OVERRIDE, 0x00},
+ {CYRF_1E_RX_OVERRIDE, 0x00},
+ {CYRF_03_TX_CFG, 0x28 | CYRF_HIGH_POWER},
+ {CYRF_12_DATA64_THOLD, 0x3f},
+ {CYRF_10_FRAMING_CFG, 0xff},
+ {CYRF_0F_XACT_CFG, 0x24}, //Switch from reading RSSI to Writing
+ {CYRF_29_RX_ABORT, 0x00},
+ {CYRF_12_DATA64_THOLD, 0x0a},
+ {CYRF_10_FRAMING_CFG, 0xea},
+};
+
+static void __attribute__((unused)) cyrf_configdata()
+{
+ for(uint8_t i = 0; i < sizeof(data_vals) / 2; i++)
+ CYRF_WriteRegister(data_vals[i][0], data_vals[i][1]);
+}
+
+static void __attribute__((unused)) set_sop_data_crc()
+{
+ uint8_t code[16];
+ uint8_t pn_row = get_pn_row(hopping_frequency[chidx]);
+ //printf("Ch: %d Row: %d SOP: %d Data: %d\n", ch[chidx], pn_row, sop_col, data_col);
+ CYRF_ConfigRFChannel(hopping_frequency[chidx]);
+ CYRF_ConfigCRCSeed(crcidx ? ~crc : crc);
+
+ read_code(code,pn_row,sop_col,8);
+ CYRF_ConfigSOPCode(code);
+ read_code(code,pn_row,data_col,16);
+ CYRF_ConfigDataCode(code, 16);
+
+ if(sub_protocol == DSMX)
+ chidx = (chidx + 1) % 23;
+ else
+ chidx = (chidx + 1) % 2;
+ crcidx = !crcidx;
+}
+
+static void __attribute__((unused)) calc_dsmx_channel()
+{
+ uint8_t idx = 0;
+ uint32_t id = ~(((uint32_t)cyrfmfg_id[0] << 24) | ((uint32_t)cyrfmfg_id[1] << 16) | ((uint32_t)cyrfmfg_id[2] << 8) | (cyrfmfg_id[3] << 0));
+ uint32_t id_tmp = id;
+ while(idx < 23)
+ {
+ uint8_t i;
+ uint8_t count_3_27 = 0, count_28_51 = 0, count_52_76 = 0;
+ id_tmp = id_tmp * 0x0019660D + 0x3C6EF35F; // Randomization
+ uint8_t next_ch = ((id_tmp >> 8) % 0x49) + 3; // Use least-significant byte and must be larger than 3
+ if (((next_ch ^ id) & 0x01 )== 0)
+ continue;
+ for (i = 0; i < idx; i++)
+ {
+ if(hopping_frequency[i] == next_ch)
+ break;
+ if(hopping_frequency[i] <= 27)
+ count_3_27++;
+ else
+ if (hopping_frequency[i] <= 51)
+ count_28_51++;
+ else
+ count_52_76++;
+ }
+ if (i != idx)
+ continue;
+ if ((next_ch < 28 && count_3_27 < 8)
+ ||(next_ch >= 28 && next_ch < 52 && count_28_51 < 7)
+ ||(next_ch >= 52 && count_52_76 < 8))
+ hopping_frequency[idx++] = next_ch;
+ }
+}
+
+uint16_t ReadDsm2()
+{
+#define CH1_CH2_DELAY 4010 // Time between write of channel 1 and channel 2
+#define WRITE_DELAY 1650 // 1550 original, Time after write to verify write complete
+#define READ_DELAY 400 // Time before write to check read state, and switch channels
+ uint8_t i = 0;
+
+ switch(cyrf_state)
+ {
+ default:
+ //Binding
+ cyrf_state++;
+ if(cyrf_state & 1)
+ {
+ //Send packet on even states
+ //Note state has already incremented,
+ // so this is actually 'even' state
+ CYRF_WriteDataPacket(packet);
+ return 8500;
+ }
+ else
+ {
+ //Check status on odd states
+ CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS);
+ return 1500;
+ }
+ case DSM2_CHANSEL:
+ BIND_DONE;
+ //Select channels and configure for writing data
+ //CYRF_FindBestChannels(ch, 2, 10, 1, 79);
+ cyrf_configdata();
+ CYRF_SetTxRxMode(TX_EN);
+ chidx = 0;
+ crcidx = 0;
+ cyrf_state = DSM2_CH1_WRITE_A; // in fact cyrf_state++
+ set_sop_data_crc();
+ return 10000;
+ case DSM2_CH1_WRITE_A:
+ case DSM2_CH1_WRITE_B:
+ build_data_packet(cyrf_state == DSM2_CH1_WRITE_B);//compare state and DSM2_CH1_WRITE_B return 0 or 1
+ case DSM2_CH2_WRITE_A:
+ case DSM2_CH2_WRITE_B:
+ CYRF_WriteDataPacket(packet);
+ cyrf_state++; // change from WRITE to CHECK mode
+ return WRITE_DELAY;
+ case DSM2_CH1_CHECK_A:
+ case DSM2_CH1_CHECK_B:
+ while (! (CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02))
+ if(++i > NUM_WAIT_LOOPS)
+ break;
+ set_sop_data_crc();
+ cyrf_state++; // change from CH1_CHECK to CH2_WRITE
+ return CH1_CH2_DELAY - WRITE_DELAY;
+ case DSM2_CH2_CHECK_A:
+ case DSM2_CH2_CHECK_B:
+ while (! (CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02))
+ if(++i > NUM_WAIT_LOOPS)
+ break;
+ if (cyrf_state == DSM2_CH2_CHECK_A)
+ CYRF_SetPower(0x28); //Keep transmit power in sync
+ // No telemetry...
+ set_sop_data_crc();
+ if (cyrf_state == DSM2_CH2_CHECK_A)
+ {
+ if(option < 8)
+ {
+ cyrf_state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper)
+ if(option>3)
+ return 11000 - CH1_CH2_DELAY - WRITE_DELAY ; // force 11ms if option>3 ie 4,5,6,7 channels @11ms
+ else
+ return 22000 - CH1_CH2_DELAY - WRITE_DELAY ; // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms
+ }
+ else
+ cyrf_state = DSM2_CH1_WRITE_B; // change from CH2_CHECK_A to CH1_WRITE_A (to transmit upper)
+ }
+ else
+ cyrf_state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_B to CH1_WRITE_A (upper already transmitted so transmit lower)
+ return 11000 - CH1_CH2_DELAY - WRITE_DELAY;
+ }
+ return 0;
+}
+
+uint16_t initDsm2()
+{
+ CYRF_Reset();
+ CYRF_GetMfgData(cyrfmfg_id);//
+
+ cyrf_config();
+
+ if (sub_protocol ==DSMX)
+ calc_dsmx_channel();
+ else
+ {
+#if RANDOM_CHANNELS == 1
+ uint8_t tmpch[10];
+ CYRF_FindBestChannels(tmpch, 10, 5, 3, 75);
+ //
+ randomSeed((uint32_t)analogRead(A6)<<10|analogRead(A7));//seed
+ uint8_t idx = random(0xfefefefe) % 10;
+ hopping_frequency[0] = tmpch[idx];
+ while(1)
+ {
+ idx = random(0xfefefefe) % 10;
+ if (tmpch[idx] != hopping_frequency[0])
+ break;
+ }
+ hopping_frequency[1] = tmpch[idx];
+#else
+ hopping_frequency[0] = (cyrfmfg_id[0] + cyrfmfg_id[2] + cyrfmfg_id[4]) % 39 + 1;
+ hopping_frequency[1] = (cyrfmfg_id[1] + cyrfmfg_id[3] + cyrfmfg_id[5]) % 40 + 40;
+#endif
+ }
+
+ ///}
+ crc = ~((cyrfmfg_id[0] << 8) + cyrfmfg_id[1]); //The crc for channel 'a' is NOT(mfgid[1] << 8 + mfgid[0])
+ crcidx = 0;//The crc for channel 'b' is (mfgid[1] << 8 + mfgid[0])
+ //
+ sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;//Ok
+ data_col = 7 - sop_col;//ok
+
+ CYRF_SetTxRxMode(TX_EN);
+ //
+ if(IS_AUTOBIND_FLAG_on)
+ {
+ cyrf_state = DSM2_BIND;
+ PROTOCOL_SticksMoved(1); //Initialize Stick position
+ initialize_bind_state();
+ binding = 1;
+ }
+ else
+ {
+ cyrf_state = DSM2_CHANSEL;//
+ binding = 0;
+ }
+ return 10000;
+}
+
+#endif
diff --git a/Multiprotocol/Devo_cyrf6936.ino b/Multiprotocol/Devo_cyrf6936.ino
index a677de9..91d752e 100644
--- a/Multiprotocol/Devo_cyrf6936.ino
+++ b/Multiprotocol/Devo_cyrf6936.ino
@@ -43,7 +43,31 @@ enum {
DEVO_BOUND_10,
};
+<<<<<<< HEAD
+const uint8_t sopcodes[][8] = {
+ /* Note these are in order transmitted (LSB 1st) */
+ /* 0 */ {0x3C,0x37,0xCC,0x91,0xE2,0xF8,0xCC,0x91}, //0x91CCF8E291CC373C
+ /* 1 */ {0x9B,0xC5,0xA1,0x0F,0xAD,0x39,0xA2,0x0F}, //0x0FA239AD0FA1C59B
+ /* 2 */ {0xEF,0x64,0xB0,0x2A,0xD2,0x8F,0xB1,0x2A}, //0x2AB18FD22AB064EF
+ /* 3 */ {0x66,0xCD,0x7C,0x50,0xDD,0x26,0x7C,0x50}, //0x507C26DD507CCD66
+ /* 4 */ {0x5C,0xE1,0xF6,0x44,0xAD,0x16,0xF6,0x44}, //0x44F616AD44F6E15C
+ /* 5 */ {0x5A,0xCC,0xAE,0x46,0xB6,0x31,0xAE,0x46}, //0x46AE31B646AECC5A
+ /* 6 */ {0xA1,0x78,0xDC,0x3C,0x9E,0x82,0xDC,0x3C}, //0x3CDC829E3CDC78A1
+ /* 7 */ {0xB9,0x8E,0x19,0x74,0x6F,0x65,0x18,0x74}, //0x7418656F74198EB9
+ /* 8 */ {0xDF,0xB1,0xC0,0x49,0x62,0xDF,0xC1,0x49}, //0x49C1DF6249C0B1DF
+ /* 9 */ {0x97,0xE5,0x14,0x72,0x7F,0x1A,0x14,0x72}, //0x72141A7F7214E597
+};
+
+uint8_t txState;
+uint8_t pkt_num;
+uint8_t ch_idx;
+uint8_t use_fixed_id;
+uint8_t failsafe_pkt;
+
+static void __attribute__((unused)) scramble_pkt()
+=======
static void __attribute__((unused)) DEVO_scramble_pkt()
+>>>>>>> refs/remotes/pascallanger/master
{
#ifdef NO_SCRAMBLE
return;
@@ -53,7 +77,11 @@ static void __attribute__((unused)) DEVO_scramble_pkt()
#endif
}
+<<<<<<< HEAD
+static void __attribute__((unused)) add_pkt_suffix()
+=======
static void __attribute__((unused)) DEVO_add_pkt_suffix()
+>>>>>>> refs/remotes/pascallanger/master
{
uint8_t bind_state;
#ifdef ENABLE_PPM
@@ -91,7 +119,11 @@ static void __attribute__((unused)) DEVO_add_pkt_suffix()
packet[15] = (MProtocol_id >> 16) & 0xff;
}
+<<<<<<< HEAD
+static void __attribute__((unused)) build_beacon_pkt(uint8_t upper)
+=======
static void __attribute__((unused)) DEVO_build_beacon_pkt(uint8_t upper)
+>>>>>>> refs/remotes/pascallanger/master
{
packet[0] = (DEVO_NUM_CHANNELS << 4) | 0x07;
uint8_t max = 8;
@@ -106,7 +138,11 @@ static void __attribute__((unused)) DEVO_build_beacon_pkt(uint8_t upper)
DEVO_add_pkt_suffix();
}
+<<<<<<< HEAD
+static void __attribute__((unused)) build_bind_pkt()
+=======
static void __attribute__((unused)) DEVO_build_bind_pkt()
+>>>>>>> refs/remotes/pascallanger/master
{
packet[0] = (DEVO_NUM_CHANNELS << 4) | 0x0a;
packet[1] = bind_counter & 0xff;
@@ -126,7 +162,11 @@ static void __attribute__((unused)) DEVO_build_bind_pkt()
packet[15] ^= cyrfmfg_id[2];
}
+<<<<<<< HEAD
+static void __attribute__((unused)) build_data_pkt()
+=======
static void __attribute__((unused)) DEVO_build_data_pkt()
+>>>>>>> refs/remotes/pascallanger/master
{
static uint8_t ch_idx=0;
@@ -150,7 +190,11 @@ static void __attribute__((unused)) DEVO_build_data_pkt()
DEVO_add_pkt_suffix();
}
+<<<<<<< HEAD
+static void __attribute__((unused)) cyrf_set_bound_sop_code()
+=======
static void __attribute__((unused)) DEVO_cyrf_set_bound_sop_code()
+>>>>>>> refs/remotes/pascallanger/master
{
/* crc == 0 isn't allowed, so use 1 if the math results in 0 */
uint8_t crc = (cyrfmfg_id[0] + (cyrfmfg_id[1] >> 6) + cyrfmfg_id[2]);
@@ -163,6 +207,9 @@ static void __attribute__((unused)) DEVO_cyrf_set_bound_sop_code()
CYRF_SetPower(0x08);
}
+<<<<<<< HEAD
+static void __attribute__((unused)) cyrf_init()
+=======
const uint8_t PROGMEM DEVO_init_vals[][2] = {
{ CYRF_1D_MODE_OVERRIDE, 0x38 },
{ CYRF_03_TX_CFG, 0x08 },
@@ -186,13 +233,18 @@ const uint8_t PROGMEM DEVO_init_vals[][2] = {
};
static void __attribute__((unused)) DEVO_cyrf_init()
+>>>>>>> refs/remotes/pascallanger/master
{
/* Initialise CYRF chip */
for(uint8_t i = 0; i < sizeof(DEVO_init_vals) / 2; i++)
CYRF_WriteRegister(pgm_read_byte( &DEVO_init_vals[i][0]), pgm_read_byte( &DEVO_init_vals[i][1]) );
}
+<<<<<<< HEAD
+static void __attribute__((unused)) set_radio_channels()
+=======
static void __attribute__((unused)) DEVO_set_radio_channels()
+>>>>>>> refs/remotes/pascallanger/master
{
CYRF_FindBestChannels(hopping_frequency, 3, 4, 4, 80);
hopping_frequency[3] = hopping_frequency[0];
@@ -285,6 +337,35 @@ uint16_t devo_callback()
return 1200;
}
+<<<<<<< HEAD
+/*static void __attribute__((unused)) devo_bind()
+{
+ fixed_id = Model_fixed_id;
+ bind_counter = DEVO_BIND_COUNT;
+ use_fixed_id = 1;
+ //PROTOCOL_SetBindState(0x1388 * 2400 / 1000); //msecs 12000ms
+}
+
+
+static void __attribute__((unused)) generate_fixed_id_bind(){
+if(BIND_0){
+//randomSeed((uint32_t)analogRead(A6)<<10|analogRead(A7));//seed
+uint8_t txid[4];
+//Model_fixed_id = random(0xfefefefe) + ((uint32_t)random(0xfefefefe) << 16);
+Model_fixed_id=0x332211;
+txid[0]= (id &0xFF);
+txid[1] = ((id >> 8) & 0xFF);
+txid[2] = ((id >> 16) & 0xFF);
+//txid[3] = ((id >> 24) & 0xFF);
+eeprom_write_block((const void*)txid,(void*)40,3);
+devo_bind();
+}
+}
+*/
+
+
+=======
+>>>>>>> refs/remotes/pascallanger/master
uint16_t DevoInit()
{
DEVO_cyrf_init();
diff --git a/Multiprotocol/FY326_nrf24l01.ino b/Multiprotocol/FY326_nrf24l01.ino
index 41837d8..670103f 100644
--- a/Multiprotocol/FY326_nrf24l01.ino
+++ b/Multiprotocol/FY326_nrf24l01.ino
@@ -15,21 +15,38 @@
// Last sync with hexfet new_protocols/fy326_nrf24l01.c dated 2015-07-29
#if defined(FY326_NRF24L01_INO)
+<<<<<<< HEAD
+=======
+>>>>>>> refs/remotes/pascallanger/master
#include "iface_nrf24l01.h"
#define FY326_INITIAL_WAIT 500
#define FY326_PACKET_PERIOD 1500
#define FY326_PACKET_CHKTIME 300
#define FY326_PACKET_SIZE 15
+<<<<<<< HEAD
+#define FY326_BIND_COUNT 16
+=======
#define FY326_BIND_COUNT 16
+>>>>>>> refs/remotes/pascallanger/master
#define FY326_RF_BIND_CHANNEL 0x17
#define FY326_NUM_RF_CHANNELS 5
enum {
+<<<<<<< HEAD
+ FY326_INIT1 = 0,
+ FY326_BIND1,
+ FY326_BIND2,
+ FY326_DATA,
+ FY319_INIT1,
+ FY319_BIND1,
+ FY319_BIND2,
+=======
FY326_BIND1=0,
FY326_BIND2,
FY326_DATA
+>>>>>>> refs/remotes/pascallanger/master
};
#define rxid channel
@@ -39,7 +56,11 @@ static void __attribute__((unused)) FY326_send_packet(uint8_t bind)
{
packet[0] = rx_tx_addr[3];
if(bind)
+<<<<<<< HEAD
+ packet[1] = 0x55;
+=======
packet[1] = 0x55;
+>>>>>>> refs/remotes/pascallanger/master
else
packet[1] = GET_FLAG(Servo_AUX3, 0x80) // Headless
| GET_FLAG(Servo_AUX2, 0x40) // RTH
@@ -50,6 +71,23 @@ static void __attribute__((unused)) FY326_send_packet(uint8_t bind)
packet[3] = convert_channel_8b_scale(ELEVATOR, 0, 200); // elevator
packet[4] = 200 - convert_channel_8b_scale(RUDDER, 0, 200); // rudder
packet[5] = convert_channel_8b_scale(THROTTLE, 0, 200); // throttle
+<<<<<<< HEAD
+ if(sub_protocol == FY319) {
+ 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] = rx_tx_addr[0];
+ packet[7] = rx_tx_addr[1];
+ packet[8] = rx_tx_addr[2];
+ }
+ packet[9] = CHAN_TO_TRIM(packet[2]); // aileron_trim;
+ packet[10] = CHAN_TO_TRIM(packet[3]); // elevator_trim;
+ packet[11] = CHAN_TO_TRIM(packet[4]); // rudder_trim;
+ packet[12] = 0; // throttle_trim;
+ packet[13] = rxid;
+=======
packet[6] = rx_tx_addr[0];
packet[7] = rx_tx_addr[1];
packet[8] = rx_tx_addr[2];
@@ -58,6 +96,7 @@ static void __attribute__((unused)) FY326_send_packet(uint8_t bind)
packet[11] = CHAN_TO_TRIM(packet[4]); // rudder_trim;
packet[12] = 0; // throttle_trim;
packet[13] = rxid;
+>>>>>>> refs/remotes/pascallanger/master
packet[14] = rx_tx_addr[4];
if (bind)
@@ -66,11 +105,20 @@ static void __attribute__((unused)) FY326_send_packet(uint8_t bind)
{
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]);
hopping_frequency_no %= FY326_NUM_RF_CHANNELS;
+<<<<<<< HEAD
+
+ }
+
+ // clear packet status bits and TX FIFO
+ NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
+ NRF24L01_FlushTx();
+=======
}
// clear packet status bits and TX FIFO
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
+>>>>>>> refs/remotes/pascallanger/master
NRF24L01_WritePayload(packet, FY326_PACKET_SIZE);
@@ -79,9 +127,18 @@ static void __attribute__((unused)) FY326_send_packet(uint8_t bind)
static void __attribute__((unused)) FY326_init()
{
+<<<<<<< HEAD
+ NRF24L01_Initialize();
+ NRF24L01_SetTxRxMode(TX_EN);
+ if(sub_protocol == FY319)
+ NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // Five-byte rx/tx address
+ else
+ NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // Three-byte rx/tx address
+=======
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // Three-byte rx/tx address
+>>>>>>> refs/remotes/pascallanger/master
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x15\x59\x23\xc6\x29", 5);
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t *)"\x15\x59\x23\xc6\x29", 5);
NRF24L01_FlushTx();
@@ -93,13 +150,112 @@ static void __attribute__((unused)) FY326_init()
NRF24L01_WriteReg(NRF24L01_05_RF_CH, FY326_RF_BIND_CHANNEL);
NRF24L01_SetBitrate(NRF24L01_BR_250K);
NRF24L01_SetPower();
+<<<<<<< HEAD
+
+ NRF24L01_Activate(0x73);
+=======
NRF24L01_Activate(0x73);
+>>>>>>> refs/remotes/pascallanger/master
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3f);
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07);
NRF24L01_Activate(0x73);
}
+<<<<<<< HEAD
+uint16_t fy326_callback()
+{
+ uint8_t i;
+ switch (phase) {
+ case FY319_INIT1:
+ NRF24L01_SetTxRxMode(TXRX_OFF);
+ NRF24L01_FlushRx();
+ NRF24L01_SetTxRxMode(RX_EN);
+ NRF24L01_WriteReg(NRF24L01_05_RF_CH, RF_BIND_CHANNEL);
+ phase = FY319_BIND1;
+ BIND_IN_PROGRESS;
+ return FY326_CHKTIME;
+ break;
+
+ case FY319_BIND1:
+ if(NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR)) {
+ NRF24L01_ReadPayload(packet, FY326_SIZE);
+ rxid = packet[13];
+ packet[0] = txid[3];
+ packet[1] = 0x80;
+ packet[14]= txid[4];
+ bind_counter = FY326_BIND_COUNT;
+ NRF24L01_SetTxRxMode(TXRX_OFF);
+ NRF24L01_SetTxRxMode(TX_EN);
+ NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
+ NRF24L01_FlushTx();
+ bind_counter = 255;
+ for(i=2; i<6; i++)
+ packet[i] = rf_chans[0];
+ phase = FY319_BIND2;
+ }
+ return FY326_CHKTIME;
+ break;
+
+ case FY319_BIND2:
+ NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
+ NRF24L01_FlushTx();
+ NRF24L01_WritePayload(packet, FY326_SIZE);
+ if(bind_counter == 250)
+ packet[1] = 0x40;
+ if(--bind_counter == 0) {
+ BIND_DONE;
+ phase = FY326_DATA;
+ }
+ break;
+
+ case FY326_INIT1:
+ bind_counter = FY326_BIND_COUNT;
+ phase = FY326_BIND2;
+ send_packet(1);
+ return FY326_CHKTIME;
+ break;
+
+ case FY326_BIND1:
+ if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR))
+ { // RX fifo data ready
+ NRF24L01_ReadPayload(packet, FY326_PACKET_SIZE);
+ rxid = packet[13];
+ rx_tx_addr[0] = 0xAA;
+ NRF24L01_SetTxRxMode(TXRX_OFF);
+ NRF24L01_SetTxRxMode(TX_EN);
+ BIND_DONE;
+ phase = FY326_DATA;
+ }
+ else
+ if (bind_counter-- == 0)
+ {
+ bind_counter = FY326_BIND_COUNT;
+ NRF24L01_SetTxRxMode(TXRX_OFF);
+ NRF24L01_SetTxRxMode(TX_EN);
+ FY326_send_packet(1);
+ phase = FY326_BIND2;
+ return FY326_PACKET_CHKTIME;
+ }
+ break;
+
+ case FY326_BIND2:
+ if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_TX_DS))
+ { // TX data sent -> switch to RX mode
+ NRF24L01_SetTxRxMode(TXRX_OFF);
+ NRF24L01_FlushRx();
+ NRF24L01_SetTxRxMode(RX_EN);
+ phase = FY326_BIND1;
+ }
+ else
+ return FY326_PACKET_CHKTIME;
+ break;
+
+ case FY326_DATA:
+ FY326_send_packet(0);
+ break;
+ }
+=======
uint16_t FY326_callback()
{
switch (phase)
@@ -141,26 +297,54 @@ uint16_t FY326_callback()
FY326_send_packet(0);
break;
}
+>>>>>>> refs/remotes/pascallanger/master
return FY326_PACKET_PERIOD;
}
static void __attribute__((unused)) FY326_initialize_txid()
{
+<<<<<<< HEAD
+ if(sub_protocol == FY319) {
+ hopping_frequency[0] = (rx_tx_addr[0]&0x0f) & ~0x80;
+ hopping_frequency[1] = (rx_tx_addr[0] >> 4) & ~0x80;
+ hopping_frequency[2] = (rx_tx_addr[1]&0x0f) & ~0x80;
+ hopping_frequency[3] = (rx_tx_addr[1] >> 4) & ~0x80;
+ hopping_frequency[4] = (rx_tx_addr[2] >> 4) & ~0x80;
+ } else {
+ hopping_frequency[0] = (rx_tx_addr[0]&0x0f);
+ hopping_frequency[1] = 0x10 + (rx_tx_addr[0] >> 4);
+ hopping_frequency[2] = 0x20 + (rx_tx_addr[1]&0x0f);
+ hopping_frequency[3] = 0x30 + (rx_tx_addr[1] >> 4);
+ hopping_frequency[4] = 0x40 + (rx_tx_addr[2] >> 4);
+ }
+=======
hopping_frequency[0] = (rx_tx_addr[0]&0x0f);
hopping_frequency[1] = 0x10 + (rx_tx_addr[0] >> 4);
hopping_frequency[2] = 0x20 + (rx_tx_addr[1]&0x0f);
hopping_frequency[3] = 0x30 + (rx_tx_addr[1] >> 4);
hopping_frequency[4] = 0x40 + (rx_tx_addr[2] >> 4);
+>>>>>>> refs/remotes/pascallanger/master
}
uint16_t initFY326(void)
{
BIND_IN_PROGRESS; // autobind protocol
+<<<<<<< HEAD
+ rxid = 0xaa;
+ bind_counter = 0;
+ FY326_initialize_txid();
+ fy326_init();
+ if(sub_protocol == FY319)
+ phase = FY319_INIT1;
+ else
+ phase = FY326_INIT1;
+=======
rxid = 0xAA;
bind_counter = 0;
FY326_initialize_txid();
FY326_init();
phase=FY326_BIND1;
+>>>>>>> refs/remotes/pascallanger/master
return FY326_INITIAL_WAIT;
}
diff --git a/Multiprotocol/FlySky_a7105.ino b/Multiprotocol/FlySky_a7105.ino
index 43ccffd..1165aea 100644
--- a/Multiprotocol/FlySky_a7105.ino
+++ b/Multiprotocol/FlySky_a7105.ino
@@ -21,6 +21,34 @@
//FlySky constants & variables
#define FLYSKY_BIND_COUNT 2500
+<<<<<<< HEAD
+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
+};
+
+enum {
+ // 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 10
FLAG_V9X9_VIDEO = 0x40,
@@ -28,26 +56,27 @@ enum {
// flags going to byte 12
FLAG_V9X9_FLIP = 0x10,
FLAG_V9X9_LED = 0x20,
+>>>>>>> refs/remotes/pascallanger/master
};
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,
};
const uint8_t PROGMEM V912_X17_SEQ[10] = { 0x14, 0x31, 0x40, 0x49, 0x49, // sometime first byte is 0x15 ?
@@ -55,6 +84,79 @@ const uint8_t PROGMEM V912_X17_SEQ[10] = { 0x14, 0x31, 0x40, 0x49, 0x49, //
static void __attribute__((unused)) flysky_apply_extension_flags()
{
+<<<<<<< HEAD
+ 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 uint8_t seq_counter;
switch(sub_protocol)
{
@@ -124,39 +226,78 @@ static void __attribute__((unused)) flysky_apply_extension_flags()
default:
break;
}
+>>>>>>> refs/remotes/pascallanger/master
}
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];
+<<<<<<< HEAD
+ 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)
+ }
+=======
for(i = 0; i < 8; i++)
{
packet[5 + i*2]=Servo_data[CH_AETR[i]]&0xFF; //low byte of servo timing(1000-2000us)
packet[6 + i*2]=(Servo_data[CH_AETR[i]]>>8)&0xFF; //high byte of servo timing(1000-2000us)
}
+>>>>>>> refs/remotes/pascallanger/master
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;
}
+<<<<<<< HEAD
+ 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();
+ }
+ 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;
+
+
+ if(IS_AUTOBIND_FLAG_on)
+ bind_counter = FLYSKY_BIND_COUNT;
+ else
+ bind_counter = 0;
+ return 2400;
+=======
else
{
flysky_build_packet(0);
@@ -211,5 +352,7 @@ uint16_t initFlySky()
else
bind_counter = 0;
return 2400;
+>>>>>>> refs/remotes/pascallanger/master
}
#endif
+
diff --git a/Multiprotocol/FrSkyX_cc2500.ino b/Multiprotocol/FrSkyX_cc2500.ino
index be159b3..5f5f6ba 100644
--- a/Multiprotocol/FrSkyX_cc2500.ino
+++ b/Multiprotocol/FrSkyX_cc2500.ino
@@ -17,9 +17,297 @@
*/
#if defined(FRSKYX_CC2500_INO)
+
+ #include "iface_cc2500.h"
+
+ uint8_t chanskip;
+ uint8_t calData[48][3];
+ uint8_t channr;
+ uint8_t pass_ = 1 ;
+ uint8_t counter_rst;
+ uint8_t ctr;
+ uint8_t FS_flag=0;
+ // uint8_t ptr[4]={0x01,0x12,0x23,0x30};
+ //uint8_t ptr[4]={0x00,0x11,0x22,0x33};
+
+ const PROGMEM uint8_t hop_data[]={
+ 0x02, 0xD4, 0xBB, 0xA2, 0x89,
+ 0x70, 0x57, 0x3E, 0x25, 0x0C,
+ 0xDE, 0xC5, 0xAC, 0x93, 0x7A,
+ 0x61, 0x48, 0x2F, 0x16, 0xE8,
+ 0xCF, 0xB6, 0x9D, 0x84, 0x6B,
+ 0x52, 0x39, 0x20, 0x07, 0xD9,
+ 0xC0, 0xA7, 0x8E, 0x75, 0x5C,
+ 0x43, 0x2A, 0x11, 0xE3, 0xCA,
+ 0xB1, 0x98, 0x7F, 0x66, 0x4D,
+ 0x34, 0x1B, 0x00, 0x1D, 0x03
+ };
-#include "iface_cc2500.h"
+ static uint8_t __attribute__((unused)) hop(uint8_t byte)
+ {
+ return pgm_read_byte_near(&hop_data[byte]);
+ }
+ static void __attribute__((unused)) set_start(uint8_t ch )
+ {
+ cc2500_strobe(CC2500_SIDLE);
+ cc2500_writeReg(CC2500_23_FSCAL3, calData[ch][0]);
+ cc2500_writeReg(CC2500_24_FSCAL2, calData[ch][1]);
+ cc2500_writeReg(CC2500_25_FSCAL1, calData[ch][2]);
+ cc2500_writeReg(CC2500_0A_CHANNR, ch==47?0:pgm_read_word(&hop_data[ch]));
+ }
+
+ static void __attribute__((unused)) frskyX_init()
+ {
+ CC2500_Reset();
+
+ 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_06_PKTLEN)
+ val=0x1E;
+ else
+ if(reg==CC2500_08_PKTCTRL0)
+ val=0x01;
+ else
+ if(reg==CC2500_0B_FSCTRL1)
+ val=0x0A;
+ else
+ if(reg==CC2500_10_MDMCFG4)
+ val=0x7B;
+ else
+ if(reg==CC2500_11_MDMCFG3)
+ val=0x61;
+ else
+ if(reg==CC2500_12_MDMCFG2)
+ val=0x13;
+ else
+ if(reg==CC2500_15_DEVIATN)
+ val=0x51;
+
+ cc2500_writeReg(reg,val);
+ }
+
+ cc2500_writeReg(CC2500_07_PKTCTRL1, 0x04);
+ cc2500_writeReg(CC2500_0C_FSCTRL0, option);
+ cc2500_strobe(CC2500_SIDLE);
+ //
+ for(uint8_t c=0;c < 47;c++){//calibrate hop channels
+ cc2500_strobe(CC2500_SIDLE);
+ cc2500_writeReg(CC2500_0A_CHANNR,pgm_read_word(&hop_data[c]));
+ cc2500_strobe(CC2500_SCAL);
+ delayMicroseconds(900);//
+ calData[c][0] = cc2500_readReg(CC2500_23_FSCAL3);
+ calData[c][1] = cc2500_readReg(CC2500_24_FSCAL2);
+ calData[c][2] = cc2500_readReg(CC2500_25_FSCAL1);
+ }
+ cc2500_strobe(CC2500_SIDLE);
+ cc2500_writeReg(CC2500_0A_CHANNR,0x00);
+ cc2500_strobe(CC2500_SCAL);
+ delayMicroseconds(900);
+ calData[47][0] = cc2500_readReg(CC2500_23_FSCAL3);
+ calData[47][1] = cc2500_readReg(CC2500_24_FSCAL2);
+ calData[47][2] = cc2500_readReg(CC2500_25_FSCAL1);
+ //#######END INIT########
+ }
+
+ static void __attribute__((unused)) initialize_data(uint8_t adr)
+ {
+ cc2500_writeReg(CC2500_0C_FSCTRL0,option); // Frequency offset hack
+ cc2500_writeReg(CC2500_18_MCSM0, 0x8);
+ cc2500_writeReg(CC2500_09_ADDR, adr ? 0x03 : rx_tx_addr[3]);
+ cc2500_writeReg(CC2500_07_PKTCTRL1,0x05);
+ }
+
+ static uint8_t __attribute__((unused)) crc_Byte( uint8_t byte )
+ {
+ crc = (crc<<8) ^ pgm_read_word(&CRCTable[((uint8_t)(crc>>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;
+ packet[1] = 0x03;
+ packet[2] = 0x01;
+ //
+ packet[3] = crc_Byte(rx_tx_addr[3]);
+ packet[4] = crc_Byte(rx_tx_addr[2]);
+ int idx = ((state -FRSKY_BIND) % 10) * 5;
+ packet[5] = crc_Byte(idx);
+ packet[6] = crc_Byte(pgm_read_word(&hop_data[idx++]));
+ packet[7] = crc_Byte(pgm_read_word(&hop_data[idx++]));
+ packet[8] = crc_Byte(pgm_read_word(&hop_data[idx++]));
+ packet[9] = crc_Byte(pgm_read_word(&hop_data[idx++]));
+ packet[10] = crc_Byte(pgm_read_word(&hop_data[idx++]));
+ packet[11] = crc_Byte(0x02);
+ packet[12] = crc_Byte(RX_num);
+ //
+ for(uint8_t i=13;i<28;i++)
+ packet[i]=crc_Byte(0);
+ //
+ packet[28]=highByte(crc);
+ packet[29]=lowByte(crc);
+ //
+ }
+
+ 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
+ //
+ uint8_t lpass = pass_ ;
+ uint16_t chan_0 ;
+ uint16_t chan_1 ;
+ uint8_t flag2 = 0;
+ uint8_t startChan = 0;
+ crc = 0;
+ //static uint8_t p = 0;
+ //
+ packet[0] = 0x1D;
+ packet[1] = rx_tx_addr[3];
+ packet[2] = rx_tx_addr[2];
+ packet[3] = crc_Byte(0x02);
+ //
+ packet[4] = crc_Byte((ctr<<6)+channr); //*64
+ packet[5] = crc_Byte(counter_rst);
+ packet[6] = crc_Byte(RX_num);
+ // FLAGS 00 - standard packet
+ //10, 12, 14, 16, 18, 1A, 1C, 1E - failsafe packet
+ //20 - range check packet
+ packet[7] = crc_Byte(FS_flag);
+ packet[8] = crc_Byte(flag2);
+ //
+ if ( lpass & 1 )
+ startChan += 8 ;
+
+ for(uint8_t i = 0; i <12 ; i+=3)
+ {//12 bytes
+ chan_0 = scaleForPXX(startChan);
+ if(lpass & 1 )
+ chan_0+=2048;
+
+ packet[9+i] = crc_Byte(lowByte(chan_0));//3 bytes*4
+ startChan++;
+ chan_1 = scaleForPXX(startChan);
+ if(lpass & 1 )
+ chan_1+= 2048;
+
+ startChan++;
+ packet[9+i+1]=crc_Byte((((chan_0>>8) & 0x0F)|(chan_1 << 4)));
+ packet[9+i+2]=crc_Byte(chan_1>>4);
+ }
+ //packet[21]=crc_Byte(0x08);//first
+ packet[21]=crc_Byte(0x80);//??? when received first telemetry frame is changed to 0x80
+ //packet[21]=crc_Byte(ptr[p]);//???
+ //p=(p+1)%4;//repeating 4 bytes sequence pattern every 4th frame.
+
+ pass_=lpass+1;
+
+ for (uint8_t i=22;i<28;i++)
+ packet[i]=crc_Byte(0);
+
+ packet[28]=highByte(crc);
+ packet[29]=lowByte(crc);
+ }
+
+<<<<<<< HEAD
+ 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>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;
+ }
+=======
uint8_t chanskip;
uint8_t counter_rst;
uint8_t ctr;
@@ -329,4 +617,5 @@ uint16_t initFrSkyX()
seq_last_rcvd = 8;
return 10000;
}
+>>>>>>> refs/remotes/pascallanger/master
#endif
\ No newline at end of file
diff --git a/Multiprotocol/FrSky_cc2500.ino b/Multiprotocol/FrSky_cc2500.ino
new file mode 100644
index 0000000..ec17450
--- /dev/null
+++ b/Multiprotocol/FrSky_cc2500.ino
@@ -0,0 +1,219 @@
+/*
+ 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(FRSKY_CC2500_INO)
+
+#include "iface_cc2500.h"
+
+//##########Variables########
+//uint32_t state;
+//uint8_t len;
+
+/*
+enum {
+ FRSKY_BIND = 0,
+ FRSKY_BIND_DONE = 1000,
+ FRSKY_DATA1,
+ FRSKY_DATA2,
+ FRSKY_DATA3,
+ FRSKY_DATA4,
+ FRSKY_DATA5
+};
+*/
+
+static void __attribute__((unused)) frsky2way_init(uint8_t bind)
+{
+ // Configure cc2500 for tx mode
+ CC2500_Reset();
+ //
+ 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();
+
+ cc2500_strobe(CC2500_SIDLE);
+
+ cc2500_writeReg(CC2500_09_ADDR, bind ? 0x03 : rx_tx_addr[3]);
+ cc2500_writeReg(CC2500_07_PKTCTRL1, 0x05);
+ cc2500_strobe(CC2500_SIDLE); // Go to idle...
+ //
+ cc2500_writeReg(CC2500_0A_CHANNR, 0x00);
+ cc2500_writeReg(CC2500_23_FSCAL3, 0x89);
+ cc2500_strobe(CC2500_SFRX);
+ //#######END INIT########
+}
+
+static uint8_t __attribute__((unused)) get_chan_num(uint16_t idx)
+{
+ uint8_t ret = (idx * 0x1e) % 0xeb;
+ if(idx == 3 || idx == 23 || idx == 47)
+ ret++;
+ if(idx > 47)
+ return 0;
+ return ret;
+}
+
+static void __attribute__((unused)) frsky2way_build_bind_packet()
+{
+ //11 03 01 d7 2d 00 00 1e 3c 5b 78 00 00 00 00 00 00 01
+ //11 03 01 19 3e 00 02 8e 2f bb 5c 00 00 00 00 00 00 01
+ packet[0] = 0x11;
+ packet[1] = 0x03;
+ packet[2] = 0x01;
+ packet[3] = rx_tx_addr[3];
+ packet[4] = rx_tx_addr[2];
+ uint16_t idx = ((state -FRSKY_BIND) % 10) * 5;
+ packet[5] = idx;
+ packet[6] = get_chan_num(idx++);
+ packet[7] = get_chan_num(idx++);
+ packet[8] = get_chan_num(idx++);
+ packet[9] = get_chan_num(idx++);
+ packet[10] = get_chan_num(idx++);
+ packet[11] = 0x00;
+ packet[12] = 0x00;
+ packet[13] = 0x00;
+ packet[14] = 0x00;
+ packet[15] = 0x00;
+ packet[16] = 0x00;
+ packet[17] = 0x01;
+}
+
+static void __attribute__((unused)) frsky2way_data_frame()
+{//pachet[4] is telemetry user frame counter(hub)
+ //11 d7 2d 22 00 01 c9 c9 ca ca 88 88 ca ca c9 ca 88 88
+ //11 57 12 00 00 01 f2 f2 f2 f2 06 06 ca ca ca ca 18 18
+ packet[0] = 0x11; //Length
+ packet[1] = rx_tx_addr[3];
+ packet[2] = rx_tx_addr[2];
+ packet[3] = counter;//
+ #if defined TELEMETRY
+ packet[4] = telemetry_counter;
+ #else
+ packet[4] = 0x00;
+ #endif
+
+ packet[5] = 0x01;
+ //
+ packet[10] = 0;
+ packet[11] = 0;
+ packet[16] = 0;
+ packet[17] = 0;
+ for(uint8_t i = 0; i < 8; i++)
+ {
+ uint16_t value;
+ value = convert_channel_frsky(i);
+ if(i < 4)
+ {
+ packet[6+i] = value & 0xff;
+ packet[10+(i>>1)] |= ((value >> 8) & 0x0f) << (4 *(i & 0x01));
+ }
+ else
+ {
+ packet[8+i] = value & 0xff;
+ packet[16+((i-4)>>1)] |= ((value >> 8) & 0x0f) << (4 * ((i-4) & 0x01));
+ }
+ }
+}
+
+uint16_t initFrSky_2way()
+{
+ if(IS_AUTOBIND_FLAG_on)
+ {
+ frsky2way_init(1);
+ state = FRSKY_BIND;//
+ }
+ else
+ {
+ frsky2way_init(0);
+ state = FRSKY_DATA2;
+ }
+ return 10000;
+}
+
+uint16_t ReadFrSky_2way()
+{
+ if (state < FRSKY_BIND_DONE)
+ {
+ frsky2way_build_bind_packet();
+ cc2500_strobe(CC2500_SIDLE);
+ cc2500_writeReg(CC2500_0A_CHANNR, 0x00);
+ cc2500_writeReg(CC2500_23_FSCAL3, 0x89);
+ cc2500_strobe(CC2500_SFRX);//0x3A
+ cc2500_writeFifo(packet, packet[0]+1);
+ state++;
+ return 9000;
+ }
+ if (state == FRSKY_BIND_DONE)
+ {
+ state = FRSKY_DATA2;
+ frsky2way_init(0);
+ counter = 0;
+ BIND_DONE;
+ }
+ else
+ if (state == FRSKY_DATA5)
+ {
+ cc2500_strobe(CC2500_SRX);//0x34 RX enable
+ state = FRSKY_DATA1;
+ return 9200;
+ }
+ counter = (counter + 1) % 188;
+ if (state == FRSKY_DATA4)
+ { //telemetry receive
+ CC2500_SetTxRxMode(RX_EN);
+ cc2500_strobe(CC2500_SIDLE);
+ cc2500_writeReg(CC2500_0A_CHANNR, get_chan_num(counter % 47));
+ cc2500_writeReg(CC2500_23_FSCAL3, 0x89);
+ state++;
+ return 1300;
+ }
+ else
+ {
+ if (state == FRSKY_DATA1)
+ {
+ len = cc2500_readReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
+ if (len<=MAX_PKT)//27 bytes
+ {
+ cc2500_readFifo(pkt, len); //received telemetry packets
+ #if defined(TELEMETRY)
+ //parse telemetry packet here
+ frsky_check_telemetry(pkt,len); //check if valid telemetry packets and buffer them.
+ #endif
+ }
+ CC2500_SetTxRxMode(TX_EN);
+ CC2500_SetPower(); // Set tx_power
+ }
+ cc2500_strobe(CC2500_SIDLE);
+ cc2500_writeReg(CC2500_0A_CHANNR, get_chan_num(counter % 47));
+ cc2500_writeReg(CC2500_23_FSCAL3, 0x89);
+ cc2500_strobe(CC2500_SFRX);
+ frsky2way_data_frame();
+ cc2500_writeFifo(packet, packet[0]+1);
+ state++;
+ }
+ return state == FRSKY_DATA4 ? 7500 : 9000;
+}
+#endif
diff --git a/Multiprotocol/KN_nrf24l01.ino b/Multiprotocol/KN_nrf24l01.ino
index 14e9566..5675181 100644
--- a/Multiprotocol/KN_nrf24l01.ino
+++ b/Multiprotocol/KN_nrf24l01.ino
@@ -246,7 +246,11 @@ static void __attribute__((unused)) kn_init()
NRF24L01_Initialize();
+<<<<<<< HEAD
+ NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO));
+=======
NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO));
+>>>>>>> refs/remotes/pascallanger/master
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknoledgement
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address
@@ -259,7 +263,11 @@ static void __attribute__((unused)) kn_init()
NRF24L01_Activate(0x73);
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 1); // Dynamic payload for data pipe 0
// Enable: Dynamic Payload Length to enable PCF
+<<<<<<< HEAD
+ NRF24L01_WriteReg(NRF24L01_1D_FEATURE, BV(NRF2401_1D_EN_DPL));
+=======
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, _BV(NRF2401_1D_EN_DPL));
+>>>>>>> refs/remotes/pascallanger/master
NRF24L01_SetPower();
diff --git a/Multiprotocol/MJXQ_nrf24l01.ino b/Multiprotocol/MJXQ_nrf24l01.ino
index ae95060..a1cb14a 100644
--- a/Multiprotocol/MJXQ_nrf24l01.ino
+++ b/Multiprotocol/MJXQ_nrf24l01.ino
@@ -12,7 +12,11 @@
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see .
*/
+<<<<<<< HEAD
+// compatible with MJX WLH08, X600, X800, H26D
+=======
// compatible with MJX WLH08, X600, X800, H26D, Eachine E010
+>>>>>>> refs/remotes/pascallanger/master
// Last sync with hexfet new_protocols/mjxq_nrf24l01.c dated 2016-01-17
#if defined(MJXQ_NRF24L01_INO)
@@ -26,6 +30,8 @@
#define MJXQ_RF_NUM_CHANNELS 4
#define MJXQ_ADDRESS_LENGTH 5
+<<<<<<< HEAD
+=======
// haven't figured out txid<-->rf channel mapping for MJX models
const uint8_t PROGMEM MJXQ_map_rfchan[][4] = {
{0x0A, 0x46, 0x3A, 0x42},
@@ -37,6 +43,7 @@ const uint8_t PROGMEM MJXQ_map_txid[][3] = {
{0x48, 0x6A, 0x40} };
+>>>>>>> refs/remotes/pascallanger/master
#define MJXQ_PAN_TILT_COUNT 16 // for H26D - match stock tx timing
#define MJXQ_PAN_DOWN 0x08
#define MJXQ_PAN_UP 0x04
@@ -50,6 +57,16 @@ static uint8_t __attribute__((unused)) MJXQ_pan_tilt_value()
packet_count++;
if(packet_count & MJXQ_PAN_TILT_COUNT)
{
+<<<<<<< HEAD
+ if(Servo_AUX8)
+ pan=MJXQ_PAN_UP;
+ if(Servo_data[AUX8]PPM_MIN_COMMAND)
+ pan=MJXQ_TILT_UP;
+ if(Servo_data[AUX9]PPM_MAX_COMMAND)
pan=MJXQ_PAN_UP;
if(Servo_data[AUX8]>>>>>> refs/remotes/pascallanger/master
}
return pan;
}
@@ -68,10 +86,17 @@ static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind)
packet[0] = convert_channel_8b(THROTTLE);
packet[1] = convert_channel_s8b(RUDDER);
packet[4] = 0x40; // rudder does not work well with dyntrim
+<<<<<<< HEAD
+ packet[2] = convert_channel_s8b(ELEVATOR);
+ packet[5] = MJXQ_CHAN2TRIM(packet[2]); // trim elevator
+ packet[3] = convert_channel_s8b(AILERON);
+ packet[6] = MJXQ_CHAN2TRIM(packet[3]); // trim aileron
+=======
packet[2] = 0x80 ^ convert_channel_s8b(ELEVATOR);
packet[5] = GET_FLAG(Servo_AUX5, 1) ? 0x40 : MJXQ_CHAN2TRIM(packet[2]); // trim elevator
packet[3] = convert_channel_s8b(AILERON);
packet[6] = GET_FLAG(Servo_AUX5, 1) ? 0x40 : MJXQ_CHAN2TRIM(packet[3]); // trim aileron
+>>>>>>> refs/remotes/pascallanger/master
packet[7] = rx_tx_addr[0];
packet[8] = rx_tx_addr[1];
packet[9] = rx_tx_addr[2];
@@ -96,7 +121,10 @@ static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind)
packet[10]=MJXQ_pan_tilt_value();
// fall through on purpose - no break
case WLH08:
+<<<<<<< HEAD
+=======
case E010:
+>>>>>>> refs/remotes/pascallanger/master
packet[10] += GET_FLAG(Servo_AUX6, 0x02) //RTH
| GET_FLAG(Servo_AUX5, 0x01); //HEADLESS
if (!bind)
@@ -109,6 +137,14 @@ static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind)
}
break;
case X600:
+<<<<<<< HEAD
+ if(Servo_AUX5) //HEADLESS
+ { // driven trims cause issues when headless is enabled
+ packet[5] = 0x40;
+ packet[6] = 0x40;
+ }
+=======
+>>>>>>> refs/remotes/pascallanger/master
packet[10] = GET_FLAG(!Servo_AUX2, 0x02); //LED
packet[11] = GET_FLAG(Servo_AUX6, 0x01); //RTH
if (!bind)
@@ -142,7 +178,11 @@ static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind)
if (sub_protocol == H26D)
NRF24L01_SetTxRxMode(TX_EN);
else
+<<<<<<< HEAD
+ XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP));
+=======
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
+>>>>>>> refs/remotes/pascallanger/master
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++ / 2]);
hopping_frequency_no %= 2 * MJXQ_RF_NUM_CHANNELS; // channels repeated
@@ -165,12 +205,20 @@ static void __attribute__((unused)) MJXQ_init()
if (sub_protocol == WLH08)
memcpy(hopping_frequency, "\x12\x22\x32\x42", MJXQ_RF_NUM_CHANNELS);
else
+<<<<<<< HEAD
+ if (sub_protocol == H26D)
+=======
if (sub_protocol == H26D || sub_protocol == E010)
+>>>>>>> refs/remotes/pascallanger/master
memcpy(hopping_frequency, "\x36\x3e\x46\x2e", MJXQ_RF_NUM_CHANNELS);
else
{
memcpy(hopping_frequency, "\x0a\x35\x42\x3d", MJXQ_RF_NUM_CHANNELS);
+<<<<<<< HEAD
+ memcpy(addr, "\x6d\x6a\x73\x73\x73", MJXQ_RF_NUM_CHANNELS);
+=======
memcpy(addr, "\x6d\x6a\x73\x73\x73", MJXQ_ADDRESS_LENGTH);
+>>>>>>> refs/remotes/pascallanger/master
}
@@ -189,25 +237,53 @@ static void __attribute__((unused)) MJXQ_init()
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, MJXQ_PACKET_SIZE); // rx pipe 0 (used only for blue board)
+<<<<<<< HEAD
+ NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
+=======
if (sub_protocol == E010)
NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250K
else
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
+>>>>>>> refs/remotes/pascallanger/master
NRF24L01_SetPower();
}
static void __attribute__((unused)) MJXQ_init2()
{
+<<<<<<< HEAD
+ // haven't figured out txid<-->rf channel mapping for MJX models
+ static const uint8_t rf_map[][4] = {
+ {0x0A, 0x46, 0x3A, 0x42},
+ {0x0A, 0x3C, 0x36, 0x3F},
+ {0x0A, 0x43, 0x36, 0x3F} };
+ if (sub_protocol == H26D)
+ memcpy(hopping_frequency, "\x32\x3e\x42\x4e", MJXQ_RF_NUM_CHANNELS);
+ else
+ if (sub_protocol == WLH08)
+ memcpy(hopping_frequency, rf_map[rx_tx_addr[0]%3], MJXQ_RF_NUM_CHANNELS);
+=======
if (sub_protocol == H26D)
memcpy(hopping_frequency, "\x32\x3e\x42\x4e", MJXQ_RF_NUM_CHANNELS);
else
if (sub_protocol != WLH08 && sub_protocol != E010)
for(uint8_t i=0;i>>>>>> refs/remotes/pascallanger/master
}
static void __attribute__((unused)) MJXQ_initialize_txid()
{
+<<<<<<< HEAD
+ // haven't figured out txid<-->rf channel mapping for MJX models
+ static const uint8_t tx_map[][3]={
+ {0xF8, 0x4F, 0x1C},
+ {0xC8, 0x6E, 0x02},
+ {0x48, 0x6A, 0x40} };
+ if (sub_protocol == WLH08)
+ rx_tx_addr[0]&=0xF8; // txid must be multiple of 8
+ else
+ memcpy(rx_tx_addr,tx_map[rx_tx_addr[0]%3],3);
+=======
rx_tx_addr[0]&=0xF8;
if (sub_protocol == E010)
{
@@ -217,6 +293,7 @@ static void __attribute__((unused)) MJXQ_initialize_txid()
else
for(uint8_t i=0;i<3;i++)
rx_tx_addr[i]=pgm_read_byte_near( &MJXQ_map_txid[rx_tx_addr[4]%3][i] );
+>>>>>>> refs/remotes/pascallanger/master
}
uint16_t MJXQ_callback()
diff --git a/Multiprotocol/MT99xx_nrf24l01.ino b/Multiprotocol/MT99xx_nrf24l01.ino
index 4fb2d65..dff51d7 100644
--- a/Multiprotocol/MT99xx_nrf24l01.ino
+++ b/Multiprotocol/MT99xx_nrf24l01.ino
@@ -12,7 +12,11 @@
You should have received a copy of the GNU General Public License
along with Multiprotocol. If not, see .
*/
+<<<<<<< HEAD
+// compatible with MT99xx, Eachine H7, Yi Zhan i6S
+=======
// compatible with MT99xx, Eachine H7, Yi Zhan i6S and LS114/124
+>>>>>>> refs/remotes/pascallanger/master
// Last sync with Goebish mt99xx_nrf24l01.c dated 2016-01-29
#if defined(MT99XX_NRF24L01_INO)
@@ -37,6 +41,8 @@ enum{
FLAG_MT_FLIP = 0x80,
};
+<<<<<<< HEAD
+=======
enum{
// flags going to packet[6] (LS)
FLAG_LS_INVERT = 0x01,
@@ -47,12 +53,43 @@ enum{
FLAG_LS_FLIP = 0x80,
};
+>>>>>>> refs/remotes/pascallanger/master
enum {
MT99XX_INIT = 0,
MT99XX_BIND,
MT99XX_DATA
};
+<<<<<<< HEAD
+static void __attribute__((unused)) MT99XX_send_packet()
+{
+ const uint8_t yz_p4_seq[] = {0xa0, 0x20, 0x60};
+ const uint8_t mys_byte[] = {
+ 0x01, 0x11, 0x02, 0x12, 0x03, 0x13, 0x04, 0x14,
+ 0x05, 0x15, 0x06, 0x16, 0x07, 0x17, 0x00, 0x10
+ };
+ static uint8_t yz_seq_num=0;
+
+ if(sub_protocol != YZ)
+ { // MT99XX & H7
+ packet[0] = convert_channel_8b_scale(THROTTLE,0x00,0xE1); // throttle
+ packet[1] = convert_channel_8b_scale(RUDDER ,0x00,0xE1); // rudder
+ packet[2] = convert_channel_8b_scale(AILERON ,0x00,0xE1); // aileron
+ packet[3] = convert_channel_8b_scale(ELEVATOR,0x00,0xE1); // elevator
+ packet[4] = 0x20; // pitch trim (0x3f-0x20-0x00)
+ packet[5] = 0x20; // roll trim (0x00-0x20-0x3f)
+ packet[6] = GET_FLAG( Servo_AUX1, FLAG_MT_FLIP )
+ | GET_FLAG( Servo_AUX3, FLAG_MT_SNAPSHOT )
+ | GET_FLAG( Servo_AUX4, FLAG_MT_VIDEO );
+ if(sub_protocol==MT99)
+ packet[6] |= 0x40 | FLAG_MT_RATE2;
+ else
+ packet[6] |= FLAG_MT_RATE1; // max rate on H7
+ // todo: mys_byte = next channel index ?
+ // low nibble: index in chan list ?
+ // high nibble: 0->start from start of list, 1->start from end of list ?
+ packet[7] = mys_byte[hopping_frequency_no];
+=======
const uint8_t h7_mys_byte[] = {
0x01, 0x11, 0x02, 0x12, 0x03, 0x13, 0x04, 0x14,
0x05, 0x15, 0x06, 0x16, 0x07, 0x17, 0x00, 0x10
@@ -101,6 +138,7 @@ static void __attribute__((unused)) MT99XX_send_packet()
ls_counter=0;
}
+>>>>>>> refs/remotes/pascallanger/master
uint8_t result=checksum_offset;
for(uint8_t i=0; i<8; i++)
result += packet[i];
@@ -109,9 +147,15 @@ static void __attribute__((unused)) MT99XX_send_packet()
else
{ // YZ
packet[0] = convert_channel_8b_scale(THROTTLE,0x00,0x64); // throttle
+<<<<<<< HEAD
+ packet[1] = convert_channel_8b_scale(RUDDER ,0x00,0x64); // rudder
+ packet[2] = convert_channel_8b_scale(ELEVATOR,0x00,0x64); // elevator
+ packet[3] = convert_channel_8b_scale(AILERON ,0x00,0x64); // aileron
+=======
packet[1] = convert_channel_8b_scale(RUDDER ,0x64,0x00); // rudder
packet[2] = convert_channel_8b_scale(ELEVATOR,0x00,0x64); // elevator
packet[3] = convert_channel_8b_scale(AILERON ,0x64,0x00); // aileron
+>>>>>>> refs/remotes/pascallanger/master
if(packet_count++ >= 23)
{
yz_seq_num ++;
@@ -132,10 +176,14 @@ static void __attribute__((unused)) MT99XX_send_packet()
packet[8] = 0xff;
}
+<<<<<<< HEAD
+ NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no] + channel_offset);
+=======
if(sub_protocol == LS)
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x2D); // LS always transmits on the same channel
else
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no] + channel_offset);
+>>>>>>> refs/remotes/pascallanger/master
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
XN297_WritePayload(packet, MT99XX_PACKET_SIZE);
@@ -153,11 +201,16 @@ static void __attribute__((unused)) MT99XX_send_packet()
static void __attribute__((unused)) MT99XX_init()
{
NRF24L01_Initialize();
+<<<<<<< HEAD
+ NRF24L01_SetTxRxMode(TX_EN);
+ NRF24L01_FlushTx();
+=======
if(sub_protocol == YZ)
XN297_SetScrambledMode(XN297_UNSCRAMBLED);
NRF24L01_SetTxRxMode(TX_EN);
NRF24L01_FlushTx();
XN297_SetTXAddr((uint8_t *)"\xCC\xCC\xCC\xCC\xCC", 5);
+>>>>>>> refs/remotes/pascallanger/master
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
@@ -169,18 +222,31 @@ static void __attribute__((unused)) MT99XX_init()
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
NRF24L01_SetPower();
+<<<<<<< HEAD
+ XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP) | (sub_protocol == YZ ? BV(XN297_UNSCRAMBLED):0) );
+
+ XN297_SetTXAddr((uint8_t *)"\xCC\xCC\xCC\xCC\xCC", 5);
+=======
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP) );
+>>>>>>> refs/remotes/pascallanger/master
}
static void __attribute__((unused)) MT99XX_initialize_txid()
{
+<<<<<<< HEAD
+=======
rx_tx_addr[3] = 0xCC;
rx_tx_addr[4] = 0xCC;
+>>>>>>> refs/remotes/pascallanger/master
if(sub_protocol == YZ)
{
rx_tx_addr[0] = 0x53; // test (SB id)
rx_tx_addr[1] = 0x00;
+<<<<<<< HEAD
+ }
+ checksum_offset = (rx_tx_addr[0] + rx_tx_addr[1]) & 0xff;
+=======
rx_tx_addr[2] = 0x00;
}
else
@@ -189,6 +255,7 @@ static void __attribute__((unused)) MT99XX_initialize_txid()
else //MT99 & H7
rx_tx_addr[2] = 0x00;
checksum_offset = rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2];
+>>>>>>> refs/remotes/pascallanger/master
channel_offset = (((checksum_offset & 0xf0)>>4) + (checksum_offset & 0x0f)) % 8;
}
@@ -200,16 +267,26 @@ uint16_t MT99XX_callback()
{
if (bind_counter == 0)
{
+<<<<<<< HEAD
+ rx_tx_addr[2] = 0x00;
+ rx_tx_addr[3] = 0xCC;
+ rx_tx_addr[4] = 0xCC;
+=======
+>>>>>>> refs/remotes/pascallanger/master
// set tx address for data packets
XN297_SetTXAddr(rx_tx_addr, 5);
BIND_DONE;
}
else
{
+<<<<<<< HEAD
+ NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
+=======
if(sub_protocol == LS)
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x2D); // LS always transmits on the same channel
else
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
+>>>>>>> refs/remotes/pascallanger/master
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
XN297_WritePayload(packet, MT99XX_PACKET_SIZE); // bind packet
@@ -236,6 +313,25 @@ uint16_t initMT99XX(void)
MT99XX_init();
packet[0] = 0x20;
+<<<<<<< HEAD
+ if(sub_protocol!=YZ)
+ { // MT99 & H7
+ packet_period = MT99XX_PACKET_PERIOD_MT;
+ packet[1] = 0x14;
+ packet[2] = 0x03;
+ packet[3] = 0x25;
+ }
+ else
+ { // YZ
+ packet_period = MT99XX_PACKET_PERIOD_YZ;
+ packet[1] = 0x15;
+ packet[2] = 0x05;
+ packet[3] = 0x06;
+ }
+ packet[4] = rx_tx_addr[0]; // 1st byte for data state tx address
+ packet[5] = rx_tx_addr[1]; // 2nd byte for data state tx address (always 0x00 on Yi Zhan ?)
+ packet[6] = 0x00; // 3rd byte for data state tx address (always 0x00 ?)
+=======
packet_period = MT99XX_PACKET_PERIOD_MT;
switch(sub_protocol)
{ // MT99 & H7
@@ -260,6 +356,7 @@ uint16_t initMT99XX(void)
packet[4] = rx_tx_addr[0];
packet[5] = rx_tx_addr[1];
packet[6] = rx_tx_addr[2];
+>>>>>>> refs/remotes/pascallanger/master
packet[7] = checksum_offset; // checksum offset
packet[8] = 0xAA; // fixed
packet_count=0;
diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino
index fc3c097..fe73f45 100644
--- a/Multiprotocol/Multiprotocol.ino
+++ b/Multiprotocol/Multiprotocol.ino
@@ -1,11 +1,17 @@
/*********************************************************
- Multiprotocol Tx code
- by Midelic and Pascal Langer(hpnuts)
- http://www.rcgroups.com/forums/showthread.php?t=2165676
+ Multiprotocol Tx code
+ by Midelic and Pascal Langer(hpnuts)
+ fork by Tipouic
+ http://www.rcgroups.com/forums/showthread.php?t=2165676
https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/edit/master/README.md
+<<<<<<< HEAD
+ Thanks to PhracturedBlue, Hexfet, Goebish and all protocol developers
+ Ported from deviation firmware
+=======
Thanks to PhracturedBlue, Hexfet, Goebish, Victzh and all protocol developers
Ported from deviation firmware
+>>>>>>> refs/remotes/pascallanger/master
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
@@ -22,12 +28,19 @@
*/
#include
#include
+<<<<<<< HEAD
+#include
+=======
//#define DEBUG_TX
#include "Pins.h"
+>>>>>>> refs/remotes/pascallanger/master
#include "Multiprotocol.h"
//Multiprotocol module configuration file
#include "_Config.h"
+<<<<<<< HEAD
+
+=======
#include "TX_Def.h"
#ifdef XMEGA
@@ -40,6 +53,7 @@
#define DSM_TELEMETRY // Enable DSM telemetry
#endif
+>>>>>>> refs/remotes/pascallanger/master
//Global constants/variables
uint32_t MProtocol_id;//tx id,
uint32_t MProtocol_id_master;
@@ -53,16 +67,40 @@ uint8_t packet[40];
// Servo data
uint16_t Servo_data[NUM_CHN];
uint8_t Servo_AUX;
+<<<<<<< HEAD
+const uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4};
+
+// Protocol variables
+uint8_t rx_tx_addr[5];
+uint8_t phase;
+=======
uint16_t servo_max_100,servo_min_100,servo_max_125,servo_min_125;
// Protocol variables
uint8_t cyrfmfg_id[6];//for dsm2 and devo
uint8_t rx_tx_addr[5];
uint8_t phase;
+>>>>>>> refs/remotes/pascallanger/master
uint16_t bind_counter;
uint8_t bind_phase;
uint8_t binding_idx;
uint16_t packet_period;
+<<<<<<< HEAD
+uint8_t packet_count;
+uint8_t packet_sent;
+uint8_t packet_length;
+uint8_t hopping_frequency[23];
+uint8_t *hopping_frequency_ptr;
+uint8_t hopping_frequency_no=0;
+uint8_t rf_ch_num;
+uint8_t throttle, rudder, elevator, aileron;
+uint8_t flags;
+uint16_t crc;
+//
+uint32_t state;
+uint8_t len;
+uint8_t RX_num;
+=======
uint8_t packet_count;
uint8_t packet_sent;
uint8_t packet_length;
@@ -89,6 +127,7 @@ const uint8_t CH_AETR[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3,
const uint8_t CH_TAER[]={THROTTLE, AILERON, ELEVATOR, RUDDER, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8};
const uint8_t CH_RETA[]={RUDDER, ELEVATOR, THROTTLE, AILERON, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8};
const uint8_t CH_EATR[]={ELEVATOR, AILERON, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8};
+>>>>>>> refs/remotes/pascallanger/master
// Mode_select variables
uint8_t mode_select;
@@ -97,10 +136,20 @@ uint8_t protocol_flags=0,protocol_flags2=0;
// PPM variable
volatile uint16_t PPM_data[NUM_CHN];
+<<<<<<< HEAD
+// Serial variables
+#define RXBUFFER_SIZE 25
+#define TXBUFFER_SIZE 12
+volatile uint8_t rx_buff[RXBUFFER_SIZE];
+volatile uint8_t rx_ok_buff[RXBUFFER_SIZE];
+volatile uint8_t tx_buff[TXBUFFER_SIZE];
+volatile uint8_t idx = 0;
+=======
#ifndef XMEGA
//Random variable
volatile uint32_t gWDT_entropy=0;
#endif
+>>>>>>> refs/remotes/pascallanger/master
//Serial protocol
uint8_t sub_protocol;
@@ -143,6 +192,11 @@ volatile uint8_t discard_frame = 0;
#define MAX_PKT 27
uint8_t pkt[MAX_PKT];//telemetry receiving packets
#if defined(TELEMETRY)
+<<<<<<< HEAD
+uint8_t pktt[MAX_PKT];//telemetry receiving packets
+ volatile uint8_t tx_head;
+ volatile uint8_t tx_tail;
+=======
#ifdef INVERT_TELEMETRY
// enable bit bash for serial
#ifndef XMEGA
@@ -158,6 +212,7 @@ uint8_t pkt[MAX_PKT];//telemetry receiving packets
volatile uint8_t tx_head=0;
volatile uint8_t tx_tail=0;
#endif // BASH_SERIAL
+>>>>>>> refs/remotes/pascallanger/master
uint8_t v_lipo;
int16_t RSSI_dBm;
//const uint8_t RSSI_offset=72;//69 71.72 values db
@@ -229,6 +284,19 @@ void setup()
#endif
// Set Chip selects
+<<<<<<< HEAD
+ CS_on;
+ CC25_CSN_on;
+ NRF_CSN_on;
+ CYRF_CSN_on;
+ // Set SPI lines
+ SDI_on;
+ SCK_off;
+
+ // Timer1 config
+ TCCR1A = 0;
+ TCCR1B = (1 << CS11); //prescaler8, set timer1 to increment every 0.5us(16Mhz) and start timer
+=======
#ifdef A7105_INSTALLED
A7105_CSN_on;
#endif
@@ -244,10 +312,42 @@ void setup()
// Set SPI lines
SDI_on;
SCLK_off;
+>>>>>>> refs/remotes/pascallanger/master
// Set servos positions
for(uint8_t i=0;i>2)&0x07 ) | ( (PINC<<3)&0x08) );//encoder dip switches 1,2,4,8=>B2,B3,B4,C0
+ //**********************************
+//mode_select=1; // here to test PPM
+ //**********************************
+
+ // Update LED
+ LED_OFF;
+ LED_SET_OUTPUT;
+
+ // Read or create protocol id
+ MProtocol_id_master=random_id(10,false);
+
+ //Init RF modules
+ #ifdef CC2500_INSTALLED
+ CC2500_Reset();
+ #endif
+
+=======
Servo_data[THROTTLE]=servo_min_100;
#ifdef ENABLE_PPM
memcpy((void *)PPM_data,Servo_data, sizeof(Servo_data));
@@ -288,12 +388,17 @@ void setup()
MProtocol_id_master=random_id(10,false);
#ifdef ENABLE_PPM
+>>>>>>> refs/remotes/pascallanger/master
//Protocol and interrupts initialization
if(mode_select != MODE_SERIAL)
{ // PPM
mode_select--;
+<<<<<<< HEAD
+ cur_protocol[0] = PPM_prot[mode_select].protocol;
+=======
protocol = PPM_prot[mode_select].protocol;
cur_protocol[1] = protocol;
+>>>>>>> refs/remotes/pascallanger/master
sub_protocol = PPM_prot[mode_select].sub_proto;
RX_num = PPM_prot[mode_select].rx_num;
MProtocol_id = RX_num + MProtocol_id_master;
@@ -301,6 +406,16 @@ void setup()
if(PPM_prot[mode_select].power) POWER_FLAG_on;
if(PPM_prot[mode_select].autobind) AUTOBIND_FLAG_on;
mode_select++;
+<<<<<<< HEAD
+
+ protocol_init();
+
+ //Configure PPM interrupt
+ EICRA |=(1<>>>>>> refs/remotes/pascallanger/master
#endif
}
else
@@ -338,6 +454,39 @@ void setup()
// Main
// Protocol scheduler
void loop()
+<<<<<<< HEAD
+{
+ if(mode_select==MODE_SERIAL && IS_RX_FLAG_on) // Serial mode and something has been received
+ {
+ update_serial_data(); // Update protocol and data
+ update_aux_flags();
+ if(IS_CHANGE_PROTOCOL_FLAG_on)
+ { // Protocol needs to be changed
+ LED_OFF; //led off during protocol init
+ module_reset(); //reset previous module
+ protocol_init(); //init new protocol
+ CHANGE_PROTOCOL_FLAG_off; //done
+ }
+ }
+ if(mode_select!=MODE_SERIAL && IS_PPM_FLAG_on) // PPM mode and a full frame has been received
+ {
+ for(uint8_t i=0;i>>>>>> refs/remotes/pascallanger/master
}
// Update Servo_AUX flags based on servo AUX positions
@@ -444,18 +594,64 @@ static void update_led_status(void)
{
if(blink>>>>>> refs/remotes/pascallanger/master
else
if(remote_callback == 0)
{ // Invalid protocol
- if(IS_LED_on) //flash to indicate invalid protocol
- blink+=BLINK_BAD_PROTO_TIME_LOW;
- else
- blink+=BLINK_BAD_PROTO_TIME_HIGH;
- }
+ if(IS_LED_on) //flash to indicate invalid protocol
+ blink+=BLINK_BAD_PROTO_TIME_LOW;
+ else
+ blink+=BLINK_BAD_PROTO_TIME_HIGH;
+ }
else
if(IS_BIND_DONE_on)
+<<<<<<< HEAD
+ LED_OFF; //bind completed -> led on
+ else
+ blink+=BLINK_BIND_TIME; //blink fastly during binding
+ LED_TOGGLE;
+ }
+}
+
+// Protocol scheduler
+static void CheckTimer(uint16_t (*cb)(void))
+{
+ uint16_t next_callback;
+ uint32_t prev;
+ if( (TIFR1 & (1< micros())
+ { // Callback did not took more than requested time for next callback
+ if(next_callback>32000)
+ { // next_callback should not be more than 32767 so we will wait here...
+ delayMicroseconds(next_callback-2000);
+ cli(); // disable global int
+ OCR1A=TCNT1+4000;
+ sei(); // enable global int
+ }
+ else
+ {
+ cli(); // disable global int
+ OCR1A+=next_callback*2; // set compare A for callback
+ sei(); // enable global int
+ }
+ TIFR1=(1< led on
else
blink+=BLINK_BIND_TIME; //blink fastly during binding
@@ -494,6 +690,7 @@ inline void tx_resume()
#endif
}
#endif
+>>>>>>> refs/remotes/pascallanger/master
}
// Protocol start
@@ -517,10 +714,227 @@ static void protocol_init()
if(IS_BIND_BUTTON_FLAG_on)
AUTOBIND_FLAG_on;
if(IS_AUTOBIND_FLAG_on)
- BIND_IN_PROGRESS; // Indicates bind in progress for blinking bind led
+ BIND_IN_PROGRESS; // Indicates bind in progress for blinking bind led
else
BIND_DONE;
+<<<<<<< HEAD
+ CTRL1_on; //NRF24L01 antenna RF3 by default
+ CTRL2_off; //NRF24L01 antenna RF3 by default
+
+ switch(cur_protocol[0]&0x1F) // Init the requested protocol
+ {
+#if defined(HM830_NRF24L01_INO)
+ case MODE_HM830:
+ next_callback=HM830_setup();
+ remote_callback = HM830_callback;
+ break;
+#endif
+#if defined(CFlie_NRF24L01_INO)
+ case MODE_CFLIE:
+ next_callback=Cflie_setup();
+ remote_callback = cflie_callback;
+ break;
+#endif
+#if defined(JOYSWAY_A7105_INO)
+ case MODE_JOYSWAY:
+ next_callback=JOYSWAY_Setup();
+ remote_callback = joysway_cb;
+ break;
+#endif
+#if defined(H377_NRF24L01_INO)
+ case MODE_H377:
+ next_callback=h377_setup();
+ remote_callback = h377_cb;
+ break;
+#endif
+#if defined(J6PRO_CYRF6936_INO)
+ case MODE_J6PRO:
+ next_callback=j6pro_setup();
+ remote_callback = j6pro_cb;
+ break;
+#endif
+#if defined(WK2x01_CYRF6936_INO)
+ case MODE_WK2x01:
+ next_callback=wk_setup();
+ remote_callback = wk_cb;
+ break;
+#endif
+#if defined(ESKY150_NRF24L01_INO)
+ case MODE_ESKY150:
+ next_callback=esky150_setup();
+ remote_callback = esky150_callback;
+ break;
+#endif
+#if defined(BlueFly_NRF24L01_INO)
+ case MODE_BlueFly:
+ next_callback=BlueFly_setup();
+ remote_callback = bluefly_cb;
+ break;
+#endif
+#if defined(HonTai_NRF24L01_INO)
+ case MODE_HonTai:
+ next_callback=ht_setup();
+ remote_callback = ht_callback;
+ break;
+#endif
+#if defined(UDI_NRF24L01_INO)
+ case MODE_UDI:
+ next_callback=UDI_setup();
+ remote_callback = UDI_callback;
+ break;
+#endif
+#if defined(NE260_NRF24L01_INO)
+ case MODE_NE260:
+ next_callback=NE260_setup();
+ remote_callback = ne260_cb;
+ break;
+#endif
+#if defined(SKYARTEC_CC2500_INO)
+ case MODE_SKYARTEC:
+ next_callback=skyartec_setup();
+ remote_callback = skyartec_cb;
+ break;
+#endif
+#if defined(FBL100_NRF24L01_INO)
+ case MODE_FBL100:
+ next_callback=fbl_setup();
+ remote_callback = ne260_cb;
+ break;
+#endif
+
+#if defined(FLYSKY_A7105_INO)
+ case MODE_FLYSKY:
+ CTRL1_off; //antenna RF1
+ next_callback = initFlySky();
+ remote_callback = ReadFlySky;
+ break;
+#endif
+#if defined(HUBSAN_A7105_INO)
+ case MODE_HUBSAN:
+ CTRL1_off; //antenna RF1
+ if(IS_BIND_BUTTON_FLAG_on) random_id(10,true); // Generate new ID if bind button is pressed.
+ next_callback = initHubsan();
+ remote_callback = ReadHubsan;
+ break;
+#endif
+#if defined(FRSKY_CC2500_INO)
+ case MODE_FRSKY:
+ CTRL1_off; //antenna RF2
+ CTRL2_on;
+ next_callback = initFrSky_2way();
+ remote_callback = ReadFrSky_2way;
+ break;
+#endif
+#if defined(FRSKYX_CC2500_INO)
+ case MODE_FRSKYX:
+ CTRL1_off; //antenna RF2
+ CTRL2_on;
+ next_callback = initFrSkyX();
+ remote_callback = ReadFrSkyX;
+ break;
+#endif
+#if defined(DSM2_CYRF6936_INO)
+ case MODE_DSM2:
+ CTRL2_on; //antenna RF4
+ next_callback = initDsm2();
+ //Servo_data[2]=1500;//before binding
+ remote_callback = ReadDsm2;
+ break;
+#endif
+#if defined(DEVO_CYRF6936_INO)
+ case MODE_DEVO:
+ CTRL2_on; //antenna RF4
+ next_callback = DevoInit();
+ remote_callback = devo_callback;
+ break;
+#endif
+#if defined(HISKY_NRF24L01_INO)
+ case MODE_HISKY:
+ next_callback=initHiSky();
+ remote_callback = hisky_cb;
+ break;
+#endif
+#if defined(V2X2_NRF24L01_INO)
+ case MODE_V2X2:
+ next_callback = initV2x2();
+ remote_callback = ReadV2x2;
+ break;
+#endif
+#if defined(YD717_NRF24L01_INO)
+ case MODE_YD717:
+ next_callback=initYD717();
+ remote_callback = yd717_callback;
+ break;
+#endif
+#if defined(KN_NRF24L01_INO)
+ case MODE_KN:
+ next_callback = initKN();
+ remote_callback = kn_callback;
+ break;
+#endif
+#if defined(SYMAX_NRF24L01_INO)
+ case MODE_SYMAX:
+ next_callback = initSymax();
+ remote_callback = symax_callback;
+ break;
+#endif
+#if defined(SLT_NRF24L01_INO)
+ case MODE_SLT:
+ next_callback=initSLT();
+ remote_callback = SLT_callback;
+ break;
+#endif
+#if defined(CX10_NRF24L01_INO)
+ case MODE_CX10:
+ next_callback=initCX10();
+ remote_callback = CX10_callback;
+ break;
+#endif
+#if defined(CG023_NRF24L01_INO)
+ case MODE_CG023:
+ next_callback=initCG023();
+ remote_callback = CG023_callback;
+ break;
+#endif
+#if defined(BAYANG_NRF24L01_INO)
+ case MODE_BAYANG:
+ next_callback=initBAYANG();
+ remote_callback = BAYANG_callback;
+ break;
+#endif
+#if defined(ESKY_NRF24L01_INO)
+ case MODE_ESKY:
+ next_callback=initESKY();
+ remote_callback = ESKY_callback;
+ break;
+#endif
+#if defined(MT99XX_NRF24L01_INO)
+ case MODE_MT99XX:
+ next_callback=initMT99XX();
+ remote_callback = MT99XX_callback;
+ break;
+#endif
+#if defined(MJXQ_NRF24L01_INO)
+ case MODE_MJXQ:
+ next_callback=initMJXQ();
+ remote_callback = MJXQ_callback;
+ break;
+#endif
+#if defined(SHENQI_NRF24L01_INO)
+ case MODE_SHENQI:
+ next_callback=initSHENQI();
+ remote_callback = SHENQI_callback;
+ break;
+#endif
+#if defined(FY326_NRF24L01_INO)
+ case MODE_FY326:
+ next_callback=initFY326();
+ remote_callback = FY326_callback;
+ break;
+#endif
+ }
+=======
PE1_on; //NRF24L01 antenna RF3 by default
PE2_off; //NRF24L01 antenna RF3 by default
@@ -721,6 +1135,7 @@ static void protocol_init()
#endif
#endif
}
+>>>>>>> refs/remotes/pascallanger/master
if(next_callback>32000)
{ // next_callback should not be more than 32767 so we will wait here...
@@ -728,15 +1143,39 @@ static void protocol_init()
delayMilliseconds(temp);
next_callback-=temp<<10; // between 2-3ms left at this stage
}
+<<<<<<< HEAD
+ cli(); // disable global int
+ OCR1A=TCNT1+next_callback*2; // set compare A for callback
+ sei(); // enable global int
+ TIFR1=(1<>>>>>> refs/remotes/pascallanger/master
}
void update_serial_data()
{
+<<<<<<< HEAD
+ if(rx_ok_buff[0]&0x20) //check range
+ RANGE_FLAG_on;
+ else
+ RANGE_FLAG_off;
+ if(rx_ok_buff[0]&0xC0) //check autobind(0x40) & bind(0x80) together
+ AUTOBIND_FLAG_on;
+ else
+ AUTOBIND_FLAG_off;
+ if(rx_ok_buff[1]&0x80) //if rx_ok_buff[1] ==1,power is low ,0-power high
+ POWER_FLAG_off; //power low
+ else
+ POWER_FLAG_on; //power high
+
+ option=rx_ok_buff[2];
+=======
RX_DONOTUPDTAE_on;
RX_FLAG_off; //data is being processed
if(rx_ok_buff[1]&0x20) //check range
@@ -751,11 +1190,29 @@ void update_serial_data()
POWER_FLAG_off; //power low
else
POWER_FLAG_on; //power high
+>>>>>>> refs/remotes/pascallanger/master
option=rx_ok_buff[3];
if( (rx_ok_buff[0] != cur_protocol[0]) || ((rx_ok_buff[1]&0x5F) != (cur_protocol[1]&0x5F)) || ( (rx_ok_buff[2]&0x7F) != (cur_protocol[2]&0x7F) ) )
{ // New model has been selected
+<<<<<<< HEAD
+ prev_protocol=cur_protocol[0]&0x1F; //store previous protocol so we can reset the module
+ cur_protocol[1] = rx_ok_buff[1]&0x7F; //store current protocol
+ CHANGE_PROTOCOL_FLAG_on; //change protocol
+ sub_protocol=(rx_ok_buff[1]>>4)& 0x07; //subprotocol no (0-7) bits 4-6
+ RX_num=rx_ok_buff[1]& 0x0F;
+ MProtocol_id=MProtocol_id_master+RX_num; //personalized RX bind + rx num // rx_num bits 0---3
+ }
+ else
+ if( ((rx_ok_buff[0]&0x80)!=0) && ((cur_protocol[0]&0x80)==0) ) // Bind flag has been set
+ CHANGE_PROTOCOL_FLAG_on; //restart protocol with bind
+ cur_protocol[0] = rx_ok_buff[0]; //store current protocol
+
+// decode channel values
+ volatile uint8_t *p=rx_ok_buff+2;
+ uint8_t dec=-3;
+=======
CHANGE_PROTOCOL_FLAG_on; //change protocol
protocol=(rx_ok_buff[0]==0x55?0:32) + (rx_ok_buff[1]&0x1F); //protocol no (0-63) bits 4-6 of buff[1] and bit 0 of buf[0]
sub_protocol=(rx_ok_buff[2]>>4)& 0x07; //subprotocol no (0-7) bits 4-6
@@ -775,11 +1232,46 @@ void update_serial_data()
// decode channel values
volatile uint8_t *p=rx_ok_buff+3;
uint8_t dec=-3;
+>>>>>>> refs/remotes/pascallanger/master
for(uint8_t i=0;i=8)
{
+<<<<<<< HEAD
+ dec-=8;
+ p++;
+ }
+ p++;
+ Servo_data[i]=((((*((uint32_t *)p))>>dec)&0x7FF)*5)/8+860; //value range 860<->2140 -125%<->+125%
+ }
+ RX_FLAG_off; //data has been processed
+}
+
+static void module_reset()
+{
+ if(remote_callback)
+ { // previous protocol loaded
+ remote_callback = 0;
+ switch(prev_protocol)
+ {
+ case MODE_FLYSKY:
+ case MODE_HUBSAN:
+ A7105_Reset();
+ break;
+ case MODE_FRSKY:
+ case MODE_FRSKYX:
+ CC2500_Reset();
+ break;
+ case MODE_DSM2:
+ case MODE_DEVO:
+ CYRF_Reset();
+ break;
+ default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY, MODE_MT99XX, MODE_MJXQ, MODE_SHENQI, MODE_FY326
+ NRF24L01_Reset();
+ break;
+ }
+=======
dec-=8;
p++;
}
@@ -796,6 +1288,7 @@ void update_serial_data()
{ memcpy((void*)rx_ok_buff,(const void*)rx_buff,RXBUFFER_SIZE);// Duplicate the buffer
RX_FLAG_on; // data to be processed next time...
RX_MISSED_BUFF_off;
+>>>>>>> refs/remotes/pascallanger/master
}
#ifdef XMEGA
sei();
@@ -862,15 +1355,35 @@ void Mprotocol_serial_init()
#if defined(TELEMETRY)
void PPM_Telemetry_serial_init()
{
+<<<<<<< HEAD
+ if(Servo_data[ch]>PPM_MAX_100)
+ return PPM_MAX_100;
+ else
+ if (Servo_data[ch]>>>>>> refs/remotes/pascallanger/master
}
#endif
+<<<<<<< HEAD
+#if defined(TELEMETRY)
+void Serial_write(uint8_t data)
+{
+ cli(); // disable global int
+ if(++tx_head>=TXBUFFER_SIZE)
+ tx_head=0;
+ tx_buff[tx_head]=data;
+ sei(); // enable global int
+ UCSR0B |= (1<>>>>>> refs/remotes/pascallanger/master
}
static uint32_t random_value(void)
{
+<<<<<<< HEAD
+ #include
+ UBRR0H = UBRRH_VALUE;
+ UBRR0L = UBRRL_VALUE;
+ UCSR0A = 0 ; // Clear X2 bit
+ //Set frame format to 8 data bits, even parity, 2 stop bits
+ UCSR0C = (1<>>>>>> refs/remotes/pascallanger/master
}
#endif
+#if defined(TELEMETRY)
+static void PPM_Telemetry_serial_init()
+{
+ //9600 bauds
+ UBRR0H = 0x00;
+ UBRR0L = 0x67;
+ UCSR0A = 0 ; // Clear X2 bit
+ //Set frame format to 8 data bits, none, 1 stop bit
+ UCSR0C = (1<> 24) & 0xFF;
+ rx_tx_addr[1] = (id >> 16) & 0xFF;
+ rx_tx_addr[2] = (id >> 8) & 0xFF;
+ rx_tx_addr[3] = (id >> 0) & 0xFF;
+ rx_tx_addr[4] = 0xC1; // for YD717: always uses first data port
+}
+
static uint32_t random_id(uint16_t adress, uint8_t create_new)
{
uint32_t id;
@@ -928,6 +1479,13 @@ static uint32_t random_id(uint16_t adress, uint8_t create_new)
/**************************/
//PPM
+<<<<<<< HEAD
+ISR(INT1_vect)
+{ // Interrupt on PPM pin
+ static int8_t chan=-1;
+ static uint16_t Prev_TCNT1=0;
+ uint16_t Cur_TCNT1;
+=======
#ifdef ENABLE_PPM
#ifdef XMEGA
#if PPM_pin == 2
@@ -946,6 +1504,7 @@ static uint32_t random_id(uint16_t adress, uint8_t create_new)
static int8_t chan=-1;
static uint16_t Prev_TCNT1=0;
uint16_t Cur_TCNT1;
+>>>>>>> refs/remotes/pascallanger/master
Cur_TCNT1 = TCNT1 - Prev_TCNT1 ; // Capture current Timer1 value
if(Cur_TCNT1<1000)
@@ -956,6 +1515,19 @@ static uint32_t random_id(uint16_t adress, uint8_t create_new)
chan=0; // start of frame
PPM_FLAG_on; // full frame present (even at startup since PPM_data has been initialized)
}
+<<<<<<< HEAD
+ Prev_TCNT1+=Cur_TCNT1;
+}
+
+//Serial RX
+ISR(USART_RX_vect)
+{ // RX interrupt
+ if((UCSR0A&0x1C)==0) // Check frame error, data overrun and parity error
+ { // received byte is ok to process
+ if(idx==0)
+ { // Let's try to sync at this point
+ if(UDR0==0x55) // If 1st byte is 0x55 it looks ok
+=======
else
if(chan!=-1) // need to wait for start of frame
{ //servo values between 500us and 2420us will end up here
@@ -1000,6 +1572,7 @@ static uint32_t random_id(uint16_t adress, uint8_t create_new)
}
}
else
+>>>>>>> refs/remotes/pascallanger/master
{
rx_buff[idx++]=UDR0; // Store received byte
if(idx>=RXBUFFER_SIZE)
@@ -1070,4 +1643,30 @@ static uint32_t random_id(uint16_t adress, uint8_t create_new)
WDTCSR = 0; // Disable Watchdog interrupt
}
}
+<<<<<<< HEAD
+}
+
+//Serial timer
+ISR(TIMER1_COMPB_vect)
+{ // Timer1 compare B interrupt
+ idx=0;
+}
+
+#if defined(TELEMETRY)
+//Serial TX
+ISR(USART_UDRE_vect)
+{ // Transmit interrupt
+ uint8_t t = tx_tail;
+ if(tx_head!=t)
+ {
+ if(++t>=TXBUFFER_SIZE)//head
+ t=0;
+ UDR0=tx_buff[t];
+ tx_tail=t;
+ }
+ if (t == tx_head)
+ UCSR0B &= ~(1<>>>>>> refs/remotes/pascallanger/master
#endif
diff --git a/Multiprotocol/NRF24l01_SPI.ino b/Multiprotocol/NRF24l01_SPI.ino
index 8627efa..dc740c5 100644
--- a/Multiprotocol/NRF24l01_SPI.ino
+++ b/Multiprotocol/NRF24l01_SPI.ino
@@ -234,7 +234,11 @@ uint8_t NRF24L01_packet_ack()
///////////////
// XN297 emulation layer
+<<<<<<< HEAD
+uint8_t xn297_scramble_enabled;
+=======
uint8_t xn297_scramble_enabled=XN297_SCRAMBLED; //enabled by default
+>>>>>>> refs/remotes/pascallanger/master
uint8_t xn297_addr_len;
uint8_t xn297_tx_addr[5];
uint8_t xn297_rx_addr[5];
@@ -247,6 +251,16 @@ static const uint8_t xn297_scramble[] = {
0x1b, 0x5d, 0x19, 0x10, 0x24, 0xd3, 0xdc, 0x3f,
0x8e, 0xc5, 0x2f};
+<<<<<<< HEAD
+const uint16_t PROGMEM xn297_crc_xorout[] = {
+ 0x0000, 0x3d5f, 0xa6f1, 0x3a23, 0xaa16, 0x1caf,
+ 0x62b2, 0xe0eb, 0x0821, 0xbe07, 0x5f1a, 0xaf15,
+ 0x4f0a, 0xad24, 0x5e48, 0xed34, 0x068c, 0xf2c9,
+ 0x1852, 0xdf36, 0x129d, 0xb17c, 0xd5f5, 0x70d7,
+ 0xb798, 0x5133, 0x67db, 0xd94e};
+
+=======
+>>>>>>> refs/remotes/pascallanger/master
const uint16_t PROGMEM xn297_crc_xorout_scrambled[] = {
0x0000, 0x3448, 0x9BA7, 0x8BBB, 0x85E1, 0x3E8C,
0x451E, 0x18E6, 0x6B24, 0xE7AB, 0x3828, 0x814B,
@@ -320,8 +334,14 @@ void XN297_SetRXAddr(const uint8_t* addr, uint8_t len)
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, buf, 5);
}
-void XN297_Configure(uint8_t flags)
+void XN297_Configure(uint16_t flags)
{
+<<<<<<< HEAD
+ xn297_scramble_enabled = !(flags & BV(XN297_UNSCRAMBLED));
+ xn297_crc = !!(flags & BV(NRF24L01_00_EN_CRC));
+ flags &= ~(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO));
+ NRF24L01_WriteReg(NRF24L01_00_CONFIG, flags & 0xFF);
+=======
xn297_crc = !!(flags & _BV(NRF24L01_00_EN_CRC));
flags &= ~(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO));
NRF24L01_WriteReg(NRF24L01_00_CONFIG, flags & 0xFF);
@@ -330,6 +350,7 @@ void XN297_Configure(uint8_t flags)
void XN297_SetScrambledMode(const u8 mode)
{
xn297_scramble_enabled = mode;
+>>>>>>> refs/remotes/pascallanger/master
}
void XN297_WritePayload(uint8_t* msg, uint8_t len)
@@ -391,6 +412,32 @@ void XN297_ReadPayload(uint8_t* msg, uint8_t len)
// End of XN297 emulation
///////////////
+<<<<<<< HEAD
+// 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;
+=======
// LT8900 emulation layer
uint8_t LT8900_buffer[64];
uint8_t LT8900_buffer_start;
@@ -415,23 +462,37 @@ void LT8900_Config(uint8_t preamble_len, uint8_t trailer_len, uint8_t flags, uin
LT8900_Preamble_Len=preamble_len;
//Trailer 4 to 18 bits
LT8900_Tailer_Len=trailer_len;
+>>>>>>> refs/remotes/pascallanger/master
//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
+<<<<<<< HEAD
+ LT8910_Flags=flags;
+ //CRC init constant
+ LT8910_CRC_Initial_Data=crc_init;
+}
+
+void LT8910_SetChannel(uint8_t channel)
+=======
LT8900_Flags=flags;
//CRC init constant
LT8900_CRC_Initial_Data=crc_init;
}
void LT8900_SetChannel(uint8_t channel)
+>>>>>>> refs/remotes/pascallanger/master
{
NRF24L01_WriteReg(NRF24L01_05_RF_CH, channel +2); //NRF24L01 is 2400+channel but LT8900 is 2402+channel
}
+<<<<<<< HEAD
+void LT8910_SetTxRxMode(enum TXRX_State mode)
+=======
void LT8900_SetTxRxMode(enum TXRX_State mode)
+>>>>>>> refs/remotes/pascallanger/master
{
if(mode == TX_EN)
{
@@ -457,12 +518,35 @@ void LT8900_SetTxRxMode(enum TXRX_State mode)
NRF24L01_SetTxRxMode(TXRX_OFF);
}
+<<<<<<< HEAD
+void LT8910_BuildOverhead()
+=======
void LT8900_BuildOverhead()
+>>>>>>> refs/remotes/pascallanger/master
{
uint8_t pos;
//Build overhead
//preamble
+<<<<<<< HEAD
+ 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)
+=======
memset(LT8900_buffer,LT8900_addr[0]&0x01?0xAA:0x55,LT8900_Preamble_Len-1);
pos=LT8900_Preamble_Len-1;
//address
@@ -480,10 +564,33 @@ void LT8900_BuildOverhead()
}
void LT8900_SetAddress(uint8_t *address,uint8_t addr_size)
+>>>>>>> refs/remotes/pascallanger/master
{
uint8_t addr[5];
//Address size (SyncWord) 2 to 8 bytes, 16/32/48/64 bits
+<<<<<<< HEAD
+ 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>>>>>> refs/remotes/pascallanger/master
//Read payload
NRF24L01_ReadPayload(buffer,end+1);
//Check address + trail
for(i=0;i>>>>>> refs/remotes/pascallanger/master
for(i=pos;i>8)&0xFF;
}
//Check len
+<<<<<<< HEAD
+ if(LT8910_Flags&_BV(LT8910_PACKET_LENGTH_EN))
+=======
if(LT8900_Flags&_BV(LT8900_PACKET_LENGTH_EN))
+>>>>>>> refs/remotes/pascallanger/master
{
crc=crc16_update(crc,buffer[pos]);
if(bit_reverse(len)!=buffer[pos++])
@@ -533,7 +652,11 @@ uint8_t LT8900_ReadPayload(uint8_t* msg, uint8_t len)
msg[i]=bit_reverse(buffer[pos++]);
}
//Check CRC
+<<<<<<< HEAD
+ if(LT8910_Flags&_BV(LT8910_CRC_ON))
+=======
if(LT8900_Flags&_BV(LT8900_CRC_ON))
+>>>>>>> refs/remotes/pascallanger/master
{
if(buffer[pos++]!=((crc>>8)&0xFF)) return 0; // wrong CRC...
if(buffer[pos]!=(crc&0xFF)) return 0; // wrong CRC...
@@ -542,12 +665,21 @@ uint8_t LT8900_ReadPayload(uint8_t* msg, uint8_t len)
return 1;
}
+<<<<<<< HEAD
+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))
+=======
void LT8900_WritePayload(uint8_t* msg, uint8_t len)
{
unsigned int crc=LT8900_CRC_Initial_Data,a,mask;
uint8_t i, pos=0,tmp, buffer[64], pos_final,shift;
//Add packet len
if(LT8900_Flags&_BV(LT8900_PACKET_LENGTH_EN))
+>>>>>>> refs/remotes/pascallanger/master
{
tmp=bit_reverse(len);
buffer[pos++]=tmp;
@@ -561,12 +693,27 @@ void LT8900_WritePayload(uint8_t* msg, uint8_t len)
crc=crc16_update(crc,tmp);
}
//Add CRC
+<<<<<<< HEAD
+ if(LT8910_Flags&_BV(LT8910_CRC_ON))
+=======
if(LT8900_Flags&_BV(LT8900_CRC_ON))
+>>>>>>> refs/remotes/pascallanger/master
{
buffer[pos++]=crc>>8;
buffer[pos++]=crc;
}
//Shift everything to fit behind the trailer (4 to 18 bits)
+<<<<<<< HEAD
+ 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;
+=======
shift=LT8900_buffer_overhead_bits&0x7;
pos_final=LT8900_buffer_overhead_bits/8;
mask=~(0xFF<<(8-shift));
@@ -576,10 +723,17 @@ void LT8900_WritePayload(uint8_t* msg, uint8_t len)
a=buffer[i]<<(8-shift);
LT8900_buffer[pos_final+i]=(LT8900_buffer[pos_final+i]&mask>>8)|a>>8;
LT8900_buffer[pos_final+i+1]=(LT8900_buffer[pos_final+i+1]&mask)|a;
+>>>>>>> refs/remotes/pascallanger/master
}
if(shift)
pos++;
//Send everything
+<<<<<<< HEAD
+ NRF24L01_WritePayload(LT8910_buffer+LT8910_buffer_start,pos_final+pos-LT8910_buffer_start);
+}
+// End of LT8910 emulation
+=======
NRF24L01_WritePayload(LT8900_buffer+LT8900_buffer_start,pos_final+pos-LT8900_buffer_start);
}
// End of LT8900 emulation
+>>>>>>> refs/remotes/pascallanger/master
diff --git a/Multiprotocol/Nrf24l01_bluefly.ino b/Multiprotocol/Nrf24l01_bluefly.ino
new file mode 100644
index 0000000..3a7f918
--- /dev/null
+++ b/Multiprotocol/Nrf24l01_bluefly.ino
@@ -0,0 +1,150 @@
+/*
+ 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
+
+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] = rx_tx_addr[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, rx_tx_addr, 5);
+ NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 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, rx_tx_addr, 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 (bind_phase>0) {
+ bind_phase--;
+ if (! bind_phase) { 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
+}
+
+static uint16_t BlueFly_setup() {
+ hopping_frequency_start = ((MProtocol_id >> 8) % 47) + 2;
+ bluefly_binding_packet();
+ bluefly_init();
+ if(IS_AUTOBIND_FLAG_on) { bind_phase = BIND_BlueFly_COUNT; } else { bind_phase = 0; }
+
+ return 1000;
+}
+#endif
diff --git a/Multiprotocol/Nrf24l01_cflie.ino b/Multiprotocol/Nrf24l01_cflie.ino
new file mode 100644
index 0000000..d4b0208
--- /dev/null
+++ b/Multiprotocol/Nrf24l01_cflie.ino
@@ -0,0 +1,318 @@
+/*
+ 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 .
+ */
+
+/* NB: Not implemented
+ Uncomment define below to enable telemetry. Also add CFlie protocol to TELEMETRY_SetTypeByProtocol to set type to DSM.
+#define CFLIE_TELEMETRY
+ */
+
+
+#if defined(CFlie_NRF24L01_INO)
+#include "iface_nrf24l01.h"
+
+#define BIND_COUNT 60
+
+// Address size
+#define TX_ADDR_SIZE 5
+
+// Timeout for callback in uSec, 10ms=10000us for Crazyflie
+#define PACKET_PERIOD 10000
+
+
+// For code readability
+enum {
+ CHANNEL1 = 0,
+ CHANNEL2,
+ CHANNEL3,
+ CHANNEL4,
+ CHANNEL5,
+ CHANNEL6,
+ CHANNEL7,
+ CHANNEL8,
+ CHANNEL9,
+ CHANNEL10
+};
+
+#define PAYLOADSIZE 8 // receive data pipes set to this size, but unused
+#define MAX_PACKET_SIZE 9 // YD717 packets have 8-byte payload, Syma X4 is 9
+
+//static uint8_t packet[MAX_PACKET_SIZE];
+
+static uint8_t data_rate, rf_channel;
+
+enum {
+ CFLIE_INIT_SEARCH = 0,
+ CFLIE_INIT_DATA,
+ CFLIE_SEARCH,
+ CFLIE_DATA
+};
+
+#ifdef CFLIE_TELEMETRY
+static const char * const cflie_opts[] = {
+ _tr_noop("Telemetry"), _tr_noop("Off"), _tr_noop("On"), NULL,
+ NULL
+};
+enum {
+ PROTOOPTS_TELEMETRY = 0,
+ LAST_PROTO_OPT,
+};
+ctassert(LAST_PROTO_OPT <= NUM_PROTO_OPTS, too_many_protocol_opts);
+
+#define TELEM_OFF 0
+#define TELEM_ON 1
+#endif
+
+#define PACKET_CHKTIME 500 // time to wait if packet not yet acknowledged or timed out
+
+static uint16_t dbg_cnt = 0;
+static uint8_t packet_ack() {
+ if (++dbg_cnt > 50) { dbg_cnt = 0; }
+ 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 set_rate_channel(uint8_t rate, uint8_t channel) {
+ NRF24L01_WriteReg(NRF24L01_05_RF_CH, channel); // Defined by model id
+ NRF24L01_SetBitrate(rate); // Defined by model id
+}
+
+static void send_search_packet() {
+ uint8_t buf[1];
+ buf[0] = 0xff;
+ // clear packet status bits and TX FIFO
+ NRF24L01_WriteReg(NRF24L01_07_STATUS, (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT)));
+ NRF24L01_FlushTx();
+
+ if (rf_channel++ > 125) {
+ rf_channel = 0;
+ switch(data_rate) {
+ case NRF24L01_BR_250K:
+ data_rate = NRF24L01_BR_1M;
+ break;
+ case NRF24L01_BR_1M:
+ data_rate = NRF24L01_BR_2M;
+ break;
+ case NRF24L01_BR_2M:
+ data_rate = NRF24L01_BR_250K;
+ break;
+ }
+ }
+
+ set_rate_channel(data_rate, rf_channel);
+
+ NRF24L01_WritePayload(buf, sizeof(buf));
+
+ ++packet_counter;
+}
+
+// Frac 16.16
+#define FRAC_MANTISSA 16
+#define FRAC_SCALE (1 << FRAC_MANTISSA)
+
+// Convert fractional 16.16 to float32
+static void frac2float(uint32_t n, float* res) {
+ if (n == 0) {
+ *res = 0.0;
+ return;
+ }
+ uint32_t m = n < 0 ? -n : n;
+ int i;
+ for (i = (31-FRAC_MANTISSA); (m & 0x80000000) == 0; i--, m <<= 1) ;
+ m <<= 1; // Clear implicit leftmost 1
+ m >>= 9;
+ uint32_t e = 127 + i;
+ if (n < 0) m |= 0x80000000;
+ m |= e << 23;
+ *((uint32_t *) res) = m;
+}
+
+static void send_cmd_packet() {
+ // Commander packet, 15 bytes
+ uint8_t buf[15];
+ float x_roll, x_pitch, yaw;
+
+ // Channels in AETR order
+
+ // Roll, aka aileron, float +- 50.0 in degrees
+ // float roll = -(float) Servo_data[AILERON]*50.0/10000;
+ uint32_t f_roll = -Servo_data[AILERON] * FRAC_SCALE / (10000 / 50);
+
+ // Pitch, aka elevator, float +- 50.0 degrees
+ //float pitch = -(float) Servo_data[ELEVATOR]*50.0/10000;
+ uint32_t f_pitch = -Servo_data[ELEVATOR] * FRAC_SCALE / (10000 / 50);
+
+ // Thrust, aka throttle 0..65535, working range 5535..65535
+ // No space for overshoot here, hard limit Channel3 by -10000..10000
+ uint32_t ch = Servo_data[THROTTLE];
+ if (ch < PPM_MIN) {
+ ch = PPM_MIN;
+ } else if (ch > PPM_MAX) {
+ ch = PPM_MAX;
+ }
+ uint16_t thrust = ch*3L + 35535L;
+
+ // Yaw, aka rudder, float +- 400.0 deg/s
+ // float yaw = -(float) Servo_data[RUDDER]*400.0/10000;
+ uint32_t f_yaw = - Servo_data[RUDDER] * FRAC_SCALE / (10000 / 400);
+ frac2float(f_yaw, &yaw);
+
+ // Convert + to X. 181 / 256 = 0.70703125 ~= sqrt(2) / 2
+ uint32_t f_x_roll = (f_roll + f_pitch) * 181 / 256;
+ frac2float(f_x_roll, &x_roll);
+ uint32_t f_x_pitch = (f_pitch - f_roll) * 181 / 256;
+ frac2float(f_x_pitch, &x_pitch);
+
+ int bufptr = 0;
+ buf[bufptr++] = 0x30; // Commander packet to channel 0
+ memcpy(&buf[bufptr], (char*) &x_roll, 4); bufptr += 4;
+ memcpy(&buf[bufptr], (char*) &x_pitch, 4); bufptr += 4;
+ memcpy(&buf[bufptr], (char*) &yaw, 4); bufptr += 4;
+ memcpy(&buf[bufptr], (char*) &thrust, 2); bufptr += 2;
+
+
+ // clear packet status bits and TX FIFO
+ NRF24L01_WriteReg(NRF24L01_07_STATUS, (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT)));
+ NRF24L01_FlushTx();
+
+ NRF24L01_WritePayload(buf, sizeof(buf));
+
+ ++packet_counter;
+
+ NRF24L01_SetPower();
+}
+
+static int cflie_init() {
+ NRF24L01_Initialize();
+
+ // CRC, radio on
+ NRF24L01_SetTxRxMode(TX_EN);
+ NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP));
+ // NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgement
+ NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x01); // Auto Acknowledgement for data pipe 0
+ NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0
+ NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, TX_ADDR_SIZE-2); // 5-byte RX/TX address
+ NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x13); // 3 retransmits, 500us delay
+
+ NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_channel); // Defined by model id
+ NRF24L01_SetBitrate(data_rate); // Defined by model id
+
+ NRF24L01_SetPower();
+ NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
+
+ NRF24L01_WriteReg(NRF24L01_17_FIFO_STATUS, 0x00); // Just in case, no real bits to write here
+
+ // this sequence necessary for module from stock tx
+ NRF24L01_ReadReg(NRF24L01_1D_FEATURE);
+ NRF24L01_Activate(0x73); // Activate feature register
+ NRF24L01_ReadReg(NRF24L01_1D_FEATURE);
+
+ NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x01); // Enable Dynamic Payload Length on pipe 0
+ NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x06); // Enable Dynamic Payload Length, enable Payload with ACK
+
+
+ // NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, TX_ADDR_SIZE);
+ NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, TX_ADDR_SIZE);
+
+ NRF24L01_Activate(0x53); // switch bank back
+
+ // 50ms delay in callback
+ return 50000;
+}
+
+
+#ifdef CFLIE_TELEMETRY
+static void update_telemetry() {
+ static uint8_t frameloss = 0;
+
+ frameloss += NRF24L01_ReadReg(NRF24L01_08_OBSERVE_TX) >> 4;
+ NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_channel); // reset packet loss counter
+
+ Telemetry.p.dsm.flog.frameloss = frameloss;
+// Telemetry.p.dsm.flog.volt[0] = read battery voltage from ack payload
+ TELEMETRY_SetUpdated(TELEM_DSM_FLOG_FRAMELOSS);
+}
+#endif
+
+
+static uint16_t cflie_callback() {
+ switch (phase) {
+ case CFLIE_INIT_SEARCH:
+ send_search_packet();
+ phase = CFLIE_SEARCH;
+ break;
+ case CFLIE_INIT_DATA:
+ send_cmd_packet();
+ phase = CFLIE_DATA;
+ break;
+ case CFLIE_SEARCH:
+ switch (packet_ack()) {
+ case PKT_PENDING:
+ return PACKET_CHKTIME; // packet send not yet complete
+ case PKT_ACKED:
+ phase = CFLIE_DATA;
+ BIND_DONE;
+ break;
+ case PKT_TIMEOUT:
+ send_search_packet();
+ counter = BIND_COUNT;
+ }
+ break;
+ case CFLIE_DATA:
+ #ifdef CFLIE_TELEMETRY
+ update_telemetry();
+ #endif
+ if (packet_ack() == PKT_PENDING)
+ return PACKET_CHKTIME; // packet send not yet complete
+ send_cmd_packet();
+ break;
+ }
+ return PACKET_PERIOD; // Packet at standard protocol interval
+}
+
+
+// Generate address to use from TX id and manufacturer id (STM32 unique id)
+static uint8_t initialize_rx_tx_addr() {
+ rx_tx_addr[0] =
+ rx_tx_addr[1] =
+ rx_tx_addr[2] =
+ rx_tx_addr[3] =
+ rx_tx_addr[4] = 0xE7; // CFlie uses fixed address
+
+ data_rate = NRF24L01_BR_250K;
+ rf_channel = 0;
+ return CFLIE_INIT_SEARCH;
+ // return CFLIE_INIT_DATA;
+}
+
+static uint16_t Cflie_setup() {
+ phase = initialize_rx_tx_addr();
+ packet_counter = 0;
+
+ int delay = cflie_init();
+
+ #ifdef CFLIE_TELEMETRY
+ memset(&Telemetry, 0, sizeof(Telemetry));
+ TELEMETRY_SetType(TELEM_DSM);
+ #endif
+ if (phase == CFLIE_INIT_SEARCH) { BIND_IN_PROGRESS; }
+ return delay;
+}
+
+#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_fbl100.ino b/Multiprotocol/Nrf24l01_fbl100.ino
new file mode 100644
index 0000000..f25e368
--- /dev/null
+++ b/Multiprotocol/Nrf24l01_fbl100.ino
@@ -0,0 +1,282 @@
+/*
+ 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 .
+
+ rewrite v977/v966 protocol to improve reliability
+ */
+
+#if defined(FBL100_NRF24L01_INO)
+#include "iface_nrf24l01.h"
+
+#define BIND_FBL_COUNT 800
+#define FBL_SIZE 5
+#define FREQUENCE_FBL_NUM 20
+
+static uint8_t binding_fbl_adr_rf[5]; // fixed binding ids for all planes
+
+static uint8_t bind_fbl_buf_array[4][10];
+
+static unsigned int fbl_data[8];
+
+
+// HiSky protocol uses TX id as an address for nRF24L01, and uses frequency hopping sequence
+// which does not depend on this id and is passed explicitly in binding sequence. So we are free
+// to generate this sequence as we wish. It should be in the range [02..77]
+static void calc_fbl_channels() {
+ int idx = 0;
+ uint32_t rnd = MProtocol_id;
+ while (idx < FREQUENCE_FBL_NUM) {
+ int i;
+ int count_2_26 = 0, count_27_50 = 0, count_51_74 = 0;
+ rnd = rnd * 0x0019660D + 0x3C6EF35F; // Randomization
+
+ // Use least-significant byte. 73 is prime, so channels 76..77 are unused
+ uint8_t next_ch = ((rnd >> 8) % 73) + 2;
+ // Keep the distance 2 between the channels - either odd or even
+ if (((next_ch ^ MProtocol_id) & 0x01 )== 0) { continue; }
+ // Check that it's not duplicate and spread uniformly
+ for (i = 0; i < idx; i++) {
+ if(hopping_frequency[i] == next_ch) { break; }
+ if(hopping_frequency[i] <= 26) { count_2_26++; }
+ else if (hopping_frequency[i] <= 50) { count_27_50++; }
+ else { count_51_74++; }
+ }
+ if (i != idx) { continue; }
+ if ((next_ch <= 26 && count_2_26 < 8) ||(next_ch >= 27 && next_ch <= 50 && count_27_50 < 8) ||(next_ch >= 51 && count_51_74 < 8)) {
+ hopping_frequency[idx++] = next_ch;
+ }
+ }
+}
+
+static void fbl100_build_binding_packet(void) {
+ uint8_t i;
+ unsigned int sum;
+ uint8_t sum_l,sum_h;
+
+ sum = 0;
+ for(i=0;i<5;i++) { sum += rx_tx_addr[i]; }
+ sum_l = (uint8_t)sum;
+ sum >>= 8;
+ sum_h = (uint8_t)sum;
+ bind_fbl_buf_array[0][0] = 0xff;
+ bind_fbl_buf_array[0][1] = 0xaa;
+ bind_fbl_buf_array[0][2] = 0x55;
+ for(i=3;i<8;i++) { bind_fbl_buf_array[0][i] = rx_tx_addr[i-3]; }
+
+ for(i=1;i<4;i++) {
+ bind_fbl_buf_array[i][0] = sum_l;
+ bind_fbl_buf_array[i][1] = sum_h;
+ bind_fbl_buf_array[i][2] = i-1;
+ }
+ for(i=0;i<7;i++) { bind_fbl_buf_array[1][i+3] = hopping_frequency[i]; }
+ for(i=0;i<7;i++) { bind_fbl_buf_array[2][i+3] = hopping_frequency[i+7]; }
+ for(i=0;i<6;i++) { bind_fbl_buf_array[3][i+3] = hopping_frequency[i+14]; }
+
+ binding_idx = 0;
+}
+
+static void hp100_build_binding_packet(void) {
+ memcpy(packet, rx_tx_addr, 5);
+ packet[5] = hopping_frequency[0]; // start address
+ for (uint8_t i = 6; i < 12; i++) { packet[i] = 0x55; }
+}
+
+static void config_nrf24l01() {
+ NRF24L01_Initialize();
+
+ NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable p0 rx
+ NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // 0:No Auto Acknoledgement; 1:Auto Acknoledgement
+ NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, packet_length); // fbl100/v922's packet size = 10, hp100 = 12
+ // 2-bytes CRC, radio off
+ 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(sub_protocol == HP100? NRF24L01_BR_250K:NRF24L01_BR_1M); //hp100:250kbps; fbl100: 1Mbps
+ NRF24L01_SetPower();
+
+ NRF24L01_FlushTx();
+ NRF24L01_FlushRx();
+ NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
+}
+
+// FBL100 channel sequence: AILE ELEV THRO RUDD GEAR PITH, channel data value is from 0 to 1000
+static void fbl100_build_ch_data() {
+ uint32_t temp;
+ uint8_t i;
+ for (i = 0; i< 8; i++) {
+ temp = (uint32_t)Servo_data[i] * 500/PPM_MAX + 500;
+ if (i == 2) { temp = 1000 -temp; } // It is clear that fbl100's thro stick is made reversely,so I adjust it here on purposely
+ if (temp < 0) { fbl_data[i] = 0; }
+ else if (temp > 1000) { fbl_data[i] = 1000; }
+ else { fbl_data[i] = (unsigned int)temp; }
+ packet[i] = (uint8_t)fbl_data[i];
+ }
+
+ packet[8] = (uint8_t)((fbl_data[0]>>8)&0x0003);
+ packet[8] |= (uint8_t)((fbl_data[1]>>6)&0x000c);
+ packet[8] |= (uint8_t)((fbl_data[2]>>4)&0x0030);
+ packet[8] |= (uint8_t)((fbl_data[3]>>2)&0x00c0);
+
+ packet[9] = (uint8_t)((fbl_data[4]>>8)&0x0003);
+ packet[9] |= (uint8_t)((fbl_data[5]>>6)&0x000c);
+ packet[9] |= (uint8_t)((fbl_data[6]>>4)&0x0030);
+ packet[9] |= (uint8_t)((fbl_data[7]>>2)&0x00c0);
+}
+
+static void hp100_build_ch_data() {
+ uint32_t temp;
+ uint8_t i;
+ for (i = 0; i< 8; i++) {
+ temp = (uint32_t)Servo_data[i] * 300/PPM_MAX + 500;
+ if (temp < 0) { temp = 0; }
+ else if (temp > 1000) { temp = 1000; }
+ if (i == 3 || i == 5) { temp = 1000 -temp; } // hp100's rudd and pit channel are made reversely,so I adjust them on purposely
+
+ fbl_data[i] = (unsigned int)temp;
+ packet[i] = (uint8_t)fbl_data[i];
+ }
+
+ packet[8] = (uint8_t)((fbl_data[0]>>8)&0x0003);
+ packet[8] |= (uint8_t)((fbl_data[1]>>6)&0x000c);
+ packet[8] |= (uint8_t)((fbl_data[2]>>4)&0x0030);
+ packet[8] |= (uint8_t)((fbl_data[3]>>2)&0x00c0);
+
+ packet[9] = (uint8_t)((fbl_data[4]>>8)&0x0003);
+ packet[9] |= (uint8_t)((fbl_data[5]>>6)&0x000c);
+ packet[9] |= (uint8_t)((fbl_data[6]>>4)&0x0030);
+ packet[9] |= (uint8_t)((fbl_data[7]>>2)&0x00c0);
+
+ unsigned char l, h, t;
+ l=h=0xff;
+ for(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;
+ }
+ packet[10] = h;
+ packet[11] = l;
+}
+
+
+static uint16_t fbl100_cb() {
+ switch(phase) {
+ case 0:
+ fbl100_build_ch_data();
+ break;
+ case 1:
+ NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
+ NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
+ hopping_frequency_no++;
+ if (hopping_frequency_no >= FREQUENCE_FBL_NUM) { hopping_frequency_no = 0; }
+ break;
+ case 2:
+ NRF24L01_FlushTx();
+ NRF24L01_WritePayload(packet, packet_length);
+ break;
+ case 3:
+ break;
+ case 4:
+ if (bind_phase>0) {
+ NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, binding_fbl_adr_rf, 5);
+ NRF24L01_WriteReg(NRF24L01_05_RF_CH, 81);
+ }
+ break;
+ case 5:
+ if (bind_phase >0) {
+ bind_phase--;
+ if (! bind_phase) { BIND_DONE; } // binding finished, change tx add
+ NRF24L01_FlushTx(); // must be invoked before NRF24L01_WritePayload()
+ NRF24L01_WritePayload(bind_fbl_buf_array[binding_idx], packet_length);
+ binding_idx++;
+ if (binding_idx >= 4)
+ binding_idx = 0;
+ }
+ break;
+ case 6:
+ break;
+ case 7:
+ NRF24L01_SetPower();
+ break;
+ default:
+ break;
+ }
+ phase++;
+ if (phase >=9) { phase = 0; } // send 1 binding packet and 1 data packet per 9ms
+ return 1000;
+}
+
+static uint16_t hp100_cb() {
+ switch(phase) {
+ case 0:
+ hp100_build_ch_data();
+ break;
+ case 1:
+ NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
+ NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[0] + hopping_frequency_no*2);
+ hopping_frequency_no++;
+ hopping_frequency_no %= 15;
+ NRF24L01_FlushTx();
+ NRF24L01_WritePayload(packet, packet_length);
+ break;
+ case 2:
+ if(bind_phase>0) { hp100_build_binding_packet(); }
+ break;
+ case 3:
+ if (bind_phase>0) {
+ bind_phase--;
+ if (! bind_phase) { BIND_DONE; }
+ NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, binding_fbl_adr_rf, 5);
+ NRF24L01_WriteReg(NRF24L01_05_RF_CH, 81);
+ NRF24L01_FlushTx();
+ NRF24L01_WritePayload(packet, packet_length);
+ }
+ break;
+ case 4:
+ break;
+ case 5:
+ NRF24L01_SetPower();
+ break;
+ default:
+ break;
+ }
+ phase++;
+ if (phase >= 6) { phase = 0; } // send 1 binding packet and 1 data packet per 10ms
+ return 1000;
+}
+
+static uint8_t fbl_setup() {
+ calc_fbl_channels();
+
+ printf("FH Seq: ");
+ for (int i = 0; i < FREQUENCE_FBL_NUM; ++i) { printf("%d, ", hopping_frequency[i]); }
+ printf("\r\n");
+
+ // debut init
+ if (sub_protocol == HP100) {
+ packet_length = 12;
+ binding_fbl_adr_rf[0] = 0x32; binding_fbl_adr_rf[1] = 0xaa; binding_fbl_adr_rf[2] = 0x45;
+ binding_fbl_adr_rf[3] = 0x45; binding_fbl_adr_rf[4] = 0x78;
+ } else {
+ packet_length = 10;
+ binding_fbl_adr_rf[0] = 0x12; binding_fbl_adr_rf[1] = 0x23; binding_fbl_adr_rf[2] = 0x23;
+ binding_fbl_adr_rf[3] = 0x45; binding_fbl_adr_rf[4] = 0x78;
+ fbl100_build_binding_packet();
+ }
+ config_nrf24l01();
+
+ if(IS_AUTOBIND_FLAG_on) { bind_phase = BIND_FBL_COUNT; }
+ else { bind_phase = 0; }
+
+// CLOCK_StartTimer(1000, sub_protocol == HP100?hp100_cb:fbl100_cb);
+}
+#endif
\ No newline at end of file
diff --git a/Multiprotocol/Nrf24l01_h377.ino b/Multiprotocol/Nrf24l01_h377.ino
new file mode 100644
index 0000000..439178d
--- /dev/null
+++ b/Multiprotocol/Nrf24l01_h377.ino
@@ -0,0 +1,210 @@
+/*
+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 (H377_NRF24L01_INO)
+#include "iface_nrf24l01.h"
+
+#define BIND_COUNT 800
+
+
+#define TXID_H377_SIZE 5
+
+#define FREQUENCE_NUM_H377 20
+#define SET_NUM_H377 9
+// available frequency must be in between 2402 and 2477
+
+static uint8_t binding_ch=0x50;
+static uint8_t hopping_frequency_data[SET_NUM_H377] = {0x1c,0x1b,0x1d,0x11,0x0e,0x0d,0x01,0x1d,0x15};
+
+static const uint8_t binding_adr_rf[5]={0x32,0xaa,0x45,0x45,0x78};
+
+static uint8_t rf_adr_buf[5];
+static uint8_t rf_adr_buf_data[SET_NUM_H377][5] = {
+ {0xad,0x9a,0xa6,0x69,0xb2},//ansheng
+ {0x92,0x9a,0x9d,0x69,0x99},//dc59
+ {0x92,0xb2,0x9d,0x69,0x9a},//small two
+ {0xad,0x9a,0x5a,0x69,0x96},//james_1
+ {0x95,0x9a,0x52,0x69,0x99},//james_2
+ {0x52,0x52,0x52,0x69,0xb9},//james_3
+ {0x52,0x52,0x52,0x52,0x55},//small two_1
+ {0x92,0xB2,0x9D,0x69,0x9A},//small two_2
+ {0x96,0x9A,0x45,0x69,0xB2}//small two_3
+};
+
+static uint8_t bind_buf_array[10];
+static uint8_t bind_buf_array_data[SET_NUM_H377][4] = {
+ {0xcf,0x1c,0x19,0x1a},
+ {0xff,0x48,0x19,0x19},
+ {0xf3,0x4d,0x19,0x19},
+ {0x9e,0x1f,0x19,0x19},
+ {0x8d,0x3d,0x19,0x19},
+ {0xbd,0x23,0x19,0x19},
+ {0xF3,0x28,0x19,0x19},
+ {0xF3,0x4D,0x19,0x19},
+ {0x82,0x8D,0x19,0x19}
+};
+
+
+static unsigned int ch_data[8];
+static uint8_t payload[10];
+static uint8_t counter1ms;
+
+static int select_ch_id = 0;
+
+static void h377_binding_packet(void) { //bind_buf_array
+ uint8_t i;
+ counter1ms = 0;
+ hopping_frequency_no = 0;
+
+ for(i=0;i<5;i++)
+ bind_buf_array[i] = rf_adr_buf[i];
+
+ bind_buf_array[5] = hopping_frequency[0];
+
+ for(i=0;i<4;i++)
+ bind_buf_array[i+6] = bind_buf_array_data[select_ch_id][i];
+}
+
+static void h377_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, rf_adr_buf, 5);
+ NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rf_adr_buf, 5);
+ NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 10); // payload size = 10
+ //NRF24L01_WriteReg(NRF24L01_05_RF_CH, 81); // binding packet must be set in channel 81
+ NRF24L01_WriteReg(NRF24L01_05_RF_CH, binding_ch); // binding packet must be set in channel 81
+
+ // 2-bytes CRC, radio off
+ NRF24L01_SetTxRxMode(TX_EN);
+ 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(0); // 1Mbps
+ NRF24L01_SetPower();
+ NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
+}
+
+// H377 channel sequence: AILE ELEV THRO RUDD GEAR PITH, channel data value is from 0 to 1000
+static void h377_ch_data() {
+ uint32_t temp;
+ uint8_t i;
+ for (i = 0; i< 8; i++) {
+ temp = (uint32_t)Servo_data[i] * 450/PPM_MAX + 500; // max/min servo range is +-125%
+ if (i == 2) // It is clear that h377's thro stick is made reversely, so I adjust it here on purpose
+ temp = 1000 -temp;
+ //if (i == 0) // It is clear that h377's thro stick is made reversely, so I adjust it here on purpose
+ // temp = 1000 -temp;
+ //if (i == 1) // It is clear that h377's thro stick is made reversely, so I adjust it here on purpose
+ // temp = 1000 -temp;
+ if (temp < 0)
+ ch_data[i] = 0;
+ else if (temp > 1000)
+ ch_data[i] = 1000;
+ else
+ ch_data[i] = (unsigned int)temp;
+ payload[i] = (uint8_t)ch_data[i];
+ }
+ payload[8] = (uint8_t)((ch_data[0]>>8)&0x0003);
+ payload[8] |= (uint8_t)((ch_data[1]>>6)&0x000c);
+ payload[8] |= (uint8_t)((ch_data[2]>>4)&0x0030);
+ payload[8] |= (uint8_t)((ch_data[3]>>2)&0x00c0);
+
+ payload[9] = (uint8_t)((ch_data[4]>>8)&0x0003);
+ payload[9] |= (uint8_t)((ch_data[5]>>6)&0x000c);
+ payload[9] |= (uint8_t)((ch_data[6]>>4)&0x0030);
+ payload[9] |= (uint8_t)((ch_data[7]>>2)&0x00c0);
+}
+
+static uint16_t h377_cb() {
+ counter1ms++;
+ if(counter1ms==1) { NRF24L01_FlushTx(); }
+ //-------------------------
+ else if(counter1ms==2) {
+ if (bind_phase>0) {
+ NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)binding_adr_rf, 5);
+ NRF24L01_WriteReg(NRF24L01_05_RF_CH, binding_ch);
+ }
+ }
+ else if(counter1ms==3) {
+ if (bind_phase >0) {
+ bind_phase--;
+ if (! bind_phase) { BIND_DONE; } // binding finished, change tx add
+ NRF24L01_WritePayload(bind_buf_array,10);
+ }
+ }
+ else if (counter1ms==4) { if (bind_phase > 0) { NRF24L01_FlushTx(); }}
+ //-------------------------
+ else if(counter1ms==5) { NRF24L01_SetPower(); }
+ //-------------------------
+ else if (counter1ms == 6) {
+ NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rf_adr_buf, 5);
+ NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
+ hopping_frequency_no++;
+ if (hopping_frequency_no >= FREQUENCE_NUM_H377) { hopping_frequency_no = 0; }
+ }
+ else if (counter1ms == 7) { h377_ch_data(); }
+ else if(counter1ms>8) {
+ counter1ms = 0;
+ NRF24L01_WritePayload(payload,10);
+ }
+ return 1000; // send 1 binding packet and 1 data packet per 9ms
+}
+
+// Linear feedback shift register with 32-bit Xilinx polinomial x^32 + x^22 + x^2 + x + 1
+static const uint32_t LFSR_FEEDBACK = 0x80200003ul;
+static const uint32_t LFSR_INTAP = 32-1;
+
+static void update_lfsr(uint32_t *lfsr, uint8_t b) {
+ for (int i = 0; i < 8; ++i) {
+ *lfsr = (*lfsr >> 1) ^ ((-(*lfsr & 1u) & LFSR_FEEDBACK) ^ ~((uint32_t)(b & 1) << LFSR_INTAP));
+ b >>= 1;
+ }
+}
+
+// Generate internal id from TX id and manufacturer id (STM32 unique id)
+
+
+static void H377_tx_id() {
+ for(int i=0;i<5;i++)
+ rf_adr_buf[i] = rf_adr_buf_data[select_ch_id][i];
+
+ hopping_frequency[0] = hopping_frequency_data[select_ch_id];
+
+ for (int i = 1; i < FREQUENCE_NUM_H377; i++) {
+ hopping_frequency[i] = hopping_frequency[i-1] + 3;
+ }
+}
+
+
+
+static uint16_t h377_setup() {
+ select_ch_id = MProtocol_id_master%SET_NUM_H377;
+
+ H377_tx_id();//rf_adr_buf hopping_frequency
+
+ h377_binding_packet();//bind_buf_array (rf_adr_buf hopping_frequency)
+
+ h377_init();
+
+ if(IS_AUTOBIND_FLAG_on) {
+ bind_phase = BIND_COUNT;
+ BIND_IN_PROGRESS;
+ }
+ else { bind_phase = 0; }
+
+ return 1000;
+}
+#endif
diff --git a/Multiprotocol/Nrf24l01_hm830.ino b/Multiprotocol/Nrf24l01_hm830.ino
new file mode 100644
index 0000000..bb30d3a
--- /dev/null
+++ b/Multiprotocol/Nrf24l01_hm830.ino
@@ -0,0 +1,267 @@
+/*
+ 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 protocol is for the HM Hobby HM830 RC Paper Airplane
+ Protocol spec:
+ Channel data:
+ AA BB CC DD EE FF GG
+ AA : Throttle Min=0x00 max =0x64
+ BB :
+ bit 0,1,2: Left/Right magnitude, bit 5 Polarity (set = right)
+ bit 6: Accelerate
+ bit 7: Right button (also the ABC Button)
+ CC : bit 0 seems to be impacted by the Right button
+ DD
+ EE
+ FF : Trim (bit 0-5: Magnitude, bit 6 polarity (set = right)
+ GG : Checksum (CRC8 on bytes AA-FF), init = 0xa5, poly = 0x01
+*/
+
+#ifdef HM830_NRF24L01_INO
+
+#include "iface_nrf24l01.h"
+
+enum {
+ HM830_BIND1A = 0,
+ HM830_BIND2A,
+ HM830_BIND3A,
+ HM830_BIND4A,
+ HM830_BIND5A,
+ HM830_BIND6A,
+ HM830_BIND7A,
+ HM830_DATA1,
+ HM830_DATA2,
+ HM830_DATA3,
+ HM830_DATA4,
+ HM830_DATA5,
+ HM830_DATA6,
+ HM830_DATA7,
+ HM830_BIND1B = 0x80,
+ HM830_BIND2B,
+ HM830_BIND3B,
+ HM830_BIND4B,
+ HM830_BIND5B,
+ HM830_BIND6B,
+ HM830_BIND7B,
+};
+
+static uint8_t init_vals_hm830[][2] = {
+ {NRF24L01_17_FIFO_STATUS, 0x00},
+ {NRF24L01_16_RX_PW_P5, 0x07},
+ {NRF24L01_15_RX_PW_P4, 0x07},
+ {NRF24L01_14_RX_PW_P3, 0x07},
+ {NRF24L01_13_RX_PW_P2, 0x07},
+ {NRF24L01_12_RX_PW_P1, 0x07},
+ {NRF24L01_11_RX_PW_P0, 0x07},
+ {NRF24L01_0F_RX_ADDR_P5, 0xC6},
+ {NRF24L01_0E_RX_ADDR_P4, 0xC5},
+ {NRF24L01_0D_RX_ADDR_P3, 0xC4},
+ {NRF24L01_0C_RX_ADDR_P2, 0xC3},
+ {NRF24L01_09_CD, 0x00},
+ {NRF24L01_08_OBSERVE_TX, 0x00},
+ {NRF24L01_07_STATUS, 0x07},
+// {NRF24L01_06_RF_SETUP, 0x07},
+ {NRF24L01_05_RF_CH, 0x18},
+ {NRF24L01_04_SETUP_RETR, 0x3F},
+ {NRF24L01_03_SETUP_AW, 0x03},
+ {NRF24L01_02_EN_RXADDR, 0x3F},
+ {NRF24L01_01_EN_AA, 0x3F},
+ {NRF24L01_00_CONFIG, 0x0E},
+};
+
+static uint8_t count;
+static uint8_t rf_ch[] = {0x08, 0x35, 0x12, 0x3f, 0x1c, 0x49, 0x26};
+static uint8_t bind_addr[] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xc2};
+
+static uint8_t crc8(uint32_t result, uint8_t *data, int len) {
+ int polynomial = 0x01;
+ for(int i = 0; i < len; i++) {
+ result = result ^ data[i];
+ for(int j = 0; j < 8; j++) {
+ if(result & 0x80) { result = (result << 1) ^ polynomial; }
+ else { result = result << 1; }
+ }
+ }
+ return result & 0xff;
+}
+
+static void HM830_init() {
+ NRF24L01_Initialize();
+ for (uint32_t i = 0; i < sizeof(init_vals_hm830) / sizeof(init_vals_hm830[0]); i++) { NRF24L01_WriteReg(init_vals_hm830[i][0], init_vals_hm830[i][1]); }
+
+ NRF24L01_SetTxRxMode(TX_EN);
+ NRF24L01_SetBitrate(0);
+ NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, bind_addr, 5);
+ NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, bind_addr+1, 5);
+ NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, bind_addr, 5);
+ NRF24L01_Activate(0x73); //Enable FEATURE
+ NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07);
+ NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3F);
+ //NRF24L01_ReadReg(NRF24L01_07_STATUS) ==> 0x07
+
+ NRF24L01_Activate(0x53); // switch bank back
+
+ NRF24L01_FlushTx();
+ //NRF24L01_ReadReg(NRF24L01_07_STATUS) ==> 0x0e
+ NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x0e);
+ //NRF24L01_ReadReg(NRF24L01_00_CONFIG); ==> 0x0e
+ NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0e);
+ NRF24L01_ReadReg(NRF24L01_01_EN_AA); // No Auto Acknoledgement
+}
+
+static void build_bind_packet_hm830() {
+ for(int i = 0; i < 6; i++) { packet[i] = rx_tx_addr[i]; }
+ packet[6] = crc8(0xa5, packet, 6);
+}
+
+static void build_data_packet() {
+ uint8_t ail_sign = 0, trim_sign = 0;
+
+ throttle = (uint32_t)Servo_data[THROTTLE] * 50 / PPM_MAX + 50;
+ if (throttle < 0) { throttle = 0; }
+
+ aileron = (uint32_t)Servo_data[AILERON] * 8 / PPM_MAX;
+ if (aileron < 0) { aileron = -aileron; ail_sign = 1; }
+ if (aileron > 7) { aileron = 7; }
+
+ uint8_t turbo = (uint32_t)Servo_data[ELEVATOR] > 0 ? 1 : 0;
+
+ uint8_t trim = ((uint32_t)Servo_data[RUDDER] * 0x1f / PPM_MAX);
+ if (trim < 0) { trim = -trim; trim_sign = 1; }
+ if (trim > 0x1f) { trim = 0x1f; }
+
+ uint8_t rbutton = (uint32_t)Servo_data[4] > 0 ? 1 : 0;
+ packet[0] = throttle;
+ packet[1] = aileron;
+ if (ail_sign) { packet[1] |= 0x20; }
+ if (turbo) { packet[1] |= 0x40; }
+ if (rbutton) { packet[1] |= 0x80; }
+ packet[5] = trim;
+ if (trim_sign) { packet[5] |= 0x20;}
+ packet[6] = crc8(0xa5, packet, 6);
+}
+
+static void send_packet_hm830() {
+ NRF24L01_ReadReg(NRF24L01_17_FIFO_STATUS);
+ NRF24L01_WritePayload(packet, 7);
+}
+
+static uint16_t handle_binding() {
+ uint8_t status = NRF24L01_ReadReg(NRF24L01_07_STATUS);
+ if (status & 0x20) {
+ //Binding complete
+ phase = HM830_DATA1 + ((phase&0x7F)-HM830_BIND1A);
+ count = 0;
+ NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5);
+ NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, rx_tx_addr+1, 5);
+ NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
+ NRF24L01_FlushTx();
+ build_data_packet();
+ uint8_t rb = NRF24L01_ReadReg(NRF24L01_07_STATUS); //==> 0x0E
+ NRF24L01_WriteReg(NRF24L01_07_STATUS, rb);
+ rb = NRF24L01_ReadReg(NRF24L01_00_CONFIG); //==> 0x0E
+ NRF24L01_WriteReg(NRF24L01_00_CONFIG, rb);
+ send_packet_hm830();
+ return 14000;
+ }
+ switch (phase) {
+ case HM830_BIND1A:
+ //Look for a Rx that is already bound
+ NRF24L01_SetPower();
+ NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5);
+ NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, rx_tx_addr+1, 5);
+ NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
+ NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch[0]);
+ build_bind_packet_hm830();
+ break;
+ case HM830_BIND1B:
+ //Look for a Rx that is not yet bound
+ NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, bind_addr, 5);
+ NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, bind_addr+1, 5);
+ NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, bind_addr, 5);
+ NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch[0]);
+ break;
+ case HM830_BIND2A:
+ case HM830_BIND3A:
+ case HM830_BIND4A:
+ case HM830_BIND5A:
+ case HM830_BIND6A:
+ case HM830_BIND7A:
+ case HM830_BIND2B:
+ case HM830_BIND3B:
+ case HM830_BIND4B:
+ case HM830_BIND5B:
+ case HM830_BIND6B:
+ case HM830_BIND7B:
+ NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch[(phase&0x7F)-HM830_BIND1A]);
+ break;
+ }
+ NRF24L01_FlushTx();
+ uint8_t rb = NRF24L01_ReadReg(NRF24L01_07_STATUS); //==> 0x0E
+ NRF24L01_WriteReg(NRF24L01_07_STATUS, rb);
+ rb = NRF24L01_ReadReg(NRF24L01_00_CONFIG); //==> 0x0E
+ NRF24L01_WriteReg(NRF24L01_00_CONFIG, rb);
+ send_packet_hm830();
+ phase++;
+ if (phase == HM830_BIND7B+1) { phase = HM830_BIND1A; }
+ else if (phase == HM830_BIND7A+1) { phase = HM830_BIND1B; }
+ return 20000;
+}
+
+static uint16_t handle_data() {
+ uint8_t status = NRF24L01_ReadReg(NRF24L01_07_STATUS);
+ if (count <= 0 || !(status & 0x20)) {
+ if(count < 0 || ! (status & 0x20)) {
+ count = 0;
+ //We didn't get a response on this channel, try the next one
+ phase++;
+ if (phase-HM830_DATA1 > 6) { phase = HM830_DATA1; }
+
+ NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch[0]);
+ NRF24L01_FlushTx();
+ build_data_packet();
+ uint8_t rb = NRF24L01_ReadReg(NRF24L01_07_STATUS); //==> 0x0E
+ NRF24L01_WriteReg(NRF24L01_07_STATUS, rb);
+ rb = NRF24L01_ReadReg(NRF24L01_00_CONFIG); //==> 0x0E
+ NRF24L01_WriteReg(NRF24L01_00_CONFIG, rb);
+ send_packet_hm830();
+ return 14000;
+ }
+ }
+ build_data_packet();
+ count++;
+ if(count == 98) {
+ count = -1;
+ NRF24L01_SetPower();
+ }
+ uint8_t rb = NRF24L01_ReadReg(NRF24L01_07_STATUS); //==> 0x0E
+ NRF24L01_WriteReg(NRF24L01_07_STATUS, rb);
+ rb = NRF24L01_ReadReg(NRF24L01_00_CONFIG); //==> 0x0E
+ NRF24L01_WriteReg(NRF24L01_00_CONFIG, rb);
+ send_packet_hm830();
+ return 20000;
+}
+
+
+
+static uint16_t HM830_callback() {
+ if ((phase & 0x7F) < HM830_DATA1) { return handle_binding(); }
+ else { return handle_data(); }
+}
+
+
+static uint32_t HM830_setup(){
+ count = 0;
+ // initialize_tx_id
+
+ rx_tx_addr[4] = 0xee;
+ rx_tx_addr[5] = 0xc2;
+ HM830_init();
+ phase = HM830_BIND1A;
+
+ return 500;
+}
+#endif
\ No newline at end of file
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..598c15b
--- /dev/null
+++ b/Multiprotocol/Nrf24l01_ne260.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 .
+ */
+/* 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 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();
+ state = NE260_BINDTX;
+
+ return 10000;
+}
+#endif
diff --git a/Multiprotocol/Nrf24l01_udi.ino b/Multiprotocol/Nrf24l01_udi.ino
new file mode 100644
index 0000000..a8eac63
--- /dev/null
+++ b/Multiprotocol/Nrf24l01_udi.ino
@@ -0,0 +1,582 @@
+/*
+ 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;
+
+ // 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
index 2ffc2fc..b8ab94b 100644
--- a/Multiprotocol/SHENQI_nrf24l01.ino
+++ b/Multiprotocol/SHENQI_nrf24l01.ino
@@ -1,3 +1,5 @@
+<<<<<<< HEAD
+=======
/*
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
@@ -13,6 +15,7 @@
along with Multiprotocol. If not, see .
*/
+>>>>>>> refs/remotes/pascallanger/master
#if defined(SHENQI_NRF24L01_INO)
#include "iface_nrf24l01.h"
@@ -39,10 +42,17 @@ void SHENQI_init()
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5 bytes rx/tx address
+<<<<<<< HEAD
+ 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);
+=======
LT8900_Config(4, 8, _BV(LT8900_CRC_ON)|_BV(LT8900_PACKET_LENGTH_EN), 0xAA);
LT8900_SetChannel(2);
LT8900_SetAddress((uint8_t *)"\x9A\x9A\x9A\x9A",4);
LT8900_SetTxRxMode(RX_EN);
+>>>>>>> refs/remotes/pascallanger/master
}
void SHENQI_send_packet()
@@ -51,6 +61,16 @@ void SHENQI_send_packet()
if(packet_count==0)
{
uint8_t bind_addr[4];
+<<<<<<< HEAD
+ 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];
+=======
bind_addr[0]=rx_tx_addr[0];
bind_addr[1]=rx_tx_addr[1];
bind_addr[2]=0x9A;
@@ -59,24 +79,39 @@ void SHENQI_send_packet()
LT8900_SetChannel(2);
packet[1]=rx_tx_addr[2];
packet[2]=rx_tx_addr[3];
+>>>>>>> refs/remotes/pascallanger/master
packet_period=2508;
}
else
{
+<<<<<<< HEAD
+ 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);
+=======
LT8900_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[2]&0x0F);
LT8900_SetChannel(freq);
+>>>>>>> refs/remotes/pascallanger/master
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...)
+<<<<<<< HEAD
+ LT8910_WritePayload(packet,3);
+ while(NRF24L01_packet_ack()!=PKT_ACKED);
+ LT8910_WritePayload(packet,3);
+=======
LT8900_WritePayload(packet,3);
while(NRF24L01_packet_ack()!=PKT_ACKED);
LT8900_WritePayload(packet,3);
+>>>>>>> refs/remotes/pascallanger/master
packet_count++;
if(packet_count==7)
@@ -94,6 +129,16 @@ uint16_t SHENQI_callback()
SHENQI_send_packet();
else
{
+<<<<<<< HEAD
+ 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);
+=======
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
{
if(LT8900_ReadPayload(packet, 3))
@@ -102,6 +147,7 @@ uint16_t SHENQI_callback()
rx_tx_addr[0]=packet[1];
rx_tx_addr[1]=packet[2];
LT8900_SetTxRxMode(TX_EN);
+>>>>>>> refs/remotes/pascallanger/master
packet_period=14000;
}
NRF24L01_FlushRx();
@@ -116,7 +162,11 @@ uint16_t initSHENQI()
SHENQI_init();
hopping_frequency_no = 0;
packet_count=0;
+<<<<<<< HEAD
+ packet_period=100;
+=======
packet_period=500;
+>>>>>>> refs/remotes/pascallanger/master
return 1000;
}
diff --git a/Multiprotocol/Telemetry.ino b/Multiprotocol/Telemetry.ino
index e9590b7..ad5e419 100644
--- a/Multiprotocol/Telemetry.ino
+++ b/Multiprotocol/Telemetry.ino
@@ -1,3 +1,178 @@
+<<<<<<< HEAD
+//*************************************
+// FrSky Telemetry serial code *
+// By Midelic on RCGroups *
+//*************************************
+
+#if defined TELEMETRY
+ #if defined FRSKYX_CC2500_INO
+ #define SPORT_TELEMETRY
+ #endif
+ #if defined FRSKY_CC2500_INO
+ #define HUB_TELEMETRY
+ #endif
+ #if defined SPORT_TELEMETRY
+ #define SPORT_TELEMETRY
+ #define SPORT_TIME 12000
+ uint32_t last=0;
+ uint8_t sport_counter=0;
+ uint8_t RxBt=0;
+ uint8_t rssi;
+ uint8_t ADC2;
+ #endif
+ #if defined HUB_TELEMETRY
+ #define MAX_PKTX 10
+ uint8_t pktx[MAX_PKTX];
+ uint8_t index;
+ uint8_t prev_index;
+ uint8_t pass = 0;
+ #endif
+ #define USER_MAX_BYTES 6
+ uint8_t frame[18];
+
+ void frskySendStuffed()
+ {
+ Serial_write(0x7E);
+ for (uint8_t i = 0; i < 9; i++)
+ {
+ if ((frame[i] == 0x7e) || (frame[i] == 0x7d))
+ {
+ Serial_write(0x7D);
+ frame[i] ^= 0x20;
+ }
+ Serial_write(frame[i]);
+ }
+ Serial_write(0x7E);
+ }
+
+ void compute_RSSIdbm(){
+
+ RSSI_dBm = (((uint16_t)(pktt[len-2])*18)>>5);
+ if(pktt[len-2] >=128)
+ RSSI_dBm -= 82;
+ else
+ RSSI_dBm += 65;
+ }
+
+ void frsky_check_telemetry(uint8_t *pkt,uint8_t len)
+ {
+ if(pkt[1] != rx_tx_addr[3] || pkt[2] != rx_tx_addr[2] || len != pkt[0] + 3)
+ {//only packets with the required id and packet length
+ for(uint8_t i=3;i<6;i++)
+ pktt[i]=0;
+ return;
+ }
+ else
+ {
+ for (uint8_t i=3;i0)
+ telemetry_counter=(telemetry_counter+1)%32;
+ }
+ }
+
+ void frsky_link_frame()
+ {
+ frame[0] = 0xFE;
+ if ((cur_protocol[0]&0x1F)==MODE_FRSKY)
+ {
+ compute_RSSIdbm();
+ frame[1] = pktt[3];
+ frame[2] = pktt[4];
+ frame[3] = (uint8_t)RSSI_dBm;
+ frame[4] = pktt[5]*2;
+ }
+ else
+ if ((cur_protocol[0]&0x1F)==MODE_HUBSAN)
+ {
+ frame[1] = v_lipo*2; //v_lipo; common 0x2A=42/10=4.2V
+ frame[2] = frame[1];
+ frame[3] = 0x00;
+ frame[4] = (uint8_t)RSSI_dBm;
+ }
+ frame[5] = frame[6] = frame[7] = frame[8] = 0;
+ frskySendStuffed();
+ }
+
+ #if defined HUB_TELEMETRY
+ void frsky_user_frame()
+ {
+ uint8_t indexx = 0, c=0, j=8, n=0, i;
+
+ if(pktt[6]>0 && pktt[6]<=MAX_PKTX)
+ {//only valid hub frames
+ frame[0] = 0xFD;
+ frame[1] = 0;
+ frame[2] = pktt[7];
+
+ switch(pass)
+ {
+ case 0:
+ indexx=pktt[6];
+ for(i=0;i>>>>>> refs/remotes/pascallanger/master
7E 98 10 05 F1 20 23 0F 00 A6 SWR_ID
7E 98 10 01 F1 33 00 00 00 C9 RSSI_ID
7E 98 10 04 F1 58 00 00 00 A1 BATT_ID
@@ -241,15 +417,24 @@ pkt[6]|(counter++)|00 01 02 03 04 05 06 07 08 09
7E BA 10 03 F1 E2 00 00 00 18 ADC2_ID
+<<<<<<< HEAD
+ Telemetry frames(RF) SPORT info 15 bytes
+ SPORT frame 6+3 bytes
+=======
Telemetry frames(RF) SPORT info
15 bytes payload
SPORT frame valid 6+3 bytes
+>>>>>>> refs/remotes/pascallanger/master
[00] PKLEN 0E 0E 0E 0E
[01] TXID1 DD DD DD DD
[02] TXID2 6D 6D 6D 6D
[03] CONST 02 02 02 02
[04] RS/RB 2C D0 2C CE //D0;CE=2*RSSI;....2C = RX battery voltage(5V from Bec)
+<<<<<<< HEAD
+ [05] ????? 03 10 21 32 //TX/RX telemetry hand-shake bytes
+=======
[05] HD-SK 03 10 21 32 //TX/RX telemetry hand-shake bytes
+>>>>>>> refs/remotes/pascallanger/master
[06] NO.BT 00 00 06 03 //No.of valid SPORT frame bytes in the frame
[07] STRM1 00 00 7E 00
[08] STRM2 00 00 1A 00
@@ -257,6 +442,146 @@ pkt[6]|(counter++)|00 01 02 03 04 05 06 07 08 09
[10] STRM4 03 03 03 03
[11] STRM5 F1 F1 F1 F1
[12] STRM6 D1 D1 D0 D0
+<<<<<<< HEAD
+ [13] CHKSUM1
+ [14] CHKSUM2
+ */
+
+
+ void sportSend(uint8_t *p)
+ {
+ uint16_t crc_s = 0;
+ Serial_write(0x7e);//+9
+ for (uint8_t i = 0; i < 9; i++)
+ {
+ if (i == 8)
+ p[i] = 0xff - crc_s;
+ if ((p[i] == 0x7e) || (p[i] == 0x7d))
+ {
+ Serial_write(0x7d);
+ Serial_write(0x20 ^ p[i]);
+ }
+ else
+ Serial_write(p[i]);
+ if (i>0)
+ {
+ crc_s += p[i]; //0-1FF
+ crc_s += crc_s >> 8; //0-100
+ crc_s &= 0x00ff;
+ }
+ }
+ }
+
+ void sportIdle()
+ {
+ Serial_write(0x7e);
+ }
+
+ void sportSendFrame()
+ {
+ //at the moment only SWR RSSI,RxBt and A2.
+ sport_counter = (sport_counter + 1) %9;
+
+ for (uint8_t i=5;i<8;i++)
+ frame[i]=0;
+
+ switch (sport_counter)
+ {
+ case 0: // SWR
+ frame[0] = 0x98;
+ frame[1] = 0x10;
+ frame[2] = 0x05;
+ frame[3] = 0xf1;
+ frame[4] = 0x20;//dummy values if swr 20230f00
+ frame[5] = 0x23;
+ frame[6] = 0x0F;
+ frame[7] = 0x00;
+ break;
+ case 1: // RSSI
+ frame[0] = 0x98;
+ frame[1] = 0x10;
+ frame[2] = 0x01;
+ frame[3] = 0xf1;
+ frame[4] = rssi;
+ break;
+ case 2: //BATT
+ frame[0] = 0x98;
+ frame[1] = 0x10;
+ frame[2] = 0x04;
+ frame[3] = 0xf1;
+ frame[4] = RxBt;//a1;
+ break;
+ case 3: //ADC2(A2)
+ frame[0] = 0x1A;
+ frame[1] = 0x10;
+ frame[2] = 0x03;
+ frame[3] = 0xf1;
+ frame[4] = ADC2;//a2;;
+ break;
+ default:
+ sportIdle();
+ return;
+ }
+ sportSend(frame);
+ }
+
+ void process_sport_data()//only for ADC2
+ {
+ uint8_t j=7;
+ if(pktt[6]>0 && pktt[6]<=USER_MAX_BYTES)
+ {
+ for(uint8_t i=0;i<6;i++)
+ if(pktt[j++]==0x03)
+ if(pktt[j]==0xF1)
+ {
+ ADC2=pktt[j+1];
+ break;
+ }
+ pktt[6]=0;//new frame
+ }
+ }
+ #endif
+
+
+ void frskyUpdate()
+ {
+ if(telemetry_link && (cur_protocol[0]&0x1F) != MODE_FRSKYX )
+ {
+ frsky_link_frame();
+ telemetry_link=0;
+ return;
+ }
+ #if defined HUB_TELEMETRY
+ if(!telemetry_link && (cur_protocol[0]&0x1F) != MODE_HUBSAN && (cur_protocol[0]&0x1F) != MODE_FRSKYX)
+ {
+ frsky_user_frame();
+ return;
+ }
+ #endif
+ #if defined SPORT_TELEMETRY
+ if ((cur_protocol[0]&0x1F)==MODE_FRSKYX)
+ {
+ if(telemetry_link)
+ {
+ process_sport_data();
+ if(pktt[4]>0x36)
+ rssi=pktt[4]/2;
+ else
+ RxBt=pktt[4];
+ telemetry_link=0;
+ }
+ uint32_t now = micros();
+ if ((now - last) > SPORT_TIME)
+ {
+ sportSendFrame();
+ last = now;
+ }
+ }
+ #endif
+ }
+
+#endif
+=======
[13] CHKSUM1 --|2 CRC bytes sent by RX (calculated on RX side crc16/table)
[14] CHKSUM2 --|
+2 appended bytes automatically RSSI and LQI/CRC bytes(len=0x0E+3);
@@ -824,3 +1149,4 @@ ISR(TIMER0_OVF_vect)
#endif // BASH_SERIAL
#endif // TELEMETRY
+>>>>>>> refs/remotes/pascallanger/master
diff --git a/Multiprotocol/YD717_nrf24l01.ino b/Multiprotocol/YD717_nrf24l01.ino
index 4e6a634..e3a3756 100644
--- a/Multiprotocol/YD717_nrf24l01.ino
+++ b/Multiprotocol/YD717_nrf24l01.ino
@@ -34,6 +34,16 @@
#define YD717_PAYLOADSIZE 8 // receive data pipes set to this size, but unused
+<<<<<<< HEAD
+enum {
+ YD717_INIT1 = 0,
+ YD717_BIND2,
+ YD717_BIND3,
+ YD717_DATA
+};
+
+=======
+>>>>>>> refs/remotes/pascallanger/master
static void __attribute__((unused)) yd717_send_packet(uint8_t bind)
{
uint8_t rudder_trim, elevator_trim, aileron_trim;
@@ -139,6 +149,11 @@ static void __attribute__((unused)) yd717_init()
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07); // Set feature bits on
NRF24L01_Activate(0x73);
+<<<<<<< HEAD
+static void __attribute__((unused)) YD717_init1()
+{
+=======
+>>>>>>> refs/remotes/pascallanger/master
// for bind packets set address to prearranged value known to receiver
uint8_t bind_rx_tx_addr[] = {0x65, 0x65, 0x65, 0x65, 0x65};
@@ -153,6 +168,16 @@ static void __attribute__((unused)) yd717_init()
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, bind_rx_tx_addr, 5);
}
+<<<<<<< HEAD
+static void __attribute__((unused)) YD717_init2()
+{
+ // set rx/tx address for data phase
+ NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5);
+ NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5);
+}
+
+=======
+>>>>>>> refs/remotes/pascallanger/master
uint16_t yd717_callback()
{
if(IS_BIND_DONE_on)
diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h
index dc194e2..17c740a 100644
--- a/Multiprotocol/_Config.h
+++ b/Multiprotocol/_Config.h
@@ -13,6 +13,85 @@
along with Multiprotocol. If not, see .
*/
+<<<<<<< HEAD
+/** Multiprotocol module configuration file ***/
+
+//Uncomment your TX type
+#define TARANIS //TARANIS TAER (1100<->1900µs)
+//#define TX_ER9X //ER9X AETR (988<->2012µs)
+//#define TX_DEVO7 //DEVO7 EATR (1120<->1920µs)
+//#define TX_SPEKTRUM //Spektrum TAER (1100<->1900µs)
+//#define TX_HISKY //HISKY AETR (1100<->1900µs)
+
+//Uncomment to enable telemetry
+#define TELEMETRY
+
+//Comment if a module is not installed
+#define A7105_INSTALLED
+#define CYRF6936_INSTALLED
+//#define CC2500_INSTALLED
+#define NFR24L01_INSTALLED
+
+//Comment a protocol to exclude it from compilation
+#ifdef A7105_INSTALLED
+ #define JOYSWAY_A7105_INO
+
+ #define FLYSKY_A7105_INO
+ #define HUBSAN_A7105_INO
+#endif
+#ifdef CYRF6936_INSTALLED
+ #define J6PRO_CYRF6936_INO
+ #define WK2x01_CYRF6936_INO
+
+ #define DEVO_CYRF6936_INO
+ #define DSM2_CYRF6936_INO
+#endif
+#ifdef CC2500_INSTALLED
+ #define SKYARTEC_CC2500_INO
+
+ #define FRSKY_CC2500_INO
+ #define FRSKYX_CC2500_INO
+#endif
+#ifdef NFR24L01_INSTALLED
+ #define HM830_NRF24L01_INO
+ #define CFlie_NRF24L01_INO
+ #define H377_NRF24L01_INO
+ #define ESKY150_NRF24L01_INO
+ #define HonTai_NRF24L01_INO
+ #define UDI_NRF24L01_INO
+ #define NE260_NRF24L01_INO
+ #define BlueFly_NRF24L01_INO //probleme gene id
+ #define FBL100_NRF24L01_INO // finir id
+
+ #define BAYANG_NRF24L01_INO
+ #define CG023_NRF24L01_INO
+ #define CX10_NRF24L01_INO
+ #define ESKY_NRF24L01_INO
+ #define HISKY_NRF24L01_INO
+ #define KN_NRF24L01_INO
+ #define SLT_NRF24L01_INO
+ #define SYMAX_NRF24L01_INO
+ #define V2X2_NRF24L01_INO
+ #define YD717_NRF24L01_INO
+ #define MT99XX_NRF24L01_INO
+ #define MJXQ_NRF24L01_INO
+ #define SHENQI_NRF24L01_INO
+ #define FY326_NRF24L01_INO
+#endif
+
+//Update this table to set which protocol and all associated settings are called for the corresponding dial number
+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 }, // D7 fine tuning
+/* 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 , 6 }, // 6 channels @ 11ms
+/* 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 },
+=======
/**********************************************/
/** Multiprotocol module configuration file ***/
/**********************************************/
@@ -155,6 +234,7 @@ const PPM_Parameters PPM_prot[15]= {
/* 7 */ {MODE_DEVO , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 8 */ {MODE_YD717 , YD717 , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 9 */ {MODE_KN , WLTOYS , 0 , P_HIGH , NO_AUTOBIND , 0 },
+>>>>>>> refs/remotes/pascallanger/master
/* 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 },
@@ -162,7 +242,11 @@ const PPM_Parameters PPM_prot[15]= {
/* 14 */ {MODE_BAYANG, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 15 */ {MODE_SYMAX , SYMAX5C , 0 , P_HIGH , NO_AUTOBIND , 0 }
};
+<<<<<<< HEAD
+/* Available protocols and associated sub protocols:
+=======
/* Available protocols and associated sub protocols to pick and choose from
+>>>>>>> refs/remotes/pascallanger/master
MODE_FLYSKY
Flysky
V9X9
@@ -170,18 +254,28 @@ const PPM_Parameters PPM_prot[15]= {
V912
MODE_HUBSAN
NONE
+<<<<<<< HEAD
+ MODE_FRSKY
+=======
MODE_FRSKYD
+>>>>>>> refs/remotes/pascallanger/master
NONE
MODE_HISKY
Hisky
HK310
MODE_V2X2
NONE
+<<<<<<< HEAD
+ MODE_DSM2
+ DSM2
+ DSMX
+=======
MODE_DSM
DSM2_22
DSM2_11
DSMX_22
DSMX_11
+>>>>>>> refs/remotes/pascallanger/master
MODE_DEVO
NONE
MODE_YD717
@@ -214,20 +308,137 @@ const PPM_Parameters PPM_prot[15]= {
MODE_BAYANG
NONE
MODE_FRSKYX
+<<<<<<< HEAD
+ NONE
+=======
CH_16
CH_8
+>>>>>>> refs/remotes/pascallanger/master
MODE_ESKY
NONE
MODE_MT99XX
MT99
H7
YZ
+<<<<<<< HEAD
+=======
LS
+>>>>>>> refs/remotes/pascallanger/master
MODE_MJXQ
WLH08
X600
X800
H26D
+<<<<<<< HEAD
+ MODE_SHENQI
+ NONE
+ MODE_FY326
+ FY326
+ FY319
+
+RX_Num value between 0 and 15
+
+Power P_HIGH or P_LOW
+
+Auto Bind AUTOBIND or NO_AUTOBIND
+
+Option value between 0 and 255. 0xD7 or 0x00 for Frsky fine tuning.
+*/
+
+//******************
+//TX definitions with timing endpoints and channels order
+
+// Turnigy PPM and channels
+#if defined(TX_ER9X)
+ #define PPM_MAX 2140
+ #define PPM_MIN 860
+ #define PPM_MAX_100 2012
+ #define PPM_MIN_100 988
+ #define AETR
+#endif
+
+// Devo PPM and channels
+#if defined(TX_DEVO7)
+ #define PPM_MAX 2100
+ #define PPM_MIN 900
+ #define PPM_MAX_100 1920
+ #define PPM_MIN_100 1120
+ #define EATR
+#endif
+
+// SPEKTRUM PPM and channels
+#if defined(TX_SPEKTRUM)
+ #define PPM_MAX 2000
+ #define PPM_MIN 1000
+ #define PPM_MAX_100 1900
+ #define PPM_MIN_100 1100
+ #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
+ #define PPM_MIN 1000
+ #define PPM_MAX_100 1900
+ #define PPM_MIN_100 1100
+ #define AETR
+#endif
+
+#if defined(EATR)
+ enum chan_order{
+ ELEVATOR=0,
+ AILERON,
+ THROTTLE,
+ RUDDER,
+ };
+#endif
+
+#if defined(TAER)
+ enum chan_order{
+ THROTTLE=0,
+ AILERON,
+ ELEVATOR,
+ RUDDER,
+ };
+#endif
+
+#if defined(AETR)
+ enum chan_order{
+ AILERON =0,
+ ELEVATOR,
+ THROTTLE,
+ RUDDER,
+ };
+#endif
+enum chan_orders{
+ AUX1 =4,
+ AUX2,
+ AUX3,
+ AUX4,
+ AUX5,
+ AUX6,
+ AUX7,
+ AUX8,
+ AUX9
+};
+
+#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
+=======
E010
MODE_SHENQI
NONE
@@ -260,4 +471,5 @@ const PPM_Parameters PPM_prot[15]= {
// As an exxample, it's usefull for the WLTOYS F929/F939/F949/F959 (all using the Flysky protocol) which requires a bind at each power up.
// Option: the value is between -127 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
\ No newline at end of file
+// 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
+>>>>>>> refs/remotes/pascallanger/master
diff --git a/Multiprotocol/iface_nrf24l01.h b/Multiprotocol/iface_nrf24l01.h
index cc8b6fe..6aab6c1 100644
--- a/Multiprotocol/iface_nrf24l01.h
+++ b/Multiprotocol/iface_nrf24l01.h
@@ -103,8 +103,13 @@ enum {
//#define NOP 0xFF
// XN297 emulation layer
+<<<<<<< HEAD
+#define XN297_UNSCRAMBLED 8
+
+=======
enum {
XN297_UNSCRAMBLED = 0,
XN297_SCRAMBLED
};
+>>>>>>> refs/remotes/pascallanger/master
#endif
\ No newline at end of file
diff --git a/Multiprotocol/multi.lua b/Multiprotocol/multi.lua
new file mode 100644
index 0000000..07721ae
--- /dev/null
+++ b/Multiprotocol/multi.lua
@@ -0,0 +1,94 @@
+-- Multiprotocole Midelic et Pascallanger
+local debut = 0
+local tps = 0
+local tpsact = 1024
+local mix, mixe
+local channel
+
+local inp = {
+ { "Protocole", VALUE, 1, 26, 2 },
+ { "Switch", SOURCE }
+}
+-- 6 7 8 15 16 17 24 25 26
+-- 4 5 12 13 14 21 22 23
+-- 1 2 3 9 10 11 18 19 20
+local out = { "Bind", "Gaz", "Aile", "Prof", "Dir" }
+
+local function run_func(proto, sw)
+ -- test mixage lua
+ if debut == 0 then
+ -- passage en lua
+ for channel = 0, 3, 1 do
+ local mix = model.getMix(channel, 0)
+ mix_source = mix["source"]
+ if mix_source < 33 or 1 then
+ model.deleteMix(channel, 0)
+ mix["source"] = channel + 34
+ mix["name"] = "Lua "
+ model.insertMix(channel, 0, mix)
+ end
+ end
+ end
+ -- inter install
+ channel = 4
+ mix = { name="Raz Bind", source=33, weight=100, switch=0, multiplex=REPLACE }
+ count = model.getMixesCount(channel + 0)
+ if count == 0 and inter == 1 then
+ model.insertMix(channel + 0, 0, mix)
+ elseif count == 1 and inter == 0 then
+ mixe = model.getMix(channel, 0)
+ if mixe["name"] == mix["name"] then
+ model.deleteMix(channel, 0)
+ end
+ end
+
+ -- delais init
+ if proto ~= debut then
+ tps = getTime() + 250 -- delai pour mini 12 cycle PPM
+ tpsact = 1024
+ debut = proto
+ end
+
+ local gaz = 1024
+ local ail = 0
+ local dir = 0
+ local pro = 0
+
+ if tpsact == 0 and sw < 100 then
+ -- reprise valeur input
+ pro = getValue(1)
+ ail = getValue(2)
+ gaz = getValue(3)
+ dir = getValue(4)
+ elseif tpsact ~= 0 then
+ -- decallage pour position memo (centre)
+ if proto > 4 then proto = proto + 1 end
+
+ -- calcul position
+ -- decallage pour > 18
+ if proto > 18 then
+ ail = 1024
+ proto = proto - 18
+ end
+ -- decallage pour > 9
+ if proto > 9 then
+ ail = -1024
+ proto = proto - 9
+ end
+
+ if proto < 4 then pro = -1024 end
+ if proto > 6 then pro = 1024 end
+
+ if proto % 3 == 1 then dir = -1024 end
+ if proto % 3 == 0 then dir = 1024 end
+
+ if tps < getTime() then
+ tpsact = tpsact - 512
+ if tpsact>-20 then tps = getTime() + 250 end
+ end
+ sw = tpsact
+ end
+
+ return sw, gaz, ail, pro, dir
+end
+return { run=run_func, input=inp, output=out}
diff --git a/Multiprotocol/multiprotocol.h b/Multiprotocol/multiprotocol.h
new file mode 100644
index 0000000..672b922
--- /dev/null
+++ b/Multiprotocol/multiprotocol.h
@@ -0,0 +1,485 @@
+/*
+ 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 .
+ */
+
+// Check selected board type
+#ifndef XMEGA
+ #if not defined(ARDUINO_AVR_PRO) && not defined(ARDUINO_AVR_MINI) && not defined(ARDUINO_AVR_NANO)
+ #error You must select the board type "Arduino Pro or Pro Mini" or "Arduino Mini"
+ #endif
+ #if F_CPU != 16000000L || not defined(__AVR_ATmega328P__)
+ #error You must select the processor type "ATmega328(5V, 16MHz)"
+ #endif
+#endif
+
+//******************
+// Protocols
+//******************
+enum PROTOCOLS
+{
+ MODE_SERIAL = 0, // Serial commands
+ MODE_FLYSKY = 1, // =>A7105
+ MODE_HUBSAN = 2, // =>A7105
+ MODE_FRSKYD = 3, // =>CC2500
+ MODE_HISKY = 4, // =>NRF24L01
+ MODE_V2X2 = 5, // =>NRF24L01
+ MODE_DSM = 6, // =>CYRF6936
+ MODE_DEVO = 7, // =>CYRF6936
+ MODE_YD717 = 8, // =>NRF24L01
+ MODE_KN = 9, // =>NRF24L01
+ MODE_SYMAX = 10, // =>NRF24L01
+ MODE_SLT = 11, // =>NRF24L01
+ MODE_CX10 = 12, // =>NRF24L01
+ MODE_CG023 = 13, // =>NRF24L01
+ MODE_BAYANG = 14, // =>NRF24L01
+ MODE_FRSKYX = 15, // =>CC2500
+ MODE_ESKY = 16, // =>NRF24L01
+ MODE_MT99XX = 17, // =>NRF24L01
+ MODE_MJXQ = 18, // =>NRF24L01
+ MODE_SHENQI = 19, // =>NRF24L01
+ MODE_FY326 = 20, // =>NRF24L01
+ MODE_SFHSS = 21, // =>CC2500
+ MODE_J6PRO = 22, // =>CYRF6936
+ MODE_FQ777 = 23, // =>NRF24L01
+ MODE_ASSAN = 24, // =>NRF24L01
+ MODE_FRSKYV = 25, // =>CC2500
+ MODE_HONTAI = 26, // =>NRF24L01
+ MODE_OPENLRS = 27, // =>OpenLRS hardware
+};
+
+enum Flysky
+{
+ Flysky = 0,
+ V9X9 = 1,
+ V6X6 = 2,
+ V912 = 3
+};
+enum Hisky
+{
+ Hisky = 0,
+ HK310 = 1
+};
+enum DSM
+{
+ DSM2_22 = 0,
+ DSM2_11 = 1,
+ DSMX_22 = 2,
+ DSMX_11 = 3,
+ DSM_AUTO = 4
+};
+enum YD717
+{
+ YD717 = 0,
+ SKYWLKR = 1,
+ SYMAX4 = 2,
+ XINXUN = 3,
+ NIHUI = 4
+};
+enum KN
+{
+ WLTOYS = 0,
+ FEILUN = 1
+};
+enum SYMAX
+{
+ SYMAX = 0,
+ SYMAX5C = 1
+};
+enum CX10
+{
+ CX10_GREEN = 0,
+ CX10_BLUE = 1, // also compatible with CX10-A, CX12
+ DM007 = 2,
+ Q282 = 3,
+ JC3015_1 = 4,
+ JC3015_2 = 5,
+ MK33041 = 6,
+ Q242 = 7
+};
+enum CG023
+{
+ CG023 = 0,
+ YD829 = 1,
+ H8_3D = 2
+};
+enum MT99XX
+{
+ MT99 = 0,
+ H7 = 1,
+ YZ = 2,
+ LS = 3
+};
+enum MJXQ
+{
+ WLH08 = 0,
+ X600 = 1,
+ X800 = 2,
+ H26D = 3,
+ E010 = 4
+};
+enum FRSKYX
+{
+ CH_16 = 0,
+ CH_8 = 1,
+};
+enum HONTAI
+{
+ FORMAT_HONTAI = 0,
+ FORMAT_JJRCX1 = 1,
+ FORMAT_X5C1 = 2
+};
+
+#define NONE 0
+#define P_HIGH 1
+#define P_LOW 0
+#define AUTOBIND 1
+#define NO_AUTOBIND 0
+
+struct PPM_Parameters
+{
+ uint8_t protocol : 6;
+ uint8_t sub_proto : 3;
+ uint8_t rx_num : 4;
+ uint8_t power : 1;
+ uint8_t autobind : 1;
+ uint8_t option;
+};
+
+// Macros
+#define NOP() __asm__ __volatile__("nop")
+
+//*******************
+//*** Timer ***
+//*******************
+#ifdef XMEGA
+ #define TIFR1 TCC1.INTFLAGS
+ #define OCF1A_bm TC1_CCAIF_bm
+ #define OCR1A TCC1.CCA
+ #define TCNT1 TCC1.CNT
+ #define UDR0 USARTC0.DATA
+ #define OCF1B_bm TC1_CCBIF_bm
+ #define OCR1B TCC1.CCB
+ #define TIMSK1 TCC1.INTCTRLB
+ #define SET_TIMSK1_OCIE1B TIMSK1 = (TIMSK1 & 0xF3) | 0x04
+ #define CLR_TIMSK1_OCIE1B TIMSK1 &= 0xF3
+#else
+ #define OCF1A_bm _BV(OCF1A)
+ #define OCF1B_bm _BV(OCF1B)
+ #define SET_TIMSK1_OCIE1B TIMSK1 |= _BV(OCIE1B)
+ #define CLR_TIMSK1_OCIE1B TIMSK1 &=~_BV(OCIE1B)
+#endif
+
+//***************
+//*** Flags ***
+//***************
+#define RX_FLAG_on protocol_flags |= _BV(0)
+#define RX_FLAG_off protocol_flags &= ~_BV(0)
+#define IS_RX_FLAG_on ( ( protocol_flags & _BV(0) ) !=0 )
+//
+#define CHANGE_PROTOCOL_FLAG_on protocol_flags |= _BV(1)
+#define CHANGE_PROTOCOL_FLAG_off protocol_flags &= ~_BV(1)
+#define IS_CHANGE_PROTOCOL_FLAG_on ( ( protocol_flags & _BV(1) ) !=0 )
+//
+#define POWER_FLAG_on protocol_flags |= _BV(2)
+#define POWER_FLAG_off protocol_flags &= ~_BV(2)
+#define IS_POWER_FLAG_on ( ( protocol_flags & _BV(2) ) !=0 )
+//
+#define RANGE_FLAG_on protocol_flags |= _BV(3)
+#define RANGE_FLAG_off protocol_flags &= ~_BV(3)
+#define IS_RANGE_FLAG_on ( ( protocol_flags & _BV(3) ) !=0 )
+//
+#define AUTOBIND_FLAG_on protocol_flags |= _BV(4)
+#define AUTOBIND_FLAG_off protocol_flags &= ~_BV(4)
+#define IS_AUTOBIND_FLAG_on ( ( protocol_flags & _BV(4) ) !=0 )
+//
+#define BIND_BUTTON_FLAG_on protocol_flags |= _BV(5)
+#define BIND_BUTTON_FLAG_off protocol_flags &= ~_BV(5)
+#define IS_BIND_BUTTON_FLAG_on ( ( protocol_flags & _BV(5) ) !=0 )
+//PPM RX OK
+#define PPM_FLAG_off protocol_flags &= ~_BV(6)
+#define PPM_FLAG_on protocol_flags |= _BV(6)
+#define IS_PPM_FLAG_on ( ( protocol_flags & _BV(6) ) !=0 )
+//Bind flag
+#define BIND_IN_PROGRESS protocol_flags &= ~_BV(7)
+#define BIND_DONE protocol_flags |= _BV(7)
+#define IS_BIND_DONE_on ( ( protocol_flags & _BV(7) ) !=0 )
+//
+#define BAD_PROTO_off protocol_flags2 &= ~_BV(0)
+#define BAD_PROTO_on protocol_flags2 |= _BV(0)
+#define IS_BAD_PROTO_on ( ( protocol_flags2 & _BV(0) ) !=0 )
+//
+#define RX_DONOTUPDTAE_off protocol_flags2 &= ~_BV(1)
+#define RX_DONOTUPDTAE_on protocol_flags2 |= _BV(1)
+#define IS_RX_DONOTUPDTAE_on ( ( protocol_flags2 & _BV(1) ) !=0 )
+//
+#define RX_MISSED_BUFF_off protocol_flags2 &= ~_BV(2)
+#define RX_MISSED_BUFF_on protocol_flags2 |= _BV(2)
+#define IS_RX_MISSED_BUFF_on ( ( protocol_flags2 & _BV(2) ) !=0 )
+//TX Pause
+#define TX_MAIN_PAUSE_off protocol_flags2 &= ~_BV(3)
+#define TX_MAIN_PAUSE_on protocol_flags2 |= _BV(3)
+#define IS_TX_MAIN_PAUSE_on ( ( protocol_flags2 & _BV(3) ) !=0 )
+#define TX_RX_PAUSE_off protocol_flags2 &= ~_BV(4)
+#define TX_RX_PAUSE_on protocol_flags2 |= _BV(4)
+#define IS_TX_RX_PAUSE_on ( ( protocol_flags2 & _BV(4) ) !=0 )
+#define IS_TX_PAUSE_on ( ( protocol_flags2 & (_BV(4)|_BV(3)) ) !=0 )
+
+//********************
+//*** Blink timing ***
+//********************
+#define BLINK_BIND_TIME 100
+#define BLINK_SERIAL_TIME 500
+#define BLINK_BAD_PROTO_TIME_LOW 1000
+#define BLINK_BAD_PROTO_TIME_HIGH 50
+
+//*******************
+//*** AUX flags ***
+//*******************
+#define GET_FLAG(ch, mask) ( ch ? mask : 0)
+#define Servo_AUX1 Servo_AUX & _BV(0)
+#define Servo_AUX2 Servo_AUX & _BV(1)
+#define Servo_AUX3 Servo_AUX & _BV(2)
+#define Servo_AUX4 Servo_AUX & _BV(3)
+#define Servo_AUX5 Servo_AUX & _BV(4)
+#define Servo_AUX6 Servo_AUX & _BV(5)
+#define Servo_AUX7 Servo_AUX & _BV(6)
+#define Servo_AUX8 Servo_AUX & _BV(7)
+
+//************************
+//*** Power settings ***
+//************************
+enum {
+ TXPOWER_100uW,
+ TXPOWER_300uW,
+ TXPOWER_1mW,
+ TXPOWER_3mW,
+ TXPOWER_10mW,
+ TXPOWER_30mW,
+ TXPOWER_100mW,
+ TXPOWER_150mW
+};
+
+// A7105 power
+// Power amp is ~+16dBm so:
+enum A7105_POWER
+{
+ A7105_POWER_0 = 0x00<<3 | 0x00, // TXPOWER_100uW = -23dBm == PAC=0 TBG=0
+ A7105_POWER_1 = 0x00<<3 | 0x01, // TXPOWER_300uW = -20dBm == PAC=0 TBG=1
+ A7105_POWER_2 = 0x00<<3 | 0x02, // TXPOWER_1mW = -16dBm == PAC=0 TBG=2
+ A7105_POWER_3 = 0x00<<3 | 0x04, // TXPOWER_3mW = -11dBm == PAC=0 TBG=4
+ A7105_POWER_4 = 0x01<<3 | 0x05, // TXPOWER_10mW = -6dBm == PAC=1 TBG=5
+ A7105_POWER_5 = 0x02<<3 | 0x07, // TXPOWER_30mW = 0dBm == PAC=2 TBG=7
+ A7105_POWER_6 = 0x03<<3 | 0x07, // TXPOWER_100mW = 1dBm == PAC=3 TBG=7
+ A7105_POWER_7 = 0x03<<3 | 0x07 // TXPOWER_150mW = 1dBm == PAC=3 TBG=7
+};
+#define A7105_HIGH_POWER A7105_POWER_7
+#define A7105_LOW_POWER A7105_POWER_3
+#define A7105_RANGE_POWER A7105_POWER_0
+#define A7105_BIND_POWER A7105_POWER_0
+
+// NRF Power
+// Power setting is 0..3 for nRF24L01
+// Claimed power amp for nRF24L01 from eBay is 20dBm.
+enum NRF_POWER
+{ // Raw w 20dBm PA
+ NRF_POWER_0 = 0x00, // 0 : -18dBm (16uW) 2dBm (1.6mW)
+ NRF_POWER_1 = 0x01, // 1 : -12dBm (60uW) 8dBm (6mW)
+ NRF_POWER_2 = 0x02, // 2 : -6dBm (250uW) 14dBm (25mW)
+ NRF_POWER_3 = 0x03 // 3 : 0dBm (1mW) 20dBm (100mW)
+};
+#define NRF_HIGH_POWER NRF_POWER_2
+#define NRF_LOW_POWER NRF_POWER_1
+#define NRF_RANGE_POWER NRF_POWER_0
+#define NRF_BIND_POWER NRF_POWER_0
+
+// CC2500 power output from the chip itself
+// The numbers do not take into account any outside amplifier
+enum CC2500_POWER
+{
+ CC2500_POWER_0 = 0x00, // –55dbm or less
+ CC2500_POWER_1 = 0x50, // -30dbm
+ CC2500_POWER_2 = 0x44, // –28dbm
+ CC2500_POWER_3 = 0xC0, // –26dbm
+ CC2500_POWER_4 = 0x84, // –24dbm
+ CC2500_POWER_5 = 0x81, // –22dbm
+ CC2500_POWER_6 = 0x46, // –20dbm
+ CC2500_POWER_7 = 0x93, // –18dbm
+ CC2500_POWER_8 = 0x55, // –16dbm
+ CC2500_POWER_9 = 0x8D, // –14dbm
+ CC2500_POWER_10 = 0xC6, // -12dbm
+ CC2500_POWER_11 = 0x97, // -10dbm
+ CC2500_POWER_12 = 0x6E, // -8dbm
+ CC2500_POWER_13 = 0x7F, // -6dbm
+ CC2500_POWER_14 = 0xA9, // -4dbm
+ CC2500_POWER_15 = 0xBB, // -2dbm
+ CC2500_POWER_16 = 0xFE, // 0dbm
+ CC2500_POWER_17 = 0xFF // +1dbm
+};
+#define CC2500_HIGH_POWER CC2500_POWER_16
+#define CC2500_LOW_POWER CC2500_POWER_13
+#define CC2500_RANGE_POWER CC2500_POWER_1
+#define CC2500_BIND_POWER CC2500_POWER_1
+
+// CYRF power
+enum CYRF_POWER
+{
+ CYRF_POWER_0 = 0x00, // -35dbm
+ CYRF_POWER_1 = 0x01, // -30dbm
+ CYRF_POWER_2 = 0x02, // -24dbm
+ CYRF_POWER_3 = 0x03, // -18dbm
+ CYRF_POWER_4 = 0x04, // -13dbm
+ CYRF_POWER_5 = 0x05, // -5dbm
+ CYRF_POWER_6 = 0x06, // 0dbm
+ CYRF_POWER_7 = 0x07 // +4dbm
+};
+#define CYRF_HIGH_POWER CYRF_POWER_7
+#define CYRF_LOW_POWER CYRF_POWER_3
+#define CYRF_RANGE_POWER CYRF_POWER_1 // 1/30 of the full power distance
+#define CYRF_BIND_POWER CYRF_POWER_0
+
+enum TXRX_State {
+ TXRX_OFF,
+ TX_EN,
+ RX_EN
+};
+
+// Packet ack status values
+enum {
+ PKT_PENDING = 0,
+ PKT_ACKED,
+ PKT_TIMEOUT
+};
+
+// baudrate defines for serial
+#define SPEED_100K 0
+#define SPEED_9600 1
+#define SPEED_57600 2
+#define SPEED_125K 3
+
+//****************************************
+//*** MULTI protocol serial definition ***
+//****************************************
+/*
+**************************
+16 channels serial protocol
+**************************
+Serial: 100000 Baud 8e2 _ xxxx xxxx p --
+ Total of 26 bytes
+ Stream[0] = 0x55 sub_protocol values are 0..31
+ Stream[0] = 0x54 sub_protocol values are 32..63
+ header
+ Stream[1] = sub_protocol|BindBit|RangeCheckBit|AutoBindBit;
+ sub_protocol is 0..31 (bits 0..4), value should be added with 32 if Stream[0] = 0x54
+ => Reserved 0
+ Flysky 1
+ Hubsan 2
+ FrskyD 3
+ Hisky 4
+ V2x2 5
+ DSM 6
+ Devo 7
+ YD717 8
+ KN 9
+ SymaX 10
+ SLT 11
+ CX10 12
+ CG023 13
+ Bayang 14
+ FrskyX 15
+ ESky 16
+ MT99XX 17
+ MJXQ 18
+ SHENQI 19
+ FY326 20
+ SFHSS 21
+ J6PRO 22
+ FQ777 23
+ ASSAN 24
+ FrskyV 25
+ HONTAI 26
+ OpenLRS 27
+ BindBit=> 0x80 1=Bind/0=No
+ AutoBindBit=> 0x40 1=Yes /0=No
+ RangeCheck=> 0x20 1=Yes /0=No
+ Stream[2] = RxNum | Power | Type;
+ RxNum value is 0..15 (bits 0..3)
+ Type is 0..7 <<4 (bit 4..6)
+ sub_protocol==Flysky
+ Flysky 0
+ V9x9 1
+ V6x6 2
+ V912 3
+ sub_protocol==Hisky
+ Hisky 0
+ HK310 1
+ sub_protocol==DSM
+ DSM2_22 0
+ DSM2_11 1
+ DSMX_22 2
+ DSMX_11 3
+ sub_protocol==YD717
+ YD717 0
+ SKYWLKR 1
+ SYMAX4 2
+ XINXUN 3
+ NIHUI 4
+ sub_protocol==KN
+ WLTOYS 0
+ FEILUN 1
+ sub_protocol==SYMAX
+ SYMAX 0
+ SYMAX5C 1
+ sub_protocol==CX10
+ CX10_GREEN 0
+ CX10_BLUE 1 // also compatible with CX10-A, CX12
+ DM007 2
+ Q282 3
+ JC3015_1 4
+ JC3015_2 5
+ MK33041 6
+ Q242 7
+ sub_protocol==CG023
+ CG023 0
+ YD829 1
+ H8_3D 2
+ sub_protocol==MT99XX
+ MT99 0
+ H7 1
+ YZ 2
+ LS 3
+ sub_protocol==MJXQ
+ WLH08 0
+ X600 1
+ X800 2
+ H26D 3
+ E010 4
+ sub_protocol==FRSKYX
+ CH_16 0
+ CH_8 1
+ sub_protocol==HONTAI
+ FORMAT_HONTAI 0
+ FORMAT_JJRCX1 1
+ FORMAT_X5C1 2
+ Power value => 0x80 0=High/1=Low
+ Stream[3] = option_protocol;
+ option_protocol value is -127..127
+ Stream[4] to [25] = Channels
+ 16 Channels on 11 bits (0..2047)
+ 0 -125%
+ 204 -100%
+ 1024 0%
+ 1843 +100%
+ 2047 +125%
+ Channels bits are concatenated to fit in 22 bytes like in SBUS protocol
+*/
diff --git a/Multiprotocol/opentx-multi-2015-24-12.bin b/Multiprotocol/opentx-multi-2015-24-12.bin
new file mode 100644
index 0000000..fe1836e
Binary files /dev/null and b/Multiprotocol/opentx-multi-2015-24-12.bin differ
diff --git a/Multiprotocol/opentx.bin b/Multiprotocol/opentx.bin
new file mode 100644
index 0000000..8e886c4
Binary files /dev/null and b/Multiprotocol/opentx.bin differ
diff --git a/README.md b/README.md
index aacc3a4..a1f3bad 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,12 @@
+<<<<<<< HEAD
+# DIY-Multiprotocol-TX-Module
+=======
# Overview of the MPTM
The **Multiprotocol Tx Module** (or **MPTM**) is a 2.4GHz transmitter module which enables almost any TX to control lot of different models available on the market.
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.
+>>>>>>> refs/remotes/pascallanger/master
## Quicklinks
* [Download latest releases of the firmware](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases)
@@ -11,6 +15,193 @@ The source code is partly based on the [Deviation TX project](http://www.deviati
* [The old documentation](docs/README-old.md)
* [Documentation to-do list](docs/Documentation_To_Do_List.md)
+<<<<<<< HEAD
+Fork du projet https://github.com/pascallanger/DIY-Multiprotocol-TX-Module
+
+Afin d'ajouter :
+- Une sélection du protocole via les manches de la radio
+- Un rebind hardware en PPM
+- La radio TARANIS (TAERB, B = rebind ;-) ) et redéclaration des radios
+- Un script "LUA" afin de faciliter la position des manches
+
+
+
+Programme des évolutions :
+- Ajout du de la télémetrie TARANIS à l'aide du projet https://github.com/shadow974/TxAdapter
+
+ (Attention, il faut rajouter un transistor afin d'inverser et amplifier le signal)
+
+
+#Schematic
+
+
+Notes:
+- Attention: All modules are 3.3V only, never power them with 5V.
+- For serial, the dial switch is not needed and the bind button optionnal
+- Ajout d'un switch + transistor sur le TX
+
+
+
+#Protocoles ajoutés mais non testés (Issue de Deviation)
+##CYRF6936 RF Module
+###J6PRO
+CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12
+---|---|---|---|---|---|---|---|---|---|---|---
+CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12
+
+###WK2x01
+Autobind
+
+####Sub_protocol WK2401
+CH1|CH2|CH3|CH4
+---|---|---|---
+CH1|CH2|CH3|CH4
+
+
+####Sub_protocol WK2601
+Option:
+
+ 0 = 5+1
+ 2 = 6+1
+ ..1 = Hélicoptère (. = autres options pour ce mode)
+ .01 = Hélicoptère normal
+ .11 = Hélicoptère avec pit inversé
+ 0.1 = Pitch curve -100
+ 1.1 = Pitch curve 100
+
+CH1|CH2|CH3|CH4|CH5|CH6|CH7
+---|---|---|---|---|---|---
+CH1|CH2|CH3|CH4|???|CONF|Gyro & Rudder mix
+
+CONF: Option 1 = Rate Throtle
+
+ Option 2 = Pitch
+
+
+####Sub_protocol WK2801
+CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
+---|---|---|---|---|---|---|---
+CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
+
+
+##A7105 RF Module
+###Joysway
+CH1|CH2|CH3|CH4
+---|---|---|---
+A|E|T|R
+
+##CC2500 RF Module
+###SKYARTEC
+CH1|CH2|CH3|CH4|CH5|CH6|CH7
+---|---|---|---|---|---|---
+ ? | ? | ? | ? | ? | ? | ?
+
+##NRF24L01 RF Module
+###BLUEFLY
+Autobind
+
+CH1|CH2|CH3|CH4|CH5|CH6
+---|---|---|---|---|---
+A|E|T|R|GEAR|PITCH
+
+###CFLIE
+Modele: CrazyFlie Nano quad
+
+Autobind
+
+CH1|CH2|CH3|CH4
+---|---|---|---
+A|E|T|R
+
+###ESKY150
+
+Autobind
+
+CH1|CH2|CH3|CH4
+---|---|---|---
+A|E|T|R
+
+###FBL100
+Autobind
+
+CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
+---|---|---|---|---|---|---|---
+ ? | ? | ? | ? | ? | ? | ? | ?
+
+####Sub_protocol HP100
+Same channels assignement as above.
+
+###Fy326
+Autobind
+
+CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
+---|---|---|---|---|---|---|---|---
+A|E|T|R|FLIP|HEADLESS|RTH|Calibrate|Expert
+
+####Sub_protocol FY319
+Same channels assignement as above.
+
+###H377
+CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
+---|---|---|---|---|---|---|---
+A|E|T|R|CH5|CH6|CH7|CH8
+
+###HM830
+Modele: HM Hobby HM830 RC Paper Airplane
+
+Autobind
+
+CH1|CH2|CH3|CH4|CH5
+---|---|---|---
+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 U839_2014
+Same channels assignement as above.
+
+
+###D'autres à venir
+=======
## Outline of the documentation
1. Introduction (this page)
1. [Available protocols](docs/Protocol_Details.md)
@@ -119,3 +310,4 @@ A very big thanks to all the people who have shared their time so graciously to
* hexfet – from Deviation-tx
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.
+>>>>>>> refs/remotes/pascallanger/master
diff --git a/sync.ffs_db b/sync.ffs_db
new file mode 100644
index 0000000..e2cbf55
Binary files /dev/null and b/sync.ffs_db differ
diff --git a/taranis_switches.png b/taranis_switches.png
new file mode 100644
index 0000000..d1645d2
Binary files /dev/null and b/taranis_switches.png differ
diff --git a/telemetryFRSKY.fzz b/telemetryFRSKY.fzz
new file mode 100644
index 0000000..0a6f49a
Binary files /dev/null and b/telemetryFRSKY.fzz differ
diff --git a/telemetryFRSKY.jpg b/telemetryFRSKY.jpg
new file mode 100644
index 0000000..5876793
Binary files /dev/null and b/telemetryFRSKY.jpg differ