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)
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/>.
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"
40 #include "pg/pg_ids.h"
41 #include "pg/rx_spi.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] = {
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}
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}
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}
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}
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
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]))
150 DSM_RECEIVER_BIND
= 0,
155 #ifdef USE_RX_SPEKTRUM_TELEMETRY
158 } dsm_receiver_status_e
;
160 typedef struct dsmReceiver_s
{
161 dsm_receiver_status_e status
;
162 dsm_protocol_e protocol
;
167 uint8_t rfChannelIdx
;
168 uint8_t rfChannels
[23];
174 uint8_t missedPackets
;
180 uint32_t timeLastPacket
;
182 uint16_t bindPackets
;
184 #ifdef USE_RX_SPEKTRUM_TELEMETRY
185 uint32_t timeLastTelemetry
;
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)
198 const uint32_t id
= ~((dsmReceiver
.mfgId
[0] << 24) | (dsmReceiver
.mfgId
[1] << 16) | (dsmReceiver
.mfgId
[2] << 8) | (dsmReceiver
.mfgId
[3] << 0));
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) {
211 for (i
= 0; i
< idx
; i
++) {
212 if (dsmReceiver
.rfChannels
[i
] == nextCh
) {
216 if (dsmReceiver
.rfChannels
[i
] <= 27) {
218 } else if (dsmReceiver
.rfChannels
[i
] <= 51) {
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
;
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
;
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();
311 memset(dsmReceiver
.rfChannels
, 0, 23);
312 dsmReceiverSetNextSyncChannel();
315 dsmReceiver
.timeLastPacket
= micros();
316 dsmReceiver
.timeout
= DSM_SYNC_TIMEOUT_US
<< 2;
320 bool spektrumSpiInit(const struct rxSpiConfig_s
*rxConfig
, struct rxRuntimeState_s
*rxRuntimeState
, rxSpiExtiConfig_t
*extiConfig
)
324 if (!rxSpiExtiConfigured()) {
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()) {
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;
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();
357 dsmReceiver
.bound
= false;
358 dsmReceiverStartBind();
364 #ifdef USE_RX_SPEKTRUM_TELEMETRY
365 static void dsmSendTelemetryPacket(void)
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);
384 static void dsmSendBindPacket(void)
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];
393 packet
[5] = dsmReceiver
.numChannels
;
394 packet
[6] = dsmReceiver
.protocol
;
396 for(unsigned i
= 0; i
< 8; 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;
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
;
428 case DSM_RECEIVER_BIND2
:
429 if (dsmReceiver
.bindPackets
++ > DSM_MAX_BIND_PACKETS
) {
430 dsmReceiverStartTransfer();
432 dsmReceiver
.timeout
= DSM_BIND_TIMEOUT_US
;
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
;
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
;
450 dsmReceiver
.timeout
= dsmReceiver
.numChannels
< 8 ? DSM_RECV_LONG_TIMEOUT_US
: DSM_RECV_MID_TIMEOUT_US
;
454 setRssiDirect(0, RSSI_SOURCE_RX_PROTOCOL
);
455 dsmReceiver
.status
= DSM_RECEIVER_SYNC_A
;
456 dsmReceiver
.timeout
= DSM_SYNC_TIMEOUT_US
;
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
;
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
);
498 if (dsmReceiver
.status
!= DSM_RECEIVER_RECV
&& (cyrf6936GetRxStatus() & CYRF6936_BAD_CRC
)) {
499 dsmReceiver
.crcSeed
= ~dsmReceiver
.crcSeed
;
504 if (!CHECK_MFG_ID(dsmReceiver
.protocol
, packet
, dsmReceiver
.mfgId
)) {
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) {
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
;
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)) {
546 for (i
= 8; i
< 14; i
++) {
547 bindSum
+= packet
[i
];
550 if (packet
[14] != bindSum
>> 8 || packet
[15] != (bindSum
& 0xFF)) {
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
;
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
;
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
;
583 dsmReceiver
.status
= DSM_RECEIVER_RECV
;
584 dsmReceiver
.missedPackets
= 0;
587 IS_DSM2(dsmReceiver
.protocol
) ? dsmReceiverSetNextSyncChannel() : dsmReceiverSetNextChannel();
588 resetReceiveTimeout(timeStamp
);
591 result
= RX_SPI_RECEIVED_DATA
;
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
;
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
);
610 result
= RX_SPI_RECEIVED_DATA
;
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
;
628 dsmReceiverSetNextChannel();
629 resetReceiveTimeout(timeStamp
);
631 #ifdef USE_RX_SPEKTRUM_TELEMETRY
634 result
= RX_SPI_RECEIVED_DATA
;
644 rx_spi_received_e
spektrumSpiDataReceived(uint8_t *payload
)
646 rx_spi_received_e result
= RX_SPI_RECEIVED_NONE
;
649 if (rxSpiCheckBindRequested(true)) {
650 dsmReceiver
.bound
= false;
651 dsmReceiverStartBind();
654 if (cyrf6936RxFinished(&timeStamp
)) {
655 result
= spektrumReadPacket(payload
, timeStamp
);
660 dsmReceiver
.bound
? (dsmReceiver
.status
== DSM_RECEIVER_BIND2
? rxSpiLedBlinkRxLoss(RX_SPI_RECEIVED_DATA
) : rxSpiLedBlinkRxLoss(result
)) : rxSpiLedBlinkBind();
665 #endif /* USE_RX_SPEKTRUM */