PX4 Firmware
PX4 Autopilot Software http://px4.io
frsky_data.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2013-2017 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 /**
35  * @file frsky_data.c
36  *
37  * @author Stefan Rado <px4@sradonia.net>
38  *
39  * FrSky telemetry implementation.
40  *
41  */
42 
43 #include "frsky_data.h"
44 #include "common.h"
45 
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <string.h>
49 #include <stdbool.h>
50 #include <lib/ecl/geo/geo.h>
51 #include <stdbool.h>
52 #include <math.h>
53 
54 #include <uORB/Subscription.hpp>
61 
62 #include <drivers/drv_hrt.h>
63 
64 #define frac(f) (f - (int)f)
65 
67 
74 };
75 
77 
78 /**
79  * Initializes the uORB subscriptions.
80  */
81 bool frsky_init()
82 {
83  subscription_data = new frsky_subscription_data_s();
84 
85  if (!subscription_data) {
86  return false;
87  }
88 
89  return true;
90 }
91 
93 {
94  if (subscription_data) {
95  delete subscription_data;
96  subscription_data = nullptr;
97  }
98 }
99 
100 /**
101  * Sends a 0x5E start/stop byte.
102  */
103 static void frsky_send_startstop(int uart)
104 {
105  static const uint8_t c = 0x5E;
106  write(uart, &c, sizeof(c));
107 }
108 
109 /**
110  * Sends one byte, performing byte-stuffing if necessary.
111  */
112 static void frsky_send_byte(int uart, uint8_t value)
113 {
114  const uint8_t x5E[] = { 0x5D, 0x3E };
115  const uint8_t x5D[] = { 0x5D, 0x3D };
116 
117  switch (value) {
118  case 0x5E:
119  write(uart, x5E, sizeof(x5E));
120  break;
121 
122  case 0x5D:
123  write(uart, x5D, sizeof(x5D));
124  break;
125 
126  default:
127  write(uart, &value, sizeof(value));
128  break;
129  }
130 }
131 
132 /**
133  * Sends one data id/value pair.
134  */
135 static void frsky_send_data(int uart, uint8_t id, int16_t data)
136 {
137  /* Cast data to unsigned, because signed shift might behave incorrectly */
138  uint16_t udata = data;
139 
140  frsky_send_startstop(uart);
141 
142  frsky_send_byte(uart, id);
143  frsky_send_byte(uart, udata); /* LSB */
144  frsky_send_byte(uart, udata >> 8); /* MSB */
145 }
146 
148 {
149  subscription_data->battery_status_sub.update();
150  subscription_data->sensor_combined_sub.update();
151  subscription_data->vehicle_air_data_sub.update();
152  subscription_data->vehicle_global_position_sub.update();
153  subscription_data->vehicle_gps_position_sub.update();
154  subscription_data->vehicle_status_sub.update();
155 }
156 
157 /**
158  * Sends frame 1 (every 200ms):
159  * acceleration values, barometer altitude, temperature, battery voltage & current
160  */
161 void frsky_send_frame1(int uart)
162 {
163  /* send formatted frame */
164  const sensor_combined_s &sensor_combined = subscription_data->sensor_combined_sub.get();
165  frsky_send_data(uart, FRSKY_ID_ACCEL_X, roundf(sensor_combined.accelerometer_m_s2[0] * 1000.0f));
166  frsky_send_data(uart, FRSKY_ID_ACCEL_Y, roundf(sensor_combined.accelerometer_m_s2[1] * 1000.0f));
167  frsky_send_data(uart, FRSKY_ID_ACCEL_Z, roundf(sensor_combined.accelerometer_m_s2[2] * 1000.0f));
168 
169  const vehicle_air_data_s &air_data = subscription_data->vehicle_air_data_sub.get();
171  frsky_send_data(uart, FRSKY_ID_BARO_ALT_AP, roundf(frac(air_data.baro_alt_meter) * 100.0f));
172 
173  const battery_status_s &bat = subscription_data->battery_status_sub.get();
174  frsky_send_data(uart, FRSKY_ID_VFAS, roundf(bat.voltage_v * 10.0f));
175  frsky_send_data(uart, FRSKY_ID_CURRENT, (bat.current_a < 0) ? 0 : roundf(bat.current_a * 10.0f));
176 
177  int16_t telem_flight_mode = get_telemetry_flight_mode(subscription_data->vehicle_status_sub.get().nav_state);
178  frsky_send_data(uart, FRSKY_ID_TEMP1, telem_flight_mode); // send flight mode as TEMP1. This matches with OpenTX & APM
179 
180  const vehicle_gps_position_s &gps = subscription_data->vehicle_gps_position_sub.get();
182 
183  frsky_send_startstop(uart);
184 }
185 
186 /**
187  * Formats the decimal latitude/longitude to the required degrees/minutes.
188  */
189 static float frsky_format_gps(float dec)
190 {
191  float dm_deg = (int) dec;
192  return (dm_deg * 100.0f) + (dec - dm_deg) * 60;
193 }
194 
195 /**
196  * Sends frame 2 (every 1000ms):
197  * GPS course, latitude, longitude, ground speed, GPS altitude, remaining battery level
198  */
199 void frsky_send_frame2(int uart)
200 {
201  const vehicle_global_position_s &gpos = subscription_data->vehicle_global_position_sub.get();
202  const battery_status_s &battery_status = subscription_data->battery_status_sub.get();
203  const vehicle_gps_position_s &gps = subscription_data->vehicle_gps_position_sub.get();
204 
205  /* send formatted frame */
206  float course = 0, lat = 0, lon = 0, speed = 0, alt = 0;
207  char lat_ns = 0, lon_ew = 0;
208  int sec = 0;
209 
210  if (gpos.timestamp != 0 && hrt_absolute_time() < gpos.timestamp + 20000) {
211  course = gpos.yaw / M_PI_F * 180.0f;
212 
213  if (course < 0.f) { // course is in range [0, 360], 0=north, CW
214  course += 360.f;
215  }
216 
217  lat = frsky_format_gps(fabsf(gpos.lat));
218  lat_ns = (gpos.lat < 0) ? 'S' : 'N';
219  lon = frsky_format_gps(fabsf(gpos.lon));
220  lon_ew = (gpos.lon < 0) ? 'W' : 'E';
221  speed = sqrtf(gpos.vel_n * gpos.vel_n + gpos.vel_e * gpos.vel_e)
222  * 25.0f / 46.0f;
223  alt = gpos.alt;
224  }
225 
226  if (gps.timestamp != 0 && hrt_absolute_time() < gps.timestamp + 20000) {
227  time_t time_gps = gps.time_utc_usec / 1000000ULL;
228  struct tm *tm_gps = gmtime(&time_gps);
229 
230  sec = tm_gps->tm_sec;
231  }
232 
233  frsky_send_data(uart, FRSKY_ID_GPS_COURS_BP, course);
234  frsky_send_data(uart, FRSKY_ID_GPS_COURS_AP, frac(course) * 1000.0f);
235 
237  frsky_send_data(uart, FRSKY_ID_GPS_LAT_AP, frac(lat) * 10000.0f);
238  frsky_send_data(uart, FRSKY_ID_GPS_LAT_NS, lat_ns);
239 
241  frsky_send_data(uart, FRSKY_ID_GPS_LONG_AP, frac(lon) * 10000.0f);
242  frsky_send_data(uart, FRSKY_ID_GPS_LONG_EW, lon_ew);
243 
245  frsky_send_data(uart, FRSKY_ID_GPS_SPEED_AP, frac(speed) * 100.0f);
246 
248  frsky_send_data(uart, FRSKY_ID_GPS_ALT_AP, frac(alt) * 100.0f);
249 
250  frsky_send_data(uart, FRSKY_ID_FUEL, roundf(battery_status.remaining * 100.0f));
251 
252  frsky_send_data(uart, FRSKY_ID_GPS_SEC, sec);
253 
254  frsky_send_startstop(uart);
255 }
256 
257 /**
258  * Sends frame 3 (every 5000ms):
259  * GPS date & time
260  */
261 void frsky_send_frame3(int uart)
262 {
263  /* send formatted frame */
264  time_t time_gps = subscription_data->vehicle_gps_position_sub.get().time_utc_usec / 1000000ULL;
265 
266  struct tm *tm_gps = gmtime(&time_gps);
267  uint16_t hour_min = (tm_gps->tm_min << 8) | (tm_gps->tm_hour & 0xff);
268  frsky_send_data(uart, FRSKY_ID_GPS_DAY_MONTH, tm_gps->tm_mday);
269  frsky_send_data(uart, FRSKY_ID_GPS_YEAR, tm_gps->tm_year);
270  frsky_send_data(uart, FRSKY_ID_GPS_HOUR_MIN, hour_min);
271  frsky_send_data(uart, FRSKY_ID_GPS_SEC, tm_gps->tm_sec);
272 
273  frsky_send_startstop(uart);
274 }
275 
276 /* parse 11 byte frames */
277 bool frsky_parse_host(uint8_t *sbuf, int nbytes, struct adc_linkquality *v)
278 {
279  bool data_ready = false;
280  static int dcount = 0;
281  static uint8_t type = 0;
282  static uint8_t data[11];
283  static enum {
284  HEADER = 0,
285  TYPE,
286  DATA,
287  TRAILER
288  } state = HEADER;
289 
290  for (int i = 0; i < nbytes; i++) {
291  switch (state) {
292  case HEADER:
293  if (sbuf[i] == 0x7E) {
294  state = TYPE;
295  }
296 
297  break;
298 
299  case TYPE:
300  if (sbuf[i] != 0x7E) {
301  state = DATA;
302  type = sbuf[i];
303  dcount = 0;
304  }
305 
306  break;
307 
308  case DATA:
309 
310  /* read 8 data bytes */
311  if (dcount < 7) {
312  data[dcount++] = sbuf[i];
313 
314  } else {
315  /* received all data bytes */
316  state = TRAILER;
317  }
318 
319  break;
320 
321  case TRAILER:
322  state = HEADER;
323 
324  if (sbuf[i] != 0x7E) {
325 // warnx("host packet error: %x", sbuf[i]);
326 
327  } else {
328  data_ready = true;
329 
330  if (type == 0xFE) {
331  /* this is an adc_linkquality packet */
332  v->ad1 = data[0];
333  v->ad2 = data[1];
334  v->linkq = data[2];
335  }
336  }
337 
338  break;
339  }
340  }
341 
342  return data_ready;
343 }
bool frsky_parse_host(uint8_t *sbuf, int nbytes, struct adc_linkquality *v)
Definition: frsky_data.cpp:277
uORB::SubscriptionData< sensor_combined_s > sensor_combined_sub
Definition: frsky_data.cpp:69
uint16_t get_telemetry_flight_mode(int px4_flight_mode)
Map the PX4 flight mode (vehicle_status_s::nav_state) to the telemetry flight mode.
static struct frsky_subscription_data_s * subscription_data
Definition: frsky_data.cpp:76
static enum @74 state
Definition of geo / math functions to perform geodesic calculations.
#define FRSKY_ID_GPS_SEC
Definition: common.h:60
uORB::SubscriptionData< battery_status_s > battery_status_sub
Definition: frsky_data.cpp:68
static void frsky_send_byte(int uart, uint8_t value)
Sends one byte, performing byte-stuffing if necessary.
Definition: frsky_data.cpp:112
void frsky_send_frame3(int uart)
Sends frame 3 (every 5000ms): GPS date & time.
Definition: frsky_data.cpp:261
uORB::SubscriptionData< vehicle_gps_position_s > vehicle_gps_position_sub
Definition: frsky_data.cpp:72
float accelerometer_m_s2[3]
uORB::SubscriptionData< vehicle_status_s > vehicle_status_sub
Definition: frsky_data.cpp:73
High-resolution timer with callouts and timekeeping.
void frsky_update_topics()
Definition: frsky_data.cpp:147
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
Definition: uORB.h:87
uORB::SubscriptionData< vehicle_global_position_s > vehicle_global_position_sub
Definition: frsky_data.cpp:71
#define FRSKY_ID_GPS_LONG_EW
Definition: common.h:66
#define FRSKY_ID_GPS_ALT_BP
Definition: common.h:45
static void frsky_send_data(int uart, uint8_t id, int16_t data)
Sends one data id/value pair.
Definition: frsky_data.cpp:135
#define FRSKY_ID_ACCEL_X
Definition: common.h:68
#define FRSKY_ID_TEMP1
Definition: common.h:46
#define FRSKY_ID_GPS_ALT_AP
Definition: common.h:51
#define FRSKY_ID_GPS_SPEED_AP
Definition: common.h:61
bool frsky_init()
Initializes the uORB subscriptions.
Definition: frsky_data.cpp:81
uint8_t * data
Definition: dataman.cpp:149
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
#define FRSKY_ID_VFAS
Definition: common.h:73
#define FRSKY_ID_GPS_COURS_AP
Definition: common.h:64
static float frsky_format_gps(float dec)
Formats the decimal latitude/longitude to the required degrees/minutes.
Definition: frsky_data.cpp:189
const T & get() const
#define FRSKY_ID_CURRENT
Definition: common.h:71
#define FRSKY_ID_GPS_LAT_AP
Definition: common.h:63
#define FRSKY_ID_ACCEL_Y
Definition: common.h:69
#define FRSKY_ID_GPS_DAY_MONTH
Definition: common.h:57
#define FRSKY_ID_GPS_HOUR_MIN
Definition: common.h:59
static void write(bootloader_app_shared_t *pshared)
#define FRSKY_ID_TEMP2
Definition: common.h:49
void frsky_send_frame1(int uart)
Sends frame 1 (every 200ms): acceleration values, barometer altitude, temperature, battery voltage & current.
Definition: frsky_data.cpp:161
#define FRSKY_ID_BARO_ALT_AP
Definition: common.h:65
#define FRSKY_ID_GPS_LONG_BP
Definition: common.h:54
#define FRSKY_ID_ACCEL_Z
Definition: common.h:70
#define FRSKY_ID_GPS_COURS_BP
Definition: common.h:56
#define FRSKY_ID_GPS_YEAR
Definition: common.h:58
#define FRSKY_ID_BARO_ALT_BP
Definition: common.h:52
static void frsky_send_startstop(int uart)
Sends a 0x5E start/stop byte.
Definition: frsky_data.cpp:103
#define M_PI_F
Definition: ashtech.cpp:44
#define FRSKY_ID_GPS_LAT_BP
Definition: common.h:55
#define FRSKY_ID_GPS_SPEED_BP
Definition: common.h:53
void frsky_deinit()
Definition: frsky_data.cpp:92
#define frac(f)
Definition: frsky_data.cpp:64
void frsky_send_frame2(int uart)
Sends frame 2 (every 1000ms): GPS course, latitude, longitude, ground speed, GPS altitude, remaining battery level.
Definition: frsky_data.cpp:199
#define FRSKY_ID_GPS_LONG_AP
Definition: common.h:62
#define FRSKY_ID_FUEL
Definition: common.h:48
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
uint8_t linkq
Definition: frsky_data.h:58
#define FRSKY_ID_GPS_LAT_NS
Definition: common.h:67
uORB::SubscriptionData< vehicle_air_data_s > vehicle_air_data_sub
Definition: frsky_data.cpp:70