diff --git a/examples/Data_Logging/DataLoggingExample7_OpenLogESP32_SPI_SDIO/DataLoggingExample7_OpenLogESP32_SPI_SDIO.ino b/examples/Data_Logging/DataLoggingExample7_OpenLogESP32_SPI_SDIO/DataLoggingExample7_OpenLogESP32_SPI_SDIO.ino new file mode 100644 index 00000000..abeca485 --- /dev/null +++ b/examples/Data_Logging/DataLoggingExample7_OpenLogESP32_SPI_SDIO/DataLoggingExample7_OpenLogESP32_SPI_SDIO.ino @@ -0,0 +1,340 @@ +/* + Configuring the GNSS to automatically send RXM SFRBX and RAWX reports over SPI and log them to file on SD card using full 4-bit SDIO + By: Paul Clark + SparkFun Electronics + Date: October 20th, 2022 + 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 RXM SFRBX and RAWX reports automatically + and log the data to SD card in UBX format. + + This code is written for the OpenLog ESP32 (DEV-20594) - coming soon! + + Hardware set-up: + Close the DSEL jumper on the ZED-F9P breakout - to select SPI mode + Connect: + OpenLog ESP32 : ZED-F9P + GND GND + 3V3_SW 3V3 + SCK (18) SCK + PICO (23) PICO (MOSI) + POCI (19) POCI (MISO) + 33 CS + + ** Please note: this example will only work on u-blox ADR or High Precision GNSS or Time Sync products ** + + Data is logged in u-blox UBX format. + + Feel like supporting open source hardware? + Buy a board from SparkFun! + OpenLog ESP32: https://www.sparkfun.com/products/20594 + ZED-F9P RTK2: https://www.sparkfun.com/products/15136 + NEO-M8P RTK: https://www.sparkfun.com/products/15005 +*/ + +#define GNSS_CS 33 // Connect the ZED-F9P CS pin to OpenLog ESP32 pin 33 +#define EN_3V3_SW 32 // The 3.3V_SW regulator Enable pin is connected to D32 +#define STAT_LED 25 // The OpenLog ESP32 STAT LED is connected to pin 25 +#define IMU_CS 5 // The ISM330 IMU CS is connected to pin 5 +#define MAG_CS 27 // The MMC5983 Mag CS is connected to pin 27 + +#include "FS.h" +#include "SD_MMC.h" +File myFile; + +#include +#define spiPort SPI + +#include //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS +SFE_UBLOX_GNSS myGNSS; + +#define sdWriteSize 2048 // Write data to the SD card in blocks of n*512 bytes +#define fileBufferSize 65530 // Allocate just under 64KBytes of RAM for UBX message storage +#define navRate 20 // Set the Nav Rate (Frequency) to 20Hz +//#define ubxOnly // Uncomment this line to log UBX (RAWX and SFRBX) only +uint8_t *myBuffer; // Use myBuffer to hold the data while we write it to SD card + +unsigned long lastPrint; // Record when the last Serial print took place + +// Note: we'll keep a count of how many SFRBX and RAWX messages arrive - but the count will not be completely accurate. +// If two or more SFRBX messages arrive together as a group and are processed by one call to checkUblox, the count will +// only increase by one. + +int numSFRBX = 0; // Keep count of how many SFRBX message groups have been received (see note above) +int numRAWX = 0; // Keep count of how many RAWX message groups have been received (see note above) + +// Callback: newSFRBX will be called when new RXM SFRBX data arrives +// See u-blox_structs.h for the full definition of UBX_RXMSFRBX_data_t +// _____ You can use any name you like for the callback. Use the same name when you call setAutoRXMSFRBXcallback +// / _____ This _must_ be UBX_RXM_SFRBX_data_t +// | / _____ You can use any name you like for the struct +// | | / +// | | | +void newSFRBX(UBX_RXM_SFRBX_data_t *ubxDataStruct) +{ + numSFRBX++; // Increment the count +} + +// 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 +// | / _____ You can use any name you like for the struct +// | | / +// | | | +void newRAWX(UBX_RXM_RAWX_data_t *ubxDataStruct) +{ + numRAWX++; // Increment the count +} + +void setup() +{ + Serial.begin(115200); + + pinMode(STAT_LED, OUTPUT); // Flash the STAT LED each time we write to the SD card + digitalWrite(STAT_LED, LOW); + + pinMode(GNSS_CS, OUTPUT); + digitalWrite(GNSS_CS, HIGH); + pinMode(IMU_CS, OUTPUT); + digitalWrite(IMU_CS, HIGH); + pinMode(MAG_CS, OUTPUT); + digitalWrite(MAG_CS, HIGH); + + spiPort.begin(); + + // Do a fake transaction to initialize the SPI pins + spiPort.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); + spiPort.transfer(0); + spiPort.endTransaction(); + + pinMode(EN_3V3_SW, OUTPUT); // Enable power for the microSD card and GNSS + digitalWrite(EN_3V3_SW, HIGH); + + delay(3000); // Allow time for the GNSS and SD card to start up and for Tera Term to reconnect + Serial.println(F("SparkFun OpenLog ESP32 GNSS Logging : SPI and SDIO")); + + // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + // Initialize the GNSS + + Serial.println(F("Initializing the GNSS...")); + + //myGNSS.enableDebugging(); // Uncomment this line to see helpful debug messages on Serial + + myGNSS.setFileBufferSize(fileBufferSize); // setFileBufferSize must be called _before_ .begin + + // Connect to the u-blox module using SPI port, csPin and speed setting + // ublox devices generally work up to 5MHz. We'll use 4MHz for this example: + bool begun = false; + do + { + begun = myGNSS.begin(spiPort, GNSS_CS, 4000000); + if (!begun) + { + Serial.println(F("u-blox GNSS not detected on SPI bus.")); + delay(1000); + } + } + while (!begun); + + // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + // Wait for a 3D fix. Get the date and time for the log file + + //myGNSS.factoryDefault(); delay(5000); // Uncomment this line to reset the module back to its factory defaults + +#ifdef ubxOnly + myGNSS.setSPIOutput(COM_TYPE_UBX); //Set the SPI port to output only UBX +#else + myGNSS.setSPIOutput(COM_TYPE_UBX | COM_TYPE_NMEA); //Set the SPI port to output both UBX and NMEA messages +#endif + + //myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Optional: save (only) the communications port settings to flash and BBR + + Serial.print(F("Waiting for a 3D fix")); + + uint8_t fix = 0; + + do + { + fix = myGNSS.getFixType(); + delay(1000); + Serial.print(F(".")); + } + while ( fix != 3 ); // Wait for a 3D fix + + Serial.println(); + + uint16_t y = myGNSS.getYear(); + uint8_t M = myGNSS.getMonth(); + uint8_t d = myGNSS.getDay(); + uint8_t h = myGNSS.getHour(); + uint8_t m = myGNSS.getMinute(); + uint8_t s = myGNSS.getSecond(); + + char szBuffer[40] = {'\0'}; + snprintf(szBuffer, sizeof(szBuffer), "/%04d%02d%02d%02d%02d%02d.ubx", y, M, d, h, m, s); + + Serial.println(F("GNSS initialized.")); + + // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + // Initialize the SD card. Open the log file + + Serial.println(F("Initializing SD card...")); + + // Begin the SD card + if(!SD_MMC.begin()) + { + Serial.println(F("Card mount failed. Freezing...")); + while(1); + } + + // Open the log file for writing + Serial.printf("Log file is: %s\r\n", szBuffer); + myFile = SD_MMC.open((const char *)szBuffer, FILE_WRITE); + if(!myFile) + { + Serial.println(F("Failed to open log file for writing. Freezing...")); + while(1); + } + + Serial.println(F("SD card initialized.")); + + // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + // Wait for a key press + + 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(); + } + + // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + // Enable RAWX and SFRBX + + myGNSS.setAutoRXMSFRBXcallbackPtr(&newSFRBX); // Enable automatic RXM SFRBX messages with callback to newSFRBX + + myGNSS.logRXMSFRBX(); // Enable RXM SFRBX data logging + + myGNSS.setAutoRXMRAWXcallbackPtr(&newRAWX); // Enable automatic RXM RAWX messages with callback to newRAWX + + myGNSS.logRXMRAWX(); // Enable RXM RAWX data logging + + myBuffer = new uint8_t[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card + +#ifndef ubxOnly + myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_SPI, navRate); // Ensure the GxGGA (Global positioning system fix data) message is enabled. Send every second. + myGNSS.enableNMEAMessage(UBX_NMEA_GSA, COM_PORT_SPI, navRate); // Ensure the GxGSA (GNSS DOP and Active satellites) message is enabled. Send every second. + myGNSS.enableNMEAMessage(UBX_NMEA_GSV, COM_PORT_SPI, navRate); // Ensure the GxGSV (GNSS satellites in view) message is enabled. Send every second. + myGNSS.enableNMEAMessage(UBX_NMEA_GST, COM_PORT_SPI, navRate); // Ensure the GxGST (Position error statistics) message is enabled. Send every second. + myGNSS.enableNMEAMessage(UBX_NMEA_RMC, COM_PORT_SPI, navRate); // Ensure the GxRMC (Recommended minimum: position, velocity and time) message is enabled. Send every second. + myGNSS.setNMEALoggingMask(SFE_UBLOX_FILTER_NMEA_GGA | SFE_UBLOX_FILTER_NMEA_GSA | SFE_UBLOX_FILTER_NMEA_GSV | SFE_UBLOX_FILTER_NMEA_GST | SFE_UBLOX_FILTER_NMEA_RMC); // Log only these NMEA messages +#endif + + myGNSS.setNavigationFrequency(navRate); // Set navigation rate + + 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. + myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed. + + // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + while (myGNSS.fileBufferAvailable() >= sdWriteSize) // Check to see if we have at least sdWriteSize waiting in the buffer + { + digitalWrite(STAT_LED, HIGH); // Flash the STAT LED each time we write to the SD card + + myGNSS.extractFileBufferData(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 + + // 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. + myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed. + + digitalWrite(STAT_LED, LOW); // Turn the STAT LED off again + } + + // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + if (millis() > (lastPrint + 1000)) // Print the message count once per second + { + uint16_t maxBufferBytes = myGNSS.getMaxFileBufferAvail(); // Get how full the file buffer has been (not how full it is now) + float bufferHigh = 100.0 * (float)maxBufferBytes / (float)fileBufferSize; + + Serial.print(F("Message groups received: SFRBX: ")); // Print how many message groups have been received (see note above) + Serial.print(numSFRBX); + Serial.print(F(" RAWX: ")); + Serial.print(numRAWX); + Serial.print(F(" \tBuffer high tide: ")); + Serial.print(bufferHigh, 1); // It is a fun thing to watch how full the buffer gets + if (bufferHigh > 90.) + Serial.println(F("%!!")); + else if (bufferHigh > 80.) + Serial.println(F("%!")); + else + Serial.println(F("%")); + + 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(STAT_LED, HIGH); // Flash the STAT LED while we write to the 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(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 + + remainingBytes -= bytesToWrite; // Decrement remainingBytes + } + + digitalWrite(STAT_LED, LOW); // Turn the STAT LED off + + myFile.close(); // Close the data file + + myGNSS.setNavigationFrequency(1); // Set navigation rate to 1Hz + + myGNSS.disableMessage(UBX_CLASS_RXM, UBX_RXM_RAWX, COM_PORT_SPI); + myGNSS.disableMessage(UBX_CLASS_RXM, UBX_RXM_SFRBX, COM_PORT_SPI); + + myGNSS.setSPIOutput(COM_TYPE_UBX | COM_TYPE_NMEA); // Re-enable NMEA + + Serial.println(F("Logging stopped. Freezing...")); + while(1); // Do nothing more + } + + // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +} diff --git a/keywords.txt b/keywords.txt index 503c596a..c654d5e4 100644 --- a/keywords.txt +++ b/keywords.txt @@ -79,6 +79,7 @@ NMEA_ZDA_data_t KEYWORD1 ####################################### setPacketCfgPayloadSize KEYWORD2 +getPacketCfgSpaceRemaining KEYWORD2 begin KEYWORD2 end KEYWORD2 setI2CpollingWait KEYWORD2 @@ -232,6 +233,7 @@ setVal8 KEYWORD2 setVal16 KEYWORD2 setVal32 KEYWORD2 setVal64 KEYWORD2 +newCfgValset KEYWORD2 newCfgValset8 KEYWORD2 newCfgValset16 KEYWORD2 newCfgValset32 KEYWORD2 @@ -244,6 +246,9 @@ sendCfgValset8 KEYWORD2 sendCfgValset16 KEYWORD2 sendCfgValset32 KEYWORD2 sendCfgValset64 KEYWORD2 +sendCfgValset KEYWORD2 +getCfgValsetLen KEYWORD2 +getCfgValsetSpaceRemaining KEYWORD2 getNAVPOSECEF KEYWORD2 setAutoNAVPOSECEF KEYWORD2 diff --git a/library.properties b/library.properties index bad7a407..705c91be 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SparkFun u-blox GNSS Arduino Library -version=2.2.17 +version=2.2.18 author=SparkFun Electronics maintainer=SparkFun Electronics sentence=Library for I2C, Serial and SPI Communication with u-blox GNSS modules

diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index 9ca23780..16dea7f1 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -627,6 +627,12 @@ bool SFE_UBLOX_GNSS::setPacketCfgPayloadSize(size_t payloadSize) return (success); } +// Return the number of free bytes remaining in packetCfgPayload +size_t SFE_UBLOX_GNSS::getPacketCfgSpaceRemaining() +{ + return (packetCfgPayloadSize - packetCfg.len); +} + // Initialize the I2C port bool SFE_UBLOX_GNSS::begin(TwoWire &wirePort, uint8_t deviceAddress, uint16_t maxWait, bool assumeSuccess) { @@ -9178,6 +9184,8 @@ uint8_t SFE_UBLOX_GNSS::newCfgValset64(uint32_t key, uint64_t value, uint8_t lay packetCfg.len = 4 + 4 + 8; // 4 byte header, 4 byte key ID, 8 bytes of value packetCfg.startingSpot = 0; + _numCfgKeyIDs = 1; + // Clear all of packet payload memset(payloadCfg, 0, packetCfgPayloadSize); @@ -9215,6 +9223,8 @@ uint8_t SFE_UBLOX_GNSS::newCfgValset32(uint32_t key, uint32_t value, uint8_t lay packetCfg.len = 4 + 4 + 4; // 4 byte header, 4 byte key ID, 4 bytes of value packetCfg.startingSpot = 0; + _numCfgKeyIDs = 1; + // Clear all of packet payload memset(payloadCfg, 0, packetCfgPayloadSize); @@ -9248,6 +9258,8 @@ uint8_t SFE_UBLOX_GNSS::newCfgValset16(uint32_t key, uint16_t value, uint8_t lay packetCfg.len = 4 + 4 + 2; // 4 byte header, 4 byte key ID, 2 bytes of value packetCfg.startingSpot = 0; + _numCfgKeyIDs = 1; + // Clear all of packet payload memset(payloadCfg, 0, packetCfgPayloadSize); @@ -9279,7 +9291,9 @@ uint8_t SFE_UBLOX_GNSS::newCfgValset8(uint32_t key, uint8_t value, uint8_t layer packetCfg.len = 4 + 4 + 1; // 4 byte header, 4 byte key ID, 1 byte value packetCfg.startingSpot = 0; - // Clear all of packet payload + _numCfgKeyIDs = 1; + +// Clear all of packet payload memset(payloadCfg, 0, packetCfgPayloadSize); payloadCfg[0] = 0; // Message Version - set to 0 @@ -9298,10 +9312,49 @@ uint8_t SFE_UBLOX_GNSS::newCfgValset8(uint32_t key, uint8_t value, uint8_t layer return (true); } +// Start defining a new (empty) UBX-CFG-VALSET ubxPacket +// Configuration of modern u-blox modules is now done via getVal/setVal/delVal, ie protocol v27 and above found on ZED-F9P +uint8_t SFE_UBLOX_GNSS::newCfgValset(uint8_t layer) +{ + packetCfg.cls = UBX_CLASS_CFG; + packetCfg.id = UBX_CFG_VALSET; + packetCfg.len = 4; // 4 byte header + packetCfg.startingSpot = 0; + + _numCfgKeyIDs = 0; + + // Clear all of packet payload + memset(payloadCfg, 0, packetCfgPayloadSize); + + payloadCfg[0] = 0; // Message Version - set to 0 + payloadCfg[1] = layer; // By default we ask for the BBR layer + + // All done + return (true); +} + // Add another keyID and value to an existing UBX-CFG-VALSET ubxPacket // This function takes a full 32-bit key and 64-bit value uint8_t SFE_UBLOX_GNSS::addCfgValset64(uint32_t key, uint64_t value) { + if (packetCfg.len >= (packetCfgPayloadSize - 12)) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("addCfgValset64: packetCfgPayloadSize reached!")); +#endif + return false; + } + + if (_numCfgKeyIDs == CFG_VALSET_MAX_KEYS) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("addCfgValset64: key limit reached!")); +#endif + return false; + } + // Load key into outgoing payload payloadCfg[packetCfg.len + 0] = key >> 8 * 0; // Key LSB payloadCfg[packetCfg.len + 1] = key >> 8 * 1; @@ -9321,6 +9374,8 @@ uint8_t SFE_UBLOX_GNSS::addCfgValset64(uint32_t key, uint64_t value) // Update packet length: 4 byte key ID, 8 bytes of value packetCfg.len = packetCfg.len + 4 + 8; + _numCfgKeyIDs++; + // All done return (true); } @@ -9329,6 +9384,24 @@ uint8_t SFE_UBLOX_GNSS::addCfgValset64(uint32_t key, uint64_t value) // This function takes a full 32-bit key and 32-bit value uint8_t SFE_UBLOX_GNSS::addCfgValset32(uint32_t key, uint32_t value) { + if (packetCfg.len >= (packetCfgPayloadSize - 8)) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("addCfgValset32: packetCfgPayloadSize reached!")); +#endif + return false; + } + + if (_numCfgKeyIDs == CFG_VALSET_MAX_KEYS) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("addCfgValset32: key limit reached!")); +#endif + return false; + } + // Load key into outgoing payload payloadCfg[packetCfg.len + 0] = key >> 8 * 0; // Key LSB payloadCfg[packetCfg.len + 1] = key >> 8 * 1; @@ -9344,6 +9417,8 @@ uint8_t SFE_UBLOX_GNSS::addCfgValset32(uint32_t key, uint32_t value) // Update packet length: 4 byte key ID, 4 bytes of value packetCfg.len = packetCfg.len + 4 + 4; + _numCfgKeyIDs++; + // All done return (true); } @@ -9352,6 +9427,24 @@ uint8_t SFE_UBLOX_GNSS::addCfgValset32(uint32_t key, uint32_t value) // This function takes a full 32-bit key and 16-bit value uint8_t SFE_UBLOX_GNSS::addCfgValset16(uint32_t key, uint16_t value) { + if (packetCfg.len >= (packetCfgPayloadSize - 6)) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("addCfgValset16: packetCfgPayloadSize reached!")); +#endif + return false; + } + + if (_numCfgKeyIDs == CFG_VALSET_MAX_KEYS) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("addCfgValset16: key limit reached!")); +#endif + return false; + } + // Load key into outgoing payload payloadCfg[packetCfg.len + 0] = key >> 8 * 0; // Key LSB payloadCfg[packetCfg.len + 1] = key >> 8 * 1; @@ -9365,6 +9458,8 @@ uint8_t SFE_UBLOX_GNSS::addCfgValset16(uint32_t key, uint16_t value) // Update packet length: 4 byte key ID, 2 bytes of value packetCfg.len = packetCfg.len + 4 + 2; + _numCfgKeyIDs++; + // All done return (true); } @@ -9373,6 +9468,24 @@ uint8_t SFE_UBLOX_GNSS::addCfgValset16(uint32_t key, uint16_t value) // This function takes a full 32-bit key and 8-bit value uint8_t SFE_UBLOX_GNSS::addCfgValset8(uint32_t key, uint8_t value) { + if (packetCfg.len >= (packetCfgPayloadSize - 5)) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("addCfgValset8: packetCfgPayloadSize reached!")); +#endif + return false; + } + + if (_numCfgKeyIDs == CFG_VALSET_MAX_KEYS) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("addCfgValset8: key limit reached!")); +#endif + return false; + } + // Load key into outgoing payload payloadCfg[packetCfg.len + 0] = key >> 8 * 0; // Key LSB payloadCfg[packetCfg.len + 1] = key >> 8 * 1; @@ -9385,6 +9498,8 @@ uint8_t SFE_UBLOX_GNSS::addCfgValset8(uint32_t key, uint8_t value) // Update packet length: 4 byte key ID, 1 byte value packetCfg.len = packetCfg.len + 4 + 1; + _numCfgKeyIDs++; + // All done return (true); } @@ -9393,8 +9508,25 @@ uint8_t SFE_UBLOX_GNSS::addCfgValset8(uint32_t key, uint8_t value) // This function takes a full 32-bit key and 64-bit value uint8_t SFE_UBLOX_GNSS::sendCfgValset64(uint32_t key, uint64_t value, uint16_t maxWait) { - // Load keyID and value into outgoing payload - addCfgValset64(key, value); + if (packetCfg.len >= (packetCfgPayloadSize - 12)) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("sendCfgValset64: packetCfgPayloadSize reached!")); +#endif + } + else if (_numCfgKeyIDs == CFG_VALSET_MAX_KEYS) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("sendCfgValset64: key limit reached!")); +#endif + } + else + // Load keyID and value into outgoing payload + addCfgValset64(key, value); + + _numCfgKeyIDs = 0; // Send VALSET command with this key and value return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK @@ -9404,8 +9536,25 @@ uint8_t SFE_UBLOX_GNSS::sendCfgValset64(uint32_t key, uint64_t value, uint16_t m // This function takes a full 32-bit key and 32-bit value uint8_t SFE_UBLOX_GNSS::sendCfgValset32(uint32_t key, uint32_t value, uint16_t maxWait) { - // Load keyID and value into outgoing payload - addCfgValset32(key, value); + if (packetCfg.len >= (packetCfgPayloadSize - 8)) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("sendCfgValset32: packetCfgPayloadSize reached!")); +#endif + } + else if (_numCfgKeyIDs == CFG_VALSET_MAX_KEYS) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("sendCfgValset32: key limit reached!")); +#endif + } + else + // Load keyID and value into outgoing payload + addCfgValset32(key, value); + + _numCfgKeyIDs = 0; // Send VALSET command with this key and value return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK @@ -9415,8 +9564,25 @@ uint8_t SFE_UBLOX_GNSS::sendCfgValset32(uint32_t key, uint32_t value, uint16_t m // This function takes a full 32-bit key and 16-bit value uint8_t SFE_UBLOX_GNSS::sendCfgValset16(uint32_t key, uint16_t value, uint16_t maxWait) { - // Load keyID and value into outgoing payload - addCfgValset16(key, value); + if (packetCfg.len >= (packetCfgPayloadSize - 6)) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("sendCfgValset16: packetCfgPayloadSize reached!")); +#endif + } + else if (_numCfgKeyIDs == CFG_VALSET_MAX_KEYS) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("sendCfgValset16: key limit reached!")); +#endif + } + else + // Load keyID and value into outgoing payload + addCfgValset16(key, value); + + _numCfgKeyIDs = 0; // Send VALSET command with this key and value return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK @@ -9426,13 +9592,51 @@ uint8_t SFE_UBLOX_GNSS::sendCfgValset16(uint32_t key, uint16_t value, uint16_t m // This function takes a full 32-bit key and 8-bit value uint8_t SFE_UBLOX_GNSS::sendCfgValset8(uint32_t key, uint8_t value, uint16_t maxWait) { - // Load keyID and value into outgoing payload - addCfgValset8(key, value); + if (packetCfg.len >= (packetCfgPayloadSize - 5)) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("sendCfgValset8: packetCfgPayloadSize reached!")); +#endif + } + else if (_numCfgKeyIDs == CFG_VALSET_MAX_KEYS) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("sendCfgValset8: key limit reached!")); +#endif + } + else + // Load keyID and value into outgoing payload + addCfgValset8(key, value); + + _numCfgKeyIDs = 0; + + // Send VALSET command with this key and value + return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK +} + +// Send the UBX-CFG-VALSET ubxPacket +uint8_t SFE_UBLOX_GNSS::sendCfgValset(uint16_t maxWait) +{ + _numCfgKeyIDs = 0; // Send VALSET command with this key and value return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } +// Return the number of keys in the CfgValset +uint8_t SFE_UBLOX_GNSS::getCfgValsetLen() +{ + return _numCfgKeyIDs; +} + +// Return the number of free bytes remaining in packetCfgPayload +size_t SFE_UBLOX_GNSS::getCfgValsetSpaceRemaining() +{ + return getPacketCfgSpaceRemaining(); +} + //=-=-=-=-=-=-=-= "Automatic" Messages =-=-=-=-=-=-=-==-=-=-=-=-=-=-= //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.h b/src/SparkFun_u-blox_GNSS_Arduino_Library.h index 746eee7c..5d4df7e5 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.h +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.h @@ -664,6 +664,7 @@ class SFE_UBLOX_GNSS // New in v2.0: allow the payload size for packetCfg to be changed bool setPacketCfgPayloadSize(size_t payloadSize); // Set packetCfgPayloadSize + size_t getPacketCfgSpaceRemaining(); // Returns the number of free bytes remaining in packetCfgPayload // Begin communication with the GNSS. Advanced users can assume success if required. Useful if the port is already outputting messages at high navigation rate. // Begin will then return true if "signs of life" have been seen: reception of _any_ valid UBX packet or _any_ valid NMEA header. @@ -979,6 +980,7 @@ class SFE_UBLOX_GNSS uint8_t setVal16(uint32_t keyID, uint16_t value, uint8_t layer = VAL_LAYER_ALL, uint16_t maxWait = defaultMaxWait); // Sets the 16-bit value at a given group/id/size location uint8_t setVal32(uint32_t keyID, uint32_t value, uint8_t layer = VAL_LAYER_ALL, uint16_t maxWait = defaultMaxWait); // Sets the 32-bit value at a given group/id/size location uint8_t setVal64(uint32_t keyID, uint64_t value, uint8_t layer = VAL_LAYER_ALL, uint16_t maxWait = defaultMaxWait); // Sets the 64-bit value at a given group/id/size location + uint8_t newCfgValset(uint8_t layer = VAL_LAYER_ALL); // Create a new, empty UBX-CFG-VALSET. Add entries with addCfgValset8/16/32/64 uint8_t newCfgValset8(uint32_t keyID, uint8_t value, uint8_t layer = VAL_LAYER_ALL); // Define a new UBX-CFG-VALSET with the given KeyID and 8-bit value uint8_t newCfgValset16(uint32_t keyID, uint16_t value, uint8_t layer = VAL_LAYER_ALL); // Define a new UBX-CFG-VALSET with the given KeyID and 16-bit value uint8_t newCfgValset32(uint32_t keyID, uint32_t value, uint8_t layer = VAL_LAYER_ALL); // Define a new UBX-CFG-VALSET with the given KeyID and 32-bit value @@ -991,6 +993,9 @@ class SFE_UBLOX_GNSS uint8_t sendCfgValset16(uint32_t keyID, uint16_t value, uint16_t maxWait = defaultMaxWait); // Add the final KeyID and 16-bit value to an existing UBX-CFG-VALSET ubxPacket and send it uint8_t sendCfgValset32(uint32_t keyID, uint32_t value, uint16_t maxWait = defaultMaxWait); // Add the final KeyID and 32-bit value to an existing UBX-CFG-VALSET ubxPacket and send it uint8_t sendCfgValset64(uint32_t keyID, uint64_t value, uint16_t maxWait = defaultMaxWait); // Add the final KeyID and 64-bit value to an existing UBX-CFG-VALSET ubxPacket and send it + uint8_t sendCfgValset(uint16_t maxWait = defaultMaxWait); // Send the CfgValset (UBX-CFG-VALSET) construct + uint8_t getCfgValsetLen(); // Returns the length of the current CfgValset construct as number-of-keyIDs + size_t getCfgValsetSpaceRemaining(); // Returns the number of free bytes remaining in packetCfg // get and set functions for all of the "automatic" message processing @@ -1402,12 +1407,12 @@ class SFE_UBLOX_GNSS // Helper functions for HPPOSECEF uint32_t getPositionAccuracy(uint16_t maxWait = defaultMaxWait); // Returns the 3D accuracy of the current high-precision fix, in mm. Supported on NEO-M8P, ZED-F9P, - int32_t getHighResECEFX(uint16_t maxWait = defaultMaxWait); // Returns the ECEF X coordinate (cm) - int32_t getHighResECEFY(uint16_t maxWait = defaultMaxWait); // Returns the ECEF Y coordinate (cm) - int32_t getHighResECEFZ(uint16_t maxWait = defaultMaxWait); // Returns the ECEF Z coordinate (cm) - int8_t getHighResECEFXHp(uint16_t maxWait = defaultMaxWait); // Returns the ECEF X coordinate High Precision Component (0.1 mm) - int8_t getHighResECEFYHp(uint16_t maxWait = defaultMaxWait); // Returns the ECEF Y coordinate High Precision Component (0.1 mm) - int8_t getHighResECEFZHp(uint16_t maxWait = defaultMaxWait); // Returns the ECEF Z coordinate High Precision Component (0.1 mm) + int32_t getHighResECEFX(uint16_t maxWait = defaultMaxWait); // Returns the ECEF X coordinate (cm) + int32_t getHighResECEFY(uint16_t maxWait = defaultMaxWait); // Returns the ECEF Y coordinate (cm) + int32_t getHighResECEFZ(uint16_t maxWait = defaultMaxWait); // Returns the ECEF Z coordinate (cm) + int8_t getHighResECEFXHp(uint16_t maxWait = defaultMaxWait); // Returns the ECEF X coordinate High Precision Component (0.1 mm) + int8_t getHighResECEFYHp(uint16_t maxWait = defaultMaxWait); // Returns the ECEF Y coordinate High Precision Component (0.1 mm) + int8_t getHighResECEFZHp(uint16_t maxWait = defaultMaxWait); // Returns the ECEF Z coordinate High Precision Component (0.1 mm) // Helper functions for HPPOSLLH @@ -1788,6 +1793,9 @@ class SFE_UBLOX_GNSS // .begin will return true if the assumeSuccess parameter is true and if _signsOfLife is true // _signsOfLife is set to true when: a valid UBX message is seen; a valig NMEA header is seen. bool _signsOfLife; + + // Keep track of how many keys have been added to CfgValset + uint8_t _numCfgKeyIDs = 0; }; #endif diff --git a/src/u-blox_config_keys.h b/src/u-blox_config_keys.h index b1589faa..a93ec336 100644 --- a/src/u-blox_config_keys.h +++ b/src/u-blox_config_keys.h @@ -43,6 +43,10 @@ #ifndef __u_blox_config_keys_h__ #define __u_blox_config_keys_h__ +// Define the maximum length of a multi-CfgValset construct +// "This message is limited to containing a maximum of 64 key-value pairs" +const uint8_t CFG_VALSET_MAX_KEYS = 64; + // The following consts are used to generate KEY values for the advanced protocol functions of VELGET/SET/DEL const uint8_t VAL_SIZE_1 = 0x01; // One bit const uint8_t VAL_SIZE_8 = 0x02; // One byte