Skip to content

Commit d72e1ff

Browse files
committed
Merge branch 'release_candidate' into pcUpdates
2 parents 644847b + c9789f8 commit d72e1ff

File tree

17 files changed

+2431
-2273
lines changed

17 files changed

+2431
-2273
lines changed

Firmware/RTK_Everywhere/AP-Config/index.html

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -362,16 +362,18 @@
362362
<span class="icon-info-circle text-primary ms-2"></span>
363363
</span>
364364
</div>
365-
<div class="form-group row">
366-
<label for="configurePPP" class="box-margin20 col-sm-3 col-5 col-form-label">Configure PPP:
367-
<span class="tt" data-bs-placement="right"
368-
title="The configuration string for PPP. Enter values separated by spaces, not commas. Default: 2 1 120 0.10 0.15">
369-
<span class="icon-info-circle text-primary ms-2"></span>
370-
</span>
371-
</label>
372-
<div class="col-sm-8 col-6">
373-
<input type="text" class="form-control" id="configurePPP">
374-
<p id="configurePPPError" class="inlineError"></p>
365+
<div id="configurePppSetting">
366+
<div class="form-group row">
367+
<label for="configurePPP" class="box-margin20 col-sm-3 col-5 col-form-label">Configure PPP:
368+
<span class="tt" data-bs-placement="right"
369+
title="The configuration string for PPP. Enter values separated by spaces, not commas. Default: 2 1 120 0.10 0.15">
370+
<span class="icon-info-circle text-primary ms-2"></span>
371+
</span>
372+
</label>
373+
<div class="col-sm-8 col-6">
374+
<input type="text" class="form-control" id="configurePPP">
375+
<p id="configurePPPError" class="inlineError"></p>
376+
</div>
375377
</div>
376378
</div>
377379
</div>

Firmware/RTK_Everywhere/AP-Config/src/main.js

