Add support for AssistNow Offline. Add Example. Add findMGAANOForDate.

This commit is contained in:
PaulZC
2021-11-26 19:11:38 +00:00
parent ae65547d01
commit 859a5d0858
6 changed files with 531 additions and 9 deletions
+185 -7
View File
@@ -3987,23 +3987,56 @@ bool SFE_UBLOX_GNSS::pushRawData(uint8_t *dataBytes, size_t numDataBytes, bool s
// allowing the user to override with their own time data with setUTCTimeAssistance.
size_t SFE_UBLOX_GNSS::pushAssistNowData(const String &dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait)
{
return (pushAssistNowDataInternal(false, (const uint8_t *)dataBytes.c_str(), numDataBytes, mgaAck, maxWait));
return (pushAssistNowDataInternal(0, false, (const uint8_t *)dataBytes.c_str(), numDataBytes, mgaAck, maxWait));
}
size_t SFE_UBLOX_GNSS::pushAssistNowData(const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait)
{
return (pushAssistNowDataInternal(false, dataBytes, numDataBytes, mgaAck, maxWait));
return (pushAssistNowDataInternal(0, false, dataBytes, numDataBytes, mgaAck, maxWait));
}
size_t SFE_UBLOX_GNSS::pushAssistNowData(bool skipTime, const String &dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait)
{
return (pushAssistNowDataInternal(skipTime, (const uint8_t *)dataBytes.c_str(), numDataBytes, mgaAck, maxWait));
return (pushAssistNowDataInternal(0, skipTime, (const uint8_t *)dataBytes.c_str(), numDataBytes, mgaAck, maxWait));
}
size_t SFE_UBLOX_GNSS::pushAssistNowData(bool skipTime, const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait)
{
return (pushAssistNowDataInternal(skipTime, dataBytes, numDataBytes, mgaAck, maxWait));
return (pushAssistNowDataInternal(0, skipTime, dataBytes, numDataBytes, mgaAck, maxWait));
}
size_t SFE_UBLOX_GNSS::pushAssistNowDataInternal(bool skipTime, const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait)
size_t SFE_UBLOX_GNSS::pushAssistNowData(size_t offset, bool skipTime, const String &dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait)
{
size_t dataPtr = 0; // Pointer into dataBytes
return (pushAssistNowDataInternal(offset, skipTime, (const uint8_t *)dataBytes.c_str(), numDataBytes, mgaAck, maxWait));
}
size_t SFE_UBLOX_GNSS::pushAssistNowData(size_t offset, bool skipTime, const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait)
{
return (pushAssistNowDataInternal(offset, skipTime, dataBytes, numDataBytes, mgaAck, maxWait));
}
size_t SFE_UBLOX_GNSS::pushAssistNowDataInternal(size_t offset, bool skipTime, const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait)
{
size_t dataPtr = offset; // Pointer into dataBytes
if ((offset >= numDataBytes) || (offset < 0)) // Sanity check. Return now if offset is invalid.
{
#ifndef SFE_UBLOX_REDUCED_PROG_MEM
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
{
_debugSerial->print(F("pushAssistNowData: offset ("));
_debugSerial->print(offset);
_debugSerial->println(F(") is invalid! Aborting..."));
}
#endif
return ((size_t)0);
}
if (numDataBytes < 0) // Sanity check. Return now if numDataBytes is negative.
{
#ifndef SFE_UBLOX_REDUCED_PROG_MEM
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
{
_debugSerial->println(F("pushAssistNowData: numDataBytes is negative! Aborting..."));
}
#endif
return ((size_t)0);
}
size_t packetsProcessed = 0; // Keep count of how many packets have been processed
bool checkForAcks = (mgaAck == SFE_UBLOX_MGA_ASSIST_ACK_YES); // If mgaAck is YES, always check for Acks
@@ -4245,7 +4278,152 @@ bool SFE_UBLOX_GNSS::setUTCTimeAssistance(uint16_t year, uint8_t month, uint8_t
}
// Return true if the one packet was pushed successfully
return (pushAssistNowDataInternal(false, iniTimeUTC, 32, mgaAck, maxWait) == 1);
return (pushAssistNowDataInternal(0, false, iniTimeUTC, 32, mgaAck, maxWait) == 1);
}
// Find the start of the AssistNow Offline (UBX_MGA_ANO) data for the chosen day
// The daysIntoFture parameter makes it easy to get the data for (e.g.) tomorrow based on today's date
// Returns numDataBytes if unsuccessful
// TO DO: enhance this so it will find the nearest data for the chosen day - instead of an exact match
size_t SFE_UBLOX_GNSS::findMGAANOForDate(const String &dataBytes, size_t numDataBytes, uint16_t year, uint8_t month, uint8_t day, uint8_t daysIntoFuture)
{
return (findMGAANOForDateInternal((const uint8_t *)dataBytes.c_str(), numDataBytes, year, month, day, daysIntoFuture));
}
size_t SFE_UBLOX_GNSS::findMGAANOForDate(const uint8_t *dataBytes, size_t numDataBytes, uint16_t year, uint8_t month, uint8_t day, uint8_t daysIntoFuture)
{
return (findMGAANOForDateInternal(dataBytes, numDataBytes, year, month, day, daysIntoFuture));
}
size_t SFE_UBLOX_GNSS::findMGAANOForDateInternal(const uint8_t *dataBytes, size_t numDataBytes, uint16_t year, uint8_t month, uint8_t day, uint8_t daysIntoFuture)
{
size_t dataPtr = 0; // Pointer into dataBytes
bool dateFound = false; // Flag to indicate when the date has been found
// Calculate matchDay, matchMonth and matchYear
uint8_t matchDay = day;
uint8_t matchMonth = month;
uint8_t matchYear = (uint8_t)(year - 2000);
// Add on daysIntoFuture
uint8_t daysIntoFutureCopy = daysIntoFuture;
while (daysIntoFutureCopy > 0)
{
matchDay++;
daysIntoFutureCopy--;
switch (matchMonth)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
if (matchDay == 32)
{
matchDay = 1;
matchMonth++;
if (matchMonth == 13)
{
matchMonth = 1;
matchYear++;
}
}
break;
case 4:
case 6:
case 9:
case 11:
if (matchDay == 31)
{
matchDay = 1;
matchMonth++;
}
break;
default: // February
if (((matchYear % 4) == 0) && (matchDay == 30))
{
matchDay = 1;
matchMonth++;
}
else if (((matchYear % 4) > 0) && (matchDay == 29))
{
matchDay = 1;
matchMonth++;
}
break;
}
}
while ((!dateFound) && (dataPtr < numDataBytes)) // Keep going until we have found the date or processed all the bytes
{
// Start by checking the validity of the packet being pointed to
bool dataIsOK = true;
dataIsOK &= (*(dataBytes + dataPtr + 0) == UBX_SYNCH_1); // Check for 0xB5
dataIsOK &= (*(dataBytes + dataPtr + 1) == UBX_SYNCH_2); // Check for 0x62
dataIsOK &= (*(dataBytes + dataPtr + 2) == UBX_CLASS_MGA); // Check for class UBX-MGA
size_t packetLength = ((size_t)*(dataBytes + dataPtr + 4)) | (((size_t)*(dataBytes + dataPtr + 5)) << 8); // Extract the length
uint8_t checksumA = 0;
uint8_t checksumB = 0;
// Calculate the checksum bytes
// Keep going until the end of the packet is reached (payloadPtr == (dataPtr + packetLength))
// or we reach the end of the AssistNow data (payloadPtr == numDataBytes)
for (size_t payloadPtr = dataPtr + ((size_t)2); (payloadPtr < (dataPtr + packetLength + ((size_t)6))) && (payloadPtr < numDataBytes); payloadPtr++)
{
checksumA += *(dataBytes + payloadPtr);
checksumB += checksumA;
}
// Check the checksum bytes
dataIsOK &= (checksumA == *(dataBytes + dataPtr + packetLength + ((size_t)6)));
dataIsOK &= (checksumB == *(dataBytes + dataPtr + packetLength + ((size_t)7)));
dataIsOK &= ((dataPtr + packetLength + ((size_t)8)) <= numDataBytes); // Check we haven't overrun
// If the data is valid, check for a date match
if (dataIsOK)
{
if ((*(dataBytes + dataPtr + 3) == UBX_MGA_ANO)
&& (*(dataBytes + dataPtr + 10) == matchYear)
&& (*(dataBytes + dataPtr + 11) == matchMonth)
&& (*(dataBytes + dataPtr + 12) == matchDay))
{
#ifndef SFE_UBLOX_REDUCED_PROG_MEM
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
{
_debugSerial->print(F("findMGAANOForDate: found date match at location "));
_debugSerial->println(dataPtr);
}
#endif
dateFound = true;
}
else
{
// The data is valid, but these are not the droids we are looking for...
dataPtr += packetLength + ((size_t)8); // Point to the next message
}
}
else
{
#ifndef SFE_UBLOX_REDUCED_PROG_MEM
// The data was invalid. Send a debug message and then try to find the next 0xB5
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
{
_debugSerial->print(F("findMGAANOForDate: bad data - ignored! dataPtr is "));
_debugSerial->println(dataPtr);
}
#endif
while ((dataPtr < numDataBytes) && (*(dataBytes + ++dataPtr) != UBX_SYNCH_1))
{
; // Increment dataPtr until we are pointing at the next 0xB5 - or we reach the end of the data
}
}
}
return (dataPtr);
}
// Support for data logging
+14 -2
View File
@@ -295,6 +295,7 @@ const uint8_t UBX_LOG_STRING = 0x04; //Store arbitrary string on on-board fl
//Class: MGA
//The following are used to configure MGA UBX messages (Multiple GNSS Assistance Messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 34)
const uint8_t UBX_MGA_ACK_DATA0 = 0x60; //Multiple GNSS Acknowledge message
const uint8_t UBX_MGA_ANO = 0x20; //Multiple GNSS AssistNow Offline assistance - NOT SUPPORTED BY THE ZED-F9P! "The ZED-F9P supports AssistNow Online only."
const uint8_t UBX_MGA_BDS_EPH = 0x03; //BDS Ephemeris Assistance
const uint8_t UBX_MGA_BDS_ALM = 0x03; //BDS Almanac Assistance
const uint8_t UBX_MGA_BDS_HEALTH = 0x03; //BDS Health Assistance
@@ -710,11 +711,14 @@ public:
// Return how many MGA packets were pushed successfully.
// If skipTime is true, any UBX-MGA-INI-TIME_UTC or UBX-MGA-INI-TIME_GNSS packets found in the data will be skipped,
// allowing the user to override with their own time data with setUTCTimeAssistance.
// offset allows a sub-set of the data to be sent - starting from offset.
#define defaultMGAdelay 7 // Default to waiting for 7ms between each MGA message
size_t pushAssistNowData(const String &dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck = SFE_UBLOX_MGA_ASSIST_ACK_NO, uint16_t maxWait = defaultMGAdelay);
size_t pushAssistNowData(const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck = SFE_UBLOX_MGA_ASSIST_ACK_NO, uint16_t maxWait = defaultMGAdelay);
size_t pushAssistNowData(bool skipTime, const String &dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck = SFE_UBLOX_MGA_ASSIST_ACK_NO, uint16_t maxWait = defaultMGAdelay);
size_t pushAssistNowData(bool skipTime, const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck = SFE_UBLOX_MGA_ASSIST_ACK_NO, uint16_t maxWait = defaultMGAdelay);
size_t pushAssistNowData(size_t offset, bool skipTime, const String &dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck = SFE_UBLOX_MGA_ASSIST_ACK_NO, uint16_t maxWait = defaultMGAdelay);
size_t pushAssistNowData(size_t offset, bool skipTime, const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck = SFE_UBLOX_MGA_ASSIST_ACK_NO, uint16_t maxWait = defaultMGAdelay);
// Provide initial time assistance
#define defaultMGAINITIMEtAccS 2 // Default to setting the seconds time accuracy to 2 seconds
@@ -722,6 +726,13 @@ public:
#define defaultMGAINITIMEsource 0 // Set default source to none, i.e. on receipt of message (will be inaccurate!)
bool setUTCTimeAssistance(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, uint32_t nanos = 0, uint16_t tAccS = defaultMGAINITIMEtAccS, uint32_t tAccNs = defaultMGAINITIMEtAccNs, uint8_t source = defaultMGAINITIMEsource, sfe_ublox_mga_assist_ack_e mgaAck = SFE_UBLOX_MGA_ASSIST_ACK_NO, uint16_t maxWait = defaultMGAdelay);
// Find the start of the AssistNow Offline (UBX_MGA_ANO) data for the chosen day
// The daysIntoFture parameter makes it easy to get the data for (e.g.) tomorrow based on today's date
// Returns numDataBytes if unsuccessful
// TO DO: enhance this so it will find the nearest data for the chosen day - instead of an exact match
size_t findMGAANOForDate(const String &dataBytes, size_t numDataBytes, uint16_t year, uint8_t month, uint8_t day, uint8_t daysIntoFuture = 0);
size_t findMGAANOForDate(const uint8_t *dataBytes, size_t numDataBytes, uint16_t year, uint8_t month, uint8_t day, uint8_t daysIntoFuture = 0);
// Support for data logging
void setFileBufferSize(uint16_t bufferSize); // Set the size of the file buffer. This must be called _before_ .begin.
uint16_t getFileBufferSize(void); // Return the size of the file buffer
@@ -1316,8 +1327,9 @@ private:
//Functions
bool checkUbloxInternal(ubxPacket *incomingUBX, uint8_t requestedClass = 255, uint8_t requestedID = 255); //Checks module with user selected commType
void addToChecksum(uint8_t incoming); //Given an incoming byte, adjust rollingChecksumA/B
size_t pushAssistNowDataInternal(bool skipTime, const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck = SFE_UBLOX_MGA_ASSIST_ACK_NO, uint16_t maxWait = defaultMGAdelay);
void addToChecksum(uint8_t incoming); //Given an incoming byte, adjust rollingChecksumA/B
size_t pushAssistNowDataInternal(size_t offset, bool skipTime, const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck = SFE_UBLOX_MGA_ASSIST_ACK_NO, uint16_t maxWait = defaultMGAdelay);
size_t findMGAANOForDateInternal(const uint8_t *dataBytes, size_t numDataBytes, uint16_t year, uint8_t month, uint8_t day, uint8_t daysIntoFuture = 0);
//Return true if this "automatic" message has storage allocated for it
bool checkAutomatic(uint8_t Class, uint8_t ID);