diff --git a/examples/Series_6_7/Example1_GetPositionAndTime_Series_6_7/Example1_GetPositionAndTime_Series_6_7.ino b/examples/Series_6_7/Example1_GetPositionAndTime_Series_6_7/Example1_GetPositionAndTime_Series_6_7.ino deleted file mode 100644 index bf7ffb2..0000000 --- a/examples/Series_6_7/Example1_GetPositionAndTime_Series_6_7/Example1_GetPositionAndTime_Series_6_7.ino +++ /dev/null @@ -1,109 +0,0 @@ -/* - Reading lat, long and UTC time via UBX binary commands - no more NMEA parsing! - By: Paul Clark and Nathan Seidle - Using the library modifications provided by @blazczak and @geeksville - - SparkFun Electronics - Date: June 16th, 2020 - License: MIT. See license file for more information but you can - basically do whatever you want with this code. - - This example shows how to query a u-blox module for its lat/long/altitude. We also - turn off the NMEA output on the I2C port. This decreases the amount of I2C traffic - dramatically. - - Note: Long/lat are large numbers because they are * 10^7. To convert lat/long - to something google maps understands simply divide the numbers by 10,000,000. We - do this so that we don't have to use floating point numbers. - - Leave NMEA parsing behind. Now you can simply ask the module for the datums you want! - - Feel like supporting open source hardware? - Buy a board from SparkFun! - ZED-F9P RTK2: https://www.sparkfun.com/products/15136 - NEO-M8P RTK: https://www.sparkfun.com/products/15005 - SAM-M8Q: https://www.sparkfun.com/products/15106 - - Hardware Connections: - Plug a Qwiic cable into the GPS and a BlackBoard - If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425) - Open the serial monitor at 115200 baud to see the output -*/ - -#include //Needed for I2C to GPS - -#include "SparkFun_Ublox_Arduino_Library_Series_6_7.h" -SFE_UBLOX_GPS myGPS; - -long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module. - -void setup() -{ - Serial.begin(115200); - while (!Serial); //Wait for user to open terminal - Serial.println("SparkFun u-blox Example"); - - Wire.begin(); - - //myGPS.enableDebugging(); // Uncomment this line to enable debug messages - - if (myGPS.begin() == false) //Connect to the u-blox module using Wire port - { - Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing.")); - while (1); - } - - myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise) - myGPS.saveConfiguration(); //Save the current settings to flash and BBR -} - -void loop() -{ - //Query module only every second. Doing it more often will just cause I2C traffic. - //The module only responds when a new position is available - if (millis() - lastTime > 1000) - { - lastTime = millis(); //Update the timer - - long latitude = myGPS.getLatitude(); - Serial.print(F("Lat: ")); - Serial.print(latitude); - - long longitude = myGPS.getLongitude(); - Serial.print(F(" Long: ")); - Serial.print(longitude); - Serial.print(F(" (degrees * 10^-7)")); - - long altitude = myGPS.getAltitude(); - Serial.print(F(" Alt: ")); - Serial.print(altitude); - Serial.print(F(" (mm)")); - - Serial.print(F(" Time: ")); - - byte Hour = myGPS.getHour(); - if (Hour < 10) - { - Serial.print(F("0")); - } - Serial.print(Hour); - Serial.print(F(":")); - - byte Minute = myGPS.getMinute(); - if (Minute < 10) - { - Serial.print(F("0")); - } - Serial.print(Minute); - Serial.print(F(":")); - - byte Second = myGPS.getSecond(); - if (Second < 10) - { - Serial.print(F("0")); - } - Serial.print(Second); - - Serial.println(); - } -} diff --git a/examples/Series_6_7/Example1_GetPositionAndTime_Series_6_7/SparkFun_Ublox_Arduino_Library_Series_6_7.cpp b/examples/Series_6_7/Example1_GetPositionAndTime_Series_6_7/SparkFun_Ublox_Arduino_Library_Series_6_7.cpp deleted file mode 100644 index bb3c7b0..0000000 --- a/examples/Series_6_7/Example1_GetPositionAndTime_Series_6_7/SparkFun_Ublox_Arduino_Library_Series_6_7.cpp +++ /dev/null @@ -1,3477 +0,0 @@ -/* - This is a library written for the u-blox ZED-F9P and NEO-M8P-2 - - Updated: June 16th, 2020 - - This copy includes changes by @blazczak and @geeksville to - provide support for the older series 6 and 7 modules. - - Disclaimer: SparkFun has not verified this copy of the library on either series 6 or 7. - It should work, it looks like it will work, but we have no way of confirming this. - We cannot guarantee that it will work reliably in your application. - - Do you like this library? Help support SparkFun. Buy a board! - https://www.sparkfun.com/products/15136 - https://www.sparkfun.com/products/15005 - https://www.sparkfun.com/products/15733 - https://www.sparkfun.com/products/15193 - https://www.sparkfun.com/products/15210 - - Original library written by Nathan Seidle @ SparkFun Electronics, September 6th, 2018 - - This library handles configuring and handling the responses - from a u-blox GPS module. Works with most modules from u-blox including - the Zed-F9P, NEO-M8P-2, NEO-M9N, ZOE-M8Q, SAM-M8Q, and many others. - - https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library - - Development environment specifics: - Arduino IDE 1.8.5 - - SparkFun code, firmware, and software is released under the MIT License(http://opensource.org/licenses/MIT). - The MIT License (MIT) - Copyright (c) 2016 SparkFun Electronics - Permission is hereby granted, free of charge, to any person obtaining a copy of this software and - associated documentation files (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the Software is furnished to - do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or substantial - portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include "SparkFun_Ublox_Arduino_Library_Series_6_7.h" - -SFE_UBLOX_GPS::SFE_UBLOX_GPS(void) -{ - // Constructor - currentGeofenceParams.numFences = 0; // Zero the number of geofences currently in use - moduleQueried.versionNumber = false; - - if (checksumFailurePin >= 0) - { - pinMode((uint8_t)checksumFailurePin, OUTPUT); - digitalWrite((uint8_t)checksumFailurePin, HIGH); - } -} - -//Initialize the Serial port -boolean SFE_UBLOX_GPS::begin(TwoWire &wirePort, uint8_t deviceAddress) -{ - commType = COMM_TYPE_I2C; - _i2cPort = &wirePort; //Grab which port the user wants us to use - - //We expect caller to begin their I2C port, with the speed of their choice external to the library - //But if they forget, we start the hardware here. - - //We're moving away from the practice of starting Wire hardware in a library. This is to avoid cross platform issues. - //ie, there are some platforms that don't handle multiple starts to the wire hardware. Also, every time you start the wire - //hardware the clock speed reverts back to 100kHz regardless of previous Wire.setClocks(). - //_i2cPort->begin(); - - _gpsI2Caddress = deviceAddress; //Store the I2C address from user - - return (isConnected()); -} - -//Initialize the Serial port -boolean SFE_UBLOX_GPS::begin(Stream &serialPort) -{ - commType = COMM_TYPE_SERIAL; - _serialPort = &serialPort; //Grab which port the user wants us to use - - return (isConnected()); -} - -//Enable or disable the printing of sent/response HEX values. -//Use this in conjunction with 'Transport Logging' from the Universal Reader Assistant to see what they're doing that we're not -void SFE_UBLOX_GPS::enableDebugging(Stream &debugPort, boolean printLimitedDebug) -{ - _debugSerial = &debugPort; //Grab which port the user wants us to use for debugging - if (printLimitedDebug == false) - { - _printDebug = true; //Should we print the commands we send? Good for debugging - } - else - { - _printLimitedDebug = true; //Should we print limited debug messages? Good for debugging high navigation rates - } -} -void SFE_UBLOX_GPS::disableDebugging(void) -{ - _printDebug = false; //Turn off extra print statements - _printLimitedDebug = false; -} - -//Safely print messages -void SFE_UBLOX_GPS::debugPrint(char *message) -{ - if (_printDebug == true) - { - _debugSerial->print(message); - } -} -//Safely print messages -void SFE_UBLOX_GPS::debugPrintln(char *message) -{ - if (_printDebug == true) - { - _debugSerial->println(message); - } -} - -const char *SFE_UBLOX_GPS::statusString(sfe_ublox_status_e stat) -{ - switch (stat) - { - case SFE_UBLOX_STATUS_SUCCESS: - return "Success"; - break; - case SFE_UBLOX_STATUS_FAIL: - return "General Failure"; - break; - case SFE_UBLOX_STATUS_CRC_FAIL: - return "CRC Fail"; - break; - case SFE_UBLOX_STATUS_TIMEOUT: - return "Timeout"; - break; - case SFE_UBLOX_STATUS_COMMAND_NACK: - return "Command not acknowledged (NACK)"; - break; - case SFE_UBLOX_STATUS_OUT_OF_RANGE: - return "Out of range"; - break; - case SFE_UBLOX_STATUS_INVALID_ARG: - return "Invalid Arg"; - break; - case SFE_UBLOX_STATUS_INVALID_OPERATION: - return "Invalid operation"; - break; - case SFE_UBLOX_STATUS_MEM_ERR: - return "Memory Error"; - break; - case SFE_UBLOX_STATUS_HW_ERR: - return "Hardware Error"; - break; - case SFE_UBLOX_STATUS_DATA_SENT: - return "Data Sent"; - break; - case SFE_UBLOX_STATUS_DATA_RECEIVED: - return "Data Received"; - break; - case SFE_UBLOX_STATUS_I2C_COMM_FAILURE: - return "I2C Comm Failure"; - break; - case SFE_UBLOX_STATUS_DATA_OVERWRITTEN: - return "Data Packet Overwritten"; - break; - default: - return "Unknown Status"; - break; - } - return "None"; -} - -void SFE_UBLOX_GPS::factoryReset() -{ - // Copy default settings to permanent - // Note: this does not load the permanent configuration into the current configuration. Calling factoryDefault() will do that. - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_CFG; - packetCfg.len = 13; - packetCfg.startingSpot = 0; - for (uint8_t i = 0; i < 4; i++) - { - 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[12] = 0xff; // all forms of permanent memory - sendCommand(&packetCfg, 0); // don't expect ACK - hardReset(); // cause factory default config to actually be loaded and used cleanly -} - -void SFE_UBLOX_GPS::hardReset() -{ - // Issue hard reset - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_RST; - packetCfg.len = 4; - packetCfg.startingSpot = 0; - payloadCfg[0] = 0xff; // cold start - payloadCfg[1] = 0xff; // cold start - payloadCfg[2] = 0; // 0=HW reset - payloadCfg[3] = 0; // reserved - sendCommand(&packetCfg, 0); // don't expect ACK -} - -//Changes the serial baud rate of the u-blox module, can't return success/fail 'cause ACK from modem -//is lost due to baud rate change -void SFE_UBLOX_GPS::setSerialRate(uint32_t baudrate, uint8_t uartPort, uint16_t maxWait) -{ - //Get the current config values for the UART port - getPortSettings(uartPort, maxWait); //This will load the payloadCfg array with current port settings - - if (_printDebug == true) - { - _debugSerial->print(F("Current baud rate: ")); - _debugSerial->println(((uint32_t)payloadCfg[10] << 16) | ((uint32_t)payloadCfg[9] << 8) | payloadCfg[8]); - } - - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_PRT; - packetCfg.len = 20; - packetCfg.startingSpot = 0; - - //payloadCfg is now loaded with current bytes. Change only the ones we need to - payloadCfg[8] = baudrate; - payloadCfg[9] = baudrate >> 8; - payloadCfg[10] = baudrate >> 16; - payloadCfg[11] = baudrate >> 24; - - if (_printDebug == true) - { - _debugSerial->print(F("New baud rate:")); - _debugSerial->println(((uint32_t)payloadCfg[10] << 16) | ((uint32_t)payloadCfg[9] << 8) | payloadCfg[8]); - } - - 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 u-blox module responds to -//0x42 is the default but can be changed with this command -boolean SFE_UBLOX_GPS::setI2CAddress(uint8_t deviceAddress, uint16_t maxWait) -{ - //Get the current config values for the I2C port - getPortSettings(COM_PORT_I2C, maxWait); //This will load the payloadCfg array with current port settings - - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_PRT; - packetCfg.len = 20; - packetCfg.startingSpot = 0; - - //payloadCfg is now loaded with current bytes. Change only the ones we need to - payloadCfg[4] = deviceAddress << 1; //DDC mode LSB - - if (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT) // We are only expecting an ACK - { - //Success! Now change our internal global. - _gpsI2Caddress = deviceAddress; //Store the I2C address from user - return (true); - } - return (false); -} - -//Want to see the NMEA messages on the Serial port? Here's how -void SFE_UBLOX_GPS::setNMEAOutputPort(Stream &nmeaOutputPort) -{ - _nmeaOutputPort = &nmeaOutputPort; //Store the port from user -} - -//Called regularly to check for available bytes on the user' specified port -boolean SFE_UBLOX_GPS::checkUblox(uint8_t requestedClass, uint8_t requestedID) -{ - return checkUbloxInternal(&packetCfg, requestedClass, requestedID); -} - -//Called regularly to check for available bytes on the user' specified port -boolean SFE_UBLOX_GPS::checkUbloxInternal(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) -{ - if (commType == COMM_TYPE_I2C) - return (checkUbloxI2C(incomingUBX, requestedClass, requestedID)); - else if (commType == COMM_TYPE_SERIAL) - return (checkUbloxSerial(incomingUBX, requestedClass, requestedID)); - return false; -} - -//Polls I2C for data, passing any new bytes to process() -//Returns true if new bytes are available -boolean SFE_UBLOX_GPS::checkUbloxI2C(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) -{ - if (millis() - lastCheck >= i2cPollingWait) - { - //Get the number of bytes available from the module - uint16_t bytesAvailable = 0; - _i2cPort->beginTransmission(_gpsI2Caddress); - _i2cPort->write(0xFD); //0xFD (MSB) and 0xFE (LSB) are the registers that contain number of bytes available - if (_i2cPort->endTransmission(false) != 0) //Send a restart command. Do not release bus. - return (false); //Sensor did not ACK - - _i2cPort->requestFrom((uint8_t)_gpsI2Caddress, (uint8_t)2); - if (_i2cPort->available()) - { - uint8_t msb = _i2cPort->read(); - uint8_t lsb = _i2cPort->read(); - if (lsb == 0xFF) - { - //I believe this is a u-blox bug. Device should never present an 0xFF. - if ((_printDebug == true) || (_printLimitedDebug == true)) // Print this if doing limited debugging - { - _debugSerial->println(F("checkUbloxI2C: u-blox bug, length lsb is 0xFF")); - } - if (checksumFailurePin >= 0) - { - digitalWrite((uint8_t)checksumFailurePin, LOW); - delay(10); - digitalWrite((uint8_t)checksumFailurePin, HIGH); - } - lastCheck = millis(); //Put off checking to avoid I2C bus traffic - return (false); - } - bytesAvailable = (uint16_t)msb << 8 | lsb; - } - - if (bytesAvailable == 0) - { - if (_printDebug == true) - { - _debugSerial->println(F("checkUbloxI2C: OK, zero bytes available")); - } - lastCheck = millis(); //Put off checking to avoid I2C bus traffic - return (false); - } - - //Check for undocumented bit error. We found this doing logic scans. - //This error is rare but if we incorrectly interpret the first bit of the two 'data available' bytes as 1 - //then we have far too many bytes to check. May be related to I2C setup time violations: https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/issues/40 - if (bytesAvailable & ((uint16_t)1 << 15)) - { - //Clear the MSbit - bytesAvailable &= ~((uint16_t)1 << 15); - - if ((_printDebug == true) || (_printLimitedDebug == true)) // Print this if doing limited debugging - { - _debugSerial->print(F("checkUbloxI2C: Bytes available error:")); - _debugSerial->println(bytesAvailable); - if (checksumFailurePin >= 0) - { - digitalWrite((uint8_t)checksumFailurePin, LOW); - delay(10); - digitalWrite((uint8_t)checksumFailurePin, HIGH); - } - } - } - - if (bytesAvailable > 100) - { - if (_printDebug == true) - { - _debugSerial->print(F("checkUbloxI2C: Large packet of ")); - _debugSerial->print(bytesAvailable); - _debugSerial->println(F(" bytes received")); - } - } - else - { - if (_printDebug == true) - { - _debugSerial->print(F("checkUbloxI2C: Reading ")); - _debugSerial->print(bytesAvailable); - _debugSerial->println(F(" bytes")); - } - } - - while (bytesAvailable) - { - _i2cPort->beginTransmission(_gpsI2Caddress); - _i2cPort->write(0xFF); //0xFF is the register to read data from - if (_i2cPort->endTransmission(false) != 0) //Send a restart command. Do not release bus. - return (false); //Sensor did not ACK - - //Limit to 32 bytes or whatever the buffer limit is for given platform - uint16_t bytesToRead = bytesAvailable; - if (bytesToRead > I2C_BUFFER_LENGTH) - bytesToRead = I2C_BUFFER_LENGTH; - - TRY_AGAIN: - - _i2cPort->requestFrom((uint8_t)_gpsI2Caddress, (uint8_t)bytesToRead); - if (_i2cPort->available()) - { - for (uint16_t x = 0; x < bytesToRead; x++) - { - uint8_t incoming = _i2cPort->read(); //Grab the actual character - - //Check to see if the first read is 0x7F. If it is, the module is not ready - //to respond. Stop, wait, and try again - if (x == 0) - { - if (incoming == 0x7F) - { - if ((_printDebug == true) || (_printLimitedDebug == true)) // Print this if doing limited debugging - { - _debugSerial->println(F("checkUbloxU2C: u-blox error, module not ready with data")); - } - delay(5); //In logic analyzation, the module starting responding after 1.48ms - if (checksumFailurePin >= 0) - { - digitalWrite((uint8_t)checksumFailurePin, LOW); - delay(10); - digitalWrite((uint8_t)checksumFailurePin, HIGH); - } - goto TRY_AGAIN; - } - } - - process(incoming, incomingUBX, requestedClass, requestedID); //Process this valid character - } - } - else - return (false); //Sensor did not respond - - bytesAvailable -= bytesToRead; - } - } - - return (true); - -} //end checkUbloxI2C() - -//Checks Serial for data, passing any new bytes to process() -boolean SFE_UBLOX_GPS::checkUbloxSerial(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) -{ - while (_serialPort->available()) - { - process(_serialPort->read(), incomingUBX, requestedClass, requestedID); - } - return (true); - -} //end checkUbloxSerial() - -//Processes NMEA and UBX binary sentences one byte at a time -//Take a given byte and file it into the proper array -void SFE_UBLOX_GPS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) -{ - if ((currentSentence == NONE) || (currentSentence == NMEA)) - { - if (incoming == 0xB5) //UBX binary frames start with 0xB5, aka μ - { - //This is the start of a binary sentence. Reset flags. - //We still don't know the response class - ubxFrameCounter = 0; - currentSentence = UBX; - //Reset the packetBuf.counter even though we will need to reset it again when ubxFrameCounter == 2 - packetBuf.counter = 0; - 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; - } - else if (incoming == '$') - { - currentSentence = NMEA; - } - else if (incoming == 0xD3) //RTCM frames start with 0xD3 - { - rtcmFrameCounter = 0; - currentSentence = RTCM; - } - else - { - //This character is unknown or we missed the previous start of a sentence - } - } - - //Depending on the sentence, pass the character to the individual processor - if (currentSentence == UBX) - { - //Decide what type of response this is - if ((ubxFrameCounter == 0) && (incoming != 0xB5)) //ISO 'μ' - currentSentence = NONE; //Something went wrong. Reset. - else if ((ubxFrameCounter == 1) && (incoming != 0x62)) //ASCII 'b' - currentSentence = NONE; //Something went wrong. Reset. - // Note to future self: - // There may be some duplication / redundancy in the next few lines as processUBX will also - // load information into packetBuf, but we'll do it here too for clarity - else if (ubxFrameCounter == 2) //Class - { - // Record the class in packetBuf until we know what to do with it - packetBuf.cls = incoming; // (Duplication) - rollingChecksumA = 0; //Reset our rolling checksums here (not when we receive the 0xB5) - rollingChecksumB = 0; - packetBuf.counter = 0; //Reset the packetBuf.counter (again) - packetBuf.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; // Reset the packet validity (redundant?) - packetBuf.startingSpot = incomingUBX->startingSpot; //Copy the startingSpot - } - else if (ubxFrameCounter == 3) //ID - { - // Record the ID in packetBuf until we know what to do with it - packetBuf.id = incoming; // (Duplication) - //We can now identify the type of response - //If the packet we are receiving is not an ACK then check for a class and ID match - 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)) - { - //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 - } - else - { - //This is not an ACK and we do not have a class and ID match - //so we should keep diverting data into packetBuf and ignore the payload - ignoreThisPayload = true; - } - } - else - { - // This is an ACK so it is to early to do anything with it - // We need to wait until we have received the length and data bytes - // So we should keep diverting data into packetBuf - } - } - else if (ubxFrameCounter == 4) //Length LSB - { - //We should save the length in packetBuf even if activePacketBuffer == SFE_UBLOX_PACKET_PACKETCFG - packetBuf.len = incoming; // (Duplication) - } - else if (ubxFrameCounter == 5) //Length MSB - { - //We should save the length in packetBuf even if activePacketBuffer == SFE_UBLOX_PACKET_PACKETCFG - packetBuf.len |= incoming << 8; // (Duplication) - } - else if (ubxFrameCounter == 6) //This should be the first byte of the payload unless .len is zero - { - if (packetBuf.len == 0) // Check if length is zero (hopefully this is impossible!) - { - if (_printDebug == true) - { - _debugSerial->print(F("process: ZERO LENGTH packet received: Class: 0x")); - _debugSerial->print(packetBuf.cls, HEX); - _debugSerial->print(F(" ID: 0x")); - _debugSerial->println(packetBuf.id, HEX); - } - //If length is zero (!) this will be the first byte of the checksum so record it - packetBuf.checksumA = incoming; - } - else - { - //The length is not zero so record this byte in the payload - packetBuf.payload[0] = incoming; - } - } - else if (ubxFrameCounter == 7) //This should be the second byte of the payload unless .len is zero or one - { - if (packetBuf.len == 0) // Check if length is zero (hopefully this is impossible!) - { - //If length is zero (!) this will be the second byte of the checksum so record it - packetBuf.checksumB = incoming; - } - else if (packetBuf.len == 1) // Check if length is one - { - //The length is one so this is the first byte of the checksum - packetBuf.checksumA = incoming; - } - else // Length is >= 2 so this must be a payload byte - { - packetBuf.payload[1] = incoming; - } - // Now that we have received two payload bytes, we can check for a matching ACK/NACK - if ((activePacketBuffer == SFE_UBLOX_PACKET_PACKETBUF) // If we are not already processing a data packet - && (packetBuf.cls == UBX_CLASS_ACK) // and if this is an ACK/NACK - && (packetBuf.payload[0] == requestedClass) // and if the class matches - && (packetBuf.payload[1] == requestedID)) // and if the ID matches - { - if (packetBuf.len == 2) // Check if .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) - { - _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); - - //Finally, increment the frame counter - ubxFrameCounter++; - } - else if (currentSentence == NMEA) - { - processNMEA(incoming); //Process each NMEA character - } - else if (currentSentence == RTCM) - { - processRTCMframe(incoming); //Deal with RTCM bytes - } -} - -//This is the default or generic NMEA processor. We're only going to pipe the data to serial port so we can see it. -//User could overwrite this function to pipe characters to nmea.process(c) of tinyGPS or MicroNMEA -//Or user could pipe each character to a buffer, radio, etc. -void SFE_UBLOX_GPS::processNMEA(char incoming) -{ - //If user has assigned an output port then pipe the characters there - if (_nmeaOutputPort != NULL) - _nmeaOutputPort->write(incoming); //Echo this byte to the serial port -} - -//We need to be able to identify an RTCM packet and then the length -//so that we know when the RTCM message is completely received and we then start -//listening for other sentences (like NMEA or UBX) -//RTCM packet structure is very odd. I never found RTCM STANDARD 10403.2 but -//http://d1.amobbs.com/bbs_upload782111/files_39/ourdev_635123CK0HJT.pdf is good -//https://dspace.cvut.cz/bitstream/handle/10467/65205/F3-BP-2016-Shkalikava-Anastasiya-Prenos%20polohove%20informace%20prostrednictvim%20datove%20site.pdf?sequence=-1 -//Lead me to: https://forum.u-blox.com/index.php/4348/how-to-read-rtcm-messages-from-neo-m8p -//RTCM 3.2 bytes look like this: -//Byte 0: Always 0xD3 -//Byte 1: 6-bits of zero -//Byte 2: 10-bits of length of this packet including the first two-ish header bytes, + 6. -//byte 3 + 4 bits: Msg type 12 bits -//Example: D3 00 7C 43 F0 ... / 0x7C = 124+6 = 130 bytes in this packet, 0x43F = Msg type 1087 -void SFE_UBLOX_GPS::processRTCMframe(uint8_t incoming) -{ - if (rtcmFrameCounter == 1) - { - rtcmLen = (incoming & 0x03) << 8; //Get the last two bits of this byte. Bits 8&9 of 10-bit length - } - else if (rtcmFrameCounter == 2) - { - rtcmLen |= incoming; //Bits 0-7 of packet length - rtcmLen += 6; //There are 6 additional bytes of what we presume is header, msgType, CRC, and stuff - } - /*else if (rtcmFrameCounter == 3) - { - rtcmMsgType = incoming << 4; //Message Type, MS 4 bits - } - else if (rtcmFrameCounter == 4) - { - rtcmMsgType |= (incoming >> 4); //Message Type, bits 0-7 - }*/ - - rtcmFrameCounter++; - - processRTCM(incoming); //Here is where we expose this byte to the user - - if (rtcmFrameCounter == rtcmLen) - { - //We're done! - currentSentence = NONE; //Reset and start looking for next sentence type - } -} - -//This function is called for each byte of an RTCM frame -//Ths user can overwrite this function and process the RTCM frame as they please -//Bytes can be piped to Serial or other interface. The consumer could be a radio or the internet (Ntrip broadcaster) -void SFE_UBLOX_GPS::processRTCM(uint8_t incoming) -{ - //Radio.sendReliable((String)incoming); //An example of passing this byte to a radio - - //_debugSerial->write(incoming); //An example of passing this byte out the serial port - - //Debug printing - // _debugSerial->print(F(" ")); - // if(incoming < 0x10) _debugSerial->print(F("0")); - // if(incoming < 0x10) _debugSerial->print(F("0")); - // _debugSerial->print(incoming, HEX); - // if(rtcmFrameCounter % 16 == 0) _debugSerial->println(); -} - -//Given a character, file it away into the uxb packet structure -//Set valid to VALID or NOT_VALID once sentence is completely received and passes or fails CRC -//The payload portion of the packet can be 100s of bytes but the max array -//size is MAX_PAYLOAD_SIZE bytes. startingSpot can be set so we only record -//a subset of bytes within a larger packet. -void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) -{ - //Add all incoming bytes to the rolling checksum - //Stop at len+4 as this is the checksum bytes to that should not be added to the rolling checksum - if (incomingUBX->counter < incomingUBX->len + 4) - addToChecksum(incoming); - - if (incomingUBX->counter == 0) - { - incomingUBX->cls = incoming; - } - else if (incomingUBX->counter == 1) - { - incomingUBX->id = incoming; - } - else if (incomingUBX->counter == 2) //Len LSB - { - incomingUBX->len = incoming; - } - else if (incomingUBX->counter == 3) //Len MSB - { - incomingUBX->len |= incoming << 8; - } - else if (incomingUBX->counter == incomingUBX->len + 4) //ChecksumA - { - incomingUBX->checksumA = incoming; - } - else if (incomingUBX->counter == incomingUBX->len + 5) //ChecksumB - { - incomingUBX->checksumB = incoming; - - currentSentence = NONE; //We're done! Reset the sentence to being looking for a new start char - - //Validate this sentence - if ((incomingUBX->checksumA == rollingChecksumA) && (incomingUBX->checksumB == rollingChecksumB)) - { - incomingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_VALID; // Flag the packet as valid - - // Let's check if the class and ID match the requestedClass and requestedID - // Remember - this could be a data packet or an ACK packet - if ((incomingUBX->cls == requestedClass) && (incomingUBX->id == requestedID)) - { - incomingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_VALID; // If we have a match, set the classAndIDmatch flag to valid - } - - // If this is an ACK then let's check if the class and ID match the requestedClass and requestedID - else if ((incomingUBX->cls == UBX_CLASS_ACK) && (incomingUBX->id == UBX_ACK_ACK) && (incomingUBX->payload[0] == requestedClass) && (incomingUBX->payload[1] == requestedID)) - { - incomingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_VALID; // If we have a match, set the classAndIDmatch flag to valid - } - - // If this is a NACK then let's check if the class and ID match the requestedClass and requestedID - else if ((incomingUBX->cls == UBX_CLASS_ACK) && (incomingUBX->id == UBX_ACK_NACK) && (incomingUBX->payload[0] == requestedClass) && (incomingUBX->payload[1] == requestedID)) - { - incomingUBX->classAndIDmatch = SFE_UBLOX_PACKET_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(incomingUBX->payload[0], HEX); - _debugSerial->print(F(" Requested ID: 0x")); - _debugSerial->println(incomingUBX->payload[1], HEX); - } - } - - if (_printDebug == true) - { - _debugSerial->print(F("Incoming: Size: ")); - _debugSerial->print(incomingUBX->len); - _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 - if (ignoreThisPayload == false) - { - processUBXpacket(incomingUBX); - } - } - else // Checksum failure - { - 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)) // Print this if doing limited debugging - { - //Drive an external pin to allow for easier logic analyzation - if (checksumFailurePin >= 0) - { - digitalWrite((uint8_t)checksumFailurePin, LOW); - delay(10); - digitalWrite((uint8_t)checksumFailurePin, HIGH); - } - - _debugSerial->print(F("Checksum failed:")); - _debugSerial->print(F(" checksumA: ")); - _debugSerial->print(incomingUBX->checksumA); - _debugSerial->print(F(" checksumB: ")); - _debugSerial->print(incomingUBX->checksumB); - - _debugSerial->print(F(" rollingChecksumA: ")); - _debugSerial->print(rollingChecksumA); - _debugSerial->print(F(" rollingChecksumB: ")); - _debugSerial->print(rollingChecksumB); - _debugSerial->println(); - - _debugSerial->print(F("Failed : ")); - _debugSerial->print(F("Size: ")); - _debugSerial->print(incomingUBX->len); - _debugSerial->print(F(" Received: ")); - printPacket(incomingUBX); - } - } - } - else //Load this byte into the payload array - { - //If a UBX_NAV_PVT packet comes in asynchronously, we need to fudge the startingSpot - uint16_t startingSpot = incomingUBX->startingSpot; - if (incomingUBX->cls == UBX_CLASS_NAV && incomingUBX->id == UBX_NAV_PVT) - startingSpot = 0; - //Begin recording if counter goes past startingSpot - if ((incomingUBX->counter - 4) >= startingSpot) - { - //Check to see if we have room for this byte - if (((incomingUBX->counter - 4) - startingSpot) < MAX_PAYLOAD_SIZE) //If counter = 208, starting spot = 200, we're good to record. - { - // Check if this is payload data which should be ignored - if (ignoreThisPayload == false) - { - incomingUBX->payload[incomingUBX->counter - 4 - startingSpot] = incoming; //Store this byte into payload array - } - } - } - } - - //Increment the counter - incomingUBX->counter++; - - if (incomingUBX->counter == MAX_PAYLOAD_SIZE) - { - //Something has gone very wrong - currentSentence = NONE; //Reset the sentence to being looking for a new start char - if (_printDebug == true) - { - _debugSerial->println(F("processUBX: counter hit MAX_PAYLOAD_SIZE")); - } - } -} - -//Once a packet has been received and validated, identify this packet's class/id and update internal flags -//Note: if the user requests a PVT or a HPPOSLLH message using a custom packet, the data extraction will -// not work as expected beacuse extractLong etc are hardwired to packetCfg payloadCfg. Ideally -// extractLong etc should be updated so they receive a pointer to the packet buffer. -void SFE_UBLOX_GPS::processUBXpacket(ubxPacket *msg) -{ - switch (msg->cls) - { - case UBX_CLASS_NAV: - //u-blox8 length == 92 - //u-blox7 length == 84 - if ((msg->id == UBX_NAV_PVT) && ((msg->len == 92) || (msg->len == 84))) - { - //Parse various byte fields into global vars - constexpr int startingSpot = 0; //fixed value used in processUBX - - timeOfWeek = extractLong(0); - gpsMillisecond = extractLong(0) % 1000; //Get last three digits of iTOW - gpsYear = extractInt(4); - gpsMonth = extractByte(6); - gpsDay = extractByte(7); - gpsHour = extractByte(8); - gpsMinute = extractByte(9); - gpsSecond = extractByte(10); - gpsNanosecond = extractLong(16); //Includes milliseconds - - fixType = extractByte(20 - startingSpot); - //Note: the u-blox7 does not support carrSoln. carrierSolution will be zero. - carrierSolution = extractByte(21 - startingSpot) >> 6; //Get 6th&7th bits of this byte - SIV = extractByte(23 - startingSpot); - longitude = extractLong(24 - startingSpot); - latitude = extractLong(28 - startingSpot); - altitude = extractLong(32 - startingSpot); - altitudeMSL = extractLong(36 - startingSpot); - groundSpeed = extractLong(60 - startingSpot); - headingOfMotion = extractLong(64 - startingSpot); - pDOP = extractInt(76 - startingSpot); - - //Mark all datums as fresh (not read before) - moduleQueried.gpsiTOW = true; - moduleQueried.gpsYear = true; - moduleQueried.gpsMonth = true; - moduleQueried.gpsDay = true; - moduleQueried.gpsHour = true; - moduleQueried.gpsMinute = true; - moduleQueried.gpsSecond = true; - moduleQueried.gpsNanosecond = true; - - moduleQueried.all = true; - moduleQueried.longitude = true; - moduleQueried.latitude = true; - moduleQueried.altitude = true; - moduleQueried.altitudeMSL = true; - moduleQueried.SIV = true; - moduleQueried.fixType = true; - moduleQueried.carrierSolution = true; - moduleQueried.groundSpeed = true; - moduleQueried.headingOfMotion = true; - moduleQueried.pDOP = true; - } - else if (msg->id == UBX_NAV_TIMEUTC && msg->len == 20) - { - timeOfWeek = extractLong(0); - gpsMillisecond = extractLong(0) % 1000; //Get last three digits of iTOW - // extractLong(4); // time accuracy estimate - gpsYear = extractInt(12); - gpsMonth = extractByte(14); - gpsDay = extractByte(15); - gpsHour = extractByte(16); - gpsMinute = extractByte(17); - gpsSecond = extractByte(18); - gpsNanosecond = extractLong(8); //Includes milliseconds - uint8_t valid = extractByte(19); - bool gotTime = (valid & 4) ? true : false; // assume all other fields filled once we have TUTC - - //Mark all datums as fresh (not read before) - moduleQueried.gpsiTOW = gotTime; // valid tow - moduleQueried.gpsYear = gotTime; // valid week num - moduleQueried.gpsMonth = gotTime; - moduleQueried.gpsDay = gotTime; // valid UTC - moduleQueried.gpsHour = gotTime; - moduleQueried.gpsMinute = gotTime; - moduleQueried.gpsSecond = gotTime; - moduleQueried.gpsNanosecond = gotTime; - } - else if (msg->id == UBX_NAV_POSLLH && msg->len == 28) - { - timeOfWeek = extractLong(0); - longitude = extractLong(4); - latitude = extractLong(8); - altitude = extractLong(12); - altitudeMSL = extractLong(16); - horizontalAccuracy = extractLong(20); - verticalAccuracy = extractLong(24); - - moduleQueried.gpsiTOW = true; - moduleQueried.longitude = true; - moduleQueried.latitude = true; - moduleQueried.altitude = true; - moduleQueried.altitudeMSL = true; - highResModuleQueried.horizontalAccuracy = true; - highResModuleQueried.verticalAccuracy = true; - } - else if (msg->id == UBX_NAV_HPPOSLLH && msg->len == 36) - { - timeOfWeek = extractLong(4); - highResLongitude = extractLong(8); - highResLatitude = extractLong(12); - elipsoid = extractLong(16); - meanSeaLevel = extractLong(20); - highResLongitudeHp = extractSignedChar(24); - highResLatitudeHp = extractSignedChar(25); - elipsoidHp = extractSignedChar(26); - meanSeaLevelHp = extractSignedChar(27); - horizontalAccuracy = extractLong(28); - verticalAccuracy = extractLong(32); - - highResModuleQueried.all = true; - highResModuleQueried.highResLatitude = true; - highResModuleQueried.highResLatitudeHp = true; - highResModuleQueried.highResLongitude = true; - highResModuleQueried.highResLongitudeHp = true; - highResModuleQueried.elipsoid = true; - highResModuleQueried.elipsoidHp = true; - highResModuleQueried.meanSeaLevel = true; - highResModuleQueried.meanSeaLevelHp = true; - highResModuleQueried.geoidSeparation = true; - highResModuleQueried.horizontalAccuracy = true; - highResModuleQueried.verticalAccuracy = true; - moduleQueried.gpsiTOW = true; // this can arrive via HPPOS too. - - if (_printDebug == true) - { - _debugSerial->print(F("Sec: ")); - _debugSerial->print(((float)extractLong(4)) / 1000.0f); - _debugSerial->print(F(" ")); - _debugSerial->print(F("LON: ")); - _debugSerial->print(((float)(int32_t)extractLong(8)) / 10000000.0f); - _debugSerial->print(F(" ")); - _debugSerial->print(F("LAT: ")); - _debugSerial->print(((float)(int32_t)extractLong(12)) / 10000000.0f); - _debugSerial->print(F(" ")); - _debugSerial->print(F("ELI M: ")); - _debugSerial->print(((float)(int32_t)extractLong(16)) / 1000.0f); - _debugSerial->print(F(" ")); - _debugSerial->print(F("MSL M: ")); - _debugSerial->print(((float)(int32_t)extractLong(20)) / 1000.0f); - _debugSerial->print(F(" ")); - _debugSerial->print(F("LON HP: ")); - _debugSerial->print(extractSignedChar(24)); - _debugSerial->print(F(" ")); - _debugSerial->print(F("LAT HP: ")); - _debugSerial->print(extractSignedChar(25)); - _debugSerial->print(F(" ")); - _debugSerial->print(F("ELI HP: ")); - _debugSerial->print(extractSignedChar(26)); - _debugSerial->print(F(" ")); - _debugSerial->print(F("MSL HP: ")); - _debugSerial->print(extractSignedChar(27)); - _debugSerial->print(F(" ")); - _debugSerial->print(F("HA 2D M: ")); - _debugSerial->print(((float)(int32_t)extractLong(28)) / 10000.0f); - _debugSerial->print(F(" ")); - _debugSerial->print(F("VERT M: ")); - _debugSerial->println(((float)(int32_t)extractLong(32)) / 10000.0f); - } - } - else { - if (_printDebug == true) - { - _debugSerial->print(F("Unexpected nav packet ")); - _debugSerial->println(msg->id); - } - } - break; - } -} - -//Given a packet and payload, send everything including CRC bytes via I2C port -sfe_ublox_status_e SFE_UBLOX_GPS::sendCommand(ubxPacket *outgoingUBX, uint16_t maxWait) -{ - sfe_ublox_status_e retVal = SFE_UBLOX_STATUS_SUCCESS; - - calcChecksum(outgoingUBX); //Sets checksum A and B bytes of the packet - - if (_printDebug == true) - { - _debugSerial->print(F("\nSending: ")); - printPacket(outgoingUBX); - } - - if (commType == COMM_TYPE_I2C) - { - retVal = sendI2cCommand(outgoingUBX, maxWait); - if (retVal != SFE_UBLOX_STATUS_SUCCESS) - { - if (_printDebug == true) - { - _debugSerial->println(F("Send I2C Command failed")); - } - return retVal; - } - } - else if (commType == COMM_TYPE_SERIAL) - { - sendSerialCommand(outgoingUBX); - } - - if (maxWait > 0) - { - //Depending on what we just sent, either we need to look for an ACK or not - if (outgoingUBX->cls == UBX_CLASS_CFG) - { - if (_printDebug == true) - { - _debugSerial->println(F("sendCommand: Waiting for ACK response")); - } - retVal = waitForACKResponse(outgoingUBX, outgoingUBX->cls, outgoingUBX->id, maxWait); //Wait for Ack response - } - else - { - if (_printDebug == true) - { - _debugSerial->println(F("sendCommand: Waiting for No ACK response")); - } - retVal = waitForNoACKResponse(outgoingUBX, outgoingUBX->cls, outgoingUBX->id, maxWait); //Wait for Ack response - } - } - return retVal; -} - -//Returns false if sensor fails to respond to I2C traffic -sfe_ublox_status_e SFE_UBLOX_GPS::sendI2cCommand(ubxPacket *outgoingUBX, uint16_t maxWait) -{ - //Point at 0xFF data register - _i2cPort->beginTransmission((uint8_t)_gpsI2Caddress); //There is no register to write to, we just begin writing data bytes - _i2cPort->write(0xFF); - if (_i2cPort->endTransmission() != 0) //Don't release bus - return (SFE_UBLOX_STATUS_I2C_COMM_FAILURE); //Sensor did not ACK - - //Write header bytes - _i2cPort->beginTransmission((uint8_t)_gpsI2Caddress); //There is no register to write to, we just begin writing data bytes - _i2cPort->write(UBX_SYNCH_1); //μ - oh ublox, you're funny. I will call you micro-blox from now on. - _i2cPort->write(UBX_SYNCH_2); //b - _i2cPort->write(outgoingUBX->cls); - _i2cPort->write(outgoingUBX->id); - _i2cPort->write(outgoingUBX->len & 0xFF); //LSB - _i2cPort->write(outgoingUBX->len >> 8); //MSB - if (_i2cPort->endTransmission(false) != 0) //Do not release bus - return (SFE_UBLOX_STATUS_I2C_COMM_FAILURE); //Sensor did not ACK - - //Write payload. Limit the sends into 32 byte chunks - //This code based on ublox: https://forum.u-blox.com/index.php/20528/how-to-use-i2c-to-get-the-nmea-frames - uint16_t bytesToSend = outgoingUBX->len; - - //"The number of data bytes must be at least 2 to properly distinguish - //from the write access to set the address counter in random read accesses." - uint16_t startSpot = 0; - while (bytesToSend > 1) - { - uint8_t len = bytesToSend; - if (len > I2C_BUFFER_LENGTH) - len = I2C_BUFFER_LENGTH; - - _i2cPort->beginTransmission((uint8_t)_gpsI2Caddress); - //_i2cPort->write(outgoingUBX->payload, len); //Write a portion of the payload to the bus - - for (uint16_t x = 0; x < len; x++) - _i2cPort->write(outgoingUBX->payload[startSpot + x]); //Write a portion of the payload to the bus - - if (_i2cPort->endTransmission(false) != 0) //Don't release bus - return (SFE_UBLOX_STATUS_I2C_COMM_FAILURE); //Sensor did not ACK - - //*outgoingUBX->payload += len; //Move the pointer forward - startSpot += len; //Move the pointer forward - bytesToSend -= len; - } - - //Write checksum - _i2cPort->beginTransmission((uint8_t)_gpsI2Caddress); - if (bytesToSend == 1) - _i2cPort->write(outgoingUBX->payload, 1); - _i2cPort->write(outgoingUBX->checksumA); - _i2cPort->write(outgoingUBX->checksumB); - - //All done transmitting bytes. Release bus. - if (_i2cPort->endTransmission() != 0) - return (SFE_UBLOX_STATUS_I2C_COMM_FAILURE); //Sensor did not ACK - return (SFE_UBLOX_STATUS_SUCCESS); -} - -//Given a packet and payload, send everything including CRC bytesA via Serial port -void SFE_UBLOX_GPS::sendSerialCommand(ubxPacket *outgoingUBX) -{ - //Write header bytes - _serialPort->write(UBX_SYNCH_1); //μ - oh ublox, you're funny. I will call you micro-blox from now on. - _serialPort->write(UBX_SYNCH_2); //b - _serialPort->write(outgoingUBX->cls); - _serialPort->write(outgoingUBX->id); - _serialPort->write(outgoingUBX->len & 0xFF); //LSB - _serialPort->write(outgoingUBX->len >> 8); //MSB - - //Write payload. - for (int i = 0; i < outgoingUBX->len; i++) - { - _serialPort->write(outgoingUBX->payload[i]); - } - - //Write checksum - _serialPort->write(outgoingUBX->checksumA); - _serialPort->write(outgoingUBX->checksumB); -} - -//Returns true if I2C device ack's -boolean SFE_UBLOX_GPS::isConnected(uint16_t maxWait) -{ - if (commType == COMM_TYPE_I2C) - { - _i2cPort->beginTransmission((uint8_t)_gpsI2Caddress); - if (_i2cPort->endTransmission() != 0) - return false; //Sensor did not ack - } - - // Query navigation rate to see whether we get a meaningful response - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_RATE; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_RECEIVED); // We are polling the RATE so we expect data and an ACK -} - -//Given a message, calc and store the two byte "8-Bit Fletcher" checksum over the entirety of the message -//This is called before we send a command message -void SFE_UBLOX_GPS::calcChecksum(ubxPacket *msg) -{ - msg->checksumA = 0; - msg->checksumB = 0; - - msg->checksumA += msg->cls; - msg->checksumB += msg->checksumA; - - msg->checksumA += msg->id; - msg->checksumB += msg->checksumA; - - msg->checksumA += (msg->len & 0xFF); - msg->checksumB += msg->checksumA; - - msg->checksumA += (msg->len >> 8); - msg->checksumB += msg->checksumA; - - for (uint16_t i = 0; i < msg->len; i++) - { - msg->checksumA += msg->payload[i]; - msg->checksumB += msg->checksumA; - } -} - -//Given a message and a byte, add to rolling "8-Bit Fletcher" checksum -//This is used when receiving messages from module -void SFE_UBLOX_GPS::addToChecksum(uint8_t incoming) -{ - rollingChecksumA += incoming; - rollingChecksumB += rollingChecksumA; -} - -//Pretty prints the current ubxPacket -void SFE_UBLOX_GPS::printPacket(ubxPacket *packet) -{ - if (_printDebug == true) - { - _debugSerial->print(F("CLS:")); - if (packet->cls == UBX_CLASS_NAV) //1 - _debugSerial->print(F("NAV")); - else if (packet->cls == UBX_CLASS_ACK) //5 - _debugSerial->print(F("ACK")); - else if (packet->cls == UBX_CLASS_CFG) //6 - _debugSerial->print(F("CFG")); - else if (packet->cls == UBX_CLASS_MON) //0x0A - _debugSerial->print(F("MON")); - else - { - _debugSerial->print(F("0x")); - _debugSerial->print(packet->cls, HEX); - } - - _debugSerial->print(F(" ID:")); - if (packet->cls == UBX_CLASS_NAV && packet->id == UBX_NAV_PVT) - _debugSerial->print(F("PVT")); - else if (packet->cls == UBX_CLASS_CFG && packet->id == UBX_CFG_RATE) - _debugSerial->print(F("RATE")); - else if (packet->cls == UBX_CLASS_CFG && packet->id == UBX_CFG_CFG) - _debugSerial->print(F("SAVE")); - else - { - _debugSerial->print(F("0x")); - _debugSerial->print(packet->id, HEX); - } - - _debugSerial->print(F(" Len: 0x")); - _debugSerial->print(packet->len, HEX); - - // Only print the payload is ignoreThisPayload is false otherwise - // we could be printing gibberish from beyond the end of packetBuf - if (ignoreThisPayload == false) - { - _debugSerial->print(F(" Payload:")); - - for (int x = 0; x < packet->len; x++) - { - _debugSerial->print(F(" ")); - _debugSerial->print(packet->payload[x], HEX); - } - } - else - { - _debugSerial->print(F(" Payload: IGNORED")); - } - _debugSerial->println(); - } -} - -//=-=-=-=-=-=-=-= Specific commands =-=-=-=-=-=-=-==-=-=-=-=-=-=-= -//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - -//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. - -//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 - -//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) - -//We need to think carefully about how interleaved PVT packets affect things. -//It is entirely possible that our packetCfg and packetAck were received successfully -//but while we are still in the "if (checkUblox() == true)" loop a PVT packet is processed -//or _starts_ to arrive (remember that Serial data can arrive very slowly). - -//Returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got an ACK and a valid packetCfg (module is responding with register content) -//Returns SFE_UBLOX_STATUS_DATA_SENT if we got an ACK and no packetCfg (no valid packetCfg needed, module absorbs new register data) -//Returns SFE_UBLOX_STATUS_FAIL if something very bad happens (e.g. a double checksum failure) -//Returns SFE_UBLOX_STATUS_COMMAND_NACK if the packet was not-acknowledged (NACK) -//Returns SFE_UBLOX_STATUS_CRC_FAIL if we had a checksum failure -//Returns SFE_UBLOX_STATUS_TIMEOUT if we timed out -//Returns SFE_UBLOX_STATUS_DATA_OVERWRITTEN if we got an ACK and a valid packetCfg but that the packetCfg has been -// or is currently being overwritten (remember that Serial data can arrive very slowly) -sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime) -{ - outgoingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; //This will go VALID (or NOT_VALID) when we receive a response to the packet we sent - packetAck.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - packetBuf.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - outgoingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; // This will go VALID (or NOT_VALID) when we receive a packet that matches the requested class and ID - packetAck.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - packetBuf.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - - unsigned long startTime = millis(); - while (millis() - startTime < maxTime) - { - 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 (_printDebug == true) - { - _debugSerial->print(F("waitForACKResponse: valid data and valid ACK received after ")); - _debugSerial->print(millis() - startTime); - _debugSerial->println(F(" msec")); - } - return (SFE_UBLOX_STATUS_DATA_RECEIVED); //We received valid data and a correct ACK! - } - - // We 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 a PVT packet. - else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED) && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID)) - { - if (_printDebug == true) - { - _debugSerial->print(F("waitForACKResponse: no data and valid ACK after ")); - _debugSerial->print(millis() - startTime); - _debugSerial->println(F(" msec")); - } - return (SFE_UBLOX_STATUS_DATA_SENT); //We got an ACK but no data... - } - - // If both the outgoingUBX->classAndIDmatch and packetAck.classAndIDmatch are VALID - // but the outgoingUBX->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) && (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 - // are NOT_VALID then we can be confident we have had a checksum failure on the data packet - else if ((packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) && (outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) && (outgoingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID)) - { - if (_printDebug == true) - { - _debugSerial->print(F("waitForACKResponse: CRC failed after ")); - _debugSerial->print(millis() - startTime); - _debugSerial->println(F(" msec")); - } - return (SFE_UBLOX_STATUS_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.classAndIDmatch == SFE_UBLOX_PACKET_NOTACKNOWLEDGED) - { - if (_printDebug == true) - { - _debugSerial->print(F("waitForACKResponse: data was NOTACKNOWLEDGED (NACK) after ")); - _debugSerial->print(millis() - startTime); - _debugSerial->println(F(" msec")); - } - return (SFE_UBLOX_STATUS_COMMAND_NACK); //We received a NACK! - } - - // If the outgoingUBX->classAndIDmatch is VALID but the packetAck.classAndIDmatch is NOT_VALID - // 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)) - { - if (_printDebug == true) - { - _debugSerial->print(F("waitForACKResponse: VALID data and INVALID ACK received after ")); - _debugSerial->print(millis() - startTime); - _debugSerial->println(F(" msec")); - } - 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 - // 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)) - { - if (_printDebug == true) - { - _debugSerial->print(F("waitForACKResponse: INVALID data and INVALID ACK received after ")); - _debugSerial->print(millis() - startTime); - _debugSerial->println(F(" msec")); - } - return (SFE_UBLOX_STATUS_FAIL); //We received invalid data and an invalid ACK! - } - - // If the outgoingUBX->classAndIDmatch is VALID and the packetAck.classAndIDmatch is NOT_DEFINED - // 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)) - { - 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); - } //while (millis() - startTime < maxTime) - - // 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 (_printDebug == true) - { - _debugSerial->print(F("waitForACKResponse: TIMEOUT with valid data after ")); - _debugSerial->print(millis() - startTime); - _debugSerial->println(F(" msec. ")); - } - return (SFE_UBLOX_STATUS_DATA_RECEIVED); //We received valid data... But no ACK! - } - - if (_printDebug == true) - { - _debugSerial->print(F("waitForACKResponse: TIMEOUT after ")); - _debugSerial->print(millis() - startTime); - _debugSerial->println(F(" msec.")); - } - - return (SFE_UBLOX_STATUS_TIMEOUT); -} - -//For non-CFG queries no ACK is sent so we use this function -//Returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got a config packet full of response data that has CLS/ID match to our query packet -//Returns SFE_UBLOX_STATUS_CRC_FAIL if we got a corrupt config packet that has CLS/ID match to our query packet -//Returns SFE_UBLOX_STATUS_TIMEOUT if we timed out -//Returns SFE_UBLOX_STATUS_DATA_OVERWRITTEN if we got an a valid packetCfg but that the packetCfg has been -// or is currently being overwritten (remember that Serial data can arrive very slowly) -sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(ubxPacket *outgoingUBX, uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime) -{ - outgoingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; //This will go VALID (or NOT_VALID) when we receive a response to the packet we sent - packetAck.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - packetBuf.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - outgoingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; // This will go VALID (or NOT_VALID) when we receive a packet that matches the requested class and ID - packetAck.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - packetBuf.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - - unsigned long startTime = millis(); - while (millis() - startTime < maxTime) - { - if (checkUbloxInternal(outgoingUBX, 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 (_printDebug == true) - { - _debugSerial->print(F("waitForNoACKResponse: valid data with CLS/ID match after ")); - _debugSerial->print(millis() - startTime); - _debugSerial->println(F(" msec")); - } - return (SFE_UBLOX_STATUS_DATA_RECEIVED); //We received valid data! - } - - // 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); - } - - if (_printDebug == true) - { - _debugSerial->print(F("waitForNoACKResponse: TIMEOUT after ")); - _debugSerial->print(millis() - startTime); - _debugSerial->println(F(" msec. No packet received.")); - } - - return (SFE_UBLOX_STATUS_TIMEOUT); -} - -//Save current configuration to flash and BBR (battery backed RAM) -//This still works but it is the old way of configuring ublox modules. See getVal and setVal for the new methods -boolean SFE_UBLOX_GPS::saveConfiguration(uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_CFG; - packetCfg.len = 12; - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint8_t x = 0; x < packetCfg.len; x++) - packetCfg.payload[x] = 0; - - packetCfg.payload[4] = 0xFF; //Set any bit in the saveMask field to save current config to Flash and BBR - packetCfg.payload[5] = 0xFF; - - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Save the selected configuration sub-sections to flash and BBR (battery backed RAM) -//This still works but it is the old way of configuring ublox modules. See getVal and setVal for the new methods -boolean SFE_UBLOX_GPS::saveConfigSelective(uint32_t configMask, uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_CFG; - packetCfg.len = 12; - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint8_t x = 0; x < packetCfg.len; x++) - packetCfg.payload[x] = 0; - - packetCfg.payload[4] = configMask & 0xFF; //Set the appropriate bits in the saveMask field to save current config to Flash and BBR - packetCfg.payload[5] = (configMask >> 8) & 0xFF; - packetCfg.payload[6] = (configMask >> 16) & 0xFF; - packetCfg.payload[7] = (configMask >> 24) & 0xFF; - - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Reset module to factory defaults -//This still works but it is the old way of configuring ublox modules. See getVal and setVal for the new methods -boolean SFE_UBLOX_GPS::factoryDefault(uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_CFG; - packetCfg.len = 12; - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint8_t x = 0; x < packetCfg.len; x++) - packetCfg.payload[x] = 0; - - packetCfg.payload[0] = 0xFF; //Set any bit in the clearMask field to clear saved config - packetCfg.payload[1] = 0xFF; - packetCfg.payload[8] = 0xFF; //Set any bit in the loadMask field to discard current config and rebuild from lower non-volatile memory layers - packetCfg.payload[9] = 0xFF; - - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Given a group, ID and size, return the value of this config spot -//The 32-bit key is put together from group/ID/size. See other getVal to send key directly. -//Configuration of modern u-blox modules is now done via getVal/setVal/delVal, ie protocol v27 and above found on ZED-F9P -uint8_t SFE_UBLOX_GPS::getVal8(uint16_t group, uint16_t id, uint8_t size, uint8_t layer, uint16_t maxWait) -{ - //Create key - uint32_t key = 0; - key |= (uint32_t)id; - key |= (uint32_t)group << 16; - key |= (uint32_t)size << 28; - - if (_printDebug == true) - { - _debugSerial->print(F("key: 0x")); - _debugSerial->print(key, HEX); - _debugSerial->println(); - } - - return getVal8(key, layer, maxWait); -} - -//Given a key, return its value -//This function takes a full 32-bit key -//Default layer is BBR -//Configuration of modern u-blox modules is now done via getVal/setVal/delVal, ie protocol v27 and above found on ZED-F9P -uint8_t SFE_UBLOX_GPS::getVal8(uint32_t key, uint8_t layer, uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_VALGET; - packetCfg.len = 4 + 4 * 1; //While multiple keys are allowed, we will send only one key at a time - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint8_t x = 0; x < packetCfg.len; x++) - packetCfg.payload[x] = 0; - - //VALGET uses different memory layer definitions to VALSET - //because it can only return the value for one layer. - //So we need to fiddle the layer here. - //And just to complicate things further, the ZED-F9P only responds - //correctly to layer 0 (RAM) and layer 7 (Default)! - uint8_t getLayer = 7; // 7 is the "Default Layer" - if ((layer & VAL_LAYER_RAM) == VAL_LAYER_RAM) // Did the user request the RAM layer? - { - getLayer = 0; // Layer 0 is RAM - } - - payloadCfg[0] = 0; //Message Version - set to 0 - payloadCfg[1] = getLayer; //Layer - - //Load key into outgoing payload - payloadCfg[4] = key >> 8 * 0; //Key LSB - payloadCfg[5] = key >> 8 * 1; - payloadCfg[6] = key >> 8 * 2; - payloadCfg[7] = key >> 8 * 3; - - if (_printDebug == true) - { - _debugSerial->print(F("key: 0x")); - _debugSerial->print(key, HEX); - _debugSerial->println(); - } - - //Send VALGET command with this key - - sfe_ublox_status_e retVal = sendCommand(&packetCfg, maxWait); - if (_printDebug == true) - { - _debugSerial->print(F("getVal8: sendCommand returned: ")); - _debugSerial->println(statusString(retVal)); - } - if (retVal != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - return (0); //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?) - //Response is 8 bytes plus cfg data - //if(packet->len > 8+1) - - //Pull the requested value from the response - //Response starts at 4+1*N with the 32-bit key so the actual data we're looking for is at 8+1*N - return (extractByte(8)); -} - -//Given a key, set a 16-bit value -//This function takes a full 32-bit key -//Default layer is BBR -//Configuration of modern u-blox modules is now done via getVal/setVal/delVal, ie protocol v27 and above found on ZED-F9P -uint8_t SFE_UBLOX_GPS::setVal(uint32_t key, uint16_t value, uint8_t layer, uint16_t maxWait) -{ - return setVal16(key, value, layer, maxWait); -} - -//Given a key, set a 16-bit value -//This function takes a full 32-bit key -//Default layer is BBR -//Configuration of modern u-blox modules is now done via getVal/setVal/delVal, ie protocol v27 and above found on ZED-F9P -uint8_t SFE_UBLOX_GPS::setVal16(uint32_t key, uint16_t value, uint8_t layer, uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_VALSET; - packetCfg.len = 4 + 4 + 2; //4 byte header, 4 byte key ID, 2 bytes of value - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint16_t x = 0; x < packetCfg.len; x++) - packetCfg.payload[x] = 0; - - payloadCfg[0] = 0; //Message Version - set to 0 - payloadCfg[1] = layer; //By default we ask for the BBR layer - - //Load key into outgoing payload - payloadCfg[4] = key >> 8 * 0; //Key LSB - payloadCfg[5] = key >> 8 * 1; - payloadCfg[6] = key >> 8 * 2; - payloadCfg[7] = key >> 8 * 3; - - //Load user's value - payloadCfg[8] = value >> 8 * 0; //Value LSB - payloadCfg[9] = value >> 8 * 1; - - //Send VALSET command with this key and value - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Given a key, set an 8-bit value -//This function takes a full 32-bit key -//Default layer is BBR -//Configuration of modern u-blox modules is now done via getVal/setVal/delVal, ie protocol v27 and above found on ZED-F9P -uint8_t SFE_UBLOX_GPS::setVal8(uint32_t key, uint8_t value, uint8_t layer, uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_VALSET; - packetCfg.len = 4 + 4 + 1; //4 byte header, 4 byte key ID, 1 byte value - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint16_t x = 0; x < packetCfg.len; x++) - packetCfg.payload[x] = 0; - - payloadCfg[0] = 0; //Message Version - set to 0 - payloadCfg[1] = layer; //By default we ask for the BBR layer - - //Load key into outgoing payload - payloadCfg[4] = key >> 8 * 0; //Key LSB - payloadCfg[5] = key >> 8 * 1; - payloadCfg[6] = key >> 8 * 2; - payloadCfg[7] = key >> 8 * 3; - - //Load user's value - payloadCfg[8] = value; //Value - - //Send VALSET command with this key and value - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Given a key, set a 32-bit value -//This function takes a full 32-bit key -//Default layer is BBR -//Configuration of modern u-blox modules is now done via getVal/setVal/delVal, ie protocol v27 and above found on ZED-F9P -uint8_t SFE_UBLOX_GPS::setVal32(uint32_t key, uint32_t value, uint8_t layer, uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_VALSET; - packetCfg.len = 4 + 4 + 4; //4 byte header, 4 byte key ID, 4 bytes of value - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint16_t x = 0; x < packetCfg.len; x++) - packetCfg.payload[x] = 0; - - payloadCfg[0] = 0; //Message Version - set to 0 - payloadCfg[1] = layer; //By default we ask for the BBR layer - - //Load key into outgoing payload - payloadCfg[4] = key >> 8 * 0; //Key LSB - payloadCfg[5] = key >> 8 * 1; - payloadCfg[6] = key >> 8 * 2; - payloadCfg[7] = key >> 8 * 3; - - //Load user's value - payloadCfg[8] = value >> 8 * 0; //Value LSB - payloadCfg[9] = value >> 8 * 1; - payloadCfg[10] = value >> 8 * 2; - payloadCfg[11] = value >> 8 * 3; - - //Send VALSET command with this key and value - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Start defining a new UBX-CFG-VALSET ubxPacket -//This function takes a full 32-bit key and 32-bit value -//Default layer is BBR -//Configuration of modern u-blox modules is now done via getVal/setVal/delVal, ie protocol v27 and above found on ZED-F9P -uint8_t SFE_UBLOX_GPS::newCfgValset32(uint32_t key, uint32_t value, uint8_t layer) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_VALSET; - packetCfg.len = 4 + 4 + 4; //4 byte header, 4 byte key ID, 4 bytes of value - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint16_t x = 0; x < MAX_PAYLOAD_SIZE; x++) - packetCfg.payload[x] = 0; - - payloadCfg[0] = 0; //Message Version - set to 0 - payloadCfg[1] = layer; //By default we ask for the BBR layer - - //Load key into outgoing payload - payloadCfg[4] = key >> 8 * 0; //Key LSB - payloadCfg[5] = key >> 8 * 1; - payloadCfg[6] = key >> 8 * 2; - payloadCfg[7] = key >> 8 * 3; - - //Load user's value - payloadCfg[8] = value >> 8 * 0; //Value LSB - payloadCfg[9] = value >> 8 * 1; - payloadCfg[10] = value >> 8 * 2; - payloadCfg[11] = value >> 8 * 3; - - //All done - return (true); -} - -//Start defining a new UBX-CFG-VALSET ubxPacket -//This function takes a full 32-bit key and 16-bit value -//Default layer is BBR -//Configuration of modern u-blox modules is now done via getVal/setVal/delVal, ie protocol v27 and above found on ZED-F9P -uint8_t SFE_UBLOX_GPS::newCfgValset16(uint32_t key, uint16_t value, uint8_t layer) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_VALSET; - packetCfg.len = 4 + 4 + 2; //4 byte header, 4 byte key ID, 2 bytes of value - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint16_t x = 0; x < MAX_PAYLOAD_SIZE; x++) - packetCfg.payload[x] = 0; - - payloadCfg[0] = 0; //Message Version - set to 0 - payloadCfg[1] = layer; //By default we ask for the BBR layer - - //Load key into outgoing payload - payloadCfg[4] = key >> 8 * 0; //Key LSB - payloadCfg[5] = key >> 8 * 1; - payloadCfg[6] = key >> 8 * 2; - payloadCfg[7] = key >> 8 * 3; - - //Load user's value - payloadCfg[8] = value >> 8 * 0; //Value LSB - payloadCfg[9] = value >> 8 * 1; - - //All done - return (true); -} - -//Start defining a new UBX-CFG-VALSET ubxPacket -//This function takes a full 32-bit key and 8-bit value -//Default layer is BBR -//Configuration of modern u-blox modules is now done via getVal/setVal/delVal, ie protocol v27 and above found on ZED-F9P -uint8_t SFE_UBLOX_GPS::newCfgValset8(uint32_t key, uint8_t value, uint8_t layer) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_VALSET; - packetCfg.len = 4 + 4 + 1; //4 byte header, 4 byte key ID, 1 byte value - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint16_t x = 0; x < MAX_PAYLOAD_SIZE; x++) - packetCfg.payload[x] = 0; - - payloadCfg[0] = 0; //Message Version - set to 0 - payloadCfg[1] = layer; //By default we ask for the BBR layer - - //Load key into outgoing payload - payloadCfg[4] = key >> 8 * 0; //Key LSB - payloadCfg[5] = key >> 8 * 1; - payloadCfg[6] = key >> 8 * 2; - payloadCfg[7] = key >> 8 * 3; - - //Load user's value - payloadCfg[8] = value; //Value - - //All done - return (true); -} - -//Add another keyID and value to an existing UBX-CFG-VALSET ubxPacket -//This function takes a full 32-bit key and 32-bit value -uint8_t SFE_UBLOX_GPS::addCfgValset32(uint32_t key, uint32_t value) -{ - //Load key into outgoing payload - payloadCfg[packetCfg.len + 0] = key >> 8 * 0; //Key LSB - payloadCfg[packetCfg.len + 1] = key >> 8 * 1; - payloadCfg[packetCfg.len + 2] = key >> 8 * 2; - payloadCfg[packetCfg.len + 3] = key >> 8 * 3; - - //Load user's value - payloadCfg[packetCfg.len + 4] = value >> 8 * 0; //Value LSB - payloadCfg[packetCfg.len + 5] = value >> 8 * 1; - payloadCfg[packetCfg.len + 6] = value >> 8 * 2; - payloadCfg[packetCfg.len + 7] = value >> 8 * 3; - - //Update packet length: 4 byte key ID, 4 bytes of value - packetCfg.len = packetCfg.len + 4 + 4; - - //All done - return (true); -} - -//Add another keyID and value to an existing UBX-CFG-VALSET ubxPacket -//This function takes a full 32-bit key and 16-bit value -uint8_t SFE_UBLOX_GPS::addCfgValset16(uint32_t key, uint16_t value) -{ - //Load key into outgoing payload - payloadCfg[packetCfg.len + 0] = key >> 8 * 0; //Key LSB - payloadCfg[packetCfg.len + 1] = key >> 8 * 1; - payloadCfg[packetCfg.len + 2] = key >> 8 * 2; - payloadCfg[packetCfg.len + 3] = key >> 8 * 3; - - //Load user's value - payloadCfg[packetCfg.len + 4] = value >> 8 * 0; //Value LSB - payloadCfg[packetCfg.len + 5] = value >> 8 * 1; - - //Update packet length: 4 byte key ID, 2 bytes of value - packetCfg.len = packetCfg.len + 4 + 2; - - //All done - return (true); -} - -//Add another keyID and value to an existing UBX-CFG-VALSET ubxPacket -//This function takes a full 32-bit key and 8-bit value -uint8_t SFE_UBLOX_GPS::addCfgValset8(uint32_t key, uint8_t value) -{ - //Load key into outgoing payload - payloadCfg[packetCfg.len + 0] = key >> 8 * 0; //Key LSB - payloadCfg[packetCfg.len + 1] = key >> 8 * 1; - payloadCfg[packetCfg.len + 2] = key >> 8 * 2; - payloadCfg[packetCfg.len + 3] = key >> 8 * 3; - - //Load user's value - payloadCfg[packetCfg.len + 4] = value; //Value - - //Update packet length: 4 byte key ID, 1 byte value - packetCfg.len = packetCfg.len + 4 + 1; - - //All done - return (true); -} - -//Add a final keyID and value to an existing UBX-CFG-VALSET ubxPacket and send it -//This function takes a full 32-bit key and 32-bit value -uint8_t SFE_UBLOX_GPS::sendCfgValset32(uint32_t key, uint32_t value, uint16_t maxWait) -{ - //Load keyID and value into outgoing payload - addCfgValset32(key, value); - - //Send VALSET command with this key and value - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Add a final keyID and value to an existing UBX-CFG-VALSET ubxPacket and send it -//This function takes a full 32-bit key and 16-bit value -uint8_t SFE_UBLOX_GPS::sendCfgValset16(uint32_t key, uint16_t value, uint16_t maxWait) -{ - //Load keyID and value into outgoing payload - addCfgValset16(key, value); - - //Send VALSET command with this key and value - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Add a final keyID and value to an existing UBX-CFG-VALSET ubxPacket and send it -//This function takes a full 32-bit key and 8-bit value -uint8_t SFE_UBLOX_GPS::sendCfgValset8(uint32_t key, uint8_t value, uint16_t maxWait) -{ - //Load keyID and value into outgoing payload - addCfgValset8(key, value); - - //Send VALSET command with this key and value - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Get the current TimeMode3 settings - these contain survey in statuses -boolean SFE_UBLOX_GPS::getSurveyMode(uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_TMODE3; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_RECEIVED); // We are expecting data and an ACK -} - -//Control Survey-In for NEO-M8P -boolean SFE_UBLOX_GPS::setSurveyMode(uint8_t mode, uint16_t observationTime, float requiredAccuracy, uint16_t maxWait) -{ - if (getSurveyMode(maxWait) == false) //Ask module for the current TimeMode3 settings. Loads into payloadCfg. - return (false); - - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_TMODE3; - packetCfg.len = 40; - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint8_t x = 0; x < packetCfg.len; x++) - packetCfg.payload[x] = 0; - - //payloadCfg should be loaded with poll response. Now modify only the bits we care about - payloadCfg[2] = mode; //Set mode. Survey-In and Disabled are most common. Use ECEF (not LAT/LON/ALT). - - //svinMinDur is U4 (uint32_t) but we'll only use a uint16_t (waiting more than 65535 seconds seems excessive!) - payloadCfg[24] = observationTime & 0xFF; //svinMinDur in seconds - payloadCfg[25] = observationTime >> 8; //svinMinDur in seconds - payloadCfg[26] = 0; //Truncate to 16 bits - payloadCfg[27] = 0; //Truncate to 16 bits - - //svinAccLimit is U4 (uint32_t) in 0.1mm. - uint32_t svinAccLimit = (uint32_t)(requiredAccuracy * 10000.0); //Convert m to 0.1mm - payloadCfg[28] = svinAccLimit & 0xFF; //svinAccLimit in 0.1mm increments - payloadCfg[29] = svinAccLimit >> 8; - payloadCfg[30] = svinAccLimit >> 16; - payloadCfg[31] = svinAccLimit >> 24; - - return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Begin Survey-In for NEO-M8P -boolean SFE_UBLOX_GPS::enableSurveyMode(uint16_t observationTime, float requiredAccuracy, uint16_t maxWait) -{ - return (setSurveyMode(SVIN_MODE_ENABLE, observationTime, requiredAccuracy, maxWait)); -} - -//Stop Survey-In for NEO-M8P -boolean SFE_UBLOX_GPS::disableSurveyMode(uint16_t maxWait) -{ - return (setSurveyMode(SVIN_MODE_DISABLE, 0, 0, maxWait)); -} - -//Reads survey in status and sets the global variables -//for status, position valid, observation time, and mean 3D StdDev -//Returns true if commands was successful -boolean SFE_UBLOX_GPS::getSurveyStatus(uint16_t maxWait) -{ - //Reset variables - svin.active = false; - svin.valid = false; - svin.observationTime = 0; - svin.meanAccuracy = 0; - - packetCfg.cls = UBX_CLASS_NAV; - packetCfg.id = UBX_NAV_SVIN; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - if ((sendCommand(&packetCfg, maxWait)) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - return (false); //If command send fails then bail - - //We got a response, now parse the bits into the svin structure - - //dur (Passed survey-in observation time) is U4 (uint32_t) seconds. We truncate to 16 bits - //(waiting more than 65535 seconds (18.2 hours) seems excessive!) - uint32_t tmpObsTime = extractLong(8); - if (tmpObsTime <= 0xFFFF) - { - svin.observationTime = (uint16_t)tmpObsTime; - } - else - { - svin.observationTime = 0xFFFF; - } - - // meanAcc is U4 (uint32_t) in 0.1mm. We convert this to float. - uint32_t tempFloat = extractLong(28); - svin.meanAccuracy = ((float)tempFloat) / 10000.0; //Convert 0.1mm to m - - svin.valid = payloadCfg[36]; //1 if survey-in position is valid, 0 otherwise - svin.active = payloadCfg[37]; //1 if survey-in in progress, 0 otherwise - - return (true); -} - -//Loads the payloadCfg array with the current protocol bits located the UBX-CFG-PRT register for a given port -boolean SFE_UBLOX_GPS::getPortSettings(uint8_t portID, uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_PRT; - packetCfg.len = 1; - packetCfg.startingSpot = 0; - - payloadCfg[0] = portID; - - return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_RECEIVED); // We are expecting data and an ACK -} - -//Configure a given port to output UBX, NMEA, RTCM3 or a combination thereof -//Port 0=I2c, 1=UART1, 2=UART2, 3=USB, 4=SPI -//Bit:0 = UBX, :1=NMEA, :5=RTCM3 -boolean SFE_UBLOX_GPS::setPortOutput(uint8_t portID, uint8_t outStreamSettings, uint16_t maxWait) -{ - //Get the current config values for this port ID - if (getPortSettings(portID, maxWait) == false) - return (false); //Something went wrong. Bail. - - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_PRT; - packetCfg.len = 20; - packetCfg.startingSpot = 0; - - //payloadCfg is now loaded with current bytes. Change only the ones we need to - payloadCfg[14] = outStreamSettings; //OutProtocolMask LSB - Set outStream bits - - return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Configure a given port to input UBX, NMEA, RTCM3 or a combination thereof -//Port 0=I2c, 1=UART1, 2=UART2, 3=USB, 4=SPI -//Bit:0 = UBX, :1=NMEA, :5=RTCM3 -boolean SFE_UBLOX_GPS::setPortInput(uint8_t portID, uint8_t inStreamSettings, uint16_t maxWait) -{ - //Get the current config values for this port ID - //This will load the payloadCfg array with current port settings - if (getPortSettings(portID, maxWait) == false) - return (false); //Something went wrong. Bail. - - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_PRT; - packetCfg.len = 20; - packetCfg.startingSpot = 0; - - //payloadCfg is now loaded with current bytes. Change only the ones we need to - payloadCfg[12] = inStreamSettings; //InProtocolMask LSB - Set inStream bits - - return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Configure a port to output UBX, NMEA, RTCM3 or a combination thereof -boolean SFE_UBLOX_GPS::setI2COutput(uint8_t comSettings, uint16_t maxWait) -{ - return (setPortOutput(COM_PORT_I2C, comSettings, maxWait)); -} -boolean SFE_UBLOX_GPS::setUART1Output(uint8_t comSettings, uint16_t maxWait) -{ - return (setPortOutput(COM_PORT_UART1, comSettings, maxWait)); -} -boolean SFE_UBLOX_GPS::setUART2Output(uint8_t comSettings, uint16_t maxWait) -{ - return (setPortOutput(COM_PORT_UART2, comSettings, maxWait)); -} -boolean SFE_UBLOX_GPS::setUSBOutput(uint8_t comSettings, uint16_t maxWait) -{ - return (setPortOutput(COM_PORT_USB, comSettings, maxWait)); -} -boolean SFE_UBLOX_GPS::setSPIOutput(uint8_t comSettings, uint16_t maxWait) -{ - return (setPortOutput(COM_PORT_SPI, comSettings, maxWait)); -} - -//Set the rate at which the module will give us an updated navigation solution -//Expects a number that is the updates per second. For example 1 = 1Hz, 2 = 2Hz, etc. -//Max is 40Hz(?!) -boolean SFE_UBLOX_GPS::setNavigationFrequency(uint8_t navFreq, uint16_t maxWait) -{ - //if(updateRate > 40) updateRate = 40; //Not needed: module will correct out of bounds values - - //Adjust the I2C polling timeout based on update rate - i2cPollingWait = 1000 / (navFreq * 4); //This is the number of ms to wait between checks for new I2C data - - //Query the module for the latest lat/long - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_RATE; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - //This will load the payloadCfg array with current settings of the given register - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - return (false); //If command send fails then bail - - uint16_t measurementRate = 1000 / navFreq; - - //payloadCfg is now loaded with current bytes. Change only the ones we need to - payloadCfg[0] = measurementRate & 0xFF; //measRate LSB - payloadCfg[1] = measurementRate >> 8; //measRate MSB - - return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Get the rate at which the module is outputting nav solutions -uint8_t SFE_UBLOX_GPS::getNavigationFrequency(uint16_t maxWait) -{ - //Query the module for the latest lat/long - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_RATE; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - //This will load the payloadCfg array with current settings of the given register - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - return (false); //If command send fails then bail - - uint16_t measurementRate = 0; - - //payloadCfg is now loaded with current bytes. Get what we need - measurementRate = extractInt(0); //Pull from payloadCfg at measRate LSB - - measurementRate = 1000 / measurementRate; //This may return an int when it's a float, but I'd rather not return 4 bytes - return (measurementRate); -} - -//In case no config access to the GPS is possible and PVT is send cyclically already -//set config to suitable parameters -boolean SFE_UBLOX_GPS::assumeAutoPVT(boolean enabled, boolean implicitUpdate) -{ - boolean changes = autoPVT != enabled || autoPVTImplicitUpdate != implicitUpdate; - if (changes) - { - autoPVT = enabled; - autoPVTImplicitUpdate = implicitUpdate; - } - return changes; -} - -//Enable or disable automatic navigation message generation by the GPS. This changes the way getPVT -//works. -boolean SFE_UBLOX_GPS::setAutoPVT(boolean enable, uint16_t maxWait) -{ - return setAutoPVT(enable, true, maxWait); -} - -//Enable or disable automatic navigation message generation by the GPS. This changes the way getPVT -//works. -boolean SFE_UBLOX_GPS::setAutoPVT(boolean enable, boolean implicitUpdate, uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_MSG; - packetCfg.len = 3; - packetCfg.startingSpot = 0; - payloadCfg[0] = UBX_CLASS_NAV; - payloadCfg[1] = UBX_NAV_PVT; - payloadCfg[2] = enable ? 1 : 0; // rate relative to navigation freq. - - boolean ok = ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK - if (ok) - { - autoPVT = enable; - autoPVTImplicitUpdate = implicitUpdate; - } - moduleQueried.all = false; - return ok; -} - -//Configure a given message type for a given port (UART1, I2C, SPI, etc) -boolean SFE_UBLOX_GPS::configureMessage(uint8_t msgClass, uint8_t msgID, uint8_t portID, uint8_t sendRate, uint16_t maxWait) -{ - //Poll for the current settings for a given message - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_MSG; - packetCfg.len = 2; - packetCfg.startingSpot = 0; - - payloadCfg[0] = msgClass; - payloadCfg[1] = msgID; - - //This will load the payloadCfg array with current settings of the given register - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - return (false); //If command send fails then bail - - //Now send it back with new mods - packetCfg.len = 8; - - //payloadCfg is now loaded with current bytes. Change only the ones we need to - payloadCfg[2 + portID] = sendRate; //Send rate is relative to the event a message is registered on. For example, if the rate of a navigation message is set to 2, the message is sent every 2nd navigation solution. - - return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Enable a given message type, default of 1 per update rate (usually 1 per second) -boolean SFE_UBLOX_GPS::enableMessage(uint8_t msgClass, uint8_t msgID, uint8_t portID, uint8_t rate, uint16_t maxWait) -{ - return (configureMessage(msgClass, msgID, portID, rate, maxWait)); -} -//Disable a given message type on a given port -boolean SFE_UBLOX_GPS::disableMessage(uint8_t msgClass, uint8_t msgID, uint8_t portID, uint16_t maxWait) -{ - return (configureMessage(msgClass, msgID, portID, 0, maxWait)); -} - -boolean SFE_UBLOX_GPS::enableNMEAMessage(uint8_t msgID, uint8_t portID, uint8_t rate, uint16_t maxWait) -{ - return (configureMessage(UBX_CLASS_NMEA, msgID, portID, rate, maxWait)); -} -boolean SFE_UBLOX_GPS::disableNMEAMessage(uint8_t msgID, uint8_t portID, uint16_t maxWait) -{ - return (enableNMEAMessage(msgID, portID, 0, maxWait)); -} - -//Given a message number turns on a message ID for output over a given portID (UART, I2C, SPI, USB, etc) -//To disable a message, set secondsBetween messages to 0 -//Note: This function will return false if the message is already enabled -//For base station RTK output we need to enable various sentences - -//NEO-M8P has four: -//1005 = 0xF5 0x05 - Stationary RTK reference ARP -//1077 = 0xF5 0x4D - GPS MSM7 -//1087 = 0xF5 0x57 - GLONASS MSM7 -//1230 = 0xF5 0xE6 - GLONASS code-phase biases, set to once every 10 seconds - -//ZED-F9P has six: -//1005, 1074, 1084, 1094, 1124, 1230 - -//Much of this configuration is not documented and instead discerned from u-center binary console -boolean SFE_UBLOX_GPS::enableRTCMmessage(uint8_t messageNumber, uint8_t portID, uint8_t sendRate, uint16_t maxWait) -{ - return (configureMessage(UBX_RTCM_MSB, messageNumber, portID, sendRate, maxWait)); -} - -//Disable a given message on a given port by setting secondsBetweenMessages to zero -boolean SFE_UBLOX_GPS::disableRTCMmessage(uint8_t messageNumber, uint8_t portID, uint16_t maxWait) -{ - return (enableRTCMmessage(messageNumber, portID, 0, maxWait)); -} - -//Add a new geofence using UBX-CFG-GEOFENCE -boolean SFE_UBLOX_GPS::addGeofence(int32_t latitude, int32_t longitude, uint32_t radius, byte confidence, byte pinPolarity, byte pin, uint16_t maxWait) -{ - if (currentGeofenceParams.numFences >= 4) - return (false); // Quit if we already have four geofences defined - - // Store the new geofence parameters - currentGeofenceParams.lats[currentGeofenceParams.numFences] = latitude; - currentGeofenceParams.longs[currentGeofenceParams.numFences] = longitude; - currentGeofenceParams.rads[currentGeofenceParams.numFences] = radius; - currentGeofenceParams.numFences = currentGeofenceParams.numFences + 1; // Increment the number of fences - - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_GEOFENCE; - packetCfg.len = (currentGeofenceParams.numFences * 12) + 8; - packetCfg.startingSpot = 0; - - payloadCfg[0] = 0; // Message version = 0x00 - payloadCfg[1] = currentGeofenceParams.numFences; // numFences - payloadCfg[2] = confidence; // confLvl = Confidence level 0-4 (none, 68%, 95%, 99.7%, 99.99%) - payloadCfg[3] = 0; // reserved1 - if (pin > 0) - { - payloadCfg[4] = 1; // enable PIO combined fence state - } - else - { - payloadCfg[4] = 0; // disable PIO combined fence state - } - payloadCfg[5] = pinPolarity; // PIO pin polarity (0 = low means inside, 1 = low means outside (or unknown)) - payloadCfg[6] = pin; // PIO pin - payloadCfg[7] = 0; //reserved2 - payloadCfg[8] = currentGeofenceParams.lats[0] & 0xFF; - payloadCfg[9] = currentGeofenceParams.lats[0] >> 8; - payloadCfg[10] = currentGeofenceParams.lats[0] >> 16; - payloadCfg[11] = currentGeofenceParams.lats[0] >> 24; - payloadCfg[12] = currentGeofenceParams.longs[0] & 0xFF; - payloadCfg[13] = currentGeofenceParams.longs[0] >> 8; - payloadCfg[14] = currentGeofenceParams.longs[0] >> 16; - payloadCfg[15] = currentGeofenceParams.longs[0] >> 24; - payloadCfg[16] = currentGeofenceParams.rads[0] & 0xFF; - payloadCfg[17] = currentGeofenceParams.rads[0] >> 8; - payloadCfg[18] = currentGeofenceParams.rads[0] >> 16; - payloadCfg[19] = currentGeofenceParams.rads[0] >> 24; - if (currentGeofenceParams.numFences >= 2) - { - payloadCfg[20] = currentGeofenceParams.lats[1] & 0xFF; - payloadCfg[21] = currentGeofenceParams.lats[1] >> 8; - payloadCfg[22] = currentGeofenceParams.lats[1] >> 16; - payloadCfg[23] = currentGeofenceParams.lats[1] >> 24; - payloadCfg[24] = currentGeofenceParams.longs[1] & 0xFF; - payloadCfg[25] = currentGeofenceParams.longs[1] >> 8; - payloadCfg[26] = currentGeofenceParams.longs[1] >> 16; - payloadCfg[27] = currentGeofenceParams.longs[1] >> 24; - payloadCfg[28] = currentGeofenceParams.rads[1] & 0xFF; - payloadCfg[29] = currentGeofenceParams.rads[1] >> 8; - payloadCfg[30] = currentGeofenceParams.rads[1] >> 16; - payloadCfg[31] = currentGeofenceParams.rads[1] >> 24; - } - if (currentGeofenceParams.numFences >= 3) - { - payloadCfg[32] = currentGeofenceParams.lats[2] & 0xFF; - payloadCfg[33] = currentGeofenceParams.lats[2] >> 8; - payloadCfg[34] = currentGeofenceParams.lats[2] >> 16; - payloadCfg[35] = currentGeofenceParams.lats[2] >> 24; - payloadCfg[36] = currentGeofenceParams.longs[2] & 0xFF; - payloadCfg[37] = currentGeofenceParams.longs[2] >> 8; - payloadCfg[38] = currentGeofenceParams.longs[2] >> 16; - payloadCfg[39] = currentGeofenceParams.longs[2] >> 24; - payloadCfg[40] = currentGeofenceParams.rads[2] & 0xFF; - payloadCfg[41] = currentGeofenceParams.rads[2] >> 8; - payloadCfg[42] = currentGeofenceParams.rads[2] >> 16; - payloadCfg[43] = currentGeofenceParams.rads[2] >> 24; - } - if (currentGeofenceParams.numFences >= 4) - { - payloadCfg[44] = currentGeofenceParams.lats[3] & 0xFF; - payloadCfg[45] = currentGeofenceParams.lats[3] >> 8; - payloadCfg[46] = currentGeofenceParams.lats[3] >> 16; - payloadCfg[47] = currentGeofenceParams.lats[3] >> 24; - payloadCfg[48] = currentGeofenceParams.longs[3] & 0xFF; - payloadCfg[49] = currentGeofenceParams.longs[3] >> 8; - payloadCfg[50] = currentGeofenceParams.longs[3] >> 16; - payloadCfg[51] = currentGeofenceParams.longs[3] >> 24; - payloadCfg[52] = currentGeofenceParams.rads[3] & 0xFF; - payloadCfg[53] = currentGeofenceParams.rads[3] >> 8; - payloadCfg[54] = currentGeofenceParams.rads[3] >> 16; - payloadCfg[55] = currentGeofenceParams.rads[3] >> 24; - } - return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Clear all geofences using UBX-CFG-GEOFENCE -boolean SFE_UBLOX_GPS::clearGeofences(uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_GEOFENCE; - packetCfg.len = 8; - packetCfg.startingSpot = 0; - - payloadCfg[0] = 0; // Message version = 0x00 - payloadCfg[1] = 0; // numFences - payloadCfg[2] = 0; // confLvl - payloadCfg[3] = 0; // reserved1 - payloadCfg[4] = 0; // disable PIO combined fence state - payloadCfg[5] = 0; // PIO pin polarity (0 = low means inside, 1 = low means outside (or unknown)) - payloadCfg[6] = 0; // PIO pin - payloadCfg[7] = 0; //reserved2 - - currentGeofenceParams.numFences = 0; // Zero the number of geofences currently in use - - return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Clear the antenna control settings using UBX-CFG-ANT -//This function is hopefully redundant but may be needed to release -//any PIO pins pre-allocated for antenna functions -boolean SFE_UBLOX_GPS::clearAntPIO(uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_ANT; - packetCfg.len = 4; - packetCfg.startingSpot = 0; - - payloadCfg[0] = 0x10; // Antenna flag mask: set the recovery bit - payloadCfg[1] = 0; - payloadCfg[2] = 0xFF; // Antenna pin configuration: set pinSwitch and pinSCD to 31 - payloadCfg[3] = 0xFF; // Antenna pin configuration: set pinOCD to 31, set reconfig bit - - return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Returns the combined geofence state using UBX-NAV-GEOFENCE -boolean SFE_UBLOX_GPS::getGeofenceState(geofenceState ¤tGeofenceState, uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_NAV; - packetCfg.id = UBX_NAV_GEOFENCE; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - //Ask module for the geofence status. Loads into payloadCfg. - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - return (false); - - currentGeofenceState.status = payloadCfg[5]; // Extract the status - currentGeofenceState.numFences = payloadCfg[6]; // Extract the number of geofences - currentGeofenceState.combState = payloadCfg[7]; // Extract the combined state of all geofences - if (currentGeofenceState.numFences > 0) - currentGeofenceState.states[0] = payloadCfg[8]; // Extract geofence 1 state - if (currentGeofenceState.numFences > 1) - currentGeofenceState.states[1] = payloadCfg[10]; // Extract geofence 2 state - if (currentGeofenceState.numFences > 2) - currentGeofenceState.states[2] = payloadCfg[12]; // Extract geofence 3 state - if (currentGeofenceState.numFences > 3) - currentGeofenceState.states[3] = payloadCfg[14]; // Extract geofence 4 state - - return (true); -} - -//Power Save Mode -//Enables/Disables Low Power Mode using UBX-CFG-RXM -boolean SFE_UBLOX_GPS::powerSaveMode(bool power_save, uint16_t maxWait) -{ - // Let's begin by checking the Protocol Version as UBX_CFG_RXM is not supported on the ZED (protocol >= 27) - uint8_t protVer = getProtocolVersionHigh(maxWait); - /* - if (_printDebug == true) - { - _debugSerial->print(F("Protocol version is ")); - _debugSerial->println(protVer); - } - */ - if (protVer >= 27) - { - if (_printDebug == true) - { - _debugSerial->println(F("powerSaveMode (UBX-CFG-RXM) is not supported by this protocol version")); - } - return (false); - } - - // Now let's change the power setting using UBX-CFG-RXM - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_RXM; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - //Ask module for the current power management settings. Loads into payloadCfg. - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - return (false); - - if (power_save) - { - payloadCfg[1] = 1; // Power Save Mode - } - else - { - payloadCfg[1] = 0; // Continuous Mode - } - - packetCfg.len = 2; - packetCfg.startingSpot = 0; - - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -// Get Power Save Mode -// Returns the current Low Power Mode using UBX-CFG-RXM -// Returns 255 if the sendCommand fails -uint8_t SFE_UBLOX_GPS::getPowerSaveMode(uint16_t maxWait) -{ - // Let's begin by checking the Protocol Version as UBX_CFG_RXM is not supported on the ZED (protocol >= 27) - uint8_t protVer = getProtocolVersionHigh(maxWait); - /* - if (_printDebug == true) - { - _debugSerial->print(F("Protocol version is ")); - _debugSerial->println(protVer); - } - */ - if (protVer >= 27) - { - if (_printDebug == true) - { - _debugSerial->println(F("powerSaveMode (UBX-CFG-RXM) is not supported by this protocol version")); - } - return (255); - } - - // Now let's read the power setting using UBX-CFG-RXM - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_RXM; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - //Ask module for the current power management settings. Loads into payloadCfg. - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - return (255); - - return (payloadCfg[1]); // Return the low power mode -} - -//Change the dynamic platform model using UBX-CFG-NAV5 -//Possible values are: -//PORTABLE,STATIONARY,PEDESTRIAN,AUTOMOTIVE,SEA, -//AIRBORNE1g,AIRBORNE2g,AIRBORNE4g,WRIST,BIKE -//WRIST is not supported in protocol versions less than 18 -//BIKE is supported in protocol versions 19.2 -boolean SFE_UBLOX_GPS::setDynamicModel(dynModel newDynamicModel, uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_NAV5; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - //Ask module for the current navigation model settings. Loads into payloadCfg. - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - return (false); - - payloadCfg[0] = 0x01; // mask: set only the dyn bit (0) - payloadCfg[1] = 0x00; // mask - payloadCfg[2] = newDynamicModel; // dynModel - - packetCfg.len = 36; - packetCfg.startingSpot = 0; - - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Get the dynamic platform model using UBX-CFG-NAV5 -//Returns 255 if the sendCommand fails -uint8_t SFE_UBLOX_GPS::getDynamicModel(uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_NAV5; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - //Ask module for the current navigation model settings. Loads into payloadCfg. - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - return (255); - - return (payloadCfg[2]); // Return the dynamic model -} - -//Given a spot in the payload array, extract four bytes and build a long -uint32_t SFE_UBLOX_GPS::extractLong(uint8_t spotToStart) -{ - uint32_t val = 0; - val |= (uint32_t)payloadCfg[spotToStart + 0] << 8 * 0; - val |= (uint32_t)payloadCfg[spotToStart + 1] << 8 * 1; - val |= (uint32_t)payloadCfg[spotToStart + 2] << 8 * 2; - val |= (uint32_t)payloadCfg[spotToStart + 3] << 8 * 3; - return (val); -} - -//Given a spot in the payload array, extract two bytes and build an int -uint16_t SFE_UBLOX_GPS::extractInt(uint8_t spotToStart) -{ - uint16_t val = 0; - val |= (uint16_t)payloadCfg[spotToStart + 0] << 8 * 0; - val |= (uint16_t)payloadCfg[spotToStart + 1] << 8 * 1; - return (val); -} - -//Given a spot, extract a byte from the payload -uint8_t SFE_UBLOX_GPS::extractByte(uint8_t spotToStart) -{ - return (payloadCfg[spotToStart]); -} - -//Given a spot, extract a signed 8-bit value from the payload -int8_t SFE_UBLOX_GPS::extractSignedChar(uint8_t spotToStart) -{ - return ((int8_t)payloadCfg[spotToStart]); -} - -//Get the current year -uint16_t SFE_UBLOX_GPS::getYear(uint16_t maxWait) -{ - if (moduleQueried.gpsYear == false) - getTimeData(maxWait); - moduleQueried.gpsYear = false; //Since we are about to give this to user, mark this data as stale - return (gpsYear); -} - -//Get the current month -uint8_t SFE_UBLOX_GPS::getMonth(uint16_t maxWait) -{ - if (moduleQueried.gpsMonth == false) - getTimeData(maxWait); - moduleQueried.gpsMonth = false; //Since we are about to give this to user, mark this data as stale - return (gpsMonth); -} - -//Get the current day -uint8_t SFE_UBLOX_GPS::getDay(uint16_t maxWait) -{ - if (moduleQueried.gpsDay == false) - getTimeData(maxWait); - moduleQueried.gpsDay = false; //Since we are about to give this to user, mark this data as stale - return (gpsDay); -} - -//Get the current hour -uint8_t SFE_UBLOX_GPS::getHour(uint16_t maxWait) -{ - if (moduleQueried.gpsHour == false) - getTimeData(maxWait); - moduleQueried.gpsHour = false; //Since we are about to give this to user, mark this data as stale - return (gpsHour); -} - -//Get the current minute -uint8_t SFE_UBLOX_GPS::getMinute(uint16_t maxWait) -{ - if (moduleQueried.gpsMinute == false) - getTimeData(maxWait); - moduleQueried.gpsMinute = false; //Since we are about to give this to user, mark this data as stale - return (gpsMinute); -} - -//Get the current second -uint8_t SFE_UBLOX_GPS::getSecond(uint16_t maxWait) -{ - if (moduleQueried.gpsSecond == false) - getTimeData(maxWait); - moduleQueried.gpsSecond = false; //Since we are about to give this to user, mark this data as stale - return (gpsSecond); -} - -//Get the current millisecond -uint16_t SFE_UBLOX_GPS::getMillisecond(uint16_t maxWait) -{ - if (moduleQueried.gpsiTOW == false) - getTimeData(maxWait); - moduleQueried.gpsiTOW = false; //Since we are about to give this to user, mark this data as stale - return (gpsMillisecond); -} - -//Get the current nanoseconds - includes milliseconds -int32_t SFE_UBLOX_GPS::getNanosecond(uint16_t maxWait) -{ - if (moduleQueried.gpsNanosecond == false) - getTimeData(maxWait); - moduleQueried.gpsNanosecond = false; //Since we are about to give this to user, mark this data as stale - return (gpsNanosecond); -} - -//Get the latest Position/Velocity/Time solution and fill all global variables -boolean SFE_UBLOX_GPS::getPVT(uint16_t maxWait) -{ - if (autoPVT && autoPVTImplicitUpdate) - { - //The GPS is automatically reporting, we just check whether we got unread data - if (_printDebug == true) - { - _debugSerial->println(F("getPVT: Autoreporting")); - } - checkUbloxInternal(&packetCfg, UBX_CLASS_NAV, UBX_NAV_PVT); - return moduleQueried.all; - } - else if (autoPVT && !autoPVTImplicitUpdate) - { - //Someone else has to call checkUblox for us... - if (_printDebug == true) - { - _debugSerial->println(F("getPVT: Exit immediately")); - } - return (false); - } - else - { - 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 - - //The data is parsed as part of processing the response - sfe_ublox_status_e retVal = sendCommand(&packetCfg, maxWait); - - if (retVal == SFE_UBLOX_STATUS_DATA_RECEIVED) - return (true); - - if (_printDebug == true) - { - _debugSerial->print(F("getPVT retVal: ")); - _debugSerial->println(statusString(retVal)); - } - return (false); - } -} - -// Update time info (using appropriate call for the chip series) -boolean SFE_UBLOX_GPS::getTimeData(uint16_t maxWait) -{ - return getProtocolVersionHigh(maxWait) < 15 ? getTIMEUTC(maxWait) : getPVT(maxWait); -} - -// Update position info (using appropriate call for the chip series) -boolean SFE_UBLOX_GPS::getPositionData(uint16_t maxWait) -{ - return getProtocolVersionHigh(maxWait) < 20 ? getPOSLLH(maxWait) : getPVT(maxWait); -} - -//Get time (for use on chips with protocol version 14 and earlier) -boolean SFE_UBLOX_GPS::getTIMEUTC(uint16_t maxWait) -{ - debugPrintln((char *)F("getTIMEUTC: Polling")); - - //The GPS is not automatically reporting navigation position so we have to poll explicitly - packetCfg.cls = UBX_CLASS_NAV; - packetCfg.id = UBX_NAV_TIMEUTC; - 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 - - //The data is parsed as part of processing the response - sfe_ublox_status_e retVal = sendCommand(&packetCfg, maxWait); - - if (retVal == SFE_UBLOX_STATUS_DATA_RECEIVED) - return (true); - - if (_printDebug == true) - { - _debugSerial->print(F("getTIMEUTC retVal: ")); - _debugSerial->println(statusString(retVal)); - } - return (false); -} - -//Get posllh (fos use on chips with protocol version 19 and earlier) -boolean SFE_UBLOX_GPS::getPOSLLH(uint16_t maxWait) -{ - debugPrintln((char *)F("getPOSLLH: Polling")); - - //The GPS is not automatically reporting navigation position so we have to poll explicitly - packetCfg.cls = UBX_CLASS_NAV; - packetCfg.id = UBX_NAV_POSLLH; - 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 - - //The data is parsed as part of processing the response - sfe_ublox_status_e retVal = sendCommand(&packetCfg, maxWait); - - if (retVal == SFE_UBLOX_STATUS_DATA_RECEIVED) - return (true); - - if (_printDebug == true) - { - _debugSerial->print(F("getPOSLLH retVal: ")); - _debugSerial->println(statusString(retVal)); - } - return (false); -} - -uint32_t SFE_UBLOX_GPS::getTimeOfWeek(uint16_t maxWait /* = 250*/) -{ - if (moduleQueried.gpsiTOW == false) - getTimeData(maxWait); - moduleQueried.gpsiTOW = false; //Since we are about to give this to user, mark this data as stale - return (timeOfWeek); -} - -int32_t SFE_UBLOX_GPS::getHighResLatitude(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.highResLatitude == false) - getHPPOSLLH(maxWait); - highResModuleQueried.highResLatitude = false; //Since we are about to give this to user, mark this data as stale - return (highResLatitude); -} - -int8_t SFE_UBLOX_GPS::getHighResLatitudeHp(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.highResLatitudeHp == false) - getHPPOSLLH(maxWait); - highResModuleQueried.highResLatitudeHp = false; //Since we are about to give this to user, mark this data as stale - return (highResLatitudeHp); -} - -int32_t SFE_UBLOX_GPS::getHighResLongitude(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.highResLongitude == false) - getHPPOSLLH(maxWait); - highResModuleQueried.highResLongitude = false; //Since we are about to give this to user, mark this data as stale - return (highResLongitude); -} - -int8_t SFE_UBLOX_GPS::getHighResLongitudeHp(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.highResLongitudeHp == false) - getHPPOSLLH(maxWait); - highResModuleQueried.highResLongitudeHp = false; //Since we are about to give this to user, mark this data as stale - return (highResLongitudeHp); -} - -int32_t SFE_UBLOX_GPS::getElipsoid(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.elipsoid == false) - getHPPOSLLH(maxWait); - highResModuleQueried.elipsoid = false; //Since we are about to give this to user, mark this data as stale - return (elipsoid); -} - -int8_t SFE_UBLOX_GPS::getElipsoidHp(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.elipsoidHp == false) - getHPPOSLLH(maxWait); - highResModuleQueried.elipsoidHp = false; //Since we are about to give this to user, mark this data as stale - return (elipsoidHp); -} - -int32_t SFE_UBLOX_GPS::getMeanSeaLevel(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.meanSeaLevel == false) - getHPPOSLLH(maxWait); - highResModuleQueried.meanSeaLevel = false; //Since we are about to give this to user, mark this data as stale - return (meanSeaLevel); -} - -int8_t SFE_UBLOX_GPS::getMeanSeaLevelHp(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.meanSeaLevelHp == false) - getHPPOSLLH(maxWait); - highResModuleQueried.meanSeaLevelHp = false; //Since we are about to give this to user, mark this data as stale - return (meanSeaLevelHp); -} - -// getGeoidSeparation is currently redundant. The geoid separation seems to only be provided in NMEA GGA and GNS messages. -int32_t SFE_UBLOX_GPS::getGeoidSeparation(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.geoidSeparation == false) - getHPPOSLLH(maxWait); - highResModuleQueried.geoidSeparation = false; //Since we are about to give this to user, mark this data as stale - return (geoidSeparation); -} - -uint32_t SFE_UBLOX_GPS::getHorizontalAccuracy(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.horizontalAccuracy == false) - getHPPOSLLH(maxWait); - highResModuleQueried.horizontalAccuracy = false; //Since we are about to give this to user, mark this data as stale - return (horizontalAccuracy); -} - -uint32_t SFE_UBLOX_GPS::getVerticalAccuracy(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.verticalAccuracy == false) - getHPPOSLLH(maxWait); - highResModuleQueried.verticalAccuracy = false; //Since we are about to give this to user, mark this data as stale - return (verticalAccuracy); -} - -boolean SFE_UBLOX_GPS::getHPPOSLLH(uint16_t maxWait) -{ - //The GPS is not automatically reporting navigation position so we have to poll explicitly - packetCfg.cls = UBX_CLASS_NAV; - packetCfg.id = UBX_NAV_HPPOSLLH; - packetCfg.len = 0; - - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_RECEIVED); // We are only expecting data (no ACK) -} - -//Get the current 3D high precision positional accuracy - a fun thing to watch -//Returns a long representing the 3D accuracy in millimeters -uint32_t SFE_UBLOX_GPS::getPositionAccuracy(uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_NAV; - packetCfg.id = UBX_NAV_HPPOSECEF; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are only expecting data (no ACK) - return (0); //If command send fails then bail - - uint32_t tempAccuracy = extractLong(24); //We got a response, now extract a long beginning at a given position - - if ((tempAccuracy % 10) >= 5) - tempAccuracy += 5; //Round fraction of mm up to next mm if .5 or above - tempAccuracy /= 10; //Convert 0.1mm units to mm - - return (tempAccuracy); -} - -//Get the current latitude in degrees -//Returns a long representing the number of degrees *10^-7 -int32_t SFE_UBLOX_GPS::getLatitude(uint16_t maxWait) -{ - if (moduleQueried.latitude == false) - getPositionData(maxWait); - moduleQueried.latitude = false; //Since we are about to give this to user, mark this data as stale - moduleQueried.all = false; - - return (latitude); -} - -//Get the current longitude in degrees -//Returns a long representing the number of degrees *10^-7 -int32_t SFE_UBLOX_GPS::getLongitude(uint16_t maxWait) -{ - if (moduleQueried.longitude == false) - getPositionData(maxWait); - moduleQueried.longitude = false; //Since we are about to give this to user, mark this data as stale - moduleQueried.all = false; - - return (longitude); -} - -//Get the current altitude in mm according to ellipsoid model -int32_t SFE_UBLOX_GPS::getAltitude(uint16_t maxWait) -{ - if (moduleQueried.altitude == false) - getPositionData(maxWait); - moduleQueried.altitude = false; //Since we are about to give this to user, mark this data as stale - moduleQueried.all = false; - - return (altitude); -} - -//Get the current altitude in mm according to mean sea level -//Ellipsoid model: https://www.esri.com/news/arcuser/0703/geoid1of3.html -//Difference between Ellipsoid Model and Mean Sea Level: https://eos-gnss.com/elevation-for-beginners/ -int32_t SFE_UBLOX_GPS::getAltitudeMSL(uint16_t maxWait) -{ - if (moduleQueried.altitudeMSL == false) - getPositionData(maxWait); - moduleQueried.altitudeMSL = false; //Since we are about to give this to user, mark this data as stale - moduleQueried.all = false; - - return (altitudeMSL); -} - -//Get the number of satellites used in fix -uint8_t SFE_UBLOX_GPS::getSIV(uint16_t maxWait) -{ - if (moduleQueried.SIV == false) - getPVT(maxWait); - moduleQueried.SIV = false; //Since we are about to give this to user, mark this data as stale - moduleQueried.all = false; - - return (SIV); -} - -//Get the current fix type -//0=no fix, 1=dead reckoning, 2=2D, 3=3D, 4=GNSS, 5=Time fix -uint8_t SFE_UBLOX_GPS::getFixType(uint16_t maxWait) -{ - if (moduleQueried.fixType == false) - { - getPVT(maxWait); - } - moduleQueried.fixType = false; //Since we are about to give this to user, mark this data as stale - moduleQueried.all = false; - - return (fixType); -} - -//Get the carrier phase range solution status -//Useful when querying module to see if it has high-precision RTK fix -//0=No solution, 1=Float solution, 2=Fixed solution -uint8_t SFE_UBLOX_GPS::getCarrierSolutionType(uint16_t maxWait) -{ - if (moduleQueried.carrierSolution == false) - getPVT(maxWait); - moduleQueried.carrierSolution = false; //Since we are about to give this to user, mark this data as stale - moduleQueried.all = false; - - return (carrierSolution); -} - -//Get the ground speed in mm/s -int32_t SFE_UBLOX_GPS::getGroundSpeed(uint16_t maxWait) -{ - if (moduleQueried.groundSpeed == false) - getPVT(maxWait); - moduleQueried.groundSpeed = false; //Since we are about to give this to user, mark this data as stale - moduleQueried.all = false; - - return (groundSpeed); -} - -//Get the heading of motion (as opposed to heading of car) in degrees * 10^-5 -int32_t SFE_UBLOX_GPS::getHeading(uint16_t maxWait) -{ - if (moduleQueried.headingOfMotion == false) - getPVT(maxWait); - moduleQueried.headingOfMotion = false; //Since we are about to give this to user, mark this data as stale - moduleQueried.all = false; - - return (headingOfMotion); -} - -//Get the positional dillution of precision * 10^-2 (dimensionless) -uint16_t SFE_UBLOX_GPS::getPDOP(uint16_t maxWait) -{ - if (moduleQueried.pDOP == false) - getPVT(maxWait); - moduleQueried.pDOP = false; //Since we are about to give this to user, mark this data as stale - moduleQueried.all = false; - - return (pDOP); -} - -//Get the current protocol version of the u-blox module we're communicating with -//This is helpful when deciding if we should call the high-precision Lat/Long (HPPOSLLH) or the regular (POSLLH) -uint8_t SFE_UBLOX_GPS::getProtocolVersionHigh(uint16_t maxWait) -{ - if (moduleQueried.versionNumber == false) - getProtocolVersion(maxWait); - return (versionHigh); -} - -//Get the current protocol version of the u-blox module we're communicating with -//This is helpful when deciding if we should call the high-precision Lat/Long (HPPOSLLH) or the regular (POSLLH) -uint8_t SFE_UBLOX_GPS::getProtocolVersionLow(uint16_t maxWait) -{ - if (moduleQueried.versionNumber == false) - getProtocolVersion(maxWait); - return (versionLow); -} - -//Get the current protocol version of the u-blox module we're communicating with -//This is helpful when deciding if we should call the high-precision Lat/Long (HPPOSLLH) or the regular (POSLLH) -boolean SFE_UBLOX_GPS::getProtocolVersion(uint16_t maxWait) -{ - //Send packet with only CLS and ID, length of zero. This will cause the module to respond with the contents of that CLS/ID. - packetCfg.cls = UBX_CLASS_MON; - packetCfg.id = UBX_MON_VER; - - packetCfg.len = 0; - packetCfg.startingSpot = 40; //Start at first "extended software information" string - - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are only expecting data (no ACK) - return (false); //If command send fails then bail - - //Payload should now contain ~220 characters (depends on module type) - - // if (_printDebug == true) - // { - // _debugSerial->print(F("MON VER Payload:")); - // for (int location = 0; location < packetCfg.len; location++) - // { - // if (location % 30 == 0) - // _debugSerial->println(); - // _debugSerial->write(payloadCfg[location]); - // } - // _debugSerial->println(); - // } - - //We will step through the payload looking at each extension field of 30 bytes - for (uint8_t extensionNumber = 0; extensionNumber < 10; extensionNumber++) - { - //Now we need to find "PROTVER=18.00" in the incoming byte stream - if (payloadCfg[(30 * extensionNumber) + 0] == 'P' && payloadCfg[(30 * extensionNumber) + 6] == 'R') - { - versionHigh = (payloadCfg[(30 * extensionNumber) + 8] - '0') * 10 + (payloadCfg[(30 * extensionNumber) + 9] - '0'); //Convert '18' to 18 - versionLow = (payloadCfg[(30 * extensionNumber) + 11] - '0') * 10 + (payloadCfg[(30 * extensionNumber) + 12] - '0'); //Convert '00' to 00 - moduleQueried.versionNumber = true; //Mark this data as new - - if (_printDebug == true) - { - _debugSerial->print(F("Protocol version: ")); - _debugSerial->print(versionHigh); - _debugSerial->print(F(".")); - _debugSerial->println(versionLow); - } - return (true); //Success! - } - } - - return (false); //We failed -} - -//Mark all the PVT data as read/stale. This is handy to get data alignment after CRC failure -void SFE_UBLOX_GPS::flushPVT() -{ - //Mark all datums as stale (read before) - moduleQueried.gpsiTOW = false; - moduleQueried.gpsYear = false; - moduleQueried.gpsMonth = false; - moduleQueried.gpsDay = false; - moduleQueried.gpsHour = false; - moduleQueried.gpsMinute = false; - moduleQueried.gpsSecond = false; - moduleQueried.gpsNanosecond = false; - - moduleQueried.all = false; - moduleQueried.longitude = false; - moduleQueried.latitude = false; - moduleQueried.altitude = false; - moduleQueried.altitudeMSL = false; - moduleQueried.SIV = false; - moduleQueried.fixType = false; - moduleQueried.carrierSolution = false; - moduleQueried.groundSpeed = false; - moduleQueried.headingOfMotion = false; - moduleQueried.pDOP = false; -} - -//Relative Positioning Information in NED frame -//Returns true if commands was successful -boolean SFE_UBLOX_GPS::getRELPOSNED(uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_NAV; - packetCfg.id = UBX_NAV_RELPOSNED; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are only expecting data (no ACK) - return (false); //If command send fails then bail - - //We got a response, now parse the bits - - uint16_t refStationID = extractInt(2); - //_debugSerial->print(F("refStationID: ")); - //_debugSerial->println(refStationID)); - - int32_t tempRelPos; - - tempRelPos = extractLong(8); - relPosInfo.relPosN = tempRelPos / 100.0; //Convert cm to m - - tempRelPos = extractLong(12); - relPosInfo.relPosE = tempRelPos / 100.0; //Convert cm to m - - tempRelPos = extractLong(16); - relPosInfo.relPosD = tempRelPos / 100.0; //Convert cm to m - - relPosInfo.relPosLength = extractLong(20); - relPosInfo.relPosHeading = extractLong(24); - - relPosInfo.relPosHPN = payloadCfg[32]; - relPosInfo.relPosHPE = payloadCfg[33]; - relPosInfo.relPosHPD = payloadCfg[34]; - relPosInfo.relPosHPLength = payloadCfg[35]; - - uint32_t tempAcc; - - tempAcc = extractLong(36); - relPosInfo.accN = tempAcc / 10000.0; //Convert 0.1 mm to m - - tempAcc = extractLong(40); - relPosInfo.accE = tempAcc / 10000.0; //Convert 0.1 mm to m - - tempAcc = extractLong(44); - relPosInfo.accD = tempAcc / 10000.0; //Convert 0.1 mm to m - - uint8_t flags = payloadCfg[60]; - - relPosInfo.gnssFixOk = flags & (1 << 0); - relPosInfo.diffSoln = flags & (1 << 1); - relPosInfo.relPosValid = flags & (1 << 2); - relPosInfo.carrSoln = (flags & (0b11 << 3)) >> 3; - relPosInfo.isMoving = flags & (1 << 5); - relPosInfo.refPosMiss = flags & (1 << 6); - relPosInfo.refObsMiss = flags & (1 << 7); - - return (true); -} -boolean SFE_UBLOX_GPS::getEsfInfo(uint16_t maxWait) -{ - // Requesting Data from the receiver - packetCfg.cls = UBX_CLASS_ESF; - packetCfg.id = UBX_ESF_STATUS; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) - return (false); //If command send fails then bail - - checkUblox(); - - // payload should be loaded. - imuMeas.version = extractByte(4); - imuMeas.fusionMode = extractByte(12); - ubloxSen.numSens = extractByte(15); - - // Individual Status Sensor in different function - return (true); -} - -// -boolean SFE_UBLOX_GPS::getEsfIns(uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_ESF; - packetCfg.id = UBX_ESF_INS; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) - return (false); //If command send fails then bail - - checkUblox(); - - // Validity of each sensor value below - uint32_t validity = extractLong(0); - - imuMeas.xAngRateVald = (validity && 0x0080) >> 8; - imuMeas.yAngRateVald = (validity && 0x0100) >> 9; - imuMeas.zAngRateVald = (validity && 0x0200) >> 10; - imuMeas.xAccelVald = (validity && 0x0400) >> 11; - imuMeas.yAccelVald = (validity && 0x0800) >> 12; - imuMeas.zAccelVald = (validity && 0x1000) >> 13; - - imuMeas.xAngRate = extractLong(12); // deg/s - imuMeas.yAngRate = extractLong(16); // deg/s - imuMeas.zAngRate = extractLong(20); // deg/s - - imuMeas.xAccel = extractLong(24); // m/s - imuMeas.yAccel = extractLong(28); // m/s - imuMeas.zAccel = extractLong(32); // m/s - - return (true); -} - -// -boolean SFE_UBLOX_GPS::getEsfDataInfo(uint16_t maxWait) -{ - - packetCfg.cls = UBX_CLASS_ESF; - packetCfg.id = UBX_ESF_MEAS; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) - return (false); //If command send fails then bail - - checkUblox(); - - uint32_t timeStamp = extractLong(0); - uint32_t flags = extractInt(4); - - uint8_t timeSent = (flags && 0x01) >> 1; - uint8_t timeEdge = (flags && 0x02) >> 2; - uint8_t tagValid = (flags && 0x04) >> 3; - uint8_t numMeas = (flags && 0x1000) >> 15; - - if (numMeas > DEF_NUM_SENS) - numMeas = DEF_NUM_SENS; - - uint8_t byteOffset = 4; - - for (uint8_t i = 0; i < numMeas; i++) - { - - uint32_t bitField = extractLong(4 + byteOffset * i); - imuMeas.dataType[i] = (bitField && 0xFF000000) >> 23; - imuMeas.data[i] = (bitField && 0xFFFFFF); - imuMeas.dataTStamp[i] = extractLong(8 + byteOffset * i); - } - - return (true); -} - -boolean SFE_UBLOX_GPS::getEsfRawDataInfo(uint16_t maxWait) -{ - - // Need to know the number of sensor to get the correct data - // Rate selected in UBX-CFG-MSG is not respected - packetCfg.cls = UBX_CLASS_ESF; - packetCfg.id = UBX_ESF_RAW; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) - return (false); //If command send fails then bail - - checkUblox(); - - uint32_t bitField = extractLong(4); - imuMeas.rawDataType = (bitField && 0xFF000000) >> 23; - imuMeas.rawData = (bitField && 0xFFFFFF); - imuMeas.rawTStamp = extractLong(8); - - return (true); -} - -sfe_ublox_status_e SFE_UBLOX_GPS::getSensState(uint8_t sensor, uint16_t maxWait) -{ - - packetCfg.cls = UBX_CLASS_ESF; - packetCfg.id = UBX_ESF_STATUS; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) - return (SFE_UBLOX_STATUS_FAIL); //If command send fails then bail - - ubloxSen.numSens = extractByte(15); - - if (sensor > ubloxSen.numSens) - return (SFE_UBLOX_STATUS_OUT_OF_RANGE); - - checkUblox(); - - uint8_t offset = 4; - - // Only the last sensor value checked will remain. - for (uint8_t i = 0; i < sensor; i++) - { - - uint8_t sensorFieldOne = extractByte(16 + offset * i); - uint8_t sensorFieldTwo = extractByte(17 + offset * i); - ubloxSen.freq = extractByte(18 + offset * i); - uint8_t sensorFieldThr = extractByte(19 + offset * i); - - ubloxSen.senType = (sensorFieldOne && 0x10) >> 5; - ubloxSen.isUsed = (sensorFieldOne && 0x20) >> 6; - ubloxSen.isReady = (sensorFieldOne && 0x30) >> 7; - - ubloxSen.calibStatus = sensorFieldTwo && 0x03; - ubloxSen.timeStatus = (sensorFieldTwo && 0xC) >> 2; - - ubloxSen.badMeas = (sensorFieldThr && 0x01); - ubloxSen.badTag = (sensorFieldThr && 0x02) >> 1; - ubloxSen.missMeas = (sensorFieldThr && 0x04) >> 2; - ubloxSen.noisyMeas = (sensorFieldThr && 0x08) >> 3; - } - - return (SFE_UBLOX_STATUS_SUCCESS); -} - -boolean SFE_UBLOX_GPS::getVehAtt(uint16_t maxWait) -{ - - packetCfg.cls = UBX_CLASS_NAV; - packetCfg.id = UBX_NAV_ATT; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) - return (SFE_UBLOX_STATUS_FAIL); //If command send fails then bail - - checkUblox(); - - vehAtt.roll = extractLong(8); - vehAtt.pitch = extractLong(12); - vehAtt.heading = extractLong(16); - - vehAtt.accRoll = extractLong(20); - vehAtt.accPitch = extractLong(24); - vehAtt.accHeading = extractLong(28); - - return (true); -} diff --git a/examples/Series_6_7/Example1_GetPositionAndTime_Series_6_7/SparkFun_Ublox_Arduino_Library_Series_6_7.h b/examples/Series_6_7/Example1_GetPositionAndTime_Series_6_7/SparkFun_Ublox_Arduino_Library_Series_6_7.h deleted file mode 100644 index a243865..0000000 --- a/examples/Series_6_7/Example1_GetPositionAndTime_Series_6_7/SparkFun_Ublox_Arduino_Library_Series_6_7.h +++ /dev/null @@ -1,932 +0,0 @@ -/* - This is a library written for the u-blox ZED-F9P and NEO-M8P-2 - - Updated: June 16th, 2020 - - This copy includes changes by @blazczak and @geeksville to - provide support for the older series 6 and 7 modules. - - Disclaimer: SparkFun has not verified this copy of the library on either series 6 or 7. - It should work, it looks like it will work, but we have no way of confirming this. - We cannot guarantee that it will work reliably in your application. - - Do you like this library? Help support SparkFun. Buy a board! - https://www.sparkfun.com/products/15136 - https://www.sparkfun.com/products/15005 - https://www.sparkfun.com/products/15733 - https://www.sparkfun.com/products/15193 - https://www.sparkfun.com/products/15210 - - Original library written by Nathan Seidle @ SparkFun Electronics, September 6th, 2018 - - This library handles configuring and handling the responses - from a u-blox GPS module. Works with most modules from u-blox including - the Zed-F9P, NEO-M8P-2, NEO-M9N, ZOE-M8Q, SAM-M8Q, and many others. - - https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library - - Development environment specifics: - Arduino IDE 1.8.5 - - SparkFun code, firmware, and software is released under the MIT License(http://opensource.org/licenses/MIT). - The MIT License (MIT) - Copyright (c) 2016 SparkFun Electronics - Permission is hereby granted, free of charge, to any person obtaining a copy of this software and - associated documentation files (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the Software is furnished to - do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or substantial - portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef SPARKFUN_UBLOX_ARDUINO_LIBRARY_H -#define SPARKFUN_UBLOX_ARDUINO_LIBRARY_H - -#if (ARDUINO >= 100) -#include "Arduino.h" -#else -#include "WProgram.h" -#endif - -#include - -//Platform specific configurations - -//Define the size of the I2C buffer based on the platform the user has -//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) - -//I2C_BUFFER_LENGTH is defined in Wire.H -#define I2C_BUFFER_LENGTH BUFFER_LENGTH - -#elif defined(__SAMD21G18A__) - -//SAMD21 uses RingBuffer.h -#define I2C_BUFFER_LENGTH SERIAL_BUFFER_SIZE - -//#elif __MK20DX256__ -//Teensy - -#endif - -#ifndef I2C_BUFFER_LENGTH - -//The catch-all default is 32 -#define I2C_BUFFER_LENGTH 32 -//#define I2C_BUFFER_LENGTH 16 //For testing on Artemis - -#endif - -// Define Serial for SparkFun SAMD based boards. -// Boards like the RedBoard Turbo use SerialUSB (not Serial). -// But other boards like the SAMD51 Thing Plus use Serial (not SerialUSB). -// The next nine lines let the code compile cleanly on as many SAMD boards as possible. -#if defined(ARDUINO_ARCH_SAMD) // Is this a SAMD board? - #if defined(USB_VID) // Is the USB Vendor ID defined? - #if (USB_VID == 0x1B4F) // Is this a SparkFun board? - #if !defined(ARDUINO_SAMD51_THING_PLUS) // If it is not a SAMD51 Thing Plus - #define Serial SerialUSB // Define Serial as SerialUSB - #endif - #endif - #endif -#endif -//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - -//Define a digital pin to aid checksum failure capture and analysis -//Leave set to -1 if not needed -const int checksumFailurePin = -1; - -// Global Status Returns -typedef enum -{ - SFE_UBLOX_STATUS_SUCCESS, - SFE_UBLOX_STATUS_FAIL, - SFE_UBLOX_STATUS_CRC_FAIL, - SFE_UBLOX_STATUS_TIMEOUT, - SFE_UBLOX_STATUS_COMMAND_NACK, // Indicates that the command was unrecognised, invalid or that the module is too busy to respond - SFE_UBLOX_STATUS_OUT_OF_RANGE, - SFE_UBLOX_STATUS_INVALID_ARG, - SFE_UBLOX_STATUS_INVALID_OPERATION, - SFE_UBLOX_STATUS_MEM_ERR, - SFE_UBLOX_STATUS_HW_ERR, - SFE_UBLOX_STATUS_DATA_SENT, // This indicates that a 'set' was successful - SFE_UBLOX_STATUS_DATA_RECEIVED, // This indicates that a 'get' (poll) was successful - SFE_UBLOX_STATUS_I2C_COMM_FAILURE, - SFE_UBLOX_STATUS_DATA_OVERWRITTEN // This is an error - the data was valid but has been or _is being_ overwritten by another packet -} sfe_ublox_status_e; - -// ubxPacket validity -typedef enum -{ - SFE_UBLOX_PACKET_VALIDITY_NOT_VALID, - SFE_UBLOX_PACKET_VALIDITY_VALID, - SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, - SFE_UBLOX_PACKET_NOTACKNOWLEDGED // This indicates that we received a NACK -} sfe_ublox_packet_validity_e; - -// Identify which packet buffer is in use: -// packetCfg (or a custom packet), packetAck or packetBuf -typedef enum -{ - SFE_UBLOX_PACKET_PACKETCFG, - SFE_UBLOX_PACKET_PACKETACK, - SFE_UBLOX_PACKET_PACKETBUF -} sfe_ublox_packet_buffer_e; - -//Registers -const uint8_t UBX_SYNCH_1 = 0xB5; -const uint8_t UBX_SYNCH_2 = 0x62; - -//The following are UBX Class IDs. Descriptions taken from ZED-F9P Interface Description Document page 32, NEO-M8P Interface Description page 145 -const uint8_t UBX_CLASS_NAV = 0x01; //Navigation Results Messages: Position, Speed, Time, Acceleration, Heading, DOP, SVs used -const uint8_t UBX_CLASS_RXM = 0x02; //Receiver Manager Messages: Satellite Status, RTC Status -const uint8_t UBX_CLASS_INF = 0x04; //Information Messages: Printf-Style Messages, with IDs such as Error, Warning, Notice -const uint8_t UBX_CLASS_ACK = 0x05; //Ack/Nak Messages: Acknowledge or Reject messages to UBX-CFG input messages -const uint8_t UBX_CLASS_CFG = 0x06; //Configuration Input Messages: Configure the receiver. -const uint8_t UBX_CLASS_UPD = 0x09; //Firmware Update Messages: Memory/Flash erase/write, Reboot, Flash identification, etc. -const uint8_t UBX_CLASS_MON = 0x0A; //Monitoring Messages: Communication Status, CPU Load, Stack Usage, Task Status -const uint8_t UBX_CLASS_AID = 0x0B; //(NEO-M8P ONLY!!!) AssistNow Aiding Messages: Ephemeris, Almanac, other A-GPS data input -const uint8_t UBX_CLASS_TIM = 0x0D; //Timing Messages: Time Pulse Output, Time Mark Results -const uint8_t UBX_CLASS_ESF = 0x10; //(NEO-M8P ONLY!!!) External Sensor Fusion Messages: External Sensor Measurements and Status Information -const uint8_t UBX_CLASS_MGA = 0x13; //Multiple GNSS Assistance Messages: Assistance data for various GNSS -const uint8_t UBX_CLASS_LOG = 0x21; //Logging Messages: Log creation, deletion, info and retrieval -const uint8_t UBX_CLASS_SEC = 0x27; //Security Feature Messages -const uint8_t UBX_CLASS_HNR = 0x28; //(NEO-M8P ONLY!!!) High Rate Navigation Results Messages: High rate time, position speed, heading -const uint8_t UBX_CLASS_NMEA = 0xF0; //NMEA Strings: standard NMEA strings - -//The following are used for configuration. Descriptions are from the ZED-F9P Interface Description pg 33-34 and NEO-M9N Interface Description pg 47-48 -const uint8_t UBX_CFG_ANT = 0x13; //Antenna Control Settings. Used to configure the antenna control settings -const uint8_t UBX_CFG_BATCH = 0x93; //Get/set data batching configuration. -const uint8_t UBX_CFG_CFG = 0x09; //Clear, Save, and Load Configurations. Used to save current configuration -const uint8_t UBX_CFG_DAT = 0x06; //Set User-defined Datum or The currently defined Datum -const uint8_t UBX_CFG_DGNSS = 0x70; //DGNSS configuration -const uint8_t UBX_CFG_GEOFENCE = 0x69; //Geofencing configuration. Used to configure a geofence -const uint8_t UBX_CFG_GNSS = 0x3E; //GNSS system configuration -const uint8_t UBX_CFG_INF = 0x02; //Depending on packet length, either: poll configuration for one protocol, or information message configuration -const uint8_t UBX_CFG_ITFM = 0x39; //Jamming/Interference Monitor configuration -const uint8_t UBX_CFG_LOGFILTER = 0x47; //Data Logger Configuration -const uint8_t UBX_CFG_MSG = 0x01; //Poll a message configuration, or Set Message Rate(s), or Set Message Rate -const uint8_t UBX_CFG_NAV5 = 0x24; //Navigation Engine Settings. Used to configure the navigation engine including the dynamic model. -const uint8_t UBX_CFG_NAVX5 = 0x23; //Navigation Engine Expert Settings -const uint8_t UBX_CFG_NMEA = 0x17; //Extended NMEA protocol configuration V1 -const uint8_t UBX_CFG_ODO = 0x1E; //Odometer, Low-speed COG Engine Settings -const uint8_t UBX_CFG_PM2 = 0x3B; //Extended power management configuration -const uint8_t UBX_CFG_PMS = 0x86; //Power mode setup -const uint8_t UBX_CFG_PRT = 0x00; //Used to configure port specifics. Polls the configuration for one I/O Port, or Port configuration for UART ports, or Port configuration for USB port, or Port configuration for SPI port, or Port configuration for DDC port -const uint8_t UBX_CFG_PWR = 0x57; //Put receiver in a defined power state -const uint8_t UBX_CFG_RATE = 0x08; //Navigation/Measurement Rate Settings. Used to set port baud rates. -const uint8_t UBX_CFG_RINV = 0x34; //Contents of Remote Inventory -const uint8_t UBX_CFG_RST = 0x04; //Reset Receiver / Clear Backup Data Structures. Used to reset device. -const uint8_t UBX_CFG_RXM = 0x11; //RXM configuration -const uint8_t UBX_CFG_SBAS = 0x16; //SBAS configuration -const uint8_t UBX_CFG_TMODE3 = 0x71; //Time Mode Settings 3. Used to enable Survey In Mode -const uint8_t UBX_CFG_TP5 = 0x31; //Time Pulse Parameters -const uint8_t UBX_CFG_USB = 0x1B; //USB Configuration -const uint8_t UBX_CFG_VALDEL = 0x8C; //Used for config of higher version u-blox modules (ie protocol v27 and above). Deletes values corresponding to provided keys/ provided keys with a transaction -const uint8_t UBX_CFG_VALGET = 0x8B; //Used for config of higher version u-blox modules (ie protocol v27 and above). Configuration Items -const uint8_t UBX_CFG_VALSET = 0x8A; //Used for config of higher version u-blox modules (ie protocol v27 and above). Sets values corresponding to provided key-value pairs/ provided key-value pairs within a transaction. - -//The following are used to enable NMEA messages. Descriptions come from the NMEA messages overview in the ZED-F9P Interface Description -const uint8_t UBX_NMEA_MSB = 0xF0; //All NMEA enable commands have 0xF0 as MSB -const uint8_t UBX_NMEA_DTM = 0x0A; //GxDTM (datum reference) -const uint8_t UBX_NMEA_GAQ = 0x45; //GxGAQ (poll a standard message (if the current talker ID is GA)) -const uint8_t UBX_NMEA_GBQ = 0x44; //GxGBQ (poll a standard message (if the current Talker ID is GB)) -const uint8_t UBX_NMEA_GBS = 0x09; //GxGBS (GNSS satellite fault detection) -const uint8_t UBX_NMEA_GGA = 0x00; //GxGGA (Global positioning system fix data) -const uint8_t UBX_NMEA_GLL = 0x01; //GxGLL (latitude and long, whith time of position fix and status) -const uint8_t UBX_NMEA_GLQ = 0x43; //GxGLQ (poll a standard message (if the current Talker ID is GL)) -const uint8_t UBX_NMEA_GNQ = 0x42; //GxGNQ (poll a standard message (if the current Talker ID is GN)) -const uint8_t UBX_NMEA_GNS = 0x0D; //GxGNS (GNSS fix data) -const uint8_t UBX_NMEA_GPQ = 0x040; //GxGPQ (poll a standard message (if the current Talker ID is GP)) -const uint8_t UBX_NMEA_GRS = 0x06; //GxGRS (GNSS range residuals) -const uint8_t UBX_NMEA_GSA = 0x02; //GxGSA (GNSS DOP and Active satellites) -const uint8_t UBX_NMEA_GST = 0x07; //GxGST (GNSS Pseudo Range Error Statistics) -const uint8_t UBX_NMEA_GSV = 0x03; //GxGSV (GNSS satellites in view) -const uint8_t UBX_NMEA_RMC = 0x04; //GxRMC (Recommended minimum data) -const uint8_t UBX_NMEA_TXT = 0x41; //GxTXT (text transmission) -const uint8_t UBX_NMEA_VLW = 0x0F; //GxVLW (dual ground/water distance) -const uint8_t UBX_NMEA_VTG = 0x05; //GxVTG (course over ground and Ground speed) -const uint8_t UBX_NMEA_ZDA = 0x08; //GxZDA (Time and Date) - -//The following are used to configure the NMEA protocol main talker ID and GSV talker ID -const uint8_t UBX_NMEA_MAINTALKERID_NOTOVERRIDDEN = 0x00; //main talker ID is system dependent -const uint8_t UBX_NMEA_MAINTALKERID_GP = 0x01; //main talker ID is GPS -const uint8_t UBX_NMEA_MAINTALKERID_GL = 0x02; //main talker ID is GLONASS -const uint8_t UBX_NMEA_MAINTALKERID_GN = 0x03; //main talker ID is combined receiver -const uint8_t UBX_NMEA_MAINTALKERID_GA = 0x04; //main talker ID is Galileo -const uint8_t UBX_NMEA_MAINTALKERID_GB = 0x05; //main talker ID is BeiDou -const uint8_t UBX_NMEA_GSVTALKERID_GNSS = 0x00; //GNSS specific Talker ID (as defined by NMEA) -const uint8_t UBX_NMEA_GSVTALKERID_MAIN = 0x01; //use the main Talker ID - -//The following are used to configure INF UBX messages (information messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 34) -const uint8_t UBX_INF_CLASS = 0x04; //All INF messages have 0x04 as the class -const uint8_t UBX_INF_DEBUG = 0x04; //ASCII output with debug contents -const uint8_t UBX_INF_ERROR = 0x00; //ASCII output with error contents -const uint8_t UBX_INF_NOTICE = 0x02; //ASCII output with informational contents -const uint8_t UBX_INF_TEST = 0x03; //ASCII output with test contents -const uint8_t UBX_INF_WARNING = 0x01; //ASCII output with warning contents - -//The following are used to configure LOG UBX messages (loggings messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 34) -const uint8_t UBX_LOG_CREATE = 0x07; //Create Log File -const uint8_t UBX_LOG_ERASE = 0x03; //Erase Logged Data -const uint8_t UBX_LOG_FINDTIME = 0x0E; //Find index of a log entry based on a given time, or response to FINDTIME requested -const uint8_t UBX_LOG_INFO = 0x08; //Poll for log information, or Log information -const uint8_t UBX_LOG_RETRIEVEPOSEXTRA = 0x0F; //Odometer log entry -const uint8_t UBX_LOG_RETRIEVEPOS = 0x0B; //Position fix log entry -const uint8_t UBX_LOG_RETRIEVESTRING = 0x0D; //Byte string log entry -const uint8_t UBX_LOG_RETRIEVE = 0x09; //Request log data -const uint8_t UBX_LOG_STRING = 0x04; //Store arbitrary string on on-board flash - -//The following are used to configure MGA UBX messages (Multiple GNSS Assistance Messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 34) -const uint8_t UBX_MGA_ACK_DATA0 = 0x60; //Multiple GNSS Acknowledge message -const uint8_t UBX_MGA_BDS_EPH = 0x03; //BDS Ephemeris Assistance -const uint8_t UBX_MGA_BDS_ALM = 0x03; //BDS Almanac Assistance -const uint8_t UBX_MGA_BDS_HEALTH = 0x03; //BDS Health Assistance -const uint8_t UBX_MGA_BDS_UTC = 0x03; //BDS UTC Assistance -const uint8_t UBX_MGA_BDS_IONO = 0x03; //BDS Ionospheric Assistance -const uint8_t UBX_MGA_DBD = 0x80; //Either: Poll the Navigation Database, or Navigation Database Dump Entry -const uint8_t UBX_MGA_GAL_EPH = 0x02; //Galileo Ephemeris Assistance -const uint8_t UBX_MGA_GAL_ALM = 0x02; //Galileo Almanac Assitance -const uint8_t UBX_MGA_GAL_TIMOFFSET = 0x02; //Galileo GPS time offset assistance -const uint8_t UBX_MGA_GAL_UTC = 0x02; //Galileo UTC Assistance -const uint8_t UBX_MGA_GLO_EPH = 0x06; //GLONASS Ephemeris Assistance -const uint8_t UBX_MGA_GLO_ALM = 0x06; //GLONASS Almanac Assistance -const uint8_t UBX_MGA_GLO_TIMEOFFSET = 0x06; //GLONASS Auxiliary Time Offset Assistance -const uint8_t UBX_MGA_GPS_EPH = 0x00; //GPS Ephemeris Assistance -const uint8_t UBX_MGA_GPS_ALM = 0x00; //GPS Almanac Assistance -const uint8_t UBX_MGA_GPS_HEALTH = 0x00; //GPS Health Assistance -const uint8_t UBX_MGA_GPS_UTC = 0x00; //GPS UTC Assistance -const uint8_t UBX_MGA_GPS_IONO = 0x00; //GPS Ionosphere Assistance -const uint8_t UBX_MGA_INI_POS_XYZ = 0x40; //Initial Position Assistance -const uint8_t UBX_MGA_INI_POS_LLH = 0x40; //Initial Position Assitance -const uint8_t UBX_MGA_INI_TIME_UTC = 0x40; //Initial Time Assistance -const uint8_t UBX_MGA_INI_TIME_GNSS = 0x40; //Initial Time Assistance -const uint8_t UBX_MGA_INI_CLKD = 0x40; //Initial Clock Drift Assitance -const uint8_t UBX_MGA_INI_FREQ = 0x40; //Initial Frequency Assistance -const uint8_t UBX_MGA_INI_EOP = 0x40; //Earth Orientation Parameters Assistance -const uint8_t UBX_MGA_QZSS_EPH = 0x05; //QZSS Ephemeris Assistance -const uint8_t UBX_MGA_QZSS_ALM = 0x05; //QZSS Almanac Assistance -const uint8_t UBX_MGA_QZAA_HEALTH = 0x05; //QZSS Health Assistance - -//The following are used to configure the MON UBX messages (monitoring messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 35) -const uint8_t UBX_MON_COMMS = 0x36; //Comm port information -const uint8_t UBX_MON_GNSS = 0x28; //Information message major GNSS selection -const uint8_t UBX_MON_HW2 = 0x0B; //Extended Hardware Status -const uint8_t UBX_MON_HW3 = 0x37; //HW I/O pin information -const uint8_t UBX_MON_HW = 0x09; //Hardware Status -const uint8_t UBX_MON_IO = 0x02; //I/O Subsystem Status -const uint8_t UBX_MON_MSGPP = 0x06; //Message Parse and Process Status -const uint8_t UBX_MON_PATCH = 0x27; //Output information about installed patches -const uint8_t UBX_MON_RF = 0x38; //RF information -const uint8_t UBX_MON_RXBUF = 0x07; //Receiver Buffer Status -const uint8_t UBX_MON_RXR = 0x21; //Receiver Status Information -const uint8_t UBX_MON_TXBUF = 0x08; //Transmitter Buffer Status. Used for query tx buffer size/state. -const uint8_t UBX_MON_VER = 0x04; //Receiver/Software Version. Used for obtaining Protocol Version. - -//The following are used to configure the NAV UBX messages (navigation results messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 35-36) -const uint8_t UBX_NAV_ATT = 0x05; //Vehicle "Attitude" Solution -const uint8_t UBX_NAV_CLOCK = 0x22; //Clock Solution -const uint8_t UBX_NAV_DOP = 0x04; //Dilution of precision -const uint8_t UBX_NAV_EOE = 0x61; //End of Epoch -const uint8_t UBX_NAV_GEOFENCE = 0x39; //Geofencing status. Used to poll the geofence status -const uint8_t UBX_NAV_HPPOSECEF = 0x13; //High Precision Position Solution in ECEF. Used to find our positional accuracy (high precision). -const uint8_t UBX_NAV_HPPOSLLH = 0x14; //High Precision Geodetic Position Solution. Used for obtaining lat/long/alt in high precision -const uint8_t UBX_NAV_ODO = 0x09; //Odometer Solution -const uint8_t UBX_NAV_ORB = 0x34; //GNSS Orbit Database Info -const uint8_t UBX_NAV_POSECEF = 0x01; //Position Solution in ECEF -const uint8_t UBX_NAV_POSLLH = 0x02; //Geodetic Position Solution -const uint8_t UBX_NAV_PVT = 0x07; //All the things! Position, velocity, time, PDOP, height, h/v accuracies, number of satellites. Navigation Position Velocity Time Solution. -const uint8_t UBX_NAV_RELPOSNED = 0x3C; //Relative Positioning Information in NED frame -const uint8_t UBX_NAV_RESETODO = 0x10; //Reset odometer -const uint8_t UBX_NAV_SAT = 0x35; //Satellite Information -const uint8_t UBX_NAV_SIG = 0x43; //Signal Information -const uint8_t UBX_NAV_STATUS = 0x03; //Receiver Navigation Status -const uint8_t UBX_NAV_SVIN = 0x3B; //Survey-in data. Used for checking Survey In status -const uint8_t UBX_NAV_TIMEBDS = 0x24; //BDS Time Solution -const uint8_t UBX_NAV_TIMEGAL = 0x25; //Galileo Time Solution -const uint8_t UBX_NAV_TIMEGLO = 0x23; //GLO Time Solution -const uint8_t UBX_NAV_TIMEGPS = 0x20; //GPS Time Solution -const uint8_t UBX_NAV_TIMELS = 0x26; //Leap second event information -const uint8_t UBX_NAV_TIMEUTC = 0x21; //UTC Time Solution -const uint8_t UBX_NAV_VELECEF = 0x11; //Velocity Solution in ECEF -const uint8_t UBX_NAV_VELNED = 0x12; //Velocity Solution in NED - -//The following are used to configure the RXM UBX messages (receiver manager messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 36) -const uint8_t UBX_RXM_MEASX = 0x14; //Satellite Measurements for RRLP -const uint8_t UBX_RXM_PMREQ = 0x41; //Requests a Power Management task (two differenent packet sizes) -const uint8_t UBX_RXM_RAWX = 0x15; //Multi-GNSS Raw Measurement Data -const uint8_t UBX_RXM_RLM = 0x59; //Galileo SAR Short-RLM report (two different packet sizes) -const uint8_t UBX_RXM_RTCM = 0x32; //RTCM input status -const uint8_t UBX_RXM_SFRBX = 0x13; //Boradcast Navigation Data Subframe - -//The following are used to configure the SEC UBX messages (security feature messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 36) -const uint8_t UBX_SEC_UNIQID = 0x03; //Unique chip ID - -//The following are used to configure the TIM UBX messages (timing messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 36) -const uint8_t UBX_TIM_TM2 = 0x03; //Time mark data -const uint8_t UBX_TIM_TP = 0x01; //Time Pulse Timedata -const uint8_t UBX_TIM_VRFY = 0x06; //Sourced Time Verification - -//The following are used to configure the UPD UBX messages (firmware update messages). Descriptions from UBX messages overview (ZED-F9P Interface Description Document page 36) -const uint8_t UBX_UPD_SOS = 0x14; //Poll Backup Fil Restore Status, Create Backup File in Flash, Clear Backup File in Flash, Backup File Creation Acknowledge, System Restored from Backup - -//The following are used to enable RTCM messages -const uint8_t UBX_RTCM_MSB = 0xF5; //All RTCM enable commands have 0xF5 as MSB -const uint8_t UBX_RTCM_1005 = 0x05; //Stationary RTK reference ARP -const uint8_t UBX_RTCM_1074 = 0x4A; //GPS MSM4 -const uint8_t UBX_RTCM_1077 = 0x4D; //GPS MSM7 -const uint8_t UBX_RTCM_1084 = 0x54; //GLONASS MSM4 -const uint8_t UBX_RTCM_1087 = 0x57; //GLONASS MSM7 -const uint8_t UBX_RTCM_1094 = 0x5E; //Galileo MSM4 -const uint8_t UBX_RTCM_1097 = 0x61; //Galileo MSM7 -const uint8_t UBX_RTCM_1124 = 0x7C; //BeiDou MSM4 -const uint8_t UBX_RTCM_1127 = 0x7F; //BeiDou MSM7 -const uint8_t UBX_RTCM_1230 = 0xE6; //GLONASS code-phase biases, set to once every 10 seconds -const uint8_t UBX_RTCM_4072_0 = 0xFE; //Reference station PVT (ublox proprietary RTCM message) -const uint8_t UBX_RTCM_4072_1 = 0xFD; //Additional reference station information (ublox proprietary RTCM message) - -const uint8_t UBX_ACK_NACK = 0x00; -const uint8_t UBX_ACK_ACK = 0x01; -const uint8_t UBX_ACK_NONE = 0x02; //Not a real value - -// The following constants are used to get External Sensor Measurements and Status -// Information. -const uint8_t UBX_ESF_MEAS = 0x02; -const uint8_t UBX_ESF_RAW = 0x03; -const uint8_t UBX_ESF_STATUS = 0x10; -const uint8_t UBX_ESF_INS = 0x15; //36 bytes - -const uint8_t SVIN_MODE_DISABLE = 0x00; -const uint8_t SVIN_MODE_ENABLE = 0x01; - -//The following consts are used to configure the various ports and streams for those ports. See -CFG-PRT. -const uint8_t COM_PORT_I2C = 0; -const uint8_t COM_PORT_UART1 = 1; -const uint8_t COM_PORT_UART2 = 2; -const uint8_t COM_PORT_USB = 3; -const uint8_t COM_PORT_SPI = 4; - -const uint8_t COM_TYPE_UBX = (1 << 0); -const uint8_t COM_TYPE_NMEA = (1 << 1); -const uint8_t COM_TYPE_RTCM3 = (1 << 5); - -//The following consts are used to generate KEY values for the advanced protocol functions of VELGET/SET/DEL -const uint8_t VAL_SIZE_1 = 0x01; //One bit -const uint8_t VAL_SIZE_8 = 0x02; //One byte -const uint8_t VAL_SIZE_16 = 0x03; //Two bytes -const uint8_t VAL_SIZE_32 = 0x04; //Four bytes -const uint8_t VAL_SIZE_64 = 0x05; //Eight bytes - -//These are the Bitfield layers definitions for the UBX-CFG-VALSET message (not to be confused with Bitfield deviceMask in UBX-CFG-CFG) -const uint8_t VAL_LAYER_RAM = (1 << 0); -const uint8_t VAL_LAYER_BBR = (1 << 1); -const uint8_t VAL_LAYER_FLASH = (1 << 2); - -//Below are various Groups, IDs, and sizes for various settings -//These can be used to call getVal/setVal/delVal -const uint8_t VAL_GROUP_I2COUTPROT = 0x72; -const uint8_t VAL_GROUP_I2COUTPROT_SIZE = VAL_SIZE_1; //All fields in I2C group are currently 1 bit - -const uint8_t VAL_ID_I2COUTPROT_UBX = 0x01; -const uint8_t VAL_ID_I2COUTPROT_NMEA = 0x02; -const uint8_t VAL_ID_I2COUTPROT_RTCM3 = 0x03; - -const uint8_t VAL_GROUP_I2C = 0x51; -const uint8_t VAL_GROUP_I2C_SIZE = VAL_SIZE_8; //All fields in I2C group are currently 1 byte - -const uint8_t VAL_ID_I2C_ADDRESS = 0x01; - -// Configuration Sub-Section mask definitions for saveConfigSelective (UBX-CFG-CFG) -const uint32_t VAL_CFG_SUBSEC_IOPORT = 0x00000001; // ioPort - communications port settings (causes IO system reset!) -const uint32_t VAL_CFG_SUBSEC_MSGCONF = 0x00000002; // msgConf - message configuration -const uint32_t VAL_CFG_SUBSEC_INFMSG = 0x00000004; // infMsg - INF message configuration -const uint32_t VAL_CFG_SUBSEC_NAVCONF = 0x00000008; // navConf - navigation configuration -const uint32_t VAL_CFG_SUBSEC_RXMCONF = 0x00000010; // rxmConf - receiver manager configuration -const uint32_t VAL_CFG_SUBSEC_SENCONF = 0x00000100; // senConf - sensor interface configuration (requires protocol 19+) -const uint32_t VAL_CFG_SUBSEC_RINVCONF = 0x00000200; // rinvConf - remove inventory configuration -const uint32_t VAL_CFG_SUBSEC_ANTCONF = 0x00000400; // antConf - antenna configuration -const uint32_t VAL_CFG_SUBSEC_LOGCONF = 0x00000800; // logConf - logging configuration -const uint32_t VAL_CFG_SUBSEC_FTSCONF = 0x00001000; // ftsConf - FTS configuration (FTS products only) - -enum dynModel // Possible values for the dynamic platform model, which provide more accuract position output for the situation. Description extracted from ZED-F9P Integration Manual -{ - DYN_MODEL_PORTABLE = 0, //Applications with low acceleration, e.g. portable devices. Suitable for most situations. - // 1 is not defined - DYN_MODEL_STATIONARY = 2, //Used in timing applications (antenna must be stationary) or other stationary applications. Velocity restricted to 0 m/s. Zero dynamics assumed. - DYN_MODEL_PEDESTRIAN, //Applications with low acceleration and speed, e.g. how a pedestrian would move. Low acceleration assumed. - DYN_MODEL_AUTOMOTIVE, //Used for applications with equivalent dynamics to those of a passenger car. Low vertical acceleration assumed - DYN_MODEL_SEA, //Recommended for applications at sea, with zero vertical velocity. Zero vertical velocity assumed. Sea level assumed. - DYN_MODEL_AIRBORNE1g, //Airborne <1g acceleration. Used for applications with a higher dynamic range and greater vertical acceleration than a passenger car. No 2D position fixes supported. - DYN_MODEL_AIRBORNE2g, //Airborne <2g acceleration. Recommended for typical airborne environments. No 2D position fixes supported. - DYN_MODEL_AIRBORNE4g, //Airborne <4g acceleration. Only recommended for extremely dynamic environments. No 2D position fixes supported. - DYN_MODEL_WRIST, // Not supported in protocol versions less than 18. Only recommended for wrist worn applications. Receiver will filter out arm motion. - DYN_MODEL_BIKE, // Supported in protocol versions 19.2 -}; - -#ifndef MAX_PAYLOAD_SIZE - -#define MAX_PAYLOAD_SIZE 256 //We need ~220 bytes for getProtocolVersion on most ublox modules -//#define MAX_PAYLOAD_SIZE 768 //Worst case: UBX_CFG_VALSET packet with 64 keyIDs each with 64 bit values - -#endif - -//-=-=-=-=- UBX binary specific variables -typedef struct -{ - uint8_t cls; - uint8_t id; - uint16_t len; //Length of the payload. Does not include cls, id, or checksum bytes - uint16_t counter; //Keeps track of number of overall bytes received. Some responses are larger than 255 bytes. - uint16_t startingSpot; //The counter value needed to go past before we begin recording into payload array - uint8_t *payload; - 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 -} ubxPacket; - -// Struct to hold the results returned by getGeofenceState (returned by UBX-NAV-GEOFENCE) -typedef struct -{ - uint8_t status; // Geofencing status: 0 - Geofencing not available or not reliable; 1 - Geofencing active - uint8_t numFences; // Number of geofences - uint8_t combState; // Combined (logical OR) state of all geofences: 0 - Unknown; 1 - Inside; 2 - Outside - uint8_t states[4]; // Geofence states: 0 - Unknown; 1 - Inside; 2 - Outside -} geofenceState; - -// Struct to hold the current geofence parameters -typedef struct -{ - uint8_t numFences; // Number of active geofences - int32_t lats[4]; // Latitudes of geofences (in degrees * 10^-7) - int32_t longs[4]; // Longitudes of geofences (in degrees * 10^-7) - uint32_t rads[4]; // Radii of geofences (in m * 10^-2) -} geofenceParams; - -class SFE_UBLOX_GPS -{ -public: - SFE_UBLOX_GPS(void); - -// A default of 250ms for maxWait seems fine for I2C but is not enough for SerialUSB. -// If you know you are only going to be using I2C / Qwiic communication, you can -// safely reduce defaultMaxWait to 250. -#ifndef defaultMaxWait // Let's allow the user to define their own value if they want to -#define defaultMaxWait 1100 -#endif - - //By default use the default I2C address, and use Wire port - boolean begin(TwoWire &wirePort = Wire, uint8_t deviceAddress = 0x42); //Returns true if module is detected - //serialPort needs to be perviously initialized to correct baud rate - boolean begin(Stream &serialPort); //Returns true if module is detected - - //Returns true if device answers on _gpsI2Caddress address or via Serial - //maxWait is only used for Serial - boolean isConnected(uint16_t maxWait = 1100); - - //Changed in V1.8.1: provides backward compatibility for the examples that call checkUblox directly - //Will default to using packetCfg to look for explicit autoPVT packets so they get processed correctly by processUBX - boolean checkUblox(uint8_t requestedClass = UBX_CLASS_NAV, uint8_t requestedID = UBX_NAV_PVT); //Checks module with user selected commType - - 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() - - void process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID); //Processes NMEA and UBX binary sentences one byte at a time - 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 processRTCMframe(uint8_t incoming); //Monitor the incoming bytes for start and length bytes - void processRTCM(uint8_t incoming) __attribute__((weak)); //Given rtcm byte, do something with it. User can overwrite if desired to pipe bytes to radio, internet, etc. - - void processUBXpacket(ubxPacket *msg); //Once a packet has been received and validated, identify this packet's class/id and update internal flags - void processNMEA(char incoming) __attribute__((weak)); //Given a NMEA character, do something with it. User can overwrite if desired to use something like tinyGPS or MicroNMEA libraries - - void calcChecksum(ubxPacket *msg); //Sets the checksumA and checksumB of a given messages - sfe_ublox_status_e sendCommand(ubxPacket *outgoingUBX, uint16_t maxWait = defaultMaxWait); //Given a packet and payload, send everything including CRC bytes, return true if we got a response - sfe_ublox_status_e sendI2cCommand(ubxPacket *outgoingUBX, uint16_t maxWait = 250); - void sendSerialCommand(ubxPacket *outgoingUBX); - - void printPacket(ubxPacket *packet); //Useful for debugging - - void factoryReset(); //Send factory reset sequence (i.e. load "default" configuration and perform hardReset) - void hardReset(); //Perform a reset leading to a cold start (zero info start-up) - - boolean setI2CAddress(uint8_t deviceAddress, uint16_t maxTime = 250); //Changes the I2C address of the u-blox module - void setSerialRate(uint32_t baudrate, uint8_t uartPort = COM_PORT_UART1, uint16_t maxTime = defaultMaxWait); //Changes the serial baud rate of the u-blox module, uartPort should be COM_PORT_UART1/2 - void setNMEAOutputPort(Stream &nmeaOutputPort); //Sets the internal variable for the port to direct NMEA characters to - - boolean setNavigationFrequency(uint8_t navFreq, uint16_t maxWait = defaultMaxWait); //Set the number of nav solutions sent per second - uint8_t getNavigationFrequency(uint16_t maxWait = defaultMaxWait); //Get the number of nav solutions sent per second currently being output by module - boolean saveConfiguration(uint16_t maxWait = defaultMaxWait); //Save current configuration to flash and BBR (battery backed RAM) - boolean factoryDefault(uint16_t maxWait = defaultMaxWait); //Reset module to factory defaults - boolean saveConfigSelective(uint32_t configMask, uint16_t maxWait = defaultMaxWait); //Save the selected configuration sub-sections to flash and BBR (battery backed RAM) - - sfe_ublox_status_e waitForACKResponse(ubxPacket *outgoingUBX, uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime = defaultMaxWait); //Poll the module until a config packet and an ACK is received - sfe_ublox_status_e waitForNoACKResponse(ubxPacket *outgoingUBX, uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime = defaultMaxWait); //Poll the module until a config packet is received - -// getPVT will only return data once in each navigation cycle. By default, that is once per second. -// Therefore we should set getPVTmaxWait to slightly longer than that. -// If you change the navigation frequency to (e.g.) 4Hz using setNavigationFrequency(4) -// then you should use a shorter maxWait for getPVT. 300msec would be about right: getPVT(300) -// The same is true for getHPPOSLLH. -#define getPVTmaxWait 1100 // Default maxWait for getPVT and all functions which call it -#define getHPPOSLLHmaxWait 1100 // Default maxWait for getHPPOSLLH and all functions which call it - - boolean assumeAutoPVT(boolean enabled, boolean implicitUpdate = true); //In case no config access to the GPS is possible and PVT is send cyclically already - boolean setAutoPVT(boolean enabled, uint16_t maxWait = defaultMaxWait); //Enable/disable automatic PVT reports at the navigation frequency - boolean getPVT(uint16_t maxWait = getPVTmaxWait); //Query module for latest group of datums and load global vars: lat, long, alt, speed, SIV, accuracies, etc. If autoPVT is disabled, performs an explicit poll and waits, if enabled does not block. Returns true if new PVT is available. - boolean getTimeData(uint16_t maxWait = getPVTmaxWait); //Query module for latest time data. Calls getPVT or getTIMEUTC depending on which module is attached. - boolean getPositionData(uint16_t maxWait = getPVTmaxWait); //Query module for latest position data. Calls getPVT or getPOSLLH depending on which module is attached. - boolean getTIMEUTC(uint16_t maxWait = getPVTmaxWait); //Query module for current time (for use with older chip series). Returns true if new data is available. - boolean getPOSLLH(uint16_t maxWait = getPVTmaxWait); //Query module for current position (for use with older chip series). Returns true if new data is available. - - boolean setAutoPVT(boolean enabled, boolean implicitUpdate, uint16_t maxWait = defaultMaxWait); //Enable/disable automatic PVT reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update - boolean getHPPOSLLH(uint16_t maxWait = getHPPOSLLHmaxWait); //Query module for latest group of datums and load global vars: lat, long, alt, speed, SIV, accuracies, etc. If autoPVT is disabled, performs an explicit poll and waits, if enabled does not block. Returns true if new PVT is available. - void flushPVT(); //Mark all the PVT data as read/stale. This is handy to get data alignment after CRC failure - - int32_t getLatitude(uint16_t maxWait = getPVTmaxWait); //Returns the current latitude in degrees * 10^-7. Auto selects between HighPrecision and Regular depending on ability of module. - int32_t getLongitude(uint16_t maxWait = getPVTmaxWait); //Returns the current longitude in degrees * 10-7. Auto selects between HighPrecision and Regular depending on ability of module. - int32_t getAltitude(uint16_t maxWait = getPVTmaxWait); //Returns the current altitude in mm above ellipsoid - int32_t getAltitudeMSL(uint16_t maxWait = getPVTmaxWait); //Returns the current altitude in mm above mean sea level - uint8_t getSIV(uint16_t maxWait = getPVTmaxWait); //Returns number of sats used in fix - uint8_t getFixType(uint16_t maxWait = getPVTmaxWait); //Returns the type of fix: 0=no, 3=3D, 4=GNSS+Deadreckoning - uint8_t getCarrierSolutionType(uint16_t maxWait = getPVTmaxWait); //Returns RTK solution: 0=no, 1=float solution, 2=fixed solution - int32_t getGroundSpeed(uint16_t maxWait = getPVTmaxWait); //Returns speed in mm/s - int32_t getHeading(uint16_t maxWait = getPVTmaxWait); //Returns heading in degrees * 10^-7 - uint16_t getPDOP(uint16_t maxWait = getPVTmaxWait); //Returns positional dillution of precision * 10^-2 (dimensionless) - uint16_t getYear(uint16_t maxWait = getPVTmaxWait); - uint8_t getMonth(uint16_t maxWait = getPVTmaxWait); - uint8_t getDay(uint16_t maxWait = getPVTmaxWait); - uint8_t getHour(uint16_t maxWait = getPVTmaxWait); - uint8_t getMinute(uint16_t maxWait = getPVTmaxWait); - uint8_t getSecond(uint16_t maxWait = getPVTmaxWait); - uint16_t getMillisecond(uint16_t maxWait = getPVTmaxWait); - int32_t getNanosecond(uint16_t maxWait = getPVTmaxWait); - uint32_t getTimeOfWeek(uint16_t maxWait = getPVTmaxWait); - - int32_t getHighResLatitude(uint16_t maxWait = getHPPOSLLHmaxWait); - int8_t getHighResLatitudeHp(uint16_t maxWait = getHPPOSLLHmaxWait); - int32_t getHighResLongitude(uint16_t maxWait = getHPPOSLLHmaxWait); - int8_t getHighResLongitudeHp(uint16_t maxWait = getHPPOSLLHmaxWait); - int32_t getElipsoid(uint16_t maxWait = getHPPOSLLHmaxWait); - int8_t getElipsoidHp(uint16_t maxWait = getHPPOSLLHmaxWait); - int32_t getMeanSeaLevel(uint16_t maxWait = getHPPOSLLHmaxWait); - int8_t getMeanSeaLevelHp(uint16_t maxWait = getHPPOSLLHmaxWait); - int32_t getGeoidSeparation(uint16_t maxWait = getHPPOSLLHmaxWait); - uint32_t getHorizontalAccuracy(uint16_t maxWait = getHPPOSLLHmaxWait); - uint32_t getVerticalAccuracy(uint16_t maxWait = getHPPOSLLHmaxWait); - - //Port configurations - boolean setPortOutput(uint8_t portID, uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure a given port to output UBX, NMEA, RTCM3 or a combination thereof - boolean setPortInput(uint8_t portID, uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure a given port to input UBX, NMEA, RTCM3 or a combination thereof - boolean getPortSettings(uint8_t portID, uint16_t maxWait = defaultMaxWait); //Returns the current protocol bits in the UBX-CFG-PRT command for a given port - - boolean setI2COutput(uint8_t comSettings, uint16_t maxWait = 250); //Configure I2C port to output UBX, NMEA, RTCM3 or a combination thereof - boolean setUART1Output(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure UART1 port to output UBX, NMEA, RTCM3 or a combination thereof - boolean setUART2Output(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure UART2 port to output UBX, NMEA, RTCM3 or a combination thereof - boolean setUSBOutput(uint8_t comSettings, uint16_t maxWait = 250); //Configure USB port to output UBX, NMEA, RTCM3 or a combination thereof - boolean setSPIOutput(uint8_t comSettings, uint16_t maxWait = 250); //Configure SPI port to output UBX, NMEA, RTCM3 or a combination thereof - - //Functions to turn on/off message types for a given port ID (see COM_PORT_I2C, etc above) - boolean configureMessage(uint8_t msgClass, uint8_t msgID, uint8_t portID, uint8_t sendRate, uint16_t maxWait = defaultMaxWait); - boolean enableMessage(uint8_t msgClass, uint8_t msgID, uint8_t portID, uint8_t sendRate = 1, uint16_t maxWait = defaultMaxWait); - boolean disableMessage(uint8_t msgClass, uint8_t msgID, uint8_t portID, uint16_t maxWait = defaultMaxWait); - boolean enableNMEAMessage(uint8_t msgID, uint8_t portID, uint8_t sendRate = 1, uint16_t maxWait = defaultMaxWait); - boolean disableNMEAMessage(uint8_t msgID, uint8_t portID, uint16_t maxWait = defaultMaxWait); - boolean enableRTCMmessage(uint8_t messageNumber, uint8_t portID, uint8_t sendRate, uint16_t maxWait = defaultMaxWait); //Given a message number turns on a message ID for output over given PortID - boolean disableRTCMmessage(uint8_t messageNumber, uint8_t portID, uint16_t maxWait = defaultMaxWait); //Turn off given RTCM message from a given port - - //General configuration (used only on protocol v27 and higher - ie, ZED-F9P) - //It is probably safe to assume that users of the ZED-F9P will be using I2C / Qwiic. - //If they are using Serial then the higher baud rate will also help. So let's leave maxWait set to 250ms. - uint8_t getVal8(uint16_t group, uint16_t id, uint8_t size, uint8_t layer = VAL_LAYER_BBR, uint16_t maxWait = 250); //Returns the value at a given group/id/size location - uint8_t getVal8(uint32_t keyID, uint8_t layer = VAL_LAYER_BBR, uint16_t maxWait = 250); //Returns the value at a given group/id/size location - uint8_t setVal(uint32_t keyID, uint16_t value, uint8_t layer = VAL_LAYER_BBR, uint16_t maxWait = 250); //Sets the 16-bit value at a given group/id/size location - uint8_t setVal8(uint32_t keyID, uint8_t value, uint8_t layer = VAL_LAYER_BBR, uint16_t maxWait = 250); //Sets the 8-bit value at a given group/id/size location - uint8_t setVal16(uint32_t keyID, uint16_t value, uint8_t layer = VAL_LAYER_BBR, uint16_t maxWait = 250); //Sets the 16-bit value at a given group/id/size location - uint8_t setVal32(uint32_t keyID, uint32_t value, uint8_t layer = VAL_LAYER_BBR, uint16_t maxWait = 250); //Sets the 32-bit value at a given group/id/size location - uint8_t newCfgValset8(uint32_t keyID, uint8_t value, uint8_t layer = VAL_LAYER_BBR); //Define a new UBX-CFG-VALSET with the given KeyID and 8-bit value - uint8_t newCfgValset16(uint32_t keyID, uint16_t value, uint8_t layer = VAL_LAYER_BBR); //Define a new UBX-CFG-VALSET with the given KeyID and 16-bit value - uint8_t newCfgValset32(uint32_t keyID, uint32_t value, uint8_t layer = VAL_LAYER_BBR); //Define a new UBX-CFG-VALSET with the given KeyID and 32-bit value - uint8_t addCfgValset8(uint32_t keyID, uint8_t value); //Add a new KeyID and 8-bit value to an existing UBX-CFG-VALSET ubxPacket - uint8_t addCfgValset16(uint32_t keyID, uint16_t value); //Add a new KeyID and 16-bit value to an existing UBX-CFG-VALSET ubxPacket - uint8_t addCfgValset32(uint32_t keyID, uint32_t value); //Add a new KeyID and 32-bit value to an existing UBX-CFG-VALSET ubxPacket - uint8_t sendCfgValset8(uint32_t keyID, uint8_t value, uint16_t maxWait = 250); //Add the final KeyID and 8-bit value to an existing UBX-CFG-VALSET ubxPacket and send it - uint8_t sendCfgValset16(uint32_t keyID, uint16_t value, uint16_t maxWait = 250); //Add the final KeyID and 16-bit value to an existing UBX-CFG-VALSET ubxPacket and send it - uint8_t sendCfgValset32(uint32_t keyID, uint32_t value, uint16_t maxWait = 250); //Add the final KeyID and 32-bit value to an existing UBX-CFG-VALSET ubxPacket and send it - - //Functions used for RTK and base station setup - //It is probably safe to assume that users of the RTK will be using I2C / Qwiic. So let's leave maxWait set to 250ms. - boolean getSurveyMode(uint16_t maxWait = 250); //Get the current TimeMode3 settings - boolean setSurveyMode(uint8_t mode, uint16_t observationTime, float requiredAccuracy, uint16_t maxWait = 250); //Control survey in mode - boolean enableSurveyMode(uint16_t observationTime, float requiredAccuracy, uint16_t maxWait = 250); //Begin Survey-In for NEO-M8P - boolean disableSurveyMode(uint16_t maxWait = 250); //Stop Survey-In mode - - boolean getSurveyStatus(uint16_t maxWait); //Reads survey in status and sets the global variables - - uint32_t getPositionAccuracy(uint16_t maxWait = 1100); //Returns the 3D accuracy of the current high-precision fix, in mm. Supported on NEO-M8P, ZED-F9P, - - uint8_t getProtocolVersionHigh(uint16_t maxWait = 500); //Returns the PROTVER XX.00 from UBX-MON-VER register - uint8_t getProtocolVersionLow(uint16_t maxWait = 500); //Returns the PROTVER 00.XX from UBX-MON-VER register - boolean getProtocolVersion(uint16_t maxWait = 500); //Queries module, loads low/high bytes - - boolean getRELPOSNED(uint16_t maxWait = 1100); //Get Relative Positioning Information of the NED frame - - void enableDebugging(Stream &debugPort = Serial, boolean printLimitedDebug = false); //Given a port to print to, enable debug messages. Default to all, not limited. - void disableDebugging(void); //Turn off debug statements - void debugPrint(char *message); //Safely print debug statements - void debugPrintln(char *message); //Safely print debug statements - const char *statusString(sfe_ublox_status_e stat); //Pretty print the return value - - //Support for geofences - boolean addGeofence(int32_t latitude, int32_t longitude, uint32_t radius, byte confidence = 0, byte pinPolarity = 0, byte pin = 0, uint16_t maxWait = 1100); // Add a new geofence - boolean clearGeofences(uint16_t maxWait = 1100); //Clears all geofences - boolean getGeofenceState(geofenceState ¤tGeofenceState, uint16_t maxWait = 1100); //Returns the combined geofence state - boolean clearAntPIO(uint16_t maxWait = 1100); //Clears the antenna control pin settings to release the PIOs - geofenceParams currentGeofenceParams; // Global to store the geofence parameters - - boolean powerSaveMode(bool power_save = true, uint16_t maxWait = 1100); - uint8_t getPowerSaveMode(uint16_t maxWait = 1100); // Returns 255 if the sendCommand fails - - //Change the dynamic platform model using UBX-CFG-NAV5 - boolean setDynamicModel(dynModel newDynamicModel = DYN_MODEL_PORTABLE, uint16_t maxWait = 1100); - uint8_t getDynamicModel(uint16_t maxWait = 1100); // Get the dynamic model - returns 255 if the sendCommand fails - - boolean getEsfInfo(uint16_t maxWait = 1100); - boolean getEsfIns(uint16_t maxWait = 1100); - boolean getEsfDataInfo(uint16_t maxWait = 1100); - boolean getEsfRawDataInfo(uint16_t maxWait = 1100); - sfe_ublox_status_e getSensState(uint8_t sensor, uint16_t maxWait = 1100); - boolean getVehAtt(uint16_t maxWait = 1100); - - //Survey-in specific controls - struct svinStructure - { - boolean active; - boolean valid; - uint16_t observationTime; - float meanAccuracy; - } svin; - - //Relative Positioning Info in NED frame specific controls - struct frelPosInfoStructure - { - uint16_t refStationID; - - float relPosN; - float relPosE; - float relPosD; - - long relPosLength; - long relPosHeading; - - int8_t relPosHPN; - int8_t relPosHPE; - int8_t relPosHPD; - int8_t relPosHPLength; - - float accN; - float accE; - float accD; - - bool gnssFixOk; - bool diffSoln; - bool relPosValid; - uint8_t carrSoln; - bool isMoving; - bool refPosMiss; - bool refObsMiss; - } relPosInfo; - - //The major datums we want to globally store - uint16_t gpsYear; - uint8_t gpsMonth; - uint8_t gpsDay; - uint8_t gpsHour; - uint8_t gpsMinute; - uint8_t gpsSecond; - uint16_t gpsMillisecond; - int32_t gpsNanosecond; - - int32_t latitude; //Degrees * 10^-7 (more accurate than floats) - int32_t longitude; //Degrees * 10^-7 (more accurate than floats) - int32_t altitude; //Number of mm above ellipsoid - int32_t altitudeMSL; //Number of mm above Mean Sea Level - uint8_t SIV; //Number of satellites used in position solution - uint8_t fixType; //Tells us when we have a solution aka lock - uint8_t carrierSolution; //Tells us when we have an RTK float/fixed solution - int32_t groundSpeed; //mm/s - int32_t headingOfMotion; //degrees * 10^-5 - uint16_t pDOP; //Positional dilution of precision * 10^-2 (dimensionless) - uint8_t versionLow; //Loaded from getProtocolVersion(). - uint8_t versionHigh; - - uint32_t timeOfWeek; // ms - int32_t highResLatitude; // Degrees * 10^-7 - int32_t highResLongitude; // Degrees * 10^-7 - int32_t elipsoid; // Height above ellipsoid in mm (Typo! Should be eLLipsoid! **Uncorrected for backward-compatibility.**) - int32_t meanSeaLevel; // Height above mean sea level in mm - int32_t geoidSeparation; // This seems to only be provided in NMEA GGA and GNS messages - uint32_t horizontalAccuracy; // mm * 10^-1 (i.e. 0.1mm) - uint32_t verticalAccuracy; // mm * 10^-1 (i.e. 0.1mm) - int8_t elipsoidHp; // High precision component of the height above ellipsoid in mm * 10^-1 (Deliberate typo! Should be eLLipsoidHp!) - int8_t meanSeaLevelHp; // High precision component of Height above mean sea level in mm * 10^-1 - int8_t highResLatitudeHp; // High precision component of latitude: Degrees * 10^-9 - int8_t highResLongitudeHp; // High precision component of longitude: Degrees * 10^-9 - - uint16_t rtcmFrameCounter = 0; //Tracks the type of incoming byte inside RTCM frame - -#define DEF_NUM_SENS 7 - struct deadReckData - { - uint8_t version; - uint8_t fusionMode; - - uint8_t xAngRateVald; - uint8_t yAngRateVald; - uint8_t zAngRateVald; - uint8_t xAccelVald; - uint8_t yAccelVald; - uint8_t zAccelVald; - - int32_t xAngRate; - int32_t yAngRate; - int32_t zAngRate; - - int32_t xAccel; - int32_t yAccel; - int32_t zAccel; - - // The array size is based on testing directly on M8U and F9R - uint32_t rawData; - uint32_t rawDataType; - uint32_t rawTStamp; - - uint32_t data[DEF_NUM_SENS]; - uint32_t dataType[DEF_NUM_SENS]; - uint32_t dataTStamp[DEF_NUM_SENS]; - } imuMeas; - - struct indivImuData - { - - uint8_t numSens; - - uint8_t senType; - boolean isUsed; - boolean isReady; - uint8_t calibStatus; - uint8_t timeStatus; - - uint8_t freq; // Hz - - boolean badMeas; - boolean badTag; - boolean missMeas; - boolean noisyMeas; - } ubloxSen; - - struct vehicleAttitude - { - // All values in degrees - int32_t roll; - int32_t pitch; - int32_t heading; - uint32_t accRoll; - uint32_t accPitch; - uint32_t accHeading; - } vehAtt; - -private: - //Depending on the sentence type the processor will load characters into different arrays - enum SentenceTypes - { - NONE = 0, - NMEA, - UBX, - RTCM - } currentSentence = NONE; - - //Depending on the ubx binary response class, store binary responses into different places - enum classTypes - { - CLASS_NONE = 0, - CLASS_ACK, - CLASS_NOT_AN_ACK - } ubxFrameClass = CLASS_NONE; - - enum commTypes - { - COMM_TYPE_I2C = 0, - COMM_TYPE_SERIAL, - COMM_TYPE_SPI - } commType = COMM_TYPE_I2C; //Controls which port we look to for incoming bytes - - //Functions - boolean checkUbloxInternal(ubxPacket *incomingUBX, uint8_t requestedClass = 255, uint8_t requestedID = 255); //Checks module with user selected commType - uint32_t extractLong(uint8_t spotToStart); //Combine four bytes from payload into long - uint16_t extractInt(uint8_t spotToStart); //Combine two bytes from payload into int - uint8_t extractByte(uint8_t spotToStart); //Get byte from payload - int8_t extractSignedChar(uint8_t spotToStart); //Get signed 8-bit value from payload - void addToChecksum(uint8_t incoming); //Given an incoming byte, adjust rollingChecksumA/B - - //Variables - TwoWire *_i2cPort; //The generic connection to user's chosen I2C hardware - Stream *_serialPort; //The generic connection to user's chosen Serial hardware - 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 - - 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 - - boolean _printDebug = false; //Flag to print the serial commands we are sending to the Serial port for debug - boolean _printLimitedDebug = false; //Flag to print limited debug messages. Useful for I2C debugging or high navigation rates - - //The packet buffers - //These are pointed at from within the ubxPacket - uint8_t payloadAck[2]; // Holds the requested ACK/NACK - uint8_t payloadCfg[MAX_PAYLOAD_SIZE]; // Holds the requested data packet - uint8_t payloadBuf[2]; // Temporary buffer used to screen incoming packets or dump unrequested packets - - //Init the packet structures and init them with pointers to the payloadAck, payloadCfg and payloadBuf arrays - ubxPacket packetAck = {0, 0, 0, 0, 0, payloadAck, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; - ubxPacket packetCfg = {0, 0, 0, 0, 0, payloadCfg, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; - ubxPacket packetBuf = {0, 0, 0, 0, 0, payloadBuf, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; - - //Flag if this packet is unrequested (and so should be ignored and not copied into packetCfg or packetAck) - boolean ignoreThisPayload = false; - - //Identify which buffer is in use - //Data is stored in packetBuf until the requested class and ID can be validated - //If a match is seen, data is diverted into packetAck or packetCfg - sfe_ublox_packet_buffer_e activePacketBuffer = SFE_UBLOX_PACKET_PACKETBUF; - - //Limit checking of new data to every X ms - //If we are expecting an update every X Hz then we should check every half that amount of time - //Otherwise we may block ourselves from seeing new data - uint8_t i2cPollingWait = 100; //Default to 100ms. Adjusted when user calls setNavigationFrequency() - - unsigned long lastCheck = 0; - boolean autoPVT = false; //Whether autoPVT is enabled or not - boolean autoPVTImplicitUpdate = true; // Whether autoPVT is triggered by accessing stale data (=true) or by a call to checkUblox (=false) - uint16_t ubxFrameCounter; //It counts all UBX frame. [Fixed header(2bytes), CLS(1byte), ID(1byte), length(2bytes), payload(x bytes), checksums(2bytes)] - - uint8_t rollingChecksumA; //Rolls forward as we receive incoming bytes. Checked against the last two A/B checksum bytes - uint8_t rollingChecksumB; //Rolls forward as we receive incoming bytes. Checked against the last two A/B checksum bytes - - //Create bit field for staleness of each datum in PVT we want to monitor - //moduleQueried.latitude goes true each time we call getPVT() - //This reduces the number of times we have to call getPVT as this can take up to ~1s per read - //depending on update rate - struct - { - uint32_t gpsiTOW : 1; - uint32_t gpsYear : 1; - uint32_t gpsMonth : 1; - uint32_t gpsDay : 1; - uint32_t gpsHour : 1; - uint32_t gpsMinute : 1; - uint32_t gpsSecond : 1; - uint32_t gpsNanosecond : 1; - - uint32_t all : 1; - uint32_t longitude : 1; - uint32_t latitude : 1; - uint32_t altitude : 1; - uint32_t altitudeMSL : 1; - uint32_t SIV : 1; - uint32_t fixType : 1; - uint32_t carrierSolution : 1; - uint32_t groundSpeed : 1; - uint32_t headingOfMotion : 1; - uint32_t pDOP : 1; - uint32_t versionNumber : 1; - } moduleQueried; - - struct - { - uint16_t all : 1; - uint16_t timeOfWeek : 1; - uint16_t highResLatitude : 1; - uint16_t highResLongitude : 1; - uint16_t elipsoid : 1; - uint16_t meanSeaLevel : 1; - uint16_t geoidSeparation : 1; // Redundant but kept for backward-compatibility - uint16_t horizontalAccuracy : 1; - uint16_t verticalAccuracy : 1; - uint16_t elipsoidHp : 1; - uint16_t meanSeaLevelHp : 1; - uint16_t highResLatitudeHp : 1; - uint16_t highResLongitudeHp : 1; - } highResModuleQueried; - - uint16_t rtcmLen = 0; -}; - -#endif diff --git a/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/CMakeLists.txt b/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/CMakeLists.txt deleted file mode 100644 index 3dd6c0a..0000000 --- a/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -cmake_minimum_required(VERSION 3.13.1) - -find_package(Zephyr HINTS $ENV{ZEPHYR_BASE}) -project(sparkfun_ublox_zephyr_library) - -zephyr_compile_options(-fdiagnostics-color=always) - -zephyr_include_directories(.) -target_sources(app PRIVATE src/SparkFun_Ublox_Zephyr_Library.cpp) -target_sources(app PRIVATE src/SparkFun_Ublox_Zephyr_Interface.cpp) - -target_sources(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c) diff --git a/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/nrf52840dk_nrf52840.overlay b/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/nrf52840dk_nrf52840.overlay deleted file mode 100644 index 3c95572..0000000 --- a/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/nrf52840dk_nrf52840.overlay +++ /dev/null @@ -1,4 +0,0 @@ -&i2c0 { - status = "okay"; - compatible = "nordic,nrf-twim"; -}; \ No newline at end of file diff --git a/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/prj.conf b/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/prj.conf deleted file mode 100644 index e239329..0000000 --- a/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/prj.conf +++ /dev/null @@ -1,7 +0,0 @@ -#turn on c++ support -CONFIG_CPLUSPLUS=y - -# turn on peripherals -CONFIG_GPIO=y -CONFIG_I2C=y -CONFIG_I2C_0=y diff --git a/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/src/SparkFun_Ublox_Zephyr_Interface.cpp b/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/src/SparkFun_Ublox_Zephyr_Interface.cpp deleted file mode 100644 index ea96afe..0000000 --- a/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/src/SparkFun_Ublox_Zephyr_Interface.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - This is an interface that connects the CPP u-blox library with the main C code. - Added to make it possible to run u-blox lib on Zephyr (NCS) - - This port was made by Vid Rajtmajer , www.irnas.eu -*/ -#include "SparkFun_Ublox_Zephyr_Interface.h" - -#include -#include -#include -#include - -#include "SparkFun_Ublox_Zephyr_Library.h" - - -SFE_UBLOX_GPS myGPS; // driver class instance -long lastTime = 0; // Simple local timer. Limits amount if I2C traffic to u-blox module. - -// init GPIO checksumFailurePin and load GPIO device pointer to the driver -uint8_t set_gpio_dev(struct device *gpio_dev, uint8_t enable_debug) -{ - if (myGPS.init_gpio_pins(*gpio_dev) == false) - { - return -EIO; - } - // turn on debugging if enable_debug is set - if (enable_debug) - { - myGPS.enableDebugging(); - } - return 0; -} - -// initialize I2C and check if GPS device respons -uint8_t gps_begin(struct device *i2c_dev) -{ - if (myGPS.begin(*i2c_dev) == false) - { - return -EIO; - } - return 0; -} - -// This will pipe all NMEA sentences to UART so we can see them -void pipe_nmea_sentences(void) -{ - myGPS.setNMEAOutputPort(); -} - -// Check for available bytes from the device -void check_ublox(void) -{ - myGPS.checkUblox(); -} - -// Get position information when requested, also display number of satellites used in the fix -int get_position(void) -{ - //Query module only every second. Doing it more often will just cause I2C traffic. - //The module only responds when a new position is available, print it to console - if (k_uptime_get_32() - lastTime > 1000) - { - lastTime = k_uptime_get_32(); //Update the timer - - long latitude = myGPS.getLatitude(); - long longitude = myGPS.getLongitude(); - long altitude = myGPS.getAltitude(); - uint8_t SIV = myGPS.getSIV(); - - printk("Position: Lat: %ld, Lon: %ld, Alt: %ld, SIV: %d", latitude, longitude, altitude, SIV); - return 0; - } - return -EBUSY; -} - -// Get date and time information when requested, check if they are valid and print info to console, it returns UNIX time -void get_datetime(void) -{ - int year = myGPS.getYear(); - int month = myGPS.getMonth(); - int day = myGPS.getDay(); - int hour = myGPS.getHour(); - int minute = myGPS.getMinute(); - int second = myGPS.getSecond(); - - printk("DateTime: %d-%d-%d %d:%d:%d\n", year, month, day, hour, minute, second); - - printk("Time is "); - if (myGPS.getTimeValid() == false) - { - printk("not "); - } - printk("valid. Date is "); - if (myGPS.getDateValid() == false) - { - printk("not "); - } - printk("valid.\n"); -} diff --git a/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/src/SparkFun_Ublox_Zephyr_Interface.h b/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/src/SparkFun_Ublox_Zephyr_Interface.h deleted file mode 100644 index a4e23e4..0000000 --- a/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/src/SparkFun_Ublox_Zephyr_Interface.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - This is an interface that connects the CPP u-blox library with the main C code. - Added to make it possible to run u-blox lib on Zephyr (NCS) - - This port was made by Vid Rajtmajer , www.irnas.eu -*/ -#include -#include - -#ifndef _UBLOX_LIB_INTERFACE_H_ -#define _UBLOX_LIB_INTERFACE_H_ - -#ifdef __cplusplus -extern "C" { -#endif - - uint8_t set_gpio_dev(struct device *gpio_dev, uint8_t enable_debug); // init GPIO - uint8_t gps_begin(struct device *i2c_dev); // initialize I2C and check if GPS device respons - void pipe_nmea_sentences(void); // print NMEA sentences - - void check_ublox(void); // Check for available bytes from the device - int get_position(void); // Get position information - void get_datetime(void); // Get date and time information - -#ifdef __cplusplus -} -#endif - -#endif //UBLOX_LIB_INTERFACE_H_ \ No newline at end of file diff --git a/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/src/SparkFun_Ublox_Zephyr_Library.cpp b/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/src/SparkFun_Ublox_Zephyr_Library.cpp deleted file mode 100644 index 0e77979..0000000 --- a/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/src/SparkFun_Ublox_Zephyr_Library.cpp +++ /dev/null @@ -1,3492 +0,0 @@ -/* - This is a library written for the u-blox ZED-F9P and NEO-M8P-2 - SparkFun sells these at its website: www.sparkfun.com - Do you like this library? Help support SparkFun. Buy a board! - https://www.sparkfun.com/products/15136 - https://www.sparkfun.com/products/15005 - https://www.sparkfun.com/products/15733 - https://www.sparkfun.com/products/15193 - https://www.sparkfun.com/products/15210 - - Written by Nathan Seidle @ SparkFun Electronics, September 6th, 2018 - - This library handles configuring and handling the responses - from a u-blox GPS module. Works with most modules from u-blox including - the Zed-F9P, NEO-M8P-2, NEO-M9N, ZOE-M8Q, SAM-M8Q, and many others. - - https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library - - Development environment specifics: - NCS v1.0.3 release - this port - - This port was made by Vid Rajtmajer , www.irnas.eu - - SparkFun code, firmware, and software is released under the MIT License(http://opensource.org/licenses/MIT). - The MIT License (MIT) - Copyright (c) 2016 SparkFun Electronics - Permission is hereby granted, free of charge, to any person obtaining a copy of this software and - associated documentation files (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the Software is furnished to - do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or substantial - portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include "SparkFun_Ublox_Zephyr_Library.h" -#include - -SFE_UBLOX_GPS::SFE_UBLOX_GPS(void) -{ - // Constructor - currentGeofenceParams.numFences = 0; // Zero the number of geofences currently in use - moduleQueried.versionNumber = false; -} - -// Get i2c device to the class and configure checksumFailurePin -bool SFE_UBLOX_GPS::init_gpio_pins(struct device &gpio_dev) -{ - _gpio_dev = &gpio_dev; - if (checksumFailurePin >= 0) - { - int err; - err = gpio_pin_configure(_gpio_dev, (uint8_t)checksumFailurePin, GPIO_OUTPUT); - err = gpio_pin_set(_gpio_dev, (uint8_t)checksumFailurePin, HIGH); - if (err) - { - return false; - } - } - return true; -} - -//Initialize the I2C port -bool SFE_UBLOX_GPS::begin(struct device &i2c_dev, uint8_t deviceAddress) -{ - commType = COMM_TYPE_I2C; - _i2cPort = &i2c_dev; //Grab which port the user wants us to use - - //We expect caller to begin their I2C port, with the speed of their choice external to the library - //But if they forget, we start the hardware here. - - //We're moving away from the practice of starting Wire hardware in a library. This is to avoid cross platform issues. - //ie, there are some platforms that don't handle multiple starts to the wire hardware. Also, every time you start the wire - //hardware the clock speed reverts back to 100kHz regardless of previous Wire.setClocks(). - //_i2cPort->begin(); - - _gpsI2Caddress = deviceAddress; //Store the I2C address from user - - return (isConnected()); -} - -//Initialize the Serial port - function not ported -/* -bool SFE_UBLOX_GPS::begin(Stream &serialPort) -{ - commType = COMM_TYPE_SERIAL; - _serialPort = &serialPort; //Grab which port the user wants us to use - - return (isConnected()); -} -*/ - -//Enable or disable the printing of sent/response HEX values. -//Use this in conjunction with 'Transport Logging' from the Universal Reader Assistant to see what they're doing that we're not -void SFE_UBLOX_GPS::enableDebugging(bool printLimitedDebug) -{ - if (printLimitedDebug == false) - { - _printDebug = true; //Should we print the commands we send? Good for debugging - } - else - { - _printLimitedDebug = true; //Should we print limited debug messages? Good for debugging high navigation rates - } -} - -void SFE_UBLOX_GPS::disableDebugging(void) -{ - _printDebug = false; //Turn off extra print statements - _printLimitedDebug = false; -} - -//Safely print messages -void SFE_UBLOX_GPS::debugPrint(char *message) -{ - if (_printDebug == true) - { - printk("%s", message); - } -} -//Safely print messages -void SFE_UBLOX_GPS::debugPrintln(char *message) -{ - if (_printDebug == true) - { - printk("%s\n", message); - } -} - -const char *SFE_UBLOX_GPS::statusString(sfe_ublox_status_e stat) -{ - switch (stat) - { - case SFE_UBLOX_STATUS_SUCCESS: - return "Success"; - break; - case SFE_UBLOX_STATUS_FAIL: - return "General Failure"; - break; - case SFE_UBLOX_STATUS_CRC_FAIL: - return "CRC Fail"; - break; - case SFE_UBLOX_STATUS_TIMEOUT: - return "Timeout"; - break; - case SFE_UBLOX_STATUS_COMMAND_NACK: - return "Command not acknowledged (NACK)"; - break; - case SFE_UBLOX_STATUS_OUT_OF_RANGE: - return "Out of range"; - break; - case SFE_UBLOX_STATUS_INVALID_ARG: - return "Invalid Arg"; - break; - case SFE_UBLOX_STATUS_INVALID_OPERATION: - return "Invalid operation"; - break; - case SFE_UBLOX_STATUS_MEM_ERR: - return "Memory Error"; - break; - case SFE_UBLOX_STATUS_HW_ERR: - return "Hardware Error"; - break; - case SFE_UBLOX_STATUS_DATA_SENT: - return "Data Sent"; - break; - case SFE_UBLOX_STATUS_DATA_RECEIVED: - return "Data Received"; - break; - case SFE_UBLOX_STATUS_I2C_COMM_FAILURE: - return "I2C Comm Failure"; - break; - case SFE_UBLOX_STATUS_DATA_OVERWRITTEN: - return "Data Packet Overwritten"; - break; - default: - return "Unknown Status"; - break; - } - return "None"; -} - -void SFE_UBLOX_GPS::factoryReset() -{ - // Copy default settings to permanent - // Note: this does not load the permanent configuration into the current configuration. Calling factoryDefault() will do that. - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_CFG; - packetCfg.len = 13; - packetCfg.startingSpot = 0; - for (uint8_t i = 0; i < 4; i++) - { - 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[12] = 0xff; // all forms of permanent memory - sendCommand(&packetCfg, 0); // don't expect ACK - hardReset(); // cause factory default config to actually be loaded and used cleanly -} - -void SFE_UBLOX_GPS::hardReset() -{ - // Issue hard reset - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_RST; - packetCfg.len = 4; - packetCfg.startingSpot = 0; - payloadCfg[0] = 0xff; // cold start - payloadCfg[1] = 0xff; // cold start - payloadCfg[2] = 0; // 0=HW reset - payloadCfg[3] = 0; // reserved - sendCommand(&packetCfg, 0); // don't expect ACK -} - -// Write data to I2C, Arguments: buffer - data to write, num_bytes - buffer length, -// stop - if true send STOP, if false send RESTART after message -int SFE_UBLOX_GPS::transferWriteI2C(u8_t *buffer, u32_t num_bytes, bool stop) -{ - struct i2c_msg msgs[1]; - // Data to be written and STOP or RESTART after this. - msgs[0].buf = buffer; - msgs[0].len = num_bytes; - if (stop) { - msgs[0].flags = I2C_MSG_WRITE | I2C_MSG_STOP; - } - else { - msgs[0].flags = I2C_MSG_WRITE | I2C_MSG_RESTART; - } - return i2c_transfer(_i2cPort, &msgs[0], 1, _gpsI2Caddress); -} - -// Read data from I2C, Arguments: buffer - store read data, num_bytes - buffer length -int SFE_UBLOX_GPS::transferReadI2C(u8_t *buffer, u32_t num_bytes) -{ - struct i2c_msg msgs[1]; - // Data to be read and STOP after this - msgs[0].buf = buffer; - msgs[0].len = num_bytes; - msgs[0].flags = I2C_MSG_READ | I2C_MSG_STOP; - - int err = i2c_transfer(_i2cPort, &msgs[0], 1, _gpsI2Caddress); - return err; -} - -//Changes the serial baud rate of the u-blox module, can't return success/fail 'cause ACK from modem -//is lost due to baud rate change -void SFE_UBLOX_GPS::setSerialRate(uint32_t baudrate, uint8_t uartPort, uint16_t maxWait) -{ - //Get the current config values for the UART port - getPortSettings(uartPort, maxWait); //This will load the payloadCfg array with current port settings - - if (_printDebug == true) - { - printk("Current baud rate: "); - printk("%d\n", ((uint32_t)payloadCfg[10] << 16) | ((uint32_t)payloadCfg[9] << 8) | payloadCfg[8]); - } - - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_PRT; - packetCfg.len = 20; - packetCfg.startingSpot = 0; - - //payloadCfg is now loaded with current bytes. Change only the ones we need to - payloadCfg[8] = baudrate; - payloadCfg[9] = baudrate >> 8; - payloadCfg[10] = baudrate >> 16; - payloadCfg[11] = baudrate >> 24; - - if (_printDebug == true) - { - printk("New baud rate: "); - printk("%d\n", ((uint32_t)payloadCfg[10] << 16) | ((uint32_t)payloadCfg[9] << 8) | payloadCfg[8]); - } - - sfe_ublox_status_e retVal = sendCommand(&packetCfg, maxWait); - if (_printDebug == true) - { - printk("setSerialRate: sendCommand returned: %s\n", statusString(retVal)); - } -} - -//Changes the I2C address that the u-blox module responds to -//0x42 is the default but can be changed with this command -bool SFE_UBLOX_GPS::setI2CAddress(uint8_t deviceAddress, uint16_t maxWait) -{ - //Get the current config values for the I2C port - getPortSettings(COM_PORT_I2C, maxWait); //This will load the payloadCfg array with current port settings - - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_PRT; - packetCfg.len = 20; - packetCfg.startingSpot = 0; - - //payloadCfg is now loaded with current bytes. Change only the ones we need to - payloadCfg[4] = deviceAddress << 1; //DDC mode LSB - - if (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT) // We are only expecting an ACK - { - //Success! Now change our internal global. - _gpsI2Caddress = deviceAddress; //Store the I2C address from user - return (true); - } - return (false); -} - -//Want to see the NMEA messages on the Serial port? Here's how - ported to print to console, here only enable the flag -void SFE_UBLOX_GPS::setNMEAOutputPort() -{ - _nmeaOutputPort = true; -} - -//Called regularly to check for available bytes on the user' specified port -bool SFE_UBLOX_GPS::checkUblox(uint8_t requestedClass, uint8_t requestedID) -{ - return checkUbloxInternal(&packetCfg, requestedClass, requestedID); -} - -//Called regularly to check for available bytes on the user' specified port -bool SFE_UBLOX_GPS::checkUbloxInternal(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) -{ - if (commType == COMM_TYPE_I2C) - return (checkUbloxI2C(incomingUBX, requestedClass, requestedID)); - else if (commType == COMM_TYPE_SERIAL) - return (checkUbloxSerial(incomingUBX, requestedClass, requestedID)); - return false; -} - -//Polls I2C for data, passing any new bytes to process() -//Returns true if new bytes are available -bool SFE_UBLOX_GPS::checkUbloxI2C(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) -{ - if (k_uptime_get_32() - lastCheck >= i2cPollingWait) - { - uint16_t bytesAvailable = 0; - int err; - - //Get the number of bytes available from the module - //0xFD (MSB) and 0xFE (LSB) are the registers that contain number of bytes available - u8_t data_buffer[1]; - data_buffer[0] = 0xFD; - err = transferWriteI2C(data_buffer, 1, true); - if (err) { - return (false); - } - - bool data_read_ok = true; - u8_t read_buffer[2]; - err = transferReadI2C(data_buffer, 2); - if (err) { - data_read_ok = false; - } - - if (data_read_ok) - { - uint8_t msb = read_buffer[0]; - uint8_t lsb = read_buffer[1]; - if (lsb == 0xFF) - { - //I believe this is a u-blox bug. Device should never present an 0xFF. - if ((_printDebug == true) || (_printLimitedDebug == true)) // Print this if doing limited debugging - { - printk("checkUbloxI2C: u-blox bug, length lsb is 0xFF\n"); - } - if (checksumFailurePin >= 0) - { - gpio_pin_set(_gpio_dev, (uint8_t)checksumFailurePin, LOW); - k_msleep(10); - gpio_pin_set(_gpio_dev, (uint8_t)checksumFailurePin, HIGH); - } - lastCheck = k_uptime_get_32(); //Put off checking to avoid I2C bus traffic - return (false); - } - bytesAvailable = (uint16_t)msb << 8 | lsb; - } - - if (bytesAvailable == 0) - { - if (_printDebug == true) - { - printk("checkUbloxI2C: OK, zero bytes available\n"); - } - lastCheck = k_uptime_get_32(); //Put off checking to avoid I2C bus traffic - return (false); - } - - //Check for undocumented bit error. We found this doing logic scans. - //This error is rare but if we incorrectly interpret the first bit of the two 'data available' bytes as 1 - //then we have far too many bytes to check. May be related to I2C setup time violations: https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/issues/40 - if (bytesAvailable & ((uint16_t)1 << 15)) - { - //Clear the MSbit - bytesAvailable &= ~((uint16_t)1 << 15); - - if ((_printDebug == true) || (_printLimitedDebug == true)) // Print this if doing limited debugging - { - printk("checkUbloxI2C: Bytes available error: %d\n", bytesAvailable); - if (checksumFailurePin >= 0) - { - gpio_pin_set(_gpio_dev, (uint8_t)checksumFailurePin, LOW); - k_msleep(10); - gpio_pin_set(_gpio_dev, (uint8_t)checksumFailurePin, HIGH); - } - } - } - - if (bytesAvailable > 100) - { - if (_printDebug == true) - { - printk("checkUbloxI2C: Large packet of %d bytes received\n", bytesAvailable); - } - } - else - { - if (_printDebug == true) - { - printk("checkUbloxI2C: Reading %d bytes\n", bytesAvailable); - } - } - - while (bytesAvailable) - { - u8_t data_buffer[1]; - data_buffer[0] = 0xFF; //0xFF is the register to read data from - err = transferWriteI2C(data_buffer, 1, false); //Send a restart command. Do not release bus. - if (err) { - return (false); - } - - //Limit to 32 bytes or whatever the buffer limit is for given platform - uint16_t bytesToRead = bytesAvailable; - if (bytesToRead > I2C_BUFFER_LENGTH) - bytesToRead = I2C_BUFFER_LENGTH; - - TRY_AGAIN: - bool data_read_ok = true; - u8_t read_buffer[(uint8_t)bytesToRead]; - err = transferReadI2C(read_buffer, (uint8_t)bytesToRead); - if (err) { - data_read_ok = false; - } - - if (data_read_ok) - { - for (uint16_t x = 0; x < bytesToRead; x++) - { - uint8_t incoming = read_buffer[x]; //Grab the actual character - - //Check to see if the first read is 0x7F. If it is, the module is not ready - //to respond. Stop, wait, and try again - if (x == 0) - { - if (incoming == 0x7F) - { - if ((_printDebug == true) || (_printLimitedDebug == true)) // Print this if doing limited debugging - { - printk("checkUbloxU2C: u-blox error, module not ready with data\n"); - } - k_msleep(5); //In logic analyzation, the module starting responding after 1.48ms - if (checksumFailurePin >= 0) - { - gpio_pin_set(_gpio_dev, (uint8_t)checksumFailurePin, LOW); - k_msleep(10); - gpio_pin_set(_gpio_dev, (uint8_t)checksumFailurePin, HIGH); - } - goto TRY_AGAIN; - } - } - process(incoming, incomingUBX, requestedClass, requestedID); //Process this valid character - } - } - else - return (false); //Sensor did not respond - - bytesAvailable -= bytesToRead; - } - } - - return (true); - -} //end checkUbloxI2C() - -//Checks Serial for data, passing any new bytes to process() -bool SFE_UBLOX_GPS::checkUbloxSerial(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) -{ - printk("checkUbloxSerial function not ported...\n"); - /* - while (_serialPort->available()) - { - process(_serialPort->read(), incomingUBX, requestedClass, requestedID); - } - */ - return (true); - -} //end checkUbloxSerial() - -//Processes NMEA and UBX binary sentences one byte at a time -//Take a given byte and file it into the proper array -void SFE_UBLOX_GPS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) -{ - if ((currentSentence == NONE) || (currentSentence == NMEA)) - { - if (incoming == 0xB5) //UBX binary frames start with 0xB5, aka μ - { - //This is the start of a binary sentence. Reset flags. - //We still don't know the response class - ubxFrameCounter = 0; - currentSentence = UBX; - //Reset the packetBuf.counter even though we will need to reset it again when ubxFrameCounter == 2 - packetBuf.counter = 0; - 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; - } - else if (incoming == '$') - { - currentSentence = NMEA; - } - else if (incoming == 0xD3) //RTCM frames start with 0xD3 - { - rtcmFrameCounter = 0; - currentSentence = RTCM; - } - else - { - //This character is unknown or we missed the previous start of a sentence - } - } - - //Depending on the sentence, pass the character to the individual processor - if (currentSentence == UBX) - { - //Decide what type of response this is - if ((ubxFrameCounter == 0) && (incoming != 0xB5)) //ISO 'μ' - currentSentence = NONE; //Something went wrong. Reset. - else if ((ubxFrameCounter == 1) && (incoming != 0x62)) //ASCII 'b' - currentSentence = NONE; //Something went wrong. Reset. - // Note to future self: - // There may be some duplication / redundancy in the next few lines as processUBX will also - // load information into packetBuf, but we'll do it here too for clarity - else if (ubxFrameCounter == 2) //Class - { - // Record the class in packetBuf until we know what to do with it - packetBuf.cls = incoming; // (Duplication) - rollingChecksumA = 0; //Reset our rolling checksums here (not when we receive the 0xB5) - rollingChecksumB = 0; - packetBuf.counter = 0; //Reset the packetBuf.counter (again) - packetBuf.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; // Reset the packet validity (redundant?) - packetBuf.startingSpot = incomingUBX->startingSpot; //Copy the startingSpot - } - else if (ubxFrameCounter == 3) //ID - { - // Record the ID in packetBuf until we know what to do with it - packetBuf.id = incoming; // (Duplication) - //We can now identify the type of response - //If the packet we are receiving is not an ACK then check for a class and ID match - 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)) - { - //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 - } - else - { - //This is not an ACK and we do not have a class and ID match - //so we should keep diverting data into packetBuf and ignore the payload - ignoreThisPayload = true; - } - } - else - { - // This is an ACK so it is to early to do anything with it - // We need to wait until we have received the length and data bytes - // So we should keep diverting data into packetBuf - } - } - else if (ubxFrameCounter == 4) //Length LSB - { - //We should save the length in packetBuf even if activePacketBuffer == SFE_UBLOX_PACKET_PACKETCFG - packetBuf.len = incoming; // (Duplication) - } - else if (ubxFrameCounter == 5) //Length MSB - { - //We should save the length in packetBuf even if activePacketBuffer == SFE_UBLOX_PACKET_PACKETCFG - packetBuf.len |= incoming << 8; // (Duplication) - } - else if (ubxFrameCounter == 6) //This should be the first byte of the payload unless .len is zero - { - if (packetBuf.len == 0) // Check if length is zero (hopefully this is impossible!) - { - if (_printDebug == true) - { - printk("process: ZERO LENGTH packet received: Class: 0x%x ID: 0x%x\n", packetBuf.cls, packetBuf.id); - } - //If length is zero (!) this will be the first byte of the checksum so record it - packetBuf.checksumA = incoming; - } - else - { - //The length is not zero so record this byte in the payload - packetBuf.payload[0] = incoming; - } - } - else if (ubxFrameCounter == 7) //This should be the second byte of the payload unless .len is zero or one - { - if (packetBuf.len == 0) // Check if length is zero (hopefully this is impossible!) - { - //If length is zero (!) this will be the second byte of the checksum so record it - packetBuf.checksumB = incoming; - } - else if (packetBuf.len == 1) // Check if length is one - { - //The length is one so this is the first byte of the checksum - packetBuf.checksumA = incoming; - } - else // Length is >= 2 so this must be a payload byte - { - packetBuf.payload[1] = incoming; - } - // Now that we have received two payload bytes, we can check for a matching ACK/NACK - if ((activePacketBuffer == SFE_UBLOX_PACKET_PACKETBUF) // If we are not already processing a data packet - && (packetBuf.cls == UBX_CLASS_ACK) // and if this is an ACK/NACK - && (packetBuf.payload[0] == requestedClass) // and if the class matches - && (packetBuf.payload[1] == requestedID)) // and if the ID matches - { - if (packetBuf.len == 2) // Check if .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) - { - printk("process: ACK received with .len != 2: Class: 0x%x ID: 0x%x, len: %d\n", packetBuf.payload[0], packetBuf.payload[1], 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); - - //Finally, increment the frame counter - ubxFrameCounter++; - } - else if (currentSentence == NMEA) - { - processNMEA(incoming); //Process each NMEA character - } - else if (currentSentence == RTCM) - { - processRTCMframe(incoming); //Deal with RTCM bytes - } -} - -//This is the default or generic NMEA processor. We're only going to pipe the data to serial port so we can see it. -//User could overwrite this function to pipe characters to nmea.process(c) of tinyGPS or MicroNMEA -//Or user could pipe each character to a buffer, radio, etc. -void SFE_UBLOX_GPS::processNMEA(char incoming) -{ - //If user has assigned an output port then pipe the characters there - - if (_nmeaOutputPort) - printk("%c", incoming); //Echo this byte to the serial port -} - -//We need to be able to identify an RTCM packet and then the length -//so that we know when the RTCM message is completely received and we then start -//listening for other sentences (like NMEA or UBX) -//RTCM packet structure is very odd. I never found RTCM STANDARD 10403.2 but -//http://d1.amobbs.com/bbs_upload782111/files_39/ourdev_635123CK0HJT.pdf is good -//https://dspace.cvut.cz/bitstream/handle/10467/65205/F3-BP-2016-Shkalikava-Anastasiya-Prenos%20polohove%20informace%20prostrednictvim%20datove%20site.pdf?sequence=-1 -//Lead me to: https://forum.u-blox.com/index.php/4348/how-to-read-rtcm-messages-from-neo-m8p -//RTCM 3.2 bytes look like this: -//Byte 0: Always 0xD3 -//Byte 1: 6-bits of zero -//Byte 2: 10-bits of length of this packet including the first two-ish header bytes, + 6. -//byte 3 + 4 bits: Msg type 12 bits -//Example: D3 00 7C 43 F0 ... / 0x7C = 124+6 = 130 bytes in this packet, 0x43F = Msg type 1087 -void SFE_UBLOX_GPS::processRTCMframe(uint8_t incoming) -{ - if (rtcmFrameCounter == 1) - { - rtcmLen = (incoming & 0x03) << 8; //Get the last two bits of this byte. Bits 8&9 of 10-bit length - } - else if (rtcmFrameCounter == 2) - { - rtcmLen |= incoming; //Bits 0-7 of packet length - rtcmLen += 6; //There are 6 additional bytes of what we presume is header, msgType, CRC, and stuff - } - /*else if (rtcmFrameCounter == 3) - { - rtcmMsgType = incoming << 4; //Message Type, MS 4 bits - } - else if (rtcmFrameCounter == 4) - { - rtcmMsgType |= (incoming >> 4); //Message Type, bits 0-7 - }*/ - - rtcmFrameCounter++; - - processRTCM(incoming); //Here is where we expose this byte to the user - - if (rtcmFrameCounter == rtcmLen) - { - //We're done! - currentSentence = NONE; //Reset and start looking for next sentence type - } -} - -//This function is called for each byte of an RTCM frame -//Ths user can overwrite this function and process the RTCM frame as they please -//Bytes can be piped to Serial or other interface. The consumer could be a radio or the internet (Ntrip broadcaster) -void SFE_UBLOX_GPS::processRTCM(uint8_t incoming) -{ - //Radio.sendReliable((String)incoming); //An example of passing this byte to a radio - - //Debug printing - // printk(" "); - // if(incoming < 0x10) printk("0"); - // if(incoming < 0x10) printk("0"); - // printk("%d", incoming); - // if(rtcmFrameCounter % 16 == 0) printk("\n"); -} - -//Given a character, file it away into the uxb packet structure -//Set valid to VALID or NOT_VALID once sentence is completely received and passes or fails CRC -//The payload portion of the packet can be 100s of bytes but the max array -//size is MAX_PAYLOAD_SIZE bytes. startingSpot can be set so we only record -//a subset of bytes within a larger packet. -void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) -{ - //Add all incoming bytes to the rolling checksum - //Stop at len+4 as this is the checksum bytes to that should not be added to the rolling checksum - if (incomingUBX->counter < incomingUBX->len + 4) - addToChecksum(incoming); - - if (incomingUBX->counter == 0) - { - incomingUBX->cls = incoming; - } - else if (incomingUBX->counter == 1) - { - incomingUBX->id = incoming; - } - else if (incomingUBX->counter == 2) //Len LSB - { - incomingUBX->len = incoming; - } - else if (incomingUBX->counter == 3) //Len MSB - { - incomingUBX->len |= incoming << 8; - } - else if (incomingUBX->counter == incomingUBX->len + 4) //ChecksumA - { - incomingUBX->checksumA = incoming; - } - else if (incomingUBX->counter == incomingUBX->len + 5) //ChecksumB - { - incomingUBX->checksumB = incoming; - - currentSentence = NONE; //We're done! Reset the sentence to being looking for a new start char - - //Validate this sentence - if ((incomingUBX->checksumA == rollingChecksumA) && (incomingUBX->checksumB == rollingChecksumB)) - { - incomingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_VALID; // Flag the packet as valid - - // Let's check if the class and ID match the requestedClass and requestedID - // Remember - this could be a data packet or an ACK packet - if ((incomingUBX->cls == requestedClass) && (incomingUBX->id == requestedID)) - { - incomingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_VALID; // If we have a match, set the classAndIDmatch flag to valid - } - - // If this is an ACK then let's check if the class and ID match the requestedClass and requestedID - else if ((incomingUBX->cls == UBX_CLASS_ACK) && (incomingUBX->id == UBX_ACK_ACK) && (incomingUBX->payload[0] == requestedClass) && (incomingUBX->payload[1] == requestedID)) - { - incomingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_VALID; // If we have a match, set the classAndIDmatch flag to valid - } - - // If this is a NACK then let's check if the class and ID match the requestedClass and requestedID - else if ((incomingUBX->cls == UBX_CLASS_ACK) && (incomingUBX->id == UBX_ACK_NACK) && (incomingUBX->payload[0] == requestedClass) && (incomingUBX->payload[1] == requestedID)) - { - incomingUBX->classAndIDmatch = SFE_UBLOX_PACKET_NOTACKNOWLEDGED; // If we have a match, set the classAndIDmatch flag to NOTACKNOWLEDGED - if (_printDebug == true) - { - printk("processUBX: NACK received: Requested Class: 0x%x, Requested ID: 0x%x\n", incomingUBX->payload[0], incomingUBX->payload[1]); - } - } - - if (_printDebug == true) - { - printk("Incoming: Size: %d Received: \n", incomingUBX->len); - printPacket(incomingUBX); - - if (incomingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_VALID) - { - printk("packetCfg now valid\n"); - } - if (packetAck.valid == SFE_UBLOX_PACKET_VALIDITY_VALID) - { - printk("packetAck now valid\n"); - } - if (incomingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) - { - printk("packetCfg classAndIDmatch\n"); - } - if (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) - { - printk("packetAck classAndIDmatch\n"); - } - } - - //We've got a valid packet, now do something with it but only if ignoreThisPayload is false - if (ignoreThisPayload == false) - { - processUBXpacket(incomingUBX); - } - } - else // Checksum failure - { - 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)) // Print this if doing limited debugging - { - //Drive an external pin to allow for easier logic analyzation - if (checksumFailurePin >= 0) - { - gpio_pin_set(_gpio_dev, (uint8_t)checksumFailurePin, LOW); - k_msleep(10); - gpio_pin_set(_gpio_dev, (uint8_t)checksumFailurePin, HIGH); - } - - printk("Checksum failed: checksumA: %d checksumB: %d\n", incomingUBX->checksumA, incomingUBX->checksumB); - printk("rollingChecksumA: %d, rollingChecksumB: %d\n", rollingChecksumA, rollingChecksumB); - printk("Failed: Size: %d Received: \n", incomingUBX->len); - printPacket(incomingUBX); - } - } - } - else //Load this byte into the payload array - { - //If a UBX_NAV_PVT packet comes in asynchronously, we need to fudge the startingSpot - uint16_t startingSpot = incomingUBX->startingSpot; - if (incomingUBX->cls == UBX_CLASS_NAV && incomingUBX->id == UBX_NAV_PVT) - startingSpot = 0; - //Begin recording if counter goes past startingSpot - if ((incomingUBX->counter - 4) >= startingSpot) - { - //Check to see if we have room for this byte - if (((incomingUBX->counter - 4) - startingSpot) < MAX_PAYLOAD_SIZE) //If counter = 208, starting spot = 200, we're good to record. - { - // Check if this is payload data which should be ignored - if (ignoreThisPayload == false) - { - incomingUBX->payload[incomingUBX->counter - 4 - startingSpot] = incoming; //Store this byte into payload array - } - } - } - } - - //Increment the counter - incomingUBX->counter++; - - if (incomingUBX->counter == MAX_PAYLOAD_SIZE) - { - //Something has gone very wrong - currentSentence = NONE; //Reset the sentence to being looking for a new start char - if (_printDebug == true) - { - printk("processUBX: counter hit MAX_PAYLOAD_SIZE\n"); - } - } -} - -//Once a packet has been received and validated, identify this packet's class/id and update internal flags -//Note: if the user requests a PVT or a HPPOSLLH message using a custom packet, the data extraction will -// not work as expected beacuse extractLong etc are hardwired to packetCfg payloadCfg. Ideally -// extractLong etc should be updated so they receive a pointer to the packet buffer. -void SFE_UBLOX_GPS::processUBXpacket(ubxPacket *msg) -{ - switch (msg->cls) - { - case UBX_CLASS_NAV: - if (msg->id == UBX_NAV_PVT && msg->len == 92) - { - //Parse various byte fields into global vars - constexpr int startingSpot = 0; //fixed value used in processUBX - - timeOfWeek = extractLong(0); - gpsMillisecond = extractLong(0) % 1000; //Get last three digits of iTOW - gpsYear = extractInt(4); - gpsMonth = extractByte(6); - gpsDay = extractByte(7); - gpsHour = extractByte(8); - gpsMinute = extractByte(9); - gpsSecond = extractByte(10); - gpsDateValid = extractByte(11) & 0x01; - gpsTimeValid = (extractByte(11) & 0x02) >> 1; - gpsNanosecond = extractLong(16); //Includes milliseconds - - fixType = extractByte(20 - startingSpot); - carrierSolution = extractByte(21 - startingSpot) >> 6; //Get 6th&7th bits of this byte - SIV = extractByte(23 - startingSpot); - longitude = extractLong(24 - startingSpot); - latitude = extractLong(28 - startingSpot); - altitude = extractLong(32 - startingSpot); - altitudeMSL = extractLong(36 - startingSpot); - groundSpeed = extractLong(60 - startingSpot); - headingOfMotion = extractLong(64 - startingSpot); - pDOP = extractInt(76 - startingSpot); - - //Mark all datums as fresh (not read before) - moduleQueried.gpsiTOW = true; - moduleQueried.gpsYear = true; - moduleQueried.gpsMonth = true; - moduleQueried.gpsDay = true; - moduleQueried.gpsHour = true; - moduleQueried.gpsMinute = true; - moduleQueried.gpsSecond = true; - moduleQueried.gpsDateValid = true; - moduleQueried.gpsTimeValid = true; - moduleQueried.gpsNanosecond = true; - - moduleQueried.all = true; - moduleQueried.longitude = true; - moduleQueried.latitude = true; - moduleQueried.altitude = true; - moduleQueried.altitudeMSL = true; - moduleQueried.SIV = true; - moduleQueried.fixType = true; - moduleQueried.carrierSolution = true; - moduleQueried.groundSpeed = true; - moduleQueried.headingOfMotion = true; - moduleQueried.pDOP = true; - } - else if (msg->id == UBX_NAV_HPPOSLLH && msg->len == 36) - { - timeOfWeek = extractLong(4); - highResLongitude = extractLong(8); - highResLatitude = extractLong(12); - elipsoid = extractLong(16); - meanSeaLevel = extractLong(20); - highResLongitudeHp = extractSignedChar(24); - highResLatitudeHp = extractSignedChar(25); - elipsoidHp = extractSignedChar(26); - meanSeaLevelHp = extractSignedChar(27); - horizontalAccuracy = extractLong(28); - verticalAccuracy = extractLong(32); - - highResModuleQueried.all = true; - highResModuleQueried.highResLatitude = true; - highResModuleQueried.highResLatitudeHp = true; - highResModuleQueried.highResLongitude = true; - highResModuleQueried.highResLongitudeHp = true; - highResModuleQueried.elipsoid = true; - highResModuleQueried.elipsoidHp = true; - highResModuleQueried.meanSeaLevel = true; - highResModuleQueried.meanSeaLevelHp = true; - highResModuleQueried.geoidSeparation = true; - highResModuleQueried.horizontalAccuracy = true; - highResModuleQueried.verticalAccuracy = true; - moduleQueried.gpsiTOW = true; // this can arrive via HPPOS too. - - if (_printDebug == true) - { - printk("Sec: %f", ((float)extractLong(4)) / 1000.0f); - printk("\n"); - printk("LON: %f", ((float)(int32_t)extractLong(8)) / 10000000.0f); - printk("\n"); - printk("LAT: %f", ((float)(int32_t)extractLong(12)) / 10000000.0f); - printk("\n"); - printk("ELI M: %f", ((float)(int32_t)extractLong(16)) / 1000.0f); - printk("\n"); - printk("MSL M: %f", ((float)(int32_t)extractLong(20)) / 1000.0f); - printk("\n"); - printk("LON HP: %c", extractSignedChar(24)); - printk("\n"); - printk("LAT HP: %c", extractSignedChar(25)); - printk("\n"); - printk("ELI HP: %calcChecksum", extractSignedChar(26)); - printk("\n"); - printk("MSL HP: %c", extractSignedChar(27)); - printk("\n"); - printk("HA 2D M: %f", ((float)(int32_t)extractLong(28)) / 10000.0f); - printk("\n"); - printk("VERT M: %f", ((float)(int32_t)extractLong(32)) / 10000.0f); - } - } - break; - } -} - -//Given a packet and payload, send everything including CRC bytes via I2C port -sfe_ublox_status_e SFE_UBLOX_GPS::sendCommand(ubxPacket *outgoingUBX, uint16_t maxWait) -{ - sfe_ublox_status_e retVal = SFE_UBLOX_STATUS_SUCCESS; - - calcChecksum(outgoingUBX); //Sets checksum A and B bytes of the packet - - if (_printDebug == true) - { - printk("\nSending: "); - printPacket(outgoingUBX); - } - - if (commType == COMM_TYPE_I2C) - { - retVal = sendI2cCommand(outgoingUBX, maxWait); - if (retVal != SFE_UBLOX_STATUS_SUCCESS) - { - if (_printDebug == true) - { - printk("Send I2C Command failed\n"); - } - return retVal; - } - } - else if (commType == COMM_TYPE_SERIAL) - { - sendSerialCommand(outgoingUBX); - } - - if (maxWait > 0) - { - //Depending on what we just sent, either we need to look for an ACK or not - if (outgoingUBX->cls == UBX_CLASS_CFG) - { - if (_printDebug == true) - { - printk("sendCommand: Waiting for ACK response\n"); - } - retVal = waitForACKResponse(outgoingUBX, outgoingUBX->cls, outgoingUBX->id, maxWait); //Wait for Ack response - } - else - { - if (_printDebug == true) - { - printk("sendCommand: Waiting for No ACK response\n"); - } - retVal = waitForNoACKResponse(outgoingUBX, outgoingUBX->cls, outgoingUBX->id, maxWait); //Wait for Ack response - } - } - return retVal; -} - -//Returns false if sensor fails to respond to I2C traffic -sfe_ublox_status_e SFE_UBLOX_GPS::sendI2cCommand(ubxPacket *outgoingUBX, uint16_t maxWait) -{ - int err; - //Point at 0xFF data register - u8_t small_buffer[1]; - small_buffer[0] = 0xFF; - err = transferWriteI2C(small_buffer, 1); //There is no register to write to, we just begin writing data bytes - if (err) { - return (SFE_UBLOX_STATUS_I2C_COMM_FAILURE); //Sensor did not ACK - } - - //Write header bytes - u8_t header_buffer[6]; //There is no register to write to, we just begin writing data bytes - header_buffer[0] = UBX_SYNCH_1; //μ - oh ublox, you're funny. I will call you micro-blox from now on. - header_buffer[1] = UBX_SYNCH_2; //b - header_buffer[2] = outgoingUBX->cls; - header_buffer[3] = outgoingUBX->id; - header_buffer[4] = outgoingUBX->len & 0xFF; //LSB - header_buffer[5] = outgoingUBX->len >> 8; //MSB - - err = transferWriteI2C(header_buffer, 6, false); - k_msleep(1); // added this millisecond sleep to not progress too fast - if (err) { - return (SFE_UBLOX_STATUS_I2C_COMM_FAILURE); //Sensor did not ACK - } - - //Write payload. Limit the sends into 32 byte chunks - //This code based on ublox: https://forum.u-blox.com/index.php/20528/how-to-use-i2c-to-get-the-nmea-frames - uint16_t bytesToSend = outgoingUBX->len; - - //"The number of data bytes must be at least 2 to properly distinguish - //from the write access to set the address counter in random read accesses." - uint16_t startSpot = 0; - while (bytesToSend > 1) - { - uint8_t len = bytesToSend; - if (len > I2C_BUFFER_LENGTH) - len = I2C_BUFFER_LENGTH; - - u8_t data_buffer[len]; - for (uint16_t x = 0; x < len; x++) { - data_buffer[x] = outgoingUBX->payload[startSpot + x]; - } - err = transferWriteI2C(data_buffer, len, false); //Write a portion of the payload to the bus - if (err) { - return (SFE_UBLOX_STATUS_I2C_COMM_FAILURE); //Sensor did not ACK - } - - //*outgoingUBX->payload += len; //Move the pointer forward - startSpot += len; //Move the pointer forward - bytesToSend -= len; - } - - //Write checksum - if (bytesToSend == 1) { - u8_t checksum_buffer[3]; - uint8_t payload = *outgoingUBX->payload; - checksum_buffer[0] = payload; - checksum_buffer[1] = outgoingUBX->checksumA; - checksum_buffer[2] = outgoingUBX->checksumB; - err = transferWriteI2C(checksum_buffer, 3, true); - } - else { - u8_t checksum_buffer[2]; - checksum_buffer[0] = outgoingUBX->checksumA; - checksum_buffer[1] = outgoingUBX->checksumB; - err = transferWriteI2C(checksum_buffer, 2, true); - } - if (err) { - return (SFE_UBLOX_STATUS_I2C_COMM_FAILURE); //Sensor did not ACK - } - - return (SFE_UBLOX_STATUS_SUCCESS); -} - -//Given a packet and payload, send everything including CRC bytesA via Serial port -void SFE_UBLOX_GPS::sendSerialCommand(ubxPacket *outgoingUBX) -{ - printk("sendSerialCommand function not ported...\n"); - /* - //Write header bytes - _serialPort->write(UBX_SYNCH_1); //μ - oh ublox, you're funny. I will call you micro-blox from now on. - _serialPort->write(UBX_SYNCH_2); //b - _serialPort->write(outgoingUBX->cls); - _serialPort->write(outgoingUBX->id); - _serialPort->write(outgoingUBX->len & 0xFF); //LSB - _serialPort->write(outgoingUBX->len >> 8); //MSB - - //Write payload. - for (int i = 0; i < outgoingUBX->len; i++) - { - _serialPort->write(outgoingUBX->payload[i]); - } - - //Write checksum - _serialPort->write(outgoingUBX->checksumA); - _serialPort->write(outgoingUBX->checksumB); - */ -} - -//Returns true if I2C device ack's -bool SFE_UBLOX_GPS::isConnected(uint16_t maxWait) -{ - if (commType == COMM_TYPE_I2C) - { - u8_t buff[1]; - buff[0] = 0x00; - int err = transferWriteI2C(buff, 1); - if (err) { - return false; //Sensor did not ack - } - } - - // Query navigation rate to see whether we get a meaningful response - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_RATE; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - //return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_RECEIVED); // We are polling the RATE so we expect data and an ACK - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // data send is returned, not data received - TODO library bug? -} - -//Given a message, calc and store the two byte "8-Bit Fletcher" checksum over the entirety of the message -//This is called before we send a command message -void SFE_UBLOX_GPS::calcChecksum(ubxPacket *msg) -{ - msg->checksumA = 0; - msg->checksumB = 0; - - msg->checksumA += msg->cls; - msg->checksumB += msg->checksumA; - - msg->checksumA += msg->id; - msg->checksumB += msg->checksumA; - - msg->checksumA += (msg->len & 0xFF); - msg->checksumB += msg->checksumA; - - msg->checksumA += (msg->len >> 8); - msg->checksumB += msg->checksumA; - - for (uint16_t i = 0; i < msg->len; i++) - { - msg->checksumA += msg->payload[i]; - msg->checksumB += msg->checksumA; - } -} - -//Given a message and a byte, add to rolling "8-Bit Fletcher" checksum -//This is used when receiving messages from module -void SFE_UBLOX_GPS::addToChecksum(uint8_t incoming) -{ - rollingChecksumA += incoming; - rollingChecksumB += rollingChecksumA; -} - -//Pretty prints the current ubxPacket -void SFE_UBLOX_GPS::printPacket(ubxPacket *packet) -{ - if (_printDebug == true) - { - printk("CLS:"); - if (packet->cls == UBX_CLASS_NAV) //1 - printk("NAV"); - else if (packet->cls == UBX_CLASS_ACK) //5 - printk("ACK"); - else if (packet->cls == UBX_CLASS_CFG) //6 - printk("CFG"); - else if (packet->cls == UBX_CLASS_MON) //0x0A - printk("MON"); - else - { - printk("0x%x", packet->cls); - } - - printk(" ID:"); - if (packet->cls == UBX_CLASS_NAV && packet->id == UBX_NAV_PVT) - printk("PVT"); - else if (packet->cls == UBX_CLASS_CFG && packet->id == UBX_CFG_RATE) - printk("RATE"); - else if (packet->cls == UBX_CLASS_CFG && packet->id == UBX_CFG_CFG) - printk("SAVE"); - else - { - printk("0x%x", packet->id); - } - - printk(" Len: 0x%x", packet->len); - - // Only print the payload is ignoreThisPayload is false otherwise - // we could be printing gibberish from beyond the end of packetBuf - if (ignoreThisPayload == false) - { - printk(" Payload:"); - - for (int x = 0; x < packet->len; x++) - { - printk(" %x", packet->payload[x]); - } - } - else - { - printk(" Payload: IGNORED"); - } - printk("\n"); - } -} - -//=-=-=-=-=-=-=-= Specific commands =-=-=-=-=-=-=-==-=-=-=-=-=-=-= -//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - -//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. - -//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 - -//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) - -//We need to think carefully about how interleaved PVT packets affect things. -//It is entirely possible that our packetCfg and packetAck were received successfully -//but while we are still in the "if (checkUblox() == true)" loop a PVT packet is processed -//or _starts_ to arrive (remember that Serial data can arrive very slowly). - -//Returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got an ACK and a valid packetCfg (module is responding with register content) -//Returns SFE_UBLOX_STATUS_DATA_SENT if we got an ACK and no packetCfg (no valid packetCfg needed, module absorbs new register data) -//Returns SFE_UBLOX_STATUS_FAIL if something very bad happens (e.g. a double checksum failure) -//Returns SFE_UBLOX_STATUS_COMMAND_NACK if the packet was not-acknowledged (NACK) -//Returns SFE_UBLOX_STATUS_CRC_FAIL if we had a checksum failure -//Returns SFE_UBLOX_STATUS_TIMEOUT if we timed out -//Returns SFE_UBLOX_STATUS_DATA_OVERWRITTEN if we got an ACK and a valid packetCfg but that the packetCfg has been -// or is currently being overwritten (remember that Serial data can arrive very slowly) -sfe_ublox_status_e SFE_UBLOX_GPS::waitForACKResponse(ubxPacket *outgoingUBX, uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime) -{ - outgoingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; //This will go VALID (or NOT_VALID) when we receive a response to the packet we sent - packetAck.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - packetBuf.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - outgoingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; // This will go VALID (or NOT_VALID) when we receive a packet that matches the requested class and ID - packetAck.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - packetBuf.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - - unsigned long startTime = k_uptime_get_32(); - while (k_uptime_get_32() - startTime < maxTime) - { - 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 (_printDebug == true) - { - printk("waitForACKResponse: valid data and valid ACK received after %lu msec\n", k_uptime_get_32() - startTime); - } - 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 a PVT packet. - else if ((outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED) && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID)) - { - if (_printDebug == true) - { - printk("waitForACKResponse: no data and valid ACK after %lu msec\n", k_uptime_get_32() - startTime); - } - 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 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) && (packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) && !((outgoingUBX->cls != requestedClass) || (outgoingUBX->id != requestedID))) - { - if (_printDebug == true) - { - printk("waitForACKResponse: data being OVERWRITTEN after %lu msec\n", k_uptime_get_32() - startTime); - } - return (SFE_UBLOX_STATUS_DATA_OVERWRITTEN); // Data was valid but has been or is being overwritten - } - - // If packetAck.classAndIDmatch is VALID but both outgoingUBX->valid and outgoingUBX->classAndIDmatch - // are NOT_VALID then we can be confident we have had a checksum failure on the data packet - else if ((packetAck.classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_VALID) && (outgoingUBX->classAndIDmatch == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID) && (outgoingUBX->valid == SFE_UBLOX_PACKET_VALIDITY_NOT_VALID)) - { - if (_printDebug == true) - { - printk("waitForACKResponse: CRC failed after %lu msec\n", k_uptime_get_32() - startTime); - } - 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.classAndIDmatch == SFE_UBLOX_PACKET_NOTACKNOWLEDGED) - { - if (_printDebug == true) - { - printk("waitForACKResponse: data was NOTACKNOWLEDGED (NACK) after %lu msec\n", k_uptime_get_32() - startTime); - } - return (SFE_UBLOX_STATUS_COMMAND_NACK); //We received a NACK! - } - - // If the outgoingUBX->classAndIDmatch is VALID but the packetAck.classAndIDmatch is NOT_VALID - // 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)) - { - if (_printDebug == true) - { - printk("waitForACKResponse: VALID data and INVALID ACK received after %lu msec\n", k_uptime_get_32() - startTime); - } - 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 - // 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)) - { - if (_printDebug == true) - { - printk("waitForACKResponse: INVALID data and INVALID ACK received after %lu msec\n", k_uptime_get_32() - startTime); - } - 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 - // 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)) - { - if (_printDebug == true) - { - printk("waitForACKResponse: valid data after %lu msec. Waiting for ACK\n", k_uptime_get_32() - startTime); - } - } - - } //checkUbloxInternal == true - - k_usleep(500); - } //while (k_uptime_get_32() - startTime < maxTime) - - // 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 (_printDebug == true) - { - printk("waitForACKResponse: TIMEOUT with valid data after %lu msec.\n", k_uptime_get_32() - startTime); - } - return (SFE_UBLOX_STATUS_DATA_RECEIVED); //We received valid data... But no ACK! - } - - if (_printDebug == true) - { - printk("waitForACKResponse: TIMEOUT after %lu msec.\n", k_uptime_get_32() - startTime); - } - - return (SFE_UBLOX_STATUS_TIMEOUT); -} - -//For non-CFG queries no ACK is sent so we use this function -//Returns SFE_UBLOX_STATUS_DATA_RECEIVED if we got a config packet full of response data that has CLS/ID match to our query packet -//Returns SFE_UBLOX_STATUS_CRC_FAIL if we got a corrupt config packet that has CLS/ID match to our query packet -//Returns SFE_UBLOX_STATUS_TIMEOUT if we timed out -//Returns SFE_UBLOX_STATUS_DATA_OVERWRITTEN if we got an a valid packetCfg but that the packetCfg has been -// or is currently being overwritten (remember that Serial data can arrive very slowly) -sfe_ublox_status_e SFE_UBLOX_GPS::waitForNoACKResponse(ubxPacket *outgoingUBX, uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime) -{ - outgoingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; //This will go VALID (or NOT_VALID) when we receive a response to the packet we sent - packetAck.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - packetBuf.valid = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - outgoingUBX->classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; // This will go VALID (or NOT_VALID) when we receive a packet that matches the requested class and ID - packetAck.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - packetBuf.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED; - - unsigned long startTime = k_uptime_get_32(); - while (k_uptime_get_32() - startTime < maxTime) - { - if (checkUbloxInternal(outgoingUBX, 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 (_printDebug == true) - { - printk("waitForNoACKResponse: valid data with CLS/ID match after %lu msec\n", k_uptime_get_32() - startTime); - } - 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) - { - printk("waitForNoACKResponse: data being OVERWRITTEN after %lu msec\n", k_uptime_get_32() - startTime); - } - 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) - { - printk("waitForNoACKResponse: valid but UNWANTED data after %lu msec. Class: %d ID: %d\n", k_uptime_get_32() - startTime, outgoingUBX->cls, 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) - { - printk("waitForNoACKResponse: CLS/ID match but failed CRC after %lu msec\n", k_uptime_get_32() - startTime); - } - return (SFE_UBLOX_STATUS_CRC_FAIL); //We received invalid data - } - } - - k_usleep(500); - } - - if (_printDebug == true) - { - printk("waitForNoACKResponse: TIMEOUT after %lu msec. No packet received.\n", k_uptime_get_32() - startTime); - } - - return (SFE_UBLOX_STATUS_TIMEOUT); -} - -//Save current configuration to flash and BBR (battery backed RAM) -//This still works but it is the old way of configuring ublox modules. See getVal and setVal for the new methods -bool SFE_UBLOX_GPS::saveConfiguration(uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_CFG; - packetCfg.len = 12; - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint8_t x = 0; x < packetCfg.len; x++) - packetCfg.payload[x] = 0; - - packetCfg.payload[4] = 0xFF; //Set any bit in the saveMask field to save current config to Flash and BBR - packetCfg.payload[5] = 0xFF; - - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Save the selected configuration sub-sections to flash and BBR (battery backed RAM) -//This still works but it is the old way of configuring ublox modules. See getVal and setVal for the new methods -bool SFE_UBLOX_GPS::saveConfigSelective(uint32_t configMask, uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_CFG; - packetCfg.len = 12; - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint8_t x = 0; x < packetCfg.len; x++) - packetCfg.payload[x] = 0; - - packetCfg.payload[4] = configMask & 0xFF; //Set the appropriate bits in the saveMask field to save current config to Flash and BBR - packetCfg.payload[5] = (configMask >> 8) & 0xFF; - packetCfg.payload[6] = (configMask >> 16) & 0xFF; - packetCfg.payload[7] = (configMask >> 24) & 0xFF; - - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Reset module to factory defaults -//This still works but it is the old way of configuring ublox modules. See getVal and setVal for the new methods -bool SFE_UBLOX_GPS::factoryDefault(uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_CFG; - packetCfg.len = 12; - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint8_t x = 0; x < packetCfg.len; x++) - packetCfg.payload[x] = 0; - - packetCfg.payload[0] = 0xFF; //Set any bit in the clearMask field to clear saved config - packetCfg.payload[1] = 0xFF; - packetCfg.payload[8] = 0xFF; //Set any bit in the loadMask field to discard current config and rebuild from lower non-volatile memory layers - packetCfg.payload[9] = 0xFF; - - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Given a group, ID and size, return the value of this config spot -//The 32-bit key is put together from group/ID/size. See other getVal to send key directly. -//Configuration of modern u-blox modules is now done via getVal/setVal/delVal, ie protocol v27 and above found on ZED-F9P -uint8_t SFE_UBLOX_GPS::getVal8(uint16_t group, uint16_t id, uint8_t size, uint8_t layer, uint16_t maxWait) -{ - //Create key - uint32_t key = 0; - key |= (uint32_t)id; - key |= (uint32_t)group << 16; - key |= (uint32_t)size << 28; - - if (_printDebug == true) - { - printk("key: 0x%x\n", key); - } - - return getVal8(key, layer, maxWait); -} - -//Given a key, return its value -//This function takes a full 32-bit key -//Default layer is BBR -//Configuration of modern u-blox modules is now done via getVal/setVal/delVal, ie protocol v27 and above found on ZED-F9P -uint8_t SFE_UBLOX_GPS::getVal8(uint32_t key, uint8_t layer, uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_VALGET; - packetCfg.len = 4 + 4 * 1; //While multiple keys are allowed, we will send only one key at a time - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint8_t x = 0; x < packetCfg.len; x++) - packetCfg.payload[x] = 0; - - //VALGET uses different memory layer definitions to VALSET - //because it can only return the value for one layer. - //So we need to fiddle the layer here. - //And just to complicate things further, the ZED-F9P only responds - //correctly to layer 0 (RAM) and layer 7 (Default)! - uint8_t getLayer = 7; // 7 is the "Default Layer" - if ((layer & VAL_LAYER_RAM) == VAL_LAYER_RAM) // Did the user request the RAM layer? - { - getLayer = 0; // Layer 0 is RAM - } - - payloadCfg[0] = 0; //Message Version - set to 0 - payloadCfg[1] = getLayer; //Layer - - //Load key into outgoing payload - payloadCfg[4] = key >> 8 * 0; //Key LSB - payloadCfg[5] = key >> 8 * 1; - payloadCfg[6] = key >> 8 * 2; - payloadCfg[7] = key >> 8 * 3; - - if (_printDebug == true) - { - printk("key: 0x%x\n", key); - } - - //Send VALGET command with this key - - sfe_ublox_status_e retVal = sendCommand(&packetCfg, maxWait); - if (_printDebug == true) - { - printk("getVal8: sendCommand returned: %s\n", statusString(retVal)); - } - if (retVal != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - return (0); //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?) - //Response is 8 bytes plus cfg data - //if(packet->len > 8+1) - - //Pull the requested value from the response - //Response starts at 4+1*N with the 32-bit key so the actual data we're looking for is at 8+1*N - return (extractByte(8)); -} - -//Given a key, set a 16-bit value -//This function takes a full 32-bit key -//Default layer is BBR -//Configuration of modern u-blox modules is now done via getVal/setVal/delVal, ie protocol v27 and above found on ZED-F9P -uint8_t SFE_UBLOX_GPS::setVal(uint32_t key, uint16_t value, uint8_t layer, uint16_t maxWait) -{ - return setVal16(key, value, layer, maxWait); -} - -//Given a key, set a 16-bit value -//This function takes a full 32-bit key -//Default layer is BBR -//Configuration of modern u-blox modules is now done via getVal/setVal/delVal, ie protocol v27 and above found on ZED-F9P -uint8_t SFE_UBLOX_GPS::setVal16(uint32_t key, uint16_t value, uint8_t layer, uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_VALSET; - packetCfg.len = 4 + 4 + 2; //4 byte header, 4 byte key ID, 2 bytes of value - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint16_t x = 0; x < packetCfg.len; x++) - packetCfg.payload[x] = 0; - - payloadCfg[0] = 0; //Message Version - set to 0 - payloadCfg[1] = layer; //By default we ask for the BBR layer - - //Load key into outgoing payload - payloadCfg[4] = key >> 8 * 0; //Key LSB - payloadCfg[5] = key >> 8 * 1; - payloadCfg[6] = key >> 8 * 2; - payloadCfg[7] = key >> 8 * 3; - - //Load user's value - payloadCfg[8] = value >> 8 * 0; //Value LSB - payloadCfg[9] = value >> 8 * 1; - - //Send VALSET command with this key and value - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Given a key, set an 8-bit value -//This function takes a full 32-bit key -//Default layer is BBR -//Configuration of modern u-blox modules is now done via getVal/setVal/delVal, ie protocol v27 and above found on ZED-F9P -uint8_t SFE_UBLOX_GPS::setVal8(uint32_t key, uint8_t value, uint8_t layer, uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_VALSET; - packetCfg.len = 4 + 4 + 1; //4 byte header, 4 byte key ID, 1 byte value - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint16_t x = 0; x < packetCfg.len; x++) - packetCfg.payload[x] = 0; - - payloadCfg[0] = 0; //Message Version - set to 0 - payloadCfg[1] = layer; //By default we ask for the BBR layer - - //Load key into outgoing payload - payloadCfg[4] = key >> 8 * 0; //Key LSB - payloadCfg[5] = key >> 8 * 1; - payloadCfg[6] = key >> 8 * 2; - payloadCfg[7] = key >> 8 * 3; - - //Load user's value - payloadCfg[8] = value; //Value - - //Send VALSET command with this key and value - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Given a key, set a 32-bit value -//This function takes a full 32-bit key -//Default layer is BBR -//Configuration of modern u-blox modules is now done via getVal/setVal/delVal, ie protocol v27 and above found on ZED-F9P -uint8_t SFE_UBLOX_GPS::setVal32(uint32_t key, uint32_t value, uint8_t layer, uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_VALSET; - packetCfg.len = 4 + 4 + 4; //4 byte header, 4 byte key ID, 4 bytes of value - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint16_t x = 0; x < packetCfg.len; x++) - packetCfg.payload[x] = 0; - - payloadCfg[0] = 0; //Message Version - set to 0 - payloadCfg[1] = layer; //By default we ask for the BBR layer - - //Load key into outgoing payload - payloadCfg[4] = key >> 8 * 0; //Key LSB - payloadCfg[5] = key >> 8 * 1; - payloadCfg[6] = key >> 8 * 2; - payloadCfg[7] = key >> 8 * 3; - - //Load user's value - payloadCfg[8] = value >> 8 * 0; //Value LSB - payloadCfg[9] = value >> 8 * 1; - payloadCfg[10] = value >> 8 * 2; - payloadCfg[11] = value >> 8 * 3; - - //Send VALSET command with this key and value - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Start defining a new UBX-CFG-VALSET ubxPacket -//This function takes a full 32-bit key and 32-bit value -//Default layer is BBR -//Configuration of modern u-blox modules is now done via getVal/setVal/delVal, ie protocol v27 and above found on ZED-F9P -uint8_t SFE_UBLOX_GPS::newCfgValset32(uint32_t key, uint32_t value, uint8_t layer) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_VALSET; - packetCfg.len = 4 + 4 + 4; //4 byte header, 4 byte key ID, 4 bytes of value - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint16_t x = 0; x < MAX_PAYLOAD_SIZE; x++) - packetCfg.payload[x] = 0; - - payloadCfg[0] = 0; //Message Version - set to 0 - payloadCfg[1] = layer; //By default we ask for the BBR layer - - //Load key into outgoing payload - payloadCfg[4] = key >> 8 * 0; //Key LSB - payloadCfg[5] = key >> 8 * 1; - payloadCfg[6] = key >> 8 * 2; - payloadCfg[7] = key >> 8 * 3; - - //Load user's value - payloadCfg[8] = value >> 8 * 0; //Value LSB - payloadCfg[9] = value >> 8 * 1; - payloadCfg[10] = value >> 8 * 2; - payloadCfg[11] = value >> 8 * 3; - - //All done - return (true); -} - -//Start defining a new UBX-CFG-VALSET ubxPacket -//This function takes a full 32-bit key and 16-bit value -//Default layer is BBR -//Configuration of modern u-blox modules is now done via getVal/setVal/delVal, ie protocol v27 and above found on ZED-F9P -uint8_t SFE_UBLOX_GPS::newCfgValset16(uint32_t key, uint16_t value, uint8_t layer) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_VALSET; - packetCfg.len = 4 + 4 + 2; //4 byte header, 4 byte key ID, 2 bytes of value - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint16_t x = 0; x < MAX_PAYLOAD_SIZE; x++) - packetCfg.payload[x] = 0; - - payloadCfg[0] = 0; //Message Version - set to 0 - payloadCfg[1] = layer; //By default we ask for the BBR layer - - //Load key into outgoing payload - payloadCfg[4] = key >> 8 * 0; //Key LSB - payloadCfg[5] = key >> 8 * 1; - payloadCfg[6] = key >> 8 * 2; - payloadCfg[7] = key >> 8 * 3; - - //Load user's value - payloadCfg[8] = value >> 8 * 0; //Value LSB - payloadCfg[9] = value >> 8 * 1; - - //All done - return (true); -} - -//Start defining a new UBX-CFG-VALSET ubxPacket -//This function takes a full 32-bit key and 8-bit value -//Default layer is BBR -//Configuration of modern u-blox modules is now done via getVal/setVal/delVal, ie protocol v27 and above found on ZED-F9P -uint8_t SFE_UBLOX_GPS::newCfgValset8(uint32_t key, uint8_t value, uint8_t layer) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_VALSET; - packetCfg.len = 4 + 4 + 1; //4 byte header, 4 byte key ID, 1 byte value - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint16_t x = 0; x < MAX_PAYLOAD_SIZE; x++) - packetCfg.payload[x] = 0; - - payloadCfg[0] = 0; //Message Version - set to 0 - payloadCfg[1] = layer; //By default we ask for the BBR layer - - //Load key into outgoing payload - payloadCfg[4] = key >> 8 * 0; //Key LSB - payloadCfg[5] = key >> 8 * 1; - payloadCfg[6] = key >> 8 * 2; - payloadCfg[7] = key >> 8 * 3; - - //Load user's value - payloadCfg[8] = value; //Value - - //All done - return (true); -} - -//Add another keyID and value to an existing UBX-CFG-VALSET ubxPacket -//This function takes a full 32-bit key and 32-bit value -uint8_t SFE_UBLOX_GPS::addCfgValset32(uint32_t key, uint32_t value) -{ - //Load key into outgoing payload - payloadCfg[packetCfg.len + 0] = key >> 8 * 0; //Key LSB - payloadCfg[packetCfg.len + 1] = key >> 8 * 1; - payloadCfg[packetCfg.len + 2] = key >> 8 * 2; - payloadCfg[packetCfg.len + 3] = key >> 8 * 3; - - //Load user's value - payloadCfg[packetCfg.len + 4] = value >> 8 * 0; //Value LSB - payloadCfg[packetCfg.len + 5] = value >> 8 * 1; - payloadCfg[packetCfg.len + 6] = value >> 8 * 2; - payloadCfg[packetCfg.len + 7] = value >> 8 * 3; - - //Update packet length: 4 byte key ID, 4 bytes of value - packetCfg.len = packetCfg.len + 4 + 4; - - //All done - return (true); -} - -//Add another keyID and value to an existing UBX-CFG-VALSET ubxPacket -//This function takes a full 32-bit key and 16-bit value -uint8_t SFE_UBLOX_GPS::addCfgValset16(uint32_t key, uint16_t value) -{ - //Load key into outgoing payload - payloadCfg[packetCfg.len + 0] = key >> 8 * 0; //Key LSB - payloadCfg[packetCfg.len + 1] = key >> 8 * 1; - payloadCfg[packetCfg.len + 2] = key >> 8 * 2; - payloadCfg[packetCfg.len + 3] = key >> 8 * 3; - - //Load user's value - payloadCfg[packetCfg.len + 4] = value >> 8 * 0; //Value LSB - payloadCfg[packetCfg.len + 5] = value >> 8 * 1; - - //Update packet length: 4 byte key ID, 2 bytes of value - packetCfg.len = packetCfg.len + 4 + 2; - - //All done - return (true); -} - -//Add another keyID and value to an existing UBX-CFG-VALSET ubxPacket -//This function takes a full 32-bit key and 8-bit value -uint8_t SFE_UBLOX_GPS::addCfgValset8(uint32_t key, uint8_t value) -{ - //Load key into outgoing payload - payloadCfg[packetCfg.len + 0] = key >> 8 * 0; //Key LSB - payloadCfg[packetCfg.len + 1] = key >> 8 * 1; - payloadCfg[packetCfg.len + 2] = key >> 8 * 2; - payloadCfg[packetCfg.len + 3] = key >> 8 * 3; - - //Load user's value - payloadCfg[packetCfg.len + 4] = value; //Value - - //Update packet length: 4 byte key ID, 1 byte value - packetCfg.len = packetCfg.len + 4 + 1; - - //All done - return (true); -} - -//Add a final keyID and value to an existing UBX-CFG-VALSET ubxPacket and send it -//This function takes a full 32-bit key and 32-bit value -uint8_t SFE_UBLOX_GPS::sendCfgValset32(uint32_t key, uint32_t value, uint16_t maxWait) -{ - //Load keyID and value into outgoing payload - addCfgValset32(key, value); - - //Send VALSET command with this key and value - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Add a final keyID and value to an existing UBX-CFG-VALSET ubxPacket and send it -//This function takes a full 32-bit key and 16-bit value -uint8_t SFE_UBLOX_GPS::sendCfgValset16(uint32_t key, uint16_t value, uint16_t maxWait) -{ - //Load keyID and value into outgoing payload - addCfgValset16(key, value); - - //Send VALSET command with this key and value - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Add a final keyID and value to an existing UBX-CFG-VALSET ubxPacket and send it -//This function takes a full 32-bit key and 8-bit value -uint8_t SFE_UBLOX_GPS::sendCfgValset8(uint32_t key, uint8_t value, uint16_t maxWait) -{ - //Load keyID and value into outgoing payload - addCfgValset8(key, value); - - //Send VALSET command with this key and value - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Get the current TimeMode3 settings - these contain survey in statuses -bool SFE_UBLOX_GPS::getSurveyMode(uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_TMODE3; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_RECEIVED); // We are expecting data and an ACK -} - -//Control Survey-In for NEO-M8P -bool SFE_UBLOX_GPS::setSurveyMode(uint8_t mode, uint16_t observationTime, float requiredAccuracy, uint16_t maxWait) -{ - if (getSurveyMode(maxWait) == false) //Ask module for the current TimeMode3 settings. Loads into payloadCfg. - return (false); - - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_TMODE3; - packetCfg.len = 40; - packetCfg.startingSpot = 0; - - //Clear packet payload - for (uint8_t x = 0; x < packetCfg.len; x++) - packetCfg.payload[x] = 0; - - //payloadCfg should be loaded with poll response. Now modify only the bits we care about - payloadCfg[2] = mode; //Set mode. Survey-In and Disabled are most common. Use ECEF (not LAT/LON/ALT). - - //svinMinDur is U4 (uint32_t) but we'll only use a uint16_t (waiting more than 65535 seconds seems excessive!) - payloadCfg[24] = observationTime & 0xFF; //svinMinDur in seconds - payloadCfg[25] = observationTime >> 8; //svinMinDur in seconds - payloadCfg[26] = 0; //Truncate to 16 bits - payloadCfg[27] = 0; //Truncate to 16 bits - - //svinAccLimit is U4 (uint32_t) in 0.1mm. - uint32_t svinAccLimit = (uint32_t)(requiredAccuracy * 10000.0); //Convert m to 0.1mm - payloadCfg[28] = svinAccLimit & 0xFF; //svinAccLimit in 0.1mm increments - payloadCfg[29] = svinAccLimit >> 8; - payloadCfg[30] = svinAccLimit >> 16; - payloadCfg[31] = svinAccLimit >> 24; - - return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Begin Survey-In for NEO-M8P -bool SFE_UBLOX_GPS::enableSurveyMode(uint16_t observationTime, float requiredAccuracy, uint16_t maxWait) -{ - return (setSurveyMode(SVIN_MODE_ENABLE, observationTime, requiredAccuracy, maxWait)); -} - -//Stop Survey-In for NEO-M8P -bool SFE_UBLOX_GPS::disableSurveyMode(uint16_t maxWait) -{ - return (setSurveyMode(SVIN_MODE_DISABLE, 0, 0, maxWait)); -} - -//Reads survey in status and sets the global variables -//for status, position valid, observation time, and mean 3D StdDev -//Returns true if commands was successful -bool SFE_UBLOX_GPS::getSurveyStatus(uint16_t maxWait) -{ - //Reset variables - svin.active = false; - svin.valid = false; - svin.observationTime = 0; - svin.meanAccuracy = 0; - - packetCfg.cls = UBX_CLASS_NAV; - packetCfg.id = UBX_NAV_SVIN; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - if ((sendCommand(&packetCfg, maxWait)) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - return (false); //If command send fails then bail - - //We got a response, now parse the bits into the svin structure - - //dur (Passed survey-in observation time) is U4 (uint32_t) seconds. We truncate to 16 bits - //(waiting more than 65535 seconds (18.2 hours) seems excessive!) - uint32_t tmpObsTime = extractLong(8); - if (tmpObsTime <= 0xFFFF) - { - svin.observationTime = (uint16_t)tmpObsTime; - } - else - { - svin.observationTime = 0xFFFF; - } - - // meanAcc is U4 (uint32_t) in 0.1mm. We convert this to float. - uint32_t tempFloat = extractLong(28); - svin.meanAccuracy = ((float)tempFloat) / 10000.0; //Convert 0.1mm to m - - svin.valid = payloadCfg[36]; //1 if survey-in position is valid, 0 otherwise - svin.active = payloadCfg[37]; //1 if survey-in in progress, 0 otherwise - - return (true); -} - -//Loads the payloadCfg array with the current protocol bits located the UBX-CFG-PRT register for a given port -bool SFE_UBLOX_GPS::getPortSettings(uint8_t portID, uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_PRT; - packetCfg.len = 1; - packetCfg.startingSpot = 0; - - payloadCfg[0] = portID; - - return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_RECEIVED); // We are expecting data and an ACK -} - -//Configure a given port to output UBX, NMEA, RTCM3 or a combination thereof -//Port 0=I2c, 1=UART1, 2=UART2, 3=USB, 4=SPI -//Bit:0 = UBX, :1=NMEA, :5=RTCM3 -bool SFE_UBLOX_GPS::setPortOutput(uint8_t portID, uint8_t outStreamSettings, uint16_t maxWait) -{ - //Get the current config values for this port ID - if (getPortSettings(portID, maxWait) == false) - return (false); //Something went wrong. Bail. - - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_PRT; - packetCfg.len = 20; - packetCfg.startingSpot = 0; - - //payloadCfg is now loaded with current bytes. Change only the ones we need to - payloadCfg[14] = outStreamSettings; //OutProtocolMask LSB - Set outStream bits - - return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Configure a given port to input UBX, NMEA, RTCM3 or a combination thereof -//Port 0=I2c, 1=UART1, 2=UART2, 3=USB, 4=SPI -//Bit:0 = UBX, :1=NMEA, :5=RTCM3 -bool SFE_UBLOX_GPS::setPortInput(uint8_t portID, uint8_t inStreamSettings, uint16_t maxWait) -{ - //Get the current config values for this port ID - //This will load the payloadCfg array with current port settings - if (getPortSettings(portID, maxWait) == false) - return (false); //Something went wrong. Bail. - - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_PRT; - packetCfg.len = 20; - packetCfg.startingSpot = 0; - - //payloadCfg is now loaded with current bytes. Change only the ones we need to - payloadCfg[12] = inStreamSettings; //InProtocolMask LSB - Set inStream bits - - return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Configure a port to output UBX, NMEA, RTCM3 or a combination thereof -bool SFE_UBLOX_GPS::setI2COutput(uint8_t comSettings, uint16_t maxWait) -{ - return (setPortOutput(COM_PORT_I2C, comSettings, maxWait)); -} -bool SFE_UBLOX_GPS::setUART1Output(uint8_t comSettings, uint16_t maxWait) -{ - return (setPortOutput(COM_PORT_UART1, comSettings, maxWait)); -} -bool SFE_UBLOX_GPS::setUART2Output(uint8_t comSettings, uint16_t maxWait) -{ - return (setPortOutput(COM_PORT_UART2, comSettings, maxWait)); -} -bool SFE_UBLOX_GPS::setUSBOutput(uint8_t comSettings, uint16_t maxWait) -{ - return (setPortOutput(COM_PORT_USB, comSettings, maxWait)); -} -bool SFE_UBLOX_GPS::setSPIOutput(uint8_t comSettings, uint16_t maxWait) -{ - return (setPortOutput(COM_PORT_SPI, comSettings, maxWait)); -} - -//Set the rate at which the module will give us an updated navigation solution -//Expects a number that is the updates per second. For example 1 = 1Hz, 2 = 2Hz, etc. -//Max is 40Hz(?!) -bool SFE_UBLOX_GPS::setNavigationFrequency(uint8_t navFreq, uint16_t maxWait) -{ - //if(updateRate > 40) updateRate = 40; //Not needed: module will correct out of bounds values - - //Adjust the I2C polling timeout based on update rate - i2cPollingWait = 1000 / (navFreq * 4); //This is the number of ms to wait between checks for new I2C data - - //Query the module for the latest lat/long - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_RATE; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - //This will load the payloadCfg array with current settings of the given register - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - return (false); //If command send fails then bail - - uint16_t measurementRate = 1000 / navFreq; - - //payloadCfg is now loaded with current bytes. Change only the ones we need to - payloadCfg[0] = measurementRate & 0xFF; //measRate LSB - payloadCfg[1] = measurementRate >> 8; //measRate MSB - - return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Get the rate at which the module is outputting nav solutions -uint8_t SFE_UBLOX_GPS::getNavigationFrequency(uint16_t maxWait) -{ - //Query the module for the latest lat/long - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_RATE; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - //This will load the payloadCfg array with current settings of the given register - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - return (false); //If command send fails then bail - - uint16_t measurementRate = 0; - - //payloadCfg is now loaded with current bytes. Get what we need - measurementRate = extractInt(0); //Pull from payloadCfg at measRate LSB - - measurementRate = 1000 / measurementRate; //This may return an int when it's a float, but I'd rather not return 4 bytes - return (measurementRate); -} - -//In case no config access to the GPS is possible and PVT is send cyclically already -//set config to suitable parameters -bool SFE_UBLOX_GPS::assumeAutoPVT(bool enabled, bool implicitUpdate) -{ - bool changes = autoPVT != enabled || autoPVTImplicitUpdate != implicitUpdate; - if (changes) - { - autoPVT = enabled; - autoPVTImplicitUpdate = implicitUpdate; - } - return changes; -} - -//Enable or disable automatic navigation message generation by the GPS. This changes the way getPVT -//works. -bool SFE_UBLOX_GPS::setAutoPVT(bool enable, uint16_t maxWait) -{ - return setAutoPVT(enable, true, maxWait); -} - -//Enable or disable automatic navigation message generation by the GPS. This changes the way getPVT -//works. -bool SFE_UBLOX_GPS::setAutoPVT(bool enable, bool implicitUpdate, uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_MSG; - packetCfg.len = 3; - packetCfg.startingSpot = 0; - payloadCfg[0] = UBX_CLASS_NAV; - payloadCfg[1] = UBX_NAV_PVT; - payloadCfg[2] = enable ? 1 : 0; // rate relative to navigation freq. - - bool ok = ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK - if (ok) - { - autoPVT = enable; - autoPVTImplicitUpdate = implicitUpdate; - } - moduleQueried.all = false; - return ok; -} - -//Configure a given message type for a given port (UART1, I2C, SPI, etc) -bool SFE_UBLOX_GPS::configureMessage(uint8_t msgClass, uint8_t msgID, uint8_t portID, uint8_t sendRate, uint16_t maxWait) -{ - //Poll for the current settings for a given message - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_MSG; - packetCfg.len = 2; - packetCfg.startingSpot = 0; - - payloadCfg[0] = msgClass; - payloadCfg[1] = msgID; - - //This will load the payloadCfg array with current settings of the given register - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - return (false); //If command send fails then bail - - //Now send it back with new mods - packetCfg.len = 8; - - //payloadCfg is now loaded with current bytes. Change only the ones we need to - payloadCfg[2 + portID] = sendRate; //Send rate is relative to the event a message is registered on. For example, if the rate of a navigation message is set to 2, the message is sent every 2nd navigation solution. - - return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Enable a given message type, default of 1 per update rate (usually 1 per second) -bool SFE_UBLOX_GPS::enableMessage(uint8_t msgClass, uint8_t msgID, uint8_t portID, uint8_t rate, uint16_t maxWait) -{ - return (configureMessage(msgClass, msgID, portID, rate, maxWait)); -} -//Disable a given message type on a given port -bool SFE_UBLOX_GPS::disableMessage(uint8_t msgClass, uint8_t msgID, uint8_t portID, uint16_t maxWait) -{ - return (configureMessage(msgClass, msgID, portID, 0, maxWait)); -} - -bool SFE_UBLOX_GPS::enableNMEAMessage(uint8_t msgID, uint8_t portID, uint8_t rate, uint16_t maxWait) -{ - return (configureMessage(UBX_CLASS_NMEA, msgID, portID, rate, maxWait)); -} -bool SFE_UBLOX_GPS::disableNMEAMessage(uint8_t msgID, uint8_t portID, uint16_t maxWait) -{ - return (enableNMEAMessage(msgID, portID, 0, maxWait)); -} - -//Given a message number turns on a message ID for output over a given portID (UART, I2C, SPI, USB, etc) -//To disable a message, set secondsBetween messages to 0 -//Note: This function will return false if the message is already enabled -//For base station RTK output we need to enable various sentences - -//NEO-M8P has four: -//1005 = 0xF5 0x05 - Stationary RTK reference ARP -//1077 = 0xF5 0x4D - GPS MSM7 -//1087 = 0xF5 0x57 - GLONASS MSM7 -//1230 = 0xF5 0xE6 - GLONASS code-phase biases, set to once every 10 seconds - -//ZED-F9P has six: -//1005, 1074, 1084, 1094, 1124, 1230 - -//Much of this configuration is not documented and instead discerned from u-center binary console -bool SFE_UBLOX_GPS::enableRTCMmessage(uint8_t messageNumber, uint8_t portID, uint8_t sendRate, uint16_t maxWait) -{ - return (configureMessage(UBX_RTCM_MSB, messageNumber, portID, sendRate, maxWait)); -} - -//Disable a given message on a given port by setting secondsBetweenMessages to zero -bool SFE_UBLOX_GPS::disableRTCMmessage(uint8_t messageNumber, uint8_t portID, uint16_t maxWait) -{ - return (enableRTCMmessage(messageNumber, portID, 0, maxWait)); -} - -//Add a new geofence using UBX-CFG-GEOFENCE -bool SFE_UBLOX_GPS::addGeofence(int32_t latitude, int32_t longitude, uint32_t radius, uint8_t confidence, uint8_t pinPolarity, uint8_t pin, uint16_t maxWait) -{ - if (currentGeofenceParams.numFences >= 4) - return (false); // Quit if we already have four geofences defined - - // Store the new geofence parameters - currentGeofenceParams.lats[currentGeofenceParams.numFences] = latitude; - currentGeofenceParams.longs[currentGeofenceParams.numFences] = longitude; - currentGeofenceParams.rads[currentGeofenceParams.numFences] = radius; - currentGeofenceParams.numFences = currentGeofenceParams.numFences + 1; // Increment the number of fences - - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_GEOFENCE; - packetCfg.len = (currentGeofenceParams.numFences * 12) + 8; - packetCfg.startingSpot = 0; - - payloadCfg[0] = 0; // Message version = 0x00 - payloadCfg[1] = currentGeofenceParams.numFences; // numFences - payloadCfg[2] = confidence; // confLvl = Confidence level 0-4 (none, 68%, 95%, 99.7%, 99.99%) - payloadCfg[3] = 0; // reserved1 - if (pin > 0) - { - payloadCfg[4] = 1; // enable PIO combined fence state - } - else - { - payloadCfg[4] = 0; // disable PIO combined fence state - } - payloadCfg[5] = pinPolarity; // PIO pin polarity (0 = low means inside, 1 = low means outside (or unknown)) - payloadCfg[6] = pin; // PIO pin - payloadCfg[7] = 0; //reserved2 - payloadCfg[8] = currentGeofenceParams.lats[0] & 0xFF; - payloadCfg[9] = currentGeofenceParams.lats[0] >> 8; - payloadCfg[10] = currentGeofenceParams.lats[0] >> 16; - payloadCfg[11] = currentGeofenceParams.lats[0] >> 24; - payloadCfg[12] = currentGeofenceParams.longs[0] & 0xFF; - payloadCfg[13] = currentGeofenceParams.longs[0] >> 8; - payloadCfg[14] = currentGeofenceParams.longs[0] >> 16; - payloadCfg[15] = currentGeofenceParams.longs[0] >> 24; - payloadCfg[16] = currentGeofenceParams.rads[0] & 0xFF; - payloadCfg[17] = currentGeofenceParams.rads[0] >> 8; - payloadCfg[18] = currentGeofenceParams.rads[0] >> 16; - payloadCfg[19] = currentGeofenceParams.rads[0] >> 24; - if (currentGeofenceParams.numFences >= 2) - { - payloadCfg[20] = currentGeofenceParams.lats[1] & 0xFF; - payloadCfg[21] = currentGeofenceParams.lats[1] >> 8; - payloadCfg[22] = currentGeofenceParams.lats[1] >> 16; - payloadCfg[23] = currentGeofenceParams.lats[1] >> 24; - payloadCfg[24] = currentGeofenceParams.longs[1] & 0xFF; - payloadCfg[25] = currentGeofenceParams.longs[1] >> 8; - payloadCfg[26] = currentGeofenceParams.longs[1] >> 16; - payloadCfg[27] = currentGeofenceParams.longs[1] >> 24; - payloadCfg[28] = currentGeofenceParams.rads[1] & 0xFF; - payloadCfg[29] = currentGeofenceParams.rads[1] >> 8; - payloadCfg[30] = currentGeofenceParams.rads[1] >> 16; - payloadCfg[31] = currentGeofenceParams.rads[1] >> 24; - } - if (currentGeofenceParams.numFences >= 3) - { - payloadCfg[32] = currentGeofenceParams.lats[2] & 0xFF; - payloadCfg[33] = currentGeofenceParams.lats[2] >> 8; - payloadCfg[34] = currentGeofenceParams.lats[2] >> 16; - payloadCfg[35] = currentGeofenceParams.lats[2] >> 24; - payloadCfg[36] = currentGeofenceParams.longs[2] & 0xFF; - payloadCfg[37] = currentGeofenceParams.longs[2] >> 8; - payloadCfg[38] = currentGeofenceParams.longs[2] >> 16; - payloadCfg[39] = currentGeofenceParams.longs[2] >> 24; - payloadCfg[40] = currentGeofenceParams.rads[2] & 0xFF; - payloadCfg[41] = currentGeofenceParams.rads[2] >> 8; - payloadCfg[42] = currentGeofenceParams.rads[2] >> 16; - payloadCfg[43] = currentGeofenceParams.rads[2] >> 24; - } - if (currentGeofenceParams.numFences >= 4) - { - payloadCfg[44] = currentGeofenceParams.lats[3] & 0xFF; - payloadCfg[45] = currentGeofenceParams.lats[3] >> 8; - payloadCfg[46] = currentGeofenceParams.lats[3] >> 16; - payloadCfg[47] = currentGeofenceParams.lats[3] >> 24; - payloadCfg[48] = currentGeofenceParams.longs[3] & 0xFF; - payloadCfg[49] = currentGeofenceParams.longs[3] >> 8; - payloadCfg[50] = currentGeofenceParams.longs[3] >> 16; - payloadCfg[51] = currentGeofenceParams.longs[3] >> 24; - payloadCfg[52] = currentGeofenceParams.rads[3] & 0xFF; - payloadCfg[53] = currentGeofenceParams.rads[3] >> 8; - payloadCfg[54] = currentGeofenceParams.rads[3] >> 16; - payloadCfg[55] = currentGeofenceParams.rads[3] >> 24; - } - return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Clear all geofences using UBX-CFG-GEOFENCE -bool SFE_UBLOX_GPS::clearGeofences(uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_GEOFENCE; - packetCfg.len = 8; - packetCfg.startingSpot = 0; - - payloadCfg[0] = 0; // Message version = 0x00 - payloadCfg[1] = 0; // numFences - payloadCfg[2] = 0; // confLvl - payloadCfg[3] = 0; // reserved1 - payloadCfg[4] = 0; // disable PIO combined fence state - payloadCfg[5] = 0; // PIO pin polarity (0 = low means inside, 1 = low means outside (or unknown)) - payloadCfg[6] = 0; // PIO pin - payloadCfg[7] = 0; //reserved2 - - currentGeofenceParams.numFences = 0; // Zero the number of geofences currently in use - - return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Clear the antenna control settings using UBX-CFG-ANT -//This function is hopefully redundant but may be needed to release -//any PIO pins pre-allocated for antenna functions -bool SFE_UBLOX_GPS::clearAntPIO(uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_ANT; - packetCfg.len = 4; - packetCfg.startingSpot = 0; - - payloadCfg[0] = 0x10; // Antenna flag mask: set the recovery bit - payloadCfg[1] = 0; - payloadCfg[2] = 0xFF; // Antenna pin configuration: set pinSwitch and pinSCD to 31 - payloadCfg[3] = 0xFF; // Antenna pin configuration: set pinOCD to 31, set reconfig bit - - return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Returns the combined geofence state using UBX-NAV-GEOFENCE -bool SFE_UBLOX_GPS::getGeofenceState(geofenceState ¤tGeofenceState, uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_NAV; - packetCfg.id = UBX_NAV_GEOFENCE; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - //Ask module for the geofence status. Loads into payloadCfg. - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - return (false); - - currentGeofenceState.status = payloadCfg[5]; // Extract the status - currentGeofenceState.numFences = payloadCfg[6]; // Extract the number of geofences - currentGeofenceState.combState = payloadCfg[7]; // Extract the combined state of all geofences - if (currentGeofenceState.numFences > 0) - currentGeofenceState.states[0] = payloadCfg[8]; // Extract geofence 1 state - if (currentGeofenceState.numFences > 1) - currentGeofenceState.states[1] = payloadCfg[10]; // Extract geofence 2 state - if (currentGeofenceState.numFences > 2) - currentGeofenceState.states[2] = payloadCfg[12]; // Extract geofence 3 state - if (currentGeofenceState.numFences > 3) - currentGeofenceState.states[3] = payloadCfg[14]; // Extract geofence 4 state - - return (true); -} - -//Power Save Mode -//Enables/Disables Low Power Mode using UBX-CFG-RXM -bool SFE_UBLOX_GPS::powerSaveMode(bool power_save, uint16_t maxWait) -{ - // Let's begin by checking the Protocol Version as UBX_CFG_RXM is not supported on the ZED (protocol >= 27) - uint8_t protVer = getProtocolVersionHigh(maxWait); - /* - if (_printDebug == true) - { - printk"(Protocol version is %d\n", protVer); - } - */ - if (protVer >= 27) - { - if (_printDebug == true) - { - printk("powerSaveMode (UBX-CFG-RXM) is not supported by this protocol version\n"); - } - return (false); - } - - // Now let's change the power setting using UBX-CFG-RXM - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_RXM; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - //Ask module for the current power management settings. Loads into payloadCfg. - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - return (false); - - if (power_save) - { - payloadCfg[1] = 1; // Power Save Mode - } - else - { - payloadCfg[1] = 0; // Continuous Mode - } - - packetCfg.len = 2; - packetCfg.startingSpot = 0; - - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -// Get Power Save Mode -// Returns the current Low Power Mode using UBX-CFG-RXM -// Returns 255 if the sendCommand fails -uint8_t SFE_UBLOX_GPS::getPowerSaveMode(uint16_t maxWait) -{ - // Let's begin by checking the Protocol Version as UBX_CFG_RXM is not supported on the ZED (protocol >= 27) - uint8_t protVer = getProtocolVersionHigh(maxWait); - /* - if (_printDebug == true) - { - printk("Protocol version is %d\n", protVer); - } - */ - if (protVer >= 27) - { - if (_printDebug == true) - { - printk("powerSaveMode (UBX-CFG-RXM) is not supported by this protocol version\n"); - } - return (255); - } - - // Now let's read the power setting using UBX-CFG-RXM - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_RXM; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - //Ask module for the current power management settings. Loads into payloadCfg. - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - return (255); - - return (payloadCfg[1]); // Return the low power mode -} - -// Powers off the GPS device for a given duration to reduce power consumption. -// NOTE: Querying the device before the duration is complete, for example by "getLatitude()" will wake it up! -// Returns true if command has not been not acknowledged. -// Returns false if command has not been acknowledged or maxWait = 0. -bool SFE_UBLOX_GPS::powerOff(uint32_t durationInMs, uint16_t maxWait) -{ - // use durationInMs = 0 for infinite duration - if (_printDebug == true) - { - printk("Powering off for %d ms\n", durationInMs); - } - - // Power off device using UBX-RXM-PMREQ - packetCfg.cls = UBX_CLASS_RXM; // 0x02 - packetCfg.id = UBX_RXM_PMREQ; // 0x41 - packetCfg.len = 8; - packetCfg.startingSpot = 0; - - // duration - // big endian to little endian, switch byte order - payloadCfg[0] = (durationInMs >> (8 * 0)) & 0xff; - payloadCfg[1] = (durationInMs >> (8 * 1)) & 0xff; - payloadCfg[2] = (durationInMs >> (8 * 2)) & 0xff; - payloadCfg[3] = (durationInMs >> (8 * 3)) & 0xff; - - payloadCfg[4] = 0x02; //Flags : set the backup bit - payloadCfg[5] = 0x00; //Flags - payloadCfg[6] = 0x00; //Flags - payloadCfg[7] = 0x00; //Flags - - if (maxWait != 0) - { - // check for "not acknowledged" command - return (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_COMMAND_NACK); - } - else - { - sendCommand(&packetCfg, maxWait); - return false; // can't tell if command not acknowledged if maxWait = 0 - } -} - -// Powers off the GPS device for a given duration to reduce power consumption. -// While powered off it can be woken up by creating a falling or rising voltage edge on the specified pin. -// NOTE: The GPS seems to be sensitve to signals on the pins while powered off. Works best when Microcontroller is in deepsleep. -// NOTE: Querying the device before the duration is complete, for example by "getLatitude()" will wake it up! -// Returns true if command has not been not acknowledged. -// Returns false if command has not been acknowledged or maxWait = 0. -bool SFE_UBLOX_GPS::powerOffWithInterrupt(uint32_t durationInMs, uint32_t wakeupSources, bool forceWhileUsb, uint16_t maxWait) -{ - // use durationInMs = 0 for infinite duration - if (_printDebug == true) - { - printk("Powering off for %d ms\n", durationInMs); - } - - // Power off device using UBX-RXM-PMREQ - packetCfg.cls = UBX_CLASS_RXM; // 0x02 - packetCfg.id = UBX_RXM_PMREQ; // 0x41 - packetCfg.len = 16; - packetCfg.startingSpot = 0; - - payloadCfg[0] = 0x00; // message version - - // bytes 1-3 are reserved - and must be set to zero - payloadCfg[1] = 0x00; - payloadCfg[2] = 0x00; - payloadCfg[3] = 0x00; - - // duration - // big endian to little endian, switch byte order - payloadCfg[4] = (durationInMs >> (8 * 0)) & 0xff; - payloadCfg[5] = (durationInMs >> (8 * 1)) & 0xff; - payloadCfg[6] = (durationInMs >> (8 * 2)) & 0xff; - payloadCfg[7] = (durationInMs >> (8 * 3)) & 0xff; - - // flags - - // disables USB interface when powering off, defaults to true - if (forceWhileUsb) - { - payloadCfg[8] = 0x06; // force | backup - } - else - { - payloadCfg[8] = 0x02; // backup only (leave the force bit clear - module will stay on if USB is connected) - } - - payloadCfg[9] = 0x00; - payloadCfg[10] = 0x00; - payloadCfg[11] = 0x00; - - // wakeUpSources - - // wakeupPin mapping, defaults to VAL_RXM_PMREQ_WAKEUPSOURCE_EXTINT0 - - // Possible values are: - // VAL_RXM_PMREQ_WAKEUPSOURCE_UARTRX - // VAL_RXM_PMREQ_WAKEUPSOURCE_EXTINT0 - // VAL_RXM_PMREQ_WAKEUPSOURCE_EXTINT1 - // VAL_RXM_PMREQ_WAKEUPSOURCE_SPICS - - payloadCfg[12] = (wakeupSources >> (8 * 0)) & 0xff; - payloadCfg[13] = (wakeupSources >> (8 * 1)) & 0xff; - payloadCfg[14] = (wakeupSources >> (8 * 2)) & 0xff; - payloadCfg[15] = (wakeupSources >> (8 * 3)) & 0xff; - - if (maxWait != 0) - { - // check for "not acknowledged" command - return (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_COMMAND_NACK); - } - else - { - sendCommand(&packetCfg, maxWait); - return false; // can't tell if command not acknowledged if maxWait = 0 - } -} - -//Change the dynamic platform model using UBX-CFG-NAV5 -//Possible values are: -//PORTABLE,STATIONARY,PEDESTRIAN,AUTOMOTIVE,SEA, -//AIRBORNE1g,AIRBORNE2g,AIRBORNE4g,WRIST,BIKE -//WRIST is not supported in protocol versions less than 18 -//BIKE is supported in protocol versions 19.2 -bool SFE_UBLOX_GPS::setDynamicModel(dynModel newDynamicModel, uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_NAV5; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - //Ask module for the current navigation model settings. Loads into payloadCfg. - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - return (false); - - payloadCfg[0] = 0x01; // mask: set only the dyn bit (0) - payloadCfg[1] = 0x00; // mask - payloadCfg[2] = newDynamicModel; // dynModel - - packetCfg.len = 36; - packetCfg.startingSpot = 0; - - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK -} - -//Get the dynamic platform model using UBX-CFG-NAV5 -//Returns 255 if the sendCommand fails -uint8_t SFE_UBLOX_GPS::getDynamicModel(uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_NAV5; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - //Ask module for the current navigation model settings. Loads into payloadCfg. - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK - return (255); - - return (payloadCfg[2]); // Return the dynamic model -} - -//Given a spot in the payload array, extract four bytes and build a long -uint32_t SFE_UBLOX_GPS::extractLong(uint8_t spotToStart) -{ - uint32_t val = 0; - val |= (uint32_t)payloadCfg[spotToStart + 0] << 8 * 0; - val |= (uint32_t)payloadCfg[spotToStart + 1] << 8 * 1; - val |= (uint32_t)payloadCfg[spotToStart + 2] << 8 * 2; - val |= (uint32_t)payloadCfg[spotToStart + 3] << 8 * 3; - return (val); -} - -//Given a spot in the payload array, extract two bytes and build an int -uint16_t SFE_UBLOX_GPS::extractInt(uint8_t spotToStart) -{ - uint16_t val = 0; - val |= (uint16_t)payloadCfg[spotToStart + 0] << 8 * 0; - val |= (uint16_t)payloadCfg[spotToStart + 1] << 8 * 1; - return (val); -} - -//Given a spot, extract a byte from the payload -uint8_t SFE_UBLOX_GPS::extractByte(uint8_t spotToStart) -{ - return (payloadCfg[spotToStart]); -} - -//Given a spot, extract a signed 8-bit value from the payload -int8_t SFE_UBLOX_GPS::extractSignedChar(uint8_t spotToStart) -{ - return ((int8_t)payloadCfg[spotToStart]); -} - -//Get the current year -uint16_t SFE_UBLOX_GPS::getYear(uint16_t maxWait) -{ - if (moduleQueried.gpsYear == false) - getPVT(maxWait); - moduleQueried.gpsYear = false; //Since we are about to give this to user, mark this data as stale - return (gpsYear); -} - -//Get the current month -uint8_t SFE_UBLOX_GPS::getMonth(uint16_t maxWait) -{ - if (moduleQueried.gpsMonth == false) - getPVT(maxWait); - moduleQueried.gpsMonth = false; //Since we are about to give this to user, mark this data as stale - return (gpsMonth); -} - -//Get the current day -uint8_t SFE_UBLOX_GPS::getDay(uint16_t maxWait) -{ - if (moduleQueried.gpsDay == false) - getPVT(maxWait); - moduleQueried.gpsDay = false; //Since we are about to give this to user, mark this data as stale - return (gpsDay); -} - -//Get the current hour -uint8_t SFE_UBLOX_GPS::getHour(uint16_t maxWait) -{ - if (moduleQueried.gpsHour == false) - getPVT(maxWait); - moduleQueried.gpsHour = false; //Since we are about to give this to user, mark this data as stale - return (gpsHour); -} - -//Get the current minute -uint8_t SFE_UBLOX_GPS::getMinute(uint16_t maxWait) -{ - if (moduleQueried.gpsMinute == false) - getPVT(maxWait); - moduleQueried.gpsMinute = false; //Since we are about to give this to user, mark this data as stale - return (gpsMinute); -} - -//Get the current second -uint8_t SFE_UBLOX_GPS::getSecond(uint16_t maxWait) -{ - if (moduleQueried.gpsSecond == false) - getPVT(maxWait); - moduleQueried.gpsSecond = false; //Since we are about to give this to user, mark this data as stale - return (gpsSecond); -} - -//Get the current date validity -bool SFE_UBLOX_GPS::getDateValid(uint16_t maxWait) -{ - if (moduleQueried.gpsDateValid == false) - getPVT(maxWait); - moduleQueried.gpsDateValid = false; //Since we are about to give this to user, mark this data as stale - return (gpsDateValid); -} - -//Get the current time validity -bool SFE_UBLOX_GPS::getTimeValid(uint16_t maxWait) -{ - if (moduleQueried.gpsTimeValid == false) - getPVT(maxWait); - moduleQueried.gpsTimeValid = false; //Since we are about to give this to user, mark this data as stale - return (gpsTimeValid); -} - -//Get the current millisecond -uint16_t SFE_UBLOX_GPS::getMillisecond(uint16_t maxWait) -{ - if (moduleQueried.gpsiTOW == false) - getPVT(maxWait); - moduleQueried.gpsiTOW = false; //Since we are about to give this to user, mark this data as stale - return (gpsMillisecond); -} - -//Get the current nanoseconds - includes milliseconds -int32_t SFE_UBLOX_GPS::getNanosecond(uint16_t maxWait) -{ - if (moduleQueried.gpsNanosecond == false) - getPVT(maxWait); - moduleQueried.gpsNanosecond = false; //Since we are about to give this to user, mark this data as stale - return (gpsNanosecond); -} - -//Get the latest Position/Velocity/Time solution and fill all global variables -bool SFE_UBLOX_GPS::getPVT(uint16_t maxWait) -{ - if (autoPVT && autoPVTImplicitUpdate) - { - //The GPS is automatically reporting, we just check whether we got unread data - if (_printDebug == true) - { - printk("getPVT: Autoreporting\n"); - } - checkUbloxInternal(&packetCfg, UBX_CLASS_NAV, UBX_NAV_PVT); - return moduleQueried.all; - } - else if (autoPVT && !autoPVTImplicitUpdate) - { - //Someone else has to call checkUblox for us... - if (_printDebug == true) - { - printk("getPVT: Exit immediately\n"); - } - return (false); - } - else - { - if (_printDebug == true) - { - printk("getPVT: Polling\n"); - } - - //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 - - //The data is parsed as part of processing the response - sfe_ublox_status_e retVal = sendCommand(&packetCfg, maxWait); - - if (retVal == SFE_UBLOX_STATUS_DATA_RECEIVED) - return (true); - - if (_printDebug == true) - { - printk("getPVT retVal: %s\n", statusString(retVal)); - } - return (false); - } -} - -uint32_t SFE_UBLOX_GPS::getTimeOfWeek(uint16_t maxWait /* = 250*/) -{ - if (moduleQueried.gpsiTOW == false) - getPVT(maxWait); - moduleQueried.gpsiTOW = false; //Since we are about to give this to user, mark this data as stale - return (timeOfWeek); -} - -int32_t SFE_UBLOX_GPS::getHighResLatitude(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.highResLatitude == false) - getHPPOSLLH(maxWait); - highResModuleQueried.highResLatitude = false; //Since we are about to give this to user, mark this data as stale - return (highResLatitude); -} - -int8_t SFE_UBLOX_GPS::getHighResLatitudeHp(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.highResLatitudeHp == false) - getHPPOSLLH(maxWait); - highResModuleQueried.highResLatitudeHp = false; //Since we are about to give this to user, mark this data as stale - return (highResLatitudeHp); -} - -int32_t SFE_UBLOX_GPS::getHighResLongitude(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.highResLongitude == false) - getHPPOSLLH(maxWait); - highResModuleQueried.highResLongitude = false; //Since we are about to give this to user, mark this data as stale - return (highResLongitude); -} - -int8_t SFE_UBLOX_GPS::getHighResLongitudeHp(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.highResLongitudeHp == false) - getHPPOSLLH(maxWait); - highResModuleQueried.highResLongitudeHp = false; //Since we are about to give this to user, mark this data as stale - return (highResLongitudeHp); -} - -int32_t SFE_UBLOX_GPS::getElipsoid(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.elipsoid == false) - getHPPOSLLH(maxWait); - highResModuleQueried.elipsoid = false; //Since we are about to give this to user, mark this data as stale - return (elipsoid); -} - -int8_t SFE_UBLOX_GPS::getElipsoidHp(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.elipsoidHp == false) - getHPPOSLLH(maxWait); - highResModuleQueried.elipsoidHp = false; //Since we are about to give this to user, mark this data as stale - return (elipsoidHp); -} - -int32_t SFE_UBLOX_GPS::getMeanSeaLevel(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.meanSeaLevel == false) - getHPPOSLLH(maxWait); - highResModuleQueried.meanSeaLevel = false; //Since we are about to give this to user, mark this data as stale - return (meanSeaLevel); -} - -int8_t SFE_UBLOX_GPS::getMeanSeaLevelHp(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.meanSeaLevelHp == false) - getHPPOSLLH(maxWait); - highResModuleQueried.meanSeaLevelHp = false; //Since we are about to give this to user, mark this data as stale - return (meanSeaLevelHp); -} - -// getGeoidSeparation is currently redundant. The geoid separation seems to only be provided in NMEA GGA and GNS messages. -int32_t SFE_UBLOX_GPS::getGeoidSeparation(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.geoidSeparation == false) - getHPPOSLLH(maxWait); - highResModuleQueried.geoidSeparation = false; //Since we are about to give this to user, mark this data as stale - return (geoidSeparation); -} - -uint32_t SFE_UBLOX_GPS::getHorizontalAccuracy(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.horizontalAccuracy == false) - getHPPOSLLH(maxWait); - highResModuleQueried.horizontalAccuracy = false; //Since we are about to give this to user, mark this data as stale - return (horizontalAccuracy); -} - -uint32_t SFE_UBLOX_GPS::getVerticalAccuracy(uint16_t maxWait /* = 250*/) -{ - if (highResModuleQueried.verticalAccuracy == false) - getHPPOSLLH(maxWait); - highResModuleQueried.verticalAccuracy = false; //Since we are about to give this to user, mark this data as stale - return (verticalAccuracy); -} - -bool SFE_UBLOX_GPS::getHPPOSLLH(uint16_t maxWait) -{ - //The GPS is not automatically reporting navigation position so we have to poll explicitly - packetCfg.cls = UBX_CLASS_NAV; - packetCfg.id = UBX_NAV_HPPOSLLH; - packetCfg.len = 0; - - return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_RECEIVED); // We are only expecting data (no ACK) -} - -//Get the current 3D high precision positional accuracy - a fun thing to watch -//Returns a long representing the 3D accuracy in millimeters -uint32_t SFE_UBLOX_GPS::getPositionAccuracy(uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_NAV; - packetCfg.id = UBX_NAV_HPPOSECEF; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are only expecting data (no ACK) - return (0); //If command send fails then bail - - uint32_t tempAccuracy = extractLong(24); //We got a response, now extract a long beginning at a given position - - if ((tempAccuracy % 10) >= 5) - tempAccuracy += 5; //Round fraction of mm up to next mm if .5 or above - tempAccuracy /= 10; //Convert 0.1mm units to mm - - return (tempAccuracy); -} - -//Get the current latitude in degrees -//Returns a long representing the number of degrees *10^-7 -int32_t SFE_UBLOX_GPS::getLatitude(uint16_t maxWait) -{ - if (moduleQueried.latitude == false) - getPVT(maxWait); - moduleQueried.latitude = false; //Since we are about to give this to user, mark this data as stale - moduleQueried.all = false; - - return (latitude); -} - -//Get the current longitude in degrees -//Returns a long representing the number of degrees *10^-7 -int32_t SFE_UBLOX_GPS::getLongitude(uint16_t maxWait) -{ - if (moduleQueried.longitude == false) - getPVT(maxWait); - moduleQueried.longitude = false; //Since we are about to give this to user, mark this data as stale - moduleQueried.all = false; - - return (longitude); -} - -//Get the current altitude in mm according to ellipsoid model -int32_t SFE_UBLOX_GPS::getAltitude(uint16_t maxWait) -{ - if (moduleQueried.altitude == false) - getPVT(maxWait); - moduleQueried.altitude = false; //Since we are about to give this to user, mark this data as stale - moduleQueried.all = false; - - return (altitude); -} - -//Get the current altitude in mm according to mean sea level -//Ellipsoid model: https://www.esri.com/news/arcuser/0703/geoid1of3.html -//Difference between Ellipsoid Model and Mean Sea Level: https://eos-gnss.com/elevation-for-beginners/ -int32_t SFE_UBLOX_GPS::getAltitudeMSL(uint16_t maxWait) -{ - if (moduleQueried.altitudeMSL == false) - getPVT(maxWait); - moduleQueried.altitudeMSL = false; //Since we are about to give this to user, mark this data as stale - moduleQueried.all = false; - - return (altitudeMSL); -} - -//Get the number of satellites used in fix -uint8_t SFE_UBLOX_GPS::getSIV(uint16_t maxWait) -{ - if (moduleQueried.SIV == false) - getPVT(maxWait); - moduleQueried.SIV = false; //Since we are about to give this to user, mark this data as stale - moduleQueried.all = false; - - return (SIV); -} - -//Get the current fix type -//0=no fix, 1=dead reckoning, 2=2D, 3=3D, 4=GNSS, 5=Time fix -uint8_t SFE_UBLOX_GPS::getFixType(uint16_t maxWait) -{ - if (moduleQueried.fixType == false) - { - getPVT(maxWait); - } - moduleQueried.fixType = false; //Since we are about to give this to user, mark this data as stale - moduleQueried.all = false; - - return (fixType); -} - -//Get the carrier phase range solution status -//Useful when querying module to see if it has high-precision RTK fix -//0=No solution, 1=Float solution, 2=Fixed solution -uint8_t SFE_UBLOX_GPS::getCarrierSolutionType(uint16_t maxWait) -{ - if (moduleQueried.carrierSolution == false) - getPVT(maxWait); - moduleQueried.carrierSolution = false; //Since we are about to give this to user, mark this data as stale - moduleQueried.all = false; - - return (carrierSolution); -} - -//Get the ground speed in mm/s -int32_t SFE_UBLOX_GPS::getGroundSpeed(uint16_t maxWait) -{ - if (moduleQueried.groundSpeed == false) - getPVT(maxWait); - moduleQueried.groundSpeed = false; //Since we are about to give this to user, mark this data as stale - moduleQueried.all = false; - - return (groundSpeed); -} - -//Get the heading of motion (as opposed to heading of car) in degrees * 10^-5 -int32_t SFE_UBLOX_GPS::getHeading(uint16_t maxWait) -{ - if (moduleQueried.headingOfMotion == false) - getPVT(maxWait); - moduleQueried.headingOfMotion = false; //Since we are about to give this to user, mark this data as stale - moduleQueried.all = false; - - return (headingOfMotion); -} - -//Get the positional dillution of precision * 10^-2 -uint16_t SFE_UBLOX_GPS::getPDOP(uint16_t maxWait) -{ - if (moduleQueried.pDOP == false) - getPVT(maxWait); - moduleQueried.pDOP = false; //Since we are about to give this to user, mark this data as stale - moduleQueried.all = false; - - return (pDOP); -} - -//Get the current protocol version of the u-blox module we're communicating with -//This is helpful when deciding if we should call the high-precision Lat/Long (HPPOSLLH) or the regular (POSLLH) -uint8_t SFE_UBLOX_GPS::getProtocolVersionHigh(uint16_t maxWait) -{ - if (moduleQueried.versionNumber == false) - getProtocolVersion(maxWait); - return (versionHigh); -} - -//Get the current protocol version of the u-blox module we're communicating with -//This is helpful when deciding if we should call the high-precision Lat/Long (HPPOSLLH) or the regular (POSLLH) -uint8_t SFE_UBLOX_GPS::getProtocolVersionLow(uint16_t maxWait) -{ - if (moduleQueried.versionNumber == false) - getProtocolVersion(maxWait); - return (versionLow); -} - -//Get the current protocol version of the u-blox module we're communicating with -//This is helpful when deciding if we should call the high-precision Lat/Long (HPPOSLLH) or the regular (POSLLH) -bool SFE_UBLOX_GPS::getProtocolVersion(uint16_t maxWait) -{ - //Send packet with only CLS and ID, length of zero. This will cause the module to respond with the contents of that CLS/ID. - packetCfg.cls = UBX_CLASS_MON; - packetCfg.id = UBX_MON_VER; - - packetCfg.len = 0; - packetCfg.startingSpot = 40; //Start at first "extended software information" string - - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are only expecting data (no ACK) - return (false); //If command send fails then bail - - //Payload should now contain ~220 characters (depends on module type) - - // if (_printDebug == true) - // { - // printk("MON VER Payload:")); - // for (int location = 0; location < packetCfg.len; location++) - // { - // if (location % 30 == 0) - // printk("\n"); - // printk("%d", payloadCfg[location]); - // } - // printk("\n"); - // } - - //We will step through the payload looking at each extension field of 30 bytes - for (uint8_t extensionNumber = 0; extensionNumber < 10; extensionNumber++) - { - //Now we need to find "PROTVER=18.00" in the incoming byte stream - if (payloadCfg[(30 * extensionNumber) + 0] == 'P' && payloadCfg[(30 * extensionNumber) + 6] == 'R') - { - versionHigh = (payloadCfg[(30 * extensionNumber) + 8] - '0') * 10 + (payloadCfg[(30 * extensionNumber) + 9] - '0'); //Convert '18' to 18 - versionLow = (payloadCfg[(30 * extensionNumber) + 11] - '0') * 10 + (payloadCfg[(30 * extensionNumber) + 12] - '0'); //Convert '00' to 00 - moduleQueried.versionNumber = true; //Mark this data as new - - if (_printDebug == true) - { - printk("Protocol version: %d.%d\n", versionHigh, versionLow); - } - return (true); //Success! - } - } - - return (false); //We failed -} - -//Mark all the PVT data as read/stale. This is handy to get data alignment after CRC failure -void SFE_UBLOX_GPS::flushPVT() -{ - //Mark all datums as stale (read before) - moduleQueried.gpsiTOW = false; - moduleQueried.gpsYear = false; - moduleQueried.gpsMonth = false; - moduleQueried.gpsDay = false; - moduleQueried.gpsHour = false; - moduleQueried.gpsMinute = false; - moduleQueried.gpsSecond = false; - moduleQueried.gpsDateValid = false; - moduleQueried.gpsTimeValid = false; - moduleQueried.gpsNanosecond = false; - - moduleQueried.all = false; - moduleQueried.longitude = false; - moduleQueried.latitude = false; - moduleQueried.altitude = false; - moduleQueried.altitudeMSL = false; - moduleQueried.SIV = false; - moduleQueried.fixType = false; - moduleQueried.carrierSolution = false; - moduleQueried.groundSpeed = false; - moduleQueried.headingOfMotion = false; - moduleQueried.pDOP = false; -} - -//Relative Positioning Information in NED frame -//Returns true if commands was successful -bool SFE_UBLOX_GPS::getRELPOSNED(uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_NAV; - packetCfg.id = UBX_NAV_RELPOSNED; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are only expecting data (no ACK) - return (false); //If command send fails then bail - - //We got a response, now parse the bits - - uint16_t refStationID = extractInt(2); - //printk("refStationID: %d\n", refStationID); - - int32_t tempRelPos; - - tempRelPos = extractLong(8); - relPosInfo.relPosN = tempRelPos / 100.0; //Convert cm to m - - tempRelPos = extractLong(12); - relPosInfo.relPosE = tempRelPos / 100.0; //Convert cm to m - - tempRelPos = extractLong(16); - relPosInfo.relPosD = tempRelPos / 100.0; //Convert cm to m - - relPosInfo.relPosLength = extractLong(20); - relPosInfo.relPosHeading = extractLong(24); - - relPosInfo.relPosHPN = payloadCfg[32]; - relPosInfo.relPosHPE = payloadCfg[33]; - relPosInfo.relPosHPD = payloadCfg[34]; - relPosInfo.relPosHPLength = payloadCfg[35]; - - uint32_t tempAcc; - - tempAcc = extractLong(36); - relPosInfo.accN = tempAcc / 10000.0; //Convert 0.1 mm to m - - tempAcc = extractLong(40); - relPosInfo.accE = tempAcc / 10000.0; //Convert 0.1 mm to m - - tempAcc = extractLong(44); - relPosInfo.accD = tempAcc / 10000.0; //Convert 0.1 mm to m - - uint8_t flags = payloadCfg[60]; - - relPosInfo.gnssFixOk = flags & (1 << 0); - relPosInfo.diffSoln = flags & (1 << 1); - relPosInfo.relPosValid = flags & (1 << 2); - relPosInfo.carrSoln = (flags & (0b11 << 3)) >> 3; - relPosInfo.isMoving = flags & (1 << 5); - relPosInfo.refPosMiss = flags & (1 << 6); - relPosInfo.refObsMiss = flags & (1 << 7); - - return (true); -} -bool SFE_UBLOX_GPS::getEsfInfo(uint16_t maxWait) -{ - // Requesting Data from the receiver - packetCfg.cls = UBX_CLASS_ESF; - packetCfg.id = UBX_ESF_STATUS; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) - return (false); //If command send fails then bail - - checkUblox(); - - // payload should be loaded. - imuMeas.version = extractByte(4); - imuMeas.fusionMode = extractByte(12); - ubloxSen.numSens = extractByte(15); - - // Individual Status Sensor in different function - return (true); -} - -// -bool SFE_UBLOX_GPS::getEsfIns(uint16_t maxWait) -{ - packetCfg.cls = UBX_CLASS_ESF; - packetCfg.id = UBX_ESF_INS; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) - return (false); //If command send fails then bail - - checkUblox(); - - // Validity of each sensor value below - uint32_t validity = extractLong(0); - - imuMeas.xAngRateVald = (validity && 0x0080) >> 8; - imuMeas.yAngRateVald = (validity && 0x0100) >> 9; - imuMeas.zAngRateVald = (validity && 0x0200) >> 10; - imuMeas.xAccelVald = (validity && 0x0400) >> 11; - imuMeas.yAccelVald = (validity && 0x0800) >> 12; - imuMeas.zAccelVald = (validity && 0x1000) >> 13; - - imuMeas.xAngRate = extractLong(12); // deg/s - imuMeas.yAngRate = extractLong(16); // deg/s - imuMeas.zAngRate = extractLong(20); // deg/s - - imuMeas.xAccel = extractLong(24); // m/s - imuMeas.yAccel = extractLong(28); // m/s - imuMeas.zAccel = extractLong(32); // m/s - - return (true); -} - -// -bool SFE_UBLOX_GPS::getEsfDataInfo(uint16_t maxWait) -{ - - packetCfg.cls = UBX_CLASS_ESF; - packetCfg.id = UBX_ESF_MEAS; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) - return (false); //If command send fails then bail - - checkUblox(); - - uint32_t timeStamp = extractLong(0); - uint32_t flags = extractInt(4); - - uint8_t timeSent = (flags && 0x01) >> 1; - uint8_t timeEdge = (flags && 0x02) >> 2; - uint8_t tagValid = (flags && 0x04) >> 3; - uint8_t numMeas = (flags && 0x1000) >> 15; - - if (numMeas > DEF_NUM_SENS) - numMeas = DEF_NUM_SENS; - - uint8_t byteOffset = 4; - - for (uint8_t i = 0; i < numMeas; i++) - { - - uint32_t bitField = extractLong(4 + byteOffset * i); - imuMeas.dataType[i] = (bitField && 0xFF000000) >> 23; - imuMeas.data[i] = (bitField && 0xFFFFFF); - imuMeas.dataTStamp[i] = extractLong(8 + byteOffset * i); - } - - return (true); -} - -bool SFE_UBLOX_GPS::getEsfRawDataInfo(uint16_t maxWait) -{ - - // Need to know the number of sensor to get the correct data - // Rate selected in UBX-CFG-MSG is not respected - packetCfg.cls = UBX_CLASS_ESF; - packetCfg.id = UBX_ESF_RAW; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) - return (false); //If command send fails then bail - - checkUblox(); - - uint32_t bitField = extractLong(4); - imuMeas.rawDataType = (bitField && 0xFF000000) >> 23; - imuMeas.rawData = (bitField && 0xFFFFFF); - imuMeas.rawTStamp = extractLong(8); - - return (true); -} - -sfe_ublox_status_e SFE_UBLOX_GPS::getSensState(uint8_t sensor, uint16_t maxWait) -{ - - packetCfg.cls = UBX_CLASS_ESF; - packetCfg.id = UBX_ESF_STATUS; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) - return (SFE_UBLOX_STATUS_FAIL); //If command send fails then bail - - ubloxSen.numSens = extractByte(15); - - if (sensor > ubloxSen.numSens) - return (SFE_UBLOX_STATUS_OUT_OF_RANGE); - - checkUblox(); - - uint8_t offset = 4; - - // Only the last sensor value checked will remain. - for (uint8_t i = 0; i < sensor; i++) - { - - uint8_t sensorFieldOne = extractByte(16 + offset * i); - uint8_t sensorFieldTwo = extractByte(17 + offset * i); - ubloxSen.freq = extractByte(18 + offset * i); - uint8_t sensorFieldThr = extractByte(19 + offset * i); - - ubloxSen.senType = (sensorFieldOne && 0x10) >> 5; - ubloxSen.isUsed = (sensorFieldOne && 0x20) >> 6; - ubloxSen.isReady = (sensorFieldOne && 0x30) >> 7; - - ubloxSen.calibStatus = sensorFieldTwo && 0x03; - ubloxSen.timeStatus = (sensorFieldTwo && 0xC) >> 2; - - ubloxSen.badMeas = (sensorFieldThr && 0x01); - ubloxSen.badTag = (sensorFieldThr && 0x02) >> 1; - ubloxSen.missMeas = (sensorFieldThr && 0x04) >> 2; - ubloxSen.noisyMeas = (sensorFieldThr && 0x08) >> 3; - } - - return (SFE_UBLOX_STATUS_SUCCESS); -} - -bool SFE_UBLOX_GPS::getVehAtt(uint16_t maxWait) -{ - - packetCfg.cls = UBX_CLASS_NAV; - packetCfg.id = UBX_NAV_ATT; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) - return (SFE_UBLOX_STATUS_FAIL); //If command send fails then bail - - checkUblox(); - - vehAtt.roll = extractLong(8); - vehAtt.pitch = extractLong(12); - vehAtt.heading = extractLong(16); - - vehAtt.accRoll = extractLong(20); - vehAtt.accPitch = extractLong(24); - vehAtt.accHeading = extractLong(28); - - return (true); -} diff --git a/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/src/SparkFun_Ublox_Zephyr_Library.h b/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/src/SparkFun_Ublox_Zephyr_Library.h deleted file mode 100644 index 7163d79..0000000 --- a/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/src/SparkFun_Ublox_Zephyr_Library.h +++ /dev/null @@ -1,901 +0,0 @@ -/* - This is a library written for the u-blox ZED-F9P and NEO-M8P-2 - SparkFun sells these at its website: www.sparkfun.com - Do you like this library? Help support SparkFun. Buy a board! - https://www.sparkfun.com/products/15136 - https://www.sparkfun.com/products/15005 - https://www.sparkfun.com/products/15733 - https://www.sparkfun.com/products/15193 - https://www.sparkfun.com/products/15210 - - Written by Nathan Seidle @ SparkFun Electronics, September 6th, 2018 - - This library handles configuring and handling the responses - from a u-blox GPS module. Works with most modules from u-blox including - the Zed-F9P, NEO-M8P-2, NEO-M9N, ZOE-M8Q, SAM-M8Q, and many others. - - https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library - - Development environment specifics: - NCS v1.0.3 release - - This port was made by Vid Rajtmajer , IRNAS www.irnas.eu - - SparkFun code, firmware, and software is released under the MIT License(http://opensource.org/licenses/MIT). - The MIT License (MIT) - Copyright (c) 2016 SparkFun Electronics - Permission is hereby granted, free of charge, to any person obtaining a copy of this software and - associated documentation files (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the Software is furnished to - do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or substantial - portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef SPARKFUN_UBLOX_ZEPHYR_LIBRARY_H -#define SPARKFUN_UBLOX_ZEPHYR_LIBRARY_H - -#include -#include - -//The catch-all default is 32 -#define I2C_BUFFER_LENGTH 32 - -//Define pin states -#define LOW 0 -#define HIGH 1 - -//Define a digital pin to aid checksum failure capture and analysis -//Leave set to -1 if not needed -const int checksumFailurePin = -1; - -// Global Status Returns -typedef enum -{ - SFE_UBLOX_STATUS_SUCCESS, - SFE_UBLOX_STATUS_FAIL, - SFE_UBLOX_STATUS_CRC_FAIL, - SFE_UBLOX_STATUS_TIMEOUT, - SFE_UBLOX_STATUS_COMMAND_NACK, // Indicates that the command was unrecognised, invalid or that the module is too busy to respond - SFE_UBLOX_STATUS_OUT_OF_RANGE, - SFE_UBLOX_STATUS_INVALID_ARG, - SFE_UBLOX_STATUS_INVALID_OPERATION, - SFE_UBLOX_STATUS_MEM_ERR, - SFE_UBLOX_STATUS_HW_ERR, - SFE_UBLOX_STATUS_DATA_SENT, // This indicates that a 'set' was successful - SFE_UBLOX_STATUS_DATA_RECEIVED, // This indicates that a 'get' (poll) was successful - SFE_UBLOX_STATUS_I2C_COMM_FAILURE, - SFE_UBLOX_STATUS_DATA_OVERWRITTEN // This is an error - the data was valid but has been or _is being_ overwritten by another packet -} sfe_ublox_status_e; - -// ubxPacket validity -typedef enum -{ - SFE_UBLOX_PACKET_VALIDITY_NOT_VALID, - SFE_UBLOX_PACKET_VALIDITY_VALID, - SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, - SFE_UBLOX_PACKET_NOTACKNOWLEDGED // This indicates that we received a NACK -} sfe_ublox_packet_validity_e; - -// Identify which packet buffer is in use: -// packetCfg (or a custom packet), packetAck or packetBuf -typedef enum -{ - SFE_UBLOX_PACKET_PACKETCFG, - SFE_UBLOX_PACKET_PACKETACK, - SFE_UBLOX_PACKET_PACKETBUF -} sfe_ublox_packet_buffer_e; - -//Registers -const uint8_t UBX_SYNCH_1 = 0xB5; -const uint8_t UBX_SYNCH_2 = 0x62; - -//The following are UBX Class IDs. Descriptions taken from ZED-F9P Interface Description Document page 32, NEO-M8P Interface Description page 145 -const uint8_t UBX_CLASS_NAV = 0x01; //Navigation Results Messages: Position, Speed, Time, Acceleration, Heading, DOP, SVs used -const uint8_t UBX_CLASS_RXM = 0x02; //Receiver Manager Messages: Satellite Status, RTC Status -const uint8_t UBX_CLASS_INF = 0x04; //Information Messages: Printf-Style Messages, with IDs such as Error, Warning, Notice -const uint8_t UBX_CLASS_ACK = 0x05; //Ack/Nak Messages: Acknowledge or Reject messages to UBX-CFG input messages -const uint8_t UBX_CLASS_CFG = 0x06; //Configuration Input Messages: Configure the receiver. -const uint8_t UBX_CLASS_UPD = 0x09; //Firmware Update Messages: Memory/Flash erase/write, Reboot, Flash identification, etc. -const uint8_t UBX_CLASS_MON = 0x0A; //Monitoring Messages: Communication Status, CPU Load, Stack Usage, Task Status -const uint8_t UBX_CLASS_AID = 0x0B; //(NEO-M8P ONLY!!!) AssistNow Aiding Messages: Ephemeris, Almanac, other A-GPS data input -const uint8_t UBX_CLASS_TIM = 0x0D; //Timing Messages: Time Pulse Output, Time Mark Results -const uint8_t UBX_CLASS_ESF = 0x10; //(NEO-M8P ONLY!!!) External Sensor Fusion Messages: External Sensor Measurements and Status Information -const uint8_t UBX_CLASS_MGA = 0x13; //Multiple GNSS Assistance Messages: Assistance data for various GNSS -const uint8_t UBX_CLASS_LOG = 0x21; //Logging Messages: Log creation, deletion, info and retrieval -const uint8_t UBX_CLASS_SEC = 0x27; //Security Feature Messages -const uint8_t UBX_CLASS_HNR = 0x28; //(NEO-M8P ONLY!!!) High Rate Navigation Results Messages: High rate time, position speed, heading -const uint8_t UBX_CLASS_NMEA = 0xF0; //NMEA Strings: standard NMEA strings - -//The following are used for configuration. Descriptions are from the ZED-F9P Interface Description pg 33-34 and NEO-M9N Interface Description pg 47-48 -const uint8_t UBX_CFG_ANT = 0x13; //Antenna Control Settings. Used to configure the antenna control settings -const uint8_t UBX_CFG_BATCH = 0x93; //Get/set data batching configuration. -const uint8_t UBX_CFG_CFG = 0x09; //Clear, Save, and Load Configurations. Used to save current configuration -const uint8_t UBX_CFG_DAT = 0x06; //Set User-defined Datum or The currently defined Datum -const uint8_t UBX_CFG_DGNSS = 0x70; //DGNSS configuration -const uint8_t UBX_CFG_GEOFENCE = 0x69; //Geofencing configuration. Used to configure a geofence -const uint8_t UBX_CFG_GNSS = 0x3E; //GNSS system configuration -const uint8_t UBX_CFG_INF = 0x02; //Depending on packet length, either: poll configuration for one protocol, or information message configuration -const uint8_t UBX_CFG_ITFM = 0x39; //Jamming/Interference Monitor configuration -const uint8_t UBX_CFG_LOGFILTER = 0x47; //Data Logger Configuration -const uint8_t UBX_CFG_MSG = 0x01; //Poll a message configuration, or Set Message Rate(s), or Set Message Rate -const uint8_t UBX_CFG_NAV5 = 0x24; //Navigation Engine Settings. Used to configure the navigation engine including the dynamic model. -const uint8_t UBX_CFG_NAVX5 = 0x23; //Navigation Engine Expert Settings -const uint8_t UBX_CFG_NMEA = 0x17; //Extended NMEA protocol configuration V1 -const uint8_t UBX_CFG_ODO = 0x1E; //Odometer, Low-speed COG Engine Settings -const uint8_t UBX_CFG_PM2 = 0x3B; //Extended power management configuration -const uint8_t UBX_CFG_PMS = 0x86; //Power mode setup -const uint8_t UBX_CFG_PRT = 0x00; //Used to configure port specifics. Polls the configuration for one I/O Port, or Port configuration for UART ports, or Port configuration for USB port, or Port configuration for SPI port, or Port configuration for DDC port -const uint8_t UBX_CFG_PWR = 0x57; //Put receiver in a defined power state -const uint8_t UBX_CFG_RATE = 0x08; //Navigation/Measurement Rate Settings. Used to set port baud rates. -const uint8_t UBX_CFG_RINV = 0x34; //Contents of Remote Inventory -const uint8_t UBX_CFG_RST = 0x04; //Reset Receiver / Clear Backup Data Structures. Used to reset device. -const uint8_t UBX_CFG_RXM = 0x11; //RXM configuration -const uint8_t UBX_CFG_SBAS = 0x16; //SBAS configuration -const uint8_t UBX_CFG_TMODE3 = 0x71; //Time Mode Settings 3. Used to enable Survey In Mode -const uint8_t UBX_CFG_TP5 = 0x31; //Time Pulse Parameters -const uint8_t UBX_CFG_USB = 0x1B; //USB Configuration -const uint8_t UBX_CFG_VALDEL = 0x8C; //Used for config of higher version u-blox modules (ie protocol v27 and above). Deletes values corresponding to provided keys/ provided keys with a transaction -const uint8_t UBX_CFG_VALGET = 0x8B; //Used for config of higher version u-blox modules (ie protocol v27 and above). Configuration Items -const uint8_t UBX_CFG_VALSET = 0x8A; //Used for config of higher version u-blox modules (ie protocol v27 and above). Sets values corresponding to provided key-value pairs/ provided key-value pairs within a transaction. - -//The following are used to enable NMEA messages. Descriptions come from the NMEA messages overview in the ZED-F9P Interface Description -const uint8_t UBX_NMEA_MSB = 0xF0; //All NMEA enable commands have 0xF0 as MSB -const uint8_t UBX_NMEA_DTM = 0x0A; //GxDTM (datum reference) -const uint8_t UBX_NMEA_GAQ = 0x45; //GxGAQ (poll a standard message (if the current talker ID is GA)) -const uint8_t UBX_NMEA_GBQ = 0x44; //GxGBQ (poll a standard message (if the current Talker ID is GB)) -const uint8_t UBX_NMEA_GBS = 0x09; //GxGBS (GNSS satellite fault detection) -const uint8_t UBX_NMEA_GGA = 0x00; //GxGGA (Global positioning system fix data) -const uint8_t UBX_NMEA_GLL = 0x01; //GxGLL (latitude and long, whith time of position fix and status) -const uint8_t UBX_NMEA_GLQ = 0x43; //GxGLQ (poll a standard message (if the current Talker ID is GL)) -const uint8_t UBX_NMEA_GNQ = 0x42; //GxGNQ (poll a standard message (if the current Talker ID is GN)) -const uint8_t UBX_NMEA_GNS = 0x0D; //GxGNS (GNSS fix data) -const uint8_t UBX_NMEA_GPQ = 0x040; //GxGPQ (poll a standard message (if the current Talker ID is GP)) -const uint8_t UBX_NMEA_GRS = 0x06; //GxGRS (GNSS range residuals) -const uint8_t UBX_NMEA_GSA = 0x02; //GxGSA (GNSS DOP and Active satellites) -const uint8_t UBX_NMEA_GST = 0x07; //GxGST (GNSS Pseudo Range Error Statistics) -const uint8_t UBX_NMEA_GSV = 0x03; //GxGSV (GNSS satellites in view) -const uint8_t UBX_NMEA_RMC = 0x04; //GxRMC (Recommended minimum data) -const uint8_t UBX_NMEA_TXT = 0x41; //GxTXT (text transmission) -const uint8_t UBX_NMEA_VLW = 0x0F; //GxVLW (dual ground/water distance) -const uint8_t UBX_NMEA_VTG = 0x05; //GxVTG (course over ground and Ground speed) -const uint8_t UBX_NMEA_ZDA = 0x08; //GxZDA (Time and Date) - -//The following are used to configure the NMEA protocol main talker ID and GSV talker ID -const uint8_t UBX_NMEA_MAINTALKERID_NOTOVERRIDDEN = 0x00; //main talker ID is system dependent -const uint8_t UBX_NMEA_MAINTALKERID_GP = 0x01; //main talker ID is GPS -const uint8_t UBX_NMEA_MAINTALKERID_GL = 0x02; //main talker ID is GLONASS -const uint8_t UBX_NMEA_MAINTALKERID_GN = 0x03; //main talker ID is combined receiver -const uint8_t UBX_NMEA_MAINTALKERID_GA = 0x04; //main talker ID is Galileo -const uint8_t UBX_NMEA_MAINTALKERID_GB = 0x05; //main talker ID is BeiDou -const uint8_t UBX_NMEA_GSVTALKERID_GNSS = 0x00; //GNSS specific Talker ID (as defined by NMEA) -const uint8_t UBX_NMEA_GSVTALKERID_MAIN = 0x01; //use the main Talker ID - -//The following are used to configure INF UBX messages (information messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 34) -const uint8_t UBX_INF_CLASS = 0x04; //All INF messages have 0x04 as the class -const uint8_t UBX_INF_DEBUG = 0x04; //ASCII output with debug contents -const uint8_t UBX_INF_ERROR = 0x00; //ASCII output with error contents -const uint8_t UBX_INF_NOTICE = 0x02; //ASCII output with informational contents -const uint8_t UBX_INF_TEST = 0x03; //ASCII output with test contents -const uint8_t UBX_INF_WARNING = 0x01; //ASCII output with warning contents - -//The following are used to configure LOG UBX messages (loggings messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 34) -const uint8_t UBX_LOG_CREATE = 0x07; //Create Log File -const uint8_t UBX_LOG_ERASE = 0x03; //Erase Logged Data -const uint8_t UBX_LOG_FINDTIME = 0x0E; //Find index of a log entry based on a given time, or response to FINDTIME requested -const uint8_t UBX_LOG_INFO = 0x08; //Poll for log information, or Log information -const uint8_t UBX_LOG_RETRIEVEPOSEXTRA = 0x0F; //Odometer log entry -const uint8_t UBX_LOG_RETRIEVEPOS = 0x0B; //Position fix log entry -const uint8_t UBX_LOG_RETRIEVESTRING = 0x0D; //Byte string log entry -const uint8_t UBX_LOG_RETRIEVE = 0x09; //Request log data -const uint8_t UBX_LOG_STRING = 0x04; //Store arbitrary string on on-board flash - -//The following are used to configure MGA UBX messages (Multiple GNSS Assistance Messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 34) -const uint8_t UBX_MGA_ACK_DATA0 = 0x60; //Multiple GNSS Acknowledge message -const uint8_t UBX_MGA_BDS_EPH = 0x03; //BDS Ephemeris Assistance -const uint8_t UBX_MGA_BDS_ALM = 0x03; //BDS Almanac Assistance -const uint8_t UBX_MGA_BDS_HEALTH = 0x03; //BDS Health Assistance -const uint8_t UBX_MGA_BDS_UTC = 0x03; //BDS UTC Assistance -const uint8_t UBX_MGA_BDS_IONO = 0x03; //BDS Ionospheric Assistance -const uint8_t UBX_MGA_DBD = 0x80; //Either: Poll the Navigation Database, or Navigation Database Dump Entry -const uint8_t UBX_MGA_GAL_EPH = 0x02; //Galileo Ephemeris Assistance -const uint8_t UBX_MGA_GAL_ALM = 0x02; //Galileo Almanac Assitance -const uint8_t UBX_MGA_GAL_TIMOFFSET = 0x02; //Galileo GPS time offset assistance -const uint8_t UBX_MGA_GAL_UTC = 0x02; //Galileo UTC Assistance -const uint8_t UBX_MGA_GLO_EPH = 0x06; //GLONASS Ephemeris Assistance -const uint8_t UBX_MGA_GLO_ALM = 0x06; //GLONASS Almanac Assistance -const uint8_t UBX_MGA_GLO_TIMEOFFSET = 0x06; //GLONASS Auxiliary Time Offset Assistance -const uint8_t UBX_MGA_GPS_EPH = 0x00; //GPS Ephemeris Assistance -const uint8_t UBX_MGA_GPS_ALM = 0x00; //GPS Almanac Assistance -const uint8_t UBX_MGA_GPS_HEALTH = 0x00; //GPS Health Assistance -const uint8_t UBX_MGA_GPS_UTC = 0x00; //GPS UTC Assistance -const uint8_t UBX_MGA_GPS_IONO = 0x00; //GPS Ionosphere Assistance -const uint8_t UBX_MGA_INI_POS_XYZ = 0x40; //Initial Position Assistance -const uint8_t UBX_MGA_INI_POS_LLH = 0x40; //Initial Position Assitance -const uint8_t UBX_MGA_INI_TIME_UTC = 0x40; //Initial Time Assistance -const uint8_t UBX_MGA_INI_TIME_GNSS = 0x40; //Initial Time Assistance -const uint8_t UBX_MGA_INI_CLKD = 0x40; //Initial Clock Drift Assitance -const uint8_t UBX_MGA_INI_FREQ = 0x40; //Initial Frequency Assistance -const uint8_t UBX_MGA_INI_EOP = 0x40; //Earth Orientation Parameters Assistance -const uint8_t UBX_MGA_QZSS_EPH = 0x05; //QZSS Ephemeris Assistance -const uint8_t UBX_MGA_QZSS_ALM = 0x05; //QZSS Almanac Assistance -const uint8_t UBX_MGA_QZAA_HEALTH = 0x05; //QZSS Health Assistance - -//The following are used to configure the MON UBX messages (monitoring messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 35) -const uint8_t UBX_MON_COMMS = 0x36; //Comm port information -const uint8_t UBX_MON_GNSS = 0x28; //Information message major GNSS selection -const uint8_t UBX_MON_HW2 = 0x0B; //Extended Hardware Status -const uint8_t UBX_MON_HW3 = 0x37; //HW I/O pin information -const uint8_t UBX_MON_HW = 0x09; //Hardware Status -const uint8_t UBX_MON_IO = 0x02; //I/O Subsystem Status -const uint8_t UBX_MON_MSGPP = 0x06; //Message Parse and Process Status -const uint8_t UBX_MON_PATCH = 0x27; //Output information about installed patches -const uint8_t UBX_MON_RF = 0x38; //RF information -const uint8_t UBX_MON_RXBUF = 0x07; //Receiver Buffer Status -const uint8_t UBX_MON_RXR = 0x21; //Receiver Status Information -const uint8_t UBX_MON_TXBUF = 0x08; //Transmitter Buffer Status. Used for query tx buffer size/state. -const uint8_t UBX_MON_VER = 0x04; //Receiver/Software Version. Used for obtaining Protocol Version. - -//The following are used to configure the NAV UBX messages (navigation results messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 35-36) -const uint8_t UBX_NAV_ATT = 0x05; //Vehicle "Attitude" Solution -const uint8_t UBX_NAV_CLOCK = 0x22; //Clock Solution -const uint8_t UBX_NAV_DOP = 0x04; //Dilution of precision -const uint8_t UBX_NAV_EOE = 0x61; //End of Epoch -const uint8_t UBX_NAV_GEOFENCE = 0x39; //Geofencing status. Used to poll the geofence status -const uint8_t UBX_NAV_HPPOSECEF = 0x13; //High Precision Position Solution in ECEF. Used to find our positional accuracy (high precision). -const uint8_t UBX_NAV_HPPOSLLH = 0x14; //High Precision Geodetic Position Solution. Used for obtaining lat/long/alt in high precision -const uint8_t UBX_NAV_ODO = 0x09; //Odometer Solution -const uint8_t UBX_NAV_ORB = 0x34; //GNSS Orbit Database Info -const uint8_t UBX_NAV_POSECEF = 0x01; //Position Solution in ECEF -const uint8_t UBX_NAV_POSLLH = 0x02; //Geodetic Position Solution -const uint8_t UBX_NAV_PVT = 0x07; //All the things! Position, velocity, time, PDOP, height, h/v accuracies, number of satellites. Navigation Position Velocity Time Solution. -const uint8_t UBX_NAV_RELPOSNED = 0x3C; //Relative Positioning Information in NED frame -const uint8_t UBX_NAV_RESETODO = 0x10; //Reset odometer -const uint8_t UBX_NAV_SAT = 0x35; //Satellite Information -const uint8_t UBX_NAV_SIG = 0x43; //Signal Information -const uint8_t UBX_NAV_STATUS = 0x03; //Receiver Navigation Status -const uint8_t UBX_NAV_SVIN = 0x3B; //Survey-in data. Used for checking Survey In status -const uint8_t UBX_NAV_TIMEBDS = 0x24; //BDS Time Solution -const uint8_t UBX_NAV_TIMEGAL = 0x25; //Galileo Time Solution -const uint8_t UBX_NAV_TIMEGLO = 0x23; //GLO Time Solution -const uint8_t UBX_NAV_TIMEGPS = 0x20; //GPS Time Solution -const uint8_t UBX_NAV_TIMELS = 0x26; //Leap second event information -const uint8_t UBX_NAV_TIMEUTC = 0x21; //UTC Time Solution -const uint8_t UBX_NAV_VELECEF = 0x11; //Velocity Solution in ECEF -const uint8_t UBX_NAV_VELNED = 0x12; //Velocity Solution in NED - -//The following are used to configure the RXM UBX messages (receiver manager messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 36) -const uint8_t UBX_RXM_MEASX = 0x14; //Satellite Measurements for RRLP -const uint8_t UBX_RXM_PMREQ = 0x41; //Requests a Power Management task (two differenent packet sizes) -const uint8_t UBX_RXM_RAWX = 0x15; //Multi-GNSS Raw Measurement Data -const uint8_t UBX_RXM_RLM = 0x59; //Galileo SAR Short-RLM report (two different packet sizes) -const uint8_t UBX_RXM_RTCM = 0x32; //RTCM input status -const uint8_t UBX_RXM_SFRBX = 0x13; //Boradcast Navigation Data Subframe - -//The following are used to configure the SEC UBX messages (security feature messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 36) -const uint8_t UBX_SEC_UNIQID = 0x03; //Unique chip ID - -//The following are used to configure the TIM UBX messages (timing messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 36) -const uint8_t UBX_TIM_TM2 = 0x03; //Time mark data -const uint8_t UBX_TIM_TP = 0x01; //Time Pulse Timedata -const uint8_t UBX_TIM_VRFY = 0x06; //Sourced Time Verification - -//The following are used to configure the UPD UBX messages (firmware update messages). Descriptions from UBX messages overview (ZED-F9P Interface Description Document page 36) -const uint8_t UBX_UPD_SOS = 0x14; //Poll Backup Fil Restore Status, Create Backup File in Flash, Clear Backup File in Flash, Backup File Creation Acknowledge, System Restored from Backup - -//The following are used to enable RTCM messages -const uint8_t UBX_RTCM_MSB = 0xF5; //All RTCM enable commands have 0xF5 as MSB -const uint8_t UBX_RTCM_1005 = 0x05; //Stationary RTK reference ARP -const uint8_t UBX_RTCM_1074 = 0x4A; //GPS MSM4 -const uint8_t UBX_RTCM_1077 = 0x4D; //GPS MSM7 -const uint8_t UBX_RTCM_1084 = 0x54; //GLONASS MSM4 -const uint8_t UBX_RTCM_1087 = 0x57; //GLONASS MSM7 -const uint8_t UBX_RTCM_1094 = 0x5E; //Galileo MSM4 -const uint8_t UBX_RTCM_1097 = 0x61; //Galileo MSM7 -const uint8_t UBX_RTCM_1124 = 0x7C; //BeiDou MSM4 -const uint8_t UBX_RTCM_1127 = 0x7F; //BeiDou MSM7 -const uint8_t UBX_RTCM_1230 = 0xE6; //GLONASS code-phase biases, set to once every 10 seconds -const uint8_t UBX_RTCM_4072_0 = 0xFE; //Reference station PVT (ublox proprietary RTCM message) -const uint8_t UBX_RTCM_4072_1 = 0xFD; //Additional reference station information (ublox proprietary RTCM message) - -const uint8_t UBX_ACK_NACK = 0x00; -const uint8_t UBX_ACK_ACK = 0x01; -const uint8_t UBX_ACK_NONE = 0x02; //Not a real value - -// The following constants are used to get External Sensor Measurements and Status -// Information. -const uint8_t UBX_ESF_MEAS = 0x02; -const uint8_t UBX_ESF_RAW = 0x03; -const uint8_t UBX_ESF_STATUS = 0x10; -const uint8_t UBX_ESF_INS = 0x15; //36 bytes - -const uint8_t SVIN_MODE_DISABLE = 0x00; -const uint8_t SVIN_MODE_ENABLE = 0x01; - -//The following consts are used to configure the various ports and streams for those ports. See -CFG-PRT. -const uint8_t COM_PORT_I2C = 0; -const uint8_t COM_PORT_UART1 = 1; -const uint8_t COM_PORT_UART2 = 2; -const uint8_t COM_PORT_USB = 3; -const uint8_t COM_PORT_SPI = 4; - -const uint8_t COM_TYPE_UBX = (1 << 0); -const uint8_t COM_TYPE_NMEA = (1 << 1); -const uint8_t COM_TYPE_RTCM3 = (1 << 5); - -//The following consts are used to generate KEY values for the advanced protocol functions of VELGET/SET/DEL -const uint8_t VAL_SIZE_1 = 0x01; //One bit -const uint8_t VAL_SIZE_8 = 0x02; //One byte -const uint8_t VAL_SIZE_16 = 0x03; //Two bytes -const uint8_t VAL_SIZE_32 = 0x04; //Four bytes -const uint8_t VAL_SIZE_64 = 0x05; //Eight bytes - -//These are the Bitfield layers definitions for the UBX-CFG-VALSET message (not to be confused with Bitfield deviceMask in UBX-CFG-CFG) -const uint8_t VAL_LAYER_RAM = (1 << 0); -const uint8_t VAL_LAYER_BBR = (1 << 1); -const uint8_t VAL_LAYER_FLASH = (1 << 2); - -//Below are various Groups, IDs, and sizes for various settings -//These can be used to call getVal/setVal/delVal -const uint8_t VAL_GROUP_I2COUTPROT = 0x72; -const uint8_t VAL_GROUP_I2COUTPROT_SIZE = VAL_SIZE_1; //All fields in I2C group are currently 1 bit - -const uint8_t VAL_ID_I2COUTPROT_UBX = 0x01; -const uint8_t VAL_ID_I2COUTPROT_NMEA = 0x02; -const uint8_t VAL_ID_I2COUTPROT_RTCM3 = 0x03; - -const uint8_t VAL_GROUP_I2C = 0x51; -const uint8_t VAL_GROUP_I2C_SIZE = VAL_SIZE_8; //All fields in I2C group are currently 1 byte - -const uint8_t VAL_ID_I2C_ADDRESS = 0x01; - -// Configuration Sub-Section mask definitions for saveConfigSelective (UBX-CFG-CFG) -const uint32_t VAL_CFG_SUBSEC_IOPORT = 0x00000001; // ioPort - communications port settings (causes IO system reset!) -const uint32_t VAL_CFG_SUBSEC_MSGCONF = 0x00000002; // msgConf - message configuration -const uint32_t VAL_CFG_SUBSEC_INFMSG = 0x00000004; // infMsg - INF message configuration -const uint32_t VAL_CFG_SUBSEC_NAVCONF = 0x00000008; // navConf - navigation configuration -const uint32_t VAL_CFG_SUBSEC_RXMCONF = 0x00000010; // rxmConf - receiver manager configuration -const uint32_t VAL_CFG_SUBSEC_SENCONF = 0x00000100; // senConf - sensor interface configuration (requires protocol 19+) -const uint32_t VAL_CFG_SUBSEC_RINVCONF = 0x00000200; // rinvConf - remove inventory configuration -const uint32_t VAL_CFG_SUBSEC_ANTCONF = 0x00000400; // antConf - antenna configuration -const uint32_t VAL_CFG_SUBSEC_LOGCONF = 0x00000800; // logConf - logging configuration -const uint32_t VAL_CFG_SUBSEC_FTSCONF = 0x00001000; // ftsConf - FTS configuration (FTS products only) - -// Bitfield wakeupSources for UBX_RXM_PMREQ -const uint32_t VAL_RXM_PMREQ_WAKEUPSOURCE_UARTRX = 0x00000008; // uartrx -const uint32_t VAL_RXM_PMREQ_WAKEUPSOURCE_EXTINT0 = 0x00000020; // extint0 -const uint32_t VAL_RXM_PMREQ_WAKEUPSOURCE_EXTINT1 = 0x00000040; // extint1 -const uint32_t VAL_RXM_PMREQ_WAKEUPSOURCE_SPICS = 0x00000080; // spics - -enum dynModel // Possible values for the dynamic platform model, which provide more accuract position output for the situation. Description extracted from ZED-F9P Integration Manual -{ - DYN_MODEL_PORTABLE = 0, //Applications with low acceleration, e.g. portable devices. Suitable for most situations. - // 1 is not defined - DYN_MODEL_STATIONARY = 2, //Used in timing applications (antenna must be stationary) or other stationary applications. Velocity restricted to 0 m/s. Zero dynamics assumed. - DYN_MODEL_PEDESTRIAN, //Applications with low acceleration and speed, e.g. how a pedestrian would move. Low acceleration assumed. - DYN_MODEL_AUTOMOTIVE, //Used for applications with equivalent dynamics to those of a passenger car. Low vertical acceleration assumed - DYN_MODEL_SEA, //Recommended for applications at sea, with zero vertical velocity. Zero vertical velocity assumed. Sea level assumed. - DYN_MODEL_AIRBORNE1g, //Airborne <1g acceleration. Used for applications with a higher dynamic range and greater vertical acceleration than a passenger car. No 2D position fixes supported. - DYN_MODEL_AIRBORNE2g, //Airborne <2g acceleration. Recommended for typical airborne environments. No 2D position fixes supported. - DYN_MODEL_AIRBORNE4g, //Airborne <4g acceleration. Only recommended for extremely dynamic environments. No 2D position fixes supported. - DYN_MODEL_WRIST, // Not supported in protocol versions less than 18. Only recommended for wrist worn applications. Receiver will filter out arm motion. - DYN_MODEL_BIKE, // Supported in protocol versions 19.2 -}; - -#ifndef MAX_PAYLOAD_SIZE - -#define MAX_PAYLOAD_SIZE 256 //We need ~220 bytes for getProtocolVersion on most ublox modules -//#define MAX_PAYLOAD_SIZE 768 //Worst case: UBX_CFG_VALSET packet with 64 keyIDs each with 64 bit values - -#endif - -//-=-=-=-=- UBX binary specific variables -typedef struct -{ - uint8_t cls; - uint8_t id; - uint16_t len; //Length of the payload. Does not include cls, id, or checksum bytes - uint16_t counter; //Keeps track of number of overall bytes received. Some responses are larger than 255 bytes. - uint16_t startingSpot; //The counter value needed to go past before we begin recording into payload array - uint8_t *payload; - 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 -} ubxPacket; - -// Struct to hold the results returned by getGeofenceState (returned by UBX-NAV-GEOFENCE) -typedef struct -{ - uint8_t status; // Geofencing status: 0 - Geofencing not available or not reliable; 1 - Geofencing active - uint8_t numFences; // Number of geofences - uint8_t combState; // Combined (logical OR) state of all geofences: 0 - Unknown; 1 - Inside; 2 - Outside - uint8_t states[4]; // Geofence states: 0 - Unknown; 1 - Inside; 2 - Outside -} geofenceState; - -// Struct to hold the current geofence parameters -typedef struct -{ - uint8_t numFences; // Number of active geofences - int32_t lats[4]; // Latitudes of geofences (in degrees * 10^-7) - int32_t longs[4]; // Longitudes of geofences (in degrees * 10^-7) - uint32_t rads[4]; // Radii of geofences (in m * 10^-2) -} geofenceParams; - -class SFE_UBLOX_GPS -{ -public: - SFE_UBLOX_GPS(void); - -// A default of 250ms for maxWait seems fine for I2C but is not enough for SerialUSB. -// If you know you are only going to be using I2C / Qwiic communication, you can -// safely reduce defaultMaxWait to 250. -#ifndef defaultMaxWait // Let's allow the user to define their own value if they want to -#define defaultMaxWait 250 // only I2C is used, so this has been reduced from 1100 -#endif - - // Set gpio device, used by checksumFailurePin - bool init_gpio_pins(struct device &gpio_dev); - - //By default use the default I2C address - bool begin(struct device &i2c_dev, uint8_t deviceAddress = 0x42); //Returns true if module is detected - //serialPort needs to be perviously initialized to correct baud rate - //bool begin(Stream &serialPort); //Returns true if module is detected - function not ported - - //Returns true if device answers on _gpsI2Caddress address or via Serial - //maxWait is only used for Serial - bool isConnected(uint16_t maxWait = 1100); - - //Changed in V1.8.1: provides backward compatibility for the examples that call checkUblox directly - //Will default to using packetCfg to look for explicit autoPVT packets so they get processed correctly by processUBX - bool checkUblox(uint8_t requestedClass = UBX_CLASS_NAV, uint8_t requestedID = UBX_NAV_PVT); //Checks module with user selected commType - - bool checkUbloxI2C(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID); //Method for I2C polling of data, passing any new bytes to process() - bool checkUbloxSerial(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID); //Method for serial polling of data, passing any new bytes to process() - - void process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID); //Processes NMEA and UBX binary sentences one byte at a time - 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 processRTCMframe(uint8_t incoming); //Monitor the incoming bytes for start and length bytes - void processRTCM(uint8_t incoming) __attribute__((weak)); //Given rtcm byte, do something with it. User can overwrite if desired to pipe bytes to radio, internet, etc. - - void processUBXpacket(ubxPacket *msg); //Once a packet has been received and validated, identify this packet's class/id and update internal flags - void processNMEA(char incoming) __attribute__((weak)); //Given a NMEA character, do something with it. User can overwrite if desired to use something like tinyGPS or MicroNMEA libraries - - void calcChecksum(ubxPacket *msg); //Sets the checksumA and checksumB of a given messages - sfe_ublox_status_e sendCommand(ubxPacket *outgoingUBX, uint16_t maxWait = defaultMaxWait); //Given a packet and payload, send everything including CRC bytes, return true if we got a response - sfe_ublox_status_e sendI2cCommand(ubxPacket *outgoingUBX, uint16_t maxWait = 250); - void sendSerialCommand(ubxPacket *outgoingUBX); - - void printPacket(ubxPacket *packet); //Useful for debugging - - void factoryReset(); //Send factory reset sequence (i.e. load "default" configuration and perform hardReset) - void hardReset(); //Perform a reset leading to a cold start (zero info start-up) - - int transferWriteI2C(u8_t *buf, u32_t num_bytes, bool stop = true); // Port to Zephyr, i2c function to actualy WRITE data - int transferReadI2C(u8_t *buf, u32_t num_bytes); // Port to Zephyr, i2c function to actualy READ data - - bool setI2CAddress(uint8_t deviceAddress, uint16_t maxTime = 250); //Changes the I2C address of the u-blox module - void setSerialRate(uint32_t baudrate, uint8_t uartPort = COM_PORT_UART1, uint16_t maxTime = defaultMaxWait); //Changes the serial baud rate of the u-blox module, uartPort should be COM_PORT_UART1/2 - void setNMEAOutputPort(); //Sets the internal variable for the port to direct NMEA characters to - - bool setNavigationFrequency(uint8_t navFreq, uint16_t maxWait = defaultMaxWait); //Set the number of nav solutions sent per second - uint8_t getNavigationFrequency(uint16_t maxWait = defaultMaxWait); //Get the number of nav solutions sent per second currently being output by module - bool saveConfiguration(uint16_t maxWait = defaultMaxWait); //Save current configuration to flash and BBR (battery backed RAM) - bool factoryDefault(uint16_t maxWait = defaultMaxWait); //Reset module to factory defaults - bool saveConfigSelective(uint32_t configMask, uint16_t maxWait = defaultMaxWait); //Save the selected configuration sub-sections to flash and BBR (battery backed RAM) - - sfe_ublox_status_e waitForACKResponse(ubxPacket *outgoingUBX, uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime = defaultMaxWait); //Poll the module until a config packet and an ACK is received - sfe_ublox_status_e waitForNoACKResponse(ubxPacket *outgoingUBX, uint8_t requestedClass, uint8_t requestedID, uint16_t maxTime = defaultMaxWait); //Poll the module until a config packet is received - -// getPVT will only return data once in each navigation cycle. By default, that is once per second. -// Therefore we should set getPVTmaxWait to slightly longer than that. -// If you change the navigation frequency to (e.g.) 4Hz using setNavigationFrequency(4) -// then you should use a shorter maxWait for getPVT. 300msec would be about right: getPVT(300) -// The same is true for getHPPOSLLH. -#define getPVTmaxWait 1100 // Default maxWait for getPVT and all functions which call it -#define getHPPOSLLHmaxWait 1100 // Default maxWait for getHPPOSLLH and all functions which call it - - bool assumeAutoPVT(bool enabled, bool implicitUpdate = true); //In case no config access to the GPS is possible and PVT is send cyclically already - bool setAutoPVT(bool enabled, uint16_t maxWait = defaultMaxWait); //Enable/disable automatic PVT reports at the navigation frequency - bool getPVT(uint16_t maxWait = getPVTmaxWait); //Query module for latest group of datums and load global vars: lat, long, alt, speed, SIV, accuracies, etc. If autoPVT is disabled, performs an explicit poll and waits, if enabled does not block. Retruns true if new PVT is available. - bool setAutoPVT(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); //Enable/disable automatic PVT reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update - bool getHPPOSLLH(uint16_t maxWait = getHPPOSLLHmaxWait); //Query module for latest group of datums and load global vars: lat, long, alt, speed, SIV, accuracies, etc. If autoPVT is disabled, performs an explicit poll and waits, if enabled does not block. Retruns true if new PVT is available. - void flushPVT(); //Mark all the PVT data as read/stale. This is handy to get data alignment after CRC failure - - int32_t getLatitude(uint16_t maxWait = getPVTmaxWait); //Returns the current latitude in degrees * 10^-7. Auto selects between HighPrecision and Regular depending on ability of module. - int32_t getLongitude(uint16_t maxWait = getPVTmaxWait); //Returns the current longitude in degrees * 10-7. Auto selects between HighPrecision and Regular depending on ability of module. - int32_t getAltitude(uint16_t maxWait = getPVTmaxWait); //Returns the current altitude in mm above ellipsoid - int32_t getAltitudeMSL(uint16_t maxWait = getPVTmaxWait); //Returns number of sats used in fix - uint8_t getSIV(uint16_t maxWait = getPVTmaxWait); //Returns number of sats used in fix - uint8_t getFixType(uint16_t maxWait = getPVTmaxWait); //Returns the type of fix: 0=no, 3=3D, 4=GNSS+Deadreckoning - uint8_t getCarrierSolutionType(uint16_t maxWait = getPVTmaxWait); //Returns RTK solution: 0=no, 1=float solution, 2=fixed solution - int32_t getGroundSpeed(uint16_t maxWait = getPVTmaxWait); //Returns speed in mm/s - int32_t getHeading(uint16_t maxWait = getPVTmaxWait); //Returns heading in degrees * 10^-7 - uint16_t getPDOP(uint16_t maxWait = getPVTmaxWait); //Returns positional dillution of precision * 10^-2 - uint16_t getYear(uint16_t maxWait = getPVTmaxWait); - uint8_t getMonth(uint16_t maxWait = getPVTmaxWait); - uint8_t getDay(uint16_t maxWait = getPVTmaxWait); - uint8_t getHour(uint16_t maxWait = getPVTmaxWait); - uint8_t getMinute(uint16_t maxWait = getPVTmaxWait); - uint8_t getSecond(uint16_t maxWait = getPVTmaxWait); - uint16_t getMillisecond(uint16_t maxWait = getPVTmaxWait); - int32_t getNanosecond(uint16_t maxWait = getPVTmaxWait); - uint32_t getTimeOfWeek(uint16_t maxWait = getPVTmaxWait); - bool getDateValid(uint16_t maxWait = getPVTmaxWait); - bool getTimeValid(uint16_t maxWait = getPVTmaxWait); - - int32_t getHighResLatitude(uint16_t maxWait = getHPPOSLLHmaxWait); - int8_t getHighResLatitudeHp(uint16_t maxWait = getHPPOSLLHmaxWait); - int32_t getHighResLongitude(uint16_t maxWait = getHPPOSLLHmaxWait); - int8_t getHighResLongitudeHp(uint16_t maxWait = getHPPOSLLHmaxWait); - int32_t getElipsoid(uint16_t maxWait = getHPPOSLLHmaxWait); - int8_t getElipsoidHp(uint16_t maxWait = getHPPOSLLHmaxWait); - int32_t getMeanSeaLevel(uint16_t maxWait = getHPPOSLLHmaxWait); - int8_t getMeanSeaLevelHp(uint16_t maxWait = getHPPOSLLHmaxWait); - int32_t getGeoidSeparation(uint16_t maxWait = getHPPOSLLHmaxWait); - uint32_t getHorizontalAccuracy(uint16_t maxWait = getHPPOSLLHmaxWait); - uint32_t getVerticalAccuracy(uint16_t maxWait = getHPPOSLLHmaxWait); - - //Port configurations - bool setPortOutput(uint8_t portID, uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure a given port to output UBX, NMEA, RTCM3 or a combination thereof - bool setPortInput(uint8_t portID, uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure a given port to input UBX, NMEA, RTCM3 or a combination thereof - bool getPortSettings(uint8_t portID, uint16_t maxWait = defaultMaxWait); //Returns the current protocol bits in the UBX-CFG-PRT command for a given port - - bool setI2COutput(uint8_t comSettings, uint16_t maxWait = 250); //Configure I2C port to output UBX, NMEA, RTCM3 or a combination thereof - bool setUART1Output(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure UART1 port to output UBX, NMEA, RTCM3 or a combination thereof - bool setUART2Output(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure UART2 port to output UBX, NMEA, RTCM3 or a combination thereof - bool setUSBOutput(uint8_t comSettings, uint16_t maxWait = 250); //Configure USB port to output UBX, NMEA, RTCM3 or a combination thereof - bool setSPIOutput(uint8_t comSettings, uint16_t maxWait = 250); //Configure SPI port to output UBX, NMEA, RTCM3 or a combination thereof - - //Functions to turn on/off message types for a given port ID (see COM_PORT_I2C, etc above) - bool configureMessage(uint8_t msgClass, uint8_t msgID, uint8_t portID, uint8_t sendRate, uint16_t maxWait = defaultMaxWait); - bool enableMessage(uint8_t msgClass, uint8_t msgID, uint8_t portID, uint8_t sendRate = 1, uint16_t maxWait = defaultMaxWait); - bool disableMessage(uint8_t msgClass, uint8_t msgID, uint8_t portID, uint16_t maxWait = defaultMaxWait); - bool enableNMEAMessage(uint8_t msgID, uint8_t portID, uint8_t sendRate = 1, uint16_t maxWait = defaultMaxWait); - bool disableNMEAMessage(uint8_t msgID, uint8_t portID, uint16_t maxWait = defaultMaxWait); - bool enableRTCMmessage(uint8_t messageNumber, uint8_t portID, uint8_t sendRate, uint16_t maxWait = defaultMaxWait); //Given a message number turns on a message ID for output over given PortID - bool disableRTCMmessage(uint8_t messageNumber, uint8_t portID, uint16_t maxWait = defaultMaxWait); //Turn off given RTCM message from a given port - - //General configuration (used only on protocol v27 and higher - ie, ZED-F9P) - //It is probably safe to assume that users ofovaj the ZED-F9P will be using I2C / Qwiic. - //If they are using Serial then the higher baud rate will also help. So let's leave maxWait set to 250ms. - uint8_t getVal8(uint16_t group, uint16_t id, uint8_t size, uint8_t layer = VAL_LAYER_BBR, uint16_t maxWait = 250); //Returns the value at a given group/id/size location - uint8_t getVal8(uint32_t keyID, uint8_t layer = VAL_LAYER_BBR, uint16_t maxWait = 250); //Returns the value at a given group/id/size location - uint8_t setVal(uint32_t keyID, uint16_t value, uint8_t layer = VAL_LAYER_BBR, uint16_t maxWait = 250); //Sets the 16-bit value at a given group/id/size location - uint8_t setVal8(uint32_t keyID, uint8_t value, uint8_t layer = VAL_LAYER_BBR, uint16_t maxWait = 250); //Sets the 8-bit value at a given group/id/size location - uint8_t setVal16(uint32_t keyID, uint16_t value, uint8_t layer = VAL_LAYER_BBR, uint16_t maxWait = 250); //Sets the 16-bit value at a given group/id/size location - uint8_t setVal32(uint32_t keyID, uint32_t value, uint8_t layer = VAL_LAYER_BBR, uint16_t maxWait = 250); //Sets the 32-bit value at a given group/id/size location - uint8_t newCfgValset8(uint32_t keyID, uint8_t value, uint8_t layer = VAL_LAYER_BBR); //Define a new UBX-CFG-VALSET with the given KeyID and 8-bit value - uint8_t newCfgValset16(uint32_t keyID, uint16_t value, uint8_t layer = VAL_LAYER_BBR); //Define a new UBX-CFG-VALSET with the given KeyID and 16-bit value - uint8_t newCfgValset32(uint32_t keyID, uint32_t value, uint8_t layer = VAL_LAYER_BBR); //Define a new UBX-CFG-VALSET with the given KeyID and 32-bit value - uint8_t addCfgValset8(uint32_t keyID, uint8_t value); //Add a new KeyID and 8-bit value to an existing UBX-CFG-VALSET ubxPacket - uint8_t addCfgValset16(uint32_t keyID, uint16_t value); //Add a new KeyID and 16-bit value to an existing UBX-CFG-VALSET ubxPacket - uint8_t addCfgValset32(uint32_t keyID, uint32_t value); //Add a new KeyID and 32-bit value to an existing UBX-CFG-VALSET ubxPacket - uint8_t sendCfgValset8(uint32_t keyID, uint8_t value, uint16_t maxWait = 250); //Add the final KeyID and 8-bit value to an existing UBX-CFG-VALSET ubxPacket and send it - uint8_t sendCfgValset16(uint32_t keyID, uint16_t value, uint16_t maxWait = 250); //Add the final KeyID and 16-bit value to an existing UBX-CFG-VALSET ubxPacket and send it - uint8_t sendCfgValset32(uint32_t keyID, uint32_t value, uint16_t maxWait = 250); //Add the final KeyID and 32-bit value to an existing UBX-CFG-VALSET ubxPacket and send it - - //Functions used for RTK and base station setup - //It is probably safe to assume that users of the RTK will be using I2C / Qwiic. So let's leave maxWait set to 250ms. - bool getSurveyMode(uint16_t maxWait = 250); //Get the current TimeMode3 settings - bool setSurveyMode(uint8_t mode, uint16_t ovajobservationTime, float requiredAccuracy, uint16_t maxWait = 250); //Control survey in mode - bool enableSurveyMode(uint16_t observationTime, float requiredAccuracy, uint16_t maxWait = 250); //Begin Survey-In for NEO-M8P - bool disableSurveyMode(uint16_t maxWait = 250); //Stop Survey-In mode - - bool getSurveyStatus(uint16_t maxWait); //Reads survey in status and sets the global variables - - uint32_t getPositionAccuracy(uint16_t maxWait = 1100); //Returns the 3D accuracy of the current high-precision fix, in mm. Supported on NEO-M8P, ZED-F9P, - - uint8_t getProtocolVersionHigh(uint16_t maxWait = 500); //Returns the PROTVER XX.00 from UBX-MON-VER register - uint8_t getProtocolVersionLow(uint16_t maxWait = 500); //Returns the PROTVER 00.XX from UBX-MON-VER register - bool getProtocolVersion(uint16_t maxWait = 500); //Queries module, loads low/high bytes - - bool getRELPOSNED(uint16_t maxWait = 1100); //Get Relative Positioning Information of the NED frame - - void enableDebugging(bool printLimitedDebug = false); //Given a port to print to, enable debug messages. Default to all, not limited. - void disableDebugging(void); //Turn off debug statements - void debugPrint(char *message); //Safely print debug statements - void debugPrintln(char *message); //Safely print debug statements - const char *statusString(sfe_ublox_status_e stat); //Pretty print the return value - - //Support for geofences - bool addGeofence(int32_t latitude, int32_t longitude, uint32_t radius, uint8_t confidence = 0, uint8_t pinPolarity = 0, uint8_t pin = 0, uint16_t maxWait = 1100); // Add a new geofence - bool clearGeofences(uint16_t maxWait = 1100); //Clears all geofences - bool getGeofenceState(geofenceState ¤tGeofenceState, uint16_t maxWait = 1100); //Returns the combined geofence state - bool clearAntPIO(uint16_t maxWait = 1100); //Clears the antenna control pin settings to release the PIOs - geofenceParams currentGeofenceParams; // Global to store the geofence parameters - - bool powerSaveMode(bool power_save = true, uint16_t maxWait = 1100); - uint8_t getPowerSaveMode(uint16_t maxWait = 1100); // Returns 255 if the sendCommand fails - bool powerOff(uint32_t durationInMs, uint16_t maxWait = 1100); - bool powerOffWithInterrupt(uint32_t durationInMs, uint32_t wakeupSources = VAL_RXM_PMREQ_WAKEUPSOURCE_EXTINT0, bool forceWhileUsb = true, uint16_t maxWait = 1100); - - //Change the dynamic platform model using UBX-CFG-NAV5 - bool setDynamicModel(dynModel newDynamicModel = DYN_MODEL_PORTABLE, uint16_t maxWait = 1100); - uint8_t getDynamicModel(uint16_t maxWait = 1100); // Get the dynamic model - returns 255 if the sendCommand fails - - bool getEsfInfo(uint16_t maxWait = 1100); - bool getEsfIns(uint16_t maxWait = 1100); - bool getEsfDataInfo(uint16_t maxWait = 1100); - bool getEsfRawDataInfo(uint16_t maxWait = 1100); - sfe_ublox_status_e getSensState(uint8_t sensor, uint16_t maxWait = 1100); - bool getVehAtt(uint16_t maxWait = 1100); - - //Survey-in specific controls - struct svinStructure - { - bool active; - bool valid; - uint16_t observationTime; - float meanAccuracy; - } svin; - - //Relative Positioning Info in NED frame specific controls - struct frelPosInfoStructure - { - uint16_t refStationID; - - float relPosN; - float relPosE; - float relPosD; - - long relPosLength; - long relPosHeading; - - int8_t relPosHPN; - int8_t relPosHPE; - int8_t relPosHPD; - int8_t relPosHPLength; - - float accN; - float accE; - float accD; - - bool gnssFixOk; - bool diffSoln; - bool relPosValid; - uint8_t carrSoln; - bool isMoving; - bool refPosMiss; - bool refObsMiss; - } relPosInfo; - - //The major datums we want to globally store - uint16_t gpsYear; - uint8_t gpsMonth; - uint8_t gpsDay; - uint8_t gpsHour; - uint8_t gpsMinute; - uint8_t gpsSecond; - uint16_t gpsMillisecond; - int32_t gpsNanosecond; - bool gpsDateValid; - bool gpsTimeValid; - - int32_t latitude; //Degrees * 10^-7 (more accurate than floats) - int32_t longitude; //Degrees * 10^-7 (more accurate than floats) - int32_t altitude; //Number of mm above ellipsoid - int32_t altitudeMSL; //Number of mm above Mean Sea Level - uint8_t SIV; //Number of satellites used in position solution - uint8_t fixType; //Tells us when we have a solution aka lock - uint8_t carrierSolution; //Tells us when we have an RTK float/fixed solution - int32_t groundSpeed; //mm/s - int32_t headingOfMotion; //degrees * 10^-5 - uint16_t pDOP; //Positional dilution of precision - uint8_t versionLow; //Loaded from getProtocolVersion(). - uint8_t versionHigh; - - uint32_t timeOfWeek; // ms - int32_t highResLatitude; // Degrees * 10^-7 - int32_t highResLongitude; // Degrees * 10^-7 - int32_t elipsoid; // Height above ellipsoid in mm (Typo! Should be eLLipsoid! **Uncorrected for backward-compatibility.**) - int32_t meanSeaLevel; // Height above mean sea level in mm - int32_t geoidSeparation; // This seems to only be provided in NMEA GGA and GNS messages - uint32_t horizontalAccuracy; // mm * 10^-1 (i.e. 0.1mm) - uint32_t verticalAccuracy; // mm * 10^-1 (i.e. 0.1mm) - int8_t elipsoidHp; // High precision component of the height above ellipsoid in mm * 10^-1 (Deliberate typo! Should be eLLipsoidHp!) - int8_t meanSeaLevelHp; // High precision component of Height above mean sea level in mm * 10^-1 - int8_t highResLatitudeHp; // High precision component of latitude: Degrees * 10^-9 - int8_t highResLongitudeHp; // High precision component of longitude: Degrees * 10^-9 - - uint16_t rtcmFrameCounter = 0; //Tracks the type of incoming byte inside RTCM frame - -#define DEF_NUM_SENS 7 - struct deadReckData - { - uint8_t version; - uint8_t fusionMode; - - uint8_t xAngRateVald; - uint8_t yAngRateVald; - uint8_t zAngRateVald; - uint8_t xAccelVald; - uint8_t yAccelVald; - uint8_t zAccelVald; - - int32_t xAngRate; - int32_t yAngRate; - int32_t zAngRate; - - int32_t xAccel; - int32_t yAccel; - int32_t zAccel; - - // The array size is based on testing directly on M8U and F9R - uint32_t rawData; - uint32_t rawDataType; - uint32_t rawTStamp; - - uint32_t data[DEF_NUM_SENS]; - uint32_t dataType[DEF_NUM_SENS]; - uint32_t dataTStamp[DEF_NUM_SENS]; - } imuMeas; - - struct indivImuData - { - - uint8_t numSens; - - uint8_t senType; - bool isUsed; - bool isReady; - uint8_t calibStatus; - uint8_t timeStatus; - - uint8_t freq; // Hz - - bool badMeas; - bool badTag; - bool missMeas; - bool noisyMeas; - } ubloxSen; - - struct vehicleAttitude - { - // All values in degrees - int32_t roll; - int32_t pitch; - int32_t heading; - uint32_t accRoll; - uint32_t accPitch; - uint32_t accHeading; - } vehAtt; - -private: - //Depending on the sentence type the processor will load characters into different arrays - enum SentenceTypes - { - NONE = 0, - NMEA, - UBX, - RTCM - } currentSentence = NONE; - - //Depending on the ubx binary response class, store binary responses into different places - enum classTypes - { - CLASS_NONE = 0, - CLASS_ACK, - CLASS_NOT_AN_ACK - } ubxFrameClass = CLASS_NONE; - - enum commTypes - { - COMM_TYPE_I2C = 0, - COMM_TYPE_SERIAL, - COMM_TYPE_SPI - } commType = COMM_TYPE_I2C; //Controls which port we look to for incoming bytes - - //Functions - bool checkUbloxInternal(ubxPacket *incomingUBX, uint8_t requestedClass = 255, uint8_t requestedID = 255); //Checks module with user selected commType - uint32_t extractLong(uint8_t spotToStart); //Combine four bytes from payload into long - uint16_t extractInt(uint8_t spotToStart); //Combine two bytes from payload into int - uint8_t extractByte(uint8_t spotToStart); //Get byte from payload - int8_t extractSignedChar(uint8_t spotToStart); //Get signed 8-bit value from payload - void addToChecksum(uint8_t incoming); //Given an incoming byte, adjust rollingChecksumA/B - - //Variables - struct device *_gpio_dev; // GPIO device - struct device *_i2cPort; //The generic connection to user's chosen I2C hardware - //Stream *_serialPort; //The generic connection to user's chosen Serial hardware - bool _nmeaOutputPort = false; //The user can assign an output port to print NMEA sentences if they wish - ported to print to console, converted to flag - //Stream *_debugSerial; //The stream to send debug messages to if enabled - - 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 - - bool _printDebug = false; //Flag to print the serial commands we are sending to the Serial port for debug - bool _printLimitedDebug = false; //Flag to print limited debug messages. Useful for I2C debugging or high navigation rates - - //The packet buffers - //These are pointed at from within the ubxPacket - uint8_t payloadAck[2]; // Holds the requested ACK/NACK - uint8_t payloadCfg[MAX_PAYLOAD_SIZE]; // Holds the requested data packet - uint8_t payloadBuf[2]; // Temporary buffer used to screen incoming packets or dump unrequested packets - - //Init the packet structures and init them with pointers to the payloadAck, payloadCfg and payloadBuf arrays - ubxPacket packetAck = {0, 0, 0, 0, 0, payloadAck, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; - ubxPacket packetCfg = {0, 0, 0, 0, 0, payloadCfg, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; - ubxPacket packetBuf = {0, 0, 0, 0, 0, payloadBuf, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; - - //Flag if this packet is unrequested (and so should be ignored and not copied into packetCfg or packetAck) - bool ignoreThisPayload = false; - - //Identify which buffer is in use - //Data is stored in packetBuf until the requested class and ID can be validated - //If a match is seen, data is diverted into packetAck or packetCfg - sfe_ublox_packet_buffer_e activePacketBuffer = SFE_UBLOX_PACKET_PACKETBUF; - - //Limit checking of new data to every X ms - //If we are expecting an update every X Hz then we should check every half that amount of time - //Otherwise we may block ourselves from seeing new data - uint8_t i2cPollingWait = 100; //Default to 100ms. Adjusted when user calls setNavigationFrequency() - - unsigned long lastCheck = 0; - bool autoPVT = false; //Whether autoPVT is enabled or not - bool autoPVTImplicitUpdate = true; // Whether autoPVT is triggered by accessing stale data (=true) or by a call to checkUblox (=false) - uint16_t ubxFrameCounter; //It counts all UBX frame. [Fixed header(2bytes), CLS(1byte), ID(1byte), length(2bytes), payload(x bytes), checksums(2bytes)] - - uint8_t rollingChecksumA; //Rolls forward as we receive incoming bytes. Checked against the last two A/B checksum bytes - uint8_t rollingChecksumB; //Rolls forward as we receive incoming bytes. Checked against the last two A/B checksum bytes - - //Create bit field for staleness of each datum in PVT we want to monitor - //moduleQueried.latitude goes true each time we call getPVT() - //This reduces the number of times we have to call getPVT as this can take up to ~1s per read - //depending on update rate - struct - { - uint32_t gpsiTOW : 1; - uint32_t gpsYear : 1; - uint32_t gpsMonth : 1; - uint32_t gpsDay : 1; - uint32_t gpsHour : 1; - uint32_t gpsMinute : 1; - uint32_t gpsSecond : 1; - uint32_t gpsDateValid : 1; - uint32_t gpsTimeValid : 1; - uint32_t gpsNanosecond : 1; - - uint32_t all : 1; - uint32_t longitude : 1; - uint32_t latitude : 1; - uint32_t altitude : 1; - uint32_t altitudeMSL : 1; - uint32_t SIV : 1; - uint32_t fixType : 1; - uint32_t carrierSolution : 1; - uint32_t groundSpeed : 1; - uint32_t headingOfMotion : 1; - uint32_t pDOP : 1; - uint32_t versionNumber : 1; - } moduleQueried; - - struct - { - uint16_t all : 1; - uint16_t timeOfWeek : 1; - uint16_t highResLatitude : 1; - uint16_t highResLongitude : 1; - uint16_t elipsoid : 1; - uint16_t meanSeaLevel : 1; - uint16_t geoidSeparation : 1; // Redundant but kept for backward-compatibility - uint16_t horizontalAccuracy : 1; - uint16_t verticalAccuracy : 1; - uint16_t elipsoidHp : 1; - uint16_t meanSeaLevelHp : 1; - uint16_t highResLatitudeHp : 1; - uint16_t highResLongitudeHp : 1; - } highResModuleQueried; - - uint16_t rtcmLen = 0; -}; - -#endif //SPARKFUN_UBLOX_ZEPHYR_LIBRARY_H diff --git a/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/src/main.c b/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/src/main.c deleted file mode 100644 index 2945c21..0000000 --- a/examples/Zephyr/Example1_GetPositionAndTime_Zephyr/src/main.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - Reading lat, long and UTC time via UBX binary commands - By: Nathan Seidle - SparkFun Electronics - Date: August 22nd, 2018 - License: MIT. See license file for more information but you can - basically do whatever you want with this code. - - This example reads the NMEA setences from the u-blox module over I2c and outputs - them to the serial port - - Open the serial monitor at 115200 baud to see the output - I2C clock speed: 100 kHz - - Ported to Zephyr by Vid Rajtmajer , www.irnas.eu - - Development environment specifics: NCS v1.0.3 release - - To build: west build -b -p Can also read NMEA sentences over I2C with check_ublox function - To flash: west flash --erase -*/ -#include -#include -#include -#include -#include - -#include "SparkFun_Ublox_Zephyr_Interface.h" - - -#define I2C_DEV "I2C_0" - -struct device *gpio_dev; -struct device *i2c_dev; -/* I2C pins used are defaults for I2C_0 on nrf52840 - SDA: 26 - SCL: 27 -*/ - -uint8_t init_gpio(void) { - const char* gpioName = "GPIO_0"; - gpio_dev = device_get_binding(gpioName); - if (gpio_dev == NULL) { - printk("Error: Could not get %s device\n", gpioName); - return -EIO; - } - int err = set_gpio_dev(gpio_dev, true); // set GPIO_0 device and enable debugging - if (err) { - return -EIO; - } - return 0; -} - -uint8_t init_i2c(void) { - i2c_dev = device_get_binding(I2C_DEV); - if (!i2c_dev) - { - printk("I2C_0 error\n"); - return -1; - } - else - { - printk("I2C_0 Init OK\n"); - return 0; - } -} - -uint8_t init_gps(void) { - if (gps_begin(i2c_dev) != 0) - { - printk("u-blox GPS init error!\n"); - return -1; - } - return 0; -} - - -void main(void) { - printk("Zephyr u-blox example\n"); - - int err; - err = init_gpio(); - if (err) { - return; - } - err = init_i2c(); - if (err) { - return; - } - - err = init_gps(); - if (err) { - return; - } - - while(1) { - //check_ublox(); // See if new data is available. Process bytes as they come in. - get_position(); - get_datetime(); - k_msleep(250); // Don't pound too hard on the I2C bus - } -} \ No newline at end of file