Skip to content

Commit

Permalink
v3.1.3 - add full support for NAV-SIG - change NEO-F10N example to NA…
Browse files Browse the repository at this point in the history
…V SIG
  • Loading branch information
PaulZC committed Feb 29, 2024
1 parent 7ceb69b commit 0396f45
Show file tree
Hide file tree
Showing 6 changed files with 355 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
/*
Configuring the NEO-F10N GNSS to send RXM RAWX reports over Serial and display them using a callback
Configuring the NEO-F10N GNSS to send NAV SIG reports over Serial and display them using a callback
By: Paul Clark
SparkFun Electronics
Date: November 24th, 2023
Date: February 29th, 2024
License: MIT. See license file for more information.
This example shows how to configure the u-blox NEO-F10N GNSS to send RXM RAWX reports automatically
This example shows how to configure the u-blox NEO-F10N GNSS to send NAV SIG reports automatically
and access the data via a callback. It also demonstrates how to mark the L5 signals as healthy.
Note: the NEO-F10N only supports UART1. It does not support I2C, SPI or built-in USB.
To run this example on the SparkFun NEO-F10N breakout, you need to open the USB-TX and USB-RX jumpers
to isolate the on-board CH340 USB interface chip. See Hardware Connections below.
Note: the engineering sample of the NEO-F10N-00B supports RXM-RAWX. Production firmware may not.
Feel like supporting open source hardware?
Buy a board from SparkFun!
NEO-F10N: https://www.sparkfun.com/products/24114
Expand All @@ -32,22 +30,22 @@
#include <SparkFun_u-blox_GNSS_v3.h> //http://librarymanager/All#SparkFun_u-blox_GNSS_v3
SFE_UBLOX_GNSS_SERIAL myGNSS;

// Callback: newRAWX will be called when new RXM RAWX data arrives
// See u-blox_structs.h for the full definition of UBX_RXMRAWX_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoRXMRAWXcallback
// / _____ This _must_ be UBX_RXM_RAWX_data_t
// Callback: newSIG will be called when new NAV SIG data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_SIG_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoNAVSIGcallback
// / _____ This _must_ be UBX_NAV_SIG_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void newRAWX(UBX_RXM_RAWX_data_t *ubxDataStruct)
void newSIG(UBX_NAV_SIG_data_t *ubxDataStruct)
{
Serial.println();

Serial.print(F("New RAWX data received. It contains "));
Serial.print(ubxDataStruct->header.numMeas); // Print numMeas (Number of measurements / blocks)
Serial.print(F("New NAV SIG data received. It contains "));
Serial.print(ubxDataStruct->header.numSigs); // Print numSigs (Number of signals / blocks)
Serial.println(F(" data blocks:"));

for (uint8_t block = 0; block < ubxDataStruct->header.numMeas; block++) // For each block
for (uint8_t block = 0; block < ubxDataStruct->header.numSigs; block++) // For each block
{
char SV[14 + 4 + 4 + 256 + 1]; // Allocate space for sigId plus svId plus cno plus bars plus NULL
switch (ubxDataStruct->blocks[block].gnssId)
Expand Down Expand Up @@ -274,7 +272,7 @@ void setup()
myGNSS.setUART1Output(COM_TYPE_UBX); //Set the UART1 port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR

myGNSS.setMeasurementRate(5000); //Produce one solution every five seconds (RAWX produces a _lot_ of data!)
myGNSS.setMeasurementRate(5000); //Produce one solution every five seconds (NAV SIG produces a _lot_ of data!)

myGNSS.setVal8(UBLOX_CFG_SIGNAL_GPS_L5_ENA, 1); // Make sure the GPS L5 band is enabled (needed on the NEO-F9P)

Expand All @@ -284,7 +282,7 @@ void setup()

myGNSS.softwareResetGNSSOnly(); // Restart the GNSS to apply the L5 health override

myGNSS.setAutoRXMRAWXcallbackPtr(&newRAWX); // Enable automatic RXM RAWX messages with callback to newRAWX
myGNSS.setAutoNAVSIGcallbackPtr(&newSIG); // Enable automatic NAV SIG messages with callback to newSIG
}

void loop()
Expand Down
11 changes: 11 additions & 0 deletions keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ UBX_NAV_PVAT_data_t KEYWORD1
UBX_NAV_TIMEUTC_data_t KEYWORD1
UBX_NAV_CLOCK_data_t KEYWORD1
UBX_NAV_SAT_data_t KEYWORD1
UBX_NAV_SIG_data_t KEYWORD1
UBX_NAV_SVIN_data_t KEYWORD1
UBX_NAV_RELPOSNED_data_t KEYWORD1
UBX_NAV_TIMELS_data_t KEYWORD1
Expand Down Expand Up @@ -441,6 +442,15 @@ assumeAutoNAVSAT KEYWORD2
flushNAVSAT KEYWORD2
logNAVSAT KEYWORD2

getNAVSIG KEYWORD2
setAutoNAVSIG KEYWORD2
setAutoNAVSIGrate KEYWORD2
setAutoNAVSIGcallback KEYWORD2
setAutoNAVSIGcallbackPtr KEYWORD2
assumeAutoNAVSIG KEYWORD2
flushNAVSIG KEYWORD2
logNAVSIG KEYWORD2

getRELPOSNED KEYWORD2
setAutoRELPOSNED KEYWORD2
setAutoRELPOSNEDrate KEYWORD2
Expand Down Expand Up @@ -923,6 +933,7 @@ UBX_NAV_PVAT LITERAL1
UBX_NAV_RELPOSNED LITERAL1
UBX_NAV_RESETODO LITERAL1
UBX_NAV_SAT LITERAL1
UBX_NAV_SIG LITERAL1
UBX_NAV_SBAS LITERAL1
UBX_NAV_SIG LITERAL1
UBX_NAV_SLAS LITERAL1
Expand Down
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.2
version=3.1.3
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
241 changes: 241 additions & 0 deletions src/u-blox_GNSS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,16 @@ void DevUBLOXGNSS::end(void)
packetUBXNAVSAT = nullptr;
}

if (packetUBXNAVSIG != nullptr)
{
if (packetUBXNAVSIG->callbackData != nullptr)
{
delete packetUBXNAVSIG->callbackData;
}
delete packetUBXNAVSIG;
packetUBXNAVSIG = nullptr;
}

if (packetUBXRXMPMP != nullptr)
{
if (packetUBXRXMPMP->callbackData != nullptr)
Expand Down Expand Up @@ -1409,6 +1419,12 @@ bool DevUBLOXGNSS::autoLookup(uint8_t Class, uint8_t ID, uint16_t *maxSize)
*maxSize = UBX_NAV_SAT_MAX_LEN;
return (packetUBXNAVSAT != nullptr);
}
else if (ID == UBX_NAV_SIG)
{
if (maxSize != nullptr)
*maxSize = UBX_NAV_SIG_MAX_LEN;
return (packetUBXNAVSIG != nullptr);
}
#endif
break;
case UBX_CLASS_RXM:
Expand Down Expand Up @@ -3868,6 +3884,49 @@ void DevUBLOXGNSS::processUBXpacket(ubxPacket *msg)
}
}
}
else if (msg->id == UBX_NAV_SIG) // Note: length is variable
{
// Parse various byte fields into storage - but only if we have memory allocated for it
if (packetUBXNAVSIG != nullptr)
{
packetUBXNAVSIG->data.header.iTOW = extractLong(msg, 0);
packetUBXNAVSIG->data.header.version = extractByte(msg, 4);
packetUBXNAVSIG->data.header.numSigs = extractByte(msg, 5);

// The NAV SIG message could potentially contain data for 255 signals. (numSigs is uint8_t. UBX_NAV_SIG_MAX_BLOCKS is 92)
for (uint16_t i = 0; (i < UBX_NAV_SIG_MAX_BLOCKS) && (i < ((uint16_t)packetUBXNAVSIG->data.header.numSigs)) && ((i * 16) < (msg->len - 8)); i++)
{
uint16_t offset = (i * 16) + 8;
packetUBXNAVSIG->data.blocks[i].gnssId = extractByte(msg, offset + 0);
packetUBXNAVSIG->data.blocks[i].svId = extractByte(msg, offset + 1);
packetUBXNAVSIG->data.blocks[i].sigId = extractByte(msg, offset + 2);
packetUBXNAVSIG->data.blocks[i].freqId = extractByte(msg, offset + 3);
packetUBXNAVSIG->data.blocks[i].prRes = extractSignedInt(msg, offset + 4);
packetUBXNAVSIG->data.blocks[i].cno = extractByte(msg, offset + 6);
packetUBXNAVSIG->data.blocks[i].qualityInd = extractByte(msg, offset + 7);
packetUBXNAVSIG->data.blocks[i].corrSource = extractByte(msg, offset + 8);
packetUBXNAVSIG->data.blocks[i].ionoModel = extractByte(msg, offset + 9);
packetUBXNAVSIG->data.blocks[i].sigFlags.all = extractInt(msg, offset + 10);
}

// Mark all datums as fresh (not read before)
packetUBXNAVSIG->moduleQueried = true;

// Check if we need to copy the data for the callback
if ((packetUBXNAVSIG->callbackData != nullptr) // If RAM has been allocated for the copy of the data
&& (packetUBXNAVSIG->automaticFlags.flags.bits.callbackCopyValid == false)) // AND the data is stale
{
memcpy(&packetUBXNAVSIG->callbackData->header.iTOW, &packetUBXNAVSIG->data.header.iTOW, sizeof(UBX_NAV_SIG_data_t));
packetUBXNAVSIG->automaticFlags.flags.bits.callbackCopyValid = true;
}

// Check if we need to copy the data into the file buffer
if (packetUBXNAVSIG->automaticFlags.flags.bits.addToFileBuffer)
{
addedToFileBuffer = storePacket(msg);
}
}
}
#endif
else if (msg->id == UBX_NAV_RELPOSNED && ((msg->len == UBX_NAV_RELPOSNED_LEN) || (msg->len == UBX_NAV_RELPOSNED_LEN_F9)))
{
Expand Down Expand Up @@ -5747,6 +5806,17 @@ void DevUBLOXGNSS::checkCallbacks(void)
}
packetUBXNAVSAT->automaticFlags.flags.bits.callbackCopyValid = false; // Mark the data as stale
}

if (packetUBXNAVSIG != nullptr) // If RAM has been allocated for message storage
if (packetUBXNAVSIG->callbackData != nullptr) // If RAM has been allocated for the copy of the data
if (packetUBXNAVSIG->automaticFlags.flags.bits.callbackCopyValid == true) // If the copy of the data is valid
{
if (packetUBXNAVSIG->callbackPointerPtr != nullptr) // If the pointer to the callback has been defined
{
packetUBXNAVSIG->callbackPointerPtr(packetUBXNAVSIG->callbackData); // Call the callback
}
packetUBXNAVSIG->automaticFlags.flags.bits.callbackCopyValid = false; // Mark the data as stale
}
#endif

if (packetUBXNAVRELPOSNED != nullptr) // If RAM has been allocated for message storage
Expand Down Expand Up @@ -12958,6 +13028,177 @@ void DevUBLOXGNSS::logNAVSAT(bool enabled)
return; // Bail if RAM has not been allocated (otherwise we could be writing anywhere!)
packetUBXNAVSAT->automaticFlags.flags.bits.addToFileBuffer = (uint8_t)enabled;
}

// ***** NAV SIG automatic support

// Signal information
// Returns true if commands was successful
bool DevUBLOXGNSS::getNAVSIG(uint16_t maxWait)
{
if (packetUBXNAVSIG == nullptr)
initPacketUBXNAVSIG(); // Check that RAM has been allocated for the NAVSIG data
if (packetUBXNAVSIG == nullptr) // Bail if the RAM allocation failed
return (false);

if (packetUBXNAVSIG->automaticFlags.flags.bits.automatic && packetUBXNAVSIG->automaticFlags.flags.bits.implicitUpdate)
{
// The GPS is automatically reporting, we just check whether we got unread data
checkUbloxInternal(&packetCfg, 0, 0); // Call checkUbloxInternal to parse any incoming data. Don't overwrite the requested Class and ID
return packetUBXNAVSIG->moduleQueried;
}
else if (packetUBXNAVSIG->automaticFlags.flags.bits.automatic && !packetUBXNAVSIG->automaticFlags.flags.bits.implicitUpdate)
{
// Someone else has to call checkUblox for us...
return (false);
}
else
{
// The GPS is not automatically reporting NAVSIG so we have to poll explicitly
packetCfg.cls = UBX_CLASS_NAV;
packetCfg.id = UBX_NAV_SIG;
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);
}
}

// Enable or disable automatic NAVSIG message generation by the GNSS. This changes the way getNAVSIG
// works.
bool DevUBLOXGNSS::setAutoNAVSIG(bool enable, uint8_t layer, uint16_t maxWait)
{
return setAutoNAVSIGrate(enable ? 1 : 0, true, layer, maxWait);
}

// Enable or disable automatic NAVSIG message generation by the GNSS. This changes the way getNAVSIG
// works.
bool DevUBLOXGNSS::setAutoNAVSIG(bool enable, bool implicitUpdate, uint8_t layer, uint16_t maxWait)
{
return setAutoNAVSIGrate(enable ? 1 : 0, implicitUpdate, layer, maxWait);
}

// Enable or disable automatic NAV SAT message generation by the GNSS. This changes the way getNAVSIG
// works.
bool DevUBLOXGNSS::setAutoNAVSIGrate(uint8_t rate, bool implicitUpdate, uint8_t layer, uint16_t maxWait)
{
if (packetUBXNAVSIG == nullptr)
initPacketUBXNAVSIG(); // Check that RAM has been allocated for the data
if (packetUBXNAVSIG == nullptr) // Only attempt this if RAM allocation was successful
return false;

if (rate > 127)
rate = 127;

uint32_t key = UBLOX_CFG_MSGOUT_UBX_NAV_SIG_I2C;
if (_commType == COMM_TYPE_SPI)
key = UBLOX_CFG_MSGOUT_UBX_NAV_SIG_SPI;
else if (_commType == COMM_TYPE_SERIAL)
{
if (!_UART2)
key = UBLOX_CFG_MSGOUT_UBX_NAV_SIG_UART1;
else
key = UBLOX_CFG_MSGOUT_UBX_NAV_SIG_UART2;
}

bool ok = setVal8(key, rate, layer, maxWait);
if (ok)
{
packetUBXNAVSIG->automaticFlags.flags.bits.automatic = (rate > 0);
packetUBXNAVSIG->automaticFlags.flags.bits.implicitUpdate = implicitUpdate;
}
packetUBXNAVSIG->moduleQueried = false; // Mark data as stale
return ok;
}

// Enable automatic navigation message generation by the GNSS.
bool DevUBLOXGNSS::setAutoNAVSIGcallbackPtr(void (*callbackPointerPtr)(UBX_NAV_SIG_data_t *), uint8_t layer, uint16_t maxWait)
{
// Enable auto messages. Set implicitUpdate to false as we expect the user to call checkUblox manually.
bool result = setAutoNAVSIG(true, false, layer, maxWait);
if (!result)
return (result); // Bail if setAuto failed

if (packetUBXNAVSIG->callbackData == nullptr) // Check if RAM has been allocated for the callback copy
{
packetUBXNAVSIG->callbackData = new UBX_NAV_SIG_data_t; // Allocate RAM for the main struct
}

if (packetUBXNAVSIG->callbackData == nullptr)
{
#ifndef SFE_UBLOX_REDUCED_PROG_MEM
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
_debugSerial.println(F("setAutoNAVSIGcallbackPtr: RAM alloc failed!"));
#endif
return (false);
}

packetUBXNAVSIG->callbackPointerPtr = callbackPointerPtr;
return (true);
}

// In case no config access to the GNSS is possible and NAV SAT is send cyclically already
// set config to suitable parameters
bool DevUBLOXGNSS::assumeAutoNAVSIG(bool enabled, bool implicitUpdate)
{
if (packetUBXNAVSIG == nullptr)
initPacketUBXNAVSIG(); // Check that RAM has been allocated for the NAVSIG data
if (packetUBXNAVSIG == nullptr) // Bail if the RAM allocation failed
return (false);

bool changes = packetUBXNAVSIG->automaticFlags.flags.bits.automatic != enabled || packetUBXNAVSIG->automaticFlags.flags.bits.implicitUpdate != implicitUpdate;
if (changes)
{
packetUBXNAVSIG->automaticFlags.flags.bits.automatic = enabled;
packetUBXNAVSIG->automaticFlags.flags.bits.implicitUpdate = implicitUpdate;
}
return changes;
}

// PRIVATE: Allocate RAM for packetUBXNAVSIG and initialize it
bool DevUBLOXGNSS::initPacketUBXNAVSIG()
{
packetUBXNAVSIG = new UBX_NAV_SIG_t; // Allocate RAM for the main struct
if (packetUBXNAVSIG == nullptr)
{
#ifndef SFE_UBLOX_REDUCED_PROG_MEM
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
_debugSerial.println(F("initPacketUBXNAVSIG: RAM alloc failed!"));
#endif
return (false);
}
packetUBXNAVSIG->automaticFlags.flags.all = 0;
packetUBXNAVSIG->callbackPointerPtr = nullptr;
packetUBXNAVSIG->callbackData = nullptr;
packetUBXNAVSIG->moduleQueried = false;
return (true);
}

// Mark all the data as read/stale
void DevUBLOXGNSS::flushNAVSIG()
{
if (packetUBXNAVSIG == nullptr)
return; // Bail if RAM has not been allocated (otherwise we could be writing anywhere!)
packetUBXNAVSIG->moduleQueried = false; // Mark all datums as stale (read before)
}

// Log this data in file buffer
void DevUBLOXGNSS::logNAVSIG(bool enabled)
{
if (packetUBXNAVSIG == nullptr)
return; // Bail if RAM has not been allocated (otherwise we could be writing anywhere!)
packetUBXNAVSIG->automaticFlags.flags.bits.addToFileBuffer = (uint8_t)enabled;
}
#endif

// ***** NAV RELPOSNED automatic support
Expand Down
Loading

0 comments on commit 0396f45

Please sign in to comment.