Paparazzi UAS  v5.8.2_stable-0-g6260b7c
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
gps_mtk.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2011 The Paparazzi Team
3  *
4  * This file is part of paparazzi.
5  *
6  * paparazzi is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * paparazzi is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with paparazzi; see the file COPYING. If not, write to
18  * the Free Software Foundation, 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 
34 #include "subsystems/gps.h"
35 #include "subsystems/abi.h"
36 #include "led.h"
37 
38 /* currently needed to get nav_utm_zone0 */
41 
42 #include "mcu_periph/sys_time.h"
43 
44 #define MTK_DIY_OUTPUT_RATE MTK_DIY_OUTPUT_4HZ
45 #define OUTPUT_RATE 4
46 
47 /* parser status */
48 #define UNINIT 0
49 #define GOT_SYNC1_14 1
50 #define GOT_SYNC2_14 2
51 #define GOT_CLASS_14 3
52 #define GOT_SYNC1_16 4
53 #define GOT_SYNC2_16 5
54 #define GOT_ID 6
55 #define GOT_PAYLOAD 7
56 #define GOT_CHECKSUM1 8
57 
58 /* last error type */
59 #define GPS_MTK_ERR_NONE 0
60 #define GPS_MTK_ERR_OVERRUN 1
61 #define GPS_MTK_ERR_MSG_TOO_LONG 2
62 #define GPS_MTK_ERR_CHECKSUM 3
63 #define GPS_MTK_ERR_UNEXPECTED 4
64 #define GPS_MTK_ERR_OUT_OF_SYNC 5
65 
66 /* mediatek gps fix mask */
67 #define MTK_DIY_FIX_3D 3
68 #define MTK_DIY_FIX_2D 2
69 #define MTK_DIY_FIX_NONE 1
70 
71 
72 /* defines for UTC-GPS time conversion */
73 #define SECS_MINUTE (60)
74 #define SECS_HOUR (60*60)
75 #define SECS_DAY (60*60*24)
76 #define SECS_WEEK (60*60*24*7)
77 
78 #define isleap(x) ((((x)%400)==0) || (!(((x)%100)==0) && (((x)%4)==0)))
79 
80 const int8_t DAYS_MONTH[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
81 
82 struct GpsMtk gps_mtk;
83 
84 #ifdef GPS_CONFIGURE
85 #define MTK_DIY_SET_BINARY "$PGCMD,16,0,0,0,0,0*6A\r\n"
86 #define MTK_DIY_SET_NMEA "$PGCMD,16,1,1,1,1,1*6B\r\n"
87 
88 #define MTK_DIY_OUTPUT_1HZ "$PMTK220,1000*1F\r\n"
89 #define MTK_DIY_OUTPUT_2HZ "$PMTK220,500*2B\r\n"
90 #define MTK_DIY_OUTPUT_4HZ "$PMTK220,250*29\r\n"
91 #define MTK_DIY_OTUPUT_5HZ "$PMTK220,200*2C\r\n"
92 #define MTK_DIY_OUTPUT_10HZ "$PMTK220,100*2F\r\n"
93 
94 #define MTK_BAUD_RATE_38400 "$PMTK251,38400*27\r\n"
95 
96 #define MTK_DIY_SBAS_ON "$PMTK313,1*2E\r\n"
97 #define MTK_DIY_SBAS_OFF "$PMTK313,0*2F\r\n"
98 
99 #define MTK_DIY_WAAS_ON "$PSRF151,1*3F\r\n"
100 #define MTK_DIY_WAAS_OFF "$PSRF151,0*3E\r\n"
101 
102 bool_t gps_configuring;
103 static uint8_t gps_status_config;
104 #endif
105 
106 void gps_impl_init(void)
107 {
110  gps_mtk.error_cnt = 0;
112 #ifdef GPS_CONFIGURE
113  gps_status_config = 0;
114  gps_configuring = TRUE;
115 #endif
116 }
117 
118 void gps_mtk_msg(void)
119 {
120  // current timestamp
121  uint32_t now_ts = get_sys_time_usec();
122 
126  if (gps_mtk.msg_class == MTK_DIY14_ID &&
127  gps_mtk.msg_id == MTK_DIY14_NAV_ID) {
128  if (gps.fix == GPS_FIX_3D) {
131  }
132  AbiSendMsgGPS(GPS_MTK_ID, now_ts, &gps);
133  }
134  if (gps_mtk.msg_class == MTK_DIY16_ID &&
135  gps_mtk.msg_id == MTK_DIY16_NAV_ID) {
136  if (gps.fix == GPS_FIX_3D) {
139  }
140  AbiSendMsgGPS(GPS_MTK_ID, now_ts, &gps);
141  }
143 }
144 
145 static void gps_mtk_time2itow(uint32_t gps_date, uint32_t gps_time,
146  int16_t *gps_week, uint32_t *gps_itow)
147 {
148  /* convert UTC date/time to GPS week/itow, we have no idea about GPS
149  leap seconds for now */
150  uint16_t gps_msecond = gps_time % 1000;
151  uint8_t gps_second = (gps_time / 1000) % 100;
152  uint8_t gps_minute = (gps_time / 100000) % 100;
153  uint8_t gps_hour = (gps_time / 10000000) % 100;
154  uint16_t gps_year = 2000 + (gps_date % 100);
155  uint8_t gps_month = (gps_date / 100) % 100;
156  uint8_t gps_day = (gps_date / 10000) % 100;
157  int32_t i, days;
158 
159  *gps_week = 0;
160  *gps_itow = 0;
161 
162  /* sanity checks */
163  if (gps_month > 12) { return; }
164  if (gps_day > (DAYS_MONTH[gps_month] +
165  ((gps_month == 1) ? isleap(gps_year) : 0))) { return; }
166  if (gps_hour > 23) { return; }
167  if (gps_minute > 59) { return; }
168  if (gps_second > 59) { return; }
169 
170  /* days since 6-JAN-1980 */
171  days = -6;
172  for (i = 1980; i < gps_year; i++) { days += (365 + isleap(i)); }
173 
174  /* add days in gps_year */
175  for (i = 0; i < gps_month - 1; i++) {
176  days += DAYS_MONTH[i] + ((i == 1) ? isleap(gps_year) : 0);
177  }
178  days += gps_day;
179 
180  /* convert */
181  *gps_week = (uint16_t)(days / 7);
182  *gps_itow = ((days % 7) * SECS_DAY +
183  gps_hour * SECS_HOUR +
184  gps_minute * SECS_MINUTE +
185  gps_second) * 1000 +
186  gps_msecond;
187 }
188 
190 {
191  if (gps_mtk.msg_class == MTK_DIY14_ID) {
192  if (gps_mtk.msg_id == MTK_DIY14_NAV_ID) {
193  /* get hardware clock ticks */
195  gps_time_sync.t0_tow = MTK_DIY14_NAV_ITOW(gps_mtk.msg_buf);
197  gps.lla_pos.lat = MTK_DIY14_NAV_LAT(gps_mtk.msg_buf) * 10;
198  gps.lla_pos.lon = MTK_DIY14_NAV_LON(gps_mtk.msg_buf) * 10;
199  // FIXME: with MTK you do not receive vertical speed
200  if (sys_time.nb_sec - gps.last_3dfix_time < 2) {
201  gps.ned_vel.z = ((gps.hmsl -
202  MTK_DIY14_NAV_HEIGHT(gps_mtk.msg_buf) * 10) * OUTPUT_RATE) / 10;
203  } else { gps.ned_vel.z = 0; }
204  gps.hmsl = MTK_DIY14_NAV_HEIGHT(gps_mtk.msg_buf) * 10;
205  // FIXME: with MTK you do not receive ellipsoid altitude
206  gps.lla_pos.alt = gps.hmsl;
207  gps.gspeed = MTK_DIY14_NAV_GSpeed(gps_mtk.msg_buf);
208  // FIXME: with MTK you do not receive speed 3D
210  gps.course = (RadOfDeg(MTK_DIY14_NAV_Heading(gps_mtk.msg_buf))) * 10;
211  gps.num_sv = MTK_DIY14_NAV_numSV(gps_mtk.msg_buf);
212  switch (MTK_DIY14_NAV_GPSfix(gps_mtk.msg_buf)) {
213  case MTK_DIY_FIX_3D:
214  gps.fix = GPS_FIX_3D;
215  break;
216  case MTK_DIY_FIX_2D:
217  gps.fix = GPS_FIX_2D;
218  break;
219  default:
220  gps.fix = GPS_FIX_NONE;
221  }
222  gps.tow = MTK_DIY14_NAV_ITOW(gps_mtk.msg_buf);;
223  // FIXME: with MTK DIY 1.4 you do not receive GPS week
224  gps.week = 0;
225  /* Computes from (lat, long) in the referenced UTM zone */
226  struct LlaCoor_f lla_f;
227  LLA_FLOAT_OF_BFP(lla_f, gps.lla_pos);
228  struct UtmCoor_f utm_f;
229  utm_f.zone = nav_utm_zone0;
230  /* convert to utm */
231  utm_of_lla_f(&utm_f, &lla_f);
232  /* copy results of utm conversion */
233  gps.utm_pos.east = utm_f.east * 100;
234  gps.utm_pos.north = utm_f.north * 100;
237 #ifdef GPS_LED
238  if (gps.fix == GPS_FIX_3D) {
239  LED_ON(GPS_LED);
240  } else {
241  LED_TOGGLE(GPS_LED);
242  }
243 #endif
244  }
245  }
246 
247  if (gps_mtk.msg_class == MTK_DIY16_ID) {
248  if (gps_mtk.msg_id == MTK_DIY16_NAV_ID) {
249  uint32_t gps_date, gps_time;
250  gps_date = MTK_DIY16_NAV_UTC_DATE(gps_mtk.msg_buf);
251  gps_time = MTK_DIY16_NAV_UTC_TIME(gps_mtk.msg_buf);
252  gps_mtk_time2itow(gps_date, gps_time, &gps.week, &gps.tow);
253 #ifdef GPS_TIMESTAMP
254  /* get hardware clock ticks */
256  gps.t0_tow = gps.tow;
257  gps.t0_tow_frac = 0;
258 #endif
259  gps.lla_pos.lat = MTK_DIY16_NAV_LAT(gps_mtk.msg_buf) * 10;
260  gps.lla_pos.lon = MTK_DIY16_NAV_LON(gps_mtk.msg_buf) * 10;
261  // FIXME: with MTK you do not receive vertical speed
262  if (sys_time.nb_sec - gps.last_3dfix_time < 2) {
263  gps.ned_vel.z = ((gps.hmsl -
264  MTK_DIY16_NAV_HEIGHT(gps_mtk.msg_buf) * 10) * OUTPUT_RATE) / 10;
265  } else { gps.ned_vel.z = 0; }
266  gps.hmsl = MTK_DIY16_NAV_HEIGHT(gps_mtk.msg_buf) * 10;
267  // FIXME: with MTK you do not receive ellipsoid altitude
268  gps.lla_pos.alt = gps.hmsl;
269  gps.gspeed = MTK_DIY16_NAV_GSpeed(gps_mtk.msg_buf);
270  // FIXME: with MTK you do not receive speed 3D
272  gps.course = (RadOfDeg(MTK_DIY16_NAV_Heading(gps_mtk.msg_buf) * 10000)) * 10;
273  gps.num_sv = MTK_DIY16_NAV_numSV(gps_mtk.msg_buf);
274  switch (MTK_DIY16_NAV_GPSfix(gps_mtk.msg_buf)) {
275  case MTK_DIY_FIX_3D:
276  gps.fix = GPS_FIX_3D;
277  break;
278  case MTK_DIY_FIX_2D:
279  gps.fix = GPS_FIX_2D;
280  break;
281  default:
282  gps.fix = GPS_FIX_NONE;
283  }
284  /* HDOP? */
285  /* Computes from (lat, long) in the referenced UTM zone */
286  struct LlaCoor_f lla_f;
287  LLA_FLOAT_OF_BFP(lla_f, gps.lla_pos);
288  struct UtmCoor_f utm_f;
289  utm_f.zone = nav_utm_zone0;
290  /* convert to utm */
291  utm_of_lla_f(&utm_f, &lla_f);
292  /* copy results of utm conversion */
293  gps.utm_pos.east = utm_f.east * 100;
294  gps.utm_pos.north = utm_f.north * 100;
297 #ifdef GPS_LED
298  if (gps.fix == GPS_FIX_3D) {
299  LED_ON(GPS_LED);
300  } else {
301  LED_TOGGLE(GPS_LED);
302  }
303 #endif
304  }
305  }
306 }
307 
308 /* byte parsing */
310 {
311  if (gps_mtk.status < GOT_PAYLOAD) {
312  gps_mtk.ck_a += c;
314  }
315  switch (gps_mtk.status) {
316  case UNINIT:
317  if (c == MTK_DIY14_SYNC1) {
319  }
320  if (c == MTK_DIY16_ID) {
321  gps_mtk.msg_class = c;
322  }
324  break;
325  /* MTK_DIY_VER_14 */
326  case GOT_SYNC1_14:
327  if (c != MTK_DIY14_SYNC2) {
329  goto error;
330  }
331  if (gps_mtk.msg_available) {
332  /* Previous message has not yet been parsed: discard this one */
334  goto error;
335  }
336  gps_mtk.ck_a = 0;
337  gps_mtk.ck_b = 0;
338  gps_mtk.status++;
339  gps_mtk.len = MTK_DIY14_NAV_LENGTH;
340  break;
341  case GOT_SYNC2_14:
342  if (c != MTK_DIY14_ID) {
344  goto error;
345  }
346  gps_mtk.msg_class = c;
347  gps_mtk.msg_idx = 0;
348  gps_mtk.status++;
349  break;
350  case GOT_CLASS_14:
351  if (c != MTK_DIY14_NAV_ID) {
353  goto error;
354  }
355  gps_mtk.msg_id = c;
357  break;
358  /* MTK_DIY_VER_16 */
359  case GOT_SYNC1_16:
360  if (c != MTK_DIY16_NAV_ID) {
362  goto error;
363  }
364  if (gps_mtk.msg_available) {
365  /* Previous message has not yet been parsed: discard this one */
367  goto error;
368  }
369  gps_mtk.msg_id = c;
370  gps_mtk.ck_a = 0;
371  gps_mtk.ck_b = 0;
372  gps_mtk.status++;
373  break;
374  case GOT_SYNC2_16:
375  gps_mtk.len = c;
376  gps_mtk.msg_idx = 0;
378  break;
379  case GOT_ID:
381  gps_mtk.msg_idx++;
382  if (gps_mtk.msg_idx >= gps_mtk.len) {
383  gps_mtk.status++;
384  }
385  break;
386  case GOT_PAYLOAD:
387  if (c != gps_mtk.ck_a) {
389  goto error;
390  }
391  gps_mtk.status++;
392  break;
393  case GOT_CHECKSUM1:
394  if (c != gps_mtk.ck_b) {
396  goto error;
397  }
399  goto restart;
400  break;
401  default:
403  goto error;
404  }
405  return;
406 error:
407  gps_mtk.error_cnt++;
408 restart:
410  return;
411 }
412 
413 
414 /*
415  *
416  *
417  * GPS dynamic configuration
418  *
419  *
420  */
421 #ifdef GPS_CONFIGURE
422 
423 #include "mcu_periph/link_device.h"
424 
425 static void MtkSend_CFG(char *dat)
426 {
427  struct link_device *dev = &((GPS_LINK).device);
428  while (*dat != 0) { dev->put_byte(dev->periph, *dat++); }
429 }
430 
431 void gps_configure_uart(void)
432 {
433 }
434 
435 #ifdef USER_GPS_CONFIGURE
436 #include USER_GPS_CONFIGURE
437 #else
438 static bool_t user_gps_configure(bool_t cpt)
439 {
440  switch (cpt) {
441  case 0:
442  MtkSend_CFG(MTK_DIY_SET_BINARY);
443  break;
444  case 1:
445  MtkSend_CFG(MTK_DIY_OUTPUT_RATE);
446  return FALSE;
447  default:
448  break;
449  }
450  return TRUE; /* Continue, except for the last case */
451 }
452 #endif // ! USER_GPS_CONFIGURE
453 
454 void gps_configure(void)
455 {
456  static uint32_t count = 0;
457  /* start configuring after having received 50 bytes */
458  if (count++ > 50) {
459  gps_configuring = user_gps_configure(gps_status_config++);
460  }
461 }
462 
463 #endif /* GPS_CONFIGURE */
unsigned short uint16_t
Definition: types.h:16
uint32_t t0_tow
GPS time of week in ms from last message.
Definition: gps.h:98
int32_t north
in centimeters
uint8_t msg_idx
Definition: gps_mtk.h:41
uint8_t error_cnt
Definition: gps_mtk.h:44
float east
in meters
#define SECS_MINUTE
Definition: gps_mtk.c:73
float north
in meters
void gps_mtk_read_message(void)
Definition: gps_mtk.c:189
uint32_t t0_ticks
hw clock ticks when GPS message is received
Definition: gps.h:100
uint16_t week
GPS week.
Definition: gps.h:83
struct GpsMtk gps_mtk
Definition: gps_mtk.c:82
Main include for ABI (AirBorneInterface).
uint8_t nav_utm_zone0
Definition: common_nav.c:44
#define UNINIT
Definition: gps_mtk.c:48
uint8_t ck_b
Definition: gps_mtk.h:42
bool_t msg_available
Definition: gps_mtk.h:34
#define MTK_DIY_OUTPUT_RATE
Definition: gps_mtk.c:44
position in UTM coordinates Units: meters
int32_t east
in centimeters
volatile uint32_t nb_tick
SYS_TIME_TICKS since startup.
Definition: sys_time.h:71
#define GPS_MTK_ERR_NONE
Definition: gps_mtk.c:59
uint16_t speed_3d
norm of 3d speed in cm/s
Definition: gps.h:75
#define GPS_FIX_3D
3D GPS fix
Definition: gps.h:43
int32_t z
Down.
#define OUTPUT_RATE
Definition: gps_mtk.c:45
struct UtmCoor_i utm_pos
position in UTM (north,east: cm; alt: mm over ellipsoid)
Definition: gps.h:70
uint8_t ck_a
Definition: gps_mtk.h:42
uint32_t last_3dfix_ticks
cpu time ticks at last valid 3D fix
Definition: gps.h:89
#define FALSE
Definition: std.h:5
int32_t alt
in millimeters above WGS84 reference ellipsoid
static uint32_t get_sys_time_usec(void)
Get the time in microseconds since startup.
Definition: sys_time_arch.h:39
#define LED_TOGGLE(i)
Definition: led_hw.h:44
uint32_t last_msg_time
cpu time in sec at last received GPS message
Definition: gps.h:92
uint8_t zone
UTM zone number.
Paparazzi floating point math for geodetic calculations.
static void gps_mtk_time2itow(uint32_t gps_date, uint32_t gps_time, int16_t *gps_week, uint32_t *gps_itow)
Definition: gps_mtk.c:145
#define GPS_MTK_ERR_CHECKSUM
Definition: gps_mtk.c:62
vector in Latitude, Longitude and Altitude
#define MTK_DIY_FIX_3D
Definition: gps_mtk.c:67
#define TRUE
Definition: std.h:4
uint8_t msg_buf[GPS_MTK_MAX_PAYLOAD]
Definition: gps_mtk.h:35
int32_t hmsl
height above mean sea level in mm
Definition: gps.h:71
void gps_mtk_parse(uint8_t c)
Definition: gps_mtk.c:309
Architecture independent timing functions.
uint16_t len
Definition: gps_mtk.h:40
uint32_t tow
GPS time of week in ms.
Definition: gps.h:84
#define GPS_FIX_NONE
No GPS fix.
Definition: gps.h:41
#define GPS_FIX_2D
2D GPS fix
Definition: gps.h:42
#define GOT_SYNC2_16
Definition: gps_mtk.c:53
Device independent GPS code (interface)
#define SECS_DAY
Definition: gps_mtk.c:75
unsigned long uint32_t
Definition: types.h:18
signed short int16_t
Definition: types.h:17
#define GOT_PAYLOAD
Definition: gps_mtk.c:55
int32_t lon
in degrees*1e7
#define GPS_MTK_ERR_UNEXPECTED
Definition: gps_mtk.c:63
#define GOT_SYNC1_16
Definition: gps_mtk.c:52
uint8_t zone
UTM zone number.
#define GOT_CHECKSUM1
Definition: gps_mtk.c:56
volatile uint32_t nb_sec_rem
remainder of seconds since startup in CPU_TICKS
Definition: sys_time.h:70
uint8_t msg_class
Definition: gps_mtk.h:37
#define GPS_MTK_ERR_OUT_OF_SYNC
Definition: gps_mtk.c:64
signed long int32_t
Definition: types.h:19
uint8_t status
Definition: gps_mtk.h:39
Definition: gps_mtk.h:33
static const struct usb_device_descriptor dev
Definition: usb_ser_hw.c:69
#define LED_ON(i)
Definition: led_hw.h:42
void gps_impl_init(void)
GPS initialization.
Definition: gps_mtk.c:106
#define GOT_SYNC2_14
Definition: gps_mtk.c:50
uint32_t last_3dfix_time
cpu time in sec at last valid 3D fix
Definition: gps.h:90
int32_t alt
in millimeters above WGS84 reference ellipsoid
unsigned char uint8_t
Definition: types.h:14
int32_t course
GPS course over ground in rad*1e7, [0, 2*Pi]*1e7 (CW/north)
Definition: gps.h:76
volatile uint32_t nb_sec
full seconds since startup
Definition: sys_time.h:69
#define SECS_HOUR
Definition: gps_mtk.c:74
#define GOT_CLASS_14
Definition: gps_mtk.c:51
void gps_mtk_msg(void)
Definition: gps_mtk.c:118
int32_t t0_tow_frac
fractional ns remainder of tow [ms], range -500000 .. 500000
Definition: gps.h:99
#define GPS_MTK_ID
struct GpsTimeSync gps_time_sync
Definition: gps.c:43
uint32_t last_msg_ticks
cpu time ticks at last received GPS message
Definition: gps.h:91
uint8_t num_sv
number of sat in fix
Definition: gps.h:81
arch independent LED (Light Emitting Diodes) API
#define GOT_ID
Definition: gps_mtk.c:54
uint16_t gspeed
norm of 2d ground speed in cm/s
Definition: gps.h:74
struct LlaCoor_i lla_pos
position in LLA (lat,lon: deg*1e7; alt: mm over ellipsoid)
Definition: gps.h:69
uint8_t error_last
Definition: gps_mtk.h:45
#define SysTimeTimerStart(_t)
Definition: sys_time.h:213
signed char int8_t
Definition: types.h:15
#define isleap(x)
Definition: gps_mtk.c:78
const int8_t DAYS_MONTH[12]
Definition: gps_mtk.c:80
#define GOT_SYNC1_14
Definition: gps_mtk.c:49
int32_t lat
in degrees*1e7
uint8_t msg_id
Definition: gps_mtk.h:36
uint8_t fix
status of fix
Definition: gps.h:82
struct NedCoor_i ned_vel
speed NED in cm/s
Definition: gps.h:73
#define GPS_MTK_ERR_OVERRUN
Definition: gps_mtk.c:60
struct GpsState gps
global GPS state
Definition: gps.c:41
#define LLA_FLOAT_OF_BFP(_o, _i)
void utm_of_lla_f(struct UtmCoor_f *utm, struct LlaCoor_f *lla)
#define MTK_DIY_FIX_2D
Definition: gps_mtk.c:68