8 #include <aversive/endian.h>
9 #include <aversive/wait.h>
17 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
18 #define letoh16(x) (x)
19 #define letoh32(x) (x)
20 #define letoh64(x) (x)
21 #define htole16(x) (x)
22 #define htole32(x) (x)
23 #define htole64(x) (x)
28 /* note: enabling debug will make the code fail due to rx queue full */
29 #define debug_printf(fmt, a...) do { } while (0)
30 //#define debug_printf(fmt, ...) printf(fmt, ##__VA_ARGS__)
33 #define GPS_PERIOD_MS 2
38 struct gps_ubx_cksum {
49 uint8_t data[MAX_LEN];
52 static struct gps_frame rxframe;
53 static struct gps_ubx_cksum rxcksum;
54 static struct callout gps_timer;
56 /* Navigation Results: Position, Speed, Time, Acc, Heading, DOP, SVs
58 #define GPS_UBX_CLASS_NAV 0x01
60 #define GPS_UBX_ID_NAV_POSECEF 0x01
61 #define GPS_UBX_ID_NAV_POSLLH 0x02
62 #define GPS_UBX_ID_NAV_STATUS 0x03
63 #define GPS_UBX_ID_NAV_DOP 0x04
64 #define GPS_UBX_ID_NAV_SOL 0x06
65 #define GPS_UBX_ID_NAV_VELECEF 0x11
66 #define GPS_UBX_ID_NAV_VELNED 0x12
67 #define GPS_UBX_ID_NAV_TIMEGPS 0x20
68 #define GPS_UBX_ID_NAV_TIMEUTC 0x21
69 #define GPS_UBX_ID_NAV_CLOCK 0x22
70 #define GPS_UBX_ID_NAV_SVINFO 0x30
71 #define GPS_UBX_ID_NAV_DGPS 0x31
72 #define GPS_UBX_ID_NAV_SBAS 0x32
73 #define GPS_UBX_ID_NAV_EKFSTATUS 0x40
74 #define GPS_UBX_ID_NAV_AOPSTATUS 0x60
76 /* Receiver Manager Messages: Satellite Status, RTC Status */
77 #define GPS_UBX_CLASS_RXM 0x02
79 #define GPS_UBX_ID_RXM_ALM 0x30
80 #define GPS_UBX_ID_RXM_EPH 0x31
81 #define GPS_UBX_ID_RXM_PMREQ 0x41
82 #define GPS_UBX_ID_RXM_RAW 0x10
83 #define GPS_UBX_ID_RXM_SFRB 0x11
84 #define GPS_UBX_ID_RXM_SVSI 0x20
86 /* Information Messages: Printf-Style Messages, with IDs such as Error, Warning,
88 #define GPS_UBX_CLASS_INF 0x04
90 /* Ack/Nack Messages: as replies to CFG Input Messages */
91 #define GPS_UBX_CLASS_ACK 0x05
93 /* Configuration Input Messages: Set Dynamic Model, Set DOP Mask, Set
95 #define GPS_UBX_CLASS_CFG 0x06
97 #define GPS_UBX_ID_CFG_MSG 0x01
98 #define GPS_UBX_ID_CFG_RATE 0x08
99 #define GPS_UBX_ID_CFG_SBAS 0x16
101 /* Monitoring Messages: Comunication Status, CPU Load, Stack Usage, Task
103 #define GPS_UBX_CLASS_MON 0x0A
105 /* AssistNow Aiding Messages: Ephemeris, Almanac, other A-GPS data
107 #define GPS_UBX_CLASS_AID 0x0B
109 /* Timing Messages: Timepulse Output, Timemark Results */
110 #define GPS_UBX_CLASS_TIM 0x0D
112 #define GPS_UBX_CLASS_NMEA_STD 0xF0
113 #define GPS_UBX_CLASS_NMEA_UBX 0xF1
115 #define GPS_UBX_ID_NMEA_GGA 0x00
116 #define GPS_UBX_ID_NMEA_GLL 0x01
117 #define GPS_UBX_ID_NMEA_GSA 0x02
118 #define GPS_UBX_ID_NMEA_GSV 0x03
119 #define GPS_UBX_ID_NMEA_RMC 0x04
120 #define GPS_UBX_ID_NMEA_VTG 0x05
122 /********************* NAV class */
124 /* Position Solution in ECEF */
125 struct gps_ubx_posecef {
126 uint32_t iTOW; /* ms - GPS Millisecond Time of Week */
127 int32_t ecefX; /* cm - ECEF X coordinate */
128 int32_t ecefY; /* cm - ECEF Y coordinate */
129 int32_t ecefZ; /* cm - ECEF Z coordinate */
130 uint32_t pAcc; /* cm - Position Accuracy Estimate */
133 /* Geodetic Position Solution */
134 struct gps_ubx_posllh {
135 uint32_t iTOW; /* ms - GPS Millisecond Time of Week */
136 int32_t lon; /* 1e-7 deg - Longitude */
137 int32_t lat; /* 1e-7 deg - Latitude */
138 int32_t height; /* mm - Height above ellipsoid */
139 int32_t heightMSL; /* mm - Height above mean sea level */
140 uint32_t hAcc; /* mm - Horizontal Accuracy Estimate */
141 uint32_t vAcc; /* mm - Vertical Accuracy Estimate */
144 /* Velocity solution in NED */
145 struct gps_ubx_velned {
146 uint32_t iTOW; /* GPS Millisecond Time of Week */
147 int32_t velN; /* NED north velocity */
148 int32_t velE; /* NED east velocity */
149 int32_t velD; /* NED down velocity */
150 uint32_t speed; /* Speed (3-D) */
151 uint32_t gSpeed; /* Ground Speed (2-D) */
152 int32_t heading; /* eading of motion 2-D */
153 uint32_t sAcc; /* Speed Accuracy Estimate */
154 uint32_t cAcc; /* Course / Heading Accuracy Estimate */
157 /* This message combines Position, velocity and time solution in ECEF, including
158 * accuracy figures */
159 struct gps_ubx_nav_sol {
161 int32_t fTOW; /* Fractional Nanoseconds remainder of rounded ms above,
162 * range -500000 .. 500000 */
163 int16_t week; /* GPS week (GPS time) */
164 uint8_t gpsFix; /* GPSfix Type, 0x00 = No Fix, 0x01 = Dead Reckoning only,
165 * 0x02 = 2D-Fix 0x03 = 3D-Fix, 0x04 = GPS + dead reckoning
166 * combined, 0x05 = Time only fix, 0x06..0xff: reserved */
167 uint8_t flags; /* Fix Status Flags (see graphic below) */
168 int32_t ecefX; /* cm - ECEF X coordinate */
169 int32_t ecefY; /* cm - ECEF Y coordinate */
170 int32_t ecefZ; /* cm - ECEF Z coordinate */
171 uint32_t pAcc; /* cm - 3D Position Accuracy Estimate */
172 int32_t ecefVX; /* cm/s - ECEF X velocity */
173 int32_t ecefVY; /* cm/s - ECEF Y velocity */
174 int32_t ecefVZ; /* cm/s - ECEF Z velocity */
175 uint32_t sAcc; /* cm/s - Speed Accuracy Estimate */
176 uint16_t pDOP; /* Position DOP */
178 uint8_t numSV; /* Number of SVs used in Nav Solution */
182 /********************* CFG class */
184 /* Get/Set Port Configuration for UART
185 * Several configurations can be concatenated to one input message. In
186 * this case the payload length can be a multiple of the normal length
187 * (see the other versions of CFG-PRT). Output messages from the module
188 * contain only one configuration unit. */
190 uint8_t portID; /* Port Identifier Number (= 1 or 2 for UART ports) */
192 #define GPS_UBX_PRT_TXREADY_EN_MASK 0x0001
193 #define GPS_UBX_PRT_TXREADY_POL_MASK 0x0002
194 #define GPS_UBX_PRT_TXREADY_PIN_MASK 0x007c
195 #define GPS_UBX_PRT_TXREADY_THRES_MASK 0xff80
196 uint16_t txReady; /* reserved (Alwyas set to zero) up to Firmware 7.
197 * TX ready PIN configuration (since Firmware 7). */
198 #define GPS_UBX_PRT_MODE_RESERVED1_MASK 0x00000010
199 #define GPS_UBX_PRT_MODE_CHARLEN_MASK 0x000000c0
200 #define GPS_UBX_PRT_MODE_CHARLEN_5BITS 0x00000000
201 #define GPS_UBX_PRT_MODE_CHARLEN_6BITS 0x00000040
202 #define GPS_UBX_PRT_MODE_CHARLEN_7BITS 0x00000080
203 #define GPS_UBX_PRT_MODE_CHARLEN_8BITS 0x000000c0
204 #define GPS_UBX_PRT_MODE_PARITY_MASK 0x00000e00
205 #define GPS_UBX_PRT_MODE_PARITY_EVEN 0x00000000
206 #define GPS_UBX_PRT_MODE_PARITY_ODD 0x00000200
207 #define GPS_UBX_PRT_MODE_PARITY_NONE 0x00000800
208 #define GPS_UBX_PRT_MODE_NSTOP_MASK 0x00003000
209 #define GPS_UBX_PRT_MODE_NSTOP_1 0x00000000
210 #define GPS_UBX_PRT_MODE_NSTOP_1_5 0x00001000
211 #define GPS_UBX_PRT_MODE_NSTOP_2 0x00002000
212 #define GPS_UBX_PRT_MODE_NSTOP_0_5 0x00003000
213 uint32_t mode; /* A bit mask describing the UART mode */
215 #define GPS_UBX_PRT_PROTOMASK_UBX 0x0001
216 #define GPS_UBX_PRT_PROTOMASK_NMEA 0x0002
217 /* A mask describing which input protocols are active. Each bit
218 * of this mask is used for a protocol. Through that, multiple
219 * protocols can be defined on a single port. */
220 uint16_t inProtoMask;
221 /* A mask describing which output protocols are active */
222 uint16_t outProtoMask;
226 /* Set/Get message rate configuration to/from the receiver. */
230 uint8_t rate; /* Send rate */
234 /* Configure the SBAS (Satellite-based augmentation systems) receiver subsystem
235 * (i.e. WAAS, EGNOS, MSAS). */
236 struct gps_ubx_sbas {
237 #define GPS_UBX_SBAS_MODE_ENABLED 0x01 /* SBAS Enabled */
238 #define GPS_UBX_SBAS_MODE_TEST 0x02 /* SBAS Testbed: Use data anyhow */
239 uint8_t mode; /* bitfield */
240 #define GPS_UBX_SBAS_USAGE_RANGE 0x01 /* Use SBAS GEOs as a ranging source */
241 #define GPS_UBX_SBAS_USAGE_DIFFCORR 0x02 /* Use SBAS Differential Corrections */
242 #define GPS_UBX_SBAS_USAGE_INTEGRITY 0x04 /* Use SBAS Integrity Information */
243 uint8_t usage; /* bitfield */
244 uint8_t maxSBAS; /* Maximum Number of SBAS prioritized tracking
245 * channels (valid range: 0 - 3) to use */
246 uint8_t scanmode2; /* PRN152 -> PRN156 (bit 0 to 6) */
247 uint32_t scanmode1; /* PRN120 -> PRN151 (bit 0 to 31) */
250 /* The u-blox positioning technology supports navigation update rates higher or
251 * lower than 1 update per second. The calculation of the navigation solution
252 * will always be aligned to the top of a second.
254 * • The update rate has a direct influence on the power consumption. The more
255 * fixes that are required, the more CPU power and communication resources
257 * • For most applications a 1 Hz update rate would be sufficient. */
258 struct gps_ubx_rate {
259 uint16_t measRate; /* ms - Measurement Rate */
260 uint16_t navRate; /* cycles - Navigation Rate, in number of measurement
261 cycles. On u-blox 5 and u-blox 6, this parameter
262 cannot be changed, and is always equals 1. */
263 uint16_t timeRef; /* Alignment to reference time: 0 = UTC time,
269 /********************* ACK class */
271 /* When messages from the Class CFG are sent to the receiver, the
272 * receiver will send an Acknowledge (ACK-ACK) or a Not Acknowledge
273 * (ACK-NAK) message back to the sender, depending on whether or not the
274 * message was processed correctly. There is no ACK/NAK mechanism for
275 * message poll requests outside Class CFG. */
277 #define GPS_UBX_ID_NACK 0x00
278 #define GPS_UBX_ID_ACK 0x01
281 uint8_t class; /* GPS_UBX_CLASS_ACK */
282 uint8_t id; /* GPS_UBX_ID_ACK or GPS_UBX_ID_NACK */
287 /********************* RXM class */
289 struct gps_ubx_rxm_svsi {
290 int32_t iTOW; /* Measurement integer millisecond GPS time of week */
291 int16_t week; /* Measurement GPS week number. */
292 uint8_t numVis; /* Number of visible satellites */
293 uint8_t numSV; /* Number of per-SV data blocks following */
295 uint8_t svid; /* Satellite ID */
296 uint8_t svFlag; /* Information Flags */
297 int16_t azim; /* Azimuth */
298 int8_t elev; /* Elevation */
299 uint8_t age; /* Age of Almanach and Ephemeris */
300 } sv[]; /* reapeated numSV times */
305 static void gps_ubx_cksum_update(struct gps_ubx_cksum *cksum, uint8_t byte)
307 cksum->ck_a = cksum->ck_a + byte;
308 cksum->ck_b = cksum->ck_b + cksum->ck_a;
311 static void serial1_tx_cout(uint8_t c)
313 debug_printf("%.2X ", c);
314 uart_send(GPS_UART, c);
318 void gps_ubx_send(uint8_t class, uint8_t id, void *payload, uint16_t len)
320 struct gps_ubx_cksum cksum = { 0, 0 };
324 debug_printf("SEND ");
326 serial1_tx_cout(START1);
327 serial1_tx_cout(START2);
328 serial1_tx_cout(class);
329 gps_ubx_cksum_update(&cksum, class);
331 gps_ubx_cksum_update(&cksum, id);
332 serial1_tx_cout(len & 0xff);
333 gps_ubx_cksum_update(&cksum, len & 0xff);
334 serial1_tx_cout((len >> 8) & 0xff);
335 gps_ubx_cksum_update(&cksum, (len >> 8) & 0xff);
337 for (n = 0; n < len; n++) {
338 byte = *(uint8_t *)payload;
339 serial1_tx_cout(byte);
340 gps_ubx_cksum_update(&cksum, byte);
343 /* checksum and tail */
344 serial1_tx_cout(cksum.ck_a);
345 serial1_tx_cout(cksum.ck_b);
350 /* frequency of messages */
351 void gps_ubx_set_msg_rate(uint8_t class, uint8_t id, uint8_t rate)
353 struct gps_ubx_msg msg_rate;
355 memset(&msg_rate, 0, sizeof(msg_rate));
356 msg_rate.class = class;
358 msg_rate.rate = rate;
360 gps_ubx_send(GPS_UBX_CLASS_CFG, GPS_UBX_ID_CFG_MSG,
361 &msg_rate, sizeof(msg_rate));
365 void gps_ubx_set_rate(uint16_t measRate, uint16_t navRate, uint16_t timeRef)
367 struct gps_ubx_rate rate;
369 memset(&rate, 0, sizeof(rate));
370 rate.measRate = htole16(measRate);
371 rate.navRate = htole16(navRate);
372 rate.timeRef = htole16(timeRef);
374 gps_ubx_send(GPS_UBX_CLASS_CFG, GPS_UBX_ID_CFG_RATE,
375 &rate, sizeof(rate));
378 /* set satellite-based augmentation system (differential gps) */
379 void gps_ubx_set_sbas(uint8_t mode, uint8_t usage, uint8_t maxSBAS,
380 uint8_t scanmode2, uint32_t scanmode1)
382 struct gps_ubx_sbas msg_sbas;
384 memset(&msg_sbas, 0, sizeof(msg_sbas));
385 msg_sbas.mode = mode;
386 msg_sbas.usage = usage;
387 msg_sbas.maxSBAS = maxSBAS;
388 msg_sbas.scanmode2 = scanmode2;
389 msg_sbas.scanmode1 = htole32(scanmode1);
391 gps_ubx_send(GPS_UBX_CLASS_CFG, GPS_UBX_ID_CFG_SBAS,
392 &msg_sbas, sizeof(msg_sbas));
395 int8_t recv_cb(uint8_t byte)
399 /* bytes 0 and 1 are start bytes */
400 if (rxframe.cur_len == 0) {
401 debug_printf("start1 %x\n", byte);
402 if (byte != START1) {
403 debug_printf("bad start1 %.2X\n", byte);
407 else if (rxframe.cur_len == 1) {
408 debug_printf("start2 %x\n", byte);
409 if (byte != START2) {
410 debug_printf("bad start2 %.2X\n", byte);
414 /* bytes 2 and 3 are the class and id */
415 else if (rxframe.cur_len == 2) {
416 debug_printf("class %x\n", byte);
417 rxframe.class = byte;
419 else if (rxframe.cur_len == 3) {
420 debug_printf("id %x\n", byte);
423 /* bytes 4 and 5 are the length of frame in little endian order */
424 else if (rxframe.cur_len == 4) {
425 debug_printf("len_l %x\n", byte);
426 rxframe.len = (uint16_t)byte;
428 else if (rxframe.cur_len == 5) {
429 debug_printf("len_h %x\n", byte);
430 rxframe.len |= (uint16_t)byte << 8;
431 if (rxframe.len > MAX_LEN) {
432 debug_printf("bad len %d\n", rxframe.len);
436 /* next bytes are data (the 6 below is the size of header) */
437 else if ((rxframe.cur_len - 6) < rxframe.len) {
438 debug_printf("data %x\n", byte);
439 rxframe.data[rxframe.cur_len - 6] = byte;
441 /* then it's the cksum */
442 else if ((rxframe.cur_len - 6) == rxframe.len) {
443 debug_printf("ck_a %x\n", byte);
446 else if ((rxframe.cur_len - 6) == rxframe.len + 1) {
447 struct gps_ubx_cksum cksum = { 0, 0 };
449 debug_printf("ck_b %x\n", byte);
453 gps_ubx_cksum_update(&cksum, rxframe.class);
454 gps_ubx_cksum_update(&cksum, rxframe.id);
455 gps_ubx_cksum_update(&cksum, rxframe.len & 0xff);
456 gps_ubx_cksum_update(&cksum, rxframe.len >> 8);
457 for (i = 0; i < rxframe.len; i++)
458 gps_ubx_cksum_update(&cksum, rxframe.data[i]);
459 if (cksum.ck_a != rxcksum.ck_a ||
460 cksum.ck_b != rxcksum.ck_b) {
461 debug_printf("invalid checksum %2.2x%2.2x != %2.2x%2.2x\n",
462 cksum.ck_a, cksum.ck_b,
463 rxcksum.ck_a, rxcksum.ck_a);
467 debug_printf("valid frame received\n");
471 else /* should not happen */
487 uint16_t t1, t2, diff;
491 IRQ_UNLOCK(irq_flags);
496 IRQ_UNLOCK(irq_flags);
499 printf_P(PSTR("recv_msg timeout\n"));
503 c = uart_recv_nowait(GPS_UART);
507 debug_printf("%2.2x\n", c);
515 int wait_ack(int msg_type)
519 uint16_t t1, t2, diff;
523 IRQ_UNLOCK(irq_flags);
533 IRQ_UNLOCK(irq_flags);
536 printf_P(PSTR("wait_ack timeout\n"));
540 /* retry if it's not the expected message */
541 if (rxframe.data[0] != 0x83 && rxframe.data[0] != 0x84)
543 if (rxframe.data[1] != msg_type)
546 if (rxframe.data[0] == 0x83)
547 printf_P(PSTR("ACK\n"));
548 else if (rxframe.data[0] == 0x84)
549 printf_P(PSTR("NACK\n"));
551 printf_P(PSTR("ZARB\n"));
558 static int decode_gps_posllh(const struct gps_frame *frame)
560 const struct gps_ubx_posllh *posllh =
561 (const struct gps_ubx_posllh *)&frame->data;
562 int32_t height, heightMSL;
565 //printf("%s\n", __FUNCTION__);
566 /* pos struct is in cm, convert */
567 height = letoh32(posllh->height) / 10;
568 heightMSL = letoh32(posllh->heightMSL) / 10;
571 gps_pos.tow = letoh32(posllh->iTOW);
572 gps_pos.longitude = letoh32(posllh->lon);
573 gps_pos.latitude = letoh32(posllh->lat);
574 gps_pos.altitude = height;
575 gps_pos.sea_altitude = heightMSL;
576 IRQ_UNLOCK(irq_flags);
581 static int decode_gps_posecef(const struct gps_frame *frame)
583 const struct gps_ubx_posecef *posecef =
584 (const struct gps_ubx_posecef *)&frame->data;
587 //printf("%s\n", __FUNCTION__);
589 gps_pos.tow = letoh32(posecef->iTOW);
590 gps_pos.ecef_x = letoh32(posecef->ecefX);
591 gps_pos.ecef_y = letoh32(posecef->ecefY);
592 gps_pos.ecef_z = letoh32(posecef->ecefZ);
593 IRQ_UNLOCK(irq_flags);
598 static int decode_gps_velned(const struct gps_frame *frame)
600 const struct gps_ubx_velned *velned =
601 (const struct gps_ubx_velned *)&frame->data;
604 //printf("%s\n", __FUNCTION__);
606 gps_pos.tow = letoh32(velned->iTOW);
607 //gps_pos.speed = letoh32(velned->speed); //XXX add speed ?
608 IRQ_UNLOCK(irq_flags);
613 static int decode_gps_nav_sol(const struct gps_frame *frame)
615 const struct gps_ubx_nav_sol *nav_sol =
616 (const struct gps_ubx_nav_sol *)&frame->data;
619 //printf("%s\n", __FUNCTION__);
621 gps_pos.tow = letoh32(nav_sol->iTOW);
622 gps_pos.gps_week = letoh16(nav_sol->week);
623 gps_pos.mode = nav_sol->gpsFix;
624 gps_pos.sv_num = nav_sol->numSV;
625 gps_pos.ecef_x = letoh32(nav_sol->ecefX);
626 gps_pos.ecef_y = letoh32(nav_sol->ecefY);
627 gps_pos.ecef_z = letoh32(nav_sol->ecefZ);
628 gps_pos.ecef_vx = letoh32(nav_sol->ecefVX);
629 gps_pos.ecef_vy = letoh32(nav_sol->ecefVY);
630 gps_pos.ecef_vz = letoh32(nav_sol->ecefVZ);
631 IRQ_UNLOCK(irq_flags);
636 static int decode_gps_rxm_svsi(const struct gps_frame *frame)
638 const struct gps_ubx_rxm_svsi *rxm_svsi =
639 (const struct gps_ubx_rxm_svsi *)&frame->data;
642 //printf("%s\n", __FUNCTION__);
644 gps_pos.tow = letoh32(rxm_svsi->iTOW);
645 gps_pos.gps_week = letoh16(rxm_svsi->week);
646 gps_pos.sv_num = rxm_svsi->numVis;
647 IRQ_UNLOCK(irq_flags);
652 static int decode_gps(const struct gps_frame *frame)
656 switch (frame->class) {
657 case GPS_UBX_CLASS_NAV:
659 case GPS_UBX_ID_NAV_POSLLH:
660 ret = decode_gps_posllh(frame);
662 case GPS_UBX_ID_NAV_POSECEF:
663 ret = decode_gps_posecef(frame);
665 case GPS_UBX_ID_NAV_VELNED:
666 ret = decode_gps_velned(frame);
668 case GPS_UBX_ID_NAV_SOL:
669 ret = decode_gps_nav_sol(frame);
675 case GPS_UBX_CLASS_RXM:
677 case GPS_UBX_ID_RXM_SVSI:
678 ret = decode_gps_rxm_svsi(frame);
688 debug_printf("error processing message class=%x id=%x\n",
689 frame->class, frame->id);
693 /* fix endianness inside the frame */
694 pos->gps_week = ntohs(pos->gps_week);
695 pos->tow = ntohl(pos->tow);
697 pos->latitude = ntohl(pos->latitude);
698 pos->longitude = ntohl(pos->longitude);
699 pos->altitude = ntohl(pos->altitude);
701 pos->sea_altitude = ntohl(pos->sea_altitude);
703 pos->gdop = ntohs(pos->gdop);
704 pos->pdop = ntohs(pos->pdop);
705 pos->hdop = ntohs(pos->hdop);
706 pos->vdop = ntohs(pos->vdop);
707 pos->tdop = ntohs(pos->tdop);
709 pos->ecef_vx = ntohl(pos->ecef_vx);
710 pos->ecef_vy = ntohl(pos->ecef_vy);
711 pos->ecef_vz = ntohl(pos->ecef_vz);
713 /* update global structure */
715 memcpy(&gps_pos, pos, sizeof(gps_pos));
716 IRQ_UNLOCK(irq_flags);
722 /* display current GPS position stored in the global variable */
723 static void display_gps(void)
725 /* no need to call ntohs/ntohl because the frame is already fixed by
726 * decode_gps_pos() */
727 printf_P(PSTR("id %.2X mode %.2X svnum %.2X gpsw %.4X "
728 "tow %.10"PRIu32"\t"),
735 printf_P(PSTR("lat %.8"PRIx32" long %.8"PRIx32" alt %.8"PRIx32"\n"),
740 printf_P(PSTR("gdop %3.3f pdop %3.3f hdop %3.3f vdop %3.3f "
742 (double)gps_pos.gdop/100.,
743 (double)gps_pos.pdop/100.,
744 (double)gps_pos.hdop/100.,
745 (double)gps_pos.vdop/100.,
746 (double)gps_pos.tdop/100.);
748 printf_P(PSTR("lat %3.5f long %3.5f alt %3.5f sea_alt %3.5f\n"),
749 (double)gps_pos.latitude/10000000.,
750 (double)gps_pos.longitude/10000000.,
751 (double)gps_pos.altitude/100.,
752 (double)gps_pos.sea_altitude/100.);
754 printf_P(PSTR("vx %3.3f vy %3.3f vz %3.3f\n"),
755 (double)gps_pos.ecef_vx/100.,
756 (double)gps_pos.ecef_vy/100.,
757 (double)gps_pos.ecef_vz/100.);
760 /* called on timer event */
761 static void gps_ubx_cb(struct callout_mgr *cm, struct callout *tim, void *arg)
763 static int16_t last_valid = 0;
764 static uint8_t is_valid = 0;
776 IRQ_UNLOCK(irq_flags);
779 c = uart_recv_nowait(GPS_UART);
780 if (c < 0) /* no more char */
785 decode_gps(&rxframe);
794 diff = ms - last_valid;
795 if (is_valid == 1 && diff > 500) {
798 /* update global structure */
800 memset(&gps_pos, 0, sizeof(gps_pos));
801 gps_pos.latitude = 0xffffffff;
802 IRQ_UNLOCK(irq_flags);
805 callout_schedule(cm, tim, GPS_PERIOD_MS);
808 int gps_ubx_init(void)
810 printf_P(PSTR("gps_ubx_init\n"));
812 gps_ubx_set_msg_rate(GPS_UBX_CLASS_NMEA_STD, GPS_UBX_ID_NMEA_GGA, 0);
813 gps_ubx_set_msg_rate(GPS_UBX_CLASS_NMEA_STD, GPS_UBX_ID_NMEA_GLL, 0);
814 gps_ubx_set_msg_rate(GPS_UBX_CLASS_NMEA_STD, GPS_UBX_ID_NMEA_GSA, 0);
815 gps_ubx_set_msg_rate(GPS_UBX_CLASS_NMEA_STD, GPS_UBX_ID_NMEA_GSV, 0);
816 gps_ubx_set_msg_rate(GPS_UBX_CLASS_NMEA_STD, GPS_UBX_ID_NMEA_RMC, 0);
817 gps_ubx_set_msg_rate(GPS_UBX_CLASS_NMEA_STD, GPS_UBX_ID_NMEA_VTG, 0);
819 gps_ubx_set_msg_rate(GPS_UBX_CLASS_NAV, GPS_UBX_ID_NAV_POSLLH, 1);
820 gps_ubx_set_msg_rate(GPS_UBX_CLASS_NAV, GPS_UBX_ID_NAV_STATUS, 1);
821 gps_ubx_set_msg_rate(GPS_UBX_CLASS_NAV, GPS_UBX_ID_NAV_SOL, 1);
822 gps_ubx_set_msg_rate(GPS_UBX_CLASS_NAV, GPS_UBX_ID_NAV_VELNED, 1);
823 //gps_ubx_set_msg_rate(GPS_UBX_CLASS_RXM, GPS_UBX_ID_RXM_SVSI, 1);
826 gps_ubx_set_sbas(GPS_UBX_SBAS_MODE_ENABLED,
827 GPS_UBX_SBAS_USAGE_RANGE | GPS_UBX_SBAS_USAGE_DIFFCORR |
828 GPS_UBX_SBAS_USAGE_INTEGRITY, 3, 0x0, 0x851);
830 gps_ubx_set_rate(500, 1, 1); /* 2hz */
832 printf_P(PSTR("GPS configuration done !\n"));
834 callout_init(&gps_timer, gps_ubx_cb, NULL, GPS_PRIO);
835 callout_schedule(&imuboard.intr_cm, &gps_timer, GPS_PERIOD_MS); /* every 2ms */