PX4 Firmware
PX4 Autopilot Software http://px4.io
sPort_data.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2013-2014 PX4 Development Team. All rights reserved.
4  * Author: Stefan Rado <px4@sradonia.net>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  * 3. Neither the name PX4 nor the names of its contributors may be
17  * used to endorse or promote products derived from this software
18  * without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  ****************************************************************************/
34 
35 /**
36  * @file sPort_data.c
37  * @author Stefan Rado <px4@sradonia.net>
38  * @author Mark Whitehorn <kd0aij@github.com>
39  *
40  * FrSky SmartPort telemetry implementation.
41  *
42  */
43 
44 #include "sPort_data.h"
45 #include "common.h"
46 
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include <math.h>
51 
52 #include <lib/ecl/geo/geo.h>
53 
54 #include <uORB/Subscription.hpp>
62 
63 #include <drivers/drv_hrt.h>
64 
65 #define frac(f) (f - (int)f)
66 
75 };
76 
78 
79 
80 /**
81  * Initializes the uORB subscriptions.
82  */
83 bool sPort_init()
84 {
85  s_port_subscription_data = new s_port_subscription_data_s();
86 
87  if (s_port_subscription_data == nullptr) {
88  return false;
89  }
90 
91  return true;
92 }
93 
95 {
96  if (s_port_subscription_data) {
98  s_port_subscription_data = nullptr;
99  }
100 }
101 
103 {
104  s_port_subscription_data->battery_status_sub.update();
105  s_port_subscription_data->sensor_combined_sub.update();
106  s_port_subscription_data->vehicle_air_data_sub.update();
107  s_port_subscription_data->vehicle_global_position_sub.update();
108  s_port_subscription_data->vehicle_gps_position_sub.update();
109  s_port_subscription_data->vehicle_local_position_sub.update();
110  s_port_subscription_data->vehicle_status_sub.update();
111 }
112 
113 static void update_crc(uint16_t *crc, unsigned char b)
114 {
115  *crc += b;
116  *crc += *crc >> 8;
117  *crc &= 0xFF;
118 }
119 
120 /**
121  * Sends one byte, performing byte-stuffing if necessary.
122  */
123 static void sPort_send_byte(int uart, uint8_t value)
124 {
125  const uint8_t x7E[] = { 0x7D, 0x5E };
126  const uint8_t x7D[] = { 0x7D, 0x5D };
127 
128  switch (value) {
129  case 0x7E:
130  write(uart, x7E, sizeof(x7E));
131  break;
132 
133  case 0x7D:
134  write(uart, x7D, sizeof(x7D));
135  break;
136 
137  default:
138  write(uart, &value, sizeof(value));
139  break;
140  }
141 }
142 
143 /**
144  * Sends one data id/value pair.
145  */
146 void sPort_send_data(int uart, uint16_t id, uint32_t data)
147 {
148  union {
149  uint32_t word;
150  uint8_t byte[4];
151  } buf;
152 
153  /* send start byte */
154  const uint8_t c = 0x10;
155  write(uart, &c, 1);
156 
157  /* init crc */
158  uint16_t crc = c;
159 
160  buf.word = id;
161 
162  for (int i = 0; i < 2; i++) {
163  update_crc(&crc, buf.byte[i]);
164  sPort_send_byte(uart, buf.byte[i]); /* LSB first */
165  }
166 
167  buf.word = data;
168 
169  for (int i = 0; i < 4; i++) {
170  update_crc(&crc, buf.byte[i]);
171  sPort_send_byte(uart, buf.byte[i]); /* LSB first */
172  }
173 
174  sPort_send_byte(uart, 0xFF - crc);
175 }
176 
177 
178 // scaling correct with OpenTX 2.1.7
179 void sPort_send_BATV(int uart)
180 {
181  /* send battery voltage as VFAS */
182  uint32_t voltage = (int)(100 * s_port_subscription_data->battery_status_sub.get().voltage_v);
183  sPort_send_data(uart, SMARTPORT_ID_VFAS, voltage);
184 }
185 
186 // verified scaling
187 void sPort_send_CUR(int uart)
188 {
189  /* send data */
190  uint32_t current = (int)(10 * s_port_subscription_data->battery_status_sub.get().current_a);
191  sPort_send_data(uart, SMARTPORT_ID_CURR, current);
192 }
193 
194 // verified scaling for "custom" altitude option
195 // OpenTX uses the initial reading as field elevation and displays
196 // the difference (altitude - field)
197 void sPort_send_ALT(int uart)
198 {
199  /* send data */
200  uint32_t alt = (int)(100 * s_port_subscription_data->vehicle_air_data_sub.get().baro_alt_meter);
201  sPort_send_data(uart, SMARTPORT_ID_ALT, alt);
202 }
203 
204 // verified scaling for "calculated" option
205 void sPort_send_SPD(int uart)
206 {
207  const vehicle_global_position_s &global_pos = s_port_subscription_data->vehicle_global_position_sub.get();
208 
209  /* send data for A2 */
210  float speed = sqrtf(global_pos.vel_n * global_pos.vel_n + global_pos.vel_e * global_pos.vel_e);
211  uint32_t ispeed = (int)(10 * speed);
212  sPort_send_data(uart, SMARTPORT_ID_GPS_SPD, ispeed);
213 }
214 
215 // TODO: verify scaling
216 void sPort_send_VSPD(int uart, float speed)
217 {
218  /* send data for VARIO vertical speed: int16 cm/sec */
219  int32_t ispeed = (int)(100 * speed);
220  sPort_send_data(uart, SMARTPORT_ID_VARIO, ispeed);
221 }
222 
223 // verified scaling
224 void sPort_send_FUEL(int uart)
225 {
226  /* send data */
227  uint32_t fuel = (int)(100 * s_port_subscription_data->battery_status_sub.get().remaining);
228  sPort_send_data(uart, SMARTPORT_ID_FUEL, fuel);
229 }
230 
231 void sPort_send_GPS_LON(int uart)
232 {
233  /* send longitude */
234  /* convert to 30 bit signed magnitude degrees*6E5 with MSb = 1 and bit 30=sign */
235  /* precision is approximately 0.1m */
236  uint32_t iLon = 6E-2 * fabs(s_port_subscription_data->vehicle_gps_position_sub.get().lon);
237 
238  iLon |= (1 << 31);
239 
240  if (s_port_subscription_data->vehicle_gps_position_sub.get().lon < 0) { iLon |= (1 << 30); }
241 
243 }
244 
245 void sPort_send_GPS_LAT(int uart)
246 {
247  /* send latitude */
248  /* convert to 30 bit signed magnitude degrees*6E5 with MSb = 0 and bit 30=sign */
249  uint32_t iLat = 6E-2 * fabs(s_port_subscription_data->vehicle_gps_position_sub.get().lat);
250 
251  if (s_port_subscription_data->vehicle_gps_position_sub.get().lat < 0) { iLat |= (1 << 30); }
252 
254 }
255 
256 void sPort_send_GPS_ALT(int uart)
257 {
258  /* send altitude */
259  uint32_t iAlt = s_port_subscription_data->vehicle_gps_position_sub.get().alt / 10;
261 }
262 
263 void sPort_send_GPS_CRS(int uart)
264 {
265  /* send course */
266 
267  /* convert to 30 bit signed magnitude degrees*6E5 with MSb = 1 and bit 30=sign */
268  int32_t iYaw = s_port_subscription_data->vehicle_local_position_sub.get().yaw * 18000.0f / M_PI_F;
269 
270  if (iYaw < 0) { iYaw += 36000; }
271 
273 }
274 
275 void sPort_send_GPS_TIME(int uart)
276 {
277  static int date = 0;
278 
279  /* send formatted frame */
280  time_t time_gps = s_port_subscription_data->vehicle_gps_position_sub.get().time_utc_usec / 1000000ULL;
281  struct tm *tm_gps = gmtime(&time_gps);
282 
283  if (date) {
284 
286  (uint32_t) 0xff | (tm_gps->tm_mday << 8) | ((tm_gps->tm_mon + 1) << 16) | ((tm_gps->tm_year - 100) << 24));
287  date = 0;
288 
289  } else {
290 
292  (uint32_t) 0x00 | (tm_gps->tm_sec << 8) | (tm_gps->tm_min << 16) | (tm_gps->tm_hour << 24));
293  date = 1;
294 
295  }
296 }
297 
298 void sPort_send_GPS_SPD(int uart)
299 {
300  const vehicle_global_position_s &global_pos = s_port_subscription_data->vehicle_global_position_sub.get();
301 
302  /* send 100 * knots */
303  float speed = sqrtf(global_pos.vel_n * global_pos.vel_n + global_pos.vel_e * global_pos.vel_e);
304  uint32_t ispeed = (int)(1944 * speed);
305  sPort_send_data(uart, SMARTPORT_ID_GPS_SPD, ispeed);
306 }
307 
308 /*
309  * Sends nav_state + 128
310  */
311 void sPort_send_NAV_STATE(int uart)
312 {
313  uint32_t navstate = (int)(128 + s_port_subscription_data->vehicle_status_sub.get().nav_state);
314 
315  /* send data */
317 }
318 
319 // verified scaling
320 // sends number of sats and type of gps fix
321 void sPort_send_GPS_FIX(int uart)
322 {
323  /* send data */
324  uint32_t satcount = (int)(s_port_subscription_data->vehicle_gps_position_sub.get().satellites_used);
325  uint32_t fixtype = (int)(s_port_subscription_data->vehicle_gps_position_sub.get().fix_type);
326  uint32_t t2 = satcount * 10 + fixtype;
328 }
329 
331 {
332  int16_t telem_flight_mode = get_telemetry_flight_mode(s_port_subscription_data->vehicle_status_sub.get().nav_state);
333 
334  sPort_send_data(uart, FRSKY_ID_TEMP1, telem_flight_mode); // send flight mode as TEMP1. This matches with OpenTX & APM
335 }
336 
337 void sPort_send_GPS_info(int uart)
338 {
339  const vehicle_gps_position_s &gps = s_port_subscription_data->vehicle_gps_position_sub.get();
341 }
#define SMARTPORT_ID_ALT
Definition: sPort_data.h: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 s_port_subscription_data_s * s_port_subscription_data
Definition: sPort_data.cpp:77
void sPort_deinit()
Definition: sPort_data.cpp:94
void sPort_send_GPS_ALT(int uart)
Definition: sPort_data.cpp:256
Definition of geo / math functions to perform geodesic calculations.
#define SMARTPORT_ID_FUEL
Definition: sPort_data.h:68
uORB::SubscriptionData< vehicle_global_position_s > vehicle_global_position_sub
Definition: sPort_data.cpp:71
void sPort_send_GPS_TIME(int uart)
Definition: sPort_data.cpp:275
void sPort_send_SPD(int uart)
Definition: sPort_data.cpp:205
void sPort_send_ALT(int uart)
Definition: sPort_data.cpp:197
void sPort_send_FUEL(int uart)
Definition: sPort_data.cpp:224
High-resolution timer with callouts and timekeeping.
#define SMARTPORT_ID_GPS_LON_LAT
Definition: sPort_data.h:77
uORB::SubscriptionData< battery_status_s > battery_status_sub
Definition: sPort_data.cpp:68
#define SMARTPORT_ID_GPS_SPD
Definition: sPort_data.h:79
#define SMARTPORT_ID_GPS_ALT
Definition: sPort_data.h:78
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
Definition: uORB.h:87
#define SMARTPORT_ID_VARIO
Definition: sPort_data.h:70
uORB::SubscriptionData< vehicle_air_data_s > vehicle_air_data_sub
Definition: sPort_data.cpp:70
#define FRSKY_ID_TEMP1
Definition: common.h:46
static void update_crc(uint16_t *crc, unsigned char b)
Definition: sPort_data.cpp:113
#define SMARTPORT_ID_VFAS
Definition: sPort_data.h:75
#define SMARTPORT_ID_DIY_NAVSTATE
Definition: sPort_data.h:84
uORB::SubscriptionData< sensor_combined_s > sensor_combined_sub
Definition: sPort_data.cpp:69
uint8_t * data
Definition: dataman.cpp:149
void sPort_send_data(int uart, uint16_t id, uint32_t data)
Sends one data id/value pair.
Definition: sPort_data.cpp:146
void sPort_send_VSPD(int uart, float speed)
Definition: sPort_data.cpp:216
uORB::SubscriptionData< vehicle_status_s > vehicle_status_sub
Definition: sPort_data.cpp:74
void sPort_update_topics()
Definition: sPort_data.cpp:102
void sPort_send_NAV_STATE(int uart)
Definition: sPort_data.cpp:311
const T & get() const
void sPort_send_GPS_info(int uart)
Definition: sPort_data.cpp:337
static void write(bootloader_app_shared_t *pshared)
#define FRSKY_ID_TEMP2
Definition: common.h:49
#define SMARTPORT_ID_GPS_CRS
Definition: sPort_data.h:80
void sPort_send_flight_mode(int uart)
Definition: sPort_data.cpp:330
t2
Definition: calcH_YAW312.c:3
void sPort_send_GPS_CRS(int uart)
Definition: sPort_data.cpp:263
void sPort_send_GPS_LON(int uart)
Definition: sPort_data.cpp:231
void sPort_send_GPS_FIX(int uart)
Definition: sPort_data.cpp:321
void sPort_send_CUR(int uart)
Definition: sPort_data.cpp:187
#define SMARTPORT_ID_CURR
Definition: sPort_data.h:74
void sPort_send_GPS_SPD(int uart)
Definition: sPort_data.cpp:298
void sPort_send_BATV(int uart)
Definition: sPort_data.cpp:179
void sPort_send_GPS_LAT(int uart)
Definition: sPort_data.cpp:245
#define M_PI_F
Definition: ashtech.cpp:44
uORB::SubscriptionData< vehicle_local_position_s > vehicle_local_position_sub
Definition: sPort_data.cpp:73
#define SMARTPORT_ID_DIY_GPSFIX
Definition: sPort_data.h:85
bool sPort_init()
Initializes the uORB subscriptions.
Definition: sPort_data.cpp:83
#define SMARTPORT_ID_GPS_TIME
Definition: sPort_data.h:81
static void sPort_send_byte(int uart, uint8_t value)
Sends one byte, performing byte-stuffing if necessary.
Definition: sPort_data.cpp:123
uORB::SubscriptionData< vehicle_gps_position_s > vehicle_gps_position_sub
Definition: sPort_data.cpp:72