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/>.
28 #ifdef USE_RX_FRSKY_SPI_D
30 #include "build/build_config.h"
31 #include "build/debug.h"
33 #include "common/maths.h"
34 #include "common/utils.h"
36 #include "config/feature.h"
38 #include "drivers/adc.h"
39 #include "drivers/io.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/frsky_hub.h"
60 #include "cc2500_frsky_d.h"
62 #if defined(USE_RX_FRSKY_SPI_TELEMETRY)
63 static uint8_t frame
[20];
64 static uint8_t telemetryId
;
66 #if defined(USE_TELEMETRY_FRSKY_HUB)
67 static bool telemetryEnabled
= false;
69 #define MAX_SERIAL_BYTES 64
71 #define A1_CONST_D 100
73 static uint8_t telemetryBytesGenerated
;
74 static uint8_t serialBuffer
[MAX_SERIAL_BYTES
]; // buffer for telemetry serial data
76 static uint8_t appendFrSkyHubData(uint8_t *buf
)
78 static uint8_t telemetryBytesSent
= 0;
79 static uint8_t telemetryBytesAcknowledged
= 0;
80 static uint8_t telemetryIdExpected
= 0;
82 if (telemetryId
== telemetryIdExpected
) {
83 telemetryBytesAcknowledged
= telemetryBytesSent
;
85 telemetryIdExpected
= (telemetryId
+ 1) & 0x1F;
86 if (!telemetryBytesGenerated
) {
87 telemetryBytesSent
= 0;
89 processFrSkyHubTelemetry(micros());
91 } else { // rx re-requests last packet
92 telemetryBytesSent
= telemetryBytesAcknowledged
;
96 for (uint8_t i
= 0; i
< 10; i
++) {
97 if (telemetryBytesSent
== telemetryBytesGenerated
) {
98 telemetryBytesGenerated
= 0;
102 buf
[i
] = serialBuffer
[telemetryBytesSent
];
103 telemetryBytesSent
= (telemetryBytesSent
+ 1) & (MAX_SERIAL_BYTES
- 1);
109 static void frSkyDTelemetryWriteByte(const char data
)
111 if (telemetryBytesGenerated
< MAX_SERIAL_BYTES
) {
112 serialBuffer
[telemetryBytesGenerated
++] = data
;
117 static void buildTelemetryFrame(const uint8_t *packet
)
120 switch (rxCc2500SpiConfig()->a1Source
) {
121 case FRSKY_SPI_A1_SOURCE_EXTADC
:
122 a1Value
= (adcGetChannel(ADC_EXTERNAL1
) & 0xff0) >> 4;
124 #if defined(USE_TELEMETRY_FRSKY_HUB)
125 case FRSKY_SPI_A1_SOURCE_CONST
:
126 a1Value
= A1_CONST_D
& 0xff;
129 case FRSKY_SPI_A1_SOURCE_VBAT
:
131 a1Value
= (getBatteryVoltage() / 5) & 0xff;
134 const uint8_t a2Value
= (adcGetChannel(ADC_RSSI
)) >> 4;
135 telemetryId
= packet
[4];
136 frame
[0] = 0x11; // length
137 frame
[1] = rxCc2500SpiConfig()->bindTxId
[0];
138 frame
[2] = rxCc2500SpiConfig()->bindTxId
[1];
141 frame
[5] = (uint8_t)cc2500getRssiDbm();
142 uint8_t bytesUsed
= 0;
143 #if defined(USE_TELEMETRY_FRSKY_HUB)
144 if (telemetryEnabled
) {
145 bytesUsed
= appendFrSkyHubData(&frame
[8]);
148 frame
[6] = bytesUsed
;
149 frame
[7] = telemetryId
;
151 #endif // USE_RX_FRSKY_SPI_TELEMETRY
153 #define FRSKY_D_CHANNEL_SCALING (2.0f / 3)
155 static void decodeChannelPair(uint16_t *channels
, const uint8_t *packet
, const uint8_t highNibbleOffset
)
157 channels
[0] = FRSKY_D_CHANNEL_SCALING
* (uint16_t)((packet
[highNibbleOffset
] & 0xf) << 8 | packet
[0]);
158 channels
[1] = FRSKY_D_CHANNEL_SCALING
* (uint16_t)((packet
[highNibbleOffset
] & 0xf0) << 4 | packet
[1]);
161 void frSkyDSetRcData(uint16_t *rcData
, const uint8_t *packet
)
163 static uint16_t dataErrorCount
= 0;
165 uint16_t channels
[RC_CHANNEL_COUNT_FRSKY_D
];
166 bool dataError
= false;
168 decodeChannelPair(channels
, packet
+ 6, 4);
169 decodeChannelPair(channels
+ 2, packet
+ 8, 3);
170 decodeChannelPair(channels
+ 4, packet
+ 12, 4);
171 decodeChannelPair(channels
+ 6, packet
+ 14, 3);
173 for (int i
= 0; i
< RC_CHANNEL_COUNT_FRSKY_D
; i
++) {
174 if ((channels
[i
] < 800) || (channels
[i
] > 2200)) {
182 for (int i
= 0; i
< RC_CHANNEL_COUNT_FRSKY_D
; i
++) {
183 rcData
[i
] = channels
[i
];
186 DEBUG_SET(DEBUG_RX_FRSKY_SPI
, DEBUG_DATA_ERROR_COUNT
, ++dataErrorCount
);
190 rx_spi_received_e
frSkyDHandlePacket(uint8_t * const packet
, uint8_t * const protocolState
)
192 static timeUs_t lastPacketReceivedTime
= 0;
193 static timeUs_t telemetryTimeUs
;
195 rx_spi_received_e ret
= RX_SPI_RECEIVED_NONE
;
197 const timeUs_t currentPacketReceivedTime
= micros();
199 switch (*protocolState
) {
202 initialiseData(false);
203 *protocolState
= STATE_UPDATE
;
205 cc2500Strobe(CC2500_SRX
);
209 lastPacketReceivedTime
= currentPacketReceivedTime
;
210 *protocolState
= STATE_DATA
;
212 if (rxSpiCheckBindRequested(false)) {
213 lastPacketReceivedTime
= 0;
217 *protocolState
= STATE_INIT
;
221 FALLTHROUGH
; //!!TODO -check this fall through is correct
222 // here FS code could be
224 if (rxSpiGetExtiState()) {
225 uint8_t ccLen
= cc2500ReadReg(CC2500_3B_RXBYTES
| CC2500_READ_BURST
) & 0x7F;
226 bool packetOk
= false;
228 cc2500ReadFifo(packet
, 20);
229 if (packet
[19] & 0x80) {
233 if (packet
[0] == 0x11) {
234 if ((packet
[1] == rxCc2500SpiConfig()->bindTxId
[0]) &&
235 (packet
[2] == rxCc2500SpiConfig()->bindTxId
[1]) &&
236 (packet
[5] == rxCc2500SpiConfig()->bindTxId
[2])) {
239 cc2500setRssiDbm(packet
[18]);
240 #if defined(USE_RX_FRSKY_SPI_TELEMETRY)
241 if ((packet
[3] % 4) == 2) {
242 telemetryTimeUs
= micros();
243 buildTelemetryFrame(packet
);
244 *protocolState
= STATE_TELEMETRY
;
248 cc2500Strobe(CC2500_SRX
);
249 *protocolState
= STATE_UPDATE
;
251 ret
= RX_SPI_RECEIVED_DATA
;
252 lastPacketReceivedTime
= currentPacketReceivedTime
;
258 cc2500Strobe(CC2500_SFRX
);
262 if (cmpTimeUs(currentPacketReceivedTime
, lastPacketReceivedTime
) > (timeoutUs
* SYNC_DELAY_MAX
)) {
263 #if defined(USE_RX_CC2500_SPI_PA_LNA)
266 if (timeoutUs
== 1) {
267 #if defined(USE_RX_CC2500_SPI_PA_LNA) && defined(USE_RX_CC2500_SPI_DIVERSITY) // SE4311 chip
268 if (missingPackets
>= 2) {
269 cc2500switchAntennae();
273 if (missingPackets
> MAX_MISSING_PKT
) {
276 setRssiDirect(0, RSSI_SOURCE_RX_PROTOCOL
);
284 setRssi(0, RSSI_SOURCE_RX_PROTOCOL
);
288 cc2500Strobe(CC2500_SRX
);
289 *protocolState
= STATE_UPDATE
;
292 #if defined(USE_RX_FRSKY_SPI_TELEMETRY)
293 case STATE_TELEMETRY
:
294 if (cmpTimeUs(micros(), telemetryTimeUs
) >= 1380) {
295 cc2500Strobe(CC2500_SIDLE
);
297 cc2500Strobe(CC2500_SFRX
);
298 #if defined(USE_RX_CC2500_SPI_PA_LNA)
301 cc2500Strobe(CC2500_SIDLE
);
302 cc2500WriteFifo(frame
, frame
[0] + 1);
303 *protocolState
= STATE_DATA
;
304 lastPacketReceivedTime
= currentPacketReceivedTime
;
315 void frSkyDInit(void)
317 #if defined(USE_RX_FRSKY_SPI_TELEMETRY) && defined(USE_TELEMETRY_FRSKY_HUB)
318 if (featureIsEnabled(FEATURE_TELEMETRY
)) {
319 telemetryEnabled
= initFrSkyHubTelemetryExternal(frSkyDTelemetryWriteByte
);