Skip to content

v2.2.6 #129

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Mar 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/*
Use ESP32 WiFi to get AssistNow Online (MGA) data from PointPerfect (broker) as a Client using MQTT
By: Paul Clark / SparkFun
Date: March 9th, 2022
Based on original code by: u-blox AG / Michael Ammann
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 AssistNow Online (MGA) 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 service.

You will need to have a valid u-blox Thingstream account and have a PointPerfect Thing and payed plan.
To 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 AssistNow MGA data.

For more information about MQTT, SPARTN and PointPerfect Correction Services
please see: https://www.u-blox.com/en/product/pointperfect

Feel like supporting open source hardware?
Buy a board from SparkFun!
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193

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 <WiFi.h>
#include <WiFiClientSecure.h>
#include <ArduinoMqttClient.h> // Click here to get the library: http://librarymanager/All#ArduinoMqttClient
#include "secrets.h"

#include <SparkFun_u-blox_GNSS_Arduino_Library.h> // Click here to get the library: 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 AssistNow testing"));

Wire.begin(); //Start I2C

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);

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 Client."));

delay(1000);
}

WiFiClientSecure wifiClient = WiFiClientSecure();
MqttClient mqttClient(wifiClient);

void mqttMessageHandler(int messageSize) {
uint8_t mgaData[512 * 4]; //Most incoming data is around 500 bytes but may be larger
int mgaCount = 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
mgaData[mgaCount++] = ch;
if (mgaCount == sizeof(mgaData))
break;
}

if (mgaCount > 0)
{
//Push MGA data to GNSS module over I2C
myGNSS.pushRawData(mgaData, mgaCount, false);
lastReceived_ms = millis();
}
}

//Connect to MQTT broker, receive MGA, 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);
mqttClient.setId(MQTT_CLIENT_ID);
mqttClient.setKeepAliveInterval(60*1000);
mqttClient.setConnectionTimeout( 5*1000);
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_ASSISTNOW);
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("Timeout. Disconnecting..."));
if (mqttClient.connected() == true)
mqttClient.stop();
return;
}

delay(10);
}

Serial.println(F("User pressed a key"));
Serial.println(F("Disconnecting..."));
wifiClient.stop();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//Your WiFi credentials
const char ssid[] = "<YOUR SSID>";
const char password[] = "<YOUR 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.

// <Your PointPerfect Thing> -> Credentials -> Hostname
const char AWS_IOT_ENDPOINT[] = "pp.services.u-blox.com";
const unsigned short AWS_IOT_PORT = 8883;
// <Your PointPerfect Thing> -> Credentials -> AssistNow (MGA) topic
const char MQTT_TOPIC_ASSISTNOW[] = "/pp/ubx/mga";

// <Your PointPerfect Thing> -> Credentials -> Client Id
static const char MQTT_CLIENT_ID[] = "<ADD YOUR CLIENT ID HERE>";

// <Your PointPerfect Thing> -> Credentials -> Amazon Root Certificate
static const char AWS_CERT_CA[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
<ADD YOUR CERTICICATE HERE>
-----END CERTIFICATE-----
)EOF";

// <Your PointPerfect Thing> -> Credentials -> Client Certificate
static const char AWS_CERT_CRT[] PROGMEM = R"KEY(
-----BEGIN CERTIFICATE-----
<ADD YOUR CERTICICATE HERE>
-----END CERTIFICATE-----
)KEY";

// Get this from Thingstream Portal
// <Your PointPerfect Thing> -> Credentials -> Client Key
static const char AWS_CERT_PRIVATE[] PROGMEM = R"KEY(
-----BEGIN RSA PRIVATE KEY-----
<ADD YOUR KEY HERE>
-----END RSA PRIVATE KEY-----
)KEY";
128 changes: 128 additions & 0 deletions examples/Example30_NEO-D9S/Example30_NEO-D9S.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/*
NEO-D9S L-Band receiver example
By: SparkFun Electronics / Paul Clark
Date: March 7th, 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 display the NEO-D9S's received signal imbalance and magnitude, plus a summary of any received PMP data.

Feel like supporting open source hardware?
Buy a board from SparkFun!
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
NEO-D9S: Coming soon!

Hardware Connections:
Use a Qwiic cable to connect the NEO-D9S L-Band corection data receiver to your board
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 <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myLBand; // NEO-D9S

const uint32_t myLBandFreq = 1556290000; // Uncomment this line to use the US SPARTN 1.8 service
//const uint32_t myLBandFreq = 1545260000; // Uncomment this line to use the EU SPARTN 1.8 service

#define OK(ok) (ok ? F(" -> OK") : F(" -> ERROR!")) // Convert uint8_t into OK/ERROR

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

// Callback: printRXMPMP will be called when new PMP data arrives
// See u-blox_structs.h for the full definition of UBX_RXM_PMP_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setRXMPMPcallbackPtr
// / _____ This _must_ be UBX_RXM_PMP_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printRXMPMP(UBX_RXM_PMP_data_t *pmpData)
{
Serial.println(F("New PMP data received:"));

Serial.print(F("PMP message version: "));
Serial.println(pmpData->version);

Serial.print(F("numBytesUserData : "));
Serial.println(pmpData->numBytesUserData);

Serial.print(F("serviceIdentifier: "));
Serial.println(pmpData->serviceIdentifier);

Serial.print(F("uniqueWordBitErrors: "));
Serial.println(pmpData->uniqueWordBitErrors);

Serial.print(F("fecBits: "));
Serial.println(pmpData->fecBits);

Serial.print(F("ebno: "));
Serial.println(pmpData->ebno);

Serial.println();
}

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

void setup()
{
Serial.begin(115200);
Serial.println(F("NEO-D9S Example"));

Wire.begin(); //Start I2C

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Begin and configure the NEO-D9S L-Band receiver

//myLBand.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial

while (myLBand.begin(Wire, 0x43) == false) //Connect to the u-blox NEO-D9S using Wire port. The D9S default I2C address is 0x43 (not 0x42)
{
Serial.println(F("u-blox NEO-D9S not detected at default I2C address. Please check wiring."));
delay(2000);
}
Serial.println(F("u-blox NEO-D9S connected"));

uint8_t 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
if (ok) ok = myLBand.setVal16(UBLOX_CFG_PMP_DATA_RATE, 2400); // Default 2400 bps
if (ok) ok = myLBand.setVal8(UBLOX_CFG_PMP_USE_DESCRAMBLER, 1); // Default 1
if (ok) ok = myLBand.setVal16(UBLOX_CFG_PMP_DESCRAMBLER_INIT, 26969); // Default 23560
if (ok) ok = myLBand.setVal8(UBLOX_CFG_PMP_USE_PRESCRAMBLING, 0); // Default 0
if (ok) ok = myLBand.setVal64(UBLOX_CFG_PMP_UNIQUE_WORD, 16238547128276412563ull);
if (ok) ok = myLBand.setVal(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_I2C, 1); // Ensure UBX-RXM-PMP is enabled on the I2C port
if (ok) ok = myLBand.setVal(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_UART1, 1); // Output UBX-RXM-PMP on UART1
if (ok) ok = myLBand.setVal(UBLOX_CFG_UART2OUTPROT_UBX, 1); // Enable UBX output on UART2
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));

myLBand.softwareResetGNSSOnly(); // Do a restart

myLBand.setRXMPMPcallbackPtr(&printRXMPMP); // Call printRXMPMP when new PMP data arrives
}

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

void loop()
{
myLBand.checkUblox(); // Check for the arrival of new PMP data and process it.
myLBand.checkCallbacks(); // Check if any LBand callbacks are waiting to be processed.

UBX_MON_HW2_data_t hwStatus; // Create storage for the HW2 extended hardware status
if (myLBand.getHW2status(&hwStatus)) // Request the extended hardware status
{
// Print the signal imbalance and magnitude
Serial.print(F("Signal imbalance and magnitude: ofsI: "));
Serial.print(hwStatus.ofsI);
Serial.print(F(" magI: "));
Serial.print(hwStatus.magI);
Serial.print(F(" ofsQ: "));
Serial.print(hwStatus.ofsQ);
Serial.print(F(" magQ: "));
Serial.println(hwStatus.magQ);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ void beginClient()
wifiClient.setCACert(AWS_CERT_CA);
wifiClient.setCertificate(AWS_CERT_CRT);
wifiClient.setPrivateKey(AWS_CERT_PRIVATE);
mqttClient.setId(MQTT_CLIENT_ID);
mqttClient.setKeepAliveInterval(60*1000);
mqttClient.setConnectionTimeout( 5*1000);
if (!mqttClient.connect(AWS_IOT_ENDPOINT, AWS_IOT_PORT)) {
Serial.print(F("MQTT connection failed! Error code = "));
Serial.println(mqttClient.connectError());
Expand Down
3 changes: 3 additions & 0 deletions examples/ZED-F9P/Example18_PointPerfectClient/secrets.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ const char MQTT_TOPIC_KEY[] = "/pp/key/ip";
// <Your PointPerfect Thing> -> Credentials -> IP correction topic for EU/US region
const char MQTT_TOPIC_SPARTN[] = "/pp/ip/us"; // choice of {eu, us}

// <Your PointPerfect Thing> -> Credentials -> Client Id
static const char MQTT_CLIENT_ID[] = "<ADD YOUR CLIENT ID HERE>";

// <Your PointPerfect Thing> -> Credentials -> Amazon Root Certificate
static const char AWS_CERT_CA[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ void setup()
if (ok) ok = myLBand.setVal64(UBLOX_CFG_PMP_UNIQUE_WORD, 16238547128276412563ull);
if (ok) ok = myLBand.setVal(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_I2C, 1); // Ensure UBX-RXM-PMP is enabled on the I2C port
if (ok) ok = myLBand.setVal(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_UART1, 1); // Output UBX-RXM-PMP on UART1
if (ok) ok = myLBand.setVal(UBLOX_CFG_UART2OUTPROT_UBX, 1); // Enable UBX output on UART2
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
Expand Down
2 changes: 2 additions & 0 deletions keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ UBX_ESF_STATUS_sensorStatus_t KEYWORD1
UBX_CFG_ITFM_data_t KEYWORD1
UBX_MON_RF_data_t KEYWORD1
UBX_MON_HW_data_t KEYWORD1
UBX_MON_HW2_data_t KEYWORD1

UBX_NAV_POSECEF_data_t KEYWORD1
UBX_NAV_STATUS_data_t KEYWORD1
Expand Down Expand Up @@ -195,6 +196,7 @@ setJammingConfiguration KEYWORD2
getRFinformation KEYWORD2

getHWstatus KEYWORD2
getHW2status KEYWORD2

getAckAiding KEYWORD2
setAckAiding KEYWORD2
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=SparkFun u-blox GNSS Arduino Library
version=2.2.5
version=2.2.6
author=SparkFun Electronics <[email protected]>
maintainer=SparkFun Electronics <sparkfun.com>
sentence=Library for I2C, Serial and SPI Communication with u-blox GNSS modules<br/><br/>
Expand Down
Loading