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/>.
25 #ifdef USE_RX_FRSKY_SPI_X
27 #include "build/build_config.h"
28 #include "build/debug.h"
30 #include "common/maths.h"
31 #include "common/utils.h"
33 #include "config/feature.h"
35 #include "drivers/adc.h"
36 #include "drivers/io.h"
37 #include "drivers/io_def.h"
38 #include "drivers/io_types.h"
39 #include "drivers/resource.h"
40 #include "drivers/rx/rx_cc2500.h"
41 #include "drivers/rx/rx_spi.h"
42 #include "drivers/system.h"
43 #include "drivers/time.h"
45 #include "config/config.h"
48 #include "pg/rx_spi.h"
49 #include "pg/rx_spi_cc2500.h"
51 #include "rx/rx_spi_common.h"
52 #include "rx/cc2500_common.h"
53 #include "rx/cc2500_frsky_common.h"
54 #include "rx/cc2500_frsky_shared.h"
56 #include "sensors/battery.h"
58 #include "telemetry/smartport.h"
60 #include "cc2500_frsky_x.h"
62 const uint16_t crcTable_Short
[] = {
63 0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,
64 0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
67 #define TELEMETRY_OUT_BUFFER_SIZE 64
69 #define TELEMETRY_SEQUENCE_LENGTH 4
73 typedef struct telemetrySequenceMarkerData_s
{
74 unsigned int packetSequenceId
: 2;
75 unsigned int unused
: 1;
76 unsigned int initRequest
: 1;
77 unsigned int ackSequenceId
: 2;
78 unsigned int retransmissionRequested
: 1;
79 unsigned int initResponse
: 1;
80 } __attribute__ ((__packed__
)) telemetrySequenceMarkerData_t
;
82 typedef union telemetrySequenceMarker_s
{
84 telemetrySequenceMarkerData_t data
;
85 } __attribute__ ((__packed__
)) telemetrySequenceMarker_t
;
87 #define SEQUENCE_MARKER_REMOTE_PART 0xf0
89 #define TELEMETRY_DATA_SIZE 5
91 typedef struct telemetryData_s
{
93 uint8_t data
[TELEMETRY_DATA_SIZE
];
94 } __attribute__ ((__packed__
)) telemetryData_t
;
96 typedef struct telemetryBuffer_s
{
98 uint8_t needsProcessing
;
101 #define TELEMETRY_FRAME_SIZE sizeof(telemetryData_t)
103 typedef struct telemetryPayload_s
{
106 telemetrySequenceMarker_t sequence
;
107 telemetryData_t data
;
109 } __attribute__ ((__packed__
)) telemetryPayload_t
;
111 #if defined(USE_RX_FRSKY_SPI_TELEMETRY)
112 static telemetryData_t telemetryTxBuffer
[TELEMETRY_SEQUENCE_LENGTH
];
115 static telemetryBuffer_t telemetryRxBuffer
[TELEMETRY_SEQUENCE_LENGTH
];
117 static telemetrySequenceMarker_t responseToSend
;
119 #if defined(USE_RX_FRSKY_SPI_TELEMETRY)
120 static uint8_t frame
[20];
122 #if defined(USE_TELEMETRY_SMARTPORT)
123 static uint8_t telemetryOutWriter
;
125 static uint8_t telemetryOutBuffer
[TELEMETRY_OUT_BUFFER_SIZE
];
127 static bool telemetryEnabled
= false;
129 static uint8_t remoteToProcessId
= 0;
130 static uint8_t remoteToProcessIndex
= 0;
132 #endif // USE_RX_FRSKY_SPI_TELEMETRY
134 static uint8_t packetLength
;
135 static uint16_t telemetryDelayUs
;
137 static uint16_t crcTable(uint8_t val
)
140 word
= (*(&crcTable_Short
[val
& 0x0f]));
142 return word
^ (0x1081 * val
);
145 static uint16_t calculateCrc(const uint8_t *data
, uint8_t len
)
148 for (unsigned i
= 0; i
< len
; i
++) {
149 crc
= (crc
<< 8) ^ crcTable((uint8_t)(crc
>> 8) ^ *data
++);
154 #if defined(USE_RX_FRSKY_SPI_TELEMETRY)
155 #if defined(USE_TELEMETRY_SMARTPORT)
156 static uint8_t appendSmartPortData(uint8_t *buf
)
158 static uint8_t telemetryOutReader
= 0;
161 for (index
= 0; index
< TELEMETRY_DATA_SIZE
; index
++) { // max 5 bytes in a frame
162 if (telemetryOutReader
== telemetryOutWriter
) { // no new data
165 buf
[index
] = telemetryOutBuffer
[telemetryOutReader
];
166 telemetryOutReader
= (telemetryOutReader
+ 1) % TELEMETRY_OUT_BUFFER_SIZE
;
173 static void buildTelemetryFrame(uint8_t *packet
)
175 static uint8_t localPacketId
;
177 static bool evenRun
= false;
179 frame
[0] = 0x0E;//length
180 frame
[1] = rxCc2500SpiConfig()->bindTxId
[0];
181 frame
[2] = rxCc2500SpiConfig()->bindTxId
[1];
183 if (spiProtocol
== RX_SPI_FRSKY_X_V2
|| spiProtocol
== RX_SPI_FRSKY_X_LBT_V2
) {
184 frame
[3] = rxCc2500SpiConfig()->bindTxId
[2];
186 frame
[3] = packet
[3];
190 frame
[4] = (uint8_t)cc2500getRssiDbm() | 0x80;
193 switch (rxCc2500SpiConfig()->a1Source
) {
194 case FRSKY_SPI_A1_SOURCE_EXTADC
:
195 a1Value
= (uint8_t)((adcGetChannel(ADC_EXTERNAL1
) & 0xfe0) >> 5);
197 case FRSKY_SPI_A1_SOURCE_CONST
:
198 a1Value
= A1_CONST_X
& 0x7f;
200 case FRSKY_SPI_A1_SOURCE_VBAT
:
202 a1Value
= getLegacyBatteryVoltage() & 0x7f;
209 telemetrySequenceMarker_t
*inFrameMarker
= (telemetrySequenceMarker_t
*)&packet
[21];
210 telemetrySequenceMarker_t
*outFrameMarker
= (telemetrySequenceMarker_t
*)&frame
[5];
211 if (inFrameMarker
->data
.initRequest
) { // check syncronization at startup ok if not no sport telemetry
212 outFrameMarker
-> raw
= 0;
213 outFrameMarker
->data
.initRequest
= 1;
214 outFrameMarker
->data
.initResponse
= 1;
218 if (inFrameMarker
->data
.retransmissionRequested
) {
219 uint8_t retransmissionFrameId
= inFrameMarker
->data
.ackSequenceId
;
220 outFrameMarker
->raw
= responseToSend
.raw
& SEQUENCE_MARKER_REMOTE_PART
;
221 outFrameMarker
->data
.packetSequenceId
= retransmissionFrameId
;
223 memcpy(&frame
[6], &telemetryTxBuffer
[retransmissionFrameId
], TELEMETRY_FRAME_SIZE
);
225 uint8_t localAckId
= inFrameMarker
->data
.ackSequenceId
;
226 if (localPacketId
!= (localAckId
+ 1) % TELEMETRY_SEQUENCE_LENGTH
) {
227 outFrameMarker
->raw
= responseToSend
.raw
& SEQUENCE_MARKER_REMOTE_PART
;
228 outFrameMarker
->data
.packetSequenceId
= localPacketId
;
230 #if defined(USE_TELEMETRY_SMARTPORT)
231 frame
[6] = appendSmartPortData(&frame
[7]);
232 memcpy(&telemetryTxBuffer
[localPacketId
], &frame
[6], TELEMETRY_FRAME_SIZE
);
234 localPacketId
= (localPacketId
+ 1) % TELEMETRY_SEQUENCE_LENGTH
;
239 uint16_t lcrc
= calculateCrc(&frame
[3], 10);
244 #if defined(USE_TELEMETRY_SMARTPORT)
245 static bool frSkyXReadyToSend(void)
251 #if defined(USE_TELEMETRY_SMARTPORT)
252 static void frSkyXTelemetrySendByte(uint8_t c
)
254 if (c
== FSSP_DLE
|| c
== FSSP_START_STOP
) {
255 telemetryOutBuffer
[telemetryOutWriter
] = FSSP_DLE
;
256 telemetryOutWriter
= (telemetryOutWriter
+ 1) % TELEMETRY_OUT_BUFFER_SIZE
;
257 telemetryOutBuffer
[telemetryOutWriter
] = c
^ FSSP_DLE_XOR
;
258 telemetryOutWriter
= (telemetryOutWriter
+ 1) % TELEMETRY_OUT_BUFFER_SIZE
;
260 telemetryOutBuffer
[telemetryOutWriter
] = c
;
261 telemetryOutWriter
= (telemetryOutWriter
+ 1) % TELEMETRY_OUT_BUFFER_SIZE
;
265 static void frSkyXTelemetryWriteFrame(const smartPortPayload_t
*payload
)
267 telemetryOutBuffer
[telemetryOutWriter
] = FSSP_START_STOP
;
268 telemetryOutWriter
= (telemetryOutWriter
+ 1) % TELEMETRY_OUT_BUFFER_SIZE
;
269 telemetryOutBuffer
[telemetryOutWriter
] = FSSP_SENSOR_ID1
& 0x1f;
270 telemetryOutWriter
= (telemetryOutWriter
+ 1) % TELEMETRY_OUT_BUFFER_SIZE
;
271 uint8_t *data
= (uint8_t *)payload
;
272 for (unsigned i
= 0; i
< sizeof(smartPortPayload_t
); i
++) {
273 frSkyXTelemetrySendByte(*data
++);
277 #endif // USE_RX_FRSKY_SPI_TELEMETRY
280 void frSkyXSetRcData(uint16_t *rcData
, const uint8_t *packet
)
283 // ignore failsafe packet
284 if (packet
[7] != 0) {
287 c
[0] = (uint16_t)((packet
[10] << 8) & 0xF00) | packet
[9];
288 c
[1] = (uint16_t)((packet
[11] << 4) & 0xFF0) | (packet
[10] >> 4);
289 c
[2] = (uint16_t)((packet
[13] << 8) & 0xF00) | packet
[12];
290 c
[3] = (uint16_t)((packet
[14] << 4) & 0xFF0) | (packet
[13] >> 4);
291 c
[4] = (uint16_t)((packet
[16] << 8) & 0xF00) | packet
[15];
292 c
[5] = (uint16_t)((packet
[17] << 4) & 0xFF0) | (packet
[16] >> 4);
293 c
[6] = (uint16_t)((packet
[19] << 8) & 0xF00) | packet
[18];
294 c
[7] = (uint16_t)((packet
[20] << 4) & 0xFF0) | (packet
[19] >> 4);
296 for (unsigned i
= 0; i
< 8; i
++) {
297 const bool channelIsShifted
= c
[i
] & 0x800;
298 const uint16_t channelValue
= c
[i
] & 0x7FF;
299 rcData
[channelIsShifted
? i
+ 8 : i
] = ((channelValue
- 64) * 2 + 860 * 3) / 3;
303 bool isValidPacket(const uint8_t *packet
)
305 bool useBindTxId2
= false;
307 if (spiProtocol
== RX_SPI_FRSKY_X_V2
|| spiProtocol
== RX_SPI_FRSKY_X_LBT_V2
) {
309 if (!(packet
[packetLength
- 1] & 0x80)) {
314 uint16_t lcrc
= calculateCrc(&packet
[3], (packetLength
- 7));
316 if ((lcrc
>> 8) == packet
[packetLength
- 4] && (lcrc
& 0x00FF) == packet
[packetLength
- 3] &&
317 (packet
[0] == packetLength
- 3) &&
318 (packet
[1] == rxCc2500SpiConfig()->bindTxId
[0]) &&
319 (packet
[2] == rxCc2500SpiConfig()->bindTxId
[1]) &&
320 (!useBindTxId2
|| (packet
[3] == rxCc2500SpiConfig()->bindTxId
[2])) &&
321 (rxCc2500SpiConfig()->rxNum
== 0 || packet
[6] == 0 || packet
[6] == rxCc2500SpiConfig()->rxNum
)) {
327 rx_spi_received_e
frSkyXHandlePacket(uint8_t * const packet
, uint8_t * const protocolState
)
329 static unsigned receiveTelemetryRetryCount
= 0;
330 static bool skipChannels
= true;
332 static uint8_t remoteAckId
= 0;
334 static timeUs_t packetTimerUs
;
336 static bool frameReceived
;
337 static timeDelta_t receiveDelayUs
;
338 static uint8_t channelsToSkip
= 1;
339 static uint32_t packetErrors
= 0;
341 #if defined(USE_RX_FRSKY_SPI_TELEMETRY)
342 static bool telemetryReceived
= false;
345 rx_spi_received_e ret
= RX_SPI_RECEIVED_NONE
;
347 switch (*protocolState
) {
350 initialiseData(false);
351 *protocolState
= STATE_UPDATE
;
353 cc2500Strobe(CC2500_SRX
);
356 packetTimerUs
= micros();
357 *protocolState
= STATE_DATA
;
358 frameReceived
= false; // again set for receive
359 receiveDelayUs
= 5300;
360 if (rxSpiCheckBindRequested(false)) {
364 *protocolState
= STATE_INIT
;
370 // here FS code could be
372 if (rxSpiGetExtiState() && (!frameReceived
)) {
373 uint8_t ccLen
= cc2500ReadReg(CC2500_3B_RXBYTES
| CC2500_READ_BURST
) & 0x7F;
374 if (ccLen
>= packetLength
) {
375 cc2500ReadFifo(packet
, packetLength
);
376 if (isValidPacket(packet
)) {
382 channelsToSkip
= (packet
[5] << 2) | (packet
[4] >> 6);
383 telemetryReceived
= true; // now telemetry can be sent
384 skipChannels
= false;
386 cc2500setRssiDbm(packet
[packetLength
- 2]);
388 telemetrySequenceMarker_t
*inFrameMarker
= (telemetrySequenceMarker_t
*)&packet
[21];
390 uint8_t remoteNewPacketId
= inFrameMarker
->data
.packetSequenceId
;
391 memcpy(&telemetryRxBuffer
[remoteNewPacketId
].data
, &packet
[22], TELEMETRY_FRAME_SIZE
);
392 telemetryRxBuffer
[remoteNewPacketId
].needsProcessing
= true;
394 responseToSend
.raw
= 0;
395 uint8_t remoteToAckId
= (remoteAckId
+ 1) % TELEMETRY_SEQUENCE_LENGTH
;
396 if (remoteNewPacketId
!= remoteToAckId
) {
397 while (remoteToAckId
!= remoteNewPacketId
) {
398 if (!telemetryRxBuffer
[remoteToAckId
].needsProcessing
) {
399 responseToSend
.data
.ackSequenceId
= remoteToAckId
;
400 responseToSend
.data
.retransmissionRequested
= 1;
402 receiveTelemetryRetryCount
++;
407 remoteToAckId
= (remoteToAckId
+ 1) % TELEMETRY_SEQUENCE_LENGTH
;
411 if (!responseToSend
.data
.retransmissionRequested
) {
412 receiveTelemetryRetryCount
= 0;
414 remoteToAckId
= (remoteAckId
+ 1) % TELEMETRY_SEQUENCE_LENGTH
;
415 uint8_t remoteNextAckId
= remoteToAckId
;
416 while (telemetryRxBuffer
[remoteToAckId
].needsProcessing
&& remoteToAckId
!= remoteAckId
) {
417 remoteNextAckId
= remoteToAckId
;
418 remoteToAckId
= (remoteToAckId
+ 1) % TELEMETRY_SEQUENCE_LENGTH
;
420 remoteAckId
= remoteNextAckId
;
421 responseToSend
.data
.ackSequenceId
= remoteAckId
;
424 if (receiveTelemetryRetryCount
>= 5) {
425 #if defined(USE_RX_FRSKY_SPI_TELEMETRY) && defined(USE_TELEMETRY_SMARTPORT)
426 remoteToProcessId
= 0;
427 remoteToProcessIndex
= 0;
429 remoteAckId
= TELEMETRY_SEQUENCE_LENGTH
- 1;
430 for (unsigned i
= 0; i
< TELEMETRY_SEQUENCE_LENGTH
; i
++) {
431 telemetryRxBuffer
[i
].needsProcessing
= false;
434 receiveTelemetryRetryCount
= 0;
437 packetTimerUs
= micros();
438 frameReceived
= true; // no need to process frame again.
440 if (!frameReceived
) {
442 DEBUG_SET(DEBUG_RX_FRSKY_SPI
, DEBUG_DATA_BAD_FRAME
, packetErrors
);
443 cc2500Strobe(CC2500_SFRX
);
447 if (telemetryReceived
) {
448 if (cmpTimeUs(micros(), packetTimerUs
) > receiveDelayUs
) { // if received or not received in this time sent telemetry data
449 *protocolState
= STATE_TELEMETRY
;
450 buildTelemetryFrame(packet
);
453 if (cmpTimeUs(micros(), packetTimerUs
) > timeoutUs
* SYNC_DELAY_MAX
) {
456 setRssiDirect(0, RSSI_SOURCE_RX_PROTOCOL
);
458 cc2500Strobe(CC2500_SRX
);
459 *protocolState
= STATE_UPDATE
;
462 ret
|= RX_SPI_RECEIVED_DATA
;
464 frameReceived
= false;
468 #ifdef USE_RX_FRSKY_SPI_TELEMETRY
469 case STATE_TELEMETRY
:
470 if (cmpTimeUs(micros(), packetTimerUs
) >= receiveDelayUs
+ telemetryDelayUs
) { // if received or not received in this time sent telemetry data
471 cc2500Strobe(CC2500_SIDLE
);
473 cc2500Strobe(CC2500_SFRX
);
474 delayMicroseconds(30);
475 #if defined(USE_RX_CC2500_SPI_PA_LNA)
478 cc2500Strobe(CC2500_SIDLE
);
479 cc2500WriteFifo(frame
, frame
[0] + 1);
481 #if defined(USE_TELEMETRY_SMARTPORT)
482 if (telemetryEnabled
) {
483 ret
|= RX_SPI_PROCESSING_REQUIRED
;
486 *protocolState
= STATE_RESUME
;
490 #endif // USE_RX_FRSKY_SPI_TELEMETRY
492 if (cmpTimeUs(micros(), packetTimerUs
) > receiveDelayUs
+ 3700) {
493 packetTimerUs
= micros();
494 receiveDelayUs
= 5300;
495 frameReceived
= false; // again set for receive
496 nextChannel(channelsToSkip
);
497 cc2500Strobe(CC2500_SRX
);
498 #ifdef USE_RX_CC2500_SPI_PA_LNA
500 #if defined(USE_RX_CC2500_SPI_DIVERSITY)
501 if (missingPackets
>= 2) {
502 cc2500switchAntennae();
505 #endif // USE_RX_CC2500_SPI_PA_LNA
506 if (missingPackets
> MAX_MISSING_PKT
) {
509 telemetryReceived
= false;
510 *protocolState
= STATE_UPDATE
;
514 DEBUG_SET(DEBUG_RX_FRSKY_SPI
, DEBUG_DATA_MISSING_PACKETS
, missingPackets
);
515 *protocolState
= STATE_DATA
;
523 #if defined(USE_RX_FRSKY_SPI_TELEMETRY) && defined(USE_TELEMETRY_SMARTPORT)
524 rx_spi_received_e
frSkyXProcessFrame(uint8_t * const packet
)
526 static timeMs_t pollingTimeMs
= 0;
530 bool clearToSend
= false;
531 timeMs_t now
= millis();
532 smartPortPayload_t
*payload
= NULL
;
533 if ((now
- pollingTimeMs
) > 24) {
538 while (telemetryRxBuffer
[remoteToProcessId
].needsProcessing
&& !payload
) {
539 if (remoteToProcessIndex
>= telemetryRxBuffer
[remoteToProcessId
].data
.dataLength
) {
540 remoteToProcessIndex
= 0;
541 telemetryRxBuffer
[remoteToProcessId
].needsProcessing
= false;
542 remoteToProcessId
= (remoteToProcessId
+ 1) % TELEMETRY_SEQUENCE_LENGTH
;
544 if (!telemetryRxBuffer
[remoteToProcessId
].needsProcessing
) {
549 while (remoteToProcessIndex
< telemetryRxBuffer
[remoteToProcessId
].data
.dataLength
&& !payload
) {
550 payload
= smartPortDataReceive(telemetryRxBuffer
[remoteToProcessId
].data
.data
[remoteToProcessIndex
], &clearToSend
, frSkyXReadyToSend
, false);
551 remoteToProcessIndex
= remoteToProcessIndex
+ 1;
556 processSmartPortTelemetry(payload
, &clearToSend
, NULL
);
558 return RX_SPI_RECEIVED_NONE
;
562 uint8_t frSkyXInit(void)
564 switch(spiProtocol
) {
566 packetLength
= FRSKY_RX_D16FCC_LENGTH
;
567 telemetryDelayUs
= 400;
569 case RX_SPI_FRSKY_X_LBT
:
570 packetLength
= FRSKY_RX_D16LBT_LENGTH
;
571 telemetryDelayUs
= 1400;
573 case RX_SPI_FRSKY_X_V2
:
574 packetLength
= FRSKY_RX_D16v2_LENGTH
;
575 telemetryDelayUs
= 400;
577 case RX_SPI_FRSKY_X_LBT_V2
:
578 packetLength
= FRSKY_RX_D16v2_LENGTH
;
579 telemetryDelayUs
= 1500;
584 #if defined(USE_TELEMETRY_SMARTPORT)
585 if (featureIsEnabled(FEATURE_TELEMETRY
)) {
586 telemetryEnabled
= initSmartPortTelemetryExternal(frSkyXTelemetryWriteFrame
);