Put gyro debug axis in header (#13752)
[betaflight.git] / src / main / telemetry / smartport.c
blob7f1ebbbdf595de6d28e13425a20aec0d47faef99
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/>.
22 * SmartPort Telemetry implementation by frank26080115
23 * see https://github.com/frank26080115/cleanflight/wiki/Using-Smart-Port
25 #include <stdbool.h>
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <math.h>
31 #include "platform.h"
33 #if defined(USE_TELEMETRY_SMARTPORT)
35 #include "common/axis.h"
36 #include "common/color.h"
37 #include "common/maths.h"
38 #include "common/utils.h"
40 #include "config/feature.h"
42 #include "rx/frsky_crc.h"
44 #include "drivers/accgyro/accgyro.h"
45 #include "drivers/compass/compass.h"
46 #include "drivers/sensor.h"
47 #include "drivers/time.h"
48 #include "drivers/dshot.h"
50 #include "config/config.h"
51 #include "fc/controlrate_profile.h"
52 #include "fc/rc_controls.h"
53 #include "fc/runtime_config.h"
55 #include "flight/failsafe.h"
56 #include "flight/imu.h"
57 #include "flight/mixer.h"
58 #include "flight/pid.h"
59 #include "flight/position.h"
61 #include "io/beeper.h"
62 #include "io/gps.h"
63 #include "io/serial.h"
65 #include "msp/msp.h"
67 #include "rx/rx.h"
69 #include "pg/pg.h"
70 #include "pg/pg_ids.h"
71 #include "pg/rx.h"
73 #include "sensors/acceleration.h"
74 #include "sensors/adcinternal.h"
75 #include "sensors/barometer.h"
76 #include "sensors/battery.h"
77 #include "sensors/boardalignment.h"
78 #include "sensors/compass.h"
79 #include "sensors/esc_sensor.h"
80 #include "sensors/gyro.h"
81 #include "sensors/sensors.h"
83 #include "telemetry/msp_shared.h"
84 #include "telemetry/smartport.h"
85 #include "telemetry/telemetry.h"
87 #define SMARTPORT_MIN_TELEMETRY_RESPONSE_DELAY_US 500
89 // these data identifiers are obtained from https://github.com/opentx/opentx/blob/master/radio/src/telemetry/frsky_hub.h
90 enum
92 FSSP_DATAID_SPEED = 0x0830 ,
93 FSSP_DATAID_VFAS = 0x0210 ,
94 FSSP_DATAID_VFAS1 = 0x0211 ,
95 FSSP_DATAID_VFAS2 = 0x0212 ,
96 FSSP_DATAID_VFAS3 = 0x0213 ,
97 FSSP_DATAID_VFAS4 = 0x0214 ,
98 FSSP_DATAID_VFAS5 = 0x0215 ,
99 FSSP_DATAID_VFAS6 = 0x0216 ,
100 FSSP_DATAID_VFAS7 = 0x0217 ,
101 FSSP_DATAID_VFAS8 = 0x0218 ,
102 FSSP_DATAID_CURRENT = 0x0200 ,
103 FSSP_DATAID_CURRENT1 = 0x0201 ,
104 FSSP_DATAID_CURRENT2 = 0x0202 ,
105 FSSP_DATAID_CURRENT3 = 0x0203 ,
106 FSSP_DATAID_CURRENT4 = 0x0204 ,
107 FSSP_DATAID_CURRENT5 = 0x0205 ,
108 FSSP_DATAID_CURRENT6 = 0x0206 ,
109 FSSP_DATAID_CURRENT7 = 0x0207 ,
110 FSSP_DATAID_CURRENT8 = 0x0208 ,
111 FSSP_DATAID_RPM = 0x0500 ,
112 FSSP_DATAID_RPM1 = 0x0501 ,
113 FSSP_DATAID_RPM2 = 0x0502 ,
114 FSSP_DATAID_RPM3 = 0x0503 ,
115 FSSP_DATAID_RPM4 = 0x0504 ,
116 FSSP_DATAID_RPM5 = 0x0505 ,
117 FSSP_DATAID_RPM6 = 0x0506 ,
118 FSSP_DATAID_RPM7 = 0x0507 ,
119 FSSP_DATAID_RPM8 = 0x0508 ,
120 FSSP_DATAID_ALTITUDE = 0x0100 ,
121 FSSP_DATAID_FUEL = 0x0600 ,
122 FSSP_DATAID_ADC1 = 0xF102 ,
123 FSSP_DATAID_ADC2 = 0xF103 ,
124 FSSP_DATAID_LATLONG = 0x0800 ,
125 FSSP_DATAID_VARIO = 0x0110 ,
126 FSSP_DATAID_CELLS = 0x0300 ,
127 FSSP_DATAID_CELLS_LAST = 0x030F ,
128 FSSP_DATAID_HEADING = 0x0840 ,
129 // DIY range 0x5100 to 0x52FF
130 FSSP_DATAID_CAP_USED = 0x5250 ,
131 #if defined(USE_ACC)
132 FSSP_DATAID_PITCH = 0x5230 , // custom
133 FSSP_DATAID_ROLL = 0x5240 , // custom
134 FSSP_DATAID_ACCX = 0x0700 ,
135 FSSP_DATAID_ACCY = 0x0710 ,
136 FSSP_DATAID_ACCZ = 0x0720 ,
137 #endif
138 FSSP_DATAID_T1 = 0x0400 ,
139 FSSP_DATAID_T11 = 0x0401 ,
140 FSSP_DATAID_T2 = 0x0410 ,
141 FSSP_DATAID_HOME_DIST = 0x0420 ,
142 FSSP_DATAID_GPS_ALT = 0x0820 ,
143 FSSP_DATAID_ASPD = 0x0A00 ,
144 FSSP_DATAID_TEMP = 0x0B70 ,
145 FSSP_DATAID_TEMP1 = 0x0B71 ,
146 FSSP_DATAID_TEMP2 = 0x0B72 ,
147 FSSP_DATAID_TEMP3 = 0x0B73 ,
148 FSSP_DATAID_TEMP4 = 0x0B74 ,
149 FSSP_DATAID_TEMP5 = 0x0B75 ,
150 FSSP_DATAID_TEMP6 = 0x0B76 ,
151 FSSP_DATAID_TEMP7 = 0x0B77 ,
152 FSSP_DATAID_TEMP8 = 0x0B78 ,
153 FSSP_DATAID_A3 = 0x0900 ,
154 FSSP_DATAID_A4 = 0x0910
157 // if adding more sensors then increase this value (should be equal to the maximum number of ADD_SENSOR calls)
158 #define MAX_DATAIDS 20
160 static uint16_t frSkyDataIdTable[MAX_DATAIDS];
162 #ifdef USE_ESC_SENSOR_TELEMETRY
163 // number of sensors to send between sending the ESC sensors
164 #define ESC_SENSOR_PERIOD 7
166 // if adding more esc sensors then increase this value
167 #define MAX_ESC_DATAIDS 4
169 static uint16_t frSkyEscDataIdTable[MAX_ESC_DATAIDS];
170 #endif
172 typedef struct frSkyTableInfo_s {
173 uint16_t * table;
174 uint8_t size;
175 uint8_t index;
176 } frSkyTableInfo_t;
178 static frSkyTableInfo_t frSkyDataIdTableInfo = { frSkyDataIdTable, 0, 0 };
179 #ifdef USE_ESC_SENSOR_TELEMETRY
180 static frSkyTableInfo_t frSkyEscDataIdTableInfo = {frSkyEscDataIdTable, 0, 0};
181 #endif
183 #define SMARTPORT_BAUD 57600
184 #define SMARTPORT_UART_MODE MODE_RXTX
185 #define SMARTPORT_SERVICE_TIMEOUT_US 1000 // max allowed time to find a value to send
187 static serialPort_t *smartPortSerialPort = NULL; // The 'SmartPort'(tm) Port.
188 static const serialPortConfig_t *portConfig;
190 static portSharing_e smartPortPortSharing;
192 enum
194 TELEMETRY_STATE_UNINITIALIZED,
195 TELEMETRY_STATE_INITIALIZED_SERIAL,
196 TELEMETRY_STATE_INITIALIZED_EXTERNAL,
199 static uint8_t telemetryState = TELEMETRY_STATE_UNINITIALIZED;
201 typedef struct smartPortFrame_s {
202 uint8_t sensorId;
203 smartPortPayload_t payload;
204 uint8_t crc;
205 } __attribute__((packed)) smartPortFrame_t;
207 #define SMARTPORT_MSP_PAYLOAD_SIZE (sizeof(smartPortPayload_t) - sizeof(uint8_t))
209 static smartPortWriteFrameFn *smartPortWriteFrame;
211 #if defined(USE_MSP_OVER_TELEMETRY)
212 static bool smartPortMspReplyPending = false;
213 #endif
215 smartPortPayload_t *smartPortDataReceive(uint16_t c, bool *clearToSend, smartPortReadyToSendFn *readyToSend, bool useChecksum)
217 static uint8_t rxBuffer[sizeof(smartPortPayload_t)];
218 static uint8_t smartPortRxBytes = 0;
219 static bool skipUntilStart = true;
220 static bool awaitingSensorId = false;
221 static bool byteStuffing = false;
222 static uint16_t checksum = 0;
224 if (c == FSSP_START_STOP) {
225 *clearToSend = false;
226 smartPortRxBytes = 0;
227 awaitingSensorId = true;
228 skipUntilStart = false;
230 return NULL;
231 } else if (skipUntilStart) {
232 return NULL;
235 if (awaitingSensorId) {
236 awaitingSensorId = false;
237 if ((c == FSSP_SENSOR_ID1) && readyToSend()) {
238 // our slot is starting, start sending
239 *clearToSend = true;
240 // no need to decode more
241 skipUntilStart = true;
242 } else if (c == FSSP_SENSOR_ID2) {
243 checksum = 0;
244 } else {
245 skipUntilStart = true;
247 } else {
248 if (c == FSSP_DLE) {
249 byteStuffing = true;
251 return NULL;
252 } else if (byteStuffing) {
253 c ^= FSSP_DLE_XOR;
254 byteStuffing = false;
257 if (smartPortRxBytes < sizeof(smartPortPayload_t)) {
258 rxBuffer[smartPortRxBytes++] = (uint8_t)c;
259 checksum += c;
261 if (!useChecksum && (smartPortRxBytes == sizeof(smartPortPayload_t))) {
262 skipUntilStart = true;
264 return (smartPortPayload_t *)&rxBuffer;
266 } else {
267 skipUntilStart = true;
269 checksum += c;
270 checksum = (checksum & 0xFF) + (checksum >> 8);
271 if (checksum == 0xFF) {
272 return (smartPortPayload_t *)&rxBuffer;
277 return NULL;
280 void smartPortSendByte(uint8_t c, uint16_t *checksum, serialPort_t *port)
282 // smart port escape sequence
283 if (c == FSSP_DLE || c == FSSP_START_STOP) {
284 serialWrite(port, FSSP_DLE);
285 serialWrite(port, c ^ FSSP_DLE_XOR);
286 } else {
287 serialWrite(port, c);
290 if (checksum != NULL) {
291 frskyCheckSumStep(checksum, c);
295 bool smartPortPayloadContainsMSP(const smartPortPayload_t *payload)
297 return payload->frameId == FSSP_MSPC_FRAME_SMARTPORT || payload->frameId == FSSP_MSPC_FRAME_FPORT;
300 void smartPortWriteFrameSerial(const smartPortPayload_t *payload, serialPort_t *port, uint16_t checksum)
302 uint8_t *data = (uint8_t *)payload;
303 for (unsigned i = 0; i < sizeof(smartPortPayload_t); i++) {
304 smartPortSendByte(*data++, &checksum, port);
306 frskyCheckSumFini(&checksum);
307 smartPortSendByte(checksum, NULL, port);
310 static void smartPortWriteFrameInternal(const smartPortPayload_t *payload)
312 smartPortWriteFrameSerial(payload, smartPortSerialPort, 0);
315 static void smartPortSendPackage(uint16_t id, uint32_t val)
317 smartPortPayload_t payload;
318 payload.frameId = FSSP_DATA_FRAME;
319 payload.valueId = id;
320 payload.data = val;
322 smartPortWriteFrame(&payload);
325 #define ADD_SENSOR(dataId) frSkyDataIdTableInfo.table[frSkyDataIdTableInfo.index++] = dataId
326 #define ADD_ESC_SENSOR(dataId) frSkyEscDataIdTableInfo.table[frSkyEscDataIdTableInfo.index++] = dataId
328 static void initSmartPortSensors(void)
330 frSkyDataIdTableInfo.index = 0;
332 if (telemetryIsSensorEnabled(SENSOR_MODE)) {
333 ADD_SENSOR(FSSP_DATAID_T1);
334 ADD_SENSOR(FSSP_DATAID_T2);
337 #if defined(USE_ADC_INTERNAL)
338 if (telemetryIsSensorEnabled(SENSOR_TEMPERATURE)) {
339 ADD_SENSOR(FSSP_DATAID_T11);
341 #endif
343 if (isBatteryVoltageConfigured() && telemetryIsSensorEnabled(SENSOR_VOLTAGE)) {
344 #ifdef USE_ESC_SENSOR_TELEMETRY
345 if (!telemetryIsSensorEnabled(ESC_SENSOR_VOLTAGE))
346 #endif
348 ADD_SENSOR(FSSP_DATAID_VFAS);
351 ADD_SENSOR(FSSP_DATAID_A4);
354 if (isAmperageConfigured() && telemetryIsSensorEnabled(SENSOR_CURRENT)) {
355 #ifdef USE_ESC_SENSOR_TELEMETRY
356 if (!telemetryIsSensorEnabled(ESC_SENSOR_CURRENT))
357 #endif
359 ADD_SENSOR(FSSP_DATAID_CURRENT);
362 if (telemetryIsSensorEnabled(SENSOR_FUEL)) {
363 ADD_SENSOR(FSSP_DATAID_FUEL);
366 if (telemetryIsSensorEnabled(SENSOR_CAP_USED)) {
367 ADD_SENSOR(FSSP_DATAID_CAP_USED);
371 if (telemetryIsSensorEnabled(SENSOR_HEADING)) {
372 ADD_SENSOR(FSSP_DATAID_HEADING);
375 #if defined(USE_ACC)
376 if (sensors(SENSOR_ACC)) {
377 if (telemetryIsSensorEnabled(SENSOR_PITCH)) {
378 ADD_SENSOR(FSSP_DATAID_PITCH);
380 if (telemetryIsSensorEnabled(SENSOR_ROLL)) {
381 ADD_SENSOR(FSSP_DATAID_ROLL);
383 if (telemetryIsSensorEnabled(SENSOR_ACC_X)) {
384 ADD_SENSOR(FSSP_DATAID_ACCX);
386 if (telemetryIsSensorEnabled(SENSOR_ACC_Y)) {
387 ADD_SENSOR(FSSP_DATAID_ACCY);
389 if (telemetryIsSensorEnabled(SENSOR_ACC_Z)) {
390 ADD_SENSOR(FSSP_DATAID_ACCZ);
393 #endif
395 if (sensors(SENSOR_BARO)) {
396 if (telemetryIsSensorEnabled(SENSOR_ALTITUDE)) {
397 ADD_SENSOR(FSSP_DATAID_ALTITUDE);
399 if (telemetryIsSensorEnabled(SENSOR_VARIO)) {
400 ADD_SENSOR(FSSP_DATAID_VARIO);
404 #ifdef USE_GPS
405 if (featureIsEnabled(FEATURE_GPS)) {
406 if (telemetryIsSensorEnabled(SENSOR_GROUND_SPEED)) {
407 ADD_SENSOR(FSSP_DATAID_SPEED);
409 if (telemetryIsSensorEnabled(SENSOR_LAT_LONG)) {
410 ADD_SENSOR(FSSP_DATAID_LATLONG);
411 ADD_SENSOR(FSSP_DATAID_LATLONG); // twice (one for lat, one for long)
413 if (telemetryIsSensorEnabled(SENSOR_DISTANCE)) {
414 ADD_SENSOR(FSSP_DATAID_HOME_DIST);
416 if (telemetryIsSensorEnabled(SENSOR_ALTITUDE)) {
417 ADD_SENSOR(FSSP_DATAID_GPS_ALT);
420 #endif
422 frSkyDataIdTableInfo.size = frSkyDataIdTableInfo.index;
423 frSkyDataIdTableInfo.index = 0;
425 #ifdef USE_ESC_SENSOR_TELEMETRY
426 frSkyEscDataIdTableInfo.index = 0;
428 if (telemetryIsSensorEnabled(ESC_SENSOR_VOLTAGE)) {
429 ADD_ESC_SENSOR(FSSP_DATAID_VFAS);
431 if (telemetryIsSensorEnabled(ESC_SENSOR_CURRENT)) {
432 ADD_ESC_SENSOR(FSSP_DATAID_CURRENT);
434 if (telemetryIsSensorEnabled(ESC_SENSOR_RPM)) {
435 ADD_ESC_SENSOR(FSSP_DATAID_RPM);
437 if (telemetryIsSensorEnabled(ESC_SENSOR_TEMPERATURE)) {
438 ADD_ESC_SENSOR(FSSP_DATAID_TEMP);
441 frSkyEscDataIdTableInfo.size = frSkyEscDataIdTableInfo.index;
442 frSkyEscDataIdTableInfo.index = 0;
443 #endif
446 bool initSmartPortTelemetry(void)
448 if (telemetryState == TELEMETRY_STATE_UNINITIALIZED) {
449 portConfig = findSerialPortConfig(FUNCTION_TELEMETRY_SMARTPORT);
450 if (portConfig) {
451 smartPortPortSharing = determinePortSharing(portConfig, FUNCTION_TELEMETRY_SMARTPORT);
453 smartPortWriteFrame = smartPortWriteFrameInternal;
455 initSmartPortSensors();
457 telemetryState = TELEMETRY_STATE_INITIALIZED_SERIAL;
460 return true;
463 return false;
466 bool initSmartPortTelemetryExternal(smartPortWriteFrameFn *smartPortWriteFrameExternal)
468 if (telemetryState == TELEMETRY_STATE_UNINITIALIZED) {
469 smartPortWriteFrame = smartPortWriteFrameExternal;
471 initSmartPortSensors();
473 telemetryState = TELEMETRY_STATE_INITIALIZED_EXTERNAL;
475 return true;
478 return false;
481 static void freeSmartPortTelemetryPort(void)
483 closeSerialPort(smartPortSerialPort);
484 smartPortSerialPort = NULL;
487 static void configureSmartPortTelemetryPort(void)
489 if (portConfig) {
490 portOptions_e portOptions = (telemetryConfig()->halfDuplex ? SERIAL_BIDIR : SERIAL_UNIDIR) | (telemetryConfig()->telemetry_inverted ? SERIAL_NOT_INVERTED : SERIAL_INVERTED);
492 smartPortSerialPort = openSerialPort(portConfig->identifier, FUNCTION_TELEMETRY_SMARTPORT, NULL, NULL, SMARTPORT_BAUD, SMARTPORT_UART_MODE, portOptions);
496 void checkSmartPortTelemetryState(void)
498 if (telemetryState == TELEMETRY_STATE_INITIALIZED_SERIAL) {
499 bool enableSerialTelemetry = telemetryDetermineEnabledState(smartPortPortSharing);
501 if (enableSerialTelemetry && !smartPortSerialPort) {
502 configureSmartPortTelemetryPort();
503 } else if (!enableSerialTelemetry && smartPortSerialPort) {
504 freeSmartPortTelemetryPort();
509 #if defined(USE_MSP_OVER_TELEMETRY)
510 static void smartPortSendMspResponse(uint8_t *data, const uint8_t dataSize)
512 smartPortPayload_t payload;
513 payload.frameId = FSSP_MSPS_FRAME;
514 memcpy(&payload.valueId, data, MIN(dataSize,SMARTPORT_MSP_PAYLOAD_SIZE));
516 smartPortWriteFrame(&payload);
518 #endif
520 void processSmartPortTelemetry(smartPortPayload_t *payload, volatile bool *clearToSend, const timeUs_t *requestTimeout)
522 static uint8_t smartPortIdCycleCnt = 0;
523 static uint8_t t1Cnt = 0;
524 static uint8_t t2Cnt = 0;
525 static uint8_t skipRequests = 0;
526 #ifdef USE_ESC_SENSOR_TELEMETRY
527 static uint8_t smartPortIdOffset = 0;
528 #endif
530 #if defined(USE_MSP_OVER_TELEMETRY)
531 if (skipRequests) {
532 skipRequests--;
533 } else if (payload && smartPortPayloadContainsMSP(payload)) {
534 // Do not check the physical ID here again
535 // unless we start receiving other sensors' packets
536 // Pass only the payload: skip frameId
537 uint8_t *frameStart = (uint8_t *)&payload->valueId;
538 smartPortMspReplyPending = handleMspFrame(frameStart, SMARTPORT_MSP_PAYLOAD_SIZE, &skipRequests);
540 // Don't send MSP response after write to eeprom
541 // CPU just got out of suspended state after writeEEPROM()
542 // We don't know if the receiver is listening again
543 // Skip a few telemetry requests before sending response
544 if (skipRequests) {
545 *clearToSend = false;
548 #else
549 UNUSED(payload);
550 #endif
552 bool doRun = true;
553 while (doRun && *clearToSend && !skipRequests) {
554 // Ensure we won't get stuck in the loop if there happens to be nothing available to send in a timely manner - dump the slot if we loop in there for too long.
555 if (requestTimeout) {
556 if (cmpTimeUs(micros(), *requestTimeout) >= 0) {
557 *clearToSend = false;
559 return;
561 } else {
562 doRun = false;
565 #if defined(USE_MSP_OVER_TELEMETRY)
566 if (smartPortMspReplyPending) {
567 smartPortMspReplyPending = sendMspReply(SMARTPORT_MSP_PAYLOAD_SIZE, &smartPortSendMspResponse);
568 *clearToSend = false;
570 return;
572 #endif
574 // we can send back any data we want, our tables keep track of the order and frequency of each data type we send
575 frSkyTableInfo_t * tableInfo = &frSkyDataIdTableInfo;
577 #ifdef USE_ESC_SENSOR_TELEMETRY
578 if (smartPortIdCycleCnt >= ESC_SENSOR_PERIOD) {
579 // send ESC sensors
580 tableInfo = &frSkyEscDataIdTableInfo;
581 if (tableInfo->index == tableInfo->size) { // end of ESC table, return to other sensors
582 tableInfo->index = 0;
583 smartPortIdCycleCnt = 0;
584 smartPortIdOffset++;
585 if (smartPortIdOffset == getMotorCount() + 1) { // each motor and ESC_SENSOR_COMBINED
586 smartPortIdOffset = 0;
590 if (smartPortIdCycleCnt < ESC_SENSOR_PERIOD) {
591 // send other sensors
592 tableInfo = &frSkyDataIdTableInfo;
593 #endif
594 if (tableInfo->index == tableInfo->size) { // end of table reached, loop back
595 tableInfo->index = 0;
597 #ifdef USE_ESC_SENSOR_TELEMETRY
599 #endif
600 uint16_t id = tableInfo->table[tableInfo->index];
601 #ifdef USE_ESC_SENSOR_TELEMETRY
602 if (smartPortIdCycleCnt >= ESC_SENSOR_PERIOD) {
603 id += smartPortIdOffset;
605 #endif
606 smartPortIdCycleCnt++;
607 tableInfo->index++;
609 int32_t tmpi;
610 uint32_t tmp2 = 0;
611 uint16_t vfasVoltage;
613 #ifdef USE_ESC_SENSOR_TELEMETRY
614 escSensorData_t *escData;
615 #endif
617 switch (id) {
618 case FSSP_DATAID_VFAS :
619 vfasVoltage = telemetryConfig()->report_cell_voltage ? getBatteryAverageCellVoltage() : getBatteryVoltage();
620 smartPortSendPackage(id, vfasVoltage); // in 0.01V according to SmartPort spec
621 *clearToSend = false;
622 break;
623 #ifdef USE_ESC_SENSOR_TELEMETRY
624 case FSSP_DATAID_VFAS1 :
625 case FSSP_DATAID_VFAS2 :
626 case FSSP_DATAID_VFAS3 :
627 case FSSP_DATAID_VFAS4 :
628 case FSSP_DATAID_VFAS5 :
629 case FSSP_DATAID_VFAS6 :
630 case FSSP_DATAID_VFAS7 :
631 case FSSP_DATAID_VFAS8 :
632 escData = getEscSensorData(id - FSSP_DATAID_VFAS1);
633 if (escData != NULL) {
634 smartPortSendPackage(id, escData->voltage);
635 *clearToSend = false;
637 break;
638 #endif
639 case FSSP_DATAID_CURRENT :
640 smartPortSendPackage(id, getAmperage() / 10); // in 0.1A according to SmartPort spec
641 *clearToSend = false;
642 break;
643 #ifdef USE_ESC_SENSOR_TELEMETRY
644 case FSSP_DATAID_CURRENT1 :
645 case FSSP_DATAID_CURRENT2 :
646 case FSSP_DATAID_CURRENT3 :
647 case FSSP_DATAID_CURRENT4 :
648 case FSSP_DATAID_CURRENT5 :
649 case FSSP_DATAID_CURRENT6 :
650 case FSSP_DATAID_CURRENT7 :
651 case FSSP_DATAID_CURRENT8 :
652 escData = getEscSensorData(id - FSSP_DATAID_CURRENT1);
653 if (escData != NULL) {
654 smartPortSendPackage(id, escData->current);
655 *clearToSend = false;
657 break;
658 case FSSP_DATAID_RPM :
659 escData = getEscSensorData(ESC_SENSOR_COMBINED);
660 if (escData != NULL) {
661 smartPortSendPackage(id, lrintf(erpmToRpm(escData->rpm)));
662 *clearToSend = false;
664 break;
665 case FSSP_DATAID_RPM1 :
666 case FSSP_DATAID_RPM2 :
667 case FSSP_DATAID_RPM3 :
668 case FSSP_DATAID_RPM4 :
669 case FSSP_DATAID_RPM5 :
670 case FSSP_DATAID_RPM6 :
671 case FSSP_DATAID_RPM7 :
672 case FSSP_DATAID_RPM8 :
673 escData = getEscSensorData(id - FSSP_DATAID_RPM1);
674 if (escData != NULL) {
675 smartPortSendPackage(id, lrintf(erpmToRpm(escData->rpm)));
676 *clearToSend = false;
678 break;
679 case FSSP_DATAID_TEMP :
680 escData = getEscSensorData(ESC_SENSOR_COMBINED);
681 if (escData != NULL) {
682 smartPortSendPackage(id, escData->temperature);
683 *clearToSend = false;
685 break;
686 case FSSP_DATAID_TEMP1 :
687 case FSSP_DATAID_TEMP2 :
688 case FSSP_DATAID_TEMP3 :
689 case FSSP_DATAID_TEMP4 :
690 case FSSP_DATAID_TEMP5 :
691 case FSSP_DATAID_TEMP6 :
692 case FSSP_DATAID_TEMP7 :
693 case FSSP_DATAID_TEMP8 :
694 escData = getEscSensorData(id - FSSP_DATAID_TEMP1);
695 if (escData != NULL) {
696 smartPortSendPackage(id, escData->temperature);
697 *clearToSend = false;
699 break;
700 #endif
701 case FSSP_DATAID_ALTITUDE :
702 smartPortSendPackage(id, getEstimatedAltitudeCm()); // in cm according to SmartPort spec
703 *clearToSend = false;
704 break;
705 case FSSP_DATAID_FUEL :
707 uint32_t data;
708 if (batteryConfig()->batteryCapacity > 0) {
709 data = calculateBatteryPercentageRemaining();
710 } else {
711 data = getMAhDrawn();
713 smartPortSendPackage(id, data);
714 *clearToSend = false;
716 break;
717 case FSSP_DATAID_CAP_USED :
718 smartPortSendPackage(id, getMAhDrawn()); // given in mAh, should be in percent according to SmartPort spec
719 *clearToSend = false;
720 break;
721 #if defined(USE_VARIO)
722 case FSSP_DATAID_VARIO :
723 smartPortSendPackage(id, getEstimatedVario()); // in cm/s according to SmartPort spec
724 *clearToSend = false;
725 break;
726 #endif
727 case FSSP_DATAID_HEADING :
728 smartPortSendPackage(id, attitude.values.yaw * 10); // in degrees * 100 according to SmartPort spec
729 *clearToSend = false;
730 break;
731 #if defined(USE_ACC)
732 case FSSP_DATAID_PITCH :
733 smartPortSendPackage(id, attitude.values.pitch); // given in 10*deg
734 *clearToSend = false;
735 break;
736 case FSSP_DATAID_ROLL :
737 smartPortSendPackage(id, attitude.values.roll); // given in 10*deg
738 *clearToSend = false;
739 break;
740 case FSSP_DATAID_ACCX :
741 smartPortSendPackage(id, lrintf(100 * acc.accADC[X] * acc.dev.acc_1G_rec)); // Multiply by 100 to show as x.xx g on Taranis
742 *clearToSend = false;
743 break;
744 case FSSP_DATAID_ACCY :
745 smartPortSendPackage(id, lrintf(100 * acc.accADC[Y] * acc.dev.acc_1G_rec));
746 *clearToSend = false;
747 break;
748 case FSSP_DATAID_ACCZ :
749 smartPortSendPackage(id, lrintf(100 * acc.accADC[Z] * acc.dev.acc_1G_rec));
750 *clearToSend = false;
751 break;
752 #endif
753 case FSSP_DATAID_T1 :
754 // we send all the flags as decimal digits for easy reading
756 // the t1Cnt simply allows the telemetry view to show at least some changes
757 t1Cnt++;
758 if (t1Cnt == 4) {
759 t1Cnt = 1;
761 tmpi = t1Cnt * 10000; // start off with at least one digit so the most significant 0 won't be cut off
762 // the Taranis seems to be able to fit 5 digits on the screen
763 // the Taranis seems to consider this number a signed 16 bit integer
765 if (!isArmingDisabled()) {
766 tmpi += 1;
767 } else {
768 tmpi += 2;
770 if (ARMING_FLAG(ARMED)) {
771 tmpi += 4;
774 if (FLIGHT_MODE(ANGLE_MODE)) {
775 tmpi += 10;
777 if (FLIGHT_MODE(HORIZON_MODE)) {
778 tmpi += 20;
780 if (FLIGHT_MODE(PASSTHRU_MODE)) {
781 tmpi += 40;
784 if (FLIGHT_MODE(MAG_MODE)) {
785 tmpi += 100;
788 if (FLIGHT_MODE(HEADFREE_MODE)) {
789 tmpi += 4000;
792 smartPortSendPackage(id, (uint32_t)tmpi);
793 *clearToSend = false;
794 break;
795 case FSSP_DATAID_T2 :
796 #ifdef USE_GPS
797 if (sensors(SENSOR_GPS)) {
798 // satellite accuracy PDOP: 0 = worst [PDOP > 5.5m], 9 = best [PDOP <= 1.0m]
799 // the above comment isn't entirely right. DOP is accuracy relative to specified accuracy of the module, not a value in meters
800 // eg a value of 1.0 means 1.0 times specified accuracy (typically 2m)
801 uint16_t pdop = constrain(scaleRange(gpsSol.dop.pdop, 100, 550, 9, 0), 0, 9) * 100;
802 smartPortSendPackage(id, (STATE(GPS_FIX) ? 1000 : 0) + (STATE(GPS_FIX_HOME) ? 2000 : 0) + pdop + gpsSol.numSat);
803 *clearToSend = false;
804 } else if (featureIsEnabled(FEATURE_GPS)) {
805 smartPortSendPackage(id, 0);
806 *clearToSend = false;
807 } else
808 #endif
809 if (telemetryConfig()->pidValuesAsTelemetry) {
810 switch (t2Cnt) {
811 case 0:
812 tmp2 = currentPidProfile->pid[PID_ROLL].P;
813 tmp2 += (currentPidProfile->pid[PID_PITCH].P<<8);
814 tmp2 += (currentPidProfile->pid[PID_YAW].P<<16);
815 break;
816 case 1:
817 tmp2 = currentPidProfile->pid[PID_ROLL].I;
818 tmp2 += (currentPidProfile->pid[PID_PITCH].I<<8);
819 tmp2 += (currentPidProfile->pid[PID_YAW].I<<16);
820 break;
821 case 2:
822 tmp2 = currentPidProfile->pid[PID_ROLL].D;
823 tmp2 += (currentPidProfile->pid[PID_PITCH].D<<8);
824 tmp2 += (currentPidProfile->pid[PID_YAW].D<<16);
825 break;
826 case 3:
827 tmp2 = currentControlRateProfile->rates[FD_ROLL];
828 tmp2 += (currentControlRateProfile->rates[FD_PITCH]<<8);
829 tmp2 += (currentControlRateProfile->rates[FD_YAW]<<16);
830 break;
832 tmp2 += t2Cnt<<24;
833 t2Cnt++;
834 if (t2Cnt == 4) {
835 t2Cnt = 0;
837 smartPortSendPackage(id, tmp2);
838 *clearToSend = false;
841 break;
842 #if defined(USE_ADC_INTERNAL)
843 case FSSP_DATAID_T11 :
844 smartPortSendPackage(id, getCoreTemperatureCelsius());
845 *clearToSend = false;
846 break;
847 #endif
848 #ifdef USE_GPS
849 case FSSP_DATAID_SPEED :
850 if (STATE(GPS_FIX)) {
851 //convert to knots: 1cm/s = 0.0194384449 knots
852 //Speed should be sent in knots/1000 (GPS speed is in cm/s)
853 uint32_t tmpui = gpsSol.groundSpeed * 1944 / 100;
854 smartPortSendPackage(id, tmpui);
855 *clearToSend = false;
857 break;
858 case FSSP_DATAID_LATLONG :
859 if (STATE(GPS_FIX)) {
860 uint32_t tmpui = 0;
861 // the same ID is sent twice, one for longitude, one for latitude
862 // the MSB of the sent uint32_t helps FrSky keep track
863 // the even/odd bit of our counter helps us keep track
864 if (tableInfo->index & 1) {
865 tmpui = abs(gpsSol.llh.lon); // now we have unsigned value and one bit to spare
866 tmpui = (tmpui + tmpui / 2) / 25 | 0x80000000; // 6/100 = 1.5/25, division by power of 2 is fast
867 if (gpsSol.llh.lon < 0) tmpui |= 0x40000000;
869 else {
870 tmpui = abs(gpsSol.llh.lat); // now we have unsigned value and one bit to spare
871 tmpui = (tmpui + tmpui / 2) / 25; // 6/100 = 1.5/25, division by power of 2 is fast
872 if (gpsSol.llh.lat < 0) tmpui |= 0x40000000;
874 smartPortSendPackage(id, tmpui);
875 *clearToSend = false;
877 break;
878 case FSSP_DATAID_HOME_DIST :
879 if (STATE(GPS_FIX)) {
880 smartPortSendPackage(id, GPS_distanceToHome);
881 *clearToSend = false;
883 break;
884 case FSSP_DATAID_GPS_ALT :
885 if (STATE(GPS_FIX)) {
886 smartPortSendPackage(id, gpsSol.llh.altCm); // in cm according to SmartPort spec
887 *clearToSend = false;
889 break;
890 #endif
891 case FSSP_DATAID_A4 :
892 vfasVoltage = getBatteryAverageCellVoltage(); // in 0.01V according to SmartPort spec
893 smartPortSendPackage(id, vfasVoltage);
894 *clearToSend = false;
895 break;
896 default:
897 break;
898 // if nothing is sent, hasRequest isn't cleared, we already incremented the counter, just loop back to the start
903 static bool serialReadyToSend(void)
905 return (serialRxBytesWaiting(smartPortSerialPort) == 0);
908 void handleSmartPortTelemetry(void)
910 const timeUs_t requestTimeout = micros() + SMARTPORT_SERVICE_TIMEOUT_US;
912 if (telemetryState == TELEMETRY_STATE_INITIALIZED_SERIAL && smartPortSerialPort) {
913 smartPortPayload_t *payload = NULL;
914 bool clearToSend = false;
915 while (serialRxBytesWaiting(smartPortSerialPort) > 0 && !payload) {
916 uint8_t c = serialRead(smartPortSerialPort);
917 payload = smartPortDataReceive(c, &clearToSend, serialReadyToSend, true);
920 processSmartPortTelemetry(payload, &clearToSend, &requestTimeout);
923 #endif