diff --git a/examples/ZED-F9P/Example15_downloadDeviceConfig/Example15_downloadDeviceConfig.ino b/examples/ZED-F9P/Example15_downloadDeviceConfig/Example15_downloadDeviceConfig.ino new file mode 100644 index 0000000..d828185 --- /dev/null +++ b/examples/ZED-F9P/Example15_downloadDeviceConfig/Example15_downloadDeviceConfig.ino @@ -0,0 +1,63 @@ +/* + Download the entire configuration of a module + By: SparkFun Electronics / Nathan Seidle + Date: May 19th, 2021 + License: MIT. See license file for more information but you can + basically do whatever you want with this code. + + This example shows how to download the entire ZED configuration and display + it over serial. This same data can be piped to an SD card or other text file + that can later be opened by u-center or by the uploadDeviceConfig() function. + + 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 + + Hardware Connections: + Plug a Qwiic cable into the GNSS 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 GNSS + +#include //http://librarymanager/All#SparkFun_u-blox_GNSS +SFE_UBLOX_GNSS myGNSS; + +void setup() +{ + Serial.begin(115200); // You may need to increase this for high navigation rates! + while (!Serial) + ; //Wait for user to open terminal + Serial.println(F("SparkFun u-blox Example")); + + Wire.begin(); + + //myGNSS.enableDebugging(); // Uncomment this line to enable debug messages + + if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port + { + Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing.")); + while (1) + ; + } + + myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise) + + myGNSS.setPacketCfgPayloadSize(1024); //Increase max payload to allow for 580 byte key responses + + //Basic call - Output config file to Serial + myGNSS.downloadDeviceConfig(); + + //Stream - Download config data to Serial. This can also be an SD file. + //layer - Read the RAM layer. Currently only RAM layer is tested. + //maxWait - Device can take up to 1000ms to respond with keys + //downloadDeviceConfig(Serial, VAL_LAYER_RAM, 1000); + + Serial.println("Config read complete!"); +} + +void loop() +{ +} \ No newline at end of file diff --git a/keywords.txt b/keywords.txt index b2b7cab..24b22ce 100644 --- a/keywords.txt +++ b/keywords.txt @@ -164,6 +164,7 @@ addCfgValset32 KEYWORD2 sendCfgValset8 KEYWORD2 sendCfgValset16 KEYWORD2 sendCfgValset32 KEYWORD2 +downloadDeviceConfig KEYWORD2 getNAVPOSECEF KEYWORD2 setAutoNAVPOSECEF KEYWORD2 diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index bc45a0c..8879910 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -464,11 +464,11 @@ void SFE_UBLOX_GNSS::setI2CpollingWait(uint8_t newPollingWait_ms) //Most platforms use 32 bytes (the default) but this allows users to increase the transaction //size if the platform supports it //Note: If the transaction size is set larger than the platforms buffer size, bad things will happen. -void SFE_UBLOX_GNSS::setI2CTransactionSize(uint8_t transactionSize) +void SFE_UBLOX_GNSS::setI2CTransactionSize(uint16_t transactionSize) { i2cTransactionSize = transactionSize; } -uint8_t SFE_UBLOX_GNSS::getI2CTransactionSize(void) +uint16_t SFE_UBLOX_GNSS::getI2CTransactionSize(void) { return (i2cTransactionSize); } @@ -2728,7 +2728,7 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::sendI2cCommand(ubxPacket *outgoingUBX, uint16 uint16_t startSpot = 0; while (bytesToSend > 1) { - uint8_t len = bytesToSend; + uint16_t len = bytesToSend; if (len > i2cTransactionSize) len = i2cTransactionSize; @@ -4818,7 +4818,7 @@ uint32_t SFE_UBLOX_GNSS::createKey(uint16_t group, uint16_t id, uint8_t size) //This function takes a full 32-bit key //Default layer is RAM //Configuration of modern u-blox modules is now done via getVal/setVal/delVal, ie protocol v27 and above found on ZED-F9P -sfe_ublox_status_e SFE_UBLOX_GNSS::getVal(uint32_t key, uint8_t layer, uint16_t maxWait) +sfe_ublox_status_e SFE_UBLOX_GNSS::getVal(uint32_t key, uint8_t layer, uint16_t skipAmt, uint16_t maxWait) { packetCfg.cls = UBX_CLASS_CFG; packetCfg.id = UBX_CFG_VALGET; @@ -4842,6 +4842,9 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::getVal(uint32_t key, uint8_t layer, uint16_t payloadCfg[0] = 0; //Message Version - set to 0 payloadCfg[1] = getLayer; //Layer + payloadCfg[2] = skipAmt >> 8 * 0; //Position - skip this many key values + payloadCfg[3] = skipAmt >> 8 * 1; + //Load key into outgoing payload payloadCfg[4] = key >> 8 * 0; //Key LSB payloadCfg[5] = key >> 8 * 1; @@ -4878,21 +4881,21 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::getVal(uint32_t key, uint8_t layer, uint16_t //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_GNSS::getVal8(uint32_t key, uint8_t layer, uint16_t maxWait) { - if (getVal(key, layer, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) + if (getVal(key, layer, 0, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) return (0); return (extractByte(&packetCfg, 8)); } uint16_t SFE_UBLOX_GNSS::getVal16(uint32_t key, uint8_t layer, uint16_t maxWait) { - if (getVal(key, layer, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) + if (getVal(key, layer, 0, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) return (0); return (extractInt(&packetCfg, 8)); } uint32_t SFE_UBLOX_GNSS::getVal32(uint32_t key, uint8_t layer, uint16_t maxWait) { - if (getVal(key, layer, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) + if (getVal(key, layer, 0, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) return (0); return (extractLong(&packetCfg, 8)); @@ -4926,6 +4929,31 @@ uint8_t SFE_UBLOX_GNSS::setVal(uint32_t key, uint16_t value, uint8_t layer, uint return setVal16(key, value, layer, maxWait); } +//Given an array of data (most likely from a config file) push using valSet +uint8_t SFE_UBLOX_GNSS::setVal(uint8_t* value, uint16_t len, uint8_t layer, uint16_t maxWait) +{ + packetCfg.cls = UBX_CLASS_CFG; + packetCfg.id = UBX_CFG_VALSET; + packetCfg.len = 4 + len; //4 byte header, *no* key ID, len bytes of raw data + packetCfg.startingSpot = 0; + + //Clear packet payload + memset(payloadCfg, 0, packetCfg.len); + + payloadCfg[0] = 1; //Message Version - set to 1 + payloadCfg[1] = layer; //By default we ask for the RAM layer + + // payloadCfg[2] = skipAmt >> 8 * 0; //Position - skip this many key values + // payloadCfg[3] = skipAmt >> 8 * 1; + + //Copy data into payload + for(uint16_t x = 0 ; x < len ; x++) + payloadCfg[4 + x] = value[x]; + + //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 16-bit value //This function takes a full 32-bit key //Default layer is all: RAM+BBR+Flash @@ -5211,6 +5239,59 @@ uint8_t SFE_UBLOX_GNSS::sendCfgValset8(uint32_t key, uint8_t value, uint16_t max return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK } +//u-center reads 19 queries, 64 keys obtained in each query for 1216 keys +//Format the output to match the config files that u-center can understand +//Layer number can be 0 (RAM) or layer 7 (Default) +void SFE_UBLOX_GNSS::downloadDeviceConfig(Stream &downloadPort, uint8_t layerNumber, uint16_t maxWait) +{ + const uint16_t keysToObtain = 1216; + const uint16_t keysPerQuery = 64; + const uint16_t loops = keysToObtain / keysPerQuery; + + const uint32_t keyIDRequestAll = 0x0FFF0000; //KeyID of 0x0FFF0000 is request for all items known to the receiver in all groups. + + for (uint16_t x = 0; x < loops; x++) + { + + //Advance by keysPerQuery keys each time + if (getVal(keyIDRequestAll, layerNumber, x * keysPerQuery, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) + { + //Try again + if (getVal(keyIDRequestAll, layerNumber, x * keysPerQuery, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) + { + if (_printDebug == true) + { + _debugSerial->println(F("downloadDeviceConfig: Failed to obtain config data.")); + } + } + } + + //All lines start with a VALGET + downloadPort.print(F("CFG-VALGET - 06 8B ")); + + //Pretty print the response length + uint16_t responseLength = packetCfg.len; + if ((responseLength & 0xFF) < 0x10) + downloadPort.print(F("0")); + downloadPort.print(responseLength & 0xFF, HEX); + downloadPort.print(F(" ")); + if ((responseLength >> 8) < 0x10) + downloadPort.print(F("0")); + downloadPort.print(responseLength >> 8, HEX); + + //Pretty print the payload + for (int x = 0; x < packetCfg.len; x++) + { + downloadPort.print(F(" ")); + if (payloadCfg[x] < 0x10) + downloadPort.print(F("0")); + downloadPort.print(payloadCfg[x], HEX); + } + downloadPort.println(); + } +} + + //=-=-=-=-=-=-=-= "Automatic" Messages =-=-=-=-=-=-=-==-=-=-=-=-=-=-= //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.h b/src/SparkFun_u-blox_GNSS_Arduino_Library.h index 42e72eb..7326996 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.h +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.h @@ -566,11 +566,11 @@ class SFE_UBLOX_GNSS void setI2CpollingWait(uint8_t newPollingWait_ms); // Allow the user to change the I2C polling wait if required //Control the size of the internal I2C transaction amount - void setI2CTransactionSize(uint8_t bufferSize); - uint8_t getI2CTransactionSize(void); + void setI2CTransactionSize(uint16_t bufferSize); + uint16_t getI2CTransactionSize(void); //Set the max number of bytes set in a given I2C transaction - uint8_t i2cTransactionSize = 32; //Default to ATmega328 limit + uint16_t i2cTransactionSize = 32; //Default to ATmega328 limit //Returns true if device answers on _gpsI2Caddress address or via Serial boolean isConnected(uint16_t maxWait = 1100); @@ -747,7 +747,7 @@ class SFE_UBLOX_GNSS //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. uint32_t createKey(uint16_t group, uint16_t id, uint8_t size); //Form 32-bit key from group/id/size - sfe_ublox_status_e getVal(uint32_t keyID, uint8_t layer = VAL_LAYER_RAM, uint16_t maxWait = 250); //Load payload with response + sfe_ublox_status_e getVal(uint32_t keyID, uint8_t layer = VAL_LAYER_RAM, uint16_t skipAmt = 0, uint16_t maxWait = 250); //Load payload with response uint8_t getVal8(uint32_t keyID, uint8_t layer = VAL_LAYER_RAM, uint16_t maxWait = 250); //Returns the value at a given key location uint16_t getVal16(uint32_t keyID, uint8_t layer = VAL_LAYER_RAM, uint16_t maxWait = 250); //Returns the value at a given key location uint32_t getVal32(uint32_t keyID, uint8_t layer = VAL_LAYER_RAM, uint16_t maxWait = 250); //Returns the value at a given key location @@ -755,6 +755,7 @@ class SFE_UBLOX_GNSS uint16_t getVal16(uint16_t group, uint16_t id, uint8_t size, uint8_t layer = VAL_LAYER_RAM, uint16_t maxWait = 250); //Returns the value at a given group/id/size location uint32_t getVal32(uint16_t group, uint16_t id, uint8_t size, uint8_t layer = VAL_LAYER_RAM, 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_ALL, uint16_t maxWait = 250); //Sets the 16-bit value at a given group/id/size location + uint8_t setVal(uint8_t *values, uint16_t len, uint8_t layer = VAL_LAYER_RAM, uint16_t maxWait = 250); //Send an array of keys and values uint8_t setVal8(uint32_t keyID, uint8_t value, uint8_t layer = VAL_LAYER_ALL, 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_ALL, 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_ALL, uint16_t maxWait = 250); //Sets the 32-bit value at a given group/id/size location @@ -767,6 +768,7 @@ class SFE_UBLOX_GNSS 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 + void downloadDeviceConfig(Stream &port = Serial, uint8_t layerNumber = VAL_LAYER_RAM, uint16_t maxWait = 1000); //Pipe entire device's config data to a user chosen stream // getPVT will only return data once in each navigation cycle. By default, that is once per second. // Therefore we should set defaultMaxWait to slightly longer than that.