Merge pull request #11198 from SteveCEvans/sce_rc2
[betaflight.git] / src / main / rx / cyrf6936_spektrum.c
blobf0dd5677faf1a2f196a70a2ba4685be2f25a0922
1 /*
2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
8 * any later version.
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
21 #include <string.h>
22 #include "platform.h"
24 #ifdef USE_RX_SPEKTRUM
26 #include "build/debug.h"
28 #include "drivers/io.h"
29 #include "drivers/rx/rx_cyrf6936.h"
30 #include "drivers/rx/rx_spi.h"
31 #include "drivers/system.h"
32 #include "drivers/time.h"
34 #include "sensors/battery.h"
36 #include "config/config.h"
37 #include "config/feature.h"
39 #include "pg/pg.h"
40 #include "pg/pg_ids.h"
41 #include "pg/rx_spi.h"
43 #include "rx/rx.h"
44 #include "rx/rx_spi.h"
45 #include "rx/rx_spi_common.h"
47 #include "rx/cyrf6936_spektrum.h"
49 static const uint8_t pnCodes[5][9][8] = {
50 { /* Row 0 */
51 /* Col 0 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8},
52 /* Col 1 */ {0x88, 0x17, 0x13, 0x3B, 0x2D, 0xBF, 0x06, 0xD6},
53 /* Col 2 */ {0xF1, 0x94, 0x30, 0x21, 0xA1, 0x1C, 0x88, 0xA9},
54 /* Col 3 */ {0xD0, 0xD2, 0x8E, 0xBC, 0x82, 0x2F, 0xE3, 0xB4},
55 /* Col 4 */ {0x8C, 0xFA, 0x47, 0x9B, 0x83, 0xA5, 0x66, 0xD0},
56 /* Col 5 */ {0x07, 0xBD, 0x9F, 0x26, 0xC8, 0x31, 0x0F, 0xB8},
57 /* Col 6 */ {0xEF, 0x03, 0x95, 0x89, 0xB4, 0x71, 0x61, 0x9D},
58 /* Col 7 */ {0x40, 0xBA, 0x97, 0xD5, 0x86, 0x4F, 0xCC, 0xD1},
59 /* Col 8 */ {0xD7, 0xA1, 0x54, 0xB1, 0x5E, 0x89, 0xAE, 0x86}
61 { /* Row 1 */
62 /* Col 0 */ {0x83, 0xF7, 0xA8, 0x2D, 0x7A, 0x44, 0x64, 0xD3},
63 /* Col 1 */ {0x3F, 0x2C, 0x4E, 0xAA, 0x71, 0x48, 0x7A, 0xC9},
64 /* Col 2 */ {0x17, 0xFF, 0x9E, 0x21, 0x36, 0x90, 0xC7, 0x82},
65 /* Col 3 */ {0xBC, 0x5D, 0x9A, 0x5B, 0xEE, 0x7F, 0x42, 0xEB},
66 /* Col 4 */ {0x24, 0xF5, 0xDD, 0xF8, 0x7A, 0x77, 0x74, 0xE7},
67 /* Col 5 */ {0x3D, 0x70, 0x7C, 0x94, 0xDC, 0x84, 0xAD, 0x95},
68 /* Col 6 */ {0x1E, 0x6A, 0xF0, 0x37, 0x52, 0x7B, 0x11, 0xD4},
69 /* Col 7 */ {0x62, 0xF5, 0x2B, 0xAA, 0xFC, 0x33, 0xBF, 0xAF},
70 /* Col 8 */ {0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97}
72 { /* Row 2 */
73 /* Col 0 */ {0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97},
74 /* Col 1 */ {0x8E, 0x4A, 0xD0, 0xA9, 0xA7, 0xFF, 0x20, 0xCA},
75 /* Col 2 */ {0x4C, 0x97, 0x9D, 0xBF, 0xB8, 0x3D, 0xB5, 0xBE},
76 /* Col 3 */ {0x0C, 0x5D, 0x24, 0x30, 0x9F, 0xCA, 0x6D, 0xBD},
77 /* Col 4 */ {0x50, 0x14, 0x33, 0xDE, 0xF1, 0x78, 0x95, 0xAD},
78 /* Col 5 */ {0x0C, 0x3C, 0xFA, 0xF9, 0xF0, 0xF2, 0x10, 0xC9},
79 /* Col 6 */ {0xF4, 0xDA, 0x06, 0xDB, 0xBF, 0x4E, 0x6F, 0xB3},
80 /* Col 7 */ {0x9E, 0x08, 0xD1, 0xAE, 0x59, 0x5E, 0xE8, 0xF0},
81 /* Col 8 */ {0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E}
83 { /* Row 3 */
84 /* Col 0 */ {0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E},
85 /* Col 1 */ {0x80, 0x69, 0x26, 0x80, 0x08, 0xF8, 0x49, 0xE7},
86 /* Col 2 */ {0x7D, 0x2D, 0x49, 0x54, 0xD0, 0x80, 0x40, 0xC1},
87 /* Col 3 */ {0xB6, 0xF2, 0xE6, 0x1B, 0x80, 0x5A, 0x36, 0xB4},
88 /* Col 4 */ {0x42, 0xAE, 0x9C, 0x1C, 0xDA, 0x67, 0x05, 0xF6},
89 /* Col 5 */ {0x9B, 0x75, 0xF7, 0xE0, 0x14, 0x8D, 0xB5, 0x80},
90 /* Col 6 */ {0xBF, 0x54, 0x98, 0xB9, 0xB7, 0x30, 0x5A, 0x88},
91 /* Col 7 */ {0x35, 0xD1, 0xFC, 0x97, 0x23, 0xD4, 0xC9, 0x88},
92 /* Col 8 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93}
94 { /* Row 4 */
95 /* Col 0 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93},
96 /* Col 1 */ {0xDC, 0x68, 0x08, 0x99, 0x97, 0xAE, 0xAF, 0x8C},
97 /* Col 2 */ {0xC3, 0x0E, 0x01, 0x16, 0x0E, 0x32, 0x06, 0xBA},
98 /* Col 3 */ {0xE0, 0x83, 0x01, 0xFA, 0xAB, 0x3E, 0x8F, 0xAC},
99 /* Col 4 */ {0x5C, 0xD5, 0x9C, 0xB8, 0x46, 0x9C, 0x7D, 0x84},
100 /* Col 5 */ {0xF1, 0xC6, 0xFE, 0x5C, 0x9D, 0xA5, 0x4F, 0xB7},
101 /* Col 6 */ {0x58, 0xB5, 0xB3, 0xDD, 0x0E, 0x28, 0xF1, 0xB0},
102 /* Col 7 */ {0x5F, 0x30, 0x3B, 0x56, 0x96, 0x45, 0xF4, 0xA1},
103 /* Col 8 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8}
107 static const uint8_t bindDataCode[16] = {0x98, 0x88, 0x1B, 0xE4, 0x30, 0x79, 0x03, 0x84, 0x98, 0x88, 0x1B, 0xE4, 0x30, 0x79, 0x03, 0x84};
109 static const uint8_t cyrf6936Config[][2] = {
110 {CYRF6936_CLK_EN, CYRF6936_RXF}, // Enable the clock
111 {CYRF6936_AUTO_CAL_TIME, 0x3C}, // From manual, needed for initialization
112 {CYRF6936_AUTO_CAL_OFFSET, 0x14}, // From manual, needed for initialization
113 {CYRF6936_RX_CFG, CYRF6936_LNA | CYRF6936_FAST_TURN_EN}, // Enable low noise amplifier and fast turning
114 {CYRF6936_TX_OFFSET_LSB, 0x55}, // From manual, typical configuration
115 {CYRF6936_TX_OFFSET_MSB, 0x05}, // From manual, typical configuration
116 {CYRF6936_XACT_CFG, CYRF6936_MODE_SYNTH_RX | CYRF6936_FRC_END}, // Force in Synth RX mode
117 {CYRF6936_TX_CFG, CYRF6936_DATA_CODE_LENGTH | CYRF6936_DATA_MODE_SDR | CYRF6936_PA_4}, // Enable 64 chip codes, SDR mode and amplifier +4dBm
118 {CYRF6936_DATA64_THOLD, 0x0E}, // From manual, typical configuration
120 static const uint8_t cyrf6936BindConfig[][2] = {
121 {CYRF6936_TX_CFG, CYRF6936_DATA_CODE_LENGTH | CYRF6936_DATA_MODE_SDR | CYRF6936_PA_4}, // Enable 64 chip codes, SDR mode and amplifier +4dBm
122 {CYRF6936_FRAMING_CFG, CYRF6936_SOP_LEN | 0xE}, // Set SOP CODE to 64 chips and SOP Correlator Threshold to 0xE
123 {CYRF6936_RX_OVERRIDE, CYRF6936_FRC_RXDR | CYRF6936_DIS_RXCRC}, // Force receive data rate and disable receive CRC checker
124 {CYRF6936_EOP_CTRL, 0x02}, // Only enable EOP symbol count of 2
125 {CYRF6936_TX_OVERRIDE, CYRF6936_DIS_TXCRC}, // Disable transmit CRC generate
127 static const uint8_t cyrf6936TransferConfig[][2] = {
128 {CYRF6936_TX_CFG, CYRF6936_DATA_CODE_LENGTH | CYRF6936_DATA_MODE_8DR | CYRF6936_PA_4}, // Enable 64 chip codes, 8DR mode and amplifier +4dBm
129 {CYRF6936_FRAMING_CFG, CYRF6936_SOP_EN | CYRF6936_SOP_LEN | CYRF6936_LEN_EN | 0xE}, // Set SOP CODE enable, SOP CODE to 64 chips, Packet length enable, and SOP Correlator Threshold to 0xE
130 {CYRF6936_TX_OVERRIDE, 0x00}, // Reset TX overrides
131 {CYRF6936_RX_OVERRIDE, 0x00}, // Reset RX overrides
134 typedef enum {
135 DSM2_22 = 0x01,
136 DSM2_11 = 0x02,
137 DSM2_11_DX6 = 0x03,
138 DSM2_11_DX8 = 0x12,
139 DSMX_22 = 0xA2,
140 DSMX_11 = 0xB2,
141 } dsm_protocol_e;
143 #define IS_DSM2(x) (x == DSM2_22 || x == DSM2_11 || x == DSM2_11_DX6 || x == DSM2_11_DX8)
144 #define IS_DSMX(x) (!IS_DSM2(x))
146 #define CHECK_MFG_ID(protocol, packet, id) ((IS_DSM2(protocol) && packet[0] == (~id[2]&0xFF) && packet[1] == (~id[3]&0xFF)) || \
147 (IS_DSMX(protocol) && packet[0] == id[2] && packet[1] == id[3]))
149 typedef enum {
150 DSM_RECEIVER_BIND = 0,
151 DSM_RECEIVER_BIND2,
152 DSM_RECEIVER_SYNC_A,
153 DSM_RECEIVER_SYNC_B,
154 DSM_RECEIVER_RECV,
155 #ifdef USE_RX_SPEKTRUM_TELEMETRY
156 DSM_RECEIVER_TLM,
157 #endif
158 } dsm_receiver_status_e;
160 typedef struct dsmReceiver_s {
161 dsm_receiver_status_e status;
162 dsm_protocol_e protocol;
164 uint8_t mfgId[4];
166 uint8_t rfChannel;
167 uint8_t rfChannelIdx;
168 uint8_t rfChannels[23];
170 uint8_t sopCol;
171 uint8_t dataCol;
172 uint16_t crcSeed;
174 uint8_t missedPackets;
175 uint8_t numChannels;
177 bool bound;
179 uint32_t timeout;
180 uint32_t timeLastPacket;
182 uint16_t bindPackets;
184 #ifdef USE_RX_SPEKTRUM_TELEMETRY
185 uint32_t timeLastTelemetry;
186 bool sendTelemetry;
187 #endif
188 } dsmReceiver_t;
190 STATIC_UNIT_TESTED dsmReceiver_t dsmReceiver;
192 PG_REGISTER_WITH_RESET_TEMPLATE(spektrumConfig_t, spektrumConfig, PG_RX_SPEKTRUM_SPI_CONFIG, 0);
193 PG_RESET_TEMPLATE(spektrumConfig_t, spektrumConfig, .protocol = 0, .mfgId = {0, 0, 0, 0}, .numChannels = 0);
195 static void dsmGenerateDsmxChannels(void)
197 unsigned idx = 0;
198 const uint32_t id = ~((dsmReceiver.mfgId[0] << 24) | (dsmReceiver.mfgId[1] << 16) | (dsmReceiver.mfgId[2] << 8) | (dsmReceiver.mfgId[3] << 0));
199 uint32_t idTmp = id;
201 while (idx < 23) {
202 unsigned i;
203 unsigned count3To27 = 0, count28To51 = 0, count52To76 = 0;
205 idTmp = idTmp * 0x0019660D + 0x3C6EF35F; // Randomization
206 const uint8_t nextCh = ((idTmp >> 8) % 0x49) + 3;
207 if (((nextCh ^ id) & 0x01) == 0) {
208 continue;
211 for (i = 0; i < idx; i++) {
212 if (dsmReceiver.rfChannels[i] == nextCh) {
213 break;
216 if (dsmReceiver.rfChannels[i] <= 27) {
217 count3To27++;
218 } else if (dsmReceiver.rfChannels[i] <= 51) {
219 count28To51++;
220 } else {
221 count52To76++;
225 if (i != idx) {
226 continue;
229 if ((nextCh < 28 && count3To27 < 8)
230 || (nextCh >= 28 && nextCh < 52 && count28To51 < 7)
231 || (nextCh >= 52 && count52To76 < 8)) {
232 dsmReceiver.rfChannels[idx++] = nextCh;
237 static void dsmSetChannel(const uint8_t channel, const uint8_t sopCol, const uint8_t dataCol, const uint16_t crcSeed)
239 const uint8_t pnRow = IS_DSM2(dsmReceiver.protocol) ? channel % 5 : (channel - 2) % 5;
241 cyrf6936SetCrcSeed(crcSeed);
242 cyrf6936SetSopCode(pnCodes[pnRow][sopCol]);
243 cyrf6936SetDataCode(pnCodes[pnRow][dataCol]);
245 cyrf6936SetChannel(channel);
248 static void dsmReceiverSetNextSyncChannel(void)
250 dsmReceiver.crcSeed = ~dsmReceiver.crcSeed;
251 dsmReceiver.rfChannel = (dsmReceiver.rfChannel + 1) % DSM_MAX_RF_CHANNEL;
252 dsmSetChannel(dsmReceiver.rfChannel, dsmReceiver.sopCol, dsmReceiver.dataCol, dsmReceiver.crcSeed);
255 static void dsmReceiverSetNextChannel(void)
257 dsmReceiver.rfChannelIdx = IS_DSM2(dsmReceiver.protocol) ? (dsmReceiver.rfChannelIdx + 1) % 2 : (dsmReceiver.rfChannelIdx + 1) % 23;
258 dsmReceiver.crcSeed = ~dsmReceiver.crcSeed;
259 dsmReceiver.rfChannel = dsmReceiver.rfChannels[dsmReceiver.rfChannelIdx];
260 dsmSetChannel(dsmReceiver.rfChannel, dsmReceiver.sopCol, dsmReceiver.dataCol, dsmReceiver.crcSeed);
263 static void resetReceiveTimeout(const uint32_t timeStamp)
265 dsmReceiver.timeLastPacket = timeStamp;
266 if (dsmReceiver.crcSeed == ((dsmReceiver.mfgId[0] << 8) + dsmReceiver.mfgId[1])) {
267 dsmReceiver.timeout = DSM_RECV_SHORT_TIMEOUT_US;
268 } else {
269 dsmReceiver.timeout = (dsmReceiver.numChannels < 8 ? DSM_RECV_LONG_TIMEOUT_US : DSM_RECV_MID_TIMEOUT_US);
273 static void dsmReceiverStartBind(void)
275 uint8_t dataCode[16];
276 dsmReceiver.status = DSM_RECEIVER_BIND;
278 cyrf6936SetConfigLen(cyrf6936BindConfig, ARRAYLEN(cyrf6936BindConfig));
280 memcpy(dataCode, pnCodes[0][8], 8);
281 memcpy(dataCode + 8, pnCodes[0][8], 8);
282 cyrf6936SetDataCode(dataCode);
284 dsmReceiver.rfChannel = DSM_INITIAL_BIND_CHANNEL;
285 cyrf6936SetChannel(dsmReceiver.rfChannel);
286 dsmReceiver.timeLastPacket = micros();
287 dsmReceiver.timeout = DSM_BIND_TIMEOUT_US;
288 cyrf6936StartRecv();
291 static void dsmReceiverStartTransfer(void)
293 dsmReceiver.status = DSM_RECEIVER_SYNC_A;
294 dsmReceiver.rfChannelIdx = 0;
295 dsmReceiver.missedPackets = 0;
297 cyrf6936SetConfigLen(cyrf6936TransferConfig, ARRAYLEN(cyrf6936TransferConfig));
299 dsmReceiver.numChannels = spektrumConfig()->numChannels;
300 dsmReceiver.protocol = spektrumConfig()->protocol;
302 dsmReceiver.crcSeed = ~((dsmReceiver.mfgId[0] << 8) + dsmReceiver.mfgId[1]);
303 dsmReceiver.sopCol = (dsmReceiver.mfgId[0] + dsmReceiver.mfgId[1] + dsmReceiver.mfgId[2] + 2) & 0x07;
304 dsmReceiver.dataCol = 7 - dsmReceiver.sopCol;
306 if (IS_DSMX(dsmReceiver.protocol)) {
307 dsmGenerateDsmxChannels();
308 dsmReceiver.rfChannelIdx = 22;
309 dsmReceiverSetNextChannel();
310 } else {
311 memset(dsmReceiver.rfChannels, 0, 23);
312 dsmReceiverSetNextSyncChannel();
315 dsmReceiver.timeLastPacket = micros();
316 dsmReceiver.timeout = DSM_SYNC_TIMEOUT_US << 2;
317 cyrf6936StartRecv();
320 bool spektrumSpiInit(const struct rxSpiConfig_s *rxConfig, struct rxRuntimeState_s *rxRuntimeState, rxSpiExtiConfig_t *extiConfig)
322 UNUSED(extiConfig);
324 if (!rxSpiExtiConfigured()) {
325 return false;
328 rxSpiCommonIOInit(rxConfig);
331 rxRuntimeState->channelCount = DSM_MAX_CHANNEL_COUNT;
333 extiConfig->ioConfig = IOCFG_IPD;
334 extiConfig->trigger = BETAFLIGHT_EXTI_TRIGGER_FALLING;
336 if (!cyrf6936Init()) {
337 return false;
340 if (rssiSource == RSSI_SOURCE_NONE) {
341 rssiSource = RSSI_SOURCE_RX_PROTOCOL;
344 cyrf6936SetConfigLen(cyrf6936Config, ARRAYLEN(cyrf6936Config));
346 #ifdef USE_RX_SPEKTRUM_TELEMETRY
347 dsmReceiver.timeLastTelemetry = micros() + DSM_TELEMETRY_TIME_US;
348 dsmReceiver.sendTelemetry = false;
349 #endif
351 if (spektrumConfig()->mfgId[0] || spektrumConfig()->mfgId[1]
352 || spektrumConfig()->mfgId[2] || spektrumConfig()->mfgId[3]) {
353 dsmReceiver.bound = true;
354 memcpy(dsmReceiver.mfgId, spektrumConfig()->mfgId, 4);
355 dsmReceiverStartTransfer();
356 } else {
357 dsmReceiver.bound = false;
358 dsmReceiverStartBind();
361 return true;
364 #ifdef USE_RX_SPEKTRUM_TELEMETRY
365 static void dsmSendTelemetryPacket(void)
367 uint8_t packet[9];
368 const uint16_t voltage = getBatteryVoltage();
370 packet[0] = DSM_TELEMETRY_FRAME_RPM;
371 packet[1] = 0xFF; //sid
372 packet[2] = 0xFF; //rpm
373 packet[3] = 0xFF; //rpm
374 packet[4] = voltage >> 8;
375 packet[5] = voltage & 0xFF;
376 packet[6] = 0x7F; //temperature
377 packet[7] = 0xFF; //temperature
378 packet[8] = getRssiPercent();
379 cyrf6936SetMode(CYRF6936_MODE_IDLE, true);
380 cyrf6936SendLen(packet, 9);
382 #endif
384 static void dsmSendBindPacket(void)
386 uint8_t packet[10];
387 uint16_t sum = 384 - 0x10;
388 packet[0] = 0xff ^ dsmReceiver.mfgId[0];
389 packet[1] = 0xff ^ dsmReceiver.mfgId[1];
390 packet[2] = 0xff ^ dsmReceiver.mfgId[2];
391 packet[3] = 0xff ^ dsmReceiver.mfgId[3];
392 packet[4] = 0x01;
393 packet[5] = dsmReceiver.numChannels;
394 packet[6] = dsmReceiver.protocol;
395 packet[7] = 0x00;
396 for(unsigned i = 0; i < 8; i++)
397 sum += packet[i];
398 packet[8] = sum >> 8;
399 packet[9] = sum & 0xff;
400 cyrf6936SetMode(CYRF6936_MODE_IDLE, true);
401 cyrf6936SendLen(packet, 10);
404 static void checkTimeout(void)
406 const uint32_t time = micros();
408 #ifdef USE_RX_SPEKTRUM_TELEMETRY
409 if (featureIsEnabled(FEATURE_TELEMETRY) && (time - dsmReceiver.timeLastTelemetry) > DSM_TELEMETRY_TIME_US) {
410 dsmReceiver.timeLastTelemetry = time;
411 dsmReceiver.sendTelemetry = true;
413 #endif
415 if ((time - dsmReceiver.timeLastPacket) > dsmReceiver.timeout) {
416 cyrf6936SetMode(CYRF6936_MODE_SYNTH_RX, true);
417 cyrf6936WriteRegister(CYRF6936_RX_ABORT, 0x00);
419 dsmReceiver.timeLastPacket += dsmReceiver.timeout;
421 switch (dsmReceiver.status) {
422 case DSM_RECEIVER_BIND:
423 dsmReceiver.rfChannel = (dsmReceiver.rfChannel + 2) % DSM_MAX_RF_CHANNEL;
424 cyrf6936SetChannel(dsmReceiver.rfChannel);
425 dsmReceiver.timeout = DSM_BIND_TIMEOUT_US;
426 cyrf6936StartRecv();
427 break;
428 case DSM_RECEIVER_BIND2:
429 if (dsmReceiver.bindPackets++ > DSM_MAX_BIND_PACKETS) {
430 dsmReceiverStartTransfer();
431 } else {
432 dsmReceiver.timeout = DSM_BIND_TIMEOUT_US;
433 dsmSendBindPacket();
435 break;
436 case DSM_RECEIVER_SYNC_A:
437 case DSM_RECEIVER_SYNC_B:
438 IS_DSM2(dsmReceiver.protocol) ? dsmReceiverSetNextSyncChannel() : dsmReceiverSetNextChannel();
439 dsmReceiver.timeout = DSM_SYNC_TIMEOUT_US;
440 cyrf6936StartRecv();
441 break;
442 case DSM_RECEIVER_RECV:
443 dsmReceiver.missedPackets++;
444 DEBUG_SET(DEBUG_RX_SPEKTRUM_SPI, 0, dsmReceiver.missedPackets);
445 if (dsmReceiver.missedPackets < DSM_MAX_MISSED_PACKETS) {
446 dsmReceiverSetNextChannel();
447 if (dsmReceiver.crcSeed == ((dsmReceiver.mfgId[0] << 8) + dsmReceiver.mfgId[1])) {
448 dsmReceiver.timeout = DSM_RECV_SHORT_TIMEOUT_US;
449 } else {
450 dsmReceiver.timeout = dsmReceiver.numChannels < 8 ? DSM_RECV_LONG_TIMEOUT_US : DSM_RECV_MID_TIMEOUT_US;
452 cyrf6936StartRecv();
453 } else {
454 setRssiDirect(0, RSSI_SOURCE_RX_PROTOCOL);
455 dsmReceiver.status = DSM_RECEIVER_SYNC_A;
456 dsmReceiver.timeout = DSM_SYNC_TIMEOUT_US;
458 break;
459 #ifdef USE_RX_SPEKTRUM_TELEMETRY
460 case DSM_RECEIVER_TLM:
461 DEBUG_SET(DEBUG_RX_SPEKTRUM_SPI, 2, (cyrf6936ReadRegister(CYRF6936_TX_IRQ_STATUS) & CYRF6936_TXC_IRQ) == 0);
462 dsmReceiverSetNextChannel();
463 dsmReceiver.status = DSM_RECEIVER_RECV;
464 dsmReceiver.timeout = (dsmReceiver.numChannels < 8 ? DSM_RECV_LONG_TIMEOUT_US : DSM_RECV_MID_TIMEOUT_US) - DSM_TELEMETRY_TIMEOUT_US;
465 cyrf6936StartRecv();
466 break;
467 #endif
468 default:
469 break;
474 void spektrumSpiSetRcDataFromPayload(uint16_t *rcData, const uint8_t *payload)
476 if (rcData && payload) {
477 const uint8_t divider = (uint8_t) IS_DSMX(dsmReceiver.protocol);
478 const uint8_t bitShift = 10 + divider;
479 const uint16_t valueMax = IS_DSMX(dsmReceiver.protocol) ? 0x7FF : 0x3FF;
481 for (unsigned i = 0; i < 7; i++) {
482 const uint16_t tmp = (payload[2 * i] << 8) + payload[2 * i + 1];
483 const uint8_t chan = (tmp >> bitShift) & 0x0F;
484 const int16_t val = (tmp & valueMax) >> divider;
486 if (chan < dsmReceiver.numChannels) {
487 rcData[chan] = 988 + val;
493 static bool isValidPacket(const uint8_t *packet)
495 DEBUG_SET(DEBUG_RX_SPEKTRUM_SPI, 1, isError);
497 if (isError) {
498 if (dsmReceiver.status != DSM_RECEIVER_RECV && (cyrf6936GetRxStatus() & CYRF6936_BAD_CRC)) {
499 dsmReceiver.crcSeed = ~dsmReceiver.crcSeed;
500 } else {
501 return false;
504 if (!CHECK_MFG_ID(dsmReceiver.protocol, packet, dsmReceiver.mfgId)) {
505 return false;
507 return true;
510 rx_spi_received_e spektrumReadPacket(uint8_t *payload, const uint32_t timeStamp)
512 rx_spi_received_e result = RX_SPI_RECEIVED_NONE;
514 uint8_t packetLength, packet[16];
516 packetLength = cyrf6936ReadRegister(CYRF6936_RX_COUNT);
517 cyrf6936RecvLen(packet, packetLength);
519 cyrf6936WriteRegister(CYRF6936_XACT_CFG, CYRF6936_MODE_SYNTH_RX | CYRF6936_FRC_END);
520 cyrf6936WriteRegister(CYRF6936_RX_ABORT, 0x00);
522 if (packetLength < 2) {
523 return result;
526 switch (dsmReceiver.status) {
527 case DSM_RECEIVER_BIND:
528 if (packet[0] != packet[4] || packet[1] != packet[5]
529 || packet[2] != packet[6] || packet[3] != packet[7]) {
531 dsmReceiver.timeLastPacket = timeStamp;
532 dsmReceiver.timeout = DSM_BIND_TIMEOUT_US;
533 break;
536 unsigned i;
537 uint16_t bindSum = 384 - 0x10;
538 for (i = 0; i < 8; i++) {
539 bindSum += packet[i];
542 if (packet[8] != bindSum >> 8 || packet[9] != (bindSum & 0xFF)) {
543 break;
546 for (i = 8; i < 14; i++) {
547 bindSum += packet[i];
550 if (packet[14] != bindSum >> 8 || packet[15] != (bindSum & 0xFF)) {
551 break;
554 dsmReceiver.mfgId[0] = ~packet[0];
555 dsmReceiver.mfgId[1] = ~packet[1];
556 dsmReceiver.mfgId[2] = ~packet[2];
557 dsmReceiver.mfgId[3] = ~packet[3];
558 dsmReceiver.numChannels = packet[11];
559 dsmReceiver.protocol = packet[12];
560 memcpy(spektrumConfigMutable()->mfgId, dsmReceiver.mfgId, 4);
561 spektrumConfigMutable()->numChannels = dsmReceiver.numChannels;
562 spektrumConfigMutable()->protocol = dsmReceiver.protocol;
563 writeEEPROM();
565 cyrf6936SetDataCode(bindDataCode);
567 dsmReceiver.bindPackets = 0;
568 dsmReceiver.status = DSM_RECEIVER_BIND2;
569 dsmReceiver.timeLastPacket = timeStamp;
570 dsmReceiver.timeout = DSM_BIND_TIMEOUT_US;
571 dsmReceiver.bound = true;
573 result = RX_SPI_RECEIVED_BIND;
574 break;
575 case DSM_RECEIVER_SYNC_A:
576 if (isValidPacket(packet)) {
577 if (IS_DSM2(dsmReceiver.protocol)) {
578 dsmReceiver.rfChannels[0] = dsmReceiver.rfChannel;
579 dsmReceiver.rfChannels[1] = dsmReceiver.rfChannel;
581 dsmReceiver.status = DSM_RECEIVER_SYNC_B;
582 } else {
583 dsmReceiver.status = DSM_RECEIVER_RECV;
584 dsmReceiver.missedPackets = 0;
587 IS_DSM2(dsmReceiver.protocol) ? dsmReceiverSetNextSyncChannel() : dsmReceiverSetNextChannel();
588 resetReceiveTimeout(timeStamp);
589 cyrf6936StartRecv();
591 result = RX_SPI_RECEIVED_DATA;
593 break;
594 case DSM_RECEIVER_SYNC_B:
595 if (isValidPacket(packet)) {
596 if (dsmReceiver.crcSeed != ((dsmReceiver.mfgId[0] << 8) + dsmReceiver.mfgId[1])) {
597 dsmReceiver.rfChannels[0] = dsmReceiver.rfChannel;
598 } else {
599 dsmReceiver.rfChannels[1] = dsmReceiver.rfChannel;
602 if (dsmReceiver.rfChannels[0] != dsmReceiver.rfChannels[1]) {
603 dsmReceiver.status = DSM_RECEIVER_RECV;
604 dsmReceiver.missedPackets = 0;
605 dsmReceiverSetNextChannel();
606 resetReceiveTimeout(timeStamp);
607 cyrf6936StartRecv();
610 result = RX_SPI_RECEIVED_DATA;
612 break;
613 case DSM_RECEIVER_RECV:
614 if (isValidPacket(packet)) {
615 setRssi(403 + cyrf6936GetRssi() * 20, RSSI_SOURCE_RX_PROTOCOL);
616 dsmReceiver.missedPackets = 0;
617 DEBUG_SET(DEBUG_RX_SPEKTRUM_SPI, 0, dsmReceiver.missedPackets);
618 memcpy(payload, &packet[2], 14);
619 #ifdef USE_RX_SPEKTRUM_TELEMETRY
620 if (dsmReceiver.sendTelemetry && dsmReceiver.crcSeed == ((dsmReceiver.mfgId[0] << 8) + dsmReceiver.mfgId[1])) {
621 dsmSendTelemetryPacket();
622 dsmReceiver.sendTelemetry = false;
623 dsmReceiver.timeLastPacket = timeStamp;
624 dsmReceiver.timeout = DSM_TELEMETRY_TIMEOUT_US;
625 dsmReceiver.status = DSM_RECEIVER_TLM;
626 } else {
627 #endif
628 dsmReceiverSetNextChannel();
629 resetReceiveTimeout(timeStamp);
630 cyrf6936StartRecv();
631 #ifdef USE_RX_SPEKTRUM_TELEMETRY
633 #endif
634 result = RX_SPI_RECEIVED_DATA;
636 break;
637 default:
638 break;
641 return result;
644 rx_spi_received_e spektrumSpiDataReceived(uint8_t *payload)
646 rx_spi_received_e result = RX_SPI_RECEIVED_NONE;
647 uint32_t timeStamp;
649 if (rxSpiCheckBindRequested(true)) {
650 dsmReceiver.bound = false;
651 dsmReceiverStartBind();
654 if (cyrf6936RxFinished(&timeStamp)) {
655 result = spektrumReadPacket(payload, timeStamp);
658 checkTimeout();
660 dsmReceiver.bound ? (dsmReceiver.status == DSM_RECEIVER_BIND2 ? rxSpiLedBlinkRxLoss(RX_SPI_RECEIVED_DATA) : rxSpiLedBlinkRxLoss(result)) : rxSpiLedBlinkBind();
662 return result;
665 #endif /* USE_RX_SPEKTRUM */