@@ -87,6 +87,9 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Branch name
|
||||
run: echo running on branch ${GITHUB_REF##*/}
|
||||
|
||||
- name: Compile Sketch
|
||||
uses: arduino/compile-sketches@v1
|
||||
@@ -94,20 +97,11 @@ jobs:
|
||||
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:
|
||||
|
||||
@@ -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!
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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():
|
||||
|
||||
+188
@@ -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);
|
||||
}
|
||||
+207
@@ -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
|
||||
}
|
||||
+188
@@ -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();
|
||||
}
|
||||
+177
@@ -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
|
||||
};
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
//Your WiFi credentials
|
||||
const char ssid[] = "TRex";
|
||||
const char password[] = "hasBigTeeth";
|
||||
|
||||
//Your AssistNow token
|
||||
const char myAssistNowToken[] = "58XXXXXXXXXXXXXXXXXXYQ";
|
||||
+325
@@ -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";
|
||||
+236
@@ -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";
|
||||
+254
@@ -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";
|
||||
+299
@@ -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";
|
||||
+232
@@ -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";
|
||||
@@ -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
|
||||
|
||||
|
||||
+13
-16
@@ -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
|
||||
|
||||
@@ -90,10 +89,10 @@ int numRAWX = 0; // Keep count of how many RAWX message groups have been receive
|
||||
// See u-blox_structs.h for the full definition of UBX_RXMSFRBX_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoRXMSFRBXcallback
|
||||
// / _____ This _must_ be UBX_RXM_SFRBX_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void newSFRBX(UBX_RXM_SFRBX_data_t ubxDataStruct)
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
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
|
||||
|
||||
|
||||
+6
-9
@@ -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);
|
||||
}
|
||||
+16
-16
@@ -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,26 +31,21 @@
|
||||
|
||||
#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
|
||||
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
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
long lastReport_ms = 0; //Time of last report of bytes sent
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200); // You may need to increase this for high navigation rates!
|
||||
@@ -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];
|
||||
const int SERVER_BUFFER_SIZE = 512;
|
||||
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,10 +278,10 @@ 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,15 @@
|
||||
//Your WiFi credentials
|
||||
const char* ssid = "TRex";
|
||||
const char* password = "hasBigTeeth";
|
||||
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
|
||||
+491
@@ -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";
|
||||
+212
@@ -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;
|
||||
+22
-1
@@ -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
|
||||
+189
-1
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
+1471
-1212
File diff suppressed because it is too large
Load Diff
+1072
-988
File diff suppressed because it is too large
Load Diff
+886
-347
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user