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"
49 #include "config/config.h"
50 #include "fc/controlrate_profile.h"
51 #include "fc/rc_controls.h"
52 #include "fc/runtime_config.h"
54 #include "flight/failsafe.h"
55 #include "flight/imu.h"
56 #include "flight/mixer.h"
57 #include "flight/pid.h"
58 #include "flight/position.h"
60 #include "io/beeper.h"
62 #include "io/motors.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_CAP_USED
= 0x0600 ,
126 FSSP_DATAID_VARIO
= 0x0110 ,
127 FSSP_DATAID_CELLS
= 0x0300 ,
128 FSSP_DATAID_CELLS_LAST
= 0x030F ,
129 FSSP_DATAID_HEADING
= 0x0840 ,
131 FSSP_DATAID_PITCH
= 0x5230 , // custom
132 FSSP_DATAID_ROLL
= 0x5240 , // custom
133 FSSP_DATAID_ACCX
= 0x0700 ,
134 FSSP_DATAID_ACCY
= 0x0710 ,
135 FSSP_DATAID_ACCZ
= 0x0720 ,
137 FSSP_DATAID_T1
= 0x0400 ,
138 FSSP_DATAID_T11
= 0x0401 ,
139 FSSP_DATAID_T2
= 0x0410 ,
140 FSSP_DATAID_HOME_DIST
= 0x0420 ,
141 FSSP_DATAID_GPS_ALT
= 0x0820 ,
142 FSSP_DATAID_ASPD
= 0x0A00 ,
143 FSSP_DATAID_TEMP
= 0x0B70 ,
144 FSSP_DATAID_TEMP1
= 0x0B71 ,
145 FSSP_DATAID_TEMP2
= 0x0B72 ,
146 FSSP_DATAID_TEMP3
= 0x0B73 ,
147 FSSP_DATAID_TEMP4
= 0x0B74 ,
148 FSSP_DATAID_TEMP5
= 0x0B75 ,
149 FSSP_DATAID_TEMP6
= 0x0B76 ,
150 FSSP_DATAID_TEMP7
= 0x0B77 ,
151 FSSP_DATAID_TEMP8
= 0x0B78 ,
152 FSSP_DATAID_A3
= 0x0900 ,
153 FSSP_DATAID_A4
= 0x0910
156 // if adding more sensors then increase this value (should be equal to the maximum number of ADD_SENSOR calls)
157 #define MAX_DATAIDS 20
159 static uint16_t frSkyDataIdTable
[MAX_DATAIDS
];
161 #ifdef USE_ESC_SENSOR_TELEMETRY
162 // number of sensors to send between sending the ESC sensors
163 #define ESC_SENSOR_PERIOD 7
165 // if adding more esc sensors then increase this value
166 #define MAX_ESC_DATAIDS 4
168 static uint16_t frSkyEscDataIdTable
[MAX_ESC_DATAIDS
];
171 typedef struct frSkyTableInfo_s
{
177 static frSkyTableInfo_t frSkyDataIdTableInfo
= { frSkyDataIdTable
, 0, 0 };
178 #ifdef USE_ESC_SENSOR_TELEMETRY
179 static frSkyTableInfo_t frSkyEscDataIdTableInfo
= {frSkyEscDataIdTable
, 0, 0};
182 #define SMARTPORT_BAUD 57600
183 #define SMARTPORT_UART_MODE MODE_RXTX
184 #define SMARTPORT_SERVICE_TIMEOUT_US 1000 // max allowed time to find a value to send
186 static serialPort_t
*smartPortSerialPort
= NULL
; // The 'SmartPort'(tm) Port.
187 static const serialPortConfig_t
*portConfig
;
189 static portSharing_e smartPortPortSharing
;
193 TELEMETRY_STATE_UNINITIALIZED
,
194 TELEMETRY_STATE_INITIALIZED_SERIAL
,
195 TELEMETRY_STATE_INITIALIZED_EXTERNAL
,
198 static uint8_t telemetryState
= TELEMETRY_STATE_UNINITIALIZED
;
200 typedef struct smartPortFrame_s
{
202 smartPortPayload_t payload
;
204 } __attribute__((packed
)) smartPortFrame_t
;
206 #define SMARTPORT_MSP_PAYLOAD_SIZE (sizeof(smartPortPayload_t) - sizeof(uint8_t))
208 static smartPortWriteFrameFn
*smartPortWriteFrame
;
210 #if defined(USE_MSP_OVER_TELEMETRY)
211 static bool smartPortMspReplyPending
= false;
214 smartPortPayload_t
*smartPortDataReceive(uint16_t c
, bool *clearToSend
, smartPortReadyToSendFn
*readyToSend
, bool useChecksum
)
216 static uint8_t rxBuffer
[sizeof(smartPortPayload_t
)];
217 static uint8_t smartPortRxBytes
= 0;
218 static bool skipUntilStart
= true;
219 static bool awaitingSensorId
= false;
220 static bool byteStuffing
= false;
221 static uint16_t checksum
= 0;
223 if (c
== FSSP_START_STOP
) {
224 *clearToSend
= false;
225 smartPortRxBytes
= 0;
226 awaitingSensorId
= true;
227 skipUntilStart
= false;
230 } else if (skipUntilStart
) {
234 if (awaitingSensorId
) {
235 awaitingSensorId
= false;
236 if ((c
== FSSP_SENSOR_ID1
) && readyToSend()) {
237 // our slot is starting, start sending
239 // no need to decode more
240 skipUntilStart
= true;
241 } else if (c
== FSSP_SENSOR_ID2
) {
244 skipUntilStart
= true;
251 } else if (byteStuffing
) {
253 byteStuffing
= false;
256 if (smartPortRxBytes
< sizeof(smartPortPayload_t
)) {
257 rxBuffer
[smartPortRxBytes
++] = (uint8_t)c
;
260 if (!useChecksum
&& (smartPortRxBytes
== sizeof(smartPortPayload_t
))) {
261 skipUntilStart
= true;
263 return (smartPortPayload_t
*)&rxBuffer
;
266 skipUntilStart
= true;
269 checksum
= (checksum
& 0xFF) + (checksum
>> 8);
270 if (checksum
== 0xFF) {
271 return (smartPortPayload_t
*)&rxBuffer
;
279 void smartPortSendByte(uint8_t c
, uint16_t *checksum
, serialPort_t
*port
)
281 // smart port escape sequence
282 if (c
== FSSP_DLE
|| c
== FSSP_START_STOP
) {
283 serialWrite(port
, FSSP_DLE
);
284 serialWrite(port
, c
^ FSSP_DLE_XOR
);
286 serialWrite(port
, c
);
289 if (checksum
!= NULL
) {
290 frskyCheckSumStep(checksum
, c
);
294 bool smartPortPayloadContainsMSP(const smartPortPayload_t
*payload
)
296 return payload
->frameId
== FSSP_MSPC_FRAME_SMARTPORT
|| payload
->frameId
== FSSP_MSPC_FRAME_FPORT
;
299 void smartPortWriteFrameSerial(const smartPortPayload_t
*payload
, serialPort_t
*port
, uint16_t checksum
)
301 uint8_t *data
= (uint8_t *)payload
;
302 for (unsigned i
= 0; i
< sizeof(smartPortPayload_t
); i
++) {
303 smartPortSendByte(*data
++, &checksum
, port
);
305 frskyCheckSumFini(&checksum
);
306 smartPortSendByte(checksum
, NULL
, port
);
309 static void smartPortWriteFrameInternal(const smartPortPayload_t
*payload
)
311 smartPortWriteFrameSerial(payload
, smartPortSerialPort
, 0);
314 static void smartPortSendPackage(uint16_t id
, uint32_t val
)
316 smartPortPayload_t payload
;
317 payload
.frameId
= FSSP_DATA_FRAME
;
318 payload
.valueId
= id
;
321 smartPortWriteFrame(&payload
);
324 #define ADD_SENSOR(dataId) frSkyDataIdTableInfo.table[frSkyDataIdTableInfo.index++] = dataId
325 #define ADD_ESC_SENSOR(dataId) frSkyEscDataIdTableInfo.table[frSkyEscDataIdTableInfo.index++] = dataId
327 static void initSmartPortSensors(void)
329 frSkyDataIdTableInfo
.index
= 0;
331 if (telemetryIsSensorEnabled(SENSOR_MODE
)) {
332 ADD_SENSOR(FSSP_DATAID_T1
);
333 ADD_SENSOR(FSSP_DATAID_T2
);
336 #if defined(USE_ADC_INTERNAL)
337 if (telemetryIsSensorEnabled(SENSOR_TEMPERATURE
)) {
338 ADD_SENSOR(FSSP_DATAID_T11
);
342 if (isBatteryVoltageConfigured() && telemetryIsSensorEnabled(SENSOR_VOLTAGE
)) {
343 #ifdef USE_ESC_SENSOR_TELEMETRY
344 if (!telemetryIsSensorEnabled(ESC_SENSOR_VOLTAGE
))
347 ADD_SENSOR(FSSP_DATAID_VFAS
);
350 ADD_SENSOR(FSSP_DATAID_A4
);
353 if (isAmperageConfigured() && telemetryIsSensorEnabled(SENSOR_CURRENT
)) {
354 #ifdef USE_ESC_SENSOR_TELEMETRY
355 if (!telemetryIsSensorEnabled(ESC_SENSOR_CURRENT
))
358 ADD_SENSOR(FSSP_DATAID_CURRENT
);
361 if (telemetryIsSensorEnabled(SENSOR_FUEL
)) {
362 ADD_SENSOR(FSSP_DATAID_FUEL
);
366 if (telemetryIsSensorEnabled(SENSOR_HEADING
)) {
367 ADD_SENSOR(FSSP_DATAID_HEADING
);
371 if (sensors(SENSOR_ACC
)) {
372 if (telemetryIsSensorEnabled(SENSOR_PITCH
)) {
373 ADD_SENSOR(FSSP_DATAID_PITCH
);
375 if (telemetryIsSensorEnabled(SENSOR_ROLL
)) {
376 ADD_SENSOR(FSSP_DATAID_ROLL
);
378 if (telemetryIsSensorEnabled(SENSOR_ACC_X
)) {
379 ADD_SENSOR(FSSP_DATAID_ACCX
);
381 if (telemetryIsSensorEnabled(SENSOR_ACC_Y
)) {
382 ADD_SENSOR(FSSP_DATAID_ACCY
);
384 if (telemetryIsSensorEnabled(SENSOR_ACC_Z
)) {
385 ADD_SENSOR(FSSP_DATAID_ACCZ
);
390 if (sensors(SENSOR_BARO
)) {
391 if (telemetryIsSensorEnabled(SENSOR_ALTITUDE
)) {
392 ADD_SENSOR(FSSP_DATAID_ALTITUDE
);
394 if (telemetryIsSensorEnabled(SENSOR_VARIO
)) {
395 ADD_SENSOR(FSSP_DATAID_VARIO
);
400 if (featureIsEnabled(FEATURE_GPS
)) {
401 if (telemetryIsSensorEnabled(SENSOR_GROUND_SPEED
)) {
402 ADD_SENSOR(FSSP_DATAID_SPEED
);
404 if (telemetryIsSensorEnabled(SENSOR_LAT_LONG
)) {
405 ADD_SENSOR(FSSP_DATAID_LATLONG
);
406 ADD_SENSOR(FSSP_DATAID_LATLONG
); // twice (one for lat, one for long)
408 if (telemetryIsSensorEnabled(SENSOR_DISTANCE
)) {
409 ADD_SENSOR(FSSP_DATAID_HOME_DIST
);
411 if (telemetryIsSensorEnabled(SENSOR_ALTITUDE
)) {
412 ADD_SENSOR(FSSP_DATAID_GPS_ALT
);
417 frSkyDataIdTableInfo
.size
= frSkyDataIdTableInfo
.index
;
418 frSkyDataIdTableInfo
.index
= 0;
420 #ifdef USE_ESC_SENSOR_TELEMETRY
421 frSkyEscDataIdTableInfo
.index
= 0;
423 if (telemetryIsSensorEnabled(ESC_SENSOR_VOLTAGE
)) {
424 ADD_ESC_SENSOR(FSSP_DATAID_VFAS
);
426 if (telemetryIsSensorEnabled(ESC_SENSOR_CURRENT
)) {
427 ADD_ESC_SENSOR(FSSP_DATAID_CURRENT
);
429 if (telemetryIsSensorEnabled(ESC_SENSOR_RPM
)) {
430 ADD_ESC_SENSOR(FSSP_DATAID_RPM
);
432 if (telemetryIsSensorEnabled(ESC_SENSOR_TEMPERATURE
)) {
433 ADD_ESC_SENSOR(FSSP_DATAID_TEMP
);
436 frSkyEscDataIdTableInfo
.size
= frSkyEscDataIdTableInfo
.index
;
437 frSkyEscDataIdTableInfo
.index
= 0;
441 bool initSmartPortTelemetry(void)
443 if (telemetryState
== TELEMETRY_STATE_UNINITIALIZED
) {
444 portConfig
= findSerialPortConfig(FUNCTION_TELEMETRY_SMARTPORT
);
446 smartPortPortSharing
= determinePortSharing(portConfig
, FUNCTION_TELEMETRY_SMARTPORT
);
448 smartPortWriteFrame
= smartPortWriteFrameInternal
;
450 initSmartPortSensors();
452 telemetryState
= TELEMETRY_STATE_INITIALIZED_SERIAL
;
461 bool initSmartPortTelemetryExternal(smartPortWriteFrameFn
*smartPortWriteFrameExternal
)
463 if (telemetryState
== TELEMETRY_STATE_UNINITIALIZED
) {
464 smartPortWriteFrame
= smartPortWriteFrameExternal
;
466 initSmartPortSensors();
468 telemetryState
= TELEMETRY_STATE_INITIALIZED_EXTERNAL
;
476 static void freeSmartPortTelemetryPort(void)
478 closeSerialPort(smartPortSerialPort
);
479 smartPortSerialPort
= NULL
;
482 static void configureSmartPortTelemetryPort(void)
485 portOptions_e portOptions
= (telemetryConfig()->halfDuplex
? SERIAL_BIDIR
: SERIAL_UNIDIR
) | (telemetryConfig()->telemetry_inverted
? SERIAL_NOT_INVERTED
: SERIAL_INVERTED
);
487 smartPortSerialPort
= openSerialPort(portConfig
->identifier
, FUNCTION_TELEMETRY_SMARTPORT
, NULL
, NULL
, SMARTPORT_BAUD
, SMARTPORT_UART_MODE
, portOptions
);
491 void checkSmartPortTelemetryState(void)
493 if (telemetryState
== TELEMETRY_STATE_INITIALIZED_SERIAL
) {
494 bool enableSerialTelemetry
= telemetryDetermineEnabledState(smartPortPortSharing
);
496 if (enableSerialTelemetry
&& !smartPortSerialPort
) {
497 configureSmartPortTelemetryPort();
498 } else if (!enableSerialTelemetry
&& smartPortSerialPort
) {
499 freeSmartPortTelemetryPort();
504 #if defined(USE_MSP_OVER_TELEMETRY)
505 static void smartPortSendMspResponse(uint8_t *data
) {
506 smartPortPayload_t payload
;
507 payload
.frameId
= FSSP_MSPS_FRAME
;
508 memcpy(&payload
.valueId
, data
, SMARTPORT_MSP_PAYLOAD_SIZE
);
510 smartPortWriteFrame(&payload
);
514 void processSmartPortTelemetry(smartPortPayload_t
*payload
, volatile bool *clearToSend
, const timeUs_t
*requestTimeout
)
516 static uint8_t smartPortIdCycleCnt
= 0;
517 static uint8_t t1Cnt
= 0;
518 static uint8_t t2Cnt
= 0;
519 static uint8_t skipRequests
= 0;
520 #ifdef USE_ESC_SENSOR_TELEMETRY
521 static uint8_t smartPortIdOffset
= 0;
524 #if defined(USE_MSP_OVER_TELEMETRY)
527 } else if (payload
&& smartPortPayloadContainsMSP(payload
)) {
528 // Do not check the physical ID here again
529 // unless we start receiving other sensors' packets
530 // Pass only the payload: skip frameId
531 uint8_t *frameStart
= (uint8_t *)&payload
->valueId
;
532 smartPortMspReplyPending
= handleMspFrame(frameStart
, SMARTPORT_MSP_PAYLOAD_SIZE
, &skipRequests
);
534 // Don't send MSP response after write to eeprom
535 // CPU just got out of suspended state after writeEEPROM()
536 // We don't know if the receiver is listening again
537 // Skip a few telemetry requests before sending response
539 *clearToSend
= false;
547 while (doRun
&& *clearToSend
&& !skipRequests
) {
548 // 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.
549 if (requestTimeout
) {
550 if (cmpTimeUs(micros(), *requestTimeout
) >= 0) {
551 *clearToSend
= false;
559 #if defined(USE_MSP_OVER_TELEMETRY)
560 if (smartPortMspReplyPending
) {
561 smartPortMspReplyPending
= sendMspReply(SMARTPORT_MSP_PAYLOAD_SIZE
, &smartPortSendMspResponse
);
562 *clearToSend
= false;
568 // we can send back any data we want, our tables keep track of the order and frequency of each data type we send
569 frSkyTableInfo_t
* tableInfo
= &frSkyDataIdTableInfo
;
571 #ifdef USE_ESC_SENSOR_TELEMETRY
572 if (smartPortIdCycleCnt
>= ESC_SENSOR_PERIOD
) {
574 tableInfo
= &frSkyEscDataIdTableInfo
;
575 if (tableInfo
->index
== tableInfo
->size
) { // end of ESC table, return to other sensors
576 tableInfo
->index
= 0;
577 smartPortIdCycleCnt
= 0;
579 if (smartPortIdOffset
== getMotorCount() + 1) { // each motor and ESC_SENSOR_COMBINED
580 smartPortIdOffset
= 0;
584 if (smartPortIdCycleCnt
< ESC_SENSOR_PERIOD
) {
585 // send other sensors
586 tableInfo
= &frSkyDataIdTableInfo
;
588 if (tableInfo
->index
== tableInfo
->size
) { // end of table reached, loop back
589 tableInfo
->index
= 0;
591 #ifdef USE_ESC_SENSOR_TELEMETRY
594 uint16_t id
= tableInfo
->table
[tableInfo
->index
];
595 #ifdef USE_ESC_SENSOR_TELEMETRY
596 if (smartPortIdCycleCnt
>= ESC_SENSOR_PERIOD
) {
597 id
+= smartPortIdOffset
;
600 smartPortIdCycleCnt
++;
605 uint16_t vfasVoltage
;
608 #ifdef USE_ESC_SENSOR_TELEMETRY
609 escSensorData_t
*escData
;
613 case FSSP_DATAID_VFAS
:
614 vfasVoltage
= getBatteryVoltage();
615 if (telemetryConfig()->report_cell_voltage
) {
616 cellCount
= getBatteryCellCount();
617 vfasVoltage
= cellCount
? getBatteryVoltage() / cellCount
: 0;
619 smartPortSendPackage(id
, vfasVoltage
); // in 0.01V according to SmartPort spec
620 *clearToSend
= false;
622 #ifdef USE_ESC_SENSOR_TELEMETRY
623 case FSSP_DATAID_VFAS1
:
624 case FSSP_DATAID_VFAS2
:
625 case FSSP_DATAID_VFAS3
:
626 case FSSP_DATAID_VFAS4
:
627 case FSSP_DATAID_VFAS5
:
628 case FSSP_DATAID_VFAS6
:
629 case FSSP_DATAID_VFAS7
:
630 case FSSP_DATAID_VFAS8
:
631 escData
= getEscSensorData(id
- FSSP_DATAID_VFAS1
);
632 if (escData
!= NULL
) {
633 smartPortSendPackage(id
, escData
->voltage
);
634 *clearToSend
= false;
638 case FSSP_DATAID_CURRENT
:
639 smartPortSendPackage(id
, getAmperage() / 10); // in 0.1A according to SmartPort spec
640 *clearToSend
= false;
642 #ifdef USE_ESC_SENSOR_TELEMETRY
643 case FSSP_DATAID_CURRENT1
:
644 case FSSP_DATAID_CURRENT2
:
645 case FSSP_DATAID_CURRENT3
:
646 case FSSP_DATAID_CURRENT4
:
647 case FSSP_DATAID_CURRENT5
:
648 case FSSP_DATAID_CURRENT6
:
649 case FSSP_DATAID_CURRENT7
:
650 case FSSP_DATAID_CURRENT8
:
651 escData
= getEscSensorData(id
- FSSP_DATAID_CURRENT1
);
652 if (escData
!= NULL
) {
653 smartPortSendPackage(id
, escData
->current
);
654 *clearToSend
= false;
657 case FSSP_DATAID_RPM
:
658 escData
= getEscSensorData(ESC_SENSOR_COMBINED
);
659 if (escData
!= NULL
) {
660 smartPortSendPackage(id
, calcEscRpm(escData
->rpm
));
661 *clearToSend
= false;
664 case FSSP_DATAID_RPM1
:
665 case FSSP_DATAID_RPM2
:
666 case FSSP_DATAID_RPM3
:
667 case FSSP_DATAID_RPM4
:
668 case FSSP_DATAID_RPM5
:
669 case FSSP_DATAID_RPM6
:
670 case FSSP_DATAID_RPM7
:
671 case FSSP_DATAID_RPM8
:
672 escData
= getEscSensorData(id
- FSSP_DATAID_RPM1
);
673 if (escData
!= NULL
) {
674 smartPortSendPackage(id
, calcEscRpm(escData
->rpm
));
675 *clearToSend
= false;
678 case FSSP_DATAID_TEMP
:
679 escData
= getEscSensorData(ESC_SENSOR_COMBINED
);
680 if (escData
!= NULL
) {
681 smartPortSendPackage(id
, escData
->temperature
);
682 *clearToSend
= false;
685 case FSSP_DATAID_TEMP1
:
686 case FSSP_DATAID_TEMP2
:
687 case FSSP_DATAID_TEMP3
:
688 case FSSP_DATAID_TEMP4
:
689 case FSSP_DATAID_TEMP5
:
690 case FSSP_DATAID_TEMP6
:
691 case FSSP_DATAID_TEMP7
:
692 case FSSP_DATAID_TEMP8
:
693 escData
= getEscSensorData(id
- FSSP_DATAID_TEMP1
);
694 if (escData
!= NULL
) {
695 smartPortSendPackage(id
, escData
->temperature
);
696 *clearToSend
= false;
700 case FSSP_DATAID_ALTITUDE
:
701 smartPortSendPackage(id
, getEstimatedAltitudeCm()); // in cm according to SmartPort spec
702 *clearToSend
= false;
704 case FSSP_DATAID_FUEL
:
705 smartPortSendPackage(id
, getMAhDrawn()); // given in mAh, should be in percent according to SmartPort spec
706 *clearToSend
= false;
708 case FSSP_DATAID_VARIO
:
709 smartPortSendPackage(id
, getEstimatedVario()); // in cm/s according to SmartPort spec
710 *clearToSend
= false;
712 case FSSP_DATAID_HEADING
:
713 smartPortSendPackage(id
, attitude
.values
.yaw
* 10); // in degrees * 100 according to SmartPort spec
714 *clearToSend
= false;
717 case FSSP_DATAID_PITCH
:
718 smartPortSendPackage(id
, attitude
.values
.pitch
); // given in 10*deg
719 *clearToSend
= false;
721 case FSSP_DATAID_ROLL
:
722 smartPortSendPackage(id
, attitude
.values
.roll
); // given in 10*deg
723 *clearToSend
= false;
725 case FSSP_DATAID_ACCX
:
726 smartPortSendPackage(id
, lrintf(100 * acc
.accADC
[X
] * acc
.dev
.acc_1G_rec
)); // Multiply by 100 to show as x.xx g on Taranis
727 *clearToSend
= false;
729 case FSSP_DATAID_ACCY
:
730 smartPortSendPackage(id
, lrintf(100 * acc
.accADC
[Y
] * acc
.dev
.acc_1G_rec
));
731 *clearToSend
= false;
733 case FSSP_DATAID_ACCZ
:
734 smartPortSendPackage(id
, lrintf(100 * acc
.accADC
[Z
] * acc
.dev
.acc_1G_rec
));
735 *clearToSend
= false;
738 case FSSP_DATAID_T1
:
739 // we send all the flags as decimal digits for easy reading
741 // the t1Cnt simply allows the telemetry view to show at least some changes
746 tmpi
= t1Cnt
* 10000; // start off with at least one digit so the most significant 0 won't be cut off
747 // the Taranis seems to be able to fit 5 digits on the screen
748 // the Taranis seems to consider this number a signed 16 bit integer
750 if (!isArmingDisabled()) {
755 if (ARMING_FLAG(ARMED
)) {
759 if (FLIGHT_MODE(ANGLE_MODE
)) {
762 if (FLIGHT_MODE(HORIZON_MODE
)) {
765 if (FLIGHT_MODE(PASSTHRU_MODE
)) {
769 if (FLIGHT_MODE(MAG_MODE
)) {
773 if (FLIGHT_MODE(HEADFREE_MODE
)) {
777 smartPortSendPackage(id
, (uint32_t)tmpi
);
778 *clearToSend
= false;
780 case FSSP_DATAID_T2
:
782 if (sensors(SENSOR_GPS
)) {
783 // satellite accuracy HDOP: 0 = worst [HDOP > 5.5m], 9 = best [HDOP <= 1.0m]
784 uint16_t hdop
= constrain(scaleRange(gpsSol
.hdop
, 100, 550, 9, 0), 0, 9) * 100;
785 smartPortSendPackage(id
, (STATE(GPS_FIX
) ? 1000 : 0) + (STATE(GPS_FIX_HOME
) ? 2000 : 0) + hdop
+ gpsSol
.numSat
);
786 *clearToSend
= false;
787 } else if (featureIsEnabled(FEATURE_GPS
)) {
788 smartPortSendPackage(id
, 0);
789 *clearToSend
= false;
792 if (telemetryConfig()->pidValuesAsTelemetry
) {
795 tmp2
= currentPidProfile
->pid
[PID_ROLL
].P
;
796 tmp2
+= (currentPidProfile
->pid
[PID_PITCH
].P
<<8);
797 tmp2
+= (currentPidProfile
->pid
[PID_YAW
].P
<<16);
800 tmp2
= currentPidProfile
->pid
[PID_ROLL
].I
;
801 tmp2
+= (currentPidProfile
->pid
[PID_PITCH
].I
<<8);
802 tmp2
+= (currentPidProfile
->pid
[PID_YAW
].I
<<16);
805 tmp2
= currentPidProfile
->pid
[PID_ROLL
].D
;
806 tmp2
+= (currentPidProfile
->pid
[PID_PITCH
].D
<<8);
807 tmp2
+= (currentPidProfile
->pid
[PID_YAW
].D
<<16);
810 tmp2
= currentControlRateProfile
->rates
[FD_ROLL
];
811 tmp2
+= (currentControlRateProfile
->rates
[FD_PITCH
]<<8);
812 tmp2
+= (currentControlRateProfile
->rates
[FD_YAW
]<<16);
820 smartPortSendPackage(id
, tmp2
);
821 *clearToSend
= false;
825 #if defined(USE_ADC_INTERNAL)
826 case FSSP_DATAID_T11
:
827 smartPortSendPackage(id
, getCoreTemperatureCelsius());
828 *clearToSend
= false;
832 case FSSP_DATAID_SPEED
:
833 if (STATE(GPS_FIX
)) {
834 //convert to knots: 1cm/s = 0.0194384449 knots
835 //Speed should be sent in knots/1000 (GPS speed is in cm/s)
836 uint32_t tmpui
= gpsSol
.groundSpeed
* 1944 / 100;
837 smartPortSendPackage(id
, tmpui
);
838 *clearToSend
= false;
841 case FSSP_DATAID_LATLONG
:
842 if (STATE(GPS_FIX
)) {
844 // the same ID is sent twice, one for longitude, one for latitude
845 // the MSB of the sent uint32_t helps FrSky keep track
846 // the even/odd bit of our counter helps us keep track
847 if (tableInfo
->index
& 1) {
848 tmpui
= abs(gpsSol
.llh
.lon
); // now we have unsigned value and one bit to spare
849 tmpui
= (tmpui
+ tmpui
/ 2) / 25 | 0x80000000; // 6/100 = 1.5/25, division by power of 2 is fast
850 if (gpsSol
.llh
.lon
< 0) tmpui
|= 0x40000000;
853 tmpui
= abs(gpsSol
.llh
.lat
); // now we have unsigned value and one bit to spare
854 tmpui
= (tmpui
+ tmpui
/ 2) / 25; // 6/100 = 1.5/25, division by power of 2 is fast
855 if (gpsSol
.llh
.lat
< 0) tmpui
|= 0x40000000;
857 smartPortSendPackage(id
, tmpui
);
858 *clearToSend
= false;
861 case FSSP_DATAID_HOME_DIST
:
862 if (STATE(GPS_FIX
)) {
863 smartPortSendPackage(id
, GPS_distanceToHome
);
864 *clearToSend
= false;
867 case FSSP_DATAID_GPS_ALT
:
868 if (STATE(GPS_FIX
)) {
869 smartPortSendPackage(id
, gpsSol
.llh
.altCm
); // in cm according to SmartPort spec
870 *clearToSend
= false;
874 case FSSP_DATAID_A4
:
875 cellCount
= getBatteryCellCount();
876 vfasVoltage
= cellCount
? (getBatteryVoltage() / cellCount
) : 0; // in 0.01V according to SmartPort spec
877 smartPortSendPackage(id
, vfasVoltage
);
878 *clearToSend
= false;
882 // if nothing is sent, hasRequest isn't cleared, we already incremented the counter, just loop back to the start
887 static bool serialReadyToSend(void)
889 return (serialRxBytesWaiting(smartPortSerialPort
) == 0);
892 void handleSmartPortTelemetry(void)
894 const timeUs_t requestTimeout
= micros() + SMARTPORT_SERVICE_TIMEOUT_US
;
896 if (telemetryState
== TELEMETRY_STATE_INITIALIZED_SERIAL
&& smartPortSerialPort
) {
897 smartPortPayload_t
*payload
= NULL
;
898 bool clearToSend
= false;
899 while (serialRxBytesWaiting(smartPortSerialPort
) > 0 && !payload
) {
900 uint8_t c
= serialRead(smartPortSerialPort
);
901 payload
= smartPortDataReceive(c
, &clearToSend
, serialReadyToSend
, true);
904 processSmartPortTelemetry(payload
, &clearToSend
, &requestTimeout
);