Skip to content
This repository was archived by the owner on Jan 28, 2021. It is now read-only.

Commit 4ea5e2a

Browse files
authored
Merge pull request #97 from sparkfun/Experimental_packetBuf
Adding packetBuf. Changing sendCommand. Requested class and ID passing. Please see #97 for full details.
2 parents e71059e + 8ce607c commit 4ea5e2a

File tree

5 files changed

+706
-264
lines changed

5 files changed

+706
-264
lines changed

Diff for: README.md

+6-7
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@ Need a library for the Ublox and Particle? Checkout the [Particle library](https
4444
Repository Contents
4545
-------------------
4646

47-
* **/examples** - Example sketches for the library (.ino). Run these from the Arduino IDE.
47+
* **/examples** - Example sketches for the library (.ino). Run these from the Arduino IDE.
4848
* **/src** - Source files for the library (.cpp, .h).
49-
* **keywords.txt** - Keywords from this library that will be highlighted in the Arduino IDE.
50-
* **library.properties** - General library properties for the Arduino package manager.
49+
* **keywords.txt** - Keywords from this library that will be highlighted in the Arduino IDE.
50+
* **library.properties** - General library properties for the Arduino package manager.
5151

5252
Documentation
5353
--------------
@@ -85,9 +85,9 @@ As an example, assume that the GPS is set to produce 5 navigation
8585
solutions per second and that the sketch only calls getPVT once a second, then the GPS will queue 5
8686
packets in its internal buffer (about 500 bytes) and the library will read those when getPVT is
8787
called, update its internal copy of the nav data 5 times, and return `true` to the sketch. The
88-
skecth calls `getLatitude`, etc. and retrieve the data of the most recent of those 5 packets.
88+
sketch calls `getLatitude`, etc. and retrieve the data of the most recent of those 5 packets.
8989

90-
Products That Use This Library
90+
Products That Use This Library
9191
---------------------------------
9292

9393
* [GPS-15136](https://www.sparkfun.com/products/15136) - SparkFun GPS-RTK2 ZED-F9P
@@ -102,7 +102,7 @@ Products That Use This Library
102102
License Information
103103
-------------------
104104

105-
This product is _**open source**_!
105+
This product is _**open source**_!
106106

107107
Various bits of the code have different licenses applied. Anything SparkFun wrote is beerware; if you see me (or any other SparkFun employee) at the local, and you've found our code helpful, please buy us a round!
108108

@@ -111,4 +111,3 @@ Please use, reuse, and modify these files as you see fit. Please maintain attrib
111111
Distributed as-is; no warranty is given.
112112

113113
- Your friends at SparkFun.
114-

Diff for: Theory.md

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
How I2C (aka DDC) communication works with a uBlox module
22
===========================================================
33

4-
When the user calls one of the methods the library will poll the Ublox module for new data.
4+
When the user calls one of the methods the library will poll the Ublox module for new data.
55

66
* Wait for a minimum of 25 ms between polls (configured dynamically when update rate is set)
77
* Write 0xFD to module
@@ -19,9 +19,14 @@ A method will call **sendCommand()**. This will begin waiting for a response wit
1919

2020
Once **waitForACKResponse()** or **waitForNoACKResponse()** is called the library will start checking the ublox module for new bytes. These bytes may be part of a NMEA sentence, an RTCM sentence, or a UBX packet. The library will file each byte into the appropriate container. Once a given sentence or packet is complete, the appropriate processUBX(), processNMEA() will be called. These functions deal with specific processing for each type.
2121

22-
Note: When interfacing to a ublox module over I2C the **checkUbloxI2C()** will read all bytes currently sitting in the I2C buffer. This may pick up multiple UBX packets. For example, an ACK for a VALSET may be mixed in with an auto-PVT response. We cannot tell **checkUbloxI2C()** to stop once a give ACK is found because we run the risk of leaving bytes in the I2C buffer and loosing them. We don't have this issue with **checkUbloxSerial()**.
22+
Note: When interfacing to a ublox module over I2C **checkUbloxI2C()** will read all bytes currently sitting in the I2C buffer. This may pick up multiple UBX packets. For example, an ACK for a VALSET may be mixed in with an auto-PVT response. We cannot tell **checkUbloxI2C()** to stop once a given ACK is found because we run the risk of leaving bytes in the I2C buffer and losing them. We don't have this issue with **checkUbloxSerial()**.
2323

2424
**processUBX()** will check the CRC of the UBX packet. If validated, the packet will be marked as valid. Once a packet is marked as valid then **processUBXpacket()** is called to extract the contents. This is most commonly used to get the position, velocity, and time (PVT) out of the packet but is also used to check the nature of an ACK packet.
2525

26-
Once a packet has been processed, **waitForACKResponse()/waitForNoACKResponse()** makes the appropriate decision what to do with it. If a packet satisfies the CLS/ID and characteristics of what **waitForACKResponse()/waitForNoACKResponse()** is waiting for, then it returns back to sendCommand. If the packet didn't match or was invalid then **waitForACKResponse()/waitForNoACKResponse()** will continue to wait until the correct packet is received or we time out. **sendCommand()** then returns with true/false depending on the success of **waitForACKResponse()/waitForNoACKResponse()**.
26+
Once a packet has been processed, **waitForACKResponse()/waitForNoACKResponse()** makes the appropriate decision what to do with it. If a packet satisfies the CLS/ID and characteristics of what **waitForACKResponse()/waitForNoACKResponse()** is waiting for, then it returns back to sendCommand. If the packet didn't match or was invalid then **waitForACKResponse()/waitForNoACKResponse()** will continue to wait until the correct packet is received or we time out. **sendCommand()** then returns with a value from the **sfe_ublox_status_e** enum depending on the success of **waitForACKResponse()/waitForNoACKResponse()**.
2727

28+
If we are getting / polling data from the module, **sendCommand()** will return **SFE_UBLOX_STATUS_DATA_RECEIVED** if the get was successful.
29+
30+
If we are setting / writing data to the module, **sendCommand()** will return **SFE_UBLOX_STATUS_DATA_SENT** if the set was successful.
31+
32+
There are circumstances where the library can get the data it is expecting from the module, but it is overwritten (e.g. by an auto-PVT packet) before **sendCommand()** is able to return. In this case, **sendCommand()** will return the error **SFE_UBLOX_STATUS_DATA_OVERWRITTEN**. We should simply call the library function again, but we will need to reset the packet contents first as they will indeed have been overwritten as the error implies.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
Send Custom Command
3+
By: Paul Clark (PaulZC)
4+
Date: April 20th, 2020
5+
6+
License: MIT. See license file for more information but you can
7+
basically do whatever you want with this code.
8+
9+
This example shows how you can create and send a custom UBX packet
10+
using the SparkFun u-blox library.
11+
12+
Previously it was possible to create and send a custom packet
13+
through the library but it would always appear to timeout as
14+
some of the internal functions referred to the internal private
15+
struct packetCfg.
16+
The most recent version of the library allows sendCommand to
17+
use a custom packet as if it were packetCfg and so:
18+
- sendCommand will return a sfe_ublox_status_e enum as if
19+
it had been called from within the library
20+
- the custom packet will be updated with data returned by the module
21+
(previously this was not possible from outside the library)
22+
23+
Feel like supporting open source hardware?
24+
Buy a board from SparkFun!
25+
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
26+
NEO-M8P RTK: https://www.sparkfun.com/products/15005
27+
SAM-M8Q: https://www.sparkfun.com/products/15106
28+
29+
Hardware Connections:
30+
Plug a Qwiic cable into the GPS and a BlackBoard
31+
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
32+
Open the serial monitor at 115200 baud to see the output
33+
*/
34+
35+
#define NAV_RATE 20 // The new navigation rate in Hz (measurements per second)
36+
37+
#include <Wire.h> //Needed for I2C to GPS
38+
39+
#include "SparkFun_Ublox_Arduino_Library.h" //http://librarymanager/All#SparkFun_Ublox_GPS
40+
SFE_UBLOX_GPS myGPS;
41+
42+
void setup()
43+
{
44+
Serial.begin(115200); // You may need to increase this for high navigation rates!
45+
while (!Serial)
46+
; //Wait for user to open terminal
47+
Serial.println("SparkFun Ublox Example");
48+
49+
Wire.begin();
50+
51+
//myGPS.enableDebugging(); // Uncomment this line to enable debug messages
52+
53+
if (myGPS.begin() == false) //Connect to the Ublox module using Wire port
54+
{
55+
Serial.println(F("Ublox GPS not detected at default I2C address. Please check wiring. Freezing."));
56+
while (1)
57+
;
58+
}
59+
60+
myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
61+
62+
// Let's configure the module's navigation rate as if we were using setNavigationFrequency
63+
64+
// Let's create our custom packet
65+
uint8_t customPayload[MAX_PAYLOAD_SIZE]; // This array holds the payload data bytes
66+
// The next line creates and initialises the packet information which wraps around the payload
67+
ubxPacket customCfg = {0, 0, 0, 0, 0, customPayload, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED};
68+
69+
// The structure of ubxPacket is:
70+
// uint8_t cls : The message Class
71+
// uint8_t id : The message ID
72+
// uint16_t len : Length of the payload. Does not include cls, id, or checksum bytes
73+
// uint16_t counter : Keeps track of number of overall bytes received. Some responses are larger than 255 bytes.
74+
// uint16_t startingSpot : The counter value needed to go past before we begin recording into payload array
75+
// uint8_t *payload : The payload
76+
// uint8_t checksumA : Given to us by the module. Checked against the rolling calculated A/B checksums.
77+
// uint8_t checksumB
78+
// sfe_ublox_packet_validity_e valid : Goes from NOT_DEFINED to VALID or NOT_VALID when checksum is checked
79+
// sfe_ublox_packet_validity_e classAndIDmatch : Goes from NOT_DEFINED to VALID or NOT_VALID when the Class and ID match the requestedClass and requestedID
80+
81+
// sendCommand will return:
82+
// SFE_UBLOX_STATUS_DATA_RECEIVED if the data we requested was read / polled successfully
83+
// SFE_UBLOX_STATUS_DATA_SENT if the data we sent was writted successfully (ACK'd)
84+
// Other values indicate errors. Please see the sfe_ublox_status_e enum for further details.
85+
86+
// Referring to the u-blox M8 Receiver Description and Protocol Specification we see that
87+
// the navigation rate is configured using the UBX-CFG-RATE message. So let's load our
88+
// custom packet with the correct information so we can read (poll / get) the current settings.
89+
90+
customCfg.cls = UBX_CLASS_CFG; // This is the message Class
91+
customCfg.id = UBX_CFG_RATE; // This is the message ID
92+
customCfg.len = 0; // Setting the len (length) to zero let's us poll the current settings
93+
customCfg.startingSpot = 0; // Always set the startingSpot to zero (unless you really know what you are doing)
94+
95+
// We also need to tell sendCommand how long it should wait for a reply
96+
uint16_t maxWait = 250; // Wait for up to 250ms (Serial may need a lot longer e.g. 1100)
97+
98+
// Now let's read the current navigation rate. The results will be loaded into customCfg.
99+
if (myGPS.sendCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK
100+
{
101+
Serial.println(F("sendCommand (poll / get) failed! Freezing..."));
102+
while (1)
103+
;
104+
}
105+
106+
// Referring to the message definition for UBX-CFG-RATE we see that the measurement rate
107+
// is stored in payload bytes 0 and 1 as a uint16_t in LSB-first (little endian) format
108+
109+
uint16_t rate = (customPayload[1] << 8) | customPayload[0]; // Extract the current rate (ms)
110+
float f_rate = 1000.0 / ((float)rate); // Convert the navigation rate to Hz (measurements per second)
111+
112+
// Print the current measurement rate
113+
Serial.print(F("The current measurement rate is: "));
114+
Serial.println(f_rate, 1);
115+
116+
// Let's change it
117+
rate = 1000 / NAV_RATE; // Load the new value into rate
118+
customPayload[0] = rate & 0xFF; // Store it in the payload
119+
customPayload[1] = rate >> 8;
120+
121+
// Print the new measurement rate
122+
Serial.print(F("The new measurement rate will be: "));
123+
Serial.println(NAV_RATE);
124+
125+
// We don't need to update customCfg.len as it will have been set to 6
126+
// when sendCommand read the data
127+
128+
// Now we write the custom packet back again to change the setting
129+
if (myGPS.sendCommand(&customCfg, maxWait) != SFE_UBLOX_STATUS_DATA_SENT) // This time we are only expecting an ACK
130+
{
131+
Serial.println(F("sendCommand (set) failed! Freezing."));
132+
while (1)
133+
;
134+
}
135+
else
136+
{
137+
Serial.println(F("Navigation rate updated. Here we go..."));
138+
}
139+
140+
myGPS.setAutoPVT(true); // Enable AutoPVT. The module will generate measurements automatically without being polled.
141+
142+
//myGPS.saveConfigSelective(VAL_CFG_SUBSEC_NAVCONF); //Uncomment this line to save only the NAV settings to flash and BBR
143+
}
144+
145+
void loop()
146+
{
147+
//Query the module as fast as possible
148+
int32_t latitude = myGPS.getLatitude();
149+
Serial.print(F("Lat: "));
150+
Serial.print(latitude);
151+
152+
int32_t longitude = myGPS.getLongitude();
153+
Serial.print(F(" Lon: "));
154+
Serial.print(longitude);
155+
Serial.print(F(" (degrees * 10^-7)"));
156+
157+
int32_t altitude = myGPS.getAltitude();
158+
Serial.print(F(" Alt: "));
159+
Serial.print(altitude);
160+
Serial.println(F(" (mm)"));
161+
}

0 commit comments

Comments
 (0)