@@ -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();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
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
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
name=SparkFun u-blox GNSS Arduino Library
|
||||
version=2.1.3
|
||||
version=2.1.4
|
||||
author=SparkFun Electronics <techsupport@sparkfun.com>
|
||||
maintainer=SparkFun Electronics <sparkfun.com>
|
||||
sentence=Library for I2C and Serial Communication with u-blox GNSS modules<br/><br/>
|
||||
|
||||
@@ -442,6 +442,7 @@ bool SFE_UBLOX_GNSS::begin(TwoWire &wirePort, uint8_t deviceAddress, uint16_t ma
|
||||
{
|
||||
commType = COMM_TYPE_I2C;
|
||||
_i2cPort = &wirePort; //Grab which port the user wants us to use
|
||||
_signsOfLife = false; //Clear the _signsOfLife flag. It will be set true if valid traffic is seen.
|
||||
|
||||
//We expect caller to begin their I2C port, with the speed of their choice external to the library
|
||||
//But if they forget, we start the hardware here.
|
||||
@@ -485,7 +486,7 @@ bool SFE_UBLOX_GNSS::begin(TwoWire &wirePort, uint8_t deviceAddress, uint16_t ma
|
||||
connected = isConnected(maxWait);
|
||||
}
|
||||
|
||||
if ((!connected ) && assumeSuccess) // Advanced users can assume success if required. Useful if the port is outputting messages at high navigation rate.
|
||||
if ((!connected ) && assumeSuccess && _signsOfLife) // Advanced users can assume success if required. Useful if the port is outputting messages at high navigation rate.
|
||||
{
|
||||
#ifndef SFE_UBLOX_REDUCED_PROG_MEM
|
||||
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
|
||||
@@ -504,6 +505,7 @@ bool SFE_UBLOX_GNSS::begin(Stream &serialPort, uint16_t maxWait, bool assumeSucc
|
||||
{
|
||||
commType = COMM_TYPE_SERIAL;
|
||||
_serialPort = &serialPort; //Grab which port the user wants us to use
|
||||
_signsOfLife = false; //Clear the _signsOfLife flag. It will be set true if valid traffic is seen.
|
||||
|
||||
//New in v2.0: allocate memory for the packetCfg payload here - if required. (The user may have called setPacketCfgPayloadSize already)
|
||||
if (packetCfgPayloadSize == 0)
|
||||
@@ -512,6 +514,30 @@ bool SFE_UBLOX_GNSS::begin(Stream &serialPort, uint16_t maxWait, bool assumeSucc
|
||||
//New in v2.0: allocate memory for the file buffer - if required. (The user should have called setFileBufferSize already)
|
||||
createFileBuffer();
|
||||
|
||||
//Get rid of any stale serial data already in the processor's RX buffer
|
||||
while (_serialPort->available())
|
||||
_serialPort->read();
|
||||
|
||||
//If assumeSuccess is true, the user must really want begin to succeed. So, let's empty the module's serial transmit buffer too!
|
||||
//Keep discarding new serial data until we see a gap of 2ms - hopefully indicating that the module's TX buffer is empty.
|
||||
if (assumeSuccess)
|
||||
{
|
||||
unsigned long startTime = millis();
|
||||
unsigned long lastActivity = startTime;
|
||||
bool keepGoing = true;
|
||||
while (keepGoing && (millis() < (startTime + (unsigned long)maxWait)))
|
||||
{
|
||||
while (_serialPort->available()) // Discard any new data
|
||||
{
|
||||
_serialPort->read();
|
||||
lastActivity = millis();
|
||||
}
|
||||
|
||||
if (millis() > (lastActivity + (unsigned long)2)) // Check if we have seen no new data for at least 2ms
|
||||
keepGoing = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Call isConnected up to three times - tests on the NEO-M8U show the CFG RATE poll occasionally being ignored
|
||||
bool connected = isConnected(maxWait);
|
||||
|
||||
@@ -537,7 +563,7 @@ bool SFE_UBLOX_GNSS::begin(Stream &serialPort, uint16_t maxWait, bool assumeSucc
|
||||
connected = isConnected(maxWait);
|
||||
}
|
||||
|
||||
if ((!connected ) && assumeSuccess) // Advanced users can assume success if required. Useful if the port is outputting messages at high navigation rate.
|
||||
if ((!connected ) && assumeSuccess && _signsOfLife) // Advanced users can assume success if required. Useful if the port is outputting messages at high navigation rate.
|
||||
{
|
||||
#ifndef SFE_UBLOX_REDUCED_PROG_MEM
|
||||
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
|
||||
@@ -558,6 +584,7 @@ bool SFE_UBLOX_GNSS::begin(SPIClass &spiPort, uint8_t csPin, uint32_t spiSpeed,
|
||||
_spiPort = &spiPort;
|
||||
_csPin = csPin;
|
||||
_spiSpeed = spiSpeed;
|
||||
_signsOfLife = false; //Clear the _signsOfLife flag. It will be set true if valid traffic is seen.
|
||||
|
||||
// Initialize the chip select pin
|
||||
pinMode(_csPin, OUTPUT);
|
||||
@@ -617,7 +644,7 @@ bool SFE_UBLOX_GNSS::begin(SPIClass &spiPort, uint8_t csPin, uint32_t spiSpeed,
|
||||
connected = isConnected(maxWait);
|
||||
}
|
||||
|
||||
if ((!connected ) && assumeSuccess) // Advanced users can assume success if required. Useful if the port is outputting messages at high navigation rate.
|
||||
if ((!connected ) && assumeSuccess && _signsOfLife) // Advanced users can assume success if required. Useful if the port is outputting messages at high navigation rate.
|
||||
{
|
||||
#ifndef SFE_UBLOX_REDUCED_PROG_MEM
|
||||
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
|
||||
@@ -1637,6 +1664,11 @@ void SFE_UBLOX_GNSS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t r
|
||||
|
||||
if (nmeaByteCounter == 5)
|
||||
{
|
||||
if (!_signsOfLife) // If _signsOfLife is not already true, set _signsOfLife to true if the NMEA header is valid
|
||||
{
|
||||
_signsOfLife = isNMEAHeaderValid();
|
||||
}
|
||||
|
||||
// We've just received the end of the address field. Check if it is selected for logging
|
||||
if (logThisNMEA())
|
||||
{
|
||||
@@ -1710,6 +1742,38 @@ bool SFE_UBLOX_GNSS::logThisNMEA()
|
||||
return (false);
|
||||
}
|
||||
|
||||
// PRIVATE: Return true if the NMEA header is valid
|
||||
bool SFE_UBLOX_GNSS::isNMEAHeaderValid()
|
||||
{
|
||||
if (nmeaAddressField[0] != '*') return (false);
|
||||
if (nmeaAddressField[1] != 'G') return (false);
|
||||
if ((nmeaAddressField[3] == 'D') && (nmeaAddressField[4] == 'T') && (nmeaAddressField[5] == 'M')) return (true);
|
||||
if (nmeaAddressField[3] == 'G')
|
||||
{
|
||||
if ((nmeaAddressField[4] == 'A') && (nmeaAddressField[5] == 'Q')) return (true);
|
||||
if ((nmeaAddressField[4] == 'B') && (nmeaAddressField[5] == 'Q')) return (true);
|
||||
if ((nmeaAddressField[4] == 'B') && (nmeaAddressField[5] == 'S')) return (true);
|
||||
if ((nmeaAddressField[4] == 'G') && (nmeaAddressField[5] == 'A')) return (true);
|
||||
if ((nmeaAddressField[4] == 'L') && (nmeaAddressField[5] == 'L')) return (true);
|
||||
if ((nmeaAddressField[4] == 'L') && (nmeaAddressField[5] == 'Q')) return (true);
|
||||
if ((nmeaAddressField[4] == 'N') && (nmeaAddressField[5] == 'Q')) return (true);
|
||||
if ((nmeaAddressField[4] == 'N') && (nmeaAddressField[5] == 'S')) return (true);
|
||||
if ((nmeaAddressField[4] == 'P') && (nmeaAddressField[5] == 'Q')) return (true);
|
||||
if ((nmeaAddressField[4] == 'Q') && (nmeaAddressField[5] == 'Q')) return (true);
|
||||
if ((nmeaAddressField[4] == 'R') && (nmeaAddressField[5] == 'S')) return (true);
|
||||
if ((nmeaAddressField[4] == 'S') && (nmeaAddressField[5] == 'A')) return (true);
|
||||
if ((nmeaAddressField[4] == 'S') && (nmeaAddressField[5] == 'T')) return (true);
|
||||
if ((nmeaAddressField[4] == 'S') && (nmeaAddressField[5] == 'V')) return (true);
|
||||
}
|
||||
if ((nmeaAddressField[3] == 'R') && (nmeaAddressField[4] == 'L') && (nmeaAddressField[5] == 'M')) return (true);
|
||||
if ((nmeaAddressField[3] == 'R') && (nmeaAddressField[4] == 'M') && (nmeaAddressField[5] == 'C')) return (true);
|
||||
if ((nmeaAddressField[3] == 'T') && (nmeaAddressField[4] == 'X') && (nmeaAddressField[5] == 'T')) return (true);
|
||||
if ((nmeaAddressField[3] == 'V') && (nmeaAddressField[4] == 'L') && (nmeaAddressField[5] == 'W')) return (true);
|
||||
if ((nmeaAddressField[3] == 'V') && (nmeaAddressField[4] == 'T') && (nmeaAddressField[5] == 'G')) return (true);
|
||||
if ((nmeaAddressField[3] == 'Z') && (nmeaAddressField[4] == 'D') && (nmeaAddressField[5] == 'A')) return (true);
|
||||
return (false);
|
||||
}
|
||||
|
||||
// PRIVATE: Return true if we should pass this NMEA message to processNMEA
|
||||
bool SFE_UBLOX_GNSS::processThisNMEA()
|
||||
{
|
||||
@@ -1887,6 +1951,7 @@ void SFE_UBLOX_GNSS::processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_
|
||||
if ((incomingUBX->checksumA == rollingChecksumA) && (incomingUBX->checksumB == rollingChecksumB))
|
||||
{
|
||||
incomingUBX->valid = SFE_UBLOX_PACKET_VALIDITY_VALID; // Flag the packet as valid
|
||||
_signsOfLife = true; //The checksum is valid, so set the _signsOfLife flag
|
||||
|
||||
// Let's check if the class and ID match the requestedClass and requestedID
|
||||
// Remember - this could be a data packet or an ACK packet
|
||||
@@ -3601,7 +3666,7 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForACKResponse(ubxPacket *outgoingUBX, ui
|
||||
packetAuto.classAndIDmatch = SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED;
|
||||
|
||||
unsigned long startTime = millis();
|
||||
while (millis() - startTime < maxTime)
|
||||
while (millis() < (startTime + (unsigned long)maxTime))
|
||||
{
|
||||
if (checkUbloxInternal(outgoingUBX, requestedClass, requestedID) == true) //See if new data is available. Process bytes as they come in.
|
||||
{
|
||||
@@ -3740,7 +3805,7 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForACKResponse(ubxPacket *outgoingUBX, ui
|
||||
} //checkUbloxInternal == true
|
||||
|
||||
delay(1); // Allow an RTOS to get an elbow in (#11)
|
||||
} //while (millis() - startTime < maxTime)
|
||||
} //while (millis() < (startTime + (unsigned long)maxTime))
|
||||
|
||||
// We have timed out...
|
||||
// If the outgoingUBX->classAndIDmatch is VALID then we can take a gamble and return DATA_RECEIVED
|
||||
|
||||
@@ -599,6 +599,7 @@ public:
|
||||
void setPacketCfgPayloadSize(size_t payloadSize); // Set packetCfgPayloadSize
|
||||
|
||||
//Begin communication with the GNSS. Advanced users can assume success if required. Useful if the port is already outputting messages at high navigation rate.
|
||||
//Begin will then return true if "signs of life" have been seen: reception of _any_ valid UBX packet or _any_ valid NMEA header.
|
||||
//By default use the default I2C address, and use Wire port
|
||||
bool begin(TwoWire &wirePort = Wire, uint8_t deviceAddress = 0x42, uint16_t maxWait = defaultMaxWait, bool assumeSuccess = false); //Returns true if module is detected
|
||||
//serialPort needs to be perviously initialized to correct baud rate
|
||||
@@ -1498,6 +1499,7 @@ private:
|
||||
uint8_t nmeaAddressField[6]; // NMEA Address Field - includes the start character (*)
|
||||
bool logThisNMEA(); // Return true if we should log this NMEA message
|
||||
bool processThisNMEA(); // Return true if we should pass this NMEA message to processNMEA
|
||||
bool isNMEAHeaderValid(); // Return true if the six byte NMEA header appears valid. Used to set _signsOfLife
|
||||
|
||||
uint16_t rtcmLen = 0;
|
||||
|
||||
@@ -1527,6 +1529,10 @@ private:
|
||||
bool _pushSingleByte = false;
|
||||
uint8_t _pushThisSingleByte;
|
||||
|
||||
// .begin will return true if the assumeSuccess parameter is true and if _signsOfLife is true
|
||||
// _signsOfLife is set to true when: a valid UBX message is seen; a valig NMEA header is seen.
|
||||
bool _signsOfLife;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user