From 48ace0a29f460a102ada0cd666b9c7f1f784fb4a Mon Sep 17 00:00:00 2001 From: Andrew Berridge Date: Sun, 27 Jun 2021 06:00:16 +0100 Subject: [PATCH 1/6] Add support for SPI interface --- src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 121 +++++++++++++++++++ src/SparkFun_u-blox_GNSS_Arduino_Library.h | 18 ++- 2 files changed, 138 insertions(+), 1 deletion(-) diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index bc45a0c..ae80176 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -451,6 +451,35 @@ boolean SFE_UBLOX_GNSS::begin(Stream &serialPort) return (connected); } +// Initialize for SPI +boolean SFE_UBLOX_GNSS::begin(SPIClass &spiPort, uint8_t ssPin, int spiSpeed) +{ + commType = COMM_TYPE_SPI; + _spiPort = &spiPort; + _ssPin = ssPin; + _spiSpeed = spiSpeed; + //New in v2.0: allocate memory for the packetCfg payload here - if required. (The user may have called setPacketCfgPayloadSize already) + if (packetCfgPayloadSize == 0) + setPacketCfgPayloadSize(MAX_PAYLOAD_SIZE); + Serial.println("Creating buffer"); + createFileBuffer(); + boolean connected = isConnected(); + if (!connected) + connected = isConnected(); + + if (!connected) + connected = isConnected(); + + // Initialize/clear the SPI buffer - fill it with 0xFF as this is what is received from the UBLOX module if there's no data to be processed + for (uint8_t i = 0; i < 20; i++) + { + spiBuffer[i] = 0xFF; + } + + return (connected); +} + + // Allow the user to change I2C polling wait (the minimum interval between I2C data requests - to avoid pounding the bus) // i2cPollingWait defaults to 100ms and is adjusted automatically when setNavigationFrequency() // or setHNRNavigationRate() are called. But if the user is using callbacks, it might be advantageous @@ -598,6 +627,8 @@ boolean SFE_UBLOX_GNSS::checkUbloxInternal(ubxPacket *incomingUBX, uint8_t reque return (checkUbloxI2C(incomingUBX, requestedClass, requestedID)); else if (commType == COMM_TYPE_SERIAL) return (checkUbloxSerial(incomingUBX, requestedClass, requestedID)); + else if (commType == COMM_TYPE_SPI) + return (checkUbloxSpi(incomingUBX, requestedClass, requestedID)); return false; } @@ -755,6 +786,42 @@ boolean SFE_UBLOX_GNSS::checkUbloxSerial(ubxPacket *incomingUBX, uint8_t request } //end checkUbloxSerial() + +//Checks SPI for data, passing any new bytes to process() +boolean SFE_UBLOX_GNSS::checkUbloxSpi(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) +{ + // process the contents of the SPI buffer if not empty! + uint8_t bufferByte = spiBuffer[0]; + uint8_t bufferIndex = 0; + + while (bufferByte != 0xFF) { + process(bufferByte, incomingUBX, requestedClass, requestedID); + bufferIndex++; + bufferByte = spiBuffer[bufferIndex]; + } + + // reset the contents of the SPI buffer + for(uint8_t i = 0; i < bufferIndex; i++) + { + spiBuffer[i] = 0xFF; + } + + SPISettings settingsA(_spiSpeed, MSBFIRST, SPI_MODE0); + _spiPort->beginTransaction(settingsA); + digitalWrite(_ssPin, LOW); + uint8_t byteReturned = _spiPort->transfer(0x0A); + while (byteReturned != 0xFF || currentSentence != NONE) + { + process(byteReturned, incomingUBX, requestedClass, requestedID); + byteReturned = _spiPort->transfer(0x0A); + } + digitalWrite(_ssPin, HIGH); + _spiPort->endTransaction(); + return (true); + +} //end checkUbloxSpi() + + //PRIVATE: Check if we have storage allocated for an incoming "automatic" message boolean SFE_UBLOX_GNSS::checkAutomatic(uint8_t Class, uint8_t ID) { @@ -2675,6 +2742,10 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::sendCommand(ubxPacket *outgoingUBX, uint16_t { sendSerialCommand(outgoingUBX); } + else if (commType == COMM_TYPE_SPI) + { + sendSpiCommand(outgoingUBX); + } if (maxWait > 0) { @@ -2781,6 +2852,56 @@ void SFE_UBLOX_GNSS::sendSerialCommand(ubxPacket *outgoingUBX) _serialPort->write(outgoingUBX->checksumB); } + +// Transfer a byte to SPI. Also capture any bytes received from the UBLOX device during sending and capture them in a small buffer so that +// they can be processed later with process +void SFE_UBLOX_GNSS::spiTransfer(uint8_t byteToTransfer) +{ + uint8_t returnedByte = _spiPort->transfer(byteToTransfer); + if (returnedByte != 0xFF) + { + spiBuffer[spiBufferIndex] = returnedByte; + spiBufferIndex++; + } +} + +// Send a command via SPI +void SFE_UBLOX_GNSS::sendSpiCommand(ubxPacket *outgoingUBX) +{ + SPISettings settingsA(_spiSpeed, MSBFIRST, SPI_MODE0); + _spiPort->beginTransaction(settingsA); + digitalWrite(_ssPin, LOW); + //Write header bytes + spiTransfer(UBX_SYNCH_1); //μ - oh ublox, you're funny. I will call you micro-blox from now on. + if (_printDebug) _debugSerial->printf("%x ", UBX_SYNCH_1); + spiTransfer(UBX_SYNCH_2); //b + if (_printDebug) _debugSerial->printf("%x ", UBX_SYNCH_2); + + spiTransfer(outgoingUBX->cls); + if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->cls); + spiTransfer(outgoingUBX->id); + if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->id); + spiTransfer(outgoingUBX->len & 0xFF); //LSB + if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->len & 0xFF); + spiTransfer(outgoingUBX->len >> 8); + if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->len >> 8); + + //Write payload. + for (uint16_t i = 0; i < outgoingUBX->len; i++) + { + spiTransfer(outgoingUBX->payload[i]); + if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->payload[i]); + } + + //Write checksum + spiTransfer(outgoingUBX->checksumA); + if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->checksumA); + spiTransfer(outgoingUBX->checksumB); + if (_printDebug) _debugSerial->printf("%x \n", outgoingUBX->checksumB); + digitalWrite(_ssPin, HIGH); + _spiPort->endTransaction(); +} + //Pretty prints the current ubxPacket void SFE_UBLOX_GNSS::printPacket(ubxPacket *packet, boolean alwaysPrintPayload) { diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.h b/src/SparkFun_u-blox_GNSS_Arduino_Library.h index 42e72eb..015ba3f 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.h +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.h @@ -51,6 +51,8 @@ #include +#include + #include "u-blox_config_keys.h" #include "u-blox_structs.h" @@ -560,6 +562,8 @@ class SFE_UBLOX_GNSS boolean begin(TwoWire &wirePort = Wire, uint8_t deviceAddress = 0x42); //Returns true if module is detected //serialPort needs to be perviously initialized to correct baud rate boolean begin(Stream &serialPort); //Returns true if module is detected + //SPI - supply instance of SPIClass, slave select pin and SPI speed (in Hz) + boolean begin(SPIClass &spiPort, uint8_t ssPin, int spiSpeed); void end(void); //Stop all automatic message processing. Free all used RAM @@ -612,6 +616,7 @@ class SFE_UBLOX_GNSS boolean checkUbloxI2C(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID); //Method for I2C polling of data, passing any new bytes to process() boolean checkUbloxSerial(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID); //Method for serial polling of data, passing any new bytes to process() + boolean checkUbloxSpi(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID); //Method for spi polling of data, passing any new bytes to process() // Process the incoming data @@ -622,12 +627,13 @@ class SFE_UBLOX_GNSS void processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID); //Given a character, file it away into the uxb packet structure void processUBXpacket(ubxPacket *msg); //Once a packet has been received and validated, identify this packet's class/id and update internal flags - // Send I2C/Serial commands to the module + // Send I2C/Serial/SPI commands to the module void calcChecksum(ubxPacket *msg); //Sets the checksumA and checksumB of a given messages sfe_ublox_status_e sendCommand(ubxPacket *outgoingUBX, uint16_t maxWait = defaultMaxWait, boolean expectACKonly = false); //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 = defaultMaxWait); void sendSerialCommand(ubxPacket *outgoingUBX); + void sendSpiCommand(ubxPacket *outgoingUBX); void printPacket(ubxPacket *packet, boolean alwaysPrintPayload = false); //Useful for debugging @@ -1235,6 +1241,9 @@ class SFE_UBLOX_GNSS //Calculate how much RAM is needed to store the payload for a given automatic message uint16_t getMaxPayloadSize(uint8_t Class, uint8_t ID); + //Do the actual transfer to SPI + void spiTransfer(uint8_t byteToTransfer); + boolean initGeofenceParams(); // Allocate RAM for currentGeofenceParams and initialize it boolean initModuleSWVersion(); // Allocate RAM for moduleSWVersion and initialize it @@ -1273,6 +1282,10 @@ class SFE_UBLOX_GNSS Stream *_nmeaOutputPort = NULL; //The user can assign an output port to print NMEA sentences if they wish Stream *_debugSerial; //The stream to send debug messages to if enabled + SPIClass *_spiPort; //The instance of SPIClass + uint8_t _ssPin; //The slave select pin + int _spiSpeed; //The speed to use for SPI (Hz) + uint8_t _gpsI2Caddress = 0x42; //Default 7-bit unshifted address of the ublox 6/7/8/M8/F9 series //This can be changed using the ublox configuration software @@ -1292,6 +1305,9 @@ class SFE_UBLOX_GNSS uint8_t *payloadCfg = NULL; uint8_t *payloadAuto = NULL; + uint8_t spiBuffer[20]; // A small buffer to store any bytes being recieved back from the device while we are sending via SPI + uint8_t spiBufferIndex = 0; // The index into the SPI buffer + //Init the packet structures and init them with pointers to the payloadAck, payloadCfg, payloadBuf and payloadAuto arrays ubxPacket packetAck = {0, 0, 0, 0, 0, payloadAck, 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}; From a92139ca53433a5f8490800b894759690e2410f3 Mon Sep 17 00:00:00 2001 From: Andrew Berridge Date: Sun, 27 Jun 2021 07:01:56 +0100 Subject: [PATCH 2/6] Improved state management - member functions on packet buffers indicate if the class and ID match, rather than using flags that get set during the process and processUBX functions. Still some tidy-up required, but makes debugging and maintenance easier and helps prevents some race conditions/panics/crashes (due to writing data where it shouldn't be written)! --- src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 275 ++++++++++--------- src/SparkFun_u-blox_GNSS_Arduino_Library.h | 13 +- 2 files changed, 152 insertions(+), 136 deletions(-) diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index ae80176..fde7f75 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -1084,6 +1084,8 @@ uint16_t SFE_UBLOX_GNSS::getMaxPayloadSize(uint8_t Class, uint8_t ID) //Processes NMEA and UBX binary sentences one byte at a time //Take a given byte and file it into the proper array +// Note - AJB - we will ALWAYS use packetBuf to receive incoming, and then process them into the +// appropriate packet structures void SFE_UBLOX_GNSS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) { if ((currentSentence == NONE) || (currentSentence == NMEA)) @@ -1096,6 +1098,8 @@ void SFE_UBLOX_GNSS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t r currentSentence = UBX; //Reset the packetBuf.counter even though we will need to reset it again when ubxFrameCounter == 2 packetBuf.counter = 0; + packetBuf.cls = 0; + packetBuf.id = 0; 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; @@ -1146,14 +1150,24 @@ void SFE_UBLOX_GNSS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t r if (packetBuf.cls != UBX_CLASS_ACK) { //This is not an ACK so check for a class and ID match - if ((packetBuf.cls == requestedClass) && (packetBuf.id == requestedID)) + if (packetBuf.isClassAndIdMatch(requestedClass, requestedID)) { + if (_printDebug) _debugSerial->println("got requested class and ID"); //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; - incomingUBX->cls = packetBuf.cls; //Copy the class and ID into incomingUBX (usually packetCfg) - incomingUBX->id = packetBuf.id; - incomingUBX->counter = packetBuf.counter; //Copy over the .counter too + //So start diverting data into the correct buffer + if (packetBuf.cls == UBX_CLASS_CFG) + { + if (_printDebug) _debugSerial->println("process: activeBuffer PACKETCFG"); + activePacketBuffer = SFE_UBLOX_PACKET_PACKETCFG; + packetCfg.cls = packetBuf.cls; + packetCfg.id = packetBuf.id; + packetCfg.counter = packetBuf.counter; + } + else + { + if (_printDebug) _debugSerial->println("process: activeBuffer PACKETBUF"); + activePacketBuffer = SFE_UBLOX_PACKET_PACKETBUF; + } } //This is not an ACK and we do not have a complete class and ID match //So let's check if this is an "automatic" message which has its own storage defined @@ -1196,8 +1210,9 @@ void SFE_UBLOX_GNSS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t r _debugSerial->println(packetBuf.id, HEX); _debugSerial->println(F("process: \"automatic\" message could overwrite data")); } - // The RAM allocation failed so fall back to using incomingUBX (usually packetCfg) even though we risk overwriting data - activePacketBuffer = SFE_UBLOX_PACKET_PACKETCFG; + // The RAM allocation failed so fall back to using incomingUBX (packetBuf) + // todo - tidy this! + activePacketBuffer = SFE_UBLOX_PACKET_PACKETBUF; incomingUBX->cls = packetBuf.cls; //Copy the class and ID into incomingUBX (usually packetCfg) incomingUBX->id = packetBuf.id; incomingUBX->counter = packetBuf.counter; //Copy over the .counter too @@ -1221,16 +1236,22 @@ void SFE_UBLOX_GNSS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t r } else { - //This is not an ACK and we do not have a class and ID match + //This is not an ACK, nor auto and we do not have a class and ID match //so we should keep diverting data into packetBuf and ignore the payload + if (_printDebug) _debugSerial->println("IGNORING!!!"); ignoreThisPayload = true; } } else - { - // 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 + { + // Ack packet! We can deal with it just like any other packet + // Then this is an ACK so copy it into packetAck + activePacketBuffer = SFE_UBLOX_PACKET_PACKETACK; + if (_printDebug) _debugSerial->println("process: activeBuffer PACKETACK"); + packetAck.cls = packetBuf.cls; + packetAck.id = packetBuf.id; + packetAck.counter = packetBuf.counter; + packetAck.startingSpot = packetBuf.startingSpot; } } else if (ubxFrameCounter == 4) //Length LSB @@ -1278,49 +1299,21 @@ void SFE_UBLOX_GNSS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t r 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 .len is 2 - { - // 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]; - } - else // Length is not 2 (hopefully this is impossible!) - { - if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging - { - _debugSerial->print(F("process: ACK received with .len != 2: Class: 0x")); - _debugSerial->print(packetBuf.payload[0], HEX); - _debugSerial->print(F(" ID: 0x")); - _debugSerial->print(packetBuf.payload[1], HEX); - _debugSerial->print(F(" len: ")); - _debugSerial->println(packetBuf.len); - } - } - } + } } - //Divert incoming into the correct buffer - if (activePacketBuffer == SFE_UBLOX_PACKET_PACKETACK) - processUBX(incoming, &packetAck, requestedClass, requestedID); - else if (activePacketBuffer == SFE_UBLOX_PACKET_PACKETCFG) - processUBX(incoming, incomingUBX, requestedClass, requestedID); - else if (activePacketBuffer == SFE_UBLOX_PACKET_PACKETBUF) - processUBX(incoming, &packetBuf, requestedClass, requestedID); - else // if (activePacketBuffer == SFE_UBLOX_PACKET_PACKETAUTO) - processUBX(incoming, &packetAuto, requestedClass, requestedID); - + if (ubxFrameCounter > 1) // we have passed the micro and b characters + { + //Divert incoming into the correct buffer + if (activePacketBuffer == SFE_UBLOX_PACKET_PACKETACK) + processUBX(incoming, &packetAck, requestedClass, requestedID); + else if (activePacketBuffer == SFE_UBLOX_PACKET_PACKETCFG) + processUBX(incoming, &packetCfg, requestedClass, requestedID); + else if (activePacketBuffer == SFE_UBLOX_PACKET_PACKETBUF) + processUBX(incoming, &packetBuf, requestedClass, requestedID); + else // if (activePacketBuffer == SFE_UBLOX_PACKET_PACKETAUTO) + processUBX(incoming, &packetAuto, requestedClass, requestedID); + } //Finally, increment the frame counter ubxFrameCounter++; } @@ -1528,24 +1521,26 @@ void SFE_UBLOX_GNSS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_ uint16_t maximum_payload_size; if (activePacketBuffer == SFE_UBLOX_PACKET_PACKETCFG) maximum_payload_size = packetCfgPayloadSize; - else if (activePacketBuffer == SFE_UBLOX_PACKET_PACKETAUTO) + else if (incomingUBX->counter > 1 // wait for class and ID + && (activePacketBuffer == SFE_UBLOX_PACKET_PACKETAUTO || activePacketBuffer == SFE_UBLOX_PACKET_PACKETBUF)) { // Calculate maximum payload size once Class and ID have been received // (This check is probably redundant as activePacketBuffer can only be SFE_UBLOX_PACKET_PACKETAUTO // when ubxFrameCounter >= 3) //if (incomingUBX->counter >= 2) //{ - maximum_payload_size = getMaxPayloadSize(incomingUBX->cls, incomingUBX->id); - if (maximum_payload_size == 0) + maximum_payload_size = getMaxPayloadSize(incomingUBX->cls, incomingUBX->id); + if (maximum_payload_size == 0) + { + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging { - if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging - { - _debugSerial->print(F("processUBX: getMaxPayloadSize returned ZERO!! Class: 0x")); - _debugSerial->print(incomingUBX->cls); - _debugSerial->print(F(" ID: 0x")); - _debugSerial->println(incomingUBX->id); - } + _debugSerial->print(F("processUBX: getMaxPayloadSize returned ZERO!! Class: 0x")); + _debugSerial->printf("%x", incomingUBX->cls); + _debugSerial->print(F(" ID: 0x")); + _debugSerial->printf("%x\n", incomingUBX->id); + } + } //} //else // maximum_payload_size = 2; @@ -1590,27 +1585,35 @@ void SFE_UBLOX_GNSS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_ if ((incomingUBX->checksumA == rollingChecksumA) && (incomingUBX->checksumB == rollingChecksumB)) { incomingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_VALID; // Flag the packet as valid + if (_printDebug) _debugSerial->println("processUBX packet is 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 + // ACK or NACK??? + if (incomingUBX->isAckForClassAndId(requestedClass, requestedID)) { + if (_printDebug) + { + _debugSerial->print(F("processUBX: ACK received: Requested Class: 0x")); + _debugSerial->print(incomingUBX->payload[0], HEX); + _debugSerial->print(F(" Requested ID: 0x")); + _debugSerial->println(incomingUBX->payload[1], HEX); + } } - // 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 + else if (incomingUBX->isAckForClassAndId(requestedClass, requestedID)) + { + if (_printDebug == true) + { + _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); + } } - // 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)) + else if (incomingUBX->isClassAndIdMatch(requestedClass, requestedID)) { - 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: 0x")); + _debugSerial->print(F("processUBX: Message received for requested Class: 0x")); _debugSerial->print(incomingUBX->payload[0], HEX); _debugSerial->print(F(" Requested ID: 0x")); _debugSerial->println(incomingUBX->payload[1], HEX); @@ -1639,22 +1642,6 @@ void SFE_UBLOX_GNSS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_ _debugSerial->print(F(" Received: ")); printPacket(incomingUBX); - if (incomingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_VALID) - { - _debugSerial->println(F("packetCfg now valid")); - } - if (packetAck.valid == SFE_UBLOX_PACKET_VALIDITY_VALID) - { - _debugSerial->println(F("packetAck now valid")); - } - if (incomingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) - { - _debugSerial->println(F("packetCfg classAndIDmatch")); - } - if (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) - { - _debugSerial->println(F("packetAck classAndIDmatch")); - } } //We've got a valid packet, now do something with it but only if ignoreThisPayload is false @@ -1718,11 +1705,16 @@ void SFE_UBLOX_GNSS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_ { //If an automatic packet comes in asynchronously, we need to fudge the startingSpot uint16_t startingSpot = incomingUBX->startingSpot; - if (checkAutomatic(incomingUBX->cls, incomingUBX->id)) + if (!incomingUBX->isClassAndIdMatch(requestedClass, requestedID) && checkAutomatic(incomingUBX->cls, incomingUBX->id)) + { + //_debugSerial->println("processUBX: incoming is automatic"); startingSpot = 0; + } + // Check if this is payload data which should be ignored if (ignoreThisPayload == false) { + //_debugSerial->printf("incomingUBX->counter: %d, startingSpot: %d, maximum_payload_size: %d", incomingUBX->counter, startingSpot, maximum_payload_size); //Begin recording if counter goes past startingSpot if ((incomingUBX->counter - 4) >= startingSpot) { @@ -2756,7 +2748,7 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::sendCommand(ubxPacket *outgoingUBX, uint16_t { _debugSerial->println(F("sendCommand: Waiting for ACK response")); } - retVal = waitForACKResponse(outgoingUBX, outgoingUBX->cls, outgoingUBX->id, maxWait); //Wait for Ack response + retVal = waitForACKResponse(outgoingUBX, outgoingUBX->cls, outgoingUBX->id, maxWait, expectACKonly); //Wait for Ack response } else { @@ -2989,7 +2981,7 @@ void SFE_UBLOX_GNSS::printPacket(ubxPacket *packet, boolean alwaysPrintPayload) //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_GNSS::waitForACKResponse(ubxPacket *outgoingUBX, uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime) +sfe_ublox_status_e SFE_UBLOX_GNSS::waitForACKResponse(ubxPacket *outgoingUBX, uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime, bool expectACKonly) { 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; @@ -3005,10 +2997,22 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForACKResponse(ubxPacket *outgoingUBX, ui { if (checkUbloxInternal(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 - // 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) && (outgoingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_VALID) && (outgoingUBX->cls == requestedClass) && (outgoingUBX->id == requestedID)) + + // If we are expecting an ACK only, return as soon as we have it! + if (expectACKonly && packetAck.isAckForClassAndId(requestedClass, requestedID) && packetAck.valid == SFE_UBLOX_PACKET_VALIDITY_VALID) + { + if (_printDebug == true) + { + _debugSerial->print(F("waitForACKResponse: expecting ACK only, and valid ACK received after ")); + _debugSerial->print(millis() - startTime); + _debugSerial->println(F(" msec")); + } + return (SFE_UBLOX_STATUS_DATA_SENT); //todo - AJB - I'd prefer another flag - ACK_RECEIVED or something like that! + } + + // If both the packetCfg->isClassAndIdMatch and packetAck.isClassAndIdMatch + // then we can be confident that the data in packetCfg is valid + if (packetAck.isAckForClassAndId(requestedClass, requestedID) && packetCfg.valid == SFE_UBLOX_PACKET_VALIDITY_VALID && packetAck.valid == SFE_UBLOX_PACKET_VALIDITY_VALID && packetCfg.isClassAndIdMatch(requestedClass, requestedID)) { if (_printDebug == true) { @@ -3024,7 +3028,7 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForACKResponse(ubxPacket *outgoingUBX, ui // 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 an automatic packet. - else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED) && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID)) + else if (!packetCfg.isClassAndIdMatch(requestedClass, requestedID) && packetAck.isClassAndIdMatch(requestedClass, requestedID)) { if (_printDebug == true) { @@ -3073,7 +3077,7 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForACKResponse(ubxPacket *outgoingUBX, ui // 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) + else if (packetAck.isNackForClassAndId(requestedClass, requestedID)) { if (_printDebug == true) { @@ -3131,7 +3135,7 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForACKResponse(ubxPacket *outgoingUBX, ui // We have timed out... // 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) && (outgoingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_VALID) && (outgoingUBX->cls == requestedClass) && (outgoingUBX->id == requestedID)) + if ((packetCfg.isClassAndIdMatch(requestedClass, requestedID) && !packetAck.isClassAndIdMatch(requestedClass, requestedID)) && (packetCfg.valid == SFE_UBLOX_PACKET_VALIDITY_VALID)) { if (_printDebug == true) { @@ -3172,13 +3176,13 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForNoACKResponse(ubxPacket *outgoingUBX, unsigned long startTime = millis(); while (millis() - startTime < maxTime) { - if (checkUbloxInternal(outgoingUBX, requestedClass, requestedID) == true) //See if new data is available. Process bytes as they come in. + if (checkUbloxInternal(&packetBuf, requestedClass, requestedID) == true) //See if new data is available. Process bytes as they come in. { // 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->cls == requestedClass) && (outgoingUBX->id == requestedID)) + if (packetBuf.isClassAndIdMatch(requestedClass, requestedID) && packetBuf.valid == SFE_UBLOX_PACKET_VALIDITY_VALID) { if (_printDebug == true) { @@ -3223,7 +3227,7 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForNoACKResponse(ubxPacket *outgoingUBX, } // If the outgoingUBX->classAndIDmatch is NOT_VALID then we return CRC failure - else if (outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) + /*else if (outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) { if (_printDebug == true) { @@ -3232,7 +3236,7 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForNoACKResponse(ubxPacket *outgoingUBX, _debugSerial->println(F(" msec")); } return (SFE_UBLOX_STATUS_CRC_FAIL); //We received invalid data - } + }*/ } delayMicroseconds(500); @@ -5410,7 +5414,7 @@ boolean SFE_UBLOX_GNSS::setAutoNAVPOSECEFrate(uint8_t rate, boolean implicitUpda payloadCfg[1] = UBX_NAV_POSECEF; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXNAVPOSECEF->automaticFlags.flags.bits.automatic = (rate > 0); @@ -5567,7 +5571,7 @@ boolean SFE_UBLOX_GNSS::setAutoNAVSTATUSrate(uint8_t rate, boolean implicitUpdat payloadCfg[1] = UBX_NAV_STATUS; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXNAVSTATUS->automaticFlags.flags.bits.automatic = (rate > 0); @@ -5744,7 +5748,7 @@ boolean SFE_UBLOX_GNSS::setAutoDOPrate(uint8_t rate, boolean implicitUpdate, uin payloadCfg[1] = UBX_NAV_DOP; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXNAVDOP->automaticFlags.flags.bits.automatic = (rate > 0); @@ -5907,7 +5911,7 @@ boolean SFE_UBLOX_GNSS::setAutoNAVATTrate(uint8_t rate, boolean implicitUpdate, payloadCfg[1] = UBX_NAV_ATT; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXNAVATT->automaticFlags.flags.bits.automatic = (rate > 0); @@ -6086,8 +6090,11 @@ boolean SFE_UBLOX_GNSS::setAutoPVTrate(uint8_t rate, boolean implicitUpdate, uin payloadCfg[0] = UBX_CLASS_NAV; payloadCfg[1] = UBX_NAV_PVT; payloadCfg[2] = rate; // rate relative to navigation freq. + packetCfg.payload = payloadCfg; + + // Payload is working here but again we get no ack! - boolean ok = ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + boolean ok = ((sendCommand(&packetCfg, maxWait, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXNAVPVT->automaticFlags.flags.bits.automatic = (rate > 0); @@ -6246,7 +6253,7 @@ boolean SFE_UBLOX_GNSS::setAutoNAVODOrate(uint8_t rate, boolean implicitUpdate, payloadCfg[1] = UBX_NAV_ODO; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXNAVODO->automaticFlags.flags.bits.automatic = (rate > 0); @@ -6402,7 +6409,7 @@ boolean SFE_UBLOX_GNSS::setAutoNAVVELECEFrate(uint8_t rate, boolean implicitUpda payloadCfg[1] = UBX_NAV_VELECEF; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXNAVVELECEF->automaticFlags.flags.bits.automatic = (rate > 0); @@ -6556,7 +6563,7 @@ boolean SFE_UBLOX_GNSS::setAutoNAVVELNEDrate(uint8_t rate, boolean implicitUpdat payloadCfg[1] = UBX_NAV_VELNED; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXNAVVELNED->automaticFlags.flags.bits.automatic = (rate > 0); @@ -6712,7 +6719,7 @@ boolean SFE_UBLOX_GNSS::setAutoNAVHPPOSECEFrate(uint8_t rate, boolean implicitUp payloadCfg[1] = UBX_NAV_HPPOSECEF; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXNAVHPPOSECEF->automaticFlags.flags.bits.automatic = (rate > 0); @@ -6890,7 +6897,7 @@ boolean SFE_UBLOX_GNSS::setAutoHPPOSLLHrate(uint8_t rate, boolean implicitUpdate payloadCfg[1] = UBX_NAV_HPPOSLLH; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXNAVHPPOSLLH->automaticFlags.flags.bits.automatic = (rate > 0); @@ -7046,7 +7053,7 @@ boolean SFE_UBLOX_GNSS::setAutoNAVCLOCKrate(uint8_t rate, boolean implicitUpdate payloadCfg[1] = UBX_NAV_CLOCK; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXNAVCLOCK->automaticFlags.flags.bits.automatic = (rate > 0); @@ -7301,7 +7308,7 @@ boolean SFE_UBLOX_GNSS::setAutoRELPOSNEDrate(uint8_t rate, boolean implicitUpdat payloadCfg[1] = UBX_NAV_RELPOSNED; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXNAVRELPOSNED->automaticFlags.flags.bits.automatic = (rate > 0); @@ -7457,7 +7464,7 @@ boolean SFE_UBLOX_GNSS::setAutoRXMSFRBXrate(uint8_t rate, boolean implicitUpdate payloadCfg[1] = UBX_RXM_SFRBX; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXRXMSFRBX->automaticFlags.flags.bits.automatic = (rate > 0); @@ -7613,7 +7620,7 @@ boolean SFE_UBLOX_GNSS::setAutoRXMRAWXrate(uint8_t rate, boolean implicitUpdate, payloadCfg[1] = UBX_RXM_RAWX; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXRXMRAWX->automaticFlags.flags.bits.automatic = (rate > 0); @@ -7816,7 +7823,7 @@ boolean SFE_UBLOX_GNSS::setAutoTIMTM2rate(uint8_t rate, boolean implicitUpdate, payloadCfg[1] = UBX_TIM_TM2; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXTIMTM2->automaticFlags.flags.bits.automatic = (rate > 0); @@ -8001,7 +8008,7 @@ boolean SFE_UBLOX_GNSS::setAutoESFALGrate(uint8_t rate, boolean implicitUpdate, payloadCfg[1] = UBX_ESF_ALG; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXESFALG->automaticFlags.flags.bits.automatic = (rate > 0); @@ -8186,7 +8193,7 @@ boolean SFE_UBLOX_GNSS::setAutoESFSTATUSrate(uint8_t rate, boolean implicitUpdat payloadCfg[1] = UBX_ESF_STATUS; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXESFSTATUS->automaticFlags.flags.bits.automatic = (rate > 0); @@ -8372,7 +8379,7 @@ boolean SFE_UBLOX_GNSS::setAutoESFINSrate(uint8_t rate, boolean implicitUpdate, payloadCfg[1] = UBX_ESF_INS; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXESFINS->automaticFlags.flags.bits.automatic = (rate > 0); @@ -8557,7 +8564,7 @@ boolean SFE_UBLOX_GNSS::setAutoESFMEASrate(uint8_t rate, boolean implicitUpdate, payloadCfg[1] = UBX_ESF_MEAS; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXESFMEAS->automaticFlags.flags.bits.automatic = (rate > 0); @@ -8742,7 +8749,7 @@ boolean SFE_UBLOX_GNSS::setAutoESFRAWrate(uint8_t rate, boolean implicitUpdate, payloadCfg[1] = UBX_ESF_RAW; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXESFRAW->automaticFlags.flags.bits.automatic = (rate > 0); @@ -8932,7 +8939,7 @@ boolean SFE_UBLOX_GNSS::setAutoHNRATTrate(uint8_t rate, boolean implicitUpdate, payloadCfg[1] = UBX_HNR_ATT; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXHNRATT->automaticFlags.flags.bits.automatic = (rate > 0); @@ -9123,7 +9130,7 @@ boolean SFE_UBLOX_GNSS::setAutoHNRINSrate(uint8_t rate, boolean implicitUpdate, payloadCfg[1] = UBX_HNR_INS; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXHNRINS->automaticFlags.flags.bits.automatic = (rate > 0); @@ -9308,7 +9315,7 @@ boolean SFE_UBLOX_GNSS::setAutoHNRPVTrate(uint8_t rate, boolean implicitUpdate, payloadCfg[1] = UBX_HNR_PVT; payloadCfg[2] = rate; // 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, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK if (ok) { packetUBXHNRPVT->automaticFlags.flags.bits.automatic = (rate > 0); @@ -9441,7 +9448,7 @@ boolean SFE_UBLOX_GNSS::setNavigationFrequency(uint8_t navFreq, uint16_t maxWait payloadCfg[0] = measurementRate & 0xFF; //measRate LSB payloadCfg[1] = measurementRate >> 8; //measRate MSB - boolean result = ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + boolean result = ((sendCommand(&packetCfg, maxWait, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK flushCFGRATE(); // Mark the polled measurement and navigation rate data as stale @@ -9486,7 +9493,7 @@ boolean SFE_UBLOX_GNSS::setMeasurementRate(uint16_t rate, uint16_t maxWait) payloadCfg[0] = rate & 0xFF; //measRate LSB payloadCfg[1] = rate >> 8; //measRate MSB - boolean result = ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + boolean result = ((sendCommand(&packetCfg, maxWait, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK flushCFGRATE(); // Mark the polled measurement and navigation rate data as stale @@ -9525,7 +9532,7 @@ boolean SFE_UBLOX_GNSS::setNavigationRate(uint16_t rate, uint16_t maxWait) payloadCfg[2] = rate & 0xFF; //navRate LSB payloadCfg[3] = rate >> 8; //navRate MSB - boolean result = ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK + boolean result = ((sendCommand(&packetCfg, maxWait, true)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK flushCFGRATE(); // Mark the polled measurement and navigation rate data as stale @@ -10753,7 +10760,7 @@ boolean SFE_UBLOX_GNSS::setHNRNavigationRate(uint8_t rate, uint16_t maxWait) payloadCfg[0] = rate; //Update the navigation rate - sfe_ublox_status_e result = sendCommand(&packetCfg, maxWait); // We are only expecting an ACK + sfe_ublox_status_e result = sendCommand(&packetCfg, maxWait, true); // We are only expecting an ACK //Adjust the I2C polling timeout based on update rate if (result == SFE_UBLOX_STATUS_DATA_SENT) diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.h b/src/SparkFun_u-blox_GNSS_Arduino_Library.h index 015ba3f..86ae99c 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.h +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.h @@ -507,6 +507,15 @@ struct ubxPacket 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 + bool isClassAndIdMatch(uint8_t theClass, uint8_t theId) { + return cls == theClass && theId == id; + } + bool isAckForClassAndId(uint8_t theClass, uint8_t theId) { + return isClassAndIdMatch(UBX_CLASS_ACK, UBX_ACK_ACK) && payload[0] == theClass && payload[1] == theId; + } + bool isNackForClassAndId(uint8_t theClass, uint8_t theId) { + return isClassAndIdMatch(UBX_CLASS_ACK, UBX_ACK_NACK) && payload[0] == theClass && payload[1] == theId; + } }; // Struct to hold the results returned by getGeofenceState (returned by UBX-NAV-GEOFENCE) @@ -639,7 +648,7 @@ class SFE_UBLOX_GNSS // After sending a message to the module, wait for the expected response (data+ACK or just data) - 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, or just an ACK + sfe_ublox_status_e waitForACKResponse(ubxPacket *outgoingUBX, uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime = defaultMaxWait, bool expectACKonly = false); //Poll the module until a config packet and an ACK is received, or just an ACK 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 // Check if any callbacks need to be called @@ -1300,7 +1309,7 @@ class SFE_UBLOX_GNSS //The packet buffers //These are pointed at from within the ubxPacket uint8_t payloadAck[2]; // Holds the requested ACK/NACK - uint8_t payloadBuf[2]; // Temporary buffer used to screen incoming packets or dump unrequested packets + uint8_t payloadBuf[MAX_PAYLOAD_SIZE]; // Temporary buffer used to screen incoming packets or dump unrequested packets aberridg TODO: figure out if we can reduce memory usage by not using the whole buffer - needs some clean-up size_t packetCfgPayloadSize = 0; // Size for the packetCfg payload. .begin will set this to MAX_PAYLOAD_SIZE if necessary. User can change with setPacketCfgPayloadSize uint8_t *payloadCfg = NULL; uint8_t *payloadAuto = NULL; From a1ca3d4608e4998910cb29797baba985ece85e41 Mon Sep 17 00:00:00 2001 From: Andrew Berridge Date: Sun, 27 Jun 2021 07:36:52 +0100 Subject: [PATCH 3/6] Removed classAndIdMatch flag on packet buffers. Gradually moving state management out of the process and processUBX functions. --- src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 126 ++----------------- src/SparkFun_u-blox_GNSS_Arduino_Library.h | 9 +- 2 files changed, 17 insertions(+), 118 deletions(-) diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index fde7f75..1b615a9 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -1625,7 +1625,7 @@ void SFE_UBLOX_GNSS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_ else if (checkAutomatic(incomingUBX->cls, incomingUBX->id)) { // This isn't the message we are looking for... - // Let's say so and leave incomingUBX->classAndIDmatch _unchanged_ + // Let's say so... if (_printDebug == true) { _debugSerial->print(F("processUBX: incoming \"automatic\" message: Class: 0x")); @@ -1654,20 +1654,6 @@ void SFE_UBLOX_GNSS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_ { 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 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) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging { //Drive an external pin to allow for easier logic analyzation @@ -2987,10 +2973,6 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForACKResponse(ubxPacket *outgoingUBX, ui packetAck.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; packetBuf.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; packetAuto.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; - packetAuto.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; unsigned long startTime = millis(); while (millis() - startTime < maxTime) @@ -3022,12 +3004,6 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForACKResponse(ubxPacket *outgoingUBX, ui } return (SFE_UBLOX_STATUS_DATA_RECEIVED); //We received valid data and a correct ACK! } - - // 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 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 an automatic packet. else if (!packetCfg.isClassAndIdMatch(requestedClass, requestedID) && packetAck.isClassAndIdMatch(requestedClass, requestedID)) { if (_printDebug == true) @@ -3039,27 +3015,9 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForACKResponse(ubxPacket *outgoingUBX, ui 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->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 an automatic 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. - // 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) || (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 + // If packetAck is for requested class/ID but both outgoingUBX->valid and packetCfg isClassAndIDmatch // 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)) + else if ((packetAck.isAckForClassAndId(requestedClass, requestedID) && (packetCfg.valid == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID))) { if (_printDebug == true) { @@ -3069,14 +3027,6 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForACKResponse(ubxPacket *outgoingUBX, ui } 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->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.isNackForClassAndId(requestedClass, requestedID)) { if (_printDebug == true) @@ -3088,10 +3038,10 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForACKResponse(ubxPacket *outgoingUBX, ui return (SFE_UBLOX_STATUS_COMMAND_NACK); //We received a NACK! } - // If the outgoingUBX->classAndIDmatch is VALID but the packetAck.classAndIDmatch is NOT_VALID + // If the packetCfg.isClassAndIdMatch but the packetAck is not for this class/ID // 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) && (outgoingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_VALID) && (outgoingUBX->cls == requestedClass) && (outgoingUBX->id == requestedID)) + else if ((packetCfg.isClassAndIdMatch(requestedClass, requestedID) && (packetAck.isClassAndIdMatch(requestedClass, requestedID) == false) && (packetCfg.valid == SFE_UBLOX_PACKET_VALIDITY_VALID))) { if (_printDebug == true) { @@ -3102,9 +3052,9 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForACKResponse(ubxPacket *outgoingUBX, ui return (SFE_UBLOX_STATUS_DATA_RECEIVED); //We received valid data and an invalid ACK! } - // If the outgoingUBX->classAndIDmatch is NOT_VALID and the packetAck.classAndIDmatch is NOT_VALID + // If classes of ack and data do not match // 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)) + else if ((packetCfg.isClassAndIdMatch(requestedClass, requestedID) == false) && (packetAck.isClassAndIdMatch(requestedClass, requestedID) == false)) { if (_printDebug == true) { @@ -3115,9 +3065,9 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForACKResponse(ubxPacket *outgoingUBX, ui return (SFE_UBLOX_STATUS_FAIL); //We received invalid data and an invalid ACK! } - // If the outgoingUBX->classAndIDmatch is VALID and the packetAck.classAndIDmatch is NOT_DEFINED + // If the config packet is VALID and packetAck does not match the requested class/ID // 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)) + else if ((packetCfg.isClassAndIdMatch(requestedClass, requestedID) == true) && (packetAck.isClassAndIdMatch(requestedClass, requestedID) == false)) { // if (_printDebug == true) // { @@ -3133,7 +3083,7 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForACKResponse(ubxPacket *outgoingUBX, ui } //while (millis() - startTime < maxTime) // We have timed out... - // If the outgoingUBX->classAndIDmatch is VALID then we can take a gamble and return DATA_RECEIVED + // If the packetCfg matches the requested class/ID then we can take a gamble and return DATA_RECEIVED // even though we did not get an ACK if ((packetCfg.isClassAndIdMatch(requestedClass, requestedID) && !packetAck.isClassAndIdMatch(requestedClass, requestedID)) && (packetCfg.valid == SFE_UBLOX_PACKET_VALIDITY_VALID)) { @@ -3168,20 +3118,16 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForNoACKResponse(ubxPacket *outgoingUBX, packetAck.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; packetBuf.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; packetAuto.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; - packetAuto.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - + unsigned long startTime = millis(); while (millis() - startTime < maxTime) { if (checkUbloxInternal(&packetBuf, requestedClass, requestedID) == true) //See if new data is available. Process bytes as they come in. { - // If outgoingUBX->classAndIDmatch is VALID + // If packetBuf matches // 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 + // then we can be confident that the data in packetBuf is valid if (packetBuf.isClassAndIdMatch(requestedClass, requestedID) && packetBuf.valid == SFE_UBLOX_PACKET_VALIDITY_VALID) { if (_printDebug == true) @@ -3192,53 +3138,7 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForNoACKResponse(ubxPacket *outgoingUBX, } return (SFE_UBLOX_STATUS_DATA_RECEIVED); //We received valid data! } - - // If the outgoingUBX->classAndIDmatch is VALID - // 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. - // 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))) - { - if (_printDebug == true) - { - _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 - } - - // 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)) - { - // if (_printDebug == true) - // { - // _debugSerial->print(F("waitForNoACKResponse: valid but UNWANTED data after ")); - // _debugSerial->print(millis() - startTime); - // _debugSerial->print(F(" msec. Class: ")); - // _debugSerial->print(outgoingUBX->cls); - // _debugSerial->print(F(" ID: ")); - // _debugSerial->print(outgoingUBX->id); - // } - } - - // 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 - }*/ } - delayMicroseconds(500); } diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.h b/src/SparkFun_u-blox_GNSS_Arduino_Library.h index 86ae99c..2aa85a0 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.h +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.h @@ -506,7 +506,6 @@ struct ubxPacket 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 NOT_DEFINED to VALID or NOT_VALID when the Class and ID match the requestedClass and requestedID bool isClassAndIdMatch(uint8_t theClass, uint8_t theId) { return cls == theClass && theId == id; } @@ -1318,10 +1317,10 @@ class SFE_UBLOX_GNSS uint8_t spiBufferIndex = 0; // The index into the SPI buffer //Init the packet structures and init them with pointers to the payloadAck, payloadCfg, payloadBuf and payloadAuto arrays - ubxPacket packetAck = {0, 0, 0, 0, 0, payloadAck, 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}; - ubxPacket packetCfg = {0, 0, 0, 0, 0, payloadCfg, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; - ubxPacket packetAuto = {0, 0, 0, 0, 0, payloadAuto, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; + ubxPacket packetAck = {0, 0, 0, 0, 0, payloadAck, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; + ubxPacket packetBuf = {0, 0, 0, 0, 0, payloadBuf, 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 packetAuto = {0, 0, 0, 0, 0, payloadAuto, 0, 0, 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; From 87b641cd4270b9c450e82c7f85ddac930bf0fbdc Mon Sep 17 00:00:00 2001 From: Andrew Berridge Date: Sun, 27 Jun 2021 08:16:41 +0100 Subject: [PATCH 4/6] Removing class/ID match checking from processUBX. All checking now done much higher up the call chain --- src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 81 +++----------------- src/SparkFun_u-blox_GNSS_Arduino_Library.h | 2 +- 2 files changed, 12 insertions(+), 71 deletions(-) diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index 1b615a9..d0372c8 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -1306,13 +1306,13 @@ void SFE_UBLOX_GNSS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t r { //Divert incoming into the correct buffer if (activePacketBuffer == SFE_UBLOX_PACKET_PACKETACK) - processUBX(incoming, &packetAck, requestedClass, requestedID); + processUBX(incoming, &packetAck); else if (activePacketBuffer == SFE_UBLOX_PACKET_PACKETCFG) - processUBX(incoming, &packetCfg, requestedClass, requestedID); + processUBX(incoming, &packetCfg); else if (activePacketBuffer == SFE_UBLOX_PACKET_PACKETBUF) - processUBX(incoming, &packetBuf, requestedClass, requestedID); + processUBX(incoming, &packetBuf); else // if (activePacketBuffer == SFE_UBLOX_PACKET_PACKETAUTO) - processUBX(incoming, &packetAuto, requestedClass, requestedID); + processUBX(incoming, &packetAuto); } //Finally, increment the frame counter ubxFrameCounter++; @@ -1513,7 +1513,7 @@ void SFE_UBLOX_GNSS::processRTCM(uint8_t incoming) // IGNORE COMPILER WARNING un //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 packetCfgPayloadSize bytes. //startingSpot can be set so we only record a subset of bytes within a larger packet. -void SFE_UBLOX_GNSS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) +void SFE_UBLOX_GNSS::processUBX(uint8_t incoming, ubxPacket *incomingUBX) { //If incomingUBX is a user-defined custom packet, then the payload size could be different to packetCfgPayloadSize. //TO DO: update this to prevent an overrun when receiving an automatic message @@ -1587,54 +1587,6 @@ void SFE_UBLOX_GNSS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_ incomingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_VALID; // Flag the packet as valid if (_printDebug) _debugSerial->println("processUBX packet is valid"); - // ACK or NACK??? - if (incomingUBX->isAckForClassAndId(requestedClass, requestedID)) { - if (_printDebug) - { - _debugSerial->print(F("processUBX: ACK received: Requested Class: 0x")); - _debugSerial->print(incomingUBX->payload[0], HEX); - _debugSerial->print(F(" Requested ID: 0x")); - _debugSerial->println(incomingUBX->payload[1], HEX); - } - } - - else if (incomingUBX->isAckForClassAndId(requestedClass, requestedID)) - { - if (_printDebug == true) - { - _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); - } - } - - else if (incomingUBX->isClassAndIdMatch(requestedClass, requestedID)) - { - if (_printDebug == true) - { - _debugSerial->print(F("processUBX: Message received for requested Class: 0x")); - _debugSerial->print(incomingUBX->payload[0], HEX); - _debugSerial->print(F(" Requested ID: 0x")); - _debugSerial->println(incomingUBX->payload[1], HEX); - } - } - - //This is not an ACK and we do not have a complete class and ID match - //So let's check for an "automatic" message arriving - else if (checkAutomatic(incomingUBX->cls, incomingUBX->id)) - { - // This isn't the message we are looking for... - // Let's say so... - if (_printDebug == true) - { - _debugSerial->print(F("processUBX: incoming \"automatic\" message: Class: 0x")); - _debugSerial->print(incomingUBX->cls, HEX); - _debugSerial->print(F(" ID: 0x")); - _debugSerial->println(incomingUBX->id, HEX); - } - } - if (_printDebug == true) { _debugSerial->print(F("Incoming: Size: ")); @@ -1643,7 +1595,6 @@ void SFE_UBLOX_GNSS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_ printPacket(incomingUBX); } - //We've got a valid packet, now do something with it but only if ignoreThisPayload is false if (ignoreThisPayload == false) { @@ -1691,9 +1642,13 @@ void SFE_UBLOX_GNSS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_ { //If an automatic packet comes in asynchronously, we need to fudge the startingSpot uint16_t startingSpot = incomingUBX->startingSpot; - if (!incomingUBX->isClassAndIdMatch(requestedClass, requestedID) && checkAutomatic(incomingUBX->cls, incomingUBX->id)) + if (checkAutomatic(incomingUBX->cls, incomingUBX->id)) { - //_debugSerial->println("processUBX: incoming is automatic"); + if(_printDebug == true) + { + //_debugSerial->println("processUBX: incoming is automatic"); + } + startingSpot = 0; } @@ -2979,7 +2934,6 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForACKResponse(ubxPacket *outgoingUBX, ui { if (checkUbloxInternal(outgoingUBX, requestedClass, requestedID) == true) //See if new data is available. Process bytes as they come in. { - // If we are expecting an ACK only, return as soon as we have it! if (expectACKonly && packetAck.isAckForClassAndId(requestedClass, requestedID) && packetAck.valid == SFE_UBLOX_PACKET_VALIDITY_VALID) { @@ -3064,19 +3018,6 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForACKResponse(ubxPacket *outgoingUBX, ui } return (SFE_UBLOX_STATUS_FAIL); //We received invalid data and an invalid ACK! } - - // If the config packet is VALID and packetAck does not match the requested class/ID - // then the ACK has not yet been received and we should keep waiting for it - else if ((packetCfg.isClassAndIdMatch(requestedClass, requestedID) == true) && (packetAck.isClassAndIdMatch(requestedClass, requestedID) == false)) - { - // if (_printDebug == true) - // { - // _debugSerial->print(F("waitForACKResponse: valid data after ")); - // _debugSerial->print(millis() - startTime); - // _debugSerial->println(F(" msec. Waiting for ACK.")); - // } - } - } //checkUbloxInternal == true delayMicroseconds(500); diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.h b/src/SparkFun_u-blox_GNSS_Arduino_Library.h index 2aa85a0..e7fc142 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.h +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.h @@ -632,7 +632,7 @@ class SFE_UBLOX_GNSS 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 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 processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID); //Given a character, file it away into the uxb packet structure + void processUBX(uint8_t incoming, ubxPacket *incomingUBX); //Given a character, file it away into the uxb packet structure void processUBXpacket(ubxPacket *msg); //Once a packet has been received and validated, identify this packet's class/id and update internal flags // Send I2C/Serial/SPI commands to the module From b7e90c6925c434d67d5d5887fc72dde0f1d8c091 Mon Sep 17 00:00:00 2001 From: Andrew Berridge Date: Sun, 27 Jun 2021 12:52:36 +0100 Subject: [PATCH 5/6] Commits as suggested by Paul --- keywords.txt | 1 + src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 52 +++++++++++--------- src/SparkFun_u-blox_GNSS_Arduino_Library.h | 13 +++-- 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/keywords.txt b/keywords.txt index b2b7cab..831b4c2 100644 --- a/keywords.txt +++ b/keywords.txt @@ -66,6 +66,7 @@ disableUBX7Fcheck KEYWORD2 checkUblox KEYWORD2 checkUbloxI2C KEYWORD2 checkUbloxSerial KEYWORD2 +checkUbloxSPI KEYWORD2 process KEYWORD2 processNMEA KEYWORD2 diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index ae80176..c50645b 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -452,12 +452,15 @@ boolean SFE_UBLOX_GNSS::begin(Stream &serialPort) } // Initialize for SPI -boolean SFE_UBLOX_GNSS::begin(SPIClass &spiPort, uint8_t ssPin, int spiSpeed) +boolean SFE_UBLOX_GNSS::begin(SPIClass &spiPort, uint8_t csPin, uint32_t spiSpeed) { commType = COMM_TYPE_SPI; _spiPort = &spiPort; - _ssPin = ssPin; + _csPin = csPin; _spiSpeed = spiSpeed; + // Initialize the chip select pin + pinMode(_csPin, OUTPUT); + digitalWrite(_csPin, HIGH); //New in v2.0: allocate memory for the packetCfg payload here - if required. (The user may have called setPacketCfgPayloadSize already) if (packetCfgPayloadSize == 0) setPacketCfgPayloadSize(MAX_PAYLOAD_SIZE); @@ -790,32 +793,22 @@ boolean SFE_UBLOX_GNSS::checkUbloxSerial(ubxPacket *incomingUBX, uint8_t request //Checks SPI for data, passing any new bytes to process() boolean SFE_UBLOX_GNSS::checkUbloxSpi(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) { - // process the contents of the SPI buffer if not empty! - uint8_t bufferByte = spiBuffer[0]; - uint8_t bufferIndex = 0; - - while (bufferByte != 0xFF) { - process(bufferByte, incomingUBX, requestedClass, requestedID); - bufferIndex++; - bufferByte = spiBuffer[bufferIndex]; + // Process the contents of the SPI buffer if not empty! + for (uint8_t i = 0; i < spiBufferIndex; i++) { + process(spiBuffer[i], incomingUBX, requestedClass, requestedID); } - - // reset the contents of the SPI buffer - for(uint8_t i = 0; i < bufferIndex; i++) - { - spiBuffer[i] = 0xFF; - } - + spiBufferIndex = 0; + SPISettings settingsA(_spiSpeed, MSBFIRST, SPI_MODE0); _spiPort->beginTransaction(settingsA); - digitalWrite(_ssPin, LOW); + digitalWrite(_csPin, LOW); uint8_t byteReturned = _spiPort->transfer(0x0A); while (byteReturned != 0xFF || currentSentence != NONE) { process(byteReturned, incomingUBX, requestedClass, requestedID); byteReturned = _spiPort->transfer(0x0A); } - digitalWrite(_ssPin, HIGH); + digitalWrite(_csPin, HIGH); _spiPort->endTransaction(); return (true); @@ -2858,7 +2851,7 @@ void SFE_UBLOX_GNSS::sendSerialCommand(ubxPacket *outgoingUBX) void SFE_UBLOX_GNSS::spiTransfer(uint8_t byteToTransfer) { uint8_t returnedByte = _spiPort->transfer(byteToTransfer); - if (returnedByte != 0xFF) + if (returnedByte != 0xFF || currentSentence != NONE) { spiBuffer[spiBufferIndex] = returnedByte; spiBufferIndex++; @@ -2868,9 +2861,24 @@ void SFE_UBLOX_GNSS::spiTransfer(uint8_t byteToTransfer) // Send a command via SPI void SFE_UBLOX_GNSS::sendSpiCommand(ubxPacket *outgoingUBX) { + if (spiBuffer == NULL) //Memory has not yet been allocated - so use new + { + spiBuffer = new uint8_t[SPI_BUFFER_SIZE]; + } + + if (spiBuffer == NULL) { + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + { + _debugSerial->print(F("process: memory allocation failed for SPI Buffer!")); + } + } + + // Start at the beginning of the SPI buffer + spiBufferIndex = 0; + SPISettings settingsA(_spiSpeed, MSBFIRST, SPI_MODE0); _spiPort->beginTransaction(settingsA); - digitalWrite(_ssPin, LOW); + digitalWrite(_csPin, LOW); //Write header bytes spiTransfer(UBX_SYNCH_1); //μ - oh ublox, you're funny. I will call you micro-blox from now on. if (_printDebug) _debugSerial->printf("%x ", UBX_SYNCH_1); @@ -2898,7 +2906,7 @@ void SFE_UBLOX_GNSS::sendSpiCommand(ubxPacket *outgoingUBX) if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->checksumA); spiTransfer(outgoingUBX->checksumB); if (_printDebug) _debugSerial->printf("%x \n", outgoingUBX->checksumB); - digitalWrite(_ssPin, HIGH); + digitalWrite(_csPin, HIGH); _spiPort->endTransaction(); } diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.h b/src/SparkFun_u-blox_GNSS_Arduino_Library.h index 015ba3f..6f75034 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.h +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.h @@ -494,6 +494,9 @@ enum sfe_ublox_ls_src_e //#define MAX_PAYLOAD_SIZE 768 //Worst case: UBX_CFG_VALSET packet with 64 keyIDs each with 64 bit values #endif +// For storing SPI bytes received during sendSpiCommand +#define SPI_BUFFER_SIZE 128 + //-=-=-=-=- UBX binary specific variables struct ubxPacket { @@ -562,8 +565,8 @@ class SFE_UBLOX_GNSS boolean begin(TwoWire &wirePort = Wire, uint8_t deviceAddress = 0x42); //Returns true if module is detected //serialPort needs to be perviously initialized to correct baud rate boolean begin(Stream &serialPort); //Returns true if module is detected - //SPI - supply instance of SPIClass, slave select pin and SPI speed (in Hz) - boolean begin(SPIClass &spiPort, uint8_t ssPin, int spiSpeed); + //SPI - supply instance of SPIClass, chip select pin and SPI speed (in Hz) + boolean begin(SPIClass &spiPort, uint8_t csPin, uint32_t spiSpeed); void end(void); //Stop all automatic message processing. Free all used RAM @@ -1283,7 +1286,7 @@ class SFE_UBLOX_GNSS Stream *_debugSerial; //The stream to send debug messages to if enabled SPIClass *_spiPort; //The instance of SPIClass - uint8_t _ssPin; //The slave select pin + uint8_t _csPin; //The chip select pin int _spiSpeed; //The speed to use for SPI (Hz) uint8_t _gpsI2Caddress = 0x42; //Default 7-bit unshifted address of the ublox 6/7/8/M8/F9 series @@ -1305,8 +1308,8 @@ class SFE_UBLOX_GNSS uint8_t *payloadCfg = NULL; uint8_t *payloadAuto = NULL; - uint8_t spiBuffer[20]; // A small buffer to store any bytes being recieved back from the device while we are sending via SPI - uint8_t spiBufferIndex = 0; // The index into the SPI buffer + uint8_t *spiBuffer = NULL; // A buffer to store any bytes being recieved back from the device while we are sending via SPI + uint8_t spiBufferIndex = 0; // Index into the SPI buffer //Init the packet structures and init them with pointers to the payloadAck, payloadCfg, payloadBuf and payloadAuto arrays ubxPacket packetAck = {0, 0, 0, 0, 0, payloadAck, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; From cb24b642de59db16bb37aa5c21b9340d003c2cf1 Mon Sep 17 00:00:00 2001 From: Andrew Berridge Date: Sun, 27 Jun 2021 14:53:01 +0100 Subject: [PATCH 6/6] Added spi transaction size :-) It still defaults to 128... please adjust downwards if you feel necessary. --- keywords.txt | 2 ++ src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 19 ++++++++++++++++--- src/SparkFun_u-blox_GNSS_Arduino_Library.h | 6 ++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/keywords.txt b/keywords.txt index 831b4c2..a1556c3 100644 --- a/keywords.txt +++ b/keywords.txt @@ -55,6 +55,8 @@ end KEYWORD2 setI2CpollingWait KEYWORD2 setI2CTransactionSize KEYWORD2 getI2CTransactionSize KEYWORD2 +setSpiTransactionSize KEYWORD2 +getSpiTransactionSize KEYWORD2 isConnected KEYWORD2 enableDebugging KEYWORD2 disableDebugging KEYWORD2 diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index c50645b..dda1e27 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -505,6 +505,19 @@ uint8_t SFE_UBLOX_GNSS::getI2CTransactionSize(void) return (i2cTransactionSize); } +//Sets the global size for the SPI buffer/transactions. +//Call this before begin()! +//Note: if the buffer size is too small, incoming characters may be lost if the message sent +//is larger than this buffer. If too big, you may run out of SRAM on constrained architectures! +void SFE_UBLOX_GNSS::setSpiTransactionSize(uint8_t transactionSize) +{ + spiTransactionSize = transactionSize; +} +uint8_t SFE_UBLOX_GNSS::getSpiTransactionSize(void) +{ + return (spiTransactionSize); +} + //Returns true if I2C device ack's boolean SFE_UBLOX_GNSS::isConnected(uint16_t maxWait) { @@ -2851,7 +2864,7 @@ void SFE_UBLOX_GNSS::sendSerialCommand(ubxPacket *outgoingUBX) void SFE_UBLOX_GNSS::spiTransfer(uint8_t byteToTransfer) { uint8_t returnedByte = _spiPort->transfer(byteToTransfer); - if (returnedByte != 0xFF || currentSentence != NONE) + if ((spiBufferIndex < getSpiTransactionSize()) && (returnedByte != 0xFF || currentSentence != NONE)) { spiBuffer[spiBufferIndex] = returnedByte; spiBufferIndex++; @@ -2863,13 +2876,13 @@ void SFE_UBLOX_GNSS::sendSpiCommand(ubxPacket *outgoingUBX) { if (spiBuffer == NULL) //Memory has not yet been allocated - so use new { - spiBuffer = new uint8_t[SPI_BUFFER_SIZE]; + spiBuffer = new uint8_t[getSpiTransactionSize()]; } if (spiBuffer == NULL) { if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging { - _debugSerial->print(F("process: memory allocation failed for SPI Buffer!")); + _debugSerial->print(F("sendSpiCommand: memory allocation failed for SPI Buffer!")); } } diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.h b/src/SparkFun_u-blox_GNSS_Arduino_Library.h index 6f75034..f67510e 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.h +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.h @@ -576,6 +576,11 @@ class SFE_UBLOX_GNSS void setI2CTransactionSize(uint8_t bufferSize); uint8_t getI2CTransactionSize(void); + //Control the size of the spi buffer. If the buffer isn't big enough, we'll start to lose bytes + //That we receive if the buffer is full! + void setSpiTransactionSize(uint8_t bufferSize); + uint8_t getSpiTransactionSize(void); + //Set the max number of bytes set in a given I2C transaction uint8_t i2cTransactionSize = 32; //Default to ATmega328 limit @@ -1310,6 +1315,7 @@ class SFE_UBLOX_GNSS uint8_t *spiBuffer = NULL; // A buffer to store any bytes being recieved back from the device while we are sending via SPI uint8_t spiBufferIndex = 0; // Index into the SPI buffer + uint8_t spiTransactionSize = SPI_BUFFER_SIZE; //Default size of the SPI buffer //Init the packet structures and init them with pointers to the payloadAck, payloadCfg, payloadBuf and payloadAuto arrays ubxPacket packetAck = {0, 0, 0, 0, 0, payloadAck, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED};