/*
- derived from TinyGPS
*/
//
#ifndef GpsNEO6_h
#define GpsNEO6_h
//
#include <Arduino.h>
#include <stdlib.h>
//
#define _GPS_VERSION 13 // software version of this library
#define _GPS_MPH_PER_KNOT 1.15077945
#define _GPS_MPS_PER_KNOT 0.51444444
#define _GPS_KMPH_PER_KNOT 1.852
#define _GPS_MILES_PER_METER 0.00062137112
#define _GPS_KM_PER_METER 0.001
#define _GPRMC_TERM "GPRMC"
#define _GPGGA_TERM "GPGGA"
//
class CGpsNEO6
{
  public:
  // Constant
  static const float GPS_INVALID_F_ANGLE, GPS_INVALID_F_ALTITUDE, GPS_INVALID_F_SPEED;
  // Type
  enum 
  {
    _GPS_SENTENCE_GPGGA, 
    _GPS_SENTENCE_GPRMC, 
    _GPS_SENTENCE_OTHER
  };
  enum 
  {
    GPS_INVALID_AGE = 0xFFFFFFFF,      GPS_INVALID_ANGLE = 999999999, 
    GPS_INVALID_ALTITUDE = 999999999,  GPS_INVALID_DATE = 0,
    GPS_INVALID_TIME = 0xFFFFFFFF,		 GPS_INVALID_SPEED = 999999999, 
    GPS_INVALID_FIX_TIME = 0xFFFFFFFF, GPS_INVALID_SATELLITES = 0xFF,
    GPS_INVALID_HDOP = 0xFFFFFFFF
  };
  private:
  // Field
  unsigned long _time, _new_time;
  unsigned long _date, _new_date;
  long _latitude, _new_latitude;
  long _longitude, _new_longitude;
  long _altitude, _new_altitude;
  unsigned long  _speed, _new_speed;
  unsigned long  _course, _new_course;
  unsigned long  _hdop, _new_hdop;
  unsigned short _numsats, _new_numsats;
  unsigned long _last_time_fix, _new_time_fix;
  unsigned long _last_position_fix, _new_position_fix;
  // 
  byte _parity;
  bool _is_checksum_term;
  char _term[15];
  byte _sentence_type;
  byte _term_number;
  byte _term_offset;
  bool _gps_data_good;
#ifndef _GPS_NO_STATS 
  unsigned long _encoded_characters;
  unsigned short _good_sentences;
  unsigned short _failed_checksum;
  unsigned short _passed_checksum;
#endif
  // Utility
  int from_hex(char a);
  unsigned long parse_decimal();
  unsigned long parse_degrees();
  bool term_complete();
  bool gpsisdigit(char c) { return c >= '0' && c <= '9'; }
  long gpsatol(const char *str);
  int gpsstrcmp(const char *str1, const char *str2);  public:
  //
  public:
  CGpsNEO6();
  bool encode(char c); // process one character received from GPS
  CGpsNEO6 &operator << (char c) {encode(c); return *this;}
  // lat/long in MILLIONTHs of a degree and age of fix in milliseconds
  // (note: versions 12 and earlier gave lat/long in 100,000ths of a degree.
  void GetPosition(long *latitude, long *longitude, unsigned long *fix_age = 0);
  // date as ddmmyy, time as hhmmsscc, and age in milliseconds
  void get_datetime(unsigned long *date, unsigned long *time, unsigned long *age = 0);
  // signed altitude in centimeters (from GPGGA sentence)
  inline long altitude() { return _altitude; }
  // course in last full GPRMC sentence in 100th of a degree
  inline unsigned long course() { return _course; }
  // speed in last full GPRMC sentence in 100ths of a knot
  inline unsigned long speed() { return _speed; }
  // satellites used in last full GPGGA sentence
  inline unsigned short GetCountSatellites(void) { return _numsats; }
  // horizontal dilution of precision in 100ths
  inline unsigned long hdop() { return _hdop; }
  void GetLocation(float *latitude, float *longitude, 
                   unsigned long *fix_age = 0);
  void ReadDateTime(int *year, byte *month, byte *day, 
                      byte *hours, byte *minutes, byte *seconds, 
                      byte *millis = 0, unsigned long *fixage = 0);
  float GetAltitude(void);
  float f_course();
  float f_speed_knots();
  float f_speed_mph();
  float f_speed_mps();
  float f_speed_kmph();
  static int library_version() { return _GPS_VERSION; }
  static float distance_between (float lat1, float long1, float lat2, float long2);
  static float course_to (float lat1, float long1, float lat2, float long2);
  static const char *cardinal(float course);
#ifndef _GPS_NO_STATS
  void GetStatistics(unsigned long *countcharacters, 
                     unsigned short *countgood, 
                     unsigned short *countfailed);
#endif
};
//
#endif // GpsNEO6
//