Skip to content

pcUpdates #701

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 42 commits into from
Jul 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
aaf8511
Add RTCM1005/1006 parsing - resolves #256 - requires SEMP v1.0.4
PaulZC Jul 15, 2025
2ca5841
Move rtcmParserTable etc. into Tasks.ino. Make table global
PaulZC Jul 16, 2025
6dd3503
Make rtcmData[] and rtcmCount static
PaulZC Jul 16, 2025
46dbdf7
Better ARP log file debug print
PaulZC Jul 16, 2025
2de7f6b
Merge branch 'release_candidate' into pcUpdates
PaulZC Jul 17, 2025
e2df434
Add missing menuPeriodicPrint systemPrints
PaulZC Jul 17, 2025
a7f048a
Add FUNCTION_ARPWRITE
PaulZC Jul 17, 2025
87e6b90
Restructure sdCardPresent
PaulZC Jul 17, 2025
411852a
Protect ntripClient = new NetworkClient();
PaulZC Jul 17, 2025
52e77de
Initialize sdCardSemaphore = NULL
PaulZC Jul 17, 2025
997e405
Sync log file before printing ARP data
PaulZC Jul 17, 2025
05d3da1
Don't record ARP if web server is running
PaulZC Jul 17, 2025
9008125
For SD, write all available data to prevent ARP Write gatecrashing re…
PaulZC Jul 17, 2025
3e1a593
Update required library versions
PaulZC Jul 17, 2025
794fe34
Change default ARP logging interval to 60s
PaulZC Jul 17, 2025
d73180c
Return default ARP logging interval to 10s
PaulZC Jul 18, 2025
5816dc6
Initialize newARPAvailable
PaulZC Jul 18, 2025
4a2e732
Fix that typo!
PaulZC Jul 18, 2025
248ba03
Add ntripClient timeouts:
PaulZC Jul 18, 2025
b2c6be3
Switch to NetworkClient readBytes
PaulZC Jul 18, 2025
8207da4
Update comment
PaulZC Jul 22, 2025
971899b
Correctly handle zero maxLogTime_minutes and maxLogLength_minutes
PaulZC Jul 22, 2025
51526b7
Add comments
PaulZC Jul 22, 2025
8ab22c5
Add inMainMenu check for NTRIP GGA printing
PaulZC Jul 23, 2025
a62eb75
Logging improvements:
PaulZC Jul 23, 2025
f0c8076
Better use of startLogTime_minutes
PaulZC Jul 23, 2025
f19cb6e
Sanity check
PaulZC Jul 23, 2025
82681f7
Update lastUBXLogSyncTime when writing ARP and Events
PaulZC Jul 23, 2025
02be331
Merge branch 'release_candidate' into pcUpdates
PaulZC Jul 23, 2025
e402600
Move Event and ARP logging into handleGnssDataTask
PaulZC Jul 24, 2025
40a17ac
Merge branch 'release_candidate' into pcUpdates
PaulZC Jul 24, 2025
979309d
Remove redundant RTCM parsing
PaulZC Jul 24, 2025
3af1b8f
ringBuffer improvements
PaulZC Jul 25, 2025
f2efc25
More improvements:
PaulZC Jul 26, 2025
1171241
Resolve #695 ???!!!
PaulZC Jul 26, 2025
916a41e
Keep the ntripClient alive by pushing GPGGA when the menu is open
PaulZC Jul 26, 2025
fbb5e71
Update tpISR comment
PaulZC Jul 26, 2025
d66c96d
Add a semaphore for tcpServer - UNTESTED
PaulZC Jul 26, 2025
f520466
Notify incomingSettings wrap-around
PaulZC Jul 27, 2025
56de3d2
Add settings.alignedLogFiles - resolves #630
PaulZC Jul 27, 2025
c7c6377
Add log file alignment to menuLog
PaulZC Jul 27, 2025
d685ba7
Make NTRIP_SERVER_DATA ntripServerArray[] volatile - prevents unneede…
PaulZC Jul 27, 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 .github/workflows/compile-rtk-everywhere.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,12 @@ jobs:
"SparkFun u-blox GNSS v3"@3.1.8
"SparkFun Qwiic OLED Arduino Library"@1.0.13
[email protected]
"SparkFun Extensible Message Parser"@1.0.2
"SparkFun Extensible Message Parser"@1.0.4
"SparkFun BQ40Z50 Battery Manager Arduino Library"@1.0.0
"ArduinoMqttClient"@0.1.8
"SparkFun u-blox PointPerfect Library"@1.11.4
"SparkFun IM19 IMU Arduino Library"@1.0.1
"SparkFun UM980 Triband RTK GNSS Arduino Library"@1.0.4
"SparkFun UM980 Triband RTK GNSS Arduino Library"@1.0.5
"SparkFun LG290P Quadband RTK GNSS Arduino Library"@1.0.8
"SparkFun I2C Expander Arduino Library"@1.0.1

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/non-release-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,13 @@ jobs:
"SparkFun u-blox GNSS v3"@3.1.8
"SparkFun Qwiic OLED Arduino Library"@1.0.13
[email protected]
"SparkFun Extensible Message Parser"@1.0.2
"SparkFun Extensible Message Parser"@1.0.4
"SparkFun BQ40Z50 Battery Manager Arduino Library"@1.0.0
"ArduinoMqttClient"@0.1.8
"SparkFun u-blox PointPerfect Library"@1.11.4
"SparkFun IM19 IMU Arduino Library"@1.0.1
"SparkFun UM980 Triband RTK GNSS Arduino Library"@1.0.4
"SparkFun LG290P Quadband RTK GNSS Arduino Library"@1.0.7
"SparkFun UM980 Triband RTK GNSS Arduino Library"@1.0.5
"SparkFun LG290P Quadband RTK GNSS Arduino Library"@1.0.8
"SparkFun I2C Expander Arduino Library"@1.0.1

