Skip to content

Commit 77365a0

Browse files
committed
Add NTRIP Server example using UART for harvesting
1 parent 26ffb82 commit 77365a0

File tree

4 files changed

+347
-0
lines changed

4 files changed

+347
-0
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
Push RTCM data to RTK2Go
3+
4+
RTCM will come in over UART1 from ZED into ESP32
5+
ESP32 will read UART1 and then push over WiFi to RTK2Go
6+
7+
For testing, the ZED is manually configured for:
8+
Permanent base location (immediate RTCM output)
9+
UART1 is enabled for RTCM output
10+
Sentences for RTCM are enabled for UART1
11+
Reduce fixes to 1Hz
12+
13+
The I2C library won't see the UART1 RTCM bytes
14+
15+
*/
16+
const int FIRMWARE_VERSION_MAJOR = 1;
17+
const int FIRMWARE_VERSION_MINOR = 1;
18+
19+
#define RTK_IDENTIFIER (FIRMWARE_VERSION_MAJOR * 0x10 + FIRMWARE_VERSION_MINOR)
20+
21+
#include <WiFi.h>
22+
23+
#include "secrets.h"
24+
25+
//Hardware serial buffers
26+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
27+
HardwareSerial GPS(2);
28+
#define RXD2 16
29+
#define TXD2 17
30+
31+
#define SERIAL_SIZE_RX 16384 //Using a large buffer. This might be much bigger than needed but the ESP32 has enough RAM
32+
uint8_t rBuffer[SERIAL_SIZE_RX]; //Buffer for reading F9P
33+
//uint8_t wBuffer[SERIAL_SIZE_RX]; //Buffer for writing to F9P
34+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
35+
36+
//GNSS configuration
37+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
38+
#define MAX_PAYLOAD_SIZE 384 // Override MAX_PAYLOAD_SIZE for getModuleInfo which can return up to 348 bytes
39+
40+
#include "SparkFun_Ublox_Arduino_Library.h" //Click here to get the library: http://librarymanager/All#SparkFun_Ublox_GPS
41+
SFE_UBLOX_GPS myGPS;
42+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
43+
44+
//Connection settings to RTK2Go NTRIP Caster
45+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
46+
const uint16_t casterPort = 2101;
47+
const char * casterHost = "rtk2go.com";
48+
const char * ntrip_server_name = "SparkFun_RTK_Surveyor";
49+
50+
#define TOCAST_BUFFER_SIZE 512 * 4 //RTCM updates are ~300 bytes but can vary in size
51+
char toCastBuffer[TOCAST_BUFFER_SIZE];
52+
int castSpot = 0; //Tracks next available spot in cast buffer
53+
bool toCastFrameComplete = false;
54+
bool toCastFrameStale = false;
55+
56+
long lastReceivedRTCM_ms = 0; //5 RTCM messages take approximately ~300ms to arrive at 115200bps
57+
long lastReceivedCastFrame_ms = 0; //Time of last complete frame
58+
int maxTimeBeforeHangup_ms = 10000; //If we fail to get a complete RTCM frame after 10s, then disconnect from caster
59+
60+
uint32_t serverBytesSent = 0; //Just a running total
61+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
62+
63+
void setup()
64+
{
65+
Serial.begin(115200);
66+
Serial.println("NTRIP testing");
67+
68+
GPS.begin(115200); //The ZED-F9P will be configured to output RTCM over its UART1 at 115200bps into the ESP32.
69+
GPS.setRxBufferSize(SERIAL_SIZE_RX);
70+
GPS.setTimeout(1);
71+
72+
Wire.begin(); //Start I2C
73+
74+
if (myGPS.begin() == false) //Connect to the Ublox module using Wire port
75+
{
76+
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
77+
while (1);
78+
}
79+
Serial.println(F("u-blox module connected"));
80+
81+
Serial.print("Connecting to local WiFi");
82+
WiFi.begin(ssid, password);
83+
while (WiFi.status() != WL_CONNECTED) {
84+
delay(500);
85+
Serial.print(".");
86+
}
87+
88+
Serial.print("\nWiFi connected with IP: ");
89+
Serial.println(WiFi.localIP());
90+
91+
//Start the tasks for handling incoming and outgoing BT bytes to/from ZED-F9P
92+
xTaskCreate(F9PSerialReadTask, "F9Read", 10000, NULL, 0, NULL);
93+
//xTaskCreate(F9PSerialWriteTask, "F9Write", 10000, NULL, 0, NULL);
94+
95+
}
96+
97+
void loop()
98+
{
99+
if (Serial.available()) menuMain(); //Present user menu
100+
101+
myGPS.checkUblox(); //See if new data is available. Process bytes as they come in.
102+
103+
delay(10);
104+
}
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
2+
3+
//Base status goes from Rover-Mode (LED off), surveying in (blinking), to survey is complete/trasmitting RTCM (solid)
4+
typedef enum
5+
{
6+
BASE_OFF = 0,
7+
BASE_SURVEYING_IN_NOTSTARTED, //User has indicated base, but current pos accuracy is too low
8+
BASE_SURVEYING_IN_SLOW,
9+
BASE_SURVEYING_IN_FAST,
10+
BASE_TRANSMITTING,
11+
} BaseState;
12+
13+
14+
void menuMain()
15+
{
16+
while (1)
17+
{
18+
Serial.println();
19+
Serial.println("Menu:");
20+
Serial.println("1) Connect to RTK2GO");
21+
22+
byte incoming = getByteChoice(30); //Timeout after x seconds
23+
24+
if (incoming == '1')
25+
{
26+
Serial.println("Xmit to RTK2Go. Press key to stop");
27+
delay(10); //Wait for any serial to arrive
28+
while (Serial.available()) Serial.read(); //Flush
29+
30+
WiFiClient client;
31+
32+
while (Serial.available() == 0)
33+
{
34+
//Spin until we have a frame ready
35+
//Serial.print("Getting frame");
36+
while (toCastFrameStale == true)
37+
{
38+
//Serial.print(".");
39+
delay(100);
40+
}
41+
42+
//Connect if we are not already
43+
if (client.connected() == false)
44+
{
45+
Serial.printf("Opening socket to %s\n", casterHost);
46+
47+
if (client.connect(casterHost, casterPort) == true) //Attempt connection
48+
{
49+
Serial.printf("Connected to %s:%d\n", casterHost, casterPort);
50+
51+
const int SERVER_BUFFER_SIZE = 512;
52+
char serverBuffer[SERVER_BUFFER_SIZE];
53+
54+
snprintf(serverBuffer, SERVER_BUFFER_SIZE, "SOURCE %s /%s\r\nSource-Agent: NTRIP %s/v%d.%d\r\n\r\n",
55+
mntpnt_pw, mntpnt, ntrip_server_name, FIRMWARE_VERSION_MAJOR, FIRMWARE_VERSION_MINOR);
56+
57+
Serial.printf("Sending credentials:\n%s\n", serverBuffer);
58+
client.write(serverBuffer, strlen(serverBuffer));
59+
60+
//Wait for response
61+
unsigned long timeout = millis();
62+
while (client.available() == 0)
63+
{
64+
if (millis() - timeout > 5000)
65+
{
66+
Serial.println(">>> Client Timeout !");
67+
client.stop();
68+
return;
69+
}
70+
delay(10);
71+
}
72+
73+
//Check reply
74+
bool connectionSuccess = false;
75+
char response[512];
76+
int responseSpot = 0;
77+
while (client.available())
78+
{
79+
response[responseSpot++] = client.read();
80+
if (strstr(response, "200") > 0) //Look for 'ICY 200 OK'
81+
connectionSuccess = true;
82+
if (responseSpot == 512 - 1) break;
83+
}
84+
response[responseSpot] = '\0';
85+
//Serial.printf("RTK2Go response: %s", response);
86+
87+
if (connectionSuccess == false)
88+
{
89+
Serial.printf("Failed to connect to RTK2Go: %s", response);
90+
}
91+
} //End attempt to connect
92+
else
93+
{
94+
Serial.println("Connection to host failed");
95+
}
96+
} //End connected == false
97+
98+
if (client.connected() == true)
99+
{
100+
//We are already connected so now push RTCM frame
101+
client.write(toCastBuffer, castSpot);
102+
serverBytesSent += castSpot;
103+
toCastFrameStale = true;
104+
Serial.printf("Sent: %d / Total sent: %d\n", castSpot, serverBytesSent);
105+
}
106+
107+
//Close socket if we don't have new data for 10s
108+
if (millis() - lastReceivedCastFrame_ms > maxTimeBeforeHangup_ms)
109+
{
110+
Serial.println("RTCM timeout. Disconnecting...");
111+
client.stop();
112+
}
113+
114+
delay(10);
115+
}
116+
117+
Serial.println("User pressed a key");
118+
Serial.println("Disconnecting...");
119+
client.stop();
120+
}
121+
else if (incoming == '2')
122+
{
123+
Serial.println("Hi");
124+
}
125+
else if (incoming == 0xFF)
126+
break;
127+
else
128+
{
129+
Serial.printf("Unknown: 0x%02X\n", incoming);
130+
}
131+
}
132+
133+
while (Serial.available()) Serial.read(); //Empty buffer of any newline chars
134+
}
135+
136+
int baseState = BASE_TRANSMITTING;
137+
138+
//If the ZED has any new NMEA data, pass it out over Bluetooth
139+
//Task for reading data from the GNSS receiver.
140+
void F9PSerialReadTask(void *e)
141+
{
142+
while (true)
143+
{
144+
//If we are in base transmitting mode and user wants to serve to client, check if 100ms has passed without new serial.
145+
//This indicates end of RTCM frame. This presumes NMEA and RAWX sentences are turned off, and 1Hz
146+
if (baseState == BASE_TRANSMITTING) //&& settings.serveToCaster == true)
147+
{
148+
if (toCastFrameComplete == false)
149+
{
150+
if (millis() - lastReceivedRTCM_ms > 800)
151+
{
152+
toCastFrameComplete = true;
153+
toCastFrameStale = false; //ntripServer() will now post buffer next socket connection
154+
lastReceivedCastFrame_ms = millis();
155+
}
156+
}
157+
}
158+
159+
if (GPS.available())
160+
{
161+
auto s = GPS.readBytes(rBuffer, SERIAL_SIZE_RX);
162+
163+
//If we are in base transmitting mode and user wants to serve to client, then fill toCastBuffer
164+
if (baseState == BASE_TRANSMITTING) //&& settings.serveToCaster == true)
165+
{
166+
if (toCastFrameComplete == true) //Start of a new frame so flush old data
167+
{
168+
castSpot = 0;
169+
toCastFrameComplete = false;
170+
}
171+
172+
lastReceivedRTCM_ms = millis();
173+
174+
//Append latest incoming UART bytes (should be RTCM) to outgoing cast buffer
175+
if (castSpot + s >= TOCAST_BUFFER_SIZE)
176+
{
177+
Serial.println("Overrun");
178+
for (int x = 0 ; x < TOCAST_BUFFER_SIZE ; x++)
179+
Serial.write(toCastBuffer[x]);
180+
}
181+
else
182+
{
183+
for (int x = 0 ; x < s ; x++)
184+
{
185+
toCastBuffer[castSpot] = rBuffer[x];
186+
castSpot++;
187+
}
188+
}
189+
}
190+
// else if (SerialBT.connected())
191+
// {
192+
// SerialBT.write(rBuffer, s);
193+
// }
194+
}
195+
taskYIELD();
196+
}
197+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//const char* ssid = "Rover1";
2+
//const char* password = "notHere1";
3+
4+
const char* ssid = "TRex";
5+
const char* password = "parachutes";
6+
7+
//const char* ssid = "Sparky";
8+
//const char* password = "sparkfun";
9+
10+
const char* mntpnt_pw = "WR5wRo4H";
11+
const char* mntpnt = "bldr_dwntwn2";
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//Get single byte from user
2+
//Waits for and returns the character that the user provides
3+
//Returns STATUS_GETNUMBER_TIMEOUT if input times out
4+
//Returns 'x' if user presses 'x'
5+
uint8_t getByteChoice(int numberOfSeconds)
6+
{
7+
Serial.flush();
8+
delay(50);//Wait for any incoming chars to hit buffer
9+
while (Serial.available() > 0) Serial.read(); //Clear buffer
10+
11+
long startTime = millis();
12+
byte incoming;
13+
while (1)
14+
{
15+
delay(10); //Yield to processor
16+
17+
if (Serial.available() > 0)
18+
{
19+
incoming = Serial.read();
20+
// Serial.print(F("byte: 0x"));
21+
// Serial.println(incoming, HEX);
22+
if (incoming >= 'a' && incoming <= 'z') break;
23+
if (incoming >= 'A' && incoming <= 'Z') break;
24+
if (incoming >= '0' && incoming <= '9') break;
25+
}
26+
27+
if ( (millis() - startTime) / 1000 >= numberOfSeconds)
28+
{
29+
Serial.println(F("No user input received."));
30+
return (-1); //Timeout. No user input.
31+
}
32+
}
33+
34+
return (incoming);
35+
}

0 commit comments

Comments
 (0)