Skip to content

Commit 43bb6fa

Browse files
authored
Merge pull request #207 from alonbl/virtual
Convert to polymorphic class
2 parents abffe1a + 4b4ed43 commit 43bb6fa

File tree

3 files changed

+190
-4
lines changed

3 files changed

+190
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
/*
2+
Note: compiles OK with v2.0 but is currently untested
3+
4+
Send UBX binary commands to enable RTCM sentences on u-blox NEO-M8P-2 module
5+
By: Nathan Seidle
6+
SparkFun Electronics
7+
Date: September 7th, 2018
8+
License: MIT. See license file for more information but you can
9+
basically do whatever you want with this code.
10+
11+
This example does all steps to configure and enable a NEO-M8P-2 as a base station:
12+
Begin Survey-In
13+
Once we've achieved 2m accuracy and 300s have passed, survey is complete
14+
Enable four RTCM messages
15+
Begin outputting RTCM bytes
16+
17+
Feel like supporting open source hardware?
18+
Buy a board from SparkFun!
19+
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
20+
NEO-M8P RTK: https://www.sparkfun.com/products/15005
21+
SAM-M8Q: https://www.sparkfun.com/products/15106
22+
23+
Hardware Connections:
24+
Plug a Qwiic cable into the GNSS and a BlackBoard
25+
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
26+
Open the serial monitor at 115200 baud to see the output
27+
*/
28+
29+
#include <Wire.h> //Needed for I2C to GNSS
30+
31+
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
32+
33+
class MY_SFE_UBLOX_GNSS : public SFE_UBLOX_GNSS
34+
{
35+
//This function gets called from the SparkFun u-blox Arduino Library.
36+
//As each RTCM byte comes in you can specify what to do with it
37+
//Useful for passing the RTCM correction data to a radio, Ntrip broadcaster, etc.
38+
virtual void processRTCM_v(uint8_t incoming)
39+
{
40+
//Let's just pretty-print the HEX values for now
41+
if (rtcmFrameCounter % 16 == 0) Serial.println();
42+
Serial.print(F(" "));
43+
if (incoming < 0x10) Serial.print(F("0"));
44+
Serial.print(incoming, HEX);
45+
}
46+
};
47+
48+
MY_SFE_UBLOX_GNSS myGNSS;
49+
50+
void setup()
51+
{
52+
Serial.begin(115200);
53+
while (!Serial); //Wait for user to open terminal
54+
Serial.println(F("u-blox NEO-M8P-2 base station example"));
55+
56+
Wire.begin();
57+
Wire.setClock(400000); //Increase I2C clock speed to 400kHz
58+
59+
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
60+
{
61+
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
62+
while (1);
63+
}
64+
65+
myGNSS.setI2COutput(COM_TYPE_UBX | COM_TYPE_NMEA | COM_TYPE_RTCM3); // Ensure RTCM3 is enabled
66+
myGNSS.saveConfiguration(); //Save the current settings to flash and BBR
67+
68+
while (Serial.available()) Serial.read(); //Clear any latent chars in serial buffer
69+
Serial.println(F("Press any key to send commands to begin Survey-In"));
70+
while (Serial.available() == 0) ; //Wait for user to press a key
71+
72+
bool response;
73+
74+
//Check if Survey is in Progress before initiating one
75+
// From v2.0, the data from getSurveyStatus (UBX-NAV-SVIN) is returned in UBX_NAV_SVIN_t packetUBXNAVSVIN
76+
// Please see u-blox_structs.h for the full definition of UBX_NAV_SVIN_t
77+
// You can either read the data from packetUBXNAVSVIN directly
78+
// or can use the helper functions: getSurveyInActive; getSurveyInValid; getSurveyInObservationTime; and getSurveyInMeanAccuracy
79+
response = myGNSS.getSurveyStatus(2000); //Query module for SVIN status with 2000ms timeout (request can take a long time)
80+
81+
if (response == false) // Check if fresh data was received
82+
{
83+
Serial.println(F("Failed to get Survey In status. Freezing..."));
84+
while (1); //Freeze
85+
}
86+
87+
if (myGNSS.getSurveyInActive() == true) // Use the helper function
88+
{
89+
Serial.print(F("Survey already in progress."));
90+
}
91+
else
92+
{
93+
//Start survey
94+
response = myGNSS.enableSurveyMode(300, 2.000); //Enable Survey in, 300 seconds, 2.0m
95+
if (response == false)
96+
{
97+
Serial.println(F("Survey start failed. Freezing..."));
98+
while (1);
99+
}
100+
Serial.println(F("Survey started. This will run until 300s has passed and less than 2m accuracy is achieved."));
101+
}
102+
103+
while(Serial.available()) Serial.read(); //Clear buffer
104+
105+
//Begin waiting for survey to complete
106+
while (myGNSS.getSurveyInValid() == false) // Call the helper function
107+
{
108+
if(Serial.available())
109+
{
110+
byte incoming = Serial.read();
111+
if(incoming == 'x')
112+
{
113+
//Stop survey mode
114+
response = myGNSS.disableSurveyMode(); //Disable survey
115+
Serial.println(F("Survey stopped"));
116+
break;
117+
}
118+
}
119+
120+
// From v2.0, the data from getSurveyStatus (UBX-NAV-SVIN) is returned in UBX_NAV_SVIN_t packetUBXNAVSVIN
121+
// Please see u-blox_structs.h for the full definition of UBX_NAV_SVIN_t
122+
// You can either read the data from packetUBXNAVSVIN directly
123+
// or can use the helper functions: getSurveyInActive; getSurveyInValid; getSurveyInObservationTime; and getSurveyInMeanAccuracy
124+
response = myGNSS.getSurveyStatus(2000); //Query module for SVIN status with 2000ms timeout (req can take a long time)
125+
if (response == true) // Check if fresh data was received
126+
{
127+
Serial.print(F("Press x to end survey - "));
128+
Serial.print(F("Time elapsed: "));
129+
Serial.print((String)myGNSS.getSurveyInObservationTime());
130+
131+
Serial.print(F(" Accuracy: "));
132+
Serial.print((String)myGNSS.getSurveyInMeanAccuracy());
133+
Serial.println();
134+
}
135+
else
136+
{
137+
Serial.println(F("SVIN request failed"));
138+
}
139+
140+
delay(1000);
141+
}
142+
Serial.println(F("Survey valid!"));
143+
144+
response = true;
145+
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1005, COM_PORT_I2C, 1); //Enable message 1005 to output through I2C port, message every second
146+
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1077, COM_PORT_I2C, 1);
147+
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1087, COM_PORT_I2C, 1);
148+
response &= myGNSS.enableRTCMmessage(UBX_RTCM_1230, COM_PORT_I2C, 10); //Enable message every 10 seconds
149+
150+
if (response == true)
151+
{
152+
Serial.println(F("RTCM messages enabled"));
153+
}
154+
else
155+
{
156+
Serial.println(F("RTCM failed to enable. Are you sure you have an NEO-M8P?"));
157+
while (1); //Freeze
158+
}
159+
160+
Serial.println(F("Base survey complete! RTCM now broadcasting."));
161+
}
162+
163+
void loop()
164+
{
165+
myGNSS.checkUblox(); //See if new data is available. Process bytes as they come in.
166+
167+
delay(250); //Don't pound too hard on the I2C bus
168+
}

