diff --git a/Multiprotocol/E01X_nrf24l01.ino b/Multiprotocol/E01X_nrf24l01.ino
new file mode 100644
index 0000000..1b87832
--- /dev/null
+++ b/Multiprotocol/E01X_nrf24l01.ino
@@ -0,0 +1,248 @@
+/*
+ This project is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Multiprotocol is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Multiprotocol. If not, see .
+ */
+// compatible with E012 and E015
+
+#if defined(E01X_NRF24L01_INO)
+
+#include "iface_nrf24l01.h"
+
+//Protocols constants
+#define E01X_BIND_COUNT 500
+#define E01X_INITIAL_WAIT 500
+#define E01X_ADDRESS_LENGTH 5
+
+#define E012_PACKET_PERIOD 4525
+#define E012_RF_BIND_CHANNEL 0x3c
+#define E012_NUM_RF_CHANNELS 4
+#define E012_PACKET_SIZE 15
+
+#define E015_PACKET_PERIOD 4500 // stock Tx=9000, but let's send more packets ...
+#define E015_RF_CHANNEL 0x2d // 2445 MHz
+#define E015_PACKET_SIZE 10
+#define E015_BIND_PACKET_SIZE 9
+
+//Channels
+#define E01X_ARM_SW CH5_SW
+#define E01X_FLIP_SW CH6_SW
+#define E01X_LED_SW CH7_SW
+#define E01X_HEADLESS_SW CH8_SW
+#define E01X_RTH_SW CH9_SW
+
+// E012 flags packet[1]
+#define E012_FLAG_FLIP 0x40
+#define E012_FLAG_HEADLESS 0x10
+#define E012_FLAG_RTH 0x04
+// E012 flags packet[7]
+#define E012_FLAG_EXPERT 0x02
+
+// E015 flags packet[6]
+#define E015_FLAG_DISARM 0x80
+#define E015_FLAG_ARM 0x40
+// E015 flags packet[7]
+#define E015_FLAG_FLIP 0x80
+#define E015_FLAG_HEADLESS 0x10
+#define E015_FLAG_RTH 0x08
+#define E015_FLAG_LED 0x04
+#define E015_FLAG_EXPERT 0x02
+#define E015_FLAG_INTERMEDIATE 0x01
+
+static void __attribute__((unused)) E015_check_arming()
+{
+ uint8_t arm_channel = E01X_ARM_SW;
+
+ if (arm_channel != arm_channel_previous)
+ {
+ arm_channel_previous = arm_channel;
+ if (arm_channel)
+ {
+ armed = 1;
+ arm_flags ^= E015_FLAG_ARM;
+ }
+ else
+ {
+ armed = 0;
+ arm_flags ^= E015_FLAG_DISARM;
+ }
+ }
+}
+
+static void __attribute__((unused)) E01X_send_packet(uint8_t bind)
+{
+ if(sub_protocol==E012)
+ {
+ packet_length=E012_PACKET_SIZE;
+ packet[0] = rx_tx_addr[1];
+ if(bind)
+ {
+ packet[1] = 0xaa;
+ memcpy(&packet[2], hopping_frequency, E012_NUM_RF_CHANNELS);
+ memcpy(&packet[6], rx_tx_addr, E01X_ADDRESS_LENGTH);
+ rf_ch_num=E012_RF_BIND_CHANNEL;
+ }
+ else
+ {
+ packet[1] = 0x01
+ | GET_FLAG(E01X_RTH_SW, E012_FLAG_RTH)
+ | GET_FLAG(E01X_HEADLESS_SW, E012_FLAG_HEADLESS)
+ | GET_FLAG(E01X_FLIP_SW, E012_FLAG_FLIP);
+ packet[2] = convert_channel_16b_limit(AILERON, 0xc8, 0x00); // aileron
+ packet[3] = convert_channel_16b_limit(ELEVATOR, 0x00, 0xc8); // elevator
+ packet[4] = convert_channel_16b_limit(RUDDER, 0xc8, 0x00); // rudder
+ packet[5] = convert_channel_16b_limit(THROTTLE, 0x00, 0xc8); // throttle
+ packet[6] = 0xaa;
+ packet[7] = E012_FLAG_EXPERT; // rate (0-2)
+ packet[8] = 0x00;
+ packet[9] = 0x00;
+ packet[10]= 0x00;
+ rf_ch_num=hopping_frequency[hopping_frequency_no++];
+ hopping_frequency_no %= E012_NUM_RF_CHANNELS;
+ }
+ packet[11] = 0x00;
+ packet[12] = 0x00;
+ packet[13] = 0x56;
+ packet[14] = rx_tx_addr[2];
+ }
+ else
+ { // E015
+ if(bind)
+ {
+ packet[0] = 0x18;
+ packet[1] = 0x04;
+ packet[2] = 0x06;
+ // data phase address
+ memcpy(&packet[3], rx_tx_addr, E01X_ADDRESS_LENGTH);
+ // checksum
+ packet[8] = packet[3];
+ for(uint8_t i=4; i<8; i++)
+ packet[8] += packet[i];
+ packet_length=E015_BIND_PACKET_SIZE;
+ }
+ else
+ {
+ E015_check_arming();
+ packet[0] = convert_channel_16b_limit(THROTTLE, 0, 225); // throttle
+ packet[1] = convert_channel_16b_limit(RUDDER, 225, 0); // rudder
+ packet[2] = convert_channel_16b_limit(AILERON, 0, 225); // aileron
+ packet[3] = convert_channel_16b_limit(ELEVATOR, 225, 0); // elevator
+ packet[4] = 0x20; // elevator trim
+ packet[5] = 0x20; // aileron trim
+ packet[6] = arm_flags;
+ packet[7] = E015_FLAG_EXPERT
+ | GET_FLAG(E01X_FLIP_SW, E015_FLAG_FLIP)
+ | GET_FLAG(E01X_LED_SW, E015_FLAG_LED)
+ | GET_FLAG(E01X_HEADLESS_SW,E015_FLAG_HEADLESS)
+ | GET_FLAG(E01X_RTH_SW, E015_FLAG_RTH);
+ packet[8] = 0;
+ // checksum
+ packet[9] = packet[0];
+ for(uint8_t i=1; i<9; i++)
+ packet[9] += packet[i];
+ packet_length=E015_PACKET_SIZE;
+ }
+ }
+
+ // Power on, TX mode, CRC enabled
+ HS6200_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP));
+ NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch_num);
+
+ NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
+ NRF24L01_FlushTx();
+
+ // transmit packet twice in a row without waiting for
+ // the first one to complete, seems to help the hs6200
+ // demodulator to start decoding.
+ HS6200_WritePayload(packet, packet_length);
+ HS6200_WritePayload(packet, packet_length);
+
+ // Check and adjust transmission power. We do this after
+ // transmission to not bother with timeout after power
+ // settings change - we have plenty of time until next
+ // packet.
+ NRF24L01_SetPower();
+}
+
+static void __attribute__((unused)) E01X_init()
+{
+ NRF24L01_Initialize();
+ NRF24L01_SetTxRxMode(TX_EN);
+ if(sub_protocol==E012)
+ HS6200_SetTXAddr((uint8_t *)"\x55\x42\x9C\x8F\xC9", E01X_ADDRESS_LENGTH);
+ else // E015
+ HS6200_SetTXAddr((uint8_t *)"\x62\x54\x79\x38\x53", E01X_ADDRESS_LENGTH);
+ NRF24L01_FlushTx();
+ NRF24L01_FlushRx();
+ NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
+ NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
+ NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03);
+ NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
+ NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1 Mbps
+ NRF24L01_SetPower();
+ NRF24L01_Activate(0x73); // Activate feature register
+ NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
+ NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01); // Set feature bits on
+ NRF24L01_Activate(0x73);
+}
+
+uint16_t E01X_callback()
+{
+ if(IS_BIND_IN_PROGRESS)
+ {
+ if (bind_counter == 0)
+ {
+ HS6200_SetTXAddr(rx_tx_addr, 5);
+ BIND_DONE;
+ }
+ else
+ {
+ E01X_send_packet(1);
+ bind_counter--;
+ }
+ }
+ else
+ E01X_send_packet(0);
+ return packet_period;
+}
+
+static void __attribute__((unused)) E012_initialize_txid()
+{
+ // rf channels
+ uint32_t lfsr=random(0xfefefefe);
+ for(uint8_t i=0; i> (i*8)) & 0xff) % 0x32);
+}
+
+uint16_t initE01X()
+{
+ BIND_IN_PROGRESS;
+ if(sub_protocol==E012)
+ {
+ E012_initialize_txid();
+ packet_period=E012_PACKET_PERIOD;
+ }
+ else
+ { // E015
+ packet_period=E015_PACKET_PERIOD;
+ rf_ch_num=E015_RF_CHANNEL;
+ armed = 0;
+ arm_flags = 0;
+ arm_channel_previous = E01X_ARM_SW;
+ }
+ E01X_init();
+ bind_counter = E01X_BIND_COUNT;
+ hopping_frequency_no = 0;
+ return E01X_INITIAL_WAIT;
+}
+
+#endif
diff --git a/Multiprotocol/Multi.txt b/Multiprotocol/Multi.txt
index b416a3b..8363a4c 100644
--- a/Multiprotocol/Multi.txt
+++ b/Multiprotocol/Multi.txt
@@ -42,4 +42,5 @@
42,BUGSMINI
43,Traxxas
44,NCC1701
+45,E01X,E012,E015
63,Test
diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h
index cbe3d3f..d8e8767 100644
--- a/Multiprotocol/Multiprotocol.h
+++ b/Multiprotocol/Multiprotocol.h
@@ -19,7 +19,7 @@
#define VERSION_MAJOR 1
#define VERSION_MINOR 2
#define VERSION_REVISION 1
-#define VERSION_PATCH_LEVEL 7
+#define VERSION_PATCH_LEVEL 8
//******************
// Protocols
diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino
index 48b9b55..4cfa344 100644
--- a/Multiprotocol/Multiprotocol.ino
+++ b/Multiprotocol/Multiprotocol.ino
@@ -110,6 +110,7 @@ uint16_t seed;
uint16_t failsafe_count;
uint16_t state;
uint8_t len;
+uint8_t armed, arm_flags, arm_channel_previous;
#if defined(FRSKYX_CC2500_INO) || defined(SFHSS_CC2500_INO)
uint8_t calData[48];
@@ -1199,6 +1200,12 @@ static void protocol_init()
remote_callback = NCC_callback;
break;
#endif
+ #if defined(E01X_NRF24L01_INO)
+ case PROTO_E01X:
+ next_callback=initE01X();
+ remote_callback = E01X_callback;
+ break;
+ #endif
#if defined(TEST_NRF24L01_INO)
case PROTO_TEST:
next_callback=initTest();
diff --git a/Multiprotocol/NRF24l01_SPI.ino b/Multiprotocol/NRF24l01_SPI.ino
index 881e0a9..8c5f12c 100644
--- a/Multiprotocol/NRF24l01_SPI.ino
+++ b/Multiprotocol/NRF24l01_SPI.ino
@@ -490,6 +490,109 @@ uint8_t XN297_ReadEnhancedPayload(uint8_t* msg, uint8_t len)
// End of XN297 emulation
+//
+// HS6200 emulation layer
+///////////////////////////
+static uint8_t hs6200_crc;
+static uint16_t hs6200_crc_init;
+static uint8_t hs6200_tx_addr[5];
+static uint8_t hs6200_address_length;
+
+static const uint8_t hs6200_scramble[] = {
+ 0x80,0xf5,0x3b,0x0d,0x6d,0x2a,0xf9,0xbc,
+ 0x51,0x8e,0x4c,0xfd,0xc1,0x65,0xd0 }; // todo: find all 32 bytes ...
+
+void HS6200_SetTXAddr(const uint8_t* addr, uint8_t len)
+{
+ if(len < 4)
+ len = 4;
+ else if(len > 5)
+ len = 5;
+
+ // use nrf24 address field as a longer preamble
+ if(addr[len-1] & 0x80)
+ NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\x55\x55\x55\x55\x55", 5);
+ else
+ NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\xaa\xaa\xaa\xaa\xaa", 5);
+
+ // precompute address crc
+ hs6200_crc_init = 0xffff;
+ for(int i=0; i 0)
+ crc = crc16_update(crc, msg[pos+1], 1);
+ return crc;
+}
+
+void HS6200_Configure(uint8_t flags)
+{
+ hs6200_crc = !!(flags & BV(NRF24L01_00_EN_CRC));
+ flags &= ~(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO));
+ NRF24L01_WriteReg(NRF24L01_00_CONFIG, flags & 0xff);
+}
+
+void HS6200_WritePayload(uint8_t* msg, uint8_t len)
+{
+ uint8_t payload[32];
+ const uint8_t no_ack = 1; // never ask for an ack
+ static uint8_t pid;
+ uint8_t pos = 0;
+
+ if(len > sizeof(hs6200_scramble))
+ len = sizeof(hs6200_scramble);
+
+ // address
+ for(int i=hs6200_address_length-1; i>=0; i--)
+ payload[pos++] = hs6200_tx_addr[i];
+
+ // guard bytes
+ payload[pos++] = hs6200_tx_addr[0];
+ payload[pos++] = hs6200_tx_addr[0];
+
+ // packet control field
+ payload[pos++] = ((len & 0x3f) << 2) | (pid & 0x03);
+ payload[pos] = (no_ack & 0x01) << 7;
+ pid++;
+
+ // scrambled payload
+ if(len > 0)
+ {
+ payload[pos++] |= (msg[0] ^ hs6200_scramble[0]) >> 1;
+ for(uint8_t i=1; i> 1);
+ payload[pos] = (msg[len-1] ^ hs6200_scramble[len-1]) << 7;
+ }
+
+ // crc
+ if(hs6200_crc)
+ {
+ uint16_t crc = hs6200_calc_crc(&payload[hs6200_address_length+2], len+2);
+ uint8_t hcrc = crc >> 8;
+ uint8_t lcrc = crc & 0xff;
+ payload[pos++] |= (hcrc >> 1);
+ payload[pos++] = (hcrc << 7) | (lcrc >> 1);
+ payload[pos++] = lcrc << 7;
+ }
+
+ NRF24L01_WritePayload(payload, pos);
+}
+//
+// End of HS6200 emulation
+////////////////////////////
+
///////////////
// LT8900 emulation layer
uint8_t LT8900_buffer[64];
diff --git a/Multiprotocol/Validate.h b/Multiprotocol/Validate.h
index af530a7..92ce4bc 100644
--- a/Multiprotocol/Validate.h
+++ b/Multiprotocol/Validate.h
@@ -183,6 +183,7 @@
#undef CFLIE_NRF24L01_INO
#undef BUGSMINI_NRF24L01_INO
#undef NCC1701_NRF24L01_INO
+ #undef E01X_NRF24L01_INO
#endif
//Make sure telemetry is selected correctly
diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h
index c21c081..720b861 100644
--- a/Multiprotocol/_Config.h
+++ b/Multiprotocol/_Config.h
@@ -196,7 +196,7 @@
#define SYMAX_NRF24L01_INO
#define V2X2_NRF24L01_INO
#define YD717_NRF24L01_INO
-
+#define E01X_NRF24L01_INO
/**************************/
/*** FAILSAFE SETTINGS ***/
@@ -578,6 +578,9 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
NONE
PROTO_NCC1701
NONE
+ PROTO_E01X
+ E012
+ E015
*/
// RX_Num is used for TX & RX match. Using different RX_Num values for each receiver will prevent starting a model with the false config loaded...