From b66297c2cb33b5fa17193337a43f7203375a6b17 Mon Sep 17 00:00:00 2001 From: Adam Blazczak Date: Sun, 14 Jun 2020 22:15:37 -0700 Subject: [PATCH] Add support for older u-blox chips (7 series, 6 series). Fixes https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/issues/113 Based on https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library/commit/512833eef5124226a36747f19a320f6aee4b53e6 by @geeksville Includes my suggestion to check hardware capability before invoking the proper parsing routine from https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/issues/113 and a fix for obtaining accuracies from UBX-NAV-POSLLH. getProtocolVersionHigh() short-circuits after the 1st invocation. --- src/SparkFun_Ublox_Arduino_Library.cpp | 138 ++++++++++++++++++++++--- src/SparkFun_Ublox_Arduino_Library.h | 9 +- 2 files changed, 132 insertions(+), 15 deletions(-) diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index f3f4490..25ffc3d 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -938,6 +938,49 @@ void SFE_UBLOX_GPS::processUBXpacket(ubxPacket *msg) moduleQueried.headingOfMotion = true; moduleQueried.pDOP = true; } + else if (msg->id == UBX_NAV_TIMEUTC && msg->len == 20) + { + timeOfWeek = extractLong(0); + gpsMillisecond = extractLong(0) % 1000; //Get last three digits of iTOW + // extractLong(4); // time accuracy estimate + gpsYear = extractInt(12); + gpsMonth = extractByte(14); + gpsDay = extractByte(15); + gpsHour = extractByte(16); + gpsMinute = extractByte(17); + gpsSecond = extractByte(18); + gpsNanosecond = extractLong(8); //Includes milliseconds + uint8_t valid = extractByte(19); + bool gotTime = (valid & 4) ? true : false; // assume all other fields filled once we have TUTC + + //Mark all datums as fresh (not read before) + moduleQueried.gpsiTOW = gotTime; // valid tow + moduleQueried.gpsYear = gotTime; // valid week num + moduleQueried.gpsMonth = gotTime; + moduleQueried.gpsDay = gotTime; // valid UTC + moduleQueried.gpsHour = gotTime; + moduleQueried.gpsMinute = gotTime; + moduleQueried.gpsSecond = gotTime; + moduleQueried.gpsNanosecond = gotTime; + } + else if (msg->id == UBX_NAV_POSLLH && msg->len == 28) + { + timeOfWeek = extractLong(0); + longitude = extractLong(4); + latitude = extractLong(8); + altitude = extractLong(12); + altitudeMSL = extractLong(16); + horizontalAccuracy = extractLong(20); + verticalAccuracy = extractLong(24); + + moduleQueried.gpsiTOW = true; + moduleQueried.longitude = true; + moduleQueried.latitude = true; + moduleQueried.altitude = true; + moduleQueried.altitudeMSL = true; + highResModuleQueried.horizontalAccuracy = true; + highResModuleQueried.verticalAccuracy = true; + } else if (msg->id == UBX_NAV_HPPOSLLH && msg->len == 36) { timeOfWeek = extractLong(4); @@ -1002,6 +1045,13 @@ void SFE_UBLOX_GPS::processUBXpacket(ubxPacket *msg) _debugSerial->println(((float)(int32_t)extractLong(32)) / 10000.0f); } } + else { + if (_printDebug == true) + { + _debugSerial->print(F("Unexpected nav packet ")); + _debugSerial->println(msg->id); + } + } break; } } @@ -2644,7 +2694,7 @@ int8_t SFE_UBLOX_GPS::extractSignedChar(uint8_t spotToStart) uint16_t SFE_UBLOX_GPS::getYear(uint16_t maxWait) { if (moduleQueried.gpsYear == false) - getPVT(maxWait); + getTimeData(maxWait); moduleQueried.gpsYear = false; //Since we are about to give this to user, mark this data as stale return (gpsYear); } @@ -2653,7 +2703,7 @@ uint16_t SFE_UBLOX_GPS::getYear(uint16_t maxWait) uint8_t SFE_UBLOX_GPS::getMonth(uint16_t maxWait) { if (moduleQueried.gpsMonth == false) - getPVT(maxWait); + getTimeData(maxWait); moduleQueried.gpsMonth = false; //Since we are about to give this to user, mark this data as stale return (gpsMonth); } @@ -2662,7 +2712,7 @@ uint8_t SFE_UBLOX_GPS::getMonth(uint16_t maxWait) uint8_t SFE_UBLOX_GPS::getDay(uint16_t maxWait) { if (moduleQueried.gpsDay == false) - getPVT(maxWait); + getTimeData(maxWait); moduleQueried.gpsDay = false; //Since we are about to give this to user, mark this data as stale return (gpsDay); } @@ -2671,7 +2721,7 @@ uint8_t SFE_UBLOX_GPS::getDay(uint16_t maxWait) uint8_t SFE_UBLOX_GPS::getHour(uint16_t maxWait) { if (moduleQueried.gpsHour == false) - getPVT(maxWait); + getTimeData(maxWait); moduleQueried.gpsHour = false; //Since we are about to give this to user, mark this data as stale return (gpsHour); } @@ -2680,7 +2730,7 @@ uint8_t SFE_UBLOX_GPS::getHour(uint16_t maxWait) uint8_t SFE_UBLOX_GPS::getMinute(uint16_t maxWait) { if (moduleQueried.gpsMinute == false) - getPVT(maxWait); + getTimeData(maxWait); moduleQueried.gpsMinute = false; //Since we are about to give this to user, mark this data as stale return (gpsMinute); } @@ -2689,7 +2739,7 @@ uint8_t SFE_UBLOX_GPS::getMinute(uint16_t maxWait) uint8_t SFE_UBLOX_GPS::getSecond(uint16_t maxWait) { if (moduleQueried.gpsSecond == false) - getPVT(maxWait); + getTimeData(maxWait); moduleQueried.gpsSecond = false; //Since we are about to give this to user, mark this data as stale return (gpsSecond); } @@ -2698,7 +2748,7 @@ uint8_t SFE_UBLOX_GPS::getSecond(uint16_t maxWait) uint16_t SFE_UBLOX_GPS::getMillisecond(uint16_t maxWait) { if (moduleQueried.gpsiTOW == false) - getPVT(maxWait); + getTimeData(maxWait); moduleQueried.gpsiTOW = false; //Since we are about to give this to user, mark this data as stale return (gpsMillisecond); } @@ -2707,7 +2757,7 @@ uint16_t SFE_UBLOX_GPS::getMillisecond(uint16_t maxWait) int32_t SFE_UBLOX_GPS::getNanosecond(uint16_t maxWait) { if (moduleQueried.gpsNanosecond == false) - getPVT(maxWait); + getTimeData(maxWait); moduleQueried.gpsNanosecond = false; //Since we are about to give this to user, mark this data as stale return (gpsNanosecond); } @@ -2762,10 +2812,72 @@ boolean SFE_UBLOX_GPS::getPVT(uint16_t maxWait) } } +// Update time info (using appropriate call for the chip series) +boolean SFE_UBLOX_GPS::getTimeData(uint16_t maxWait) +{ + return getProtocolVersionHigh(maxWait) < 15 ? getTIMEUTC(maxWait) : getPVT(maxWait); +} + +// Update position info (using appropriate call for the chip series) +boolean SFE_UBLOX_GPS::getPositionData(uint16_t maxWait) +{ + return getProtocolVersionHigh(maxWait) < 20 ? getPOSLLH(maxWait) : getPVT(maxWait); +} + +//Get time (for use on chips with protocol version 14 and earlier) +boolean SFE_UBLOX_GPS::getTIMEUTC(uint16_t maxWait) +{ + debugPrintln((char *)F("getTIMEUTC: Polling")); + + //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 = 20; //Begin listening at spot 20 so we can record up to 20+MAX_PAYLOAD_SIZE = 84 bytes Note:now hard-coded in processUBX + + //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("getTIMEUTC retVal: ")); + _debugSerial->println(statusString(retVal)); + } + return (false); +} + +//Get posllh (fos use on chips with protocol version 19 and earlier) +boolean SFE_UBLOX_GPS::getPOSLLH(uint16_t maxWait) +{ + debugPrintln((char *)F("getPOSLLH: Polling")); + + //The GPS is not automatically reporting navigation position so we have to poll explicitly + packetCfg.cls = UBX_CLASS_NAV; + packetCfg.id = UBX_NAV_POSLLH; + packetCfg.len = 0; + //packetCfg.startingSpot = 20; //Begin listening at spot 20 so we can record up to 20+MAX_PAYLOAD_SIZE = 84 bytes Note:now hard-coded in processUBX + + //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("getPOSLLH retVal: ")); + _debugSerial->println(statusString(retVal)); + } + return (false); +} + uint32_t SFE_UBLOX_GPS::getTimeOfWeek(uint16_t maxWait /* = 250*/) { if (moduleQueried.gpsiTOW == false) - getPVT(maxWait); + getTimeData(maxWait); moduleQueried.gpsiTOW = false; //Since we are about to give this to user, mark this data as stale return (timeOfWeek); } @@ -2895,7 +3007,7 @@ uint32_t SFE_UBLOX_GPS::getPositionAccuracy(uint16_t maxWait) int32_t SFE_UBLOX_GPS::getLatitude(uint16_t maxWait) { if (moduleQueried.latitude == false) - getPVT(maxWait); + getPositionData(maxWait); moduleQueried.latitude = false; //Since we are about to give this to user, mark this data as stale moduleQueried.all = false; @@ -2907,7 +3019,7 @@ int32_t SFE_UBLOX_GPS::getLatitude(uint16_t maxWait) int32_t SFE_UBLOX_GPS::getLongitude(uint16_t maxWait) { if (moduleQueried.longitude == false) - getPVT(maxWait); + getPositionData(maxWait); moduleQueried.longitude = false; //Since we are about to give this to user, mark this data as stale moduleQueried.all = false; @@ -2918,7 +3030,7 @@ int32_t SFE_UBLOX_GPS::getLongitude(uint16_t maxWait) int32_t SFE_UBLOX_GPS::getAltitude(uint16_t maxWait) { if (moduleQueried.altitude == false) - getPVT(maxWait); + getPositionData(maxWait); moduleQueried.altitude = false; //Since we are about to give this to user, mark this data as stale moduleQueried.all = false; @@ -2931,7 +3043,7 @@ int32_t SFE_UBLOX_GPS::getAltitude(uint16_t maxWait) int32_t SFE_UBLOX_GPS::getAltitudeMSL(uint16_t maxWait) { if (moduleQueried.altitudeMSL == false) - getPVT(maxWait); + getPositionData(maxWait); moduleQueried.altitudeMSL = false; //Since we are about to give this to user, mark this data as stale moduleQueried.all = false; diff --git a/src/SparkFun_Ublox_Arduino_Library.h b/src/SparkFun_Ublox_Arduino_Library.h index dfa6ce4..2a6338d 100644 --- a/src/SparkFun_Ublox_Arduino_Library.h +++ b/src/SparkFun_Ublox_Arduino_Library.h @@ -531,9 +531,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 getTimeData(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 getPositionData(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 getTIMEUTC(uint16_t maxWait = getPVTmaxWait); //Query module for current time (for use with older chip series). Returns true if new data is available. + boolean getPOSLLH(uint16_t maxWait = getPVTmaxWait); //Query module for current position (for use with older chip series). Returns true if new data 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 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 PVT is available. void flushPVT(); //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.