400 lines
12 KiB
Arduino
400 lines
12 KiB
Arduino
|
#include <NeoGPS_cfg.h>
|
||
|
#include <ublox/ubxGPS.h>
|
||
|
|
||
|
//======================================================================
|
||
|
// Program: ublox.ino
|
||
|
//
|
||
|
// Prerequisites:
|
||
|
// 1) You have a ublox GPS device
|
||
|
// 2) PUBX.ino works with your device
|
||
|
// 3) You have installed the ubxGPS.* and ubxmsg.* files.
|
||
|
// 4) At least one UBX message has been enabled in ubxGPS.h.
|
||
|
// 5) Implicit Merging is disabled in NMEAGPS_cfg.h.
|
||
|
//
|
||
|
// Description: This program parses UBX binary protocal messages from
|
||
|
// ublox devices. It shows how to acquire the information necessary
|
||
|
// to use the GPS Time-Of-Week in many UBX messages. As an offset
|
||
|
// from midnight Sunday morning (GPS time), you also need the current
|
||
|
// UTC time (this is *not* GPS time) and the current number of GPS
|
||
|
// leap seconds.
|
||
|
//
|
||
|
// Serial is for debug output to the Serial Monitor window.
|
||
|
//
|
||
|
// License:
|
||
|
// Copyright (C) 2014-2017, SlashDevin
|
||
|
//
|
||
|
// This file is part of NeoGPS
|
||
|
//
|
||
|
// NeoGPS is free software: you can redistribute it and/or modify
|
||
|
// it under the terms of the GNU General Public License as published by
|
||
|
// the Free Software Foundation, either version 3 of the License, or
|
||
|
// (at your option) any later version.
|
||
|
//
|
||
|
// NeoGPS is distributed in the hope that it will be useful,
|
||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
// GNU General Public License for more details.
|
||
|
//
|
||
|
// You should have received a copy of the GNU General Public License
|
||
|
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
|
||
|
//
|
||
|
//======================================================================
|
||
|
|
||
|
#include <GPSport.h>
|
||
|
|
||
|
#include <Streamers.h>
|
||
|
|
||
|
//------------------------------------------------------------
|
||
|
// Check that the config files are set up properly
|
||
|
|
||
|
#ifndef NMEAGPS_DERIVED_TYPES
|
||
|
#error You must "#define NMEAGPS_DERIVED_TYPES" in NMEAGPS_cfg.h!
|
||
|
#endif
|
||
|
|
||
|
#if !defined(UBLOX_PARSE_STATUS) & !defined(UBLOX_PARSE_TIMEGPS) & \
|
||
|
!defined(UBLOX_PARSE_TIMEUTC) & !defined(UBLOX_PARSE_POSLLH) & \
|
||
|
!defined(UBLOX_PARSE_DOP) & !defined(UBLOX_PARSE_PVT) & \
|
||
|
!defined(UBLOX_PARSE_VELNED) & !defined(UBLOX_PARSE_SVINFO) & \
|
||
|
!defined(UBLOX_PARSE_HNR_PVT)
|
||
|
|
||
|
#error No UBX binary messages enabled: no fix data available.
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#ifndef NMEAGPS_RECOGNIZE_ALL
|
||
|
// Resetting the messages with ublox::configNMEA requires that
|
||
|
// all message types are recognized (i.e., the enum has all
|
||
|
// values).
|
||
|
#error You must "#define NMEAGPS_RECOGNIZE_ALL" in NMEAGPS_cfg.h!
|
||
|
#endif
|
||
|
|
||
|
//-----------------------------------------------------------------
|
||
|
// Derive a class to add the state machine for starting up:
|
||
|
// 1) The status must change to something other than NONE.
|
||
|
// 2) The GPS leap seconds must be received
|
||
|
// 3) The UTC time must be received
|
||
|
// 4) All configured messages are "requested"
|
||
|
// (i.e., "enabled" in the ublox device)
|
||
|
// Then, all configured messages are parsed and explicitly merged.
|
||
|
|
||
|
class MyGPS : public ubloxGPS
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
enum
|
||
|
{
|
||
|
GETTING_STATUS,
|
||
|
GETTING_LEAP_SECONDS,
|
||
|
GETTING_UTC,
|
||
|
RUNNING
|
||
|
}
|
||
|
state NEOGPS_BF(8);
|
||
|
|
||
|
MyGPS( Stream *device ) : ubloxGPS( device )
|
||
|
{
|
||
|
state = GETTING_STATUS;
|
||
|
}
|
||
|
|
||
|
//--------------------------
|
||
|
|
||
|
void get_status()
|
||
|
{
|
||
|
static bool acquiring = false;
|
||
|
|
||
|
if (fix().status == gps_fix::STATUS_NONE) {
|
||
|
static uint32_t dotPrint;
|
||
|
bool requestNavStatus = false;
|
||
|
|
||
|
if (!acquiring) {
|
||
|
acquiring = true;
|
||
|
dotPrint = millis();
|
||
|
DEBUG_PORT.print( F("Acquiring...") );
|
||
|
requestNavStatus = true;
|
||
|
|
||
|
} else if (millis() - dotPrint > 1000UL) {
|
||
|
dotPrint = millis();
|
||
|
DEBUG_PORT << '.';
|
||
|
|
||
|
static uint8_t requestPeriod;
|
||
|
if ((++requestPeriod & 0x07) == 0)
|
||
|
requestNavStatus = true;
|
||
|
}
|
||
|
|
||
|
if (requestNavStatus)
|
||
|
// Turn on the UBX status message
|
||
|
enable_msg( ublox::UBX_NAV, ublox::UBX_NAV_STATUS );
|
||
|
|
||
|
} else {
|
||
|
if (acquiring)
|
||
|
DEBUG_PORT << '\n';
|
||
|
DEBUG_PORT << F("Acquired status: ") << (uint8_t) fix().status << '\n';
|
||
|
|
||
|
#if defined(GPS_FIX_TIME) & defined(GPS_FIX_DATE) & \
|
||
|
defined(UBLOX_PARSE_TIMEGPS)
|
||
|
|
||
|
if (!enable_msg( ublox::UBX_NAV, ublox::UBX_NAV_TIMEGPS ))
|
||
|
DEBUG_PORT.println( F("enable TIMEGPS failed!") );
|
||
|
|
||
|
state = GETTING_LEAP_SECONDS;
|
||
|
#else
|
||
|
start_running();
|
||
|
state = RUNNING;
|
||
|
#endif
|
||
|
}
|
||
|
} // get_status
|
||
|
|
||
|
//--------------------------
|
||
|
|
||
|
void get_leap_seconds()
|
||
|
{
|
||
|
#if defined(GPS_FIX_TIME) & defined(GPS_FIX_DATE) & \
|
||
|
defined(UBLOX_PARSE_TIMEGPS)
|
||
|
|
||
|
if (GPSTime::leap_seconds != 0) {
|
||
|
DEBUG_PORT << F("Acquired leap seconds: ") << GPSTime::leap_seconds << '\n';
|
||
|
|
||
|
if (!disable_msg( ublox::UBX_NAV, ublox::UBX_NAV_TIMEGPS ))
|
||
|
DEBUG_PORT.println( F("disable TIMEGPS failed!") );
|
||
|
|
||
|
#if defined(UBLOX_PARSE_TIMEUTC)
|
||
|
if (!enable_msg( ublox::UBX_NAV, ublox::UBX_NAV_TIMEUTC ))
|
||
|
DEBUG_PORT.println( F("enable TIMEUTC failed!") );
|
||
|
state = GETTING_UTC;
|
||
|
#else
|
||
|
start_running();
|
||
|
#endif
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
} // get_leap_seconds
|
||
|
|
||
|
//--------------------------
|
||
|
|
||
|
void get_utc()
|
||
|
{
|
||
|
#if defined(GPS_FIX_TIME) & defined(GPS_FIX_DATE) & \
|
||
|
defined(UBLOX_PARSE_TIMEUTC)
|
||
|
|
||
|
lock();
|
||
|
bool safe = is_safe();
|
||
|
NeoGPS::clock_t sow = GPSTime::start_of_week();
|
||
|
NeoGPS::time_t utc = fix().dateTime;
|
||
|
unlock();
|
||
|
|
||
|
if (safe && (sow != 0)) {
|
||
|
DEBUG_PORT << F("Acquired UTC: ") << utc << '\n';
|
||
|
DEBUG_PORT << F("Acquired Start-of-Week: ") << sow << '\n';
|
||
|
|
||
|
start_running();
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
} // get_utc
|
||
|
|
||
|
//--------------------------
|
||
|
|
||
|
void start_running()
|
||
|
{
|
||
|
bool enabled_msg_with_time = false;
|
||
|
|
||
|
#if defined(UBLOX_PARSE_POSLLH)
|
||
|
if (!enable_msg( ublox::UBX_NAV, ublox::UBX_NAV_POSLLH ))
|
||
|
DEBUG_PORT.println( F("enable POSLLH failed!") );
|
||
|
|
||
|
enabled_msg_with_time = true;
|
||
|
#endif
|
||
|
|
||
|
#if defined(UBLOX_PARSE_PVT)
|
||
|
if (!enable_msg( ublox::UBX_NAV, ublox::UBX_NAV_PVT ))
|
||
|
DEBUG_PORT.println( F("enable PVT failed!") );
|
||
|
|
||
|
enabled_msg_with_time = true;
|
||
|
#endif
|
||
|
|
||
|
#if defined(UBLOX_PARSE_VELNED)
|
||
|
if (!enable_msg( ublox::UBX_NAV, ublox::UBX_NAV_VELNED ))
|
||
|
DEBUG_PORT.println( F("enable VELNED failed!") );
|
||
|
|
||
|
enabled_msg_with_time = true;
|
||
|
#endif
|
||
|
|
||
|
#if defined(UBLOX_PARSE_DOP)
|
||
|
if (!enable_msg( ublox::UBX_NAV, ublox::UBX_NAV_DOP ))
|
||
|
DEBUG_PORT.println( F("enable DOP failed!") );
|
||
|
else
|
||
|
DEBUG_PORT.println( F("enabled DOP.") );
|
||
|
|
||
|
enabled_msg_with_time = true;
|
||
|
#endif
|
||
|
|
||
|
#if defined(UBLOX_PARSE_SVINFO)
|
||
|
if (!enable_msg( ublox::UBX_NAV, ublox::UBX_NAV_SVINFO ))
|
||
|
DEBUG_PORT.println( F("enable SVINFO failed!") );
|
||
|
|
||
|
enabled_msg_with_time = true;
|
||
|
#endif
|
||
|
|
||
|
#if defined(UBLOX_PARSE_TIMEUTC)
|
||
|
|
||
|
#if defined(GPS_FIX_TIME) & defined(GPS_FIX_DATE)
|
||
|
if (enabled_msg_with_time &&
|
||
|
!disable_msg( ublox::UBX_NAV, ublox::UBX_NAV_TIMEUTC ))
|
||
|
DEBUG_PORT.println( F("disable TIMEUTC failed!") );
|
||
|
|
||
|
#elif defined(GPS_FIX_TIME) | defined(GPS_FIX_DATE)
|
||
|
// If both aren't defined, we can't convert TOW to UTC,
|
||
|
// so ask for the separate UTC message.
|
||
|
if (!enable_msg( ublox::UBX_NAV, ublox::UBX_NAV_TIMEUTC ))
|
||
|
DEBUG_PORT.println( F("enable TIMEUTC failed!") );
|
||
|
#endif
|
||
|
|
||
|
#endif
|
||
|
|
||
|
state = RUNNING;
|
||
|
trace_header( DEBUG_PORT );
|
||
|
|
||
|
} // start_running
|
||
|
|
||
|
//--------------------------
|
||
|
|
||
|
bool running()
|
||
|
{
|
||
|
switch (state) {
|
||
|
case GETTING_STATUS : get_status (); break;
|
||
|
case GETTING_LEAP_SECONDS: get_leap_seconds(); break;
|
||
|
case GETTING_UTC : get_utc (); break;
|
||
|
}
|
||
|
|
||
|
return (state == RUNNING);
|
||
|
|
||
|
} // running
|
||
|
|
||
|
} NEOGPS_PACKED;
|
||
|
|
||
|
// Construct the GPS object and hook it to the appropriate serial device
|
||
|
static MyGPS gps( &gpsPort );
|
||
|
|
||
|
#ifdef NMEAGPS_INTERRUPT_PROCESSING
|
||
|
static void GPSisr( uint8_t c )
|
||
|
{
|
||
|
gps.handle( c );
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//--------------------------
|
||
|
|
||
|
static void configNMEA( uint8_t rate )
|
||
|
{
|
||
|
for (uint8_t i=NMEAGPS::NMEA_FIRST_MSG; i<=NMEAGPS::NMEA_LAST_MSG; i++) {
|
||
|
ublox::configNMEA( gps, (NMEAGPS::nmea_msg_t) i, rate );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//--------------------------
|
||
|
|
||
|
static void disableUBX()
|
||
|
{
|
||
|
gps.disable_msg( ublox::UBX_NAV, ublox::UBX_NAV_TIMEGPS );
|
||
|
gps.disable_msg( ublox::UBX_NAV, ublox::UBX_NAV_TIMEUTC );
|
||
|
gps.disable_msg( ublox::UBX_NAV, ublox::UBX_NAV_VELNED );
|
||
|
gps.disable_msg( ublox::UBX_NAV, ublox::UBX_NAV_POSLLH );
|
||
|
gps.disable_msg( ublox::UBX_NAV, ublox::UBX_NAV_DOP );
|
||
|
}
|
||
|
|
||
|
//--------------------------
|
||
|
|
||
|
void setup()
|
||
|
{
|
||
|
// Start the normal trace output
|
||
|
DEBUG_PORT.begin(9600);
|
||
|
while (!DEBUG_PORT)
|
||
|
;
|
||
|
|
||
|
DEBUG_PORT.print( F("ublox binary protocol example started.\n") );
|
||
|
DEBUG_PORT << F("fix object size = ") << sizeof(gps.fix()) << '\n';
|
||
|
DEBUG_PORT << F("ubloxGPS object size = ") << sizeof(ubloxGPS) << '\n';
|
||
|
DEBUG_PORT << F("MyGPS object size = ") << sizeof(gps) << '\n';
|
||
|
DEBUG_PORT.println( F("Looking for GPS device on " GPS_PORT_NAME) );
|
||
|
DEBUG_PORT.flush();
|
||
|
|
||
|
// Start the UART for the GPS device
|
||
|
#ifdef NMEAGPS_INTERRUPT_PROCESSING
|
||
|
gpsPort.attachInterrupt( GPSisr );
|
||
|
#endif
|
||
|
gpsPort.begin(9600);
|
||
|
|
||
|
// Turn off the preconfigured NMEA standard messages
|
||
|
configNMEA( 0 );
|
||
|
|
||
|
// Turn off things that may be left on by a previous build
|
||
|
disableUBX();
|
||
|
|
||
|
#if 0
|
||
|
// Test a Neo M8 message -- should be rejected by Neo-6 and Neo7
|
||
|
ublox::cfg_nmea_v1_t test;
|
||
|
|
||
|
test.always_output_pos = false; // invalid or failed
|
||
|
test.output_invalid_pos = false;
|
||
|
test.output_invalid_time= false;
|
||
|
test.output_invalid_date= false;
|
||
|
test.use_GPS_only = false;
|
||
|
test.output_heading = false; // even if frozen
|
||
|
test.__not_used__ = false;
|
||
|
|
||
|
test.nmea_version = ublox::cfg_nmea_v1_t::NMEA_V_4_0;
|
||
|
test.num_sats_per_talker_id = ublox::cfg_nmea_v1_t::SV_PER_TALKERID_UNLIMITED;
|
||
|
|
||
|
test.compatibility_mode = false;
|
||
|
test.considering_mode = true;
|
||
|
test.max_line_length_82 = false;
|
||
|
test.__not_used_1__ = 0;
|
||
|
|
||
|
test.filter_gps = false;
|
||
|
test.filter_sbas = false;
|
||
|
test.__not_used_2__= 0;
|
||
|
test.filter_qzss = false;
|
||
|
test.filter_glonass= false;
|
||
|
test.filter_beidou = false;
|
||
|
test.__not_used_3__= 0;
|
||
|
|
||
|
test.proprietary_sat_numbering = false;
|
||
|
test.main_talker_id = ublox::cfg_nmea_v1_t::MAIN_TALKER_ID_GP;
|
||
|
test.gsv_uses_main_talker_id = true;
|
||
|
test.beidou_talker_id[0] = 'G';
|
||
|
test.beidou_talker_id[1] = 'P';
|
||
|
|
||
|
DEBUG_PORT << F("CFG_NMEA result = ") << gps.send( test );
|
||
|
#endif
|
||
|
|
||
|
while (!gps.running())
|
||
|
if (gps.available( gpsPort ))
|
||
|
gps.read();
|
||
|
}
|
||
|
|
||
|
//--------------------------
|
||
|
|
||
|
void loop()
|
||
|
{
|
||
|
if (gps.available( gpsPort ))
|
||
|
trace_all( DEBUG_PORT, gps, gps.read() );
|
||
|
|
||
|
// If the user types something, reset the message configuration
|
||
|
// back to a normal set of NMEA messages. This makes it
|
||
|
// convenient to switch to another example program that
|
||
|
// expects a typical set of messages. This also saves
|
||
|
// putting those config messages in every other example.
|
||
|
|
||
|
if (DEBUG_PORT.available()) {
|
||
|
do { DEBUG_PORT.read(); } while (DEBUG_PORT.available());
|
||
|
DEBUG_PORT.println( F("Stopping...") );
|
||
|
|
||
|
configNMEA( 1 );
|
||
|
disableUBX();
|
||
|
gpsPort.flush();
|
||
|
gpsPort.end();
|
||
|
|
||
|
DEBUG_PORT.println( F("STOPPED.") );
|
||
|
for (;;);
|
||
|
}
|
||
|
}
|