diff --git a/Multiprotocol/FrSkyX_Rx_cc2500.ino b/Multiprotocol/FrSkyX_Rx_cc2500.ino
new file mode 100644
index 0000000..9b5304a
--- /dev/null
+++ b/Multiprotocol/FrSkyX_Rx_cc2500.ino
@@ -0,0 +1,216 @@
+/*
+ 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 .
+ */
+
+ #define FRSKYX_FCC_LENGTH 32
+ #define FRSKYX_LBT_LENGTH 35
+
+ enum {
+ FRSKYX_RX_BIND,
+ FRSKYX_RX_DATA,
+ };
+
+ static uint16_t frskyx_bind_packets;
+ static uint8_t frskyx_rx_txid[3];
+ static uint8_t frskyx_rx_chanskip;
+
+static void __attribute__((unused)) FrSkyX_Rx_initialise() {
+ CC2500_Reset();
+
+ CC2500_WriteReg(CC2500_02_IOCFG0, 0x01);
+ CC2500_WriteReg(CC2500_18_MCSM0, 0x18);
+ CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x04);
+ CC2500_WriteReg(CC2500_3E_PATABLE, 0xFF);
+ CC2500_WriteReg(CC2500_0C_FSCTRL0, 0x00);
+ CC2500_WriteReg(CC2500_0D_FREQ2, 0x5C);
+ CC2500_WriteReg(CC2500_13_MDMCFG1, 0x23);
+ CC2500_WriteReg(CC2500_14_MDMCFG0, 0x7A);
+ CC2500_WriteReg(CC2500_19_FOCCFG, 0x16);
+ CC2500_WriteReg(CC2500_1A_BSCFG, 0x6C);
+ CC2500_WriteReg(CC2500_1B_AGCCTRL2, 0x03);
+ CC2500_WriteReg(CC2500_1C_AGCCTRL1, 0x40);
+ CC2500_WriteReg(CC2500_1D_AGCCTRL0, 0x91);
+ CC2500_WriteReg(CC2500_21_FREND1, 0x56);
+ CC2500_WriteReg(CC2500_22_FREND0, 0x10);
+ CC2500_WriteReg(CC2500_23_FSCAL3, 0xA9);
+ CC2500_WriteReg(CC2500_24_FSCAL2, 0x0A);
+ CC2500_WriteReg(CC2500_25_FSCAL1, 0x00);
+ CC2500_WriteReg(CC2500_26_FSCAL0, 0x11);
+ CC2500_WriteReg(CC2500_29_FSTEST, 0x59);
+ CC2500_WriteReg(CC2500_2C_TEST2, 0x88);
+ CC2500_WriteReg(CC2500_2D_TEST1, 0x31);
+ CC2500_WriteReg(CC2500_2E_TEST0, 0x0B);
+ CC2500_WriteReg(CC2500_03_FIFOTHR, 0x07);
+ CC2500_WriteReg(CC2500_09_ADDR, 0x00);
+
+ switch (sub_protocol) {
+ case FRSKYX_FCC:
+ CC2500_WriteReg(CC2500_17_MCSM1, 0x0C);
+ CC2500_WriteReg(CC2500_0E_FREQ1, 0x76);
+ CC2500_WriteReg(CC2500_0F_FREQ0, 0x27);
+ CC2500_WriteReg(CC2500_06_PKTLEN, 0x1E);
+ CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x01);
+ CC2500_WriteReg(CC2500_0B_FSCTRL1, 0x0A);
+ CC2500_WriteReg(CC2500_10_MDMCFG4, 0x7B);
+ CC2500_WriteReg(CC2500_11_MDMCFG3, 0x61);
+ CC2500_WriteReg(CC2500_12_MDMCFG2, 0x13);
+ CC2500_WriteReg(CC2500_15_DEVIATN, 0x51);
+ break;
+ case FRSKYX_LBT:
+ CC2500_WriteReg(CC2500_17_MCSM1, 0x0E);
+ CC2500_WriteReg(CC2500_0E_FREQ1, 0x80);
+ CC2500_WriteReg(CC2500_0F_FREQ0, 0x00);
+ CC2500_WriteReg(CC2500_06_PKTLEN, 0x23);
+ CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x01);
+ CC2500_WriteReg(CC2500_0B_FSCTRL1, 0x08);
+ CC2500_WriteReg(CC2500_10_MDMCFG4, 0x7B);
+ CC2500_WriteReg(CC2500_11_MDMCFG3, 0xF8);
+ CC2500_WriteReg(CC2500_12_MDMCFG2, 0x03);
+ CC2500_WriteReg(CC2500_15_DEVIATN, 0x53);
+ break;
+ }
+
+ CC2500_SetTxRxMode(RX_EN); // Receive mode
+
+ CC2500_Strobe(CC2500_SIDLE);
+ CC2500_Strobe(CC2500_SFRX);
+ CC2500_Strobe(CC2500_SRX);
+ CC2500_WriteReg(CC2500_0A_CHANNR, 0);
+ CC2500_WriteReg(CC2500_25_FSCAL1, calData[0]);
+ delayMicroseconds(1000); // wait for RX to activate
+}
+
+static void __attribute__((unused)) frskyx_rx_set_channel(uint8_t channel)
+{
+ CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[channel]);
+ CC2500_WriteReg(CC2500_25_FSCAL1, calData[channel]);
+ CC2500_Strobe(CC2500_SIDLE);
+ CC2500_Strobe(CC2500_SFRX);
+ CC2500_Strobe(CC2500_SRX);
+}
+
+static void __attribute__((unused)) frskyx_rx_calibrate()
+{
+ CC2500_Strobe(CC2500_SIDLE);
+ CC2500_Strobe(CC2500_SFRX);
+ CC2500_Strobe(CC2500_SRX);
+ for (unsigned c = 0; c < 47; c++)
+ {
+ CC2500_Strobe(CC2500_SIDLE);
+ CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[c]);
+ CC2500_Strobe(CC2500_SCAL);
+ delayMicroseconds(900);
+ calData[c] = CC2500_ReadReg(CC2500_25_FSCAL1);
+ }
+}
+
+uint8_t __attribute__((unused)) frskyx_rx_check_crc()
+{
+ uint8_t limit = packet_length - 4; //(sub_protocol == FRSKYX_LBT) ? 31 : 28;
+ uint16_t lcrc = frskyX_crc_x(&packet[3], limit - 3); // computed crc
+ uint16_t rcrc = (packet[limit] << 8) | (packet[limit + 1] & 0xff); // received crc
+ return lcrc == rcrc;
+}
+
+uint16_t initFrSkyX_Rx()
+{
+ debugln("initFrSkyX_Rx()");
+ FrSkyX_Rx_initialise();
+ frskyx_bind_packets = 0;
+ frskyx_rx_chanskip = 0;
+ hopping_frequency_no = 0;
+ phase = FRSKYX_RX_BIND;
+ packet_length = (sub_protocol == FRSKYX_LBT) ? FRSKYX_LBT_LENGTH : FRSKYX_FCC_LENGTH;
+ return 1000;
+}
+
+uint16_t FrSkyX_Rx_callback()
+{
+ static uint32_t lasttime=0, counter=0;
+ static int8_t loops=0;
+ uint8_t len;
+ switch(phase) {
+ case FRSKYX_RX_BIND:
+ len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
+ if(len >= packet_length) {
+ CC2500_ReadData(packet, packet_length);
+ if (frskyx_rx_check_crc()) {
+ debug("bind:");
+ for(uint8_t i=0; i= packet_length) {
+ CC2500_ReadData(packet, packet_length);
+ if (frskyx_rx_check_crc()) {
+ /*debug("%02X:", hopping_frequency_no);
+ for (uint8_t i = 0; i < len; i++)
+ debug(" %02X", packet[i]);
+ debugln("");*/
+
+ // hop to next channel
+ frskyx_rx_chanskip = ((packet[4] & 0xC0) >> 6) | ((packet[5] & 0x3F) << 2);
+ hopping_frequency_no = (hopping_frequency_no + frskyx_rx_chanskip) % 47;
+ frskyx_rx_set_channel(hopping_frequency_no);
+
+ if(packet[7] == 0) { // standard packet, decode PXX channels
+ // TODO, or just send raw PXX channels ?
+ int16_t chan1 = packet[9] | ((packet[10] & 0x0F) << 8);
+ int16_t chan2= ((packet[10] & 0xF0) >> 4) | (packet[11] << 4);
+ //if(chan1 < 2048)
+ // debugln("Ch1: %d Ch2: %d", chan1, chan2);
+ }
+ loops = 0;
+ counter++;
+ }
+ // debug packets per second
+ if (millis() - lasttime >= 1000) {
+ lasttime = millis();
+ debugln("%ld pps", counter);
+ counter = 0;
+ }
+ }
+ loops++;
+ // skip channel if no packet received in time
+ if (loops >= 10) {
+ debugln("!");
+ hopping_frequency_no = (hopping_frequency_no + frskyx_rx_chanskip) % 47;
+ frskyx_rx_set_channel(hopping_frequency_no);
+ loops = 0;
+ }
+ break;
+ }
+ return 1000;
+}
diff --git a/Multiprotocol/FrSkyX_cc2500.ino b/Multiprotocol/FrSkyX_cc2500.ino
index 40f0622..90954f9 100644
--- a/Multiprotocol/FrSkyX_cc2500.ino
+++ b/Multiprotocol/FrSkyX_cc2500.ino
@@ -66,7 +66,7 @@ static uint16_t __attribute__((unused)) frskyX_CRCTable(uint8_t val)
val /= 16 ;
return word ^ (0x1081 * val) ;
}
-static uint16_t __attribute__((unused)) frskyX_crc_x(uint8_t *data, uint8_t len)
+uint16_t frskyX_crc_x(uint8_t *data, uint8_t len)
{
uint16_t crc = 0;
for(uint8_t i=0; i < len; i++)
diff --git a/Multiprotocol/Validate.h b/Multiprotocol/Validate.h
index a360016..72ceb75 100644
--- a/Multiprotocol/Validate.h
+++ b/Multiprotocol/Validate.h
@@ -250,6 +250,7 @@
#undef MULTI_STATUS
#undef MULTI_TELEMETRY
#undef SCANNER_TELEMETRY
+ #undef FRSKYX_RX_TELEMETRY
#else
#if defined MULTI_TELEMETRY && not defined INVERT_TELEMETRY
#warning MULTI_TELEMETRY has been defined but not INVERT_TELEMETRY. They should be both enabled for OpenTX telemetry and status to work.