Add setDynamicSPARTNKeys. Update Example19

This commit is contained in:
PaulZC
2022-02-11 15:01:41 +00:00
parent b70cb1ceac
commit 213d29cafe
3 changed files with 220 additions and 28 deletions
@@ -10,6 +10,9 @@
This is a proof of concept to show how the UBX-RXM-PMP corrections control the accuracy.
You will need a Thingstream PointPerfect account to be able to access the SPARTN Credentials (IP Dynamic Keys).
Copy and paste the Current Key and Next Key into secrets.h.
Feel like supporting open source hardware?
Buy a board from SparkFun!
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
@@ -21,6 +24,8 @@
Open the serial monitor at 115200 baud to see the output
*/
#include "secrets.h" // <- Copy and paste the Current Key and Next Key into secrets.h
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS; // ZED-F9x
SFE_UBLOX_GNSS myLBand; // NEO-D9S
@@ -141,17 +146,28 @@ void setup()
}
Serial.println(F("u-blox GNSS module connected"));
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
myGNSS.setPortInput(COM_PORT_I2C, COM_TYPE_UBX | COM_TYPE_NMEA | COM_TYPE_SPARTN); //Be sure SPARTN input is enabled
uint8_t ok = myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
if (ok) ok = myGNSS.setPortInput(COM_PORT_I2C, COM_TYPE_UBX | COM_TYPE_NMEA | COM_TYPE_SPARTN); //Be sure SPARTN input is enabled
myGNSS.setDGNSSConfiguration(SFE_UBLOX_DGNSS_MODE_FIXED); // Set the differential mode - ambiguities are fixed whenever possible
if (ok) ok = myGNSS.setDGNSSConfiguration(SFE_UBLOX_DGNSS_MODE_FIXED); // Set the differential mode - ambiguities are fixed whenever possible
myGNSS.setNavigationFrequency(1); //Set output in Hz.
if (ok) ok = myGNSS.setNavigationFrequency(1); //Set output in Hz.
//Configure the SPARTN IP Dynamic Keys
//"When the receiver boots, the host should send 'current' and 'next' keys in one message." - Use setDynamicSPARTNKeys for this.
//"Every time the 'current' key is expired, 'next' takes its place."
//"Therefore the host should then retrieve the new 'next' key and send only that." - Use setDynamicSPARTNKey for this.
// The key can be provided in binary format or in ASCII Hex format, but in both cases keyLengthBytes _must_ represent the binary key length in bytes.
if (ok) ok = myGNSS.setDynamicSPARTNKeys(currentKeyLengthBytes, currentKeyGPSWeek, currentKeyGPSToW, currentDynamicKey,
nextKeyLengthBytes, nextKeyGPSWeek, nextKeyGPSToW, nextDynamicKey);
//if (ok) ok = myGNSS.saveConfiguration(VAL_CFG_SUBSEC_IOPORT | VAL_CFG_SUBSEC_MSGCONF); //Optional: Save the ioPort and message settings to NVM
Serial.print(F("GNSS: configuration "));
Serial.println(OK(ok));
myGNSS.setAutoPVTcallbackPtr(&printPVTdata); // Enable automatic NAV PVT messages with callback to printPVTdata so we can watch the carrier solution go to fixed
//myGNSS.saveConfiguration(VAL_CFG_SUBSEC_IOPORT | VAL_CFG_SUBSEC_MSGCONF); //Optional: Save the ioPort and message settings to NVM
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Begin and configure the NEO-D9S L-Band receiver
@@ -164,7 +180,7 @@ void setup()
}
Serial.println(F("u-blox NEO-D9S connected"));
uint8_t ok = myLBand.setVal32(UBLOX_CFG_PMP_CENTER_FREQUENCY, myLBandFreq); // Default 1539812500 Hz
ok = myLBand.setVal32(UBLOX_CFG_PMP_CENTER_FREQUENCY, myLBandFreq); // Default 1539812500 Hz
if (ok) ok = myLBand.setVal16(UBLOX_CFG_PMP_SEARCH_WINDOW, 2200); // Default 2200 Hz
if (ok) ok = myLBand.setVal8(UBLOX_CFG_PMP_USE_SERVICE_ID, 0); // Default 1
if (ok) ok = myLBand.setVal16(UBLOX_CFG_PMP_SERVICE_ID, 21845); // Default 50821
@@ -178,6 +194,7 @@ void setup()
if (ok) ok = myLBand.setVal(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_UART2, 1); // Output UBX-RXM-PMP on UART2
if (ok) ok = myLBand.setVal32(UBLOX_CFG_UART1_BAUDRATE, 38400); // match baudrate with ZED default
if (ok) ok = myLBand.setVal32(UBLOX_CFG_UART2_BAUDRATE, 38400); // match baudrate with ZED default
Serial.print(F("L-Band: configuration "));
Serial.println(OK(ok));
@@ -0,0 +1,24 @@
// You can set the information below after signing up with the u-blox Thingstream portal
// and adding a new New PointPerfect Thing
// https://portal.thingstream.io/app/location-services/things
// In the new PointPerfect Thing, you go to the credentials tab and copy and paste the IP Dynamic Keys here.
//
// The keys are valid from a particular GPS Week Number and Time of Week.
// Looking at the credentials tab, the current key expires 23:59 Feb 11th 2022.
// This means the next key is valid _from_ Midnight Feb 12th 2022.
// That is GPS Week 2196. The GPS Time of Week in seconds is 518418.
// Working backwards, the current key became valid exactly 4 weeks earlier (Midnight Jan 15th 2022).
//
// See: https://www.labsat.co.uk/index.php/en/gps-time-calculator
//
// The keys are given as: 32 hexadecimal digits = 128 bits = 16 Bytes
const uint8_t currentKeyLengthBytes = 16;
const uint8_t currentDynamicKey[] = "f742bd6b7248043177dd649141d8fb0b";
const uint16_t currentKeyGPSWeek = 2192;
const uint32_t currentKeyGPSToW = 518418;
const uint8_t nextKeyLengthBytes = 16;
const uint8_t nextDynamicKey[] = "8206........................29f4";
const uint16_t nextKeyGPSWeek = 2196;
const uint32_t nextKeyGPSToW = 518418;
+172 -21
View File
@@ -7585,27 +7585,6 @@ bool SFE_UBLOX_GNSS::setAopCfg(uint8_t aopCfg, uint16_t aopOrbMaxErr, uint16_t m
// The key can be provided in binary format or in ASCII Hex format, but in both cases keyLengthBytes _must_ represent the binary key length in bytes.
bool SFE_UBLOX_GNSS::setDynamicSPARTNKey(uint8_t keyLengthBytes, uint16_t validFromWno, uint32_t validFromTow, const uint8_t *key, uint16_t maxWait)
{
// Check if all keyLengthBytes are ASCII Hex 0-9, a-f, A-F
bool isASCIIHex = true;
uint16_t i = 0;
while ((i < (uint16_t)keyLengthBytes) && (isASCIIHex == true))
{
if (((key[i] >= '0') && (key[i] <= '9')) || ((key[i] >= 'a') && (key[i] <= 'f')) || ((key[i] >= 'A') && (key[i] <= 'F')))
i++; // Keep checking if data is all ASCII Hex
else
isASCIIHex = false; // Data is binary
}
if (isASCIIHex) // Check the second half of the ASCII Hex key
{
while ((i < ((uint16_t)keyLengthBytes * 2) && (isASCIIHex == true)))
{
if (((key[i] >= '0') && (key[i] <= '9')) || ((key[i] >= 'a') && (key[i] <= 'f')) || ((key[i] >= 'A') && (key[i] <= 'F')))
i++; // Keep checking if data is all ASCII Hex
else
isASCIIHex = false; // Data is binary
}
}
// Check if there is room for the key in packetCfg. Resize the buffer if not.
size_t payloadLength = (size_t)keyLengthBytes + 12;
if (packetCfgPayloadSize < payloadLength)
@@ -7635,6 +7614,27 @@ bool SFE_UBLOX_GNSS::setDynamicSPARTNKey(uint8_t keyLengthBytes, uint16_t validF
payloadCfg[10] = (validFromTow >> 16) & 0xFF;
payloadCfg[11] = (validFromTow >> 24) & 0xFF;
// Check if all keyLengthBytes are ASCII Hex 0-9, a-f, A-F
bool isASCIIHex = true;
uint16_t i = 0;
while ((i < (uint16_t)keyLengthBytes) && (isASCIIHex == true))
{
if (((key[i] >= '0') && (key[i] <= '9')) || ((key[i] >= 'a') && (key[i] <= 'f')) || ((key[i] >= 'A') && (key[i] <= 'F')))
i++; // Keep checking if data is all ASCII Hex
else
isASCIIHex = false; // Data is binary
}
if (isASCIIHex) // Check the second half of the ASCII Hex key
{
while ((i < ((uint16_t)keyLengthBytes * 2) && (isASCIIHex == true)))
{
if (((key[i] >= '0') && (key[i] <= '9')) || ((key[i] >= 'a') && (key[i] <= 'f')) || ((key[i] >= 'A') && (key[i] <= 'F')))
i++; // Keep checking if data is all ASCII Hex
else
isASCIIHex = false; // Data is binary
}
}
if (isASCIIHex) // Convert ASCII Hex key to binary
{
for (i = 0; i < ((uint16_t)keyLengthBytes * 2); i += 2)
@@ -7677,6 +7677,157 @@ bool SFE_UBLOX_GNSS::setDynamicSPARTNKey(uint8_t keyLengthBytes, uint16_t validF
bool SFE_UBLOX_GNSS::setDynamicSPARTNKeys(uint8_t keyLengthBytes1, uint16_t validFromWno1, uint32_t validFromTow1, const uint8_t *key1,
uint8_t keyLengthBytes2, uint16_t validFromWno2, uint32_t validFromTow2, const uint8_t *key2, uint16_t maxWait)
{
// Check if there is room for the key in packetCfg. Resize the buffer if not.
size_t payloadLength = (size_t)keyLengthBytes1 + (size_t)keyLengthBytes2 + 20;
if (packetCfgPayloadSize < payloadLength)
{
if (!setPacketCfgPayloadSize(payloadLength)) // Check if the resize was successful
{
return (false);
}
}
// Copy the key etc. into packetCfg
packetCfg.cls = UBX_CLASS_RXM;
packetCfg.id = UBX_RXM_SPARTNKEY;
packetCfg.len = payloadLength;
packetCfg.startingSpot = 0;
payloadCfg[0] = 0x01; // version
payloadCfg[1] = 0x02; // numKeys
payloadCfg[2] = 0x00; // reserved0
payloadCfg[3] = 0x00; // reserved0
payloadCfg[4] = 0x00; // reserved1
payloadCfg[5] = keyLengthBytes1;
payloadCfg[6] = validFromWno1 & 0xFF; // validFromWno little-endian
payloadCfg[7] = validFromWno1 >> 8;
payloadCfg[8] = validFromTow1 & 0xFF; // validFromTow little-endian
payloadCfg[9] = (validFromTow1 >> 8) & 0xFF;
payloadCfg[10] = (validFromTow1 >> 16) & 0xFF;
payloadCfg[11] = (validFromTow1 >> 24) & 0xFF;
payloadCfg[12] = 0x00; // reserved1
payloadCfg[13] = keyLengthBytes2;
payloadCfg[14] = validFromWno2 & 0xFF; // validFromWno little-endian
payloadCfg[15] = validFromWno2 >> 8;
payloadCfg[16] = validFromTow2 & 0xFF; // validFromTow little-endian
payloadCfg[17] = (validFromTow2 >> 8) & 0xFF;
payloadCfg[18] = (validFromTow2 >> 16) & 0xFF;
payloadCfg[19] = (validFromTow2 >> 24) & 0xFF;
// Check if all keyLengthBytes are ASCII Hex 0-9, a-f, A-F
bool isASCIIHex = true;
uint16_t i = 0;
while ((i < (uint16_t)keyLengthBytes1) && (isASCIIHex == true))
{
if (((key1[i] >= '0') && (key1[i] <= '9')) || ((key1[i] >= 'a') && (key1[i] <= 'f')) || ((key1[i] >= 'A') && (key1[i] <= 'F')))
i++; // Keep checking if data is all ASCII Hex
else
isASCIIHex = false; // Data is binary
}
if (isASCIIHex) // Check the second half of the ASCII Hex key
{
while ((i < ((uint16_t)keyLengthBytes1 * 2) && (isASCIIHex == true)))
{
if (((key1[i] >= '0') && (key1[i] <= '9')) || ((key1[i] >= 'a') && (key1[i] <= 'f')) || ((key1[i] >= 'A') && (key1[i] <= 'F')))
i++; // Keep checking if data is all ASCII Hex
else
isASCIIHex = false; // Data is binary
}
}
if (isASCIIHex) // Convert ASCII Hex key to binary
{
for (i = 0; i < ((uint16_t)keyLengthBytes1 * 2); i += 2)
{
if ((key1[i] >= '0') && (key1[i] <= '9'))
{
payloadCfg[20 + (i >> 1)] = (key1[i] - '0') << 4;
}
else if ((key1[i] >= 'a') && (key1[i] <= 'f'))
{
payloadCfg[20 + (i >> 1)] = (key1[i] + 10 - 'a') << 4;
}
else // if ((key1[i] >= 'A') && (key1[i] <= 'F'))
{
payloadCfg[20 + (i >> 1)] = (key1[i] + 10 - 'A') << 4;
}
if ((key1[i + 1] >= '0') && (key1[i + 1] <= '9'))
{
payloadCfg[20 + (i >> 1)] |= key1[i + 1] - '0';
}
else if ((key1[i + 1] >= 'a') && (key1[i + 1] <= 'f'))
{
payloadCfg[20 + (i >> 1)] |= key1[i + 1] + 10 - 'a';
}
else // if ((key1[i + 1] >= 'A') && (key1[i + 1] <= 'F'))
{
payloadCfg[20 + (i >> 1)] |= key1[i + 1] + 10 - 'A';
}
}
}
else // Binary key
{
memcpy(&payloadCfg[20], key1, keyLengthBytes1);
}
// Check if all keyLengthBytes are ASCII Hex 0-9, a-f, A-F
isASCIIHex = true;
i = 0;
while ((i < (uint16_t)keyLengthBytes2) && (isASCIIHex == true))
{
if (((key2[i] >= '0') && (key2[i] <= '9')) || ((key2[i] >= 'a') && (key2[i] <= 'f')) || ((key2[i] >= 'A') && (key2[i] <= 'F')))
i++; // Keep checking if data is all ASCII Hex
else
isASCIIHex = false; // Data is binary
}
if (isASCIIHex) // Check the second half of the ASCII Hex key
{
while ((i < ((uint16_t)keyLengthBytes2 * 2) && (isASCIIHex == true)))
{
if (((key2[i] >= '0') && (key2[i] <= '9')) || ((key2[i] >= 'a') && (key2[i] <= 'f')) || ((key2[i] >= 'A') && (key2[i] <= 'F')))
i++; // Keep checking if data is all ASCII Hex
else
isASCIIHex = false; // Data is binary
}
}
if (isASCIIHex) // Convert ASCII Hex key to binary
{
for (i = 0; i < ((uint16_t)keyLengthBytes2 * 2); i += 2)
{
if ((key2[i] >= '0') && (key2[i] <= '9'))
{
payloadCfg[20 + keyLengthBytes1 + (i >> 1)] = (key2[i] - '0') << 4;
}
else if ((key2[i] >= 'a') && (key2[i] <= 'f'))
{
payloadCfg[20 + keyLengthBytes1 + (i >> 1)] = (key2[i] + 10 - 'a') << 4;
}
else // if ((key2[i] >= 'A') && (key2[i] <= 'F'))
{
payloadCfg[20 + keyLengthBytes1 + (i >> 1)] = (key2[i] + 10 - 'A') << 4;
}
if ((key2[i + 1] >= '0') && (key2[i + 1] <= '9'))
{
payloadCfg[20 + keyLengthBytes1 + (i >> 1)] |= key2[i + 1] - '0';
}
else if ((key2[i + 1] >= 'a') && (key2[i + 1] <= 'f'))
{
payloadCfg[20 + keyLengthBytes1 + (i >> 1)] |= key2[i + 1] + 10 - 'a';
}
else // if ((key2[i + 1] >= 'A') && (key2[i + 1] <= 'F'))
{
payloadCfg[20 + keyLengthBytes1 + (i >> 1)] |= key2[i + 1] + 10 - 'A';
}
}
}
else // Binary key
{
memcpy(&payloadCfg[20 + keyLengthBytes1], key2, keyLengthBytes2);
}
return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK
}