From 9f729265ad624e7a91faf16c202a12dbad354a4b Mon Sep 17 00:00:00 2001 From: PaulZC Date: Tue, 27 Oct 2020 12:20:34 +0000 Subject: [PATCH 1/4] autoHPPOSLLH functions added - work in progress --- keywords.txt | 4 + src/SparkFun_Ublox_Arduino_Library.cpp | 131 ++++++++++++++++++++++++- src/SparkFun_Ublox_Arduino_Library.h | 12 ++- 3 files changed, 139 insertions(+), 8 deletions(-) diff --git a/keywords.txt b/keywords.txt index d5ec567..05fb2a3 100644 --- a/keywords.txt +++ b/keywords.txt @@ -118,6 +118,10 @@ getDateValid KEYWORD2 getTimeValid KEYWORD2 getHPPOSLLH KEYWORD2 +assumeAutoHPPOSLLH KEYWORD2 +setAutoHPPOSLLH KEYWORD2 +flushHPPOSLLH KEYWORD2 + getTimeOfWeek KEYWORD2 getHighResLatitude KEYWORD2 getHighResLatitudeHp KEYWORD2 diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index bba8a3e..22d961a 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -2291,6 +2291,48 @@ boolean SFE_UBLOX_GPS::setAutoPVT(boolean enable, boolean implicitUpdate, uint16 return ok; } +//In case no config access to the GPS is possible and HPPOSLLH is send cyclically already +//set config to suitable parameters +boolean SFE_UBLOX_GPS::assumeAutoHPPOSLLH(boolean enabled, boolean implicitUpdate) +{ + boolean changes = autoHPPOSLLH != enabled || autoHPPOSLLHImplicitUpdate != implicitUpdate; + if (changes) + { + autoHPPOSLLH = enabled; + autoHPPOSLLHImplicitUpdate = implicitUpdate; + } + return changes; +} + +//Enable or disable automatic navigation message generation by the GPS. This changes the way getHPPOSLLH +//works. +boolean SFE_UBLOX_GPS::setAutoHPPOSLLH(boolean enable, uint16_t maxWait) +{ + return setAutoHPPOSLLH(enable, true, maxWait); +} + +//Enable or disable automatic navigation message generation by the GPS. This changes the way getHPPOSLLH +//works. +boolean SFE_UBLOX_GPS::setAutoHPPOSLLH(boolean enable, boolean implicitUpdate, uint16_t maxWait) +{ + 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_HPPOSLLH; + payloadCfg[2] = enable ? 1 : 0; // rate relative to navigation freq. + + boolean ok = ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + if (ok) + { + autoHPPOSLLH = enable; + autoHPPOSLLHImplicitUpdate = implicitUpdate; + } + highResModuleQueried.all = false; + return ok; +} + //Configure a given message type for a given port (UART1, I2C, SPI, etc) boolean SFE_UBLOX_GPS::configureMessage(uint8_t msgClass, uint8_t msgID, uint8_t portID, uint8_t sendRate, uint16_t maxWait) { @@ -2955,6 +2997,8 @@ int32_t SFE_UBLOX_GPS::getHighResLatitude(uint16_t maxWait /* = 250*/) if (highResModuleQueried.highResLatitude == false) getHPPOSLLH(maxWait); highResModuleQueried.highResLatitude = false; //Since we are about to give this to user, mark this data as stale + highResModuleQueried.all = false; + return (highResLatitude); } @@ -2963,6 +3007,8 @@ int8_t SFE_UBLOX_GPS::getHighResLatitudeHp(uint16_t maxWait /* = 250*/) if (highResModuleQueried.highResLatitudeHp == false) getHPPOSLLH(maxWait); highResModuleQueried.highResLatitudeHp = false; //Since we are about to give this to user, mark this data as stale + highResModuleQueried.all = false; + return (highResLatitudeHp); } @@ -2971,6 +3017,8 @@ int32_t SFE_UBLOX_GPS::getHighResLongitude(uint16_t maxWait /* = 250*/) if (highResModuleQueried.highResLongitude == false) getHPPOSLLH(maxWait); highResModuleQueried.highResLongitude = false; //Since we are about to give this to user, mark this data as stale + highResModuleQueried.all = false; + return (highResLongitude); } @@ -2979,6 +3027,8 @@ int8_t SFE_UBLOX_GPS::getHighResLongitudeHp(uint16_t maxWait /* = 250*/) if (highResModuleQueried.highResLongitudeHp == false) getHPPOSLLH(maxWait); highResModuleQueried.highResLongitudeHp = false; //Since we are about to give this to user, mark this data as stale + highResModuleQueried.all = false; + return (highResLongitudeHp); } @@ -2987,6 +3037,8 @@ int32_t SFE_UBLOX_GPS::getElipsoid(uint16_t maxWait /* = 250*/) if (highResModuleQueried.elipsoid == false) getHPPOSLLH(maxWait); highResModuleQueried.elipsoid = false; //Since we are about to give this to user, mark this data as stale + highResModuleQueried.all = false; + return (elipsoid); } @@ -2995,6 +3047,8 @@ int8_t SFE_UBLOX_GPS::getElipsoidHp(uint16_t maxWait /* = 250*/) if (highResModuleQueried.elipsoidHp == false) getHPPOSLLH(maxWait); highResModuleQueried.elipsoidHp = false; //Since we are about to give this to user, mark this data as stale + highResModuleQueried.all = false; + return (elipsoidHp); } @@ -3003,6 +3057,8 @@ int32_t SFE_UBLOX_GPS::getMeanSeaLevel(uint16_t maxWait /* = 250*/) if (highResModuleQueried.meanSeaLevel == false) getHPPOSLLH(maxWait); highResModuleQueried.meanSeaLevel = false; //Since we are about to give this to user, mark this data as stale + highResModuleQueried.all = false; + return (meanSeaLevel); } @@ -3011,6 +3067,8 @@ int8_t SFE_UBLOX_GPS::getMeanSeaLevelHp(uint16_t maxWait /* = 250*/) if (highResModuleQueried.meanSeaLevelHp == false) getHPPOSLLH(maxWait); highResModuleQueried.meanSeaLevelHp = false; //Since we are about to give this to user, mark this data as stale + highResModuleQueried.all = false; + return (meanSeaLevelHp); } @@ -3020,6 +3078,8 @@ int32_t SFE_UBLOX_GPS::getGeoidSeparation(uint16_t maxWait /* = 250*/) if (highResModuleQueried.geoidSeparation == false) getHPPOSLLH(maxWait); highResModuleQueried.geoidSeparation = false; //Since we are about to give this to user, mark this data as stale + highResModuleQueried.all = false; + return (geoidSeparation); } @@ -3028,6 +3088,8 @@ uint32_t SFE_UBLOX_GPS::getHorizontalAccuracy(uint16_t maxWait /* = 250*/) if (highResModuleQueried.horizontalAccuracy == false) getHPPOSLLH(maxWait); highResModuleQueried.horizontalAccuracy = false; //Since we are about to give this to user, mark this data as stale + highResModuleQueried.all = false; + return (horizontalAccuracy); } @@ -3036,17 +3098,57 @@ uint32_t SFE_UBLOX_GPS::getVerticalAccuracy(uint16_t maxWait /* = 250*/) if (highResModuleQueried.verticalAccuracy == false) getHPPOSLLH(maxWait); highResModuleQueried.verticalAccuracy = false; //Since we are about to give this to user, mark this data as stale + highResModuleQueried.all = false; + return (verticalAccuracy); } boolean SFE_UBLOX_GPS::getHPPOSLLH(uint16_t maxWait) { - //The GPS is not automatically reporting navigation position so we have to poll explicitly - packetCfg.cls = UBX_CLASS_NAV; - packetCfg.id = UBX_NAV_HPPOSLLH; - packetCfg.len = 0; + if (autoHPPOSLLH && autoHPPOSLLHImplicitUpdate) + { + //The GPS is automatically reporting, we just check whether we got unread data + if (_printDebug == true) + { + _debugSerial->println(F("getHPPOSLLH: Autoreporting")); + } + checkUbloxInternal(&packetCfg, UBX_CLASS_NAV, UBX_NAV_HPPOSLLH); + return highResModuleQueried.all; + } + else if (autoHPPOSLLH && !autoHPPOSLLHImplicitUpdate) + { + //Someone else has to call checkUblox for us... + if (_printDebug == true) + { + _debugSerial->println(F("getHPPOSLLH: Exit immediately")); + } + return (false); + } + else + { + if (_printDebug == true) + { + _debugSerial->println(F("getHPPOSLLH: Polling")); + } - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_RECEIVED); // We are only expecting data (no ACK) + //The GPS is not automatically reporting navigation position so we have to poll explicitly + packetCfg.cls = UBX_CLASS_NAV; + packetCfg.id = UBX_NAV_HPPOSLLH; + packetCfg.len = 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 (_printDebug == true) + { + _debugSerial->print(F("getHPPOSLLH retVal: ")); + _debugSerial->println(statusString(retVal)); + } + return (false); + } } //Get the current 3D high precision positional accuracy - a fun thing to watch @@ -3287,6 +3389,25 @@ void SFE_UBLOX_GPS::flushPVT() moduleQueried.pDOP = false; } +//Mark all the HPPOSLLH data as read/stale. This is handy to get data alignment after CRC failure +void SFE_UBLOX_GPS::flushHPPOSLLH() +{ + //Mark all datums as stale (read before) + highResModuleQueried.all = false; + highResModuleQueried.highResLatitude = false; + highResModuleQueried.highResLatitudeHp = false; + highResModuleQueried.highResLongitude = false; + highResModuleQueried.highResLongitudeHp = false; + highResModuleQueried.elipsoid = false; + highResModuleQueried.elipsoidHp = false; + highResModuleQueried.meanSeaLevel = false; + highResModuleQueried.meanSeaLevelHp = false; + highResModuleQueried.geoidSeparation = false; + highResModuleQueried.horizontalAccuracy = false; + highResModuleQueried.verticalAccuracy = false; + //moduleQueried.gpsiTOW = false; // this can arrive via HPPOS too. +} + //Relative Positioning Information in NED frame //Returns true if commands was successful boolean SFE_UBLOX_GPS::getRELPOSNED(uint16_t maxWait) diff --git a/src/SparkFun_Ublox_Arduino_Library.h b/src/SparkFun_Ublox_Arduino_Library.h index 2ba24be..d37e4dc 100644 --- a/src/SparkFun_Ublox_Arduino_Library.h +++ b/src/SparkFun_Ublox_Arduino_Library.h @@ -461,7 +461,7 @@ class SFE_UBLOX_GPS //Control the size of the internal I2C transaction amount void setI2CTransactionSize(uint8_t bufferSize); uint8_t getI2CTransactionSize(void); - + //Set the max number of bytes set in a given I2C transaction uint8_t i2cTransactionSize = 32; //Default to ATmega328 limit @@ -517,10 +517,14 @@ class SFE_UBLOX_GPS boolean assumeAutoPVT(boolean enabled, boolean implicitUpdate = true); //In case no config access to the GPS is possible and PVT is send cyclically already boolean setAutoPVT(boolean enabled, uint16_t maxWait = defaultMaxWait); //Enable/disable automatic PVT reports at the navigation frequency - boolean getPVT(uint16_t maxWait = getPVTmaxWait); //Query module for latest group of datums and load global vars: lat, long, alt, speed, SIV, accuracies, etc. If autoPVT is disabled, performs an explicit poll and waits, if enabled does not block. Retruns true if new PVT is available. + boolean getPVT(uint16_t maxWait = getPVTmaxWait); //Query module for latest group of datums and load global vars: lat, long, alt, speed, SIV, accuracies, etc. If autoPVT is disabled, performs an explicit poll and waits, if enabled does not block. Returns true if new PVT is available. boolean setAutoPVT(boolean enabled, boolean implicitUpdate, uint16_t maxWait = defaultMaxWait); //Enable/disable automatic PVT 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 - boolean getHPPOSLLH(uint16_t maxWait = getHPPOSLLHmaxWait); //Query module for latest group of datums and load global vars: lat, long, alt, speed, SIV, accuracies, etc. If autoPVT is disabled, performs an explicit poll and waits, if enabled does not block. Retruns true if new PVT is available. + boolean assumeAutoHPPOSLLH(boolean enabled, boolean implicitUpdate = true); //In case no config access to the GPS is possible and HPPOSLLH is send cyclically already + boolean setAutoHPPOSLLH(boolean enabled, uint16_t maxWait = defaultMaxWait); //Enable/disable automatic HPPOSLLH reports at the navigation frequency + boolean setAutoHPPOSLLH(boolean enabled, boolean implicitUpdate, uint16_t maxWait = defaultMaxWait); //Enable/disable automatic HPPOSLLH 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 + boolean getHPPOSLLH(uint16_t maxWait = getHPPOSLLHmaxWait); //Query module for latest group of datums and load global vars: lat, long, alt, speed, SIV, accuracies, etc. If autoPVT is disabled, performs an explicit poll and waits, if enabled does not block. Returns true if new HPPOSLLH is available. void flushPVT(); //Mark all the PVT data as read/stale. This is handy to get data alignment after CRC failure + void flushHPPOSLLH(); //Mark all the PVT data as read/stale. This is handy to get data alignment after CRC failure int32_t getLatitude(uint16_t maxWait = getPVTmaxWait); //Returns the current latitude in degrees * 10^-7. Auto selects between HighPrecision and Regular depending on ability of module. int32_t getLongitude(uint16_t maxWait = getPVTmaxWait); //Returns the current longitude in degrees * 10-7. Auto selects between HighPrecision and Regular depending on ability of module. @@ -853,6 +857,8 @@ class SFE_UBLOX_GPS unsigned long lastCheck = 0; boolean autoPVT = false; //Whether autoPVT is enabled or not boolean autoPVTImplicitUpdate = true; // Whether autoPVT is triggered by accessing stale data (=true) or by a call to checkUblox (=false) + boolean autoHPPOSLLH = false; //Whether autoHPPOSLLH is enabled or not + boolean autoHPPOSLLHImplicitUpdate = true; // Whether autoHPPOSLLH is triggered by accessing stale data (=true) or by a call to checkUblox (=false) uint16_t ubxFrameCounter; //It counts all UBX frame. [Fixed header(2bytes), CLS(1byte), ID(1byte), length(2bytes), payload(x bytes), checksums(2bytes)] uint8_t rollingChecksumA; //Rolls forward as we receive incoming bytes. Checked against the last two A/B checksum bytes From 9bc3a2d1e7eb493382141b5bbd5cb0f69501f2bd Mon Sep 17 00:00:00 2001 From: PaulZC Date: Tue, 27 Oct 2020 16:08:31 +0000 Subject: [PATCH 2/4] autoHPPOSLLH - almost ready --- src/SparkFun_Ublox_Arduino_Library.cpp | 56 +++++++++++++++++++++----- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index 22d961a..a06db3f 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -549,6 +549,25 @@ void SFE_UBLOX_GPS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t re incomingUBX->id = packetBuf.id; incomingUBX->counter = packetBuf.counter; //Copy over the .counter too } + //This is not an ACK and we do not have a complete class and ID match + //So let's check for an HPPOSLLH message arriving when we were expecting PVT and vice versa + else if ((packetBuf.cls == requestedClass) && + (((packetBuf.id == UBX_NAV_PVT) && (requestedID == UBX_NAV_HPPOSLLH)) || + ((packetBuf.id == UBX_NAV_HPPOSLLH) && (requestedID == UBX_NAV_PVT)))) + { + //This is not the message we were expecting but we start diverting data into incomingUBX (usually packetCfg) and process it anyway + activePacketBuffer = SFE_UBLOX_PACKET_PACKETCFG; + incomingUBX->cls = packetBuf.cls; //Copy the class and ID into incomingUBX (usually packetCfg) + incomingUBX->id = packetBuf.id; + incomingUBX->counter = packetBuf.counter; //Copy over the .counter too + if (_printDebug == true) + { + _debugSerial->print(F("process: auto PVT/HPPOSLLH collision: Requested ID: 0x")); + _debugSerial->print(requestedID, HEX); + _debugSerial->print(F(" Message ID: 0x")); + _debugSerial->println(packetBuf.id, HEX); + } + } else { //This is not an ACK and we do not have a class and ID match @@ -802,6 +821,23 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t } } + //This is not an ACK and we do not have a complete class and ID match + //So let's check for an HPPOSLLH message arriving when we were expecting PVT and vice versa + else if ((incomingUBX->cls == requestedClass) && + (((incomingUBX->id == UBX_NAV_PVT) && (requestedID == UBX_NAV_HPPOSLLH)) || + ((incomingUBX->id == UBX_NAV_HPPOSLLH) && (requestedID == UBX_NAV_PVT)))) + { + // This isn't the message we are looking for... + // Let's say so and leave incomingUBX->classAndIDmatch _unchanged_ + if (_printDebug == true) + { + _debugSerial->print(F("processUBX: auto PVT/HPPOSLLH collision: Requested ID: 0x")); + _debugSerial->print(requestedID, HEX); + _debugSerial->print(F(" Message ID: 0x")); + _debugSerial->println(incomingUBX->id, HEX); + } + } + if (_printDebug == true) { _debugSerial->print(F("Incoming: Size: ")); @@ -1005,6 +1041,7 @@ void SFE_UBLOX_GPS::processUBXpacket(ubxPacket *msg) highResModuleQueried.verticalAccuracy = true; moduleQueried.gpsiTOW = true; // this can arrive via HPPOS too. +/* if (_printDebug == true) { _debugSerial->print(F("Sec: ")); @@ -1040,6 +1077,7 @@ void SFE_UBLOX_GPS::processUBXpacket(ubxPacket *msg) _debugSerial->print(F("VERT M: ")); _debugSerial->println(((float)(int32_t)extractLong(32)) / 10000.0f); } +*/ } break; } @@ -1541,15 +1579,15 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(ubxPacket *outgoingUBX, u // and outgoingUBX->valid is VALID then this must be (e.g.) a PVT packet else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED) && (outgoingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_VALID)) { - if (_printDebug == true) - { - _debugSerial->print(F("waitForNoACKResponse: valid but UNWANTED data after ")); - _debugSerial->print(millis() - startTime); - _debugSerial->print(F(" msec. Class: ")); - _debugSerial->print(outgoingUBX->cls); - _debugSerial->print(F(" ID: ")); - _debugSerial->print(outgoingUBX->id); - } + // if (_printDebug == true) + // { + // _debugSerial->print(F("waitForNoACKResponse: valid but UNWANTED data after ")); + // _debugSerial->print(millis() - startTime); + // _debugSerial->print(F(" msec. Class: ")); + // _debugSerial->print(outgoingUBX->cls); + // _debugSerial->print(F(" ID: ")); + // _debugSerial->print(outgoingUBX->id); + // } } // If the outgoingUBX->classAndIDmatch is NOT_VALID then we return CRC failure From 1075c2e3c7c252176707b86f901db0e98e0b1a10 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Tue, 27 Oct 2020 16:09:38 +0000 Subject: [PATCH 3/4] Removing two incorrect inversions. These were preventing OVERWRITTEN being detected. --- src/SparkFun_Ublox_Arduino_Library.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index a06db3f..77dab6d 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -1412,7 +1412,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uin // If (e.g.) a PVT packet _has been_ received: outgoingUBX->valid will be VALID (or just possibly NOT_VALID) // So we cannot use outgoingUBX->valid as part of this check. // Note: the addition of packetBuf should make this check redundant! - else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) && !((outgoingUBX->cls != requestedClass) || (outgoingUBX->id != requestedID))) + else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) && ((outgoingUBX->cls != requestedClass) || (outgoingUBX->id != requestedID))) { if (_printDebug == true) { @@ -1564,7 +1564,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(ubxPacket *outgoingUBX, u // If (e.g.) a PVT packet _has been_ received: outgoingUBX->valid will be VALID (or just possibly NOT_VALID) // So we cannot use outgoingUBX->valid as part of this check. // Note: the addition of packetBuf should make this check redundant! - else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) && !((outgoingUBX->cls != requestedClass) || (outgoingUBX->id != requestedID))) + else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) && ((outgoingUBX->cls != requestedClass) || (outgoingUBX->id != requestedID))) { if (_printDebug == true) { From 47c83dadcaed86630808e372e42daf8acd4f2d54 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Tue, 27 Oct 2020 16:49:04 +0000 Subject: [PATCH 4/4] Adding autoHPPOSLLH. Tested on the ZED-F9P. --- .../Example11_autoHPPOSLLH.ino | 149 ++++++++++++++++++ src/SparkFun_Ublox_Arduino_Library.cpp | 18 +++ 2 files changed, 167 insertions(+) create mode 100644 examples/ZED-F9P/Example11_autoHPPOSLLH/Example11_autoHPPOSLLH.ino diff --git a/examples/ZED-F9P/Example11_autoHPPOSLLH/Example11_autoHPPOSLLH.ino b/examples/ZED-F9P/Example11_autoHPPOSLLH/Example11_autoHPPOSLLH.ino new file mode 100644 index 0000000..7bf220b --- /dev/null +++ b/examples/ZED-F9P/Example11_autoHPPOSLLH/Example11_autoHPPOSLLH.ino @@ -0,0 +1,149 @@ +/* + Configuring the GPS to automatically send HPPOSLLH position reports over I2C + By: Paul Clark + Date: October 27th 2020 + + Based on an earlier example: + By: Nathan Seidle and Thorsten von Eicken + SparkFun Electronics + Date: January 3rd, 2019 + 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 GPS the send navigation reports automatically + and retrieving the latest one via getHPPOSLLH. This eliminates the blocking in getHPPOSLLH while the GPS + produces a fresh navigation solution at the expense of returning a slighly old solution. + + This can be used over serial or over I2C, this example shows the I2C use. With serial the GPS + simply outputs the UBX_NAV_HPPOSLLH packet. With I2C it queues it into its internal I2C buffer (4KB in + size?) where it can be retrieved in the next I2C poll. + + 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 + + Hardware Connections: + Plug a Qwiic cable into the GPS and a BlackBoard + 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 GPS + +#include //http://librarymanager/All#SparkFun_Ublox_GPS +SFE_UBLOX_GPS myGPS; + +void setup() +{ + Serial.begin(115200); + while (!Serial); //Wait for user to open terminal + Serial.println("SparkFun Ublox Example"); + + Wire.begin(); + + //myGPS.enableDebugging(); // Uncomment this line to enable lots of helpful debug messages + + if (myGPS.begin() == false) //Connect to the Ublox module using Wire port + { + Serial.println(F("Ublox GPS not detected at default I2C address. Please check wiring. Freezing.")); + while (1); + } + + // Uncomment the next line if you want to reset your module back to the default settings with 1Hz navigation rate + //myGPS.factoryDefault(); delay(5000); + + myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise) + myGPS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save the communications port settings to flash and BBR + + myGPS.setNavigationFrequency(1); //Produce one solution per second + + + // The acid test: all four of these combinations should work seamlessly :-) + + //myGPS.setAutoPVT(false); // Library will poll each reading + //myGPS.setAutoHPPOSLLH(false); // Library will poll each reading + + //myGPS.setAutoPVT(true); // Tell the GPS to "send" each solution automatically + //myGPS.setAutoHPPOSLLH(false); // Library will poll each reading + + // This combination causes the PVT data to be overwritten by HPPOSLLH. + // But that's OK. Both sets of readings are still extracted OK. + //myGPS.setAutoPVT(false); // Library will poll each reading + //myGPS.setAutoHPPOSLLH(true); // Tell the GPS to "send" each hi res solution automatically + + myGPS.setAutoPVT(true); // Tell the GPS to "send" each solution automatically + myGPS.setAutoHPPOSLLH(true); // Tell the GPS to "send" each hi res solution automatically + +} + +void loop() +{ + Serial.println(); + + // PVT first + + long latitude = myGPS.getLatitude(); + Serial.print(F("Lat: ")); + Serial.print(latitude); + + long longitude = myGPS.getLongitude(); + Serial.print(F(" Long: ")); + Serial.print(longitude); + + long highResLatitude = myGPS.getHighResLatitude(); + Serial.print(F(" Hi Res Lat: ")); + Serial.print(highResLatitude); + + int highResLatitudeHp = myGPS.getHighResLatitudeHp(); + Serial.print(F(" ")); + Serial.print(highResLatitudeHp); + + long highResLongitude = myGPS.getHighResLongitude(); + Serial.print(F(" Hi Res Long: ")); + Serial.print(highResLongitude); + + int highResLongitudeHp = myGPS.getHighResLongitudeHp(); + Serial.print(F(" ")); + Serial.print(highResLongitudeHp); + + unsigned long horizAccuracy = myGPS.getHorizontalAccuracy(); + Serial.print(F(" Horiz accuracy: ")); + Serial.println(horizAccuracy); + + delay(750); + + Serial.println(); + + // HPPOSLLH first + + highResLatitude = myGPS.getHighResLatitude(); + Serial.print(F("Hi Res Lat: ")); + Serial.print(highResLatitude); + + highResLatitudeHp = myGPS.getHighResLatitudeHp(); + Serial.print(F(" ")); + Serial.print(highResLatitudeHp); + + highResLongitude = myGPS.getHighResLongitude(); + Serial.print(F(" Hi Res Long: ")); + Serial.print(highResLongitude); + + highResLongitudeHp = myGPS.getHighResLongitudeHp(); + Serial.print(F(" ")); + Serial.print(highResLongitudeHp); + + horizAccuracy = myGPS.getHorizontalAccuracy(); + Serial.print(F(" Horiz accuracy: ")); + Serial.print(horizAccuracy); + + latitude = myGPS.getLatitude(); + Serial.print(F(" Lat: ")); + Serial.print(latitude); + + longitude = myGPS.getLongitude(); + Serial.print(F(" Long: ")); + Serial.println(longitude); + + delay(750); +} diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index 77dab6d..0fdab4c 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -3013,6 +3013,15 @@ boolean SFE_UBLOX_GPS::getPVT(uint16_t maxWait) if (retVal == SFE_UBLOX_STATUS_DATA_RECEIVED) return (true); + if ((retVal == SFE_UBLOX_STATUS_DATA_OVERWRITTEN) && (packetCfg.id == UBX_NAV_HPPOSLLH)) + { + if (_printDebug == true) + { + _debugSerial->println(F("getPVT: data was OVERWRITTEN by HPPOSLLH (but that's OK)")); + } + return (true); + } + if (_printDebug == true) { _debugSerial->print(F("getPVT retVal: ")); @@ -3180,6 +3189,15 @@ boolean SFE_UBLOX_GPS::getHPPOSLLH(uint16_t maxWait) if (retVal == SFE_UBLOX_STATUS_DATA_RECEIVED) return (true); + if ((retVal == SFE_UBLOX_STATUS_DATA_OVERWRITTEN) && (packetCfg.id == UBX_NAV_PVT)) + { + if (_printDebug == true) + { + _debugSerial->println(F("getHPPOSLLH: data was OVERWRITTEN by PVT (but that's OK)")); + } + return (true); + } + if (_printDebug == true) { _debugSerial->print(F("getHPPOSLLH retVal: "));