- name: Patch libmbedtls
Expand Down
16 changes: 12 additions & 4 deletions Firmware/RTK_Everywhere/AP-Config/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2016,7 +2016,7 @@
<label for="maxLogTime" class="box-margin40 col-sm-3 col-7 col-form-label">Max Logging
Time (min):
<span class="tt" data-bs-placement="right"
title="Once the max log time is achieved, logging will cease. This is useful for limiting long term, overnight, static surveys to a certain length of time. Default: 1440 minutes. Limits: 1 to 2880 minutes.">
title="Once the max log time is achieved, logging will cease. This is useful for limiting long term, overnight, static surveys to a certain length of time. Default: 1440 minutes. Limits: 0 to 1,051,200 minutes. 0 = no limit.">
<span class="icon-info-circle text-primary ms-2"></span>
</span>
</label>
Expand All @@ -2027,15 +2027,23 @@
<div class="form-group row">
<label for="maxLogLength" class="box-margin40 col-sm-3 col-7 col-form-label">Max Log
File Length (min):<span class="tt" data-bs-placement="right"
title="Once this length of time is achieved, a new log will be created. This is useful for creating multiple logs over a long survey. Default: 1440 minutes. Limits: 1 to 2880 minutes.">
title="Once this length of time is achieved, a new log will be created. This is useful for creating multiple logs over a long survey. Default: 1440 minutes. Limits: 0 to 2880 minutes. 0 = no limit.">
<span class="icon-info-circle text-primary ms-2"></span>
</span>
</label>

<input type="number" class="form-control box-small" id="maxLogLength">
<p id="maxLogLengthError" class="inlineError"></p>
</div>

<div class="form-check mt-1 box-margin20">
<label class="form-check-label" for="alignedLogFiles">Aligned Log Files</label>
<input class="form-check-input" type="checkbox" value="" id="alignedLogFiles" unchecked>
<span class="tt" data-bs-placement="right"
title="If enabled, log files will be aligned to the Max Log File Length. Only possible if the Max Log Length is an integral fraction of 24 hours.">
<span class="icon-info-circle text-primary ms-2"></span>
</span>
</div>

