From 19ff31b8b768cd00eea8d5cc84def3212b3851e1 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Thu, 25 Nov 2021 20:31:44 +0000 Subject: [PATCH] AssistNow_Online Example1 is working nicely! TO DO: Overload (?) pushAssistNowData so it can accept uint8_t * as the data source, instead of a String. --- .../Example1_AssistNowClient.ino | 68 ++++++++++---- src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 89 ++++++++++++------- src/SparkFun_u-blox_GNSS_Arduino_Library.h | 4 +- 3 files changed, 111 insertions(+), 50 deletions(-) diff --git a/examples/AssistNow/AssistNow_Online/Example1_AssistNowClient/Example1_AssistNowClient.ino b/examples/AssistNow/AssistNow_Online/Example1_AssistNowClient/Example1_AssistNowClient.ino index eb468b2..96f4d9d 100644 --- a/examples/AssistNow/AssistNow_Online/Example1_AssistNowClient/Example1_AssistNowClient.ino +++ b/examples/AssistNow/AssistNow_Online/Example1_AssistNowClient/Example1_AssistNowClient.ino @@ -6,7 +6,7 @@ basically do whatever you want with this code. This example shows how to obtain AssistNow Online data from u-blox Thingstream over WiFi - and push it over I2C to a ZED-F9x. + and push it over I2C to a u-blox module. You will need to have a token to be able to access Thingstream. See the AssistNow README for more details. @@ -14,11 +14,14 @@ - WiFi credentials - AssistNow token string + Uncomment the "#define USE_MGA_ACKs" below to test the more robust method of using the + UBX_MGA_ACK_DATA0 acknowledgements to confirm that each MGA message has been accepted. + Feel like supporting open source hardware? Buy a board from SparkFun! - SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663 - ZED-F9P RTK2: https://www.sparkfun.com/products/16481 - SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193 + SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663 + ZED-F9P RTK2: https://www.sparkfun.com/products/16481 + SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193 Hardware Connections: Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus @@ -26,6 +29,8 @@ Open the serial monitor at 115200 baud to see the output */ +//#define USE_MGA_ACKs // Uncomment this line to use the UBX_MGA_ACK_DATA0 acknowledgements + #include #include #include "secrets.h" @@ -67,8 +72,6 @@ void setup() myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise - myGNSS.setNavigationFrequency(1); //Set output in Hz. - //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // Connect to WiFi. @@ -91,7 +94,8 @@ void setup() 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. Note the slash after assistNowServer + // Assemble the URL + // Note the slash after the first %s (assistNowServer) snprintf(theURL, URL_BUFFER_SIZE, "%s/%s%s%s%s%s%s", assistNowServer, getQuery, @@ -114,18 +118,18 @@ void setup() if(httpCode > 0) { // HTTP header has been sent and Server response header has been handled - Serial.printf("[HTTP] GET... code: %d\n", httpCode); + Serial.printf("[HTTP] GET... code: %d\r\n", httpCode); // If the GET was successful, read the data - if(httpCode == HTTP_CODE_OK) // Code 200 + if(httpCode == HTTP_CODE_OK) // Check for code 200 { payloadSize = http.getSize(); Serial.printf("Server returned %d bytes\r\n", payloadSize); payload = http.getString(); // Get the payload - // Pretty-print the payload as HEX - /* + // Pretty-print the payload as HEX + /* int i; for(i = 0; i < payloadSize; i++) { @@ -143,7 +147,7 @@ void setup() } else { - Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); + Serial.printf("[HTTP] GET... failed, error: %s\r\n", http.errorToString(httpCode).c_str()); } http.end(); @@ -152,12 +156,40 @@ 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); + +#ifndef USE_MGA_ACKs + + // ***** Don't use the UBX_MGA_ACK_DATA0 messages ***** + + // Push all the AssistNow data. Don't use UBX_MGA_ACK_DATA0's. Use the default delay of 7ms between messages. + myGNSS.pushAssistNowData(payload, (size_t)payloadSize); + +#else + + // ***** Use the UBX_MGA_ACK_DATA0 messages ***** + + // Tell the module to return UBX_MGA_ACK_DATA0 messages when we push the AssistNow data + myGNSS.setAckAiding(1); + + // Speed things up by setting setI2CpollingWait to 1ms + myGNSS.setI2CpollingWait(1); + + // Push all the AssistNow data. + // We have called setAckAiding(1) to instruct the module to return MGA-ACK messages. + // So, we could set the pushAssistNowData mgaAck parameter to SFE_UBLOX_MGA_ASSIST_ACK_YES. + // But, just for giggles, let's use SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE just to confirm that the + // MGA-ACK messages are actually enabled. + // Wait for up to 1000ms for each ACK to arrive! 1000ms is a bit excessive... 7ms is nearer the mark. + myGNSS.pushAssistNowData(payload, (size_t)payloadSize, SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE, 1000); + + // Set setI2CpollingWait to 125ms to avoid pounding the I2C bus + myGNSS.setI2CpollingWait(125); + +#endif + } } @@ -165,6 +197,8 @@ void setup() void loop() { + // Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D + long latitude = myGNSS.getLatitude(); Serial.print(F("Lat: ")); Serial.print(latitude); @@ -193,4 +227,4 @@ void loop() else if(fixType == 5) Serial.print(F("Time only")); Serial.println(); -} +} \ No newline at end of file diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index 3217208..e9cdda2 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -1075,6 +1075,11 @@ bool SFE_UBLOX_GNSS::checkAutomatic(uint8_t Class, uint8_t ID) } } break; + case UBX_CLASS_MGA: + { + if (packetUBXMGAACK != NULL) result = true; + } + break; case UBX_CLASS_HNR: { switch (ID) @@ -1205,6 +1210,11 @@ uint16_t SFE_UBLOX_GNSS::getMaxPayloadSize(uint8_t Class, uint8_t ID) } } break; + case UBX_CLASS_MGA: + { + maxSize = UBX_MGA_ACK_DATA0_LEN; + } + break; case UBX_CLASS_HNR: { switch (ID) @@ -3973,7 +3983,7 @@ bool SFE_UBLOX_GNSS::pushRawData(uint8_t *dataBytes, size_t numDataBytes, bool s // 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) +uint16_t SFE_UBLOX_GNSS::pushAssistNowData(String 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 @@ -3986,9 +3996,15 @@ uint16_t SFE_UBLOX_GNSS::pushAssistNowData(uint8_t *dataBytes, size_t numDataByt uint8_t ackAiding = getAckAiding(maxWait); // Enquire if we should expect Acks if (ackAiding == 1) checkForAcks = true; + + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + { + _debugSerial->print(F("pushAssistNowData: mgaAck is ENQUIRE. getAckAiding returned ")); + _debugSerial->println(ackAiding); + } } - // If checkForAcks is true, then we need to set up storage for the UBX-MGA-ACK-DATA0 messages and use the callback + // If checkForAcks is true, then we need to set up storage for the UBX-MGA-ACK-DATA0 messages if (checkForAcks) { if (packetUBXMGAACK == NULL) initPacketUBXMGAACK(); //Check that RAM has been allocated for the MGA_ACK data @@ -4001,31 +4017,43 @@ uint16_t SFE_UBLOX_GNSS::pushAssistNowData(uint8_t *dataBytes, size_t numDataByt // 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 + 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 + 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++) + 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 + 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 ((_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->print(F(" length ")); + _debugSerial->println(packetLength); + } + if (checkForAcks) { unsigned long startTime = millis(); @@ -4036,26 +4064,21 @@ uint16_t SFE_UBLOX_GNSS::pushAssistNowData(uint8_t *dataBytes, size_t numDataByt 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]; + dataAckd &= (packetUBXMGAACK->data[packetUBXMGAACK->tail].msgId == dataBytes[dataPtr + 3]); // Check if the message ID matches + dataAckd &= (packetUBXMGAACK->data[packetUBXMGAACK->tail].msgPayloadStart[0] == dataBytes[dataPtr + 6]); // Check if the first four data bytes match + 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")); + _debugSerial->print(F("pushAssistNowData: packet was accepted after ")); + _debugSerial->print(millis() - startTime); + _debugSerial->println(F(" ms")); } packetsProcessed++; } @@ -4063,7 +4086,7 @@ uint16_t SFE_UBLOX_GNSS::pushAssistNowData(uint8_t *dataBytes, size_t numDataByt { if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging { - _debugSerial->print(F(" was _not_ accepted. infoCode is ")); + _debugSerial->print(F("pushAssistNowData: packet was _not_ accepted. infoCode is ")); _debugSerial->println(packetUBXMGAACK->data[packetUBXMGAACK->tail].infoCode); } } @@ -4079,16 +4102,14 @@ uint16_t SFE_UBLOX_GNSS::pushAssistNowData(uint8_t *dataBytes, size_t numDataByt { 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!")); + _debugSerial->println(F("pushAssistNowData: packet ack timed out!")); } } } else { + // We are not checking for Acks, so let's assume the send was successful? + packetsProcessed++; // 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) { @@ -4103,7 +4124,7 @@ uint16_t SFE_UBLOX_GNSS::pushAssistNowData(uint8_t *dataBytes, size_t numDataByt // 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->print(F("pushAssistNowData: bad data - ignored! dataPtr is ")); _debugSerial->println(dataPtr); } @@ -4114,6 +4135,12 @@ uint16_t SFE_UBLOX_GNSS::pushAssistNowData(uint8_t *dataBytes, size_t numDataByt } } + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + { + _debugSerial->print(F("pushAssistNowData: packetsProcessed: ")); + _debugSerial->println(packetsProcessed); + } + return (packetsProcessed); } @@ -5615,7 +5642,7 @@ bool SFE_UBLOX_GNSS::setAckAiding(uint8_t ackAiding, uint16_t maxWait) // Set th // 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[3] = 0x04; // 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 diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.h b/src/SparkFun_u-blox_GNSS_Arduino_Library.h index 90eea67..b905c0c 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.h +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.h @@ -708,8 +708,8 @@ public: // 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); + #define defaultMGAdelay 7 // Default to waiting for 7ms between each MGA message + uint16_t pushAssistNowData(String 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.