Fix 2.2.2RC1 no gvar compile (#5961)
[opentx.git] / radio / src / telemetry / nmea.cpp
bloba80f42c7d8fb630dfa7946046f33e739cedd2518
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
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.
21 #include "opentx.h"
23 #define LG_BUF 14
24 #define NB_LONG_BUF 3
25 #define NB_SHORT_BUF 3
26 #define LONG_BUF(val) (val)
27 #define SHORT_BUF(val) (val+NB_LONG_BUF)
28 #define VALSTR(val) (rbuf[val][0] ? rbuf[val] : val_unknown)
29 #define APSIZE (BSS | DBLSIZE)
31 uint8_t i; // working variable
32 uint8_t state; // currrent state
33 uint8_t rval, rpack; // received items
34 uint8_t xval[NB_LONG_BUF+NB_SHORT_BUF]; // expected value
35 uint8_t xpack[NB_LONG_BUF+NB_SHORT_BUF]; // expected packet
36 uint8_t ibuf[NB_LONG_BUF]; // subscripts on long buffers values
37 char rbuf[NB_LONG_BUF][LG_BUF]; // long receive buffers
38 char sbuf[NB_SHORT_BUF]; // short receive buffers
39 const char val_unknown[] = "?";
40 int32_t home_alt, save_alt, rel_alt, prev_alt, lift_alt, max_alt, abs_alt; // integer values for altitude computations
41 int32_t gpstimer=0;
42 int32_t gpstime;
43 uint8_t ggareceived;
44 uint8_t beep_on;
45 uint8_t show_timer;
47 /* Received data
48 Data are received as packets, each packet is identified by a prefix of seven
49 characters ('$GPGGA,' or '$GPRMC,')and is ended by one star plus two bytes checksum.
50 The values are terminated by a comma.
52 $GPGGA - Global Positioning System Fix Data, Time, Position and fix related data fora GPS receiver.
55 1 2 3 4 5 6 7 8 9 10 | 12 13 14 15
56 | | | | | | | | | | | | | | |
57 GGA,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh<CR><LF>
59 Field Number:
60 1) Universal Time Coordinated (UTC)
61 2) Latitude
62 3) N or S (North or South)
63 4) Longitude
64 5) E or W (East or West)
65 6) GPS Quality Indicator,
66 0 - fix not available,
67 1 - GPS fix,
68 2 - Differential GPS fix
69 7) Number of satellites in view, 00 - 12
70 8) Horizontal Dilution of precision
71 9) Antenna Altitude above/below mean-sea-level (geoid)
72 10) Units of antenna altitude, meters
73 11) Geoidal separation, the difference between the WGS-84 earth
74 ellipsoid and mean-sea-level (geoid), "-" means mean-sea-level
75 below ellipsoid
76 12) Units of geoidal separation, meters
77 13) Age of differential GPS data, time in seconds since last SC104
78 type 1 or 9 update, null field when DGPS is not used
79 14) Differential reference station ID, 0000-1023
81 15) Checksum
82 CrLf
85 $GPRMC - Recommended Minimum Navigation Information
87 1 2 3 4 5 6 7 8 9 10 11|
88 | | | | | | | | | | | |
89 RMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,xxxx,x.x,a*hh<CR><LF>
91 Field Number:
92 1) UTC Time
93 2) Status, V = Navigation receiver warning
94 3) Latitude
95 4) N or S
96 5) Longitude
97 6) E or W
98 7) Speed over ground, knots
99 8) Track made good, degrees true. = = Course over ground (COG)
100 9) Date, ddmmyy
101 10) Magnetic Variation, degrees
102 11) E or W
103 12) Checksum
106 // GGA record prefix
107 #define PACK_GGA 0x47 // "G"
108 #define PACK_GGA3 0x41 // "A"
109 // value occurence number in the GGA packet
110 #define TIM 1
111 #define LAT 2
112 #define NOS 3
113 #define LON 4
114 #define EOW 5
115 #define FIX 6
116 #define SAT 7
117 #define DIL 8
118 #define ALT 9
119 #define MTR 10
120 #define GEO 11
121 #define MET 12
122 #define AGE 13
123 #define DIF 14
125 // RMC record prefix
126 #define PACK_RMC 0x52 // "R"
127 #define PACK_RMC2 0x4D // "M"
128 #define PACK_RMC3 0x43 // "C"
129 // value occurence number in the RMC packet
130 #define TIM 1
131 #define NRW 2
132 #define LT1 3
133 #define NSO 4
134 #define LN1 5
135 #define EWE 6
136 #define SOG 7
137 #define COG 8
138 #define DAT 9
139 #define MAG 10
140 #define EAW 11
142 // end of packet
143 #define PACK_END 0x2a // *
144 // end of value
145 #define VAL_END 0x2c // ,
147 // stateful machine
149 // Since the packets are sent continuously, we need to synchronize on the
150 // reception of the three chars prefixing a packet, whatever they are.
152 // states values
153 #define WAIT_PACKET 1
154 #define WAIT_PACK_GGA1 2
155 #define WAIT_PACK_GGA2 3
156 #define WAIT_PACK_GGA3 4
157 #define WAIT_PACK_RMC2 5
158 #define WAIT_PACK_RMC3 6
159 #define WAIT_VAL_END 7
160 #define READ_VALUE 8
162 void menuViewTelemetryNMEA1(event_t event);
163 void menuViewTelemetryNMEA2(event_t event);
164 void menuViewTelemetryNMEA3(event_t event);
165 void menuViewTelemetryNMEA4(event_t event);
166 void title(char x);
167 void initval(uint8_t num, uint8_t pack, uint8_t val);
168 int32_t binary (char *str);
169 int32_t bintime (char *str);
171 #ifndef SIMU
172 ISR (USART0_RX_vect)
174 uint8_t rl;
175 // uint8_t rh; //USART control and Status Register 0 B
176 uint8_t iostat; //USART control and Status Register 0 A
178 rl = UDR0;
179 iostat = UCSR0A; //USART control and Status Register 0 A
181 bit 7 6 5 4 3 2 1 0
182 RxC0 TxC0 UDRE0 FE0 DOR0 UPE0 U2X0 MPCM0
184 RxC0: Receive complete
185 TXC0: Transmit Complete
186 UDRE0: USART Data Register Empty
187 FE0: Frame Error
188 DOR0: Data OverRun
189 UPE0: USART Parity Error
190 U2X0: Double Tx Speed
191 MPCM0: MultiProcessor Comms Mode
193 if (iostat & ((1 << FE0) | (1 << DOR0) | (1 << UPE0)))
195 rl = xpack[0] = xpack[1] = xval[0] = xval[1] = 0;
196 initval (LONG_BUF(2), PACK_GGA, TIM); // always get UTC time for timer
197 state = WAIT_PACKET; // restart on error
199 // rh = UCSR0B; //USART control and Status Register 0 B
200 /* bit 7 6 5 4 3 2 1 0
201 RxCIE0 TxCIE0 UDRIE0 RXEN0 TXEN0 UCSZ02 RXB80 TXB80
203 RxCIE0: Receive complete int enable
204 TXCIE0: Transmit Complete int enable
205 UDRIE0: USART Data Register Empty int enable
206 RXEN0: Rx enable
207 TXEN0: Tx Enable
208 UCSZ02: Character Size bit 2
209 RXB80: Rx data bit 8
210 TXB80: Tx data bit 8
212 switch (state)
214 case WAIT_PACKET:
215 switch (rl)
217 case PACK_GGA: // found a new GGA packet "G"
218 state = WAIT_PACK_GGA2; // wait for the 2nd char
219 break;
220 case PACK_RMC: // found a new RMS packet "R"
221 state = WAIT_PACK_RMC2; // wait for the 2nd char
222 break;
224 break;
226 case WAIT_PACK_GGA2: // received 2nd char "G"
227 if (rl == PACK_GGA)
228 state = WAIT_PACK_GGA3; // wait for 3rd character "A"
229 else
230 state = WAIT_PACKET; // restart if not "G"
231 break;
232 case WAIT_PACK_GGA3: // received 3rd char "A"
233 if (rl == PACK_GGA3) // found
235 state = WAIT_VAL_END; // wait for ","
236 rpack = PACK_GGA;
237 rval = 1; //clear the buffer
238 for (i = 0; i < NB_LONG_BUF; i++)
239 ibuf[i] = 0;
241 else
242 state = WAIT_PACKET; // restart if not found
243 break;
245 case WAIT_PACK_RMC2: // wait for 2nd char "M"
246 if (rl == PACK_RMC2)
247 state = WAIT_PACK_RMC3;
248 else
249 state = WAIT_PACKET; // restart if not found
250 break;
251 case WAIT_PACK_RMC3: // wait for 3rd char "C"
252 if (rl == PACK_RMC3)
254 state = WAIT_VAL_END; // wait for ","
255 rpack = PACK_RMC;
256 rval = 1;
257 for (i = 0; i < NB_LONG_BUF; i++) // clear buffer
258 ibuf[i] = 0;
260 else
261 state = WAIT_PACKET; // restart if not found
262 break;
264 case WAIT_VAL_END:
265 if (rl == VAL_END) // "," nach "GGA" oder "RMC"
267 state = READ_VALUE;
268 rval = 1;
269 for (i = 0; i < NB_LONG_BUF; i++) // clear buffer
270 ibuf[i] = 0;
272 else
273 state = WAIT_PACKET; // restart if not found
274 break;
277 case READ_VALUE:
278 switch (rl)
280 case PACK_END:
281 if (rpack == PACK_GGA)
282 ggareceived = 1;
283 state = WAIT_PACKET; // packet completed, wait for the next packet
284 break;
285 case VAL_END: // comma found, value completed
286 rval++; // and get next value
287 break;
288 default: // store the char in the corresponding buffer
289 for (i = 0; i < NB_LONG_BUF; i++)
290 { // is it the expected value in the expected packet ?
291 if (rpack == xpack[i] && rval == xval[i] && ibuf[i] < LG_BUF - 1)
292 { // yes, store the char
293 rbuf[i] [ibuf[i]] = rl;
294 ibuf[i]++;
295 rbuf[i] [ibuf[i]] = 0;
298 for (i = NB_LONG_BUF; i < NB_LONG_BUF+NB_SHORT_BUF; i++) {
299 if (rpack == xpack[i] // is this the expected short value in the expected packet ?
300 && rval == xval[i])
301 sbuf[i-NB_LONG_BUF] = rl; // yes, store the char
304 break;
307 #endif
309 void NMEA_Init (void)
311 #ifndef SIMU
312 DDRE &= ~(1 << DDE0); // set RXD0 pin as input
313 PORTE &= ~(1 << PORTE0); // disable pullup on RXD0 pin
315 // switch (Telem_baud)
316 // {
317 // case 1:
318 #undef BAUD
319 #define BAUD 4800
320 #include <util/setbaud.h>
321 UBRR0H = UBRRH_VALUE;
322 UBRR0L = UBRRL_VALUE;
323 // break;
324 // }
326 UCSR0A &= ~(1 << U2X0); // disable double speed operation
327 // set 8N1
328 UCSR0B = 0|(0<< RXCIE0)|(0<<TXCIE0)|(0<<UDRIE0)|(0<<RXEN0)|(0<<TXEN0)|(0<<UCSZ02);
329 UCSR0C = 0|(1 << UCSZ01) | (1 << UCSZ00);
330 while ( UCSR0A & (1 << RXC0) )
331 UDR0; // flush receive buffer
332 #endif
333 home_alt = rel_alt = ggareceived =0;
334 gpstimer = -1;
335 beep_on=1;
338 // TX Capabilities are not required for NMEA
339 // void NMEA_DisableTXD (void)
340 // {
341 // UCSR0B &= ~(1 << TXEN0); // disable TX
342 // }
344 // void NMEA_EnableTXD (void)
345 // {
346 // UCSR0B |= (1 << TXEN0); // enable TX
347 // }
349 void NMEA_DisableRXD (void)
351 UCSR0B &= ~(1 << RXEN0); // disable RX
352 UCSR0B &= ~(1 << RXCIE0); // disable Interrupt
355 void NMEA_EnableRXD (void)
357 for (i = 0; i < NB_LONG_BUF; i++)
359 ibuf[i] = 0;
360 rbuf[i][0] = 0;
361 xpack[i] = 0;
362 xval[i] = 0;
364 initval (LONG_BUF(2), PACK_GGA, TIM); // always get UTC time for timer
365 state = WAIT_PACKET; // wait for the next packet
366 UCSR0B |= (1 << RXEN0); // enable RX
367 UCSR0B |= (1 << RXCIE0); // enable Interrupt
370 void menuViewTelemetryNMEA(event_t event)
372 menuViewTelemetryNMEA1(event);
375 // Start of NMEA menus 1-4 <<<<<<<<<<<<<<<<<<<<<<<<<<<
377 void menuViewTelemetryNMEA1(event_t event)
379 switch(event) // new event received, branch accordingly
381 case EVT_KEY_BREAK(KEY_LEFT):
382 chainMenu(menuViewTelemetryNMEA4);
383 break;
384 case EVT_KEY_BREAK(KEY_RIGHT):
385 chainMenu(menuViewTelemetryNMEA2);
386 break;
387 case EVT_KEY_LONG(KEY_UP):
388 NMEA_DisableRXD();
389 chainMenu(menuStatisticsView);
390 break;
391 case EVT_KEY_LONG(KEY_DOWN):
392 NMEA_DisableRXD();
393 chainMenu(menuMainView);
394 break;
395 case EVT_KEY_FIRST(KEY_MENU):
396 if (show_timer == 0) {
397 show_timer = 1;
398 if (gpstimer <= 0)
399 gpstimer = bintime(rbuf[2]);
401 else
402 show_timer = 0;
403 break;
404 case EVT_KEY_FIRST(KEY_EXIT):
405 if ((show_timer == 1) &&(rbuf[2][0]))
406 gpstimer = bintime(rbuf[2]); // get actual GPS time ->resets timer to 00:00
407 break;
410 How to use:
412 You choose the values to be displayed using the function:
414 initval(<number>, <packet>, <value>);
415 -------------------------------------
417 That means that "<value>" of "<packet>" is stored in the <number> buffer.
418 The first <number> is 0.
420 Here are the packet names and the associated value names:
422 Position packet (beginning with "GGA"): "PACK_GGA"
423 value names: "TIM", "LAT", "NOS", "LON", "EOW", "FIX", "SAT", "DIL", "ALT", "MTR", "GEO", "MET", "AGE", "DIF",
425 Required minimum packet (beginning with "RMC"): "PACK_RMC"
426 value names: "TIM", "NRW", "LT1", "NSO", "LN1", "EWE", "SOG", "COG", "DAT", "MAG", "EAW"
428 The buffers are accessed using the macro "VALSTR(<n>)", where "<n>" is "0"
429 for the first buffer, and "1" for the second buffer.
431 When a value is missing, it is replaced by the contents of val_unknown ("?").
434 if (ggareceived)
436 gpstime=bintime(rbuf[2]);
437 ggareceived=0;
440 initval (LONG_BUF(0), PACK_RMC, TIM); // sets rbuf[0][.]
441 initval (LONG_BUF(1), PACK_RMC, DAT); // sets rbuf[1][.]
442 initval (SHORT_BUF(0), PACK_RMC, NRW); // sets sbuf[0]
443 initval (SHORT_BUF(2), PACK_GGA, SAT); // -> sbuf[2]
446 title ('1');
447 lcdDrawText ( 2*FW, 1*FH, PSTR("UTC-Time Sat"));
449 if (rbuf[0][0]) { // show always if data have been received
450 lcdDrawChar ( 19*FW, 1*FH, sbuf[2], 0); // satellites in view
451 lcdDrawSizedText ( 2*FW, 2*FH, &rbuf[0][0], 2, APSIZE); // hours
452 lcdDrawChar ( 6*FW, 2*FH, ':', DBLSIZE); // ":"
453 lcdDrawSizedText ( 8*FW, 2*FH, &rbuf[0][2], 2, APSIZE); // minutes
454 lcdDrawChar ( 12*FW, 2*FH, ':', DBLSIZE); // ":"
455 lcdDrawSizedText ( 14*FW, 2*FH, &rbuf[0][4], 2, APSIZE); // seconds
457 else
458 lcdDrawText ( 2*FW, 2*FH, val_unknown, APSIZE); // "?"
460 if ((show_timer == 1) && rbuf[0][0]) { // show the Timer when data have been received
462 lcdDrawText ( 2*FW, 4*FH, PSTR("Timer")); // display "Timer"
463 drawTimer ( 5*FW, 5*FH, (gpstime-gpstimer), DBLSIZE, DBLSIZE); // display difference as mm:ss
465 else
467 lcdDrawText ( 2*FW, 4*FH, PSTR("Date")); // show the UTC Date
469 if (rbuf[1][0]) {
470 lcdDrawSizedText( 2*FW, 5*FH, &rbuf[1][0], 2, APSIZE); // year
471 lcdDrawChar ( 6*FW, 5*FH, '/', DBLSIZE); // "/"
472 lcdDrawSizedText( 8*FW, 5*FH, &rbuf[1][2], 2, APSIZE); // month
473 lcdDrawChar (12*FW, 5*FH, '/', DBLSIZE); // "/"
474 lcdDrawSizedText(14*FW, 5*FH, &rbuf[1][4], 2, APSIZE); // day
476 else
477 lcdDrawText ( 2*FW, 5*FH, val_unknown, APSIZE); // "?"
483 void menuViewTelemetryNMEA2(event_t event)
485 static uint8_t ignore_break;
488 switch(event)
490 // Menu navigation
491 case EVT_KEY_BREAK(KEY_LEFT):
492 if (ignore_break==1) {
493 ignore_break=0;
494 break;}
495 chainMenu(menuViewTelemetryNMEA1);
496 break;
497 case EVT_KEY_BREAK(KEY_RIGHT):
498 if (ignore_break==1) {
499 ignore_break=0;
500 break;}
501 chainMenu(menuViewTelemetryNMEA3);
502 break;
503 case EVT_KEY_LONG(KEY_UP):
504 NMEA_DisableRXD();
505 chainMenu(menuStatisticsView);
506 break;
507 case EVT_KEY_LONG(KEY_DOWN):
508 NMEA_DisableRXD();
509 chainMenu(menuMainView);
510 break;
512 //Beep setting
513 case EVT_KEY_LONG(KEY_LEFT):
514 ignore_break = 1;
515 beep_on=0;
516 AUDIO_KEY_PRESS();
517 break;
518 case EVT_KEY_LONG(KEY_RIGHT):
519 ignore_break = 1;
520 beep_on=1;
521 AUDIO_KEY_PRESS();
522 break;
524 //Altitude setting
525 /* Set a home position for altitude. Normally used before starting
526 the model when GPS has got a fix.
527 MENU[short] --> alternating relative and absolute altitudes
528 MENU[long] --> set home altitude to current
529 EXIT[long] --> reset max altitude to 0
531 Switch ON / OFF short beep with positive lift
532 LEFT[long] --> Positive lift Beep off
533 RIGHT[long] --> Positive lift Beep on */
536 case EVT_KEY_BREAK(KEY_MENU):
537 if (ignore_break==1) {
538 ignore_break=0;
539 break;}
541 if (!home_alt) // umschalten zwischen absoluter und relativer H�he
542 home_alt = save_alt;
543 else
544 home_alt=0;
546 if (save_alt==0) // wenn noch keine Home H�he gesetzt war, wird sie es jetzt, weil sonst
547 // das Umschalten keine Wirkung zeigt
548 save_alt = home_alt = abs_alt; // absolute altitude
549 AUDIO_KEY_PRESS();
550 break;
552 case EVT_KEY_LONG(KEY_MENU):
553 ignore_break = 1;
554 save_alt = home_alt = abs_alt; // Home altitude auf aktuelle absolute H�he setzen
555 AUDIO_KEY_PRESS();
556 break;
558 case EVT_KEY_LONG(KEY_EXIT): // Max Altitude auf 0 zur�cksetzen
559 max_alt=0;
560 AUDIO_KEY_PRESS();
561 break;
564 title ('2');
566 lcdDrawText ( 1*FW, 1*FH, PSTR("Altitude Sat Max"));
569 lcdDrawText ( 16*FW, 3*FH, PSTR("Home"));
570 lcdDrawText ( 2*FW, 4*FH, PSTR("Lift") );
572 lcdDrawText ( 16*FW, 5*FH, PSTR("Beep") );
573 if (beep_on==1)
574 lcdDrawText ( 18*FW, 6*FH, PSTR("ON") );
576 else
577 lcdDrawText ( 17*FW, 6*FH, PSTR("OFF") );
580 lcdDrawNumber( 20*FW, 4*FH, home_alt, PREC1, 6); // display home_alt, small characters
582 if (xpack[0] != PACK_GGA)
583 ggareceived = 0;
585 initval (LONG_BUF(0), PACK_GGA, ALT); // -> rbuf[0]
586 initval (LONG_BUF(1), PACK_GGA, GEO); // -> rbuf[1]
587 initval (SHORT_BUF(0), PACK_GGA, MTR); // -> sbuf[0]
588 initval (SHORT_BUF(1), PACK_GGA, FIX); // -> sbuf[1]
589 initval (SHORT_BUF(2), PACK_GGA, SAT); // -> sbuf[2]
591 if (ggareceived) // at least one second has elapsed
593 ggareceived = 0;
595 /* ALT and GEO have one single digit following the decimal point
596 e.g. ALT=359.7 GEO=47.7
597 The altitude over mean sea level is to be calculated as:
598 altitude minus geoidal separation
601 abs_alt = binary(rbuf[0]) - binary(rbuf[1]); // alt - geo that is absolute altitude
603 if (abs_alt> max_alt) max_alt=abs_alt; // hold max altitude relative to 0 m
605 rel_alt=abs_alt - home_alt; // alt - geo - home altitude relative to home
608 lift_alt = rel_alt - prev_alt;
609 prev_alt = rel_alt;
611 if ((lift_alt >= 0) && (sbuf[1]>0x30) && beep_on) // GGA record must have Fix> 0
612 AUDIO_KEY_PRESS(); // short blip for non negative lift
616 if (rbuf[0][0]) {
617 lcdDrawChar ( 13*FW, 1*FH, sbuf[2], 0); // satellites in view
619 if (sbuf[1]>0x30) { // & GGA has FIX > 0
622 lcdDrawNumber( 10*FW, 2*FH, rel_alt, DBLSIZE|PREC1, 7); // altitude
624 if (home_alt >= 0)
625 lcdDrawNumber( 20*FW, 2*FH, (max_alt-home_alt), PREC1, 6); // display small characters
626 else
627 lcdDrawNumber( 20*FW, 2*FH, max_alt, PREC1, 6); // display small characters
630 lcdDrawChar ( 11*FW, 3*FH, sbuf[0], 0); // dimension [m]
632 lcdDrawNumber( 10*FW, 5*FH, lift_alt, DBLSIZE|PREC1, 6); // lift
633 lcdDrawChar ( 11*FW, 6*FH, sbuf[0], 0); // dimension [m/S]
634 lcdDrawText ( 12*FW, 6*FH, PSTR("/S") );
637 else {
638 lcdDrawText ( 2*FW, 2*FH, val_unknown, APSIZE);
639 lcdDrawText ( 2*FW, 5*FH, val_unknown, APSIZE);
645 void menuViewTelemetryNMEA3(event_t event)
647 switch(event)
649 case EVT_KEY_BREAK(KEY_LEFT):
650 chainMenu(menuViewTelemetryNMEA2);
651 break;
652 case EVT_KEY_BREAK(KEY_RIGHT):
653 chainMenu(menuViewTelemetryNMEA4);
654 break;
655 case EVT_KEY_LONG(KEY_UP):
656 NMEA_DisableRXD();
657 chainMenu(menuStatisticsView);
658 break;
659 case EVT_KEY_LONG(KEY_DOWN):
660 NMEA_DisableRXD();
661 chainMenu(menuMainView);
662 break;
664 initval (LONG_BUF(0), PACK_RMC, SOG);
665 initval (LONG_BUF(1), PACK_RMC, COG);
666 initval (SHORT_BUF(2), PACK_GGA, SAT); // -> sbuf[2]
667 title ('3');
668 lcdDrawText ( 0*FW, 1*FH, PSTR("GrndSpeed[knt] Sat"));
669 if (rbuf[0][0]) // if first position is 00, buffer is empty, taken as false
670 { // any other value is true
671 uint8_t i = 0;
672 while (rbuf[0][i])
674 if (rbuf[0][i] == '.') // find decimal point and insert End of String 3 positions higher
676 rbuf[0][i+3] = 0;
677 break;
679 i++;
681 lcdDrawText ( 2*FW, 2*FH, VALSTR(0), APSIZE); // speed over ground
683 else
684 lcdDrawText ( 2*FW, 2*FH, val_unknown, APSIZE);
686 lcdDrawChar ( 19*FW, 1*FH, sbuf[2], 0); // satellites in view
688 lcdDrawText ( 1*FW, 4*FH, PSTR("Course over ground") );
689 lcdDrawText ( 2*FW, 5*FH, VALSTR(1), APSIZE); // course over ground
694 void menuViewTelemetryNMEA4(event_t event)
696 switch(event) // new event received, branch accordingly
698 case EVT_KEY_BREAK(KEY_LEFT):
699 chainMenu(menuViewTelemetryNMEA3);
700 break;
701 case EVT_KEY_BREAK(KEY_RIGHT):
702 chainMenu(menuViewTelemetryNMEA1);
703 break;
704 case EVT_KEY_LONG(KEY_UP):
705 NMEA_DisableRXD();
706 chainMenu(menuStatisticsView);
707 break;
708 case EVT_KEY_LONG(KEY_DOWN):
709 NMEA_DisableRXD();
710 chainMenu(menuMainView);
711 break;
713 // expecting LAT value in POS packet to be stored in the first buffer
714 initval (LONG_BUF(0), PACK_GGA, LAT);
715 initval (SHORT_BUF(0), PACK_GGA, NOS);
716 // and LON value in POS packet stored in the second buffer
717 initval (LONG_BUF(1), PACK_GGA, LON);
718 initval (SHORT_BUF(1), PACK_GGA, EOW);
719 initval (SHORT_BUF(2), PACK_GGA, SAT); // -> sbuf[2]
720 // title of the screen
721 title ('4');
722 lcdDrawText ( 3*FW, 1*FH, PSTR("Latitude Sat")); // line 1 column 3
723 // first buffer into line 2 column 2
724 if (rbuf[0][0])
726 lcdDrawChar ( 13*FW, 1*FH, sbuf[0], 0); // N or S
727 lcdDrawChar ( 19*FW, 1*FH, sbuf[2], 0); // satellites in view
728 lcdDrawSizedText ( 1*FW, 2*FH, rbuf[0], 2, APSIZE);
729 lcdDrawChar ( 5*FW, 2*FH, '@',0);
730 lcdDrawText ( 6*FW, 2*FH, &rbuf[0][2], APSIZE); // minutes with small decimal point
732 else
733 lcdDrawText ( 2*FW, 2*FH, val_unknown, APSIZE);
734 lcdDrawText ( 3*FW, 4*FH, PSTR("Longitude")); // line 4 column 5
735 // second buffer into line 5 column 2
736 if (rbuf[0][0])
738 lcdDrawChar ( 13*FW, 4*FH, sbuf[1], 0); // E or W
739 lcdDrawSizedText ( 0*FW, 5*FH, rbuf[1], 3, APSIZE);
740 lcdDrawChar ( 6*FW, 5*FH, '@',0);
741 lcdDrawText ( 7*FW, 5*FH, &rbuf[1][3], APSIZE); // minutes with small decimal point
744 else
745 lcdDrawText ( 2*FW, 5*FH, val_unknown, APSIZE);
748 void title(char x)
750 lcdDrawText (0*FW, 0*FH, PSTR(" GPS NMEA data ?/4 "), INVERS);
751 lcdDrawChar(16*FW, 0*FH, x, INVERS);
754 void initval(uint8_t num, uint8_t pack, uint8_t val)
756 if (xpack[num] != pack || xval[num] != val)
758 if (num < NB_LONG_BUF) {
759 ibuf[num] = rbuf[num][0] = 0;
761 else
762 sbuf[num-NB_LONG_BUF] = '?';
763 xpack[num] = pack;
764 xval[num] = val;
765 state = WAIT_PACKET; // synchronize to the next packet
769 int32_t binary (char *str)
771 int32_t numval = 0;
772 uint8_t sign = 0;
774 while (*str) {
775 if (*str == '-')
776 sign = 1;
777 else if (*str >= '0' && *str <= '9')
778 numval = numval * 10 + (*str - '0');
779 str++;
781 if (sign)
782 numval = -numval;
783 return numval;
786 int32_t bintime (char *str)
788 int32_t numval=0;
790 if (*str) {
791 numval = ((str[0] - '0') * 10l) + (str[1] - '0'); // hours
792 numval = numval * 3600l;
793 numval = numval + ((( (str[2] - '0') * 10l) + (str[3] - '0')) * 60l); // minutes
794 numval = numval + ((str[4] - '0') * 10l) + (str[5] - '0'); // seconds
796 return numval;
799 Without NMEA:
801 Size after:
802 AVR Memory Usage
803 ----------------
804 Device: atmega64
806 Program: 54226 bytes (82.7% Full)
807 (.text + .data + .bootloader)
809 Data: 3440 bytes (84.0% Full)
810 (.data + .bss + .noinit)
812 ----------------------------------
814 With NMEA:
816 Size after:
817 AVR Memory Usage
818 ----------------
819 Device: atmega64
821 Program: 57098 bytes (87.1% Full)
822 (.text + .data + .bootloader)
824 Data: 3524 bytes (86.0% Full)
825 (.data + .bss + .noinit)