Merge remote-tracking branch 'origin/master' into mmosca-mavlinkrc
[inav.git] / src / main / telemetry / jetiexbus.c
blobb0ffad843477b49e94b94eda8f59206f4c8d9cb9
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/>.
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <string.h>
25 #include "platform.h"
27 #if defined(USE_TELEMETRY_JETIEXBUS)
29 #include "build/build_config.h"
30 #include "build/debug.h"
31 #include "fc/runtime_config.h"
32 #include "fc/config.h"
33 #include "config/feature.h"
35 #include "common/utils.h"
36 #include "common/bitarray.h"
38 #include "drivers/serial.h"
39 #include "drivers/serial_uart.h"
40 #include "drivers/time.h"
42 #include "flight/imu.h"
44 #include "io/serial.h"
45 #include "io/gps.h"
47 #include "rx/rx.h"
48 #include "rx/jetiexbus.h"
50 #include "sensors/battery.h"
51 #include "sensors/sensors.h"
52 #include "sensors/acceleration.h"
54 #include "telemetry/jetiexbus.h"
55 #include "telemetry/telemetry.h"
57 #include "navigation/navigation.h"
59 #ifdef USE_ESC_SENSOR
60 #include "sensors/esc_sensor.h"
61 #include "flight/mixer.h"
62 #endif
64 #define EXTEL_DATA_MSG (0x40)
65 #define EXTEL_UNMASK_TYPE (0x3F)
66 #define EXTEL_SYNC_LEN 1
67 #define EXTEL_CRC_LEN 1
68 #define EXTEL_HEADER_LEN 6
69 #define EXTEL_MAX_LEN 26
70 #define EXTEL_OVERHEAD (EXTEL_SYNC_LEN + EXTEL_HEADER_LEN + EXTEL_CRC_LEN)
71 #define EXTEL_MAX_PAYLOAD (EXTEL_MAX_LEN - EXTEL_OVERHEAD)
72 #define EXBUS_MAX_REQUEST_BUFFER_SIZE (EXBUS_OVERHEAD + EXTEL_MAX_LEN)
74 enum exTelHeader_e {
75 EXTEL_HEADER_SYNC = 0,
76 EXTEL_HEADER_TYPE_LEN,
77 EXTEL_HEADER_USN_LB,
78 EXTEL_HEADER_USN_HB,
79 EXTEL_HEADER_LSN_LB,
80 EXTEL_HEADER_LSN_HB,
81 EXTEL_HEADER_RES,
82 EXTEL_HEADER_ID,
83 EXTEL_HEADER_DATA
86 enum {
87 EXBUS_TRANS_ZERO = 0,
88 EXBUS_TRANS_RX_READY,
89 EXBUS_TRANS_RX,
90 EXBUS_TRANS_IS_TX_COMPLETED,
91 EXBUS_TRANS_TX
94 enum exDataType_e {
95 EX_TYPE_6b = 0, // int6_t Data type 6b (-31 ¸31)
96 EX_TYPE_14b = 1, // int14_t Data type 14b (-8191 ¸8191)
97 EX_TYPE_22b = 4, // int22_t Data type 22b (-2097151 ¸2097151)
98 EX_TYPE_DT = 5, // int22_t Special data type – time and date
99 EX_TYPE_30b = 8, // int30_t Data type 30b (-536870911 ¸536870911)
100 EX_TYPE_GPS = 9, // int30_t Special data type – GPS coordinates: lo/hi minute - lo/hi degree.
101 EX_TYPE_DES = 255 // only for devicedescription
104 const uint8_t exDataTypeLen[] = {
105 [EX_TYPE_6b] = 1,
106 [EX_TYPE_14b] = 2,
107 [EX_TYPE_22b] = 3,
108 [EX_TYPE_DT] = 3,
109 [EX_TYPE_30b] = 4,
110 [EX_TYPE_GPS] = 4
113 typedef struct exBusSensor_s {
114 const char *label;
115 const char *unit;
116 const uint8_t exDataType;
117 const uint8_t decimals;
118 } exBusSensor_t;
120 #define DECIMAL_MASK(decimals) (decimals << 5)
122 // list of telemetry messages
123 // after every 15 sensors a new header has to be inserted (e.g. "BF D2")
124 const exBusSensor_t jetiExSensors[] = {
125 {"INAV D1", "", EX_TYPE_DES, 0 }, // device descripton
126 {"Voltage", "V", EX_TYPE_22b, DECIMAL_MASK(2)},
127 {"Current", "A", EX_TYPE_22b, DECIMAL_MASK(2)},
128 {"Altitude", "m", EX_TYPE_22b, DECIMAL_MASK(2)},
129 {"Capacity", "mAh", EX_TYPE_22b, DECIMAL_MASK(0)},
130 {"Power", "W", EX_TYPE_22b, DECIMAL_MASK(0)},
131 {"Roll angle", "\xB0", EX_TYPE_22b, DECIMAL_MASK(1)},
132 {"Pitch angle", "\xB0", EX_TYPE_22b, DECIMAL_MASK(1)},
133 {"Heading", "\xB0", EX_TYPE_22b, DECIMAL_MASK(1)},
134 {"Vario", "m/s", EX_TYPE_22b, DECIMAL_MASK(2)},
135 {"GPS Sats", "", EX_TYPE_22b, DECIMAL_MASK(0)},
136 {"GPS Long", "", EX_TYPE_GPS, DECIMAL_MASK(0)},
137 {"GPS Lat", "", EX_TYPE_GPS, DECIMAL_MASK(0)},
138 {"GPS Speed", "m/s", EX_TYPE_22b, DECIMAL_MASK(2)},
139 {"GPS H-Distance", "m", EX_TYPE_22b, DECIMAL_MASK(0)},
140 {"GPS H-Direction", "\xB0", EX_TYPE_22b, DECIMAL_MASK(1)},
141 {"INAV D2", "", EX_TYPE_DES, 0 }, // device descripton
142 {"GPS Heading", "\xB0", EX_TYPE_22b, DECIMAL_MASK(1)},
143 {"GPS Altitude", "m", EX_TYPE_22b, DECIMAL_MASK(2)},
144 {"G-Force X", "", EX_TYPE_22b, DECIMAL_MASK(3)},
145 {"G-Force Y", "", EX_TYPE_22b, DECIMAL_MASK(3)},
146 {"G-Force Z", "", EX_TYPE_22b, DECIMAL_MASK(3)},
147 {"RPM", "", EX_TYPE_22b, DECIMAL_MASK(0)},
148 {"Trip Distance", "m", EX_TYPE_22b, DECIMAL_MASK(1)}
151 // after every 15 sensors increment the step by 2 (e.g. ...EX_VAL15, EX_VAL16 = 17) to skip the device description
152 enum exSensors_e {
153 EX_VOLTAGE = 1,
154 EX_CURRENT,
155 EX_ALTITUDE,
156 EX_CAPACITY,
157 EX_POWER,
158 EX_ROLL_ANGLE,
159 EX_PITCH_ANGLE,
160 EX_HEADING,
161 EX_VARIO,
162 EX_GPS_SATS,
163 EX_GPS_LONG,
164 EX_GPS_LAT,
165 EX_GPS_SPEED,
166 EX_GPS_DISTANCE_TO_HOME,
167 EX_GPS_DIRECTION_TO_HOME,
168 EX_GPS_HEADING = 17,
169 EX_GPS_ALTITUDE,
170 EX_GFORCE_X,
171 EX_GFORCE_Y,
172 EX_GFORCE_Z,
173 EX_RPM,
174 EX_TRIP_DISTANCE,
177 union{
178 int32_t vInt;
179 uint16_t vWord[2];
180 char vBytes[4];
181 } exGps;
184 #define JETI_EX_SENSOR_COUNT (ARRAYLEN(jetiExSensors))
186 static uint8_t jetiExBusTelemetryFrame[40];
187 static uint8_t jetiExBusTransceiveState = EXBUS_TRANS_RX;
188 static uint8_t firstActiveSensor = 0;
189 static uint32_t exSensorEnabled = 0;
191 static uint8_t sendJetiExBusTelemetry(uint8_t packetID, uint8_t item);
192 static uint8_t getNextActiveSensor(uint8_t currentSensor);
194 // Jeti Ex Telemetry CRC calculations for a frame
195 uint8_t calcCRC8(uint8_t *pt, uint8_t msgLen)
197 uint8_t crc=0;
198 for (uint8_t mlen = 0; mlen < msgLen; mlen++) {
199 crc ^= pt[mlen];
200 crc = crc ^ (crc << 1) ^ (crc << 2) ^ (0x0e090700 >> ((crc >> 3) & 0x18));
202 return(crc);
205 void enableGpsTelemetry(bool enable)
207 if (enable) {
208 bitArraySet(&exSensorEnabled, EX_GPS_SATS);
209 bitArraySet(&exSensorEnabled, EX_GPS_LONG);
210 bitArraySet(&exSensorEnabled, EX_GPS_LAT);
211 bitArraySet(&exSensorEnabled, EX_GPS_SPEED);
212 bitArraySet(&exSensorEnabled, EX_GPS_DISTANCE_TO_HOME);
213 bitArraySet(&exSensorEnabled, EX_GPS_DIRECTION_TO_HOME);
214 bitArraySet(&exSensorEnabled, EX_GPS_HEADING);
215 bitArraySet(&exSensorEnabled, EX_GPS_ALTITUDE);
216 bitArraySet(&exSensorEnabled, EX_TRIP_DISTANCE);
217 } else {
218 bitArrayClr(&exSensorEnabled, EX_GPS_SATS);
219 bitArrayClr(&exSensorEnabled, EX_GPS_LONG);
220 bitArrayClr(&exSensorEnabled, EX_GPS_LAT);
221 bitArrayClr(&exSensorEnabled, EX_GPS_SPEED);
222 bitArrayClr(&exSensorEnabled, EX_GPS_DISTANCE_TO_HOME);
223 bitArrayClr(&exSensorEnabled, EX_GPS_DIRECTION_TO_HOME);
224 bitArrayClr(&exSensorEnabled, EX_GPS_HEADING);
225 bitArrayClr(&exSensorEnabled, EX_GPS_ALTITUDE);
226 bitArrayClr(&exSensorEnabled, EX_TRIP_DISTANCE);
231 * -----------------------------------------------
232 * Jeti Ex Bus Telemetry
233 * -----------------------------------------------
235 void initJetiExBusTelemetry(void)
237 // Init Ex Bus Frame header
238 jetiExBusTelemetryFrame[EXBUS_HEADER_SYNC] = 0x3B; // Startbytes
239 jetiExBusTelemetryFrame[EXBUS_HEADER_REQ] = 0x01;
240 jetiExBusTelemetryFrame[EXBUS_HEADER_DATA_ID] = 0x3A; // Ex Telemetry
242 // Init Ex Telemetry header
243 uint8_t *jetiExTelemetryFrame = &jetiExBusTelemetryFrame[EXBUS_HEADER_DATA];
245 jetiExTelemetryFrame[EXTEL_HEADER_SYNC] = 0x9F; // Startbyte
246 jetiExTelemetryFrame[EXTEL_HEADER_USN_LB] = 0x1E; // Serial Number 4 Byte
247 jetiExTelemetryFrame[EXTEL_HEADER_USN_HB] = 0xA4;
248 jetiExTelemetryFrame[EXTEL_HEADER_LSN_LB] = 0x00; // increment by telemetry count (%16) > only 15 values per device possible
249 jetiExTelemetryFrame[EXTEL_HEADER_LSN_HB] = 0x00;
250 jetiExTelemetryFrame[EXTEL_HEADER_RES] = 0x00; // reserved, by default 0x00
252 // Check which sensors are available
253 if (isBatteryVoltageConfigured()) {
254 bitArraySet(&exSensorEnabled, EX_VOLTAGE);
256 if (isAmperageConfigured()) {
257 bitArraySet(&exSensorEnabled, EX_CURRENT);
259 if (isBatteryVoltageConfigured() && isAmperageConfigured()) {
260 bitArraySet(&exSensorEnabled, EX_POWER);
261 bitArraySet(&exSensorEnabled, EX_CAPACITY);
263 if (sensors(SENSOR_BARO)) {
264 bitArraySet(&exSensorEnabled, EX_ALTITUDE);
265 bitArraySet(&exSensorEnabled, EX_VARIO);
267 if (sensors(SENSOR_ACC)) {
268 bitArraySet(&exSensorEnabled, EX_ROLL_ANGLE);
269 bitArraySet(&exSensorEnabled, EX_PITCH_ANGLE);
270 bitArraySet(&exSensorEnabled, EX_GFORCE_X);
271 bitArraySet(&exSensorEnabled, EX_GFORCE_Y);
272 bitArraySet(&exSensorEnabled, EX_GFORCE_Z);
274 if (sensors(SENSOR_MAG)) {
275 bitArraySet(&exSensorEnabled, EX_HEADING);
278 enableGpsTelemetry(feature(FEATURE_GPS));
280 #ifdef USE_ESC_SENSOR
281 if (STATE(ESC_SENSOR_ENABLED) && getMotorCount() > 0) {
282 bitArraySet(&exSensorEnabled, EX_RPM);
284 #endif
286 firstActiveSensor = getNextActiveSensor(0); // find the first active sensor
289 void createExTelemetryTextMessage(uint8_t *exMessage, uint8_t messageID, const exBusSensor_t *sensor)
291 uint8_t labelLength = strlen(sensor->label);
292 uint8_t unitLength = strlen(sensor->unit);
294 exMessage[EXTEL_HEADER_TYPE_LEN] = EXTEL_OVERHEAD + labelLength + unitLength;
295 exMessage[EXTEL_HEADER_LSN_LB] = messageID & 0xF0; // Device ID
296 exMessage[EXTEL_HEADER_ID] = messageID & 0x0F; // Sensor ID (%16)
297 exMessage[EXTEL_HEADER_DATA] = (labelLength << 3) + unitLength;
299 memcpy(&exMessage[EXTEL_HEADER_DATA + 1], sensor->label, labelLength);
300 memcpy(&exMessage[EXTEL_HEADER_DATA + 1 + labelLength], sensor->unit, unitLength);
302 exMessage[exMessage[EXTEL_HEADER_TYPE_LEN] + EXTEL_CRC_LEN] = calcCRC8(&exMessage[EXTEL_HEADER_TYPE_LEN], exMessage[EXTEL_HEADER_TYPE_LEN]);
305 uint32_t calcGpsDDMMmmm(int32_t value, bool isLong)
307 uint32_t absValue = ABS(value);
308 uint16_t deg16 = absValue / GPS_DEGREES_DIVIDER;
309 uint16_t min16 = (absValue - deg16 * GPS_DEGREES_DIVIDER) * 6 / 1000;
311 exGps.vInt = 0;
312 exGps.vWord[0] = min16;
313 exGps.vWord[1] = deg16;
314 exGps.vWord[1] |= isLong ? 0x2000 : 0;
315 exGps.vWord[1] |= (value < 0) ? 0x4000 : 0;
317 return exGps.vInt;
321 int32_t getSensorValue(uint8_t sensor)
324 #ifdef USE_ESC_SENSOR
325 escSensorData_t * escSensor;
326 #endif
328 switch (sensor) {
329 case EX_VOLTAGE:
330 return telemetryConfig()->report_cell_voltage ? getBatteryAverageCellVoltage() : getBatteryVoltage();
331 break;
333 case EX_CURRENT:
334 return getAmperage();
335 break;
337 case EX_ALTITUDE:
338 return getEstimatedActualPosition(Z);
339 break;
341 case EX_CAPACITY:
342 return getMAhDrawn();
343 break;
345 case EX_POWER:
346 return (getBatteryVoltage() * getAmperage() / 10000);
347 break;
349 case EX_ROLL_ANGLE:
350 return attitude.values.roll;
351 break;
353 case EX_PITCH_ANGLE:
354 return attitude.values.pitch;
355 break;
357 case EX_HEADING:
358 return attitude.values.yaw;
359 break;
361 case EX_VARIO:
362 return getEstimatedActualVelocity(Z);
363 break;
365 #ifdef USE_GPS
366 case EX_GPS_SATS:
367 return gpsSol.numSat;
368 break;
370 case EX_GPS_LONG:
371 return calcGpsDDMMmmm(gpsSol.llh.lon, true);
372 break;
374 case EX_GPS_LAT:
375 return calcGpsDDMMmmm(gpsSol.llh.lat, false);
376 break;
378 case EX_GPS_SPEED:
379 return gpsSol.groundSpeed;
380 break;
382 case EX_GPS_DISTANCE_TO_HOME:
383 return GPS_distanceToHome;
384 break;
386 case EX_GPS_DIRECTION_TO_HOME:
387 return GPS_directionToHome;
388 break;
390 case EX_GPS_HEADING:
391 return gpsSol.groundCourse;
392 break;
394 case EX_GPS_ALTITUDE:
395 return getEstimatedActualPosition(Z);
396 break;
397 #endif
399 case EX_GFORCE_X:
400 return acc.accADCf[X] * 1000;
401 break;
403 case EX_GFORCE_Y:
404 return acc.accADCf[Y] * 1000;
405 break;
407 case EX_GFORCE_Z:
408 return acc.accADCf[Z] * 1000;
409 break;
411 #ifdef USE_ESC_SENSOR
412 case EX_RPM:
413 escSensor = escSensorGetData();
414 if (escSensor && escSensor->dataAge <= ESC_DATA_MAX_AGE) {
415 return escSensor->rpm;
416 } else {
417 return 0;
419 break;
420 #endif
422 case EX_TRIP_DISTANCE:
423 return getTotalTravelDistance() / 10;
425 default:
426 return -1;
430 uint8_t getNextActiveSensor(uint8_t currentSensor)
432 while( ++currentSensor < JETI_EX_SENSOR_COUNT) {
433 if (bitArrayGet(&exSensorEnabled, currentSensor)) {
434 break;
437 if (currentSensor == JETI_EX_SENSOR_COUNT ) {
438 currentSensor = firstActiveSensor;
440 return currentSensor;
443 uint8_t createExTelemetryValueMessage(uint8_t *exMessage, uint8_t item)
445 uint8_t startItem = item;
446 uint8_t sensorItemMaxGroup = (item & 0xF0) + 0x10;
447 uint8_t iCount;
448 uint8_t messageSize;
449 uint32_t sensorValue;
451 exMessage[EXTEL_HEADER_LSN_LB] = item & 0xF0; // Device ID
452 uint8_t *p = &exMessage[EXTEL_HEADER_ID];
454 while (item < sensorItemMaxGroup) {
455 *p++ = ((item & 0x0F) << 4) | jetiExSensors[item].exDataType; // Sensor ID (%16) | EX Data Type
457 sensorValue = getSensorValue(item);
458 iCount = exDataTypeLen[jetiExSensors[item].exDataType];
460 while (iCount > 1) {
461 *p++ = sensorValue;
462 sensorValue = sensorValue >> 8;
463 iCount--;
465 if (jetiExSensors[item].exDataType != EX_TYPE_GPS) {
466 *p++ = (sensorValue & 0x9F) | jetiExSensors[item].decimals;
467 } else {
468 *p++ = sensorValue;
471 item = getNextActiveSensor(item);
473 if (startItem >= item) {
474 break;
477 if ((p - &exMessage[EXTEL_HEADER_ID]) + exDataTypeLen[jetiExSensors[item].exDataType] + 1 >= EXTEL_MAX_PAYLOAD) {
478 break;
481 messageSize = (EXTEL_HEADER_LEN + (p-&exMessage[EXTEL_HEADER_ID]));
482 exMessage[EXTEL_HEADER_TYPE_LEN] = EXTEL_DATA_MSG | messageSize;
483 exMessage[messageSize + EXTEL_CRC_LEN] = calcCRC8(&exMessage[EXTEL_HEADER_TYPE_LEN], messageSize);
485 return item; // return the next item
488 void createExBusMessage(uint8_t *exBusMessage, uint8_t *exMessage, uint8_t packetID)
490 uint16_t crc16;
492 exBusMessage[EXBUS_HEADER_PACKET_ID] = packetID;
493 exBusMessage[EXBUS_HEADER_SUBLEN] = (exMessage[EXTEL_HEADER_TYPE_LEN] & EXTEL_UNMASK_TYPE) + 2; // +2: startbyte & CRC8
494 exBusMessage[EXBUS_HEADER_MSG_LEN] = EXBUS_OVERHEAD + exBusMessage[EXBUS_HEADER_SUBLEN];
496 crc16 = jetiExBusCalcCRC16(exBusMessage, exBusMessage[EXBUS_HEADER_MSG_LEN] - EXBUS_CRC_LEN);
497 exBusMessage[exBusMessage[EXBUS_HEADER_MSG_LEN] - 2] = crc16;
498 exBusMessage[exBusMessage[EXBUS_HEADER_MSG_LEN] - 1] = crc16 >> 8;
501 void checkJetiExBusTelemetryState(void)
503 return;
506 void handleJetiExBusTelemetry(void)
508 static uint16_t framesLost = 0; // only for debug
509 static uint8_t item = 0;
510 uint32_t timeDiff;
512 // Check if we shall reset frame position due to time
513 if (jetiExBusRequestState == EXBUS_STATE_RECEIVED) {
515 // to prevent timing issues from request to answer - max. 4ms
516 timeDiff = micros() - jetiTimeStampRequest;
518 if (timeDiff > 3000) { // include reserved time
519 jetiExBusRequestState = EXBUS_STATE_ZERO;
520 framesLost++;
521 return;
524 if ((jetiExBusRequestFrame[EXBUS_HEADER_DATA_ID] == EXBUS_EX_REQUEST) && (jetiExBusCalcCRC16(jetiExBusRequestFrame, jetiExBusRequestFrame[EXBUS_HEADER_MSG_LEN]) == 0)) {
525 if (serialRxBytesWaiting(jetiExBusPort) == 0) {
526 jetiExBusTransceiveState = EXBUS_TRANS_TX;
527 item = sendJetiExBusTelemetry(jetiExBusRequestFrame[EXBUS_HEADER_PACKET_ID], item);
528 jetiExBusRequestState = EXBUS_STATE_PROCESSED;
529 return;
531 } else {
532 jetiExBusRequestState = EXBUS_STATE_ZERO;
533 return;
537 // check the state if transmit is ready
538 if (jetiExBusTransceiveState == EXBUS_TRANS_IS_TX_COMPLETED) {
539 if (isSerialTransmitBufferEmpty(jetiExBusPort)) {
540 jetiExBusTransceiveState = EXBUS_TRANS_RX;
541 jetiExBusRequestState = EXBUS_STATE_ZERO;
546 uint8_t sendJetiExBusTelemetry(uint8_t packetID, uint8_t item)
548 static uint8_t sensorDescriptionCounter = 0xFF;
549 static uint8_t requestLoop = 0xFF;
550 static bool allSensorsActive = true;
551 uint8_t *jetiExTelemetryFrame = &jetiExBusTelemetryFrame[EXBUS_HEADER_DATA];
553 if (requestLoop) {
554 while( ++sensorDescriptionCounter < JETI_EX_SENSOR_COUNT) {
555 if (bitArrayGet(&exSensorEnabled, sensorDescriptionCounter) || (jetiExSensors[sensorDescriptionCounter].exDataType == EX_TYPE_DES)) {
556 break;
559 if (sensorDescriptionCounter == JETI_EX_SENSOR_COUNT ) {
560 sensorDescriptionCounter = 0;
563 createExTelemetryTextMessage(jetiExTelemetryFrame, sensorDescriptionCounter, &jetiExSensors[sensorDescriptionCounter]);
564 createExBusMessage(jetiExBusTelemetryFrame, jetiExTelemetryFrame, packetID);
565 requestLoop--;
566 if (requestLoop == 0) {
567 item = firstActiveSensor;
568 if (feature(FEATURE_GPS)) {
569 enableGpsTelemetry(false);
570 allSensorsActive = false;
573 } else {
574 item = createExTelemetryValueMessage(jetiExTelemetryFrame, item);
575 createExBusMessage(jetiExBusTelemetryFrame, jetiExTelemetryFrame, packetID);
577 if (!allSensorsActive) {
578 if (sensors(SENSOR_GPS)
579 #ifdef USE_GPS_FIX_ESTIMATION
580 || STATE(GPS_ESTIMATED_FIX)
581 #endif
583 enableGpsTelemetry(true);
584 allSensorsActive = true;
589 serialWriteBuf(jetiExBusPort, jetiExBusTelemetryFrame, jetiExBusTelemetryFrame[EXBUS_HEADER_MSG_LEN]);
590 jetiExBusTransceiveState = EXBUS_TRANS_IS_TX_COMPLETED;
592 return item;
594 #endif