Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
Demonstrate how to 'process' any UBX message - without needing the Auto methods
By: Paul Clark
SparkFun Electronics
Date: July 14th, 2025
License: MIT. See license file for more information.

This example shows how to configure the u-blox GNSS to output (e.g.) UBX_MON_SYS
and process those messages within your own code. This is cool because UBX_MON_SYS
does not have full "Auto" support. There are no setAutoMONSYS or setAutoMONSYScallbackPtr methods.
But we can process it anyway...!

** Please note: processLoggedUBX is called by the library's internal processUBXpacket method. **
** The library will stall while processLoggedUBX is executing. **
** For best results, avoid Serial prints and delays etc. within processLoggedUBX. **

Hardware Connections:
Plug a Qwiic cable into the GPS and a Redboard Qwiic
If you don't have a platform with a Qwiic connection use the
SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)

To minimise I2C bus errors, it is a good idea to open the I2C pull-up split pad links on
the u-blox module breakout.

Feel like supporting open source hardware?
Buy a board from SparkFun!
SparkFun GPS-RTK2 - ZED-F9P (GPS-15136) https://www.sparkfun.com/products/15136
SparkFun GPS-RTK-SMA - ZED-F9P (GPS-16481) https://www.sparkfun.com/products/16481
SparkFun MAX-M10S Breakout (GPS-18037) https://www.sparkfun.com/products/18037
SparkFun ZED-F9K Breakout (GPS-18719) https://www.sparkfun.com/products/18719
SparkFun ZED-F9R Breakout (GPS-16344) https://www.sparkfun.com/products/16344

*/

#include <Wire.h> //Needed for I2C to GNSS

#include <SparkFun_u-blox_GNSS_v3.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS_v3

// Define a custom class so we can override processLoggedUBX
class my_SFE_UBLOX_GNSS : public SFE_UBLOX_GNSS
{
public:
void processLoggedUBX(ubxPacket *incomingUBX)
{
// processLoggedUBX will stall the library while it is executing
// For best results, quickly copy the data elsewhere. Avoid Serial prints, delays etc..
// incomingUBX->len contains the payload length (uint16_t)
// incomingUBX->payload points to the payload (uint8_t *)
// The ubxPacket struct is defined in u-blox_external_typedefs.h

Serial.printf("UBX message received: Class 0x%02x ID 0x%02x", incomingUBX->cls, incomingUBX->id);
if ((incomingUBX->cls == UBX_CLASS_MON) && (incomingUBX->id == UBX_MON_SYS))
{
// We can use the "extract" helper functions to read the data - useful for 16, 32 and 64-bit values
// The full list is:
// uint64_t extractLongLong(ubxPacket *msg, uint16_t spotToStart); // Combine eight bytes from payload into uint64_t
// uint64_t extractSignedLongLong(ubxPacket *msg, uint16_t spotToStart); // Combine eight bytes from payload into int64_t
// uint32_t extractLong(ubxPacket *msg, uint16_t spotToStart); // Combine four bytes from payload into long
// int32_t extractSignedLong(ubxPacket *msg, uint16_t spotToStart); // Combine four bytes from payload into signed long (avoiding any ambiguity caused by casting)
// uint16_t extractInt(ubxPacket *msg, uint16_t spotToStart); // Combine two bytes from payload into int
// int16_t extractSignedInt(ubxPacket *msg, uint16_t spotToStart);
// uint8_t extractByte(ubxPacket *msg, uint16_t spotToStart); // Get byte from payload
// int8_t extractSignedChar(ubxPacket *msg, uint16_t spotToStart); // Get signed 8-bit value from payload
// float extractFloat(ubxPacket *msg, uint16_t spotToStart); // Get 32-bit float from payload
// double extractDouble(ubxPacket *msg, uint16_t spotToStart); // Get 64-bit double from payload

uint8_t cpuLoad = extractByte(incomingUBX, 2);
uint32_t runTime = extractLong(incomingUBX, 8);
int8_t tempValue = extractSignedChar(incomingUBX, 18);

Serial.printf(" : UBX-MON-SYS : cpuLoad %d%% runTime %ds tempValue %dC", (int)cpuLoad, (int)runTime, (int)tempValue);
}
Serial.println();
}
};
my_SFE_UBLOX_GNSS myGNSS;

