This repository was archived by the owner on Jan 28, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 85
/
Copy pathExample14_NTRIPServer.ino
274 lines (223 loc) · 9.62 KB
/
Example14_NTRIPServer.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
/*
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
basically do whatever you want with this code.
This example shows how to gather RTCM data over I2C and push it to a casting service over WiFi.
It's confusing, but the Arduino is acting as a 'server' to a 'caster'. In this case we will
use RTK2Go.com as our caster because it is free. A rover (car, surveyor stick, etc) can
then connect to RTK2Go as a 'client' and get the RTCM data it needs.
You will need to register your mountpoint here: http://www.rtk2go.com/new-reservation/
(They'll probably block the credentials we include in this example)
To see if your mountpoint is active go here: http://rtk2go.com:2101/
This is a proof of concept. Serving RTCM to a caster over WiFi is useful when you need to
set up a high-precision base station.
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/17369
Hardware Connections:
Plug a Qwiic cable into the GPS 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"
WiFiClient client;
#include <Wire.h> //Needed for I2C to GPS
#include "SparkFun_Ublox_Arduino_Library.h" //http://librarymanager/All#SparkFun_Ublox_GPS
SFE_UBLOX_GPS myGPS;
//Basic Connection settings to RTK2Go NTRIP Caster - See secrets for mount specific credentials
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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()
{
Serial.begin(115200); // You may need to increase this for high navigation rates!
while (!Serial)
; //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));
Wire.begin();
//myGPS.enableDebugging(); // Uncomment this line to enable debug messages
if (myGPS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
Serial.print("Connecting to local WiFi");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.print("\nWiFi connected with IP: ");
Serial.println(WiFi.localIP());
myGPS.setI2COutput(COM_TYPE_UBX | COM_TYPE_NMEA | COM_TYPE_RTCM3); //UBX+RTCM3 is not a valid option so we enable all three.
myGPS.setNavigationFrequency(1); //Set output in Hz. RTCM rarely benefits from >1Hz.
//Disable all NMEA sentences
bool response = true;
response &= myGPS.disableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C);
response &= myGPS.disableNMEAMessage(UBX_NMEA_GSA, COM_PORT_I2C);
response &= myGPS.disableNMEAMessage(UBX_NMEA_GSV, COM_PORT_I2C);
response &= myGPS.disableNMEAMessage(UBX_NMEA_RMC, COM_PORT_I2C);
response &= myGPS.disableNMEAMessage(UBX_NMEA_GST, COM_PORT_I2C);
response &= myGPS.disableNMEAMessage(UBX_NMEA_GLL, COM_PORT_I2C);
response &= myGPS.disableNMEAMessage(UBX_NMEA_VTG, COM_PORT_I2C);
if (response == false)
{
Serial.println(F("Failed to disable NMEA. Freezing..."));
while (1);
}
else
Serial.println(F("NMEA disabled"));
//Enable necessary RTCM sentences
response &= myGPS.enableRTCMmessage(UBX_RTCM_1005, COM_PORT_I2C, 1); //Enable message 1005 to output through UART2, message every second
response &= myGPS.enableRTCMmessage(UBX_RTCM_1074, COM_PORT_I2C, 1);
response &= myGPS.enableRTCMmessage(UBX_RTCM_1084, COM_PORT_I2C, 1);
response &= myGPS.enableRTCMmessage(UBX_RTCM_1094, COM_PORT_I2C, 1);
response &= myGPS.enableRTCMmessage(UBX_RTCM_1124, COM_PORT_I2C, 1);
response &= myGPS.enableRTCMmessage(UBX_RTCM_1230, COM_PORT_I2C, 10); //Enable message every 10 seconds
if (response == false)
{
Serial.println(F("Failed to enable RTCM. Freezing..."));
while (1);
}
else
Serial.println(F("RTCM sentences enabled"));
//-1280208.308,-4716803.847,4086665.811 is SparkFun HQ so...
//Units are cm with a high precision extension so -1234.5678 should be called: (-123456, -78)
//For more infomation see Example12_setStaticPosition
//Note: If you leave these coordinates in place and setup your antenna *not* at SparkFun, your receiver
//will be very confused and fail to generate correction data because, well, you aren't at SparkFun...
//See this tutorial on getting PPP coordinates: https://learn.sparkfun.com/tutorials/how-to-build-a-diy-gnss-reference-station/all
response &= myGPS.setStaticPosition(-128020830, -80, -471680384, -70, 408666581, 10); //With high precision 0.1mm parts
if (response == false)
{
Serial.println(F("Failed to enter static position. Freezing..."));
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
//myGPS.enableSurveyMode(60, 5.000); //Enable Survey in, 60 seconds, 5.0m
if (myGPS.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();
Serial.println(F("Press any key to start serving."));
delay(1000);
}
void beginServing()
{
Serial.println("Xmit to RTK2Go. Press any key to stop");
delay(10); //Wait for any serial to arrive
while (Serial.available()) Serial.read(); //Flush
while (Serial.available() == 0)
{
//Connect if we are not already
if (client.connected() == false)
{
Serial.printf("Opening socket to %s\n", casterHost);
if (client.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];
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");
Serial.printf("Sending credentials:\n%s\n", serverBuffer);
client.write(serverBuffer, strlen(serverBuffer));
//Wait for response
unsigned long timeout = millis();
while (client.available() == 0)
{
if (millis() - timeout > 5000)
{
Serial.println(">>> Client Timeout !");
client.stop();
return;
}
delay(10);
}
//Check reply
bool connectionSuccess = false;
char response[512];
int responseSpot = 0;
while (client.available())
{
response[responseSpot++] = client.read();
if (strstr(response, "200") > 0) //Look for 'ICY 200 OK'
connectionSuccess = true;
if (responseSpot == 512 - 1) break;
}
response[responseSpot] = '\0';
if (connectionSuccess == false)
{
Serial.printf("Failed to connect to RTK2Go: %s", response);
}
} //End attempt to connect
else
{
Serial.println("Connection to host failed");
}
} //End connected == false
if (client.connected() == true)
{
delay(10);
while (Serial.available()) Serial.read(); //Flush any endlines or carriage returns
lastReport_ms = millis();
lastSentRTCM_ms = millis();
//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;
myGPS.checkUblox(); //See if new data is available. Process bytes as they come in.
//Close socket if we don't have new data for 10s
//RTK2Go will ban your IP address if you abuse it. See http://www.rtk2go.com/how-to-get-your-ip-banned/
//So let's not leave the socket open/hanging without data
if (millis() - lastSentRTCM_ms > maxTimeBeforeHangup_ms)
{
Serial.println("RTCM timeout. Disconnecting...");
client.stop();
return;
}
delay(10);
//Report some statistics every 250
if (millis() - lastReport_ms > 250)
{
lastReport_ms += 250;
Serial.printf("Total sent: %d\n", serverBytesSent);
}
}
}
delay(10);
}
Serial.println("User pressed a key");
Serial.println("Disconnecting...");
client.stop();
delay(10);
while (Serial.available()) Serial.read(); //Flush any endlines or carriage returns
}
//This function gets called from the SparkFun u-blox Arduino Library.
//As each RTCM byte comes in you can specify what to do with it
//Useful for passing the RTCM correction data to a radio, Ntrip broadcaster, etc.
void SFE_UBLOX_GPS::processRTCM(uint8_t incoming)
{
if (client.connected() == true)
{
client.write(incoming); //Send this byte to socket
serverBytesSent++;
lastSentRTCM_ms = millis();
}
}