Data Structures | Defines | Typedefs | Enumerations | Functions | Variables

gps-parser.h File Reference

interface to GPS parser More...

#include <stdint.h>
#include <avr/pgmspace.h>
#include <stdlib.h>
#include <string.h>
#include <usarts.h>
#include <ff.h>

Go to the source code of this file.

Data Structures

struct  gps_time_s
 store GPS timestamp (time of day) More...
struct  gps_date_s
 store GPS date (day) More...
struct  gps_dms_s
 store one dimension of coordinate (degrees/minutes/seconds) More...
struct  gps_dop_s
 store "dilution of precision" More...
struct  gps_height_s
 store height info More...
struct  gps_sat_s
 store data for one satellite More...
struct  gps_position_t
 store all GPS data used for GPX logging More...
struct  gps_proto_functions_s
 function pointers to protocol-specific parser More...
struct  gps_proto_parser_s
 protocol-specific parser interface More...
struct  gps_parser_s
 internal state of parser More...

Defines

#define GPS_DEGREE_SCALE   (10000000L)
#define GPS_DEGREE_SCALE_EXP   (7)
#define MAX_NUM_SATS   (18)
 maximum number of satellites to allocate in data
#define PROTO_CALL(FUNCP, ARGS...)
 call a protocol-specific function

Typedefs

typedef struct gps_time_s gps_time_t
 store GPS timestamp (time of day)
typedef struct gps_date_s gps_date_t
 store GPS date (day)
typedef int32_t gps_degree_t
 store one dimension of coordinate
typedef struct gps_dms_s gps_dms_t
 store one dimension of coordinate (degrees/minutes/seconds)
typedef struct gps_dop_s gps_dop_t
 store "dilution of precision"
typedef struct gps_height_s gps_height_t
 store height info
typedef struct gps_sat_s gps_sat_t
 store data for one satellite
typedef struct gps_parser_s gps_parser_t
typedef struct
gps_proto_functions_s 
gps_proto_functions_t
 function pointers to protocol-specific parser
typedef struct gps_proto_parser_s gps_proto_parser_t
 protocol-specific parser interface

Enumerations

enum  gps_line_status_t {
  GPS_LINE_MORE = 0, GPS_LINE_CKERR, GPS_LINE_OVERFLOW, GPS_LINE_OK,
  GPS_LINE_FIX, GPS_LINE_TIME, GPS_LINE_SAT
}
 

return status for gps_recvd()

More...
enum  gps_proto_t { GPSPROTO_NONE = 0, GPSPROTO_NMEA, GPSPROTO_SiRF, GPSPROTO_NUMPROTOS }
 

GPS data formats.


Functions

gps_dms_t gps_degree_to_dms (gps_degree_t v)
 convert gps_degree_t into sign/degrees/minutes/Seconds
gps_parser_tnew_gps_parser (usart_control_t *usart)
 create a new GPS parser instance
void free_gps_parser (gps_parser_t *parser)
 free a GPS parser instance
gps_proto_t gps_get_proto (gps_parser_t *parser)
 get currently used GPS protocol
gps_proto_t gps_set_proto (gps_parser_t *parser, gps_proto_t newproto, baudrate_t baud)
 switch to another GPS protocol
void gps_timestamp_set_trigger (gps_parser_t *parser, uint8_t trigger)
 set the trigger byte for timestamping
void gps_timestamp_start_of_message (gps_parser_t *parser)
 mark start of message
baudrate_t gps_set_baudrate (gps_parser_t *parser, baudrate_t baudrate)
 set baudrate of USART
void gps_start_log (gps_parser_t *parser)
 start logging of raw GPS data
gps_line_status_t gps_recvd (gps_parser_t *parser, usart_rxdata_t c)
 give one character to GPS parser
uint8_t gps_usart_can_recv (gps_parser_t *parser)
gps_line_status_t gps_usart_recv_and_handle (gps_parser_t *parser, usart_rxdata_t *c)
 get one character from USART and give that to GPS parser
int gps_format_position (char *buf, size_t sz, gps_parser_t *parser)
 format current position for output
