Add Example17_NTRIPClient_With_GGA_Callback
This commit is contained in:
@@ -60,7 +60,7 @@ v2.1.0 of the library adds support for u-blox AssistNow<sup>TM</sup> Assisted GN
|
|||||||
## Automatic support for correction services like RTK2go, Emlid Caster and Skylark (Swift Navigation)
|
## Automatic support for correction services like RTK2go, Emlid Caster and Skylark (Swift Navigation)
|
||||||
|
|
||||||
RTK NTRIP corrections services often require you to send them your location in NMEA GPGGA format. v2.2 of the library makes this simple by providing get functions and automatic callbacks
|
RTK NTRIP corrections services often require you to send them your location in NMEA GPGGA format. v2.2 of the library makes this simple by providing get functions and automatic callbacks
|
||||||
for both GPGGA and GNGGA messages. You can now instruct your module to output GPGGA (e.g.) every 10 seconds and then push it to the correction server directly from the callback! No more polling, no more parsing!
|
for both GPGGA and GNGGA messages. You can now instruct your module to output GPGGA (e.g.) every 10 seconds and then push it to the correction server directly from the callback. No more polling, no more parsing!
|
||||||
|
|
||||||
v2.2 also includes two new functions useful for correction services:
|
v2.2 also includes two new functions useful for correction services:
|
||||||
|
|
||||||
|
|||||||
+497
@@ -0,0 +1,497 @@
|
|||||||
|
/*
|
||||||
|
Use ESP32 WiFi to get RTCM data from Swift Navigation's Skylark caster as a Client, and transmit GGA using a callback
|
||||||
|
By: SparkFun Electronics / Nathan Seidle & Paul Clark
|
||||||
|
Date: January 13th, 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 RTCM data from a NTRIP Caster over WiFi and push it over I2C to a ZED-F9x.
|
||||||
|
It's confusing, but the Arduino is acting as a 'client' to a 'caster'.
|
||||||
|
In this case we will use Skylark. But you can of course use RTK2Go or Emlid's Caster too. Change secrets.h. as required.
|
||||||
|
|
||||||
|
The rover's location will be broadcast to the caster every 10s via GGA setence - automatically using a callback.
|
||||||
|
|
||||||
|
This is a proof of concept to show how to connect to a caster via HTTP and show how the corrections control the accuracy.
|
||||||
|
|
||||||
|
It's a fun thing to disconnect from the caster and watch the accuracy degrade. Then connect again and watch it recover!
|
||||||
|
|
||||||
|
For more information about NTRIP Clients and the differences between Rev1 and Rev2 of the protocol
|
||||||
|
please see: https://www.use-snip.com/kb/knowledge-base/ntrip-rev1-versus-rev2-formats/
|
||||||
|
|
||||||
|
"In broad protocol terms, the NTRIP client must first connect (get an HTTP “OK” reply) and only then
|
||||||
|
should it send the sentence. NTRIP protocol revision 2 (which does not have very broad industry
|
||||||
|
acceptance at this time) does allow sending the sentence in the original header."
|
||||||
|
https://www.use-snip.com/kb/knowledge-base/subtle-issues-with-using-ntrip-client-nmea-183-strings/
|
||||||
|
|
||||||
|
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 <WiFi.h>
|
||||||
|
#include "secrets.h"
|
||||||
|
|
||||||
|
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||||
|
SFE_UBLOX_GNSS myGNSS;
|
||||||
|
|
||||||
|
//The ESP32 core has a built in base64 library but not every platform does
|
||||||
|
//We'll use an external lib if necessary.
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
|
#include "base64.h" //Built-in ESP32 library
|
||||||
|
#else
|
||||||
|
#include <Base64.h> //nfriendly library from https://github.com/adamvr/arduino-base64, will work with any platform
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
|
|
||||||
|
//Global variables
|
||||||
|
|
||||||
|
unsigned long lastReceivedRTCM_ms = 0; //5 RTCM messages take approximately ~300ms to arrive at 115200bps
|
||||||
|
const unsigned long maxTimeBeforeHangup_ms = 10000UL; //If we fail to get a complete RTCM frame after 10s, then disconnect from caster
|
||||||
|
|
||||||
|
bool transmitLocation = true; //By default we will transmit the unit's location via GGA sentence.
|
||||||
|
|
||||||
|
WiFiClient ntripClient; // The WiFi connection to the NTRIP server. This is global so pushGGA can see if we are connected.
|
||||||
|
|
||||||
|
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
|
|
||||||
|
// Callback: pushGPGGA will be called when new GPGGA NMEA data arrives
|
||||||
|
// See u-blox_structs.h for the full definition of NMEA_GGA_data_t
|
||||||
|
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGPGGAcallback
|
||||||
|
// / _____ This _must_ be NMEA_GGA_data_t
|
||||||
|
// | / _____ You can use any name you like for the struct
|
||||||
|
// | | /
|
||||||
|
// | | |
|
||||||
|
void pushGPGGA(NMEA_GGA_data_t nmeaData)
|
||||||
|
{
|
||||||
|
//Provide the caster with our current position as needed
|
||||||
|
if ((ntripClient.connected() == true) && (transmitLocation == true))
|
||||||
|
{
|
||||||
|
Serial.print(F("Pushing GGA to server: "));
|
||||||
|
Serial.print((const char *)nmeaData.nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
|
||||||
|
|
||||||
|
//Push our current GGA sentence to caster
|
||||||
|
ntripClient.print((const char *)nmeaData.nmea);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
|
|
||||||
|
// Callback: printPVTdata will be called when new NAV PVT data arrives
|
||||||
|
// See u-blox_structs.h for the full definition of UBX_NAV_PVT_data_t
|
||||||
|
// _____ You can use any name you like for the callback. Use the same name when you call setAutoPVTcallback
|
||||||
|
// / _____ This _must_ be UBX_NAV_PVT_data_t
|
||||||
|
// | / _____ You can use any name you like for the struct
|
||||||
|
// | | /
|
||||||
|
// | | |
|
||||||
|
void printPVTdata(UBX_NAV_PVT_data_t ubxDataStruct)
|
||||||
|
{
|
||||||
|
long latitude = ubxDataStruct.lat; // Print the latitude
|
||||||
|
Serial.print(F("Lat: "));
|
||||||
|
Serial.print(latitude / 10000000L);
|
||||||
|
Serial.print(F("."));
|
||||||
|
Serial.print(abs(latitude % 10000000L));
|
||||||
|
|
||||||
|
long longitude = ubxDataStruct.lon; // Print the longitude
|
||||||
|
Serial.print(F(" Long: "));
|
||||||
|
Serial.print(longitude / 10000000L);
|
||||||
|
Serial.print(F("."));
|
||||||
|
Serial.print(abs(longitude % 10000000L));
|
||||||
|
|
||||||
|
long altitude = ubxDataStruct.hMSL; // Print the height above mean sea level
|
||||||
|
Serial.print(F(" Height: "));
|
||||||
|
Serial.print(altitude);
|
||||||
|
Serial.print(F(" (mm)"));
|
||||||
|
|
||||||
|
uint8_t fixType = ubxDataStruct.fixType; // Print the fix type
|
||||||
|
Serial.print(F(" Fix: "));
|
||||||
|
Serial.print(fixType);
|
||||||
|
if (fixType == 0)
|
||||||
|
Serial.print(F(" (None)"));
|
||||||
|
else if (fixType == 1)
|
||||||
|
Serial.print(F(" (Dead Reckoning)"));
|
||||||
|
else if (fixType == 2)
|
||||||
|
Serial.print(F(" (2D)"));
|
||||||
|
else if (fixType == 3)
|
||||||
|
Serial.print(F(" (3D)"));
|
||||||
|
else if (fixType == 3)
|
||||||
|
Serial.print(F(" (GNSS + Dead Reckoning)"));
|
||||||
|
else if (fixType == 5)
|
||||||
|
Serial.print(F(" (Time Only)"));
|
||||||
|
else
|
||||||
|
Serial.print(F(" (UNKNOWN)"));
|
||||||
|
|
||||||
|
uint8_t carrSoln = ubxDataStruct.flags.bits.carrSoln; // Print the carrier solution
|
||||||
|
Serial.print(F(" Carrier Solution: "));
|
||||||
|
Serial.print(carrSoln);
|
||||||
|
if (carrSoln == 0)
|
||||||
|
Serial.print(F(" (None)"));
|
||||||
|
else if (carrSoln == 1)
|
||||||
|
Serial.print(F(" (Floating)"));
|
||||||
|
else if (carrSoln == 2)
|
||||||
|
Serial.print(F(" (Fixed)"));
|
||||||
|
else
|
||||||
|
Serial.print(F(" (UNKNOWN)"));
|
||||||
|
|
||||||
|
uint32_t hAcc = ubxDataStruct.hAcc; // Print the horizontal accuracy estimate
|
||||||
|
Serial.print(F(" Horizontal Accuracy Estimate: "));
|
||||||
|
Serial.print(hAcc);
|
||||||
|
Serial.print(F(" (mm)"));
|
||||||
|
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println(F("NTRIP testing"));
|
||||||
|
|
||||||
|
Wire.begin(); //Start I2C
|
||||||
|
|
||||||
|
while (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."));
|
||||||
|
delay(2000);
|
||||||
|
//while (1);
|
||||||
|
}
|
||||||
|
Serial.println(F("u-blox module connected"));
|
||||||
|
|
||||||
|
myGNSS.setI2COutput(COM_TYPE_UBX | COM_TYPE_NMEA); //Set the I2C port to output both NMEA and UBX messages
|
||||||
|
myGNSS.setPortInput(COM_PORT_I2C, COM_TYPE_UBX | COM_TYPE_NMEA | COM_TYPE_RTCM3); //Be sure RTCM3 input is enabled. UBX + RTCM3 is not a valid state.
|
||||||
|
|
||||||
|
myGNSS.setDGNSSConfiguration(SFE_UBLOX_DGNSS_MODE_FIXED); // Set the differential mode - ambiguities are fixed whenever possible
|
||||||
|
|
||||||
|
myGNSS.setNavigationFrequency(1); //Set output in Hz.
|
||||||
|
|
||||||
|
// Set the Main Talker ID to "GP". The NMEA GGA messages will be GPGGA instead of GNGGA
|
||||||
|
myGNSS.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_GP);
|
||||||
|
|
||||||
|
myGNSS.setNMEAGPGGAcallback(&pushGPGGA); // Set up the callback for GPGGA
|
||||||
|
|
||||||
|
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C, 10); // Tell the module to output GGA every 10 seconds
|
||||||
|
|
||||||
|
myGNSS.setAutoPVTcallback(&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
|
||||||
|
|
||||||
|
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
|
|
||||||
|
bool keepTrying = true;
|
||||||
|
while (keepTrying)
|
||||||
|
{
|
||||||
|
Serial.print(F("Connecting to local WiFi"));
|
||||||
|
|
||||||
|
unsigned long startTime = millis();
|
||||||
|
WiFi.begin(ssid, password);
|
||||||
|
while ((WiFi.status() != WL_CONNECTED) && (millis() < (startTime + 10000))) // Timeout after 10 seconds
|
||||||
|
{
|
||||||
|
delay(500);
|
||||||
|
Serial.print(F("."));
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
if (WiFi.status() == WL_CONNECTED)
|
||||||
|
keepTrying = false; // Connected!
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WiFi.disconnect(true);
|
||||||
|
WiFi.mode(WIFI_OFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.print(F("WiFi connected with IP: "));
|
||||||
|
Serial.println(WiFi.localIP());
|
||||||
|
|
||||||
|
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
|
|
||||||
|
while (Serial.available()) // Empty the serial buffer
|
||||||
|
Serial.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
myGNSS.checkUblox(); // Check for the arrival of new GNSS data and process it.
|
||||||
|
myGNSS.checkCallbacks(); // Check if any GNSS callbacks are waiting to be processed.
|
||||||
|
|
||||||
|
enum states // Use a 'state machine' to open and close the connection
|
||||||
|
{
|
||||||
|
open_connection,
|
||||||
|
push_data_and_wait_for_keypress,
|
||||||
|
close_connection,
|
||||||
|
waiting_for_keypress
|
||||||
|
};
|
||||||
|
static states state = open_connection;
|
||||||
|
|
||||||
|
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
|
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case open_connection:
|
||||||
|
Serial.println(F("Connecting to the NTRIP caster..."));
|
||||||
|
if (beginClient()) // Try to open the connection to the caster
|
||||||
|
{
|
||||||
|
Serial.println(F("Connected to the NTRIP caster! Press any key to disconnect..."));
|
||||||
|
state = push_data_and_wait_for_keypress; // Move on
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial.print(F("Could not connect to the caster. Trying again in 5 seconds."));
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
delay(1000);
|
||||||
|
Serial.print(F("."));
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
|
|
||||||
|
case push_data_and_wait_for_keypress:
|
||||||
|
// If the connection has dropped or timed out, or if the user has pressed a key
|
||||||
|
if ((processConnection() == false) || (keyPressed()))
|
||||||
|
{
|
||||||
|
state = close_connection; // Move on
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
|
|
||||||
|
case close_connection:
|
||||||
|
Serial.println(F("Closing the connection to the NTRIP caster..."));
|
||||||
|
closeConnection();
|
||||||
|
Serial.println(F("Press any key to reconnect..."));
|
||||||
|
state = waiting_for_keypress; // Move on
|
||||||
|
break;
|
||||||
|
|
||||||
|
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
|
|
||||||
|
case waiting_for_keypress:
|
||||||
|
// If the connection has dropped or timed out, or if the user has pressed a key
|
||||||
|
if (keyPressed())
|
||||||
|
state = open_connection; // Move on
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
|
|
||||||
|
//Connect to NTRIP Caster. Return true is connection is successful.
|
||||||
|
bool beginClient()
|
||||||
|
{
|
||||||
|
Serial.print(F("Opening socket to "));
|
||||||
|
Serial.println(casterHost);
|
||||||
|
|
||||||
|
if (ntripClient.connect(casterHost, casterPort) == false) //Attempt connection
|
||||||
|
{
|
||||||
|
Serial.println(F("Connection to caster failed"));
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial.print(F("Connected to "));
|
||||||
|
Serial.print(casterHost);
|
||||||
|
Serial.print(F(" : "));
|
||||||
|
Serial.println(casterPort);
|
||||||
|
|
||||||
|
Serial.print(F("Requesting NTRIP Data from mount point "));
|
||||||
|
Serial.println(mountPoint);
|
||||||
|
|
||||||
|
// Set up the server request (GET)
|
||||||
|
const int SERVER_BUFFER_SIZE = 512;
|
||||||
|
char serverRequest[SERVER_BUFFER_SIZE];
|
||||||
|
snprintf(serverRequest,
|
||||||
|
SERVER_BUFFER_SIZE,
|
||||||
|
"GET /%s HTTP/1.0\r\nUser-Agent: NTRIP SparkFun u-blox Client v1.0\r\n",
|
||||||
|
mountPoint);
|
||||||
|
|
||||||
|
// Set up the credentials
|
||||||
|
char credentials[512];
|
||||||
|
if (strlen(casterUser) == 0)
|
||||||
|
{
|
||||||
|
strncpy(credentials, "Accept: */*\r\nConnection: close\r\n", sizeof(credentials));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Pass base64 encoded user:pw
|
||||||
|
char userCredentials[sizeof(casterUser) + sizeof(casterUserPW) + 1]; //The ':' takes up a spot
|
||||||
|
snprintf(userCredentials, sizeof(userCredentials), "%s:%s", casterUser, casterUserPW);
|
||||||
|
|
||||||
|
Serial.print(F("Sending credentials: "));
|
||||||
|
Serial.println(userCredentials);
|
||||||
|
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
|
//Encode with ESP32 built-in library
|
||||||
|
base64 b;
|
||||||
|
String strEncodedCredentials = b.encode(userCredentials);
|
||||||
|
char encodedCredentials[strEncodedCredentials.length() + 1];
|
||||||
|
strEncodedCredentials.toCharArray(encodedCredentials, sizeof(encodedCredentials)); //Convert String to char array
|
||||||
|
#else
|
||||||
|
//Encode with nfriendly library
|
||||||
|
int encodedLen = base64_enc_len(strlen(userCredentials));
|
||||||
|
char encodedCredentials[encodedLen]; //Create array large enough to house encoded data
|
||||||
|
base64_encode(encodedCredentials, userCredentials, strlen(userCredentials)); //Note: Input array is consumed
|
||||||
|
#endif
|
||||||
|
|
||||||
|
snprintf(credentials, sizeof(credentials), "Authorization: Basic %s\r\n", encodedCredentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the encoded credentials to the server request
|
||||||
|
strncat(serverRequest, credentials, SERVER_BUFFER_SIZE);
|
||||||
|
strncat(serverRequest, "\r\n", SERVER_BUFFER_SIZE);
|
||||||
|
|
||||||
|
Serial.print(F("serverRequest size: "));
|
||||||
|
Serial.print(strlen(serverRequest));
|
||||||
|
Serial.print(F(" of "));
|
||||||
|
Serial.print(sizeof(serverRequest));
|
||||||
|
Serial.println(F(" bytes available"));
|
||||||
|
|
||||||
|
// Send the server request
|
||||||
|
Serial.println(F("Sending server request: "));
|
||||||
|
Serial.println(serverRequest);
|
||||||
|
ntripClient.write(serverRequest, strlen(serverRequest));
|
||||||
|
|
||||||
|
//Wait up to 5 seconds for response
|
||||||
|
unsigned long startTime = millis();
|
||||||
|
while (ntripClient.available() == 0)
|
||||||
|
{
|
||||||
|
if (millis() > (startTime + 5000))
|
||||||
|
{
|
||||||
|
Serial.println(F("Caster timed out!"));
|
||||||
|
ntripClient.stop();
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check reply
|
||||||
|
int connectionResult = 0;
|
||||||
|
char response[512];
|
||||||
|
size_t responseSpot = 0;
|
||||||
|
while (ntripClient.available()) // Read bytes from the caster and store them
|
||||||
|
{
|
||||||
|
if (responseSpot == sizeof(response) - 1) // Exit the loop if we get too much data
|
||||||
|
break;
|
||||||
|
|
||||||
|
response[responseSpot++] = ntripClient.read();
|
||||||
|
|
||||||
|
if (connectionResult == 0) // Only print success/fail once
|
||||||
|
{
|
||||||
|
if (strstr(response, "200") != NULL) //Look for '200 OK'
|
||||||
|
{
|
||||||
|
connectionResult = 200;
|
||||||
|
}
|
||||||
|
if (strstr(response, "401") != NULL) //Look for '401 Unauthorized'
|
||||||
|
{
|
||||||
|
Serial.println(F("Hey - your credentials look bad! Check your caster username and password."));
|
||||||
|
connectionResult = 401;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response[responseSpot] = '\0'; // NULL-terminate the response
|
||||||
|
|
||||||
|
//Serial.print(F("Caster responded with: ")); Serial.println(response); // Uncomment this line to see the full response
|
||||||
|
|
||||||
|
if (connectionResult != 200)
|
||||||
|
{
|
||||||
|
Serial.print(F("Failed to connect to "));
|
||||||
|
Serial.println(casterHost);
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial.print(F("Connected to: "));
|
||||||
|
Serial.println(casterHost);
|
||||||
|
lastReceivedRTCM_ms = millis(); //Reset timeout
|
||||||
|
}
|
||||||
|
} //End attempt to connect
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
} // /beginClient
|
||||||
|
|
||||||
|
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
|
|
||||||
|
//Check for the arrival of any correction data. Push it to the GNSS.
|
||||||
|
//Return false if: the connection has dropped, or if we receive no data for maxTimeBeforeHangup_ms
|
||||||
|
bool processConnection()
|
||||||
|
{
|
||||||
|
if (ntripClient.connected() == true) // Check that the connection is still open
|
||||||
|
{
|
||||||
|
uint8_t rtcmData[512 * 4]; //Most incoming data is around 500 bytes but may be larger
|
||||||
|
size_t rtcmCount = 0;
|
||||||
|
|
||||||
|
//Collect any available RTCM data
|
||||||
|
while (ntripClient.available())
|
||||||
|
{
|
||||||
|
//Serial.write(ntripClient.read()); //Pipe to serial port is fine but beware, it's a lot of binary data!
|
||||||
|
rtcmData[rtcmCount++] = ntripClient.read();
|
||||||
|
if (rtcmCount == sizeof(rtcmData))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rtcmCount > 0)
|
||||||
|
{
|
||||||
|
lastReceivedRTCM_ms = millis();
|
||||||
|
|
||||||
|
//Push RTCM to GNSS module over I2C
|
||||||
|
myGNSS.pushRawData(rtcmData, rtcmCount);
|
||||||
|
|
||||||
|
Serial.print(F("Pushed "));
|
||||||
|
Serial.print(rtcmCount);
|
||||||
|
Serial.println(F(" RTCM bytes to ZED"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial.println(F("Connection dropped!"));
|
||||||
|
return (false); // Connection has dropped - return false
|
||||||
|
}
|
||||||
|
|
||||||
|
//Timeout if we don't have new data for maxTimeBeforeHangup_ms
|
||||||
|
if ((millis() - lastReceivedRTCM_ms) > maxTimeBeforeHangup_ms)
|
||||||
|
{
|
||||||
|
Serial.println(F("RTCM timeout!"));
|
||||||
|
return (false); // Connection has timed out - return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
} // /processConnection
|
||||||
|
|
||||||
|
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
|
|
||||||
|
void closeConnection()
|
||||||
|
{
|
||||||
|
if (ntripClient.connected() == true)
|
||||||
|
{
|
||||||
|
ntripClient.stop();
|
||||||
|
}
|
||||||
|
Serial.println(F("Disconnected!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
|
|
||||||
|
//Return true if a key has been pressed
|
||||||
|
bool keyPressed()
|
||||||
|
{
|
||||||
|
if (Serial.available()) // Check for a new key press
|
||||||
|
{
|
||||||
|
delay(100); // Wait for any more keystrokes to arrive
|
||||||
|
while (Serial.available()) // Empty the serial buffer
|
||||||
|
Serial.read();
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
//Your WiFi credentials
|
||||||
|
const char ssid[] = "yourSSID";
|
||||||
|
const char password[] = "yourPassword";
|
||||||
|
|
||||||
|
//RTK2Go works well and is free
|
||||||
|
//const char casterHost[] = "rtk2go.com";
|
||||||
|
//const uint16_t casterPort = 2101;
|
||||||
|
//const char casterUser[] = "myEmail@test.com"; //User must provide their own email address to use RTK2Go
|
||||||
|
//const char casterUserPW[] = "";
|
||||||
|
//const char mountPoint[] = "bldr_SparkFun1"; //The mount point you want to get data from
|
||||||
|
|
||||||
|
//Emlid Caster also works well and is free
|
||||||
|
//const char casterHost[] = "caster.emlid.com";
|
||||||
|
//const uint16_t casterPort = 2101;
|
||||||
|
//const char casterUser[] = "u99696"; //User name and pw must be obtained through their web portal
|
||||||
|
//const char casterUserPW[] = "466zez";
|
||||||
|
//const char mountPoint[] = "MP1979"; //The mount point you want to get data from
|
||||||
|
|
||||||
|
// Skylark (Swift Navigation) is awesome - but requires a subscription:
|
||||||
|
// https://www.swiftnav.com/skylark
|
||||||
|
// https://account.swiftnav.com/sign-up
|
||||||
|
// Use the promo-code ONEMONTHFREE for a free one month access to Skylark on one device
|
||||||
|
const char casterHost[] = "na.skylark.swiftnav.com"; // na = North Americs L1+L2; eu = Europe L1+L2
|
||||||
|
const uint16_t casterPort = 2101;
|
||||||
|
const char casterUser[] = "NTRIPusername+accountSubdomain"; // This is generated when you add a device to your Skylark account
|
||||||
|
const char casterUserPW[] = "devicePassword";
|
||||||
|
const char mountPoint[] = "CRS"; // The mount point you want to get data from. Select CRS (Cloud Reference Station) for the ZED-F9x
|
||||||
Reference in New Issue
Block a user