Skip to content
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
48ec988
Add pin_debug to help solve the NTRIP Server write stall
PaulZC Nov 21, 2025
34820f9
Add settings.networkClientWriteTimeout_ms and ntripServer->networkCli…
PaulZC Nov 22, 2025
1d6500b
Use semaphore to protect write from connected
PaulZC Nov 23, 2025
affa6f1
Add rtcmConsumerBuffer
PaulZC Nov 23, 2025
e4853e1
Add ntripServerSendRTCM to Developer.ino
PaulZC Nov 23, 2025
43cd008
Update comments
PaulZC Nov 23, 2025
0de67da
More comments
PaulZC Nov 23, 2025
76e99e9
Comment pin_debug for PR
PaulZC Nov 23, 2025
18e2de2
Improve buffersInUse
PaulZC Nov 24, 2025
b95c093
Update Dinger.py - add printLines
PaulZC Nov 24, 2025
2163c37
Move sendRTCMToConsumers() outside ringBufferSemaphore
PaulZC Nov 24, 2025
ddc032b
Move NTRIP_SERVER_DATA into NtripServer.ino
PaulZC Nov 24, 2025
1de1d1f
Remove redundant debugMessagePrefix
PaulZC Nov 24, 2025
0f58126
Correct debugMessagePrefix
PaulZC Nov 24, 2025
d4e188f
Require SEMP v1.0.6
PaulZC Nov 24, 2025
7653d4d
Add ntripServer_CasterEnabled
PaulZC Nov 24, 2025
2785d4a
Merge branch 'release_candidate' into pcUpdates_ntripServer_CasterEna…
PaulZC Nov 25, 2025
21739da
Add ntripServerCasterEnabled to web config
PaulZC Nov 25, 2025
ea8b034
Temporary workaround to prevent crash in bluetoothStop
PaulZC Nov 25, 2025
2132119
Correct logic when NTRIP Server settings change
PaulZC Nov 25, 2025
56aac72
Merge branch 'release_candidate' into pcUpdates_ntripServer_CasterEna…
PaulZC Nov 26, 2025
53d7757
Merge branch 'release_candidate' into pcUpdates_ntripServer_CasterEna…
PaulZC Nov 26, 2025
c350304
Nudge NTRIP Server Enable checkboxes on web config
PaulZC Nov 26, 2025
c17d700
Make rtcmConsumerBufferHead and Tail volatile
PaulZC Nov 26, 2025
0d2877c
Correct createSettingsString for tNSCEn
PaulZC Nov 26, 2025
c2263a2
Web config : handle enableExtCorrRadio
PaulZC Nov 26, 2025
8a73029
Fix compiler warnings
PaulZC Nov 26, 2025
b2f9dfc
Add Base Assist
PaulZC Nov 27, 2025
2552225
Use BaseAsst on 64x48 displays
PaulZC Nov 27, 2025
ba72661
Change the order of SystemState - keep Base contiguous
PaulZC Nov 28, 2025
927dc29
Debug
PaulZC Nov 28, 2025
64b146b
Add RTK_MODE_BASE_UNDECIDED to prevent NTRIP Client starting prematurely
PaulZC Dec 1, 2025
9c644df
Add getGeoidalSeparation
PaulZC Dec 1, 2025
830e080
Move the geoidal separation fix into the GNSS classes
PaulZC Dec 1, 2025
db2e3a8
Revert verbose wifi
PaulZC Dec 1, 2025
d5fdc17
Merge pull request #810 from sparkfun/Add_BaseAssist
PaulZC Dec 1, 2025
84bb8a2
Merge branch 'release_candidate' into pcUpdates_ntripServer_CasterEna…
nseidle Dec 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Firmware/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,12 @@ RUN arduino-cli lib install "SparkFun MAX1704x Fuel Gauge Arduino Library"@1.0.4
RUN arduino-cli lib install "SparkFun u-blox GNSS v3"@3.1.10
RUN arduino-cli lib install "SparkFun Qwiic OLED Arduino Library"@1.0.13
RUN arduino-cli lib install [email protected]
RUN arduino-cli lib install "SparkFun Extensible Message Parser"@1.0.4
RUN arduino-cli lib install "SparkFun Extensible Message Parser"@1.0.6
RUN arduino-cli lib install "SparkFun BQ40Z50 Battery Manager Arduino Library"@1.0.0
RUN arduino-cli lib install "ArduinoMqttClient"@0.1.8
RUN arduino-cli lib install "SparkFun u-blox PointPerfect Library"@1.11.4
RUN arduino-cli lib install "SparkFun IM19 IMU Arduino Library"@1.0.1
RUN arduino-cli lib install "SparkFun UM980 Triband RTK GNSS Arduino Library"@1.0.9
RUN arduino-cli lib install "SparkFun UM980 Triband RTK GNSS Arduino Library"@1.0.10
RUN arduino-cli lib install "SparkFun LG290P Quadband RTK GNSS Arduino Library"@1.0.8
RUN arduino-cli lib install "SparkFun I2C Expander Arduino Library"@1.0.1
RUN arduino-cli lib install "SparkFun Apple Accessory Arduino Library"@3.0.9
Expand Down
20 changes: 20 additions & 0 deletions Firmware/RTK_Everywhere/AP-Config/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,11 @@
<div class="collapse" id="ntripServerConfig0">
<div class="card card-body" style="margin-top:5px;">

