From 51de78e3f505399e9ef42160e6e55d90ea159f6e Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Fri, 17 Apr 2020 18:41:25 +0100 Subject: [PATCH 01/21] Experimental code - passes requested class and id down to processUBX --- src/SparkFun_Ublox_Arduino_Library.cpp | 272 ++++++++++++++----------- src/SparkFun_Ublox_Arduino_Library.h | 18 +- 2 files changed, 164 insertions(+), 126 deletions(-) diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index c395918..7b0ced2 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -263,18 +263,18 @@ void SFE_UBLOX_GPS::setNMEAOutputPort(Stream &nmeaOutputPort) } //Called regularly to check for available bytes on the user' specified port -boolean SFE_UBLOX_GPS::checkUblox() +boolean SFE_UBLOX_GPS::checkUblox(uint8_t requestedClass, uint8_t requestedID) { if (commType == COMM_TYPE_I2C) - return (checkUbloxI2C()); + return (checkUbloxI2C(requestedClass, requestedID)); else if (commType == COMM_TYPE_SERIAL) - return (checkUbloxSerial()); + return (checkUbloxSerial(requestedClass, requestedID)); return false; } //Polls I2C for data, passing any new bytes to process() //Returns true if new bytes are available -boolean SFE_UBLOX_GPS::checkUbloxI2C() +boolean SFE_UBLOX_GPS::checkUbloxI2C(uint8_t requestedClass, uint8_t requestedID) { if (millis() - lastCheck >= i2cPollingWait) { @@ -401,7 +401,7 @@ boolean SFE_UBLOX_GPS::checkUbloxI2C() } } - process(incoming); //Process this valid character + process(incoming, requestedClass, requestedID); //Process this valid character } } else @@ -416,11 +416,11 @@ boolean SFE_UBLOX_GPS::checkUbloxI2C() } //end checkUbloxI2C() //Checks Serial for data, passing any new bytes to process() -boolean SFE_UBLOX_GPS::checkUbloxSerial() +boolean SFE_UBLOX_GPS::checkUbloxSerial(uint8_t requestedClass, uint8_t requestedID) { while (_serialPort->available()) { - process(_serialPort->read()); + process(_serialPort->read(), requestedClass, requestedID); } return (true); @@ -428,7 +428,7 @@ boolean SFE_UBLOX_GPS::checkUbloxSerial() //Processes NMEA and UBX binary sentences one byte at a time //Take a given byte and file it into the proper array -void SFE_UBLOX_GPS::process(uint8_t incoming) +void SFE_UBLOX_GPS::process(uint8_t incoming, uint8_t requestedClass, uint8_t requestedID) { if (currentSentence == NONE || currentSentence == NMEA) { @@ -487,9 +487,9 @@ void SFE_UBLOX_GPS::process(uint8_t incoming) //Depending on this frame's class, pass different structs and payload arrays if (ubxFrameClass == CLASS_ACK) - processUBX(incoming, &packetAck); + processUBX(incoming, &packetAck, requestedClass, requestedID); else if (ubxFrameClass == CLASS_NOT_AN_ACK) - processUBX(incoming, &packetCfg); + processUBX(incoming, &packetCfg, requestedClass, requestedID); } else if (currentSentence == NMEA) { @@ -577,7 +577,7 @@ void SFE_UBLOX_GPS::processRTCM(uint8_t incoming) //The payload portion of the packet can be 100s of bytes but the max array //size is roughly 64 bytes. startingSpot can be set so we only record //a subset of bytes within a larger packet. -void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX) +void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) { //Add all incoming bytes to the rolling checksum //Stop at len+4 as this is the checksum bytes to that should not be added to the rolling checksum @@ -615,6 +615,26 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX) { incomingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_VALID; + // Let's check if the class and ID match the requestedClass and requestedID + if ((incomingUBX->cls == requestedClass) && (incomingUBX->id == requestedID)) + { + incomingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_VALID; // If we have a match, set the classAndIDmatch flag to valid + } + + // If this is an ACK then let's check if the class and ID match the requestedClass and requestedID + else if ((incomingUBX->cls == UBX_CLASS_ACK) && (incomingUBX->id == UBX_ACK_ACK) + && (incomingUBX->payload[0] == requestedClass) && (incomingUBX->payload[1] == requestedID)) + { + incomingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_VALID; // If we have a match, set the classAndIDmatch flag to valid + } + + // If this is a NACK then let's check if the class and ID match the requestedClass and requestedID + else if ((incomingUBX->cls == UBX_CLASS_ACK) && (incomingUBX->id == UBX_ACK_NACK) + && (incomingUBX->payload[0] == requestedClass) && (incomingUBX->payload[1] == requestedID)) + { + incomingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_VALID; // If we have a match, set the classAndIDmatch flag to NOT_VALID + } + if (_printDebug == true) { _debugSerial->print(F("Incoming: Size: ")); @@ -636,6 +656,20 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX) _debugSerial->println(F("packetAck now valid")); } } + if (packetCfg.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) + { + if (_printDebug == true) + { + _debugSerial->println(F("packetCfg classAndIDmatch")); + } + } + if (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) + { + if (_printDebug == true) + { + _debugSerial->println(F("packetAck classAndIDmatch")); + } + } } processUBXpacket(incomingUBX); //We've got a valid packet, now do something with it @@ -644,6 +678,15 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX) { incomingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_NOT_VALID; + // Let's check if the class and ID match the requestedClass and requestedID. + // This is potentially risky as we are saying that we saw the requested Class and ID + // but that the packet checksum failed. Potentially it could be the class or ID bytes + // that caused the checksum error! + if ((incomingUBX->cls == requestedClass) && (incomingUBX->id == requestedID)) + { + incomingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_VALID; // If we have a match, set the classAndIDmatch flag to not valid + } + if (_printDebug == true) { //Drive an external pin to allow for easier logic analyzation @@ -707,28 +750,6 @@ void SFE_UBLOX_GPS::processUBXpacket(ubxPacket *msg) { switch (msg->cls) { - case UBX_CLASS_ACK: - //We don't want to store ACK packets, just set commandAck flag - if (msg->id == UBX_ACK_ACK && msg->payload[0] == packetCfg.cls && msg->payload[1] == packetCfg.id) - { - //The ack we just received matched the CLS/ID of last packetCfg sent (or received) - if (_printDebug == true) - { - _debugSerial->println(F("UBX ACK: Command sent/ack'd successfully")); - } - commandAck = UBX_ACK_ACK; - } - else if (msg->id == UBX_ACK_NACK && msg->payload[0] == packetCfg.cls && msg->payload[1] == packetCfg.id) - { - //The ack we just received matched the CLS/ID of last packetCfg sent - if (_printDebug == true) - { - _debugSerial->println(F("UBX ACK: Not-Acknowledged")); - } - commandAck = UBX_ACK_NACK; - } - break; - case UBX_CLASS_NAV: if (msg->id == UBX_NAV_PVT && msg->len == 92) { @@ -1105,103 +1126,125 @@ void SFE_UBLOX_GPS::printPacket(ubxPacket *packet) //Returns SFE_UBLOX_STATUS_TIMEOUT if we timed out sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime) { - commandAck = UBX_ACK_NONE; //Reset flag packetCfg.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; //This will go VALID (or NOT_VALID) when we receive a response to the packet we sent packetAck.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; + packetCfg.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; // This will go VALID (or NOT_VALID) when we receive a packet that matches the requested class and ID + packetAck.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; unsigned long startTime = millis(); while (millis() - startTime < maxTime) { - if (checkUblox() == true) //See if new data is available. Process bytes as they come in. + if (checkUblox(requestedClass, requestedID) == true) //See if new data is available. Process bytes as they come in. { - //First we verify the ACK. commandAck will only go UBX_ACK_ACK if CLS/ID matches - if (commandAck == UBX_ACK_ACK) + // If both the packetCfg.classAndIDmatch and packetAck.classAndIDmatch are VALID then we are all done + if ((packetCfg.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) + && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID)) { if (_printDebug == true) { - _debugSerial->print(F("waitForACKResponse: ACK received after ")); + _debugSerial->print(F("waitForACKResponse: valid data and valid ACK received after ")); _debugSerial->print(millis() - startTime); _debugSerial->println(F(" msec")); } + return (SFE_UBLOX_STATUS_DATA_RECEIVED); //We received valid data and a correct ACK! + } - //We've got the a valid ACK for this CLS/ID, so is packetCfg valid? - if (packetCfg.valid == SFE_UBLOX_PACKET_VALIDITY_VALID) + // If the packetCfg.classAndIDmatch is NOT_VALID but the packetAck.classAndIDmatch is VALID + // then we could take a gamble and return DATA_RECEIVED, but it is safer to return + // FAIL instead + else if ((packetCfg.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) + && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID)) + { + if (_printDebug == true) { - //We've got a valid packetCfg, so does it match the requested Class and ID? - if (packetCfg.cls == requestedClass && packetCfg.id == requestedID) - { - if (_printDebug == true) - { - _debugSerial->print(F("waitForACKResponse: CLS/ID match after ")); - _debugSerial->print(millis() - startTime); - _debugSerial->println(F(" msec")); - } - return (SFE_UBLOX_STATUS_DATA_RECEIVED); //Received a data and a correct ACK! - } - else - // The Class and/or ID don't match the requested ones, so keep trying... - { - //Reset packet and continue checking incoming data for matching cls/id - if (_printDebug == true) - { - _debugSerial->println(F("waitForACKResponse: CLS/ID mismatch, continue to wait...")); - } - packetCfg.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; //This will go VALID (or NOT_VALID) when we receive a response to the packet we sent - } + _debugSerial->print(F("waitForACKResponse: INVALID data and VALID ACK received after ")); + _debugSerial->print(millis() - startTime); + _debugSerial->println(F(" msec")); } - //If we received an invalid packetCfg (checksum failure) then we can't trust it, including its Class and ID - else if (packetCfg.valid == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) + return (SFE_UBLOX_STATUS_FAIL); //We received valid data and a correct ACK! + } + + // If the packetCfg.classAndIDmatch is VALID but the packetAck.classAndIDmatch is NOT_VALID + // then we will take a gamble and return DATA_RECEIVED. If we were playing safe, we should + // return FAIL instead + else if ((packetCfg.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) + && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID)) + { + if (_printDebug == true) { - //We were expecting data but didn't get a valid config packet - if (_printDebug == true) - { - _debugSerial->println(F("waitForACKResponse: Invalid config packet")); - } - return (SFE_UBLOX_STATUS_FAIL); //We got a checksum failure, we're never going to get valid config data + _debugSerial->print(F("waitForACKResponse: VALID data and INVALID ACK received after ")); + _debugSerial->print(millis() - startTime); + _debugSerial->println(F(" msec")); } - //We didn't receive a valid or invalid packetCfg, so we must have only received the ACK - //Let's hope this was a set? - else + return (SFE_UBLOX_STATUS_DATA_RECEIVED); //We received valid data and an invalid ACK! + } + + // If the packetCfg.classAndIDmatch is NOT_VALID and the packetAck.classAndIDmatch is NOT_VALID + // then we return a FAIL + else if ((packetCfg.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) + && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID)) + { + if (_printDebug == true) { - //We have sent new data. We expect an ACK but no return config packet. - if (_printDebug == true) - { - _debugSerial->println(F("waitForACKResponse: New data successfully sent")); - } - return (SFE_UBLOX_STATUS_DATA_SENT); //New data successfully sent + _debugSerial->print(F("waitForACKResponse: INVALID data and INVALID ACK received after ")); + _debugSerial->print(millis() - startTime); + _debugSerial->println(F(" msec")); + } + return (SFE_UBLOX_STATUS_FAIL); //We received invalid data and an invalid ACK! + } + + // If the packetCfg.classAndIDmatch is VALID and the packetAck.classAndIDmatch is NOT_DEFINED + // then we keep waiting for an ACK + else if ((packetCfg.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) + && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED)) + { + if (_printDebug == true) + { + _debugSerial->print(F("waitForACKResponse: valid data after ")); + _debugSerial->print(millis() - startTime); + _debugSerial->println(F(" msec")); } } - //Did we receive a NACK? - else if (commandAck == UBX_ACK_NACK) + + // If the packetCfg.classAndIDmatch is NOT_DEFINED and the packetAck.classAndIDmatch is VALID + // then we return DATA_SENT. + else if ((packetCfg.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED) + && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID)) { if (_printDebug == true) { - _debugSerial->print(F("waitForACKResponse: NACK received after ")); + _debugSerial->print(F("waitForACKResponse: VALID data after ")); _debugSerial->print(millis() - startTime); _debugSerial->println(F(" msec")); } - return (SFE_UBLOX_STATUS_COMMAND_UNKNOWN); //Received a NACK + return (SFE_UBLOX_STATUS_DATA_SENT); //We got an ACK but no data... } + } //checkUblox == true delayMicroseconds(500); } //while (millis() - startTime < maxTime) - //TODO add check here if config went valid but we never got the following ack - //Through debug warning, This command might not get an ACK - if (packetCfg.valid == SFE_UBLOX_PACKET_VALIDITY_VALID) + // We have timed out... + // If the packetCfg.classAndIDmatch is VALID then we can take a gamble and return DATA_RECEIVED + // even though we did not get an ACK + if ((packetCfg.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) + && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED)) { if (_printDebug == true) { - _debugSerial->println(F("waitForACKResponse: Config was valid but ACK not received")); + _debugSerial->print(F("waitForACKResponse: TIMEOUT with valid data after ")); + _debugSerial->print(millis() - startTime); + _debugSerial->println(F(" msec. ")); } + return (SFE_UBLOX_STATUS_DATA_RECEIVED); //We received valid data... But no ACK! } if (_printDebug == true) { - _debugSerial->print(F("waitForACKResponse: timeout after ")); + _debugSerial->print(F("waitForACKResponse: TIMEOUT after ")); _debugSerial->print(millis() - startTime); - _debugSerial->println(F(" msec. No ack packet received.")); + _debugSerial->println(F(" msec.")); } return (SFE_UBLOX_STATUS_TIMEOUT); @@ -1215,37 +1258,41 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(uint8_t requestedClass, u { packetCfg.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; //This will go VALID (or NOT_VALID) when we receive a response to the packet we sent packetAck.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - packetCfg.cls = 255; + packetCfg.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; // This will go VALID (or NOT_VALID) when we receive a packet that matches the requested class and ID + packetAck.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; + packetCfg.cls = 255; // Use the packet class and id to indicate if an unexpected packet has been received packetCfg.id = 255; unsigned long startTime = millis(); while (millis() - startTime < maxTime) { - if (checkUblox() == true) //See if new data is available. Process bytes as they come in. + if (checkUblox(requestedClass, requestedID) == true) //See if new data is available. Process bytes as they come in. { - //Did we receive a config packet that matches the cls/id we requested? - if ((packetCfg.cls == requestedClass) && (packetCfg.id == requestedID) && (packetCfg.valid != SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED)) + + // If the packetCfg.classAndIDmatch is VALID then we are all done + if (packetCfg.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) { - //This packet might be good or it might be CRC corrupt - if (packetCfg.valid == SFE_UBLOX_PACKET_VALIDITY_VALID) + if (_printDebug == true) { - if (_printDebug == true) - { - _debugSerial->print(F("waitForNoACKResponse: CLS/ID match after ")); - _debugSerial->print(millis() - startTime); - _debugSerial->println(F(" msec")); - } - return (SFE_UBLOX_STATUS_DATA_RECEIVED); //We have new data to act upon + _debugSerial->print(F("waitForNoACKResponse: CLS/ID match after ")); + _debugSerial->print(millis() - startTime); + _debugSerial->println(F(" msec")); } - else // if (packetCfg.valid == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) + return (SFE_UBLOX_STATUS_DATA_RECEIVED); //We received valid data and a correct ACK! + } + + // If the packetCfg.classAndIDmatch is NOT_VALID then we return CRC failure + else if (packetCfg.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) + { + if (_printDebug == true) { - if (_printDebug == true) - { - _debugSerial->println(F("waitForNoACKResponse: CLS/ID match but failed CRC")); - } - return (SFE_UBLOX_STATUS_CRC_FAIL); //We got the right packet but it was corrupt + _debugSerial->print(F("waitForNoACKResponse: CLS/ID match but failed CRC after ")); + _debugSerial->print(millis() - startTime); + _debugSerial->println(F(" msec")); } + return (SFE_UBLOX_STATUS_CRC_FAIL); //We received invalid data } + else if ((packetCfg.cls < 255) && (packetCfg.id < 255) && (packetCfg.valid != SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED)) { //We got a valid or invalid packet but it was not the droid we were looking for @@ -1271,7 +1318,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(uint8_t requestedClass, u if (_printDebug == true) { - _debugSerial->print(F("waitForNoACKResponse: timeout after ")); + _debugSerial->print(F("waitForNoACKResponse: TIMEOUT after ")); _debugSerial->print(millis() - startTime); _debugSerial->println(F(" msec. No packet received.")); } @@ -1828,15 +1875,6 @@ boolean SFE_UBLOX_GPS::setPortOutput(uint8_t portID, uint8_t outStreamSettings, if (getPortSettings(portID, maxWait) == false) return (false); //Something went wrong. Bail. - if (commandAck != UBX_ACK_ACK) - { - if (_printDebug == true) - { - _debugSerial->println(F("setPortOutput failed to ACK")); - } - return (false); - } - packetCfg.cls = UBX_CLASS_CFG; packetCfg.id = UBX_CFG_PRT; packetCfg.len = 20; diff --git a/src/SparkFun_Ublox_Arduino_Library.h b/src/SparkFun_Ublox_Arduino_Library.h index 32a7ed7..a20bcd8 100644 --- a/src/SparkFun_Ublox_Arduino_Library.h +++ b/src/SparkFun_Ublox_Arduino_Library.h @@ -409,6 +409,7 @@ typedef struct uint8_t checksumA; //Given to us from module. Checked against the rolling calculated A/B checksums. uint8_t checksumB; sfe_ublox_packet_validity_e valid; //Goes from NOT_DEFINED to VALID or NOT_VALID when checksum is checked + sfe_ublox_packet_validity_e classAndIDmatch; // Goes from flase to true when the Class and ID match the requestedClass and requestedID } ubxPacket; // Struct to hold the results returned by getGeofenceState (returned by UBX-NAV-GEOFENCE) @@ -448,13 +449,13 @@ class SFE_UBLOX_GPS //maxWait is only used for Serial boolean isConnected(uint16_t maxWait = 1100); - boolean checkUblox(); //Checks module with user selected commType - boolean checkUbloxI2C(); //Method for I2C polling of data, passing any new bytes to process() - boolean checkUbloxSerial(); //Method for serial polling of data, passing any new bytes to process() + boolean checkUblox(uint8_t requestedClass = 255, uint8_t requestedID = 255); //Checks module with user selected commType + boolean checkUbloxI2C(uint8_t requestedClass = 255, uint8_t requestedID = 255); //Method for I2C polling of data, passing any new bytes to process() + boolean checkUbloxSerial(uint8_t requestedClass = 255, uint8_t requestedID = 255); //Method for serial polling of data, passing any new bytes to process() - void process(uint8_t incoming); //Processes NMEA and UBX binary sentences one byte at a time - void processUBX(uint8_t incoming, ubxPacket *incomingUBX); //Given a character, file it away into the uxb packet structure - void processRTCMframe(uint8_t incoming); //Monitor the incoming bytes for start and length bytes + void process(uint8_t incoming, uint8_t requestedClass = 255, uint8_t requestedID = 255); //Processes NMEA and UBX binary sentences one byte at a time + void processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass = 255, uint8_t requestedID = 255); //Given a character, file it away into the uxb packet structure + void processRTCMframe(uint8_t incoming); //Monitor the incoming bytes for start and length bytes void processRTCM(uint8_t incoming) __attribute__((weak)); //Given rtcm byte, do something with it. User can overwrite if desired to pipe bytes to radio, internet, etc. void processUBXpacket(ubxPacket *msg); //Once a packet has been received and validated, identify this packet's class/id and update internal flags @@ -729,8 +730,8 @@ class SFE_UBLOX_GPS uint8_t payloadCfg[MAX_PAYLOAD_SIZE]; //Init the packet structures and init them with pointers to the payloadAck and payloadCfg arrays - ubxPacket packetAck = {0, 0, 0, 0, 0, payloadAck, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; - ubxPacket packetCfg = {0, 0, 0, 0, 0, payloadCfg, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; + ubxPacket packetAck = {0, 0, 0, 0, 0, payloadAck, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; + ubxPacket packetCfg = {0, 0, 0, 0, 0, payloadCfg, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; //Limit checking of new data to every X ms //If we are expecting an update every X Hz then we should check every half that amount of time @@ -740,7 +741,6 @@ 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) - uint8_t commandAck = UBX_ACK_NONE; //This goes to UBX_ACK_ACK after we send a command and it's ack'd 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 2b30dd0a25a3b95b3d1027367d98d646ff1af8fb Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Sat, 18 Apr 2020 11:30:09 +0100 Subject: [PATCH 02/21] Initial commit - passing the ubxPacket down to processUBX --- src/SparkFun_Ublox_Arduino_Library.cpp | 96 +++++++++++++------------- src/SparkFun_Ublox_Arduino_Library.h | 12 ++-- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index 7b0ced2..98ee207 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -263,18 +263,18 @@ void SFE_UBLOX_GPS::setNMEAOutputPort(Stream &nmeaOutputPort) } //Called regularly to check for available bytes on the user' specified port -boolean SFE_UBLOX_GPS::checkUblox(uint8_t requestedClass, uint8_t requestedID) +boolean SFE_UBLOX_GPS::checkUblox(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) { if (commType == COMM_TYPE_I2C) - return (checkUbloxI2C(requestedClass, requestedID)); + return (checkUbloxI2C(incomingUBX, requestedClass, requestedID)); else if (commType == COMM_TYPE_SERIAL) - return (checkUbloxSerial(requestedClass, requestedID)); + return (checkUbloxSerial(incomingUBX, requestedClass, requestedID)); return false; } //Polls I2C for data, passing any new bytes to process() //Returns true if new bytes are available -boolean SFE_UBLOX_GPS::checkUbloxI2C(uint8_t requestedClass, uint8_t requestedID) +boolean SFE_UBLOX_GPS::checkUbloxI2C(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) { if (millis() - lastCheck >= i2cPollingWait) { @@ -401,7 +401,7 @@ boolean SFE_UBLOX_GPS::checkUbloxI2C(uint8_t requestedClass, uint8_t requestedID } } - process(incoming, requestedClass, requestedID); //Process this valid character + process(incoming, incomingUBX, requestedClass, requestedID); //Process this valid character } } else @@ -416,11 +416,11 @@ boolean SFE_UBLOX_GPS::checkUbloxI2C(uint8_t requestedClass, uint8_t requestedID } //end checkUbloxI2C() //Checks Serial for data, passing any new bytes to process() -boolean SFE_UBLOX_GPS::checkUbloxSerial(uint8_t requestedClass, uint8_t requestedID) +boolean SFE_UBLOX_GPS::checkUbloxSerial(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) { while (_serialPort->available()) { - process(_serialPort->read(), requestedClass, requestedID); + process(_serialPort->read(), incomingUBX, requestedClass, requestedID); } return (true); @@ -428,7 +428,7 @@ boolean SFE_UBLOX_GPS::checkUbloxSerial(uint8_t requestedClass, uint8_t requeste //Processes NMEA and UBX binary sentences one byte at a time //Take a given byte and file it into the proper array -void SFE_UBLOX_GPS::process(uint8_t incoming, uint8_t requestedClass, uint8_t requestedID) +void SFE_UBLOX_GPS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) { if (currentSentence == NONE || currentSentence == NMEA) { @@ -477,8 +477,8 @@ void SFE_UBLOX_GPS::process(uint8_t incoming, uint8_t requestedClass, uint8_t re } else { - packetCfg.counter = 0; - packetCfg.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; + incomingUBX->counter = 0; + incomingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; ubxFrameClass = CLASS_NOT_AN_ACK; } } @@ -489,7 +489,7 @@ void SFE_UBLOX_GPS::process(uint8_t incoming, uint8_t requestedClass, uint8_t re if (ubxFrameClass == CLASS_ACK) processUBX(incoming, &packetAck, requestedClass, requestedID); else if (ubxFrameClass == CLASS_NOT_AN_ACK) - processUBX(incoming, &packetCfg, requestedClass, requestedID); + processUBX(incoming, incomingUBX, requestedClass, requestedID); } else if (currentSentence == NMEA) { @@ -906,7 +906,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::sendCommand(ubxPacket outgoingUBX, uint16_t ma { _debugSerial->println(F("sendCommand: Waiting for ACK response")); } - retVal = waitForACKResponse(outgoingUBX.cls, outgoingUBX.id, maxWait); //Wait for Ack response + retVal = waitForACKResponse(&outgoingUBX, outgoingUBX.cls, outgoingUBX.id, maxWait); //Wait for Ack response } else { @@ -914,7 +914,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::sendCommand(ubxPacket outgoingUBX, uint16_t ma { _debugSerial->println(F("sendCommand: Waiting for No ACK response")); } - retVal = waitForNoACKResponse(outgoingUBX.cls, outgoingUBX.id, maxWait); //Wait for Ack response + retVal = waitForNoACKResponse(&outgoingUBX, outgoingUBX.cls, outgoingUBX.id, maxWait); //Wait for Ack response } } return retVal; @@ -1124,20 +1124,20 @@ void SFE_UBLOX_GPS::printPacket(ubxPacket *packet) //Returns SFE_UBLOX_STATUS_FAIL if we got an invalid packetCfg (checksum failure) //Returns SFE_UBLOX_STATUS_COMMAND_UNKNOWN if we got a NACK (command unknown) //Returns SFE_UBLOX_STATUS_TIMEOUT if we timed out -sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime) +sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime) { - packetCfg.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; //This will go VALID (or NOT_VALID) when we receive a response to the packet we sent + outgoingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; //This will go VALID (or NOT_VALID) when we receive a response to the packet we sent packetAck.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - packetCfg.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; // This will go VALID (or NOT_VALID) when we receive a packet that matches the requested class and ID + outgoingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; // This will go VALID (or NOT_VALID) when we receive a packet that matches the requested class and ID packetAck.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; unsigned long startTime = millis(); while (millis() - startTime < maxTime) { - if (checkUblox(requestedClass, requestedID) == true) //See if new data is available. Process bytes as they come in. + if (checkUblox(outgoingUBX, requestedClass, requestedID) == true) //See if new data is available. Process bytes as they come in. { - // If both the packetCfg.classAndIDmatch and packetAck.classAndIDmatch are VALID then we are all done - if ((packetCfg.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) + // If both the outgoingUBX->classAndIDmatch and packetAck.classAndIDmatch are VALID then we are all done + if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID)) { if (_printDebug == true) @@ -1149,10 +1149,10 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(uint8_t requestedClass, uin return (SFE_UBLOX_STATUS_DATA_RECEIVED); //We received valid data and a correct ACK! } - // If the packetCfg.classAndIDmatch is NOT_VALID but the packetAck.classAndIDmatch is VALID + // If the outgoingUBX->classAndIDmatch is NOT_VALID but the packetAck.classAndIDmatch is VALID // then we could take a gamble and return DATA_RECEIVED, but it is safer to return // FAIL instead - else if ((packetCfg.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) + else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID)) { if (_printDebug == true) @@ -1164,10 +1164,10 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(uint8_t requestedClass, uin return (SFE_UBLOX_STATUS_FAIL); //We received valid data and a correct ACK! } - // If the packetCfg.classAndIDmatch is VALID but the packetAck.classAndIDmatch is NOT_VALID + // If the outgoingUBX->classAndIDmatch is VALID but the packetAck.classAndIDmatch is NOT_VALID // then we will take a gamble and return DATA_RECEIVED. If we were playing safe, we should // return FAIL instead - else if ((packetCfg.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) + else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID)) { if (_printDebug == true) @@ -1179,9 +1179,9 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(uint8_t requestedClass, uin return (SFE_UBLOX_STATUS_DATA_RECEIVED); //We received valid data and an invalid ACK! } - // If the packetCfg.classAndIDmatch is NOT_VALID and the packetAck.classAndIDmatch is NOT_VALID + // If the outgoingUBX->classAndIDmatch is NOT_VALID and the packetAck.classAndIDmatch is NOT_VALID // then we return a FAIL - else if ((packetCfg.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) + else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID)) { if (_printDebug == true) @@ -1193,9 +1193,9 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(uint8_t requestedClass, uin return (SFE_UBLOX_STATUS_FAIL); //We received invalid data and an invalid ACK! } - // If the packetCfg.classAndIDmatch is VALID and the packetAck.classAndIDmatch is NOT_DEFINED + // If the outgoingUBX->classAndIDmatch is VALID and the packetAck.classAndIDmatch is NOT_DEFINED // then we keep waiting for an ACK - else if ((packetCfg.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) + else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED)) { if (_printDebug == true) @@ -1206,9 +1206,9 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(uint8_t requestedClass, uin } } - // If the packetCfg.classAndIDmatch is NOT_DEFINED and the packetAck.classAndIDmatch is VALID + // If the outgoingUBX->classAndIDmatch is NOT_DEFINED and the packetAck.classAndIDmatch is VALID // then we return DATA_SENT. - else if ((packetCfg.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED) + else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED) && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID)) { if (_printDebug == true) @@ -1226,9 +1226,9 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(uint8_t requestedClass, uin } //while (millis() - startTime < maxTime) // We have timed out... - // If the packetCfg.classAndIDmatch is VALID then we can take a gamble and return DATA_RECEIVED + // If the outgoingUBX->classAndIDmatch is VALID then we can take a gamble and return DATA_RECEIVED // even though we did not get an ACK - if ((packetCfg.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) + if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED)) { if (_printDebug == true) @@ -1254,23 +1254,23 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(uint8_t requestedClass, uin //Returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got a config packet full of response data that has CLS/ID match to our query packet //Returns SFE_UBLOX_STATUS_CRC_FAIL if we got a corrupt config packet that has CLS/ID match to our query packet //Returns SFE_UBLOX_STATUS_TIMEOUT if we timed out -sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime) +sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(ubxPacket *outgoingUBX, uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime) { - packetCfg.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; //This will go VALID (or NOT_VALID) when we receive a response to the packet we sent + outgoingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; //This will go VALID (or NOT_VALID) when we receive a response to the packet we sent packetAck.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - packetCfg.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; // This will go VALID (or NOT_VALID) when we receive a packet that matches the requested class and ID + outgoingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; // This will go VALID (or NOT_VALID) when we receive a packet that matches the requested class and ID packetAck.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - packetCfg.cls = 255; // Use the packet class and id to indicate if an unexpected packet has been received - packetCfg.id = 255; + outgoingUBX->cls = 255; // Use the packet class and id to indicate if an unexpected packet has been received + outgoingUBX->id = 255; unsigned long startTime = millis(); while (millis() - startTime < maxTime) { - if (checkUblox(requestedClass, requestedID) == true) //See if new data is available. Process bytes as they come in. + if (checkUblox(outgoingUBX, requestedClass, requestedID) == true) //See if new data is available. Process bytes as they come in. { - // If the packetCfg.classAndIDmatch is VALID then we are all done - if (packetCfg.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) + // If the outgoingUBX->classAndIDmatch is VALID then we are all done + if (outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) { if (_printDebug == true) { @@ -1281,8 +1281,8 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(uint8_t requestedClass, u return (SFE_UBLOX_STATUS_DATA_RECEIVED); //We received valid data and a correct ACK! } - // If the packetCfg.classAndIDmatch is NOT_VALID then we return CRC failure - else if (packetCfg.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) + // If the outgoingUBX->classAndIDmatch is NOT_VALID then we return CRC failure + else if (outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) { if (_printDebug == true) { @@ -1293,7 +1293,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(uint8_t requestedClass, u return (SFE_UBLOX_STATUS_CRC_FAIL); //We received invalid data } - else if ((packetCfg.cls < 255) && (packetCfg.id < 255) && (packetCfg.valid != SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED)) + else if ((outgoingUBX->cls < 255) && (outgoingUBX->id < 255) && (outgoingUBX->valid != SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED)) { //We got a valid or invalid packet but it was not the droid we were looking for //Reset packet and continue checking incoming data for matching cls/id @@ -1301,15 +1301,15 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(uint8_t requestedClass, u { _debugSerial->print(F("waitForNoACKResponse: CLS/ID mismatch: ")); _debugSerial->print(F("CLS: ")); - _debugSerial->print(packetCfg.cls, HEX); + _debugSerial->print(outgoingUBX->cls, HEX); _debugSerial->print(F(" ID: ")); - _debugSerial->print(packetCfg.id, HEX); + _debugSerial->print(outgoingUBX->id, HEX); _debugSerial->println(); } - packetCfg.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; //This will go VALID (or NOT_VALID) when we receive a response to the packet we sent - packetCfg.cls = 255; - packetCfg.id = 255; + outgoingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; //This will go VALID (or NOT_VALID) when we receive a response to the packet we sent + outgoingUBX->cls = 255; + outgoingUBX->id = 255; } } @@ -2434,7 +2434,7 @@ boolean SFE_UBLOX_GPS::getPVT(uint16_t maxWait) { _debugSerial->println(F("getPVT: Autoreporting")); } - checkUblox(); + checkUblox(&packetCfg, UBX_CLASS_NAV, UBX_NAV_PVT); return moduleQueried.all; } else if (autoPVT && !autoPVTImplicitUpdate) diff --git a/src/SparkFun_Ublox_Arduino_Library.h b/src/SparkFun_Ublox_Arduino_Library.h index a20bcd8..8e63d32 100644 --- a/src/SparkFun_Ublox_Arduino_Library.h +++ b/src/SparkFun_Ublox_Arduino_Library.h @@ -449,11 +449,11 @@ class SFE_UBLOX_GPS //maxWait is only used for Serial boolean isConnected(uint16_t maxWait = 1100); - boolean checkUblox(uint8_t requestedClass = 255, uint8_t requestedID = 255); //Checks module with user selected commType - boolean checkUbloxI2C(uint8_t requestedClass = 255, uint8_t requestedID = 255); //Method for I2C polling of data, passing any new bytes to process() - boolean checkUbloxSerial(uint8_t requestedClass = 255, uint8_t requestedID = 255); //Method for serial polling of data, passing any new bytes to process() + boolean checkUblox(ubxPacket *incomingUBX, uint8_t requestedClass = 255, uint8_t requestedID = 255); //Checks module with user selected commType + boolean checkUbloxI2C(ubxPacket *incomingUBX, uint8_t requestedClass = 255, uint8_t requestedID = 255); //Method for I2C polling of data, passing any new bytes to process() + boolean checkUbloxSerial(ubxPacket *incomingUBX, uint8_t requestedClass = 255, uint8_t requestedID = 255); //Method for serial polling of data, passing any new bytes to process() - void process(uint8_t incoming, uint8_t requestedClass = 255, uint8_t requestedID = 255); //Processes NMEA and UBX binary sentences one byte at a time + void process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass = 255, uint8_t requestedID = 255); //Processes NMEA and UBX binary sentences one byte at a time void processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass = 255, uint8_t requestedID = 255); //Given a character, file it away into the uxb packet structure void processRTCMframe(uint8_t incoming); //Monitor the incoming bytes for start and length bytes void processRTCM(uint8_t incoming) __attribute__((weak)); //Given rtcm byte, do something with it. User can overwrite if desired to pipe bytes to radio, internet, etc. @@ -481,8 +481,8 @@ class SFE_UBLOX_GPS boolean factoryDefault(uint16_t maxWait = defaultMaxWait); //Reset module to factory defaults boolean saveConfigSelective(uint32_t configMask, uint16_t maxWait = defaultMaxWait); //Save the selected configuration sub-sections to flash and BBR (battery backed RAM) - sfe_ublox_status_e waitForACKResponse(uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime = defaultMaxWait); //Poll the module until a config packet and an ACK is received - sfe_ublox_status_e waitForNoACKResponse(uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime = defaultMaxWait); //Poll the module until a config packet is received + sfe_ublox_status_e waitForACKResponse(ubxPacket *outgoingUBX, uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime = defaultMaxWait); //Poll the module until a config packet and an ACK is received + sfe_ublox_status_e waitForNoACKResponse(ubxPacket *outgoingUBX, uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime = defaultMaxWait); //Poll the module until a config packet is received // getPVT will only return data once in each navigation cycle. By default, that is once per second. // Therefore we should set getPVTmaxWait to slightly longer than that. From 852dfe1649eb35cbaabba8dfadfb6b1f474bc2e9 Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Sat, 18 Apr 2020 11:33:10 +0100 Subject: [PATCH 03/21] Update SparkFun_Ublox_Arduino_Library.cpp --- src/SparkFun_Ublox_Arduino_Library.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index 7b0ced2..5dcdf5f 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -2434,7 +2434,7 @@ boolean SFE_UBLOX_GPS::getPVT(uint16_t maxWait) { _debugSerial->println(F("getPVT: Autoreporting")); } - checkUblox(); + checkUblox(UBX_CLASS_NAV, UBX_NAV_PVT); return moduleQueried.all; } else if (autoPVT && !autoPVTImplicitUpdate) From d2503cf484bf00092aed2401fd236bcb1e8dabb1 Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Sat, 18 Apr 2020 12:42:18 +0100 Subject: [PATCH 04/21] Update SparkFun_Ublox_Arduino_Library.cpp --- src/SparkFun_Ublox_Arduino_Library.cpp | 35 ++++++++++++++++++++------ 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index 98ee207..0a9d1f9 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -633,6 +633,13 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t && (incomingUBX->payload[0] == requestedClass) && (incomingUBX->payload[1] == requestedID)) { incomingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_VALID; // If we have a match, set the classAndIDmatch flag to NOT_VALID + if (_printDebug == true) + { + _debugSerial->print(F("processUBX: NACK received: Requested Class: ")); + _debugSerial->print(incomingUBX->payload[0]); + _debugSerial->print(F(" Requested ID: ")); + _debugSerial->println(incomingUBX->payload[1]); + } } if (_printDebug == true) @@ -642,7 +649,7 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t _debugSerial->print(F(" Received: ")); printPacket(incomingUBX); - if (packetCfg.valid == SFE_UBLOX_PACKET_VALIDITY_VALID) + if (incomingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_VALID) { if (_printDebug == true) { @@ -656,7 +663,7 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t _debugSerial->println(F("packetAck now valid")); } } - if (packetCfg.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) + if (incomingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) { if (_printDebug == true) { @@ -682,6 +689,7 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t // This is potentially risky as we are saying that we saw the requested Class and ID // but that the packet checksum failed. Potentially it could be the class or ID bytes // that caused the checksum error! + if ((incomingUBX->cls == requestedClass) && (incomingUBX->id == requestedID)) { incomingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_VALID; // If we have a match, set the classAndIDmatch flag to not valid @@ -1284,13 +1292,26 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(ubxPacket *outgoingUBX, u // If the outgoingUBX->classAndIDmatch is NOT_VALID then we return CRC failure else if (outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) { - if (_printDebug == true) + if (outgoingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_VALID) { - _debugSerial->print(F("waitForNoACKResponse: CLS/ID match but failed CRC after ")); - _debugSerial->print(millis() - startTime); - _debugSerial->println(F(" msec")); + if (_printDebug == true) + { + _debugSerial->print(F("waitForNoACKResponse: CLS/ID match but NACK received after ")); + _debugSerial->print(millis() - startTime); + _debugSerial->println(F(" msec")); + } + return (SFE_UBLOX_STATUS_CRC_FAIL); //We received invalid data + } + else if (outgoingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) + { + if (_printDebug == true) + { + _debugSerial->print(F("waitForNoACKResponse: CLS/ID match but failed CRC after ")); + _debugSerial->print(millis() - startTime); + _debugSerial->println(F(" msec")); + } + return (SFE_UBLOX_STATUS_CRC_FAIL); //We received invalid data } - return (SFE_UBLOX_STATUS_CRC_FAIL); //We received invalid data } else if ((outgoingUBX->cls < 255) && (outgoingUBX->id < 255) && (outgoingUBX->valid != SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED)) From 95a729a70d5e67510c720b93f8106e12917ed77f Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Sat, 18 Apr 2020 15:10:24 +0100 Subject: [PATCH 05/21] Update SparkFun_Ublox_Arduino_Library.cpp --- src/SparkFun_Ublox_Arduino_Library.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index 0a9d1f9..9b3a285 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -611,7 +611,7 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t currentSentence = NONE; //We're done! Reset the sentence to being looking for a new start char //Validate this sentence - if (incomingUBX->checksumA == rollingChecksumA && incomingUBX->checksumB == rollingChecksumB) + if ((incomingUBX->checksumA == rollingChecksumA) && (incomingUBX->checksumB == rollingChecksumB)) { incomingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_VALID; From 98d9edf45ef9042ac7af0903452436aa4d147205 Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Sat, 18 Apr 2020 16:57:55 +0100 Subject: [PATCH 06/21] Update SparkFun_Ublox_Arduino_Library.cpp --- src/SparkFun_Ublox_Arduino_Library.cpp | 54 +++++++++++++++++++------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index ae6bbb7..13ae553 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -430,7 +430,7 @@ boolean SFE_UBLOX_GPS::checkUbloxSerial(ubxPacket *incomingUBX, uint8_t requeste //Take a given byte and file it into the proper array void SFE_UBLOX_GPS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) { - if (currentSentence == NONE || currentSentence == NMEA) + if ((currentSentence == NONE) || (currentSentence == NMEA)) { if (incoming == 0xB5) //UBX binary frames start with 0xB5, aka μ { @@ -462,9 +462,9 @@ void SFE_UBLOX_GPS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t re if (currentSentence == UBX) { //Decide what type of response this is - if (ubxFrameCounter == 0 && incoming != 0xB5) //ISO 'μ' + if ((ubxFrameCounter == 0) && (incoming != 0xB5)) //ISO 'μ' currentSentence = NONE; //Something went wrong. Reset. - else if (ubxFrameCounter == 1 && incoming != 0x62) //ASCII 'b' + else if ((ubxFrameCounter == 1) && (incoming != 0x62)) //ASCII 'b' currentSentence = NONE; //Something went wrong. Reset. else if (ubxFrameCounter == 2) //Class { @@ -587,18 +587,54 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t if (incomingUBX->counter == 0) { incomingUBX->cls = incoming; + if (_printDebug == true) + { + _debugSerial->print(F("processUBX: Class : 0x")); + _debugSerial->print(incomingUBX->cls, HEX); + _debugSerial->print(F(" CSUMA: 0x")); + _debugSerial->print(rollingChecksumA, HEX); + _debugSerial->print(F(" CSUMB: 0x")); + _debugSerial->println(rollingChecksumB, HEX); + } } else if (incomingUBX->counter == 1) { incomingUBX->id = incoming; + if (_printDebug == true) + { + _debugSerial->print(F("processUBX: ID : 0x")); + _debugSerial->print(incomingUBX->id, HEX); + _debugSerial->print(F(" CSUMA: 0x")); + _debugSerial->print(rollingChecksumA, HEX); + _debugSerial->print(F(" CSUMB: 0x")); + _debugSerial->println(rollingChecksumB, HEX); + } } else if (incomingUBX->counter == 2) //Len LSB { incomingUBX->len = incoming; + if (_printDebug == true) + { + _debugSerial->print(F("processUBX: LEN_LSB: 0x")); + _debugSerial->print(incomingUBX->len, HEX); + _debugSerial->print(F(" CSUMA: 0x")); + _debugSerial->print(rollingChecksumA, HEX); + _debugSerial->print(F(" CSUMB: 0x")); + _debugSerial->println(rollingChecksumB, HEX); + } } else if (incomingUBX->counter == 3) //Len MSB { incomingUBX->len |= incoming << 8; + if (_printDebug == true) + { + _debugSerial->print(F("processUBX: LEN_MSB: 0x")); + _debugSerial->print(incoming, HEX); + _debugSerial->print(F(" CSUMA: 0x")); + _debugSerial->print(rollingChecksumA, HEX); + _debugSerial->print(F(" CSUMB: 0x")); + _debugSerial->println(rollingChecksumB, HEX); + } } else if (incomingUBX->counter == incomingUBX->len + 4) //ChecksumA { @@ -651,31 +687,19 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t if (incomingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_VALID) { - if (_printDebug == true) - { _debugSerial->println(F("packetCfg now valid")); - } } if (packetAck.valid == SFE_UBLOX_PACKET_VALIDITY_VALID) { - if (_printDebug == true) - { _debugSerial->println(F("packetAck now valid")); - } } if (incomingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) { - if (_printDebug == true) - { _debugSerial->println(F("packetCfg classAndIDmatch")); - } } if (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) { - if (_printDebug == true) - { _debugSerial->println(F("packetAck classAndIDmatch")); - } } } From 46cd041b3c80d4e966e8353a5f60621050e4bec6 Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Sat, 18 Apr 2020 17:00:33 +0100 Subject: [PATCH 07/21] Update SparkFun_Ublox_Arduino_Library.cpp --- src/SparkFun_Ublox_Arduino_Library.cpp | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index 3d30618..3526ca3 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -587,18 +587,54 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t if (incomingUBX->counter == 0) { incomingUBX->cls = incoming; + if (_printDebug == true) + { + _debugSerial->print(F("processUBX: Class : 0x")); + _debugSerial->print(incomingUBX->cls, HEX); + _debugSerial->print(F(" CSUMA: 0x")); + _debugSerial->print(rollingChecksumA, HEX); + _debugSerial->print(F(" CSUMB: 0x")); + _debugSerial->println(rollingChecksumB, HEX); + } } else if (incomingUBX->counter == 1) { incomingUBX->id = incoming; + if (_printDebug == true) + { + _debugSerial->print(F("processUBX: ID : 0x")); + _debugSerial->print(incomingUBX->id, HEX); + _debugSerial->print(F(" CSUMA: 0x")); + _debugSerial->print(rollingChecksumA, HEX); + _debugSerial->print(F(" CSUMB: 0x")); + _debugSerial->println(rollingChecksumB, HEX); + } } else if (incomingUBX->counter == 2) //Len LSB { incomingUBX->len = incoming; + if (_printDebug == true) + { + _debugSerial->print(F("processUBX: LEN_LSB: 0x")); + _debugSerial->print(incomingUBX->len, HEX); + _debugSerial->print(F(" CSUMA: 0x")); + _debugSerial->print(rollingChecksumA, HEX); + _debugSerial->print(F(" CSUMB: 0x")); + _debugSerial->println(rollingChecksumB, HEX); + } } else if (incomingUBX->counter == 3) //Len MSB { incomingUBX->len |= incoming << 8; + if (_printDebug == true) + { + _debugSerial->print(F("processUBX: LEN_MSB: 0x")); + _debugSerial->print(incoming, HEX); + _debugSerial->print(F(" CSUMA: 0x")); + _debugSerial->print(rollingChecksumA, HEX); + _debugSerial->print(F(" CSUMB: 0x")); + _debugSerial->println(rollingChecksumB, HEX); + } } else if (incomingUBX->counter == incomingUBX->len + 4) //ChecksumA { From 3a694516dc1d16ac4a06ea1e258ba047aec3fc6a Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Sat, 18 Apr 2020 17:25:10 +0100 Subject: [PATCH 08/21] Update SparkFun_Ublox_Arduino_Library.cpp --- src/SparkFun_Ublox_Arduino_Library.cpp | 79 +++++++++++++------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index 3526ca3..add5153 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -437,10 +437,6 @@ void SFE_UBLOX_GPS::process(uint8_t incoming, uint8_t requestedClass, uint8_t re //This is the start of a binary sentence. Reset flags. //We still don't know the response class ubxFrameCounter = 0; - - rollingChecksumA = 0; //Reset our rolling checksums - rollingChecksumB = 0; - currentSentence = UBX; } else if (incoming == '$') @@ -468,6 +464,9 @@ void SFE_UBLOX_GPS::process(uint8_t incoming, uint8_t requestedClass, uint8_t re currentSentence = NONE; //Something went wrong. Reset. else if (ubxFrameCounter == 2) //Class { + //Reset our rolling checksums here (not when we receive the 0xB5) + rollingChecksumA = 0; + rollingChecksumB = 0; //We can now identify the type of response if (incoming == UBX_CLASS_ACK) { @@ -587,54 +586,54 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t if (incomingUBX->counter == 0) { incomingUBX->cls = incoming; - if (_printDebug == true) - { - _debugSerial->print(F("processUBX: Class : 0x")); - _debugSerial->print(incomingUBX->cls, HEX); - _debugSerial->print(F(" CSUMA: 0x")); - _debugSerial->print(rollingChecksumA, HEX); - _debugSerial->print(F(" CSUMB: 0x")); - _debugSerial->println(rollingChecksumB, HEX); - } + // if (_printDebug == true) + // { + // _debugSerial->print(F("processUBX: Class : 0x")); + // _debugSerial->print(incomingUBX->cls, HEX); + // _debugSerial->print(F(" CSUMA: 0x")); + // _debugSerial->print(rollingChecksumA, HEX); + // _debugSerial->print(F(" CSUMB: 0x")); + // _debugSerial->println(rollingChecksumB, HEX); + // } } else if (incomingUBX->counter == 1) { incomingUBX->id = incoming; - if (_printDebug == true) - { - _debugSerial->print(F("processUBX: ID : 0x")); - _debugSerial->print(incomingUBX->id, HEX); - _debugSerial->print(F(" CSUMA: 0x")); - _debugSerial->print(rollingChecksumA, HEX); - _debugSerial->print(F(" CSUMB: 0x")); - _debugSerial->println(rollingChecksumB, HEX); - } + // if (_printDebug == true) + // { + // _debugSerial->print(F("processUBX: ID : 0x")); + // _debugSerial->print(incomingUBX->id, HEX); + // _debugSerial->print(F(" CSUMA: 0x")); + // _debugSerial->print(rollingChecksumA, HEX); + // _debugSerial->print(F(" CSUMB: 0x")); + // _debugSerial->println(rollingChecksumB, HEX); + // } } else if (incomingUBX->counter == 2) //Len LSB { incomingUBX->len = incoming; - if (_printDebug == true) - { - _debugSerial->print(F("processUBX: LEN_LSB: 0x")); - _debugSerial->print(incomingUBX->len, HEX); - _debugSerial->print(F(" CSUMA: 0x")); - _debugSerial->print(rollingChecksumA, HEX); - _debugSerial->print(F(" CSUMB: 0x")); - _debugSerial->println(rollingChecksumB, HEX); - } + // if (_printDebug == true) + // { + // _debugSerial->print(F("processUBX: LEN_LSB: 0x")); + // _debugSerial->print(incomingUBX->len, HEX); + // _debugSerial->print(F(" CSUMA: 0x")); + // _debugSerial->print(rollingChecksumA, HEX); + // _debugSerial->print(F(" CSUMB: 0x")); + // _debugSerial->println(rollingChecksumB, HEX); + // } } else if (incomingUBX->counter == 3) //Len MSB { incomingUBX->len |= incoming << 8; - if (_printDebug == true) - { - _debugSerial->print(F("processUBX: LEN_MSB: 0x")); - _debugSerial->print(incoming, HEX); - _debugSerial->print(F(" CSUMA: 0x")); - _debugSerial->print(rollingChecksumA, HEX); - _debugSerial->print(F(" CSUMB: 0x")); - _debugSerial->println(rollingChecksumB, HEX); - } + // if (_printDebug == true) + // { + // _debugSerial->print(F("processUBX: LEN_MSB: 0x")); + // _debugSerial->print(incoming, HEX); + // _debugSerial->print(F(" CSUMA: 0x")); + // _debugSerial->print(rollingChecksumA, HEX); + // _debugSerial->print(F(" CSUMB: 0x")); + // _debugSerial->println(rollingChecksumB, HEX); + // } } else if (incomingUBX->counter == incomingUBX->len + 4) //ChecksumA { From 12b48f9f0353b917a9e1537cc1107fb38111603c Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Sat, 18 Apr 2020 19:59:44 +0100 Subject: [PATCH 09/21] Added Example20_SendCustomCommand --- .../Example20_SendCustomCommand.ino | 170 ++++++++++++++++++ keywords.txt | 1 + src/SparkFun_Ublox_Arduino_Library.cpp | 54 +++++- src/SparkFun_Ublox_Arduino_Library.h | 3 +- 4 files changed, 226 insertions(+), 2 deletions(-) create mode 100644 examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino diff --git a/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino b/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino new file mode 100644 index 0000000..dee620c --- /dev/null +++ b/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino @@ -0,0 +1,170 @@ +/* + sendCustomCommand + By: Paul Clark (PaulZC) + Date: April 18th, 2020 + + License: MIT. See license file for more information but you can + basically do whatever you want with this code. + + This example shows how you can create and send a custom UBX packet + using the SparkFun u-blox library. + + Previously it was possible to create and send a custom packet + through the library but it would always appear to timeout as + some of the internal functions referred to the internal private + struct packetCfg. + The most recent version of the library allows sendCustomCommand to + use a custom packet as if it were packetCfg and so: + - sendCustomCommand will return a sfe_ublox_status_e enum as if + sendCommand had been called from within the library + - the custom packet will be updated with data returned by the module + (previously this was not possible) + + 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 + SAM-M8Q: https://www.sparkfun.com/products/15106 + + 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 "SparkFun_Ublox_Arduino_Library.h" //http://librarymanager/All#SparkFun_Ublox_GPS +SFE_UBLOX_GPS myGPS; + +long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to Ublox module. + +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 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) + ; + } + + myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise) + + // Let's configure the module's dynamic platform model as if we were using setDynamicModel + // Possible values are: + // 0 (PORTABLE), 2 (STATIONARY), 3 (PEDESTRIAN), 4 (AUTOMOTIVE), 5 (SEA), + // 6 (AIRBORNE1g), 7 (AIRBORNE2g), 8 (AIRBORNE4g), 9 (WRIST), 10 (BIKE) + + // Let's create our custom packet + uint8_t customPayload[MAX_PAYLOAD_SIZE]; // This array holds the payload data bytes + // The next line creates and initialises the packet information which wraps around the payload + ubxPacket customCfg = {0, 0, 0, 0, 0, customPayload, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; + + // The structure of ubxPacket is: + // uint8_t cls : The message Class + // uint8_t id : The message ID + // uint16_t len : Length of the payload. Does not include cls, id, or checksum bytes + // uint16_t counter : Keeps track of number of overall bytes received. Some responses are larger than 255 bytes. + // uint16_t startingSpot : The counter value needed to go past before we begin recording into payload array + // uint8_t *payload : The payload + // uint8_t checksumA : Given to us by the module. Checked against the rolling calculated A/B checksums. + // uint8_t checksumB + // sfe_ublox_packet_validity_e valid : Goes from NOT_DEFINED to VALID or NOT_VALID when checksum is checked + // sfe_ublox_packet_validity_e classAndIDmatch : Goes from NOT_DEFINED to VALID or NOT_VALID when the Class and ID match the requestedClass and requestedID + + // sendCustomCommand will return: + // SFE_UBLOX_STATUS_DATA_RECEIVED if the data we requested was read / polled successfully + // SFE_UBLOX_STATUS_DATA_SENT if the data we sent was writted successfully (ACK'd) + // Other values indicate errors. Please see the sfe_ublox_status_e enum for further details. + + // Referring to the u-blox M8 Receiver Description and Protocol Specification we see that + // the dynamic model is configured using the UBX-CFG-NAV5 message. So let's load our + // custom packet with the correct information so we can read (poll) the current settings. + + customCfg.cls = UBX_CLASS_CFG; // This is the message Class + customCfg.id = UBX_CFG_NAV5; // This is the message ID + customCfg.len = 0; // Setting the len (length) to zero let's us poll the current settings + customCfg.startingSpot = 0; // Always set the startingSpot to zero (unless you really know what you are doing) + + // We also need to tell sendCustomCommand how long it should wait for a reply + uint16_t maxWait = 250; // Wait for up to 250ms (Serial may need longer) + + // Now let's read the current navigation model settings. The results will be loaded into customCfg. + if (myGPS.sendCustomCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK + { + Serial.println(F("sendCustomCommand (poll) failed! Freezing.")); + while (1) + ; + } + + // Referring to the message definition for UBX-CFG-NAV5 we see that we need to change + // byte 2 to update the dynamic platform model. + + // Print the current dynamic model + Serial.print(F("The current dynamic model is: ")); + Serial.print(customPayload[2]); + + // Let's change it + if (customPayload[2] != 0x04) // If it is current not 4, change it to 4 + { + Serial.println(F(". Changing it to 4.")); + customPayload[2] = 0x04; + } + else // If it is already 4, change it to 2 + { + Serial.println(F(". Changing it to 2.")); + customPayload[2] = 0x02; + } + + // We don't need to update customCfg.len as it will have been set to 36 (0x24) + // when sendCustomCommand read the data + + // Now we write the custom packet back again to change the setting + if (myGPS.sendCustomCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) // This time we are only expecting an ACK + { + Serial.println(F("sendCustomCommand (set) failed! Freezing.")); + while (1) + ; + } + else + { + Serial.println(F("Dynamic platform model updated.")); + } + + //myGPS.saveConfigSelective(VAL_CFG_SUBSEC_NAVCONF); //Uncomment this line to save only the NAV settings to flash and BBR +} + +void loop() +{ + //Query module only every second. Doing it more often will just cause I2C traffic. + //The module only responds when a new position is available + if (millis() - lastTime > 1000) + { + lastTime = millis(); //Update the timer + + long latitude = myGPS.getLatitude(); + Serial.print(F("Lat: ")); + Serial.print(latitude); + + long longitude = myGPS.getLongitude(); + Serial.print(F(" Long: ")); + Serial.print(longitude); + Serial.print(F(" (degrees * 10^-7)")); + + long altitude = myGPS.getAltitude(); + Serial.print(F(" Alt: ")); + Serial.print(altitude); + Serial.print(F(" (mm)")); + + Serial.println(); + } +} diff --git a/keywords.txt b/keywords.txt index 3bdbcf1..e56f27d 100644 --- a/keywords.txt +++ b/keywords.txt @@ -27,6 +27,7 @@ processNMEA KEYWORD2 calcChecksum KEYWORD2 sendCommand KEYWORD2 +sendCustomCommand KEYWORD2 printPacket KEYWORD2 setI2CAddress KEYWORD2 setSerialRate KEYWORD2 diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index 41f9197..fc11b33 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -712,7 +712,6 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t // This is potentially risky as we are saying that we saw the requested Class and ID // but that the packet checksum failed. Potentially it could be the class or ID bytes // that caused the checksum error! - if ((incomingUBX->cls == requestedClass) && (incomingUBX->id == requestedID)) { incomingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_VALID; // If we have a match, set the classAndIDmatch flag to not valid @@ -950,6 +949,59 @@ sfe_ublox_status_e SFE_UBLOX_GPS::sendCommand(ubxPacket outgoingUBX, uint16_t ma return retVal; } +//Given a custom packet and payload, send everything including CRC bytes via I2C port +sfe_ublox_status_e SFE_UBLOX_GPS::sendCustomCommand(ubxPacket *outgoingUBX, uint16_t maxWait) +{ + sfe_ublox_status_e retVal = SFE_UBLOX_STATUS_SUCCESS; + + calcChecksum(outgoingUBX); //Sets checksum A and B bytes of the packet + + if (_printDebug == true) + { + _debugSerial->print(F("\nSending: ")); + printPacket(outgoingUBX); + } + + if (commType == COMM_TYPE_I2C) + { + retVal = sendI2cCommand(*outgoingUBX, maxWait); + if (retVal != SFE_UBLOX_STATUS_SUCCESS) + { + if (_printDebug == true) + { + _debugSerial->println(F("Send I2C Command failed")); + } + return retVal; + } + } + else if (commType == COMM_TYPE_SERIAL) + { + sendSerialCommand(*outgoingUBX); + } + + if (maxWait > 0) + { + //Depending on what we just sent, either we need to look for an ACK or not + if (outgoingUBX->cls == UBX_CLASS_CFG) + { + if (_printDebug == true) + { + _debugSerial->println(F("sendCommand: Waiting for ACK response")); + } + retVal = waitForACKResponse(outgoingUBX, outgoingUBX->cls, outgoingUBX->id, maxWait); //Wait for Ack response + } + else + { + if (_printDebug == true) + { + _debugSerial->println(F("sendCommand: Waiting for No ACK response")); + } + retVal = waitForNoACKResponse(outgoingUBX, outgoingUBX->cls, outgoingUBX->id, maxWait); //Wait for Ack response + } + } + return retVal; +} + //Returns false if sensor fails to respond to I2C traffic sfe_ublox_status_e SFE_UBLOX_GPS::sendI2cCommand(ubxPacket outgoingUBX, uint16_t maxWait) { diff --git a/src/SparkFun_Ublox_Arduino_Library.h b/src/SparkFun_Ublox_Arduino_Library.h index 8e63d32..22d646c 100644 --- a/src/SparkFun_Ublox_Arduino_Library.h +++ b/src/SparkFun_Ublox_Arduino_Library.h @@ -409,7 +409,7 @@ typedef struct uint8_t checksumA; //Given to us from module. Checked against the rolling calculated A/B checksums. uint8_t checksumB; sfe_ublox_packet_validity_e valid; //Goes from NOT_DEFINED to VALID or NOT_VALID when checksum is checked - sfe_ublox_packet_validity_e classAndIDmatch; // Goes from flase to true when the Class and ID match the requestedClass and requestedID + sfe_ublox_packet_validity_e classAndIDmatch; // Goes from NOT_DEFINED to VALID or NOT_VALID when the Class and ID match the requestedClass and requestedID } ubxPacket; // Struct to hold the results returned by getGeofenceState (returned by UBX-NAV-GEOFENCE) @@ -463,6 +463,7 @@ class SFE_UBLOX_GPS void calcChecksum(ubxPacket *msg); //Sets the checksumA and checksumB of a given messages sfe_ublox_status_e sendCommand(ubxPacket outgoingUBX, uint16_t maxWait = defaultMaxWait); //Given a packet and payload, send everything including CRC bytes, return true if we got a response + sfe_ublox_status_e sendCustomCommand(ubxPacket *outgoingUBX, uint16_t maxWait = defaultMaxWait); //This allows custom packets to be used sfe_ublox_status_e sendI2cCommand(ubxPacket outgoingUBX, uint16_t maxWait = 250); void sendSerialCommand(ubxPacket outgoingUBX); From 927b9cb4562f674a038d1b5bcd89707d3d5bc38f Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Sun, 19 Apr 2020 11:31:55 +0100 Subject: [PATCH 10/21] Added NOTACKNOWLEDGED --- .../Example20_SendCustomCommand.ino | 22 +- src/SparkFun_Ublox_Arduino_Library.cpp | 208 ++++++++++++------ src/SparkFun_Ublox_Arduino_Library.h | 10 +- 3 files changed, 161 insertions(+), 79 deletions(-) diff --git a/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino b/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino index dee620c..bf50c4b 100644 --- a/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino +++ b/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino @@ -2,7 +2,7 @@ sendCustomCommand By: Paul Clark (PaulZC) Date: April 18th, 2020 - + License: MIT. See license file for more information but you can basically do whatever you want with this code. @@ -61,7 +61,7 @@ void setup() // Let's configure the module's dynamic platform model as if we were using setDynamicModel // Possible values are: - // 0 (PORTABLE), 2 (STATIONARY), 3 (PEDESTRIAN), 4 (AUTOMOTIVE), 5 (SEA), + // 0 (PORTABLE), 2 (STATIONARY), 3 (PEDESTRIAN), 4 (AUTOMOTIVE), 5 (SEA), // 6 (AIRBORNE1g), 7 (AIRBORNE2g), 8 (AIRBORNE4g), 9 (WRIST), 10 (BIKE) // Let's create our custom packet @@ -85,6 +85,7 @@ void setup() // SFE_UBLOX_STATUS_DATA_RECEIVED if the data we requested was read / polled successfully // SFE_UBLOX_STATUS_DATA_SENT if the data we sent was writted successfully (ACK'd) // Other values indicate errors. Please see the sfe_ublox_status_e enum for further details. + // If you see a failure you can of course simply try sending the same command again. // Referring to the u-blox M8 Receiver Description and Protocol Specification we see that // the dynamic model is configured using the UBX-CFG-NAV5 message. So let's load our @@ -101,9 +102,18 @@ void setup() // Now let's read the current navigation model settings. The results will be loaded into customCfg. if (myGPS.sendCustomCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK { - Serial.println(F("sendCustomCommand (poll) failed! Freezing.")); - while (1) - ; + Serial.println(F("sendCustomCommand (poll) failed! Trying again...")); + // We need to reset the packet before we try again as the values could have changed + customCfg.cls = UBX_CLASS_CFG; + customCfg.id = UBX_CFG_NAV5; + customCfg.len = 0; + customCfg.startingSpot = 0; + if (myGPS.sendCustomCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK + { + Serial.println(F("sendCustomCommand (poll) failed again! Freezing.")); + while (1) + ; + } } // Referring to the message definition for UBX-CFG-NAV5 we see that we need to change @@ -133,7 +143,7 @@ void setup() { Serial.println(F("sendCustomCommand (set) failed! Freezing.")); while (1) - ; + ; } else { diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index fc11b33..7160005 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -574,7 +574,7 @@ void SFE_UBLOX_GPS::processRTCM(uint8_t incoming) //Given a character, file it away into the uxb packet structure //Set valid to VALID or NOT_VALID once sentence is completely received and passes or fails CRC //The payload portion of the packet can be 100s of bytes but the max array -//size is roughly 64 bytes. startingSpot can be set so we only record +//size is MAX_PAYLOAD_SIZE bytes. startingSpot can be set so we only record //a subset of bytes within a larger packet. void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) { @@ -651,6 +651,7 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t incomingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_VALID; // Let's check if the class and ID match the requestedClass and requestedID + // Remember - this could be a data packet or an ACK packet if ((incomingUBX->cls == requestedClass) && (incomingUBX->id == requestedID)) { incomingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_VALID; // If we have a match, set the classAndIDmatch flag to valid @@ -667,7 +668,7 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t else if ((incomingUBX->cls == UBX_CLASS_ACK) && (incomingUBX->id == UBX_ACK_NACK) && (incomingUBX->payload[0] == requestedClass) && (incomingUBX->payload[1] == requestedID)) { - incomingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_VALID; // If we have a match, set the classAndIDmatch flag to NOT_VALID + incomingUBX->classAndIDmatch = SFE_UBLOX_PACKET_NOTACKNOWLEDGED; // If we have a match, set the classAndIDmatch flag to NOTACKNOWLEDGED if (_printDebug == true) { _debugSerial->print(F("processUBX: NACK received: Requested Class: ")); @@ -1201,11 +1202,19 @@ void SFE_UBLOX_GPS::printPacket(ubxPacket *packet) //If we are going to set the value for a setting, then packetCfg.len will be at least 3 when the packetCfg is _sent_. //(UBX-CFG-MSG appears to have the shortest set length of 3 bytes) +//We need to think carefully about how interleaved PVT packets affect things. +//It is entirely possible that our packetCfg and packetAck were received successfully +//but while we are still in the "if (checkUblox() == true)" loop a PVT packet is processed +//or _starts_ to arrive (remember that Serial data can arrive very slowly). + //Returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got an ACK and a valid packetCfg (module is responding with register content) //Returns SFE_UBLOX_STATUS_DATA_SENT if we got an ACK and no packetCfg (no valid packetCfg needed, module absorbs new register data) -//Returns SFE_UBLOX_STATUS_FAIL if we got an invalid packetCfg (checksum failure) -//Returns SFE_UBLOX_STATUS_COMMAND_UNKNOWN if we got a NACK (command unknown) +//Returns SFE_UBLOX_STATUS_FAIL if something very bad happens (e.g. a double checksum failure) +//Returns SFE_UBLOX_STATUS_COMMAND_UNKNOWN if the packet was not-acknowledged (NACK) +//Returns SFE_UBLOX_STATUS_CRC_FAIL if we had a checksum failure //Returns SFE_UBLOX_STATUS_TIMEOUT if we timed out +//Returns SFE_UBLOX_STATUS_DATA_OVERWRITTEN if we got an ACK and a valid packetCfg but that the packetCfg has been +// or is currently being overwritten (remember that Serial data can arrive very slowly) sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime) { outgoingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; //This will go VALID (or NOT_VALID) when we receive a response to the packet we sent @@ -1218,9 +1227,14 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uin { if (checkUblox(outgoingUBX, requestedClass, requestedID) == true) //See if new data is available. Process bytes as they come in. { - // If both the outgoingUBX->classAndIDmatch and packetAck.classAndIDmatch are VALID then we are all done + // If both the outgoingUBX->classAndIDmatch and packetAck.classAndIDmatch are VALID + // and outgoingUBX->valid is _still_ VALID and the class and ID _still_ match + // then we can be confident that the data in outgoingUBX is valid if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) - && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID)) + && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) + && (outgoingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_VALID) + && (outgoingUBX->class == requestedClass) + && (outgoingUBX->id == requestedID)) { if (_printDebug == true) { @@ -1231,26 +1245,83 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uin return (SFE_UBLOX_STATUS_DATA_RECEIVED); //We received valid data and a correct ACK! } - // If the outgoingUBX->classAndIDmatch is NOT_VALID but the packetAck.classAndIDmatch is VALID - // then we could take a gamble and return DATA_RECEIVED, but it is safer to return - // FAIL instead - else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) + // We can be confident that the data packet (if we are going to get one) will always arrive + // before the matching ACK. So if we accidentally sent a config packet which only produces an ACK + // then outgoingUBX->classAndIDmatch will be NOT_DEFINED and the packetAck.classAndIDmatch will VALID. + // We should not check outgoingUBX->valid, outgoingUBX->class or outgoingUBX->id + // as these may have been changed by a PVT packet. + else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED) && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID)) { if (_printDebug == true) { - _debugSerial->print(F("waitForACKResponse: INVALID data and VALID ACK received after ")); + _debugSerial->print(F("waitForACKResponse: NO DATA and VALID ACK after ")); + _debugSerial->print(millis() - startTime); + _debugSerial->println(F(" msec")); + } + return (SFE_UBLOX_STATUS_DATA_SENT); //We got an ACK but no data... + } + + // If both the outgoingUBX->classAndIDmatch and packetAck.classAndIDmatch are VALID + // but the outgoingUBX->class or ID no longer match then we can be confident that we had + // valid data but it has been or is currently being overwritten by another packet (e.g. PVT). + // If (e.g.) a PVT packet is _being_ received: outgoingUBX->valid will be NOT_DEFINED + // 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. + else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) + && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) + && !((outgoingUBX->class != requestedClass) + || (outgoingUBX->id != requestedID))) + { + if (_printDebug == true) + { + _debugSerial->print(F("waitForACKResponse: data being OVERWRITTEN after ")); + _debugSerial->print(millis() - startTime); + _debugSerial->println(F(" msec")); + } + return (SFE_UBLOX_STATUS_DATA_OVERWRITTEN); // Data was valid but has been or is being overwritten + } + + // If packetAck.classAndIDmatch is VALID but both outgoingUBX->valid and outgoingUBX->classAndIDmatch + // are NOT_VALID then we can be confident we have had a checksum failure on the data packet + else if ((packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) + && (outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) + && (outgoingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID)) + { + if (_printDebug == true) + { + _debugSerial->print(F("waitForACKResponse: CRC failed after ")); _debugSerial->print(millis() - startTime); _debugSerial->println(F(" msec")); } - return (SFE_UBLOX_STATUS_FAIL); //We received valid data and a correct ACK! + return (SFE_UBLOX_STATUS_CRC_FAIL); //Checksum fail + } + + // If our packet was not-acknowledged (NACK) we do not receive a data packet - we only get the NACK. + // So you would expect outgoingUBX->valid and outgoingUBX->classAndIDmatch to still be NOT_DEFINED + // But if a full PVT packet arrives afterwards outgoingUBX->valid could be VALID (or just possibly NOT_VALID) + // but outgoingUBX->class and outgoingUBX->id would not match... + // So I think this is telling us we need a special state for packetAck.classAndIDmatch to tell us + // the packet was definitely NACK'd otherwise we are possibly just guessing... + else if (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_NOTACKNOWLEDGED) + { + if (_printDebug == true) + { + _debugSerial->print(F("waitForACKResponse: data was NOTACKNOWLEDGED (NACK) after ")); + _debugSerial->print(millis() - startTime); + _debugSerial->println(F(" msec")); + } + return (SFE_UBLOX_STATUS_COMMAND_UNKNOWN); //We received a NACK! } // If the outgoingUBX->classAndIDmatch is VALID but the packetAck.classAndIDmatch is NOT_VALID - // then we will take a gamble and return DATA_RECEIVED. If we were playing safe, we should - // return FAIL instead + // then the ack probably had a checksum error. We will take a gamble and return DATA_RECEIVED. + // If we were playing safe, we should return FAIL instead else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) - && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID)) + && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) + && (outgoingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_VALID) + && (outgoingUBX->class == requestedClass) + && (outgoingUBX->id == requestedID)) { if (_printDebug == true) { @@ -1262,7 +1333,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uin } // If the outgoingUBX->classAndIDmatch is NOT_VALID and the packetAck.classAndIDmatch is NOT_VALID - // then we return a FAIL + // then we return a FAIL. This must be a double checksum failure? else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID)) { @@ -1276,7 +1347,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uin } // If the outgoingUBX->classAndIDmatch is VALID and the packetAck.classAndIDmatch is NOT_DEFINED - // then we keep waiting for an ACK + // then the ACK has not yet been received and we should keep waiting for it else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED)) { @@ -1284,22 +1355,8 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uin { _debugSerial->print(F("waitForACKResponse: valid data after ")); _debugSerial->print(millis() - startTime); - _debugSerial->println(F(" msec")); - } - } - - // If the outgoingUBX->classAndIDmatch is NOT_DEFINED and the packetAck.classAndIDmatch is VALID - // then we return DATA_SENT. - else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED) - && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID)) - { - if (_printDebug == true) - { - _debugSerial->print(F("waitForACKResponse: VALID data after ")); - _debugSerial->print(millis() - startTime); - _debugSerial->println(F(" msec")); + _debugSerial->println(F(" msec. Waiting for ACK.")); } - return (SFE_UBLOX_STATUS_DATA_SENT); //We got an ACK but no data... } } //checkUblox == true @@ -1311,7 +1368,10 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uin // If the outgoingUBX->classAndIDmatch is VALID then we can take a gamble and return DATA_RECEIVED // even though we did not get an ACK if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) - && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED)) + && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED) + && (outgoingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_VALID) + && (outgoingUBX->class == requestedClass) + && (outgoingUBX->id == requestedID)) { if (_printDebug == true) { @@ -1336,14 +1396,14 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uin //Returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got a config packet full of response data that has CLS/ID match to our query packet //Returns SFE_UBLOX_STATUS_CRC_FAIL if we got a corrupt config packet that has CLS/ID match to our query packet //Returns SFE_UBLOX_STATUS_TIMEOUT if we timed out +//Returns SFE_UBLOX_STATUS_DATA_OVERWRITTEN if we got an a valid packetCfg but that the packetCfg has been +// or is currently being overwritten (remember that Serial data can arrive very slowly) sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(ubxPacket *outgoingUBX, uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime) { outgoingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; //This will go VALID (or NOT_VALID) when we receive a response to the packet we sent packetAck.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; outgoingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; // This will go VALID (or NOT_VALID) when we receive a packet that matches the requested class and ID packetAck.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - outgoingUBX->cls = 255; // Use the packet class and id to indicate if an unexpected packet has been received - outgoingUBX->id = 255; unsigned long startTime = millis(); while (millis() - startTime < maxTime) @@ -1351,60 +1411,68 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(ubxPacket *outgoingUBX, u if (checkUblox(outgoingUBX, requestedClass, requestedID) == true) //See if new data is available. Process bytes as they come in. { - // If the outgoingUBX->classAndIDmatch is VALID then we are all done - if (outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) + // If outgoingUBX->classAndIDmatch is VALID + // and outgoingUBX->valid is _still_ VALID and the class and ID _still_ match + // then we can be confident that the data in outgoingUBX is valid + if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) + && (outgoingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_VALID) + && (outgoingUBX->class == requestedClass) + && (outgoingUBX->id == requestedID)) { if (_printDebug == true) { - _debugSerial->print(F("waitForNoACKResponse: CLS/ID match after ")); + _debugSerial->print(F("waitForNoACKResponse: valid data with CLS/ID match after ")); _debugSerial->print(millis() - startTime); _debugSerial->println(F(" msec")); } - return (SFE_UBLOX_STATUS_DATA_RECEIVED); //We received valid data and a correct ACK! + return (SFE_UBLOX_STATUS_DATA_RECEIVED); //We received valid data! } - // If the outgoingUBX->classAndIDmatch is NOT_VALID then we return CRC failure - else if (outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) + // If the outgoingUBX->classAndIDmatch is VALID + // but the outgoingUBX->class or ID no longer match then we can be confident that we had + // valid data but it has been or is currently being overwritten by another packet (e.g. PVT). + // If (e.g.) a PVT packet is _being_ received: outgoingUBX->valid will be NOT_DEFINED + // 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. + else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) + && !((outgoingUBX->class != requestedClass) + || (outgoingUBX->id != requestedID))) { - if (outgoingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_VALID) - { - if (_printDebug == true) - { - _debugSerial->print(F("waitForNoACKResponse: CLS/ID match but NACK received after ")); - _debugSerial->print(millis() - startTime); - _debugSerial->println(F(" msec")); - } - return (SFE_UBLOX_STATUS_CRC_FAIL); //We received invalid data - } - else if (outgoingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) + if (_printDebug == true) { - if (_printDebug == true) - { - _debugSerial->print(F("waitForNoACKResponse: CLS/ID match but failed CRC after ")); - _debugSerial->print(millis() - startTime); - _debugSerial->println(F(" msec")); - } - return (SFE_UBLOX_STATUS_CRC_FAIL); //We received invalid data + _debugSerial->print(F("waitForNoACKResponse: data being OVERWRITTEN after ")); + _debugSerial->print(millis() - startTime); + _debugSerial->println(F(" msec")); } + return (SFE_UBLOX_STATUS_DATA_OVERWRITTEN); // Data was valid but has been or is being overwritten } - else if ((outgoingUBX->cls < 255) && (outgoingUBX->id < 255) && (outgoingUBX->valid != SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED)) + // If outgoingUBX->classAndIDmatch is NOT_DEFINED + // 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)) { - //We got a valid or invalid packet but it was not the droid we were looking for - //Reset packet and continue checking incoming data for matching cls/id if (_printDebug == true) { - _debugSerial->print(F("waitForNoACKResponse: CLS/ID mismatch: ")); - _debugSerial->print(F("CLS: ")); - _debugSerial->print(outgoingUBX->cls, HEX); + _debugSerial->print(F("waitForNoACKResponse: valid but UNWANTED data after ")); + _debugSerial->print(millis() - startTime); + _debugSerial->print(F(" msec. Class: ")); + _debugSerial->print(outgoingUBX->class); _debugSerial->print(F(" ID: ")); - _debugSerial->print(outgoingUBX->id, HEX); - _debugSerial->println(); + _debugSerial->print(outgoingUBX->id); } + } - outgoingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; //This will go VALID (or NOT_VALID) when we receive a response to the packet we sent - outgoingUBX->cls = 255; - outgoingUBX->id = 255; + // If the outgoingUBX->classAndIDmatch is NOT_VALID then we return CRC failure + else if (outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) + { + if (_printDebug == true) + { + _debugSerial->print(F("waitForNoACKResponse: CLS/ID match but failed CRC after ")); + _debugSerial->print(millis() - startTime); + _debugSerial->println(F(" msec")); + } + return (SFE_UBLOX_STATUS_CRC_FAIL); //We received invalid data } } diff --git a/src/SparkFun_Ublox_Arduino_Library.h b/src/SparkFun_Ublox_Arduino_Library.h index 22d646c..0fa1cac 100644 --- a/src/SparkFun_Ublox_Arduino_Library.h +++ b/src/SparkFun_Ublox_Arduino_Library.h @@ -99,9 +99,10 @@ typedef enum SFE_UBLOX_STATUS_INVALID_OPERATION, SFE_UBLOX_STATUS_MEM_ERR, SFE_UBLOX_STATUS_HW_ERR, - SFE_UBLOX_STATUS_DATA_SENT, - SFE_UBLOX_STATUS_DATA_RECEIVED, + SFE_UBLOX_STATUS_DATA_SENT, // This indicates that a 'set' was successful + SFE_UBLOX_STATUS_DATA_RECEIVED, // This indicates that a 'get' (poll) was successful SFE_UBLOX_STATUS_I2C_COMM_FAILURE, + SFE_UBLOX_STATUS_DATA_OVERWRITTEN // This is an error - the data was valid but has been or _is being_ overwritten by another packet } sfe_ublox_status_e; // ubxPacket validity @@ -109,7 +110,8 @@ typedef enum { SFE_UBLOX_PACKET_VALIDITY_NOT_VALID, SFE_UBLOX_PACKET_VALIDITY_VALID, - SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED + SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, + SFE_UBLOX_PACKET_NOTACKNOWLEDGED // This indicates that we received a NACK } sfe_ublox_packet_validity_e; //Registers @@ -438,7 +440,9 @@ class SFE_UBLOX_GPS // A default of 250ms for maxWait seems fine for I2C but is not enough for SerialUSB. // If you know you are only going to be using I2C / Qwiic communication, you can // safely reduce defaultMaxWait to 250. + #ifndef defaultMaxWait // Let's allow the user to define their own value if they want to #define defaultMaxWait 1100 + #endif //By default use the default I2C address, and use Wire port boolean begin(TwoWire &wirePort = Wire, uint8_t deviceAddress = 0x42); //Returns true if module is detected From 3154c9597a26bc0f119a100f99923526f263c1bc Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Sun, 19 Apr 2020 12:19:03 +0100 Subject: [PATCH 11/21] Removed typos --- .../Example20_SendCustomCommand.ino | 2 +- src/SparkFun_Ublox_Arduino_Library.cpp | 22 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino b/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino index bf50c4b..35b2130 100644 --- a/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino +++ b/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino @@ -97,7 +97,7 @@ void setup() customCfg.startingSpot = 0; // Always set the startingSpot to zero (unless you really know what you are doing) // We also need to tell sendCustomCommand how long it should wait for a reply - uint16_t maxWait = 250; // Wait for up to 250ms (Serial may need longer) + uint16_t maxWait = 250; // Wait for up to 250ms (Serial may need a lot longer e.g. 1100) // Now let's read the current navigation model settings. The results will be loaded into customCfg. if (myGPS.sendCustomCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index 7160005..856b64b 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -1233,7 +1233,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uin if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) && (outgoingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_VALID) - && (outgoingUBX->class == requestedClass) + && (outgoingUBX->cls == requestedClass) && (outgoingUBX->id == requestedID)) { if (_printDebug == true) @@ -1248,7 +1248,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uin // We can be confident that the data packet (if we are going to get one) will always arrive // before the matching ACK. So if we accidentally sent a config packet which only produces an ACK // then outgoingUBX->classAndIDmatch will be NOT_DEFINED and the packetAck.classAndIDmatch will VALID. - // We should not check outgoingUBX->valid, outgoingUBX->class or outgoingUBX->id + // We should not check outgoingUBX->valid, outgoingUBX->cls or outgoingUBX->id // as these may have been changed by a PVT packet. else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED) && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID)) @@ -1263,14 +1263,14 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uin } // If both the outgoingUBX->classAndIDmatch and packetAck.classAndIDmatch are VALID - // but the outgoingUBX->class or ID no longer match then we can be confident that we had + // but the outgoingUBX->cls or ID no longer match then we can be confident that we had // valid data but it has been or is currently being overwritten by another packet (e.g. PVT). // If (e.g.) a PVT packet is _being_ received: outgoingUBX->valid will be NOT_DEFINED // 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. else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) - && !((outgoingUBX->class != requestedClass) + && !((outgoingUBX->cls != requestedClass) || (outgoingUBX->id != requestedID))) { if (_printDebug == true) @@ -1300,7 +1300,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uin // If our packet was not-acknowledged (NACK) we do not receive a data packet - we only get the NACK. // So you would expect outgoingUBX->valid and outgoingUBX->classAndIDmatch to still be NOT_DEFINED // But if a full PVT packet arrives afterwards outgoingUBX->valid could be VALID (or just possibly NOT_VALID) - // but outgoingUBX->class and outgoingUBX->id would not match... + // but outgoingUBX->cls and outgoingUBX->id would not match... // So I think this is telling us we need a special state for packetAck.classAndIDmatch to tell us // the packet was definitely NACK'd otherwise we are possibly just guessing... else if (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_NOTACKNOWLEDGED) @@ -1320,7 +1320,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uin else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) && (outgoingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_VALID) - && (outgoingUBX->class == requestedClass) + && (outgoingUBX->cls == requestedClass) && (outgoingUBX->id == requestedID)) { if (_printDebug == true) @@ -1370,7 +1370,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uin if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED) && (outgoingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_VALID) - && (outgoingUBX->class == requestedClass) + && (outgoingUBX->cls == requestedClass) && (outgoingUBX->id == requestedID)) { if (_printDebug == true) @@ -1416,7 +1416,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(ubxPacket *outgoingUBX, u // then we can be confident that the data in outgoingUBX is valid if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) && (outgoingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_VALID) - && (outgoingUBX->class == requestedClass) + && (outgoingUBX->cls == requestedClass) && (outgoingUBX->id == requestedID)) { if (_printDebug == true) @@ -1429,13 +1429,13 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(ubxPacket *outgoingUBX, u } // If the outgoingUBX->classAndIDmatch is VALID - // but the outgoingUBX->class or ID no longer match then we can be confident that we had + // but the outgoingUBX->cls or ID no longer match then we can be confident that we had // valid data but it has been or is currently being overwritten by another packet (e.g. PVT). // If (e.g.) a PVT packet is _being_ received: outgoingUBX->valid will be NOT_DEFINED // 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. else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) - && !((outgoingUBX->class != requestedClass) + && !((outgoingUBX->cls != requestedClass) || (outgoingUBX->id != requestedID))) { if (_printDebug == true) @@ -1457,7 +1457,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(ubxPacket *outgoingUBX, u _debugSerial->print(F("waitForNoACKResponse: valid but UNWANTED data after ")); _debugSerial->print(millis() - startTime); _debugSerial->print(F(" msec. Class: ")); - _debugSerial->print(outgoingUBX->class); + _debugSerial->print(outgoingUBX->cls); _debugSerial->print(F(" ID: ")); _debugSerial->print(outgoingUBX->id); } From 8e037a5c524d34b82f4c142f9b3f61bbee707a25 Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Sun, 19 Apr 2020 16:51:47 +0100 Subject: [PATCH 12/21] Added the bug fix for setNavigationFrequency --- .../Example20_SendCustomCommand.ino | 19 +++++++++++++++++++ src/SparkFun_Ublox_Arduino_Library.cpp | 5 +++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino b/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino index 35b2130..82a4f94 100644 --- a/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino +++ b/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino @@ -150,6 +150,25 @@ void setup() Serial.println(F("Dynamic platform model updated.")); } + // Now let's read the navigation model settings again to see if the change was successful. + + // We need to reset the packet before we try again as the values could have changed + customCfg.cls = UBX_CLASS_CFG; + customCfg.id = UBX_CFG_NAV5; + customCfg.len = 0; + customCfg.startingSpot = 0; + + if (myGPS.sendCustomCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK + { + Serial.println(F("sendCustomCommand (poll) failed! Freezing.")); + while (1) + ; + } + + // Print the current dynamic model + Serial.print(F("The new dynamic model is: ")); + Serial.println(customPayload[2]); + //myGPS.saveConfigSelective(VAL_CFG_SUBSEC_NAVCONF); //Uncomment this line to save only the NAV settings to flash and BBR } diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index 856b64b..73a8187 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -1246,7 +1246,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uin } // We can be confident that the data packet (if we are going to get one) will always arrive - // before the matching ACK. So if we accidentally sent a config packet which only produces an ACK + // before the matching ACK. So if we sent a config packet which only produces an ACK // then outgoingUBX->classAndIDmatch will be NOT_DEFINED and the packetAck.classAndIDmatch will VALID. // We should not check outgoingUBX->valid, outgoingUBX->cls or outgoingUBX->id // as these may have been changed by a PVT packet. @@ -1255,7 +1255,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uin { if (_printDebug == true) { - _debugSerial->print(F("waitForACKResponse: NO DATA and VALID ACK after ")); + _debugSerial->print(F("waitForACKResponse: no data and valid ACK after ")); _debugSerial->print(millis() - startTime); _debugSerial->println(F(" msec")); } @@ -2117,6 +2117,7 @@ boolean SFE_UBLOX_GPS::setNavigationFrequency(uint8_t navFreq, uint16_t maxWait) //payloadCfg is now loaded with current bytes. Change only the ones we need to payloadCfg[0] = measurementRate & 0xFF; //measRate LSB payloadCfg[1] = measurementRate >> 8; //measRate MSB + packetCfg.len = 6; // Bug fix! return ((sendCommand(packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } From b22e8121fd6210a9953726916b5edc07ee32dba3 Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Sun, 19 Apr 2020 16:55:28 +0100 Subject: [PATCH 13/21] Added an extra debug print in setNavigationFrequency --- src/SparkFun_Ublox_Arduino_Library.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index 73a8187..f908cd3 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -2112,6 +2112,12 @@ boolean SFE_UBLOX_GPS::setNavigationFrequency(uint8_t navFreq, uint16_t maxWait) if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK return (false); //If command send fails then bail + if (_printDebug == true) + { + _debugSerial->print(F("setNavigationFrequency packetCfg.len is ")); + _debugSerial->println(packetCfg.len); + } + uint16_t measurementRate = 1000 / navFreq; //payloadCfg is now loaded with current bytes. Change only the ones we need to From e0c32306343e88fa1eefe93f741270d7feaad6c3 Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Sun, 19 Apr 2020 18:05:01 +0100 Subject: [PATCH 14/21] Updated so packet pointers are used everywhere from sendCommand down --- .../Example20_SendCustomCommand.ino | 32 ++-- keywords.txt | 1 - src/SparkFun_Ublox_Arduino_Library.cpp | 181 +++++++----------- src/SparkFun_Ublox_Arduino_Library.h | 7 +- 4 files changed, 83 insertions(+), 138 deletions(-) diff --git a/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino b/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino index 82a4f94..f9e9e73 100644 --- a/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino +++ b/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino @@ -1,5 +1,5 @@ /* - sendCustomCommand + Send Custom Command By: Paul Clark (PaulZC) Date: April 18th, 2020 @@ -13,12 +13,12 @@ through the library but it would always appear to timeout as some of the internal functions referred to the internal private struct packetCfg. - The most recent version of the library allows sendCustomCommand to + The most recent version of the library allows sendCommand to use a custom packet as if it were packetCfg and so: - - sendCustomCommand will return a sfe_ublox_status_e enum as if - sendCommand had been called from within the library + - sendCommand will return a sfe_ublox_status_e enum as if + it had been called from within the library - the custom packet will be updated with data returned by the module - (previously this was not possible) + (previously this was not possible from outside the library) Feel like supporting open source hardware? Buy a board from SparkFun! @@ -81,7 +81,7 @@ void setup() // sfe_ublox_packet_validity_e valid : Goes from NOT_DEFINED to VALID or NOT_VALID when checksum is checked // sfe_ublox_packet_validity_e classAndIDmatch : Goes from NOT_DEFINED to VALID or NOT_VALID when the Class and ID match the requestedClass and requestedID - // sendCustomCommand will return: + // sendCommand will return: // SFE_UBLOX_STATUS_DATA_RECEIVED if the data we requested was read / polled successfully // SFE_UBLOX_STATUS_DATA_SENT if the data we sent was writted successfully (ACK'd) // Other values indicate errors. Please see the sfe_ublox_status_e enum for further details. @@ -96,21 +96,21 @@ void setup() customCfg.len = 0; // Setting the len (length) to zero let's us poll the current settings customCfg.startingSpot = 0; // Always set the startingSpot to zero (unless you really know what you are doing) - // We also need to tell sendCustomCommand how long it should wait for a reply + // We also need to tell sendCommand how long it should wait for a reply uint16_t maxWait = 250; // Wait for up to 250ms (Serial may need a lot longer e.g. 1100) // Now let's read the current navigation model settings. The results will be loaded into customCfg. - if (myGPS.sendCustomCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK + if (myGPS.sendCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK { - Serial.println(F("sendCustomCommand (poll) failed! Trying again...")); + Serial.println(F("sendCommand (poll) failed! Trying again...")); // We need to reset the packet before we try again as the values could have changed customCfg.cls = UBX_CLASS_CFG; customCfg.id = UBX_CFG_NAV5; customCfg.len = 0; customCfg.startingSpot = 0; - if (myGPS.sendCustomCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK + if (myGPS.sendCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK { - Serial.println(F("sendCustomCommand (poll) failed again! Freezing.")); + Serial.println(F("sendCommand (poll) failed again! Freezing.")); while (1) ; } @@ -136,12 +136,12 @@ void setup() } // We don't need to update customCfg.len as it will have been set to 36 (0x24) - // when sendCustomCommand read the data + // when sendCommand read the data // Now we write the custom packet back again to change the setting - if (myGPS.sendCustomCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) // This time we are only expecting an ACK + if (myGPS.sendCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) // This time we are only expecting an ACK { - Serial.println(F("sendCustomCommand (set) failed! Freezing.")); + Serial.println(F("sendCommand (set) failed! Freezing.")); while (1) ; } @@ -158,9 +158,9 @@ void setup() customCfg.len = 0; customCfg.startingSpot = 0; - if (myGPS.sendCustomCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK + if (myGPS.sendCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK { - Serial.println(F("sendCustomCommand (poll) failed! Freezing.")); + Serial.println(F("sendCommand (poll) failed! Freezing.")); while (1) ; } diff --git a/keywords.txt b/keywords.txt index e56f27d..3bdbcf1 100644 --- a/keywords.txt +++ b/keywords.txt @@ -27,7 +27,6 @@ processNMEA KEYWORD2 calcChecksum KEYWORD2 sendCommand KEYWORD2 -sendCustomCommand KEYWORD2 printPacket KEYWORD2 setI2CAddress KEYWORD2 setSerialRate KEYWORD2 diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index f908cd3..261de6d 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -176,7 +176,7 @@ void SFE_UBLOX_GPS::factoryReset() payloadCfg[8 + i] = 0x00; // load mask: don't copy permanent config to current } payloadCfg[12] = 0xff; // all forms of permanent memory - sendCommand(packetCfg, 0); // don't expect ACK + sendCommand(&packetCfg, 0); // don't expect ACK hardReset(); // cause factory default config to actually be loaded and used cleanly } @@ -191,7 +191,7 @@ void SFE_UBLOX_GPS::hardReset() payloadCfg[1] = 0xff; // cold start payloadCfg[2] = 0; // 0=HW reset payloadCfg[3] = 0; // reserved - sendCommand(packetCfg, 0); // don't expect ACK + sendCommand(&packetCfg, 0); // don't expect ACK } //Changes the serial baud rate of the Ublox module, can't return success/fail 'cause ACK from modem @@ -224,7 +224,7 @@ void SFE_UBLOX_GPS::setSerialRate(uint32_t baudrate, uint8_t uartPort, uint16_t _debugSerial->println(((uint32_t)payloadCfg[10] << 16) | ((uint32_t)payloadCfg[9] << 8) | payloadCfg[8]); } - sfe_ublox_status_e retVal = sendCommand(packetCfg, maxWait); + sfe_ublox_status_e retVal = sendCommand(&packetCfg, maxWait); if (_printDebug == true) { _debugSerial->print(F("setSerialRate: sendCommand returned: ")); @@ -247,7 +247,7 @@ boolean SFE_UBLOX_GPS::setI2CAddress(uint8_t deviceAddress, uint16_t maxWait) //payloadCfg is now loaded with current bytes. Change only the ones we need to payloadCfg[4] = deviceAddress << 1; //DDC mode LSB - if (sendCommand(packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT) // We are only expecting an ACK + if (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT) // We are only expecting an ACK { //Success! Now change our internal global. _gpsI2Caddress = deviceAddress; //Store the I2C address from user @@ -898,60 +898,7 @@ void SFE_UBLOX_GPS::processUBXpacket(ubxPacket *msg) } //Given a packet and payload, send everything including CRC bytes via I2C port -sfe_ublox_status_e SFE_UBLOX_GPS::sendCommand(ubxPacket outgoingUBX, uint16_t maxWait) -{ - sfe_ublox_status_e retVal = SFE_UBLOX_STATUS_SUCCESS; - - calcChecksum(&outgoingUBX); //Sets checksum A and B bytes of the packet - - if (_printDebug == true) - { - _debugSerial->print(F("\nSending: ")); - printPacket(&outgoingUBX); - } - - if (commType == COMM_TYPE_I2C) - { - retVal = sendI2cCommand(outgoingUBX, maxWait); - if (retVal != SFE_UBLOX_STATUS_SUCCESS) - { - if (_printDebug == true) - { - _debugSerial->println(F("Send I2C Command failed")); - } - return retVal; - } - } - else if (commType == COMM_TYPE_SERIAL) - { - sendSerialCommand(outgoingUBX); - } - - if (maxWait > 0) - { - //Depending on what we just sent, either we need to look for an ACK or not - if (outgoingUBX.cls == UBX_CLASS_CFG) - { - if (_printDebug == true) - { - _debugSerial->println(F("sendCommand: Waiting for ACK response")); - } - retVal = waitForACKResponse(&outgoingUBX, outgoingUBX.cls, outgoingUBX.id, maxWait); //Wait for Ack response - } - else - { - if (_printDebug == true) - { - _debugSerial->println(F("sendCommand: Waiting for No ACK response")); - } - retVal = waitForNoACKResponse(&outgoingUBX, outgoingUBX.cls, outgoingUBX.id, maxWait); //Wait for Ack response - } - } - return retVal; -} - -//Given a custom packet and payload, send everything including CRC bytes via I2C port -sfe_ublox_status_e SFE_UBLOX_GPS::sendCustomCommand(ubxPacket *outgoingUBX, uint16_t maxWait) +sfe_ublox_status_e SFE_UBLOX_GPS::sendCommand(ubxPacket *outgoingUBX, uint16_t maxWait) { sfe_ublox_status_e retVal = SFE_UBLOX_STATUS_SUCCESS; @@ -965,7 +912,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::sendCustomCommand(ubxPacket *outgoingUBX, uint if (commType == COMM_TYPE_I2C) { - retVal = sendI2cCommand(*outgoingUBX, maxWait); + retVal = sendI2cCommand(outgoingUBX, maxWait); if (retVal != SFE_UBLOX_STATUS_SUCCESS) { if (_printDebug == true) @@ -977,7 +924,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::sendCustomCommand(ubxPacket *outgoingUBX, uint } else if (commType == COMM_TYPE_SERIAL) { - sendSerialCommand(*outgoingUBX); + sendSerialCommand(outgoingUBX); } if (maxWait > 0) @@ -1004,7 +951,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::sendCustomCommand(ubxPacket *outgoingUBX, uint } //Returns false if sensor fails to respond to I2C traffic -sfe_ublox_status_e SFE_UBLOX_GPS::sendI2cCommand(ubxPacket outgoingUBX, uint16_t maxWait) +sfe_ublox_status_e SFE_UBLOX_GPS::sendI2cCommand(ubxPacket *outgoingUBX, uint16_t maxWait) { //Point at 0xFF data register _i2cPort->beginTransmission((uint8_t)_gpsI2Caddress); //There is no register to write to, we just begin writing data bytes @@ -1016,16 +963,16 @@ sfe_ublox_status_e SFE_UBLOX_GPS::sendI2cCommand(ubxPacket outgoingUBX, uint16_t _i2cPort->beginTransmission((uint8_t)_gpsI2Caddress); //There is no register to write to, we just begin writing data bytes _i2cPort->write(UBX_SYNCH_1); //μ - oh ublox, you're funny. I will call you micro-blox from now on. _i2cPort->write(UBX_SYNCH_2); //b - _i2cPort->write(outgoingUBX.cls); - _i2cPort->write(outgoingUBX.id); - _i2cPort->write(outgoingUBX.len & 0xFF); //LSB - _i2cPort->write(outgoingUBX.len >> 8); //MSB + _i2cPort->write(outgoingUBX->cls); + _i2cPort->write(outgoingUBX->id); + _i2cPort->write(outgoingUBX->len & 0xFF); //LSB + _i2cPort->write(outgoingUBX->len >> 8); //MSB if (_i2cPort->endTransmission(false) != 0) //Do not release bus return (SFE_UBLOX_STATUS_I2C_COMM_FAILURE); //Sensor did not ACK //Write payload. Limit the sends into 32 byte chunks //This code based on ublox: https://forum.u-blox.com/index.php/20528/how-to-use-i2c-to-get-the-nmea-frames - uint16_t bytesToSend = outgoingUBX.len; + uint16_t bytesToSend = outgoingUBX->len; //"The number of data bytes must be at least 2 to properly distinguish //from the write access to set the address counter in random read accesses." @@ -1037,15 +984,15 @@ sfe_ublox_status_e SFE_UBLOX_GPS::sendI2cCommand(ubxPacket outgoingUBX, uint16_t len = I2C_BUFFER_LENGTH; _i2cPort->beginTransmission((uint8_t)_gpsI2Caddress); - //_i2cPort->write(outgoingUBX.payload, len); //Write a portion of the payload to the bus + //_i2cPort->write(outgoingUBX->payload, len); //Write a portion of the payload to the bus for (uint16_t x = 0; x < len; x++) - _i2cPort->write(outgoingUBX.payload[startSpot + x]); //Write a portion of the payload to the bus + _i2cPort->write(outgoingUBX->payload[startSpot + x]); //Write a portion of the payload to the bus if (_i2cPort->endTransmission(false) != 0) //Don't release bus return (SFE_UBLOX_STATUS_I2C_COMM_FAILURE); //Sensor did not ACK - //*outgoingUBX.payload += len; //Move the pointer forward + //*outgoingUBX->payload += len; //Move the pointer forward startSpot += len; //Move the pointer forward bytesToSend -= len; } @@ -1053,9 +1000,9 @@ sfe_ublox_status_e SFE_UBLOX_GPS::sendI2cCommand(ubxPacket outgoingUBX, uint16_t //Write checksum _i2cPort->beginTransmission((uint8_t)_gpsI2Caddress); if (bytesToSend == 1) - _i2cPort->write(outgoingUBX.payload, 1); - _i2cPort->write(outgoingUBX.checksumA); - _i2cPort->write(outgoingUBX.checksumB); + _i2cPort->write(outgoingUBX->payload, 1); + _i2cPort->write(outgoingUBX->checksumA); + _i2cPort->write(outgoingUBX->checksumB); //All done transmitting bytes. Release bus. if (_i2cPort->endTransmission() != 0) @@ -1064,25 +1011,25 @@ sfe_ublox_status_e SFE_UBLOX_GPS::sendI2cCommand(ubxPacket outgoingUBX, uint16_t } //Given a packet and payload, send everything including CRC bytesA via Serial port -void SFE_UBLOX_GPS::sendSerialCommand(ubxPacket outgoingUBX) +void SFE_UBLOX_GPS::sendSerialCommand(ubxPacket *outgoingUBX) { //Write header bytes _serialPort->write(UBX_SYNCH_1); //μ - oh ublox, you're funny. I will call you micro-blox from now on. _serialPort->write(UBX_SYNCH_2); //b - _serialPort->write(outgoingUBX.cls); - _serialPort->write(outgoingUBX.id); - _serialPort->write(outgoingUBX.len & 0xFF); //LSB - _serialPort->write(outgoingUBX.len >> 8); //MSB + _serialPort->write(outgoingUBX->cls); + _serialPort->write(outgoingUBX->id); + _serialPort->write(outgoingUBX->len & 0xFF); //LSB + _serialPort->write(outgoingUBX->len >> 8); //MSB //Write payload. - for (int i = 0; i < outgoingUBX.len; i++) + for (int i = 0; i < outgoingUBX->len; i++) { - _serialPort->write(outgoingUBX.payload[i]); + _serialPort->write(outgoingUBX->payload[i]); } //Write checksum - _serialPort->write(outgoingUBX.checksumA); - _serialPort->write(outgoingUBX.checksumB); + _serialPort->write(outgoingUBX->checksumA); + _serialPort->write(outgoingUBX->checksumB); } //Returns true if I2C device ack's @@ -1101,7 +1048,7 @@ boolean SFE_UBLOX_GPS::isConnected(uint16_t maxWait) packetCfg.len = 0; packetCfg.startingSpot = 0; - return (sendCommand(packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_RECEIVED); // We are polling the RATE so we expect data and an ACK + return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_RECEIVED); // We are polling the RATE so we expect data and an ACK } return false; } @@ -1505,7 +1452,7 @@ boolean SFE_UBLOX_GPS::saveConfiguration(uint16_t maxWait) packetCfg.payload[4] = 0xFF; //Set any bit in the saveMask field to save current config to Flash and BBR packetCfg.payload[5] = 0xFF; - return (sendCommand(packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } //Save the selected configuration sub-sections to flash and BBR (battery backed RAM) @@ -1526,7 +1473,7 @@ boolean SFE_UBLOX_GPS::saveConfigSelective(uint32_t configMask, uint16_t maxWait packetCfg.payload[6] = (configMask >> 16) & 0xFF; packetCfg.payload[7] = (configMask >> 24) & 0xFF; - return (sendCommand(packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } //Reset module to factory defaults @@ -1547,7 +1494,7 @@ boolean SFE_UBLOX_GPS::factoryDefault(uint16_t maxWait) packetCfg.payload[8] = 0xFF; //Set any bit in the loadMask field to discard current config and rebuild from lower non-volatile memory layers packetCfg.payload[9] = 0xFF; - return (sendCommand(packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } //Given a group, ID and size, return the value of this config spot @@ -1615,7 +1562,7 @@ uint8_t SFE_UBLOX_GPS::getVal8(uint32_t key, uint8_t layer, uint16_t maxWait) //Send VALGET command with this key - sfe_ublox_status_e retVal = sendCommand(packetCfg, maxWait); + sfe_ublox_status_e retVal = sendCommand(&packetCfg, maxWait); if (_printDebug == true) { _debugSerial->print(F("getVal8: sendCommand returned: ")); @@ -1671,7 +1618,7 @@ uint8_t SFE_UBLOX_GPS::setVal16(uint32_t key, uint16_t value, uint8_t layer, uin payloadCfg[9] = value >> 8 * 1; //Send VALSET command with this key and value - return (sendCommand(packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } //Given a key, set an 8-bit value @@ -1702,7 +1649,7 @@ uint8_t SFE_UBLOX_GPS::setVal8(uint32_t key, uint8_t value, uint8_t layer, uint1 payloadCfg[8] = value; //Value //Send VALSET command with this key and value - return (sendCommand(packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } //Given a key, set a 32-bit value @@ -1736,7 +1683,7 @@ uint8_t SFE_UBLOX_GPS::setVal32(uint32_t key, uint32_t value, uint8_t layer, uin payloadCfg[11] = value >> 8 * 3; //Send VALSET command with this key and value - return (sendCommand(packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } //Start defining a new UBX-CFG-VALSET ubxPacket @@ -1908,7 +1855,7 @@ uint8_t SFE_UBLOX_GPS::sendCfgValset32(uint32_t key, uint32_t value, uint16_t ma addCfgValset32(key, value); //Send VALSET command with this key and value - return (sendCommand(packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } //Add a final keyID and value to an existing UBX-CFG-VALSET ubxPacket and send it @@ -1919,7 +1866,7 @@ uint8_t SFE_UBLOX_GPS::sendCfgValset16(uint32_t key, uint16_t value, uint16_t ma addCfgValset16(key, value); //Send VALSET command with this key and value - return (sendCommand(packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } //Add a final keyID and value to an existing UBX-CFG-VALSET ubxPacket and send it @@ -1930,7 +1877,7 @@ uint8_t SFE_UBLOX_GPS::sendCfgValset8(uint32_t key, uint8_t value, uint16_t maxW addCfgValset8(key, value); //Send VALSET command with this key and value - return (sendCommand(packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } //Get the current TimeMode3 settings - these contain survey in statuses @@ -1941,7 +1888,7 @@ boolean SFE_UBLOX_GPS::getSurveyMode(uint16_t maxWait) packetCfg.len = 0; packetCfg.startingSpot = 0; - return ((sendCommand(packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_RECEIVED); // We are expecting data and an ACK + return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_RECEIVED); // We are expecting data and an ACK } //Control Survey-In for NEO-M8P @@ -1970,7 +1917,7 @@ boolean SFE_UBLOX_GPS::setSurveyMode(uint8_t mode, uint16_t observationTime, flo payloadCfg[29] = svinAccLimit >> 8; payloadCfg[30] = svinAccLimit >> 16; - return ((sendCommand(packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } //Begin Survey-In for NEO-M8P @@ -2001,7 +1948,7 @@ boolean SFE_UBLOX_GPS::getSurveyStatus(uint16_t maxWait) packetCfg.len = 0; packetCfg.startingSpot = 0; - if ((sendCommand(packetCfg, maxWait)) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK + if ((sendCommand(&packetCfg, maxWait)) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK return (false); //If command send fails then bail //We got a response, now parse the bits into the svin structure @@ -2026,7 +1973,7 @@ boolean SFE_UBLOX_GPS::getPortSettings(uint8_t portID, uint16_t maxWait) payloadCfg[0] = portID; - return ((sendCommand(packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_RECEIVED); // We are expecting data and an ACK + return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_RECEIVED); // We are expecting data and an ACK } //Configure a given port to output UBX, NMEA, RTCM3 or a combination thereof @@ -2046,7 +1993,7 @@ boolean SFE_UBLOX_GPS::setPortOutput(uint8_t portID, uint8_t outStreamSettings, //payloadCfg is now loaded with current bytes. Change only the ones we need to payloadCfg[14] = outStreamSettings; //OutProtocolMask LSB - Set outStream bits - return ((sendCommand(packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } //Configure a given port to input UBX, NMEA, RTCM3 or a combination thereof @@ -2067,7 +2014,7 @@ boolean SFE_UBLOX_GPS::setPortInput(uint8_t portID, uint8_t inStreamSettings, ui //payloadCfg is now loaded with current bytes. Change only the ones we need to payloadCfg[12] = inStreamSettings; //InProtocolMask LSB - Set inStream bits - return ((sendCommand(packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } //Configure a port to output UBX, NMEA, RTCM3 or a combination thereof @@ -2109,7 +2056,7 @@ boolean SFE_UBLOX_GPS::setNavigationFrequency(uint8_t navFreq, uint16_t maxWait) packetCfg.startingSpot = 0; //This will load the payloadCfg array with current settings of the given register - if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK + if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK return (false); //If command send fails then bail if (_printDebug == true) @@ -2123,9 +2070,9 @@ boolean SFE_UBLOX_GPS::setNavigationFrequency(uint8_t navFreq, uint16_t maxWait) //payloadCfg is now loaded with current bytes. Change only the ones we need to payloadCfg[0] = measurementRate & 0xFF; //measRate LSB payloadCfg[1] = measurementRate >> 8; //measRate MSB - packetCfg.len = 6; // Bug fix! + //packetCfg.len = 6; - return ((sendCommand(packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } //Get the rate at which the module is outputting nav solutions @@ -2138,7 +2085,7 @@ uint8_t SFE_UBLOX_GPS::getNavigationFrequency(uint16_t maxWait) packetCfg.startingSpot = 0; //This will load the payloadCfg array with current settings of the given register - if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK + if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK return (0); //If command send fails then bail uint16_t measurementRate = 0; @@ -2182,7 +2129,7 @@ boolean SFE_UBLOX_GPS::setAutoPVT(boolean enable, boolean implicitUpdate, uint16 payloadCfg[1] = UBX_NAV_PVT; 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 + boolean ok = ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { autoPVT = enable; @@ -2208,7 +2155,7 @@ boolean SFE_UBLOX_GPS::configureMessage(uint8_t msgClass, uint8_t msgID, uint8_t packetCfg.payload[1] = msgID; packetCfg.payload[2 + portID] = sendRate; //Send rate is relative to the event a message is registered on. For example, if the rate of a navigation message is set to 2, the message is sent every 2nd navigation solution. - return ((sendCommand(packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } //Enable a given message type, default of 1 per update rate (usually 1 per second) @@ -2346,7 +2293,7 @@ boolean SFE_UBLOX_GPS::addGeofence(int32_t latitude, int32_t longitude, uint32_t payloadCfg[54] = currentGeofenceParams.rads[3] >> 16; payloadCfg[55] = currentGeofenceParams.rads[3] >> 24; } - return ((sendCommand(packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } //Clear all geofences using UBX-CFG-GEOFENCE @@ -2368,7 +2315,7 @@ boolean SFE_UBLOX_GPS::clearGeofences(uint16_t maxWait) currentGeofenceParams.numFences = 0; // Zero the number of geofences currently in use - return ((sendCommand(packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } //Clear the antenna control settings using UBX-CFG-ANT @@ -2386,7 +2333,7 @@ boolean SFE_UBLOX_GPS::clearAntPIO(uint16_t maxWait) payloadCfg[2] = 0xFF; // Antenna pin configuration: set pinSwitch and pinSCD to 31 payloadCfg[3] = 0xFF; // Antenna pin configuration: set pinOCD to 31, set reconfig bit - return ((sendCommand(packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } //Returns the combined geofence state using UBX-NAV-GEOFENCE @@ -2398,7 +2345,7 @@ boolean SFE_UBLOX_GPS::getGeofenceState(geofenceState ¤tGeofenceState, uin packetCfg.startingSpot = 0; //Ask module for the geofence status. Loads into payloadCfg. - if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK + if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK return (false); currentGeofenceState.status = payloadCfg[5]; // Extract the status @@ -2445,7 +2392,7 @@ boolean SFE_UBLOX_GPS::powerSaveMode(bool power_save, uint16_t maxWait) packetCfg.startingSpot = 0; //Ask module for the current power management settings. Loads into payloadCfg. - if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK + if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK return (false); if (power_save) @@ -2460,7 +2407,7 @@ boolean SFE_UBLOX_GPS::powerSaveMode(bool power_save, uint16_t maxWait) packetCfg.len = 2; packetCfg.startingSpot = 0; - return (sendCommand(packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } //Change the dynamic platform model using UBX-CFG-NAV5 @@ -2477,7 +2424,7 @@ boolean SFE_UBLOX_GPS::setDynamicModel(dynModel newDynamicModel, uint16_t maxWai packetCfg.startingSpot = 0; //Ask module for the current navigation model settings. Loads into payloadCfg. - if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK + if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK return (false); payloadCfg[0] = 0x01; // mask: set only the dyn bit (0) @@ -2487,7 +2434,7 @@ boolean SFE_UBLOX_GPS::setDynamicModel(dynModel newDynamicModel, uint16_t maxWai packetCfg.len = 36; packetCfg.startingSpot = 0; - return (sendCommand(packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } //Given a spot in the payload array, extract four bytes and build a long @@ -2630,7 +2577,7 @@ boolean SFE_UBLOX_GPS::getPVT(uint16_t maxWait) //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); + sfe_ublox_status_e retVal = sendCommand(&packetCfg, maxWait); if (retVal == SFE_UBLOX_STATUS_DATA_RECEIVED) return (true); @@ -2748,7 +2695,7 @@ boolean SFE_UBLOX_GPS::getHPPOSLLH(uint16_t maxWait) packetCfg.id = UBX_NAV_HPPOSLLH; packetCfg.len = 0; - return (sendCommand(packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_RECEIVED); // We are only expecting data (no ACK) + return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_RECEIVED); // We are only expecting data (no ACK) } //Get the current 3D high precision positional accuracy - a fun thing to watch @@ -2760,7 +2707,7 @@ uint32_t SFE_UBLOX_GPS::getPositionAccuracy(uint16_t maxWait) packetCfg.len = 0; packetCfg.startingSpot = 0; - if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are only expecting data (no ACK) + if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are only expecting data (no ACK) return (0); //If command send fails then bail uint32_t tempAccuracy = extractLong(24); //We got a response, now extract a long beginning at a given position @@ -2920,7 +2867,7 @@ boolean SFE_UBLOX_GPS::getProtocolVersion(uint16_t maxWait) packetCfg.len = 0; packetCfg.startingSpot = 40; //Start at first "extended software information" string - if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are only expecting data (no ACK) + if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are only expecting data (no ACK) return (false); //If command send fails then bail //Payload should now contain ~220 characters (depends on module type) @@ -2996,7 +2943,7 @@ boolean SFE_UBLOX_GPS::getRELPOSNED(uint16_t maxWait) packetCfg.len = 0; packetCfg.startingSpot = 0; - if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are only expecting data (no ACK) + if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are only expecting data (no ACK) return (false); //If command send fails then bail //We got a response, now parse the bits diff --git a/src/SparkFun_Ublox_Arduino_Library.h b/src/SparkFun_Ublox_Arduino_Library.h index 0fa1cac..bc38765 100644 --- a/src/SparkFun_Ublox_Arduino_Library.h +++ b/src/SparkFun_Ublox_Arduino_Library.h @@ -466,10 +466,9 @@ class SFE_UBLOX_GPS void processNMEA(char incoming) __attribute__((weak)); //Given a NMEA character, do something with it. User can overwrite if desired to use something like tinyGPS or MicroNMEA libraries void calcChecksum(ubxPacket *msg); //Sets the checksumA and checksumB of a given messages - sfe_ublox_status_e sendCommand(ubxPacket outgoingUBX, uint16_t maxWait = defaultMaxWait); //Given a packet and payload, send everything including CRC bytes, return true if we got a response - sfe_ublox_status_e sendCustomCommand(ubxPacket *outgoingUBX, uint16_t maxWait = defaultMaxWait); //This allows custom packets to be used - sfe_ublox_status_e sendI2cCommand(ubxPacket outgoingUBX, uint16_t maxWait = 250); - void sendSerialCommand(ubxPacket outgoingUBX); + sfe_ublox_status_e sendCommand(ubxPacket *outgoingUBX, uint16_t maxWait = defaultMaxWait); //Given a packet and payload, send everything including CRC bytes, return true if we got a response + sfe_ublox_status_e sendI2cCommand(ubxPacket *outgoingUBX, uint16_t maxWait = 250); + void sendSerialCommand(ubxPacket *outgoingUBX); void printPacket(ubxPacket *packet); //Useful for debugging From e72463836884d0fb3155ced77699d48417e4533c Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Sun, 19 Apr 2020 20:43:17 +0100 Subject: [PATCH 15/21] Updated the example --- .../Example20_SendCustomCommand.ino | 18 ++++-------------- src/SparkFun_Ublox_Arduino_Library.cpp | 12 ++++-------- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino b/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino index f9e9e73..03f82b0 100644 --- a/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino +++ b/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino @@ -85,11 +85,10 @@ void setup() // SFE_UBLOX_STATUS_DATA_RECEIVED if the data we requested was read / polled successfully // SFE_UBLOX_STATUS_DATA_SENT if the data we sent was writted successfully (ACK'd) // Other values indicate errors. Please see the sfe_ublox_status_e enum for further details. - // If you see a failure you can of course simply try sending the same command again. // Referring to the u-blox M8 Receiver Description and Protocol Specification we see that // the dynamic model is configured using the UBX-CFG-NAV5 message. So let's load our - // custom packet with the correct information so we can read (poll) the current settings. + // custom packet with the correct information so we can read (poll / get) the current settings. customCfg.cls = UBX_CLASS_CFG; // This is the message Class customCfg.id = UBX_CFG_NAV5; // This is the message ID @@ -102,18 +101,9 @@ void setup() // Now let's read the current navigation model settings. The results will be loaded into customCfg. if (myGPS.sendCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK { - Serial.println(F("sendCommand (poll) failed! Trying again...")); - // We need to reset the packet before we try again as the values could have changed - customCfg.cls = UBX_CLASS_CFG; - customCfg.id = UBX_CFG_NAV5; - customCfg.len = 0; - customCfg.startingSpot = 0; - if (myGPS.sendCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - { - Serial.println(F("sendCommand (poll) failed again! Freezing.")); - while (1) - ; - } + Serial.println(F("sendCommand (poll) failed! Freezing...")); + while (1) + ; } // Referring to the message definition for UBX-CFG-NAV5 we see that we need to change diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index 261de6d..0f13d0d 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -128,7 +128,7 @@ const char *SFE_UBLOX_GPS::statusString(sfe_ublox_status_e stat) return "Timeout"; break; case SFE_UBLOX_STATUS_COMMAND_UNKNOWN: - return "Command Unknown"; + return "Command Unknown (NACK)"; break; case SFE_UBLOX_STATUS_OUT_OF_RANGE: return "Out of range"; @@ -154,6 +154,9 @@ const char *SFE_UBLOX_GPS::statusString(sfe_ublox_status_e stat) case SFE_UBLOX_STATUS_I2C_COMM_FAILURE: return "I2C Comm Failure"; break; + case SFE_UBLOX_STATUS_DATA_OVERWRITTEN: + return "Data Packet Overwritten"; + break; default: return "Unknown Status"; break; @@ -2059,18 +2062,11 @@ boolean SFE_UBLOX_GPS::setNavigationFrequency(uint8_t navFreq, uint16_t maxWait) if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK return (false); //If command send fails then bail - if (_printDebug == true) - { - _debugSerial->print(F("setNavigationFrequency packetCfg.len is ")); - _debugSerial->println(packetCfg.len); - } - uint16_t measurementRate = 1000 / navFreq; //payloadCfg is now loaded with current bytes. Change only the ones we need to payloadCfg[0] = measurementRate & 0xFF; //measRate LSB payloadCfg[1] = measurementRate >> 8; //measRate MSB - //packetCfg.len = 6; return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } From 3e2aa741f8d2e470a6b1b1161b36435bd6c3fc7e Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Sun, 19 Apr 2020 22:35:53 +0100 Subject: [PATCH 16/21] Updated Theory.md --- README.md | 13 ++++++------- Theory.md | 11 ++++++++--- .../Example20_SendCustomCommand.ino | 4 ++-- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 3743b33..1c0f251 100644 --- a/README.md +++ b/README.md @@ -44,10 +44,10 @@ Need a library for the Ublox and Particle? Checkout the [Particle library](https Repository Contents ------------------- -* **/examples** - Example sketches for the library (.ino). Run these from the Arduino IDE. +* **/examples** - Example sketches for the library (.ino). Run these from the Arduino IDE. * **/src** - Source files for the library (.cpp, .h). -* **keywords.txt** - Keywords from this library that will be highlighted in the Arduino IDE. -* **library.properties** - General library properties for the Arduino package manager. +* **keywords.txt** - Keywords from this library that will be highlighted in the Arduino IDE. +* **library.properties** - General library properties for the Arduino package manager. Documentation -------------- @@ -85,9 +85,9 @@ As an example, assume that the GPS is set to produce 5 navigation solutions per second and that the sketch only calls getPVT once a second, then the GPS will queue 5 packets in its internal buffer (about 500 bytes) and the library will read those when getPVT is called, update its internal copy of the nav data 5 times, and return `true` to the sketch. The -skecth calls `getLatitude`, etc. and retrieve the data of the most recent of those 5 packets. +sketch calls `getLatitude`, etc. and retrieve the data of the most recent of those 5 packets. -Products That Use This Library +Products That Use This Library --------------------------------- * [GPS-15136](https://www.sparkfun.com/products/15136) - SparkFun GPS-RTK2 ZED-F9P @@ -102,7 +102,7 @@ Products That Use This Library License Information ------------------- -This product is _**open source**_! +This product is _**open source**_! Various bits of the code have different licenses applied. Anything SparkFun wrote is beerware; if you see me (or any other SparkFun employee) at the local, and you've found our code helpful, please buy us a round! @@ -111,4 +111,3 @@ Please use, reuse, and modify these files as you see fit. Please maintain attrib Distributed as-is; no warranty is given. - Your friends at SparkFun. - diff --git a/Theory.md b/Theory.md index 86fcbc4..2153f64 100644 --- a/Theory.md +++ b/Theory.md @@ -1,7 +1,7 @@ How I2C (aka DDC) communication works with a uBlox module =========================================================== -When the user calls one of the methods the library will poll the Ublox module for new data. +When the user calls one of the methods the library will poll the Ublox module for new data. * Wait for a minimum of 25 ms between polls (configured dynamically when update rate is set) * Write 0xFD to module @@ -19,9 +19,14 @@ A method will call **sendCommand()**. This will begin waiting for a response wit Once **waitForACKResponse()** or **waitForNoACKResponse()** is called the library will start checking the ublox module for new bytes. These bytes may be part of a NMEA sentence, an RTCM sentence, or a UBX packet. The library will file each byte into the appropriate container. Once a given sentence or packet is complete, the appropriate processUBX(), processNMEA() will be called. These functions deal with specific processing for each type. -Note: When interfacing to a ublox module over I2C the **checkUbloxI2C()** will read all bytes currently sitting in the I2C buffer. This may pick up multiple UBX packets. For example, an ACK for a VALSET may be mixed in with an auto-PVT response. We cannot tell **checkUbloxI2C()** to stop once a give ACK is found because we run the risk of leaving bytes in the I2C buffer and loosing them. We don't have this issue with **checkUbloxSerial()**. +Note: When interfacing to a ublox module over I2C **checkUbloxI2C()** will read all bytes currently sitting in the I2C buffer. This may pick up multiple UBX packets. For example, an ACK for a VALSET may be mixed in with an auto-PVT response. We cannot tell **checkUbloxI2C()** to stop once a given ACK is found because we run the risk of leaving bytes in the I2C buffer and losing them. We don't have this issue with **checkUbloxSerial()**. **processUBX()** will check the CRC of the UBX packet. If validated, the packet will be marked as valid. Once a packet is marked as valid then **processUBXpacket()** is called to extract the contents. This is most commonly used to get the position, velocity, and time (PVT) out of the packet but is also used to check the nature of an ACK packet. -Once a packet has been processed, **waitForACKResponse()/waitForNoACKResponse()** makes the appropriate decision what to do with it. If a packet satisfies the CLS/ID and characteristics of what **waitForACKResponse()/waitForNoACKResponse()** is waiting for, then it returns back to sendCommand. If the packet didn't match or was invalid then **waitForACKResponse()/waitForNoACKResponse()** will continue to wait until the correct packet is received or we time out. **sendCommand()** then returns with true/false depending on the success of **waitForACKResponse()/waitForNoACKResponse()**. +Once a packet has been processed, **waitForACKResponse()/waitForNoACKResponse()** makes the appropriate decision what to do with it. If a packet satisfies the CLS/ID and characteristics of what **waitForACKResponse()/waitForNoACKResponse()** is waiting for, then it returns back to sendCommand. If the packet didn't match or was invalid then **waitForACKResponse()/waitForNoACKResponse()** will continue to wait until the correct packet is received or we time out. **sendCommand()** then returns with a value from the **sfe_ublox_status_e** enum depending on the success of **waitForACKResponse()/waitForNoACKResponse()**. +If we are getting / polling data from the module, **sendCommand()** will return **SFE_UBLOX_STATUS_DATA_RECEIVED** if the get was successful. + +If we are setting / writing data to the module, **sendCommand()** will return **SFE_UBLOX_STATUS_DATA_SENT** if the set was successful. + +There are circumstances where the library can get the data it is expecting from the module, but it is overwritten (e.g. by an auto-PVT packet) before **sendCommand()** is able to return. In this case, **sendCommand()** will return the error **SFE_UBLOX_STATUS_DATA_OVERWRITTEN**. We should simply call the library function again, but we will need to reset the packet contents first as they will indeed have been overwritten as the error implies. diff --git a/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino b/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino index 03f82b0..74d0b49 100644 --- a/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino +++ b/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino @@ -101,7 +101,7 @@ void setup() // Now let's read the current navigation model settings. The results will be loaded into customCfg. if (myGPS.sendCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK { - Serial.println(F("sendCommand (poll) failed! Freezing...")); + Serial.println(F("sendCommand (poll / get) failed! Freezing...")); while (1) ; } @@ -114,7 +114,7 @@ void setup() Serial.print(customPayload[2]); // Let's change it - if (customPayload[2] != 0x04) // If it is current not 4, change it to 4 + if (customPayload[2] != 0x04) // If it is currently not 4, change it to 4 { Serial.println(F(". Changing it to 4.")); customPayload[2] = 0x04; From 504efe7a482918e6de8ab0b9be65453f5eadf9aa Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Mon, 20 Apr 2020 06:26:26 +0100 Subject: [PATCH 17/21] Added packetBuf etc to the header --- src/SparkFun_Ublox_Arduino_Library.h | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/SparkFun_Ublox_Arduino_Library.h b/src/SparkFun_Ublox_Arduino_Library.h index bc38765..a0376f6 100644 --- a/src/SparkFun_Ublox_Arduino_Library.h +++ b/src/SparkFun_Ublox_Arduino_Library.h @@ -114,6 +114,15 @@ typedef enum SFE_UBLOX_PACKET_NOTACKNOWLEDGED // This indicates that we received a NACK } sfe_ublox_packet_validity_e; +// Identify which packet buffer is in use: +// packetCfg (or a custom packet), packetAck or packetBuf +typedef enum +{ + SFE_UBLOX_PACKET_PACKETCFG, + SFE_UBLOX_PACKET_PACKETACK, + SFE_UBLOX_PACKET_PACKETBUF +} sfe_ublox_packet_buffer_e; + //Registers const uint8_t UBX_SYNCH_1 = 0xB5; const uint8_t UBX_SYNCH_2 = 0x62; @@ -729,13 +738,21 @@ class SFE_UBLOX_GPS boolean _printDebug = false; //Flag to print the serial commands we are sending to the Serial port for debug + //The packet buffers //These are pointed at from within the ubxPacket - uint8_t payloadAck[2]; - uint8_t payloadCfg[MAX_PAYLOAD_SIZE]; + uint8_t payloadAck[2]; // Holds the requested ACK/NACK + uint8_t payloadCfg[MAX_PAYLOAD_SIZE]; // Holds the requested data packet + uint8_t payloadBuf[2]; // Temporary buffer used to screen incoming packets (same size as Ack) - //Init the packet structures and init them with pointers to the payloadAck and payloadCfg arrays + //Init the packet structures and init them with pointers to the payloadAck, payloadCfg and payloadBuf arrays ubxPacket packetAck = {0, 0, 0, 0, 0, payloadAck, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; ubxPacket packetCfg = {0, 0, 0, 0, 0, payloadCfg, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; + ubxPacket packetBuf = {0, 0, 0, 0, 0, payloadBuf, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; + + //Identify which buffer is in use + //Data is stored in packetBuf until the requested class and ID can be validated + //If a match is seen, data is diverted into packetAck or packetCfg + sfe_ublox_packet_buffer_e activePacketBuffer = SFE_UBLOX_PACKET_PACKETBUF; //Limit checking of new data to every X ms //If we are expecting an update every X Hz then we should check every half that amount of time From 956b41f85fc6d6b1e0b1101df6b45c96f570e4d1 Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Mon, 20 Apr 2020 13:16:47 +0100 Subject: [PATCH 18/21] Added most of the packetBuf functionality --- src/SparkFun_Ublox_Arduino_Library.cpp | 211 ++++++++++++++++++------- src/SparkFun_Ublox_Arduino_Library.h | 7 +- 2 files changed, 158 insertions(+), 60 deletions(-) diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index 0f13d0d..278c3f1 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -127,8 +127,8 @@ const char *SFE_UBLOX_GPS::statusString(sfe_ublox_status_e stat) case SFE_UBLOX_STATUS_TIMEOUT: return "Timeout"; break; - case SFE_UBLOX_STATUS_COMMAND_UNKNOWN: - return "Command Unknown (NACK)"; + case SFE_UBLOX_STATUS_COMMAND_NACK: + return "Command not acknowledged (NACK)"; break; case SFE_UBLOX_STATUS_OUT_OF_RANGE: return "Out of range"; @@ -441,6 +441,12 @@ void SFE_UBLOX_GPS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t re //We still don't know the response class ubxFrameCounter = 0; currentSentence = UBX; + //Reset the packetBuf.counter even though we will need to reset it again when ubxFrameCounter == 2 + packetBuf.counter = 0; + //We should not ignore this payload - yet + ignoreThisPayload = false; + //Store data in packetBuf until we know if we have a requested class and ID match + activePacketBuffer = SFE_UBLOX_PACKET_PACKETBUF; } else if (incoming == '$') { @@ -465,33 +471,140 @@ void SFE_UBLOX_GPS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t re currentSentence = NONE; //Something went wrong. Reset. else if ((ubxFrameCounter == 1) && (incoming != 0x62)) //ASCII 'b' currentSentence = NONE; //Something went wrong. Reset. - else if (ubxFrameCounter == 2) //Class + else if (ubxFrameCounter == 2) //Class { + // Record the class in packetBuf until we know what to do with it + packetBuf.cls = incoming; // (Duplication) //Reset our rolling checksums here (not when we receive the 0xB5) rollingChecksumA = 0; rollingChecksumB = 0; + //Reset the packetBuf.counter (again) + packetBuf.counter = 0; + } + // Note to future self: + // There may be some duplication / redundancy in the next few lines as processUBX will also + // load information into packetBuf, but we'll do it here too for clarity + else if (ubxFrameCounter == 3) //ID + { + // Record the ID in packetBuf until we know what to do with it + packetBuf.id = incoming; // (Duplication) //We can now identify the type of response - if (incoming == UBX_CLASS_ACK) + //If the packet we are receiving is not an ACK then check for a class and ID match + if (packetBuf.cls != UBX_CLASS_ACK) { - packetAck.counter = 0; - packetAck.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - ubxFrameClass = CLASS_ACK; + //This is not an ACK so check for a class and ID match + if ((packetBuf.cls == requestedClass) && (packetBuf.id == requestedID)) + { + //This is not an ACK and we have a class and ID match + //So start diverting data into incomingUBX (usually packetCfg) + activePacketBuffer = SFE_UBLOX_PACKET_PACKETCFG; + //Copy the class and ID into incomingUBX (usually packetCfg) + incomingUBX->cls = packetBuf.cls; + incomingUBX->id = packetBuf.id; + //Copy over the .counter too + incomingUBX->counter = packetBuf.counter; + } + else + { + //This is not an ACK and we do not have a class and ID match + //so we should keep diverting data into packetBuf and ignore the payload + ignoreThisPayload = true; + } } else { - incomingUBX->counter = 0; - incomingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - ubxFrameClass = CLASS_NOT_AN_ACK; + // This is an ACK so it is to early to do anything with it + // We need to wait until we have received the length and data bytes + // So we should keep diverting data into packetBuf + } + } + else if (ubxFrameCounter == 4) //Length LSB + { + //We should save the length in packetBuf even if activePacketBuffer == SFE_UBLOX_PACKET_PACKETCFG + packetBuf.len = incoming; // (Duplication) + } + else if (ubxFrameCounter == 5) //Length MSB + { + //We should save the length in packetBuf even if activePacketBuffer == SFE_UBLOX_PACKET_PACKETCFG + packetBuf.len |= incoming << 8; // (Duplication) + } + else if (ubxFrameCounter == 6) //This should be the first byte of the payload unless .len is zero + { + if (packetBuf.len == 0) // Check if length is zero (hopefully this is impossible!) + { + if (_printDebug == true) + { + _debugSerial->print(F("process: ZERO LENGTH packet received: Class: 0x")); + _debugSerial->print(packetBuf.cls, HEX); + _debugSerial->print(F(" ID: 0x")); + _debugSerial->println(packetBuf.id, HEX); + } + //If length is zero (!) this will be the first byte of the checksum so record it + packetBuf.checksumA = incoming; + } + else + { + //The length is not zero so record this byte in the payload + packetBuf.payload[0] = incoming; + } + } + else if (ubxFrameCounter == 7) //This should be the second byte of the payload unless .len is zero or one + { + if (packetBuf.len == 0) // Check if length is zero (hopefully this is impossible!) + { + //If length is zero (!) this will be the second byte of the checksum so record it + packetBuf.checksumB = incoming; + } + else if (packetBuf.len == 1) // Check if length is one + { + //The length is one so this is the first byte of the checksum + packetBuf.checksumA = incoming; + } + else // Length is >= 2 so this must be a payload byte + { + packetBuf.payload[1] = incoming; + } + // Now that we have received two payload bytes, we can check for a matching ACK/NACK + if ((activePacketBuffer == SFE_UBLOX_PACKET_PACKETBUF) // If we are not already processing a data packet + && (packetBuf.cls == UBX_CLASS_ACK) // and if this is an ACK/NACK + && (packetBuf.payload[0] == requestedClass) // and if the class matches + && (packetBuf.payload[1] == requestedID)) // and if the ID matches + { + if (packetBuf.len != 2) // Check if length is not 2 (hopefully this is impossible!) + { + if (_printDebug == true) + { + _debugSerial->print(F("process: ACK received with .len != 2: Class: 0x")); + _debugSerial->print(packetBuf.payload[0], HEX); + _debugSerial->print(F(" ID: 0x")); + _debugSerial->println(packetBuf.payload[1], HEX); + } + } + else + { + // Then this is a matching ACK so copy it into packetAck + activePacketBuffer = SFE_UBLOX_PACKET_PACKETACK; + packetAck.cls = packetBuf.cls; + packetAck.id = packetBuf.id; + packetAck.len = packetBuf.len; + packetAck.counter = packetBuf.counter; + packetAck.payload[0] = packetBuf.payload[0]; + packetAck.payload[1] = packetBuf.payload[1]; + } } } - ubxFrameCounter++; - - //Depending on this frame's class, pass different structs and payload arrays - if (ubxFrameClass == CLASS_ACK) + //Divert incoming into the correct buffer + if (activePacketBuffer == SFE_UBLOX_PACKET_PACKETACK) processUBX(incoming, &packetAck, requestedClass, requestedID); - else if (ubxFrameClass == CLASS_NOT_AN_ACK) + else if (activePacketBuffer == SFE_UBLOX_PACKET_PACKETCFG) processUBX(incoming, incomingUBX, requestedClass, requestedID); + else // if (activePacketBuffer == SFE_UBLOX_PACKET_PACKETBUF) + processUBX(incoming, &packetBuf, requestedClass, requestedID); + + //Finally, increment the frame counter + ubxFrameCounter++; + } else if (currentSentence == NMEA) { @@ -589,54 +702,18 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t if (incomingUBX->counter == 0) { incomingUBX->cls = incoming; - // if (_printDebug == true) - // { - // _debugSerial->print(F("processUBX: Class : 0x")); - // _debugSerial->print(incomingUBX->cls, HEX); - // _debugSerial->print(F(" CSUMA: 0x")); - // _debugSerial->print(rollingChecksumA, HEX); - // _debugSerial->print(F(" CSUMB: 0x")); - // _debugSerial->println(rollingChecksumB, HEX); - // } } else if (incomingUBX->counter == 1) { incomingUBX->id = incoming; - // if (_printDebug == true) - // { - // _debugSerial->print(F("processUBX: ID : 0x")); - // _debugSerial->print(incomingUBX->id, HEX); - // _debugSerial->print(F(" CSUMA: 0x")); - // _debugSerial->print(rollingChecksumA, HEX); - // _debugSerial->print(F(" CSUMB: 0x")); - // _debugSerial->println(rollingChecksumB, HEX); - // } } else if (incomingUBX->counter == 2) //Len LSB { incomingUBX->len = incoming; - // if (_printDebug == true) - // { - // _debugSerial->print(F("processUBX: LEN_LSB: 0x")); - // _debugSerial->print(incomingUBX->len, HEX); - // _debugSerial->print(F(" CSUMA: 0x")); - // _debugSerial->print(rollingChecksumA, HEX); - // _debugSerial->print(F(" CSUMB: 0x")); - // _debugSerial->println(rollingChecksumB, HEX); - // } } else if (incomingUBX->counter == 3) //Len MSB { incomingUBX->len |= incoming << 8; - // if (_printDebug == true) - // { - // _debugSerial->print(F("processUBX: LEN_MSB: 0x")); - // _debugSerial->print(incoming, HEX); - // _debugSerial->print(F(" CSUMA: 0x")); - // _debugSerial->print(rollingChecksumA, HEX); - // _debugSerial->print(F(" CSUMB: 0x")); - // _debugSerial->println(rollingChecksumB, HEX); - // } } else if (incomingUBX->counter == incomingUBX->len + 4) //ChecksumA { @@ -674,10 +751,10 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t incomingUBX->classAndIDmatch = SFE_UBLOX_PACKET_NOTACKNOWLEDGED; // If we have a match, set the classAndIDmatch flag to NOTACKNOWLEDGED if (_printDebug == true) { - _debugSerial->print(F("processUBX: NACK received: Requested Class: ")); - _debugSerial->print(incomingUBX->payload[0]); - _debugSerial->print(F(" Requested ID: ")); - _debugSerial->println(incomingUBX->payload[1]); + _debugSerial->print(F("processUBX: NACK received: Requested Class: 0x")); + _debugSerial->print(incomingUBX->payload[0], HEX); + _debugSerial->print(F(" Requested ID: 0x")); + _debugSerial->println(incomingUBX->payload[1], HEX); } } @@ -762,11 +839,19 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t { //Check to see if we have room for this byte if (((incomingUBX->counter - 4) - startingSpot) < MAX_PAYLOAD_SIZE) //If counter = 208, starting spot = 200, we're good to record. - incomingUBX->payload[incomingUBX->counter - 4 - startingSpot] = incoming; //Store this byte into payload array + { + // Check if this is payload data which should be ignored + if (ignoreThisPayload == false) + { + incomingUBX->payload[incomingUBX->counter - 4 - startingSpot] = incoming; //Store this byte into payload array + } + } } } + //Increment the counter incomingUBX->counter++; + if (incomingUBX->counter == MAX_PAYLOAD_SIZE) { //Something has gone very wrong @@ -1105,7 +1190,10 @@ void SFE_UBLOX_GPS::printPacket(ubxPacket *packet) else if (packet->cls == UBX_CLASS_MON) //0x0A _debugSerial->print("MON"); else + { + _debugSerial->print(F("0x")); _debugSerial->print(packet->cls, HEX); + } _debugSerial->print(F(" ID:")); if (packet->cls == UBX_CLASS_NAV && packet->id == UBX_NAV_PVT) @@ -1115,7 +1203,10 @@ void SFE_UBLOX_GPS::printPacket(ubxPacket *packet) else if (packet->cls == UBX_CLASS_CFG && packet->id == UBX_CFG_CFG) _debugSerial->print("SAVE"); else + { + _debugSerial->print(F("0x")); _debugSerial->print(packet->id, HEX); + } _debugSerial->print(F(" Len: 0x")); _debugSerial->print(packet->len, HEX); @@ -1160,7 +1251,7 @@ void SFE_UBLOX_GPS::printPacket(ubxPacket *packet) //Returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got an ACK and a valid packetCfg (module is responding with register content) //Returns SFE_UBLOX_STATUS_DATA_SENT if we got an ACK and no packetCfg (no valid packetCfg needed, module absorbs new register data) //Returns SFE_UBLOX_STATUS_FAIL if something very bad happens (e.g. a double checksum failure) -//Returns SFE_UBLOX_STATUS_COMMAND_UNKNOWN if the packet was not-acknowledged (NACK) +//Returns SFE_UBLOX_STATUS_COMMAND_NACK if the packet was not-acknowledged (NACK) //Returns SFE_UBLOX_STATUS_CRC_FAIL if we had a checksum failure //Returns SFE_UBLOX_STATUS_TIMEOUT if we timed out //Returns SFE_UBLOX_STATUS_DATA_OVERWRITTEN if we got an ACK and a valid packetCfg but that the packetCfg has been @@ -1169,8 +1260,10 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uin { outgoingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; //This will go VALID (or NOT_VALID) when we receive a response to the packet we sent packetAck.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; + packetBuf.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; outgoingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; // This will go VALID (or NOT_VALID) when we receive a packet that matches the requested class and ID packetAck.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; + packetBuf.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; unsigned long startTime = millis(); while (millis() - startTime < maxTime) @@ -1261,7 +1354,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uin _debugSerial->print(millis() - startTime); _debugSerial->println(F(" msec")); } - return (SFE_UBLOX_STATUS_COMMAND_UNKNOWN); //We received a NACK! + return (SFE_UBLOX_STATUS_COMMAND_NACK); //We received a NACK! } // If the outgoingUBX->classAndIDmatch is VALID but the packetAck.classAndIDmatch is NOT_VALID @@ -1352,8 +1445,10 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(ubxPacket *outgoingUBX, u { outgoingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; //This will go VALID (or NOT_VALID) when we receive a response to the packet we sent packetAck.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; + packetBuf.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; outgoingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; // This will go VALID (or NOT_VALID) when we receive a packet that matches the requested class and ID packetAck.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; + packetBuf.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; unsigned long startTime = millis(); while (millis() - startTime < maxTime) diff --git a/src/SparkFun_Ublox_Arduino_Library.h b/src/SparkFun_Ublox_Arduino_Library.h index a0376f6..7c517df 100644 --- a/src/SparkFun_Ublox_Arduino_Library.h +++ b/src/SparkFun_Ublox_Arduino_Library.h @@ -93,7 +93,7 @@ typedef enum SFE_UBLOX_STATUS_FAIL, SFE_UBLOX_STATUS_CRC_FAIL, SFE_UBLOX_STATUS_TIMEOUT, - SFE_UBLOX_STATUS_COMMAND_UNKNOWN, + SFE_UBLOX_STATUS_COMMAND_NACK, // Indicates that the command was unrecognised, invalid or that the module is too busy to respond SFE_UBLOX_STATUS_OUT_OF_RANGE, SFE_UBLOX_STATUS_INVALID_ARG, SFE_UBLOX_STATUS_INVALID_OPERATION, @@ -742,13 +742,16 @@ class SFE_UBLOX_GPS //These are pointed at from within the ubxPacket uint8_t payloadAck[2]; // Holds the requested ACK/NACK uint8_t payloadCfg[MAX_PAYLOAD_SIZE]; // Holds the requested data packet - uint8_t payloadBuf[2]; // Temporary buffer used to screen incoming packets (same size as Ack) + uint8_t payloadBuf[2]; // Temporary buffer used to screen incoming packets or dump unrequested packets //Init the packet structures and init them with pointers to the payloadAck, payloadCfg and payloadBuf arrays ubxPacket packetAck = {0, 0, 0, 0, 0, payloadAck, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; ubxPacket packetCfg = {0, 0, 0, 0, 0, payloadCfg, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; ubxPacket packetBuf = {0, 0, 0, 0, 0, payloadBuf, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; + //Flag if this packet is unrequested (and so should be ignored and not copied into packetCfg or packetAck) + boolean ignoreThisPayload = false; + //Identify which buffer is in use //Data is stored in packetBuf until the requested class and ID can be validated //If a match is seen, data is diverted into packetAck or packetCfg From 66ee2b3876b30d981840045494f7d242ddd96127 Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Mon, 20 Apr 2020 15:31:31 +0100 Subject: [PATCH 19/21] Update SparkFun_Ublox_Arduino_Library.cpp --- src/SparkFun_Ublox_Arduino_Library.cpp | 52 +++++++++++++------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index 278c3f1..aa1e27c 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -443,8 +443,7 @@ void SFE_UBLOX_GPS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t re currentSentence = UBX; //Reset the packetBuf.counter even though we will need to reset it again when ubxFrameCounter == 2 packetBuf.counter = 0; - //We should not ignore this payload - yet - ignoreThisPayload = false; + ignoreThisPayload = false; //We should not ignore this payload - yet //Store data in packetBuf until we know if we have a requested class and ID match activePacketBuffer = SFE_UBLOX_PACKET_PACKETBUF; } @@ -471,19 +470,18 @@ void SFE_UBLOX_GPS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t re currentSentence = NONE; //Something went wrong. Reset. else if ((ubxFrameCounter == 1) && (incoming != 0x62)) //ASCII 'b' currentSentence = NONE; //Something went wrong. Reset. + // Note to future self: + // There may be some duplication / redundancy in the next few lines as processUBX will also + // load information into packetBuf, but we'll do it here too for clarity else if (ubxFrameCounter == 2) //Class { // Record the class in packetBuf until we know what to do with it packetBuf.cls = incoming; // (Duplication) - //Reset our rolling checksums here (not when we receive the 0xB5) - rollingChecksumA = 0; + rollingChecksumA = 0; //Reset our rolling checksums here (not when we receive the 0xB5) rollingChecksumB = 0; - //Reset the packetBuf.counter (again) - packetBuf.counter = 0; + packetBuf.counter = 0; //Reset the packetBuf.counter (again) + packetBuf.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; // Reset the packet validity (redundant?) } - // Note to future self: - // There may be some duplication / redundancy in the next few lines as processUBX will also - // load information into packetBuf, but we'll do it here too for clarity else if (ubxFrameCounter == 3) //ID { // Record the ID in packetBuf until we know what to do with it @@ -498,11 +496,9 @@ void SFE_UBLOX_GPS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t re //This is not an ACK and we have a class and ID match //So start diverting data into incomingUBX (usually packetCfg) activePacketBuffer = SFE_UBLOX_PACKET_PACKETCFG; - //Copy the class and ID into incomingUBX (usually packetCfg) - incomingUBX->cls = packetBuf.cls; + incomingUBX->cls = packetBuf.cls; //Copy the class and ID into incomingUBX (usually packetCfg) incomingUBX->id = packetBuf.id; - //Copy over the .counter too - incomingUBX->counter = packetBuf.counter; + incomingUBX->counter = packetBuf.counter; //Copy over the .counter too } else { @@ -570,17 +566,7 @@ void SFE_UBLOX_GPS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t re && (packetBuf.payload[0] == requestedClass) // and if the class matches && (packetBuf.payload[1] == requestedID)) // and if the ID matches { - if (packetBuf.len != 2) // Check if length is not 2 (hopefully this is impossible!) - { - if (_printDebug == true) - { - _debugSerial->print(F("process: ACK received with .len != 2: Class: 0x")); - _debugSerial->print(packetBuf.payload[0], HEX); - _debugSerial->print(F(" ID: 0x")); - _debugSerial->println(packetBuf.payload[1], HEX); - } - } - else + if (packetBuf.len == 2) // Check if .len is 2 { // Then this is a matching ACK so copy it into packetAck activePacketBuffer = SFE_UBLOX_PACKET_PACKETACK; @@ -591,6 +577,16 @@ void SFE_UBLOX_GPS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t re packetAck.payload[0] = packetBuf.payload[0]; packetAck.payload[1] = packetBuf.payload[1]; } + else // Length is not 2 (hopefully this is impossible!) + { + if (_printDebug == true) + { + _debugSerial->print(F("process: ACK received with .len != 2: Class: 0x")); + _debugSerial->print(packetBuf.payload[0], HEX); + _debugSerial->print(F(" ID: 0x")); + _debugSerial->println(packetBuf.payload[1], HEX); + } + } } } @@ -728,7 +724,7 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t //Validate this sentence if ((incomingUBX->checksumA == rollingChecksumA) && (incomingUBX->checksumB == rollingChecksumB)) { - incomingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_VALID; + incomingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_VALID; // Flag the packet as valid // Let's check if the class and ID match the requestedClass and requestedID // Remember - this could be a data packet or an ACK packet @@ -797,6 +793,12 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t { incomingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_VALID; // If we have a match, set the classAndIDmatch flag to not valid } + // If this is an ACK then let's check if the class and ID match the requestedClass and requestedID + else if ((incomingUBX->cls == UBX_CLASS_ACK) + && (incomingUBX->payload[0] == requestedClass) && (incomingUBX->payload[1] == requestedID)) + { + incomingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_VALID; // If we have a match, set the classAndIDmatch flag to not valid + } if (_printDebug == true) { From d42082030593922581b96181881c8d87d7137962 Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Mon, 20 Apr 2020 16:22:30 +0100 Subject: [PATCH 20/21] Update Example20_SendCustomCommand.ino --- .../Example20_SendCustomCommand.ino | 92 +++++++------------ 1 file changed, 32 insertions(+), 60 deletions(-) diff --git a/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino b/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino index 74d0b49..d00e5d5 100644 --- a/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino +++ b/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino @@ -1,7 +1,7 @@ /* Send Custom Command By: Paul Clark (PaulZC) - Date: April 18th, 2020 + Date: April 20th, 2020 License: MIT. See license file for more information but you can basically do whatever you want with this code. @@ -32,16 +32,16 @@ Open the serial monitor at 115200 baud to see the output */ +#define NAV_RATE 20 // The new navigation rate in Hz (measurements per second) + #include //Needed for I2C to GPS #include "SparkFun_Ublox_Arduino_Library.h" //http://librarymanager/All#SparkFun_Ublox_GPS SFE_UBLOX_GPS myGPS; -long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to Ublox module. - void setup() { - Serial.begin(115200); + Serial.begin(115200); // You may need to increase this for high navigation rates! while (!Serial) ; //Wait for user to open terminal Serial.println("SparkFun Ublox Example"); @@ -59,10 +59,7 @@ void setup() myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise) - // Let's configure the module's dynamic platform model as if we were using setDynamicModel - // Possible values are: - // 0 (PORTABLE), 2 (STATIONARY), 3 (PEDESTRIAN), 4 (AUTOMOTIVE), 5 (SEA), - // 6 (AIRBORNE1g), 7 (AIRBORNE2g), 8 (AIRBORNE4g), 9 (WRIST), 10 (BIKE) + // Let's configure the module's navigation rate as if we were using setNavigationFrequency // Let's create our custom packet uint8_t customPayload[MAX_PAYLOAD_SIZE]; // This array holds the payload data bytes @@ -87,18 +84,18 @@ void setup() // Other values indicate errors. Please see the sfe_ublox_status_e enum for further details. // Referring to the u-blox M8 Receiver Description and Protocol Specification we see that - // the dynamic model is configured using the UBX-CFG-NAV5 message. So let's load our + // the navigation rate is configured using the UBX-CFG-RATE message. So let's load our // custom packet with the correct information so we can read (poll / get) the current settings. customCfg.cls = UBX_CLASS_CFG; // This is the message Class - customCfg.id = UBX_CFG_NAV5; // This is the message ID + customCfg.id = UBX_CFG_RATE; // This is the message ID customCfg.len = 0; // Setting the len (length) to zero let's us poll the current settings customCfg.startingSpot = 0; // Always set the startingSpot to zero (unless you really know what you are doing) // We also need to tell sendCommand how long it should wait for a reply uint16_t maxWait = 250; // Wait for up to 250ms (Serial may need a lot longer e.g. 1100) - // Now let's read the current navigation model settings. The results will be loaded into customCfg. + // Now let's read the current navigation rate. The results will be loaded into customCfg. if (myGPS.sendCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK { Serial.println(F("sendCommand (poll / get) failed! Freezing...")); @@ -106,26 +103,26 @@ void setup() ; } - // Referring to the message definition for UBX-CFG-NAV5 we see that we need to change - // byte 2 to update the dynamic platform model. + // Referring to the message definition for UBX-CFG-RATE we see that the measurement rate + // is stored in payload bytes 0 and 1 as a uint16_t in LSB-first (little endian) format + + uint16_t rate = (customPayload[1] << 8) | customPayload[0]; // Extract the current rate (ms) + float f_rate = 1000.0 / ((float)rate); // Convert the navigation rate to Hz (measurements per second) - // Print the current dynamic model - Serial.print(F("The current dynamic model is: ")); - Serial.print(customPayload[2]); + // Print the current measurement rate + Serial.print(F("The current measurement rate is: ")); + Serial.println(f_rate, 1); // Let's change it - if (customPayload[2] != 0x04) // If it is currently not 4, change it to 4 - { - Serial.println(F(". Changing it to 4.")); - customPayload[2] = 0x04; - } - else // If it is already 4, change it to 2 - { - Serial.println(F(". Changing it to 2.")); - customPayload[2] = 0x02; - } + rate = 1000 / NAV_RATE; // Load the new value into rate + customPayload[0] = rate & 0xFF; // Store it in the payload + customPayload[1] = rate >> 8; + + // Print the new measurement rate + Serial.print(F("The new measurement rate will be: ")); + Serial.println(NAV_RATE); - // We don't need to update customCfg.len as it will have been set to 36 (0x24) + // We don't need to update customCfg.len as it will have been set to 6 // when sendCommand read the data // Now we write the custom packet back again to change the setting @@ -137,53 +134,28 @@ void setup() } else { - Serial.println(F("Dynamic platform model updated.")); - } - - // Now let's read the navigation model settings again to see if the change was successful. - - // We need to reset the packet before we try again as the values could have changed - customCfg.cls = UBX_CLASS_CFG; - customCfg.id = UBX_CFG_NAV5; - customCfg.len = 0; - customCfg.startingSpot = 0; - - if (myGPS.sendCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - { - Serial.println(F("sendCommand (poll) failed! Freezing.")); - while (1) - ; + Serial.println(F("Navigation rate updated. Here we go...")); } - // Print the current dynamic model - Serial.print(F("The new dynamic model is: ")); - Serial.println(customPayload[2]); + myGPS.setAutoPVT(true); // Enable AutoPVT. The module will generate measurements automatically without being polled. //myGPS.saveConfigSelective(VAL_CFG_SUBSEC_NAVCONF); //Uncomment this line to save only the NAV settings to flash and BBR } void loop() { - //Query module only every second. Doing it more often will just cause I2C traffic. - //The module only responds when a new position is available - if (millis() - lastTime > 1000) - { - lastTime = millis(); //Update the timer - - long latitude = myGPS.getLatitude(); + //Query the module as fast as possible + int32_t latitude = myGPS.getLatitude(); Serial.print(F("Lat: ")); Serial.print(latitude); - long longitude = myGPS.getLongitude(); - Serial.print(F(" Long: ")); + int32_t longitude = myGPS.getLongitude(); + Serial.print(F(" Lon: ")); Serial.print(longitude); Serial.print(F(" (degrees * 10^-7)")); - long altitude = myGPS.getAltitude(); + int32_t altitude = myGPS.getAltitude(); Serial.print(F(" Alt: ")); Serial.print(altitude); - Serial.print(F(" (mm)")); - - Serial.println(); - } + Serial.println(F(" (mm)")); } From 8ce607c729f7f2705eb9bf3d3e20f5fe113ddb70 Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Mon, 20 Apr 2020 16:55:14 +0100 Subject: [PATCH 21/21] Update SparkFun_Ublox_Arduino_Library.cpp --- src/SparkFun_Ublox_Arduino_Library.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index aa1e27c..7383371 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -481,6 +481,7 @@ void SFE_UBLOX_GPS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t re rollingChecksumB = 0; packetBuf.counter = 0; //Reset the packetBuf.counter (again) packetBuf.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; // Reset the packet validity (redundant?) + packetBuf.startingSpot = incomingUBX->startingSpot; //Copy the startingSpot } else if (ubxFrameCounter == 3) //ID { @@ -1313,6 +1314,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uin // If (e.g.) a PVT packet is _being_ received: outgoingUBX->valid will be NOT_DEFINED // 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) @@ -1348,6 +1350,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uin // but outgoingUBX->cls and outgoingUBX->id would not match... // So I think this is telling us we need a special state for packetAck.classAndIDmatch to tell us // the packet was definitely NACK'd otherwise we are possibly just guessing... + // Note: the addition of packetBuf changes the logic of this, but we'll leave the code as is for now. else if (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_NOTACKNOWLEDGED) { if (_printDebug == true) @@ -1481,6 +1484,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(ubxPacket *outgoingUBX, u // If (e.g.) a PVT packet is _being_ received: outgoingUBX->valid will be NOT_DEFINED // 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)))