diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index c8c68e2..2db25bf 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -164,9 +164,11 @@ void SFE_UBLOX_GPS::factoryReset() packetCfg.startingSpot = 0; for (uint8_t i = 0; i < 4; i++) { + //u-center suggests we should set clear mask _and_ load mask, to ensure the defaults are restored and made current + //then we can save them using saveConfiguration payloadCfg[0 + i] = 0xff; // clear mask: copy default config to permanent config payloadCfg[4 + i] = 0x00; // save mask: don't save current to permanent - payloadCfg[8 + i] = 0x00; // load mask: don't copy permanent config to current + payloadCfg[8 + i] = 0xff; // load mask: copy permanent config to current } payloadCfg[12] = 0xff; // all forms of permanent memory sendCommand(packetCfg, 0); // don't expect ACK @@ -217,7 +219,12 @@ 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]); } - sendCommand(packetCfg, maxWait); + sfe_ublox_status_e retVal = sendCommand(packetCfg, maxWait); + if (_printDebug == true) + { + _debugSerial->print(F("setSerialRate: sendCommand returned: ")); + _debugSerial->println(statusString(retVal)); + } } //Changes the I2C address that the Ublox module responds to @@ -235,7 +242,9 @@ 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) == true) + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_SENT if it got an ACK and no packetCfg + // (no valid packetCfg needed, module absorbs new register data) + if (sendCommand(packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT) { //Success! Now change our internal global. _gpsI2Caddress = deviceAddress; //Store the I2C address from user @@ -281,7 +290,10 @@ boolean SFE_UBLOX_GPS::checkUbloxI2C() if (lsb == 0xFF) { //I believe this is a Ublox bug. Device should never present an 0xFF. - debugPrintln((char *)F("checkUbloxI2C: Ublox bug, no bytes available")); + if (_printDebug == true) + { + _debugSerial->println(F("checkUbloxI2C: Ublox bug, no bytes available")); + } lastCheck = millis(); //Put off checking to avoid I2C bus traffic return (false); } @@ -290,7 +302,10 @@ boolean SFE_UBLOX_GPS::checkUbloxI2C() if (bytesAvailable == 0) { - debugPrintln((char *)F("checkUbloxI2C: OK, zero bytes available")); + if (_printDebug == true) + { + _debugSerial->println(F("checkUbloxI2C: OK, zero bytes available")); + } lastCheck = millis(); //Put off checking to avoid I2C bus traffic return (false); } @@ -347,7 +362,10 @@ boolean SFE_UBLOX_GPS::checkUbloxI2C() { if (incoming == 0x7F) { - debugPrintln((char *)F("Module not ready with data")); + if (_printDebug == true) + { + _debugSerial->println(F("checkUbloxI2C: Module not ready with data. Retrying.")); + } delay(5); //In logic analyzation, the module starting responding after 1.48ms goto TRY_AGAIN; } @@ -424,13 +442,13 @@ void SFE_UBLOX_GPS::process(uint8_t incoming) if (incoming == UBX_CLASS_ACK) { packetAck.counter = 0; - packetAck.valid = false; + packetAck.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; ubxFrameClass = CLASS_ACK; } else { packetCfg.counter = 0; - packetCfg.valid = false; + packetCfg.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; ubxFrameClass = CLASS_NOT_AN_ACK; } } @@ -525,7 +543,7 @@ void SFE_UBLOX_GPS::processRTCM(uint8_t incoming) } //Given a character, file it away into the uxb packet structure -//Set valid = true once sentence is completely received and passes CRC +//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 //a subset of bytes within a larger packet. @@ -565,7 +583,7 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX) //Validate this sentence if (incomingUBX->checksumA == rollingChecksumA && incomingUBX->checksumB == rollingChecksumB) { - incomingUBX->valid = true; + incomingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_VALID; if (_printDebug == true) { @@ -574,16 +592,28 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX) _debugSerial->print(F(" Received: ")); printPacket(incomingUBX); - if (packetCfg.valid == true) - debugPrintln((char *)F("packetCfg now valid")); - if (packetAck.valid == true) - debugPrintln((char *)F("packetAck now valid")); + if (packetCfg.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")); + } + } } processUBXpacket(incomingUBX); //We've got a valid packet, now do something with it } - else + else // Checksum failure { + incomingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_NOT_VALID; + if (_printDebug == true) { //Drive an external pin to allow for easier logic analyzation @@ -594,7 +624,7 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX) digitalWrite((uint8_t)checksumFailurePin, HIGH); } - debugPrint((char *)F("Checksum failed:")); + _debugSerial->print(F("Checksum failed:")); _debugSerial->print(F(" checksumA: ")); _debugSerial->print(incomingUBX->checksumA); _debugSerial->print(F(" checksumB: ")); @@ -642,13 +672,19 @@ void SFE_UBLOX_GPS::processUBXpacket(ubxPacket *msg) 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) - debugPrintln((char *)F("UBX ACK: Command sent/ack'd successfully")); + 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 - debugPrintln((char *)F("UBX ACK: Not-Acknowledged")); + if (_printDebug == true) + { + _debugSerial->println(F("UBX ACK: Not-Acknowledged")); + } commandAck = UBX_ACK_NACK; } break; @@ -773,7 +809,10 @@ sfe_ublox_status_e SFE_UBLOX_GPS::sendCommand(ubxPacket outgoingUBX, uint16_t ma retVal = sendI2cCommand(outgoingUBX, maxWait); if (retVal != SFE_UBLOX_STATUS_SUCCESS) { - debugPrintln((char *)F("Send I2C Command failed")); + if (_printDebug == true) + { + _debugSerial->println(F("Send I2C Command failed")); + } return retVal; } } @@ -787,12 +826,18 @@ sfe_ublox_status_e SFE_UBLOX_GPS::sendCommand(ubxPacket outgoingUBX, uint16_t ma //Depending on what we just sent, either we need to look for an ACK or not if (outgoingUBX.cls == UBX_CLASS_CFG) { - debugPrintln((char *)F("sendCommand: Waiting for ACK response")); + if (_printDebug == true) + { + _debugSerial->println(F("sendCommand: Waiting for ACK response")); + } retVal = waitForACKResponse(outgoingUBX.cls, outgoingUBX.id, maxWait); //Wait for Ack response } else { - debugPrintln((char *)F("sendCommand: Waiting for No ACK response")); + if (_printDebug == true) + { + _debugSerial->println(F("sendCommand: Waiting for No ACK response")); + } retVal = waitForNoACKResponse(outgoingUBX.cls, outgoingUBX.id, maxWait); //Wait for Ack response } } @@ -897,9 +942,13 @@ boolean SFE_UBLOX_GPS::isConnected() packetCfg.len = 0; packetCfg.startingSpot = 0; - return sendCommand(packetCfg); + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got an ACK and a valid packetCfg + // (module is responding with register content) + sfe_ublox_status_e retVal = sendCommand(packetCfg); // Use default maxWait + if (retVal == SFE_UBLOX_STATUS_DATA_RECEIVED) + return (true); } - return false; + return (false); } //Given a message, calc and store the two byte "8-Bit Fletcher" checksum over the entirety of the message @@ -956,6 +1005,10 @@ void SFE_UBLOX_GPS::printPacket(ubxPacket *packet) _debugSerial->print(F(" ID:")); if (packet->cls == UBX_CLASS_NAV && packet->id == UBX_NAV_PVT) _debugSerial->print("PVT"); + else if (packet->cls == UBX_CLASS_CFG && packet->id == UBX_CFG_VALSET) + _debugSerial->print("VALSET"); + else if (packet->cls == UBX_CLASS_CFG && packet->id == UBX_CFG_VALGET) + _debugSerial->print("VALGET"); else _debugSerial->print(packet->id, HEX); @@ -976,22 +1029,37 @@ void SFE_UBLOX_GPS::printPacket(ubxPacket *packet) //=-=-=-=-=-=-=-= Specific commands =-=-=-=-=-=-=-==-=-=-=-=-=-=-= //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +//waitForACKResponse: + //When messages from the class CFG are sent to the receiver, the receiver will send an "acknowledge"(UBX - ACK - ACK) or a //"not acknowledge"(UBX-ACK-NAK) message back to the sender, depending on whether or not the message was processed correctly. //Some messages from other classes also use the same acknowledgement mechanism. -//If the packetCfg len is 1, then we are querying the device for data -//If the packetCfg len is >1, then we are sending a new setting +//When we poll or get a setting, we will receive _both_ a config packet and an ACK +//If the poll or get request is not valid, we will receive _only_ a NACK -//Returns true if we got the following: -//* If packetCfg len is 1 and we got and ACK and a valid packetCfg (module is responding with register content) -//* If packetCfg len is >1 and we got an ACK (no valid packetCfg needed, module absorbs new register data) -//Returns false if we timed out, got a NACK (command unknown), or had a CLS/ID mismatch +//If we are trying to get or poll a setting, then packetCfg.len will be 0 or 1 when the packetCfg is _sent_. +//If we poll the setting for a particular port using UBX-CFG-PRT then .len will be 1 initially +//For all other gets or polls, .len will be 0 initially +//(It would be possible for .len to be 2 _if_ we were using UBX-CFG-MSG to poll the settings for a particular message - but we don't use that (currently)) + +//If the get or poll _fails_, i.e. is NACK'd, then packetCfg.len could still be 0 or 1 after the NACK is received +//But if the get or poll is ACK'd, then packetCfg.len will have been updated by the incoming data and will always be at least 2 + +//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) +//And we are only expecting an ACK (or a NACK) in return. + +//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_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 = false; //This will go true when we receive a response to the packet we sent - packetAck.valid = false; + 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; unsigned long startTime = millis(); while (millis() - startTime < maxTime) @@ -1008,43 +1076,54 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(uint8_t requestedClass, uin _debugSerial->println(F(" msec")); } - //Are we expecting data back or just an ACK? - if (packetCfg.len == 1) + //We've got the a valid ACK for this CLS/ID, so is packetCfg valid? + if (packetCfg.valid == SFE_UBLOX_PACKET_VALIDITY_VALID) { - //We are expecting a data response so now we verify the response packet was valid - if (packetCfg.valid == true) + //We've got a valid packetCfg, so does it match the requested Class and ID? + if (packetCfg.cls == requestedClass && packetCfg.id == requestedID) { - if (packetCfg.cls == requestedClass && packetCfg.id == requestedID) + if (_printDebug == true) { - 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! + _debugSerial->print(F("waitForACKResponse: CLS/ID match after ")); + _debugSerial->print(millis() - startTime); + _debugSerial->println(F(" msec")); } - else + 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) { - //Reset packet and continue checking incoming data for matching cls/id - debugPrintln((char *)F("waitForACKResponse: CLS/ID mismatch, continue to wait...")); - packetCfg.valid = false; //This will go true when we receive a response to the packet we sent + _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 } - else + } + //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) + { + //We were expecting data but didn't get a valid config packet + if (_printDebug == true) { - //We were expecting data but didn't get a valid config packet - debugPrintln((char *)F("waitForACKResponse: Invalid config packet")); - return (SFE_UBLOX_STATUS_FAIL); //We got an ACK, we're never going to get valid config data + _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 } + //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 { //We have sent new data. We expect an ACK but no return config packet. - debugPrintln((char *)F("waitForACKResponse: New data successfully sent")); + if (_printDebug == true) + { + _debugSerial->println(F("waitForACKResponse: New data successfully sent")); + } return (SFE_UBLOX_STATUS_DATA_SENT); //New data successfully sent } } + //Did we receive a NACK? else if (commandAck == UBX_ACK_NACK) { if (_printDebug == true) @@ -1062,9 +1141,12 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(uint8_t requestedClass, uin //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 == true) + if (packetCfg.valid == SFE_UBLOX_PACKET_VALIDITY_VALID) { - debugPrintln((char *)F("waitForACKResponse: Config was valid but ACK not received")); + if (_printDebug == true) + { + _debugSerial->println(F("waitForACKResponse: Config was valid but ACK not received")); + } } if (_printDebug == true) @@ -1077,13 +1159,14 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(uint8_t requestedClass, uin return (SFE_UBLOX_STATUS_TIMEOUT); } -//For non-CFG queries no ACK is sent so we use this function -//Returns true if we got a config packet full of response data that has CLS/ID match to our query packet -//Returns false if we timed out +//waitForNoACKResponse: for non-CFG queries no ACK is sent so we use this function +//Returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got a valid config packet full of response data that has CLS/ID match to our query packet +//Returns SFE_UBLOX_STATUS_CRC_FAIL if we received an invalid packet (checksum failure) +//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) { - packetCfg.valid = false; //This will go true when we receive a response to the packet we sent - packetAck.valid = false; + 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.id = 255; @@ -1093,10 +1176,10 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(uint8_t requestedClass, u if (checkUblox() == 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) + if (packetCfg.cls == requestedClass && packetCfg.id == requestedID && packetCfg.valid != SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED) { //This packet might be good or it might be CRC corrupt - if (packetCfg.valid == true) + if (packetCfg.valid == SFE_UBLOX_PACKET_VALIDITY_VALID) { if (_printDebug == true) { @@ -1106,18 +1189,21 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(uint8_t requestedClass, u } return (SFE_UBLOX_STATUS_DATA_RECEIVED); //We have new data to act upon } - else + else //if (packetCfg.valid == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) { - debugPrintln((char *)F("waitForNoACKResponse: CLS/ID match but failed CRC")); + 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 } } - else if (packetCfg.cls < 255 && packetCfg.id < 255) + else if (packetCfg.cls < 255 && packetCfg.id < 255 && packetCfg.valid != SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED) { //Reset packet and continue checking incoming data for matching cls/id if (_printDebug == true) { - debugPrint((char *)F("waitForNoACKResponse: CLS/ID mismatch: ")); + _debugSerial->print(F("waitForNoACKResponse: CLS/ID mismatch: ")); _debugSerial->print(F("CLS: ")); _debugSerial->print(packetCfg.cls, HEX); _debugSerial->print(F(" ID: ")); @@ -1125,7 +1211,7 @@ sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(uint8_t requestedClass, u _debugSerial->println(); } - packetCfg.valid = false; //This will go true when we receive a response to the packet we sent + 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; } @@ -1159,7 +1245,9 @@ 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 - if (sendCommand(packetCfg, maxWait) == false) + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_SENT if it got an ACK and no packetCfg + // (no valid packetCfg needed, module absorbs new register data) + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) return (false); //If command send fails then bail return (true); @@ -1181,7 +1269,9 @@ boolean SFE_UBLOX_GPS::factoryDefault(uint16_t maxWait) packetCfg.payload[0] = 0xFF; //Set any bit in the clearMask field to clear saved config packetCfg.payload[8] = 0xFF; //Set any bit in the loadMask field to discard current config and rebuild from lower non-volatile memory layers - if (sendCommand(packetCfg, maxWait) == false) + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_SENT if it got an ACK and no packetCfg + // (no valid packetCfg needed, module absorbs new register data) + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) return (false); //If command send fails then bail return (true); @@ -1240,7 +1330,10 @@ uint8_t SFE_UBLOX_GPS::getVal8(uint32_t key, uint8_t layer, uint16_t maxWait) } //Send VALGET command with this key - if (sendCommand(packetCfg, maxWait) == false) + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got an ACK and a valid packetCfg + // (module is responding with register content) + // PZC: THIS NEEDS TESTING! Does VALGET return a packet _and_ an ACK? + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) return (false); //If command send fails then bail //Verify the response is the correct length as compared to what the user called (did the module respond with 8-bits but the user called getVal32?) @@ -1290,7 +1383,10 @@ 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 - if (sendCommand(packetCfg, maxWait) == false) + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_SENT if it got an ACK and no packetCfg + // (no valid packetCfg needed, module absorbs new register data) + // PZC: THIS NEEDS TESTING! Does VALSET only return an ACK? + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) return (false); //If command send fails then bail //All done @@ -1325,7 +1421,10 @@ 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 - if (sendCommand(packetCfg, maxWait) == false) + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_SENT if it got an ACK and no packetCfg + // (no valid packetCfg needed, module absorbs new register data) + // PZC: THIS NEEDS TESTING! Does VALSET only return an ACK? + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) return (false); //If command send fails then bail //All done @@ -1363,7 +1462,10 @@ 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 - if (sendCommand(packetCfg, maxWait) == false) + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_SENT if it got an ACK and no packetCfg + // (no valid packetCfg needed, module absorbs new register data) + // PZC: THIS NEEDS TESTING! Does VALSET only return an ACK? + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) return (false); //If command send fails then bail //All done @@ -1539,7 +1641,10 @@ 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 - if (sendCommand(packetCfg, maxWait) == false) + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_SENT if it got an ACK and no packetCfg + // (no valid packetCfg needed, module absorbs new register data) + // PZC: THIS NEEDS TESTING! Does VALSET only return an ACK? + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) return (false); //If command send fails then bail //All done @@ -1554,7 +1659,10 @@ 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 - if (sendCommand(packetCfg, maxWait) == false) + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_SENT if it got an ACK and no packetCfg + // (no valid packetCfg needed, module absorbs new register data) + // PZC: THIS NEEDS TESTING! Does VALSET only return an ACK? + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) return (false); //If command send fails then bail //All done @@ -1569,7 +1677,10 @@ 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 - if (sendCommand(packetCfg, maxWait) == false) + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_SENT if it got an ACK and no packetCfg + // (no valid packetCfg needed, module absorbs new register data) + // PZC: THIS NEEDS TESTING! Does VALSET only return an ACK? + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) return (false); //If command send fails then bail //All done @@ -1584,7 +1695,13 @@ boolean SFE_UBLOX_GPS::getSurveyMode(uint16_t maxWait) packetCfg.len = 0; packetCfg.startingSpot = 0; - return (sendCommand(packetCfg, maxWait)); + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got an ACK and a valid packetCfg + // (module is responding with register content) + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) + return (false); + + //All done + return (true); } //Control Survey-In for NEO-M8P @@ -1613,7 +1730,13 @@ boolean SFE_UBLOX_GPS::setSurveyMode(uint8_t mode, uint16_t observationTime, flo payloadCfg[29] = svinAccLimit >> 8; payloadCfg[30] = svinAccLimit >> 16; - return (sendCommand(packetCfg, maxWait)); //Wait for ack + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_SENT if it got an ACK and no packetCfg + // (no valid packetCfg needed, module absorbs new register data) + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) + return (false); + + //All done + return (true); } //Begin Survey-In for NEO-M8P @@ -1644,7 +1767,9 @@ boolean SFE_UBLOX_GPS::getSurveyStatus(uint16_t maxWait) packetCfg.len = 0; packetCfg.startingSpot = 0; - if (sendCommand(packetCfg, maxWait) == false) + // waitForNoACKResponse returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got a valid packetCfg + // (module is responding with register content) + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) return (false); //If command send fails then bail //We got a response, now parse the bits into the svin structure @@ -1669,7 +1794,13 @@ boolean SFE_UBLOX_GPS::getPortSettings(uint8_t portID, uint16_t maxWait) payloadCfg[0] = portID; - return (sendCommand(packetCfg, maxWait)); + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got an ACK and a valid packetCfg + // (module is responding with register content) + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) + return (false); //If command send fails then bail + + //All done + return (true); } //Configure a given port to output UBX, NMEA, RTCM3 or a combination thereof @@ -1683,7 +1814,10 @@ boolean SFE_UBLOX_GPS::setPortOutput(uint8_t portID, uint8_t outStreamSettings, if (commandAck != UBX_ACK_ACK) { - debugPrintln((char *)F("setPortOutput failed to ACK")); + if (_printDebug == true) + { + _debugSerial->println(F("setPortOutput failed to ACK")); + } return (false); } @@ -1695,7 +1829,13 @@ 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)); + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_SENT if it got an ACK and no packetCfg + // (no valid packetCfg needed, module absorbs new register data) + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) + return (false); + + //All done + return (true); } //Configure a given port to input UBX, NMEA, RTCM3 or a combination thereof @@ -1716,7 +1856,13 @@ 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)); + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_SENT if it got an ACK and no packetCfg + // (no valid packetCfg needed, module absorbs new register data) + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) + return (false); + + //All done + return (true); } //Configure a port to output UBX, NMEA, RTCM3 or a combination thereof @@ -1757,8 +1903,11 @@ boolean SFE_UBLOX_GPS::setNavigationFrequency(uint8_t navFreq, uint16_t maxWait) packetCfg.len = 0; packetCfg.startingSpot = 0; - if (sendCommand(packetCfg, maxWait) == false) //This will load the payloadCfg array with current settings of the given register - return (false); //If command send fails then bail + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got an ACK and a valid packetCfg + // (module is responding with register content) + //This will load the payloadCfg array with current settings of the given register + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) + return (false); //If command send fails then bail uint16_t measurementRate = 1000 / navFreq; @@ -1766,7 +1915,13 @@ boolean SFE_UBLOX_GPS::setNavigationFrequency(uint8_t navFreq, uint16_t maxWait) payloadCfg[0] = measurementRate & 0xFF; //measRate LSB payloadCfg[1] = measurementRate >> 8; //measRate MSB - return (sendCommand(packetCfg, maxWait)); + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_SENT if it got an ACK and no packetCfg + // (no valid packetCfg needed, module absorbs new register data) + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) + return (false); + + //All done + return (true); } //Get the rate at which the module is outputting nav solutions @@ -1778,8 +1933,11 @@ uint8_t SFE_UBLOX_GPS::getNavigationFrequency(uint16_t maxWait) packetCfg.len = 0; packetCfg.startingSpot = 0; - if (sendCommand(packetCfg, maxWait) == false) //This will load the payloadCfg array with current settings of the given register - return (0); //If command send fails then bail + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got an ACK and a valid packetCfg + // (module is responding with register content) + //This will load the payloadCfg array with current settings of the given register + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) + return (0); //If command send fails then bail uint16_t measurementRate = 0; @@ -1822,7 +1980,11 @@ 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. - bool ok = sendCommand(packetCfg, maxWait); + bool ok = true; + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_SENT if it got an ACK and no packetCfg + // (no valid packetCfg needed, module absorbs new register data) + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) + ok = false; if (ok) { autoPVT = enable; @@ -1848,7 +2010,13 @@ 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)); + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_SENT if it got an ACK and no packetCfg + // (no valid packetCfg needed, module absorbs new register data) + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) + return (false); + + //All done + return (true); } //Enable a given message type, default of 1 per update rate (usually 1 per second) @@ -1986,7 +2154,13 @@ 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)); //Wait for ack + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_SENT if it got an ACK and no packetCfg + // (no valid packetCfg needed, module absorbs new register data) + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) + return (false); + + //All done + return (true); } //Clear all geofences using UBX-CFG-GEOFENCE @@ -2008,7 +2182,13 @@ boolean SFE_UBLOX_GPS::clearGeofences(uint16_t maxWait) currentGeofenceParams.numFences = 0; // Zero the number of geofences currently in use - return (sendCommand(packetCfg, maxWait)); //Wait for ack + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_SENT if it got an ACK and no packetCfg + // (no valid packetCfg needed, module absorbs new register data) + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) + return (false); + + //All done + return (true); } //Clear the antenna control settings using UBX-CFG-ANT @@ -2026,7 +2206,13 @@ 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)); //Wait for ack + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_SENT if it got an ACK and no packetCfg + // (no valid packetCfg needed, module absorbs new register data) + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) + return (false); + + //All done + return (true); } //Returns the combined geofence state using UBX-NAV-GEOFENCE @@ -2037,7 +2223,10 @@ boolean SFE_UBLOX_GPS::getGeofenceState(geofenceState ¤tGeofenceState, uin packetCfg.len = 0; packetCfg.startingSpot = 0; - if (sendCommand(packetCfg, maxWait) == false) //Ask module for the geofence status. Loads into payloadCfg. + // waitForNoACKResponse returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got a valid packetCfg + // (module is responding with register content) + //Ask module for the geofence status. Loads into payloadCfg. + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) return (false); currentGeofenceState.status = payloadCfg[5]; // Extract the status @@ -2070,7 +2259,10 @@ boolean SFE_UBLOX_GPS::powerSaveMode(bool power_save, uint16_t maxWait) */ if (protVer >= 27) { - debugPrintln((char *)F("powerSaveMode (UBX-CFG-RXM) is not supported by this protocol version")); + if (_printDebug == true) + { + _debugSerial->println(F("powerSaveMode (UBX-CFG-RXM) is not supported by this protocol version")); + } return (false); } @@ -2080,7 +2272,10 @@ boolean SFE_UBLOX_GPS::powerSaveMode(bool power_save, uint16_t maxWait) packetCfg.len = 0; packetCfg.startingSpot = 0; - if (sendCommand(packetCfg, maxWait) == false) //Ask module for the current power management settings. Loads into payloadCfg. + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got an ACK and a valid packetCfg + // (module is responding with register content) + //Ask module for the current power management settings. Loads into payloadCfg. + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) return (false); if (power_save) @@ -2095,7 +2290,13 @@ boolean SFE_UBLOX_GPS::powerSaveMode(bool power_save, uint16_t maxWait) packetCfg.len = 2; packetCfg.startingSpot = 0; - return (sendCommand(packetCfg, maxWait)); //Wait for ack + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_SENT if it got an ACK and no packetCfg + // (no valid packetCfg needed, module absorbs new register data) + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) + return (false); + + //All done + return (true); } //Change the dynamic platform model using UBX-CFG-NAV5 @@ -2111,7 +2312,10 @@ boolean SFE_UBLOX_GPS::setDynamicModel(dynModel newDynamicModel, uint16_t maxWai packetCfg.len = 0; packetCfg.startingSpot = 0; - if (sendCommand(packetCfg, maxWait) == false) //Ask module for the current navigation model settings. Loads into payloadCfg. + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got an ACK and a valid packetCfg + // (module is responding with register content) + //Ask module for the current navigation model settings. Loads into payloadCfg. + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) return (false); payloadCfg[0] = 0x01; // mask: set only the dyn bit (0) @@ -2121,7 +2325,13 @@ boolean SFE_UBLOX_GPS::setDynamicModel(dynModel newDynamicModel, uint16_t maxWai packetCfg.len = 36; packetCfg.startingSpot = 0; - return (sendCommand(packetCfg, maxWait)); //Wait for ack + // waitForACKResponse returns SFE_UBLOX_STATUS_DATA_SENT if it got an ACK and no packetCfg + // (no valid packetCfg needed, module absorbs new register data) + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) + return (false); + + //All done + return (true); } //Given a spot in the payload array, extract four bytes and build a long @@ -2228,25 +2438,35 @@ boolean SFE_UBLOX_GPS::getPVT(uint16_t maxWait) if (autoPVT && autoPVTImplicitUpdate) { //The GPS is automatically reporting, we just check whether we got unread data - debugPrintln((char *)F("getPVT: Autoreporting")); + if (_printDebug == true) + { + _debugSerial->println(F("getPVT: Autoreporting")); + } checkUblox(); return moduleQueried.all; } else if (autoPVT && !autoPVTImplicitUpdate) { //Someone else has to call checkUblox for us... - debugPrintln((char *)F("getPVT: Exit immediately")); + if (_printDebug == true) + { + _debugSerial->println(F("getPVT: Exit immediately")); + } return (false); } else { - debugPrintln((char *)F("getPVT: Polling")); + if (_printDebug == true) + { + _debugSerial->println(F("getPVT: Polling")); + } //The GPS is not automatically reporting navigation position so we have to poll explicitly packetCfg.cls = UBX_CLASS_NAV; packetCfg.id = UBX_NAV_PVT; packetCfg.len = 0; //packetCfg.startingSpot = 20; //Begin listening at spot 20 so we can record up to 20+MAX_PAYLOAD_SIZE = 84 bytes Note:now hard-coded in processUBX + packetCfg.startingSpot = 0; //The data is parsed as part of processing the response sfe_ublox_status_e retVal = sendCommand(packetCfg, maxWait); @@ -2334,8 +2554,13 @@ boolean SFE_UBLOX_GPS::getHPPOSLLH(uint16_t maxWait) packetCfg.id = UBX_NAV_HPPOSLLH; packetCfg.len = 0; - return sendCommand(packetCfg, maxWait); - return (false); //If command send fails then bail + // waitForNoACKResponse returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got a valid packetCfg + // (module is responding with register content) + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) + return (false); //If command send fails then bail + + //All done + return (true); } //Get the current 3D high precision positional accuracy - a fun thing to watch @@ -2347,7 +2572,9 @@ uint32_t SFE_UBLOX_GPS::getPositionAccuracy(uint16_t maxWait) packetCfg.len = 0; packetCfg.startingSpot = 0; - if (sendCommand(packetCfg, maxWait) == false) + // waitForNoACKResponse returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got a valid packetCfg + // (module is responding with register content) + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) 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 @@ -2507,7 +2734,9 @@ 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) == false) + // waitForNoACKResponse returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got a valid packetCfg + // (module is responding with register content) + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) return (false); //If command send fails then bail //Payload should now contain ~220 characters (depends on module type) @@ -2583,7 +2812,9 @@ boolean SFE_UBLOX_GPS::getRELPOSNED(uint16_t maxWait) packetCfg.len = 0; packetCfg.startingSpot = 0; - if (sendCommand(packetCfg, maxWait) == false) + // waitForNoACKResponse returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got a valid packetCfg + // (module is responding with register content) + if (sendCommand(packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) 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 843a203..dbedc93 100644 --- a/src/SparkFun_Ublox_Arduino_Library.h +++ b/src/SparkFun_Ublox_Arduino_Library.h @@ -84,8 +84,8 @@ const int checksumFailurePin = -1; // Global Status Returns typedef enum { - SFE_UBLOX_STATUS_SUCCESS, - SFE_UBLOX_STATUS_FAIL, + SFE_UBLOX_STATUS_FAIL = 0, // FAIL == 0 + SFE_UBLOX_STATUS_SUCCESS, // SUCCESS == 1 SFE_UBLOX_STATUS_CRC_FAIL, SFE_UBLOX_STATUS_TIMEOUT, SFE_UBLOX_STATUS_COMMAND_UNKNOWN, @@ -99,6 +99,13 @@ typedef enum SFE_UBLOX_STATUS_I2C_COMM_FAILURE, } sfe_ublox_status_e; +typedef enum +{ + SFE_UBLOX_PACKET_VALIDITY_NOT_VALID = 0, // NOT_VALID == 0 + SFE_UBLOX_PACKET_VALIDITY_VALID, // VALID == 1 + SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED +} sfe_ublox_packet_validity_e; + //Registers const uint8_t UBX_SYNCH_1 = 0xB5; const uint8_t UBX_SYNCH_2 = 0x62; @@ -244,7 +251,7 @@ typedef struct uint8_t *payload; uint8_t checksumA; //Given to us from module. Checked against the rolling calculated A/B checksums. uint8_t checksumB; - boolean valid; //Goes true when both checksums pass + sfe_ublox_packet_validity_e valid; //Goes from NOT_DEFINED to VALID or NOT_VALID when checksum is checked } ubxPacket; // Struct to hold the results returned by getGeofenceState (returned by UBX-NAV-GEOFENCE) @@ -545,8 +552,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, false}; - ubxPacket packetCfg = {0, 0, 0, 0, 0, payloadCfg, 0, 0, false}; + 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}; //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