<div class="form-check mt-3 mb-2 box-margin20">
<label class="form-check-label" for="ntripServerCasterEnabled_0">Enable</label>
<input class="form-check-input" type="checkbox" value="" id="ntripServerCasterEnabled_0">
</div>

<div class="form-group row">
<label for="ntripServerCasterHost_0"
class="box-margin20 col-sm-3 col-5 col-form-label">Caster
Expand Down Expand Up @@ -976,6 +981,11 @@
<div class="collapse" id="ntripServerConfig1">
<div class="card card-body" style="margin-top:5px;">

<div class="form-check mt-3 mb-2 box-margin20">
<label class="form-check-label" for="ntripServerCasterEnabled_1">Enable</label>
<input class="form-check-input" type="checkbox" value="" id="ntripServerCasterEnabled_1">
</div>

<div class="form-group row">
<label for="ntripServerCasterHost_1"
class="box-margin20 col-sm-3 col-5 col-form-label">Caster
Expand Down Expand Up @@ -1049,6 +1059,11 @@
<div class="collapse" id="ntripServerConfig2">
<div class="card card-body" style="margin-top:5px;">

<div class="form-check mt-3 mb-2 box-margin20">
<label class="form-check-label" for="ntripServerCasterEnabled_2">Enable</label>
<input class="form-check-input" type="checkbox" value="" id="ntripServerCasterEnabled_2">
</div>

<div class="form-group row">
<label for="ntripServerCasterHost_2"
class="box-margin20 col-sm-3 col-5 col-form-label">Caster
Expand Down Expand Up @@ -1122,6 +1137,11 @@
<div class="collapse" id="ntripServerConfig3">
<div class="card card-body" style="margin-top:5px;">

<div class="form-check mt-3 mb-2 box-margin20">
<label class="form-check-label" for="ntripServerCasterEnabled_3">Enable</label>
<input class="form-check-input" type="checkbox" value="" id="ntripServerCasterEnabled_3">
</div>

<div class="form-group row">
<label for="ntripServerCasterHost_3"
class="box-margin20 col-sm-3 col-5 col-form-label">Caster
Expand Down
10 changes: 10 additions & 0 deletions Firmware/RTK_Everywhere/AP-Config/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,16 @@ function parseIncoming(msg) {
ge("antennaHeight_m").value = val / 1000.0;
}

