diff --git a/README.md b/README.md index db53b78e..e3a4f227 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ v2.1 of the library adds support for u-blox AssistNowTM Assisted GNSS This library is the new and improved version of the very popular SparkFun u-blox GNSS Arduino Library. v2.0 contains some big changes and improvements: * Seamless support for "automatic" message delivery: - * In v1.8, you could ask for the NAV PVT (Navigation Position Velocity Time) message to be delivered _automatically_, without polling. v2.0 adds automatic support for [**27 messages**](./Theory.md#auto-messages), covering the full range of: standard and High Precision position, velocity, attitude and time information; relative positioning; event capture with nanosecond time resolution; raw GNSS signal data including carrier phase; Sensor Fusion; and High Navigation Rate data. + * In v1.8, you could ask for the NAV PVT (Navigation Position Velocity Time) message to be delivered _automatically_, without polling. v2.0 adds automatic support for [**29 messages**](./Theory.md#auto-messages), covering the full range of: standard and High Precision position, velocity, attitude and time information; relative positioning; event capture with nanosecond time resolution; raw GNSS signal data including carrier phase; Sensor Fusion; and High Navigation Rate data. * Don't see the message you really need? [Adding_New_Messages](./Adding_New_Messages.md) provides details on how to add "auto" support for your favourite message. * Dynamic memory allocation with clearly-defined data storage structs for each message: * There are no static 'global' variables to eat up your RAM. v2.0 automatically allocates memory for the automatic messages when they are enabled. You may find your total RAM use is lower with v2.0 than with v1.8. diff --git a/Theory.md b/Theory.md index 608860e9..70170c3c 100644 --- a/Theory.md +++ b/Theory.md @@ -55,11 +55,13 @@ In v2.0, the full list of messages which can be processed and logged automatical - UBX-NAV-HPPOSECEF (0x01 0x13): High precision position solution in ECEF - UBX-NAV-HPPOSLLH (0x01 0x14): High precision geodetic position solution - UBX-NAV-PVAT (0x01 0x17): Navigation position velocity attitude time solution (**only with ADR or UDR products**) +- UBX-NAV-TIMEUTC (0x01 0x21): UTC time solution - UBX-NAV-CLOCK (0x01 0x22): Clock solution - UBX-NAV-SAT (0x01 0x35): Satellite information - UBX-NAV-SVIN (0x01 0x3B): Survey-in data (**only with High Precision GNSS products**) - UBX-NAV-RELPOSNED (0x01 0x3C): Relative positioning information in NED frame (**only with High Precision GNSS products**) - UBX-NAV-AOPSTATUS (0x01 0x60): AssistNow Autonomous status +- UBX-NAV-EOE (0x01 0x61): End of epoch - UBX-RXM-SFRBX (0x02 0x13): Broadcast navigation data subframe - UBX-RXM-RAWX (0x02 0x15): Multi-GNSS raw measurement data (**only with ADR or High Precision GNSS or Time Sync products**) - UBX-TIM-TM2 (0x0D 0x03): Time mark data @@ -76,7 +78,6 @@ Please see [Adding_New_Messages](./Adding_New_Messages.md) for details on how to Notes: - UBX-NAV-POSLLH is not supported as UBX-NAV-PVT contains the same information -- UBX-NAV-TIMEUTC is not supported as UBX-NAV-PVT contains the same information ## Migrating your code to v2.0 diff --git a/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino b/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino index b468f93e..003f801e 100644 --- a/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino +++ b/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino @@ -167,6 +167,6 @@ void loop() uint16_t milliseconds = myGNSS.getMillisecond(); Serial.print(F(" Milliseconds: ")); - Serial.print(altitude); + Serial.print(milliseconds); Serial.println(); } diff --git a/keys/u-blox-D9-QZS-1.01_InterfaceDescription_UBX-21031777_keys_sorted.txt b/keys/u-blox-D9-QZS-1.01_InterfaceDescription_UBX-21031777_keys_sorted.txt new file mode 100644 index 00000000..3ca6e9b4 --- /dev/null +++ b/keys/u-blox-D9-QZS-1.01_InterfaceDescription_UBX-21031777_keys_sorted.txt @@ -0,0 +1,37 @@ +0x10520005 +0x10650001 +0x10650002 +0x10730001 +0x10730003 +0x10740001 +0x10770001 +0x10770003 +0x10780001 +0x20370020 +0x20370030 +0x20370050 +0x20370060 +0x20370080 +0x20520002 +0x20520003 +0x20520004 +0x2091033b +0x2091033d +0x20920002 +0x20920004 +0x3065000a +0x3065000b +0x3065000c +0x40520001 +0x5065000d +0x5065000e +0x5065000f +0x50650010 +0x50650011 +0x50650012 +0x50650013 +0x50650014 +0x50650015 +0x50650016 +0x50650017 +0x50650018 diff --git a/keys/u-blox_config_keys_sorted.txt b/keys/u-blox_config_keys_sorted.txt index e6cc6550..0e4a7a9d 100644 --- a/keys/u-blox_config_keys_sorted.txt +++ b/keys/u-blox_config_keys_sorted.txt @@ -198,6 +198,11 @@ 0x20240013 0x20240014 0x20250038 +0x20370020 +0x20370030 +0x20370050 +0x20370060 +0x20370080 0x20410001 0x20410002 0x20410010 @@ -584,6 +589,11 @@ 0x20910338 0x20910339 0x2091033a +0x2091033b +0x2091033c +0x2091033d +0x2091033e +0x2091033f 0x20910345 0x20910346 0x20910347 diff --git a/keywords.txt b/keywords.txt index 1dd87061..206b7513 100644 --- a/keywords.txt +++ b/keywords.txt @@ -45,12 +45,14 @@ UBX_NAV_SVIN_data_t KEYWORD1 UBX_NAV_RELPOSNED_data_t KEYWORD1 UBX_NAV_TIMELS_data_t KEYWORD1 UBX_NAV_AOPSTATUS_data_t KEYWORD1 +UBX_NAV_EOE_data_t KEYWORD1 UBX_RXM_PMP_data_t KEYWORD1 UBX_RXM_PMP_message_data_t KEYWORD1 UBX_RXM_COR_data_t KEYWORD1 UBX_RXM_SFRBX_data_t KEYWORD1 UBX_RXM_RAWX_data_t KEYWORD1 +UBX_RXM_QZSSL6_message_data_t KEYWORD1 UBX_TIM_TM2_data_t KEYWORD1 @@ -344,6 +346,14 @@ assumeAutoNAVPVAT KEYWORD2 flushNAVPVAT KEYWORD2 logNAVPVAT KEYWORD2 +getNAVTIMEUTC KEYWORD2 +setAutoNAVTIMEUTC KEYWORD2 +setAutoNAVTIMEUTCrate KEYWORD2 +setAutoNAVTIMEUTCcallbackPtr KEYWORD2 +assumeAutoNAVTIMEUTC KEYWORD2 +flushNAVTIMEUTC KEYWORD2 +logNAVTIMEUTC KEYWORD2 + getNAVCLOCK KEYWORD2 setAutoNAVCLOCK KEYWORD2 setAutoNAVCLOCKrate KEYWORD2 @@ -392,9 +402,19 @@ assumeAutoAOPSTATUS KEYWORD2 flushAOPSTATUS KEYWORD2 logAOPSTATUS KEYWORD2 +getNAVEOE KEYWORD2 +setAutoNAVEOE KEYWORD2 +setAutoNAVEOErate KEYWORD2 +setAutoNAVEOEcallbackPtr KEYWORD2 +assumeAutoNAVEOE KEYWORD2 +flushNAVEOE KEYWORD2 +logNAVEOE KEYWORD2 + setRXMPMPcallbackPtr KEYWORD2 setRXMPMPmessageCallbackPtr KEYWORD2 +setRXMQZSSL6messageCallbackPtr KEYWORD2 + setRXMCORcallbackPtr KEYWORD2 getRXMSFRBX KEYWORD2 @@ -770,6 +790,7 @@ UBX_RXM_COR LITERAL1 UBX_RXM_RAWX LITERAL1 UBX_RXM_SFRBX LITERAL1 UBX_RXM_SPARTN LITERAL1 +UBX_RXM_QZSSL6 LITERAL1 UBX_TIM_TM2 LITERAL1 diff --git a/library.properties b/library.properties index b598d402..7959456f 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SparkFun u-blox GNSS Arduino Library -version=2.2.11 +version=2.2.12 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 d74ff8ba..1b50c199 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -251,6 +251,16 @@ void SFE_UBLOX_GNSS::end(void) packetUBXNAVPVAT = NULL; // Redundant? } + if (packetUBXNAVTIMEUTC != NULL) + { + if (packetUBXNAVTIMEUTC->callbackData != NULL) + { + delete packetUBXNAVTIMEUTC->callbackData; + } + delete packetUBXNAVTIMEUTC; + packetUBXNAVTIMEUTC = NULL; // Redundant? + } + if (packetUBXNAVCLOCK != NULL) { if (packetUBXNAVCLOCK->callbackData != NULL) @@ -301,6 +311,16 @@ void SFE_UBLOX_GNSS::end(void) packetUBXNAVAOPSTATUS = NULL; // Redundant? } + if (packetUBXNAVEOE != NULL) + { + if (packetUBXNAVEOE->callbackData != NULL) + { + delete packetUBXNAVEOE->callbackData; + } + delete packetUBXNAVEOE; + packetUBXNAVEOE = NULL; // Redundant? + } + if (packetUBXRXMPMP != NULL) { if (packetUBXRXMPMP->callbackData != NULL) @@ -321,6 +341,16 @@ void SFE_UBLOX_GNSS::end(void) packetUBXRXMPMPmessage = NULL; // Redundant? } + if (packetUBXRXMQZSSL6message != NULL) + { + if (packetUBXRXMQZSSL6message->callbackData != NULL) + { + delete [] packetUBXRXMQZSSL6message->callbackData; + } + delete packetUBXRXMQZSSL6message; + packetUBXRXMQZSSL6message = NULL; // Redundant? + } + if (packetUBXRXMCOR != NULL) { if (packetUBXRXMCOR->callbackData != NULL) @@ -1327,6 +1357,10 @@ bool SFE_UBLOX_GNSS::checkAutomatic(uint8_t Class, uint8_t ID) if (packetUBXNAVPVAT != NULL) result = true; break; + case UBX_NAV_TIMEUTC: + if (packetUBXNAVTIMEUTC != NULL) + result = true; + break; case UBX_NAV_CLOCK: if (packetUBXNAVCLOCK != NULL) result = true; @@ -1351,6 +1385,10 @@ bool SFE_UBLOX_GNSS::checkAutomatic(uint8_t Class, uint8_t ID) if (packetUBXNAVAOPSTATUS != NULL) result = true; break; + case UBX_NAV_EOE: + if (packetUBXNAVEOE != NULL) + result = true; + break; } } break; @@ -1370,6 +1408,10 @@ bool SFE_UBLOX_GNSS::checkAutomatic(uint8_t Class, uint8_t ID) if ((packetUBXRXMPMP != NULL) || (packetUBXRXMPMPmessage != NULL)) result = true; break; + case UBX_RXM_QZSSL6: + if (packetUBXRXMQZSSL6message != NULL) + result = true; + break; case UBX_RXM_COR: if (packetUBXRXMCOR != NULL) result = true; @@ -1511,6 +1553,9 @@ uint16_t SFE_UBLOX_GNSS::getMaxPayloadSize(uint8_t Class, uint8_t ID) case UBX_NAV_PVAT: maxSize = UBX_NAV_PVAT_LEN; break; + case UBX_NAV_TIMEUTC: + maxSize = UBX_NAV_TIMEUTC; + break; case UBX_NAV_CLOCK: maxSize = UBX_NAV_CLOCK_LEN; break; @@ -1529,6 +1574,9 @@ uint16_t SFE_UBLOX_GNSS::getMaxPayloadSize(uint8_t Class, uint8_t ID) case UBX_NAV_AOPSTATUS: maxSize = UBX_NAV_AOPSTATUS_LEN; break; + case UBX_NAV_EOE: + maxSize = UBX_NAV_EOE_LEN; + break; } } break; @@ -1545,6 +1593,9 @@ uint16_t SFE_UBLOX_GNSS::getMaxPayloadSize(uint8_t Class, uint8_t ID) case UBX_RXM_PMP: maxSize = UBX_RXM_PMP_MAX_LEN; break; + case UBX_RXM_QZSSL6: + maxSize = UBX_RXM_QZSSL6_MAX_LEN; + break; case UBX_RXM_COR: maxSize = UBX_RXM_COR_LEN; break; @@ -3545,6 +3596,40 @@ void SFE_UBLOX_GNSS::processUBXpacket(ubxPacket *msg) } } } + else if (msg->id == UBX_NAV_TIMEUTC && msg->len == UBX_NAV_TIMEUTC_LEN) + { + // Parse various byte fields into storage - but only if we have memory allocated for it + if (packetUBXNAVTIMEUTC != NULL) + { + packetUBXNAVTIMEUTC->data.iTOW = extractLong(msg, 0); + packetUBXNAVTIMEUTC->data.tAcc = extractLong(msg, 4); + packetUBXNAVTIMEUTC->data.nano = extractSignedLong(msg, 8); + packetUBXNAVTIMEUTC->data.year = extractInt(msg, 12); + packetUBXNAVTIMEUTC->data.month = extractByte(msg, 14); + packetUBXNAVTIMEUTC->data.day = extractByte(msg, 15); + packetUBXNAVTIMEUTC->data.hour = extractByte(msg, 16); + packetUBXNAVTIMEUTC->data.min = extractByte(msg, 17); + packetUBXNAVTIMEUTC->data.sec = extractByte(msg, 18); + packetUBXNAVTIMEUTC->data.valid.all = extractByte(msg, 19); + + // Mark all datums as fresh (not read before) + packetUBXNAVTIMEUTC->moduleQueried.moduleQueried.all = 0xFFFFFFFF; + + // Check if we need to copy the data for the callback + if ((packetUBXNAVTIMEUTC->callbackData != NULL) // If RAM has been allocated for the copy of the data + && (packetUBXNAVTIMEUTC->automaticFlags.flags.bits.callbackCopyValid == false)) // AND the data is stale + { + memcpy(&packetUBXNAVTIMEUTC->callbackData->iTOW, &packetUBXNAVTIMEUTC->data.iTOW, sizeof(UBX_NAV_TIMEUTC_data_t)); + packetUBXNAVTIMEUTC->automaticFlags.flags.bits.callbackCopyValid = true; + } + + // Check if we need to copy the data into the file buffer + if (packetUBXNAVTIMEUTC->automaticFlags.flags.bits.addToFileBuffer) + { + storePacket(msg); + } + } + } else if (msg->id == UBX_NAV_CLOCK && msg->len == UBX_NAV_CLOCK_LEN) { // Parse various byte fields into storage - but only if we have memory allocated for it @@ -3765,6 +3850,31 @@ void SFE_UBLOX_GNSS::processUBXpacket(ubxPacket *msg) } } } + else if (msg->id == UBX_NAV_EOE && msg->len == UBX_NAV_EOE_LEN) + { + // Parse various byte fields into storage - but only if we have memory allocated for it + if (packetUBXNAVEOE != NULL) + { + packetUBXNAVEOE->data.iTOW = extractLong(msg, 0); + + // Mark all datums as fresh (not read before) + packetUBXNAVEOE->moduleQueried.moduleQueried.all = 0xFFFFFFFF; + + // Check if we need to copy the data for the callback + if ((packetUBXNAVEOE->callbackData != NULL) // If RAM has been allocated for the copy of the data + && (packetUBXNAVEOE->automaticFlags.flags.bits.callbackCopyValid == false)) // AND the data is stale + { + memcpy(&packetUBXNAVEOE->callbackData->iTOW, &packetUBXNAVEOE->data.iTOW, sizeof(UBX_NAV_EOE_data_t)); + packetUBXNAVEOE->automaticFlags.flags.bits.callbackCopyValid = true; + } + + // Check if we need to copy the data into the file buffer + if (packetUBXNAVEOE->automaticFlags.flags.bits.addToFileBuffer) + { + storePacket(msg); + } + } + } break; case UBX_CLASS_RXM: if (msg->id == UBX_RXM_PMP) @@ -3830,6 +3940,31 @@ void SFE_UBLOX_GNSS::processUBXpacket(ubxPacket *msg) packetUBXRXMPMPmessage->automaticFlags.flags.bits.callbackCopyValid = true; // Mark the data as valid } } + else if (msg->id == UBX_RXM_QZSSL6) + // Note: length is variable with version 0x01 + // Note: the field positions depend on the version + { + // Full QZSSL6 message, including Class, ID and checksum + for (int ch = 0; ch < UBX_RXM_QZSSL6_NUM_CHANNELS; ch ++) { + if (0 == (packetUBXRXMQZSSL6message->automaticFlags.flags.bits.callbackCopyValid & (1 << ch))) { + + packetUBXRXMQZSSL6message->callbackData[ch].sync1 = UBX_SYNCH_1; + packetUBXRXMQZSSL6message->callbackData[ch].sync2 = UBX_SYNCH_2; + packetUBXRXMQZSSL6message->callbackData[ch].cls = UBX_CLASS_RXM; + packetUBXRXMQZSSL6message->callbackData[ch].ID = UBX_RXM_QZSSL6; + packetUBXRXMQZSSL6message->callbackData[ch].lengthLSB = msg->len & 0xFF; + packetUBXRXMQZSSL6message->callbackData[ch].lengthMSB = msg->len >> 8; + + memcpy(packetUBXRXMQZSSL6message->callbackData[ch].payload, msg->payload, msg->len); + + packetUBXRXMQZSSL6message->callbackData[ch].checksumA = msg->checksumA; + packetUBXRXMQZSSL6message->callbackData[ch].checksumB = msg->checksumB; + + packetUBXRXMQZSSL6message->automaticFlags.flags.bits.callbackCopyValid |= (1 << ch); + break; // abort when added + } + } + } else if (msg->id == UBX_RXM_COR) { // Parse various byte fields into storage - but only if we have memory allocated for it @@ -5334,6 +5469,19 @@ void SFE_UBLOX_GNSS::checkCallbacks(void) packetUBXNAVPVAT->automaticFlags.flags.bits.callbackCopyValid = false; // Mark the data as stale } + if ((packetUBXNAVTIMEUTC != NULL) // If RAM has been allocated for message storage + && (packetUBXNAVTIMEUTC->callbackData != NULL) // If RAM has been allocated for the copy of the data + && (packetUBXNAVTIMEUTC->automaticFlags.flags.bits.callbackCopyValid == true)) // If the copy of the data is valid + { + if (packetUBXNAVTIMEUTC->callbackPointerPtr != NULL) // If the pointer to the callback has been defined + { + // if (_printDebug == true) + // _debugSerial->println(F("checkCallbacks: calling callbackPtr for NAV TIMEUTC")); + packetUBXNAVTIMEUTC->callbackPointerPtr(packetUBXNAVTIMEUTC->callbackData); // Call the callback + } + packetUBXNAVTIMEUTC->automaticFlags.flags.bits.callbackCopyValid = false; // Mark the data as stale + } + if ((packetUBXNAVCLOCK != NULL) // If RAM has been allocated for message storage && (packetUBXNAVCLOCK->callbackData != NULL) // If RAM has been allocated for the copy of the data && (packetUBXNAVCLOCK->automaticFlags.flags.bits.callbackCopyValid == true)) // If the copy of the data is valid @@ -5423,6 +5571,19 @@ void SFE_UBLOX_GNSS::checkCallbacks(void) packetUBXNAVAOPSTATUS->automaticFlags.flags.bits.callbackCopyValid = false; // Mark the data as stale } + if ((packetUBXNAVEOE != NULL) // If RAM has been allocated for message storage + && (packetUBXNAVEOE->callbackData != NULL) // If RAM has been allocated for the copy of the data + && (packetUBXNAVEOE->automaticFlags.flags.bits.callbackCopyValid == true)) // If the copy of the data is valid + { + if (packetUBXNAVEOE->callbackPointerPtr != NULL) // If the pointer to the callback has been defined + { + // if (_printDebug == true) + // _debugSerial->println(F("checkCallbacks: calling callbackPtr for NAV EOE")); + packetUBXNAVEOE->callbackPointerPtr(packetUBXNAVEOE->callbackData); // Call the callback + } + packetUBXNAVEOE->automaticFlags.flags.bits.callbackCopyValid = false; // Mark the data as stale + } + if ((packetUBXRXMPMP != NULL) // If RAM has been allocated for message storage && (packetUBXRXMPMP->callbackData != NULL) // If RAM has been allocated for the copy of the data && (packetUBXRXMPMP->callbackPointerPtr != NULL) // If the pointer to the callback has been defined @@ -5444,6 +5605,19 @@ void SFE_UBLOX_GNSS::checkCallbacks(void) packetUBXRXMPMPmessage->callbackPointerPtr(packetUBXRXMPMPmessage->callbackData); // Call the callback packetUBXRXMPMPmessage->automaticFlags.flags.bits.callbackCopyValid = false; // Mark the data as stale } + + if ((packetUBXRXMQZSSL6message != NULL) && // If RAM has been allocated for message storage + (packetUBXRXMQZSSL6message->callbackData != NULL) && // If RAM has been allocated for the copy of the data + (packetUBXRXMQZSSL6message->callbackPointerPtr != NULL)) // If the pointer to the callback has been defined + { + for (int ch = 0; ch < UBX_RXM_QZSSL6_NUM_CHANNELS; ch ++) { + if (packetUBXRXMQZSSL6message->automaticFlags.flags.bits.callbackCopyValid & (1 << ch)) // If the copy of the data is valid + { + packetUBXRXMQZSSL6message->callbackPointerPtr( &packetUBXRXMQZSSL6message->callbackData[ch] ); // Call the callback + packetUBXRXMQZSSL6message->automaticFlags.flags.bits.callbackCopyValid &= ~(1 << ch); // clear it + } + } + } if ((packetUBXRXMCOR != NULL) // If RAM has been allocated for message storage && (packetUBXRXMCOR->callbackData != NULL) // If RAM has been allocated for the copy of the data @@ -9842,6 +10016,7 @@ bool SFE_UBLOX_GNSS::initPacketUBXNAVDOP() } packetUBXNAVDOP->automaticFlags.flags.all = 0; packetUBXNAVDOP->callbackPointer = NULL; + packetUBXNAVDOP->callbackPointerPtr = NULL; packetUBXNAVDOP->callbackData = NULL; packetUBXNAVDOP->moduleQueried.moduleQueried.all = 0; return (true); @@ -9863,6 +10038,191 @@ void SFE_UBLOX_GNSS::logNAVDOP(bool enabled) packetUBXNAVDOP->automaticFlags.flags.bits.addToFileBuffer = (uint8_t)enabled; } +// ***** EOE automatic support + +bool SFE_UBLOX_GNSS::getNAVEOE(uint16_t maxWait) +{ + if (packetUBXNAVEOE == NULL) + initPacketUBXNAVEOE(); // Check that RAM has been allocated for the EOE data + if (packetUBXNAVEOE == NULL) // Bail if the RAM allocation failed + return (false); + + if (packetUBXNAVEOE->automaticFlags.flags.bits.automatic && packetUBXNAVEOE->automaticFlags.flags.bits.implicitUpdate) + { + // The GPS is automatically reporting, we just check whether we got unread data + // if (_printDebug == true) + // { + // _debugSerial->println(F("getEOE: Autoreporting")); + // } + checkUbloxInternal(&packetCfg, UBX_CLASS_NAV, UBX_NAV_EOE); + return packetUBXNAVEOE->moduleQueried.moduleQueried.bits.all; + } + else if (packetUBXNAVEOE->automaticFlags.flags.bits.automatic && !packetUBXNAVEOE->automaticFlags.flags.bits.implicitUpdate) + { + // Someone else has to call checkUblox for us... + // if (_printDebug == true) + // { + // _debugSerial->println(F("getEOE: Exit immediately")); + // } + return (false); + } + else + { + // if (_printDebug == true) + // { + // _debugSerial->println(F("getEOE: Polling")); + // } + + // The GPS is not automatically reporting navigation position so we have to poll explicitly + packetCfg.cls = UBX_CLASS_NAV; + packetCfg.id = UBX_NAV_EOE; + 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) + { + // if (_printDebug == true) + // { + // _debugSerial->println(F("getEOE: data in packetCfg was OVERWRITTEN by another message (but that's OK)")); + // } + return (true); + } + + // if (_printDebug == true) + // { + // _debugSerial->print(F("getEOE retVal: ")); + // _debugSerial->println(statusString(retVal)); + // } + return (false); + } +} + +// Enable or disable automatic navigation message generation by the GNSS. This changes the way getEOE +// works. +bool SFE_UBLOX_GNSS::setAutoNAVEOE(bool enable, uint16_t maxWait) +{ + return setAutoNAVEOErate(enable ? 1 : 0, true, maxWait); +} + +// Enable or disable automatic navigation message generation by the GNSS. This changes the way getEOE +// works. +bool SFE_UBLOX_GNSS::setAutoNAVEOE(bool enable, bool implicitUpdate, uint16_t maxWait) +{ + return setAutoNAVEOErate(enable ? 1 : 0, implicitUpdate, maxWait); +} + +// Enable or disable automatic navigation message generation by the GNSS. This changes the way getEOE +// works. +bool SFE_UBLOX_GNSS::setAutoNAVEOErate(uint8_t rate, bool implicitUpdate, uint16_t maxWait) +{ + if (packetUBXNAVEOE == NULL) + initPacketUBXNAVEOE(); // Check that RAM has been allocated for the data + if (packetUBXNAVEOE == NULL) // Only attempt this if RAM allocation was successful + return false; + + packetCfg.cls = UBX_CLASS_CFG; + packetCfg.id = UBX_CFG_MSG; + packetCfg.len = 3; + packetCfg.startingSpot = 0; + payloadCfg[0] = UBX_CLASS_NAV; + payloadCfg[1] = UBX_NAV_EOE; + payloadCfg[2] = rate; // rate relative to navigation freq. + + bool ok = ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + if (ok) + { + packetUBXNAVEOE->automaticFlags.flags.bits.automatic = (rate > 0); + packetUBXNAVEOE->automaticFlags.flags.bits.implicitUpdate = implicitUpdate; + } + packetUBXNAVEOE->moduleQueried.moduleQueried.bits.all = false; + return ok; +} + +// Enable automatic navigation message generation by the GNSS. +bool SFE_UBLOX_GNSS::setAutoNAVEOEcallbackPtr(void (*callbackPointerPtr)(UBX_NAV_EOE_data_t *), uint16_t maxWait) +{ + // Enable auto messages. Set implicitUpdate to false as we expect the user to call checkUblox manually. + bool result = setAutoNAVEOE(true, false, maxWait); + if (!result) + return (result); // Bail if setAuto failed + + if (packetUBXNAVEOE->callbackData == NULL) // Check if RAM has been allocated for the callback copy + { + packetUBXNAVEOE->callbackData = new UBX_NAV_EOE_data_t; // Allocate RAM for the main struct + } + + if (packetUBXNAVEOE->callbackData == NULL) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("setAutoNAVEOEcallbackPtr: RAM alloc failed!")); +#endif + return (false); + } + + packetUBXNAVEOE->callbackPointerPtr = callbackPointerPtr; + return (true); +} + +// In case no config access to the GNSS is possible and EOE is send cyclically already +// set config to suitable parameters +bool SFE_UBLOX_GNSS::assumeAutoNAVEOE(bool enabled, bool implicitUpdate) +{ + if (packetUBXNAVEOE == NULL) + initPacketUBXNAVEOE(); // Check that RAM has been allocated for the data + if (packetUBXNAVEOE == NULL) // Only attempt this if RAM allocation was successful + return false; + + bool changes = packetUBXNAVEOE->automaticFlags.flags.bits.automatic != enabled || packetUBXNAVEOE->automaticFlags.flags.bits.implicitUpdate != implicitUpdate; + if (changes) + { + packetUBXNAVEOE->automaticFlags.flags.bits.automatic = enabled; + packetUBXNAVEOE->automaticFlags.flags.bits.implicitUpdate = implicitUpdate; + } + return changes; +} + +// PRIVATE: Allocate RAM for packetUBXNAVEOE and initialize it +bool SFE_UBLOX_GNSS::initPacketUBXNAVEOE() +{ + packetUBXNAVEOE = new UBX_NAV_EOE_t; // Allocate RAM for the main struct + if (packetUBXNAVEOE == NULL) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("initPacketUBXNAVEOE: RAM alloc failed!")); +#endif + return (false); + } + packetUBXNAVEOE->automaticFlags.flags.all = 0; + packetUBXNAVEOE->callbackPointerPtr = NULL; + packetUBXNAVEOE->callbackData = NULL; + packetUBXNAVEOE->moduleQueried.moduleQueried.all = 0; + return (true); +} + +// Mark all the EOE data as read/stale. This is handy to get data alignment after CRC failure +void SFE_UBLOX_GNSS::flushNAVEOE() +{ + if (packetUBXNAVEOE == NULL) + return; // Bail if RAM has not been allocated (otherwise we could be writing anywhere!) + packetUBXNAVEOE->moduleQueried.moduleQueried.all = 0; // Mark all EOEs as stale (read before) +} + +// Log this data in file buffer +void SFE_UBLOX_GNSS::logNAVEOE(bool enabled) +{ + if (packetUBXNAVEOE == NULL) + return; // Bail if RAM has not been allocated (otherwise we could be writing anywhere!) + packetUBXNAVEOE->automaticFlags.flags.bits.addToFileBuffer = (uint8_t)enabled; +} + // ***** VEH ATT automatic support bool SFE_UBLOX_GNSS::getVehAtt(uint16_t maxWait) @@ -11457,6 +11817,169 @@ void SFE_UBLOX_GNSS::logNAVPVAT(bool enabled) packetUBXNAVPVAT->automaticFlags.flags.bits.addToFileBuffer = (uint8_t)enabled; } +// ***** NAV TIMEUTC automatic support + +bool SFE_UBLOX_GNSS::getNAVTIMEUTC(uint16_t maxWait) +{ + if (packetUBXNAVTIMEUTC == NULL) + initPacketUBXNAVTIMEUTC(); // Check that RAM has been allocated for the TIMEUTC data + if (packetUBXNAVTIMEUTC == NULL) // Bail if the RAM allocation failed + return (false); + + if (packetUBXNAVTIMEUTC->automaticFlags.flags.bits.automatic && packetUBXNAVTIMEUTC->automaticFlags.flags.bits.implicitUpdate) + { + // The GPS is automatically reporting, we just check whether we got unread data + checkUbloxInternal(&packetCfg, UBX_CLASS_NAV, UBX_NAV_TIMEUTC); + return packetUBXNAVTIMEUTC->moduleQueried.moduleQueried.bits.all; + } + else if (packetUBXNAVTIMEUTC->automaticFlags.flags.bits.automatic && !packetUBXNAVTIMEUTC->automaticFlags.flags.bits.implicitUpdate) + { + // Someone else has to call checkUblox for us... + return (false); + } + else + { + // The GPS is not automatically reporting navigation position so we have to poll explicitly + packetCfg.cls = UBX_CLASS_NAV; + packetCfg.id = UBX_NAV_TIMEUTC; + 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 navigation message generation by the GNSS. This changes the way getTIMEUTC +// works. +bool SFE_UBLOX_GNSS::setAutoNAVTIMEUTC(bool enable, uint16_t maxWait) +{ + return setAutoNAVTIMEUTCrate(enable ? 1 : 0, true, maxWait); +} + +// Enable or disable automatic navigation message generation by the GNSS. This changes the way getTIMEUTC +// works. +bool SFE_UBLOX_GNSS::setAutoNAVTIMEUTC(bool enable, bool implicitUpdate, uint16_t maxWait) +{ + return setAutoNAVTIMEUTCrate(enable ? 1 : 0, implicitUpdate, maxWait); +} + +// Enable or disable automatic navigation message generation by the GNSS. This changes the way getTIMEUTC +// works. +bool SFE_UBLOX_GNSS::setAutoNAVTIMEUTCrate(uint8_t rate, bool implicitUpdate, uint16_t maxWait) +{ + if (packetUBXNAVTIMEUTC == NULL) + initPacketUBXNAVTIMEUTC(); // Check that RAM has been allocated for the data + if (packetUBXNAVTIMEUTC == NULL) // Only attempt this if RAM allocation was successful + return false; + + packetCfg.cls = UBX_CLASS_CFG; + packetCfg.id = UBX_CFG_MSG; + packetCfg.len = 3; + packetCfg.startingSpot = 0; + payloadCfg[0] = UBX_CLASS_NAV; + payloadCfg[1] = UBX_NAV_TIMEUTC; + payloadCfg[2] = rate; // rate relative to navigation freq. + + bool ok = ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + if (ok) + { + packetUBXNAVTIMEUTC->automaticFlags.flags.bits.automatic = (rate > 0); + packetUBXNAVTIMEUTC->automaticFlags.flags.bits.implicitUpdate = implicitUpdate; + } + packetUBXNAVTIMEUTC->moduleQueried.moduleQueried.bits.all = false; + return ok; +} + +// Enable automatic navigation message generation by the GNSS. +bool SFE_UBLOX_GNSS::setAutoNAVTIMEUTCcallbackPtr(void (*callbackPointerPtr)(UBX_NAV_TIMEUTC_data_t *), uint16_t maxWait) +{ + // Enable auto messages. Set implicitUpdate to false as we expect the user to call checkUblox manually. + bool result = setAutoNAVTIMEUTC(true, false, maxWait); + if (!result) + return (result); // Bail if setAuto failed + + if (packetUBXNAVTIMEUTC->callbackData == NULL) // Check if RAM has been allocated for the callback copy + { + packetUBXNAVTIMEUTC->callbackData = new UBX_NAV_TIMEUTC_data_t; // Allocate RAM for the main struct + } + + if (packetUBXNAVTIMEUTC->callbackData == NULL) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("setAutoNAVTIMEUTCcallbackPtr: RAM alloc failed!")); +#endif + return (false); + } + + packetUBXNAVTIMEUTC->callbackPointerPtr = callbackPointerPtr; + return (true); +} + +// In case no config access to the GNSS is possible and TIMEUTC is send cyclically already +// set config to suitable parameters +bool SFE_UBLOX_GNSS::assumeAutoNAVTIMEUTC(bool enabled, bool implicitUpdate) +{ + if (packetUBXNAVTIMEUTC == NULL) + initPacketUBXNAVTIMEUTC(); // Check that RAM has been allocated for the data + if (packetUBXNAVTIMEUTC == NULL) // Only attempt this if RAM allocation was successful + return false; + + bool changes = packetUBXNAVTIMEUTC->automaticFlags.flags.bits.automatic != enabled || packetUBXNAVTIMEUTC->automaticFlags.flags.bits.implicitUpdate != implicitUpdate; + if (changes) + { + packetUBXNAVTIMEUTC->automaticFlags.flags.bits.automatic = enabled; + packetUBXNAVTIMEUTC->automaticFlags.flags.bits.implicitUpdate = implicitUpdate; + } + return changes; +} + +// PRIVATE: Allocate RAM for packetUBXNAVTIMEUTC and initialize it +bool SFE_UBLOX_GNSS::initPacketUBXNAVTIMEUTC() +{ + packetUBXNAVTIMEUTC = new UBX_NAV_TIMEUTC_t; // Allocate RAM for the main struct + if (packetUBXNAVTIMEUTC == NULL) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("initPacketUBXNAVTIMEUTC: RAM alloc failed!")); +#endif + return (false); + } + packetUBXNAVTIMEUTC->automaticFlags.flags.all = 0; + packetUBXNAVTIMEUTC->callbackPointerPtr = NULL; + packetUBXNAVTIMEUTC->callbackData = NULL; + packetUBXNAVTIMEUTC->moduleQueried.moduleQueried.all = 0; + return (true); +} + +// Mark all the data as read/stale +void SFE_UBLOX_GNSS::flushNAVTIMEUTC() +{ + if (packetUBXNAVTIMEUTC == NULL) + return; // Bail if RAM has not been allocated (otherwise we could be writing anywhere!) + packetUBXNAVTIMEUTC->moduleQueried.moduleQueried.all = 0; // Mark all datums as stale (read before) +} + +// Log this data in file buffer +void SFE_UBLOX_GNSS::logNAVTIMEUTC(bool enabled) +{ + if (packetUBXNAVTIMEUTC == NULL) + return; // Bail if RAM has not been allocated (otherwise we could be writing anywhere!) + packetUBXNAVTIMEUTC->automaticFlags.flags.bits.addToFileBuffer = (uint8_t)enabled; +} + // ***** NAV CLOCK automatic support bool SFE_UBLOX_GNSS::getNAVCLOCK(uint16_t maxWait) @@ -12561,6 +13084,53 @@ bool SFE_UBLOX_GNSS::initPacketUBXRXMPMPmessage() return (true); } +// ***** RXM QZSSL6 automatic support + +// Callback receives a pointer to the data, instead of _all_ the data. Much kinder on the stack! +bool SFE_UBLOX_GNSS::setRXMQZSSL6messageCallbackPtr(void (*callbackPointer)(UBX_RXM_QZSSL6_message_data_t *)) +{ + if (packetUBXRXMQZSSL6message == NULL) + initPacketUBXRXMQZSSL6message(); // Check that RAM has been allocated for the data + if (packetUBXRXMQZSSL6message == NULL) // Only attempt this if RAM allocation was successful + return false; + + if (packetUBXRXMQZSSL6message->callbackData == NULL) // Check if RAM has been allocated for the callback copy + { + packetUBXRXMQZSSL6message->callbackData = new UBX_RXM_QZSSL6_message_data_t[UBX_RXM_QZSSL6_NUM_CHANNELS]; // Allocate RAM for the main struct + } + + if (packetUBXRXMQZSSL6message->callbackData == NULL) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("setAutoRXMQZSSL6messagecallbackPtr: RAM alloc failed!")); +#endif + return (false); + } + + packetUBXRXMQZSSL6message->callbackPointerPtr = callbackPointer; + return (true); +} + +// PRIVATE: Allocate RAM for packetUBXRXMQZSSL6message and initialize it +bool SFE_UBLOX_GNSS::initPacketUBXRXMQZSSL6message() +{ + packetUBXRXMQZSSL6message = new UBX_RXM_QZSSL6_message_t; // Allocate RAM for the main struct + if (packetUBXRXMQZSSL6message == NULL) + { +#ifndef SFE_UBLOX_REDUCED_PROG_MEM + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("initPacketUBXRXMQZSSL6message: RAM alloc failed!")); +#endif + return (false); + } + packetUBXRXMQZSSL6message->automaticFlags.flags.all = 0; + packetUBXRXMQZSSL6message->callbackPointerPtr = NULL; + packetUBXRXMQZSSL6message->callbackData = NULL; + return (true); +} + + bool SFE_UBLOX_GNSS::setRXMCORcallbackPtr(void (*callbackPointer)(UBX_RXM_COR_data_t *)) { if (packetUBXRXMCOR == NULL) @@ -17457,7 +18027,7 @@ bool SFE_UBLOX_GNSS::getSensorFusionMeasurement(UBX_ESF_MEAS_sensorData_t *senso if (packetUBXESFMEAS == NULL) // Bail if the RAM allocation failed return (false); - if (packetUBXESFMEAS->moduleQueried.moduleQueried.bits.data & ((1 << sensor) == 0)) + if ((packetUBXESFMEAS->moduleQueried.moduleQueried.bits.data & (1 << sensor)) == 0) getESFMEAS(maxWait); packetUBXESFMEAS->moduleQueried.moduleQueried.bits.data &= ~(1 << sensor); // Since we are about to give this to user, mark this data as stale packetUBXESFMEAS->moduleQueried.moduleQueried.bits.all = false; @@ -17478,7 +18048,7 @@ bool SFE_UBLOX_GNSS::getRawSensorMeasurement(UBX_ESF_RAW_sensorData_t *sensorDat if (packetUBXESFRAW == NULL) // Bail if the RAM allocation failed return (false); - if (packetUBXESFRAW->moduleQueried.moduleQueried.bits.data & ((1 << sensor) == 0)) + if ((packetUBXESFRAW->moduleQueried.moduleQueried.bits.data & (1 << sensor)) == 0) getESFRAW(maxWait); packetUBXESFRAW->moduleQueried.moduleQueried.bits.data &= ~(1 << sensor); // Since we are about to give this to user, mark this data as stale packetUBXESFRAW->moduleQueried.moduleQueried.bits.all = false; @@ -17501,7 +18071,7 @@ bool SFE_UBLOX_GNSS::getSensorFusionStatus(UBX_ESF_STATUS_sensorStatus_t *sensor if (packetUBXESFSTATUS == NULL) // Bail if the RAM allocation failed return (false); - if (packetUBXESFSTATUS->moduleQueried.moduleQueried.bits.status & ((1 << sensor) == 0)) + if ((packetUBXESFSTATUS->moduleQueried.moduleQueried.bits.status & (1 << sensor)) == 0) getESFSTATUS(maxWait); packetUBXESFSTATUS->moduleQueried.moduleQueried.bits.status &= ~(1 << sensor); // Since we are about to give this to user, mark this data as stale packetUBXESFSTATUS->moduleQueried.moduleQueried.bits.all = false; diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.h b/src/SparkFun_u-blox_GNSS_Arduino_Library.h index a60ee2b0..4cb97171 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.h +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.h @@ -397,6 +397,7 @@ const uint8_t UBX_NAV_AOPSTATUS = 0x60; // AssistNow Autonomous status const uint8_t UBX_RXM_COR = 0x34; // Differential correction input status const uint8_t UBX_RXM_MEASX = 0x14; // Satellite Measurements for RRLP const uint8_t UBX_RXM_PMP = 0x72; // PMP raw data (NEO-D9S) (two different versions) (packet size for version 0x01 is variable) +const uint8_t UBX_RXM_QZSSL6 = 0x73; // QZSSL6 data (NEO-D9C) const uint8_t UBX_RXM_PMREQ = 0x41; // Requests a Power Management task (two different packet sizes) const uint8_t UBX_RXM_RAWX = 0x15; // Multi-GNSS Raw Measurement Data const uint8_t UBX_RXM_RLM = 0x59; // Galileo SAR Short-RLM report (two different packet sizes) @@ -861,7 +862,7 @@ class SFE_UBLOX_GNSS // Functions used for RTK and base station setup bool getSurveyMode(uint16_t maxWait = defaultMaxWait); // Get the current TimeMode3 settings - bool getSurveyMode(UBX_CFG_TMODE3_data_t *data = NULL, uint16_t maxWait = defaultMaxWait); // Get the current TimeMode3 settings + bool getSurveyMode(UBX_CFG_TMODE3_data_t *data = NULL, uint16_t maxWait = defaultMaxWait); // Get the current TimeMode3 settings bool setSurveyMode(uint8_t mode, uint16_t observationTime, float requiredAccuracy, uint16_t maxWait = defaultMaxWait); // Control survey in mode bool setSurveyModeFull(uint8_t mode, uint32_t observationTime, float requiredAccuracy, uint16_t maxWait = defaultMaxWait); // Control survey in mode bool enableSurveyMode(uint16_t observationTime, float requiredAccuracy, uint16_t maxWait = defaultMaxWait); // Begin Survey-In for NEO-M8P / ZED-F9x @@ -1102,6 +1103,15 @@ class SFE_UBLOX_GNSS void flushNAVPVAT(); // Mark all the PVAT data as read/stale void logNAVPVAT(bool enabled = true); // Log data to file buffer + bool getNAVTIMEUTC(uint16_t maxWait = defaultMaxWait); // NAV TIMEUTC + bool setAutoNAVTIMEUTC(bool enabled, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic TIMEUTC reports at the navigation frequency + bool setAutoNAVTIMEUTC(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic TIMEUTC reports at the navigation frequency, 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 + bool setAutoNAVTIMEUTCrate(uint8_t rate, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic TIMEUTC reports + bool setAutoNAVTIMEUTCcallbackPtr(void (*callbackPointerPtr)(UBX_NAV_TIMEUTC_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic TIMEUTC reports at the navigation frequency. Data is accessed from the callback. + bool assumeAutoNAVTIMEUTC(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and TIMEUTC is send cyclically already + void flushNAVTIMEUTC(); // Mark all the data as read/stale + void logNAVTIMEUTC(bool enabled = true); // Log data to file buffer + bool getNAVCLOCK(uint16_t maxWait = defaultMaxWait); // NAV CLOCK bool setAutoNAVCLOCK(bool enabled, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic clock reports at the navigation frequency bool setAutoNAVCLOCK(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic clock reports at the navigation frequency, 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 @@ -1121,6 +1131,15 @@ class SFE_UBLOX_GNSS void flushNAVSVIN(); // Mark all the data as read/stale void logNAVSVIN(bool enabled = true); // Log data to file buffer + bool getNAVEOE(uint16_t maxWait = defaultMaxWait); // Query module for latest dilution of precision values and load global vars:. If autoEOE is disabled, performs an explicit poll and waits, if enabled does not block. Returns true if new EOE is available. + bool setAutoNAVEOE(bool enabled, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic EOE reports at the navigation frequency + bool setAutoNAVEOE(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic EOE reports at the navigation frequency, 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 + bool setAutoNAVEOErate(uint8_t rate, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic EOE reports + bool setAutoNAVEOEcallbackPtr(void (*callbackPointerPtr)(UBX_NAV_EOE_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic EOE reports at the navigation frequency. Data is accessed from the callback. + bool assumeAutoNAVEOE(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and EOE is send cyclically already + void flushNAVEOE(); // Mark all the EOE data as read/stale + void logNAVEOE(bool enabled = true); // Log data to file buffer + // Add "auto" support for NAV TIMELS - to avoid needing 'global' storage bool getLeapSecondEvent(uint16_t maxWait = defaultMaxWait); // Reads leap second event info @@ -1163,6 +1182,12 @@ class SFE_UBLOX_GNSS bool setRXMPMPcallbackPtr(void (*callbackPointerPtr)(UBX_RXM_PMP_data_t *)); // Callback receives a pointer to the data, instead of _all_ the data. Much kinder on the stack! bool setRXMPMPmessageCallbackPtr(void (*callbackPointerPtr)(UBX_RXM_PMP_message_data_t *)); // Use this if you want all of the PMP message (including sync chars, checksum, etc.) to push to a GNSS + // Configure a callback for the UBX-RXM-QZSSL6 messages produced by the NEO-D9C + // Note: on the NEO-D9C, the UBX-RXM-QZSSL6 messages are enabled by default on all ports. + // You can disable them by calling (e.g.) setVal8(UBLOX_CFG_MSGOUT_UBX_RXM_QZSSL6_I2C, 0) + // The NEO-D9C does not support UBX-CFG-MSG + bool setRXMQZSSL6messageCallbackPtr(void (*callbackPointerPtr)(UBX_RXM_QZSSL6_message_data_t *)); // Use this if you want all of the QZSSL6 message (including sync chars, checksum, etc.) to push to a GNSS + bool setRXMCORcallbackPtr(void (*callbackPointerPtr)(UBX_RXM_COR_data_t *)); // RXM COR bool getRXMSFRBX(uint16_t maxWait = defaultMaxWait); // RXM SFRBX @@ -1501,9 +1526,11 @@ class SFE_UBLOX_GNSS UBX_NAV_POSECEF_t *packetUBXNAVPOSECEF = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary UBX_NAV_STATUS_t *packetUBXNAVSTATUS = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary UBX_NAV_DOP_t *packetUBXNAVDOP = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary + UBX_NAV_EOE_t *packetUBXNAVEOE = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary UBX_NAV_ATT_t *packetUBXNAVATT = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary UBX_NAV_PVT_t *packetUBXNAVPVT = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary UBX_NAV_ODO_t *packetUBXNAVODO = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary + UBX_NAV_TIMEUTC_t *packetUBXNAVTIMEUTC = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary UBX_NAV_VELECEF_t *packetUBXNAVVELECEF = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary UBX_NAV_VELNED_t *packetUBXNAVVELNED = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary UBX_NAV_HPPOSECEF_t *packetUBXNAVHPPOSECEF = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary @@ -1518,6 +1545,7 @@ class SFE_UBLOX_GNSS UBX_RXM_PMP_t *packetUBXRXMPMP = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary UBX_RXM_PMP_message_t *packetUBXRXMPMPmessage = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary + UBX_RXM_QZSSL6_message_t *packetUBXRXMQZSSL6message = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary UBX_RXM_COR_t *packetUBXRXMCOR = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary UBX_RXM_SFRBX_t *packetUBXRXMSFRBX = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary UBX_RXM_RAWX_t *packetUBXRXMRAWX = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary @@ -1609,14 +1637,17 @@ class SFE_UBLOX_GNSS bool initPacketUBXNAVHPPOSECEF(); // Allocate RAM for packetUBXNAVHPPOSECEF and initialize it bool initPacketUBXNAVHPPOSLLH(); // Allocate RAM for packetUBXNAVHPPOSLLH and initialize it bool initPacketUBXNAVPVAT(); // Allocate RAM for packetUBXNAVPVAT and initialize it + bool initPacketUBXNAVTIMEUTC(); // Allocate RAM for packetUBXNAVTIMEUTC and initialize it bool initPacketUBXNAVCLOCK(); // Allocate RAM for packetUBXNAVCLOCK and initialize it bool initPacketUBXNAVTIMELS(); // Allocate RAM for packetUBXNAVTIMELS and initialize it bool initPacketUBXNAVSVIN(); // Allocate RAM for packetUBXNAVSVIN and initialize it bool initPacketUBXNAVSAT(); // Allocate RAM for packetUBXNAVSAT and initialize it bool initPacketUBXNAVRELPOSNED(); // Allocate RAM for packetUBXNAVRELPOSNED and initialize it bool initPacketUBXNAVAOPSTATUS(); // Allocate RAM for packetUBXNAVAOPSTATUS and initialize it + bool initPacketUBXNAVEOE(); // Allocate RAM for packetUBXNAVEOE and initialize it bool initPacketUBXRXMPMP(); // Allocate RAM for packetUBXRXMPMP and initialize it bool initPacketUBXRXMPMPmessage(); // Allocate RAM for packetUBXRXMPMPRaw and initialize it + bool initPacketUBXRXMQZSSL6message(); // Allocate RAM for packetUBXRXMQZSSL6raw and initialize it bool initPacketUBXRXMCOR(); // Allocate RAM for packetUBXRXMCOR and initialize it bool initPacketUBXRXMSFRBX(); // Allocate RAM for packetUBXRXMSFRBX and initialize it bool initPacketUBXRXMRAWX(); // Allocate RAM for packetUBXRXMRAWX and initialize it diff --git a/src/u-blox_config_keys.h b/src/u-blox_config_keys.h index d8893c21..b1589faa 100644 --- a/src/u-blox_config_keys.h +++ b/src/u-blox_config_keys.h @@ -826,6 +826,14 @@ const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_PMP_UART1 = 0x20910323; // Output rate o const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_PMP_UART2 = 0x20910324; // Output rate of the UBX_MON_PMP message on port UART2 const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_PMP_USB = 0x20910325; // Output rate of the UBX_MON_PMP message on port USB +// Additional CFG_MSGOUT keys for the NEO-D9S +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_QZSSL6_I2C = 0x2091033f; // Output rate of the UBX_RXM_QZSSL6 message on port I2C +const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_QZSSL6_SPI = 0x2091033e; // Output rate of the UBX_RXM_QZSSL6 message on port SPI +const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_QZSSL6_UART1 = 0x2091033b; // Output rate of the UBX_RXM_QZSSL6 message on port UART1 +const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_QZSSL6_UART2 = 0x2091033c; // Output rate of the UBX_RXM_QZSSL6 message on port UART2 +const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_QZSSL6_USB = 0x2091033d; // Output rate of the UBX_RXM_QZSSL6 message on port USB + // CFG-NAV2: Secondary output configuration //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- const uint32_t UBLOX_CFG_NAV2_OUT_ENABLED = 0x10170001; // Enable secondary (NAV2) output @@ -928,6 +936,14 @@ const uint32_t UBLOX_CFG_PMP_DESCRAMBLER_INIT = 0x30b10015; // Descrambler init const uint32_t UBLOX_CFG_PMP_USE_PRESCRAMBLING = 0x10b10019; // Use prescrambling. Enables/disables the prescrambling. const uint32_t UBLOX_CFG_PMP_UNIQUE_WORD = 0x50b1001a; // Unique word. Defines value of unique word. +// CFG-QZSS-L6: QZSS system configuration configuration (NEO-D9C) +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +const uint32_t UBLOX_CFG_QZSSL6_SVIDA = 0x20370020; // QZSS L6 SV Id to be decoded by channel A +const uint32_t UBLOX_CFG_QZSSL6_SVIDB = 0x20370030; // QZSS L6 SV Id to be decoded by channel B +const uint32_t UBLOX_CFG_QZSSL6_MSGA = 0x20370050; // QZSS L6 messages to be decoded by channel A +const uint32_t UBLOX_CFG_QZSSL6_MSGB = 0x20370060; // QZSS L6 messages to be decoded by channel B +const uint32_t UBLOX_CFG_QZSSL6_RSDECODER = 0x20370080; // QZSS L6 message Reed-Solomon decoder mode + // CFG-QZSS: QZSS system configuration //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- const uint32_t UBLOX_CFG_QZSS_USE_SLAS_DGNSS = 0x10370005; // Apply QZSS SLAS DGNSS corrections diff --git a/src/u-blox_structs.h b/src/u-blox_structs.h index 019aebb3..80ca38a3 100644 --- a/src/u-blox_structs.h +++ b/src/u-blox_structs.h @@ -999,7 +999,6 @@ typedef struct ubxAutomaticFlags automaticFlags; UBX_NAV_TIMEUTC_data_t data; UBX_NAV_TIMEUTC_moduleQueried_t moduleQueried; - void (*callbackPointer)(UBX_NAV_TIMEUTC_data_t); void (*callbackPointerPtr)(UBX_NAV_TIMEUTC_data_t *); UBX_NAV_TIMEUTC_data_t *callbackData; } UBX_NAV_TIMEUTC_t; @@ -1383,6 +1382,37 @@ typedef struct UBX_NAV_AOPSTATUS_data_t *callbackData; } UBX_NAV_AOPSTATUS_t; +// UBX-NAV-EOE (0x01 0x61): End of Epoch +const uint16_t UBX_NAV_EOE_LEN = 4; + +typedef struct +{ + uint32_t iTOW; // GPS time of week of the navigation epoch: ms +} UBX_NAV_EOE_data_t; + +typedef struct +{ + union + { + uint32_t all; + struct + { + uint32_t all : 1; + + uint32_t iTOW : 1; + } bits; + } moduleQueried; +} UBX_NAV_EOE_moduleQueried_t; + +typedef struct +{ + ubxAutomaticFlags automaticFlags; + UBX_NAV_EOE_data_t data; + UBX_NAV_EOE_moduleQueried_t moduleQueried; + void (*callbackPointerPtr)(UBX_NAV_EOE_data_t *); + UBX_NAV_EOE_data_t *callbackData; +} UBX_NAV_EOE_t; + // RXM-specific structs // UBX-RXM-SFRBX (0x02 0x13): Broadcast navigation data subframe @@ -1599,6 +1629,62 @@ typedef struct UBX_RXM_PMP_message_data_t *callbackData; } UBX_RXM_PMP_message_t; +// UBX-RXM-QZSSL6 (0x02 0x73): QZSS L6 raw data (D9C modules) +#define UBX_RXM_QZSSL6_NUM_CHANNELS 2 +const uint16_t UBX_RXM_QZSSL6_DATALEN = 250; +const uint16_t UBX_RXM_QZSSL6_MAX_LEN = UBX_RXM_QZSSL6_DATALEN + 14; + +typedef struct +{ + uint8_t version; // Message version (0x00 / 0x01) + uint8_t svId; // Satellite identifier + uint16_t cno; // Mean C/N0 + uint32_t timeTag; // Time since startup when frame started : ms + uint8_t groupDelay; // L6 group delay w.r.t. L2 on channel + uint8_t bitErrCorr; // Number of bit errors corrected by Reed-Solomon decoder + uint16_t chInfo; // Information about receiver channel associated with a received QZSS L6 message + uint8_t reserved0[2]; // Reserved + uint8_t msgBytes[UBX_RXM_QZSSL6_DATALEN]; // Bytes in a QZSS L6 message +} UBX_RXM_QZSSL6_data_t; + +struct ubxQZSSL6AutomaticFlags +{ + union + { + uint8_t all; + struct + { + uint8_t automatic : 1; // Will this message be delivered and parsed "automatically" (without polling) + uint8_t implicitUpdate : 1; // Is the update triggered by accessing stale data (=true) or by a call to checkUblox (=false) + uint8_t addToFileBuffer : 1; // Should the raw UBX data be added to the file buffer? + uint8_t callbackCopyValid : UBX_RXM_QZSSL6_NUM_CHANNELS; // Is the copies of the data structs used by the callback valid/fresh? + } bits; + } flags; +}; + +// Define a struct to hold the entire QZSSL6 message so the whole thing can be pushed to a GNSS. +// Remember that the length of the payload could be variable (with version 1 messages). +typedef struct +{ + uint8_t sync1; // 0xB5 + uint8_t sync2; // 0x62 + uint8_t cls; + uint8_t ID; + uint8_t lengthLSB; + uint8_t lengthMSB; + uint8_t payload[UBX_RXM_QZSSL6_MAX_LEN]; + uint8_t checksumA; + uint8_t checksumB; +} UBX_RXM_QZSSL6_message_data_t; + +// The QZSSL6 data can only be accessed via a callback. QZSSL6 cannot be polled. +typedef struct +{ + ubxQZSSL6AutomaticFlags automaticFlags; + void (*callbackPointerPtr)(UBX_RXM_QZSSL6_message_data_t *); + UBX_RXM_QZSSL6_message_data_t *callbackData; +} UBX_RXM_QZSSL6_message_t; + // CFG-specific structs // UBX-CFG-PRT (0x06 0x00): Port configuration