Merge pull request #99 from sparkfun/release_candidate

v2.2.0
This commit is contained in:
Paul
2022-01-14 09:26:15 +00:00
committed by GitHub
17 changed files with 2342 additions and 49 deletions
-9
View File
@@ -99,15 +99,6 @@ jobs:
libraries: | libraries: |
- source-path: ./ - source-path: ./
sketch-paths: | 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/Example18_PowerSaveMode
- examples/Example19_DynamicModel
- examples/Example20_SendCustomCommand - examples/Example20_SendCustomCommand
enable-warnings-report: true enable-warnings-report: true
enable-deltas-report: true enable-deltas-report: true
+166
View File
@@ -0,0 +1,166 @@
## 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 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.4: Update checkCallbacks()
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/b53bffaa3ae12482cfb268f23796963d0b8519c9) for the changes.
#### Step 6.5: Add the "auto" functions
See [this commit](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/commit/e394ae003ad38117d150598774d0552059416473) for the changes.
#### Step 6.6: 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!
+24 -7
View File
@@ -21,12 +21,31 @@ 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**. This library can be installed via the Arduino Library manager. Search for **SparkFun u-blox GNSS**.
## v2.0 ## Automatic support for correction services like RTK2go, Emlid Caster and Skylark (Swift Navigation)
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: 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: * 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: * 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. * 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. * Each "auto" message has a clearly-defined [data storage struct](./src/u-blox_structs.h) which follows the u-blox protocol specification precisely.
@@ -53,9 +72,7 @@ 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. 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.
## AssistNow<sup>TM</sup> 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!
v2.1.0 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).
## Memory Usage ## Memory Usage
@@ -83,9 +100,9 @@ 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. 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.
## Contributing ## Contributing
+3
View File
@@ -54,6 +54,7 @@ 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-VELNED (0x01 0x12): Velocity solution in NED frame
- UBX-NAV-HPPOSECEF (0x01 0x13): High precision position solution in ECEF - UBX-NAV-HPPOSECEF (0x01 0x13): High precision position solution in ECEF
- UBX-NAV-HPPOSLLH (0x01 0x14): High precision geodetic position solution - 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-CLOCK (0x01 0x22): Clock solution
- UBX-NAV-SVIN (0x01 0x3B): Survey-in data (**only with High Precision GNSS products**) - 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-RELPOSNED (0x01 0x3C): Relative positioning information in NED frame (**only with High Precision GNSS products**)
@@ -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-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**) - 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: Notes:
- UBX-NAV-POSLLH is not supported as UBX-NAV-PVT contains the same information - 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 - UBX-NAV-TIMEUTC is not supported as UBX-NAV-PVT contains the same information
@@ -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.setNMEAGPGGAcallback(&printGPGGA);
// Set up the callback for GNGGA
myGNSS.setNMEAGNGGAcallback(&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);
}
@@ -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);
}
@@ -0,0 +1,497 @@
/*
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)
{
long latitude = ubxDataStruct.lat; // Print the latitude
Serial.print(F("Lat: "));
Serial.print(latitude / 10000000L);
Serial.print(F("."));
Serial.print(abs(latitude % 10000000L));
long longitude = ubxDataStruct.lon; // Print the longitude
Serial.print(F(" Long: "));
Serial.print(longitude / 10000000L);
Serial.print(F("."));
Serial.print(abs(longitude % 10000000L));
long altitude = ubxDataStruct.hMSL; // Print the height above mean sea level
Serial.print(F(" Height: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
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. 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.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.setNMEAGPGGAcallback(&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.setAutoPVTcallback(&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
@@ -40,6 +40,7 @@
0x10310022 0x10310022
0x10310024 0x10310024
0x10310025 0x10310025
0x10340014
0x10360002 0x10360002
0x10360003 0x10360003
0x10360004 0x10360004
@@ -50,7 +51,6 @@
0x10510003 0x10510003
0x10520005 0x10520005
0x10530005 0x10530005
0x10530006
0x10640002 0x10640002
0x10640003 0x10640003
0x10640005 0x10640005
@@ -60,26 +60,31 @@
0x10710001 0x10710001
0x10710002 0x10710002
0x10710004 0x10710004
0x10710005
0x10720001 0x10720001
0x10720002 0x10720002
0x10730001 0x10730001
0x10730002 0x10730002
0x10730004 0x10730004
0x10730005
0x10740001 0x10740001
0x10740002 0x10740002
0x10750001 0x10750001
0x10750002 0x10750002
0x10750004 0x10750004
0x10750005
0x10760001 0x10760001
0x10760002 0x10760002
0x10770001 0x10770001
0x10770002 0x10770002
0x10770004 0x10770004
0x10770005
0x10780001 0x10780001
0x10780002 0x10780002
0x10790001 0x10790001
0x10790002 0x10790002
0x10790004 0x10790004
0x10790005
0x107a0001 0x107a0001
0x107a0002 0x107a0002
0x10930003 0x10930003
@@ -114,6 +119,7 @@
0x2005000c 0x2005000c
0x20050023 0x20050023
0x20050030 0x20050030
0x20050035
0x20060008 0x20060008
0x20060009 0x20060009
0x20060015 0x20060015
@@ -486,6 +492,21 @@
0x20910402 0x20910402
0x20910403 0x20910403
0x20910404 0x20910404
0x20910605
0x20910606
0x20910607
0x20910608
0x20910609
0x2091062a
0x2091062b
0x2091062c
0x2091062d
0x2091062e
0x20910634
0x20910635
0x20910636
0x20910637
0x20910638
0x20920001 0x20920001
0x20920002 0x20920002
0x20920003 0x20920003
+15
View File
@@ -82,30 +82,35 @@
0x10710001 0x10710001
0x10710002 0x10710002
0x10710004 0x10710004
0x10710005
0x10720001 0x10720001
0x10720002 0x10720002
0x10720004 0x10720004
0x10730001 0x10730001
0x10730002 0x10730002
0x10730004 0x10730004
0x10730005
0x10740001 0x10740001
0x10740002 0x10740002
0x10740004 0x10740004
0x10750001 0x10750001
0x10750002 0x10750002
0x10750004 0x10750004
0x10750005
0x10760001 0x10760001
0x10760002 0x10760002
0x10760004 0x10760004
0x10770001 0x10770001
0x10770002 0x10770002
0x10770004 0x10770004
0x10770005
0x10780001 0x10780001
0x10780002 0x10780002
0x10780004 0x10780004
0x10790001 0x10790001
0x10790002 0x10790002
0x10790004 0x10790004
0x10790005
0x107a0001 0x107a0001
0x107a0002 0x107a0002
0x107a0004 0x107a0004
@@ -732,11 +737,21 @@
0x20910592 0x20910592
0x20910593 0x20910593
0x20910594 0x20910594
0x20910605
0x20910606
0x20910607
0x20910608
0x20910609
0x20910610 0x20910610
0x20910611 0x20910611
0x20910612 0x20910612
0x20910613 0x20910613
0x20910614 0x20910614
0x2091062a
0x2091062b
0x2091062c
0x2091062d
0x2091062e
0x20910634 0x20910634
0x20910635 0x20910635
0x20910636 0x20910636
+43 -5
View File
@@ -140,6 +140,7 @@ setSurveyMode KEYWORD2
enableSurveyMode KEYWORD2 enableSurveyMode KEYWORD2
disableSurveyMode KEYWORD2 disableSurveyMode KEYWORD2
setStaticPosition KEYWORD2 setStaticPosition KEYWORD2
setDGNSSConfiguration KEYWORD2
getProtocolVersionHigh KEYWORD2 getProtocolVersionHigh KEYWORD2
getProtocolVersionLow KEYWORD2 getProtocolVersionLow KEYWORD2
@@ -287,6 +288,15 @@ initPacketUBXNAVHPPOSLLH KEYWORD2
flushHPPOSLLH KEYWORD2 flushHPPOSLLH KEYWORD2
logNAVHPPOSLLH KEYWORD2 logNAVHPPOSLLH KEYWORD2
getNAVPVAT KEYWORD2
setAutoNAVPVAT KEYWORD2
setAutoNAVPVAT KEYWORD2
setAutoNAVPVATrate KEYWORD2
setAutoNAVPVATcallback KEYWORD2
assumeAutoNAVPVAT KEYWORD2
flushNAVPVAT KEYWORD2
logNAVPVAT KEYWORD2
getNAVCLOCK KEYWORD2 getNAVCLOCK KEYWORD2
setAutoNAVCLOCK KEYWORD2 setAutoNAVCLOCK KEYWORD2
setAutoNAVCLOCKrate KEYWORD2 setAutoNAVCLOCKrate KEYWORD2
@@ -437,11 +447,6 @@ initPacketUBXHNRPVT KEYWORD2
flushHNRPVT KEYWORD2 flushHNRPVT KEYWORD2
logHNRPVT KEYWORD2 logHNRPVT KEYWORD2
setNMEALoggingMask KEYWORD2
getNMEALoggingMask KEYWORD2
setProcessNMEAMask KEYWORD2
getProcessNMEAMask KEYWORD2
setNavigationFrequency KEYWORD2 setNavigationFrequency KEYWORD2
getNavigationFrequency KEYWORD2 getNavigationFrequency KEYWORD2
setMeasurementRate KEYWORD2 setMeasurementRate KEYWORD2
@@ -517,6 +522,11 @@ getMeanSeaLevelHp KEYWORD2
getHorizontalAccuracy KEYWORD2 getHorizontalAccuracy KEYWORD2
getVerticalAccuracy KEYWORD2 getVerticalAccuracy KEYWORD2
getVehicleRoll KEYWORD2
getVehiclePitch KEYWORD2
getVehicleHeading KEYWORD2
getMotionHeading KEYWORD2
getSurveyInActive KEYWORD2 getSurveyInActive KEYWORD2
getSurveyInValid KEYWORD2 getSurveyInValid KEYWORD2
getSurveyInObservationTime KEYWORD2 getSurveyInObservationTime KEYWORD2
@@ -545,6 +555,19 @@ getHNRroll KEYWORD2
getHNRpitch KEYWORD2 getHNRpitch KEYWORD2
getHNRheading KEYWORD2 getHNRheading KEYWORD2
setNMEALoggingMask KEYWORD2
getNMEALoggingMask KEYWORD2
setProcessNMEAMask KEYWORD2
getProcessNMEAMask KEYWORD2
setMainTalkerID KEYWORD2
setHighPrecisionMode KEYWORD2
getLatestNMEAGPGGA KEYWORD2
setNMEAGPGGAcallback KEYWORD2
getLatestNMEAGNGGA KEYWORD2
setNMEAGNGGAcallback KEYWORD2
extractLong KEYWORD2 extractLong KEYWORD2
extractSignedLong KEYWORD2 extractSignedLong KEYWORD2
extractInt KEYWORD2 extractInt KEYWORD2
@@ -652,6 +675,7 @@ UBX_NAV_HPPOSLLH LITERAL1
UBX_NAV_ODO LITERAL1 UBX_NAV_ODO LITERAL1
UBX_NAV_POSECEF LITERAL1 UBX_NAV_POSECEF LITERAL1
UBX_NAV_PVT LITERAL1 UBX_NAV_PVT LITERAL1
UBX_NAV_PVAT LITERAL1
UBX_NAV_RELPOSNED LITERAL1 UBX_NAV_RELPOSNED LITERAL1
UBX_NAV_RESETODO LITERAL1 UBX_NAV_RESETODO LITERAL1
UBX_NAV_STATUS LITERAL1 UBX_NAV_STATUS LITERAL1
@@ -662,6 +686,7 @@ UBX_NAV_VELNED LITERAL1
UBX_RXM_RAWX LITERAL1 UBX_RXM_RAWX LITERAL1
UBX_RXM_SFRBX LITERAL1 UBX_RXM_SFRBX LITERAL1
UBX_RXM_SPARTN LITERAL1
UBX_TIM_TM2 LITERAL1 UBX_TIM_TM2 LITERAL1
@@ -706,6 +731,8 @@ DYN_MODEL_AIRBORNE2g LITERAL1
DYN_MODEL_AIRBORNE4g LITERAL1 DYN_MODEL_AIRBORNE4g LITERAL1
DYN_MODEL_WRIST LITERAL1 DYN_MODEL_WRIST LITERAL1
DYN_MODEL_BIKE LITERAL1 DYN_MODEL_BIKE LITERAL1
DYN_MODEL_MOWER LITERAL1
DYN_MODEL_ESCOOTER LITERAL1
DYN_MODEL_UNKNOWN LITERAL1 DYN_MODEL_UNKNOWN LITERAL1
SFE_UBLOX_GNSS_ID_GPS LITERAL1 SFE_UBLOX_GNSS_ID_GPS LITERAL1
@@ -727,3 +754,14 @@ SFE_UBLOX_MGA_ACK_INFOCODE_SIZE_MISMATCH LITERAL1
SFE_UBLOX_MGA_ACK_INFOCODE_NOT_STORED LITERAL1 SFE_UBLOX_MGA_ACK_INFOCODE_NOT_STORED LITERAL1
SFE_UBLOX_MGA_ACK_INFOCODE_NOT_READY LITERAL1 SFE_UBLOX_MGA_ACK_INFOCODE_NOT_READY LITERAL1
SFE_UBLOX_MGA_ACK_INFOCODE_TYPE_UNKNOWN LITERAL1 SFE_UBLOX_MGA_ACK_INFOCODE_TYPE_UNKNOWN LITERAL1
SFE_UBLOX_MAIN_TALKER_ID_DEFAULT LITERAL1
SFE_UBLOX_MAIN_TALKER_ID_GP LITERAL1
SFE_UBLOX_MAIN_TALKER_ID_GL LITERAL1
SFE_UBLOX_MAIN_TALKER_ID_GN LITERAL1
SFE_UBLOX_MAIN_TALKER_ID_GA LITERAL1
SFE_UBLOX_MAIN_TALKER_ID_GB LITERAL1
SFE_UBLOX_MAIN_TALKER_ID_GQ LITERAL1
SFE_UBLOX_DGNSS_MODE_FLOAT LITERAL1
SFE_UBLOX_DGNSS_MODE_FIXED LITERAL1
+3 -3
View File
@@ -1,9 +1,9 @@
name=SparkFun u-blox GNSS Arduino Library name=SparkFun u-blox GNSS Arduino Library
version=2.1.5 version=2.2.0
author=SparkFun Electronics <techsupport@sparkfun.com> author=SparkFun Electronics <techsupport@sparkfun.com>
maintainer=SparkFun Electronics <sparkfun.com> maintainer=SparkFun Electronics <sparkfun.com>
sentence=Library for I2C and Serial Communication with u-blox GNSS modules<br/><br/> sentence=Library for I2C, Serial and SPI 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/> 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 category=Sensors
url=https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library url=https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library
architectures=* architectures=*
@@ -214,6 +214,16 @@ void SFE_UBLOX_GNSS::end(void)
packetUBXNAVHPPOSLLH = NULL; // Redundant? packetUBXNAVHPPOSLLH = NULL; // Redundant?
} }
if (packetUBXNAVPVAT != NULL)
{
if (packetUBXNAVPVAT->callbackData != NULL)
{
delete packetUBXNAVPVAT->callbackData;
}
delete packetUBXNAVPVAT;
packetUBXNAVPVAT = NULL; // Redundant?
}
if (packetUBXNAVCLOCK != NULL) if (packetUBXNAVCLOCK != NULL)
{ {
if (packetUBXNAVCLOCK->callbackData != NULL) if (packetUBXNAVCLOCK->callbackData != NULL)
@@ -396,6 +406,26 @@ void SFE_UBLOX_GNSS::end(void)
packetUBXHNRPVT = NULL; // Redundant? packetUBXHNRPVT = NULL; // Redundant?
} }
if (storageNMEAGPGGA != NULL)
{
if (storageNMEAGPGGA->callbackCopy != NULL)
{
delete storageNMEAGPGGA->callbackCopy;
}
delete storageNMEAGPGGA;
storageNMEAGPGGA = NULL; // Redundant?
}
if (storageNMEAGNGGA != NULL)
{
if (storageNMEAGNGGA->callbackCopy != NULL)
{
delete storageNMEAGNGGA->callbackCopy;
}
delete storageNMEAGNGGA;
storageNMEAGNGGA = NULL; // Redundant?
}
} }
//Allow the user to change packetCfgPayloadSize. Handy if you want to process big messages like RAWX //Allow the user to change packetCfgPayloadSize. Handy if you want to process big messages like RAWX
@@ -1145,6 +1175,9 @@ bool SFE_UBLOX_GNSS::checkAutomatic(uint8_t Class, uint8_t ID)
case UBX_NAV_HPPOSLLH: case UBX_NAV_HPPOSLLH:
if (packetUBXNAVHPPOSLLH != NULL) result = true; if (packetUBXNAVHPPOSLLH != NULL) result = true;
break; break;
case UBX_NAV_PVAT:
if (packetUBXNAVPVAT != NULL) result = true;
break;
case UBX_NAV_CLOCK: case UBX_NAV_CLOCK:
if (packetUBXNAVCLOCK != NULL) result = true; if (packetUBXNAVCLOCK != NULL) result = true;
break; break;
@@ -1669,6 +1702,24 @@ void SFE_UBLOX_GNSS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t r
_signsOfLife = isNMEAHeaderValid(); _signsOfLife = isNMEAHeaderValid();
} }
// Check if we have automatic storage for this message
if (isThisNMEAauto())
{
uint8_t *lengthPtr = getNMEAWorkingLengthPtr(); // Get a pointer to the working copy length
uint8_t *nmeaPtr = getNMEAWorkingNMEAPtr(); // Get a pointer to the working copy NMEA data
uint8_t nmeaMaxLength = getNMEAMaxLength();
*lengthPtr = 6; // Set the working copy length
memset(nmeaPtr, 0, nmeaMaxLength); // Clear the working copy
memcpy(nmeaPtr, &nmeaAddressField[0], 6); // Copy the start character and address field into the working copy
}
else
{
// if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
// {
// _debugSerial->println(F("process: non-auto NMEA message"));
// }
}
// We've just received the end of the address field. Check if it is selected for logging // We've just received the end of the address field. Check if it is selected for logging
if (logThisNMEA()) if (logThisNMEA())
{ {
@@ -1688,6 +1739,24 @@ void SFE_UBLOX_GNSS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t r
if ((nmeaByteCounter > 5) || (nmeaByteCounter < 0)) // Should we add incoming to the file buffer and/or pass it to processNMEA? if ((nmeaByteCounter > 5) || (nmeaByteCounter < 0)) // Should we add incoming to the file buffer and/or pass it to processNMEA?
{ {
if (isThisNMEAauto())
{
uint8_t *lengthPtr = getNMEAWorkingLengthPtr(); // Get a pointer to the working copy length
uint8_t *nmeaPtr = getNMEAWorkingNMEAPtr(); // Get a pointer to the working copy NMEA data
uint8_t nmeaMaxLength = getNMEAMaxLength();
if (*lengthPtr < nmeaMaxLength)
{
*(nmeaPtr + *lengthPtr) = incoming; // Store the character
*lengthPtr = *lengthPtr + 1; // Increment the length
if (*lengthPtr == nmeaMaxLength)
{
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
{
_debugSerial->println(F("process: NMEA buffer is full!"));
}
}
}
}
if (logThisNMEA()) if (logThisNMEA())
storeFileBytes(&incoming, 1); // Add incoming to the file buffer storeFileBytes(&incoming, 1); // Add incoming to the file buffer
if (processThisNMEA()) if (processThisNMEA())
@@ -1703,7 +1772,86 @@ void SFE_UBLOX_GNSS::process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t r
currentSentence = NONE; //Something went wrong. Reset. currentSentence = NONE; //Something went wrong. Reset.
if (nmeaByteCounter == 0) // Check if we are done if (nmeaByteCounter == 0) // Check if we are done
{
if (isThisNMEAauto())
{
uint8_t *workingLengthPtr = getNMEAWorkingLengthPtr(); // Get a pointer to the working copy length
uint8_t *workingNMEAPtr = getNMEAWorkingNMEAPtr(); // Get a pointer to the working copy NMEA data
uint8_t nmeaMaxLength = getNMEAMaxLength();
// Check the checksum: the checksum is the exclusive-OR of all characters between the $ and the *
uint8_t nmeaChecksum = 0;
uint8_t charsChecked = 1; // Start after the $
uint8_t thisChar = '\0';
while ((charsChecked < (nmeaMaxLength - 1))
&& (charsChecked < ((*workingLengthPtr) - 4))
&& (thisChar != '*'))
{
thisChar = *(workingNMEAPtr + charsChecked); // Get a char from the working copy
if (thisChar != '*') // Ex-or the char into the checksum - but not if it is the '*'
nmeaChecksum ^= thisChar;
charsChecked++; // Increment the counter
}
if (thisChar == '*') // Make sure we found the *
{
uint8_t expectedChecksum1 = (nmeaChecksum >> 4) + '0';
if (expectedChecksum1 >= ':') // Handle Hex correctly
expectedChecksum1 += 'A' - ':';
uint8_t expectedChecksum2 = (nmeaChecksum & 0x0F) + '0';
if (expectedChecksum2 >= ':') // Handle Hex correctly
expectedChecksum2 += 'A' - ':';
if ((expectedChecksum1 == *(workingNMEAPtr + charsChecked))
&& (expectedChecksum2 == *(workingNMEAPtr + charsChecked + 1)))
{
uint8_t *completeLengthPtr = getNMEACompleteLengthPtr(); // Get a pointer to the complete copy length
uint8_t *completeNMEAPtr = getNMEACompleteNMEAPtr(); // Get a pointer to the complete copy NMEA data
memset(completeNMEAPtr, 0, nmeaMaxLength); // Clear the previous complete copy
memcpy(completeNMEAPtr, workingNMEAPtr, *workingLengthPtr); // Copy the working copy into the complete copy
*completeLengthPtr = *workingLengthPtr; // Update the length
nmeaAutomaticFlags *flagsPtr = getNMEAFlagsPtr(); // Get a pointer to the flags
nmeaAutomaticFlags flagsCopy = *flagsPtr;
flagsCopy.flags.bits.completeCopyValid = 1; // Set the complete copy valid flag
flagsCopy.flags.bits.completeCopyRead = 0; // Clear the complete copy read flag
*flagsPtr = flagsCopy; // Update the flags
// Callback
if (doesThisNMEAHaveCallback()) // Do we need to copy the data into the callback copy?
{
if (flagsCopy.flags.bits.callbackCopyValid == 0) // Has the callback copy valid flag been cleared (by checkCallbacks)
{
uint8_t *callbackLengthPtr = getNMEACallbackLengthPtr(); // Get a pointer to the callback copy length
uint8_t *callbackNMEAPtr = getNMEACallbackNMEAPtr(); // Get a pointer to the callback copy NMEA data
memset(callbackNMEAPtr, 0, nmeaMaxLength); // Clear the previous callback copy
memcpy(callbackNMEAPtr, workingNMEAPtr, *workingLengthPtr); // Copy the working copy into the callback copy
*callbackLengthPtr = *workingLengthPtr; // Update the length
flagsCopy.flags.bits.callbackCopyValid = 1; // Set the callback copy valid flag
*flagsPtr = flagsCopy; // Update the flags
}
}
}
else
{
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
{
_debugSerial->print(F("process: NMEA checksum fail (2)! Expected "));
_debugSerial->write(expectedChecksum1);
_debugSerial->write(expectedChecksum2);
_debugSerial->print(F(" Got "));
_debugSerial->write(*(workingNMEAPtr + charsChecked));
_debugSerial->write(*(workingNMEAPtr + charsChecked + 1));
_debugSerial->println();
}
}
}
else
{
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
{
_debugSerial->println(F("process: NMEA checksum fail (1)!"));
}
}
}
currentSentence = NONE; // All done! currentSentence = NONE; // All done!
}
} }
else if (currentSentence == RTCM) else if (currentSentence == RTCM)
{ {
@@ -1815,6 +1963,194 @@ void SFE_UBLOX_GNSS::processNMEA(char incoming)
_nmeaOutputPort->write(incoming); //Echo this byte to the serial port _nmeaOutputPort->write(incoming); //Echo this byte to the serial port
} }
// Check if the NMEA message (in nmeaAddressField) is "auto" (i.e. has RAM allocated for it)
bool SFE_UBLOX_GNSS::isThisNMEAauto()
{
char thisNMEA[] = "GPGGA";
if (memcmp(thisNMEA, &nmeaAddressField[1], 5) == 0)
{
if (storageNMEAGPGGA != NULL)
return true;
}
strcpy(thisNMEA, "GNGGA");
if (memcmp(thisNMEA, &nmeaAddressField[1], 5) == 0)
{
if (storageNMEAGNGGA != NULL)
return true;
}
return false;
}
// Do we need to copy the data into the callback copy?
bool SFE_UBLOX_GNSS::doesThisNMEAHaveCallback()
{
char thisNMEA[] = "GPGGA";
if (memcmp(thisNMEA, &nmeaAddressField[1], 5) == 0)
{
if (storageNMEAGPGGA != NULL)
if (storageNMEAGPGGA->callbackCopy != NULL)
if (storageNMEAGPGGA->callbackPointer != NULL)
return true;
}
strcpy(thisNMEA, "GNGGA");
if (memcmp(thisNMEA, &nmeaAddressField[1], 5) == 0)
{
if (storageNMEAGNGGA != NULL)
if (storageNMEAGNGGA->callbackCopy != NULL)
if (storageNMEAGNGGA->callbackPointer != NULL)
return true;
}
return false;
}
// Get a pointer to the working copy length
uint8_t * SFE_UBLOX_GNSS::getNMEAWorkingLengthPtr()
{
char thisNMEA[] = "GPGGA";
if (memcmp(thisNMEA, &nmeaAddressField[1], 5) == 0)
{
return &storageNMEAGPGGA->workingCopy.length;
}
strcpy(thisNMEA, "GNGGA");
if (memcmp(thisNMEA, &nmeaAddressField[1], 5) == 0)
{
return &storageNMEAGNGGA->workingCopy.length;
}
return NULL;
}
// Get a pointer to the working copy NMEA data
uint8_t * SFE_UBLOX_GNSS::getNMEAWorkingNMEAPtr()
{
char thisNMEA[] = "GPGGA";
if (memcmp(thisNMEA, &nmeaAddressField[1], 5) == 0)
{
return &storageNMEAGPGGA->workingCopy.nmea[0];
}
strcpy(thisNMEA, "GNGGA");
if (memcmp(thisNMEA, &nmeaAddressField[1], 5) == 0)
{
return &storageNMEAGNGGA->workingCopy.nmea[0];
}
return NULL;
}
// Get a pointer to the complete copy length
uint8_t * SFE_UBLOX_GNSS::getNMEACompleteLengthPtr()
{
char thisNMEA[] = "GPGGA";
if (memcmp(thisNMEA, &nmeaAddressField[1], 5) == 0)
{
return &storageNMEAGPGGA->completeCopy.length;
}
strcpy(thisNMEA, "GNGGA");
if (memcmp(thisNMEA, &nmeaAddressField[1], 5) == 0)
{
return &storageNMEAGNGGA->completeCopy.length;
}
return NULL;
}
// Get a pointer to the complete copy NMEA data
uint8_t * SFE_UBLOX_GNSS::getNMEACompleteNMEAPtr()
{
char thisNMEA[] = "GPGGA";
if (memcmp(thisNMEA, &nmeaAddressField[1], 5) == 0)
{
return &storageNMEAGPGGA->completeCopy.nmea[0];
}
strcpy(thisNMEA, "GNGGA");
if (memcmp(thisNMEA, &nmeaAddressField[1], 5) == 0)
{
return &storageNMEAGNGGA->completeCopy.nmea[0];
}
return NULL;
}
// Get a pointer to the callback copy length
uint8_t * SFE_UBLOX_GNSS::getNMEACallbackLengthPtr()
{
char thisNMEA[] = "GPGGA";
if (memcmp(thisNMEA, &nmeaAddressField[1], 5) == 0)
{
return &storageNMEAGPGGA->callbackCopy->length;
}
strcpy(thisNMEA, "GNGGA");
if (memcmp(thisNMEA, &nmeaAddressField[1], 5) == 0)
{
return &storageNMEAGNGGA->callbackCopy->length;
}
return NULL;
}
// Get a pointer to the callback copy NMEA data
uint8_t * SFE_UBLOX_GNSS::getNMEACallbackNMEAPtr()
{
char thisNMEA[] = "GPGGA";
if (memcmp(thisNMEA, &nmeaAddressField[1], 5) == 0)
{
return &storageNMEAGPGGA->callbackCopy->nmea[0];
}
strcpy(thisNMEA, "GNGGA");
if (memcmp(thisNMEA, &nmeaAddressField[1], 5) == 0)
{
return &storageNMEAGNGGA->callbackCopy->nmea[0];
}
return NULL;
}
// Get the maximum length of this NMEA message
uint8_t SFE_UBLOX_GNSS::getNMEAMaxLength()
{
char thisNMEA[] = "GPGGA";
if (memcmp(thisNMEA, &nmeaAddressField[1], 5) == 0)
{
return NMEA_GGA_MAX_LENGTH;
}
strcpy(thisNMEA, "GNGGA");
if (memcmp(thisNMEA, &nmeaAddressField[1], 5) == 0)
{
return NMEA_GGA_MAX_LENGTH;
}
return 0;
}
// Get a pointer to the automatic NMEA flags
nmeaAutomaticFlags * SFE_UBLOX_GNSS::getNMEAFlagsPtr()
{
char thisNMEA[] = "GPGGA";
if (memcmp(thisNMEA, &nmeaAddressField[1], 5) == 0)
{
return &storageNMEAGPGGA->automaticFlags;
}
strcpy(thisNMEA, "GNGGA");
if (memcmp(thisNMEA, &nmeaAddressField[1], 5) == 0)
{
return &storageNMEAGNGGA->automaticFlags;
}
return NULL;
}
//We need to be able to identify an RTCM packet and then the length //We need to be able to identify an RTCM packet and then the length
//so that we know when the RTCM message is completely received and we then start //so that we know when the RTCM message is completely received and we then start
//listening for other sentences (like NMEA or UBX) //listening for other sentences (like NMEA or UBX)
@@ -2478,6 +2814,69 @@ void SFE_UBLOX_GNSS::processUBXpacket(ubxPacket *msg)
} }
} }
} }
else if (msg->id == UBX_NAV_PVAT && msg->len == UBX_NAV_PVAT_LEN)
{
//Parse various byte fields into storage - but only if we have memory allocated for it
if (packetUBXNAVPVAT != NULL)
{
packetUBXNAVPVAT->data.iTOW = extractLong(msg, 0);
packetUBXNAVPVAT->data.version = extractByte(msg, 4);
packetUBXNAVPVAT->data.valid.all = extractByte(msg, 5);
packetUBXNAVPVAT->data.year = extractInt(msg, 6);
packetUBXNAVPVAT->data.month = extractByte(msg, 8);
packetUBXNAVPVAT->data.day = extractByte(msg, 9);
packetUBXNAVPVAT->data.hour = extractByte(msg, 10);
packetUBXNAVPVAT->data.min = extractByte(msg, 11);
packetUBXNAVPVAT->data.sec = extractByte(msg, 12);
packetUBXNAVPVAT->data.tAcc = extractLong(msg, 16);
packetUBXNAVPVAT->data.nano = extractSignedLong(msg, 20); //Includes milliseconds
packetUBXNAVPVAT->data.fixType = extractByte(msg, 24);
packetUBXNAVPVAT->data.flags.all = extractByte(msg, 25);
packetUBXNAVPVAT->data.flags2.all = extractByte(msg, 26);
packetUBXNAVPVAT->data.numSV = extractByte(msg, 27);
packetUBXNAVPVAT->data.lon = extractSignedLong(msg, 28);
packetUBXNAVPVAT->data.lat = extractSignedLong(msg, 32);
packetUBXNAVPVAT->data.height = extractSignedLong(msg, 36);
packetUBXNAVPVAT->data.hMSL = extractSignedLong(msg, 40);
packetUBXNAVPVAT->data.hAcc = extractLong(msg, 44);
packetUBXNAVPVAT->data.vAcc = extractLong(msg, 48);
packetUBXNAVPVAT->data.velN = extractSignedLong(msg, 52);
packetUBXNAVPVAT->data.velE = extractSignedLong(msg, 56);
packetUBXNAVPVAT->data.velD = extractSignedLong(msg, 60);
packetUBXNAVPVAT->data.gSpeed = extractSignedLong(msg, 64);
packetUBXNAVPVAT->data.sAcc = extractLong(msg, 68);
packetUBXNAVPVAT->data.vehRoll = extractSignedLong(msg, 72);
packetUBXNAVPVAT->data.vehPitch = extractSignedLong(msg, 76);
packetUBXNAVPVAT->data.vehHeading = extractSignedLong(msg, 80);
packetUBXNAVPVAT->data.motHeading = extractSignedLong(msg, 84);
packetUBXNAVPVAT->data.accRoll = extractInt(msg, 88);
packetUBXNAVPVAT->data.accPitch = extractInt(msg, 90);
packetUBXNAVPVAT->data.accHeading = extractInt(msg, 92);
packetUBXNAVPVAT->data.magDec = extractSignedInt(msg, 94);
packetUBXNAVPVAT->data.magAcc = extractInt(msg, 96);
packetUBXNAVPVAT->data.errEllipseOrient = extractInt(msg, 98);
packetUBXNAVPVAT->data.errEllipseMajor = extractLong(msg, 100);
packetUBXNAVPVAT->data.errEllipseMinor = extractLong(msg, 104);
//Mark all datums as fresh (not read before)
packetUBXNAVPVAT->moduleQueried.moduleQueried1.all = 0xFFFFFFFF;
packetUBXNAVPVAT->moduleQueried.moduleQueried2.all = 0xFFFFFFFF;
//Check if we need to copy the data for the callback
if ((packetUBXNAVPVAT->callbackData != NULL) // If RAM has been allocated for the copy of the data
&& (packetUBXNAVPVAT->automaticFlags.flags.bits.callbackCopyValid == false)) // AND the data is stale
{
memcpy(&packetUBXNAVPVAT->callbackData->iTOW, &packetUBXNAVPVAT->data.iTOW, sizeof(UBX_NAV_PVAT_data_t));
packetUBXNAVPVAT->automaticFlags.flags.bits.callbackCopyValid = true;
}
//Check if we need to copy the data into the file buffer
if (packetUBXNAVPVAT->automaticFlags.flags.bits.addToFileBuffer)
{
storePacket(msg);
}
}
}
else if (msg->id == UBX_NAV_CLOCK && msg->len == UBX_NAV_CLOCK_LEN) else if (msg->id == UBX_NAV_CLOCK && msg->len == UBX_NAV_CLOCK_LEN)
{ {
//Parse various byte fields into storage - but only if we have memory allocated for it //Parse various byte fields into storage - but only if we have memory allocated for it
@@ -4057,6 +4456,17 @@ void SFE_UBLOX_GNSS::checkCallbacks(void)
packetUBXNAVHPPOSLLH->automaticFlags.flags.bits.callbackCopyValid = false; // Mark the data as stale packetUBXNAVHPPOSLLH->automaticFlags.flags.bits.callbackCopyValid = false; // Mark the data as stale
} }
if ((packetUBXNAVPVAT != NULL) // If RAM has been allocated for message storage
&& (packetUBXNAVPVAT->callbackData != NULL) // If RAM has been allocated for the copy of the data
&& (packetUBXNAVPVAT->callbackPointer != NULL) // If the pointer to the callback has been defined
&& (packetUBXNAVPVAT->automaticFlags.flags.bits.callbackCopyValid == true)) // If the copy of the data is valid
{
//if (_printDebug == true)
// _debugSerial->println(F("checkCallbacks: calling callback for NAV PVAT"));
packetUBXNAVPVAT->callbackPointer(*packetUBXNAVPVAT->callbackData); // Call the callback
packetUBXNAVPVAT->automaticFlags.flags.bits.callbackCopyValid = false; // Mark the data as stale
}
if ((packetUBXNAVCLOCK != NULL) // If RAM has been allocated for message storage if ((packetUBXNAVCLOCK != NULL) // If RAM has been allocated for message storage
&& (packetUBXNAVCLOCK->callbackData != NULL) // If RAM has been allocated for the copy of the data && (packetUBXNAVCLOCK->callbackData != NULL) // If RAM has been allocated for the copy of the data
&& (packetUBXNAVCLOCK->callbackPointer != NULL) // If the pointer to the callback has been defined && (packetUBXNAVCLOCK->callbackPointer != NULL) // If the pointer to the callback has been defined
@@ -4222,6 +4632,28 @@ void SFE_UBLOX_GNSS::checkCallbacks(void)
packetUBXHNRPVT->automaticFlags.flags.bits.callbackCopyValid = false; // Mark the data as stale packetUBXHNRPVT->automaticFlags.flags.bits.callbackCopyValid = false; // Mark the data as stale
} }
if ((storageNMEAGPGGA != NULL) // If RAM has been allocated for message storage
&& (storageNMEAGPGGA->callbackCopy != NULL) // If RAM has been allocated for the copy of the data
&& (storageNMEAGPGGA->callbackPointer != NULL) // If the pointer to the callback has been defined
&& (storageNMEAGPGGA->automaticFlags.flags.bits.callbackCopyValid == 1)) // If the copy of the data is valid
{
// if (_printDebug == true)
// _debugSerial->println(F("checkCallbacks: calling callback for GPGGA"));
storageNMEAGPGGA->callbackPointer(*storageNMEAGPGGA->callbackCopy); // Call the callback
storageNMEAGPGGA->automaticFlags.flags.bits.callbackCopyValid = 0; // Mark the data as stale
}
if ((storageNMEAGNGGA != NULL) // If RAM has been allocated for message storage
&& (storageNMEAGNGGA->callbackCopy != NULL) // If RAM has been allocated for the copy of the data
&& (storageNMEAGNGGA->callbackPointer != NULL) // If the pointer to the callback has been defined
&& (storageNMEAGNGGA->automaticFlags.flags.bits.callbackCopyValid == 1)) // If the copy of the data is valid
{
// if (_printDebug == true)
// _debugSerial->println(F("checkCallbacks: calling callback for GNGGA"));
storageNMEAGNGGA->callbackPointer(*storageNMEAGNGGA->callbackCopy); // Call the callback
storageNMEAGNGGA->automaticFlags.flags.bits.callbackCopyValid = 0; // Mark the data as stale
}
checkCallbacksReentrant = false; checkCallbacksReentrant = false;
} }
@@ -5803,6 +6235,23 @@ bool SFE_UBLOX_GNSS::setStaticPosition(int32_t ecefXOrLat, int32_t ecefYOrLon, i
return (setStaticPosition(ecefXOrLat, 0, ecefYOrLon, 0, ecefZOrAlt, 0, latlong, maxWait)); return (setStaticPosition(ecefXOrLat, 0, ecefYOrLon, 0, ecefZOrAlt, 0, latlong, maxWait));
} }
// Set the DGNSS differential mode
bool SFE_UBLOX_GNSS::setDGNSSConfiguration(sfe_ublox_dgnss_mode_e dgnssMode, uint16_t maxWait)
{
packetCfg.cls = UBX_CLASS_CFG;
packetCfg.id = UBX_CFG_DGNSS;
packetCfg.len = 4;
packetCfg.startingSpot = 0;
payloadCfg[0] = (uint8_t)dgnssMode;
payloadCfg[1] = 0; // reserved0
payloadCfg[2] = 0;
payloadCfg[3] = 0;
return ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK
}
// Module Protocol Version // Module Protocol Version
//Get the current protocol version of the u-blox module we're communicating with //Get the current protocol version of the u-blox module we're communicating with
@@ -8697,6 +9146,165 @@ void SFE_UBLOX_GNSS::logNAVHPPOSLLH(bool enabled)
packetUBXNAVHPPOSLLH->automaticFlags.flags.bits.addToFileBuffer = (uint8_t)enabled; packetUBXNAVHPPOSLLH->automaticFlags.flags.bits.addToFileBuffer = (uint8_t)enabled;
} }
// ***** PVAT automatic support
//Get the latest Position/Velocity/Time solution and fill all global variables
bool SFE_UBLOX_GNSS::getNAVPVAT(uint16_t maxWait)
{
if (packetUBXNAVPVAT == NULL) initPacketUBXNAVPVAT(); //Check that RAM has been allocated for the PVAT data
if (packetUBXNAVPVAT == NULL) //Bail if the RAM allocation failed
return (false);
if (packetUBXNAVPVAT->automaticFlags.flags.bits.automatic && packetUBXNAVPVAT->automaticFlags.flags.bits.implicitUpdate)
{
checkUbloxInternal(&packetCfg, UBX_CLASS_NAV, UBX_NAV_PVAT);
return packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all;
}
else if (packetUBXNAVPVAT->automaticFlags.flags.bits.automatic && !packetUBXNAVPVAT->automaticFlags.flags.bits.implicitUpdate)
{
//Someone else has to call checkUblox for us...
return (false);
}
else
{
//The GPS is not automatically reporting navigation position so we have to poll explicitly
packetCfg.cls = UBX_CLASS_NAV;
packetCfg.id = UBX_NAV_PVAT;
packetCfg.len = 0;
packetCfg.startingSpot = 0;
//The data is parsed as part of processing the response
sfe_ublox_status_e retVal = sendCommand(&packetCfg, maxWait);
if (retVal == SFE_UBLOX_STATUS_DATA_RECEIVED)
return (true);
if (retVal == SFE_UBLOX_STATUS_DATA_OVERWRITTEN)
{
return (true);
}
return (false);
}
}
//Enable or disable automatic navigation message generation by the GNSS. This changes the way getPVAT
//works.
bool SFE_UBLOX_GNSS::setAutoNAVPVAT(bool enable, uint16_t maxWait)
{
return setAutoNAVPVATrate(enable ? 1 : 0, true, maxWait);
}
//Enable or disable automatic navigation message generation by the GNSS. This changes the way getPVAT
//works.
bool SFE_UBLOX_GNSS::setAutoNAVPVAT(bool enable, bool implicitUpdate, uint16_t maxWait)
{
return setAutoNAVPVATrate(enable ? 1 : 0, implicitUpdate, maxWait);
}
//Enable or disable automatic navigation message generation by the GNSS. This changes the way getPVAT
//works.
bool SFE_UBLOX_GNSS::setAutoNAVPVATrate(uint8_t rate, bool implicitUpdate, uint16_t maxWait)
{
if (packetUBXNAVPVAT == NULL) initPacketUBXNAVPVAT(); //Check that RAM has been allocated for the PVAT data
if (packetUBXNAVPVAT == NULL) //Only attempt this if RAM allocation was successful
return false;
if (rate > 127) rate = 127;
packetCfg.cls = UBX_CLASS_CFG;
packetCfg.id = UBX_CFG_MSG;
packetCfg.len = 3;
packetCfg.startingSpot = 0;
payloadCfg[0] = UBX_CLASS_NAV;
payloadCfg[1] = UBX_NAV_PVAT;
payloadCfg[2] = rate; // rate relative to navigation freq.
bool ok = ((sendCommand(&packetCfg, maxWait)) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK
if (ok)
{
packetUBXNAVPVAT->automaticFlags.flags.bits.automatic = (rate > 0);
packetUBXNAVPVAT->automaticFlags.flags.bits.implicitUpdate = implicitUpdate;
}
packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
return ok;
}
//Enable automatic navigation message generation by the GNSS. This changes the way getPVAT works.
bool SFE_UBLOX_GNSS::setAutoNAVPVATcallback(void (*callbackPointer)(UBX_NAV_PVAT_data_t), uint16_t maxWait)
{
// Enable auto messages. Set implicitUpdate to false as we expect the user to call checkUblox manually.
bool result = setAutoNAVPVAT(true, false, maxWait);
if (!result)
return (result); // Bail if setAutoPVAT failed
if (packetUBXNAVPVAT->callbackData == NULL) //Check if RAM has been allocated for the callback copy
{
packetUBXNAVPVAT->callbackData = new UBX_NAV_PVAT_data_t; //Allocate RAM for the main struct
}
if (packetUBXNAVPVAT->callbackData == NULL)
{
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
_debugSerial->println(F("setAutoNAVPVATcallback: RAM alloc failed!"));
return (false);
}
packetUBXNAVPVAT->callbackPointer = callbackPointer; // RAM has been allocated so now update the pointer
return (true);
}
//In case no config access to the GNSS is possible and PVAT is send cyclically already
//set config to suitable parameters
bool SFE_UBLOX_GNSS::assumeAutoNAVPVAT(bool enabled, bool implicitUpdate)
{
if (packetUBXNAVPVAT == NULL) initPacketUBXNAVPVAT(); //Check that RAM has been allocated for the PVAT data
if (packetUBXNAVPVAT == NULL) //Only attempt this if RAM allocation was successful
return false;
bool changes = packetUBXNAVPVAT->automaticFlags.flags.bits.automatic != enabled || packetUBXNAVPVAT->automaticFlags.flags.bits.implicitUpdate != implicitUpdate;
if (changes)
{
packetUBXNAVPVAT->automaticFlags.flags.bits.automatic = enabled;
packetUBXNAVPVAT->automaticFlags.flags.bits.implicitUpdate = implicitUpdate;
}
return changes;
}
// PRIVATE: Allocate RAM for packetUBXNAVPVAT and initialize it
bool SFE_UBLOX_GNSS::initPacketUBXNAVPVAT()
{
packetUBXNAVPVAT = new UBX_NAV_PVAT_t; //Allocate RAM for the main struct
if (packetUBXNAVPVAT == NULL)
{
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
_debugSerial->println(F("initPacketUBXNAVPVAT: RAM alloc failed!"));
return (false);
}
packetUBXNAVPVAT->automaticFlags.flags.all = 0;
packetUBXNAVPVAT->callbackPointer = NULL;
packetUBXNAVPVAT->callbackData = NULL;
packetUBXNAVPVAT->moduleQueried.moduleQueried1.all = 0;
packetUBXNAVPVAT->moduleQueried.moduleQueried2.all = 0;
return (true);
}
//Mark all the PVAT data as read/stale. This is handy to get data alignment after CRC failure
void SFE_UBLOX_GNSS::flushNAVPVAT()
{
if (packetUBXNAVPVAT == NULL) return; // Bail if RAM has not been allocated (otherwise we could be writing anywhere!)
packetUBXNAVPVAT->moduleQueried.moduleQueried1.all = 0; //Mark all datums as stale (read before)
packetUBXNAVPVAT->moduleQueried.moduleQueried2.all = 0;
}
//Log this data in file buffer
void SFE_UBLOX_GNSS::logNAVPVAT(bool enabled)
{
if (packetUBXNAVPVAT == NULL) return; // Bail if RAM has not been allocated (otherwise we could be writing anywhere!)
packetUBXNAVPVAT->automaticFlags.flags.bits.addToFileBuffer = (uint8_t)enabled;
}
// ***** NAV CLOCK automatic support // ***** NAV CLOCK automatic support
bool SFE_UBLOX_GNSS::getNAVCLOCK(uint16_t maxWait) bool SFE_UBLOX_GNSS::getNAVCLOCK(uint16_t maxWait)
@@ -11449,6 +12057,54 @@ void SFE_UBLOX_GNSS::logHNRPVT(bool enabled)
// ***** Helper Functions for NMEA Logging / Processing // ***** Helper Functions for NMEA Logging / Processing
// Set the mainTalkerId used by NMEA messages - allows all NMEA messages except GSV to be prefixed with GP instead of GN
bool SFE_UBLOX_GNSS::setMainTalkerID(sfe_ublox_talker_ids_e id, uint16_t maxWait)
{
//Get the current extended NMEA protocol configuration (V1)
packetCfg.cls = UBX_CLASS_CFG;
packetCfg.id = UBX_CFG_NMEA;
packetCfg.len = 0;
packetCfg.startingSpot = 0;
//Ask module for the current settings. Loads into payloadCfg.
if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK
return (false);
payloadCfg[9] = (uint8_t)id;
packetCfg.len = 20;
packetCfg.startingSpot = 0;
return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK
}
// Enable/Disable NMEA High Precision Mode - include extra decimal places in the Lat and Lon
bool SFE_UBLOX_GNSS::setHighPrecisionMode(bool enable, uint16_t maxWait)
{
//Get the current extended NMEA protocol configuration (V1)
packetCfg.cls = UBX_CLASS_CFG;
packetCfg.id = UBX_CFG_NMEA;
packetCfg.len = 0;
packetCfg.startingSpot = 0;
//Ask module for the current settings. Loads into payloadCfg.
if (sendCommand(&packetCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK
return (false);
if (enable)
{
payloadCfg[3] |= (1 << 3); // Set the highPrec flag
payloadCfg[3] &= ~((1 << 0) | (1 << 2)); // Clear the compat and limit82 flags
}
else
payloadCfg[3] &= ~(1 << 3); // Clear the highPrec flag
packetCfg.len = 20;
packetCfg.startingSpot = 0;
return (sendCommand(&packetCfg, maxWait) == SFE_UBLOX_STATUS_DATA_SENT); // We are only expecting an ACK
}
// Log selected NMEA messages to file buffer - if the messages are enabled and if the file buffer exists // Log selected NMEA messages to file buffer - if the messages are enabled and if the file buffer exists
// User needs to call setFileBufferSize before .begin // User needs to call setFileBufferSize before .begin
void SFE_UBLOX_GNSS::setNMEALoggingMask(uint32_t messages) void SFE_UBLOX_GNSS::setNMEALoggingMask(uint32_t messages)
@@ -11470,6 +12126,153 @@ uint32_t SFE_UBLOX_GNSS::getProcessNMEAMask()
return (_processNMEA.all); return (_processNMEA.all);
} }
// Initiate automatic storage of NMEA GPGGA messages
// Get the most recent GPGGA message
// Return 0 if the message has not been received from the module
// Return 1 if the data is valid but has been read before
// Return 2 if the data is valid and is fresh/unread
uint8_t SFE_UBLOX_GNSS::getLatestNMEAGPGGA(NMEA_GGA_data_t *data)
{
if (storageNMEAGPGGA == NULL) initStorageNMEAGPGGA(); //Check that RAM has been allocated for the message
if (storageNMEAGPGGA == NULL) //Bail if the RAM allocation failed
return (false);
checkUbloxInternal(&packetCfg, 0, 0); // Call checkUbloxInternal to parse any incoming data. Use a fake UBX class and ID.
memcpy(data, &storageNMEAGPGGA->completeCopy, sizeof(NMEA_GGA_data_t)); // Copy the complete copy
uint8_t result = 0;
if (storageNMEAGPGGA->automaticFlags.flags.bits.completeCopyValid == 1) // Is the complete copy valid?
{
result = 1;
if (storageNMEAGPGGA->automaticFlags.flags.bits.completeCopyRead == 0) // Has the data already been read?
{
result = 2;
storageNMEAGPGGA->automaticFlags.flags.bits.completeCopyRead = 1; // Mark the data as read
}
}
return (result);
}
//Enable a callback on the arrival of a GPGGA message
bool SFE_UBLOX_GNSS::setNMEAGPGGAcallback(void (*callbackPointer)(NMEA_GGA_data_t))
{
if (storageNMEAGPGGA == NULL) initStorageNMEAGPGGA(); //Check that RAM has been allocated for the message
if (storageNMEAGPGGA == NULL) //Bail if the RAM allocation failed
return (false);
if (storageNMEAGPGGA->callbackCopy == NULL) // Check if RAM has been allocated for the callback copy
{
storageNMEAGPGGA->callbackCopy = new NMEA_GGA_data_t;
}
if (storageNMEAGPGGA->callbackCopy == NULL)
{
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
_debugSerial->println(F("setNMEAGPGGAcallback: RAM alloc failed!"));
return (false);
}
storageNMEAGPGGA->callbackPointer = callbackPointer;
return (true);
}
// Private: allocate RAM for incoming NMEA GPGGA messages and initialize it
bool SFE_UBLOX_GNSS::initStorageNMEAGPGGA()
{
storageNMEAGPGGA = new NMEA_GPGGA_t; //Allocate RAM for the main struct
if (storageNMEAGPGGA == NULL)
{
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
_debugSerial->println(F("initStorageNMEAGPGGA: RAM alloc failed!"));
return (false);
}
storageNMEAGPGGA->workingCopy.length = 0; // Clear the data length
memset(storageNMEAGPGGA->workingCopy.nmea, 0, NMEA_GGA_MAX_LENGTH); // Clear the nmea storage
storageNMEAGPGGA->completeCopy.length = 0; // Clear the data length
memset(storageNMEAGPGGA->completeCopy.nmea, 0, NMEA_GGA_MAX_LENGTH); // Clear the nmea storage
storageNMEAGPGGA->callbackPointer = NULL; // Clear the callback pointers
storageNMEAGPGGA->callbackCopy = NULL;
storageNMEAGPGGA->automaticFlags.flags.all = 0; // Mark the data as invalid/stale and unread
return (true);
}
uint8_t SFE_UBLOX_GNSS::getLatestNMEAGNGGA(NMEA_GGA_data_t *data)
{
if (storageNMEAGNGGA == NULL) initStorageNMEAGNGGA(); //Check that RAM has been allocated for the message
if (storageNMEAGNGGA == NULL) //Bail if the RAM allocation failed
return (false);
checkUbloxInternal(&packetCfg, 0, 0); // Call checkUbloxInternal to parse any incoming data. Use a fake UBX class and ID.
memcpy(data, &storageNMEAGNGGA->completeCopy, sizeof(NMEA_GGA_data_t)); // Copy the complete copy
uint8_t result = 0;
if (storageNMEAGNGGA->automaticFlags.flags.bits.completeCopyValid == 1) // Is the complete copy valid?
{
result = 1;
if (storageNMEAGNGGA->automaticFlags.flags.bits.completeCopyRead == 0) // Has the data already been read?
{
result = 2;
storageNMEAGNGGA->automaticFlags.flags.bits.completeCopyRead = 1; // Mark the data as read
}
}
return (result);
}
bool SFE_UBLOX_GNSS::setNMEAGNGGAcallback(void (*callbackPointer)(NMEA_GGA_data_t))
{
if (storageNMEAGNGGA == NULL) initStorageNMEAGNGGA(); //Check that RAM has been allocated for the message
if (storageNMEAGNGGA == NULL) //Bail if the RAM allocation failed
return (false);
if (storageNMEAGNGGA->callbackCopy == NULL) // Check if RAM has been allocated for the callback copy
{
storageNMEAGNGGA->callbackCopy = new NMEA_GGA_data_t;
}
if (storageNMEAGNGGA->callbackCopy == NULL)
{
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
_debugSerial->println(F("setNMEAGNGGAcallback: RAM alloc failed!"));
return (false);
}
storageNMEAGNGGA->callbackPointer = callbackPointer;
return (true);
}
// Private: allocate RAM for incoming NMEA GNGGA messages and initialize it
bool SFE_UBLOX_GNSS::initStorageNMEAGNGGA()
{
storageNMEAGNGGA = new NMEA_GNGGA_t; //Allocate RAM for the main struct
if (storageNMEAGNGGA == NULL)
{
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
_debugSerial->println(F("initStorageNMEAGNGGA: RAM alloc failed!"));
return (false);
}
storageNMEAGNGGA->workingCopy.length = 0; // Clear the data length
memset(storageNMEAGNGGA->workingCopy.nmea, 0, NMEA_GGA_MAX_LENGTH); // Clear the nmea storage
storageNMEAGNGGA->completeCopy.length = 0; // Clear the data length
memset(storageNMEAGNGGA->completeCopy.nmea, 0, NMEA_GGA_MAX_LENGTH); // Clear the nmea storage
storageNMEAGNGGA->callbackPointer = NULL; // Clear the callback pointers
storageNMEAGNGGA->callbackCopy = NULL;
storageNMEAGNGGA->automaticFlags.flags.all = 0; // Mark the data as invalid/stale and unread
return (true);
}
// ***** CFG RATE Helper Functions // ***** CFG RATE Helper Functions
//Set the rate at which the module will give us an updated navigation solution //Set the rate at which the module will give us an updated navigation solution
@@ -12525,6 +13328,60 @@ uint32_t SFE_UBLOX_GNSS::getVerticalAccuracy(uint16_t maxWait)
return (packetUBXNAVHPPOSLLH->data.vAcc); return (packetUBXNAVHPPOSLLH->data.vAcc);
} }
// ***** PVAT Helper Functions
int32_t SFE_UBLOX_GNSS::getVehicleRoll(uint16_t maxWait)
{
if (packetUBXNAVPVAT == NULL) initPacketUBXNAVPVAT(); //Check that RAM has been allocated for the PVAT data
if (packetUBXNAVPVAT == NULL) //Bail if the RAM allocation failed
return 0;
if (packetUBXNAVPVAT->moduleQueried.moduleQueried2.bits.vehRoll == false)
getNAVPVAT(maxWait);
packetUBXNAVPVAT->moduleQueried.moduleQueried2.bits.vehRoll = false; //Since we are about to give this to user, mark this data as stale
packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
return (packetUBXNAVPVAT->data.vehRoll);
}
int32_t SFE_UBLOX_GNSS::getVehiclePitch(uint16_t maxWait)
{
if (packetUBXNAVPVAT == NULL) initPacketUBXNAVPVAT(); //Check that RAM has been allocated for the PVAT data
if (packetUBXNAVPVAT == NULL) //Bail if the RAM allocation failed
return 0;
if (packetUBXNAVPVAT->moduleQueried.moduleQueried2.bits.vehPitch == false)
getNAVPVAT(maxWait);
packetUBXNAVPVAT->moduleQueried.moduleQueried2.bits.vehPitch = false; //Since we are about to give this to user, mark this data as stale
packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
return (packetUBXNAVPVAT->data.vehPitch);
}
int32_t SFE_UBLOX_GNSS::getVehicleHeading(uint16_t maxWait)
{
if (packetUBXNAVPVAT == NULL) initPacketUBXNAVPVAT(); //Check that RAM has been allocated for the PVAT data
if (packetUBXNAVPVAT == NULL) //Bail if the RAM allocation failed
return 0;
if (packetUBXNAVPVAT->moduleQueried.moduleQueried2.bits.vehHeading == false)
getNAVPVAT(maxWait);
packetUBXNAVPVAT->moduleQueried.moduleQueried2.bits.vehHeading = false; //Since we are about to give this to user, mark this data as stale
packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
return (packetUBXNAVPVAT->data.vehHeading);
}
int32_t SFE_UBLOX_GNSS::getMotionHeading(uint16_t maxWait)
{
if (packetUBXNAVPVAT == NULL) initPacketUBXNAVPVAT(); //Check that RAM has been allocated for the PVAT data
if (packetUBXNAVPVAT == NULL) //Bail if the RAM allocation failed
return 0;
if (packetUBXNAVPVAT->moduleQueried.moduleQueried2.bits.motHeading == false)
getNAVPVAT(maxWait);
packetUBXNAVPVAT->moduleQueried.moduleQueried2.bits.motHeading = false; //Since we are about to give this to user, mark this data as stale
packetUBXNAVPVAT->moduleQueried.moduleQueried1.bits.all = false;
return (packetUBXNAVPVAT->data.motHeading);
}
// ***** SVIN Helper Functions // ***** SVIN Helper Functions
bool SFE_UBLOX_GNSS::getSurveyInActive(uint16_t maxWait) bool SFE_UBLOX_GNSS::getSurveyInActive(uint16_t maxWait)
+90 -18
View File
@@ -355,6 +355,7 @@ const uint8_t UBX_NAV_ORB = 0x34; //GNSS Orbit Database Info
const uint8_t UBX_NAV_POSECEF = 0x01; //Position Solution in ECEF const uint8_t UBX_NAV_POSECEF = 0x01; //Position Solution in ECEF
const uint8_t UBX_NAV_POSLLH = 0x02; //Geodetic Position Solution const uint8_t UBX_NAV_POSLLH = 0x02; //Geodetic Position Solution
const uint8_t UBX_NAV_PVT = 0x07; //All the things! Position, velocity, time, PDOP, height, h/v accuracies, number of satellites. Navigation Position Velocity Time Solution. const uint8_t UBX_NAV_PVT = 0x07; //All the things! Position, velocity, time, PDOP, height, h/v accuracies, number of satellites. Navigation Position Velocity Time Solution.
const uint8_t UBX_NAV_PVAT = 0x17; //Navigation position velocity attitude time solution (ZED-F9R only)
const uint8_t UBX_NAV_RELPOSNED = 0x3C; //Relative Positioning Information in NED frame const uint8_t UBX_NAV_RELPOSNED = 0x3C; //Relative Positioning Information in NED frame
const uint8_t UBX_NAV_RESETODO = 0x10; //Reset odometer const uint8_t UBX_NAV_RESETODO = 0x10; //Reset odometer
const uint8_t UBX_NAV_SAT = 0x35; //Satellite Information const uint8_t UBX_NAV_SAT = 0x35; //Satellite Information
@@ -378,7 +379,8 @@ const uint8_t UBX_RXM_PMREQ = 0x41; //Requests a Power Management task (two diff
const uint8_t UBX_RXM_RAWX = 0x15; //Multi-GNSS Raw Measurement Data const uint8_t UBX_RXM_RAWX = 0x15; //Multi-GNSS Raw Measurement Data
const uint8_t UBX_RXM_RLM = 0x59; //Galileo SAR Short-RLM report (two different packet sizes) const uint8_t UBX_RXM_RLM = 0x59; //Galileo SAR Short-RLM report (two different packet sizes)
const uint8_t UBX_RXM_RTCM = 0x32; //RTCM input status const uint8_t UBX_RXM_RTCM = 0x32; //RTCM input status
const uint8_t UBX_RXM_SFRBX = 0x13; //Boradcast Navigation Data Subframe const uint8_t UBX_RXM_SFRBX = 0x13; //Broadcast Navigation Data Subframe
const uint8_t UBX_RXM_SPARTN = 0x33; //SPARTN input status
//Class: SEC //Class: SEC
//The following are used to configure the SEC UBX messages (security feature messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 36) //The following are used to configure the SEC UBX messages (security feature messages). Descriptions from UBX messages overview (ZED_F9P Interface Description Document page 36)
@@ -437,6 +439,7 @@ const uint8_t COM_PORT_SPI = 4;
const uint8_t COM_TYPE_UBX = (1 << 0); const uint8_t COM_TYPE_UBX = (1 << 0);
const uint8_t COM_TYPE_NMEA = (1 << 1); const uint8_t COM_TYPE_NMEA = (1 << 1);
const uint8_t COM_TYPE_RTCM3 = (1 << 5); const uint8_t COM_TYPE_RTCM3 = (1 << 5);
const uint8_t COM_TYPE_SPARTN = (1 << 6);
// Configuration Sub-Section mask definitions for saveConfigSelective (UBX-CFG-CFG) // Configuration Sub-Section mask definitions for saveConfigSelective (UBX-CFG-CFG)
const uint32_t VAL_CFG_SUBSEC_IOPORT = 0x00000001; // ioPort - communications port settings (causes IO system reset!) const uint32_t VAL_CFG_SUBSEC_IOPORT = 0x00000001; // ioPort - communications port settings (causes IO system reset!)
@@ -468,7 +471,9 @@ enum dynModel // Possible values for the dynamic platform model, which provide m
DYN_MODEL_AIRBORNE2g, //Airborne <2g acceleration. Recommended for typical airborne environments. No 2D position fixes supported. DYN_MODEL_AIRBORNE2g, //Airborne <2g acceleration. Recommended for typical airborne environments. No 2D position fixes supported.
DYN_MODEL_AIRBORNE4g, //Airborne <4g acceleration. Only recommended for extremely dynamic environments. No 2D position fixes supported. DYN_MODEL_AIRBORNE4g, //Airborne <4g acceleration. Only recommended for extremely dynamic environments. No 2D position fixes supported.
DYN_MODEL_WRIST, // Not supported in protocol versions less than 18. Only recommended for wrist worn applications. Receiver will filter out arm motion. DYN_MODEL_WRIST, // Not supported in protocol versions less than 18. Only recommended for wrist worn applications. Receiver will filter out arm motion.
DYN_MODEL_BIKE, // Supported in protocol versions 19.2 DYN_MODEL_BIKE, // Supported in protocol versions 19.2. (not available in all products)
DYN_MODEL_MOWER, // Added in HPS 1.21 (not available in all products)
DYN_MODEL_ESCOOTER, // Added in HPS 1.21 (not available in all products)
DYN_MODEL_UNKNOWN = 255 // getDynamicModel will return 255 if sendCommand fails DYN_MODEL_UNKNOWN = 255 // getDynamicModel will return 255 if sendCommand fails
}; };
@@ -517,6 +522,25 @@ enum sfe_ublox_mga_ack_infocode_e
SFE_UBLOX_MGA_ACK_INFOCODE_TYPE_UNKNOWN SFE_UBLOX_MGA_ACK_INFOCODE_TYPE_UNKNOWN
}; };
// The mainTalkerId, set by UBX-CFG-NMEA setMainTalkerID
enum sfe_ublox_talker_ids_e
{
SFE_UBLOX_MAIN_TALKER_ID_DEFAULT,
SFE_UBLOX_MAIN_TALKER_ID_GP,
SFE_UBLOX_MAIN_TALKER_ID_GL,
SFE_UBLOX_MAIN_TALKER_ID_GN,
SFE_UBLOX_MAIN_TALKER_ID_GA,
SFE_UBLOX_MAIN_TALKER_ID_GB,
SFE_UBLOX_MAIN_TALKER_ID_GQ
};
// The DGNSS differential mode
enum sfe_ublox_dgnss_mode_e
{
SFE_UBLOX_DGNSS_MODE_FLOAT = 2, // No attempts are made to fix ambiguities
SFE_UBLOX_DGNSS_MODE_FIXED // Ambiguities are fixed whenever possible
};
//-=-=-=-=- //-=-=-=-=-
#ifndef MAX_PAYLOAD_SIZE #ifndef MAX_PAYLOAD_SIZE
@@ -767,17 +791,17 @@ public:
//Port configurations //Port configurations
bool getPortSettings(uint8_t portID, uint16_t maxWait = defaultMaxWait); //Returns the current protocol bits in the UBX-CFG-PRT command for a given port bool getPortSettings(uint8_t portID, uint16_t maxWait = defaultMaxWait); //Returns the current protocol bits in the UBX-CFG-PRT command for a given port
bool setPortOutput(uint8_t portID, uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure a given port to output UBX, NMEA, RTCM3 or a combination thereof bool setPortOutput(uint8_t portID, uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure a given port to output UBX, NMEA, RTCM3, SPARTN or a combination thereof
bool setPortInput(uint8_t portID, uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure a given port to input UBX, NMEA, RTCM3 or a combination thereof bool setPortInput(uint8_t portID, uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure a given port to input UBX, NMEA, RTCM3, SPARTN or a combination thereof
bool setI2CAddress(uint8_t deviceAddress, uint16_t maxTime = defaultMaxWait); //Changes the I2C address of the u-blox module bool setI2CAddress(uint8_t deviceAddress, uint16_t maxTime = defaultMaxWait); //Changes the I2C address of the u-blox module
void setSerialRate(uint32_t baudrate, uint8_t uartPort = COM_PORT_UART1, uint16_t maxTime = defaultMaxWait); //Changes the serial baud rate of the u-blox module, uartPort should be COM_PORT_UART1/2 void setSerialRate(uint32_t baudrate, uint8_t uartPort = COM_PORT_UART1, uint16_t maxTime = defaultMaxWait); //Changes the serial baud rate of the u-blox module, uartPort should be COM_PORT_UART1/2
bool setI2COutput(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure I2C port to output UBX, NMEA, RTCM3 or a combination thereof bool setI2COutput(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure I2C port to output UBX, NMEA, RTCM3, SPARTN or a combination thereof
bool setUART1Output(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure UART1 port to output UBX, NMEA, RTCM3 or a combination thereof bool setUART1Output(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure UART1 port to output UBX, NMEA, RTCM3, SPARTN or a combination thereof
bool setUART2Output(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure UART2 port to output UBX, NMEA, RTCM3 or a combination thereof bool setUART2Output(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure UART2 port to output UBX, NMEA, RTCM3, SPARTN or a combination thereof
bool setUSBOutput(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure USB port to output UBX, NMEA, RTCM3 or a combination thereof bool setUSBOutput(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure USB port to output UBX, NMEA, RTCM3, SPARTN or a combination thereof
bool setSPIOutput(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure SPI port to output UBX, NMEA, RTCM3 or a combination thereof bool setSPIOutput(uint8_t comSettings, uint16_t maxWait = defaultMaxWait); //Configure SPI port to output UBX, NMEA, RTCM3, SPARTN or a combination thereof
void setNMEAOutputPort(Stream &nmeaOutputPort); //Sets the internal variable for the port to direct NMEA characters to void setNMEAOutputPort(Stream &nmeaOutputPort); //Sets the internal variable for the port to direct NMEA characters to
//Reset to defaults //Reset to defaults
@@ -812,6 +836,7 @@ public:
// For Lat/Lon/Alt the units are: degrees^-7, degrees^-9, degrees^-7, degrees^-9, cm, 0.1mm // For Lat/Lon/Alt the units are: degrees^-7, degrees^-9, degrees^-7, degrees^-9, cm, 0.1mm
bool setStaticPosition(int32_t ecefXOrLat, int8_t ecefXOrLatHP, int32_t ecefYOrLon, int8_t ecefYOrLonHP, int32_t ecefZOrAlt, int8_t ecefZOrAltHP, bool latLong = false, uint16_t maxWait = 250); bool setStaticPosition(int32_t ecefXOrLat, int8_t ecefXOrLatHP, int32_t ecefYOrLon, int8_t ecefYOrLonHP, int32_t ecefZOrAlt, int8_t ecefZOrAltHP, bool latLong = false, uint16_t maxWait = 250);
bool setStaticPosition(int32_t ecefXOrLat, int32_t ecefYOrLon, int32_t ecefZOrAlt, bool latLong = false, uint16_t maxWait = 250); bool setStaticPosition(int32_t ecefXOrLat, int32_t ecefYOrLon, int32_t ecefZOrAlt, bool latLong = false, uint16_t maxWait = 250);
bool setDGNSSConfiguration(sfe_ublox_dgnss_mode_e dgnssMode = SFE_UBLOX_DGNSS_MODE_FIXED, uint16_t maxWait = defaultMaxWait); // Set the DGNSS differential mode
//Read the module's protocol version //Read the module's protocol version
uint8_t getProtocolVersionHigh(uint16_t maxWait = defaultMaxWait); //Returns the PROTVER XX.00 from UBX-MON-VER register uint8_t getProtocolVersionHigh(uint16_t maxWait = defaultMaxWait); //Returns the PROTVER XX.00 from UBX-MON-VER register
@@ -983,7 +1008,7 @@ public:
void flushNAVHPPOSECEF(); //Mark all the data as read/stale void flushNAVHPPOSECEF(); //Mark all the data as read/stale
void logNAVHPPOSECEF(bool enabled = true); // Log data to file buffer void logNAVHPPOSECEF(bool enabled = true); // Log data to file buffer
bool getHPPOSLLH(uint16_t maxWait = defaultMaxWait); //Query module for latest group of datums and load global vars: lat, long, alt, speed, SIV, accuracies, etc. If autoPVT is disabled, performs an explicit poll and waits, if enabled does not block. Returns true if new HPPOSLLH is available. bool getHPPOSLLH(uint16_t maxWait = defaultMaxWait); // NAV HPPOSLLH
bool setAutoHPPOSLLH(bool enabled, uint16_t maxWait = defaultMaxWait); //Enable/disable automatic HPPOSLLH reports at the navigation frequency bool setAutoHPPOSLLH(bool enabled, uint16_t maxWait = defaultMaxWait); //Enable/disable automatic HPPOSLLH reports at the navigation frequency
bool setAutoHPPOSLLH(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); //Enable/disable automatic HPPOSLLH reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update bool setAutoHPPOSLLH(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); //Enable/disable automatic HPPOSLLH reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoHPPOSLLHrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); //Set the rate for automatic HPPOSLLH reports bool setAutoHPPOSLLHrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); //Set the rate for automatic HPPOSLLH reports
@@ -992,6 +1017,15 @@ public:
void flushHPPOSLLH(); //Mark all the HPPPOSLLH data as read/stale. This is handy to get data alignment after CRC failure void flushHPPOSLLH(); //Mark all the HPPPOSLLH data as read/stale. This is handy to get data alignment after CRC failure
void logNAVHPPOSLLH(bool enabled = true); // Log data to file buffer void logNAVHPPOSLLH(bool enabled = true); // Log data to file buffer
bool getNAVPVAT(uint16_t maxWait = defaultMaxWait); // NAV PVAT
bool setAutoNAVPVAT(bool enabled, uint16_t maxWait = defaultMaxWait); //Enable/disable automatic PVAT reports at the navigation frequency
bool setAutoNAVPVAT(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); //Enable/disable automatic PVAT reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
bool setAutoNAVPVATrate(uint8_t rate, bool implicitUpdate = true, uint16_t maxWait = defaultMaxWait); //Set the rate for automatic PVAT reports
bool setAutoNAVPVATcallback(void (*callbackPointer)(UBX_NAV_PVAT_data_t), uint16_t maxWait = defaultMaxWait); //Enable automatic PVAT reports at the navigation frequency. Data is accessed from the callback.
bool assumeAutoNAVPVAT(bool enabled, bool implicitUpdate = true); //In case no config access to the GPS is possible and PVAT is send cyclically already
void flushNAVPVAT(); //Mark all the PVAT data as read/stale
void logNAVPVAT(bool enabled = true); // Log data to file buffer
bool getNAVCLOCK(uint16_t maxWait = defaultMaxWait); // NAV CLOCK bool getNAVCLOCK(uint16_t maxWait = defaultMaxWait); // NAV CLOCK
bool setAutoNAVCLOCK(bool enabled, uint16_t maxWait = defaultMaxWait); //Enable/disable automatic clock reports at the navigation frequency bool setAutoNAVCLOCK(bool enabled, uint16_t maxWait = defaultMaxWait); //Enable/disable automatic clock reports at the navigation frequency
bool setAutoNAVCLOCK(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); //Enable/disable automatic clock reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update bool setAutoNAVCLOCK(bool enabled, bool implicitUpdate, uint16_t maxWait = defaultMaxWait); //Enable/disable automatic clock reports at the navigation frequency, with implicitUpdate == false accessing stale data will not issue parsing of data in the rxbuffer of your interface, instead you have to call checkUblox when you want to perform an update
@@ -1153,14 +1187,6 @@ public:
void flushHNRPVT(); //Mark all the data as read/stale void flushHNRPVT(); //Mark all the data as read/stale
void logHNRPVT(bool enabled = true); // Log data to file buffer void logHNRPVT(bool enabled = true); // Log data to file buffer
// Helper functions for NMEA logging
void setNMEALoggingMask(uint32_t messages = SFE_UBLOX_FILTER_NMEA_ALL); // Add selected NMEA messages to file buffer - if enabled. Default to adding ALL messages to the file buffer
uint32_t getNMEALoggingMask(); // Return which NMEA messages are selected for logging to the file buffer - if enabled
// Helper functions to control which NMEA messages are passed to processNMEA
void setProcessNMEAMask(uint32_t messages = SFE_UBLOX_FILTER_NMEA_ALL); // Control which NMEA messages are passed to processNMEA. Default to passing ALL messages
uint32_t getProcessNMEAMask(); // Return which NMEA messages are passed to processNMEA
// Helper functions for CFG RATE // Helper functions for CFG RATE
bool setNavigationFrequency(uint8_t navFreq, uint16_t maxWait = defaultMaxWait); //Set the number of nav solutions sent per second bool setNavigationFrequency(uint8_t navFreq, uint16_t maxWait = defaultMaxWait); //Set the number of nav solutions sent per second
@@ -1256,6 +1282,13 @@ public:
uint32_t getHorizontalAccuracy(uint16_t maxWait = defaultMaxWait); uint32_t getHorizontalAccuracy(uint16_t maxWait = defaultMaxWait);
uint32_t getVerticalAccuracy(uint16_t maxWait = defaultMaxWait); uint32_t getVerticalAccuracy(uint16_t maxWait = defaultMaxWait);
// Helper functions for PVAT
int32_t getVehicleRoll(uint16_t maxWait = defaultMaxWait); // Returns vehicle roll in degrees * 10^-5
int32_t getVehiclePitch(uint16_t maxWait = defaultMaxWait); // Returns vehicle pitch in degrees * 10^-5
int32_t getVehicleHeading(uint16_t maxWait = defaultMaxWait); // Returns vehicle heading in degrees * 10^-5
int32_t getMotionHeading(uint16_t maxWait = defaultMaxWait); // Returns the motion heading in degrees * 10^-5
// Helper functions for SVIN // Helper functions for SVIN
bool getSurveyInActive(uint16_t maxWait = defaultMaxWait); bool getSurveyInActive(uint16_t maxWait = defaultMaxWait);
@@ -1302,6 +1335,26 @@ public:
float getHNRpitch(uint16_t maxWait = defaultMaxWait); // Returned as degrees float getHNRpitch(uint16_t maxWait = defaultMaxWait); // Returned as degrees
float getHNRheading(uint16_t maxWait = defaultMaxWait); // Returned as degrees float getHNRheading(uint16_t maxWait = defaultMaxWait); // Returned as degrees
// Set the mainTalkerId used by NMEA messages - allows all NMEA messages except GSV to be prefixed with GP instead of GN
bool setMainTalkerID(sfe_ublox_talker_ids_e id = SFE_UBLOX_MAIN_TALKER_ID_DEFAULT, uint16_t maxWait = defaultMaxWait);
// Enable/Disable NMEA High Precision Mode - include extra decimal places in the Lat and Lon
bool setHighPrecisionMode(bool enable = true, uint16_t maxWait = defaultMaxWait);
// Helper functions for NMEA logging
void setNMEALoggingMask(uint32_t messages = SFE_UBLOX_FILTER_NMEA_ALL); // Add selected NMEA messages to file buffer - if enabled. Default to adding ALL messages to the file buffer
uint32_t getNMEALoggingMask(); // Return which NMEA messages are selected for logging to the file buffer - if enabled
// Helper functions to control which NMEA messages are passed to processNMEA
void setProcessNMEAMask(uint32_t messages = SFE_UBLOX_FILTER_NMEA_ALL); // Control which NMEA messages are passed to processNMEA. Default to passing ALL messages
uint32_t getProcessNMEAMask(); // Return which NMEA messages are passed to processNMEA
// Support for "auto" storage of NMEA messages
uint8_t getLatestNMEAGPGGA(NMEA_GGA_data_t *data); // Return the most recent GPGGA: 0 = no data, 1 = stale data, 2 = fresh data
bool setNMEAGPGGAcallback(void (*callbackPointer)(NMEA_GGA_data_t)); //Enable a callback on the arrival of a GPGGA message
uint8_t getLatestNMEAGNGGA(NMEA_GGA_data_t *data); // Return the most recent GNGGA: 0 = no data, 1 = stale data, 2 = fresh data
bool setNMEAGNGGAcallback(void (*callbackPointer)(NMEA_GGA_data_t)); //Enable a callback on the arrival of a GNGGA message
// Functions to extract signed and unsigned 8/16/32-bit data from a ubxPacket // Functions to extract signed and unsigned 8/16/32-bit data from a ubxPacket
// From v2.0: These are public. The user can call these to extract data from custom packets // From v2.0: These are public. The user can call these to extract data from custom packets
uint32_t extractLong(ubxPacket *msg, uint8_t spotToStart); //Combine four bytes from payload into long uint32_t extractLong(ubxPacket *msg, uint8_t spotToStart); //Combine four bytes from payload into long
@@ -1324,6 +1377,7 @@ public:
UBX_NAV_VELNED_t *packetUBXNAVVELNED = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary UBX_NAV_VELNED_t *packetUBXNAVVELNED = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_NAV_HPPOSECEF_t *packetUBXNAVHPPOSECEF = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary UBX_NAV_HPPOSECEF_t *packetUBXNAVHPPOSECEF = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_NAV_HPPOSLLH_t *packetUBXNAVHPPOSLLH = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary UBX_NAV_HPPOSLLH_t *packetUBXNAVHPPOSLLH = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_NAV_PVAT_t *packetUBXNAVPVAT = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_NAV_CLOCK_t *packetUBXNAVCLOCK = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary UBX_NAV_CLOCK_t *packetUBXNAVCLOCK = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_NAV_TIMELS_t *packetUBXNAVTIMELS = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary UBX_NAV_TIMELS_t *packetUBXNAVTIMELS = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_NAV_SVIN_t *packetUBXNAVSVIN = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary UBX_NAV_SVIN_t *packetUBXNAVSVIN = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
@@ -1351,6 +1405,9 @@ public:
UBX_MGA_ACK_DATA0_t *packetUBXMGAACK = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary UBX_MGA_ACK_DATA0_t *packetUBXMGAACK = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
UBX_MGA_DBD_t *packetUBXMGADBD = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary UBX_MGA_DBD_t *packetUBXMGADBD = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
NMEA_GPGGA_t *storageNMEAGPGGA = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
NMEA_GNGGA_t *storageNMEAGNGGA = NULL; // Pointer to struct. RAM will be allocated for this if/when necessary
uint16_t rtcmFrameCounter = 0; //Tracks the type of incoming byte inside RTCM frame uint16_t rtcmFrameCounter = 0; //Tracks the type of incoming byte inside RTCM frame
private: private:
@@ -1408,6 +1465,7 @@ private:
bool initPacketUBXNAVVELNED(); // Allocate RAM for packetUBXNAVVELNED and initialize it bool initPacketUBXNAVVELNED(); // Allocate RAM for packetUBXNAVVELNED and initialize it
bool initPacketUBXNAVHPPOSECEF(); // Allocate RAM for packetUBXNAVHPPOSECEF and initialize it bool initPacketUBXNAVHPPOSECEF(); // Allocate RAM for packetUBXNAVHPPOSECEF and initialize it
bool initPacketUBXNAVHPPOSLLH(); // Allocate RAM for packetUBXNAVHPPOSLLH and initialize it bool initPacketUBXNAVHPPOSLLH(); // Allocate RAM for packetUBXNAVHPPOSLLH and initialize it
bool initPacketUBXNAVPVAT(); // Allocate RAM for packetUBXNAVPVAT and initialize it
bool initPacketUBXNAVCLOCK(); // Allocate RAM for packetUBXNAVCLOCK and initialize it bool initPacketUBXNAVCLOCK(); // Allocate RAM for packetUBXNAVCLOCK and initialize it
bool initPacketUBXNAVTIMELS(); // Allocate RAM for packetUBXNAVTIMELS and initialize it bool initPacketUBXNAVTIMELS(); // Allocate RAM for packetUBXNAVTIMELS and initialize it
bool initPacketUBXNAVSVIN(); // Allocate RAM for packetUBXNAVSVIN and initialize it bool initPacketUBXNAVSVIN(); // Allocate RAM for packetUBXNAVSVIN and initialize it
@@ -1429,6 +1487,9 @@ private:
bool initPacketUBXMGAACK(); // Allocate RAM for packetUBXMGAACK and initialize it bool initPacketUBXMGAACK(); // Allocate RAM for packetUBXMGAACK and initialize it
bool initPacketUBXMGADBD(); // Allocate RAM for packetUBXMGADBD and initialize it bool initPacketUBXMGADBD(); // Allocate RAM for packetUBXMGADBD and initialize it
bool initStorageNMEAGPGGA(); // Allocate RAM for incoming NMEA GPGGA messages and initialize it
bool initStorageNMEAGNGGA(); // Allocate RAM for incoming NMEA GNGGA messages and initialize it
//Variables //Variables
TwoWire *_i2cPort; //The generic connection to user's chosen I2C hardware TwoWire *_i2cPort; //The generic connection to user's chosen I2C hardware
Stream *_serialPort; //The generic connection to user's chosen Serial hardware Stream *_serialPort; //The generic connection to user's chosen Serial hardware
@@ -1503,6 +1564,17 @@ private:
bool processThisNMEA(); // Return true if we should pass this NMEA message to processNMEA bool processThisNMEA(); // Return true if we should pass this NMEA message to processNMEA
bool isNMEAHeaderValid(); // Return true if the six byte NMEA header appears valid. Used to set _signsOfLife bool isNMEAHeaderValid(); // Return true if the six byte NMEA header appears valid. Used to set _signsOfLife
bool isThisNMEAauto(); // Check if the NMEA message (in nmeaAddressField) is "auto" (i.e. has RAM allocated for it)
bool doesThisNMEAHaveCallback(); // Do we need to copy the data into the callback copy?
uint8_t *getNMEAWorkingLengthPtr(); // Get a pointer to the working copy length
uint8_t *getNMEAWorkingNMEAPtr(); // Get a pointer to the working copy NMEA data
uint8_t *getNMEACompleteLengthPtr(); // Get a pointer to the complete copy length
uint8_t *getNMEACompleteNMEAPtr(); // Get a pointer to the complete copy NMEA data
uint8_t *getNMEACallbackLengthPtr(); // Get a pointer to the callback copy length
uint8_t *getNMEACallbackNMEAPtr(); // Get a pointer to the callback copy NMEA data
uint8_t getNMEAMaxLength(); // Get the maximum length of this NMEA message
nmeaAutomaticFlags *getNMEAFlagsPtr(); // Get a pointer to the flags
uint16_t rtcmLen = 0; uint16_t rtcmLen = 0;
// Flag to prevent reentry into checkCallbacks // Flag to prevent reentry into checkCallbacks
+22 -6
View File
@@ -134,6 +134,7 @@ const uint32_t UBLOX_CFG_I2C_ENABLED = 0x10510003; // Flag to indicate if the I2
const uint32_t UBLOX_CFG_I2CINPROT_UBX = 0x10710001; // Flag to indicate if UBX should be an input protocol on I2C const uint32_t UBLOX_CFG_I2CINPROT_UBX = 0x10710001; // Flag to indicate if UBX should be an input protocol on I2C
const uint32_t UBLOX_CFG_I2CINPROT_NMEA = 0x10710002; // Flag to indicate if NMEA should be an input protocol on I2C const uint32_t UBLOX_CFG_I2CINPROT_NMEA = 0x10710002; // Flag to indicate if NMEA should be an input protocol on I2C
const uint32_t UBLOX_CFG_I2CINPROT_RTCM3X = 0x10710004; // Flag to indicate if RTCM3X should be an input protocol on I2C const uint32_t UBLOX_CFG_I2CINPROT_RTCM3X = 0x10710004; // Flag to indicate if RTCM3X should be an input protocol on I2C
const uint32_t UBLOX_CFG_I2CINPROT_SPARTN = 0x10710005; // Flag to indicate if SPARTN should be an input protocol on I2C
//CFG-I2COUTPROT: Output protocol configuration of the I2C interface //CFG-I2COUTPROT: Output protocol configuration of the I2C interface
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
@@ -550,6 +551,16 @@ const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_SFRBX_SPI = 0x20910235; // Output rate
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_SFRBX_UART1 = 0x20910232; // Output rate of the UBX-RXM-SFRBX message on port UART1 const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_SFRBX_UART1 = 0x20910232; // Output rate of the UBX-RXM-SFRBX message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_SFRBX_UART2 = 0x20910233; // Output rate of the UBX-RXM-SFRBX message on port UART2 const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_SFRBX_UART2 = 0x20910233; // Output rate of the UBX-RXM-SFRBX message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_SFRBX_USB = 0x20910234; // Output rate of the UBX-RXM-SFRBX message on port USB const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_SFRBX_USB = 0x20910234; // Output rate of the UBX-RXM-SFRBX message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_SPARTN_I2C = 0x20910605; // Output rate of the UBX-RXM-SPARTN message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_SPARTN_UART1 = 0x20910606; // Output rate of the UBX-RXM-SPARTN message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_SPARTN_UART2 = 0x20910607; // Output rate of the UBX-RXM-SPARTN message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_SPARTN_USB = 0x20910608; // Output rate of the UBX-RXM-SPARTN message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_RXM_SPARTN_SPI = 0x20910609; // Output rate of the UBX-RXM-SPARTN message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIG_I2C = 0x20910634; // Output rate of the UBX-SEC-SIG message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIG_SPI = 0x20910638; // Output rate of the UBX-SEC-SIG message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIG_UART1 = 0x20910635; // Output rate of the UBX-SEC-SIG message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIG_UART2 = 0x20910636; // Output rate of the UBX-SEC-SIG message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIG_USB = 0x20910637; // Output rate of the UBX-SEC-SIG message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_TM2_I2C = 0x20910178; // Output rate of the UBX-TIM-TM2 message on port I2C const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_TM2_I2C = 0x20910178; // Output rate of the UBX-TIM-TM2 message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_TM2_SPI = 0x2091017c; // Output rate of the UBX-TIM-TM2 message on port SPI const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_TM2_SPI = 0x2091017c; // Output rate of the UBX-TIM-TM2 message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_TM2_UART1 = 0x20910179; // Output rate of the UBX-TIM-TM2 message on port UART1 const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_TM2_UART1 = 0x20910179; // Output rate of the UBX-TIM-TM2 message on port UART1
@@ -566,7 +577,7 @@ const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_VRFY_UART1 = 0x20910093; // Output rat
const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_VRFY_UART2 = 0x20910094; // Output rate of the UBX-TIM-VRFY message on port UART2 const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_VRFY_UART2 = 0x20910094; // Output rate of the UBX-TIM-VRFY message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_VRFY_USB = 0x20910095; // Output rate of the UBX-TIM-VRFY message on port USB const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_VRFY_USB = 0x20910095; // Output rate of the UBX-TIM-VRFY message on port USB
//Additional CFG_MSGOUT keys for the ZED-F9R HPS120 //Additional CFG_MSGOUT keys for the ZED-F9R HPS121
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_COV_I2C = 0x20910083; // Output rate of the UBX-NAV-COV message on port I2C const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_COV_I2C = 0x20910083; // Output rate of the UBX-NAV-COV message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_COV_UART1 = 0x20910084; // Output rate of the UBX-NAV-COV message on port UART1 const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_COV_UART1 = 0x20910084; // Output rate of the UBX-NAV-COV message on port UART1
@@ -608,6 +619,12 @@ const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_EELL_UART1 = 0x20910314; // Output rate
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_EELL_UART2 = 0x20910315; // Output rate of the UBX-NAV-EELL message on port UART2 const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_EELL_UART2 = 0x20910315; // Output rate of the UBX-NAV-EELL message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_EELL_USB = 0x20910316; // Output rate of the UBX-NAV-EELL message on port USB const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_EELL_USB = 0x20910316; // Output rate of the UBX-NAV-EELL message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_EELL_SPI = 0x20910317; // Output rate of the UBX-NAV-EELL message on port SPI const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_EELL_SPI = 0x20910317; // Output rate of the UBX-NAV-EELL message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_PVAT_I2C = 0x2091062a; // Output rate of the UBX-NAV-PVAT message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_PVAT_UART1 = 0x2091062b; // Output rate of the UBX-NAV-PVAT message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_PVAT_UART2 = 0x2091062c; // Output rate of the UBX-NAV-PVAT message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_PVAT_USB = 0x2091062d; // Output rate of the UBX-NAV-PVAT message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_NAV_PVAT_SPI = 0x2091062e; // Output rate of the UBX-NAV-PVAT message on port SPI
//Additional CFG_MSGOUT keys for the ZED-F9T //Additional CFG_MSGOUT keys for the ZED-F9T
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
@@ -761,11 +778,6 @@ const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIGLOG_SPI = 0x2091068d; // Output rate
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIGLOG_UART1 = 0x2091068a; // Output rate of the UBX-SEC-SIGLOG message on port UART1 const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIGLOG_UART1 = 0x2091068a; // Output rate of the UBX-SEC-SIGLOG message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIGLOG_UART2 = 0x2091068b; // Output rate of the UBX-SEC-SIGLOG message on port UART2 const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIGLOG_UART2 = 0x2091068b; // Output rate of the UBX-SEC-SIGLOG message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIGLOG_USB = 0x2091068c; // Output rate of the UBX-SEC-SIGLOG message on port USB const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIGLOG_USB = 0x2091068c; // Output rate of the UBX-SEC-SIGLOG message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIG_I2C = 0x20910634; // Output rate of the UBX-DBG-SKYMAP message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIG_SPI = 0x20910638; // Output rate of the UBX-SEC-SIG message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIG_UART1 = 0x20910635; // Output rate of the UBX-SEC-SIG message on port UART1
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIG_UART2 = 0x20910636; // Output rate of the UBX-SEC-SIG message on port UART2
const uint32_t UBLOX_CFG_MSGOUT_UBX_SEC_SIG_USB = 0x20910637; // Output rate of the UBX-SEC-SIG message on port USB
const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_SVIN_I2C = 0x20910097; // Output rate of the UBX-TIM-SVIN message on port I2C const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_SVIN_I2C = 0x20910097; // Output rate of the UBX-TIM-SVIN message on port I2C
const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_SVIN_SPI = 0x2091009b; // Output rate of the UBX-TIM-SVIN message on port SPI const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_SVIN_SPI = 0x2091009b; // Output rate of the UBX-TIM-SVIN message on port SPI
const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_SVIN_UART1 = 0x20910098; // Output rate of the UBX-TIM-SVIN message on port UART1 const uint32_t UBLOX_CFG_MSGOUT_UBX_TIM_SVIN_UART1 = 0x20910098; // Output rate of the UBX-TIM-SVIN message on port UART1
@@ -976,6 +988,7 @@ const uint32_t UBLOX_CFG_SPI_ENABLED = 0x10640006; // Flag to indicate if the SP
const uint32_t UBLOX_CFG_SPIINPROT_UBX = 0x10790001; // Flag to indicate if UBX should be an input protocol on SPI const uint32_t UBLOX_CFG_SPIINPROT_UBX = 0x10790001; // Flag to indicate if UBX should be an input protocol on SPI
const uint32_t UBLOX_CFG_SPIINPROT_NMEA = 0x10790002; // Flag to indicate if NMEA should be an input protocol on SPI const uint32_t UBLOX_CFG_SPIINPROT_NMEA = 0x10790002; // Flag to indicate if NMEA should be an input protocol on SPI
const uint32_t UBLOX_CFG_SPIINPROT_RTCM3X = 0x10790004; // Flag to indicate if RTCM3X should be an input protocol on SPI const uint32_t UBLOX_CFG_SPIINPROT_RTCM3X = 0x10790004; // Flag to indicate if RTCM3X should be an input protocol on SPI
const uint32_t UBLOX_CFG_SPIINPROT_SPARTN = 0x10790005; // Flag to indicate if SPARTN should be an input protocol on SPI
//CFG-SPIOUTPROT: Output protocol configuration of the SPI interface //CFG-SPIOUTPROT: Output protocol configuration of the SPI interface
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
@@ -1062,6 +1075,7 @@ const uint32_t UBLOX_CFG_UART1_ENABLED = 0x10520005; // Flag to indicate if the
const uint32_t UBLOX_CFG_UART1INPROT_UBX = 0x10730001; // Flag to indicate if UBX should be an input protocol on UART1 const uint32_t UBLOX_CFG_UART1INPROT_UBX = 0x10730001; // Flag to indicate if UBX should be an input protocol on UART1
const uint32_t UBLOX_CFG_UART1INPROT_NMEA = 0x10730002; // Flag to indicate if NMEA should be an input protocol on UART1 const uint32_t UBLOX_CFG_UART1INPROT_NMEA = 0x10730002; // Flag to indicate if NMEA should be an input protocol on UART1
const uint32_t UBLOX_CFG_UART1INPROT_RTCM3X = 0x10730004; // Flag to indicate if RTCM3X should be an input protocol on UART1 const uint32_t UBLOX_CFG_UART1INPROT_RTCM3X = 0x10730004; // Flag to indicate if RTCM3X should be an input protocol on UART1
const uint32_t UBLOX_CFG_UART1INPROT_SPARTN = 0x10730005; // Flag to indicate if SPARTN should be an input protocol on UART1
//CFG-UART1OUTPROT: Output protocol configuration of the UART1 interface //CFG-UART1OUTPROT: Output protocol configuration of the UART1 interface
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
@@ -1083,6 +1097,7 @@ const uint32_t UBLOX_CFG_UART2_REMAP = 0x10530006; // UART2 Remapping
const uint32_t UBLOX_CFG_UART2INPROT_UBX = 0x10750001; // Flag to indicate if UBX should be an input protocol on UART2 const uint32_t UBLOX_CFG_UART2INPROT_UBX = 0x10750001; // Flag to indicate if UBX should be an input protocol on UART2
const uint32_t UBLOX_CFG_UART2INPROT_NMEA = 0x10750002; // Flag to indicate if NMEA should be an input protocol on UART2 const uint32_t UBLOX_CFG_UART2INPROT_NMEA = 0x10750002; // Flag to indicate if NMEA should be an input protocol on UART2
const uint32_t UBLOX_CFG_UART2INPROT_RTCM3X = 0x10750004; // Flag to indicate if RTCM3X should be an input protocol on UART2 const uint32_t UBLOX_CFG_UART2INPROT_RTCM3X = 0x10750004; // Flag to indicate if RTCM3X should be an input protocol on UART2
const uint32_t UBLOX_CFG_UART2INPROT_SPARTN = 0x10750005; // Flag to indicate if SPARTN should be an input protocol on UART2
//CFG-UART2OUTPROT: Output protocol configuration of the UART2 interface //CFG-UART2OUTPROT: Output protocol configuration of the UART2 interface
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
@@ -1115,6 +1130,7 @@ const uint32_t UBLOX_CFG_USB_SERIAL_NO_STR3 = 0x50650018; // Serial number strin
const uint32_t UBLOX_CFG_USBINPROT_UBX = 0x10770001; // Flag to indicate if UBX should be an input protocol on USB const uint32_t UBLOX_CFG_USBINPROT_UBX = 0x10770001; // Flag to indicate if UBX should be an input protocol on USB
const uint32_t UBLOX_CFG_USBINPROT_NMEA = 0x10770002; // Flag to indicate if NMEA should be an input protocol on USB const uint32_t UBLOX_CFG_USBINPROT_NMEA = 0x10770002; // Flag to indicate if NMEA should be an input protocol on USB
const uint32_t UBLOX_CFG_USBINPROT_RTCM3X = 0x10770004; // Flag to indicate if RTCM3X should be an input protocol on USB const uint32_t UBLOX_CFG_USBINPROT_RTCM3X = 0x10770004; // Flag to indicate if RTCM3X should be an input protocol on USB
const uint32_t UBLOX_CFG_USBINPROT_SPARTN = 0x10770005; // Flag to indicate if SPARTN should be an input protocol on USB
//CFG-USBOUTPROT: Output protocol configuration of the USB interface //CFG-USBOUTPROT: Output protocol configuration of the USB interface
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+222
View File
@@ -753,6 +753,180 @@ typedef struct
UBX_NAV_HPPOSLLH_data_t *callbackData; UBX_NAV_HPPOSLLH_data_t *callbackData;
} UBX_NAV_HPPOSLLH_t; } UBX_NAV_HPPOSLLH_t;
// UBX-NAV-PVAT (0x01 0x17): Navigation position velocity attitude time solution
const uint16_t UBX_NAV_PVAT_LEN = 116;
typedef struct
{
uint32_t iTOW; // GPS time of week of the navigation epoch: ms
uint8_t version; // Message version (0x00 for this version)
union
{
uint8_t all;
struct
{
uint8_t validDate : 1; // 1 = valid UTC Date
uint8_t validTime : 1; // 1 = valid UTC time of day
uint8_t fullyResolved : 1; // 1 = UTC time of day has been fully resolved (no seconds uncertainty).
uint8_t validMag : 1; // 1 = valid magnetic declination
} bits;
} valid;
uint16_t year; // Year (UTC)
uint8_t month; // Month, range 1..12 (UTC)
uint8_t day; // Day of month, range 1..31 (UTC)
uint8_t hour; // Hour of day, range 0..23 (UTC)
uint8_t min; // Minute of hour, range 0..59 (UTC)
uint8_t sec; // Seconds of minute, range 0..60 (UTC)
uint8_t reserved0;
uint8_t reserved1[2];
uint32_t tAcc; // Time accuracy estimate (UTC): ns
int32_t nano; // Fraction of second, range -1e9 .. 1e9 (UTC): ns
uint8_t fixType; // GNSSfix Type:
// 0: no fix
// 1: dead reckoning only
// 2: 2D-fix
// 3: 3D-fix
// 4: GNSS + dead reckoning combined
// 5: time only fix
union
{
uint8_t all;
struct
{
uint8_t gnssFixOK : 1; // 1 = valid fix (i.e within DOP & accuracy masks)
uint8_t diffSoln : 1; // 1 = differential corrections were applied
uint8_t reserved : 1;
uint8_t vehRollValid : 1; // 1 = roll of vehicle is valid, only set if the receiver is in sensor fusion mode
uint8_t vehPitchValid : 1; // 1 = pitch of vehicle is valid, only set if the receiver is in sensor fusion mode
uint8_t vehHeadingValid : 1; // 1 = heading of vehicle is valid, only set if the receiver is in sensor fusion mode
uint8_t carrSoln : 2; // Carrier phase range solution status:
// 0: no carrier phase range solution
// 1: carrier phase range solution with floating ambiguities
// 2: carrier phase range solution with fixed ambiguities
} bits;
} flags;
union
{
uint8_t all;
struct
{
uint8_t reserved : 5;
uint8_t confirmedAvai : 1; // 1 = information about UTC Date and Time of Day validity confirmation is available
uint8_t confirmedDate : 1; // 1 = UTC Date validity could be confirmed
uint8_t confirmedTime : 1; // 1 = UTC Time of Day could be confirmed
} bits;
} flags2;
uint8_t numSV; // Number of satellites used in Nav Solution
int32_t lon; // Longitude: deg * 1e-7
int32_t lat; // Latitude: deg * 1e-7
int32_t height; // Height above ellipsoid: mm
int32_t hMSL; // Height above mean sea level: mm
uint32_t hAcc; // Horizontal accuracy estimate: mm
uint32_t vAcc; // Vertical accuracy estimate: mm
int32_t velN; // NED north velocity: mm/s
int32_t velE; // NED east velocity: mm/s
int32_t velD; // NED down velocity: mm/s
int32_t gSpeed; // Ground Speed (2-D): mm/s
uint32_t sAcc; // Speed accuracy estimate: mm/s
int32_t vehRoll; // Vehicle roll: 1e-5 deg
int32_t vehPitch; // Vehicle pitch: 1e-5 deg
int32_t vehHeading; // Vehicle heading: 1e-5 deg
int32_t motHeading; // Motion heading.: 1e-5 deg
uint16_t accRoll; // Vehicle roll accuracy (if null, roll angle is not available): 1e-2 deg
uint16_t accPitch; // Vehicle pitch accuracy (if null, pitch angle is not available): 1e-2 deg
uint16_t accHeading; // Vehicle heading accuracy (if null, heading angle is not available): 1e-2 deg
int16_t magDec; // Magnetic declination: 1e-2 deg
uint16_t magAcc; // Magnetic declination accuracy: 1e-2 deg
uint16_t errEllipseOrient; // Orientation of semi-major axis of error ellipse (degrees from true north): 1e-2 deg
uint32_t errEllipseMajor; // Semi-major axis of error ellipse: mm
uint32_t errEllipseMinor; // Semi-minor axis of error ellipse: mm
uint8_t reserved2[4];
uint8_t reserved3[4];
} UBX_NAV_PVAT_data_t;
typedef struct
{
union
{
uint32_t all;
struct
{
uint32_t all : 1;
uint32_t iTOW : 1;
uint32_t version : 1;
uint32_t validDate : 1;
uint32_t validTime : 1;
uint32_t fullyResolved : 1;
uint32_t validMag : 1;
uint32_t year : 1;
uint32_t month : 1;
uint32_t day : 1;
uint32_t hour : 1;
uint32_t min : 1;
uint32_t sec : 1;
uint32_t tAcc : 1;
uint32_t nano : 1;
uint32_t fixType : 1;
uint32_t gnssFixOK : 1;
uint32_t diffSoln : 1;
uint32_t vehRollValid : 1;
uint32_t vehPitchValid : 1;
uint32_t vehHeadingValid : 1;
uint32_t carrSoln : 1;
uint32_t confirmedAvai : 1;
uint32_t confirmedDate : 1;
uint32_t confirmedTime : 1;
uint32_t numSV : 1;
uint32_t lon : 1;
uint32_t lat : 1;
uint32_t height : 1;
uint32_t hMSL : 1;
uint32_t hAcc : 1;
uint32_t vAcc : 1;
} bits;
} moduleQueried1;
union
{
uint32_t all;
struct
{
uint32_t velN : 1;
uint32_t velE : 1;
uint32_t velD : 1;
uint32_t gSpeed : 1;
uint32_t sAcc : 1;
uint32_t vehRoll : 1;
uint32_t vehPitch : 1;
uint32_t vehHeading : 1;
uint32_t motHeading : 1;
uint32_t accRoll : 1;
uint32_t accPitch : 1;
uint32_t accHeading : 1;
uint32_t magDec : 1;
uint32_t magAcc : 1;
uint32_t errEllipseOrient : 1;
uint32_t errEllipseMajor : 1;
uint32_t errEllipseMinor : 1;
} bits;
} moduleQueried2;
} UBX_NAV_PVAT_moduleQueried_t;
typedef struct
{
ubxAutomaticFlags automaticFlags;
UBX_NAV_PVAT_data_t data;
UBX_NAV_PVAT_moduleQueried_t moduleQueried;
void (*callbackPointer)(UBX_NAV_PVAT_data_t);
UBX_NAV_PVAT_data_t *callbackData;
} UBX_NAV_PVAT_t;
// UBX-NAV-TIMEUTC (0x01 0x21): UTC time solution // UBX-NAV-TIMEUTC (0x01 0x21): UTC time solution
const uint16_t UBX_NAV_TIMEUTC_LEN = 20; const uint16_t UBX_NAV_TIMEUTC_LEN = 20;
@@ -2058,4 +2232,52 @@ typedef struct
UBX_HNR_INS_data_t *callbackData; UBX_HNR_INS_data_t *callbackData;
} UBX_HNR_INS_t; } UBX_HNR_INS_t;
// NMEA-specific structs
//Additional flags and pointers that need to be stored with each message type
struct nmeaAutomaticFlags
{
union
{
uint8_t all;
struct
{
uint8_t completeCopyValid : 1; // Is the copy of the data struct used by the get function valid/fresh? 0 = invalid, 1 = valid
uint8_t completeCopyRead : 1; // Has the complete copy been read? 0 = unread, 1 = read
uint8_t callbackCopyValid : 1; // Is the copy of the data struct used by the callback valid/fresh? 0 = invalid/stale, 1 = valid/fresh
} bits;
} flags;
};
// The max length for NMEA messages should be 82 bytes, but GGA messages can exceed that if they include the
// extra decimal places for "High Precision Mode".
//
// To be safe, let's allocate 100 bytes to store the GGA message
const uint8_t NMEA_GGA_MAX_LENGTH = 100;
typedef struct
{
uint8_t length; // The number of bytes in nmea
uint8_t nmea[NMEA_GGA_MAX_LENGTH];
} NMEA_GGA_data_t;
typedef struct
{
nmeaAutomaticFlags automaticFlags;
NMEA_GGA_data_t workingCopy; // Incoming data is added to the working copy
NMEA_GGA_data_t completeCopy; // The working copy is copied into the complete copy when all data has been received and the checksum is valid
void (*callbackPointer)(NMEA_GGA_data_t);
NMEA_GGA_data_t *callbackCopy; // The callback gets its own preserved copy of the complete copy
} NMEA_GPGGA_t;
typedef struct
{
nmeaAutomaticFlags automaticFlags;
NMEA_GGA_data_t workingCopy; // Incoming data is added to the working copy
NMEA_GGA_data_t completeCopy; // The working copy is copied into the complete copy when all data has been received and the checksum is valid
void (*callbackPointer)(NMEA_GGA_data_t);
NMEA_GGA_data_t *callbackCopy; // The callback gets its own preserved copy of the complete copy
} NMEA_GNGGA_t;
#endif #endif