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...