Diff for: src/SparkFun_u-blox_GNSS_Arduino_Library.cpp

+18-3
Original file line numberDiff line numberDiff line change
@@ -2288,13 +2288,18 @@ bool SFE_UBLOX_GNSS::processThisNMEA()
22882288
// This is the default or generic NMEA processor. We're only going to pipe the data to serial port so we can see it.
22892289
// User could overwrite this function to pipe characters to nmea.process(c) of tinyGPS or MicroNMEA
22902290
// Or user could pipe each character to a buffer, radio, etc.
2291-
void SFE_UBLOX_GNSS::processNMEA(char incoming)
2291+
void SFE_UBLOX_GNSS::processNMEA_v(char incoming)
22922292
{
22932293
// If user has assigned an output port then pipe the characters there
22942294
if (_nmeaOutputPort != NULL)
22952295
_nmeaOutputPort->write(incoming); // Echo this byte to the serial port
22962296
}
22972297

2298+
void SFE_UBLOX_GNSS::processNMEA(char incoming)
2299+
{
2300+
processNMEA_v(incoming);
2301+
}
2302+
22982303
#ifndef SFE_UBLOX_DISABLE_AUTO_NMEA
22992304
// Check if the NMEA message (in nmeaAddressField) is "auto" (i.e. has RAM allocated for it)
23002305
bool SFE_UBLOX_GNSS::isThisNMEAauto()
@@ -2882,7 +2887,7 @@ nmeaAutomaticFlags *SFE_UBLOX_GNSS::getNMEAFlagsPtr()
28822887
// Byte 2: 10-bits of length of this packet including the first two-ish header bytes, + 6.
28832888
// byte 3 + 4 bits: Msg type 12 bits
28842889
// Example: D3 00 7C 43 F0 ... / 0x7C = 124+6 = 130 bytes in this packet, 0x43F = Msg type 1087
2885-
SFE_UBLOX_GNSS::sfe_ublox_sentence_types_e SFE_UBLOX_GNSS::processRTCMframe(uint8_t incoming, uint16_t *rtcmFrameCounter)
2890+
SFE_UBLOX_GNSS::sfe_ublox_sentence_types_e SFE_UBLOX_GNSS::processRTCMframe_v(uint8_t incoming, uint16_t *rtcmFrameCounter)
28862891
{
28872892
static uint16_t rtcmLen = 0;
28882893

@@ -2912,10 +2917,15 @@ SFE_UBLOX_GNSS::sfe_ublox_sentence_types_e SFE_UBLOX_GNSS::processRTCMframe(uint
29122917
return (*rtcmFrameCounter == rtcmLen) ? SFE_UBLOX_SENTENCE_TYPE_NONE : SFE_UBLOX_SENTENCE_TYPE_RTCM;
29132918
}
29142919

2920+
SFE_UBLOX_GNSS::sfe_ublox_sentence_types_e SFE_UBLOX_GNSS::processRTCMframe(uint8_t incoming, uint16_t *rtcmFrameCounter)
2921+
{
2922+
return processRTCMframe_v(incoming, rtcmFrameCounter);
2923+
}
2924+
29152925
// This function is called for each byte of an RTCM frame
29162926
// Ths user can overwrite this function and process the RTCM frame as they please
29172927
// Bytes can be piped to Serial or other interface. The consumer could be a radio or the internet (Ntrip broadcaster)
2918-
void SFE_UBLOX_GNSS::processRTCM(uint8_t incoming)
2928+
void SFE_UBLOX_GNSS::processRTCM_v(uint8_t incoming)
29192929
{
29202930
// Radio.sendReliable((String)incoming); //An example of passing this byte to a radio
29212931

@@ -2930,6 +2940,11 @@ void SFE_UBLOX_GNSS::processRTCM(uint8_t incoming)
29302940
(void)incoming; // Do something with incoming just to get rid of the pesky compiler warning!
29312941
}
29322942

2943+
void SFE_UBLOX_GNSS::processRTCM(uint8_t incoming)
2944+
{
2945+
processRTCM_v(incoming);
2946+
}
2947+
29332948
// Given a character, file it away into the uxb packet structure
29342949
// Set valid to VALID or NOT_VALID once sentence is completely received and passes or fails CRC
29352950
// The payload portion of the packet can be 100s of bytes but the max array size is packetCfgPayloadSize bytes.

Diff for: src/SparkFun_u-blox_GNSS_Arduino_Library.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,7 @@ class SFE_UBLOX_GNSS
679679
{
680680
public:
681681
SFE_UBLOX_GNSS(void);
682-
~SFE_UBLOX_GNSS(void);
682+
virtual ~SFE_UBLOX_GNSS(void);
683683

684684
// Depending on the sentence type the processor will load characters into different arrays
685685
enum sfe_ublox_sentence_types_e
@@ -783,8 +783,11 @@ class SFE_UBLOX_GNSS
783783

784784
void process(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID); // Processes NMEA and UBX binary sentences one byte at a time
785785
void processNMEA(char incoming) __attribute__((weak)); // Given a NMEA character, do something with it. User can overwrite if desired to use something like tinyGPS or MicroNMEA libraries
786+
virtual void processNMEA_v(char incoming); // Given a NMEA character, do something with it. User can overwrite if desired to use something like tinyGPS or MicroNMEA libraries
786787
sfe_ublox_sentence_types_e processRTCMframe(uint8_t incoming, uint16_t *rtcmFrameCounter) __attribute__((weak)); // Monitor the incoming bytes for start and length bytes
788+
virtual sfe_ublox_sentence_types_e processRTCMframe_v(uint8_t incoming, uint16_t *rtcmFrameCounter); // Monitor the incoming bytes for start and length bytes
787789
void processRTCM(uint8_t incoming) __attribute__((weak)); // Given rtcm byte, do something with it. User can overwrite if desired to pipe bytes to radio, internet, etc.
790+
virtual void processRTCM_v(uint8_t incoming); // Given rtcm byte, do something with it. User can overwrite if desired to pipe bytes to radio, internet, etc.
788791
void processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID); // Given a character, file it away into the uxb packet structure
789792
void processUBXpacket(ubxPacket *msg); // Once a packet has been received and validated, identify this packet's class/id and update internal flags
790793

0 commit comments

Comments
 (0)