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/>.
22 * SmartPort Telemetry implementation by frank26080115
23 * see https://github.com/frank26080115/cleanflight/wiki/Using-Smart-Port
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"
63 #include "io/serial.h"
70 #include "pg/pg_ids.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
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 ,
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 ,
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
];
172 typedef struct frSkyTableInfo_s
{
178 static frSkyTableInfo_t frSkyDataIdTableInfo
= { frSkyDataIdTable
, 0, 0 };
179 #ifdef USE_ESC_SENSOR_TELEMETRY
180 static frSkyTableInfo_t frSkyEscDataIdTableInfo
= {frSkyEscDataIdTable
, 0, 0};
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
;
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
{
203 smartPortPayload_t payload
;
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;
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;
231 } else if (skipUntilStart
) {
235 if (awaitingSensorId
) {
236 awaitingSensorId
= false;
237 if ((c
== FSSP_SENSOR_ID1
) && readyToSend()) {
238 // our slot is starting, start sending
240 // no need to decode more
241 skipUntilStart
= true;
242 } else if (c
== FSSP_SENSOR_ID2
) {
245 skipUntilStart
= true;
252 } else if (byteStuffing
) {
254 byteStuffing
= false;
257 if (smartPortRxBytes
< sizeof(smartPortPayload_t
)) {
258 rxBuffer
[smartPortRxBytes
++] = (uint8_t)c
;
261 if (!useChecksum
&& (smartPortRxBytes
== sizeof(smartPortPayload_t
))) {
262 skipUntilStart
= true;
264 return (smartPortPayload_t
*)&rxBuffer
;
267 skipUntilStart
= true;
270 checksum
= (checksum
& 0xFF) + (checksum
>> 8);
271 if (checksum
== 0xFF) {
272 return (smartPortPayload_t
*)&rxBuffer
;
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
);
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
;
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
);
343 if (isBatteryVoltageConfigured() && telemetryIsSensorEnabled(SENSOR_VOLTAGE
)) {
344 #ifdef USE_ESC_SENSOR_TELEMETRY
345 if (!telemetryIsSensorEnabled(ESC_SENSOR_VOLTAGE
))
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
))
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
);
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
);
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
);
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
);
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;
446 bool initSmartPortTelemetry(void)
448 if (telemetryState
== TELEMETRY_STATE_UNINITIALIZED
) {
449 portConfig
= findSerialPortConfig(FUNCTION_TELEMETRY_SMARTPORT
);
451 smartPortPortSharing
= determinePortSharing(portConfig
, FUNCTION_TELEMETRY_SMARTPORT
);
453 smartPortWriteFrame
= smartPortWriteFrameInternal
;
455 initSmartPortSensors();
457 telemetryState
= TELEMETRY_STATE_INITIALIZED_SERIAL
;
466 bool initSmartPortTelemetryExternal(smartPortWriteFrameFn
*smartPortWriteFrameExternal
)
468 if (telemetryState
== TELEMETRY_STATE_UNINITIALIZED
) {
469 smartPortWriteFrame
= smartPortWriteFrameExternal
;
471 initSmartPortSensors();
473 telemetryState
= TELEMETRY_STATE_INITIALIZED_EXTERNAL
;
481 static void freeSmartPortTelemetryPort(void)
483 closeSerialPort(smartPortSerialPort
);
484 smartPortSerialPort
= NULL
;
487 static void configureSmartPortTelemetryPort(void)
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
);
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;
530 #if defined(USE_MSP_OVER_TELEMETRY)
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
545 *clearToSend
= false;
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;
565 #if defined(USE_MSP_OVER_TELEMETRY)
566 if (smartPortMspReplyPending
) {
567 smartPortMspReplyPending
= sendMspReply(SMARTPORT_MSP_PAYLOAD_SIZE
, &smartPortSendMspResponse
);
568 *clearToSend
= false;
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
) {
580 tableInfo
= &frSkyEscDataIdTableInfo
;
581 if (tableInfo
->index
== tableInfo
->size
) { // end of ESC table, return to other sensors
582 tableInfo
->index
= 0;
583 smartPortIdCycleCnt
= 0;
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
;
594 if (tableInfo
->index
== tableInfo
->size
) { // end of table reached, loop back
595 tableInfo
->index
= 0;
597 #ifdef USE_ESC_SENSOR_TELEMETRY
600 uint16_t id
= tableInfo
->table
[tableInfo
->index
];
601 #ifdef USE_ESC_SENSOR_TELEMETRY
602 if (smartPortIdCycleCnt
>= ESC_SENSOR_PERIOD
) {
603 id
+= smartPortIdOffset
;
606 smartPortIdCycleCnt
++;
611 uint16_t vfasVoltage
;
613 #ifdef USE_ESC_SENSOR_TELEMETRY
614 escSensorData_t
*escData
;
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;
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;
639 case FSSP_DATAID_CURRENT
:
640 smartPortSendPackage(id
, getAmperage() / 10); // in 0.1A according to SmartPort spec
641 *clearToSend
= false;
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;
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;
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;
679 case FSSP_DATAID_TEMP
:
680 escData
= getEscSensorData(ESC_SENSOR_COMBINED
);
681 if (escData
!= NULL
) {
682 smartPortSendPackage(id
, escData
->temperature
);
683 *clearToSend
= false;
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;
701 case FSSP_DATAID_ALTITUDE
:
702 smartPortSendPackage(id
, getEstimatedAltitudeCm()); // in cm according to SmartPort spec
703 *clearToSend
= false;
705 case FSSP_DATAID_FUEL
:
708 if (batteryConfig()->batteryCapacity
> 0) {
709 data
= calculateBatteryPercentageRemaining();
711 data
= getMAhDrawn();
713 smartPortSendPackage(id
, data
);
714 *clearToSend
= false;
717 case FSSP_DATAID_CAP_USED
:
718 smartPortSendPackage(id
, getMAhDrawn()); // given in mAh, should be in percent according to SmartPort spec
719 *clearToSend
= false;
721 #if defined(USE_VARIO)
722 case FSSP_DATAID_VARIO
:
723 smartPortSendPackage(id
, getEstimatedVario()); // in cm/s according to SmartPort spec
724 *clearToSend
= false;
727 case FSSP_DATAID_HEADING
:
728 smartPortSendPackage(id
, attitude
.values
.yaw
* 10); // in degrees * 100 according to SmartPort spec
729 *clearToSend
= false;
732 case FSSP_DATAID_PITCH
:
733 smartPortSendPackage(id
, attitude
.values
.pitch
); // given in 10*deg
734 *clearToSend
= false;
736 case FSSP_DATAID_ROLL
:
737 smartPortSendPackage(id
, attitude
.values
.roll
); // given in 10*deg
738 *clearToSend
= false;
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;
744 case FSSP_DATAID_ACCY
:
745 smartPortSendPackage(id
, lrintf(100 * acc
.accADC
[Y
] * acc
.dev
.acc_1G_rec
));
746 *clearToSend
= false;
748 case FSSP_DATAID_ACCZ
:
749 smartPortSendPackage(id
, lrintf(100 * acc
.accADC
[Z
] * acc
.dev
.acc_1G_rec
));
750 *clearToSend
= false;
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
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()) {
770 if (ARMING_FLAG(ARMED
)) {
774 if (FLIGHT_MODE(ANGLE_MODE
)) {
777 if (FLIGHT_MODE(HORIZON_MODE
)) {
780 if (FLIGHT_MODE(PASSTHRU_MODE
)) {
784 if (FLIGHT_MODE(MAG_MODE
)) {
788 if (FLIGHT_MODE(HEADFREE_MODE
)) {
792 smartPortSendPackage(id
, (uint32_t)tmpi
);
793 *clearToSend
= false;
795 case FSSP_DATAID_T2
:
797 if (sensors(SENSOR_GPS
)) {
798 // satellite accuracy HDOP: 0 = worst [HDOP > 5.5m], 9 = best [HDOP <= 1.0m]
799 uint16_t hdop
= constrain(scaleRange(gpsSol
.dop
.hdop
, 100, 550, 9, 0), 0, 9) * 100;
800 smartPortSendPackage(id
, (STATE(GPS_FIX
) ? 1000 : 0) + (STATE(GPS_FIX_HOME
) ? 2000 : 0) + hdop
+ gpsSol
.numSat
);
801 *clearToSend
= false;
802 } else if (featureIsEnabled(FEATURE_GPS
)) {
803 smartPortSendPackage(id
, 0);
804 *clearToSend
= false;
807 if (telemetryConfig()->pidValuesAsTelemetry
) {
810 tmp2
= currentPidProfile
->pid
[PID_ROLL
].P
;
811 tmp2
+= (currentPidProfile
->pid
[PID_PITCH
].P
<<8);
812 tmp2
+= (currentPidProfile
->pid
[PID_YAW
].P
<<16);
815 tmp2
= currentPidProfile
->pid
[PID_ROLL
].I
;
816 tmp2
+= (currentPidProfile
->pid
[PID_PITCH
].I
<<8);
817 tmp2
+= (currentPidProfile
->pid
[PID_YAW
].I
<<16);
820 tmp2
= currentPidProfile
->pid
[PID_ROLL
].D
;
821 tmp2
+= (currentPidProfile
->pid
[PID_PITCH
].D
<<8);
822 tmp2
+= (currentPidProfile
->pid
[PID_YAW
].D
<<16);
825 tmp2
= currentControlRateProfile
->rates
[FD_ROLL
];
826 tmp2
+= (currentControlRateProfile
->rates
[FD_PITCH
]<<8);
827 tmp2
+= (currentControlRateProfile
->rates
[FD_YAW
]<<16);
835 smartPortSendPackage(id
, tmp2
);
836 *clearToSend
= false;
840 #if defined(USE_ADC_INTERNAL)
841 case FSSP_DATAID_T11
:
842 smartPortSendPackage(id
, getCoreTemperatureCelsius());
843 *clearToSend
= false;
847 case FSSP_DATAID_SPEED
:
848 if (STATE(GPS_FIX
)) {
849 //convert to knots: 1cm/s = 0.0194384449 knots
850 //Speed should be sent in knots/1000 (GPS speed is in cm/s)
851 uint32_t tmpui
= gpsSol
.groundSpeed
* 1944 / 100;
852 smartPortSendPackage(id
, tmpui
);
853 *clearToSend
= false;
856 case FSSP_DATAID_LATLONG
:
857 if (STATE(GPS_FIX
)) {
859 // the same ID is sent twice, one for longitude, one for latitude
860 // the MSB of the sent uint32_t helps FrSky keep track
861 // the even/odd bit of our counter helps us keep track
862 if (tableInfo
->index
& 1) {
863 tmpui
= abs(gpsSol
.llh
.lon
); // now we have unsigned value and one bit to spare
864 tmpui
= (tmpui
+ tmpui
/ 2) / 25 | 0x80000000; // 6/100 = 1.5/25, division by power of 2 is fast
865 if (gpsSol
.llh
.lon
< 0) tmpui
|= 0x40000000;
868 tmpui
= abs(gpsSol
.llh
.lat
); // now we have unsigned value and one bit to spare
869 tmpui
= (tmpui
+ tmpui
/ 2) / 25; // 6/100 = 1.5/25, division by power of 2 is fast
870 if (gpsSol
.llh
.lat
< 0) tmpui
|= 0x40000000;
872 smartPortSendPackage(id
, tmpui
);
873 *clearToSend
= false;
876 case FSSP_DATAID_HOME_DIST
:
877 if (STATE(GPS_FIX
)) {
878 smartPortSendPackage(id
, GPS_distanceToHome
);
879 *clearToSend
= false;
882 case FSSP_DATAID_GPS_ALT
:
883 if (STATE(GPS_FIX
)) {
884 smartPortSendPackage(id
, gpsSol
.llh
.altCm
); // in cm according to SmartPort spec
885 *clearToSend
= false;
889 case FSSP_DATAID_A4
:
890 vfasVoltage
= getBatteryAverageCellVoltage(); // in 0.01V according to SmartPort spec
891 smartPortSendPackage(id
, vfasVoltage
);
892 *clearToSend
= false;
896 // if nothing is sent, hasRequest isn't cleared, we already incremented the counter, just loop back to the start
901 static bool serialReadyToSend(void)
903 return (serialRxBytesWaiting(smartPortSerialPort
) == 0);
906 void handleSmartPortTelemetry(void)
908 const timeUs_t requestTimeout
= micros() + SMARTPORT_SERVICE_TIMEOUT_US
;
910 if (telemetryState
== TELEMETRY_STATE_INITIALIZED_SERIAL
&& smartPortSerialPort
) {
911 smartPortPayload_t
*payload
= NULL
;
912 bool clearToSend
= false;
913 while (serialRxBytesWaiting(smartPortSerialPort
) > 0 && !payload
) {
914 uint8_t c
= serialRead(smartPortSerialPort
);
915 payload
= smartPortDataReceive(c
, &clearToSend
, serialReadyToSend
, true);
918 processSmartPortTelemetry(payload
, &clearToSend
, &requestTimeout
);