2 * This file is part of u360gts, aka amv-open360tracker 32bits:
3 * https://github.com/raul-ortega/amv-open360tracker-32bits
5 * The code below is an adaptation by Raúl Ortega of the original code written by Samuel Brucksch:
6 * https://github.com/SamuelBrucksch/open360tracker
8 * u360gts is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * u360gts is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with u360gts. If not, see <http://www.gnu.org/licenses/>.
24 #include "telemetry.h"
27 void processFrskyPacket(uint8_t *packet
);
28 void parseTelemHubByte(uint8_t c
);
29 int32_t coordToLong(int8_t neg
, uint16_t bp
, uint16_t ap
);
31 #define START_STOP 0x7e
32 #define BYTESTUFF 0x7d
33 #define STUFF_MASK 0x20
35 // FrSky PRIM IDs (1 byte)
36 #define DATA_FRAME 0x10
38 // FrSky old DATA IDs (1 byte)
39 #define GPS_ALT_BP_ID 0x01
40 #define GPS_ALT_AP_ID 0x09
41 #define BARO_ALT_BP_ID 0x10
42 #define BARO_ALT_AP_ID 0x21
43 #define GPS_LONG_BP_ID 0x12
44 #define GPS_LONG_AP_ID 0x1A
45 #define GPS_LAT_BP_ID 0x13
46 #define GPS_LAT_AP_ID 0x1B
47 #define GPS_LONG_EW_ID 0x22
48 #define GPS_LAT_NS_ID 0x23
49 #define FRSKY_LAST_ID 0x3f
50 //used for sats and fix type
53 // FrSky Passthrough DATA IDs from APM
54 #define GPS_STATUS 0x5002
55 #define AIRCRAFT_HOME 0X5004
56 #define bitmask(X,Y) (((1 << X) -1) << Y)
58 // FrSky new DATA IDs (2 bytes)
59 #define VFAS_FIRST_ID 0x0210
60 #define VFAS_LAST_ID 0x021f
61 #define ALT_FIRST_ID 0x0100
62 #define ALT_LAST_ID 0x010f
63 #define T2_FIRST_ID 0x0410
64 #define T2_LAST_ID 0x041f
65 #define GPS_LONG_LATI_FIRST_ID 0x0800
66 #define GPS_LONG_LATI_LAST_ID 0x080f
67 #define GPS_ALT_FIRST_ID 0x0820
68 #define GPS_ALT_LAST_ID 0x082f
69 #define GPS_SPEED_FIRST_ID 0x0830
70 #define GPS_SPEED_LAST_ID 0x083f
71 #define GPS_COURS_FIRST_ID 0x0840
72 #define GPS_COURS_LAST_ID 0x084f
74 #define TELEMETRY_INIT 0
75 #define TELEMETRY_OK 1
76 #define TELEMETRY_KO 2
78 #define FRSKY_RX_PACKET_SIZE 8
80 #define FRSKYX_LATLON_DIVIDER 1000000
82 uint8_t frskyx_RxBuffer
[FRSKY_RX_PACKET_SIZE
];
83 uint8_t telemetryState
= TELEMETRY_INIT
;
93 //lat lon in decimal degree dd.ddddd
99 //VFAS sensor = voltage
100 int16_t telemetry_voltage
;
102 int32_t frskyx_setLat() {
103 int32_t value
= coordToLong(NS
== 'N' ? 1 : -1, lat_bp
, lat_ap
);
108 int32_t frskyx_setLon() {
109 int32_t value
= coordToLong(EW
== 'E' ? 1 : -1, lon_bp
, lon_ap
);
114 int32_t coordToLong(int8_t neg
, uint16_t bp
, uint16_t ap
) {
115 uint32_t first
= ((uint32_t)bp
/ 100) * FRSKYX_LATLON_DIVIDER
;
116 uint32_t second
= ((((uint32_t)bp
% 100) * FRSKYX_LATLON_DIVIDER
) + ((uint32_t)ap
* 100)) / 60;
117 return ((int32_t)(first
+ second
) * (uint32_t)neg
);
120 void processHubPacket(uint8_t id
, uint16_t value
)
122 if (id
> FRSKY_LAST_ID
)
149 if(telemetry_provider
== TELEMETRY_PROVIDER_DIY_GPS
){
152 } else if (telemetry_provider
== TELEMETRY_PROVIDER_INAV
){
155 if ((value
>= 1000) && (value
< 2000)) {
156 telemetry_fixtype
= 1;
158 else if ((value
>= 2000) && (value
< 3000)) {
159 telemetry_fixtype
= 2;
161 else if (value
>= 3000) {
162 telemetry_fixtype
= 3;
165 telemetry_fixtype
= 0;
172 if ((NS
== 'N' || NS
== 'S') && (EW
== 'E' || EW
== 'W')) {
173 telemetry_lat
= frskyx_setLat();
174 telemetry_lon
= frskyx_setLon();
175 telemetry_sats
= sats
;
180 bool checkSportPacket_V1(uint8_t *packet
)
183 for (int i
= 1; i
< FRSKY_RX_PACKET_SIZE
; i
++) {
184 crc
+= packet
[i
]; //0-1FF
185 crc
+= crc
>> 8; //0-100
187 crc
+= crc
>> 8; //0-0FF
190 return (crc
== 0x00ff);
193 static uint8_t checkSportPacket_V2(uint8_t * packet
)
196 for (int i
=1; i
<FRSKY_RX_PACKET_SIZE
-1; ++i
) {
197 crc
+= packet
[i
]; // 0-1FE
198 crc
+= crc
>> 8; // 0-1FF
199 crc
&= 0x00ff; // 0-FF
204 #define SPORT_DATA_U8(packet) (packet[4])
205 #define SPORT_DATA_S32(packet) (*((int32_t *)(packet+4)))
206 #define SPORT_DATA_U32(packet) (*((uint32_t *)(packet+4)))
207 #define HUB_DATA_U16(packet) (*((uint16_t *)(packet+4)))
209 void processSportPacket(uint8_t *packet
)
211 uint8_t prim
= packet
[1];
212 uint16_t appId
= *((uint16_t *)(packet
+ 2));
214 if (!checkSportPacket_V1(packet
) && !checkSportPacket_V2(packet
)){
215 telemetry_failed_cs
++;
219 if(appId
== GPS_STATUS
) telemetry_provider
= TELEMETRY_PROVIDER_APM10
;
224 if ((appId
>> 8) == 0) {
226 uint8_t id
= (uint8_t)appId
;
227 uint16_t value
= HUB_DATA_U16(packet
);
228 processHubPacket(id
, value
);
230 else if (appId
>= VFAS_FIRST_ID
&& appId
<= VFAS_LAST_ID
) {
231 telemetry_voltage
= SPORT_DATA_S32(packet
); //get voltage
233 else if (appId
>= T2_FIRST_ID
&& appId
<= T2_LAST_ID
) {
234 if(telemetry_provider
== TELEMETRY_PROVIDER_DIY_GPS
){
235 sats
= SPORT_DATA_S32(packet
) / 10;
236 //fix = SPORT_DATA_S32(packet) % 10;
237 } else if (telemetry_provider
== TELEMETRY_PROVIDER_INAV
){
238 sats
= SPORT_DATA_S32(packet
) % 100;
239 if ((SPORT_DATA_S32(packet
) >= 1000) && (SPORT_DATA_S32(packet
) < 2000)) {
240 telemetry_fixtype
= 1;
242 else if ((SPORT_DATA_S32(packet
) >= 2000) && (SPORT_DATA_S32(packet
) < 3000)) {
243 telemetry_fixtype
= 2;
245 else if (SPORT_DATA_S32(packet
) >= 3000) {
246 telemetry_fixtype
= 3;
249 telemetry_fixtype
= 0;
252 //we assume that other systems just send the sats over temp2 and fix over temp1
253 sats
= SPORT_DATA_S32(packet
);
258 else if (appId
>= GPS_SPEED_FIRST_ID
&& appId
<= GPS_SPEED_LAST_ID
) {
259 //frskyData.hub.gpsSpeed_bp = (uint16_t) (SPORT_DATA_U32(packet) / 1000);
261 else if (appId
>= GPS_COURS_FIRST_ID
&& appId
<= GPS_COURS_LAST_ID
) {
262 //uint32_t course = SPORT_DATA_U32(packet)/100;
264 else if (appId
>= GPS_ALT_FIRST_ID
&& appId
<= GPS_ALT_LAST_ID
) {
265 alt
= SPORT_DATA_S32(packet
) / 100;
270 else if (appId
>= GPS_LONG_LATI_FIRST_ID
&& appId
<= GPS_LONG_LATI_LAST_ID
) {
271 uint32_t gps_long_lati_data
= SPORT_DATA_U32(packet
);
272 uint32_t gps_long_lati_b1w
, gps_long_lati_a1w
;
273 gps_long_lati_b1w
= (gps_long_lati_data
& 0x3fffffff) / 10000;
274 gps_long_lati_a1w
= (gps_long_lati_data
& 0x3fffffff) % 10000;
276 switch ((gps_long_lati_data
& 0xc0000000) >> 30) {
278 lat_bp
= (gps_long_lati_b1w
/ 60 * 100) + (gps_long_lati_b1w
% 60);
279 lat_ap
= gps_long_lati_a1w
;
283 lat_bp
= (gps_long_lati_b1w
/ 60 * 100) + (gps_long_lati_b1w
% 60);
284 lat_ap
= gps_long_lati_a1w
;
288 lon_bp
= (gps_long_lati_b1w
/ 60 * 100) + (gps_long_lati_b1w
% 60);
289 lon_ap
= gps_long_lati_a1w
;
293 lon_bp
= (gps_long_lati_b1w
/ 60 * 100) + (gps_long_lati_b1w
% 60);
294 lon_ap
= gps_long_lati_a1w
;
298 if ((NS
== 'N' || NS
== 'S') && (EW
== 'E' || EW
== 'W')) {
299 telemetry_lat
= frskyx_setLat();
300 telemetry_lon
= frskyx_setLon();
301 telemetry_sats
= sats
;
306 else if(appId
== GPS_STATUS
&& telemetry_provider
== TELEMETRY_PROVIDER_APM10
){
307 sats
= (uint8_t) (SPORT_DATA_U32(packet
) & bitmask(4,0));
308 //telemetry.gpsAlt = bit32.extract(VALUE,24,7) * (10^bit32.extract(VALUE,22,2)) * (bit32.extract(VALUE,31,1) == 1 and -1 or 1) -- dm
309 uint16_t msl_dc
, msl_x
, msl_sgn
;
310 msl_dc
= (SPORT_DATA_U32(packet
) & bitmask(7,24)) >> 24;
311 msl_x
= (SPORT_DATA_U32(packet
) & bitmask(2,22)) >> 22;
312 msl_sgn
= (SPORT_DATA_U32(packet
) & bitmask(1,31)) >> 31;
313 telemetry_alt
= (int16_t) (msl_dc
* pow(10,msl_x
) * 0.1 * (msl_sgn
== 1?-1:1));
320 // Receive buffer state machine state enum
321 enum FrSkyDataState
{
327 void frskyx_encodeTargetData(uint8_t data
) {
328 static uint8_t numPktBytes
= 0;
329 static uint8_t dataState
= STATE_DATA_IDLE
;
331 if (data
== START_STOP
) {
332 dataState
= STATE_DATA_IN_FRAME
;
338 frskyx_RxBuffer
[numPktBytes
++] = data
^ STUFF_MASK
;
339 dataState
= STATE_DATA_IN_FRAME
;
342 case STATE_DATA_IN_FRAME
:
343 if (data
== BYTESTUFF
)
344 dataState
= STATE_DATA_XOR
; // XOR next byte
346 frskyx_RxBuffer
[numPktBytes
++] = data
;
351 if (numPktBytes
== FRSKY_RX_PACKET_SIZE
) {
352 processSportPacket(frskyx_RxBuffer
);
353 dataState
= STATE_DATA_IDLE
;