From 2a337bc8b6a1a2c07723a932f89ed97acbeaf5d5 Mon Sep 17 00:00:00 2001 From: Goebish Date: Fri, 12 Apr 2019 13:41:10 +0200 Subject: [PATCH 1/8] First attempt at adding the JJRC 345 protocol --- src/protocol/Makefile.inc | 6 + src/protocol/jjrc345_nrf24l01.c | 214 ++++++++++++++++++++++++++++++++ src/protocol/protocol.h | 1 + 3 files changed, 221 insertions(+) create mode 100644 src/protocol/jjrc345_nrf24l01.c diff --git a/src/protocol/Makefile.inc b/src/protocol/Makefile.inc index c9d32d23dd..54c2c3d8d5 100644 --- a/src/protocol/Makefile.inc +++ b/src/protocol/Makefile.inc @@ -61,6 +61,7 @@ PROTO_MODULES += $(ODIR)/protocol/loli.mod PROTO_MODULES += $(ODIR)/protocol/e016h.mod PROTO_MODULES += $(ODIR)/protocol/sumd.mod PROTO_MODULES += $(ODIR)/protocol/scancyrf.mod +PROTO_MODULES += $(ODIR)/protocol/jjrc345.mod ALL += $(PROTO_MODULES) else #BUILD_TARGET @@ -307,4 +308,9 @@ $(ODIR)/protocol/sumd.mod : $(ODIR)/sumd_uart.bin $(ODIR)/protocol/scancyrf.mod : $(ODIR)/scanner_cyrf6936.bin @echo Building 'scancyrf' module /bin/mkdir -p $(ODIR)/protocol/ 2>/dev/null; /bin/cp $< $@ + +$(ODIR)/protocol/jjrc345.mod : $(ODIR)/jjrc345_nrf24l01.bin + @echo Building 'jjrc345' module + /bin/mkdir -p $(ODIR)/protocol/ 2>/dev/null; /bin/cp $< $@ + endif #BUILD_TARGET diff --git a/src/protocol/jjrc345_nrf24l01.c b/src/protocol/jjrc345_nrf24l01.c new file mode 100644 index 0000000000..ccf8f4a9b4 --- /dev/null +++ b/src/protocol/jjrc345_nrf24l01.c @@ -0,0 +1,214 @@ +/* + 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 . + */ + +#ifdef MODULAR + // Allows the linker to properly relocate + #define JJRC345_Cmds PROTO_Cmds + #pragma long_calls +#endif +#include "common.h" +#include "interface.h" +#include "mixer.h" +#include "config/model.h" +#include "config/tx.h" // for Transmitter + +#ifdef PROTO_HAS_NRF24L01 + +#ifdef EMULATOR +#define USE_FIXED_MFGID +#define JJRC345_BIND_COUNT 20 +#define JJRC345_PACKET_PERIOD 100 +#define dbgprintf printf +#else +#define JJRC345_BIND_COUNT 500 +#define JJRC345_PACKET_PERIOD 4000 // Timeout for callback in uSec +#define dbgprintf if (0) printf +#endif + +#define JJRC345_INITIAL_WAIT 500 +#define JJRC345_PACKET_LEN 16 +#define JJRC345_RF_BIND_CHANNEL 5 +#define JJRC_NUM_CHANNELS 4 + +static u8 packet[JJRC345_PACKET_LEN]; +static u8 tx_power; +static u8 hopping_frequency[JJRC_NUM_CHANNELS]; +static u8 txid[2]; +static u8 hopping_frequency_no; +static u16 bind_counter; +static u8 phase; + +enum{ + JJRC345_BIND, + JJRC345_DATA +}; + +enum{ + CHANNEL1 = 0, + CHANNEL2, + CHANNEL3, + CHANNEL4, + CHANNEL5, + CHANNEL6 +}; + +// Bit vector from bit position +#define BV(bit) (1 << bit) + +static void JJRC345_init() +{ + NRF24L01_Initialize(); + NRF24L01_SetTxRxMode(TX_EN); + XN297_SetTXAddr((u8*)"\xcc\xcc\xcc\xcc\xcc", 5); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, JJRC345_RF_BIND_CHANNEL); // Bind channel + 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_02_EN_RXADDR, 0x01); // Enable data pipe 0 only + NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1 Mbps + NRF24L01_SetPower(tx_power); +} + +static void JJRC345_initialize_txid() +{ + // only fixed id for now + txid[0] = 0x1b; + txid[1] = 0x12; + + hopping_frequency[0] = 0x3f; + hopping_frequency[1] = 0x49; + hopping_frequency[2] = 0x47; + hopping_frequency[3] = 0x47; +} + +#define CHAN_RANGE (CHAN_MAX_VALUE - CHAN_MIN_VALUE) +static u16 scale_channel(u8 ch, u16 destMin, u16 destMax) +{ + s32 chanval = Channels[ch]; + s32 range = (s32) destMax - (s32) destMin; + + if (chanval < CHAN_MIN_VALUE) + chanval = CHAN_MIN_VALUE; + else if (chanval > CHAN_MAX_VALUE) + chanval = CHAN_MAX_VALUE; + return (range * (chanval - CHAN_MIN_VALUE)) / CHAN_RANGE + destMin; +} + +static void JJRC45_send_packet(u8 bind) +{ + packet[0] = 0x00; + packet[2] = 0x00; + packet[3] = 0x0a; + + if (bind) { + packet[1] = JJRC345_RF_BIND_CHANNEL; + packet[4] = hopping_frequency[0]; + packet[5] = hopping_frequency[1]; + packet[6] = hopping_frequency[2]; + packet[7] = hopping_frequency[3]; + packet[12] = 0xa5; + } + else + { + NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]); + if (hopping_frequency_no == JJRC_NUM_CHANNELS) + hopping_frequency_no = 0; + packet[1] = hopping_frequency[hopping_frequency_no]; // next packet will be sent on this channel + packet[4] = scale_channel(CHANNEL3, 0, 255); // throttle + packet[5] = scale_channel(CHANNEL4, 0xc1, 0x41); // rudder + packet[6] = scale_channel(CHANNEL2, 0x41, 0xc1); // elevator + packet[7] = scale_channel(CHANNEL1, 0xc1, 0x41); // aileron + packet[12] = 0x03; // high rates + } + + packet[8] = 0; // trim + packet[9] = 0; // trim + packet[10] = 0x40; // trim + + packet[11] = 0x3f; // ? + + // checksum + packet[13] = 0xf8; // not sure this is a constant + for (u8 i = 0; i < 13; i++) + packet[13] += packet[i]; + + // tx id ? + packet[14] = txid[0]; + packet[15] = txid[1]; + + XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP)); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); + NRF24L01_FlushTx(); + XN297_WritePayload(packet, JJRC345_PACKET_LEN); + + if (tx_power != Model.tx_power) { + // Keep transmit power updated + tx_power = Model.tx_power; + NRF24L01_SetPower(tx_power); + } +} + +static u16 JJRC345_callback() +{ + switch (phase) { + case JJRC345_BIND: + JJRC45_send_packet(1); + bind_counter--; + if (bind_counter == 0) + phase = JJRC345_DATA; + break; + case JJRC345_DATA: + JJRC45_send_packet(0); + break; + } + return JJRC345_PACKET_PERIOD; +} + +static void JJRC345_initialize() +{ + CLOCK_StopTimer(); + tx_power = Model.tx_power; + PROTOCOL_SetBindState((JJRC345_BIND_COUNT * JJRC345_PACKET_PERIOD)/1000); + JJRC345_initialize_txid(); + JJRC345_init(); + hopping_frequency_no = 0; + bind_counter = JJRC345_BIND_COUNT; + phase = JJRC345_BIND; + CLOCK_StartTimer(JJRC345_INITIAL_WAIT, JJRC345_callback); +} + +uintptr_t JJRC345_Cmds(enum ProtoCmds cmd) +{ + switch (cmd) { + case PROTOCMD_INIT: JJRC345_initialize(); return 0; + case PROTOCMD_DEINIT: + case PROTOCMD_RESET: + CLOCK_StopTimer(); + return (NRF24L01_Reset() ? 1 : -1); + case PROTOCMD_CHECK_AUTOBIND: return 1; + case PROTOCMD_BIND: JJRC345_initialize(); return 0; + case PROTOCMD_NUMCHAN: return 6; + case PROTOCMD_DEFAULT_NUMCHAN: return 6; + case PROTOCMD_CURRENT_ID: return Model.fixed_id; + case PROTOCMD_GETOPTIONS: return 0; + case PROTOCMD_TELEMETRYSTATE: return PROTO_TELEM_UNSUPPORTED; + case PROTOCMD_CHANNELMAP: return AETRG; + default: break; + } + return 0; +} + +#endif diff --git a/src/protocol/protocol.h b/src/protocol/protocol.h index e7a089cc98..1fb39d27e2 100644 --- a/src/protocol/protocol.h +++ b/src/protocol/protocol.h @@ -65,6 +65,7 @@ PROTODEF(PROTOCOL_V911S, NRF24L01, AETRG, V911S_Cmds, "V911S") PROTODEF(PROTOCOL_GD00X, NRF24L01, AETRG, GD00X_Cmds, "GD00X") PROTODEF(PROTOCOL_LOLI, NRF24L01, AETRG, LOLI_Cmds, "LOLI") PROTODEF(PROTOCOL_E016H, NRF24L01, AETRG, E016H_Cmds, "E016H") +PROTODEF(PROTOCOL_JJRC345, NRF24L01, AETRG, JJRC345_Cmds, "JJRC345") #endif //PROTO_HAS_NRF24L01 PROTODEF(PROTOCOL_PPM, TX_MODULE_LAST, NULL, PPMOUT_Cmds, "PPM") From b5484e1bcac6c8417d9f4432b0f97b891e6f8fe6 Mon Sep 17 00:00:00 2001 From: Goebish Date: Fri, 12 Apr 2019 13:42:37 +0200 Subject: [PATCH 2/8] Fix lint --- src/protocol/jjrc345_nrf24l01.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/protocol/jjrc345_nrf24l01.c b/src/protocol/jjrc345_nrf24l01.c index ccf8f4a9b4..d475b27109 100644 --- a/src/protocol/jjrc345_nrf24l01.c +++ b/src/protocol/jjrc345_nrf24l01.c @@ -133,11 +133,11 @@ static void JJRC45_send_packet(u8 bind) packet[7] = scale_channel(CHANNEL1, 0xc1, 0x41); // aileron packet[12] = 0x03; // high rates } - + packet[8] = 0; // trim packet[9] = 0; // trim - packet[10] = 0x40; // trim - + packet[10] = 0x40; // trim + packet[11] = 0x3f; // ? // checksum From 3211d8acefb00efc3c03d4355d3d5306642838bc Mon Sep 17 00:00:00 2001 From: Goebish Date: Fri, 12 Apr 2019 14:45:18 +0200 Subject: [PATCH 3/8] add packet period and original txid options --- src/protocol/jjrc345_nrf24l01.c | 35 +++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/protocol/jjrc345_nrf24l01.c b/src/protocol/jjrc345_nrf24l01.c index d475b27109..fad6929f4b 100644 --- a/src/protocol/jjrc345_nrf24l01.c +++ b/src/protocol/jjrc345_nrf24l01.c @@ -47,14 +47,27 @@ static u8 tx_power; static u8 hopping_frequency[JJRC_NUM_CHANNELS]; static u8 txid[2]; static u8 hopping_frequency_no; -static u16 bind_counter; static u8 phase; +static u16 bind_counter; enum{ JJRC345_BIND, JJRC345_DATA }; +static const char * const jjrc345_opts[] = { + _tr_noop("Period"), "1000", "20000", "100", NULL, + _tr_noop("Orig.ID"), "Yes", "No", NULL, + NULL +}; + +enum { + PROTOOPTS_PERIOD = 0, + PROTOOPTS_ORIGINAL_ID, + LAST_PROTO_OPT, +}; +ctassert(LAST_PROTO_OPT <= NUM_PROTO_OPTS, too_many_protocol_opts); + enum{ CHANNEL1 = 0, CHANNEL2, @@ -84,9 +97,16 @@ static void JJRC345_init() static void JJRC345_initialize_txid() { - // only fixed id for now - txid[0] = 0x1b; - txid[1] = 0x12; + if (Model.proto_opts[PROTOOPTS_ORIGINAL_ID] == 0) { + // only fixed id for now + txid[0] = 0x1b; + txid[1] = 0x12; + } + else // arbitrary ID + { + txid[0] = 0xf0; + txid[1] = 0x0d; + } hopping_frequency[0] = 0x3f; hopping_frequency[1] = 0x49; @@ -174,7 +194,7 @@ static u16 JJRC345_callback() JJRC45_send_packet(0); break; } - return JJRC345_PACKET_PERIOD; + return Model.proto_opts[PROTOOPTS_PERIOD]; } static void JJRC345_initialize() @@ -203,7 +223,10 @@ uintptr_t JJRC345_Cmds(enum ProtoCmds cmd) case PROTOCMD_NUMCHAN: return 6; case PROTOCMD_DEFAULT_NUMCHAN: return 6; case PROTOCMD_CURRENT_ID: return Model.fixed_id; - case PROTOCMD_GETOPTIONS: return 0; + case PROTOCMD_GETOPTIONS: + if (Model.proto_opts[PROTOOPTS_PERIOD] == 0) + Model.proto_opts[PROTOOPTS_PERIOD] = 4000; + return (uintptr_t)jjrc345_opts; case PROTOCMD_TELEMETRYSTATE: return PROTO_TELEM_UNSUPPORTED; case PROTOCMD_CHANNELMAP: return AETRG; default: break; From 9f7776c55615ebc86f2f423934218bf885f5b814 Mon Sep 17 00:00:00 2001 From: Goebish Date: Fri, 12 Apr 2019 15:12:29 +0200 Subject: [PATCH 4/8] Add arbitrary channels option --- src/protocol/jjrc345_nrf24l01.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/protocol/jjrc345_nrf24l01.c b/src/protocol/jjrc345_nrf24l01.c index fad6929f4b..0fc18b18c8 100644 --- a/src/protocol/jjrc345_nrf24l01.c +++ b/src/protocol/jjrc345_nrf24l01.c @@ -40,11 +40,11 @@ #define JJRC345_INITIAL_WAIT 500 #define JJRC345_PACKET_LEN 16 #define JJRC345_RF_BIND_CHANNEL 5 -#define JJRC_NUM_CHANNELS 4 +#define JJRC345_NUM_CHANNELS 4 static u8 packet[JJRC345_PACKET_LEN]; static u8 tx_power; -static u8 hopping_frequency[JJRC_NUM_CHANNELS]; +static u8 hopping_frequency[JJRC345_NUM_CHANNELS]; static u8 txid[2]; static u8 hopping_frequency_no; static u8 phase; @@ -58,12 +58,14 @@ enum{ static const char * const jjrc345_opts[] = { _tr_noop("Period"), "1000", "20000", "100", NULL, _tr_noop("Orig.ID"), "Yes", "No", NULL, + _tr_noop("Orig.Ch"), "Yes", "No", NULL, NULL }; enum { PROTOOPTS_PERIOD = 0, PROTOOPTS_ORIGINAL_ID, + PROTOOPTS_ORIGINAL_CH, LAST_PROTO_OPT, }; ctassert(LAST_PROTO_OPT <= NUM_PROTO_OPTS, too_many_protocol_opts); @@ -108,10 +110,20 @@ static void JJRC345_initialize_txid() txid[1] = 0x0d; } - hopping_frequency[0] = 0x3f; - hopping_frequency[1] = 0x49; - hopping_frequency[2] = 0x47; - hopping_frequency[3] = 0x47; + if (Model.proto_opts[PROTOOPTS_ORIGINAL_ID] == 0) { + // as dumped from origianl transmitter + hopping_frequency[0] = 0x3f; + hopping_frequency[1] = 0x49; + hopping_frequency[2] = 0x47; + hopping_frequency[3] = 0x47; + } + else // arbitrary channels + { + hopping_frequency[0] = 0x10; + hopping_frequency[1] = 0x20; + hopping_frequency[2] = 0x30; + hopping_frequency[3] = 0x40; + } } #define CHAN_RANGE (CHAN_MAX_VALUE - CHAN_MIN_VALUE) @@ -144,7 +156,7 @@ static void JJRC45_send_packet(u8 bind) else { NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]); - if (hopping_frequency_no == JJRC_NUM_CHANNELS) + if (hopping_frequency_no == JJRC345_NUM_CHANNELS) hopping_frequency_no = 0; packet[1] = hopping_frequency[hopping_frequency_no]; // next packet will be sent on this channel packet[4] = scale_channel(CHANNEL3, 0, 255); // throttle From d00843b1dd455daeccffbdde71d6201d6e395205 Mon Sep 17 00:00:00 2001 From: Goebish Date: Fri, 12 Apr 2019 16:19:43 +0200 Subject: [PATCH 5/8] Fix arbitrary channels option --- src/protocol/jjrc345_nrf24l01.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocol/jjrc345_nrf24l01.c b/src/protocol/jjrc345_nrf24l01.c index 0fc18b18c8..5fd614c9a9 100644 --- a/src/protocol/jjrc345_nrf24l01.c +++ b/src/protocol/jjrc345_nrf24l01.c @@ -110,8 +110,8 @@ static void JJRC345_initialize_txid() txid[1] = 0x0d; } - if (Model.proto_opts[PROTOOPTS_ORIGINAL_ID] == 0) { - // as dumped from origianl transmitter + if (Model.proto_opts[PROTOOPTS_ORIGINAL_CH] == 0) { + // as dumped from original transmitter hopping_frequency[0] = 0x3f; hopping_frequency[1] = 0x49; hopping_frequency[2] = 0x47; From 6ab4451f4fde9e9298e686a99f083403e82684ee Mon Sep 17 00:00:00 2001 From: Goebish Date: Wed, 17 Apr 2019 01:50:26 +0200 Subject: [PATCH 6/8] Fix rate flag --- src/protocol/jjrc345_nrf24l01.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/protocol/jjrc345_nrf24l01.c b/src/protocol/jjrc345_nrf24l01.c index 5fd614c9a9..7d47779fa7 100644 --- a/src/protocol/jjrc345_nrf24l01.c +++ b/src/protocol/jjrc345_nrf24l01.c @@ -143,7 +143,6 @@ static void JJRC45_send_packet(u8 bind) { packet[0] = 0x00; packet[2] = 0x00; - packet[3] = 0x0a; if (bind) { packet[1] = JJRC345_RF_BIND_CHANNEL; @@ -163,9 +162,10 @@ static void JJRC45_send_packet(u8 bind) packet[5] = scale_channel(CHANNEL4, 0xc1, 0x41); // rudder packet[6] = scale_channel(CHANNEL2, 0x41, 0xc1); // elevator packet[7] = scale_channel(CHANNEL1, 0xc1, 0x41); // aileron - packet[12] = 0x03; // high rates + packet[12] = 0x02; // high rates } - + packet[3] = (packet[4] == 0xff) ? 0x0e : 0x0a; + packet[8] = 0; // trim packet[9] = 0; // trim packet[10] = 0x40; // trim From fe74a71039c29008114af9d901f9f042eac813db Mon Sep 17 00:00:00 2001 From: Goebish Date: Wed, 17 Apr 2019 01:53:37 +0200 Subject: [PATCH 7/8] Fix lint --- src/protocol/jjrc345_nrf24l01.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocol/jjrc345_nrf24l01.c b/src/protocol/jjrc345_nrf24l01.c index 7d47779fa7..5fb2fd837f 100644 --- a/src/protocol/jjrc345_nrf24l01.c +++ b/src/protocol/jjrc345_nrf24l01.c @@ -165,7 +165,7 @@ static void JJRC45_send_packet(u8 bind) packet[12] = 0x02; // high rates } packet[3] = (packet[4] == 0xff) ? 0x0e : 0x0a; - + packet[8] = 0; // trim packet[9] = 0; // trim packet[10] = 0x40; // trim From d072d23072f5e1cc72a0bb3934cb67d991f9f5de Mon Sep 17 00:00:00 2001 From: Goebish Date: Wed, 17 Apr 2019 18:56:40 +0200 Subject: [PATCH 8/8] Add end of bind --- src/protocol/jjrc345_nrf24l01.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/protocol/jjrc345_nrf24l01.c b/src/protocol/jjrc345_nrf24l01.c index 5fb2fd837f..45ae876cfc 100644 --- a/src/protocol/jjrc345_nrf24l01.c +++ b/src/protocol/jjrc345_nrf24l01.c @@ -199,8 +199,10 @@ static u16 JJRC345_callback() case JJRC345_BIND: JJRC45_send_packet(1); bind_counter--; - if (bind_counter == 0) + if (bind_counter == 0) { phase = JJRC345_DATA; + PROTOCOL_SetBindState(0); + } break; case JJRC345_DATA: JJRC45_send_packet(0);