Merge pull request #92 from sparkfun/AddGPGGAToNTRIP

Add NTRIP Client with GGA example
This commit is contained in:
Paul
2021-12-14 10:43:54 +00:00
committed by GitHub
5 changed files with 532 additions and 84 deletions
@@ -1,7 +1,5 @@
/*
Note: compiles OK with v2.0 but is currently untested
Use ESP32 WiFi to push RTCM data to RTK2Go (caster) as a Server
Use ESP32 WiFi to push RTCM data to RTK2Go (Caster) as a Server
By: SparkFun Electronics / Nathan Seidle
Date: December 14th, 2020
License: MIT. See license file for more information but you can
@@ -33,25 +31,20 @@
#include <WiFi.h>
#include "secrets.h"
WiFiClient client;
WiFiClient ntripCaster;
#include <Wire.h> //Needed for I2C to GNSS
#include <Wire.h>
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
//Basic Connection settings to RTK2Go NTRIP Caster - See secrets for mount specific credentials
//Global Variables
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
const uint16_t casterPort = 2101;
const char * casterHost = "rtk2go.com";
const char * ntrip_server_name = "SparkFun_RTK_Surveyor";
long lastSentRTCM_ms = 0; //Time of last data pushed to socket
int maxTimeBeforeHangup_ms = 10000; //If we fail to get a complete RTCM frame after 10s, then disconnect from caster
uint32_t serverBytesSent = 0; //Just a running total
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
long lastReport_ms = 0; //Time of last report of bytes sent
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
@@ -73,7 +66,8 @@ void setup()
Serial.print("Connecting to local WiFi");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
@@ -98,7 +92,8 @@ void setup()
if (response == false)
{
Serial.println(F("Failed to disable NMEA. Freezing..."));
while (1);
while (1)
;
}
else
Serial.println(F("NMEA disabled"));
@@ -114,7 +109,8 @@ void setup()
if (response == false)
{
Serial.println(F("Failed to enable RTCM. Freezing..."));
while (1);
while (1)
;
}
else
Serial.println(F("RTCM sentences enabled"));
@@ -129,63 +125,72 @@ void setup()
if (response == false)
{
Serial.println(F("Failed to enter static position. Freezing..."));
while (1);
while (1)
;
}
else
Serial.println(F("Static position set"));
//You could instead do a survey-in but it takes much longer to start generating RTCM data. See Example4_BaseWithLCD
//Alternatively to setting a static position, you could do a survey-in
//but it takes much longer to start generating RTCM data. See Example4_BaseWithLCD
//myGNSS.enableSurveyMode(60, 5.000); //Enable Survey in, 60 seconds, 5.0m
if (myGNSS.saveConfiguration() == false) //Save the current settings to flash and BBR
Serial.println(F("Module failed to save."));
//If you were setting up a full GNSS station, you would want to save these settings.
//Because setting an incorrect static position will disable the ability to get a lock, we will skip saving during this example
//if (myGNSS.saveConfiguration() == false) //Save the current settings to flash and BBR
// Serial.println(F("Module failed to save"));
Serial.println(F("Module configuration complete"));
}
void loop()
{
if (Serial.available()) beginServing();
if (Serial.available())
beginServing();
Serial.println(F("Press any key to start serving."));
Serial.println(F("Press any key to start serving"));
delay(1000);
}
void beginServing()
{
Serial.println("Xmit to RTK2Go. Press any key to stop");
Serial.println("Begin transmitting to caster. Press any key to stop");
delay(10); //Wait for any serial to arrive
while (Serial.available()) Serial.read(); //Flush
while (Serial.available())
Serial.read(); //Flush
while (Serial.available() == 0)
{
//Connect if we are not already
if (client.connected() == false)
if (ntripCaster.connected() == false)
{
Serial.printf("Opening socket to %s\n", casterHost);
if (client.connect(casterHost, casterPort) == true) //Attempt connection
if (ntripCaster.connect(casterHost, casterPort) == true) //Attempt connection
{
Serial.printf("Connected to %s:%d\n", casterHost, casterPort);
const int SERVER_BUFFER_SIZE = 512;
char serverBuffer[SERVER_BUFFER_SIZE];
char serverRequest[SERVER_BUFFER_SIZE];
snprintf(serverBuffer, SERVER_BUFFER_SIZE, "SOURCE %s /%s\r\nSource-Agent: NTRIP %s/%s\r\n\r\n",
mntpnt_pw, mntpnt, ntrip_server_name, "App Version 1.0");
snprintf(serverRequest,
SERVER_BUFFER_SIZE,
"SOURCE %s /%s\r\nSource-Agent: NTRIP SparkFun u-blox Server v1.0\r\n\r\n",
mountPointPW, mountPoint);
Serial.printf("Sending credentials:\n%s\n", serverBuffer);
client.write(serverBuffer, strlen(serverBuffer));
Serial.println(F("Sending server request:"));
Serial.println(serverRequest);
ntripCaster.write(serverRequest, strlen(serverRequest));
//Wait for response
unsigned long timeout = millis();
while (client.available() == 0)
while (ntripCaster.available() == 0)
{
if (millis() - timeout > 5000)
{
Serial.println(">>> Client Timeout !");
client.stop();
Serial.println("Caster timed out!");
ntripCaster.stop();
return;
}
delay(10);
@@ -195,30 +200,34 @@ void beginServing()
bool connectionSuccess = false;
char response[512];
int responseSpot = 0;
while (client.available())
while (ntripCaster.available())
{
response[responseSpot++] = client.read();
response[responseSpot++] = ntripCaster.read();
if (strstr(response, "200") > 0) //Look for 'ICY 200 OK'
connectionSuccess = true;
if (responseSpot == 512 - 1) break;
if (responseSpot == 512 - 1)
break;
}
response[responseSpot] = '\0';
if (connectionSuccess == false)
{
Serial.printf("Failed to connect to RTK2Go: %s", response);
Serial.printf("Failed to connect to Caster: %s", response);
return;
}
} //End attempt to connect
else
{
Serial.println("Connection to host failed");
return;
}
} //End connected == false
if (client.connected() == true)
if (ntripCaster.connected() == true)
{
delay(10);
while (Serial.available()) Serial.read(); //Flush any endlines or carriage returns
while (Serial.available())
Serial.read(); //Flush any endlines or carriage returns
lastReport_ms = millis();
lastSentRTCM_ms = millis();
@@ -226,7 +235,8 @@ void beginServing()
//This is the main sending loop. We scan for new ublox data but processRTCM() is where the data actually gets sent out.
while (1)
{
if (Serial.available()) break;
if (Serial.available())
break;
myGNSS.checkUblox(); //See if new data is available. Process bytes as they come in.
@@ -236,7 +246,7 @@ void beginServing()
if (millis() - lastSentRTCM_ms > maxTimeBeforeHangup_ms)
{
Serial.println("RTCM timeout. Disconnecting...");
client.stop();
ntripCaster.stop();
return;
}
@@ -256,10 +266,11 @@ void beginServing()
Serial.println("User pressed a key");
Serial.println("Disconnecting...");
client.stop();
ntripCaster.stop();
delay(10);
while (Serial.available()) Serial.read(); //Flush any endlines or carriage returns
while (Serial.available())
Serial.read(); //Flush any endlines or carriage returns
}
//This function gets called from the SparkFun u-blox Arduino Library.
@@ -267,9 +278,9 @@ void beginServing()
//Useful for passing the RTCM correction data to a radio, Ntrip broadcaster, etc.
void SFE_UBLOX_GNSS::processRTCM(uint8_t incoming)
{
if (client.connected() == true)
if (ntripCaster.connected() == true)
{
client.write(incoming); //Send this byte to socket
ntripCaster.write(incoming); //Send this byte to socket
serverBytesSent++;
lastSentRTCM_ms = millis();
}
@@ -1,7 +1,15 @@
//Your WiFi credentials
const char* ssid = "TRex";
const char* password = "hasBigTeeth";
const char *ssid = "TRex";
const char *password = "hasBigTeeth";
//Your RTK2GO mount point credentials
const char* mntpnt_pw = "WR5wRo4H";
const char* mntpnt = "bldr_dwntwn2";
//RTK2Go works well and is free
const char casterHost[] = "rtk2go.com";
const uint16_t casterPort = 2101;
const char mountPoint[] = "bldr_dwntwn2"; //The mount point you want to push data to
const char mountPointPW[] = "WR5wRo4H";
//Emlid Caster also works well and is free
//const char casterHost[] = "caster.emlid.com";
//const uint16_t casterPort = 2101;
//const char mountPoint[] = "MP1979d"; //The mount point you want to push data to
//const char mountPointPW[] = "296ynq";
@@ -16,6 +16,9 @@
This is a proof of concept to show how to connect to a caster via HTTP. Using WiFi for a rover
is generally a bad idea because of limited WiFi range in the field.
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/
Feel like supporting open source hardware?
Buy a board from SparkFun!
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
@@ -50,7 +53,7 @@ int maxTimeBeforeHangup_ms = 10000; //If we fail to get a complete RTCM frame af
void setup()
{
Serial.begin(115200);
Serial.println("NTRIP testing");
Serial.println(F("NTRIP testing"));
Wire.begin(); //Start I2C
@@ -66,15 +69,15 @@ void setup()
myGNSS.setNavigationFrequency(1); //Set output in Hz.
Serial.print("Connecting to local WiFi");
Serial.print(F("Connecting to local WiFi"));
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
Serial.print(F("."));
}
Serial.println();
Serial.print("WiFi connected with IP: ");
Serial.print(F("WiFi connected with IP: "));
Serial.println(WiFi.localIP());
while (Serial.available()) Serial.read();
@@ -82,7 +85,11 @@ void setup()
void loop()
{
if (Serial.available()) beginClient();
if (Serial.available())
{
beginClient();
while (Serial.available()) Serial.read(); //Empty buffer of any newline chars
}
Serial.println(F("Press any key to start NTRIP Client."));
@@ -95,36 +102,37 @@ void beginClient()
WiFiClient ntripClient;
long rtcmCount = 0;
Serial.println("Subscribing to Caster. Press key to stop");
Serial.println(F("Subscribing to Caster. 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
//Connect if we are not already. Limit to 5s between attempts.
if (ntripClient.connected() == false)
{
Serial.print("Opening socket to");
Serial.print(F("Opening socket to "));
Serial.println(casterHost);
if (ntripClient.connect(casterHost, casterPort) == false) //Attempt connection
{
Serial.println("Connection to caster failed");
Serial.println(F("Connection to caster failed"));
return;
}
else
{
Serial.print("Connected to ");
Serial.print(F("Connected to "));
Serial.print(casterHost);
Serial.print(": ");
Serial.print(F(": "));
Serial.println(casterPort);
Serial.print("Requesting NTRIP Data from mount point ");
Serial.print(F("Requesting NTRIP Data from mount point "));
Serial.println(mountPoint);
const int SERVER_BUFFER_SIZE = 512;
char serverRequest[SERVER_BUFFER_SIZE];
snprintf(serverRequest, SERVER_BUFFER_SIZE, "GET /%s HTTP/1.0\r\nUser-Agent: SparkFun u-blox NTRIPClient v1.0\r\n",
snprintf(serverRequest, SERVER_BUFFER_SIZE, "GET /%s HTTP/1.0\r\nUser-Agent: NTRIP SparkFun u-blox Client v1.0\r\n",
mountPoint);
char credentials[512];
@@ -138,7 +146,7 @@ void beginClient()
char userCredentials[sizeof(casterUser) + sizeof(casterUserPW) + 1]; //The ':' takes up a spot
snprintf(userCredentials, sizeof(userCredentials), "%s:%s", casterUser, casterUserPW);
Serial.print("Sending credentials: ");
Serial.print(F("Sending credentials: "));
Serial.println(userCredentials);
#if defined(ARDUINO_ARCH_ESP32)
@@ -158,13 +166,13 @@ void beginClient()
strncat(serverRequest, credentials, SERVER_BUFFER_SIZE);
strncat(serverRequest, "\r\n", SERVER_BUFFER_SIZE);
Serial.print("serverRequest size: ");
Serial.print(F("serverRequest size: "));
Serial.print(strlen(serverRequest));
Serial.print(" of ");
Serial.print(F(" of "));
Serial.print(sizeof(serverRequest));
Serial.println(" bytes available");
Serial.println(F(" bytes available"));
Serial.println("Sending server request:");
Serial.println(F("Sending server request:"));
Serial.println(serverRequest);
ntripClient.write(serverRequest, strlen(serverRequest));
@@ -174,7 +182,7 @@ void beginClient()
{
if (millis() - timeout > 5000)
{
Serial.println("Mountpoint timed out!");
Serial.println(F("Caster timed out!"));
ntripClient.stop();
return;
}
@@ -194,23 +202,26 @@ void beginClient()
connectionSuccess = true;
if (strstr(response, "401") > 0) //Look for '401 Unauthorized'
{
Serial.println("Hey - your credentials look bad! Check you caster username and password.");
Serial.println(F("Hey - your credentials look bad! Check you caster username and password."));
connectionSuccess = false;
}
}
response[responseSpot] = '\0';
Serial.print(F("Caster responded with: "));
Serial.println(response);
if (connectionSuccess == false)
{
Serial.print("Failed to connect to ");
Serial.print(F("Failed to connect to "));
Serial.print(casterHost);
Serial.print(": ");
Serial.print(F(": "));
Serial.println(response);
delay(5000); //Don't spam with lots of connection attempts
return;
}
else
{
Serial.print("Connected to ");
Serial.print(F("Connected to "));
Serial.println(casterHost);
lastReceivedRTCM_ms = millis(); //Reset timeout
}
@@ -236,7 +247,7 @@ void beginClient()
//Push RTCM to GNSS module over I2C
myGNSS.pushRawData(rtcmData, rtcmCount, false);
Serial.print("RTCM pushed to ZED: ");
Serial.print(F("RTCM pushed to ZED: "));
Serial.println(rtcmCount);
}
}
@@ -244,7 +255,7 @@ void beginClient()
//Close socket if we don't have new data for 10s
if (millis() - lastReceivedRTCM_ms > maxTimeBeforeHangup_ms)
{
Serial.println("RTCM timeout. Disconnecting...");
Serial.println(F("RTCM timeout. Disconnecting..."));
if (ntripClient.connected() == true)
ntripClient.stop();
return;
@@ -253,9 +264,7 @@ void beginClient()
delay(10);
}
Serial.println("User pressed a key");
Serial.println("Disconnecting...");
Serial.println(F("User pressed a key"));
Serial.println(F("Disconnecting..."));
ntripClient.stop();
while (Serial.available()) Serial.read(); //Empty buffer of any newline chars
}
@@ -0,0 +1,403 @@
/*
Use ESP32 WiFi to get RTCM data from RTK2Go (caster) as a Client, and transmit GGA (needed for some Casters)
By: SparkFun Electronics / Nathan Seidle
Date: November 18th, 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 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 RTK2Go.com as our caster because it is free. See the NTRIPServer example to see how
to push RTCM data to the caster.
The rover's location will be broadcast to the Caster every 10s via GGA setence.
You will need to have a valid mountpoint available. To see available mountpoints go here: http://rtk2go.com:2101/
This is a proof of concept to show how to connect to a caster via HTTP.
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
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
long lastReceivedRTCM_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
bool transmitLocation = true; //By default we will transmit the units location via GGA sentence.
int timeBetweenGGAUpdate_ms = 10000; //GGA is required for Rev2 NTRIP casters. Don't transmit but once every 10 seconds
long lastTransmittedGGA_ms = 0;
//Used for GGA sentence parsing from incoming NMEA
bool ggaSentenceStarted = false;
bool ggaSentenceComplete = false;
bool ggaTransmitComplete = false; //Goes true once we transmit GGA to the caster
char ggaSentence[128] = {0};
byte ggaSentenceSpot = 0;
int ggaSentenceEndSpot = 0;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C); //Verify the GGA sentence 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 NTRIP Client."));
delay(1000);
}
//Connect to NTRIP Caster, receive RTCM, and push to ZED module over I2C
void beginClient()
{
WiFiClient ntripClient;
long rtcmCount = 0;
Serial.println(F("Subscribing to Caster. Press key to stop"));
delay(10); //Wait for any serial to arrive
while (Serial.available())
Serial.read(); //Flush
while (Serial.available() == 0)
{
myGNSS.checkUblox();
//Connect if we are not already. Limit to 5s between attempts.
if (ntripClient.connected() == false)
{
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;
}
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);
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);
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);
}
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"));
Serial.println(F("Sending server request:"));
Serial.println(serverRequest);
ntripClient.write(serverRequest, strlen(serverRequest));
//Wait for response
unsigned long timeout = millis();
while (ntripClient.available() == 0)
{
if (millis() - timeout > 5000)
{
Serial.println(F("Caster timed out!"));
ntripClient.stop();
return;
}
delay(10);
}
//Check reply
bool connectionSuccess = false;
char response[512];
int responseSpot = 0;
while (ntripClient.available())
{
if (responseSpot == sizeof(response) - 1)
break;
response[responseSpot++] = ntripClient.read();
if (strstr(response, "200") > 0) //Look for '200 OK'
connectionSuccess = true;
if (strstr(response, "401") > 0) //Look for '401 Unauthorized'
{
Serial.println(F("Hey - your credentials look bad! Check you caster username and password."));
connectionSuccess = false;
}
}
response[responseSpot] = '\0';
Serial.print(F("Caster responded with: "));
Serial.println(response);
if (connectionSuccess == false)
{
Serial.print(F("Failed to connect to "));
Serial.println(casterHost);
return;
}
else
{
Serial.print(F("Connected to "));
Serial.println(casterHost);
lastReceivedRTCM_ms = millis(); //Reset timeout
ggaTransmitComplete = true; //Reset to start polling for new GGA data
}
} //End attempt to connect
} //End connected == false
if (ntripClient.connected() == true)
{
uint8_t rtcmData[512 * 4]; //Most incoming data is around 500 bytes but may be larger
rtcmCount = 0;
//Print 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, false);
Serial.print(F("RTCM pushed to ZED: "));
Serial.println(rtcmCount);
}
}
//Provide the caster with our current position as needed
if (ntripClient.connected() == true && transmitLocation == true && (millis() - lastTransmittedGGA_ms) > timeBetweenGGAUpdate_ms && ggaSentenceComplete == true && ggaTransmitComplete == false)
{
Serial.print(F("Pushing GGA to server: "));
Serial.println(ggaSentence);
lastTransmittedGGA_ms = millis();
//Push our current GGA sentence to caster
ntripClient.print(ggaSentence);
ntripClient.print("\r\n");
ggaTransmitComplete = true;
//Wait for response
unsigned long timeout = millis();
while (ntripClient.available() == 0)
{
if (millis() - timeout > 5000)
{
Serial.println(F("Caster timed out!"));
ntripClient.stop();
return;
}
delay(10);
}
//Check reply
bool connectionSuccess = false;
char response[512];
int responseSpot = 0;
while (ntripClient.available())
{
if (responseSpot == sizeof(response) - 1)
break;
response[responseSpot++] = ntripClient.read();
if (strstr(response, "200") > 0) //Look for '200 OK'
connectionSuccess = true;
if (strstr(response, "401") > 0) //Look for '401 Unauthorized'
{
Serial.println(F("Hey - your credentials look bad! Check you caster username and password."));
connectionSuccess = false;
}
}
response[responseSpot] = '\0';
Serial.print(F("Caster responded with: "));
Serial.println(response);
}
//Close socket if we don't have new data for 10s
if (millis() - lastReceivedRTCM_ms > maxTimeBeforeHangup_ms)
{
Serial.println(F("RTCM timeout. Disconnecting..."));
if (ntripClient.connected() == true)
ntripClient.stop();
return;
}
delay(10);
}
Serial.println(F("User pressed a key"));
Serial.println(F("Disconnecting..."));
ntripClient.stop();
}
//This function gets called from the SparkFun u-blox Arduino Library
//As each NMEA character comes in you can specify what to do with it
//We will look for and copy the GGA sentence
void SFE_UBLOX_GNSS::processNMEA(char incoming)
{
//Take the incoming char from the u-blox I2C port and check to see if we should record it or not
if (incoming == '$' && ggaTransmitComplete == true)
{
ggaSentenceStarted = true;
ggaSentenceSpot = 0;
ggaSentenceEndSpot = sizeof(ggaSentence);
ggaSentenceComplete = false;
}
if (ggaSentenceStarted == true)
{
ggaSentence[ggaSentenceSpot++] = incoming;
//Make sure we don't go out of bounds
if (ggaSentenceSpot == sizeof(ggaSentence))
{
//Start over
ggaSentenceStarted = false;
}
//Verify this is the GGA setence
else if (ggaSentenceSpot == 5 && incoming != 'G')
{
//Ignore this sentence, start over
ggaSentenceStarted = false;
}
else if (incoming == '*')
{
//We're near the end. Keep listening for two more bytes to complete the CRC
ggaSentenceEndSpot = ggaSentenceSpot + 2;
}
else if (ggaSentenceSpot == ggaSentenceEndSpot)
{
ggaSentence[ggaSentenceSpot] = '\0'; //Terminate this string
ggaSentenceComplete = true;
ggaTransmitComplete = false; //We are ready for transmission
//Serial.print("GGA Parsed - ");
//Serial.println(ggaSentence);
//Start over
ggaSentenceStarted = false;
}
}
}
@@ -0,0 +1,17 @@
//Your WiFi credentials
const char ssid[] = "TRex";
const char password[] = "parachutes";
//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