gps_sat_tgps_get_satellite (gps_parser_t *parser, uint8_t idx)
 return reception status for one satellite
uint8_t gps_get_time (gps_parser_t *parser, gps_date_t *pdate, gps_time_t *ptime)
 get current time
uint8_t gps_get_position (gps_parser_t *parser, gps_degree_t *plat, gps_degree_t *plon)
 get current position
uint8_t gps_get_height (gps_parser_t *parser, gps_height_t *pheight)
 get height above WGS84 ellipsoid
uint8_t gps_get_hdop (gps_parser_t *parser, gps_dop_t *phdop)
uint8_t gps_get_data (gps_parser_t *parser, gps_position_t *data)
 get current GPS data, to be passed to hlog_record()
uint8_t gps_get_source (gps_parser_t *parser, const char **psrc, const char **pproto, baudrate_t *baud)
 get source parameter
uint8_t gps_usart_is_active (gps_parser_t *parser)
 tell whether USART is active
void gps_usart_power (gps_parser_t *parser, uint8_t onoff)
 set power status for USART used by that parser
void gps_set_parsed_time (gps_parser_t *parser, gps_date_t date, gps_time_t time)
 provide parsed time to generic GPS layer

Variables

const gps_proto_functions_t gps_proto_sirf
const gps_proto_functions_t gps_proto_nmea

Detailed Description

interface to GPS parser


Define Documentation

#define PROTO_CALL (   FUNCP,
  ARGS... 
)
Value:
__extension__({                                                 \
    __typeof__(*FUNCP) __p = (__typeof__(*FUNCP))pgm_read_word (FUNCP); \
    (__p) (ARGS);                                                       \
  })

call a protocol-specific function


Typedef Documentation

typedef int32_t gps_degree_t

store one dimension of coordinate

The data is stored as $value*10^7$. Positive value means North/East, negative means South/West.


Enumeration Type Documentation

return status for gps_recvd()

Enumerator:
GPS_LINE_MORE 

line is not complete yet

GPS_LINE_CKERR 

checksum error

GPS_LINE_OVERFLOW 

too many characters for buffer

GPS_LINE_OK 

line OK

GPS_LINE_FIX 

position fix

GPS_LINE_TIME 

date and time

GPS_LINE_SAT 

SAT info

             {
  GPS_LINE_MORE = 0, 
  GPS_LINE_CKERR,    
  GPS_LINE_OVERFLOW, 
  GPS_LINE_OK,       
  GPS_LINE_FIX,      
  GPS_LINE_TIME,     
  GPS_LINE_SAT,      
} gps_line_status_t;


Function Documentation

uint8_t gps_get_data ( gps_parser_t parser,
gps_position_t data 
)

get current GPS data, to be passed to hlog_record()

Parameters:
parser 
data pointer to store GPS data
Returns:
1 if date/time and position is valid, 0 otherwise

                                                                    {
  int res = 0;
  res = gps_get_time (parser, &data->date, &data->time);
  gps_get_position (parser, &data->lat, &data->lon);
  gps_get_height (parser, &data->height);
  gps_get_hdop (parser, &data->hdop);
  return res;
}

uint8_t gps_get_height ( gps_parser_t parser,
gps_height_t pheight 
)

get height above WGS84 ellipsoid

Parameters:
parser 
pheight pointer to store height into
Returns:
1 if GPS height data is valid

{
  *pheight = parser->height;
  return 1;
}

uint8_t gps_get_position ( gps_parser_t parser,
gps_degree_t plat,
gps_degree_t plon 
)

get current position

Parameters:
parser 
plat pointer to store latitude into
plon pointer to store longitude into
Returns:
1 if GPS position data is valid

{
  *plat = parser->lat;
  *plon = parser->lon;
  return 1;
}

gps_sat_t* gps_get_satellite ( gps_parser_t parser,
uint8_t  idx 
)

return reception status for one satellite

Parameters:
parser 
idx index of satellite to get status for
Returns:
pointer to satellite status, NULL if idx is invalid

{
  gps_parser_t * p = parser;
  if (idx < sizeof(p->satellites)/sizeof(p->satellites[0])
      && idx < p->num_sats)
    return &p->satellites[idx];
  else
    return NULL;
}

