HS6200 emulation using CYRF for E01X protocol

This commit is contained in:
Pascal Langer
2021-11-13 19:03:01 +01:00
parent 24aaa0dd0c
commit db017c73b6
10 changed files with 188 additions and 158 deletions

View File

@@ -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;

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#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<addr_len; i++)
crc16_update(addr[addr_len-1-i], 8);
HS6200_crc_init=crc;
memcpy(HS6200_tx_addr, addr, addr_len);
HS6200_address_length = addr_len;
}
static uint16_t __attribute__((unused)) HS6200_calc_crc(uint8_t* msg, uint8_t len)
{
uint8_t pos;
crc = HS6200_crc_init;
// pcf + payload
for(pos=0; pos < len-1; pos++)
crc16_update(msg[pos], 8);
// last byte (1 bit only)
if(len > 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<len; i++)
payload[pos++] = ((msg[i-1] ^ HS6200_scramble[i-1]) << 7) | ((msg[i] ^ HS6200_scramble[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; i<pos; i++)
debug(" %02X",payload[i]);
debugln("");
#endif
//CYRF wants LSB first
for(uint8_t i=0; i<pos; i++)
payload[i]=bit_reverse(payload[i]);
//Send
CYRF_WriteRegister(CYRF_01_TX_LENGTH, pos);
CYRF_GFSK1M_SendPayload(payload, pos);
}
#endif

View File

@@ -285,6 +285,12 @@ static void __attribute__((unused)) MT99XX_send_packet()
XN297_SetFreqOffset();
XN297_SetTxRxMode(TX_EN);
XN297_WritePayload(packet, MT99XX_PACKET_SIZE);
#if 0
for(uint8_t i=0; i<MT99XX_PACKET_SIZE; i++)
debug(" %02X",packet[i]);
debugln();
#endif
}
static void __attribute__((unused)) MT99XX_RF_init()

View File

@@ -247,8 +247,8 @@ const mm_protocol_definition multi_protocols[] = {
#if defined(E016HV2_CC2500_INO)
{PROTO_E016HV2, STR_E016HV2, NO_SUBTYPE, 0, OPTION_RFTUNE, 0, 0, SW_CC2500, E016HV2_init, E016HV2_callback },
#endif
#if defined(E01X_NRF24L01_INO)
{PROTO_E01X, STR_E01X, STR_SUBTYPE_E01X, 2, OPTION_OPTION, 0, 0, SW_NRF, E01X_init, E01X_callback },
#if defined(E01X_CYRF6936_INO)
{PROTO_E01X, STR_E01X, STR_SUBTYPE_E01X, 2, OPTION_NONE, 0, 0, SW_CYRF, E01X_init, E01X_callback },
#endif
#if defined(E129_CYRF6936_INO)
{PROTO_E129, STR_E129, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_CYRF, E129_init, E129_callback },

View File

@@ -19,7 +19,7 @@
#define VERSION_MAJOR 1
#define VERSION_MINOR 3
#define VERSION_REVISION 3
#define VERSION_PATCH_LEVEL 4
#define VERSION_PATCH_LEVEL 6
#define MODE_SERIAL 0
@@ -73,7 +73,7 @@ enum PROTOCOLS
PROTO_BUGSMINI = 42, // =>NRF24L01
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

View File

@@ -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<len; i++)
crc16_update(addr[len-1-i], 8);
hs6200_crc_init=crc;
memcpy(hs6200_tx_addr, addr, len);
hs6200_address_length = len;
}
static uint16_t hs6200_calc_crc(uint8_t* msg, uint8_t len)
{
uint8_t pos;
crc = hs6200_crc_init;
// pcf + payload
for(pos=0; pos < len-1; pos++)
crc16_update(msg[pos], 8);
// last byte (1 bit only)
if(len > 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<len; i++)
payload[pos++] = ((msg[i-1] ^ hs6200_scramble[i-1]) << 7) | ((msg[i] ^ hs6200_scramble[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];

View File

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

View File

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

View File

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