<div id="logFile" class="row">
<div class="mb-2">
<label for="logFile" class="form-group box-margin20">Log file name: <span
Expand Down Expand Up @@ -2069,7 +2077,7 @@
<label for="ARPLoggingInterval" class="box-margin40 col-sm-3 col-7 col-form-label">ARP
Logging Interval (s):
<span class="tt" data-bs-placement="right"
title="If ARP logging is enabled, the Antenna Reference Position will be logged at intervals of this many seconds.">
title="If ARP logging is enabled, the Antenna Reference Position will be logged at intervals of this many seconds. Min: 1. Max 600. Default: 10.">
<span class="icon-info-circle text-primary ms-2"></span>
</span>
</label>
Expand Down
4 changes: 2 additions & 2 deletions Firmware/RTK_Everywhere/AP-Config/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -1004,8 +1004,8 @@ function validateFields() {

//System Config
if (ge("enableLogging").checked == true) {
checkElementValue("maxLogTime", 1, 1051200, "Must be 1 to 1,051,200", "collapseSystemConfig");
checkElementValue("maxLogLength", 1, 1051200, "Must be 1 to 1,051,200", "collapseSystemConfig");
checkElementValue("maxLogTime", 0, 1051200, "Must be 0 to 1,051,200", "collapseSystemConfig");
checkElementValue("maxLogLength", 0, 2880, "Must be 0 to 2880", "collapseSystemConfig");
}
else {
clearElement("maxLogTime", 60 * 24);
Expand Down
12 changes: 6 additions & 6 deletions Firmware/RTK_Everywhere/Begin.ino
Original file line number Diff line number Diff line change
Expand Up @@ -843,10 +843,10 @@ void beginSD()

gotSemaphore = false;

while (settings.enableSD == true)
while (settings.enableSD == true) // Note: settings.enableSD is never set to false
{
// Setup SD card access semaphore
if (sdCardSemaphore == nullptr)
if (sdCardSemaphore == NULL)
sdCardSemaphore = xSemaphoreCreateMutex();
else if (xSemaphoreTake(sdCardSemaphore, fatSemaphore_shortWait_ms) != pdPASS)
{
Expand All @@ -862,7 +862,7 @@ void beginSD()
break; // Give up on loop

// If an SD card is present, allow SdFat to take over
log_d("SD card detected");
systemPrintf("SD card detected @ %s\r\n", getTimeStamp());

// Allocate the data structure that manages the microSD card
if (!sd)
Expand Down Expand Up @@ -930,7 +930,7 @@ void beginSD()
sdCardSize = 0;
outOfSDSpace = true;

systemPrintln("microSD: Online");
systemPrintf("microSD: Online @ %s\r\n", getTimeStamp());
online.microSD = true;
break;
}
Expand All @@ -951,7 +951,7 @@ void endSD(bool alreadyHaveSemaphore, bool releaseSemaphore)
sd->end();

online.microSD = false;
systemPrintln("microSD: Offline");
systemPrintf("microSD: Offline @ %s\r\n", getTimeStamp());
}

// Free the caches for the microSD card
Expand Down Expand Up @@ -1699,7 +1699,7 @@ void tpISR()
{
if (online.rtc) // Only sync if the RTC has been set via PVT first
{
if (timTpUpdated) // Only sync if timTpUpdated is true
if (timTpUpdated) // Only sync if timTpUpdated is true - set by storeTIMTPdata on ZED platforms only
{
if (millisNow - lastRTCSync >
syncRTCInterval) // Only sync if it is more than syncRTCInterval since the last sync
Expand Down
2 changes: 1 addition & 1 deletion Firmware/RTK_Everywhere/Buttons.ino
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ void buttonRead()
gpioChanged = false;

// Get all the pins in one read
uint8_t currentState = io.getInputRegister() & 0b00111111; // Ignore unconnected GPIO6/7
uint8_t currentState = io.getInputRegister() & 0b00011111; // Mask the five buttons. Ignore SD detect

if (currentState != gpioExpander_previousState)
{
Expand Down
1 change: 1 addition & 0 deletions Firmware/RTK_Everywhere/ESPNOW.ino
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ void espNowOnDataReceived(const esp_now_recv_info *mac, const uint8_t *incomingD
{
// Pass RTCM bytes (presumably) from ESP NOW out ESP32-UART to GNSS
gnss->pushRawData((uint8_t *)incomingData, len);
sempParseNextBytes(rtcmParse, (uint8_t *)incomingData, len); // Parse the data for RTCM1005/1006

if ((settings.debugEspNow == true || settings.debugCorrections == true) && !inMainMenu)
systemPrintf("ESPNOW received %d RTCM bytes, pushed to GNSS, RSSI: %d\r\n", len, espNowRSSI);
Expand Down
55 changes: 39 additions & 16 deletions Firmware/RTK_Everywhere/GNSS.ino
Original file line number Diff line number Diff line change
Expand Up @@ -72,29 +72,52 @@ bool GNSS::supportsAntennaShortOpen()
}

// Periodically push GGA sentence over NTRIP Client, to Caster, if enabled
void pushGPGGA(char *ggaData)
// We must not push to the Caster while we are reading data from the Caster
// See #695
// pushGPGGA is called by processUart1Message from gnssReadTask
// ntripClient->read is called by ntripClientUpdate and ntripClientResponse from networkUpdate from loop
// We need to make sure processUart1Message doesn't gatecrash
// If ggaData is provided, store it. If ggaData is nullptr, try to push it
static void pushGPGGA(char *ggaData)
{
#ifdef COMPILE_NETWORK
// Wait until the client has been created
if (ntripClient != nullptr)
static char storedGPGGA[100];

static SemaphoreHandle_t reentrant = xSemaphoreCreateMutex(); // Create the mutex

if (xSemaphoreTake(reentrant, 10 / portTICK_PERIOD_MS) == pdPASS)
{
// Provide the caster with our current position as needed
if (ntripClient->connected() && settings.ntripClient_TransmitGGA == true)
if (ggaData)
{
if (millis() - lastGGAPush > NTRIPCLIENT_MS_BETWEEN_GGA)
{
lastGGAPush = millis();
snprintf(storedGPGGA, sizeof(storedGPGGA), "%s", ggaData);
xSemaphoreGive(reentrant);
return;
}

if (settings.debugNtripClientRtcm || PERIODIC_DISPLAY(PD_NTRIP_CLIENT_GGA))
#ifdef COMPILE_NETWORK
// Wait until the client has been created
if (ntripClient != nullptr)
{
// Provide the caster with our current position as needed
if (ntripClient->connected() && settings.ntripClient_TransmitGGA == true)
{
if (millis() - lastGGAPush > NTRIPCLIENT_MS_BETWEEN_GGA)
{
PERIODIC_CLEAR(PD_NTRIP_CLIENT_GGA);
systemPrintf("NTRIP Client pushing GGA to server: %s", (const char *)ggaData);
}
lastGGAPush = millis();

// Push our current GGA sentence to caster
ntripClient->print((const char *)ggaData);
if ((settings.debugNtripClientRtcm || PERIODIC_DISPLAY(PD_NTRIP_CLIENT_GGA)) && !inMainMenu)
{
PERIODIC_CLEAR(PD_NTRIP_CLIENT_GGA);
systemPrintf("NTRIP Client pushing GGA to server: %s", (const char *)storedGPGGA);
}

// Push our current GGA sentence to caster
if (strlen(storedGPGGA) > 0)
ntripClient->write((const uint8_t *)storedGPGGA, strlen(storedGPGGA));
}
}
}
}
#endif // COMPILE_NETWORK

xSemaphoreGive(reentrant);
}
}
28 changes: 0 additions & 28 deletions Firmware/RTK_Everywhere/GNSS_ZED.ino
Original file line number Diff line number Diff line change
Expand Up @@ -542,10 +542,6 @@ bool GNSS_ZED::configureGNSS()
_zed->setAutoPVTcallbackPtr(&storePVTdata, VAL_LAYER_ALL); // Enable automatic NAV PVT messages with callback to storePVTdata
response &= _zed->setAutoHPPOSLLHcallbackPtr(
&storeHPdata, VAL_LAYER_ALL); // Enable automatic NAV HPPOSLLH messages with callback to storeHPdata
_zed->setRTCM1005InputcallbackPtr(
&storeRTCM1005data); // Configure a callback for RTCM 1005 - parsed from pushRawData
_zed->setRTCM1006InputcallbackPtr(
&storeRTCM1006data); // Configure a callback for RTCM 1006 - parsed from pushRawData

if (present.timePulseInterrupt)
response &= _zed->setAutoTIMTPcallbackPtr(
Expand Down Expand Up @@ -2598,30 +2594,6 @@ void GNSS_ZED::storeMONCOMMSdataRadio(UBX_MON_COMMS_data_t *ubxDataStruct)
}
}

//----------------------------------------
// Callback to save ARPECEF*
//----------------------------------------
void storeRTCM1005data(RTCM_1005_data_t *rtcmData1005)
{
ARPECEFX = rtcmData1005->AntennaReferencePointECEFX;
ARPECEFY = rtcmData1005->AntennaReferencePointECEFY;
ARPECEFZ = rtcmData1005->AntennaReferencePointECEFZ;
ARPECEFH = 0;
newARPAvailable = true;
}

//----------------------------------------
// Callback to save ARPECEF*
//----------------------------------------
void storeRTCM1006data(RTCM_1006_data_t *rtcmData1006)
{
ARPECEFX = rtcmData1006->AntennaReferencePointECEFX;
ARPECEFY = rtcmData1006->AntennaReferencePointECEFY;
ARPECEFZ = rtcmData1006->AntennaReferencePointECEFZ;
ARPECEFH = rtcmData1006->AntennaHeight;
newARPAvailable = true;
}

//----------------------------------------
void storeTIMTPdata(UBX_TIM_TP_data_t *ubxDataStruct)
{
Expand Down
6 changes: 6 additions & 0 deletions Firmware/RTK_Everywhere/LoRa.ino
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,9 @@ void updateLora()
// Pass RTCM bytes (presumably) from LoRa out ESP32-UART to GNSS
gnss->pushRawData(rtcmData, rtcmCount); // Push RTCM to GNSS module

// Parse the data for RTCM1005/1006
sempParseNextBytes(rtcmParse, rtcmData, rtcmCount);

if (((settings.debugCorrections == true) || (settings.debugLora == true)) && !inMainMenu)
{
systemFlush(); // Complete prints
Expand Down Expand Up @@ -254,6 +257,9 @@ void updateLora()
// Pass RTCM bytes (presumably) from LoRa out ESP32-UART to GNSS
gnss->pushRawData(rtcmData, rtcmCount); // Push RTCM to GNSS module

// Parse the data for RTCM1005/1006
sempParseNextBytes(rtcmParse, rtcmData, rtcmCount);

if (((settings.debugCorrections == true) || (settings.debugLora == true)) && !inMainMenu)
{
systemFlush(); // Complete prints
Expand Down
2 changes: 2 additions & 0 deletions Firmware/RTK_Everywhere/MQTT_Client.ino
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ int mqttClientProcessZedMessage(uint8_t *mqttData, uint16_t mqttCount, int bytes
zed->updateCorrectionsSource(0); // Set SOURCE to 0 (IP) if needed

gnss->pushRawData(mqttData, mqttCount);
// Corrections are SPARTN. No point in pushing them to rtcmParse
bytesPushed += mqttCount;

mqttClientDataReceived = true;
Expand Down Expand Up @@ -542,6 +543,7 @@ int mqttClientProcessZedMessage(uint8_t *mqttData, uint16_t mqttCount, int bytes
}

gnss->pushRawData(mqttData, mqttCount);
// No point in pushing keys / MGA to rtcmParse
bytesPushed += mqttCount;
}
#endif // COMPILE_ZED
Expand Down
18 changes: 12 additions & 6 deletions Firmware/RTK_Everywhere/NtripClient.ino
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ static const uint32_t NTRIP_CLIENT_RESPONSE_TIMEOUT = 10 * 1000; // Milliseconds
static const uint32_t NTRIP_CLIENT_RECEIVE_DATA_TIMEOUT = 30 * 1000; // Milliseconds

// Most incoming data is around 500 bytes but may be larger
static const int RTCM_DATA_SIZE = 512 * 4;
static const size_t RTCM_DATA_SIZE = 512 * 4;

// NTRIP client server request buffer size
static const int SERVER_BUFFER_SIZE = CREDENTIALS_BUFFER_SIZE + 3;
Expand Down Expand Up @@ -228,7 +228,7 @@ bool ntripClientConnect()
systemPrintf("NTRIP Client connecting to %s:%d\r\n", settings.ntripClient_CasterHost,
settings.ntripClient_CasterPort);

int connectResponse = ntripClient->connect(settings.ntripClient_CasterHost, settings.ntripClient_CasterPort);
int connectResponse = ntripClient->connect(settings.ntripClient_CasterHost, settings.ntripClient_CasterPort, NTRIP_CLIENT_RESPONSE_TIMEOUT);

if (connectResponse < 1)
{
Expand All @@ -248,7 +248,7 @@ bool ntripClientConnect()
length = strlen(serverRequest);
serverRequest[length++] = '\r';
serverRequest[length++] = '\n';
serverRequest[length++] = 0;
serverRequest[length] = 0;

// Set up the credentials
char credentials[CREDENTIALS_BUFFER_SIZE];
Expand Down Expand Up @@ -657,7 +657,8 @@ void ntripClientUpdate()
{
// Allocate the ntripClient structure
networkUseDefaultInterface();
ntripClient = new NetworkClient();
if (!ntripClient)
ntripClient = new NetworkClient();
if (!ntripClient)
{
// Failed to allocate the ntripClient structure
Expand Down Expand Up @@ -803,6 +804,7 @@ void ntripClientUpdate()
// We don't use a task because we use I2C hardware (and don't have a semaphore).
online.ntripClient = true;
ntripClientStartTime = millis();
ntripClient->setConnectionTimeout(NTRIP_CLIENT_RECEIVE_DATA_TIMEOUT);
ntripClientSetState(NTRIP_CLIENT_CONNECTED);
}
}
Expand Down Expand Up @@ -919,9 +921,10 @@ void ntripClientUpdate()
{
// Push RTCM to GNSS module over I2C / SPI
gnss->pushRawData(rtcmData, rtcmCount);
sempParseNextBytes(rtcmParse, rtcmData, rtcmCount); // Parse the data for RTCM1005/1006

if ((settings.debugCorrections || settings.debugNtripClientRtcm ||
PERIODIC_DISPLAY(PD_NTRIP_CLIENT_DATA)) &&
PERIODIC_DISPLAY(PD_NTRIP_CLIENT_DATA)) &&
(!inMainMenu))
{
PERIODIC_CLEAR(PD_NTRIP_CLIENT_DATA);
Expand All @@ -931,7 +934,7 @@ void ntripClientUpdate()
else
{
if ((settings.debugCorrections || settings.debugNtripClientRtcm ||
PERIODIC_DISPLAY(PD_NTRIP_CLIENT_DATA)) &&
PERIODIC_DISPLAY(PD_NTRIP_CLIENT_DATA)) &&
(!inMainMenu))
{
PERIODIC_CLEAR(PD_NTRIP_CLIENT_DATA);
Expand All @@ -943,6 +946,9 @@ void ntripClientUpdate()
}
}
}

// Now that the ntripClient->read is complete, write GPGGA if needed and available. See #695
pushGPGGA(nullptr);
}
break;
}
Expand Down
Loading