uint8_t gps_get_time ( gps_parser_t parser,
gps_date_t pdate,
gps_time_t ptime 
)

get current time

Parameters:
parser 
pdate pointer to place date into, if not NULL
ptime pointer to place time into, if not NULL
Returns:
1 if GPS time makes sense, 0 otherwise

{
  gps_parser_t * p = parser;
  if (!p->date.month)
    return 0;

  if (pdate) *pdate = p->date;
  if (ptime) *ptime = p->time;
  return 1;
}

gps_line_status_t gps_recvd ( gps_parser_t parser,
usart_rxdata_t  c 
)

give one character to GPS parser

Returns:
information about last received line (if any)

{
  if (c.flags) {
    /* Trigger baud rate detection */
    if (c.flags & USART_FRAME_ERROR) {
      uint16_t d = c.data;
      uint8_t i;
      uint8_t faster = 0;

      parser->autobaud.frame_errors++;

      /* add start and stop bits */
      d |= 0xFF00;
      d <<= 1;
      for (i = 7; i; i--) {
        if ((d & 0x07) == 0x02 || (d & 0x07) == 0x05) {
          faster = ++parser->autobaud.faster;
          break;
        }
        d >>= 1;
      }

      if (faster >= 20
          /* prevent overflow */
          && parser->autobaud.baud*2
          <= pgm_read_dword (&parser->proto_parser->func->baudrate_max)) {
        baudrate_t old = parser->autobaud.baud;
        gps_change_baudrate (parser, +1);
        printf_P (PSTR("AUTOBAUD(%lu=>%lu)\r\n"), old, parser->autobaud.baud);
        return GPS_LINE_CKERR;
      }

      /* slow down ? */
      d = c.data;
      d |= 0xFF00;
      d <<= 1;

      d ^= d >> 1;
      d &= 0x55;
      if (d == 0) {
        parser->autobaud.slower++;
        if (parser->autobaud.slower >= 40
            && parser->autobaud.baud > 1200 /* limit */) {
          baudrate_t old = parser->autobaud.baud;
          gps_change_baudrate (parser, -1);
          printf_P (PSTR("AUTOBAUD(%lu=>%lu)\r\n"), old, parser->autobaud.baud);
          return GPS_LINE_CKERR;
        }
      }
    }

    /* save timestamp-related data */
    if (c.flags & USART_TIMESTAMPED) {
      parser->msg_timestamp[0].tcnt2 = usart_get_timestamp (parser->usart);
    }
  }
  return PROTO_CALL(&(parser->proto_parser->func->recvd), parser, c);
}

void gps_set_parsed_time ( gps_parser_t parser,
gps_date_t  date,
gps_time_t  time 
)

provide parsed time to generic GPS layer

gps_set_parsed_time() is intended to be called from the protocol-specific module to provide the time parsed from a GPS message.

If the time has changed compared to the time already stored in *parser, this function adjusts the internal clock assuming the current message is the first message in the dataset.

{
  gps_parser_t *p = parser;

  uint8_t changed = 0;

#ifdef DEBUG
  printf_P (PSTR("TIME %04u-%02u-%02u %02u:%02u:%05u\r\n"),
            date.year ? date.year : p->date.year, date.month, date.day,
            time.hour, time.min, time.msec);
#endif

  if (date.year) {
    if (date.year < 100 && p->date.year > 100) {
      date.year = date.year + ((p->date.year/100)*100);
    }
  }

  if (date.year && date.month && date.day) {
    changed = p->date.year != date.year || p->date.month != date.month
      || p->date.day != date.day;
    if (changed) p->date = date;
  }
  if (changed || p->time.hour >= time.hour || p->time.min >= time.min
      || p->time.msec >= time.msec) {
    changed |= 1;
    p->time = time;
  }

  if (changed) {
    clock_time_t clktime =
      {
        .year = date.year, .month = date.month, .day = date.day,
        .hour = time.hour, .min = time.min, .sec = time.msec/1000,
      };
    if (date.year == 0)
      clktime.year = p->date.year;
    if (date.month == 0)
      clktime.month = p->date.month;
    if (date.day == 0)
      clktime.day = p->date.day;

    /* call clock adjustment */
    clock_adjust (p->msg_timestamp_ticks, p->msg_timestamp[1].tcnt2,
                  strcmp_P (p->usart_name, PSTR("USART3"))
                  ? CLOCKADJ_GPS_MOD : CLOCKADJ_GPS_EXT,
                  &clktime);
  }
}

