diff --git a/.gitmodules b/.gitmodules
index 80a95d75ad..545c8e91f6 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,4 +1,3 @@
-[submodule "libopencm3"]
+[submodule "src/libopencm3"]
path = src/libopencm3
- url = https://github.com/DeviationTx/libopencm3.git
- branch = stm32f2_adc
+ url = https://github.com/libopencm3/libopencm3.git
diff --git a/src/.vscode/settings.json b/src/.vscode/settings.json
new file mode 100644
index 0000000000..c7f6a46606
--- /dev/null
+++ b/src/.vscode/settings.json
@@ -0,0 +1,11 @@
+{
+ "files.associations": {
+ "limits": "cpp",
+ "protocol.h": "c",
+ "interface.h": "c",
+ "mixer.h": "c",
+ "model.h": "c",
+ "tx.h": "c",
+ "*.tcc": "c"
+ }
+}
\ No newline at end of file
diff --git a/src/libopencm3 b/src/libopencm3
index d55bbafddb..6763681c26 160000
--- a/src/libopencm3
+++ b/src/libopencm3
@@ -1 +1 @@
-Subproject commit d55bbafddb9768228748f48a82967f91a910806e
+Subproject commit 6763681c260cf280487d70ca0d1996a8b79fff30
diff --git a/src/protocol/Makefile.inc b/src/protocol/Makefile.inc
index 15c03d346e..a701442a67 100644
--- a/src/protocol/Makefile.inc
+++ b/src/protocol/Makefile.inc
@@ -60,6 +60,7 @@ PROTO_MODULES += $(ODIR)/protocol/pxx.mod
PROTO_MODULES += $(ODIR)/protocol/loli.mod
PROTO_MODULES += $(ODIR)/protocol/e016h.mod
PROTO_MODULES += $(ODIR)/protocol/sumd.mod
+PROTO_MODULES += $(ODIR)/protocol/omp.mod
ifeq "$(SUPPORT_SCANNER)" "1"
PROTO_MODULES += $(ODIR)/protocol/scancyrf.mod
endif
@@ -328,6 +329,10 @@ $(ODIR)/protocol/e010.mod : $(ODIR)/e010_cc2500.bin
@echo Building 'e010' module
/bin/mkdir -p $(ODIR)/protocol/ 2>/dev/null; /bin/cp $< $@
+$(ODIR)/protocol/omp.mod : $(ODIR)/omp_cc2500.bin
+ @echo Building 'omp' module
+ /bin/mkdir -p $(ODIR)/protocol/ 2>/dev/null; /bin/cp $< $@
+
$(ODIR)/protocol/v761.mod : $(ODIR)/v761_nrf24l01.bin
@echo Building 'v761' module
/bin/mkdir -p $(ODIR)/protocol/ 2>/dev/null; /bin/cp $< $@
diff --git a/src/protocol/e010_cc2500.c b/src/protocol/e010_cc2500.c
index c197f6ebf3..f0631916b7 100644
--- a/src/protocol/e010_cc2500.c
+++ b/src/protocol/e010_cc2500.c
@@ -106,6 +106,7 @@ e010_tx_rf_map[] = { {{0x4F, 0x1C}, {0x3A, 0x35, 0x4A, 0x45}},
{{0xFD, 0x4F}, {0x33, 0x3B, 0x43, 0x4B}},
{{0x86, 0x3C}, {0x34, 0x3E, 0x44, 0x4E}} };
+/*
// xn297 emulation
////////////////////
static u8 xn297_addr_len;
@@ -213,6 +214,7 @@ static void XN297L_WritePayload(const u8* msg, u8 len)
// end of xn297 emulation
///////////////////////////
+*/
// Bit vector from bit position
#define BV(bit) (1 << bit)
@@ -300,7 +302,7 @@ static void send_packet(u8 bind)
static void e010_init()
{
u8 rx_tx_addr[ADDRESS_LENGTH];
- XN297L_init(); // setup cc2500 for xn297L@250kbps emulation
+ XN297L_Configure(XN297L_SCRAMBLED, XN297L_CRC, PACKET_SIZE+8); // setup cc2500 for xn297L@250kbps emulation packet_size(16) + 5byte address + + 2byte crc + 1byte preamble (0x55)
CC2500_WriteReg(CC2500_0C_FSCTRL0, fine);
memcpy(rx_tx_addr, "\x6d\x6a\x77\x77\x77", sizeof(rx_tx_addr));
memcpy(rf_channels, "\x36\x3e\x46\x2e", sizeof(rf_channels));
diff --git a/src/protocol/iface_cc2500.h b/src/protocol/iface_cc2500.h
index 4e8f645671..f3a69acc9c 100644
--- a/src/protocol/iface_cc2500.h
+++ b/src/protocol/iface_cc2500.h
@@ -135,4 +135,24 @@ void CC2500_WriteData(u8 *packet, u8 length);
void CC2500_ReadData(u8 *dpbuffer, int len);
void CC2500_SetTxRxMode(enum TXRX_State);
void CC2500_SetPower(int power);
+
+void XN297L_Configure(u8 scramble_en, u8 crc_en, u8 cc2500_packet_len);
+void XN297L_SetTXAddr(const u8* addr, u8 len);
+void XN297L_SetRXAddr(const u8* addr, u8 len);
+void XN297L_WritePayload(u8* msg, u8 len);
+void XN297L_SetChannel(u8 ch);
+void XN297L_SetScrambledMode(const u8 mode);
+void XN297L_WriteEnhancedPayload(u8* msg, u8 len, u8 noack);
+u8 _xn297l_write_enhancedpayload(const u8* msg, u8 len, u8* out, u8 noack);
+u8 _xn297l_write_payload(const u8* msg, u8 len, u8* out);
+u8 XN297L_ReadPayload(u8* msg, u8 len);
+u8 XN297L_ReadEnhancedPayload(u8* msg, u8 len);
+#define XN297L_UNSCRAMBLED 0
+#define XN297L_SCRAMBLED 1
+#define XN297L_NOCRC 0
+#define XN297L_CRC 1
+
+u16 crc16_update(u16 crc, u8 a, u8 bits);
+u8 bit_reverse(u8 b_in);
+
#endif
diff --git a/src/protocol/iface_nrf24l01.h b/src/protocol/iface_nrf24l01.h
index 6039ae5354..050120f514 100644
--- a/src/protocol/iface_nrf24l01.h
+++ b/src/protocol/iface_nrf24l01.h
@@ -145,17 +145,20 @@ enum {
extern const u8 xn297_scramble[];
extern const u16 xn297_crc_xorout_scrambled[];
extern const u16 xn297_crc_xorout[];
-uint8_t bit_reverse(uint8_t b_in);
+extern const u16 xn297_crc_xorout_scrambled_enhanced[];
+extern const u16 xn297_crc_xorout_enhanced[];
-void XN297_SetTXAddr(const u8* addr, int len);
-void XN297_SetRXAddr(const u8* addr, int len);
+// uint8_t bit_reverse(uint8_t b_in);
+
+void XN297_SetTXAddr(const u8* addr, u8 len);
+void XN297_SetRXAddr(const u8* addr, u8 len);
void XN297_Configure(u8 flags);
void XN297_SetScrambledMode(const u8 mode);
u8 XN297_WritePayload(u8* msg, int len);
-u8 XN297_WriteEnhancedPayload(u8* msg, int len, int noack, u16 crc_xorout);
-u8 XN297_ReadPayload(u8* msg, int len);
-u8 XN297_ReadEnhancedPayload(u8* msg, int len);
-u16 crc16_update(u16 crc, u8 a, u8 bits);
+u8 XN297_WriteEnhancedPayload(u8* msg, u8 len, u8 noack, u16 crc_xorout);
+u8 XN297_ReadPayload(u8* msg, u8 len);
+u8 XN297_ReadEnhancedPayload(u8* msg, u8 len);
+// u16 crc16_update(u16 crc, u8 a, u8 bits);
// HS6200 emulation layer
void HS6200_SetTXAddr(const u8* addr, u8 len);
diff --git a/src/protocol/omp_cc2500.c b/src/protocol/omp_cc2500.c
new file mode 100755
index 0000000000..b285cd56f5
--- /dev/null
+++ b/src/protocol/omp_cc2500.c
@@ -0,0 +1,445 @@
+/*
+ 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 .
+ */
+
+#include "common.h"
+#include "interface.h"
+#include "mixer.h"
+#include "config/model.h"
+#include "config/tx.h" // for Transmitter
+
+
+#ifdef PROTO_HAS_CC2500
+
+#ifdef EMULATOR
+#define USE_FIXED_MFGID
+#define OMP_BIND_COUNT 20
+#define OMP_PACKET_PERIOD 100
+#define dbgprintf printf
+#else
+#define OMP_BIND_COUNT 100
+#define OMP_PACKET_PERIOD 5000 // Timeout for callback in uSec
+// printf inside an interrupt handler is really dangerous
+// this shouldn't be enabled even in debug builds without explicitly
+// turning it on
+#define dbgprintf if (0) printf
+#endif
+
+#define OMP_PACKET_SIZE 16
+#define OMP_RF_BIND_CHANNEL 35
+#define OMP_NUM_RF_CHANNELS 8
+#define OMP_ADDR_LEN 5
+
+
+static const char * const omp_opts[] = {
+ _tr_noop("Freq-Fine"), "-127", "127", NULL,
+ _tr_noop("Telemetry"), _tr_noop("On"), _tr_noop("Off"), NULL,
+ NULL
+};
+
+enum {
+ PROTOOPTS_FREQFINE = 0,
+ PROTOOPTS_TELEMETRY,
+ LAST_PROTO_OPT,
+};
+
+ctassert(LAST_PROTO_OPT <= NUM_PROTO_OPTS, too_many_protocol_opts);
+
+#define TELEM_ON 0
+#define TELEM_OFF 1
+
+
+static u8 tx_power;
+static u8 packet[16];
+static u8 hopping_frequency_no = 0;
+static u8 rx_tx_addr[5];
+static u8 hopping_frequency[OMP_NUM_RF_CHANNELS];
+static u16 bind_counter;
+static u8 phase;
+static u8 calibration[OMP_NUM_RF_CHANNELS];
+static u8 calibration_fscal2;
+static u8 calibration_fscal3;
+static s8 fine;
+static u8 telm_req = 0;
+static u16 tx_wait = 0;
+static u8 last_good_v_lipo = 0;
+
+
+enum{
+ OMP_BIND,
+ OMP_DATA,
+ OMP_PACKET_SEND,
+};
+
+enum {
+ CHANNEL1 = 0,
+ CHANNEL2,
+ CHANNEL3,
+ CHANNEL4,
+ CHANNEL5,
+ CHANNEL6,
+ CHANNEL7,
+};
+
+// Bit vector from bit position
+#define BV(bit) (1 << bit)
+
+#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;
+}
+
+#define GET_FLAG(ch, mask) (Channels[ch] > 0 ? mask : 0)
+
+
+// calibrate used RF channels for faster hopping
+static void calibrate_rf_chans()
+{
+ for (int c = 0; c < OMP_NUM_RF_CHANNELS; c++) {
+ CLOCK_ResetWatchdog();
+ CC2500_Strobe(CC2500_SIDLE);
+ XN297L_SetChannel(hopping_frequency[c]);
+ CC2500_Strobe(CC2500_SCAL);
+ usleep(900);
+ calibration[c] = CC2500_ReadReg(CC2500_25_FSCAL1);
+ }
+ calibration_fscal3 = CC2500_ReadReg(CC2500_23_FSCAL3); // only needs to be done once
+ calibration_fscal2 = CC2500_ReadReg(CC2500_24_FSCAL2); // only needs to be done once
+ CC2500_Strobe(CC2500_SIDLE);
+}
+
+static void calc_fh_channels(u8 num_ch)
+{
+ u8 idx = 0;
+ u32 rnd = Model.fixed_id;
+ u8 max = (num_ch/3)+2;
+
+ while (idx < num_ch)
+ {
+ u8 i;
+ u8 count_2_26 = 0, count_27_50 = 0, count_51_74 = 0;
+
+ rnd = rnd * 0x0019660D + 0x3C6EF35F; // Randomization
+ // Use least-significant byte. 73 is prime, so channels 76..77 are unused
+ u8 next_ch = ((rnd >> 8) % 73) + 2;
+ // Keep a distance of 5 between consecutive channels
+ if (idx !=0)
+ {
+ if (hopping_frequency[idx-1] > next_ch)
+ {
+ if (hopping_frequency[idx-1] - next_ch < 5)
+ continue;
+ }
+ else
+ if (next_ch-hopping_frequency[idx-1] < 5)
+ continue;
+ }
+ // Check that it's not duplicated and spread uniformly
+ for (i = 0; i < idx; i++) {
+ if (hopping_frequency[i] == next_ch)
+ break;
+ if (hopping_frequency[i] <= 26)
+ count_2_26++;
+ else if (hopping_frequency[i] <= 50)
+ count_27_50++;
+ else
+ count_51_74++;
+ }
+ if (i != idx)
+ continue;
+ if ( (next_ch <= 26 && count_2_26 < max) || (next_ch >= 27 && next_ch <= 50 && count_27_50 < max) || (next_ch >= 51 && count_51_74 < max) )
+ hopping_frequency[idx++] = next_ch; // find hopping frequency
+ }
+}
+
+static void omp_update_telemetry()
+{
+// raw receive data first byte should be 0x55 (last xn297l preamble word) and then 5 byte address + 2byte PCF + 16byte payload +2 byte crc, total=1+5+2+16+2=26
+// packet_in = 01 00 98 2C 03 19 19 F0 49 02 00 00 00 00 00 00
+// all bytes are fixed and unknown except 2 and 3 which represent the battery voltage: packet_in[3]*256+packet_in[2]=lipo voltage*100 in V
+ const u8 *update = NULL;
+ static const u8 omp_telem[] = { TELEM_DEVO_VOLT1, TELEM_DEVO_RPM1, TELEM_DEVO_RPM2, 0 }; // use TELEM_DEVO_RPM1 for LRSSI, TELEM_DEVO_RPM2 for LQI
+
+ u16 V = 0;
+ u8 telem_len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
+
+ if (telem_len == 28) // 26 plus 2byte append rx_status(RSSI+LQI)
+ {
+ u8 crc_ok = XN297L_ReadEnhancedPayload(packet, telem_len);
+
+ if (crc_ok)
+ { // packet with good CRC and length
+ V = ((packet[3] << 8) + packet[2]) / 100;
+ last_good_v_lipo = V;
+ Telemetry.value[TELEM_DEVO_VOLT1] = V;
+ Telemetry.value[TELEM_DEVO_RPM1] = ((s8)crc_ok) / 2 - 72; // rssi to dbm
+ update = omp_telem;
+ }
+ else
+ { // As soon as the motor spins the telem packets are becoming really bad and the CRC throws most of them in error as it should but...
+ if (packet[0] == 0x01 && packet[1] == 0x00)
+ { // the start of the packet looks ok...
+ V = ((packet[3] << 8) + packet[2]) / 100;
+ if (V < 130 && V > 60)
+ { // voltage is less than 13V and more than 6V (3V/element)
+ u16 v1 = V - last_good_v_lipo;
+ if (v1&0x8000) v1 = -v1;
+ if (v1 < 10) // the batt voltage is within 1V from a good reading...
+ {
+ Telemetry.value[TELEM_DEVO_VOLT1] = V;
+ update = omp_telem;
+ }
+ }
+ }
+ }
+ Telemetry.value[TELEM_DEVO_RPM2] = CC2500_ReadReg(CC2500_33_LQI | CC2500_READ_BURST) & 0x7F;
+ update = omp_telem;
+ }
+ CC2500_Strobe(CC2500_SFRX);
+ CC2500_Strobe(CC2500_SIDLE);
+ CC2500_SetTxRxMode(TXRX_OFF);
+ if (update)
+ {
+ while (*update) {
+ TELEMETRY_SetUpdated(*update++);
+ }
+ }
+}
+
+static void OMP_send_packet(u8 bind)
+{
+ CC2500_SetTxRxMode(TX_EN);
+ CLOCK_ResetWatchdog();
+ CLOCK_RunMixer();
+ if (!bind)
+ {
+ memset(packet, 0x00, OMP_PACKET_SIZE);
+ packet[0] = hopping_frequency_no;
+ telm_req++;
+ telm_req %= OMP_NUM_RF_CHANNELS-1; // Change telem RX channels every time
+
+ if (telm_req == 0)
+ packet[0] |= 0x40;
+ CC2500_WriteReg(CC2500_23_FSCAL3, calibration_fscal3);
+ CC2500_WriteReg(CC2500_24_FSCAL2, calibration_fscal2);
+ CC2500_WriteReg(CC2500_25_FSCAL1, calibration[hopping_frequency_no]);
+ XN297L_SetChannel(hopping_frequency[hopping_frequency_no]);
+ hopping_frequency_no++;
+ hopping_frequency_no &= OMP_NUM_RF_CHANNELS-1;
+
+ packet[1] = 0x08 // unknown
+ | GET_FLAG(CHANNEL5, 0x20); // HOLD
+ packet[2] = 0x40; // unknown
+ u16 ch = scale_channel(CHANNEL6, 0, 0x7FF); // throttle
+ if (ch > 0x600)
+ packet[2] |= 0x20; // IDLE2
+ else if (ch > 0x200)
+ packet[1] |= 0x40; // IDLE1
+ ch = scale_channel(CHANNEL7, 0, 0x7FF); // throttle
+ if (ch > 0x600)
+ packet[2] |= 0x08; // 3D
+ else if (ch > 0x200)
+ packet[2] |= 0x04; // ATTITUDE
+ ch = scale_channel(CHANNEL3, 0, 0x7FF); // throttle
+ packet[7] = ch;
+ packet[8] = ch >> 8;
+ ch = scale_channel(CHANNEL1, 0, 0x7FF); // aileron
+ packet[8] |= ch << 3;
+ packet[9] = ch >> 5;
+ ch = scale_channel(CHANNEL2, 0, 0x7FF); // elevator
+ packet[9] |= ch << 6;
+ packet[10] = ch >> 2;
+ packet[11] = ch >> 10;
+ ch = scale_channel(CHANNEL4, 0, 0x7FF); // rudder
+ packet[11] |= ch << 1;
+ packet[12] = ch >> 7;
+ packet[15] = 0x04;
+ }
+
+ XN297L_WriteEnhancedPayload(packet, OMP_PACKET_SIZE, telm_req != 0); // ack/8packet
+
+ if (tx_power != Model.tx_power) // Keep transmit power updated
+ {
+ tx_power = Model.tx_power;
+ CC2500_SetPower(tx_power);
+ }
+}
+
+
+static u16 OMP_callback()
+{
+ u16 timeout = OMP_PACKET_PERIOD;
+ if (fine != (s8)Model.proto_opts[PROTOOPTS_FREQFINE])
+ {
+ fine = (s8)Model.proto_opts[PROTOOPTS_FREQFINE];
+ CC2500_WriteReg(CC2500_0C_FSCTRL0, fine);
+ }
+ switch (phase) {
+ case OMP_BIND:
+ if (bind_counter == 0)
+ {
+ PROTOCOL_SetBindState(0);
+ XN297L_SetTXAddr(rx_tx_addr, 5);
+ phase = OMP_DATA;
+ }
+ else
+ {
+ OMP_send_packet(1);
+ bind_counter--;
+ }
+ break;
+
+ case OMP_DATA:
+ OMP_send_packet(0);
+ phase = OMP_PACKET_SEND;
+ timeout = 1250;
+ tx_wait = 0;
+ break;
+
+ case OMP_PACKET_SEND:
+ if (CC2500_ReadReg(CC2500_35_MARCSTATE | CC2500_READ_BURST) == 0x13)
+ {
+ timeout = 50;
+ tx_wait += 50;
+ if (tx_wait > 1000)
+ {
+ phase = OMP_DATA;
+ timeout = OMP_PACKET_PERIOD-2250;
+ }
+ break;
+ }
+ CC2500_Strobe(CC2500_SIDLE);
+ CC2500_SetTxRxMode(TXRX_OFF);
+ timeout = OMP_PACKET_PERIOD-1250-tx_wait;
+ phase = OMP_DATA;
+
+ if (Model.proto_opts[PROTOOPTS_TELEMETRY])
+ break;
+
+ switch (telm_req)
+ {
+ case 0:
+ CC2500_SetTxRxMode(RX_EN);
+ CC2500_Strobe(CC2500_SFRX);
+ CC2500_Strobe(CC2500_SRX);
+ break;
+ case 1:
+ omp_update_telemetry();
+ timeout -= 50;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ return timeout;
+}
+
+static void OMP_init()
+{
+ // setup cc2500 for xn297L@250kbps emulation, scrambled, crc enabled
+ XN297L_Configure(XN297L_SCRAMBLED, XN297L_CRC, OMP_PACKET_SIZE+10); // packet_size + 5byte address + 2 byte pcf + 2byte crc + 1byte preamble
+ calibrate_rf_chans();
+ CC2500_SetPower(tx_power);
+}
+
+static void OMP_initialize_txid()
+{
+ u32 lfsr = 0xb2c54a2ful;
+ u8 i, j;
+
+ if (Model.fixed_id) {
+ for (i = 0, j = 0; i < sizeof(Model.fixed_id); ++i, j += 8)
+ rand32_r(&lfsr, (Model.fixed_id >> j) & 0xff);
+ }
+ // Pump zero bytes for LFSR to diverge more
+ for (i = 0; i < sizeof(lfsr); ++i) rand32_r(&lfsr, 0);
+
+ for (i=0, j=0; i < 4; i++, j+=8)
+ rx_tx_addr[i] = (lfsr >> j) & 0xff;
+
+ rand32_r(&lfsr, 0);
+ rx_tx_addr[4] = lfsr & 0xff;
+ // channels
+ calc_fh_channels(OMP_NUM_RF_CHANNELS);
+}
+
+static void initialize(u8 bind)
+{
+ CLOCK_StopTimer();
+ OMP_initialize_txid();
+
+ tx_power = Model.tx_power;
+ OMP_init();
+
+ fine = (s8)Model.proto_opts[PROTOOPTS_FREQFINE];
+ CC2500_WriteReg(CC2500_0C_FSCTRL0, fine);
+
+ if (bind)
+ {
+ bind_counter = OMP_BIND_COUNT;
+ PROTOCOL_SetBindState(OMP_BIND_COUNT * OMP_PACKET_PERIOD / 1000);
+ phase = OMP_BIND;
+ XN297L_SetTXAddr((u8*)"FLPBD", OMP_ADDR_LEN);
+ XN297L_SetChannel(OMP_RF_BIND_CHANNEL);
+ CC2500_Strobe(CC2500_SCAL);
+ usleep(900);
+ CC2500_Strobe(CC2500_SIDLE);
+ memset(packet, 0x00, OMP_PACKET_SIZE);
+ memcpy(packet, "BND", 3);
+ memcpy(&packet[3], rx_tx_addr, 5);
+ memcpy(&packet[8], hopping_frequency, 8);
+ }
+ else
+ {
+ XN297L_SetTXAddr(rx_tx_addr, OMP_ADDR_LEN);
+ XN297L_SetRXAddr(rx_tx_addr, OMP_ADDR_LEN);
+ phase = OMP_DATA;
+ }
+
+ CLOCK_StartTimer(OMP_PACKET_PERIOD, OMP_callback);
+}
+
+uintptr_t OMP_Cmds(enum ProtoCmds cmd)
+{
+ switch (cmd) {
+ case PROTOCMD_INIT: initialize(0); return 0;
+ case PROTOCMD_DEINIT:
+ case PROTOCMD_RESET:
+ CLOCK_StopTimer();
+ return (CC2500_Reset() ? 1 : -1);
+ case PROTOCMD_CHECK_AUTOBIND: return 0;
+ case PROTOCMD_BIND: initialize(1); return 0;
+ case PROTOCMD_NUMCHAN: return 7;
+ case PROTOCMD_DEFAULT_NUMCHAN: return 7;
+ case PROTOCMD_CURRENT_ID: return Model.fixed_id;
+ case PROTOCMD_GETOPTIONS: return (uintptr_t)omp_opts;
+ case PROTOCMD_TELEMETRYSTATE:
+ return (Model.proto_opts[PROTOOPTS_TELEMETRY] != TELEM_OFF ? PROTO_TELEM_ON : PROTO_TELEM_OFF);
+ case PROTOCMD_TELEMETRYTYPE:
+ return TELEM_DEVO;
+ case PROTOCMD_CHANNELMAP: return AETRG;
+ default: break;
+ }
+ return 0;
+}
+
+#endif
diff --git a/src/protocol/protocol.h b/src/protocol/protocol.h
index b33a8d66e0..75bf177822 100644
--- a/src/protocol/protocol.h
+++ b/src/protocol/protocol.h
@@ -30,6 +30,7 @@ PROTODEF(PROTOCOL_SFHSS, CC2500, AETRG, SFHSS_Cmds, "S-FHSS")
PROTODEF(PROTOCOL_CORONA, CC2500, AETRG, Corona_Cmds, "Corona")
PROTODEF(PROTOCOL_HITEC, CC2500, AETRG, Hitec_Cmds, "Hitec")
PROTODEF(PROTOCOL_E010, CC2500, AETRG, E010_Cmds, "E010")
+PROTODEF(PROTOCOL_OMP, CC2500, AETRG, OMP_Cmds, "OMP")
#endif //PROTO_HAS_CC2500
#ifdef PROTO_HAS_NRF24L01
PROTODEF(PROTOCOL_V202, NRF24L01, AETRG, V202_Cmds, "V202")
diff --git a/src/protocol/spi/cc2500.c b/src/protocol/spi/cc2500.c
index ae6ec9f1f3..813515d3c2 100644
--- a/src/protocol/spi/cc2500.c
+++ b/src/protocol/spi/cc2500.c
@@ -135,4 +135,389 @@ int CC2500_Reset()
CC2500_SetTxRxMode(TXRX_OFF);
return CC2500_ReadReg(CC2500_0E_FREQ1) == 0xC4;
}
+
+// XN297 EMU
+
+u8 xn297_crc;
+u8 xn297_scramble_enabled;
+u8 xn297_addr_len;
+u8 xn297_tx_addr[5];
+u8 xn297_rx_addr[5];
+
+void XN297L_Configure(u8 scramble_en, u8 crc_en, u8 cc2500_packet_len)
+{
+ // Address Config = check for (0x55)
+ // Base Frequency = 2400
+ // CRC Autoflush = false
+ // CRC Enable = false
+ // Carrier Frequency = 2400
+ // Channel Number = 0
+ // Channel Spacing = 333.251953
+ // Data Format = Normal mode
+ // Data Rate = 249.939
+ // Deviation = 126.953125
+ // Device Address = 0
+ // Manchester Enable = false
+ // Modulated = true
+ // Modulation Format = GFSK
+ // Packet Length = fix len
+ // Packet Length Mode = Variable packet length mode. Packet length configured by the first byte after sync word
+ // Preamble Count = 1
+ // RX Filter BW = 464kHz
+ // !!! channel filter bandwidth should be selected so that the signal bandwidth occupies at most 80% of the channel filter bandwidth.
+ // The channel centre tolerance due to crystal accuracy should also be subtracted from the signal bandwidth.
+ // Sync Word Qualifier Mode = preamble (0x71 0x0F)
+ // TX Power = 0
+ // Whitening = false
+
+ CC2500_Reset();
+ CC2500_Strobe(CC2500_SIDLE);
+ CC2500_WriteReg(CC2500_04_SYNC1, 0x71); // Sync word, high byte (Sync word = 0x71,0x0F,address=0x55)
+ CC2500_WriteReg(CC2500_05_SYNC0, 0x0F); // Sync word, low byte
+ CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x05); // Packet Automation Control, address check true auto append RSSI & LQI
+ CC2500_WriteReg(CC2500_06_PKTLEN, cc2500_packet_len); // Packet len, fix packet len
+ CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x00); // Packet Automation Control, fix packet len
+ CC2500_WriteReg(CC2500_09_ADDR, 0x55); // Set addr to 0x55 (Sync word = 0x71,0x0F,address=0x55)
+ CC2500_WriteReg(CC2500_0B_FSCTRL1, 0x0A); // Frequency Synthesizer Control (IF Frequency)
+ CC2500_WriteReg(CC2500_0C_FSCTRL0, 0x00); // Frequency Synthesizer Control
+ CC2500_WriteReg(CC2500_0D_FREQ2, 0x5C); // Frequency Control Word, High Byte
+ CC2500_WriteReg(CC2500_0E_FREQ1, 0x4E); // Frequency Control Word, Middle Byte
+ CC2500_WriteReg(CC2500_0F_FREQ0, 0xC5); // Frequency Control Word, Low Byte
+ CC2500_WriteReg(CC2500_10_MDMCFG4, 0x3D); // Modem Configuration Set to 406kHz BW filter
+ CC2500_WriteReg(CC2500_11_MDMCFG3, 0x3B); // Modem Configuration
+ CC2500_WriteReg(CC2500_12_MDMCFG2, 0x12); // Modem Configuration 16/16 Sync Word detect
+ CC2500_WriteReg(CC2500_13_MDMCFG1, 0x03); // Modem Configuration
+ CC2500_WriteReg(CC2500_14_MDMCFG0, 0xA4); // Modem Configuration
+ CC2500_WriteReg(CC2500_15_DEVIATN, 0x62); // Modem Deviation Setting
+ // CC2500_WriteReg(CC2500_16_MCSM2, 0x07); // Main Radio Control State Machine Configuration
+ // CC2500_WriteReg(CC2500_17_MCSM1, 0x30); // Main Radio Control State Machine Configuration
+ CC2500_WriteReg(CC2500_18_MCSM0, 0x28); // Main Radio Control State Machine Configuration
+ CC2500_WriteReg(CC2500_19_FOCCFG, 0x1D); // Frequency Offset Compensation Configuration
+ CC2500_WriteReg(CC2500_1A_BSCFG, 0x1C); // Bit Synchronization Configuration
+ CC2500_WriteReg(CC2500_1B_AGCCTRL2, 0xC7); // AGC Control
+ CC2500_WriteReg(CC2500_1C_AGCCTRL1, 0x00); // AGC Control
+ CC2500_WriteReg(CC2500_1D_AGCCTRL0, 0xB0); // AGC Control
+ CC2500_WriteReg(CC2500_21_FREND1, 0xB6); // Front End RX Configuration
+ CC2500_WriteReg(CC2500_23_FSCAL3, 0xEA); // Frequency Synthesizer Calibration
+ CC2500_WriteReg(CC2500_25_FSCAL1, 0x00); // Frequency Synthesizer Calibration
+ CC2500_WriteReg(CC2500_26_FSCAL0, 0x11); // Frequency Synthesizer Calibration
+
+ XN297L_SetScrambledMode(scramble_en);
+ xn297_crc = crc_en;
+}
+
+void XN297L_SetTXAddr(const u8* addr, u8 len)
+{
+ if (len > 5) len = 5;
+ if (len < 3) len = 3;
+ xn297_addr_len = len;
+ memcpy(xn297_tx_addr, addr, len);
+}
+
+void XN297L_SetRXAddr(const u8* addr, u8 len)
+{
+ if (len > 5) len = 5;
+ if (len < 3) len = 3;
+ xn297_addr_len = len;
+ memcpy(xn297_rx_addr, addr, len);
+}
+
+void XN297L_SetChannel(u8 ch)
+{
+ if (ch > 85)
+ ch = 85;
+ // channel spacing is 333.25 MHz
+ CC2500_WriteReg(CC2500_0A_CHANNR, ch * 3);
+}
+
+const u8 xn297_scramble[] = {
+ 0xE3, 0xB1, 0x4B, 0xEA, 0x85, 0xBC, 0xE5, 0x66,
+ 0x0D, 0xAE, 0x8C, 0x88, 0x12, 0x69, 0xEE, 0x1F,
+ 0xC7, 0x62, 0x97, 0xD5, 0x0B, 0x79, 0xCA, 0xCC,
+ 0x1B, 0x5D, 0x19, 0x10, 0x24, 0xD3, 0xDC, 0x3F,
+ 0x8E, 0xC5, 0x2F, 0xAA, 0x16, 0xF3, 0x95 };
+
+const u16 xn297_crc_xorout_scrambled[] = {
+ 0x0000, 0x3448, 0x9BA7, 0x8BBB, 0x85E1, 0x3E8C,
+ 0x451E, 0x18E6, 0x6B24, 0xE7AB, 0x3828, 0x814B,
+ 0xD461, 0xF494, 0x2503, 0x691D, 0xFE8B, 0x9BA7,
+ 0x8B17, 0x2920, 0x8B5F, 0x61B1, 0xD391, 0x7401,
+ 0x2138, 0x129F, 0xB3A0, 0x2988, 0x23CA, 0xC0CB,
+ 0x0C6C, 0xB329, 0xA0A1, 0x0A16, 0xA9D0 };
+
+const u16 xn297_crc_xorout[] = {
+ 0x0000, 0x3D5F, 0xA6F1, 0x3A23, 0xAA16, 0x1CAF,
+ 0x62B2, 0xE0EB, 0x0821, 0xBE07, 0x5F1A, 0xAF15,
+ 0x4F0A, 0xAD24, 0x5E48, 0xED34, 0x068C, 0xF2C9,
+ 0x1852, 0xDF36, 0x129D, 0xB17C, 0xD5F5, 0x70D7,
+ 0xB798, 0x5133, 0x67DB, 0xD94E, 0x0A5B, 0xE445,
+ 0xE6A5, 0x26E7, 0xBDAB, 0xC379, 0x8E20 };
+
+const u16 xn297_crc_xorout_scrambled_enhanced[] = {
+ 0x0000, 0x7EBF, 0x3ECE, 0x07A4, 0xCA52, 0x343B,
+ 0x53F8, 0x8CD0, 0x9EAC, 0xD0C0, 0x150D, 0x5186,
+ 0xD251, 0xA46F, 0x8435, 0xFA2E, 0x7EBD, 0x3C7D,
+ 0x94E0, 0x3D5F, 0xA685, 0x4E47, 0xF045, 0xB483,
+ 0x7A1F, 0xDEA2, 0x9642, 0xBF4B, 0x032F, 0x01D2,
+ 0xDC86, 0x92A5, 0x183A, 0xB760, 0xA953 };
+
+const u16 xn297_crc_xorout_enhanced[] = {
+ 0x0000, 0x8BE6, 0xD8EC, 0xB87A, 0x42DC, 0xAA89,
+ 0x83AF, 0x10E4, 0xE83E, 0x5C29, 0xAC76, 0x1C69,
+ 0xA4B2, 0x5961, 0xB4D3, 0x2A50, 0xCB27, 0x5128,
+ 0x7CDB, 0x7A14, 0xD5D2, 0x57D7, 0xE31D, 0xCE42,
+ 0x648D, 0xBF2D, 0x653B, 0x190C, 0x9117, 0x9A97,
+ 0xABFC, 0xE68E, 0x0DE7, 0x28A2, 0x1965 };
+
+
+#if defined(__GNUC__) && defined(__ARM_ARCH_ISA_THUMB) && (__ARM_ARCH_ISA_THUMB == 2)
+// rbit instruction works on cortex m3
+u32 __RBIT_(u32 in)
+{
+ u32 out = 0;
+ __asm volatile ("rbit %0, %1" : "=r" (out) : "r" (in) );
+ return(out);
+}
+
+u8 bit_reverse(u8 b_in)
+{
+ return __RBIT_( (unsigned int) b_in)>>24;
+}
+#else
+u8 bit_reverse(u8 b_in)
+{
+ u8 b_out = 0;
+ for (int i = 0; i < 8; ++i) {
+ b_out = (b_out << 1) | (b_in & 1);
+ b_in >>= 1;
+ }
+ return b_out;
+}
+#endif
+
+const u16 polynomial = 0x1021;
+
+u16 crc16_update(u16 crc, u8 a, u8 bits)
+{
+ crc ^= a << 8;
+ while (bits--) {
+ if (crc & 0x8000) {
+ crc = (crc << 1) ^ polynomial;
+ } else {
+ crc = crc << 1;
+ }
+ }
+ return crc;
+}
+
+void XN297L_SetScrambledMode(const u8 mode)
+{
+ xn297_scramble_enabled = mode;
+}
+
+u8 _xn297l_write_payload(const u8* msg, u8 len, u8* out)
+{
+ u8 last = 0;
+ u8 i;
+
+ for (i = 0; i < xn297_addr_len; ++i) {
+ out[last] = xn297_tx_addr[xn297_addr_len-i-1];
+ if (xn297_scramble_enabled)
+ out[last] ^= xn297_scramble[i];
+ last++;
+ }
+
+ for (i = 0; i < len; ++i) {
+ // bit-reverse bytes in packet
+ u8 b_out = bit_reverse(msg[i]);
+ out[last] = b_out;
+ if (xn297_scramble_enabled)
+ out[last] ^= xn297_scramble[xn297_addr_len+i];
+ last++;
+ }
+
+ if (xn297_crc) {
+ u16 crc = 0xb5d2;
+ for (i = 0; i < last; ++i) {
+ crc = crc16_update(crc, out[i], 8);
+ }
+ if (xn297_scramble_enabled)
+ crc ^= xn297_crc_xorout_scrambled[xn297_addr_len - 3 + len];
+ else
+ crc ^= xn297_crc_xorout[xn297_addr_len - 3 + len];
+ out[last++] = crc >> 8;
+ out[last++] = crc & 0xff;
+ }
+ return last;
+}
+
+u8 _xn297l_write_enhancedpayload(const u8* msg, u8 len, u8* out, u8 noack)
+{
+ u8 scramble_index = 0;
+ u8 last = 0;
+ static u8 pid = 0;
+ u8 i;
+ // address
+ for ( i = 0; i < xn297_addr_len; ++i ) {
+ out[last] = xn297_tx_addr[xn297_addr_len-i-1];
+ if (xn297_scramble_enabled)
+ out[last] ^= xn297_scramble[scramble_index++];
+ last++;
+ }
+ // pcf
+ out[last] = (len << 1) | (pid>>1);
+ if (xn297_scramble_enabled)
+ out[last] ^= xn297_scramble[scramble_index++];
+ last++;
+ out[last] = (pid << 7) | (noack << 6);
+ // payload
+ out[last]|= bit_reverse(msg[0]) >> 2; // first 6 bit of payload
+ if (xn297_scramble_enabled)
+ out[last] ^= xn297_scramble[scramble_index++];
+
+ for ( i = 0; i < len-1; ++i ) {
+ last++;
+ out[last] = (bit_reverse(msg[i]) << 6) | (bit_reverse(msg[i+1]) >> 2);
+ if (xn297_scramble_enabled)
+ out[last] ^= xn297_scramble[scramble_index++];
+ }
+
+ last++;
+ out[last] = bit_reverse(msg[len-1]) << 6; // last 2 bit of payload
+ if (xn297_scramble_enabled)
+ out[last] ^= xn297_scramble[scramble_index++] & 0xc0;
+
+ // crc
+ if (xn297_crc) {
+ u16 crc = 0xb5d2;
+ for ( i = 0; i < last; ++i)
+ crc = crc16_update(crc, out[i], 8);
+ crc = crc16_update(crc, out[last] & 0xc0, 2);
+
+ if (xn297_scramble_enabled)
+ crc ^= xn297_crc_xorout_scrambled_enhanced[xn297_addr_len - 3+len];
+ else
+ crc ^= xn297_crc_xorout_enhanced[xn297_addr_len - 3 + len];
+
+ out[last++] |= (crc >> 8) >> 2;
+ out[last++] = ((crc >> 8) << 6) | ((crc & 0xff) >> 2);
+ out[last++] = (crc & 0xff) << 6;
+ }
+ pid++;
+ pid &= 3;
+ return last;
+}
+
+void XN297L_WritePayload(u8* msg, u8 len)
+{
+ u8 buf[32];
+ u8 count = _xn297l_write_payload(msg, len, buf);
+ // halt Tx/Rx
+ CC2500_Strobe(CC2500_SIDLE);
+ // flush tx FIFO
+ CC2500_Strobe(CC2500_SFTX);
+ // set cc2500 packet length
+ // CC2500_WriteReg(CC2500_3F_TXFIFO, count+3);
+ // XN297L preamble
+ CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, (u8*)"\x55", 1); // preamble was writen in cc2500 sync word & preamble.
+ // packet
+ CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, buf, count);
+ // transmit
+ CC2500_Strobe(CC2500_STX);
+}
+
+void XN297L_WriteEnhancedPayload(u8* msg, u8 len, u8 noack)
+{
+ u8 buf[32];
+ u8 count = _xn297l_write_enhancedpayload(msg, len, buf, noack);
+ // halt Tx/Rx
+ CC2500_Strobe(CC2500_SIDLE);
+ // flush tx FIFO
+ CC2500_Strobe(CC2500_SFTX);
+ // set cc2500 packet length
+ // CC2500_WriteReg(CC2500_3F_TXFIFO, count + 3);
+ // XN297L preamble
+ CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, (u8*)"\x55", 1); // preamble was writen in cc2500 sync word & preamble.
+ // packet
+ CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, buf, count);
+ // transmit
+ CC2500_Strobe(CC2500_STX);
+}
+
+u8 XN297L_ReadPayload(u8* msg, u8 len) // just what it should be, no tested yeah.
+{ // cc2500 receive 1byte address(0x55) + 5byte xnl297 address + 16byte payload +2byte crc
+ u8 buf[32];
+ u8 rx_fifo = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
+ CC2500_ReadData(buf, rx_fifo);
+ // Decode payload
+ for (u8 i = 0; i < len; i++)
+ {
+ u8 b_in = buf[i+6];
+ if (xn297_scramble_enabled)
+ b_in ^= xn297_scramble[i+xn297_addr_len];
+ msg[i] = bit_reverse(b_in);
+ }
+ if (!xn297_crc)
+ return 1; // No CRC so OK by default...
+
+ // Calculate CRC
+ u16 crc = 0xb5d2;
+ // process address
+ for (u8 i = 0; i < xn297_addr_len; ++i)
+ {
+ u8 b_in = xn297_rx_addr[xn297_addr_len-i-1];
+ if (xn297_scramble_enabled)
+ b_in ^= xn297_scramble[i];
+ crc = crc16_update(crc, b_in, 8);
+ }
+ // process payload
+ for (u8 i = 0; i < len; ++i)
+ crc = crc16_update(crc, buf[i+6], 8);
+ // xorout
+ if (xn297_scramble_enabled)
+ crc ^= xn297_crc_xorout_scrambled[xn297_addr_len - 3 + len];
+ else
+ crc ^= xn297_crc_xorout[xn297_addr_len - 3 + len];
+ // test
+ if ((crc >> 8) == buf[len+6] && (crc & 0xff) == buf[len+7])
+ return 1; // CRC OK
+ return 0; // CRC NOK
+}
+
+u8 XN297L_ReadEnhancedPayload(u8* msg, u8 len)
+{ // cc2500 receive 1byte preamble(0x55) + 5byte xnl297 address + 2byte pcf + 16byte payload +2byte crc +2byte rx_status
+ u8 buffer[32];
+ u8 pcf_size; // pcf payload size
+ CC2500_ReadData(buffer, len);
+ len = len -2; // 2byte append rx_status
+ pcf_size = buffer[6]; // 0x55+5byte addr
+ if (xn297_scramble_enabled)
+ pcf_size ^= xn297_scramble[xn297_addr_len];
+ pcf_size = pcf_size >> 1;
+ for (u8 i=0; i < len-10; i++) // no include preamble(1byte) xnl297 address(5byte) PCF(2byte) crc(2byte)
+ {
+ msg[i] = bit_reverse((buffer[i+7] << 2) | (buffer[i+8] >> 6));
+ if (xn297_scramble_enabled)
+ msg[i] ^= bit_reverse((xn297_scramble[xn297_addr_len+i+1] << 2) |
+ (xn297_scramble[xn297_addr_len+i+2] >> 6));
+ }
+
+ if (!xn297_crc)
+ return pcf_size; // No CRC so OK by default...
+
+ // Calculate CRC
+ u16 crc = 0xb5d2;
+ for (u8 i = 0; i < len-4; ++i)
+ crc = crc16_update(crc, buffer[i+1], 8);
+ crc = crc16_update(crc, buffer[len-3] & 0xc0, 2);
+ // xorout
+ if (xn297_scramble_enabled)
+ crc ^= xn297_crc_xorout_scrambled_enhanced[xn297_addr_len-3+16];
+
+ u16 crcxored = (buffer[len-3] << 10)|(buffer[len-2] << 2)|(buffer[len-1] >> 6);
+ if (crc == crcxored)
+ return buffer[len]; // CRC OK, return RSSI
+ return 0; // CRC NOK
+}
+
#endif
diff --git a/src/protocol/spi/nrf24l01.c b/src/protocol/spi/nrf24l01.c
index 78be9c6485..ae58c16b2a 100644
--- a/src/protocol/spi/nrf24l01.c
+++ b/src/protocol/spi/nrf24l01.c
@@ -273,28 +273,11 @@ static u8 xn297_tx_addr[5];
static u8 xn297_rx_addr[5];
static u8 xn297_crc = 0;
-const uint8_t xn297_scramble[] = {
- 0xe3, 0xb1, 0x4b, 0xea, 0x85, 0xbc, 0xe5, 0x66,
- 0x0d, 0xae, 0x8c, 0x88, 0x12, 0x69, 0xee, 0x1f,
- 0xc7, 0x62, 0x97, 0xd5, 0x0b, 0x79, 0xca, 0xcc,
- 0x1b, 0x5d, 0x19, 0x10, 0x24, 0xd3, 0xdc, 0x3f,
- 0x8e, 0xc5, 0x2f};
-
-const u16 xn297_crc_xorout_scrambled[] = {
- 0x0000, 0x3448, 0x9BA7, 0x8BBB, 0x85E1, 0x3E8C,
- 0x451E, 0x18E6, 0x6B24, 0xE7AB, 0x3828, 0x814B,
- 0xD461, 0xF494, 0x2503, 0x691D, 0xFE8B, 0x9BA7,
- 0x8B17, 0x2920, 0x8B5F, 0x61B1, 0xD391, 0x7401,
- 0x2138, 0x129F, 0xB3A0, 0x2988};
-
-const u16 xn297_crc_xorout[] = {
- 0x0000, 0x3d5f, 0xa6f1, 0x3a23, 0xaa16, 0x1caf,
- 0x62b2, 0xe0eb, 0x0821, 0xbe07, 0x5f1a, 0xaf15,
- 0x4f0a, 0xad24, 0x5e48, 0xed34, 0x068c, 0xf2c9,
- 0x1852, 0xdf36, 0x129d, 0xb17c, 0xd5f5, 0x70d7,
- 0xb798, 0x5133, 0x67db, 0xd94e};
-
+extern const u8 xn297_scramble[];
+extern const u16 xn297_crc_xorout_scrambled[];
+extern const u16 xn297_crc_xorout[];
+/*
#if defined(__GNUC__) && defined(__ARM_ARCH_ISA_THUMB) && (__ARM_ARCH_ISA_THUMB==2)
// rbit instruction works on cortex m3
uint32_t __RBIT_(uint32_t in)
@@ -335,9 +318,11 @@ u16 crc16_update(u16 crc, u8 a, u8 bits)
}
return crc;
}
+*/
+static const uint16_t initial = 0xb5d2;
-void XN297_SetTXAddr(const u8* addr, int len)
+void XN297_SetTXAddr(const u8* addr, u8 len)
{
if (len > 5) len = 5;
if (len < 3) len = 3;
@@ -359,7 +344,7 @@ void XN297_SetTXAddr(const u8* addr, int len)
}
-void XN297_SetRXAddr(const u8* addr, int len)
+void XN297_SetRXAddr(const u8* addr, u8 len)
{
if (len > 5) len = 5;
if (len < 3) len = 3;
@@ -433,7 +418,7 @@ u8 XN297_WritePayload(u8* msg, int len)
return res;
}
-u8 XN297_WriteEnhancedPayload(u8* msg, int len, int noack, u16 crc_xorout)
+u8 XN297_WriteEnhancedPayload(u8* msg, u8 len, u8 noack, u16 crc_xorout)
{
u8 packet[32];
u8 scramble_index=0;
@@ -501,35 +486,95 @@ u8 XN297_WriteEnhancedPayload(u8* msg, int len, int noack, u16 crc_xorout)
return res;
}
-u8 XN297_ReadPayload(u8* msg, int len)
-{
- // TODO: if xn297_crc==1, check CRC before filling *msg
- u8 res = NRF24L01_ReadPayload(msg, len);
- for(u8 i=0; i> 8) == buf[len] && (crc & 0xff) == buf[len+1])
+ return 1; // CRC OK
+ return 0; // CRC NOK
}
-u8 XN297_ReadEnhancedPayload(u8* msg, int len)
-{
+u8 XN297_ReadEnhancedPayload(u8* msg, u8 len)
+{ //!!! Don't forget do a +2 and if using CRC add +4 on any of the used NRF24L01_11_RX_PW_Px !!!
u8 buffer[32];
u8 pcf_size; // pcf payload size
- NRF24L01_ReadPayload(buffer, len+2); // pcf + payload
+ if (xn297_crc)
+ NRF24L01_ReadPayload(buffer, len+4); // Read pcf + payload + CRC
+ else
+ NRF24L01_ReadPayload(buffer, len+2); // Read pcf + payload
pcf_size = buffer[0];
- if(xn297_scramble_enabled)
+ if (xn297_scramble_enabled)
pcf_size ^= xn297_scramble[xn297_addr_len];
pcf_size = pcf_size >> 1;
- for(int i=0; i> 6));
- if(xn297_scramble_enabled)
+ if (xn297_scramble_enabled)
msg[i] ^= bit_reverse((xn297_scramble[xn297_addr_len+i+1] << 2) |
(xn297_scramble[xn297_addr_len+i+2] >> 6));
}
- return pcf_size;
+
+ if (!xn297_crc)
+ return pcf_size; // No CRC so OK by default...
+
+ // Calculate CRC
+ u16 crc = 0xb5d2;
+ // process address
+ for (u8 i = 0; i < xn297_addr_len; ++i)
+ {
+ u8 b_in = xn297_rx_addr[xn297_addr_len-i-1];
+ if (xn297_scramble_enabled)
+ b_in ^= xn297_scramble[i];
+ crc = crc16_update(crc, b_in, 8);
+ }
+ // process payload
+ for (u8 i = 0; i < len+1; ++i)
+ crc = crc16_update(crc, buffer[i], 8);
+ crc = crc16_update(crc, buffer[len+1] & 0xc0, 2);
+ // xorout
+ if (xn297_scramble_enabled)
+ crc ^= xn297_crc_xorout_scrambled_enhanced[xn297_addr_len-3+len];
+
+ u16 crcxored = (buffer[len+1] << 10)|(buffer[len+2] << 2)|(buffer[len+3] >> 6);
+ if (crc == crcxored)
+ return pcf_size; // CRC OK
+ return 0; // CRC NOK
}
+
//
// End of XN297 emulation
///////////////////////////
diff --git a/src/target/drivers/mcu/stm32/f1/pwr.h b/src/target/drivers/mcu/stm32/f1/pwr.h
index 2c52c8bad5..7ec1502cfe 100644
--- a/src/target/drivers/mcu/stm32/f1/pwr.h
+++ b/src/target/drivers/mcu/stm32/f1/pwr.h
@@ -5,7 +5,7 @@ static inline void _pwr_init()
{
SCB_VTOR = VECTOR_TABLE_LOCATION;
SCB_SCR &= ~SCB_SCR_SLEEPONEXIT; // sleep immediate on WFI
- rcc_clock_setup_in_hse_8mhz_out_72mhz();
+ rcc_clock_setup_pll(&rcc_hse_configs[RCC_CLOCK_HSE8_72MHZ]);
}
static inline void _pwr_shutdown()