508 lines
17 KiB
C++
508 lines
17 KiB
C++
#include <NeoGPS_cfg.h>
|
|
#include <ublox/ubxGPS.h>
|
|
#include <NeoTeeStream.h>
|
|
|
|
//======================================================================
|
|
// Program: ubloxRate.ino
|
|
//
|
|
// Description: This program sends ublox commands to enable and disable
|
|
// NMEA sentences, set the update rate, and set the
|
|
// baud rate to 9600 or 115200.
|
|
//
|
|
// Enter the following commands through the Serial Monitor window:
|
|
//
|
|
const char help[] PROGMEM = R"(
|
|
'?' - dislay this help message
|
|
'1' - send NMEA PUBX text command to enable all sentences
|
|
'0' - send NMEA PUBX text command to disable all sentences except GLL
|
|
'd' - send UBX binary command to disable all sentences except GLL
|
|
'r1' - send UBX binary command to set update rate to 1Hz
|
|
'r5' - send UBX binary command to set update rate to 5Hz
|
|
'r0' - send UBX binary command to set update rate to 10Hz
|
|
'r6' - send UBX binary command to set update rate to 16Hz
|
|
're' - send UBX binary command to reset the GPS device (cold start)
|
|
'5' - send NMEA PUBX text command to set baud rate to 115200
|
|
'7' - send NMEA PUBX text command to set baud rate to 57600
|
|
'3' - send NMEA PUBX text command to set baud rate to 38400
|
|
'9' - send NMEA PUBX text command to set baud rate to 9600
|
|
'e' - toggle echo of all characters received from GPS device.
|
|
't' - toggle tracing of parsed GPS fields.
|
|
)";
|
|
// CAUTION: If your Serial Monitor window baud rate is less
|
|
// than the GPS baud rate, turning echo ON will cause the
|
|
// sketch to lose some or all GPS data and/or fixes.
|
|
//
|
|
// NOTE: All NMEA PUBX text commands are also echoed to the debug port.
|
|
//
|
|
// Prerequisites:
|
|
// 1) Your GPS device has been correctly powered.
|
|
// Be careful when connecting 3.3V devices.
|
|
// 2) Your GPS device is correctly connected to an Arduino serial port.
|
|
// See GPSport.h for the default connections.
|
|
// 3) You know the default baud rate of your GPS device.
|
|
// If 9600 does not work, use NMEAdiagnostic.ino to
|
|
// scan for the correct baud rate.
|
|
// 4) LAST_SENTENCE_IN_INTERVAL is defined to be
|
|
// the following in NMEAGPS_cfg.h:
|
|
//
|
|
// #include <stdint.h>
|
|
// extern uint8_t LastSentenceInInterval; // a variable!
|
|
// #define LAST_SENTENCE_IN_INTERVAL \
|
|
// ((NMEAGPS::nmea_msg_t) LastSentenceInInterval)
|
|
//
|
|
// This is a replacement for the typical
|
|
//
|
|
// #define LAST_SENTENCE_IN_INTERVAL NMEAGPS::NMEA_GLL
|
|
//
|
|
// This allows the sketch to choose the last sentence *at run time*, not
|
|
// compile time. This is necessary because this sketch can send
|
|
// configuration commands that change which sentences are enabled.
|
|
// The storage for the "externed" variable is below.
|
|
// 5) ublox.ino builds correctly (see its prequisites).
|
|
//
|
|
// 'Serial' is for debug output to the Serial Monitor window.
|
|
//
|
|
// License:
|
|
// Copyright (C) 2014-2018, 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
|
|
|
|
#ifdef NMEAGPS_INTERRUPT_PROCESSING
|
|
#error You must *not* enable NMEAGPS_INTERRUPT_PROCESSING in NMEAGPS_cfg.h!
|
|
#endif
|
|
|
|
#ifndef NMEAGPS_DERIVED_TYPES
|
|
#error You must enable NMEAGPS_DERIVED_TYPES in NMEAGPS_cfg.h!
|
|
#endif
|
|
|
|
#if !defined(NMEAGPS_PARSE_GLL)
|
|
#error You must enable NMEAGPS_PARSE_GLL 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
|
|
|
|
//-----------------------------------------------------------------
|
|
|
|
static ubloxGPS gps( &gpsPort );
|
|
static gps_fix fix_data;
|
|
uint8_t LastSentenceInInterval = 0xFF; // storage for the run-time selection
|
|
|
|
static char lastChar; // last command char
|
|
static bool echoing = false;
|
|
static bool tracing = true;
|
|
|
|
// Use NeoTee to echo the NMEA text commands to the Serial Monitor window
|
|
Stream *both[2] = { &DEBUG_PORT, &gpsPort };
|
|
NeoTeeStream tee( both, sizeof(both)/sizeof(both[0]) );
|
|
|
|
//-------------------------------------------
|
|
// U-blox UBX binary commands
|
|
|
|
const unsigned char ubxRate1Hz[] PROGMEM =
|
|
{ 0x06,0x08,0x06,0x00,0xE8,0x03,0x01,0x00,0x01,0x00 };
|
|
const unsigned char ubxRate5Hz[] PROGMEM =
|
|
{ 0x06,0x08,0x06,0x00,200,0x00,0x01,0x00,0x01,0x00 };
|
|
const unsigned char ubxRate10Hz[] PROGMEM =
|
|
{ 0x06,0x08,0x06,0x00,100,0x00,0x01,0x00,0x01,0x00 };
|
|
const unsigned char ubxRate16Hz[] PROGMEM =
|
|
{ 0x06,0x08,0x06,0x00,50,0x00,0x01,0x00,0x01,0x00 };
|
|
|
|
// Disable specific NMEA sentences
|
|
const unsigned char ubxDisableGGA[] PROGMEM =
|
|
{ 0x06,0x01,0x08,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x01 };
|
|
const unsigned char ubxDisableGLL[] PROGMEM =
|
|
{ 0x06,0x01,0x08,0x00,0xF0,0x01,0x00,0x00,0x00,0x00,0x00,0x01 };
|
|
const unsigned char ubxDisableGSA[] PROGMEM =
|
|
{ 0x06,0x01,0x08,0x00,0xF0,0x02,0x00,0x00,0x00,0x00,0x00,0x01 };
|
|
const unsigned char ubxDisableGSV[] PROGMEM =
|
|
{ 0x06,0x01,0x08,0x00,0xF0,0x03,0x00,0x00,0x00,0x00,0x00,0x01 };
|
|
const unsigned char ubxDisableRMC[] PROGMEM =
|
|
{ 0x06,0x01,0x08,0x00,0xF0,0x04,0x00,0x00,0x00,0x00,0x00,0x01 };
|
|
const unsigned char ubxDisableVTG[] PROGMEM =
|
|
{ 0x06,0x01,0x08,0x00,0xF0,0x05,0x00,0x00,0x00,0x00,0x00,0x01 };
|
|
const unsigned char ubxDisableZDA[] PROGMEM =
|
|
{ 0x06,0x01,0x08,0x00,0xF0,0x08,0x00,0x00,0x00,0x00,0x00,0x01 };
|
|
|
|
static const uint8_t ubxReset[] __PROGMEM =
|
|
{ ublox::UBX_CFG, ublox::UBX_CFG_RST,
|
|
UBX_MSG_LEN(ublox::cfg_reset_t), 0, // word length MSB is 0
|
|
0,0, // clear bbr section
|
|
ublox::cfg_reset_t::CONTROLLED_SW_RESET_GPS_ONLY, // reset mode
|
|
0x00 // reserved
|
|
};
|
|
|
|
void resetGPS()
|
|
{
|
|
enum sendUBXmethod_t
|
|
{
|
|
FROM_RAM_STRUCT,
|
|
FROM_PROGMEM_BYTES,
|
|
FROM_PROGMEM_STRUCT
|
|
};
|
|
|
|
const sendUBXmethod_t WAY = FROM_PROGMEM_STRUCT; // pick one
|
|
|
|
switch (WAY) {
|
|
case FROM_RAM_STRUCT:
|
|
{
|
|
ublox::cfg_reset_t cfg_cold; // RAM
|
|
cfg_cold.clear_bbr_section =
|
|
// Hotstart
|
|
{ false };
|
|
|
|
// Warmstart
|
|
// { true, false };
|
|
|
|
// Coldstart
|
|
// { true, true, true, true, true, true, true, true, true,
|
|
// true, // reserved1 is 2 bits
|
|
// true, true, true,
|
|
// true, // reserved2 is 1 bit
|
|
// true };
|
|
|
|
cfg_cold.reset_mode = ublox::cfg_reset_t::CONTROLLED_SW_RESET_GPS_ONLY;
|
|
cfg_cold.reserved = 0;
|
|
gps.send_request( cfg_cold );
|
|
}
|
|
break;
|
|
|
|
case FROM_PROGMEM_BYTES:
|
|
sendUBX( ubxReset, sizeof(ubxReset) ); // just send the PROGMEM bytes
|
|
break;
|
|
|
|
case FROM_PROGMEM_STRUCT:
|
|
{
|
|
const ublox::cfg_reset_t *cfg_cold_ptr = (const ublox::cfg_reset_t *) ubxReset;
|
|
gps.send_request_P( *cfg_cold_ptr );
|
|
}
|
|
break;
|
|
}
|
|
|
|
} // resetGPS
|
|
|
|
//--------------------------
|
|
|
|
void sendUBX( const unsigned char *progmemBytes, size_t len )
|
|
{
|
|
gpsPort.write( 0xB5 ); // SYNC1
|
|
gpsPort.write( 0x62 ); // SYNC2
|
|
|
|
uint8_t a = 0, b = 0;
|
|
while (len-- > 0) {
|
|
uint8_t c = pgm_read_byte( progmemBytes++ );
|
|
a += c;
|
|
b += a;
|
|
gpsPort.write( c );
|
|
}
|
|
|
|
gpsPort.write( a ); // CHECKSUM A
|
|
gpsPort.write( b ); // CHECKSUM B
|
|
|
|
} // sendUBX
|
|
|
|
//-------------------------------------------
|
|
// U-blox NMEA text commands
|
|
|
|
const char disableRMC[] PROGMEM = "PUBX,40,RMC,0,0,0,0,0,0";
|
|
const char disableGLL[] PROGMEM = "PUBX,40,GLL,0,0,0,0,0,0";
|
|
const char disableGSV[] PROGMEM = "PUBX,40,GSV,0,0,0,0,0,0";
|
|
const char disableGSA[] PROGMEM = "PUBX,40,GSA,0,0,0,0,0,0";
|
|
const char disableGGA[] PROGMEM = "PUBX,40,GGA,0,0,0,0,0,0";
|
|
const char disableVTG[] PROGMEM = "PUBX,40,VTG,0,0,0,0,0,0";
|
|
const char disableZDA[] PROGMEM = "PUBX,40,ZDA,0,0,0,0,0,0";
|
|
|
|
const char enableRMC[] PROGMEM = "PUBX,40,RMC,0,1,0,0,0,0";
|
|
const char enableGLL[] PROGMEM = "PUBX,40,GLL,0,1,0,0,0,0";
|
|
const char enableGSV[] PROGMEM = "PUBX,40,GSV,0,1,0,0,0,0";
|
|
const char enableGSA[] PROGMEM = "PUBX,40,GSA,0,1,0,0,0,0";
|
|
const char enableGGA[] PROGMEM = "PUBX,40,GGA,0,1,0,0,0,0";
|
|
const char enableVTG[] PROGMEM = "PUBX,40,VTG,0,1,0,0,0,0";
|
|
const char enableZDA[] PROGMEM = "PUBX,40,ZDA,0,1,0,0,0,0";
|
|
|
|
const char baud9600 [] PROGMEM = "PUBX,41,1,3,3,9600,0";
|
|
const char baud38400 [] PROGMEM = "PUBX,41,1,3,3,38400,0";
|
|
const char baud57600 [] PROGMEM = "PUBX,41,1,3,3,57600,0";
|
|
const char baud115200[] PROGMEM = "PUBX,41,1,3,3,115200,0";
|
|
|
|
//--------------------------
|
|
|
|
const uint32_t COMMAND_DELAY = 250;
|
|
|
|
void changeBaud( const char *textCommand, unsigned long baud )
|
|
{
|
|
gps.send_P( &tee, (const __FlashStringHelper *) disableRMC );
|
|
delay( COMMAND_DELAY );
|
|
gps.send_P( &tee, (const __FlashStringHelper *) disableGLL );
|
|
delay( COMMAND_DELAY );
|
|
gps.send_P( &tee, (const __FlashStringHelper *) disableGSV );
|
|
delay( COMMAND_DELAY );
|
|
gps.send_P( &tee, (const __FlashStringHelper *) disableGSA );
|
|
delay( COMMAND_DELAY );
|
|
gps.send_P( &tee, (const __FlashStringHelper *) disableGGA );
|
|
delay( COMMAND_DELAY );
|
|
gps.send_P( &tee, (const __FlashStringHelper *) disableVTG );
|
|
delay( COMMAND_DELAY );
|
|
gps.send_P( &tee, (const __FlashStringHelper *) disableZDA );
|
|
delay( 500 );
|
|
gps.send_P( &tee, (const __FlashStringHelper *) textCommand );
|
|
gpsPort.flush();
|
|
gpsPort.end();
|
|
|
|
DEBUG_PORT.print( F("All sentences disabled for baud rate ") );
|
|
DEBUG_PORT.print( baud );
|
|
DEBUG_PORT.println( F(" change. Enter '1' to reenable sentences.") );
|
|
delay( 500 );
|
|
gpsPort.begin( baud );
|
|
|
|
} // changeBaud
|
|
|
|
//------------------------------------
|
|
|
|
static void doSomeWork()
|
|
{
|
|
// Print all the things!
|
|
|
|
if (tracing)
|
|
trace_all( DEBUG_PORT, gps, fix_data );
|
|
|
|
} // doSomeWork
|
|
|
|
//--------------------------
|
|
|
|
void setup()
|
|
{
|
|
DEBUG_PORT.begin(9600);
|
|
while (!DEBUG_PORT)
|
|
;
|
|
|
|
DEBUG_PORT.println( F("ubloxRate.INO: started\r\n"
|
|
"Looking for GPS device on " GPS_PORT_NAME "\r\n"
|
|
"Enter '?' for help.") );
|
|
|
|
#ifdef NMEAGPS_INTERRUPT_PROCESSING
|
|
#error You must *NOT* define NMEAGPS_INTERRUPT_PROCESSING in NMEAGPS_cfg.h!
|
|
#endif
|
|
|
|
#if !defined( NMEAGPS_PARSE_GGA ) & !defined( NMEAGPS_PARSE_GLL ) & \
|
|
!defined( NMEAGPS_PARSE_GSA ) & !defined( NMEAGPS_PARSE_GSV ) & \
|
|
!defined( NMEAGPS_PARSE_RMC ) & !defined( NMEAGPS_PARSE_VTG ) & \
|
|
!defined( NMEAGPS_PARSE_ZDA ) & !defined( NMEAGPS_PARSE_GST )
|
|
|
|
DEBUG_PORT.println( F("\nWARNING: No NMEA sentences are enabled: no fix data will be displayed.") );
|
|
|
|
#else
|
|
if (gps.merging == NMEAGPS::NO_MERGING) {
|
|
DEBUG_PORT.print ( F("\nWARNING: displaying data from ") );
|
|
DEBUG_PORT.print ( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) );
|
|
DEBUG_PORT.print ( F(" sentences ONLY, and only if ") );
|
|
DEBUG_PORT.print ( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) );
|
|
DEBUG_PORT.println( F(" is enabled.\n"
|
|
" Other sentences may be parsed, but their data will not be displayed.") );
|
|
}
|
|
#endif
|
|
|
|
// Make sure the run-time selectable LAST_SENTENCE is
|
|
// configured correctly in NMEAGPS_cfg.h
|
|
for (uint8_t i=0; i < 1; i++) {
|
|
if (LastSentenceInInterval != LAST_SENTENCE_IN_INTERVAL) {
|
|
DEBUG_PORT.println(
|
|
F("LAST_SENTENCE_IN_INTERVAL is not properly defined in NMEAGPS_cfg.h!\n"
|
|
" See Prerequisite 4 above") );
|
|
for (;;); // hang here!
|
|
}
|
|
LastSentenceInInterval ++;
|
|
}
|
|
LastSentenceInInterval = NMEAGPS::NMEA_GLL;
|
|
|
|
trace_header( DEBUG_PORT );
|
|
DEBUG_PORT.flush();
|
|
|
|
gpsPort.begin( 9600 );
|
|
}
|
|
|
|
void loop()
|
|
{
|
|
// Check for commands
|
|
|
|
if (DEBUG_PORT.available()) {
|
|
char c = DEBUG_PORT.read();
|
|
|
|
switch (c) {
|
|
case '?':
|
|
DEBUG_PORT.print( (const __FlashStringHelper *) help );
|
|
echoing = false;
|
|
tracing = false;
|
|
DEBUG_PORT.print( F("Enter command> ") );
|
|
break;
|
|
|
|
case '0':
|
|
if (lastChar == 'r') {
|
|
sendUBX( ubxRate10Hz, sizeof(ubxRate10Hz) );
|
|
} else {
|
|
gps.send_P( &tee, (const __FlashStringHelper *) disableRMC );
|
|
delay( COMMAND_DELAY );
|
|
gps.send_P( &tee, (const __FlashStringHelper *) enableGLL );
|
|
delay( COMMAND_DELAY );
|
|
gps.send_P( &tee, (const __FlashStringHelper *) disableGSV );
|
|
delay( COMMAND_DELAY );
|
|
gps.send_P( &tee, (const __FlashStringHelper *) disableGSA );
|
|
delay( COMMAND_DELAY );
|
|
gps.send_P( &tee, (const __FlashStringHelper *) disableGGA );
|
|
delay( COMMAND_DELAY );
|
|
gps.send_P( &tee, (const __FlashStringHelper *) disableVTG );
|
|
delay( COMMAND_DELAY );
|
|
gps.send_P( &tee, (const __FlashStringHelper *) disableZDA );
|
|
LastSentenceInInterval = NMEAGPS::NMEA_GLL;
|
|
}
|
|
break;
|
|
case '1':
|
|
if (lastChar == 'r') {
|
|
sendUBX( ubxRate1Hz, sizeof(ubxRate1Hz) );
|
|
} else {
|
|
gps.send_P( &tee, (const __FlashStringHelper *) enableRMC );
|
|
delay( COMMAND_DELAY );
|
|
gps.send_P( &tee, (const __FlashStringHelper *) enableGLL );
|
|
delay( COMMAND_DELAY );
|
|
gps.send_P( &tee, (const __FlashStringHelper *) enableGSV );
|
|
delay( COMMAND_DELAY );
|
|
gps.send_P( &tee, (const __FlashStringHelper *) enableGSA );
|
|
delay( COMMAND_DELAY );
|
|
gps.send_P( &tee, (const __FlashStringHelper *) enableGGA );
|
|
delay( COMMAND_DELAY );
|
|
gps.send_P( &tee, (const __FlashStringHelper *) enableVTG );
|
|
delay( COMMAND_DELAY );
|
|
gps.send_P( &tee, (const __FlashStringHelper *) enableZDA );
|
|
LastSentenceInInterval = NMEAGPS::NMEA_ZDA;
|
|
}
|
|
break;
|
|
case '3':
|
|
changeBaud( baud38400, 38400UL );
|
|
break;
|
|
case '5':
|
|
if (lastChar == 'r') {
|
|
sendUBX( ubxRate5Hz, sizeof(ubxRate5Hz) );
|
|
} else {
|
|
changeBaud( baud115200, 115200UL );
|
|
}
|
|
break;
|
|
case '6':
|
|
if (lastChar == 'r') {
|
|
sendUBX( ubxRate16Hz, sizeof(ubxRate16Hz) );
|
|
}
|
|
break;
|
|
case '7':
|
|
changeBaud( baud57600, 57600UL );
|
|
break;
|
|
case '9':
|
|
changeBaud( baud9600, 9600UL );
|
|
break;
|
|
|
|
case 'd':
|
|
sendUBX( ubxDisableRMC, sizeof(ubxDisableRMC) );
|
|
delay( COMMAND_DELAY );
|
|
//sendUBX( ubxDisableGLL, sizeof(ubxDisableGLL) );
|
|
sendUBX( ubxDisableGSV, sizeof(ubxDisableGSV) );
|
|
delay( COMMAND_DELAY );
|
|
sendUBX( ubxDisableGSA, sizeof(ubxDisableGSA) );
|
|
delay( COMMAND_DELAY );
|
|
sendUBX( ubxDisableGGA, sizeof(ubxDisableGGA) );
|
|
delay( COMMAND_DELAY );
|
|
sendUBX( ubxDisableVTG, sizeof(ubxDisableVTG) );
|
|
delay( COMMAND_DELAY );
|
|
sendUBX( ubxDisableZDA, sizeof(ubxDisableZDA) );
|
|
LastSentenceInInterval = NMEAGPS::NMEA_GLL;
|
|
break;
|
|
|
|
case 'e':
|
|
if (lastChar == 'r') {
|
|
resetGPS();
|
|
} else {
|
|
echoing = !echoing;
|
|
}
|
|
break;
|
|
|
|
case 't':
|
|
tracing = !tracing;
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
lastChar = c;
|
|
}
|
|
|
|
// Check for GPS data
|
|
|
|
static bool displayingHex = false;
|
|
|
|
if (echoing) {
|
|
// Use advanced character-oriented methods to echo received characters to
|
|
// the Serial Monitor window.
|
|
if (gpsPort.available()) {
|
|
|
|
char c = gpsPort.read();
|
|
|
|
if (((' ' <= c) && (c <= '~')) || (c == '\r') || (c == '\n')) {
|
|
DEBUG_PORT.write( c );
|
|
displayingHex = false;
|
|
} else {
|
|
if (!displayingHex) {
|
|
displayingHex = true;
|
|
DEBUG_PORT.print( F("0x") );
|
|
}
|
|
if (c < 0x10)
|
|
DEBUG_PORT.write( '0' );
|
|
DEBUG_PORT.print( (uint8_t) c, HEX );
|
|
DEBUG_PORT.write( ' ' );
|
|
}
|
|
|
|
gps.handle( c );
|
|
if (gps.available()) {
|
|
fix_data = gps.read();
|
|
|
|
if (displayingHex)
|
|
displayingHex = false;
|
|
DEBUG_PORT.println();
|
|
doSomeWork();
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
// Use the normal fix-oriented methods to display fixes
|
|
if (gps.available( gpsPort )) {
|
|
fix_data = gps.read();
|
|
doSomeWork();
|
|
displayingHex = false;
|
|
}
|
|
}
|
|
}
|