Merge pull request #1 from sparkfun/main

merge in SparkFun's main
This commit is contained in:
Thomas Nabelek
2022-02-25 12:56:59 -07:00
committed by GitHub
59 changed files with 15929 additions and 5377 deletions
+5 -11
View File
@@ -88,26 +88,20 @@ jobs:
- name: Checkout
uses: actions/checkout@v2
- name: Branch name
run: echo running on branch ${GITHUB_REF##*/}
- name: Compile Sketch
uses: arduino/compile-sketches@v1
with:
platforms: ${{ matrix.board.platforms }}
fqbn: ${{ matrix.board.fqbn }}
libraries: |
- source-url: https://github.com/${{github.repository}}.git
- source-path: ./
sketch-paths: |
- examples/Example10_AltitudeMSL
- examples/Example11_ResetModule/Example1_FactoryDefaultviaI2C
- examples/Example13_PVT/Example1_AutoPVT
- examples/Example13_PVT/Example2_AutoPVT_ExplicitUpdate
- examples/Example14_DebugOutput
- examples/Example15_GetDateTime
- examples/Example16_Nanosecond_MaxOutput
- examples/Example16_PartialSecond_MaxOutput
- examples/Example18_PowerSaveMode
- examples/Example19_DynamicModel
- examples/Example20_SendCustomCommand
enable-warnings-report: true
enable-deltas-report: true
# verbose: true
# outputs:
+168
View File
@@ -0,0 +1,168 @@
## How to add new messages to the SparkFun u-blox GNSS Arduino Library
Based on [this issue](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/issues/97), here is a summary of how to add new messages to the SparkFun u-blox GNSS Arduino Library with full "auto" support (for callbacks, logging, etc.).
Looking at the issue, we see that the library is not supporting the UBX-NAV-PVAT (Navigation Position Velocity Attitude Time solution).
PVAT is a new message added in version 1.21 of the HPS (High Precision Fusion) firmware and version 33.21 of the F9 Interface Description.
This makes us wonder if more new messages have been added which should also be included?
### Step 1: Check the Interface Description for new keys
* Download the latest [interface description](https://www.u-blox.com/sites/default/files/F9-HPS-1.21_InterfaceDescription_UBX-21019746.pdf) from the [u-blox website](https://www.u-blox.com/en/product/zed-f9r-module#tab-documentation-resources)
* Open the interface description in Adobe Acrobat Reader DC (the free version)
* Do a ```File \ Save as Text...```
* Save the file in ```Text (Accessible) (*.txt)``` format
* Go make a cup of tea - this takes a while
* Open the txt file in Notepad++ or another editor which supports Regular Expressions
* The keys will have been saved as individual lines in the format: 0xnnnnnnnn space CR LF
* So all we need to do is use a regex to delete everything else
* Open Search \ Replace
* Click the Search Mode - Regular Expression button
* In the "Find what :" box enter: ```^(?!.*0x[\dabcdefABCDEF]{8}\s\r\n).*```
* Clear the "Replace with :" box
* Click "Replace All"
* You are left with just the keys - and a bunch of empty lines, some of which contain form feeds (\f)
* Delete the empty lines (\r\n) by replacing \r\n with nothing - don't panic, this takes a few seconds
* Delete the form feeds by replacing \f with nothing
* Finally replace the remaining spaces (\s) with \r\n
* Delete any spurious lines left at the start of the file. E.g. ROM and BASE and 0x118B2060. These came from the General information section
* The following line (0x10340014) is the first key from the "Configuration Reference" section
* Search for that key number and you will find it again half way through the file. This second copy came from "Configuration Defaults"
* Delete the duplicate keys from that line onwards
* Save the file
* Open it in a spreadsheet, e.g. LibreOffice Calc
* Select the "A" column and click "Sort Ascending A-Z"
* Save the file (as Text CSV)
* Use KDiff3 or another diff package to see the new additions
You can find the keys in the [keys folder](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/tree/main/keys), saved as sorted text files.
There are separate files for the P, R and T interfaces, plus a combined list (also sorted in ascending order).
Comparing HPS 1.21 to HPS 1.20, we can see that the following keys have been added:
* 0x10340014 CFG-BDS-USE_GEO_PRN
* 0x10710005 CFG-I2CINPROT-SPARTN
* 0x10730005 CFG-UART1INPROT-SPARTN
* 0x10750005 CFG-UART2INPROT-SPARTN
* 0x10770005 CFG-USBINPROT-SPARTN
* 0x10790005 CFG-SPIINPROT-SPARTN
* 0x20050035 CFG-TP-DRSTR_TP1
* 0x20910605 CFG-MSGOUT-UBX_RXM_SPARTN_I2C
* 0x20910606 CFG-MSGOUT-UBX_RXM_SPARTN_UART1
* 0x20910607 CFG-MSGOUT-UBX_RXM_SPARTN_UART2
* 0x20910608 CFG-MSGOUT-UBX_RXM_SPARTN_USB
* 0x20910609 CFG-MSGOUT-UBX_RXM_SPARTN_SPI
* 0x2091062a CFG-MSGOUT-UBX_NAV_PVAT_I2C
* 0x2091062b CFG-MSGOUT-UBX_NAV_PVAT_UART1
* 0x2091062c CFG-MSGOUT-UBX_NAV_PVAT_UART2
* 0x2091062d CFG-MSGOUT-UBX_NAV_PVAT_USB
* 0x2091062e CFG-MSGOUT-UBX_NAV_PVAT_SPI
* 0x20910634 CFG-MSGOUT-UBX_SEC_SIG_I2C
* 0x20910635 CFG-MSGOUT-UBX_SEC_SIG_UART1
* 0x20910636 CFG-MSGOUT-UBX_SEC_SIG_UART2
* 0x20910637 CFG-MSGOUT-UBX_SEC_SIG_USB
* 0x20910638 CFG-MSGOUT-UBX_SEC_SIG_SPI
Interestingly, we can also see that one key has been deleted:
* 0x10530006 CFG-UART2-REMAP
From this we can confirm - as documented by u-blox in the [Release Notes](https://www.u-blox.com/sites/default/files/ZED-F9R-02B_FW1.00HPS1.21_RN_UBX-21035491_1.3.pdf) -
that HPS 1.21:
* adds support for SPARTN (Safe Position Augmentation for Real-Time Navigation) correction messages
* enables the use of BeiDou geostationary satellites (previously, this configuration item had a different name)
* enables UBX-SEC-SIG message (signal security measures) as output across the different interfaces
* enables UBX_NAV_PVAT message (navigation and altitude position) as output across the different interfaces
There are also two new dynamic models, robotic lawn mower (11) and e-scooter model (12), which we need to add to the library.
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/805aab18b6656513bfee473487a437754cd3965d) for the changes.
### Step 2: Update the combined keys file
Update [u-blox_config_keys_sorted.txt](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/blob/main/keys/u-blox_config_keys_sorted.txt)
to include the new keys.
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/8895764f237ae494dcd0fa1ae942d487d2e1557f) for the changes.
### Step 3: Update u-blox_config_keys.h
Update [u-blox_config_keys.h](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/blob/main/src/u-blox_config_keys.h) to include the new keys.
Include the descriptions as defined in the Interface Description.
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/3609da15f90a7a66b41524e77c6dc3dd76cd362c) for the changes.
### Step 4: Add the new message struct to u-blox_struct.h
The next step is to add the new struct for UBX-NAV-PVAT to u-blox_struct.h.
The messages are in ascending class and ID order. So we add UBX-NAV-PVAT (0x01 0x17) after UBX-NAV-HPPOSLLH (0x01 0x14).
The names and widths of the fields are taken directly from the interface definition.
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/a4ba440c6240e0974c27f40b976a5ddf0fbdb9b6) for the changes.
### Step 5: Update SparkFun_u-blox_GNSS_Arduino_Library.h
Add the new message ID: ```const uint8_t UBX_NAV_PVAT = 0x17;```
Add the new functions to provide "auto" support for UBX-NAV-PVAT: ```getNAVPVAT```, ```setAutoNAVPVAT```, ..., ```logNAVPVAT```
Add new helper functions to access the most important fields: ```getVehicleRoll```, ..., ```getMotionHeading```
Add the pointer to the struct storage: ```UBX_NAV_PVAT_t *packetUBXNAVPVAT = NULL;```
Add the private init function: ```bool initPacketUBXNAVPVAT();```
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/423a1e2ccd418dd679257edc6edeec0bd3029052) for the changes.
### Step 6: Update SparkFun_u-blox_GNSS_Arduino_Library.cpp
Now we need to update SparkFun_u-blox_GNSS_Arduino_Library.cpp:
#### Step 6.1: Update end()
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/35d225e3f1abb316eda3becb7f8e2eb04ff1d17c) for the changes.
#### Step 6.2: Update checkAutomatic()
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/b746d8e2742961ede95e2d06d5db3a3a557e571d) for the changes.
#### Step 6.3: Update getMaxPayloadSize()
#### Step 6.4: Update processUBXpacket()
Take time to double-check that you have used the correct data width, signed/unsigned and position for each field.
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/8eecdd5044f810b0e2b567150ff63a17c219fe8e) for the changes.
#### Step 6.5: Update checkCallbacks()
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/b53bffaa3ae12482cfb268f23796963d0b8519c9) for the changes.
#### Step 6.6: Add the "auto" functions
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/e394ae003ad38117d150598774d0552059416473) for the changes.
#### Step 6.7: Add the helper functions (if any)
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/318e76383e96d6676bbb57294c25e665c0d4a31f) for the changes.
### Step 7: Add an example
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/06014dc95f1b9ffae4876fbacfb9390541d7c31d) for the changes.
### Step 8: Update keywords.txt
Add the new "auto" and helper functions to keywords.txt.
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/4f0a0ca3c5e6420be9064b91702947c23104bd1b) for the changes.
### Step 9: Update Theory.md
Add the new message to the list of "auto" messages.
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/57f133259245d8071c73797e4be2ff630c2720ab) for the changes.
That's all folks!
+33 -4
View File
@@ -21,12 +21,35 @@ u-blox makes some incredible GNSS receivers covering everything from low-cost, h
This library can be installed via the Arduino Library manager. Search for **SparkFun u-blox GNSS**.
## v2.0
## Automatic support for correction services like PointPerfect (u-blox), RTK2go, Emlid Caster and Skylark (Swift Navigation)
u-blox's PointPerfect GNSS augmentation service uses the secure MQTT protocol to download SPARTN format correction data, providing "3-6 cm accuracy and convergence within seconds". Please see the new [PointPerfect Client example](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/tree/main/examples/ZED-F9P/Example18_PointPerfectClient) for more details.
v2.2.1 also supports L-band correction services using the new u-blox NEO-D9S correction data receiver. Please see the new [L-band Corrections example](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/tree/main/examples/ZED-F9P/Example19_LBand_Corrections_with_NEO-D9S) for more details.
Other RTK NTRIP corrections services often require you to send them your location in NMEA GPGGA format. v2.2 of the library makes this easy by providing get functions and automatic callbacks
for both GPGGA and GNGGA messages. You can now instruct your module to output GPGGA (e.g.) every 10 seconds and then push it to the correction server directly from the callback. No more polling, no more parsing!
v2.2 also includes two new functions useful for correction services:
* ```setMainTalkerID``` : lets you change the NMEA Talker ID (prefix) from "GN" to "GP" - just in case your correction service really does need GPGGA, not GNGGA
* ```setHighPrecisionMode``` : adds extra decimal places in the GGA messages, increasing the resolution of latitude, longitude and altitude
Please see the new [Automatic_NMEA examples](./examples/Automatic_NMEA) for more details.
We've also added a new [NTRIP Caster Client example](./examples/ZED-F9P/Example17_NTRIPClient_With_GGA_Callback) showing how to use these new features to full effect.
## AssistNow<sup>TM</sup>
v2.1 of the library adds support for u-blox AssistNow<sup>TM</sup> Assisted GNSS (A-GNSS) which can dramatically reduce the time-to-first-fix. You can find further details in the [AssistNow Examples folder](./examples/AssistNow).
## v2 vs. v1
This library is the new and improved version of the very popular SparkFun u-blox GNSS Arduino Library. v2.0 contains some big changes and improvements:
* Seamless support for "automatic" message delivery:
* In v1.8, you could ask for the NAV PVT (Navigation Position Velocity Time) message to be delivered _automatically_, without polling. v2.0 adds automatic support for [**23 messages**](./Theory.md#auto-messages), covering the full range of: standard and High Precision position, velocity and time information; relative positioning; event capture with nanosecond time resolution; raw GNSS signal data including carrier phase; Sensor Fusion; and High Navigation Rate data.
* In v1.8, you could ask for the NAV PVT (Navigation Position Velocity Time) message to be delivered _automatically_, without polling. v2.0 adds automatic support for [**26 messages**](./Theory.md#auto-messages), covering the full range of: standard and High Precision position, velocity, attitude and time information; relative positioning; event capture with nanosecond time resolution; raw GNSS signal data including carrier phase; Sensor Fusion; and High Navigation Rate data.
* Don't see the message you really need? [Adding_New_Messages](./Adding_New_Messages.md) provides details on how to add "auto" support for your favourite message.
* Dynamic memory allocation with clearly-defined data storage structs for each message:
* There are no static 'global' variables to eat up your RAM. v2.0 automatically allocates memory for the automatic messages when they are enabled. You may find your total RAM use is lower with v2.0 than with v1.8.
* Each "auto" message has a clearly-defined [data storage struct](./src/u-blox_structs.h) which follows the u-blox protocol specification precisely.
@@ -53,6 +76,8 @@ Migrating to v2.0 is easy. There are two small changes all users will need to ma
If you are using the Dead Reckoning Sensor Fusion or High Dynamic Rate messages, you will need to make more small changes to your code. Please see the [dead reckoning examples](./examples/Dead_Reckoning) for more details. There is more detail available in [Theory.md](./Theory.md#migrating-your-code-to-v20) if you need it.
There is a [new example](./examples/Dead_Reckoning/Example8_getNAVPVAT) showing how to read the UBX-NAV-PVAT (Position, Velocity, Attitude, Time) with a single function call. UBX-NAV-PVAT has full "auto" callback and data-logging support too!
## Memory Usage
The u-blox GNSS library has grown considerably over the years and v2.0.8 came very close to completely filling the program memory on platforms like the ATmega328 (Arduino Uno).
@@ -79,9 +104,13 @@ The SPI examples have their [own folder](./examples/SPI).
Please check the module datasheets for details on what clock speeds and data rates each module supports. The maximum clock speed is typically 5.5MHz and the maximum transfer rate is typically 125kBytes/s.
## Max (400kHz) I<sup>2</sup>C Support
## I<sup>2</sup>C Support
To achieve 400kHz I<sup>2</sup>C speed please be sure to remove all pull-ups on the I<sup>2</sup>C bus. Most, if not all, u-blox modules include internal pull ups on the I<sup>2</sup>C lines (sometimes called DDC in their manuals). Cut all I<sup>2</sup>C pull up jumpers and/or remove them from peripheral boards. Otherwise, various data glitches can occur. See issues [38](https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/issues/38) and [40](https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/issues/40) for more information. If possible, run the I<sup>2</sup>C bus at 100kHz.
For I<sup>2</sup>C communication, please be sure to remove all additional pull-ups on the I<sup>2</sup>C bus. u-blox modules include internal pull-ups on the I<sup>2</sup>C lines (sometimes called DDC in their manuals). Cut all I<sup>2</sup>C pull-up jumpers and/or remove them from peripheral boards. Otherwise, various data glitches can occur. See issues [38](https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/issues/38) and [40](https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/issues/40) for more information. We recommend running the I<sup>2</sup>C bus at 100kHz.
## Compatibility
v2 of the library provides support for generation 8, 9 and 10 u-blox GNSS modules. For generation 6 and 7, please see [this example (depricated)](https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/tree/master/examples/Series_6_7/Example1_GetPositionAndTime_Series_6_7).
## Contributing
+4 -1
View File
@@ -5,7 +5,6 @@ When the user calls one of the methods the library will poll the u-blox module f
* Wait for a minimum of 25 ms between polls (configured dynamically when update rate is set)
* Write 0xFD to module
* Read two bytes (0xFD and 0xFE) for bytes available
* If 0x7F or 0xFF then no bytes are available
* Otherwise, read number of bytes and process into NMEA, UBX, or RTCM frame.
* If checksum is valid, flag frame as complete.
@@ -55,9 +54,11 @@ In v2.0, the full list of messages which can be processed and logged automatical
- UBX-NAV-VELNED (0x01 0x12): Velocity solution in NED frame
- UBX-NAV-HPPOSECEF (0x01 0x13): High precision position solution in ECEF
- UBX-NAV-HPPOSLLH (0x01 0x14): High precision geodetic position solution
- UBX-NAV-PVAT (0x01 0x17): Navigation position velocity attitude time solution (**only with ADR or UDR products**)
- UBX-NAV-CLOCK (0x01 0x22): Clock solution
- UBX-NAV-SVIN (0x01 0x3B): Survey-in data (**only with High Precision GNSS products**)
- UBX-NAV-RELPOSNED (0x01 0x3C): Relative positioning information in NED frame (**only with High Precision GNSS products**)
- UBX-NAV-AOPSTATUS (0x01 0x60): AssistNow Autonomous status
- UBX-RXM-SFRBX (0x02 0x13): Broadcast navigation data subframe
- UBX-RXM-RAWX (0x02 0x15): Multi-GNSS raw measurement data (**only with ADR or High Precision GNSS or Time Sync products**)
- UBX-TIM-TM2 (0x0D 0x03): Time mark data
@@ -70,6 +71,8 @@ In v2.0, the full list of messages which can be processed and logged automatical
- UBX-HNR-ATT (0x28 0x01): Attitude solution (**only with ADR or UDR products**)
- UBX-HNR-INS (0x28 0x02): Vehicle dynamics information (**only with ADR or UDR products**)
Please see [Adding_New_Messages](./Adding_New_Messages.md) for details on how to add "auto" support for new messages.
Notes:
- UBX-NAV-POSLLH is not supported as UBX-NAV-PVT contains the same information
- UBX-NAV-TIMEUTC is not supported as UBX-NAV-PVT contains the same information
+14 -5
View File
@@ -102,7 +102,6 @@ if (repairFile):
processed = -1 # The number of bytes processed
messages = {} # The collected message types
longest = 0 # The length of the longest UBX message
keepGoing = True
# Sync 'state machine'
@@ -132,6 +131,8 @@ ubx_checksum_A = 0
ubx_checksum_B = 0
ubx_expected_checksum_A = 0
ubx_expected_checksum_B = 0
longest_UBX = 0 # The length of the longest UBX message
longest_UBX_candidate = 0 # Candidate for the length of the longest valid UBX message
# Storage for NMEA messages
nmea_length = 0
@@ -145,8 +146,9 @@ nmea_csum1 = 0
nmea_csum2 = 0
nmea_expected_csum1 = 0
nmea_expected_csum2 = 0
longest_NMEA = 0 # The length of the longest valid NMEA message
max_nmea_len = 100 # Maximum length for an NMEA message: use this to detect if we have lost sync while receiving an NMEA message
max_nmea_len = 128 # Maximum length for an NMEA message: use this to detect if we have lost sync while receiving an NMEA message
sync_lost_at = -1 # Record where we lost sync
rewind_to = -1 # Keep a note of where we should rewind to if sync is lost
rewind_attempts = 0 # Keep a note of how many rewinds have been attempted
@@ -257,8 +259,7 @@ try:
ubx_length = ubx_length + (c * 256) # Add the length MSB
ubx_expected_checksum_A = ubx_expected_checksum_A + c # Update the expected checksum
ubx_expected_checksum_B = ubx_expected_checksum_B + ubx_expected_checksum_A
if (ubx_length > longest): # Update the longest UBX message length
longest = ubx_length
longest_UBX_candidate = ubx_length + 8 # Update the longest UBX message length candidate. Include the header, class, ID, length and checksum bytes
rewind_to = processed # If we lose sync due to dropped bytes then rewind to here
ubx_nmea_state = processing_payload # Now look for payload bytes (length: ubx_length)
elif (ubx_nmea_state == processing_payload):
@@ -287,6 +288,8 @@ try:
messages[message_type] += 1 # if we have, increment its count
else:
messages[message_type] = 1 # if we have not, set its count to 1
if (longest_UBX_candidate > longest_UBX): # Update the longest UBX message length
longest_UBX = longest_UBX_candidate
rewind_in_progress = False # Clear rewind_in_progress
rewind_to = -1
if (resync_in_progress == True): # Check if we are resyncing
@@ -330,6 +333,8 @@ try:
else: # ubx_length == 5
nmea_char_5 = c
message_type = chr(nmea_char_1) + chr(nmea_char_2) + chr(nmea_char_3) + chr(nmea_char_4) + chr(nmea_char_5) # Record the message type
if (message_type == "PUBX,"): # Remove the comma from PUBX
message_type = "PUBX"
# Now check if this is an '*'
if (c == 0x2A):
# Asterix received
@@ -389,6 +394,8 @@ try:
messages[message_type] += 1 # if we have, increment its count
else:
messages[message_type] = 1 # if we have not, set its count to 1
if (nmea_length > longest_NMEA): # Update the longest NMEA message length
longest_NMEA = nmea_length
# LF was received so go back to looking for B5 or a $
ubx_nmea_state = looking_for_B5_dollar
rewind_in_progress = False # Clear rewind_in_progress
@@ -441,7 +448,9 @@ finally:
print('File size was',filesize)
if (processed != filesize):
print('FILE SIZE MISMATCH!!')
print('Longest UBX message was %i data bytes'%longest)
print('Longest valid UBX message was %i bytes'%longest_UBX)
if (containsNMEA == True):
print('Longest valid NMEA message was %i characters'%longest_NMEA)
if len(messages) > 0:
print('Message types and totals were:')
for key in messages.keys():
@@ -0,0 +1,188 @@
/*
Monitor AssistNow Autonomous data collection
By: SparkFun Electronics / Paul Clark
Date: November 29th, 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 enable and monitor AssistNow Autonomous data collection by the module.
A callback is used to monitor AssistNow Autonomous data availability for each satellite.
A second callback is used to print the AOPSTATUS status.
If your GNSS board has battery-backup for the RAM - and all SparkFun boards do! - then you can:
wait until the module has AssistNow Autonomous data for a few satellites;
power-cycle the board;
watch how fast it gets its first fix!
Note: this example will only work on boards which have plenty of RAM available.
The UBX-NAV-SAT information occupies several kBytes.
Note: this example will not work on the ZED-F9P. "The ZED-F9P supports AssistNow Online only."
Feel like supporting open source hardware?
Buy a board from SparkFun!
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
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 <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Callback: printSATdata will be called when new NAV SAT data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_SAT_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoNAVSATcallback
// / _____ This _must_ be UBX_NAV_SAT_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printSATdata(UBX_NAV_SAT_data_t *ubxDataStruct)
{
//Serial.println();
Serial.print(F("UBX-NAV-SAT contains data for "));
Serial.print(ubxDataStruct->header.numSvs);
if (ubxDataStruct->header.numSvs == 1)
Serial.println(F(" SV"));
else
Serial.println(F(" SVs"));
uint16_t numAopAvail = 0; // Count how many SVs have AssistNow Autonomous data available
for (uint16_t block = 0; block < ubxDataStruct->header.numSvs; block++) // For each SV
{
if (ubxDataStruct->blocks[block].flags.bits.aopAvail == 1) // If the aopAvail bit is set
numAopAvail++; // Increment the number of SVs
}
Serial.print(F("AssistNow Autonomous data is available for "));
Serial.print(numAopAvail);
if (numAopAvail == 1)
Serial.println(F(" SV"));
else
Serial.println(F(" SVs"));
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Callback: printAOPstatus will be called when new NAV AOPSTATUS data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_AOPSTATUS_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoNAVAOPSTATUScallback
// / _____ This _must_ be UBX_NAV_AOPSTATUS_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printAOPstatus(UBX_NAV_AOPSTATUS_data_t *ubxDataStruct)
{
//Serial.println();
Serial.print(F("AOPSTATUS status is "));
Serial.println(ubxDataStruct->status);
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Callback: printPVTdata will be called when new NAV PVT data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_PVT_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoPVTcallback
// / _____ This _must_ be UBX_NAV_PVT_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printPVTdata(UBX_NAV_PVT_data_t *ubxDataStruct)
{
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
Serial.println();
long latitude = ubxDataStruct->lat; // Print the latitude
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = ubxDataStruct->lon; // Print the longitude
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = ubxDataStruct->hMSL; // Print the height above mean sea level
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte fixType = ubxDataStruct->fixType; // Print the fix type
Serial.print(F(" Fix: "));
if(fixType == 0) Serial.print(F("No fix"));
else if(fixType == 1) Serial.print(F("Dead reckoning"));
else if(fixType == 2) Serial.print(F("2D"));
else if(fixType == 3) Serial.print(F("3D"));
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
else if(fixType == 5) Serial.print(F("Time only"));
Serial.println();
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
delay(1000);
Serial.begin(115200);
Serial.println(F("AssistNow Example"));
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Start I2C. Connect to the GNSS.
Wire.begin(); //Start I2C
//myGNSS.enableDebugging(Serial, true); // Uncomment this line to see the 'major' debug messages on Serial
if (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."));
while (1);
}
Serial.println(F("u-blox module connected"));
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Enable AssistNow Autonomous data collection.
if (myGNSS.setAopCfg(1) == true)
{
Serial.println(F("aopCfg enabled"));
}
else
{
Serial.println(F("Could not enable aopCfg. Please check wiring. Freezing."));
while (1);
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Enable automatic UBX-NAV-SAT and UBX-NAV-AOPSTATUS messages and set up the callbacks
myGNSS.setNavigationFrequency(1); //Produce one solution per second
myGNSS.setAutoNAVSATcallbackPtr(&printSATdata); // Enable automatic NAV SAT messages with callback to printSATdata
myGNSS.setAutoAOPSTATUScallbackPtr(&printAOPstatus); // Enable automatic NAV AOPSTATUS messages with callback to printAOPstatus
myGNSS.setAutoPVTcallbackPtr(&printPVTdata); // Enable automatic NAV PVT messages with callback to printPVTdata
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
Serial.print(".");
delay(50);
}
@@ -0,0 +1,207 @@
/*
Read the AssistNow Autonomous database from the module
By: SparkFun Electronics / Paul Clark
Date: November 29th, 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 enable, check the status of, and read the AssistNow Autonomous data from the module.
Note: this example will only work on boards which have plenty of RAM available.
The database can be several kBytes in length.
Note: this example will not work on the ZED-F9P. "The ZED-F9P supports AssistNow Online only."
Feel like supporting open source hardware?
Buy a board from SparkFun!
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
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 <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Callback: printSATdata will be called when new NAV SAT data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_SAT_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoNAVSATcallback
// / _____ This _must_ be UBX_NAV_SAT_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printSATdata(UBX_NAV_SAT_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("UBX-NAV-SAT contains data for "));
Serial.print(ubxDataStruct->header.numSvs);
if (ubxDataStruct->header.numSvs == 1)
Serial.println(F(" SV"));
else
Serial.println(F(" SVs"));
uint16_t numAopAvail = 0; // Count how many SVs have AssistNow Autonomous data available
for (uint16_t block = 0; block < ubxDataStruct->header.numSvs; block++) // For each SV
{
if (ubxDataStruct->blocks[block].flags.bits.aopAvail == 1) // If the aopAvail bit is set
numAopAvail++; // Increment the number of SVs
}
Serial.print(F("AssistNow Autonomous data is available for "));
Serial.print(numAopAvail);
if (numAopAvail == 1)
Serial.println(F(" SV"));
else
Serial.println(F(" SVs"));
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Callback: printAOPstatus will be called when new NAV AOPSTATUS data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_AOPSTATUS_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoNAVAOPSTATUScallback
// / _____ This _must_ be UBX_NAV_AOPSTATUS_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printAOPstatus(UBX_NAV_AOPSTATUS_data_t *ubxDataStruct)
{
//Serial.println();
Serial.print(F("AOPSTATUS status is "));
Serial.println(ubxDataStruct->status);
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
delay(1000);
Serial.begin(115200);
Serial.println(F("AssistNow Example"));
while (Serial.available()) Serial.read(); // Empty the serial buffer
Serial.println(F("Press any key to begin..."));
while (!Serial.available()); // Wait for a keypress
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Start I2C. Connect to the GNSS.
Wire.begin(); //Start I2C
if (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."));
while (1);
}
Serial.println(F("u-blox module connected"));
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
//myGNSS.enableDebugging(Serial, true); // Uncomment this line to see helpful debug messages on Serial
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Enable AssistNow Autonomous data collection.
if (myGNSS.setAopCfg(1) == true)
{
Serial.println(F("aopCfg enabled"));
}
else
{
Serial.println(F("Could not enable aopCfg. Please check wiring. Freezing."));
while (1);
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Enable automatic UBX-NAV-SAT and UBX-NAV-AOPSTATUS messages and set up the callbacks
myGNSS.setNavigationFrequency(1); //Produce one solution per second
myGNSS.setAutoNAVSATcallbackPtr(&printSATdata); // Enable automatic NAV SAT messages with callback to printSATdata
myGNSS.setAutoAOPSTATUScallbackPtr(&printAOPstatus); // Enable automatic NAV AOPSTATUS messages with callback to printAOPstatus
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Keep displaying NAV SAT and AOPSTATUS until the user presses a key
Serial.println(F("AssistNow Autonomous data collection is in progress. Press any key to quit and read the database."));
while (Serial.available()) Serial.read(); // Empty the serial buffer
while (!Serial.available()) // Wait for the arrival of a keypress
{
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
Serial.print(".");
delay(50);
}
Serial.println();
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Disable the automatic UBX-NAV-SAT and UBX-NAV-AOPSTATUS messages
myGNSS.setAutoNAVSAT(false);
myGNSS.setAutoAOPSTATUS(false);
delay(1100);
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Read the AssistNow Autonomous database from the module and pretty-print it (so it can be copied and pasted into the next example)
#define MAX_DATABASE_LENGTH 32768 // Allocate 32kBytes to store the navigation database
size_t maxDatabaseLen = MAX_DATABASE_LENGTH;
uint8_t *database = new uint8_t[MAX_DATABASE_LENGTH]; // The database will be stored here
Serial.println(F("Storage has been allocated for the database.")); Serial.flush();
size_t actualDatabaseLen = myGNSS.readNavigationDatabase(database, maxDatabaseLen); // Read the database
Serial.print(F("The Navigation Database length was "));
Serial.println(actualDatabaseLen);
if (actualDatabaseLen == maxDatabaseLen)
Serial.println(F("There was not enough memory to store the entire database. Some data will have been lost!"));
// Pretty-print the database so it can be copied into the next example
Serial.println(F("Copy and paste the following into the next example, so you can write it back to the module:"));
Serial.println();
Serial.print(F("size_t databaseLen = "));
Serial.print(actualDatabaseLen);
Serial.println(F(";"));
Serial.print(F("const uint8_t database["));
Serial.print(actualDatabaseLen);
Serial.println(F("] = {"));
size_t i;
for(i = 0; i < actualDatabaseLen; i++)
{
if ((i % 32) == 0)
Serial.print(F(" 0x"));
if (*(database + i) < 0x10) // Print leading zero
Serial.print(F("0"));
Serial.print(*(database + i), HEX);
if (i == (actualDatabaseLen - 1))
Serial.println();
else if ((i % 32) == 31)
Serial.println(F(","));
else
Serial.print(F(", 0x"));
}
Serial.println(F("};"));
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void loop()
{
// Nothing to do here
}
@@ -0,0 +1,188 @@
/*
Write the AssistNow Autonomous database data to the module
By: SparkFun Electronics / Paul Clark
Date: December 1st, 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 write the AssistNow Autonomous database date back to the module.
This example is written for the ESP32. A WiFi connection is used to get network time to pass to the module.
(You could use an RTC instead.)
Copy and paste the database data from the previous example into database.h.
Update secrets.h with your:
- WiFi credentials
Note: this example will not work on the ZED-F9P. "The ZED-F9P supports AssistNow Online only."
Note: this example works best if you have the GNSS RAM battery-backup disabled.
All SparkFun boards have battery-backup for the RAM which will means the database is retained if you disconnect the power.
The module will use the database data from the battery-backed RAM when you turn the power back on.
You will only see the improvement in the time-to-first-fix if you disable the battery first - or you are using a non-SparkFun
board that does not have the backup battery.
Feel like supporting open source hardware?
Buy a board from SparkFun!
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
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 "database.h" // <- Copy and paste the database data from the previous example into database.h
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <WiFi.h>
#include <HTTPClient.h>
#include "secrets.h"
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include "time.h"
const char* ntpServer = "pool.ntp.org"; // The Network Time Protocol Server
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
delay(1000);
Serial.begin(115200);
Serial.println(F("AssistNow Example"));
while (Serial.available()) Serial.read(); // Empty the serial buffer
Serial.println(F("Press any key to begin..."));
while (!Serial.available()); // Wait for a keypress
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Start I2C. Connect to the GNSS.
Wire.begin(); //Start I2C
if (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."));
while (1);
}
Serial.println(F("u-blox module connected"));
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
//myGNSS.enableDebugging(Serial, true); // Uncomment this line to see helpful debug messages on Serial
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Connect to WiFi.
Serial.print(F("Connecting to local WiFi"));
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(F("."));
}
Serial.println();
Serial.println(F("WiFi connected!"));
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Set the RTC using network time. (Code taken from the SimpleTime example.)
// Request the time from the NTP server and use it to set the ESP32's RTC.
configTime(0, 0, ntpServer); // Set the GMT and daylight offsets to zero. We need UTC, not local time.
struct tm timeinfo;
if(!getLocalTime(&timeinfo))
{
Serial.println("Failed to obtain time");
}
else
{
Serial.println(&timeinfo, "Time is: %A, %B %d %Y %H:%M:%S");
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Push the RTC time to the module
// Uncomment the next line to enable the 'major' debug messages on Serial so you can see what AssistNow data is being sent
//myGNSS.enableDebugging(Serial, true);
if(getLocalTime(&timeinfo))
{
// setUTCTimeAssistance uses a default time accuracy of 2 seconds which should be OK here.
// Have a look at the library source code for more details.
myGNSS.setUTCTimeAssistance(timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
}
else
{
Serial.println("Failed to obtain time. This will not work well. The GNSS needs accurate time to start up quickly.");
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Push the AssistNow Autonomous data to the module
size_t bytesPushed = myGNSS.pushAssistNowData(database, databaseLen);
Serial.print(F("Pushed "));
Serial.print(bytesPushed);
Serial.println(F(" bytes of AssistNow Autonomous data to the module"));
if (bytesPushed != databaseLen)
Serial.println(F("Warning: bytesPushed does not match databaseLen! Maybe the database contains bad data? Or there was a communication error?"));
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Disconnect the WiFi as it's no longer needed
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
Serial.println(F("WiFi disconnected"));
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void loop()
{
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
byte fixType = myGNSS.getFixType();
Serial.print(F(" Fix: "));
if(fixType == 0) Serial.print(F("No fix"));
else if(fixType == 1) Serial.print(F("Dead reckoning"));
else if(fixType == 2) Serial.print(F("2D"));
else if(fixType == 3) Serial.print(F("3D"));
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
else if(fixType == 5) Serial.print(F("Time only"));
Serial.println();
}
@@ -0,0 +1,177 @@
// Paste the AssistNow Autonomous database data from the previous example here:
size_t databaseLen = 5480;
const uint8_t database[5480] = {
0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00, 0x00, 0x02, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x01, 0x08, 0xC4, 0x04, 0x26, 0xFE, 0x02, 0x54, 0xBA, 0xA9,
0xFF, 0xDA, 0x8C, 0x05, 0xA3, 0xC1, 0xCD, 0x85, 0x86, 0x0A, 0x14, 0x20, 0xAA, 0xE6, 0xB4, 0xD3, 0x4F, 0x27, 0x12, 0xE0, 0xE6, 0xC3, 0xE4, 0x79, 0x0E, 0xA1, 0xD3, 0x49, 0xF4, 0xFF, 0xAF, 0xF7,
0x67, 0x2E, 0x93, 0xF9, 0x6A, 0x1B, 0x2D, 0x10, 0xD3, 0x49, 0xBD, 0xFF, 0x26, 0x01, 0x00, 0x1E, 0x81, 0x22, 0xA1, 0xE4, 0x2A, 0x00, 0x10, 0x50, 0x04, 0x00, 0xB7, 0xBF, 0xB5, 0x62, 0x13, 0x80,
0x54, 0x00, 0x01, 0x00, 0x00, 0x05, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x04, 0x1E, 0xC4, 0x44, 0x72, 0x2F, 0x02, 0x71, 0xAD, 0xA4, 0xFF, 0xE8, 0xAE, 0xFA,
0x42, 0x25, 0xD1, 0x0F, 0x0D, 0x03, 0xCB, 0x71, 0xCF, 0x12, 0x6F, 0x89, 0x0F, 0x27, 0xF3, 0x49, 0x7B, 0x29, 0x4B, 0xF1, 0x0C, 0xA1, 0xD4, 0x49, 0xF5, 0xFF, 0xB6, 0x03, 0x98, 0x36, 0xA0, 0x03,
0xBB, 0x0F, 0x72, 0x1D, 0xD4, 0x49, 0xEE, 0xFF, 0x17, 0x00, 0x00, 0xC0, 0x85, 0x22, 0x2F, 0xF0, 0x3D, 0x00, 0x3C, 0x50, 0x04, 0x00, 0x1A, 0x35, 0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00,
0x00, 0x07, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x06, 0x5B, 0xC4, 0x44, 0xD8, 0xEC, 0x02, 0x4E, 0x79, 0xAC, 0xFF, 0xE8, 0x8A, 0x1D, 0xBC, 0x9F, 0xE8, 0x86,
0xD9, 0x07, 0x45, 0xD0, 0x05, 0x6A, 0x05, 0x06, 0xC3, 0x26, 0xB5, 0x7D, 0x4A, 0xA2, 0x86, 0xCA, 0x0D, 0xA1, 0xD4, 0x49, 0x2B, 0x00, 0x62, 0x07, 0x63, 0x2F, 0xF5, 0x05, 0x1E, 0x1A, 0x98, 0x10,
0xD4, 0x49, 0x38, 0x00, 0xBA, 0xFF, 0x00, 0xCB, 0xBE, 0x22, 0xF4, 0x59, 0x09, 0x00, 0xB6, 0x50, 0x04, 0x00, 0x2E, 0x9B, 0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00, 0x00, 0x09, 0x15, 0x0C,
0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x08, 0x5E, 0xC4, 0x44, 0xFA, 0x7B, 0x02, 0x4E, 0x1B, 0xA5, 0xFF, 0x03, 0x6E, 0x07, 0xF5, 0x25, 0xF3, 0xB8, 0x36, 0x01, 0xDB, 0x4F,
0x56, 0x3E, 0x8D, 0xA6, 0xD7, 0x26, 0x82, 0xFE, 0xA8, 0x4A, 0x7A, 0x44, 0x0D, 0xA1, 0xD4, 0x49, 0x05, 0x00, 0x7A, 0xFA, 0x1C, 0x37, 0xDC, 0xFA, 0x33, 0x0E, 0x7E, 0x1E, 0xD4, 0x49, 0xE5, 0xFF,
0xFC, 0xFF, 0x00, 0xB7, 0xBA, 0x22, 0x87, 0x2A, 0x34, 0x00, 0xBC, 0x50, 0x04, 0x00, 0xDF, 0x11, 0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00, 0x00, 0x0B, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00,
0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x0A, 0x2F, 0xC4, 0x44, 0xC7, 0x68, 0x00, 0xF6, 0x09, 0xAA, 0xFF, 0xED, 0xB8, 0x38, 0x24, 0x1C, 0xE8, 0xC5, 0x30, 0x00, 0xD0, 0x23, 0x17, 0xEC, 0xF7, 0x92,
0x2D, 0x27, 0x7C, 0x39, 0x2C, 0x6B, 0x66, 0xF5, 0x0D, 0xA1, 0xD4, 0x49, 0xEA, 0xFF, 0x27, 0xF9, 0x09, 0x2F, 0x2B, 0xFA, 0x6A, 0x1B, 0xFB, 0x0F, 0xD4, 0x49, 0x01, 0x00, 0x0F, 0x00, 0x00, 0xC1,
0x82, 0x22, 0x2A, 0x8A, 0x80, 0xFF, 0x5E, 0x50, 0x04, 0x00, 0x52, 0xBB, 0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00, 0x00, 0x0D, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A,
0x01, 0x03, 0x0C, 0x96, 0xC4, 0x44, 0x8E, 0xBD, 0x02, 0xE4, 0x39, 0xA6, 0xFF, 0xE8, 0x7E, 0xBE, 0x5F, 0xFE, 0xF3, 0xCA, 0xF0, 0x02, 0x5D, 0x9F, 0x84, 0x44, 0x3A, 0xC9, 0x6F, 0x27, 0xFD, 0x1B,
0xDB, 0x27, 0x60, 0x63, 0x0D, 0xA1, 0xD4, 0x49, 0x32, 0x00, 0x4B, 0xFA, 0xA6, 0x33, 0x2C, 0xFB, 0x5C, 0x10, 0xB8, 0x1C, 0xD4, 0x49, 0x0E, 0x00, 0x1E, 0x00, 0x00, 0x0D, 0xB9, 0x22, 0x3A, 0x4D,
0x07, 0x00, 0x2C, 0x51, 0x04, 0x00, 0x76, 0x2E, 0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00, 0x00, 0x10, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x0F, 0x22,
0xC4, 0x44, 0x47, 0xD2, 0x02, 0x47, 0xEA, 0xA3, 0xFF, 0xEA, 0x53, 0xBB, 0xBD, 0x37, 0xBE, 0x0A, 0x5B, 0x06, 0x85, 0x4F, 0x13, 0x98, 0x48, 0x33, 0x95, 0x27, 0xC8, 0x3B, 0xE7, 0x1B, 0x37, 0x8F,
0x0C, 0xA1, 0xD4, 0x49, 0xC9, 0xFF, 0x09, 0x0C, 0x98, 0x30, 0xB3, 0x0A, 0x16, 0x09, 0x14, 0x26, 0xD4, 0x49, 0xB3, 0xFF, 0x4E, 0x00, 0x00, 0xE0, 0x81, 0x22, 0x2D, 0xCD, 0x31, 0x00, 0x44, 0x50,
0x04, 0x00, 0x39, 0x9B, 0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00, 0x00, 0x14, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x13, 0x1B, 0xC4, 0x44, 0x6A, 0xD2,
0x02, 0xE9, 0x7C, 0xA3, 0xFF, 0xEE, 0xD1, 0x59, 0xEE, 0xE7, 0x56, 0x56, 0xCC, 0x02, 0xE4, 0x2C, 0x39, 0x0E, 0xB6, 0x13, 0x56, 0x26, 0xDF, 0xE5, 0x41, 0x7C, 0xDA, 0x86, 0x0D, 0xA1, 0xD4, 0x49,
0xFE, 0xFF, 0x81, 0x04, 0x73, 0x3A, 0x0F, 0x04, 0x54, 0x10, 0x59, 0x1B, 0xD4, 0x49, 0x37, 0x00, 0xDF, 0xFF, 0x00, 0x21, 0x87, 0x22, 0x0B, 0xF8, 0x10, 0x00, 0x36, 0x50, 0x04, 0x00, 0x75, 0x76,
0xB5, 0x62, 0x13, 0x80, 0x54, 0x00, 0x01, 0x00, 0x00, 0x1D, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x1C, 0x31, 0xC4, 0xC4, 0x58, 0xF9, 0x02, 0xFC, 0xD0, 0xA5,
0xFF, 0xEA, 0x04, 0x79, 0x3B, 0x17, 0xD6, 0x48, 0xEF, 0x00, 0xB9, 0x34, 0x1C, 0xC2, 0x1E, 0x93, 0x05, 0x28, 0xA0, 0x7E, 0x9D, 0x60, 0x7C, 0x63, 0x0C, 0xA1, 0xD4, 0x49, 0xD2, 0xFF, 0x51, 0xF4,
0xD6, 0x2D, 0xD9, 0xF5, 0x45, 0x08, 0x41, 0x27, 0xD4, 0x49, 0x23, 0x00, 0xFE, 0xFF, 0x00, 0x7C, 0xBC, 0x22, 0x15, 0x51, 0x31, 0x00, 0x62, 0x50, 0x04, 0x00, 0xEC, 0xE1, 0xB5, 0x62, 0x13, 0x80,
0x54, 0x00, 0x01, 0x00, 0x00, 0x1E, 0x15, 0x0C, 0x01, 0x0D, 0x3B, 0x00, 0x04, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x1D, 0x22, 0xC4, 0x04, 0x53, 0x24, 0x02, 0xF4, 0x99, 0xA8, 0xFF, 0x08, 0x62, 0xE5,
0x6F, 0x9E, 0x9C, 0x48, 0xBC, 0x02, 0xB4, 0x07, 0x9B, 0x6A, 0x21, 0x82, 0x28, 0x26, 0x78, 0x77, 0x0C, 0x90, 0x2F, 0xF9, 0x0C, 0xA1, 0xD4, 0x49, 0xE5, 0xFF, 0x34, 0x08, 0x30, 0x33, 0xC0, 0x06,
0x34, 0x1B, 0x7C, 0x0E, 0xD4, 0x49, 0xF7, 0xFF, 0xEE, 0xFF, 0x00, 0x19, 0xBE, 0x22, 0x6F, 0xC0, 0x2F, 0x00, 0x44, 0x50, 0x04, 0x00, 0x93, 0x6D, 0xB5, 0x62, 0x13, 0x80, 0x38, 0x00, 0x01, 0x00,
0x06, 0x07, 0x15, 0x0C, 0x01, 0x0C, 0x21, 0x00, 0x02, 0x24, 0xE0, 0x4A, 0x01, 0x03, 0xA5, 0xB9, 0xC6, 0x04, 0x16, 0x44, 0x02, 0xC6, 0xE0, 0xD9, 0x21, 0x1C, 0xC0, 0xE0, 0xF8, 0xD5, 0x3D, 0x6E,
0x01, 0x56, 0x21, 0xC1, 0x0F, 0x39, 0xF8, 0x70, 0x2D, 0x10, 0x7F, 0xFF, 0x10, 0x38, 0xEE, 0xA5, 0x80, 0x00, 0x00, 0xE8, 0x55, 0x0C, 0x1C, 0xEB, 0xB5, 0x62, 0x13, 0x80, 0x38, 0x00, 0x01, 0x00,
0x06, 0x0F, 0x15, 0x0C, 0x01, 0x0C, 0x21, 0x00, 0x02, 0x24, 0xE0, 0x4A, 0x01, 0x03, 0xAD, 0xB9, 0xC6, 0x04, 0x6F, 0x28, 0x02, 0x17, 0x5C, 0xB7, 0xE5, 0xF7, 0x80, 0x1F, 0x46, 0x2A, 0xDE, 0xBE,
0xF0, 0x59, 0x45, 0x5C, 0xCE, 0x39, 0x75, 0x99, 0xF7, 0x10, 0x1B, 0x7B, 0xFF, 0x78, 0x18, 0x5D, 0xFE, 0x00, 0x00, 0xE8, 0x55, 0x07, 0xC8, 0x8F, 0xB5, 0x62, 0x13, 0x80, 0x38, 0x00, 0x01, 0x00,
0x06, 0x10, 0x15, 0x0C, 0x01, 0x0C, 0x21, 0x00, 0x02, 0x24, 0xE0, 0x4A, 0x01, 0x03, 0xAE, 0xB9, 0xC6, 0x84, 0x26, 0x63, 0x02, 0x0C, 0x60, 0x9D, 0xDA, 0x44, 0x5E, 0xE2, 0x3C, 0x27, 0xDD, 0xED,
0xF5, 0x3B, 0xDE, 0xC1, 0xDE, 0x39, 0xA7, 0xDD, 0xF9, 0x20, 0x11, 0x54, 0x2A, 0x80, 0xFB, 0x6C, 0x80, 0x00, 0xFF, 0xEF, 0x55, 0x06, 0x17, 0x43, 0xB5, 0x62, 0x13, 0x80, 0x38, 0x00, 0x01, 0x00,
0x06, 0x15, 0x15, 0x0C, 0x01, 0x0C, 0x21, 0x00, 0x02, 0x24, 0xE0, 0x4A, 0x01, 0x03, 0xB3, 0xB9, 0xC6, 0x04, 0x6F, 0xC3, 0x02, 0xF0, 0xC6, 0x33, 0xC1, 0x45, 0x3F, 0x28, 0xC9, 0xBB, 0xBF, 0x1B,
0x1B, 0xEC, 0x14, 0xF1, 0xF5, 0x39, 0x55, 0x25, 0x06, 0x30, 0x84, 0xAE, 0xC7, 0xA8, 0x89, 0x3D, 0x44, 0x00, 0xFD, 0xEF, 0x55, 0x0B, 0x89, 0xE0, 0xB5, 0x62, 0x13, 0x80, 0x38, 0x00, 0x01, 0x00,
0x06, 0x17, 0x15, 0x0C, 0x01, 0x0C, 0x21, 0x00, 0x02, 0x24, 0xE0, 0x4A, 0x01, 0x03, 0xB5, 0xB9, 0xC6, 0x04, 0x34, 0xBC, 0x02, 0xF5, 0xBE, 0x0D, 0x15, 0xEA, 0x21, 0xA3, 0xC8, 0xDB, 0x1E, 0x3A,
0x31, 0x5A, 0x38, 0xB6, 0x20, 0x39, 0x8B, 0x4A, 0xD9, 0x30, 0xDF, 0x66, 0xF8, 0xB8, 0x9D, 0x5B, 0x00, 0x02, 0xFF, 0xEF, 0x55, 0x0A, 0x20, 0x5A, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00,
0x00, 0x01, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x00, 0x7B, 0xB0, 0x04, 0xC5, 0xE4, 0x01, 0x73, 0x47, 0x5B, 0xAE, 0x1C, 0x18, 0x0D, 0xA1, 0x00, 0x65, 0xFD,
0x00, 0x7B, 0x41, 0x2C, 0xEA, 0x00, 0x14, 0x16, 0x24, 0x00, 0xF1, 0x02, 0x67, 0x00, 0x06, 0xEA, 0x3F, 0x8A, 0xA4, 0x7B, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x02, 0x15, 0x0C,
0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x01, 0x7B, 0xB0, 0x44, 0x66, 0x1F, 0x03, 0xC2, 0x82, 0xA8, 0x90, 0x0E, 0x1C, 0x0E, 0xA1, 0x00, 0x4E, 0xFD, 0x00, 0x7B, 0x4F, 0x99,
0xE6, 0x00, 0xF3, 0xEB, 0xC3, 0x00, 0xE8, 0x8A, 0x6E, 0x00, 0x5C, 0x05, 0x00, 0x8A, 0xDF, 0xF9, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x03, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C,
0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x02, 0x7B, 0xB0, 0x04, 0x96, 0x8D, 0x01, 0xEB, 0x94, 0x1F, 0x20, 0x13, 0x6B, 0x0D, 0xA1, 0x00, 0x69, 0xFD, 0x00, 0x7B, 0xC1, 0x59, 0x14, 0x00, 0x8A, 0xAC,
0x28, 0x00, 0xDD, 0x24, 0x37, 0x00, 0xE0, 0xEF, 0x3F, 0x8A, 0x0F, 0xED, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x04, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A,
0x01, 0x03, 0x03, 0x7B, 0xB0, 0x44, 0x8F, 0x51, 0x01, 0xFF, 0xCA, 0x0C, 0xA8, 0x0B, 0xD6, 0x0C, 0xA1, 0x00, 0x44, 0xFD, 0x00, 0x7B, 0x3F, 0x67, 0x40, 0x00, 0x77, 0x26, 0x80, 0x00, 0x3A, 0x7C,
0xB2, 0x00, 0x2E, 0x07, 0x00, 0x8A, 0xD8, 0xB6, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x05, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x04, 0x00,
0xB0, 0x14, 0xB8, 0x76, 0x03, 0xEA, 0xD0, 0x30, 0x92, 0x0A, 0xF1, 0x0C, 0xA1, 0x00, 0x25, 0xFD, 0xD4, 0x49, 0x71, 0xCF, 0x12, 0x00, 0x49, 0x7B, 0x29, 0x00, 0xFA, 0x42, 0x25, 0x00, 0xBE, 0xFF,
0x3F, 0x8A, 0xD6, 0xA9, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x06, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x05, 0x7B, 0xB0, 0x44, 0xBB, 0x76,
0x01, 0x15, 0x1F, 0x14, 0x47, 0x1C, 0xB5, 0x0C, 0xA1, 0x00, 0x63, 0xFD, 0x00, 0x7B, 0x16, 0xD6, 0xE9, 0x00, 0xEC, 0xC2, 0xD5, 0x00, 0xAB, 0x35, 0x77, 0x00, 0x8C, 0x18, 0x80, 0x8A, 0x81, 0xB1,
0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x07, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x06, 0x00, 0xB0, 0x14, 0x33, 0xF6, 0x03, 0x49, 0x98, 0x7D,
0xC9, 0x05, 0xCA, 0x0D, 0xA1, 0x00, 0x63, 0xFD, 0xD4, 0x49, 0xD0, 0x05, 0x6A, 0x00, 0x7D, 0x4A, 0xA2, 0x00, 0x1D, 0xBC, 0x9F, 0x00, 0x2B, 0x09, 0x00, 0x8A, 0x4B, 0xEC, 0xB5, 0x62, 0x13, 0x80,
0x34, 0x00, 0x02, 0x00, 0x00, 0x08, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x07, 0x7B, 0xB0, 0x04, 0x04, 0xE8, 0x01, 0xB3, 0x40, 0x38, 0xDD, 0x0E, 0x13, 0x0D,
0xA1, 0x00, 0x22, 0xFD, 0x00, 0x7B, 0x33, 0x39, 0xBE, 0x00, 0x60, 0x6D, 0x02, 0x00, 0xAF, 0xE0, 0xC5, 0x00, 0xCF, 0x07, 0x80, 0x8A, 0x59, 0x50, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00,
0x00, 0x09, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x08, 0x00, 0xB0, 0x14, 0x50, 0xB2, 0x03, 0x0A, 0x6B, 0x13, 0x14, 0x07, 0x44, 0x0D, 0xA1, 0x00, 0x28, 0xFD,
0xD4, 0x49, 0x4F, 0x56, 0x3E, 0x00, 0xFE, 0xA8, 0x4A, 0x00, 0x07, 0xF5, 0x25, 0x00, 0x85, 0x06, 0x00, 0x8A, 0x09, 0xB0, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x0A, 0x15, 0x0C,
0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x09, 0x7B, 0xB0, 0x44, 0x94, 0x64, 0x01, 0x0C, 0xB3, 0x3B, 0x06, 0x13, 0x0D, 0x0D, 0xA1, 0x00, 0x6E, 0xFD, 0x00, 0x7B, 0x68, 0x3C,
0x14, 0x00, 0x15, 0x6E, 0x97, 0x00, 0x53, 0x99, 0x16, 0x00, 0xEF, 0xF6, 0xBF, 0x8A, 0xC1, 0xA9, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x0B, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C,
0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x0A, 0x7B, 0xB0, 0x04, 0xF5, 0x0B, 0x01, 0xDE, 0x10, 0x03, 0x70, 0x0C, 0x97, 0x0D, 0xA1, 0xFF, 0x52, 0xFD, 0x00, 0x7B, 0x7A, 0x06, 0xEC, 0x00, 0xA3, 0x44,
0x6B, 0x00, 0xA1, 0xEB, 0xC8, 0x00, 0x11, 0xF8, 0xBF, 0x8A, 0xB4, 0x35, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x0C, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A,
0x01, 0x03, 0x0B, 0x7B, 0xB0, 0x04, 0xFD, 0x31, 0x01, 0x09, 0xE0, 0x44, 0xFA, 0x12, 0xD4, 0x0C, 0xA1, 0x00, 0x54, 0xFD, 0x00, 0x7B, 0xBC, 0x3F, 0x97, 0x00, 0x0C, 0x17, 0x32, 0x00, 0x5D, 0xE0,
0x30, 0x00, 0x72, 0xF7, 0xBF, 0x8A, 0x91, 0x2E, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x0D, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x0C, 0x00,
0xB0, 0x14, 0x82, 0xD3, 0x03, 0x6F, 0x0C, 0x2F, 0x96, 0x10, 0x63, 0x0D, 0xA1, 0x00, 0x31, 0xFD, 0xD4, 0x49, 0x9F, 0x84, 0x44, 0x00, 0x1B, 0xDB, 0x27, 0x00, 0xBE, 0x5F, 0xFE, 0x00, 0xE9, 0x08,
0x00, 0x8A, 0x4A, 0x74, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x0E, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x0D, 0x7B, 0xB0, 0x44, 0x3E, 0xB1,
0x01, 0x66, 0xD7, 0x09, 0x30, 0x08, 0xCD, 0x0C, 0xA1, 0x00, 0x4A, 0xFD, 0x00, 0x7B, 0x72, 0x05, 0x96, 0x00, 0x85, 0x34, 0x7E, 0x00, 0xFE, 0xFB, 0x2F, 0x00, 0xCC, 0xF7, 0xBF, 0x8A, 0x3C, 0x14,
0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x0F, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x0E, 0x7B, 0xB0, 0x44, 0x92, 0xB0, 0x01, 0xBF, 0xF2, 0x71,
0x4F, 0xF7, 0x0E, 0x0D, 0xA1, 0x00, 0x26, 0xFD, 0x00, 0x7B, 0x66, 0x06, 0x3A, 0x00, 0xAE, 0x39, 0x2B, 0x00, 0xEF, 0x2D, 0x9C, 0x00, 0x95, 0x0F, 0x80, 0x8A, 0x3F, 0x35, 0xB5, 0x62, 0x13, 0x80,
0x34, 0x00, 0x02, 0x00, 0x00, 0x10, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x0F, 0x00, 0xB0, 0x14, 0x96, 0x34, 0x03, 0x8E, 0xB0, 0x65, 0xEC, 0x12, 0x8F, 0x0C,
0xA1, 0x00, 0x1F, 0xFD, 0xD4, 0x49, 0x4F, 0x13, 0x98, 0x00, 0x3B, 0xE7, 0x1B, 0x00, 0xBB, 0xBD, 0x37, 0x00, 0x39, 0xF6, 0x3F, 0x8A, 0xF3, 0x43, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00,
0x00, 0x11, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x10, 0x7B, 0xB0, 0x04, 0x5E, 0xE6, 0x01, 0xF3, 0xDF, 0x70, 0xA4, 0x18, 0x50, 0x0D, 0xA1, 0x00, 0x34, 0xFD,
0x00, 0x7B, 0x86, 0x84, 0xC1, 0x00, 0x0F, 0xBA, 0xC1, 0x00, 0xF9, 0x59, 0xC2, 0x00, 0x39, 0x0A, 0x80, 0x8A, 0x83, 0x21, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x12, 0x15, 0x0C,
0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x11, 0x7B, 0xB0, 0x04, 0x92, 0xB3, 0x01, 0xCD, 0x23, 0x11, 0x1A, 0x12, 0xC7, 0x0C, 0xA1, 0x00, 0x57, 0xFD, 0x00, 0x7B, 0x1B, 0x89,
0xEA, 0x00, 0x3E, 0x35, 0x7D, 0x00, 0x7D, 0xB8, 0x6F, 0x00, 0x2B, 0xF1, 0xBF, 0x8A, 0x1F, 0x89, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x13, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C,
0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x12, 0x7B, 0xB0, 0x44, 0xDE, 0x29, 0x01, 0x15, 0x35, 0x49, 0xCA, 0x17, 0xF3, 0x0C, 0xA1, 0x00, 0x30, 0xFD, 0x00, 0x7B, 0xBE, 0x59, 0xC3, 0x00, 0xEA, 0xA7,
0x50, 0x00, 0xBF, 0x3E, 0x23, 0x00, 0x5C, 0x08, 0x80, 0x8A, 0x31, 0x50, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x14, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A,
0x01, 0x03, 0x13, 0x00, 0xB0, 0x14, 0x3E, 0x72, 0x03, 0xA1, 0xC5, 0x2C, 0xFA, 0xFE, 0x86, 0x0D, 0xA1, 0x00, 0x1B, 0xFD, 0xD4, 0x49, 0x2C, 0x39, 0x0E, 0x00, 0xE5, 0x41, 0x7C, 0x00, 0x59, 0xEE,
0xE7, 0x00, 0x1F, 0xFA, 0x3F, 0x8A, 0x05, 0x19, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x15, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x14, 0x7B,
0xB0, 0x44, 0x9E, 0xFA, 0x01, 0xD6, 0x02, 0xC7, 0xCD, 0x0A, 0x8B, 0x0C, 0xA1, 0x00, 0x4C, 0xFD, 0x00, 0x7B, 0x38, 0x8D, 0xE6, 0x00, 0x0D, 0x36, 0xD5, 0x00, 0xBA, 0x5E, 0xC7, 0x00, 0xA0, 0x00,
0x80, 0x8A, 0x7F, 0x6E, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x16, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x15, 0x7B, 0xB0, 0x44, 0x9E, 0x17,
0x01, 0x24, 0x81, 0x37, 0xE8, 0xFC, 0xEA, 0x0C, 0xA1, 0x00, 0x4C, 0xFD, 0x00, 0x7B, 0xDE, 0x06, 0x10, 0x00, 0xD1, 0x69, 0xDC, 0x00, 0xC5, 0x18, 0x94, 0x00, 0x28, 0x16, 0x80, 0x8A, 0xBE, 0x20,
0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x17, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x16, 0x7B, 0xB0, 0x44, 0x2E, 0xDB, 0x01, 0x43, 0xB7, 0x0F,
0xCC, 0x0F, 0x25, 0x0D, 0xA1, 0x00, 0x68, 0xFD, 0x00, 0x7B, 0x32, 0x3D, 0x13, 0x00, 0x85, 0x6C, 0x73, 0x00, 0xE0, 0xD5, 0x4F, 0x00, 0x1B, 0xF8, 0xBF, 0x8A, 0x13, 0xA5, 0xB5, 0x62, 0x13, 0x80,
0x34, 0x00, 0x02, 0x00, 0x00, 0x18, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x17, 0x7B, 0xB0, 0x04, 0xAC, 0x23, 0x01, 0x3F, 0x2F, 0x63, 0xE2, 0xFA, 0x29, 0x0D,
0xA1, 0x00, 0x4A, 0xFD, 0x00, 0x7B, 0x90, 0xA3, 0x66, 0x00, 0x3C, 0x04, 0x20, 0x00, 0x7B, 0x4A, 0x74, 0x00, 0x1E, 0x09, 0x80, 0x8A, 0x67, 0xDD, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00,
0x00, 0x19, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x18, 0x7B, 0xB0, 0x04, 0xF3, 0x84, 0x01, 0x2A, 0xEE, 0x52, 0xCB, 0x0A, 0x9F, 0x0D, 0xA1, 0x00, 0x4E, 0xFD,
0x00, 0x7B, 0xFC, 0x28, 0x94, 0x00, 0x03, 0x3B, 0x27, 0x00, 0x5D, 0xC2, 0x28, 0x00, 0x06, 0x11, 0x00, 0x8A, 0xBF, 0x71, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x1A, 0x15, 0x0C,
0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x19, 0x7B, 0xB0, 0x44, 0x12, 0x8B, 0x01, 0xA4, 0xBC, 0x35, 0x56, 0xFE, 0xF0, 0x0C, 0xA1, 0x00, 0x43, 0xFD, 0x00, 0x7B, 0x47, 0x4D,
0x92, 0x00, 0xCE, 0xEF, 0x0C, 0x00, 0x55, 0x6B, 0x0E, 0x00, 0xA9, 0x08, 0x00, 0x8A, 0x09, 0xC6, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x1B, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C,
0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x1A, 0x7B, 0xB0, 0x44, 0x25, 0xAF, 0x01, 0xD4, 0x10, 0x50, 0x81, 0x14, 0xC4, 0x0C, 0xA1, 0x00, 0x29, 0xFD, 0x00, 0x7B, 0xA9, 0xFD, 0xBE, 0x00, 0x17, 0x91,
0x19, 0x00, 0x63, 0x98, 0xC1, 0x00, 0x12, 0xFF, 0x3F, 0x8A, 0x9F, 0x4C, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x1D, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A,
0x01, 0x03, 0x1C, 0x00, 0xB0, 0x14, 0x3D, 0x4B, 0x03, 0x1C, 0xF4, 0x0E, 0xF2, 0x19, 0x63, 0x0C, 0xA1, 0x00, 0x2E, 0xFD, 0xD4, 0x49, 0x34, 0x1C, 0xC2, 0x00, 0x7E, 0x9D, 0x60, 0x00, 0x79, 0x3B,
0x17, 0x00, 0x2A, 0xF6, 0x3F, 0x8A, 0x99, 0x1E, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x1E, 0x15, 0x0C, 0x0F, 0x0C, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x1D, 0x00,
0xB0, 0x14, 0x9C, 0x70, 0x03, 0x50, 0xC4, 0x2B, 0x21, 0xFC, 0xF9, 0x0C, 0xA1, 0x00, 0x44, 0xFD, 0xD4, 0x49, 0x07, 0x9B, 0x6A, 0x00, 0x77, 0x0C, 0x90, 0x00, 0xE5, 0x6F, 0x9E, 0x00, 0xF8, 0xFD,
0x3F, 0x8A, 0x8C, 0x9F, 0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x1F, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x1E, 0x7B, 0xB0, 0x04, 0x9F, 0xDA,
0x01, 0x5F, 0x6C, 0x55, 0x80, 0x08, 0xD4, 0x0C, 0xA1, 0x00, 0x5E, 0xFD, 0x00, 0x7B, 0xCB, 0xAE, 0x6A, 0x00, 0x9B, 0x04, 0x0E, 0x00, 0x96, 0x65, 0x3A, 0x00, 0x5F, 0x07, 0x80, 0x8A, 0xAA, 0xFA,
0xB5, 0x62, 0x13, 0x80, 0x34, 0x00, 0x02, 0x00, 0x00, 0x20, 0x15, 0x0C, 0x11, 0x13, 0x38, 0x1C, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x1F, 0x7B, 0xB0, 0x44, 0x7E, 0x41, 0x01, 0x92, 0xEF, 0x2A,
0x99, 0x09, 0x6C, 0x0D, 0xA1, 0x00, 0x40, 0xFD, 0x00, 0x7B, 0x3C, 0xB6, 0x3E, 0x00, 0x0C, 0xA2, 0x9E, 0x00, 0x27, 0x24, 0xDF, 0x00, 0xE0, 0xFF, 0xBF, 0x8A, 0xEB, 0xFB, 0xB5, 0x62, 0x13, 0x80,
0x24, 0x00, 0x02, 0x00, 0x01, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x23, 0x00, 0xB0, 0x44, 0x55, 0xF1, 0x01, 0x0A, 0x01, 0xB6, 0x8F, 0x10, 0x40, 0x8D,
0x04, 0x00, 0x8A, 0x08, 0x0E, 0x00, 0x92, 0x02, 0xB5, 0x62, 0x13, 0x80, 0x24, 0x00, 0x02, 0x00, 0x01, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x30, 0x00,
0xB0, 0x44, 0x66, 0xC5, 0x03, 0x31, 0x1B, 0xBF, 0xC2, 0x02, 0x40, 0x8D, 0x04, 0x00, 0x8A, 0x08, 0x0E, 0x00, 0x02, 0x61, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x01, 0x15, 0x0C,
0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x9F, 0xBD, 0xD2, 0x04, 0x7B, 0x94, 0x00, 0x0C, 0xC5, 0x40, 0x6B, 0x08, 0x38, 0xC3, 0x24, 0xFD, 0xC5, 0xC3, 0xA5, 0x57, 0xE1, 0x21,
0x3E, 0x01, 0x58, 0x1D, 0x78, 0x3A, 0x38, 0x13, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x02, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA0, 0xBD,
0xB2, 0x04, 0x91, 0x39, 0x00, 0x56, 0xDD, 0x3F, 0x2B, 0x17, 0x59, 0xC0, 0x82, 0xEF, 0x6C, 0x9A, 0xA8, 0x57, 0x7C, 0x9D, 0x72, 0x07, 0xBA, 0x27, 0x78, 0x3A, 0xB1, 0x11, 0xB5, 0x62, 0x13, 0x80,
0x2C, 0x00, 0x02, 0x00, 0x06, 0x03, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA1, 0xBD, 0xD2, 0x04, 0xBE, 0x31, 0x00, 0xB5, 0xD6, 0x3F, 0x6B, 0x19, 0x87, 0xDB,
0x80, 0xFE, 0x42, 0x0C, 0xAB, 0x57, 0xDE, 0xA0, 0x21, 0x07, 0xF9, 0x23, 0x74, 0x3A, 0x7E, 0x46, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x04, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A,
0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA2, 0xBD, 0xB2, 0x04, 0x57, 0x31, 0x00, 0x4B, 0xBE, 0x3F, 0xAB, 0x21, 0x5E, 0x0B, 0x3F, 0xFC, 0x75, 0x74, 0xAD, 0x57, 0x5F, 0xB2, 0x07, 0x03, 0x1B, 0x2B,
0x70, 0x3A, 0xBB, 0x0F, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x05, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA3, 0xBD, 0xD2, 0x04, 0x33, 0x11,
0x00, 0x49, 0xAC, 0x3F, 0x6B, 0x28, 0xE3, 0x3A, 0x7D, 0xFD, 0x5F, 0xDB, 0xAF, 0x57, 0x9D, 0x88, 0x4D, 0x02, 0x72, 0x2B, 0x6C, 0x3A, 0x3E, 0x71, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00,
0x06, 0x06, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA4, 0xBD, 0xD2, 0x04, 0xEC, 0x1E, 0x00, 0xD0, 0xF5, 0x3F, 0x2B, 0x37, 0x2E, 0xF3, 0xBA, 0x80, 0x9A, 0xA6,
0xB2, 0x57, 0xF7, 0x5D, 0x55, 0x03, 0xF4, 0x1C, 0x68, 0x3A, 0x19, 0x49, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x07, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A,
0x01, 0x03, 0xA5, 0xBD, 0xD2, 0x84, 0xCD, 0x4A, 0x02, 0x75, 0xE1, 0x3F, 0x6B, 0x39, 0x75, 0x51, 0x48, 0x81, 0x45, 0x3F, 0xA1, 0x57, 0x5D, 0xA0, 0x16, 0x06, 0x27, 0x24, 0x84, 0x3A, 0xA8, 0x47,
0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x08, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA6, 0xBD, 0xD2, 0x04, 0x3F, 0xAB, 0x00, 0xC5, 0xCE, 0x3F,
0xAB, 0x41, 0x2F, 0x8F, 0x06, 0x82, 0x68, 0x8F, 0xA3, 0x57, 0xB1, 0xB2, 0x4E, 0x07, 0x51, 0x24, 0x90, 0x3A, 0x81, 0x71, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x09, 0x15, 0x0C,
0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA7, 0xBD, 0xD2, 0x04, 0xEF, 0x93, 0x00, 0x15, 0x7A, 0x40, 0xAB, 0x4F, 0xD9, 0xD5, 0x4F, 0xFF, 0xD6, 0x42, 0xA5, 0x57, 0xAC, 0x90,
0x39, 0x06, 0x3F, 0x11, 0x94, 0x3B, 0xA2, 0xFC, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x0A, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA8, 0xBD,
0xD2, 0x84, 0x00, 0xC3, 0x00, 0xBA, 0x16, 0x40, 0x6B, 0x56, 0xF5, 0x1B, 0x8E, 0x82, 0xD8, 0x8B, 0xA7, 0x57, 0x1B, 0x06, 0xE9, 0x06, 0x2D, 0x21, 0x94, 0x3B, 0x71, 0x55, 0xB5, 0x62, 0x13, 0x80,
0x2C, 0x00, 0x02, 0x00, 0x06, 0x0B, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xA9, 0xBD, 0xD2, 0x04, 0xD3, 0x18, 0x00, 0x90, 0x2C, 0x40, 0x2B, 0x58, 0xCF, 0x2D,
0x8C, 0x7E, 0xEF, 0x12, 0xAA, 0x57, 0xD2, 0xB1, 0xAD, 0x01, 0x45, 0x27, 0x94, 0x3B, 0x8F, 0x20, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x0C, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A,
0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xAA, 0xBD, 0xD2, 0x04, 0x7F, 0x3D, 0x00, 0x5E, 0x7A, 0x40, 0xEB, 0x67, 0x2C, 0x45, 0xCA, 0xF6, 0x48, 0xA8, 0xAC, 0x57, 0xF8, 0xD5, 0x66, 0x04, 0x36, 0x22,
0x94, 0x3B, 0x5B, 0x01, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x0D, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xAB, 0xBD, 0xD2, 0x84, 0xC1, 0x1E,
0x00, 0xC6, 0xFF, 0x3F, 0xAB, 0x6F, 0xFE, 0x69, 0x28, 0x82, 0xE4, 0x06, 0xAF, 0x57, 0x3D, 0x34, 0x38, 0x02, 0xFB, 0x20, 0x94, 0x3B, 0xC8, 0xB3, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00,
0x06, 0x0E, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xAC, 0xBD, 0xB2, 0x04, 0x41, 0xAE, 0x00, 0xFC, 0x51, 0x40, 0x6B, 0x76, 0x2D, 0x7B, 0xA6, 0xFD, 0x9C, 0x9F,
0xB1, 0x57, 0xDA, 0xAF, 0xDE, 0x01, 0xB5, 0x1B, 0x98, 0x3B, 0x8D, 0x75, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x0F, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A,
0x01, 0x03, 0xAD, 0xBD, 0xD2, 0x04, 0x32, 0x99, 0x02, 0x17, 0x61, 0x40, 0x2B, 0x78, 0x76, 0xB4, 0xD3, 0xFC, 0x10, 0x45, 0xA0, 0x57, 0x67, 0xC7, 0xEF, 0x02, 0x93, 0x20, 0x90, 0x3B, 0xC3, 0x1E,
0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x10, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xAE, 0xBD, 0xD2, 0x04, 0x70, 0x64, 0x02, 0x10, 0xC5, 0x40,
0xEB, 0x87, 0x72, 0x87, 0xF1, 0x80, 0x8E, 0xF2, 0xA2, 0x57, 0x57, 0x0A, 0x76, 0x0C, 0xD9, 0x17, 0x88, 0x3B, 0x91, 0xAA, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x11, 0x15, 0x0C,
0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xAF, 0xBD, 0xD2, 0x04, 0x95, 0xB0, 0x00, 0x24, 0x2D, 0x40, 0x2B, 0x89, 0x3B, 0x4D, 0x5B, 0xF0, 0xAB, 0x5C, 0xA4, 0x57, 0x50, 0x95,
0x23, 0x04, 0xB1, 0x3A, 0x0C, 0x3A, 0x59, 0x64, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x12, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xB0, 0xBD,
0xD2, 0x04, 0x61, 0xBD, 0x00, 0xC7, 0x14, 0x40, 0x6B, 0x97, 0x82, 0x8D, 0xD9, 0xFC, 0xB9, 0xB4, 0xA6, 0x57, 0x71, 0xE6, 0x0F, 0x05, 0x96, 0x40, 0x10, 0x3A, 0xD3, 0x7B, 0xB5, 0x62, 0x13, 0x80,
0x2C, 0x00, 0x02, 0x00, 0x06, 0x13, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xB1, 0xBD, 0xD2, 0x04, 0x61, 0x35, 0x00, 0xC3, 0xC6, 0x3F, 0xEB, 0x98, 0x44, 0x01,
0x98, 0x85, 0xA8, 0xE9, 0xA8, 0x57, 0xC2, 0xA4, 0x0D, 0x01, 0xFD, 0x45, 0x10, 0x3A, 0x94, 0x41, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x14, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A,
0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xB2, 0xBD, 0xD2, 0x04, 0xB1, 0x18, 0x00, 0x5D, 0x11, 0x40, 0xAB, 0xA0, 0xC8, 0xDF, 0x15, 0x82, 0xB1, 0xB9, 0xAB, 0x57, 0xF1, 0xE9, 0xC1, 0x03, 0x4A, 0x46,
0x10, 0x3A, 0xA7, 0x43, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x15, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xB3, 0xBD, 0xD2, 0x04, 0x28, 0x00,
0x02, 0x5E, 0x5E, 0x40, 0x2B, 0xA9, 0x27, 0xA6, 0x73, 0x88, 0xE6, 0x73, 0xAE, 0x57, 0xCC, 0x8C, 0xAD, 0x02, 0x36, 0x3F, 0x14, 0x3A, 0xAF, 0x7C, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00,
0x06, 0x16, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xB4, 0xBD, 0xD2, 0x04, 0x85, 0xEC, 0x00, 0x91, 0xEE, 0x3F, 0x6B, 0xB7, 0x72, 0xF2, 0xD1, 0x84, 0x7D, 0xBE,
0xB0, 0x57, 0xEE, 0x05, 0x09, 0x08, 0x71, 0x43, 0x18, 0x3A, 0x1D, 0x65, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x17, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A,
0x01, 0x03, 0xB5, 0xBD, 0xD2, 0x04, 0xB1, 0x72, 0x02, 0x0E, 0xDA, 0x3E, 0xEB, 0xB8, 0xE4, 0xB4, 0xAF, 0x80, 0x21, 0xAF, 0xB3, 0x57, 0x7C, 0x50, 0x49, 0x00, 0x24, 0x43, 0x18, 0x3A, 0x26, 0xE7,
0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x02, 0x00, 0x06, 0x18, 0x15, 0x0C, 0x15, 0x15, 0x00, 0x2A, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0xB6, 0xBD, 0xD2, 0x04, 0xE1, 0x9D, 0x00, 0xA2, 0x0C, 0x40,
0xAB, 0xC0, 0xEA, 0x39, 0xDD, 0xFD, 0x09, 0xEC, 0xA1, 0x57, 0x92, 0xAE, 0x92, 0x03, 0x96, 0x2B, 0x08, 0x3A, 0x64, 0xD1, 0xB5, 0x62, 0x13, 0x80, 0x78, 0x00, 0x03, 0x00, 0x00, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x19, 0x00, 0x00, 0x05, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x07, 0x00, 0x8A, 0x08, 0x89, 0x08, 0x12, 0x07,
0x12, 0x00, 0xC1, 0x03, 0x00, 0x00, 0x19, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80, 0x32, 0x00, 0x00, 0x80, 0xB2, 0x00, 0x00, 0x80, 0xB3, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0xEC, 0x47, 0x00, 0x00,
0x60, 0xC8, 0x00, 0x00, 0x80, 0xC7, 0x00, 0x00, 0x50, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0x22, 0xB5, 0x62, 0x13, 0x80, 0x2C, 0x00, 0x03, 0x00, 0x06, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x4A, 0x01, 0x03, 0x12, 0x00, 0x06, 0x07, 0x11, 0x00, 0x06, 0x15, 0x01, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xBD, 0x3A, 0xBD, 0x02, 0x92, 0xC7,
0x1E, 0x00, 0xBD, 0x3A, 0x00, 0x00, 0x83, 0xEB, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x02, 0x15, 0x0C, 0x04, 0x14, 0x0F, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x01, 0x5E,
0xAD, 0x14, 0x0D, 0xD9, 0x01, 0x99, 0x8A, 0x08, 0x57, 0xFD, 0x00, 0x00, 0x00, 0xC4, 0xA0, 0xFF, 0xAF, 0x13, 0x31, 0x04, 0x00, 0xED, 0x07, 0xBB, 0xE2, 0xC1, 0xE2, 0xA6, 0xA2, 0x5F, 0x18, 0xC2,
0x8E, 0x08, 0x42, 0xC9, 0xD5, 0x17, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x07, 0x20, 0x00, 0x50, 0xF8, 0xAB, 0xA6, 0xD0, 0xC2, 0x7C, 0xE2, 0xDC, 0x80, 0x36, 0x92, 0x07, 0x9C, 0x36, 0xA1, 0x2E,
0x78, 0x0C, 0x91, 0xCE, 0x7E, 0xE6, 0x3E, 0x63, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x05, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x04, 0x5E,
0xAD, 0x14, 0xBB, 0x54, 0x01, 0x85, 0x8A, 0x08, 0x58, 0xFD, 0x00, 0x00, 0x40, 0xC4, 0xA9, 0xFF, 0xAF, 0x13, 0xEE, 0xD1, 0x3F, 0xF4, 0xE8, 0xBA, 0x02, 0x42, 0xDB, 0xA6, 0xE2, 0x4F, 0x93, 0xCC,
0x86, 0x08, 0x5E, 0xE0, 0xFB, 0x01, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0xB2, 0xC2, 0xA1, 0xA2, 0x5A, 0xF1, 0x5A, 0x67, 0xD2, 0x32, 0xCB, 0x87, 0x73, 0xEA, 0xA6, 0x22, 0x7E, 0xCE,
0xB7, 0xF8, 0x59, 0xCB, 0x13, 0xCF, 0x90, 0x3D, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x07, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x06, 0x5E,
0xAD, 0x14, 0x1C, 0x84, 0x01, 0x3C, 0x8A, 0x08, 0x58, 0x01, 0x00, 0x00, 0x40, 0x44, 0x5B, 0x01, 0xA0, 0x13, 0xB1, 0x77, 0x00, 0xF4, 0xE8, 0xBA, 0x02, 0x02, 0xDC, 0xA6, 0x62, 0x0D, 0x9B, 0x10,
0x8D, 0x08, 0xE8, 0xB3, 0x12, 0x04, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0xD3, 0xB5, 0xB7, 0x0A, 0x9E, 0x12, 0x42, 0xA2, 0x14, 0xB9, 0xAD, 0xE8, 0xD6, 0xBA, 0xA1, 0x04, 0xEB, 0x56,
0xE5, 0x29, 0xD2, 0xF1, 0x3E, 0xD4, 0x51, 0xD3, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x09, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x08, 0x5E,
0xAD, 0x14, 0xAE, 0x75, 0x01, 0xEB, 0x8A, 0x08, 0x58, 0x7D, 0x00, 0x00, 0x40, 0x44, 0x27, 0x00, 0xA0, 0x13, 0x2A, 0x09, 0x80, 0x01, 0xE8, 0xBA, 0x02, 0xC2, 0xDC, 0xA6, 0x42, 0x7D, 0x43, 0x25,
0x97, 0x08, 0x0E, 0x55, 0xE8, 0x19, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0x34, 0x43, 0x60, 0xE2, 0x59, 0x42, 0xAE, 0xE1, 0xE5, 0x34, 0x86, 0x80, 0xA7, 0xDF, 0xA3, 0xE9, 0x4E, 0xB1,
0xF7, 0x28, 0xB4, 0xBC, 0x8B, 0xD9, 0x5E, 0x5F, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x0D, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x0C, 0x5E,
0xAD, 0x14, 0x79, 0x8D, 0x01, 0x81, 0x8A, 0x08, 0x58, 0x01, 0x00, 0x00, 0x40, 0x44, 0x91, 0x01, 0xA0, 0x13, 0x16, 0xD5, 0x3F, 0xF4, 0xE8, 0xBA, 0x02, 0x42, 0xDC, 0xA6, 0x62, 0x60, 0x15, 0x2D,
0x81, 0x08, 0x74, 0x9A, 0x0E, 0x09, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0x43, 0x1D, 0xEA, 0x22, 0xB7, 0x2E, 0xD8, 0x3E, 0x59, 0x3A, 0x55, 0x75, 0x09, 0xE7, 0x0A, 0x39, 0xC6, 0x02,
0x6D, 0xFD, 0xE5, 0xF4, 0x5E, 0xEB, 0x85, 0x41, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x10, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x0F, 0x5E,
0xAD, 0x14, 0xB3, 0xBB, 0x01, 0x4E, 0x8A, 0x08, 0x58, 0xFD, 0x00, 0x00, 0x40, 0xC4, 0x49, 0xFE, 0xAF, 0x13, 0x9A, 0xA4, 0x3F, 0xF5, 0xE8, 0xBA, 0x02, 0x02, 0xDC, 0xA6, 0xA2, 0x33, 0xC9, 0x6D,
0x90, 0x08, 0x5A, 0x9A, 0xE3, 0x00, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0x0D, 0xDD, 0x6D, 0xCD, 0xC2, 0x40, 0x3A, 0x97, 0x5C, 0x01, 0x02, 0x3D, 0x12, 0x48, 0x55, 0xDE, 0xBA, 0x35,
0x8E, 0xFB, 0xE1, 0xF2, 0x92, 0xCE, 0x5C, 0xFB, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x14, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x13, 0x5E,
0xAD, 0x14, 0x31, 0xC2, 0x01, 0x0F, 0x8A, 0x08, 0x58, 0x81, 0x00, 0x00, 0x40, 0x44, 0xF0, 0xFF, 0xAF, 0x13, 0x98, 0x87, 0x3F, 0xF7, 0xE8, 0xBA, 0x02, 0xC2, 0xDC, 0xA6, 0x42, 0x50, 0xFF, 0x9B,
0x8B, 0x08, 0x16, 0xF0, 0x21, 0x1C, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0x93, 0x50, 0xE6, 0x06, 0xCF, 0xB8, 0x8C, 0x20, 0xB6, 0x0C, 0x26, 0x4A, 0xC1, 0xC6, 0x7E, 0x22, 0xAC, 0xC6,
0x13, 0x14, 0x27, 0xFF, 0x18, 0xD2, 0xBA, 0xBA, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x1D, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x1C, 0x5E,
0xAD, 0x14, 0x13, 0x8D, 0x01, 0xBC, 0x8A, 0x08, 0x58, 0xFD, 0x00, 0x00, 0x40, 0xC4, 0x8F, 0xFE, 0xAF, 0x13, 0x52, 0xDC, 0x00, 0xF5, 0xE8, 0xBA, 0x02, 0xC2, 0xDC, 0xA6, 0xC2, 0x76, 0x7B, 0x55,
0x91, 0x08, 0x2A, 0xA2, 0xE2, 0x18, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0x0F, 0xB0, 0x0B, 0x57, 0x2E, 0x66, 0x57, 0xE9, 0x32, 0x5E, 0x4E, 0x14, 0x13, 0x5E, 0xFF, 0x22, 0xFA, 0x2A,
0x77, 0xDB, 0x2C, 0xC6, 0xC6, 0xDE, 0x74, 0x97, 0xB5, 0x62, 0x13, 0x80, 0x58, 0x00, 0x05, 0x00, 0x00, 0x1E, 0x15, 0x0C, 0x04, 0x14, 0x1E, 0x03, 0x06, 0x1E, 0xE0, 0x4A, 0x01, 0x03, 0x1D, 0x5E,
0xAD, 0x14, 0x8D, 0x68, 0x01, 0xBB, 0x8A, 0x08, 0x58, 0xFD, 0x00, 0x00, 0x40, 0x44, 0x28, 0xFF, 0xAF, 0x13, 0x5F, 0x5B, 0x00, 0x04, 0xE8, 0xBA, 0x02, 0x42, 0xDC, 0xA6, 0x22, 0x7D, 0x16, 0x76,
0x89, 0x08, 0xDE, 0x80, 0xDF, 0x08, 0x7A, 0x3A, 0x00, 0x00, 0xAA, 0x6C, 0x08, 0x20, 0xE3, 0x37, 0xB1, 0x7F, 0xE8, 0xDA, 0x6C, 0x66, 0x21, 0x07, 0x1F, 0x55, 0x27, 0x27, 0x42, 0x1B, 0x68, 0x58,
0x2E, 0x2E, 0x19, 0xA5, 0xC5, 0xE3, 0xBB, 0x38
};
@@ -0,0 +1,6 @@
//Your WiFi credentials
const char ssid[] = "TRex";
const char password[] = "hasBigTeeth";
//Your AssistNow token
const char myAssistNowToken[] = "58XXXXXXXXXXXXXXXXXXYQ";
@@ -0,0 +1,325 @@
/*
Use ESP32 WiFi to get AssistNow Offline data from u-blox Thingstream
By: SparkFun Electronics / Paul Clark
Date: November 26th, 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 AssistNow Offline data from u-blox Thingstream over WiFi
and push it over I2C to a u-blox module.
The module still needs to be given time assistance to achieve a fast fix. This example
uses network time to do that. If you don't have a WiFi connection, you may have to use
a separate RTC to provide the time.
Note: AssistNow Offline is not supported by the ZED-F9P! "The ZED-F9P supports AssistNow Online only."
You will need to have a token to be able to access Thingstream. See the AssistNow README for more details.
Update secrets.h with your:
- WiFi credentials
- AssistNow token string
Uncomment the "#define USE_MGA_ACKs" below to test the more robust method of using the
UBX_MGA_ACK_DATA0 acknowledgements to confirm that each MGA message has been accepted.
Feel like supporting open source hardware?
Buy a board from SparkFun!
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
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
*/
//#define USE_MGA_ACKs // Uncomment this line to use the UBX_MGA_ACK_DATA0 acknowledgements
#include <WiFi.h>
#include <HTTPClient.h>
#include "secrets.h"
const char assistNowServer[] = "https://offline-live1.services.u-blox.com";
//const char assistNowServer[] = "https://offline-live2.services.u-blox.com"; // Alternate server
const char getQuery[] = "GetOfflineData.ashx?";
const char tokenPrefix[] = "token=";
const char tokenSuffix[] = ";";
const char getGNSS[] = "gnss=gps,glo;"; // GNSS can be: gps,qzss,glo,bds,gal
const char getFormat[] = "format=mga;"; // Data format. Leave set to mga for M8 onwards. Can be aid.
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.
const char getMgaResolution[] = "resolution=1;"; // Optional. Data resolution: 1 = every day; 2 = every other day; 3 = every 3rd day.
//Note: always use resolution=1. findMGAANOForDate does not yet support finding the 'closest' date. It needs an exact match.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include "time.h"
const char* ntpServer = "pool.ntp.org"; // The Network Time Protocol Server
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
delay(1000);
Serial.begin(115200);
Serial.println(F("AssistNow Example"));
while (Serial.available()) Serial.read(); // Empty the serial buffer
Serial.println(F("Press any key to begin..."));
while (!Serial.available()); // Wait for a keypress
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Start I2C. Connect to the GNSS.
Wire.begin(); //Start I2C
if (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."));
while (1);
}
Serial.println(F("u-blox module connected"));
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Connect to WiFi.
Serial.print(F("Connecting to local WiFi"));
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(F("."));
}
Serial.println();
Serial.println(F("WiFi connected!"));
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Set the RTC using network time. (Code taken from the SimpleTime example.)
// Request the time from the NTP server and use it to set the ESP32's RTC.
configTime(0, 0, ntpServer); // Set the GMT and daylight offsets to zero. We need UTC, not local time.
struct tm timeinfo;
if(!getLocalTime(&timeinfo))
{
Serial.println("Failed to obtain time");
}
else
{
Serial.println(&timeinfo, "Time is: %A, %B %d %Y %H:%M:%S");
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Use HTTP GET to receive the AssistNow_Online data
const int URL_BUFFER_SIZE = 256;
char theURL[URL_BUFFER_SIZE]; // This will contain the HTTP URL
int payloadSize = 0; // This will be updated with the length of the data we get from the server
String payload; // This will store the data we get from the server
// Assemble the URL
// Note the slash after the first %s (assistNowServer)
snprintf(theURL, URL_BUFFER_SIZE, "%s/%s%s%s%s%s%s%s%s",
assistNowServer,
getQuery,
tokenPrefix,
myAssistNowToken,
tokenSuffix,
getGNSS,
getFormat,
getPeriod,
getMgaResolution
);
Serial.print(F("HTTP URL is: "));
Serial.println(theURL);
HTTPClient http;
http.begin(theURL);
int httpCode = http.GET(); // HTTP GET
// httpCode will be negative on error
if(httpCode > 0)
{
// HTTP header has been sent and Server response header has been handled
Serial.printf("[HTTP] GET... code: %d\r\n", httpCode);
// If the GET was successful, read the data
if(httpCode == HTTP_CODE_OK) // Check for code 200
{
payloadSize = http.getSize();
Serial.printf("Server returned %d bytes\r\n", payloadSize);
payload = http.getString(); // Get the payload
// Pretty-print the payload as HEX
/*
int i;
for(i = 0; i < payloadSize; i++)
{
if (payload[i] < 0x10) // Print leading zero
Serial.print("0");
Serial.print(payload[i], HEX);
Serial.print(" ");
if ((i % 16) == 15)
Serial.println();
}
if ((i % 16) != 15)
Serial.println();
*/
}
}
else
{
Serial.printf("[HTTP] GET... failed, error: %s\r\n", http.errorToString(httpCode).c_str());
}
http.end();
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Find where the AssistNow data for today starts and ends
size_t todayStart = 0; // Default to sending all the data
size_t tomorrowStart = (size_t)payloadSize;
// Uncomment the next line to enable the 'major' debug messages on Serial so you can see what AssistNow data is being sent
//myGNSS.enableDebugging(Serial, true);
if (payloadSize > 0)
{
if(getLocalTime(&timeinfo))
{
// Find the start of today's data
todayStart = myGNSS.findMGAANOForDate(payload, (size_t)payloadSize, timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday);
if (todayStart < (size_t)payloadSize)
{
Serial.print(F("Found the data for today starting at location "));
Serial.println(todayStart);
}
else
{
Serial.println("Could not find the data for today. This will not work well. The GNSS needs help to start up quickly.");
}
// Find the start of tomorrow's data
tomorrowStart = myGNSS.findMGAANOForDate(payload, (size_t)payloadSize, timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday, 1);
if (tomorrowStart < (size_t)payloadSize)
{
Serial.print(F("Found the data for tomorrow starting at location "));
Serial.println(tomorrowStart);
}
else
{
Serial.println("Could not find the data for tomorrow. (Today's data may be the last?)");
}
}
else
{
Serial.println("Failed to obtain time. This will not work well. The GNSS needs accurate time to start up quickly.");
}
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Push the RTC time to the module
if(getLocalTime(&timeinfo)) // Get the local time again, just to make sure we are using the most accurate time
{
// setUTCTimeAssistance uses a default time accuracy of 2 seconds which should be OK here.
// Have a look at the library source code for more details.
myGNSS.setUTCTimeAssistance(timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
}
else
{
Serial.println("Failed to obtain time. This will not work well. The GNSS needs accurate time to start up quickly.");
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Push the AssistNow data for today to the module - without the time
if (payloadSize > 0)
{
#ifndef USE_MGA_ACKs
// ***** Don't use the UBX_MGA_ACK_DATA0 messages *****
// Push the AssistNow data for today. Don't use UBX_MGA_ACK_DATA0's. Use the default delay of 7ms between messages.
myGNSS.pushAssistNowData(todayStart, true, payload, tomorrowStart - todayStart);
#else
// ***** Use the UBX_MGA_ACK_DATA0 messages *****
// Tell the module to return UBX_MGA_ACK_DATA0 messages when we push the AssistNow data
myGNSS.setAckAiding(1);
// Speed things up by setting setI2CpollingWait to 1ms
myGNSS.setI2CpollingWait(1);
// Push the AssistNow data for today.
myGNSS.pushAssistNowData(todayStart, true, payload, tomorrowStart - todayStart, SFE_UBLOX_MGA_ASSIST_ACK_YES, 100);
// Set setI2CpollingWait to 125ms to avoid pounding the I2C bus
myGNSS.setI2CpollingWait(125);
#endif
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Disconnect the WiFi as it's no longer needed
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
Serial.println(F("WiFi disconnected"));
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void loop()
{
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
byte fixType = myGNSS.getFixType();
Serial.print(F(" Fix: "));
if(fixType == 0) Serial.print(F("No fix"));
else if(fixType == 1) Serial.print(F("Dead reckoning"));
else if(fixType == 2) Serial.print(F("2D"));
else if(fixType == 3) Serial.print(F("3D"));
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
else if(fixType == 5) Serial.print(F("Time only"));
Serial.println();
}
@@ -0,0 +1,6 @@
//Your WiFi credentials
const char ssid[] = "TRex";
const char password[] = "hasBigTeeth";
//Your AssistNow token
const char myAssistNowToken[] = "58XXXXXXXXXXXXXXXXXXYQ";
@@ -0,0 +1,236 @@
/*
Use ESP32 WiFi to get AssistNow Online data from u-blox Thingstream
By: SparkFun Electronics / Paul Clark
Date: November 24th, 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 AssistNow Online data from u-blox Thingstream over WiFi
and push it over I2C to a u-blox module.
You will need to have a token to be able to access Thingstream. See the AssistNow README for more details.
Update secrets.h with your:
- WiFi credentials
- AssistNow token string
Uncomment the "#define USE_MGA_ACKs" below to test the more robust method of using the
UBX_MGA_ACK_DATA0 acknowledgements to confirm that each MGA message has been accepted.
Feel like supporting open source hardware?
Buy a board from SparkFun!
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
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
*/
//#define USE_MGA_ACKs // Uncomment this line to use the UBX_MGA_ACK_DATA0 acknowledgements
#include <WiFi.h>
#include <HTTPClient.h>
#include "secrets.h"
const char assistNowServer[] = "https://online-live1.services.u-blox.com";
//const char assistNowServer[] = "https://online-live2.services.u-blox.com"; // Alternate server
const char getQuery[] = "GetOnlineData.ashx?";
const char tokenPrefix[] = "token=";
const char tokenSuffix[] = ";";
const char getGNSS[] = "gnss=gps,glo;"; // GNSS can be: gps,qzss,glo,bds,gal
const char getDataType[] = "datatype=eph,alm,aux;"; // Data type can be: eph,alm,aux,pos
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
delay(1000);
Serial.begin(115200);
Serial.println(F("AssistNow Example"));
while (Serial.available()) Serial.read(); // Empty the serial buffer
Serial.println(F("Press any key to begin..."));
while (!Serial.available()); // Wait for a keypress
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Start I2C. Connect to the GNSS.
Wire.begin(); //Start I2C
if (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."));
while (1);
}
Serial.println(F("u-blox module connected"));
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Connect to WiFi.
Serial.print(F("Connecting to local WiFi"));
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(F("."));
}
Serial.println();
Serial.println(F("WiFi connected!"));
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Use HTTP GET to receive the AssistNow_Online data
const int URL_BUFFER_SIZE = 256;
char theURL[URL_BUFFER_SIZE]; // This will contain the HTTP URL
int payloadSize = 0; // This will be updated with the length of the data we get from the server
String payload; // This will store the data we get from the server
// Assemble the URL
// Note the slash after the first %s (assistNowServer)
snprintf(theURL, URL_BUFFER_SIZE, "%s/%s%s%s%s%s%s",
assistNowServer,
getQuery,
tokenPrefix,
myAssistNowToken,
tokenSuffix,
getGNSS,
getDataType);
Serial.print(F("HTTP URL is: "));
Serial.println(theURL);
HTTPClient http;
http.begin(theURL);
int httpCode = http.GET(); // HTTP GET
// httpCode will be negative on error
if(httpCode > 0)
{
// HTTP header has been sent and Server response header has been handled
Serial.printf("[HTTP] GET... code: %d\r\n", httpCode);
// If the GET was successful, read the data
if(httpCode == HTTP_CODE_OK) // Check for code 200
{
payloadSize = http.getSize();
Serial.printf("Server returned %d bytes\r\n", payloadSize);
payload = http.getString(); // Get the payload
// Pretty-print the payload as HEX
/*
int i;
for(i = 0; i < payloadSize; i++)
{
if (payload[i] < 0x10) // Print leading zero
Serial.print("0");
Serial.print(payload[i], HEX);
Serial.print(" ");
if ((i % 16) == 15)
Serial.println();
}
if ((i % 16) != 15)
Serial.println();
*/
}
}
else
{
Serial.printf("[HTTP] GET... failed, error: %s\r\n", http.errorToString(httpCode).c_str());
}
http.end();
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Push the AssistNow data to the module
if (payloadSize > 0)
{
// Uncomment the next line to enable the 'major' debug messages on Serial so you can see what AssistNow data is being sent
//myGNSS.enableDebugging(Serial, true);
#ifndef USE_MGA_ACKs
// ***** Don't use the UBX_MGA_ACK_DATA0 messages *****
// Push all the AssistNow data. Don't use UBX_MGA_ACK_DATA0's. Use the default delay of 7ms between messages.
myGNSS.pushAssistNowData(payload, (size_t)payloadSize);
#else
// ***** Use the UBX_MGA_ACK_DATA0 messages *****
// Tell the module to return UBX_MGA_ACK_DATA0 messages when we push the AssistNow data
myGNSS.setAckAiding(1);
// Speed things up by setting setI2CpollingWait to 1ms
myGNSS.setI2CpollingWait(1);
// Push all the AssistNow data.
// We have called setAckAiding(1) to instruct the module to return MGA-ACK messages.
// So, we could set the pushAssistNowData mgaAck parameter to SFE_UBLOX_MGA_ASSIST_ACK_YES.
// But, just for giggles, let's use SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE just to confirm that the
// MGA-ACK messages are actually enabled.
// Wait for up to 100ms for each ACK to arrive! 100ms is a bit excessive... 7ms is nearer the mark.
myGNSS.pushAssistNowData(payload, (size_t)payloadSize, SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE, 100);
// Set setI2CpollingWait to 125ms to avoid pounding the I2C bus
myGNSS.setI2CpollingWait(125);
#endif
}
Serial.println(F("Here we go!"));
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void loop()
{
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
byte fixType = myGNSS.getFixType();
Serial.print(F(" Fix: "));
if(fixType == 0) Serial.print(F("No fix"));
else if(fixType == 1) Serial.print(F("Dead reckoning"));
else if(fixType == 2) Serial.print(F("2D"));
else if(fixType == 3) Serial.print(F("3D"));
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
else if(fixType == 5) Serial.print(F("Time only"));
Serial.println();
}
@@ -0,0 +1,6 @@
//Your WiFi credentials
const char ssid[] = "TRex";
const char password[] = "hasBigTeeth";
//Your AssistNow token
const char myAssistNowToken[] = "58XXXXXXXXXXXXXXXXXXYQ";
@@ -0,0 +1,254 @@
/*
Use ESP32 WiFi to get AssistNow Online data from u-blox Thingstream
By: SparkFun Electronics / Paul Clark
Date: November 24th, 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 AssistNow Online data from u-blox Thingstream over WiFi
and push it over I2C to a u-blox module.
The AssistNow Online data is valid for 2-4 hours, so it can be re-used.
BUT you need to provide the time assistance separately.
This example shows how to do that.
The ESP32's RTC is set from network time.
The RTC time is pushed to the module using setUTCTimeAssistance,
followed by the AssistNow data (without time).
You will need to have a token to be able to access Thingstream. See the AssistNow README for more details.
Update secrets.h with your:
- WiFi credentials
- AssistNow token string
Feel like supporting open source hardware?
Buy a board from SparkFun!
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
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 <HTTPClient.h>
#include "secrets.h"
const char assistNowServer[] = "https://online-live1.services.u-blox.com";
//const char assistNowServer[] = "https://online-live2.services.u-blox.com"; // Alternate server
const char getQuery[] = "GetOnlineData.ashx?";
const char tokenPrefix[] = "token=";
const char tokenSuffix[] = ";";
const char getGNSS[] = "gnss=gps,glo;"; // GNSS can be: gps,qzss,glo,bds,gal
const char getDataType[] = "datatype=eph,alm,aux;"; // Data type can be: eph,alm,aux,pos
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include "time.h"
const char* ntpServer = "pool.ntp.org"; // The Network Time Protocol Server
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
delay(1000);
Serial.begin(115200);
Serial.println(F("AssistNow Example"));
while (Serial.available()) Serial.read(); // Empty the serial buffer
Serial.println(F("Press any key to begin..."));
while (!Serial.available()); // Wait for a keypress
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Start I2C. Connect to the GNSS.
Wire.begin(); //Start I2C
if (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."));
while (1);
}
Serial.println(F("u-blox module connected"));
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Connect to WiFi.
Serial.print(F("Connecting to local WiFi"));
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(F("."));
}
Serial.println();
Serial.println(F("WiFi connected!"));
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Set the RTC using network time. (Code taken from the SimpleTime example.)
// Request the time from the NTP server and use it to set the ESP32's RTC.
configTime(0, 0, ntpServer); // Set the GMT and daylight offsets to zero. We need UTC, not local time.
struct tm timeinfo;
if(!getLocalTime(&timeinfo))
{
Serial.println("Failed to obtain time");
}
else
{
Serial.println(&timeinfo, "Time is: %A, %B %d %Y %H:%M:%S");
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Use HTTP GET to receive the AssistNow_Online data
const int URL_BUFFER_SIZE = 256;
char theURL[URL_BUFFER_SIZE]; // This will contain the HTTP URL
int payloadSize = 0; // This will be updated with the length of the data we get from the server
String payload; // This will store the data we get from the server
// Assemble the URL
// Note the slash after the first %s (assistNowServer)
snprintf(theURL, URL_BUFFER_SIZE, "%s/%s%s%s%s%s%s",
assistNowServer,
getQuery,
tokenPrefix,
myAssistNowToken,
tokenSuffix,
getGNSS,
getDataType);
Serial.print(F("HTTP URL is: "));
Serial.println(theURL);
HTTPClient http;
http.begin(theURL);
int httpCode = http.GET(); // HTTP GET
// httpCode will be negative on error
if(httpCode > 0)
{
// HTTP header has been sent and Server response header has been handled
Serial.printf("[HTTP] GET... code: %d\r\n", httpCode);
// If the GET was successful, read the data
if(httpCode == HTTP_CODE_OK) // Check for code 200
{
payloadSize = http.getSize();
Serial.printf("Server returned %d bytes\r\n", payloadSize);
payload = http.getString(); // Get the payload
// Pretty-print the payload as HEX
/*
int i;
for(i = 0; i < payloadSize; i++)
{
if (payload[i] < 0x10) // Print leading zero
Serial.print("0");
Serial.print(payload[i], HEX);
Serial.print(" ");
if ((i % 16) == 15)
Serial.println();
}
if ((i % 16) != 15)
Serial.println();
*/
}
}
else
{
Serial.printf("[HTTP] GET... failed, error: %s\r\n", http.errorToString(httpCode).c_str());
}
http.end();
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Push the RTC time to the module
// Uncomment the next line to enable the 'major' debug messages on Serial so you can see what AssistNow data is being sent
//myGNSS.enableDebugging(Serial, true);
if(getLocalTime(&timeinfo))
{
// setUTCTimeAssistance uses a default time accuracy of 2 seconds which should be OK here.
// Have a look at the library source code for more details.
myGNSS.setUTCTimeAssistance(timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
}
else
{
Serial.println("Failed to obtain time. This will not work well. The GNSS needs accurate time to start up quickly.");
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Push the AssistNow data to the module - WITHOUT THE TIME
if (payloadSize > 0)
{
// Push the AssistNow data. Don't use UBX_MGA_ACK_DATA0's. Use the default delay of 7ms between messages.
// The 'true' parameter tells pushAssistNowData not to push any time data from the payload.
myGNSS.pushAssistNowData(true, payload, (size_t)payloadSize);
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Disconnect the WiFi as it's no longer needed
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
Serial.println(F("WiFi disconnected"));
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void loop()
{
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
byte fixType = myGNSS.getFixType();
Serial.print(F(" Fix: "));
if(fixType == 0) Serial.print(F("No fix"));
else if(fixType == 1) Serial.print(F("Dead reckoning"));
else if(fixType == 2) Serial.print(F("2D"));
else if(fixType == 3) Serial.print(F("3D"));
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
else if(fixType == 5) Serial.print(F("Time only"));
Serial.println();
}
@@ -0,0 +1,6 @@
//Your WiFi credentials
const char ssid[] = "TRex";
const char password[] = "hasBigTeeth";
//Your AssistNow token
const char myAssistNowToken[] = "58XXXXXXXXXXXXXXXXXXYQ";
@@ -0,0 +1,299 @@
/*
Use ESP32 WiFi to get AssistNow Online data from u-blox Thingstream
By: SparkFun Electronics / Paul Clark
Date: November 24th, 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 AssistNow Online data from u-blox Thingstream over WiFi
and push it over I2C to a u-blox module.
This example shows how to provide initial position assistance. Uncomment #define USE_SERVER_ASSISTANCE
below to include the position in the AssistNow data request, instead of using setPositionAssistanceLLH.
You will need to have a token to be able to access Thingstream. See the AssistNow README for more details.
Update secrets.h with your:
- WiFi credentials
- AssistNow token string
Feel like supporting open source hardware?
Buy a board from SparkFun!
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
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
*/
//#define USE_SERVER_ASSISTANCE // Uncomment this line to include the position in the AssistNow data request
#include <WiFi.h>
#include <HTTPClient.h>
#include "secrets.h"
const char assistNowServer[] = "https://online-live1.services.u-blox.com";
//const char assistNowServer[] = "https://online-live2.services.u-blox.com"; // Alternate server
const char getQuery[] = "GetOnlineData.ashx?";
const char tokenPrefix[] = "token=";
const char tokenSuffix[] = ";";
const char getGNSS[] = "gnss=gps,glo;"; // GNSS can be: gps,qzss,glo,bds,gal
const char getDataType[] = "datatype=eph,alm,aux;"; // Data type can be: eph,alm,aux,pos
#ifdef USE_SERVER_ASSISTANCE
const char useLatitude[] = "lat=55.0;"; // Use an approximate latitude of 55 degrees north. Replace this with your latitude.
const char useLongitude[] = "lon=-1.0;"; // Use an approximate longitude of 1 degree west. Replace this with your longitude.
const char useAlt[] = "alt=100;"; // Use an approximate latitude of 100m above WGS84. Replace this with your altitude.
const char usePosAcc[] = "pacc=100000;"; // Use a position accuracy of 100000m (100km)
#endif
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include "time.h"
const char* ntpServer = "pool.ntp.org"; // The Network Time Protocol Server
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
delay(1000);
Serial.begin(115200);
Serial.println(F("AssistNow Example"));
while (Serial.available()) Serial.read(); // Empty the serial buffer
Serial.println(F("Press any key to begin..."));
while (!Serial.available()); // Wait for a keypress
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Start I2C. Connect to the GNSS.
Wire.begin(); //Start I2C
if (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."));
while (1);
}
Serial.println(F("u-blox module connected"));
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Connect to WiFi.
Serial.print(F("Connecting to local WiFi"));
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(F("."));
}
Serial.println();
Serial.println(F("WiFi connected!"));
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Set the RTC using network time. (Code taken from the SimpleTime example.)
// Request the time from the NTP server and use it to set the ESP32's RTC.
configTime(0, 0, ntpServer); // Set the GMT and daylight offsets to zero. We need UTC, not local time.
struct tm timeinfo;
if(!getLocalTime(&timeinfo))
{
Serial.println("Failed to obtain time");
}
else
{
Serial.println(&timeinfo, "Time is: %A, %B %d %Y %H:%M:%S");
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Use HTTP GET to receive the AssistNow_Online data
const int URL_BUFFER_SIZE = 256;
char theURL[URL_BUFFER_SIZE]; // This will contain the HTTP URL
int payloadSize = 0; // This will be updated with the length of the data we get from the server
String payload; // This will store the data we get from the server
// Assemble the URL
// Note the slash after the first %s (assistNowServer)
#ifdef USE_SERVER_ASSISTANCE
snprintf(theURL, URL_BUFFER_SIZE, "%s/%s%s%s%s%s%s%s%s%s%s",
assistNowServer,
getQuery,
tokenPrefix,
myAssistNowToken,
tokenSuffix,
getGNSS,
getDataType,
useLatitude,
useLongitude,
useAlt,
usePosAcc);
#else
snprintf(theURL, URL_BUFFER_SIZE, "%s/%s%s%s%s%s%s",
assistNowServer,
getQuery,
tokenPrefix,
myAssistNowToken,
tokenSuffix,
getGNSS,
getDataType);
#endif
Serial.print(F("HTTP URL is: "));
Serial.println(theURL);
HTTPClient http;
http.begin(theURL);
int httpCode = http.GET(); // HTTP GET
// httpCode will be negative on error
if(httpCode > 0)
{
// HTTP header has been sent and Server response header has been handled
Serial.printf("[HTTP] GET... code: %d\r\n", httpCode);
// If the GET was successful, read the data
if(httpCode == HTTP_CODE_OK) // Check for code 200
{
payloadSize = http.getSize();
Serial.printf("Server returned %d bytes\r\n", payloadSize);
payload = http.getString(); // Get the payload
// Pretty-print the payload as HEX
/*
int i;
for(i = 0; i < payloadSize; i++)
{
if (payload[i] < 0x10) // Print leading zero
Serial.print("0");
Serial.print(payload[i], HEX);
Serial.print(" ");
if ((i % 16) == 15)
Serial.println();
}
if ((i % 16) != 15)
Serial.println();
*/
}
}
else
{
Serial.printf("[HTTP] GET... failed, error: %s\r\n", http.errorToString(httpCode).c_str());
}
http.end();
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Speed things up by setting setI2CpollingWait to 1ms
myGNSS.setI2CpollingWait(1);
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Tell the module to return UBX_MGA_ACK_DATA0 messages when we push the AssistNow data
myGNSS.setAckAiding(1);
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Push the RTC time to the module
// Uncomment the next line to enable the 'major' debug messages on Serial so you can see what AssistNow data is being sent
//myGNSS.enableDebugging(Serial, true);
if(getLocalTime(&timeinfo))
{
// Provide time assistance. Use the UBX_MGA_ACK_DATA0 acknowledgements. Set tAccS to 2 seconds.
myGNSS.setUTCTimeAssistance(timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, 0, 2, 0, 0, SFE_UBLOX_MGA_ASSIST_ACK_YES, 100);
}
else
{
Serial.println("Failed to obtain time. This will not work well. The GNSS needs accurate time to start up quickly.");
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// If desired - push initial position assistance to the module
#ifndef USE_SERVER_ASSISTANCE
// Use 55 degrees (*10^7) north, 1 degree (*10^7) west, 100m (10000cm) altitude, 100km (10000000cm) accuracy. Replace these with your position.
// The units for lat and lon are degrees * 1e-7 (WGS84)
// The units for alt (WGS84) and posAcc (stddev) are cm.
myGNSS.setPositionAssistanceLLH(550000000, -10000000, 10000, 10000000, SFE_UBLOX_MGA_ASSIST_ACK_YES, 100);
// We could use setPositionAssistanceXYZ instead if needed.
#endif
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Push the AssistNow data to the module - WITHOUT THE TIME
if (payloadSize > 0)
{
// Push the AssistNow data. Use the UBX_MGA_ACK_DATA0 acknowledgements.
// The 'true' parameter tells pushAssistNowData not to push any time data from the payload.
myGNSS.pushAssistNowData(true, payload, (size_t)payloadSize, SFE_UBLOX_MGA_ASSIST_ACK_YES, 100);
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Disconnect the WiFi as it's no longer needed
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
Serial.println(F("WiFi disconnected"));
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Avoid pounding the I2C bus by setting setI2CpollingWait to 125ms
myGNSS.setI2CpollingWait(125);
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void loop()
{
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
byte fixType = myGNSS.getFixType();
Serial.print(F(" Fix: "));
if(fixType == 0) Serial.print(F("No fix"));
else if(fixType == 1) Serial.print(F("Dead reckoning"));
else if(fixType == 2) Serial.print(F("2D"));
else if(fixType == 3) Serial.print(F("3D"));
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
else if(fixType == 5) Serial.print(F("Time only"));
Serial.println();
}
@@ -0,0 +1,6 @@
//Your WiFi credentials
const char ssid[] = "TRex";
const char password[] = "hasBigTeeth";
//Your AssistNow token
const char myAssistNowToken[] = "58XXXXXXXXXXXXXXXXXXYQ";
@@ -0,0 +1,232 @@
/*
Use ESP32 WiFi to get AssistNow Online data from u-blox Thingstream
By: SparkFun Electronics / Paul Clark
Date: November 24th, 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 AssistNow Online data from u-blox Thingstream over WiFi
and push it to a u-blox module using Serial.
You will need to have a token to be able to access Thingstream. See the AssistNow README for more details.
Update secrets.h with your:
- WiFi credentials
- AssistNow token string
Uncomment the "#define USE_MGA_ACKs" below to test the more robust method of using the
UBX_MGA_ACK_DATA0 acknowledgements to confirm that each MGA message has been accepted.
Feel like supporting open source hardware?
Buy a board from SparkFun!
SparkFun Thing Plus - ESP32 WROOM: https://www.sparkfun.com/products/15663
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
SparkFun GPS Breakout - ZOE-M8Q (Qwiic): https://www.sparkfun.com/products/15193
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
*/
//#define USE_MGA_ACKs // Uncomment this line to use the UBX_MGA_ACK_DATA0 acknowledgements
#include <WiFi.h>
#include <HTTPClient.h>
#include "secrets.h"
const char assistNowServer[] = "https://online-live1.services.u-blox.com";
//const char assistNowServer[] = "https://online-live2.services.u-blox.com"; // Alternate server
const char getQuery[] = "GetOnlineData.ashx?";
const char tokenPrefix[] = "token=";
const char tokenSuffix[] = ";";
const char getGNSS[] = "gnss=gps,glo;"; // GNSS can be: gps,qzss,glo,bds,gal
const char getDataType[] = "datatype=eph,alm,aux;"; // Data type can be: eph,alm,aux,pos
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
#define mySerial Serial1 // Use Serial1 to communicate with the GNSS module
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
delay(1000);
Serial.begin(115200);
Serial.println(F("AssistNow Example"));
while (Serial.available()) Serial.read(); // Empty the serial buffer
Serial.println(F("Press any key to begin..."));
while (!Serial.available()); // Wait for a keypress
mySerial.begin(9600); // Use 9600 baud (for u-blox M8)
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Connect to the GNSS.
if (myGNSS.begin(mySerial) == false) //Connect to the Ublox module using mySerial
{
Serial.println(F("u-blox GPS not detected. Please check wiring. Freezing."));
while (1);
}
Serial.println(F("u-blox module connected"));
myGNSS.setUART1Output(COM_TYPE_UBX); //Set the UART port to output UBX only
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Connect to WiFi.
Serial.print(F("Connecting to local WiFi"));
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(F("."));
}
Serial.println();
Serial.println(F("WiFi connected!"));
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Use HTTP GET to receive the AssistNow_Online data
const int URL_BUFFER_SIZE = 256;
char theURL[URL_BUFFER_SIZE]; // This will contain the HTTP URL
int payloadSize = 0; // This will be updated with the length of the data we get from the server
String payload; // This will store the data we get from the server
// Assemble the URL
// Note the slash after the first %s (assistNowServer)
snprintf(theURL, URL_BUFFER_SIZE, "%s/%s%s%s%s%s%s",
assistNowServer,
getQuery,
tokenPrefix,
myAssistNowToken,
tokenSuffix,
getGNSS,
getDataType);
Serial.print(F("HTTP URL is: "));
Serial.println(theURL);
HTTPClient http;
http.begin(theURL);
int httpCode = http.GET(); // HTTP GET
// httpCode will be negative on error
if(httpCode > 0)
{
// HTTP header has been sent and Server response header has been handled
Serial.printf("[HTTP] GET... code: %d\r\n", httpCode);
// If the GET was successful, read the data
if(httpCode == HTTP_CODE_OK) // Check for code 200
{
payloadSize = http.getSize();
Serial.printf("Server returned %d bytes\r\n", payloadSize);
payload = http.getString(); // Get the payload
// Pretty-print the payload as HEX
/*
int i;
for(i = 0; i < payloadSize; i++)
{
if (payload[i] < 0x10) // Print leading zero
Serial.print("0");
Serial.print(payload[i], HEX);
Serial.print(" ");
if ((i % 16) == 15)
Serial.println();
}
if ((i % 16) != 15)
Serial.println();
*/
}
}
else
{
Serial.printf("[HTTP] GET... failed, error: %s\r\n", http.errorToString(httpCode).c_str());
}
http.end();
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Push the AssistNow data to the module
if (payloadSize > 0)
{
// Uncomment the next line to enable the 'major' debug messages on Serial so you can see what AssistNow data is being sent
//myGNSS.enableDebugging(Serial, true);
#ifndef USE_MGA_ACKs
// ***** Don't use the UBX_MGA_ACK_DATA0 messages *****
// Push all the AssistNow data. Don't use UBX_MGA_ACK_DATA0's. Use the default delay of 7ms between messages.
myGNSS.pushAssistNowData(payload, (size_t)payloadSize);
#else
// ***** Use the UBX_MGA_ACK_DATA0 messages *****
// Tell the module to return UBX_MGA_ACK_DATA0 messages when we push the AssistNow data
myGNSS.setAckAiding(1);
// Push all the AssistNow data.
// We have called setAckAiding(1) to instruct the module to return MGA-ACK messages.
// So, we could set the pushAssistNowData mgaAck parameter to SFE_UBLOX_MGA_ASSIST_ACK_YES.
// But, just for giggles, let's use SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE just to confirm that the
// MGA-ACK messages are actually enabled.
// Wait for up to 100ms for each ACK to arrive! 100ms is a bit excessive... 7ms is nearer the mark.
myGNSS.pushAssistNowData(payload, (size_t)payloadSize, SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE, 100);
#endif
}
Serial.println(F("Here we go!"));
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void loop()
{
// Print the UBX-NAV-PVT data so we can see how quickly the fixType goes to 3D
long latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
long longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = myGNSS.getAltitude();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
byte SIV = myGNSS.getSIV();
Serial.print(F(" SIV: "));
Serial.print(SIV);
byte fixType = myGNSS.getFixType();
Serial.print(F(" Fix: "));
if(fixType == 0) Serial.print(F("No fix"));
else if(fixType == 1) Serial.print(F("Dead reckoning"));
else if(fixType == 2) Serial.print(F("2D"));
else if(fixType == 3) Serial.print(F("3D"));
else if(fixType == 4) Serial.print(F("GNSS + Dead reckoning"));
else if(fixType == 5) Serial.print(F("Time only"));
Serial.println();
}
@@ -0,0 +1,6 @@
//Your WiFi credentials
const char ssid[] = "TRex";
const char password[] = "hasBigTeeth";
//Your AssistNow token
const char myAssistNowToken[] = "58XXXXXXXXXXXXXXXXXXYQ";
+222
View File
@@ -0,0 +1,222 @@
# SparkFun u-blox Arduino GNSS Library - AssistNow<sup>TM</sup>
v2.1.0 of the library adds support for u-blox [AssistNow<sup>TM</sup> Assisted GNSS (A-GNSS)](https://www.u-blox.com/en/product/assistnow) which can dramatically reduce the time-to-first-fix.
To use AssistNow Online or AssistNow Offline, you will need a token to access the u-blox Thingstream server. See [below](#AssistNow-Service-Token) for details.
## AssistNow<sup>TM</sup> Online
With AssistNow Online, an Internet connected host downloads assistance data from the u-blox AssistNow Online service to the receiver at system start-up. AssistNow Online data is valid for 2 - 4 hours; beyond that fresh data must be downloaded.
Please see the [AssistNow_Online](./AssistNow_Online) examples for more details. These examples were written for the ESP32, but will run on other platforms too.
The new functions we've added to the library to support AssistNow Online are described [Support for AssistNow below](#Support-for-AssistNow).
## AssistNow<sup>TM</sup> Offline
With the AssistNow Offline service, users can download long-term orbit data over the Internet at their convenience. The orbit data can be stored in the memory of the application processor. The function requires no connectivity at system start-up, enabling a position fix within seconds, even when no network is available. AssistNow Offline offers augmentation for up to 35 days.
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.
**Note: AssistNow Offline is not supported by the ZED-F9P. "The ZED-F9P supports AssistNow Online only."**
The new functions we've added to the library to support AssistNow Offline are described [Support for AssistNow](#Support-for-AssistNow) and [Additional Support for AssistNow Offline](#Additional-Support-for-AssistNow-Offline).
## AssistNow<sup>TM</sup> Autonomous
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.
The benefits of AssistNow Autonomous are:
* Faster fix in situations where GNSS satellite signals are weak
* No connectivity required
* Compatible with AssistNow Online (can work stand-alone, or in tandem with AssistNow Online service)
* No integration effort; calculations are done in the background, transparent to the user
AssistNow Autonomous offers augmentation for up to 6 days.
Please see the [AssistNow_Autonomous](./AssistNow_Autonomous) examples for more details.
**Note: AssistNow Autonomous does not work on the ZED-F9P. "The ZED-F9P supports AssistNow Online only."**
The new functions we've added to the library to support AssistNow Autonomous are described [Support for AssistNow Autonomous below](#Support-for-AssistNow-Autonomous).
## AssistNow Service Token
To be able to use AssistNow Online or AssistNow Offline, you will need a token to access the u-blox Thingstream server.
The following u-blox resources contain useful information:
* [AssistNow - u-blox A-GNSS services](https://www.u-blox.com/en/product/assistnow)
* [AssistNow Product Summary](https://www.u-blox.com/sites/default/files/products/documents/AssistNow_ProductSummary_UBX-13003352.pdf)
* [AssistNow User Guide](https://www.u-blox.com/sites/default/files/products/documents/MultiGNSS-Assistance_UserGuide_%28UBX-13004360%29.pdf)
* [Thingstream Pricing](https://portal.thingstream.io/pricing)
You can apply for a _free_ AssistNow Service Evaluation Token by completing the request form:
* [AssistNow Service evaluation token request form](https://www.u-blox.com/en/assistnow-service-evaluation-token-request-form)
The _free_ AssistNow Developer token entitles you to:
* AssistNow Online Developer: 100K free location requests per month. Capped.
* AssistNow Offline Developer: 20K free location requests per month. Capped.
* CellLocate Developer: 5K free location requests per month. Capped.
The free token will expire after 90 days, but you can continue to use it beyond that by registering it on [Thingstream](https://portal.thingstream.io/).
## Initial Position Assistance
You can further decrease the time-to-first-fix by providing the receiver's approximate position - if known. There are two ways to do this:
* The position can be specified when requesting AssistNow Online data from the server:
* include the key name ```lat``` with the approximate user latitude in WGS 84 expressed in degrees and fractional degrees. Must be in range -90 to 90. Example: ```lat=47.2;```
* include the key name ```lon``` with the approximate user longitude in WGS 84 expressed in degrees and fractional degrees. Must be in range -180 to 180. Example: ```lon=8.55;```
* include the key name ```alt``` with the approximate user altitude above WGS 84 Ellipsoid in meters. If this value is not provided, the server assumes an altitude of 0 meters. Must be in range -1000 to 50000
* include the key name ```pacc``` with the approximate accuracy of submitted position in meters. If this value is not provided, the server assumes an accuracy of 300 km. Must be in range 0 to 6000000
* the position assistance data will then be automatically included in the AssistNow Online data
* Provide initial position assistance data by calling one of:
* <b>bool setPositionAssistanceXYZ(int32_t ecefX, int32_t ecefY, int32_t ecefZ, uint32_t posAcc, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
* The units for ```ecefX/Y/Z``` and ```posAcc``` (stddev) are cm
* <b>bool setPositionAssistanceLLH(int32_t lat, int32_t lon, int32_t alt, uint32_t posAcc, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
* The units for ```lat``` and ```lon``` are degrees * 1e-7 (WGS84). The units for ```alt``` (WGS84) and ```posAcc``` (stddev) are cm (not m)
## Support for AssistNow
```pushAssistNowData``` allows AssistNow Online, Offline or Autonomous data to be pushed to the module. As the ESP32 HTTP GET function returns a ```String```, we've included overloaded functions which allow you to pass the data as a ```String``` or as ```const uint8_t *```.
The String-based function declarations are:
* <b>size_t pushAssistNowData(const String &dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
* <b>size_t pushAssistNowData(bool skipTime, const String &dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
* <b>size_t pushAssistNowData(size_t offset, bool skipTime, const String &dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
The const uint8_t * function declarations are:
* <b>size_t pushAssistNowData(const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
* <b>size_t pushAssistNowData(bool skipTime, const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
* <b>size_t pushAssistNowData(size_t offset, bool skipTime, const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
```dataBytes``` is a pointer to the AssistNow data.
<br>
```numDataBytes``` is the length of the AssistNow data.
<br>
```pushAssistNowData``` pushes individual packets of data to the u-blox module. Sending all of the data contiguously would overload the module, so ```pushAssistNowData``` can either:
* insert a small delay between each packet (the default is 7ms)
* or use the ```UBX-MGA-ACK-DATA0``` acknowledgement message to acknowledge each packet
```mgaAck``` controls which method is used.
* if ```mgaAck``` is ```SFE_UBLOX_MGA_ASSIST_ACK_NO``` (**default**), a delay of ```maxWait``` milliseconds is inserted between each packet. ```maxWait``` defaults to 7ms.
* if ```mgaAck``` is ```SFE_UBLOX_MGA_ASSIST_ACK_YES```, acknowledgement messages will be expected with a _timeout_ of ```maxWait``` milliseconds. The default timeout is again 7ms, but you can change this if required by passing a different value.
* if ```mgaAck``` is ```SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE```, the code will poll the module to enquire if the acknowledgement messages are enabled. If they are, they will be used. If not, a delay is used.
```setAckAiding``` enables or disables the acknowledgement messages. By default they are disabled. ```setAckAiding(1)``` will enable them. ```setAckAiding(0)``` will disable them again.
* <b>bool setAckAiding(uint8_t ackAiding, uint16_t maxWait);</b>
```getAckAiding``` returns 1 if the acknowledgement messages are enabled, 0 if they are disabled. 255 indicates an error or timeout.
* <b>uint8_t getAckAiding(uint16_t maxWait);</b>
```pushAssistNowData``` returns the number of _bytes_ pushed (not the number of _packets_). The return value should be equal to ```numDataBytes``` if all data was valid and pushed successfully.
AssistNow Online data is valid for 2-4 hours. 'Stale' data can be re-used but:
* ```pushAssistNowData``` needs to be told to skip the time information contained in the AssistNow data
* the user needs to provide the module with UTC time separately
The ```skipTime``` parameter tells ```pushAssistNowData``` to skip any time information in the data. ```skipTime``` is bool. Set it to ```true``` to skip the time information.
<br>
UTC time can be pushed to the module first by calling ```setUTCTimeAssistance```:
* <b>bool setUTCTimeAssistance(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, uint32_t nanos, uint16_t tAccS, uint32_t tAccNs, uint8_t source, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);</b>
Only the ```year```, ```month```, ```day```, ```hour```, ```minute``` and ```second``` parameters are mandatory. The others default to sensible values. Again ```mgaAck``` and ```maxWait``` control if a delay is used when configuring the time, or if an acknowledgement message will be expected.
<br>
```nanos``` (nanoseconds), ```tAccS``` (time accuracy estimate (seconds)), ```tAccNs``` (time accuracy estimate (nanoseconds)) and ```source``` (if a clock signal will be provided on EXT_INT) are optional, but are available for advanced users.
<br>
```year``` numbering starts at 0; 2021 is 2021, not 121 (years since 1900). ```month``` and ```day``` numbering starts at 1, not 0.
<br>
Call ```setUTCTimeAssistance``` _before_ ```pushAssistNowData```.
## Additional Support for AssistNow Offline
AssistNow Offline data downloaded from the u-blox server can contain 1-5 weeks of data. However, only the data for _today_ should be pushed the module. Sending data for past or future days will confuse the module.
```findMGAANOForDate``` can be used to find the location of the start of the UBX-MGA-ANO data for the specified date within the offline data. That location can then be passed to ```pushAssistNowData``` using the ```offset``` parameter.
* <b>size_t findMGAANOForDate(const uint8_t *dataBytes, size_t numDataBytes, uint16_t year, uint8_t month, uint8_t day, uint8_t daysIntoFuture);</b>
The sequence of events is:
* call ```findMGAANOForDate``` passing the ```year```, ```month``` and ```day``` for today. ```findMGAANOForDate``` will return the location / offset of the data for today within the offline data.
* call ```findMGAANOForDate``` again passing the ```year```, ```month``` and ```day``` for _today_ but also set ```daysIntoFuture``` to 1. ```findMGAANOForDate``` will then return the location / offset of the data for _tomorrow_ (one day into the future).
* call ```pushAssistNowData``` setting:
* ```offset``` to the location (offset) of today's data within the offline data
* ```skipTime``` to ```true```
* ```numDataBytes``` to ((tomorrow's location) - (today's location)). Only the offline data for today will be pushed.
```findMGAANOForDate``` will return a value of numDataBytes if the data for the chosen day cannot be found.
<br>
Again, call ```setUTCTimeAssistance``` _before_ ```pushAssistNowData```.
## Support for AssistNow Autonomous
AssistNow Autonomous is disabled by default. You can enable it by calling ```setAopCfg``` and check if it is enabled by calling ```getAopCfg```:
* <b>uint8_t getAopCfg(uint16_t maxWait);</b>
* <b>bool SFE_UBLOX_GNSS::setAopCfg(uint8_t aopCfg, uint16_t aopOrbMaxErr, uint16_t maxWait)</b>
```getAopCfg``` will return 1 if AssistNow Autonomous is enabled, 0 if disabled. 255 indicates an error or timeout.
```setAopCfg``` has two parameters:
* set ```aopCfg``` to 1 to enable AssistNow Autonomous, or 0 to disable it
* ```aopOrbMaxErr``` is used to set the 'lifetime' of the AssistNow data. It is recommended to set aopOrbMaxErr to 0 (the default value). This instructs the module to use the firmware default value that corresponds to a default orbit data validity of approximately three days (for GPS satellites observed once) and up to six days (for GPS and GLONASS satellites observed multiple times over a period of at least half a day).
Once AssistNow Autonomous is enabled, you can monitor its status via the ```status``` field in the UBX-NAV-AOPSTATUS message. You can read the ```status``` by calling the helper function ```getAOPSTATUSstatus```. It will return zero when the AssistNow Autonomous data collection is idle. Non-zero values indicate that data collection is in progress. Only power-off the receiver when the subsystem is idle (that is, when the status shows a steady zero).
* <b>uint8_t getAOPSTATUSstatus(uint16_t maxWait);</b>
* <b>uint8_t getAOPSTATUSuseAOP(uint16_t maxWait);</b>
We have included full 'auto' support for UBX-NAV-AOPSTATUS, so you can have the message delivered periodically, add a callback for it, and/or log it to the file buffer:
* <b>bool getAOPSTATUS(uint16_t maxWait);</b>
* <b>bool setAutoAOPSTATUS(bool enabled, uint16_t maxWait);</b>
* <b>bool setAutoAOPSTATUS(bool enabled, bool implicitUpdate, uint16_t maxWait);</b>
* <b>bool setAutoAOPSTATUSrate(uint8_t rate, bool implicitUpdate, uint16_t maxWait);</b>
* <b>bool setAutoAOPSTATUScallback(void (*callbackPointer)(UBX_NAV_AOPSTATUS_data_t), uint16_t maxWait);</b>
* <b>bool assumeAutoAOPSTATUS(bool enabled, bool implicitUpdate);</b>
* <b>void flushAOPSTATUS();</b>
* <b>void logAOPSTATUS(bool enabled);</b>
You can also monitor the AssistNow Autonomous satellite information via the UBX-NAV-SAT message. Again, we have included full 'auto' support for UBX-NAV-SAT. UBX-NAV-SAT contains useful information for each individual satellite which the module has acquired: carrier to noise ratio (signal strength); elevation; azimuth; pseudorange residual; quality indication, health; ephemeris available; almanac available; **AssistNow Offline data availability**; and more. The data can be analyzed using a callback. Please see the AssistNowAutonomous examples for more details.
* <b>bool getNAVSAT(uint16_t maxWait);</b>
* <b>bool setAutoNAVSAT(bool enabled, uint16_t maxWait);</b>
* <b>bool setAutoNAVSAT(bool enabled, bool implicitUpdate, uint16_t maxWait);</b>
* <b>bool setAutoNAVSATrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait);</b>
* <b>bool setAutoNAVSATcallback(void (*callbackPointer)(UBX_NAV_NAVSAT_data_t), uint16_t maxWait);</b>
* <b>bool assumeAutoNAVSAT(bool enabled, bool implicitUpdate);</b>
* <b>void flushNAVSAT();</b>
* <b>void logNAVSAT(bool enabled);</b>
The AssistNow Autonomous data is stored in the module's RAM memory. If that RAM is Battery-Backed - all SparkFun GNSS boards include battery back-up - then the data will be available after the module is powered down and powered back up again. However, you can also read (poll) the navigation database and store the contents in processor memory. ```readNavigationDatabase``` allows you to do that:
* <b>size_t readNavigationDatabase(uint8_t *dataBytes, size_t maxNumDataBytes, uint16_t maxWait);</b>
Data is written to ```dataBytes```. Set ```maxNumDataBytes``` to the (maximum) size of dataBytes. If the database exceeds maxNumDataBytes, the excess bytes will be lost.
```readNavigationDatabase``` returns the number of database bytes written to ```dataBytes```. The return value will be equal to ```maxNumDataBytes``` if excess data was received.
```readNavigationDatabase``` will timeout after ```maxWait``` milliseconds - in case the final UBX-MGA-ACK was missed.
You can then write the database back into the module using ```pushAssistNowData```. Don't forget to call ```setUTCTimeAssistance``` _before_ ```pushAssistNowData```.
Note: UBX-MGA-DBD messages are only intended to be sent back to the same receiver that generated them. They are firmware-specific.
@@ -0,0 +1,123 @@
/*
Get the GPGGA NMEA sentence using getLatestNMEAGPGGA
By: Paul Clark
SparkFun Electronics
Date: January 12th, 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 turn on/off the NMEA sentences being output over I2C.
It then demonstrates how to use the new getLatestNMEAGPGGA function to retrieve the latest GPGGA message.
getLatestNMEAGPGGA returns immediately - it is not blocking.
It returns:
0 if no data is available
1 if the data is valid but is stale (you have read it before)
2 if the data is valid and fresh
If the module is using multiple GNSS constellations, the GGA message will be prefixed with Talker ID "GN" instead of "GP".
The library includes a getLatestNMEAGNGGA function too.
This example shows how to use both functions - and how to change the Talker ID so the GNGGA messages become GPGGA.
This example turns off all sentences except for GGA.
Feel like supporting open source hardware?
Buy a board from SparkFun!
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
NEO-M8P RTK: https://www.sparkfun.com/products/15005
SAM-M8Q: https://www.sparkfun.com/products/15106
Hardware Connections:
Plug a Qwiic cable into the GNSS and a RedBoard
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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
Serial.println(F("SparkFun u-blox GNSS Example"));
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
if (myGNSS.begin() == false)
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
//Disable or enable various NMEA sentences over the I2C interface
myGNSS.setI2COutput(COM_TYPE_NMEA | COM_TYPE_UBX); // Turn on both UBX and NMEA sentences on I2C. (Turn off RTCM and SPARTN)
myGNSS.disableNMEAMessage(UBX_NMEA_GLL, COM_PORT_I2C); // Several of these are on by default on ublox board so let's disable them
myGNSS.disableNMEAMessage(UBX_NMEA_GSA, COM_PORT_I2C);
myGNSS.disableNMEAMessage(UBX_NMEA_GSV, COM_PORT_I2C);
myGNSS.disableNMEAMessage(UBX_NMEA_RMC, COM_PORT_I2C);
myGNSS.disableNMEAMessage(UBX_NMEA_VTG, COM_PORT_I2C);
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C); // Leave only GGA enabled at current navigation rate
// Set the Main Talker ID to "GP". The NMEA GGA messages will be GPGGA instead of GNGGA
myGNSS.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_GP);
//myGNSS.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_DEFAULT); // Uncomment this line to restore the default main talker ID
myGNSS.setHighPrecisionMode(true); // Enable High Precision Mode - include extra decimal places in the GGA messages
//myGNSS.saveConfiguration(VAL_CFG_SUBSEC_IOPORT | VAL_CFG_SUBSEC_MSGCONF); //Optional: Save only the ioPort and message settings to NVM
Serial.println(F("Messages configured"));
//myGNSS.setNMEAOutputPort(Serial); // Uncomment this line to echo all NMEA data to Serial for debugging
}
void loop()
{
// getLatestNMEAGPGGA calls checkUblox for us. We don't need to do it here
NMEA_GGA_data_t data; // Storage for the GPGGA data
uint8_t result = myGNSS.getLatestNMEAGPGGA(&data); // Get the latest GPGGA data (if any)
if (result == 0)
{
Serial.println(F("No GPGGA data available"));
}
else if (result == 1)
{
Serial.println(F("GPGGA data is available but is stale"));
}
else // if (result == 2)
{
// Data contains .length and .nmea
Serial.print(F("Latest GPGGA: Length: "));
Serial.print(data.length);
Serial.print(F("\tData: "));
Serial.println((const char *)data.nmea); // .nmea is printable (NULL-terminated)
}
result = myGNSS.getLatestNMEAGNGGA(&data); // Get the latest GNGGA data (if any)
if (result == 0)
{
Serial.println(F("No GNGGA data available"));
}
else if (result == 1)
{
Serial.println(F("GNGGA data is available but is stale"));
}
else // if (result == 2)
{
// Data contains .length and .nmea
Serial.print(F("Latest GNGGA: Length: "));
Serial.print(data.length);
Serial.print(F("\tData: "));
Serial.println((const char *)data.nmea); // .nmea is printable (NULL-terminated)
}
delay(250);
}
@@ -0,0 +1,117 @@
/*
Get the latest GPGGA / GNGGA NMEA sentence using callbacks
By: Paul Clark
SparkFun Electronics
Date: January 12th, 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 turn on/off the NMEA sentences being output over I2C.
It then demonstrates how to get the latest GPGGA or GNGGA message autonomously using callbacks.
If the module is using multiple GNSS constellations, the GGA message will be prefixed with Talker ID "GN" instead of "GP".
This example shows how to change the Talker ID so the GNGGA messages become GPGGA.
It also shows how to enable "high precision mode" to include extra decimal places in the GGA messages.
This example turns off all sentences except for GGA.
Feel like supporting open source hardware?
Buy a board from SparkFun!
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
NEO-M8P RTK: https://www.sparkfun.com/products/15005
SAM-M8Q: https://www.sparkfun.com/products/15106
Hardware Connections:
Plug a Qwiic cable into the GNSS and a RedBoard
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 <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
// Callback: printGPGGA will be called when new GPGGA NMEA data arrives
// See u-blox_structs.h for the full definition of NMEA_GGA_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGPGGAcallback
// / _____ This _must_ be NMEA_GGA_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printGPGGA(NMEA_GGA_data_t *nmeaData)
{
Serial.print(F("\r\nGPGGA: Length: "));
Serial.print(nmeaData->length);
Serial.print(F("\tData: "));
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
}
// Callback: printGNGGA will be called if new GNGGA NMEA data arrives
// See u-blox_structs.h for the full definition of NMEA_GGA_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGNGGAcallback
// / _____ This _must_ be NMEA_GGA_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printGNGGA(NMEA_GGA_data_t *nmeaData)
{
Serial.print(F("\r\nGNGGA: Length: "));
Serial.print(nmeaData->length);
Serial.print(F("\tData: "));
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
}
void setup()
{
Serial.begin(115200);
Serial.println(F("SparkFun u-blox GNSS Example"));
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable debug messages on Serial
if (myGNSS.begin() == false)
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
// Disable or enable various NMEA sentences over the I2C interface
myGNSS.setI2COutput(COM_TYPE_NMEA | COM_TYPE_UBX); // Turn on both UBX and NMEA sentences on I2C. (Turn off RTCM and SPARTN)
myGNSS.disableNMEAMessage(UBX_NMEA_GLL, COM_PORT_I2C); // Several of these are on by default on ublox board so let's disable them
myGNSS.disableNMEAMessage(UBX_NMEA_GSA, COM_PORT_I2C);
myGNSS.disableNMEAMessage(UBX_NMEA_GSV, COM_PORT_I2C);
myGNSS.disableNMEAMessage(UBX_NMEA_RMC, COM_PORT_I2C);
myGNSS.disableNMEAMessage(UBX_NMEA_VTG, COM_PORT_I2C);
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C); // Leave only GGA enabled at current navigation rate
// Set the Main Talker ID to "GP". The NMEA GGA messages will be GPGGA instead of GNGGA
myGNSS.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_GP);
//myGNSS.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_DEFAULT); // Uncomment this line to restore the default main talker ID
myGNSS.setHighPrecisionMode(true); // Enable High Precision Mode - include extra decimal places in the GGA messages
//myGNSS.saveConfiguration(VAL_CFG_SUBSEC_IOPORT | VAL_CFG_SUBSEC_MSGCONF); //Optional: Save only the ioPort and message settings to NVM
Serial.println(F("Messages configured"));
//myGNSS.setNMEAOutputPort(Serial); // Uncomment this line to echo all NMEA data to Serial for debugging
// Set up the callback for GPGGA
myGNSS.setNMEAGPGGAcallbackPtr(&printGPGGA);
// Set up the callback for GNGGA
myGNSS.setNMEAGNGGAcallbackPtr(&printGNGGA);
}
void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
Serial.print(".");
delay(50);
}
@@ -33,38 +33,38 @@ SFE_UBLOX_GNSS myGNSS;
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printPVTdata(UBX_NAV_PVT_data_t ubxDataStruct)
void printPVTdata(UBX_NAV_PVT_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("Time: ")); // Print the time
uint8_t hms = ubxDataStruct.hour; // Print the hours
uint8_t hms = ubxDataStruct->hour; // Print the hours
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
Serial.print(hms);
Serial.print(F(":"));
hms = ubxDataStruct.min; // Print the minutes
hms = ubxDataStruct->min; // Print the minutes
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
Serial.print(hms);
Serial.print(F(":"));
hms = ubxDataStruct.sec; // Print the seconds
hms = ubxDataStruct->sec; // Print the seconds
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
Serial.print(hms);
Serial.print(F("."));
unsigned long millisecs = ubxDataStruct.iTOW % 1000; // Print the milliseconds
unsigned long millisecs = ubxDataStruct->iTOW % 1000; // Print the milliseconds
if (millisecs < 100) Serial.print(F("0")); // Print the trailing zeros correctly
if (millisecs < 10) Serial.print(F("0"));
Serial.print(millisecs);
long latitude = ubxDataStruct.lat; // Print the latitude
long latitude = ubxDataStruct->lat; // Print the latitude
Serial.print(F(" Lat: "));
Serial.print(latitude);
long longitude = ubxDataStruct.lon; // Print the longitude
long longitude = ubxDataStruct->lon; // Print the longitude
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = ubxDataStruct.hMSL; // Print the height above mean sea level
long altitude = ubxDataStruct->hMSL; // Print the height above mean sea level
Serial.print(F(" Height above MSL: "));
Serial.print(altitude);
Serial.println(F(" (mm)"));
@@ -91,7 +91,7 @@ void setup()
myGNSS.setNavigationFrequency(2); //Produce two solutions per second
myGNSS.setAutoPVTcallback(&printPVTdata); // Enable automatic NAV PVT messages with callback to printPVTdata
myGNSS.setAutoPVTcallbackPtr(&printPVTdata); // Enable automatic NAV PVT messages with callback to printPVTdata
}
void loop()
@@ -33,22 +33,22 @@ SFE_UBLOX_GNSS myGNSS;
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printODOdata(UBX_NAV_ODO_data_t ubxDataStruct)
void printODOdata(UBX_NAV_ODO_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("TOW: ")); // Print the Time Of Week
unsigned long iTOW = ubxDataStruct.iTOW; // iTOW is in milliseconds
unsigned long iTOW = ubxDataStruct->iTOW; // iTOW is in milliseconds
Serial.print(iTOW);
Serial.print(F(" (ms)"));
Serial.print(F(" Distance: "));
unsigned long distance = ubxDataStruct.distance; // Print the distance
unsigned long distance = ubxDataStruct->distance; // Print the distance
Serial.print(distance);
Serial.print(F(" (m)"));
Serial.print(F(" Total Distance: "));
unsigned long totalDistance = ubxDataStruct.totalDistance; // Print the total distance
unsigned long totalDistance = ubxDataStruct->totalDistance; // Print the total distance
Serial.print(totalDistance);
Serial.println(F(" (m)"));
}
@@ -76,7 +76,7 @@ void setup()
//myGNSS.resetOdometer(); //Uncomment this line to reset the odometer
myGNSS.setAutoNAVODOcallback(&printODOdata); // Enable automatic NAV ODO messages with callback to printODOdata
myGNSS.setAutoNAVODOcallbackPtr(&printODOdata); // Enable automatic NAV ODO messages with callback to printODOdata
}
void loop()
@@ -48,30 +48,30 @@ int dotsPrinted = 0; // Print dots in rows of 50 while waiting for a TIM TM2 mes
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printTIMTM2data(UBX_TIM_TM2_data_t ubxDataStruct)
void printTIMTM2data(UBX_TIM_TM2_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("newFallingEdge: ")); // 1 if a new falling edge was detected
Serial.print(ubxDataStruct.flags.bits.newFallingEdge);
Serial.print(ubxDataStruct->flags.bits.newFallingEdge);
Serial.print(F(" newRisingEdge: ")); // 1 if a new rising edge was detected
Serial.print(ubxDataStruct.flags.bits.newRisingEdge);
Serial.print(ubxDataStruct->flags.bits.newRisingEdge);
Serial.print(F(" Rising Edge Counter: ")); // Rising edge counter
Serial.print(ubxDataStruct.count);
Serial.print(ubxDataStruct->count);
Serial.print(F(" towMsR: ")); // Time Of Week of rising edge (ms)
Serial.print(ubxDataStruct.towMsR);
Serial.print(ubxDataStruct->towMsR);
Serial.print(F(" towSubMsR: ")); // Millisecond fraction of Time Of Week of rising edge in nanoseconds
Serial.print(ubxDataStruct.towSubMsR);
Serial.print(ubxDataStruct->towSubMsR);
Serial.print(F(" towMsF: ")); // Time Of Week of falling edge (ms)
Serial.print(ubxDataStruct.towMsF);
Serial.print(ubxDataStruct->towMsF);
Serial.print(F(" towSubMsF: ")); // Millisecond fraction of Time Of Week of falling edge in nanoseconds
Serial.println(ubxDataStruct.towSubMsF);
Serial.println(ubxDataStruct->towSubMsF);
dotsPrinted = 0; // Reset dotsPrinted
}
@@ -97,7 +97,7 @@ void setup()
myGNSS.setNavigationFrequency(1); //Produce one solution per second
myGNSS.setAutoTIMTM2callback(&printTIMTM2data); // Enable automatic TIM TM2 messages with callback to printTIMTM2data
myGNSS.setAutoTIMTM2callbackPtr(&printTIMTM2data); // Enable automatic TIM TM2 messages with callback to printTIMTM2data
}
void loop()
@@ -38,39 +38,39 @@ SFE_UBLOX_GNSS myGNSS;
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printHNRATTdata(UBX_HNR_ATT_data_t ubxDataStruct)
void printHNRATTdata(UBX_HNR_ATT_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("Roll: ")); // Print selected data
Serial.print((float)ubxDataStruct.roll / 100000.0, 2); // Convert roll to degrees
Serial.print((float)ubxDataStruct->roll / 100000.0, 2); // Convert roll to degrees
Serial.print(F(" Pitch: "));
Serial.print((float)ubxDataStruct.pitch / 100000.0, 2); // Convert pitch to degrees
Serial.print((float)ubxDataStruct->pitch / 100000.0, 2); // Convert pitch to degrees
Serial.print(F(" Heading: "));
Serial.println((float)ubxDataStruct.heading / 100000.0, 2); // Convert heading to degrees
Serial.println((float)ubxDataStruct->heading / 100000.0, 2); // Convert heading to degrees
}
// Callback: printHNRINSdata will be called when new HNR INS data arrives
// See u-blox_structs.h for the full definition of UBX_HNR_INS_data_t
void printHNRINSdata(UBX_HNR_INS_data_t ubxDataStruct)
void printHNRINSdata(UBX_HNR_INS_data_t *ubxDataStruct)
{
Serial.print(F("xAccel: ")); // Print selected data
Serial.print(ubxDataStruct.xAccel);
Serial.print(ubxDataStruct->xAccel);
Serial.print(F(" yAccel: "));
Serial.print(ubxDataStruct.yAccel);
Serial.print(ubxDataStruct->yAccel);
Serial.print(F(" zAccel: "));
Serial.println(ubxDataStruct.zAccel);
Serial.println(ubxDataStruct->zAccel);
}
// Callback: printHNRPVTdata will be called when new HNR PVT data arrives
// See u-blox_structs.h for the full definition of UBX_HNR_PVT_data_t
void printHNRPVTdata(UBX_HNR_PVT_data_t ubxDataStruct)
void printHNRPVTdata(UBX_HNR_PVT_data_t *ubxDataStruct)
{
Serial.print(F("ns: ")); // Print selected data
Serial.print(ubxDataStruct.nano);
Serial.print(ubxDataStruct->nano);
Serial.print(F(" Lat: "));
Serial.print(ubxDataStruct.lat);
Serial.print(ubxDataStruct->lat);
Serial.print(F(" Lon: "));
Serial.println(ubxDataStruct.lon);
Serial.println(ubxDataStruct->lon);
}
void setup()
@@ -97,13 +97,13 @@ void setup()
else
Serial.println(F("setHNRNavigationRate was NOT successful"));
if (myGNSS.setAutoHNRATTcallback(&printHNRATTdata) == true) // Enable automatic HNR ATT messages with callback to printHNRATTdata
if (myGNSS.setAutoHNRATTcallbackPtr(&printHNRATTdata) == true) // Enable automatic HNR ATT messages with callback to printHNRATTdata
Serial.println(F("setAutoHNRATTcallback successful"));
if (myGNSS.setAutoHNRINScallback(&printHNRINSdata) == true) // Enable automatic HNR INS messages with callback to printHNRINSdata
if (myGNSS.setAutoHNRINScallbackPtr(&printHNRINSdata) == true) // Enable automatic HNR INS messages with callback to printHNRINSdata
Serial.println(F("setAutoHNRINScallback successful"));
if (myGNSS.setAutoHNRPVTcallback(&printHNRPVTdata) == true) // Enable automatic HNR PVT messages with callback to printHNRPVTdata
if (myGNSS.setAutoHNRPVTcallbackPtr(&printHNRPVTdata) == true) // Enable automatic HNR PVT messages with callback to printHNRPVTdata
Serial.println(F("setAutoHNRPVTcallback successful"));
}
@@ -35,39 +35,39 @@ SFE_UBLOX_GNSS myGNSS;
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printESFALGdata(UBX_ESF_ALG_data_t ubxDataStruct)
void printESFALGdata(UBX_ESF_ALG_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("TOW: ")); // Print the Time Of Week
unsigned long iTOW = ubxDataStruct.iTOW; // iTOW is in milliseconds
unsigned long iTOW = ubxDataStruct->iTOW; // iTOW is in milliseconds
Serial.print(iTOW);
Serial.print(F(" (ms)"));
Serial.print(F(" Roll: ")); // Print selected data
Serial.print((float)ubxDataStruct.roll / 100.0, 2); // Convert roll to degrees
Serial.print((float)ubxDataStruct->roll / 100.0, 2); // Convert roll to degrees
Serial.print(F(" Pitch: "));
Serial.print((float)ubxDataStruct.pitch / 100.0, 2); // Convert pitch to degrees
Serial.print((float)ubxDataStruct->pitch / 100.0, 2); // Convert pitch to degrees
Serial.print(F(" Yaw: "));
Serial.print((float)ubxDataStruct.yaw / 100.0, 2); // Convert yaw to degrees
Serial.print((float)ubxDataStruct->yaw / 100.0, 2); // Convert yaw to degrees
Serial.println(F(" (Degrees)"));
}
// Callback: printESFINSdata will be called when new ESF INS data arrives
// See u-blox_structs.h for the full definition of UBX_ESF_INS_data_t
void printESFINSdata(UBX_ESF_INS_data_t ubxDataStruct)
void printESFINSdata(UBX_ESF_INS_data_t *ubxDataStruct)
{
Serial.print(F("xAccel: ")); // Print selected data
Serial.print(ubxDataStruct.xAccel);
Serial.print(ubxDataStruct->xAccel);
Serial.print(F(" yAccel: "));
Serial.print(ubxDataStruct.yAccel);
Serial.print(ubxDataStruct->yAccel);
Serial.print(F(" zAccel: "));
Serial.print(ubxDataStruct.zAccel);
Serial.print(ubxDataStruct->zAccel);
Serial.println(F(" (m/s^2)"));
}
@@ -75,23 +75,23 @@ void printESFINSdata(UBX_ESF_INS_data_t ubxDataStruct)
// Callback: printESFMEASdata will be called when new ESF MEAS data arrives
// See u-blox_structs.h for the full definition of UBX_ESF_MEAS_data_t
// and UBX_ESF_MEAS_sensorData_t
void printESFMEASdata(UBX_ESF_MEAS_data_t ubxDataStruct)
void printESFMEASdata(UBX_ESF_MEAS_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("id: ")); // Print selected data
Serial.print(ubxDataStruct.id);
Serial.print(ubxDataStruct->id);
Serial.print(F(" numMeas: "));
Serial.println(ubxDataStruct.flags.bits.numMeas);
Serial.println(ubxDataStruct->flags.bits.numMeas);
for (uint8_t num = 0; num < ubxDataStruct.flags.bits.numMeas; num++) // For each sensor
for (uint8_t num = 0; num < ubxDataStruct->flags.bits.numMeas; num++) // For each sensor
{
Serial.print(F("Sensor "));
Serial.print(num);
UBX_ESF_MEAS_sensorData_t sensorData;
myGNSS.getSensorFusionMeasurement(&sensorData, ubxDataStruct, num); // Extract the data for one sensor
myGNSS.getSensorFusionMeasurement(&sensorData, *ubxDataStruct, num); // Extract the data for one sensor
Serial.print(F(": Type: "));
Serial.print(sensorData.data.bits.dataType);
@@ -103,21 +103,21 @@ void printESFMEASdata(UBX_ESF_MEAS_data_t ubxDataStruct)
// Callback: printESFSTATUSdata will be called when new ESF STATUS data arrives
// See u-blox_structs.h for the full definition of UBX_ESF_STATUS_data_t
// and UBX_ESF_STATUS_sensorStatus_t
void printESFSTATUSdata(UBX_ESF_STATUS_data_t ubxDataStruct)
void printESFSTATUSdata(UBX_ESF_STATUS_data_t *ubxDataStruct)
{
Serial.print(F("fusionMode: ")); // Print selected data
Serial.print(ubxDataStruct.fusionMode);
Serial.print(ubxDataStruct->fusionMode);
Serial.print(F(" numSens: "));
Serial.println(ubxDataStruct.numSens);
Serial.println(ubxDataStruct->numSens);
for (uint8_t num = 0; num < ubxDataStruct.numSens; num++) // For each sensor
for (uint8_t num = 0; num < ubxDataStruct->numSens; num++) // For each sensor
{
Serial.print(F("Sensor "));
Serial.print(num);
UBX_ESF_STATUS_sensorStatus_t sensorStatus;
myGNSS.getSensorFusionStatus(&sensorStatus, ubxDataStruct, num); // Extract the data for one sensor
myGNSS.getSensorFusionStatus(&sensorStatus, *ubxDataStruct, num); // Extract the data for one sensor
Serial.print(F(": Type: "));
Serial.print(sensorStatus.sensStatus1.bits.type);
@@ -156,16 +156,16 @@ void setup()
myGNSS.setI2CpollingWait(50); //Allow checkUblox to poll I2C data every 50ms to keep up with the ESF MEAS messages
if (myGNSS.setAutoESFALGcallback(&printESFALGdata) == true) // Enable automatic ESF ALG messages with callback to printESFALGdata
if (myGNSS.setAutoESFALGcallbackPtr(&printESFALGdata) == true) // Enable automatic ESF ALG messages with callback to printESFALGdata
Serial.println(F("setAutoESFALGcallback successful"));
if (myGNSS.setAutoESFINScallback(&printESFINSdata) == true) // Enable automatic ESF INS messages with callback to printESFINSdata
if (myGNSS.setAutoESFINScallbackPtr(&printESFINSdata) == true) // Enable automatic ESF INS messages with callback to printESFINSdata
Serial.println(F("setAutoESFINScallback successful"));
if (myGNSS.setAutoESFMEAScallback(&printESFMEASdata) == true) // Enable automatic ESF MEAS messages with callback to printESFMEASdata
if (myGNSS.setAutoESFMEAScallbackPtr(&printESFMEASdata) == true) // Enable automatic ESF MEAS messages with callback to printESFMEASdata
Serial.println(F("setAutoESFMEAScallback successful"));
if (myGNSS.setAutoESFSTATUScallback(&printESFSTATUSdata) == true) // Enable automatic ESF STATUS messages with callback to printESFSTATUSdata
if (myGNSS.setAutoESFSTATUScallbackPtr(&printESFSTATUSdata) == true) // Enable automatic ESF STATUS messages with callback to printESFSTATUSdata
Serial.println(F("setAutoESFSTATUScallback successful"));
}
@@ -31,38 +31,38 @@ SFE_UBLOX_GNSS myGNSS;
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void newRAWX(UBX_RXM_RAWX_data_t ubxDataStruct)
void newRAWX(UBX_RXM_RAWX_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("New RAWX data received. It contains "));
Serial.print(ubxDataStruct.header.numMeas); // Print numMeas (Number of measurements / blocks)
Serial.print(ubxDataStruct->header.numMeas); // Print numMeas (Number of measurements / blocks)
Serial.println(F(" data blocks:"));
for (uint8_t block = 0; block < ubxDataStruct.header.numMeas; block++) // For each block
for (uint8_t block = 0; block < ubxDataStruct->header.numMeas; block++) // For each block
{
Serial.print(F("GNSS ID: "));
if (ubxDataStruct.blocks[block].gnssId < 100) Serial.print(F(" ")); // Align the gnssId
if (ubxDataStruct.blocks[block].gnssId < 10) Serial.print(F(" ")); // Align the gnssId
Serial.print(ubxDataStruct.blocks[block].gnssId);
if (ubxDataStruct->blocks[block].gnssId < 100) Serial.print(F(" ")); // Align the gnssId
if (ubxDataStruct->blocks[block].gnssId < 10) Serial.print(F(" ")); // Align the gnssId
Serial.print(ubxDataStruct->blocks[block].gnssId);
Serial.print(F(" SV ID: "));
if (ubxDataStruct.blocks[block].svId < 100) Serial.print(F(" ")); // Align the svId
if (ubxDataStruct.blocks[block].svId < 10) Serial.print(F(" ")); // Align the svId
Serial.print(ubxDataStruct.blocks[block].svId);
if (ubxDataStruct->blocks[block].svId < 100) Serial.print(F(" ")); // Align the svId
if (ubxDataStruct->blocks[block].svId < 10) Serial.print(F(" ")); // Align the svId
Serial.print(ubxDataStruct->blocks[block].svId);
if (sizeof(double) == 8) // Check if our processor supports 64-bit double
{
// Convert prMes from uint8_t[8] to 64-bit double
// prMes is little-endian
double pseudorange;
memcpy(&pseudorange, &ubxDataStruct.blocks[block].prMes, 8);
memcpy(&pseudorange, &ubxDataStruct->blocks[block].prMes, 8);
Serial.print(F(" PR: "));
Serial.print(pseudorange, 3);
// Convert cpMes from uint8_t[8] to 64-bit double
// cpMes is little-endian
double carrierPhase;
memcpy(&carrierPhase, &ubxDataStruct.blocks[block].cpMes, 8);
memcpy(&carrierPhase, &ubxDataStruct->blocks[block].cpMes, 8);
Serial.print(F(" m CP: "));
Serial.print(carrierPhase, 3);
Serial.print(F(" cycles"));
@@ -94,7 +94,7 @@ void setup()
myGNSS.setNavigationFrequency(1); //Produce one solution per second (RAWX produces a _lot_ of data!)
myGNSS.setAutoRXMRAWXcallback(&newRAWX); // Enable automatic RXM RAWX messages with callback to newRAWX
myGNSS.setAutoRXMRAWXcallbackPtr(&newRAWX); // Enable automatic RXM RAWX messages with callback to newRAWX
}
void loop()
@@ -0,0 +1,121 @@
/*
Configuring the GNSS to automatically send NAV SAT reports over I2C and display them using a callback
By: Paul Clark
SparkFun Electronics
Date: December 1st, 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 configure the u-blox GNSS to send NAV SAT reports automatically
and access the data via a callback. No more polling!
Feel like supporting open source hardware?
Buy a board from SparkFun!
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
Hardware Connections:
Plug a Qwiic cable into the GPS and a BlackBoard
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 <Wire.h> //Needed for I2C to GPS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
// Callback: newNAVSAT will be called when new NAV SAT data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_SAT_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoNAVSATcallback
// / _____ This _must_ be UBX_NAV_SAT_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void newNAVSAT(UBX_NAV_SAT_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("New NAV SAT data received. It contains data for "));
Serial.print(ubxDataStruct->header.numSvs);
if (ubxDataStruct->header.numSvs == 1)
Serial.println(F(" SV."));
else
Serial.println(F(" SVs."));
// Just for giggles, print the signal strength for each SV as a barchart
for (uint16_t block = 0; block < ubxDataStruct->header.numSvs; block++) // For each SV
{
switch (ubxDataStruct->blocks[block].gnssId) // Print the GNSS ID
{
case 0:
Serial.print(F("GPS "));
break;
case 1:
Serial.print(F("SBAS "));
break;
case 2:
Serial.print(F("Galileo "));
break;
case 3:
Serial.print(F("BeiDou "));
break;
case 4:
Serial.print(F("IMES "));
break;
case 5:
Serial.print(F("QZSS "));
break;
case 6:
Serial.print(F("GLONASS "));
break;
default:
Serial.print(F("UNKNOWN "));
break;
}
Serial.print(ubxDataStruct->blocks[block].svId); // Print the SV ID
if (ubxDataStruct->blocks[block].svId < 10) Serial.print(F(" "));
else if (ubxDataStruct->blocks[block].svId < 100) Serial.print(F(" "));
else Serial.print(F(" "));
// Print the signal strength as a bar chart
for (uint8_t cno = 0; cno < ubxDataStruct->blocks[block].cno; cno++)
Serial.print(F("="));
Serial.println();
}
}
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println("SparkFun u-blox Example");
Wire.begin();
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
myGNSS.setNavigationFrequency(1); //Produce one solution per second
myGNSS.setAutoNAVSATcallbackPtr(&newNAVSAT); // Enable automatic NAV SAT messages with callback to newNAVSAT
}
void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
Serial.print(".");
delay(50);
}
@@ -22,9 +22,7 @@
Insert a formatted micro-SD card into the socket on the Carrier Board.
Connect the Carrier Board to your computer using a USB-C cable.
Ensure you have the SparkFun Apollo3 boards installed: http://boardsmanager/All#SparkFun_Apollo3
This code has been tested using version 2.1.0 of the Apollo3 boards on Arduino IDE 1.8.13.
- Version 2.1.1 of Apollo3 contains a feature which makes I2C communication with u-blox modules problematic
- We recommend using v2.1.0 of Apollo3 until v2.2.0 is released
This code has been tested using version 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
Select "Artemis MicroMod Processor" as the board type.
Press upload to upload the code onto the Artemis.
Open the Serial Monitor at 115200 baud to see the output.
@@ -69,6 +67,7 @@ File myFile; //File that all GNSS data is written to
#endif
#define packetLength 100 // NAV PVT is 92 + 8 bytes in length (including the sync chars, class, id, length and checksum bytes)
uint8_t *myBuffer; // Use myBuffer to hold the data while we write it to SD card
// Callback: printPVTdata will be called when new NAV PVT data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_PVT_data_t
@@ -77,38 +76,38 @@ File myFile; //File that all GNSS data is written to
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printPVTdata(UBX_NAV_PVT_data_t ubxDataStruct)
void printPVTdata(UBX_NAV_PVT_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("Time: ")); // Print the time
uint8_t hms = ubxDataStruct.hour; // Print the hours
uint8_t hms = ubxDataStruct->hour; // Print the hours
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
Serial.print(hms);
Serial.print(F(":"));
hms = ubxDataStruct.min; // Print the minutes
hms = ubxDataStruct->min; // Print the minutes
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
Serial.print(hms);
Serial.print(F(":"));
hms = ubxDataStruct.sec; // Print the seconds
hms = ubxDataStruct->sec; // Print the seconds
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
Serial.print(hms);
Serial.print(F("."));
unsigned long millisecs = ubxDataStruct.iTOW % 1000; // Print the milliseconds
unsigned long millisecs = ubxDataStruct->iTOW % 1000; // Print the milliseconds
if (millisecs < 100) Serial.print(F("0")); // Print the trailing zeros correctly
if (millisecs < 10) Serial.print(F("0"));
Serial.print(millisecs);
long latitude = ubxDataStruct.lat; // Print the latitude
long latitude = ubxDataStruct->lat; // Print the latitude
Serial.print(F(" Lat: "));
Serial.print(latitude);
long longitude = ubxDataStruct.lon; // Print the longitude
long longitude = ubxDataStruct->lon; // Print the longitude
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = ubxDataStruct.hMSL; // Print the height above mean sea level
long altitude = ubxDataStruct->hMSL; // Print the height above mean sea level
Serial.print(F(" Height above MSL: "));
Serial.print(altitude);
Serial.println(F(" (mm)"));
@@ -200,10 +199,12 @@ void setup()
myGNSS.setNavigationFrequency(1); //Produce one navigation solution per second
myGNSS.setAutoPVTcallback(&printPVTdata); // Enable automatic NAV PVT messages with callback to printPVTdata
myGNSS.setAutoPVTcallbackPtr(&printPVTdata); // Enable automatic NAV PVT messages with callback to printPVTdata
myGNSS.logNAVPVT(); // Enable NAV PVT data logging
myBuffer = new uint8_t[packetLength]; // Create our own buffer to hold the data while we write it to SD card
Serial.println(F("Press any key to stop logging."));
}
@@ -214,9 +215,7 @@ void loop()
if (myGNSS.fileBufferAvailable() >= packetLength) // Check to see if a new packetLength-byte NAV PVT message has been stored
{
uint8_t myBuffer[packetLength]; // Create our own buffer to hold the data while we write it to SD card
myGNSS.extractFileBufferData((uint8_t *)&myBuffer, packetLength); // Extract exactly packetLength bytes from the UBX file buffer and put them into myBuffer
myGNSS.extractFileBufferData(myBuffer, packetLength); // Extract exactly packetLength bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, packetLength); // Write exactly packetLength bytes from myBuffer to the ubxDataFile on the SD card
@@ -22,9 +22,7 @@
Insert a formatted micro-SD card into the socket on the Carrier Board.
Connect the Carrier Board to your computer using a USB-C cable.
Ensure you have the SparkFun Apollo3 boards installed: http://boardsmanager/All#SparkFun_Apollo3
This code has been tested using version 2.1.0 of the Apollo3 boards on Arduino IDE 1.8.13.
- Version 2.1.1 of Apollo3 contains a feature which makes I2C communication with u-blox modules problematic
- We recommend using v2.1.0 of Apollo3 until v2.2.0 is released
This code has been tested using version 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
Select "Artemis MicroMod Processor" as the board type.
Press upload to upload the code onto the Artemis.
Open the Serial Monitor at 115200 baud to see the output.
@@ -82,6 +80,7 @@ File myFile; //File that all GNSS data is written to
#endif
#define packetLength 36 // TIM TM2 is 28 + 8 bytes in length (including the sync chars, class, id, length and checksum bytes)
uint8_t *myBuffer; // Use myBuffer to hold the data while we write it to SD card
int dotsPrinted = 0; // Print dots in rows of 50 while waiting for a TIM TM2 message
@@ -92,30 +91,30 @@ int dotsPrinted = 0; // Print dots in rows of 50 while waiting for a TIM TM2 mes
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printTIMTM2data(UBX_TIM_TM2_data_t ubxDataStruct)
void printTIMTM2data(UBX_TIM_TM2_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("newFallingEdge: ")); // 1 if a new falling edge was detected
Serial.print(ubxDataStruct.flags.bits.newFallingEdge);
Serial.print(ubxDataStruct->flags.bits.newFallingEdge);
Serial.print(F(" newRisingEdge: ")); // 1 if a new rising edge was detected
Serial.print(ubxDataStruct.flags.bits.newRisingEdge);
Serial.print(ubxDataStruct->flags.bits.newRisingEdge);
Serial.print(F(" Rising Edge Counter: ")); // Rising edge counter
Serial.print(ubxDataStruct.count);
Serial.print(ubxDataStruct->count);
Serial.print(F(" towMsR: ")); // Time Of Week of rising edge (ms)
Serial.print(ubxDataStruct.towMsR);
Serial.print(ubxDataStruct->towMsR);
Serial.print(F(" towSubMsR: ")); // Millisecond fraction of Time Of Week of rising edge in nanoseconds
Serial.print(ubxDataStruct.towSubMsR);
Serial.print(ubxDataStruct->towSubMsR);
Serial.print(F(" towMsF: ")); // Time Of Week of falling edge (ms)
Serial.print(ubxDataStruct.towMsF);
Serial.print(ubxDataStruct->towMsF);
Serial.print(F(" towSubMsF: ")); // Millisecond fraction of Time Of Week of falling edge in nanoseconds
Serial.println(ubxDataStruct.towSubMsF);
Serial.println(ubxDataStruct->towSubMsF);
dotsPrinted = 0; // Reset dotsPrinted
}
@@ -206,10 +205,12 @@ void setup()
myGNSS.setNavigationFrequency(1); //Produce one navigation solution per second
myGNSS.setAutoTIMTM2callback(&printTIMTM2data); // Enable automatic TIM TM2 messages with callback to printTIMTM2data
myGNSS.setAutoTIMTM2callbackPtr(&printTIMTM2data); // Enable automatic TIM TM2 messages with callback to printTIMTM2data
myGNSS.logTIMTM2(); // Enable TIM TM2 data logging
myBuffer = new uint8_t[packetLength]; // Create our own buffer to hold the data while we write it to SD card
Serial.println(F("Press any key to stop logging."));
}
@@ -220,9 +221,7 @@ void loop()
if (myGNSS.fileBufferAvailable() >= packetLength) // Check to see if a new packetLength-byte TIM TM2 message has been stored
{
uint8_t myBuffer[packetLength]; // Create our own buffer to hold the data while we write it to SD card
myGNSS.extractFileBufferData((uint8_t *)&myBuffer, packetLength); // Extract exactly packetLength bytes from the UBX file buffer and put them into myBuffer
myGNSS.extractFileBufferData(myBuffer, packetLength); // Extract exactly packetLength bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, packetLength); // Write exactly packetLength bytes from myBuffer to the ubxDataFile on the SD card
@@ -34,9 +34,7 @@
Insert a formatted micro-SD card into the socket on the Carrier Board.
Connect the Carrier Board to your computer using a USB-C cable.
Ensure you have the SparkFun Apollo3 boards installed: http://boardsmanager/All#SparkFun_Apollo3
This code has been tested using version 2.1.0 of the Apollo3 boards on Arduino IDE 1.8.13.
- Version 2.1.1 of Apollo3 contains a feature which makes I2C communication with u-blox modules problematic
- We recommend using v2.1.0 of Apollo3 until v2.2.0 is released
This code has been tested using version 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
Select "Artemis MicroMod Processor" as the board type.
Press upload to upload the code onto the Artemis.
Open the Serial Monitor at 115200 baud to see the output.
@@ -76,6 +74,7 @@ File myFile; //File that all GNSS data is written to
#define sdWriteSize 512 // Write data to the SD card in blocks of 512 bytes
#define fileBufferSize 16384 // Allocate 16KBytes of RAM for UBX message storage
uint8_t *myBuffer; // Use myBuffer to hold the data while we write it to SD card
unsigned long lastPrint; // Record when the last Serial print took place
@@ -93,7 +92,7 @@ int numRAWX = 0; // Keep count of how many RAWX message groups have been receive
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void newSFRBX(UBX_RXM_SFRBX_data_t ubxDataStruct)
void newSFRBX(UBX_RXM_SFRBX_data_t *ubxDataStruct)
{
numSFRBX++; // Increment the count
}
@@ -105,7 +104,7 @@ void newSFRBX(UBX_RXM_SFRBX_data_t ubxDataStruct)
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void newRAWX(UBX_RXM_RAWX_data_t ubxDataStruct)
void newRAWX(UBX_RXM_RAWX_data_t *ubxDataStruct)
{
numRAWX++; // Increment the count
}
@@ -202,14 +201,16 @@ void setup()
myGNSS.setNavigationFrequency(1); //Produce one navigation solution per second (that's plenty for Precise Point Positioning)
myGNSS.setAutoRXMSFRBXcallback(&newSFRBX); // Enable automatic RXM SFRBX messages with callback to newSFRBX
myGNSS.setAutoRXMSFRBXcallbackPtr(&newSFRBX); // Enable automatic RXM SFRBX messages with callback to newSFRBX
myGNSS.logRXMSFRBX(); // Enable RXM SFRBX data logging
myGNSS.setAutoRXMRAWXcallback(&newRAWX); // Enable automatic RXM RAWX messages with callback to newRAWX
myGNSS.setAutoRXMRAWXcallbackPtr(&newRAWX); // Enable automatic RXM RAWX messages with callback to newRAWX
myGNSS.logRXMRAWX(); // Enable RXM RAWX data logging
myBuffer = new uint8_t[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
Serial.println(F("Press any key to stop logging."));
lastPrint = millis(); // Initialize lastPrint
@@ -228,9 +229,7 @@ void loop()
{
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN each time we write to the SD card
uint8_t myBuffer[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
myGNSS.extractFileBufferData((uint8_t *)&myBuffer, sdWriteSize); // Extract exactly sdWriteSize bytes from the UBX file buffer and put them into myBuffer
myGNSS.extractFileBufferData(myBuffer, sdWriteSize); // Extract exactly sdWriteSize bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, sdWriteSize); // Write exactly sdWriteSize bytes from myBuffer to the ubxDataFile on the SD card
@@ -273,15 +272,13 @@ void loop()
{
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN while we write to the SD card
uint8_t myBuffer[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
uint16_t bytesToWrite = remainingBytes; // Write the remaining bytes to SD card sdWriteSize bytes at a time
if (bytesToWrite > sdWriteSize)
{
bytesToWrite = sdWriteSize;
}
myGNSS.extractFileBufferData((uint8_t *)&myBuffer, bytesToWrite); // Extract bytesToWrite bytes from the UBX file buffer and put them into myBuffer
myGNSS.extractFileBufferData(myBuffer, bytesToWrite); // Extract bytesToWrite bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, bytesToWrite); // Write bytesToWrite bytes from myBuffer to the ubxDataFile on the SD card
@@ -35,9 +35,7 @@
Insert a formatted micro-SD card into the socket on the Carrier Board.
Connect the Carrier Board to your computer using a USB-C cable.
Ensure you have the SparkFun Apollo3 boards installed: http://boardsmanager/All#SparkFun_Apollo3
This code has been tested using version 2.1.0 of the Apollo3 boards on Arduino IDE 1.8.13.
- Version 2.1.1 of Apollo3 contains a feature which makes I2C communication with u-blox modules problematic
- We recommend using v2.1.0 of Apollo3 until v2.2.0 is released
This code has been tested using version 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
Select "Artemis MicroMod Processor" as the board type.
Press upload to upload the code onto the Artemis.
Open the Serial Monitor at 115200 baud to see the output.
@@ -77,6 +75,7 @@ File myFile; //File that all GNSS data is written to
#define sdWriteSize 512 // Write data to the SD card in blocks of 512 bytes
#define fileBufferSize 16384 // Allocate 16KBytes of RAM for UBX message storage
uint8_t *myBuffer; // A buffer to hold the data while we write it to SD card
unsigned long lastPrint; // Record when the last Serial print took place
unsigned long bytesWritten = 0; // Record how many bytes have been written to SD card
@@ -181,6 +180,8 @@ void setup()
myGNSS.logRXMRAWX(); // Enable RXM RAWX data logging
myBuffer = new uint8_t[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
Serial.println(F("Press any key to stop logging."));
lastPrint = millis(); // Initialize lastPrint
@@ -198,9 +199,7 @@ void loop()
{
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN each time we write to the SD card
uint8_t myBuffer[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
myGNSS.extractFileBufferData((uint8_t *)&myBuffer, sdWriteSize); // Extract exactly sdWriteSize bytes from the UBX file buffer and put them into myBuffer
myGNSS.extractFileBufferData(myBuffer, sdWriteSize); // Extract exactly sdWriteSize bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, sdWriteSize); // Write exactly sdWriteSize bytes from myBuffer to the ubxDataFile on the SD card
@@ -242,15 +241,13 @@ void loop()
{
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN while we write to the SD card
uint8_t myBuffer[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
uint16_t bytesToWrite = remainingBytes; // Write the remaining bytes to SD card sdWriteSize bytes at a time
if (bytesToWrite > sdWriteSize)
{
bytesToWrite = sdWriteSize;
}
myGNSS.extractFileBufferData((uint8_t *)&myBuffer, bytesToWrite); // Extract bytesToWrite bytes from the UBX file buffer and put them into myBuffer
myGNSS.extractFileBufferData(myBuffer, bytesToWrite); // Extract bytesToWrite bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, bytesToWrite); // Write bytesToWrite bytes from myBuffer to the ubxDataFile on the SD card
@@ -35,9 +35,7 @@
Insert a formatted micro-SD card into the socket on the Carrier Board.
Connect the Carrier Board to your computer using a USB-C cable.
Ensure you have the SparkFun Apollo3 boards installed: http://boardsmanager/All#SparkFun_Apollo3
This code has been tested using version 2.1.0 of the Apollo3 boards on Arduino IDE 1.8.13.
- Version 2.1.1 of Apollo3 contains a feature which makes I2C communication with u-blox modules problematic
- We recommend using v2.1.0 of Apollo3 until v2.2.0 is released
This code has been tested using version 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
Select "Artemis MicroMod Processor" as the board type.
Press upload to upload the code onto the Artemis.
Open the Serial Monitor at 115200 baud to see the output.
@@ -77,6 +75,7 @@ File myFile; //File that all GNSS data is written to
#define sdWriteSize 512 // Write data to the SD card in blocks of 512 bytes
#define fileBufferSize 32768 // Allocate 32KBytes of RAM for UBX message storage
uint8_t *myBuffer; // A buffer to hold the data while we write it to SD card
unsigned long lastPrint; // Record when the last Serial print took place
unsigned long bytesWritten = 0; // Record how many bytes have been written to SD card
@@ -196,6 +195,8 @@ void setup()
myGNSS.logRXMRAWX(); // Enable RXM RAWX data logging
myBuffer = new uint8_t[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
Serial.println(F("Press any key to stop logging."));
lastPrint = millis(); // Initialize lastPrint
@@ -213,9 +214,7 @@ void loop()
{
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN each time we write to the SD card
uint8_t myBuffer[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
myGNSS.extractFileBufferData((uint8_t *)&myBuffer, sdWriteSize); // Extract exactly sdWriteSize bytes from the UBX file buffer and put them into myBuffer
myGNSS.extractFileBufferData(myBuffer, sdWriteSize); // Extract exactly sdWriteSize bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, sdWriteSize); // Write exactly sdWriteSize bytes from myBuffer to the ubxDataFile on the SD card
@@ -263,15 +262,13 @@ void loop()
{
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN while we write to the SD card
uint8_t myBuffer[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
uint16_t bytesToWrite = remainingBytes; // Write the remaining bytes to SD card sdWriteSize bytes at a time
if (bytesToWrite > sdWriteSize)
{
bytesToWrite = sdWriteSize;
}
myGNSS.extractFileBufferData((uint8_t *)&myBuffer, bytesToWrite); // Extract bytesToWrite bytes from the UBX file buffer and put them into myBuffer
myGNSS.extractFileBufferData(myBuffer, bytesToWrite); // Extract bytesToWrite bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, bytesToWrite); // Write bytesToWrite bytes from myBuffer to the ubxDataFile on the SD card
@@ -24,9 +24,7 @@
Insert a formatted micro-SD card into the socket on the Carrier Board.
Connect the Carrier Board to your computer using a USB-C cable.
Ensure you have the SparkFun Apollo3 boards installed: http://boardsmanager/All#SparkFun_Apollo3
This code has been tested using version 2.1.0 of the Apollo3 boards on Arduino IDE 1.8.13.
- Version 2.1.1 of Apollo3 contains a feature which makes I2C communication with u-blox modules problematic
- We recommend using v2.1.0 of Apollo3 until v2.2.0 is released
This code has been tested using version 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
Select "Artemis MicroMod Processor" as the board type.
Press upload to upload the code onto the Artemis.
Open the Serial Monitor at 115200 baud to see the output.
@@ -68,6 +66,7 @@ File myFile; //File that all GNSS data is written to
#define sdWriteSize 512 // Write data to the SD card in blocks of 512 bytes
#define fileBufferSize 16384 // Allocate 16KBytes of RAM for UBX message storage
uint8_t *myBuffer; // A buffer to hold the data while we write it to SD card
unsigned long lastPrint; // Record when the last Serial print took place
unsigned long bytesWritten = 0; // Record how many bytes have been written to SD card
@@ -175,6 +174,8 @@ void setup()
myGNSS.setNMEALoggingMask(SFE_UBLOX_FILTER_NMEA_ALL); // Enable logging of all enabled NMEA messages
//myGNSS.setNMEALoggingMask(SFE_UBLOX_FILTER_NMEA_GGA | SFE_UBLOX_FILTER_NMEA_GSA); // Or we can, for example, log only GxGGA & GxGSA and ignore GxGSV
myBuffer = new uint8_t[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
Serial.println(F("Press any key to stop logging."));
lastPrint = millis(); // Initialize lastPrint
@@ -192,9 +193,7 @@ void loop()
{
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN each time we write to the SD card
uint8_t myBuffer[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
myGNSS.extractFileBufferData((uint8_t *)&myBuffer, sdWriteSize); // Extract exactly sdWriteSize bytes from the UBX file buffer and put them into myBuffer
myGNSS.extractFileBufferData(myBuffer, sdWriteSize); // Extract exactly sdWriteSize bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, sdWriteSize); // Write exactly sdWriteSize bytes from myBuffer to the ubxDataFile on the SD card
@@ -236,15 +235,13 @@ void loop()
{
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN while we write to the SD card
uint8_t myBuffer[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
uint16_t bytesToWrite = remainingBytes; // Write the remaining bytes to SD card sdWriteSize bytes at a time
if (bytesToWrite > sdWriteSize)
{
bytesToWrite = sdWriteSize;
}
myGNSS.extractFileBufferData((uint8_t *)&myBuffer, bytesToWrite); // Extract bytesToWrite bytes from the UBX file buffer and put them into myBuffer
myGNSS.extractFileBufferData(myBuffer, bytesToWrite); // Extract bytesToWrite bytes from the UBX file buffer and put them into myBuffer
myFile.write(myBuffer, bytesToWrite); // Write bytesToWrite bytes from myBuffer to the ubxDataFile on the SD card
@@ -0,0 +1,111 @@
/*
By: Paul CLark
SparkFun Electronics
Date: January, 2022
License: MIT. See license file for more information but you can
basically do whatever you want with this code.
Feel like supporting open source hardware?
Buy a board from SparkFun!
ZED-F9R: https://www.sparkfun.com/products/16344
Hardware Connections:
Plug a Qwiic cable into the GNSS and a Redboard Qwiic
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
After calibrating the module and securing it to your vehicle such that it's
stable within 2 degrees, and the board is oriented correctly with regards to
the vehicle's frame, you can now read the vehicle's "attitude". The attitude
includes the vehicle's heading, pitch, and roll.
*/
#include <Wire.h> //Needed for I2C to GNSS
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
while (!Serial); //Wait for user to open terminal
Serial.println(F("SparkFun u-blox Example"));
Wire.begin();
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
while (1);
}
myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
}
void loop()
{
// PVAT data is produced at the navigation rate, so by default we'll get fresh data once per second
if (myGNSS.getNAVPVAT()) // Poll new PVAT
{
Serial.print(F("Roll: "));
Serial.print((float)myGNSS.getVehicleRoll() / 100000.0, 5); // Use the helper function to get the roll in degrees * 10^-5
Serial.print(F(" Pitch: "));
Serial.print((float)myGNSS.getVehiclePitch() / 100000.0, 5); // Use the helper function to get the pitch in degrees * 10^-5
Serial.print(F(" Heading: "));
Serial.print((float)myGNSS.getVehicleHeading() / 100000.0, 5); // Use the helper function to get the heading in degrees * 10^-5
// We don't have helper functions to extract the roll, pitch and heading valid flags from the PVAT message. But we can do it manually:
Serial.print(F(" Roll Valid: "));
Serial.print(myGNSS.packetUBXNAVPVAT->data.flags.bits.vehRollValid);
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.vehRollValid = false; // Mark the data as stale
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
Serial.print(F(" Pitch Valid: "));
Serial.print(myGNSS.packetUBXNAVPVAT->data.flags.bits.vehPitchValid);
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.vehPitchValid = false; // Mark the data as stale
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
Serial.print(F(" Heading Valid: "));
Serial.print(myGNSS.packetUBXNAVPVAT->data.flags.bits.vehHeadingValid);
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.vehHeadingValid = false; // Mark the data as stale
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
// We don't have helper functions to extract the roll, pitch and heading accuracy from the PVAT message. But we can do it manually:
Serial.print(F(" Roll Acc: "));
Serial.print(((float)myGNSS.packetUBXNAVPVAT->data.accRoll) / 100, 2);
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried2.bits.accRoll = false; // Mark the data as stale
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
Serial.print(F(" Pitch Acc: "));
Serial.print(((float)myGNSS.packetUBXNAVPVAT->data.accPitch) / 100, 2);
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried2.bits.accPitch = false; // Mark the data as stale
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
Serial.print(F(" Heading Acc: "));
Serial.print(((float)myGNSS.packetUBXNAVPVAT->data.accHeading) / 100, 2);
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried2.bits.accHeading = false; // Mark the data as stale
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
// We don't have helper functions to extract the lat and lon from the PVAT message. But we can do it manually:
Serial.print(F(" Lat: "));
Serial.print(((float)myGNSS.packetUBXNAVPVAT->data.lat) / 10000000.0, 7);
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.lat = false; // Mark the data as stale
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
Serial.print(F(" Lon: "));
Serial.print(((float)myGNSS.packetUBXNAVPVAT->data.lon) / 10000000.0, 7);
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.lon = false; // Mark the data as stale
myGNSS.packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
Serial.println();
}
delay(250);
}
@@ -41,27 +41,27 @@ SFE_UBLOX_GNSS myGNSS;
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printHPdata(UBX_NAV_HPPOSLLH_data_t ubxDataStruct)
void printHPdata(UBX_NAV_HPPOSLLH_data_t *ubxDataStruct)
{
Serial.println();
long highResLatitude = ubxDataStruct.lat;
long highResLatitude = ubxDataStruct->lat;
Serial.print(F("Hi Res Lat: "));
Serial.print(highResLatitude);
int highResLatitudeHp = ubxDataStruct.latHp;
int highResLatitudeHp = ubxDataStruct->latHp;
Serial.print(F(" "));
Serial.print(highResLatitudeHp);
long highResLongitude = ubxDataStruct.lon;
long highResLongitude = ubxDataStruct->lon;
Serial.print(F(" Hi Res Long: "));
Serial.print(highResLongitude);
int highResLongitudeHp = ubxDataStruct.lonHp;
int highResLongitudeHp = ubxDataStruct->lonHp;
Serial.print(F(" "));
Serial.print(highResLongitudeHp);
float horizAccuracy = ((float)ubxDataStruct.hAcc) / 10000.0; // Convert hAcc from mm*0.1 to m
float horizAccuracy = ((float)ubxDataStruct->hAcc) / 10000.0; // Convert hAcc from mm*0.1 to m
Serial.print(F(" Horiz accuracy: "));
Serial.println(horizAccuracy);
}
@@ -73,38 +73,38 @@ void printHPdata(UBX_NAV_HPPOSLLH_data_t ubxDataStruct)
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printPVTdata(UBX_NAV_PVT_data_t ubxDataStruct)
void printPVTdata(UBX_NAV_PVT_data_t *ubxDataStruct)
{
Serial.println();
Serial.print(F("Time: ")); // Print the time
uint8_t hms = ubxDataStruct.hour; // Print the hours
uint8_t hms = ubxDataStruct->hour; // Print the hours
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
Serial.print(hms);
Serial.print(F(":"));
hms = ubxDataStruct.min; // Print the minutes
hms = ubxDataStruct->min; // Print the minutes
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
Serial.print(hms);
Serial.print(F(":"));
hms = ubxDataStruct.sec; // Print the seconds
hms = ubxDataStruct->sec; // Print the seconds
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
Serial.print(hms);
Serial.print(F("."));
unsigned long millisecs = ubxDataStruct.iTOW % 1000; // Print the milliseconds
unsigned long millisecs = ubxDataStruct->iTOW % 1000; // Print the milliseconds
if (millisecs < 100) Serial.print(F("0")); // Print the trailing zeros correctly
if (millisecs < 10) Serial.print(F("0"));
Serial.print(millisecs);
long latitude = ubxDataStruct.lat; // Print the latitude
long latitude = ubxDataStruct->lat; // Print the latitude
Serial.print(F(" Lat: "));
Serial.print(latitude);
long longitude = ubxDataStruct.lon; // Print the longitude
long longitude = ubxDataStruct->lon; // Print the longitude
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
long altitude = ubxDataStruct.hMSL; // Print the height above mean sea level
long altitude = ubxDataStruct->hMSL; // Print the height above mean sea level
Serial.print(F(" Height above MSL: "));
Serial.print(altitude);
Serial.println(F(" (mm)"));
@@ -135,9 +135,9 @@ void setup()
myGNSS.setNavigationFrequency(2); //Produce two solutions per second
myGNSS.setAutoPVTcallback(&printPVTdata); // Enable automatic NAV PVT messages with callback to printPVTdata
myGNSS.setAutoPVTcallbackPtr(&printPVTdata); // Enable automatic NAV PVT messages with callback to printPVTdata
myGNSS.setAutoHPPOSLLHcallback(&printHPdata); // Enable automatic NAV HPPOSLLH messages with callback to printHPdata
myGNSS.setAutoHPPOSLLHcallbackPtr(&printHPdata); // Enable automatic NAV HPPOSLLH messages with callback to printHPdata
}
void loop()
@@ -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
@@ -0,0 +1,491 @@
/*
Use ESP32 WiFi to get RTCM data from Swift Navigation's Skylark caster as a Client, and transmit GGA using a callback
By: SparkFun Electronics / Nathan Seidle & Paul Clark
Date: January 13th, 2022
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 Skylark. But you can of course use RTK2Go or Emlid's Caster too. Change secrets.h. as required.
The rover's location will be broadcast to the caster every 10s via GGA setence - automatically using a callback.
This is a proof of concept to show how to connect to a caster via HTTP and show how the corrections control the accuracy.
It's a fun thing to disconnect from the caster and watch the accuracy degrade. Then connect again and watch it recover!
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
unsigned long lastReceivedRTCM_ms = 0; //5 RTCM messages take approximately ~300ms to arrive at 115200bps
const unsigned long maxTimeBeforeHangup_ms = 10000UL; //If we fail to get a complete RTCM frame after 10s, then disconnect from caster
bool transmitLocation = true; //By default we will transmit the unit's location via GGA sentence.
WiFiClient ntripClient; // The WiFi connection to the NTRIP server. This is global so pushGGA can see if we are connected.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Callback: pushGPGGA will be called when new GPGGA NMEA data arrives
// See u-blox_structs.h for the full definition of NMEA_GGA_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setNMEAGPGGAcallback
// / _____ This _must_ be NMEA_GGA_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void pushGPGGA(NMEA_GGA_data_t *nmeaData)
{
//Provide the caster with our current position as needed
if ((ntripClient.connected() == true) && (transmitLocation == true))
{
Serial.print(F("Pushing GGA to server: "));
Serial.print((const char *)nmeaData->nmea); // .nmea is printable (NULL-terminated) and already has \r\n on the end
//Push our current GGA sentence to caster
ntripClient.print((const char *)nmeaData->nmea);
}
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Callback: printPVTdata will be called when new NAV PVT data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_PVT_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoPVTcallback
// / _____ This _must_ be UBX_NAV_PVT_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printPVTdata(UBX_NAV_PVT_data_t *ubxDataStruct)
{
double latitude = ubxDataStruct->lat; // Print the latitude
Serial.print(F("Lat: "));
Serial.print(latitude / 10000000.0, 7);
double longitude = ubxDataStruct->lon; // Print the longitude
Serial.print(F(" Long: "));
Serial.print(longitude / 10000000.0, 7);
double altitude = ubxDataStruct->hMSL; // Print the height above mean sea level
Serial.print(F(" Height: "));
Serial.print(altitude / 1000.0, 3);
uint8_t fixType = ubxDataStruct->fixType; // Print the fix type
Serial.print(F(" Fix: "));
Serial.print(fixType);
if (fixType == 0)
Serial.print(F(" (None)"));
else if (fixType == 1)
Serial.print(F(" (Dead Reckoning)"));
else if (fixType == 2)
Serial.print(F(" (2D)"));
else if (fixType == 3)
Serial.print(F(" (3D)"));
else if (fixType == 3)
Serial.print(F(" (GNSS + Dead Reckoning)"));
else if (fixType == 5)
Serial.print(F(" (Time Only)"));
else
Serial.print(F(" (UNKNOWN)"));
uint8_t carrSoln = ubxDataStruct->flags.bits.carrSoln; // Print the carrier solution
Serial.print(F(" Carrier Solution: "));
Serial.print(carrSoln);
if (carrSoln == 0)
Serial.print(F(" (None)"));
else if (carrSoln == 1)
Serial.print(F(" (Floating)"));
else if (carrSoln == 2)
Serial.print(F(" (Fixed)"));
else
Serial.print(F(" (UNKNOWN)"));
uint32_t hAcc = ubxDataStruct->hAcc; // Print the horizontal accuracy estimate
Serial.print(F(" Horizontal Accuracy Estimate: "));
Serial.print(hAcc);
Serial.print(F(" (mm)"));
Serial.println();
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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."));
delay(2000);
}
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.setDGNSSConfiguration(SFE_UBLOX_DGNSS_MODE_FIXED); // Set the differential mode - ambiguities are fixed whenever possible
myGNSS.setNavigationFrequency(1); //Set output in Hz.
// Set the Main Talker ID to "GP". The NMEA GGA messages will be GPGGA instead of GNGGA
myGNSS.setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_GP);
myGNSS.setNMEAGPGGAcallbackPtr(&pushGPGGA); // Set up the callback for GPGGA
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C, 10); // Tell the module to output GGA every 10 seconds
myGNSS.setAutoPVTcallbackPtr(&printPVTdata); // Enable automatic NAV PVT messages with callback to printPVTdata so we can watch the carrier solution go to fixed
//myGNSS.saveConfiguration(VAL_CFG_SUBSEC_IOPORT | VAL_CFG_SUBSEC_MSGCONF); //Optional: Save the ioPort and message settings to NVM
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
bool keepTrying = true;
while (keepTrying)
{
Serial.print(F("Connecting to local WiFi"));
unsigned long startTime = millis();
WiFi.begin(ssid, password);
while ((WiFi.status() != WL_CONNECTED) && (millis() < (startTime + 10000))) // Timeout after 10 seconds
{
delay(500);
Serial.print(F("."));
}
Serial.println();
if (WiFi.status() == WL_CONNECTED)
keepTrying = false; // Connected!
else
{
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
}
}
Serial.print(F("WiFi connected with IP: "));
Serial.println(WiFi.localIP());
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
while (Serial.available()) // Empty the serial buffer
Serial.read();
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new GNSS data and process it.
myGNSS.checkCallbacks(); // Check if any GNSS callbacks are waiting to be processed.
enum states // Use a 'state machine' to open and close the connection
{
open_connection,
push_data_and_wait_for_keypress,
close_connection,
waiting_for_keypress
};
static states state = open_connection;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
switch (state)
{
case open_connection:
Serial.println(F("Connecting to the NTRIP caster..."));
if (beginClient()) // Try to open the connection to the caster
{
Serial.println(F("Connected to the NTRIP caster! Press any key to disconnect..."));
state = push_data_and_wait_for_keypress; // Move on
}
else
{
Serial.print(F("Could not connect to the caster. Trying again in 5 seconds."));
for (int i = 0; i < 5; i++)
{
delay(1000);
Serial.print(F("."));
}
Serial.println();
}
break;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
case push_data_and_wait_for_keypress:
// If the connection has dropped or timed out, or if the user has pressed a key
if ((processConnection() == false) || (keyPressed()))
{
state = close_connection; // Move on
}
break;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
case close_connection:
Serial.println(F("Closing the connection to the NTRIP caster..."));
closeConnection();
Serial.println(F("Press any key to reconnect..."));
state = waiting_for_keypress; // Move on
break;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
case waiting_for_keypress:
// If the connection has dropped or timed out, or if the user has pressed a key
if (keyPressed())
state = open_connection; // Move on
break;
}
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//Connect to NTRIP Caster. Return true is connection is successful.
bool beginClient()
{
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 (false);
}
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);
// Set up the server request (GET)
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);
// Set up the credentials
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);
}
// Add the encoded credentials to the server request
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"));
// Send the server request
Serial.println(F("Sending server request: "));
Serial.println(serverRequest);
ntripClient.write(serverRequest, strlen(serverRequest));
//Wait up to 5 seconds for response
unsigned long startTime = millis();
while (ntripClient.available() == 0)
{
if (millis() > (startTime + 5000))
{
Serial.println(F("Caster timed out!"));
ntripClient.stop();
return (false);
}
delay(10);
}
//Check reply
int connectionResult = 0;
char response[512];
size_t responseSpot = 0;
while (ntripClient.available()) // Read bytes from the caster and store them
{
if (responseSpot == sizeof(response) - 1) // Exit the loop if we get too much data
break;
response[responseSpot++] = ntripClient.read();
if (connectionResult == 0) // Only print success/fail once
{
if (strstr(response, "200") != NULL) //Look for '200 OK'
{
connectionResult = 200;
}
if (strstr(response, "401") != NULL) //Look for '401 Unauthorized'
{
Serial.println(F("Hey - your credentials look bad! Check your caster username and password."));
connectionResult = 401;
}
}
}
response[responseSpot] = '\0'; // NULL-terminate the response
//Serial.print(F("Caster responded with: ")); Serial.println(response); // Uncomment this line to see the full response
if (connectionResult != 200)
{
Serial.print(F("Failed to connect to "));
Serial.println(casterHost);
return (false);
}
else
{
Serial.print(F("Connected to: "));
Serial.println(casterHost);
lastReceivedRTCM_ms = millis(); //Reset timeout
}
} //End attempt to connect
return (true);
} // /beginClient
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//Check for the arrival of any correction data. Push it to the GNSS.
//Return false if: the connection has dropped, or if we receive no data for maxTimeBeforeHangup_ms
bool processConnection()
{
if (ntripClient.connected() == true) // Check that the connection is still open
{
uint8_t rtcmData[512 * 4]; //Most incoming data is around 500 bytes but may be larger
size_t rtcmCount = 0;
//Collect 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);
Serial.print(F("Pushed "));
Serial.print(rtcmCount);
Serial.println(F(" RTCM bytes to ZED"));
}
}
else
{
Serial.println(F("Connection dropped!"));
return (false); // Connection has dropped - return false
}
//Timeout if we don't have new data for maxTimeBeforeHangup_ms
if ((millis() - lastReceivedRTCM_ms) > maxTimeBeforeHangup_ms)
{
Serial.println(F("RTCM timeout!"));
return (false); // Connection has timed out - return false
}
return (true);
} // /processConnection
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void closeConnection()
{
if (ntripClient.connected() == true)
{
ntripClient.stop();
}
Serial.println(F("Disconnected!"));
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//Return true if a key has been pressed
bool keyPressed()
{
if (Serial.available()) // Check for a new key press
{
delay(100); // Wait for any more keystrokes to arrive
while (Serial.available()) // Empty the serial buffer
Serial.read();
return (true);
}
return (false);
}
@@ -0,0 +1,27 @@
//Your WiFi credentials
const char ssid[] = "yourSSID";
const char password[] = "yourPassword";
//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
// Skylark (Swift Navigation) is awesome - but requires a subscription:
// https://www.swiftnav.com/skylark
// https://account.swiftnav.com/sign-up
// Use the promo-code ONEMONTHFREE for a free one month access to Skylark on one device
const char casterHost[] = "na.skylark.swiftnav.com"; // na = North Americs L1+L2; eu = Europe L1+L2
const uint16_t casterPort = 2101;
const char casterUser[] = "NTRIPusername+accountSubdomain"; // This is generated when you add a device to your Skylark account
const char casterUserPW[] = "devicePassword";
const char mountPoint[] = "CRS"; // The mount point you want to get data from. Select CRS (Cloud Reference Station) for the ZED-F9x
@@ -0,0 +1,174 @@
/*
Use ESP32 WiFi to get SPARTN data from PointPerfect (broker) as a Client
By: u-blox AG / Michael Ammann
Date: January 27th, 2022
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 SPARTN data from a PointPerfect Broker over WiFi
and push it over I2C to a ZED-F9x.
It's confusing, but the Arduino is acting as a 'client' to the PointPerfect SSR correction service.
You will need to have a valid u-blox Thingstream account and have a PointPerfect Thing and payed plan.
Thingstream offers SSR corrections to SPARTN capable RTK receivers such as the u-blox ZED-F9 series
in continental Europe and US. Their Network is planned to be expanded to other regions over the next years.
To sign up, go to: https://portal.thingstream.io/app/location-services/things
This is a proof of concept to show how to connect via MQTT to get SPARTN SSR correction.
Using WiFi for a rover is generally a bad idea because of limited WiFi range in the field.
You may use this exmaple in combination with a cell phone with hotspot mode enabled.
For more information about MQTT, SPARTN and PointPerfect Correction Services
please see: https://www.u-blox.com/en/product/pointperfect
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
Recommended Hardware:
MicroMod GNSS Carrier Board: https://www.sparkfun.com/products/17722
ESP32 Micromod https://www.sparkfun.com/products/16781
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 <WiFiClientSecure.h>
#include <ArduinoMqttClient.h> // Click here to get the library: http://librarymanager/All#ArduinoMqttClient
#include "secrets.h"
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> // Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
//Global variables
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
long lastReceived_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
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println(F("PointPerfect testing"));
Wire.begin(); //Start I2C
if (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."));
while (1);
}
Serial.println(F("u-blox module connected"));
myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
myGNSS.setPortInput(COM_PORT_I2C, COM_TYPE_UBX | COM_TYPE_NMEA | COM_TYPE_SPARTN); // Be sure SPARTN input 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 MQTT/SPARTN Client."));
delay(1000);
}
WiFiClientSecure wifiClient = WiFiClientSecure();
MqttClient mqttClient(wifiClient);
void mqttMessageHandler(int messageSize) {
uint8_t spartnData[512 * 4]; //Most incoming data is around 500 bytes but may be larger
int spartnCount = 0;
Serial.print(F("Pushed data from "));
Serial.print(mqttClient.messageTopic());
Serial.println(F(" topic to ZED"));
while (mqttClient.available())
{
char ch = mqttClient.read();
//Serial.write(ch); //Pipe to serial port is fine but beware, it's a lot of binary data
spartnData[spartnCount++] = ch;
if (spartnCount == sizeof(spartnData))
break;
}
if (spartnCount > 0)
{
//Push KEYS or SPARTN data to GNSS module over I2C
myGNSS.pushRawData(spartnData, spartnCount, false);
lastReceived_ms = millis();
}
}
//Connect to STARTN MQTT broker, receive RTCM, and push to ZED module over I2C
void beginClient()
{
Serial.println(F("Subscribing to Broker. 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
if (wifiClient.connected() == false)
{
// Connect to AWS IoT
wifiClient.setCACert(AWS_CERT_CA);
wifiClient.setCertificate(AWS_CERT_CRT);
wifiClient.setPrivateKey(AWS_CERT_PRIVATE);
if (!mqttClient.connect(AWS_IOT_ENDPOINT, AWS_IOT_PORT)) {
Serial.print(F("MQTT connection failed! Error code = "));
Serial.println(mqttClient.connectError());
return;
} else {
Serial.println(F("You're connected to the PointPerfect MQTT broker: "));
Serial.println(AWS_IOT_ENDPOINT);
// Subscribe to MQTT and register a callback
Serial.println(F("Subscribe to Topics"));
mqttClient.onMessage(mqttMessageHandler);
mqttClient.subscribe(MQTT_TOPIC_KEY);
mqttClient.subscribe(MQTT_TOPIC_SPARTN);
lastReceived_ms = millis();
} //End attempt to connect
} //End connected == false
else {
mqttClient.poll();
}
//Close socket if we don't have new data for 10s
if (millis() - lastReceived_ms > maxTimeBeforeHangup_ms)
{
Serial.println(F("SPARTN timeout. Disconnecting..."));
if (mqttClient.connected() == true)
mqttClient.stop();
return;
}
delay(10);
}
Serial.println(F("User pressed a key"));
Serial.println(F("Disconnecting..."));
wifiClient.stop();
}
@@ -0,0 +1,38 @@
//Your WiFi credentials
const char ssid[] = "<YOUR SSID>";
const char password[] = "<YOUR PASSWORD>";
// Below infomation you can set after signing up with u-blox Thingstream portal
// and after add a new New PointPerfect Thing
// https://portal.thingstream.io/app/location-services/things
// in the new PointPerfect Thing you go to the credentials page and copy past the values and certificate into this.
// <Your PointPerfect Thing> -> Credentials -> Hostname
const char AWS_IOT_ENDPOINT[] = "pp.services.u-blox.com";
const unsigned short AWS_IOT_PORT = 8883;
// <Your PointPerfect Thing> -> Credentials -> IP key distribution topic
const char MQTT_TOPIC_KEY[] = "/pp/key/ip";
// <Your PointPerfect Thing> -> Credentials -> IP correction topic for EU/US region
const char MQTT_TOPIC_SPARTN[] = "/pp/ip/us"; // choice of {eu, us}
// <Your PointPerfect Thing> -> Credentials -> Amazon Root Certificate
static const char AWS_CERT_CA[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
<ADD YOUR CERTICICATE HERE>
-----END CERTIFICATE-----
)EOF";
// <Your PointPerfect Thing> -> Credentials -> Client Certificate
static const char AWS_CERT_CRT[] PROGMEM = R"KEY(
-----BEGIN CERTIFICATE-----
<ADD YOUR CERTICICATE HERE>
-----END CERTIFICATE-----
)KEY";
// Get this from Thingstream Portal
// <Your PointPerfect Thing> -> Credentials -> Client Key
static const char AWS_CERT_PRIVATE[] PROGMEM = R"KEY(
-----BEGIN RSA PRIVATE KEY-----
<ADD YOUR KEY HERE>
-----END RSA PRIVATE KEY-----
)KEY";
@@ -0,0 +1,212 @@
/*
Use the NEO-D9S L-Band receiver to provide corrections to a ZED-F9x via UBX-RXM-PMP messages
By: SparkFun Electronics / Paul Clark
Based on original code by: u-blox AG / Michael Ammann
Date: February 7th, 2022
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 SPARTN correction data from a NEO-D9S L-Band receiver and push it over I2C to a ZED-F9x.
This is a proof of concept to show how the UBX-RXM-PMP corrections control the accuracy.
You will need a Thingstream PointPerfect account to be able to access the SPARTN Credentials (IP Dynamic Keys).
Copy and paste the Current Key and Next Key into secrets.h.
Feel like supporting open source hardware?
Buy a board from SparkFun!
ZED-F9P RTK2: https://www.sparkfun.com/products/16481
NEO-D9S: Coming soon!
Hardware Connections:
Use Qwiic cables to connect the NEO-D9S and ZED-F9x GNSS to your board
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 "secrets.h" // <- Copy and paste the Current Key and Next Key into secrets.h
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS; // ZED-F9x
SFE_UBLOX_GNSS myLBand; // NEO-D9S
const uint32_t myLBandFreq = 1556290000; // Uncomment this line to use the US SPARTN 1.8 service
//const uint32_t myLBandFreq = 1545260000; // Uncomment this line to use the EU SPARTN 1.8 service
#define OK(ok) (ok ? F(" -> OK") : F(" -> ERROR!")) // Convert uint8_t into OK/ERROR
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Callback: pushRXMPMP will be called when new PMP data arrives
// See u-blox_structs.h for the full definition of UBX_RXM_PMP_message_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setRXMPMPmessageCallbackPtr
// / _____ This _must_ be UBX_RXM_PMP_message_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void pushRXMPMP(UBX_RXM_PMP_message_data_t *pmpData)
{
//Extract the raw message payload length
uint16_t payloadLen = ((uint16_t)pmpData->lengthMSB << 8) | (uint16_t)pmpData->lengthLSB;
Serial.print(F("New RXM-PMP data received. Message payload length is "));
Serial.print(payloadLen);
Serial.println(F(" Bytes. Pushing it to the GNSS..."));
//Push the PMP data to the GNSS
//The payload length could be variable, so we need to push the header and payload, then checksum
myGNSS.pushRawData(&pmpData->sync1, (size_t)payloadLen + 6); // Push the sync chars, class, ID, length and payload
myGNSS.pushRawData(&pmpData->checksumA, (size_t)2); // Push the checksum bytes
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Callback: printPVTdata will be called when new NAV PVT data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_PVT_data_t
// _____ You can use any name you like for the callback. Use the same name when you call setAutoPVTcallbackPtr
// / _____ This _must_ be UBX_NAV_PVT_data_t
// | / _____ You can use any name you like for the struct
// | | /
// | | |
void printPVTdata(UBX_NAV_PVT_data_t *ubxDataStruct)
{
double latitude = ubxDataStruct->lat; // Print the latitude
Serial.print(F("Lat: "));
Serial.print(latitude / 10000000.0, 7);
double longitude = ubxDataStruct->lon; // Print the longitude
Serial.print(F(" Long: "));
Serial.print(longitude / 10000000.0, 7);
double altitude = ubxDataStruct->hMSL; // Print the height above mean sea level
Serial.print(F(" Height: "));
Serial.print(altitude / 1000.0, 3);
uint8_t fixType = ubxDataStruct->fixType; // Print the fix type
Serial.print(F(" Fix: "));
Serial.print(fixType);
if (fixType == 0)
Serial.print(F(" (None)"));
else if (fixType == 1)
Serial.print(F(" (Dead Reckoning)"));
else if (fixType == 2)
Serial.print(F(" (2D)"));
else if (fixType == 3)
Serial.print(F(" (3D)"));
else if (fixType == 3)
Serial.print(F(" (GNSS + Dead Reckoning)"));
else if (fixType == 5)
Serial.print(F(" (Time Only)"));
else
Serial.print(F(" (UNKNOWN)"));
uint8_t carrSoln = ubxDataStruct->flags.bits.carrSoln; // Print the carrier solution
Serial.print(F(" Carrier Solution: "));
Serial.print(carrSoln);
if (carrSoln == 0)
Serial.print(F(" (None)"));
else if (carrSoln == 1)
Serial.print(F(" (Floating)"));
else if (carrSoln == 2)
Serial.print(F(" (Fixed)"));
else
Serial.print(F(" (UNKNOWN)"));
uint32_t hAcc = ubxDataStruct->hAcc; // Print the horizontal accuracy estimate
Serial.print(F(" Horizontal Accuracy Estimate: "));
Serial.print(hAcc);
Serial.print(F(" (mm)"));
Serial.println();
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void setup()
{
Serial.begin(115200);
Serial.println(F("NEO-D9S SPARTN Corrections"));
Wire.begin(); //Start I2C
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Begin and configure the ZED-F9x
//myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
while (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
{
Serial.println(F("u-blox GNSS module not detected at default I2C address. Please check wiring."));
delay(2000);
}
Serial.println(F("u-blox GNSS module connected"));
uint8_t ok = myGNSS.setI2COutput(COM_TYPE_UBX); //Turn off NMEA noise
if (ok) ok = myGNSS.setPortInput(COM_PORT_I2C, COM_TYPE_UBX | COM_TYPE_NMEA | COM_TYPE_SPARTN); //Be sure SPARTN input is enabled
if (ok) ok = myGNSS.setDGNSSConfiguration(SFE_UBLOX_DGNSS_MODE_FIXED); // Set the differential mode - ambiguities are fixed whenever possible
if (ok) ok = myGNSS.setNavigationFrequency(1); //Set output in Hz.
if (ok) ok = myGNSS.setVal8(UBLOX_CFG_SPARTN_USE_SOURCE, 1); // use LBAND PMP message
//Configure the SPARTN IP Dynamic Keys
//"When the receiver boots, the host should send 'current' and 'next' keys in one message." - Use setDynamicSPARTNKeys for this.
//"Every time the 'current' key is expired, 'next' takes its place."
//"Therefore the host should then retrieve the new 'next' key and send only that." - Use setDynamicSPARTNKey for this.
// The key can be provided in binary (uint8_t) format or in ASCII Hex (char) format, but in both cases keyLengthBytes _must_ represent the binary key length in bytes.
if (ok) ok = myGNSS.setDynamicSPARTNKeys(currentKeyLengthBytes, currentKeyGPSWeek, currentKeyGPSToW, currentDynamicKey,
nextKeyLengthBytes, nextKeyGPSWeek, nextKeyGPSToW, nextDynamicKey);
//if (ok) ok = myGNSS.saveConfiguration(VAL_CFG_SUBSEC_IOPORT | VAL_CFG_SUBSEC_MSGCONF); //Optional: Save the ioPort and message settings to NVM
Serial.print(F("GNSS: configuration "));
Serial.println(OK(ok));
myGNSS.setAutoPVTcallbackPtr(&printPVTdata); // Enable automatic NAV PVT messages with callback to printPVTdata so we can watch the carrier solution go to fixed
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Begin and configure the NEO-D9S L-Band receiver
//myLBand.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial
while (myLBand.begin(Wire, 0x43) == false) //Connect to the u-blox NEO-D9S using Wire port. The D9S default I2C address is 0x43 (not 0x42)
{
Serial.println(F("u-blox NEO-D9S not detected at default I2C address. Please check wiring."));
delay(2000);
}
Serial.println(F("u-blox NEO-D9S connected"));
ok = myLBand.setVal32(UBLOX_CFG_PMP_CENTER_FREQUENCY, myLBandFreq); // Default 1539812500 Hz
if (ok) ok = myLBand.setVal16(UBLOX_CFG_PMP_SEARCH_WINDOW, 2200); // Default 2200 Hz
if (ok) ok = myLBand.setVal8(UBLOX_CFG_PMP_USE_SERVICE_ID, 0); // Default 1
if (ok) ok = myLBand.setVal16(UBLOX_CFG_PMP_SERVICE_ID, 21845); // Default 50821
if (ok) ok = myLBand.setVal16(UBLOX_CFG_PMP_DATA_RATE, 2400); // Default 2400 bps
if (ok) ok = myLBand.setVal8(UBLOX_CFG_PMP_USE_DESCRAMBLER, 1); // Default 1
if (ok) ok = myLBand.setVal16(UBLOX_CFG_PMP_DESCRAMBLER_INIT, 26969); // Default 23560
if (ok) ok = myLBand.setVal8(UBLOX_CFG_PMP_USE_PRESCRAMBLING, 0); // Default 0
if (ok) ok = myLBand.setVal64(UBLOX_CFG_PMP_UNIQUE_WORD, 16238547128276412563ull);
if (ok) ok = myLBand.setVal(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_I2C, 1); // Ensure UBX-RXM-PMP is enabled on the I2C port
if (ok) ok = myLBand.setVal(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_UART1, 1); // Output UBX-RXM-PMP on UART1
if (ok) ok = myLBand.setVal(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_UART2, 1); // Output UBX-RXM-PMP on UART2
if (ok) ok = myLBand.setVal32(UBLOX_CFG_UART1_BAUDRATE, 38400); // match baudrate with ZED default
if (ok) ok = myLBand.setVal32(UBLOX_CFG_UART2_BAUDRATE, 38400); // match baudrate with ZED default
Serial.print(F("L-Band: configuration "));
Serial.println(OK(ok));
myLBand.softwareResetGNSSOnly(); // Do a restart
myLBand.setRXMPMPmessageCallbackPtr(&pushRXMPMP); // Call pushRXMPMP when new PMP data arrives. Push it to the GNSS
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void loop()
{
myGNSS.checkUblox(); // Check for the arrival of new GNSS data and process it.
myGNSS.checkCallbacks(); // Check if any GNSS callbacks are waiting to be processed.
myLBand.checkUblox(); // Check for the arrival of new PMP data and process it.
myLBand.checkCallbacks(); // Check if any LBand callbacks are waiting to be processed.
}
@@ -0,0 +1,24 @@
// You can set the information below after signing up with the u-blox Thingstream portal
// and adding a new New PointPerfect Thing
// https://portal.thingstream.io/app/location-services/things
// In the new PointPerfect Thing, you go to the credentials tab and copy and paste the IP Dynamic Keys here.
//
// The keys are valid from a particular GPS Week Number and Time of Week.
// Looking at the credentials tab, the current key expires 23:59 Feb 11th 2022.
// This means the next key is valid _from_ Midnight Feb 12th 2022.
// That is GPS Week 2196. The GPS Time of Week in seconds is 518418.
// Working backwards, the current key became valid exactly 4 weeks earlier (Midnight Jan 15th 2022).
//
// See: https://www.labsat.co.uk/index.php/en/gps-time-calculator
//
// The keys are given as: 32 hexadecimal digits = 128 bits = 16 Bytes
const uint8_t currentKeyLengthBytes = 16;
const char currentDynamicKey[] = "f742bd6b7248043177dd649141d8fb0b";
const uint16_t currentKeyGPSWeek = 2192;
const uint32_t currentKeyGPSToW = 518418;
const uint8_t nextKeyLengthBytes = 16;
const char nextDynamicKey[] = "8206........................29f4";
const uint16_t nextKeyGPSWeek = 2196;
const uint32_t nextKeyGPSToW = 518418;
@@ -40,6 +40,7 @@
0x10310022
0x10310024
0x10310025
0x10340014
0x10360002
0x10360003
0x10360004
@@ -50,7 +51,6 @@
0x10510003
0x10520005
0x10530005
0x10530006
0x10640002
0x10640003
0x10640005
@@ -60,26 +60,31 @@
0x10710001
0x10710002
0x10710004
0x10710005
0x10720001
0x10720002
0x10730001
0x10730002
0x10730004
0x10730005
0x10740001
0x10740002
0x10750001
0x10750002
0x10750004
0x10750005
0x10760001
0x10760002
0x10770001
0x10770002
0x10770004
0x10770005
0x10780001
0x10780002
0x10790001
0x10790002
0x10790004
0x10790005
0x107a0001
0x107a0002
0x10930003
@@ -114,6 +119,7 @@
0x2005000c
0x20050023
0x20050030
0x20050035
0x20060008
0x20060009
0x20060015
@@ -486,6 +492,21 @@
0x20910402
0x20910403
0x20910404
0x20910605
0x20910606
0x20910607
0x20910608
0x20910609
0x2091062a
0x2091062b
0x2091062c
0x2091062d
0x2091062e
0x20910634
0x20910635
0x20910636
0x20910637
0x20910638
0x20920001
0x20920002
0x20920003
@@ -0,0 +1,151 @@
0x1041000d
0x10410013
0x10510002
0x10510003
0x10520005
0x10530005
0x10530006
0x10640002
0x10640003
0x10640005
0x10640006
0x10650001
0x10650002
0x10710001
0x10720001
0x10730001
0x10740001
0x10750001
0x10760001
0x10770001
0x10780001
0x10790001
0x107a0001
0x10a20001
0x10a20002
0x10a3002e
0x10a3002f
0x10a30030
0x10a30031
0x10a30032
0x10a30033
0x10a30034
0x10a30035
0x10b10014
0x10b10016
0x10b10019
0x10c70001
0x10c70002
0x10d0000c
0x10d0000d
0x10d0000e
0x20210003
0x20410001
0x20410002
0x20410010
0x20510001
0x20520002
0x20520003
0x20520004
0x20530002
0x20530003
0x20530004
0x20640001
0x20910187
0x20910188
0x20910189
0x2091018a
0x2091018b
0x20910196
0x20910197
0x20910198
0x20910199
0x2091019a
0x2091019b
0x2091019c
0x2091019d
0x2091019e
0x2091019f
0x209101a0
0x209101a1
0x209101a2
0x209101a3
0x209101a4
0x209101a5
0x209101a6
0x209101a7
0x209101a8
0x209101a9
0x209101b4
0x209101b5
0x209101b6
0x209101b7
0x209101b8
0x209101b9
0x209101ba
0x209101bb
0x209101bc
0x209101bd
0x20910231
0x20910232
0x20910233
0x20910234
0x20910235
0x20910259
0x2091025a
0x2091025b
0x2091025c
0x2091025d
0x2091031d
0x2091031e
0x2091031f
0x20910320
0x20910321
0x20920001
0x20920002
0x20920003
0x20920004
0x20920005
0x20920006
0x20920007
0x20920008
0x20920009
0x2092000a
0x20a20003
0x20a20005
0x20a30036
0x20a30037
0x20a30038
0x20c70003
0x20d0000b
0x30210001
0x30210002
0x3065000a
0x3065000b
0x3065000c
0x30a20004
0x30b10012
0x30b10013
0x30b10015
0x30b10017
0x40520001
0x40530001
0x40b10011
0x40d0000f
0x5065000d
0x5065000e
0x5065000f
0x50650010
0x50650011
0x50650012
0x50650013
0x50650014
0x50650015
0x50650016
0x50650017
0x50650018
0x50b1001a
0x50c70004
0x50c70005
0x50c70006
0x50c70007
@@ -6,6 +6,9 @@
0x10110013
0x10110025
0x10110061
0x101100d7
0x10170001
0x10170002
0x10220001
0x10220002
0x10220003
@@ -47,7 +50,6 @@
0x10510003
0x10520005
0x10530005
0x10530006
0x10640002
0x10640003
0x10640005
@@ -57,30 +59,35 @@
0x10710001
0x10710002
0x10710004
0x10710005
0x10720001
0x10720002
0x10720004
0x10730001
0x10730002
0x10730004
0x10730005
0x10740001
0x10740002
0x10740004
0x10750001
0x10750002
0x10750004
0x10750005
0x10760001
0x10760002
0x10760004
0x10770001
0x10770002
0x10770004
0x10770005
0x10780001
0x10780002
0x10780004
0x10790001
0x10790002
0x10790004
0x10790005
0x107a0001
0x107a0002
0x107a0004
@@ -115,6 +122,7 @@
0x10de0002
0x10de0003
0x10de0004
0x10f60009
0x20030001
0x20030002
0x20030006
@@ -126,6 +134,7 @@
0x2005000c
0x20050023
0x20050030
0x20050035
0x20090009
0x20110011
0x2011001c
@@ -259,6 +268,11 @@
0x20910080
0x20910081
0x20910082
0x20910083
0x20910084
0x20910085
0x20910086
0x20910087
0x20910088
0x20910089
0x2091008a
@@ -539,6 +553,176 @@
0x20910402
0x20910403
0x20910404
0x20910415
0x20910416
0x20910417
0x20910418
0x20910419
0x20910430
0x20910431
0x20910432
0x20910433
0x20910434
0x20910435
0x20910436
0x20910437
0x20910438
0x20910439
0x20910465
0x20910466
0x20910467
0x20910468
0x20910469
0x20910475
0x20910476
0x20910477
0x20910478
0x20910479
0x20910480
0x20910481
0x20910482
0x20910483
0x20910484
0x20910485
0x20910486
0x20910487
0x20910488
0x20910489
0x20910490
0x20910491
0x20910492
0x20910493
0x20910494
0x20910495
0x20910496
0x20910497
0x20910498
0x20910499
0x20910500
0x20910501
0x20910502
0x20910503
0x20910504
0x20910505
0x20910506
0x20910507
0x20910508
0x20910509
0x20910510
0x20910511
0x20910512
0x20910513
0x20910514
0x20910515
0x20910516
0x20910517
0x20910518
0x20910519
0x20910520
0x20910521
0x20910522
0x20910523
0x20910524
0x20910525
0x20910526
0x20910527
0x20910528
0x20910529
0x20910530
0x20910531
0x20910532
0x20910533
0x20910534
0x20910535
0x20910536
0x20910537
0x20910538
0x20910539
0x20910540
0x20910541
0x20910542
0x20910543
0x20910544
0x20910545
0x20910546
0x20910547
0x20910548
0x20910549
0x20910550
0x20910551
0x20910552
0x20910553
0x20910554
0x20910555
0x20910556
0x20910557
0x20910558
0x20910559
0x20910560
0x20910561
0x20910562
0x20910563
0x20910564
0x20910565
0x20910566
0x20910567
0x20910568
0x20910569
0x20910575
0x20910576
0x20910577
0x20910578
0x20910579
0x20910605
0x20910606
0x20910607
0x20910608
0x20910609
0x20910652
0x20910653
0x20910654
0x20910655
0x20910656
0x20910657
0x20910658
0x20910659
0x2091065a
0x2091065b
0x2091065c
0x2091065d
0x2091065e
0x2091065f
0x20910660
0x20910661
0x20910662
0x20910663
0x20910664
0x20910665
0x20910666
0x20910667
0x20910668
0x20910669
0x2091066a
0x20910670
0x20910671
0x20910672
0x20910673
0x20910674
0x2091067f
0x20910680
0x20910681
0x20910682
0x20910683
0x2091069d
0x2091069e
0x2091069f
0x209106a0
0x209106a1
0x209106b6
0x209106b7
0x209106b8
0x209106b9
0x209106ba
0x20920001
0x20920002
0x20920003
@@ -562,6 +746,7 @@
0x20a30054
0x20a30055
0x20a30056
0x20a70001
0x20c70003
0x30050001
0x30090001
@@ -575,6 +760,7 @@
0x30210001
0x30210002
0x3025003b
0x30370008
0x3065000a
0x3065000b
0x3065000c
@@ -583,6 +769,8 @@
0x30de0005
0x30de0006
0x30de0007
0x30f6000a
0x30f6000b
0x40030003
0x40030004
0x40030005
+67
View File
@@ -24,6 +24,7 @@
0x10110019
0x10110025
0x10110061
0x101100d7
0x10170001
0x10170002
0x10220001
@@ -82,30 +83,35 @@
0x10710001
0x10710002
0x10710004
0x10710005
0x10720001
0x10720002
0x10720004
0x10730001
0x10730002
0x10730004
0x10730005
0x10740001
0x10740002
0x10740004
0x10750001
0x10750002
0x10750004
0x10750005
0x10760001
0x10760002
0x10760004
0x10770001
0x10770002
0x10770004
0x10770005
0x10780001
0x10780002
0x10780004
0x10790001
0x10790002
0x10790004
0x10790005
0x107a0001
0x107a0002
0x107a0004
@@ -135,8 +141,14 @@
0x10a30033
0x10a30034
0x10a30035
0x10b10014
0x10b10016
0x10b10019
0x10c70001
0x10c70002
0x10d0000c
0x10d0000d
0x10d0000e
0x10de0002
0x10de0003
0x10de0004
@@ -562,6 +574,11 @@
0x2091031a
0x2091031b
0x2091031c
0x2091031d
0x2091031e
0x2091031f
0x20910320
0x20910321
0x20910336
0x20910337
0x20910338
@@ -627,6 +644,11 @@
0x20910402
0x20910403
0x20910404
0x20910415
0x20910416
0x20910417
0x20910418
0x20910419
0x20910430
0x20910431
0x20910432
@@ -677,11 +699,21 @@
0x20910507
0x20910508
0x20910509
0x20910510
0x20910511
0x20910512
0x20910513
0x20910514
0x20910515
0x20910516
0x20910517
0x20910518
0x20910519
0x20910520
0x20910521
0x20910522
0x20910523
0x20910524
0x20910525
0x20910526
0x20910527
@@ -727,16 +759,31 @@
0x20910567
0x20910568
0x20910569
0x20910575
0x20910576
0x20910577
0x20910578
0x20910579
0x20910590
0x20910591
0x20910592
0x20910593
0x20910594
0x20910605
0x20910606
0x20910607
0x20910608
0x20910609
0x20910610
0x20910611
0x20910612
0x20910613
0x20910614
0x2091062a
0x2091062b
0x2091062c
0x2091062d
0x2091062e
0x20910634
0x20910635
0x20910636
@@ -782,6 +829,16 @@
0x2091068b
0x2091068c
0x2091068d
0x2091069d
0x2091069e
0x2091069f
0x209106a0
0x209106a1
0x209106b6
0x209106b7
0x209106b8
0x209106b9
0x209106ba
0x20920001
0x20920002
0x20920003
@@ -805,7 +862,9 @@
0x20a30054
0x20a30055
0x20a30056
0x20a70001
0x20c70003
0x20d0000b
0x30050001
0x30060007
0x3006000a
@@ -827,11 +886,16 @@
0x30210001
0x30210002
0x3025003b
0x30370008
0x3065000a
0x3065000b
0x3065000c
0x30930033
0x30a20004
0x30b10012
0x30b10013
0x30b10015
0x30b10017
0x30de0005
0x30de0006
0x30de0007
@@ -887,6 +951,8 @@
0x40240053
0x40520001
0x40530001
0x40b10011
0x40d0000f
0x40de0008
0x5005002a
0x5005002b
@@ -907,6 +973,7 @@
0x50650016
0x50650017
0x50650018
0x50b1001a
0x50c70004
0x50c70005
0x50c70006
+146 -9
View File
@@ -26,10 +26,15 @@ UBX_NAV_VELECEF_data_t KEYWORD1
UBX_NAV_VELNED_data_t KEYWORD1
UBX_NAV_HPPOSECEF_data_t KEYWORD1
UBX_NAV_HPPOSLLH_data_t KEYWORD1
UBX_NAV_PVAT_data_t KEYWORD1
UBX_NAV_CLOCK_data_t KEYWORD1
UBX_NAV_SAT_data_t KEYWORD1
UBX_NAV_RELPOSNED_data_t KEYWORD1
UBX_NAV_TIMELS_data_t KEYWORD1
UBX_NAV_AOPSTATUS_data_t KEYWORD1
UBX_RXM_PMP_data_t KEYWORD1
UBX_RXM_PMP_message_data_t KEYWORD1
UBX_RXM_SFRBX_data_t KEYWORD1
UBX_RXM_RAWX_data_t KEYWORD1
@@ -45,6 +50,8 @@ UBX_HNR_PVT_data_t KEYWORD1
UBX_HNR_ATT_data_t KEYWORD1
UBX_HNR_INS_data_t KEYWORD1
NMEA_GGA_data_t KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
@@ -90,6 +97,13 @@ checkCallbacks KEYWORD2
pushRawData KEYWORD2
pushAssistNowData KEYWORD2
setUTCTimeAssistance KEYWORD2
setPositionAssistanceXYZ KEYWORD2
setPositionAssistanceLLH KEYWORD2
findMGAANOForDate KEYWORD2
readNavigationDatabase KEYWORD2
setFileBufferSize KEYWORD2
getFileBufferSize KEYWORD2
extractFileBufferData KEYWORD2
@@ -111,9 +125,11 @@ setUART2Output KEYWORD2
setUSBOutput KEYWORD2
setSPIOutput KEYWORD2
setNMEAOutputPort KEYWORD2
setOutputPort KEYWORD2
factoryReset KEYWORD2
hardReset KEYWORD2
softwareResetGNSSOnly KEYWORD2
factoryDefault KEYWORD2
saveConfiguration KEYWORD2
@@ -132,6 +148,7 @@ setSurveyMode KEYWORD2
enableSurveyMode KEYWORD2
disableSurveyMode KEYWORD2
setStaticPosition KEYWORD2
setDGNSSConfiguration KEYWORD2
getProtocolVersionHigh KEYWORD2
getProtocolVersionLow KEYWORD2
@@ -153,30 +170,54 @@ getDynamicModel KEYWORD2
resetOdometer KEYWORD2
enableGNSS KEYWORD2
isGNSSenabled KEYWORD2
resetIMUalignment KEYWORD2
getESFAutoAlignment KEYWORD2
setESFAutoAlignment KEYWORD2
getTimePulseParameters KEYWORD2
setTimePulseParameters KEYWORD2
getAckAiding KEYWORD2
setAckAiding KEYWORD2
getAopCfg KEYWORD2
setAopCfg KEYWORD2
setDynamicSPARTNKey KEYWORD2
setDynamicSPARTNKeys KEYWORD2
createKey KEYWORD2
getVal KEYWORD2
getVal8 KEYWORD2
getVal16 KEYWORD2
getVal32 KEYWORD2
getVal64 KEYWORD2
setVal KEYWORD2
setVal8 KEYWORD2
setVal16 KEYWORD2
setVal32 KEYWORD2
setVal64 KEYWORD2
newCfgValset8 KEYWORD2
newCfgValset16 KEYWORD2
newCfgValset32 KEYWORD2
newCfgValset64 KEYWORD2
addCfgValset8 KEYWORD2
addCfgValset16 KEYWORD2
addCfgValset32 KEYWORD2
addCfgValset64 KEYWORD2
sendCfgValset8 KEYWORD2
sendCfgValset16 KEYWORD2
sendCfgValset32 KEYWORD2
sendCfgValset64 KEYWORD2
getNAVPOSECEF KEYWORD2
setAutoNAVPOSECEF KEYWORD2
setAutoNAVPOSECEFrate KEYWORD2
setAutoNAVPOSECEFcallback KEYWORD2
setAutoNAVPOSECEFcallbackPtr KEYWORD2
assumeAutoNAVPOSECEF KEYWORD2
initPacketUBXNAVPOSECEF KEYWORD2
flushNAVPOSECEF KEYWORD2
@@ -186,6 +227,7 @@ getNAVSTATUS KEYWORD2
setAutoNAVSTATUS KEYWORD2
setAutoNAVSTATUSrate KEYWORD2
setAutoNAVSTATUScallback KEYWORD2
setAutoNAVSTATUScallbackPtr KEYWORD2
assumeAutoNAVSTATUS KEYWORD2
initPacketUBXNAVSTATUS KEYWORD2
flushNAVSTATUS KEYWORD2
@@ -195,6 +237,7 @@ getDOP KEYWORD2
setAutoDOP KEYWORD2
setAutoDOPrate KEYWORD2
setAutoDOPcallback KEYWORD2
setAutoDOPcallbackPtr KEYWORD2
assumeAutoDOP KEYWORD2
initPacketUBXNAVDOP KEYWORD2
flushDOP KEYWORD2
@@ -205,6 +248,7 @@ getNAVATT KEYWORD2
setAutoNAVATT KEYWORD2
setAutoNAVATTrate KEYWORD2
setAutoNAVATTcallback KEYWORD2
setAutoNAVATTcallbackPtr KEYWORD2
assumeAutoNAVATT KEYWORD2
initPacketUBXNAVATT KEYWORD2
flushNAVATT KEYWORD2
@@ -214,6 +258,7 @@ getPVT KEYWORD2
setAutoPVT KEYWORD2
setAutoPVTrate KEYWORD2
setAutoPVTcallback KEYWORD2
setAutoPVTcallbackPtr KEYWORD2
assumeAutoPVT KEYWORD2
initPacketUBXNAVPVT KEYWORD2
flushPVT KEYWORD2
@@ -223,6 +268,7 @@ getNAVODO KEYWORD2
setAutoNAVODO KEYWORD2
setAutoNAVODOrate KEYWORD2
setAutoNAVODOcallback KEYWORD2
setAutoNAVODOcallbackPtr KEYWORD2
assumeAutoNAVODO KEYWORD2
initPacketUBXNAVODO KEYWORD2
flushNAVODO KEYWORD2
@@ -232,6 +278,7 @@ getNAVVELECEF KEYWORD2
setAutoNAVVELECEF KEYWORD2
setAutoNAVVELECEFrate KEYWORD2
setAutoNAVVELECEFcallback KEYWORD2
setAutoNAVVELECEFcallbackPtr KEYWORD2
assumeAutoNAVVELECEF KEYWORD2
initPacketUBXNAVVELECEF KEYWORD2
flushNAVVELECEF KEYWORD2
@@ -241,6 +288,7 @@ getNAVVELNED KEYWORD2
setAutoNAVVELNED KEYWORD2
setAutoNAVVELNEDrate KEYWORD2
setAutoNAVVELNEDcallback KEYWORD2
setAutoNAVVELNEDcallbackPtr KEYWORD2
assumeAutoNAVVELNED KEYWORD2
initPacketUBXNAVVELNED KEYWORD2
flushNAVVELNED KEYWORD2
@@ -250,6 +298,7 @@ getNAVHPPOSECEF KEYWORD2
setAutoNAVHPPOSECEF KEYWORD2
setAutoNAVHPPOSECEFrate KEYWORD2
setAutoNAVHPPOSECEFcallback KEYWORD2
setAutoNAVHPPOSECEFcallbackPtr KEYWORD2
assumeAutoNAVHPPOSECEF KEYWORD2
initPacketUBXNAVHPPOSECEF KEYWORD2
flushNAVHPPOSECEF KEYWORD2
@@ -259,15 +308,27 @@ getHPPOSLLH KEYWORD2
setAutoHPPOSLLH KEYWORD2
setAutoHPPOSLLHrate KEYWORD2
setAutoHPPOSLLHcallback KEYWORD2
setAutoHPPOSLLHcallbackPtr KEYWORD2
assumeAutoHPPOSLLH KEYWORD2
initPacketUBXNAVHPPOSLLH KEYWORD2
flushHPPOSLLH KEYWORD2
logNAVHPPOSLLH KEYWORD2
getNAVPVAT KEYWORD2
setAutoNAVPVAT KEYWORD2
setAutoNAVPVAT KEYWORD2
setAutoNAVPVATrate KEYWORD2
setAutoNAVPVATcallback KEYWORD2
setAutoNAVPVATcallbackPtr KEYWORD2
assumeAutoNAVPVAT KEYWORD2
flushNAVPVAT KEYWORD2
logNAVPVAT KEYWORD2
getNAVCLOCK KEYWORD2
setAutoNAVCLOCK KEYWORD2
setAutoNAVCLOCKrate KEYWORD2
setAutoNAVCLOCKcallback KEYWORD2
setAutoNAVCLOCKcallbackPtr KEYWORD2
assumeAutoNAVCLOCK KEYWORD2
initPacketUBXNAVCLOCK KEYWORD2
flushNAVCLOCK KEYWORD2
@@ -281,19 +342,44 @@ initPacketUBXNAVTIMELS KEYWORD2
getSurveyStatus KEYWORD2
initPacketUBXNAVSVIN KEYWORD2
getNAVSAT KEYWORD2
setAutoNAVSAT KEYWORD2
setAutoNAVSATrate KEYWORD2
setAutoNAVSATcallback KEYWORD2
setAutoNAVSATcallbackPtr KEYWORD2
assumeAutoNAVSAT KEYWORD2
initPacketUBXNAVSAT KEYWORD2
flushNAVSAT KEYWORD2
logNAVSAT KEYWORD2
getRELPOSNED KEYWORD2
setAutoRELPOSNED KEYWORD2
setAutoRELPOSNEDrate KEYWORD2
setAutoRELPOSNEDcallback KEYWORD2
setAutoRELPOSNEDcallbackPtr KEYWORD2
assumeAutoRELPOSNED KEYWORD2
initPacketUBXNAVRELPOSNED KEYWORD2
flushNAVRELPOSNED KEYWORD2
logNAVRELPOSNED KEYWORD2
getAOPSTATUS KEYWORD2
setAutoAOPSTATUS KEYWORD2
setAutoAOPSTATUSrate KEYWORD2
setAutoAOPSTATUScallback KEYWORD2
setAutoAOPSTATUScallbackPtr KEYWORD2
assumeAutoAOPSTATUS KEYWORD2
initPacketUBXAOPSTATUS KEYWORD2
flushAOPSTATUS KEYWORD2
logAOPSTATUS KEYWORD2
setRXMPMPcallbackPtr KEYWORD2
setRXMPMPmessageCallbackPtr KEYWORD2
getRXMSFRBX KEYWORD2
setAutoRXMSFRBX KEYWORD2
setAutoRXMSFRBXrate KEYWORD2
setAutoRXMSFRBXcallback KEYWORD2
setAutoRXMSFRBXcallbackPtr KEYWORD2
assumeAutoRXMSFRBX KEYWORD2
initPacketUBXRXMSFRBX KEYWORD2
flushRXMSFRBX KEYWORD2
@@ -303,6 +389,7 @@ getRXMRAWX KEYWORD2
setAutoRXMRAWX KEYWORD2
setAutoRXMRAWXrate KEYWORD2
setAutoRXMRAWXcallback KEYWORD2
setAutoRXMRAWXcallbackPtr KEYWORD2
assumeAutoRXMRAWX KEYWORD2
initPacketUBXRXMRAWX KEYWORD2
flushRXMRAWX KEYWORD2
@@ -312,6 +399,7 @@ getTIMTM2 KEYWORD2
setAutoTIMTM2 KEYWORD2
setAutoTIMTM2rate KEYWORD2
setAutoTIMTM2callback KEYWORD2
setAutoTIMTM2callbackPtr KEYWORD2
assumeAutoTIMTM2 KEYWORD2
initPacketUBXTIMTM2 KEYWORD2
flushTIMTM2 KEYWORD2
@@ -322,6 +410,7 @@ getESFALG KEYWORD2
setAutoESFALG KEYWORD2
setAutoESFALGrate KEYWORD2
setAutoESFALGcallback KEYWORD2
setAutoESFALGcallbackPtr KEYWORD2
assumeAutoESFALG KEYWORD2
initPacketUBXESFALG KEYWORD2
flushESFALG KEYWORD2
@@ -332,6 +421,7 @@ getESFSTATUS KEYWORD2
setAutoESFSTATUS KEYWORD2
setAutoESFSTATUSrate KEYWORD2
setAutoESFSTATUScallback KEYWORD2
setAutoESFSTATUScallbackPtr KEYWORD2
assumeAutoESFSTATUS KEYWORD2
initPacketUBXESFSTATUS KEYWORD2
flushESFSTATUS KEYWORD2
@@ -342,6 +432,7 @@ getESFINS KEYWORD2
setAutoESFINS KEYWORD2
setAutoESFINSrate KEYWORD2
setAutoESFINScallback KEYWORD2
setAutoESFINScallbackPtr KEYWORD2
assumeAutoESFINS KEYWORD2
initPacketUBXESFINS KEYWORD2
flushESFINS KEYWORD2
@@ -352,6 +443,7 @@ getESFMEAS KEYWORD2
setAutoESFMEAS KEYWORD2
setAutoESFMEASrate KEYWORD2
setAutoESFMEAScallback KEYWORD2
setAutoESFMEAScallbackPtr KEYWORD2
assumeAutoESFMEAS KEYWORD2
initPacketUBXESFMEAS KEYWORD2
flushESFMEAS KEYWORD2
@@ -362,19 +454,18 @@ getESFRAW KEYWORD2
setAutoESFRAW KEYWORD2
setAutoESFRAWrate KEYWORD2
setAutoESFRAWcallback KEYWORD2
setAutoESFRAWcallbackPtr KEYWORD2
assumeAutoESFRAW KEYWORD2
initPacketUBXESFRAW KEYWORD2
flushESFRAW KEYWORD2
logESFRAW KEYWORD2
getESFAutoAlignment KEYWORD2
setESFAutoAlignment KEYWORD2
getHNRAtt KEYWORD2
getHNRATT KEYWORD2
setAutoHNRATT KEYWORD2
setAutoHNRATTrate KEYWORD2
setAutoHNRATTcallback KEYWORD2
setAutoHNRATTcallbackPtr KEYWORD2
assumeAutoHNRATT KEYWORD2
initPacketUBXHNRATT KEYWORD2
flushHNRATT KEYWORD2
@@ -385,6 +476,7 @@ getHNRINS KEYWORD2
setAutoHNRINS KEYWORD2
setAutoHNRINSrate KEYWORD2
setAutoHNRINScallback KEYWORD2
setAutoHNRINScallbackPtr KEYWORD2
assumeAutoHNRINS KEYWORD2
initPacketUBXHNRINS KEYWORD2
flushHNRINS KEYWORD2
@@ -394,16 +486,12 @@ getHNRPVT KEYWORD2
setAutoHNRPVT KEYWORD2
setAutoHNRPVTrate KEYWORD2
setAutoHNRPVTcallback KEYWORD2
setAutoHNRPVTcallbackPtr KEYWORD2
assumeAutoHNRPVT KEYWORD2
initPacketUBXHNRPVT KEYWORD2
flushHNRPVT KEYWORD2
logHNRPVT KEYWORD2
setNMEALoggingMask KEYWORD2
getNMEALoggingMask KEYWORD2
setProcessNMEAMask KEYWORD2
getProcessNMEAMask KEYWORD2
setNavigationFrequency KEYWORD2
getNavigationFrequency KEYWORD2
setMeasurementRate KEYWORD2
@@ -479,6 +567,11 @@ getMeanSeaLevelHp KEYWORD2
getHorizontalAccuracy KEYWORD2
getVerticalAccuracy KEYWORD2
getVehicleRoll KEYWORD2
getVehiclePitch KEYWORD2
getVehicleHeading KEYWORD2
getMotionHeading KEYWORD2
getSurveyInActive KEYWORD2
getSurveyInValid KEYWORD2
getSurveyInObservationTime KEYWORD2
@@ -491,6 +584,9 @@ getRelPosAccN KEYWORD2
getRelPosAccE KEYWORD2
getRelPosAccD KEYWORD2
getAOPSTATUSuseAOP KEYWORD2
getAOPSTATUSstatus KEYWORD2
getESFroll KEYWORD2
getESFpitch KEYWORD2
getESFyaw KEYWORD2
@@ -504,6 +600,21 @@ getHNRroll KEYWORD2
getHNRpitch KEYWORD2
getHNRheading KEYWORD2
setNMEALoggingMask KEYWORD2
getNMEALoggingMask KEYWORD2
setProcessNMEAMask KEYWORD2
getProcessNMEAMask KEYWORD2
setMainTalkerID KEYWORD2
setHighPrecisionMode KEYWORD2
getLatestNMEAGPGGA KEYWORD2
setNMEAGPGGAcallback KEYWORD2
setNMEAGPGGAcallbackPtr KEYWORD2
getLatestNMEAGNGGA KEYWORD2
setNMEAGNGGAcallback KEYWORD2
setNMEAGNGGAcallbackPtr KEYWORD2
extractLong KEYWORD2
extractSignedLong KEYWORD2
extractInt KEYWORD2
@@ -533,6 +644,7 @@ SFE_UBLOX_STATUS_DATA_OVERWRITTEN LITERAL1
COM_TYPE_UBX LITERAL1
COM_TYPE_NMEA LITERAL1
COM_TYPE_RTCM3 LITERAL1
COM_TYPE_SPARTN LITERAL1
COM_PORT_I2C LITERAL1
COM_PORT_UART1 LITERAL1
@@ -611,6 +723,7 @@ UBX_NAV_HPPOSLLH LITERAL1
UBX_NAV_ODO LITERAL1
UBX_NAV_POSECEF LITERAL1
UBX_NAV_PVT LITERAL1
UBX_NAV_PVAT LITERAL1
UBX_NAV_RELPOSNED LITERAL1
UBX_NAV_RESETODO LITERAL1
UBX_NAV_STATUS LITERAL1
@@ -621,6 +734,7 @@ UBX_NAV_VELNED LITERAL1
UBX_RXM_RAWX LITERAL1
UBX_RXM_SFRBX LITERAL1
UBX_RXM_SPARTN LITERAL1
UBX_TIM_TM2 LITERAL1
@@ -665,6 +779,8 @@ DYN_MODEL_AIRBORNE2g LITERAL1
DYN_MODEL_AIRBORNE4g LITERAL1
DYN_MODEL_WRIST LITERAL1
DYN_MODEL_BIKE LITERAL1
DYN_MODEL_MOWER LITERAL1
DYN_MODEL_ESCOOTER LITERAL1
DYN_MODEL_UNKNOWN LITERAL1
SFE_UBLOX_GNSS_ID_GPS LITERAL1
@@ -675,4 +791,25 @@ SFE_UBLOX_GNSS_ID_IMES LITERAL1
SFE_UBLOX_GNSS_ID_QZSS LITERAL1
SFE_UBLOX_GNSS_ID_GLONASS LITERAL1
DAYS_SINCE_MONTH LITERAL1
SFE_UBLOX_MGA_ASSIST_ACK_NO LITERAL1
SFE_UBLOX_MGA_ASSIST_ACK_YES LITERAL1
SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE LITERAL1
SFE_UBLOX_MGA_ACK_INFOCODE_ACCEPTED LITERAL1
SFE_UBLOX_MGA_ACK_INFOCODE_NO_TIME LITERAL1
SFE_UBLOX_MGA_ACK_INFOCODE_NOT_SUPPORTED LITERAL1
SFE_UBLOX_MGA_ACK_INFOCODE_SIZE_MISMATCH LITERAL1
SFE_UBLOX_MGA_ACK_INFOCODE_NOT_STORED LITERAL1
SFE_UBLOX_MGA_ACK_INFOCODE_NOT_READY LITERAL1
SFE_UBLOX_MGA_ACK_INFOCODE_TYPE_UNKNOWN LITERAL1
SFE_UBLOX_MAIN_TALKER_ID_DEFAULT LITERAL1
SFE_UBLOX_MAIN_TALKER_ID_GP LITERAL1
SFE_UBLOX_MAIN_TALKER_ID_GL LITERAL1
SFE_UBLOX_MAIN_TALKER_ID_GN LITERAL1
SFE_UBLOX_MAIN_TALKER_ID_GA LITERAL1
SFE_UBLOX_MAIN_TALKER_ID_GB LITERAL1
SFE_UBLOX_MAIN_TALKER_ID_GQ LITERAL1
SFE_UBLOX_DGNSS_MODE_FLOAT LITERAL1
SFE_UBLOX_DGNSS_MODE_FIXED LITERAL1
+3 -3
View File
@@ -1,9 +1,9 @@
name=SparkFun u-blox GNSS Arduino Library
version=2.0.18
version=2.2.1
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/>
paragraph=An Arduino Library to enable I2C, Serial and SPI communication for both NMEA reception and binary UBX sending to u-blox modules. Useful for interfacing to the <a href="https://www.sparkfun.com/products/15136">SparkFun GPS-RTK2</a> ZED-F9P, <a href="https://www.sparkfun.com/products/15005">SparkFun GPS-RTK</a> NEO-M8P-2, the <a href="https://www.sparkfun.com/products/15210">SparkFun SAM-M8Q</a>, and the <a href="https://www.sparkfun.com/products/15193">SparkFun ZOE-M8Q</a>. Library also works with other u-blox based boards.<br/><br/>The ZED-F9P and NEO-M8P-2 modules are top-of-the-line modules for high accuracy GNSS and GPS location solutions including RTK. The ZED-F9P is unique in that it is capable of both rover and base station operations allowing the module to become a base station and produce RTCM 3.x correction data.<br/>
sentence=Library for I2C, Serial and SPI Communication with u-blox GNSS modules<br/><br/>
paragraph=An Arduino Library to support the full range of u-blox GNSS modules, using both NMEA and UBX protocols over I2C, Serial and SPI. Useful for interfacing to the <a href="https://www.sparkfun.com/products/15136">SparkFun GPS-RTK2</a> ZED-F9P, <a href="https://www.sparkfun.com/products/15005">SparkFun GPS-RTK</a> NEO-M8P-2, <a href="https://www.sparkfun.com/products/15210">SparkFun SAM-M8Q</a>, <a href="https://www.sparkfun.com/products/15193">SparkFun ZOE-M8Q</a> and all the other SparkFun u-blox GNSS Breakouts.<br/><br/>The ZED-F9P and NEO-M8P-2 modules are top-of-the-line modules for high accuracy GNSS and GPS location solutions including RTK. The ZED-F9P is unique in that it is capable of both rover and base station operations allowing the module to become a base station and produce RTCM 3.x correction data.<br/><br/>Need support for RTK NTRIP Caster services like RTK2go, Emlid Caster and Skylark? This library has functions, callbacks and tried-and-tested examples to let you push RTCM correction data to your module seamlessly!<br/>
category=Sensors
url=https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library
architectures=*
File diff suppressed because it is too large Load Diff
+300 -41
View File
@@ -60,7 +60,7 @@
//#define SFE_UBLOX_REDUCED_PROG_MEM // Uncommenting this line will delete the minor debug messages to save memory
// The code just about fills the program memory on the ATmega328P (Arduino Uno), so let's delete the minor debug messages anyway
#if !defined(SFE_UBLOX_REDUCED_PROG_MEM) && defined(ARDUINO_AVR_UNO)
#if !defined(SFE_UBLOX_REDUCED_PROG_MEM) && defined(ARDUINO_ARCH_AVR)
#define SFE_UBLOX_REDUCED_PROG_MEM
#endif
@@ -295,6 +295,7 @@ const uint8_t UBX_LOG_STRING = 0x04; //Store arbitrary string on on-board fl
// Class: MGA
// The following are used to configure MGA UBX messages (Multiple GNSS Assistance Messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 34)
const uint8_t UBX_MGA_ACK_DATA0 = 0x60; // Multiple GNSS Acknowledge message
const uint8_t UBX_MGA_ANO = 0x20; // Multiple GNSS AssistNow Offline assistance - NOT SUPPORTED BY THE ZED-F9P! "The ZED-F9P supports AssistNow Online only."
const uint8_t UBX_MGA_BDS_EPH = 0x03; // BDS Ephemeris Assistance
const uint8_t UBX_MGA_BDS_ALM = 0x03; // BDS Almanac Assistance
const uint8_t UBX_MGA_BDS_HEALTH = 0x03; // BDS Health Assistance
@@ -337,6 +338,8 @@ const uint8_t UBX_MON_PATCH = 0x27; //Output information about installed patches
const uint8_t UBX_MON_RF = 0x38; // RF information
const uint8_t UBX_MON_RXBUF = 0x07; // Receiver Buffer Status
const uint8_t UBX_MON_RXR = 0x21; // Receiver Status Information
const uint8_t UBX_MON_SPAN = 0x31; // Signal characteristics
const uint8_t UBX_MON_SYS = 0x39; // Current system performance information
const uint8_t UBX_MON_TXBUF = 0x08; // Transmitter Buffer Status. Used for query tx buffer size/state.
const uint8_t UBX_MON_VER = 0x04; // Receiver/Software Version. Used for obtaining Protocol Version.
@@ -351,9 +354,11 @@ const uint8_t UBX_NAV_HPPOSECEF = 0x13; //High Precision Position Solution in EC
const uint8_t UBX_NAV_HPPOSLLH = 0x14; // High Precision Geodetic Position Solution. Used for obtaining lat/long/alt in high precision
const uint8_t UBX_NAV_ODO = 0x09; // Odometer Solution
const uint8_t UBX_NAV_ORB = 0x34; // GNSS Orbit Database Info
const uint8_t UBX_NAV_PL = 0x62; // Protection Level Information
const uint8_t UBX_NAV_POSECEF = 0x01; // Position Solution in ECEF
const uint8_t UBX_NAV_POSLLH = 0x02; // Geodetic Position Solution
const uint8_t UBX_NAV_PVT = 0x07; // All the things! Position, velocity, time, PDOP, height, h/v accuracies, number of satellites. Navigation Position Velocity Time Solution.
const uint8_t UBX_NAV_PVAT = 0x17; // Navigation position velocity attitude time solution (ZED-F9R only)
const uint8_t UBX_NAV_RELPOSNED = 0x3C; // Relative Positioning Information in NED frame
const uint8_t UBX_NAV_RESETODO = 0x10; // Reset odometer
const uint8_t UBX_NAV_SAT = 0x35; // Satellite Information
@@ -368,15 +373,20 @@ const uint8_t UBX_NAV_TIMELS = 0x26; //Leap second event information
const uint8_t UBX_NAV_TIMEUTC = 0x21; // UTC Time Solution
const uint8_t UBX_NAV_VELECEF = 0x11; // Velocity Solution in ECEF
const uint8_t UBX_NAV_VELNED = 0x12; // Velocity Solution in NED
const uint8_t UBX_NAV_AOPSTATUS = 0x60; // AssistNow Autonomous status
// Class: RXM
// The following are used to configure the RXM UBX messages (receiver manager messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 36)
const uint8_t UBX_RXM_COR = 0x34; // Differential correction input status
const uint8_t UBX_RXM_MEASX = 0x14; // Satellite Measurements for RRLP
const uint8_t UBX_RXM_PMREQ = 0x41; //Requests a Power Management task (two differenent packet sizes)
const uint8_t UBX_RXM_PMP = 0x72; // PMP raw data (NEO-D9S) (two different versions) (packet size for version 0x01 is variable)
const uint8_t UBX_RXM_PMREQ = 0x41; // Requests a Power Management task (two different packet sizes)
const uint8_t UBX_RXM_RAWX = 0x15; // Multi-GNSS Raw Measurement Data
const uint8_t UBX_RXM_RLM = 0x59; // Galileo SAR Short-RLM report (two different packet sizes)
const uint8_t UBX_RXM_RTCM = 0x32; // RTCM input status
const uint8_t UBX_RXM_SFRBX = 0x13; //Boradcast Navigation Data Subframe
const uint8_t UBX_RXM_SFRBX = 0x13; // Broadcast Navigation Data Subframe
const uint8_t UBX_RXM_SPARTN = 0x33; // SPARTN input status
const uint8_t UBX_RXM_SPARTNKEY = 0x36; // Poll/transfer dynamic SPARTN keys
// Class: SEC
// The following are used to configure the SEC UBX messages (security feature messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 36)
@@ -435,6 +445,7 @@ const uint8_t COM_PORT_SPI = 4;
const uint8_t COM_TYPE_UBX = (1 << 0);
const uint8_t COM_TYPE_NMEA = (1 << 1);
const uint8_t COM_TYPE_RTCM3 = (1 << 5);
const uint8_t COM_TYPE_SPARTN = (1 << 6);
// Configuration Sub-Section mask definitions for saveConfigSelective (UBX-CFG-CFG)
const uint32_t VAL_CFG_SUBSEC_IOPORT = 0x00000001; // ioPort - communications port settings (causes IO system reset!)
@@ -466,7 +477,9 @@ enum dynModel // Possible values for the dynamic platform model, which provide m
DYN_MODEL_AIRBORNE2g, // Airborne <2g acceleration. Recommended for typical airborne environments. No 2D position fixes supported.
DYN_MODEL_AIRBORNE4g, // Airborne <4g acceleration. Only recommended for extremely dynamic environments. No 2D position fixes supported.
DYN_MODEL_WRIST, // Not supported in protocol versions less than 18. Only recommended for wrist worn applications. Receiver will filter out arm motion.
DYN_MODEL_BIKE, // Supported in protocol versions 19.2
DYN_MODEL_BIKE, // Supported in protocol versions 19.2. (not available in all products)
DYN_MODEL_MOWER, // Added in HPS 1.21 (not available in all products)
DYN_MODEL_ESCOOTER, // Added in HPS 1.21 (not available in all products)
DYN_MODEL_UNKNOWN = 255 // getDynamicModel will return 255 if sendCommand fails
};
@@ -496,6 +509,46 @@ enum sfe_ublox_ls_src_e
SFE_UBLOX_LS_SRC_UNKNOWN = 255
};
typedef enum
{
SFE_UBLOX_MGA_ASSIST_ACK_NO, // Do not expect UBX-MGA-ACK's. If the module outputs them, they will be ignored
SFE_UBLOX_MGA_ASSIST_ACK_YES, // Expect and check for UBX-MGA-ACK's
SFE_UBLOX_MGA_ASSIST_ACK_ENQUIRE // Check UBX-CFG-NAVX5 ackAiding to determine if UBX-MGA-ACK's are expected
} sfe_ublox_mga_assist_ack_e;
// The infoCode byte included in UBX-MGA-ACK-DATA0
enum sfe_ublox_mga_ack_infocode_e
{
SFE_UBLOX_MGA_ACK_INFOCODE_ACCEPTED,
SFE_UBLOX_MGA_ACK_INFOCODE_NO_TIME,
SFE_UBLOX_MGA_ACK_INFOCODE_NOT_SUPPORTED,
SFE_UBLOX_MGA_ACK_INFOCODE_SIZE_MISMATCH,
SFE_UBLOX_MGA_ACK_INFOCODE_NOT_STORED,
SFE_UBLOX_MGA_ACK_INFOCODE_NOT_READY,
SFE_UBLOX_MGA_ACK_INFOCODE_TYPE_UNKNOWN
};
// The mainTalkerId, set by UBX-CFG-NMEA setMainTalkerID
enum sfe_ublox_talker_ids_e
{
SFE_UBLOX_MAIN_TALKER_ID_DEFAULT,
SFE_UBLOX_MAIN_TALKER_ID_GP,
SFE_UBLOX_MAIN_TALKER_ID_GL,
SFE_UBLOX_MAIN_TALKER_ID_GN,
SFE_UBLOX_MAIN_TALKER_ID_GA,
SFE_UBLOX_MAIN_TALKER_ID_GB,
SFE_UBLOX_MAIN_TALKER_ID_GQ
};
// The DGNSS differential mode
enum sfe_ublox_dgnss_mode_e
{
SFE_UBLOX_DGNSS_MODE_FLOAT = 2, // No attempts are made to fix ambiguities
SFE_UBLOX_DGNSS_MODE_FIXED // Ambiguities are fixed whenever possible
};
//-=-=-=-=-
#ifndef MAX_PAYLOAD_SIZE
// v2.0: keep this for backwards-compatibility, but this is largely superseded by setPacketCfgPayloadSize
#define MAX_PAYLOAD_SIZE 256 // We need ~220 bytes for getProtocolVersion on most ublox modules
@@ -573,14 +626,16 @@ public:
#endif
// New in v2.0: allow the payload size for packetCfg to be changed
void setPacketCfgPayloadSize(size_t payloadSize); // Set packetCfgPayloadSize
bool 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); //Returns true if module is detected
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
bool begin(Stream &serialPort); //Returns true if module is detected
bool begin(Stream &serialPort, uint16_t maxWait = defaultMaxWait, bool assumeSuccess = false); // Returns true if module is detected
// SPI - supply instance of SPIClass, chip select pin and SPI speed (in Hz)
bool begin(SPIClass &spiPort, uint8_t csPin, uint32_t spiSpeed);
bool begin(SPIClass &spiPort, uint8_t csPin, uint32_t spiSpeed, uint16_t maxWait = defaultMaxWait, bool assumeSuccess = false);
void end(void); // Stop all automatic message processing. Free all used RAM
@@ -610,7 +665,7 @@ public:
int8_t getMaxNMEAByteCount(void);
// Returns true if device answers on _gpsI2Caddress address or via Serial
bool isConnected(uint16_t maxWait = 1100);
bool isConnected(uint16_t maxWait = defaultMaxWait);
// Enable debug messages using the chosen Serial port (Stream)
// Boards like the RedBoard Turbo use SerialUSB (not Serial).
@@ -683,6 +738,52 @@ public:
// Default to using a restart between transmissions. But processors like ESP32 seem to need a stop (#30). Set stop to true to use a stop instead.
bool pushRawData(uint8_t *dataBytes, size_t numDataBytes, bool stop = false);
// Push MGA AssistNow data to the module.
// Check for UBX-MGA-ACK responses if required (if mgaAck is YES or ENQUIRE).
// Wait for maxWait millis after sending each packet (if mgaAck is NO).
// Return how many bytes were pushed successfully.
// If skipTime is true, any UBX-MGA-INI-TIME_UTC or UBX-MGA-INI-TIME_GNSS packets found in the data will be skipped,
// allowing the user to override with their own time data with setUTCTimeAssistance.
// offset allows a sub-set of the data to be sent - starting from offset.
#define defaultMGAdelay 7 // Default to waiting for 7ms between each MGA message
size_t pushAssistNowData(const String &dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck = SFE_UBLOX_MGA_ASSIST_ACK_NO, uint16_t maxWait = defaultMGAdelay);
size_t pushAssistNowData(const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck = SFE_UBLOX_MGA_ASSIST_ACK_NO, uint16_t maxWait = defaultMGAdelay);
size_t pushAssistNowData(bool skipTime, const String &dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck = SFE_UBLOX_MGA_ASSIST_ACK_NO, uint16_t maxWait = defaultMGAdelay);
size_t pushAssistNowData(bool skipTime, const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck = SFE_UBLOX_MGA_ASSIST_ACK_NO, uint16_t maxWait = defaultMGAdelay);
size_t pushAssistNowData(size_t offset, bool skipTime, const String &dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck = SFE_UBLOX_MGA_ASSIST_ACK_NO, uint16_t maxWait = defaultMGAdelay);
size_t pushAssistNowData(size_t offset, bool skipTime, const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck = SFE_UBLOX_MGA_ASSIST_ACK_NO, uint16_t maxWait = defaultMGAdelay);
// Provide initial time assistance
#define defaultMGAINITIMEtAccS 2 // Default to setting the seconds time accuracy to 2 seconds
#define defaultMGAINITIMEtAccNs 0 // Default to setting the nanoseconds time accuracy to zero
#define defaultMGAINITIMEsource 0 // Set default source to none, i.e. on receipt of message (will be inaccurate!)
bool setUTCTimeAssistance(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, uint32_t nanos = 0,
uint16_t tAccS = defaultMGAINITIMEtAccS, uint32_t tAccNs = defaultMGAINITIMEtAccNs, uint8_t source = defaultMGAINITIMEsource,
sfe_ublox_mga_assist_ack_e mgaAck = SFE_UBLOX_MGA_ASSIST_ACK_NO, uint16_t maxWait = defaultMGAdelay);
// Provide initial position assistance
// The units for ecefX/Y/Z and posAcc (stddev) are cm.
bool setPositionAssistanceXYZ(int32_t ecefX, int32_t ecefY, int32_t ecefZ, uint32_t posAcc, sfe_ublox_mga_assist_ack_e mgaAck = SFE_UBLOX_MGA_ASSIST_ACK_NO, uint16_t maxWait = defaultMGAdelay);
// The units for lat and lon are degrees * 1e-7 (WGS84)
// The units for alt (WGS84) and posAcc (stddev) are cm.
bool setPositionAssistanceLLH(int32_t lat, int32_t lon, int32_t alt, uint32_t posAcc, sfe_ublox_mga_assist_ack_e mgaAck = SFE_UBLOX_MGA_ASSIST_ACK_NO, uint16_t maxWait = defaultMGAdelay);
// Find the start of the AssistNow Offline (UBX_MGA_ANO) data for the chosen day
// The daysIntoFture parameter makes it easy to get the data for (e.g.) tomorrow based on today's date
// Returns numDataBytes if unsuccessful
// TO DO: enhance this so it will find the nearest data for the chosen day - instead of an exact match
size_t findMGAANOForDate(const String &dataBytes, size_t numDataBytes, uint16_t year, uint8_t month, uint8_t day, uint8_t daysIntoFuture = 0);
size_t findMGAANOForDate(const uint8_t *dataBytes, size_t numDataBytes, uint16_t year, uint8_t month, uint8_t day, uint8_t daysIntoFuture = 0);
// Read the whole navigation data base. The receiver will send all available data from its internal database.
// Data is written to dataBytes. Set maxNumDataBytes to the (maximum) size of dataBytes.
// If the database exceeds maxNumDataBytes, the excess bytes will be lost.
// The function returns the number of database bytes written to dataBytes.
// The return value will be equal to maxNumDataBytes if excess data was received.
// The function will timeout after maxWait milliseconds - in case the final UBX-MGA-ACK was missed.
#define defaultNavDBDMaxWait 3100
size_t readNavigationDatabase(uint8_t *dataBytes, size_t maxNumDataBytes, uint16_t maxWait = defaultNavDBDMaxWait);
// Support for data logging
void setFileBufferSize(uint16_t bufferSize); // Set the size of the file buffer. This must be called _before_ .begin.
uint16_t getFileBufferSize(void); // Return the size of the file buffer
@@ -696,23 +797,25 @@ public:
// Port configurations
bool getPortSettings(uint8_t portID, uint16_t maxWait = defaultMaxWait); // Returns the current protocol bits in the UBX-CFG-PRT command for a given port
bool setPortOutput(uint8_t portID, uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure a given port to output UBX, NMEA, RTCM3 or a combination thereof
bool setPortInput(uint8_t portID, uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure a given port to input UBX, NMEA, RTCM3 or a combination thereof
bool setPortOutput(uint8_t portID, uint8_t comSettings, uint16_t maxWait = defaultMaxWait); // Configure a given port to output UBX, NMEA, RTCM3, SPARTN or a combination thereof
bool setPortInput(uint8_t portID, uint8_t comSettings, uint16_t maxWait = defaultMaxWait); // Configure a given port to input UBX, NMEA, RTCM3, SPARTN or a combination thereof
bool setI2CAddress(uint8_t deviceAddress, uint16_t maxTime = defaultMaxWait); // Changes the I2C address of the u-blox module
void setSerialRate(uint32_t baudrate, uint8_t uartPort = COM_PORT_UART1, uint16_t maxTime = defaultMaxWait); // Changes the serial baud rate of the u-blox module, uartPort should be COM_PORT_UART1/2
bool setI2COutput(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure I2C port to output UBX, NMEA, RTCM3 or a combination thereof
bool setUART1Output(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure UART1 port to output UBX, NMEA, RTCM3 or a combination thereof
bool setUART2Output(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure UART2 port to output UBX, NMEA, RTCM3 or a combination thereof
bool setUSBOutput(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure USB port to output UBX, NMEA, RTCM3 or a combination thereof
bool setSPIOutput(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure SPI port to output UBX, NMEA, RTCM3 or a combination thereof
bool setI2COutput(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); // Configure I2C port to output UBX, NMEA, RTCM3, SPARTN or a combination thereof
bool setUART1Output(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); // Configure UART1 port to output UBX, NMEA, RTCM3, SPARTN or a combination thereof
bool setUART2Output(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); // Configure UART2 port to output UBX, NMEA, RTCM3, SPARTN or a combination thereof
bool setUSBOutput(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); // Configure USB port to output UBX, NMEA, RTCM3, SPARTN or a combination thereof
bool setSPIOutput(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); // Configure SPI port to output UBX, NMEA, RTCM3, SPARTN or a combination thereof
void setNMEAOutputPort(Stream &nmeaOutputPort); // Sets the internal variable for the port to direct NMEA characters to
void setOutputPort(Stream &outputPort); // Sets the internal variable for the port to direct ALL characters to
// Reset to defaults
void factoryReset(); // Send factory reset sequence (i.e. load "default" configuration and perform hardReset)
void hardReset(); // Perform a reset leading to a cold start (zero info start-up)
void softwareResetGNSSOnly(); // Controlled Software Reset (GNSS only) only restarts the GNSS tasks, without reinitializing the full system or reloading any stored configuration.
bool factoryDefault(uint16_t maxWait = defaultMaxWait); // Reset module to factory defaults
// Save configuration to BBR / Flash
@@ -740,6 +843,7 @@ public:
// For Lat/Lon/Alt the units are: degrees^-7, degrees^-9, degrees^-7, degrees^-9, cm, 0.1mm
bool setStaticPosition(int32_t ecefXOrLat, int8_t ecefXOrLatHP, int32_t ecefYOrLon, int8_t ecefYOrLonHP, int32_t ecefZOrAlt, int8_t ecefZOrAltHP, bool latLong = false, uint16_t maxWait = 250);
bool setStaticPosition(int32_t ecefXOrLat, int32_t ecefYOrLon, int32_t ecefZOrAlt, bool latLong = false, uint16_t maxWait = 250);
bool setDGNSSConfiguration(sfe_ublox_dgnss_mode_e dgnssMode = SFE_UBLOX_DGNSS_MODE_FIXED, uint16_t maxWait = defaultMaxWait); // Set the DGNSS differential mode
// Read the module's protocol version
uint8_t getProtocolVersionHigh(uint16_t maxWait = defaultMaxWait); // Returns the PROTVER XX.00 from UBX-MON-VER register
@@ -759,7 +863,7 @@ public:
bool powerSaveMode(bool power_save = true, uint16_t maxWait = defaultMaxWait);
uint8_t getPowerSaveMode(uint16_t maxWait = defaultMaxWait); // Returns 255 if the sendCommand fails
bool powerOff(uint32_t durationInMs, uint16_t maxWait = defaultMaxWait);
bool powerOffWithInterrupt(uint32_t durationInMs, uint32_t wakeupSources = VAL_RXM_PMREQ_WAKEUPSOURCE_EXTINT0, bool forceWhileUsb = true, uint16_t maxWait = 1100);
bool powerOffWithInterrupt(uint32_t durationInMs, uint32_t wakeupSources = VAL_RXM_PMREQ_WAKEUPSOURCE_EXTINT0, bool forceWhileUsb = true, uint16_t maxWait = defaultMaxWait);
// Change the dynamic platform model using UBX-CFG-NAV5
bool setDynamicModel(dynModel newDynamicModel = DYN_MODEL_PORTABLE, uint16_t maxWait = defaultMaxWait);
@@ -785,6 +889,27 @@ public:
bool getTimePulseParameters(UBX_CFG_TP5_data_t *data = NULL, uint16_t maxWait = defaultMaxWait); // Get the time pulse parameters using UBX_CFG_TP5
bool setTimePulseParameters(UBX_CFG_TP5_data_t *data = NULL, uint16_t maxWait = defaultMaxWait); // Set the time pulse parameters using UBX_CFG_TP5
// UBX-CFG-NAVX5 - get/set the ackAiding byte. If ackAiding is 1, UBX-MGA-ACK messages will be sent by the module to acknowledge the MGA data
uint8_t getAckAiding(uint16_t maxWait = defaultMaxWait); // Get the ackAiding byte - returns 255 if the sendCommand fails
bool setAckAiding(uint8_t ackAiding, uint16_t maxWait = defaultMaxWait); // Set the ackAiding byte
// AssistNow Autonomous support
// UBX-CFG-NAVX5 - get/set the aopCfg byte and set the aopOrdMaxErr word. If aopOrbMaxErr is 0 (default), the max orbit error is reset to the firmware default.
uint8_t getAopCfg(uint16_t maxWait = defaultMaxWait); // Get the AssistNow Autonomous configuration (aopCfg) - returns 255 if the sendCommand fails
bool setAopCfg(uint8_t aopCfg, uint16_t aopOrbMaxErr = 0, uint16_t maxWait = defaultMaxWait); // Set the aopCfg byte and the aopOrdMaxErr word
// SPARTN dynamic keys
//"When the receiver boots, the host should send 'current' and 'next' keys in one message." - Use setDynamicSPARTNKeys for this.
//"Every time the 'current' key is expired, 'next' takes its place."
//"Therefore the host should then retrieve the new 'next' key and send only that." - Use setDynamicSPARTNKey for this.
// The key can be provided in binary (uint8_t) format or in ASCII Hex (char) format, but in both cases keyLengthBytes _must_ represent the binary key length in bytes.
bool setDynamicSPARTNKey(uint8_t keyLengthBytes, uint16_t validFromWno, uint32_t validFromTow, const char *key);
bool setDynamicSPARTNKey(uint8_t keyLengthBytes, uint16_t validFromWno, uint32_t validFromTow, const uint8_t *key);
bool setDynamicSPARTNKeys(uint8_t keyLengthBytes1, uint16_t validFromWno1, uint32_t validFromTow1, const char *key1,
uint8_t keyLengthBytes2, uint16_t validFromWno2, uint32_t validFromTow2, const char *key2);
bool setDynamicSPARTNKeys(uint8_t keyLengthBytes1, uint16_t validFromWno1, uint32_t validFromTow1, const uint8_t *key1,
uint8_t keyLengthBytes2, uint16_t validFromWno2, uint32_t validFromTow2, const uint8_t *key2);
// General configuration (used only on protocol v27 and higher - ie, ZED-F9P)
// It is probably safe to assume that users of the ZED-F9P will be using I2C / Qwiic.
@@ -794,37 +919,44 @@ public:
uint8_t getVal8(uint32_t keyID, uint8_t layer = VAL_LAYER_RAM, uint16_t maxWait = 250); // Returns the value at a given key location
uint16_t getVal16(uint32_t keyID, uint8_t layer = VAL_LAYER_RAM, uint16_t maxWait = 250); // Returns the value at a given key location
uint32_t getVal32(uint32_t keyID, uint8_t layer = VAL_LAYER_RAM, uint16_t maxWait = 250); // Returns the value at a given key location
uint64_t getVal64(uint32_t keyID, uint8_t layer = VAL_LAYER_RAM, uint16_t maxWait = 250); // Returns the value at a given key location
uint8_t getVal8(uint16_t group, uint16_t id, uint8_t size, uint8_t layer = VAL_LAYER_RAM, uint16_t maxWait = 250); // Returns the value at a given group/id/size location
uint16_t getVal16(uint16_t group, uint16_t id, uint8_t size, uint8_t layer = VAL_LAYER_RAM, uint16_t maxWait = 250); // Returns the value at a given group/id/size location
uint32_t getVal32(uint16_t group, uint16_t id, uint8_t size, uint8_t layer = VAL_LAYER_RAM, uint16_t maxWait = 250); // Returns the value at a given group/id/size location
uint64_t getVal64(uint16_t group, uint16_t id, uint8_t size, uint8_t layer = VAL_LAYER_RAM, uint16_t maxWait = 250); // Returns the value at a given group/id/size location
uint8_t setVal(uint32_t keyID, uint16_t value, uint8_t layer = VAL_LAYER_ALL, uint16_t maxWait = 250); // Sets the 16-bit value at a given group/id/size location
uint8_t setVal8(uint32_t keyID, uint8_t value, uint8_t layer = VAL_LAYER_ALL, uint16_t maxWait = 250); // Sets the 8-bit value at a given group/id/size location
uint8_t setVal16(uint32_t keyID, uint16_t value, uint8_t layer = VAL_LAYER_ALL, uint16_t maxWait = 250); // Sets the 16-bit value at a given group/id/size location
uint8_t setVal32(uint32_t keyID, uint32_t value, uint8_t layer = VAL_LAYER_ALL, uint16_t maxWait = 250); // Sets the 32-bit value at a given group/id/size location
uint8_t setVal64(uint32_t keyID, uint64_t value, uint8_t layer = VAL_LAYER_ALL, uint16_t maxWait = 250); // Sets the 64-bit value at a given group/id/size location
uint8_t newCfgValset8(uint32_t keyID, uint8_t value, uint8_t layer = VAL_LAYER_ALL); // Define a new UBX-CFG-VALSET with the given KeyID and 8-bit value
uint8_t newCfgValset16(uint32_t keyID, uint16_t value, uint8_t layer = VAL_LAYER_ALL); // Define a new UBX-CFG-VALSET with the given KeyID and 16-bit value
uint8_t newCfgValset32(uint32_t keyID, uint32_t value, uint8_t layer = VAL_LAYER_ALL); // Define a new UBX-CFG-VALSET with the given KeyID and 32-bit value
uint8_t newCfgValset64(uint32_t keyID, uint64_t value, uint8_t layer = VAL_LAYER_ALL); // Define a new UBX-CFG-VALSET with the given KeyID and 64-bit value
uint8_t addCfgValset8(uint32_t keyID, uint8_t value); // Add a new KeyID and 8-bit value to an existing UBX-CFG-VALSET ubxPacket
uint8_t addCfgValset16(uint32_t keyID, uint16_t value); // Add a new KeyID and 16-bit value to an existing UBX-CFG-VALSET ubxPacket
uint8_t addCfgValset32(uint32_t keyID, uint32_t value); // Add a new KeyID and 32-bit value to an existing UBX-CFG-VALSET ubxPacket
uint8_t addCfgValset64(uint32_t keyID, uint64_t value); // Add a new KeyID and 64-bit value to an existing UBX-CFG-VALSET ubxPacket
uint8_t sendCfgValset8(uint32_t keyID, uint8_t value, uint16_t maxWait = 250); // Add the final KeyID and 8-bit value to an existing UBX-CFG-VALSET ubxPacket and send it
uint8_t sendCfgValset16(uint32_t keyID, uint16_t value, uint16_t maxWait = 250); // Add the final KeyID and 16-bit value to an existing UBX-CFG-VALSET ubxPacket and send it
uint8_t sendCfgValset32(uint32_t keyID, uint32_t value, uint16_t maxWait = 250); // Add the final KeyID and 32-bit value to an existing UBX-CFG-VALSET ubxPacket and send it
uint8_t sendCfgValset64(uint32_t keyID, uint64_t value, uint16_t maxWait = 250); // Add the final KeyID and 64-bit value to an existing UBX-CFG-VALSET ubxPacket and send it
// get and set functions for all of the "automatic" message processing
// Navigation (NAV)
// getPVT will only return data once in each navigation cycle. By default, that is once per second.
// Therefore we should set defaultMaxWait to slightly longer than that.
// If you change the navigation frequency to (e.g.) 4Hz using setNavigationFrequency(4)
// then you should use a shorter maxWait. 300msec would be about right: getPVT(300)
// get and set functions for all of the "automatic" message processing
// Navigation (NAV)
bool getNAVPOSECEF(uint16_t maxWait = defaultMaxWait); // NAV POSECEF
bool setAutoNAVPOSECEF(bool enabled, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic POSECEF reports at the navigation frequency
bool setAutoNAVPOSECEF(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic POSECEF reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoNAVPOSECEFrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic POSECEF reports
bool setAutoNAVPOSECEFcallback(void (*callbackPointer)(UBX_NAV_POSECEF_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic POSECEF reports at the navigation frequency. Data is accessed from the callback.
bool setAutoNAVPOSECEFcallbackPtr(void (*callbackPointerPtr)(UBX_NAV_POSECEF_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic POSECEF reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoNAVPOSECEF(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and POSECEF is send cyclically already
void flushNAVPOSECEF(); // Mark all the data as read/stale
void logNAVPOSECEF(bool enabled = true); // Log data to file buffer
@@ -834,6 +966,7 @@ public:
bool setAutoNAVSTATUS(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic STATUS reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoNAVSTATUSrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic STATUS reports
bool setAutoNAVSTATUScallback(void (*callbackPointer)(UBX_NAV_STATUS_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic STATUS reports at the navigation frequency. Data is accessed from the callback.
bool setAutoNAVSTATUScallbackPtr(void (*callbackPointerPtr)(UBX_NAV_STATUS_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic STATUS reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoNAVSTATUS(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and STATUS is send cyclically already
void flushNAVSTATUS(); // Mark all the data as read/stale
void logNAVSTATUS(bool enabled = true); // Log data to file buffer
@@ -843,6 +976,7 @@ public:
bool setAutoDOP(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic DOP reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoDOPrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic DOP reports
bool setAutoDOPcallback(void (*callbackPointer)(UBX_NAV_DOP_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic DOP reports at the navigation frequency. Data is accessed from the callback.
bool setAutoDOPcallbackPtr(void (*callbackPointerPtr)(UBX_NAV_DOP_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic DOP reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoDOP(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and DOP is send cyclically already
void flushDOP(); // Mark all the DOP data as read/stale
void logNAVDOP(bool enabled = true); // Log data to file buffer
@@ -853,6 +987,7 @@ public:
bool setAutoNAVATT(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic vehicle attitude reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoNAVATTrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic ATT reports
bool setAutoNAVATTcallback(void (*callbackPointer)(UBX_NAV_ATT_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic ATT reports at the navigation frequency. Data is accessed from the callback.
bool setAutoNAVATTcallbackPtr(void (*callbackPointerPtr)(UBX_NAV_ATT_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic ATT reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoNAVATT(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and vehicle attitude is send cyclically already
void flushNAVATT(); // Mark all the data as read/stale
void logNAVATT(bool enabled = true); // Log data to file buffer
@@ -862,6 +997,7 @@ public:
bool setAutoPVT(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic PVT reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoPVTrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic PVT reports
bool setAutoPVTcallback(void (*callbackPointer)(UBX_NAV_PVT_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic PVT reports at the navigation frequency. Data is accessed from the callback.
bool setAutoPVTcallbackPtr(void (*callbackPointerPtr)(UBX_NAV_PVT_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic PVT reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoPVT(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and PVT is send cyclically already
void flushPVT(); // Mark all the PVT data as read/stale
void logNAVPVT(bool enabled = true); // Log data to file buffer
@@ -871,6 +1007,7 @@ public:
bool setAutoNAVODO(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic ODO reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoNAVODOrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic ODO reports
bool setAutoNAVODOcallback(void (*callbackPointer)(UBX_NAV_ODO_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic ODO reports at the navigation frequency. Data is accessed from the callback.
bool setAutoNAVODOcallbackPtr(void (*callbackPointerPtr)(UBX_NAV_ODO_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic ODO reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoNAVODO(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and ODO is send cyclically already
void flushNAVODO(); // Mark all the data as read/stale
void logNAVODO(bool enabled = true); // Log data to file buffer
@@ -880,6 +1017,7 @@ public:
bool setAutoNAVVELECEF(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic VELECEF reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoNAVVELECEFrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic VELECEF reports
bool setAutoNAVVELECEFcallback(void (*callbackPointer)(UBX_NAV_VELECEF_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic VELECEF reports at the navigation frequency. Data is accessed from the callback.
bool setAutoNAVVELECEFcallbackPtr(void (*callbackPointerPtr)(UBX_NAV_VELECEF_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic VELECEF reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoNAVVELECEF(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and VELECEF is send cyclically already
void flushNAVVELECEF(); // Mark all the data as read/stale
void logNAVVELECEF(bool enabled = true); // Log data to file buffer
@@ -889,6 +1027,7 @@ public:
bool setAutoNAVVELNED(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic VELNED reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoNAVVELNEDrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic VELNED reports
bool setAutoNAVVELNEDcallback(void (*callbackPointer)(UBX_NAV_VELNED_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic VELNED reports at the navigation frequency. Data is accessed from the callback.
bool setAutoNAVVELNEDcallbackPtr(void (*callbackPointerPtr)(UBX_NAV_VELNED_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic VELNED reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoNAVVELNED(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and VELNED is send cyclically already
void flushNAVVELNED(); // Mark all the data as read/stale
void logNAVVELNED(bool enabled = true); // Log data to file buffer
@@ -898,24 +1037,37 @@ public:
bool setAutoNAVHPPOSECEF(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic HPPOSECEF reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoNAVHPPOSECEFrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic HPPOSECEF reports
bool setAutoNAVHPPOSECEFcallback(void (*callbackPointer)(UBX_NAV_HPPOSECEF_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic HPPOSECEF reports at the navigation frequency. Data is accessed from the callback.
bool setAutoNAVHPPOSECEFcallbackPtr(void (*callbackPointerPtr)(UBX_NAV_HPPOSECEF_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic HPPOSECEF reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoNAVHPPOSECEF(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and HPPOSECEF is send cyclically already
void flushNAVHPPOSECEF(); // Mark all the data as read/stale
void logNAVHPPOSECEF(bool enabled = true); // Log data to file buffer
bool getHPPOSLLH(uint16_t maxWait = defaultMaxWait); //Query module for latest group of datums and load global vars: lat, long, alt, speed, SIV, accuracies, etc. If autoPVT is disabled, performs an explicit poll and waits, if enabled does not block. Returns true if new HPPOSLLH is available.
bool getHPPOSLLH(uint16_t maxWait = defaultMaxWait); // NAV HPPOSLLH
bool setAutoHPPOSLLH(bool enabled, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic HPPOSLLH reports at the navigation frequency
bool setAutoHPPOSLLH(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic HPPOSLLH reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoHPPOSLLHrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic HPPOSLLH reports
bool setAutoHPPOSLLHcallback(void (*callbackPointer)(UBX_NAV_HPPOSLLH_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic HPPOSLLH reports at the navigation frequency. Data is accessed from the callback.
bool setAutoHPPOSLLHcallbackPtr(void (*callbackPointerPtr)(UBX_NAV_HPPOSLLH_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic HPPOSLLH reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoHPPOSLLH(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and HPPOSLLH is send cyclically already
void flushHPPOSLLH(); // Mark all the HPPPOSLLH data as read/stale. This is handy to get data alignment after CRC failure
void logNAVHPPOSLLH(bool enabled = true); // Log data to file buffer
bool getNAVPVAT(uint16_t maxWait = defaultMaxWait); // NAV PVAT
bool setAutoNAVPVAT(bool enabled, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic PVAT reports at the navigation frequency
bool setAutoNAVPVAT(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic PVAT reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoNAVPVATrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic PVAT reports
bool setAutoNAVPVATcallback(void (*callbackPointer)(UBX_NAV_PVAT_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic PVAT reports at the navigation frequency. Data is accessed from the callback.
bool setAutoNAVPVATcallbackPtr(void (*callbackPointerPtr)(UBX_NAV_PVAT_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic PVAT reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoNAVPVAT(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and PVAT is send cyclically already
void flushNAVPVAT(); // Mark all the PVAT data as read/stale
void logNAVPVAT(bool enabled = true); // Log data to file buffer
bool getNAVCLOCK(uint16_t maxWait = defaultMaxWait); // NAV CLOCK
bool setAutoNAVCLOCK(bool enabled, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic clock reports at the navigation frequency
bool setAutoNAVCLOCK(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic clock reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoNAVCLOCKrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic CLOCK reports
bool setAutoNAVCLOCKcallback(void (*callbackPointer)(UBX_NAV_CLOCK_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic CLOCK reports at the navigation frequency. Data is accessed from the callback.
bool setAutoNAVCLOCKcallbackPtr(void (*callbackPointerPtr)(UBX_NAV_CLOCK_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic CLOCK reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoNAVCLOCK(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and clock is send cyclically already
void flushNAVCLOCK(); // Mark all the data as read/stale
void logNAVCLOCK(bool enabled = true); // Log data to file buffer
@@ -926,22 +1078,51 @@ public:
// Add "auto" support for NAV TIMELS - to avoid needing 'global' storage
bool getLeapSecondEvent(uint16_t maxWait); // Reads leap second event info
bool getNAVSAT(uint16_t maxWait = defaultMaxWait); // Query module for latest AssistNow Autonomous status and load global vars:. If autoNAVSAT is disabled, performs an explicit poll and waits, if enabled does not block. Returns true if new NAVSAT is available.
bool setAutoNAVSAT(bool enabled, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic NAVSAT reports at the navigation frequency
bool setAutoNAVSAT(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic NAVSAT reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoNAVSATrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic NAVSAT reports
bool setAutoNAVSATcallback(void (*callbackPointer)(UBX_NAV_SAT_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic NAVSAT reports at the navigation frequency. Data is accessed from the callback.
bool setAutoNAVSATcallbackPtr(void (*callbackPointerPtr)(UBX_NAV_SAT_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic NAVSAT reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoNAVSAT(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and NAVSAT is send cyclically already
void flushNAVSAT(); // Mark all the NAVSAT data as read/stale
void logNAVSAT(bool enabled = true); // Log data to file buffer
bool getRELPOSNED(uint16_t maxWait = defaultMaxWait); // Get Relative Positioning Information of the NED frame
bool setAutoRELPOSNED(bool enabled, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic RELPOSNED reports
bool setAutoRELPOSNED(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic RELPOSNED, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoRELPOSNEDrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic RELPOSNEDreports
bool setAutoRELPOSNEDcallback(void (*callbackPointer)(UBX_NAV_RELPOSNED_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic RELPOSNED reports at the navigation frequency. Data is accessed from the callback.
bool setAutoRELPOSNEDcallbackPtr(void (*callbackPointerPtr)(UBX_NAV_RELPOSNED_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic RELPOSNED reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoRELPOSNED(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and RELPOSNED is send cyclically already
void flushNAVRELPOSNED(); // Mark all the data as read/stale
void logNAVRELPOSNED(bool enabled = true); // Log data to file buffer
bool getAOPSTATUS(uint16_t maxWait = defaultMaxWait); // Query module for latest AssistNow Autonomous status and load global vars:. If autoAOPSTATUS is disabled, performs an explicit poll and waits, if enabled does not block. Returns true if new AOPSTATUS is available.
bool setAutoAOPSTATUS(bool enabled, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic AOPSTATUS reports at the navigation frequency
bool setAutoAOPSTATUS(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic AOPSTATUS reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoAOPSTATUSrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic AOPSTATUS reports
bool setAutoAOPSTATUScallback(void (*callbackPointer)(UBX_NAV_AOPSTATUS_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic AOPSTATUS reports at the navigation frequency. Data is accessed from the callback.
bool setAutoAOPSTATUScallbackPtr(void (*callbackPointerPtr)(UBX_NAV_AOPSTATUS_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic AOPSTATUS reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoAOPSTATUS(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and AOPSTATUS is send cyclically already
void flushAOPSTATUS(); // Mark all the AOPSTATUS data as read/stale
void logAOPSTATUS(bool enabled = true); // Log data to file buffer
// Receiver Manager Messages (RXM)
// Configure a callback for the UBX-RXM-PMP messages produced by the NEO-D9S
// Note: on the NEO-D9S, the UBX-RXM-PMP messages are enabled by default on all ports.
// You can disable them by calling (e.g.) setVal8(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_I2C, 0)
// The NEO-D9S does not support UBX-CFG-MSG
bool setRXMPMPcallbackPtr(void (*callbackPointerPtr)(UBX_RXM_PMP_data_t *)); // Callback receives a pointer to the data, instead of _all_ the data. Much kinder on the stack!
bool setRXMPMPmessageCallbackPtr(void (*callbackPointerPtr)(UBX_RXM_PMP_message_data_t *)); // Use this if you want all of the PMP message (including sync chars, checksum, etc.) to push to a GNSS
bool getRXMSFRBX(uint16_t maxWait = defaultMaxWait); // RXM SFRBX
bool setAutoRXMSFRBX(bool enabled, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic RXM SFRBX reports at the navigation frequency
bool setAutoRXMSFRBX(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic RXM SFRBX reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoRXMSFRBXrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic SFRBX reports
bool setAutoRXMSFRBXcallback(void (*callbackPointer)(UBX_RXM_SFRBX_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic SFRBX reports at the navigation frequency. Data is accessed from the callback.
bool setAutoRXMSFRBXcallbackPtr(void (*callbackPointerPtr)(UBX_RXM_SFRBX_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic SFRBX reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoRXMSFRBX(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and RXM SFRBX is send cyclically already
void flushRXMSFRBX(); // Mark all the data as read/stale
void logRXMSFRBX(bool enabled = true); // Log data to file buffer
@@ -951,13 +1132,15 @@ public:
bool setAutoRXMRAWX(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic RXM RAWX reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoRXMRAWXrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic RAWX reports
bool setAutoRXMRAWXcallback(void (*callbackPointer)(UBX_RXM_RAWX_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic RAWX reports at the navigation frequency. Data is accessed from the callback.
bool setAutoRXMRAWXcallbackPtr(void (*callbackPointerPtr)(UBX_RXM_RAWX_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic RAWX reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoRXMRAWX(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and RXM RAWX is send cyclically already
void flushRXMRAWX(); // Mark all the data as read/stale
void logRXMRAWX(bool enabled = true); // Log data to file buffer
// Configuration (CFG)
// Add "auto" support for CFG RATE - because we use it for isConnected (to stop it being mugged by other messages)
// Add "auto" support for CFG PRT - because we use it for isConnected (to stop it being mugged by other messages)
bool getPortSettingsInternal(uint8_t portID, uint16_t maxWait = defaultMaxWait); // Read the port configuration for a given port using UBX-CFG-PRT
bool getNavigationFrequencyInternal(uint16_t maxWait = defaultMaxWait); // Get the number of nav solutions sent per second currently being output by module
// Timing messages (TIM)
@@ -967,6 +1150,7 @@ public:
bool setAutoTIMTM2(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic TIM TM2 reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoTIMTM2rate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic TIM TM2 reports
bool setAutoTIMTM2callback(void (*callbackPointer)(UBX_TIM_TM2_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic TM2 reports at the navigation frequency. Data is accessed from the callback.
bool setAutoTIMTM2callbackPtr(void (*callbackPointerPtr)(UBX_TIM_TM2_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic TM2 reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoTIMTM2(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and TIM TM2 is send cyclically already
void flushTIMTM2(); // Mark all the data as read/stale
void logTIMTM2(bool enabled = true); // Log data to file buffer
@@ -979,6 +1163,7 @@ public:
bool setAutoESFALG(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic ESF ALG reports, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoESFALGrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic ALG reports
bool setAutoESFALGcallback(void (*callbackPointer)(UBX_ESF_ALG_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic ALG reports at the navigation frequency. Data is accessed from the callback.
bool setAutoESFALGcallbackPtr(void (*callbackPointerPtr)(UBX_ESF_ALG_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic ALG reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoESFALG(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and ESF ALG is send cyclically already
void flushESFALG(); // Mark all the data as read/stale
void logESFALG(bool enabled = true); // Log data to file buffer
@@ -989,6 +1174,7 @@ public:
bool setAutoESFSTATUS(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic ESF STATUS reports, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoESFSTATUSrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic STATUS reports
bool setAutoESFSTATUScallback(void (*callbackPointer)(UBX_ESF_STATUS_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic STATUS reports at the navigation frequency. Data is accessed from the callback.
bool setAutoESFSTATUScallbackPtr(void (*callbackPointerPtr)(UBX_ESF_STATUS_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic STATUS reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoESFSTATUS(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and ESF STATUS is send cyclically already
void flushESFSTATUS(); // Mark all the data as read/stale
void logESFSTATUS(bool enabled = true); // Log data to file buffer
@@ -999,6 +1185,7 @@ public:
bool setAutoESFINS(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic ESF INS reports, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoESFINSrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic INS reports
bool setAutoESFINScallback(void (*callbackPointer)(UBX_ESF_INS_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic INS reports at the navigation frequency. Data is accessed from the callback.
bool setAutoESFINScallbackPtr(void (*callbackPointerPtr)(UBX_ESF_INS_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic INS reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoESFINS(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and ESF INS is send cyclically already
void flushESFINS(); // Mark all the data as read/stale
void logESFINS(bool enabled = true); // Log data to file buffer
@@ -1009,6 +1196,7 @@ public:
bool setAutoESFMEAS(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic ESF MEAS reports, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoESFMEASrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic MEAS reports
bool setAutoESFMEAScallback(void (*callbackPointer)(UBX_ESF_MEAS_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic MEAS reports at the navigation frequency. Data is accessed from the callback.
bool setAutoESFMEAScallbackPtr(void (*callbackPointerPtr)(UBX_ESF_MEAS_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic MEAS reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoESFMEAS(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and ESF MEAS is send cyclically already
void flushESFMEAS(); // Mark all the data as read/stale
void logESFMEAS(bool enabled = true); // Log data to file buffer
@@ -1019,6 +1207,7 @@ public:
bool setAutoESFRAW(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic ESF RAW reports, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoESFRAWrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic RAW reports
bool setAutoESFRAWcallback(void (*callbackPointer)(UBX_ESF_RAW_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic RAW reports at the navigation frequency. Data is accessed from the callback.
bool setAutoESFRAWcallbackPtr(void (*callbackPointerPtr)(UBX_ESF_RAW_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic RAW reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoESFRAW(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and ESF RAW is send cyclically already
void flushESFRAW(); // Mark all the data as read/stale
void logESFRAW(bool enabled = true); // Log data to file buffer
@@ -1031,6 +1220,7 @@ public:
bool setAutoHNRATT(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic HNR Attitude reports at the HNR rate, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoHNRATTrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic ATT reports
bool setAutoHNRATTcallback(void (*callbackPointer)(UBX_HNR_ATT_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic ATT reports at the navigation frequency. Data is accessed from the callback.
bool setAutoHNRATTcallbackPtr(void (*callbackPointerPtr)(UBX_HNR_ATT_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic ATT reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoHNRATT(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and HNR Attitude is send cyclically already
void flushHNRATT(); // Mark all the data as read/stale
void logHNRATT(bool enabled = true); // Log data to file buffer
@@ -1041,6 +1231,7 @@ public:
bool setAutoHNRINS(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic HNR dynamics reports at the HNR rate, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoHNRINSrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic INS reports
bool setAutoHNRINScallback(void (*callbackPointer)(UBX_HNR_INS_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic INS reports at the navigation frequency. Data is accessed from the callback.
bool setAutoHNRINScallbackPtr(void (*callbackPointerPtr)(UBX_HNR_INS_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic INS reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoHNRINS(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and HNR dynamics is send cyclically already
void flushHNRINS(); // Mark all the data as read/stale
void logHNRINS(bool enabled = true); // Log data to file buffer
@@ -1050,18 +1241,11 @@ public:
bool setAutoHNRPVT(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); // Enable/disable automatic HNR PVT reports at the HNR rate, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoHNRPVTrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); // Set the rate for automatic PVT reports
bool setAutoHNRPVTcallback(void (*callbackPointer)(UBX_HNR_PVT_data_t), uint16_t maxWait = defaultMaxWait); // Enable automatic PVT reports at the navigation frequency. Data is accessed from the callback.
bool setAutoHNRPVTcallbackPtr(void (*callbackPointerPtr)(UBX_HNR_PVT_data_t *), uint16_t maxWait = defaultMaxWait); // Enable automatic PVT reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoHNRPVT(bool enabled, bool implicitUpdate = true); // In case no config access to the GPS is possible and HNR PVT is send cyclically already
void flushHNRPVT(); // Mark all the data as read/stale
void logHNRPVT(bool enabled = true); // Log data to file buffer
// Helper functions for NMEA logging
void setNMEALoggingMask(uint32_t messages = SFE_UBLOX_FILTER_NMEA_ALL); // Add selected NMEA messages to file buffer - if enabled. Default to adding ALL messages to the file buffer
uint32_t getNMEALoggingMask(); // Return which NMEA messages are selected for logging to the file buffer - if enabled
// Helper functions to control which NMEA messages are passed to processNMEA
void setProcessNMEAMask(uint32_t messages = SFE_UBLOX_FILTER_NMEA_ALL); // Control which NMEA messages are passed to processNMEA. Default to passing ALL messages
uint32_t getProcessNMEAMask(); // Return which NMEA messages are passed to processNMEA
// Helper functions for CFG RATE
bool setNavigationFrequency(uint8_t navFreq, uint16_t maxWait = defaultMaxWait); // Set the number of nav solutions sent per second
@@ -1141,7 +1325,7 @@ public:
// Helper functions for HPPOSECEF
uint32_t getPositionAccuracy(uint16_t maxWait = 1100); //Returns the 3D accuracy of the current high-precision fix, in mm. Supported on NEO-M8P, ZED-F9P,
uint32_t getPositionAccuracy(uint16_t maxWait = defaultMaxWait); // Returns the 3D accuracy of the current high-precision fix, in mm. Supported on NEO-M8P, ZED-F9P,
// Helper functions for HPPOSLLH
@@ -1157,6 +1341,13 @@ public:
uint32_t getHorizontalAccuracy(uint16_t maxWait = defaultMaxWait);
uint32_t getVerticalAccuracy(uint16_t maxWait = defaultMaxWait);
// Helper functions for PVAT
int32_t getVehicleRoll(uint16_t maxWait = defaultMaxWait); // Returns vehicle roll in degrees * 10^-5
int32_t getVehiclePitch(uint16_t maxWait = defaultMaxWait); // Returns vehicle pitch in degrees * 10^-5
int32_t getVehicleHeading(uint16_t maxWait = defaultMaxWait); // Returns vehicle heading in degrees * 10^-5
int32_t getMotionHeading(uint16_t maxWait = defaultMaxWait); // Returns the motion heading in degrees * 10^-5
// Helper functions for SVIN
bool getSurveyInActive(uint16_t maxWait = defaultMaxWait);
@@ -1178,6 +1369,11 @@ public:
float getRelPosAccE(uint16_t maxWait = defaultMaxWait); // Returned as m
float getRelPosAccD(uint16_t maxWait = defaultMaxWait); // Returned as m
// Helper functions for AOPSTATUS
uint8_t getAOPSTATUSuseAOP(uint16_t maxWait = defaultMaxWait); // Returns the UBX-NAV-AOPSTATUS useAOP flag. Don't confuse this with getAopCfg - which returns the aopCfg byte from UBX-CFG-NAVX5
uint8_t getAOPSTATUSstatus(uint16_t maxWait = defaultMaxWait); // Returns the UBX-NAV-AOPSTATUS status field. A host application can determine the optimal time to shut down the receiver by monitoring the status field for a steady 0.
// Helper functions for ESF
float getESFroll(uint16_t maxWait = defaultMaxWait); // Returned as degrees
@@ -1192,20 +1388,43 @@ public:
// Helper functions for HNR
bool setHNRNavigationRate(uint8_t rate, uint16_t maxWait = 1100); // Returns true if the setHNRNavigationRate is successful
uint8_t getHNRNavigationRate(uint16_t maxWait = 1100); // Returns 0 if the getHNRNavigationRate fails
bool setHNRNavigationRate(uint8_t rate, uint16_t maxWait = defaultMaxWait); // Returns true if the setHNRNavigationRate is successful
uint8_t getHNRNavigationRate(uint16_t maxWait = defaultMaxWait); // Returns 0 if the getHNRNavigationRate fails
float getHNRroll(uint16_t maxWait = defaultMaxWait); // Returned as degrees
float getHNRpitch(uint16_t maxWait = defaultMaxWait); // Returned as degrees
float getHNRheading(uint16_t maxWait = defaultMaxWait); // Returned as degrees
// Set the mainTalkerId used by NMEA messages - allows all NMEA messages except GSV to be prefixed with GP instead of GN
bool setMainTalkerID(sfe_ublox_talker_ids_e id = SFE_UBLOX_MAIN_TALKER_ID_DEFAULT, uint16_t maxWait = defaultMaxWait);
// Enable/Disable NMEA High Precision Mode - include extra decimal places in the Lat and Lon
bool setHighPrecisionMode(bool enable = true, uint16_t maxWait = defaultMaxWait);
// Helper functions for NMEA logging
void setNMEALoggingMask(uint32_t messages = SFE_UBLOX_FILTER_NMEA_ALL); // Add selected NMEA messages to file buffer - if enabled. Default to adding ALL messages to the file buffer
uint32_t getNMEALoggingMask(); // Return which NMEA messages are selected for logging to the file buffer - if enabled
// Helper functions to control which NMEA messages are passed to processNMEA
void setProcessNMEAMask(uint32_t messages = SFE_UBLOX_FILTER_NMEA_ALL); // Control which NMEA messages are passed to processNMEA. Default to passing ALL messages
uint32_t getProcessNMEAMask(); // Return which NMEA messages are passed to processNMEA
// Support for "auto" storage of NMEA messages
uint8_t getLatestNMEAGPGGA(NMEA_GGA_data_t *data); // Return the most recent GPGGA: 0 = no data, 1 = stale data, 2 = fresh data
bool setNMEAGPGGAcallback(void (*callbackPointer)(NMEA_GGA_data_t)); // Enable a callback on the arrival of a GPGGA message
bool setNMEAGPGGAcallbackPtr(void (*callbackPointerPtr)(NMEA_GGA_data_t *)); // Enable a callback on the arrival of a GPGGA message
uint8_t getLatestNMEAGNGGA(NMEA_GGA_data_t *data); // Return the most recent GNGGA: 0 = no data, 1 = stale data, 2 = fresh data
bool setNMEAGNGGAcallback(void (*callbackPointer)(NMEA_GGA_data_t)); // Enable a callback on the arrival of a GNGGA message
bool setNMEAGNGGAcallbackPtr(void (*callbackPointerPtr)(NMEA_GGA_data_t *)); // Enable a callback on the arrival of a GNGGA message
// Functions to extract signed and unsigned 8/16/32-bit data from a ubxPacket
// From v2.0: These are public. The user can call these to extract data from custom packets
uint32_t extractLong(ubxPacket *msg, uint8_t spotToStart); //Combine four bytes from payload into long
int32_t extractSignedLong(ubxPacket *msg, uint8_t spotToStart); //Combine four bytes from payload into signed long (avoiding any ambiguity caused by casting)
uint16_t extractInt(ubxPacket *msg, uint8_t spotToStart); //Combine two bytes from payload into int
int16_t extractSignedInt(ubxPacket *msg, int8_t spotToStart);
uint8_t extractByte(ubxPacket *msg, uint8_t spotToStart); //Get byte from payload
int8_t extractSignedChar(ubxPacket *msg, uint8_t spotToStart); //Get signed 8-bit value from payload
uint64_t extractLongLong(ubxPacket *msg, uint16_t spotToStart); // Combine eight bytes from payload into uint64_t
uint32_t extractLong(ubxPacket *msg, uint16_t spotToStart); // Combine four bytes from payload into long
int32_t extractSignedLong(ubxPacket *msg, uint16_t spotToStart); // Combine four bytes from payload into signed long (avoiding any ambiguity caused by casting)
uint16_t extractInt(ubxPacket *msg, uint16_t spotToStart); // Combine two bytes from payload into int
int16_t extractSignedInt(ubxPacket *msg, uint16_t spotToStart);
uint8_t extractByte(ubxPacket *msg, uint16_t spotToStart); // Get byte from payload
int8_t extractSignedChar(ubxPacket *msg, uint16_t spotToStart); // Get signed 8-bit value from payload
// Pointers to storage for the "automatic" messages
// RAM is allocated for these if/when required.
@@ -1220,14 +1439,20 @@ public:
UBX_NAV_VELNED_t *packetUBXNAVVELNED = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_NAV_HPPOSECEF_t *packetUBXNAVHPPOSECEF = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_NAV_HPPOSLLH_t *packetUBXNAVHPPOSLLH = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_NAV_PVAT_t *packetUBXNAVPVAT = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_NAV_CLOCK_t *packetUBXNAVCLOCK = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_NAV_TIMELS_t *packetUBXNAVTIMELS = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_NAV_SVIN_t *packetUBXNAVSVIN = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_NAV_SAT_t *packetUBXNAVSAT = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_NAV_RELPOSNED_t *packetUBXNAVRELPOSNED = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_NAV_AOPSTATUS_t *packetUBXNAVAOPSTATUS = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_RXM_PMP_t *packetUBXRXMPMP = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_RXM_PMP_message_t *packetUBXRXMPMPmessage = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_RXM_SFRBX_t *packetUBXRXMSFRBX = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_RXM_RAWX_t *packetUBXRXMRAWX = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_CFG_PRT_t *packetUBXCFGPRT = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_CFG_RATE_t *packetUBXCFGRATE = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_TIM_TM2_t *packetUBXTIMTM2 = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
@@ -1242,6 +1467,12 @@ public:
UBX_HNR_ATT_t *packetUBXHNRATT = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_HNR_INS_t *packetUBXHNRINS = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_MGA_ACK_DATA0_t *packetUBXMGAACK = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_MGA_DBD_t *packetUBXMGADBD = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
NMEA_GPGGA_t *storageNMEAGPGGA = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
NMEA_GNGGA_t *storageNMEAGNGGA = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
uint16_t rtcmFrameCounter = 0; // Tracks the type of incoming byte inside RTCM frame
private:
@@ -1272,6 +1503,8 @@ private:
// Functions
bool checkUbloxInternal(ubxPacket *incomingUBX, uint8_t requestedClass = 255, uint8_t requestedID = 255); // Checks module with user selected commType
void addToChecksum(uint8_t incoming); // Given an incoming byte, adjust rollingChecksumA/B
size_t pushAssistNowDataInternal(size_t offset, bool skipTime, const uint8_t *dataBytes, size_t numDataBytes, sfe_ublox_mga_assist_ack_e mgaAck, uint16_t maxWait);
size_t findMGAANOForDateInternal(const uint8_t *dataBytes, size_t numDataBytes, uint16_t year, uint8_t month, uint8_t day, uint8_t daysIntoFuture);
// Return true if this "automatic" message has storage allocated for it
bool checkAutomatic(uint8_t Class, uint8_t ID);
@@ -1297,12 +1530,18 @@ private:
bool initPacketUBXNAVVELNED(); // Allocate RAM for packetUBXNAVVELNED and initialize it
bool initPacketUBXNAVHPPOSECEF(); // Allocate RAM for packetUBXNAVHPPOSECEF and initialize it
bool initPacketUBXNAVHPPOSLLH(); // Allocate RAM for packetUBXNAVHPPOSLLH and initialize it
bool initPacketUBXNAVPVAT(); // Allocate RAM for packetUBXNAVPVAT and initialize it
bool initPacketUBXNAVCLOCK(); // Allocate RAM for packetUBXNAVCLOCK and initialize it
bool initPacketUBXNAVTIMELS(); // Allocate RAM for packetUBXNAVTIMELS and initialize it
bool initPacketUBXNAVSVIN(); // Allocate RAM for packetUBXNAVSVIN and initialize it
bool initPacketUBXNAVSAT(); // Allocate RAM for packetUBXNAVSAT and initialize it
bool initPacketUBXNAVRELPOSNED(); // Allocate RAM for packetUBXNAVRELPOSNED and initialize it
bool initPacketUBXNAVAOPSTATUS(); // Allocate RAM for packetUBXNAVAOPSTATUS and initialize it
bool initPacketUBXRXMPMP(); // Allocate RAM for packetUBXRXMPMP and initialize it
bool initPacketUBXRXMPMPmessage(); // Allocate RAM for packetUBXRXMPMPRaw and initialize it
bool initPacketUBXRXMSFRBX(); // Allocate RAM for packetUBXRXMSFRBX and initialize it
bool initPacketUBXRXMRAWX(); // Allocate RAM for packetUBXRXMRAWX and initialize it
bool initPacketUBXCFGPRT(); // Allocate RAM for packetUBXCFGPRT and initialize it
bool initPacketUBXCFGRATE(); // Allocate RAM for packetUBXCFGRATE and initialize it
bool initPacketUBXTIMTM2(); // Allocate RAM for packetUBXTIMTM2 and initialize it
bool initPacketUBXESFALG(); // Allocate RAM for packetUBXESFALG and initialize it
@@ -1313,13 +1552,18 @@ private:
bool initPacketUBXHNRATT(); // Allocate RAM for packetUBXHNRATT and initialize it
bool initPacketUBXHNRINS(); // Allocate RAM for packetUBXHNRINS and initialize it
bool initPacketUBXHNRPVT(); // Allocate RAM for packetUBXHNRPVT and initialize it
bool initPacketUBXMGAACK(); // Allocate RAM for packetUBXMGAACK and initialize it
bool initPacketUBXMGADBD(); // Allocate RAM for packetUBXMGADBD and initialize it
bool initStorageNMEAGPGGA(); // Allocate RAM for incoming NMEA GPGGA messages and initialize it
bool initStorageNMEAGNGGA(); // Allocate RAM for incoming NMEA GNGGA messages and initialize it
// Variables
TwoWire *_i2cPort; // The generic connection to user's chosen I2C hardware
Stream *_serialPort; // The generic connection to user's chosen Serial hardware
Stream *_nmeaOutputPort = NULL; // The user can assign an output port to print NMEA sentences if they wish
Stream *_debugSerial; // The stream to send debug messages to if enabled
Stream *_outputPort = NULL;
SPIClass *_spiPort; // The instance of SPIClass
uint8_t _csPin; // The chip select pin
uint32_t _spiSpeed; // The speed to use for SPI (Hz)
@@ -1386,6 +1630,18 @@ 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
bool isThisNMEAauto(); // Check if the NMEA message (in nmeaAddressField) is "auto" (i.e. has RAM allocated for it)
bool doesThisNMEAHaveCallback(); // Do we need to copy the data into the callback copy?
uint8_t *getNMEAWorkingLengthPtr(); // Get a pointer to the working copy length
uint8_t *getNMEAWorkingNMEAPtr(); // Get a pointer to the working copy NMEA data
uint8_t *getNMEACompleteLengthPtr(); // Get a pointer to the complete copy length
uint8_t *getNMEACompleteNMEAPtr(); // Get a pointer to the complete copy NMEA data
uint8_t *getNMEACallbackLengthPtr(); // Get a pointer to the callback copy length
uint8_t *getNMEACallbackNMEAPtr(); // Get a pointer to the callback copy NMEA data
uint8_t getNMEAMaxLength(); // Get the maximum length of this NMEA message
nmeaAutomaticFlags *getNMEAFlagsPtr(); // Get a pointer to the flags
uint16_t rtcmLen = 0;
@@ -1415,6 +1671,9 @@ 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
+90 -6
View File
@@ -134,6 +134,7 @@ const uint32_t UBLOX_CFG_I2C_ENABLED = 0x10510003; // Flag to indicate if the I2
const uint32_t UBLOX_CFG_I2CINPROT_UBX = 0x10710001; // Flag to indicate if UBX should be an input protocol on I2C
const uint32_t UBLOX_CFG_I2CINPROT_NMEA = 0x10710002; // Flag to indicate if NMEA should be an input protocol on I2C
const uint32_t UBLOX_CFG_I2CINPROT_RTCM3X = 0x10710004; // Flag to indicate if RTCM3X should be an input protocol on I2C
const uint32_t UBLOX_CFG_I2CINPROT_SPARTN = 0x10710005; // Flag to indicate if SPARTN should be an input protocol on I2C
// CFG-I2COUTPROT: Output protocol configuration of the I2C interface
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
@@ -380,6 +381,11 @@ const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_SPAN_SPI = 0x2091038f; // Output rate
const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_SPAN_UART1 = 0x2091038c; // Output rate of the UBX-MON-SPAN message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_SPAN_UART2 = 0x2091038d; // Output rate of the UBX-MON-SPAN message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_SPAN_USB = 0x2091038e; // Output rate of the UBX-MON-SPAN message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_SYS_I2C = 0x2091069d; // Output rate of the UBX-MON-SYS message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_SYS_SPI = 0x209106a1; // Output rate of the UBX-MON-SYS message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_SYS_UART1 = 0x2091069e; // Output rate of the UBX-MON-SYS message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_SYS_UART2 = 0x2091069f; // Output rate of the UBX-MON-SYS message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_SYS_USB = 0x209106a0; // Output rate of the UBX-MON-SYS message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_TXBUF_I2C = 0x2091019b; // Output rate of the UBX-MON-TXBUF message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_TXBUF_SPI = 0x2091019f; // Output rate of the UBX-MON-TXBUF message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_TXBUF_UART1 = 0x2091019c; // Output rate of the UBX-MON-TXBUF message on port UART1
@@ -430,6 +436,11 @@ const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_ORB_SPI = 0x20910014; // Output rate
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_ORB_UART1 = 0x20910011; // Output rate of the UBX-NAV-ORB message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_ORB_UART2 = 0x20910012; // Output rate of the UBX-NAV-ORB message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_ORB_USB = 0x20910013; // Output rate of the UBX-NAV-ORB message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_PL_I2C = 0x20910415; // Output rate of the UBX-NAV-PL message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_PL_SPI = 0x20910419; // Output rate of the UBX-NAV-PL message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_PL_UART1 = 0x20910416; // Output rate of the UBX-NAV-PL message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_PL_UART2 = 0x20910417; // Output rate of the UBX-NAV-PL message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_PL_USB = 0x20910418; // Output rate of the UBX-NAV-PL message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_POSECEF_I2C = 0x20910024; // Output rate of the UBX-NAV-POSECEF message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_POSECEF_SPI = 0x20910028; // Output rate of the UBX-NAV-POSECEF message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_POSECEF_UART1 = 0x20910025; // Output rate of the UBX-NAV-POSECEF message on port UART1
@@ -525,6 +536,11 @@ const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_VELNED_SPI = 0x20910046; // Output rate
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_VELNED_UART1 = 0x20910043; // Output rate of the UBX-NAV-VELNED message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_VELNED_UART2 = 0x20910044; // Output rate of the UBX-NAV-VELNED message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_VELNED_USB = 0x20910045; // Output rate of the UBX-NAV-VELNED message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_COR_I2C = 0x209106b6; // Output rate of the UBX-RXM-COR message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_COR_SPI = 0x209106ba; // Output rate of the UBX-RXM-COR message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_COR_UART1 = 0x209106b7; // Output rate of the UBX-RXM-COR message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_COR_UART2 = 0x209106b8; // Output rate of the UBX-RXM-COR message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_COR_USB = 0x209106b9; // Output rate of the UBX-RXM-COR message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_MEASX_I2C = 0x20910204; // Output rate of the UBX-RXM-MEASX message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_MEASX_SPI = 0x20910208; // Output rate of the UBX-RXM-MEASX message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_MEASX_UART1 = 0x20910205; // Output rate of the UBX-RXM-MEASX message on port UART1
@@ -550,6 +566,16 @@ const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_SFRBX_SPI = 0x20910235; // Output rate
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_SFRBX_UART1 = 0x20910232; // Output rate of the UBX-RXM-SFRBX message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_SFRBX_UART2 = 0x20910233; // Output rate of the UBX-RXM-SFRBX message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_SFRBX_USB = 0x20910234; // Output rate of the UBX-RXM-SFRBX message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_SPARTN_I2C = 0x20910605; // Output rate of the UBX-RXM-SPARTN message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_SPARTN_UART1 = 0x20910606; // Output rate of the UBX-RXM-SPARTN message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_SPARTN_UART2 = 0x20910607; // Output rate of the UBX-RXM-SPARTN message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_SPARTN_USB = 0x20910608; // Output rate of the UBX-RXM-SPARTN message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_SPARTN_SPI = 0x20910609; // Output rate of the UBX-RXM-SPARTN message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIG_I2C = 0x20910634; // Output rate of the UBX-SEC-SIG message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIG_SPI = 0x20910638; // Output rate of the UBX-SEC-SIG message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIG_UART1 = 0x20910635; // Output rate of the UBX-SEC-SIG message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIG_UART2 = 0x20910636; // Output rate of the UBX-SEC-SIG message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIG_USB = 0x20910637; // Output rate of the UBX-SEC-SIG message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_TM2_I2C = 0x20910178; // Output rate of the UBX-TIM-TM2 message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_TM2_SPI = 0x2091017c; // Output rate of the UBX-TIM-TM2 message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_TM2_UART1 = 0x20910179; // Output rate of the UBX-TIM-TM2 message on port UART1
@@ -566,7 +592,7 @@ const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_VRFY_UART1 = 0x20910093; // Output rat
const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_VRFY_UART2 = 0x20910094; // Output rate of the UBX-TIM-VRFY message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_VRFY_USB = 0x20910095; // Output rate of the UBX-TIM-VRFY message on port USB
//Additional CFG_MSGOUT keys for the ZED-F9R HPS120
// Additional CFG_MSGOUT keys for the ZED-F9R HPS121
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_COV_I2C = 0x20910083; // Output rate of the UBX-NAV-COV message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_COV_UART1 = 0x20910084; // Output rate of the UBX-NAV-COV message on port UART1
@@ -608,6 +634,11 @@ const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_EELL_UART1 = 0x20910314; // Output rate
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_EELL_UART2 = 0x20910315; // Output rate of the UBX-NAV-EELL message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_EELL_USB = 0x20910316; // Output rate of the UBX-NAV-EELL message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_EELL_SPI = 0x20910317; // Output rate of the UBX-NAV-EELL message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_PVAT_I2C = 0x2091062a; // Output rate of the UBX-NAV-PVAT message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_PVAT_UART1 = 0x2091062b; // Output rate of the UBX-NAV-PVAT message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_PVAT_UART2 = 0x2091062c; // Output rate of the UBX-NAV-PVAT message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_PVAT_USB = 0x2091062d; // Output rate of the UBX-NAV-PVAT message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_PVAT_SPI = 0x2091062e; // Output rate of the UBX-NAV-PVAT message on port SPI
// Additional CFG_MSGOUT keys for the ZED-F9T
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
@@ -701,11 +732,21 @@ const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_SIG_SPI = 0x20910509; // Output rate of
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_SIG_UART1 = 0x20910506; // Output rate of the UBX-NAV2-SIG message onport UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_SIG_UART2 = 0x20910507; // Output rate of the UBX-NAV2-SIG message onport UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_SIG_USB = 0x20910508; // Output rate of the UBX-NAV2-SIG message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_SLAS_I2C = 0x20910510; // Output rate of the UBX-NAV2-SLAS message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_SLAS_SPI = 0x20910514; // Output rate of the UBX-NAV2-SLAS message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_SLAS_UART1 = 0x20910511; // Output rate of the UBX-NAV2-SLAS message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_SLAS_UART2 = 0x20910512; // Output rate of the UBX-NAV2-SLAS message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_SLAS_USB = 0x20910513; // Output rate of the UBX-NAV2-SLAS message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_STATUS_I2C = 0x20910515; // Output rate of the UBX-NAV2-STATUS message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_STATUS_SPI = 0x20910519; // Output rate of the UBX-NAV2-STATUS message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_STATUS_UART1 = 0x20910516; // Output rate of the UBX-NAV2-STATUS message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_STATUS_UART2 = 0x20910517; // Output rate of the UBX-NAV2-STATUS message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_STATUS_USB = 0x20910518; // Output rate of the UBX-NAV2-STATUS message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_SVIN_I2C = 0x20910520; // Output rate of the UBX-NAV2-SVIN message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_SVIN_SPI = 0x20910524; // Output rate of the UBX-NAV2-SVIN message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_SVIN_UART1 = 0x20910521; // Output rate of the UBX-NAV2-SVIN message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_SVIN_UART2 = 0x20910522; // Output rate of the UBX-NAV2-SVIN message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_SVIN_USB = 0x20910523; // Output rate of the UBX-NAV2-SVIN message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_TIMEBDS_I2C = 0x20910525; // Output rate of the UBX-NAV2-TIMEBDS message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_TIMEBDS_SPI = 0x20910529; // Output rate of the UBX-NAV2-TIMEBDS message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_TIMEBDS_UART1 = 0x20910526; // Output rate of the UBX-NAV2-TIMEBDS message on port UART1
@@ -731,6 +772,11 @@ const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_TIMELS_SPI = 0x20910549; // Output rate
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_TIMELS_UART1 = 0x20910546; // Output rate of the UBX-NAV2-TIMELS message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_TIMELS_UART2 = 0x20910547; // Output rate of the UBX-NAV2-TIMELS message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_TIMELS_USB = 0x20910548; // Output rate of the UBX-NAV2-TIMELS message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_TIMEQZSS_I2C = 0x20910575; // Output rate of the UBX-NAV2-TIMEQZSS message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_TIMEQZSS_SPI = 0x20910579; // Output rate of the UBX-NAV2-TIMEQZSS message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_TIMEQZSS_UART1 = 0x20910576; // Output rate of the UBX-NAV2-TIMEQZSS message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_TIMEQZSS_UART2 = 0x20910577; // Output rate of the UBX-NAV2-TIMEQZSS message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_TIMEQZSS_USB = 0x20910578; // Output rate of the UBX-NAV2-TIMEQZSS message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_TIMEUTC_I2C = 0x20910550; // Output rate of the UBX-NAV2-TIMEUTC message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_TIMEUTC_SPI = 0x20910554; // Output rate of the UBX-NAV2-TIMEUTC message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV2_TIMEUTC_UART1 = 0x20910551; // Output rate of the UBX-NAV2-TIMEUTC message on port UART1
@@ -761,17 +807,25 @@ const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIGLOG_SPI = 0x2091068d; // Output rate
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIGLOG_UART1 = 0x2091068a; // Output rate of the UBX-SEC-SIGLOG message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIGLOG_UART2 = 0x2091068b; // Output rate of the UBX-SEC-SIGLOG message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIGLOG_USB = 0x2091068c; // Output rate of the UBX-SEC-SIGLOG message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIG_I2C = 0x20910634; // Output rate of the UBX-DBG-SKYMAP message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIG_SPI = 0x20910638; // Output rate of the UBX-SEC-SIG message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIG_UART1 = 0x20910635; // Output rate of the UBX-SEC-SIG message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIG_UART2 = 0x20910636; // Output rate of the UBX-SEC-SIG message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIG_USB = 0x20910637; // Output rate of the UBX-SEC-SIG message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_SVIN_I2C = 0x20910097; // Output rate of the UBX-TIM-SVIN message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_SVIN_SPI = 0x2091009b; // Output rate of the UBX-TIM-SVIN message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_SVIN_UART1 = 0x20910098; // Output rate of the UBX-TIM-SVIN message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_SVIN_UART2 = 0x20910099; // Output rate of the UBX-TIM-SVIN message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_SVIN_USB = 0x2091009a; // Output rate of the UBX-TIM-SVIN message on port USB
// Additional CFG_MSGOUT keys for the NEO-D9S
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_PMP_I2C = 0x2091031d; // Output rate of the UBX_RXM_PMP message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_PMP_SPI = 0x20910321; // Output rate of the UBX_RXM_PMP message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_PMP_UART1 = 0x2091031e; // Output rate of the UBX_RXM_PMP message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_PMP_UART2 = 0x2091031f; // Output rate of the UBX_RXM_PMP message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_PMP_USB = 0x20910320; // Output rate of the UBX_RXM_PMP message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_PMP_I2C = 0x20910322; // Output rate of the UBX_MON_PMP message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_PMP_SPI = 0x20910326; // Output rate of the UBX_MON_PMP message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_PMP_UART1 = 0x20910323; // Output rate of the UBX_MON_PMP message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_PMP_UART2 = 0x20910324; // Output rate of the UBX_MON_PMP message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_MON_PMP_USB = 0x20910325; // Output rate of the UBX_MON_PMP message on port USB
// CFG-NAV2: Secondary output configuration
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
const uint32_t UBLOX_CFG_NAV2_OUT_ENABLED = 0x10170001; // Enable secondary (NAV2) output
@@ -815,6 +869,7 @@ const uint32_t UBLOX_CFG_NAVSPG_CONSTR_ALT = 0x401100c1; // Fixed altitude (mean
const uint32_t UBLOX_CFG_NAVSPG_CONSTR_ALTVAR = 0x401100c2; // Fixed altitude variance for 2D mode
const uint32_t UBLOX_CFG_NAVSPG_CONSTR_DGNSSTO = 0x201100c4; // DGNSS timeout
const uint32_t UBLOX_CFG_NAVSPG_SIGATTCOMP = 0x201100d6; // Permanently attenuated signal compensation mode
const uint32_t UBLOX_CFG_NAVSPG_PL_ENA = 0x101100d7; // Enable Protection level. If enabled, protection level computing will be on.
// CFG-NMEA: NMEA protocol configuration
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
@@ -853,11 +908,32 @@ const uint32_t UBLOX_CFG_ODO_COGMAXPOSACC = 0x20220022; // Maximum acceptable po
const uint32_t UBLOX_CFG_ODO_VELLPGAIN = 0x20220031; // Velocity low-pass filter level
const uint32_t UBLOX_CFG_ODO_COGLPGAIN = 0x20220032; // Course over ground low-pass filter level (at speed < 8 m/s)
// CFG-PM: Configuration for receiver power management (NEO-D9S)
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
const uint32_t UBLOX_CFG_PM_EXTINTSEL = 0x20d0000b; // EXTINT pin select
const uint32_t UBLOX_CFG_PM_EXTINTWAKE = 0x10d0000c; // EXTINT pin control (Wake). Enable to keep receiver awake as long as selected EXTINT pin is "high".
const uint32_t UBLOX_CFG_PM_EXTINTBACKUP = 0x10d0000d; // EXTINT pin control (Backup). Enable to force receiver into BACKUP mode when selected EXTINT pin is "low".
const uint32_t UBLOX_CFG_PM_EXTINTINACTIVE = 0x10d0000e; // EXTINT pin control (Inactive). Enable to force backup in case EXTINT Pin is inactive for time longer than CFG-PM-EXTINTINACTIVITY.
const uint32_t UBLOX_CFG_PM_EXTINTINACTIVITY = 0x40d0000f; // Inactivity time out on EXTINT pin if enabled
// CFG-PMP: Point to multipoint (PMP) configuration (NEO-D9S)
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
const uint32_t UBLOX_CFG_PMP_CENTER_FREQUENCY = 0x40b10011; // Center frequency. The center frequency for the receiver can be set from 1525000000 to 1559000000 Hz.
const uint32_t UBLOX_CFG_PMP_SEARCH_WINDOW = 0x30b10012; // Search window. Search window can be set from 0 to 65535 Hz. It is +/- this value from the center frequency set by CENTER_FREQUENCY.
const uint32_t UBLOX_CFG_PMP_USE_SERVICE_ID = 0x10b10016; // Use service ID. Enable/disable service ID check to confirm the correct service is received.
const uint32_t UBLOX_CFG_PMP_SERVICE_ID = 0x30b10017; // Service identifier. Defines the expected service ID.
const uint32_t UBLOX_CFG_PMP_DATA_RATE = 0x30b10013; // bps Data rate. The data rate of the received data.
const uint32_t UBLOX_CFG_PMP_USE_DESCRAMBLER = 0x10b10014; // Use descrambler. Enables/disables the descrambler.
const uint32_t UBLOX_CFG_PMP_DESCRAMBLER_INIT = 0x30b10015; // Descrambler initialization. Set the intialisation value for the descrambler.
const uint32_t UBLOX_CFG_PMP_USE_PRESCRAMBLING = 0x10b10019; // Use prescrambling. Enables/disables the prescrambling.
const uint32_t UBLOX_CFG_PMP_UNIQUE_WORD = 0x50b1001a; // Unique word. Defines value of unique word.
// CFG-QZSS: QZSS system configuration
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
const uint32_t UBLOX_CFG_QZSS_USE_SLAS_DGNSS = 0x10370005; // Apply QZSS SLAS DGNSS corrections
const uint32_t UBLOX_CFG_QZSS_USE_SLAS_TESTMODE = 0x10370006; // Use QZSS SLAS data when it is in test mode (SLAS msg 0)
const uint32_t UBLOX_CFG_QZSS_USE_SLAS_RAIM_UNCORR = 0x10370007; // Raim out measurements that are not corrected by QZSS SLAS, if at least 5 measurements are corrected
const uint32_t UBLOX_CFG_QZSS_SLAS_MAX_BASELINE = 0x30370008; // Maximum baseline distance to closest Ground Monitoring Station: km
// CFG-RATE: Navigation and measurement rate configuration
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
@@ -963,6 +1039,10 @@ const uint32_t UBLOX_CFG_SIGNAL_GLO_ENA = 0x10310025; // GLONASS enable
const uint32_t UBLOX_CFG_SIGNAL_GLO_L1_ENA = 0x10310018; // GLONASS L1
const uint32_t UBLOX_CFG_SIGNAL_GLO_L2_ENA = 0x1031001a; // GLONASS L2 (only on u-blox F9 platform products)
// CFG-SPARTN: Configuration of the SPARTN interface
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
const uint32_t UBLOX_CFG_SPARTN_USE_SOURCE = 0x20a70001;
// CFG-SPI: Configuration of the SPI interface
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
const uint32_t UBLOX_CFG_SPI_MAXFF = 0x20640001; // Number of bytes containing 0xFF to receive before switching off reception. Range: 0 (mechanism off) - 63
@@ -976,6 +1056,7 @@ const uint32_t UBLOX_CFG_SPI_ENABLED = 0x10640006; // Flag to indicate if the SP
const uint32_t UBLOX_CFG_SPIINPROT_UBX = 0x10790001; // Flag to indicate if UBX should be an input protocol on SPI
const uint32_t UBLOX_CFG_SPIINPROT_NMEA = 0x10790002; // Flag to indicate if NMEA should be an input protocol on SPI
const uint32_t UBLOX_CFG_SPIINPROT_RTCM3X = 0x10790004; // Flag to indicate if RTCM3X should be an input protocol on SPI
const uint32_t UBLOX_CFG_SPIINPROT_SPARTN = 0x10790005; // Flag to indicate if SPARTN should be an input protocol on SPI
// CFG-SPIOUTPROT: Output protocol configuration of the SPI interface
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
@@ -1062,6 +1143,7 @@ const uint32_t UBLOX_CFG_UART1_ENABLED = 0x10520005; // Flag to indicate if the
const uint32_t UBLOX_CFG_UART1INPROT_UBX = 0x10730001; // Flag to indicate if UBX should be an input protocol on UART1
const uint32_t UBLOX_CFG_UART1INPROT_NMEA = 0x10730002; // Flag to indicate if NMEA should be an input protocol on UART1
const uint32_t UBLOX_CFG_UART1INPROT_RTCM3X = 0x10730004; // Flag to indicate if RTCM3X should be an input protocol on UART1
const uint32_t UBLOX_CFG_UART1INPROT_SPARTN = 0x10730005; // Flag to indicate if SPARTN should be an input protocol on UART1
// CFG-UART1OUTPROT: Output protocol configuration of the UART1 interface
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
@@ -1083,6 +1165,7 @@ const uint32_t UBLOX_CFG_UART2_REMAP = 0x10530006; // UART2 Remapping
const uint32_t UBLOX_CFG_UART2INPROT_UBX = 0x10750001; // Flag to indicate if UBX should be an input protocol on UART2
const uint32_t UBLOX_CFG_UART2INPROT_NMEA = 0x10750002; // Flag to indicate if NMEA should be an input protocol on UART2
const uint32_t UBLOX_CFG_UART2INPROT_RTCM3X = 0x10750004; // Flag to indicate if RTCM3X should be an input protocol on UART2
const uint32_t UBLOX_CFG_UART2INPROT_SPARTN = 0x10750005; // Flag to indicate if SPARTN should be an input protocol on UART2
// CFG-UART2OUTPROT: Output protocol configuration of the UART2 interface
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
@@ -1115,6 +1198,7 @@ const uint32_t UBLOX_CFG_USB_SERIAL_NO_STR3 = 0x50650018; // Serial number strin
const uint32_t UBLOX_CFG_USBINPROT_UBX = 0x10770001; // Flag to indicate if UBX should be an input protocol on USB
const uint32_t UBLOX_CFG_USBINPROT_NMEA = 0x10770002; // Flag to indicate if NMEA should be an input protocol on USB
const uint32_t UBLOX_CFG_USBINPROT_RTCM3X = 0x10770004; // Flag to indicate if RTCM3X should be an input protocol on USB
const uint32_t UBLOX_CFG_USBINPROT_SPARTN = 0x10770005; // Flag to indicate if SPARTN should be an input protocol on USB
// CFG-USBOUTPROT: Output protocol configuration of the USB interface
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+541 -2
View File
@@ -65,6 +65,8 @@ struct ubxAutomaticFlags
} flags;
};
// NAV-specific structs
// UBX-NAV-POSECEF (0x01 0x01): Position solution in ECEF
const uint16_t UBX_NAV_POSECEF_LEN = 20;
@@ -101,6 +103,7 @@ typedef struct
UBX_NAV_POSECEF_data_t data;
UBX_NAV_POSECEF_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_NAV_POSECEF_data_t);
void (*callbackPointerPtr)(UBX_NAV_POSECEF_data_t *);
UBX_NAV_POSECEF_data_t *callbackData;
} UBX_NAV_POSECEF_t;
@@ -144,6 +147,7 @@ typedef struct
UBX_NAV_POSLLH_data_t data;
UBX_NAV_POSLLH_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_NAV_POSLLH_data_t);
void (*callbackPointerPtr)(UBX_NAV_POSLLH_data_t *);
UBX_NAV_POSLLH_data_t *callbackData;
} UBX_NAV_POSLLH_t;
@@ -244,6 +248,7 @@ typedef struct
UBX_NAV_STATUS_data_t data;
UBX_NAV_STATUS_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_NAV_STATUS_data_t);
void (*callbackPointerPtr)(UBX_NAV_STATUS_data_t *);
UBX_NAV_STATUS_data_t *callbackData;
} UBX_NAV_STATUS_t;
@@ -289,6 +294,7 @@ typedef struct
UBX_NAV_DOP_data_t data;
UBX_NAV_DOP_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_NAV_DOP_data_t);
void (*callbackPointerPtr)(UBX_NAV_DOP_data_t *);
UBX_NAV_DOP_data_t *callbackData;
} UBX_NAV_DOP_t;
@@ -335,6 +341,7 @@ typedef struct
UBX_NAV_ATT_data_t data;
UBX_NAV_ATT_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_NAV_ATT_data_t);
void (*callbackPointerPtr)(UBX_NAV_ATT_data_t *);
UBX_NAV_ATT_data_t *callbackData;
} UBX_NAV_ATT_t;
@@ -498,6 +505,7 @@ typedef struct
UBX_NAV_PVT_data_t data;
UBX_NAV_PVT_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_NAV_PVT_data_t);
void (*callbackPointerPtr)(UBX_NAV_PVT_data_t *);
UBX_NAV_PVT_data_t *callbackData;
} UBX_NAV_PVT_t;
@@ -538,6 +546,7 @@ typedef struct
UBX_NAV_ODO_data_t data;
UBX_NAV_ODO_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_NAV_ODO_data_t);
void (*callbackPointerPtr)(UBX_NAV_ODO_data_t *);
UBX_NAV_ODO_data_t *callbackData;
} UBX_NAV_ODO_t;
@@ -577,6 +586,7 @@ typedef struct
UBX_NAV_VELECEF_data_t data;
UBX_NAV_VELECEF_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_NAV_VELECEF_data_t);
void (*callbackPointerPtr)(UBX_NAV_VELECEF_data_t *);
UBX_NAV_VELECEF_data_t *callbackData;
} UBX_NAV_VELECEF_t;
@@ -624,6 +634,7 @@ typedef struct
UBX_NAV_VELNED_data_t data;
UBX_NAV_VELNED_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_NAV_VELNED_data_t);
void (*callbackPointerPtr)(UBX_NAV_VELNED_data_t *);
UBX_NAV_VELNED_data_t *callbackData;
} UBX_NAV_VELNED_t;
@@ -683,6 +694,7 @@ typedef struct
UBX_NAV_HPPOSECEF_data_t data;
UBX_NAV_HPPOSECEF_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_NAV_HPPOSECEF_data_t);
void (*callbackPointerPtr)(UBX_NAV_HPPOSECEF_data_t *);
UBX_NAV_HPPOSECEF_data_t *callbackData;
} UBX_NAV_HPPOSECEF_t;
@@ -748,9 +760,185 @@ typedef struct
UBX_NAV_HPPOSLLH_data_t data;
UBX_NAV_HPPOSLLH_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_NAV_HPPOSLLH_data_t);
void (*callbackPointerPtr)(UBX_NAV_HPPOSLLH_data_t *);
UBX_NAV_HPPOSLLH_data_t *callbackData;
} UBX_NAV_HPPOSLLH_t;
// UBX-NAV-PVAT (0x01 0x17): Navigation position velocity attitude time solution
const uint16_t UBX_NAV_PVAT_LEN = 116;
typedef struct
{
uint32_t iTOW; // GPS time of week of the navigation epoch: ms
uint8_t version; // Message version (0x00 for this version)
union
{
uint8_t all;
struct
{
uint8_t validDate : 1; // 1 = valid UTC Date
uint8_t validTime : 1; // 1 = valid UTC time of day
uint8_t fullyResolved : 1; // 1 = UTC time of day has been fully resolved (no seconds uncertainty).
uint8_t validMag : 1; // 1 = valid magnetic declination
} bits;
} valid;
uint16_t year; // Year (UTC)
uint8_t month; // Month, range 1..12 (UTC)
uint8_t day; // Day of month, range 1..31 (UTC)
uint8_t hour; // Hour of day, range 0..23 (UTC)
uint8_t min; // Minute of hour, range 0..59 (UTC)
uint8_t sec; // Seconds of minute, range 0..60 (UTC)
uint8_t reserved0;
uint8_t reserved1[2];
uint32_t tAcc; // Time accuracy estimate (UTC): ns
int32_t nano; // Fraction of second, range -1e9 .. 1e9 (UTC): ns
uint8_t fixType; // GNSSfix Type:
// 0: no fix
// 1: dead reckoning only
// 2: 2D-fix
// 3: 3D-fix
// 4: GNSS + dead reckoning combined
// 5: time only fix
union
{
uint8_t all;
struct
{
uint8_t gnssFixOK : 1; // 1 = valid fix (i.e within DOP & accuracy masks)
uint8_t diffSoln : 1; // 1 = differential corrections were applied
uint8_t reserved : 1;
uint8_t vehRollValid : 1; // 1 = roll of vehicle is valid, only set if the receiver is in sensor fusion mode
uint8_t vehPitchValid : 1; // 1 = pitch of vehicle is valid, only set if the receiver is in sensor fusion mode
uint8_t vehHeadingValid : 1; // 1 = heading of vehicle is valid, only set if the receiver is in sensor fusion mode
uint8_t carrSoln : 2; // Carrier phase range solution status:
// 0: no carrier phase range solution
// 1: carrier phase range solution with floating ambiguities
// 2: carrier phase range solution with fixed ambiguities
} bits;
} flags;
union
{
uint8_t all;
struct
{
uint8_t reserved : 5;
uint8_t confirmedAvai : 1; // 1 = information about UTC Date and Time of Day validity confirmation is available
uint8_t confirmedDate : 1; // 1 = UTC Date validity could be confirmed
uint8_t confirmedTime : 1; // 1 = UTC Time of Day could be confirmed
} bits;
} flags2;
uint8_t numSV; // Number of satellites used in Nav Solution
int32_t lon; // Longitude: deg * 1e-7
int32_t lat; // Latitude: deg * 1e-7
int32_t height; // Height above ellipsoid: mm
int32_t hMSL; // Height above mean sea level: mm
uint32_t hAcc; // Horizontal accuracy estimate: mm
uint32_t vAcc; // Vertical accuracy estimate: mm
int32_t velN; // NED north velocity: mm/s
int32_t velE; // NED east velocity: mm/s
int32_t velD; // NED down velocity: mm/s
int32_t gSpeed; // Ground Speed (2-D): mm/s
uint32_t sAcc; // Speed accuracy estimate: mm/s
int32_t vehRoll; // Vehicle roll: 1e-5 deg
int32_t vehPitch; // Vehicle pitch: 1e-5 deg
int32_t vehHeading; // Vehicle heading: 1e-5 deg
int32_t motHeading; // Motion heading.: 1e-5 deg
uint16_t accRoll; // Vehicle roll accuracy (if null, roll angle is not available): 1e-2 deg
uint16_t accPitch; // Vehicle pitch accuracy (if null, pitch angle is not available): 1e-2 deg
uint16_t accHeading; // Vehicle heading accuracy (if null, heading angle is not available): 1e-2 deg
int16_t magDec; // Magnetic declination: 1e-2 deg
uint16_t magAcc; // Magnetic declination accuracy: 1e-2 deg
uint16_t errEllipseOrient; // Orientation of semi-major axis of error ellipse (degrees from true north): 1e-2 deg
uint32_t errEllipseMajor; // Semi-major axis of error ellipse: mm
uint32_t errEllipseMinor; // Semi-minor axis of error ellipse: mm
uint8_t reserved2[4];
uint8_t reserved3[4];
} UBX_NAV_PVAT_data_t;
typedef struct
{
union
{
uint32_t all;
struct
{
uint32_t all : 1;
uint32_t iTOW : 1;
uint32_t version : 1;
uint32_t validDate : 1;
uint32_t validTime : 1;
uint32_t fullyResolved : 1;
uint32_t validMag : 1;
uint32_t year : 1;
uint32_t month : 1;
uint32_t day : 1;
uint32_t hour : 1;
uint32_t min : 1;
uint32_t sec : 1;
uint32_t tAcc : 1;
uint32_t nano : 1;
uint32_t fixType : 1;
uint32_t gnssFixOK : 1;
uint32_t diffSoln : 1;
uint32_t vehRollValid : 1;
uint32_t vehPitchValid : 1;
uint32_t vehHeadingValid : 1;
uint32_t carrSoln : 1;
uint32_t confirmedAvai : 1;
uint32_t confirmedDate : 1;
uint32_t confirmedTime : 1;
uint32_t numSV : 1;
uint32_t lon : 1;
uint32_t lat : 1;
uint32_t height : 1;
uint32_t hMSL : 1;
uint32_t hAcc : 1;
uint32_t vAcc : 1;
} bits;
} moduleQueried1;
union
{
uint32_t all;
struct
{
uint32_t velN : 1;
uint32_t velE : 1;
uint32_t velD : 1;
uint32_t gSpeed : 1;
uint32_t sAcc : 1;
uint32_t vehRoll : 1;
uint32_t vehPitch : 1;
uint32_t vehHeading : 1;
uint32_t motHeading : 1;
uint32_t accRoll : 1;
uint32_t accPitch : 1;
uint32_t accHeading : 1;
uint32_t magDec : 1;
uint32_t magAcc : 1;
uint32_t errEllipseOrient : 1;
uint32_t errEllipseMajor : 1;
uint32_t errEllipseMinor : 1;
} bits;
} moduleQueried2;
} UBX_NAV_PVAT_moduleQueried_t;
typedef struct
{
ubxAutomaticFlags automaticFlags;
UBX_NAV_PVAT_data_t data;
UBX_NAV_PVAT_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_NAV_PVAT_data_t);
void (*callbackPointerPtr)(UBX_NAV_PVAT_data_t *);
UBX_NAV_PVAT_data_t *callbackData;
} UBX_NAV_PVAT_t;
// UBX-NAV-TIMEUTC (0x01 0x21): UTC time solution
const uint16_t UBX_NAV_TIMEUTC_LEN = 20;
@@ -812,6 +1000,7 @@ typedef struct
UBX_NAV_TIMEUTC_data_t data;
UBX_NAV_TIMEUTC_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_NAV_TIMEUTC_data_t);
void (*callbackPointerPtr)(UBX_NAV_TIMEUTC_data_t *);
UBX_NAV_TIMEUTC_data_t *callbackData;
} UBX_NAV_TIMEUTC_t;
@@ -851,6 +1040,7 @@ typedef struct
UBX_NAV_CLOCK_data_t data;
UBX_NAV_CLOCK_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_NAV_CLOCK_data_t);
void (*callbackPointerPtr)(UBX_NAV_CLOCK_data_t *);
UBX_NAV_CLOCK_data_t *callbackData;
} UBX_NAV_CLOCK_t;
@@ -911,9 +1101,84 @@ typedef struct
UBX_NAV_TIMELS_data_t data;
UBX_NAV_TIMELS_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_NAV_TIMELS_data_t);
void (*callbackPointerPtr)(UBX_NAV_TIMELS_data_t *);
UBX_NAV_TIMELS_data_t *callbackData;
} UBX_NAV_TIMELS_t;
// UBX-NAV-SAT (0x01 0x35): Satellite Information
const uint16_t UBX_NAV_SAT_MAX_BLOCKS = 255; // numSvs is 8-bit
const uint16_t UBX_NAV_SAT_MAX_LEN = 8 + (12 * UBX_NAV_SAT_MAX_BLOCKS);
typedef struct
{
uint32_t iTOW; // GPS time of week
uint8_t version; // Message version (0x01 for this version)
uint8_t numSvs; // Number of satellites
uint8_t reserved1[2];
} UBX_NAV_SAT_header_t;
typedef struct
{
uint8_t gnssId; // GNSS identifier
uint8_t svId; // Satellite identifier
uint8_t cno; // Carrier-to-noise density ratio: dB-Hz
int8_t elev; // Elevation (range: +/-90): deg
int16_t azim; // Azimuth (range 0-360): deg
int16_t prRes; // Pseudorange residual: m * 0.1
union
{
uint32_t all;
struct
{
uint32_t qualityInd : 3; // Signal quality indicator: 0: no signal
// 1: searching signal
// 2: signal acquired
// 3: signal detected but unusable
// 4: code locked and time synchronized
// 5, 6, 7: code and carrier locked and time synchronized
uint32_t svUsed : 1; // 1 = Signal in the subset specified in Signal Identifiers is currently being used for navigation
uint32_t health : 2; // Signal health flag: 0: unknown 1: healthy 2: unhealthy
uint32_t diffCorr : 1; // 1 = differential correction data is available for this SV
uint32_t smoothed : 1; // 1 = carrier smoothed pseudorange used
uint32_t orbitSource : 3; // Orbit source: 0: no orbit information is available for this SV
// 1: ephemeris is used
// 2: almanac is used
// 3: AssistNow Offline orbit is used
// 4: AssistNow Autonomous orbit is used
// 5, 6, 7: other orbit information is used
uint32_t ephAvail : 1; // 1 = ephemeris is available for this SV
uint32_t almAvail : 1; // 1 = almanac is available for this SV
uint32_t anoAvail : 1; // 1 = AssistNow Offline data is available for this SV
uint32_t aopAvail : 1; // 1 = AssistNow Autonomous data is available for this SV
uint32_t reserved1 : 1;
uint32_t sbasCorrUsed : 1; // 1 = SBAS corrections have been used for a signal in the subset specified in Signal Identifiers
uint32_t rtcmCorrUsed : 1; // 1 = RTCM corrections have been used for a signal in the subset specified in Signal Identifiers
uint32_t slasCorrUsed : 1; // 1 = QZSS SLAS corrections have been used for a signal in the subset specified in Signal Identifiers
uint32_t spartnCorrUsed : 1; // 1 = SPARTN corrections have been used for a signal in the subset specified in Signal Identifiers
uint32_t prCorrUsed : 1; // 1 = Pseudorange corrections have been used for a signal in the subset specified in Signal Identifiers
uint32_t crCorrUsed : 1; // 1 = Carrier range corrections have been used for a signal in the subset specified in Signal Identifiers
uint32_t doCorrUsed : 1; // 1 = Range rate (Doppler) corrections have been used for a signal in the subset specified in Signal Identifiers
uint32_t reserved2 : 9;
} bits;
} flags;
} UBX_NAV_SAT_block_t;
typedef struct
{
UBX_NAV_SAT_header_t header;
UBX_NAV_SAT_block_t blocks[UBX_NAV_SAT_MAX_BLOCKS];
} UBX_NAV_SAT_data_t;
typedef struct
{
ubxAutomaticFlags automaticFlags;
UBX_NAV_SAT_data_t data;
bool moduleQueried;
void (*callbackPointer)(UBX_NAV_SAT_data_t);
void (*callbackPointerPtr)(UBX_NAV_SAT_data_t *);
UBX_NAV_SAT_data_t *callbackData;
} UBX_NAV_SAT_t;
// UBX-NAV-SVIN (0x01 0x3B): Survey-in data
const uint16_t UBX_NAV_SVIN_LEN = 40;
@@ -969,6 +1234,7 @@ typedef struct
UBX_NAV_SVIN_data_t data;
UBX_NAV_SVIN_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_NAV_SVIN_data_t);
void (*callbackPointerPtr)(UBX_NAV_SVIN_data_t *);
UBX_NAV_SVIN_data_t *callbackData;
} UBX_NAV_SVIN_t;
@@ -1068,9 +1334,56 @@ typedef struct
UBX_NAV_RELPOSNED_data_t data;
UBX_NAV_RELPOSNED_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_NAV_RELPOSNED_data_t);
void (*callbackPointerPtr)(UBX_NAV_RELPOSNED_data_t *);
UBX_NAV_RELPOSNED_data_t *callbackData;
} UBX_NAV_RELPOSNED_t;
// UBX-NAV-AOPSTATUS (0x01 0x60): AssistNow Autonomous status
const uint16_t UBX_NAV_AOPSTATUS_LEN = 16;
typedef struct
{
uint32_t iTOW; // GPS time of week of the navigation epoch: ms
union
{
uint8_t all;
struct
{
uint8_t useAOP : 1; // AOP enabled flag
} bits;
} aopCfg; // AssistNow Autonomous configuration
uint8_t status; // AssistNow Autonomous subsystem is idle (0) or running (not 0)
uint8_t reserved1[10];
} UBX_NAV_AOPSTATUS_data_t;
typedef struct
{
union
{
uint32_t all;
struct
{
uint32_t all : 1;
uint32_t iTOW : 1;
uint32_t useAOP : 1;
uint32_t status : 1;
} bits;
} moduleQueried;
} UBX_NAV_AOPSTATUS_moduleQueried_t;
typedef struct
{
ubxAutomaticFlags automaticFlags;
UBX_NAV_AOPSTATUS_data_t data;
UBX_NAV_AOPSTATUS_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_NAV_AOPSTATUS_data_t);
void (*callbackPointerPtr)(UBX_NAV_AOPSTATUS_data_t *);
UBX_NAV_AOPSTATUS_data_t *callbackData;
} UBX_NAV_AOPSTATUS_t;
// RXM-specific structs
// UBX-RXM-SFRBX (0x02 0x13): Broadcast navigation data subframe
@@ -1099,6 +1412,7 @@ typedef struct
UBX_RXM_SFRBX_data_t data;
bool moduleQueried;
void (*callbackPointer)(UBX_RXM_SFRBX_data_t);
void (*callbackPointerPtr)(UBX_RXM_SFRBX_data_t *);
UBX_RXM_SFRBX_data_t *callbackData;
} UBX_RXM_SFRBX_t;
@@ -1166,11 +1480,125 @@ typedef struct
UBX_RXM_RAWX_data_t data;
bool moduleQueried;
void (*callbackPointer)(UBX_RXM_RAWX_data_t);
void (*callbackPointerPtr)(UBX_RXM_RAWX_data_t *);
UBX_RXM_RAWX_data_t *callbackData;
} UBX_RXM_RAWX_t;
// UBX-RXM-PMP (0x02 0x72): PMP raw data (D9 modules)
// There are two versions of this message but, fortunately, both have a max len of 528
const uint16_t UBX_RXM_PMP_MAX_USER_DATA = 504;
const uint16_t UBX_RXM_PMP_MAX_LEN = UBX_RXM_PMP_MAX_USER_DATA + 24;
typedef struct
{
uint8_t version; // Message version (0x00 / 0x01)
uint8_t reserved0; // Reserved
uint16_t numBytesUserData; // version 0x00: reserved0 ; version 0x01: Number of bytes the userData block has in this frame (0...504)
uint32_t timeTag; // Time since startup when frame started : ms
uint32_t uniqueWord[2]; // Received unique words
uint16_t serviceIdentifier; // Received service identifier
uint8_t spare; // Received spare data
uint8_t uniqueWordBitErrors; // Number of bit errors in both unique words
// The position of fecBits, ebno and reserved1 depends on the message version
uint16_t fecBits; // Number of bits corrected by FEC (forward error correction)
uint8_t ebno; // Energy per bit to noise power spectral density ratio : 2^-3 dB
uint8_t reserved1; // Reserved
uint8_t userData[UBX_RXM_PMP_MAX_USER_DATA]; // Received user data: version 0x00 : starts at byte 20 ; version 0x01 : starts at byte 24
} UBX_RXM_PMP_data_t;
// The PMP data can only be accessed via a callback. PMP cannot be polled.
typedef struct
{
ubxAutomaticFlags automaticFlags;
void (*callbackPointerPtr)(UBX_RXM_PMP_data_t *);
UBX_RXM_PMP_data_t *callbackData;
} UBX_RXM_PMP_t;
// Define a struct to hold the entire PMP message so the whole thing can be pushed to a GNSS.
// Remember that the length of the payload could be variable (with version 1 messages).
typedef struct
{
uint8_t sync1; // 0xB5
uint8_t sync2; // 0x62
uint8_t cls;
uint8_t ID;
uint8_t lengthLSB;
uint8_t lengthMSB;
uint8_t payload[UBX_RXM_PMP_MAX_LEN];
uint8_t checksumA;
uint8_t checksumB;
} UBX_RXM_PMP_message_data_t;
// The PMP data can only be accessed via a callback. PMP cannot be polled.
typedef struct
{
ubxAutomaticFlags automaticFlags;
void (*callbackPointerPtr)(UBX_RXM_PMP_message_data_t *);
UBX_RXM_PMP_message_data_t *callbackData;
} UBX_RXM_PMP_message_t;
// CFG-specific structs
// UBX-CFG-PRT (0x06 0x00): Port configuration
// The content changes depending on which port type is being configured
// This struct defines the common structure
const uint16_t UBX_CFG_PRT_LEN = 20;
typedef struct
{
uint8_t portID; // Port identifier number
uint8_t reserved0; // Reserved
union
{
uint16_t all;
struct
{
uint16_t en : 1; // Enable TX ready feature for this port
uint16_t pol : 1; // Polarity: 0 High-active; 1 Low-active
uint16_t pin : 5; // PIO to be used (must not be in use by another function)
uint16_t thres : 9; // Threshold
} bits;
} txReady;
uint32_t mode; // Content changes depending on the port type
uint32_t baudRate; // Content changes depending on the port type
union
{
uint16_t all;
struct
{
uint16_t inUbx : 1; // UBX protocol
uint16_t inNmea : 1; // NMEA protocol
uint16_t inRtcm : 1; // RTCM2 protocol
uint16_t reserved : 2;
uint16_t inRtcm3 : 1; // RTCM3 protocol (not supported for protocol versions less than 20.00)
uint16_t inSPARTN : 1;
} bits;
} inProtoMask;
union
{
uint16_t all;
struct
{
uint16_t outUbx : 1; // UBX protocol
uint16_t outNmea : 1; // NMEA protocol
uint16_t reserved : 3;
uint16_t outRtcm3 : 1; // RTCM3 protocol (not supported for protocol versions less than 20.00)
uint16_t outSPARTN : 1;
} bits;
} outProtoMask;
uint16_t flags; // Content changes depending on the port type
uint16_t reserved1;
} UBX_CFG_PRT_data_t;
typedef struct
{
UBX_CFG_PRT_data_t data;
bool dataValid;
} UBX_CFG_PRT_t;
// UBX-CFG-RATE (0x06 0x08): Navigation/measurement rate settings
const uint16_t UBX_CFG_RATE_LEN = 6;
@@ -1202,8 +1630,6 @@ typedef struct
ubxAutomaticFlags automaticFlags;
UBX_CFG_RATE_data_t data;
UBX_CFG_RATE_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_CFG_RATE_data_t);
UBX_CFG_RATE_data_t *callbackData;
} UBX_CFG_RATE_t;
// UBX-CFG-TP5 (0x06 0x31): Time pulse parameters
@@ -1309,6 +1735,7 @@ typedef struct
UBX_TIM_TM2_data_t data;
UBX_TIM_TM2_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_TIM_TM2_data_t);
void (*callbackPointerPtr)(UBX_TIM_TM2_data_t *);
UBX_TIM_TM2_data_t *callbackData;
} UBX_TIM_TM2_t;
@@ -1383,6 +1810,7 @@ typedef struct
UBX_ESF_ALG_data_t data;
UBX_ESF_ALG_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_ESF_ALG_data_t);
void (*callbackPointerPtr)(UBX_ESF_ALG_data_t *);
UBX_ESF_ALG_data_t *callbackData;
} UBX_ESF_ALG_t;
@@ -1449,6 +1877,7 @@ typedef struct
UBX_ESF_INS_data_t data;
UBX_ESF_INS_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_ESF_INS_data_t);
void (*callbackPointerPtr)(UBX_ESF_INS_data_t *);
UBX_ESF_INS_data_t *callbackData;
} UBX_ESF_INS_t;
@@ -1519,6 +1948,7 @@ typedef struct
UBX_ESF_MEAS_data_t data;
UBX_ESF_MEAS_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_ESF_MEAS_data_t);
void (*callbackPointerPtr)(UBX_ESF_MEAS_data_t *);
UBX_ESF_MEAS_data_t *callbackData;
} UBX_ESF_MEAS_t;
@@ -1566,6 +1996,7 @@ typedef struct
UBX_ESF_RAW_data_t data;
UBX_ESF_RAW_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_ESF_RAW_data_t);
void (*callbackPointerPtr)(UBX_ESF_RAW_data_t *);
UBX_ESF_RAW_data_t *callbackData;
} UBX_ESF_RAW_t;
@@ -1653,9 +2084,64 @@ typedef struct
UBX_ESF_STATUS_data_t data;
UBX_ESF_STATUS_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_ESF_STATUS_data_t);
void (*callbackPointerPtr)(UBX_ESF_STATUS_data_t *);
UBX_ESF_STATUS_data_t *callbackData;
} UBX_ESF_STATUS_t;
// MGA-specific structs
// UBX-MGA-ACK-DATA0 (0x13 0x60): Multiple GNSS acknowledge message
const uint16_t UBX_MGA_ACK_DATA0_LEN = 8;
typedef struct
{
uint8_t type; // Type of acknowledgment:
// 0: The message was not used by the receiver (see infoCode field for an indication of why)
// 1: The message was accepted for use by the receiver (the infoCode field will be 0)
uint8_t version; // Message version
uint8_t infoCode; // Provides greater information on what the receiver chose to do with the message contents
// See sfe_ublox_mga_ack_infocode_e
uint8_t msgId; // UBX message ID of the acknowledged message
uint8_t msgPayloadStart[4]; // The first 4 bytes of the acknowledged message's payload
} UBX_MGA_ACK_DATA0_data_t;
#define UBX_MGA_ACK_DATA0_RINGBUFFER_LEN 16 // Provide storage for 16 MGA ACK packets
typedef struct
{
uint8_t head;
uint8_t tail;
UBX_MGA_ACK_DATA0_data_t data[UBX_MGA_ACK_DATA0_RINGBUFFER_LEN]; // Create a storage array for the MGA ACK packets
} UBX_MGA_ACK_DATA0_t;
// UBX-MGA-DBD (0x13 0x80): Navigation database dump entry
const uint16_t UBX_MGA_DBD_LEN = 164; // "The maximum payload size for firmware 2.01 onwards is 164 bytes"
typedef struct
{
uint8_t dbdEntryHeader1; // We need to save the entire message - header, payload and checksum
uint8_t dbdEntryHeader2;
uint8_t dbdEntryClass;
uint8_t dbdEntryID;
uint8_t dbdEntryLenLSB; // We need to store the length of the DBD entry. The entry itself does not contain a length...
uint8_t dbdEntryLenMSB;
uint8_t dbdEntry[UBX_MGA_DBD_LEN];
uint8_t dbdEntryChecksumA;
uint8_t dbdEntryChecksumB;
} UBX_MGA_DBD_data_t;
#if defined(ARDUINO_ARCH_AVR)
#define UBX_MGA_DBD_RINGBUFFER_LEN 190 // Fix to let the code compile on AVR platforms - including the UNO.
#else
#define UBX_MGA_DBD_RINGBUFFER_LEN 250 // Provide storage for MGA DBD packets. TO DO: confirm if 250 is large enough for all modules!
#endif
typedef struct
{
uint8_t head;
uint8_t tail;
UBX_MGA_DBD_data_t data[UBX_MGA_DBD_RINGBUFFER_LEN]; // Create a storage array for the MGA DBD packets
} UBX_MGA_DBD_t;
// HNR-specific structs
// UBX-HNR-PVT (0x28 0x00): High rate output of PVT solution
@@ -1769,6 +2255,7 @@ typedef struct
UBX_HNR_PVT_data_t data;
UBX_HNR_PVT_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_HNR_PVT_data_t);
void (*callbackPointerPtr)(UBX_HNR_PVT_data_t *);
UBX_HNR_PVT_data_t *callbackData;
} UBX_HNR_PVT_t;
@@ -1815,6 +2302,7 @@ typedef struct
UBX_HNR_ATT_data_t data;
UBX_HNR_ATT_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_HNR_ATT_data_t);
void (*callbackPointerPtr)(UBX_HNR_ATT_data_t *);
UBX_HNR_ATT_data_t *callbackData;
} UBX_HNR_ATT_t;
@@ -1881,7 +2369,58 @@ typedef struct
UBX_HNR_INS_data_t data;
UBX_HNR_INS_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_HNR_INS_data_t);
void (*callbackPointerPtr)(UBX_HNR_INS_data_t *);
UBX_HNR_INS_data_t *callbackData;
} UBX_HNR_INS_t;
// NMEA-specific structs
// Additional flags and pointers that need to be stored with each message type
struct nmeaAutomaticFlags
{
union
{
uint8_t all;
struct
{
uint8_t completeCopyValid : 1; // Is the copy of the data struct used by the get function valid/fresh? 0 = invalid, 1 = valid
uint8_t completeCopyRead : 1; // Has the complete copy been read? 0 = unread, 1 = read
uint8_t callbackCopyValid : 1; // Is the copy of the data struct used by the callback valid/fresh? 0 = invalid/stale, 1 = valid/fresh
} bits;
} flags;
};
// The max length for NMEA messages should be 82 bytes, but GGA messages can exceed that if they include the
// extra decimal places for "High Precision Mode".
//
// To be safe, let's allocate 100 bytes to store the GGA message
const uint8_t NMEA_GGA_MAX_LENGTH = 100;
typedef struct
{
uint8_t length; // The number of bytes in nmea
uint8_t nmea[NMEA_GGA_MAX_LENGTH];
} NMEA_GGA_data_t;
typedef struct
{
nmeaAutomaticFlags automaticFlags;
NMEA_GGA_data_t workingCopy; // Incoming data is added to the working copy
NMEA_GGA_data_t completeCopy; // The working copy is copied into the complete copy when all data has been received and the checksum is valid
void (*callbackPointer)(NMEA_GGA_data_t);
void (*callbackPointerPtr)(NMEA_GGA_data_t *);
NMEA_GGA_data_t *callbackCopy; // The callback gets its own preserved copy of the complete copy
} NMEA_GPGGA_t;
typedef struct
{
nmeaAutomaticFlags automaticFlags;
NMEA_GGA_data_t workingCopy; // Incoming data is added to the working copy
NMEA_GGA_data_t completeCopy; // The working copy is copied into the complete copy when all data has been received and the checksum is valid
void (*callbackPointer)(NMEA_GGA_data_t);
void (*callbackPointerPtr)(NMEA_GGA_data_t *);
NMEA_GGA_data_t *callbackCopy; // The callback gets its own preserved copy of the complete copy
} NMEA_GNGGA_t;
#endif