diff --git a/Multiprotocol/Multi.txt b/Multiprotocol/Multi.txt
index 5820172..0161a81 100644
--- a/Multiprotocol/Multi.txt
+++ b/Multiprotocol/Multi.txt
@@ -67,4 +67,5 @@
67,LR12,LR12,LR12_6ch
68,Skyartec
69,ESKYv2,150V2
-70,DSM_RX
\ No newline at end of file
+70,DSM_RX
+71,Q90C
\ No newline at end of file
diff --git a/Multiprotocol/Multi_Names.ino b/Multiprotocol/Multi_Names.ino
index 80856a2..82fb50c 100644
--- a/Multiprotocol/Multi_Names.ino
+++ b/Multiprotocol/Multi_Names.ino
@@ -49,6 +49,7 @@ const char STR_AFHDS2A[] ="FSky 2A";
const char STR_Q2X2[] ="Q2x2";
const char STR_WK2x01[] ="Walkera";
const char STR_Q303[] ="Q303";
+const char STR_Q90C[] ="Q90C";
const char STR_GW008[] ="GW008";
const char STR_DM002[] ="DM002";
const char STR_CABELL[] ="Cabell";
@@ -307,6 +308,9 @@ const mm_protocol_definition multi_protocols[] = {
#if defined(Q303_NRF24L01_INO)
{PROTO_Q303, STR_Q303, 4, STR_SUBTYPE_Q303, OPTION_NONE },
#endif
+ #if defined(Q90C_NRF24L01_INO)
+ {PROTO_Q90C, STR_Q90C, 0, NO_SUBTYPE, OPTION_RFTUNE },
+ #endif
#if defined(REDPINE_CC2500_INO)
{PROTO_REDPINE, STR_REDPINE, 2, STR_SUBTYPE_REDPINE, OPTION_RFTUNE },
#endif
diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h
index 7b9e7f2..f2fcb11 100644
--- a/Multiprotocol/Multiprotocol.h
+++ b/Multiprotocol/Multiprotocol.h
@@ -19,7 +19,7 @@
#define VERSION_MAJOR 1
#define VERSION_MINOR 3
#define VERSION_REVISION 1
-#define VERSION_PATCH_LEVEL 2
+#define VERSION_PATCH_LEVEL 3
//******************
// Protocols
@@ -98,6 +98,7 @@ enum PROTOCOLS
PROTO_ESKY150V2 = 69, // =>CC2500+NRF24L01
PROTO_DSM_RX = 70, // =>CYRF6936
PROTO_JJRC345 = 71, // =>NRF24L01
+ PROTO_Q90C = 72, // =>NRF24L01 or CC2500
};
enum Flysky
@@ -767,6 +768,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
ESKY150V2 69
DSM_RX 70
JJRC345 71
+ Q90C 72
BindBit=> 0x80 1=Bind/0=No
AutoBindBit=> 0x40 1=Yes /0=No
RangeCheck=> 0x20 1=Yes /0=No
diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino
index 1445905..a5b42ba 100644
--- a/Multiprotocol/Multiprotocol.ino
+++ b/Multiprotocol/Multiprotocol.ino
@@ -1548,6 +1548,13 @@ static void protocol_init()
remote_callback = JJRC345_callback;
break;
#endif
+ #if defined(Q90C_NRF24L01_INO)
+ case PROTO_Q90C:
+ next_callback=initQ90C();
+ remote_callback = Q90C_callback;
+ break;
+ #endif
+
#endif
#ifdef SX1276_INSTALLED
#if defined(FRSKYR9_SX1276_INO)
diff --git a/Multiprotocol/Q90C_nrf24l01.ino b/Multiprotocol/Q90C_nrf24l01.ino
new file mode 100644
index 0000000..d6c124f
--- /dev/null
+++ b/Multiprotocol/Q90C_nrf24l01.ino
@@ -0,0 +1,142 @@
+/*
+ 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 .
+ */
+// Compatible with Q90C quad.
+
+#if defined(Q90C_NRF24L01_INO)
+
+#include "iface_nrf250k.h"
+
+#define FORCE_Q90C_ORIGINAL_ID
+
+#define Q90C_BIND_COUNT 250
+#define Q90C_PACKET_PERIOD 7336
+#define Q90C_INITIAL_WAIT 500
+#define Q90C_PACKET_SIZE 12
+#define Q90C_RF_BIND_CHANNEL 0x33
+#define Q90C_RF_NUM_CHANNELS 3
+#define Q90C_ADDRESS_LENGTH 5
+
+int16_t Q90C_channel(uint8_t num, int16_t in_min,int16_t in_max, int16_t out_min,int16_t out_max)
+{
+ int32_t val=Channel_data[num];
+ if(valin_max) val=in_max;
+ val=(val-in_min)*(out_max-out_min)/(in_max-in_min)+out_min;
+ return (uint16_t)val;
+}
+
+static void __attribute__((unused)) Q90C_send_packet()
+{
+ if(IS_BIND_IN_PROGRESS)
+ {
+ memcpy(packet, rx_tx_addr, 4);
+ memcpy(&packet[4], hopping_frequency, 3);
+ packet[7] = 0x1e;
+ packet[8] = 0;
+ packet[9] = 0;
+ packet[10] = rx_tx_addr[4];
+ packet[11] = 0x3a; // initial checksum value ?
+ }
+ else
+ {
+ XN297L_Hopping(hopping_frequency_no++); // RF Freq
+ if (hopping_frequency_no >= Q90C_RF_NUM_CHANNELS)
+ hopping_frequency_no = 0;
+ packet[0]= convert_channel_8b(THROTTLE); // 0..255
+ // A,E,R have weird scaling, 0x00-0xff range (unsigned) but center isn't 7f or 80
+ // rudder ff-7a-00
+ if (Channel_data[RUDDER] <= CHANNEL_MID)
+ packet[1] = Q90C_channel(RUDDER, CHANNEL_MIN_100, CHANNEL_MID, 0x00, 0x7a );
+ else
+ packet[1] = Q90C_channel(RUDDER, CHANNEL_MID, CHANNEL_MAX_100, 0x7a, 0xff );
+ // elevator 00-88-ff
+ if (Channel_data[ELEVATOR] <= CHANNEL_MID)
+ packet[2] = Q90C_channel(ELEVATOR, CHANNEL_MIN_100, CHANNEL_MID, 0x00, 0x88);
+ else
+ packet[2] = Q90C_channel(ELEVATOR, CHANNEL_MID, CHANNEL_MAX_100, 0x88, 0xff);
+ // aileron ff-88-00
+ if (Channel_data[AILERON] <= CHANNEL_MID)
+ packet[3] = Q90C_channel(AILERON, CHANNEL_MIN_100, CHANNEL_MID, 0x00, 0x88);
+ else
+ packet[3] = Q90C_channel(AILERON, CHANNEL_MID, CHANNEL_MAX_100, 0x88, 0xff);
+ // required to "arm" (low throttle + aileron to the right)
+ if (packet[0] < 5 && packet[3] < 25) {
+ packet[1] = 0x7a;
+ packet[2] = 0x88;
+ }
+ packet[4] = 0x1e; // T trim 00-1e-3c
+ packet[5] = 0x1e; // R trim 3c-1e-00
+ packet[6] = 0x1e; // E trim 00-1e-3c
+ packet[7] = 0x1e; // A trim 00-1e-3c
+ packet[8] = 0x00; // flags: 3 position flight mode (Angle - Horizon - Acro), VTX Toggle HIGH = next vTX frequency
+ packet[9] = 0x00;
+ packet[10] = packet_count++;
+ packet[11] = 0x9c; // initial checksum value ?
+ }
+
+ // checksum
+ for (uint8_t i = 0; i < Q90C_PACKET_SIZE - 1; i++)
+ packet[11] += packet[i];
+
+ XN297L_SetFreqOffset(); // Set frequency offset
+ XN297L_WriteEnhancedPayload(packet, Q90C_PACKET_SIZE, 0);
+ XN297L_SetPower(); // Set tx_power
+}
+
+static void __attribute__((unused)) Q90C_initialize_txid()
+{
+ #ifdef FORCE_Q90C_ORIGINAL_ID
+ memcpy(rx_tx_addr, (uint8_t*)"\x24\x03\x01\x82\x4B", Q90C_ADDRESS_LENGTH);
+ memcpy(hopping_frequency, (uint8_t*)"\x18\x26\x37", Q90C_RF_NUM_CHANNELS);
+ #endif
+}
+
+static void __attribute__((unused)) Q90C_init()
+{
+ XN297L_Init();
+ if(IS_BIND_IN_PROGRESS)
+ XN297L_SetTXAddr((uint8_t*)"\x4F\x43\x54\x81\x81", Q90C_ADDRESS_LENGTH);
+ else
+ XN297L_SetTXAddr(rx_tx_addr, Q90C_ADDRESS_LENGTH);
+ XN297L_HoppingCalib(Q90C_RF_NUM_CHANNELS); // Calibrate all channels
+ XN297L_RFChannel(Q90C_RF_BIND_CHANNEL); // Set bind channel
+}
+
+uint16_t Q90C_callback()
+{
+ #ifdef MULTI_SYNC
+ telemetry_set_input_sync(Q90C_PACKET_PERIOD);
+ #endif
+ if(IS_BIND_IN_PROGRESS)
+ if(--bind_counter==0)
+ {
+ BIND_DONE;
+ XN297L_SetTXAddr(rx_tx_addr, Q90C_ADDRESS_LENGTH);
+ }
+ Q90C_send_packet();
+ return Q90C_PACKET_PERIOD;
+}
+
+uint16_t initQ90C()
+{
+ Q90C_initialize_txid();
+ Q90C_init();
+ hopping_frequency_no = 0;
+ packet_count = 0;
+ bind_counter=Q90C_BIND_COUNT;
+ return Q90C_INITIAL_WAIT;
+}
+
+#endif
diff --git a/Multiprotocol/Validate.h b/Multiprotocol/Validate.h
index 5e4aaef..d7f44d1 100644
--- a/Multiprotocol/Validate.h
+++ b/Multiprotocol/Validate.h
@@ -257,6 +257,7 @@
#undef POTENSIC_NRF24L01_INO
#undef PROPEL_NRF24L01_INO
#undef Q303_NRF24L01_INO
+ #undef Q90C_NRF24L01_INO
#undef SHENQI_NRF24L01_INO
#undef SLT_NRF24L01_INO
#undef SYMAX_NRF24L01_INO
diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h
index e00a81e..fea6ee7 100644
--- a/Multiprotocol/_Config.h
+++ b/Multiprotocol/_Config.h
@@ -221,6 +221,7 @@
#define POTENSIC_NRF24L01_INO
#define PROPEL_NRF24L01_INO
#define Q303_NRF24L01_INO
+#define Q90C_NRF24L01_INO
#define SHENQI_NRF24L01_INO
#define SLT_NRF24L01_INO
#define SYMAX_NRF24L01_INO
@@ -674,6 +675,8 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
CX35
CX10D
CX10WD
+ PROTO_Q90C
+ NONE
PROTO_REDPINE
RED_FAST
RED_SLOW