From db017c73b68f07ccfb2b3c9096a46d03c587d7ec Mon Sep 17 00:00:00 2001 From: Pascal Langer Date: Sat, 13 Nov 2021 19:03:01 +0100 Subject: [PATCH] HS6200 emulation using CYRF for E01X protocol --- .../{E01X_nrf24l01.ino => E01X_cyrf6936.ino} | 55 +++++---- Multiprotocol/HS6200_EMU.ino | 112 ++++++++++++++++++ Multiprotocol/MT99xx_ccnrf.ino | 6 + Multiprotocol/Multi_Protos.ino | 4 +- Multiprotocol/Multiprotocol.h | 4 +- Multiprotocol/NRF24l01_SPI.ino | 106 ----------------- Multiprotocol/Validate.h | 2 +- Multiprotocol/_Config.h | 2 +- Multiprotocol/iface_hs6200.h | 13 ++ Protocols_Details.md | 42 ++++--- 10 files changed, 188 insertions(+), 158 deletions(-) rename Multiprotocol/{E01X_nrf24l01.ino => E01X_cyrf6936.ino} (85%) create mode 100644 Multiprotocol/HS6200_EMU.ino create mode 100644 Multiprotocol/iface_hs6200.h diff --git a/Multiprotocol/E01X_nrf24l01.ino b/Multiprotocol/E01X_cyrf6936.ino similarity index 85% rename from Multiprotocol/E01X_nrf24l01.ino rename to Multiprotocol/E01X_cyrf6936.ino index b0b59b8..821f4fb 100644 --- a/Multiprotocol/E01X_nrf24l01.ino +++ b/Multiprotocol/E01X_cyrf6936.ino @@ -14,9 +14,9 @@ */ // compatible with E012 and E015 -#if defined(E01X_NRF24L01_INO) +#if defined(E01X_CYRF6936_INO) -#include "iface_nrf24l01.h" +#include "iface_HS6200.h" //Protocols constants #define E01X_BIND_COUNT 500 @@ -28,7 +28,8 @@ #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_FORCE_ID +#define E015_PACKET_PERIOD 9000 #define E015_RF_CHANNEL 0x2d // 2445 MHz #define E015_PACKET_SIZE 10 #define E015_BIND_PACKET_SIZE 9 @@ -87,13 +88,15 @@ static void __attribute__((unused)) E01X_send_packet() packet[0] = rx_tx_addr[1]; if(IS_BIND_IN_PROGRESS) { + rf_ch_num = E012_RF_BIND_CHANNEL; 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 { + rf_ch_num = hopping_frequency[hopping_frequency_no++]; + hopping_frequency_no %= E012_NUM_RF_CHANNELS; packet[1] = 0x01 | GET_FLAG(E01X_RTH_SW, E012_FLAG_RTH) | GET_FLAG(E01X_HEADLESS_SW, E012_FLAG_HEADLESS) @@ -107,8 +110,6 @@ static void __attribute__((unused)) E01X_send_packet() 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; @@ -117,6 +118,7 @@ static void __attribute__((unused)) E01X_send_packet() } else { // E015 + rf_ch_num = E015_RF_CHANNEL; if(IS_BIND_IN_PROGRESS) { packet[0] = 0x18; @@ -124,10 +126,11 @@ static void __attribute__((unused)) E01X_send_packet() packet[2] = 0x06; // data phase address memcpy(&packet[3], rx_tx_addr, E01X_ADDRESS_LENGTH); + packet[8] = 0x63; // unknown calculation // checksum - packet[8] = packet[3]; - for(uint8_t i=4; i<8; i++) - packet[8] += packet[i]; + //packet[8] = packet[3]; + //for(uint8_t i=4; i<8; i++) + // packet[8] += packet[i]; packet_length=E015_BIND_PACKET_SIZE; } else @@ -154,24 +157,15 @@ static void __attribute__((unused)) E01X_send_packet() } } - 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(); - - 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(); + HS6200_RFChannel(rf_ch_num); + HS6200_SetPower(); + delayMicroseconds(270); // Wait for RF channel to settle + HS6200_SendPayload(packet, packet_length); } static void __attribute__((unused)) E01X_RF_init() { - NRF24L01_Initialize(); + HS6200_Init(true); // CRC enabled if(sub_protocol==E012) HS6200_SetTXAddr((uint8_t *)"\x55\x42\x9C\x8F\xC9", E01X_ADDRESS_LENGTH); @@ -218,8 +212,21 @@ void E01X_init() } else //E015 { + #ifdef E015_FORCE_ID + rx_tx_addr[0] = 0x06; + rx_tx_addr[1] = 0xC6; + rx_tx_addr[2] = 0xB7; + rx_tx_addr[3] = 0x56; + rx_tx_addr[4] = 0x8A; + #endif + + //force the sum to give 0x63 since the id calculation is unknown + uint8_t sum=0x63; + for(uint8_t i=0; i < 4; i++) + sum -= rx_tx_addr[i]; + rx_tx_addr[4] = sum; + packet_period=E015_PACKET_PERIOD; - rf_ch_num=E015_RF_CHANNEL; armed = 0; arm_flags = 0; arm_channel_previous = E01X_ARM_SW; diff --git a/Multiprotocol/HS6200_EMU.ino b/Multiprotocol/HS6200_EMU.ino new file mode 100644 index 0000000..dd359ae --- /dev/null +++ b/Multiprotocol/HS6200_EMU.ino @@ -0,0 +1,112 @@ +/* + 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 . + */ +#ifdef CYRF6936_INSTALLED +#include "iface_HS6200.h" + +static bool HS6200_crc; +static uint16_t HS6200_crc_init; +static uint8_t HS6200_address_length, HS6200_tx_addr[5]; + +static void __attribute__((unused)) HS6200_Init(bool crc_en) +{ + CYRF_GFSK1M_Init(32, 1); //Dummy number of bytes for now + HS6200_crc = crc_en; +} + +static void __attribute__((unused)) HS6200_SetTXAddr(const uint8_t* addr, uint8_t addr_len) +{ + // precompute address crc + crc = 0xffff; + for(uint8_t i=0; i 0) + crc16_update(msg[pos+1], 1); + return crc; +} + +static void __attribute__((unused)) HS6200_SendPayload(uint8_t* msg, uint8_t len) +{ + 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 ... + 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(int8_t 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; + } + + #if 0 + debug("E:"); + for(uint8_t i=0; iNRF24L01 PROTO_TRAXXAS = 43, // =>CYRF6936 PROTO_NCC1701 = 44, // =>NRF24L01 - PROTO_E01X = 45, // =>NRF24L01 + PROTO_E01X = 45, // =>CYRF6936 PROTO_V911S = 46, // =>NRF24L01 PROTO_GD00X = 47, // =>NRF24L01 PROTO_V761 = 48, // =>NRF24L01 diff --git a/Multiprotocol/NRF24l01_SPI.ino b/Multiprotocol/NRF24l01_SPI.ino index 4d527ef..106639e 100644 --- a/Multiprotocol/NRF24l01_SPI.ino +++ b/Multiprotocol/NRF24l01_SPI.ino @@ -244,112 +244,6 @@ uint8_t NRF24L01_packet_ack() return PKT_PENDING; } -// -// 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 - crc = 0xffff; - for(int i=0; i 0) - crc16_update(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); - delayMicroseconds(option+20); - 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 99a1408..08d9763 100644 --- a/Multiprotocol/Validate.h +++ b/Multiprotocol/Validate.h @@ -258,6 +258,7 @@ #undef DSM_CYRF6936_INO #undef DSM_RX_CYRF6936_INO #undef E010R5_CYRF6936_INO + #undef E01X_CYRF6936_INO #undef E129_CYRF6936_INO #undef J6PRO_CYRF6936_INO #undef LOSI_CYRF6936_INO @@ -295,7 +296,6 @@ #undef CX10_NRF24L01_INO #undef DM002_NRF24L01_INO #undef E016H_NRF24L01_INO - #undef E01X_NRF24L01_INO #undef ESKY_NRF24L01_INO #undef ESKY150_NRF24L01_INO #undef FQ777_NRF24L01_INO diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index ff3bc3a..87b459e 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -188,6 +188,7 @@ #define DSM_CYRF6936_INO #define DSM_RX_CYRF6936_INO #define E010R5_CYRF6936_INO +#define E01X_CYRF6936_INO #define E129_CYRF6936_INO #define J6PRO_CYRF6936_INO #define LOSI_CYRF6936_INO @@ -225,7 +226,6 @@ #define CX10_NRF24L01_INO //Include Q2X2 protocol #define DM002_NRF24L01_INO #define E016H_NRF24L01_INO -#define E01X_NRF24L01_INO #define ESKY_NRF24L01_INO #define ESKY150_NRF24L01_INO #define FQ777_NRF24L01_INO diff --git a/Multiprotocol/iface_hs6200.h b/Multiprotocol/iface_hs6200.h new file mode 100644 index 0000000..7081c00 --- /dev/null +++ b/Multiprotocol/iface_hs6200.h @@ -0,0 +1,13 @@ +#ifndef _IFACE_HS6200_H_ +#define _IFACE_HS6200_H_ + +#include "iface_cyrf6936.h" + +//HS6200 +static void __attribute__((unused)) HS6200_Init(bool); +static void __attribute__((unused)) HS6200_SetTXAddr(const uint8_t*, uint8_t); +static void __attribute__((unused)) HS6200_SendPayload(uint8_t*, uint8_t); +#define HS6200_SetPower() CYRF_GFSK1M_SetPower() +#define HS6200_RFChannel(X) CYRF_ConfigRFChannel(X) + +#endif diff --git a/Protocols_Details.md b/Protocols_Details.md index 83a104c..996d0f1 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -79,7 +79,7 @@ CFlie|38|CFlie||||||||NRF24L01| [E010R5](Protocols_Details.md#E010R5---81)|81|||||||||CYRF6936/NRF24L01|RF2500 [E016H](Protocols_Details.md#E016H---85)|85|||||||||NRF24L01|XN297 [E016HV2](Protocols_Details.md#E016HV2---80)|80|||||||||CC2500/NRF24L01|unknown -[E01X](Protocols_Details.md#E01X---45)|45|E012|E015|||||||NRF24L01|HS6200 +[E01X](Protocols_Details.md#E01X---45)|45|E012|E015|||||||CYRF6936|HS6200 [E129](Protocols_Details.md#E129---83)|83|||||||||CYRF6936/NRF24L01|RF2500 [ESky](Protocols_Details.md#ESKY---16)|16|ESky|ET4|||||||NRF24L01| [ESky150](Protocols_Details.md#ESKY150---35)|35|||||||||NRF24L01| @@ -576,6 +576,25 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10 ---|---|---|---|---|---|---|---|---|--- A|E|T|R|FLIP|LED|CALIB|HEADLESS|RTH|GLIDE +## E01X - *45* +Autobind protocol + +Not supported by Atmega328p modules. + +### Sub_protocol E012 - *0* +Models: Eachine E012 + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R||FLIP||HEADLESS|RTH + +### Sub_protocol E015 - *1* +Models: Eachine E015 + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R|ARM|FLIP|LED|HEADLESS|RTH + ## E129 - *83* Models: Eachine E129/E130 and Twister Ninja 250 @@ -1527,27 +1546,6 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 ---|---|---|---|---|---|---|---|--- A|E|T|R|STOP|FLIP|-|HEADLESS|RTH -## E01X - *45* -Autobind protocol - -### Sub_protocol E012 - *0* -Models: Eachine E012 - -This protocol has been reported to not work properly due to the emulation of the HS6200 RF component using the NRF24L01. The option value is used to adjust the timing, try every values between -127 and +127. If it works please report which value you've used. - -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 ----|---|---|---|---|---|---|---|--- -A|E|T|R||FLIP||HEADLESS|RTH - -### Sub_protocol E015 - *1* -Models: Eachine E015 - -This protocol has been reported to not work properly due to the emulation of the HS6200 RF component using the NRF24L01. The option value is used to adjust the timing, try every values between -127 and +127. If it works please report which value you've used. - -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 ----|---|---|---|---|---|---|---|--- -A|E|T|R|ARM|FLIP|LED|HEADLESS|RTH - ## ESKY - *16* CH1|CH2|CH3|CH4|CH5|CH6