gps_proto_t gps_set_proto ( gps_parser_t parser,
gps_proto_t  newproto,
baudrate_t  baud 
)

switch to another GPS protocol

Switch to another GPS protocol if it is obvious how to do that. This function does not try to figure out a way for the switch in the case a switch to an intermediate protocol is needed.

Parameters:
parser instance of parser to switch protocol for
newproto requested protocol
baud requested new baud rate
Returns:
protocol used by parser after return. In most cases this will either be new when the switch was successful or the old protocol otherwise.

{
  const gps_proto_functions_t * f1 = parser->proto_parser->func;
  __typeof__ (f1->switchproto) sw
    = (__typeof__(f1->switchproto)) pgm_read_word (&f1->switchproto);
  if (sw) {
    const gps_proto_functions_t * f = (sw) (parser, newproto, baud);
    if (f && f != f1) {
      PROTO_CALL(&parser->proto_parser->func->freeparser, parser);
      parser->proto_parser = PROTO_CALL(&f->newparser, parser);
    }
  }
  return gps_get_proto (parser);
}

void gps_start_log ( gps_parser_t parser  ) 

start logging of raw GPS data

Parameters:
parser 

{
  gps_parser_t *p = parser;
  FIL * logfile;

  if (!p->usart_name) return;

  logfile = malloc (sizeof(FIL));
  if (logfile) {
    XCHAR fname[16];
    FRESULT r;
    strcpy (fname, p->usart_name);
    strcat_P (fname, PSTR(".log\0"));
    printf_P (PSTR("f_open(%s)\r\n"), fname);
    r = f_open (logfile, fname, FA_WRITE | FA_OPEN_ALWAYS);
    if (r == FR_OK) {
      /* seek to end for append */
      r = f_lseek (logfile, logfile->fsize);
      if (r != FR_OK) {
        printf_P (PSTR("f_lseek(%s,%lu) failed: %d\r\n"),
                  fname, logfile->fsize, r);
        f_close (logfile);
        goto free_file;
      }
      p->logfile = logfile;
    } else {
      printf_P (PSTR("f_open(%s) failed: %d\r\n"), fname, r);
    free_file:
      free (logfile);
    }
  }
}

void gps_timestamp_set_trigger ( gps_parser_t parser,
uint8_t  trigger 
) [inline]

set the trigger byte for timestamping

gps_timestamp_set_trigger() is intended to be called from the protocol-specific module to set the byte which triggers timestamping.

{
  usart_timestamp_set_trigger (parser->usart, trigger);
}

void gps_timestamp_start_of_message ( gps_parser_t parser  )  [inline]

mark start of message

gps_timestamp_start_of_message() should be called by the protocol-specific module when its state machine thinks a message has started

{
  parser->msg_timestamp[1] = parser->msg_timestamp[0];
  parser->msg_timestamp_ticks = hl_get_current_time().ticks;
}

gps_parser_t* new_gps_parser ( usart_control_t usart  ) 

create a new GPS parser instance

Parameters:
usart USART structure to be used for control messages

{
  gps_parser_t * p = malloc (sizeof (*p));
  uint8_t i;

  p->usart = usart;
  p->date.year = 2000;
  p->date.month = 0;
  p->date.day = 0;
  p->num_sats = 0;
  for (i=0; i < MAX_NUM_SATS; i++)
    p->satellites[i].snr = 0xFF;

  gps_init_autobaud (p, 2400);

  p->usart_name = malloc (strlen_P(usart->name)+1);
  if (p->usart_name)
    strcpy_P (p->usart_name, usart->name);

  p->logfile = NULL;

  p->proto_parser = PROTO_CALL(&gps_proto_nmea.newparser, p);
  return p;
}