From 9de604cd664e56caf081957cf26261daed981f87 Mon Sep 17 00:00:00 2001 From: Michael Ammann Date: Mon, 31 Jan 2022 09:54:21 +0100 Subject: [PATCH 1/7] Create Example18_PointPerfectClient.ino --- .../Example18_PointPerfectClient.ino | 170 ++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 examples/ZED-F9P/Example18_PointPerfectClient/Example18_PointPerfectClient.ino diff --git a/examples/ZED-F9P/Example18_PointPerfectClient/Example18_PointPerfectClient.ino b/examples/ZED-F9P/Example18_PointPerfectClient/Example18_PointPerfectClient.ino new file mode 100644 index 0000000..8401bd4 --- /dev/null +++ b/examples/ZED-F9P/Example18_PointPerfectClient/Example18_PointPerfectClient.ino @@ -0,0 +1,170 @@ +/* + Use ESP32 WiFi to get SPARTN data from PointPerfect (broker) as a Client + By: u-blox AG / Michael Ammann + Date: January 27th, 2022 + License: MIT. See license file for more information but you can + basically do whatever you want with this code. + + This example shows how to obtain SPARTN data from a PointPerfect Broker over WiFi + and push it over I2C to a ZED-F9x. + It's confusing, but the Arduino is acting as a 'client' to the PointPerfect SSR correction service. + + You will need to have a valid u-blox Thingstream account and have a PointPerfect Thinng and Plan. + Thingstream offers continetal SSR corrections to SPARTN cabalble RTK receivers such as the u-blox + ZED-F9 sweries in continental Europ and US. There Network is planned to be expanded to ther regions + over next years. To see sign up go to https://portal.thingstream.io/app/location-services/things + + This is a proof of concept to show how to connect via MQTT to get SPARTN SSR correction. + Using WiFi for a rover is generally a bad idea because of limited WiFi range in the field. + + For more information about MQTT, SPARTN and PointPerfect Correction Services + please see: https://www.u-blox.com/en/product/pointperfect?lang=de + + Feel like supporting open source hardware? + Buy a board from SparkFun! + ZED-F9P RTK2: https://www.sparkfun.com/products/16481 + RTK Surveyor: https://www.sparkfun.com/products/18443 + RTK Express: https://www.sparkfun.com/products/18442 + + Hardware Connections: + Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus + 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 +#include +#include +#include "secrets.h" + +#include //http://librarymanager/All#SparkFun_u-blox_GNSS +SFE_UBLOX_GNSS myGNSS; + +//Global variables +//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +long lastReceived_ms = 0; //5 RTCM messages take approximately ~300ms to arrive at 115200bps +int maxTimeBeforeHangup_ms = 10000; //If we fail to get a complete RTCM frame after 10s, then disconnect from caster +//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +void setup() +{ + Serial.begin(115200); + while (!Serial); + Serial.println(F("PointPerfect testing")); + + Wire.begin(); //Start I2C + Wire.setClock(100000); + + if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port + { + Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing.")); + while (1); + } + + Serial.println(F("u-blox 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. + + myGNSS.setNavigationFrequency(1); //Set output in Hz. + Serial.print(F("Connecting to local WiFi")); + WiFi.begin(ssid, password); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print(F(".")); + } + Serial.println(); + + Serial.print(F("WiFi connected with IP: ")); + Serial.println(WiFi.localIP()); + + while (Serial.available()) Serial.read(); +} + +void loop() +{ + if (Serial.available()) + { + beginClient(); + while (Serial.available()) Serial.read(); //Empty buffer of any newline chars + } + + Serial.println(F("Press any key to start MQTT/SPARTN Client.")); + + delay(1000); +} + +WiFiClientSecure wifiClient = WiFiClientSecure(); +MqttClient mqttClient(wifiClient); + +void mqttMessageHandler(int messageSize) { + uint8_t spartnData[512 * 4]; //Most incoming data is around 500 bytes but may be larger + int spartnCount = 0; + Serial.print(F("Pushed data from ")); + Serial.print(mqttClient.messageTopic()); + Serial.println(F(" topic to ZED")); + while (mqttClient.available()) + { + char ch = mqttClient.read(); + //Serial.write(ch); //Pipe to serial port is fine but beware, it's a lot of binary data + spartnData[spartnCount++] = ch; + if (spartnCount == sizeof(spartnData)) + break; + } + + if (spartnCount > 0) + { + //Push KEYS or SPARTN data to GNSS module over I2C + myGNSS.pushRawData(spartnData, spartnCount, false); + lastReceived_ms = millis(); + } +} + +//Connect to STARTN MQTT broker, receive RTCM, and push to ZED module over I2C +void beginClient() +{ + Serial.println(F("Subscribing to Broker. Press key to stop")); + delay(10); //Wait for any serial to arrive + while (Serial.available()) Serial.read(); //Flush + + while (Serial.available() == 0) + { + //Connect if we are not already + if (wifiClient.connected() == false) + { + // Connect to AWS IoT + wifiClient.setCACert(AWS_CERT_CA); + wifiClient.setCertificate(AWS_CERT_CRT); + wifiClient.setPrivateKey(AWS_CERT_PRIVATE); + if (!mqttClient.connect(AWS_IOT_ENDPOINT, AWS_IOT_PORT)) { + Serial.print(F("MQTT connection failed! Error code = ")); + Serial.println(mqttClient.connectError()); + return; + } else { + Serial.println(F("You're connected to the PointPerfect MQTT broker: ")); + Serial.println(AWS_IOT_ENDPOINT); + // Subscribe to MQTT and register a callback + Serial.println(F("Subscribe to Topics")); + mqttClient.onMessage(mqttMessageHandler); + mqttClient.subscribe(MQTT_TOPIC_KEY); + mqttClient.subscribe(MQTT_TOPIC_SPARTN); + lastReceived_ms = millis(); + } //End attempt to connect + } //End connected == false + else { + mqttClient.poll(); + } + //Close socket if we don't have new data for 10s + if (millis() - lastReceived_ms > maxTimeBeforeHangup_ms) + { + Serial.println(F("SPARTN timeout. Disconnecting...")); + if (mqttClient.connected() == true) + mqttClient.stop(); + return; + } + + delay(10); + } + + Serial.println(F("User pressed a key")); + Serial.println(F("Disconnecting...")); + wifiClient.stop(); +} From 29dda946d649cf78becf025b2336c4366bb42548 Mon Sep 17 00:00:00 2001 From: Michael Ammann Date: Mon, 31 Jan 2022 09:58:21 +0100 Subject: [PATCH 2/7] Create secrets.h --- .../Example18_PointPerfectClient/secrets.h | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 examples/ZED-F9P/Example18_PointPerfectClient/secrets.h diff --git a/examples/ZED-F9P/Example18_PointPerfectClient/secrets.h b/examples/ZED-F9P/Example18_PointPerfectClient/secrets.h new file mode 100644 index 0000000..4353c50 --- /dev/null +++ b/examples/ZED-F9P/Example18_PointPerfectClient/secrets.h @@ -0,0 +1,38 @@ +//Your WiFi credentials +const char ssid[] = ""; +const char password[] = ""; + +// Below infomation you can set after signing up with u-blox Thingstream portal +// and after add a new New PointPerfect Thing +// https://portal.thingstream.io/app/location-services/things +// in the new PointPerfect Thing you go to the credentials page and copy past the values and certificate into this. + +// -> Credentials -> Hostname +const char AWS_IOT_ENDPOINT[] = "pp.services.u-blox.com"; +const unsigned short AWS_IOT_PORT = 8883; +// -> Credentials -> IP key distribution topic +const char MQTT_TOPIC_KEY[] = "/pp/key/ip"; +// -> Credentials -> IP correction topic for EU/US region +const char MQTT_TOPIC_SPARTN[] = "/pp/ip/us"; // choice of {eu, us} + +// -> Credentials -> Amazon Root Certificate +static const char AWS_CERT_CA[] PROGMEM = R"EOF( +-----BEGIN CERTIFICATE----- + +-----END CERTIFICATE----- +)EOF"; + +// -> Credentials -> Client Certificate +static const char AWS_CERT_CRT[] PROGMEM = R"KEY( +-----BEGIN CERTIFICATE----- + +-----END CERTIFICATE----- +)KEY"; + +// Get this from Thingstream Portal +// -> Credentials -> Client Key +static const char AWS_CERT_PRIVATE[] PROGMEM = R"KEY( +-----BEGIN RSA PRIVATE KEY----- + +-----END RSA PRIVATE KEY----- +)KEY"; From 7754abfbd805739d6158828c3616c376a361522b Mon Sep 17 00:00:00 2001 From: Michael Ammann Date: Mon, 31 Jan 2022 10:00:19 +0100 Subject: [PATCH 3/7] Update Example18_PointPerfectClient.ino --- .../Example18_PointPerfectClient.ino | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/ZED-F9P/Example18_PointPerfectClient/Example18_PointPerfectClient.ino b/examples/ZED-F9P/Example18_PointPerfectClient/Example18_PointPerfectClient.ino index 8401bd4..6635f26 100644 --- a/examples/ZED-F9P/Example18_PointPerfectClient/Example18_PointPerfectClient.ino +++ b/examples/ZED-F9P/Example18_PointPerfectClient/Example18_PointPerfectClient.ino @@ -52,7 +52,6 @@ void setup() Serial.println(F("PointPerfect testing")); Wire.begin(); //Start I2C - Wire.setClock(100000); if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port { From 25ab860f42d5977dcdcd456d4e4214f975a1c9f7 Mon Sep 17 00:00:00 2001 From: Michael Ammann Date: Mon, 31 Jan 2022 10:06:03 +0100 Subject: [PATCH 4/7] Update Example18_PointPerfectClient.ino --- .../Example18_PointPerfectClient.ino | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/examples/ZED-F9P/Example18_PointPerfectClient/Example18_PointPerfectClient.ino b/examples/ZED-F9P/Example18_PointPerfectClient/Example18_PointPerfectClient.ino index 6635f26..d9f8fd0 100644 --- a/examples/ZED-F9P/Example18_PointPerfectClient/Example18_PointPerfectClient.ino +++ b/examples/ZED-F9P/Example18_PointPerfectClient/Example18_PointPerfectClient.ino @@ -9,22 +9,27 @@ and push it over I2C to a ZED-F9x. It's confusing, but the Arduino is acting as a 'client' to the PointPerfect SSR correction service. - You will need to have a valid u-blox Thingstream account and have a PointPerfect Thinng and Plan. - Thingstream offers continetal SSR corrections to SPARTN cabalble RTK receivers such as the u-blox - ZED-F9 sweries in continental Europ and US. There Network is planned to be expanded to ther regions - over next years. To see sign up go to https://portal.thingstream.io/app/location-services/things + You will need to have a valid u-blox Thingstream account and have a PointPerfect Thing and payed plan. + Thingstream offers SSR corrections to SPARTN cabalble RTK receivers such as the u-blox ZED-F9 series + in continental Europ and US. There Network is planned to be expanded to ther regions over next years. + To see sign up go to https://portal.thingstream.io/app/location-services/things This is a proof of concept to show how to connect via MQTT to get SPARTN SSR correction. - Using WiFi for a rover is generally a bad idea because of limited WiFi range in the field. + Using WiFi for a rover is generally a bad idea because of limited WiFi range in the field. + You may use this exmaple in combination with a cell phone with hotspot mode enabled. For more information about MQTT, SPARTN and PointPerfect Correction Services - please see: https://www.u-blox.com/en/product/pointperfect?lang=de + please see: https://www.u-blox.com/en/product/pointperfect Feel like supporting open source hardware? Buy a board from SparkFun! ZED-F9P RTK2: https://www.sparkfun.com/products/16481 RTK Surveyor: https://www.sparkfun.com/products/18443 RTK Express: https://www.sparkfun.com/products/18442 + + Recommended Hardware: + MicroMod GNSS Carrier Board: https://www.sparkfun.com/products/17722 + ESP32 Micromod https://www.sparkfun.com/products/16781 Hardware Connections: Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus From 9bff608dfbe5599166c69260996a1338d472195b Mon Sep 17 00:00:00 2001 From: PaulZC Date: Tue, 1 Feb 2022 18:46:27 +0000 Subject: [PATCH 5/7] Add COM_TYPE_SPARTN to keywords.txt --- keywords.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/keywords.txt b/keywords.txt index b40d37e..32d0fcb 100644 --- a/keywords.txt +++ b/keywords.txt @@ -597,6 +597,7 @@ SFE_UBLOX_STATUS_DATA_OVERWRITTEN LITERAL1 COM_TYPE_UBX LITERAL1 COM_TYPE_NMEA LITERAL1 COM_TYPE_RTCM3 LITERAL1 +COM_TYPE_SPARTN LITERAL1 COM_PORT_I2C LITERAL1 COM_PORT_UART1 LITERAL1 From f5b40719cddf33dc4387855c155d0bc3bf323125 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Wed, 2 Feb 2022 14:48:29 +0000 Subject: [PATCH 6/7] Add RXM-PMP to u-blox_structs.h --- src/u-blox_structs.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/u-blox_structs.h b/src/u-blox_structs.h index eb51598..e7588b4 100644 --- a/src/u-blox_structs.h +++ b/src/u-blox_structs.h @@ -1463,6 +1463,33 @@ typedef struct UBX_RXM_RAWX_data_t *callbackData; } UBX_RXM_RAWX_t; +// UBX-RXM-PMP (0x02 0x72): PMP raw data (D9 modules) +const uint16_t UBX_RXM_PMP_MAX_LEN = 528; + +typedef struct +{ + uint8_t version; // Message version (0x00 for this version) + uint8_t reserved0[3]; // Reserved + uint32_t timeTag; // Time since startup when frame started : ms + uint32_t uniqueWord[2]; // Received unique words + uint16_t serviceIdentifier; // Received service identifier + uint8_t spare; // Received spare data + uint8_t uniqueWordBitErrors; // Number of bit errors in both unique words + uint8_t userData[504]; // Received user data + uint16_t fecBits; // Number of bits corrected by FEC (forward error correction) + uint8_t ebno; // Energy per bit to noise power spectral density ratio : 2^-3 dB + uint8_t reserved1; // Reserved +} UBX_RXM_PMP_data_t; + +typedef struct +{ + ubxAutomaticFlags automaticFlags; + UBX_RXM_PMP_data_t data; + bool moduleQueried; + void (*callbackPointer)(UBX_RXM_PMP_data_t); + UBX_RXM_PMP_data_t *callbackData; +} UBX_RXM_PMP_t; + // CFG-specific structs // UBX-CFG-RATE (0x06 0x08): Navigation/measurement rate settings From 773cee24c06b521da91105d792276564ef7550a0 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Fri, 4 Feb 2022 08:45:25 +0000 Subject: [PATCH 7/7] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 2a64007..6b233a4 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,10 @@ Please check the module datasheets for details on what clock speeds and data rat For I2C communication, please be sure to remove all additional pull-ups on the I2C bus. u-blox modules include internal pull-ups on the I2C lines (sometimes called DDC in their manuals). Cut all I2C pull-up jumpers and/or remove them from peripheral boards. Otherwise, various data glitches can occur. See issues [38](https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/issues/38) and [40](https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/issues/40) for more information. We recommend running the I2C bus at 100kHz. +## Compatibility + +v2 of the library provides support for generation 8, 9 and 10 u-blox GNSS modules. For generation 6 and 7, please see [this example (depricated)](https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/tree/master/examples/Series_6_7/Example1_GetPositionAndTime_Series_6_7). + ## Contributing If you would like to contribute to this library: please do, we truly appreciate it, but please follow [these guidelines](./CONTRIBUTING.md). Thanks!