//enableExtCorrRadio should be bool but is sent as uint8_t because it _could_ be 254
else if (id.includes("enableExtCorrRadio")) {
if (val == 0) {
ge(id).checked = false;
}
else {
ge(id).checked = true;
}
}

//Check boxes / radio buttons
else if (val == "true") {
try {
Expand Down
124 changes: 114 additions & 10 deletions Firmware/RTK_Everywhere/Base.ino
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,125 @@
Base.ino
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/

// This function gets called when an RTCM packet passes parser check in processUart1Message() task
// Pass data along to NTRIP Server, or ESP-NOW radio
void processRTCM(uint8_t *rtcmData, uint16_t dataLength)
// Enough storage for two rounds of RTCM 1074,1084,1094,1124,1005
// To help prevent the "no increase in file size" and "due to lack of RTCM" glitch:
// RTCM is stored in PSRAM by the processUart1Message task and written by sendRTCMToConsumers
const uint8_t rtcmConsumerBufferEntries = 16;
const uint16_t rtcmConsumerBufferEntrySize = 1032; // RTCM can be up to 1024 + 6 bytes
uint16_t rtcmConsumerBufferLengths[rtcmConsumerBufferEntries];
volatile uint8_t rtcmConsumerBufferHead;
volatile uint8_t rtcmConsumerBufferTail;
uint8_t *rtcmConsumerBufferPtr = nullptr;

//----------------------------------------
// Allocate and initialize the rtcmConsumerBuffer
//----------------------------------------
bool rtcmConsumerBufferAllocated()
{
// Give this byte to the various possible transmission methods
for (int x = 0; x < dataLength; x++)
if (rtcmConsumerBufferPtr == nullptr)
{
for (int serverIndex = 0; serverIndex < NTRIP_SERVER_MAX; serverIndex++)
ntripServerProcessRTCM(serverIndex, rtcmData[x]);
rtcmConsumerBufferPtr = (uint8_t *)rtkMalloc(
(size_t)rtcmConsumerBufferEntrySize * (size_t)rtcmConsumerBufferEntries,
"ntripBuffer");
for (uint8_t i = 0; i < rtcmConsumerBufferEntries; i++)
rtcmConsumerBufferLengths[i] = 0;
rtcmConsumerBufferHead = 0;
rtcmConsumerBufferTail = 0;
}
if (rtcmConsumerBufferPtr == nullptr)
{
systemPrintln("rtcmConsumerBuffer malloc failed!");
return false;
}

for (int x = 0; x < dataLength; x++)
espNowProcessRTCM(rtcmData[x]);
return true;
}

loraProcessRTCM(rtcmData, dataLength);
//----------------------------------------
// Check how many RTCM buffers contain data
//----------------------------------------
uint8_t rtcmBuffersInUse()
{
if (!rtcmConsumerBufferAllocated())
return 0;

uint8_t buffersInUse = rtcmConsumerBufferHead - rtcmConsumerBufferTail;
if (buffersInUse >= rtcmConsumerBufferEntries) // Wrap if Tail is > Head
buffersInUse += rtcmConsumerBufferEntries;
return buffersInUse;
}

//----------------------------------------
// Check if any RTCM data is available
//----------------------------------------
bool rtcmDataAvailable()
{
return (rtcmBuffersInUse() > 0);
}

//----------------------------------------
// Store each RTCM message in a PSRAM buffer
// This function gets called as each complete RTCM message comes in
// The messages are written to the servers by sendRTCMToConsumers
//----------------------------------------
void storeRTCMForConsumers(uint8_t *rtcmData, uint16_t dataLength)
{
if (!rtcmConsumerBufferAllocated())
return;

// Check if a buffer is available
if (rtcmBuffersInUse() < (rtcmConsumerBufferEntries - 1))
{
uint8_t *dest = rtcmConsumerBufferPtr;
dest += (size_t)rtcmConsumerBufferEntrySize * (size_t)rtcmConsumerBufferHead;
memcpy(dest, rtcmData, dataLength); // Store the RTCM
rtcmConsumerBufferLengths[rtcmConsumerBufferHead] = dataLength; // Store the length
rtcmConsumerBufferHead = rtcmConsumerBufferHead + 1; // Increment the Head
rtcmConsumerBufferHead = rtcmConsumerBufferHead % rtcmConsumerBufferEntries; // Wrap
}
else
{
if (settings.debugNtripServerRtcm && (!inMainMenu))
systemPrintln("rtcmConsumerBuffer full. RTCM lost");
}
}

//----------------------------------------
// Send the stored RTCM to consumers: ntripServer, LoRa and ESP-NOW
//----------------------------------------
void sendRTCMToConsumers()
{
if (!rtcmConsumerBufferAllocated())
return;

while (rtcmConsumerBufferHead != rtcmConsumerBufferTail)
{
uint8_t *dest = rtcmConsumerBufferPtr;
dest += (size_t)rtcmConsumerBufferEntrySize * (size_t)rtcmConsumerBufferTail;

// NTRIP Server
for (int serverIndex = 0; serverIndex < NTRIP_SERVER_MAX; serverIndex++)
ntripServerSendRTCM(serverIndex, dest, rtcmConsumerBufferLengths[rtcmConsumerBufferTail]);

// LoRa
loraProcessRTCM(dest, rtcmConsumerBufferLengths[rtcmConsumerBufferTail]);

// ESP-NOW
for (uint16_t x = 0; x < rtcmConsumerBufferLengths[rtcmConsumerBufferTail]; x++)
espNowProcessRTCM(dest[x]);

rtcmConsumerBufferTail = rtcmConsumerBufferTail + 1; // Increment the Tail
rtcmConsumerBufferTail = rtcmConsumerBufferTail % rtcmConsumerBufferEntries; // Wrap
}
}

//----------------------------------------
// Store data ready to be passed along to NTRIP Server, or ESP-NOW radio
// This function gets called when an RTCM packet passes parser check in processUart1Message() task
//----------------------------------------
void processRTCM(uint8_t *rtcmData, uint16_t dataLength)
{
storeRTCMForConsumers(rtcmData, dataLength);

rtcmLastPacketSent = millis();
rtcmPacketsSent++;
Expand Down
5 changes: 5 additions & 0 deletions Firmware/RTK_Everywhere/Begin.ino
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ void beginBoard()
pin_modeButton = 0;
// 24, D2 : Status LED
pin_baseStatusLED = 2;
//pin_debug = 2; // On EVK we can use the Status LED for debug
// 29, D5 : GNSS TP via 74LVC4066 switch
pin_GNSS_TimePulse = 5;
// 14, D12 : I2C1 SDA via 74LVC4066 switch
Expand Down Expand Up @@ -421,6 +422,10 @@ void beginBoard()
pinMode(pin_baseStatusLED, OUTPUT);
baseStatusLedOff();

DMW_if systemPrintf("pin_debug: %d\r\n", pin_debug);
pinMode(pin_debug, OUTPUT);
pinDebugOff();

DMW_if systemPrintf("pin_Cellular_Network_Indicator: %d\r\n", pin_Cellular_Network_Indicator);
pinMode(pin_Cellular_Network_Indicator, INPUT);

Expand Down
8 changes: 4 additions & 4 deletions Firmware/RTK_Everywhere/Bluetooth.ino
Original file line number Diff line number Diff line change
Expand Up @@ -742,13 +742,13 @@ void bluetoothStop()
{
bluetoothSerialBle->flush(); // Complete any transfers
bluetoothSerialBle->disconnect(); // Drop any clients
bluetoothSerialBle->end(); // Release resources
//bluetoothSerialBle->end(); // Release resources : causes FreeRTOS Task "BLEFlushTask_" should not return, Aborting now!
//delete bluetoothSerialBle;
//bluetoothSerialBle = nullptr;

bluetoothSerialBleCommands->flush(); // Complete any transfers
bluetoothSerialBleCommands->disconnect(); // Drop any clients
bluetoothSerialBleCommands->end(); // Release resources
//bluetoothSerialBleCommands->end(); // Release resources : causes FreeRTOS Task "BLEFlushTask_" should not return, Aborting now!
//delete bluetoothSerialBleCommands;
//bluetoothSerialBleCommands = nullptr;

Expand Down Expand Up @@ -776,13 +776,13 @@ void bluetoothStop()
{
bluetoothSerialBle->flush(); // Complete any transfers
bluetoothSerialBle->disconnect(); // Drop any clients
bluetoothSerialBle->end(); // Release resources
//bluetoothSerialBle->end(); // Release resources : FreeRTOS Task "BLEFlushTask_" should not return, Aborting now!
//delete bluetoothSerialBle;
//bluetoothSerialBle = nullptr;

bluetoothSerialBleCommands->flush(); // Complete any transfers
bluetoothSerialBleCommands->disconnect(); // Drop any clients
bluetoothSerialBleCommands->end(); // Release resources
//bluetoothSerialBleCommands->end(); // Release resources : FreeRTOS Task "BLEFlushTask_" should not return, Aborting now!
//delete bluetoothSerialBleCommands;
//bluetoothSerialBleCommands = nullptr;

Expand Down
3 changes: 2 additions & 1 deletion Firmware/RTK_Everywhere/Developer.ino
Original file line number Diff line number Diff line change
Expand Up @@ -238,10 +238,11 @@ void ntripClientSettingsChanged() {}
#ifndef COMPILE_NTRIP_SERVER
bool ntripServerIsCasting(int serverIndex) {return false;}
void ntripServerPrintStatus(int serverIndex) {systemPrintf("**NTRIP Server %d not compiled**\r\n", serverIndex);}
void ntripServerProcessRTCM(int serverIndex, uint8_t incoming) {}
void ntripServerSendRTCM(int serverIndex, uint8_t *rtcmData, uint16_t dataLength) {}
void ntripServerStop(int serverIndex, bool shutdown) {online.ntripServer[serverIndex] = false;}
void ntripServerUpdate() {}
void ntripServerValidateTables() {}
void ntripServerSettingsChanged(int serverIndex) {}
#endif // COMPILE_NTRIP_SERVER

//----------------------------------------
Expand Down
2 changes: 2 additions & 0 deletions Firmware/RTK_Everywhere/Display.ino
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ void displayUpdate()
break;

case (STATE_BASE_CASTER_NOT_STARTED):
case (STATE_BASE_ASSIST_NOT_STARTED):
case (STATE_BASE_NOT_STARTED):
case (STATE_BASE_CONFIG_WAIT):
displayBaseStart(0); // Show 'Base' while the system configures the Base
Expand Down Expand Up @@ -1281,6 +1282,7 @@ void setModeIcon(std::vector<iconPropertyBlinking> *iconList)
break;

case (STATE_BASE_CASTER_NOT_STARTED):
case (STATE_BASE_ASSIST_NOT_STARTED):
case (STATE_BASE_NOT_STARTED):
case (STATE_BASE_CONFIG_WAIT):
// Do nothing. Static display shown during state change.
Expand Down
6 changes: 5 additions & 1 deletion Firmware/RTK_Everywhere/GNSS.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ typedef enum
class GNSS
{
protected:
float _altitude; // Altitude in meters
double _altitude; // Altitude in meters
double _geoidalSeparation; // Geoidal separation in meters
float _horizontalAccuracy; // Horizontal position accuracy in meters
double _latitude; // Latitude in degrees
double _longitude; // Longitude in degrees
Expand Down Expand Up @@ -166,6 +167,9 @@ class GNSS
// Returns the fix type or zero if not online
virtual uint8_t getFixType();

// Returns the geoidal separation
virtual double getGeoidalSeparation();

// Returns the hours of 24 hour clock or zero if not online
virtual uint8_t getHour();

Expand Down
3 changes: 3 additions & 0 deletions Firmware/RTK_Everywhere/GNSS_LG290P.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,9 @@ class GNSS_LG290P : GNSS
// Returns the fix type or zero if not online
uint8_t getFixType();

// Returns the geoidal separation
double getGeoidalSeparation();

// Returns the hours of 24 hour clock or zero if not online
uint8_t getHour();

Expand Down
15 changes: 14 additions & 1 deletion Firmware/RTK_Everywhere/GNSS_LG290P.ino
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,10 @@ uint8_t GNSS_LG290P::getActiveRtcmMessageCount()
double GNSS_LG290P::getAltitude()
{
if (online.gnss)
return (_lg290p->getAltitude());
// See issue #809
// getAltitude returns the Altitude above mean sea level (meters)
// For Height above Ellipsoid, we need to add the the geoidalSeparation
return (_lg290p->getAltitude() + _lg290p->getGeoidalSeparation());
return (0);
}

Expand Down Expand Up @@ -829,6 +832,16 @@ uint8_t GNSS_LG290P::getFixType()
return 0;
}

//----------------------------------------
// Returns the geoidal separation in meters or zero if the GNSS is offline
//----------------------------------------
double GNSS_LG290P::getGeoidalSeparation()
{
if (online.gnss)
return (_lg290p->getGeoidalSeparation());
return (0);
}

//----------------------------------------
// Get the horizontal position accuracy
// Returns the horizontal position accuracy or zero if offline
Expand Down
3 changes: 3 additions & 0 deletions Firmware/RTK_Everywhere/GNSS_Mosaic.h
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,9 @@ class GNSS_MOSAIC : GNSS
// Returns the fix type or zero if not online
uint8_t getFixType();

// Returns the geoidal separation
double getGeoidalSeparation();

// Returns the hours of 24 hour clock or zero if not online
uint8_t getHour();

Expand Down
13 changes: 12 additions & 1 deletion Firmware/RTK_Everywhere/GNSS_Mosaic.ino
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,8 @@ uint8_t GNSS_MOSAIC::getActiveMessageCount()
//----------------------------------------
double GNSS_MOSAIC::getAltitude()
{
// _altitude contains the Ellipsoidal height (meters) from SBF Block 4007
// We don't need to adjust for the Geoidal Separation (Undulation)
return _altitude;
}

Expand Down Expand Up @@ -952,6 +954,14 @@ uint8_t GNSS_MOSAIC::getFixType()
return _fixType;
}

//----------------------------------------
// Returns the geoidal separation in meters or zero if the GNSS is offline
//----------------------------------------
double GNSS_MOSAIC::getGeoidalSeparation()
{
return _geoidalSeparation;
}

//----------------------------------------
// Returns the hours of 24 hour clock or zero if not online
//----------------------------------------
Expand Down Expand Up @@ -2527,7 +2537,8 @@ void GNSS_MOSAIC::storeBlock4007(SEMP_PARSE_STATE *parse)
{
_latitude = sempSbfGetF8(parse, 16) * 180.0 / PI; // Convert from radians to degrees
_longitude = sempSbfGetF8(parse, 24) * 180.0 / PI;
_altitude = (float)sempSbfGetF8(parse, 32);
_altitude = sempSbfGetF8(parse, 32); // Ellipsoidal height
_geoidalSeparation = (double)sempSbfGetF4(parse, 40); // Geoid undulation
_horizontalAccuracy = ((float)sempSbfGetU2(parse, 90)) / 100.0; // Convert from cm to m

// NrSV is the total number of satellites used in the PVT computation.
Expand Down
Loading