@@ -14,113 +14,116 @@ bool configureUbloxModuleBase()
1414 firstPowerOn = false ; // If we switch between rover/base in the future, force config of module.
1515
1616 theGNSS.checkUblox (); // Regularly poll to get latest data and any RTCM
17+ theGNSS.checkCallbacks (); // Process any callbacks: ie, storePVTdata
1718
1819 theGNSS.setNMEAGPGGAcallbackPtr (nullptr ); // Disable GPGGA call back that may have been set during Rover NTRIP Client mode
1920
20- bool response = true ;
21+ bool success = false ;
22+ int tryNo = -1 ;
2123
22- // In Base mode we force 1Hz
23- response &= theGNSS.newCfgValset ();
24- response &= theGNSS.addCfgValset (UBLOX_CFG_RATE_MEAS, 1000 );
25- response &= theGNSS.addCfgValset (UBLOX_CFG_RATE_NAV, 1 );
26-
27- // Since we are at 1Hz, allow GSV NMEA to be reported at whatever the user has chosen
28- response &= theGNSS.addCfgValset (settings.ubxMessages [8 ].msgConfigKey , settings.ubxMessages [8 ].msgRate ); // Update rate on module
29-
30- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_NMEA_ID_GGA_I2C, 0 ); // Disable NMEA message that may have been set during Rover NTRIP Client mode
31-
32- // Survey mode is only available on ZED-F9P modules
33- if (zedModuleType == PLATFORM_F9P)
34- response &= theGNSS.addCfgValset (UBLOX_CFG_TMODE_MODE, 0 ); // Disable survey-in mode
35-
36- response &= theGNSS.addCfgValset (UBLOX_CFG_NAVSPG_DYNMODEL, (dynModel)settings.dynamicModel ); // Set dynamic model
37-
38- // RTCM is only available on ZED-F9P modules
39- //
40- // For most RTK products, the GNSS is interfaced via both I2C and UART1. Configuration and PVT/HPPOS messages are
41- // configured over I2C. Any messages that need to be logged are output on UART1, and received by this code using
42- // serialGNSS.
43- // In base mode the RTK device should output RTCM over all ports:
44- // (Primary) UART2 in case the Surveyor is connected via radio to rover
45- // (Optional) I2C in case user wants base to connect to WiFi and NTRIP Caster
46- // (Seconday) USB in case the Surveyor is used as an NTRIP caster connected to SBC or other
47- // (Tertiary) UART1 in case Surveyor is sending RTCM to phone that is then NTRIP Caster
48- //
49- // But, on the Reference Station, the GNSS is interfaced via SPI. It has no access to I2C and UART1.
50- // We use the GNSS library's built-in logging buffer to mimic UART1. The code in Tasks.ino reads
51- // data from the logging buffer as if it had come from UART1.
52- // So for that product - in Base mode - we can only output RTCM on SPI, USB and UART2.
53- // If we want to log the RTCM messages, we need to add them to the logging buffer inside the GNSS library.
54- // If we want to pass them along to (e.g.) radio, we do that using processRTCM (defined below).
55-
56- if (USE_I2C_GNSS)
57- {
58- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1005_I2C, 1 );
59- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1074_I2C, 1 );
60- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1084_I2C, 1 );
61- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1094_I2C, 1 );
62- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1124_I2C, 1 );
63- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1230_I2C, 10 ); // Enable message every 10 cycles - note: this may conflict with settings and setMessages?
64-
65- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1005_UART1, 1 );
66- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1074_UART1, 1 );
67- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1084_UART1, 1 );
68- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1094_UART1, 1 );
69- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1124_UART1, 1 );
70- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1230_UART1, 10 );
71- }
72- else // SPI GNSS
24+ // Try up to MAX_SET_MESSAGES_RETRIES times to configure the GNSS
25+ // This corrects occasional failures seen on the Reference Station where the GNSS is connected via SPI
26+ // instead of I2C and UART1. I believe the SETVAL ACK is occasionally missed due to the level of messages being processed.
27+ while ((++tryNo < MAX_SET_MESSAGES_RETRIES) && !success)
7328 {
74- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1005_SPI, 1 );
75- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1074_SPI, 1 );
76- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1084_SPI, 1 );
77- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1094_SPI, 1 );
78- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1124_SPI, 1 );
79- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1230_SPI, 10 ); // Enable message every 10 cycles - note: this may conflict with settings and setMessages?
80-
81- // Enable logging of these messages so the RTCM will be stored automatically in the logging buffer.
82- // This mimics the data arriving via UART1.
83- uint32_t logRTCMMessages = theGNSS.getRTCMLoggingMask ();
84- logRTCMMessages |= ( SFE_UBLOX_FILTER_RTCM_TYPE1005 | SFE_UBLOX_FILTER_RTCM_TYPE1074 | SFE_UBLOX_FILTER_RTCM_TYPE1084
85- | SFE_UBLOX_FILTER_RTCM_TYPE1094 | SFE_UBLOX_FILTER_RTCM_TYPE1124 | SFE_UBLOX_FILTER_RTCM_TYPE1230 );
86- theGNSS.setRTCMLoggingMask (logRTCMMessages);
87- log_d (" setRTCMLoggingMask 0x%X" , logRTCMMessages);
88-
89- // Update settings, otherwise setMessages could disable these again...
90- for (int x = 0 ; x < MAX_UBX_MSG; x++)
29+ bool response = true ;
30+
31+ // In Base mode we force 1Hz
32+ response &= theGNSS.newCfgValset ();
33+ response &= theGNSS.addCfgValset (UBLOX_CFG_RATE_MEAS, 1000 );
34+ response &= theGNSS.addCfgValset (UBLOX_CFG_RATE_NAV, 1 );
35+
36+ // Since we are at 1Hz, allow GSV NMEA to be reported at whatever the user has chosen
37+ uint32_t spiOffset = 0 ; // Set to 3 if using SPI to convert UART1 keys to SPI. This is brittle and non-perfect, but works.
38+ if (USE_SPI_GNSS)
39+ spiOffset = 3 ;
40+ response &= theGNSS.addCfgValset (ubxMessages[8 ].msgConfigKey + spiOffset, settings.ubxMessageRates [8 ]); // Update rate on module
41+
42+ if (USE_I2C_GNSS)
43+ response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_NMEA_ID_GGA_I2C, 0 ); // Disable NMEA message that may have been set during Rover NTRIP Client mode
44+
45+ // Survey mode is only available on ZED-F9P modules
46+ if (commandSupported (UBLOX_CFG_TMODE_MODE) == true )
47+ response &= theGNSS.addCfgValset (UBLOX_CFG_TMODE_MODE, 0 ); // Disable survey-in mode
48+
49+ // Note that using UBX-CFG-TMODE3 to set the receiver mode to Survey In or to Fixed Mode, will set
50+ // automatically the dynamic platform model (CFG-NAVSPG-DYNMODEL) to Stationary.
51+ // response &= theGNSS.addCfgValset(UBLOX_CFG_NAVSPG_DYNMODEL, (dynModel)settings.dynamicModel); //Not needed
52+
53+ // RTCM is only available on ZED-F9P modules
54+ //
55+ // For most RTK products, the GNSS is interfaced via both I2C and UART1. Configuration and PVT/HPPOS messages are
56+ // configured over I2C. Any messages that need to be logged are output on UART1, and received by this code using
57+ // serialGNSS.
58+ // In base mode the RTK device should output RTCM over all ports:
59+ // (Primary) UART2 in case the Surveyor is connected via radio to rover
60+ // (Optional) I2C in case user wants base to connect to WiFi and NTRIP Caster
61+ // (Seconday) USB in case the Surveyor is used as an NTRIP caster connected to SBC or other
62+ // (Tertiary) UART1 in case Surveyor is sending RTCM to phone that is then NTRIP Caster
63+ //
64+ // But, on the Reference Station, the GNSS is interfaced via SPI. It has no access to I2C and UART1.
65+ // We use the GNSS library's built-in logging buffer to mimic UART1. The code in Tasks.ino reads
66+ // data from the logging buffer as if it had come from UART1.
67+ // So for that product - in Base mode - we can only output RTCM on SPI, USB and UART2.
68+ // If we want to log the RTCM messages, we need to add them to the logging buffer inside the GNSS library.
69+ // If we want to pass them along to (e.g.) radio, we do that using processRTCM (defined below).
70+
71+ // Find first RTCM record in ubxMessage array
72+ int firstRTCMRecord = getMessageNumberByName (" UBX_RTCM_1005" );
73+
74+ // ubxMessageRatesBase is an array of ~12 uint8_ts
75+ // ubxMessage is an array of ~80 messages
76+ // We use firstRTCMRecord as an offset for the keys, but use x as the rate
77+
78+ if (USE_I2C_GNSS)
9179 {
92- if (settings. ubxMessages [x]. msgClass == UBX_RTCM_MSB) // RTCM messages
80+ for ( int x = 0 ; x < MAX_UBX_MSG_RTCM; x++)
9381 {
94- if (settings.ubxMessages [x].filterMask & // This is quicker than checking the msgID
95- ( SFE_UBLOX_FILTER_RTCM_TYPE1005 | SFE_UBLOX_FILTER_RTCM_TYPE1074 | SFE_UBLOX_FILTER_RTCM_TYPE1084
96- | SFE_UBLOX_FILTER_RTCM_TYPE1094 | SFE_UBLOX_FILTER_RTCM_TYPE1124))
97- settings.ubxMessages [x].msgRate = 1 ;
98- if (settings.ubxMessages [x].filterMask & SFE_UBLOX_FILTER_RTCM_TYPE1230)
99- settings.ubxMessages [x].msgRate = 10 ;
82+ response &= theGNSS.addCfgValset (ubxMessages[firstRTCMRecord + x].msgConfigKey - 1 , settings.ubxMessageRatesBase [x]); // UBLOX_CFG UART1 - 1 = I2C
83+ response &= theGNSS.addCfgValset (ubxMessages[firstRTCMRecord + x].msgConfigKey , settings.ubxMessageRatesBase [x]); // UBLOX_CFG UART1
84+
85+ // Disable messages on SPI
86+ response &= theGNSS.addCfgValset (ubxMessages[firstRTCMRecord + x].msgConfigKey + 3 , 0 ); // UBLOX_CFG UART1 + 3 = SPI
10087 }
10188 }
102- }
89+ else // SPI GNSS
90+ {
91+ for (int x = 0 ; x < MAX_UBX_MSG_RTCM; x++)
92+ {
93+ response &= theGNSS.addCfgValset (ubxMessages[firstRTCMRecord + x].msgConfigKey + 3 , settings.ubxMessageRatesBase [x]); // UBLOX_CFG UART1 + 3 = SPI
10394
104- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1005_USB, 1 );
105- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1074_USB, 1 );
106- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1084_USB, 1 );
107- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1094_USB, 1 );
108- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1124_USB, 1 );
109- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1230_USB, 10 );
95+ // Disable messages on I2C and UART1
96+ response &= theGNSS.addCfgValset (ubxMessages[firstRTCMRecord + x].msgConfigKey - 1 , 0 ); // UBLOX_CFG UART1 - 1 = I2C
97+ response &= theGNSS.addCfgValset (ubxMessages[firstRTCMRecord + x].msgConfigKey , 0 ); // UBLOX_CFG UART1
98+ }
11099
111- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1005_UART2, 1 );
112- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1074_UART2, 1 );
113- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1084_UART2, 1 );
114- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1094_UART2, 1 );
115- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1124_UART2, 1 );
116- response &= theGNSS.addCfgValset (UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1230_UART2, 10 );
100+ // Enable logging of these messages so the RTCM will be stored automatically in the logging buffer.
101+ // This mimics the data arriving via UART1.
102+ uint32_t logRTCMMessages = theGNSS.getRTCMLoggingMask ();
103+ logRTCMMessages |= ( SFE_UBLOX_FILTER_RTCM_TYPE1005 | SFE_UBLOX_FILTER_RTCM_TYPE1074 | SFE_UBLOX_FILTER_RTCM_TYPE1084
104+ | SFE_UBLOX_FILTER_RTCM_TYPE1094 | SFE_UBLOX_FILTER_RTCM_TYPE1124 | SFE_UBLOX_FILTER_RTCM_TYPE1230 );
105+ theGNSS.setRTCMLoggingMask (logRTCMMessages);
106+ }
117107
118- response &= theGNSS.sendCfgValset (); // Closing value - #31
108+ // Update message rates for UART2 and USB
109+ for (int x = 0 ; x < MAX_UBX_MSG_RTCM; x++)
110+ {
111+ response &= theGNSS.addCfgValset (ubxMessages[firstRTCMRecord + x].msgConfigKey + 1 , settings.ubxMessageRatesBase [x]); // UBLOX_CFG UART1 + 1 = UART2
112+ response &= theGNSS.addCfgValset (ubxMessages[firstRTCMRecord + x].msgConfigKey + 2 , settings.ubxMessageRatesBase [x]); // UBLOX_CFG UART1 + 2 = USB
113+ }
119114
120- if (response == false )
115+ response &= theGNSS.addCfgValset (UBLOX_CFG_NAVSPG_INFIL_MINELEV, settings.minElev ); // Set minimum elevation
116+
117+ response &= theGNSS.sendCfgValset (); // Closing value
118+
119+ if (response)
120+ success = true ;
121+ }
122+
123+ if (!success)
121124 systemPrintln (" Base config fail" );
122125
123- return (response );
126+ return (success );
124127}
125128
126129// Start survey
@@ -140,9 +143,15 @@ bool surveyInStart()
140143
141144 if (surveyInReset () == false )
142145 {
143- systemPrintln (" Survey reset failed" );
146+ systemPrintln (" Survey reset failed - attempt 1/3 " );
144147 if (surveyInReset () == false )
145- systemPrintln (" Survey reset failed - 2nd attempt" );
148+ {
149+ systemPrintln (" Survey reset failed - attempt 2/3" );
150+ if (surveyInReset () == false )
151+ {
152+ systemPrintln (" Survey reset failed - attempt 3/3" );
153+ }
154+ }
146155 }
147156 }
148157
@@ -158,9 +167,9 @@ bool surveyInStart()
158167 }
159168
160169 systemPrintf (" Survey started. This will run until %d seconds have passed and less than %0.03f meter accuracy is achieved.\r\n " ,
161- settings.observationSeconds ,
162- settings.observationPositionAccuracy
163- );
170+ settings.observationSeconds ,
171+ settings.observationPositionAccuracy
172+ );
164173
165174 // Wait until active becomes true
166175 long maxTime = 5000 ;
@@ -291,6 +300,13 @@ bool startFixedBase()
291300// Useful for passing the RTCM correction data to a radio, Ntrip broadcaster, etc.
292301void DevUBLOXGNSS::processRTCM (uint8_t incoming)
293302{
303+ // We need to prevent ntripServerProcessRTCM from writing data via Ethernet (SPI W5500)
304+ // during an SPI checkUbloxSpi...
305+ // We can pass incoming to ntripServerProcessRTCM if the GNSS is I2C or the variant does not have Ethernet.
306+ // For the Ref Stn, processRTCMBuffer is called manually from inside ntripServerUpdate
307+ if ((USE_SPI_GNSS) && (HAS_ETHERNET))
308+ return ;
309+
294310 // Check for too many digits
295311 if (settings.enableResetDisplay == true )
296312 {
@@ -318,3 +334,44 @@ void DevUBLOXGNSS::processRTCM(uint8_t incoming)
318334 espnowProcessRTCM (incoming);
319335 }
320336}
337+
338+ // For Ref Stn (USE_SPI_GNSS and HAS_ETHERNET), call ntripServerProcessRTCM manually if there is RTCM data in the buffer
339+ void processRTCMBuffer ()
340+ {
341+ if ((USE_I2C_GNSS) || (!HAS_ETHERNET))
342+ return ;
343+
344+ // Check if there is any data waiting in the RTCM buffer
345+ uint16_t rtcmBytesAvail = theGNSS.rtcmBufferAvailable ();
346+ if (rtcmBytesAvail > 0 )
347+ {
348+ // Check for too many digits
349+ if (settings.enableResetDisplay == true )
350+ {
351+ if (rtcmPacketsSent > 99 ) rtcmPacketsSent = 1 ; // Trim to two digits to avoid overlap
352+ }
353+ else
354+ {
355+ if (rtcmPacketsSent > 999 ) rtcmPacketsSent = 1 ; // Trim to three digits to avoid log icon and increasing bar
356+ }
357+
358+ while (rtcmBytesAvail > 0 )
359+ {
360+ uint8_t incoming;
361+
362+ if (theGNSS.extractRTCMBufferData (&incoming, 1 ) != 1 )
363+ return ;
364+
365+ rtcmBytesAvail--;
366+
367+ // Data in the u-blox library RTCM buffer is pre-checked. We don't need to check it again here.
368+
369+ rtcmLastReceived = millis ();
370+ rtcmBytesSent++;
371+
372+ ntripServerProcessRTCM (incoming);
373+
374+ espnowProcessRTCM (incoming);
375+ }
376+ }
377+ }
0 commit comments