Merge pull request #26 from sparkfun/release_candidate

v2.0.6
This commit is contained in:
Paul
2021-04-26 10:28:05 +01:00
committed by GitHub
9 changed files with 904 additions and 53 deletions
@@ -0,0 +1,241 @@
/*
Demonstrate how to log NMEA and UBX data simultaneously
By: Paul Clark
SparkFun Electronics
Date: April 13th, 2021
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to configure the u-blox GNSS to send PVT reports automatically
and log those and any incoming NMEA messages to SD card in UBX format
** Please note: this example will only work on processors like the Artemis which have plenty of RAM available **
This code is intended to be run on the MicroMod Data Logging Carrier Board using the Artemis Processor
but can be adapted by changing the chip select pin and SPI definitions:
https://www.sparkfun.com/products/16829
https://www.sparkfun.com/products/16401
Hardware Connections:
Please see: https://learn.sparkfun.com/tutorials/micromod-data-logging-carrier-board-hookup-guide
Insert the Artemis Processor into the MicroMod Data Logging Carrier Board and secure with the screw.
Connect your GNSS breakout to the Carrier Board using a Qwiic cable.
Connect an antenna to your GNSS board if required.
Insert a formatted micro-SD card into the socket on the Carrier Board.
Connect the Carrier Board to your computer using a USB-C cable.
Ensure you have the SparkFun Apollo3 boards installed: http://boardsmanager/All#SparkFun_Apollo3
This code has been tested using version 1.2.1 of the Apollo3 boards on Arduino IDE 1.8.13.
Select "SparkFun Artemis MicroMod" as the board type.
Press upload to upload the code onto the Artemis.
Open the Serial Monitor at 115200 baud to see the output.
To minimise I2C bus errors, it is a good idea to open the I2C pull-up split pad links on
both the MicroMod Data Logging Carrier Board and the u-blox module breakout.
Feel like supporting open source hardware?
Buy a board from SparkFun!
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
NEO-M8P RTK: https://www.sparkfun.com/products/15005
ZOE-M8Q: https://www.sparkfun.com/products/15193
SAM-M8Q: https://www.sparkfun.com/products/15210
*/
#include <SPI.h>
#include <SD.h>
#include <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
File myFile; //File that all GNSS data is written to
#define sdChipSelect CS //Primary SPI Chip Select is CS for the MicroMod Artemis Processor. Adjust for your processor if necessary.
#define sdWriteSize 512 // Write data to the SD card in blocks of 512 bytes
#define fileBufferSize 16384 // Allocate 16KBytes of RAM for UBX message storage
unsigned long lastPrint; // Record when the last Serial print took place
unsigned long bytesWritten = 0; // Record how many bytes have been written to SD card
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
pinMode(LED_BUILTIN, OUTPUT); // Flash LED_BUILTIN each time we write to the SD card
digitalWrite(LED_BUILTIN, LOW);
Wire.begin(); // Start I2C communication
#if defined(AM_PART_APOLLO3)
Wire.setPullups(0); // On the Artemis, we can disable the internal I2C pull-ups too to help reduce bus errors
#endif
while (Serial.available()) // Make sure the Serial buffer is empty
{
Serial.read();
}
Serial.println(F("Press any key to start logging."));
while (!Serial.available()) // Wait for the user to press a key
{
; // Do nothing
}
delay(100); // Wait, just in case multiple characters were sent
while (Serial.available()) // Empty the Serial buffer
{
Serial.read();
}
Serial.println("Initializing SD card...");
// See if the card is present and can be initialized:
if (!SD.begin(sdChipSelect))
{
Serial.println("Card failed, or not present. Freezing...");
// don't do anything more:
while (1);
}
Serial.println("SD card initialized.");
// Create or open a file called "PVT_NMEA.ubx" on the SD card.
// If the file already exists, the new data is appended to the end of the file.
myFile = SD.open("PVT_NMEA.ubx", FILE_WRITE);
if(!myFile)
{
Serial.println(F("Failed to create UBX data file! Freezing..."));
while (1);
}
//myGNSS.enableDebugging(); // Uncomment this line to enable lots of helpful GNSS debug messages on Serial
//myGNSS.enableDebugging(Serial, true); // Or, uncomment this line to enable only the important GNSS debug messages on Serial
//myGNSS.disableUBX7Fcheck(); // RAWX data can legitimately contain 0x7F. Uncomment this line to disable the "7F" check in checkUbloxI2C
// SD cards can occasionally 'hiccup' and a write takes much longer than usual. The buffer needs to be big enough
// to hold the backlog of data if/when this happens.
// getMaxFileBufferAvail will tell us the maximum number of bytes which the file buffer has contained.
myGNSS.setFileBufferSize(fileBufferSize); // setFileBufferSize must be called _before_ .begin
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing..."));
while (1);
}
// Uncomment the next line if you want to reset your module back to the default settings with 1Hz navigation rate
// This will (re)enable the standard NMEA messages too
// This will also disable any "auto" UBX messages that were enabled and saved by other examples and reduce the load on the I2C bus
//myGNSS.factoryDefault(); delay(5000);
myGNSS.setI2COutput(COM_TYPE_UBX | COM_TYPE_NMEA); //Set the I2C port to output both UBX and NMEA messages
//myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Optional: save (only) the communications port settings to flash and BBR
myGNSS.setNavigationFrequency(1); //Produce one navigation solution per second
myGNSS.setAutoPVT(true, false); // Enable automatic NAV PVT messages: without callback; without implicit update
myGNSS.logNAVPVT(); // Enable NAV PVT data logging
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C, 1); // Ensure the GxGGA (Global positioning system fix data) message is enabled. Send every measurement.
myGNSS.enableNMEAMessage(UBX_NMEA_GSA, COM_PORT_I2C, 1); // Ensure the GxGSA (GNSS DOP and Active satellites) message is enabled. Send every measurement.
myGNSS.enableNMEAMessage(UBX_NMEA_GSV, COM_PORT_I2C, 1); // Ensure the GxGSV (GNSS satellites in view) message is enabled. Send every measurement.
myGNSS.setNMEALoggingMask(SFE_UBLOX_FILTER_NMEA_ALL); // Enable logging of all enabled NMEA messages
//myGNSS.setNMEALoggingMask(SFE_UBLOX_FILTER_NMEA_GGA | SFE_UBLOX_FILTER_NMEA_GSA); // Or we can, for example, log only GxGGA & GxGSA and ignore GxGSV
Serial.println(F("Press any key to stop logging."));
lastPrint = millis(); // Initialize lastPrint
}
void loop()
{
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
while (myGNSS.fileBufferAvailable() >= sdWriteSize) // Check to see if we have at least sdWriteSize waiting in the buffer
{
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN each time we write to the SD card
uint8_t myBuffer[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
myGNSS.extractFileBufferData((uint8_t *)&myBuffer, sdWriteSize); // Extract exactly sdWriteSize bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, sdWriteSize); // Write exactly sdWriteSize bytes from myBuffer to the ubxDataFile on the SD card
bytesWritten += sdWriteSize; // Update bytesWritten
// In case the SD writing is slow or there is a lot of data to write, keep checking for the arrival of new data
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off again
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
if (millis() > (lastPrint + 1000)) // Print bytesWritten once per second
{
Serial.print(F("The number of bytes written to SD card is ")); // Print how many bytes have been written to SD card
Serial.println(bytesWritten);
uint16_t maxBufferBytes = myGNSS.getMaxFileBufferAvail(); // Get how full the file buffer has been (not how full it is now)
//Serial.print(F("The maximum number of bytes which the file buffer has contained is: ")); // It is a fun thing to watch how full the buffer gets
//Serial.println(maxBufferBytes);
if (maxBufferBytes > ((fileBufferSize / 5) * 4)) // Warn the user if fileBufferSize was more than 80% full
{
Serial.println(F("Warning: the file buffer has been over 80% full. Some data may have been lost."));
}
lastPrint = millis(); // Update lastPrint
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
if (Serial.available()) // Check if the user wants to stop logging
{
uint16_t remainingBytes = myGNSS.fileBufferAvailable(); // Check if there are any bytes remaining in the file buffer
while (remainingBytes > 0) // While there is still data in the file buffer
{
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN while we write to the SD card
uint8_t myBuffer[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
uint16_t bytesToWrite = remainingBytes; // Write the remaining bytes to SD card sdWriteSize bytes at a time
if (bytesToWrite > sdWriteSize)
{
bytesToWrite = sdWriteSize;
}
myGNSS.extractFileBufferData((uint8_t *)&myBuffer, bytesToWrite); // Extract bytesToWrite bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, bytesToWrite); // Write bytesToWrite bytes from myBuffer to the ubxDataFile on the SD card
bytesWritten += bytesToWrite; // Update bytesWritten
remainingBytes -= bytesToWrite; // Decrement remainingBytes
}
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off
Serial.print(F("The total number of bytes written to SD card is ")); // Print how many bytes have been written to SD card
Serial.println(bytesWritten);
myFile.close(); // Close the data file
Serial.println(F("Logging stopped. Freezing..."));
while(1); // Do nothing more
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
}
@@ -81,9 +81,6 @@ void setup()
while (1);
}
// Another trick we can use is to mark the CFG RATE data as stale so we can be sure we read fresh data
myGNSS.packetUBXCFGRATE->moduleQueried.moduleQueried.all = 0; // Mark all of the CFG RATE data as stale
// Read and print the updated measurement rate and navigation rate
rate = myGNSS.getMeasurementRate(); //Get the measurement rate of this module
@@ -0,0 +1,143 @@
/*
Getting leap second event info as SNTP Leap Indicator, time to a leap second event and the number of leap seconds since GPS epoch
By: UT2UH
Date: April 14th, 2021
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
This example shows how to query a u-blox module for the leap second event info to cast to SNTP Leap Indicator enumeration.
We also turn off the NMEA output on the I2C port. This decreases the amount of I2C traffic dramatically.
Leave NMEA parsing behind. Now you can simply ask the module for the datums you want!
Feel like supporting open source hardware?
Buy a board from SparkFun!
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
NEO-M8P RTK: https://www.sparkfun.com/products/15005
SAM-M8Q: https://www.sparkfun.com/products/15106
Hardware Connections:
Plug a Qwiic cable into the GNSS and a BlackBoard
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
Open the serial monitor at 115200 baud to see the output
*/
#include <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
typedef enum {
LI_NO_WARNING, //Time leaping not scheduled
LI_LAST_MINUTE_61_SEC, //Last minute has 61 seconds
LI_LAST_MINUTE_59_SEC, //Last minute has 59 seconds
LI_ALARM_CONDITION //The NTP server's clock not synchronized
} ntp_LI_e;
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
void setup()
{
Serial.begin(115200);
while (!Serial)
; //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
// Uncomment the next line if you need to completely reset your module
//myGNSS.factoryDefault(); delay(5000); // Reset everything and wait while the module restarts
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR
Serial.println("Compare Unix Epoch given with reference one from https://www.epochconverter.com/");
}
void loop()
{
//Query module only every second. Doing it more often will just cause I2C traffic.
//The module only responds when a new position is available
if (millis() - lastTime > 1000)
{
lastTime = millis(); //Update the timer
// getUnixEpoch marks the PVT data as stale so you will get Unix time and PVT time on alternate seconds
uint32_t us; //microseconds returned by getUnixEpoch()
uint32_t epoch = myGNSS.getUnixEpoch();
Serial.print("Unix Epoch rounded: ");
Serial.print(epoch, DEC);
epoch = myGNSS.getUnixEpoch(us);
Serial.print(" Exact Unix Epoch: ");
Serial.print(epoch, DEC);
Serial.print(" micros: ");
Serial.println(us, DEC);
int32_t timeToLeapSecEvent;
ntp_LI_e leapIndicator = (ntp_LI_e)myGNSS.getLeapIndicator(timeToLeapSecEvent);
Serial.print("NTP LI: ");
Serial.print(leapIndicator, DEC);
switch (leapIndicator){
case LI_NO_WARNING:
Serial.print(" - No event scheduled");
break;
case LI_LAST_MINUTE_61_SEC:
Serial.print(" - last minute will end at 23:60");
break;
case LI_LAST_MINUTE_59_SEC:
Serial.print(" - last minute will end at 23:58");
break;
case LI_ALARM_CONDITION:
default:
Serial.print(" - Unknown (clock not synchronized)");
break;
}
Serial.print(". Time to the next leap second event: ");
Serial.println(timeToLeapSecEvent, DEC);
sfe_ublox_ls_src_e leapSecSource;
Serial.print("Leap seconds since GPS Epoch (Jan 6th, 1980): ");
Serial.print(myGNSS.getCurrentLeapSeconds(leapSecSource), DEC);
switch (leapSecSource){
case SFE_UBLOX_LS_SRC_DEFAULT:
Serial.print(" - hardcoded");
break;
case SFE_UBLOX_LS_SRC_GLONASS:
Serial.print(" - derived from GPS and GLONASS time difference");
break;
case SFE_UBLOX_LS_SRC_GPS:
Serial.print(" - according to GPS");
break;
case SFE_UBLOX_LS_SRC_SBAS:
Serial.print(" - according to SBAS");
break;
case SFE_UBLOX_LS_SRC_BEIDOU:
Serial.print(" - according to BeiDou");
break;
case SFE_UBLOX_LS_SRC_GALILEO:
Serial.print(" - according to Galileo");
break;
case SFE_UBLOX_LS_SRC_AIDED:
Serial.print(" - last minute will end at 23:58");
break;
case SFE_UBLOX_LS_SRC_CONFIGURED:
Serial.print(" - as configured)");
break;
case SFE_UBLOX_LS_SRC_UNKNOWN:
default:
Serial.print(" - source unknown");
break;
}
Serial.println();
}
Serial.println();
}
@@ -45,6 +45,10 @@ void setup()
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setProcessNMEAMask(SFE_UBLOX_FILTER_NMEA_ALL); // Make sure the library is passing all NMEA messages to processNMEA
myGNSS.setProcessNMEAMask(SFE_UBLOX_FILTER_NMEA_GGA); // Or, we can be kind to MicroNMEA and _only_ pass the GGA messages to it
}
void loop()
@@ -60,12 +64,12 @@ void loop()
Serial.println(latitude_mdeg / 1000000., 6);
Serial.print("Longitude (deg): ");
Serial.println(longitude_mdeg / 1000000., 6);
nmea.clear(); // Clear the MicroNMEA storage to make sure we are getting fresh data
}
else
{
Serial.print("No Fix - ");
Serial.print("Num. satellites: ");
Serial.println(nmea.getNumSatellites());
Serial.println("Waiting for fresh data");
}
delay(250); //Don't pound too hard on the I2C bus
+38
View File
@@ -28,6 +28,7 @@ UBX_NAV_HPPOSECEF_data_t KEYWORD1
UBX_NAV_HPPOSLLH_data_t KEYWORD1
UBX_NAV_CLOCK_data_t KEYWORD1
UBX_NAV_RELPOSNED_data_t KEYWORD1
UBX_NAV_TIMELS_data_t KEYWORD1
UBX_RXM_SFRBX_data_t KEYWORD1
UBX_RXM_RAWX_data_t KEYWORD1
@@ -264,6 +265,11 @@ initPacketUBXNAVCLOCK KEYWORD2
flushNAVCLOCK KEYWORD2
logNAVCLOCK KEYWORD2
getLeapSecondEvent KEYWORD2
getLeapIndicator KEYWORD2
getCurrentLeapSeconds KEYWORD2
initPacketUBXNAVTIMELS KEYWORD2
getSurveyStatus KEYWORD2
initPacketUBXNAVSVIN KEYWORD2
@@ -382,12 +388,18 @@ initPacketUBXHNRPVT KEYWORD2
flushHNRPVT KEYWORD2
logHNRPVT KEYWORD2
setNMEALoggingMask KEYWORD2
getNMEALoggingMask KEYWORD2
setProcessNMEAMask KEYWORD2
getProcessNMEAMask KEYWORD2
setNavigationFrequency KEYWORD2
getNavigationFrequency KEYWORD2
setMeasurementRate KEYWORD2
getMeasurementRate KEYWORD2
setNavigationRate KEYWORD2
getNavigationRate KEYWORD2
flushCFGRATE KEYWORD2
getGeometricDOP KEYWORD2
getPositionDOP KEYWORD2
@@ -543,16 +555,41 @@ UBX_NMEA_GLQ LITERAL1
UBX_NMEA_GNQ LITERAL1
UBX_NMEA_GNS LITERAL1
UBX_NMEA_GPQ LITERAL1
UBX_NMEA_GQQ LITERAL1
UBX_NMEA_GRS LITERAL1
UBX_NMEA_GSA LITERAL1
UBX_NMEA_GST LITERAL1
UBX_NMEA_GSV LITERAL1
UBX_NMEA_RLM LITERAL1
UBX_NMEA_RMC LITERAL1
UBX_NMEA_TXT LITERAL1
UBX_NMEA_VLW LITERAL1
UBX_NMEA_VTG LITERAL1
UBX_NMEA_ZDA LITERAL1
SFE_UBLOX_FILTER_NMEA_ALL LITERAL1
SFE_UBLOX_FILTER_NMEA_DTM LITERAL1
SFE_UBLOX_FILTER_NMEA_GAQ LITERAL1
SFE_UBLOX_FILTER_NMEA_GBQ LITERAL1
SFE_UBLOX_FILTER_NMEA_GBS LITERAL1
SFE_UBLOX_FILTER_NMEA_GGA LITERAL1
SFE_UBLOX_FILTER_NMEA_GLL LITERAL1
SFE_UBLOX_FILTER_NMEA_GLQ LITERAL1
SFE_UBLOX_FILTER_NMEA_GNQ LITERAL1
SFE_UBLOX_FILTER_NMEA_GNS LITERAL1
SFE_UBLOX_FILTER_NMEA_GPQ LITERAL1
SFE_UBLOX_FILTER_NMEA_GQQ LITERAL1
SFE_UBLOX_FILTER_NMEA_GRS LITERAL1
SFE_UBLOX_FILTER_NMEA_GSA LITERAL1
SFE_UBLOX_FILTER_NMEA_GST LITERAL1
SFE_UBLOX_FILTER_NMEA_GSV LITERAL1
SFE_UBLOX_FILTER_NMEA_RLM LITERAL1
SFE_UBLOX_FILTER_NMEA_RMC LITERAL1
SFE_UBLOX_FILTER_NMEA_TXT LITERAL1
SFE_UBLOX_FILTER_NMEA_VLW LITERAL1
SFE_UBLOX_FILTER_NMEA_VTG LITERAL1
SFE_UBLOX_FILTER_NMEA_ZDA LITERAL1
UBX_NAV_ATT LITERAL1
UBX_NAV_CLOCK LITERAL1
UBX_NAV_DOP LITERAL1
@@ -566,6 +603,7 @@ UBX_NAV_RELPOSNED LITERAL1
UBX_NAV_RESETODO LITERAL1
UBX_NAV_STATUS LITERAL1
UBX_NAV_SVIN LITERAL1
UBX_NAV_TIMELS LITERAL1
UBX_NAV_VELECEF LITERAL1
UBX_NAV_VELNED LITERAL1
+1 -1
View File
@@ -1,5 +1,5 @@
name=SparkFun u-blox GNSS Arduino Library
version=2.0.5
version=2.0.6
author=SparkFun Electronics <techsupport@sparkfun.com>
maintainer=SparkFun Electronics <sparkfun.com>
sentence=Library for I2C and Serial Communication with u-blox GNSS modules<br/><br/>
+300 -38
View File
@@ -50,6 +50,9 @@ SFE_UBLOX_GNSS::SFE_UBLOX_GNSS(void)
pinMode((uint8_t)debugPin, OUTPUT);
digitalWrite((uint8_t)debugPin, HIGH);
}
_logNMEA.all = 0; // Default to passing no NMEA messages to the file buffer
_processNMEA.all = SFE_UBLOX_FILTER_NMEA_ALL; // Default to passing all NMEA messages to processNMEA
}
//Stop all automatic message processing. Free all used RAM
@@ -82,6 +85,12 @@ void SFE_UBLOX_GNSS::end(void)
delete[] currentGeofenceParams;
currentGeofenceParams = NULL; // Redundant?
}
if (packetUBXNAVTIMELS != NULL)
{
delete[] packetUBXNAVTIMELS;
packetUBXNAVTIMELS = NULL; // Redundant?
}
if (packetUBXNAVPOSECEF != NULL)
{
@@ -789,6 +798,9 @@ boolean SFE_UBLOX_GNSS::checkAutomatic(uint8_t Class, uint8_t ID)
case UBX_NAV_CLOCK:
if (packetUBXNAVCLOCK != NULL) result = true;
break;
case UBX_NAV_TIMELS:
if (packetUBXNAVTIMELS != NULL) result = true;
break;
case UBX_NAV_SVIN:
if (packetUBXNAVSVIN != NULL) result = true;
break;
@@ -916,6 +928,9 @@ uint16_t SFE_UBLOX_GNSS::getMaxPayloadSize(uint8_t Class, uint8_t ID)
case UBX_NAV_CLOCK:
maxSize = UBX_NAV_CLOCK_LEN;
break;
case UBX_NAV_TIMELS:
maxSize = UBX_NAV_TIMELS_LEN;
break;
case UBX_NAV_SVIN:
maxSize = UBX_NAV_SVIN_LEN;
break;
@@ -1020,6 +1035,7 @@ void SFE_UBLOX_GNSS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t r
}
else if (incoming == '$')
{
nmeaByteCounter = 0; // Reset the NMEA byte counter
currentSentence = NMEA;
}
else if (incoming == 0xD3) //RTCM frames start with 0xD3
@@ -1241,9 +1257,58 @@ void SFE_UBLOX_GNSS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t r
//Finally, increment the frame counter
ubxFrameCounter++;
}
else if (currentSentence == NMEA)
else if (currentSentence == NMEA) // Process incoming NMEA mesages. Selectively log if desired.
{
processNMEA(incoming); //Process each NMEA character
if ((nmeaByteCounter == 0) && (incoming != '$'))
{
currentSentence = NONE; //Something went wrong. Reset. (Almost certainly redundant!)
}
else if ((nmeaByteCounter == 1) && (incoming != 'G'))
{
currentSentence = NONE; //Something went wrong. Reset.
}
else if ((nmeaByteCounter >= 0) && (nmeaByteCounter <= 5))
{
nmeaAddressField[nmeaByteCounter] = incoming; // Store the start character and NMEA address field
}
if (nmeaByteCounter == 5)
{
// We've just received the end of the address field. Check if it is selected for logging
if (logThisNMEA())
{
storeFileBytes(&nmeaAddressField[0], 6); // Add start character and address field to the file buffer
}
// Check if it should be passed to processNMEA
if (processThisNMEA())
{
processNMEA(nmeaAddressField[0]); //Process the start character and address field
processNMEA(nmeaAddressField[1]);
processNMEA(nmeaAddressField[2]);
processNMEA(nmeaAddressField[3]);
processNMEA(nmeaAddressField[4]);
processNMEA(nmeaAddressField[5]);
}
}
if ((nmeaByteCounter > 5) || (nmeaByteCounter < 0)) // Should we add incoming to the file buffer and/or pass it to processNMEA?
{
if (logThisNMEA())
storeFileBytes(&incoming, 1); // Add incoming to the file buffer
if (processThisNMEA())
processNMEA(incoming); // Pass incoming to processNMEA
}
if (incoming == '*')
nmeaByteCounter = -5; // We are expecting * plus two checksum bytes plus CR and LF
nmeaByteCounter++; // Increment the byte counter
if (nmeaByteCounter == maxNMEAByteCount) // Check if we have processed too many bytes
currentSentence = NONE; //Something went wrong. Reset.
if (nmeaByteCounter == 0) // Check if we are done
currentSentence = NONE; // All done!
}
else if (currentSentence == RTCM)
{
@@ -1251,6 +1316,68 @@ void SFE_UBLOX_GNSS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t r
}
}
// PRIVATE: Return true if we should add this NMEA message to the file buffer for logging
boolean SFE_UBLOX_GNSS::logThisNMEA()
{
if (_logNMEA.bits.all == 1) return (true);
if ((nmeaAddressField[3] == 'D') && (nmeaAddressField[4] == 'T') && (nmeaAddressField[5] == 'M') && (_logNMEA.bits.UBX_NMEA_DTM == 1)) return (true);
if (nmeaAddressField[3] == 'G')
{
if ((nmeaAddressField[4] == 'A') && (nmeaAddressField[5] == 'Q') && (_logNMEA.bits.UBX_NMEA_GAQ == 1)) return (true);
if ((nmeaAddressField[4] == 'B') && (nmeaAddressField[5] == 'Q') && (_logNMEA.bits.UBX_NMEA_GBQ == 1)) return (true);
if ((nmeaAddressField[4] == 'B') && (nmeaAddressField[5] == 'S') && (_logNMEA.bits.UBX_NMEA_GBS == 1)) return (true);
if ((nmeaAddressField[4] == 'G') && (nmeaAddressField[5] == 'A') && (_logNMEA.bits.UBX_NMEA_GGA == 1)) return (true);
if ((nmeaAddressField[4] == 'L') && (nmeaAddressField[5] == 'L') && (_logNMEA.bits.UBX_NMEA_GLL == 1)) return (true);
if ((nmeaAddressField[4] == 'L') && (nmeaAddressField[5] == 'Q') && (_logNMEA.bits.UBX_NMEA_GLQ == 1)) return (true);
if ((nmeaAddressField[4] == 'N') && (nmeaAddressField[5] == 'Q') && (_logNMEA.bits.UBX_NMEA_GNQ == 1)) return (true);
if ((nmeaAddressField[4] == 'N') && (nmeaAddressField[5] == 'S') && (_logNMEA.bits.UBX_NMEA_GNS == 1)) return (true);
if ((nmeaAddressField[4] == 'P') && (nmeaAddressField[5] == 'Q') && (_logNMEA.bits.UBX_NMEA_GPQ == 1)) return (true);
if ((nmeaAddressField[4] == 'Q') && (nmeaAddressField[5] == 'Q') && (_logNMEA.bits.UBX_NMEA_GQQ == 1)) return (true);
if ((nmeaAddressField[4] == 'R') && (nmeaAddressField[5] == 'S') && (_logNMEA.bits.UBX_NMEA_GRS == 1)) return (true);
if ((nmeaAddressField[4] == 'S') && (nmeaAddressField[5] == 'A') && (_logNMEA.bits.UBX_NMEA_GSA == 1)) return (true);
if ((nmeaAddressField[4] == 'S') && (nmeaAddressField[5] == 'T') && (_logNMEA.bits.UBX_NMEA_GST == 1)) return (true);
if ((nmeaAddressField[4] == 'S') && (nmeaAddressField[5] == 'V') && (_logNMEA.bits.UBX_NMEA_GSV == 1)) return (true);
}
if ((nmeaAddressField[3] == 'R') && (nmeaAddressField[4] == 'L') && (nmeaAddressField[5] == 'M') && (_logNMEA.bits.UBX_NMEA_RLM == 1)) return (true);
if ((nmeaAddressField[3] == 'R') && (nmeaAddressField[4] == 'M') && (nmeaAddressField[5] == 'C') && (_logNMEA.bits.UBX_NMEA_RMC == 1)) return (true);
if ((nmeaAddressField[3] == 'T') && (nmeaAddressField[4] == 'X') && (nmeaAddressField[5] == 'T') && (_logNMEA.bits.UBX_NMEA_TXT == 1)) return (true);
if ((nmeaAddressField[3] == 'V') && (nmeaAddressField[4] == 'L') && (nmeaAddressField[5] == 'W') && (_logNMEA.bits.UBX_NMEA_VLW == 1)) return (true);
if ((nmeaAddressField[3] == 'V') && (nmeaAddressField[4] == 'T') && (nmeaAddressField[5] == 'G') && (_logNMEA.bits.UBX_NMEA_VTG == 1)) return (true);
if ((nmeaAddressField[3] == 'Z') && (nmeaAddressField[4] == 'D') && (nmeaAddressField[5] == 'A') && (_logNMEA.bits.UBX_NMEA_ZDA == 1)) return (true);
return (false);
}
// PRIVATE: Return true if we should pass this NMEA message to processNMEA
boolean SFE_UBLOX_GNSS::processThisNMEA()
{
if (_processNMEA.bits.all == 1) return (true);
if ((nmeaAddressField[3] == 'D') && (nmeaAddressField[4] == 'T') && (nmeaAddressField[5] == 'M') && (_processNMEA.bits.UBX_NMEA_DTM == 1)) return (true);
if (nmeaAddressField[3] == 'G')
{
if ((nmeaAddressField[4] == 'A') && (nmeaAddressField[5] == 'Q') && (_processNMEA.bits.UBX_NMEA_GAQ == 1)) return (true);
if ((nmeaAddressField[4] == 'B') && (nmeaAddressField[5] == 'Q') && (_processNMEA.bits.UBX_NMEA_GBQ == 1)) return (true);
if ((nmeaAddressField[4] == 'B') && (nmeaAddressField[5] == 'S') && (_processNMEA.bits.UBX_NMEA_GBS == 1)) return (true);
if ((nmeaAddressField[4] == 'G') && (nmeaAddressField[5] == 'A') && (_processNMEA.bits.UBX_NMEA_GGA == 1)) return (true);
if ((nmeaAddressField[4] == 'L') && (nmeaAddressField[5] == 'L') && (_processNMEA.bits.UBX_NMEA_GLL == 1)) return (true);
if ((nmeaAddressField[4] == 'L') && (nmeaAddressField[5] == 'Q') && (_processNMEA.bits.UBX_NMEA_GLQ == 1)) return (true);
if ((nmeaAddressField[4] == 'N') && (nmeaAddressField[5] == 'Q') && (_processNMEA.bits.UBX_NMEA_GNQ == 1)) return (true);
if ((nmeaAddressField[4] == 'N') && (nmeaAddressField[5] == 'S') && (_processNMEA.bits.UBX_NMEA_GNS == 1)) return (true);
if ((nmeaAddressField[4] == 'P') && (nmeaAddressField[5] == 'Q') && (_processNMEA.bits.UBX_NMEA_GPQ == 1)) return (true);
if ((nmeaAddressField[4] == 'Q') && (nmeaAddressField[5] == 'Q') && (_processNMEA.bits.UBX_NMEA_GQQ == 1)) return (true);
if ((nmeaAddressField[4] == 'R') && (nmeaAddressField[5] == 'S') && (_processNMEA.bits.UBX_NMEA_GRS == 1)) return (true);
if ((nmeaAddressField[4] == 'S') && (nmeaAddressField[5] == 'A') && (_processNMEA.bits.UBX_NMEA_GSA == 1)) return (true);
if ((nmeaAddressField[4] == 'S') && (nmeaAddressField[5] == 'T') && (_processNMEA.bits.UBX_NMEA_GST == 1)) return (true);
if ((nmeaAddressField[4] == 'S') && (nmeaAddressField[5] == 'V') && (_processNMEA.bits.UBX_NMEA_GSV == 1)) return (true);
}
if ((nmeaAddressField[3] == 'R') && (nmeaAddressField[4] == 'L') && (nmeaAddressField[5] == 'M') && (_processNMEA.bits.UBX_NMEA_RLM == 1)) return (true);
if ((nmeaAddressField[3] == 'R') && (nmeaAddressField[4] == 'M') && (nmeaAddressField[5] == 'C') && (_processNMEA.bits.UBX_NMEA_RMC == 1)) return (true);
if ((nmeaAddressField[3] == 'T') && (nmeaAddressField[4] == 'X') && (nmeaAddressField[5] == 'T') && (_processNMEA.bits.UBX_NMEA_TXT == 1)) return (true);
if ((nmeaAddressField[3] == 'V') && (nmeaAddressField[4] == 'L') && (nmeaAddressField[5] == 'W') && (_processNMEA.bits.UBX_NMEA_VLW == 1)) return (true);
if ((nmeaAddressField[3] == 'V') && (nmeaAddressField[4] == 'T') && (nmeaAddressField[5] == 'G') && (_processNMEA.bits.UBX_NMEA_VTG == 1)) return (true);
if ((nmeaAddressField[3] == 'Z') && (nmeaAddressField[4] == 'D') && (nmeaAddressField[5] == 'A') && (_processNMEA.bits.UBX_NMEA_ZDA == 1)) return (true);
return (false);
}
//This is the default or generic NMEA processor. We're only going to pipe the data to serial port so we can see it.
//User could overwrite this function to pipe characters to nmea.process(c) of tinyGPS or MicroNMEA
//Or user could pipe each character to a buffer, radio, etc.
@@ -1945,6 +2072,26 @@ void SFE_UBLOX_GNSS::processUBXpacket(ubxPacket *msg)
}
}
}
else if (msg->id == UBX_NAV_TIMELS && msg->len == UBX_NAV_TIMELS_LEN)
{
//Parse various byte fields into storage - but only if we have memory allocated for it
if (packetUBXNAVTIMELS != NULL)
{
packetUBXNAVTIMELS->data.iTOW = extractLong(msg, 0);
packetUBXNAVTIMELS->data.version = extractByte(msg, 4);
packetUBXNAVTIMELS->data.srcOfCurrLs = extractByte(msg, 8);
packetUBXNAVTIMELS->data.currLs = extractSignedChar(msg, 9);
packetUBXNAVTIMELS->data.srcOfLsChange = extractByte(msg, 10);
packetUBXNAVTIMELS->data.lsChange = extractSignedChar(msg, 11);
packetUBXNAVTIMELS->data.timeToLsEvent = extractSignedLong(msg, 12);
packetUBXNAVTIMELS->data.dateOfLsGpsWn = extractInt(msg, 16);
packetUBXNAVTIMELS->data.dateOfLsGpsDn = extractInt(msg, 18);
packetUBXNAVTIMELS->data.valid.all = extractSignedChar(msg, 23);
//Mark all datums as fresh (not read before)
packetUBXNAVTIMELS->moduleQueried.moduleQueried.all = 0xFFFFFFFF;
}
}
else if (msg->id == UBX_NAV_SVIN && msg->len == UBX_NAV_SVIN_LEN)
{
//Parse various byte fields into storage - but only if we have memory allocated for it
@@ -6858,6 +7005,53 @@ void SFE_UBLOX_GNSS::logNAVCLOCK(boolean enabled)
packetUBXNAVCLOCK->automaticFlags.flags.bits.addToFileBuffer = (uint8_t)enabled;
}
// ***** NAV TIMELS automatic support
//Reads leap second event information and sets the global variables
//for future leap second change and number of leap seconds since GPS epoch
//Returns true if commands was successful
boolean SFE_UBLOX_GNSS::getLeapSecondEvent(uint16_t maxWait)
{
if (packetUBXNAVTIMELS == NULL) initPacketUBXNAVTIMELS(); //Check that RAM has been allocated for the TIMELS data
if (packetUBXNAVTIMELS == NULL) // Abort if the RAM allocation failed
return (false);
packetCfg.cls = UBX_CLASS_NAV;
packetCfg.id = UBX_NAV_TIMELS;
packetCfg.len = 0;
packetCfg.startingSpot = 0;
//The data is parsed as part of processing the response
sfe_ublox_status_e retVal = sendCommand(&packetCfg, maxWait);
if (retVal == SFE_UBLOX_STATUS_DATA_RECEIVED)
return (true);
if (retVal == SFE_UBLOX_STATUS_DATA_OVERWRITTEN)
{
return (true);
}
return (false);
}
// PRIVATE: Allocate RAM for packetUBXNAVTIMELS and initialize it
boolean SFE_UBLOX_GNSS::initPacketUBXNAVTIMELS()
{
packetUBXNAVTIMELS = new UBX_NAV_TIMELS_t; //Allocate RAM for the main struct
if (packetUBXNAVTIMELS == NULL)
{
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
_debugSerial->println(F("initPacketUBXNAVTIMELS: PANIC! RAM allocation failed!"));
return (false);
}
packetUBXNAVTIMELS->automaticFlags.flags.all = 0;
packetUBXNAVTIMELS->callbackPointer = NULL;
packetUBXNAVTIMELS->callbackData = NULL;
packetUBXNAVTIMELS->moduleQueried.moduleQueried.all = 0;
return (true);
}
// ***** NAV SVIN automatic support
//Reads survey in status and sets the global variables
@@ -7387,38 +7581,25 @@ boolean SFE_UBLOX_GNSS::getNavigationFrequencyInternal(uint16_t maxWait)
if (packetUBXCFGRATE == NULL) //Bail if the RAM allocation failed
return (false);
if (packetUBXCFGRATE->automaticFlags.flags.bits.automatic && packetUBXCFGRATE->automaticFlags.flags.bits.implicitUpdate)
// The CFG RATE message will never be produced automatically - that would be pointless.
// There is no setAutoCFGRATE function. We always need to poll explicitly.
packetCfg.cls = UBX_CLASS_CFG;
packetCfg.id = UBX_CFG_RATE;
packetCfg.len = 0;
packetCfg.startingSpot = 0;
//The data is parsed as part of processing the response
sfe_ublox_status_e retVal = sendCommand(&packetCfg, maxWait);
if (retVal == SFE_UBLOX_STATUS_DATA_RECEIVED)
return (true);
if (retVal == SFE_UBLOX_STATUS_DATA_OVERWRITTEN)
{
//The GPS is automatically reporting, we just check whether we got unread data
checkUbloxInternal(&packetCfg, UBX_CLASS_CFG, UBX_CFG_RATE);
return packetUBXCFGRATE->moduleQueried.moduleQueried.bits.all;
return (true);
}
else if (packetUBXCFGRATE->automaticFlags.flags.bits.automatic && !packetUBXCFGRATE->automaticFlags.flags.bits.implicitUpdate)
{
//Someone else has to call checkUblox for us...
return (false);
}
else
{
//The GPS is not automatically reporting navigation rate so we have to poll explicitly
packetCfg.cls = UBX_CLASS_CFG;
packetCfg.id = UBX_CFG_RATE;
packetCfg.len = 0;
packetCfg.startingSpot = 0;
//The data is parsed as part of processing the response
sfe_ublox_status_e retVal = sendCommand(&packetCfg, maxWait);
if (retVal == SFE_UBLOX_STATUS_DATA_RECEIVED)
return (true);
if (retVal == SFE_UBLOX_STATUS_DATA_OVERWRITTEN)
{
return (true);
}
return (false);
}
return (false);
}
// PRIVATE: Allocate RAM for packetUBXCFGRATE and initialize it
@@ -7431,10 +7612,10 @@ boolean SFE_UBLOX_GNSS::initPacketUBXCFGRATE()
_debugSerial->println(F("initPacketUBXCFGRATE: PANIC! RAM allocation failed!"));
return (false);
}
packetUBXCFGRATE->automaticFlags.flags.all = 0;
packetUBXCFGRATE->callbackPointer = NULL;
packetUBXCFGRATE->callbackData = NULL;
packetUBXCFGRATE->moduleQueried.moduleQueried.all = 0;
packetUBXCFGRATE->automaticFlags.flags.all = 0; // Redundant
packetUBXCFGRATE->callbackPointer = NULL; // Redundant
packetUBXCFGRATE->callbackData = NULL; // Redundant
packetUBXCFGRATE->moduleQueried.moduleQueried.all = 0; // Mark all data as stale/read
return (true);
}
@@ -9086,6 +9267,29 @@ void SFE_UBLOX_GNSS::logHNRPVT(boolean enabled)
packetUBXHNRPVT->automaticFlags.flags.bits.addToFileBuffer = (uint8_t)enabled;
}
// ***** Helper Functions for NMEA Logging / Processing
// Log selected NMEA messages to file buffer - if the messages are enabled and if the file buffer exists
// User needs to call setFileBufferSize before .begin
void SFE_UBLOX_GNSS::setNMEALoggingMask(uint32_t messages)
{
_logNMEA.all = messages;
}
uint32_t SFE_UBLOX_GNSS::getNMEALoggingMask()
{
return (_logNMEA.all);
}
// Pass selected NMEA messages to processNMEA
void SFE_UBLOX_GNSS::setProcessNMEAMask(uint32_t messages)
{
_processNMEA.all = messages;
}
uint32_t SFE_UBLOX_GNSS::getProcessNMEAMask()
{
return (_processNMEA.all);
}
// ***** CFG RATE Helper Functions
//Set the rate at which the module will give us an updated navigation solution
@@ -9114,7 +9318,11 @@ boolean SFE_UBLOX_GNSS::setNavigationFrequency(uint8_t navFreq, uint16_t maxWait
payloadCfg[0] = measurementRate & 0xFF; //measRate LSB
payloadCfg[1] = measurementRate >> 8; //measRate MSB
return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK
boolean result = ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK
flushCFGRATE(); // Mark the polled measurement and navigation rate data as stale
return (result);
}
//Get the rate at which the module is outputting nav solutions
@@ -9155,7 +9363,11 @@ boolean SFE_UBLOX_GNSS::setMeasurementRate(uint16_t rate, uint16_t maxWait)
payloadCfg[0] = rate & 0xFF; //measRate LSB
payloadCfg[1] = rate >> 8; //measRate MSB
return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK
boolean result = ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK
flushCFGRATE(); // Mark the polled measurement and navigation rate data as stale
return (result);
}
//Return the elapsed time between GNSS measurements in milliseconds, which defines the rate
@@ -9190,7 +9402,11 @@ boolean SFE_UBLOX_GNSS::setNavigationRate(uint16_t rate, uint16_t maxWait)
payloadCfg[2] = rate & 0xFF; //navRate LSB
payloadCfg[3] = rate >> 8; //navRate MSB
return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK
boolean result = ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK
flushCFGRATE(); // Mark the polled measurement and navigation rate data as stale
return (result);
}
//Return the ratio between the number of measurements and the number of navigation solutions. Unit is cycles
@@ -9208,6 +9424,13 @@ uint16_t SFE_UBLOX_GNSS::getNavigationRate(uint16_t maxWait)
return (packetUBXCFGRATE->data.navRate);
}
//Mark the CFG RATE data as read/stale
void SFE_UBLOX_GNSS::flushCFGRATE()
{
if (packetUBXCFGRATE == NULL) return; // Bail if RAM has not been allocated (otherwise we could be writing anywhere!)
packetUBXCFGRATE->moduleQueried.moduleQueried.all = 0; //Mark all datums as stale (read before)
}
// ***** DOP Helper Functions
uint16_t SFE_UBLOX_GNSS::getGeometricDOP(uint16_t maxWait)
@@ -10160,6 +10383,45 @@ float SFE_UBLOX_GNSS::getSurveyInMeanAccuracy(uint16_t maxWait) // Returned as m
return (((float)tempFloat) / 10000.0); //Convert 0.1mm to m
}
// ***** TIMELS Helper Functions
uint8_t SFE_UBLOX_GNSS::getLeapIndicator(int32_t& timeToLsEvent, uint16_t maxWait)
{
if (packetUBXNAVTIMELS == NULL) initPacketUBXNAVTIMELS(); //Check that RAM has been allocated for the TIMELS data
if (packetUBXNAVTIMELS == NULL) //Bail if the RAM allocation failed
return 3;
if (packetUBXNAVTIMELS->moduleQueried.moduleQueried.bits.validTimeToLsEvent == false)
getLeapSecondEvent(maxWait);
packetUBXNAVTIMELS->moduleQueried.moduleQueried.bits.validTimeToLsEvent = false; //Since we are about to give this to user, mark this data as stale
packetUBXNAVTIMELS->moduleQueried.moduleQueried.bits.lsChange = false;
packetUBXNAVTIMELS->moduleQueried.moduleQueried.bits.timeToLsEvent = false;
packetUBXNAVTIMELS->moduleQueried.moduleQueried.bits.all = false;
timeToLsEvent = packetUBXNAVTIMELS->data.timeToLsEvent;
// returns NTP Leap Indicator
// 0 -no warning
// 1 -last minute of the day has 61 seconds
// 2 -last minute of the day has 59 seconds
// 3 -unknown (clock unsynchronized)
return ((boolean)packetUBXNAVTIMELS->data.valid.bits.validTimeToLsEvent ? (uint8_t)(packetUBXNAVTIMELS->data.lsChange == -1 ? 2 : packetUBXNAVTIMELS->data.lsChange) : 3);
}
int8_t SFE_UBLOX_GNSS::getCurrentLeapSeconds(sfe_ublox_ls_src_e& source, uint16_t maxWait)
{
if (packetUBXNAVTIMELS == NULL) initPacketUBXNAVTIMELS(); //Check that RAM has been allocated for the TIMELS data
if (packetUBXNAVTIMELS == NULL) //Bail if the RAM allocation failed
return false;
if (packetUBXNAVTIMELS->moduleQueried.moduleQueried.bits.validCurrLs == false)
getLeapSecondEvent(maxWait);
packetUBXNAVTIMELS->moduleQueried.moduleQueried.bits.validCurrLs = false; //Since we are about to give this to user, mark this data as stale
packetUBXNAVTIMELS->moduleQueried.moduleQueried.bits.srcOfCurrLs = false;
packetUBXNAVTIMELS->moduleQueried.moduleQueried.bits.currLs = false;
packetUBXNAVTIMELS->moduleQueried.moduleQueried.bits.all = false;
source = ((sfe_ublox_ls_src_e)packetUBXNAVTIMELS->data.srcOfCurrLs);
return ((int8_t)packetUBXNAVTIMELS->data.currLs);
}
// ***** RELPOSNED Helper Functions and automatic support
float SFE_UBLOX_GNSS::getRelPosN(uint16_t maxWait) // Returned as m
+114 -8
View File
@@ -99,6 +99,69 @@ typedef enum
SFE_UBLOX_PACKET_PACKETAUTO
} sfe_ublox_packet_buffer_e;
// Define a struct to allow selective logging / processing of NMEA messages
// Set the individual bits to pass the NMEA messages to the file buffer and/or processNMEA
// Setting bits.all will pass all messages to the file buffer and processNMEA
typedef struct
{
union
{
uint32_t all;
struct
{
uint32_t all : 1;
uint32_t UBX_NMEA_DTM : 1;
uint32_t UBX_NMEA_GAQ : 1;
uint32_t UBX_NMEA_GBQ : 1;
uint32_t UBX_NMEA_GBS : 1;
uint32_t UBX_NMEA_GGA : 1;
uint32_t UBX_NMEA_GLL : 1;
uint32_t UBX_NMEA_GLQ : 1;
uint32_t UBX_NMEA_GNQ : 1;
uint32_t UBX_NMEA_GNS : 1;
uint32_t UBX_NMEA_GPQ : 1;
uint32_t UBX_NMEA_GQQ : 1;
uint32_t UBX_NMEA_GRS : 1;
uint32_t UBX_NMEA_GSA : 1;
uint32_t UBX_NMEA_GST : 1;
uint32_t UBX_NMEA_GSV : 1;
uint32_t UBX_NMEA_RLM : 1;
uint32_t UBX_NMEA_RMC : 1;
uint32_t UBX_NMEA_TXT : 1;
uint32_t UBX_NMEA_VLW : 1;
uint32_t UBX_NMEA_VTG : 1;
uint32_t UBX_NMEA_ZDA : 1;
} bits;
};
} sfe_ublox_nmea_filtering_t;
// Define an enum to make it easy to enable/disable selected NMEA messages for logging / processing
typedef enum
{
SFE_UBLOX_FILTER_NMEA_ALL = 0x00000001,
SFE_UBLOX_FILTER_NMEA_DTM = 0x00000002,
SFE_UBLOX_FILTER_NMEA_GAQ = 0x00000004,
SFE_UBLOX_FILTER_NMEA_GBQ = 0x00000008,
SFE_UBLOX_FILTER_NMEA_GBS = 0x00000010,
SFE_UBLOX_FILTER_NMEA_GGA = 0x00000020,
SFE_UBLOX_FILTER_NMEA_GLL = 0x00000040,
SFE_UBLOX_FILTER_NMEA_GLQ = 0x00000080,
SFE_UBLOX_FILTER_NMEA_GNQ = 0x00000100,
SFE_UBLOX_FILTER_NMEA_GNS = 0x00000200,
SFE_UBLOX_FILTER_NMEA_GPQ = 0x00000400,
SFE_UBLOX_FILTER_NMEA_GQQ = 0x00000800,
SFE_UBLOX_FILTER_NMEA_GRS = 0x00001000,
SFE_UBLOX_FILTER_NMEA_GSA = 0x00002000,
SFE_UBLOX_FILTER_NMEA_GST = 0x00004000,
SFE_UBLOX_FILTER_NMEA_GSV = 0x00008000,
SFE_UBLOX_FILTER_NMEA_RLM = 0x00010000,
SFE_UBLOX_FILTER_NMEA_RMC = 0x00020000,
SFE_UBLOX_FILTER_NMEA_TXT = 0x00040000,
SFE_UBLOX_FILTER_NMEA_VLW = 0x00080000,
SFE_UBLOX_FILTER_NMEA_VTG = 0x00100000,
SFE_UBLOX_FILTER_NMEA_ZDA = 0x00200000
} sfe_ublox_nmea_filtering_e;
//Registers
const uint8_t UBX_SYNCH_1 = 0xB5;
const uint8_t UBX_SYNCH_2 = 0x62;
@@ -159,7 +222,7 @@ const uint8_t UBX_CFG_VALSET = 0x8A; //Used for config of higher version u-blox
//Class: NMEA
//The following are used to enable NMEA messages. Descriptions come from the NMEA messages overview in the ZED-F9P Interface Description
const uint8_t UBX_NMEA_MSB = 0xF0; //All NMEA enable commands have 0xF0 as MSB
const uint8_t UBX_NMEA_MSB = 0xF0; //All NMEA enable commands have 0xF0 as MSB. Equal to UBX_CLASS_NMEA
const uint8_t UBX_NMEA_DTM = 0x0A; //GxDTM (datum reference)
const uint8_t UBX_NMEA_GAQ = 0x45; //GxGAQ (poll a standard message (if the current talker ID is GA))
const uint8_t UBX_NMEA_GBQ = 0x44; //GxGBQ (poll a standard message (if the current Talker ID is GB))
@@ -169,11 +232,13 @@ const uint8_t UBX_NMEA_GLL = 0x01; //GxGLL (latitude and long, whith time of pos
const uint8_t UBX_NMEA_GLQ = 0x43; //GxGLQ (poll a standard message (if the current Talker ID is GL))
const uint8_t UBX_NMEA_GNQ = 0x42; //GxGNQ (poll a standard message (if the current Talker ID is GN))
const uint8_t UBX_NMEA_GNS = 0x0D; //GxGNS (GNSS fix data)
const uint8_t UBX_NMEA_GPQ = 0x040; //GxGPQ (poll a standard message (if the current Talker ID is GP))
const uint8_t UBX_NMEA_GPQ = 0x40; //GxGPQ (poll a standard message (if the current Talker ID is GP))
const uint8_t UBX_NMEA_GQQ = 0x47; //GxGQQ (poll a standard message (if the current Talker ID is GQ))
const uint8_t UBX_NMEA_GRS = 0x06; //GxGRS (GNSS range residuals)
const uint8_t UBX_NMEA_GSA = 0x02; //GxGSA (GNSS DOP and Active satellites)
const uint8_t UBX_NMEA_GST = 0x07; //GxGST (GNSS Pseudo Range Error Statistics)
const uint8_t UBX_NMEA_GSV = 0x03; //GxGSV (GNSS satellites in view)
const uint8_t UBX_NMEA_RLM = 0x0B; //GxRMC (Return link message (RLM))
const uint8_t UBX_NMEA_RMC = 0x04; //GxRMC (Recommended minimum data)
const uint8_t UBX_NMEA_TXT = 0x41; //GxTXT (text transmission)
const uint8_t UBX_NMEA_VLW = 0x0F; //GxVLW (dual ground/water distance)
@@ -407,6 +472,20 @@ enum sfe_ublox_gnss_ids_e
SFE_UBLOX_GNSS_ID_GLONASS
};
// The GNSS identifiers of leap second event info source - used by UBX-NAV-TIMELS
enum sfe_ublox_ls_src_e
{
SFE_UBLOX_LS_SRC_DEFAULT,
SFE_UBLOX_LS_SRC_GLONASS,
SFE_UBLOX_LS_SRC_GPS,
SFE_UBLOX_LS_SRC_SBAS,
SFE_UBLOX_LS_SRC_BEIDOU,
SFE_UBLOX_LS_SRC_GALILEO,
SFE_UBLOX_LS_SRC_AIDED,
SFE_UBLOX_LS_SRC_CONFIGURED,
SFE_UBLOX_LS_SRC_UNKNOWN = 255
};
#ifndef MAX_PAYLOAD_SIZE
// v2.0: keep this for backwards-compatibility, but this is largely superseded by setPacketCfgPayloadSize
#define MAX_PAYLOAD_SIZE 256 //We need ~220 bytes for getProtocolVersion on most ublox modules
@@ -580,15 +659,15 @@ public:
boolean setPortOutput(uint8_t portID, uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure a given port to output UBX, NMEA, RTCM3 or a combination thereof
boolean setPortInput(uint8_t portID, uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure a given port to input UBX, NMEA, RTCM3 or a combination thereof
boolean setI2CAddress(uint8_t deviceAddress, uint16_t maxTime = defaultMaxWait); //Changes the I2C address of the u-blox module
boolean setI2CAddress(uint8_t deviceAddress, uint16_t maxTime = defaultMaxWait); //Changes the I2C address of the u-blox module
void setSerialRate(uint32_t baudrate, uint8_t uartPort = COM_PORT_UART1, uint16_t maxTime = defaultMaxWait); //Changes the serial baud rate of the u-blox module, uartPort should be COM_PORT_UART1/2
boolean setI2COutput(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure I2C port to output UBX, NMEA, RTCM3 or a combination thereof
boolean setUART1Output(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure UART1 port to output UBX, NMEA, RTCM3 or a combination thereof
boolean setUART2Output(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure UART2 port to output UBX, NMEA, RTCM3 or a combination thereof
boolean setUART1Output(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure UART1 port to output UBX, NMEA, RTCM3 or a combination thereof
boolean setUART2Output(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure UART2 port to output UBX, NMEA, RTCM3 or a combination thereof
boolean setUSBOutput(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure USB port to output UBX, NMEA, RTCM3 or a combination thereof
boolean setSPIOutput(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure SPI port to output UBX, NMEA, RTCM3 or a combination thereof
void setNMEAOutputPort(Stream &nmeaOutputPort); //Sets the internal variable for the port to direct NMEA characters to
void setNMEAOutputPort(Stream &nmeaOutputPort); //Sets the internal variable for the port to direct NMEA characters to
//Reset to defaults
@@ -800,6 +879,9 @@ public:
// Add "auto" support for NAV SVIN - to avoid needing 'global' storage
boolean getSurveyStatus(uint16_t maxWait); //Reads survey in status
// Add "auto" support for NAV TIMELS - to avoid needing 'global' storage
boolean getLeapSecondEvent(uint16_t maxWait); //Reads leap second event info
boolean getRELPOSNED(uint16_t maxWait = defaultMaxWait); //Get Relative Positioning Information of the NED frame
boolean setAutoRELPOSNED(boolean enabled, uint16_t maxWait = defaultMaxWait); //Enable/disable automatic RELPOSNED reports
boolean setAutoRELPOSNED(boolean enabled, boolean implicitUpdate, uint16_t maxWait = defaultMaxWait); //Enable/disable automatic RELPOSNED, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
@@ -928,6 +1010,14 @@ public:
void flushHNRPVT(); //Mark all the data as read/stale
void logHNRPVT(boolean enabled = true); // Log data to file buffer
// Helper functions for NMEA logging
void setNMEALoggingMask(uint32_t messages = SFE_UBLOX_FILTER_NMEA_ALL); // Add selected NMEA messages to file buffer - if enabled. Default to adding ALL messages to the file buffer
uint32_t getNMEALoggingMask(); // Return which NMEA messages are selected for logging to the file buffer - if enabled
// Helper functions to control which NMEA messages are passed to processNMEA
void setProcessNMEAMask(uint32_t messages = SFE_UBLOX_FILTER_NMEA_ALL); // Control which NMEA messages are passed to processNMEA. Default to passing ALL messages
uint32_t getProcessNMEAMask(); // Return which NMEA messages are passed to processNMEA
// Helper functions for CFG RATE
boolean setNavigationFrequency(uint8_t navFreq, uint16_t maxWait = defaultMaxWait); //Set the number of nav solutions sent per second
@@ -936,6 +1026,7 @@ public:
uint16_t getMeasurementRate(uint16_t maxWait = defaultMaxWait); //Return the elapsed time between GNSS measurements in milliseconds
boolean setNavigationRate(uint16_t rate, uint16_t maxWait = defaultMaxWait); //Set the ratio between the number of measurements and the number of navigation solutions. Unit is cycles. Max is 127
uint16_t getNavigationRate(uint16_t maxWait = defaultMaxWait); //Return the ratio between the number of measurements and the number of navigation solutions. Unit is cycles
void flushCFGRATE(); // Mark the measurement and navigation rate data as stale - used by the set rate functions
// Helper functions for DOP
@@ -1028,6 +1119,11 @@ public:
uint16_t getSurveyInObservationTime(uint16_t maxWait = defaultMaxWait); // Truncated to 65535 seconds
float getSurveyInMeanAccuracy(uint16_t maxWait = defaultMaxWait); // Returned as m
// Helper functions for TIMELS
uint8_t getLeapIndicator(int32_t& timeToLsEvent, uint16_t maxWait = defaultMaxWait);
int8_t getCurrentLeapSeconds(sfe_ublox_ls_src_e& source, uint16_t maxWait = defaultMaxWait);
// Helper functions for RELPOSNED
float getRelPosN(uint16_t maxWait = defaultMaxWait); // Returned as m
@@ -1080,6 +1176,7 @@ public:
UBX_NAV_HPPOSECEF_t *packetUBXNAVHPPOSECEF = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_NAV_HPPOSLLH_t *packetUBXNAVHPPOSLLH = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_NAV_CLOCK_t *packetUBXNAVCLOCK = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_NAV_TIMELS_t *packetUBXNAVTIMELS = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_NAV_SVIN_t *packetUBXNAVSVIN = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_NAV_RELPOSNED_t *packetUBXNAVRELPOSNED = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
@@ -1153,6 +1250,7 @@ private:
boolean initPacketUBXNAVHPPOSECEF(); // Allocate RAM for packetUBXNAVHPPOSECEF and initialize it
boolean initPacketUBXNAVHPPOSLLH(); // Allocate RAM for packetUBXNAVHPPOSLLH and initialize it
boolean initPacketUBXNAVCLOCK(); // Allocate RAM for packetUBXNAVCLOCK and initialize it
boolean initPacketUBXNAVTIMELS(); // Allocate RAM for packetUBXNAVTIMELS and initialize it
boolean initPacketUBXNAVSVIN(); // Allocate RAM for packetUBXNAVSVIN and initialize it
boolean initPacketUBXNAVRELPOSNED(); // Allocate RAM for packetUBXNAVRELPOSNED and initialize it
boolean initPacketUBXRXMSFRBX(); // Allocate RAM for packetUBXRXMSFRBX and initialize it
@@ -1182,6 +1280,9 @@ private:
boolean ubx7FcheckDisabled = false; // Flag to indicate if the "7F" check should be ignored in checkUbloxI2C
sfe_ublox_nmea_filtering_t _logNMEA; // Flags to indicate which NMEA messages should be added to the file buffer for logging
sfe_ublox_nmea_filtering_t _processNMEA; // Flags to indicate which NMEA messages should be passed to processNMEA
//The packet buffers
//These are pointed at from within the ubxPacket
uint8_t payloadAck[2]; // Holds the requested ACK/NACK
@@ -1212,11 +1313,16 @@ private:
unsigned long lastCheck = 0;
uint16_t ubxFrameCounter; //It counts all UBX frame. [Fixed header(2bytes), CLS(1byte), ID(1byte), length(2bytes), payload(x bytes), checksums(2bytes)]
uint16_t ubxFrameCounter; //Count all UBX frame bytes. [Fixed header(2bytes), CLS(1byte), ID(1byte), length(2bytes), payload(x bytes), checksums(2bytes)]
uint8_t rollingChecksumA; //Rolls forward as we receive incoming bytes. Checked against the last two A/B checksum bytes
uint8_t rollingChecksumB; //Rolls forward as we receive incoming bytes. Checked against the last two A/B checksum bytes
int8_t nmeaByteCounter; //Count all NMEA message bytes.
const int8_t maxNMEAByteCount = 82; // Abort NMEA message reception if nmeaByteCounter exceeds this (https://en.wikipedia.org/wiki/NMEA_0183#Message_structure)
uint8_t nmeaAddressField[6]; // NMEA Address Field - includes the start character (*)
boolean logThisNMEA(); // Return true if we should log this NMEA message
boolean processThisNMEA(); // Return true if we should pass this NMEA message to processNMEA
uint16_t rtcmLen = 0;
// Flag to prevent reentry into checkCallbacks
+60
View File
@@ -854,6 +854,66 @@ typedef struct
UBX_NAV_CLOCK_data_t *callbackData;
} UBX_NAV_CLOCK_t;
// UBX-NAV-TIMELS (0x01 0x26): Leap second event information
const uint16_t UBX_NAV_TIMELS_LEN = 24;
typedef struct
{
uint32_t iTOW; // GPS time of week of the navigation epoch: ms
uint8_t version; // Message version (0x00 for this version)
uint8_t reserved1[3];
uint8_t srcOfCurrLs; //Information source for the current number of leap seconds
int8_t currLs; //Current number of leap seconds since start of GPS (Jan 6, 1980), s
uint8_t srcOfLsChange; //Information source for the future leap second event
int8_t lsChange; //Future leap second change if one is scheduled, +1, 0, -1s
int32_t timeToLsEvent; //Num of secs until the next or from the last leap second, s
uint16_t dateOfLsGpsWn; //GPS week num (WN) of the next or the last leap second event
uint16_t dateOfLsGpsDn; //GPS day of week num (DN) for the next or last leap second event
uint8_t reserved2[3];
union
{
uint8_t all;
struct
{
uint8_t validCurrLs : 1; // 1 = Valid current number of leap seconds value
uint8_t validTimeToLsEvent : 1; // 1 = Valid time to next leap second event or from the last leap second event if no future event scheduled
} bits;
} valid;
} UBX_NAV_TIMELS_data_t;
typedef struct
{
union
{
uint32_t all;
struct
{
uint32_t all : 1;
uint32_t iTOW : 1;
uint32_t version : 1;
uint32_t srcOfCurrLs : 1;
uint32_t currLs : 1;
uint32_t srcOfLsChange : 1;
uint32_t lsChange : 1;
uint32_t timeToLsEvent : 1;
uint32_t dateOfLsGpsWn : 1;
uint32_t dateOfLsGpsDn : 1;
uint32_t validCurrLs : 1;
uint32_t validTimeToLsEvent : 1;
} bits;
} moduleQueried;
} UBX_NAV_TIMELS_moduleQueried_t;
typedef struct
{
ubxAutomaticFlags automaticFlags;
UBX_NAV_TIMELS_data_t data;
UBX_NAV_TIMELS_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_NAV_TIMELS_data_t);
UBX_NAV_TIMELS_data_t *callbackData;
} UBX_NAV_TIMELS_t;
// UBX-NAV-SVIN (0x01 0x3B): Survey-in data
const uint16_t UBX_NAV_SVIN_LEN = 40;