2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
25 #ifdef USE_RX_FRSKY_SPI_D
27 #include "build/build_config.h"
28 #include "build/debug.h"
30 #include "common/maths.h"
31 #include "common/utils.h"
33 #include "drivers/adc.h"
34 #include "drivers/rx/rx_cc2500.h"
35 #include "drivers/io.h"
36 #include "drivers/system.h"
37 #include "drivers/time.h"
39 #include "fc/config.h"
41 #include "rx/cc2500_frsky_common.h"
42 #include "rx/cc2500_frsky_shared.h"
44 #include "sensors/battery.h"
46 #include "telemetry/frsky_hub.h"
48 #include "cc2500_frsky_d.h"
50 #if defined(USE_RX_FRSKY_SPI_TELEMETRY)
51 static uint8_t frame
[20];
52 static uint8_t telemetryId
;
54 #if defined(USE_TELEMETRY_FRSKY_HUB)
55 static bool telemetryEnabled
= false;
57 #define MAX_SERIAL_BYTES 64
59 static uint8_t telemetryBytesGenerated
;
60 static uint8_t serialBuffer
[MAX_SERIAL_BYTES
]; // buffer for telemetry serial data
62 static uint8_t appendFrSkyHubData(uint8_t *buf
)
64 static uint8_t telemetryBytesSent
= 0;
65 static uint8_t telemetryBytesAcknowledged
= 0;
66 static uint8_t telemetryIdExpected
= 0;
68 if (telemetryId
== telemetryIdExpected
) {
69 telemetryBytesAcknowledged
= telemetryBytesSent
;
71 telemetryIdExpected
= (telemetryId
+ 1) & 0x1F;
72 if (!telemetryBytesGenerated
) {
73 telemetryBytesSent
= 0;
75 processFrSkyHubTelemetry(micros());
77 } else { // rx re-requests last packet
78 telemetryBytesSent
= telemetryBytesAcknowledged
;
82 for (uint8_t i
= 0; i
< 10; i
++) {
83 if (telemetryBytesSent
== telemetryBytesGenerated
) {
84 telemetryBytesGenerated
= 0;
88 buf
[i
] = serialBuffer
[telemetryBytesSent
];
89 telemetryBytesSent
= (telemetryBytesSent
+ 1) & (MAX_SERIAL_BYTES
- 1);
95 static void frSkyDTelemetryWriteByte(const char data
)
97 if (telemetryBytesGenerated
< MAX_SERIAL_BYTES
) {
98 serialBuffer
[telemetryBytesGenerated
++] = data
;
103 static void buildTelemetryFrame(uint8_t *packet
)
105 const uint16_t adcExternal1Sample
= adcGetChannel(ADC_EXTERNAL1
);
106 const uint16_t adcRssiSample
= adcGetChannel(ADC_RSSI
);
107 telemetryId
= packet
[4];
108 frame
[0] = 0x11; // length
109 frame
[1] = rxFrSkySpiConfig()->bindTxId
[0];
110 frame
[2] = rxFrSkySpiConfig()->bindTxId
[1];
111 frame
[3] = (uint8_t)((adcExternal1Sample
& 0xff0) >> 4); // A1
112 frame
[4] = (uint8_t)((adcRssiSample
& 0xff0) >> 4); // A2
113 frame
[5] = (uint8_t)rssiDbm
;
114 uint8_t bytesUsed
= 0;
115 #if defined(USE_TELEMETRY_FRSKY_HUB)
116 if (telemetryEnabled
) {
117 bytesUsed
= appendFrSkyHubData(&frame
[8]);
120 frame
[6] = bytesUsed
;
121 frame
[7] = telemetryId
;
123 #endif // USE_RX_FRSKY_SPI_TELEMETRY
125 #define FRSKY_D_CHANNEL_SCALING (2.0f / 3)
127 static void decodeChannelPair(uint16_t *channels
, const uint8_t *packet
, const uint8_t highNibbleOffset
) {
128 channels
[0] = FRSKY_D_CHANNEL_SCALING
* (uint16_t)((packet
[highNibbleOffset
] & 0xf) << 8 | packet
[0]);
129 channels
[1] = FRSKY_D_CHANNEL_SCALING
* (uint16_t)((packet
[highNibbleOffset
] & 0xf0) << 4 | packet
[1]);
132 void frSkyDSetRcData(uint16_t *rcData
, const uint8_t *packet
)
134 static uint16_t dataErrorCount
= 0;
136 uint16_t channels
[RC_CHANNEL_COUNT_FRSKY_D
];
137 bool dataError
= false;
139 decodeChannelPair(channels
, packet
+ 6, 4);
140 decodeChannelPair(channels
+ 2, packet
+ 8, 3);
141 decodeChannelPair(channels
+ 4, packet
+ 12, 4);
142 decodeChannelPair(channels
+ 6, packet
+ 14, 3);
144 for (int i
= 0; i
< RC_CHANNEL_COUNT_FRSKY_D
; i
++) {
145 if ((channels
[i
] < 800) || (channels
[i
] > 2200)) {
153 for (int i
= 0; i
< RC_CHANNEL_COUNT_FRSKY_D
; i
++) {
154 rcData
[i
] = channels
[i
];
157 DEBUG_SET(DEBUG_RX_FRSKY_SPI
, DEBUG_DATA_ERROR_COUNT
, ++dataErrorCount
);
161 rx_spi_received_e
frSkyDHandlePacket(uint8_t * const packet
, uint8_t * const protocolState
)
163 static timeUs_t lastPacketReceivedTime
= 0;
164 static timeUs_t telemetryTimeUs
;
168 rx_spi_received_e ret
= RX_SPI_RECEIVED_NONE
;
170 const timeUs_t currentPacketReceivedTime
= micros();
172 switch (*protocolState
) {
176 *protocolState
= STATE_UPDATE
;
178 cc2500Strobe(CC2500_SRX
);
182 lastPacketReceivedTime
= currentPacketReceivedTime
;
183 *protocolState
= STATE_DATA
;
185 if (checkBindRequested(false)) {
186 lastPacketReceivedTime
= 0;
190 *protocolState
= STATE_INIT
;
194 FALLTHROUGH
; //!!TODO -check this fall through is correct
195 // here FS code could be
197 if (IORead(gdoPin
)) {
198 uint8_t ccLen
= cc2500ReadReg(CC2500_3B_RXBYTES
| CC2500_READ_BURST
) & 0x7F;
200 cc2500ReadFifo(packet
, 20);
201 if (packet
[19] & 0x80) {
204 if (packet
[0] == 0x11) {
205 if ((packet
[1] == rxFrSkySpiConfig()->bindTxId
[0]) &&
206 (packet
[2] == rxFrSkySpiConfig()->bindTxId
[1])) {
209 #if defined(USE_RX_FRSKY_SPI_TELEMETRY)
210 if ((packet
[3] % 4) == 2) {
211 telemetryTimeUs
= micros();
212 setRssiDbm(packet
[18]);
213 buildTelemetryFrame(packet
);
214 *protocolState
= STATE_TELEMETRY
;
218 cc2500Strobe(CC2500_SRX
);
219 *protocolState
= STATE_UPDATE
;
221 ret
= RX_SPI_RECEIVED_DATA
;
222 lastPacketReceivedTime
= currentPacketReceivedTime
;
229 if (cmpTimeUs(currentPacketReceivedTime
, lastPacketReceivedTime
) > (timeoutUs
* SYNC_DELAY_MAX
)) {
230 #if defined(USE_RX_FRSKY_SPI_PA_LNA)
233 if (timeoutUs
== 1) {
234 #if defined(USE_RX_FRSKY_SPI_PA_LNA) && defined(USE_RX_FRSKY_SPI_DIVERSITY) // SE4311 chip
235 if (missingPackets
>= 2) {
240 if (missingPackets
> MAX_MISSING_PKT
) {
243 #if defined(USE_RX_FRSKY_SPI_TELEMETRY)
244 setRssiFiltered(0, RSSI_SOURCE_RX_PROTOCOL
);
258 #if defined(USE_RX_FRSKY_SPI_TELEMETRY)
259 setRssiUnfiltered(0, RSSI_SOURCE_RX_PROTOCOL
);
264 cc2500Strobe(CC2500_SRX
);
265 *protocolState
= STATE_UPDATE
;
268 #if defined(USE_RX_FRSKY_SPI_TELEMETRY)
269 case STATE_TELEMETRY
:
270 if (cmpTimeUs(micros(), telemetryTimeUs
) >= 1380) {
271 cc2500Strobe(CC2500_SIDLE
);
273 cc2500Strobe(CC2500_SFRX
);
274 #if defined(USE_RX_FRSKY_SPI_PA_LNA)
277 cc2500Strobe(CC2500_SIDLE
);
278 cc2500WriteFifo(frame
, frame
[0] + 1);
279 *protocolState
= STATE_DATA
;
280 ret
= RX_SPI_RECEIVED_DATA
;
281 lastPacketReceivedTime
= currentPacketReceivedTime
;
292 void frSkyDInit(void)
294 #if defined(USE_RX_FRSKY_SPI_TELEMETRY) && defined(USE_TELEMETRY_FRSKY_HUB)
295 telemetryEnabled
= initFrSkyHubTelemetryExternal(frSkyDTelemetryWriteByte
);