30#define PX_NMEA_BUFFER_SIZE 128
34 PX_NMEA_RX_STATE_START = 0,
35 PX_NMEA_RX_STATE_PAYLOAD,
36 PX_NMEA_RX_STATE_CHECKSUM1,
37 PX_NMEA_RX_STATE_CHECKSUM2,
38 PX_NMEA_RX_STATE_END_CR,
39 PX_NMEA_RX_STATE_END_LF,
52static uint8_t px_nmea_rx_buf[PX_NMEA_BUFFER_SIZE];
53static uint16_t px_nmea_rx_index;
54static uint8_t px_nmea_rx_checksum;
55static px_nmea_rx_state_t px_nmea_rx_state;
58static void px_nmea_tx_byte (uint8_t data);
60static bool px_nmea_cmp_nibble_with_hex_ascii(uint8_t nibble,
char ascii);
61static char * px_nmea_parse_str_to_u32 (
char * buf, uint32_t * value);
62static char * px_nmea_parse_str_to_s16 (
char * buf, int16_t * value);
63static char * px_nmea_parse_str_to_u16 (
char * buf, uint16_t * value);
64static char * px_nmea_parse_str_fraction_to_u16(
char * buf, uint16_t * value, uint8_t precision);
65static char * px_nmea_parse_str_to_u8 (
char * buf, uint8_t * value);
66static char * px_nmea_parse_str_fraction_to_u8 (
char * buf, uint8_t * value, uint8_t precision);
67static char * px_nmea_find_next_param (
char * buf);
69static void px_nmea_on_rx_frame (
char * buf);
72static void px_nmea_tx_byte(uint8_t data)
74 if(px_nmea_tx_byte_fn ==
NULL)
78 (*px_nmea_tx_byte_fn)(data);
81static bool px_nmea_cmp_nibble_with_hex_ascii(uint8_t nibble,
char ascii)
102static char * px_nmea_parse_str_to_u32(
char * buf, uint32_t * value)
104 uint32_t u32Value = 0;
105 while((*buf !=
',') && (*buf !=
'.') && (*buf !=
'\0'))
114 u32Value += (*buf++) -
'0';
120static char * px_nmea_parse_str_to_s16(
char * buf, int16_t * value)
123 int16_t s16Value = 0;
125 while((*buf !=
',') && (*buf !=
'.') && (*buf !=
'\0'))
141 s16Value += (*buf++) -
'0';
144 if(bNeg) s16Value *= -1;
150static char * px_nmea_parse_str_to_u16(
char * buf, uint16_t * value)
152 uint16_t u16Value = 0;
153 while((*buf !=
',') && (*buf !=
'.') && (*buf !=
'\0'))
162 u16Value += (*buf++) -
'0';
168static char * px_nmea_parse_str_fraction_to_u16(
char * buf, uint16_t * value, uint8_t precision)
170 uint16_t u16Value = 0;
171 while((*buf !=
',') && (*buf !=
'.') && (*buf !=
'\0') && (precision != 0))
180 u16Value += (*buf++) -
'0';
183 while(precision != 0)
192static char * px_nmea_parse_str_to_u8(
char * buf, uint8_t * value)
195 while((*buf !=
',') && (*buf !=
'.') && (*buf !=
'\0'))
204 u8Value += (*buf++) -
'0';
210static char * px_nmea_parse_str_fraction_to_u8(
char * buf, uint8_t * value, uint8_t precision)
213 while((*buf !=
',') && (*buf !=
'.') && (*buf !=
'\0') && (precision != 0))
222 u8Value += (*buf++) -
'0';
225 while(precision != 0)
234static char * px_nmea_find_next_param(
char * buf)
238 if(*buf ==
'\0')
return buf;
244static void px_nmea_on_rx_frame(
char * buf)
247 (*px_nmea_on_valid_str_fn)(buf);
263 if(px_nmea_data.gga_valid_flag)
270 px_nmea_data.gga_valid_flag =
false;
271 px_nmea_data.latitude_fraction = 0;
272 px_nmea_data.longitude_fraction = 0;
274 buf = px_nmea_parse_str_to_u32(buf, &px_nmea_data.utc_time);
278 buf = px_nmea_parse_str_fraction_to_u16(buf, &px_nmea_data.utc_time_fraction, 3);
280 buf = px_nmea_find_next_param(buf);
283 buf = px_nmea_parse_str_to_u16(buf, (uint16_t *)&px_nmea_data.latitude);
287 buf = px_nmea_parse_str_fraction_to_u16(buf, &px_nmea_data.latitude_fraction, 4);
289 buf = px_nmea_find_next_param(buf);
292 px_nmea_data.latitude *= -1;
294 buf = px_nmea_find_next_param(buf);
297 buf = px_nmea_parse_str_to_u16(buf, (uint16_t *)&px_nmea_data.longitude);
301 buf = px_nmea_parse_str_fraction_to_u16(buf, &px_nmea_data.longitude_fraction, 4);
303 buf = px_nmea_find_next_param(buf);
306 px_nmea_data.longitude *= -1;
308 buf = px_nmea_find_next_param(buf);
312 px_nmea_data.gga_valid_flag =
true;
314 buf = px_nmea_find_next_param(buf);
316 buf = px_nmea_parse_str_to_u8(buf, &px_nmea_data.sattelites_used);
317 buf = px_nmea_find_next_param(buf);
319 buf = px_nmea_parse_str_to_u8(buf, &px_nmea_data.hdop);
323 buf = px_nmea_parse_str_fraction_to_u8(buf, &px_nmea_data.hdop_fraction, 1);
325 buf = px_nmea_find_next_param(buf);
327 buf = px_nmea_parse_str_to_s16(buf, &px_nmea_data.altitude);
331 buf = px_nmea_parse_str_fraction_to_u8(buf, &px_nmea_data.altitude_fraction, 2);
334 px_nmea_data.gga_valid_flag =
true;
337 if(px_nmea_data.gga_valid_flag && px_nmea_data.vtg_valid_flag)
339 (*px_nmea_on_valid_gps_data_fn)();
340 px_nmea_data.gga_valid_flag =
false;
341 px_nmea_data.vtg_valid_flag =
false;
350 buf = px_nmea_parse_str_to_u16(buf,&px_nmea_data.heading);
354 buf = px_nmea_parse_str_fraction_to_u8(buf,&px_nmea_data.heading_fraction,2);
356 buf = px_nmea_find_next_param(buf);
357 buf = px_nmea_find_next_param(buf);
358 buf = px_nmea_find_next_param(buf);
359 buf = px_nmea_find_next_param(buf);
360 buf = px_nmea_find_next_param(buf);
361 buf = px_nmea_find_next_param(buf);
364 buf = px_nmea_parse_str_to_u8(buf,&px_nmea_data.speed);
368 buf = px_nmea_parse_str_fraction_to_u8(buf,&px_nmea_data.speed_fraction,2);
371 px_nmea_data.vtg_valid_flag =
true;
374 if(px_nmea_data.gga_valid_flag && px_nmea_data.vtg_valid_flag)
376 (*px_nmea_on_valid_gps_data_fn)();
377 px_nmea_data.gga_valid_flag =
false;
378 px_nmea_data.vtg_valid_flag =
false;
389 px_nmea_tx_byte_fn = tx_byte;
390 px_nmea_on_valid_str_fn = on_valid_str;
391 px_nmea_on_valid_gps_data_fn = on_valid_gps_data;
394 px_nmea_rx_state = PX_NMEA_RX_STATE_START;
395 px_nmea_rx_index = 0;
396 px_nmea_data.gga_valid_flag =
false;
397 px_nmea_data.vtg_valid_flag =
false;
402 switch(px_nmea_rx_state)
404 case PX_NMEA_RX_STATE_START :
411 px_nmea_rx_state = PX_NMEA_RX_STATE_PAYLOAD;
413 px_nmea_rx_checksum = 0;
414 px_nmea_rx_index = 0;
417 case PX_NMEA_RX_STATE_PAYLOAD :
430 px_nmea_rx_state = PX_NMEA_RX_STATE_CHECKSUM1;
434 px_nmea_rx_checksum ^= data;
436 px_nmea_rx_buf[px_nmea_rx_index] = data;
438 if(++px_nmea_rx_index >= (PX_NMEA_BUFFER_SIZE-1))
444 case PX_NMEA_RX_STATE_CHECKSUM1 :
447 if(!px_nmea_cmp_nibble_with_hex_ascii(((px_nmea_rx_checksum>>4)&0x0f), data))
452 px_nmea_rx_state = PX_NMEA_RX_STATE_CHECKSUM2;
455 case PX_NMEA_RX_STATE_CHECKSUM2 :
458 if(!px_nmea_cmp_nibble_with_hex_ascii((px_nmea_rx_checksum&0x0f),data))
463 px_nmea_rx_state = PX_NMEA_RX_STATE_END_CR;
466 case PX_NMEA_RX_STATE_END_CR :
473 px_nmea_rx_state = PX_NMEA_RX_STATE_END_LF;
476 case PX_NMEA_RX_STATE_END_LF:
484 px_nmea_rx_buf[px_nmea_rx_index] =
'\0';
486 px_nmea_on_rx_frame((
char *)px_nmea_rx_buf);
491 px_nmea_rx_state = PX_NMEA_RX_STATE_START;
497 uint8_t checksum =
'$';
504 px_nmea_tx_byte(data);
508 px_nmea_tx_byte(
'*');
512 px_nmea_tx_byte(((checksum >> 4) & 0x0f) +
'0');
516 px_nmea_tx_byte(((checksum >> 4) & 0x0f) + (
'A' - 10));
522 px_nmea_tx_byte(checksum +
'0');
526 px_nmea_tx_byte(checksum + (
'A' - 10));
530 px_nmea_tx_byte(
'\r');
531 px_nmea_tx_byte(
'\n');
#define NULL
NULL pointer.
#define PX_LOG_NAME(name)
Macro to declare a log name string once for each file to reduce code size.
void(* px_nmea_on_valid_gps_data_t)(void)
Definition for a pointer to a function that will be called when GPS data is valid.
#define PX_NMEA_GGA_STR
Time, position and fix type data.
void(* px_nmea_on_valid_str_t)(const char *data)
Definition for a pointer to a function that when a valid NMEA string is received.
#define PX_NMEA_VTG_STR
Course and speed information relative to the ground.
void(* px_nmea_tx_byte_t)(uint8_t data)
Definition for a pointer to a function that will be called to send a character.
void px_nmea_tx_frame(char *frame)
Function that is called to send an NMEA frame with the checksum appended.
void px_nmea_on_rx_byte(uint8_t data)
Function handler that is fed all raw received data.
void px_nmea_init(px_nmea_tx_byte_t tx_byte, px_nmea_on_valid_str_t on_valid_str, px_nmea_on_valid_gps_data_t on_valid_gps_data)
Initialise NMEA parser module.
Parsed time, position, quality data.