void setup()
{
delay(1000);

Serial.begin(115200);
Serial.println("SparkFun u-blox Example");

Wire.begin(); // Start I2C communication

//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

while (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..."));
}

// 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 | COM_TYPE_RTCM3); //Set the I2C port to output UBX, NMEA and RTCM 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.newCfgValset(VAL_LAYER_RAM_BBR); // Use cfgValset to disable / enable individual messages
myGNSS.addCfgValset(UBLOX_CFG_MSGOUT_UBX_MON_SYS_I2C, 1); // Enable the UBX-MON-SYS message on I2C
myGNSS.sendCfgValset(); // Send the configuration VALSET

myGNSS.enableUBXlogging(UBX_CLASS_MON, UBX_MON_SYS, false, true); // Disable logging of MON-SYS. Enable processing
}

void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new data. MON-SYS data will be processed by processLoggedUBX
}
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=SparkFun u-blox GNSS v3
version=3.1.10
version=3.1.11
author=SparkFun Electronics <[email protected]>
maintainer=SparkFun Electronics <sparkfun.com>
sentence=Library for I2C, Serial and SPI Communication with u-blox GNSS modules<br/><br/>
Expand Down
40 changes: 29 additions & 11 deletions src/u-blox_GNSS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1702,7 +1702,7 @@ void DevUBLOXGNSS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t req
if (packetBuf.cls != UBX_CLASS_ACK)
{
bool logBecauseAuto = autoLookup(packetBuf.cls, packetBuf.id, &maxPayload);
bool logBecauseEnabled = logThisUBX(packetBuf.cls, packetBuf.id);
bool logBecauseEnabled = logThisUBX(packetBuf.cls, packetBuf.id) || processThisUBX(packetBuf.cls, packetBuf.id);

// This is not an ACK so check for a class and ID match
if ((packetBuf.cls == storedClass) && (packetBuf.id == storedID))
Expand Down Expand Up @@ -3260,7 +3260,7 @@ void DevUBLOXGNSS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t
//{

bool logBecauseAuto = autoLookup(incomingUBX->cls, incomingUBX->id, &maximum_payload_size);
bool logBecauseEnabled = logThisUBX(incomingUBX->cls, incomingUBX->id);
bool logBecauseEnabled = logThisUBX(incomingUBX->cls, incomingUBX->id) || processThisUBX(incomingUBX->cls, incomingUBX->id);
if ((!logBecauseAuto) && (logBecauseEnabled))
maximum_payload_size = SFE_UBX_MAX_LENGTH;
if (maximum_payload_size == 0)
Expand Down Expand Up @@ -3351,7 +3351,7 @@ void DevUBLOXGNSS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t

// This is not an ACK and we do not have a complete class and ID match
// So let's check for an "automatic" message arriving
else if ((autoLookup(incomingUBX->cls, incomingUBX->id)) || (logThisUBX(incomingUBX->cls, incomingUBX->id)))
else if ((autoLookup(incomingUBX->cls, incomingUBX->id)) || (logThisUBX(incomingUBX->cls, incomingUBX->id)) || (processThisUBX(incomingUBX->cls, incomingUBX->id)))
{
// This isn't the message we are looking for...
// Let's say so and leave incomingUBX->classAndIDmatch _unchanged_
Expand Down Expand Up @@ -5117,10 +5117,14 @@ void DevUBLOXGNSS::processUBXpacket(ubxPacket *msg)
// Check if this UBX message should be added to the file buffer - if it has not been added already
if ((!addedToFileBuffer) && (logThisUBX(msg->cls, msg->id)))
storePacket(msg);

// Check if UBX message should be processed
if (processThisUBX(msg->cls, msg->id))
processLoggedUBX(msg);
}

// UBX Logging - without needing to have or use "Auto" methods
void DevUBLOXGNSS::enableUBXlogging(uint8_t UBX_CLASS, uint8_t UBX_ID, bool enable)
void DevUBLOXGNSS::enableUBXlogging(uint8_t UBX_CLASS, uint8_t UBX_ID, bool logMe, bool processMe)
{
// If the list is empty
if (sfe_ublox_ubx_logging_list_head == nullptr)
Expand All @@ -5129,7 +5133,8 @@ void DevUBLOXGNSS::enableUBXlogging(uint8_t UBX_CLASS, uint8_t UBX_ID, bool enab
sfe_ublox_ubx_logging_list_head = new sfe_ublox_ubx_logging_list_t;
sfe_ublox_ubx_logging_list_head->UBX_CLASS = UBX_CLASS;
sfe_ublox_ubx_logging_list_head->UBX_ID = UBX_ID;
sfe_ublox_ubx_logging_list_head->enable = enable;
sfe_ublox_ubx_logging_list_head->logMe = logMe;
sfe_ublox_ubx_logging_list_head->processMe = processMe;
sfe_ublox_ubx_logging_list_head->next = nullptr;
return;
}
Expand All @@ -5144,7 +5149,8 @@ void DevUBLOXGNSS::enableUBXlogging(uint8_t UBX_CLASS, uint8_t UBX_ID, bool enab
if ((sfe_ublox_ubx_logging_list_ptr->UBX_CLASS == UBX_CLASS) // Check for a match
&& (sfe_ublox_ubx_logging_list_ptr->UBX_ID == UBX_ID))
{
sfe_ublox_ubx_logging_list_ptr->enable = enable; // Update enable
sfe_ublox_ubx_logging_list_ptr->logMe = logMe; // Update logMe
sfe_ublox_ubx_logging_list_ptr->logMe = processMe; // Update processMe
return;
}

Expand All @@ -5159,12 +5165,21 @@ void DevUBLOXGNSS::enableUBXlogging(uint8_t UBX_CLASS, uint8_t UBX_ID, bool enab
sfe_ublox_ubx_logging_list_ptr = sfe_ublox_ubx_logging_list_ptr->next;
sfe_ublox_ubx_logging_list_ptr->UBX_CLASS = UBX_CLASS;
sfe_ublox_ubx_logging_list_ptr->UBX_ID = UBX_ID;
sfe_ublox_ubx_logging_list_ptr->enable = enable;
sfe_ublox_ubx_logging_list_ptr->logMe = logMe;
sfe_ublox_ubx_logging_list_ptr->processMe = processMe;
sfe_ublox_ubx_logging_list_ptr->next = nullptr;
}

// PRIVATE: Returns true if this UBX should be added to the logging buffer
bool DevUBLOXGNSS::logThisUBX(uint8_t UBX_CLASS, uint8_t UBX_ID)
{
return logOrProcessThisUBX(UBX_CLASS, UBX_ID, true);
}
bool DevUBLOXGNSS::processThisUBX(uint8_t UBX_CLASS, uint8_t UBX_ID)
{
return logOrProcessThisUBX(UBX_CLASS, UBX_ID, false);
}
bool DevUBLOXGNSS::logOrProcessThisUBX(uint8_t UBX_CLASS, uint8_t UBX_ID, bool log)
{
// If the list is empty
if (sfe_ublox_ubx_logging_list_head == nullptr)
Expand All @@ -5178,7 +5193,10 @@ bool DevUBLOXGNSS::logThisUBX(uint8_t UBX_CLASS, uint8_t UBX_ID)
if ((sfe_ublox_ubx_logging_list_ptr->UBX_CLASS == UBX_CLASS) // Check for a match
&& (sfe_ublox_ubx_logging_list_ptr->UBX_ID == UBX_ID))
{
return sfe_ublox_ubx_logging_list_ptr->enable;
if (log)
return (sfe_ublox_ubx_logging_list_ptr->logMe);
else
return (sfe_ublox_ubx_logging_list_ptr->processMe);
}

if (sfe_ublox_ubx_logging_list_ptr->next == nullptr)
Expand Down Expand Up @@ -9062,7 +9080,7 @@ bool DevUBLOXGNSS::getESFAutoAlignment(bool *enabled, uint8_t layer, uint16_t ma
}
bool DevUBLOXGNSS::getESFAutoAlignment(uint8_t layer, uint16_t maxWait) // Unsafe overload
{
uint8_t result;
uint8_t result = 0;
getVal8(UBLOX_CFG_SFIMU_AUTO_MNTALG_ENA, &result, layer, maxWait);
return (bool)result;
}
Expand Down Expand Up @@ -17859,7 +17877,7 @@ bool DevUBLOXGNSS::getMeasurementRate(uint16_t *measRate, uint8_t layer, uint16_
}
uint16_t DevUBLOXGNSS::getMeasurementRate(uint8_t layer, uint16_t maxWait) // Unsafe overload...
{
uint16_t measurementRate;
uint16_t measurementRate = 0;

getMeasurementRate(&measurementRate, layer, maxWait);

Expand All @@ -17886,7 +17904,7 @@ bool DevUBLOXGNSS::getNavigationRate(uint16_t *navRate, uint8_t layer, uint16_t
}
uint16_t DevUBLOXGNSS::getNavigationRate(uint8_t layer, uint16_t maxWait) // Unsafe overload...
{
uint16_t navigationRate;
uint16_t navigationRate = 0;

getNavigationRate(&navigationRate, layer, maxWait);

Expand Down
7 changes: 5 additions & 2 deletions src/u-blox_GNSS.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ class DevUBLOXGNSS
void processRTCM(uint8_t incoming) __attribute__((weak)); // Given rtcm byte, do something with it. User can overwrite if desired to pipe bytes to radio, internet, etc.
void processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID); // Given a character, file it away into the uxb packet structure
void processUBXpacket(ubxPacket *msg); // Once a packet has been received and validated, identify this packet's class/id and update internal flags
virtual void processLoggedUBX(ubxPacket *incomingUBX) {} // Process any UBX message with enableUBXlogging processMe set true

// Send I2C/Serial/SPI commands to the module

Expand Down Expand Up @@ -1361,7 +1362,7 @@ void logSECSIG(bool enabled = true);
#endif

// UBX Logging - log any UBX message using packetAuto and avoiding having to have and use "Auto" (setAutonnn and lognnn) methods
void enableUBXlogging(uint8_t UBX_CLASS, uint8_t UBX_ID, bool enable = true);
void enableUBXlogging(uint8_t UBX_CLASS, uint8_t UBX_ID, bool logMe = true, bool processMe = false);

// Functions to extract signed and unsigned 8/16/32-bit data from a ubxPacket
// From v2.0: These are public. The user can call these to extract data from custom packets
Expand Down Expand Up @@ -1663,7 +1664,9 @@ void logSECSIG(bool enabled = true);

// UBX logging
sfe_ublox_ubx_logging_list_t *sfe_ublox_ubx_logging_list_head = nullptr; // Linked list of which messages to log
bool logThisUBX(uint8_t UBX_CLASS, uint8_t UBX_ID); // Returns true if this UBX should be added to the logging buffer
bool logThisUBX(uint8_t UBX_CLASS, uint8_t UBX_ID); // Returns true if this UBX should be added to the logging buffer - for logging
bool processThisUBX(uint8_t UBX_CLASS, uint8_t UBX_ID); // Returns true if this UBX should be added to the logging buffer - for processing
bool logOrProcessThisUBX(uint8_t UBX_CLASS, uint8_t UBX_ID, bool log); // Called by logThisUBX and processThisUBX

// Flag to prevent reentry into checkCallbacks
// Prevent badness if the user accidentally calls checkCallbacks from inside a callback
Expand Down
3 changes: 2 additions & 1 deletion src/u-blox_external_typedefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,8 @@ struct sfe_ublox_ubx_logging_list_t
{
uint8_t UBX_CLASS;
uint8_t UBX_ID;
bool enable;
bool logMe;
bool processMe;
sfe_ublox_ubx_logging_list_t *next;
};

Expand Down