Lines changed: 85 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ const CoordinateTypes = {
7878
var convertedCoordinate = 0.0;
7979
var coordinateInputType = CoordinateTypes.COORDINATE_INPUT_TYPE_DD;
8080

81+
var initialSettings = {};
82+
8183
function parseIncoming(msg) {
8284
//console.log("Incoming message: " + msg);
8385

@@ -226,6 +228,9 @@ function parseIncoming(msg) {
226228
hide("constellationSbas"); //Not supported on UM980
227229
hide("constellationNavic"); //Not supported on UM980
228230

231+
show("galileoHasSetting");
232+
hide("lg290pGnssSettings");
233+
229234
show("measurementRateInput");
230235

231236
show("loraConfig");
@@ -326,7 +331,7 @@ function parseIncoming(msg) {
326331
hide("logToSDCard"); //No SD card on Torch
327332

328333
hide("constellationSbas"); //Not supported on LG290P
329-
show("constellationNavic");
334+
show("constellationNavic");
330335
show("galileoHasSetting");
331336
show("lg290pGnssSettings");
332337
hide("tiltConfig"); //Not supported on Torch X2
@@ -711,6 +716,7 @@ function parseIncoming(msg) {
711716
ge("enableARPLogging").dispatchEvent(new CustomEvent('change'));
712717
ge("enableAutoFirmwareUpdate").dispatchEvent(new CustomEvent('change'));
713718
ge("enableAutoReset").dispatchEvent(new CustomEvent('change'));
719+
ge("enableGalileoHas").dispatchEvent(new CustomEvent('change'));
714720

715721
updateECEFList();
716722
updateGeodeticList();
@@ -720,9 +726,38 @@ function parseIncoming(msg) {
720726
dhcpEthernet();
721727
updateLatLong();
722728
updateCorrectionsPriorities();
729+
730+
// Create copy of settings, send only changes when 'Save Configuration' is pressed
731+
saveInitialSettings();
723732
}
724733
}
725734

735+
// Save the current state of settings
736+
function saveInitialSettings() {
737+
initialSettings = {}; // Clear previous settings
738+
739+
// Save input boxes and dropdowns
740+
var clsElements = document.querySelectorAll(".form-control, .form-dropdown");
741+
for (let x = 0; x < clsElements.length; x++) {
742+
initialSettings[clsElements[x].id] = clsElements[x].value;
743+
}
744+
745+
// Save checkboxes and radio buttons
746+
clsElements = document.querySelectorAll(".form-check-input:not(.fileManagerCheck), .form-radio");
747+
for (let x = 0; x < clsElements.length; x++) {
748+
// Store boolean values for easy comparison
749+
initialSettings[clsElements[x].id] = clsElements[x].checked.toString();
750+
}
751+
752+
// Save corrections priorities
753+
for (let x = 0; x < numCorrectionsSources; x++) {
754+
initialSettings["correctionsPriority_" + correctionsSourceNames[x]] = correctionsSourcePriorities[x].toString();
755+
}
756+
757+
// Note: recordsECEF and recordsGeodetic change very little so instead
758+
// of creating copy here, we will resend any entered coordinates every time.
759+
}
760+
726761
function hide(id) {
727762
ge(id).style.display = "none";
728763
}
@@ -738,39 +773,62 @@ function isElementShown(id) {
738773
return (false);
739774
}
740775

741-
//Create CSV of all setting data
776+
//Create CSV of all setting data that has changed from the original given to us
742777
function sendData() {
743778
var settingCSV = "";
779+
var changedCount = 0;
744780

745-
//Input boxes
781+
// Check input boxes and dropdowns
746782
var clsElements = document.querySelectorAll(".form-control, .form-dropdown");
747783
for (let x = 0; x < clsElements.length; x++) {
748-
settingCSV += clsElements[x].id + "," + clsElements[x].value + ",";
784+
var id = clsElements[x].id;
785+
var currentValue = clsElements[x].value;
786+
if (initialSettings[id] !== currentValue) {
787+
settingCSV += id + "," + currentValue + ",";
788+
changedCount++;
789+
}
749790
}
750791

751-
//Check boxes, radio buttons
752-
//Remove file manager files
792+
// Check boxes, radio buttons
753793
clsElements = document.querySelectorAll(".form-check-input:not(.fileManagerCheck), .form-radio");
754794
for (let x = 0; x < clsElements.length; x++) {
755-
settingCSV += clsElements[x].id + "," + clsElements[x].checked + ",";
795+
var id = clsElements[x].id;
796+
// Store boolean as string 'true'/'false' for consistent comparison with initialSettings
797+
var currentValue = clsElements[x].checked.toString();
798+
if (initialSettings[id] !== currentValue) {
799+
settingCSV += id + "," + currentValue + ",";
800+
changedCount++;
801+
}
756802
}
757803

804+
// Records (ECEF and Geodetic) - For simplicity, we send the full list if any list element exists.
758805
for (let x = 0; x < recordsECEF.length; x++) {
759806
settingCSV += "stationECEF" + x + ',' + recordsECEF[x] + ",";
760807
}
761-
762808
for (let x = 0; x < recordsGeodetic.length; x++) {
763809
settingCSV += "stationGeodetic" + x + ',' + recordsGeodetic[x] + ",";
764810
}
765811

812+
// Corrections Priorities
766813
for (let x = 0; x < correctionsSourceNames.length; x++) {
767-
settingCSV += "correctionsPriority_" + correctionsSourceNames[x] + ',' + correctionsSourcePriorities[x] + ",";
814+
var id = "correctionsPriority_" + correctionsSourceNames[x];
815+
var currentValue = correctionsSourcePriorities[x].toString();
816+
if (initialSettings[id] !== currentValue) {
817+
settingCSV += id + ',' + currentValue + ",";
818+
changedCount++;
819+
}
768820
}
769821

770-
console.log("Sending: " + settingCSV);
771-
websocket.send(settingCSV);
822+
console.log("Sending " + changedCount + " changed settings: " + settingCSV);
772823

773-
sendDataTimeout = setTimeout(sendData, 2000);
824+
// Only send if there are changes (plus the always-sent records)
825+
if (settingCSV.length > 0) {
826+
websocket.send(settingCSV);
827+
sendDataTimeout = setTimeout(sendData, 2000);
828+
} else {
829+
// If nothing changed, immediately report success.
830+
showSuccess('saveBtn', "No changes detected.");
831+
}
774832
}
775833

776834
function showError(id, errorText) {
@@ -876,7 +934,7 @@ function validateFields() {
876934
if (isElementShown("lg290pGnssSettings") == true) {
877935
checkElementValue("rtcmMinElev", -90, 90, "Must be between -90 and 90", "collapseGNSSConfig");
878936
}
879-
if (ge("enableGalileoHas").checked == true) {
937+
if (isElementShown("configurePppSetting") == true) {
880938
checkElementStringSpacesNoCommas("configurePPP", 1, 30, "Must be 1 to 30 characters. Separated by spaces. Commas not allowed", "collapseGNSSConfig");
881939
}
882940
if (ge("enableNtripClient").checked == true) {
@@ -2006,6 +2064,20 @@ document.addEventListener("DOMContentLoaded", (event) => {
20062064
adjustHAE();
20072065
});
20082066

2067+
ge("enableGalileoHas").addEventListener("change", function () {
2068+
if ((isElementShown("galileoHasSetting") == true) && (isElementShown("lg290pGnssSettings") == true)) {
2069+
if (ge("enableGalileoHas").checked == true) {
2070+
show("configurePppSetting");
2071+
}
2072+
else {
2073+
hide("configurePppSetting");
2074+
}
2075+
}
2076+
else {
2077+
hide("configurePppSetting"); // Hide on Torch UM980 - i.e. non-LG290P
2078+
}
2079+
});
2080+
20092081
for (let y = 0; y < numCorrectionsSources; y++) {
20102082
var buttonName = "corrPrioButton" + y;
20112083
ge(buttonName).addEventListener("click", function () {

Firmware/RTK_Everywhere/Begin.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ void beginBoard()
657657
present.invertedFastPowerOff = true;
658658
present.gnss_to_uart = true;
659659
present.gnss_to_uart2 = true;
660-
present.mosaicMicroSd;
660+
present.mosaicMicroSd = true;
661661
present.microSdCardDetectLow = true; // Except microSD is connected to mosaic... present.microSd is false
662662

663663
present.minCno = true;

Firmware/RTK_Everywhere/Display.ino

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2813,11 +2813,12 @@ void displayMessage(const char *message, uint16_t displayTime)
28132813
// Count words based on spaces
28142814
uint8_t wordCount = 0;
28152815
strncpy(temp, message, sizeof(temp) - 1); // strtok modifies the message so make copy
2816-
char *token = strtok(temp, " ");
2816+
char *preservedPointer;
2817+
char *token = strtok_r(temp, " ", &preservedPointer);
28172818
while (token != nullptr)
28182819
{
28192820
wordCount++;
2820-
token = strtok(nullptr, " ");
2821+
token = strtok_r(nullptr, " ", &preservedPointer);
28212822
}
28222823

28232824
uint8_t yPos = (oled->getHeight() / 2) - (fontHeight / 2);
@@ -2829,11 +2830,11 @@ void displayMessage(const char *message, uint16_t displayTime)
28292830
// drawFrame();
28302831

28312832
strncpy(temp, message, sizeof(temp) - 1);
2832-
token = strtok(temp, " ");
2833+
token = strtok_r(temp, " ", &preservedPointer);
28332834
while (token != nullptr)
28342835
{
28352836
printTextCenter(token, yPos, QW_FONT_8X16, 1, false); // text, y, font type, kerning, inverted
2836-
token = strtok(nullptr, " ");
2837+
token = strtok_r(nullptr, " ", &preservedPointer);
28372838
yPos += fontHeight;
28382839
}
28392840

Firmware/RTK_Everywhere/GNSS.ino

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,10 @@ bool gnssCmdUpdateConstellations(int commandIndex)
442442
if (gnss == nullptr)
443443
return false;
444444

445-
return gnss->setConstellations();
445+
//return gnss->setConstellations();
446+
// setConstellations() can take multiple seconds. Avoid calling during WebConfig
447+
// as this can lead to >10 seconds required for parsing of the incoming settings blob
448+
return true;
446449
}
447450

448451
//----------------------------------------
@@ -453,7 +456,8 @@ bool gnssCmdUpdateMessageRates(int commandIndex)
453456
if (gnss == nullptr)
454457
return false;
455458

456-
return gnss->setMessages(MAX_SET_MESSAGES_RETRIES);
459+
//return gnss->setMessages(MAX_SET_MESSAGES_RETRIES);
460+
return true;
457461
}
458462

459463
//----------------------------------------

Firmware/RTK_Everywhere/GNSS_UM980.ino

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,6 @@ void GNSS_UM980::begin()
6969
// Instantiate the library
7070
_um980 = new UM980();
7171

72-
// Turn on/off debug messages
73-
if (settings.debugGnss)
74-
debuggingEnable();
75-
7672
// In order to reduce UM980 configuration time, the UM980 library blocks the start of BESTNAV and RECTIME until 3D
7773
// fix is achieved However, if all NMEA messages are disabled, the UM980 will never detect a 3D fix.
7874
if (isGgaActive())
@@ -97,8 +93,14 @@ void GNSS_UM980::begin()
9793
return;
9894
}
9995
}
96+
97+
online.gnss = true;
98+
10099
systemPrintln("GNSS UM980 online");
101100

101+
if (settings.debugGnss)
102+
debuggingEnable(); // Print all debug to Serial
103+
102104
// Check firmware version and print info
103105
printModuleInfo();
104106

@@ -119,8 +121,6 @@ void GNSS_UM980::begin()
119121
gnssFirmwareVersionInt = 99;
120122

121123
snprintf(gnssUniqueId, sizeof(gnssUniqueId), "%s", _um980->getID());
122-
123-
online.gnss = true;
124124
}
125125

126126
//----------------------------------------
@@ -475,8 +475,10 @@ void GNSS_UM980::disableAllOutput()
475475
response &= _um980->disableOutputPort("COM2");
476476
response &= _um980->disableOutputPort("COM3");
477477
if (response)
478-
break;
478+
return;
479479
}
480+
481+
systemPrintln("UM980 failed to disable output");
480482
}
481483

482484
//----------------------------------------

Firmware/RTK_Everywhere/LoRa.ino

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,7 @@ void beginLoraFirmwareUpdate()
542542
else
543543
systemPrintln("ERROR: productVariant does not support LoRa");
544544

545-
// Make sure ESP32 is connected to LoRa STM32 UART
545+
// Make sure ESP-UART1 is connected to LoRa STM32 UART0
546546
muxSelectLoRaConfigure();
547547

548548
loraEnterBootloader(); // Push boot pin high and reset STM32
@@ -715,7 +715,7 @@ bool loraEnterCommandMode()
715715

716716
systemFlush(); // Complete prints
717717

718-
muxSelectLoRaConfigure(); // Connect to the STM32 for configuration
718+
muxSelectLoRaCommunication(); // Connect the LoRa radio to ESP32 UART0 (shared with USB)
719719

720720
delay(50); // Wait for incoming serial to complete
721721
while (Serial.available())

Firmware/RTK_Everywhere/NVM.ino

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -990,8 +990,16 @@ bool parseLine(char *str)
990990
{
991991
char *ptr;
992992

993+
// A health warning about strtok:
994+
// strtok will convert any delimiters it finds ("=" in our case) into NULL characters.
995+
// Also, be very careful that you do not use strtok within an strtok while loop.
996+
// The next call of strtok(NULL, ...) in the outer loop will use the pointer saved from the inner loop!
997+
// The same is true for tasks!
998+
// The solution is to use strtok_r - the reentrant version of strtok
999+
9931000
// Set strtok start of line.
994-
str = strtok(str, "=");
1001+
char *preservedPointer;
1002+
str = strtok_r(str, "=", &preservedPointer);
9951003
if (!str)
9961004
{
9971005
log_d("Fail");
@@ -1006,7 +1014,7 @@ bool parseLine(char *str)
10061014
char settingString[100] = "";
10071015

10081016
// Move pointer to end of line
1009-
str = strtok(nullptr, "\n");
1017+
str = strtok_r(nullptr, "\n", &preservedPointer);
10101018
if (!str)
10111019
{
10121020
// This line does not contain a \n or the settingString is zero length

Firmware/RTK_Everywhere/Network.ino

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,10 +262,11 @@ void menuTcpUdp()
262262
// Remove any http:// or https:// prefix from host name
263263
// strtok modifies string to be parsed so we create a copy
264264
strncpy(hostname, settings.tcpClientHost, sizeof(hostname) - 1);
265-
char *token = strtok(hostname, "//");
265+
char *preservedPointer;
266+
char *token = strtok_r(hostname, "//", &preservedPointer);
266267
if (token != nullptr)
267268
{
268-
token = strtok(nullptr, "//"); // Advance to data after //
269+
token = strtok_r(nullptr, "//", &preservedPointer); // Advance to data after //
269270
if (token != nullptr)
270271
strcpy(settings.tcpClientHost, token);
271272
}

Firmware/RTK_Everywhere/NtripClient.ino

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,11 @@ bool ntripClientConnect()
216216
char hostname[51];
217217
strncpy(hostname, settings.ntripClient_CasterHost,
218218
sizeof(hostname) - 1); // strtok modifies string to be parsed so we create a copy
219-
char *token = strtok(hostname, "//");
219+
char *preservedPointer;
220+
char *token = strtok_r(hostname, "//", &preservedPointer);
220221
if (token != nullptr)
221222
{
222-
token = strtok(nullptr, "//"); // Advance to data after //
223+
token = strtok_r(nullptr, "//", &preservedPointer); // Advance to data after //
223224
if (token != nullptr)
224225
strcpy(settings.ntripClient_CasterHost, token);
225226
}

0 commit comments

Comments
 (0)