Skip to content

Commit 859a5d0

Browse files
committed
Add support for AssistNow Offline. Add Example. Add findMGAANOForDate.
1 parent ae65547 commit 859a5d0

File tree

6 files changed

+531
-9
lines changed

6 files changed

+531
-9
lines changed
Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
/*
2+
Use ESP32 WiFi to get AssistNow Offline data from u-blox Thingstream
3+
By: SparkFun Electronics / Paul Clark
4+
Date: November 26th, 2021
5+
License: MIT. See license file for more information but you can
6+
basically do whatever you want with this code.
7+
8+
This example shows how to obtain AssistNow Offline data from u-blox Thingstream over WiFi
9+
and push it over I2C to a u-blox module.
10+
11+
The module still needs to be given time assistance to achieve a fast fix. This example
12+
uses network time to do that. If you don't have a WiFi connection, you may have to use
13+
a separate RTC to provide the time.
14+
15+
Note: AssistNow Offline is not supported by the ZED-F9P! "The ZED-F9P supports AssistNow Online only."
16+
17+
You will need to have a token to be able to access Thingstream. See the AssistNow README for more details.
18+
19+
Update secrets.h with your:
20+
- WiFi credentials
21+
- AssistNow token string
22+
23+
Uncomment the "#define USE_MGA_ACKs" below to test the more robust method of using the
24+
UBX_MGA_ACK_DATA0 acknowledgements to confirm that each MGA message has been accepted.
25+
26+
Feel like supporting open source hardware?
27+
Buy a board from SparkFun!
28+
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
29+
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
30+
31+
Hardware Connections:
32+
Plug a Qwiic cable into the GNSS and a ESP32 Thing Plus
33+
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
34+
Open the serial monitor at 115200 baud to see the output
35+
*/
36+
37+
//#define USE_MGA_ACKs // Uncomment this line to use the UBX_MGA_ACK_DATA0 acknowledgements
38+
39+
#include <WiFi.h>
40+
#include <HTTPClient.h>
41+
#include "secrets.h"
42+
43+
const char assistNowServer[] = "https://offline-live1.services.u-blox.com";
44+
//const char assistNowServer[] = "https://offline-live2.services.u-blox.com"; // Alternate server
45+
46+
const char getQuery[] = "GetOfflineData.ashx?";
47+
const char tokenPrefix[] = "token=";
48+
const char tokenSuffix[] = ";";
49+
const char getGNSS[] = "gnss=gps,glo;"; // GNSS can be: gps,qzss,glo,bds,gal
50+
const char getFormat[] = "format=mga;"; // Data format. Leave set to mga for M8 onwards. Can be aid.
51+
const char getPeriod[] = "period=1;"; // Optional. The number of weeks into the future that the data will be valid. Can be 1-5. Default = 4.
52+
const char getMgaResolution[] = "resolution=1;"; // Optional. Data resolution: 1 = every day; 2 = every other day; 3 = every 3rd day.
53+
//Note: always use resolution=1. findMGAANOForDate does not yet support finding the 'closest' date. It needs an exact match.
54+
55+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
56+
57+
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
58+
SFE_UBLOX_GNSS myGNSS;
59+
60+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
61+
62+
#include "time.h"
63+
64+
const char* ntpServer = "pool.ntp.org"; // The Network Time Protocol Server
65+
66+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
67+
68+
void setup()
69+
{
70+
delay(1000);
71+
72+
Serial.begin(115200);
73+
Serial.println(F("AssistNow Example"));
74+
75+
while (Serial.available()) Serial.read(); // Empty the serial buffer
76+
Serial.println(F("Press any key to begin..."));
77+
while (!Serial.available()); // Wait for a keypress
78+
79+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
80+
// Start I2C. Connect to the GNSS.
81+
82+
Wire.begin(); //Start I2C
83+
84+
if (myGNSS.begin() == false) //Connect to the Ublox module using Wire port
85+
{
86+
Serial.println(F("u-blox GPS not detected at default I2C address. Please check wiring. Freezing."));
87+
while (1);
88+
}
89+
Serial.println(F("u-blox module connected"));
90+
91+
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
92+
93+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
94+
// Connect to WiFi.
95+
96+
Serial.print(F("Connecting to local WiFi"));
97+
98+
WiFi.begin(ssid, password);
99+
while (WiFi.status() != WL_CONNECTED) {
100+
delay(500);
101+
Serial.print(F("."));
102+
}
103+
Serial.println();
104+
105+
Serial.println(F("WiFi connected!"));
106+
107+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
108+
// Set the RTC using network time. (Code taken from the SimpleTime example.)
109+
110+
// Request the time from the NTP server and use it to set the ESP32's RTC.
111+
configTime(0, 0, ntpServer); // Set the GMT and daylight offsets to zero. We need UTC, not local time.
112+
113+
struct tm timeinfo;
114+
if(!getLocalTime(&timeinfo))
115+
{
116+
Serial.println("Failed to obtain time");
117+
return;
118+
}
119+
Serial.println(&timeinfo, "Time is: %A, %B %d %Y %H:%M:%S");
120+
121+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
122+
// Use HTTP GET to receive the AssistNow_Online data
123+
124+
const int URL_BUFFER_SIZE = 256;
125+
char theURL[URL_BUFFER_SIZE]; // This will contain the HTTP URL
126+
int payloadSize = 0; // This will be updated with the length of the data we get from the server
127+
String payload; // This will store the data we get from the server
128+
129+
// Assemble the URL
130+
// Note the slash after the first %s (assistNowServer)
131+
snprintf(theURL, URL_BUFFER_SIZE, "%s/%s%s%s%s%s%s%s%s",
132+
assistNowServer,
133+
getQuery,
134+
tokenPrefix,
135+
myAssistNowToken,
136+
tokenSuffix,
137+
getGNSS,
138+
getFormat,
139+
getPeriod,
140+
getMgaResolution
141+
);
142+
143+
Serial.print(F("HTTP URL is: "));
144+
Serial.println(theURL);
145+
146+
HTTPClient http;
147+
148+
http.begin(theURL);
149+
150+
int httpCode = http.GET(); // HTTP GET
151+
152+
// httpCode will be negative on error
153+
if(httpCode > 0)
154+
{
155+
// HTTP header has been sent and Server response header has been handled
156+
Serial.printf("[HTTP] GET... code: %d\r\n", httpCode);
157+
158+
// If the GET was successful, read the data
159+
if(httpCode == HTTP_CODE_OK) // Check for code 200
160+
{
161+
payloadSize = http.getSize();
162+
Serial.printf("Server returned %d bytes\r\n", payloadSize);
163+
164+
payload = http.getString(); // Get the payload
165+
166+
// Pretty-print the payload as HEX
167+
/*
168+
int i;
169+
for(i = 0; i < payloadSize; i++)
170+
{
171+
if (payload[i] < 0x10) // Print leading zero
172+
Serial.print("0");
173+
Serial.print(payload[i], HEX);
174+
Serial.print(" ");
175+
if ((i % 16) == 15)
176+
Serial.println();
177+
}
178+
if ((i % 16) != 15)
179+
Serial.println();
180+
*/
181+
}
182+
}
183+
else
184+
{
185+
Serial.printf("[HTTP] GET... failed, error: %s\r\n", http.errorToString(httpCode).c_str());
186+
}
187+
188+
http.end();
189+
190+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
191+
// Find where the AssistNow data for today starts and ends
192+
193+
size_t todayStart = 0; // Default to sending all the data
194+
size_t tomorrowStart = (size_t)payloadSize;
195+
196+
// Uncomment the next line to enable the 'major' debug messages on Serial so you can see what AssistNow data is being sent
197+
//myGNSS.enableDebugging(Serial, true);
198+
199+
if (payloadSize > 0)
200+
{
201+
if(getLocalTime(&timeinfo))
202+
{
203+
// Find the start of today's data
204+
todayStart = myGNSS.findMGAANOForDate(payload, (size_t)payloadSize, timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday);
205+
if (todayStart < (size_t)payloadSize)
206+
{
207+
Serial.print(F("Found the data for today starting at location "));
208+
Serial.println(todayStart);
209+
}
210+
else
211+
{
212+
Serial.println("Could not find the data for today. This will not work well. The GNSS needs help to start up quickly.");
213+
}
214+
215+
// Find the start of tomorrow's data
216+
tomorrowStart = myGNSS.findMGAANOForDate(payload, (size_t)payloadSize, timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday, 1);
217+
if (tomorrowStart < (size_t)payloadSize)
218+
{
219+
Serial.print(F("Found the data for tomorrow starting at location "));
220+
Serial.println(tomorrowStart);
221+
}
222+
else
223+
{
224+
Serial.println("Could not find the data for tomorrow. (Today's data may be the last?)");
225+
}
226+
}
227+
else
228+
{
229+
Serial.println("Failed to obtain time. This will not work well. The GNSS needs accurate time to start up quickly.");
230+
}
231+
}
232+
233+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
234+
// Push the RTC time to the module
235+
236+
if(getLocalTime(&timeinfo)) // Get the local time again, just to make sure we are using the most accurate time
237+
{
238+
// setUTCTimeAssistance uses a default time accuracy of 2 seconds which should be OK here.
239+
// Have a look at the library source code for more details.
240+
myGNSS.setUTCTimeAssistance(timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
241+
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
242+
}
243+
else
244+
{
245+
Serial.println("Failed to obtain time. This will not work well. The GNSS needs accurate time to start up quickly.");
246+
}
247+
248+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
249+
// Push the AssistNow data for today to the module - without the time
250+
251+
if (payloadSize > 0)
252+
{
253+
254+
#ifndef USE_MGA_ACKs
255+
256+
// ***** Don't use the UBX_MGA_ACK_DATA0 messages *****
257+
258+
// Push the AssistNow data for today. Don't use UBX_MGA_ACK_DATA0's. Use the default delay of 7ms between messages.
259+
myGNSS.pushAssistNowData(todayStart, true, payload, tomorrowStart - todayStart);
260+
261+
#else
262+
263+
// ***** Use the UBX_MGA_ACK_DATA0 messages *****
264+
265+
// Tell the module to return UBX_MGA_ACK_DATA0 messages when we push the AssistNow data
266+
myGNSS.setAckAiding(1);
267+
268+
// Speed things up by setting setI2CpollingWait to 1ms
269+
myGNSS.setI2CpollingWait(1);
270+
271+
// Push the AssistNow data for today.
272+
myGNSS.pushAssistNowData(todayStart, true, payload, tomorrowStart - todayStart, SFE_UBLOX_MGA_ASSIST_ACK_YES, 100);
273+
274+
// Set setI2CpollingWait to 125ms to avoid pounding the I2C bus
275+
myGNSS.setI2CpollingWait(125);
276+
277+
#endif
278+
279+
}
280+
281+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
282+
// Disconnect the WiFi as it's no longer needed
283+
284+
WiFi.disconnect(true);
285+
WiFi.mode(WIFI_OFF);
286+
Serial.println(F("WiFi disconnected"));
287+
}
288+
289+
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
290+
291+
void loop()
292+
{
293+
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
294+
295+
long latitude = myGNSS.getLatitude();
296+
Serial.print(F("Lat: "));
297+
Serial.print(latitude);
298+
299+
long longitude = myGNSS.getLongitude();
300+
Serial.print(F(" Long: "));
301+
Serial.print(longitude);
302+
Serial.print(F(" (degrees * 10^-7)"));
303+
304+
long altitude = myGNSS.getAltitude();
305+
Serial.print(F(" Alt: "));
306+
Serial.print(altitude);
307+
Serial.print(F(" (mm)"));
308+
309+
byte SIV = myGNSS.getSIV();
310+
Serial.print(F(" SIV: "));
311+
Serial.print(SIV);
312+
313+
byte fixType = myGNSS.getFixType();
314+
Serial.print(F(" Fix: "));
315+
if(fixType == 0) Serial.print(F("No fix"));
316+
else if(fixType == 1) Serial.print(F("Dead reckoning"));
317+
else if(fixType == 2) Serial.print(F("2D"));
318+
else if(fixType == 3) Serial.print(F("3D"));
319+
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
320+
else if(fixType == 5) Serial.print(F("Time only"));
321+
322+
Serial.println();
323+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
//Your WiFi credentials
2+
const char ssid[] = "TRex";
3+
const char password[] = "hasBigTeeth";
4+
5+
//Your AssistNow token
6+
const char myAssistNowToken[] = "58XXXXXXXXXXXXXXXXXXYQ";

examples/AssistNow/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ With the AssistNow Offline service, users can download long-term orbit data over
1616

1717
Please see the [AssistNow_Offline](./AssistNow_Offline) examples for more details. These examples were written for the ESP32, but will run on other platforms too.
1818

19+
**Note: AssistNow Offline is not supported by the ZED-F9P. "The ZED-F9P supports AssistNow Online only."**
20+
1921
## AssistNow<sup>TM</sup> Autonomous
2022

2123
AssistNow Autonomous provides aiding information without the need for a host or external network connection. Based on previous broadcast satellite ephemeris data downloaded to and stored by the GNSS receiver, AssistNow Autonomous automatically generates accurate predictions of satellite orbital data (“AssistNow Autonomous data”) that is usable for future GNSS position fixes.

keywords.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ pushRawData KEYWORD2
9292

9393
pushAssistNowData KEYWORD2
9494
setUTCTimeAssistance KEYWORD2
95+
findMGAANOForDate KEYWORD2
9596

9697
setFileBufferSize KEYWORD2
9798
getFileBufferSize KEYWORD2

0 commit comments

Comments
 (0)