From a08198b27e4cf108efad5c5070408409792beb77 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Thu, 13 Jan 2022 12:01:23 +0000 Subject: [PATCH] Add the new callback example --- .../Example1_getLatestNMEAGPGGA.ino | 2 +- .../Example2_NMEA_GGA_Callbacks.ino | 117 ++++++++++++++++++ src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 22 +++- src/SparkFun_u-blox_GNSS_Arduino_Library.h | 2 +- src/u-blox_structs.h | 3 +- 5 files changed, 140 insertions(+), 6 deletions(-) create mode 100644 examples/Automatic_NMEA/Example2_NMEA_GGA_Callbacks/Example2_NMEA_GGA_Callbacks.ino diff --git a/examples/Automatic_NMEA/Example1_getLatestNMEAGPGGA/Example1_getLatestNMEAGPGGA.ino b/examples/Automatic_NMEA/Example1_getLatestNMEAGPGGA/Example1_getLatestNMEAGPGGA.ino index bb6b68a..0e66a56 100644 --- a/examples/Automatic_NMEA/Example1_getLatestNMEAGPGGA/Example1_getLatestNMEAGPGGA.ino +++ b/examples/Automatic_NMEA/Example1_getLatestNMEAGPGGA/Example1_getLatestNMEAGPGGA.ino @@ -18,7 +18,7 @@ The library includes a getLatestNMEAGNGGA function too. This example shows how to use both functions - and how to change the Talker ID so the GNGGA messages become GPGGA. - This example turns off all sentences except for GPGGA. + This example turns off all sentences except for GGA. Feel like supporting open source hardware? Buy a board from SparkFun! diff --git a/examples/Automatic_NMEA/Example2_NMEA_GGA_Callbacks/Example2_NMEA_GGA_Callbacks.ino b/examples/Automatic_NMEA/Example2_NMEA_GGA_Callbacks/Example2_NMEA_GGA_Callbacks.ino new file mode 100644 index 0000000..ca6380a --- /dev/null +++ b/examples/Automatic_NMEA/Example2_NMEA_GGA_Callbacks/Example2_NMEA_GGA_Callbacks.ino @@ -0,0 +1,117 @@ +/* + Get the latest GPGGA / GNGGA NMEA sentence using callbacks + By: Paul Clark + SparkFun Electronics + Date: January 12th, 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 turn on/off the NMEA sentences being output over I2C. + It then demonstrates how to get the latest GPGGA or GNGGA message autonomously using callbacks. + + If the module is using multiple GNSS constellations, the GGA message will be prefixed with Talker ID "GN" instead of "GP". + This example shows how to change the Talker ID so the GNGGA messages become GPGGA. + It also shows how to enable "high precision mode" to include extra decimal places in the GGA messages. + + This example turns off all sentences except for GGA. + + 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 RedBoard + 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 //Needed for I2C to GNSS + +#include //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS +SFE_UBLOX_GNSS myGNSS; + +// Callback: printGPGGA will be called when new GPGGA NMEA data arrives +// See u-blox_structs.h for the full definition of NMEA_GGA_data_t +// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGPGGAcallback +// / _____ This _must_ be NMEA_GGA_data_t +// | / _____ You can use any name you like for the struct +// | | / +// | | | +void printGPGGA(NMEA_GGA_data_t nmeaData) +{ + Serial.print(F("\r\nGPGGA: Length: ")); + Serial.print(nmeaData.length); + Serial.print(F("\tData: ")); + Serial.print((const char *)nmeaData.nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end +} + +// Callback: printGNGGA will be called if new GNGGA NMEA data arrives +// See u-blox_structs.h for the full definition of NMEA_GGA_data_t +// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGNGGAcallback +// / _____ This _must_ be NMEA_GGA_data_t +// | / _____ You can use any name you like for the struct +// | | / +// | | | +void printGNGGA(NMEA_GGA_data_t nmeaData) +{ + Serial.print(F("\r\nGNGGA: Length: ")); + Serial.print(nmeaData.length); + Serial.print(F("\tData: ")); + Serial.print((const char *)nmeaData.nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end +} + +void setup() +{ + + Serial.begin(115200); + Serial.println(F("SparkFun u-blox GNSS Example")); + + Wire.begin(); + + //myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial + + if (myGNSS.begin() == false) + { + Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing.")); + while (1) + ; + } + + // Disable or enable various NMEA sentences over the I2C interface + myGNSS.setI2COutput(COM_TYPE_NMEA | COM_TYPE_UBX); // Turn on both UBX and NMEA sentences on I2C. (Turn off RTCM and SPARTN) + myGNSS.disableNMEAMessage(UBX_NMEA_GLL, COM_PORT_I2C); // Several of these are on by default on ublox board so let's disable them + myGNSS.disableNMEAMessage(UBX_NMEA_GSA, COM_PORT_I2C); + myGNSS.disableNMEAMessage(UBX_NMEA_GSV, COM_PORT_I2C); + myGNSS.disableNMEAMessage(UBX_NMEA_RMC, COM_PORT_I2C); + myGNSS.disableNMEAMessage(UBX_NMEA_VTG, COM_PORT_I2C); + myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C); // Leave only GGA enabled at current navigation rate + + // Set the Main Talker ID to "GP". The NMEA GGA messages will be GPGGA instead of GNGGA + myGNSS.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_GP); + //myGNSS.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_DEFAULT); // Uncomment this line to restore the default main talker ID + + myGNSS.setHighPrecisionMode(true); // Enable High Precision Mode - include extra decimal places in the GGA messages + + //myGNSS.saveConfiguration(VAL_CFG_SUBSEC_IOPORT | VAL_CFG_SUBSEC_MSGCONF); //Optional: Save only the ioPort and message settings to NVM + + Serial.println(F("Messages configured")); + + //myGNSS.setNMEAOutputPort(Serial); // Uncomment this line to echo all NMEA data to Serial for debugging + + // Set up the callback for GPGGA + myGNSS.setNMEAGPGGAcallback(&printGPGGA); + + // Set up the callback for GNGGA + myGNSS.setNMEAGNGGAcallback(&printGNGGA); +} + +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. + + Serial.print("."); + delay(50); +} diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index 650a15e..43e1665 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -1712,6 +1712,13 @@ void SFE_UBLOX_GNSS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t r memset(nmeaPtr, 0, nmeaMaxLength); // Clear the working copy memcpy(nmeaPtr, &nmeaAddressField[0], 6); // Copy the start character and address field into the working copy } + else + { + // if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + // { + // _debugSerial->println(F("process: non-auto NMEA message")); + // } + } // We've just received the end of the address field. Check if it is selected for logging if (logThisNMEA()) @@ -1804,7 +1811,7 @@ void SFE_UBLOX_GNSS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t r nmeaAutomaticFlags *flagsPtr = getNMEAFlagsPtr(); // Get a pointer to the flags nmeaAutomaticFlags flagsCopy = *flagsPtr; flagsCopy.flags.bits.completeCopyValid = 1; // Set the complete copy valid flag - flagsCopy.flags.bits.completeCopyRead = 0; // Clear the complete copy read/stale flag + flagsCopy.flags.bits.completeCopyRead = 0; // Clear the complete copy read flag *flagsPtr = flagsCopy; // Update the flags // Callback if (doesThisNMEAHaveCallback()) // Do we need to copy the data into the callback copy? @@ -4628,7 +4635,7 @@ void SFE_UBLOX_GNSS::checkCallbacks(void) if ((storageNMEAGPGGA != NULL) // If RAM has been allocated for message storage && (storageNMEAGPGGA->callbackCopy != NULL) // If RAM has been allocated for the copy of the data && (storageNMEAGPGGA->callbackPointer != NULL) // If the pointer to the callback has been defined - && (storageNMEAGPGGA->automaticFlags.flags.bits.callbackCopyValid == true)) // If the copy of the data is valid + && (storageNMEAGPGGA->automaticFlags.flags.bits.callbackCopyValid == 1)) // If the copy of the data is valid { // if (_printDebug == true) // _debugSerial->println(F("checkCallbacks: calling callback for GPGGA")); @@ -4636,6 +4643,17 @@ void SFE_UBLOX_GNSS::checkCallbacks(void) storageNMEAGPGGA->automaticFlags.flags.bits.callbackCopyValid = 0; // Mark the data as stale } + if ((storageNMEAGNGGA != NULL) // If RAM has been allocated for message storage + && (storageNMEAGNGGA->callbackCopy != NULL) // If RAM has been allocated for the copy of the data + && (storageNMEAGNGGA->callbackPointer != NULL) // If the pointer to the callback has been defined + && (storageNMEAGNGGA->automaticFlags.flags.bits.callbackCopyValid == 1)) // If the copy of the data is valid + { + // if (_printDebug == true) + // _debugSerial->println(F("checkCallbacks: calling callback for GNGGA")); + storageNMEAGNGGA->callbackPointer(*storageNMEAGNGGA->callbackCopy); // Call the callback + storageNMEAGNGGA->automaticFlags.flags.bits.callbackCopyValid = 0; // Mark the data as stale + } + checkCallbacksReentrant = false; } diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.h b/src/SparkFun_u-blox_GNSS_Arduino_Library.h index 5e0252c..77946ce 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.h +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.h @@ -1345,7 +1345,7 @@ public: uint8_t getLatestNMEAGPGGA(NMEA_GGA_data_t *data); // Return the most recent GPGGA: 0 = no data, 1 = stale data, 2 = fresh data bool setNMEAGPGGAcallback(void (*callbackPointer)(NMEA_GGA_data_t)); //Enable a callback on the arrival of a GPGGA message uint8_t getLatestNMEAGNGGA(NMEA_GGA_data_t *data); // Return the most recent GNGGA: 0 = no data, 1 = stale data, 2 = fresh data - bool setNMEAGNGGAcallback(void (*callbackPointer)(NMEA_GGA_data_t)); //Enable a callback on the arrival of a GPGGA message + bool setNMEAGNGGAcallback(void (*callbackPointer)(NMEA_GGA_data_t)); //Enable a callback on the arrival of a GNGGA message // 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 diff --git a/src/u-blox_structs.h b/src/u-blox_structs.h index 31fba28..eb51598 100644 --- a/src/u-blox_structs.h +++ b/src/u-blox_structs.h @@ -2242,7 +2242,7 @@ struct nmeaAutomaticFlags uint8_t all; struct { - uint8_t completeCopyValid : 1; // Is the copy of the data struct used by the get function valid/fresh? 0 = invalid/stale, 1 = valid/fresh + uint8_t completeCopyValid : 1; // Is the copy of the data struct used by the get function valid/fresh? 0 = invalid, 1 = valid uint8_t completeCopyRead : 1; // Has the complete copy been read? 0 = unread, 1 = read uint8_t callbackCopyValid : 1; // Is the copy of the data struct used by the callback valid/fresh? 0 = invalid/stale, 1 = valid/fresh } bits; @@ -2280,5 +2280,4 @@ typedef struct NMEA_GGA_data_t *callbackCopy; // The callback gets its own preserved copy of the complete copy } NMEA_GNGGA_t; - #endif