5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
23 void parseTelemHubByte(uint8_t byte
)
25 static int8_t structPos
;
26 static uint8_t lowByte
;
27 static TS_STATE state
= TS_IDLE
;
33 if (state
== TS_IDLE
) {
38 state
= (TS_STATE
)(state
- TS_XOR
);
40 else if (byte
== 0x5d) {
41 state
= (TS_STATE
)(state
| TS_XOR
);
44 if (state
== TS_DATA_ID
) {
54 if (state
== TS_DATA_LOW
) {
61 processHubPacket(structPos
, (byte
<< 8) + lowByte
);
64 void frskyDProcessPacket(const uint8_t *packet
)
66 // What type of packet?
69 case LINKPKT
: // A1/A2/RSSI values
71 setTelemetryValue(PROTOCOL_TELEMETRY_FRSKY_D
, D_A1_ID
, 0, 0, packet
[1], UNIT_VOLTS
, 0);
72 setTelemetryValue(PROTOCOL_TELEMETRY_FRSKY_D
, D_A2_ID
, 0, 0, packet
[2], UNIT_VOLTS
, 0);
73 setTelemetryValue(PROTOCOL_TELEMETRY_FRSKY_D
, D_RSSI_ID
, 0, 0, packet
[3], UNIT_RAW
, 0);
74 telemetryData
.rssi
.set(packet
[3]);
75 telemetryStreaming
= TELEMETRY_TIMEOUT10ms
; // reset counter only if valid packets are being detected
79 case USRPKT
: // User Data packet
80 uint8_t numBytes
= 3 + (packet
[1] & 0x07); // sanitize in case of data corruption leading to buffer overflow
81 for (uint8_t i
=3; i
<numBytes
; i
++) {
82 parseTelemHubByte(packet
[i
]);
91 const TelemetryUnit unit
;
95 const FrSkyDSensor frskyDSensors
[] = {
96 { D_RSSI_ID
, ZSTR_RSSI
, UNIT_RAW
, 0 },
97 { D_A1_ID
, ZSTR_A1
, UNIT_VOLTS
, 1 },
98 { D_A2_ID
, ZSTR_A2
, UNIT_VOLTS
, 1 },
99 { RPM_ID
, ZSTR_RPM
, UNIT_RPMS
, 0 },
100 { FUEL_ID
, ZSTR_FUEL
, UNIT_PERCENT
, 0 },
101 { TEMP1_ID
, ZSTR_TEMP1
, UNIT_CELSIUS
, 0 },
102 { TEMP2_ID
, ZSTR_TEMP2
, UNIT_CELSIUS
, 0 },
103 { CURRENT_ID
, ZSTR_CURR
, UNIT_AMPS
, 1 },
104 { ACCEL_X_ID
, ZSTR_ACCX
, UNIT_G
, 3 },
105 { ACCEL_Y_ID
, ZSTR_ACCY
, UNIT_G
, 3 },
106 { ACCEL_Z_ID
, ZSTR_ACCZ
, UNIT_G
, 3 },
107 { VARIO_ID
, ZSTR_VSPD
, UNIT_METERS_PER_SECOND
, 2 },
108 { VFAS_ID
, ZSTR_VFAS
, UNIT_VOLTS
, 2 },
109 { BARO_ALT_AP_ID
, ZSTR_ALT
, UNIT_METERS
, 1 }, // we map hi precision vario into PREC1!
110 { VOLTS_AP_ID
, ZSTR_VFAS
, UNIT_VOLTS
, 2 },
111 { GPS_SPEED_BP_ID
, ZSTR_GSPD
, UNIT_KTS
, 0 },
112 { GPS_COURS_BP_ID
, ZSTR_HDG
, UNIT_DEGREE
, 0 },
113 { VOLTS_ID
, ZSTR_CELLS
, UNIT_CELLS
, 2 },
114 { GPS_ALT_BP_ID
, ZSTR_GPSALT
, UNIT_METERS
, 0 },
115 { GPS_HOUR_MIN_ID
, ZSTR_GPSDATETIME
, UNIT_DATETIME
, 0 },
116 { GPS_LAT_AP_ID
, ZSTR_GPS
, UNIT_GPS
, 0 },
117 { 0, NULL
, UNIT_RAW
, 0 } // sentinel
120 const FrSkyDSensor
* getFrSkyDSensor(uint8_t id
)
122 const FrSkyDSensor
* result
= NULL
;
123 for (const FrSkyDSensor
* sensor
= frskyDSensors
; sensor
->id
; sensor
++) {
124 if (id
== sensor
->id
) {
133 uint16_t lastBPValue
= 0;
134 uint16_t lastAPValue
= 0;
136 int32_t getFrSkyDProtocolGPSValue(int32_t sign
)
138 div_t qr
= div(lastBPValue
, 100);
139 return sign
* (((uint32_t) (qr
.quot
) * 1000000) + (((uint32_t) (qr
.rem
) * 10000 + lastAPValue
) * 5) / 3);
142 void processHubPacket(uint8_t id
, int16_t value
)
144 TelemetryUnit unit
= UNIT_RAW
;
145 uint8_t precision
= 0;
146 int32_t data
= value
;
148 if (id
> FRSKY_LAST_ID
|| id
== GPS_SPEED_AP_ID
|| id
== GPS_ALT_AP_ID
|| id
== GPS_COURS_AP_ID
) {
152 if (id
== GPS_LAT_BP_ID
|| id
== GPS_LONG_BP_ID
|| id
== BARO_ALT_BP_ID
|| id
== VOLTS_BP_ID
) {
158 if (id
== GPS_LAT_AP_ID
) {
159 if (lastId
== GPS_LAT_BP_ID
) {
165 else if (id
== GPS_LONG_AP_ID
) {
166 if (lastId
== GPS_LONG_BP_ID
) {
172 else if (id
== GPS_LAT_NS_ID
) {
173 if (lastId
== GPS_LAT_AP_ID
) {
175 unit
= UNIT_GPS_LATITUDE
;
176 data
= getFrSkyDProtocolGPSValue(value
== 'N' ? 1 : -1);
182 else if (id
== GPS_LONG_EW_ID
) {
183 if (lastId
== GPS_LONG_AP_ID
) {
185 unit
= UNIT_GPS_LONGITUDE
;
186 data
= getFrSkyDProtocolGPSValue(value
== 'E' ? 1 : -1);
192 else if (id
== BARO_ALT_AP_ID
) {
193 if (lastId
== BARO_ALT_BP_ID
) {
194 if (data
> 9 || telemetryData
.varioHighPrecision
) {
195 telemetryData
.varioHighPrecision
= true;
196 data
/= 10; // map hi precision vario into low precision. Altitude is stored in 0.1m anyways
198 data
= (int16_t)lastBPValue
* 10 + (((int16_t)lastBPValue
< 0) ? -data
: data
);
206 else if (id
== VOLTS_AP_ID
) {
207 if (lastId
== VOLTS_BP_ID
) {
208 #if defined(FAS_PROTOTYPE)
209 data
= lastBPValue
* 100 + value
* 10;
211 data
= ((lastBPValue
* 100 + value
* 10) * 210) / 110;
220 else if (id
== VOLTS_ID
) {
222 uint32_t cellData
= (uint32_t)data
;
223 data
= ((cellData
& 0x00F0) << 12) + (((((cellData
& 0xFF00) >> 8) + ((cellData
& 0x000F) << 8))) / 5);
225 else if (id
== GPS_DAY_MONTH_ID
) {
226 id
= GPS_HOUR_MIN_ID
;
227 unit
= UNIT_DATETIME_DAY_MONTH
;
229 else if (id
== GPS_HOUR_MIN_ID
) {
230 unit
= UNIT_DATETIME_HOUR_MIN
;
232 else if (id
== GPS_SEC_ID
) {
233 id
= GPS_HOUR_MIN_ID
;
234 unit
= UNIT_DATETIME_SEC
;
236 else if (id
== GPS_YEAR_ID
) {
237 id
= GPS_HOUR_MIN_ID
;
238 unit
= UNIT_DATETIME_YEAR
;
241 const FrSkyDSensor
* sensor
= getFrSkyDSensor(id
);
244 precision
= sensor
->prec
;
250 else if (id
== VFAS_ID
) {
251 if (data
>= VFAS_D_HIPREC_OFFSET
) {
252 // incoming value has a resolution of 0.01V and added offset of VFAS_D_HIPREC_OFFSET
253 data
-= VFAS_D_HIPREC_OFFSET
;
256 // incoming value has a resolution of 0.1V
261 setTelemetryValue(PROTOCOL_TELEMETRY_FRSKY_D
, id
, 0, 0, data
, unit
, precision
);
264 void frskyDSetDefault(int index
, uint16_t id
)
266 TelemetrySensor
& telemetrySensor
= g_model
.telemetrySensors
[index
];
268 telemetrySensor
.id
= id
;
269 telemetrySensor
.instance
= 0;
271 const FrSkyDSensor
* sensor
= getFrSkyDSensor(id
);
273 TelemetryUnit unit
= sensor
->unit
;
274 uint8_t prec
= min
<uint8_t>(2, sensor
->prec
);
275 telemetrySensor
.init(sensor
->name
, unit
, prec
);
276 if (id
== D_RSSI_ID
) {
277 telemetrySensor
.filter
= 1;
278 telemetrySensor
.logs
= true;
280 else if (id
>= D_A1_ID
&& id
<= D_A2_ID
) {
281 telemetrySensor
.custom
.ratio
= 132;
282 telemetrySensor
.filter
= 1;
284 else if (id
== CURRENT_ID
) {
285 telemetrySensor
.onlyPositive
= 1;
287 else if (id
== BARO_ALT_AP_ID
) {
288 telemetrySensor
.autoOffset
= 1;
290 if (unit
== UNIT_RPMS
) {
291 telemetrySensor
.custom
.ratio
= 1;
292 telemetrySensor
.custom
.offset
= 1;
294 else if (unit
== UNIT_METERS
) {
295 if (IS_IMPERIAL_ENABLE()) {
296 telemetrySensor
.unit
= UNIT_FEET
;
301 telemetrySensor
.init(id
);
304 storageDirty(EE_MODEL
);