diff --git a/examples/AssistNow/AssistNow_Online/Example1_AssistNowClient/Example1_AssistNowClient.ino b/examples/AssistNow/AssistNow_Online/Example1_AssistNowClient/Example1_AssistNowClient.ino index 4650355..eb468b2 100644 --- a/examples/AssistNow/AssistNow_Online/Example1_AssistNowClient/Example1_AssistNowClient.ino +++ b/examples/AssistNow/AssistNow_Online/Example1_AssistNowClient/Example1_AssistNowClient.ino @@ -39,8 +39,6 @@ const char tokenSuffix[] = ";"; const char getGNSS[] = "gnss=gps,glo;"; // GNSS can be: gps,qzss,glo,bds,gal const char getDataType[] = "datatype=eph,alm,aux;"; // Data type can be: eph,alm,aux,pos -const unsigned long maxTimeBeforeHangup_ms = 10000; //If we fail to get data after 10s, then disconnect - //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= #include //http://librarymanager/All#SparkFun_u-blox_GNSS @@ -58,18 +56,18 @@ void setup() //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // Start I2C. Connect to the GNSS. -// Wire.begin(); //Start I2C -// -// if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port -// { -// Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing.")); -// while (1); -// } -// Serial.println(F("u-blox module connected")); -// -// myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise -// -// myGNSS.setNavigationFrequency(1); //Set output in Hz. + Wire.begin(); //Start I2C + + if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port + { + Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing.")); + while (1); + } + Serial.println(F("u-blox module connected")); + + myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise + + myGNSS.setNavigationFrequency(1); //Set output in Hz. //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // Connect to WiFi. @@ -86,14 +84,14 @@ void setup() Serial.println("WiFi connected!"); //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - // Make the HTTP request + // Use HTTP GET to receive the AssistNow_Online data - const int URL_BUFFER_SIZE = 512; - char theURL[URL_BUFFER_SIZE]; - int payloadSize; - String payload; + const int URL_BUFFER_SIZE = 256; + char theURL[URL_BUFFER_SIZE]; // This will contain the HTTP URL + int payloadSize = 0; // This will be updated with the length of the data we get from the server + String payload; // This will store the data we get from the server - // Assemble the URL + // Assemble the URL. Note the slash after assistNowServer snprintf(theURL, URL_BUFFER_SIZE, "%s/%s%s%s%s%s%s", assistNowServer, getQuery, @@ -103,14 +101,14 @@ void setup() getGNSS, getDataType); - Serial.print("URL is: "); + Serial.print("HTTP URL is: "); Serial.println(theURL); HTTPClient http; http.begin(theURL); - int httpCode = http.GET(); + int httpCode = http.GET(); // HTTP GET // httpCode will be negative on error if(httpCode > 0) @@ -118,7 +116,7 @@ void setup() // HTTP header has been sent and Server response header has been handled Serial.printf("[HTTP] GET... code: %d\n", httpCode); - // file found at server + // If the GET was successful, read the data if(httpCode == HTTP_CODE_OK) // Code 200 { payloadSize = http.getSize(); @@ -127,6 +125,7 @@ void setup() payload = http.getString(); // Get the payload // Pretty-print the payload as HEX + /* int i; for(i = 0; i < payloadSize; i++) { @@ -139,6 +138,7 @@ void setup() } if ((i % 16) != 15) Serial.println(); + */ } } else @@ -151,13 +151,46 @@ void setup() //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // Push the AssistNow data to the module + if (payloadSize > 0) + { + // Enable the 'major' debug messages on Serial so we can see what AssistNow data is being sent + myGNSS.enableDebugging(Serial, true); - + // Push all the AssistNow data - without checking for UBX-MGA-ACK messages + myGNSS.pushAssistNowData((uint8_t *)&payload, (size_t)payloadSize); + } } //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= void loop() { - // Nothing to do here + long latitude = myGNSS.getLatitude(); + Serial.print(F("Lat: ")); + Serial.print(latitude); + + long longitude = myGNSS.getLongitude(); + Serial.print(F(" Long: ")); + Serial.print(longitude); + Serial.print(F(" (degrees * 10^-7)")); + + long altitude = myGNSS.getAltitude(); + Serial.print(F(" Alt: ")); + Serial.print(altitude); + Serial.print(F(" (mm)")); + + byte SIV = myGNSS.getSIV(); + Serial.print(F(" SIV: ")); + Serial.print(SIV); + + byte fixType = myGNSS.getFixType(); + Serial.print(F(" Fix: ")); + if(fixType == 0) Serial.print(F("No fix")); + else if(fixType == 1) Serial.print(F("Dead reckoning")); + else if(fixType == 2) Serial.print(F("2D")); + else if(fixType == 3) Serial.print(F("3D")); + else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning")); + else if(fixType == 5) Serial.print(F("Time only")); + + Serial.println(); } diff --git a/keywords.txt b/keywords.txt index d1268a2..6d1123a 100644 --- a/keywords.txt +++ b/keywords.txt @@ -90,6 +90,8 @@ checkCallbacks KEYWORD2 pushRawData KEYWORD2 +pushAssistNowData KEYWORD2 + setFileBufferSize KEYWORD2 getFileBufferSize KEYWORD2 extractFileBufferData KEYWORD2 @@ -153,6 +155,18 @@ getDynamicModel KEYWORD2 resetOdometer KEYWORD2 enableGNSS KEYWORD2 +isGNSSenabled KEYWORD2 + +resetIMUalignment KEYWORD2 + +getESFAutoAlignment KEYWORD2 +setESFAutoAlignment KEYWORD2 + +getTimePulseParameters KEYWORD2 +setTimePulseParameters KEYWORD2 + +getAckAiding KEYWORD2 +setAckAiding KEYWORD2 createKey KEYWORD2 getVal KEYWORD2 @@ -367,9 +381,6 @@ initPacketUBXESFRAW KEYWORD2 flushESFRAW KEYWORD2 logESFRAW KEYWORD2 -getESFAutoAlignment KEYWORD2 -setESFAutoAlignment KEYWORD2 - getHNRAtt KEYWORD2 getHNRATT KEYWORD2 setAutoHNRATT KEYWORD2 @@ -675,4 +686,14 @@ SFE_UBLOX_GNSS_ID_IMES LITERAL1 SFE_UBLOX_GNSS_ID_QZSS LITERAL1 SFE_UBLOX_GNSS_ID_GLONASS LITERAL1 -DAYS_SINCE_MONTH LITERAL1 +SFE_UBLOX_MGA_ASSIST_ACK_NO LITERAL1 +SFE_UBLOX_MGA_ASSIST_ACK_YES LITERAL1 +SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE LITERAL1 + +SFE_UBLOX_MGA_ACK_INFOCODE_ACCEPTED LITERAL1 +SFE_UBLOX_MGA_ACK_INFOCODE_NO_TIME LITERAL1 +SFE_UBLOX_MGA_ACK_INFOCODE_NOT_SUPPORTED LITERAL1 +SFE_UBLOX_MGA_ACK_INFOCODE_SIZE_MISMATCH LITERAL1 +SFE_UBLOX_MGA_ACK_INFOCODE_NOT_STORED LITERAL1 +SFE_UBLOX_MGA_ACK_INFOCODE_NOT_READY LITERAL1 +SFE_UBLOX_MGA_ACK_INFOCODE_TYPE_UNKNOWN LITERAL1 diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index 68130fa..3217208 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -2715,6 +2715,44 @@ void SFE_UBLOX_GNSS::processUBXpacket(ubxPacket *msg) } } break; + case UBX_CLASS_MGA: + if (msg->id == UBX_MGA_ACK_DATA0 && msg->len == UBX_MGA_ACK_DATA0_LEN) + { + //Parse various byte fields into storage - but only if we have memory allocated for it + if (packetUBXMGAACK != NULL) + { + // Calculate how many ACKs are already stored in the ring buffer + uint8_t ackBufferContains; + if (packetUBXMGAACK->head >= packetUBXMGAACK->tail) // Check if wrap-around has occurred + { + // Wrap-around has not occurred so do a simple subtraction + ackBufferContains = packetUBXMGAACK->head - packetUBXMGAACK->tail; + } + else + { + // Wrap-around has occurred so do a simple subtraction but add in the buffer length (UBX_MGA_ACK_RINGBUFFER_LEN) + ackBufferContains = ((uint8_t)(((uint16_t)packetUBXMGAACK->head + (uint16_t)UBX_MGA_ACK_DATA0_RINGBUFFER_LEN) - (uint16_t)packetUBXMGAACK->tail)); + } + // Have we got space to store this ACK? + if (ackBufferContains < (UBX_MGA_ACK_DATA0_RINGBUFFER_LEN - 1)) + { + // Yes, we have, so store it + packetUBXMGAACK->data[packetUBXMGAACK->head].type = extractByte(msg, 0); + packetUBXMGAACK->data[packetUBXMGAACK->head].version = extractByte(msg, 1); + packetUBXMGAACK->data[packetUBXMGAACK->head].infoCode = extractByte(msg, 2); + packetUBXMGAACK->data[packetUBXMGAACK->head].msgId = extractByte(msg, 3); + packetUBXMGAACK->data[packetUBXMGAACK->head].msgPayloadStart[0] = extractByte(msg, 4); + packetUBXMGAACK->data[packetUBXMGAACK->head].msgPayloadStart[1] = extractByte(msg, 5); + packetUBXMGAACK->data[packetUBXMGAACK->head].msgPayloadStart[2] = extractByte(msg, 6); + packetUBXMGAACK->data[packetUBXMGAACK->head].msgPayloadStart[3] = extractByte(msg, 7); + // Increment the head + packetUBXMGAACK->head++; + if (packetUBXMGAACK->head == UBX_MGA_ACK_DATA0_RINGBUFFER_LEN) + packetUBXMGAACK->head = 0; + } + } + } + break; case UBX_CLASS_HNR: if (msg->id == UBX_HNR_PVT && msg->len == UBX_HNR_PVT_LEN) { @@ -3931,6 +3969,169 @@ bool SFE_UBLOX_GNSS::pushRawData(uint8_t *dataBytes, size_t numDataBytes, bool s } } +// Push MGA AssistNow data to the module +// Check for UBX-MGA-ACK responses if required (if mgaAck is YES or ENQUIRE) +// Wait for maxWait millis after sending each packet (if mgaAck is NO) +// Return how many MGA packets were pushed successfully +uint16_t SFE_UBLOX_GNSS::pushAssistNowData(uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait) +{ + size_t dataPtr = 0; // Pointer into dataBytes + uint16_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 + + // If mgaAck is ENQUIRE, we need to check UBX-CFG-NAVX5 ackAiding to determine if UBX-MGA-ACK's are expected + if (mgaAck == SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE) + { + uint8_t ackAiding = getAckAiding(maxWait); // Enquire if we should expect Acks + if (ackAiding == 1) + checkForAcks = true; + } + + // If checkForAcks is true, then we need to set up storage for the UBX-MGA-ACK-DATA0 messages and use the callback + if (checkForAcks) + { + if (packetUBXMGAACK == NULL) initPacketUBXMGAACK(); //Check that RAM has been allocated for the MGA_ACK data + if (packetUBXMGAACK == NULL) //Bail if the RAM allocation failed + return (0); + } + + while (dataPtr < numDataBytes) // Keep going until we have 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)6); (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, push it + if (dataIsOK) + { + pushRawData((uint8_t *)&dataBytes[dataPtr], packetLength + ((size_t)8)); // Push the data + + if (checkForAcks) + { + unsigned long startTime = millis(); + bool keepGoing = true; + while (keepGoing && (millis() < (startTime + maxWait))) // Keep checking for the ACK until we time out + { + checkUblox(); + if (packetUBXMGAACK->head != packetUBXMGAACK->tail) // Does the MGA ACK ringbuffer contain any ACK's? + { + bool dataAckd = true; // Check if we've received the correct ACK + dataAckd &= packetUBXMGAACK->data[packetUBXMGAACK->tail].msgId == dataBytes[dataPtr + 3]; + dataAckd &= packetUBXMGAACK->data[packetUBXMGAACK->tail].msgPayloadStart[0] == dataBytes[dataPtr + 6]; + dataAckd &= packetUBXMGAACK->data[packetUBXMGAACK->tail].msgPayloadStart[1] == dataBytes[dataPtr + 7]; + dataAckd &= packetUBXMGAACK->data[packetUBXMGAACK->tail].msgPayloadStart[2] == dataBytes[dataPtr + 8]; + dataAckd &= packetUBXMGAACK->data[packetUBXMGAACK->tail].msgPayloadStart[3] == dataBytes[dataPtr + 9]; + + if (dataAckd) // Is this the ACK we are looking for? + { + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + { + _debugSerial->print(F("pushAssistNowData: packet ID 0x")); + if (dataBytes[dataPtr + 3] < 0x10) + _debugSerial->print(F("0")); + _debugSerial->print(dataBytes[dataPtr + 3], HEX); + } + if ((packetUBXMGAACK->data[packetUBXMGAACK->tail].type == (uint8_t)1) && (packetUBXMGAACK->data[packetUBXMGAACK->tail].infoCode == (uint8_t)SFE_UBLOX_MGA_ACK_INFOCODE_ACCEPTED)) + { + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + { + _debugSerial->println(F(" was accepted")); + } + packetsProcessed++; + } + else + { + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + { + _debugSerial->print(F(" was _not_ accepted. infoCode is ")); + _debugSerial->println(packetUBXMGAACK->data[packetUBXMGAACK->tail].infoCode); + } + } + keepGoing = false; + } + // Increment the tail + packetUBXMGAACK->tail++; + if (packetUBXMGAACK->tail == UBX_MGA_ACK_DATA0_RINGBUFFER_LEN) + packetUBXMGAACK->tail = 0; + } + } + if (keepGoing) // If keepGoing is still true, we must have timed out + { + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + { + _debugSerial->print(F("pushAssistNowData: packet ID 0x")); + if (dataBytes[dataPtr + 3] < 0x10) + _debugSerial->print(F("0")); + _debugSerial->print(dataBytes[dataPtr + 3], HEX); + _debugSerial->println(F(" timed out!")); + } + } + } + else + { + // We are not checking for Acks, so delay for maxWait millis unless we've reached the end of the data + if ((dataPtr + packetLength + ((size_t)8)) < numDataBytes) + { + delay(maxWait); + } + } + + dataPtr += packetLength + ((size_t)8); // Point to the next message + } + else + { + // 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("pushAssistNowData: bad data - ignored! dataPtr is")); + _debugSerial->println(dataPtr); + } + + 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 (packetsProcessed); +} + +// PRIVATE: Allocate RAM for packetUBXMGAACK and initialize it +bool SFE_UBLOX_GNSS::initPacketUBXMGAACK() +{ + packetUBXMGAACK = new UBX_MGA_ACK_DATA0_t; //Allocate RAM for the main struct + if (packetUBXMGAACK == NULL) + { + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + _debugSerial->println(F("initPacketUBXMGAACK: RAM alloc failed!")); + return (false); + } + packetUBXMGAACK->head = 0; // Initialize the ring buffer pointers + packetUBXMGAACK->tail = 0; + return (true); +} + // Support for data logging //Set the file buffer size. This must be called _before_ .begin @@ -5383,6 +5584,44 @@ bool SFE_UBLOX_GNSS::setTimePulseParameters(UBX_CFG_TP5_data_t *data, uint16_t m return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } +//UBX-CFG-NAVX5 - get/set the ackAiding byte. If ackAiding is 1, UBX-MGA-ACK messages will be sent by the module to acknowledge the MGA data +uint8_t SFE_UBLOX_GNSS::getAckAiding(uint16_t maxWait) // Get the ackAiding byte - returns 255 if the sendCommand fails +{ + packetCfg.cls = UBX_CLASS_CFG; + packetCfg.id = UBX_CFG_NAVX5; + packetCfg.len = 0; + packetCfg.startingSpot = 0; + + if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK + return (255); + + // Extract the ackAiding byte + // There are three versions of UBX-CFG-NAVX5 but ackAiding is always in byte 17 + return (extractByte(&packetCfg, 17)); +} +bool SFE_UBLOX_GNSS::setAckAiding(uint8_t ackAiding, uint16_t maxWait) // Set the ackAiding byte +{ + packetCfg.cls = UBX_CLASS_CFG; + packetCfg.id = UBX_CFG_NAVX5; + packetCfg.len = 0; + packetCfg.startingSpot = 0; + + if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK + return (false); + + // Set the ackAiding byte + // There are three versions of UBX-CFG-NAVX5 but ackAiding is always in byte 17 + payloadCfg[17] = ackAiding; + + // There are three versions of UBX-CFG-NAVX5 but the ackAid flag is always in bit 10 of mask1 + payloadCfg[2] = 0x00; // Clear the LS byte of mask1 + payloadCfg[3] = 0x40; // Set _only_ the ackAid flag = bit 10 of mask1 = bit 2 of the MS byte + payloadCfg[4] = 0x00; // Clear the LS byte of mask2, just in case + payloadCfg[5] = 0x00; // Clear the LS byte of mask2, just in case + + return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK +} + // CONFIGURATION INTERFACE (protocol v27 and above) //Form 32-bit key from group/id/size diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.h b/src/SparkFun_u-blox_GNSS_Arduino_Library.h index 1bc37b9..90eea67 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.h +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.h @@ -200,7 +200,7 @@ const uint8_t UBX_CFG_BATCH = 0x93; //Get/set data batching configuration. const uint8_t UBX_CFG_CFG = 0x09; //Clear, Save, and Load Configurations. Used to save current configuration const uint8_t UBX_CFG_DAT = 0x06; //Set User-defined Datum or The currently defined Datum const uint8_t UBX_CFG_DGNSS = 0x70; //DGNSS configuration -const uint8_t UBX_CFG_ESFALG = 0x56; //ESF alignment +const uint8_t UBX_CFG_ESFALG = 0x56; //ESF alignment const uint8_t UBX_CFG_ESFA = 0x4C; //ESF accelerometer const uint8_t UBX_CFG_ESFG = 0x4D; //ESF gyro const uint8_t UBX_CFG_GEOFENCE = 0x69; //Geofencing configuration. Used to configure a geofence @@ -496,6 +496,27 @@ enum sfe_ublox_ls_src_e SFE_UBLOX_LS_SRC_UNKNOWN = 255 }; +typedef enum +{ + SFE_UBLOX_MGA_ASSIST_ACK_NO, // Do not expect UBX-MGA-ACK's. If the module outputs them, they will be ignored + SFE_UBLOX_MGA_ASSIST_ACK_YES, // Expect and check for UBX-MGA-ACK's + SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE // Check UBX-CFG-NAVX5 ackAiding to determine if UBX-MGA-ACK's are expected +} sfe_ublox_mga_assist_ack_e; + +// The infoCode byte included in UBX-MGA-ACK-DATA0 +enum sfe_ublox_mga_ack_infocode_e +{ + SFE_UBLOX_MGA_ACK_INFOCODE_ACCEPTED, + SFE_UBLOX_MGA_ACK_INFOCODE_NO_TIME, + SFE_UBLOX_MGA_ACK_INFOCODE_NOT_SUPPORTED, + SFE_UBLOX_MGA_ACK_INFOCODE_SIZE_MISMATCH, + SFE_UBLOX_MGA_ACK_INFOCODE_NOT_STORED, + SFE_UBLOX_MGA_ACK_INFOCODE_NOT_READY, + SFE_UBLOX_MGA_ACK_INFOCODE_TYPE_UNKNOWN +}; + +//-=-=-=-=- + #ifndef MAX_PAYLOAD_SIZE // v2.0: keep this for backwards-compatibility, but this is largely superseded by setPacketCfgPayloadSize #define MAX_PAYLOAD_SIZE 256 //We need ~220 bytes for getProtocolVersion on most ublox modules @@ -683,6 +704,13 @@ public: // Default to using a restart between transmissions. But processors like ESP32 seem to need a stop (#30). Set stop to true to use a stop instead. bool pushRawData(uint8_t *dataBytes, size_t numDataBytes, bool stop = false); + // Push MGA AssistNow data to the module + // Check for UBX-MGA-ACK responses if required (if mgaAck is YES or ENQUIRE) + // Wait for maxWait millis after sending each packet (if mgaAck is NO) + // Return how many MGA packets were pushed successfully + #define defaultMGAdelay 10 // Default to waiting for 10ms between each MGA message + uint16_t pushAssistNowData(uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck = SFE_UBLOX_MGA_ASSIST_ACK_NO, uint16_t maxWait = defaultMGAdelay); + // 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 @@ -785,6 +813,10 @@ public: bool getTimePulseParameters(UBX_CFG_TP5_data_t *data = NULL, uint16_t maxWait = defaultMaxWait); // Get the time pulse parameters using UBX_CFG_TP5 bool setTimePulseParameters(UBX_CFG_TP5_data_t *data = NULL, uint16_t maxWait = defaultMaxWait); // Set the time pulse parameters using UBX_CFG_TP5 + //UBX-CFG-NAVX5 - get/set the ackAiding byte. If ackAiding is 1, UBX-MGA-ACK messages will be sent by the module to acknowledge the MGA data + uint8_t getAckAiding(uint16_t maxWait = defaultMaxWait); // Get the ackAiding byte - returns 255 if the sendCommand fails + bool setAckAiding(uint8_t ackAiding, uint16_t maxWait = defaultMaxWait); // Set the ackAiding byte + //General configuration (used only on protocol v27 and higher - ie, ZED-F9P) //It is probably safe to assume that users of the ZED-F9P will be using I2C / Qwiic. @@ -1242,6 +1274,8 @@ public: UBX_HNR_ATT_t *packetUBXHNRATT = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary UBX_HNR_INS_t *packetUBXHNRINS = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary + UBX_MGA_ACK_DATA0_t *packetUBXMGAACK = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary + uint16_t rtcmFrameCounter = 0; //Tracks the type of incoming byte inside RTCM frame private: @@ -1313,6 +1347,7 @@ private: bool initPacketUBXHNRATT(); // Allocate RAM for packetUBXHNRATT and initialize it bool initPacketUBXHNRINS(); // Allocate RAM for packetUBXHNRINS and initialize it bool initPacketUBXHNRPVT(); // Allocate RAM for packetUBXHNRPVT and initialize it + bool initPacketUBXMGAACK(); // Allocate RAM for packetUBXMGAACK and initialize it //Variables TwoWire *_i2cPort; //The generic connection to user's chosen I2C hardware diff --git a/src/u-blox_structs.h b/src/u-blox_structs.h index 763bdb6..ac38510 100644 --- a/src/u-blox_structs.h +++ b/src/u-blox_structs.h @@ -1656,6 +1656,31 @@ typedef struct UBX_ESF_STATUS_data_t *callbackData; } UBX_ESF_STATUS_t; +// MGA-specific structs + +// UBX-MGA-ACK-DATA0 (0x13 0x60): Multiple GNSS acknowledge message +const uint16_t UBX_MGA_ACK_DATA0_LEN = 8; + +typedef struct +{ + uint8_t type; // Type of acknowledgment: + // 0: The message was not used by the receiver (see infoCode field for an indication of why) + // 1: The message was accepted for use by the receiver (the infoCode field will be 0) + uint8_t version; // Message version + uint8_t infoCode; // Provides greater information on what the receiver chose to do with the message contents + // See sfe_ublox_mga_ack_infocode_e + uint8_t msgId; // UBX message ID of the acknowledged message + uint8_t msgPayloadStart[4]; // The first 4 bytes of the acknowledged message's payload +} UBX_MGA_ACK_DATA0_data_t; + +#define UBX_MGA_ACK_DATA0_RINGBUFFER_LEN 16 // Provide storage for 16 MGA ACK packets +typedef struct +{ + uint8_t head; + uint8_t tail; + UBX_MGA_ACK_DATA0_data_t data[UBX_MGA_ACK_DATA0_RINGBUFFER_LEN]; // Create a storage array for the MGA ACK packets +} UBX_MGA_ACK_DATA0_t; + // HNR-specific structs // UBX-HNR-PVT (0x28 0x00): High rate output of PVT solution