From fb524f740cec5d978d276b15e96dc2b277fd4023 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Fri, 3 Oct 2025 10:10:31 -0600 Subject: [PATCH 01/68] Add compile guard --- Firmware/RTK_Everywhere/Bluetooth.ino | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Firmware/RTK_Everywhere/Bluetooth.ino b/Firmware/RTK_Everywhere/Bluetooth.ino index e4f3d7ec9..edac8d3ca 100644 --- a/Firmware/RTK_Everywhere/Bluetooth.ino +++ b/Firmware/RTK_Everywhere/Bluetooth.ino @@ -421,7 +421,9 @@ void bluetoothFlush() void BTConfirmRequestCallback(uint32_t numVal) { systemPrintf("Device sent PIN: %06lu. Sending confirmation\r\n", numVal); +#ifdef COMPILE_BT bluetoothSerialSpp->confirmReply(true); // AUTO_PAIR - equivalent to enableSSP(false, true); +#endif // COMPILE_BT // TODO: if the RTK device has an OLED, we should display the PIN so user can confirm } From 11757850152b1738a9c25cd4feccac1f0ec14583 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Fri, 3 Oct 2025 10:10:38 -0600 Subject: [PATCH 02/68] Whitespace --- Firmware/RTK_Everywhere/Bluetooth.ino | 31 ++++++++++++++------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/Firmware/RTK_Everywhere/Bluetooth.ino b/Firmware/RTK_Everywhere/Bluetooth.ino index edac8d3ca..f4eb1554c 100644 --- a/Firmware/RTK_Everywhere/Bluetooth.ino +++ b/Firmware/RTK_Everywhere/Bluetooth.ino @@ -419,7 +419,8 @@ void bluetoothFlush() #endif // COMPILE_BT } -void BTConfirmRequestCallback(uint32_t numVal) { +void BTConfirmRequestCallback(uint32_t numVal) +{ systemPrintf("Device sent PIN: %06lu. Sending confirmation\r\n", numVal); #ifdef COMPILE_BT bluetoothSerialSpp->confirmReply(true); // AUTO_PAIR - equivalent to enableSSP(false, true); @@ -551,21 +552,21 @@ void bluetoothStart() { // Uncomment the next line to force deletion of all paired (bonded) devices // (This should only be necessary if you have changed the SSP pairing type) - //settings.clearBtPairings = true; - + // settings.clearBtPairings = true; + // Enable secure pairing without PIN : // iPhone displays Connection Unsuccessful - but then connects anyway... bluetoothSerialSpp->enableSSP(false, false); // Enable secure pairing with PIN : - //bluetoothSerialSpp->enableSSP(false, true); + // bluetoothSerialSpp->enableSSP(false, true); // Accessory Protocol recommends using a PIN // Support Apple Accessory: Device to Accessory // 1. Search for an accessory from the device and initiate pairing. // 2. Verify pairing is successful after exchanging a pin code. - //bluetoothSerialSpp->enableSSP(true, true); // Enable secure pairing with PIN - //bluetoothSerialSpp->onConfirmRequest(&BTConfirmRequestCallback); // Callback to verify the PIN + // bluetoothSerialSpp->enableSSP(true, true); // Enable secure pairing with PIN + // bluetoothSerialSpp->onConfirmRequest(&BTConfirmRequestCallback); // Callback to verify the PIN beginSuccess &= bluetoothSerialSpp->begin( deviceName, true, true, settings.sppRxQueueSize, settings.sppTxQueueSize, 0, 0, @@ -596,9 +597,9 @@ void bluetoothStart() record.type = ESP_SDP_TYPE_RAW; record.uuid.len = sizeof(UUID_IAP2); memcpy(record.uuid.uuid.uuid128, UUID_IAP2, sizeof(UUID_IAP2)); - //record.service_name_length = strlen(sdp_service_name) + 1; - //record.service_name = (char *)sdp_service_name; - // Use the same EIR Local Name parameter as the Name in the IdentificationInformation + // record.service_name_length = strlen(sdp_service_name) + 1; + // record.service_name = (char *)sdp_service_name; + // Use the same EIR Local Name parameter as the Name in the IdentificationInformation record.service_name_length = strlen(deviceName) + 1; record.service_name = (char *)deviceName; // record.rfcomm_channel_number = 1; // Doesn't seem to help the failed connects @@ -672,7 +673,7 @@ void bluetoothStart() if (pin_bluetoothStatusLED != PIN_UNDEFINED) { - bluetoothLedTask.detach(); // Reset BT LED blinker task rate to 2Hz + bluetoothLedTask.detach(); // Reset BT LED blinker task rate to 2Hz bluetoothLedTask.attach(bluetoothLedTaskPace2Hz, tickerBluetoothLedUpdate); // Rate in seconds, callback } @@ -682,11 +683,11 @@ void bluetoothStart() { if (bluetoothCommandTaskHandle == nullptr) xTaskCreatePinnedToCore( - bluetoothCommandTask, // Function to run - "BluetoothCommandTask", // Just for humans - 4000, // Stack Size - must be ~4000 - nullptr, // Task input parameter - 0, // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest + bluetoothCommandTask, // Function to run + "BluetoothCommandTask", // Just for humans + 4000, // Stack Size - must be ~4000 + nullptr, // Task input parameter + 0, // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest &bluetoothCommandTaskHandle, // Task handle settings.bluetoothInterruptsCore); // Core where task should run, 0 = core, 1 = Arduino } From 392b7d825db857203b0d7f4fff750350cc5b9eb1 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Fri, 3 Oct 2025 10:15:44 -0600 Subject: [PATCH 03/68] Add MSM format selection Only for LG290P at the moment. See present.msmFormat to add to other platforms. Enable corrections debugging ('h'ardware, 10) to view output. --- Firmware/RTK_Everywhere/Begin.ino | 3 ++- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 22 +++++++++++++--------- Firmware/RTK_Everywhere/menuGNSS.ino | 12 ++++++++++++ Firmware/RTK_Everywhere/settings.h | 5 ++++- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/Firmware/RTK_Everywhere/Begin.ino b/Firmware/RTK_Everywhere/Begin.ino index 8090fd978..9a2f645fe 100644 --- a/Firmware/RTK_Everywhere/Begin.ino +++ b/Firmware/RTK_Everywhere/Begin.ino @@ -731,7 +731,8 @@ void beginBoard() present.microSd = true; present.gpioExpanderButtons = true; present.microSdCardDetectGpioExpanderHigh = true; // CD is on GPIO 5 of expander. High = SD in place. - + present.msmFormat = true; // Can control different RTCM formats, ie MSM4 vs MSM7 + // We can't enable here because we don't know if lg290pFirmwareVersion is >= v05 // present.minElevation = true; // present.minCno = true; diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index 43dbce880..7b6bd81ed 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -39,7 +39,7 @@ void GNSS_LG290P::baseRtcmLowDataRate() settings.lg290pMessageRatesRTCMBase[x] = 0; settings.lg290pMessageRatesRTCMBase[getRtcmMessageNumberByName("RTCM3-1005")] = - 10; // 1005 0.1Hz - Exclude antenna height + 10; // 1005 0.1Hz - Exclude antenna height settings.lg290pMessageRatesRTCMBase[getRtcmMessageNumberByName("RTCM3-107X")] = 2; // 1074 0.5Hz settings.lg290pMessageRatesRTCMBase[getRtcmMessageNumberByName("RTCM3-108X")] = 2; // 1084 0.5Hz settings.lg290pMessageRatesRTCMBase[getRtcmMessageNumberByName("RTCM3-109X")] = 2; // 1094 0.5Hz @@ -845,12 +845,17 @@ bool GNSS_LG290P::enableRTCMBase() if (enableRTCM == true) { - if (settings.debugGnss) - systemPrintln("Enabling Base RTCM output"); + int minimumRtcmRate = 1; // Set base RTCM output to 1 second interval + + if (settings.debugCorrections) + systemPrintf("Enabling Base RTCM MSM%d output with rate of %d\r\n", settings.rtcmMsmFormat, minimumRtcmRate); + + // Enable RTCM MSM7 (for faster PPP CSRS results), output at a rate equal to the minimum RTCM rate (EPH Mode = 2) + // PQTMCFGRTCM, W, , , , , , , // PQTMCFGRTCM fails to respond with OK over UART2 of LG290P, so don't look for it - _lg290p->sendOkCommand( - "PQTMCFGRTCM,W,4,0,-90,07,06,2,1"); // Enable MSM4, output regular intervals, interval (seconds) + char msmCommand[40] = {0}; + snprintf(msmCommand, sizeof(msmCommand), "PQTMCFGRTCM,W,%d,0,%d,07,06,2,%d", settings.rtcmMsmFormat, settings.minElev, minimumRtcmRate); } return (response); @@ -1003,14 +1008,13 @@ bool GNSS_LG290P::enableRTCMRover() if (enableRTCM == true) { if (settings.debugCorrections) - systemPrintf("Enabling Rover RTCM MSM output with rate of %d\r\n", minimumRtcmRate); + systemPrintf("Enabling Rover RTCM MSM%d output with rate of %d, min elevation of %d degrees\r\n", settings.rtcmMsmFormat, minimumRtcmRate, settings.minElev); - // Enable MSM7 (for faster PPP CSRS results), output at a rate equal to the minimum RTCM rate (EPH Mode = 2) + // Enable RTCM MSM7 (for faster PPP CSRS results), output at a rate equal to the minimum RTCM rate (EPH Mode = 2) // PQTMCFGRTCM, W, , , , , , , - // Set MSM_ElevThd to 15 degrees from rftop suggestion char msmCommand[40] = {0}; - snprintf(msmCommand, sizeof(msmCommand), "PQTMCFGRTCM,W,7,0,15,07,06,2,%d", minimumRtcmRate); + snprintf(msmCommand, sizeof(msmCommand), "PQTMCFGRTCM,W,%d,0,%d,07,06,2,%d", settings.rtcmMsmFormat, settings.minElev, minimumRtcmRate); // PQTMCFGRTCM fails to respond with OK over UART2 of LG290P, so don't look for it _lg290p->sendOkCommand(msmCommand); diff --git a/Firmware/RTK_Everywhere/menuGNSS.ino b/Firmware/RTK_Everywhere/menuGNSS.ino index 259d65ba1..75ea4245c 100644 --- a/Firmware/RTK_Everywhere/menuGNSS.ino +++ b/Firmware/RTK_Everywhere/menuGNSS.ino @@ -171,6 +171,11 @@ void menuGNSS() settings.enableMultipathMitigation ? "Enabled" : "Disabled"); } + if (present.msmFormat) + { + systemPrintf("16) RTCM MSM format: MSM%d\r\n", settings.rtcmMsmFormat); + } + systemPrintln("x) Exit"); int incoming = getUserInputNumber(); // Returns EXIT, TIMEOUT, or long @@ -389,6 +394,13 @@ void menuGNSS() restartRover = true; } + else if ((incoming == 16) && present.msmFormat) + { + if (getNewSetting("Enter MSM format number", 1, 9, &settings.rtcmMsmFormat) == + INPUT_RESPONSE_VALID) + restartRover = true; + } + else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) break; else if (incoming == INPUT_RESPONSE_GETNUMBER_TIMEOUT) diff --git a/Firmware/RTK_Everywhere/settings.h b/Firmware/RTK_Everywhere/settings.h index d66b99634..41bcc2542 100644 --- a/Firmware/RTK_Everywhere/settings.h +++ b/Firmware/RTK_Everywhere/settings.h @@ -937,7 +937,8 @@ struct Settings uint8_t dynamicModel = 254; // Default will be applied by checkGNSSArrayDefaults bool enablePrintRoverAccuracy = true; int16_t minCNO = 6; // Minimum satellite signal level for navigation. ZED-F9P default is 6 dBHz - uint8_t minElev = 10; // Minimum elevation (in deg) for a GNSS satellite to be used in NAV + uint8_t minElev = 10; // Minimum elevation (in deg) for a GNSS satellite to be used + uint8_t rtcmMsmFormat = 7; // Control between MSM4 and MSM7 RTCM formats. // RTC (Real Time Clock) bool enablePrintRtcSync = false; @@ -1631,6 +1632,7 @@ const RTK_Settings_Entry rtkSettingsEntries[] = { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.enablePrintRoverAccuracy, "enablePrintRoverAccuracy", }, { 0, 1, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _int16_t, 0, & settings.minCNO, "minCNO", }, // Not inWebConfig - createSettingsString gets from GNSS { 1, 1, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _uint8_t, 0, & settings.minElev, "minElev", }, + { 1, 1, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _uint8_t, 0, & settings.rtcmMsmFormat, "rtcmMsmFormat", }, // RTC (Real Time Clock) { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.enablePrintRtcSync, "enablePrintRtcSync", }, @@ -1953,6 +1955,7 @@ struct struct_present bool multipathMitigation = false; // UM980 has MPM, other platforms do not bool minCno = false; // ZED, mosaic, UM980 have minCN0. LG290P does on version >= v5. bool minElevation = false; // ZED, mosaic, UM980 have minElevation. LG290P does on versions >= v5. + bool msmFormat = false; // LG290P can output different RTCM MSM formats (ie, MSM4 vs MSM7) bool dynamicModel = false; // ZED, mosaic, UM980 have dynamic models. LG290P does not. bool gpioExpanderSwitches = false; // Used on Flex bool tiltPossible = false; //Flex may have a tilt IMU From 30bedfdc1d48cabe2f7d452b9f43e3c152a6d21f Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 7 Oct 2025 10:20:44 -0600 Subject: [PATCH 04/68] Revert "Add MSM format selection" This reverts commit 392b7d825db857203b0d7f4fff750350cc5b9eb1. --- Firmware/RTK_Everywhere/Begin.ino | 3 +-- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 22 +++++++++------------- Firmware/RTK_Everywhere/menuGNSS.ino | 12 ------------ Firmware/RTK_Everywhere/settings.h | 5 +---- 4 files changed, 11 insertions(+), 31 deletions(-) diff --git a/Firmware/RTK_Everywhere/Begin.ino b/Firmware/RTK_Everywhere/Begin.ino index 9a2f645fe..8090fd978 100644 --- a/Firmware/RTK_Everywhere/Begin.ino +++ b/Firmware/RTK_Everywhere/Begin.ino @@ -731,8 +731,7 @@ void beginBoard() present.microSd = true; present.gpioExpanderButtons = true; present.microSdCardDetectGpioExpanderHigh = true; // CD is on GPIO 5 of expander. High = SD in place. - present.msmFormat = true; // Can control different RTCM formats, ie MSM4 vs MSM7 - + // We can't enable here because we don't know if lg290pFirmwareVersion is >= v05 // present.minElevation = true; // present.minCno = true; diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index 7b6bd81ed..43dbce880 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -39,7 +39,7 @@ void GNSS_LG290P::baseRtcmLowDataRate() settings.lg290pMessageRatesRTCMBase[x] = 0; settings.lg290pMessageRatesRTCMBase[getRtcmMessageNumberByName("RTCM3-1005")] = - 10; // 1005 0.1Hz - Exclude antenna height + 10; // 1005 0.1Hz - Exclude antenna height settings.lg290pMessageRatesRTCMBase[getRtcmMessageNumberByName("RTCM3-107X")] = 2; // 1074 0.5Hz settings.lg290pMessageRatesRTCMBase[getRtcmMessageNumberByName("RTCM3-108X")] = 2; // 1084 0.5Hz settings.lg290pMessageRatesRTCMBase[getRtcmMessageNumberByName("RTCM3-109X")] = 2; // 1094 0.5Hz @@ -845,17 +845,12 @@ bool GNSS_LG290P::enableRTCMBase() if (enableRTCM == true) { - int minimumRtcmRate = 1; // Set base RTCM output to 1 second interval - - if (settings.debugCorrections) - systemPrintf("Enabling Base RTCM MSM%d output with rate of %d\r\n", settings.rtcmMsmFormat, minimumRtcmRate); - - // Enable RTCM MSM7 (for faster PPP CSRS results), output at a rate equal to the minimum RTCM rate (EPH Mode = 2) - // PQTMCFGRTCM, W, , , , , , , + if (settings.debugGnss) + systemPrintln("Enabling Base RTCM output"); // PQTMCFGRTCM fails to respond with OK over UART2 of LG290P, so don't look for it - char msmCommand[40] = {0}; - snprintf(msmCommand, sizeof(msmCommand), "PQTMCFGRTCM,W,%d,0,%d,07,06,2,%d", settings.rtcmMsmFormat, settings.minElev, minimumRtcmRate); + _lg290p->sendOkCommand( + "PQTMCFGRTCM,W,4,0,-90,07,06,2,1"); // Enable MSM4, output regular intervals, interval (seconds) } return (response); @@ -1008,13 +1003,14 @@ bool GNSS_LG290P::enableRTCMRover() if (enableRTCM == true) { if (settings.debugCorrections) - systemPrintf("Enabling Rover RTCM MSM%d output with rate of %d, min elevation of %d degrees\r\n", settings.rtcmMsmFormat, minimumRtcmRate, settings.minElev); + systemPrintf("Enabling Rover RTCM MSM output with rate of %d\r\n", minimumRtcmRate); - // Enable RTCM MSM7 (for faster PPP CSRS results), output at a rate equal to the minimum RTCM rate (EPH Mode = 2) + // Enable MSM7 (for faster PPP CSRS results), output at a rate equal to the minimum RTCM rate (EPH Mode = 2) // PQTMCFGRTCM, W, , , , , , , + // Set MSM_ElevThd to 15 degrees from rftop suggestion char msmCommand[40] = {0}; - snprintf(msmCommand, sizeof(msmCommand), "PQTMCFGRTCM,W,%d,0,%d,07,06,2,%d", settings.rtcmMsmFormat, settings.minElev, minimumRtcmRate); + snprintf(msmCommand, sizeof(msmCommand), "PQTMCFGRTCM,W,7,0,15,07,06,2,%d", minimumRtcmRate); // PQTMCFGRTCM fails to respond with OK over UART2 of LG290P, so don't look for it _lg290p->sendOkCommand(msmCommand); diff --git a/Firmware/RTK_Everywhere/menuGNSS.ino b/Firmware/RTK_Everywhere/menuGNSS.ino index 75ea4245c..259d65ba1 100644 --- a/Firmware/RTK_Everywhere/menuGNSS.ino +++ b/Firmware/RTK_Everywhere/menuGNSS.ino @@ -171,11 +171,6 @@ void menuGNSS() settings.enableMultipathMitigation ? "Enabled" : "Disabled"); } - if (present.msmFormat) - { - systemPrintf("16) RTCM MSM format: MSM%d\r\n", settings.rtcmMsmFormat); - } - systemPrintln("x) Exit"); int incoming = getUserInputNumber(); // Returns EXIT, TIMEOUT, or long @@ -394,13 +389,6 @@ void menuGNSS() restartRover = true; } - else if ((incoming == 16) && present.msmFormat) - { - if (getNewSetting("Enter MSM format number", 1, 9, &settings.rtcmMsmFormat) == - INPUT_RESPONSE_VALID) - restartRover = true; - } - else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) break; else if (incoming == INPUT_RESPONSE_GETNUMBER_TIMEOUT) diff --git a/Firmware/RTK_Everywhere/settings.h b/Firmware/RTK_Everywhere/settings.h index 41bcc2542..d66b99634 100644 --- a/Firmware/RTK_Everywhere/settings.h +++ b/Firmware/RTK_Everywhere/settings.h @@ -937,8 +937,7 @@ struct Settings uint8_t dynamicModel = 254; // Default will be applied by checkGNSSArrayDefaults bool enablePrintRoverAccuracy = true; int16_t minCNO = 6; // Minimum satellite signal level for navigation. ZED-F9P default is 6 dBHz - uint8_t minElev = 10; // Minimum elevation (in deg) for a GNSS satellite to be used - uint8_t rtcmMsmFormat = 7; // Control between MSM4 and MSM7 RTCM formats. + uint8_t minElev = 10; // Minimum elevation (in deg) for a GNSS satellite to be used in NAV // RTC (Real Time Clock) bool enablePrintRtcSync = false; @@ -1632,7 +1631,6 @@ const RTK_Settings_Entry rtkSettingsEntries[] = { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.enablePrintRoverAccuracy, "enablePrintRoverAccuracy", }, { 0, 1, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _int16_t, 0, & settings.minCNO, "minCNO", }, // Not inWebConfig - createSettingsString gets from GNSS { 1, 1, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _uint8_t, 0, & settings.minElev, "minElev", }, - { 1, 1, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _uint8_t, 0, & settings.rtcmMsmFormat, "rtcmMsmFormat", }, // RTC (Real Time Clock) { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.enablePrintRtcSync, "enablePrintRtcSync", }, @@ -1955,7 +1953,6 @@ struct struct_present bool multipathMitigation = false; // UM980 has MPM, other platforms do not bool minCno = false; // ZED, mosaic, UM980 have minCN0. LG290P does on version >= v5. bool minElevation = false; // ZED, mosaic, UM980 have minElevation. LG290P does on versions >= v5. - bool msmFormat = false; // LG290P can output different RTCM MSM formats (ie, MSM4 vs MSM7) bool dynamicModel = false; // ZED, mosaic, UM980 have dynamic models. LG290P does not. bool gpioExpanderSwitches = false; // Used on Flex bool tiltPossible = false; //Flex may have a tilt IMU From 81be2c81b99e106df78cec38e682d5ae751d8efe Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 9 Oct 2025 13:54:53 -0600 Subject: [PATCH 05/68] Change to buffered BLE serial library --- Firmware/RTK_Everywhere/bluetoothSelect.h | 39 ++++++++++++++++------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/Firmware/RTK_Everywhere/bluetoothSelect.h b/Firmware/RTK_Everywhere/bluetoothSelect.h index 02a73363d..cc9b434d1 100644 --- a/Firmware/RTK_Everywhere/bluetoothSelect.h +++ b/Firmware/RTK_Everywhere/bluetoothSelect.h @@ -6,6 +6,7 @@ #include "src/BluetoothSerial/BluetoothSerial.h" #include //Click here to get the library: http://librarymanager/All#ESP32_BleSerial by Avinab Malla +#include #include "esp_sdp_api.h" @@ -164,14 +165,18 @@ class BTClassicSerial : public virtual BTSerialInterface, public BluetoothSerial } }; -class BTLESerial : public virtual BTSerialInterface, public BleSerial +//class BTLESerial : public virtual BTSerialInterface, public BleSerial + +//Use buffered BLE serial to handle LIST command over CLI interface +class BTLESerial : public virtual BTSerialInterface, public BleBufferedSerial { public: // Missing from BleSerial bool begin(String deviceName, bool isMaster, bool disableBLE, uint16_t rxQueueSize, uint16_t txQueueSize, const char *serviceID, const char *rxID, const char *txID) { - BleSerial::begin(deviceName.c_str(), serviceID, rxID, txID, -1); // name, service_uuid, rx_uuid, tx_uuid, led_pin + BleBufferedSerial::begin(deviceName.c_str(), serviceID, rxID, txID, -1); // name, service_uuid, rx_uuid, tx_uuid, led_pin + //BleSerial::begin(deviceName.c_str(), serviceID, rxID, txID, -1); // name, service_uuid, rx_uuid, tx_uuid, led_pin return true; } @@ -183,7 +188,8 @@ class BTLESerial : public virtual BTSerialInterface, public BleSerial void end() { - BleSerial::end(); + BleBufferedSerial::end(); + // BleSerial::end(); } // esp_err_t register_callback(esp_spp_cb_t callback) @@ -194,42 +200,50 @@ class BTLESerial : public virtual BTSerialInterface, public BleSerial void setTimeout(unsigned long timeout) { - BleSerial::setTimeout(timeout); + BleBufferedSerial::setTimeout(timeout); + // BleSerial::setTimeout(timeout); } int available() { - return BleSerial::available(); + return BleBufferedSerial::available(); + // return BleSerial::available(); } size_t readBytes(uint8_t *buffer, size_t bufferSize) { - return BleSerial::readBytes(buffer, bufferSize); + return BleBufferedSerial::readBytes(buffer, bufferSize); + // return BleSerial::readBytes(buffer, bufferSize); } int read() { - return BleSerial::read(); + return BleBufferedSerial::read(); + // return BleSerial::read(); } int peek() { - return BleSerial::peek(); + return BleBufferedSerial::peek(); + // return BleSerial::peek(); } size_t write(const uint8_t *buffer, size_t size) { - return BleSerial::write(buffer, size); + return BleBufferedSerial::write(buffer, size); + // return BleSerial::write(buffer, size); } size_t write(uint8_t value) { - return BleSerial::write(value); + return BleBufferedSerial::write(value); + // return BleSerial::write(value); } void flush() { - BleSerial::flush(); + BleBufferedSerial::flush(); + // BleSerial::flush(); } bool connect(uint8_t remoteAddress[], int channel, esp_spp_sec_t sec_mask, esp_spp_role_t role) @@ -239,7 +253,8 @@ class BTLESerial : public virtual BTSerialInterface, public BleSerial bool connected() { - return (BleSerial::connected()); + return (BleBufferedSerial::connected()); + // return (BleSerial::connected()); } void enableSSP(bool inputCapability, bool outputCapability) {} From 48ee2b8fa5a759cbe1ea027e08c922fefc1118a9 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 9 Oct 2025 13:57:23 -0600 Subject: [PATCH 06/68] Add gnssUpdate() to allow for configuration change requests --- Firmware/RTK_Everywhere/GNSS.ino | 108 +++++++++++++++++++++ Firmware/RTK_Everywhere/RTK_Everywhere.ino | 4 +- 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index cdab75d8c..c27e3c447 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -4,6 +4,27 @@ GNSS.ino GNSS layer implementation ------------------------------------------------------------------------------*/ +// We may receive a command or the user may change a setting that needs to modify the configuration of the GNSS receiver +// Because this can take time, we group all the changes together and re-configure the receiver once the user has exited +// the menu system, closed the Web Config, or the CLI is closed. +enum +{ + UPDATE_NONE = 0, + UPDATE_ROVER = (1 << 0), + UPDATE_BASE = (1 << 1), // Fixed base or survey in, location, etc + UPDATE_CONSTELLATION = (1 << 2), // Turn on/off a constellation + UPDATE_MESSAGE_RATE = (1 << 3), // Update all message rates + UPDATE_MESSAGE_RATE_NMEA = (1 << 4), // Update NMEA message rates + UPDATE_MESSAGE_RATE_RTCM_ROVER = (1 << 5), // Update RTCM Rover message rates + UPDATE_MESSAGE_RATE_RTCM_BASE = (1 << 6), // Update RTCM Base message rates + UPDATE_HAS_E6 = (1 << 7), // Enable/disable HAS E6 capabilities + UPDATE_BAUD_RATE = (1 << 8), + UPDATE_MULTIPATH = (1 << 9), +}; + +uint16_t gnssConfigureRequest = + UPDATE_NONE; // Bitfield containing an update be made to various settings on the GNSS receiver + extern int NTRIPCLIENT_MS_BETWEEN_GGA; #ifdef COMPILE_NETWORK @@ -77,6 +98,93 @@ bool GNSS::supportsAntennaShortOpen() return false; } +void gnssUpdate() +{ + // Belt and suspender + if (gnss == nullptr) + return; + + // Allow the GNSS platform to update itself + gnss->update(); + + // Handle any requested configuration changes + // Only update the GNSS receiver once the CLI, serial menu, and Web Config interfaces are disconnected + // This is to avoid multiple reconfigure delays when multiple commands are received, ie enable GPS, disable Galileo, + // should only trigger one GNSS reconfigure + if (gnssConfigureRequest != UPDATE_NONE && bluetoothCommandIsConnected() == false && inMainMenu == false && + inWebConfigMode() == false) + { + // Test for individual changes as needed + if (gnssConfigureRequest & UPDATE_CONSTELLATION) + { + Serial.println("Update const"); + } + + // Here we need a table to determine if the given combination of setting requests trigger a GNSS's NVM save + + // Here we need a table to determine if the given combination of setting requests require a GNSS reset to take + // effect + + // For now we will maintain the previous approach of, if any setting gets changed, re-start in the current mode + // and use the settings currently in the ESP32 NVM + + // Restart current state to reconfigure receiver + systemPrintln("Restarting GNSS receiver with new settings"); + if (inBaseMode() == true) + { + settings.gnssConfiguredRover = false; // Reapply configuration + requestChangeState(STATE_BASE_NOT_STARTED); // Restart base for latest changes to take effect + } + else if (inRoverMode() == true) + { + settings.gnssConfiguredRover = false; // Reapply configuration + // TODO when does GNSS configured rover go true? + requestChangeState(STATE_ROVER_NOT_STARTED); // Restart rover for latest changes to take effect + } + // else if (inWebConfigMode() == true) {} + // else if (inNtpMode() == true) {} + else + { + systemPrintln("gnssUpdate: Uncaught mode change"); + } + + gnssConfigureRequest = UPDATE_NONE; // Clear requests + } +} + +//---------------------------------------- +// Update the constellations following a set command +//---------------------------------------- +bool gnssCmdUpdateConstellations(const char *settingName, void *settingData, int settingType) +{ + gnssConfigureRequest |= + UPDATE_CONSTELLATION; // Once BLE Command, Web Config, and CLI are closed, reconfigure receiver + + return (true); +} + +//---------------------------------------- +// Update the message rates following a set command +//---------------------------------------- +bool gnssCmdUpdateMessageRates(const char *settingName, void *settingData, int settingType) +{ + gnssConfigureRequest |= + UPDATE_MESSAGE_RATE; // Once BLE Command, Web Config, and CLI are closed, reconfigure receiver + + return (true); +} + +//---------------------------------------- +// Update the PointPerfect service following a set command +//---------------------------------------- +// TODO move to PointPerfect once callback is in place +bool pointPerfectCmdUpdateServiceType(const char *settingName, void *settingData, int settingType) +{ + // Require a rover restart to enable / disable RTCM for PPL + gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request receiver to use new settings + return (true); +} + // Periodically push GGA sentence over NTRIP Client, to Caster, if enabled // We must not push to the Caster while we are reading data from the Caster // See #695 diff --git a/Firmware/RTK_Everywhere/RTK_Everywhere.ino b/Firmware/RTK_Everywhere/RTK_Everywhere.ino index da9f0afdb..45af830b3 100644 --- a/Firmware/RTK_Everywhere/RTK_Everywhere.ino +++ b/Firmware/RTK_Everywhere/RTK_Everywhere.ino @@ -1464,8 +1464,8 @@ void loop() DMW_c("periodicDisplay"); updatePeriodicDisplay(); - DMW_c("gnss->update"); - gnss->update(); + DMW_c("gnssUpdate"); + gnssUpdate(); DMW_c("stateUpdate"); stateUpdate(); From 8364825342dfd5417bd779d75541d4f337aa6bca Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 9 Oct 2025 13:59:16 -0600 Subject: [PATCH 07/68] Add setNmeaMessageRateByName() for all platforms --- Firmware/RTK_Everywhere/GNSS.h | 2 ++ Firmware/RTK_Everywhere/GNSS_Mosaic.h | 3 +++ Firmware/RTK_Everywhere/GNSS_Mosaic.ino | 7 +++++++ Firmware/RTK_Everywhere/GNSS_None.h | 6 ++++++ Firmware/RTK_Everywhere/GNSS_ZED.h | 3 +++ Firmware/RTK_Everywhere/GNSS_ZED.ino | 7 +++++++ 6 files changed, 28 insertions(+) diff --git a/Firmware/RTK_Everywhere/GNSS.h b/Firmware/RTK_Everywhere/GNSS.h index 5628a90a4..a49f7ab67 100644 --- a/Firmware/RTK_Everywhere/GNSS.h +++ b/Firmware/RTK_Everywhere/GNSS.h @@ -347,6 +347,8 @@ class GNSS // elevationDegrees: The elevation value in degrees virtual bool setElevation(uint8_t elevationDegrees); + virtual bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); + // Enable all the valid messages for this platform virtual bool setMessages(int maxRetries); diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.h b/Firmware/RTK_Everywhere/GNSS_Mosaic.h index a2cace644..47e63202d 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.h +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.h @@ -1085,6 +1085,9 @@ class GNSS_MOSAIC : GNSS // modelNumber: Number of the model to use, provided by radio library bool setModel(uint8_t modelNumber); + // Given the name of a message, find it, and set the rate + bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); + bool setRadioBaudRate(uint32_t baud); // Specify the interval between solutions diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino index 063b0cbf3..72aeb9dcd 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino @@ -2494,6 +2494,13 @@ bool GNSS_MOSAIC::setModel(uint8_t modelNumber) return (sendWithResponse(setting, "ReceiverDynamics")); } +// Given the name of a message, find it, and set the rate +bool GNSS_MOSAIC::setNmeaMessageRateByName(const char *msgName, uint8_t msgRate) +{ + // TODO + return (false); +} + //---------------------------------------- bool GNSS_MOSAIC::setRadioBaudRate(uint32_t baud) { diff --git a/Firmware/RTK_Everywhere/GNSS_None.h b/Firmware/RTK_Everywhere/GNSS_None.h index 879804b6e..133a2513f 100644 --- a/Firmware/RTK_Everywhere/GNSS_None.h +++ b/Firmware/RTK_Everywhere/GNSS_None.h @@ -579,6 +579,12 @@ class GNSS_None : public GNSS return true; } + // Given the name of a message, find it, and set the rate + bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate) + { + return (true); + } + bool setRadioBaudRate(uint32_t baud) { return true; diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.h b/Firmware/RTK_Everywhere/GNSS_ZED.h index 79e6edd10..1a5414936 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.h +++ b/Firmware/RTK_Everywhere/GNSS_ZED.h @@ -712,6 +712,9 @@ class GNSS_ZED : GNSS // modelNumber: Number of the model to use, provided by radio library bool setModel(uint8_t modelNumber); + // Given the name of a message, find it, and set the rate + bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); + bool setRadioBaudRate(uint32_t baud); // Specify the interval between solutions diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index ddded33da..a1bc85009 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -2231,6 +2231,13 @@ bool GNSS_ZED::setMessageRateByName(const char *msgName, uint8_t msgRate) return (false); } +// Given the name of a message, find it, and set the rate +bool GNSS_ZED::setNmeaMessageRateByName(const char *msgName, uint8_t msgRate) +{ + // TODO + return (false); +} + //---------------------------------------- // Enable all the valid messages for this platform // There are many messages so split into batches. VALSET is limited to 64 max per batch From 678f6b484d1092c0be9ab94d932143ec68268c0c Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 9 Oct 2025 14:02:21 -0600 Subject: [PATCH 08/68] Extend command change callback to include setting name, data, and type. --- Firmware/RTK_Everywhere/GNSS.h | 4 ++-- Firmware/RTK_Everywhere/GNSS.ino | 28 ++---------------------- Firmware/RTK_Everywhere/menuCommands.ino | 4 ++-- Firmware/RTK_Everywhere/settings.h | 2 +- 4 files changed, 7 insertions(+), 31 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.h b/Firmware/RTK_Everywhere/GNSS.h index a49f7ab67..ca6e438e6 100644 --- a/Firmware/RTK_Everywhere/GNSS.h +++ b/Firmware/RTK_Everywhere/GNSS.h @@ -399,9 +399,9 @@ class GNSS }; // Update the constellations following a set command -bool gnssCmdUpdateConstellations(int commandIndex); +bool gnssCmdUpdateConstellations(const char *settingName, void *settingData, int settingType); // Update the message rates following a set command -bool gnssCmdUpdateMessageRates(int commandIndex); +bool gnssCmdUpdateMessageRates(const char *settingName, void *settingData, int settingType); #endif // __GNSS_H__ diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index c27e3c447..5495906ee 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -117,7 +117,6 @@ void gnssUpdate() // Test for individual changes as needed if (gnssConfigureRequest & UPDATE_CONSTELLATION) { - Serial.println("Update const"); } // Here we need a table to determine if the given combination of setting requests trigger a GNSS's NVM save @@ -252,7 +251,8 @@ void gnssDetectReceiverType() // Note: with this in place, the X5 detection will take a lot longer due to the baud rate change #ifdef FLEX_OVERRIDE systemPrintln("<<<<<<<<<< !!!!!!!!!! FLEX FORCED !!!!!!!!!! >>>>>>>>>>"); - // settings.detectedGnssReceiver = GNSS_RECEIVER_UNKNOWN; // This may be causing weirdness on the LG290P. Commenting for now + // settings.detectedGnssReceiver = GNSS_RECEIVER_UNKNOWN; // This may be causing weirdness on the LG290P. Commenting + // for now #endif // Start auto-detect if NVM is not yet set @@ -533,27 +533,3 @@ void gnssFirmwareRemoveUpdateFile(const char *filename) LittleFS.remove(filename); } } - -//---------------------------------------- -// Update the constellations following a set command -//---------------------------------------- -bool gnssCmdUpdateConstellations(int commandIndex) -{ - if (gnss == nullptr) - return false; - - return gnss->setConstellations(); -} - -//---------------------------------------- -// Update the message rates following a set command -//---------------------------------------- -bool gnssCmdUpdateMessageRates(int commandIndex) -{ - if (gnss == nullptr) - return false; - - return gnss->setMessages(MAX_SET_MESSAGES_RETRIES); -} - -//---------------------------------------- diff --git a/Firmware/RTK_Everywhere/menuCommands.ino b/Firmware/RTK_Everywhere/menuCommands.ino index 48bd3f03c..87ca25b72 100644 --- a/Firmware/RTK_Everywhere/menuCommands.ino +++ b/Firmware/RTK_Everywhere/menuCommands.ino @@ -1288,14 +1288,14 @@ SettingValueResponse updateSettingWithValue(bool inCommands, const char *setting { // Determine if extra work needs to be done when the setting changes if (rtkSettingsEntries[i].afterSetCmd) - rtkSettingsEntries[i].afterSetCmd(i); + rtkSettingsEntries[i].afterSetCmd(settingName, (void *)settingValueStr, (int)type); return (SETTING_KNOWN_STRING); } else if (knownSetting == true) { // Determine if extra work needs to be done when the setting changes if (rtkSettingsEntries[i].afterSetCmd) - rtkSettingsEntries[i].afterSetCmd(i); + rtkSettingsEntries[i].afterSetCmd(settingName, &settingValue, (int)type); return (SETTING_KNOWN); } } diff --git a/Firmware/RTK_Everywhere/settings.h b/Firmware/RTK_Everywhere/settings.h index 33efb9b1a..477fb1149 100644 --- a/Firmware/RTK_Everywhere/settings.h +++ b/Firmware/RTK_Everywhere/settings.h @@ -1203,7 +1203,7 @@ typedef enum MSM = L29, // Platforms which require parameter selection of MSM7 over MSM4 } Facet_Flex_Variant; -typedef bool (* AFTER_CMD)(int cmdIndex); +typedef bool (* AFTER_CMD)(const char *settingName, void *settingData, int settingType); typedef struct { From bd472bdccbc385bb2dec06197578d0011a48ae09 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 9 Oct 2025 14:02:55 -0600 Subject: [PATCH 09/68] Whitespace --- Firmware/RTK_Everywhere/GNSS_Mosaic.h | 402 +++++++++++--------------- Firmware/RTK_Everywhere/GNSS_None.h | 4 +- 2 files changed, 163 insertions(+), 243 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.h b/Firmware/RTK_Everywhere/GNSS_Mosaic.h index 47e63202d..73e92d851 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.h +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.h @@ -9,7 +9,8 @@ GNSS_Mosaic.h #include //http://librarymanager/All#SparkFun_Extensible_Message_Parser -typedef struct { +typedef struct +{ const uint16_t ID; const bool fixedLength; const uint16_t length; // Padded to modulo-4 @@ -17,13 +18,9 @@ typedef struct { } mosaicExpectedID; const mosaicExpectedID mosaicExpectedIDs[] = { - { 4007, true, 96, "PVTGeodetic" }, - { 4013, false, 0, "ChannelStatus" }, - { 4014, false, 0, "ReceiverStatus" }, - { 4059, false, 0, "DiskStatus" }, - { 4090, false, 0, "InputLink" }, - { 4097, false, 0, "EncapsulatedOutput" }, - { 5914, true, 24, "ReceiverTime" }, + {4007, true, 96, "PVTGeodetic"}, {4013, false, 0, "ChannelStatus"}, {4014, false, 0, "ReceiverStatus"}, + {4059, false, 0, "DiskStatus"}, {4090, false, 0, "InputLink"}, {4097, false, 0, "EncapsulatedOutput"}, + {5914, true, 24, "ReceiverTime"}, }; #define MAX_MOSAIC_EXPECTED_SBF (sizeof(mosaicExpectedIDs) / sizeof(mosaicExpectedID)) @@ -34,7 +31,7 @@ const mosaicExpectedID mosaicExpectedIDs[] = { // We actually need four times this many as COM1, COM2, USB1 and DSK1 all need their own individual streams // COM1 uses streams 1 & 2; COM2 uses 3 & 4; USB1 uses 5 & 6; DSK1 uses 7 & 8 #define MOSAIC_NUM_NMEA_STREAMS 2 // X5 supports 10 streams in total -#define MOSAIC_DEFAULT_NMEA_STREAM_INTERVALS {MOSAIC_MSG_RATE_MSEC500,MOSAIC_MSG_RATE_SEC1} +#define MOSAIC_DEFAULT_NMEA_STREAM_INTERVALS {MOSAIC_MSG_RATE_MSEC500, MOSAIC_MSG_RATE_SEC1} // Output SBF PVTGeodetic and ReceiverTime on this stream - on COM1 only // The SBFOutput streams are separate to the NMEAOutput streams. It is OK to start at Stream1. @@ -64,7 +61,8 @@ const mosaicExpectedID mosaicExpectedIDs[] = { // eccf,RxDefault,Boot // eccf,RxDefault,Current -enum mosaicFileDuration_e { +enum mosaicFileDuration_e +{ MOSAIC_FILE_DURATION_HOUR1 = 0, MOSAIC_FILE_DURATION_HOUR6, MOSAIC_FILE_DURATION_HOUR24, @@ -82,15 +80,16 @@ typedef struct } mosaicFileDuration; const mosaicFileDuration mosaicFileDurations[] = { - { "hour1", "IGS1H", "1h", 60 }, - { "hour6", "IGS6H", "6h", 360 }, - { "hour24", "IGS24H", "24h", 1440 }, - { "minute15", "IGS15M", "15min", 15 }, + {"hour1", "IGS1H", "1h", 60}, + {"hour6", "IGS6H", "6h", 360}, + {"hour24", "IGS24H", "24h", 1440}, + {"minute15", "IGS15M", "15min", 15}, }; #define MAX_MOSAIC_FILE_DURATIONS (sizeof(mosaicFileDurations) / sizeof(mosaicFileDuration)) -enum mosaicObsInterval_e { +enum mosaicObsInterval_e +{ MOSAIC_OBS_INTERVAL_SEC1 = 0, MOSAIC_OBS_INTERVAL_SEC2, MOSAIC_OBS_INTERVAL_SEC5, @@ -110,18 +109,14 @@ typedef struct } mosaicObsInterval; const mosaicObsInterval mosaicObsIntervals[] = { - { "sec1", "1s", 1 }, - { "sec2", "2s", 2 }, - { "sec5", "5s", 5 }, - { "sec10", "10s", 10 }, - { "sec15", "15s", 15 }, - { "sec30", "30s", 30 }, - { "sec60", "60s", 60 }, + {"sec1", "1s", 1}, {"sec2", "2s", 2}, {"sec5", "5s", 5}, {"sec10", "10s", 10}, + {"sec15", "15s", 15}, {"sec30", "30s", 30}, {"sec60", "60s", 60}, }; #define MAX_MOSAIC_OBS_INTERVALS (sizeof(mosaicObsIntervals) / sizeof(mosaicObsInterval)) -enum mosaicCOMBaud { +enum mosaicCOMBaud +{ MOSAIC_COM_RATE_BAUD4800 = 0, MOSAIC_COM_RATE_BAUD9600, MOSAIC_COM_RATE_BAUD19200, @@ -143,20 +138,15 @@ typedef struct } mosaicComRate; const mosaicComRate mosaicComRates[] = { - { "baud4800", 4800 }, - { "baud9600", 9600 }, - { "baud19200", 19200 }, - { "baud38400", 38400 }, - { "baud57600", 57600 }, - { "baud115200", 115200 }, - { "baud230400", 230400 }, - { "baud460800", 460800 }, - { "baud921600", 921600 }, + {"baud4800", 4800}, {"baud9600", 9600}, {"baud19200", 19200}, + {"baud38400", 38400}, {"baud57600", 57600}, {"baud115200", 115200}, + {"baud230400", 230400}, {"baud460800", 460800}, {"baud921600", 921600}, }; #define MAX_MOSAIC_COM_RATES (sizeof(mosaicComRates) / sizeof(mosaicComRate)) -enum mosaicPpsIntervals { +enum mosaicPpsIntervals +{ // OFF is dealt with by settings.enableExternalPulse MOSAIC_PPS_INTERVAL_MSEC10 = 0, MOSAIC_PPS_INTERVAL_MSEC20, @@ -185,25 +175,17 @@ typedef struct } mosaicPPSInterval; const mosaicPPSInterval mosaicPPSIntervals[] = { - { "msec10", "10ms", 10000 }, - { "msec20", "20ms", 20000 }, - { "msec50", "50ms", 50000 }, - { "msec100", "100ms", 100000 }, - { "msec200", "200ms", 200000 }, - { "msec250", "250ms", 250000 }, - { "msec500", "500ms", 500000 }, - { "sec1", "1s", 1000000 }, - { "sec2", "2s", 2000000 }, - { "sec4", "4s", 4000000 }, - { "sec5", "5s", 5000000 }, - { "sec10", "10s", 10000000 }, - { "sec30", "30s", 30000000 }, - { "sec60", "60s", 60000000 }, + {"msec10", "10ms", 10000}, {"msec20", "20ms", 20000}, {"msec50", "50ms", 50000}, + {"msec100", "100ms", 100000}, {"msec200", "200ms", 200000}, {"msec250", "250ms", 250000}, + {"msec500", "500ms", 500000}, {"sec1", "1s", 1000000}, {"sec2", "2s", 2000000}, + {"sec4", "4s", 4000000}, {"sec5", "5s", 5000000}, {"sec10", "10s", 10000000}, + {"sec30", "30s", 30000000}, {"sec60", "60s", 60000000}, }; #define MAX_MOSAIC_PPS_INTERVALS (sizeof(mosaicPPSIntervals) / sizeof(mosaicPPSInterval)) -enum mosaicConstellations { +enum mosaicConstellations +{ MOSAIC_SIGNAL_CONSTELLATION_GPS = 0, MOSAIC_SIGNAL_CONSTELLATION_GLONASS, MOSAIC_SIGNAL_CONSTELLATION_GALILEO, @@ -224,13 +206,8 @@ typedef struct // Constellations monitored/used for fix const mosaicSignalConstellation mosaicSignalConstellations[] = { - {"GPS","GPS"}, - {"GLONASS","GLONASS"}, - {"GALILEO","Galileo"}, - {"SBAS","SBAS"}, - {"BEIDOU","BeiDou"}, - {"QZSS","QZSS"}, - {"NAVIC","NavIC"}, + {"GPS", "GPS"}, {"GLONASS", "GLONASS"}, {"GALILEO", "Galileo"}, {"SBAS", "SBAS"}, + {"BEIDOU", "BeiDou"}, {"QZSS", "QZSS"}, {"NAVIC", "NavIC"}, }; #define MAX_MOSAIC_CONSTELLATIONS (sizeof(mosaicSignalConstellations) / sizeof(mosaicSignalConstellation)) @@ -238,7 +215,8 @@ const mosaicSignalConstellation mosaicSignalConstellations[] = { // Enum to define message output rates // Don't allow rate to be "off" // If the user wants to disable a message, the stream (mosaicStreamIntervalsNMEA etc.) should be set to 0 instead -enum mosaicMessageRates { +enum mosaicMessageRates +{ // MOSAIC_MSG_RATE_OFF = 0, // MOSAIC_MSG_RATE_ONCHANGE, MOSAIC_MSG_RATE_MSEC10 = 0, @@ -276,26 +254,10 @@ typedef struct const mosaicMsgRate mosaicMsgRates[] = { // { "off"}, // { "OnChange"}, - { "msec10", "10ms" }, - { "msec20", "20ms" }, - { "msec40", "40ms" }, - { "msec50", "50ms" }, - { "msec100", "100ms" }, - { "msec200", "200ms" }, - { "msec500", "500ms" }, - { "sec1", "1s" }, - { "sec2", "2s" }, - { "sec5", "5s" }, - { "sec10", "10s" }, - { "sec15", "15s" }, - { "sec30", "30s" }, - { "sec60", "60s" }, - { "min2", "2min" }, - { "min5", "5min" }, - { "min10", "10min" }, - { "min15", "15min" }, - { "min30", "30min" }, - { "min60", "60min" }, + {"msec10", "10ms"}, {"msec20", "20ms"}, {"msec40", "40ms"}, {"msec50", "50ms"}, {"msec100", "100ms"}, + {"msec200", "200ms"}, {"msec500", "500ms"}, {"sec1", "1s"}, {"sec2", "2s"}, {"sec5", "5s"}, + {"sec10", "10s"}, {"sec15", "15s"}, {"sec30", "30s"}, {"sec60", "60s"}, {"min2", "2min"}, + {"min5", "5min"}, {"min10", "10min"}, {"min15", "15min"}, {"min30", "30min"}, {"min60", "60min"}, }; // Check MAX_MOSAIC_MSG_RATES == MOSAIC_NUM_MSG_RATES @@ -314,16 +276,10 @@ typedef struct // Stream 0 is off; stream 1 defaults to MSEC500; stream 2 defaults to SEC1 const mosaicNMEAMsg mosaicMessagesNMEA[] = { // NMEA - {"ALM", 0}, {"AVR", 0}, {"DTM", 0}, - {"GBS", 0}, {"GFA", 0}, {"GGA", 1}, - {"GGK", 0}, {"GGQ", 0}, {"GLL", 0}, - {"GMP", 0}, {"GNS", 0}, {"GRS", 0}, - {"GSA", 1}, {"GST", 1}, {"GSV", 2}, - {"HDT", 0}, {"HRP", 0}, {"LLK", 0}, - {"LLQ", 0}, {"RBD", 0}, {"RBP", 0}, - {"RBV", 0}, {"RMC", 1}, {"ROT", 0}, - {"SNC", 0}, {"TFM", 0}, {"THS", 0}, - {"TXTbase", 0}, {"VTG", 0}, {"ZDA", 0}, + {"ALM", 0}, {"AVR", 0}, {"DTM", 0}, {"GBS", 0}, {"GFA", 0}, {"GGA", 1}, {"GGK", 0}, {"GGQ", 0}, + {"GLL", 0}, {"GMP", 0}, {"GNS", 0}, {"GRS", 0}, {"GSA", 1}, {"GST", 1}, {"GSV", 2}, {"HDT", 0}, + {"HRP", 0}, {"LLK", 0}, {"LLQ", 0}, {"RBD", 0}, {"RBP", 0}, {"RBV", 0}, {"RMC", 1}, {"ROT", 0}, + {"SNC", 0}, {"TFM", 0}, {"THS", 0}, {"TXTbase", 0}, {"VTG", 0}, {"ZDA", 0}, }; #define MAX_MOSAIC_NMEA_MSG (sizeof(mosaicMessagesNMEA) / sizeof(mosaicNMEAMsg)) @@ -357,7 +313,8 @@ const mosaicRTCMv2Msg mosaicMessagesRTCMv2[] = { */ -enum mosaicRTCMv3IntervalGroups { +enum mosaicRTCMv3IntervalGroups +{ MOSAIC_RTCM_V3_INTERVAL_GROUP_RTCM1001_2 = 0, MOSAIC_RTCM_V3_INTERVAL_GROUP_RTCM1003_4, MOSAIC_RTCM_V3_INTERVAL_GROUP_RTCM1005_6, @@ -392,32 +349,15 @@ typedef struct } mosaicRTCMv3MsgIntervalGroup; const mosaicRTCMv3MsgIntervalGroup mosaicRTCMv3MsgIntervalGroups[] = { - { "RTCM1001|2", 1.0 }, - { "RTCM1003|4", 1.0 }, - { "RTCM1005|6", 1.0 }, - { "RTCM1007|8", 1.0 }, - { "RTCM1009|10", 1.0 }, - { "RTCM1011|12", 1.0 }, - { "RTCM1013", 1.0 }, - { "RTCM1019", 1.0 }, - { "RTCM1020", 1.0 }, - { "RTCM1029", 1.0 }, - { "RTCM1033", 10.0 }, - { "RTCM1042", 1.0 }, - { "RTCM1044", 1.0 }, - { "RTCM1045", 1.0 }, - { "RTCM1046", 1.0 }, - { "MSM1", 1.0 }, - { "MSM2", 1.0 }, - { "MSM3", 1.0 }, - { "MSM4", 1.0 }, - { "MSM5", 1.0 }, - { "MSM6", 1.0 }, - { "MSM7", 1.0 }, - { "RTCM1230", 1.0 }, + {"RTCM1001|2", 1.0}, {"RTCM1003|4", 1.0}, {"RTCM1005|6", 1.0}, {"RTCM1007|8", 1.0}, {"RTCM1009|10", 1.0}, + {"RTCM1011|12", 1.0}, {"RTCM1013", 1.0}, {"RTCM1019", 1.0}, {"RTCM1020", 1.0}, {"RTCM1029", 1.0}, + {"RTCM1033", 10.0}, {"RTCM1042", 1.0}, {"RTCM1044", 1.0}, {"RTCM1045", 1.0}, {"RTCM1046", 1.0}, + {"MSM1", 1.0}, {"MSM2", 1.0}, {"MSM3", 1.0}, {"MSM4", 1.0}, {"MSM5", 1.0}, + {"MSM6", 1.0}, {"MSM7", 1.0}, {"RTCM1230", 1.0}, }; -#define MAX_MOSAIC_RTCM_V3_INTERVAL_GROUPS (sizeof(mosaicRTCMv3MsgIntervalGroups) / sizeof(mosaicRTCMv3MsgIntervalGroup)) +#define MAX_MOSAIC_RTCM_V3_INTERVAL_GROUPS \ + (sizeof(mosaicRTCMv3MsgIntervalGroups) / sizeof(mosaicRTCMv3MsgIntervalGroup)) typedef struct { @@ -456,57 +396,57 @@ const mosaicRTCMv3Msg mosaicMessagesRTCMv3[] = { {"MSM5", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM5, false}, {"MSM6", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM6, false}, {"MSM7", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM7, false}, -/* - {"RTCM1071", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM1, false}, - {"RTCM1072", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM2, false}, - {"RTCM1073", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM3, false}, - {"RTCM1074", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM4, false}, - {"RTCM1075", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM5, false}, - {"RTCM1076", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM6, false}, - {"RTCM1077", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM7, false}, - {"RTCM1081", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM1, false}, - {"RTCM1082", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM2, false}, - {"RTCM1083", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM3, false}, - {"RTCM1084", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM4, false}, - {"RTCM1085", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM5, false}, - {"RTCM1086", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM6, false}, - {"RTCM1087", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM7, false}, - {"RTCM1091", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM1, false}, - {"RTCM1092", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM2, false}, - {"RTCM1093", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM3, false}, - {"RTCM1094", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM4, false}, - {"RTCM1095", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM5, false}, - {"RTCM1096", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM6, false}, - {"RTCM1097", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM7, false}, - {"RTCM1101", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM1, false}, - {"RTCM1102", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM2, false}, - {"RTCM1103", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM3, false}, - {"RTCM1104", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM4, false}, - {"RTCM1105", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM5, false}, - {"RTCM1106", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM6, false}, - {"RTCM1107", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM7, false}, - {"RTCM1111", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM1, false}, - {"RTCM1112", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM2, false}, - {"RTCM1113", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM3, false}, - {"RTCM1114", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM4, false}, - {"RTCM1115", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM5, false}, - {"RTCM1116", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM6, false}, - {"RTCM1117", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM7, false}, - {"RTCM1121", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM1, false}, - {"RTCM1122", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM2, false}, - {"RTCM1123", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM3, false}, - {"RTCM1124", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM4, false}, - {"RTCM1125", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM5, false}, - {"RTCM1126", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM6, false}, - {"RTCM1127", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM7, false}, - {"RTCM1131", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM1, false}, - {"RTCM1132", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM2, false}, - {"RTCM1133", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM3, false}, - {"RTCM1134", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM4, false}, - {"RTCM1135", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM5, false}, - {"RTCM1136", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM6, false}, - {"RTCM1137", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM7, false}, -*/ + /* + {"RTCM1071", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM1, false}, + {"RTCM1072", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM2, false}, + {"RTCM1073", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM3, false}, + {"RTCM1074", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM4, false}, + {"RTCM1075", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM5, false}, + {"RTCM1076", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM6, false}, + {"RTCM1077", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM7, false}, + {"RTCM1081", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM1, false}, + {"RTCM1082", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM2, false}, + {"RTCM1083", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM3, false}, + {"RTCM1084", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM4, false}, + {"RTCM1085", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM5, false}, + {"RTCM1086", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM6, false}, + {"RTCM1087", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM7, false}, + {"RTCM1091", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM1, false}, + {"RTCM1092", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM2, false}, + {"RTCM1093", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM3, false}, + {"RTCM1094", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM4, false}, + {"RTCM1095", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM5, false}, + {"RTCM1096", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM6, false}, + {"RTCM1097", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM7, false}, + {"RTCM1101", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM1, false}, + {"RTCM1102", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM2, false}, + {"RTCM1103", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM3, false}, + {"RTCM1104", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM4, false}, + {"RTCM1105", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM5, false}, + {"RTCM1106", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM6, false}, + {"RTCM1107", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM7, false}, + {"RTCM1111", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM1, false}, + {"RTCM1112", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM2, false}, + {"RTCM1113", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM3, false}, + {"RTCM1114", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM4, false}, + {"RTCM1115", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM5, false}, + {"RTCM1116", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM6, false}, + {"RTCM1117", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM7, false}, + {"RTCM1121", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM1, false}, + {"RTCM1122", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM2, false}, + {"RTCM1123", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM3, false}, + {"RTCM1124", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM4, false}, + {"RTCM1125", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM5, false}, + {"RTCM1126", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM6, false}, + {"RTCM1127", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM7, false}, + {"RTCM1131", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM1, false}, + {"RTCM1132", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM2, false}, + {"RTCM1133", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM3, false}, + {"RTCM1134", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM4, false}, + {"RTCM1135", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM5, false}, + {"RTCM1136", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM6, false}, + {"RTCM1137", MOSAIC_RTCM_V3_INTERVAL_GROUP_MSM7, false}, + */ {"RTCM1230", MOSAIC_RTCM_V3_INTERVAL_GROUP_RTCM1230, false}, }; @@ -533,14 +473,14 @@ typedef struct } mosaicReceiverDynamic; const mosaicReceiverDynamic mosaicReceiverDynamics[] = { - { "Static", "Static" }, - { "Quasistatic","Quasistatic" }, - { "Pedestrian","Pedestrian" }, - { "Automotive", "Automotive" }, - { "RaceCar", "Race Car" }, - { "HeavyMachinery", "Heavy Machinery" }, - { "UAV", "UAV" }, - { "Unlimited", "Unlimited" }, + {"Static", "Static"}, + {"Quasistatic", "Quasistatic"}, + {"Pedestrian", "Pedestrian"}, + {"Automotive", "Automotive"}, + {"RaceCar", "Race Car"}, + {"HeavyMachinery", "Heavy Machinery"}, + {"UAV", "UAV"}, + {"Unlimited", "Unlimited"}, }; #define MAX_MOSAIC_RX_DYNAMICS (sizeof(mosaicReceiverDynamics) / sizeof(mosaicReceiverDynamic)) @@ -550,23 +490,23 @@ bool mosaicX5waitCR(unsigned long timeout = 25); // Header class GNSS_MOSAIC : GNSS { - // The mosaic-X5 does not have self-contained interface library. - // But the ZED-F9P, UM980 and LG290P all do. - // On the X5, we communicate manually over serial2GNSS using functions like - // sendWithResponse and sendAndWaitForIdle. - // In essence, the interface library is wholly contained in this class. - // TODO: consider breaking the mosaic comms functions out into their own library - // and add a private library class instance here. + // The mosaic-X5 does not have self-contained interface library. + // But the ZED-F9P, UM980 and LG290P all do. + // On the X5, we communicate manually over serial2GNSS using functions like + // sendWithResponse and sendAndWaitForIdle. + // In essence, the interface library is wholly contained in this class. + // TODO: consider breaking the mosaic comms functions out into their own library + // and add a private library class instance here. protected: // Flag which indicates GNSS is blocking (needs exclusive access to the UART) bool _isBlocking = false; // These globals are updated regularly via the SBF parser - double _clkBias_ms; // PVTGeodetic RxClkBias (will be sawtooth unless clock steering is enabled) + double _clkBias_ms; // PVTGeodetic RxClkBias (will be sawtooth unless clock steering is enabled) bool _determiningFixedPosition; // PVTGeodetic Mode Bit 6 - bool _antennaIsOpen; // ReceiverStatus RxState Bit 1 ACTIVEANTENNA indicates antenna current draw - bool _antennaIsShorted; // ReceiverStatus RxError Bit 5 ANTENNA indicates antenna overcurrent + bool _antennaIsOpen; // ReceiverStatus RxState Bit 1 ACTIVEANTENNA indicates antenna current draw + bool _antennaIsShorted; // ReceiverStatus RxError Bit 5 ANTENNA indicates antenna overcurrent // Record NrBytesReceived so we can tell if Radio Ext (COM2) is receiving correction data. // On the mosaic, we know that InputLink will arrive at 1Hz. But on the ZED, UBX-MON-COMMS @@ -587,15 +527,14 @@ class GNSS_MOSAIC : GNSS bool configureGNSS(); // Set the minimum satellite signal level for navigation. - bool setMinCnoRadio (uint8_t cnoValue); + bool setMinCnoRadio(uint8_t cnoValue); public: - // Allow access from parser routines - float _latStdDev; - float _lonStdDev; - bool _receiverSetupSeen; - bool _diskStatusSeen; + float _latStdDev; + float _lonStdDev; + bool _receiverSetupSeen; + bool _diskStatusSeen; struct svTracking_t { uint8_t SVID; @@ -607,8 +546,10 @@ class GNSS_MOSAIC : GNSS struct find_sv { uint8_t findThisSv; - find_sv(uint8_t sv) : findThisSv(sv) {} - bool operator () (const svTracking_t& m) const + find_sv(uint8_t sv) : findThisSv(sv) + { + } + bool operator()(const svTracking_t &m) const { return m.SVID == findThisSv; } @@ -618,19 +559,20 @@ class GNSS_MOSAIC : GNSS { const unsigned long expireAfter_millis = 2000; unsigned long millisNow; - find_stale_sv(unsigned long now) : millisNow(now) {} - bool operator () (const svTracking_t& m) const + find_stale_sv(unsigned long now) : millisNow(now) + { + } + bool operator()(const svTracking_t &m) const { return (millisNow > (m.lastSeen + expireAfter_millis)); } }; // Constructor - GNSS_MOSAIC() : _determiningFixedPosition(true), _clkBias_ms(0), - _latStdDev(999.9), _lonStdDev(999.9), _receiverSetupSeen(false), - _radioExtBytesReceived_millis(0), _diskStatusSeen(false), - _antennaIsOpen(false), _antennaIsShorted(false), - GNSS() + GNSS_MOSAIC() + : _determiningFixedPosition(true), _clkBias_ms(0), _latStdDev(999.9), _lonStdDev(999.9), + _receiverSetupSeen(false), _radioExtBytesReceived_millis(0), _diskStatusSeen(false), _antennaIsOpen(false), + _antennaIsShorted(false), GNSS() { svInTracking.clear(); } @@ -649,7 +591,7 @@ class GNSS_MOSAIC : GNSS bool baudIsAllowed(uint32_t baudRate); uint32_t baudGetMinimum(); uint32_t baudGetMaximum(); - + // Connect to GNSS and identify particulars void begin(); @@ -743,7 +685,10 @@ class GNSS_MOSAIC : GNSS uint8_t getActiveMessageCount(); // Return the number of active/enabled RTCM messages - uint8_t getActiveRtcmMessageCount() {return(0);} + uint8_t getActiveRtcmMessageCount() + { + return (0); + } // Get the altitude // Outputs: @@ -780,7 +725,7 @@ class GNSS_MOSAIC : GNSS // Returns the horizontal position accuracy or zero if offline float getHorizontalAccuracy(); - const char * getId(); + const char *getId(); // Get the latitude value // Outputs: @@ -821,9 +766,9 @@ class GNSS_MOSAIC : GNSS // Returns the seconds between solutions double getRateS(); - const char * getRtcmDefaultString(); + const char *getRtcmDefaultString(); - const char * getRtcmLowDataRateString(); + const char *getRtcmLowDataRateString(); // Given the name of a message, return the array number int getRtcmMessageNumberByName(const char *msgName); @@ -887,7 +832,8 @@ class GNSS_MOSAIC : GNSS // Send commands out the UART to see if a mosaic module is present bool isPresent(); - bool isPresentOnSerial(HardwareSerial *serialPort, const char *command, const char *response, const char *console, int retryLimit = 20); + bool isPresentOnSerial(HardwareSerial *serialPort, const char *command, const char *response, const char *console, + int retryLimit = 20); bool mosaicIsPresentOnFlex(); // Some functions (L-Band area frequency determination) merely need @@ -965,21 +911,12 @@ class GNSS_MOSAIC : GNSS // responseSize: Maximum number of bytes to copy // Outputs: // Returns true if the response was received and false upon failure - bool sendAndWaitForIdle(const char *message, - const char *reply, - unsigned long timeout = 1000, - unsigned long idle = 25, - char *response = nullptr, - size_t responseSize = 0, - bool debug = true); - bool sendAndWaitForIdle(HardwareSerial *serialPort, - const char *message, - const char *reply, - unsigned long timeout = 1000, - unsigned long idle = 25, - char *response = nullptr, - size_t responseSize = 0, + bool sendAndWaitForIdle(const char *message, const char *reply, unsigned long timeout = 1000, + unsigned long idle = 25, char *response = nullptr, size_t responseSize = 0, bool debug = true); + bool sendAndWaitForIdle(HardwareSerial *serialPort, const char *message, const char *reply, + unsigned long timeout = 1000, unsigned long idle = 25, char *response = nullptr, + size_t responseSize = 0, bool debug = true); // Send message. Wait for up to timeout millis for reply to arrive // If the reply is received, keep reading bytes until the serial port has @@ -994,13 +931,8 @@ class GNSS_MOSAIC : GNSS // responseSize: Maximum number of bytes to copy // Outputs: // Returns true if the response was received and false upon failure - bool sendAndWaitForIdle(String message, - const char *reply, - unsigned long timeout = 1000, - unsigned long idle = 25, - char *response = nullptr, - size_t responseSize = 0, - bool debug = true); + bool sendAndWaitForIdle(String message, const char *reply, unsigned long timeout = 1000, unsigned long idle = 25, + char *response = nullptr, size_t responseSize = 0, bool debug = true); // Send message. Wait for up to timeout millis for reply to arrive // If the reply has started to be received when timeout is reached, wait for a further wait millis @@ -1016,18 +948,10 @@ class GNSS_MOSAIC : GNSS // responseSize: Maximum number of bytes to copy // Outputs: // Returns true if the response was received and false upon failure - bool sendWithResponse(const char *message, - const char *reply, - unsigned long timeout = 1000, - unsigned long wait = 25, - char *response = nullptr, - size_t responseSize = 0); - bool sendWithResponse(HardwareSerial *serialPort, - const char *message, - const char *reply, - unsigned long timeout = 1000, - unsigned long wait = 25, - char *response = nullptr, + bool sendWithResponse(const char *message, const char *reply, unsigned long timeout = 1000, unsigned long wait = 25, + char *response = nullptr, size_t responseSize = 0); + bool sendWithResponse(HardwareSerial *serialPort, const char *message, const char *reply, + unsigned long timeout = 1000, unsigned long wait = 25, char *response = nullptr, size_t responseSize = 0); // Send message. Wait for up to timeout millis for reply to arrive @@ -1043,12 +967,8 @@ class GNSS_MOSAIC : GNSS // responseSize: Maximum number of bytes to copy // Outputs: // Returns true if the response was received and false upon failure - bool sendWithResponse(String message, - const char *reply, - unsigned long timeout = 1000, - unsigned long wait = 25, - char *response = nullptr, - size_t responseSize = 0); + bool sendWithResponse(String message, const char *reply, unsigned long timeout = 1000, unsigned long wait = 25, + char *response = nullptr, size_t responseSize = 0); // Set the baud rate of mosaic-X5 COM1 // This is used during the Bluetooth test @@ -1145,4 +1065,4 @@ class GNSS_MOSAIC : GNSS void waitSBFReceiverSetup(HardwareSerial *serialPort, unsigned long timeout); }; -#endif // __GNSS_MOSAIC_H__ +#endif // __GNSS_MOSAIC_H__ diff --git a/Firmware/RTK_Everywhere/GNSS_None.h b/Firmware/RTK_Everywhere/GNSS_None.h index 133a2513f..238e6579e 100644 --- a/Firmware/RTK_Everywhere/GNSS_None.h +++ b/Firmware/RTK_Everywhere/GNSS_None.h @@ -9,7 +9,7 @@ GNSS_None.h class GNSS_None : public GNSS { -protected: + protected: // Setup the general configuration of the GNSS // Not Rover or Base specific (ie, baud rates) // Outputs: @@ -25,7 +25,7 @@ class GNSS_None : public GNSS return false; } -public: + public: // Constructor GNSS_None() : GNSS() { From 92e5f3d28669f349a19a61fd3d48ca5b74f69fbf Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 9 Oct 2025 14:04:11 -0600 Subject: [PATCH 10/68] Replace restartRover/Base bools with gnssConfigureRequest. This is a large, potentially breaking change. --- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 42 +++++++---- Firmware/RTK_Everywhere/GNSS_Mosaic.ino | 84 +++++++++++---------- Firmware/RTK_Everywhere/GNSS_UM980.ino | 17 ++--- Firmware/RTK_Everywhere/RTK_Everywhere.ino | 2 - Firmware/RTK_Everywhere/menuBase.ino | 88 +++++++++++++++------- Firmware/RTK_Everywhere/menuGNSS.ino | 24 +++--- Firmware/RTK_Everywhere/menuMain.ino | 21 +----- Firmware/RTK_Everywhere/menuMessages.ino | 7 +- Firmware/RTK_Everywhere/menuPP.ino | 4 +- Firmware/RTK_Everywhere/menuPorts.ino | 27 +++---- 10 files changed, 166 insertions(+), 150 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index bc8e432f1..08595983f 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -862,8 +862,7 @@ bool GNSS_LG290P::enableRTCMBase() // PQTMCFGRTCM fails to respond with OK over UART2 of LG290P, so don't look for it char cfgRtcm[40]; snprintf(cfgRtcm, sizeof(cfgRtcm), "PQTMCFGRTCM,W,%c,0,-90,07,06,2,1", settings.useMSM7 ? '7' : '4'); - _lg290p->sendOkCommand( - cfgRtcm); // Enable MSM4/7, output regular intervals, interval (seconds) + _lg290p->sendOkCommand(cfgRtcm); // Enable MSM4/7, output regular intervals, interval (seconds) } return (response); @@ -1023,8 +1022,8 @@ bool GNSS_LG290P::enableRTCMRover() // Set MSM_ElevThd to 15 degrees from rftop suggestion char msmCommand[40] = {0}; - snprintf(msmCommand, sizeof(msmCommand), "PQTMCFGRTCM,W,%c,0,15,07,06,2,%d", - settings.useMSM7 ? '7' : '4', minimumRtcmRate); + snprintf(msmCommand, sizeof(msmCommand), "PQTMCFGRTCM,W,%c,0,15,07,06,2,%d", settings.useMSM7 ? '7' : '4', + minimumRtcmRate); // PQTMCFGRTCM fails to respond with OK over UART2 of LG290P, so don't look for it _lg290p->sendOkCommand(msmCommand); @@ -1870,10 +1869,12 @@ void GNSS_LG290P::menuConstellations() incoming--; // Align choice to constellation array of 0 to 5 settings.lg290pConstellations[incoming] ^= 1; + gnssConfigureRequest |= UPDATE_CONSTELLATION; // Reconfigure receiver } else if ((incoming == MAX_LG290P_CONSTELLATIONS + 1) && present.galileoHasCapable) { settings.enableGalileoHas ^= 1; + gnssConfigureRequest |= UPDATE_HAS_E6; // Reconfigure receiver } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) break; @@ -1918,7 +1919,6 @@ void GNSS_LG290P::menuMessages() systemPrintln("11) Reset to PPP Logging (NMEAx7 / RTCMx4 - 30 second decimation)"); systemPrintln("12) Reset to High-rate PPP Logging (NMEAx7 / RTCMx4 - 1Hz)"); - if (namedSettingAvailableOnPlatform("useMSM7")) // Redundant - but good practice for code reuse systemPrintf("13) MSM Selection: MSM%c\r\n", settings.useMSM7 ? '7' : '4'); @@ -1952,6 +1952,8 @@ void GNSS_LG290P::menuMessages() for (int x = 0; x < MAX_LG290P_PQTM_MSG; x++) settings.lg290pMessageRatesPQTM[x] = lgMessagesPQTM[x].msgDefaultRate; + gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request update + systemPrintln("Reset to Defaults"); } else if (incoming == 11 || incoming == 12) @@ -1994,9 +1996,15 @@ void GNSS_LG290P::menuMessages() { systemPrintln("Reset to PPP Logging Defaults (NMEAx7 / RTCMx4 - 30 second decimation)"); } + + gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request update } - else if ((incoming == 13) && (namedSettingAvailableOnPlatform("useMSM7"))) // Redundant - but good practice for code reuse) + else if ((incoming == 13) && + (namedSettingAvailableOnPlatform("useMSM7"))) // Redundant - but good practice for code reuse) + { settings.useMSM7 ^= 1; + gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request update + } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) break; @@ -2008,12 +2016,6 @@ void GNSS_LG290P::menuMessages() clearBuffer(); // Empty buffer of any newline chars - // Apply these changes at menu exit - if (inRoverMode()) - restartRover = true; - else - restartBase = true; - setLoggingType(); // Determine if we are standard, PPP, or custom. Changes logging icon accordingly. } @@ -2121,22 +2123,34 @@ void GNSS_LG290P::menuMessagesSubtype(int *localMessageRate, const char *message if (strcmp(messageType, "NMEA") == 0) { if (getNewSetting(messageString, 0, 1, &newSetting) == INPUT_RESPONSE_VALID) + { settings.lg290pMessageRatesNMEA[incoming] = newSetting; + gnssConfigureRequest |= UPDATE_MESSAGE_RATE_NMEA; + } } if (strcmp(messageType, "RTCMRover") == 0) { if (getNewSetting(messageString, 0, 1200, &newSetting) == INPUT_RESPONSE_VALID) + { settings.lg290pMessageRatesRTCMRover[incoming] = newSetting; + gnssConfigureRequest |= UPDATE_MESSAGE_RATE_RTCM_ROVER; + } } if (strcmp(messageType, "RTCMBase") == 0) { if (getNewSetting(messageString, 0, 1200, &newSetting) == INPUT_RESPONSE_VALID) + { settings.lg290pMessageRatesRTCMBase[incoming] = newSetting; + gnssConfigureRequest |= UPDATE_MESSAGE_RATE_RTCM_BASE; + } } if (strcmp(messageType, "PQTM") == 0) { if (getNewSetting(messageString, 0, 1, &newSetting) == INPUT_RESPONSE_VALID) + { settings.lg290pMessageRatesPQTM[incoming] = newSetting; + gnssConfigureRequest |= UPDATE_MESSAGE_RATE; + } } } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) @@ -2147,10 +2161,6 @@ void GNSS_LG290P::menuMessagesSubtype(int *localMessageRate, const char *message printUnknown(incoming); } - settings.gnssConfiguredOnce = false; // Update the GNSS config at the next boot - settings.gnssConfiguredBase = false; - settings.gnssConfiguredRover = false; - clearBuffer(); // Empty buffer of any newline chars } diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino index 72aeb9dcd..dd2a8d8e1 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino @@ -251,7 +251,7 @@ void GNSS_MOSAIC::begin() return; } - if(isPresent() == false) //Detect if the module is present + if (isPresent() == false) // Detect if the module is present return; int retries = 0; @@ -309,7 +309,7 @@ void GNSS_MOSAIC::begin() return; } - if(isPresent() == false) //Detect if the module is present + if (isPresent() == false) // Detect if the module is present return; // Set COM2 (Radio) and COM3 (Data) baud rates @@ -1833,6 +1833,8 @@ void GNSS_MOSAIC::menuMessagesNMEA() settings.mosaicMessageStreamNMEA[incoming] += 1; if (settings.mosaicMessageStreamNMEA[incoming] > MOSAIC_NUM_NMEA_STREAMS) settings.mosaicMessageStreamNMEA[incoming] = 0; // Wrap around + + gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request receiver to use new settings } else if (incoming > MAX_MOSAIC_NMEA_MSG && incoming <= (MAX_MOSAIC_NMEA_MSG + MOSAIC_NUM_NMEA_STREAMS)) // Stream intervals @@ -1851,6 +1853,7 @@ void GNSS_MOSAIC::menuMessagesNMEA() if (interval >= 1 && interval <= MAX_MOSAIC_MSG_RATES) { settings.mosaicStreamIntervalsNMEA[incoming] = interval - 1; + gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request receiver to use new settings } } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) @@ -1861,9 +1864,6 @@ void GNSS_MOSAIC::menuMessagesNMEA() printUnknown(incoming); } - settings.gnssConfiguredBase = false; // Update the GNSS config at the next boot - settings.gnssConfiguredRover = false; - clearBuffer(); // Empty buffer of any newline chars } @@ -1913,7 +1913,10 @@ void GNSS_MOSAIC::menuMessagesRTCM(bool rover) if (getUserInputDouble(&interval) == INPUT_RESPONSE_VALID) // Returns EXIT, TIMEOUT, or long { if ((interval >= 0.1) && (interval <= 600.0)) + { intervalPtr[incoming] = interval; + gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request receiver to use new settings + } else systemPrintln("Invalid interval: Min 0.1; Max 600.0"); } @@ -1933,9 +1936,6 @@ void GNSS_MOSAIC::menuMessagesRTCM(bool rover) printUnknown(incoming); } - settings.gnssConfiguredBase = false; // Update the GNSS config at the next boot - settings.gnssConfiguredRover = false; - clearBuffer(); // Empty buffer of any newline chars } @@ -1991,6 +1991,8 @@ void GNSS_MOSAIC::menuMessages() for (int x = 0; x < MAX_MOSAIC_RTCM_V3_MSG; x++) settings.mosaicMessageEnabledRTCMv3Base[x] = mosaicMessagesRTCMv3[x].defaultEnabled; + gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request receiver to use new settings + systemPrintln("Reset to Defaults"); } @@ -2005,12 +2007,6 @@ void GNSS_MOSAIC::menuMessages() clearBuffer(); // Empty buffer of any newline chars setLoggingType(); // Update Standard, PPP, or custom for icon selection - - // Apply these changes at menu exit - if (inRoverMode() == true) - restartRover = true; - else - restartBase = true; } //---------------------------------------- @@ -2097,15 +2093,16 @@ bool GNSS_MOSAIC::saveConfiguration() // Returns true if the response was received and false upon failure //---------------------------------------- bool GNSS_MOSAIC::sendAndWaitForIdle(const char *message, const char *reply, unsigned long timeout, unsigned long wait, - char *response, size_t responseSize, bool debug) + char *response, size_t responseSize, bool debug) { if (productVariant == RTK_FACET_MOSAIC) return sendAndWaitForIdle(serial2GNSS, message, reply, timeout, wait, response, responseSize, debug); else return sendAndWaitForIdle(serialGNSS, message, reply, timeout, wait, response, responseSize, debug); } -bool GNSS_MOSAIC::sendAndWaitForIdle(HardwareSerial *serialPort, const char *message, const char *reply, unsigned long timeout, unsigned long idle, - char *response, size_t responseSize, bool debug) +bool GNSS_MOSAIC::sendAndWaitForIdle(HardwareSerial *serialPort, const char *message, const char *reply, + unsigned long timeout, unsigned long idle, char *response, size_t responseSize, + bool debug) { if (strlen(reply) == 0) // Reply can't be zero-length return false; @@ -2126,8 +2123,8 @@ bool GNSS_MOSAIC::sendAndWaitForIdle(HardwareSerial *serialPort, const char *mes if (serialPort->available()) // If a char is available { uint8_t c = serialPort->read(); // Read it - //if (debug && (settings.debugGnss == true) && (!inMainMenu)) - // systemPrintf("%c", (char)c); + // if (debug && (settings.debugGnss == true) && (!inMainMenu)) + // systemPrintf("%c", (char)c); if (c == *(reply + replySeen)) // Is it a char from reply? { if (response && (replySeen < (responseSize - 1))) @@ -2150,8 +2147,8 @@ bool GNSS_MOSAIC::sendAndWaitForIdle(HardwareSerial *serialPort, const char *mes if (serialPort->available()) { uint8_t c = serialPort->read(); - //if (debug && (settings.debugGnss == true) && (!inMainMenu)) - // systemPrintf("%c", (char)c); + // if (debug && (settings.debugGnss == true) && (!inMainMenu)) + // systemPrintf("%c", (char)c); if (response && (replySeen < (responseSize - 1))) { *(response + replySeen) = c; @@ -2217,8 +2214,8 @@ bool GNSS_MOSAIC::sendWithResponse(const char *message, const char *reply, unsig else return sendWithResponse(serialGNSS, message, reply, timeout, wait, response, responseSize); } -bool GNSS_MOSAIC::sendWithResponse(HardwareSerial *serialPort, const char *message, const char *reply, unsigned long timeout, unsigned long wait, - char *response, size_t responseSize) +bool GNSS_MOSAIC::sendWithResponse(HardwareSerial *serialPort, const char *message, const char *reply, + unsigned long timeout, unsigned long wait, char *response, size_t responseSize) { if (strlen(reply) == 0) // Reply can't be zero-length return false; @@ -2240,8 +2237,8 @@ bool GNSS_MOSAIC::sendWithResponse(HardwareSerial *serialPort, const char *messa if (serialPort->available()) // If a char is available { uint8_t c = serialPort->read(); // Read it - //if ((settings.debugGnss == true) && (!inMainMenu)) - // systemPrintf("%c", (char)c); + // if ((settings.debugGnss == true) && (!inMainMenu)) + // systemPrintf("%c", (char)c); if (c == *(reply + replySeen)) // Is it a char from reply? { if (response && (replySeen < (responseSize - 1))) @@ -2261,7 +2258,7 @@ bool GNSS_MOSAIC::sendWithResponse(HardwareSerial *serialPort, const char *messa keepGoing = false; if ((millis() - startTime) > (timeout + wait)) // Have we really timed out? - keepGoing = false; // Don't keepGoing + keepGoing = false; // Don't keepGoing } if (replySeen == strlen(reply)) // If the reply was seen @@ -2272,8 +2269,8 @@ bool GNSS_MOSAIC::sendWithResponse(HardwareSerial *serialPort, const char *messa if (serialPort->available()) { uint8_t c = serialPort->read(); - //if ((settings.debugGnss == true) && (!inMainMenu)) - // systemPrintf("%c", (char)c); + // if ((settings.debugGnss == true) && (!inMainMenu)) + // systemPrintf("%c", (char)c); if (response && (replySeen < (responseSize - 1))) { *(response + replySeen) = c; @@ -2602,7 +2599,8 @@ void GNSS_MOSAIC::storeBlock4013(SEMP_PARSE_STATE *parse) if (Tracking) { // SV is being tracked - std::vector::iterator pos = std::find_if(svInTracking.begin(), svInTracking.end(), find_sv(SVID)); + std::vector::iterator pos = + std::find_if(svInTracking.begin(), svInTracking.end(), find_sv(SVID)); if (pos == svInTracking.end()) // If it is not in svInTracking, add it svInTracking.push_back({SVID, millis()}); else // Update lastSeen @@ -2615,7 +2613,8 @@ void GNSS_MOSAIC::storeBlock4013(SEMP_PARSE_STATE *parse) else { // SV is not being tracked. If it is in svInTracking, remove it - std::vector::iterator pos = std::find_if(svInTracking.begin(), svInTracking.end(), find_sv(SVID)); + std::vector::iterator pos = + std::find_if(svInTracking.begin(), svInTracking.end(), find_sv(SVID)); if (pos != svInTracking.end()) svInTracking.erase(pos); } @@ -2628,7 +2627,8 @@ void GNSS_MOSAIC::storeBlock4013(SEMP_PARSE_STATE *parse) bool keepGoing = true; while (keepGoing) { - std::vector::iterator pos = std::find_if(svInTracking.begin(), svInTracking.end(), find_stale_sv(millis())); + std::vector::iterator pos = + std::find_if(svInTracking.begin(), svInTracking.end(), find_stale_sv(millis())); if (pos != svInTracking.end()) svInTracking.erase(pos); else @@ -2664,7 +2664,7 @@ void GNSS_MOSAIC::storeBlock4059(SEMP_PARSE_STATE *parse) { if (!present.mosaicMicroSd) return; - + if (sempSbfGetU1(parse, 14) < 1) // Check N is at least 1 return; @@ -2962,7 +2962,7 @@ uint32_t GNSS_MOSAIC::baudGetMaximum() return (mosaicComRates[MAX_MOSAIC_COM_RATES - 1].rate); } -//Return true if the receiver is detected +// Return true if the receiver is detected bool GNSS_MOSAIC::isPresent() { if (productVariant != RTK_FLEX) // productVariant == RTK_FACET_MOSAIC @@ -2975,12 +2975,14 @@ bool GNSS_MOSAIC::isPresent() { // Set COM1 to: auto input, RTCMv3+SBF+NMEA+Encapsulate output // Mosaic could still be starting up, so allow many retries - return isPresentOnSerial(serialGNSS, "sdio,COM1,auto,RTCMv3+SBF+NMEA+Encapsulate\n\r", "DataInOut", "COM1>", 20); + return isPresentOnSerial(serialGNSS, "sdio,COM1,auto,RTCMv3+SBF+NMEA+Encapsulate\n\r", "DataInOut", "COM1>", + 20); } } -//Return true if the receiver is detected -bool GNSS_MOSAIC::isPresentOnSerial(HardwareSerial *serialPort, const char *command, const char *response, const char *console, int retryLimit) +// Return true if the receiver is detected +bool GNSS_MOSAIC::isPresentOnSerial(HardwareSerial *serialPort, const char *command, const char *response, + const char *console, int retryLimit) { // Mosaic could still be starting up, so allow many retries int retries = 0; @@ -3012,7 +3014,7 @@ bool GNSS_MOSAIC::isPresentOnSerial(HardwareSerial *serialPort, const char *comm if (retries == retryLimit) { systemPrintln("Could not communicate with mosaic-X5 at selected baud rate"); - return(false); + return (false); } } @@ -3284,7 +3286,8 @@ bool mosaicIsPresentOnFlex() serialTestGNSS.begin(115200, SERIAL_8N1, pin_GnssUart_RX, pin_GnssUart_TX); // Only try 3 times. LG290P detection will have been done first. X5 should have booted. Baud rate could be wrong. - if (mosaic.isPresentOnSerial(&serialTestGNSS, "sdio,COM1,auto,RTCMv3+SBF+NMEA+Encapsulate\n\r", "DataInOut", "COM1>", 3) == true) + if (mosaic.isPresentOnSerial(&serialTestGNSS, "sdio,COM1,auto,RTCMv3+SBF+NMEA+Encapsulate\n\r", "DataInOut", + "COM1>", 3) == true) { if (settings.debugGnss) systemPrintln("mosaic-X5 detected at 115200 baud"); @@ -3304,14 +3307,15 @@ bool mosaicIsPresentOnFlex() serialTestGNSS.begin(460800, SERIAL_8N1, pin_GnssUart_RX, pin_GnssUart_TX); // Only try 3 times, so we fail and pass on to the next Facet GNSS detection - if (mosaic.isPresentOnSerial(&serialTestGNSS, "sdio,COM1,auto,RTCMv3+SBF+NMEA+Encapsulate\n\r", "DataInOut", "COM1>", 3) == true) + if (mosaic.isPresentOnSerial(&serialTestGNSS, "sdio,COM1,auto,RTCMv3+SBF+NMEA+Encapsulate\n\r", "DataInOut", + "COM1>", 3) == true) { // serialGNSS and serial2GNSS have not yet been begun. We need to saveConfiguration manually unsigned long start = millis(); bool result = mosaic.sendWithResponse(&serialTestGNSS, "eccf,Current,Boot\n\r", "CopyConfigFile", 5000); if (settings.debugGnss) systemPrintf("saveConfiguration: sendWithResponse returned %s after %d ms\r\n", result ? "true" : "false", - millis() - start); + millis() - start); if (settings.debugGnss) systemPrintf("mosaic-X5 baud rate %supdated\r\n", result ? "" : "NOT "); serialTestGNSS.end(); diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index 0a8c3d6f9..4393d0621 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -1359,6 +1359,8 @@ void GNSS_UM980::menuMessages() settings.um980MessageRatesRTCMBase[x] = umMessagesRTCM[x].msgDefaultRate; systemPrintln("Reset to Defaults"); + + gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request receiver to use new settings } else if (incoming == 11 || incoming == 12) { @@ -1393,6 +1395,8 @@ void GNSS_UM980::menuMessages() { systemPrintln("Reset to PPP Logging (NMEAx5 / RTCMx4 - 30 second decimation)"); } + + gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request receiver to use new settings } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) @@ -1404,12 +1408,6 @@ void GNSS_UM980::menuMessages() } clearBuffer(); // Empty buffer of any newline chars - - // Apply these changes at menu exit - if (inRoverMode()) - restartRover = true; - else - restartBase = true; } //---------------------------------------- @@ -1508,6 +1506,8 @@ void GNSS_UM980::menuMessagesSubtype(float *localMessageRate, const char *messag settings.um980MessageRatesRTCMRover[incoming] = (float)newSetting; if (strcmp(messageType, "RTCMBase") == 0) settings.um980MessageRatesRTCMBase[incoming] = (float)newSetting; + + gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request receiver to use new settings } } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) @@ -1518,10 +1518,6 @@ void GNSS_UM980::menuMessagesSubtype(float *localMessageRate, const char *messag printUnknown(incoming); } - settings.gnssConfiguredOnce = false; // Update the GNSS config at the next boot - settings.gnssConfiguredBase = false; - settings.gnssConfiguredRover = false; - clearBuffer(); // Empty buffer of any newline chars } @@ -1622,7 +1618,6 @@ bool GNSS_UM980::setBaudRateCOM3(uint32_t baudRate) //---------------------------------------- // Enable all the valid constellations and bands for this platform // Band support varies between platforms and firmware versions -// We open/close a complete set 19 messages //---------------------------------------- bool GNSS_UM980::setConstellations() { diff --git a/Firmware/RTK_Everywhere/RTK_Everywhere.ino b/Firmware/RTK_Everywhere/RTK_Everywhere.ino index 45af830b3..052bdcb84 100644 --- a/Firmware/RTK_Everywhere/RTK_Everywhere.ino +++ b/Firmware/RTK_Everywhere/RTK_Everywhere.ino @@ -886,8 +886,6 @@ uint32_t triggerTowSubMsR; // Global copy - Millisecond fraction of Time Of Week uint32_t triggerAccEst; // Global copy - Accuracy estimate in nanoseconds unsigned long splashStart; // Controls how long the splash is displayed for. Currently min of 2s. -bool restartBase; // If the user modifies any NTRIP Server settings, we need to restart the base -bool restartRover; // If the user modifies any NTRIP Client or PointPerfect settings, we need to restart the rover unsigned long startTime; // Used for checking longest-running functions bool lbandCorrectionsReceived; // Used to display L-Band SIV icon when corrections are successfully decrypted (NEO-D9S diff --git a/Firmware/RTK_Everywhere/menuBase.ino b/Firmware/RTK_Everywhere/menuBase.ino index 4fb9e4937..e8aeb6de3 100644 --- a/Firmware/RTK_Everywhere/menuBase.ino +++ b/Firmware/RTK_Everywhere/menuBase.ino @@ -27,9 +27,9 @@ void menuBase() // Print the combined HAE APC if we are in the given mode if (settings.fixedBase == true && settings.fixedBaseCoordinateType == COORD_TYPE_GEODETIC) { - systemPrintf("Total Height Above Ellipsoid of Antenna Phase Center (HAE APC): %0.4fmm\r\n", - ((settings.fixedAltitude + - (settings.antennaHeight_mm + settings.antennaPhaseCenter_mm) / 1000))); + systemPrintf( + "Total Height Above Ellipsoid of Antenna Phase Center (HAE APC): %0.4fmm\r\n", + ((settings.fixedAltitude + (settings.antennaHeight_mm + settings.antennaPhaseCenter_mm) / 1000))); } systemPrint("1) Toggle Base Mode: "); @@ -142,12 +142,12 @@ void menuBase() if (incoming == 1) { settings.fixedBase ^= 1; - restartBase = true; + gnssConfigureRequest |= UPDATE_BASE; // Request receiver to use new settings } else if (settings.fixedBase == true && incoming == 2) { settings.fixedBaseCoordinateType ^= 1; - restartBase = true; + gnssConfigureRequest |= UPDATE_BASE; // Request receiver to use new settings } else if (settings.fixedBase == true && incoming == 3) @@ -174,7 +174,10 @@ void menuBase() systemPrint("\nECEF Z in meters (ex: 4086669.6393): "); double fixedEcefZ; if (getUserInputDouble(&fixedEcefZ) == INPUT_RESPONSE_VALID) + { settings.fixedEcefZ = fixedEcefZ; + gnssConfigureRequest |= UPDATE_BASE; // Request receiver to use new settings + } } } } @@ -214,7 +217,10 @@ void menuBase() systemPrint("\r\nAltitude in meters (ex: 1560.2284): "); double fixedAltitude; if (getUserInputDouble(&fixedAltitude) == INPUT_RESPONSE_VALID) + { settings.fixedAltitude = fixedAltitude; + gnssConfigureRequest |= UPDATE_BASE; // Request receiver to use new settings + } } else { @@ -233,36 +239,54 @@ void menuBase() } else if (settings.fixedBase == true && settings.fixedBaseCoordinateType == COORD_TYPE_GEODETIC && incoming == 5) { - getNewSetting("Enter the antenna height (a.k.a. pole length) in millimeters", -15000, 15000, - &settings.antennaHeight_mm); + if (getNewSetting("Enter the antenna height (a.k.a. pole length) in millimeters", -15000, 15000, + &settings.antennaHeight_mm) == INPUT_RESPONSE_VALID) + { + gnssConfigureRequest |= UPDATE_BASE; // Request receiver to use new settings + // TODO Does any other hardware need to be reconfigured after this setting change? Tilt sensor? + } } else if (settings.fixedBase == true && settings.fixedBaseCoordinateType == COORD_TYPE_GEODETIC && incoming == 6) { - getNewSetting("Enter the antenna phase center (the distance between the ARP and the APC) in millimeters. " - "Common antennas " - "Torch=116mm", - -200.0, 200.0, &settings.antennaPhaseCenter_mm); + if (getNewSetting( + "Enter the antenna phase center (the distance between the ARP and the APC) in millimeters. " + "Common antennas " + "Torch/X2=116.5, Facet mosaic=68.5, EVK=42.0, Postcard=37.5, Flex=62.5", + -200.0, 200.0, &settings.antennaPhaseCenter_mm) == INPUT_RESPONSE_VALID) + { + gnssConfigureRequest |= UPDATE_BASE; // Request receiver to use new settings + } } else if (settings.fixedBase == false && incoming == 2 && (!present.gnss_mosaicX5)) { // Arbitrary 10 minute limit - getNewSetting("Enter the number of seconds for survey-in observation time", 60, 60 * 10, - &settings.observationSeconds); + if (getNewSetting("Enter the number of seconds for survey-in observation time", 60, 60 * 10, + &settings.observationSeconds) == INPUT_RESPONSE_VALID) + { + gnssConfigureRequest |= UPDATE_BASE; // Request receiver to use new settings + } } else if (settings.fixedBase == false && incoming == 3 && present.gnss_zedf9p) // UM980 does not support survey in minimum deviation { // Arbitrary 1m minimum - getNewSetting("Enter the number of meters for survey-in required position accuracy", 1.0, - (double)maxObservationPositionAccuracy, &settings.observationPositionAccuracy); + if (getNewSetting("Enter the number of meters for survey-in required position accuracy", 1.0, + (double)maxObservationPositionAccuracy, + &settings.observationPositionAccuracy) == INPUT_RESPONSE_VALID) + { + gnssConfigureRequest |= UPDATE_BASE; // Request receiver to use new settings + } } else if (settings.fixedBase == false && incoming == 4 && (!present.gnss_mosaicX5)) { // Arbitrary 0.1m minimum - - getNewSetting("Enter the positional accuracy required before Survey-In begins", 0.1, - (double)maxSurveyInStartingAccuracy, &settings.surveyInStartingAccuracy); + if (getNewSetting("Enter the positional accuracy required before Survey-In begins", 0.1, + (double)maxSurveyInStartingAccuracy, + &settings.surveyInStartingAccuracy) == INPUT_RESPONSE_VALID) + { + gnssConfigureRequest |= UPDATE_BASE; // Request receiver to use new settings + } } else if (incoming == 7) @@ -273,7 +297,6 @@ void menuBase() else if (incoming == 8) { settings.enableNtripServer ^= 1; - restartBase = true; } // NTRIP Server entries @@ -290,8 +313,10 @@ void menuBase() systemPrintf("Enter Caster Address for Server %d: ", serverNumber + 1); if (getUserInputString(&settings.ntripServer_CasterHost[serverNumber][0], NTRIP_SERVER_STRING_SIZE) == INPUT_RESPONSE_VALID) - restartBase = true; - } + { + // NTRIP Server state machine will update automatically + } + } else if (incoming == 1) { // Arbitrary 99k max port # @@ -303,7 +328,9 @@ void menuBase() if (getNewSetting(tempString, 1, 99999, &settings.ntripServer_CasterPort[serverNumber]) == INPUT_RESPONSE_VALID) - restartBase = true; + { + // NTRIP Server state machine will update automatically + } } else if (incoming == 2) { @@ -314,7 +341,9 @@ void menuBase() if (getUserInputString(&settings.ntripServer_CasterUser[serverNumber][0], NTRIP_SERVER_STRING_SIZE) == INPUT_RESPONSE_VALID) - restartBase = true; + { + // NTRIP Server state machine will update automatically + } } else if (incoming == 3) { @@ -325,7 +354,9 @@ void menuBase() if (getUserInputString(&settings.ntripServer_CasterUserPW[serverNumber][0], NTRIP_SERVER_STRING_SIZE) == INPUT_RESPONSE_VALID) - restartBase = true; + { + // NTRIP Server state machine will update automatically + } } else if (incoming == 4) { @@ -336,7 +367,9 @@ void menuBase() if (getUserInputString(&settings.ntripServer_MountPoint[serverNumber][0], NTRIP_SERVER_STRING_SIZE) == INPUT_RESPONSE_VALID) - restartBase = true; + { + // NTRIP Server state machine will update automatically + } } else if (incoming == 5) { @@ -347,7 +380,9 @@ void menuBase() if (getUserInputString(&settings.ntripServer_MountPointPW[serverNumber][0], NTRIP_SERVER_STRING_SIZE) == INPUT_RESPONSE_VALID) - restartBase = true; + { + // NTRIP Server state machine will update automatically + } } } @@ -385,6 +420,7 @@ void menuBaseCoordinateType() if (incoming >= 1 && incoming < (COORDINATE_INPUT_TYPE_INVALID_UNKNOWN + 1)) { settings.coordinateInputType = (CoordinateInputType)(incoming - 1); // Align from 1-9 to 0-8 + // This setting does not affect the receiver configuration } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) break; diff --git a/Firmware/RTK_Everywhere/menuGNSS.ino b/Firmware/RTK_Everywhere/menuGNSS.ino index 259d65ba1..f82d42d6f 100644 --- a/Firmware/RTK_Everywhere/menuGNSS.ino +++ b/Firmware/RTK_Everywhere/menuGNSS.ino @@ -2,10 +2,6 @@ // Update rate, constellations, etc void menuGNSS() { - // If user modifies any NTRIP settings etc., we need to restart the rover with "restartRover = true;"" - // But, don't set "restartRover = false;" here as that may prevent a restart requested by menuPointPerfect - // for example... - while (1) { systemPrintln(); @@ -336,13 +332,13 @@ void menuGNSS() else if (incoming == 7) { settings.enableNtripClient ^= 1; - restartRover = true; + // No need to restart rover. NTRIP Client state machine will service the change. } else if ((incoming == 8) && settings.enableNtripClient == true) { systemPrint("Enter new Caster Address: "); getUserInputString(settings.ntripClient_CasterHost, sizeof(settings.ntripClient_CasterHost)); - restartRover = true; + // No need to restart rover. NTRIP Client state machine will service the change. } else if ((incoming == 9) && settings.enableNtripClient == true) { @@ -350,43 +346,45 @@ void menuGNSS() if (getNewSetting("Enter new Caster Port", 1, 99999, &settings.ntripClient_CasterPort) == INPUT_RESPONSE_VALID) { - restartRover = true; + // No need to restart rover. NTRIP Client state machine will service the change. } } else if ((incoming == 10) && settings.enableNtripClient == true) { systemPrintf("Enter user name for %s: ", settings.ntripClient_CasterHost); getUserInputString(settings.ntripClient_CasterUser, sizeof(settings.ntripClient_CasterUser)); - restartRover = true; + // No need to restart rover. NTRIP Client state machine will service the change. } else if ((incoming == 11) && settings.enableNtripClient == true) { systemPrintf("Enter user password for %s: ", settings.ntripClient_CasterHost); getUserInputString(settings.ntripClient_CasterUserPW, sizeof(settings.ntripClient_CasterUserPW)); - restartRover = true; + // No need to restart rover. NTRIP Client state machine will service the change. } else if ((incoming == 12) && settings.enableNtripClient == true) { systemPrint("Enter new Mount Point: "); getUserInputString(settings.ntripClient_MountPoint, sizeof(settings.ntripClient_MountPoint)); - restartRover = true; + // No need to restart rover. NTRIP Client state machine will service the change. } else if ((incoming == 13) && settings.enableNtripClient == true) { systemPrintf("Enter password for Mount Point %s: ", settings.ntripClient_MountPoint); getUserInputString(settings.ntripClient_MountPointPW, sizeof(settings.ntripClient_MountPointPW)); - restartRover = true; + // No need to restart rover. NTRIP Client state machine will service the change. } else if ((incoming == 14) && settings.enableNtripClient == true) { settings.ntripClient_TransmitGGA ^= 1; - restartRover = true; + + // We may need to enable the GGA message. Trigger GNSS receiver reconfigure. + gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request update } else if ((incoming == 15) && present.multipathMitigation) { settings.enableMultipathMitigation ^= 1; - restartRover = true; + gnssConfigureRequest |= UPDATE_MULTIPATH; // Request update } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) diff --git a/Firmware/RTK_Everywhere/menuMain.ino b/Firmware/RTK_Everywhere/menuMain.ino index e9db3dc93..fb6c72c61 100644 --- a/Firmware/RTK_Everywhere/menuMain.ino +++ b/Firmware/RTK_Everywhere/menuMain.ino @@ -268,30 +268,13 @@ void menuMain() printUnknown(incoming); } - // Reboot as base only if currently operating as a base station - if (restartBase == true && inBaseMode() == true) - { - restartBase = false; - settings.gnssConfiguredBase = false; // Reapply configuration - requestChangeState(STATE_BASE_NOT_STARTED); // Restart base upon exit for latest changes to take effect - } - - if (restartRover == true && inRoverMode() == true) - { - restartRover = false; - settings.gnssConfiguredRover = false; // Reapply configuration - requestChangeState(STATE_ROVER_NOT_STARTED); // Restart rover upon exit for latest changes to take effect - } - - gnss->saveConfiguration(); - - recordSystemSettings(); // Once all menus have exited, record the new settings to LittleFS and config file - if (settings.debugGnss == true) { // Re-enable GNSS debug once we exit config menus gnss->debuggingEnable(); } + + recordSystemSettings(); // Once all menus have exited, record the new settings to LittleFS and config file clearBuffer(); // Empty buffer of any newline chars btPrintEchoExit = false; // We are out of the menu system diff --git a/Firmware/RTK_Everywhere/menuMessages.ino b/Firmware/RTK_Everywhere/menuMessages.ino index 611120311..1cc8a13b7 100644 --- a/Firmware/RTK_Everywhere/menuMessages.ino +++ b/Firmware/RTK_Everywhere/menuMessages.ino @@ -240,26 +240,25 @@ void menuMessagesBaseRTCM() if (incoming == 1) { gnss->menuMessageBaseRtcm(); - restartBase = true; } else if (incoming == 2) { gnss->baseRtcmDefault(); + gnssConfigureRequest |= UPDATE_MESSAGE_RATE_RTCM_BASE; // Request receiver to use new settings systemPrintf("Reset to Defaults (%s)\r\n", gnss->getRtcmDefaultString()); - restartBase = true; } else if (incoming == 3) { gnss->baseRtcmLowDataRate(); + gnssConfigureRequest |= UPDATE_MESSAGE_RATE_RTCM_BASE; // Request receiver to use new settings systemPrintf("Reset to Low Bandwidth Link (%s)\r\n", gnss->getRtcmLowDataRateString()); - restartBase = true; } else if ((incoming == 4) && (namedSettingAvailableOnPlatform("useMSM7"))) { settings.useMSM7 ^= 1; - restartBase = true; + gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request receiver to use new settings } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) diff --git a/Firmware/RTK_Everywhere/menuPP.ino b/Firmware/RTK_Everywhere/menuPP.ino index f491ab1c3..710db12b9 100644 --- a/Firmware/RTK_Everywhere/menuPP.ino +++ b/Firmware/RTK_Everywhere/menuPP.ino @@ -340,7 +340,9 @@ void menuPointPerfectSelectService() { settings.pointPerfectService = incoming - 1; // Align incoming to array - restartRover = true; // Require a rover restart to enable / disable RTCM for PPL + // Require a rover restart to enable / disable RTCM for PPL + gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request receiver to use new settings + settings.requestKeyUpdate = settings.pointPerfectService != PP_NICKNAME_DISABLED; // Force a key update - or don't diff --git a/Firmware/RTK_Everywhere/menuPorts.ino b/Firmware/RTK_Everywhere/menuPorts.ino index 598e14295..cd1aee888 100644 --- a/Firmware/RTK_Everywhere/menuPorts.ino +++ b/Firmware/RTK_Everywhere/menuPorts.ino @@ -80,7 +80,8 @@ void menuPortsNoMux() systemPrintf("4) Allow incoming corrections on RADIO port: %s\r\n", settings.enableExtCorrRadio ? "Enabled" : "Disabled"); systemPrintf("5) Limit RADIO port output to RTCM: %s\r\n", - settings.enableNmeaOnRadio ? "Disabled" : "Enabled"); //Reverse disabled/enabled to align with prompt + settings.enableNmeaOnRadio ? "Disabled" + : "Enabled"); // Reverse disabled/enabled to align with prompt } systemPrintln("x) Exit"); @@ -154,17 +155,12 @@ void menuPortsNoMux() printUnknown(incoming); } -#ifdef COMPILE_LG290P if (present.gnss_lg290p) { - // Apply these changes at menu exit - to enable/disable NMEA on radio - GNSS_LG290P *aLG290P = (GNSS_LG290P *)gnss; - if (aLG290P->inRoverMode() == true) - restartRover = true; - else - restartBase = true; + // All platforms, except the LG290P can modify their baud rates immediately. + // The LG290P requires a reset for settings to take effect + gnssConfigureRequest |= UPDATE_BAUD_RATE; // Request receiver to use new settings } -#endif // COMPILE_LG290P clearBuffer(); // Empty buffer of any newline chars } @@ -218,7 +214,8 @@ void menuPortsMultiplexed() systemPrintf("5) Output GNSS data to USB1 serial: %s\r\n", settings.enableGnssToUsbSerial ? "Enabled" : "Disabled"); systemPrintf("6) Limit RADIO port output to RTCM: %s\r\n", - settings.enableNmeaOnRadio ? "Disabled" : "Enabled"); //Reverse disabled/enabled to align with prompt + settings.enableNmeaOnRadio ? "Disabled" + : "Enabled"); // Reverse disabled/enabled to align with prompt } systemPrintln("x) Exit"); @@ -315,20 +312,14 @@ void menuPortsMultiplexed() clearBuffer(); // Empty buffer of any newline chars -#ifdef COMPILE_MOSAICX5 if (present.gnss_mosaicX5) { // Apply these changes at menu exit - to enable message output on USB1 // and/or enable/disable NMEA on radio - GNSS_MOSAIC *mosaic = (GNSS_MOSAIC *)gnss; - if (mosaic->inRoverMode() == true) - restartRover = true; - else - restartBase = true; + gnssConfigureRequest |= UPDATE_BAUD_RATE; // Request receiver to use new settings } -#endif // COMPILE_MOSAICX5 - gnss->beginExternalEvent(); // Update with new settings + gnss->beginExternalEvent(); // Update with new settings gnss->beginPPS(); } From fb3957f5f471d85c8b9a8c8f24200f81934f6381 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 9 Oct 2025 20:02:23 -0600 Subject: [PATCH 11/68] Add RESET and SAVE to gnssUpdate bitfield. Make setHAS() on all platforms. --- Firmware/RTK_Everywhere/GNSS.h | 2 ++ Firmware/RTK_Everywhere/GNSS.ino | 19 ++++++++++++++++++- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 13 +++++++------ Firmware/RTK_Everywhere/GNSS_Mosaic.h | 3 +++ Firmware/RTK_Everywhere/GNSS_Mosaic.ino | 9 +++++++++ Firmware/RTK_Everywhere/GNSS_None.h | 6 ++++++ Firmware/RTK_Everywhere/GNSS_UM980.ino | 11 +++++++++++ Firmware/RTK_Everywhere/GNSS_ZED.h | 3 +++ Firmware/RTK_Everywhere/GNSS_ZED.ino | 9 +++++++++ 9 files changed, 68 insertions(+), 7 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.h b/Firmware/RTK_Everywhere/GNSS.h index ca6e438e6..7de5e0836 100644 --- a/Firmware/RTK_Everywhere/GNSS.h +++ b/Firmware/RTK_Everywhere/GNSS.h @@ -347,6 +347,8 @@ class GNSS // elevationDegrees: The elevation value in degrees virtual bool setElevation(uint8_t elevationDegrees); + virtual bool setHighAccuracyService(bool enableGalileoHas); + virtual bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); // Enable all the valid messages for this platform diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index 5495906ee..81591038a 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -20,6 +20,8 @@ enum UPDATE_HAS_E6 = (1 << 7), // Enable/disable HAS E6 capabilities UPDATE_BAUD_RATE = (1 << 8), UPDATE_MULTIPATH = (1 << 9), + UPDATE_SAVE = (1 << 10), // Indicates current settings be saved to GNSS receiver NVM + UPDATE_RESET = (1 << 11), // Indicates receiver needs resetting }; uint16_t gnssConfigureRequest = @@ -107,6 +109,9 @@ void gnssUpdate() // Allow the GNSS platform to update itself gnss->update(); + // In general, the GNSS configuration should only be modified here, not in menus, not in commands + // Those should trigger a request for modification + // Handle any requested configuration changes // Only update the GNSS receiver once the CLI, serial menu, and Web Config interfaces are disconnected // This is to avoid multiple reconfigure delays when multiple commands are received, ie enable GPS, disable Galileo, @@ -114,12 +119,24 @@ void gnssUpdate() if (gnssConfigureRequest != UPDATE_NONE && bluetoothCommandIsConnected() == false && inMainMenu == false && inWebConfigMode() == false) { + bool result = true; + // Test for individual changes as needed if (gnssConfigureRequest & UPDATE_CONSTELLATION) { } + if (gnssConfigureRequest & UPDATE_HAS_E6) + { + result &= gnss->setHighAccuracyService(settings.enableGalileoHas); + } - // Here we need a table to determine if the given combination of setting requests trigger a GNSS's NVM save + // Platforms will set the UPDATE_SAVE and UPDATE_RESET bits appropriately for each command issued + + // If one of the previous configuration changes requested save to NVM, do so + if (gnssConfigureRequest & UPDATE_SAVE) + { + result &= gnss->saveConfiguration(); + } // Here we need a table to determine if the given combination of setting requests require a GNSS reset to take // effect diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index 08595983f..6a8762087 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -1884,9 +1884,6 @@ void GNSS_LG290P::menuConstellations() printUnknown(incoming); } - // Apply current settings to module - gnss->setConstellations(); - setHighAccuracyService(settings.enableGalileoHas); clearBuffer(); // Empty buffer of any newline chars @@ -2358,24 +2355,27 @@ bool GNSS_LG290P::setElevation(uint8_t elevationDegrees) return true; } +//---------------------------------------- +// Control whether HAS E6 is used in location fixes or not //---------------------------------------- bool GNSS_LG290P::setHighAccuracyService(bool enableGalileoHas) { bool result = true; - // E6 reception requires version v03 with 'PPP_TEMP' in firmware title + // E6 reception requires version v06 with 'PPP_TEMP' in firmware title // Present is set during LG290P begin() if (present.galileoHasCapable == false) - return (result); // We are unable to set this setting to report success + return (result); // We are unable to set this setting so report success // Enable E6 and PPP if enabled - if (settings.enableGalileoHas) + if (enableGalileoHas) { // $PQTMCFGPPP,W,2,1,120,0.10,0.15*68 // Enable E6 HAS, WGS84, 120 timeout, 0.10m Horizontal convergence accuracy threshold, 0.15m Vertical threshold if (_lg290p->sendOkCommand("$PQTMCFGPPP", ",W,2,1,120,0.10,0.15") == true) { systemPrintln("Galileo E6 HAS service enabled"); + gnssConfigureRequest |= UPDATE_SAVE; // Request receiver commit this change to NVM } else { @@ -2390,6 +2390,7 @@ bool GNSS_LG290P::setHighAccuracyService(bool enableGalileoHas) if (_lg290p->sendOkCommand("$PQTMCFGPPP", ",W,0") == true) { systemPrintln("Galileo E6 HAS service disabled"); + gnssConfigureRequest |= UPDATE_SAVE; // Request receiver commit this change to NVM } else { diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.h b/Firmware/RTK_Everywhere/GNSS_Mosaic.h index 73e92d851..255d615e5 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.h +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.h @@ -994,6 +994,9 @@ class GNSS_MOSAIC : GNSS // elevationDegrees: The elevation value in degrees bool setElevation(uint8_t elevationDegrees); + // Enable or disable HAS E6 capability + bool setHighAccuracyService(bool enableGalileoHas); + // Enable all the valid messages for this platform bool setMessages(int maxRetries); diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino index dd2a8d8e1..a27789dad 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino @@ -2442,6 +2442,15 @@ bool GNSS_MOSAIC::setElevation(uint8_t elevationDegrees) return (sendWithResponse(setting, "ElevationMask")); } +//---------------------------------------- +// Control whether HAS E6 is used in location fixes or not +//---------------------------------------- +bool GNSS_MOSAIC::setHighAccuracyService(bool enableGalileoHas) +{ + // Not yet supported on this platform + return (false); +} + //---------------------------------------- // Enable all the valid messages for this platform //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/GNSS_None.h b/Firmware/RTK_Everywhere/GNSS_None.h index 238e6579e..c6b3fa972 100644 --- a/Firmware/RTK_Everywhere/GNSS_None.h +++ b/Firmware/RTK_Everywhere/GNSS_None.h @@ -559,6 +559,12 @@ class GNSS_None : public GNSS return true; } + // Control whether HAS E6 is used in location fixes or not + bool setHighAccuracyService(bool enableGalileoHas) + { + return true; + } + // Enable all the valid messages for this platform bool setMessages(int maxRetries) { diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index 4393d0621..cf0b8f786 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -1666,6 +1666,8 @@ bool GNSS_UM980::setElevation(uint8_t elevationDegrees) return false; } +//---------------------------------------- +// Control whether HAS E6 is used in location fixes or not //---------------------------------------- bool GNSS_UM980::setHighAccuracyService(bool enableGalileoHas) { @@ -1681,7 +1683,10 @@ bool GNSS_UM980::setHighAccuracyService(bool enableGalileoHas) if (_um980->isConfigurationPresent("CONFIG PPP ENABLE E6-HAS") == false) { if (_um980->sendCommand("CONFIG PPP ENABLE E6-HAS")) + { systemPrintln("Galileo E6 HAS service enabled"); + gnssConfigureRequest |= UPDATE_SAVE; // Request receiver commit this change to NVM + } else { systemPrintln("Galileo E6 HAS service failed to enable"); @@ -1689,7 +1694,10 @@ bool GNSS_UM980::setHighAccuracyService(bool enableGalileoHas) } if (_um980->sendCommand("CONFIG PPP DATUM WGS84")) + { systemPrintln("WGS84 Datum applied"); + gnssConfigureRequest |= UPDATE_SAVE; // Request receiver commit this change to NVM + } else { systemPrintln("WGS84 Datum failed to apply"); @@ -1712,7 +1720,10 @@ bool GNSS_UM980::setHighAccuracyService(bool enableGalileoHas) if (_um980->isConfigurationPresent("CONFIG PPP ENABLE E6-HAS")) { if (_um980->sendCommand("CONFIG PPP DISABLE")) + { systemPrintln("Galileo E6 HAS service disabled"); + gnssConfigureRequest |= UPDATE_SAVE; // Request receiver commit this change to NVM + } else { systemPrintln("Galileo E6 HAS service failed to disable"); diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.h b/Firmware/RTK_Everywhere/GNSS_ZED.h index 1a5414936..2b3a5f2f9 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.h +++ b/Firmware/RTK_Everywhere/GNSS_ZED.h @@ -692,6 +692,9 @@ class GNSS_ZED : GNSS // elevationDegrees: The elevation value in degrees bool setElevation(uint8_t elevationDegrees); + // Enable or disable HAS E6 capability + bool setHighAccuracyService(bool enableGalileoHas); + // Given a unique string, find first and last records containing that string in message array void setMessageOffsets(const ubxMsg *localMessage, const char *messageType, int &startOfBlock, int &endOfBlock); diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index a1bc85009..d28313a83 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -2183,6 +2183,15 @@ bool GNSS_ZED::setElevation(uint8_t elevationDegrees) return false; } +//---------------------------------------- +// Control whether HAS E6 is used in location fixes or not +//---------------------------------------- +bool GNSS_ZED::setHighAccuracyService(bool enableGalileoHas) +{ + // Not yet supported on this platform + return (false); +} + //---------------------------------------- // Given a unique string, find first and last records containing that string in message array //---------------------------------------- From 807c2a7cbf2e8a96f1133677deff3524596069ef Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 9 Oct 2025 20:34:59 -0600 Subject: [PATCH 12/68] Rename enums. --- Firmware/RTK_Everywhere/GNSS.ino | 63 +++++++++++++++--------- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 22 ++++----- Firmware/RTK_Everywhere/GNSS_Mosaic.ino | 8 +-- Firmware/RTK_Everywhere/GNSS_UM980.ino | 12 ++--- Firmware/RTK_Everywhere/menuBase.ino | 18 +++---- Firmware/RTK_Everywhere/menuGNSS.ino | 4 +- Firmware/RTK_Everywhere/menuMessages.ino | 9 ++-- Firmware/RTK_Everywhere/menuPP.ino | 2 +- Firmware/RTK_Everywhere/menuPorts.ino | 4 +- 9 files changed, 81 insertions(+), 61 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index 81591038a..f920e65fc 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -9,23 +9,26 @@ GNSS.ino // the menu system, closed the Web Config, or the CLI is closed. enum { - UPDATE_NONE = 0, - UPDATE_ROVER = (1 << 0), - UPDATE_BASE = (1 << 1), // Fixed base or survey in, location, etc - UPDATE_CONSTELLATION = (1 << 2), // Turn on/off a constellation - UPDATE_MESSAGE_RATE = (1 << 3), // Update all message rates - UPDATE_MESSAGE_RATE_NMEA = (1 << 4), // Update NMEA message rates - UPDATE_MESSAGE_RATE_RTCM_ROVER = (1 << 5), // Update RTCM Rover message rates - UPDATE_MESSAGE_RATE_RTCM_BASE = (1 << 6), // Update RTCM Base message rates - UPDATE_HAS_E6 = (1 << 7), // Enable/disable HAS E6 capabilities - UPDATE_BAUD_RATE = (1 << 8), - UPDATE_MULTIPATH = (1 << 9), - UPDATE_SAVE = (1 << 10), // Indicates current settings be saved to GNSS receiver NVM - UPDATE_RESET = (1 << 11), // Indicates receiver needs resetting + GNSS_CONFIG_ROVER, + GNSS_CONFIG_BASE, // Fixed base or survey in, location, etc + GNSS_CONFIG_CONSTELLATION, // Turn on/off a constellation + GNSS_CONFIG_MESSAGE_RATE, // Update all message rates + GNSS_CONFIG_MESSAGE_RATE_NMEA, // Update NMEA message rates + GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER, // Update RTCM Rover message rates + GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE, // Update RTCM Base message rates + GNSS_CONFIG_HAS_E6, // Enable/disable HAS E6 capabilities + GNSS_CONFIG_BAUD_RATE, + GNSS_CONFIG_MULTIPATH, + GNSS_CONFIG_SAVE, // Indicates current settings be saved to GNSS receiver NVM + GNSS_CONFIG_RESET, // Indicates receiver needs resetting + + // Add new entries above here + GNSS_CONFIG_LAST, + GNSS_CONFIG_NONE, }; uint16_t gnssConfigureRequest = - UPDATE_NONE; // Bitfield containing an update be made to various settings on the GNSS receiver + GNSS_CONFIG_NONE; // Bitfield containing an update be made to various settings on the GNSS receiver extern int NTRIPCLIENT_MS_BETWEEN_GGA; @@ -116,24 +119,24 @@ void gnssUpdate() // Only update the GNSS receiver once the CLI, serial menu, and Web Config interfaces are disconnected // This is to avoid multiple reconfigure delays when multiple commands are received, ie enable GPS, disable Galileo, // should only trigger one GNSS reconfigure - if (gnssConfigureRequest != UPDATE_NONE && bluetoothCommandIsConnected() == false && inMainMenu == false && + if (gnssConfigureRequest != GNSS_CONFIG_NONE && bluetoothCommandIsConnected() == false && inMainMenu == false && inWebConfigMode() == false) { bool result = true; // Test for individual changes as needed - if (gnssConfigureRequest & UPDATE_CONSTELLATION) + if (gnssConfigureRequest & GNSS_CONFIG_CONSTELLATION) { } - if (gnssConfigureRequest & UPDATE_HAS_E6) + if (gnssConfigureRequest & GNSS_CONFIG_HAS_E6) { result &= gnss->setHighAccuracyService(settings.enableGalileoHas); } - // Platforms will set the UPDATE_SAVE and UPDATE_RESET bits appropriately for each command issued + // Platforms will set theGNSS_CONFIG_SAVE andGNSS_CONFIG_RESET bits appropriately for each command issued // If one of the previous configuration changes requested save to NVM, do so - if (gnssConfigureRequest & UPDATE_SAVE) + if (gnssConfigureRequest & GNSS_CONFIG_SAVE) { result &= gnss->saveConfiguration(); } @@ -164,17 +167,31 @@ void gnssUpdate() systemPrintln("gnssUpdate: Uncaught mode change"); } - gnssConfigureRequest = UPDATE_NONE; // Clear requests + gnssConfigureRequest = GNSS_CONFIG_NONE; // Clear requests } } +// Given a bit to configure, set that bit in the overall bitfield +void gnssConfigure(uint16_t configureBit) +{ + uint16_t mask = (1 << configureBit); + gnssConfigureRequest |= mask; +} + +// Set all bits in the request bitfield to cause the GNSS receiver to go through a full (re)configuration +void gnssConfigureAll() +{ + for (int x = 0; x < GNSS_CONFIG_LAST; x++) + gnssConfigure(x); +} + //---------------------------------------- // Update the constellations following a set command //---------------------------------------- bool gnssCmdUpdateConstellations(const char *settingName, void *settingData, int settingType) { gnssConfigureRequest |= - UPDATE_CONSTELLATION; // Once BLE Command, Web Config, and CLI are closed, reconfigure receiver + GNSS_CONFIG_CONSTELLATION; // Once BLE Command, Web Config, and CLI are closed, reconfigure receiver return (true); } @@ -185,7 +202,7 @@ bool gnssCmdUpdateConstellations(const char *settingName, void *settingData, int bool gnssCmdUpdateMessageRates(const char *settingName, void *settingData, int settingType) { gnssConfigureRequest |= - UPDATE_MESSAGE_RATE; // Once BLE Command, Web Config, and CLI are closed, reconfigure receiver + GNSS_CONFIG_MESSAGE_RATE; // Once BLE Command, Web Config, and CLI are closed, reconfigure receiver return (true); } @@ -197,7 +214,7 @@ bool gnssCmdUpdateMessageRates(const char *settingName, void *settingData, int s bool pointPerfectCmdUpdateServiceType(const char *settingName, void *settingData, int settingType) { // Require a rover restart to enable / disable RTCM for PPL - gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings return (true); } diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index 6a8762087..269e802d3 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -1869,12 +1869,12 @@ void GNSS_LG290P::menuConstellations() incoming--; // Align choice to constellation array of 0 to 5 settings.lg290pConstellations[incoming] ^= 1; - gnssConfigureRequest |= UPDATE_CONSTELLATION; // Reconfigure receiver + gnssConfigure(GNSS_CONFIG_CONSTELLATION); // Request receiver to use new settings } else if ((incoming == MAX_LG290P_CONSTELLATIONS + 1) && present.galileoHasCapable) { settings.enableGalileoHas ^= 1; - gnssConfigureRequest |= UPDATE_HAS_E6; // Reconfigure receiver + gnssConfigure(GNSS_CONFIG_HAS_E6); // Request receiver to use new settings } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) break; @@ -1949,7 +1949,7 @@ void GNSS_LG290P::menuMessages() for (int x = 0; x < MAX_LG290P_PQTM_MSG; x++) settings.lg290pMessageRatesPQTM[x] = lgMessagesPQTM[x].msgDefaultRate; - gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request update + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings systemPrintln("Reset to Defaults"); } @@ -1994,13 +1994,13 @@ void GNSS_LG290P::menuMessages() systemPrintln("Reset to PPP Logging Defaults (NMEAx7 / RTCMx4 - 30 second decimation)"); } - gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request update + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings } else if ((incoming == 13) && (namedSettingAvailableOnPlatform("useMSM7"))) // Redundant - but good practice for code reuse) { settings.useMSM7 ^= 1; - gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request update + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) @@ -2122,7 +2122,7 @@ void GNSS_LG290P::menuMessagesSubtype(int *localMessageRate, const char *message if (getNewSetting(messageString, 0, 1, &newSetting) == INPUT_RESPONSE_VALID) { settings.lg290pMessageRatesNMEA[incoming] = newSetting; - gnssConfigureRequest |= UPDATE_MESSAGE_RATE_NMEA; + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Configure receiver to use new setting } } if (strcmp(messageType, "RTCMRover") == 0) @@ -2130,7 +2130,7 @@ void GNSS_LG290P::menuMessagesSubtype(int *localMessageRate, const char *message if (getNewSetting(messageString, 0, 1200, &newSetting) == INPUT_RESPONSE_VALID) { settings.lg290pMessageRatesRTCMRover[incoming] = newSetting; - gnssConfigureRequest |= UPDATE_MESSAGE_RATE_RTCM_ROVER; + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Configure receiver to use new setting } } if (strcmp(messageType, "RTCMBase") == 0) @@ -2138,7 +2138,7 @@ void GNSS_LG290P::menuMessagesSubtype(int *localMessageRate, const char *message if (getNewSetting(messageString, 0, 1200, &newSetting) == INPUT_RESPONSE_VALID) { settings.lg290pMessageRatesRTCMBase[incoming] = newSetting; - gnssConfigureRequest |= UPDATE_MESSAGE_RATE_RTCM_BASE; + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); // Configure receiver to use new setting } } if (strcmp(messageType, "PQTM") == 0) @@ -2146,7 +2146,7 @@ void GNSS_LG290P::menuMessagesSubtype(int *localMessageRate, const char *message if (getNewSetting(messageString, 0, 1, &newSetting) == INPUT_RESPONSE_VALID) { settings.lg290pMessageRatesPQTM[incoming] = newSetting; - gnssConfigureRequest |= UPDATE_MESSAGE_RATE; + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Configure receiver to use new setting } } } @@ -2375,7 +2375,7 @@ bool GNSS_LG290P::setHighAccuracyService(bool enableGalileoHas) if (_lg290p->sendOkCommand("$PQTMCFGPPP", ",W,2,1,120,0.10,0.15") == true) { systemPrintln("Galileo E6 HAS service enabled"); - gnssConfigureRequest |= UPDATE_SAVE; // Request receiver commit this change to NVM + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM } else { @@ -2390,7 +2390,7 @@ bool GNSS_LG290P::setHighAccuracyService(bool enableGalileoHas) if (_lg290p->sendOkCommand("$PQTMCFGPPP", ",W,0") == true) { systemPrintln("Galileo E6 HAS service disabled"); - gnssConfigureRequest |= UPDATE_SAVE; // Request receiver commit this change to NVM + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM } else { diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino index a27789dad..783c2c5a0 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino @@ -1834,7 +1834,7 @@ void GNSS_MOSAIC::menuMessagesNMEA() if (settings.mosaicMessageStreamNMEA[incoming] > MOSAIC_NUM_NMEA_STREAMS) settings.mosaicMessageStreamNMEA[incoming] = 0; // Wrap around - gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings } else if (incoming > MAX_MOSAIC_NMEA_MSG && incoming <= (MAX_MOSAIC_NMEA_MSG + MOSAIC_NUM_NMEA_STREAMS)) // Stream intervals @@ -1853,7 +1853,7 @@ void GNSS_MOSAIC::menuMessagesNMEA() if (interval >= 1 && interval <= MAX_MOSAIC_MSG_RATES) { settings.mosaicStreamIntervalsNMEA[incoming] = interval - 1; - gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings } } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) @@ -1915,7 +1915,7 @@ void GNSS_MOSAIC::menuMessagesRTCM(bool rover) if ((interval >= 0.1) && (interval <= 600.0)) { intervalPtr[incoming] = interval; - gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings } else systemPrintln("Invalid interval: Min 0.1; Max 600.0"); @@ -1991,7 +1991,7 @@ void GNSS_MOSAIC::menuMessages() for (int x = 0; x < MAX_MOSAIC_RTCM_V3_MSG; x++) settings.mosaicMessageEnabledRTCMv3Base[x] = mosaicMessagesRTCMv3[x].defaultEnabled; - gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings systemPrintln("Reset to Defaults"); } diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index cf0b8f786..03cc0c56a 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -1360,7 +1360,7 @@ void GNSS_UM980::menuMessages() systemPrintln("Reset to Defaults"); - gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings } else if (incoming == 11 || incoming == 12) { @@ -1396,7 +1396,7 @@ void GNSS_UM980::menuMessages() systemPrintln("Reset to PPP Logging (NMEAx5 / RTCMx4 - 30 second decimation)"); } - gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) @@ -1507,7 +1507,7 @@ void GNSS_UM980::menuMessagesSubtype(float *localMessageRate, const char *messag if (strcmp(messageType, "RTCMBase") == 0) settings.um980MessageRatesRTCMBase[incoming] = (float)newSetting; - gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings } } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) @@ -1685,7 +1685,7 @@ bool GNSS_UM980::setHighAccuracyService(bool enableGalileoHas) if (_um980->sendCommand("CONFIG PPP ENABLE E6-HAS")) { systemPrintln("Galileo E6 HAS service enabled"); - gnssConfigureRequest |= UPDATE_SAVE; // Request receiver commit this change to NVM + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM } else { @@ -1696,7 +1696,7 @@ bool GNSS_UM980::setHighAccuracyService(bool enableGalileoHas) if (_um980->sendCommand("CONFIG PPP DATUM WGS84")) { systemPrintln("WGS84 Datum applied"); - gnssConfigureRequest |= UPDATE_SAVE; // Request receiver commit this change to NVM + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM } else { @@ -1722,7 +1722,7 @@ bool GNSS_UM980::setHighAccuracyService(bool enableGalileoHas) if (_um980->sendCommand("CONFIG PPP DISABLE")) { systemPrintln("Galileo E6 HAS service disabled"); - gnssConfigureRequest |= UPDATE_SAVE; // Request receiver commit this change to NVM + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM } else { diff --git a/Firmware/RTK_Everywhere/menuBase.ino b/Firmware/RTK_Everywhere/menuBase.ino index e8aeb6de3..4956f6b3f 100644 --- a/Firmware/RTK_Everywhere/menuBase.ino +++ b/Firmware/RTK_Everywhere/menuBase.ino @@ -142,12 +142,12 @@ void menuBase() if (incoming == 1) { settings.fixedBase ^= 1; - gnssConfigureRequest |= UPDATE_BASE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } else if (settings.fixedBase == true && incoming == 2) { settings.fixedBaseCoordinateType ^= 1; - gnssConfigureRequest |= UPDATE_BASE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } else if (settings.fixedBase == true && incoming == 3) @@ -176,7 +176,7 @@ void menuBase() if (getUserInputDouble(&fixedEcefZ) == INPUT_RESPONSE_VALID) { settings.fixedEcefZ = fixedEcefZ; - gnssConfigureRequest |= UPDATE_BASE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } } } @@ -219,7 +219,7 @@ void menuBase() if (getUserInputDouble(&fixedAltitude) == INPUT_RESPONSE_VALID) { settings.fixedAltitude = fixedAltitude; - gnssConfigureRequest |= UPDATE_BASE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } } else @@ -242,7 +242,7 @@ void menuBase() if (getNewSetting("Enter the antenna height (a.k.a. pole length) in millimeters", -15000, 15000, &settings.antennaHeight_mm) == INPUT_RESPONSE_VALID) { - gnssConfigureRequest |= UPDATE_BASE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings // TODO Does any other hardware need to be reconfigured after this setting change? Tilt sensor? } } @@ -254,7 +254,7 @@ void menuBase() "Torch/X2=116.5, Facet mosaic=68.5, EVK=42.0, Postcard=37.5, Flex=62.5", -200.0, 200.0, &settings.antennaPhaseCenter_mm) == INPUT_RESPONSE_VALID) { - gnssConfigureRequest |= UPDATE_BASE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } } @@ -264,7 +264,7 @@ void menuBase() if (getNewSetting("Enter the number of seconds for survey-in observation time", 60, 60 * 10, &settings.observationSeconds) == INPUT_RESPONSE_VALID) { - gnssConfigureRequest |= UPDATE_BASE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } } else if (settings.fixedBase == false && incoming == 3 && @@ -275,7 +275,7 @@ void menuBase() (double)maxObservationPositionAccuracy, &settings.observationPositionAccuracy) == INPUT_RESPONSE_VALID) { - gnssConfigureRequest |= UPDATE_BASE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } } else if (settings.fixedBase == false && incoming == 4 && (!present.gnss_mosaicX5)) @@ -285,7 +285,7 @@ void menuBase() (double)maxSurveyInStartingAccuracy, &settings.surveyInStartingAccuracy) == INPUT_RESPONSE_VALID) { - gnssConfigureRequest |= UPDATE_BASE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } } diff --git a/Firmware/RTK_Everywhere/menuGNSS.ino b/Firmware/RTK_Everywhere/menuGNSS.ino index f82d42d6f..dfb658315 100644 --- a/Firmware/RTK_Everywhere/menuGNSS.ino +++ b/Firmware/RTK_Everywhere/menuGNSS.ino @@ -378,13 +378,13 @@ void menuGNSS() settings.ntripClient_TransmitGGA ^= 1; // We may need to enable the GGA message. Trigger GNSS receiver reconfigure. - gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request update + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request update } else if ((incoming == 15) && present.multipathMitigation) { settings.enableMultipathMitigation ^= 1; - gnssConfigureRequest |= UPDATE_MULTIPATH; // Request update + gnssConfigure(GNSS_CONFIG_MULTIPATH); // Request update } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) diff --git a/Firmware/RTK_Everywhere/menuMessages.ino b/Firmware/RTK_Everywhere/menuMessages.ino index 1cc8a13b7..cda64586d 100644 --- a/Firmware/RTK_Everywhere/menuMessages.ino +++ b/Firmware/RTK_Everywhere/menuMessages.ino @@ -244,21 +244,21 @@ void menuMessagesBaseRTCM() else if (incoming == 2) { gnss->baseRtcmDefault(); - gnssConfigureRequest |= UPDATE_MESSAGE_RATE_RTCM_BASE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); // Request receiver to use new settings systemPrintf("Reset to Defaults (%s)\r\n", gnss->getRtcmDefaultString()); } else if (incoming == 3) { gnss->baseRtcmLowDataRate(); - gnssConfigureRequest |= UPDATE_MESSAGE_RATE_RTCM_BASE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); // Request receiver to use new settings systemPrintf("Reset to Low Bandwidth Link (%s)\r\n", gnss->getRtcmLowDataRateString()); } else if ((incoming == 4) && (namedSettingAvailableOnPlatform("useMSM7"))) { settings.useMSM7 ^= 1; - gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) @@ -878,7 +878,10 @@ void checkGNSSArrayDefaults() } if (defaultsApplied == true) + { + gnssConfigureAll(); //Request a full reconfigure of the GNSS receiver recordSystemSettings(); + } } // Determine logging type based on the GNSS receiver diff --git a/Firmware/RTK_Everywhere/menuPP.ino b/Firmware/RTK_Everywhere/menuPP.ino index 710db12b9..26a30950b 100644 --- a/Firmware/RTK_Everywhere/menuPP.ino +++ b/Firmware/RTK_Everywhere/menuPP.ino @@ -341,7 +341,7 @@ void menuPointPerfectSelectService() settings.pointPerfectService = incoming - 1; // Align incoming to array // Require a rover restart to enable / disable RTCM for PPL - gnssConfigureRequest |= UPDATE_MESSAGE_RATE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings settings.requestKeyUpdate = settings.pointPerfectService != PP_NICKNAME_DISABLED; // Force a key update - or don't diff --git a/Firmware/RTK_Everywhere/menuPorts.ino b/Firmware/RTK_Everywhere/menuPorts.ino index cd1aee888..d4544d7b2 100644 --- a/Firmware/RTK_Everywhere/menuPorts.ino +++ b/Firmware/RTK_Everywhere/menuPorts.ino @@ -159,7 +159,7 @@ void menuPortsNoMux() { // All platforms, except the LG290P can modify their baud rates immediately. // The LG290P requires a reset for settings to take effect - gnssConfigureRequest |= UPDATE_BAUD_RATE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_BAUD_RATE); // Request receiver to use new settings } clearBuffer(); // Empty buffer of any newline chars @@ -316,7 +316,7 @@ void menuPortsMultiplexed() { // Apply these changes at menu exit - to enable message output on USB1 // and/or enable/disable NMEA on radio - gnssConfigureRequest |= UPDATE_BAUD_RATE; // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_BAUD_RATE); // Request receiver to use new settings } gnss->beginExternalEvent(); // Update with new settings From ff7a9ae976f2a9b79c6571869a48ebe4f7d5833d Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 9 Oct 2025 21:31:40 -0600 Subject: [PATCH 13/68] Unify setBaudRate Comm/Data/Radio across platforms. --- Firmware/RTK_Everywhere/GNSS.h | 8 ++- Firmware/RTK_Everywhere/GNSS.ino | 5 +- Firmware/RTK_Everywhere/GNSS_LG290P.h | 10 ++-- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 14 ++--- Firmware/RTK_Everywhere/GNSS_Mosaic.h | 10 ++-- Firmware/RTK_Everywhere/GNSS_Mosaic.ino | 36 +++++++----- Firmware/RTK_Everywhere/GNSS_None.h | 25 ++++---- Firmware/RTK_Everywhere/GNSS_UM980.h | 22 +++---- Firmware/RTK_Everywhere/GNSS_UM980.ino | 77 +++++++++++++++++-------- Firmware/RTK_Everywhere/GNSS_ZED.h | 10 ++-- Firmware/RTK_Everywhere/GNSS_ZED.ino | 38 ++++++------ Firmware/RTK_Everywhere/menuPorts.ino | 8 +-- 12 files changed, 156 insertions(+), 107 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.h b/Firmware/RTK_Everywhere/GNSS.h index 7de5e0836..7bce39e46 100644 --- a/Firmware/RTK_Everywhere/GNSS.h +++ b/Firmware/RTK_Everywhere/GNSS.h @@ -340,7 +340,11 @@ class GNSS virtual bool setBaudRate(uint8_t uartNumber, uint32_t baudRate); - virtual bool setDataBaudRate(uint32_t baud); + virtual bool setBaudRateComm(uint32_t baud); + + virtual bool setBaudRateData(uint32_t baud); + + virtual bool setBaudRateRadio(uint32_t baud); // Set the elevation in degrees // Inputs: @@ -365,8 +369,6 @@ class GNSS // modelNumber: Number of the model to use, provided by radio library virtual bool setModel(uint8_t modelNumber); - virtual bool setRadioBaudRate(uint32_t baud); - // Specify the interval between solutions // Inputs: // secondsBetweenSolutions: Number of seconds between solutions diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index f920e65fc..469fc9067 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -10,14 +10,15 @@ GNSS.ino enum { GNSS_CONFIG_ROVER, - GNSS_CONFIG_BASE, // Fixed base or survey in, location, etc + GNSS_CONFIG_BASE, // Fixed base or survey in, location, etc + GNSS_CONFIG_BAUD_RATE, + GNSS_CONFIG_RATE, GNSS_CONFIG_CONSTELLATION, // Turn on/off a constellation GNSS_CONFIG_MESSAGE_RATE, // Update all message rates GNSS_CONFIG_MESSAGE_RATE_NMEA, // Update NMEA message rates GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER, // Update RTCM Rover message rates GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE, // Update RTCM Base message rates GNSS_CONFIG_HAS_E6, // Enable/disable HAS E6 capabilities - GNSS_CONFIG_BAUD_RATE, GNSS_CONFIG_MULTIPATH, GNSS_CONFIG_SAVE, // Indicates current settings be saved to GNSS receiver NVM GNSS_CONFIG_RESET, // Indicates receiver needs resetting diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.h b/Firmware/RTK_Everywhere/GNSS_LG290P.h index c28a278dc..892b66a4a 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.h +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.h @@ -434,7 +434,11 @@ class GNSS_LG290P : GNSS bool setBaudRate(uint8_t uartNumber, uint32_t baudRate); - bool setCommBaudrate(uint32_t baud); + bool setBaudRateComm(uint32_t baudRate); + + bool setBaudRateData(uint32_t baudRate); + + bool setBaudRateRadio(uint32_t baudRate); // Enable all the valid constellations and bands for this platform bool setConstellations(); @@ -443,8 +447,6 @@ class GNSS_LG290P : GNSS // Always update if force is true. Otherwise, only update if enable has changed state bool setCorrRadioExtPort(bool enable, bool force); - bool setDataBaudRate(uint32_t baud); - // Set the elevation in degrees // Inputs: // elevationDegrees: The elevation value in degrees @@ -463,8 +465,6 @@ class GNSS_LG290P : GNSS // modelNumber: Number of the model to use, provided by radio library bool setModel(uint8_t modelNumber); - bool setRadioBaudRate(uint32_t baud); - // Specify the interval between solutions // Inputs: // secondsBetweenSolutions: Number of seconds between solutions diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index 269e802d3..cdac5a633 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -263,12 +263,12 @@ bool GNSS_LG290P::configureOnce() // Set the baud rate for the three UARTs if (response == true) { - response &= setDataBaudRate(settings.dataPortBaud); // If available, set baud of DATA port + response &= setBaudRateData(settings.dataPortBaud); // If available, set baud of DATA port - // The following setCommBaudrate() is redundant because to get this far, the comm interface must already be - // working response &= setCommBaudrate(115200 * 4); // Set baud for main comm channel + // The following setBaudRateComm() is redundant because to get this far, the comm interface must already be + // working response &= setBaudRateComm(115200 * 4); // Set baud for main comm channel - response &= setRadioBaudRate(settings.radioPortBaud); // If available, set baud of RADIO port + response &= setBaudRateRadio(settings.radioPortBaud); // If available, set baud of RADIO port if (response == false && settings.debugGnss) systemPrintln("configureOnce: setBauds failed."); @@ -1264,7 +1264,7 @@ uint32_t GNSS_LG290P::getDataBaudRate() //---------------------------------------- // Set the baud rate of port nicknamed DATA //---------------------------------------- -bool GNSS_LG290P::setDataBaudRate(uint32_t baud) +bool GNSS_LG290P::setBaudRateData(uint32_t baud) { if (online.gnss) { @@ -1327,7 +1327,7 @@ uint32_t GNSS_LG290P::getRadioBaudRate() //---------------------------------------- // Set the baud rate for the Radio connection //---------------------------------------- -bool GNSS_LG290P::setRadioBaudRate(uint32_t baud) +bool GNSS_LG290P::setBaudRateRadio(uint32_t baud) { if (online.gnss) { @@ -2242,7 +2242,7 @@ bool GNSS_LG290P::saveConfiguration() // Set the baud rate on the GNSS port that interfaces between the ESP32 and the GNSS // This just sets the GNSS side //---------------------------------------- -bool GNSS_LG290P::setCommBaudrate(uint32_t baud) +bool GNSS_LG290P::setBaudRateComm(uint32_t baud) { if (online.gnss) { diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.h b/Firmware/RTK_Everywhere/GNSS_Mosaic.h index 255d615e5..2bc992570 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.h +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.h @@ -980,6 +980,12 @@ class GNSS_MOSAIC : GNSS bool setBaudRate(uint8_t uartNumber, uint32_t baudRate); // From the super class bool setBaudRateCOM(uint8_t port, uint32_t baudRate); // Original X5 implementation + bool setBaudRateComm(uint32_t baudRate); + + bool setBaudRateData(uint32_t baudRate); + + bool setBaudRateRadio(uint32_t baudRate); + // Enable all the valid constellations and bands for this platform bool setConstellations(); @@ -987,8 +993,6 @@ class GNSS_MOSAIC : GNSS // Always update if force is true. Otherwise, only update if enable has changed state bool setCorrRadioExtPort(bool enable, bool force); - bool setDataBaudRate(uint32_t baud); - // Set the elevation in degrees // Inputs: // elevationDegrees: The elevation value in degrees @@ -1011,8 +1015,6 @@ class GNSS_MOSAIC : GNSS // Given the name of a message, find it, and set the rate bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); - bool setRadioBaudRate(uint32_t baud); - // Specify the interval between solutions // Inputs: // secondsBetweenSolutions: Number of seconds between solutions diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino index 783c2c5a0..f6f0de929 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino @@ -258,7 +258,7 @@ void GNSS_MOSAIC::begin() int retryLimit = 3; // Set COM1 baud rate. X5 defaults to 115200. Settings default to 230400bps - while (!setBaudRateCOM(1, settings.dataPortBaud)) + while (!setBaudRateComm(settings.dataPortBaud)) { if (retries == retryLimit) break; @@ -273,8 +273,8 @@ void GNSS_MOSAIC::begin() } // Set COM2 (Radio) and COM3 (Data) baud rates - setRadioBaudRate(settings.radioPortBaud); - setDataBaudRate(settings.dataPortBaud); + setBaudRateRadio(settings.radioPortBaud); + setBaudRateData(settings.dataPortBaud); // Set COM2 (Radio) protocol(s) setCorrRadioExtPort(settings.enableExtCorrRadio, true); // Force the setting @@ -313,8 +313,8 @@ void GNSS_MOSAIC::begin() return; // Set COM2 (Radio) and COM3 (Data) baud rates - setRadioBaudRate(settings.radioPortBaud); - setDataBaudRate(settings.dataPortBaud); // Probably redundant + setBaudRateRadio(settings.radioPortBaud); + setBaudRateData(settings.dataPortBaud); // Probably redundant // Set COM2 (Radio) protocol(s) setCorrRadioExtPort(settings.enableExtCorrRadio, true); // Force the setting @@ -2330,6 +2330,21 @@ bool GNSS_MOSAIC::setBaudRate(uint8_t port, uint32_t baudRate) return setBaudRateCOM(port, baudRate); } +bool GNSS_MOSAIC::setBaudRateComm(uint32_t baud) +{ + return setBaudRateCOM(1, baud); +} + +bool GNSS_MOSAIC::setBaudRateData(uint32_t baud) +{ + return setBaudRateCOM(3, baud); +} + +bool GNSS_MOSAIC::setBaudRateRadio(uint32_t baud) +{ + return setBaudRateCOM(2, baud); +} + //---------------------------------------- // Set the baud rate of mosaic-X5 COM1 // This is used during the Bluetooth test @@ -2420,11 +2435,6 @@ bool GNSS_MOSAIC::setCorrRadioExtPort(bool enable, bool force) return false; } -//---------------------------------------- -bool GNSS_MOSAIC::setDataBaudRate(uint32_t baud) -{ - return setBaudRateCOM(3, baud); -} //---------------------------------------- // Set the elevation in degrees @@ -2507,12 +2517,6 @@ bool GNSS_MOSAIC::setNmeaMessageRateByName(const char *msgName, uint8_t msgRate) return (false); } -//---------------------------------------- -bool GNSS_MOSAIC::setRadioBaudRate(uint32_t baud) -{ - return setBaudRateCOM(2, baud); -} - //---------------------------------------- // Specify the interval between solutions // Inputs: diff --git a/Firmware/RTK_Everywhere/GNSS_None.h b/Firmware/RTK_Everywhere/GNSS_None.h index c6b3fa972..fbcecdc75 100644 --- a/Firmware/RTK_Everywhere/GNSS_None.h +++ b/Firmware/RTK_Everywhere/GNSS_None.h @@ -534,19 +534,29 @@ class GNSS_None : public GNSS return false; } - // Enable all the valid constellations and bands for this platform - bool setConstellations() + bool setBaudRateData(uint32_t baud) { return true; } - // Enable / disable corrections protocol(s) on the Radio External port - bool setCorrRadioExtPort(bool enable, bool force) + bool setBaudRateComm(uint32_t baud) + { + return true; + } + + bool setBaudRateRadio(uint32_t baud) + { + return true; + } + + // Enable all the valid constellations and bands for this platform + bool setConstellations() { return true; } - bool setDataBaudRate(uint32_t baud) + // Enable / disable corrections protocol(s) on the Radio External port + bool setCorrRadioExtPort(bool enable, bool force) { return true; } @@ -591,11 +601,6 @@ class GNSS_None : public GNSS return (true); } - bool setRadioBaudRate(uint32_t baud) - { - return true; - } - // Specify the interval between solutions // Inputs: // secondsBetweenSolutions: Number of seconds between solutions diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.h b/Firmware/RTK_Everywhere/GNSS_UM980.h index 588f228c1..760f4ddec 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.h +++ b/Firmware/RTK_Everywhere/GNSS_UM980.h @@ -143,13 +143,6 @@ class GNSS_UM980 : GNSS // Controls the messages that get broadcast over Bluetooth and logged (if enabled) void menuMessagesSubtype(float *localMessageRate, const char *messageType); - bool setBaudRate(uint8_t uartNumber, uint32_t baudRate); // From the super class - - // Set the baud rate on the GNSS port that interfaces between the ESP32 and the GNSS - // Inputs: - // baudRate: The desired baudrate - bool setBaudRateCOM3(uint32_t baudRate); - bool setHighAccuracyService(bool enableGalileoHas); // Set the minimum satellite signal level for navigation. @@ -433,6 +426,17 @@ class GNSS_UM980 : GNSS // Returns true when the configuration was saved and false upon failure bool saveConfiguration(); + bool setBaudRate(uint8_t uartNumber, uint32_t baudRate); // From the super class + + // Set the baud rate on the GNSS port that interfaces between the ESP32 and the GNSS + // Inputs: + // baudRate: The desired baudrate + bool setBaudRateComm(uint32_t baudRate); + + bool setBaudRateData(uint32_t baudRate); + + bool setBaudRateRadio(uint32_t baudRate); + // Enable all the valid constellations and bands for this platform bool setConstellations(); @@ -442,8 +446,6 @@ class GNSS_UM980 : GNSS return true; } - bool setDataBaudRate(uint32_t baud); - // Set the elevation in degrees // Inputs: // elevationDegrees: The elevation value in degrees @@ -472,8 +474,6 @@ class GNSS_UM980 : GNSS // Given the name of a message, find it, and set the rate bool setRtcmRoverMessageRateByName(const char *msgName, uint8_t msgRate); - bool setRadioBaudRate(uint32_t baud); - // Specify the interval between solutions // Inputs: // secondsBetweenSolutions: Number of seconds between solutions diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index 03cc0c56a..d28c4555f 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -248,12 +248,11 @@ bool GNSS_UM980::configureOnce() disableAllOutput(); // Disable COM1/2/3 bool response = true; - response &= _um980->setPortBaudrate("COM1", 115200); // COM1 is connected to switch, then USB - response &= _um980->setPortBaudrate("COM2", 115200); // COM2 is connected to the IMU - response &= _um980->setPortBaudrate("COM3", 115200); // COM3 is connected to the switch, then ESP32 + response &= _um980->setPortBaudrate("COM1", 115200); // UM980 UART1 is connected to switch, then USB + response &= _um980->setPortBaudrate("COM2", 115200); // UM980 UART2 is connected to the IMU - // // For now, let's not change the baud rate of the interface. We'll be using the default 115200 for now. - // response &= setBaudRateCOM3(settings.dataPortBaud); // COM3 is connected to ESP UART2 + // Assume if we've made it this far, the UM980 UART3 is communicating + // response &= setBaudRateComm(115200); // UM980 UART3 is connected to the switch, then ESP32 // Enable PPS signal with a width of 200ms, and a period of 1 second response &= _um980->enablePPS(200000, 1000); // widthMicroseconds, periodMilliseconds @@ -542,6 +541,9 @@ bool GNSS_UM980::enableNMEA() response &= _um980->setNMEAPortMessage("GPZDA", "COM3", 1); } + if (response == true) + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + return (response); } @@ -630,6 +632,9 @@ bool GNSS_UM980::enableRTCMRover() response &= _um980->setRTCMPortMessage("RTCM1046", "COM3", 1); } + if (response == true) + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + return (response); } @@ -1602,19 +1607,30 @@ bool GNSS_UM980::setBaudRate(uint8_t uartNumber, uint32_t baudRate) return (false); } - return setBaudRateCOM3(baudRate); + return setBaudRateComm(baudRate); } //---------------------------------------- // Set the baud rate on the GNSS port that interfaces between the ESP32 and the GNSS +// This just sets the GNSS side //---------------------------------------- -bool GNSS_UM980::setBaudRateCOM3(uint32_t baudRate) +bool GNSS_UM980::setBaudRateComm(uint32_t baudRate) { if (online.gnss) return _um980->setPortBaudrate("COM3", baudRate); return false; } +bool GNSS_UM980::setBaudRateData(uint32_t baudRate) +{ + return false; // UM980 has DATA port +} + +bool GNSS_UM980::setBaudRateRadio(uint32_t baudRate) +{ + return false; // UM980 has no RADIO port +} + //---------------------------------------- // Enable all the valid constellations and bands for this platform // Band support varies between platforms and firmware versions @@ -1650,12 +1666,6 @@ bool GNSS_UM980::setConstellations() return (response); } -//---------------------------------------- -bool GNSS_UM980::setDataBaudRate(uint32_t baud) -{ - return false; // UM980 has no multiplexer -} - //---------------------------------------- // Set the elevation in degrees //---------------------------------------- @@ -1823,12 +1833,6 @@ bool GNSS_UM980::setMultipathMitigation(bool enableMultipathMitigation) return (result); } -//---------------------------------------- -bool GNSS_UM980::setRadioBaudRate(uint32_t baud) -{ - return false; // UM980 has no multiplexer -} - //---------------------------------------- // Given the number of seconds between desired solution reports, determine measurementRateMs and navigationRate //---------------------------------------- @@ -1842,17 +1846,44 @@ bool GNSS_UM980::setRate(double secondsBetweenSolutions) // ie, if a message != 0, then it will be output at the measurementRate. // All RTCM for a base will be based on a measurementRateMs of 1000 with messages // that can be reported more slowly than that (ie 1 per 10 seconds). + + // Read/Modify/Write + // Determine if we need to modify the setting at all + bool changeRequired = false; + + // Determine if the given setting different from our current settings + for (int messageNumber = 0; messageNumber < MAX_UM980_NMEA_MSG; messageNumber++) + { + if (settings.um980MessageRatesNMEA[messageNumber] > 0) + if (settings.um980MessageRatesNMEA[messageNumber] != secondsBetweenSolutions) + changeRequired = true; + } + for (int messageNumber = 0; messageNumber < MAX_UM980_RTCM_MSG; messageNumber++) + { + if (settings.um980MessageRatesRTCMRover[messageNumber] > 0) + if (settings.um980MessageRatesRTCMRover[messageNumber] != secondsBetweenSolutions) + changeRequired = true; + } + + if (changeRequired == false) + { + if (settings.debugGnss) + systemPrintln("setRate: No change required"); + return (true); // Success + } + + if (settings.debugGnss) + systemPrintln("setRate: Modifying rates"); + bool response = true; - disableAllOutput(); + disableAllOutput(); // Turn everything off, before we turn on specific messages // Overwrite any enabled messages with this rate for (int messageNumber = 0; messageNumber < MAX_UM980_NMEA_MSG; messageNumber++) { if (settings.um980MessageRatesNMEA[messageNumber] > 0) - { settings.um980MessageRatesNMEA[messageNumber] = secondsBetweenSolutions; - } } response &= enableNMEA(); // Enact these rates @@ -1862,9 +1893,7 @@ bool GNSS_UM980::setRate(double secondsBetweenSolutions) for (int messageNumber = 0; messageNumber < MAX_UM980_RTCM_MSG; messageNumber++) { if (settings.um980MessageRatesRTCMRover[messageNumber] > 0) - { settings.um980MessageRatesRTCMRover[messageNumber] = secondsBetweenSolutions; - } } response &= enableRTCMRover(); // Enact these rates diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.h b/Firmware/RTK_Everywhere/GNSS_ZED.h index 2b3a5f2f9..7744f8417 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.h +++ b/Firmware/RTK_Everywhere/GNSS_ZED.h @@ -678,6 +678,12 @@ class GNSS_ZED : GNSS // Set the baud rate on the designated port bool setBaudRate(uint8_t uartNumber, uint32_t baudRate); // From the super class + bool setBaudRateComm(uint32_t baudRate); + + bool setBaudRateData(uint32_t baudRate); + + bool setBaudRateRadio(uint32_t baudRate); + // Enable all the valid constellations and bands for this platform bool setConstellations(); @@ -685,8 +691,6 @@ class GNSS_ZED : GNSS // Always update if force is true. Otherwise, only update if enable has changed state bool setCorrRadioExtPort(bool enable, bool force); - bool setDataBaudRate(uint32_t baud); - // Set the elevation in degrees // Inputs: // elevationDegrees: The elevation value in degrees @@ -718,8 +722,6 @@ class GNSS_ZED : GNSS // Given the name of a message, find it, and set the rate bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); - bool setRadioBaudRate(uint32_t baud); - // Specify the interval between solutions // Inputs: // secondsBetweenSolutions: Number of seconds between solutions diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index d28313a83..89fc507d1 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -2026,11 +2026,30 @@ bool GNSS_ZED::setBaudRate(uint8_t port, uint32_t baudRate) } if (port == 1) - return setDataBaudRate(baudRate); + return setBaudRateData(baudRate); else - return setRadioBaudRate(baudRate); + return setBaudRateRadio(baudRate); } +// With ZED modules, configuration communication is done over I2C. No 'Comm' UART exists. +bool GNSS_ZED::setBaudRateComm(uint32_t baudRate) +{ + return false; +} + +bool GNSS_ZED::setBaudRateData(uint32_t baudRate) +{ + if (online.gnss) + return _zed->setVal32(UBLOX_CFG_UART1_BAUDRATE, baudRate, VAL_LAYER_ALL); + return false; +} + +bool GNSS_ZED::setBaudRateRadio(uint32_t baudRate) +{ + if (online.gnss) + return _zed->setVal32(UBLOX_CFG_UART2_BAUDRATE, baudRate, VAL_LAYER_ALL); + return false; +} //---------------------------------------- // Save the current configuration // Returns true when the configuration was saved and false upon failure @@ -2162,13 +2181,6 @@ bool GNSS_ZED::setCorrRadioExtPort(bool enable, bool force) return false; } -//---------------------------------------- -bool GNSS_ZED::setDataBaudRate(uint32_t baud) -{ - if (online.gnss) - return _zed->setVal32(UBLOX_CFG_UART1_BAUDRATE, baud, VAL_LAYER_ALL); - return false; -} //---------------------------------------- // Set the elevation in degrees @@ -2373,14 +2385,6 @@ bool GNSS_ZED::setModel(uint8_t modelNumber) return false; } -//---------------------------------------- -bool GNSS_ZED::setRadioBaudRate(uint32_t baud) -{ - if (online.gnss) - return _zed->setVal32(UBLOX_CFG_UART2_BAUDRATE, baud, VAL_LAYER_ALL); - return false; -} - //---------------------------------------- // Given the number of seconds between desired solution reports, determine measurementRateMs and navigationRate // measurementRateS > 25 & <= 65535 diff --git a/Firmware/RTK_Everywhere/menuPorts.ino b/Firmware/RTK_Everywhere/menuPorts.ino index d4544d7b2..4ae265d53 100644 --- a/Firmware/RTK_Everywhere/menuPorts.ino +++ b/Firmware/RTK_Everywhere/menuPorts.ino @@ -98,7 +98,7 @@ void menuPortsNoMux() { settings.radioPortBaud = newBaud; if (online.gnss == true) - gnss->setRadioBaudRate(newBaud); + gnss->setBaudRateRadio(newBaud); } else { @@ -116,7 +116,7 @@ void menuPortsNoMux() { settings.dataPortBaud = newBaud; if (online.gnss == true) - gnss->setDataBaudRate(newBaud); + gnss->setBaudRateData(newBaud); } else { @@ -232,7 +232,7 @@ void menuPortsMultiplexed() { settings.radioPortBaud = newBaud; if (online.gnss == true) - gnss->setRadioBaudRate(newBaud); + gnss->setBaudRateRadio(newBaud); } else { @@ -269,7 +269,7 @@ void menuPortsMultiplexed() { settings.dataPortBaud = newBaud; if (online.gnss == true) - gnss->setDataBaudRate(newBaud); + gnss->setBaudRateData(newBaud); } else { From 033a8c3902d9285f93053ef87358aca787c02cc4 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Fri, 10 Oct 2025 11:16:15 -0600 Subject: [PATCH 14/68] UM980: Read/Modify/Write baud rates --- Firmware/RTK_Everywhere/GNSS_UM980.ino | 30 ++++++++++++++++++-------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index d28c4555f..61e5c61e0 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -248,8 +248,8 @@ bool GNSS_UM980::configureOnce() disableAllOutput(); // Disable COM1/2/3 bool response = true; - response &= _um980->setPortBaudrate("COM1", 115200); // UM980 UART1 is connected to switch, then USB - response &= _um980->setPortBaudrate("COM2", 115200); // UM980 UART2 is connected to the IMU + response &= setBaudRateData(115200); // UM980 UART1 is connected to switch, then USB + response &= setBaudRate(2, 115200); // UM980 UART2 is connected to the IMU // Assume if we've made it this far, the UM980 UART3 is communicating // response &= setBaudRateComm(115200); // UM980 UART3 is connected to the switch, then ESP32 @@ -1601,29 +1601,40 @@ bool GNSS_UM980::saveConfiguration() //---------------------------------------- bool GNSS_UM980::setBaudRate(uint8_t uartNumber, uint32_t baudRate) { - if (uartNumber != 3) + if (uartNumber < 1 || uartNumber > 3) { systemPrintln("setBaudRate error: out of range"); return (false); } - return setBaudRateComm(baudRate); + // The UART on the UM980 is passed as a string with quotes, ie "COM2" + char comName[7]; // "COM3" + snprintf(comName, sizeof(comName), "\"COM%d\"", uartNumber); + + // Read, modify, write + uint32_t currentBaudRate = _um980->getPortBaudrate(comName); + if (currentBaudRate == baudRate) + return (true); // No change needed + + return _um980->setPortBaudrate(comName, baudRate); //("COM3", 115200) } +// UM980 COM1 - (DATA) Connected to the USB CH342 +// UM980 COM2 - Connected To IMU +// UM980 COM3 - (COMM) Connected to ESP32 for BT, configuration, and LoRa Radio. +// No RADIO connection. //---------------------------------------- // Set the baud rate on the GNSS port that interfaces between the ESP32 and the GNSS // This just sets the GNSS side //---------------------------------------- bool GNSS_UM980::setBaudRateComm(uint32_t baudRate) { - if (online.gnss) - return _um980->setPortBaudrate("COM3", baudRate); - return false; + return (setBaudRate(3, baudRate)); } bool GNSS_UM980::setBaudRateData(uint32_t baudRate) { - return false; // UM980 has DATA port + return (setBaudRate(1, baudRate)); // The DATA port on the Torch is the USB C connector } bool GNSS_UM980::setBaudRateRadio(uint32_t baudRate) @@ -1719,7 +1730,8 @@ bool GNSS_UM980::setHighAccuracyService(bool enableGalileoHas) { systemPrintf( "Current UM980 firmware: v%d. Galileo E6 reception requires v11833 or newer. Please update the " - "firmware on your UM980 to allow for HAS operation. Please see https://bit.ly/sfe-rtk-um980-update\r\n", + "firmware on your UM980 to allow for HAS operation. Please see " + "https://bit.ly/sfe-rtk-um980-update\r\n", um980Version); // Don't fail the result. Module is still configured, just without HAS. } From dcad59db169c2aa8e8ebe40861df34d1c1643615 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Fri, 10 Oct 2025 11:33:32 -0600 Subject: [PATCH 15/68] Remove setNmeaMessageRates --- Firmware/RTK_Everywhere/GNSS_LG290P.h | 3 --- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 7 ------- Firmware/RTK_Everywhere/GNSS_UM980.h | 3 --- Firmware/RTK_Everywhere/GNSS_UM980.ino | 7 ------- 4 files changed, 20 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.h b/Firmware/RTK_Everywhere/GNSS_LG290P.h index 892b66a4a..c4fe7ade3 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.h +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.h @@ -132,9 +132,6 @@ class GNSS_LG290P : GNSS // Set the minimum satellite signal level for navigation. bool setMinCnoRadio(uint8_t cnoValue); - // Set all NMEA message report rates to one value - void setNmeaMessageRates(uint8_t msgRate); - // Given the name of a message, find it, and set the rate bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index cdac5a633..e0b442d1a 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -2668,13 +2668,6 @@ uint32_t GNSS_LG290P::baudGetMaximum() return (lg290pAllowedRates[lg290pAllowedRatesCount - 1]); } -// Set all NMEA message report rates to one value -void GNSS_LG290P::setNmeaMessageRates(uint8_t msgRate) -{ - for (int x = 0; x < MAX_LG290P_NMEA_MSG; x++) - settings.lg290pMessageRatesNMEA[x] = msgRate; -} - // Set all RTCM Rover message report rates to one value void GNSS_LG290P::setRtcmRoverMessageRates(uint8_t msgRate) { diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.h b/Firmware/RTK_Everywhere/GNSS_UM980.h index 760f4ddec..41e5aa967 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.h +++ b/Firmware/RTK_Everywhere/GNSS_UM980.h @@ -462,9 +462,6 @@ class GNSS_UM980 : GNSS // modelNumber: Number of the model to use, provided by radio library bool setModel(uint8_t modelNumber); - // Set all NMEA message report rates to one value - void setNmeaMessageRates(uint8_t msgRate); - // Given the name of a message, find it, and set the rate bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index 61e5c61e0..9c0fa0c71 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -2038,13 +2038,6 @@ void GNSS_UM980::update() // We don't check serial data here; the gnssReadTask takes care of serial consumption } -// Set all NMEA message report rates to one value -void GNSS_UM980::setNmeaMessageRates(uint8_t msgRate) -{ - for (int x = 0; x < MAX_UM980_NMEA_MSG; x++) - settings.um980MessageRatesNMEA[x] = msgRate; -} - // Set all RTCM Rover message report rates to one value void GNSS_UM980::setRtcmRoverMessageRates(uint8_t msgRate) { From 6ffcda52e20bb2e73b88553cad3dd222a1ad4001 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Fri, 10 Oct 2025 12:46:29 -0600 Subject: [PATCH 16/68] Rename setMinCnoRadio, change setMinCno in master class to public --- Firmware/RTK_Everywhere/GNSS.h | 5 +- Firmware/RTK_Everywhere/GNSS.ino | 63 ++++++++++++++----------- Firmware/RTK_Everywhere/GNSS_LG290P.h | 2 +- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 8 ++-- Firmware/RTK_Everywhere/GNSS_Mosaic.h | 2 +- Firmware/RTK_Everywhere/GNSS_Mosaic.ino | 6 +-- Firmware/RTK_Everywhere/GNSS_None.h | 2 +- Firmware/RTK_Everywhere/GNSS_UM980.h | 2 +- Firmware/RTK_Everywhere/GNSS_UM980.ino | 34 ++++++++++--- Firmware/RTK_Everywhere/GNSS_ZED.h | 2 +- Firmware/RTK_Everywhere/GNSS_ZED.ino | 2 +- 11 files changed, 78 insertions(+), 50 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.h b/Firmware/RTK_Everywhere/GNSS.h index 7bce39e46..1b39bdffa 100644 --- a/Firmware/RTK_Everywhere/GNSS.h +++ b/Firmware/RTK_Everywhere/GNSS.h @@ -49,9 +49,6 @@ class GNSS // Returns true if successfully configured and false upon failure virtual bool configureGNSS(); - // Set the minimum satellite signal level for navigation. - virtual bool setMinCnoRadio(uint8_t cnoValue); - public: // Constructor GNSS() : _leapSeconds(18), _pvtArrivalMillis(0), _pvtUpdated(0), _satellitesInView(0) @@ -362,7 +359,7 @@ class GNSS virtual bool setMessagesUsb(int maxRetries); // Set the minimum satellite signal level for navigation. - bool setMinCno(uint8_t cnoValue); + virtual bool setMinCno(uint8_t cnoValue); // Set the dynamic model to use for RTK // Inputs: diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index 469fc9067..e33393d05 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -13,7 +13,9 @@ enum GNSS_CONFIG_BASE, // Fixed base or survey in, location, etc GNSS_CONFIG_BAUD_RATE, GNSS_CONFIG_RATE, - GNSS_CONFIG_CONSTELLATION, // Turn on/off a constellation + GNSS_CONFIG_CONSTELLATION, // Turn on/off a constellation + GNSS_CONFIG_ELEVATION, + GNSS_CONFIG_CN0, GNSS_CONFIG_MESSAGE_RATE, // Update all message rates GNSS_CONFIG_MESSAGE_RATE_NMEA, // Update NMEA message rates GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER, // Update RTCM Rover message rates @@ -28,7 +30,7 @@ enum GNSS_CONFIG_NONE, }; -uint16_t gnssConfigureRequest = +uint32_t gnssConfigureRequest = GNSS_CONFIG_NONE; // Bitfield containing an update be made to various settings on the GNSS receiver extern int NTRIPCLIENT_MS_BETWEEN_GGA; @@ -86,18 +88,6 @@ bool GNSS::isAntennaOpen() return false; } -//---------------------------------------- -// Set the minimum satellite signal level for navigation. -//---------------------------------------- -bool GNSS::setMinCno(uint8_t cnoValue) -{ - // Update the setting - settings.minCNO = cnoValue; - - // Pass the value to the GNSS receiver - return gnss->setMinCnoRadio(cnoValue); -} - // Antenna Short / Open detection bool GNSS::supportsAntennaShortOpen() { @@ -125,21 +115,38 @@ void gnssUpdate() { bool result = true; - // Test for individual changes as needed + // Service requests + // Clear the requests as they are completed successfully + if (gnssConfigureRequest & GNSS_CONFIG_CONSTELLATION) { } + + if (gnssConfigureRequest & GNSS_CONFIG_ELEVATION) + { + if(gnss->setElevation(settings.minElev) == true) + gnssConfigureClear(GNSS_CONFIG_ELEVATION); + } + + if (gnssConfigureRequest & GNSS_CONFIG_CN0) + { + if(gnss->setMinCno(settings.minCNO) == true) + gnssConfigureClear(GNSS_CONFIG_CN0); + } + if (gnssConfigureRequest & GNSS_CONFIG_HAS_E6) { - result &= gnss->setHighAccuracyService(settings.enableGalileoHas); + if(gnss->setHighAccuracyService(settings.enableGalileoHas) == true) + gnssConfigureClear(GNSS_CONFIG_HAS_E6); } - // Platforms will set theGNSS_CONFIG_SAVE andGNSS_CONFIG_RESET bits appropriately for each command issued + // Platforms will set the GNSS_CONFIG_SAVE and GNSS_CONFIG_RESET bits appropriately for each command issued // If one of the previous configuration changes requested save to NVM, do so if (gnssConfigureRequest & GNSS_CONFIG_SAVE) { - result &= gnss->saveConfiguration(); + if(gnss->saveConfiguration()) + gnssConfigureClear(GNSS_CONFIG_SAVE); } // Here we need a table to determine if the given combination of setting requests require a GNSS reset to take @@ -167,18 +174,23 @@ void gnssUpdate() { systemPrintln("gnssUpdate: Uncaught mode change"); } - - gnssConfigureRequest = GNSS_CONFIG_NONE; // Clear requests } } // Given a bit to configure, set that bit in the overall bitfield -void gnssConfigure(uint16_t configureBit) +void gnssConfigure(uint8_t configureBit) { - uint16_t mask = (1 << configureBit); + uint32_t mask = (1 << configureBit); gnssConfigureRequest |= mask; } +// Given a bit to configure, clear that bit from the overall bitfield +void gnssConfigureClear(uint8_t configureBit) +{ + uint32_t mask = ~(1 << configureBit); + gnssConfigureRequest &= mask; +} + // Set all bits in the request bitfield to cause the GNSS receiver to go through a full (re)configuration void gnssConfigureAll() { @@ -191,8 +203,7 @@ void gnssConfigureAll() //---------------------------------------- bool gnssCmdUpdateConstellations(const char *settingName, void *settingData, int settingType) { - gnssConfigureRequest |= - GNSS_CONFIG_CONSTELLATION; // Once BLE Command, Web Config, and CLI are closed, reconfigure receiver + gnssConfigure(GNSS_CONFIG_CONSTELLATION); // Request receiver to use new settings return (true); } @@ -202,9 +213,7 @@ bool gnssCmdUpdateConstellations(const char *settingName, void *settingData, int //---------------------------------------- bool gnssCmdUpdateMessageRates(const char *settingName, void *settingData, int settingType) { - gnssConfigureRequest |= - GNSS_CONFIG_MESSAGE_RATE; // Once BLE Command, Web Config, and CLI are closed, reconfigure receiver - + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings return (true); } diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.h b/Firmware/RTK_Everywhere/GNSS_LG290P.h index c4fe7ade3..adb42bba1 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.h +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.h @@ -130,7 +130,7 @@ class GNSS_LG290P : GNSS void menuMessagesSubtype(int *localMessageRate, const char *messageType); // Set the minimum satellite signal level for navigation. - bool setMinCnoRadio(uint8_t cnoValue); + bool setMinCno(uint8_t cnoValue); // Given the name of a message, find it, and set the rate bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index e0b442d1a..1c3216c5f 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -363,7 +363,7 @@ bool GNSS_LG290P::configureRover() response &= setElevation(settings.minElev); - response &= setMinCnoRadio(settings.minCNO); + response &= setMinCno(settings.minCNO); // If we are on a platform that supports tilt if (present.tiltPossible == true) @@ -509,7 +509,7 @@ bool GNSS_LG290P::configureBase() response &= setElevation(settings.minElev); - response &= setMinCnoRadio(settings.minCNO); + response &= setMinCno(settings.minCNO); response &= setHighAccuracyService(settings.enableGalileoHas); @@ -1981,7 +1981,7 @@ void GNSS_LG290P::menuMessages() // Override settings for PPP logging setElevation(15); - setMinCnoRadio(30); + setMinCno(30); setRate(1); // Go to 1 Hz @@ -2426,7 +2426,7 @@ bool GNSS_LG290P::setMessagesUsb(int maxRetries) //---------------------------------------- // Set the minimum satellite signal level for navigation. //---------------------------------------- -bool GNSS_LG290P::setMinCnoRadio(uint8_t cnoValue) +bool GNSS_LG290P::setMinCno(uint8_t cnoValue) { // Present on >= v05 if (lg290pFirmwareVersion >= 5) diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.h b/Firmware/RTK_Everywhere/GNSS_Mosaic.h index 2bc992570..7ed6f9558 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.h +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.h @@ -527,7 +527,7 @@ class GNSS_MOSAIC : GNSS bool configureGNSS(); // Set the minimum satellite signal level for navigation. - bool setMinCnoRadio(uint8_t cnoValue); + bool setMinCno(uint8_t cnoValue); public: // Allow access from parser routines diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino index f6f0de929..b13a6c0cc 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino @@ -471,7 +471,7 @@ bool GNSS_MOSAIC::configureBase() response &= setElevation(settings.minElev); - response &= setMinCnoRadio(settings.minCNO); + response &= setMinCno(settings.minCNO); response &= setConstellations(); @@ -718,7 +718,7 @@ bool GNSS_MOSAIC::configureRover() response &= setElevation(settings.minElev); // Set by menuGNSS which calls gnss->setElevation - response &= setMinCnoRadio(settings.minCNO); + response &= setMinCno(settings.minCNO); response &= setConstellations(); @@ -2482,7 +2482,7 @@ bool GNSS_MOSAIC::setMessagesUsb(int maxRetries) //---------------------------------------- // Set the minimum satellite signal level for navigation. //---------------------------------------- -bool GNSS_MOSAIC::setMinCnoRadio(uint8_t cnoValue) +bool GNSS_MOSAIC::setMinCno(uint8_t cnoValue) { if (cnoValue > 60) cnoValue = 60; diff --git a/Firmware/RTK_Everywhere/GNSS_None.h b/Firmware/RTK_Everywhere/GNSS_None.h index fbcecdc75..b2248533d 100644 --- a/Firmware/RTK_Everywhere/GNSS_None.h +++ b/Firmware/RTK_Everywhere/GNSS_None.h @@ -20,7 +20,7 @@ class GNSS_None : public GNSS } // Set the minimum satellite signal level for navigation. - bool setMinCnoRadio(uint8_t cnoValue) + bool setMinCno(uint8_t cnoValue) { return false; } diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.h b/Firmware/RTK_Everywhere/GNSS_UM980.h index 41e5aa967..4b653281f 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.h +++ b/Firmware/RTK_Everywhere/GNSS_UM980.h @@ -146,7 +146,7 @@ class GNSS_UM980 : GNSS bool setHighAccuracyService(bool enableGalileoHas); // Set the minimum satellite signal level for navigation. - bool setMinCnoRadio(uint8_t cnoValue); + bool setMinCno(uint8_t cnoValue); bool setMultipathMitigation(bool enableMultipathMitigation); diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index 9c0fa0c71..f2c3455f6 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -249,7 +249,7 @@ bool GNSS_UM980::configureOnce() bool response = true; response &= setBaudRateData(115200); // UM980 UART1 is connected to switch, then USB - response &= setBaudRate(2, 115200); // UM980 UART2 is connected to the IMU + response &= setBaudRate(2, 115200); // UM980 UART2 is connected to the IMU // Assume if we've made it this far, the UM980 UART3 is communicating // response &= setBaudRateComm(115200); // UM980 UART3 is connected to the switch, then ESP32 @@ -257,9 +257,10 @@ bool GNSS_UM980::configureOnce() // Enable PPS signal with a width of 200ms, and a period of 1 second response &= _um980->enablePPS(200000, 1000); // widthMicroseconds, periodMilliseconds - response &= setElevation(settings.minElev); // UM980 default is 5 degrees. Our default is 10. + gnssConfigure(GNSS_CONFIG_ELEVATION); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_CN0); - response &= setMinCnoRadio(settings.minCNO); + response &= setMinCno(settings.minCNO); response &= setConstellations(); @@ -1683,7 +1684,15 @@ bool GNSS_UM980::setConstellations() bool GNSS_UM980::setElevation(uint8_t elevationDegrees) { if (online.gnss) + { + // Read, modify, write + float currentElevation = _um980->getElevationAngle(); + if (currentElevation == elevationDegrees) + return (true); // Nothing to change + + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM return _um980->setElevationAngle(elevationDegrees); + } return false; } @@ -1701,6 +1710,7 @@ bool GNSS_UM980::setHighAccuracyService(bool enableGalileoHas) int um980Version = String(_um980->getVersion()).toInt(); // Convert the string response to a value if (um980Version >= 11833) { + // Read, modify, write if (_um980->isConfigurationPresent("CONFIG PPP ENABLE E6-HAS") == false) { if (_um980->sendCommand("CONFIG PPP ENABLE E6-HAS")) @@ -1780,13 +1790,16 @@ bool GNSS_UM980::setMessagesUsb(int maxRetries) } //---------------------------------------- -// Set the minimum satellite signal level for navigation. +// Set the minimum satellite signal level (carrier to noise ratio) for navigation. //---------------------------------------- -bool GNSS_UM980::setMinCnoRadio(uint8_t cnoValue) +bool GNSS_UM980::setMinCno(uint8_t cn0Value) { if (online.gnss) { - _um980->setMinCNO(cnoValue); + // Read, modify, write + // The UM980 does not currently have a way to read the CN0, so we must write only + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + _um980->setMinCNO(cn0Value); return true; } return false; @@ -1799,6 +1812,8 @@ bool GNSS_UM980::setModel(uint8_t modelNumber) { if (online.gnss) { + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + if (modelNumber == UM980_DYN_MODEL_SURVEY) return (_um980->setModeRoverSurvey()); else if (modelNumber == UM980_DYN_MODEL_UAV) @@ -1820,7 +1835,10 @@ bool GNSS_UM980::setMultipathMitigation(bool enableMultipathMitigation) if (_um980->isConfigurationPresent("CONFIG MMP ENABLE") == false) { if (_um980->sendCommand("CONFIG MMP ENABLE")) + { systemPrintln("Multipath Mitigation enabled"); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } else { systemPrintln("Multipath Mitigation failed to enable"); @@ -1834,7 +1852,10 @@ bool GNSS_UM980::setMultipathMitigation(bool enableMultipathMitigation) if (_um980->isConfigurationPresent("CONFIG MMP ENABLE")) { if (_um980->sendCommand("CONFIG MMP DISABLE")) + { systemPrintln("Multipath Mitigation disabled"); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } else { systemPrintln("Multipath Mitigation failed to disable"); @@ -1914,6 +1935,7 @@ bool GNSS_UM980::setRate(double secondsBetweenSolutions) { uint16_t msBetweenSolutions = secondsBetweenSolutions * 1000; settings.measurementRateMs = msBetweenSolutions; + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM } else { diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.h b/Firmware/RTK_Everywhere/GNSS_ZED.h index 7744f8417..03f16cb66 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.h +++ b/Firmware/RTK_Everywhere/GNSS_ZED.h @@ -712,7 +712,7 @@ class GNSS_ZED : GNSS bool setMessagesUsb(int maxRetries); // Set the minimum satellite signal level for navigation. - bool setMinCnoRadio(uint8_t cnoValue); + bool setMinCno(uint8_t cnoValue); // Set the dynamic model to use for RTK // Inputs: diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index 89fc507d1..a0817c5ce 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -2362,7 +2362,7 @@ bool GNSS_ZED::setMessagesUsb(int maxRetries) //---------------------------------------- // Set the minimum satellite signal level for navigation. //---------------------------------------- -bool GNSS_ZED::setMinCnoRadio(uint8_t cnoValue) +bool GNSS_ZED::setMinCno(uint8_t cnoValue) { if (online.gnss) { From da19e19ee47d28aab04ed4eb82ae01d44ad1df8c Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Fri, 10 Oct 2025 13:01:17 -0600 Subject: [PATCH 17/68] Remove beginPPS(), convert toe setPPS --- Firmware/RTK_Everywhere/GNSS.h | 575 ++++++++++++------------ Firmware/RTK_Everywhere/GNSS.ino | 7 + Firmware/RTK_Everywhere/GNSS_LG290P.h | 7 +- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 2 +- Firmware/RTK_Everywhere/GNSS_Mosaic.h | 12 +- Firmware/RTK_Everywhere/GNSS_Mosaic.ino | 2 +- Firmware/RTK_Everywhere/GNSS_None.h | 15 +- Firmware/RTK_Everywhere/GNSS_UM980.h | 11 +- Firmware/RTK_Everywhere/GNSS_UM980.ino | 23 +- Firmware/RTK_Everywhere/GNSS_ZED.h | 14 +- Firmware/RTK_Everywhere/GNSS_ZED.ino | 4 +- Firmware/RTK_Everywhere/menuGNSS.ino | 8 +- Firmware/RTK_Everywhere/menuPorts.ino | 4 +- Firmware/RTK_Everywhere/settings.h | 2 +- 14 files changed, 339 insertions(+), 347 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.h b/Firmware/RTK_Everywhere/GNSS.h index 1b39bdffa..c9374bb0a 100644 --- a/Firmware/RTK_Everywhere/GNSS.h +++ b/Firmware/RTK_Everywhere/GNSS.h @@ -9,394 +9,391 @@ GNSS.h class GNSS { -protected: - float _altitude; // Altitude in meters - float _horizontalAccuracy; // Horizontal position accuracy in meters - double _latitude; // Latitude in degrees - double _longitude; // Longitude in degrees - - uint8_t _day; // Day number - uint8_t _month; // Month number - uint16_t _year; - uint8_t _hour; // Hours for 24 hour clock - uint8_t _minute; - uint8_t _second; - uint8_t _leapSeconds; - uint16_t _millisecond; // Limited to first two digits - uint32_t _nanosecond; - - uint8_t _satellitesInView; - uint8_t _fixType; - uint8_t _carrierSolution; - - bool _validDate; // True when date is valid - bool _validTime; // True when time is valid - bool _confirmedDate; - bool _confirmedTime; - bool _fullyResolved; - uint32_t _tAcc; - - unsigned long _pvtArrivalMillis; - bool _pvtUpdated; - - bool _corrRadioExtPortEnabled = false; - - unsigned long _autoBaseStartTimer; // Tracks how long the base auto / averaging mode has been running - - // Setup the general configuration of the GNSS - // Not Rover or Base specific (ie, baud rates) - // Outputs: - // Returns true if successfully configured and false upon failure - virtual bool configureGNSS(); - -public: - // Constructor - GNSS() : _leapSeconds(18), _pvtArrivalMillis(0), _pvtUpdated(0), _satellitesInView(0) - { - } - - // If we have decryption keys, configure module - // Note: don't check online.lband_neo here. We could be using ip corrections - virtual void applyPointPerfectKeys(); + protected: + float _altitude; // Altitude in meters + float _horizontalAccuracy; // Horizontal position accuracy in meters + double _latitude; // Latitude in degrees + double _longitude; // Longitude in degrees + + uint8_t _day; // Day number + uint8_t _month; // Month number + uint16_t _year; + uint8_t _hour; // Hours for 24 hour clock + uint8_t _minute; + uint8_t _second; + uint8_t _leapSeconds; + uint16_t _millisecond; // Limited to first two digits + uint32_t _nanosecond; + + uint8_t _satellitesInView; + uint8_t _fixType; + uint8_t _carrierSolution; + + bool _validDate; // True when date is valid + bool _validTime; // True when time is valid + bool _confirmedDate; + bool _confirmedTime; + bool _fullyResolved; + uint32_t _tAcc; + + unsigned long _pvtArrivalMillis; + bool _pvtUpdated; + + bool _corrRadioExtPortEnabled = false; + + unsigned long _autoBaseStartTimer; // Tracks how long the base auto / averaging mode has been running - // Set RTCM for base mode to defaults (1005/1074/1084/1094/1124 1Hz & 1230 0.1Hz) - virtual void baseRtcmDefault(); + // Setup the general configuration of the GNSS + // Not Rover or Base specific (ie, baud rates) + // Outputs: + // Returns true if successfully configured and false upon failure + virtual bool configureGNSS(); + + public: + // Constructor + GNSS() : _leapSeconds(18), _pvtArrivalMillis(0), _pvtUpdated(0), _satellitesInView(0) + { + } - // Reset to Low Bandwidth Link (1074/1084/1094/1124 0.5Hz & 1005/1230 0.1Hz) - virtual void baseRtcmLowDataRate(); + // If we have decryption keys, configure module + // Note: don't check online.lband_neo here. We could be using ip corrections + virtual void applyPointPerfectKeys(); - // Check if a given baud rate is supported by this module - virtual bool baudIsAllowed(uint32_t baudRate); - virtual uint32_t baudGetMinimum(); - virtual uint32_t baudGetMaximum(); + // Set RTCM for base mode to defaults (1005/1074/1084/1094/1124 1Hz & 1230 0.1Hz) + virtual void baseRtcmDefault(); - // Connect to GNSS and identify particulars - virtual void begin(); + // Reset to Low Bandwidth Link (1074/1084/1094/1124 0.5Hz & 1005/1230 0.1Hz) + virtual void baseRtcmLowDataRate(); - // Setup TM2 time stamp input as need - // Outputs: - // Returns true when an external event occurs and false if no event - virtual bool beginExternalEvent(); + // Check if a given baud rate is supported by this module + virtual bool baudIsAllowed(uint32_t baudRate); + virtual uint32_t baudGetMinimum(); + virtual uint32_t baudGetMaximum(); - // Setup the timepulse output on the PPS pin for external triggering - // Outputs - // Returns true if the pin was successfully setup and false upon - // failure - virtual bool beginPPS(); + // Connect to GNSS and identify particulars + virtual void begin(); - virtual bool checkNMEARates(); + // Setup TM2 time stamp input as need + // Outputs: + // Returns true when an external event occurs and false if no event + virtual bool beginExternalEvent(); - virtual bool checkPPPRates(); + virtual bool checkNMEARates(); - // Setup the general configuration of the GNSS - // Not Rover or Base specific (ie, baud rates) - // Outputs: - // Returns true if successfully configured and false upon failure - bool configure(); + virtual bool checkPPPRates(); - // Configure the Base - // Outputs: - // Returns true if successfully configured and false upon failure - virtual bool configureBase(); + // Setup the general configuration of the GNSS + // Not Rover or Base specific (ie, baud rates) + // Outputs: + // Returns true if successfully configured and false upon failure + bool configure(); - // Configure specific aspects of the receiver for NTP mode - virtual bool configureNtpMode(); + // Configure the Base + // Outputs: + // Returns true if successfully configured and false upon failure + virtual bool configureBase(); - // Configure the Rover - // Outputs: - // Returns true if successfully configured and false upon failure - virtual bool configureRover(); + // Configure specific aspects of the receiver for NTP mode + virtual bool configureNtpMode(); - // Responds with the messages supported on this platform - // Inputs: - // returnText: String to receive message names - // Returns message names in the returnText string - virtual void createMessageList(String &returnText); + // Configure the Rover + // Outputs: + // Returns true if successfully configured and false upon failure + virtual bool configureRover(); - // Responds with the RTCM/Base messages supported on this platform - // Inputs: - // returnText: String to receive message names - // Returns message names in the returnText string - virtual void createMessageListBase(String &returnText); + // Responds with the messages supported on this platform + // Inputs: + // returnText: String to receive message names + // Returns message names in the returnText string + virtual void createMessageList(String &returnText); - virtual void debuggingDisable(); + // Responds with the RTCM/Base messages supported on this platform + // Inputs: + // returnText: String to receive message names + // Returns message names in the returnText string + virtual void createMessageListBase(String &returnText); - virtual void debuggingEnable(); + virtual void debuggingDisable(); - virtual void enableGgaForNtrip(); + virtual void debuggingEnable(); - // Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted - // even if there is no GPS fix. We use it to test serial output. - // Outputs: - // Returns true if successfully started and false upon failure - virtual bool enableRTCMTest(); + virtual void enableGgaForNtrip(); - // Restore the GNSS to the factory settings - virtual void factoryReset(); + // Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted + // even if there is no GPS fix. We use it to test serial output. + // Outputs: + // Returns true if successfully started and false upon failure + virtual bool enableRTCMTest(); - virtual uint16_t fileBufferAvailable(); + // Restore the GNSS to the factory settings + virtual void factoryReset(); - virtual uint16_t fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead); + virtual uint16_t fileBufferAvailable(); - // Start the base using fixed coordinates - // Outputs: - // Returns true if successfully started and false upon failure - virtual bool fixedBaseStart(); + virtual uint16_t fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead); - // Return the number of active/enabled messages - virtual uint8_t getActiveMessageCount(); + // Start the base using fixed coordinates + // Outputs: + // Returns true if successfully started and false upon failure + virtual bool fixedBaseStart(); - // Return the number of active/enabled RTCM messages - virtual uint8_t getActiveRtcmMessageCount(); + // Return the number of active/enabled messages + virtual uint8_t getActiveMessageCount(); - // Get the altitude - // Outputs: - // Returns the altitude in meters or zero if the GNSS is offline - virtual double getAltitude(); + // Return the number of active/enabled RTCM messages + virtual uint8_t getActiveRtcmMessageCount(); - // Returns the carrier solution or zero if not online - virtual uint8_t getCarrierSolution(); + // Get the altitude + // Outputs: + // Returns the altitude in meters or zero if the GNSS is offline + virtual double getAltitude(); - virtual uint32_t getDataBaudRate(); + // Returns the carrier solution or zero if not online + virtual uint8_t getCarrierSolution(); - // Returns the day number or zero if not online - virtual uint8_t getDay(); + virtual uint32_t getDataBaudRate(); - // Return the number of milliseconds since GNSS data was last updated - virtual uint16_t getFixAgeMilliseconds(); + // Returns the day number or zero if not online + virtual uint8_t getDay(); - // Returns the fix type or zero if not online - virtual uint8_t getFixType(); + // Return the number of milliseconds since GNSS data was last updated + virtual uint16_t getFixAgeMilliseconds(); - // Returns the hours of 24 hour clock or zero if not online - virtual uint8_t getHour(); + // Returns the fix type or zero if not online + virtual uint8_t getFixType(); - // Get the horizontal position accuracy - // Outputs: - // Returns the horizontal position accuracy or zero if offline - virtual float getHorizontalAccuracy(); + // Returns the hours of 24 hour clock or zero if not online + virtual uint8_t getHour(); - virtual const char *getId(); + // Get the horizontal position accuracy + // Outputs: + // Returns the horizontal position accuracy or zero if offline + virtual float getHorizontalAccuracy(); - // Get the latitude value - // Outputs: - // Returns the latitude value or zero if not online - virtual double getLatitude(); + virtual const char *getId(); - // Query GNSS for current leap seconds - virtual uint8_t getLeapSeconds(); + // Get the latitude value + // Outputs: + // Returns the latitude value or zero if not online + virtual double getLatitude(); - // Return the type of logging that matches the enabled messages - drives the logging icon - virtual uint8_t getLoggingType(); + // Query GNSS for current leap seconds + virtual uint8_t getLeapSeconds(); - // Get the longitude value - // Outputs: - // Returns the longitude value or zero if not online - virtual double getLongitude(); + // Return the type of logging that matches the enabled messages - drives the logging icon + virtual uint8_t getLoggingType(); - // Returns two digits of milliseconds or zero if not online - virtual uint8_t getMillisecond(); + // Get the longitude value + // Outputs: + // Returns the longitude value or zero if not online + virtual double getLongitude(); - // Get the minimum satellite signal level for navigation. - uint8_t getMinCno(); + // Returns two digits of milliseconds or zero if not online + virtual uint8_t getMillisecond(); - // Returns minutes or zero if not online - virtual uint8_t getMinute(); + // Get the minimum satellite signal level for navigation. + uint8_t getMinCno(); - // Returns month number or zero if not online - virtual uint8_t getMonth(); + // Returns minutes or zero if not online + virtual uint8_t getMinute(); - // Returns nanoseconds or zero if not online - virtual uint32_t getNanosecond(); + // Returns month number or zero if not online + virtual uint8_t getMonth(); - virtual uint32_t getRadioBaudRate(); + // Returns nanoseconds or zero if not online + virtual uint32_t getNanosecond(); - // Returns the seconds between solutions - virtual double getRateS(); + virtual uint32_t getRadioBaudRate(); - virtual const char *getRtcmDefaultString(); + // Returns the seconds between solutions + virtual double getRateS(); - virtual const char *getRtcmLowDataRateString(); + virtual const char *getRtcmDefaultString(); - // Returns the number of satellites in view or zero if offline - virtual uint8_t getSatellitesInView(); + virtual const char *getRtcmLowDataRateString(); - // Returns seconds or zero if not online - virtual uint8_t getSecond(); + // Returns the number of satellites in view or zero if offline + virtual uint8_t getSatellitesInView(); - // Get the survey-in mean accuracy - // Outputs: - // Returns the mean accuracy or zero (0) - virtual float getSurveyInMeanAccuracy(); + // Returns seconds or zero if not online + virtual uint8_t getSecond(); - // Return the number of seconds the survey-in process has been running - virtual int getSurveyInObservationTime(); + // Get the survey-in mean accuracy + // Outputs: + // Returns the mean accuracy or zero (0) + virtual float getSurveyInMeanAccuracy(); - float getSurveyInStartingAccuracy(); + // Return the number of seconds the survey-in process has been running + virtual int getSurveyInObservationTime(); - // Returns timing accuracy or zero if not online - virtual uint32_t getTimeAccuracy(); + float getSurveyInStartingAccuracy(); - // Returns full year, ie 2023, not 23. - virtual uint16_t getYear(); + // Returns timing accuracy or zero if not online + virtual uint32_t getTimeAccuracy(); - // Antenna Short / Open detection - virtual bool isAntennaShorted(); - virtual bool isAntennaOpen(); + // Returns full year, ie 2023, not 23. + virtual uint16_t getYear(); - virtual bool isBlocking(); + // Antenna Short / Open detection + virtual bool isAntennaShorted(); + virtual bool isAntennaOpen(); - // Date is confirmed once we have GNSS fix - virtual bool isConfirmedDate(); + virtual bool isBlocking(); - // Date is confirmed once we have GNSS fix - virtual bool isConfirmedTime(); + // Date is confirmed once we have GNSS fix + virtual bool isConfirmedDate(); - // Returns true if data is arriving on the Radio Ext port - virtual bool isCorrRadioExtPortActive(); + // Date is confirmed once we have GNSS fix + virtual bool isConfirmedTime(); - // Return true if GNSS receiver has a higher quality DGPS fix than 3D - virtual bool isDgpsFixed(); + // Returns true if data is arriving on the Radio Ext port + virtual bool isCorrRadioExtPortActive(); - // Some functions (L-Band area frequency determination) merely need - // to know if we have a valid fix, not what type of fix - // This function checks to see if the given platform has reached - // sufficient fix type to be considered valid - virtual bool isFixed(); + // Return true if GNSS receiver has a higher quality DGPS fix than 3D + virtual bool isDgpsFixed(); - // Used in tpISR() for time pulse synchronization - virtual bool isFullyResolved(); + // Some functions (L-Band area frequency determination) merely need + // to know if we have a valid fix, not what type of fix + // This function checks to see if the given platform has reached + // sufficient fix type to be considered valid + virtual bool isFixed(); - virtual bool isPppConverged(); + // Used in tpISR() for time pulse synchronization + virtual bool isFullyResolved(); - virtual bool isPppConverging(); + virtual bool isPppConverged(); - // Some functions (L-Band area frequency determination) merely need - // to know if we have an RTK Fix. This function checks to see if the - // given platform has reached sufficient fix type to be considered valid - virtual bool isRTKFix(); + virtual bool isPppConverging(); - // Some functions (L-Band area frequency determination) merely need - // to know if we have an RTK Float. This function checks to see if - // the given platform has reached sufficient fix type to be considered - // valid - virtual bool isRTKFloat(); + // Some functions (L-Band area frequency determination) merely need + // to know if we have an RTK Fix. This function checks to see if the + // given platform has reached sufficient fix type to be considered valid + virtual bool isRTKFix(); - // Determine if the survey-in operation is complete - // Outputs: - // Returns true if the survey-in operation is complete and false - // if the operation is still running - virtual bool isSurveyInComplete(); + // Some functions (L-Band area frequency determination) merely need + // to know if we have an RTK Float. This function checks to see if + // the given platform has reached sufficient fix type to be considered + // valid + virtual bool isRTKFloat(); - // Date will be valid if the RTC is reporting (regardless of GNSS fix) - virtual bool isValidDate(); + // Determine if the survey-in operation is complete + // Outputs: + // Returns true if the survey-in operation is complete and false + // if the operation is still running + virtual bool isSurveyInComplete(); - // Time will be valid if the RTC is reporting (regardless of GNSS fix) - virtual bool isValidTime(); + // Date will be valid if the RTC is reporting (regardless of GNSS fix) + virtual bool isValidDate(); - // Controls the constellations that are used to generate a fix and logged - virtual void menuConstellations(); + // Time will be valid if the RTC is reporting (regardless of GNSS fix) + virtual bool isValidTime(); - virtual void menuMessageBaseRtcm(); + // Controls the constellations that are used to generate a fix and logged + virtual void menuConstellations(); - // Control the messages that get broadcast over Bluetooth and logged (if enabled) - virtual void menuMessages(); + virtual void menuMessageBaseRtcm(); - // Print the module type and firmware version - virtual void printModuleInfo(); + // Control the messages that get broadcast over Bluetooth and logged (if enabled) + virtual void menuMessages(); - // Send correction data to the GNSS - // Inputs: - // dataToSend: Address of a buffer containing the data - // dataLength: The number of valid data bytes in the buffer - // Outputs: - // Returns the number of correction data bytes written - virtual int pushRawData(uint8_t *dataToSend, int dataLength); + // Print the module type and firmware version + virtual void printModuleInfo(); - virtual uint16_t rtcmBufferAvailable(); + // Send correction data to the GNSS + // Inputs: + // dataToSend: Address of a buffer containing the data + // dataLength: The number of valid data bytes in the buffer + // Outputs: + // Returns the number of correction data bytes written + virtual int pushRawData(uint8_t *dataToSend, int dataLength); - // If LBand is being used, ignore any RTCM that may come in from the GNSS - virtual void rtcmOnGnssDisable(); + virtual uint16_t rtcmBufferAvailable(); - // If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver - virtual void rtcmOnGnssEnable(); + // If LBand is being used, ignore any RTCM that may come in from the GNSS + virtual void rtcmOnGnssDisable(); - virtual uint16_t rtcmRead(uint8_t *rtcmBuffer, int rtcmBytesToRead); + // If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver + virtual void rtcmOnGnssEnable(); - // Save the current configuration - // Outputs: - // Returns true when the configuration was saved and false upon failure - virtual bool saveConfiguration(); + virtual uint16_t rtcmRead(uint8_t *rtcmBuffer, int rtcmBytesToRead); - // Enable all the valid constellations and bands for this platform - virtual bool setConstellations(); + // Save the current configuration + // Outputs: + // Returns true when the configuration was saved and false upon failure + virtual bool saveConfiguration(); - // Enable / disable corrections protocol(s) on the Radio External port - // Always update if force is true. Otherwise, only update if enable has changed state - virtual bool setCorrRadioExtPort(bool enable, bool force); + // Enable all the valid constellations and bands for this platform + virtual bool setConstellations(); - virtual bool setBaudRate(uint8_t uartNumber, uint32_t baudRate); + // Enable / disable corrections protocol(s) on the Radio External port + // Always update if force is true. Otherwise, only update if enable has changed state + virtual bool setCorrRadioExtPort(bool enable, bool force); - virtual bool setBaudRateComm(uint32_t baud); + virtual bool setBaudRate(uint8_t uartNumber, uint32_t baudRate); - virtual bool setBaudRateData(uint32_t baud); + virtual bool setBaudRateComm(uint32_t baud); - virtual bool setBaudRateRadio(uint32_t baud); + virtual bool setBaudRateData(uint32_t baud); - // Set the elevation in degrees - // Inputs: - // elevationDegrees: The elevation value in degrees - virtual bool setElevation(uint8_t elevationDegrees); + virtual bool setBaudRateRadio(uint32_t baud); - virtual bool setHighAccuracyService(bool enableGalileoHas); + // Set the elevation in degrees + // Inputs: + // elevationDegrees: The elevation value in degrees + virtual bool setElevation(uint8_t elevationDegrees); - virtual bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); + virtual bool setHighAccuracyService(bool enableGalileoHas); - // Enable all the valid messages for this platform - virtual bool setMessages(int maxRetries); + virtual bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); - // Enable all the valid messages for this platform over the USB port - virtual bool setMessagesUsb(int maxRetries); + // Enable all the valid messages for this platform + virtual bool setMessages(int maxRetries); - // Set the minimum satellite signal level for navigation. - virtual bool setMinCno(uint8_t cnoValue); + // Enable all the valid messages for this platform over the USB port + virtual bool setMessagesUsb(int maxRetries); - // Set the dynamic model to use for RTK - // Inputs: - // modelNumber: Number of the model to use, provided by radio library - virtual bool setModel(uint8_t modelNumber); + // Set the minimum satellite signal level for navigation. + virtual bool setMinCno(uint8_t cnoValue); - // Specify the interval between solutions - // Inputs: - // secondsBetweenSolutions: Number of seconds between solutions - // Outputs: - // Returns true if the rate was successfully set and false upon - // failure - virtual bool setRate(double secondsBetweenSolutions); + // Set the dynamic model to use for RTK + // Inputs: + // modelNumber: Number of the model to use, provided by radio library + virtual bool setModel(uint8_t modelNumber); - virtual bool setTalkerGNGGA(); + // Configure the Pulse-per-second pin based on user settings + virtual bool setPPS(); - // Hotstart GNSS to try to get RTK lock - virtual bool softwareReset(); + // Specify the interval between solutions + // Inputs: + // secondsBetweenSolutions: Number of seconds between solutions + // Outputs: + // Returns true if the rate was successfully set and false upon + // failure + virtual bool setRate(double secondsBetweenSolutions); - virtual bool standby(); + virtual bool setTalkerGNGGA(); - // Antenna Short / Open detection - virtual bool supportsAntennaShortOpen(); + // Hotstart GNSS to try to get RTK lock + virtual bool softwareReset(); - // Reset the survey-in operation - // Outputs: - // Returns true if the survey-in operation was reset successfully - // and false upon failure - virtual bool surveyInReset(); + virtual bool standby(); - // Start the survey-in operation - // Outputs: - // Return true if successful and false upon failure - virtual bool surveyInStart(); + // Antenna Short / Open detection + virtual bool supportsAntennaShortOpen(); - // Poll routine to update the GNSS state - virtual void update(); + // Reset the survey-in operation + // Outputs: + // Returns true if the survey-in operation was reset successfully + // and false upon failure + virtual bool surveyInReset(); + + // Start the survey-in operation + // Outputs: + // Return true if successful and false upon failure + virtual bool surveyInStart(); + + // Poll routine to update the GNSS state + virtual void update(); }; // Update the constellations following a set command diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index e33393d05..3d4c126a3 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -16,6 +16,7 @@ enum GNSS_CONFIG_CONSTELLATION, // Turn on/off a constellation GNSS_CONFIG_ELEVATION, GNSS_CONFIG_CN0, + GNSS_CONFIG_PPS, GNSS_CONFIG_MESSAGE_RATE, // Update all message rates GNSS_CONFIG_MESSAGE_RATE_NMEA, // Update NMEA message rates GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER, // Update RTCM Rover message rates @@ -134,6 +135,12 @@ void gnssUpdate() gnssConfigureClear(GNSS_CONFIG_CN0); } + if (gnssConfigureRequest & GNSS_CONFIG_PPS) + { + if(gnss->setPPS() == true) + gnssConfigureClear(GNSS_CONFIG_PPS); + } + if (gnssConfigureRequest & GNSS_CONFIG_HAS_E6) { if(gnss->setHighAccuracyService(settings.enableGalileoHas) == true) diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.h b/Firmware/RTK_Everywhere/GNSS_LG290P.h index adb42bba1..b956f114d 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.h +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.h @@ -170,11 +170,8 @@ class GNSS_LG290P : GNSS // Returns true when an external event occurs and false if no event bool beginExternalEvent(); - // Setup the timepulse output on the PPS pin for external triggering - // Outputs - // Returns true if the pin was successfully setup and false upon - // failure - bool beginPPS(); + // Setup the PPS pin for PPS LED + bool setPPS(); bool checkNMEARates(); diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index 1c3216c5f..a7acfd4b0 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -158,7 +158,7 @@ bool GNSS_LG290P::beginExternalEvent() //---------------------------------------- // Setup the timepulse output on the PPS pin for external triggering //---------------------------------------- -bool GNSS_LG290P::beginPPS() +bool GNSS_LG290P::setPPS() { // TODO LG290P return (false); diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.h b/Firmware/RTK_Everywhere/GNSS_Mosaic.h index 7ed6f9558..a8cca68da 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.h +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.h @@ -600,12 +600,6 @@ class GNSS_MOSAIC : GNSS // Returns true when an external event occurs and false if no event bool beginExternalEvent(); - // Setup the timepulse output on the PPS pin for external triggering - // Outputs - // Returns true if the pin was successfully setup and false upon - // failure - bool beginPPS(); - bool checkNMEARates(); bool checkPPPRates(); @@ -1015,6 +1009,12 @@ class GNSS_MOSAIC : GNSS // Given the name of a message, find it, and set the rate bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); + // Setup the timepulse output on the PPS pin for external triggering + // Outputs + // Returns true if the pin was successfully setup and false upon + // failure + bool setPPS(); + // Specify the interval between solutions // Inputs: // secondsBetweenSolutions: Number of seconds between solutions diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino index b13a6c0cc..4e2a06fc2 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino @@ -384,7 +384,7 @@ bool GNSS_MOSAIC::beginExternalEvent() // Returns true if the pin was successfully setup and false upon // failure //---------------------------------------- -bool GNSS_MOSAIC::beginPPS() +bool GNSS_MOSAIC::setPPS() { if (online.gnss == false) return (false); diff --git a/Firmware/RTK_Everywhere/GNSS_None.h b/Firmware/RTK_Everywhere/GNSS_None.h index b2248533d..fee65f9bc 100644 --- a/Firmware/RTK_Everywhere/GNSS_None.h +++ b/Firmware/RTK_Everywhere/GNSS_None.h @@ -74,15 +74,6 @@ class GNSS_None : public GNSS return false; } - // Setup the timepulse output on the PPS pin for external triggering - // Outputs - // Returns true if the pin was successfully setup and false upon - // failure - bool beginPPS() - { - return false; - } - bool checkNMEARates() { return false; @@ -601,6 +592,12 @@ class GNSS_None : public GNSS return (true); } + // Configure the Pulse-per-second pin based on user settings + bool setPPS() + { + return false; + } + // Specify the interval between solutions // Inputs: // secondsBetweenSolutions: Number of seconds between solutions diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.h b/Firmware/RTK_Everywhere/GNSS_UM980.h index 4b653281f..321222073 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.h +++ b/Firmware/RTK_Everywhere/GNSS_UM980.h @@ -179,12 +179,6 @@ class GNSS_UM980 : GNSS // Returns true when an external event occurs and false if no event bool beginExternalEvent(); - // Setup the timepulse output on the PPS pin for external triggering - // Outputs - // Returns true if the pin was successfully setup and false upon - // failure - bool beginPPS(); - bool checkNMEARates(); bool checkPPPRates(); @@ -434,7 +428,7 @@ class GNSS_UM980 : GNSS bool setBaudRateComm(uint32_t baudRate); bool setBaudRateData(uint32_t baudRate); - + bool setBaudRateRadio(uint32_t baudRate); // Enable all the valid constellations and bands for this platform @@ -465,6 +459,9 @@ class GNSS_UM980 : GNSS // Given the name of a message, find it, and set the rate bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); + // Configure the Pulse-per-second pin based on user settings + bool setPPS(); + // Set all RTCM Rover message report rates to one value void setRtcmRoverMessageRates(uint8_t msgRate); diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index f2c3455f6..2ef8111e9 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -124,8 +124,6 @@ void GNSS_UM980::begin() } //---------------------------------------- -// Setup the timepulse output on the PPS pin for external triggering -// Setup TM2 time stamp input as need //---------------------------------------- bool GNSS_UM980::beginExternalEvent() { @@ -133,13 +131,16 @@ bool GNSS_UM980::beginExternalEvent() return (false); } -//---------------------------------------- -// Setup the timepulse output on the PPS pin for external triggering -//---------------------------------------- -bool GNSS_UM980::beginPPS() +// Configure the Pulse-per-second pin based on user settings +bool GNSS_UM980::setPPS() { - // UM980 PPS signal not exposed - return (false); + // The PPS signal is not exposed on the Torch so we don't configure the PPS based on internal settings, but we do + // configure the PPS so that the GNSS LED blinks + + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + + // Enable PPS signal with a width of 200ms, and a period of 1 second + return(_um980->enablePPS(settings.externalPulseLength_us, settings.externalPulseTimeBetweenPulse_us / 1000)); // widthMicroseconds, periodMilliseconds } //---------------------------------------- @@ -254,13 +255,9 @@ bool GNSS_UM980::configureOnce() // Assume if we've made it this far, the UM980 UART3 is communicating // response &= setBaudRateComm(115200); // UM980 UART3 is connected to the switch, then ESP32 - // Enable PPS signal with a width of 200ms, and a period of 1 second - response &= _um980->enablePPS(200000, 1000); // widthMicroseconds, periodMilliseconds - gnssConfigure(GNSS_CONFIG_ELEVATION); // Request receiver to use new settings gnssConfigure(GNSS_CONFIG_CN0); - - response &= setMinCno(settings.minCNO); + gnssConfigure(GNSS_CONFIG_PPS); response &= setConstellations(); diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.h b/Firmware/RTK_Everywhere/GNSS_ZED.h index 03f16cb66..d5cb1a0b3 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.h +++ b/Firmware/RTK_Everywhere/GNSS_ZED.h @@ -408,12 +408,6 @@ class GNSS_ZED : GNSS // Returns true when an external event occurs and false if no event bool beginExternalEvent(); - // Setup the timepulse output on the PPS pin for external triggering - // Outputs - // Returns true if the pin was successfully setup and false upon - // failure - bool beginPPS(); - bool checkNMEARates(); bool checkPPPRates(); @@ -681,7 +675,7 @@ class GNSS_ZED : GNSS bool setBaudRateComm(uint32_t baudRate); bool setBaudRateData(uint32_t baudRate); - + bool setBaudRateRadio(uint32_t baudRate); // Enable all the valid constellations and bands for this platform @@ -722,6 +716,12 @@ class GNSS_ZED : GNSS // Given the name of a message, find it, and set the rate bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); + // Setup the timepulse output on the PPS pin for external triggering + // Outputs + // Returns true if the pin was successfully setup and false upon + // failure + bool setPPS(); + // Specify the interval between solutions // Inputs: // secondsBetweenSolutions: Number of seconds between solutions diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index a0817c5ce..f8faf2336 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -262,7 +262,7 @@ bool GNSS_ZED::beginExternalEvent() // This will be called once by setup and possibly multiple times by // menuPortsMultiplexed. //---------------------------------------- -bool GNSS_ZED::beginPPS() +bool GNSS_ZED::setPPS() { if (online.gnss == false) return (false); @@ -295,7 +295,7 @@ bool GNSS_ZED::beginPPS() } if (response == false) - systemPrintln("beginPPS failed"); + systemPrintln("setPPS failed"); return (response); } diff --git a/Firmware/RTK_Everywhere/menuGNSS.ino b/Firmware/RTK_Everywhere/menuGNSS.ino index dfb658315..07366cb1d 100644 --- a/Firmware/RTK_Everywhere/menuGNSS.ino +++ b/Firmware/RTK_Everywhere/menuGNSS.ino @@ -315,7 +315,7 @@ void menuGNSS() // Arbitrary 90 degree max if (getNewSetting("Enter minimum elevation in degrees", 0, 90, &settings.minElev) == INPUT_RESPONSE_VALID) { - gnss->setElevation(settings.minElev); + gnssConfigure(GNSS_CONFIG_ELEVATION); // Request receiver to use new settings } } else if (incoming == 6 && present.minCno) @@ -325,7 +325,7 @@ void menuGNSS() if (getNewSetting("Enter minimum satellite signal level for navigation in dBHz", 0, present.gnss_mosaicX5 ? 60 : 90, &minCNO) == INPUT_RESPONSE_VALID) { - gnss->setMinCno(minCNO); // Set the setting and configure the GNSS receiver + gnssConfigure(GNSS_CONFIG_CN0); // Request receiver to use new settings } } @@ -346,7 +346,7 @@ void menuGNSS() if (getNewSetting("Enter new Caster Port", 1, 99999, &settings.ntripClient_CasterPort) == INPUT_RESPONSE_VALID) { - // No need to restart rover. NTRIP Client state machine will service the change. + // No need to restart rover. NTRIP Client state machine will service the change. } } else if ((incoming == 10) && settings.enableNtripClient == true) @@ -376,7 +376,7 @@ void menuGNSS() else if ((incoming == 14) && settings.enableNtripClient == true) { settings.ntripClient_TransmitGGA ^= 1; - + // We may need to enable the GGA message. Trigger GNSS receiver reconfigure. gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request update } diff --git a/Firmware/RTK_Everywhere/menuPorts.ino b/Firmware/RTK_Everywhere/menuPorts.ino index 4ae265d53..230ab4616 100644 --- a/Firmware/RTK_Everywhere/menuPorts.ino +++ b/Firmware/RTK_Everywhere/menuPorts.ino @@ -320,13 +320,13 @@ void menuPortsMultiplexed() } gnss->beginExternalEvent(); // Update with new settings - gnss->beginPPS(); + gnssConfigure(GNSS_CONFIG_PPS); // Request receiver to use new settings } // Configure the behavior of the PPS and INT pins. // Most often used for logging events (inputs) and when external triggers (outputs) occur. // menuPortHardwareTriggers is only called by menuPortsMultiplexed. -// Call gnss->beginExternalEvent() and gnss->beginPPS() in menuPortsMultiplexed, not here +// Call gnss->beginExternalEvent() and gnss->setPPS() in menuPortsMultiplexed, not here // since menuPortsMultiplexed has control of the multiplexer void menuPortHardwareTriggers() { diff --git a/Firmware/RTK_Everywhere/settings.h b/Firmware/RTK_Everywhere/settings.h index 477fb1149..6acdccb5e 100644 --- a/Firmware/RTK_Everywhere/settings.h +++ b/Firmware/RTK_Everywhere/settings.h @@ -932,7 +932,7 @@ struct Settings // Pulse bool enableExternalPulse = true; // Send pulse once lock is achieved - uint64_t externalPulseLength_us = 100000; // us length of pulse, max of 60s = 60 * 1000 * 1000 + uint64_t externalPulseLength_us = 200000; // us length of pulse, max of 60s = 60 * 1000 * 1000 pulseEdgeType_e externalPulsePolarity = PULSE_RISING_EDGE; // Pulse rises for pulse length, then falls uint64_t externalPulseTimeBetweenPulse_us = 1000000; // us between pulses, max of 60s = 60 * 1000 * 1000 From e3b33f7dd28e90f8371aab57c2cb3f2e4160ec28 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Fri, 10 Oct 2025 13:37:17 -0600 Subject: [PATCH 18/68] Add setMultipathMitigation too all platforms --- Firmware/RTK_Everywhere/GNSS.h | 2 + Firmware/RTK_Everywhere/GNSS.ino | 49 +- Firmware/RTK_Everywhere/GNSS_LG290P.h | 605 ++++++++++++------------ Firmware/RTK_Everywhere/GNSS_LG290P.ino | 11 +- Firmware/RTK_Everywhere/GNSS_Mosaic.h | 6 +- Firmware/RTK_Everywhere/GNSS_Mosaic.ino | 9 + Firmware/RTK_Everywhere/GNSS_None.h | 7 +- Firmware/RTK_Everywhere/GNSS_UM980.h | 4 +- Firmware/RTK_Everywhere/GNSS_UM980.ino | 32 +- Firmware/RTK_Everywhere/GNSS_ZED.h | 2 + Firmware/RTK_Everywhere/GNSS_ZED.ino | 9 + 11 files changed, 399 insertions(+), 337 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.h b/Firmware/RTK_Everywhere/GNSS.h index c9374bb0a..ead6249c1 100644 --- a/Firmware/RTK_Everywhere/GNSS.h +++ b/Firmware/RTK_Everywhere/GNSS.h @@ -360,6 +360,8 @@ class GNSS // modelNumber: Number of the model to use, provided by radio library virtual bool setModel(uint8_t modelNumber); + virtual bool setMultipathMitigation(bool enableMultipathMitigation); + // Configure the Pulse-per-second pin based on user settings virtual bool setPPS(); diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index 3d4c126a3..3e167dfe2 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -17,6 +17,7 @@ enum GNSS_CONFIG_ELEVATION, GNSS_CONFIG_CN0, GNSS_CONFIG_PPS, + GNSS_CONFIG_MODEL, GNSS_CONFIG_MESSAGE_RATE, // Update all message rates GNSS_CONFIG_MESSAGE_RATE_NMEA, // Update NMEA message rates GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER, // Update RTCM Rover message rates @@ -121,30 +122,65 @@ void gnssUpdate() if (gnssConfigureRequest & GNSS_CONFIG_CONSTELLATION) { + if (gnss->setConstellations() == true) + { + gnssConfigureClear(GNSS_CONFIG_CONSTELLATION); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } } if (gnssConfigureRequest & GNSS_CONFIG_ELEVATION) { - if(gnss->setElevation(settings.minElev) == true) + if (gnss->setElevation(settings.minElev) == true) + { gnssConfigureClear(GNSS_CONFIG_ELEVATION); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } } if (gnssConfigureRequest & GNSS_CONFIG_CN0) { - if(gnss->setMinCno(settings.minCNO) == true) + if (gnss->setMinCno(settings.minCNO) == true) + { gnssConfigureClear(GNSS_CONFIG_CN0); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } } if (gnssConfigureRequest & GNSS_CONFIG_PPS) { - if(gnss->setPPS() == true) + if (gnss->setPPS() == true) + { gnssConfigureClear(GNSS_CONFIG_PPS); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } + } + + if (gnssConfigureRequest & GNSS_CONFIG_MODEL) + { + if (gnss->setModel(settings.dynamicModel) == true) + { + gnssConfigureClear(GNSS_CONFIG_MODEL); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } } if (gnssConfigureRequest & GNSS_CONFIG_HAS_E6) { - if(gnss->setHighAccuracyService(settings.enableGalileoHas) == true) + if (gnss->setHighAccuracyService(settings.enableGalileoHas) == true) + { gnssConfigureClear(GNSS_CONFIG_HAS_E6); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } + } + + if (gnssConfigureRequest & GNSS_CONFIG_MULTIPATH) + { + if (gnss->setMultipathMitigation(settings.enableMultipathMitigation) == true) + { + gnssConfigureClear(GNSS_CONFIG_MULTIPATH); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } } // Platforms will set the GNSS_CONFIG_SAVE and GNSS_CONFIG_RESET bits appropriately for each command issued @@ -152,7 +188,7 @@ void gnssUpdate() // If one of the previous configuration changes requested save to NVM, do so if (gnssConfigureRequest & GNSS_CONFIG_SAVE) { - if(gnss->saveConfiguration()) + if (gnss->saveConfiguration()) gnssConfigureClear(GNSS_CONFIG_SAVE); } @@ -181,6 +217,9 @@ void gnssUpdate() { systemPrintln("gnssUpdate: Uncaught mode change"); } + + // We do not clear the request bits here. Instead, if bits are still set, the next update will attempt to + // service them. } } diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.h b/Firmware/RTK_Everywhere/GNSS_LG290P.h index b956f114d..17659dff0 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.h +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.h @@ -14,12 +14,7 @@ GNSS_LG290P.h // Constellations monitored/used for fix // Available constellations: GPS, BDS, GLO, GAL, QZSS, NavIC const char *lg290pConstellationNames[] = { - "GPS", - "GLONASS", - "Galileo", - "BeiDou", - "QZSS", - "NavIC", + "GPS", "GLONASS", "Galileo", "BeiDou", "QZSS", "NavIC", }; #define MAX_LG290P_CONSTELLATIONS (6) @@ -28,31 +23,22 @@ const char *lg290pConstellationNames[] = { // Each message will have the serial command and its default value typedef struct { - const char msgTextName[11]; - const float msgDefaultRate; - const uint8_t firmwareVersionSupported; // The minimum version this message is supported. - // 0 = all versions. - // 9999 = Not supported + const char msgTextName[11]; + const float msgDefaultRate; + const uint8_t firmwareVersionSupported; // The minimum version this message is supported. + // 0 = all versions. + // 9999 = Not supported } lg290pMsg; // Static array containing all the compatible messages // Rate = Output once every N position fix(es). const lg290pMsg lgMessagesNMEA[] = { - {"RMC", 1, 0}, - {"GGA", 1, 0}, - {"GSV", 1, 0}, - {"GSA", 1, 0}, - {"VTG", 1, 0}, - {"GLL", 1, 0}, - {"GBS", 0, 4}, - {"GNS", 0, 4}, - {"GST", 1, 4}, - {"ZDA", 0, 4}, + {"RMC", 1, 0}, {"GGA", 1, 0}, {"GSV", 1, 0}, {"GSA", 1, 0}, {"VTG", 1, 0}, + {"GLL", 1, 0}, {"GBS", 0, 4}, {"GNS", 0, 4}, {"GST", 1, 4}, {"ZDA", 0, 4}, }; const lg290pMsg lgMessagesRTCM[] = { - {"RTCM3-1005", 1, 0}, - {"RTCM3-1006", 0, 0}, + {"RTCM3-1005", 1, 0}, {"RTCM3-1006", 0, 0}, {"RTCM3-1019", 0, 0}, @@ -60,17 +46,10 @@ const lg290pMsg lgMessagesRTCM[] = { {"RTCM3-1033", 0, 4}, // v4 and above - {"RTCM3-1041", 0, 0}, - {"RTCM3-1042", 0, 0}, - {"RTCM3-1044", 0, 0}, - {"RTCM3-1046", 0, 0}, - - {"RTCM3-107X", 1, 0}, - {"RTCM3-108X", 1, 0}, - {"RTCM3-109X", 1, 0}, - {"RTCM3-111X", 1, 0}, - {"RTCM3-112X", 1, 0}, - {"RTCM3-113X", 1, 0}, + {"RTCM3-1041", 0, 0}, {"RTCM3-1042", 0, 0}, {"RTCM3-1044", 0, 0}, {"RTCM3-1046", 0, 0}, + + {"RTCM3-107X", 1, 0}, {"RTCM3-108X", 1, 0}, {"RTCM3-109X", 1, 0}, {"RTCM3-111X", 1, 0}, + {"RTCM3-112X", 1, 0}, {"RTCM3-113X", 1, 0}, }; // Quectel Proprietary messages @@ -85,61 +64,61 @@ const lg290pMsg lgMessagesPQTM[] = { enum lg290p_Models { - // LG290P does not have models - LG290P_DYN_MODEL_SURVEY = 0, - LG290P_DYN_MODEL_UAV, - LG290P_DYN_MODEL_AUTOMOTIVE, + // LG290P does not have models + LG290P_DYN_MODEL_SURVEY = 0, + LG290P_DYN_MODEL_UAV, + LG290P_DYN_MODEL_AUTOMOTIVE, }; class GNSS_LG290P : GNSS { -private: - LG290P *_lg290p; // Library class instance + private: + LG290P *_lg290p; // Library class instance -protected: - bool configureOnce(); + protected: + bool configureOnce(); - // Setup the general configuration of the GNSS - // Not Rover or Base specific (ie, baud rates) - // Outputs: - // Returns true if successfully configured and false upon failure - bool configureGNSS(); + // Setup the general configuration of the GNSS + // Not Rover or Base specific (ie, baud rates) + // Outputs: + // Returns true if successfully configured and false upon failure + bool configureGNSS(); - // Turn on all the enabled NMEA messages on COM3 - bool enableNMEA(); + // Turn on all the enabled NMEA messages on COM3 + bool enableNMEA(); - // Turn on all the enabled RTCM Rover messages on COM3 - bool enableRTCMRover(); + // Turn on all the enabled RTCM Rover messages on COM3 + bool enableRTCMRover(); - // Turn on all the enabled RTCM Base messages on COM3 - bool enableRTCMBase(); + // Turn on all the enabled RTCM Base messages on COM3 + bool enableRTCMBase(); - uint8_t getActiveNmeaMessageCount(); + uint8_t getActiveNmeaMessageCount(); - // Given the name of an NMEA message, return the array number - uint8_t getNmeaMessageNumberByName(const char *msgName); + // Given the name of an NMEA message, return the array number + uint8_t getNmeaMessageNumberByName(const char *msgName); - // Given the name of an RTCM message, return the array number - uint8_t getRtcmMessageNumberByName(const char *msgName); + // Given the name of an RTCM message, return the array number + uint8_t getRtcmMessageNumberByName(const char *msgName); - // Return true if the GPGGA message is active - bool isGgaActive(); + // Return true if the GPGGA message is active + bool isGgaActive(); - // Given a sub type (ie "RTCM", "NMEA") present menu showing messages with this subtype - // Controls the messages that get broadcast over Bluetooth and logged (if enabled) - void menuMessagesSubtype(int *localMessageRate, const char *messageType); + // Given a sub type (ie "RTCM", "NMEA") present menu showing messages with this subtype + // Controls the messages that get broadcast over Bluetooth and logged (if enabled) + void menuMessagesSubtype(int *localMessageRate, const char *messageType); - // Set the minimum satellite signal level for navigation. - bool setMinCno(uint8_t cnoValue); + // Set the minimum satellite signal level for navigation. + bool setMinCno(uint8_t cnoValue); - // Given the name of a message, find it, and set the rate - bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); + // Given the name of a message, find it, and set the rate + bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); - // Set all RTCM Rover message report rates to one value - void setRtcmRoverMessageRates(uint8_t msgRate); + // Set all RTCM Rover message report rates to one value + void setRtcmRoverMessageRates(uint8_t msgRate); - // Given the name of a message, find it, and set the rate - bool setRtcmRoverMessageRateByName(const char *msgName, uint8_t msgRate); + // Given the name of a message, find it, and set the rate + bool setRtcmRoverMessageRateByName(const char *msgName, uint8_t msgRate); public: // Constructor @@ -147,350 +126,352 @@ class GNSS_LG290P : GNSS { } - // If we have decryption keys, configure module - // Note: don't check online.lband_neo here. We could be using ip corrections - void applyPointPerfectKeys(); + // If we have decryption keys, configure module + // Note: don't check online.lband_neo here. We could be using ip corrections + void applyPointPerfectKeys(); + + // Set RTCM for base mode to defaults (1005/1074/1084/1094/1124 1Hz & 1230 0.1Hz) + void baseRtcmDefault(); - // Set RTCM for base mode to defaults (1005/1074/1084/1094/1124 1Hz & 1230 0.1Hz) - void baseRtcmDefault(); + // Reset to Low Bandwidth Link (1074/1084/1094/1124 0.5Hz & 1005/1230 0.1Hz) + void baseRtcmLowDataRate(); - // Reset to Low Bandwidth Link (1074/1084/1094/1124 0.5Hz & 1005/1230 0.1Hz) - void baseRtcmLowDataRate(); + // Check if a given baud rate is supported by this module + bool baudIsAllowed(uint32_t baudRate); + uint32_t baudGetMinimum(); + uint32_t baudGetMaximum(); - // Check if a given baud rate is supported by this module - bool baudIsAllowed(uint32_t baudRate); - uint32_t baudGetMinimum(); - uint32_t baudGetMaximum(); + // Connect to GNSS and identify particulars + void begin(); - // Connect to GNSS and identify particulars - void begin(); + // Setup TM2 time stamp input as need + // Outputs: + // Returns true when an external event occurs and false if no event + bool beginExternalEvent(); - // Setup TM2 time stamp input as need - // Outputs: - // Returns true when an external event occurs and false if no event - bool beginExternalEvent(); + // Setup the PPS pin for PPS LED + bool setPPS(); - // Setup the PPS pin for PPS LED - bool setPPS(); + bool checkNMEARates(); - bool checkNMEARates(); + bool checkPPPRates(); - bool checkPPPRates(); + // Configure the Base + // Outputs: + // Returns true if successfully configured and false upon failure + bool configureBase(); - // Configure the Base - // Outputs: - // Returns true if successfully configured and false upon failure - bool configureBase(); + // Configure specific aspects of the receiver for NTP mode + bool configureNtpMode(); - // Configure specific aspects of the receiver for NTP mode - bool configureNtpMode(); + // Configure the Rover + // Outputs: + // Returns true if successfully configured and false upon failure + bool configureRover(); - // Configure the Rover - // Outputs: - // Returns true if successfully configured and false upon failure - bool configureRover(); + // Responds with the messages supported on this platform + // Inputs: + // returnText: String to receive message names + // Returns message names in the returnText string + void createMessageList(String &returnText); - // Responds with the messages supported on this platform - // Inputs: - // returnText: String to receive message names - // Returns message names in the returnText string - void createMessageList(String &returnText); + // Responds with the RTCM/Base messages supported on this platform + // Inputs: + // returnText: String to receive message names + // Returns message names in the returnText string + void createMessageListBase(String &returnText); - // Responds with the RTCM/Base messages supported on this platform - // Inputs: - // returnText: String to receive message names - // Returns message names in the returnText string - void createMessageListBase(String &returnText); + void debuggingDisable(); - void debuggingDisable(); + void debuggingEnable(); - void debuggingEnable(); + bool disableSurveyIn(bool saveAndReset); - bool disableSurveyIn(bool saveAndReset); + void enableGgaForNtrip(); - void enableGgaForNtrip(); + // Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted + // even if there is no GPS fix. We use it to test serial output. + // Outputs: + // Returns true if successfully started and false upon failure + bool enableRTCMTest(); - // Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted - // even if there is no GPS fix. We use it to test serial output. - // Outputs: - // Returns true if successfully started and false upon failure - bool enableRTCMTest(); + bool enterConfigMode(unsigned long waitForSemaphoreTimeout_millis); - bool enterConfigMode(unsigned long waitForSemaphoreTimeout_millis); + bool exitConfigMode(); - bool exitConfigMode(); + // Restore the GNSS to the factory settings + void factoryReset(); - // Restore the GNSS to the factory settings - void factoryReset(); + uint16_t fileBufferAvailable(); - uint16_t fileBufferAvailable(); + uint16_t fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead); - uint16_t fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead); + // Start the base using fixed coordinates + // Outputs: + // Returns true if successfully started and false upon failure + bool fixedBaseStart(); - // Start the base using fixed coordinates - // Outputs: - // Returns true if successfully started and false upon failure - bool fixedBaseStart(); + // Return the number of active/enabled messages + uint8_t getActiveMessageCount(); - // Return the number of active/enabled messages - uint8_t getActiveMessageCount(); + // Return the number of active/enabled RTCM messages + uint8_t getActiveRtcmMessageCount(); - // Return the number of active/enabled RTCM messages - uint8_t getActiveRtcmMessageCount(); + // Get the altitude + // Outputs: + // Returns the altitude in meters or zero if the GNSS is offline + double getAltitude(); - // Get the altitude - // Outputs: - // Returns the altitude in meters or zero if the GNSS is offline - double getAltitude(); + uint32_t getBaudRate(uint8_t uartNumber); - uint32_t getBaudRate(uint8_t uartNumber); + // Returns the carrier solution or zero if not online + uint8_t getCarrierSolution(); - // Returns the carrier solution or zero if not online - uint8_t getCarrierSolution(); + uint32_t getCommBaudRate(); - uint32_t getCommBaudRate(); + uint32_t getDataBaudRate(); - uint32_t getDataBaudRate(); + // Returns the day number or zero if not online + uint8_t getDay(); - // Returns the day number or zero if not online - uint8_t getDay(); + // Return the number of milliseconds since GNSS data was last updated + uint16_t getFixAgeMilliseconds(); - // Return the number of milliseconds since GNSS data was last updated - uint16_t getFixAgeMilliseconds(); + // Returns the fix type or zero if not online + uint8_t getFixType(); - // Returns the fix type or zero if not online - uint8_t getFixType(); + // Returns the hours of 24 hour clock or zero if not online + uint8_t getHour(); - // Returns the hours of 24 hour clock or zero if not online - uint8_t getHour(); + // Get the horizontal position accuracy + // Outputs: + // Returns the horizontal position accuracy or zero if offline + float getHorizontalAccuracy(); - // Get the horizontal position accuracy - // Outputs: - // Returns the horizontal position accuracy or zero if offline - float getHorizontalAccuracy(); + const char *getId(); - const char *getId(); + // Get the latitude value + // Outputs: + // Returns the latitude value or zero if not online + double getLatitude(); - // Get the latitude value - // Outputs: - // Returns the latitude value or zero if not online - double getLatitude(); + // Query GNSS for current leap seconds + uint8_t getLeapSeconds(); - // Query GNSS for current leap seconds - uint8_t getLeapSeconds(); + // Return the type of logging that matches the enabled messages - drives the logging icon + uint8_t getLoggingType(); - // Return the type of logging that matches the enabled messages - drives the logging icon - uint8_t getLoggingType(); + // Get the longitude value + // Outputs: + // Returns the longitude value or zero if not online + double getLongitude(); - // Get the longitude value - // Outputs: - // Returns the longitude value or zero if not online - double getLongitude(); + // Returns two digits of milliseconds or zero if not online + uint8_t getMillisecond(); - // Returns two digits of milliseconds or zero if not online - uint8_t getMillisecond(); + // Get the minimum satellite signal level for navigation. + uint8_t getMinCno(); - // Get the minimum satellite signal level for navigation. - uint8_t getMinCno(); + // Returns minutes or zero if not online + uint8_t getMinute(); - // Returns minutes or zero if not online - uint8_t getMinute(); + // Returns 0 - Unknown, 1 - Rover, 2 - Base + uint8_t getMode(); - // Returns 0 - Unknown, 1 - Rover, 2 - Base - uint8_t getMode(); + // Returns month number or zero if not online + uint8_t getMonth(); - // Returns month number or zero if not online - uint8_t getMonth(); + // Returns nanoseconds or zero if not online + uint32_t getNanosecond(); - // Returns nanoseconds or zero if not online - uint32_t getNanosecond(); + uint32_t getRadioBaudRate(); - uint32_t getRadioBaudRate(); + // Returns the seconds between solutions + double getRateS(); - // Returns the seconds between solutions - double getRateS(); + const char *getRtcmDefaultString(); - const char *getRtcmDefaultString(); + const char *getRtcmLowDataRateString(); - const char *getRtcmLowDataRateString(); + // Returns the number of satellites in view or zero if offline + uint8_t getSatellitesInView(); - // Returns the number of satellites in view or zero if offline - uint8_t getSatellitesInView(); + // Returns seconds or zero if not online + uint8_t getSecond(); - // Returns seconds or zero if not online - uint8_t getSecond(); + // Get the survey-in mean accuracy + // Outputs: + // Returns the mean accuracy or zero (0) + float getSurveyInMeanAccuracy(); - // Get the survey-in mean accuracy - // Outputs: - // Returns the mean accuracy or zero (0) - float getSurveyInMeanAccuracy(); + uint8_t getSurveyInMode(); - uint8_t getSurveyInMode(); + // Return the number of seconds the survey-in process has been running + int getSurveyInObservationTime(); - // Return the number of seconds the survey-in process has been running - int getSurveyInObservationTime(); + float getSurveyInStartingAccuracy(); - float getSurveyInStartingAccuracy(); + // Returns timing accuracy or zero if not online + uint32_t getTimeAccuracy(); - // Returns timing accuracy or zero if not online - uint32_t getTimeAccuracy(); + // Returns full year, ie 2023, not 23. + uint16_t getYear(); - // Returns full year, ie 2023, not 23. - uint16_t getYear(); + // Returns true if the device is in Rover mode + // Currently the only two modes are Rover or Base + bool inRoverMode(); - // Returns true if the device is in Rover mode - // Currently the only two modes are Rover or Base - bool inRoverMode(); + bool isBlocking(); - bool isBlocking(); + // Date is confirmed once we have GNSS fix + bool isConfirmedDate(); - // Date is confirmed once we have GNSS fix - bool isConfirmedDate(); + // Date is confirmed once we have GNSS fix + bool isConfirmedTime(); - // Date is confirmed once we have GNSS fix - bool isConfirmedTime(); + // Returns true if data is arriving on the Radio Ext port + bool isCorrRadioExtPortActive(); - // Returns true if data is arriving on the Radio Ext port - bool isCorrRadioExtPortActive(); + // Return true if GNSS receiver has a higher quality DGPS fix than 3D + bool isDgpsFixed(); - // Return true if GNSS receiver has a higher quality DGPS fix than 3D - bool isDgpsFixed(); + // Some functions (L-Band area frequency determination) merely need + // to know if we have a valid fix, not what type of fix + // This function checks to see if the given platform has reached + // sufficient fix type to be considered valid + bool isFixed(); - // Some functions (L-Band area frequency determination) merely need - // to know if we have a valid fix, not what type of fix - // This function checks to see if the given platform has reached - // sufficient fix type to be considered valid - bool isFixed(); + // Used in tpISR() for time pulse synchronization + bool isFullyResolved(); - // Used in tpISR() for time pulse synchronization - bool isFullyResolved(); + bool isPppConverged(); - bool isPppConverged(); + bool isPppConverging(); - bool isPppConverging(); + // Some functions (L-Band area frequency determination) merely need + // to know if we have an RTK Fix. This function checks to see if the + // given platform has reached sufficient fix type to be considered valid + bool isRTKFix(); - // Some functions (L-Band area frequency determination) merely need - // to know if we have an RTK Fix. This function checks to see if the - // given platform has reached sufficient fix type to be considered valid - bool isRTKFix(); + // Some functions (L-Band area frequency determination) merely need + // to know if we have an RTK Float. This function checks to see if + // the given platform has reached sufficient fix type to be considered + // valid + bool isRTKFloat(); - // Some functions (L-Band area frequency determination) merely need - // to know if we have an RTK Float. This function checks to see if - // the given platform has reached sufficient fix type to be considered - // valid - bool isRTKFloat(); + // Determine if the survey-in operation is complete + // Outputs: + // Returns true if the survey-in operation is complete and false + // if the operation is still running + bool isSurveyInComplete(); - // Determine if the survey-in operation is complete - // Outputs: - // Returns true if the survey-in operation is complete and false - // if the operation is still running - bool isSurveyInComplete(); + // Date will be valid if the RTC is reporting (regardless of GNSS fix) + bool isValidDate(); - // Date will be valid if the RTC is reporting (regardless of GNSS fix) - bool isValidDate(); + // Time will be valid if the RTC is reporting (regardless of GNSS fix) + bool isValidTime(); - // Time will be valid if the RTC is reporting (regardless of GNSS fix) - bool isValidTime(); + // Controls the constellations that are used to generate a fix and logged + void menuConstellations(); - // Controls the constellations that are used to generate a fix and logged - void menuConstellations(); + void menuMessageBaseRtcm(); - void menuMessageBaseRtcm(); + // Control the messages that get broadcast over Bluetooth and logged (if enabled) + void menuMessages(); - // Control the messages that get broadcast over Bluetooth and logged (if enabled) - void menuMessages(); + // Print the module type and firmware version + void printModuleInfo(); - // Print the module type and firmware version - void printModuleInfo(); + // Send correction data to the GNSS + // Inputs: + // dataToSend: Address of a buffer containing the data + // dataLength: The number of valid data bytes in the buffer + // Outputs: + // Returns the number of correction data bytes written + int pushRawData(uint8_t *dataToSend, int dataLength); - // Send correction data to the GNSS - // Inputs: - // dataToSend: Address of a buffer containing the data - // dataLength: The number of valid data bytes in the buffer - // Outputs: - // Returns the number of correction data bytes written - int pushRawData(uint8_t *dataToSend, int dataLength); + uint16_t rtcmBufferAvailable(); - uint16_t rtcmBufferAvailable(); + // If LBand is being used, ignore any RTCM that may come in from the GNSS + void rtcmOnGnssDisable(); - // If LBand is being used, ignore any RTCM that may come in from the GNSS - void rtcmOnGnssDisable(); + // If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver + void rtcmOnGnssEnable(); - // If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver - void rtcmOnGnssEnable(); + uint16_t rtcmRead(uint8_t *rtcmBuffer, int rtcmBytesToRead); - uint16_t rtcmRead(uint8_t *rtcmBuffer, int rtcmBytesToRead); + // Save the current configuration + // Outputs: + // Returns true when the configuration was saved and false upon failure + bool saveConfiguration(); - // Save the current configuration - // Outputs: - // Returns true when the configuration was saved and false upon failure - bool saveConfiguration(); + bool setBaudRate(uint8_t uartNumber, uint32_t baudRate); - bool setBaudRate(uint8_t uartNumber, uint32_t baudRate); + bool setBaudRateComm(uint32_t baudRate); - bool setBaudRateComm(uint32_t baudRate); + bool setBaudRateData(uint32_t baudRate); - bool setBaudRateData(uint32_t baudRate); + bool setBaudRateRadio(uint32_t baudRate); - bool setBaudRateRadio(uint32_t baudRate); + // Enable all the valid constellations and bands for this platform + bool setConstellations(); - // Enable all the valid constellations and bands for this platform - bool setConstellations(); + // Enable / disable corrections protocol(s) on the Radio External port + // Always update if force is true. Otherwise, only update if enable has changed state + bool setCorrRadioExtPort(bool enable, bool force); - // Enable / disable corrections protocol(s) on the Radio External port - // Always update if force is true. Otherwise, only update if enable has changed state - bool setCorrRadioExtPort(bool enable, bool force); + // Set the elevation in degrees + // Inputs: + // elevationDegrees: The elevation value in degrees + bool setElevation(uint8_t elevationDegrees); - // Set the elevation in degrees - // Inputs: - // elevationDegrees: The elevation value in degrees - bool setElevation(uint8_t elevationDegrees); + bool setHighAccuracyService(bool enableGalileoHas); - bool setHighAccuracyService(bool enableGalileoHas); + // Enable all the valid messages for this platform + bool setMessages(int maxRetries); - // Enable all the valid messages for this platform - bool setMessages(int maxRetries); + // Enable all the valid messages for this platform over the USB port + bool setMessagesUsb(int maxRetries); - // Enable all the valid messages for this platform over the USB port - bool setMessagesUsb(int maxRetries); + // Set the dynamic model to use for RTK + // Inputs: + // modelNumber: Number of the model to use, provided by radio library + bool setModel(uint8_t modelNumber); - // Set the dynamic model to use for RTK - // Inputs: - // modelNumber: Number of the model to use, provided by radio library - bool setModel(uint8_t modelNumber); + bool setMultipathMitigation(bool enableMultipathMitigation); - // Specify the interval between solutions - // Inputs: - // secondsBetweenSolutions: Number of seconds between solutions - // Outputs: - // Returns true if the rate was successfully set and false upon - // failure - bool setRate(double secondsBetweenSolutions); + // Specify the interval between solutions + // Inputs: + // secondsBetweenSolutions: Number of seconds between solutions + // Outputs: + // Returns true if the rate was successfully set and false upon + // failure + bool setRate(double secondsBetweenSolutions); - bool setTalkerGNGGA(); + bool setTalkerGNGGA(); - // Hotstart GNSS to try to get RTK lock - bool softwareReset(); + // Hotstart GNSS to try to get RTK lock + bool softwareReset(); - bool standby(); + bool standby(); - // Reset the survey-in operation - // Outputs: - // Returns true if the survey-in operation was reset successfully - // and false upon failure - bool surveyInReset(); + // Reset the survey-in operation + // Outputs: + // Returns true if the survey-in operation was reset successfully + // and false upon failure + bool surveyInReset(); - // Start the survey-in operation - // Outputs: - // Return true if successful and false upon failure - bool surveyInStart(); + // Start the survey-in operation + // Outputs: + // Return true if successful and false upon failure + bool surveyInStart(); - // If we have received serial data from the LG290P outside of the library (ie, from processUart1Message task) - // we can pass data back into the LG290P library to allow it to update its own variables - void lg290pUpdate(uint8_t *incomingBuffer, int bufferLength); + // If we have received serial data from the LG290P outside of the library (ie, from processUart1Message task) + // we can pass data back into the LG290P library to allow it to update its own variables + void lg290pUpdate(uint8_t *incomingBuffer, int bufferLength); - // Poll routine to update the GNSS state - void update(); + // Poll routine to update the GNSS state + void update(); }; #endif // COMPILE_LG290P diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index a7acfd4b0..b06999404 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -2442,7 +2442,16 @@ bool GNSS_LG290P::setMinCno(uint8_t cnoValue) bool GNSS_LG290P::setModel(uint8_t modelNumber) { // Not a feature on LG290p - return (false); + return true; +} + +//---------------------------------------- +// Configure multipath mitigation +//---------------------------------------- +bool GNSS_LG290P::setMultipathMitigation(bool enableMultipathMitigation) +{ + // Does not exist on this platform + return true; } //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.h b/Firmware/RTK_Everywhere/GNSS_Mosaic.h index a8cca68da..a3420a93e 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.h +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.h @@ -1006,15 +1006,17 @@ class GNSS_MOSAIC : GNSS // modelNumber: Number of the model to use, provided by radio library bool setModel(uint8_t modelNumber); + bool setMultipathMitigation(bool enableMultipathMitigation); + // Given the name of a message, find it, and set the rate bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); - // Setup the timepulse output on the PPS pin for external triggering + // Setup the timepulse output on the PPS pin for external triggering // Outputs // Returns true if the pin was successfully setup and false upon // failure bool setPPS(); - + // Specify the interval between solutions // Inputs: // secondsBetweenSolutions: Number of seconds between solutions diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino index 4e2a06fc2..6950b83ab 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino @@ -2510,6 +2510,15 @@ bool GNSS_MOSAIC::setModel(uint8_t modelNumber) return (sendWithResponse(setting, "ReceiverDynamics")); } +//---------------------------------------- +// Configure multipath mitigation +//---------------------------------------- +bool GNSS_MOSAIC::setMultipathMitigation(bool enableMultipathMitigation) +{ + // Does not exist on this platform + return true; +} + // Given the name of a message, find it, and set the rate bool GNSS_MOSAIC::setNmeaMessageRateByName(const char *msgName, uint8_t msgRate) { diff --git a/Firmware/RTK_Everywhere/GNSS_None.h b/Firmware/RTK_Everywhere/GNSS_None.h index fee65f9bc..bb81a8b56 100644 --- a/Firmware/RTK_Everywhere/GNSS_None.h +++ b/Firmware/RTK_Everywhere/GNSS_None.h @@ -586,10 +586,15 @@ class GNSS_None : public GNSS return true; } + bool setMultipathMitigation(bool enableMultipathMitigation) + { + return true; + } + // Given the name of a message, find it, and set the rate bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate) { - return (true); + return true; } // Configure the Pulse-per-second pin based on user settings diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.h b/Firmware/RTK_Everywhere/GNSS_UM980.h index 321222073..03708d8ee 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.h +++ b/Firmware/RTK_Everywhere/GNSS_UM980.h @@ -148,8 +148,6 @@ class GNSS_UM980 : GNSS // Set the minimum satellite signal level for navigation. bool setMinCno(uint8_t cnoValue); - bool setMultipathMitigation(bool enableMultipathMitigation); - public: // Constructor GNSS_UM980() : GNSS() @@ -456,6 +454,8 @@ class GNSS_UM980 : GNSS // modelNumber: Number of the model to use, provided by radio library bool setModel(uint8_t modelNumber); + bool setMultipathMitigation(bool enableMultipathMitigation); + // Given the name of a message, find it, and set the rate bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index 2ef8111e9..c43d8677b 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -137,10 +137,15 @@ bool GNSS_UM980::setPPS() // The PPS signal is not exposed on the Torch so we don't configure the PPS based on internal settings, but we do // configure the PPS so that the GNSS LED blinks + // Read, modify, write + // The UM980 does have the ability to read the current PPS settings in config, but this function + // gets called very rarely. Just do a write for now. + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM // Enable PPS signal with a width of 200ms, and a period of 1 second - return(_um980->enablePPS(settings.externalPulseLength_us, settings.externalPulseTimeBetweenPulse_us / 1000)); // widthMicroseconds, periodMilliseconds + return (_um980->enablePPS(settings.externalPulseLength_us, settings.externalPulseTimeBetweenPulse_us / + 1000)); // widthMicroseconds, periodMilliseconds } //---------------------------------------- @@ -191,11 +196,10 @@ bool GNSS_UM980::configureBase() // Set the dynamic mode. This will cancel any base averaging mode and is needed // to allow a freshly started device to settle in regular GNSS reception mode before issuing // um980BaseAverageStart(). - response &= setModel(settings.dynamicModel); - response &= setMultipathMitigation(settings.enableMultipathMitigation); - - response &= setHighAccuracyService(settings.enableGalileoHas); + gnssConfigure(GNSS_CONFIG_MODEL); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MULTIPATH); + gnssConfigure(GNSS_CONFIG_HAS_E6); response &= enableRTCMBase(); // Only turn on messages, do not turn off messages. We assume the caller has // UNLOG or similar. @@ -258,8 +262,7 @@ bool GNSS_UM980::configureOnce() gnssConfigure(GNSS_CONFIG_ELEVATION); // Request receiver to use new settings gnssConfigure(GNSS_CONFIG_CN0); gnssConfigure(GNSS_CONFIG_PPS); - - response &= setConstellations(); + gnssConfigure(GNSS_CONFIG_CONSTELLATION); if (_um980->isConfigurationPresent("CONFIG SIGNALGROUP 2") == false) { @@ -1642,12 +1645,14 @@ bool GNSS_UM980::setBaudRateRadio(uint32_t baudRate) //---------------------------------------- // Enable all the valid constellations and bands for this platform -// Band support varies between platforms and firmware versions //---------------------------------------- bool GNSS_UM980::setConstellations() { bool response = true; + // Read, modify, write + // The UM980 does not have a way to read the currently enabled constellations so we do only a write + for (int constellationNumber = 0; constellationNumber < MAX_UM980_CONSTELLATIONS; constellationNumber++) { if (settings.um980Constellations[constellationNumber]) @@ -1687,7 +1692,6 @@ bool GNSS_UM980::setElevation(uint8_t elevationDegrees) if (currentElevation == elevationDegrees) return (true); // Nothing to change - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM return _um980->setElevationAngle(elevationDegrees); } return false; @@ -1713,7 +1717,6 @@ bool GNSS_UM980::setHighAccuracyService(bool enableGalileoHas) if (_um980->sendCommand("CONFIG PPP ENABLE E6-HAS")) { systemPrintln("Galileo E6 HAS service enabled"); - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM } else { @@ -1724,7 +1727,6 @@ bool GNSS_UM980::setHighAccuracyService(bool enableGalileoHas) if (_um980->sendCommand("CONFIG PPP DATUM WGS84")) { systemPrintln("WGS84 Datum applied"); - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM } else { @@ -1751,7 +1753,6 @@ bool GNSS_UM980::setHighAccuracyService(bool enableGalileoHas) if (_um980->sendCommand("CONFIG PPP DISABLE")) { systemPrintln("Galileo E6 HAS service disabled"); - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM } else { @@ -1795,7 +1796,6 @@ bool GNSS_UM980::setMinCno(uint8_t cn0Value) { // Read, modify, write // The UM980 does not currently have a way to read the CN0, so we must write only - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM _um980->setMinCNO(cn0Value); return true; } @@ -1809,7 +1809,9 @@ bool GNSS_UM980::setModel(uint8_t modelNumber) { if (online.gnss) { - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + // Read, modify, write + // #MODE,97,GPS,FINE,2387,501442000,0,0,18,511;MODE ROVER SURVEY,*10 + // There is the ability to check the #MODE response, but for now, just write it if (modelNumber == UM980_DYN_MODEL_SURVEY) return (_um980->setModeRoverSurvey()); @@ -1821,6 +1823,8 @@ bool GNSS_UM980::setModel(uint8_t modelNumber) return (false); } +//---------------------------------------- +// Configure multipath mitigation //---------------------------------------- bool GNSS_UM980::setMultipathMitigation(bool enableMultipathMitigation) { diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.h b/Firmware/RTK_Everywhere/GNSS_ZED.h index d5cb1a0b3..fb8266838 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.h +++ b/Firmware/RTK_Everywhere/GNSS_ZED.h @@ -713,6 +713,8 @@ class GNSS_ZED : GNSS // modelNumber: Number of the model to use, provided by radio library bool setModel(uint8_t modelNumber); + bool setMultipathMitigation(bool enableMultipathMitigation); + // Given the name of a message, find it, and set the rate bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index f8faf2336..ddfb2ced1 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -2385,6 +2385,15 @@ bool GNSS_ZED::setModel(uint8_t modelNumber) return false; } +//---------------------------------------- +// Configure multipath mitigation +//---------------------------------------- +bool GNSS_ZED::setMultipathMitigation(bool enableMultipathMitigation) +{ + // Does not exist on the ZED platform + return true; +} + //---------------------------------------- // Given the number of seconds between desired solution reports, determine measurementRateMs and navigationRate // measurementRateS > 25 & <= 65535 From a72b2f52cc1d2c8bccc41c6c5a091733fea52374 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Sat, 11 Oct 2025 12:56:54 -0600 Subject: [PATCH 19/68] Make setMessagesNMEA/RTCM uniform across all platforms. --- Firmware/RTK_Everywhere/GNSS.h | 573 +++++------ Firmware/RTK_Everywhere/GNSS.ino | 9 + Firmware/RTK_Everywhere/GNSS_LG290P.h | 20 +- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 1079 ++++++++++---------- Firmware/RTK_Everywhere/GNSS_Mosaic.h | 20 +- Firmware/RTK_Everywhere/GNSS_Mosaic.ino | 746 +++++++------- Firmware/RTK_Everywhere/GNSS_None.h | 18 +- Firmware/RTK_Everywhere/GNSS_UM980.h | 683 +++++++------ Firmware/RTK_Everywhere/GNSS_UM980.ino | 322 +++--- Firmware/RTK_Everywhere/GNSS_ZED.h | 15 +- Firmware/RTK_Everywhere/GNSS_ZED.ino | 62 +- Firmware/RTK_Everywhere/RTK_Everywhere.ino | 4 +- Firmware/RTK_Everywhere/menuSystem.ino | 15 - 13 files changed, 1759 insertions(+), 1807 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.h b/Firmware/RTK_Everywhere/GNSS.h index ead6249c1..88fd3b344 100644 --- a/Firmware/RTK_Everywhere/GNSS.h +++ b/Firmware/RTK_Everywhere/GNSS.h @@ -9,393 +9,396 @@ GNSS.h class GNSS { - protected: - float _altitude; // Altitude in meters - float _horizontalAccuracy; // Horizontal position accuracy in meters - double _latitude; // Latitude in degrees - double _longitude; // Longitude in degrees - - uint8_t _day; // Day number - uint8_t _month; // Month number - uint16_t _year; - uint8_t _hour; // Hours for 24 hour clock - uint8_t _minute; - uint8_t _second; - uint8_t _leapSeconds; - uint16_t _millisecond; // Limited to first two digits - uint32_t _nanosecond; - - uint8_t _satellitesInView; - uint8_t _fixType; - uint8_t _carrierSolution; - - bool _validDate; // True when date is valid - bool _validTime; // True when time is valid - bool _confirmedDate; - bool _confirmedTime; - bool _fullyResolved; - uint32_t _tAcc; - - unsigned long _pvtArrivalMillis; - bool _pvtUpdated; - - bool _corrRadioExtPortEnabled = false; - - unsigned long _autoBaseStartTimer; // Tracks how long the base auto / averaging mode has been running +protected: + float _altitude; // Altitude in meters + float _horizontalAccuracy; // Horizontal position accuracy in meters + double _latitude; // Latitude in degrees + double _longitude; // Longitude in degrees + + uint8_t _day; // Day number + uint8_t _month; // Month number + uint16_t _year; + uint8_t _hour; // Hours for 24 hour clock + uint8_t _minute; + uint8_t _second; + uint8_t _leapSeconds; + uint16_t _millisecond; // Limited to first two digits + uint32_t _nanosecond; + + uint8_t _satellitesInView; + uint8_t _fixType; + uint8_t _carrierSolution; + + bool _validDate; // True when date is valid + bool _validTime; // True when time is valid + bool _confirmedDate; + bool _confirmedTime; + bool _fullyResolved; + uint32_t _tAcc; + + unsigned long _pvtArrivalMillis; + bool _pvtUpdated; + + bool _corrRadioExtPortEnabled = false; + + unsigned long _autoBaseStartTimer; // Tracks how long the base auto / averaging mode has been running - // Setup the general configuration of the GNSS - // Not Rover or Base specific (ie, baud rates) - // Outputs: - // Returns true if successfully configured and false upon failure - virtual bool configureGNSS(); - - public: - // Constructor - GNSS() : _leapSeconds(18), _pvtArrivalMillis(0), _pvtUpdated(0), _satellitesInView(0) - { - } + // Setup the general configuration of the GNSS + // Not Rover or Base specific (ie, baud rates) + // Outputs: + // Returns true if successfully configured and false upon failure + virtual bool configureGNSS(); + +public: + // Constructor + GNSS() : _leapSeconds(18), _pvtArrivalMillis(0), _pvtUpdated(0), _satellitesInView(0) + { + } - // If we have decryption keys, configure module - // Note: don't check online.lband_neo here. We could be using ip corrections - virtual void applyPointPerfectKeys(); + // If we have decryption keys, configure module + // Note: don't check online.lband_neo here. We could be using ip corrections + virtual void applyPointPerfectKeys(); - // Set RTCM for base mode to defaults (1005/1074/1084/1094/1124 1Hz & 1230 0.1Hz) - virtual void baseRtcmDefault(); + // Set RTCM for base mode to defaults (1005/1074/1084/1094/1124 1Hz & 1230 0.1Hz) + virtual void baseRtcmDefault(); - // Reset to Low Bandwidth Link (1074/1084/1094/1124 0.5Hz & 1005/1230 0.1Hz) - virtual void baseRtcmLowDataRate(); + // Reset to Low Bandwidth Link (1074/1084/1094/1124 0.5Hz & 1005/1230 0.1Hz) + virtual void baseRtcmLowDataRate(); - // Check if a given baud rate is supported by this module - virtual bool baudIsAllowed(uint32_t baudRate); - virtual uint32_t baudGetMinimum(); - virtual uint32_t baudGetMaximum(); + // Check if a given baud rate is supported by this module + virtual bool baudIsAllowed(uint32_t baudRate); + virtual uint32_t baudGetMinimum(); + virtual uint32_t baudGetMaximum(); - // Connect to GNSS and identify particulars - virtual void begin(); + // Connect to GNSS and identify particulars + virtual void begin(); - // Setup TM2 time stamp input as need - // Outputs: - // Returns true when an external event occurs and false if no event - virtual bool beginExternalEvent(); + // Setup TM2 time stamp input as need + // Outputs: + // Returns true when an external event occurs and false if no event + virtual bool beginExternalEvent(); - virtual bool checkNMEARates(); + virtual bool checkNMEARates(); - virtual bool checkPPPRates(); + virtual bool checkPPPRates(); - // Setup the general configuration of the GNSS - // Not Rover or Base specific (ie, baud rates) - // Outputs: - // Returns true if successfully configured and false upon failure - bool configure(); + // Setup the general configuration of the GNSS + // Not Rover or Base specific (ie, baud rates) + // Outputs: + // Returns true if successfully configured and false upon failure + bool configure(); - // Configure the Base - // Outputs: - // Returns true if successfully configured and false upon failure - virtual bool configureBase(); + // Configure the Base + // Outputs: + // Returns true if successfully configured and false upon failure + virtual bool configureBase(); - // Configure specific aspects of the receiver for NTP mode - virtual bool configureNtpMode(); + // Configure specific aspects of the receiver for NTP mode + virtual bool configureNtpMode(); - // Configure the Rover - // Outputs: - // Returns true if successfully configured and false upon failure - virtual bool configureRover(); + // Configure the Rover + // Outputs: + // Returns true if successfully configured and false upon failure + virtual bool configureRover(); - // Responds with the messages supported on this platform - // Inputs: - // returnText: String to receive message names - // Returns message names in the returnText string - virtual void createMessageList(String &returnText); + // Responds with the messages supported on this platform + // Inputs: + // returnText: String to receive message names + // Returns message names in the returnText string + virtual void createMessageList(String &returnText); - // Responds with the RTCM/Base messages supported on this platform - // Inputs: - // returnText: String to receive message names - // Returns message names in the returnText string - virtual void createMessageListBase(String &returnText); + // Responds with the RTCM/Base messages supported on this platform + // Inputs: + // returnText: String to receive message names + // Returns message names in the returnText string + virtual void createMessageListBase(String &returnText); - virtual void debuggingDisable(); + virtual void debuggingDisable(); - virtual void debuggingEnable(); + virtual void debuggingEnable(); - virtual void enableGgaForNtrip(); + virtual void enableGgaForNtrip(); - // Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted - // even if there is no GPS fix. We use it to test serial output. - // Outputs: - // Returns true if successfully started and false upon failure - virtual bool enableRTCMTest(); + // Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted + // even if there is no GPS fix. We use it to test serial output. + // Outputs: + // Returns true if successfully started and false upon failure + virtual bool enableRTCMTest(); - // Restore the GNSS to the factory settings - virtual void factoryReset(); + // Restore the GNSS to the factory settings + virtual void factoryReset(); - virtual uint16_t fileBufferAvailable(); + virtual uint16_t fileBufferAvailable(); - virtual uint16_t fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead); + virtual uint16_t fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead); - // Start the base using fixed coordinates - // Outputs: - // Returns true if successfully started and false upon failure - virtual bool fixedBaseStart(); + // Start the base using fixed coordinates + // Outputs: + // Returns true if successfully started and false upon failure + virtual bool fixedBaseStart(); - // Return the number of active/enabled messages - virtual uint8_t getActiveMessageCount(); + // Return the number of active/enabled messages + virtual uint8_t getActiveMessageCount(); - // Return the number of active/enabled RTCM messages - virtual uint8_t getActiveRtcmMessageCount(); + // Return the number of active/enabled RTCM messages + virtual uint8_t getActiveRtcmMessageCount(); - // Get the altitude - // Outputs: - // Returns the altitude in meters or zero if the GNSS is offline - virtual double getAltitude(); + // Get the altitude + // Outputs: + // Returns the altitude in meters or zero if the GNSS is offline + virtual double getAltitude(); - // Returns the carrier solution or zero if not online - virtual uint8_t getCarrierSolution(); + // Returns the carrier solution or zero if not online + virtual uint8_t getCarrierSolution(); - virtual uint32_t getDataBaudRate(); + virtual uint32_t getDataBaudRate(); - // Returns the day number or zero if not online - virtual uint8_t getDay(); + // Returns the day number or zero if not online + virtual uint8_t getDay(); - // Return the number of milliseconds since GNSS data was last updated - virtual uint16_t getFixAgeMilliseconds(); + // Return the number of milliseconds since GNSS data was last updated + virtual uint16_t getFixAgeMilliseconds(); - // Returns the fix type or zero if not online - virtual uint8_t getFixType(); + // Returns the fix type or zero if not online + virtual uint8_t getFixType(); - // Returns the hours of 24 hour clock or zero if not online - virtual uint8_t getHour(); + // Returns the hours of 24 hour clock or zero if not online + virtual uint8_t getHour(); - // Get the horizontal position accuracy - // Outputs: - // Returns the horizontal position accuracy or zero if offline - virtual float getHorizontalAccuracy(); + // Get the horizontal position accuracy + // Outputs: + // Returns the horizontal position accuracy or zero if offline + virtual float getHorizontalAccuracy(); - virtual const char *getId(); + virtual const char *getId(); - // Get the latitude value - // Outputs: - // Returns the latitude value or zero if not online - virtual double getLatitude(); + // Get the latitude value + // Outputs: + // Returns the latitude value or zero if not online + virtual double getLatitude(); - // Query GNSS for current leap seconds - virtual uint8_t getLeapSeconds(); + // Query GNSS for current leap seconds + virtual uint8_t getLeapSeconds(); - // Return the type of logging that matches the enabled messages - drives the logging icon - virtual uint8_t getLoggingType(); + // Return the type of logging that matches the enabled messages - drives the logging icon + virtual uint8_t getLoggingType(); - // Get the longitude value - // Outputs: - // Returns the longitude value or zero if not online - virtual double getLongitude(); + // Get the longitude value + // Outputs: + // Returns the longitude value or zero if not online + virtual double getLongitude(); - // Returns two digits of milliseconds or zero if not online - virtual uint8_t getMillisecond(); + // Returns two digits of milliseconds or zero if not online + virtual uint8_t getMillisecond(); - // Get the minimum satellite signal level for navigation. - uint8_t getMinCno(); + // Get the minimum satellite signal level for navigation. + uint8_t getMinCno(); - // Returns minutes or zero if not online - virtual uint8_t getMinute(); + // Returns minutes or zero if not online + virtual uint8_t getMinute(); - // Returns month number or zero if not online - virtual uint8_t getMonth(); + // Returns month number or zero if not online + virtual uint8_t getMonth(); - // Returns nanoseconds or zero if not online - virtual uint32_t getNanosecond(); + // Returns nanoseconds or zero if not online + virtual uint32_t getNanosecond(); - virtual uint32_t getRadioBaudRate(); + virtual uint32_t getRadioBaudRate(); - // Returns the seconds between solutions - virtual double getRateS(); + // Returns the seconds between solutions + virtual double getRateS(); - virtual const char *getRtcmDefaultString(); + virtual const char *getRtcmDefaultString(); - virtual const char *getRtcmLowDataRateString(); + virtual const char *getRtcmLowDataRateString(); - // Returns the number of satellites in view or zero if offline - virtual uint8_t getSatellitesInView(); + // Returns the number of satellites in view or zero if offline + virtual uint8_t getSatellitesInView(); - // Returns seconds or zero if not online - virtual uint8_t getSecond(); + // Returns seconds or zero if not online + virtual uint8_t getSecond(); - // Get the survey-in mean accuracy - // Outputs: - // Returns the mean accuracy or zero (0) - virtual float getSurveyInMeanAccuracy(); + // Get the survey-in mean accuracy + // Outputs: + // Returns the mean accuracy or zero (0) + virtual float getSurveyInMeanAccuracy(); - // Return the number of seconds the survey-in process has been running - virtual int getSurveyInObservationTime(); + // Return the number of seconds the survey-in process has been running + virtual int getSurveyInObservationTime(); - float getSurveyInStartingAccuracy(); + float getSurveyInStartingAccuracy(); - // Returns timing accuracy or zero if not online - virtual uint32_t getTimeAccuracy(); + // Returns timing accuracy or zero if not online + virtual uint32_t getTimeAccuracy(); - // Returns full year, ie 2023, not 23. - virtual uint16_t getYear(); + // Returns full year, ie 2023, not 23. + virtual uint16_t getYear(); - // Antenna Short / Open detection - virtual bool isAntennaShorted(); - virtual bool isAntennaOpen(); + // Antenna Short / Open detection + virtual bool isAntennaShorted(); + virtual bool isAntennaOpen(); - virtual bool isBlocking(); + virtual bool isBlocking(); - // Date is confirmed once we have GNSS fix - virtual bool isConfirmedDate(); + // Date is confirmed once we have GNSS fix + virtual bool isConfirmedDate(); - // Date is confirmed once we have GNSS fix - virtual bool isConfirmedTime(); + // Date is confirmed once we have GNSS fix + virtual bool isConfirmedTime(); - // Returns true if data is arriving on the Radio Ext port - virtual bool isCorrRadioExtPortActive(); + // Returns true if data is arriving on the Radio Ext port + virtual bool isCorrRadioExtPortActive(); - // Return true if GNSS receiver has a higher quality DGPS fix than 3D - virtual bool isDgpsFixed(); + // Return true if GNSS receiver has a higher quality DGPS fix than 3D + virtual bool isDgpsFixed(); - // Some functions (L-Band area frequency determination) merely need - // to know if we have a valid fix, not what type of fix - // This function checks to see if the given platform has reached - // sufficient fix type to be considered valid - virtual bool isFixed(); + // Some functions (L-Band area frequency determination) merely need + // to know if we have a valid fix, not what type of fix + // This function checks to see if the given platform has reached + // sufficient fix type to be considered valid + virtual bool isFixed(); - // Used in tpISR() for time pulse synchronization - virtual bool isFullyResolved(); + // Used in tpISR() for time pulse synchronization + virtual bool isFullyResolved(); - virtual bool isPppConverged(); + virtual bool isPppConverged(); - virtual bool isPppConverging(); + virtual bool isPppConverging(); - // Some functions (L-Band area frequency determination) merely need - // to know if we have an RTK Fix. This function checks to see if the - // given platform has reached sufficient fix type to be considered valid - virtual bool isRTKFix(); + // Some functions (L-Band area frequency determination) merely need + // to know if we have an RTK Fix. This function checks to see if the + // given platform has reached sufficient fix type to be considered valid + virtual bool isRTKFix(); - // Some functions (L-Band area frequency determination) merely need - // to know if we have an RTK Float. This function checks to see if - // the given platform has reached sufficient fix type to be considered - // valid - virtual bool isRTKFloat(); + // Some functions (L-Band area frequency determination) merely need + // to know if we have an RTK Float. This function checks to see if + // the given platform has reached sufficient fix type to be considered + // valid + virtual bool isRTKFloat(); - // Determine if the survey-in operation is complete - // Outputs: - // Returns true if the survey-in operation is complete and false - // if the operation is still running - virtual bool isSurveyInComplete(); + // Determine if the survey-in operation is complete + // Outputs: + // Returns true if the survey-in operation is complete and false + // if the operation is still running + virtual bool isSurveyInComplete(); - // Date will be valid if the RTC is reporting (regardless of GNSS fix) - virtual bool isValidDate(); + // Date will be valid if the RTC is reporting (regardless of GNSS fix) + virtual bool isValidDate(); - // Time will be valid if the RTC is reporting (regardless of GNSS fix) - virtual bool isValidTime(); + // Time will be valid if the RTC is reporting (regardless of GNSS fix) + virtual bool isValidTime(); - // Controls the constellations that are used to generate a fix and logged - virtual void menuConstellations(); + // Controls the constellations that are used to generate a fix and logged + virtual void menuConstellations(); - virtual void menuMessageBaseRtcm(); + virtual void menuMessageBaseRtcm(); - // Control the messages that get broadcast over Bluetooth and logged (if enabled) - virtual void menuMessages(); + // Control the messages that get broadcast over Bluetooth and logged (if enabled) + virtual void menuMessages(); - // Print the module type and firmware version - virtual void printModuleInfo(); + // Print the module type and firmware version + virtual void printModuleInfo(); - // Send correction data to the GNSS - // Inputs: - // dataToSend: Address of a buffer containing the data - // dataLength: The number of valid data bytes in the buffer - // Outputs: - // Returns the number of correction data bytes written - virtual int pushRawData(uint8_t *dataToSend, int dataLength); + // Send correction data to the GNSS + // Inputs: + // dataToSend: Address of a buffer containing the data + // dataLength: The number of valid data bytes in the buffer + // Outputs: + // Returns the number of correction data bytes written + virtual int pushRawData(uint8_t *dataToSend, int dataLength); - virtual uint16_t rtcmBufferAvailable(); + virtual uint16_t rtcmBufferAvailable(); - // If LBand is being used, ignore any RTCM that may come in from the GNSS - virtual void rtcmOnGnssDisable(); + // If LBand is being used, ignore any RTCM that may come in from the GNSS + virtual void rtcmOnGnssDisable(); - // If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver - virtual void rtcmOnGnssEnable(); + // If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver + virtual void rtcmOnGnssEnable(); - virtual uint16_t rtcmRead(uint8_t *rtcmBuffer, int rtcmBytesToRead); + virtual uint16_t rtcmRead(uint8_t *rtcmBuffer, int rtcmBytesToRead); - // Save the current configuration - // Outputs: - // Returns true when the configuration was saved and false upon failure - virtual bool saveConfiguration(); + // Save the current configuration + // Outputs: + // Returns true when the configuration was saved and false upon failure + virtual bool saveConfiguration(); - // Enable all the valid constellations and bands for this platform - virtual bool setConstellations(); + // Enable all the valid constellations and bands for this platform + virtual bool setConstellations(); - // Enable / disable corrections protocol(s) on the Radio External port - // Always update if force is true. Otherwise, only update if enable has changed state - virtual bool setCorrRadioExtPort(bool enable, bool force); + // Enable / disable corrections protocol(s) on the Radio External port + // Always update if force is true. Otherwise, only update if enable has changed state + virtual bool setCorrRadioExtPort(bool enable, bool force); - virtual bool setBaudRate(uint8_t uartNumber, uint32_t baudRate); + virtual bool setBaudRate(uint8_t uartNumber, uint32_t baudRate); - virtual bool setBaudRateComm(uint32_t baud); + virtual bool setBaudRateComm(uint32_t baud); - virtual bool setBaudRateData(uint32_t baud); + virtual bool setBaudRateData(uint32_t baud); - virtual bool setBaudRateRadio(uint32_t baud); + virtual bool setBaudRateRadio(uint32_t baud); - // Set the elevation in degrees - // Inputs: - // elevationDegrees: The elevation value in degrees - virtual bool setElevation(uint8_t elevationDegrees); + // Set the elevation in degrees + // Inputs: + // elevationDegrees: The elevation value in degrees + virtual bool setElevation(uint8_t elevationDegrees); - virtual bool setHighAccuracyService(bool enableGalileoHas); + virtual bool setHighAccuracyService(bool enableGalileoHas); - virtual bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); + virtual bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); - // Enable all the valid messages for this platform - virtual bool setMessages(int maxRetries); + // Enable/disable messages according to the NMEA array + virtual bool setMessagesNMEA(); - // Enable all the valid messages for this platform over the USB port - virtual bool setMessagesUsb(int maxRetries); + // Enable/disable messages according to the RTCM Base array + virtual bool setMessagesRTCMBase(); - // Set the minimum satellite signal level for navigation. - virtual bool setMinCno(uint8_t cnoValue); + // Enable/disable messages according to the NMEA array + virtual bool setMessagesRTCMRover(); - // Set the dynamic model to use for RTK - // Inputs: - // modelNumber: Number of the model to use, provided by radio library - virtual bool setModel(uint8_t modelNumber); + // Set the minimum satellite signal level for navigation. + virtual bool setMinCno(uint8_t cnoValue); - virtual bool setMultipathMitigation(bool enableMultipathMitigation); + // Set the dynamic model to use for RTK + // Inputs: + // modelNumber: Number of the model to use, provided by radio library + virtual bool setModel(uint8_t modelNumber); - // Configure the Pulse-per-second pin based on user settings - virtual bool setPPS(); + virtual bool setMultipathMitigation(bool enableMultipathMitigation); - // Specify the interval between solutions - // Inputs: - // secondsBetweenSolutions: Number of seconds between solutions - // Outputs: - // Returns true if the rate was successfully set and false upon - // failure - virtual bool setRate(double secondsBetweenSolutions); + // Configure the Pulse-per-second pin based on user settings + virtual bool setPPS(); - virtual bool setTalkerGNGGA(); + // Specify the interval between solutions + // Inputs: + // secondsBetweenSolutions: Number of seconds between solutions + // Outputs: + // Returns true if the rate was successfully set and false upon + // failure + virtual bool setRate(double secondsBetweenSolutions); - // Hotstart GNSS to try to get RTK lock - virtual bool softwareReset(); + virtual bool setTalkerGNGGA(); - virtual bool standby(); + // Hotstart GNSS to try to get RTK lock + virtual bool softwareReset(); - // Antenna Short / Open detection - virtual bool supportsAntennaShortOpen(); + virtual bool standby(); - // Reset the survey-in operation - // Outputs: - // Returns true if the survey-in operation was reset successfully - // and false upon failure - virtual bool surveyInReset(); + // Antenna Short / Open detection + virtual bool supportsAntennaShortOpen(); - // Start the survey-in operation - // Outputs: - // Return true if successful and false upon failure - virtual bool surveyInStart(); + // Reset the survey-in operation + // Outputs: + // Returns true if the survey-in operation was reset successfully + // and false upon failure + virtual bool surveyInReset(); - // Poll routine to update the GNSS state - virtual void update(); + // Start the survey-in operation + // Outputs: + // Return true if successful and false upon failure + virtual bool surveyInStart(); + + // Poll routine to update the GNSS state + virtual void update(); }; // Update the constellations following a set command diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index 3e167dfe2..310b8cd6f 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -120,6 +120,15 @@ void gnssUpdate() // Service requests // Clear the requests as they are completed successfully + if (gnssConfigureRequest & GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE) + { + if (gnss->setMessagesRTCMBase() == true) + { + gnssConfigureClear(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } + } + if (gnssConfigureRequest & GNSS_CONFIG_CONSTELLATION) { if (gnss->setConstellations() == true) diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.h b/Firmware/RTK_Everywhere/GNSS_LG290P.h index 17659dff0..7ebf16b8b 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.h +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.h @@ -84,15 +84,6 @@ class GNSS_LG290P : GNSS // Returns true if successfully configured and false upon failure bool configureGNSS(); - // Turn on all the enabled NMEA messages on COM3 - bool enableNMEA(); - - // Turn on all the enabled RTCM Rover messages on COM3 - bool enableRTCMRover(); - - // Turn on all the enabled RTCM Base messages on COM3 - bool enableRTCMBase(); - uint8_t getActiveNmeaMessageCount(); // Given the name of an NMEA message, return the array number @@ -427,11 +418,14 @@ class GNSS_LG290P : GNSS bool setHighAccuracyService(bool enableGalileoHas); - // Enable all the valid messages for this platform - bool setMessages(int maxRetries); + // Set the NMEA messages + bool setMessagesNMEA(); + + // Set then RTCM Base messages + bool setMessagesRTCMBase(); - // Enable all the valid messages for this platform over the USB port - bool setMessagesUsb(int maxRetries); + // Set the RTCM Rover messages + bool setMessagesRTCMRover(); // Set the dynamic model to use for RTK // Inputs: diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index b06999404..1e40f9322 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -386,7 +386,7 @@ bool GNSS_LG290P::configureRover() if (response == false && settings.debugGnss) systemPrintln("configureRover: setBaud failed."); - // Enable of GGA, RMC, GST for tilt sensor is done in enableNMEA() + // Enable of GGA, RMC, GST for tilt sensor is done in setMessagesNMEA() } } @@ -397,11 +397,11 @@ bool GNSS_LG290P::configureRover() response &= setHighAccuracyService(settings.enableGalileoHas); - response &= enableRTCMRover(); + response &= setMessagesRTCMRover(); if (settings.debugGnss && response == false) systemPrintln("configureRover: Enable RTCM failed"); - response &= enableNMEA(); + response &= setMessagesNMEA(); if (settings.debugGnss && response == false) systemPrintln("configureRover: Enable NMEA failed"); @@ -513,11 +513,11 @@ bool GNSS_LG290P::configureBase() response &= setHighAccuracyService(settings.enableGalileoHas); - response &= enableRTCMBase(); // Set RTCM messages + response &= setMessagesRTCMBase(); // Set RTCM messages if (settings.debugGnss && response == false) systemPrintln("configureBase: Enable RTCM failed"); - response &= enableNMEA(); // Set NMEA messages + response &= setMessagesNMEA(); // Set NMEA messages if (settings.debugGnss && response == false) systemPrintln("configureBase: Enable NMEA failed"); @@ -536,7 +536,7 @@ bool GNSS_LG290P::configureBase() // When a device is changed from Rover to Base, NMEA messages settings do not survive PQTMSAVEPAR // Re-enable NMEA post reset - response &= enableNMEA(); // Set NMEA messages + response &= setMessagesNMEA(); // Set NMEA messages if (settings.debugGnss && response) systemPrintln("LG290P Base configured"); @@ -678,360 +678,6 @@ void GNSS_LG290P::enableGgaForNtrip() // TODO lg290pEnableGgaForNtrip(); } -//---------------------------------------- -// Turn on all the enabled NMEA messages -//---------------------------------------- -bool GNSS_LG290P::enableNMEA() -{ - bool response = true; - bool gpggaEnabled = false; - - int portNumber = 1; - - while (portNumber < 4) - { - for (int messageNumber = 0; messageNumber < MAX_LG290P_NMEA_MSG; messageNumber++) - { - // Check if this NMEA message is supported by the current LG290P firmware - if (lg290pFirmwareVersion >= lgMessagesNMEA[messageNumber].firmwareVersionSupported) - { - // Disable NMEA output on UART3 RADIO - int msgRate = settings.lg290pMessageRatesNMEA[messageNumber]; - if ((portNumber == 3) && (settings.enableNmeaOnRadio == false)) - msgRate = 0; - - // If firmware is 4 or higher, use setMessageRateOnPort, otherwise setMessageRate - if (lg290pFirmwareVersion >= 4) - // Enable this message, at this rate, on this port - response &= - _lg290p->setMessageRateOnPort(lgMessagesNMEA[messageNumber].msgTextName, msgRate, portNumber); - else - // Enable this message, at this rate - response &= _lg290p->setMessageRate(lgMessagesNMEA[messageNumber].msgTextName, msgRate); - if (response == false && settings.debugGnss) - systemPrintf("Enable NMEA failed at messageNumber %d %s.\r\n", messageNumber, - lgMessagesNMEA[messageNumber].msgTextName); - - // If we are using IP based corrections, we need to send local data to the PPL - // The PPL requires being fed GPGGA/ZDA, and RTCM1019/1020/1042/1046 - if (pointPerfectServiceUsesKeys()) - { - // Mark PPL required messages as enabled if rate > 0 - if (settings.lg290pMessageRatesNMEA[messageNumber] > 0) - { - if (strcmp(lgMessagesNMEA[messageNumber].msgTextName, "GGA") == 0) - gpggaEnabled = true; - } - } - } - } - - portNumber++; - - // setMessageRateOnPort only supported on v4 and above - if (lg290pFirmwareVersion < 4) - break; // Don't step through portNumbers - } - - if (pointPerfectServiceUsesKeys()) - { - // Force on any messages that are needed for PPL - // If firmware is 4 or higher, use setMessageRateOnPort, otherwise setMessageRate - if (lg290pFirmwareVersion >= 4) - { - // Enable GGA on UART 2 (connected to ESP32) only - if (gpggaEnabled == false) - response &= _lg290p->setMessageRateOnPort("GGA", 1, 2); - } - else - { - // Enable GGA on all UARTs. It's the best we can do. - if (gpggaEnabled == false) - response &= _lg290p->setMessageRate("GGA", 1); - } - } - - // If this is Flex, we may need to enable NMEA for Tilt IMU - if (present.tiltPossible == true) - { - if (present.imu_im19 == true && settings.enableTiltCompensation == true) - { - // Regardless of user settings, enable GGA, RMC, GST on UART3 - // If firmware is 4 or higher, use setMessageRateOnPort, otherwise setMessageRate - if (lg290pFirmwareVersion >= 4) - { - // Enable GGA/RMS/GST on UART 3 (connected to the IMU) only - response &= _lg290p->setMessageRateOnPort("GGA", 1, 3); - response &= _lg290p->setMessageRateOnPort("RMC", 1, 3); - response &= _lg290p->setMessageRateOnPort("GST", 1, 3); - } - else - { - // GST not supported below 4 - systemPrintf( - "Current LG290P firmware: v%d (full form: %s). Tilt compensation requires GST on firmware v4 " - "or newer. Please " - "update the " - "firmware on your LG290P to allow for these features. Please see " - "https://bit.ly/sfe-rtk-lg290p-update\r\n Marking tilt compensation offline.", - lg290pFirmwareVersion, gnssFirmwareVersion); - - present.imu_im19 = false; - } - } - } - return (response); -} - -//---------------------------------------- -// Turn on all the enabled RTCM Base messages -//---------------------------------------- -bool GNSS_LG290P::enableRTCMBase() -{ - bool response = true; - bool enableRTCM = false; // Goes true if we need to enable RTCM output reporting - - int portNumber = 1; - - while (portNumber < 4) - { - for (int messageNumber = 0; messageNumber < MAX_LG290P_RTCM_MSG; messageNumber++) - { - // Check if this RTCM message is supported by the current LG290P firmware - if (lg290pFirmwareVersion >= lgMessagesRTCM[messageNumber].firmwareVersionSupported) - { - // Setting RTCM-1005 must have only the rate - // Setting RTCM-107X must have rate and offset - if (strchr(lgMessagesRTCM[messageNumber].msgTextName, 'X') == nullptr) - { - // No X found. This is RTCM-1??? message. No offset. - - // If firmware is 4 or higher, use setMessageRateOnPort, otherwise setMessageRate - if (lg290pFirmwareVersion >= 4) - // Enable this message, at this rate, on this port - response &= _lg290p->setMessageRateOnPort(lgMessagesRTCM[messageNumber].msgTextName, - settings.lg290pMessageRatesRTCMBase[messageNumber], - portNumber); - else - // Enable this message, at this rate - response &= _lg290p->setMessageRate(lgMessagesRTCM[messageNumber].msgTextName, - settings.lg290pMessageRatesRTCMBase[messageNumber]); - - if (response == false && settings.debugGnss) - systemPrintf("Enable RTCM failed at messageNumber %d %s\r\n", messageNumber, - lgMessagesRTCM[messageNumber].msgTextName); - } - else - { - // X found. This is RTCM-1??X message. Assign 'offset' of 0 - - // If firmware is 4 or higher, use setMessageRateOnPort, otherwise setMessageRate - if (lg290pFirmwareVersion >= 4) - // Enable this message, at this rate, on this port - response &= _lg290p->setMessageRateOnPort(lgMessagesRTCM[messageNumber].msgTextName, - settings.lg290pMessageRatesRTCMBase[messageNumber], - portNumber, 0); - else - // Enable this message, at this rate - response &= _lg290p->setMessageRate(lgMessagesRTCM[messageNumber].msgTextName, - settings.lg290pMessageRatesRTCMBase[messageNumber], 0); - - if (response == false && settings.debugGnss) - systemPrintf("Enable RTCM failed at messageNumber %d %s\r\n", messageNumber, - lgMessagesRTCM[messageNumber].msgTextName); - } - - // If any message is enabled, enable RTCM output - if (settings.lg290pMessageRatesRTCMBase[messageNumber] > 0) - enableRTCM = true; - } - } - - portNumber++; - - // setMessageRateOnPort only supported on v4 and above - if (lg290pFirmwareVersion < 4) - break; // Don't step through portNumbers - } - - if (enableRTCM == true) - { - if (settings.debugGnss) - systemPrintln("Enabling Base RTCM output"); - - // PQTMCFGRTCM fails to respond with OK over UART2 of LG290P, so don't look for it - char cfgRtcm[40]; - snprintf(cfgRtcm, sizeof(cfgRtcm), "PQTMCFGRTCM,W,%c,0,-90,07,06,2,1", settings.useMSM7 ? '7' : '4'); - _lg290p->sendOkCommand(cfgRtcm); // Enable MSM4/7, output regular intervals, interval (seconds) - } - - return (response); -} - -//---------------------------------------- -// Turn on all the enabled RTCM Rover messages -//---------------------------------------- -bool GNSS_LG290P::enableRTCMRover() -{ - bool response = true; - bool rtcm1019Enabled = false; - bool rtcm1020Enabled = false; - bool rtcm1042Enabled = false; - bool rtcm1046Enabled = false; - bool enableRTCM = false; // Goes true if we need to enable RTCM output reporting - - int portNumber = 1; - - int minimumRtcmRate = 1000; - - while (portNumber < 4) - { - for (int messageNumber = 0; messageNumber < MAX_LG290P_RTCM_MSG; messageNumber++) - { - // 1019 to 1046 can only be set to 1 fix per report - // 107x to 112x can be set to 1-1200 fixes between reports - // So we set all RTCM to 1, and set PQTMCFGRTCM to the lowest value found - - // Capture the message with the lowest rate - if (settings.lg290pMessageRatesRTCMRover[messageNumber] > 0 && - settings.lg290pMessageRatesRTCMRover[messageNumber] < minimumRtcmRate) - minimumRtcmRate = settings.lg290pMessageRatesRTCMRover[messageNumber]; - - // Force all RTCM messages to 1 or 0. See above for reasoning. - int rate = settings.lg290pMessageRatesRTCMRover[messageNumber]; - if (rate > 1) - rate = 1; - - // Check if this RTCM message is supported by the current LG290P firmware - if (lg290pFirmwareVersion >= lgMessagesRTCM[messageNumber].firmwareVersionSupported) - { - // Setting RTCM-1005 must have only the rate - // Setting RTCM-107X must have rate and offset - if (strchr(lgMessagesRTCM[messageNumber].msgTextName, 'X') == nullptr) - { - // No X found. This is RTCM-1??? message. No offset. - - // If firmware is 4 or higher, use setMessageRateOnPort, otherwise setMessageRate - if (lg290pFirmwareVersion >= 4) - { - // If any one of the commands fails, report failure overall - response &= - _lg290p->setMessageRateOnPort(lgMessagesRTCM[messageNumber].msgTextName, rate, portNumber); - } - else - response &= _lg290p->setMessageRate(lgMessagesRTCM[messageNumber].msgTextName, rate); - - if (response == false && settings.debugGnss) - systemPrintf("Enable RTCM failed at messageNumber %d %s\r\n", messageNumber, - lgMessagesRTCM[messageNumber].msgTextName); - } - else - { - // X found. This is RTCM-1??X message. Assign 'offset' of 0 - - // The rate of these type of messages can be 1 to 1200, so we allow the full rate - - // If firmware is 4 or higher, use setMessageRateOnPort, otherwise setMessageRate - if (lg290pFirmwareVersion >= 4) - { - response &= _lg290p->setMessageRateOnPort(lgMessagesRTCM[messageNumber].msgTextName, - settings.lg290pMessageRatesRTCMRover[messageNumber], - portNumber, 0); - } - else - response &= _lg290p->setMessageRate(lgMessagesRTCM[messageNumber].msgTextName, - settings.lg290pMessageRatesRTCMRover[messageNumber], 0); - - if (response == false && settings.debugGnss) - systemPrintf("Enable RTCM failed at messageNumber %d %s\r\n", messageNumber, - lgMessagesRTCM[messageNumber].msgTextName); - } - - // If any message is enabled, enable RTCM output - if (settings.lg290pMessageRatesRTCMRover[messageNumber] > 0) - enableRTCM = true; - - // If we are using IP based corrections, we need to send local data to the PPL - // The PPL requires being fed GPGGA/ZDA, and RTCM1019/1020/1042/1046 - if (pointPerfectServiceUsesKeys()) - { - // Mark PPL required messages as enabled if rate > 0 - if (settings.lg290pMessageRatesRTCMRover[messageNumber] > 0) - { - if (strcmp(lgMessagesRTCM[messageNumber].msgTextName, "RTCM3-1019") == 0) - rtcm1019Enabled = true; - else if (strcmp(lgMessagesRTCM[messageNumber].msgTextName, "RTCM3-1020") == 0) - rtcm1020Enabled = true; - else if (strcmp(lgMessagesRTCM[messageNumber].msgTextName, "RTCM3-1042") == 0) - rtcm1042Enabled = true; - else if (strcmp(lgMessagesRTCM[messageNumber].msgTextName, "RTCM3-1046") == 0) - rtcm1046Enabled = true; - } - } - } - } - - portNumber++; - - // setMessageRateOnPort only supported on v4 and above - if (lg290pFirmwareVersion < 4) - break; // Don't step through portNumbers - } - - if (pointPerfectServiceUsesKeys()) - { - enableRTCM = true; // Force enable RTCM output - - // Force on any messages that are needed for PPL - if (rtcm1019Enabled == false) - { - if (settings.debugCorrections) - systemPrintln("PPL Enabling RTCM3-1019"); - response &= _lg290p->setMessageRate("RTCM3-1019", 1); - } - if (rtcm1020Enabled == false) - { - if (settings.debugCorrections) - systemPrintln("PPL Enabling RTCM3-1020"); - - response &= _lg290p->setMessageRate("RTCM3-1020", 1); - } - if (rtcm1042Enabled == false) - { - if (settings.debugCorrections) - systemPrintln("PPL Enabling RTCM3-1042"); - - response &= _lg290p->setMessageRate("RTCM3-1042", 1); - } - if (rtcm1046Enabled == false) - { - if (settings.debugCorrections) - systemPrintln("PPL Enabling RTCM3-1046"); - response &= _lg290p->setMessageRate("RTCM3-1046", 1); - } - } - - // If any RTCM message is enabled, send CFGRTCM - if (enableRTCM == true) - { - if (settings.debugCorrections) - systemPrintf("Enabling Rover RTCM MSM output with rate of %d\r\n", minimumRtcmRate); - - // Enable MSM4/7 (for faster PPP CSRS results), output at a rate equal to the minimum RTCM rate (EPH Mode = 2) - // PQTMCFGRTCM, W, , , , , , , - // Set MSM_ElevThd to 15 degrees from rftop suggestion - - char msmCommand[40] = {0}; - snprintf(msmCommand, sizeof(msmCommand), "PQTMCFGRTCM,W,%c,0,15,07,06,2,%d", settings.useMSM7 ? '7' : '4', - minimumRtcmRate); - - // PQTMCFGRTCM fails to respond with OK over UART2 of LG290P, so don't look for it - _lg290p->sendOkCommand(msmCommand); - } - - return (response); -} - //---------------------------------------- // Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted // even if there is no GPS fix. We use it to test serial output. @@ -1977,7 +1623,7 @@ void GNSS_LG290P::menuMessages() setRtcmRoverMessageRateByName("RTCM3-109X", rtcmReportRate); // setRtcmRoverMessageRateByName("RTCM3-112X", rtcmReportRate); //BeiDou not used by CSRS-PPP - // MSM7 is set during enableRTCMRover() + // MSM7 is set during setMessagesRTCMRover() // Override settings for PPP logging setElevation(15); @@ -2158,282 +1804,615 @@ void GNSS_LG290P::menuMessagesSubtype(int *localMessageRate, const char *message printUnknown(incoming); } - clearBuffer(); // Empty buffer of any newline chars + clearBuffer(); // Empty buffer of any newline chars +} + +//---------------------------------------- +// Print the module type and firmware version +//---------------------------------------- +void GNSS_LG290P::printModuleInfo() +{ + if (online.gnss) + { + std::string version, buildDate, buildTime; + if (_lg290p->getVersionInfo(version, buildDate, buildTime)) + { + systemPrintf("LG290P version: v%02d - %s %s %s - v%d\r\n", lg290pFirmwareVersion, version.c_str(), + buildDate.c_str(), buildTime.c_str()); + } + else + { + systemPrintln("Version info unavailable"); + } + } + else + { + systemPrintln("Version info unavailable"); + } +} + +//---------------------------------------- +// Send data directly from ESP GNSS UART1 to LG290P UART2 +// Returns the number of correction data bytes written +//---------------------------------------- +int GNSS_LG290P::pushRawData(uint8_t *dataToSend, int dataLength) +{ + if (online.gnss) + return (serialGNSS->write(dataToSend, dataLength)); + return (0); +} + +//---------------------------------------- +uint16_t GNSS_LG290P::rtcmBufferAvailable() +{ + // TODO return(lg290pRtcmBufferAvailable()); + return (0); +} + +//---------------------------------------- +// If LBand is being used, ignore any RTCM that may come in from the GNSS +//---------------------------------------- +void GNSS_LG290P::rtcmOnGnssDisable() +{ + // LG290P does not have a separate interface for RTCM +} + +//---------------------------------------- +// If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver +//---------------------------------------- +void GNSS_LG290P::rtcmOnGnssEnable() +{ + // LG290P does not have a separate interface for RTCM +} + +//---------------------------------------- +uint16_t GNSS_LG290P::rtcmRead(uint8_t *rtcmBuffer, int rtcmBytesToRead) +{ + // TODO return(lg290pRtcmRead(rtcmBuffer, rtcmBytesToRead)); + return (0); +} + +//---------------------------------------- +// Save the current configuration +// Returns true when the configuration was saved and false upon failure +//---------------------------------------- +bool GNSS_LG290P::saveConfiguration() +{ + if (online.gnss) + return (_lg290p->save()); + + return false; +} + +//---------------------------------------- +// Set the baud rate on the GNSS port that interfaces between the ESP32 and the GNSS +// This just sets the GNSS side +//---------------------------------------- +bool GNSS_LG290P::setBaudRateComm(uint32_t baud) +{ + if (online.gnss) + { + if (getCommBaudRate() == baud) + { + return (true); // Baud is set! + } + else + { + uint8_t commUart = 0; + if (productVariant == RTK_POSTCARD) + { + // UART2 of the LG290P is connected to the ESP32 for the main config/comm + commUart = 2; + } + else if (productVariant == RTK_FLEX) + { + // UART1 of the LG290P is connected to the ESP32 for the main config/comm + commUart = 1; + } + return (setBaudRate(commUart, baud)); + } + } + return (false); +} + +//---------------------------------------- +// Return the baud rate of the UART connected to the ESP32 UART1 +//---------------------------------------- +uint32_t GNSS_LG290P::getCommBaudRate() +{ + uint8_t commUart = 0; + if (productVariant == RTK_POSTCARD) + { + // On the Postcard, the ESP32 UART1 is connected to LG290P UART2 + commUart = 2; + } + else if (productVariant == RTK_FLEX) + { + // On the Flex, the ESP32 UART1 is connected to LG290P UART1 + commUart = 1; + } + return (getBaudRate(commUart)); +} + +//---------------------------------------- +// Enable all the valid constellations and bands for this platform +// Band support varies between platforms and firmware versions +//---------------------------------------- +bool GNSS_LG290P::setConstellations() +{ + bool response = true; + + if (online.gnss) + { + response = _lg290p->setConstellations(settings.lg290pConstellations[0], // GPS + settings.lg290pConstellations[1], // GLONASS + settings.lg290pConstellations[2], // Galileo + settings.lg290pConstellations[3], // BDS + settings.lg290pConstellations[4], // QZSS + settings.lg290pConstellations[5]); // NavIC + } + + return (response); +} + +// Enable / disable corrections protocol(s) on the Radio External port +// Always update if force is true. Otherwise, only update if enable has changed state +bool GNSS_LG290P::setCorrRadioExtPort(bool enable, bool force) +{ + if (online.gnss) + { + if (force || (enable != _corrRadioExtPortEnabled)) + { + // Set UART3 InputProt: RTCM3 (4) vs NMEA (1) + if (_lg290p->setPortInputProtocols(3, enable ? 4 : 1)) + { + if ((settings.debugCorrections == true) && !inMainMenu) + { + systemPrintf("Radio Ext corrections: %s -> %s%s\r\n", + _corrRadioExtPortEnabled ? "enabled" : "disabled", enable ? "enabled" : "disabled", + force ? " (Forced)" : ""); + } + + _corrRadioExtPortEnabled = enable; + return true; + } + else + { + systemPrintf("Radio Ext corrections FAILED: %s -> %s%s\r\n", + _corrRadioExtPortEnabled ? "enabled" : "disabled", enable ? "enabled" : "disabled", + force ? " (Forced)" : ""); + } + } + } + + return false; +} + +//---------------------------------------- +// Set the elevation in degrees +//---------------------------------------- +bool GNSS_LG290P::setElevation(uint8_t elevationDegrees) +{ + // Present on >= v05 + if (lg290pFirmwareVersion >= 5) + return (_lg290p->setElevationAngle(elevationDegrees)); + + // Because we call this during module setup we rely on a positive result + return true; } //---------------------------------------- -// Print the module type and firmware version +// Control whether HAS E6 is used in location fixes or not //---------------------------------------- -void GNSS_LG290P::printModuleInfo() +bool GNSS_LG290P::setHighAccuracyService(bool enableGalileoHas) { - if (online.gnss) + bool result = true; + + // E6 reception requires version v06 with 'PPP_TEMP' in firmware title + // Present is set during LG290P begin() + if (present.galileoHasCapable == false) + return (result); // We are unable to set this setting so report success + + // Enable E6 and PPP if enabled + if (enableGalileoHas) { - std::string version, buildDate, buildTime; - if (_lg290p->getVersionInfo(version, buildDate, buildTime)) + // $PQTMCFGPPP,W,2,1,120,0.10,0.15*68 + // Enable E6 HAS, WGS84, 120 timeout, 0.10m Horizontal convergence accuracy threshold, 0.15m Vertical threshold + if (_lg290p->sendOkCommand("$PQTMCFGPPP", ",W,2,1,120,0.10,0.15") == true) { - systemPrintf("LG290P version: v%02d - %s %s %s - v%d\r\n", lg290pFirmwareVersion, version.c_str(), - buildDate.c_str(), buildTime.c_str()); + systemPrintln("Galileo E6 HAS service enabled"); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM } else { - systemPrintln("Version info unavailable"); + systemPrintln("Galileo E6 HAS service failed to enable"); + result = false; } } else { - systemPrintln("Version info unavailable"); + // Turn off HAS/E6 + // $PQTMCFGPPP,W,0* + if (_lg290p->sendOkCommand("$PQTMCFGPPP", ",W,0") == true) + { + systemPrintln("Galileo E6 HAS service disabled"); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } + else + { + systemPrintln("Galileo E6 HAS service failed to disable"); + result = false; + } } + + return (result); } //---------------------------------------- -// Send data directly from ESP GNSS UART1 to LG290P UART2 -// Returns the number of correction data bytes written +// Set the minimum satellite signal level for navigation. //---------------------------------------- -int GNSS_LG290P::pushRawData(uint8_t *dataToSend, int dataLength) +bool GNSS_LG290P::setMinCno(uint8_t cnoValue) { - if (online.gnss) - return (serialGNSS->write(dataToSend, dataLength)); - return (0); -} + // Present on >= v05 + if (lg290pFirmwareVersion >= 5) + return (_lg290p->setCNR((float)cnoValue)); // 0.0 to 99.0 -//---------------------------------------- -uint16_t GNSS_LG290P::rtcmBufferAvailable() -{ - // TODO return(lg290pRtcmBufferAvailable()); - return (0); + // Because we call this during module setup we rely on a positive result + return true; } //---------------------------------------- -// If LBand is being used, ignore any RTCM that may come in from the GNSS +// Enable/disable NMEA messages according to the NMEA array //---------------------------------------- -void GNSS_LG290P::rtcmOnGnssDisable() +bool GNSS_LG290P::setMessagesNMEA() { - // LG290P does not have a separate interface for RTCM -} + bool response = true; + bool gpggaEnabled = false; -//---------------------------------------- -// If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver -//---------------------------------------- -void GNSS_LG290P::rtcmOnGnssEnable() -{ - // LG290P does not have a separate interface for RTCM -} + int portNumber = 1; -//---------------------------------------- -uint16_t GNSS_LG290P::rtcmRead(uint8_t *rtcmBuffer, int rtcmBytesToRead) -{ - // TODO return(lg290pRtcmRead(rtcmBuffer, rtcmBytesToRead)); - return (0); -} + while (portNumber < 4) + { + for (int messageNumber = 0; messageNumber < MAX_LG290P_NMEA_MSG; messageNumber++) + { + // Check if this NMEA message is supported by the current LG290P firmware + if (lg290pFirmwareVersion >= lgMessagesNMEA[messageNumber].firmwareVersionSupported) + { + // Disable NMEA output on UART3 RADIO + int msgRate = settings.lg290pMessageRatesNMEA[messageNumber]; + if ((portNumber == 3) && (settings.enableNmeaOnRadio == false)) + msgRate = 0; -//---------------------------------------- -// Save the current configuration -// Returns true when the configuration was saved and false upon failure -//---------------------------------------- -bool GNSS_LG290P::saveConfiguration() -{ - if (online.gnss) - return (_lg290p->save()); + // If firmware is 4 or higher, use setMessageRateOnPort, otherwise setMessageRate + if (lg290pFirmwareVersion >= 4) + // Enable this message, at this rate, on this port + response &= + _lg290p->setMessageRateOnPort(lgMessagesNMEA[messageNumber].msgTextName, msgRate, portNumber); + else + // Enable this message, at this rate + response &= _lg290p->setMessageRate(lgMessagesNMEA[messageNumber].msgTextName, msgRate); + if (response == false && settings.debugGnss) + systemPrintf("Enable NMEA failed at messageNumber %d %s.\r\n", messageNumber, + lgMessagesNMEA[messageNumber].msgTextName); - return false; -} + // If we are using IP based corrections, we need to send local data to the PPL + // The PPL requires being fed GPGGA/ZDA, and RTCM1019/1020/1042/1046 + if (pointPerfectServiceUsesKeys()) + { + // Mark PPL required messages as enabled if rate > 0 + if (settings.lg290pMessageRatesNMEA[messageNumber] > 0) + { + if (strcmp(lgMessagesNMEA[messageNumber].msgTextName, "GGA") == 0) + gpggaEnabled = true; + } + } + } + } -//---------------------------------------- -// Set the baud rate on the GNSS port that interfaces between the ESP32 and the GNSS -// This just sets the GNSS side -//---------------------------------------- -bool GNSS_LG290P::setBaudRateComm(uint32_t baud) -{ - if (online.gnss) + portNumber++; + + // setMessageRateOnPort only supported on v4 and above + if (lg290pFirmwareVersion < 4) + break; // Don't step through portNumbers + } + + if (pointPerfectServiceUsesKeys()) { - if (getCommBaudRate() == baud) + // Force on any messages that are needed for PPL + // If firmware is 4 or higher, use setMessageRateOnPort, otherwise setMessageRate + if (lg290pFirmwareVersion >= 4) { - return (true); // Baud is set! + // Enable GGA on UART 2 (connected to ESP32) only + if (gpggaEnabled == false) + response &= _lg290p->setMessageRateOnPort("GGA", 1, 2); } else { - uint8_t commUart = 0; - if (productVariant == RTK_POSTCARD) + // Enable GGA on all UARTs. It's the best we can do. + if (gpggaEnabled == false) + response &= _lg290p->setMessageRate("GGA", 1); + } + } + + // If this is Flex, we may need to enable NMEA for Tilt IMU + if (present.tiltPossible == true) + { + if (present.imu_im19 == true && settings.enableTiltCompensation == true) + { + // Regardless of user settings, enable GGA, RMC, GST on UART3 + // If firmware is 4 or higher, use setMessageRateOnPort, otherwise setMessageRate + if (lg290pFirmwareVersion >= 4) { - // UART2 of the LG290P is connected to the ESP32 for the main config/comm - commUart = 2; + // Enable GGA/RMS/GST on UART 3 (connected to the IMU) only + response &= _lg290p->setMessageRateOnPort("GGA", 1, 3); + response &= _lg290p->setMessageRateOnPort("RMC", 1, 3); + response &= _lg290p->setMessageRateOnPort("GST", 1, 3); } - else if (productVariant == RTK_FLEX) + else { - // UART1 of the LG290P is connected to the ESP32 for the main config/comm - commUart = 1; + // GST not supported below 4 + systemPrintf( + "Current LG290P firmware: v%d (full form: %s). Tilt compensation requires GST on firmware v4 " + "or newer. Please " + "update the " + "firmware on your LG290P to allow for these features. Please see " + "https://bit.ly/sfe-rtk-lg290p-update\r\n Marking tilt compensation offline.", + lg290pFirmwareVersion, gnssFirmwareVersion); + + present.imu_im19 = false; } - return (setBaudRate(commUart, baud)); } } - return (false); + return (response); } //---------------------------------------- -// Return the baud rate of the UART connected to the ESP32 UART1 +// Turn on all the enabled RTCM Base messages //---------------------------------------- -uint32_t GNSS_LG290P::getCommBaudRate() +bool GNSS_LG290P::setMessagesRTCMBase() { - uint8_t commUart = 0; - if (productVariant == RTK_POSTCARD) + bool response = true; + bool enableRTCM = false; // Goes true if we need to enable RTCM output reporting + + int portNumber = 1; + + while (portNumber < 4) { - // On the Postcard, the ESP32 UART1 is connected to LG290P UART2 - commUart = 2; + for (int messageNumber = 0; messageNumber < MAX_LG290P_RTCM_MSG; messageNumber++) + { + // Check if this RTCM message is supported by the current LG290P firmware + if (lg290pFirmwareVersion >= lgMessagesRTCM[messageNumber].firmwareVersionSupported) + { + // Setting RTCM-1005 must have only the rate + // Setting RTCM-107X must have rate and offset + if (strchr(lgMessagesRTCM[messageNumber].msgTextName, 'X') == nullptr) + { + // No X found. This is RTCM-1??? message. No offset. + + // If firmware is 4 or higher, use setMessageRateOnPort, otherwise setMessageRate + if (lg290pFirmwareVersion >= 4) + // Enable this message, at this rate, on this port + response &= _lg290p->setMessageRateOnPort(lgMessagesRTCM[messageNumber].msgTextName, + settings.lg290pMessageRatesRTCMBase[messageNumber], + portNumber); + else + // Enable this message, at this rate + response &= _lg290p->setMessageRate(lgMessagesRTCM[messageNumber].msgTextName, + settings.lg290pMessageRatesRTCMBase[messageNumber]); + + if (response == false && settings.debugGnss) + systemPrintf("Enable RTCM failed at messageNumber %d %s\r\n", messageNumber, + lgMessagesRTCM[messageNumber].msgTextName); + } + else + { + // X found. This is RTCM-1??X message. Assign 'offset' of 0 + + // If firmware is 4 or higher, use setMessageRateOnPort, otherwise setMessageRate + if (lg290pFirmwareVersion >= 4) + // Enable this message, at this rate, on this port + response &= _lg290p->setMessageRateOnPort(lgMessagesRTCM[messageNumber].msgTextName, + settings.lg290pMessageRatesRTCMBase[messageNumber], + portNumber, 0); + else + // Enable this message, at this rate + response &= _lg290p->setMessageRate(lgMessagesRTCM[messageNumber].msgTextName, + settings.lg290pMessageRatesRTCMBase[messageNumber], 0); + + if (response == false && settings.debugGnss) + systemPrintf("Enable RTCM failed at messageNumber %d %s\r\n", messageNumber, + lgMessagesRTCM[messageNumber].msgTextName); + } + + // If any message is enabled, enable RTCM output + if (settings.lg290pMessageRatesRTCMBase[messageNumber] > 0) + enableRTCM = true; + } + } + + portNumber++; + + // setMessageRateOnPort only supported on v4 and above + if (lg290pFirmwareVersion < 4) + break; // Don't step through portNumbers } - else if (productVariant == RTK_FLEX) + + if (enableRTCM == true) { - // On the Flex, the ESP32 UART1 is connected to LG290P UART1 - commUart = 1; + if (settings.debugGnss) + systemPrintln("Enabling Base RTCM output"); + + // PQTMCFGRTCM fails to respond with OK over UART2 of LG290P, so don't look for it + char cfgRtcm[40]; + snprintf(cfgRtcm, sizeof(cfgRtcm), "PQTMCFGRTCM,W,%c,0,-90,07,06,2,1", settings.useMSM7 ? '7' : '4'); + _lg290p->sendOkCommand(cfgRtcm); // Enable MSM4/7, output regular intervals, interval (seconds) } - return (getBaudRate(commUart)); + + return (response); } //---------------------------------------- -// Enable all the valid constellations and bands for this platform -// Band support varies between platforms and firmware versions +// Turn on all the enabled RTCM Rover messages //---------------------------------------- -bool GNSS_LG290P::setConstellations() +bool GNSS_LG290P::setMessagesRTCMRover() { bool response = true; + bool rtcm1019Enabled = false; + bool rtcm1020Enabled = false; + bool rtcm1042Enabled = false; + bool rtcm1046Enabled = false; + bool enableRTCM = false; // Goes true if we need to enable RTCM output reporting - if (online.gnss) - { - response = _lg290p->setConstellations(settings.lg290pConstellations[0], // GPS - settings.lg290pConstellations[1], // GLONASS - settings.lg290pConstellations[2], // Galileo - settings.lg290pConstellations[3], // BDS - settings.lg290pConstellations[4], // QZSS - settings.lg290pConstellations[5]); // NavIC - } + int portNumber = 1; - return (response); -} + int minimumRtcmRate = 1000; -// Enable / disable corrections protocol(s) on the Radio External port -// Always update if force is true. Otherwise, only update if enable has changed state -bool GNSS_LG290P::setCorrRadioExtPort(bool enable, bool force) -{ - if (online.gnss) + while (portNumber < 4) { - if (force || (enable != _corrRadioExtPortEnabled)) + for (int messageNumber = 0; messageNumber < MAX_LG290P_RTCM_MSG; messageNumber++) { - // Set UART3 InputProt: RTCM3 (4) vs NMEA (1) - if (_lg290p->setPortInputProtocols(3, enable ? 4 : 1)) + // 1019 to 1046 can only be set to 1 fix per report + // 107x to 112x can be set to 1-1200 fixes between reports + // So we set all RTCM to 1, and set PQTMCFGRTCM to the lowest value found + + // Capture the message with the lowest rate + if (settings.lg290pMessageRatesRTCMRover[messageNumber] > 0 && + settings.lg290pMessageRatesRTCMRover[messageNumber] < minimumRtcmRate) + minimumRtcmRate = settings.lg290pMessageRatesRTCMRover[messageNumber]; + + // Force all RTCM messages to 1 or 0. See above for reasoning. + int rate = settings.lg290pMessageRatesRTCMRover[messageNumber]; + if (rate > 1) + rate = 1; + + // Check if this RTCM message is supported by the current LG290P firmware + if (lg290pFirmwareVersion >= lgMessagesRTCM[messageNumber].firmwareVersionSupported) { - if ((settings.debugCorrections == true) && !inMainMenu) + // Setting RTCM-1005 must have only the rate + // Setting RTCM-107X must have rate and offset + if (strchr(lgMessagesRTCM[messageNumber].msgTextName, 'X') == nullptr) { - systemPrintf("Radio Ext corrections: %s -> %s%s\r\n", - _corrRadioExtPortEnabled ? "enabled" : "disabled", enable ? "enabled" : "disabled", - force ? " (Forced)" : ""); + // No X found. This is RTCM-1??? message. No offset. + + // If firmware is 4 or higher, use setMessageRateOnPort, otherwise setMessageRate + if (lg290pFirmwareVersion >= 4) + { + // If any one of the commands fails, report failure overall + response &= + _lg290p->setMessageRateOnPort(lgMessagesRTCM[messageNumber].msgTextName, rate, portNumber); + } + else + response &= _lg290p->setMessageRate(lgMessagesRTCM[messageNumber].msgTextName, rate); + + if (response == false && settings.debugGnss) + systemPrintf("Enable RTCM failed at messageNumber %d %s\r\n", messageNumber, + lgMessagesRTCM[messageNumber].msgTextName); } + else + { + // X found. This is RTCM-1??X message. Assign 'offset' of 0 - _corrRadioExtPortEnabled = enable; - return true; - } - else - { - systemPrintf("Radio Ext corrections FAILED: %s -> %s%s\r\n", - _corrRadioExtPortEnabled ? "enabled" : "disabled", enable ? "enabled" : "disabled", - force ? " (Forced)" : ""); - } - } - } + // The rate of these type of messages can be 1 to 1200, so we allow the full rate - return false; -} + // If firmware is 4 or higher, use setMessageRateOnPort, otherwise setMessageRate + if (lg290pFirmwareVersion >= 4) + { + response &= _lg290p->setMessageRateOnPort(lgMessagesRTCM[messageNumber].msgTextName, + settings.lg290pMessageRatesRTCMRover[messageNumber], + portNumber, 0); + } + else + response &= _lg290p->setMessageRate(lgMessagesRTCM[messageNumber].msgTextName, + settings.lg290pMessageRatesRTCMRover[messageNumber], 0); -//---------------------------------------- -// Set the elevation in degrees -//---------------------------------------- -bool GNSS_LG290P::setElevation(uint8_t elevationDegrees) -{ - // Present on >= v05 - if (lg290pFirmwareVersion >= 5) - return (_lg290p->setElevationAngle(elevationDegrees)); + if (response == false && settings.debugGnss) + systemPrintf("Enable RTCM failed at messageNumber %d %s\r\n", messageNumber, + lgMessagesRTCM[messageNumber].msgTextName); + } - // Because we call this during module setup we rely on a positive result - return true; -} + // If any message is enabled, enable RTCM output + if (settings.lg290pMessageRatesRTCMRover[messageNumber] > 0) + enableRTCM = true; -//---------------------------------------- -// Control whether HAS E6 is used in location fixes or not -//---------------------------------------- -bool GNSS_LG290P::setHighAccuracyService(bool enableGalileoHas) -{ - bool result = true; + // If we are using IP based corrections, we need to send local data to the PPL + // The PPL requires being fed GPGGA/ZDA, and RTCM1019/1020/1042/1046 + if (pointPerfectServiceUsesKeys()) + { + // Mark PPL required messages as enabled if rate > 0 + if (settings.lg290pMessageRatesRTCMRover[messageNumber] > 0) + { + if (strcmp(lgMessagesRTCM[messageNumber].msgTextName, "RTCM3-1019") == 0) + rtcm1019Enabled = true; + else if (strcmp(lgMessagesRTCM[messageNumber].msgTextName, "RTCM3-1020") == 0) + rtcm1020Enabled = true; + else if (strcmp(lgMessagesRTCM[messageNumber].msgTextName, "RTCM3-1042") == 0) + rtcm1042Enabled = true; + else if (strcmp(lgMessagesRTCM[messageNumber].msgTextName, "RTCM3-1046") == 0) + rtcm1046Enabled = true; + } + } + } + } - // E6 reception requires version v06 with 'PPP_TEMP' in firmware title - // Present is set during LG290P begin() - if (present.galileoHasCapable == false) - return (result); // We are unable to set this setting so report success + portNumber++; - // Enable E6 and PPP if enabled - if (enableGalileoHas) + // setMessageRateOnPort only supported on v4 and above + if (lg290pFirmwareVersion < 4) + break; // Don't step through portNumbers + } + + if (pointPerfectServiceUsesKeys()) { - // $PQTMCFGPPP,W,2,1,120,0.10,0.15*68 - // Enable E6 HAS, WGS84, 120 timeout, 0.10m Horizontal convergence accuracy threshold, 0.15m Vertical threshold - if (_lg290p->sendOkCommand("$PQTMCFGPPP", ",W,2,1,120,0.10,0.15") == true) + enableRTCM = true; // Force enable RTCM output + + // Force on any messages that are needed for PPL + if (rtcm1019Enabled == false) { - systemPrintln("Galileo E6 HAS service enabled"); - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + if (settings.debugCorrections) + systemPrintln("PPL Enabling RTCM3-1019"); + response &= _lg290p->setMessageRate("RTCM3-1019", 1); } - else + if (rtcm1020Enabled == false) { - systemPrintln("Galileo E6 HAS service failed to enable"); - result = false; + if (settings.debugCorrections) + systemPrintln("PPL Enabling RTCM3-1020"); + + response &= _lg290p->setMessageRate("RTCM3-1020", 1); } - } - else - { - // Turn off HAS/E6 - // $PQTMCFGPPP,W,0* - if (_lg290p->sendOkCommand("$PQTMCFGPPP", ",W,0") == true) + if (rtcm1042Enabled == false) { - systemPrintln("Galileo E6 HAS service disabled"); - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + if (settings.debugCorrections) + systemPrintln("PPL Enabling RTCM3-1042"); + + response &= _lg290p->setMessageRate("RTCM3-1042", 1); } - else + if (rtcm1046Enabled == false) { - systemPrintln("Galileo E6 HAS service failed to disable"); - result = false; + if (settings.debugCorrections) + systemPrintln("PPL Enabling RTCM3-1046"); + response &= _lg290p->setMessageRate("RTCM3-1046", 1); } } - return (result); -} + // If any RTCM message is enabled, send CFGRTCM + if (enableRTCM == true) + { + if (settings.debugCorrections) + systemPrintf("Enabling Rover RTCM MSM output with rate of %d\r\n", minimumRtcmRate); -//---------------------------------------- -// Enable all the valid messages for this platform -// There are many messages so split into batches. VALSET is limited to 64 max per batch -// Uses dummy newCfg and sendCfg values to be sure we open/close a complete set -//---------------------------------------- -bool GNSS_LG290P::setMessages(int maxRetries) -{ - // Not needed for LG290P - return (true); -} + // Enable MSM4/7 (for faster PPP CSRS results), output at a rate equal to the minimum RTCM rate (EPH Mode = 2) + // PQTMCFGRTCM, W, , , , , , , + // Set MSM_ElevThd to 15 degrees from rftop suggestion -//---------------------------------------- -// Enable all the valid messages for this platform over the USB port -// Add 2 to every UART1 key. This is brittle and non-perfect, but works. -//---------------------------------------- -bool GNSS_LG290P::setMessagesUsb(int maxRetries) -{ - // Not needed for LG290P - return (true); -} + char msmCommand[40] = {0}; + snprintf(msmCommand, sizeof(msmCommand), "PQTMCFGRTCM,W,%c,0,15,07,06,2,%d", settings.useMSM7 ? '7' : '4', + minimumRtcmRate); -//---------------------------------------- -// Set the minimum satellite signal level for navigation. -//---------------------------------------- -bool GNSS_LG290P::setMinCno(uint8_t cnoValue) -{ - // Present on >= v05 - if (lg290pFirmwareVersion >= 5) - return (_lg290p->setCNR((float)cnoValue)); // 0.0 to 99.0 + // PQTMCFGRTCM fails to respond with OK over UART2 of LG290P, so don't look for it + _lg290p->sendOkCommand(msmCommand); + } - // Because we call this during module setup we rely on a positive result - return true; + return (response); } //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.h b/Firmware/RTK_Everywhere/GNSS_Mosaic.h index a3420a93e..382ce69b9 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.h +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.h @@ -648,15 +648,6 @@ class GNSS_MOSAIC : GNSS void enableGgaForNtrip(); - // Turn on all the enabled NMEA messages on COM1 - bool enableNMEA(); - - // Turn on all the enabled RTCM Base messages on COM1, COM2 and USB1 (if enabled) - bool enableRTCMBase(); - - // Turn on all the enabled RTCM Rover messages on COM1, COM2 and USB1 (if enabled) - bool enableRTCMRover(); - // Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted // even if there is no GPS fix. We use it to test serial output. // Outputs: @@ -995,11 +986,14 @@ class GNSS_MOSAIC : GNSS // Enable or disable HAS E6 capability bool setHighAccuracyService(bool enableGalileoHas); - // Enable all the valid messages for this platform - bool setMessages(int maxRetries); + // Turn on all the enabled NMEA messages on COM1 + bool setMessagesNMEA(); - // Enable all the valid messages for this platform over the USB port - bool setMessagesUsb(int maxRetries); + // Turn on all the enabled RTCM Base messages on COM1, COM2 and USB1 (if enabled) + bool setMessagesRTCMBase(); + + // Turn on all the enabled RTCM Rover messages on COM1, COM2 and USB1 (if enabled) + bool setMessagesRTCMRover(); // Set the dynamic model to use for RTK // Inputs: diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino index 6950b83ab..918223ae1 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino @@ -152,7 +152,7 @@ void menuLogMosaic() GNSS_MOSAIC *mosaic = (GNSS_MOSAIC *)gnss; mosaic->configureLogging(); // This will enable / disable RINEX logging - mosaic->enableNMEA(); // Enable NMEA messages - this will enable/disable the DSK1 streams + mosaic->setMessagesNMEA(); // Enable NMEA messages - this will enable/disable the DSK1 streams mosaic->saveConfiguration(); // Save the configuration setLoggingType(); // Update Standard, PPP, or custom for icon selection } @@ -475,9 +475,9 @@ bool GNSS_MOSAIC::configureBase() response &= setConstellations(); - response &= enableRTCMBase(); + response &= setMessagesRTCMBase(); - response &= enableNMEA(); + response &= setMessagesNMEA(); response &= configureLogging(); @@ -602,7 +602,7 @@ bool GNSS_MOSAIC::configureOnce() Set Constellations NMEA Messages are enabled by enableNMEA - RTCMv3 messages are enabled by enableRTCMRover / enableRTCMBase + RTCMv3 messages are enabled by setMessagesRTCMRover / setMessagesRTCMBase */ if (settings.gnssConfiguredOnce) @@ -722,9 +722,9 @@ bool GNSS_MOSAIC::configureRover() response &= setConstellations(); - response &= enableRTCMRover(); + response &= setMessagesRTCMRover(); - response &= enableNMEA(); + response &= setMessagesNMEA(); response &= configureLogging(); @@ -809,409 +809,139 @@ void GNSS_MOSAIC::debuggingEnable() void GNSS_MOSAIC::enableGgaForNtrip() { // Set the talker ID to GP - // enableNMEA() will enable GGA if needed + // setMessagesNMEA() will enable GGA if needed sendWithResponse("snti,GP\n\r", "NMEATalkerID"); } //---------------------------------------- -// Turn on all the enabled NMEA messages on COM1 +// Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted +// even if there is no GPS fix. We use it to test serial output. +// Outputs: +// Returns true if successfully started and false upon failure //---------------------------------------- -bool GNSS_MOSAIC::enableNMEA() +bool GNSS_MOSAIC::enableRTCMTest() { - bool gpggaEnabled = false; - bool gpzdaEnabled = false; - bool gpgstEnabled = false; - - String streams[MOSAIC_NUM_NMEA_STREAMS]; // Build a string for each stream - for (int messageNumber = 0; messageNumber < MAX_MOSAIC_NMEA_MSG; messageNumber++) // For each NMEA message - { - int stream = settings.mosaicMessageStreamNMEA[messageNumber]; - if (stream > 0) - { - stream--; - - if (streams[stream].length() > 0) - streams[stream] += String("+"); - streams[stream] += String(mosaicMessagesNMEA[messageNumber].msgTextName); - - // If we are using IP based corrections, we need to send local data to the PPL - // The PPL requires being fed GPGGA/ZDA, and RTCM1019/1020/1042/1046 - if (strstr(settings.pointPerfectKeyDistributionTopic, "/ip") != nullptr) - { - // Mark PPL required messages as enabled if stream > 0 - if (strcmp(mosaicMessagesNMEA[messageNumber].msgTextName, "GGA") == 0) - gpggaEnabled = true; - if (strcmp(mosaicMessagesNMEA[messageNumber].msgTextName, "ZDA") == 0) - gpzdaEnabled = true; - } - - if (strcmp(mosaicMessagesNMEA[messageNumber].msgTextName, "GST") == 0) - gpgstEnabled = true; - } - } - - if (pointPerfectIsEnabled()) - { - // Force on any messages that are needed for PPL - if (gpggaEnabled == false) - { - // Add GGA to Stream1 (streams[0]) - // TODO: We may need to be cleverer about which stream we choose, - // depending on the stream intervals - if (streams[0].length() > 0) - streams[0] += String("+"); - streams[0] += String("GGA"); - gpggaEnabled = true; - } - if (gpzdaEnabled == false) - { - if (streams[0].length() > 0) - streams[0] += String("+"); - streams[0] += String("ZDA"); - gpzdaEnabled = true; - } - } + // Enable RTCM1230 on COM2 (Radio connector) + // Called by STATE_TEST. Mosaic could still be starting up, so allow many retries - if (settings.ntripClient_TransmitGGA == true) - { - // Force on GGA if needed for NTRIP - if (gpggaEnabled == false) - { - if (streams[0].length() > 0) - streams[0] += String("+"); - streams[0] += String("GGA"); - gpggaEnabled = true; - } - } + int retries = 0; + const int retryLimit = 20; - // Force GST on so we can extract the lat and lon standard deviations - if (gpgstEnabled == false) + // Add RTCMv3 output on COM2 + while (!sendWithResponse("sdio,COM2,,+RTCMv3\n\r", "DataInOut")) { - if (streams[0].length() > 0) - streams[0] += String("+"); - streams[0] += String("GST"); - gpgstEnabled = true; + if (retries == retryLimit) + break; + retries++; + sendWithResponse("SSSSSSSSSSSSSSSSSSSS\n\r", "COM"); // Send escape sequence } - bool response = true; + if (retries == retryLimit) + return false; - for (int stream = 0; stream < MOSAIC_NUM_NMEA_STREAMS; stream++) - { - if (streams[stream].length() == 0) - streams[stream] = String("none"); + bool success = true; + success &= sendWithResponse("sr3i,RTCM1230,1.0\n\r", "RTCMv3Interval"); // Set message interval to 1s + success &= sendWithResponse("sr3o,COM2,+RTCM1230\n\r", "RTCMv3Output"); // Add RTCMv3 1230 output - String setting = String("sno,Stream" + String(stream + 1) + ",COM1," + streams[stream] + "," + - String(mosaicMsgRates[settings.mosaicStreamIntervalsNMEA[stream]].name) + "\n\r"); - response &= sendWithResponse(setting, "NMEAOutput"); + return success; +} - if (settings.enableNmeaOnRadio) - setting = String("sno,Stream" + String(stream + MOSAIC_NUM_NMEA_STREAMS + 1) + ",COM2," + streams[stream] + - "," + String(mosaicMsgRates[settings.mosaicStreamIntervalsNMEA[stream]].name) + "\n\r"); - else - setting = String("sno,Stream" + String(stream + MOSAIC_NUM_NMEA_STREAMS + 1) + ",COM2,none,off\n\r"); - response &= sendWithResponse(setting, "NMEAOutput"); +//---------------------------------------- +// Restore the GNSS to the factory settings +//---------------------------------------- +void GNSS_MOSAIC::factoryReset() +{ + unsigned long start = millis(); + bool result = sendWithResponse("eccf,RxDefault,Boot\n\r", "CopyConfigFile", 5000); + if (settings.debugGnss) + systemPrintf("factoryReset: sendWithResponse eccf,RxDefault,Boot returned %s after %d ms\r\n", + result ? "true" : "false", millis() - start); - if (settings.enableGnssToUsbSerial) - { - setting = - String("sno,Stream" + String(stream + (2 * MOSAIC_NUM_NMEA_STREAMS) + 1) + ",USB1," + streams[stream] + - "," + String(mosaicMsgRates[settings.mosaicStreamIntervalsNMEA[stream]].name) + "\n\r"); - response &= sendWithResponse(setting, "NMEAOutput"); - } - else - { - // Disable the USB1 NMEA streams if settings.enableGnssToUsbSerial is not enabled - setting = String("sno,Stream" + String(stream + (2 * MOSAIC_NUM_NMEA_STREAMS) + 1) + ",USB1,none,off\n\r"); - response &= sendWithResponse(setting, "NMEAOutput"); - } + start = millis(); + result = sendWithResponse("eccf,RxDefault,Current\n\r", "CopyConfigFile", 5000); + if (settings.debugGnss) + systemPrintf("factoryReset: sendWithResponse eccf,RxDefault,Current returned %s after %d ms\r\n", + result ? "true" : "false", millis() - start); +} - if (settings.enableLogging) - { - setting = - String("sno,Stream" + String(stream + (3 * MOSAIC_NUM_NMEA_STREAMS) + 1) + ",DSK1," + streams[stream] + - "," + String(mosaicMsgRates[settings.mosaicStreamIntervalsNMEA[stream]].name) + "\n\r"); - response &= sendWithResponse(setting, "NMEAOutput"); - } - else - { - // Disable the DSK1 NMEA streams if settings.enableLogging is not enabled - setting = String("sno,Stream" + String(stream + (3 * MOSAIC_NUM_NMEA_STREAMS) + 1) + ",DSK1,none,off\n\r"); - response &= sendWithResponse(setting, "NMEAOutput"); - } - } +//---------------------------------------- +uint16_t GNSS_MOSAIC::fileBufferAvailable() +{ + // TODO + return 0; +} - return (response); +//---------------------------------------- +uint16_t GNSS_MOSAIC::fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead) +{ + // TODO + return 0; } //---------------------------------------- -// Turn on all the enabled RTCM Base messages on COM1, COM2 and USB1 (if enabled) +// Start the base using fixed coordinates +// Outputs: +// Returns true if successfully started and false upon failure //---------------------------------------- -bool GNSS_MOSAIC::enableRTCMBase() +bool GNSS_MOSAIC::fixedBaseStart() { bool response = true; - // Set RTCMv3 Intervals - for (int group = 0; group < MAX_MOSAIC_RTCM_V3_INTERVAL_GROUPS; group++) + // TODO: support alternate Datums (ETRS89, NAD83, NAD83_PA, NAD83_MA, GDA94, GDA2020) + if (settings.fixedBaseCoordinateType == COORD_TYPE_ECEF) { - char flt[10]; - snprintf(flt, sizeof(flt), "%.1f", settings.mosaicMessageIntervalsRTCMv3Base[group]); - String setting = - String("sr3i," + String(mosaicRTCMv3MsgIntervalGroups[group].name) + "," + String(flt) + "\n\r"); - response &= sendWithResponse(setting, "RTCMv3Interval"); + char pos[100]; + snprintf(pos, sizeof(pos), "sspc,Cartesian1,%.4f,%.4f,%.4f,WGS84\n\r", settings.fixedEcefX, settings.fixedEcefY, + settings.fixedEcefZ); + response &= sendWithResponse(pos, "StaticPosCartesian"); + response &= sendWithResponse("spm,Static,,Cartesian1\n\r", "PVTMode"); } - - // Enable RTCMv3 - String messages = String(""); - for (int message = 0; message < MAX_MOSAIC_RTCM_V3_MSG; message++) + else if (settings.fixedBaseCoordinateType == COORD_TYPE_GEODETIC) { - if (settings.mosaicMessageEnabledRTCMv3Base[message]) - { - if (messages.length() > 0) - messages += String("+"); - messages += String(mosaicMessagesRTCMv3[message].name); - } + // Add height of instrument (HI) to fixed altitude + // https://www.e-education.psu.edu/geog862/node/1853 + // For example, if HAE is at 100.0m, + 2m stick + 73mm APC = 102.073 + float totalFixedAltitude = + settings.fixedAltitude + ((settings.antennaHeight_mm + settings.antennaPhaseCenter_mm) / 1000.0); + char pos[100]; + snprintf(pos, sizeof(pos), "sspg,Geodetic1,%.8f,%.8f,%.4f,WGS84\n\r", settings.fixedLat, settings.fixedLong, + totalFixedAltitude); + response &= sendWithResponse(pos, "StaticPosGeodetic"); + response &= sendWithResponse("spm,Static,,Geodetic1\n\r", "PVTMode"); } - if (messages.length() == 0) - messages = String("none"); - - String setting = String("sr3o,COM1+COM2"); - if (settings.enableGnssToUsbSerial) - setting += String("+USB1"); - setting += String("," + messages + "\n\r"); - response &= sendWithResponse(setting, "RTCMv3Output"); - - if (!settings.enableGnssToUsbSerial) + if (response == false) { - response &= sendWithResponse("sr3o,USB1,none\n\r", "RTCMv3Output"); + systemPrintln("Fixed base start failed"); } return (response); } //---------------------------------------- -// Turn on all the enabled RTCM Rover messages on COM1, COM2 and USB1 (if enabled) +// Return the number of active/enabled messages //---------------------------------------- -bool GNSS_MOSAIC::enableRTCMRover() +uint8_t GNSS_MOSAIC::getActiveMessageCount() { - bool response = true; - bool rtcm1019Enabled = false; - bool rtcm1020Enabled = false; - bool rtcm1042Enabled = false; - bool rtcm1046Enabled = false; + uint8_t count = 0; - // Set RTCMv3 Intervals - for (int group = 0; group < MAX_MOSAIC_RTCM_V3_INTERVAL_GROUPS; group++) + for (int x = 0; x < MAX_MOSAIC_NMEA_MSG; x++) + if (settings.mosaicMessageStreamNMEA[x] > 0) + count++; + + // Determine which state we are in + if (inRoverMode() == true) { - char flt[10]; - snprintf(flt, sizeof(flt), "%.1f", settings.mosaicMessageIntervalsRTCMv3Rover[group]); - String setting = - String("sr3i," + String(mosaicRTCMv3MsgIntervalGroups[group].name) + "," + String(flt) + "\n\r"); - response &= sendWithResponse(setting, "RTCMv3Interval"); + for (int x = 0; x < MAX_MOSAIC_RTCM_V3_MSG; x++) + if (settings.mosaicMessageEnabledRTCMv3Rover[x] > 0) + count++; } - - // Enable RTCMv3 - String messages = String(""); - for (int message = 0; message < MAX_MOSAIC_RTCM_V3_MSG; message++) + else { - if (settings.mosaicMessageEnabledRTCMv3Rover[message]) - { - if (messages.length() > 0) - messages += String("+"); - messages += String(mosaicMessagesRTCMv3[message].name); - - // If we are using IP based corrections, we need to send local data to the PPL - // The PPL requires being fed GPGGA/ZDA, and RTCM1019/1020/1042/1046 - if (pointPerfectIsEnabled()) - { - // Mark PPL required messages as enabled if rate > 0 - if (strcmp(mosaicMessagesRTCMv3[message].name, "RTCM1019") == 0) - rtcm1019Enabled = true; - if (strcmp(mosaicMessagesRTCMv3[message].name, "RTCM1020") == 0) - rtcm1020Enabled = true; - if (strcmp(mosaicMessagesRTCMv3[message].name, "RTCM1042") == 0) - rtcm1042Enabled = true; - if (strcmp(mosaicMessagesRTCMv3[message].name, "RTCM1046") == 0) - rtcm1046Enabled = true; - } - } - } - - if (pointPerfectIsEnabled()) - { - // Force on any messages that are needed for PPL - if (rtcm1019Enabled == false) - { - if (messages.length() > 0) - messages += String("+"); - messages += String("RTCM1019"); - } - if (rtcm1020Enabled == false) - { - if (messages.length() > 0) - messages += String("+"); - messages += String("RTCM1020"); - } - if (rtcm1042Enabled == false) - { - if (messages.length() > 0) - messages += String("+"); - messages += String("RTCM1042"); - } - if (rtcm1046Enabled == false) - { - if (messages.length() > 0) - messages += String("+"); - messages += String("RTCM1046"); - } - } - - if (messages.length() == 0) - messages = String("none"); - - String setting = String("sr3o,COM1+COM2"); - if (settings.enableGnssToUsbSerial) - setting += String("+USB1"); - setting += String("," + messages + "\n\r"); - response &= sendWithResponse(setting, "RTCMv3Output"); - - if (!settings.enableGnssToUsbSerial) - { - response &= sendWithResponse("sr3o,USB1,none\n\r", "RTCMv3Output"); - } - - return (response); -} - -//---------------------------------------- -// Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted -// even if there is no GPS fix. We use it to test serial output. -// Outputs: -// Returns true if successfully started and false upon failure -//---------------------------------------- -bool GNSS_MOSAIC::enableRTCMTest() -{ - // Enable RTCM1230 on COM2 (Radio connector) - // Called by STATE_TEST. Mosaic could still be starting up, so allow many retries - - int retries = 0; - const int retryLimit = 20; - - // Add RTCMv3 output on COM2 - while (!sendWithResponse("sdio,COM2,,+RTCMv3\n\r", "DataInOut")) - { - if (retries == retryLimit) - break; - retries++; - sendWithResponse("SSSSSSSSSSSSSSSSSSSS\n\r", "COM"); // Send escape sequence - } - - if (retries == retryLimit) - return false; - - bool success = true; - success &= sendWithResponse("sr3i,RTCM1230,1.0\n\r", "RTCMv3Interval"); // Set message interval to 1s - success &= sendWithResponse("sr3o,COM2,+RTCM1230\n\r", "RTCMv3Output"); // Add RTCMv3 1230 output - - return success; -} - -//---------------------------------------- -// Restore the GNSS to the factory settings -//---------------------------------------- -void GNSS_MOSAIC::factoryReset() -{ - unsigned long start = millis(); - bool result = sendWithResponse("eccf,RxDefault,Boot\n\r", "CopyConfigFile", 5000); - if (settings.debugGnss) - systemPrintf("factoryReset: sendWithResponse eccf,RxDefault,Boot returned %s after %d ms\r\n", - result ? "true" : "false", millis() - start); - - start = millis(); - result = sendWithResponse("eccf,RxDefault,Current\n\r", "CopyConfigFile", 5000); - if (settings.debugGnss) - systemPrintf("factoryReset: sendWithResponse eccf,RxDefault,Current returned %s after %d ms\r\n", - result ? "true" : "false", millis() - start); -} - -//---------------------------------------- -uint16_t GNSS_MOSAIC::fileBufferAvailable() -{ - // TODO - return 0; -} - -//---------------------------------------- -uint16_t GNSS_MOSAIC::fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead) -{ - // TODO - return 0; -} - -//---------------------------------------- -// Start the base using fixed coordinates -// Outputs: -// Returns true if successfully started and false upon failure -//---------------------------------------- -bool GNSS_MOSAIC::fixedBaseStart() -{ - bool response = true; - - // TODO: support alternate Datums (ETRS89, NAD83, NAD83_PA, NAD83_MA, GDA94, GDA2020) - if (settings.fixedBaseCoordinateType == COORD_TYPE_ECEF) - { - char pos[100]; - snprintf(pos, sizeof(pos), "sspc,Cartesian1,%.4f,%.4f,%.4f,WGS84\n\r", settings.fixedEcefX, settings.fixedEcefY, - settings.fixedEcefZ); - response &= sendWithResponse(pos, "StaticPosCartesian"); - response &= sendWithResponse("spm,Static,,Cartesian1\n\r", "PVTMode"); - } - else if (settings.fixedBaseCoordinateType == COORD_TYPE_GEODETIC) - { - // Add height of instrument (HI) to fixed altitude - // https://www.e-education.psu.edu/geog862/node/1853 - // For example, if HAE is at 100.0m, + 2m stick + 73mm APC = 102.073 - float totalFixedAltitude = - settings.fixedAltitude + ((settings.antennaHeight_mm + settings.antennaPhaseCenter_mm) / 1000.0); - char pos[100]; - snprintf(pos, sizeof(pos), "sspg,Geodetic1,%.8f,%.8f,%.4f,WGS84\n\r", settings.fixedLat, settings.fixedLong, - totalFixedAltitude); - response &= sendWithResponse(pos, "StaticPosGeodetic"); - response &= sendWithResponse("spm,Static,,Geodetic1\n\r", "PVTMode"); - } - - if (response == false) - { - systemPrintln("Fixed base start failed"); - } - - return (response); -} - -//---------------------------------------- -// Return the number of active/enabled messages -//---------------------------------------- -uint8_t GNSS_MOSAIC::getActiveMessageCount() -{ - uint8_t count = 0; - - for (int x = 0; x < MAX_MOSAIC_NMEA_MSG; x++) - if (settings.mosaicMessageStreamNMEA[x] > 0) - count++; - - // Determine which state we are in - if (inRoverMode() == true) - { - for (int x = 0; x < MAX_MOSAIC_RTCM_V3_MSG; x++) - if (settings.mosaicMessageEnabledRTCMv3Rover[x] > 0) - count++; - } - else - { - for (int x = 0; x < MAX_MOSAIC_RTCM_V3_MSG; x++) - if (settings.mosaicMessageEnabledRTCMv3Base[x] > 0) - count++; - } + for (int x = 0; x < MAX_MOSAIC_RTCM_V3_MSG; x++) + if (settings.mosaicMessageEnabledRTCMv3Base[x] > 0) + count++; + } return (count); } @@ -2462,33 +2192,285 @@ bool GNSS_MOSAIC::setHighAccuracyService(bool enableGalileoHas) } //---------------------------------------- -// Enable all the valid messages for this platform +// Set the minimum satellite signal level for navigation. //---------------------------------------- -bool GNSS_MOSAIC::setMessages(int maxRetries) +bool GNSS_MOSAIC::setMinCno(uint8_t cnoValue) { - // TODO : do we need this? - return true; + if (cnoValue > 60) + cnoValue = 60; + String cn0 = String(cnoValue); + String setting = String("scm,all," + cn0 + "\n\r"); + return (sendWithResponse(setting, "CN0Mask", 1000, 200)); } //---------------------------------------- -// Enable all the valid messages for this platform over the USB port +// Turn on all the enabled NMEA messages on COM1 //---------------------------------------- -bool GNSS_MOSAIC::setMessagesUsb(int maxRetries) +bool GNSS_MOSAIC::setMessagesNMEA() { - // TODO : do we need this? - return true; + bool gpggaEnabled = false; + bool gpzdaEnabled = false; + bool gpgstEnabled = false; + + String streams[MOSAIC_NUM_NMEA_STREAMS]; // Build a string for each stream + for (int messageNumber = 0; messageNumber < MAX_MOSAIC_NMEA_MSG; messageNumber++) // For each NMEA message + { + int stream = settings.mosaicMessageStreamNMEA[messageNumber]; + if (stream > 0) + { + stream--; + + if (streams[stream].length() > 0) + streams[stream] += String("+"); + streams[stream] += String(mosaicMessagesNMEA[messageNumber].msgTextName); + + // If we are using IP based corrections, we need to send local data to the PPL + // The PPL requires being fed GPGGA/ZDA, and RTCM1019/1020/1042/1046 + if (strstr(settings.pointPerfectKeyDistributionTopic, "/ip") != nullptr) + { + // Mark PPL required messages as enabled if stream > 0 + if (strcmp(mosaicMessagesNMEA[messageNumber].msgTextName, "GGA") == 0) + gpggaEnabled = true; + if (strcmp(mosaicMessagesNMEA[messageNumber].msgTextName, "ZDA") == 0) + gpzdaEnabled = true; + } + + if (strcmp(mosaicMessagesNMEA[messageNumber].msgTextName, "GST") == 0) + gpgstEnabled = true; + } + } + + if (pointPerfectIsEnabled()) + { + // Force on any messages that are needed for PPL + if (gpggaEnabled == false) + { + // Add GGA to Stream1 (streams[0]) + // TODO: We may need to be cleverer about which stream we choose, + // depending on the stream intervals + if (streams[0].length() > 0) + streams[0] += String("+"); + streams[0] += String("GGA"); + gpggaEnabled = true; + } + if (gpzdaEnabled == false) + { + if (streams[0].length() > 0) + streams[0] += String("+"); + streams[0] += String("ZDA"); + gpzdaEnabled = true; + } + } + + if (settings.ntripClient_TransmitGGA == true) + { + // Force on GGA if needed for NTRIP + if (gpggaEnabled == false) + { + if (streams[0].length() > 0) + streams[0] += String("+"); + streams[0] += String("GGA"); + gpggaEnabled = true; + } + } + + // Force GST on so we can extract the lat and lon standard deviations + if (gpgstEnabled == false) + { + if (streams[0].length() > 0) + streams[0] += String("+"); + streams[0] += String("GST"); + gpgstEnabled = true; + } + + bool response = true; + + for (int stream = 0; stream < MOSAIC_NUM_NMEA_STREAMS; stream++) + { + if (streams[stream].length() == 0) + streams[stream] = String("none"); + + String setting = String("sno,Stream" + String(stream + 1) + ",COM1," + streams[stream] + "," + + String(mosaicMsgRates[settings.mosaicStreamIntervalsNMEA[stream]].name) + "\n\r"); + response &= sendWithResponse(setting, "NMEAOutput"); + + if (settings.enableNmeaOnRadio) + setting = String("sno,Stream" + String(stream + MOSAIC_NUM_NMEA_STREAMS + 1) + ",COM2," + streams[stream] + + "," + String(mosaicMsgRates[settings.mosaicStreamIntervalsNMEA[stream]].name) + "\n\r"); + else + setting = String("sno,Stream" + String(stream + MOSAIC_NUM_NMEA_STREAMS + 1) + ",COM2,none,off\n\r"); + response &= sendWithResponse(setting, "NMEAOutput"); + + if (settings.enableGnssToUsbSerial) + { + setting = + String("sno,Stream" + String(stream + (2 * MOSAIC_NUM_NMEA_STREAMS) + 1) + ",USB1," + streams[stream] + + "," + String(mosaicMsgRates[settings.mosaicStreamIntervalsNMEA[stream]].name) + "\n\r"); + response &= sendWithResponse(setting, "NMEAOutput"); + } + else + { + // Disable the USB1 NMEA streams if settings.enableGnssToUsbSerial is not enabled + setting = String("sno,Stream" + String(stream + (2 * MOSAIC_NUM_NMEA_STREAMS) + 1) + ",USB1,none,off\n\r"); + response &= sendWithResponse(setting, "NMEAOutput"); + } + + if (settings.enableLogging) + { + setting = + String("sno,Stream" + String(stream + (3 * MOSAIC_NUM_NMEA_STREAMS) + 1) + ",DSK1," + streams[stream] + + "," + String(mosaicMsgRates[settings.mosaicStreamIntervalsNMEA[stream]].name) + "\n\r"); + response &= sendWithResponse(setting, "NMEAOutput"); + } + else + { + // Disable the DSK1 NMEA streams if settings.enableLogging is not enabled + setting = String("sno,Stream" + String(stream + (3 * MOSAIC_NUM_NMEA_STREAMS) + 1) + ",DSK1,none,off\n\r"); + response &= sendWithResponse(setting, "NMEAOutput"); + } + } + + return (response); } //---------------------------------------- -// Set the minimum satellite signal level for navigation. +// Turn on all the enabled RTCM Base messages on COM1, COM2 and USB1 (if enabled) //---------------------------------------- -bool GNSS_MOSAIC::setMinCno(uint8_t cnoValue) +bool GNSS_MOSAIC::setMessagesRTCMBase() { - if (cnoValue > 60) - cnoValue = 60; - String cn0 = String(cnoValue); - String setting = String("scm,all," + cn0 + "\n\r"); - return (sendWithResponse(setting, "CN0Mask", 1000, 200)); + bool response = true; + + // Set RTCMv3 Intervals + for (int group = 0; group < MAX_MOSAIC_RTCM_V3_INTERVAL_GROUPS; group++) + { + char flt[10]; + snprintf(flt, sizeof(flt), "%.1f", settings.mosaicMessageIntervalsRTCMv3Base[group]); + String setting = + String("sr3i," + String(mosaicRTCMv3MsgIntervalGroups[group].name) + "," + String(flt) + "\n\r"); + response &= sendWithResponse(setting, "RTCMv3Interval"); + } + + // Enable RTCMv3 + String messages = String(""); + for (int message = 0; message < MAX_MOSAIC_RTCM_V3_MSG; message++) + { + if (settings.mosaicMessageEnabledRTCMv3Base[message]) + { + if (messages.length() > 0) + messages += String("+"); + messages += String(mosaicMessagesRTCMv3[message].name); + } + } + + if (messages.length() == 0) + messages = String("none"); + + String setting = String("sr3o,COM1+COM2"); + if (settings.enableGnssToUsbSerial) + setting += String("+USB1"); + setting += String("," + messages + "\n\r"); + response &= sendWithResponse(setting, "RTCMv3Output"); + + if (!settings.enableGnssToUsbSerial) + { + response &= sendWithResponse("sr3o,USB1,none\n\r", "RTCMv3Output"); + } + + return (response); +} + +//---------------------------------------- +// Turn on all the enabled RTCM Rover messages on COM1, COM2 and USB1 (if enabled) +//---------------------------------------- +bool GNSS_MOSAIC::setMessagesRTCMRover() +{ + bool response = true; + bool rtcm1019Enabled = false; + bool rtcm1020Enabled = false; + bool rtcm1042Enabled = false; + bool rtcm1046Enabled = false; + + // Set RTCMv3 Intervals + for (int group = 0; group < MAX_MOSAIC_RTCM_V3_INTERVAL_GROUPS; group++) + { + char flt[10]; + snprintf(flt, sizeof(flt), "%.1f", settings.mosaicMessageIntervalsRTCMv3Rover[group]); + String setting = + String("sr3i," + String(mosaicRTCMv3MsgIntervalGroups[group].name) + "," + String(flt) + "\n\r"); + response &= sendWithResponse(setting, "RTCMv3Interval"); + } + + // Enable RTCMv3 + String messages = String(""); + for (int message = 0; message < MAX_MOSAIC_RTCM_V3_MSG; message++) + { + if (settings.mosaicMessageEnabledRTCMv3Rover[message]) + { + if (messages.length() > 0) + messages += String("+"); + messages += String(mosaicMessagesRTCMv3[message].name); + + // If we are using IP based corrections, we need to send local data to the PPL + // The PPL requires being fed GPGGA/ZDA, and RTCM1019/1020/1042/1046 + if (pointPerfectIsEnabled()) + { + // Mark PPL required messages as enabled if rate > 0 + if (strcmp(mosaicMessagesRTCMv3[message].name, "RTCM1019") == 0) + rtcm1019Enabled = true; + if (strcmp(mosaicMessagesRTCMv3[message].name, "RTCM1020") == 0) + rtcm1020Enabled = true; + if (strcmp(mosaicMessagesRTCMv3[message].name, "RTCM1042") == 0) + rtcm1042Enabled = true; + if (strcmp(mosaicMessagesRTCMv3[message].name, "RTCM1046") == 0) + rtcm1046Enabled = true; + } + } + } + + if (pointPerfectIsEnabled()) + { + // Force on any messages that are needed for PPL + if (rtcm1019Enabled == false) + { + if (messages.length() > 0) + messages += String("+"); + messages += String("RTCM1019"); + } + if (rtcm1020Enabled == false) + { + if (messages.length() > 0) + messages += String("+"); + messages += String("RTCM1020"); + } + if (rtcm1042Enabled == false) + { + if (messages.length() > 0) + messages += String("+"); + messages += String("RTCM1042"); + } + if (rtcm1046Enabled == false) + { + if (messages.length() > 0) + messages += String("+"); + messages += String("RTCM1046"); + } + } + + if (messages.length() == 0) + messages = String("none"); + + String setting = String("sr3o,COM1+COM2"); + if (settings.enableGnssToUsbSerial) + setting += String("+USB1"); + setting += String("," + messages + "\n\r"); + response &= sendWithResponse(setting, "RTCMv3Output"); + + if (!settings.enableGnssToUsbSerial) + { + response &= sendWithResponse("sr3o,USB1,none\n\r", "RTCMv3Output"); + } + + return (response); } //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/GNSS_None.h b/Firmware/RTK_Everywhere/GNSS_None.h index bb81a8b56..c45eb2aee 100644 --- a/Firmware/RTK_Everywhere/GNSS_None.h +++ b/Firmware/RTK_Everywhere/GNSS_None.h @@ -9,7 +9,7 @@ GNSS_None.h class GNSS_None : public GNSS { - protected: +protected: // Setup the general configuration of the GNSS // Not Rover or Base specific (ie, baud rates) // Outputs: @@ -25,7 +25,7 @@ class GNSS_None : public GNSS return false; } - public: +public: // Constructor GNSS_None() : GNSS() { @@ -566,14 +566,20 @@ class GNSS_None : public GNSS return true; } - // Enable all the valid messages for this platform - bool setMessages(int maxRetries) + // Configure NMEA messages + bool setMessagesNMEA() { return true; } - // Enable all the valid messages for this platform over the USB port - bool setMessagesUsb(int maxRetries) + // Configure RTCM Base messages + bool setMessagesRTCMBase() + { + return true; + } + + // Configure RTCM Base messages + bool setMessagesRTCMRover() { return true; } diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.h b/Firmware/RTK_Everywhere/GNSS_UM980.h index 03708d8ee..7aa31ecf8 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.h +++ b/Firmware/RTK_Everywhere/GNSS_UM980.h @@ -25,15 +25,19 @@ GNSS_UM980.h // Each constellation will have its config command text, enable, and a visible name typedef struct { - char textName[30]; - char textCommand[5]; + char textName[30]; + char textCommand[5]; } um980ConstellationCommand; // Constellations monitored/used for fix // Available constellations: GPS, BDS, GLO, GAL, QZSS // SBAS and IRNSS don't seem to be supported const um980ConstellationCommand um980ConstellationCommands[] = { - {"BeiDou", "BDS"}, {"Galileo", "GAL"}, {"GLONASS", "GLO"}, {"GPS", "GPS"}, {"QZSS", "QZSS"}, + {"BeiDou", "BDS"}, + {"Galileo", "GAL"}, + {"GLONASS", "GLO"}, + {"GPS", "GPS"}, + {"QZSS", "QZSS"}, }; #define MAX_UM980_CONSTELLATIONS (sizeof(um980ConstellationCommands) / sizeof(um980ConstellationCommand)) @@ -42,51 +46,100 @@ const um980ConstellationCommand um980ConstellationCommands[] = { // Each message will have the serial command and its default value typedef struct { - const char msgTextName[9]; - const float msgDefaultRate; + const char msgTextName[9]; + const float msgDefaultRate; } um980Msg; // Static array containing all the compatible messages // Rate = Reports per second const um980Msg umMessagesNMEA[] = { // NMEA - {"GPDTM", 0}, {"GPGBS", 0}, {"GPGGA", 0.5}, {"GPGLL", 0}, {"GPGNS", 0}, - - {"GPGRS", 0}, {"GPGSA", 0.5}, {"GPGST", 0.5}, {"GPGSV", 1}, {"GPRMC", 0.5}, - - {"GPROT", 0}, {"GPTHS", 0}, {"GPVTG", 0}, {"GPZDA", 0}, + {"GPDTM", 0}, + {"GPGBS", 0}, + {"GPGGA", 0.5}, + {"GPGLL", 0}, + {"GPGNS", 0}, + + {"GPGRS", 0}, + {"GPGSA", 0.5}, + {"GPGST", 0.5}, + {"GPGSV", 1}, + {"GPRMC", 0.5}, + + {"GPROT", 0}, + {"GPTHS", 0}, + {"GPVTG", 0}, + {"GPZDA", 0}, }; const um980Msg umMessagesRTCM[] = { // RTCM - {"RTCM1001", 0}, {"RTCM1002", 0}, {"RTCM1003", 0}, {"RTCM1004", 0}, {"RTCM1005", 1}, - {"RTCM1006", 0}, {"RTCM1007", 0}, {"RTCM1009", 0}, {"RTCM1010", 0}, - - {"RTCM1011", 0}, {"RTCM1012", 0}, {"RTCM1013", 0}, {"RTCM1019", 0}, + {"RTCM1001", 0}, + {"RTCM1002", 0}, + {"RTCM1003", 0}, + {"RTCM1004", 0}, + {"RTCM1005", 1}, + {"RTCM1006", 0}, + {"RTCM1007", 0}, + {"RTCM1009", 0}, + {"RTCM1010", 0}, + + {"RTCM1011", 0}, + {"RTCM1012", 0}, + {"RTCM1013", 0}, + {"RTCM1019", 0}, {"RTCM1020", 0}, {"RTCM1033", 10}, - {"RTCM1042", 0}, {"RTCM1044", 0}, {"RTCM1045", 0}, {"RTCM1046", 0}, - - {"RTCM1071", 0}, {"RTCM1072", 0}, {"RTCM1073", 0}, {"RTCM1074", 1}, {"RTCM1075", 0}, - {"RTCM1076", 0}, {"RTCM1077", 0}, - - {"RTCM1081", 0}, {"RTCM1082", 0}, {"RTCM1083", 0}, {"RTCM1084", 1}, {"RTCM1085", 0}, - {"RTCM1086", 0}, {"RTCM1087", 0}, - - {"RTCM1091", 0}, {"RTCM1092", 0}, {"RTCM1093", 0}, {"RTCM1094", 1}, {"RTCM1095", 0}, - {"RTCM1096", 0}, {"RTCM1097", 0}, + {"RTCM1042", 0}, + {"RTCM1044", 0}, + {"RTCM1045", 0}, + {"RTCM1046", 0}, + + {"RTCM1071", 0}, + {"RTCM1072", 0}, + {"RTCM1073", 0}, + {"RTCM1074", 1}, + {"RTCM1075", 0}, + {"RTCM1076", 0}, + {"RTCM1077", 0}, + + {"RTCM1081", 0}, + {"RTCM1082", 0}, + {"RTCM1083", 0}, + {"RTCM1084", 1}, + {"RTCM1085", 0}, + {"RTCM1086", 0}, + {"RTCM1087", 0}, + + {"RTCM1091", 0}, + {"RTCM1092", 0}, + {"RTCM1093", 0}, + {"RTCM1094", 1}, + {"RTCM1095", 0}, + {"RTCM1096", 0}, + {"RTCM1097", 0}, {"RTCM1104", 0}, - {"RTCM1111", 0}, {"RTCM1112", 0}, {"RTCM1113", 0}, {"RTCM1114", 0}, {"RTCM1115", 0}, - {"RTCM1116", 0}, {"RTCM1117", 0}, - - {"RTCM1121", 0}, {"RTCM1122", 0}, {"RTCM1123", 0}, {"RTCM1124", 1}, {"RTCM1125", 0}, - {"RTCM1126", 0}, {"RTCM1127", 0}, + {"RTCM1111", 0}, + {"RTCM1112", 0}, + {"RTCM1113", 0}, + {"RTCM1114", 0}, + {"RTCM1115", 0}, + {"RTCM1116", 0}, + {"RTCM1117", 0}, + + {"RTCM1121", 0}, + {"RTCM1122", 0}, + {"RTCM1123", 0}, + {"RTCM1124", 1}, + {"RTCM1125", 0}, + {"RTCM1126", 0}, + {"RTCM1127", 0}, }; #define MAX_UM980_NMEA_MSG (sizeof(umMessagesNMEA) / sizeof(um980Msg)) @@ -94,412 +147,406 @@ const um980Msg umMessagesRTCM[] = { enum um980_Models { - UM980_DYN_MODEL_SURVEY = 0, - UM980_DYN_MODEL_UAV, - UM980_DYN_MODEL_AUTOMOTIVE, + UM980_DYN_MODEL_SURVEY = 0, + UM980_DYN_MODEL_UAV, + UM980_DYN_MODEL_AUTOMOTIVE, }; class GNSS_UM980 : GNSS { - private: - UM980 *_um980; // Library class instance - - protected: - bool configureOnce(); - - // Setup the general configuration of the GNSS - // Not Rover or Base specific (ie, baud rates) - // Outputs: - // Returns true if successfully configured and false upon failure - bool configureGNSS(); +private: + UM980 *_um980; // Library class instance - // Turn off all NMEA and RTCM - void disableAllOutput(); +protected: + bool configureOnce(); - // Disable all output, then re-enable - void disableRTCM(); + // Setup the general configuration of the GNSS + // Not Rover or Base specific (ie, baud rates) + // Outputs: + // Returns true if successfully configured and false upon failure + bool configureGNSS(); - // Turn on all the enabled NMEA messages on COM3 - bool enableNMEA(); + // Turn off all NMEA and RTCM + void disableAllOutput(); - // Turn on all the enabled RTCM Rover messages on COM3 - bool enableRTCMRover(); + // Disable all output, then re-enable + void disableRTCM(); - // Turn on all the enabled RTCM Base messages on COM3 - bool enableRTCMBase(); + uint8_t getActiveNmeaMessageCount(); - uint8_t getActiveNmeaMessageCount(); + // Given the name of an NMEA message, return the array number + uint8_t getNmeaMessageNumberByName(const char *msgName); - // Given the name of an NMEA message, return the array number - uint8_t getNmeaMessageNumberByName(const char *msgName); + // Given the name of an RTCM message, return the array number + uint8_t getRtcmMessageNumberByName(const char *msgName); - // Given the name of an RTCM message, return the array number - uint8_t getRtcmMessageNumberByName(const char *msgName); + // Return true if the GPGGA message is active + bool isGgaActive(); - // Return true if the GPGGA message is active - bool isGgaActive(); + // Given a sub type (ie "RTCM", "NMEA") present menu showing messages with this subtype + // Controls the messages that get broadcast over Bluetooth and logged (if enabled) + void menuMessagesSubtype(float *localMessageRate, const char *messageType); - // Given a sub type (ie "RTCM", "NMEA") present menu showing messages with this subtype - // Controls the messages that get broadcast over Bluetooth and logged (if enabled) - void menuMessagesSubtype(float *localMessageRate, const char *messageType); + bool setHighAccuracyService(bool enableGalileoHas); - bool setHighAccuracyService(bool enableGalileoHas); + // Set the minimum satellite signal level for navigation. + bool setMinCno(uint8_t cnoValue); - // Set the minimum satellite signal level for navigation. - bool setMinCno(uint8_t cnoValue); +public: + // Constructor + GNSS_UM980() : GNSS() + { + } - public: - // Constructor - GNSS_UM980() : GNSS() - { - } + // If we have decryption keys, configure module + // Note: don't check online.lband_neo here. We could be using ip corrections + void applyPointPerfectKeys(); - // If we have decryption keys, configure module - // Note: don't check online.lband_neo here. We could be using ip corrections - void applyPointPerfectKeys(); + // Set RTCM for base mode to defaults (1005/1074/1084/1094/1124 1Hz & 1230 0.1Hz) + void baseRtcmDefault(); - // Set RTCM for base mode to defaults (1005/1074/1084/1094/1124 1Hz & 1230 0.1Hz) - void baseRtcmDefault(); + // Reset to Low Bandwidth Link (1074/1084/1094/1124 0.5Hz & 1005/1230 0.1Hz) + void baseRtcmLowDataRate(); - // Reset to Low Bandwidth Link (1074/1084/1094/1124 0.5Hz & 1005/1230 0.1Hz) - void baseRtcmLowDataRate(); + // Check if a given baud rate is supported by this module + bool baudIsAllowed(uint32_t baudRate); + uint32_t baudGetMinimum(); + uint32_t baudGetMaximum(); - // Check if a given baud rate is supported by this module - bool baudIsAllowed(uint32_t baudRate); - uint32_t baudGetMinimum(); - uint32_t baudGetMaximum(); + // Connect to GNSS and identify particulars + void begin(); - // Connect to GNSS and identify particulars - void begin(); + // Setup TM2 time stamp input as need + // Outputs: + // Returns true when an external event occurs and false if no event + bool beginExternalEvent(); - // Setup TM2 time stamp input as need - // Outputs: - // Returns true when an external event occurs and false if no event - bool beginExternalEvent(); + bool checkNMEARates(); - bool checkNMEARates(); + bool checkPPPRates(); - bool checkPPPRates(); + // Configure the Base + // Outputs: + // Returns true if successfully configured and false upon failure + bool configureBase(); - // Configure the Base - // Outputs: - // Returns true if successfully configured and false upon failure - bool configureBase(); + // Configure specific aspects of the receiver for NTP mode + bool configureNtpMode(); - // Configure specific aspects of the receiver for NTP mode - bool configureNtpMode(); + // Configure the Rover + // Outputs: + // Returns true if successfully configured and false upon failure + bool configureRover(); - // Configure the Rover - // Outputs: - // Returns true if successfully configured and false upon failure - bool configureRover(); + // Responds with the messages supported on this platform + // Inputs: + // returnText: String to receive message names + // Returns message names in the returnText string + void createMessageList(String &returnText); - // Responds with the messages supported on this platform - // Inputs: - // returnText: String to receive message names - // Returns message names in the returnText string - void createMessageList(String &returnText); + // Responds with the RTCM/Base messages supported on this platform + // Inputs: + // returnText: String to receive message names + // Returns message names in the returnText string + void createMessageListBase(String &returnText); - // Responds with the RTCM/Base messages supported on this platform - // Inputs: - // returnText: String to receive message names - // Returns message names in the returnText string - void createMessageListBase(String &returnText); + void debuggingDisable(); - void debuggingDisable(); + void debuggingEnable(); - void debuggingEnable(); + void enableGgaForNtrip(); - void enableGgaForNtrip(); + // Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted + // even if there is no GPS fix. We use it to test serial output. + // Outputs: + // Returns true if successfully started and false upon failure + bool enableRTCMTest(); - // Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted - // even if there is no GPS fix. We use it to test serial output. - // Outputs: - // Returns true if successfully started and false upon failure - bool enableRTCMTest(); + // Restore the GNSS to the factory settings + void factoryReset(); - // Restore the GNSS to the factory settings - void factoryReset(); + uint16_t fileBufferAvailable(); - uint16_t fileBufferAvailable(); + uint16_t fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead); - uint16_t fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead); + // Start the base using fixed coordinates + // Outputs: + // Returns true if successfully started and false upon failure + bool fixedBaseStart(); - // Start the base using fixed coordinates - // Outputs: - // Returns true if successfully started and false upon failure - bool fixedBaseStart(); + // Return the number of active/enabled messages + uint8_t getActiveMessageCount(); - // Return the number of active/enabled messages - uint8_t getActiveMessageCount(); + // Return the number of active/enabled RTCM messages + uint8_t getActiveRtcmMessageCount(); - // Return the number of active/enabled RTCM messages - uint8_t getActiveRtcmMessageCount(); + // Get the altitude + // Outputs: + // Returns the altitude in meters or zero if the GNSS is offline + double getAltitude(); - // Get the altitude - // Outputs: - // Returns the altitude in meters or zero if the GNSS is offline - double getAltitude(); + // Returns the carrier solution or zero if not online + uint8_t getCarrierSolution(); - // Returns the carrier solution or zero if not online - uint8_t getCarrierSolution(); + uint32_t getDataBaudRate(); - uint32_t getDataBaudRate(); + // Returns the day number or zero if not online + uint8_t getDay(); - // Returns the day number or zero if not online - uint8_t getDay(); + // Return the number of milliseconds since GNSS data was last updated + uint16_t getFixAgeMilliseconds(); - // Return the number of milliseconds since GNSS data was last updated - uint16_t getFixAgeMilliseconds(); + // Returns the fix type or zero if not online + uint8_t getFixType(); - // Returns the fix type or zero if not online - uint8_t getFixType(); + // Returns the hours of 24 hour clock or zero if not online + uint8_t getHour(); - // Returns the hours of 24 hour clock or zero if not online - uint8_t getHour(); + // Get the horizontal position accuracy + // Outputs: + // Returns the horizontal position accuracy or zero if offline + float getHorizontalAccuracy(); - // Get the horizontal position accuracy - // Outputs: - // Returns the horizontal position accuracy or zero if offline - float getHorizontalAccuracy(); + const char *getId(); - const char *getId(); + // Get the latitude value + // Outputs: + // Returns the latitude value or zero if not online + double getLatitude(); - // Get the latitude value - // Outputs: - // Returns the latitude value or zero if not online - double getLatitude(); + // Query GNSS for current leap seconds + uint8_t getLeapSeconds(); - // Query GNSS for current leap seconds - uint8_t getLeapSeconds(); + // Return the type of logging that matches the enabled messages - drives the logging icon + uint8_t getLoggingType(); - // Return the type of logging that matches the enabled messages - drives the logging icon - uint8_t getLoggingType(); + // Get the longitude value + // Outputs: + // Returns the longitude value or zero if not online + double getLongitude(); - // Get the longitude value - // Outputs: - // Returns the longitude value or zero if not online - double getLongitude(); + // Returns two digits of milliseconds or zero if not online + uint8_t getMillisecond(); - // Returns two digits of milliseconds or zero if not online - uint8_t getMillisecond(); + // Get the minimum satellite signal level for navigation. + uint8_t getMinCno(); - // Get the minimum satellite signal level for navigation. - uint8_t getMinCno(); + // Returns minutes or zero if not online + uint8_t getMinute(); - // Returns minutes or zero if not online - uint8_t getMinute(); + // Returns month number or zero if not online + uint8_t getMonth(); - // Returns month number or zero if not online - uint8_t getMonth(); + // Returns nanoseconds or zero if not online + uint32_t getNanosecond(); - // Returns nanoseconds or zero if not online - uint32_t getNanosecond(); + uint32_t getRadioBaudRate(); - uint32_t getRadioBaudRate(); + // Returns the seconds between solutions + double getRateS(); - // Returns the seconds between solutions - double getRateS(); + const char *getRtcmDefaultString(); - const char *getRtcmDefaultString(); + const char *getRtcmLowDataRateString(); - const char *getRtcmLowDataRateString(); + // Returns the number of satellites in view or zero if offline + uint8_t getSatellitesInView(); - // Returns the number of satellites in view or zero if offline - uint8_t getSatellitesInView(); + // Returns seconds or zero if not online + uint8_t getSecond(); - // Returns seconds or zero if not online - uint8_t getSecond(); + // Get the survey-in mean accuracy + // Outputs: + // Returns the mean accuracy or zero (0) + float getSurveyInMeanAccuracy(); - // Get the survey-in mean accuracy - // Outputs: - // Returns the mean accuracy or zero (0) - float getSurveyInMeanAccuracy(); + // Return the number of seconds the survey-in process has been running + int getSurveyInObservationTime(); - // Return the number of seconds the survey-in process has been running - int getSurveyInObservationTime(); + float getSurveyInStartingAccuracy(); - float getSurveyInStartingAccuracy(); + // Returns timing accuracy or zero if not online + uint32_t getTimeAccuracy(); - // Returns timing accuracy or zero if not online - uint32_t getTimeAccuracy(); + // Returns full year, ie 2023, not 23. + uint16_t getYear(); - // Returns full year, ie 2023, not 23. - uint16_t getYear(); + // Returns true if the device is in Rover mode + // Currently the only two modes are Rover or Base + bool inRoverMode(); - // Returns true if the device is in Rover mode - // Currently the only two modes are Rover or Base - bool inRoverMode(); + bool isBlocking(); - bool isBlocking(); + // Date is confirmed once we have GNSS fix + bool isConfirmedDate(); - // Date is confirmed once we have GNSS fix - bool isConfirmedDate(); + // Date is confirmed once we have GNSS fix + bool isConfirmedTime(); - // Date is confirmed once we have GNSS fix - bool isConfirmedTime(); + // Returns true if data is arriving on the Radio Ext port + bool isCorrRadioExtPortActive() + { + return false; + } - // Returns true if data is arriving on the Radio Ext port - bool isCorrRadioExtPortActive() - { - return false; - } + // Return true if GNSS receiver has a higher quality DGPS fix than 3D + bool isDgpsFixed(); - // Return true if GNSS receiver has a higher quality DGPS fix than 3D - bool isDgpsFixed(); + // Some functions (L-Band area frequency determination) merely need + // to know if we have a valid fix, not what type of fix + // This function checks to see if the given platform has reached + // sufficient fix type to be considered valid + bool isFixed(); - // Some functions (L-Band area frequency determination) merely need - // to know if we have a valid fix, not what type of fix - // This function checks to see if the given platform has reached - // sufficient fix type to be considered valid - bool isFixed(); + // Used in tpISR() for time pulse synchronization + bool isFullyResolved(); - // Used in tpISR() for time pulse synchronization - bool isFullyResolved(); + bool isPppConverged(); - bool isPppConverged(); + bool isPppConverging(); - bool isPppConverging(); + // Some functions (L-Band area frequency determination) merely need + // to know if we have an RTK Fix. This function checks to see if the + // given platform has reached sufficient fix type to be considered valid + bool isRTKFix(); - // Some functions (L-Band area frequency determination) merely need - // to know if we have an RTK Fix. This function checks to see if the - // given platform has reached sufficient fix type to be considered valid - bool isRTKFix(); + // Some functions (L-Band area frequency determination) merely need + // to know if we have an RTK Float. This function checks to see if + // the given platform has reached sufficient fix type to be considered + // valid + bool isRTKFloat(); - // Some functions (L-Band area frequency determination) merely need - // to know if we have an RTK Float. This function checks to see if - // the given platform has reached sufficient fix type to be considered - // valid - bool isRTKFloat(); + // Determine if the survey-in operation is complete + // Outputs: + // Returns true if the survey-in operation is complete and false + // if the operation is still running + bool isSurveyInComplete(); - // Determine if the survey-in operation is complete - // Outputs: - // Returns true if the survey-in operation is complete and false - // if the operation is still running - bool isSurveyInComplete(); + // Date will be valid if the RTC is reporting (regardless of GNSS fix) + bool isValidDate(); - // Date will be valid if the RTC is reporting (regardless of GNSS fix) - bool isValidDate(); + // Time will be valid if the RTC is reporting (regardless of GNSS fix) + bool isValidTime(); - // Time will be valid if the RTC is reporting (regardless of GNSS fix) - bool isValidTime(); + // Controls the constellations that are used to generate a fix and logged + void menuConstellations(); - // Controls the constellations that are used to generate a fix and logged - void menuConstellations(); + void menuMessageBaseRtcm(); - void menuMessageBaseRtcm(); + // Control the messages that get broadcast over Bluetooth and logged (if enabled) + void menuMessages(); - // Control the messages that get broadcast over Bluetooth and logged (if enabled) - void menuMessages(); + // Print the module type and firmware version + void printModuleInfo(); - // Print the module type and firmware version - void printModuleInfo(); + // Send correction data to the GNSS + // Inputs: + // dataToSend: Address of a buffer containing the data + // dataLength: The number of valid data bytes in the buffer + // Outputs: + // Returns the number of correction data bytes written + int pushRawData(uint8_t *dataToSend, int dataLength); - // Send correction data to the GNSS - // Inputs: - // dataToSend: Address of a buffer containing the data - // dataLength: The number of valid data bytes in the buffer - // Outputs: - // Returns the number of correction data bytes written - int pushRawData(uint8_t *dataToSend, int dataLength); + uint16_t rtcmBufferAvailable(); - uint16_t rtcmBufferAvailable(); + // If LBand is being used, ignore any RTCM that may come in from the GNSS + void rtcmOnGnssDisable(); - // If LBand is being used, ignore any RTCM that may come in from the GNSS - void rtcmOnGnssDisable(); + // If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver + void rtcmOnGnssEnable(); - // If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver - void rtcmOnGnssEnable(); + uint16_t rtcmRead(uint8_t *rtcmBuffer, int rtcmBytesToRead); - uint16_t rtcmRead(uint8_t *rtcmBuffer, int rtcmBytesToRead); + // Save the current configuration + // Outputs: + // Returns true when the configuration was saved and false upon failure + bool saveConfiguration(); - // Save the current configuration - // Outputs: - // Returns true when the configuration was saved and false upon failure - bool saveConfiguration(); + bool setBaudRate(uint8_t uartNumber, uint32_t baudRate); // From the super class - bool setBaudRate(uint8_t uartNumber, uint32_t baudRate); // From the super class + // Set the baud rate on the GNSS port that interfaces between the ESP32 and the GNSS + // Inputs: + // baudRate: The desired baudrate + bool setBaudRateComm(uint32_t baudRate); - // Set the baud rate on the GNSS port that interfaces between the ESP32 and the GNSS - // Inputs: - // baudRate: The desired baudrate - bool setBaudRateComm(uint32_t baudRate); + bool setBaudRateData(uint32_t baudRate); - bool setBaudRateData(uint32_t baudRate); + bool setBaudRateRadio(uint32_t baudRate); - bool setBaudRateRadio(uint32_t baudRate); + // Enable all the valid constellations and bands for this platform + bool setConstellations(); - // Enable all the valid constellations and bands for this platform - bool setConstellations(); + // Enable / disable corrections protocol(s) on the Radio External port + bool setCorrRadioExtPort(bool enable, bool force) + { + return true; + } - // Enable / disable corrections protocol(s) on the Radio External port - bool setCorrRadioExtPort(bool enable, bool force) - { - return true; - } + // Set the elevation in degrees + // Inputs: + // elevationDegrees: The elevation value in degrees + bool setElevation(uint8_t elevationDegrees); - // Set the elevation in degrees - // Inputs: - // elevationDegrees: The elevation value in degrees - bool setElevation(uint8_t elevationDegrees); + // Turn on all the enabled NMEA messages on COM3 + bool setMessagesNMEA(); - // Enable all the valid messages for this platform - bool setMessages(int maxRetries); + // Turn on all the enabled RTCM Rover messages on COM3 + bool setMessagesRTCMRover(); - // Enable all the valid messages for this platform over the USB port - bool setMessagesUsb(int maxRetries); + // Turn on all the enabled RTCM Base messages on COM3 + bool setMessagesRTCMBase(); - // Set the dynamic model to use for RTK - // Inputs: - // modelNumber: Number of the model to use, provided by radio library - bool setModel(uint8_t modelNumber); + // Set the dynamic model to use for RTK + // Inputs: + // modelNumber: Number of the model to use, provided by radio library + bool setModel(uint8_t modelNumber); - bool setMultipathMitigation(bool enableMultipathMitigation); + bool setMultipathMitigation(bool enableMultipathMitigation); - // Given the name of a message, find it, and set the rate - bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); + // Given the name of a message, find it, and set the rate + bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); - // Configure the Pulse-per-second pin based on user settings - bool setPPS(); + // Configure the Pulse-per-second pin based on user settings + bool setPPS(); - // Set all RTCM Rover message report rates to one value - void setRtcmRoverMessageRates(uint8_t msgRate); + // Set all RTCM Rover message report rates to one value + void setRtcmRoverMessageRates(uint8_t msgRate); - // Given the name of a message, find it, and set the rate - bool setRtcmRoverMessageRateByName(const char *msgName, uint8_t msgRate); + // Given the name of a message, find it, and set the rate + bool setRtcmRoverMessageRateByName(const char *msgName, uint8_t msgRate); - // Specify the interval between solutions - // Inputs: - // secondsBetweenSolutions: Number of seconds between solutions - // Outputs: - // Returns true if the rate was successfully set and false upon - // failure - bool setRate(double secondsBetweenSolutions); + // Specify the interval between solutions + // Inputs: + // secondsBetweenSolutions: Number of seconds between solutions + // Outputs: + // Returns true if the rate was successfully set and false upon + // failure + bool setRate(double secondsBetweenSolutions); - bool setTalkerGNGGA(); + bool setTalkerGNGGA(); - // Hotstart GNSS to try to get RTK lock - bool softwareReset(); + // Hotstart GNSS to try to get RTK lock + bool softwareReset(); - bool standby(); + bool standby(); - // Reset the survey-in operation - // Outputs: - // Returns true if the survey-in operation was reset successfully - // and false upon failure - bool surveyInReset(); + // Reset the survey-in operation + // Outputs: + // Returns true if the survey-in operation was reset successfully + // and false upon failure + bool surveyInReset(); - // Start the survey-in operation - // Outputs: - // Return true if successful and false upon failure - bool surveyInStart(); + // Start the survey-in operation + // Outputs: + // Return true if successful and false upon failure + bool surveyInStart(); - // If we have received serial data from the UM980 outside of the Unicore library (ie, from processUart1Message task) - // we can pass data back into the Unicore library to allow it to update its own variables - void unicoreHandler(uint8_t *buffer, int length); + // If we have received serial data from the UM980 outside of the Unicore library (ie, from processUart1Message task) + // we can pass data back into the Unicore library to allow it to update its own variables + void unicoreHandler(uint8_t *buffer, int length); - // Poll routine to update the GNSS state - void update(); + // Poll routine to update the GNSS state + void update(); }; #endif // COMPILE_UM980 diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index c43d8677b..c22e97b95 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -201,11 +201,13 @@ bool GNSS_UM980::configureBase() gnssConfigure(GNSS_CONFIG_MULTIPATH); gnssConfigure(GNSS_CONFIG_HAS_E6); - response &= enableRTCMBase(); // Only turn on messages, do not turn off messages. We assume the caller has - // UNLOG or similar. + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); // Only turn on messages, do not turn off messages. We assume the caller has UNLOG or similar. - response &= enableNMEA(); + response &= setMessagesRTCMBase(); + + // Only turn on messages, do not turn off messages. We assume the caller has UNLOG or similar. + response &= setMessagesNMEA(); // Save the current configuration into non-volatile memory (NVM) response &= _um980->saveConfiguration(); @@ -386,11 +388,11 @@ bool GNSS_UM980::configureRover() // interface port during config. // Only turn on messages, do not turn off messages. We assume the caller has UNLOG or similar. - response &= enableRTCMRover(); + response &= setMessagesRTCMRover(); // TODO consider reducing the GSV sentence to 1/4 of the GPGGA setting // Only turn on messages, do not turn off messages. We assume the caller has UNLOG or similar. - response &= enableNMEA(); + response &= setMessagesNMEA(); // Save the current configuration into non-volatile memory (NVM) response &= _um980->saveConfiguration(); @@ -485,7 +487,7 @@ void GNSS_UM980::disableAllOutput() void GNSS_UM980::disableRTCM() { disableAllOutput(); - enableNMEA(); + setMessagesNMEA(); } //---------------------------------------- @@ -494,151 +496,6 @@ void GNSS_UM980::enableGgaForNtrip() // TODO um980EnableGgaForNtrip(); } -//---------------------------------------- -// Turn on all the enabled NMEA messages on COM3 -//---------------------------------------- -bool GNSS_UM980::enableNMEA() -{ - bool response = true; - bool gpggaEnabled = false; - bool gpzdaEnabled = false; - - for (int messageNumber = 0; messageNumber < MAX_UM980_NMEA_MSG; messageNumber++) - { - // Only turn on messages, do not turn off messages set to 0. This saves on command sending. We assume the caller - // has UNLOG or similar. - if (settings.um980MessageRatesNMEA[messageNumber] > 0) - { - // If any one of the commands fails, report failure overall - response &= _um980->setNMEAPortMessage(umMessagesNMEA[messageNumber].msgTextName, "COM3", - settings.um980MessageRatesNMEA[messageNumber]); - - if (response == false && settings.debugGnss) - systemPrintf("Enable NMEA failed at messageNumber %d %s.\r\n", messageNumber, - umMessagesNMEA[messageNumber].msgTextName); - - // If we are using IP based corrections, we need to send local data to the PPL - // The PPL requires being fed GPGGA/ZDA, and RTCM1019/1020/1042/1046 - if (pointPerfectServiceUsesKeys()) - { - // Mark PPL required messages as enabled if rate > 0 - if (settings.um980MessageRatesNMEA[messageNumber] > 0) - { - if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "GPGGA") == 0) - gpggaEnabled = true; - else if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "GPZDA") == 0) - gpzdaEnabled = true; - } - } - } - } - - if (pointPerfectServiceUsesKeys()) - { - // Force on any messages that are needed for PPL - if (gpggaEnabled == false) - response &= _um980->setNMEAPortMessage("GPGGA", "COM3", 1); - if (gpzdaEnabled == false) - response &= _um980->setNMEAPortMessage("GPZDA", "COM3", 1); - } - - if (response == true) - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM - - return (response); -} - -//---------------------------------------- -// Turn on all the enabled RTCM Base messages on COM3 -//---------------------------------------- -bool GNSS_UM980::enableRTCMBase() -{ - bool response = true; - - for (int messageNumber = 0; messageNumber < MAX_UM980_RTCM_MSG; messageNumber++) - { - // Only turn on messages, do not turn off messages set to 0. This saves on command sending. We assume the caller - // has UNLOG or similar. - if (settings.um980MessageRatesRTCMBase[messageNumber] > 0) - { - // If any one of the commands fails, report failure overall - response &= _um980->setRTCMPortMessage(umMessagesRTCM[messageNumber].msgTextName, "COM3", - settings.um980MessageRatesRTCMBase[messageNumber]); - - if (response == false && settings.debugGnss) - systemPrintf("Enable RTCM failed at messageNumber %d %s.", messageNumber, - umMessagesRTCM[messageNumber].msgTextName); - } - } - - return (response); -} - -//---------------------------------------- -// Turn on all the enabled RTCM Rover messages on COM3 -//---------------------------------------- -bool GNSS_UM980::enableRTCMRover() -{ - bool response = true; - bool rtcm1019Enabled = false; - bool rtcm1020Enabled = false; - bool rtcm1042Enabled = false; - bool rtcm1046Enabled = false; - - for (int messageNumber = 0; messageNumber < MAX_UM980_RTCM_MSG; messageNumber++) - { - // Only turn on messages, do not turn off messages set to 0. This saves on command sending. We assume the caller - // has UNLOG or similar. - if (settings.um980MessageRatesRTCMRover[messageNumber] > 0) - { - if (_um980->setRTCMPortMessage(umMessagesRTCM[messageNumber].msgTextName, "COM3", - settings.um980MessageRatesRTCMRover[messageNumber]) == false) - { - if (settings.debugGnss) - systemPrintf("Enable RTCM failed at messageNumber %d %s.", messageNumber, - umMessagesRTCM[messageNumber].msgTextName); - response &= false; // If any one of the commands fails, report failure overall - } - - // If we are using IP based corrections, we need to send local data to the PPL - // The PPL requires being fed GPGGA/ZDA, and RTCM1019/1020/1042/1046 - if (pointPerfectServiceUsesKeys()) - { - // Mark PPL required messages as enabled if rate > 0 - if (settings.um980MessageRatesRTCMRover[messageNumber] > 0) - { - if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "RTCM1019") == 0) - rtcm1019Enabled = true; - else if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "RTCM1020") == 0) - rtcm1020Enabled = true; - else if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "RTCM1042") == 0) - rtcm1042Enabled = true; - else if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "RTCM1046") == 0) - rtcm1046Enabled = true; - } - } - } - } - - if (pointPerfectServiceUsesKeys()) - { - // Force on any messages that are needed for PPL - if (rtcm1019Enabled == false) - response &= _um980->setRTCMPortMessage("RTCM1019", "COM3", 1); - if (rtcm1020Enabled == false) - response &= _um980->setRTCMPortMessage("RTCM1020", "COM3", 1); - if (rtcm1042Enabled == false) - response &= _um980->setRTCMPortMessage("RTCM1042", "COM3", 1); - if (rtcm1046Enabled == false) - response &= _um980->setRTCMPortMessage("RTCM1046", "COM3", 1); - } - - if (response == true) - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM - - return (response); -} - //---------------------------------------- // Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted // even if there is no GPS fix. We use it to test serial output. @@ -1765,41 +1622,158 @@ bool GNSS_UM980::setHighAccuracyService(bool enableGalileoHas) } //---------------------------------------- -// Enable all the valid messages for this platform -// There are many messages so split into batches. VALSET is limited to 64 max per batch -// Uses dummy newCfg and sendCfg values to be sure we open/close a complete set +// Set the minimum satellite signal level (carrier to noise ratio) for navigation. //---------------------------------------- -bool GNSS_UM980::setMessages(int maxRetries) +bool GNSS_UM980::setMinCno(uint8_t cn0Value) { - // We probably don't need this for the UM980 - // TODO return(um980SetMessages(maxRetries)); - return (true); + if (online.gnss) + { + // Read, modify, write + // The UM980 does not currently have a way to read the CN0, so we must write only + _um980->setMinCNO(cn0Value); + return true; + } + return false; } //---------------------------------------- -// Enable all the valid messages for this platform over the USB port -// Add 2 to every UART1 key. This is brittle and non-perfect, but works. +// Turn on all the enabled NMEA messages on COM3 //---------------------------------------- -bool GNSS_UM980::setMessagesUsb(int maxRetries) +bool GNSS_UM980::setMessagesNMEA() { - // We probably don't need this for the UM980 - // TODO return(um980SetMessagesUsb(maxRetries)); - return (true); + bool response = true; + bool gpggaEnabled = false; + bool gpzdaEnabled = false; + + for (int messageNumber = 0; messageNumber < MAX_UM980_NMEA_MSG; messageNumber++) + { + // Only turn on messages, do not turn off messages set to 0. This saves on command sending. We assume the caller + // has UNLOG or similar. + if (settings.um980MessageRatesNMEA[messageNumber] > 0) + { + // If any one of the commands fails, report failure overall + response &= _um980->setNMEAPortMessage(umMessagesNMEA[messageNumber].msgTextName, "COM3", + settings.um980MessageRatesNMEA[messageNumber]); + + if (response == false && settings.debugGnss) + systemPrintf("Enable NMEA failed at messageNumber %d %s.\r\n", messageNumber, + umMessagesNMEA[messageNumber].msgTextName); + + // If we are using IP based corrections, we need to send local data to the PPL + // The PPL requires being fed GPGGA/ZDA, and RTCM1019/1020/1042/1046 + if (pointPerfectServiceUsesKeys()) + { + // Mark PPL required messages as enabled if rate > 0 + if (settings.um980MessageRatesNMEA[messageNumber] > 0) + { + if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "GPGGA") == 0) + gpggaEnabled = true; + else if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "GPZDA") == 0) + gpzdaEnabled = true; + } + } + } + } + + if (pointPerfectServiceUsesKeys()) + { + // Force on any messages that are needed for PPL + if (gpggaEnabled == false) + response &= _um980->setNMEAPortMessage("GPGGA", "COM3", 1); + if (gpzdaEnabled == false) + response &= _um980->setNMEAPortMessage("GPZDA", "COM3", 1); + } + + if (response == true) + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + + return (response); } //---------------------------------------- -// Set the minimum satellite signal level (carrier to noise ratio) for navigation. +// Configure RTCM Base messages on COM3 (the connection between ESP32 and UM980) //---------------------------------------- -bool GNSS_UM980::setMinCno(uint8_t cn0Value) +bool GNSS_UM980::setMessagesRTCMBase() { - if (online.gnss) + bool response = true; + + for (int messageNumber = 0; messageNumber < MAX_UM980_RTCM_MSG; messageNumber++) { - // Read, modify, write - // The UM980 does not currently have a way to read the CN0, so we must write only - _um980->setMinCNO(cn0Value); - return true; + // If any one of the commands fails, report failure overall + response &= _um980->setRTCMPortMessage(umMessagesRTCM[messageNumber].msgTextName, "COM3", + settings.um980MessageRatesRTCMBase[messageNumber]); + + if (response == false && settings.debugGnss) + systemPrintf("setMessagesRTCMBase failed at messageNumber %d %s.", messageNumber, + umMessagesRTCM[messageNumber].msgTextName); } - return false; + + return (response); +} + +//---------------------------------------- +// Set the RTCM Rover messages on COM3 +//---------------------------------------- +bool GNSS_UM980::setMessagesRTCMRover() +{ + bool response = true; + bool rtcm1019Enabled = false; + bool rtcm1020Enabled = false; + bool rtcm1042Enabled = false; + bool rtcm1046Enabled = false; + + for (int messageNumber = 0; messageNumber < MAX_UM980_RTCM_MSG; messageNumber++) + { + // Only turn on messages, do not turn off messages set to 0. This saves on command sending. We assume the caller + // has UNLOG or similar. + if (settings.um980MessageRatesRTCMRover[messageNumber] > 0) + { + if (_um980->setRTCMPortMessage(umMessagesRTCM[messageNumber].msgTextName, "COM3", + settings.um980MessageRatesRTCMRover[messageNumber]) == false) + { + if (settings.debugGnss) + systemPrintf("Enable RTCM failed at messageNumber %d %s.", messageNumber, + umMessagesRTCM[messageNumber].msgTextName); + response &= false; // If any one of the commands fails, report failure overall + } + + // If we are using IP based corrections, we need to send local data to the PPL + // The PPL requires being fed GPGGA/ZDA, and RTCM1019/1020/1042/1046 + if (pointPerfectServiceUsesKeys()) + { + // Mark PPL required messages as enabled if rate > 0 + if (settings.um980MessageRatesRTCMRover[messageNumber] > 0) + { + if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "RTCM1019") == 0) + rtcm1019Enabled = true; + else if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "RTCM1020") == 0) + rtcm1020Enabled = true; + else if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "RTCM1042") == 0) + rtcm1042Enabled = true; + else if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "RTCM1046") == 0) + rtcm1046Enabled = true; + } + } + } + } + + if (pointPerfectServiceUsesKeys()) + { + // Force on any messages that are needed for PPL + if (rtcm1019Enabled == false) + response &= _um980->setRTCMPortMessage("RTCM1019", "COM3", 1); + if (rtcm1020Enabled == false) + response &= _um980->setRTCMPortMessage("RTCM1020", "COM3", 1); + if (rtcm1042Enabled == false) + response &= _um980->setRTCMPortMessage("RTCM1042", "COM3", 1); + if (rtcm1046Enabled == false) + response &= _um980->setRTCMPortMessage("RTCM1046", "COM3", 1); + } + + if (response == true) + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + + return (response); } //---------------------------------------- @@ -1919,7 +1893,7 @@ bool GNSS_UM980::setRate(double secondsBetweenSolutions) if (settings.um980MessageRatesNMEA[messageNumber] > 0) settings.um980MessageRatesNMEA[messageNumber] = secondsBetweenSolutions; } - response &= enableNMEA(); // Enact these rates + response &= setMessagesNMEA(); // Enact these rates // TODO We don't know what state we are in, so we don't // know which RTCM settings to update. Assume we are @@ -1929,7 +1903,7 @@ bool GNSS_UM980::setRate(double secondsBetweenSolutions) if (settings.um980MessageRatesRTCMRover[messageNumber] > 0) settings.um980MessageRatesRTCMRover[messageNumber] = secondsBetweenSolutions; } - response &= enableRTCMRover(); // Enact these rates + response &= setMessagesRTCMRover(); // Enact these rates // If we successfully set rates, only then record to settings if (response) diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.h b/Firmware/RTK_Everywhere/GNSS_ZED.h index fb8266838..61f575273 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.h +++ b/Firmware/RTK_Everywhere/GNSS_ZED.h @@ -699,15 +699,18 @@ class GNSS_ZED : GNSS // Given the name of a message, find it, and set the rate bool setMessageRateByName(const char *msgName, uint8_t msgRate); - // Enable all the valid messages for this platform - bool setMessages(int maxRetries); - - // Enable all the valid messages for this platform over the USB port - bool setMessagesUsb(int maxRetries); - // Set the minimum satellite signal level for navigation. bool setMinCno(uint8_t cnoValue); + // Set the NMEA messages + bool setMessagesNMEA(); + + // Set then RTCM Base messages + bool setMessagesRTCMBase(); + + // Set the RTCM Rover messages + bool setMessagesRTCMRover(); + // Set the dynamic model to use for RTK // Inputs: // modelNumber: Number of the model to use, provided by radio library diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index ddfb2ced1..e13cf576f 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -712,7 +712,7 @@ bool GNSS_ZED::configureGNSS() response = true; // Reset // Make sure the appropriate messages are enabled - response &= setMessages(MAX_SET_MESSAGES_RETRIES); // Does a complete open/closed val set + response &= setMessagesNMEA(); // Does a complete open/closed val set if (response == false) systemPrintln("Module failed config block 2"); success &= response; @@ -1888,7 +1888,7 @@ void GNSS_ZED::menuMessages() clearBuffer(); // Empty buffer of any newline chars // Make sure the appropriate messages are enabled - bool response = setMessages(MAX_SET_MESSAGES_RETRIES); // Does a complete open/closed val set + bool response = setMessagesNMEA(); // Does a complete open/closed val set if (response == false) systemPrintf("menuMessages: Failed to enable messages - after %d tries", MAX_SET_MESSAGES_RETRIES); else @@ -2260,12 +2260,15 @@ bool GNSS_ZED::setNmeaMessageRateByName(const char *msgName, uint8_t msgRate) } //---------------------------------------- -// Enable all the valid messages for this platform +// Set the rate for all messages +// The ZED has a lot more messages than just NMEA in ubxMessageRates[], but other platforms generally just have NMEA and RTCM // There are many messages so split into batches. VALSET is limited to 64 max per batch // Uses dummy newCfg and sendCfg values to be sure we open/close a complete set //---------------------------------------- -bool GNSS_ZED::setMessages(int maxRetries) +bool GNSS_ZED::setMessagesNMEA() { + int maxRetries = MAX_SET_MESSAGES_RETRIES; + bool success = false; if (online.gnss) @@ -2315,48 +2318,21 @@ bool GNSS_ZED::setMessages(int maxRetries) } //---------------------------------------- -// Enable all the valid messages for this platform over the USB port -// Add 2 to every UART1 key. This is brittle and non-perfect, but works. +// Configure RTCM Base messages //---------------------------------------- -bool GNSS_ZED::setMessagesUsb(int maxRetries) +bool GNSS_ZED::setMessagesRTCMBase() { - bool success = false; - - if (online.gnss) - { - int tryNo = -1; - - // Try up to maxRetries times to configure the messages - // This corrects occasional failures seen on the Reference Station where the GNSS is connected via SPI - // instead of I2C and UART1. I believe the SETVAL ACK is occasionally missed due to the level of messages being - // processed. - while ((++tryNo < maxRetries) && !success) - { - bool response = true; - int messageNumber = 0; - - while (messageNumber < MAX_UBX_MSG) - { - response &= _zed->newCfgValset(VAL_LAYER_ALL); - - do - { - if (messageSupported(messageNumber)) - response &= _zed->addCfgValset(ubxMessages[messageNumber].msgConfigKey + 2, - settings.ubxMessageRates[messageNumber]); - messageNumber++; - } while (((messageNumber % 43) < 42) && - (messageNumber < MAX_UBX_MSG)); // Limit 1st batch to 42. Batches after that will be (up to) 43 - // in size. It's a HHGTTG thing. - - response &= _zed->sendCfgValset(); - } + //TODO + return(false); +} - if (response) - success = true; - } - } - return (success); +//---------------------------------------- +// Configure RTCM Base messages +//---------------------------------------- +bool GNSS_ZED::setMessagesRTCMRover() +{ + //TODO + return(false); } //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/RTK_Everywhere.ino b/Firmware/RTK_Everywhere/RTK_Everywhere.ino index 052bdcb84..c757a0537 100644 --- a/Firmware/RTK_Everywhere/RTK_Everywhere.ino +++ b/Firmware/RTK_Everywhere/RTK_Everywhere.ino @@ -1374,8 +1374,8 @@ void setup() DMW_b("beginExternalEvent"); gnss->beginExternalEvent(); // Configure the event input - DMW_b("beginPPS"); - gnss->beginPPS(); // Configure the time pulse output + DMW_b("setPPS"); + gnss->setPPS(); // Configure the pulse per second pin DMW_b("beginInterrupts"); beginInterrupts(); // Begin the TP interrupts diff --git a/Firmware/RTK_Everywhere/menuSystem.ino b/Firmware/RTK_Everywhere/menuSystem.ino index f51a3daf2..c8cb940e2 100644 --- a/Firmware/RTK_Everywhere/menuSystem.ino +++ b/Firmware/RTK_Everywhere/menuSystem.ino @@ -993,10 +993,6 @@ void menuOperation() systemPrint("9) UART Receive Buffer Size: "); systemPrintln(settings.uartReceiveBufferSize); - // ZED - if (present.gnss_zedf9p) - systemPrintln("10) Mirror ZED-F9x's UART1 settings to USB"); - // PPL Float Lock timeout systemPrint("11) Set PPL RTK Fix Timeout (seconds): "); if (settings.pplFixTimeoutS > 0) @@ -1095,17 +1091,6 @@ void menuOperation() ESP.restart(); } } - else if (incoming == 10 && present.gnss_zedf9p) - { -#ifdef COMPILE_ZED - bool response = gnss->setMessagesUsb(MAX_SET_MESSAGES_RETRIES); - - if (response == false) - systemPrintln(F("Failed to enable USB messages")); - else - systemPrintln(F("USB messages successfully enabled")); -#endif // COMPILE_ZED - } else if (incoming == 11) { getNewSetting("Enter number of seconds in RTK float using PPL, before reset", 0, 3600, From 62f085cc30ff67fe61fbc11119fcd0e124995547 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Wed, 15 Oct 2025 13:14:56 -0600 Subject: [PATCH 20/68] Whitespace --- Firmware/RTK_Everywhere/GNSS.h | 570 ++++++++++++++++----------------- 1 file changed, 285 insertions(+), 285 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.h b/Firmware/RTK_Everywhere/GNSS.h index 88fd3b344..e461132f5 100644 --- a/Firmware/RTK_Everywhere/GNSS.h +++ b/Firmware/RTK_Everywhere/GNSS.h @@ -9,396 +9,396 @@ GNSS.h class GNSS { -protected: - float _altitude; // Altitude in meters - float _horizontalAccuracy; // Horizontal position accuracy in meters - double _latitude; // Latitude in degrees - double _longitude; // Longitude in degrees - - uint8_t _day; // Day number - uint8_t _month; // Month number - uint16_t _year; - uint8_t _hour; // Hours for 24 hour clock - uint8_t _minute; - uint8_t _second; - uint8_t _leapSeconds; - uint16_t _millisecond; // Limited to first two digits - uint32_t _nanosecond; - - uint8_t _satellitesInView; - uint8_t _fixType; - uint8_t _carrierSolution; - - bool _validDate; // True when date is valid - bool _validTime; // True when time is valid - bool _confirmedDate; - bool _confirmedTime; - bool _fullyResolved; - uint32_t _tAcc; - - unsigned long _pvtArrivalMillis; - bool _pvtUpdated; - - bool _corrRadioExtPortEnabled = false; - - unsigned long _autoBaseStartTimer; // Tracks how long the base auto / averaging mode has been running + protected: + float _altitude; // Altitude in meters + float _horizontalAccuracy; // Horizontal position accuracy in meters + double _latitude; // Latitude in degrees + double _longitude; // Longitude in degrees + + uint8_t _day; // Day number + uint8_t _month; // Month number + uint16_t _year; + uint8_t _hour; // Hours for 24 hour clock + uint8_t _minute; + uint8_t _second; + uint8_t _leapSeconds; + uint16_t _millisecond; // Limited to first two digits + uint32_t _nanosecond; + + uint8_t _satellitesInView; + uint8_t _fixType; + uint8_t _carrierSolution; + + bool _validDate; // True when date is valid + bool _validTime; // True when time is valid + bool _confirmedDate; + bool _confirmedTime; + bool _fullyResolved; + uint32_t _tAcc; + + unsigned long _pvtArrivalMillis; + bool _pvtUpdated; + + bool _corrRadioExtPortEnabled = false; + + unsigned long _autoBaseStartTimer; // Tracks how long the base auto / averaging mode has been running - // Setup the general configuration of the GNSS - // Not Rover or Base specific (ie, baud rates) - // Outputs: - // Returns true if successfully configured and false upon failure - virtual bool configureGNSS(); - -public: - // Constructor - GNSS() : _leapSeconds(18), _pvtArrivalMillis(0), _pvtUpdated(0), _satellitesInView(0) - { - } + // Setup the general configuration of the GNSS + // Not Rover or Base specific (ie, baud rates) + // Outputs: + // Returns true if successfully configured and false upon failure + virtual bool configureGNSS(); + + public: + // Constructor + GNSS() : _leapSeconds(18), _pvtArrivalMillis(0), _pvtUpdated(0), _satellitesInView(0) + { + } - // If we have decryption keys, configure module - // Note: don't check online.lband_neo here. We could be using ip corrections - virtual void applyPointPerfectKeys(); + // If we have decryption keys, configure module + // Note: don't check online.lband_neo here. We could be using ip corrections + virtual void applyPointPerfectKeys(); - // Set RTCM for base mode to defaults (1005/1074/1084/1094/1124 1Hz & 1230 0.1Hz) - virtual void baseRtcmDefault(); + // Set RTCM for base mode to defaults (1005/1074/1084/1094/1124 1Hz & 1230 0.1Hz) + virtual void baseRtcmDefault(); - // Reset to Low Bandwidth Link (1074/1084/1094/1124 0.5Hz & 1005/1230 0.1Hz) - virtual void baseRtcmLowDataRate(); + // Reset to Low Bandwidth Link (1074/1084/1094/1124 0.5Hz & 1005/1230 0.1Hz) + virtual void baseRtcmLowDataRate(); - // Check if a given baud rate is supported by this module - virtual bool baudIsAllowed(uint32_t baudRate); - virtual uint32_t baudGetMinimum(); - virtual uint32_t baudGetMaximum(); + // Check if a given baud rate is supported by this module + virtual bool baudIsAllowed(uint32_t baudRate); + virtual uint32_t baudGetMinimum(); + virtual uint32_t baudGetMaximum(); - // Connect to GNSS and identify particulars - virtual void begin(); + // Connect to GNSS and identify particulars + virtual void begin(); - // Setup TM2 time stamp input as need - // Outputs: - // Returns true when an external event occurs and false if no event - virtual bool beginExternalEvent(); + // Setup TM2 time stamp input as need + // Outputs: + // Returns true when an external event occurs and false if no event + virtual bool beginExternalEvent(); - virtual bool checkNMEARates(); + virtual bool checkNMEARates(); - virtual bool checkPPPRates(); + virtual bool checkPPPRates(); - // Setup the general configuration of the GNSS - // Not Rover or Base specific (ie, baud rates) - // Outputs: - // Returns true if successfully configured and false upon failure - bool configure(); + // Setup the general configuration of the GNSS + // Not Rover or Base specific (ie, baud rates) + // Outputs: + // Returns true if successfully configured and false upon failure + bool configure(); - // Configure the Base - // Outputs: - // Returns true if successfully configured and false upon failure - virtual bool configureBase(); + // Configure the Base + // Outputs: + // Returns true if successfully configured and false upon failure + virtual bool configureBase(); - // Configure specific aspects of the receiver for NTP mode - virtual bool configureNtpMode(); + // Configure specific aspects of the receiver for NTP mode + virtual bool configureNtpMode(); - // Configure the Rover - // Outputs: - // Returns true if successfully configured and false upon failure - virtual bool configureRover(); + // Configure the Rover + // Outputs: + // Returns true if successfully configured and false upon failure + virtual bool configureRover(); - // Responds with the messages supported on this platform - // Inputs: - // returnText: String to receive message names - // Returns message names in the returnText string - virtual void createMessageList(String &returnText); + // Responds with the messages supported on this platform + // Inputs: + // returnText: String to receive message names + // Returns message names in the returnText string + virtual void createMessageList(String &returnText); - // Responds with the RTCM/Base messages supported on this platform - // Inputs: - // returnText: String to receive message names - // Returns message names in the returnText string - virtual void createMessageListBase(String &returnText); + // Responds with the RTCM/Base messages supported on this platform + // Inputs: + // returnText: String to receive message names + // Returns message names in the returnText string + virtual void createMessageListBase(String &returnText); - virtual void debuggingDisable(); + virtual void debuggingDisable(); - virtual void debuggingEnable(); + virtual void debuggingEnable(); - virtual void enableGgaForNtrip(); + virtual void enableGgaForNtrip(); - // Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted - // even if there is no GPS fix. We use it to test serial output. - // Outputs: - // Returns true if successfully started and false upon failure - virtual bool enableRTCMTest(); + // Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted + // even if there is no GPS fix. We use it to test serial output. + // Outputs: + // Returns true if successfully started and false upon failure + virtual bool enableRTCMTest(); - // Restore the GNSS to the factory settings - virtual void factoryReset(); + // Restore the GNSS to the factory settings + virtual void factoryReset(); - virtual uint16_t fileBufferAvailable(); + virtual uint16_t fileBufferAvailable(); - virtual uint16_t fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead); + virtual uint16_t fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead); - // Start the base using fixed coordinates - // Outputs: - // Returns true if successfully started and false upon failure - virtual bool fixedBaseStart(); + // Start the base using fixed coordinates + // Outputs: + // Returns true if successfully started and false upon failure + virtual bool fixedBaseStart(); - // Return the number of active/enabled messages - virtual uint8_t getActiveMessageCount(); + // Return the number of active/enabled messages + virtual uint8_t getActiveMessageCount(); - // Return the number of active/enabled RTCM messages - virtual uint8_t getActiveRtcmMessageCount(); + // Return the number of active/enabled RTCM messages + virtual uint8_t getActiveRtcmMessageCount(); - // Get the altitude - // Outputs: - // Returns the altitude in meters or zero if the GNSS is offline - virtual double getAltitude(); + // Get the altitude + // Outputs: + // Returns the altitude in meters or zero if the GNSS is offline + virtual double getAltitude(); - // Returns the carrier solution or zero if not online - virtual uint8_t getCarrierSolution(); + // Returns the carrier solution or zero if not online + virtual uint8_t getCarrierSolution(); - virtual uint32_t getDataBaudRate(); + virtual uint32_t getDataBaudRate(); - // Returns the day number or zero if not online - virtual uint8_t getDay(); + // Returns the day number or zero if not online + virtual uint8_t getDay(); - // Return the number of milliseconds since GNSS data was last updated - virtual uint16_t getFixAgeMilliseconds(); + // Return the number of milliseconds since GNSS data was last updated + virtual uint16_t getFixAgeMilliseconds(); - // Returns the fix type or zero if not online - virtual uint8_t getFixType(); + // Returns the fix type or zero if not online + virtual uint8_t getFixType(); - // Returns the hours of 24 hour clock or zero if not online - virtual uint8_t getHour(); + // Returns the hours of 24 hour clock or zero if not online + virtual uint8_t getHour(); - // Get the horizontal position accuracy - // Outputs: - // Returns the horizontal position accuracy or zero if offline - virtual float getHorizontalAccuracy(); + // Get the horizontal position accuracy + // Outputs: + // Returns the horizontal position accuracy or zero if offline + virtual float getHorizontalAccuracy(); - virtual const char *getId(); + virtual const char *getId(); - // Get the latitude value - // Outputs: - // Returns the latitude value or zero if not online - virtual double getLatitude(); + // Get the latitude value + // Outputs: + // Returns the latitude value or zero if not online + virtual double getLatitude(); - // Query GNSS for current leap seconds - virtual uint8_t getLeapSeconds(); + // Query GNSS for current leap seconds + virtual uint8_t getLeapSeconds(); - // Return the type of logging that matches the enabled messages - drives the logging icon - virtual uint8_t getLoggingType(); + // Return the type of logging that matches the enabled messages - drives the logging icon + virtual uint8_t getLoggingType(); - // Get the longitude value - // Outputs: - // Returns the longitude value or zero if not online - virtual double getLongitude(); + // Get the longitude value + // Outputs: + // Returns the longitude value or zero if not online + virtual double getLongitude(); - // Returns two digits of milliseconds or zero if not online - virtual uint8_t getMillisecond(); + // Returns two digits of milliseconds or zero if not online + virtual uint8_t getMillisecond(); - // Get the minimum satellite signal level for navigation. - uint8_t getMinCno(); + // Get the minimum satellite signal level for navigation. + uint8_t getMinCno(); - // Returns minutes or zero if not online - virtual uint8_t getMinute(); + // Returns minutes or zero if not online + virtual uint8_t getMinute(); - // Returns month number or zero if not online - virtual uint8_t getMonth(); + // Returns month number or zero if not online + virtual uint8_t getMonth(); - // Returns nanoseconds or zero if not online - virtual uint32_t getNanosecond(); + // Returns nanoseconds or zero if not online + virtual uint32_t getNanosecond(); - virtual uint32_t getRadioBaudRate(); + virtual uint32_t getRadioBaudRate(); - // Returns the seconds between solutions - virtual double getRateS(); + // Returns the seconds between solutions + virtual double getRateS(); - virtual const char *getRtcmDefaultString(); + virtual const char *getRtcmDefaultString(); - virtual const char *getRtcmLowDataRateString(); + virtual const char *getRtcmLowDataRateString(); - // Returns the number of satellites in view or zero if offline - virtual uint8_t getSatellitesInView(); + // Returns the number of satellites in view or zero if offline + virtual uint8_t getSatellitesInView(); - // Returns seconds or zero if not online - virtual uint8_t getSecond(); + // Returns seconds or zero if not online + virtual uint8_t getSecond(); - // Get the survey-in mean accuracy - // Outputs: - // Returns the mean accuracy or zero (0) - virtual float getSurveyInMeanAccuracy(); + // Get the survey-in mean accuracy + // Outputs: + // Returns the mean accuracy or zero (0) + virtual float getSurveyInMeanAccuracy(); - // Return the number of seconds the survey-in process has been running - virtual int getSurveyInObservationTime(); + // Return the number of seconds the survey-in process has been running + virtual int getSurveyInObservationTime(); - float getSurveyInStartingAccuracy(); + float getSurveyInStartingAccuracy(); - // Returns timing accuracy or zero if not online - virtual uint32_t getTimeAccuracy(); + // Returns timing accuracy or zero if not online + virtual uint32_t getTimeAccuracy(); - // Returns full year, ie 2023, not 23. - virtual uint16_t getYear(); + // Returns full year, ie 2023, not 23. + virtual uint16_t getYear(); - // Antenna Short / Open detection - virtual bool isAntennaShorted(); - virtual bool isAntennaOpen(); + // Antenna Short / Open detection + virtual bool isAntennaShorted(); + virtual bool isAntennaOpen(); - virtual bool isBlocking(); + virtual bool isBlocking(); - // Date is confirmed once we have GNSS fix - virtual bool isConfirmedDate(); + // Date is confirmed once we have GNSS fix + virtual bool isConfirmedDate(); - // Date is confirmed once we have GNSS fix - virtual bool isConfirmedTime(); + // Date is confirmed once we have GNSS fix + virtual bool isConfirmedTime(); - // Returns true if data is arriving on the Radio Ext port - virtual bool isCorrRadioExtPortActive(); + // Returns true if data is arriving on the Radio Ext port + virtual bool isCorrRadioExtPortActive(); - // Return true if GNSS receiver has a higher quality DGPS fix than 3D - virtual bool isDgpsFixed(); + // Return true if GNSS receiver has a higher quality DGPS fix than 3D + virtual bool isDgpsFixed(); - // Some functions (L-Band area frequency determination) merely need - // to know if we have a valid fix, not what type of fix - // This function checks to see if the given platform has reached - // sufficient fix type to be considered valid - virtual bool isFixed(); + // Some functions (L-Band area frequency determination) merely need + // to know if we have a valid fix, not what type of fix + // This function checks to see if the given platform has reached + // sufficient fix type to be considered valid + virtual bool isFixed(); - // Used in tpISR() for time pulse synchronization - virtual bool isFullyResolved(); + // Used in tpISR() for time pulse synchronization + virtual bool isFullyResolved(); - virtual bool isPppConverged(); + virtual bool isPppConverged(); - virtual bool isPppConverging(); + virtual bool isPppConverging(); - // Some functions (L-Band area frequency determination) merely need - // to know if we have an RTK Fix. This function checks to see if the - // given platform has reached sufficient fix type to be considered valid - virtual bool isRTKFix(); + // Some functions (L-Band area frequency determination) merely need + // to know if we have an RTK Fix. This function checks to see if the + // given platform has reached sufficient fix type to be considered valid + virtual bool isRTKFix(); - // Some functions (L-Band area frequency determination) merely need - // to know if we have an RTK Float. This function checks to see if - // the given platform has reached sufficient fix type to be considered - // valid - virtual bool isRTKFloat(); + // Some functions (L-Band area frequency determination) merely need + // to know if we have an RTK Float. This function checks to see if + // the given platform has reached sufficient fix type to be considered + // valid + virtual bool isRTKFloat(); - // Determine if the survey-in operation is complete - // Outputs: - // Returns true if the survey-in operation is complete and false - // if the operation is still running - virtual bool isSurveyInComplete(); + // Determine if the survey-in operation is complete + // Outputs: + // Returns true if the survey-in operation is complete and false + // if the operation is still running + virtual bool isSurveyInComplete(); - // Date will be valid if the RTC is reporting (regardless of GNSS fix) - virtual bool isValidDate(); + // Date will be valid if the RTC is reporting (regardless of GNSS fix) + virtual bool isValidDate(); - // Time will be valid if the RTC is reporting (regardless of GNSS fix) - virtual bool isValidTime(); + // Time will be valid if the RTC is reporting (regardless of GNSS fix) + virtual bool isValidTime(); - // Controls the constellations that are used to generate a fix and logged - virtual void menuConstellations(); + // Controls the constellations that are used to generate a fix and logged + virtual void menuConstellations(); - virtual void menuMessageBaseRtcm(); + virtual void menuMessageBaseRtcm(); - // Control the messages that get broadcast over Bluetooth and logged (if enabled) - virtual void menuMessages(); + // Control the messages that get broadcast over Bluetooth and logged (if enabled) + virtual void menuMessages(); - // Print the module type and firmware version - virtual void printModuleInfo(); + // Print the module type and firmware version + virtual void printModuleInfo(); - // Send correction data to the GNSS - // Inputs: - // dataToSend: Address of a buffer containing the data - // dataLength: The number of valid data bytes in the buffer - // Outputs: - // Returns the number of correction data bytes written - virtual int pushRawData(uint8_t *dataToSend, int dataLength); + // Send correction data to the GNSS + // Inputs: + // dataToSend: Address of a buffer containing the data + // dataLength: The number of valid data bytes in the buffer + // Outputs: + // Returns the number of correction data bytes written + virtual int pushRawData(uint8_t *dataToSend, int dataLength); - virtual uint16_t rtcmBufferAvailable(); + virtual uint16_t rtcmBufferAvailable(); - // If LBand is being used, ignore any RTCM that may come in from the GNSS - virtual void rtcmOnGnssDisable(); + // If LBand is being used, ignore any RTCM that may come in from the GNSS + virtual void rtcmOnGnssDisable(); - // If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver - virtual void rtcmOnGnssEnable(); + // If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver + virtual void rtcmOnGnssEnable(); - virtual uint16_t rtcmRead(uint8_t *rtcmBuffer, int rtcmBytesToRead); + virtual uint16_t rtcmRead(uint8_t *rtcmBuffer, int rtcmBytesToRead); - // Save the current configuration - // Outputs: - // Returns true when the configuration was saved and false upon failure - virtual bool saveConfiguration(); + // Save the current configuration + // Outputs: + // Returns true when the configuration was saved and false upon failure + virtual bool saveConfiguration(); - // Enable all the valid constellations and bands for this platform - virtual bool setConstellations(); + // Enable all the valid constellations and bands for this platform + virtual bool setConstellations(); - // Enable / disable corrections protocol(s) on the Radio External port - // Always update if force is true. Otherwise, only update if enable has changed state - virtual bool setCorrRadioExtPort(bool enable, bool force); + // Enable / disable corrections protocol(s) on the Radio External port + // Always update if force is true. Otherwise, only update if enable has changed state + virtual bool setCorrRadioExtPort(bool enable, bool force); - virtual bool setBaudRate(uint8_t uartNumber, uint32_t baudRate); + virtual bool setBaudRate(uint8_t uartNumber, uint32_t baudRate); - virtual bool setBaudRateComm(uint32_t baud); + virtual bool setBaudRateComm(uint32_t baud); - virtual bool setBaudRateData(uint32_t baud); + virtual bool setBaudRateData(uint32_t baud); - virtual bool setBaudRateRadio(uint32_t baud); + virtual bool setBaudRateRadio(uint32_t baud); - // Set the elevation in degrees - // Inputs: - // elevationDegrees: The elevation value in degrees - virtual bool setElevation(uint8_t elevationDegrees); + // Set the elevation in degrees + // Inputs: + // elevationDegrees: The elevation value in degrees + virtual bool setElevation(uint8_t elevationDegrees); - virtual bool setHighAccuracyService(bool enableGalileoHas); + virtual bool setHighAccuracyService(bool enableGalileoHas); - virtual bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); + virtual bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); - // Enable/disable messages according to the NMEA array - virtual bool setMessagesNMEA(); + // Enable/disable messages according to the NMEA array + virtual bool setMessagesNMEA(); // Enable/disable messages according to the RTCM Base array - virtual bool setMessagesRTCMBase(); + virtual bool setMessagesRTCMBase(); // Enable/disable messages according to the NMEA array - virtual bool setMessagesRTCMRover(); + virtual bool setMessagesRTCMRover(); - // Set the minimum satellite signal level for navigation. - virtual bool setMinCno(uint8_t cnoValue); + // Set the minimum satellite signal level for navigation. + virtual bool setMinCno(uint8_t cnoValue); - // Set the dynamic model to use for RTK - // Inputs: - // modelNumber: Number of the model to use, provided by radio library - virtual bool setModel(uint8_t modelNumber); + // Set the dynamic model to use for RTK + // Inputs: + // modelNumber: Number of the model to use, provided by radio library + virtual bool setModel(uint8_t modelNumber); - virtual bool setMultipathMitigation(bool enableMultipathMitigation); + virtual bool setMultipathMitigation(bool enableMultipathMitigation); - // Configure the Pulse-per-second pin based on user settings - virtual bool setPPS(); + // Configure the Pulse-per-second pin based on user settings + virtual bool setPPS(); - // Specify the interval between solutions - // Inputs: - // secondsBetweenSolutions: Number of seconds between solutions - // Outputs: - // Returns true if the rate was successfully set and false upon - // failure - virtual bool setRate(double secondsBetweenSolutions); + // Specify the interval between solutions + // Inputs: + // secondsBetweenSolutions: Number of seconds between solutions + // Outputs: + // Returns true if the rate was successfully set and false upon + // failure + virtual bool setRate(double secondsBetweenSolutions); - virtual bool setTalkerGNGGA(); + virtual bool setTalkerGNGGA(); - // Hotstart GNSS to try to get RTK lock - virtual bool softwareReset(); + // Hotstart GNSS to try to get RTK lock + virtual bool softwareReset(); - virtual bool standby(); + virtual bool standby(); - // Antenna Short / Open detection - virtual bool supportsAntennaShortOpen(); + // Antenna Short / Open detection + virtual bool supportsAntennaShortOpen(); - // Reset the survey-in operation - // Outputs: - // Returns true if the survey-in operation was reset successfully - // and false upon failure - virtual bool surveyInReset(); + // Reset the survey-in operation + // Outputs: + // Returns true if the survey-in operation was reset successfully + // and false upon failure + virtual bool surveyInReset(); - // Start the survey-in operation - // Outputs: - // Return true if successful and false upon failure - virtual bool surveyInStart(); + // Start the survey-in operation + // Outputs: + // Return true if successful and false upon failure + virtual bool surveyInStart(); - // Poll routine to update the GNSS state - virtual void update(); + // Poll routine to update the GNSS state + virtual void update(); }; // Update the constellations following a set command From 3e818dbaa24e555bfffac64e0ff6e96464b5cc5e Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 16 Oct 2025 16:31:56 -0600 Subject: [PATCH 21/68] Add non-blocking CONFIG_WAIT to the system state machine --- Firmware/RTK_Everywhere/Display.ino | 51 +++++++++++----------- Firmware/RTK_Everywhere/States.ino | 62 ++++++++++++++------------ Firmware/RTK_Everywhere/Tasks.ino | 2 + Firmware/RTK_Everywhere/settings.h | 68 +++++++++++++++-------------- 4 files changed, 96 insertions(+), 87 deletions(-) diff --git a/Firmware/RTK_Everywhere/Display.ino b/Firmware/RTK_Everywhere/Display.ino index 5790490ea..1f2ccdcd7 100644 --- a/Firmware/RTK_Everywhere/Display.ino +++ b/Firmware/RTK_Everywhere/Display.ino @@ -218,7 +218,8 @@ void displayUpdate() forceDisplayUpdate = false; if (present.displayInverted == false) - oled->reset(false); // Incase of previous corruption, force re-alignment of CGRAM. Do not init buffers as it + oled->reset( + false); // Incase of previous corruption, force re-alignment of CGRAM. Do not init buffers as it // takes time and causes screen to blink. oled->erase(); @@ -291,6 +292,15 @@ void displayUpdate() displayFullIPAddress(&iconPropertyList); // Bottom left - 128x64 only setRadioIcons(&iconPropertyList); break; + case (STATE_ROVER_CONFIG_WAIT): + displayHorizontalAccuracy(&iconPropertyList, &CrossHairProperties, + 0b11111111); // Single crosshair, no blink + paintLogging(&iconPropertyList); + displaySivVsOpenShort(&iconPropertyList); + displayBatteryVsEthernet(&iconPropertyList); + displayFullIPAddress(&iconPropertyList); // Bottom left - 128x64 only + setRadioIcons(&iconPropertyList); + break; case (STATE_ROVER_NO_FIX): displayHorizontalAccuracy(&iconPropertyList, &CrossHairProperties, 0b01010101); // Single crosshair, blink @@ -332,6 +342,7 @@ void displayUpdate() case (STATE_BASE_CASTER_NOT_STARTED): case (STATE_BASE_NOT_STARTED): + case (STATE_BASE_CONFIG_WAIT): // Do nothing. Static display shown during state change. break; @@ -378,8 +389,7 @@ void displayUpdate() break; case (STATE_NTPSERVER_NOT_STARTED): - case (STATE_NTPSERVER_NO_SYNC): - { + case (STATE_NTPSERVER_NO_SYNC): { paintClock(&iconPropertyList, true); // Blink displaySivVsOpenShort(&iconPropertyList); @@ -400,8 +410,7 @@ void displayUpdate() } break; - case (STATE_NTPSERVER_SYNC): - { + case (STATE_NTPSERVER_SYNC): { paintClock(&iconPropertyList, false); // No blink displaySivVsOpenShort(&iconPropertyList); paintLogging(&iconPropertyList, false, true); // No pulse, NTP @@ -917,22 +926,19 @@ void setRadioIcons(std::vector *iconList) paintDynamicModel(iconList); break; case (STATE_BASE_TEMP_SETTLE): - case (STATE_BASE_TEMP_SURVEY_STARTED): - { + case (STATE_BASE_TEMP_SURVEY_STARTED): { prop.duty = 0b00001111; prop.icon = BaseTemporaryProperties.iconDisplay[present.display_type]; iconList->push_back(prop); } break; - case (STATE_BASE_TEMP_TRANSMITTING): - { + case (STATE_BASE_TEMP_TRANSMITTING): { prop.duty = 0b11111111; prop.icon = BaseTemporaryProperties.iconDisplay[present.display_type]; iconList->push_back(prop); } break; - case (STATE_BASE_FIXED_TRANSMITTING): - { + case (STATE_BASE_FIXED_TRANSMITTING): { prop.duty = 0b11111111; prop.icon = BaseFixedProperties.iconDisplay[present.display_type]; iconList->push_back(prop); @@ -1253,6 +1259,8 @@ void setModeIcon(std::vector *iconList) { case (STATE_ROVER_NOT_STARTED): break; + case (STATE_ROVER_CONFIG_WAIT): + break; case (STATE_ROVER_NO_FIX): paintDynamicModel(iconList); break; @@ -1268,26 +1276,24 @@ void setModeIcon(std::vector *iconList) case (STATE_BASE_CASTER_NOT_STARTED): case (STATE_BASE_NOT_STARTED): + case (STATE_BASE_CONFIG_WAIT): // Do nothing. Static display shown during state change. break; - case (STATE_BASE_TEMP_SETTLE): - { + case (STATE_BASE_TEMP_SETTLE): { iconPropertyBlinking prop; prop.duty = 0b00001111; prop.icon = BaseTemporaryProperties.iconDisplay[present.display_type]; iconList->push_back(prop); } break; - case (STATE_BASE_TEMP_SURVEY_STARTED): - { + case (STATE_BASE_TEMP_SURVEY_STARTED): { iconPropertyBlinking prop; prop.duty = 0b00001111; prop.icon = BaseTemporaryProperties.iconDisplay[present.display_type]; iconList->push_back(prop); } break; - case (STATE_BASE_TEMP_TRANSMITTING): - { + case (STATE_BASE_TEMP_TRANSMITTING): { iconPropertyBlinking prop; prop.duty = 0b11111111; prop.icon = BaseTemporaryProperties.iconDisplay[present.display_type]; @@ -1297,8 +1303,7 @@ void setModeIcon(std::vector *iconList) case (STATE_BASE_FIXED_NOT_STARTED): // Do nothing. Static display shown during state change. break; - case (STATE_BASE_FIXED_TRANSMITTING): - { + case (STATE_BASE_FIXED_TRANSMITTING): { iconPropertyBlinking prop; prop.duty = 0b11111111; prop.icon = BaseFixedProperties.iconDisplay[present.display_type]; @@ -2672,8 +2677,7 @@ void paintDisplaySetup() { constructSetupDisplay(&setupButtons); // Construct the vector (linked list) of buttons - uint8_t maxButtons = - ((present.display_type == DISPLAY_128x64) ? 5 : 4); + uint8_t maxButtons = ((present.display_type == DISPLAY_128x64) ? 5 : 4); uint8_t printedButtons = 0; @@ -2688,10 +2692,7 @@ void paintDisplaySetup() { if (it->newState == STATE_PROFILE) { - int nameWidth = - ((present.display_type == DISPLAY_128x64) - ? 17 - : 9); + int nameWidth = ((present.display_type == DISPLAY_128x64) ? 17 : 9); char miniProfileName[nameWidth] = {0}; snprintf(miniProfileName, sizeof(miniProfileName), "%d_%s", it->newProfile, it->name); // Prefix with index # diff --git a/Firmware/RTK_Everywhere/States.ino b/Firmware/RTK_Everywhere/States.ino index ce314d703..002635221 100644 --- a/Firmware/RTK_Everywhere/States.ino +++ b/Firmware/RTK_Everywhere/States.ino @@ -94,19 +94,11 @@ void stateUpdate() return; } - baseStatusLedOff(); - - // Configure for rover mode displayRoverStart(0); - if (gnss->configureRover() == false) - { - settings.gnssConfiguredRover = false; // On the next boot, reapply all settings - recordSystemSettings(); // Record this state for next POR - systemPrintln("Rover config failed"); - displayRoverFail(1000); - return; - } + baseStatusLedOff(); + + gnssConfigure(GNSS_CONFIG_ROVER); // Request reconfigure to rover mode setMuxport(settings.dataPortChannel); // Return mux to original channel @@ -116,23 +108,29 @@ void stateUpdate() baseCasterDisableOverride(); // Disable casting overrides // Start the UART connected to the GNSS receiver for NMEA data (enables logging) - if (tasksStartGnssUart() == false) - displayRoverFail(1000); - else + if (tasksStartGnssUart() == true) { - settings.gnssConfiguredBase = false; // When the mode changes, reapply all settings settings.lastState = STATE_ROVER_NOT_STARTED; recordSystemSettings(); // Record this state for next POR - displayRoverSuccess(500); - - changeState(STATE_ROVER_NO_FIX); + changeState(STATE_ROVER_CONFIG_WAIT); firstRoverStart = false; // Do not allow entry into test menu again } } break; + case (STATE_ROVER_CONFIG_WAIT): { + if (gnssConfigureComplete()) + { + systemPrintln("Rover configured"); + displayRoverSuccess(500); // Show 'Rover Started' + + changeState(STATE_ROVER_NO_FIX); + } + } + break; + case (STATE_ROVER_NO_FIX): { if (gnss->isFixed()) // 3D, 3D+DR changeState(STATE_ROVER_FIX); @@ -219,9 +217,11 @@ void stateUpdate() if (online.gnss == false) return; + displayBaseStart(0); // Show 'Base' + baseStatusLedOff(); - displayBaseStart(0); // Show 'Base' + gnssConfigure(GNSS_CONFIG_BASE); // Request reconfigure to rover mode bluetoothStop(); bluetoothStart(); // Restart Bluetooth with 'Base' identifier @@ -229,13 +229,20 @@ void stateUpdate() webServerStop(); // Stop the web config server // Start the UART connected to the GNSS receiver for NMEA data (enables logging) - if (tasksStartGnssUart() && gnss->configureBase()) + if (tasksStartGnssUart()) { - // settings.gnssConfiguredBase is set by gnss->configureBase() - settings.gnssConfiguredRover = false; // When the mode changes, reapply all settings settings.lastState = STATE_BASE_NOT_STARTED; // Record this state for next POR recordSystemSettings(); // Record this state for next POR + changeState(STATE_BASE_CONFIG_WAIT); + } + } + break; + + case (STATE_BASE_CONFIG_WAIT): { + if (gnssConfigureComplete()) + { + systemPrintln("Base configured"); displayBaseSuccess(500); // Show 'Base Started' if (settings.fixedBase == false) @@ -243,13 +250,6 @@ void stateUpdate() else changeState(STATE_BASE_FIXED_NOT_STARTED); } - else - { - settings.gnssConfiguredBase = false; // On the next boot, reapply all settings - recordSystemSettings(); // Record this state for next POR - - displayBaseFail(1000); - } } break; @@ -658,6 +658,8 @@ const char *getState(SystemState state, char *buffer) { case (STATE_ROVER_NOT_STARTED): return "STATE_ROVER_NOT_STARTED"; + case (STATE_ROVER_CONFIG_WAIT): + return "STATE_ROVER_CONFIG_WAIT"; case (STATE_ROVER_NO_FIX): return "STATE_ROVER_NO_FIX"; case (STATE_ROVER_FIX): @@ -670,6 +672,8 @@ const char *getState(SystemState state, char *buffer) return "STATE_BASE_CASTER_NOT_STARTED"; case (STATE_BASE_NOT_STARTED): return "STATE_BASE_NOT_STARTED"; + case (STATE_BASE_CONFIG_WAIT): + return "STATE_BASE_CONFIG_WAIT"; case (STATE_BASE_TEMP_SETTLE): return "STATE_BASE_TEMP_SETTLE"; case (STATE_BASE_TEMP_SURVEY_STARTED): diff --git a/Firmware/RTK_Everywhere/Tasks.ino b/Firmware/RTK_Everywhere/Tasks.ino index 3b4c4c8f0..291f0fec2 100644 --- a/Firmware/RTK_Everywhere/Tasks.ino +++ b/Firmware/RTK_Everywhere/Tasks.ino @@ -2201,11 +2201,13 @@ void buttonCheckTask(void *e) { // If we are in any running state, change to STATE_DISPLAY_SETUP case STATE_ROVER_NOT_STARTED: + case STATE_ROVER_CONFIG_WAIT: case STATE_ROVER_NO_FIX: case STATE_ROVER_FIX: case STATE_ROVER_RTK_FLOAT: case STATE_ROVER_RTK_FIX: case STATE_BASE_NOT_STARTED: + case STATE_BASE_CONFIG_WAIT: case STATE_BASE_TEMP_SETTLE: case STATE_BASE_TEMP_SURVEY_STARTED: case STATE_BASE_TEMP_TRANSMITTING: diff --git a/Firmware/RTK_Everywhere/settings.h b/Firmware/RTK_Everywhere/settings.h index 6acdccb5e..7afc722ea 100644 --- a/Firmware/RTK_Everywhere/settings.h +++ b/Firmware/RTK_Everywhere/settings.h @@ -15,39 +15,41 @@ typedef enum { STATE_ROVER_NOT_STARTED = 0, // 0 - STATE_ROVER_NO_FIX, // 1 - STATE_ROVER_FIX, // 2 - STATE_ROVER_RTK_FLOAT, // 3 - STATE_ROVER_RTK_FIX, // 4 - - STATE_BASE_CASTER_NOT_STARTED, // 5, Set override flag - STATE_BASE_NOT_STARTED, // 6 - STATE_BASE_TEMP_SETTLE, // 7, User has indicated base, but current pos accuracy is too low - STATE_BASE_TEMP_SURVEY_STARTED, // 8 - STATE_BASE_TEMP_TRANSMITTING, // 9 - STATE_BASE_FIXED_NOT_STARTED, // 10 - STATE_BASE_FIXED_TRANSMITTING, // 11 - - STATE_DISPLAY_SETUP, // 12 - STATE_WEB_CONFIG_NOT_STARTED, // 13 - STATE_WEB_CONFIG_WAIT_FOR_NETWORK, // 14 - STATE_WEB_CONFIG, // 15 - STATE_TEST, // 16 - STATE_TESTING, // 17 - STATE_PROFILE, // 18 - - STATE_KEYS_REQUESTED, // 19 - - STATE_ESPNOW_PAIRING_NOT_STARTED, // 20 - STATE_ESPNOW_PAIRING, // 21 - - STATE_NTPSERVER_NOT_STARTED, // 22 - STATE_NTPSERVER_NO_SYNC, // 23 - STATE_NTPSERVER_SYNC, // 24 - - STATE_SHUTDOWN, // 25 - - STATE_NOT_SET, // 26, Must be last on list + STATE_ROVER_CONFIG_WAIT, // 1 + STATE_ROVER_NO_FIX, // 2 + STATE_ROVER_FIX, // 3 + STATE_ROVER_RTK_FLOAT, // 4 + STATE_ROVER_RTK_FIX, // 5 + + STATE_BASE_CASTER_NOT_STARTED, // 6, Set override flag + STATE_BASE_NOT_STARTED, // 7 + STATE_BASE_CONFIG_WAIT, // 8 + STATE_BASE_TEMP_SETTLE, // 9, User has indicated base, but current pos accuracy is too low + STATE_BASE_TEMP_SURVEY_STARTED, // 10 + STATE_BASE_TEMP_TRANSMITTING, // 11 + STATE_BASE_FIXED_NOT_STARTED, // 12 + STATE_BASE_FIXED_TRANSMITTING, // 13 + + STATE_DISPLAY_SETUP, // 14 + STATE_WEB_CONFIG_NOT_STARTED, // 15 + STATE_WEB_CONFIG_WAIT_FOR_NETWORK, // 16 + STATE_WEB_CONFIG, // 17 + STATE_TEST, // 18 + STATE_TESTING, // 19 + STATE_PROFILE, // 20 + + STATE_KEYS_REQUESTED, // 21 + + STATE_ESPNOW_PAIRING_NOT_STARTED, // 22 + STATE_ESPNOW_PAIRING, // 23 + + STATE_NTPSERVER_NOT_STARTED, // 24 + STATE_NTPSERVER_NO_SYNC, // 25 + STATE_NTPSERVER_SYNC, // 26 + + STATE_SHUTDOWN, // 27 + + STATE_NOT_SET, // 28, Must be last on list } SystemState; volatile SystemState systemState = STATE_NOT_SET; SystemState lastSystemState = STATE_NOT_SET; From e8d510d378c1213ffc29373856a4ea10edab55b4 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 16 Oct 2025 16:33:29 -0600 Subject: [PATCH 22/68] Verify GNSS config table --- Firmware/RTK_Everywhere/GNSS.ino | 38 +++++++++++++++++++++++++---- Firmware/RTK_Everywhere/support.ino | 3 ++- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index 310b8cd6f..41b6995cf 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -32,8 +32,32 @@ enum GNSS_CONFIG_NONE, }; -uint32_t gnssConfigureRequest = - GNSS_CONFIG_NONE; // Bitfield containing an update be made to various settings on the GNSS receiver +static const char *gnssConfigDisplayNames[] = { + "ONCE", + "ROVER", + "BASE", + "BAUD_RATE_COMM", + "BAUD_RATE_RADIO", + "BAUD_RATE_DATA", + "RATE", + "CONSTELLATION", + "ELEVATION", + "CN0", + "PPS", + "MODEL", + "MESSAGE_RATE", + "MESSAGE_RATE_NMEA", + "MESSAGE_RATE_RTCM_ROVER", + "MESSAGE_RATE_RTCM_BASE", + "HAS_E6", + "MULTIPATH", + "TILT", + "DEBUG", + "SAVE", + "RESET", +}; + +static const int gnssConfigStateEntries = sizeof(gnssConfigDisplayNames) / sizeof(gnssConfigDisplayNames[0]); extern int NTRIPCLIENT_MS_BETWEEN_GGA; @@ -227,9 +251,13 @@ void gnssUpdate() systemPrintln("gnssUpdate: Uncaught mode change"); } - // We do not clear the request bits here. Instead, if bits are still set, the next update will attempt to - // service them. - } +//---------------------------------------- +// Verify the GNSS tables +//---------------------------------------- +void gnssVerifyTables() +{ + if (gnssConfigStateEntries != GNSS_CONFIG_MAX) + reportFatalError("Fix gnssConfigStateEntries to match GNSS Config Enum"); } // Given a bit to configure, set that bit in the overall bitfield diff --git a/Firmware/RTK_Everywhere/support.ino b/Firmware/RTK_Everywhere/support.ino index 7f61574b7..c772f3eba 100644 --- a/Firmware/RTK_Everywhere/support.ino +++ b/Firmware/RTK_Everywhere/support.ino @@ -751,7 +751,8 @@ void verifyTables() webServerVerifyTables(); pointPerfectVerifyTables(); wifiVerifyTables(); - + gnssVerifyTables(); + if (CORR_NUM >= (int)('x' - 'a')) reportFatalError("Too many correction sources"); } From 567bb3d765cf821b63ccc27503dbd60cc9a21e43 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 16 Oct 2025 16:34:02 -0600 Subject: [PATCH 23/68] Add debugGnssConfig setting --- Firmware/RTK_Everywhere/menuSystem.ino | 8 ++++++++ Firmware/RTK_Everywhere/settings.h | 5 ++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Firmware/RTK_Everywhere/menuSystem.ino b/Firmware/RTK_Everywhere/menuSystem.ino index c8cb940e2..9fd573e9e 100644 --- a/Firmware/RTK_Everywhere/menuSystem.ino +++ b/Firmware/RTK_Everywhere/menuSystem.ino @@ -521,6 +521,9 @@ void menuDebugHardware() systemPrintf("20) Delay between CLI LIST prints over BLE: %d\r\n", settings.cliBlePrintDelay_ms); + systemPrint("21) Print GNSS Config Debugging: "); + systemPrintf("%s\r\n", settings.debugGnssConfig ? "Enabled" : "Disabled"); + systemPrintln("e) Erase LittleFS"); systemPrintln("t) Test Screen"); @@ -643,6 +646,11 @@ void menuDebugHardware() } } + else if (incoming == 21) + { + settings.debugGnssConfig ^= 1; + } + else if (incoming == 'e') { systemPrintln("Erasing LittleFS and resetting"); diff --git a/Firmware/RTK_Everywhere/settings.h b/Firmware/RTK_Everywhere/settings.h index 7afc722ea..a9220d695 100644 --- a/Firmware/RTK_Everywhere/settings.h +++ b/Firmware/RTK_Everywhere/settings.h @@ -1117,6 +1117,8 @@ struct Settings bool baseCasterOverride = false; //When true, user has put device into 'BaseCast' mode. Change settings, but don't save to NVM. bool debugCLI = false; //When true, output BLE CLI interactions over serial uint16_t cliBlePrintDelay_ms = 50; // Time delayed between prints during a LIST command to avoid overwhelming the BLE connection + uint32_t gnssConfigureRequest = 0; // Bitfield containing the change requests for various settings on the GNSS receiver + bool debugGnssConfig = false; // Enable to print output during gnssUpdate // Add new settings to appropriate group above or create new group // Then also add to the same group in rtkSettingsEntries below @@ -1445,6 +1447,7 @@ const RTK_Settings_Entry rtkSettingsEntries[] = // GNSS Receiver { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.debugGnss, "debugGnss", nullptr, }, + { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.debugGnssConfig, "debugGnssConfig", nullptr, }, { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.enablePrintPosition, "enablePrintPosition", nullptr, }, { 0, 1, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _uint16_t, 0, & settings.measurementRateMs, "measurementRateMs", nullptr, }, { 0, 1, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _uint16_t, 0, & settings.navigationRate, "navigationRate", nullptr, }, @@ -1850,7 +1853,7 @@ const RTK_Settings_Entry rtkSettingsEntries[] = { 0, 1, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.baseCasterOverride, "baseCasterOverride", nullptr, }, { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.debugCLI, "debugCLI", nullptr, }, { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _uint16_t, 0, & settings.cliBlePrintDelay_ms, "cliBlePrintDelay_ms", nullptr, }, - + { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _uint32_t, 0, & settings.gnssConfigureRequest, "gnssConfigureRequest", nullptr, }, // Add new settings to appropriate group above or create new group // Then also add to the same group in settings above From 5529d55e39d2ef091cdaffeb06a3dbe2d3350cf0 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 16 Oct 2025 16:34:22 -0600 Subject: [PATCH 24/68] Remove GNSS direct config from Ports menu --- Firmware/RTK_Everywhere/menuPorts.ino | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/Firmware/RTK_Everywhere/menuPorts.ino b/Firmware/RTK_Everywhere/menuPorts.ino index 230ab4616..96c917e2f 100644 --- a/Firmware/RTK_Everywhere/menuPorts.ino +++ b/Firmware/RTK_Everywhere/menuPorts.ino @@ -115,8 +115,6 @@ void menuPortsNoMux() if (gnss->baudIsAllowed(newBaud)) { settings.dataPortBaud = newBaud; - if (online.gnss == true) - gnss->setBaudRateData(newBaud); } else { @@ -155,12 +153,8 @@ void menuPortsNoMux() printUnknown(incoming); } - if (present.gnss_lg290p) - { - // All platforms, except the LG290P can modify their baud rates immediately. - // The LG290P requires a reset for settings to take effect - gnssConfigure(GNSS_CONFIG_BAUD_RATE); // Request receiver to use new settings - } + gnssConfigure(GNSS_CONFIG_BAUD_RATE_RADIO); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_BAUD_RATE_DATA); // Request receiver to use new settings clearBuffer(); // Empty buffer of any newline chars } @@ -268,8 +262,6 @@ void menuPortsMultiplexed() if (gnss->baudIsAllowed(newBaud)) { settings.dataPortBaud = newBaud; - if (online.gnss == true) - gnss->setBaudRateData(newBaud); } else { @@ -312,15 +304,11 @@ void menuPortsMultiplexed() clearBuffer(); // Empty buffer of any newline chars - if (present.gnss_mosaicX5) - { - // Apply these changes at menu exit - to enable message output on USB1 - // and/or enable/disable NMEA on radio - gnssConfigure(GNSS_CONFIG_BAUD_RATE); // Request receiver to use new settings - } - gnss->beginExternalEvent(); // Update with new settings - gnssConfigure(GNSS_CONFIG_PPS); // Request receiver to use new settings + + gnssConfigure(GNSS_CONFIG_PPS); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_BAUD_RATE_RADIO); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_BAUD_RATE_DATA); // Request receiver to use new settings } // Configure the behavior of the PPS and INT pins. From a736a811266ff8ee1bc1062f29e4a8a7058694f7 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 16 Oct 2025 16:35:57 -0600 Subject: [PATCH 25/68] Remove gnss->configure from setup --- Firmware/RTK_Everywhere/GNSS.ino | 17 ----------------- Firmware/RTK_Everywhere/RTK_Everywhere.ino | 7 +++++-- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index 41b6995cf..5d2a06dd8 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -67,23 +67,6 @@ extern NetworkClient *ntripClient; extern unsigned long lastGGAPush; -//---------------------------------------- -// Setup the general configuration of the GNSS -// Not Rover or Base specific (ie, baud rates) -// Returns true if successfully configured and false otherwise -//---------------------------------------- -bool GNSS::configure() -{ - if (online.gnss == false) - return (false); - - // Check various setting arrays (message rates, etc) to see if they need to be reset to defaults - checkGNSSArrayDefaults(); - - // Configure the GNSS receiver - return configureGNSS(); -} - //---------------------------------------- // Get the minimum satellite signal level for navigation. //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/RTK_Everywhere.ino b/Firmware/RTK_Everywhere/RTK_Everywhere.ino index c757a0537..136f7bb1d 100644 --- a/Firmware/RTK_Everywhere/RTK_Everywhere.ino +++ b/Firmware/RTK_Everywhere/RTK_Everywhere.ino @@ -1349,6 +1349,9 @@ void setup() checkArrayDefaults(); // Check for uninitialized arrays that won't be initialized by gnssConfigure // (checkGNSSArrayDefaults) + checkGNSSArrayDefaults(); // Check various setting arrays (message rates, etc) to see if they need to be reset to + // defaults + DMW_b("printPartitionTable"); if (settings.printPartitionTable) printPartitionTable(); @@ -1368,8 +1371,8 @@ void setup() DMW_b("beginCharger"); beginCharger(); // Configure battery charger - DMW_b("gnss->configure"); - gnss->configure(); // Requires settings. Configure GNSS module + // DMW_b("gnss->configure"); + // gnss->configure(); // Requires settings. Configure GNSS module DMW_b("beginExternalEvent"); gnss->beginExternalEvent(); // Configure the event input From c20e5127b8437dd8fad6dbe827d1bfe9619678ba Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 16 Oct 2025 16:36:52 -0600 Subject: [PATCH 26/68] Prelim UM980 non-blocking configuration support --- Firmware/RTK_Everywhere/GNSS.h | 11 +- Firmware/RTK_Everywhere/GNSS.ino | 145 +++-- Firmware/RTK_Everywhere/GNSS_LG290P.h | 5 +- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 12 +- Firmware/RTK_Everywhere/GNSS_Mosaic.h | 5 +- Firmware/RTK_Everywhere/GNSS_Mosaic.ino | 12 +- Firmware/RTK_Everywhere/GNSS_None.h | 27 +- Firmware/RTK_Everywhere/GNSS_UM980.h | 680 +++++++++++------------- Firmware/RTK_Everywhere/GNSS_UM980.ino | 294 ++++------ Firmware/RTK_Everywhere/GNSS_ZED.h | 5 +- Firmware/RTK_Everywhere/GNSS_ZED.ino | 11 +- 11 files changed, 593 insertions(+), 614 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.h b/Firmware/RTK_Everywhere/GNSS.h index e461132f5..3b84d7453 100644 --- a/Firmware/RTK_Everywhere/GNSS.h +++ b/Firmware/RTK_Everywhere/GNSS.h @@ -43,12 +43,6 @@ class GNSS unsigned long _autoBaseStartTimer; // Tracks how long the base auto / averaging mode has been running - // Setup the general configuration of the GNSS - // Not Rover or Base specific (ie, baud rates) - // Outputs: - // Returns true if successfully configured and false upon failure - virtual bool configureGNSS(); - public: // Constructor GNSS() : _leapSeconds(18), _pvtArrivalMillis(0), _pvtUpdated(0), _satellitesInView(0) @@ -86,7 +80,7 @@ class GNSS // Not Rover or Base specific (ie, baud rates) // Outputs: // Returns true if successfully configured and false upon failure - bool configure(); + virtual bool configure(); // Configure the Base // Outputs: @@ -378,6 +372,9 @@ class GNSS virtual bool setTalkerGNGGA(); + // Enable/disable any output needed for tilt compensation + virtual bool setTilt(); + // Hotstart GNSS to try to get RTK lock virtual bool softwareReset(); diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index 5d2a06dd8..1fddcac82 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -9,9 +9,12 @@ GNSS.ino // the menu system, closed the Web Config, or the CLI is closed. enum { + GNSS_CONFIG_ONCE, // Settings specific to a receiver that don't fit into other setting categories GNSS_CONFIG_ROVER, GNSS_CONFIG_BASE, // Fixed base or survey in, location, etc - GNSS_CONFIG_BAUD_RATE, + GNSS_CONFIG_BAUD_RATE_COMM, + GNSS_CONFIG_BAUD_RATE_RADIO, + GNSS_CONFIG_BAUD_RATE_DATA, GNSS_CONFIG_RATE, GNSS_CONFIG_CONSTELLATION, // Turn on/off a constellation GNSS_CONFIG_ELEVATION, @@ -24,12 +27,12 @@ enum GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE, // Update RTCM Base message rates GNSS_CONFIG_HAS_E6, // Enable/disable HAS E6 capabilities GNSS_CONFIG_MULTIPATH, + GNSS_CONFIG_TILT, // Enable/disable any output needed for tilt compensation GNSS_CONFIG_SAVE, // Indicates current settings be saved to GNSS receiver NVM GNSS_CONFIG_RESET, // Indicates receiver needs resetting // Add new entries above here - GNSS_CONFIG_LAST, - GNSS_CONFIG_NONE, + GNSS_CONFIG_MAX, }; static const char *gnssConfigDisplayNames[] = { @@ -112,22 +115,58 @@ void gnssUpdate() // Allow the GNSS platform to update itself gnss->update(); - // In general, the GNSS configuration should only be modified here, not in menus, not in commands - // Those should trigger a request for modification + if (settings.gnssConfigureRequest == 0) + return; // No configuration requests // Handle any requested configuration changes // Only update the GNSS receiver once the CLI, serial menu, and Web Config interfaces are disconnected // This is to avoid multiple reconfigure delays when multiple commands are received, ie enable GPS, disable Galileo, // should only trigger one GNSS reconfigure - if (gnssConfigureRequest != GNSS_CONFIG_NONE && bluetoothCommandIsConnected() == false && inMainMenu == false && - inWebConfigMode() == false) + if (bluetoothCommandIsConnected() == false && inMainMenu == false && inWebConfigMode() == false) { bool result = true; // Service requests // Clear the requests as they are completed successfully + // If a platform requires a device reset to complete the config (ie, LG290P changing constellations) then + // the platform specific function should call gnssConfigure(GNSS_CONFIG_RESET) - if (gnssConfigureRequest & GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE) + if (gnssConfigureRequested(GNSS_CONFIG_ONCE)) + { + if (gnss->configure() == true) + { + gnssConfigureClear(GNSS_CONFIG_ONCE); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } + } + + if (gnssConfigureRequested(GNSS_CONFIG_ROVER)) + { + if (gnss->configureRover() == true) + { + gnssConfigureClear(GNSS_CONFIG_ROVER); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } + else + { + systemPrintln("Rover config failed"); + } + } + + if (gnssConfigureRequested(GNSS_CONFIG_BASE)) + { + if (gnss->configureBase() == true) + { + gnssConfigureClear(GNSS_CONFIG_BASE); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } + else + { + systemPrintln("Base config failed"); + } + } + + if (gnssConfigureRequested(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE)) { if (gnss->setMessagesRTCMBase() == true) { @@ -136,7 +175,7 @@ void gnssUpdate() } } - if (gnssConfigureRequest & GNSS_CONFIG_CONSTELLATION) + if (gnssConfigureRequested(GNSS_CONFIG_CONSTELLATION)) { if (gnss->setConstellations() == true) { @@ -145,7 +184,7 @@ void gnssUpdate() } } - if (gnssConfigureRequest & GNSS_CONFIG_ELEVATION) + if (gnssConfigureRequested(GNSS_CONFIG_ELEVATION)) { if (gnss->setElevation(settings.minElev) == true) { @@ -154,7 +193,7 @@ void gnssUpdate() } } - if (gnssConfigureRequest & GNSS_CONFIG_CN0) + if (gnssConfigureRequested(GNSS_CONFIG_CN0)) { if (gnss->setMinCno(settings.minCNO) == true) { @@ -163,7 +202,7 @@ void gnssUpdate() } } - if (gnssConfigureRequest & GNSS_CONFIG_PPS) + if (gnssConfigureRequested(GNSS_CONFIG_PPS)) { if (gnss->setPPS() == true) { @@ -172,7 +211,7 @@ void gnssUpdate() } } - if (gnssConfigureRequest & GNSS_CONFIG_MODEL) + if (gnssConfigureRequested(GNSS_CONFIG_MODEL)) { if (gnss->setModel(settings.dynamicModel) == true) { @@ -181,7 +220,7 @@ void gnssUpdate() } } - if (gnssConfigureRequest & GNSS_CONFIG_HAS_E6) + if (gnssConfigureRequested(GNSS_CONFIG_HAS_E6)) { if (gnss->setHighAccuracyService(settings.enableGalileoHas) == true) { @@ -190,7 +229,7 @@ void gnssUpdate() } } - if (gnssConfigureRequest & GNSS_CONFIG_MULTIPATH) + if (gnssConfigureRequested(GNSS_CONFIG_MULTIPATH)) { if (gnss->setMultipathMitigation(settings.enableMultipathMitigation) == true) { @@ -199,40 +238,28 @@ void gnssUpdate() } } - // Platforms will set the GNSS_CONFIG_SAVE and GNSS_CONFIG_RESET bits appropriately for each command issued + if (gnssConfigureRequested(GNSS_CONFIG_TILT)) + { + if (gnss->setTilt() == true) + { + gnssConfigureClear(GNSS_CONFIG_TILT); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } + } - // If one of the previous configuration changes requested save to NVM, do so - if (gnssConfigureRequest & GNSS_CONFIG_SAVE) + // Save changes to NVM + if (gnssConfigureRequested(GNSS_CONFIG_SAVE)) { if (gnss->saveConfiguration()) gnssConfigureClear(GNSS_CONFIG_SAVE); } - // Here we need a table to determine if the given combination of setting requests require a GNSS reset to take - // effect + // If gnssConfigureRequest bits are still set, the next update will attempt to service them. - // For now we will maintain the previous approach of, if any setting gets changed, re-start in the current mode - // and use the settings currently in the ESP32 NVM - - // Restart current state to reconfigure receiver - systemPrintln("Restarting GNSS receiver with new settings"); - if (inBaseMode() == true) - { - settings.gnssConfiguredRover = false; // Reapply configuration - requestChangeState(STATE_BASE_NOT_STARTED); // Restart base for latest changes to take effect - } - else if (inRoverMode() == true) - { - settings.gnssConfiguredRover = false; // Reapply configuration - // TODO when does GNSS configured rover go true? - requestChangeState(STATE_ROVER_NOT_STARTED); // Restart rover for latest changes to take effect - } - // else if (inWebConfigMode() == true) {} - // else if (inNtpMode() == true) {} - else - { - systemPrintln("gnssUpdate: Uncaught mode change"); - } + // settings.gnssConfigureRequest was likely changed. Record the current config state to ESP32 NVM + recordSystemSettings(); + } // end bluetoothCommandIsConnected(), inMainMenu, inWebConfigMode() +} //---------------------------------------- // Verify the GNSS tables @@ -247,21 +274,49 @@ void gnssVerifyTables() void gnssConfigure(uint8_t configureBit) { uint32_t mask = (1 << configureBit); - gnssConfigureRequest |= mask; + settings.gnssConfigureRequest |= mask; } // Given a bit to configure, clear that bit from the overall bitfield void gnssConfigureClear(uint8_t configureBit) { uint32_t mask = ~(1 << configureBit); - gnssConfigureRequest &= mask; + + if (settings.debugGnssConfig && (settings.gnssConfigureRequest & mask)) + systemPrintf("GNSS Config Clear: %s\r\n", gnssConfigDisplayNames[configureBit]); + + settings.gnssConfigureRequest &= mask; +} + +// Return true if a given bit is set +bool gnssConfigureRequested(uint8_t configureBit) +{ + uint32_t mask = (1 << configureBit); + + if (settings.debugGnssConfig && (settings.gnssConfigureRequest & mask)) + systemPrintf("GNSS Config Request: %s\r\n", gnssConfigDisplayNames[configureBit]); + + return (settings.gnssConfigureRequest & mask); } // Set all bits in the request bitfield to cause the GNSS receiver to go through a full (re)configuration void gnssConfigureAll() { - for (int x = 0; x < GNSS_CONFIG_LAST; x++) + for (int x = 0; x < GNSS_CONFIG_MAX; x++) gnssConfigure(x); + + // After setting all bits, clear the base bits + // TODO make this a GNSS_CONFIG_MODEf + gnssConfigureClear(GNSS_CONFIG_BASE); + gnssConfigureClear(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); +} + +// Returns true once all configuration requests are cleared +bool gnssConfigureComplete() +{ + if (settings.gnssConfigureRequest == 0) + return (true); + return (false); } //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.h b/Firmware/RTK_Everywhere/GNSS_LG290P.h index 7ebf16b8b..3050f4e67 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.h +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.h @@ -82,7 +82,7 @@ class GNSS_LG290P : GNSS // Not Rover or Base specific (ie, baud rates) // Outputs: // Returns true if successfully configured and false upon failure - bool configureGNSS(); + bool configure(); uint8_t getActiveNmeaMessageCount(); @@ -444,6 +444,9 @@ class GNSS_LG290P : GNSS bool setTalkerGNGGA(); + // Enable/disable any output needed for tilt compensation + bool setTilt(); + // Hotstart GNSS to try to get RTK lock bool softwareReset(); diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index 1e40f9322..61f2851e8 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -180,7 +180,7 @@ bool GNSS_LG290P::checkPPPRates() // Setup the GNSS module for any setup (base or rover) // In general we check if the setting is different than setting stored in NVM before writing it. //---------------------------------------- -bool GNSS_LG290P::configureGNSS() +bool GNSS_LG290P::configure() { for (int x = 0; x < 3; x++) { @@ -2529,6 +2529,16 @@ bool GNSS_LG290P::setTalkerGNGGA() return false; } +//---------------------------------------- +// Enable/disable any output needed for tilt compensation +//---------------------------------------- +bool GNSS_LG290P::setTilt() +{ + // Not yet available on this platform + return false; +} + + //---------------------------------------- // Reset GNSS via software command // Poll for isConnected() diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.h b/Firmware/RTK_Everywhere/GNSS_Mosaic.h index 382ce69b9..1f6a7a45c 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.h +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.h @@ -524,7 +524,7 @@ class GNSS_MOSAIC : GNSS // Not Rover or Base specific (ie, baud rates) // Outputs: // Returns true if successfully configured and false upon failure - bool configureGNSS(); + bool configure(); // Set the minimum satellite signal level for navigation. bool setMinCno(uint8_t cnoValue); @@ -1021,6 +1021,9 @@ class GNSS_MOSAIC : GNSS bool setTalkerGNGGA(); + // Enable/disable any output needed for tilt compensation + bool setTilt(); + // Hotstart GNSS to try to get RTK lock bool softwareReset(); diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino index 918223ae1..c37ef703f 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino @@ -670,7 +670,7 @@ bool GNSS_MOSAIC::configureOnce() // Outputs: // Returns true if successfully configured and false upon failure //---------------------------------------- -bool GNSS_MOSAIC::configureGNSS() +bool GNSS_MOSAIC::configure() { // Attempt 3 tries on MOSAICX5 config for (int x = 0; x < 3; x++) @@ -2534,6 +2534,16 @@ bool GNSS_MOSAIC::setTalkerGNGGA() return sendWithResponse("snti,GN\n\r", "NMEATalkerID"); } +//---------------------------------------- +// Enable/disable any output needed for tilt compensation +//---------------------------------------- +bool GNSS_MOSAIC::setTilt() +{ + // Not yet available on this platform + return false; +} + + //---------------------------------------- // Hotstart GNSS to try to get RTK lock //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/GNSS_None.h b/Firmware/RTK_Everywhere/GNSS_None.h index c45eb2aee..51ed452bf 100644 --- a/Firmware/RTK_Everywhere/GNSS_None.h +++ b/Firmware/RTK_Everywhere/GNSS_None.h @@ -9,23 +9,14 @@ GNSS_None.h class GNSS_None : public GNSS { -protected: - // Setup the general configuration of the GNSS - // Not Rover or Base specific (ie, baud rates) - // Outputs: - // Returns true if successfully configured and false upon failure - bool configureGNSS() - { - return false; - } - + protected: // Set the minimum satellite signal level for navigation. bool setMinCno(uint8_t cnoValue) { return false; } -public: + public: // Constructor GNSS_None() : GNSS() { @@ -84,6 +75,15 @@ class GNSS_None : public GNSS return false; } + // Setup the general configuration of the GNSS + // Not Rover or Base specific (ie, baud rates) + // Outputs: + // Returns true if successfully configured and false upon failure + bool configure() + { + return false; + } + // Configure the Base // Outputs: // Returns true if successfully configured and false upon failure @@ -625,6 +625,11 @@ class GNSS_None : public GNSS return true; } + bool setTilt() + { + return true; + } + // Hotstart GNSS to try to get RTK lock bool softwareReset() { diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.h b/Firmware/RTK_Everywhere/GNSS_UM980.h index 7aa31ecf8..5e56844eb 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.h +++ b/Firmware/RTK_Everywhere/GNSS_UM980.h @@ -25,19 +25,15 @@ GNSS_UM980.h // Each constellation will have its config command text, enable, and a visible name typedef struct { - char textName[30]; - char textCommand[5]; + char textName[30]; + char textCommand[5]; } um980ConstellationCommand; // Constellations monitored/used for fix // Available constellations: GPS, BDS, GLO, GAL, QZSS // SBAS and IRNSS don't seem to be supported const um980ConstellationCommand um980ConstellationCommands[] = { - {"BeiDou", "BDS"}, - {"Galileo", "GAL"}, - {"GLONASS", "GLO"}, - {"GPS", "GPS"}, - {"QZSS", "QZSS"}, + {"BeiDou", "BDS"}, {"Galileo", "GAL"}, {"GLONASS", "GLO"}, {"GPS", "GPS"}, {"QZSS", "QZSS"}, }; #define MAX_UM980_CONSTELLATIONS (sizeof(um980ConstellationCommands) / sizeof(um980ConstellationCommand)) @@ -46,100 +42,51 @@ const um980ConstellationCommand um980ConstellationCommands[] = { // Each message will have the serial command and its default value typedef struct { - const char msgTextName[9]; - const float msgDefaultRate; + const char msgTextName[9]; + const float msgDefaultRate; } um980Msg; // Static array containing all the compatible messages // Rate = Reports per second const um980Msg umMessagesNMEA[] = { // NMEA - {"GPDTM", 0}, - {"GPGBS", 0}, - {"GPGGA", 0.5}, - {"GPGLL", 0}, - {"GPGNS", 0}, - - {"GPGRS", 0}, - {"GPGSA", 0.5}, - {"GPGST", 0.5}, - {"GPGSV", 1}, - {"GPRMC", 0.5}, - - {"GPROT", 0}, - {"GPTHS", 0}, - {"GPVTG", 0}, - {"GPZDA", 0}, + {"GPDTM", 0}, {"GPGBS", 0}, {"GPGGA", 0.5}, {"GPGLL", 0}, {"GPGNS", 0}, + + {"GPGRS", 0}, {"GPGSA", 0.5}, {"GPGST", 0.5}, {"GPGSV", 1}, {"GPRMC", 0.5}, + + {"GPROT", 0}, {"GPTHS", 0}, {"GPVTG", 0}, {"GPZDA", 0}, }; const um980Msg umMessagesRTCM[] = { // RTCM - {"RTCM1001", 0}, - {"RTCM1002", 0}, - {"RTCM1003", 0}, - {"RTCM1004", 0}, - {"RTCM1005", 1}, - {"RTCM1006", 0}, - {"RTCM1007", 0}, - {"RTCM1009", 0}, - {"RTCM1010", 0}, - - {"RTCM1011", 0}, - {"RTCM1012", 0}, - {"RTCM1013", 0}, - {"RTCM1019", 0}, + {"RTCM1001", 0}, {"RTCM1002", 0}, {"RTCM1003", 0}, {"RTCM1004", 0}, {"RTCM1005", 1}, + {"RTCM1006", 0}, {"RTCM1007", 0}, {"RTCM1009", 0}, {"RTCM1010", 0}, + + {"RTCM1011", 0}, {"RTCM1012", 0}, {"RTCM1013", 0}, {"RTCM1019", 0}, {"RTCM1020", 0}, {"RTCM1033", 10}, - {"RTCM1042", 0}, - {"RTCM1044", 0}, - {"RTCM1045", 0}, - {"RTCM1046", 0}, - - {"RTCM1071", 0}, - {"RTCM1072", 0}, - {"RTCM1073", 0}, - {"RTCM1074", 1}, - {"RTCM1075", 0}, - {"RTCM1076", 0}, - {"RTCM1077", 0}, - - {"RTCM1081", 0}, - {"RTCM1082", 0}, - {"RTCM1083", 0}, - {"RTCM1084", 1}, - {"RTCM1085", 0}, - {"RTCM1086", 0}, - {"RTCM1087", 0}, - - {"RTCM1091", 0}, - {"RTCM1092", 0}, - {"RTCM1093", 0}, - {"RTCM1094", 1}, - {"RTCM1095", 0}, - {"RTCM1096", 0}, - {"RTCM1097", 0}, + {"RTCM1042", 0}, {"RTCM1044", 0}, {"RTCM1045", 0}, {"RTCM1046", 0}, + + {"RTCM1071", 0}, {"RTCM1072", 0}, {"RTCM1073", 0}, {"RTCM1074", 1}, {"RTCM1075", 0}, + {"RTCM1076", 0}, {"RTCM1077", 0}, + + {"RTCM1081", 0}, {"RTCM1082", 0}, {"RTCM1083", 0}, {"RTCM1084", 1}, {"RTCM1085", 0}, + {"RTCM1086", 0}, {"RTCM1087", 0}, + + {"RTCM1091", 0}, {"RTCM1092", 0}, {"RTCM1093", 0}, {"RTCM1094", 1}, {"RTCM1095", 0}, + {"RTCM1096", 0}, {"RTCM1097", 0}, {"RTCM1104", 0}, - {"RTCM1111", 0}, - {"RTCM1112", 0}, - {"RTCM1113", 0}, - {"RTCM1114", 0}, - {"RTCM1115", 0}, - {"RTCM1116", 0}, - {"RTCM1117", 0}, - - {"RTCM1121", 0}, - {"RTCM1122", 0}, - {"RTCM1123", 0}, - {"RTCM1124", 1}, - {"RTCM1125", 0}, - {"RTCM1126", 0}, - {"RTCM1127", 0}, + {"RTCM1111", 0}, {"RTCM1112", 0}, {"RTCM1113", 0}, {"RTCM1114", 0}, {"RTCM1115", 0}, + {"RTCM1116", 0}, {"RTCM1117", 0}, + + {"RTCM1121", 0}, {"RTCM1122", 0}, {"RTCM1123", 0}, {"RTCM1124", 1}, {"RTCM1125", 0}, + {"RTCM1126", 0}, {"RTCM1127", 0}, }; #define MAX_UM980_NMEA_MSG (sizeof(umMessagesNMEA) / sizeof(um980Msg)) @@ -147,406 +94,409 @@ const um980Msg umMessagesRTCM[] = { enum um980_Models { - UM980_DYN_MODEL_SURVEY = 0, - UM980_DYN_MODEL_UAV, - UM980_DYN_MODEL_AUTOMOTIVE, + UM980_DYN_MODEL_SURVEY = 0, + UM980_DYN_MODEL_UAV, + UM980_DYN_MODEL_AUTOMOTIVE, }; class GNSS_UM980 : GNSS { -private: - UM980 *_um980; // Library class instance + private: + UM980 *_um980; // Library class instance + + protected: + bool configureOnce(); -protected: - bool configureOnce(); + // Setup the general configuration of the GNSS + // Not Rover or Base specific (ie, baud rates) + // Outputs: + // Returns true if successfully configured and false upon failure + bool configure(); - // Setup the general configuration of the GNSS - // Not Rover or Base specific (ie, baud rates) - // Outputs: - // Returns true if successfully configured and false upon failure - bool configureGNSS(); + // Turn off all NMEA and RTCM + void disableAllOutput(); - // Turn off all NMEA and RTCM - void disableAllOutput(); + // Disable all output, then re-enable + void disableRTCM(); - // Disable all output, then re-enable - void disableRTCM(); + uint8_t getActiveNmeaMessageCount(); - uint8_t getActiveNmeaMessageCount(); + // Given the name of an NMEA message, return the array number + uint8_t getNmeaMessageNumberByName(const char *msgName); - // Given the name of an NMEA message, return the array number - uint8_t getNmeaMessageNumberByName(const char *msgName); + // Given the name of an RTCM message, return the array number + uint8_t getRtcmMessageNumberByName(const char *msgName); - // Given the name of an RTCM message, return the array number - uint8_t getRtcmMessageNumberByName(const char *msgName); + // Return true if the GPGGA message is active + bool isGgaActive(); - // Return true if the GPGGA message is active - bool isGgaActive(); + // Given a sub type (ie "RTCM", "NMEA") present menu showing messages with this subtype + // Controls the messages that get broadcast over Bluetooth and logged (if enabled) + void menuMessagesSubtype(float *localMessageRate, const char *messageType); - // Given a sub type (ie "RTCM", "NMEA") present menu showing messages with this subtype - // Controls the messages that get broadcast over Bluetooth and logged (if enabled) - void menuMessagesSubtype(float *localMessageRate, const char *messageType); + bool setHighAccuracyService(bool enableGalileoHas); - bool setHighAccuracyService(bool enableGalileoHas); + // Set the minimum satellite signal level for navigation. + bool setMinCno(uint8_t cnoValue); - // Set the minimum satellite signal level for navigation. - bool setMinCno(uint8_t cnoValue); + public: + // Constructor + GNSS_UM980() : GNSS() + { + } -public: - // Constructor - GNSS_UM980() : GNSS() - { - } + // If we have decryption keys, configure module + // Note: don't check online.lband_neo here. We could be using ip corrections + void applyPointPerfectKeys(); - // If we have decryption keys, configure module - // Note: don't check online.lband_neo here. We could be using ip corrections - void applyPointPerfectKeys(); + // Set RTCM for base mode to defaults (1005/1074/1084/1094/1124 1Hz & 1230 0.1Hz) + void baseRtcmDefault(); - // Set RTCM for base mode to defaults (1005/1074/1084/1094/1124 1Hz & 1230 0.1Hz) - void baseRtcmDefault(); + // Reset to Low Bandwidth Link (1074/1084/1094/1124 0.5Hz & 1005/1230 0.1Hz) + void baseRtcmLowDataRate(); - // Reset to Low Bandwidth Link (1074/1084/1094/1124 0.5Hz & 1005/1230 0.1Hz) - void baseRtcmLowDataRate(); + // Check if a given baud rate is supported by this module + bool baudIsAllowed(uint32_t baudRate); + uint32_t baudGetMinimum(); + uint32_t baudGetMaximum(); - // Check if a given baud rate is supported by this module - bool baudIsAllowed(uint32_t baudRate); - uint32_t baudGetMinimum(); - uint32_t baudGetMaximum(); + // Connect to GNSS and identify particulars + void begin(); - // Connect to GNSS and identify particulars - void begin(); + // Setup TM2 time stamp input as need + // Outputs: + // Returns true when an external event occurs and false if no event + bool beginExternalEvent(); - // Setup TM2 time stamp input as need - // Outputs: - // Returns true when an external event occurs and false if no event - bool beginExternalEvent(); + bool checkNMEARates(); - bool checkNMEARates(); + bool checkPPPRates(); - bool checkPPPRates(); + // Configure the Base + // Outputs: + // Returns true if successfully configured and false upon failure + bool configureBase(); - // Configure the Base - // Outputs: - // Returns true if successfully configured and false upon failure - bool configureBase(); + // Configure specific aspects of the receiver for NTP mode + bool configureNtpMode(); - // Configure specific aspects of the receiver for NTP mode - bool configureNtpMode(); + // Configure the Rover + // Outputs: + // Returns true if successfully configured and false upon failure + bool configureRover(); - // Configure the Rover - // Outputs: - // Returns true if successfully configured and false upon failure - bool configureRover(); + // Responds with the messages supported on this platform + // Inputs: + // returnText: String to receive message names + // Returns message names in the returnText string + void createMessageList(String &returnText); - // Responds with the messages supported on this platform - // Inputs: - // returnText: String to receive message names - // Returns message names in the returnText string - void createMessageList(String &returnText); + // Responds with the RTCM/Base messages supported on this platform + // Inputs: + // returnText: String to receive message names + // Returns message names in the returnText string + void createMessageListBase(String &returnText); - // Responds with the RTCM/Base messages supported on this platform - // Inputs: - // returnText: String to receive message names - // Returns message names in the returnText string - void createMessageListBase(String &returnText); + void debuggingDisable(); - void debuggingDisable(); + void debuggingEnable(); - void debuggingEnable(); + void enableGgaForNtrip(); - void enableGgaForNtrip(); + // Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted + // even if there is no GPS fix. We use it to test serial output. + // Outputs: + // Returns true if successfully started and false upon failure + bool enableRTCMTest(); - // Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted - // even if there is no GPS fix. We use it to test serial output. - // Outputs: - // Returns true if successfully started and false upon failure - bool enableRTCMTest(); + // Restore the GNSS to the factory settings + void factoryReset(); - // Restore the GNSS to the factory settings - void factoryReset(); + uint16_t fileBufferAvailable(); - uint16_t fileBufferAvailable(); + uint16_t fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead); - uint16_t fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead); + // Start the base using fixed coordinates + // Outputs: + // Returns true if successfully started and false upon failure + bool fixedBaseStart(); - // Start the base using fixed coordinates - // Outputs: - // Returns true if successfully started and false upon failure - bool fixedBaseStart(); + // Return the number of active/enabled messages + uint8_t getActiveMessageCount(); - // Return the number of active/enabled messages - uint8_t getActiveMessageCount(); + // Return the number of active/enabled RTCM messages + uint8_t getActiveRtcmMessageCount(); - // Return the number of active/enabled RTCM messages - uint8_t getActiveRtcmMessageCount(); + // Get the altitude + // Outputs: + // Returns the altitude in meters or zero if the GNSS is offline + double getAltitude(); - // Get the altitude - // Outputs: - // Returns the altitude in meters or zero if the GNSS is offline - double getAltitude(); + // Returns the carrier solution or zero if not online + uint8_t getCarrierSolution(); - // Returns the carrier solution or zero if not online - uint8_t getCarrierSolution(); + uint32_t getDataBaudRate(); - uint32_t getDataBaudRate(); + // Returns the day number or zero if not online + uint8_t getDay(); - // Returns the day number or zero if not online - uint8_t getDay(); + // Return the number of milliseconds since GNSS data was last updated + uint16_t getFixAgeMilliseconds(); - // Return the number of milliseconds since GNSS data was last updated - uint16_t getFixAgeMilliseconds(); + // Returns the fix type or zero if not online + uint8_t getFixType(); - // Returns the fix type or zero if not online - uint8_t getFixType(); + // Returns the hours of 24 hour clock or zero if not online + uint8_t getHour(); - // Returns the hours of 24 hour clock or zero if not online - uint8_t getHour(); + // Get the horizontal position accuracy + // Outputs: + // Returns the horizontal position accuracy or zero if offline + float getHorizontalAccuracy(); - // Get the horizontal position accuracy - // Outputs: - // Returns the horizontal position accuracy or zero if offline - float getHorizontalAccuracy(); + const char *getId(); - const char *getId(); + // Get the latitude value + // Outputs: + // Returns the latitude value or zero if not online + double getLatitude(); - // Get the latitude value - // Outputs: - // Returns the latitude value or zero if not online - double getLatitude(); + // Query GNSS for current leap seconds + uint8_t getLeapSeconds(); - // Query GNSS for current leap seconds - uint8_t getLeapSeconds(); + // Return the type of logging that matches the enabled messages - drives the logging icon + uint8_t getLoggingType(); - // Return the type of logging that matches the enabled messages - drives the logging icon - uint8_t getLoggingType(); + // Get the longitude value + // Outputs: + // Returns the longitude value or zero if not online + double getLongitude(); - // Get the longitude value - // Outputs: - // Returns the longitude value or zero if not online - double getLongitude(); + // Returns two digits of milliseconds or zero if not online + uint8_t getMillisecond(); - // Returns two digits of milliseconds or zero if not online - uint8_t getMillisecond(); + // Get the minimum satellite signal level for navigation. + uint8_t getMinCno(); - // Get the minimum satellite signal level for navigation. - uint8_t getMinCno(); + // Returns minutes or zero if not online + uint8_t getMinute(); - // Returns minutes or zero if not online - uint8_t getMinute(); + // Returns month number or zero if not online + uint8_t getMonth(); - // Returns month number or zero if not online - uint8_t getMonth(); + // Returns nanoseconds or zero if not online + uint32_t getNanosecond(); - // Returns nanoseconds or zero if not online - uint32_t getNanosecond(); + uint32_t getRadioBaudRate(); - uint32_t getRadioBaudRate(); + // Returns the seconds between solutions + double getRateS(); - // Returns the seconds between solutions - double getRateS(); + const char *getRtcmDefaultString(); - const char *getRtcmDefaultString(); + const char *getRtcmLowDataRateString(); - const char *getRtcmLowDataRateString(); + // Returns the number of satellites in view or zero if offline + uint8_t getSatellitesInView(); - // Returns the number of satellites in view or zero if offline - uint8_t getSatellitesInView(); + // Returns seconds or zero if not online + uint8_t getSecond(); - // Returns seconds or zero if not online - uint8_t getSecond(); + // Get the survey-in mean accuracy + // Outputs: + // Returns the mean accuracy or zero (0) + float getSurveyInMeanAccuracy(); - // Get the survey-in mean accuracy - // Outputs: - // Returns the mean accuracy or zero (0) - float getSurveyInMeanAccuracy(); + // Return the number of seconds the survey-in process has been running + int getSurveyInObservationTime(); - // Return the number of seconds the survey-in process has been running - int getSurveyInObservationTime(); + float getSurveyInStartingAccuracy(); - float getSurveyInStartingAccuracy(); + // Returns timing accuracy or zero if not online + uint32_t getTimeAccuracy(); - // Returns timing accuracy or zero if not online - uint32_t getTimeAccuracy(); + // Returns full year, ie 2023, not 23. + uint16_t getYear(); - // Returns full year, ie 2023, not 23. - uint16_t getYear(); + // Returns true if the device is in Rover mode + // Currently the only two modes are Rover or Base + bool inRoverMode(); - // Returns true if the device is in Rover mode - // Currently the only two modes are Rover or Base - bool inRoverMode(); + bool isBlocking(); - bool isBlocking(); + // Date is confirmed once we have GNSS fix + bool isConfirmedDate(); - // Date is confirmed once we have GNSS fix - bool isConfirmedDate(); + // Date is confirmed once we have GNSS fix + bool isConfirmedTime(); - // Date is confirmed once we have GNSS fix - bool isConfirmedTime(); + // Returns true if data is arriving on the Radio Ext port + bool isCorrRadioExtPortActive() + { + return false; + } - // Returns true if data is arriving on the Radio Ext port - bool isCorrRadioExtPortActive() - { - return false; - } + // Return true if GNSS receiver has a higher quality DGPS fix than 3D + bool isDgpsFixed(); - // Return true if GNSS receiver has a higher quality DGPS fix than 3D - bool isDgpsFixed(); + // Some functions (L-Band area frequency determination) merely need + // to know if we have a valid fix, not what type of fix + // This function checks to see if the given platform has reached + // sufficient fix type to be considered valid + bool isFixed(); - // Some functions (L-Band area frequency determination) merely need - // to know if we have a valid fix, not what type of fix - // This function checks to see if the given platform has reached - // sufficient fix type to be considered valid - bool isFixed(); + // Used in tpISR() for time pulse synchronization + bool isFullyResolved(); - // Used in tpISR() for time pulse synchronization - bool isFullyResolved(); + bool isPppConverged(); - bool isPppConverged(); + bool isPppConverging(); - bool isPppConverging(); + // Some functions (L-Band area frequency determination) merely need + // to know if we have an RTK Fix. This function checks to see if the + // given platform has reached sufficient fix type to be considered valid + bool isRTKFix(); - // Some functions (L-Band area frequency determination) merely need - // to know if we have an RTK Fix. This function checks to see if the - // given platform has reached sufficient fix type to be considered valid - bool isRTKFix(); + // Some functions (L-Band area frequency determination) merely need + // to know if we have an RTK Float. This function checks to see if + // the given platform has reached sufficient fix type to be considered + // valid + bool isRTKFloat(); - // Some functions (L-Band area frequency determination) merely need - // to know if we have an RTK Float. This function checks to see if - // the given platform has reached sufficient fix type to be considered - // valid - bool isRTKFloat(); + // Determine if the survey-in operation is complete + // Outputs: + // Returns true if the survey-in operation is complete and false + // if the operation is still running + bool isSurveyInComplete(); - // Determine if the survey-in operation is complete - // Outputs: - // Returns true if the survey-in operation is complete and false - // if the operation is still running - bool isSurveyInComplete(); + // Date will be valid if the RTC is reporting (regardless of GNSS fix) + bool isValidDate(); - // Date will be valid if the RTC is reporting (regardless of GNSS fix) - bool isValidDate(); + // Time will be valid if the RTC is reporting (regardless of GNSS fix) + bool isValidTime(); - // Time will be valid if the RTC is reporting (regardless of GNSS fix) - bool isValidTime(); + // Controls the constellations that are used to generate a fix and logged + void menuConstellations(); - // Controls the constellations that are used to generate a fix and logged - void menuConstellations(); + void menuMessageBaseRtcm(); - void menuMessageBaseRtcm(); + // Control the messages that get broadcast over Bluetooth and logged (if enabled) + void menuMessages(); - // Control the messages that get broadcast over Bluetooth and logged (if enabled) - void menuMessages(); + // Print the module type and firmware version + void printModuleInfo(); - // Print the module type and firmware version - void printModuleInfo(); + // Send correction data to the GNSS + // Inputs: + // dataToSend: Address of a buffer containing the data + // dataLength: The number of valid data bytes in the buffer + // Outputs: + // Returns the number of correction data bytes written + int pushRawData(uint8_t *dataToSend, int dataLength); - // Send correction data to the GNSS - // Inputs: - // dataToSend: Address of a buffer containing the data - // dataLength: The number of valid data bytes in the buffer - // Outputs: - // Returns the number of correction data bytes written - int pushRawData(uint8_t *dataToSend, int dataLength); + uint16_t rtcmBufferAvailable(); - uint16_t rtcmBufferAvailable(); + // If LBand is being used, ignore any RTCM that may come in from the GNSS + void rtcmOnGnssDisable(); - // If LBand is being used, ignore any RTCM that may come in from the GNSS - void rtcmOnGnssDisable(); + // If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver + void rtcmOnGnssEnable(); - // If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver - void rtcmOnGnssEnable(); + uint16_t rtcmRead(uint8_t *rtcmBuffer, int rtcmBytesToRead); - uint16_t rtcmRead(uint8_t *rtcmBuffer, int rtcmBytesToRead); + // Save the current configuration + // Outputs: + // Returns true when the configuration was saved and false upon failure + bool saveConfiguration(); - // Save the current configuration - // Outputs: - // Returns true when the configuration was saved and false upon failure - bool saveConfiguration(); + bool setBaudRate(uint8_t uartNumber, uint32_t baudRate); // From the super class - bool setBaudRate(uint8_t uartNumber, uint32_t baudRate); // From the super class + // Set the baud rate on the GNSS port that interfaces between the ESP32 and the GNSS + // Inputs: + // baudRate: The desired baudrate + bool setBaudRateComm(uint32_t baudRate); - // Set the baud rate on the GNSS port that interfaces between the ESP32 and the GNSS - // Inputs: - // baudRate: The desired baudrate - bool setBaudRateComm(uint32_t baudRate); + bool setBaudRateData(uint32_t baudRate); - bool setBaudRateData(uint32_t baudRate); + bool setBaudRateRadio(uint32_t baudRate); - bool setBaudRateRadio(uint32_t baudRate); + // Enable all the valid constellations and bands for this platform + bool setConstellations(); - // Enable all the valid constellations and bands for this platform - bool setConstellations(); + // Enable / disable corrections protocol(s) on the Radio External port + bool setCorrRadioExtPort(bool enable, bool force) + { + return true; + } - // Enable / disable corrections protocol(s) on the Radio External port - bool setCorrRadioExtPort(bool enable, bool force) - { - return true; - } + // Set the elevation in degrees + // Inputs: + // elevationDegrees: The elevation value in degrees + bool setElevation(uint8_t elevationDegrees); - // Set the elevation in degrees - // Inputs: - // elevationDegrees: The elevation value in degrees - bool setElevation(uint8_t elevationDegrees); + // Turn on all the enabled NMEA messages on COM3 + bool setMessagesNMEA(); - // Turn on all the enabled NMEA messages on COM3 - bool setMessagesNMEA(); + // Turn on all the enabled RTCM Rover messages on COM3 + bool setMessagesRTCMRover(); - // Turn on all the enabled RTCM Rover messages on COM3 - bool setMessagesRTCMRover(); + // Turn on all the enabled RTCM Base messages on COM3 + bool setMessagesRTCMBase(); - // Turn on all the enabled RTCM Base messages on COM3 - bool setMessagesRTCMBase(); + // Set the dynamic model to use for RTK + // Inputs: + // modelNumber: Number of the model to use, provided by radio library + bool setModel(uint8_t modelNumber); - // Set the dynamic model to use for RTK - // Inputs: - // modelNumber: Number of the model to use, provided by radio library - bool setModel(uint8_t modelNumber); + bool setMultipathMitigation(bool enableMultipathMitigation); - bool setMultipathMitigation(bool enableMultipathMitigation); + // Given the name of a message, find it, and set the rate + bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); - // Given the name of a message, find it, and set the rate - bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); + // Configure the Pulse-per-second pin based on user settings + bool setPPS(); - // Configure the Pulse-per-second pin based on user settings - bool setPPS(); + // Set all RTCM Rover message report rates to one value + void setRtcmRoverMessageRates(uint8_t msgRate); - // Set all RTCM Rover message report rates to one value - void setRtcmRoverMessageRates(uint8_t msgRate); + // Given the name of a message, find it, and set the rate + bool setRtcmRoverMessageRateByName(const char *msgName, uint8_t msgRate); - // Given the name of a message, find it, and set the rate - bool setRtcmRoverMessageRateByName(const char *msgName, uint8_t msgRate); + // Specify the interval between solutions + // Inputs: + // secondsBetweenSolutions: Number of seconds between solutions + // Outputs: + // Returns true if the rate was successfully set and false upon + // failure + bool setRate(double secondsBetweenSolutions); - // Specify the interval between solutions - // Inputs: - // secondsBetweenSolutions: Number of seconds between solutions - // Outputs: - // Returns true if the rate was successfully set and false upon - // failure - bool setRate(double secondsBetweenSolutions); + bool setTalkerGNGGA(); - bool setTalkerGNGGA(); + // Enable/disable any output needed for tilt compensation + bool setTilt(); - // Hotstart GNSS to try to get RTK lock - bool softwareReset(); + // Hotstart GNSS to try to get RTK lock + bool softwareReset(); - bool standby(); + bool standby(); - // Reset the survey-in operation - // Outputs: - // Returns true if the survey-in operation was reset successfully - // and false upon failure - bool surveyInReset(); + // Reset the survey-in operation + // Outputs: + // Returns true if the survey-in operation was reset successfully + // and false upon failure + bool surveyInReset(); - // Start the survey-in operation - // Outputs: - // Return true if successful and false upon failure - bool surveyInStart(); + // Start the survey-in operation + // Outputs: + // Return true if successful and false upon failure + bool surveyInStart(); - // If we have received serial data from the UM980 outside of the Unicore library (ie, from processUart1Message task) - // we can pass data back into the Unicore library to allow it to update its own variables - void unicoreHandler(uint8_t *buffer, int length); + // If we have received serial data from the UM980 outside of the Unicore library (ie, from processUart1Message task) + // we can pass data back into the Unicore library to allow it to update its own variables + void unicoreHandler(uint8_t *buffer, int length); - // Poll routine to update the GNSS state - void update(); + // Poll routine to update the GNSS state + void update(); }; #endif // COMPILE_UM980 diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index c22e97b95..7ce5f193c 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -74,7 +74,7 @@ void GNSS_UM980::begin() debuggingEnable(); // In order to reduce UM980 configuration time, the UM980 library blocks the start of BESTNAV and RECTIME until 3D - // fix is achieved However, if all NMEA messages are disabled, the UM980 will never detect a 3D fix. + // fix is achieved. However, if all NMEA messages are disabled, the UM980 will never detect a 3D fix. if (isGgaActive()) // If NMEA GPGGA is turned on, suppress BESTNAV messages until GPGGA reports a 3D fix _um980->disableBinaryBeforeFix(); @@ -138,11 +138,9 @@ bool GNSS_UM980::setPPS() // configure the PPS so that the GNSS LED blinks // Read, modify, write - // The UM980 does have the ability to read the current PPS settings in config, but this function + // The UM980 does have the ability to read the current PPS settings from CONFIG output, but this function // gets called very rarely. Just do a write for now. - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM - // Enable PPS signal with a width of 200ms, and a period of 1 second return (_um980->enablePPS(settings.externalPulseLength_us, settings.externalPulseTimeBetweenPulse_us / 1000)); // widthMicroseconds, periodMilliseconds @@ -171,56 +169,20 @@ bool GNSS_UM980::configureBase() Enable RTCM Base messages Enable NMEA messages */ - - if (online.gnss == false) - { - systemPrintln("GNSS not online"); - return (false); - } - // Trusting the saved configuration does not seem to work on the UM980. // It looks like the GPGGA NMEA output does not restart...? // (Re)configuration is quick. Doing this every time is not much of an overhead. - // - // if (settings.gnssConfiguredBase) - // { - // if (settings.debugGnss) - // systemPrintln("Skipping UM980 Base configuration"); - // return true; - // } - - disableAllOutput(); bool response = true; // Set the dynamic mode. This will cancel any base averaging mode and is needed // to allow a freshly started device to settle in regular GNSS reception mode before issuing - // um980BaseAverageStart(). - - gnssConfigure(GNSS_CONFIG_MODEL); // Request receiver to use new settings - gnssConfigure(GNSS_CONFIG_MULTIPATH); - gnssConfigure(GNSS_CONFIG_HAS_E6); + // a surveyInStart(). + gnssConfigure(GNSS_CONFIG_MODEL); + // Request receiver to use new settings gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); - - // Only turn on messages, do not turn off messages. We assume the caller has UNLOG or similar. - response &= setMessagesRTCMBase(); - - // Only turn on messages, do not turn off messages. We assume the caller has UNLOG or similar. - response &= setMessagesNMEA(); - - // Save the current configuration into non-volatile memory (NVM) - response &= _um980->saveConfiguration(); - - if (response == false) - { - systemPrintln("UM980 Base failed to configure"); - } - - if (settings.debugGnss) - systemPrintln("UM980 Base configured"); - - settings.gnssConfiguredBase = response; + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); return (response); } @@ -229,10 +191,9 @@ bool GNSS_UM980::configureBase() bool GNSS_UM980::configureOnce() { /* - Disable all message traffic Set COM port baud rates, - UM980 COM1 - Direct to USB, 115200 - UM980 COM2 - To IMU. From settings. + UM980 COM1 - Connected to ESP32 through switches. Not used. + UM980 COM2 - To IMU. UM980 COM3 - BT, config and LoRa Radio. Configured for 115200 from begin(). Set minCNO Set elevationAngle @@ -241,35 +202,26 @@ bool GNSS_UM980::configureOnce() Enable selected NMEA messages on COM3 Enable selected RTCM messages on COM3 */ - - // // If our settings haven't changed, trust GNSS's settings - if (settings.gnssConfiguredOnce) - { - systemPrintln("UM980 configuration maintained"); - return (true); - } - - if (settings.debugGnss) - debuggingEnable(); // Print all debug to Serial - - disableAllOutput(); // Disable COM1/2/3 - bool response = true; - response &= setBaudRateData(115200); // UM980 UART1 is connected to switch, then USB - response &= setBaudRate(2, 115200); // UM980 UART2 is connected to the IMU + response &= setBaudRate(2, 115200); // UM980 UART2 is connected to the IMU + if (response == false) + systemPrintln("setBaudRate failed"); // Assume if we've made it this far, the UM980 UART3 is communicating // response &= setBaudRateComm(115200); // UM980 UART3 is connected to the switch, then ESP32 - gnssConfigure(GNSS_CONFIG_ELEVATION); // Request receiver to use new settings - gnssConfigure(GNSS_CONFIG_CN0); - gnssConfigure(GNSS_CONFIG_PPS); - gnssConfigure(GNSS_CONFIG_CONSTELLATION); - + // Signal group control is not currently exposed to the user, thus is not configured using gnssConfigure() + // Read, modify, write if (_um980->isConfigurationPresent("CONFIG SIGNALGROUP 2") == false) { + // Output must be disabled before sending SIGNALGROUP command in order to get the OK response + disableAllOutput(); // Disable COM1/2/3 + if (_um980->sendCommand("CONFIG SIGNALGROUP 2") == false) + { systemPrintln("Signal group 2 command failed"); + response = false; + } else { systemPrintln("Enabling additional reception on UM980. This can take a few seconds."); @@ -284,6 +236,16 @@ bool GNSS_UM980::configureOnce() } systemPrintln("UM980 has completed reboot."); + + // configureOnce() should only be run after a system level factory reset + // Other bits to enable NMEA and RTCM should be enabled so no need to enable messages here + + // // Re-enable messages + // gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); + // if (inBaseMode()) + // gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); + // else + // gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); } } @@ -292,15 +254,10 @@ bool GNSS_UM980::configureOnce() online.gnss = true; // If we failed before, mark as online now systemPrintln("UM980 configuration updated"); - - // Save the current configuration into non-volatile memory (NVM) - response &= _um980->saveConfiguration(); } else online.gnss = false; // Take it offline - settings.gnssConfiguredOnce = response; - return (response); } @@ -316,7 +273,7 @@ bool GNSS_UM980::configureNtpMode() // Setup the GNSS module for any setup (base or rover) // In general we check if the setting is different than setting stored in NVM before writing it. //---------------------------------------- -bool GNSS_UM980::configureGNSS() +bool GNSS_UM980::configure() { for (int x = 0; x < 3; x++) { @@ -349,60 +306,18 @@ bool GNSS_UM980::configureRover() Enable RTCM messages on COM3 Enable NMEA on COM3 */ - if (online.gnss == false) - { - systemPrintln("GNSS not online"); - return (false); - } - // Trusting the saved configuration does not seem to work on the UM980. // It looks like the GPGGA NMEA output does not restart...? // (Re)configuration is quick. Doing this every time is not much of an overhead. - // - // if (settings.gnssConfiguredRover) - // { - // systemPrintln("Skipping UM980 Rover configuration"); - // return (true); - // } - - disableAllOutput(); bool response = true; - response &= setModel(settings.dynamicModel); // This will cancel any base averaging mode - - response &= setElevation(settings.minElev); // UM980 default is 5 degrees. Our default is 10. - - response &= setMultipathMitigation(settings.enableMultipathMitigation); + // Sets the dynamic model (Survey/UAV/Automotive) and puts the device into Rover mode + gnssConfigure(GNSS_CONFIG_MODEL); - response &= setHighAccuracyService(settings.enableGalileoHas); - - // Configure UM980 to output binary reports out COM2, connected to IM19 COM3 - response &= _um980->sendCommand("BESTPOSB COM2 0.2"); // 5Hz - response &= _um980->sendCommand("PSRVELB COM2 0.2"); - - // Configure UM980 to output NMEA reports out COM2, connected to IM19 COM3 - response &= _um980->setNMEAPortMessage("GPGGA", "COM2", 0.2); // 5Hz - - // Enable the NMEA sentences and RTCM on COM3 last. This limits the traffic on the config - // interface port during config. - - // Only turn on messages, do not turn off messages. We assume the caller has UNLOG or similar. - response &= setMessagesRTCMRover(); - // TODO consider reducing the GSV sentence to 1/4 of the GPGGA setting - - // Only turn on messages, do not turn off messages. We assume the caller has UNLOG or similar. - response &= setMessagesNMEA(); - - // Save the current configuration into non-volatile memory (NVM) - response &= _um980->saveConfiguration(); - - if (response == false) - { - systemPrintln("UM980 Rover failed to configure"); - } - - settings.gnssConfiguredRover = response; + // Request a change to NMEA and Rover RTCM + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); return (response); } @@ -442,6 +357,8 @@ void GNSS_UM980::createMessageListBase(String &returnText) } } +// GNSS debugging has to be outside of gnssUpdate() because we often need to immediately turn on/off debugging +// ie, entering the system menu //---------------------------------------- void GNSS_UM980::debuggingDisable() { @@ -1465,9 +1382,9 @@ bool GNSS_UM980::setBaudRate(uint8_t uartNumber, uint32_t baudRate) return (false); } - // The UART on the UM980 is passed as a string with quotes, ie "COM2" - char comName[7]; // "COM3" - snprintf(comName, sizeof(comName), "\"COM%d\"", uartNumber); + // The UART on the UM980 is passed as a string, ie "COM2" + char comName[5]; // COM3 + snprintf(comName, sizeof(comName), "COM%d", uartNumber); // Read, modify, write uint32_t currentBaudRate = _um980->getPortBaudrate(comName); @@ -1641,36 +1558,39 @@ bool GNSS_UM980::setMinCno(uint8_t cn0Value) //---------------------------------------- bool GNSS_UM980::setMessagesNMEA() { + // The UM980 is unique in that there is a UNLOG command that turns off all + // reported NMEA/RTCM messages. From this point, we could only send the commands to + // turn on the >0 messages. However, we don't use this technique, and instead send the + // command for every possible NMEA/RTCM message, because sending UNLOG would + // turn off both NMEA and RTCM, and in doing so would disrupt any previous config + // of NMEA or RTCM (individually). + // Ultimately, we must send a command for each >=0 setting in the associated message array. + bool response = true; bool gpggaEnabled = false; bool gpzdaEnabled = false; for (int messageNumber = 0; messageNumber < MAX_UM980_NMEA_MSG; messageNumber++) { - // Only turn on messages, do not turn off messages set to 0. This saves on command sending. We assume the caller - // has UNLOG or similar. - if (settings.um980MessageRatesNMEA[messageNumber] > 0) - { - // If any one of the commands fails, report failure overall - response &= _um980->setNMEAPortMessage(umMessagesNMEA[messageNumber].msgTextName, "COM3", - settings.um980MessageRatesNMEA[messageNumber]); + // If any one of the commands fails, report failure overall + response &= _um980->setNMEAPortMessage(umMessagesNMEA[messageNumber].msgTextName, "COM3", + settings.um980MessageRatesNMEA[messageNumber]); - if (response == false && settings.debugGnss) - systemPrintf("Enable NMEA failed at messageNumber %d %s.\r\n", messageNumber, - umMessagesNMEA[messageNumber].msgTextName); + if (response == false && settings.debugGnss) + systemPrintf("Enable NMEA failed at messageNumber %d %s.\r\n", messageNumber, + umMessagesNMEA[messageNumber].msgTextName); - // If we are using IP based corrections, we need to send local data to the PPL - // The PPL requires being fed GPGGA/ZDA, and RTCM1019/1020/1042/1046 - if (pointPerfectServiceUsesKeys()) + // If we are using IP based corrections, we need to send local data to the PPL + // The PPL requires being fed GPGGA/ZDA, and RTCM1019/1020/1042/1046 + if (pointPerfectServiceUsesKeys()) + { + // Mark PPL required messages as enabled if rate > 0 + if (settings.um980MessageRatesNMEA[messageNumber] > 0) { - // Mark PPL required messages as enabled if rate > 0 - if (settings.um980MessageRatesNMEA[messageNumber] > 0) - { - if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "GPGGA") == 0) - gpggaEnabled = true; - else if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "GPZDA") == 0) - gpzdaEnabled = true; - } + if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "GPGGA") == 0) + gpggaEnabled = true; + else if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "GPZDA") == 0) + gpzdaEnabled = true; } } } @@ -1684,9 +1604,6 @@ bool GNSS_UM980::setMessagesNMEA() response &= _um980->setNMEAPortMessage("GPZDA", "COM3", 1); } - if (response == true) - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM - return (response); } @@ -1704,7 +1621,7 @@ bool GNSS_UM980::setMessagesRTCMBase() settings.um980MessageRatesRTCMBase[messageNumber]); if (response == false && settings.debugGnss) - systemPrintf("setMessagesRTCMBase failed at messageNumber %d %s.", messageNumber, + systemPrintf("setMessagesRTCMBase failed at messageNumber %d %s.\r\n", messageNumber, umMessagesRTCM[messageNumber].msgTextName); } @@ -1724,35 +1641,30 @@ bool GNSS_UM980::setMessagesRTCMRover() for (int messageNumber = 0; messageNumber < MAX_UM980_RTCM_MSG; messageNumber++) { - // Only turn on messages, do not turn off messages set to 0. This saves on command sending. We assume the caller - // has UNLOG or similar. - if (settings.um980MessageRatesRTCMRover[messageNumber] > 0) + if (_um980->setRTCMPortMessage(umMessagesRTCM[messageNumber].msgTextName, "COM3", + settings.um980MessageRatesRTCMRover[messageNumber]) == false) { - if (_um980->setRTCMPortMessage(umMessagesRTCM[messageNumber].msgTextName, "COM3", - settings.um980MessageRatesRTCMRover[messageNumber]) == false) - { - if (settings.debugGnss) - systemPrintf("Enable RTCM failed at messageNumber %d %s.", messageNumber, - umMessagesRTCM[messageNumber].msgTextName); - response &= false; // If any one of the commands fails, report failure overall - } + if (settings.debugGnss) + systemPrintf("Enable RTCM failed at messageNumber %d %s.", messageNumber, + umMessagesRTCM[messageNumber].msgTextName); + response &= false; // If any one of the commands fails, report failure overall + } - // If we are using IP based corrections, we need to send local data to the PPL - // The PPL requires being fed GPGGA/ZDA, and RTCM1019/1020/1042/1046 - if (pointPerfectServiceUsesKeys()) + // If we are using IP based corrections, we need to send local data to the PPL + // The PPL requires being fed GPGGA/ZDA, and RTCM1019/1020/1042/1046 + if (pointPerfectServiceUsesKeys()) + { + // Mark PPL required messages as enabled if rate > 0 + if (settings.um980MessageRatesRTCMRover[messageNumber] > 0) { - // Mark PPL required messages as enabled if rate > 0 - if (settings.um980MessageRatesRTCMRover[messageNumber] > 0) - { - if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "RTCM1019") == 0) - rtcm1019Enabled = true; - else if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "RTCM1020") == 0) - rtcm1020Enabled = true; - else if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "RTCM1042") == 0) - rtcm1042Enabled = true; - else if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "RTCM1046") == 0) - rtcm1046Enabled = true; - } + if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "RTCM1019") == 0) + rtcm1019Enabled = true; + else if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "RTCM1020") == 0) + rtcm1020Enabled = true; + else if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "RTCM1042") == 0) + rtcm1042Enabled = true; + else if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "RTCM1046") == 0) + rtcm1046Enabled = true; } } } @@ -1770,9 +1682,6 @@ bool GNSS_UM980::setMessagesRTCMRover() response &= _um980->setRTCMPortMessage("RTCM1046", "COM3", 1); } - if (response == true) - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM - return (response); } @@ -1812,7 +1721,6 @@ bool GNSS_UM980::setMultipathMitigation(bool enableMultipathMitigation) if (_um980->sendCommand("CONFIG MMP ENABLE")) { systemPrintln("Multipath Mitigation enabled"); - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM } else { @@ -1829,7 +1737,6 @@ bool GNSS_UM980::setMultipathMitigation(bool enableMultipathMitigation) if (_um980->sendCommand("CONFIG MMP DISABLE")) { systemPrintln("Multipath Mitigation disabled"); - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM } else { @@ -1910,7 +1817,6 @@ bool GNSS_UM980::setRate(double secondsBetweenSolutions) { uint16_t msBetweenSolutions = secondsBetweenSolutions * 1000; settings.measurementRateMs = msBetweenSolutions; - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM } else { @@ -1928,6 +1834,34 @@ bool GNSS_UM980::setTalkerGNGGA() return false; } +//---------------------------------------- +// Enable/disable any output needed for tilt compensation +//---------------------------------------- +bool GNSS_UM980::setTilt() +{ + if (present.imu_im19 == false) + return (true); // Report success + + bool response = true; + + // Read, modify, write + // The UM980 does not have a way to read the currently enabled messages so we do only a write + + if (settings.enableTiltCompensation == true) + { + // Configure UM980 to output binary and NMEA reports out COM2, connected to IM19 COM3 + response &= _um980->sendCommand("BESTPOSB COM2 0.2"); // 5Hz + response &= _um980->sendCommand("PSRVELB COM2 0.2"); + response &= _um980->setNMEAPortMessage("GPGGA", "COM2", 0.2); // 5Hz + } + else + { + // We could turn off these messages but because they are only fed into the IMU, it doesn't cause any harm. + } + + return (response); +} + //---------------------------------------- // Hotstart GNSS // Needed on ZED based products where RTK Float lock is seen using L-Band diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.h b/Firmware/RTK_Everywhere/GNSS_ZED.h index 61f575273..1d743276d 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.h +++ b/Firmware/RTK_Everywhere/GNSS_ZED.h @@ -424,7 +424,7 @@ class GNSS_ZED : GNSS // Not Rover or Base specific (ie, baud rates) // Outputs: // Returns true if successfully configured and false upon failure - bool configureGNSS(); + bool configure(); // Configure the Rover // Outputs: @@ -737,6 +737,9 @@ class GNSS_ZED : GNSS bool setTalkerGNGGA(); + // Enable/disable any output needed for tilt compensation + bool setTilt(); + // Hotstart GNSS to try to get RTK lock bool softwareReset(); diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index e13cf576f..dd8d648e9 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -520,7 +520,7 @@ bool GNSS_ZED::configureNtpMode() // In general we check if the setting is incorrect before writing it. Otherwise, the set commands have, on rare // occasion, become corrupt. The worst is when the I2C port gets turned off or the I2C address gets borked. //---------------------------------------- -bool GNSS_ZED::configureGNSS() +bool GNSS_ZED::configure() { if (online.gnss == false) return (false); @@ -2460,6 +2460,15 @@ bool GNSS_ZED::setTalkerGNGGA() return false; } +//---------------------------------------- +// Enable/disable any output needed for tilt compensation +//---------------------------------------- +bool GNSS_ZED::setTilt() +{ + // Not yet available on this platform + return false; +} + //---------------------------------------- // Hotstart GNSS to try to get RTK lock //---------------------------------------- From 710068966a32f7faf84f1000abf96bba2a7e49a2 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Fri, 17 Oct 2025 11:46:35 -0600 Subject: [PATCH 27/68] Rename softwareReset to reset --- Firmware/RTK_Everywhere/GNSS.h | 6 ++-- Firmware/RTK_Everywhere/GNSS_LG290P.h | 6 ++-- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 29 ++++++++++++++++++ Firmware/RTK_Everywhere/GNSS_Mosaic.h | 6 ++-- Firmware/RTK_Everywhere/GNSS_Mosaic.ino | 39 ++++++++++++++----------- Firmware/RTK_Everywhere/GNSS_None.h | 12 ++++---- Firmware/RTK_Everywhere/GNSS_UM980.h | 6 ++-- Firmware/RTK_Everywhere/GNSS_UM980.ino | 24 +++++++++------ Firmware/RTK_Everywhere/GNSS_ZED.h | 6 ++-- Firmware/RTK_Everywhere/GNSS_ZED.ino | 23 ++++++++------- Firmware/RTK_Everywhere/menuPP.ino | 2 +- 11 files changed, 100 insertions(+), 59 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.h b/Firmware/RTK_Everywhere/GNSS.h index 3b84d7453..b6e0d92b6 100644 --- a/Firmware/RTK_Everywhere/GNSS.h +++ b/Firmware/RTK_Everywhere/GNSS.h @@ -301,6 +301,9 @@ class GNSS // Returns the number of correction data bytes written virtual int pushRawData(uint8_t *dataToSend, int dataLength); + // Hardware or software reset the GNSS receiver + virtual bool reset(); + virtual uint16_t rtcmBufferAvailable(); // If LBand is being used, ignore any RTCM that may come in from the GNSS @@ -375,9 +378,6 @@ class GNSS // Enable/disable any output needed for tilt compensation virtual bool setTilt(); - // Hotstart GNSS to try to get RTK lock - virtual bool softwareReset(); - virtual bool standby(); // Antenna Short / Open detection diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.h b/Firmware/RTK_Everywhere/GNSS_LG290P.h index 3050f4e67..da112fa31 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.h +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.h @@ -381,6 +381,9 @@ class GNSS_LG290P : GNSS // Returns the number of correction data bytes written int pushRawData(uint8_t *dataToSend, int dataLength); + // Hardware or software reset the GNSS + bool reset(); + uint16_t rtcmBufferAvailable(); // If LBand is being used, ignore any RTCM that may come in from the GNSS @@ -447,9 +450,6 @@ class GNSS_LG290P : GNSS // Enable/disable any output needed for tilt compensation bool setTilt(); - // Hotstart GNSS to try to get RTK lock - bool softwareReset(); - bool standby(); // Reset the survey-in operation diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index 61f2851e8..eb6e5f120 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -1842,6 +1842,35 @@ int GNSS_LG290P::pushRawData(uint8_t *dataToSend, int dataLength) return (0); } +//---------------------------------------- +// Hardware or software reset the GNSS receiver +// Reset GNSS via software command +// Poll for isConnected() +//---------------------------------------- +bool GNSS_LG290P::reset() +{ + if (online.gnss) + { + _lg290p->reset(); + + // Poll for a limited amount of time before unit comes back + int x = 0; + while (x++ < 50) + { + delay(100); // Wait for device to reboot + if (_lg290p->isConnected() == true) + break; + else + systemPrintln("GNSS still rebooting"); + } + if (x < 50) + return (true); + + systemPrintln("GNSS failed to connect after reboot"); + } + return (false); +} + //---------------------------------------- uint16_t GNSS_LG290P::rtcmBufferAvailable() { diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.h b/Firmware/RTK_Everywhere/GNSS_Mosaic.h index 1f6a7a45c..d471bdc3b 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.h +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.h @@ -867,6 +867,9 @@ class GNSS_MOSAIC : GNSS // Returns the number of correction data bytes written int pushRawData(uint8_t *dataToSend, int dataLength); + // Hardware or software reset the GNSS receiver + bool reset(); + uint16_t rtcmBufferAvailable(); // If LBand is being used, ignore any RTCM that may come in from the GNSS @@ -1024,9 +1027,6 @@ class GNSS_MOSAIC : GNSS // Enable/disable any output needed for tilt compensation bool setTilt(); - // Hotstart GNSS to try to get RTK lock - bool softwareReset(); - bool standby(); // Save the data from the SBF Block 4007 diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino index c37ef703f..1d3026f96 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino @@ -152,7 +152,7 @@ void menuLogMosaic() GNSS_MOSAIC *mosaic = (GNSS_MOSAIC *)gnss; mosaic->configureLogging(); // This will enable / disable RINEX logging - mosaic->setMessagesNMEA(); // Enable NMEA messages - this will enable/disable the DSK1 streams + mosaic->setMessagesNMEA(); // Enable NMEA messages - this will enable/disable the DSK1 streams mosaic->saveConfiguration(); // Save the configuration setLoggingType(); // Update Standard, PPP, or custom for icon selection } @@ -1564,7 +1564,7 @@ void GNSS_MOSAIC::menuMessagesNMEA() if (settings.mosaicMessageStreamNMEA[incoming] > MOSAIC_NUM_NMEA_STREAMS) settings.mosaicMessageStreamNMEA[incoming] = 0; // Wrap around - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings } else if (incoming > MAX_MOSAIC_NMEA_MSG && incoming <= (MAX_MOSAIC_NMEA_MSG + MOSAIC_NUM_NMEA_STREAMS)) // Stream intervals @@ -1583,7 +1583,7 @@ void GNSS_MOSAIC::menuMessagesNMEA() if (interval >= 1 && interval <= MAX_MOSAIC_MSG_RATES) { settings.mosaicStreamIntervalsNMEA[incoming] = interval - 1; - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings } } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) @@ -1645,7 +1645,10 @@ void GNSS_MOSAIC::menuMessagesRTCM(bool rover) if ((interval >= 0.1) && (interval <= 600.0)) { intervalPtr[incoming] = interval; - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings + if (inBaseMode()) + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); // Request receiver to use new settings + else + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings } else systemPrintln("Invalid interval: Min 0.1; Max 600.0"); @@ -1721,7 +1724,11 @@ void GNSS_MOSAIC::menuMessages() for (int x = 0; x < MAX_MOSAIC_RTCM_V3_MSG; x++) settings.mosaicMessageEnabledRTCMv3Base[x] = mosaicMessagesRTCMv3[x].defaultEnabled; - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings + if (inBaseMode()) + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); // Request receiver to use new settings + else + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings systemPrintln("Reset to Defaults"); } @@ -1768,6 +1775,16 @@ uint16_t GNSS_MOSAIC::rtcmBufferAvailable() return 0; } +//---------------------------------------- +// Hardware or software reset the GNSS receiver +//---------------------------------------- +bool GNSS_MOSAIC::reset() +{ + // We could restart L-Band here if needed, but gnss->reset is never called on the X5 + // Instead, update() does it when spartnCorrectionsReceived times out + return false; +} + //---------------------------------------- // If LBand is being used, ignore any RTCM that may come in from the GNSS //---------------------------------------- @@ -2165,7 +2182,6 @@ bool GNSS_MOSAIC::setCorrRadioExtPort(bool enable, bool force) return false; } - //---------------------------------------- // Set the elevation in degrees // Inputs: @@ -2543,17 +2559,6 @@ bool GNSS_MOSAIC::setTilt() return false; } - -//---------------------------------------- -// Hotstart GNSS to try to get RTK lock -//---------------------------------------- -bool GNSS_MOSAIC::softwareReset() -{ - // We could restart L-Band here if needed, but gnss->softwareReset is never called on the X5 - // Instead, update() does it when spartnCorrectionsReceived times out - return false; -} - //---------------------------------------- bool GNSS_MOSAIC::standby() { diff --git a/Firmware/RTK_Everywhere/GNSS_None.h b/Firmware/RTK_Everywhere/GNSS_None.h index 51ed452bf..b2301ffe3 100644 --- a/Firmware/RTK_Everywhere/GNSS_None.h +++ b/Firmware/RTK_Everywhere/GNSS_None.h @@ -492,6 +492,12 @@ class GNSS_None : public GNSS return dataLength; } + // Hardware or software reset the GNSS receiver + bool reset() + { + return true; + } + uint16_t rtcmBufferAvailable() { return 0; @@ -630,12 +636,6 @@ class GNSS_None : public GNSS return true; } - // Hotstart GNSS to try to get RTK lock - bool softwareReset() - { - return true; - } - bool standby() { return true; diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.h b/Firmware/RTK_Everywhere/GNSS_UM980.h index 5e56844eb..a8626c48a 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.h +++ b/Firmware/RTK_Everywhere/GNSS_UM980.h @@ -396,6 +396,9 @@ class GNSS_UM980 : GNSS uint16_t rtcmBufferAvailable(); + // Hardware or software reset the GNSS + bool reset(); + // If LBand is being used, ignore any RTCM that may come in from the GNSS void rtcmOnGnssDisable(); @@ -475,9 +478,6 @@ class GNSS_UM980 : GNSS // Enable/disable any output needed for tilt compensation bool setTilt(); - // Hotstart GNSS to try to get RTK lock - bool softwareReset(); - bool standby(); // Reset the survey-in operation diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index 7ce5f193c..5b19408fc 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -283,10 +283,7 @@ bool GNSS_UM980::configure() // If we fail, reset UM980 systemPrintln("Resetting UM980 to complete configuration"); - gnssReset(); - delay(500); - gnssBoot(); - delay(500); + reset(); // Hardware reset the UM980 } systemPrintln("UM980 failed to configure"); @@ -1867,8 +1864,20 @@ bool GNSS_UM980::setTilt() // Needed on ZED based products where RTK Float lock is seen using L-Band // Not used on UM980 based devices //---------------------------------------- -bool GNSS_UM980::softwareReset() +bool GNSS_UM980::reset() { + // Hardware reset the Torch in case UM980 is unresponsive + if (productVariant == RTK_TORCH) + { + digitalWrite(pin_GNSS_DR_Reset, LOW); // Tell UM980 and DR to reset + } + + delay(500); + + if (productVariant == RTK_TORCH) + { + digitalWrite(pin_GNSS_DR_Reset, HIGH); // Tell UM980 and DR to boot + } return false; } @@ -2091,10 +2100,7 @@ void um980FirmwareBeginUpdate() if (nextIncoming == '@') { // Reset UM980 - gnssReset(); - delay(25); - gnssBoot(); - + gnss->reset(); inBootMode = true; } } diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.h b/Firmware/RTK_Everywhere/GNSS_ZED.h index 1d743276d..ac90b3228 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.h +++ b/Firmware/RTK_Everywhere/GNSS_ZED.h @@ -654,6 +654,9 @@ class GNSS_ZED : GNSS // Returns the number of correction data bytes written int pushRawData(uint8_t *dataToSend, int dataLength); + // Hardware or software reset the GNSS + bool reset(); + uint16_t rtcmBufferAvailable(); // If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver @@ -740,9 +743,6 @@ class GNSS_ZED : GNSS // Enable/disable any output needed for tilt compensation bool setTilt(); - // Hotstart GNSS to try to get RTK lock - bool softwareReset(); - bool standby(); // Callback to save the high precision data diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index dd8d648e9..23a95951d 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -1975,6 +1975,18 @@ int GNSS_ZED::pushRawData(uint8_t *dataToSend, int dataLength) return (0); } +//---------------------------------------- +// Hardware or software reset the GNSS receiver +// Hotstart GNSS to try to get RTK lock +//---------------------------------------- +bool GNSS_ZED::reset() +{ + if (online.gnss == false) + return false; + _zed->softwareResetGNSSOnly(); + return true; +} + //---------------------------------------- uint16_t GNSS_ZED::rtcmBufferAvailable() { @@ -2469,17 +2481,6 @@ bool GNSS_ZED::setTilt() return false; } -//---------------------------------------- -// Hotstart GNSS to try to get RTK lock -//---------------------------------------- -bool GNSS_ZED::softwareReset() -{ - if (online.gnss == false) - return false; - _zed->softwareResetGNSSOnly(); - return true; -} - //---------------------------------------- bool GNSS_ZED::standby() { diff --git a/Firmware/RTK_Everywhere/menuPP.ino b/Firmware/RTK_Everywhere/menuPP.ino index 26a30950b..47721e0c0 100644 --- a/Firmware/RTK_Everywhere/menuPP.ino +++ b/Firmware/RTK_Everywhere/menuPP.ino @@ -783,7 +783,7 @@ void updateLBandCorrections() millis(); // Restart timer for L-Band. Don't immediately reset ZED to achieve fix. // Hotstart GNSS to try to get RTK lock - gnss->softwareReset(); + gnss->reset(); if (settings.debugCorrections == true) systemPrintf("Restarting ZED. Number of Float lock restarts: %d\r\n", floatLockRestarts); From 8e9a1d1884241cb45b79b1ee3dd2d49c9f92f650 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Wed, 22 Oct 2025 11:21:37 -0600 Subject: [PATCH 28/68] Add check for UNLOG then resending of all RTCM commands for UM980 config --- Firmware/RTK_Everywhere/GNSS.ino | 134 ++++++++++--- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 214 +++++++------------- Firmware/RTK_Everywhere/GNSS_UM980.h | 3 - Firmware/RTK_Everywhere/GNSS_UM980.ino | 237 +++++++++++++++-------- Firmware/RTK_Everywhere/Tasks.ino | 1 - Firmware/RTK_Everywhere/menuGNSS.ino | 2 +- Firmware/RTK_Everywhere/menuMessages.ino | 7 +- Firmware/RTK_Everywhere/menuPP.ino | 5 +- 8 files changed, 349 insertions(+), 254 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index 1fddcac82..61931461c 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -12,7 +12,6 @@ enum GNSS_CONFIG_ONCE, // Settings specific to a receiver that don't fit into other setting categories GNSS_CONFIG_ROVER, GNSS_CONFIG_BASE, // Fixed base or survey in, location, etc - GNSS_CONFIG_BAUD_RATE_COMM, GNSS_CONFIG_BAUD_RATE_RADIO, GNSS_CONFIG_BAUD_RATE_DATA, GNSS_CONFIG_RATE, @@ -21,10 +20,10 @@ enum GNSS_CONFIG_CN0, GNSS_CONFIG_PPS, GNSS_CONFIG_MODEL, - GNSS_CONFIG_MESSAGE_RATE, // Update all message rates GNSS_CONFIG_MESSAGE_RATE_NMEA, // Update NMEA message rates GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER, // Update RTCM Rover message rates GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE, // Update RTCM Base message rates + GNSS_CONFIG_MESSAGE_RATE_OTHER, // Update any other messages (UBX, PQTM, etc) GNSS_CONFIG_HAS_E6, // Enable/disable HAS E6 capabilities GNSS_CONFIG_MULTIPATH, GNSS_CONFIG_TILT, // Enable/disable any output needed for tilt compensation @@ -39,7 +38,6 @@ static const char *gnssConfigDisplayNames[] = { "ONCE", "ROVER", "BASE", - "BAUD_RATE_COMM", "BAUD_RATE_RADIO", "BAUD_RATE_DATA", "RATE", @@ -48,14 +46,13 @@ static const char *gnssConfigDisplayNames[] = { "CN0", "PPS", "MODEL", - "MESSAGE_RATE", "MESSAGE_RATE_NMEA", "MESSAGE_RATE_RTCM_ROVER", "MESSAGE_RATE_RTCM_BASE", + "MESSAGE_RATE_RTCM_OTHER", "HAS_E6", "MULTIPATH", "TILT", - "DEBUG", "SAVE", "RESET", }; @@ -166,11 +163,40 @@ void gnssUpdate() } } - if (gnssConfigureRequested(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE)) + if (gnssConfigureRequested(GNSS_CONFIG_BAUD_RATE_RADIO)) + { + if (gnss->setBaudRateRadio(settings.radioPortBaud) == true) + { + gnssConfigureClear(GNSS_CONFIG_BAUD_RATE_RADIO); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } + } + + if (gnssConfigureRequested(GNSS_CONFIG_BAUD_RATE_DATA)) + { + if (gnss->setBaudRateData(settings.dataPortBaud) == true) + { + gnssConfigureClear(GNSS_CONFIG_BAUD_RATE_DATA); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } + } + + // For some receivers (ie, UM980) changing the model changes to Rover/Base. + // Configure model before setting message rates + if (gnssConfigureRequested(GNSS_CONFIG_MODEL)) { - if (gnss->setMessagesRTCMBase() == true) + if (gnss->setModel(settings.dynamicModel) == true) { - gnssConfigureClear(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); + gnssConfigureClear(GNSS_CONFIG_MODEL); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } + } + + if (gnssConfigureRequested(GNSS_CONFIG_RATE)) + { + if (gnss->setRate(settings.measurementRateMs / 1000.0) == true) + { + gnssConfigureClear(GNSS_CONFIG_RATE); gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM } } @@ -211,15 +237,6 @@ void gnssUpdate() } } - if (gnssConfigureRequested(GNSS_CONFIG_MODEL)) - { - if (gnss->setModel(settings.dynamicModel) == true) - { - gnssConfigureClear(GNSS_CONFIG_MODEL); - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM - } - } - if (gnssConfigureRequested(GNSS_CONFIG_HAS_E6)) { if (gnss->setHighAccuracyService(settings.enableGalileoHas) == true) @@ -238,6 +255,54 @@ void gnssUpdate() } } + if (gnssConfigureRequested(GNSS_CONFIG_MESSAGE_RATE_NMEA)) + { + if (gnss->setMessagesNMEA() == true) + { + gnssConfigureClear(GNSS_CONFIG_MESSAGE_RATE_NMEA); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } + } + + if (gnssConfigureRequested(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER)) + { + if (inRoverMode() == false) + { + systemPrintln("Error: Change to RTCM Rover rates requested but not in Rover mode. Skipping."); + } + else + { + if (gnss->setMessagesRTCMRover() == true) + { + gnssConfigureClear(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } + } + } + + if (gnssConfigureRequested(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE)) + { + if (inBaseMode() == false) + { + systemPrintln("Error: Change to RTCM Base rates requested but not in Base mode. Skipping."); + } + else + { + if (gnss->setMessagesRTCMBase() == true) + { + gnssConfigureClear(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } + } + } + + if (gnssConfigureRequested(GNSS_CONFIG_MESSAGE_RATE_OTHER)) + { + // TODO - It is not clear where LG290P PQTM messages are being enabled + gnssConfigureClear(GNSS_CONFIG_MESSAGE_RATE_OTHER); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } + if (gnssConfigureRequested(GNSS_CONFIG_TILT)) { if (gnss->setTilt() == true) @@ -254,9 +319,28 @@ void gnssUpdate() gnssConfigureClear(GNSS_CONFIG_SAVE); } + if (gnssConfigureRequested(GNSS_CONFIG_RESET)) + { + if (gnss->reset()) + gnssConfigureClear(GNSS_CONFIG_RESET); + } + // If gnssConfigureRequest bits are still set, the next update will attempt to service them. + if (settings.gnssConfigureRequest != 0 && settings.debugGnssConfig) + { + systemPrint("Remaining gnssConfigureRequest: "); + + for (int x = 0; x < GNSS_CONFIG_MAX; x++) + { + if (gnssConfigureRequested(x)) + systemPrintf("%s ", gnssConfigDisplayNames[x]); + } + systemPrintln(); + } + // settings.gnssConfigureRequest was likely changed. Record the current config state to ESP32 NVM + Serial.printf("enableExtCorrRadio: %d\r\n", settings.enableExtCorrRadio); recordSystemSettings(); } // end bluetoothCommandIsConnected(), inMainMenu, inWebConfigMode() } @@ -300,15 +384,15 @@ bool gnssConfigureRequested(uint8_t configureBit) } // Set all bits in the request bitfield to cause the GNSS receiver to go through a full (re)configuration -void gnssConfigureAll() +void gnssConfigureDefaults() { for (int x = 0; x < GNSS_CONFIG_MAX; x++) gnssConfigure(x); - // After setting all bits, clear the base bits - // TODO make this a GNSS_CONFIG_MODEf + // Clear request bits that do not need to be set after a factory reset gnssConfigureClear(GNSS_CONFIG_BASE); gnssConfigureClear(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); + gnssConfigureClear(GNSS_CONFIG_RESET); } // Returns true once all configuration requests are cleared @@ -332,9 +416,10 @@ bool gnssCmdUpdateConstellations(const char *settingName, void *settingData, int //---------------------------------------- // Update the message rates following a set command //---------------------------------------- +// TODO make RTCM and NMEA specific call backs bool gnssCmdUpdateMessageRates(const char *settingName, void *settingData, int settingType) { - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings return (true); } @@ -345,7 +430,8 @@ bool gnssCmdUpdateMessageRates(const char *settingName, void *settingData, int s bool pointPerfectCmdUpdateServiceType(const char *settingName, void *settingData, int settingType) { // Require a rover restart to enable / disable RTCM for PPL - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); return (true); } @@ -507,6 +593,8 @@ void gnssBoot() { digitalWrite(pin_GNSS_Reset, HIGH); // Tell LG290P to boot } + else + systemPrintln("Uncaught gnssBoot()"); } // Based on the platform, put the GNSS receiver into reset @@ -528,6 +616,8 @@ void gnssReset() { digitalWrite(pin_GNSS_Reset, LOW); // Tell LG290P to reset } + else + systemPrintln("Uncaught gnssReset()"); } //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index eb6e5f120..1f85a1d8c 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -98,6 +98,12 @@ void GNSS_LG290P::begin() } systemPrintln("GNSS LG290P online"); + // Check baud settings. LG290P has a limited number of allowable bauds + if (baudIsAllowed(settings.dataPortBaud) == false) + settings.dataPortBaud = 460800; + if (baudIsAllowed(settings.radioPortBaud) == false) + settings.radioPortBaud = 115200; + online.gnss = true; // Check firmware version and print info @@ -227,23 +233,15 @@ bool GNSS_LG290P::configureOnce() Enable selected NMEA messages on COM2 Enable selected RTCM messages on COM2 */ - - if (settings.gnssConfiguredOnce) - { - systemPrintln("LG290P configuration maintained"); - return (true); - } - - if (settings.debugGnss) - debuggingEnable(); // Print all debug to Serial - serialGNSS->flush(); // Remove any incoming characters bool response = true; uint8_t retries = 4; - while ((retries > 0) && (!enterConfigMode(500))) + // Do we really need configMode? + + while ((retries > 0) && (enterConfigMode(500) == false)) { online.gnss = true; // Mark online so enterConfigMode can re-enter retries--; @@ -254,40 +252,11 @@ bool GNSS_LG290P::configureOnce() if (settings.debugGnss && response == false) systemPrintln("configureOnce: Enter config mode failed"); - // Check baud settings. LG290P has a limited number of allowable bauds - if (baudIsAllowed(settings.dataPortBaud) == false) - settings.dataPortBaud = 460800; - if (baudIsAllowed(settings.radioPortBaud) == false) - settings.radioPortBaud = 115200; - - // Set the baud rate for the three UARTs - if (response == true) - { - response &= setBaudRateData(settings.dataPortBaud); // If available, set baud of DATA port - - // The following setBaudRateComm() is redundant because to get this far, the comm interface must already be - // working response &= setBaudRateComm(115200 * 4); // Set baud for main comm channel - - response &= setBaudRateRadio(settings.radioPortBaud); // If available, set baud of RADIO port - - if (response == false && settings.debugGnss) - systemPrintln("configureOnce: setBauds failed."); - } - - // Enable PPS signal with a width of 200ms - if (response == true) - { - response &= _lg290p->setPPS(200, false, true); // duration time ms, alwaysOutput, polarity - if (settings.debugGnss && response == false) - systemPrintln("configureOnce: setPPS failed"); - } - - if (response == true) - { - response &= setConstellations(); - if (settings.debugGnss && response == false) - systemPrintln("configureOnce: setConstellations failed"); - } + // Set the baud rate for the two non-ESP32 connected UARTs + // gnssConfigure(GNSS_CONFIG_BAUD_RATE_DATA); // These are set after a factory reset + // gnssConfigure(GNSS_CONFIG_BAUD_RATE_RADIO); + // gnssConfigure(GNSS_CONFIG_PPS); // Enable PPS signal with a width of 200ms + // gnssConfigure(GNSS_CONFIG_CONSTELLATION); // We do not set Rover or fix rate here because fix rate only applies in rover mode. @@ -298,15 +267,10 @@ bool GNSS_LG290P::configureOnce() online.gnss = true; // If we failed before, mark as online now systemPrintln("LG290P configuration updated"); - - // Save the current configuration into non-volatile memory (NVM) - response &= saveConfiguration(); } else online.gnss = false; // Take it offline - settings.gnssConfiguredOnce = response; - return (response); } @@ -320,18 +284,6 @@ bool GNSS_LG290P::configureRover() Enable RTCM messages on UART1/2/3 Enable NMEA on UART1/2/3 */ - if (online.gnss == false) - { - systemPrintln("GNSS not online"); - return (false); - } - - // If our settings haven't changed, trust GNSS's settings - if (settings.gnssConfiguredRover) - { - systemPrintln("Skipping LG290P Rover configuration"); - return (true); - } bool response = true; @@ -349,51 +301,7 @@ bool GNSS_LG290P::configureRover() if (settings.debugGnss && response == false) systemPrintln("configureRover: Enter config mode failed"); - // We must force receiver into Rover mode so that we can set fix rate - int currentMode = getMode(); - if (currentMode != 1) // 0 - Unknown, 1 - Rover, 2 - Base - { - // response &= _lg290p->setModeRover(); // Wait for save and reset - // Ignore result for now. enterConfigMode disables NMEA, which causes the built-in write/save/reset methods to - // fail because NMEA is not present. - _lg290p->setModeRover(); // Wait for save and reset - if (settings.debugGnss && response == false) - systemPrintln("configureRover: Set mode rover failed"); - } - - response &= setElevation(settings.minElev); - - response &= setMinCno(settings.minCNO); - - // If we are on a platform that supports tilt - if (present.tiltPossible == true) - { - // And tilt is present and enabled - if (present.imu_im19 == true && settings.enableTiltCompensation == true) - { - // Configure GNSS to support the tilt sensor - - // Tilt sensor requires 5Hz at a minimum - if (settings.measurementRateMs > 200) - { - systemPrintln("Increasing GNSS measurement rate to 5Hz for tilt support"); - settings.measurementRateMs = 200; - } - - // On the LG290P Flex module, UART 3 of the GNSS is connected to the IMU UART 1 - response &= setBaudRate(3, 115200); - - if (response == false && settings.debugGnss) - systemPrintln("configureRover: setBaud failed."); - - // Enable of GGA, RMC, GST for tilt sensor is done in setMessagesNMEA() - } - } - - // Set the fix rate. Default on LG290P is 10Hz so set accordingly. - response &= setRate(settings.measurementRateMs / 1000.0); // May require save/reset - if (settings.debugGnss && response == false) - systemPrintln("configureRover: Set rate failed"); + gnssConfigure(GNSS_CONFIG_RATE); response &= setHighAccuracyService(settings.enableGalileoHas); @@ -417,7 +325,7 @@ bool GNSS_LG290P::configureRover() response &= saveConfiguration(); // For RTCM and MSM messages to take effect (ie, PointPerfect is active) we must save/reset - softwareReset(); + reset(); if (settings.debugGnss && response) systemPrintln("LG290P Rover configured"); @@ -532,7 +440,7 @@ bool GNSS_LG290P::configureBase() // Save the current configuration into non-volatile memory (NVM) response &= saveConfiguration(); - softwareReset(); + reset(); // When a device is changed from Rover to Base, NMEA messages settings do not survive PQTMSAVEPAR // Re-enable NMEA post reset @@ -646,7 +554,7 @@ bool GNSS_LG290P::disableSurveyIn(bool saveAndReset) response &= saveConfiguration(); if (settings.debugGnss && response == false) systemPrintln("disableSurveyIn: save failed"); - response &= softwareReset(); + response &= reset(); if (settings.debugGnss && response == false) systemPrintln("disableSurveyIn: reset failed"); } @@ -699,7 +607,7 @@ void GNSS_LG290P::factoryReset() _lg290p->factoryRestore(); // Restores the parameters configured by all commands to their default values. // This command takes effect after restarting. - softwareReset(); // Reboot the receiver. + reset(); // Reboot the receiver. systemPrintln("Waiting for LG290P to reboot"); while (1) @@ -1595,7 +1503,11 @@ void GNSS_LG290P::menuMessages() for (int x = 0; x < MAX_LG290P_PQTM_MSG; x++) settings.lg290pMessageRatesPQTM[x] = lgMessagesPQTM[x].msgDefaultRate; - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); + if (inBaseMode()) + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); + else + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); systemPrintln("Reset to Defaults"); } @@ -1640,13 +1552,14 @@ void GNSS_LG290P::menuMessages() systemPrintln("Reset to PPP Logging Defaults (NMEAx7 / RTCMx4 - 30 second decimation)"); } - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings } else if ((incoming == 13) && (namedSettingAvailableOnPlatform("useMSM7"))) // Redundant - but good practice for code reuse) { settings.useMSM7 ^= 1; - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) @@ -1792,7 +1705,7 @@ void GNSS_LG290P::menuMessagesSubtype(int *localMessageRate, const char *message if (getNewSetting(messageString, 0, 1, &newSetting) == INPUT_RESPONSE_VALID) { settings.lg290pMessageRatesPQTM[incoming] = newSetting; - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Configure receiver to use new setting + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_OTHER); // Configure receiver to use new setting } } } @@ -2487,11 +2400,28 @@ bool GNSS_LG290P::setRate(double secondsBetweenSolutions) int currentMode = getMode(); if (currentMode == 2) // Base { - if (settings.debugGnss || settings.debugCorrections) - systemPrintln("Error: setRate can only be used in Rover mode"); + systemPrintln("Error: setRate can only be used in Rover mode"); return (false); } + bool response = true; + + // Change to rover mode + if (currentMode != 1) // 0 - Unknown, 1 - Rover, 2 - Base + { + // response &= _lg290p->setModeRover(); // Wait for save and reset + // Ignore result for now. enterConfigMode disables NMEA, which causes the built-in write/save/reset methods to + // fail because NMEA is not present. + _lg290p->setModeRover(); // Wait for save and reset + if (response == false && settings.debugGnssConfig) + systemPrintln("configureRover: Set mode rover failed"); + } + + // // Set the fix rate. Default on LG290P is 10Hz so set accordingly. + // response &= setRate(settings.measurementRateMs / 1000.0); // May require save/reset + // if (settings.debugGnss && response == false) + // systemPrintln("configureRover: Set rate failed"); + // The LG290P has a fix interval and a message output rate // Fix interval is in milliseconds // The message output rate is the number of fix calculations before a message is issued @@ -2499,8 +2429,6 @@ bool GNSS_LG290P::setRate(double secondsBetweenSolutions) // LG290P has fix interval in milliseconds uint16_t msBetweenSolutions = secondsBetweenSolutions * 1000; - bool response = true; - // The LG290P requires some settings to be applied and then a software reset to occur to take affect // A soft reset takes multiple seconds so we will read, then write if required. uint16_t fixInterval; @@ -2522,7 +2450,7 @@ bool GNSS_LG290P::setRate(double secondsBetweenSolutions) response &= saveConfiguration(); - response &= softwareReset(); + response &= reset(); int maxTries = 10; for (int x = 0; x < maxTries; x++) @@ -2563,37 +2491,37 @@ bool GNSS_LG290P::setTalkerGNGGA() //---------------------------------------- bool GNSS_LG290P::setTilt() { - // Not yet available on this platform - return false; -} + if (present.tiltPossible == false) + return (true); // No tilt on this platform. Report success to clear request. + if (present.imu_im19 == false) + return (true); // No tilt on this platform. Report success to clear request. -//---------------------------------------- -// Reset GNSS via software command -// Poll for isConnected() -//---------------------------------------- -bool GNSS_LG290P::softwareReset() -{ - if (online.gnss) + bool response = true; + + // Tilt is present + if (settings.enableTiltCompensation == true) { - _lg290p->reset(); + // If enabled, configure GNSS to support the tilt sensor - // Poll for a limited amount of time before unit comes back - int x = 0; - while (x++ < 50) + // Tilt sensor requires 5Hz at a minimum + if (settings.measurementRateMs > 200) { - delay(100); // Wait for device to reboot - if (_lg290p->isConnected() == true) - break; - else - systemPrintln("GNSS still rebooting"); + systemPrintln("Increasing GNSS measurement rate to 5Hz for tilt support"); + settings.measurementRateMs = 200; + gnssConfigure(GNSS_CONFIG_RATE); } - if (x < 50) - return (true); - systemPrintln("GNSS failed to connect after reboot"); + // On the LG290P Flex module, UART 3 of the GNSS is connected to the IMU UART 1 + response &= setBaudRate(3, 115200); + + if (response == false && settings.debugGnssConfig) + systemPrintln("configureRover: setBaud failed."); + + // Enable of GGA, RMC, GST for tilt sensor is done in setMessagesNMEA() } - return (false); + + return response; } //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.h b/Firmware/RTK_Everywhere/GNSS_UM980.h index a8626c48a..180517f32 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.h +++ b/Firmware/RTK_Everywhere/GNSS_UM980.h @@ -116,9 +116,6 @@ class GNSS_UM980 : GNSS // Turn off all NMEA and RTCM void disableAllOutput(); - // Disable all output, then re-enable - void disableRTCM(); - uint8_t getActiveNmeaMessageCount(); // Given the name of an NMEA message, return the array number diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index 5b19408fc..1398a61af 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -15,6 +15,10 @@ GNSS_UM980.ino #ifdef COMPILE_UM980 +bool um980MessagesEnabled_NMEA = false; // Goes true when we enable NMEA messages +bool um980MessagesEnabled_RTCM_Rover = false; // Goes true when we enable RTCM Rover messages +bool um980MessagesEnabled_RTCM_Base = false; // Goes true when we enable RTCM Base messages + //---------------------------------------- // If we have decryption keys, configure module // Note: don't check online.lband_neo here. We could be using ip corrections @@ -395,15 +399,6 @@ void GNSS_UM980::disableAllOutput() } } -//---------------------------------------- -// Disable all output, then re-enable NMEA -//---------------------------------------- -void GNSS_UM980::disableRTCM() -{ - disableAllOutput(); - setMessagesNMEA(); -} - //---------------------------------------- void GNSS_UM980::enableGgaForNtrip() { @@ -1137,7 +1132,11 @@ void GNSS_UM980::menuMessages() systemPrintln("Reset to Defaults"); - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings + if (inBaseMode()) + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); // Request receiver to use new settings + else + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings } else if (incoming == 11 || incoming == 12) { @@ -1173,7 +1172,11 @@ void GNSS_UM980::menuMessages() systemPrintln("Reset to PPP Logging (NMEAx5 / RTCMx4 - 30 second decimation)"); } - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings + if (inBaseMode()) + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); // Request receiver to use new settings + else + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) @@ -1278,13 +1281,20 @@ void GNSS_UM980::menuMessagesSubtype(float *localMessageRate, const char *messag newSetting = floor(newSetting); if (strcmp(messageType, "NMEA") == 0) + { settings.um980MessageRatesNMEA[incoming] = (float)newSetting; + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings + } if (strcmp(messageType, "RTCMRover") == 0) + { settings.um980MessageRatesRTCMRover[incoming] = (float)newSetting; + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings + } if (strcmp(messageType, "RTCMBase") == 0) + { settings.um980MessageRatesRTCMBase[incoming] = (float)newSetting; - - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); // Request receiver to use new settings + } } } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) @@ -1411,7 +1421,7 @@ bool GNSS_UM980::setBaudRateData(uint32_t baudRate) bool GNSS_UM980::setBaudRateRadio(uint32_t baudRate) { - return false; // UM980 has no RADIO port + return true; // UM980 has no RADIO port } //---------------------------------------- @@ -1426,24 +1436,27 @@ bool GNSS_UM980::setConstellations() for (int constellationNumber = 0; constellationNumber < MAX_UM980_CONSTELLATIONS; constellationNumber++) { - if (settings.um980Constellations[constellationNumber]) + if (settings.um980Constellations[constellationNumber] > 0) { - if (_um980->enableConstellation(um980ConstellationCommands[constellationNumber].textCommand) == false) + response &= _um980->enableConstellation(um980ConstellationCommands[constellationNumber].textCommand); + if (response == false) { if (settings.debugGnss) - systemPrintf("Enable constellation failed at constellationNumber %d %s.", constellationNumber, - um980ConstellationCommands[constellationNumber].textName); - response &= false; // If any one of the commands fails, report failure overall + systemPrintf("setConstellations failed to enable constellation %s [%d].\r\n", + um980ConstellationCommands[constellationNumber].textName, constellationNumber); + return (false); // Don't attempt other messages, assume communication is down } } else { - if (_um980->disableConstellation(um980ConstellationCommands[constellationNumber].textCommand) == false) + response &= _um980->disableConstellation(um980ConstellationCommands[constellationNumber].textCommand); + + if (response == false) { if (settings.debugGnss) - systemPrintf("Disable constellation failed at constellationNumber %d %s.", constellationNumber, - um980ConstellationCommands[constellationNumber].textName); - response &= false; // If any one of the commands fails, report failure overall + systemPrintf("setConstellations failed to disable constellation %s [%d].\r\n", + um980ConstellationCommands[constellationNumber].textName, constellationNumber); + return (false); // Don't attempt other messages, assume communication is down } } } @@ -1555,29 +1568,55 @@ bool GNSS_UM980::setMinCno(uint8_t cn0Value) //---------------------------------------- bool GNSS_UM980::setMessagesNMEA() { - // The UM980 is unique in that there is a UNLOG command that turns off all - // reported NMEA/RTCM messages. From this point, we could only send the commands to - // turn on the >0 messages. However, we don't use this technique, and instead send the - // command for every possible NMEA/RTCM message, because sending UNLOG would - // turn off both NMEA and RTCM, and in doing so would disrupt any previous config - // of NMEA or RTCM (individually). - // Ultimately, we must send a command for each >=0 setting in the associated message array. - bool response = true; bool gpggaEnabled = false; bool gpzdaEnabled = false; + // The UM980 is unique in that there is a UNLOG command that turns off all + // reported NMEA/RTCM messages. Sending message rates of 0 works, until a + // message rate >0 is sent. Any following sending of message rates of 0 do not + // get a response. Our approach: UNLOG and set a global, and request + // RTCM be reconfigured. Send config requests only for >0 messages. + // At the end of RTCM reconfig, clear global. This approach + // presumes NMEA then RTCM will be configured in that order. Brittle but moving on. + + if (settings.debugGnssConfig == true) + systemPrintln("setMessagesNMEA disabling output"); + + disableAllOutput(); + um980MessagesEnabled_NMEA = false; + + if (um980MessagesEnabled_RTCM_Rover == true || um980MessagesEnabled_RTCM_Base == true) + { + um980MessagesEnabled_RTCM_Rover = false; + um980MessagesEnabled_RTCM_Base = false; + + // Request reconfigure of RTCM + if (inBaseMode()) + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); + else + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); + } + for (int messageNumber = 0; messageNumber < MAX_UM980_NMEA_MSG; messageNumber++) { - // If any one of the commands fails, report failure overall - response &= _um980->setNMEAPortMessage(umMessagesNMEA[messageNumber].msgTextName, "COM3", - settings.um980MessageRatesNMEA[messageNumber]); + if (settings.um980MessageRatesNMEA[messageNumber] > 0) + { + // If any one of the commands fails, report failure overall + response &= _um980->setNMEAPortMessage(umMessagesNMEA[messageNumber].msgTextName, "COM3", + settings.um980MessageRatesNMEA[messageNumber]); - if (response == false && settings.debugGnss) - systemPrintf("Enable NMEA failed at messageNumber %d %s.\r\n", messageNumber, - umMessagesNMEA[messageNumber].msgTextName); + if (response == false) + { + if (settings.debugGnss) + systemPrintf("setMessagesNMEA failed to set %0.2f for message %s [%d].\r\n", + settings.um980MessageRatesNMEA[messageNumber], + umMessagesNMEA[messageNumber].msgTextName, messageNumber); + return (false); // Don't attempt other messages, assume communication is down + } + } - // If we are using IP based corrections, we need to send local data to the PPL + // If we are using MQTT based corrections, we need to send local data to the PPL // The PPL requires being fed GPGGA/ZDA, and RTCM1019/1020/1042/1046 if (pointPerfectServiceUsesKeys()) { @@ -1601,6 +1640,9 @@ bool GNSS_UM980::setMessagesNMEA() response &= _um980->setNMEAPortMessage("GPZDA", "COM3", 1); } + if (response == true) + um980MessagesEnabled_NMEA = true; + return (response); } @@ -1611,17 +1653,36 @@ bool GNSS_UM980::setMessagesRTCMBase() { bool response = true; + if (um980MessagesEnabled_NMEA == false) + { + // If this function was called by itself (without NMEA running previously) then + // force call NMEA enable here. It will disable all output, then should um980MessagesEnabled_NMEA = true. + setMessagesNMEA(); + } + for (int messageNumber = 0; messageNumber < MAX_UM980_RTCM_MSG; messageNumber++) { - // If any one of the commands fails, report failure overall - response &= _um980->setRTCMPortMessage(umMessagesRTCM[messageNumber].msgTextName, "COM3", - settings.um980MessageRatesRTCMBase[messageNumber]); + if (settings.um980MessageRatesRTCMBase[messageNumber] > 0) + { - if (response == false && settings.debugGnss) - systemPrintf("setMessagesRTCMBase failed at messageNumber %d %s.\r\n", messageNumber, - umMessagesRTCM[messageNumber].msgTextName); + // If any one of the commands fails, report failure overall + response &= _um980->setRTCMPortMessage(umMessagesRTCM[messageNumber].msgTextName, "COM3", + settings.um980MessageRatesRTCMBase[messageNumber]); + + if (response == false) + { + if (settings.debugGnss) + systemPrintf("setMessagesRTCMBase failed to set %0.2f for message %s [%d].\r\n", + settings.um980MessageRatesRTCMBase[messageNumber], + umMessagesRTCM[messageNumber].msgTextName, messageNumber); + return (false); // Don't attempt other messages, assume communication is down + } + } } + if (response == true) + um980MessagesEnabled_RTCM_Base = true; + return (response); } @@ -1636,15 +1697,27 @@ bool GNSS_UM980::setMessagesRTCMRover() bool rtcm1042Enabled = false; bool rtcm1046Enabled = false; + if (um980MessagesEnabled_NMEA == false) + { + // If this function was called by itself (without NMEA running previously) then + // force call NMEA enable here. It will disable all output, then should um980MessagesEnabled_NMEA = true. + setMessagesNMEA(); + } + for (int messageNumber = 0; messageNumber < MAX_UM980_RTCM_MSG; messageNumber++) { - if (_um980->setRTCMPortMessage(umMessagesRTCM[messageNumber].msgTextName, "COM3", - settings.um980MessageRatesRTCMRover[messageNumber]) == false) + if (settings.um980MessageRatesRTCMRover[messageNumber] > 0) { - if (settings.debugGnss) - systemPrintf("Enable RTCM failed at messageNumber %d %s.", messageNumber, - umMessagesRTCM[messageNumber].msgTextName); - response &= false; // If any one of the commands fails, report failure overall + response &= _um980->setRTCMPortMessage(umMessagesRTCM[messageNumber].msgTextName, "COM3", + settings.um980MessageRatesRTCMRover[messageNumber]); + if (response == false) + { + if (settings.debugGnss) + systemPrintf("setMessagesRTCMRover failed to set %0.2f for message %s [%d].\r\n", + settings.um980MessageRatesRTCMRover[messageNumber], + umMessagesRTCM[messageNumber].msgTextName, messageNumber); + return (false); // Don't attempt other messages, assume communication is down + } } // If we are using IP based corrections, we need to send local data to the PPL @@ -1679,6 +1752,9 @@ bool GNSS_UM980::setMessagesRTCMRover() response &= _um980->setRTCMPortMessage("RTCM1046", "COM3", 1); } + if (response == true) + um980MessagesEnabled_RTCM_Rover = true; + return (response); } @@ -1779,35 +1855,38 @@ bool GNSS_UM980::setRate(double secondsBetweenSolutions) if (changeRequired == false) { - if (settings.debugGnss) + if (settings.debugGnssConfig) systemPrintln("setRate: No change required"); return (true); // Success } - if (settings.debugGnss) + if (settings.debugGnssConfig) systemPrintln("setRate: Modifying rates"); bool response = true; - disableAllOutput(); // Turn everything off, before we turn on specific messages + // disableAllOutput(); // Turn everything off, before we turn on specific messages + + // // Overwrite any enabled messages with this rate + // for (int messageNumber = 0; messageNumber < MAX_UM980_NMEA_MSG; messageNumber++) + // { + // if (settings.um980MessageRatesNMEA[messageNumber] > 0) + // settings.um980MessageRatesNMEA[messageNumber] = secondsBetweenSolutions; + // } + // response &= setMessagesNMEA(); // Enact these rates + + // // TODO We don't know what state we are in, so we don't + // // know which RTCM settings to update. Assume we are + // // in rover for now + // for (int messageNumber = 0; messageNumber < MAX_UM980_RTCM_MSG; messageNumber++) + // { + // if (settings.um980MessageRatesRTCMRover[messageNumber] > 0) + // settings.um980MessageRatesRTCMRover[messageNumber] = secondsBetweenSolutions; + // } + // response &= setMessagesRTCMRover(); // Enact these rates - // Overwrite any enabled messages with this rate - for (int messageNumber = 0; messageNumber < MAX_UM980_NMEA_MSG; messageNumber++) - { - if (settings.um980MessageRatesNMEA[messageNumber] > 0) - settings.um980MessageRatesNMEA[messageNumber] = secondsBetweenSolutions; - } - response &= setMessagesNMEA(); // Enact these rates - - // TODO We don't know what state we are in, so we don't - // know which RTCM settings to update. Assume we are - // in rover for now - for (int messageNumber = 0; messageNumber < MAX_UM980_RTCM_MSG; messageNumber++) - { - if (settings.um980MessageRatesRTCMRover[messageNumber] > 0) - settings.um980MessageRatesRTCMRover[messageNumber] = secondsBetweenSolutions; - } - response &= setMessagesRTCMRover(); // Enact these rates + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // If we successfully set rates, only then record to settings if (response) @@ -1860,25 +1939,20 @@ bool GNSS_UM980::setTilt() } //---------------------------------------- -// Hotstart GNSS -// Needed on ZED based products where RTK Float lock is seen using L-Band -// Not used on UM980 based devices +// Reset the GNSS receiver either through hardware or software //---------------------------------------- bool GNSS_UM980::reset() { // Hardware reset the Torch in case UM980 is unresponsive if (productVariant == RTK_TORCH) - { digitalWrite(pin_GNSS_DR_Reset, LOW); // Tell UM980 and DR to reset - } delay(500); if (productVariant == RTK_TORCH) - { digitalWrite(pin_GNSS_DR_Reset, HIGH); // Tell UM980 and DR to boot - } - return false; + + return true; } //---------------------------------------- @@ -2040,7 +2114,7 @@ void um980FirmwareBeginUpdate() // Note: UM980 needs its own dedicated update function, due to the T@ and bootloader trigger - // Note: UM980 is cuurrently only available on Torch. + // Note: UM980 is currently only available on Torch. // But um980FirmwareBeginUpdate has been reworked so it will work on Facet too. // Note: um980FirmwareBeginUpdate is called during setup, after identify board. I2C, gpio expanders, buttons @@ -2100,7 +2174,10 @@ void um980FirmwareBeginUpdate() if (nextIncoming == '@') { // Reset UM980 - gnss->reset(); + gnssReset(); + delay(500); + gnssBoot(); + delay(500); inBootMode = true; } } diff --git a/Firmware/RTK_Everywhere/Tasks.ino b/Firmware/RTK_Everywhere/Tasks.ino index 291f0fec2..8d5bf788f 100644 --- a/Firmware/RTK_Everywhere/Tasks.ino +++ b/Firmware/RTK_Everywhere/Tasks.ino @@ -2090,7 +2090,6 @@ void buttonCheckTask(void *e) } // Torch is a special case. Handle tilt stop and web config mode else if (productVariant == RTK_TORCH) - //else if (present.imu_im19 && (present.display_type == DISPLAY_MAX_NONE)) // TODO delete me { // Platform has no display and tilt corrections, ie RTK Torch diff --git a/Firmware/RTK_Everywhere/menuGNSS.ino b/Firmware/RTK_Everywhere/menuGNSS.ino index 07366cb1d..2e03e702e 100644 --- a/Firmware/RTK_Everywhere/menuGNSS.ino +++ b/Firmware/RTK_Everywhere/menuGNSS.ino @@ -378,7 +378,7 @@ void menuGNSS() settings.ntripClient_TransmitGGA ^= 1; // We may need to enable the GGA message. Trigger GNSS receiver reconfigure. - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request update + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request update } else if ((incoming == 15) && present.multipathMitigation) diff --git a/Firmware/RTK_Everywhere/menuMessages.ino b/Firmware/RTK_Everywhere/menuMessages.ino index cda64586d..c2630fc44 100644 --- a/Firmware/RTK_Everywhere/menuMessages.ino +++ b/Firmware/RTK_Everywhere/menuMessages.ino @@ -258,7 +258,7 @@ void menuMessagesBaseRTCM() else if ((incoming == 4) && (namedSettingAvailableOnPlatform("useMSM7"))) { settings.useMSM7 ^= 1; - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) @@ -680,8 +680,10 @@ void checkGNSSArrayDefaults() if (settings.enableExtCorrRadio == 254) { + Serial.printf("enableExtCorrRadio: %d\r\n", settings.enableExtCorrRadio); defaultsApplied = true; settings.enableExtCorrRadio = false; + Serial.printf("enableExtCorrRadio: %d\r\n", settings.enableExtCorrRadio); } if (settings.um980Constellations[0] == 254) @@ -757,6 +759,7 @@ void checkGNSSArrayDefaults() if (settings.mosaicMessageIntervalsRTCMv3Rover[0] == 0.0) { + defaultsApplied = true; for (int x = 0; x < MAX_MOSAIC_RTCM_V3_INTERVAL_GROUPS; x++) @@ -879,7 +882,7 @@ void checkGNSSArrayDefaults() if (defaultsApplied == true) { - gnssConfigureAll(); //Request a full reconfigure of the GNSS receiver + gnssConfigureDefaults(); // Request a full reconfigure of the GNSS receiver recordSystemSettings(); } } diff --git a/Firmware/RTK_Everywhere/menuPP.ino b/Firmware/RTK_Everywhere/menuPP.ino index 47721e0c0..4becffd0a 100644 --- a/Firmware/RTK_Everywhere/menuPP.ino +++ b/Firmware/RTK_Everywhere/menuPP.ino @@ -340,8 +340,9 @@ void menuPointPerfectSelectService() { settings.pointPerfectService = incoming - 1; // Align incoming to array - // Require a rover restart to enable / disable RTCM for PPL - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE); // Request receiver to use new settings + // Request re-config of RTCM Rover messages to enable / disable necessary RTCM messages for PPL + if(inRoverMode()) + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings settings.requestKeyUpdate = settings.pointPerfectService != PP_NICKNAME_DISABLED; // Force a key update - or don't From aa36327bb9fa40b20d836594bfb17ec310371f98 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Wed, 22 Oct 2025 14:54:40 -0600 Subject: [PATCH 29/68] Suppress enableExtCorrRadio check for UM980 --- Firmware/RTK_Everywhere/menuMessages.ino | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Firmware/RTK_Everywhere/menuMessages.ino b/Firmware/RTK_Everywhere/menuMessages.ino index c2630fc44..dac89bcad 100644 --- a/Firmware/RTK_Everywhere/menuMessages.ino +++ b/Firmware/RTK_Everywhere/menuMessages.ino @@ -678,13 +678,14 @@ void checkGNSSArrayDefaults() settings.dynamicModel = UM980_DYN_MODEL_SURVEY; } - if (settings.enableExtCorrRadio == 254) - { - Serial.printf("enableExtCorrRadio: %d\r\n", settings.enableExtCorrRadio); - defaultsApplied = true; - settings.enableExtCorrRadio = false; - Serial.printf("enableExtCorrRadio: %d\r\n", settings.enableExtCorrRadio); - } + // This setting is not supported on the UM980 nor is it in the command array + // so it does not get used nor recorded to NVM leading to the defaults being + // applied at every boot. Commented out to prevent this issue. + // if (settings.enableExtCorrRadio == 254) + // { + // defaultsApplied = true; + // settings.enableExtCorrRadio = false; + // } if (settings.um980Constellations[0] == 254) { From 1ec9595751ce24e72b094405311a94e8c6e3d9bb Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Wed, 22 Oct 2025 14:55:04 -0600 Subject: [PATCH 30/68] Enable GNSS debug after it is marked online --- Firmware/RTK_Everywhere/GNSS.ino | 1 - Firmware/RTK_Everywhere/GNSS_UM980.ino | 33 ++++++-------------------- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index 61931461c..a5b8f8ffd 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -340,7 +340,6 @@ void gnssUpdate() } // settings.gnssConfigureRequest was likely changed. Record the current config state to ESP32 NVM - Serial.printf("enableExtCorrRadio: %d\r\n", settings.enableExtCorrRadio); recordSystemSettings(); } // end bluetoothCommandIsConnected(), inMainMenu, inWebConfigMode() } diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index 1398a61af..ac6925a49 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -73,10 +73,6 @@ void GNSS_UM980::begin() // Instantiate the library _um980 = new UM980(); - // Turn on/off debug messages - if (settings.debugGnss) - debuggingEnable(); - // In order to reduce UM980 configuration time, the UM980 library blocks the start of BESTNAV and RECTIME until 3D // fix is achieved. However, if all NMEA messages are disabled, the UM980 will never detect a 3D fix. if (isGgaActive()) @@ -101,8 +97,15 @@ void GNSS_UM980::begin() return; } } + + online.gnss = true; + systemPrintln("GNSS UM980 online"); + // Turn on/off debug messages + if (settings.debugGnss) + debuggingEnable(); + // Check firmware version and print info printModuleInfo(); @@ -123,8 +126,6 @@ void GNSS_UM980::begin() gnssFirmwareVersionInt = 99; snprintf(gnssUniqueId, sizeof(gnssUniqueId), "%s", _um980->getID()); - - online.gnss = true; } //---------------------------------------- @@ -1865,26 +1866,6 @@ bool GNSS_UM980::setRate(double secondsBetweenSolutions) bool response = true; - // disableAllOutput(); // Turn everything off, before we turn on specific messages - - // // Overwrite any enabled messages with this rate - // for (int messageNumber = 0; messageNumber < MAX_UM980_NMEA_MSG; messageNumber++) - // { - // if (settings.um980MessageRatesNMEA[messageNumber] > 0) - // settings.um980MessageRatesNMEA[messageNumber] = secondsBetweenSolutions; - // } - // response &= setMessagesNMEA(); // Enact these rates - - // // TODO We don't know what state we are in, so we don't - // // know which RTCM settings to update. Assume we are - // // in rover for now - // for (int messageNumber = 0; messageNumber < MAX_UM980_RTCM_MSG; messageNumber++) - // { - // if (settings.um980MessageRatesRTCMRover[messageNumber] > 0) - // settings.um980MessageRatesRTCMRover[messageNumber] = secondsBetweenSolutions; - // } - // response &= setMessagesRTCMRover(); // Enact these rates - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); From 02e0f82ae8680f88dabe434f119da69f1095abd1 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Wed, 22 Oct 2025 17:11:29 -0600 Subject: [PATCH 31/68] Add UM980 getMode() --- Firmware/RTK_Everywhere/GNSS_UM980.h | 4 +++ Firmware/RTK_Everywhere/GNSS_UM980.ino | 47 ++++++++++++++------------ Firmware/RTK_Everywhere/States.ino | 2 +- 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.h b/Firmware/RTK_Everywhere/GNSS_UM980.h index 180517f32..bf6401a0d 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.h +++ b/Firmware/RTK_Everywhere/GNSS_UM980.h @@ -278,6 +278,10 @@ class GNSS_UM980 : GNSS // Returns minutes or zero if not online uint8_t getMinute(); + // Returns the current mode + // 0 - Unknown, 1 - Rover Survey, 2 - Rover UAV, 3 - Rover Auto, 4 - Base Survey-in, 5 - Base fixed + uint8_t getMode(); + // Returns month number or zero if not online uint8_t getMonth(); diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index ac6925a49..25dee1259 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -102,13 +102,10 @@ void GNSS_UM980::begin() systemPrintln("GNSS UM980 online"); - // Turn on/off debug messages + // Turn on/off debug messages if (settings.debugGnss) debuggingEnable(); - // Check firmware version and print info - printModuleInfo(); - // Shortly after reset, the UM980 responds to the VERSIONB command with OK but doesn't report version information snprintf(gnssFirmwareVersion, sizeof(gnssFirmwareVersion), "%s", _um980->getVersion()); @@ -117,11 +114,12 @@ void GNSS_UM980::begin() // Shortly after reset, the UM980 responds to the VERSIONB command with OK but doesn't report version // information delay(2000); // 1s fails, 2s ok - - // Ask for the version again after a short delay - snprintf(gnssFirmwareVersion, sizeof(gnssFirmwareVersion), "%s", _um980->getVersion()); } + // Ask for the version again after a short delay + // Check firmware version and print info + printModuleInfo(); + if (sscanf(gnssFirmwareVersion, "%d", &gnssFirmwareVersionInt) != 1) gnssFirmwareVersionInt = 99; @@ -300,19 +298,15 @@ bool GNSS_UM980::configure() //---------------------------------------- bool GNSS_UM980::configureRover() { - /* - Disable all message traffic - Cancel any survey-in modes - Set mode to Rover + dynamic model - Set minElevation - Enable RTCM messages on COM3 - Enable NMEA on COM3 - */ - // Trusting the saved configuration does not seem to work on the UM980. - // It looks like the GPGGA NMEA output does not restart...? - // (Re)configuration is quick. Doing this every time is not much of an overhead. - - bool response = true; + // Determine current mode. If we are already in Rover, no changes needed + // 0 - Unknown, 1 - Rover Survey, 2 - Rover UAV, 3 - Rover Auto, 4 - Base Survey-in, 5 - Base fixed + int currentMode = getMode(); + if (settings.dynamicModel == UM980_DYN_MODEL_SURVEY && currentMode == 1) + return (true); + if (settings.dynamicModel == UM980_DYN_MODEL_UAV && currentMode == 2) + return (true); + if (settings.dynamicModel == UM980_DYN_MODEL_AUTOMOTIVE && currentMode == 3) + return (true); // Sets the dynamic model (Survey/UAV/Automotive) and puts the device into Rover mode gnssConfigure(GNSS_CONFIG_MODEL); @@ -321,7 +315,7 @@ bool GNSS_UM980::configureRover() gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); - return (response); + return (true); } //---------------------------------------- @@ -710,6 +704,17 @@ uint8_t GNSS_UM980::getMinute() return 0; } +//---------------------------------------- +// Returns the current mode +// 0 - Unknown, 1 - Rover Survey, 2 - Rover UAV, 3 - Rover Auto, 4 - Base Survey-in, 5 - Base fixed +//---------------------------------------- +uint8_t GNSS_UM980::getMode() +{ + if (online.gnss) + return (_um980->getMode()); + return (0); +} + //---------------------------------------- // Returns month number or zero if not online //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/States.ino b/Firmware/RTK_Everywhere/States.ino index 002635221..f59662b97 100644 --- a/Firmware/RTK_Everywhere/States.ino +++ b/Firmware/RTK_Everywhere/States.ino @@ -221,7 +221,7 @@ void stateUpdate() baseStatusLedOff(); - gnssConfigure(GNSS_CONFIG_BASE); // Request reconfigure to rover mode + gnssConfigure(GNSS_CONFIG_BASE); // Request reconfigure to base mode bluetoothStop(); bluetoothStart(); // Restart Bluetooth with 'Base' identifier From a5e51f3fe8b707654cb67e62c28d890d37964789 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 23 Oct 2025 10:28:53 -0600 Subject: [PATCH 32/68] Add getMode check during UM980 configureBase --- Firmware/RTK_Everywhere/GNSS_UM980.ino | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index 25dee1259..448036e7d 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -166,17 +166,13 @@ bool GNSS_UM980::checkPPPRates() //---------------------------------------- bool GNSS_UM980::configureBase() { - /* - Disable all messages - Start base - Enable RTCM Base messages - Enable NMEA messages - */ - // Trusting the saved configuration does not seem to work on the UM980. - // It looks like the GPGGA NMEA output does not restart...? - // (Re)configuration is quick. Doing this every time is not much of an overhead. - - bool response = true; + // Determine current mode. If we are already in Rover, no changes needed + // 0 - Unknown, 1 - Rover Survey, 2 - Rover UAV, 3 - Rover Auto, 4 - Base Survey-in, 5 - Base fixed + int currentMode = getMode(); + if (settings.fixedBase == false && currentMode == 4) + return (true); + if (settings.fixedBase == true && currentMode == 5) + return (true); // Set the dynamic mode. This will cancel any base averaging mode and is needed // to allow a freshly started device to settle in regular GNSS reception mode before issuing @@ -187,7 +183,7 @@ bool GNSS_UM980::configureBase() gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); - return (response); + return (true); } //---------------------------------------- From a3f76ad2ef0b6683801c1a39d8dbcc18e7fa2e3f Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 23 Oct 2025 14:59:25 -0600 Subject: [PATCH 33/68] Move displays from states.ino to display.ino --- Firmware/RTK_Everywhere/Display.ino | 42 ++++++++++++++--------------- Firmware/RTK_Everywhere/States.ino | 10 +++---- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/Firmware/RTK_Everywhere/Display.ino b/Firmware/RTK_Everywhere/Display.ino index 1f2ccdcd7..aa4cb2f1b 100644 --- a/Firmware/RTK_Everywhere/Display.ino +++ b/Firmware/RTK_Everywhere/Display.ino @@ -284,22 +284,23 @@ void displayUpdate() */ case (STATE_ROVER_NOT_STARTED): - displayHorizontalAccuracy(&iconPropertyList, &CrossHairProperties, - 0b11111111); // Single crosshair, no blink - paintLogging(&iconPropertyList); - displaySivVsOpenShort(&iconPropertyList); - displayBatteryVsEthernet(&iconPropertyList); - displayFullIPAddress(&iconPropertyList); // Bottom left - 128x64 only - setRadioIcons(&iconPropertyList); - break; + // displayHorizontalAccuracy(&iconPropertyList, &CrossHairProperties, + // 0b11111111); // Single crosshair, no blink + // paintLogging(&iconPropertyList); + // displaySivVsOpenShort(&iconPropertyList); + // displayBatteryVsEthernet(&iconPropertyList); + // displayFullIPAddress(&iconPropertyList); // Bottom left - 128x64 only + // setRadioIcons(&iconPropertyList); + // break; case (STATE_ROVER_CONFIG_WAIT): - displayHorizontalAccuracy(&iconPropertyList, &CrossHairProperties, - 0b11111111); // Single crosshair, no blink - paintLogging(&iconPropertyList); - displaySivVsOpenShort(&iconPropertyList); - displayBatteryVsEthernet(&iconPropertyList); - displayFullIPAddress(&iconPropertyList); // Bottom left - 128x64 only - setRadioIcons(&iconPropertyList); + // displayHorizontalAccuracy(&iconPropertyList, &CrossHairProperties, + // 0b11111111); // Single crosshair, no blink + // paintLogging(&iconPropertyList); + // displaySivVsOpenShort(&iconPropertyList); + // displayBatteryVsEthernet(&iconPropertyList); + // displayFullIPAddress(&iconPropertyList); // Bottom left - 128x64 only + // setRadioIcons(&iconPropertyList); + displayRoverStart(0); break; case (STATE_ROVER_NO_FIX): displayHorizontalAccuracy(&iconPropertyList, &CrossHairProperties, @@ -343,7 +344,7 @@ void displayUpdate() case (STATE_BASE_CASTER_NOT_STARTED): case (STATE_BASE_NOT_STARTED): case (STATE_BASE_CONFIG_WAIT): - // Do nothing. Static display shown during state change. + displayBaseStart(0); // Show 'Base' while the system configures the Base break; // Start of base / survey in / NTRIP mode @@ -375,9 +376,10 @@ void displayUpdate() displayBaseSiv(&iconPropertyList); // 128x64 only break; case (STATE_BASE_FIXED_NOT_STARTED): - displayBatteryVsEthernet(&iconPropertyList); // Top right - displayFullIPAddress(&iconPropertyList); // Bottom left - 128x64 only - setRadioIcons(&iconPropertyList); + displayBaseSuccess(0); // Show 'Base Started' while the system configures the Base + // displayBatteryVsEthernet(&iconPropertyList); // Top right + // displayFullIPAddress(&iconPropertyList); // Bottom left - 128x64 only + // setRadioIcons(&iconPropertyList); break; case (STATE_BASE_FIXED_TRANSMITTING): paintLogging(&iconPropertyList); @@ -2106,8 +2108,6 @@ void displayBaseStart(uint16_t displayTime) oled->display(); - oled->display(); - delay(displayTime); } } diff --git a/Firmware/RTK_Everywhere/States.ino b/Firmware/RTK_Everywhere/States.ino index f59662b97..49a37456c 100644 --- a/Firmware/RTK_Everywhere/States.ino +++ b/Firmware/RTK_Everywhere/States.ino @@ -94,8 +94,6 @@ void stateUpdate() return; } - displayRoverStart(0); - baseStatusLedOff(); gnssConfigure(GNSS_CONFIG_ROVER); // Request reconfigure to rover mode @@ -217,8 +215,6 @@ void stateUpdate() if (online.gnss == false) return; - displayBaseStart(0); // Show 'Base' - baseStatusLedOff(); gnssConfigure(GNSS_CONFIG_BASE); // Request reconfigure to base mode @@ -253,7 +249,7 @@ void stateUpdate() } break; - // Wait for horz acc of 5m or less before starting survey in + // Wait for horizontal accuracy to reach a certain level before starting survey in case (STATE_BASE_TEMP_SETTLE): { // Blink base LED slowly while we wait for first fix if ((millis() - lastBaseLEDupdate) > 1000) @@ -266,13 +262,15 @@ void stateUpdate() int siv = gnss->getSatellitesInView(); float hpa = gnss->getHorizontalAccuracy(); - // Check for <1m horz accuracy before starting surveyIn + // Check for horizontal accuracy threshold before starting survey in char accuracy[20]; char temp[20]; const char *units = getHpaUnits(hpa, temp, sizeof(temp), 2, true); + // gnssGetSurveyInStartingAccuracy is 10m max const char *accUnits = getHpaUnits(gnss->getSurveyInStartingAccuracy(), accuracy, sizeof(accuracy), 2, false); + systemPrintf("Waiting for Horz Accuracy < %s (%s): %s%s%s%s, SIV: %d\r\n", accuracy, accUnits, temp, (accUnits != units) ? " (" : "", (accUnits != units) ? units : "", (accUnits != units) ? ")" : "", siv); From d068b5f17a0a616c790a1c5633c7d7e10a819585 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 23 Oct 2025 14:59:57 -0600 Subject: [PATCH 34/68] Add per platform fixRateIsAllowed functions --- Firmware/RTK_Everywhere/GNSS.h | 7 + Firmware/RTK_Everywhere/GNSS.ino | 26 +- Firmware/RTK_Everywhere/GNSS_LG290P.h | 7 + Firmware/RTK_Everywhere/GNSS_LG290P.ino | 352 +++++++++--------------- Firmware/RTK_Everywhere/GNSS_Mosaic.h | 7 + Firmware/RTK_Everywhere/GNSS_Mosaic.ino | 27 ++ Firmware/RTK_Everywhere/GNSS_None.h | 16 ++ Firmware/RTK_Everywhere/GNSS_UM980.h | 7 + Firmware/RTK_Everywhere/GNSS_UM980.ino | 52 ++-- Firmware/RTK_Everywhere/GNSS_ZED.h | 7 + Firmware/RTK_Everywhere/GNSS_ZED.ino | 79 ++++-- Firmware/RTK_Everywhere/menuBase.ino | 40 +-- Firmware/RTK_Everywhere/menuGNSS.ino | 82 +++--- 13 files changed, 365 insertions(+), 344 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.h b/Firmware/RTK_Everywhere/GNSS.h index b6e0d92b6..37be83eca 100644 --- a/Firmware/RTK_Everywhere/GNSS.h +++ b/Firmware/RTK_Everywhere/GNSS.h @@ -131,6 +131,13 @@ class GNSS // Returns true if successfully started and false upon failure virtual bool fixedBaseStart(); + virtual bool fixRateIsAllowed(uint32_t fixRateMs); + + //Return min/max rate in ms + virtual uint32_t fixRateGetMinimumMs(); + + virtual uint32_t fixRateGetMaximumMs(); + // Return the number of active/enabled messages virtual uint8_t getActiveMessageCount(); diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index a5b8f8ffd..bb432e2f3 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -152,14 +152,26 @@ void gnssUpdate() if (gnssConfigureRequested(GNSS_CONFIG_BASE)) { - if (gnss->configureBase() == true) + // Change GNSS receiver configuration if we are in base mode, otherwise, just change setting + if (inBaseMode() == true) { - gnssConfigureClear(GNSS_CONFIG_BASE); - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + if (gnss->configureBase() == true) + { + gnssConfigureClear(GNSS_CONFIG_BASE); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } + else + { + systemPrintln("Base config failed"); + } } else { - systemPrintln("Base config failed"); + // We have allowed the settings struct changes, but do not need to apply them to the GNSS receiver at + // this time + if (settings.debugGnssConfig) + systemPrintln("Not in base mode - clearing bit."); + gnssConfigureClear(GNSS_CONFIG_BASE); } } @@ -357,18 +369,18 @@ void gnssVerifyTables() void gnssConfigure(uint8_t configureBit) { uint32_t mask = (1 << configureBit); - settings.gnssConfigureRequest |= mask; + settings.gnssConfigureRequest |= mask; // Set the bit } // Given a bit to configure, clear that bit from the overall bitfield void gnssConfigureClear(uint8_t configureBit) { - uint32_t mask = ~(1 << configureBit); + uint32_t mask = (1 << configureBit); if (settings.debugGnssConfig && (settings.gnssConfigureRequest & mask)) systemPrintf("GNSS Config Clear: %s\r\n", gnssConfigDisplayNames[configureBit]); - settings.gnssConfigureRequest &= mask; + settings.gnssConfigureRequest &= ~mask; // Clear the bit } // Return true if a given bit is set diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.h b/Firmware/RTK_Everywhere/GNSS_LG290P.h index da112fa31..db757872b 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.h +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.h @@ -202,6 +202,13 @@ class GNSS_LG290P : GNSS // Returns true if successfully started and false upon failure bool fixedBaseStart(); + bool fixRateIsAllowed(uint32_t fixRateMs); + + // Return min/max rate in ms + uint32_t fixRateGetMinimumMs(); + + uint32_t fixRateGetMaximumMs(); + // Return the number of active/enabled messages uint8_t getActiveMessageCount(); diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index 1f85a1d8c..883d2f1eb 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -78,10 +78,6 @@ void GNSS_LG290P::begin() // Instantiate the library _lg290p = new LG290P(); - // // Turn on/off debug messages - if (settings.debugGnss) - debuggingEnable(); - if (_lg290p->begin(*serialGNSS) == false) // Give the serial port over to the library { if (settings.debugGnss) @@ -96,16 +92,21 @@ void GNSS_LG290P::begin() return; } } + + online.gnss = true; + systemPrintln("GNSS LG290P online"); + // Turn on/off debug messages + if (settings.debugGnss) + debuggingEnable(); + // Check baud settings. LG290P has a limited number of allowable bauds if (baudIsAllowed(settings.dataPortBaud) == false) settings.dataPortBaud = 460800; if (baudIsAllowed(settings.radioPortBaud) == false) settings.radioPortBaud = 115200; - online.gnss = true; - // Check firmware version and print info _lg290p->getFirmwareVersion(lg290pFirmwareVersion); // Needs LG290P library v1.0.7 @@ -166,8 +167,11 @@ bool GNSS_LG290P::beginExternalEvent() //---------------------------------------- bool GNSS_LG290P::setPPS() { - // TODO LG290P - return (false); + bool response = _lg290p->setPPS(200, false, true); // duration time ms, alwaysOutput, polarity + if (settings.debugGnssConfig && response == false) + systemPrintln("setPPS failed"); + + return (response); } //---------------------------------------- @@ -220,58 +224,9 @@ bool GNSS_LG290P::configure() //---------------------------------------- bool GNSS_LG290P::configureOnce() { - /* - Disable all message traffic - Set COM port baud rates, - LG290P COM1 - DATA / Direct to USB, 115200 - LG290P COM2 - BT and GNSS config. Configured for 115200 from begin(). - LG290P COM3 - RADIO / Direct output to locking JST connector. - Set minCNO - Set elevationAngle - Set Constellations - Set messages - Enable selected NMEA messages on COM2 - Enable selected RTCM messages on COM2 -*/ - serialGNSS->flush(); // Remove any incoming characters - - bool response = true; - - uint8_t retries = 4; - - // Do we really need configMode? - - while ((retries > 0) && (enterConfigMode(500) == false)) - { - online.gnss = true; // Mark online so enterConfigMode can re-enter - retries--; - systemPrintf("configureOnce: Enter config mode failed. %d retries remaining\r\n", retries); - } - - response &= (retries > 0); - if (settings.debugGnss && response == false) - systemPrintln("configureOnce: Enter config mode failed"); - - // Set the baud rate for the two non-ESP32 connected UARTs - // gnssConfigure(GNSS_CONFIG_BAUD_RATE_DATA); // These are set after a factory reset - // gnssConfigure(GNSS_CONFIG_BAUD_RATE_RADIO); - // gnssConfigure(GNSS_CONFIG_PPS); // Enable PPS signal with a width of 200ms - // gnssConfigure(GNSS_CONFIG_CONSTELLATION); - - // We do not set Rover or fix rate here because fix rate only applies in rover mode. - - response &= exitConfigMode(); // We must exit config before we save otherwise we will save with NMEA/RTCM off - - if (response) - { - online.gnss = true; // If we failed before, mark as online now - - systemPrintln("LG290P configuration updated"); - } - else - online.gnss = false; // Take it offline - - return (response); + // Nothing to do once + // All config gets done either from mode switches or user modifications + return (true); } //---------------------------------------- @@ -279,59 +234,23 @@ bool GNSS_LG290P::configureOnce() //---------------------------------------- bool GNSS_LG290P::configureRover() { - /* - Set mode to Rover - Enable RTCM messages on UART1/2/3 - Enable NMEA on UART1/2/3 - */ - - bool response = true; + Serial.println("Config rover"); - serialGNSS->flush(); // Remove any incoming characters - - uint8_t retries = 4; - - while ((retries > 0) && (!enterConfigMode(500))) + int currentMode = getMode(); + if (currentMode == 1) // 0 - Unknown, 1 - Rover, 2 - Base { - retries--; - systemPrintf("configureRover: Enter config mode failed. %d retries remaining\r\n", retries); + if (settings.debugGnssConfig) + systemPrintln("Skipping LG290P Rover configuration"); + return (true); // No changes needed } - response &= (retries > 0); - if (settings.debugGnss && response == false) - systemPrintln("configureRover: Enter config mode failed"); + bool response = _lg290p->setModeRover(false); // Don't wait for save and reset + // Setting mode to rover should disable any survey-in gnssConfigure(GNSS_CONFIG_RATE); - - response &= setHighAccuracyService(settings.enableGalileoHas); - - response &= setMessagesRTCMRover(); - if (settings.debugGnss && response == false) - systemPrintln("configureRover: Enable RTCM failed"); - - response &= setMessagesNMEA(); - if (settings.debugGnss && response == false) - systemPrintln("configureRover: Enable NMEA failed"); - - response &= exitConfigMode(); // We must exit config before we save otherwise we will save with NMEA/RTCM off - - if (response == false) - { - systemPrintln("LG290P Rover failed to configure"); - } - else - { - // Save the current configuration into non-volatile memory (NVM) - response &= saveConfiguration(); - - // For RTCM and MSM messages to take effect (ie, PointPerfect is active) we must save/reset - reset(); - - if (settings.debugGnss && response) - systemPrintln("LG290P Rover configured"); - } - - settings.gnssConfiguredRover = response; + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); + gnssConfigure(GNSS_CONFIG_RESET); // Mode change requires reset return (response); } @@ -341,46 +260,36 @@ bool GNSS_LG290P::configureRover() //---------------------------------------- bool GNSS_LG290P::configureBase() { - /* - Disable all messages - Enable RTCM Base messages - Enable NMEA messages - */ + bool response = true; - if (online.gnss == false) - { - systemPrintln("GNSS not online"); - return (false); - } + int currentMode = getMode(); + uint8_t surveyInMode = getSurveyInMode(); // 0 - Disabled, 1 - Survey-in mode, 2 - Fixed mode - // If the device is set to Survey-In, we must allow the device to be configured. - // Otherwise PQTMEPE (estimated position error) is never populated, so the survey - // never starts (Waiting for Horz Accuracy < 2.00m...) - if (settings.fixedBase == false) // Not a fixed base = Survey-in + if (currentMode == 2) // 0 - Unknown, 1 - Rover, 2 - Base { - if (settings.gnssConfiguredBase) + if (settings.fixedBase == true && surveyInMode == 2) { - if (settings.debugGnss) - systemPrintln("Skipping LG290P Base configuration"); - return true; + if (settings.debugGnssConfig) + systemPrintln("Skipping LG290P Fixed Base configuration"); + return (true); // No changes needed + } + if (settings.fixedBase == false && surveyInMode == 1) + { + if (settings.debugGnssConfig) + systemPrintln("Skipping LG290P Survey-in Base configuration"); + return (true); // No changes needed } } - bool response = true; - - serialGNSS->flush(); // Remove any incoming characters - - uint8_t retries = 4; - - while ((retries > 0) && (!enterConfigMode(500))) - { - retries--; - systemPrintf("configureBase: Enter config mode failed. %d retries remaining\r\n", retries); - } - - response &= (retries > 0); - if (settings.debugGnss && response == false) - systemPrintln("configureBase: Enter config mode failed"); + // If the device is set to Survey-In, we must allow the device to be configured. + // Otherwise PQTMEPE (estimated position error) is never populated, so the survey + // never starts (Waiting for Horz Accuracy < 2.00m...) + // if (currentMode == 2 && settings.fixedBase == false) // Not a fixed base = Survey-in + // { + // if (settings.debugGnssConfig) + // systemPrintln("Skipping LG290P Survey In Base configuration"); + // return true; + // } // "When set to Base Station mode, the receiver will automatically disable NMEA message output and enable RTCM MSM4 // and RTCM3-1005 message output." @@ -390,68 +299,44 @@ bool GNSS_LG290P::configureBase() // We set base mode here because we don't want to reset the module right before we (potentially) start a survey-in // We wait for States.ino to change us from base settle, to survey started, at which time the surveyInStart() is // issued. - int currentMode = getMode(); if (currentMode != 2) // 0 - Unknown, 1 - Rover, 2 - Base { - // response &= _lg290p->setModeBase(); // Wait for save and reset - // Ignore result for now. enterConfigMode disables NMEA, which causes the built-in write/save/reset methods to - // fail because NMEA is not present. - _lg290p->setModeBase(false); // Don't save and reset - if (settings.debugGnss && response == false) + response &= _lg290p->setModeBase(false); // Don't save and reset + if (settings.debugGnssConfig && response == false) systemPrintln("configureBase: Set mode base failed"); - - // Device should now have survey mode disabled } - // If we are in survey mode, then disable it - uint8_t surveyInMode = getSurveyInMode(); // 0 - Disabled, 1 - Survey-in mode, 2 - Fixed mode + // Switching to Base Mode should disable any currently running survey-in + // But if we were already in base mode, then disable any currently running survey-in if (surveyInMode == 1 || surveyInMode == 2) { - // response &= disableSurveyIn(); // Wait for save and reset - // Ignore result for now. enterConfigMode disables NMEA, which causes the built-in write/save/reset methods to - // fail because NMEA is not present. - disableSurveyIn(false); // Don't save and reset - if (settings.debugGnss && response == false) + response &= disableSurveyIn(false); // Don't save and reset + if (settings.debugGnssConfig && response == false) systemPrintln("configureBase: disable survey in failed"); } - response &= setElevation(settings.minElev); - - response &= setMinCno(settings.minCNO); - - response &= setHighAccuracyService(settings.enableGalileoHas); - - response &= setMessagesRTCMBase(); // Set RTCM messages - if (settings.debugGnss && response == false) - systemPrintln("configureBase: Enable RTCM failed"); - - response &= setMessagesNMEA(); // Set NMEA messages - if (settings.debugGnss && response == false) - systemPrintln("configureBase: Enable NMEA failed"); - - response &= exitConfigMode(); // We must exit config before we save otherwise we will save with NMEA/RTCM off - if (response == false) { systemPrintln("LG290P Base failed to configure"); } else { - // Save the current configuration into non-volatile memory (NVM) + // When switching between modes, we have to do a save, reset, then + // enable messages. Because of how GNSS.ino works, we force the + // save/reset here. response &= saveConfiguration(); reset(); - // When a device is changed from Rover to Base, NMEA messages settings do not survive PQTMSAVEPAR - // Re-enable NMEA post reset - response &= setMessagesNMEA(); // Set NMEA messages + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); + + // When a device is changed from Rover to Base, NMEA messages are disabled. Turn them back on. + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); - if (settings.debugGnss && response) + if (settings.debugGnssConfig && response) systemPrintln("LG290P Base configured"); } - settings.gnssConfiguredBase = response; - return (response); } @@ -673,6 +558,33 @@ bool GNSS_LG290P::fixedBaseStart() return (response); } +//---------------------------------------- +// Check if given GNSS fix rate is allowed +// Rates are expressed in ms between fixes. +//---------------------------------------- +const uint32_t lgAllowedFixRatesHz[] = {1, 2, 5, 10, 20}; // The LG290P doesn't support slower speeds than 1Hz +const int lgAllowedFixRatesCount = sizeof(lgAllowedFixRatesHz) / sizeof(lgAllowedFixRatesHz[0]); + +bool GNSS_LG290P::fixRateIsAllowed(uint32_t fixRateMs) +{ + for (int x = 0; x < lgAllowedFixRatesCount; x++) + if (fixRateMs == (1000.0 / lgAllowedFixRatesHz[x])) + return (true); + return (false); +} + +// Return minimum in milliseconds +uint32_t GNSS_LG290P::fixRateGetMinimumMs() +{ + return (1000.0 / lgAllowedFixRatesHz[0]); +} + +// Return maximum in milliseconds +uint32_t GNSS_LG290P::fixRateGetMaximumMs() +{ + return (1000.0 / lgAllowedFixRatesHz[lgAllowedFixRatesCount - 1]); +} + //---------------------------------------- // Return the number of active/enabled messages //---------------------------------------- @@ -1552,7 +1464,7 @@ void GNSS_LG290P::menuMessages() systemPrintln("Reset to PPP Logging Defaults (NMEAx7 / RTCMx4 - 30 second decimation)"); } - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings } else if ((incoming == 13) && @@ -1764,6 +1676,9 @@ bool GNSS_LG290P::reset() { if (online.gnss) { + if (settings.debugGnss || settings.debugGnssConfig) + systemPrintln("Rebooting LG290P"); + _lg290p->reset(); // Poll for a limited amount of time before unit comes back @@ -1894,6 +1809,8 @@ bool GNSS_LG290P::setConstellations() settings.lg290pConstellations[5]); // NavIC } + gnssConfigure(GNSS_CONFIG_RESET); // Constellation changes require device save/restart + return (response); } @@ -2105,6 +2022,13 @@ bool GNSS_LG290P::setMessagesNMEA() } } } + + if (response == true) + { + // For messages to take effect we must save/reset + gnssConfigure(GNSS_CONFIG_RESET); + } + return (response); } @@ -2190,6 +2114,12 @@ bool GNSS_LG290P::setMessagesRTCMBase() _lg290p->sendOkCommand(cfgRtcm); // Enable MSM4/7, output regular intervals, interval (seconds) } + if (response == true) + { + // For messages to take effect we must save/reset + gnssConfigure(GNSS_CONFIG_RESET); + } + return (response); } @@ -2354,6 +2284,12 @@ bool GNSS_LG290P::setMessagesRTCMRover() _lg290p->sendOkCommand(msmCommand); } + if (response == true) + { + // For messages to take effect we must save/reset + gnssConfigure(GNSS_CONFIG_RESET); + } + return (response); } @@ -2396,32 +2332,24 @@ bool GNSS_LG290P::setRate(double secondsBetweenSolutions) if (online.gnss == false) return (false); - // The fix rate can only be set in rover mode. Return false if we are in base mode. + // Read, modify, write + + // The fix rate can only be set in rover mode. Return true if we are in base mode. + // This allows the gnssUpdate() to clear the bit. int currentMode = getMode(); if (currentMode == 2) // Base - { - systemPrintln("Error: setRate can only be used in Rover mode"); - return (false); - } + return (true); // Nothing to modify at this time bool response = true; // Change to rover mode if (currentMode != 1) // 0 - Unknown, 1 - Rover, 2 - Base { - // response &= _lg290p->setModeRover(); // Wait for save and reset - // Ignore result for now. enterConfigMode disables NMEA, which causes the built-in write/save/reset methods to - // fail because NMEA is not present. - _lg290p->setModeRover(); // Wait for save and reset + response &= _lg290p->setModeRover(); // Wait for save and reset if (response == false && settings.debugGnssConfig) - systemPrintln("configureRover: Set mode rover failed"); + systemPrintln("setRate: Set mode rover failed"); } - // // Set the fix rate. Default on LG290P is 10Hz so set accordingly. - // response &= setRate(settings.measurementRateMs / 1000.0); // May require save/reset - // if (settings.debugGnss && response == false) - // systemPrintln("configureRover: Set rate failed"); - // The LG290P has a fix interval and a message output rate // Fix interval is in milliseconds // The message output rate is the number of fix calculations before a message is issued @@ -2442,41 +2370,15 @@ bool GNSS_LG290P::setRate(double secondsBetweenSolutions) // Set the fix interval response &= _lg290p->setFixInterval(msBetweenSolutions); - // Reboot receiver to apply changes if (response == true) - { - if (settings.debugGnss || settings.debugCorrections) - systemPrintln("Rebooting LG290P"); - - response &= saveConfiguration(); - - response &= reset(); - - int maxTries = 10; - for (int x = 0; x < maxTries; x++) - { - delay(1000); // Wait for device to reboot - if (_lg290p->isConnected()) - break; - else - systemPrintln("Device still rebooting"); - } - } + gnssConfigure(GNSS_CONFIG_RESET); // Reboot receiver to apply changes } } - // If we successfully set rates, then record to settings - if (response) - { - settings.measurementRateMs = msBetweenSolutions; - } - else - { - systemPrintln("Failed to set measurement and navigation rates"); - return (false); - } + if (response == false) + systemPrintln("Failed to set measurement rate"); - return (true); + return (response); } //---------------------------------------- @@ -2516,7 +2418,7 @@ bool GNSS_LG290P::setTilt() response &= setBaudRate(3, 115200); if (response == false && settings.debugGnssConfig) - systemPrintln("configureRover: setBaud failed."); + systemPrintln("setTilt: setBaud failed."); // Enable of GGA, RMC, GST for tilt sensor is done in setMessagesNMEA() } diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.h b/Firmware/RTK_Everywhere/GNSS_Mosaic.h index d471bdc3b..f25883b5a 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.h +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.h @@ -666,6 +666,13 @@ class GNSS_MOSAIC : GNSS // Returns true if successfully started and false upon failure bool fixedBaseStart(); + bool fixRateIsAllowed(uint32_t fixRateMs); + + //Return min/max rate in ms + uint32_t fixRateGetMinimumMs(); + + uint32_t fixRateGetMaximumMs(); + // Return the number of active/enabled messages uint8_t getActiveMessageCount(); diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino index 1d3026f96..5b0142a8b 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino @@ -918,6 +918,33 @@ bool GNSS_MOSAIC::fixedBaseStart() return (response); } +//---------------------------------------- +// Check if given GNSS fix rate is allowed +// Rates are expressed in ms between fixes. +//---------------------------------------- + +bool GNSS_MOSAIC::fixRateIsAllowed(uint32_t fixRateMs) +{ + //TODO + if (fixRateMs != 1000) + return (false); + return (true); +} + +// Return minimum in milliseconds +uint32_t GNSS_MOSAIC::fixRateGetMinimumMs() +{ + //TODO + return (1000); +} + +// Return maximum in milliseconds +uint32_t GNSS_MOSAIC::fixRateGetMaximumMs() +{ + //TODO + return (1000); +} + //---------------------------------------- // Return the number of active/enabled messages //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/GNSS_None.h b/Firmware/RTK_Everywhere/GNSS_None.h index b2301ffe3..b80da4f66 100644 --- a/Firmware/RTK_Everywhere/GNSS_None.h +++ b/Firmware/RTK_Everywhere/GNSS_None.h @@ -182,6 +182,22 @@ class GNSS_None : public GNSS return false; } + bool fixRateIsAllowed(uint32_t fixRateMs) + { + return false; + } + + //Return min/max rate in ms + uint32_t fixRateGetMinimumMs() + { + return 0; + } + + uint32_t fixRateGetMaximumMs() + { + return 0; + } + // Return the number of active/enabled messages uint8_t getActiveMessageCount() { diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.h b/Firmware/RTK_Everywhere/GNSS_UM980.h index bf6401a0d..d96674e23 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.h +++ b/Firmware/RTK_Everywhere/GNSS_UM980.h @@ -218,6 +218,13 @@ class GNSS_UM980 : GNSS // Returns true if successfully started and false upon failure bool fixedBaseStart(); + bool fixRateIsAllowed(uint32_t fixRateMs); + + //Return min/max rate in ms + uint32_t fixRateGetMinimumMs(); + + uint32_t fixRateGetMaximumMs(); + // Return the number of active/enabled messages uint8_t getActiveMessageCount(); diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index 448036e7d..6877a3cd3 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -469,6 +469,32 @@ bool GNSS_UM980::fixedBaseStart() return (response); } +//---------------------------------------- +// Check if given GNSS fix rate is allowed +// Rates are expressed in ms between fixes. +//---------------------------------------- +const float um980MinRateHz = 0.02; // 1 / 65 = 0.015384 Hz = Found experimentally +const float um980MaxRateHz = 20.0; // 20Hz + +bool GNSS_UM980::fixRateIsAllowed(uint32_t fixRateMs) +{ + if (fixRateMs > (1000.0 / um980MinRateHz) && fixRateMs < (1000.0 / um980MaxRateHz)) + return (true); + return (false); +} + +// Return minimum in milliseconds +uint32_t GNSS_UM980::fixRateGetMinimumMs() +{ + return (1000.0 / um980MinRateHz); +} + +// Return maximum in milliseconds +uint32_t GNSS_UM980::fixRateGetMaximumMs() +{ + return (1000.0 / um980MaxRateHz); +} + //---------------------------------------- // Return the number of active/enabled messages //---------------------------------------- @@ -1865,23 +1891,9 @@ bool GNSS_UM980::setRate(double secondsBetweenSolutions) if (settings.debugGnssConfig) systemPrintln("setRate: Modifying rates"); - bool response = true; - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); - // If we successfully set rates, only then record to settings - if (response) - { - uint16_t msBetweenSolutions = secondsBetweenSolutions * 1000; - settings.measurementRateMs = msBetweenSolutions; - } - else - { - systemPrintln("Failed to set measurement and navigation rates"); - return (false); - } - return (true); } @@ -1986,25 +1998,25 @@ bool GNSS_UM980::surveyInStart() //---------------------------------------- // Check if given baud rate is allowed //---------------------------------------- -const uint32_t um980AllowedRates[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600}; -const int um980AllowedRatesCount = sizeof(um980AllowedRates) / sizeof(um980AllowedRates[0]); +const uint32_t um980AllowedBaudRates[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600}; +const int um980AllowedBaudRatesCount = sizeof(um980AllowedBaudRates) / sizeof(um980AllowedBaudRates[0]); bool GNSS_UM980::baudIsAllowed(uint32_t baudRate) { - for (int x = 0; x < um980AllowedRatesCount; x++) - if (um980AllowedRates[x] == baudRate) + for (int x = 0; x < um980AllowedBaudRatesCount; x++) + if (um980AllowedBaudRates[x] == baudRate) return (true); return (false); } uint32_t GNSS_UM980::baudGetMinimum() { - return (um980AllowedRates[0]); + return (um980AllowedBaudRates[0]); } uint32_t GNSS_UM980::baudGetMaximum() { - return (um980AllowedRates[um980AllowedRatesCount - 1]); + return (um980AllowedBaudRates[um980AllowedBaudRatesCount - 1]); } //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.h b/Firmware/RTK_Everywhere/GNSS_ZED.h index ac90b3228..53e8f9166 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.h +++ b/Firmware/RTK_Everywhere/GNSS_ZED.h @@ -467,6 +467,13 @@ class GNSS_ZED : GNSS // Returns true if successfully started and false upon failure bool fixedBaseStart(); + bool fixRateIsAllowed(uint32_t fixRateMs); + + //Return min/max rate in ms + uint32_t fixRateGetMinimumMs(); + + uint32_t fixRateGetMaximumMs(); + // Return the number of active/enabled messages uint8_t getActiveMessageCount(); diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index 23a95951d..aa0b26c3a 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -58,8 +58,8 @@ void GNSS_ZED::applyPointPerfectKeys() _zed->setVal8(UBLOX_CFG_MSGOUT_UBX_RXM_COR_I2C, 1, VAL_LAYER_ALL); // Enable UBX-RXM-COR messages on I2C - _zed->setVal8(UBLOX_CFG_NAVHPG_DGNSSMODE, - 3, VAL_LAYER_ALL); // Set the differential mode - ambiguities are fixed whenever possible + _zed->setVal8(UBLOX_CFG_NAVHPG_DGNSSMODE, 3, + VAL_LAYER_ALL); // Set the differential mode - ambiguities are fixed whenever possible bool response = _zed->setDynamicSPARTNKeys(currentKeyLengthBytes, currentKeyGPSWeek, currentKeyGPSToW, settings.pointPerfectCurrentKey, nextKeyLengthBytes, nextKeyGPSWeek, @@ -243,7 +243,8 @@ bool GNSS_ZED::beginExternalEvent() if (settings.enableExternalHardwareEventLogging && (settings.dataPortChannel == MUX_PPS_EVENTTRIGGER)) { response &= _zed->setAutoTIMTM2callbackPtr( - &eventTriggerReceived, VAL_LAYER_ALL); // Enable automatic TIM TM2 messages with callback to eventTriggerReceived + &eventTriggerReceived, + VAL_LAYER_ALL); // Enable automatic TIM TM2 messages with callback to eventTriggerReceived } else { @@ -277,7 +278,7 @@ bool GNSS_ZED::setPPS() response &= _zed->addCfgValset(UBLOX_CFG_TP_PULSE_LENGTH_DEF, 1); // Define timepulse by length (not ratio) response &= _zed->addCfgValset(UBLOX_CFG_TP_USE_LOCKED_TP1, - 1); // Use CFG-TP-PERIOD_LOCK_TP1 and CFG-TP-LEN_LOCK_TP1 as soon as GNSS time is valid + 1); // Use CFG-TP-PERIOD_LOCK_TP1 and CFG-TP-LEN_LOCK_TP1 as soon as GNSS time is valid response &= _zed->addCfgValset(UBLOX_CFG_TP_TP1_ENA, settings.enableExternalPulse); // Enable/disable timepulse response &= _zed->addCfgValset(UBLOX_CFG_TP_POL_TP1, settings.externalPulsePolarity); // 0 = falling, 1 = rising edge @@ -287,10 +288,11 @@ bool GNSS_ZED::setPPS() response &= _zed->addCfgValset(UBLOX_CFG_TP_LEN_TP1, 0); // Set the pulse length in us // When the module is _locked_ to GNSS time, make it generate 1Hz (Default is 100ms high, 900ms low) - response &= _zed->addCfgValset(UBLOX_CFG_TP_PERIOD_LOCK_TP1, - settings.externalPulseTimeBetweenPulse_us); // Set the period between pulses is us response &= - _zed->addCfgValset(UBLOX_CFG_TP_LEN_LOCK_TP1, settings.externalPulseLength_us); // Set the pulse length in us + _zed->addCfgValset(UBLOX_CFG_TP_PERIOD_LOCK_TP1, + settings.externalPulseTimeBetweenPulse_us); // Set the period between pulses is us + response &= _zed->addCfgValset(UBLOX_CFG_TP_LEN_LOCK_TP1, + settings.externalPulseLength_us); // Set the pulse length in us response &= _zed->sendCfgValset(); } @@ -540,8 +542,8 @@ bool GNSS_ZED::configure() // Configure the callbacks - response &= - _zed->setAutoPVTcallbackPtr(&storePVTdata, VAL_LAYER_ALL); // Enable automatic NAV PVT messages with callback to storePVTdata + response &= _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 @@ -921,8 +923,8 @@ void GNSS_ZED::enableGgaForNtrip() measurementFrequency = 0.2; // 0.2Hz * 5 = 1 measurement every 5 seconds if (settings.debugGnss) systemPrintf("Adjusting GGA setting to %f\r\n", measurementFrequency); - _zed->setVal8(UBLOX_CFG_MSGOUT_NMEA_ID_GGA_I2C, - measurementFrequency, VAL_LAYER_ALL); // Enable GGA over I2C. Tell the module to output GGA every second + _zed->setVal8(UBLOX_CFG_MSGOUT_NMEA_ID_GGA_I2C, measurementFrequency, + VAL_LAYER_ALL); // Enable GGA over I2C. Tell the module to output GGA every second } } @@ -951,13 +953,13 @@ void GNSS_ZED::factoryReset() if (online.gnss) { // Set the clearMask and loadMask to 0xFFFF. Set deviceMask to devBBR | devFlash - uint8_t clearAndLoadMask[] = { 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0x03 }; + uint8_t clearAndLoadMask[] = {0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0x03}; _zed->cfgCfg(clearAndLoadMask, 13); delay(2000); // Set the saveMask to 0xFFFF. Set deviceMask to devBBR | devFlash - uint8_t saveMask[] = { 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0x03 }; + uint8_t saveMask[] = {0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0x03}; _zed->cfgCfg(saveMask, 13); _zed->hardReset(); // Perform a reset leading to a cold start (zero info start-up) @@ -1070,6 +1072,32 @@ bool GNSS_ZED::fixedBaseStart() return (response); } +//---------------------------------------- +// Check if given GNSS fix rate is allowed +// Rates are expressed in ms between fixes. +//---------------------------------------- +const float f9pMinRateHz = 0.00012; // Limit of 127 (navRate) * 65000ms (measRate) = 137 minute limit. +const float f9pMaxRateHz = 20.0; // 20Hz + +bool GNSS_ZED::fixRateIsAllowed(uint32_t fixRateMs) +{ + if (fixRateMs > (1000 / f9pMinRateHz) && fixRateMs < (1000 / f9pMaxRateHz)) + return (true); + return (false); +} + +// Return minimum in milliseconds +uint32_t GNSS_ZED::fixRateGetMinimumMs() +{ + return (1000.0 / f9pMinRateHz); +} + +// Return maximum in milliseconds +uint32_t GNSS_ZED::fixRateGetMaximumMs() +{ + return (1000.0 / f9pMaxRateHz); +} + //---------------------------------------- // Return the number of active/enabled messages //---------------------------------------- @@ -2193,7 +2221,6 @@ bool GNSS_ZED::setCorrRadioExtPort(bool enable, bool force) return false; } - //---------------------------------------- // Set the elevation in degrees //---------------------------------------- @@ -2273,9 +2300,9 @@ bool GNSS_ZED::setNmeaMessageRateByName(const char *msgName, uint8_t msgRate) //---------------------------------------- // Set the rate for all messages -// The ZED has a lot more messages than just NMEA in ubxMessageRates[], but other platforms generally just have NMEA and RTCM -// There are many messages so split into batches. VALSET is limited to 64 max per batch -// Uses dummy newCfg and sendCfg values to be sure we open/close a complete set +// The ZED has a lot more messages than just NMEA in ubxMessageRates[], but other platforms generally just have NMEA and +// RTCM There are many messages so split into batches. VALSET is limited to 64 max per batch Uses dummy newCfg and +// sendCfg values to be sure we open/close a complete set //---------------------------------------- bool GNSS_ZED::setMessagesNMEA() { @@ -2334,8 +2361,8 @@ bool GNSS_ZED::setMessagesNMEA() //---------------------------------------- bool GNSS_ZED::setMessagesRTCMBase() { - //TODO - return(false); + // TODO + return (false); } //---------------------------------------- @@ -2343,8 +2370,8 @@ bool GNSS_ZED::setMessagesRTCMBase() //---------------------------------------- bool GNSS_ZED::setMessagesRTCMRover() { - //TODO - return(false); + // TODO + return (false); } //---------------------------------------- @@ -2464,8 +2491,8 @@ bool GNSS_ZED::setTalkerGNGGA() if (online.gnss) { bool success = true; - success &= - _zed->setVal8(UBLOX_CFG_NMEA_MAINTALKERID, 3, VAL_LAYER_ALL); // Return talker ID to GNGGA after NTRIP Client set to GPGGA + success &= _zed->setVal8(UBLOX_CFG_NMEA_MAINTALKERID, 3, + VAL_LAYER_ALL); // Return talker ID to GNGGA after NTRIP Client set to GPGGA success &= _zed->setNMEAGPGGAcallbackPtr(nullptr); // Remove callback return success; } @@ -2730,7 +2757,8 @@ bool GNSS_ZED::surveyInStart() bool response = true; response &= _zed->setVal8(UBLOX_CFG_TMODE_MODE, 1, VAL_LAYER_ALL); // Survey-in enable - response &= _zed->setVal32(UBLOX_CFG_TMODE_SVIN_ACC_LIMIT, settings.observationPositionAccuracy * 10000, VAL_LAYER_ALL); + response &= + _zed->setVal32(UBLOX_CFG_TMODE_SVIN_ACC_LIMIT, settings.observationPositionAccuracy * 10000, VAL_LAYER_ALL); response &= _zed->setVal32(UBLOX_CFG_TMODE_SVIN_MIN_DUR, settings.observationSeconds, VAL_LAYER_ALL); if (response == false) @@ -2820,7 +2848,8 @@ const int zedAllowedRatesCount = sizeof(zedAllowedRates) / sizeof(zedAllowedRate bool GNSS_ZED::baudIsAllowed(uint32_t baudRate) { for (int x = 0; x < zedAllowedRatesCount; x++) - if (zedAllowedRates[x] == baudRate) return (true); + if (zedAllowedRates[x] == baudRate) + return (true); return (false); } diff --git a/Firmware/RTK_Everywhere/menuBase.ino b/Firmware/RTK_Everywhere/menuBase.ino index 4956f6b3f..3d03e4f43 100644 --- a/Firmware/RTK_Everywhere/menuBase.ino +++ b/Firmware/RTK_Everywhere/menuBase.ino @@ -142,11 +142,13 @@ void menuBase() if (incoming == 1) { settings.fixedBase ^= 1; + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } else if (settings.fixedBase == true && incoming == 2) { settings.fixedBaseCoordinateType ^= 1; + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } @@ -176,6 +178,7 @@ void menuBase() if (getUserInputDouble(&fixedEcefZ) == INPUT_RESPONSE_VALID) { settings.fixedEcefZ = fixedEcefZ; + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } } @@ -219,6 +222,7 @@ void menuBase() if (getUserInputDouble(&fixedAltitude) == INPUT_RESPONSE_VALID) { settings.fixedAltitude = fixedAltitude; + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } } @@ -313,10 +317,10 @@ void menuBase() systemPrintf("Enter Caster Address for Server %d: ", serverNumber + 1); if (getUserInputString(&settings.ntripServer_CasterHost[serverNumber][0], NTRIP_SERVER_STRING_SIZE) == INPUT_RESPONSE_VALID) - { - // NTRIP Server state machine will update automatically - } + { + // NTRIP Server state machine will update automatically } + } else if (incoming == 1) { // Arbitrary 99k max port # @@ -328,9 +332,9 @@ void menuBase() if (getNewSetting(tempString, 1, 99999, &settings.ntripServer_CasterPort[serverNumber]) == INPUT_RESPONSE_VALID) - { - // NTRIP Server state machine will update automatically - } + { + // NTRIP Server state machine will update automatically + } } else if (incoming == 2) { @@ -341,9 +345,9 @@ void menuBase() if (getUserInputString(&settings.ntripServer_CasterUser[serverNumber][0], NTRIP_SERVER_STRING_SIZE) == INPUT_RESPONSE_VALID) - { - // NTRIP Server state machine will update automatically - } + { + // NTRIP Server state machine will update automatically + } } else if (incoming == 3) { @@ -354,9 +358,9 @@ void menuBase() if (getUserInputString(&settings.ntripServer_CasterUserPW[serverNumber][0], NTRIP_SERVER_STRING_SIZE) == INPUT_RESPONSE_VALID) - { - // NTRIP Server state machine will update automatically - } + { + // NTRIP Server state machine will update automatically + } } else if (incoming == 4) { @@ -367,9 +371,9 @@ void menuBase() if (getUserInputString(&settings.ntripServer_MountPoint[serverNumber][0], NTRIP_SERVER_STRING_SIZE) == INPUT_RESPONSE_VALID) - { - // NTRIP Server state machine will update automatically - } + { + // NTRIP Server state machine will update automatically + } } else if (incoming == 5) { @@ -380,9 +384,9 @@ void menuBase() if (getUserInputString(&settings.ntripServer_MountPointPW[serverNumber][0], NTRIP_SERVER_STRING_SIZE) == INPUT_RESPONSE_VALID) - { - // NTRIP Server state machine will update automatically - } + { + // NTRIP Server state machine will update automatically + } } } diff --git a/Firmware/RTK_Everywhere/menuGNSS.ino b/Firmware/RTK_Everywhere/menuGNSS.ino index 2e03e702e..0d29b9515 100644 --- a/Firmware/RTK_Everywhere/menuGNSS.ino +++ b/Firmware/RTK_Everywhere/menuGNSS.ino @@ -174,59 +174,44 @@ void menuGNSS() if ((incoming == 1) && (!present.gnss_mosaicX5)) { float rateHz = 0.0; - float minRateHz = 1.0; // Measurement rate per second - float maxRateHz = 1.0; - - if (present.gnss_zedf9p) - { - minRateHz = 0.00012; // Limit of 127 (navRate) * 65000ms (measRate) = 137 minute limit. - maxRateHz = 20; // 20Hz - } - else if (present.gnss_um980) - { - minRateHz = 0.02; // 1 / 65 = 0.015384 Hz = Found experimentally - maxRateHz = 20; // 20Hz - } - else if (present.gnss_lg290p) - { - minRateHz = 1.0; // The LG290P doesn't support slower speeds than 1Hz - maxRateHz = 20; // 20Hz - } + float minRateHz = 1000.0 / gnss->fixRateGetMinimumMs(); // Convert ms to Hz + float maxRateHz = 1000.0 / gnss->fixRateGetMaximumMs(); if (getNewSetting("Enter GNSS measurement rate in Hz", minRateHz, maxRateHz, &rateHz) == - INPUT_RESPONSE_VALID) // 20Hz limit with all constellations enabled + INPUT_RESPONSE_VALID) { - gnss->setRate(1.0 / rateHz); // Convert Hz to seconds. This will set settings.measurementRateMs, - // settings.navigationRate, and GSV message + float requestedRateMs = 1000.0 / rateHz; // Convert Hz to milliseconds. + if (gnss->fixRateIsAllowed(requestedRateMs)) + { + settings.measurementRateMs = requestedRateMs; + gnssConfigure(GNSS_CONFIG_RATE); + // This will set settings.measurementRateMs, settings.navigationRate, and GSV message + // gnss->setRate(1.0 / rateHz); //TODO remove once all platforms are accounted for. Good: UM980, + // LG290P, + } + else + systemPrintln("Error: Illegal rate for this platform"); } } else if ((incoming == 2) && (!present.gnss_mosaicX5)) { - float rate_ms = 0.0; // - float minRate = 1.0; // Seconds between fixes - float maxRate = 1.0; + float requestedRateS = 0.0; + float minRateS = gnss->fixRateGetMinimumMs() / 1000.0; // Convert ms to seconds + float maxRateS = gnss->fixRateGetMaximumMs() / 1000.0; - if (present.gnss_zedf9p) - { - minRate = 0.05; // 20Hz - maxRate = 8255.0; // Limit of 127 (navRate) * 65000ms (measRate) = 137 minute limit. - } - else if (present.gnss_um980) - { - minRate = 0.05; // 20Hz - maxRate = 65.0; // Found experimentally - } - else if (present.gnss_lg290p) + if (getNewSetting("Enter GNSS measurement rate in seconds between measurements", minRateS, maxRateS, + &requestedRateS) == INPUT_RESPONSE_VALID) { - minRate = 0.05; // 20Hz - maxRate = 1.0; // The LG290P doesn't support slower speeds than 1Hz - } - - if (getNewSetting("Enter GNSS measurement rate in seconds between measurements", minRate, maxRate, - &rate_ms) == INPUT_RESPONSE_VALID) - { - // This will set settings.measurementRateMs, settings.navigationRate, and GSV message - gnss->setRate(rate_ms); + if (gnss->fixRateIsAllowed(requestedRateS * 1000.0)) //Convert S to ms + { + settings.measurementRateMs = requestedRateS * 1000.0; + gnssConfigure(GNSS_CONFIG_RATE); + // This will set settings.measurementRateMs, settings.navigationRate, and GSV message + // gnss->setRate(1.0 / rateHz); //TODO remove once all platforms are accounted for. Good: UM980, + // LG290P, + } + else + systemPrintln("Error: Illegal rate for this platform"); } } else if (incoming == 3 && present.dynamicModel) @@ -320,12 +305,11 @@ void menuGNSS() } else if (incoming == 6 && present.minCno) { - int minCNO = 0; - // Arbitrary 90 dBHz max. mosaic-X5 is 60dBHz max. - if (getNewSetting("Enter minimum satellite signal level for navigation in dBHz", 0, - present.gnss_mosaicX5 ? 60 : 90, &minCNO) == INPUT_RESPONSE_VALID) + // mosaic-X5 is 60dBHz max. + if (getNewSetting("Enter minimum satellite signal level for navigation in dBHz", 0, 60, &settings.minCNO) == + INPUT_RESPONSE_VALID) { - gnssConfigure(GNSS_CONFIG_CN0); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_CN0); // Request receiver to use new settings } } From 1f3a3ae345c400796e92c0f181f0bc2c94f63c41 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 23 Oct 2025 15:49:58 -0600 Subject: [PATCH 35/68] Correct float to double comparison (float) min of 0.05 is 0.0500000007 (double) enteredValue of 0.05 is 0.0500000000 Previous code would block a valid entry. This change may have some unintended consequences. --- Firmware/RTK_Everywhere/support.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/RTK_Everywhere/support.ino b/Firmware/RTK_Everywhere/support.ino index c772f3eba..03369eb36 100644 --- a/Firmware/RTK_Everywhere/support.ino +++ b/Firmware/RTK_Everywhere/support.ino @@ -916,7 +916,7 @@ InputResponse getNewSetting(const char *settingPrompt, float min, float max, flo if (response == INPUT_RESPONSE_VALID) { - if (enteredValue >= min && enteredValue <= max) + if ((float)enteredValue >= min && enteredValue <= max) { *setting = (float)enteredValue; // Recorded to NVM and file at main menu exit return (INPUT_RESPONSE_VALID); From c24292065da3a12b5761d584ec1d4cf7f23f22dc Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 23 Oct 2025 16:19:40 -0600 Subject: [PATCH 36/68] Add EXT_CORRECTIONS bit to gnssConfigure() --- Firmware/RTK_Everywhere/GNSS.ino | 23 ++++++-- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 70 +++++++++++++----------- Firmware/RTK_Everywhere/GNSS_UM980.ino | 15 ++--- Firmware/RTK_Everywhere/menuCommands.ino | 8 ++- Firmware/RTK_Everywhere/menuGNSS.ino | 14 ++--- Firmware/RTK_Everywhere/menuPorts.ino | 30 +++++----- 6 files changed, 86 insertions(+), 74 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index bb432e2f3..4f6d93a1f 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -14,7 +14,7 @@ enum GNSS_CONFIG_BASE, // Fixed base or survey in, location, etc GNSS_CONFIG_BAUD_RATE_RADIO, GNSS_CONFIG_BAUD_RATE_DATA, - GNSS_CONFIG_RATE, + GNSS_CONFIG_FIX_RATE, GNSS_CONFIG_CONSTELLATION, // Turn on/off a constellation GNSS_CONFIG_ELEVATION, GNSS_CONFIG_CN0, @@ -26,9 +26,10 @@ enum GNSS_CONFIG_MESSAGE_RATE_OTHER, // Update any other messages (UBX, PQTM, etc) GNSS_CONFIG_HAS_E6, // Enable/disable HAS E6 capabilities GNSS_CONFIG_MULTIPATH, - GNSS_CONFIG_TILT, // Enable/disable any output needed for tilt compensation - GNSS_CONFIG_SAVE, // Indicates current settings be saved to GNSS receiver NVM - GNSS_CONFIG_RESET, // Indicates receiver needs resetting + GNSS_CONFIG_TILT, // Enable/disable any output needed for tilt compensation + GNSS_CONFIG_EXT_CORRECTIONS, // Enable / disable corrections protocol(s) on the Radio External port + GNSS_CONFIG_SAVE, // Indicates current settings be saved to GNSS receiver NVM + GNSS_CONFIG_RESET, // Indicates receiver needs resetting // Add new entries above here GNSS_CONFIG_MAX, @@ -53,6 +54,7 @@ static const char *gnssConfigDisplayNames[] = { "HAS_E6", "MULTIPATH", "TILT", + "EXT_CORRECTIONS", "SAVE", "RESET", }; @@ -204,11 +206,11 @@ void gnssUpdate() } } - if (gnssConfigureRequested(GNSS_CONFIG_RATE)) + if (gnssConfigureRequested(GNSS_CONFIG_FIX_RATE)) { if (gnss->setRate(settings.measurementRateMs / 1000.0) == true) { - gnssConfigureClear(GNSS_CONFIG_RATE); + gnssConfigureClear(GNSS_CONFIG_FIX_RATE); gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM } } @@ -324,6 +326,15 @@ void gnssUpdate() } } + if (gnssConfigureRequested(GNSS_CONFIG_EXT_CORRECTIONS)) + { + if (gnss->setCorrRadioExtPort(settings.enableExtCorrRadio, true) == true) // Force the setting + { + gnssConfigureClear(GNSS_CONFIG_EXT_CORRECTIONS); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } + } + // Save changes to NVM if (gnssConfigureRequested(GNSS_CONFIG_SAVE)) { diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index 883d2f1eb..cfd416e9d 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -247,7 +247,7 @@ bool GNSS_LG290P::configureRover() bool response = _lg290p->setModeRover(false); // Don't wait for save and reset // Setting mode to rover should disable any survey-in - gnssConfigure(GNSS_CONFIG_RATE); + gnssConfigure(GNSS_CONFIG_FIX_RATE); gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); gnssConfigure(GNSS_CONFIG_RESET); // Mode change requires reset @@ -270,13 +270,13 @@ bool GNSS_LG290P::configureBase() if (settings.fixedBase == true && surveyInMode == 2) { if (settings.debugGnssConfig) - systemPrintln("Skipping LG290P Fixed Base configuration"); + systemPrintln("Skipping - LG290P is already in Fixed Base configuration"); return (true); // No changes needed } if (settings.fixedBase == false && surveyInMode == 1) { if (settings.debugGnssConfig) - systemPrintln("Skipping LG290P Survey-in Base configuration"); + systemPrintln("Skipping - LG290P is already in Survey-in Base configuration"); return (true); // No changes needed } } @@ -531,6 +531,26 @@ bool GNSS_LG290P::fixedBaseStart() if (online.gnss == false) return (false); + // Read, modify, write + int currentMode = getMode(); + uint8_t surveyInMode = getSurveyInMode(); // 0 - Disabled, 1 - Survey-in mode, 2 - Fixed mode + + if (currentMode == 2) // 0 - Unknown, 1 - Rover, 2 - Base + { + if (settings.fixedBase == true && surveyInMode == 2) + { + if (settings.debugGnssConfig) + systemPrintln("Skipping - LG290P is already in Fixed Base configuration"); + return (true); // No changes needed + } + if (settings.fixedBase == false && surveyInMode == 1) + { + if (settings.debugGnssConfig) + systemPrintln("Skipping - LG290P is already in Survey-in Base configuration"); + return (true); // No changes needed + } + } + if (settings.fixedBaseCoordinateType == COORD_TYPE_ECEF) { // Waits for save and reset @@ -576,13 +596,13 @@ bool GNSS_LG290P::fixRateIsAllowed(uint32_t fixRateMs) // Return minimum in milliseconds uint32_t GNSS_LG290P::fixRateGetMinimumMs() { - return (1000.0 / lgAllowedFixRatesHz[0]); + return (1000.0 / lgAllowedFixRatesHz[lgAllowedFixRatesCount - 1]); // The max Hz value is the min ms value } // Return maximum in milliseconds uint32_t GNSS_LG290P::fixRateGetMaximumMs() { - return (1000.0 / lgAllowedFixRatesHz[lgAllowedFixRatesCount - 1]); + return (1000.0 / lgAllowedFixRatesHz[0]); } //---------------------------------------- @@ -1450,22 +1470,20 @@ void GNSS_LG290P::menuMessages() // MSM7 is set during setMessagesRTCMRover() // Override settings for PPP logging - setElevation(15); - setMinCno(30); + settings.minElev = 15; // Degrees + gnssConfigure(GNSS_CONFIG_ELEVATION); + settings.minCNO = 30; // dBHz + gnssConfigure(GNSS_CONFIG_CN0); + settings.measurementRateMs = 1000; // Go to 1 Hz + gnssConfigure(GNSS_CONFIG_FIX_RATE); - setRate(1); // Go to 1 Hz + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings if (incoming == 12) - { systemPrintln("Reset to High-rate PPP Logging Defaults (NMEAx7 / RTCMx4 - 1Hz)"); - } else - { systemPrintln("Reset to PPP Logging Defaults (NMEAx7 / RTCMx4 - 30 second decimation)"); - } - - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings } else if ((incoming == 13) && (namedSettingAvailableOnPlatform("useMSM7"))) // Redundant - but good practice for code reuse) @@ -1820,6 +1838,8 @@ bool GNSS_LG290P::setCorrRadioExtPort(bool enable, bool force) { if (online.gnss) { + // Someday, read/modify/write setPortInputProtocols + if (force || (enable != _corrRadioExtPortEnabled)) { // Set UART3 InputProt: RTCM3 (4) vs NMEA (1) @@ -2023,11 +2043,7 @@ bool GNSS_LG290P::setMessagesNMEA() } } - if (response == true) - { - // For messages to take effect we must save/reset - gnssConfigure(GNSS_CONFIG_RESET); - } + // Messages take effect immediately. Save/Reset is not needed. return (response); } @@ -2114,11 +2130,7 @@ bool GNSS_LG290P::setMessagesRTCMBase() _lg290p->sendOkCommand(cfgRtcm); // Enable MSM4/7, output regular intervals, interval (seconds) } - if (response == true) - { - // For messages to take effect we must save/reset - gnssConfigure(GNSS_CONFIG_RESET); - } + // Messages take effect immediately. Save/Reset is not needed. return (response); } @@ -2284,11 +2296,7 @@ bool GNSS_LG290P::setMessagesRTCMRover() _lg290p->sendOkCommand(msmCommand); } - if (response == true) - { - // For messages to take effect we must save/reset - gnssConfigure(GNSS_CONFIG_RESET); - } + // Messages take effect immediately. Save/Reset is not needed. return (response); } @@ -2411,7 +2419,7 @@ bool GNSS_LG290P::setTilt() { systemPrintln("Increasing GNSS measurement rate to 5Hz for tilt support"); settings.measurementRateMs = 200; - gnssConfigure(GNSS_CONFIG_RATE); + gnssConfigure(GNSS_CONFIG_FIX_RATE); } // On the LG290P Flex module, UART 3 of the GNSS is connected to the IMU UART 1 diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index 6877a3cd3..96b5b372a 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -474,7 +474,7 @@ bool GNSS_UM980::fixedBaseStart() // Rates are expressed in ms between fixes. //---------------------------------------- const float um980MinRateHz = 0.02; // 1 / 65 = 0.015384 Hz = Found experimentally -const float um980MaxRateHz = 20.0; // 20Hz +const float um980MaxRateHz = 20.0; // 20Hz bool GNSS_UM980::fixRateIsAllowed(uint32_t fixRateMs) { @@ -483,13 +483,13 @@ bool GNSS_UM980::fixRateIsAllowed(uint32_t fixRateMs) return (false); } -// Return minimum in milliseconds +// Return minimum in milliseconds uint32_t GNSS_UM980::fixRateGetMinimumMs() { return (1000.0 / um980MinRateHz); } -// Return maximum in milliseconds +// Return maximum in milliseconds uint32_t GNSS_UM980::fixRateGetMaximumMs() { return (1000.0 / um980MaxRateHz); @@ -1089,10 +1089,12 @@ void GNSS_UM980::menuConstellations() incoming--; // Align choice to constellation array of 0 to 5 settings.um980Constellations[incoming] ^= 1; + gnssConfigure(GNSS_CONFIG_CONSTELLATION); // Request receiver to use new settings } else if ((incoming == MAX_UM980_CONSTELLATIONS + 1) && present.galileoHasCapable) { settings.enableGalileoHas ^= 1; + gnssConfigure(GNSS_CONFIG_HAS_E6); // Request receiver to use new settings } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) break; @@ -1102,9 +1104,6 @@ void GNSS_UM980::menuConstellations() printUnknown(incoming); } - // Apply current settings to module - gnss->setConstellations(); - clearBuffer(); // Empty buffer of any newline chars } @@ -1192,13 +1191,9 @@ void GNSS_UM980::menuMessages() // setRtcmRoverMessageRateByName("RTCM1124", reportRate); //BeiDou not used by CSRS-PPP if (incoming == 12) - { systemPrintln("Reset to High-rate PPP Logging (NMEAx5 / RTCMx4 - 1Hz)"); - } else - { systemPrintln("Reset to PPP Logging (NMEAx5 / RTCMx4 - 30 second decimation)"); - } gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings if (inBaseMode()) diff --git a/Firmware/RTK_Everywhere/menuCommands.ino b/Firmware/RTK_Everywhere/menuCommands.ino index 87ca25b72..72d6845ab 100644 --- a/Firmware/RTK_Everywhere/menuCommands.ino +++ b/Firmware/RTK_Everywhere/menuCommands.ino @@ -1327,7 +1327,8 @@ SettingValueResponse updateSettingWithValue(bool inCommands, const char *setting else if (strcmp(settingName, "measurementRateHz") == 0) { - gnss->setRate(1.0 / settingValue); + settings.measurementRateMs = 1000 / settingValue; // Convert Hz to ms + gnssConfigure(GNSS_CONFIG_FIX_RATE); // Request receiver to use new settings // This is one of the first settings to be received. If seen, remove the station files. removeFile(stationCoordinateECEFFileName); @@ -1359,8 +1360,9 @@ SettingValueResponse updateSettingWithValue(bool inCommands, const char *setting } else if (strcmp(settingName, "minCNO") == 0) { - // Note: this sends the Min CNO to the GNSS, as well as saving it in settings... - gnss->setMinCno(settingValue); + settings.minCNO = settingValue; + gnssConfigure(GNSS_CONFIG_CN0); // Request receiver to use new settings + knownSetting = true; } else if (strcmp(settingName, "fixedHAEAPC") == 0) diff --git a/Firmware/RTK_Everywhere/menuGNSS.ino b/Firmware/RTK_Everywhere/menuGNSS.ino index 0d29b9515..ffa0c318f 100644 --- a/Firmware/RTK_Everywhere/menuGNSS.ino +++ b/Firmware/RTK_Everywhere/menuGNSS.ino @@ -174,8 +174,8 @@ void menuGNSS() if ((incoming == 1) && (!present.gnss_mosaicX5)) { float rateHz = 0.0; - float minRateHz = 1000.0 / gnss->fixRateGetMinimumMs(); // Convert ms to Hz - float maxRateHz = 1000.0 / gnss->fixRateGetMaximumMs(); + float minRateHz = 1000.0 / gnss->fixRateGetMaximumMs(); // Convert ms to Hz + float maxRateHz = 1000.0 / gnss->fixRateGetMinimumMs(); //The minimum in milliseconds is the max in Hz if (getNewSetting("Enter GNSS measurement rate in Hz", minRateHz, maxRateHz, &rateHz) == INPUT_RESPONSE_VALID) @@ -184,7 +184,7 @@ void menuGNSS() if (gnss->fixRateIsAllowed(requestedRateMs)) { settings.measurementRateMs = requestedRateMs; - gnssConfigure(GNSS_CONFIG_RATE); + gnssConfigure(GNSS_CONFIG_FIX_RATE); // This will set settings.measurementRateMs, settings.navigationRate, and GSV message // gnss->setRate(1.0 / rateHz); //TODO remove once all platforms are accounted for. Good: UM980, // LG290P, @@ -205,7 +205,7 @@ void menuGNSS() if (gnss->fixRateIsAllowed(requestedRateS * 1000.0)) //Convert S to ms { settings.measurementRateMs = requestedRateS * 1000.0; - gnssConfigure(GNSS_CONFIG_RATE); + gnssConfigure(GNSS_CONFIG_FIX_RATE); // This will set settings.measurementRateMs, settings.navigationRate, and GSV message // gnss->setRate(1.0 / rateHz); //TODO remove once all platforms are accounted for. Good: UM980, // LG290P, @@ -260,7 +260,7 @@ void menuGNSS() else settings.dynamicModel = dynamicModel; // Recorded to NVM and file at main menu exit - gnss->setModel(settings.dynamicModel); + gnssConfigure(GNSS_CONFIG_MODEL); // Request receiver to use new settings } #endif // COMPILE_ZED } @@ -273,7 +273,7 @@ void menuGNSS() dynamicModel -= 1; // Align to 0 to 2 settings.dynamicModel = dynamicModel; // Recorded to NVM and file at main menu exit - gnss->setModel(settings.dynamicModel); + gnssConfigure(GNSS_CONFIG_MODEL); // Request receiver to use new settings } } else if (present.gnss_mosaicX5) @@ -285,7 +285,7 @@ void menuGNSS() dynamicModel -= 1; // Align to 0 to MAX_MOSAIC_RX_DYNAMICS - 1 settings.dynamicModel = dynamicModel; // Recorded to NVM and file at main menu exit - gnss->setModel(settings.dynamicModel); + gnssConfigure(GNSS_CONFIG_MODEL); // Request receiver to use new settings } } } diff --git a/Firmware/RTK_Everywhere/menuPorts.ino b/Firmware/RTK_Everywhere/menuPorts.ino index 96c917e2f..a44a5bbdb 100644 --- a/Firmware/RTK_Everywhere/menuPorts.ino +++ b/Firmware/RTK_Everywhere/menuPorts.ino @@ -57,11 +57,11 @@ void menuPortsNoMux() systemPrintln("Menu: Ports"); systemPrint("1) Set serial baud rate for Radio Port: "); - systemPrint(gnss->getRadioBaudRate()); + systemPrint(settings.radioPortBaud); systemPrintln(" bps"); systemPrint("2) Set serial baud rate for Data Port: "); - systemPrint(gnss->getDataBaudRate()); + systemPrint(settings.dataPortBaud); systemPrintln(" bps"); systemPrintf("3) Output GNSS data to USB serial: %s\r\n", @@ -97,8 +97,7 @@ void menuPortsNoMux() if (gnss->baudIsAllowed(newBaud)) { settings.radioPortBaud = newBaud; - if (online.gnss == true) - gnss->setBaudRateRadio(newBaud); + gnssConfigure(GNSS_CONFIG_BAUD_RATE_RADIO); // Request receiver to use new settings } else { @@ -115,6 +114,7 @@ void menuPortsNoMux() if (gnss->baudIsAllowed(newBaud)) { settings.dataPortBaud = newBaud; + gnssConfigure(GNSS_CONFIG_BAUD_RATE_DATA); // Request receiver to use new settings } else { @@ -132,7 +132,7 @@ void menuPortsNoMux() { // Toggle the enable for the external corrections radio settings.enableExtCorrRadio ^= 1; - gnss->setCorrRadioExtPort(settings.enableExtCorrRadio, true); // Force the setting + gnssConfigure(GNSS_CONFIG_EXT_CORRECTIONS); // Request receiver to use new settings } else if ((incoming == 5) && (present.gnss_zedf9p)) { @@ -153,9 +153,6 @@ void menuPortsNoMux() printUnknown(incoming); } - gnssConfigure(GNSS_CONFIG_BAUD_RATE_RADIO); // Request receiver to use new settings - gnssConfigure(GNSS_CONFIG_BAUD_RATE_DATA); // Request receiver to use new settings - clearBuffer(); // Empty buffer of any newline chars } @@ -168,7 +165,7 @@ void menuPortsMultiplexed() systemPrintln("Menu: Ports"); systemPrint("1) Set Radio port serial baud rate: "); - systemPrint(gnss->getRadioBaudRate()); + systemPrint(settings.radioPortBaud); systemPrintln(" bps"); systemPrint("2) Set Data port connections: "); @@ -184,7 +181,7 @@ void menuPortsMultiplexed() if (settings.dataPortChannel == MUX_GNSS_UART) { systemPrint("3) Set Data port serial baud rate: "); - systemPrint(gnss->getDataBaudRate()); + systemPrint(settings.dataPortBaud); systemPrintln(" bps"); } else if (settings.dataPortChannel == MUX_PPS_EVENTTRIGGER) @@ -225,8 +222,7 @@ void menuPortsMultiplexed() if (gnss->baudIsAllowed(newBaud)) { settings.radioPortBaud = newBaud; - if (online.gnss == true) - gnss->setBaudRateRadio(newBaud); + gnssConfigure(GNSS_CONFIG_BAUD_RATE_RADIO); // Request receiver to use new settings } else { @@ -251,6 +247,9 @@ void menuPortsMultiplexed() { settings.dataPortChannel = (muxConnectionType_e)(muxPort - 1); // Adjust user input from 1-4 to 0-3 setMuxport(settings.dataPortChannel); + + if (muxPort == 2) + gnssConfigure(GNSS_CONFIG_PPS); // Request receiver to use new settings } } else if (incoming == 3 && settings.dataPortChannel == MUX_GNSS_UART) @@ -262,6 +261,7 @@ void menuPortsMultiplexed() if (gnss->baudIsAllowed(newBaud)) { settings.dataPortBaud = newBaud; + gnssConfigure(GNSS_CONFIG_BAUD_RATE_DATA); // Request receiver to use new settings } else { @@ -277,7 +277,7 @@ void menuPortsMultiplexed() { // Toggle the enable for the external corrections radio settings.enableExtCorrRadio ^= 1; - gnss->setCorrRadioExtPort(settings.enableExtCorrRadio, true); // Force the setting + gnssConfigure(GNSS_CONFIG_EXT_CORRECTIONS); // Request receiver to use new settings } else if ((incoming == 5) && (present.gnss_zedf9p)) { @@ -305,10 +305,6 @@ void menuPortsMultiplexed() clearBuffer(); // Empty buffer of any newline chars gnss->beginExternalEvent(); // Update with new settings - - gnssConfigure(GNSS_CONFIG_PPS); // Request receiver to use new settings - gnssConfigure(GNSS_CONFIG_BAUD_RATE_RADIO); // Request receiver to use new settings - gnssConfigure(GNSS_CONFIG_BAUD_RATE_DATA); // Request receiver to use new settings } // Configure the behavior of the PPS and INT pins. From 8b11a2d5fc47d813a04799b4131b5219e843e149 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 23 Oct 2025 16:24:11 -0600 Subject: [PATCH 37/68] Remove redundant setHighAccuracyService() --- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index cfd416e9d..615ba4633 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -1370,8 +1370,6 @@ void GNSS_LG290P::menuConstellations() printUnknown(incoming); } - setHighAccuracyService(settings.enableGalileoHas); - clearBuffer(); // Empty buffer of any newline chars } @@ -1890,11 +1888,16 @@ bool GNSS_LG290P::setHighAccuracyService(bool enableGalileoHas) // E6 reception requires version v06 with 'PPP_TEMP' in firmware title // Present is set during LG290P begin() if (present.galileoHasCapable == false) - return (result); // We are unable to set this setting so report success + return (true); // We are unable to set this setting so report success + + // TODO - We should read/modify/write on PQTMCFGPPP // Enable E6 and PPP if enabled if (enableGalileoHas) { + // $PQTMCFGPPP,R*68 + // $PQTMCFGPPP,OK,00,2,120,0.10,0.15*0A + // $PQTMCFGPPP,W,2,1,120,0.10,0.15*68 // Enable E6 HAS, WGS84, 120 timeout, 0.10m Horizontal convergence accuracy threshold, 0.15m Vertical threshold if (_lg290p->sendOkCommand("$PQTMCFGPPP", ",W,2,1,120,0.10,0.15") == true) From c1352869b2c269eb5a8d2c3f1bbc3d87c5f16b50 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Mon, 27 Oct 2025 11:47:55 -0600 Subject: [PATCH 38/68] Remove old testGNSS and RTCM tests This was old code from ZED specific RTK Express units. No longer applicable. --- Firmware/RTK_Everywhere/Display.ino | 29 --------------- Firmware/RTK_Everywhere/GNSS.h | 6 ---- Firmware/RTK_Everywhere/GNSS_LG290P.h | 6 ---- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 11 ------ Firmware/RTK_Everywhere/GNSS_Mosaic.h | 6 ---- Firmware/RTK_Everywhere/GNSS_Mosaic.ino | 33 ----------------- Firmware/RTK_Everywhere/GNSS_None.h | 9 ----- Firmware/RTK_Everywhere/GNSS_UM980.h | 6 ---- Firmware/RTK_Everywhere/GNSS_UM980.ino | 11 ------ Firmware/RTK_Everywhere/GNSS_ZED.h | 6 ---- Firmware/RTK_Everywhere/GNSS_ZED.ino | 17 --------- Firmware/RTK_Everywhere/States.ino | 5 --- .../System_Check/System_Check.ino | 1 - .../Test Sketches/System_Check/menuSystem.ino | 36 ------------------- 14 files changed, 182 deletions(-) diff --git a/Firmware/RTK_Everywhere/Display.ino b/Firmware/RTK_Everywhere/Display.ino index aa4cb2f1b..f2d932ec2 100644 --- a/Firmware/RTK_Everywhere/Display.ino +++ b/Firmware/RTK_Everywhere/Display.ino @@ -2606,35 +2606,6 @@ void paintSystemTest() oled->print(macAddress); oled->print(":"); - // Verify the ESP UART can communicate TX/RX to ZED UART1 - if (zedUartPassed == false) - { - systemPrintln("GNSS test"); - - setMuxport(MUX_GNSS_UART); // Set mux to UART so we can debug over data port - delay(20); - - // Clear out buffer before starting - while (serialGNSS->available()) - serialGNSS->read(); - serialGNSS->flush(); - -#ifdef COMPILE_ZED - SFE_UBLOX_GNSS_SERIAL myGNSS; - - // begin() attempts 3 connections - if (myGNSS.begin(*serialGNSS) == true) - { - - zedUartPassed = true; - oled->print("OK"); - } - else - oled->print("FAIL"); -#endif // COMPILE_ZED - } - else - oled->print("OK"); } // End display 1 if (systemTestDisplayNumber == 0) diff --git a/Firmware/RTK_Everywhere/GNSS.h b/Firmware/RTK_Everywhere/GNSS.h index 37be83eca..a3fbb49a0 100644 --- a/Firmware/RTK_Everywhere/GNSS.h +++ b/Firmware/RTK_Everywhere/GNSS.h @@ -113,12 +113,6 @@ class GNSS virtual void enableGgaForNtrip(); - // Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted - // even if there is no GPS fix. We use it to test serial output. - // Outputs: - // Returns true if successfully started and false upon failure - virtual bool enableRTCMTest(); - // Restore the GNSS to the factory settings virtual void factoryReset(); diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.h b/Firmware/RTK_Everywhere/GNSS_LG290P.h index db757872b..89cdc7e3b 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.h +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.h @@ -180,12 +180,6 @@ class GNSS_LG290P : GNSS void enableGgaForNtrip(); - // Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted - // even if there is no GPS fix. We use it to test serial output. - // Outputs: - // Returns true if successfully started and false upon failure - bool enableRTCMTest(); - bool enterConfigMode(unsigned long waitForSemaphoreTimeout_millis); bool exitConfigMode(); diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index 615ba4633..2ac4e9f42 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -471,17 +471,6 @@ void GNSS_LG290P::enableGgaForNtrip() // TODO lg290pEnableGgaForNtrip(); } -//---------------------------------------- -// Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted -// even if there is no GPS fix. We use it to test serial output. -// Returns true if successfully started and false upon failure -//---------------------------------------- -bool GNSS_LG290P::enableRTCMTest() -{ - // RTCM-1230 not supported on the LG290P - return false; -} - //---------------------------------------- // Restore the GNSS to the factory settings //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.h b/Firmware/RTK_Everywhere/GNSS_Mosaic.h index f25883b5a..b701b6e5f 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.h +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.h @@ -648,12 +648,6 @@ class GNSS_MOSAIC : GNSS void enableGgaForNtrip(); - // Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted - // even if there is no GPS fix. We use it to test serial output. - // Outputs: - // Returns true if successfully started and false upon failure - bool enableRTCMTest(); - // Restore the GNSS to the factory settings void factoryReset(); diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino index 5b0142a8b..61ffd0207 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino @@ -813,39 +813,6 @@ void GNSS_MOSAIC::enableGgaForNtrip() sendWithResponse("snti,GP\n\r", "NMEATalkerID"); } -//---------------------------------------- -// Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted -// even if there is no GPS fix. We use it to test serial output. -// Outputs: -// Returns true if successfully started and false upon failure -//---------------------------------------- -bool GNSS_MOSAIC::enableRTCMTest() -{ - // Enable RTCM1230 on COM2 (Radio connector) - // Called by STATE_TEST. Mosaic could still be starting up, so allow many retries - - int retries = 0; - const int retryLimit = 20; - - // Add RTCMv3 output on COM2 - while (!sendWithResponse("sdio,COM2,,+RTCMv3\n\r", "DataInOut")) - { - if (retries == retryLimit) - break; - retries++; - sendWithResponse("SSSSSSSSSSSSSSSSSSSS\n\r", "COM"); // Send escape sequence - } - - if (retries == retryLimit) - return false; - - bool success = true; - success &= sendWithResponse("sr3i,RTCM1230,1.0\n\r", "RTCMv3Interval"); // Set message interval to 1s - success &= sendWithResponse("sr3o,COM2,+RTCM1230\n\r", "RTCMv3Output"); // Add RTCMv3 1230 output - - return success; -} - //---------------------------------------- // Restore the GNSS to the factory settings //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/GNSS_None.h b/Firmware/RTK_Everywhere/GNSS_None.h index b80da4f66..1727b4fd5 100644 --- a/Firmware/RTK_Everywhere/GNSS_None.h +++ b/Firmware/RTK_Everywhere/GNSS_None.h @@ -150,15 +150,6 @@ class GNSS_None : public GNSS { } - // Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted - // even if there is no GPS fix. We use it to test serial output. - // Outputs: - // Returns true if successfully started and false upon failure - bool enableRTCMTest() - { - return false; - } - // Restore the GNSS to the factory settings void factoryReset() { diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.h b/Firmware/RTK_Everywhere/GNSS_UM980.h index d96674e23..327a4460d 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.h +++ b/Firmware/RTK_Everywhere/GNSS_UM980.h @@ -200,12 +200,6 @@ class GNSS_UM980 : GNSS void enableGgaForNtrip(); - // Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted - // even if there is no GPS fix. We use it to test serial output. - // Outputs: - // Returns true if successfully started and false upon failure - bool enableRTCMTest(); - // Restore the GNSS to the factory settings void factoryReset(); diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index 96b5b372a..989561a62 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -396,17 +396,6 @@ void GNSS_UM980::enableGgaForNtrip() // TODO um980EnableGgaForNtrip(); } -//---------------------------------------- -// Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted -// even if there is no GPS fix. We use it to test serial output. -// Returns true if successfully started and false upon failure -//---------------------------------------- -bool GNSS_UM980::enableRTCMTest() -{ - // There is no data port on devices with the UM980 - return false; -} - //---------------------------------------- // Restore the GNSS to the factory settings //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.h b/Firmware/RTK_Everywhere/GNSS_ZED.h index 53e8f9166..744c08f43 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.h +++ b/Firmware/RTK_Everywhere/GNSS_ZED.h @@ -449,12 +449,6 @@ class GNSS_ZED : GNSS void enableGgaForNtrip(); - // Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted - // even if there is no GPS fix. We use it to test serial output. - // Outputs: - // Returns true if successfully started and false upon failure - bool enableRTCMTest(); - // Restore the GNSS to the factory settings void factoryReset(); diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index aa0b26c3a..ebd79bd50 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -928,23 +928,6 @@ void GNSS_ZED::enableGgaForNtrip() } } -//---------------------------------------- -// Enable RTCM 1230. This is the GLONASS bias sentence and is transmitted -// even if there is no GPS fix. We use it to test serial output. -// Returns true if successfully started and false upon failure -//---------------------------------------- -bool GNSS_ZED::enableRTCMTest() -{ - if (online.gnss) - { - _zed->newCfgValset(VAL_LAYER_RAM); // Create a new Configuration Item VALSET message - _zed->addCfgValset(UBLOX_CFG_MSGOUT_RTCM_3X_TYPE1230_UART2, 1); // Enable message 1230 every second - _zed->sendCfgValset(); // Send the VALSET - return true; - } - return false; -} - //---------------------------------------- // Restore the GNSS to the factory settings //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/States.ino b/Firmware/RTK_Everywhere/States.ino index 49a37456c..3a4de8f30 100644 --- a/Firmware/RTK_Everywhere/States.ino +++ b/Firmware/RTK_Everywhere/States.ino @@ -508,11 +508,6 @@ void stateUpdate() // Debounce entry into test menu if ((millis() - lastTestMenuChange) > 500) { - tasksStopGnssUart(); // Stop absoring GNSS serial via task - zedUartPassed = false; - - gnss->enableRTCMTest(); - RTK_MODE(RTK_MODE_TESTING); changeState(STATE_TESTING); } diff --git a/Firmware/Test Sketches/System_Check/System_Check.ino b/Firmware/Test Sketches/System_Check/System_Check.ino index 8d7cbd6f9..737e6164b 100644 --- a/Firmware/Test Sketches/System_Check/System_Check.ino +++ b/Firmware/Test Sketches/System_Check/System_Check.ino @@ -233,7 +233,6 @@ uint8_t ethernetMACAddress[6]; // Display this address when Ethernet is enabled, #define platformPrefix platformPrefixTable[productVariant] // Sets the prefix for broadcast names -bool zedUartPassed = false; //Goes true during testing if ESP can communicate with ZED over UART //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- void setup() diff --git a/Firmware/Test Sketches/System_Check/menuSystem.ino b/Firmware/Test Sketches/System_Check/menuSystem.ino index 4ca21dfff..77ec6bd61 100644 --- a/Firmware/Test Sketches/System_Check/menuSystem.ino +++ b/Firmware/Test Sketches/System_Check/menuSystem.ino @@ -236,39 +236,3 @@ void printCurrentConditions() } } -void testGNSS() -{ - //The following ZED test blocks the usage of UART1 for bootloading. - //Verify the ESP UART2 can communicate TX/RX to ZED UART1 - if (online.gnss == true) - { - if (zedUartPassed == false) - { - //stopUART2Tasks(); //Stop absoring ZED serial via task - - theGNSS.setSerialRate(460800, COM_PORT_UART1); //Defaults to 460800 to maximize message output support - serialGNSS.begin(460800); //UART2 on pins 16/17 for SPP. The ZED-F9P will be configured to output NMEA over its UART1 at the same rate. - - SFE_UBLOX_GNSS myGNSS; - if (myGNSS.begin(serialGNSS) == true) //begin() attempts 3 connections - { - zedUartPassed = true; - Serial.print(F("Online")); - } - else - Serial.print(F("Offline")); - - theGNSS.setSerialRate(settings.dataPortBaud, COM_PORT_UART1); //Defaults to 460800 to maximize message output support - serialGNSS.begin(settings.dataPortBaud); //UART2 on pins 16/17 for SPP. The ZED-F9P will be configured to output NMEA over its UART1 at the same rate. - - //startUART2Tasks(); //Return to normal operation - } - else - Serial.print(F("Online")); - } - else - { - Serial.print("Can't check (GNSS offline)"); - } - Serial.println(); -} From 10728b679be6b4dae8913bcd8c476c629dfed1a7 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Mon, 27 Oct 2025 11:50:07 -0600 Subject: [PATCH 39/68] Consolidate the places where setLoggingType() is needed --- Firmware/RTK_Everywhere/GNSS.ino | 14 +++++++++++++- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 2 -- Firmware/RTK_Everywhere/GNSS_Mosaic.ino | 8 -------- Firmware/RTK_Everywhere/RTK_Everywhere.ino | 1 - Firmware/RTK_Everywhere/menuCommands.ino | 1 - Firmware/RTK_Everywhere/menuMessages.ino | 1 - 6 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index 4f6d93a1f..83c3fdec4 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -114,8 +114,16 @@ void gnssUpdate() // Allow the GNSS platform to update itself gnss->update(); - if (settings.gnssConfigureRequest == 0) + if (gnssConfigureComplete() == true) + { + // We need to establish the logging type: + // After a device has completed boot up (the GNSS may or may not have been reconfigured) + // After a user changes the message configurations (NMEA, RTCM, or OTHER). + if (loggingType == LOGGING_UNKNOWN) + setLoggingType(); // Update Standard, PPP, or custom for icon selection + return; // No configuration requests + } // Handle any requested configuration changes // Only update the GNSS receiver once the CLI, serial menu, and Web Config interfaces are disconnected @@ -275,6 +283,7 @@ void gnssUpdate() { gnssConfigureClear(GNSS_CONFIG_MESSAGE_RATE_NMEA); gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + setLoggingType(); // Update Standard, PPP, or custom for icon selection } } @@ -290,6 +299,7 @@ void gnssUpdate() { gnssConfigureClear(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + setLoggingType(); // Update Standard, PPP, or custom for icon selection } } } @@ -306,6 +316,7 @@ void gnssUpdate() { gnssConfigureClear(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + setLoggingType(); // Update Standard, PPP, or custom for icon selection } } } @@ -315,6 +326,7 @@ void gnssUpdate() // TODO - It is not clear where LG290P PQTM messages are being enabled gnssConfigureClear(GNSS_CONFIG_MESSAGE_RATE_OTHER); gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + setLoggingType(); // Update Standard, PPP, or custom for icon selection } if (gnssConfigureRequested(GNSS_CONFIG_TILT)) diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index 2ac4e9f42..ef97ba1fc 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -1488,8 +1488,6 @@ void GNSS_LG290P::menuMessages() } clearBuffer(); // Empty buffer of any newline chars - - setLoggingType(); // Determine if we are standard, PPP, or custom. Changes logging icon accordingly. } //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino index 61ffd0207..50f41d7cd 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino @@ -154,7 +154,6 @@ void menuLogMosaic() mosaic->configureLogging(); // This will enable / disable RINEX logging mosaic->setMessagesNMEA(); // Enable NMEA messages - this will enable/disable the DSK1 streams mosaic->saveConfiguration(); // Save the configuration - setLoggingType(); // Update Standard, PPP, or custom for icon selection } clearBuffer(); // Empty buffer of any newline chars @@ -461,7 +460,6 @@ bool GNSS_MOSAIC::configureBase() if (settings.gnssConfiguredBase) { systemPrintln("Skipping mosaic Base configuration"); - setLoggingType(); // Needed because logUpdate exits early and never calls setLoggingType return true; } @@ -481,8 +479,6 @@ bool GNSS_MOSAIC::configureBase() response &= configureLogging(); - setLoggingType(); // Update Standard, PPP, or custom for icon selection - // Save the current configuration into non-volatile memory (NVM) response &= saveConfiguration(); @@ -706,7 +702,6 @@ bool GNSS_MOSAIC::configureRover() if (settings.gnssConfiguredRover) { systemPrintln("Skipping mosaic Rover configuration"); - setLoggingType(); // Needed because logUpdate exits early and never calls setLoggingType return (true); } @@ -728,8 +723,6 @@ bool GNSS_MOSAIC::configureRover() response &= configureLogging(); - setLoggingType(); // Update Standard, PPP, or custom for icon selection - // Save the current configuration into non-volatile memory (NVM) response &= saveConfiguration(); @@ -1737,7 +1730,6 @@ void GNSS_MOSAIC::menuMessages() clearBuffer(); // Empty buffer of any newline chars - setLoggingType(); // Update Standard, PPP, or custom for icon selection } //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/RTK_Everywhere.ino b/Firmware/RTK_Everywhere/RTK_Everywhere.ino index 136f7bb1d..f4ee7599c 100644 --- a/Firmware/RTK_Everywhere/RTK_Everywhere.ino +++ b/Firmware/RTK_Everywhere/RTK_Everywhere.ino @@ -616,7 +616,6 @@ volatile static int combinedSpaceRemaining; // Overrun indicator volatile static uint64_t logFileSize; // Updated with each write int bufferOverruns; // Running count of possible data losses since power-on -bool zedUartPassed; // Goes true during testing if ESP can communicate with ZED over UART const uint8_t btEscapeCharacter = '+'; const uint8_t btMaxEscapeCharacters = 3; // Number of characters needed to enter remote command mode over Bluetooth diff --git a/Firmware/RTK_Everywhere/menuCommands.ino b/Firmware/RTK_Everywhere/menuCommands.ino index 72d6845ab..4006cc185 100644 --- a/Firmware/RTK_Everywhere/menuCommands.ino +++ b/Firmware/RTK_Everywhere/menuCommands.ino @@ -1508,7 +1508,6 @@ SettingValueResponse updateSettingWithValue(bool inCommands, const char *setting { endLogging(false, true); //(gotSemaphore, releaseSemaphore) Close file. Reset parser stats. beginLogging(); // Create new file based on current RTC. - setLoggingType(); // Determine if we are standard, PPP, or custom. Changes logging icon accordingly. char newFileNameCSV[sizeof("logFileName,") + sizeof(logFileName) + 1]; snprintf(newFileNameCSV, sizeof(newFileNameCSV), "logFileName,%s,", logFileName); diff --git a/Firmware/RTK_Everywhere/menuMessages.ino b/Firmware/RTK_Everywhere/menuMessages.ino index dac89bcad..ef9ce8699 100644 --- a/Firmware/RTK_Everywhere/menuMessages.ino +++ b/Firmware/RTK_Everywhere/menuMessages.ino @@ -181,7 +181,6 @@ void menuLog() { endLogging(false, true); //(gotSemaphore, releaseSemaphore) Close file. Reset parser stats. beginLogging(); // Create new file based on current RTC. - setLoggingType(); // Determine if we are standard, PPP, or custom. Changes logging icon accordingly. } else if (incoming == 5 && settings.enableLogging == true) { From b0eb48b04393c600e94b37acfcbdb2d761a3517f Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Mon, 27 Oct 2025 11:50:32 -0600 Subject: [PATCH 40/68] Make ZED aware of HPG v1.51 --- Firmware/RTK_Everywhere/GNSS_ZED.ino | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index ebd79bd50..6add58ca8 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -170,10 +170,11 @@ void GNSS_ZED::begin() //"1.30" - ZED-F9P (HPG) released Dec, 2021. Also ZED-F9R (HPS) released Sept, 2022 //"1.32" - ZED-F9P released May, 2022 //"1.50" - ZED-F9P released July, 2024 + //"1.51" - ZED-F9P released November, 2024 - const uint8_t knownFirmwareVersions[] = {100, 112, 113, 120, 121, 130, 132, 150}; + const uint8_t knownFirmwareVersions[] = {100, 112, 113, 120, 121, 130, 132, 150, 151}; bool knownFirmware = false; - for (uint8_t i = 0; i < (sizeof(knownFirmwareVersions) / sizeof(uint8_t)); i++) + for (uint8_t i = 0; i < (sizeof(knownFirmwareVersions) / sizeof(knownFirmwareVersions[0])); i++) { if (gnssFirmwareVersionInt == knownFirmwareVersions[i]) knownFirmware = true; From bcadd4dfd92a0868ffcce1b41bf1d91275a3c60b Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Mon, 27 Oct 2025 11:51:27 -0600 Subject: [PATCH 41/68] Remove setLoggingType() calls --- Firmware/RTK_Everywhere/RTK_Everywhere.ino | 3 --- 1 file changed, 3 deletions(-) diff --git a/Firmware/RTK_Everywhere/RTK_Everywhere.ino b/Firmware/RTK_Everywhere/RTK_Everywhere.ino index f4ee7599c..ad3d7d390 100644 --- a/Firmware/RTK_Everywhere/RTK_Everywhere.ino +++ b/Firmware/RTK_Everywhere/RTK_Everywhere.ino @@ -1592,8 +1592,6 @@ void logUpdate() blockLogging = true; return; } - - setLoggingType(); // Determine if we are standard, PPP, or custom. Changes logging icon accordingly. } else if (online.logging == true && settings.enableLogging == false) { @@ -1614,7 +1612,6 @@ void logUpdate() systemPrintln("Log file: log length reached"); endLogging(false, true); //(gotSemaphore, releaseSemaphore) Close file. Reset parser stats. beginLogging(); // Create new file based on current RTC. - setLoggingType(); // Determine if we are standard, PPP, or custom. Changes logging icon accordingly. } } From f9a70d3c17bce46535a2cbee288772cd16d60d32 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Mon, 27 Oct 2025 13:30:04 -0600 Subject: [PATCH 42/68] Remove enableGgaForNtrip and setTalkerGNGGA Move GGA configuration to setMessagesNMEA across all platforms. I don't believe Casters care if GNGGA or GPGGA is received. This was only ever supported on ZED and mosaic with no known reported issues resulting from the lack of support on other platforms. --- Firmware/RTK_Everywhere/GNSS.h | 4 -- Firmware/RTK_Everywhere/GNSS.ino | 11 +++-- Firmware/RTK_Everywhere/GNSS_LG290P.h | 4 -- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 61 ++++++------------------- Firmware/RTK_Everywhere/GNSS_Mosaic.h | 4 -- Firmware/RTK_Everywhere/GNSS_Mosaic.ino | 21 ++------- Firmware/RTK_Everywhere/GNSS_None.h | 9 ---- Firmware/RTK_Everywhere/GNSS_UM980.h | 4 -- Firmware/RTK_Everywhere/GNSS_UM980.ino | 48 +++++++++---------- Firmware/RTK_Everywhere/GNSS_ZED.h | 4 -- Firmware/RTK_Everywhere/GNSS_ZED.ino | 3 -- Firmware/RTK_Everywhere/NtripClient.ino | 16 +++---- 12 files changed, 54 insertions(+), 135 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.h b/Firmware/RTK_Everywhere/GNSS.h index a3fbb49a0..6e65e800d 100644 --- a/Firmware/RTK_Everywhere/GNSS.h +++ b/Firmware/RTK_Everywhere/GNSS.h @@ -111,8 +111,6 @@ class GNSS virtual void debuggingEnable(); - virtual void enableGgaForNtrip(); - // Restore the GNSS to the factory settings virtual void factoryReset(); @@ -374,8 +372,6 @@ class GNSS // failure virtual bool setRate(double secondsBetweenSolutions); - virtual bool setTalkerGNGGA(); - // Enable/disable any output needed for tilt compensation virtual bool setTilt(); diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index 83c3fdec4..67a877317 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -26,10 +26,10 @@ enum GNSS_CONFIG_MESSAGE_RATE_OTHER, // Update any other messages (UBX, PQTM, etc) GNSS_CONFIG_HAS_E6, // Enable/disable HAS E6 capabilities GNSS_CONFIG_MULTIPATH, - GNSS_CONFIG_TILT, // Enable/disable any output needed for tilt compensation + GNSS_CONFIG_TILT, // Enable/disable any output needed for tilt compensation GNSS_CONFIG_EXT_CORRECTIONS, // Enable / disable corrections protocol(s) on the Radio External port - GNSS_CONFIG_SAVE, // Indicates current settings be saved to GNSS receiver NVM - GNSS_CONFIG_RESET, // Indicates receiver needs resetting + GNSS_CONFIG_SAVE, // Indicates current settings be saved to GNSS receiver NVM + GNSS_CONFIG_RESET, // Indicates receiver needs resetting // Add new entries above here GNSS_CONFIG_MAX, @@ -107,11 +107,14 @@ bool GNSS::supportsAntennaShortOpen() void gnssUpdate() { + if (online.gnss == false) + return; + // Belt and suspender if (gnss == nullptr) return; - // Allow the GNSS platform to update itself + // Allow the GNSS platform to update itself gnss->update(); if (gnssConfigureComplete() == true) diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.h b/Firmware/RTK_Everywhere/GNSS_LG290P.h index 89cdc7e3b..004e077e0 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.h +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.h @@ -178,8 +178,6 @@ class GNSS_LG290P : GNSS bool disableSurveyIn(bool saveAndReset); - void enableGgaForNtrip(); - bool enterConfigMode(unsigned long waitForSemaphoreTimeout_millis); bool exitConfigMode(); @@ -446,8 +444,6 @@ class GNSS_LG290P : GNSS // failure bool setRate(double secondsBetweenSolutions); - bool setTalkerGNGGA(); - // Enable/disable any output needed for tilt compensation bool setTilt(); diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index ef97ba1fc..40b7f4532 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -97,7 +97,7 @@ void GNSS_LG290P::begin() systemPrintln("GNSS LG290P online"); - // Turn on/off debug messages + // Turn on debug messages if needed if (settings.debugGnss) debuggingEnable(); @@ -204,9 +204,6 @@ bool GNSS_LG290P::configure() delay(1000); // Wait for device to reboot } - if (configureOnce()) - return (true); - // If we fail, reset LG290P systemPrintln("Resetting LG290P to complete configuration"); @@ -219,16 +216,6 @@ bool GNSS_LG290P::configure() return (false); } -//---------------------------------------- -// Configure the basic LG290P settings (rover/base agnostic) -//---------------------------------------- -bool GNSS_LG290P::configureOnce() -{ - // Nothing to do once - // All config gets done either from mode switches or user modifications - return (true); -} - //---------------------------------------- // Configure specific aspects of the receiver for rover mode //---------------------------------------- @@ -465,12 +452,6 @@ void GNSS_LG290P::debuggingEnable() } } -//---------------------------------------- -void GNSS_LG290P::enableGgaForNtrip() -{ - // TODO lg290pEnableGgaForNtrip(); -} - //---------------------------------------- // Restore the GNSS to the factory settings //---------------------------------------- @@ -1964,16 +1945,11 @@ bool GNSS_LG290P::setMessagesNMEA() systemPrintf("Enable NMEA failed at messageNumber %d %s.\r\n", messageNumber, lgMessagesNMEA[messageNumber].msgTextName); - // If we are using IP based corrections, we need to send local data to the PPL - // The PPL requires being fed GPGGA/ZDA, and RTCM1019/1020/1042/1046 - if (pointPerfectServiceUsesKeys()) + // Mark messages needed for other services (NTRIP Client, PointPerfect, etc) as enabled if rate > 0 + if (settings.lg290pMessageRatesNMEA[messageNumber] > 0) { - // Mark PPL required messages as enabled if rate > 0 - if (settings.lg290pMessageRatesNMEA[messageNumber] > 0) - { - if (strcmp(lgMessagesNMEA[messageNumber].msgTextName, "GGA") == 0) - gpggaEnabled = true; - } + if (strcmp(lgMessagesNMEA[messageNumber].msgTextName, "GGA") == 0) + gpggaEnabled = true; } } } @@ -1985,20 +1961,20 @@ bool GNSS_LG290P::setMessagesNMEA() break; // Don't step through portNumbers } - if (pointPerfectServiceUsesKeys()) + // Enable GGA if needed for other services + if (gpggaEnabled == false) { // Force on any messages that are needed for PPL - // If firmware is 4 or higher, use setMessageRateOnPort, otherwise setMessageRate - if (lg290pFirmwareVersion >= 4) + // Enable GGA for NTRIP + if (pointPerfectServiceUsesKeys() || + (settings.enableNtripClient == true && settings.ntripClient_TransmitGGA == true)) { - // Enable GGA on UART 2 (connected to ESP32) only - if (gpggaEnabled == false) + // If firmware is 4 or higher, use setMessageRateOnPort, otherwise setMessageRate + if (lg290pFirmwareVersion >= 4) + // Enable GGA. On Torch, LG290P connected to ESP32 on UART 2. response &= _lg290p->setMessageRateOnPort("GGA", 1, 2); - } - else - { - // Enable GGA on all UARTs. It's the best we can do. - if (gpggaEnabled == false) + else + // Enable GGA on all UARTs. It's the best we can do. response &= _lg290p->setMessageRate("GGA", 1); } } @@ -2379,13 +2355,6 @@ bool GNSS_LG290P::setRate(double secondsBetweenSolutions) return (response); } -//---------------------------------------- -bool GNSS_LG290P::setTalkerGNGGA() -{ - // TODO lg290pSetTalkerGNGGA(); - return false; -} - //---------------------------------------- // Enable/disable any output needed for tilt compensation //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.h b/Firmware/RTK_Everywhere/GNSS_Mosaic.h index b701b6e5f..d66e79e3b 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.h +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.h @@ -646,8 +646,6 @@ class GNSS_MOSAIC : GNSS void debuggingEnable(); - void enableGgaForNtrip(); - // Restore the GNSS to the factory settings void factoryReset(); @@ -1023,8 +1021,6 @@ class GNSS_MOSAIC : GNSS // failure bool setRate(double secondsBetweenSolutions); - bool setTalkerGNGGA(); - // Enable/disable any output needed for tilt compensation bool setTilt(); diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino index 50f41d7cd..74c895fee 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino @@ -798,14 +798,6 @@ void GNSS_MOSAIC::debuggingEnable() // TODO } -//---------------------------------------- -void GNSS_MOSAIC::enableGgaForNtrip() -{ - // Set the talker ID to GP - // setMessagesNMEA() will enable GGA if needed - sendWithResponse("snti,GP\n\r", "NMEATalkerID"); -} - //---------------------------------------- // Restore the GNSS to the factory settings //---------------------------------------- @@ -885,7 +877,7 @@ bool GNSS_MOSAIC::fixedBaseStart() bool GNSS_MOSAIC::fixRateIsAllowed(uint32_t fixRateMs) { - //TODO + // TODO if (fixRateMs != 1000) return (false); return (true); @@ -894,14 +886,14 @@ bool GNSS_MOSAIC::fixRateIsAllowed(uint32_t fixRateMs) // Return minimum in milliseconds uint32_t GNSS_MOSAIC::fixRateGetMinimumMs() { - //TODO + // TODO return (1000); } // Return maximum in milliseconds uint32_t GNSS_MOSAIC::fixRateGetMaximumMs() { - //TODO + // TODO return (1000); } @@ -1729,7 +1721,6 @@ void GNSS_MOSAIC::menuMessages() } clearBuffer(); // Empty buffer of any newline chars - } //---------------------------------------- @@ -2530,12 +2521,6 @@ bool GNSS_MOSAIC::setRate(double secondsBetweenSolutions) return true; } -//---------------------------------------- -bool GNSS_MOSAIC::setTalkerGNGGA() -{ - return sendWithResponse("snti,GN\n\r", "NMEATalkerID"); -} - //---------------------------------------- // Enable/disable any output needed for tilt compensation //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/GNSS_None.h b/Firmware/RTK_Everywhere/GNSS_None.h index 1727b4fd5..166c87802 100644 --- a/Firmware/RTK_Everywhere/GNSS_None.h +++ b/Firmware/RTK_Everywhere/GNSS_None.h @@ -146,10 +146,6 @@ class GNSS_None : public GNSS { } - void enableGgaForNtrip() - { - } - // Restore the GNSS to the factory settings void factoryReset() { @@ -633,11 +629,6 @@ class GNSS_None : public GNSS return true; } - bool setTalkerGNGGA() - { - return true; - } - bool setTilt() { return true; diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.h b/Firmware/RTK_Everywhere/GNSS_UM980.h index 327a4460d..4050804f9 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.h +++ b/Firmware/RTK_Everywhere/GNSS_UM980.h @@ -198,8 +198,6 @@ class GNSS_UM980 : GNSS void debuggingEnable(); - void enableGgaForNtrip(); - // Restore the GNSS to the factory settings void factoryReset(); @@ -475,8 +473,6 @@ class GNSS_UM980 : GNSS // failure bool setRate(double secondsBetweenSolutions); - bool setTalkerGNGGA(); - // Enable/disable any output needed for tilt compensation bool setTilt(); diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index 989561a62..a215cfe2f 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -390,12 +390,6 @@ void GNSS_UM980::disableAllOutput() } } -//---------------------------------------- -void GNSS_UM980::enableGgaForNtrip() -{ - // TODO um980EnableGgaForNtrip(); -} - //---------------------------------------- // Restore the GNSS to the factory settings //---------------------------------------- @@ -1628,28 +1622,35 @@ bool GNSS_UM980::setMessagesNMEA() } } + // Mark certain required messages as enabled if rate > 0 + if (settings.um980MessageRatesNMEA[messageNumber] > 0) + { + if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "GPGGA") == 0) + gpggaEnabled = true; + else if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "GPZDA") == 0) + gpzdaEnabled = true; + } + } + + // Enable GGA if needed for other services + if (gpggaEnabled == false) + { // If we are using MQTT based corrections, we need to send local data to the PPL // The PPL requires being fed GPGGA/ZDA, and RTCM1019/1020/1042/1046 - if (pointPerfectServiceUsesKeys()) + // Enable GGA for NTRIP + if (pointPerfectServiceUsesKeys() || + (settings.enableNtripClient == true && settings.ntripClient_TransmitGGA == true)) { - // Mark PPL required messages as enabled if rate > 0 - if (settings.um980MessageRatesNMEA[messageNumber] > 0) - { - if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "GPGGA") == 0) - gpggaEnabled = true; - else if (strcmp(umMessagesNMEA[messageNumber].msgTextName, "GPZDA") == 0) - gpzdaEnabled = true; - } + response &= _um980->setNMEAPortMessage("GPGGA", "COM3", 1); } } - if (pointPerfectServiceUsesKeys()) + if (gpzdaEnabled == false) { - // Force on any messages that are needed for PPL - if (gpggaEnabled == false) - response &= _um980->setNMEAPortMessage("GPGGA", "COM3", 1); - if (gpzdaEnabled == false) + if (pointPerfectServiceUsesKeys()) + { response &= _um980->setNMEAPortMessage("GPZDA", "COM3", 1); + } } if (response == true) @@ -1881,13 +1882,6 @@ bool GNSS_UM980::setRate(double secondsBetweenSolutions) return (true); } -//---------------------------------------- -bool GNSS_UM980::setTalkerGNGGA() -{ - // TODO um980SetTalkerGNGGA(); - return false; -} - //---------------------------------------- // Enable/disable any output needed for tilt compensation //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.h b/Firmware/RTK_Everywhere/GNSS_ZED.h index 744c08f43..b3506ee72 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.h +++ b/Firmware/RTK_Everywhere/GNSS_ZED.h @@ -447,8 +447,6 @@ class GNSS_ZED : GNSS void debuggingEnable(); - void enableGgaForNtrip(); - // Restore the GNSS to the factory settings void factoryReset(); @@ -739,8 +737,6 @@ class GNSS_ZED : GNSS // failure bool setRate(double secondsBetweenSolutions); - bool setTalkerGNGGA(); - // Enable/disable any output needed for tilt compensation bool setTilt(); diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index 6add58ca8..ff69cb057 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -340,9 +340,6 @@ bool GNSS_ZED::configureBase() update(); // Regularly poll to get latest data - _zed->setNMEAGPGGAcallbackPtr( - nullptr); // Disable GPGGA call back that may have been set during Rover NTRIP Client mode - bool success = false; int tryNo = -1; diff --git a/Firmware/RTK_Everywhere/NtripClient.ino b/Firmware/RTK_Everywhere/NtripClient.ino index 1f633c1f3..34d94b423 100644 --- a/Firmware/RTK_Everywhere/NtripClient.ino +++ b/Firmware/RTK_Everywhere/NtripClient.ino @@ -228,7 +228,8 @@ 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, NTRIP_CLIENT_RESPONSE_TIMEOUT); + int connectResponse = ntripClient->connect(settings.ntripClient_CasterHost, settings.ntripClient_CasterPort, + NTRIP_CLIENT_RESPONSE_TIMEOUT); if (connectResponse < 1) { @@ -595,8 +596,9 @@ void ntripClientStop(bool shutdown) // Mark the Client stop so that we don't immediately attempt re-connect to Caster ntripClientTimer = millis(); - // Return the Main Talker ID to "GN". - gnss->setTalkerGNGGA(); + // If we modified the GGA report rate, return it to whatever is in settings + if (settings.ntripClient_TransmitGGA == true) + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request configure so that GGA returns to user defined setting // Determine the next NTRIP client state online.ntripClient = false; @@ -794,9 +796,7 @@ void ntripClientUpdate() if (settings.ntripClient_TransmitGGA == true) { - // Set the Main Talker ID to "GP". The NMEA GGA messages will be GPGGA instead of GNGGA - // Tell the module to output GGA every 5 seconds - gnss->enableGgaForNtrip(); + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request configure so that GGA gets enabled lastGGAPush = millis() - NTRIPCLIENT_MS_BETWEEN_GGA; // Force immediate transmission of GGA message @@ -925,7 +925,7 @@ void ntripClientUpdate() 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); @@ -935,7 +935,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); From 9927af28208a097f175b1634300ec48286c6aac5 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Mon, 27 Oct 2025 15:49:25 -0600 Subject: [PATCH 43/68] Make gnssInRover/Base help functions universal --- Firmware/RTK_Everywhere/GNSS.h | 9 ++ Firmware/RTK_Everywhere/GNSS_LG290P.h | 7 +- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 153 +++++++++++++----------- Firmware/RTK_Everywhere/GNSS_Mosaic.h | 10 +- Firmware/RTK_Everywhere/GNSS_Mosaic.ino | 41 +++++-- Firmware/RTK_Everywhere/GNSS_None.h | 20 ++++ Firmware/RTK_Everywhere/GNSS_UM980.h | 7 +- Firmware/RTK_Everywhere/GNSS_UM980.ino | 63 ++++++---- Firmware/RTK_Everywhere/GNSS_ZED.h | 14 ++- Firmware/RTK_Everywhere/States.ino | 3 +- 10 files changed, 209 insertions(+), 118 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.h b/Firmware/RTK_Everywhere/GNSS.h index 6e65e800d..ed01830b6 100644 --- a/Firmware/RTK_Everywhere/GNSS.h +++ b/Firmware/RTK_Everywhere/GNSS.h @@ -190,6 +190,9 @@ class GNSS // Returns minutes or zero if not online virtual uint8_t getMinute(); + // Returns the current mode: Base/Rover/etc + virtual uint8_t getMode(); + // Returns month number or zero if not online virtual uint8_t getMonth(); @@ -227,6 +230,12 @@ class GNSS // Returns full year, ie 2023, not 23. virtual uint16_t getYear(); + // Helper functions for the current mode as read from the GNSS receiver + // Not to be confused with inRoverMode() and inBaseMode() used in States.ino + virtual bool gnssInBaseFixedMode(); + virtual bool gnssInBaseSurveyInMode(); + virtual bool gnssInRoverMode(); + // Antenna Short / Open detection virtual bool isAntennaShorted(); virtual bool isAntennaOpen(); diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.h b/Firmware/RTK_Everywhere/GNSS_LG290P.h index 004e077e0..9dcd19450 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.h +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.h @@ -307,9 +307,10 @@ class GNSS_LG290P : GNSS // Returns full year, ie 2023, not 23. uint16_t getYear(); - // Returns true if the device is in Rover mode - // Currently the only two modes are Rover or Base - bool inRoverMode(); + // Helper functions for the current mode as read from the GNSS receiver + bool gnssInBaseFixedMode(); + bool gnssInBaseSurveyInMode(); + bool gnssInRoverMode(); bool isBlocking(); diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index 40b7f4532..d5982080b 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -217,55 +217,24 @@ bool GNSS_LG290P::configure() } //---------------------------------------- -// Configure specific aspects of the receiver for rover mode +// Configure specific aspects of the receiver for base mode //---------------------------------------- -bool GNSS_LG290P::configureRover() +bool GNSS_LG290P::configureBase() { - Serial.println("Config rover"); + bool response = true; - int currentMode = getMode(); - if (currentMode == 1) // 0 - Unknown, 1 - Rover, 2 - Base + if (settings.fixedBase == false && gnssInBaseSurveyInMode()) { if (settings.debugGnssConfig) - systemPrintln("Skipping LG290P Rover configuration"); + systemPrintln("Skipping - LG290P is already in Fixed Base configuration"); return (true); // No changes needed } - bool response = _lg290p->setModeRover(false); // Don't wait for save and reset - // Setting mode to rover should disable any survey-in - - gnssConfigure(GNSS_CONFIG_FIX_RATE); - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); - gnssConfigure(GNSS_CONFIG_RESET); // Mode change requires reset - - return (response); -} - -//---------------------------------------- -// Configure specific aspects of the receiver for base mode -//---------------------------------------- -bool GNSS_LG290P::configureBase() -{ - bool response = true; - - int currentMode = getMode(); - uint8_t surveyInMode = getSurveyInMode(); // 0 - Disabled, 1 - Survey-in mode, 2 - Fixed mode - - if (currentMode == 2) // 0 - Unknown, 1 - Rover, 2 - Base + if (settings.fixedBase == true && gnssInBaseFixedMode()) { - if (settings.fixedBase == true && surveyInMode == 2) - { - if (settings.debugGnssConfig) - systemPrintln("Skipping - LG290P is already in Fixed Base configuration"); - return (true); // No changes needed - } - if (settings.fixedBase == false && surveyInMode == 1) - { - if (settings.debugGnssConfig) - systemPrintln("Skipping - LG290P is already in Survey-in Base configuration"); - return (true); // No changes needed - } + if (settings.debugGnssConfig) + systemPrintln("Skipping - LG290P is already in Survey-in Base configuration"); + return (true); // No changes needed } // If the device is set to Survey-In, we must allow the device to be configured. @@ -286,7 +255,7 @@ bool GNSS_LG290P::configureBase() // We set base mode here because we don't want to reset the module right before we (potentially) start a survey-in // We wait for States.ino to change us from base settle, to survey started, at which time the surveyInStart() is // issued. - if (currentMode != 2) // 0 - Unknown, 1 - Rover, 2 - Base + if (gnssInRoverMode() == true) // 0 - Unknown, 1 - Rover, 2 - Base { response &= _lg290p->setModeBase(false); // Don't save and reset if (settings.debugGnssConfig && response == false) @@ -295,7 +264,7 @@ bool GNSS_LG290P::configureBase() // Switching to Base Mode should disable any currently running survey-in // But if we were already in base mode, then disable any currently running survey-in - if (surveyInMode == 1 || surveyInMode == 2) + if (gnssInBaseSurveyInMode() || gnssInBaseFixedMode()) { response &= disableSurveyIn(false); // Don't save and reset if (settings.debugGnssConfig && response == false) @@ -327,6 +296,29 @@ bool GNSS_LG290P::configureBase() return (response); } +//---------------------------------------- +// Configure specific aspects of the receiver for rover mode +//---------------------------------------- +bool GNSS_LG290P::configureRover() +{ + if (gnssInRoverMode()) // 0 - Unknown, 1 - Rover, 2 - Base + { + if (settings.debugGnssConfig) + systemPrintln("Skipping LG290P Rover configuration"); + return (true); // No changes needed + } + + bool response = _lg290p->setModeRover(false); // Don't wait for save and reset + // Setting mode to rover should disable any survey-in + + gnssConfigure(GNSS_CONFIG_FIX_RATE); + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); + gnssConfigure(GNSS_CONFIG_RESET); // Mode change requires reset + + return (response); +} + //---------------------------------------- // Responds with the messages supported on this platform // Inputs: @@ -502,23 +494,18 @@ bool GNSS_LG290P::fixedBaseStart() return (false); // Read, modify, write - int currentMode = getMode(); - uint8_t surveyInMode = getSurveyInMode(); // 0 - Disabled, 1 - Survey-in mode, 2 - Fixed mode - if (currentMode == 2) // 0 - Unknown, 1 - Rover, 2 - Base + if (settings.fixedBase == true && gnssInBaseFixedMode()) { - if (settings.fixedBase == true && surveyInMode == 2) - { - if (settings.debugGnssConfig) - systemPrintln("Skipping - LG290P is already in Fixed Base configuration"); - return (true); // No changes needed - } - if (settings.fixedBase == false && surveyInMode == 1) - { - if (settings.debugGnssConfig) - systemPrintln("Skipping - LG290P is already in Survey-in Base configuration"); - return (true); // No changes needed - } + if (settings.debugGnssConfig) + systemPrintln("Skipping - LG290P is already in Fixed Base configuration"); + return (true); // No changes needed + } + if (settings.fixedBase == false && gnssInBaseSurveyInMode()) + { + if (settings.debugGnssConfig) + systemPrintln("Skipping - LG290P is already in Survey-in Base configuration"); + return (true); // No changes needed } if (settings.fixedBaseCoordinateType == COORD_TYPE_ECEF) @@ -1090,16 +1077,42 @@ uint16_t GNSS_LG290P::getYear() } //---------------------------------------- -// Returns true if the device is in Rover mode -// Currently the only two modes are Rover or Base +// Returns true if the device is in Base Fixed mode //---------------------------------------- -bool GNSS_LG290P::inRoverMode() +bool GNSS_LG290P::gnssInBaseFixedMode() { - // Determine which state we are in - if (settings.lastState == STATE_BASE_NOT_STARTED) - return (false); + // 0 - Unknown, 1 - Rover, 2 - Base + if (getMode() == 2) + { + if (getSurveyInMode() == 2) // 0 - Disabled, 1 - Survey-in mode, 2 - Fixed mode + return (true); + } + return (false); +} - return (true); // Default to Rover +//---------------------------------------- +// Returns true if the device is in Base Survey In mode +//---------------------------------------- +bool GNSS_LG290P::gnssInBaseSurveyInMode() +{ + // 0 - Unknown, 1 - Rover, 2 - Base + if (getMode() == 2) + { + if (getSurveyInMode() == 1) // 0 - Disabled, 1 - Survey-in mode, 2 - Fixed mode + return (true); + } + return (false); +} + +//---------------------------------------- +// Returns true if the device is in Rover mode +//---------------------------------------- +bool GNSS_LG290P::gnssInRoverMode() +{ + // 0 - Unknown, 1 - Rover, 2 - Base + if (getMode() == 1) + return (true); + return (false); } // If we issue a library command that must wait for a response, we don't want @@ -1404,7 +1417,7 @@ void GNSS_LG290P::menuMessages() settings.lg290pMessageRatesPQTM[x] = lgMessagesPQTM[x].msgDefaultRate; gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); - if (inBaseMode()) + if (inBaseMode()) // If the system is in Base mode gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); else gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); @@ -2286,12 +2299,11 @@ bool GNSS_LG290P::setMultipathMitigation(bool enableMultipathMitigation) } //---------------------------------------- -// Returns the current mode +// Returns the current mode, Base/Rover/etc // 0 - Unknown, 1 - Rover, 2 - Base //---------------------------------------- uint8_t GNSS_LG290P::getMode() { - // The fix rate can only be set in rover mode. Return false if we are in base mode. int currentMode = 0; if (online.gnss) _lg290p->getMode(currentMode); @@ -2310,14 +2322,13 @@ bool GNSS_LG290P::setRate(double secondsBetweenSolutions) // The fix rate can only be set in rover mode. Return true if we are in base mode. // This allows the gnssUpdate() to clear the bit. - int currentMode = getMode(); - if (currentMode == 2) // Base - return (true); // Nothing to modify at this time + if (gnssInBaseSurveyInMode() || gnssInBaseFixedMode()) // Base + return (true); // Nothing to modify at this time bool response = true; // Change to rover mode - if (currentMode != 1) // 0 - Unknown, 1 - Rover, 2 - Base + if (gnssInRoverMode() == false) { response &= _lg290p->setModeRover(); // Wait for save and reset if (response == false && settings.debugGnssConfig) diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.h b/Firmware/RTK_Everywhere/GNSS_Mosaic.h index d66e79e3b..2ea349c6e 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.h +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.h @@ -733,6 +733,9 @@ class GNSS_MOSAIC : GNSS // Returns minutes or zero if not online uint8_t getMinute(); + // Returns the current mode: Base/Rover/etc + uint8_t getMode(); + // Returns month number or zero if not online uint8_t getMonth(); @@ -777,9 +780,10 @@ class GNSS_MOSAIC : GNSS // Returns full year, ie 2023, not 23. uint16_t getYear(); - // Returns true if the device is in Rover mode - // Currently the only two modes are Rover or Base - bool inRoverMode(); + // Helper functions for the current mode as read from the GNSS receiver + bool gnssInBaseFixedMode(); + bool gnssInBaseSurveyInMode(); + bool gnssInRoverMode(); // Antenna Short / Open detection bool isAntennaShorted(); diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino index 74c895fee..b5c65738c 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino @@ -1124,6 +1124,15 @@ uint8_t GNSS_MOSAIC::getMinute() return _minute; } +//---------------------------------------- +// Returns the current mode: Base/Rover/etc +//---------------------------------------- +uint8_t GNSS_MOSAIC::getMode() +{ + // TODO + return 0; +} + //---------------------------------------- // Returns month number or zero if not online //---------------------------------------- @@ -1263,17 +1272,29 @@ uint16_t GNSS_MOSAIC::getYear() return _year; } +//---------------------------------------- +// Returns true if the device is in Base Fixed mode +//---------------------------------------- +bool GNSS_MOSAIC::gnssInBaseFixedMode() +{ + // TODO + return (false); +} +//---------------------------------------- +// Returns true if the device is in Base Survey In mode +//---------------------------------------- +bool GNSS_MOSAIC::gnssInBaseSurveyInMode() +{ + // TODO + return (false); +} //---------------------------------------- // Returns true if the device is in Rover mode -// Currently the only two modes are Rover or Base //---------------------------------------- -bool GNSS_MOSAIC::inRoverMode() +bool GNSS_MOSAIC::gnssInRoverMode() { - // Determine which state we are in - if (settings.lastState == STATE_BASE_NOT_STARTED) - return (false); - - return (true); // Default to Rover + // TODO + return (false); } //---------------------------------------- @@ -1624,7 +1645,7 @@ void GNSS_MOSAIC::menuMessagesRTCM(bool rover) if ((interval >= 0.1) && (interval <= 600.0)) { intervalPtr[incoming] = interval; - if (inBaseMode()) + if (inBaseMode()) // If the system state is Base mode gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); // Request receiver to use new settings else gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings @@ -1703,8 +1724,8 @@ void GNSS_MOSAIC::menuMessages() for (int x = 0; x < MAX_MOSAIC_RTCM_V3_MSG; x++) settings.mosaicMessageEnabledRTCMv3Base[x] = mosaicMessagesRTCMv3[x].defaultEnabled; - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings - if (inBaseMode()) + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings + if (inBaseMode()) // If the system state is Base mode gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); // Request receiver to use new settings else gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings diff --git a/Firmware/RTK_Everywhere/GNSS_None.h b/Firmware/RTK_Everywhere/GNSS_None.h index 166c87802..0bd07a56d 100644 --- a/Firmware/RTK_Everywhere/GNSS_None.h +++ b/Firmware/RTK_Everywhere/GNSS_None.h @@ -293,6 +293,12 @@ class GNSS_None : public GNSS return _minute; } + // Returns the current mode: Base/Rover/etc + uint8_t getMode() + { + return 0; + } + // Returns month number or zero if not online uint8_t getMonth() { @@ -369,6 +375,20 @@ class GNSS_None : public GNSS return _year; } + // Helper functions for the current mode as read from the GNSS receiver + bool gnssInBaseFixedMode() + { + return false; + } + bool gnssInBaseSurveyInMode() + { + return false; + } + bool gnssInRoverMode() + { + return false; + } + bool isBlocking() { return false; diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.h b/Firmware/RTK_Everywhere/GNSS_UM980.h index 4050804f9..bc24a48c5 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.h +++ b/Firmware/RTK_Everywhere/GNSS_UM980.h @@ -318,9 +318,10 @@ class GNSS_UM980 : GNSS // Returns full year, ie 2023, not 23. uint16_t getYear(); - // Returns true if the device is in Rover mode - // Currently the only two modes are Rover or Base - bool inRoverMode(); + // Helper functions for the current mode as read from the GNSS receiver + bool gnssInBaseFixedMode(); + bool gnssInBaseSurveyInMode(); + bool gnssInRoverMode(); bool isBlocking(); diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index a215cfe2f..d59b69614 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -166,12 +166,10 @@ bool GNSS_UM980::checkPPPRates() //---------------------------------------- bool GNSS_UM980::configureBase() { - // Determine current mode. If we are already in Rover, no changes needed - // 0 - Unknown, 1 - Rover Survey, 2 - Rover UAV, 3 - Rover Auto, 4 - Base Survey-in, 5 - Base fixed - int currentMode = getMode(); - if (settings.fixedBase == false && currentMode == 4) + // If we are already in the appropriate base mode, no changes needed + if (settings.fixedBase == false && gnssInBaseSurveyInMode()) return (true); - if (settings.fixedBase == true && currentMode == 5) + if (settings.fixedBase == true && gnssInBaseFixedMode()) return (true); // Set the dynamic mode. This will cancel any base averaging mode and is needed @@ -235,16 +233,6 @@ bool GNSS_UM980::configureOnce() } systemPrintln("UM980 has completed reboot."); - - // configureOnce() should only be run after a system level factory reset - // Other bits to enable NMEA and RTCM should be enabled so no need to enable messages here - - // // Re-enable messages - // gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); - // if (inBaseMode()) - // gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); - // else - // gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); } } @@ -866,17 +854,40 @@ uint16_t GNSS_UM980::getYear() return 0; } +//---------------------------------------- +// Returns true if the device is in Base Fixed mode +//---------------------------------------- +bool GNSS_UM980::gnssInBaseFixedMode() +{ + // 0 - Unknown, 1 - Rover Survey, 2 - Rover UAV, 3 - Rover Auto, 4 - Base Survey-in, 5 - Base fixed + if (getMode() == 5) + return (true); + return (false); +} + +//---------------------------------------- +// Returns true if the device is in Base Survey-in mode +//---------------------------------------- +bool GNSS_UM980::gnssInBaseSurveyInMode() +{ + // 0 - Unknown, 1 - Rover Survey, 2 - Rover UAV, 3 - Rover Auto, 4 - Base Survey-in, 5 - Base fixed + if (getMode() == 4) + return (true); + + return (false); +} + //---------------------------------------- // Returns true if the device is in Rover mode -// Currently the only two modes are Rover or Base //---------------------------------------- -bool GNSS_UM980::inRoverMode() +bool GNSS_UM980::gnssInRoverMode() { - // Determine which state we are in - if (settings.lastState == STATE_BASE_NOT_STARTED) - return (false); + // 0 - Unknown, 1 - Rover Survey, 2 - Rover UAV, 3 - Rover Auto, 4 - Base Survey-in, 5 - Base fixed + int currentMode = getMode(); + if (currentMode >= 1 && currentMode <= 3) + return (true); - return (true); // Default to Rover + return (false); } // If we issue a library command that must wait for a response, we don't want @@ -1142,8 +1153,8 @@ void GNSS_UM980::menuMessages() systemPrintln("Reset to Defaults"); - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings - if (inBaseMode()) + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings + if (inBaseMode()) // If the current system state is Base gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); // Request receiver to use new settings else gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings @@ -1178,8 +1189,8 @@ void GNSS_UM980::menuMessages() else systemPrintln("Reset to PPP Logging (NMEAx5 / RTCMx4 - 30 second decimation)"); - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings - if (inBaseMode()) + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings + if (inBaseMode()) // If the current system state is Base gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); // Request receiver to use new settings else gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings @@ -1598,7 +1609,7 @@ bool GNSS_UM980::setMessagesNMEA() um980MessagesEnabled_RTCM_Base = false; // Request reconfigure of RTCM - if (inBaseMode()) + if (inBaseMode()) // If the current system state is Base gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); else gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.h b/Firmware/RTK_Everywhere/GNSS_ZED.h index b3506ee72..39a329ae0 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.h +++ b/Firmware/RTK_Everywhere/GNSS_ZED.h @@ -461,7 +461,7 @@ class GNSS_ZED : GNSS bool fixRateIsAllowed(uint32_t fixRateMs); - //Return min/max rate in ms + // Return min/max rate in ms uint32_t fixRateGetMinimumMs(); uint32_t fixRateGetMaximumMs(); @@ -529,6 +529,10 @@ class GNSS_ZED : GNSS // Returns minutes or zero if not online uint8_t getMinute(); + // Returns the current mode: Base/Rover/etc + // 0 - Rover, 1 - Base Survey-In, 2 - Base Fixed + uint8_t getMode(); + // Returns month number or zero if not online uint8_t getMonth(); @@ -568,6 +572,11 @@ class GNSS_ZED : GNSS // Returns full year, ie 2023, not 23. uint16_t getYear(); + // Helper functions for the current mode as read from the GNSS receiver + bool gnssInBaseFixedMode(); + bool gnssInBaseSurveyInMode(); + bool gnssInRoverMode(); + // Antenna Short / Open detection bool isAntennaShorted(); bool isAntennaOpen(); @@ -653,6 +662,9 @@ class GNSS_ZED : GNSS // Returns the number of correction data bytes written int pushRawData(uint8_t *dataToSend, int dataLength); + // Set callback functions (PVT, etc) for u-blox library + bool registerCallbacks(); + // Hardware or software reset the GNSS bool reset(); diff --git a/Firmware/RTK_Everywhere/States.ino b/Firmware/RTK_Everywhere/States.ino index 3a4de8f30..1347a18db 100644 --- a/Firmware/RTK_Everywhere/States.ino +++ b/Firmware/RTK_Everywhere/States.ino @@ -96,7 +96,8 @@ void stateUpdate() baseStatusLedOff(); - gnssConfigure(GNSS_CONFIG_ROVER); // Request reconfigure to rover mode + if(gnss->gnssInRoverMode() == false) + gnssConfigure(GNSS_CONFIG_ROVER); // Request reconfigure to rover mode setMuxport(settings.dataPortChannel); // Return mux to original channel From 25aa95564c39d804128a68894c84bbda289447ce Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Mon, 27 Oct 2025 16:23:07 -0600 Subject: [PATCH 44/68] Initial ZED support for gnssConfigure() --- Firmware/RTK_Everywhere/Display.ino | 4 +- Firmware/RTK_Everywhere/GNSS.ino | 26 +- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 4 +- Firmware/RTK_Everywhere/GNSS_Mosaic.ino | 25 - Firmware/RTK_Everywhere/GNSS_ZED.ino | 787 +++++++++++------------- Firmware/RTK_Everywhere/NVM.ino | 39 +- Firmware/RTK_Everywhere/States.ino | 13 +- Firmware/RTK_Everywhere/Tilt.ino | 2 +- Firmware/RTK_Everywhere/menuBase.ino | 39 +- Firmware/RTK_Everywhere/menuMain.ino | 15 +- Firmware/RTK_Everywhere/settings.h | 10 - 11 files changed, 442 insertions(+), 522 deletions(-) diff --git a/Firmware/RTK_Everywhere/Display.ino b/Firmware/RTK_Everywhere/Display.ino index f2d932ec2..3b8ee5bf3 100644 --- a/Firmware/RTK_Everywhere/Display.ino +++ b/Firmware/RTK_Everywhere/Display.ino @@ -2467,8 +2467,8 @@ void paintProfile(uint8_t profileUnit) if (profileNumber >= 0) { - settings.gnssConfiguredBase = false; // On the next boot, reapply all settings - settings.gnssConfiguredRover = false; + gnssConfigureDefaults(); // Set all bits in the request bitfield to cause the GNSS receiver to go through a + // full (re)configuration recordSystemSettings(); // Before switching, we need to record the current settings to LittleFS and SD recordProfileNumber( diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index 67a877317..eb53bfe57 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -114,7 +114,7 @@ void gnssUpdate() if (gnss == nullptr) return; - // Allow the GNSS platform to update itself + // Allow the GNSS platform to update itself gnss->update(); if (gnssConfigureComplete() == true) @@ -165,26 +165,14 @@ void gnssUpdate() if (gnssConfigureRequested(GNSS_CONFIG_BASE)) { - // Change GNSS receiver configuration if we are in base mode, otherwise, just change setting - if (inBaseMode() == true) + if (gnss->configureBase() == true) { - if (gnss->configureBase() == true) - { - gnssConfigureClear(GNSS_CONFIG_BASE); - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM - } - else - { - systemPrintln("Base config failed"); - } + gnssConfigureClear(GNSS_CONFIG_BASE); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM } else { - // We have allowed the settings struct changes, but do not need to apply them to the GNSS receiver at - // this time - if (settings.debugGnssConfig) - systemPrintln("Not in base mode - clearing bit."); - gnssConfigureClear(GNSS_CONFIG_BASE); + systemPrintln("Base config failed"); } } @@ -539,8 +527,8 @@ void gnssDetectReceiverType() // Note: with this in place, the X5 detection will take a lot longer due to the baud rate change #ifdef FLEX_OVERRIDE systemPrintln("<<<<<<<<<< !!!!!!!!!! FLEX FORCED !!!!!!!!!! >>>>>>>>>>"); - // settings.detectedGnssReceiver = GNSS_RECEIVER_UNKNOWN; // This may be causing weirdness on the LG290P. Commenting - // for now + // settings.detectedGnssReceiver = GNSS_RECEIVER_UNKNOWN; // This may be causing weirdness on the LG290P. + // Commenting for now #endif // Start auto-detect if NVM is not yet set diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index d5982080b..128944bc1 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -264,7 +264,7 @@ bool GNSS_LG290P::configureBase() // Switching to Base Mode should disable any currently running survey-in // But if we were already in base mode, then disable any currently running survey-in - if (gnssInBaseSurveyInMode() || gnssInBaseFixedMode()) + if (gnss->gnssInBaseSurveyInMode() || gnss->gnssInBaseFixedMode()) { response &= disableSurveyIn(false); // Don't save and reset if (settings.debugGnssConfig && response == false) @@ -2322,7 +2322,7 @@ bool GNSS_LG290P::setRate(double secondsBetweenSolutions) // The fix rate can only be set in rover mode. Return true if we are in base mode. // This allows the gnssUpdate() to clear the bit. - if (gnssInBaseSurveyInMode() || gnssInBaseFixedMode()) // Base + if (gnss->gnssInBaseSurveyInMode() || gnss->gnssInBaseFixedMode()) // Base return (true); // Nothing to modify at this time bool response = true; diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino index b5c65738c..f118a0437 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino @@ -457,12 +457,6 @@ bool GNSS_MOSAIC::configureBase() return (false); } - if (settings.gnssConfiguredBase) - { - systemPrintln("Skipping mosaic Base configuration"); - return true; - } - bool response = true; response &= setModel(MOSAIC_DYN_MODEL_STATIC); @@ -487,8 +481,6 @@ bool GNSS_MOSAIC::configureBase() systemPrintln("mosaic-X5 Base failed to configure"); } - settings.gnssConfiguredBase = response; - return (response); } @@ -601,12 +593,6 @@ bool GNSS_MOSAIC::configureOnce() RTCMv3 messages are enabled by setMessagesRTCMRover / setMessagesRTCMBase */ - if (settings.gnssConfiguredOnce) - { - systemPrintln("mosaic configuration maintained"); - return (true); - } - bool response = true; // Configure COM1. NMEA and RTCMv3 will be encapsulated in SBF format @@ -655,8 +641,6 @@ bool GNSS_MOSAIC::configureOnce() else online.gnss = false; // Take it offline - settings.gnssConfiguredOnce = response; - return (response); } @@ -698,13 +682,6 @@ bool GNSS_MOSAIC::configureRover() return (false); } - // If our settings haven't changed, trust GNSS's settings - if (settings.gnssConfiguredRover) - { - systemPrintln("Skipping mosaic Rover configuration"); - return (true); - } - bool response = true; response &= sendWithResponse("spm,Rover,all,auto\n\r", "PVTMode"); @@ -731,8 +708,6 @@ bool GNSS_MOSAIC::configureRover() systemPrintln("mosaic-X5 Rover failed to configure"); } - settings.gnssConfiguredRover = response; - return (response); } diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index ff69cb057..7ac636e5d 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -137,18 +137,22 @@ void GNSS_ZED::begin() if (_zed->begin(*i2c_0) == false) { - systemPrintln("GNSS ZED failed to begin. Trying again."); + systemPrintln("GNSS ZED-F9P failed to begin. Trying again."); // Try again with power on delay delay(1000); // Wait for ZED-F9P to power up before it can respond to ACK if (_zed->begin(*i2c_0) == false) { - systemPrintln("GNSS ZED offline"); + systemPrintln("GNSS ZED-F9P offline"); displayGNSSFail(1000); return; } } + // Turn on debug messages if needed + if (settings.debugGnss) + debuggingEnable(); + // Increase transactions to reduce transfer time _zed->i2cTransactionSize = 128; @@ -215,13 +219,18 @@ void GNSS_ZED::begin() { snprintf(gnssUniqueId, sizeof(gnssUniqueId), "%s", _zed->getUniqueChipIdStr(&chipID)); - systemPrintln("GNSS ZED online"); + // Callbacks are volatile and must be set after each reset + registerCallbacks(); + + systemPrintln("GNSS ZED-F9P online"); + online.gnss = true; + return; } } - systemPrintln("GNSS ZED offline"); + systemPrintln("GNSS ZED-F9P offline"); displayGNSSFail(1000); } @@ -323,200 +332,9 @@ bool GNSS_ZED::checkPPPRates() return false; } -//---------------------------------------- -// Configure specific aspects of the receiver for base mode -//---------------------------------------- -bool GNSS_ZED::configureBase() -{ - if (online.gnss == false) - return (false); - - if (settings.gnssConfiguredBase) - { - if (settings.debugGnss) - systemPrintln("Skipping ZED Base configuration"); - return true; - } - - update(); // Regularly poll to get latest data - - bool success = false; - int tryNo = -1; - - // Try up to MAX_SET_MESSAGES_RETRIES times to configure the GNSS - // This corrects occasional failures seen on the Reference Station where the GNSS is connected via SPI - // instead of I2C and UART1. I believe the SETVAL ACK is occasionally missed due to the level of messages being - // processed. - while ((++tryNo < MAX_SET_MESSAGES_RETRIES) && !success) - { - bool response = true; - - // In Base mode we force 1Hz - response &= _zed->newCfgValset(VAL_LAYER_ALL); - response &= _zed->addCfgValset(UBLOX_CFG_RATE_MEAS, 1000); - response &= _zed->addCfgValset(UBLOX_CFG_RATE_NAV, 1); - - // Since we are at 1Hz, allow GSV NMEA to be reported at whatever the user has chosen - response &= _zed->addCfgValset(ubxMessages[8].msgConfigKey, - settings.ubxMessageRates[8]); // Update rate on module - - response &= _zed->addCfgValset(UBLOX_CFG_MSGOUT_NMEA_ID_GGA_I2C, - 0); // Disable NMEA message that may have been set during Rover NTRIP Client mode - - // Survey mode is only available on ZED-F9P modules - if (commandSupported(UBLOX_CFG_TMODE_MODE)) - response &= _zed->addCfgValset(UBLOX_CFG_TMODE_MODE, 0); // Disable survey-in mode - - // Note that using UBX-CFG-TMODE3 to set the receiver mode to Survey In or to Fixed Mode, will set - // automatically the dynamic platform model (CFG-NAVSPG-DYNMODEL) to Stationary. - // response &= _zed->addCfgValset(UBLOX_CFG_NAVSPG_DYNMODEL, (dynModel)settings.dynamicModel); //Not needed - - // For most RTK products, the GNSS is interfaced via both I2C and UART1. Configuration and PVT/HPPOS messages - // are configured over I2C. Any messages that need to be logged are output on UART1, and received by this code - // using serialGNSS-> In base mode the RTK device should output RTCM over all ports: (Primary) UART2 in case the - // RTK device is connected via radio to rover (Optional) I2C in case user wants base to connect to WiFi and - // NTRIP Caster (Seconday) USB in case the RTK device is used as an NTRIP caster connected to SBC or other - // (Tertiary) UART1 in case RTK device is sending RTCM to a phone that is then NTRIP Caster - - // Find first RTCM record in ubxMessage array - int firstRTCMRecord = getMessageNumberByName("RTCM_1005"); - - // ubxMessageRatesBase is an array of ~12 uint8_ts - // ubxMessage is an array of ~80 messages - // We use firstRTCMRecord as an offset for the keys, but use x as the rate - - for (int x = 0; x < MAX_UBX_MSG_RTCM; x++) - { - response &= _zed->addCfgValset(ubxMessages[firstRTCMRecord + x].msgConfigKey - 1, - settings.ubxMessageRatesBase[x]); // UBLOX_CFG UART1 - 1 = I2C - response &= _zed->addCfgValset(ubxMessages[firstRTCMRecord + x].msgConfigKey, - settings.ubxMessageRatesBase[x]); // UBLOX_CFG UART1 - - // Disable messages on SPI - response &= _zed->addCfgValset(ubxMessages[firstRTCMRecord + x].msgConfigKey + 3, - 0); // UBLOX_CFG UART1 + 3 = SPI - } - - // Update message rates for UART2 and USB - for (int x = 0; x < MAX_UBX_MSG_RTCM; x++) - { - response &= _zed->addCfgValset(ubxMessages[firstRTCMRecord + x].msgConfigKey + 1, - settings.ubxMessageRatesBase[x]); // UBLOX_CFG UART1 + 1 = UART2 - response &= _zed->addCfgValset(ubxMessages[firstRTCMRecord + x].msgConfigKey + 2, - settings.ubxMessageRatesBase[x]); // UBLOX_CFG UART1 + 2 = USB - } - - // Set minimum elevation - // Note: ZED supports negative elevations, but our firmware only allows 0-90 - response &= _zed->addCfgValset(UBLOX_CFG_NAVSPG_INFIL_MINELEV, settings.minElev); - - response &= _zed->sendCfgValset(); // Closing value - - if (response) - success = true; - } - - if (!success) - systemPrintln("Base config fail"); - - // The configuration should be saved to RAM+BBR+FLASH. No need to saveConfiguration here. - - settings.gnssConfiguredBase = success; - - return (success); -} - -//---------------------------------------- -// Configure specific aspects of the receiver for NTP mode -//---------------------------------------- -bool GNSS_ZED::configureNtpMode() -{ - bool success = false; - - if (online.gnss == false) - return (false); - - // This is only called by STATE_NTPSERVER_NOT_STARTED - // I guess it is OK to always do the configuration? - // stateUpdate clear the Base and Rover configuration flags - // to ensure the configuration is re-applied when we exit this mode - - update(); // Regularly poll to get latest data - - // Disable GPGGA call back that may have been set during Rover NTRIP Client mode - _zed->setNMEAGPGGAcallbackPtr(nullptr); - - int tryNo = -1; - - // Try up to MAX_SET_MESSAGES_RETRIES times to configure the GNSS - // This corrects occasional failures seen on the Reference Station where the GNSS is connected via SPI - // instead of I2C and UART1. I believe the SETVAL ACK is occasionally missed due to the level of messages being - // processed. - while ((++tryNo < MAX_SET_MESSAGES_RETRIES) && !success) - { - bool response = true; - - // In NTP mode we force 1Hz - response &= _zed->newCfgValset(VAL_LAYER_ALL); - response &= _zed->addCfgValset(UBLOX_CFG_RATE_MEAS, 1000); - response &= _zed->addCfgValset(UBLOX_CFG_RATE_NAV, 1); - - // Survey mode is only available on ZED-F9P modules - response &= _zed->addCfgValset(UBLOX_CFG_TMODE_MODE, 0); // Disable survey-in mode - - // Set dynamic model to stationary - response &= _zed->addCfgValset(UBLOX_CFG_NAVSPG_DYNMODEL, DYN_MODEL_STATIONARY); // Set dynamic model - - // Set time pulse to 1Hz (100:900) - response &= _zed->addCfgValset(UBLOX_CFG_TP_PULSE_DEF, 0); // Time pulse definition is a period (in us) - response &= _zed->addCfgValset(UBLOX_CFG_TP_PULSE_LENGTH_DEF, 1); // Define timepulse by length (not ratio) - response &= - _zed->addCfgValset(UBLOX_CFG_TP_USE_LOCKED_TP1, - 1); // Use CFG-TP-PERIOD_LOCK_TP1 and CFG-TP-LEN_LOCK_TP1 as soon as GNSS time is valid - response &= _zed->addCfgValset(UBLOX_CFG_TP_TP1_ENA, 1); // Enable timepulse - response &= _zed->addCfgValset(UBLOX_CFG_TP_POL_TP1, 1); // 1 = rising edge - - // While the module is _locking_ to GNSS time, turn off pulse - response &= _zed->addCfgValset(UBLOX_CFG_TP_PERIOD_TP1, 1000000); // Set the period between pulses in us - response &= _zed->addCfgValset(UBLOX_CFG_TP_LEN_TP1, 0); // Set the pulse length in us - - // When the module is _locked_ to GNSS time, make it generate 1Hz (100ms high, 900ms low) - response &= _zed->addCfgValset(UBLOX_CFG_TP_PERIOD_LOCK_TP1, 1000000); // Set the period between pulses is us - response &= _zed->addCfgValset(UBLOX_CFG_TP_LEN_LOCK_TP1, 100000); // Set the pulse length in us - - // Ensure pulse is aligned to top-of-second. This is the default. Set it here just to make sure. - response &= _zed->addCfgValset(UBLOX_CFG_TP_ALIGN_TO_TOW_TP1, 1); - - // Set the time grid to UTC. This is the default. Set it here just to make sure. - response &= _zed->addCfgValset(UBLOX_CFG_TP_TIMEGRID_TP1, 0); // 0=UTC; 1=GPS - - // Sync to GNSS. This is the default. Set it here just to make sure. - response &= _zed->addCfgValset(UBLOX_CFG_TP_SYNC_GNSS_TP1, 1); - - response &= _zed->addCfgValset(UBLOX_CFG_NAVSPG_INFIL_MINELEV, settings.minElev); // Set minimum elevation - - // Ensure PVT, HPPOSLLH and TP messages are being output at 1Hz on the correct port - response &= _zed->addCfgValset(UBLOX_CFG_MSGOUT_UBX_NAV_PVT_I2C, 1); - response &= _zed->addCfgValset(UBLOX_CFG_MSGOUT_UBX_NAV_HPPOSLLH_I2C, 1); - response &= _zed->addCfgValset(UBLOX_CFG_MSGOUT_UBX_TIM_TP_I2C, 1); - - response &= _zed->sendCfgValset(); // Closing value - - if (response) - success = true; - } - - if (!success) - systemPrintln("NTP config fail"); - - // The configuration should be saved to RAM+BBR+FLASH. No need to saveConfiguration here. - - return (success); -} - //---------------------------------------- // Setup the u-blox module for any setup (base or rover) -// This is the equivalent of configureOnce on the other platforms +// This gets run once after a factory reset, and is called until it completes successfully. // In general we check if the setting is incorrect before writing it. Otherwise, the set commands have, on rare // occasion, become corrupt. The worst is when the I2C port gets turned off or the I2C address gets borked. //---------------------------------------- @@ -526,85 +344,26 @@ bool GNSS_ZED::configure() return (false); bool response = true; - bool success = true; - - // Turn on/off debug messages - if (settings.debugGnss) - _zed->enableDebugging(Serial, true); // Enable only the critical debug messages over Serial - else - _zed->disableDebugging(); - - // Check if the ubxMessageRates or ubxMessageRatesBase need to be defaulted - // Redundant - also done by gnssConfigure - // checkGNSSArrayDefaults(); - - // Configure the callbacks - - response &= _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 - - if (present.timePulseInterrupt) - response &= _zed->setAutoTIMTPcallbackPtr( - &storeTIMTPdata, VAL_LAYER_ALL); // Enable automatic TIM TP messages with callback to storeTIMTPdata - - if (present.antennaShortOpen) - { - response &= _zed->newCfgValset(VAL_LAYER_ALL); - - response &= _zed->addCfgValset(UBLOX_CFG_HW_ANT_CFG_SHORTDET, 1); // Enable antenna short detection - response &= _zed->addCfgValset(UBLOX_CFG_HW_ANT_CFG_OPENDET, 1); // Enable antenna open detection - - response &= _zed->sendCfgValset(); - response &= _zed->setAutoMONHWcallbackPtr( - &storeMONHWdata, VAL_LAYER_ALL); // Enable automatic MON HW messages with callback to storeMONHWdata - } - - // Add a callback for UBX-MON-COMMS - response &= _zed->setAutoMONCOMMScallbackPtr(&storeMONCOMMSdata, VAL_LAYER_ALL); - // Enable RTCM3 if needed - if not enable NMEA IN to keep skipped updated - response &= setCorrRadioExtPort(settings.enableExtCorrRadio, true); // Force the setting + // // Wait for initial report from module + // int maxWait = 2000; + // startTime = millis(); + // while (_pvtUpdated == false) + // { + // update(); // Regularly poll to get latest data + + // delay(10); + // if ((millis() - startTime) > maxWait) + // { + // systemPrintln("PVT Update failed"); + // break; + // } + // } - if (!response) - { - systemPrintln("GNSS initial configuration (callbacks, short detection, radio port) failed"); - } - success &= response; - response = true; // Reset - - // Configuring the ZED can take more than 2000ms. Configuration is saved to - // ZED RAM+BBR so there is no need to update settings unless user has modified - // the settings file or internal settings. - if (settings.gnssConfiguredOnce) - { - systemPrintln("ZED-F9x configuration maintained"); - return (true); - } - - // Wait for initial report from module - int maxWait = 2000; - startTime = millis(); - while (_pvtUpdated == false) - { - update(); // Regularly poll to get latest data - - delay(10); - if ((millis() - startTime) > maxWait) - { - log_d("PVT Update failed"); - break; - } - } - - // The first thing we do is go to 1Hz to lighten any I2C traffic from a previous configuration response &= _zed->newCfgValset(VAL_LAYER_ALL); - response &= _zed->addCfgValset(UBLOX_CFG_RATE_MEAS, 1000); - response &= _zed->addCfgValset(UBLOX_CFG_RATE_NAV, 1); - if (commandSupported(UBLOX_CFG_TMODE_MODE)) - response &= _zed->addCfgValset(UBLOX_CFG_TMODE_MODE, 0); // Disable survey-in mode + response &= _zed->addCfgValset(UBLOX_CFG_HW_ANT_CFG_SHORTDET, 1); // Enable antenna short detection + response &= _zed->addCfgValset(UBLOX_CFG_HW_ANT_CFG_OPENDET, 1); // Enable antenna open detection // UART1 will primarily be used to pass NMEA and UBX from ZED to ESP32 (eventually to cell phone) // but the phone can also provide RTCM data and a user may want to configure the ZED over Bluetooth. @@ -619,12 +378,6 @@ bool GNSS_ZED::configure() if (commandSupported(UBLOX_CFG_UART1INPROT_SPARTN)) response &= _zed->addCfgValset(UBLOX_CFG_UART1INPROT_SPARTN, 0); - response &= _zed->addCfgValset(UBLOX_CFG_UART1_BAUDRATE, - settings.dataPortBaud); // Defaults to 230400 to maximize message output support - response &= - _zed->addCfgValset(UBLOX_CFG_UART2_BAUDRATE, - settings.radioPortBaud); // Defaults to 57600 to match SiK telemetry radio firmware default - // Disable SPI port - This is just to remove some overhead by ZED response &= _zed->addCfgValset(UBLOX_CFG_SPIOUTPROT_UBX, 0); response &= _zed->addCfgValset(UBLOX_CFG_SPIOUTPROT_NMEA, 0); @@ -677,13 +430,6 @@ bool GNSS_ZED::configure() if (commandSupported(UBLOX_CFG_USBINPROT_SPARTN)) response &= _zed->addCfgValset(UBLOX_CFG_USBINPROT_SPARTN, 0); - if (commandSupported(UBLOX_CFG_NAVSPG_INFIL_MINCNO)) - { - response &= - _zed->addCfgValset(UBLOX_CFG_NAVSPG_INFIL_MINCNO, - settings.minCNO); // Set minimum satellite signal level for navigation - default 6 - } - if (commandSupported(UBLOX_CFG_NAV2_OUT_ENABLED)) { // Count NAV2 messages and enable NAV2 as needed. @@ -697,26 +443,13 @@ bool GNSS_ZED::configure() response &= _zed->addCfgValset(UBLOX_CFG_NAV2_OUT_ENABLED, 0); // Disable NAV2 messages } + response &= _zed->addCfgValset(UBLOX_CFG_NMEA_HIGHPREC, 1); // Enable high precision NMEA + response &= _zed->addCfgValset(UBLOX_CFG_NMEA_SVNUMBERING, 1); // Enable extended satellite numbering + response &= _zed->sendCfgValset(); if (response == false) systemPrintln("Module failed config block 0"); - success &= response; - response = true; // Reset - - // Enable the constellations the user has set - response &= setConstellations(); // 19 messages. Send newCfg or sendCfg with value set - if (response == false) - systemPrintln("Module failed config block 1"); - success &= response; - response = true; // Reset - - // Make sure the appropriate messages are enabled - response &= setMessagesNMEA(); // Does a complete open/closed val set - if (response == false) - systemPrintln("Module failed config block 2"); - success &= response; - response = true; // Reset // Disable NMEA messages on all but UART1 response &= _zed->newCfgValset(VAL_LAYER_ALL); @@ -748,43 +481,67 @@ bool GNSS_ZED::configure() response &= _zed->sendCfgValset(); if (response == false) - systemPrintln("Module failed config block 3"); - - success &= response; - - if (success) - { - systemPrintln("ZED-F9x configuration updated"); - } + systemPrintln("Module failed config block 1"); - settings.gnssConfiguredOnce = success; + // Enable RTCM3 if needed - if not enable NMEA IN to keep skipped updated + gnssConfigure(GNSS_CONFIG_EXT_CORRECTIONS); // Request receiver to use new settings - // The configuration should be saved to RAM+BBR+FLASH. No need to saveConfiguration here. + if (response) + systemPrintln("ZED-F9P configured"); - return (success); + return (response); } //---------------------------------------- -// Configure specific aspects of the receiver for rover mode +// Configure specific aspects of the receiver for base mode //---------------------------------------- -bool GNSS_ZED::configureRover() +bool GNSS_ZED::configureBase() { - if (online.gnss == false) + if (settings.fixedBase == false && gnssInBaseSurveyInMode()) { - systemPrintln("GNSS not online"); - return (false); + if (settings.debugGnssConfig) + systemPrintln("Skipping - F9P already in Survey-In Base configuration"); + return (true); // No changes needed } + if (settings.fixedBase == true && gnssInBaseFixedMode()) + { + if (settings.debugGnssConfig) + systemPrintln("Skipping - F9P already in Fixed Base configuration"); + return (true); // No changes needed + } + + gnssConfigure(GNSS_CONFIG_FIX_RATE); + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); + + bool response = true; - // If our settings haven't changed, trust GNSS's settings - if (settings.gnssConfiguredRover) + if (settings.fixedBase == false) { - systemPrintln("Skipping ZED Rover configuration"); - return (true); + // If we are doing a Survey-In (temporary) style Base, change to Rover Mode so our location can settle + response &= _zed->setVal8(UBLOX_CFG_TMODE_MODE, 0); } - update(); // Regularly poll to get latest data + if (response == false) + systemPrintln("Base config fail"); + + return (response); +} +//---------------------------------------- +// Configure specific aspects of the receiver for NTP mode +//---------------------------------------- +bool GNSS_ZED::configureNtpMode() +{ bool success = false; + + // This is only called by STATE_NTPSERVER_NOT_STARTED + // I guess it is OK to always do the configuration? + // stateUpdate clear the Base and Rover configuration flags + // to ensure the configuration is re-applied when we exit this mode + + update(); // Regularly poll to get latest data + int tryNo = -1; // Try up to MAX_SET_MESSAGES_RETRIES times to configure the GNSS @@ -795,68 +552,90 @@ bool GNSS_ZED::configureRover() { bool response = true; - // Set output rate + // In NTP mode we force 1Hz response &= _zed->newCfgValset(VAL_LAYER_ALL); - response &= _zed->addCfgValset(UBLOX_CFG_RATE_MEAS, settings.measurementRateMs); - response &= _zed->addCfgValset(UBLOX_CFG_RATE_NAV, settings.navigationRate); + response &= _zed->addCfgValset(UBLOX_CFG_RATE_MEAS, 1000); + response &= _zed->addCfgValset(UBLOX_CFG_RATE_NAV, 1); // Survey mode is only available on ZED-F9P modules - if (commandSupported(UBLOX_CFG_TMODE_MODE)) - response &= _zed->addCfgValset(UBLOX_CFG_TMODE_MODE, 0); // Disable survey-in mode + response &= _zed->addCfgValset(UBLOX_CFG_TMODE_MODE, 0); // Disable survey-in mode - response &= _zed->addCfgValset(UBLOX_CFG_NAVSPG_DYNMODEL, (dynModel)settings.dynamicModel); // Set dynamic model + // Set dynamic model to stationary + response &= _zed->addCfgValset(UBLOX_CFG_NAVSPG_DYNMODEL, DYN_MODEL_STATIONARY); // Set dynamic model - // RTCM is only available on ZED-F9P modules - // - // For most RTK products, the GNSS is interfaced via both I2C and UART1. Configuration and PVT/HPPOS messages - // are configured over I2C. Any messages that need to be logged are output on UART1, and received by this code - // using serialGNSS-> So in Rover mode, we want to disable any RTCM messages on I2C (and USB and UART2). - // - // But, on the Reference Station, the GNSS is interfaced via SPI. It has no access to I2C and UART1. So for that - // product - in Rover mode - we want to leave any RTCM messages enabled on SPI so they can be logged if desired. + // Set time pulse to 1Hz (100:900) + response &= _zed->addCfgValset(UBLOX_CFG_TP_PULSE_DEF, 0); // Time pulse definition is a period (in us) + response &= _zed->addCfgValset(UBLOX_CFG_TP_PULSE_LENGTH_DEF, 1); // Define timepulse by length (not ratio) + response &= + _zed->addCfgValset(UBLOX_CFG_TP_USE_LOCKED_TP1, + 1); // Use CFG-TP-PERIOD_LOCK_TP1 and CFG-TP-LEN_LOCK_TP1 as soon as GNSS time is valid + response &= _zed->addCfgValset(UBLOX_CFG_TP_TP1_ENA, 1); // Enable timepulse + response &= _zed->addCfgValset(UBLOX_CFG_TP_POL_TP1, 1); // 1 = rising edge - // Find first RTCM record in ubxMessage array - int firstRTCMRecord = getMessageNumberByName("RTCM_1005"); + // While the module is _locking_ to GNSS time, turn off pulse + response &= _zed->addCfgValset(UBLOX_CFG_TP_PERIOD_TP1, 1000000); // Set the period between pulses in us + response &= _zed->addCfgValset(UBLOX_CFG_TP_LEN_TP1, 0); // Set the pulse length in us - // Set RTCM messages to user's settings - for (int x = 0; x < MAX_UBX_MSG_RTCM; x++) - response &= _zed->addCfgValset(ubxMessages[firstRTCMRecord + x].msgConfigKey - 1, - settings.ubxMessageRates[firstRTCMRecord + x]); // UBLOX_CFG UART1 - 1 = I2C + // When the module is _locked_ to GNSS time, make it generate 1Hz (100ms high, 900ms low) + response &= _zed->addCfgValset(UBLOX_CFG_TP_PERIOD_LOCK_TP1, 1000000); // Set the period between pulses is us + response &= _zed->addCfgValset(UBLOX_CFG_TP_LEN_LOCK_TP1, 100000); // Set the pulse length in us - // Set RTCM messages to user's settings - for (int x = 0; x < MAX_UBX_MSG_RTCM; x++) - { - response &= - _zed->addCfgValset(ubxMessages[firstRTCMRecord + x].msgConfigKey + 1, - settings.ubxMessageRates[firstRTCMRecord + x]); // UBLOX_CFG UART1 + 1 = UART2 - response &= _zed->addCfgValset(ubxMessages[firstRTCMRecord + x].msgConfigKey + 2, - settings.ubxMessageRates[firstRTCMRecord + x]); // UBLOX_CFG UART1 + 2 = USB - } + // Ensure pulse is aligned to top-of-second. This is the default. Set it here just to make sure. + response &= _zed->addCfgValset(UBLOX_CFG_TP_ALIGN_TO_TOW_TP1, 1); - response &= _zed->addCfgValset(UBLOX_CFG_NMEA_MAINTALKERID, - 3); // Return talker ID to GNGGA after NTRIP Client set to GPGGA + // Set the time grid to UTC. This is the default. Set it here just to make sure. + response &= _zed->addCfgValset(UBLOX_CFG_TP_TIMEGRID_TP1, 0); // 0=UTC; 1=GPS - response &= _zed->addCfgValset(UBLOX_CFG_NMEA_HIGHPREC, 1); // Enable high precision NMEA - response &= _zed->addCfgValset(UBLOX_CFG_NMEA_SVNUMBERING, 1); // Enable extended satellite numbering + // Sync to GNSS. This is the default. Set it here just to make sure. + response &= _zed->addCfgValset(UBLOX_CFG_TP_SYNC_GNSS_TP1, 1); response &= _zed->addCfgValset(UBLOX_CFG_NAVSPG_INFIL_MINELEV, settings.minElev); // Set minimum elevation - response &= _zed->sendCfgValset(); // Closing + // Ensure PVT, HPPOSLLH and TP messages are being output at 1Hz on the correct port + response &= _zed->addCfgValset(UBLOX_CFG_MSGOUT_UBX_NAV_PVT_I2C, 1); + response &= _zed->addCfgValset(UBLOX_CFG_MSGOUT_UBX_NAV_HPPOSLLH_I2C, 1); + response &= _zed->addCfgValset(UBLOX_CFG_MSGOUT_UBX_TIM_TP_I2C, 1); + + response &= _zed->sendCfgValset(); // Closing value if (response) success = true; } if (!success) - systemPrintln("Rover config fail"); - - settings.gnssConfiguredRover = success; + systemPrintln("NTP config fail"); // The configuration should be saved to RAM+BBR+FLASH. No need to saveConfiguration here. return (success); } +//---------------------------------------- +// Configure specific aspects of the receiver for rover mode +//---------------------------------------- +bool GNSS_ZED::configureRover() +{ + if (gnssInRoverMode()) + { + if (settings.debugGnssConfig) + systemPrintln("Skipping F9P Rover configuration"); + return (true); // No changes needed + } + + bool response = true; + + gnssConfigure(GNSS_CONFIG_FIX_RATE); + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); + + response &= _zed->setVal8(UBLOX_CFG_TMODE_MODE, 0); // Switch to Rover mode + + if (response == false) + systemPrintln("Rover config fail"); + + return (response); +} + //---------------------------------------- // Responds with the messages supported on this platform // Inputs: @@ -907,25 +686,6 @@ void GNSS_ZED::debuggingEnable() _zed->enableDebugging(Serial, true); } -//---------------------------------------- -void GNSS_ZED::enableGgaForNtrip() -{ - if (online.gnss) - { - // Set the Main Talker ID to "GP". The NMEA GGA messages will be GPGGA instead of GNGGA - _zed->setVal8(UBLOX_CFG_NMEA_MAINTALKERID, 1, VAL_LAYER_ALL); - _zed->setNMEAGPGGAcallbackPtr(&zedPushGPGGA); // Set up the callback for GPGGA - - float measurementFrequency = (1000.0 / settings.measurementRateMs) / settings.navigationRate; - if (measurementFrequency < 0.2) - measurementFrequency = 0.2; // 0.2Hz * 5 = 1 measurement every 5 seconds - if (settings.debugGnss) - systemPrintf("Adjusting GGA setting to %f\r\n", measurementFrequency); - _zed->setVal8(UBLOX_CFG_MSGOUT_NMEA_ID_GGA_I2C, measurementFrequency, - VAL_LAYER_ALL); // Enable GGA over I2C. Tell the module to output GGA every second - } -} - //---------------------------------------- // Restore the GNSS to the factory settings //---------------------------------------- @@ -975,9 +735,13 @@ bool GNSS_ZED::fixedBaseStart() bool response = true; if (online.gnss == false) - { - systemPrintln("GNSS not online"); return (false); + + if (gnssInBaseFixedMode()) + { + if (settings.debugGnssConfig) + systemPrintln("Skipping - F9P is already in Fixed Base configuration"); + return (true); // No changes needed } if (settings.fixedBaseCoordinateType == COORD_TYPE_ECEF) @@ -999,7 +763,7 @@ bool GNSS_ZED::fixedBaseStart() //-1280208.308,-4716803.847,4086665.811 is SparkFun HQ so... response &= _zed->newCfgValset(VAL_LAYER_ALL); - response &= _zed->addCfgValset(UBLOX_CFG_TMODE_MODE, 2); // Fixed + response &= _zed->addCfgValset(UBLOX_CFG_TMODE_MODE, 2); // Switch to Fixed Base mode response &= _zed->addCfgValset(UBLOX_CFG_TMODE_POS_TYPE, 0); // Position in ECEF response &= _zed->addCfgValset(UBLOX_CFG_TMODE_ECEF_X, majorEcefX); response &= _zed->addCfgValset(UBLOX_CFG_TMODE_ECEF_X_HP, minorEcefX); @@ -1039,7 +803,7 @@ bool GNSS_ZED::fixedBaseStart() // systemPrintf("minor (should be 84): %ld\r\n", minorAlt); response &= _zed->newCfgValset(VAL_LAYER_ALL); - response &= _zed->addCfgValset(UBLOX_CFG_TMODE_MODE, 2); // Fixed + response &= _zed->addCfgValset(UBLOX_CFG_TMODE_MODE, 2); // Switch to Fixed Base mode response &= _zed->addCfgValset(UBLOX_CFG_TMODE_POS_TYPE, 1); // Position in LLH response &= _zed->addCfgValset(UBLOX_CFG_TMODE_LAT, majorLat); response &= _zed->addCfgValset(UBLOX_CFG_TMODE_LAT_HP, minorLat); @@ -1278,6 +1042,22 @@ uint8_t GNSS_ZED::getMinute() return (_minute); } +//---------------------------------------- +// Returns the current mode +// 0 - Rover, 1 - Base Survey-In, 2 - Base Fixed +//---------------------------------------- +uint8_t GNSS_ZED::getMode() +{ + if (online.gnss) + { + // Survey mode is only available on ZED-F9P modules + if (commandSupported(UBLOX_CFG_TMODE_MODE)) + return (_zed->getVal8(UBLOX_CFG_TMODE_MODE)); + } + + return (0); // Rover +} + //---------------------------------------- // Returns month number or zero if not online //---------------------------------------- @@ -1431,6 +1211,39 @@ uint16_t GNSS_ZED::getYear() return (_year); } +//---------------------------------------- +// Returns true if the GNSS receiver is in Base Fixed mode +//---------------------------------------- +bool GNSS_ZED::gnssInBaseFixedMode() +{ + if (getMode() == 2) // 0 - Rover, 1 - Base Survey-In, 2 - Base Fixed + return (true); + + return (false); +} + +//---------------------------------------- +// Returns true if the GNSS receiver is in Base Survey-in mode +//---------------------------------------- +bool GNSS_ZED::gnssInBaseSurveyInMode() +{ + if (getMode() == 1) // 0 - Rover, 1 - Base Survey-In, 2 - Base Fixed + return (true); + + return (false); +} + +//---------------------------------------- +// Returns true if the GNSS receiver is in Rover mode +//---------------------------------------- +bool GNSS_ZED::gnssInRoverMode() +{ + if (getMode() == 0) // 0 - Rover, 1 - Base Survey-In, 2 - Base Fixed + return (true); + + return (false); +} + //---------------------------------------- // Returns true if the antenna is shorted //---------------------------------------- @@ -1856,6 +1669,8 @@ void GNSS_ZED::menuMessages() setMessageRateByName("NMEA_RMC", 1); systemPrintln("Reset to Surveying Defaults (NMEAx5)"); + + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings } else if (incoming == 11) { @@ -1875,16 +1690,22 @@ void GNSS_ZED::menuMessages() setMessageRateByName("RXM_RAWX", 1); setMessageRateByName("RXM_SFRBX", 1); systemPrintln("Reset to PPP Logging Defaults (NMEAx5 + RXMx2)"); + + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings } else if (incoming == 12) { setGNSSMessageRates(settings.ubxMessageRates, 0); // Turn off all messages systemPrintln("All messages disabled"); + + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings } else if (incoming == 13) { setGNSSMessageRates(settings.ubxMessageRates, 1); // Turn on all messages to report once per fix systemPrintln("All messages enabled"); + + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) break; @@ -1895,15 +1716,6 @@ void GNSS_ZED::menuMessages() } clearBuffer(); // Empty buffer of any newline chars - - // Make sure the appropriate messages are enabled - bool response = setMessagesNMEA(); // Does a complete open/closed val set - if (response == false) - systemPrintf("menuMessages: Failed to enable messages - after %d tries", MAX_SET_MESSAGES_RETRIES); - else - systemPrintln("menuMessages: Messages successfully enabled"); - - setLoggingType(); // Update Standard, PPP, or custom for icon selection } // Given a sub type (ie "RTCM", "NMEA") present menu showing messages with this subtype @@ -1950,7 +1762,11 @@ void GNSS_ZED::menuMessagesSubtype(uint8_t *localMessageRate, const char *messag int msgNumber = (incoming - 1) + startOfBlock; if (messageSupported(msgNumber + rtcmOffset) == true) + { inputMessageRate(localMessageRate[msgNumber], msgNumber + rtcmOffset); + + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings + } else printUnknown(incoming); } @@ -1984,6 +1800,32 @@ int GNSS_ZED::pushRawData(uint8_t *dataToSend, int dataLength) return (0); } +// These are settings used inside the library, not setting on the GNSS receiver so they are not saved to the receiver's +// NVM We have to re-enable them each time +bool GNSS_ZED::registerCallbacks() +{ + bool response = true; + + // Enable automatic NAV PVT messages with callback to storePVTdata + response &= _zed->setAutoPVTcallbackPtr(&storePVTdata, VAL_LAYER_ALL); + + // Enable automatic NAV HPPOSLLH messages with callback to storeHPdata + response &= _zed->setAutoHPPOSLLHcallbackPtr(&storeHPdata, VAL_LAYER_ALL); + + // Enable automatic TIM TP messages with callback to storeTIMTPdata + if (present.timePulseInterrupt) + response &= _zed->setAutoTIMTPcallbackPtr(&storeTIMTPdata, VAL_LAYER_ALL); + + // Enable automatic MON HW messages with callback to storeMONHWdata + if (present.antennaShortOpen) + response &= _zed->setAutoMONHWcallbackPtr(&storeMONHWdata, VAL_LAYER_ALL); + + // Add a callback for UBX-MON-COMMS + response &= _zed->setAutoMONCOMMScallbackPtr(&storeMONCOMMSdata, VAL_LAYER_ALL); + + return (response); +} + //---------------------------------------- // Hardware or software reset the GNSS receiver // Hotstart GNSS to try to get RTK lock @@ -2221,7 +2063,7 @@ bool GNSS_ZED::setElevation(uint8_t elevationDegrees) bool GNSS_ZED::setHighAccuracyService(bool enableGalileoHas) { // Not yet supported on this platform - return (false); + return (true); // Return true to clear gnssConfigure test } //---------------------------------------- @@ -2282,14 +2124,16 @@ bool GNSS_ZED::setNmeaMessageRateByName(const char *msgName, uint8_t msgRate) //---------------------------------------- // Set the rate for all messages // The ZED has a lot more messages than just NMEA in ubxMessageRates[], but other platforms generally just have NMEA and -// RTCM There are many messages so split into batches. VALSET is limited to 64 max per batch Uses dummy newCfg and -// sendCfg values to be sure we open/close a complete set +// RTCM. There are many messages so split into batches. VALSET is limited to 64 per batch. Uses dummy newCfg and +// sendCfg values to be sure we open/close a complete set. //---------------------------------------- bool GNSS_ZED::setMessagesNMEA() { int maxRetries = MAX_SET_MESSAGES_RETRIES; - bool success = false; + bool gpggaEnabled = false; + + bool success = true; if (online.gnss) { @@ -2299,7 +2143,7 @@ bool GNSS_ZED::setMessagesNMEA() // This corrects occasional failures seen on the Reference Station where the GNSS is connected via SPI // instead of I2C and UART1. I believe the SETVAL ACK is occasionally missed due to the level of messages being // processed. - while ((++tryNo < maxRetries) && !success) + while ((++tryNo < maxRetries) && success == false) { bool response = true; int messageNumber = 0; @@ -2314,7 +2158,17 @@ bool GNSS_ZED::setMessagesNMEA() { uint8_t rate = settings.ubxMessageRates[messageNumber]; - response &= _zed->addCfgValset(ubxMessages[messageNumber].msgConfigKey, rate); + // Set NMEA messages to user's settings on UART1 interface + response &= _zed->addCfgValset(ubxMessages[messageNumber].msgConfigKey, + rate); // msgConfigKey defaults to UART1 + + // Mark messages needed for other services (NTRIP Client, PointPerfect, etc) as enabled if rate + // > 0 + if (settings.ubxMessageRates[messageNumber] > 0) + { + if (strcmp(ubxMessages[messageNumber].msgTextName, "NMEA_GGA") == 0) + gpggaEnabled = true; + } } messageNumber++; } while (((messageNumber % 43) < 42) && @@ -2334,6 +2188,29 @@ bool GNSS_ZED::setMessagesNMEA() success = true; } } + + // Enable GGA if needed for other services + if (gpggaEnabled == false) + { + // Enable GGA for NTRIP + if (settings.enableNtripClient == true && settings.ntripClient_TransmitGGA == true) + { + float measurementFrequency = (1000.0 / settings.measurementRateMs) / settings.navigationRate; + if (measurementFrequency < 0.2) + measurementFrequency = 0.2; // 0.2Hz * 5 = 1 measurement every 5 seconds + if (settings.debugGnssConfig) + systemPrintf("Adjusting GGA setting to %f\r\n", measurementFrequency); + _zed->setVal8(UBLOX_CFG_MSGOUT_NMEA_ID_GGA_I2C, measurementFrequency, + VAL_LAYER_ALL); // Enable GGA over I2C. Tell the module to output GGA every second + } + } + + // Configure the callback for GGA as needed + if (settings.enableNtripClient == true && settings.ntripClient_TransmitGGA == true) + _zed->setNMEAGPGGAcallbackPtr(&zedPushGPGGA); + else + _zed->setNMEAGPGGAcallbackPtr(nullptr); + return (success); } @@ -2342,8 +2219,46 @@ bool GNSS_ZED::setMessagesNMEA() //---------------------------------------- bool GNSS_ZED::setMessagesRTCMBase() { - // TODO - return (false); + // RTCM is only available on ZED-F9P modules + // + // For the RTK EVK, the GNSS is interfaced via both I2C and UART1. Configuration and PVT/HPPOS messages + // are configured over I2C. Any messages that need to be logged are output on UART1, and received by this code + // using serialGNSS->. In base mode the RTK device should output RTCM over all ports: + // (Primary) UART2 in case the RTK device is connected via radio to rover + // (Optional) I2C in case user wants the base to connect to WiFi and NTRIP Caster + // (Secondary) USB in case the RTK device is used as an NTRIP caster connected to SBC or other + // (Tertiary) UART1 in case RTK device is sending RTCM to a phone that is then NTRIP Caster + + // ubxMessageRatesBase is an array of ~12 uint8_ts + // ubxMessage is an array of ~80 messages + // We use firstRTCMRecord as an offset for the keys, but use x as the rate + // Find first RTCM record in ubxMessage array + int firstRTCMRecord = getMessageNumberByName("RTCM_1005"); + + bool response = true; + + response &= _zed->newCfgValset(VAL_LAYER_ALL); + + // VALSET is limited to 64 per batch + // Update RTCM message rates for all interfaces. This is 12 * 5 = 60 valsets. + for (int x = 0; x < MAX_UBX_MSG_RTCM; x++) + { + response &= _zed->addCfgValset(ubxMessages[firstRTCMRecord + x].msgConfigKey - 1, + settings.ubxMessageRatesBase[x]); // UBLOX_CFG UART1 - 1 = I2C + response &= _zed->addCfgValset(ubxMessages[firstRTCMRecord + x].msgConfigKey, + settings.ubxMessageRatesBase[x]); // UBLOX_CFG UART1 + response &= _zed->addCfgValset(ubxMessages[firstRTCMRecord + x].msgConfigKey + 1, + settings.ubxMessageRatesBase[x]); // UBLOX_CFG UART1 + 1 = UART2 + response &= _zed->addCfgValset(ubxMessages[firstRTCMRecord + x].msgConfigKey + 2, + settings.ubxMessageRatesBase[x]); // UBLOX_CFG UART1 + 2 = USB + // Disable messages on SPI + response &= _zed->addCfgValset(ubxMessages[firstRTCMRecord + x].msgConfigKey + 3, + 0); // UBLOX_CFG UART1 + 3 = SPI + } + + response &= _zed->sendCfgValset(); // Closing value + + return (response); } //---------------------------------------- @@ -2351,8 +2266,39 @@ bool GNSS_ZED::setMessagesRTCMBase() //---------------------------------------- bool GNSS_ZED::setMessagesRTCMRover() { - // TODO - return (false); + // RTCM is only available on ZED-F9P modules + // + // For the RTK EVK, the GNSS is interfaced via both I2C and UART1. Configuration and PVT/HPPOS messages + // are configured over I2C. Any messages that need to be logged are output on UART1, and received by using + // serialGNSS->. So in Rover mode, we want to disable any RTCM messages on I2C (and USB and UART2). + + // Find first RTCM record in ubxMessage array + int firstRTCMRecord = getMessageNumberByName("RTCM_1005"); + + bool response = true; + + response &= _zed->newCfgValset(VAL_LAYER_ALL); + + // VALSET is limited to 64 per batch + // Update RTCM message rates for all interfaces. This is 12 * 5 = 60 valsets. + for (int x = 0; x < MAX_UBX_MSG_RTCM; x++) + { + // Disable RTCM on all interfaces but UART1 + response &= _zed->addCfgValset(ubxMessages[firstRTCMRecord + x].msgConfigKey - 1, + 0); // UBLOX_CFG UART1 - 1 = I2C + response &= _zed->addCfgValset(ubxMessages[firstRTCMRecord + x].msgConfigKey, + settings.ubxMessageRates[firstRTCMRecord + x]); // UBLOX_CFG UART1 + response &= _zed->addCfgValset(ubxMessages[firstRTCMRecord + x].msgConfigKey + 1, + 0); // UBLOX_CFG UART1 + 1 = UART2 + response &= _zed->addCfgValset(ubxMessages[firstRTCMRecord + x].msgConfigKey + 2, + 0); // UBLOX_CFG UART1 + 2 = USB + response &= _zed->addCfgValset(ubxMessages[firstRTCMRecord + x].msgConfigKey + 3, + 0); // UBLOX_CFG UART1 + 3 = SPI + } + + response &= _zed->sendCfgValset(); // Closing + + return (response); } //---------------------------------------- @@ -2362,10 +2308,15 @@ bool GNSS_ZED::setMinCno(uint8_t cnoValue) { if (online.gnss) { - _zed->setVal8(UBLOX_CFG_NAVSPG_INFIL_MINCNO, cnoValue, VAL_LAYER_ALL); - return true; + if (commandSupported(UBLOX_CFG_NAVSPG_INFIL_MINCNO)) + { + if (_zed->addCfgValset(UBLOX_CFG_NAVSPG_INFIL_MINCNO, + settings.minCNO) == + false) // Set minimum satellite signal level for navigation - default 6 + return (false); + } } - return false; + return true; // If command not supported, we still need to return true to allow gnssConfigure() to complete } //---------------------------------------- @@ -2404,6 +2355,9 @@ bool GNSS_ZED::setRate(double secondsBetweenSolutions) if (online.gnss == false) return (false); + if (gnss->gnssInBaseSurveyInMode() || gnss->gnssInBaseFixedMode()) + secondsBetweenSolutions = 1; // In Base mode we force 1Hz + // If we have more than an hour between readings, increase mesaurementRate to near max of 65,535 if (secondsBetweenSolutions > 3600.0) { @@ -2466,27 +2420,13 @@ bool GNSS_ZED::setRate(double secondsBetweenSolutions) return (true); } -//---------------------------------------- -bool GNSS_ZED::setTalkerGNGGA() -{ - if (online.gnss) - { - bool success = true; - success &= _zed->setVal8(UBLOX_CFG_NMEA_MAINTALKERID, 3, - VAL_LAYER_ALL); // Return talker ID to GNGGA after NTRIP Client set to GPGGA - success &= _zed->setNMEAGPGGAcallbackPtr(nullptr); // Remove callback - return success; - } - return false; -} - //---------------------------------------- // Enable/disable any output needed for tilt compensation //---------------------------------------- bool GNSS_ZED::setTilt() { // Not yet available on this platform - return false; + return true; } //---------------------------------------- @@ -2567,8 +2507,8 @@ void GNSS_ZED::storePVTdataRadio(UBX_NAV_PVT_data_t *ubxDataStruct) _millisecond = ceil((ubxDataStruct->iTOW % 1000) / 10.0); // Limit to first two digits _satellitesInView = ubxDataStruct->numSV; - _fixType = ubxDataStruct->fixType; // 0 = no fix, 1 = dead reckoning only, 2 = 2D-fix, 3 = 3D-fix, 4 = GNSS + dead - // reckoning combined, 5 = time only fix + _fixType = ubxDataStruct->fixType; // 0 = no fix, 1 = dead reckoning only, 2 = 2D-fix, 3 = 3D-fix, 4 = GNSS + + // dead reckoning combined, 5 = time only fix _carrierSolution = ubxDataStruct->flags.bits.carrSoln; _validDate = ubxDataStruct->valid.bits.validDate; @@ -2709,6 +2649,13 @@ bool GNSS_ZED::surveyInStart() if (online.gnss == false) return (false); + if (gnssInBaseSurveyInMode()) + { + if (settings.debugGnssConfig) + systemPrintln("Skipping F9P Survey-In Base - already running"); + return (true); // No changes needed + } + _zed->setVal8(UBLOX_CFG_TMODE_MODE, 0, VAL_LAYER_ALL); // Disable survey-in mode delay(100); diff --git a/Firmware/RTK_Everywhere/NVM.ino b/Firmware/RTK_Everywhere/NVM.ino index cb819c9e3..1a6f0c5a6 100644 --- a/Firmware/RTK_Everywhere/NVM.ino +++ b/Firmware/RTK_Everywhere/NVM.ino @@ -60,19 +60,15 @@ void loadSettings() // Temp store any variables from LFS that should override SD int resetCount = settings.resetCount; - bool gnssConfiguredOnce = settings.gnssConfiguredOnce; - bool gnssConfiguredRover = settings.gnssConfiguredRover; - bool gnssConfiguredBase = settings.gnssConfiguredBase; + uint32_t gnssConfigureRequest = settings.gnssConfigureRequest; loadSystemSettingsFromFileSD(settingsFileName); settings.resetCount = resetCount; // resetCount from LFS should override SD - // Trust gnssConfigured from LittleFS over SD. + // Trust gnssConfigureRequest from LittleFS over SD. // LittleFS may have been erased, SD could be stale. - settings.gnssConfiguredOnce = gnssConfiguredOnce; - settings.gnssConfiguredRover = gnssConfiguredRover; - settings.gnssConfiguredBase = gnssConfiguredBase; + settings.gnssConfigureRequest = gnssConfigureRequest; // Change empty profile name to 'Profile1' etc if (strlen(settings.profileName) == 0) @@ -340,13 +336,13 @@ void recordSystemSettingsToFile(File *settingsFile) break; case tCmnCnst: - break; // Nothing to do here. Let each GNSS add its settings + break; // Nothing to do here. Let each GNSS add its settings case tCmnRtNm: - break; // Nothing to do here. Let each GNSS add its settings + break; // Nothing to do here. Let each GNSS add its settings case tCnRtRtB: - break; // Nothing to do here. Let each GNSS add its settings + break; // Nothing to do here. Let each GNSS add its settings case tCnRtRtR: - break; // Nothing to do here. Let each GNSS add its settings + break; // Nothing to do here. Let each GNSS add its settings case tEspNowPr: { // Record ESP-NOW peer MAC addresses @@ -1744,29 +1740,26 @@ void loadProfileNumber() else { systemPrintln("profileNumber.txt not found"); - settings.gnssConfiguredOnce = false; // On the next boot, reapply all settings - settings.gnssConfiguredBase = false; - settings.gnssConfiguredRover = false; - recordProfileNumber(0); // Record profile + gnssConfigureDefaults(); // Set all bits in the request bitfield to cause the GNSS receiver to go through a + // full (re)configuration + recordProfileNumber(0); // Record profile } } else { systemPrintln("profileNumber.txt not found"); - settings.gnssConfiguredOnce = false; // On the next boot, reapply all settings - settings.gnssConfiguredBase = false; - settings.gnssConfiguredRover = false; - recordProfileNumber(0); // Record profile + gnssConfigureDefaults(); // Set all bits in the request bitfield to cause the GNSS receiver to go through a full + // (re)configuration + recordProfileNumber(0); // Record profile } // We have arbitrary limit of user profiles if (profileNumber >= MAX_PROFILE_COUNT) { systemPrintln("ProfileNumber invalid. Going to zero."); - settings.gnssConfiguredOnce = false; // On the next boot, reapply all settings - settings.gnssConfiguredBase = false; - settings.gnssConfiguredRover = false; - recordProfileNumber(0); // Record profile + gnssConfigureDefaults(); // Set all bits in the request bitfield to cause the GNSS receiver to go through a full + // (re)configuration + recordProfileNumber(0); // Record profile } systemPrintf("Using profile #%d\r\n", profileNumber); diff --git a/Firmware/RTK_Everywhere/States.ino b/Firmware/RTK_Everywhere/States.ino index 1347a18db..ff524a504 100644 --- a/Firmware/RTK_Everywhere/States.ino +++ b/Firmware/RTK_Everywhere/States.ino @@ -96,8 +96,7 @@ void stateUpdate() baseStatusLedOff(); - if(gnss->gnssInRoverMode() == false) - gnssConfigure(GNSS_CONFIG_ROVER); // Request reconfigure to rover mode + gnssConfigure(GNSS_CONFIG_ROVER); // Request reconfigure to rover mode setMuxport(settings.dataPortChannel); // Return mux to original channel @@ -458,9 +457,9 @@ void stateUpdate() parseIncomingSettings(); - settings.gnssConfiguredOnce = false; // On the next boot, reapply all settings - settings.gnssConfiguredBase = false; - settings.gnssConfiguredRover = false; + gnssConfigureDefaults(); // Set all bits in the request bitfield to cause the GNSS receiver to go + // through a full (re)configuration + recordSystemSettings(); // Record these settings to unit // Clear buffer @@ -570,8 +569,8 @@ void stateUpdate() if (tasksStartGnssUart() && ntpConfigureUbloxModule()) { settings.lastState = STATE_NTPSERVER_NOT_STARTED; // Record this state for next POR - settings.gnssConfiguredBase = false; // On the next boot, reapply all settings - settings.gnssConfiguredRover = false; + gnssConfigureDefaults(); // Set all bits in the request bitfield to cause the GNSS receiver to go + // through a full (re)configuration recordSystemSettings(); if (online.ethernetNTPServer) diff --git a/Firmware/RTK_Everywhere/Tilt.ino b/Firmware/RTK_Everywhere/Tilt.ino index 5a0f452c9..e129012f7 100644 --- a/Firmware/RTK_Everywhere/Tilt.ino +++ b/Firmware/RTK_Everywhere/Tilt.ino @@ -1066,7 +1066,7 @@ void tiltDetect() { present.imu_im19 = true; // Allow tiltUpdate() to run settings.detectedTilt = true; - settings.gnssConfiguredRover = false; // Update rover settings + gnssConfigure(GNSS_CONFIG_TILT); // Request receiver to use new settings break; } } diff --git a/Firmware/RTK_Everywhere/menuBase.ino b/Firmware/RTK_Everywhere/menuBase.ino index 3d03e4f43..24d399291 100644 --- a/Firmware/RTK_Everywhere/menuBase.ino +++ b/Firmware/RTK_Everywhere/menuBase.ino @@ -143,13 +143,19 @@ void menuBase() { settings.fixedBase ^= 1; - gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings + // Change GNSS receiver configuration if the receiver is in Base mode, otherwise, just change setting + // This prevents a user, while in Rover mode, but changing a Base setting, from entering Base mode + if (gnss->gnssInBaseSurveyInMode() || gnss->gnssInBaseFixedMode()) + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } else if (settings.fixedBase == true && incoming == 2) { settings.fixedBaseCoordinateType ^= 1; - gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings + // Change GNSS receiver configuration if the receiver is in Base mode, otherwise, just change setting + // This prevents a user, while in Rover mode, but changing a Base setting, from entering Base mode + if (gnss->gnssInBaseSurveyInMode() || gnss->gnssInBaseFixedMode()) + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } else if (settings.fixedBase == true && incoming == 3) @@ -179,7 +185,11 @@ void menuBase() { settings.fixedEcefZ = fixedEcefZ; - gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings + // Change GNSS receiver configuration if the receiver is in Base mode, otherwise, just + // change setting This prevents a user, while in Rover mode, but changing a Base setting, + // from entering Base mode + if (gnss->gnssInBaseSurveyInMode() || gnss->gnssInBaseFixedMode()) + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } } } @@ -223,7 +233,11 @@ void menuBase() { settings.fixedAltitude = fixedAltitude; - gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings + // Change GNSS receiver configuration if the receiver is in Base mode, + // otherwise, just change setting This prevents a user, while in Rover mode, but + // changing a Base setting, from entering Base mode + if (gnss->gnssInBaseSurveyInMode() || gnss->gnssInBaseFixedMode()) + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } } else @@ -246,7 +260,10 @@ void menuBase() if (getNewSetting("Enter the antenna height (a.k.a. pole length) in millimeters", -15000, 15000, &settings.antennaHeight_mm) == INPUT_RESPONSE_VALID) { - gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings + // Change GNSS receiver configuration if the receiver is in Base mode, otherwise, just change setting + // This prevents a user, while in Rover mode but changing a Base setting, from entering Base mode + if (gnss->gnssInBaseSurveyInMode() || gnss->gnssInBaseFixedMode()) + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings // TODO Does any other hardware need to be reconfigured after this setting change? Tilt sensor? } } @@ -258,6 +275,9 @@ void menuBase() "Torch/X2=116.5, Facet mosaic=68.5, EVK=42.0, Postcard=37.5, Flex=62.5", -200.0, 200.0, &settings.antennaPhaseCenter_mm) == INPUT_RESPONSE_VALID) { + // Change GNSS receiver configuration if the receiver is in Base mode, otherwise, just change setting + // This prevents a user, while in Rover mode but changing a Base setting, from entering Base mode + if (gnss->gnssInBaseSurveyInMode() || gnss->gnssInBaseFixedMode()) gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } } @@ -268,6 +288,9 @@ void menuBase() if (getNewSetting("Enter the number of seconds for survey-in observation time", 60, 60 * 10, &settings.observationSeconds) == INPUT_RESPONSE_VALID) { + // Change GNSS receiver configuration if the receiver is in Base mode, otherwise, just change setting + // This prevents a user, while in Rover mode but changing a Base setting, from entering Base mode + if (gnss->gnssInBaseSurveyInMode() || gnss->gnssInBaseFixedMode()) gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } } @@ -279,6 +302,9 @@ void menuBase() (double)maxObservationPositionAccuracy, &settings.observationPositionAccuracy) == INPUT_RESPONSE_VALID) { + // Change GNSS receiver configuration if the receiver is in Base mode, otherwise, just change setting + // This prevents a user, while in Rover mode but changing a Base setting, from entering Base mode + if (gnss->gnssInBaseSurveyInMode() || gnss->gnssInBaseFixedMode()) gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } } @@ -289,6 +315,9 @@ void menuBase() (double)maxSurveyInStartingAccuracy, &settings.surveyInStartingAccuracy) == INPUT_RESPONSE_VALID) { + // Change GNSS receiver configuration if the receiver is in Base mode, otherwise, just change setting + // This prevents a user, while in Rover mode but changing a Base setting, from entering Base mode + if (gnss->gnssInBaseSurveyInMode() || gnss->gnssInBaseFixedMode()) gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } } diff --git a/Firmware/RTK_Everywhere/menuMain.ino b/Firmware/RTK_Everywhere/menuMain.ino index fb6c72c61..5591eb7eb 100644 --- a/Firmware/RTK_Everywhere/menuMain.ino +++ b/Firmware/RTK_Everywhere/menuMain.ino @@ -273,7 +273,7 @@ void menuMain() // Re-enable GNSS debug once we exit config menus gnss->debuggingEnable(); } - + recordSystemSettings(); // Once all menus have exited, record the new settings to LittleFS and config file clearBuffer(); // Empty buffer of any newline chars @@ -450,9 +450,9 @@ void menuUserProfiles() // Change the active profile number, without unit reset void changeProfileNumber(byte newProfileNumber) { - settings.gnssConfiguredBase = false; // On the next boot, reapply all settings - settings.gnssConfiguredRover = false; - recordSystemSettings(); // Before switching, we need to record the current settings to LittleFS and SD + gnssConfigureDefaults(); // Set all bits in the request bitfield to cause the GNSS receiver to go through a full + // (re)configuration + recordSystemSettings(); // Before switching, we need to record the current settings to LittleFS and SD recordProfileNumber(newProfileNumber); profileNumber = newProfileNumber; @@ -565,8 +565,7 @@ BluetoothRadioType_e mmChangeBluetoothProtocol(BluetoothRadioType_e bluetoothUse // Restart Bluetooth radio if settings have changed void mmSetBluetoothProtocol(BluetoothRadioType_e bluetoothUserChoice, bool clearBtPairings) { - if ((bluetoothUserChoice != settings.bluetoothRadioType) - || (clearBtPairings != settings.clearBtPairings)) + if ((bluetoothUserChoice != settings.bluetoothRadioType) || (clearBtPairings != settings.clearBtPairings)) { bluetoothStop(); settings.bluetoothRadioType = bluetoothUserChoice; @@ -713,8 +712,8 @@ void menuRadio() { for (int x = 0; x < settings.espnowPeerCount; x++) espNowRemovePeer(settings.espnowPeers[x]); - - espNowStart(); //Restart ESP-NOW to enable broadcastMAC + + espNowStart(); // Restart ESP-NOW to enable broadcastMAC } settings.espnowPeerCount = 0; systemPrintln("Radios forgotten"); diff --git a/Firmware/RTK_Everywhere/settings.h b/Firmware/RTK_Everywhere/settings.h index a9220d695..7824e4bad 100644 --- a/Firmware/RTK_Everywhere/settings.h +++ b/Firmware/RTK_Everywhere/settings.h @@ -748,13 +748,6 @@ struct Settings uint16_t navigationRate = 1; // Ratio between number of measurements and navigation solutions. Default 1 for 4Hz (with measurementRate). - // Signatures to indicate how the GNSS is configured (Once, Base, Rover, etc.) - // Bit 0 indicates if the GNSS has been configured previously. - // Bits 1 onwards record the state of critical settings. - // Configuration is reapplied if any of those critical settings have changed - bool gnssConfiguredOnce = false; - bool gnssConfiguredBase = false; - bool gnssConfiguredRover = false; // GNSS UART uint16_t serialGNSSRxFullThreshold = 50; // RX FIFO full interrupt. Max of ~128. See pinUART2Task(). @@ -1451,9 +1444,6 @@ const RTK_Settings_Entry rtkSettingsEntries[] = { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.enablePrintPosition, "enablePrintPosition", nullptr, }, { 0, 1, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _uint16_t, 0, & settings.measurementRateMs, "measurementRateMs", nullptr, }, { 0, 1, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _uint16_t, 0, & settings.navigationRate, "navigationRate", nullptr, }, - { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.gnssConfiguredOnce, "gnssConfiguredOnce", nullptr, }, - { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.gnssConfiguredBase, "gnssConfiguredBase", nullptr, }, - { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.gnssConfiguredRover, "gnssConfiguredRover", nullptr, }, // Hardware { 1, 1, 0, 1, 1, 1, 0, 1, 0, NON, 0, _bool, 0, & settings.enableExternalHardwareEventLogging, "enableExternalHardwareEventLogging", nullptr, }, From 911eba451ce2c6b1e0009d4dc0895d185eadcff5 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Mon, 27 Oct 2025 16:26:04 -0600 Subject: [PATCH 45/68] Update display before calling lengthy GNSS configs --- Firmware/RTK_Everywhere/RTK_Everywhere.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Firmware/RTK_Everywhere/RTK_Everywhere.ino b/Firmware/RTK_Everywhere/RTK_Everywhere.ino index ad3d7d390..e3969b7b1 100644 --- a/Firmware/RTK_Everywhere/RTK_Everywhere.ino +++ b/Firmware/RTK_Everywhere/RTK_Everywhere.ino @@ -1464,9 +1464,6 @@ void loop() DMW_c("periodicDisplay"); updatePeriodicDisplay(); - DMW_c("gnssUpdate"); - gnssUpdate(); - DMW_c("stateUpdate"); stateUpdate(); @@ -1476,6 +1473,9 @@ void loop() DMW_c("displayUpdate"); displayUpdate(); + DMW_c("gnssUpdate"); + gnssUpdate(); + DMW_c("rtcUpdate"); rtcUpdate(); // Set system time to GNSS once we have fix From 9b9adf2bdfc9aa9feab483856900f7716434c254 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 28 Oct 2025 13:10:21 -0600 Subject: [PATCH 46/68] Remove navigationRate Only used on ZED and rarely. Should be calculated from measurementRateMs regardless. --- Firmware/RTK_Everywhere/GNSS_UM980.ino | 2 +- Firmware/RTK_Everywhere/GNSS_ZED.ino | 33 +++++++++++------------- Firmware/RTK_Everywhere/menuCommands.ino | 2 -- Firmware/RTK_Everywhere/menuGNSS.ino | 12 +++------ Firmware/RTK_Everywhere/settings.h | 4 --- 5 files changed, 19 insertions(+), 34 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index d59b69614..f9d3916d4 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -1846,7 +1846,7 @@ bool GNSS_UM980::setMultipathMitigation(bool enableMultipathMitigation) } //---------------------------------------- -// Given the number of seconds between desired solution reports, determine measurementRateMs and navigationRate +// Given the number of seconds between desired solution reports, determine measurementRateMs //---------------------------------------- bool GNSS_UM980::setRate(double secondsBetweenSolutions) { diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index 7ac636e5d..e4b0b0534 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -826,7 +826,7 @@ const float f9pMaxRateHz = 20.0; // 20Hz bool GNSS_ZED::fixRateIsAllowed(uint32_t fixRateMs) { - if (fixRateMs > (1000 / f9pMinRateHz) && fixRateMs < (1000 / f9pMaxRateHz)) + if (fixRateMs >= fixRateGetMinimumMs() && fixRateMs <= fixRateGetMaximumMs()) return (true); return (false); } @@ -834,13 +834,13 @@ bool GNSS_ZED::fixRateIsAllowed(uint32_t fixRateMs) // Return minimum in milliseconds uint32_t GNSS_ZED::fixRateGetMinimumMs() { - return (1000.0 / f9pMinRateHz); + return (1000.0 / f9pMaxRateHz); // Max Hz is min ms } // Return maximum in milliseconds uint32_t GNSS_ZED::fixRateGetMaximumMs() { - return (1000.0 / f9pMaxRateHz); + return (1000.0 / f9pMinRateHz); // Min Hz is max ms } //---------------------------------------- @@ -1119,7 +1119,7 @@ uint32_t GNSS_ZED::getRadioBaudRate() double GNSS_ZED::getRateS() { // Because we may be in base mode, do not get freq from module, use settings instead - float measurementFrequency = (1000.0 / settings.measurementRateMs) / settings.navigationRate; + float measurementFrequency = (1000.0 / settings.measurementRateMs); double measurementRateS = 1.0 / measurementFrequency; // 1 / 4Hz = 0.25s return (measurementRateS); @@ -1583,6 +1583,8 @@ void GNSS_ZED::menuConstellations() settings.ubxConstellations[ubxConstellationIDToIndex(SFE_UBLOX_GNSS_ID_GPS)].enabled = settings.ubxConstellations[incoming].enabled; } + + gnssConfigure(GNSS_CONFIG_CONSTELLATION); // Request receiver to use new settings } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) break; @@ -1592,9 +1594,6 @@ void GNSS_ZED::menuConstellations() printUnknown(incoming); } - // Apply current settings to module - setConstellations(); - clearBuffer(); // Empty buffer of any newline chars } @@ -1662,7 +1661,7 @@ void GNSS_ZED::menuMessages() setMessageRateByName("NMEA_GST", 1); // We want GSV NMEA to be reported at 1Hz to avoid swamping SPP connection - float measurementFrequency = (1000.0 / settings.measurementRateMs) / settings.navigationRate; + float measurementFrequency = (1000.0 / settings.measurementRateMs); if (measurementFrequency < 1.0) measurementFrequency = 1.0; setMessageRateByName("NMEA_GSV", measurementFrequency); // One report per second @@ -1680,7 +1679,7 @@ void GNSS_ZED::menuMessages() setMessageRateByName("NMEA_GST", 1); // We want GSV NMEA to be reported at 1Hz to avoid swamping SPP connection - float measurementFrequency = (1000.0 / settings.measurementRateMs) / settings.navigationRate; + float measurementFrequency = (1000.0 / settings.measurementRateMs); if (measurementFrequency < 1.0) measurementFrequency = 1.0; setMessageRateByName("NMEA_GSV", measurementFrequency); // One report per second @@ -2195,7 +2194,7 @@ bool GNSS_ZED::setMessagesNMEA() // Enable GGA for NTRIP if (settings.enableNtripClient == true && settings.ntripClient_TransmitGGA == true) { - float measurementFrequency = (1000.0 / settings.measurementRateMs) / settings.navigationRate; + float measurementFrequency = (1000.0 / settings.measurementRateMs); if (measurementFrequency < 0.2) measurementFrequency = 0.2; // 0.2Hz * 5 = 1 measurement every 5 seconds if (settings.debugGnssConfig) @@ -2310,7 +2309,7 @@ bool GNSS_ZED::setMinCno(uint8_t cnoValue) { if (commandSupported(UBLOX_CFG_NAVSPG_INFIL_MINCNO)) { - if (_zed->addCfgValset(UBLOX_CFG_NAVSPG_INFIL_MINCNO, + if (_zed->setVal8(UBLOX_CFG_NAVSPG_INFIL_MINCNO, settings.minCNO) == false) // Set minimum satellite signal level for navigation - default 6 return (false); @@ -2342,15 +2341,14 @@ bool GNSS_ZED::setMultipathMitigation(bool enableMultipathMitigation) } //---------------------------------------- -// Given the number of seconds between desired solution reports, determine measurementRateMs and navigationRate -// measurementRateS > 25 & <= 65535 -// navigationRate >= 1 && <= 127 +// Given the number of seconds between desired solution reports, determine measurementRateMs setting // We give preference to limiting a measurementRate to 30 or below due to reported problems with measRates above 30. //---------------------------------------- bool GNSS_ZED::setRate(double secondsBetweenSolutions) { - uint16_t measRate = 0; // Calculate these locally and then attempt to apply them to ZED at completion - uint16_t navRate = 0; + // Calculate these locally and then attempt to apply them to ZED at completion + uint16_t measRate = 0; // 25 < measRate <= 65535 + uint16_t navRate = 0; // 1 <= navRate <= 127 if (online.gnss == false) return (false); @@ -2408,8 +2406,7 @@ bool GNSS_ZED::setRate(double secondsBetweenSolutions) // If we successfully set rates, only then record to settings if (response) { - settings.measurementRateMs = measRate; - settings.navigationRate = navRate; + settings.measurementRateMs = secondsBetweenSolutions * 1000; } else { diff --git a/Firmware/RTK_Everywhere/menuCommands.ino b/Firmware/RTK_Everywhere/menuCommands.ino index 4006cc185..da967710b 100644 --- a/Firmware/RTK_Everywhere/menuCommands.ino +++ b/Firmware/RTK_Everywhere/menuCommands.ino @@ -1338,8 +1338,6 @@ SettingValueResponse updateSettingWithValue(bool inCommands, const char *setting knownSetting = true; } - // navigationRate is calculated using measurementRateHz - else if (strstr(settingName, "stationECEF") != nullptr) { replaceCharacter((char *)settingValueStr, ' ', ','); // Replace all ' ' with ',' before recording to file diff --git a/Firmware/RTK_Everywhere/menuGNSS.ino b/Firmware/RTK_Everywhere/menuGNSS.ino index ffa0c318f..4cb6d9295 100644 --- a/Firmware/RTK_Everywhere/menuGNSS.ino +++ b/Firmware/RTK_Everywhere/menuGNSS.ino @@ -175,7 +175,7 @@ void menuGNSS() { float rateHz = 0.0; float minRateHz = 1000.0 / gnss->fixRateGetMaximumMs(); // Convert ms to Hz - float maxRateHz = 1000.0 / gnss->fixRateGetMinimumMs(); //The minimum in milliseconds is the max in Hz + float maxRateHz = 1000.0 / gnss->fixRateGetMinimumMs(); // The minimum in milliseconds is the max in Hz if (getNewSetting("Enter GNSS measurement rate in Hz", minRateHz, maxRateHz, &rateHz) == INPUT_RESPONSE_VALID) @@ -185,9 +185,6 @@ void menuGNSS() { settings.measurementRateMs = requestedRateMs; gnssConfigure(GNSS_CONFIG_FIX_RATE); - // This will set settings.measurementRateMs, settings.navigationRate, and GSV message - // gnss->setRate(1.0 / rateHz); //TODO remove once all platforms are accounted for. Good: UM980, - // LG290P, } else systemPrintln("Error: Illegal rate for this platform"); @@ -202,16 +199,13 @@ void menuGNSS() if (getNewSetting("Enter GNSS measurement rate in seconds between measurements", minRateS, maxRateS, &requestedRateS) == INPUT_RESPONSE_VALID) { - if (gnss->fixRateIsAllowed(requestedRateS * 1000.0)) //Convert S to ms + if (gnss->fixRateIsAllowed(requestedRateS * 1000.0)) // Convert S to ms { settings.measurementRateMs = requestedRateS * 1000.0; gnssConfigure(GNSS_CONFIG_FIX_RATE); - // This will set settings.measurementRateMs, settings.navigationRate, and GSV message - // gnss->setRate(1.0 / rateHz); //TODO remove once all platforms are accounted for. Good: UM980, - // LG290P, } else - systemPrintln("Error: Illegal rate for this platform"); + systemPrintln("Error: Illegal rate for this platform"); } } else if (incoming == 3 && present.dynamicModel) diff --git a/Firmware/RTK_Everywhere/settings.h b/Firmware/RTK_Everywhere/settings.h index 7824e4bad..1cfcb4f02 100644 --- a/Firmware/RTK_Everywhere/settings.h +++ b/Firmware/RTK_Everywhere/settings.h @@ -745,9 +745,6 @@ struct Settings bool debugGnss = false; // Turn on to display GNSS library debug messages bool enablePrintPosition = false; uint16_t measurementRateMs = 250; // Elapsed ms between GNSS measurements. 25ms to 65535ms. Default 4Hz. - uint16_t navigationRate = - 1; // Ratio between number of measurements and navigation solutions. Default 1 for 4Hz (with measurementRate). - // GNSS UART uint16_t serialGNSSRxFullThreshold = 50; // RX FIFO full interrupt. Max of ~128. See pinUART2Task(). @@ -1443,7 +1440,6 @@ const RTK_Settings_Entry rtkSettingsEntries[] = { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.debugGnssConfig, "debugGnssConfig", nullptr, }, { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.enablePrintPosition, "enablePrintPosition", nullptr, }, { 0, 1, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _uint16_t, 0, & settings.measurementRateMs, "measurementRateMs", nullptr, }, - { 0, 1, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _uint16_t, 0, & settings.navigationRate, "navigationRate", nullptr, }, // Hardware { 1, 1, 0, 1, 1, 1, 0, 1, 0, NON, 0, _bool, 0, & settings.enableExternalHardwareEventLogging, "enableExternalHardwareEventLogging", nullptr, }, From 9a624d7b834d923ac7572bea60cf77ebb0b4c1a1 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 28 Oct 2025 14:46:35 -0600 Subject: [PATCH 47/68] Rename minCno to minCN0. --- Firmware/RTK_Everywhere/AP-Config/index.html | 8 ++++---- Firmware/RTK_Everywhere/AP-Config/src/main.js | 6 +++--- Firmware/RTK_Everywhere/Begin.ino | 14 +++++++------- Firmware/RTK_Everywhere/GNSS.h | 4 ++-- Firmware/RTK_Everywhere/GNSS.ino | 10 +++++----- Firmware/RTK_Everywhere/GNSS_LG290P.h | 4 ++-- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 6 +++--- Firmware/RTK_Everywhere/GNSS_Mosaic.h | 2 +- Firmware/RTK_Everywhere/GNSS_Mosaic.ino | 8 ++++---- Firmware/RTK_Everywhere/GNSS_None.h | 2 +- Firmware/RTK_Everywhere/GNSS_UM980.h | 4 ++-- Firmware/RTK_Everywhere/GNSS_UM980.ino | 4 ++-- Firmware/RTK_Everywhere/GNSS_ZED.h | 2 +- Firmware/RTK_Everywhere/GNSS_ZED.ino | 6 +++--- Firmware/RTK_Everywhere/menuCommands.ino | 8 ++++---- Firmware/RTK_Everywhere/menuGNSS.ino | 8 ++++---- Firmware/RTK_Everywhere/menuMessages.ino | 6 +++--- Firmware/RTK_Everywhere/settings.h | 6 +++--- 18 files changed, 54 insertions(+), 54 deletions(-) diff --git a/Firmware/RTK_Everywhere/AP-Config/index.html b/Firmware/RTK_Everywhere/AP-Config/index.html index f6b381e36..af2222b31 100644 --- a/Firmware/RTK_Everywhere/AP-Config/index.html +++ b/Firmware/RTK_Everywhere/AP-Config/index.html @@ -297,17 +297,17 @@ -
+
-
diff --git a/Firmware/RTK_Everywhere/AP-Config/src/main.js b/Firmware/RTK_Everywhere/AP-Config/src/main.js index 2e98cde03..818ec6e2b 100644 --- a/Firmware/RTK_Everywhere/AP-Config/src/main.js +++ b/Firmware/RTK_Everywhere/AP-Config/src/main.js @@ -274,7 +274,7 @@ function parseIncoming(msg) { hide("dynamicModelDropdown"); //Not supported on LG290P hide("minElevConfig"); //Not supported on LG290P - hide("minCNOConfig"); //Not supported on LG290P + hide("minCN0Config"); //Not supported on LG290P ge("rtcmRateInfoText").setAttribute('data-bs-original-title', 'RTCM is transmitted by the base at a default of 1Hz for messages 1005, 1074, 1084, 1094, 1114, 1124, 1134. This can be lowered for radios with low bandwidth or tailored to transmit any/all RTCM messages. Limits: 0 to 20. Note: The measurement rate is overridden to 1Hz when in Base mode.'); @@ -342,7 +342,7 @@ function parseIncoming(msg) { hide("dynamicModelDropdown"); //Not supported on LG290P hide("minElevConfig"); //Not supported on LG290P - hide("minCNOConfig"); //Not supported on LG290P + hide("minCN0Config"); //Not supported on LG290P ge("rtcmRateInfoText").setAttribute('data-bs-original-title', 'RTCM is transmitted by the base at a default of 1Hz for messages 1005, 1074, 1084, 1094, 1124, and 0.1Hz for 1033. This can be lowered for radios with low bandwidth or tailored to transmit any/all RTCM messages. Limits: 0 to 20. Note: The measurement rate is overridden to 1Hz when in Base mode.'); @@ -840,7 +840,7 @@ function validateFields() { checkConstellations(); checkElementValue("minElev", 0, 90, "Must be between 0 and 90", "collapseGNSSConfig"); - checkElementValue("minCNO", 0, 90, "Must be between 0 and 90", "collapseGNSSConfig"); + checkElementValue("minCN0", 0, 90, "Must be between 0 and 90", "collapseGNSSConfig"); if (ge("enableNtripClient").checked == true) { checkElementString("ntripClientCasterHost", 1, 45, "Must be 1 to 45 characters", "collapseGNSSConfig"); diff --git a/Firmware/RTK_Everywhere/Begin.ino b/Firmware/RTK_Everywhere/Begin.ino index 6eebe0938..db5f07064 100644 --- a/Firmware/RTK_Everywhere/Begin.ino +++ b/Firmware/RTK_Everywhere/Begin.ino @@ -237,7 +237,7 @@ void beginBoard() present.needsExternalPpl = true; // Uses the PointPerfect Library present.galileoHasCapable = true; present.multipathMitigation = true; // UM980 has MPM, other platforms do not - present.minCno = true; + present.minCN0 = true; present.minElevation = true; present.dynamicModel = true; @@ -354,7 +354,7 @@ void beginBoard() present.display_i2c1 = true; present.display_type = DISPLAY_128x64; present.i2c1BusSpeed_400 = true; // Run display bus at higher speed - present.minCno = true; + present.minCN0 = true; present.minElevation = true; present.dynamicModel = true; @@ -479,7 +479,7 @@ void beginBoard() present.fastPowerOff = true; present.invertedFastPowerOff = true; present.gnss_to_uart = true; - present.minCno = true; + present.minCN0 = true; present.minElevation = true; present.dynamicModel = true; @@ -561,7 +561,7 @@ void beginBoard() present.fastPowerOff = true; present.invertedFastPowerOff = true; present.gnss_to_uart = true; - present.minCno = true; + present.minCN0 = true; present.minElevation = true; present.dynamicModel = true; @@ -660,7 +660,7 @@ void beginBoard() present.mosaicMicroSd; present.microSdCardDetectLow = true; // Except microSD is connected to mosaic... present.microSd is false - present.minCno = true; + present.minCN0 = true; present.minElevation = true; present.needsExternalPpl = true; // Uses the PointPerfect Library for L-Band present.dynamicModel = true; @@ -734,7 +734,7 @@ void beginBoard() // We can't enable here because we don't know if lg290pFirmwareVersion is >= v05 // present.minElevation = true; - // present.minCno = true; + // present.minCN0 = true; pin_I2C0_SDA = 7; pin_I2C0_SCL = 20; @@ -878,7 +878,7 @@ void beginBoard() // We can't enable GNSS features here because we don't know if lg290pFirmwareVersion is >= v05 // present.minElevation = true; - // present.minCno = true; + // present.minCN0 = true; pin_I2C0_SDA = 15; pin_I2C0_SCL = 4; diff --git a/Firmware/RTK_Everywhere/GNSS.h b/Firmware/RTK_Everywhere/GNSS.h index ed01830b6..66f9a3ff6 100644 --- a/Firmware/RTK_Everywhere/GNSS.h +++ b/Firmware/RTK_Everywhere/GNSS.h @@ -185,7 +185,7 @@ class GNSS virtual uint8_t getMillisecond(); // Get the minimum satellite signal level for navigation. - uint8_t getMinCno(); + uint8_t getMinCN0(); // Returns minutes or zero if not online virtual uint8_t getMinute(); @@ -361,7 +361,7 @@ class GNSS virtual bool setMessagesRTCMRover(); // Set the minimum satellite signal level for navigation. - virtual bool setMinCno(uint8_t cnoValue); + virtual bool setMinCN0(uint8_t cnoValue); // Set the dynamic model to use for RTK // Inputs: diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index eb53bfe57..0027420a0 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -72,9 +72,9 @@ extern unsigned long lastGGAPush; //---------------------------------------- // Get the minimum satellite signal level for navigation. //---------------------------------------- -uint8_t GNSS::getMinCno() +uint8_t GNSS::getMinCN0() { - return (settings.minCNO); + return (settings.minCN0); } //---------------------------------------- @@ -234,7 +234,7 @@ void gnssUpdate() if (gnssConfigureRequested(GNSS_CONFIG_CN0)) { - if (gnss->setMinCno(settings.minCNO) == true) + if (gnss->setMinCN0(settings.minCN0) == true) { gnssConfigureClear(GNSS_CONFIG_CN0); gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM @@ -571,7 +571,7 @@ void gnssDetectReceiverType() gnss = (GNSS *)new GNSS_LG290P(); present.gnss_lg290p = true; - present.minCno = true; + present.minCN0 = true; present.minElevation = true; present.needsExternalPpl = true; // Uses the PointPerfect Library @@ -583,7 +583,7 @@ void gnssDetectReceiverType() gnss = (GNSS *)new GNSS_MOSAIC(); present.gnss_mosaicX5 = true; - present.minCno = true; + present.minCN0 = true; present.minElevation = true; present.dynamicModel = true; present.mosaicMicroSd = true; diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.h b/Firmware/RTK_Everywhere/GNSS_LG290P.h index 9dcd19450..ed3adcce1 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.h +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.h @@ -100,7 +100,7 @@ class GNSS_LG290P : GNSS void menuMessagesSubtype(int *localMessageRate, const char *messageType); // Set the minimum satellite signal level for navigation. - bool setMinCno(uint8_t cnoValue); + bool setMinCN0(uint8_t cnoValue); // Given the name of a message, find it, and set the rate bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); @@ -260,7 +260,7 @@ class GNSS_LG290P : GNSS uint8_t getMillisecond(); // Get the minimum satellite signal level for navigation. - uint8_t getMinCno(); + uint8_t getMinCN0(); // Returns minutes or zero if not online uint8_t getMinute(); diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index 128944bc1..495e46e82 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -144,7 +144,7 @@ void GNSS_LG290P::begin() { // Supported starting in v05 present.minElevation = true; - present.minCno = true; + present.minCN0 = true; } printModuleInfo(); @@ -1453,7 +1453,7 @@ void GNSS_LG290P::menuMessages() // Override settings for PPP logging settings.minElev = 15; // Degrees gnssConfigure(GNSS_CONFIG_ELEVATION); - settings.minCNO = 30; // dBHz + settings.minCN0 = 30; // dBHz gnssConfigure(GNSS_CONFIG_CN0); settings.measurementRateMs = 1000; // Go to 1 Hz gnssConfigure(GNSS_CONFIG_FIX_RATE); @@ -1914,7 +1914,7 @@ bool GNSS_LG290P::setHighAccuracyService(bool enableGalileoHas) //---------------------------------------- // Set the minimum satellite signal level for navigation. //---------------------------------------- -bool GNSS_LG290P::setMinCno(uint8_t cnoValue) +bool GNSS_LG290P::setMinCN0(uint8_t cnoValue) { // Present on >= v05 if (lg290pFirmwareVersion >= 5) diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.h b/Firmware/RTK_Everywhere/GNSS_Mosaic.h index 2ea349c6e..39ffde96b 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.h +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.h @@ -527,7 +527,7 @@ class GNSS_MOSAIC : GNSS bool configure(); // Set the minimum satellite signal level for navigation. - bool setMinCno(uint8_t cnoValue); + bool setMinCN0(uint8_t cnoValue); public: // Allow access from parser routines diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino index f118a0437..974a0bd11 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino @@ -463,7 +463,7 @@ bool GNSS_MOSAIC::configureBase() response &= setElevation(settings.minElev); - response &= setMinCno(settings.minCNO); + response &= setMinCN0(settings.minCN0); response &= setConstellations(); @@ -585,7 +585,7 @@ bool GNSS_MOSAIC::configureOnce() { /* Configure COM1 - Set minCNO + Set minCN0 Set elevationAngle Set Constellations @@ -690,7 +690,7 @@ bool GNSS_MOSAIC::configureRover() response &= setElevation(settings.minElev); // Set by menuGNSS which calls gnss->setElevation - response &= setMinCno(settings.minCNO); + response &= setMinCN0(settings.minCN0); response &= setConstellations(); @@ -2183,7 +2183,7 @@ bool GNSS_MOSAIC::setHighAccuracyService(bool enableGalileoHas) //---------------------------------------- // Set the minimum satellite signal level for navigation. //---------------------------------------- -bool GNSS_MOSAIC::setMinCno(uint8_t cnoValue) +bool GNSS_MOSAIC::setMinCN0(uint8_t cnoValue) { if (cnoValue > 60) cnoValue = 60; diff --git a/Firmware/RTK_Everywhere/GNSS_None.h b/Firmware/RTK_Everywhere/GNSS_None.h index 0bd07a56d..6cb7e8513 100644 --- a/Firmware/RTK_Everywhere/GNSS_None.h +++ b/Firmware/RTK_Everywhere/GNSS_None.h @@ -11,7 +11,7 @@ class GNSS_None : public GNSS { protected: // Set the minimum satellite signal level for navigation. - bool setMinCno(uint8_t cnoValue) + bool setMinCN0(uint8_t cnoValue) { return false; } diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.h b/Firmware/RTK_Everywhere/GNSS_UM980.h index bc24a48c5..a8d4532b7 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.h +++ b/Firmware/RTK_Everywhere/GNSS_UM980.h @@ -134,7 +134,7 @@ class GNSS_UM980 : GNSS bool setHighAccuracyService(bool enableGalileoHas); // Set the minimum satellite signal level for navigation. - bool setMinCno(uint8_t cnoValue); + bool setMinCN0(uint8_t cnoValue); public: // Constructor @@ -272,7 +272,7 @@ class GNSS_UM980 : GNSS uint8_t getMillisecond(); // Get the minimum satellite signal level for navigation. - uint8_t getMinCno(); + uint8_t getMinCN0(); // Returns minutes or zero if not online uint8_t getMinute(); diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index f9d3916d4..da0e24de0 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -192,7 +192,7 @@ bool GNSS_UM980::configureOnce() UM980 COM1 - Connected to ESP32 through switches. Not used. UM980 COM2 - To IMU. UM980 COM3 - BT, config and LoRa Radio. Configured for 115200 from begin(). - Set minCNO + Set minCN0 Set elevationAngle Set Constellations Set messages @@ -1568,7 +1568,7 @@ bool GNSS_UM980::setHighAccuracyService(bool enableGalileoHas) //---------------------------------------- // Set the minimum satellite signal level (carrier to noise ratio) for navigation. //---------------------------------------- -bool GNSS_UM980::setMinCno(uint8_t cn0Value) +bool GNSS_UM980::setMinCN0(uint8_t cn0Value) { if (online.gnss) { diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.h b/Firmware/RTK_Everywhere/GNSS_ZED.h index 39a329ae0..60e8cb7e3 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.h +++ b/Firmware/RTK_Everywhere/GNSS_ZED.h @@ -714,7 +714,7 @@ class GNSS_ZED : GNSS bool setMessageRateByName(const char *msgName, uint8_t msgRate); // Set the minimum satellite signal level for navigation. - bool setMinCno(uint8_t cnoValue); + bool setMinCN0(uint8_t cnoValue); // Set the NMEA messages bool setMessagesNMEA(); diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index e4b0b0534..20a4e5008 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -2303,14 +2303,14 @@ bool GNSS_ZED::setMessagesRTCMRover() //---------------------------------------- // Set the minimum satellite signal level for navigation. //---------------------------------------- -bool GNSS_ZED::setMinCno(uint8_t cnoValue) +bool GNSS_ZED::setMinCN0(uint8_t cnoValue) { if (online.gnss) { if (commandSupported(UBLOX_CFG_NAVSPG_INFIL_MINCNO)) { if (_zed->setVal8(UBLOX_CFG_NAVSPG_INFIL_MINCNO, - settings.minCNO) == + settings.minCN0) == false) // Set minimum satellite signal level for navigation - default 6 return (false); } @@ -2348,7 +2348,7 @@ bool GNSS_ZED::setRate(double secondsBetweenSolutions) { // Calculate these locally and then attempt to apply them to ZED at completion uint16_t measRate = 0; // 25 < measRate <= 65535 - uint16_t navRate = 0; // 1 <= navRate <= 127 + uint16_t navRate = 0; // 1 <= navRate <= 127 if (online.gnss == false) return (false); diff --git a/Firmware/RTK_Everywhere/menuCommands.ino b/Firmware/RTK_Everywhere/menuCommands.ino index da967710b..68ddb7040 100644 --- a/Firmware/RTK_Everywhere/menuCommands.ino +++ b/Firmware/RTK_Everywhere/menuCommands.ino @@ -1356,9 +1356,9 @@ SettingValueResponse updateSettingWithValue(bool inCommands, const char *setting systemPrintf("%s recorded\r\n", settingValueStr); knownSetting = true; } - else if (strcmp(settingName, "minCNO") == 0) + else if (strcmp(settingName, "minCN0") == 0) { - settings.minCNO = settingValue; + settings.minCN0 = settingValue; gnssConfigure(GNSS_CONFIG_CN0); // Request receiver to use new settings knownSetting = true; @@ -2206,7 +2206,7 @@ void createSettingsString(char *newSettings) stringRecord(newSettings, "udpOverWiFiStation", 0); // 1 = WiFi mode, 0 = AP // Single variables needed on Config page - stringRecord(newSettings, "minCNO", gnss->getMinCno()); + stringRecord(newSettings, "minCN0", gnss->getMinCN0()); stringRecord(newSettings, "enableRCFirmware", enableRCFirmware); // Add SD Characteristics @@ -3164,7 +3164,7 @@ SettingValueResponse getSettingValue(bool inCommands, const char *settingName, c "getNewFirmware", "measurementRateHz", "measurementRateSec", - "minCNO", + "minCN0", "nicknameECEF", "nicknameGeodetic", "resetProfile", diff --git a/Firmware/RTK_Everywhere/menuGNSS.ino b/Firmware/RTK_Everywhere/menuGNSS.ino index 4cb6d9295..644af575b 100644 --- a/Firmware/RTK_Everywhere/menuGNSS.ino +++ b/Firmware/RTK_Everywhere/menuGNSS.ino @@ -125,8 +125,8 @@ void menuGNSS() systemPrintf("5) Minimum elevation for a GNSS satellite to be used in fix (degrees): %d\r\n", settings.minElev); - if (present.minCno) - systemPrintf("6) Minimum satellite signal level for navigation (dBHz): %d\r\n", gnss->getMinCno()); + if (present.minCN0) + systemPrintf("6) Minimum satellite signal level for navigation (dBHz): %d\r\n", gnss->getMinCN0()); systemPrint("7) Toggle NTRIP Client: "); if (settings.enableNtripClient == true) @@ -297,10 +297,10 @@ void menuGNSS() gnssConfigure(GNSS_CONFIG_ELEVATION); // Request receiver to use new settings } } - else if (incoming == 6 && present.minCno) + else if (incoming == 6 && present.minCN0) { // mosaic-X5 is 60dBHz max. - if (getNewSetting("Enter minimum satellite signal level for navigation in dBHz", 0, 60, &settings.minCNO) == + if (getNewSetting("Enter minimum satellite signal level for navigation in dBHz", 0, 60, &settings.minCN0) == INPUT_RESPONSE_VALID) { gnssConfigure(GNSS_CONFIG_CN0); // Request receiver to use new settings diff --git a/Firmware/RTK_Everywhere/menuMessages.ino b/Firmware/RTK_Everywhere/menuMessages.ino index ef9ce8699..92aaced5a 100644 --- a/Firmware/RTK_Everywhere/menuMessages.ino +++ b/Firmware/RTK_Everywhere/menuMessages.ino @@ -862,19 +862,19 @@ void checkGNSSArrayDefaults() { if (present.gnss_um980) { - settings.minCNO = 10; // Default 10 dBHz + settings.minCN0 = 10; // Default 10 dBHz settings.surveyInStartingAccuracy = 2.0; // Default 2m settings.measurementRateMs = 500; // Default 2Hz. } else if (present.gnss_zedf9p) { - settings.minCNO = 6; // Default 6 dBHz + settings.minCN0 = 6; // Default 6 dBHz settings.surveyInStartingAccuracy = 1.0; // Default 1m settings.measurementRateMs = 250; // Default 4Hz. } else if (present.gnss_lg290p) { - // settings.minCNO = 10; // Not yet supported + // settings.minCN0 = 10; // Not yet supported settings.surveyInStartingAccuracy = 2.0; // Default 2m settings.measurementRateMs = 500; // Default 2Hz. } diff --git a/Firmware/RTK_Everywhere/settings.h b/Firmware/RTK_Everywhere/settings.h index 1cfcb4f02..b89201634 100644 --- a/Firmware/RTK_Everywhere/settings.h +++ b/Firmware/RTK_Everywhere/settings.h @@ -936,7 +936,7 @@ struct Settings // Rover operation uint8_t dynamicModel = 254; // Default will be applied by checkGNSSArrayDefaults bool enablePrintRoverAccuracy = true; - int16_t minCNO = 6; // Minimum satellite signal level for navigation. ZED-F9P default is 6 dBHz + int16_t minCN0 = 6; // Minimum satellite signal level for navigation. ZED-F9P default is 6 dBHz // Minimum elevation (in deg) for a GNSS satellite to be used in NAV // Note: we use 8-bit unsigned here, but some platforms (ZED, mosaic-X5) support negative elevation limits uint8_t minElev = 10; @@ -1649,7 +1649,7 @@ const RTK_Settings_Entry rtkSettingsEntries[] = // Rover operation { 1, 1, 0, 1, 1, 1, 1, 1, 0, ALL, 0, _uint8_t, 0, & settings.dynamicModel, "dynamicModel", nullptr, }, { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.enablePrintRoverAccuracy, "enablePrintRoverAccuracy", nullptr, }, - { 0, 1, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _int16_t, 0, & settings.minCNO, "minCNO", nullptr, }, // Not inWebConfig - createSettingsString gets from GNSS + { 0, 1, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _int16_t, 0, & settings.minCN0, "minCN0", nullptr, }, // Not inWebConfig - createSettingsString gets from GNSS { 1, 1, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _uint8_t, 0, & settings.minElev, "minElev", nullptr, }, // RTC (Real Time Clock) @@ -1971,7 +1971,7 @@ struct struct_present float antennaPhaseCenter_mm = 0.0; // Used to setup tilt compensation bool galileoHasCapable = false; // UM980 has HAS capabilities bool multipathMitigation = false; // UM980 has MPM, other platforms do not - bool minCno = false; // ZED, mosaic, UM980 have minCN0. LG290P does on version >= v5. + bool minCN0 = false; // ZED, mosaic, UM980 have minCN0. LG290P does on version >= v5. bool minElevation = false; // ZED, mosaic, UM980 have minElevation. LG290P does on versions >= v5. bool dynamicModel = false; // ZED, mosaic, UM980 have dynamic models. LG290P does not. bool gpioExpanderSwitches = false; // Used on Flex From b02e9d192905876ae841e5a5d79515296e132348 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 28 Oct 2025 14:47:17 -0600 Subject: [PATCH 48/68] Remove retries from setMessagesNMEA --- Firmware/RTK_Everywhere/GNSS.ino | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index 0027420a0..d7af1bc0a 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -2,7 +2,33 @@ GNSS.ino GNSS layer implementation -------------------------------------------------------------------------------*/ + + For any given GNSS receiver, the following functions need to be implemented: + * begin() - Start communication with the device and its library + * configure() - Runs once after a system wide factory reset. Any settings that need to be set but are not exposed to the user. + * configureRover() - Change mode to Rover. Request NMEA and RTCM changes as needed. + * configureBase() - Change mode to Base. Fixed/Temp are controlled in states.ino. Request NMEA and RTCM changes as needed. + * setBaudRateComm() - Set baud rate for connection between microcontroller and GNSS receiver + * setBaudRateData() - Set baud rate for connection to the GNSS UART connected to the connector labeled DATA + * setBaudRateRadio() - Set baud rate for connection to the GNSS UART connected to the connector labeled RADIO + * setRate() - Set the report rate of the GNSS receiver. May or may not drive NMEA/RTCM rates directly. + * setConstellations() - Set the constellations and bands for the GNSS receiver + * setElevation() - Set the degrees a GNSS satellite must be above the horizon in order to be used in location calculation + * setMinCN0() - Set dBHz a GNSS satellite's signal strength must be above in order to be used in location calculation + * setPPS() - Set the width, period, and polarity of the pulse-per-second signal + * setModel() - Set the model used when calculating a location + * setMessagesNMEA() - Set the NMEA messages output during Base or Rover mode + * setMessagesRTCMBase() - Set the RTCM messages output during Base mode + * setMessagesRTCMRover() - Set the RTCM messages output during Rover mode + * setHighAccuracyService() - Set the PPP/HAS E6 capabilities of the receiver + * setMultipathMitigation() - Set the multipath capabilities of the receiver + * setTilt() - Set the GNSS receiver's output to be compatible with a tilt sensor + * setCorrRadioExtPort() - Set corrections protocol(s) on the UART connected to the RADIO port + * saveConfiguration() - Save the current receiver's settings to the receiver's NVM + * reset() - Reset the receiver (through software or hardware) + * factoryReset() - Reset the receiver to factory settings + There are many more but these form the core of any configuration interface. + ------------------------------------------------------------------------------*/ // We may receive a command or the user may change a setting that needs to modify the configuration of the GNSS receiver // Because this can take time, we group all the changes together and re-configure the receiver once the user has exited From 5581a0c34b05cceeccc5c51aced71a7f76f6b41a Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 28 Oct 2025 14:47:52 -0600 Subject: [PATCH 49/68] Remove retries from setMessagesNMEA --- Firmware/RTK_Everywhere/GNSS_ZED.ino | 78 +++++++++++++--------------- 1 file changed, 35 insertions(+), 43 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index 20a4e5008..aaea42caa 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -1764,7 +1764,15 @@ void GNSS_ZED::menuMessagesSubtype(uint8_t *localMessageRate, const char *messag { inputMessageRate(localMessageRate[msgNumber], msgNumber + rtcmOffset); - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings + // Depending on the message type, trigger different config requests + // Note: anything not handled triggers a NMEA config which runs the whole array including + // NMEA, RTCM (Rover), RXM, NAV, NAV2, NMEA NAV2, MON, TIM, PUBX + if (strcmp(messageType, "RTCM") == 0) + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings + else if (strcmp(messageType, "RTCM-Base") == 0) + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); // Request receiver to use new settings + else + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings } else printUnknown(incoming); @@ -2134,57 +2142,41 @@ bool GNSS_ZED::setMessagesNMEA() bool success = true; - if (online.gnss) + bool response = true; + int messageNumber = 0; + + while (messageNumber < MAX_UBX_MSG) { - int tryNo = -1; + response &= _zed->newCfgValset(VAL_LAYER_ALL); - // Try up to maxRetries times to configure the messages - // This corrects occasional failures seen on the Reference Station where the GNSS is connected via SPI - // instead of I2C and UART1. I believe the SETVAL ACK is occasionally missed due to the level of messages being - // processed. - while ((++tryNo < maxRetries) && success == false) + do { - bool response = true; - int messageNumber = 0; - - while (messageNumber < MAX_UBX_MSG) + if (messageSupported(messageNumber)) { - response &= _zed->newCfgValset(VAL_LAYER_ALL); + uint8_t rate = settings.ubxMessageRates[messageNumber]; - do - { - if (messageSupported(messageNumber)) - { - uint8_t rate = settings.ubxMessageRates[messageNumber]; - - // Set NMEA messages to user's settings on UART1 interface - response &= _zed->addCfgValset(ubxMessages[messageNumber].msgConfigKey, - rate); // msgConfigKey defaults to UART1 - - // Mark messages needed for other services (NTRIP Client, PointPerfect, etc) as enabled if rate - // > 0 - if (settings.ubxMessageRates[messageNumber] > 0) - { - if (strcmp(ubxMessages[messageNumber].msgTextName, "NMEA_GGA") == 0) - gpggaEnabled = true; - } - } - messageNumber++; - } while (((messageNumber % 43) < 42) && - (messageNumber < MAX_UBX_MSG)); // Limit 1st batch to 42. Batches after that will be (up to) 43 - // in size. It's a HHGTTG thing. - - if (_zed->sendCfgValset() == false) + // Set NMEA messages to user's settings on UART1 interface + response &= _zed->addCfgValset(ubxMessages[messageNumber].msgConfigKey, + rate); // msgConfigKey defaults to UART1 + + // Mark messages needed for other services (NTRIP Client, PointPerfect, etc) as enabled if rate + // > 0 + if (settings.ubxMessageRates[messageNumber] > 0) { - systemPrintf("sendCfg failed at messageNumber %d %s. Try %d of %d.\r\n", messageNumber - 1, - (messageNumber - 1) < MAX_UBX_MSG ? ubxMessages[messageNumber - 1].msgTextName : "", - tryNo + 1, maxRetries); - response &= false; // If any one of the Valset fails, report failure overall + if (strcmp(ubxMessages[messageNumber].msgTextName, "NMEA_GGA") == 0) + gpggaEnabled = true; } } + messageNumber++; + } while (((messageNumber % 43) < 42) && + (messageNumber < MAX_UBX_MSG)); // Limit 1st batch to 42. Batches after that will be (up to) 43 + // in size. It's a HHGTTG thing. - if (response) - success = true; + if (_zed->sendCfgValset() == false) + { + systemPrintf("sendCfg failed at messageNumber %d %s.\r\n", messageNumber - 1, + (messageNumber - 1) < MAX_UBX_MSG ? ubxMessages[messageNumber - 1].msgTextName : ""); + response &= false; // If any one of the Valset fails, report failure overall } } From b005e7f1f1a1898700268301b3ba4d6fdb11817c Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 28 Oct 2025 16:20:31 -0600 Subject: [PATCH 50/68] Remove getMinCN0. Add setLogging. --- Firmware/RTK_Everywhere/Begin.ino | 2 +- Firmware/RTK_Everywhere/GNSS.h | 6 +-- Firmware/RTK_Everywhere/GNSS.ino | 27 +++++++---- Firmware/RTK_Everywhere/GNSS_LG290P.h | 6 +-- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 60 ++++++------------------ Firmware/RTK_Everywhere/GNSS_Mosaic.h | 11 +++-- Firmware/RTK_Everywhere/GNSS_None.h | 10 +++- Firmware/RTK_Everywhere/GNSS_UM980.h | 6 +-- Firmware/RTK_Everywhere/GNSS_UM980.ino | 17 ++++++- Firmware/RTK_Everywhere/GNSS_ZED.h | 5 +- Firmware/RTK_Everywhere/GNSS_ZED.ino | 13 +++++ Firmware/RTK_Everywhere/menuCommands.ino | 2 +- Firmware/RTK_Everywhere/menuGNSS.ino | 2 +- 13 files changed, 90 insertions(+), 77 deletions(-) diff --git a/Firmware/RTK_Everywhere/Begin.ino b/Firmware/RTK_Everywhere/Begin.ino index db5f07064..ef148046c 100644 --- a/Firmware/RTK_Everywhere/Begin.ino +++ b/Firmware/RTK_Everywhere/Begin.ino @@ -657,7 +657,7 @@ void beginBoard() present.invertedFastPowerOff = true; present.gnss_to_uart = true; present.gnss_to_uart2 = true; - present.mosaicMicroSd; + present.mosaicMicroSd = true; present.microSdCardDetectLow = true; // Except microSD is connected to mosaic... present.microSd is false present.minCN0 = true; diff --git a/Firmware/RTK_Everywhere/GNSS.h b/Firmware/RTK_Everywhere/GNSS.h index 66f9a3ff6..667de372d 100644 --- a/Firmware/RTK_Everywhere/GNSS.h +++ b/Firmware/RTK_Everywhere/GNSS.h @@ -184,9 +184,6 @@ class GNSS // Returns two digits of milliseconds or zero if not online virtual uint8_t getMillisecond(); - // Get the minimum satellite signal level for navigation. - uint8_t getMinCN0(); - // Returns minutes or zero if not online virtual uint8_t getMinute(); @@ -349,6 +346,9 @@ class GNSS virtual bool setHighAccuracyService(bool enableGalileoHas); + // Configure any logging settings - currently mosaic-X5 specific + virtual bool setLogging(); + virtual bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate); // Enable/disable messages according to the NMEA array diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index d7af1bc0a..fcfd7e0f1 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -5,15 +5,18 @@ GNSS.ino For any given GNSS receiver, the following functions need to be implemented: * begin() - Start communication with the device and its library - * configure() - Runs once after a system wide factory reset. Any settings that need to be set but are not exposed to the user. + * configure() - Runs once after a system wide factory reset. Any settings that need to be set but are not exposed to +the user. * configureRover() - Change mode to Rover. Request NMEA and RTCM changes as needed. - * configureBase() - Change mode to Base. Fixed/Temp are controlled in states.ino. Request NMEA and RTCM changes as needed. + * configureBase() - Change mode to Base. Fixed/Temp are controlled in states.ino. Request NMEA and RTCM changes as +needed. * setBaudRateComm() - Set baud rate for connection between microcontroller and GNSS receiver * setBaudRateData() - Set baud rate for connection to the GNSS UART connected to the connector labeled DATA * setBaudRateRadio() - Set baud rate for connection to the GNSS UART connected to the connector labeled RADIO * setRate() - Set the report rate of the GNSS receiver. May or may not drive NMEA/RTCM rates directly. * setConstellations() - Set the constellations and bands for the GNSS receiver - * setElevation() - Set the degrees a GNSS satellite must be above the horizon in order to be used in location calculation + * setElevation() - Set the degrees a GNSS satellite must be above the horizon in order to be used in location +calculation * setMinCN0() - Set dBHz a GNSS satellite's signal strength must be above in order to be used in location calculation * setPPS() - Set the width, period, and polarity of the pulse-per-second signal * setModel() - Set the model used when calculating a location @@ -54,6 +57,7 @@ enum GNSS_CONFIG_MULTIPATH, GNSS_CONFIG_TILT, // Enable/disable any output needed for tilt compensation GNSS_CONFIG_EXT_CORRECTIONS, // Enable / disable corrections protocol(s) on the Radio External port + GNSS_CONFIG_LOGGING, // Enable / disable logging GNSS_CONFIG_SAVE, // Indicates current settings be saved to GNSS receiver NVM GNSS_CONFIG_RESET, // Indicates receiver needs resetting @@ -81,6 +85,7 @@ static const char *gnssConfigDisplayNames[] = { "MULTIPATH", "TILT", "EXT_CORRECTIONS", + "LOGGING", "SAVE", "RESET", }; @@ -95,13 +100,6 @@ extern NetworkClient *ntripClient; extern unsigned long lastGGAPush; -//---------------------------------------- -// Get the minimum satellite signal level for navigation. -//---------------------------------------- -uint8_t GNSS::getMinCN0() -{ - return (settings.minCN0); -} //---------------------------------------- float GNSS::getSurveyInStartingAccuracy() @@ -364,6 +362,15 @@ void gnssUpdate() } } + if (gnssConfigureRequested(GNSS_CONFIG_LOGGING)) + { + if (gnss->setLogging() == true) + { + gnssConfigureClear(GNSS_CONFIG_LOGGING); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } + } + // Save changes to NVM if (gnssConfigureRequested(GNSS_CONFIG_SAVE)) { diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.h b/Firmware/RTK_Everywhere/GNSS_LG290P.h index ed3adcce1..4b0e159df 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.h +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.h @@ -259,9 +259,6 @@ class GNSS_LG290P : GNSS // Returns two digits of milliseconds or zero if not online uint8_t getMillisecond(); - // Get the minimum satellite signal level for navigation. - uint8_t getMinCN0(); - // Returns minutes or zero if not online uint8_t getMinute(); @@ -421,6 +418,9 @@ class GNSS_LG290P : GNSS bool setHighAccuracyService(bool enableGalileoHas); + // Configure any logging settings - currently mosaic-X5 specific + bool setLogging(); + // Set the NMEA messages bool setMessagesNMEA(); diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index 495e46e82..15f47e9b5 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -237,6 +237,8 @@ bool GNSS_LG290P::configureBase() return (true); // No changes needed } + // Assume we are changing from Rover to Base, request any additional config changes + // If the device is set to Survey-In, we must allow the device to be configured. // Otherwise PQTMEPE (estimated position error) is never populated, so the survey // never starts (Waiting for Horz Accuracy < 2.00m...) @@ -308,6 +310,8 @@ bool GNSS_LG290P::configureRover() return (true); // No changes needed } + // Assume we are changing from Base to Rover, request any additional config changes + bool response = _lg290p->setModeRover(false); // Don't wait for save and reset // Setting mode to rover should disable any survey-in @@ -358,49 +362,6 @@ bool GNSS_LG290P::configureNtpMode() return false; } -//---------------------------------------- -// Disable NMEA and RTCM on UART2 to reduce the serial traffic -//---------------------------------------- -bool GNSS_LG290P::enterConfigMode(unsigned long waitForSemaphoreTimeout_millis) -{ - if (online.gnss) - { - unsigned long start = millis(); - bool isBlocking; - do - { // Wait for up to waitForSemaphoreTimeout for library to stop blocking - isBlocking = _lg290p->isBlocking(); - } while (isBlocking && ((millis() - start) < waitForSemaphoreTimeout_millis)); - - // This will fail if the library is still blocking, but it is worth a punt... - - if (lg290pFirmwareVersion >= 6) // See #747 - // Disable NMEA and RTCM on the LG290P UART2, but leave the undocumented Bit 1 enabled - return (_lg290p->sendOkCommand("$PQTMCFGPROT", ",W,1,2,00000007,00000002")); - - // Disable NMEA and RTCM on the LG290P UART2 - return (_lg290p->sendOkCommand("$PQTMCFGPROT", ",W,1,2,00000000,00000000")); - } - return (false); -} - -//---------------------------------------- -// Enable NMEA and RTCM on UART2 -//---------------------------------------- -bool GNSS_LG290P::exitConfigMode() -{ - if (online.gnss) - { - if (lg290pFirmwareVersion >= 6) // See #747 - // Enable NMEA and RTCM on the LG290P UART2, plus the undocumented Bit 1 - return (_lg290p->sendOkCommand("$PQTMCFGPROT", ",W,1,2,00000007,00000007")); - - // Enable NMEA and RTCM on the LG290P UART2 - return (_lg290p->sendOkCommand("$PQTMCFGPROT", ",W,1,2,00000005,00000005")); - } - return (false); -} - //---------------------------------------- // Disable Survey-In //---------------------------------------- @@ -1869,7 +1830,7 @@ bool GNSS_LG290P::setHighAccuracyService(bool enableGalileoHas) // E6 reception requires version v06 with 'PPP_TEMP' in firmware title // Present is set during LG290P begin() if (present.galileoHasCapable == false) - return (true); // We are unable to set this setting so report success + return (true); // Return true to clear gnssConfigure test // TODO - We should read/modify/write on PQTMCFGPPP @@ -1911,6 +1872,15 @@ bool GNSS_LG290P::setHighAccuracyService(bool enableGalileoHas) return (result); } +//---------------------------------------- +// Configure device-direct logging. Currently mosaic-X5 specific. +//---------------------------------------- +bool GNSS_LG290P::setLogging() +{ + // Not supported on this platform + return (true); // Return true to clear gnssConfigure test +} + //---------------------------------------- // Set the minimum satellite signal level for navigation. //---------------------------------------- @@ -2323,7 +2293,7 @@ bool GNSS_LG290P::setRate(double secondsBetweenSolutions) // The fix rate can only be set in rover mode. Return true if we are in base mode. // This allows the gnssUpdate() to clear the bit. if (gnss->gnssInBaseSurveyInMode() || gnss->gnssInBaseFixedMode()) // Base - return (true); // Nothing to modify at this time + return (true); // Nothing to modify at this time bool response = true; diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.h b/Firmware/RTK_Everywhere/GNSS_Mosaic.h index 39ffde96b..f3a3ac0c0 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.h +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.h @@ -615,8 +615,6 @@ class GNSS_MOSAIC : GNSS // Configure mosaic-X5 L-Band bool configureLBand(bool enableLBand, uint32_t LBandFreq = 0); - bool configureLogging(); - // Configure specific aspects of the receiver for NTP mode bool configureNtpMode(); @@ -660,11 +658,11 @@ class GNSS_MOSAIC : GNSS bool fixRateIsAllowed(uint32_t fixRateMs); - //Return min/max rate in ms + // Return min/max rate in ms uint32_t fixRateGetMinimumMs(); uint32_t fixRateGetMaximumMs(); - + // Return the number of active/enabled messages uint8_t getActiveMessageCount(); @@ -780,7 +778,7 @@ class GNSS_MOSAIC : GNSS // Returns full year, ie 2023, not 23. uint16_t getYear(); - // Helper functions for the current mode as read from the GNSS receiver + // Helper functions for the current mode as read from the GNSS receiver bool gnssInBaseFixedMode(); bool gnssInBaseSurveyInMode(); bool gnssInRoverMode(); @@ -992,6 +990,9 @@ class GNSS_MOSAIC : GNSS // Enable or disable HAS E6 capability bool setHighAccuracyService(bool enableGalileoHas); + // Configure any logging settings - currently mosaic-X5 specific + bool setLogging(); + // Turn on all the enabled NMEA messages on COM1 bool setMessagesNMEA(); diff --git a/Firmware/RTK_Everywhere/GNSS_None.h b/Firmware/RTK_Everywhere/GNSS_None.h index 6cb7e8513..903b0ec03 100644 --- a/Firmware/RTK_Everywhere/GNSS_None.h +++ b/Firmware/RTK_Everywhere/GNSS_None.h @@ -174,7 +174,7 @@ class GNSS_None : public GNSS return false; } - //Return min/max rate in ms + // Return min/max rate in ms uint32_t fixRateGetMinimumMs() { return 0; @@ -375,7 +375,7 @@ class GNSS_None : public GNSS return _year; } - // Helper functions for the current mode as read from the GNSS receiver + // Helper functions for the current mode as read from the GNSS receiver bool gnssInBaseFixedMode() { return false; @@ -595,6 +595,12 @@ class GNSS_None : public GNSS return true; } + // Configure device-direct logging. Currently mosaic-X5 specific. + bool setLogging() + { + return true; + } + // Configure NMEA messages bool setMessagesNMEA() { diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.h b/Firmware/RTK_Everywhere/GNSS_UM980.h index a8d4532b7..3a568ee30 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.h +++ b/Firmware/RTK_Everywhere/GNSS_UM980.h @@ -271,9 +271,6 @@ class GNSS_UM980 : GNSS // Returns two digits of milliseconds or zero if not online uint8_t getMillisecond(); - // Get the minimum satellite signal level for navigation. - uint8_t getMinCN0(); - // Returns minutes or zero if not online uint8_t getMinute(); @@ -438,6 +435,9 @@ class GNSS_UM980 : GNSS // elevationDegrees: The elevation value in degrees bool setElevation(uint8_t elevationDegrees); + // Configure any logging settings - currently mosaic-X5 specific + bool setLogging(); + // Turn on all the enabled NMEA messages on COM3 bool setMessagesNMEA(); diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index da0e24de0..739f0b71b 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -172,14 +172,16 @@ bool GNSS_UM980::configureBase() if (settings.fixedBase == true && gnssInBaseFixedMode()) return (true); + // Assume we are changing from Rover to Base, request any additional config changes + // Set the dynamic mode. This will cancel any base averaging mode and is needed // to allow a freshly started device to settle in regular GNSS reception mode before issuing // a surveyInStart(). gnssConfigure(GNSS_CONFIG_MODEL); // Request receiver to use new settings - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); return (true); } @@ -292,12 +294,14 @@ bool GNSS_UM980::configureRover() if (settings.dynamicModel == UM980_DYN_MODEL_AUTOMOTIVE && currentMode == 3) return (true); + // Assume we are changing from Base to Rover, request any additional config changes + // Sets the dynamic model (Survey/UAV/Automotive) and puts the device into Rover mode gnssConfigure(GNSS_CONFIG_MODEL); // Request a change to NMEA and Rover RTCM - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); return (true); } @@ -1565,6 +1569,15 @@ bool GNSS_UM980::setHighAccuracyService(bool enableGalileoHas) return (result); } +//---------------------------------------- +// Configure device-direct logging. Currently mosaic-X5 specific. +//---------------------------------------- +bool GNSS_UM980::setLogging() +{ + // Not supported on this platform + return (true); // Return true to clear gnssConfigure test +} + //---------------------------------------- // Set the minimum satellite signal level (carrier to noise ratio) for navigation. //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.h b/Firmware/RTK_Everywhere/GNSS_ZED.h index 60e8cb7e3..6ae55fdcc 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.h +++ b/Firmware/RTK_Everywhere/GNSS_ZED.h @@ -572,7 +572,7 @@ class GNSS_ZED : GNSS // Returns full year, ie 2023, not 23. uint16_t getYear(); - // Helper functions for the current mode as read from the GNSS receiver + // Helper functions for the current mode as read from the GNSS receiver bool gnssInBaseFixedMode(); bool gnssInBaseSurveyInMode(); bool gnssInRoverMode(); @@ -707,6 +707,9 @@ class GNSS_ZED : GNSS // Enable or disable HAS E6 capability bool setHighAccuracyService(bool enableGalileoHas); + // Configure any logging settings - currently mosaic-X5 specific + bool setLogging(); + // Given a unique string, find first and last records containing that string in message array void setMessageOffsets(const ubxMsg *localMessage, const char *messageType, int &startOfBlock, int &endOfBlock); diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index aaea42caa..86f46801e 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -510,6 +510,8 @@ bool GNSS_ZED::configureBase() return (true); // No changes needed } + // Assume we are changing from Rover to Base, request any additional config changes + gnssConfigure(GNSS_CONFIG_FIX_RATE); gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); @@ -622,6 +624,8 @@ bool GNSS_ZED::configureRover() return (true); // No changes needed } + // Assume we are changing from Base to Rover, request any additional config changes + bool response = true; gnssConfigure(GNSS_CONFIG_FIX_RATE); @@ -2073,6 +2077,15 @@ bool GNSS_ZED::setHighAccuracyService(bool enableGalileoHas) return (true); // Return true to clear gnssConfigure test } +//---------------------------------------- +// Configure device-direct logging. Currently mosaic-X5 specific. +//---------------------------------------- +bool GNSS_ZED::setLogging() +{ + // Not supported on this platform + return (true); // Return true to clear gnssConfigure test +} + //---------------------------------------- // Given a unique string, find first and last records containing that string in message array //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/menuCommands.ino b/Firmware/RTK_Everywhere/menuCommands.ino index 68ddb7040..a225b1821 100644 --- a/Firmware/RTK_Everywhere/menuCommands.ino +++ b/Firmware/RTK_Everywhere/menuCommands.ino @@ -2206,7 +2206,7 @@ void createSettingsString(char *newSettings) stringRecord(newSettings, "udpOverWiFiStation", 0); // 1 = WiFi mode, 0 = AP // Single variables needed on Config page - stringRecord(newSettings, "minCN0", gnss->getMinCN0()); + stringRecord(newSettings, "minCN0", settings.minCN0); stringRecord(newSettings, "enableRCFirmware", enableRCFirmware); // Add SD Characteristics diff --git a/Firmware/RTK_Everywhere/menuGNSS.ino b/Firmware/RTK_Everywhere/menuGNSS.ino index 644af575b..35ee58a05 100644 --- a/Firmware/RTK_Everywhere/menuGNSS.ino +++ b/Firmware/RTK_Everywhere/menuGNSS.ino @@ -126,7 +126,7 @@ void menuGNSS() settings.minElev); if (present.minCN0) - systemPrintf("6) Minimum satellite signal level for navigation (dBHz): %d\r\n", gnss->getMinCN0()); + systemPrintf("6) Minimum satellite signal level for navigation (dBHz): %d\r\n", settings.minCN0); systemPrint("7) Toggle NTRIP Client: "); if (settings.enableNtripClient == true) From 09e5457ec67d03b4358ba047015e39ea034a8bc9 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 28 Oct 2025 16:28:34 -0600 Subject: [PATCH 51/68] Prelim mosaic support for gnssConfigure() --- Firmware/RTK_Everywhere/GNSS_Mosaic.ino | 211 ++++++++---------------- 1 file changed, 66 insertions(+), 145 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino index 974a0bd11..1f94d1be8 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino @@ -53,10 +53,10 @@ void printMosaicCardSpace() //---------------------------------------- void menuLogMosaic() { - if (!present.mosaicMicroSd) // This may be needed for the G5 P3 ? + if (present.mosaicMicroSd == false) // This may be needed for the G5 P3 ? + { return; - - bool applyChanges = false; + } while (1) { @@ -95,12 +95,12 @@ void menuLogMosaic() if (incoming == 1) { settings.enableLogging ^= 1; - applyChanges = true; + gnssConfigure(GNSS_CONFIG_LOGGING); // Request receiver to use new settings } else if (incoming == 2) { settings.enableLoggingRINEX ^= 1; - applyChanges = true; + gnssConfigure(GNSS_CONFIG_LOGGING); // Request receiver to use new settings } else if (incoming == 3 && settings.enableLoggingRINEX == true) { @@ -116,7 +116,7 @@ void menuLogMosaic() if (duration >= 1 && duration <= MAX_MOSAIC_FILE_DURATIONS) { settings.RINEXFileDuration = duration - 1; - applyChanges = true; + gnssConfigure(GNSS_CONFIG_LOGGING); // Request receiver to use new settings } } else if (incoming == 4 && settings.enableLoggingRINEX == true) @@ -133,7 +133,7 @@ void menuLogMosaic() if (interval >= 1 && interval <= MAX_MOSAIC_OBS_INTERVALS) { settings.RINEXObsInterval = interval - 1; - applyChanges = true; + gnssConfigure(GNSS_CONFIG_LOGGING); // Request receiver to use new settings } } else if (incoming == 'x') @@ -146,16 +146,6 @@ void menuLogMosaic() printUnknown(incoming); } - // Apply changes - if (applyChanges) - { - GNSS_MOSAIC *mosaic = (GNSS_MOSAIC *)gnss; - - mosaic->configureLogging(); // This will enable / disable RINEX logging - mosaic->setMessagesNMEA(); // Enable NMEA messages - this will enable/disable the DSK1 streams - mosaic->saveConfiguration(); // Save the configuration - } - clearBuffer(); // Empty buffer of any newline chars } @@ -242,6 +232,8 @@ void GNSS_MOSAIC::begin() // COM3 is N/C (ESP32 UART2 is connected to the IMU) // COM4 TX provides data to the IMU - TODO + systemPrintln("Starting communication with mosaic-X5"); + if (productVariant != RTK_FLEX) // productVariant == RTK_FACET_MOSAIC { if (serial2GNSS == nullptr) @@ -271,13 +263,6 @@ void GNSS_MOSAIC::begin() return; } - // Set COM2 (Radio) and COM3 (Data) baud rates - setBaudRateRadio(settings.radioPortBaud); - setBaudRateData(settings.dataPortBaud); - - // Set COM2 (Radio) protocol(s) - setCorrRadioExtPort(settings.enableExtCorrRadio, true); // Force the setting - updateSD(); // Check card size and free space _receiverSetupSeen = false; @@ -311,10 +296,6 @@ void GNSS_MOSAIC::begin() if (isPresent() == false) // Detect if the module is present return; - // Set COM2 (Radio) and COM3 (Data) baud rates - setBaudRateRadio(settings.radioPortBaud); - setBaudRateData(settings.dataPortBaud); // Probably redundant - // Set COM2 (Radio) protocol(s) setCorrRadioExtPort(settings.enableExtCorrRadio, true); // Force the setting @@ -362,9 +343,6 @@ bool GNSS_MOSAIC::beginExternalEvent() // Note: You can't disable events via sep. Event cannot be set to "none"... // All you can do is disable the ExtEvent stream - if (online.gnss == false) - return (false); - if (settings.dataPortChannel != MUX_PPS_EVENTTRIGGER) return (true); // No need to configure PPS if port is not selected @@ -385,9 +363,6 @@ bool GNSS_MOSAIC::beginExternalEvent() //---------------------------------------- bool GNSS_MOSAIC::setPPS() { - if (online.gnss == false) - return (false); - if (settings.dataPortChannel != MUX_PPS_EVENTTRIGGER) return (true); // No need to configure PPS if port is not selected @@ -435,57 +410,9 @@ bool GNSS_MOSAIC::checkPPPRates() return settings.enableLoggingRINEX; } +// Enable / disable RINEX logging //---------------------------------------- -// Configure the Base -// Outputs: -// Returns true if successfully configured and false upon failure -//---------------------------------------- -bool GNSS_MOSAIC::configureBase() -{ - /* - Set mode to Static + dynamic model - Enable RTCM Base messages - Enable NMEA messages - - mosaicX5AutoBaseStart() will start "survey-in" - mosaicX5FixedBaseStart() will start fixed base - */ - - if (online.gnss == false) - { - systemPrintln("GNSS not online"); - return (false); - } - - bool response = true; - - response &= setModel(MOSAIC_DYN_MODEL_STATIC); - - response &= setElevation(settings.minElev); - - response &= setMinCN0(settings.minCN0); - - response &= setConstellations(); - - response &= setMessagesRTCMBase(); - - response &= setMessagesNMEA(); - - response &= configureLogging(); - - // Save the current configuration into non-volatile memory (NVM) - response &= saveConfiguration(); - - if (response == false) - { - systemPrintln("mosaic-X5 Base failed to configure"); - } - - return (response); -} - -//---------------------------------------- -bool GNSS_MOSAIC::configureLogging() +bool GNSS_MOSAIC::setLogging() { bool response = true; String setting; @@ -576,6 +503,51 @@ bool GNSS_MOSAIC::configureLBand(bool enableLBand, uint32_t LBandFreq) return result; } +//---------------------------------------- +// Setup the general configuration of the GNSS +// Not Rover or Base specific (ie, baud rates) +// Outputs: +// Returns true if successfully configured and false upon failure +//---------------------------------------- +bool GNSS_MOSAIC::configure() +{ + // Attempt 3 tries on MOSAICX5 config + for (int x = 0; x < 3; x++) + { + if (configureOnce() == true) + return (true); + } + + systemPrintln("mosaic-X5 failed to configure"); + return (false); +} + +//---------------------------------------- +// Configure the Base +// Outputs: +// Returns true if successfully configured and false upon failure +//---------------------------------------- +bool GNSS_MOSAIC::configureBase() +{ + // TODO Check if we are already in base here. Return if we are. + + // Assume we are changing from Rover to Base, request any additional config changes + + bool response = true; + + // Set the model to static for Base mode + response &= setModel(MOSAIC_DYN_MODEL_STATIC); + + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); + + if (response == false) + { + systemPrintln("mosaic-X5 Base failed to configure"); + } + + return (response); +} + //---------------------------------------- // Perform the GNSS configuration // Outputs: @@ -627,16 +599,11 @@ bool GNSS_MOSAIC::configureOnce() response &= sendWithResponse("snt,+GPSL5\n\r", "SignalTracking", 1000, 200); response &= sendWithResponse("snu,+GPSL5,+GPSL5\n\r", "SignalUsage", 1000, 200); - configureLogging(); - if (response == true) { online.gnss = true; // If we failed before, mark as online now systemPrintln("mosaic-X5 configuration updated"); - - // Save the current configuration into non-volatile memory (NVM) - response &= saveConfiguration(); } else online.gnss = false; // Take it offline @@ -644,25 +611,6 @@ bool GNSS_MOSAIC::configureOnce() return (response); } -//---------------------------------------- -// Setup the general configuration of the GNSS -// Not Rover or Base specific (ie, baud rates) -// Outputs: -// Returns true if successfully configured and false upon failure -//---------------------------------------- -bool GNSS_MOSAIC::configure() -{ - // Attempt 3 tries on MOSAICX5 config - for (int x = 0; x < 3; x++) - { - if (configureOnce() == true) - return (true); - } - - systemPrintln("mosaic-X5 failed to configure"); - return (false); -} - //---------------------------------------- // Configure the Rover // Outputs: @@ -670,43 +618,20 @@ bool GNSS_MOSAIC::configure() //---------------------------------------- bool GNSS_MOSAIC::configureRover() { - /* - Set mode to Rover + dynamic model - Set minElevation - Enable RTCM messages on COM1 - Enable NMEA on COM1 - */ - if (online.gnss == false) - { - systemPrintln("GNSS not online"); - return (false); - } + // TODO Check if we are already in rover here. Return if we are. + + // Assume we are changing from Base to Rover, request any additional config changes bool response = true; response &= sendWithResponse("spm,Rover,all,auto\n\r", "PVTMode"); - response &= setModel(settings.dynamicModel); // Set by menuGNSS which calls gnss->setModel - - response &= setElevation(settings.minElev); // Set by menuGNSS which calls gnss->setElevation - - response &= setMinCN0(settings.minCN0); - - response &= setConstellations(); - - response &= setMessagesRTCMRover(); - - response &= setMessagesNMEA(); - - response &= configureLogging(); - - // Save the current configuration into non-volatile memory (NVM) - response &= saveConfiguration(); + gnssConfigure(GNSS_CONFIG_FIX_RATE); + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); if (response == false) - { systemPrintln("mosaic-X5 Rover failed to configure"); - } return (response); } @@ -1478,6 +1403,7 @@ void GNSS_MOSAIC::menuConstellations() incoming--; // Align choice to constellation array of 0 to 5 settings.mosaicConstellations[incoming] ^= 1; + gnssConfigure(GNSS_CONFIG_CONSTELLATION); // Request receiver to use new settings } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) break; @@ -1487,11 +1413,6 @@ void GNSS_MOSAIC::menuConstellations() printUnknown(incoming); } - // Apply current settings to module - setConstellations(); - - saveConfiguration(); // Save the updated constellations - clearBuffer(); // Empty buffer of any newline chars } @@ -2177,7 +2098,7 @@ bool GNSS_MOSAIC::setElevation(uint8_t elevationDegrees) bool GNSS_MOSAIC::setHighAccuracyService(bool enableGalileoHas) { // Not yet supported on this platform - return (false); + return (true); // Return true to clear gnssConfigure test } //---------------------------------------- @@ -2522,8 +2443,8 @@ bool GNSS_MOSAIC::setRate(double secondsBetweenSolutions) //---------------------------------------- bool GNSS_MOSAIC::setTilt() { - // Not yet available on this platform - return false; + // Not yet supported on this platform + return (true); // Return true to clear gnssConfigure test } //---------------------------------------- From c6a850844b34c709ce4398c1d2e8786697ee81a8 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Wed, 29 Oct 2025 14:09:07 -0600 Subject: [PATCH 52/68] Add getMode for mosaic. Move surveyInStart and fixedBaseStart to gnssConfigure() --- Firmware/RTK_Everywhere/Display.ino | 5 ++ Firmware/RTK_Everywhere/GNSS.h | 2 - Firmware/RTK_Everywhere/GNSS.ino | 37 +++++---- Firmware/RTK_Everywhere/GNSS_LG290P.h | 2 - Firmware/RTK_Everywhere/GNSS_LG290P.ino | 44 ++++------- Firmware/RTK_Everywhere/GNSS_Mosaic.ino | 101 +++++++++++++++++++----- Firmware/RTK_Everywhere/GNSS_None.h | 5 -- Firmware/RTK_Everywhere/GNSS_UM980.h | 2 - Firmware/RTK_Everywhere/GNSS_UM980.ino | 17 +++- Firmware/RTK_Everywhere/GNSS_ZED.ino | 10 +-- Firmware/RTK_Everywhere/States.ino | 33 +++----- Firmware/RTK_Everywhere/menuBase.ino | 10 +-- 12 files changed, 158 insertions(+), 110 deletions(-) diff --git a/Firmware/RTK_Everywhere/Display.ino b/Firmware/RTK_Everywhere/Display.ino index 3b8ee5bf3..880de6e2a 100644 --- a/Firmware/RTK_Everywhere/Display.ino +++ b/Firmware/RTK_Everywhere/Display.ino @@ -3073,6 +3073,11 @@ void paintEspNowPaired() displayMessage("ESP-NOW Paired", 2000); } +void paintMosaicBooting() +{ + displayMessage("GNSS Booting", 0); +} + void displayNtpStart(uint16_t displayTime) { if (online.display == true) diff --git a/Firmware/RTK_Everywhere/GNSS.h b/Firmware/RTK_Everywhere/GNSS.h index 667de372d..a1045380f 100644 --- a/Firmware/RTK_Everywhere/GNSS.h +++ b/Firmware/RTK_Everywhere/GNSS.h @@ -219,8 +219,6 @@ class GNSS // Return the number of seconds the survey-in process has been running virtual int getSurveyInObservationTime(); - float getSurveyInStartingAccuracy(); - // Returns timing accuracy or zero if not online virtual uint32_t getTimeAccuracy(); diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index fcfd7e0f1..99cbbbed1 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -40,7 +40,9 @@ enum { GNSS_CONFIG_ONCE, // Settings specific to a receiver that don't fit into other setting categories GNSS_CONFIG_ROVER, - GNSS_CONFIG_BASE, // Fixed base or survey in, location, etc + GNSS_CONFIG_BASE, // Apply any settings before the start of survey-in or fixed base + GNSS_CONFIG_BASE_SURVEY, // Start survey in base + GNSS_CONFIG_BASE_FIXED, // Start fixed base GNSS_CONFIG_BAUD_RATE_RADIO, GNSS_CONFIG_BAUD_RATE_DATA, GNSS_CONFIG_FIX_RATE, @@ -69,6 +71,8 @@ static const char *gnssConfigDisplayNames[] = { "ONCE", "ROVER", "BASE", + "BASE SURVEY", + "BASE FIXED", "BAUD_RATE_RADIO", "BAUD_RATE_DATA", "RATE", @@ -100,13 +104,6 @@ extern NetworkClient *ntripClient; extern unsigned long lastGGAPush; - -//---------------------------------------- -float GNSS::getSurveyInStartingAccuracy() -{ - return (settings.surveyInStartingAccuracy); -} - //---------------------------------------- // Returns true if the antenna is shorted //---------------------------------------- @@ -181,10 +178,6 @@ void gnssUpdate() gnssConfigureClear(GNSS_CONFIG_ROVER); gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM } - else - { - systemPrintln("Rover config failed"); - } } if (gnssConfigureRequested(GNSS_CONFIG_BASE)) @@ -194,9 +187,23 @@ void gnssUpdate() gnssConfigureClear(GNSS_CONFIG_BASE); gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM } - else + } + + if (gnssConfigureRequested(GNSS_CONFIG_BASE_SURVEY)) + { + if (gnss->surveyInStart() == true) { - systemPrintln("Base config failed"); + gnssConfigureClear(GNSS_CONFIG_BASE_SURVEY); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + } + } + + if (gnssConfigureRequested(GNSS_CONFIG_BASE_FIXED)) + { + if (gnss->fixedBaseStart() == true) + { + gnssConfigureClear(GNSS_CONFIG_BASE_FIXED); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM } } @@ -449,6 +456,8 @@ void gnssConfigureDefaults() // Clear request bits that do not need to be set after a factory reset gnssConfigureClear(GNSS_CONFIG_BASE); + gnssConfigureClear(GNSS_CONFIG_BASE_SURVEY); + gnssConfigureClear(GNSS_CONFIG_BASE_FIXED); gnssConfigureClear(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); gnssConfigureClear(GNSS_CONFIG_RESET); } diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.h b/Firmware/RTK_Everywhere/GNSS_LG290P.h index 4b0e159df..9efc8b69f 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.h +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.h @@ -296,8 +296,6 @@ class GNSS_LG290P : GNSS // Return the number of seconds the survey-in process has been running int getSurveyInObservationTime(); - float getSurveyInStartingAccuracy(); - // Returns timing accuracy or zero if not online uint32_t getTimeAccuracy(); diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index 15f47e9b5..27782ca5f 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -454,20 +454,9 @@ bool GNSS_LG290P::fixedBaseStart() if (online.gnss == false) return (false); - // Read, modify, write - - if (settings.fixedBase == true && gnssInBaseFixedMode()) - { - if (settings.debugGnssConfig) - systemPrintln("Skipping - LG290P is already in Fixed Base configuration"); - return (true); // No changes needed - } - if (settings.fixedBase == false && gnssInBaseSurveyInMode()) - { - if (settings.debugGnssConfig) - systemPrintln("Skipping - LG290P is already in Survey-in Base configuration"); + // If we are already in the appropriate base mode, no changes needed + if (gnssInBaseFixedMode()) return (true); // No changes needed - } if (settings.fixedBaseCoordinateType == COORD_TYPE_ECEF) { @@ -1845,7 +1834,6 @@ bool GNSS_LG290P::setHighAccuracyService(bool enableGalileoHas) if (_lg290p->sendOkCommand("$PQTMCFGPPP", ",W,2,1,120,0.10,0.15") == true) { systemPrintln("Galileo E6 HAS service enabled"); - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM } else { @@ -1860,7 +1848,6 @@ bool GNSS_LG290P::setHighAccuracyService(bool enableGalileoHas) if (_lg290p->sendOkCommand("$PQTMCFGPPP", ",W,0") == true) { systemPrintln("Galileo E6 HAS service disabled"); - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM } else { @@ -2397,24 +2384,23 @@ bool GNSS_LG290P::surveyInReset() //---------------------------------------- bool GNSS_LG290P::surveyInStart() { - if (online.gnss) - { - bool response = true; - - response &= - _lg290p->setSurveyInMode(settings.observationSeconds); // Average for a number of seconds (default is 60) + if (gnssInBaseSurveyInMode()) + return (true); // No changes needed - if (response == false) - { - systemPrintln("Survey start failed"); - return (false); - } + bool response = true; - _autoBaseStartTimer = millis(); // Stamp when averaging began + // Average for a number of seconds (default is 60) + response &= _lg290p->setSurveyInMode(settings.observationSeconds); - return (response); + if (response == false) + { + systemPrintln("Survey start failed"); + return (false); } - return false; + + _autoBaseStartTimer = millis(); // Stamp when averaging began + + return (response); } //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino index 1f94d1be8..de923f035 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino @@ -232,8 +232,6 @@ void GNSS_MOSAIC::begin() // COM3 is N/C (ESP32 UART2 is connected to the IMU) // COM4 TX provides data to the IMU - TODO - systemPrintln("Starting communication with mosaic-X5"); - if (productVariant != RTK_FLEX) // productVariant == RTK_FACET_MOSAIC { if (serial2GNSS == nullptr) @@ -529,7 +527,18 @@ bool GNSS_MOSAIC::configure() //---------------------------------------- bool GNSS_MOSAIC::configureBase() { - // TODO Check if we are already in base here. Return if we are. + if (settings.fixedBase == false && gnssInBaseSurveyInMode()) + return (true); // No changes needed + + if (settings.fixedBase == true) + { + // 0 - Unknown, 1 - Rover, 2 - Base Survey In, 3 - Base Fixed Geodetic, 4 - Base Fixed Cartesian + int currentMode = getMode(); + if (currentMode == 3 && settings.fixedBaseCoordinateType == COORD_TYPE_GEODETIC) + return (true); // No changes needed + if (currentMode == 4 && settings.fixedBaseCoordinateType == COORD_TYPE_ECEF) + return (true); // No changes needed + } // Assume we are changing from Rover to Base, request any additional config changes @@ -618,7 +627,8 @@ bool GNSS_MOSAIC::configureOnce() //---------------------------------------- bool GNSS_MOSAIC::configureRover() { - // TODO Check if we are already in rover here. Return if we are. + if (gnssInRoverMode()) + return (true); // No changes needed // Assume we are changing from Base to Rover, request any additional config changes @@ -737,6 +747,14 @@ uint16_t GNSS_MOSAIC::fileBufferExtractData(uint8_t *fileBuffer, int fileBytesTo //---------------------------------------- bool GNSS_MOSAIC::fixedBaseStart() { + // If we are already in the appropriate base mode, no changes needed + // 0 - Unknown, 1 - Rover, 2 - Base Survey In, 3 - Base Fixed Geodetic, 4 - Base Fixed Cartesian + int currentMode = getMode(); + if (currentMode == 3 && settings.fixedBaseCoordinateType == COORD_TYPE_GEODETIC) + return (true); // No changes needed + if (currentMode == 4 && settings.fixedBaseCoordinateType == COORD_TYPE_ECEF) + return (true); // No changes needed + bool response = true; // TODO: support alternate Datums (ETRS89, NAD83, NAD83_PA, NAD83_MA, GDA94, GDA2020) @@ -763,9 +781,7 @@ bool GNSS_MOSAIC::fixedBaseStart() } if (response == false) - { systemPrintln("Fixed base start failed"); - } return (response); } @@ -1026,11 +1042,43 @@ uint8_t GNSS_MOSAIC::getMinute() //---------------------------------------- // Returns the current mode: Base/Rover/etc +// 0 - Unknown, 1 - Rover, 2 - Base Survey In, 3 - Base Fixed Geodetic, 4 - Base Fixed Cartesian //---------------------------------------- uint8_t GNSS_MOSAIC::getMode() { - // TODO - return 0; + // Example responses to gpm: + // PVTMode, Rover, StandAlone+SBAS+DGNSS+RTKFloat+RTKFixed, auto + // PVTMode, Static, StandAlone+SBAS+DGNSS+RTKFloat+RTKFixed, auto + // PVTMode, Static, StandAlone+SBAS+DGNSS+RTKFloat+RTKFixed, Geodetic1 + // PVTMode, Static, StandAlone+SBAS+DGNSS+RTKFloat+RTKFixed, Cartesian1 + + char receiverResponse[500]; + // Send gpm, look for correct PVTMode response, and store the entire response for searching later + if (sendWithResponse("gpm\n\r", "PVTMode", 1000, 25, receiverResponse, sizeof(receiverResponse)) == true) + { + if (strnstr(receiverResponse, "Cartesian", sizeof(receiverResponse)) != nullptr) // Found + { + Serial.println("Mode: Base fixed Cartesian"); + return (4); + } + if (strnstr(receiverResponse, "Geodetic", sizeof(receiverResponse)) != nullptr) // Found + { + Serial.println("Mode: Base fixed Geodetic"); + return (3); + } + if (strnstr(receiverResponse, "Static", sizeof(receiverResponse)) != nullptr) // Found + { + Serial.println("Mode: Base survey-in"); + return (2); + } + if (strnstr(receiverResponse, "Rover", sizeof(receiverResponse)) != nullptr) // Found + { + Serial.println("Mode: Rover"); + return (1); + } + } + + return 0; // Unknown } //---------------------------------------- @@ -1177,7 +1225,10 @@ uint16_t GNSS_MOSAIC::getYear() //---------------------------------------- bool GNSS_MOSAIC::gnssInBaseFixedMode() { - // TODO + // 0 - Unknown, 1 - Rover, 2 - Base Survey In, 3 - Base Fixed Geodetic, 4 - Base Fixed Cartesian + int currentMode = getMode(); + if (currentMode == 3 || currentMode == 4) + return (true); return (false); } //---------------------------------------- @@ -1185,7 +1236,9 @@ bool GNSS_MOSAIC::gnssInBaseFixedMode() //---------------------------------------- bool GNSS_MOSAIC::gnssInBaseSurveyInMode() { - // TODO + // 0 - Unknown, 1 - Rover, 2 - Base Survey In, 3 - Base Fixed Geodetic, 4 - Base Fixed Cartesian + if (getMode() == 2) + return (true); return (false); } //---------------------------------------- @@ -1193,7 +1246,9 @@ bool GNSS_MOSAIC::gnssInBaseSurveyInMode() //---------------------------------------- bool GNSS_MOSAIC::gnssInRoverMode() { - // TODO + // 0 - Unknown, 1 - Rover, 2 - Base Survey In, 3 - Base Fixed Geodetic, 4 - Base Fixed Cartesian + if (getMode() == 1) + return (true); return (false); } @@ -1556,6 +1611,11 @@ void GNSS_MOSAIC::menuMessagesRTCM(bool rover) incoming--; incoming -= MAX_MOSAIC_RTCM_V3_INTERVAL_GROUPS; enabledPtr[incoming] ^= 1; + + if (inBaseMode()) // If the system state is Base mode + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); // Request receiver to use new settings + else + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings } else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT) break; @@ -1910,8 +1970,8 @@ bool GNSS_MOSAIC::sendWithResponse(HardwareSerial *serialPort, const char *messa if (serialPort->available()) { uint8_t c = serialPort->read(); - // if ((settings.debugGnss == true) && (!inMainMenu)) - // systemPrintf("%c", (char)c); + if ((settings.debugGnss == true) && (!inMainMenu)) + systemPrintf("%c", (char)c); if (response && (replySeen < (responseSize - 1))) { *(response + replySeen) = c; @@ -2679,17 +2739,19 @@ bool GNSS_MOSAIC::surveyInReset() //---------------------------------------- bool GNSS_MOSAIC::surveyInStart() { - // Start a Self-optimizing Base Station - bool response = sendWithResponse("spm,Static,,auto\n\r", "PVTMode"); - _determiningFixedPosition = true; // Ensure flag is set initially _autoBaseStartTimer = millis(); // Stamp when averaging began + // If we are already in the appropriate base mode, no changes needed + if (gnssInBaseSurveyInMode()) + return (true); // No changes needed + + // Start a Self-optimizing Base Station + bool response = sendWithResponse("spm,Static,,auto\n\r", "PVTMode"); + if (response == false) - { systemPrintln("Survey start failed"); - } return (response); } @@ -2872,6 +2934,9 @@ uint32_t GNSS_MOSAIC::baudGetMaximum() // Return true if the receiver is detected bool GNSS_MOSAIC::isPresent() { + systemPrintln("Starting communication with mosaic-X5"); + paintMosaicBooting(); + if (productVariant != RTK_FLEX) // productVariant == RTK_FACET_MOSAIC { // Set COM4 to: CMD input (only), SBF output (only) diff --git a/Firmware/RTK_Everywhere/GNSS_None.h b/Firmware/RTK_Everywhere/GNSS_None.h index 903b0ec03..dd5e94b10 100644 --- a/Firmware/RTK_Everywhere/GNSS_None.h +++ b/Firmware/RTK_Everywhere/GNSS_None.h @@ -358,11 +358,6 @@ class GNSS_None : public GNSS return 0; } - float getSurveyInStartingAccuracy() - { - return 0; - } - // Returns timing accuracy or zero if not online uint32_t getTimeAccuracy() { diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.h b/Firmware/RTK_Everywhere/GNSS_UM980.h index 3a568ee30..3d28b6e8f 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.h +++ b/Firmware/RTK_Everywhere/GNSS_UM980.h @@ -307,8 +307,6 @@ class GNSS_UM980 : GNSS // Return the number of seconds the survey-in process has been running int getSurveyInObservationTime(); - float getSurveyInStartingAccuracy(); - // Returns timing accuracy or zero if not online uint32_t getTimeAccuracy(); diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index 739f0b71b..84d066615 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -421,11 +421,15 @@ uint16_t GNSS_UM980::fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToR //---------------------------------------- bool GNSS_UM980::fixedBaseStart() { - bool response = true; - if (online.gnss == false) return (false); + // If we are already in the appropriate base mode, no changes needed + if (gnssInBaseFixedMode()) + return (true); + + bool response = true; + if (settings.fixedBaseCoordinateType == COORD_TYPE_ECEF) { _um980->setModeBaseECEF(settings.fixedEcefX, settings.fixedEcefY, settings.fixedEcefZ); @@ -1975,14 +1979,19 @@ bool GNSS_UM980::surveyInStart() { if (online.gnss) { + // If we are already in the appropriate base mode, no changes needed + if (gnssInBaseSurveyInMode()) + return (true); + bool response = true; // Start a Self-optimizing Base Station // We do not use the distance parameter (settings.observationPositionAccuracy) because that // setting on the UM980 is related to automatically restarting base mode // at power on (very different from ZED-F9P). - response &= - _um980->setModeBaseAverage(settings.observationSeconds); // Average for a number of seconds (default is 60) + + // Average for a number of seconds (default is 60) + response &= _um980->setModeBaseAverage(settings.observationSeconds); if (response == false) { diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index 86f46801e..dc75db164 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -741,12 +741,9 @@ bool GNSS_ZED::fixedBaseStart() if (online.gnss == false) return (false); + // If we are already in the appropriate base mode, no changes needed if (gnssInBaseFixedMode()) - { - if (settings.debugGnssConfig) - systemPrintln("Skipping - F9P is already in Fixed Base configuration"); return (true); // No changes needed - } if (settings.fixedBaseCoordinateType == COORD_TYPE_ECEF) { @@ -2651,12 +2648,9 @@ bool GNSS_ZED::surveyInStart() if (online.gnss == false) return (false); + // If we are already in the appropriate base mode, no changes needed if (gnssInBaseSurveyInMode()) - { - if (settings.debugGnssConfig) - systemPrintln("Skipping F9P Survey-In Base - already running"); return (true); // No changes needed - } _zed->setVal8(UBLOX_CFG_TMODE_MODE, 0, VAL_LAYER_ALL); // Disable survey-in mode delay(100); diff --git a/Firmware/RTK_Everywhere/States.ino b/Firmware/RTK_Everywhere/States.ino index ff524a504..aa78f7c00 100644 --- a/Firmware/RTK_Everywhere/States.ino +++ b/Firmware/RTK_Everywhere/States.ino @@ -244,7 +244,11 @@ void stateUpdate() if (settings.fixedBase == false) changeState(STATE_BASE_TEMP_SETTLE); else + { + gnssConfigure(GNSS_CONFIG_BASE_FIXED); // Request start of fixed base changeState(STATE_BASE_FIXED_NOT_STARTED); + RTK_MODE(RTK_MODE_BASE_FIXED); + } } } break; @@ -267,9 +271,8 @@ void stateUpdate() char temp[20]; const char *units = getHpaUnits(hpa, temp, sizeof(temp), 2, true); - // gnssGetSurveyInStartingAccuracy is 10m max - const char *accUnits = - getHpaUnits(gnss->getSurveyInStartingAccuracy(), accuracy, sizeof(accuracy), 2, false); + // surveyInStartingAccuracy is 10m max + const char *accUnits = getHpaUnits(settings.surveyInStartingAccuracy, accuracy, sizeof(accuracy), 2, false); systemPrintf("Waiting for Horz Accuracy < %s (%s): %s%s%s%s, SIV: %d\r\n", accuracy, accUnits, temp, (accUnits != units) ? " (" : "", (accUnits != units) ? units : "", @@ -277,16 +280,13 @@ void stateUpdate() // On the mosaic-X5, the HPA is undefined while the GNSS is determining its fixed position // We need to skip the HPA check... - if ((hpa > 0.0 && hpa < gnss->getSurveyInStartingAccuracy()) || present.gnss_mosaicX5) + if ((hpa > 0.0 && hpa < settings.surveyInStartingAccuracy) || present.gnss_mosaicX5) { - displaySurveyStart(0); // Show 'Survey' + gnssConfigure(GNSS_CONFIG_BASE_SURVEY); // Request reconfigure to base survey in mode - if (gnss->surveyInStart() == true) // Begin survey - { - displaySurveyStarted(500); // Show 'Survey Started' + displaySurveyStarted(500); // Show 'Survey Started' - changeState(STATE_BASE_TEMP_SURVEY_STARTED); - } + changeState(STATE_BASE_TEMP_SURVEY_STARTED); } } break; @@ -373,22 +373,13 @@ void stateUpdate() */ // User has switched to base with fixed option enabled. Let's configure and try to get there. - // If fixed base fails, we'll handle it here + // If fixed base fails, gnssConfigure() will attempt again case (STATE_BASE_FIXED_NOT_STARTED): { - RTK_MODE(RTK_MODE_BASE_FIXED); - bool response = gnss->fixedBaseStart(); - if (response == true) + if (gnssConfigureComplete()) { baseStatusLedOn(); // Turn on the base/status LED changeState(STATE_BASE_FIXED_TRANSMITTING); } - else - { - systemPrintln("Fixed base start failed"); - displayBaseFail(1000); - - changeState(STATE_ROVER_NOT_STARTED); // Return to rover mode to avoid being in fixed base mode - } } break; diff --git a/Firmware/RTK_Everywhere/menuBase.ino b/Firmware/RTK_Everywhere/menuBase.ino index 24d399291..8c279198c 100644 --- a/Firmware/RTK_Everywhere/menuBase.ino +++ b/Firmware/RTK_Everywhere/menuBase.ino @@ -100,7 +100,7 @@ void menuBase() } systemPrintf("4) Set required initial positional accuracy before Survey-In: %0.2f meters\r\n", - gnss->getSurveyInStartingAccuracy()); + settings.surveyInStartingAccuracy); } } @@ -278,7 +278,7 @@ void menuBase() // Change GNSS receiver configuration if the receiver is in Base mode, otherwise, just change setting // This prevents a user, while in Rover mode but changing a Base setting, from entering Base mode if (gnss->gnssInBaseSurveyInMode() || gnss->gnssInBaseFixedMode()) - gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } } @@ -291,7 +291,7 @@ void menuBase() // Change GNSS receiver configuration if the receiver is in Base mode, otherwise, just change setting // This prevents a user, while in Rover mode but changing a Base setting, from entering Base mode if (gnss->gnssInBaseSurveyInMode() || gnss->gnssInBaseFixedMode()) - gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } } else if (settings.fixedBase == false && incoming == 3 && @@ -305,7 +305,7 @@ void menuBase() // Change GNSS receiver configuration if the receiver is in Base mode, otherwise, just change setting // This prevents a user, while in Rover mode but changing a Base setting, from entering Base mode if (gnss->gnssInBaseSurveyInMode() || gnss->gnssInBaseFixedMode()) - gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } } else if (settings.fixedBase == false && incoming == 4 && (!present.gnss_mosaicX5)) @@ -318,7 +318,7 @@ void menuBase() // Change GNSS receiver configuration if the receiver is in Base mode, otherwise, just change setting // This prevents a user, while in Rover mode but changing a Base setting, from entering Base mode if (gnss->gnssInBaseSurveyInMode() || gnss->gnssInBaseFixedMode()) - gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings + gnssConfigure(GNSS_CONFIG_BASE); // Request receiver to use new settings } } From cec0f1f7de85076c5d96a2daddfdb7e61c960e4d Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Wed, 29 Oct 2025 14:42:56 -0600 Subject: [PATCH 53/68] Restart NTRIP Client if settings change Fix #761 The setting change notification is currently only on serial menu. Needs to be extended to CLI. --- Firmware/RTK_Everywhere/NtripClient.ino | 17 ++++++++++++++++- Firmware/RTK_Everywhere/menuGNSS.ino | 14 +++++++------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Firmware/RTK_Everywhere/NtripClient.ino b/Firmware/RTK_Everywhere/NtripClient.ino index 34d94b423..762d5f80d 100644 --- a/Firmware/RTK_Everywhere/NtripClient.ino +++ b/Firmware/RTK_Everywhere/NtripClient.ino @@ -200,6 +200,8 @@ unsigned long lastGGAPush; bool ntripClientForcedShutdown = false; // NTRIP Client was turned off due to an error. Don't allow restart. +bool ntripClientSettingsChange = false; // Goes true when a menu or command modified the client credentials + //---------------------------------------- // NTRIP Client Routines //---------------------------------------- @@ -392,6 +394,13 @@ bool ntripClientEnabled(const char **line) // Verify still enabled enabled = settings.enableNtripClient; + // Allow restart if settings change + if(ntripClientSettingsChange == true) + { + ntripClientSettingsChange = false; + ntripClientForcedShutdown = false; + } + // Determine if the shutdown is being forced if (enabled && ntripClientForcedShutdown) { @@ -871,8 +880,14 @@ void ntripClientUpdate() systemPrintln("NTRIP Client resetting connection attempt counter and timeout"); } + // Check if the there have been changes to the client settings + if(ntripClientSettingsChange == true) + { + ntripClientSettingsChange = false; + ntripClientRestart(); + } // Check for timeout receiving NTRIP data - if (ntripClientReceiveDataAvailable() == 0) + else if (ntripClientReceiveDataAvailable() == 0) { // Don't fail during retransmission attempts if ((millis() - ntripClientTimer) > NTRIP_CLIENT_RECEIVE_DATA_TIMEOUT) diff --git a/Firmware/RTK_Everywhere/menuGNSS.ino b/Firmware/RTK_Everywhere/menuGNSS.ino index 35ee58a05..2e0f30a05 100644 --- a/Firmware/RTK_Everywhere/menuGNSS.ino +++ b/Firmware/RTK_Everywhere/menuGNSS.ino @@ -310,13 +310,13 @@ void menuGNSS() else if (incoming == 7) { settings.enableNtripClient ^= 1; - // No need to restart rover. NTRIP Client state machine will service the change. } else if ((incoming == 8) && settings.enableNtripClient == true) { systemPrint("Enter new Caster Address: "); getUserInputString(settings.ntripClient_CasterHost, sizeof(settings.ntripClient_CasterHost)); - // No need to restart rover. NTRIP Client state machine will service the change. + + ntripClientSettingsChange = true; // Notify the NTRIP Client state machine of new credentials } else if ((incoming == 9) && settings.enableNtripClient == true) { @@ -324,32 +324,32 @@ void menuGNSS() if (getNewSetting("Enter new Caster Port", 1, 99999, &settings.ntripClient_CasterPort) == INPUT_RESPONSE_VALID) { - // No need to restart rover. NTRIP Client state machine will service the change. + ntripClientSettingsChange = true; // Notify the NTRIP Client state machine of new credentials } } else if ((incoming == 10) && settings.enableNtripClient == true) { systemPrintf("Enter user name for %s: ", settings.ntripClient_CasterHost); getUserInputString(settings.ntripClient_CasterUser, sizeof(settings.ntripClient_CasterUser)); - // No need to restart rover. NTRIP Client state machine will service the change. + ntripClientSettingsChange = true; // Notify the NTRIP Client state machine of new credentials } else if ((incoming == 11) && settings.enableNtripClient == true) { systemPrintf("Enter user password for %s: ", settings.ntripClient_CasterHost); getUserInputString(settings.ntripClient_CasterUserPW, sizeof(settings.ntripClient_CasterUserPW)); - // No need to restart rover. NTRIP Client state machine will service the change. + ntripClientSettingsChange = true; // Notify the NTRIP Client state machine of new credentials } else if ((incoming == 12) && settings.enableNtripClient == true) { systemPrint("Enter new Mount Point: "); getUserInputString(settings.ntripClient_MountPoint, sizeof(settings.ntripClient_MountPoint)); - // No need to restart rover. NTRIP Client state machine will service the change. + ntripClientSettingsChange = true; // Notify the NTRIP Client state machine of new credentials } else if ((incoming == 13) && settings.enableNtripClient == true) { systemPrintf("Enter password for Mount Point %s: ", settings.ntripClient_MountPoint); getUserInputString(settings.ntripClient_MountPointPW, sizeof(settings.ntripClient_MountPointPW)); - // No need to restart rover. NTRIP Client state machine will service the change. + ntripClientSettingsChange = true; // Notify the NTRIP Client state machine of new credentials } else if ((incoming == 14) && settings.enableNtripClient == true) { From 47a7d3f2f249ea715aa19d8f0f3907f430dd1c98 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Wed, 29 Oct 2025 15:31:27 -0600 Subject: [PATCH 54/68] Force on GGA online if NTRIP client and transmit GGA are enabled --- Firmware/RTK_Everywhere/GNSS_Mosaic.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino index de923f035..48ce17524 100644 --- a/Firmware/RTK_Everywhere/GNSS_Mosaic.ino +++ b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino @@ -2232,7 +2232,7 @@ bool GNSS_MOSAIC::setMessagesNMEA() } } - if (settings.ntripClient_TransmitGGA == true) + if (settings.ntripClient_TransmitGGA == true && settings.enableNtripClient == true) { // Force on GGA if needed for NTRIP if (gpggaEnabled == false) From ae1d8d67337729d284c23b9028c9dd84c5ac1e9b Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Wed, 29 Oct 2025 16:27:03 -0600 Subject: [PATCH 55/68] Extend base checking to ECEF/LLH. Restart survey-in after power cycle. --- Firmware/RTK_Everywhere/GNSS_ZED.ino | 65 ++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index dc75db164..42b90faca 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -497,17 +497,21 @@ bool GNSS_ZED::configure() //---------------------------------------- bool GNSS_ZED::configureBase() { - if (settings.fixedBase == false && gnssInBaseSurveyInMode()) - { - if (settings.debugGnssConfig) - systemPrintln("Skipping - F9P already in Survey-In Base configuration"); - return (true); // No changes needed - } - if (settings.fixedBase == true && gnssInBaseFixedMode()) + // If we are already in the appropriate base mode, no changes needed + + // We may have been in a previous survey-in. We want to restart a survey-in regardless. + // If we are already in the appropriate base mode, no changes needed + // if (settings.fixedBase == false && gnssInBaseSurveyInMode()) + // return (true); // No changes needed + + if (settings.fixedBase == true) { - if (settings.debugGnssConfig) - systemPrintln("Skipping - F9P already in Fixed Base configuration"); - return (true); // No changes needed + // 0 - Rover, 1 - Base Survey-In, 2 - Base Fixed ECEF, 3 - Base Fixed LLH + int currentMode = getMode(); + if (currentMode == 2 && settings.fixedBaseCoordinateType == COORD_TYPE_ECEF) + return (true); // No changes needed + if (currentMode == 3 && settings.fixedBaseCoordinateType == COORD_TYPE_GEODETIC) + return (true); // No changes needed } // Assume we are changing from Rover to Base, request any additional config changes @@ -521,7 +525,7 @@ bool GNSS_ZED::configureBase() if (settings.fixedBase == false) { // If we are doing a Survey-In (temporary) style Base, change to Rover Mode so our location can settle - response &= _zed->setVal8(UBLOX_CFG_TMODE_MODE, 0); + response &= _zed->setVal8(UBLOX_CFG_TMODE_MODE, 0); // Change to Rover Mode } if (response == false) @@ -742,7 +746,12 @@ bool GNSS_ZED::fixedBaseStart() return (false); // If we are already in the appropriate base mode, no changes needed - if (gnssInBaseFixedMode()) + + // 0 - Rover, 1 - Base Survey-In, 2 - Base Fixed ECEF, 3 - Base Fixed LLH + int currentMode = getMode(); + if (currentMode == 2 && settings.fixedBaseCoordinateType == COORD_TYPE_ECEF) + return (true); // No changes needed + if (currentMode == 3 && settings.fixedBaseCoordinateType == COORD_TYPE_GEODETIC) return (true); // No changes needed if (settings.fixedBaseCoordinateType == COORD_TYPE_ECEF) @@ -1045,7 +1054,7 @@ uint8_t GNSS_ZED::getMinute() //---------------------------------------- // Returns the current mode -// 0 - Rover, 1 - Base Survey-In, 2 - Base Fixed +// 0 - Rover, 1 - Base Survey-In, 2 - Base Fixed ECEF, 3 - Base Fixed LLH //---------------------------------------- uint8_t GNSS_ZED::getMode() { @@ -1053,7 +1062,22 @@ uint8_t GNSS_ZED::getMode() { // Survey mode is only available on ZED-F9P modules if (commandSupported(UBLOX_CFG_TMODE_MODE)) - return (_zed->getVal8(UBLOX_CFG_TMODE_MODE)); + { + int currentMode = _zed->getVal8(UBLOX_CFG_TMODE_MODE); + + if (currentMode == 0) // Rover + return (0); + if (currentMode == 1) // Survey-in + return (1); + if (currentMode == 2) // Fixed + { + int baseType = _zed->getVal8(UBLOX_CFG_TMODE_POS_TYPE); + if (baseType == 0) // ECEF + return (2); // Base Fixed ECEF + if (baseType == 1) // LLH + return (3); // Base Fixed LLH + } + } } return (0); // Rover @@ -1186,6 +1210,9 @@ int GNSS_ZED::getSurveyInObservationTime() if (online.gnss == false) return (0); + if(gnssConfigureComplete() == false) + return (0); + // Use a local static so we don't have to request these values multiple times (ZED takes many ms to respond // to this command) if ((millis() - lastCheck) > 1000) @@ -1217,7 +1244,7 @@ uint16_t GNSS_ZED::getYear() //---------------------------------------- bool GNSS_ZED::gnssInBaseFixedMode() { - if (getMode() == 2) // 0 - Rover, 1 - Base Survey-In, 2 - Base Fixed + if (getMode() == 2 || getMode() == 3) // 0 - Rover, 1 - Base Survey-In, 2 - Base Fixed ECEF, 3 - Base Fixed LLH return (true); return (false); @@ -1228,7 +1255,7 @@ bool GNSS_ZED::gnssInBaseFixedMode() //---------------------------------------- bool GNSS_ZED::gnssInBaseSurveyInMode() { - if (getMode() == 1) // 0 - Rover, 1 - Base Survey-In, 2 - Base Fixed + if (getMode() == 1) // 0 - Rover, 1 - Base Survey-In, 2 - Base Fixed ECEF, 3 - Base Fixed LLH return (true); return (false); @@ -2641,16 +2668,16 @@ bool GNSS_ZED::surveyInReset() //---------------------------------------- // Start the survey-in operation -// The ZED-F9P is slightly different than the NEO-M8P. See the Integration manual 3.5.8 for more info. //---------------------------------------- bool GNSS_ZED::surveyInStart() { if (online.gnss == false) return (false); + // We may have been in a previous survey-in. We want to restart a survey-in regardless. // If we are already in the appropriate base mode, no changes needed - if (gnssInBaseSurveyInMode()) - return (true); // No changes needed + // if (gnssInBaseSurveyInMode()) + // return (true); // No changes needed _zed->setVal8(UBLOX_CFG_TMODE_MODE, 0, VAL_LAYER_ALL); // Disable survey-in mode delay(100); From 147401e2fe949f7381e0f09ec14301885cd17c48 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 30 Oct 2025 09:40:55 -0600 Subject: [PATCH 56/68] Configure ZED when enter/exit Base mode. Enable GGA on UART, not I2C for NTRIP Client. --- Firmware/RTK_Everywhere/GNSS.ino | 32 +++++++++---------- Firmware/RTK_Everywhere/GNSS_ZED.ino | 47 +++++++++++++++++++--------- 2 files changed, 47 insertions(+), 32 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index 99cbbbed1..f17e8ccb2 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -311,35 +311,31 @@ void gnssUpdate() if (gnssConfigureRequested(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER)) { - if (inRoverMode() == false) + if (gnss->gnssInRoverMode() == false) { - systemPrintln("Error: Change to RTCM Rover rates requested but not in Rover mode. Skipping."); + systemPrintln("Warning: Change to RTCM Rover rates requested but not in Rover mode."); } - else + + if (gnss->setMessagesRTCMRover() == true) { - if (gnss->setMessagesRTCMRover() == true) - { - gnssConfigureClear(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM - setLoggingType(); // Update Standard, PPP, or custom for icon selection - } + gnssConfigureClear(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + setLoggingType(); // Update Standard, PPP, or custom for icon selection } } if (gnssConfigureRequested(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE)) { - if (inBaseMode() == false) + if (gnss->gnssInBaseFixedMode() == false && gnss->gnssInBaseSurveyInMode() == false) { - systemPrintln("Error: Change to RTCM Base rates requested but not in Base mode. Skipping."); + systemPrintln("Warning: Change to RTCM Base rates requested but not in Base mode."); } - else + + if (gnss->setMessagesRTCMBase() == true) { - if (gnss->setMessagesRTCMBase() == true) - { - gnssConfigureClear(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); - gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM - setLoggingType(); // Update Standard, PPP, or custom for icon selection - } + gnssConfigureClear(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); + gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM + setLoggingType(); // Update Standard, PPP, or custom for icon selection } } diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index 42b90faca..a636506cd 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -516,16 +516,19 @@ bool GNSS_ZED::configureBase() // Assume we are changing from Rover to Base, request any additional config changes - gnssConfigure(GNSS_CONFIG_FIX_RATE); - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); - bool response = true; if (settings.fixedBase == false) { // If we are doing a Survey-In (temporary) style Base, change to Rover Mode so our location can settle + // Base config resumes at the end of startSurveyIn() response &= _zed->setVal8(UBLOX_CFG_TMODE_MODE, 0); // Change to Rover Mode + gnssConfigure(GNSS_CONFIG_FIX_RATE); + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); + } + else + { + // If we are doing a Fixed Base, config occurs in fixedBaseStart() } if (response == false) @@ -633,7 +636,6 @@ bool GNSS_ZED::configureRover() bool response = true; gnssConfigure(GNSS_CONFIG_FIX_RATE); - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); response &= _zed->setVal8(UBLOX_CFG_TMODE_MODE, 0); // Switch to Rover mode @@ -824,6 +826,10 @@ bool GNSS_ZED::fixedBaseStart() response &= _zed->sendCfgValset(); } + // Now that the module is set to base mode, complete the base config. + gnssConfigure(GNSS_CONFIG_FIX_RATE); + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); + return (response); } @@ -1210,7 +1216,7 @@ int GNSS_ZED::getSurveyInObservationTime() if (online.gnss == false) return (0); - if(gnssConfigureComplete() == false) + if (gnssConfigureComplete() == false) return (0); // Use a local static so we don't have to request these values multiple times (ZED takes many ms to respond @@ -2228,18 +2234,18 @@ bool GNSS_ZED::setMessagesNMEA() measurementFrequency = 0.2; // 0.2Hz * 5 = 1 measurement every 5 seconds if (settings.debugGnssConfig) systemPrintf("Adjusting GGA setting to %f\r\n", measurementFrequency); - _zed->setVal8(UBLOX_CFG_MSGOUT_NMEA_ID_GGA_I2C, measurementFrequency, - VAL_LAYER_ALL); // Enable GGA over I2C. Tell the module to output GGA every second + response &= _zed->setVal8(UBLOX_CFG_MSGOUT_NMEA_ID_GGA_UART1, measurementFrequency, + VAL_LAYER_ALL); // Enable GGA over UART1. Tell the module to output GGA every second } } // Configure the callback for GGA as needed if (settings.enableNtripClient == true && settings.ntripClient_TransmitGGA == true) - _zed->setNMEAGPGGAcallbackPtr(&zedPushGPGGA); + response &= _zed->setNMEAGPGGAcallbackPtr(&zedPushGPGGA); else - _zed->setNMEAGPGGAcallbackPtr(nullptr); + response &= _zed->setNMEAGPGGAcallbackPtr(nullptr); - return (success); + return (response); } //---------------------------------------- @@ -2382,8 +2388,13 @@ bool GNSS_ZED::setRate(double secondsBetweenSolutions) if (online.gnss == false) return (false); - if (gnss->gnssInBaseSurveyInMode() || gnss->gnssInBaseFixedMode()) - secondsBetweenSolutions = 1; // In Base mode we force 1Hz + // In Base mode we force 1Hz, and avoid overwriting the setting + bool baseOverride = false; + if (gnssInBaseSurveyInMode() || gnssInBaseFixedMode()) + { + baseOverride = true; + secondsBetweenSolutions = 1; + } // If we have more than an hour between readings, increase mesaurementRate to near max of 65,535 if (secondsBetweenSolutions > 3600.0) @@ -2435,7 +2446,8 @@ bool GNSS_ZED::setRate(double secondsBetweenSolutions) // If we successfully set rates, only then record to settings if (response) { - settings.measurementRateMs = secondsBetweenSolutions * 1000; + if (baseOverride == false) + settings.measurementRateMs = secondsBetweenSolutions * 1000; } else { @@ -2732,6 +2744,13 @@ bool GNSS_ZED::surveyInStart() return (false); // Reset of survey failed } + // The ZED-F9P starts a Survey-in in Rover mode to allow the location fix to settle. + // Once settle is complete, the survey starts. + // Here we change the fix rate and enable RTCM messages for base mode. + // Essentially completing the Base configuration. + gnssConfigure(GNSS_CONFIG_FIX_RATE); + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); + return (true); } From 36c39624e121e0538d873328ae63a85e6786687f Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 30 Oct 2025 11:38:49 -0600 Subject: [PATCH 57/68] Fix GGA handling on LG290P --- Firmware/RTK_Everywhere/GNSS.ino | 11 ++-- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 80 +++++++++++-------------- Firmware/RTK_Everywhere/GNSS_ZED.ino | 2 +- Firmware/RTK_Everywhere/Tasks.ino | 13 +++- 4 files changed, 51 insertions(+), 55 deletions(-) diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index f17e8ccb2..2979d54a7 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -311,10 +311,8 @@ void gnssUpdate() if (gnssConfigureRequested(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER)) { - if (gnss->gnssInRoverMode() == false) - { + if (settings.debugGnssConfig == true && gnss->gnssInRoverMode() == false) systemPrintln("Warning: Change to RTCM Rover rates requested but not in Rover mode."); - } if (gnss->setMessagesRTCMRover() == true) { @@ -326,10 +324,9 @@ void gnssUpdate() if (gnssConfigureRequested(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE)) { - if (gnss->gnssInBaseFixedMode() == false && gnss->gnssInBaseSurveyInMode() == false) - { - systemPrintln("Warning: Change to RTCM Base rates requested but not in Base mode."); - } + if (settings.debugGnssConfig == true) + if (gnss->gnssInBaseFixedMode() == false && gnss->gnssInBaseSurveyInMode() == false) + systemPrintln("Warning: Change to RTCM Base rates requested but not in Base mode."); if (gnss->setMessagesRTCMBase() == true) { diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index 27782ca5f..236de6024 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -187,33 +187,11 @@ bool GNSS_LG290P::checkPPPRates() } //---------------------------------------- -// Setup the GNSS module for any setup (base or rover) -// In general we check if the setting is different than setting stored in NVM before writing it. +// begin() has already established communication. There are no one-time config requirements for the LG290P //---------------------------------------- bool GNSS_LG290P::configure() { - for (int x = 0; x < 3; x++) - { - // Wait up to 5 seconds for device to come online - for (int x = 0; x < 5; x++) - { - if (_lg290p->isConnected()) - break; - else - systemPrintln("Device still rebooting"); - delay(1000); // Wait for device to reboot - } - - // If we fail, reset LG290P - systemPrintln("Resetting LG290P to complete configuration"); - - gnssReset(); - delay(500); - gnssBoot(); - } - - systemPrintln("LG290P failed to configure"); - return (false); + return (true); } //---------------------------------------- @@ -226,29 +204,19 @@ bool GNSS_LG290P::configureBase() if (settings.fixedBase == false && gnssInBaseSurveyInMode()) { if (settings.debugGnssConfig) - systemPrintln("Skipping - LG290P is already in Fixed Base configuration"); + systemPrintln("Skipping - LG290P is already in Survey-In Base configuration"); return (true); // No changes needed } if (settings.fixedBase == true && gnssInBaseFixedMode()) { if (settings.debugGnssConfig) - systemPrintln("Skipping - LG290P is already in Survey-in Base configuration"); + systemPrintln("Skipping - LG290P is already in Fixed Base configuration"); return (true); // No changes needed } // Assume we are changing from Rover to Base, request any additional config changes - // If the device is set to Survey-In, we must allow the device to be configured. - // Otherwise PQTMEPE (estimated position error) is never populated, so the survey - // never starts (Waiting for Horz Accuracy < 2.00m...) - // if (currentMode == 2 && settings.fixedBase == false) // Not a fixed base = Survey-in - // { - // if (settings.debugGnssConfig) - // systemPrintln("Skipping LG290P Survey In Base configuration"); - // return true; - // } - // "When set to Base Station mode, the receiver will automatically disable NMEA message output and enable RTCM MSM4 // and RTCM3-1005 message output." // "Note: After switching the module's working mode, save the configuration and then reset the module. Otherwise, it @@ -286,11 +254,14 @@ bool GNSS_LG290P::configureBase() reset(); - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); - // When a device is changed from Rover to Base, NMEA messages are disabled. Turn them back on. gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); + // In Survey-In mode, configuring the RTCM Base will trigger a print warning because the survey-in + // takes a few seconds to start during which gnssInBaseSurveyInMode() incorrectly reports false. + // The print warning should be ignored. + gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); + if (settings.debugGnssConfig && response) systemPrintln("LG290P Base configured"); } @@ -306,7 +277,7 @@ bool GNSS_LG290P::configureRover() if (gnssInRoverMode()) // 0 - Unknown, 1 - Rover, 2 - Base { if (settings.debugGnssConfig) - systemPrintln("Skipping LG290P Rover configuration"); + systemPrintln("Skipping Rover configuration"); return (true); // No changes needed } @@ -317,7 +288,6 @@ bool GNSS_LG290P::configureRover() gnssConfigure(GNSS_CONFIG_FIX_RATE); gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); gnssConfigure(GNSS_CONFIG_RESET); // Mode change requires reset return (response); @@ -349,9 +319,22 @@ void GNSS_LG290P::createMessageListBase(String &returnText) //---------------------------------------- uint8_t GNSS_LG290P::getSurveyInMode() { + // Note: _lg290p->getSurveyMode() returns 0 while a survey-in is *running* + // so we check PQTMSVINSTATUS to see if a survey is in progress. + if (online.gnss) - return (_lg290p->getSurveyMode()); - return (false); + { + if (_lg290p->getSurveyMode() == 2) + return (2); // We know we are fixed + else + { + // Determine if a survey is running + int surveyStatus = _lg290p->getSurveyInStatus(); // 0 = Invalid, 1 = In-progress, 2 = Valid + if (surveyStatus == 1 || surveyStatus == 2) + return (1); // We're in survey mode + } + } + return (0); } //---------------------------------------- @@ -1939,10 +1922,16 @@ bool GNSS_LG290P::setMessagesNMEA() if (pointPerfectServiceUsesKeys() || (settings.enableNtripClient == true && settings.ntripClient_TransmitGGA == true)) { + if (settings.debugGnssConfig) + systemPrintln("Enabling GGA for NTRIP and PointPerfect"); + // If firmware is 4 or higher, use setMessageRateOnPort, otherwise setMessageRate if (lg290pFirmwareVersion >= 4) - // Enable GGA. On Torch, LG290P connected to ESP32 on UART 2. + { + // Enable GGA on a specific port + // On Torch X2 and Postcard, the LG290P UART 2 is connected to ESP32. response &= _lg290p->setMessageRateOnPort("GGA", 1, 2); + } else // Enable GGA on all UARTs. It's the best we can do. response &= _lg290p->setMessageRate("GGA", 1); @@ -2384,6 +2373,9 @@ bool GNSS_LG290P::surveyInReset() //---------------------------------------- bool GNSS_LG290P::surveyInStart() { + _autoBaseStartTimer = millis(); // Stamp when averaging began + + // We may have already started a survey-in from GNSS's previous NVM settings if (gnssInBaseSurveyInMode()) return (true); // No changes needed @@ -2398,8 +2390,6 @@ bool GNSS_LG290P::surveyInStart() return (false); } - _autoBaseStartTimer = millis(); // Stamp when averaging began - return (response); } diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino index a636506cd..831bc3777 100644 --- a/Firmware/RTK_Everywhere/GNSS_ZED.ino +++ b/Firmware/RTK_Everywhere/GNSS_ZED.ino @@ -627,7 +627,7 @@ bool GNSS_ZED::configureRover() if (gnssInRoverMode()) { if (settings.debugGnssConfig) - systemPrintln("Skipping F9P Rover configuration"); + systemPrintln("Skipping Rover configuration"); return (true); // No changes needed } diff --git a/Firmware/RTK_Everywhere/Tasks.ino b/Firmware/RTK_Everywhere/Tasks.ino index 8d5bf788f..dd32892c2 100644 --- a/Firmware/RTK_Everywhere/Tasks.ino +++ b/Firmware/RTK_Everywhere/Tasks.ino @@ -865,8 +865,17 @@ void processUart1Message(SEMP_PARSE_STATE *parse, uint16_t type) // Suppress PQTM/NMEA messages as needed if (lg290pMessageEnabled((char *)parse->buffer, parse->length) == false) { - parse->buffer[0] = 0; - parse->length = 0; + if (settings.enableNtripClient == true && settings.ntripClient_TransmitGGA == true) + { + // GGA is disabled, but the user has enabled the NTRIP Client. + // Allow GGA to get through, unmodified. + } + else + { + // Remove the contents of this message + parse->buffer[0] = 0; + parse->length = 0; + } } } } From d358a27ac55d691aaf4ef0952d3b0488da167e5b Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Mon, 3 Nov 2025 10:18:50 -0700 Subject: [PATCH 58/68] Move NTRIP settings change request to atomic function in NtripClient --- Firmware/RTK_Everywhere/Begin.ino | 1 + Firmware/RTK_Everywhere/Developer.ino | 1 + Firmware/RTK_Everywhere/GNSS.ino | 23 ++-- Firmware/RTK_Everywhere/GNSS_UM980.ino | 145 +++++++++++++----------- Firmware/RTK_Everywhere/NtripClient.ino | 16 ++- Firmware/RTK_Everywhere/Tasks.ino | 2 +- Firmware/RTK_Everywhere/menuGNSS.ino | 12 +- Firmware/RTK_Everywhere/menuSystem.ino | 2 +- 8 files changed, 116 insertions(+), 86 deletions(-) diff --git a/Firmware/RTK_Everywhere/Begin.ino b/Firmware/RTK_Everywhere/Begin.ino index ef148046c..a03316a9e 100644 --- a/Firmware/RTK_Everywhere/Begin.ino +++ b/Firmware/RTK_Everywhere/Begin.ino @@ -240,6 +240,7 @@ void beginBoard() present.minCN0 = true; present.minElevation = true; present.dynamicModel = true; + present.display_type = DISPLAY_MAX_NONE; #ifdef COMPILE_IM19_IMU present.imu_im19 = true; // Allow tiltUpdate() to run diff --git a/Firmware/RTK_Everywhere/Developer.ino b/Firmware/RTK_Everywhere/Developer.ino index ba53bce3b..f04fd6b7d 100644 --- a/Firmware/RTK_Everywhere/Developer.ino +++ b/Firmware/RTK_Everywhere/Developer.ino @@ -66,6 +66,7 @@ void networkVerifyTables() {} //---------------------------------------- void ntripClientPrintStatus() {systemPrintln("**NTRIP Client not compiled**");} +void ntripClientSettingsChanged() {} void ntripClientStop(bool clientAllocated) {online.ntripClient = false;} void ntripClientUpdate() {} void ntripClientValidateTables() {} diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index 2979d54a7..b113dce04 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -688,6 +688,7 @@ bool createGNSSPassthrough() { return createPassthrough("/updateGnssFirmware.txt"); } + bool createPassthrough(const char *filename) { if (online.fs == false) @@ -695,18 +696,21 @@ bool createPassthrough(const char *filename) if (LittleFS.exists(filename)) { - if (settings.debugGnss) + if (settings.debugGnssConfig) systemPrintf("LittleFS %s already exists\r\n", filename); return true; } - File updateUm980Firmware = LittleFS.open(filename, FILE_WRITE); - updateUm980Firmware.close(); + if (settings.debugGnssConfig) + systemPrintf("Creating passthrough file: %s \r\n", filename); + + File simpleFile = LittleFS.open(filename, FILE_WRITE); + simpleFile.close(); if (LittleFS.exists(filename)) return true; - if (settings.debugGnss) + if (settings.debugGnssConfig) systemPrintf("Unable to create %s on LittleFS\r\n", filename); return false; } @@ -833,17 +837,22 @@ bool gnssFirmwareCheckUpdateFile(const char *filename) //---------------------------------------- void gnssFirmwareRemoveUpdate() { - return gnssFirmwareRemoveUpdateFile("/updateGnssFirmware.txt"); + gnssFirmwareRemoveUpdateFile("/updateGnssFirmware.txt"); } + void gnssFirmwareRemoveUpdateFile(const char *filename) { if (online.fs == false) return; + if (settings.debugGnssConfig) + systemPrintf("Removing passthrough file: %s \r\n", filename); + + Serial.println("1"); if (LittleFS.exists(filename)) { - if (settings.debugGnss) - systemPrintf("Removing %s\r\n", filename); + Serial.println("2"); + delay(50); LittleFS.remove(filename); } diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino index 84d066615..b5809e0a1 100644 --- a/Firmware/RTK_Everywhere/GNSS_UM980.ino +++ b/Firmware/RTK_Everywhere/GNSS_UM980.ino @@ -85,7 +85,7 @@ void GNSS_UM980::begin() if (_um980->begin(*serialGNSS) == false) // Give the serial port over to the library { - if (settings.debugGnss) + if (settings.debugGnssConfig) systemPrintln("GNSS UM980 failed to begin. Trying again."); // Try again with power on delay @@ -179,8 +179,7 @@ bool GNSS_UM980::configureBase() // a surveyInStart(). gnssConfigure(GNSS_CONFIG_MODEL); - // Request receiver to use new settings - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); + // Request a change to Base RTCM gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); return (true); @@ -189,53 +188,35 @@ bool GNSS_UM980::configureBase() //---------------------------------------- bool GNSS_UM980::configureOnce() { - /* - Set COM port baud rates, - UM980 COM1 - Connected to ESP32 through switches. Not used. - UM980 COM2 - To IMU. - UM980 COM3 - BT, config and LoRa Radio. Configured for 115200 from begin(). - Set minCN0 - Set elevationAngle - Set Constellations - Set messages - Enable selected NMEA messages on COM3 - Enable selected RTCM messages on COM3 -*/ bool response = true; - response &= setBaudRate(2, 115200); // UM980 UART2 is connected to the IMU - if (response == false) - systemPrintln("setBaudRate failed"); - // Assume if we've made it this far, the UM980 UART3 is communicating - // response &= setBaudRateComm(115200); // UM980 UART3 is connected to the switch, then ESP32 + if (settings.debugGnssConfig) + systemPrintln("Configuring UM980"); - // Signal group control is not currently exposed to the user, thus is not configured using gnssConfigure() // Read, modify, write - if (_um980->isConfigurationPresent("CONFIG SIGNALGROUP 2") == false) + + // Output must be disabled before sending SIGNALGROUP command in order to get the OK response + disableAllOutput(); // Disable COM1/2/3 + + if (_um980->sendCommand("CONFIG SIGNALGROUP 2") == false) { - // Output must be disabled before sending SIGNALGROUP command in order to get the OK response - disableAllOutput(); // Disable COM1/2/3 + systemPrintln("Signal group 2 command failed"); + response = false; + } + else + { + systemPrintln("Enabling additional reception on UM980. This can take a few seconds."); - if (_um980->sendCommand("CONFIG SIGNALGROUP 2") == false) + while (1) { - systemPrintln("Signal group 2 command failed"); - response = false; + delay(1000); // Wait for device to reboot + if (_um980->isConnected()) + break; + else + systemPrintln("UM980 rebooting"); } - else - { - systemPrintln("Enabling additional reception on UM980. This can take a few seconds."); - while (1) - { - delay(1000); // Wait for device to reboot - if (_um980->isConnected()) - break; - else - systemPrintln("UM980 rebooting"); - } - - systemPrintln("UM980 has completed reboot."); - } + systemPrintln("UM980 has completed reboot."); } if (response) @@ -299,8 +280,7 @@ bool GNSS_UM980::configureRover() // Sets the dynamic model (Survey/UAV/Automotive) and puts the device into Rover mode gnssConfigure(GNSS_CONFIG_MODEL); - // Request a change to NMEA and Rover RTCM - gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); + // Request a change to Rover RTCM gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); return (true); @@ -364,7 +344,7 @@ void GNSS_UM980::debuggingEnable() // Turn off all NMEA and RTCM void GNSS_UM980::disableAllOutput() { - if (settings.debugGnss) + if (settings.debugGnssConfig) systemPrintln("UM980 disable output"); // Turn off local noise before moving to other ports @@ -712,7 +692,13 @@ uint8_t GNSS_UM980::getMinute() uint8_t GNSS_UM980::getMode() { if (online.gnss) - return (_um980->getMode()); + { + int mode = _um980->getMode(); + if (settings.debugGnssConfig) + systemPrintf("getMode(): %d\r\n", mode); + + return (mode); + } return (0); } @@ -1466,7 +1452,7 @@ bool GNSS_UM980::setConstellations() response &= _um980->enableConstellation(um980ConstellationCommands[constellationNumber].textCommand); if (response == false) { - if (settings.debugGnss) + if (settings.debugGnssConfig) systemPrintf("setConstellations failed to enable constellation %s [%d].\r\n", um980ConstellationCommands[constellationNumber].textName, constellationNumber); return (false); // Don't attempt other messages, assume communication is down @@ -1478,7 +1464,7 @@ bool GNSS_UM980::setConstellations() if (response == false) { - if (settings.debugGnss) + if (settings.debugGnssConfig) systemPrintf("setConstellations failed to disable constellation %s [%d].\r\n", um980ConstellationCommands[constellationNumber].textName, constellationNumber); return (false); // Don't attempt other messages, assume communication is down @@ -1642,7 +1628,7 @@ bool GNSS_UM980::setMessagesNMEA() if (response == false) { - if (settings.debugGnss) + if (settings.debugGnssConfig) systemPrintf("setMessagesNMEA failed to set %0.2f for message %s [%d].\r\n", settings.um980MessageRatesNMEA[messageNumber], umMessagesNMEA[messageNumber].msgTextName, messageNumber); @@ -1712,7 +1698,7 @@ bool GNSS_UM980::setMessagesRTCMBase() if (response == false) { - if (settings.debugGnss) + if (settings.debugGnssConfig) systemPrintf("setMessagesRTCMBase failed to set %0.2f for message %s [%d].\r\n", settings.um980MessageRatesRTCMBase[messageNumber], umMessagesRTCM[messageNumber].msgTextName, messageNumber); @@ -1753,7 +1739,7 @@ bool GNSS_UM980::setMessagesRTCMRover() settings.um980MessageRatesRTCMRover[messageNumber]); if (response == false) { - if (settings.debugGnss) + if (settings.debugGnssConfig) systemPrintf("setMessagesRTCMRover failed to set %0.2f for message %s [%d].\r\n", settings.um980MessageRatesRTCMRover[messageNumber], umMessagesRTCM[messageNumber].msgTextName, messageNumber); @@ -1816,6 +1802,10 @@ bool GNSS_UM980::setModel(uint8_t modelNumber) return (_um980->setModeRoverUAV()); else if (modelNumber == UM980_DYN_MODEL_AUTOMOTIVE) return (_um980->setModeRoverAutomotive()); + else + { + systemPrintf("Uncaught model: %d\r\n", modelNumber); + } } return (false); } @@ -1922,13 +1912,13 @@ bool GNSS_UM980::setTilt() // Read, modify, write // The UM980 does not have a way to read the currently enabled messages so we do only a write - if (settings.enableTiltCompensation == true) { // Configure UM980 to output binary and NMEA reports out COM2, connected to IM19 COM3 response &= _um980->sendCommand("BESTPOSB COM2 0.2"); // 5Hz response &= _um980->sendCommand("PSRVELB COM2 0.2"); response &= _um980->setNMEAPortMessage("GPGGA", "COM2", 0.2); // 5Hz + response &= setBaudRate(2, 115200); // UM980 UART2 is connected to the IMU } else { @@ -2098,15 +2088,6 @@ bool GNSS_UM980::setRtcmRoverMessageRateByName(const char *msgName, uint8_t msgR //---------------------------------------- -//---------------------------------------- -// Force UART connection to GNSS for firmware update on the next boot by special file in -// LittleFS -//---------------------------------------- -bool createUm980Passthrough() -{ - return createPassthrough("/updateUm980Firmware.txt"); -} - //---------------------------------------- void um980FirmwareBeginUpdate() { @@ -2127,10 +2108,10 @@ void um980FirmwareBeginUpdate() // This makes our job much easier... // Flag that we are in direct connect mode. Button task will um980FirmwareRemoveUpdate and exit - inDirectConnectMode = true; + // inDirectConnectMode = true; // Paint GNSS Update - paintGnssUpdate(); + // paintGnssUpdate(); // Stop all UART tasks. Redundant tasksStopGnssUart(); @@ -2163,8 +2144,8 @@ void um980FirmwareBeginUpdate() while (1) { // Data coming from UM980 to external USB - if (serialGNSS->available()) // Note: use if, not while - Serial.write(serialGNSS->read()); + // if (serialGNSS->available()) // Note: use if, not while + // Serial.write(serialGNSS->read()); // Data coming from external USB to UM980 if (Serial.available()) // Note: use if, not while @@ -2188,16 +2169,48 @@ void um980FirmwareBeginUpdate() } } + if (digitalRead(pin_powerButton) == HIGH) + { + while (digitalRead(pin_powerButton) == HIGH) + delay(100); + + // Remove file and reset to exit pass-through mode + um980FirmwareRemoveUpdate(); + + // Beep to indicate exit + beepOn(); + delay(300); + beepOff(); + delay(100); + beepOn(); + delay(300); + beepOff(); + + systemPrintln("Exiting UM980 passthrough mode"); + systemFlush(); // Complete prints + + ESP.restart(); + } // Button task will um980FirmwareRemoveUpdate and restart } } +const char *um980FirmwareFileName = "/updateUm980Firmware.txt"; + +//---------------------------------------- +// Force UART connection to GNSS for firmware update on the next boot by special file in LittleFS +//---------------------------------------- +bool um980CreatePassthrough() +{ + return createPassthrough(um980FirmwareFileName); +} + //---------------------------------------- // Check if direct connection file exists //---------------------------------------- bool um980FirmwareCheckUpdate() { - return gnssFirmwareCheckUpdateFile("/updateUm980Firmware.txt"); + return gnssFirmwareCheckUpdateFile(um980FirmwareFileName); } //---------------------------------------- @@ -2205,7 +2218,7 @@ bool um980FirmwareCheckUpdate() //---------------------------------------- void um980FirmwareRemoveUpdate() { - return gnssFirmwareRemoveUpdateFile("/updateUm980Firmware.txt"); + gnssFirmwareRemoveUpdateFile(um980FirmwareFileName); } //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/NtripClient.ino b/Firmware/RTK_Everywhere/NtripClient.ino index 762d5f80d..f541b141e 100644 --- a/Firmware/RTK_Everywhere/NtripClient.ino +++ b/Firmware/RTK_Everywhere/NtripClient.ino @@ -200,7 +200,7 @@ unsigned long lastGGAPush; bool ntripClientForcedShutdown = false; // NTRIP Client was turned off due to an error. Don't allow restart. -bool ntripClientSettingsChange = false; // Goes true when a menu or command modified the client credentials +bool settingsChanged = false; // Goes true when a menu or command modified the client credentials //---------------------------------------- // NTRIP Client Routines @@ -395,9 +395,9 @@ bool ntripClientEnabled(const char **line) enabled = settings.enableNtripClient; // Allow restart if settings change - if(ntripClientSettingsChange == true) + if(settingsChanged == true) { - ntripClientSettingsChange = false; + settingsChanged = false; ntripClientForcedShutdown = false; } @@ -568,6 +568,12 @@ void ntripClientSetState(uint8_t newState) } } +// Called from CLI call backs or serial menus to let machine know it can restart the client if it is shut down +void ntripClientSettingsChanged() +{ + settingsChanged = true; +} + //---------------------------------------- // Start the NTRIP client //---------------------------------------- @@ -881,9 +887,9 @@ void ntripClientUpdate() } // Check if the there have been changes to the client settings - if(ntripClientSettingsChange == true) + if(settingsChanged == true) { - ntripClientSettingsChange = false; + settingsChanged = false; ntripClientRestart(); } // Check for timeout receiving NTRIP data diff --git a/Firmware/RTK_Everywhere/Tasks.ino b/Firmware/RTK_Everywhere/Tasks.ino index dd32892c2..4082e531d 100644 --- a/Firmware/RTK_Everywhere/Tasks.ino +++ b/Firmware/RTK_Everywhere/Tasks.ino @@ -2044,7 +2044,7 @@ void buttonCheckTask(void *e) thisButtonRelease = 0; doubleTap = false; - if (firstButtonThrownOut == false) + if (firstButtonThrownOut == false && present.display_type != DISPLAY_MAX_NONE) firstButtonThrownOut = true; // Throw away the first button press else singleTap = true; diff --git a/Firmware/RTK_Everywhere/menuGNSS.ino b/Firmware/RTK_Everywhere/menuGNSS.ino index 2e0f30a05..8d5e046c7 100644 --- a/Firmware/RTK_Everywhere/menuGNSS.ino +++ b/Firmware/RTK_Everywhere/menuGNSS.ino @@ -316,7 +316,7 @@ void menuGNSS() systemPrint("Enter new Caster Address: "); getUserInputString(settings.ntripClient_CasterHost, sizeof(settings.ntripClient_CasterHost)); - ntripClientSettingsChange = true; // Notify the NTRIP Client state machine of new credentials + ntripClientSettingsChanged(); // Notify the NTRIP Client state machine of new credentials } else if ((incoming == 9) && settings.enableNtripClient == true) { @@ -324,32 +324,32 @@ void menuGNSS() if (getNewSetting("Enter new Caster Port", 1, 99999, &settings.ntripClient_CasterPort) == INPUT_RESPONSE_VALID) { - ntripClientSettingsChange = true; // Notify the NTRIP Client state machine of new credentials + ntripClientSettingsChanged(); // Notify the NTRIP Client state machine of new credentials } } else if ((incoming == 10) && settings.enableNtripClient == true) { systemPrintf("Enter user name for %s: ", settings.ntripClient_CasterHost); getUserInputString(settings.ntripClient_CasterUser, sizeof(settings.ntripClient_CasterUser)); - ntripClientSettingsChange = true; // Notify the NTRIP Client state machine of new credentials + ntripClientSettingsChanged(); // Notify the NTRIP Client state machine of new credentials } else if ((incoming == 11) && settings.enableNtripClient == true) { systemPrintf("Enter user password for %s: ", settings.ntripClient_CasterHost); getUserInputString(settings.ntripClient_CasterUserPW, sizeof(settings.ntripClient_CasterUserPW)); - ntripClientSettingsChange = true; // Notify the NTRIP Client state machine of new credentials + ntripClientSettingsChanged(); // Notify the NTRIP Client state machine of new credentials } else if ((incoming == 12) && settings.enableNtripClient == true) { systemPrint("Enter new Mount Point: "); getUserInputString(settings.ntripClient_MountPoint, sizeof(settings.ntripClient_MountPoint)); - ntripClientSettingsChange = true; // Notify the NTRIP Client state machine of new credentials + ntripClientSettingsChanged(); // Notify the NTRIP Client state machine of new credentials } else if ((incoming == 13) && settings.enableNtripClient == true) { systemPrintf("Enter password for Mount Point %s: ", settings.ntripClient_MountPoint); getUserInputString(settings.ntripClient_MountPointPW, sizeof(settings.ntripClient_MountPointPW)); - ntripClientSettingsChange = true; // Notify the NTRIP Client state machine of new credentials + ntripClientSettingsChanged(); // Notify the NTRIP Client state machine of new credentials } else if ((incoming == 14) && settings.enableNtripClient == true) { diff --git a/Firmware/RTK_Everywhere/menuSystem.ino b/Firmware/RTK_Everywhere/menuSystem.ino index 9fd573e9e..2b9304b71 100644 --- a/Firmware/RTK_Everywhere/menuSystem.ino +++ b/Firmware/RTK_Everywhere/menuSystem.ino @@ -571,7 +571,7 @@ void menuDebugHardware() if (present.gnss_um980) { // Create a file in LittleFS - if (createUm980Passthrough() == true) + if (um980CreatePassthrough() == true) { systemPrintln(); systemPrintln("UM980 passthrough mode has been recorded to LittleFS. Device will now reset."); From 5bc71582bd581868d017f3fc7c732083a50c756a Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 6 Nov 2025 14:34:36 -0700 Subject: [PATCH 59/68] Remove X2 override --- Firmware/RTK_Everywhere/Begin.ino | 22 ++++++++++++---------- Firmware/RTK_Everywhere/RTK_Everywhere.ino | 1 - 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Firmware/RTK_Everywhere/Begin.ino b/Firmware/RTK_Everywhere/Begin.ino index baff53137..23b90e1c8 100644 --- a/Firmware/RTK_Everywhere/Begin.ino +++ b/Firmware/RTK_Everywhere/Begin.ino @@ -163,11 +163,6 @@ void identifyBoard() systemPrintln("<<<<<<<<<< !!!!!!!!!! FLEX OVERRIDE !!!!!!!!!! >>>>>>>>>>"); productVariant = RTK_FLEX; // TODO remove once v1.1 Flex has ID resistors #endif - -#ifdef TORCH_X2_OVERRIDE - systemPrintln("<<<<<<<<<< !!!!!!!!!! TORCH X2 OVERRIDE !!!!!!!!!! >>>>>>>>>>"); - productVariant = RTK_TORCH_X2; // TODO remove once v1.1 Torch X2 has ID resistors -#endif } if (ENABLE_DEVELOPER) @@ -791,7 +786,8 @@ void beginBoard() present.gnss_to_uart = true; present.gpioExpanderSwitches = true; - // present.microSd = true; // TODO remove comment out - v1.0 hardware does not have pullup on #CD so card detection does not work + // present.microSd = true; // TODO remove comment out - v1.0 hardware does not have pullup on #CD so card + // detection does not work present.microSdCardDetectLow = true; present.display_i2c0 = true; @@ -872,7 +868,7 @@ void beginBoard() present.antennaPhaseCenter_mm = 116.5; // Default to Torch helical APC, average of L1/L2 present.fuelgauge_bq40z50 = true; present.charger_mp2762a = true; - present.button_powerHigh = true; // Button is pressed when high + present.button_powerLow = true; // Button is pressed when low present.beeper = true; present.gnss_to_uart = true; present.needsExternalPpl = true; // Uses the PointPerfect Library @@ -1540,9 +1536,15 @@ void beginButtons() else { // Use the Button library - // Facet main/power button - if (present.button_powerLow == true && pin_powerSenseAndControl != PIN_UNDEFINED) - userBtn = new Button(pin_powerSenseAndControl); + if (present.button_powerLow == true) + { + // Torch X2 has both a powerButton and powerSenseAndControl (PWRKILL). Assign button task to powerButton. + if (pin_powerButton != PIN_UNDEFINED) + userBtn = new Button(pin_powerButton); + // Facet main/power button + else if (pin_powerSenseAndControl != PIN_UNDEFINED) + userBtn = new Button(pin_powerSenseAndControl); + } // Torch main/power button if (present.button_powerHigh == true && pin_powerButton != PIN_UNDEFINED) diff --git a/Firmware/RTK_Everywhere/RTK_Everywhere.ino b/Firmware/RTK_Everywhere/RTK_Everywhere.ino index 5c6c557c4..f9cd11c3d 100644 --- a/Firmware/RTK_Everywhere/RTK_Everywhere.ino +++ b/Firmware/RTK_Everywhere/RTK_Everywhere.ino @@ -80,7 +80,6 @@ // While we wait for the next hardware revisions, Flex and Torch can be manually enabled: //#define FLEX_OVERRIDE // Uncomment to force support for Flex -//#define TORCH_X2_OVERRIDE // Uncomment to force support for Torch X2 // To reduce compile times, various parts of the firmware can be disabled/removed if they are not // needed during development From dc746fb58219e070e236348172b331f3e1fa9e2d Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 6 Nov 2025 14:35:25 -0700 Subject: [PATCH 60/68] Fix merge issues after update from RC --- Firmware/RTK_Everywhere/Bluetooth.ino | 4 ++-- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 4 +++- Firmware/RTK_Everywhere/WiFi.ino | 2 +- Firmware/RTK_Everywhere/menuMessages.ino | 4 ++-- Firmware/RTK_Everywhere/settings.h | 10 +++++----- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Firmware/RTK_Everywhere/Bluetooth.ino b/Firmware/RTK_Everywhere/Bluetooth.ino index 2272c8d21..f579e5b89 100644 --- a/Firmware/RTK_Everywhere/Bluetooth.ino +++ b/Firmware/RTK_Everywhere/Bluetooth.ino @@ -29,6 +29,8 @@ static volatile BTState bluetoothState = BT_OFF; +BluetoothRadioType_e bluetoothRadioPreviousOnType = BLUETOOTH_RADIO_OFF; + #ifdef COMPILE_BT #include @@ -48,8 +50,6 @@ BleBatteryService bluetoothBatteryService; TaskHandle_t bluetoothCommandTaskHandle = nullptr; // Task to monitor incoming CLI from BLE -BluetoothRadioType_e bluetoothRadioPreviousOnType = BLUETOOTH_RADIO_OFF; - #endif // COMPILE_BT //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index 20439b56e..e7205ad9b 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -1889,6 +1889,8 @@ bool GNSS_LG290P::setHighAccuracyService(bool enableGalileoHas) // TODO - We should read/modify/write on PQTMCFGPPP + bool result = true; + // Enable E6 and PPP if enabled if (enableGalileoHas) { @@ -1899,7 +1901,7 @@ bool GNSS_LG290P::setHighAccuracyService(bool enableGalileoHas) // Enable E6 HAS, WGS84, 120 timeout, 0.10m Horizontal convergence accuracy threshold, 0.15m Vertical // threshold char paramConfigurePPP[sizeof(settings.configurePPP) + 4]; - snprintf(paramConfigurePPP, sizeof(paramConfigurePPP), ",W,%s", configPppSpacesToCommas(configurePPP)); + snprintf(paramConfigurePPP, sizeof(paramConfigurePPP), ",W,%s", configPppSpacesToCommas(settings.configurePPP)); if (_lg290p->sendOkCommand("$PQTMCFGPPP", paramConfigurePPP) == true) { systemPrintln("Galileo E6 HAS service enabled"); diff --git a/Firmware/RTK_Everywhere/WiFi.ino b/Firmware/RTK_Everywhere/WiFi.ino index 6b409d5d2..f037753d7 100644 --- a/Firmware/RTK_Everywhere/WiFi.ino +++ b/Firmware/RTK_Everywhere/WiFi.ino @@ -1266,7 +1266,7 @@ void wifiUpdateSettings() //********************************************************************* // Determine if any of the WiFi station SSID values are set -bool wifiAfterCommand(int cmdIndex) +bool wifiAfterCommand(const char *settingName, void *settingData, int settingType) { wifiUpdateSettings(); return true; diff --git a/Firmware/RTK_Everywhere/menuMessages.ino b/Firmware/RTK_Everywhere/menuMessages.ino index 7fba125f9..fb7bd3e27 100644 --- a/Firmware/RTK_Everywhere/menuMessages.ino +++ b/Firmware/RTK_Everywhere/menuMessages.ino @@ -270,7 +270,7 @@ void menuMessagesBaseRTCM() if (elevation >= -90 && elevation <= 90) { settings.rtcmMinElev = elevation; - restartBase = true; + gnssConfigure(GNSS_CONFIG_ELEVATION); // Request receiver to use new settings } } @@ -888,7 +888,7 @@ void checkGNSSArrayDefaults() } else if (present.gnss_lg290p) { - settings.minCNO = 10; // Default 10 dBHz + settings.minCN0 = 10; // Default 10 dBHz settings.surveyInStartingAccuracy = 2.0; // Default 2m settings.measurementRateMs = 500; // Default 2Hz. } diff --git a/Firmware/RTK_Everywhere/settings.h b/Firmware/RTK_Everywhere/settings.h index 277dd7a46..611ddf5a4 100644 --- a/Firmware/RTK_Everywhere/settings.h +++ b/Firmware/RTK_Everywhere/settings.h @@ -1205,7 +1205,7 @@ typedef enum typedef bool (* AFTER_CMD)(const char *settingName, void *settingData, int settingType); // Forward routines -bool wifiAfterCommand(int cmdIndex); +bool wifiAfterCommand(const char *settingName, void *settingData, int settingType); typedef struct { @@ -1799,10 +1799,10 @@ const RTK_Settings_Entry rtkSettingsEntries[] = // WiFi { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.debugWebServer, "debugWebServer", nullptr, }, { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.debugWifiState, "debugWifiState", nullptr, }, - { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.enableCaptivePortal, "enableCaptivePortal", wifiAfterCommand, }, - { 0, 1, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _uint8_t, 0, & settings.wifiChannel, "wifiChannel", wifiAfterCommand, }, - { 1, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.wifiConfigOverAP, "wifiConfigOverAP", wifiAfterCommand, }, - { 1, 1, 1, 1, 1, 1, 1, 1, 1, ALL, 1, tWiFiNet, MAX_WIFI_NETWORKS, & settings.wifiNetworks, "wifiNetwork_", wifiAfterCommand, }, + { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.enableCaptivePortal, "enableCaptivePortal", nullptr, }, + { 0, 1, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _uint8_t, 0, & settings.wifiChannel, "wifiChannel", nullptr, }, + { 1, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.wifiConfigOverAP, "wifiConfigOverAP", nullptr, }, + { 1, 1, 1, 1, 1, 1, 1, 1, 1, ALL, 1, tWiFiNet, MAX_WIFI_NETWORKS, & settings.wifiNetworks, "wifiNetwork_", nullptr, }, { 0, 0, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _uint32_t, 0, & settings.wifiConnectTimeoutMs, "wifiConnectTimeoutMs", nullptr, }, { 0, 1, 0, 1, 1, 1, 1, 1, 1, ALL, 1, _bool, 0, & settings.outputTipAltitude, "outputTipAltitude", nullptr, }, From 6a190c21a90d8efcd1497e703cdf7bb7f6e6dc83 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 6 Nov 2025 16:09:46 -0700 Subject: [PATCH 61/68] Make power button work. Detect CoAuth if it's alone on the bus. --- Firmware/RTK_Everywhere/Begin.ino | 17 +++++++++++++---- Firmware/RTK_Everywhere/menuMessages.ino | 6 +++++- Firmware/RTK_Everywhere/settings.h | 2 +- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Firmware/RTK_Everywhere/Begin.ino b/Firmware/RTK_Everywhere/Begin.ino index 23b90e1c8..2f95d1ec9 100644 --- a/Firmware/RTK_Everywhere/Begin.ino +++ b/Firmware/RTK_Everywhere/Begin.ino @@ -94,7 +94,7 @@ void identifyBoard() // 0x08 - HUSB238 - USB C PD Sink Controller bool husb238Present = i2cIsDevicePresent(i2c_0, 0x08); - // 0x10 -MFI343S00177 Authentication Coprocessor + // 0x10 - MFI343S00177 Authentication Coprocessor bool mfiPresent = i2cIsDevicePresent(i2c_0, 0x10); i2c_0->end(); @@ -447,7 +447,6 @@ void beginBoard() // Facet V2 is based on the ESP32-WROVER // ZED-F9P is interfaced via I2C and UART1 // NEO-D9S is interfaced via I2C. UART2 TX is also connected to ESP32 pin 4 - // TODO: pass PMP over serial to save I2C traffic? // Specify the GNSS radio #ifdef COMPILE_ZED @@ -872,6 +871,8 @@ void beginBoard() present.beeper = true; present.gnss_to_uart = true; present.needsExternalPpl = true; // Uses the PointPerfect Library + present.fastPowerOff = true; + present.invertedFastPowerOff = true; // Driving PWRKILL high will cause powerdown // We can't enable GNSS features here because we don't know if lg290pFirmwareVersion is >= v05 // present.minElevation = true; @@ -884,7 +885,7 @@ void beginBoard() pin_GnssUart_TX = 17; pin_GNSS_DR_Reset = 22; // Push low to reset GNSS/DR. - pin_GNSS_TimePulse = 39; // PPS on UM980 + pin_GNSS_TimePulse = 39; // PPS on LG290P pin_usbSelect = 12; // Controls U18 switch between ESP UART0 to USB or GNSS UART1 pin_powerAdapterDetect = 36; // Goes low when USB cable is plugged in @@ -896,12 +897,14 @@ void beginBoard() pin_beeper = 33; pin_powerButton = 34; - // pin_powerSenseAndControl = 18; // PWRKILL + pin_powerFastOff = 18; // PWRKILL pin_loraRadio_power = 19; // LoRa_EN // pin_loraRadio_boot = 23; // LoRa_BOOT0 // pin_loraRadio_reset = 5; // LoRa_NRST + pinMode(pin_powerFastOff, INPUT); // Leave this as an input. powerDown() will drive high for fast power off + DMW_if systemPrintf("pin_bluetoothStatusLED: %d\r\n", pin_bluetoothStatusLED); pinMode(pin_bluetoothStatusLED, OUTPUT); @@ -1808,6 +1811,12 @@ bool i2cBusInitialization(TwoWire *i2cBus, int sda, int scl, int clockKHz) // SDA/VCC shorted: 1000ms, response 5 // SDA/GND shorted: 14ms, response 5 timer = millis(); + + // If there is nothing else on the bus, the authentication coprocessor can be asleep + // Ping it twice to be sure + if (addr == 0x10) + i2cIsDevicePresent(i2cBus, addr); // Throw away result. Just wake it up. + if (i2cIsDevicePresent(i2cBus, addr)) { if (deviceFound == false) diff --git a/Firmware/RTK_Everywhere/menuMessages.ino b/Firmware/RTK_Everywhere/menuMessages.ino index fb7bd3e27..345c921c9 100644 --- a/Firmware/RTK_Everywhere/menuMessages.ino +++ b/Firmware/RTK_Everywhere/menuMessages.ino @@ -809,9 +809,13 @@ void checkGNSSArrayDefaults() #ifdef COMPILE_LG290P else if (present.gnss_lg290p) { + // This setting is not supported on the Torch X2 nor is it in the command array + // so it does not get used nor recorded to NVM leading to the defaults being + // applied at every boot. if (settings.enableExtCorrRadio == 254) { - defaultsApplied = true; + if(productVariant != RTK_TORCH_X2) // Prevent defaults from being applied if this *is* a Torch X2 + defaultsApplied = true; settings.enableExtCorrRadio = false; } diff --git a/Firmware/RTK_Everywhere/settings.h b/Firmware/RTK_Everywhere/settings.h index 611ddf5a4..e56a3281c 100644 --- a/Firmware/RTK_Everywhere/settings.h +++ b/Firmware/RTK_Everywhere/settings.h @@ -1779,13 +1779,13 @@ const RTK_Settings_Entry rtkSettingsEntries[] = // i d i v V i c n r e X // g s x k 2 c h d d x 2 Type Qual Variable Name afterSetCmd - // UM980 GNSS Receiver - TODO these apply to more than UM980 { 1, 1, 0, 0, 0, 0, 1, 0, 1, HAS, 1, _bool, 0, & settings.enableGalileoHas, "enableGalileoHas", nullptr, }, { 1, 1, 0, 0, 0, 0, 1, 0, 0, ALL, 0, _bool, 3, & settings.enableMultipathMitigation, "enableMultipathMitigation", nullptr, }, { 0, 0, 0, 0, 0, 0, 1, 0, 0, ALL, 0, _bool, 0, & settings.enableImuCompensationDebug, "enableImuCompensationDebug", nullptr, }, { 0, 0, 0, 0, 0, 0, 1, 0, 0, ALL, 0, _bool, 0, & settings.enableImuDebug, "enableImuDebug", nullptr, }, { 1, 1, 0, 0, 0, 0, 1, 0, 0, ALL, 0, _bool, 0, & settings.enableTiltCompensation, "enableTiltCompensation", nullptr, }, + // UM980 GNSS Receiver #ifdef COMPILE_UM980 { 1, 1, 1, 0, 0, 0, 1, 0, 0, U98, 0, tUmConst, MAX_UM980_CONSTELLATIONS, & settings.um980Constellations, "constellation_", gnssCmdUpdateConstellations, }, { 0, 1, 1, 0, 0, 0, 1, 0, 0, U98, 0, tUmMRNmea, MAX_UM980_NMEA_MSG, & settings.um980MessageRatesNMEA, "messageRateNMEA_", gnssCmdUpdateMessageRates, }, From 68c138220cacd91a2e916739bc4acbbc4343d980 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Fri, 7 Nov 2025 15:16:52 -0700 Subject: [PATCH 62/68] Add Torch X2 to button task --- Firmware/RTK_Everywhere/Tasks.ino | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Firmware/RTK_Everywhere/Tasks.ino b/Firmware/RTK_Everywhere/Tasks.ino index a9f6c1a36..0bad58076 100644 --- a/Firmware/RTK_Everywhere/Tasks.ino +++ b/Firmware/RTK_Everywhere/Tasks.ino @@ -2094,9 +2094,9 @@ void buttonCheckTask(void *e) } } // Torch is a special case. Handle tilt stop and web config mode - else if (productVariant == RTK_TORCH) + else if (productVariant == RTK_TORCH || productVariant == RTK_TORCH_X2) { - // Platform has no display and tilt corrections, ie RTK Torch + // Platform has no display and possibly tilt corrections, ie RTK Torch and RTK Torch X2 // In in tilt mode, exit on button press if ((singleTap || doubleTap) && (tiltIsCorrecting() == true)) @@ -2169,10 +2169,14 @@ void buttonCheckTask(void *e) // from firing } + // If we have fast power off, use it + if (present.fastPowerOff == true) + powerDown(false); //Don't display info + while (1) ; } - } // End productVariant == Torch + } // End productVariant == Torch/Torch X2 else // RTK EVK, RTK Facet v2, RTK Facet mosaic, RTK Postcard { if (systemState == STATE_SHUTDOWN) @@ -2335,7 +2339,7 @@ void buttonCheckTask(void *e) break; } // End doubleTap switch (systemState) } // End doubleTap - } // End productVariant != Torch + } // End productVariant != (Torch | Torch X2) feedWdt(); taskYIELD(); From 37eaa4ee1c96fe27812ecc613320d897b5db7234 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Fri, 7 Nov 2025 15:17:23 -0700 Subject: [PATCH 63/68] Whitespace --- Firmware/RTK_Everywhere/Tasks.ino | 266 +++++++++++++++--------------- 1 file changed, 129 insertions(+), 137 deletions(-) diff --git a/Firmware/RTK_Everywhere/Tasks.ino b/Firmware/RTK_Everywhere/Tasks.ino index 0bad58076..17350bc39 100644 --- a/Firmware/RTK_Everywhere/Tasks.ino +++ b/Firmware/RTK_Everywhere/Tasks.ino @@ -38,11 +38,11 @@ Tasks.ino // Macros //---------------------------------------- -#define WRAP_OFFSET(offset, increment, arraySize) \ - { \ - offset += increment; \ - if (offset >= arraySize) \ - offset -= arraySize; \ +#define WRAP_OFFSET(offset, increment, arraySize) \ + { \ + offset += increment; \ + if (offset >= arraySize) \ + offset -= arraySize; \ } //---------------------------------------- @@ -62,12 +62,7 @@ enum RingBufferConsumers }; const char *const ringBufferConsumer[] = { - "Bluetooth", - "TCP Client", - "TCP Server", - "SD Card", - "UDP Server", - "USB Serial", + "Bluetooth", "TCP Client", "TCP Server", "SD Card", "UDP Server", "USB Serial", }; const int ringBufferConsumerEntries = sizeof(ringBufferConsumer) / sizeof(ringBufferConsumer[0]); @@ -81,21 +76,13 @@ const int ringBufferConsumerEntries = sizeof(ringBufferConsumer) / sizeof(ringBu // List the parsers to be included SEMP_PARSE_ROUTINE const parserTable[] = { - sempNmeaPreamble, - sempUnicoreHashPreamble, - sempRtcmPreamble, - sempUbloxPreamble, - sempUnicoreBinaryPreamble, + sempNmeaPreamble, sempUnicoreHashPreamble, sempRtcmPreamble, sempUbloxPreamble, sempUnicoreBinaryPreamble, }; const int parserCount = sizeof(parserTable) / sizeof(parserTable[0]); // List the names of the parsers const char *const parserNames[] = { - "NMEA", - "Unicore Hash_(#)", - "RTCM", - "u-Blox", - "Unicore Binary", + "NMEA", "Unicore Hash_(#)", "RTCM", "u-Blox", "Unicore Binary", }; const int parserNameCount = sizeof(parserNames) / sizeof(parserNames[0]); @@ -115,9 +102,9 @@ const char *const spartnParserNames[] = { }; const int spartnParserNameCount = sizeof(spartnParserNames) / sizeof(spartnParserNames[0]); -SEMP_PARSE_ROUTINE const rtcmParserTable[] = { sempRtcmPreamble }; +SEMP_PARSE_ROUTINE const rtcmParserTable[] = {sempRtcmPreamble}; const int rtcmParserCount = sizeof(rtcmParserTable) / sizeof(rtcmParserTable[0]); -const char *const rtcmParserNames[] = { "RTCM" }; +const char *const rtcmParserNames[] = {"RTCM"}; const int rtcmParserNameCount = sizeof(rtcmParserNames) / sizeof(rtcmParserNames[0]); //---------------------------------------- @@ -153,7 +140,7 @@ void btReadTask(void *e) unsigned long btLastByteReceived = 0; // Track when the last BT transmission was received. const long btMinEscapeTime = - 2000; // Bluetooth serial traffic must stop this amount before an escape char is recognized + 2000; // Bluetooth serial traffic must stop this amount before an escape char is recognized uint8_t btEscapeCharsReceived = 0; // Used to enter remote command mode // Start notification @@ -206,7 +193,6 @@ void btReadTask(void *e) } } - else // This character is not a command character, pass along to GNSS { // Pass any escape characters that turned out to not be a complete escape sequence @@ -280,7 +266,8 @@ void sendGnssBuffer() { if (correctionLastSeen(CORR_BLUETOOTH)) { - sempParseNextBytes(rtcmParse, bluetoothOutgoingToGnss, bluetoothOutgoingToGnssHead); // Parse the data for RTCM1005/1006 + sempParseNextBytes(rtcmParse, bluetoothOutgoingToGnss, + bluetoothOutgoingToGnssHead); // Parse the data for RTCM1005/1006 if (gnss->pushRawData(bluetoothOutgoingToGnss, bluetoothOutgoingToGnssHead)) { if ((settings.debugCorrections || PERIODIC_DISPLAY(PD_GNSS_DATA_TX)) && !inMainMenu) @@ -396,11 +383,12 @@ void gnssReadTask(void *e) sempSbfSetInvalidDataCallback(sbfParse, processNonSBFData); // Initialize the SPARTN parser for the mosaic-X5 - spartnParse = sempBeginParser(spartnParserTable, spartnParserCount, spartnParserNames, spartnParserNameCount, - 0, // Scratchpad bytes - 1200, // Buffer length - SPARTN payload is 1024 bytes max - processUart1SPARTN, // eom Call Back - in mosaic.ino - "spartnParse"); // Parser Name + spartnParse = + sempBeginParser(spartnParserTable, spartnParserCount, spartnParserNames, spartnParserNameCount, + 0, // Scratchpad bytes + 1200, // Buffer length - SPARTN payload is 1024 bytes max + processUart1SPARTN, // eom Call Back - in mosaic.ino + "spartnParse"); // Parser Name if (!spartnParse) reportFatalError("Failed to initialize the SPARTN parser"); @@ -499,7 +487,7 @@ void gnssReadTask(void *e) if (!expected) // SBF is not expected so restart the parsers { sbfParse->state = sempFirstByte; - if (spartnParserNeeded) + if (spartnParserNeeded) spartnParse->state = sempFirstByte; if (settings.debugGnss) systemPrintf("Unexpected SBF block %d - rejected on ID or length\r\n", @@ -540,7 +528,7 @@ void gnssReadTask(void *e) if (!expected) // SBF is not expected so restart the parsers { sbfParse->state = sempFirstByte; - if (spartnParserNeeded) + if (spartnParserNeeded) spartnParse->state = sempFirstByte; if (settings.debugGnss) systemPrintf("Unexpected EncapsulatedOutput block - rejected\r\n"); @@ -581,12 +569,12 @@ void forceTalkerId(const char *Id, char *msg, size_t maxLen) char oldTalker = msg[2]; msg[2] = *Id; // Force the Talker ID - + // Update the checksum: XOR chars between '$' and '*' size_t len = 1; uint8_t csum = 0; while ((len < maxLen) && (msg[len] != '*')) - csum = csum ^ msg[len++]; + csum = csum ^ msg[len++]; if (len >= (maxLen - 3)) { @@ -638,7 +626,7 @@ void forceRmcCog(char *msg, size_t maxLen) len = 1; uint8_t csum = 0; while ((len < maxLen) && (msg[len] != '*')) - csum = csum ^ msg[len++]; + csum = csum ^ msg[len++]; len++; // Point at the checksum and update it sprintf(&msg[len], "%02X", csum); } @@ -683,7 +671,7 @@ void removeRmcNavStat(char *msg, size_t maxLen) len = 1; uint8_t csum = 0; while ((len < maxLen) && (msg[len] != '*')) - csum = csum ^ msg[len++]; + csum = csum ^ msg[len++]; len++; // Point at the checksum and update it sprintf(&msg[len], "%02X", csum); } @@ -754,7 +742,7 @@ void processUart1Message(SEMP_PARSE_STATE *parse, uint16_t type) latestGPGGA[parse->length] = 0; // NULL terminate if ((strlen(latestGPGGA) > 10) && (latestGPGGA[strlen(latestGPGGA) - 2] == '\r')) latestGPGGA[strlen(latestGPGGA) - 2] = 0; // Truncate the \r\n - forceTalkerId("P",latestGPGGA,latestNmeaMaxLen); + forceTalkerId("P", latestGPGGA, latestNmeaMaxLen); } else systemPrintf("Increase latestNmeaMaxLen to > %d\r\n", parse->length); @@ -767,9 +755,9 @@ void processUart1Message(SEMP_PARSE_STATE *parse, uint16_t type) latestGPRMC[parse->length] = 0; // NULL terminate if ((strlen(latestGPRMC) > 10) && (latestGPRMC[strlen(latestGPRMC) - 2] == '\r')) latestGPRMC[strlen(latestGPRMC) - 2] = 0; // Truncate the \r\n - forceTalkerId("P",latestGPRMC,latestNmeaMaxLen); - forceRmcCog(latestGPRMC,latestNmeaMaxLen); - removeRmcNavStat(latestGPRMC,latestNmeaMaxLen); + forceTalkerId("P", latestGPRMC, latestNmeaMaxLen); + forceRmcCog(latestGPRMC, latestNmeaMaxLen); + removeRmcNavStat(latestGPRMC, latestNmeaMaxLen); } else systemPrintf("Increase latestNmeaMaxLen to > %d\r\n", parse->length); @@ -782,7 +770,7 @@ void processUart1Message(SEMP_PARSE_STATE *parse, uint16_t type) latestGPGST[parse->length] = 0; // NULL terminate if ((strlen(latestGPGST) > 10) && (latestGPGST[strlen(latestGPGST) - 2] == '\r')) latestGPGST[strlen(latestGPGST) - 2] = 0; // Truncate the \r\n - forceTalkerId("P",latestGPGST,latestNmeaMaxLen); + forceTalkerId("P", latestGPGST, latestNmeaMaxLen); } else systemPrintf("Increase latestNmeaMaxLen to > %d\r\n", parse->length); @@ -795,13 +783,13 @@ void processUart1Message(SEMP_PARSE_STATE *parse, uint16_t type) latestGPVTG[parse->length] = 0; // NULL terminate if ((strlen(latestGPVTG) > 10) && (latestGPVTG[strlen(latestGPVTG) - 2] == '\r')) latestGPVTG[strlen(latestGPVTG) - 2] = 0; // Truncate the \r\n - forceTalkerId("P",latestGPVTG,latestNmeaMaxLen); + forceTalkerId("P", latestGPVTG, latestNmeaMaxLen); } else systemPrintf("Increase latestNmeaMaxLen to > %d\r\n", parse->length); } - else if ((strstr(sempNmeaGetSentenceName(parse), "GSA") != nullptr) - || (strstr(sempNmeaGetSentenceName(parse), "GSV") != nullptr)) + else if ((strstr(sempNmeaGetSentenceName(parse), "GSA") != nullptr) || + (strstr(sempNmeaGetSentenceName(parse), "GSV") != nullptr)) { // If the Apple Accessory is sending the data to the EA Session, // discard this GSA / GSV. Bad things would happen if we were to @@ -811,14 +799,14 @@ void processUart1Message(SEMP_PARSE_STATE *parse, uint16_t type) { size_t spaceAvailable = latestEASessionDataMaxLen - strlen(latestEASessionData); if (spaceAvailable >= 3) - spaceAvailable -= 3; // Leave room for the CR, LF and NULL + spaceAvailable -= 3; // Leave room for the CR, LF and NULL while (spaceAvailable < parse->length) // If the buffer is full, delete the oldest message(s) { const char *lfPtr = strstr(latestEASessionData, "\n"); // Find the first LF if (lfPtr == nullptr) - break; // Something has gone badly wrong... - lfPtr++; // Point at the byte after the LF - size_t oldLen = lfPtr - latestEASessionData; // This much data is old + break; // Something has gone badly wrong... + lfPtr++; // Point at the byte after the LF + size_t oldLen = lfPtr - latestEASessionData; // This much data is old size_t newLen = strlen(latestEASessionData) - oldLen; // This much is new (not old) for (size_t i = 0; i <= newLen; i++) // Move the new data over the old. Include the NULL latestEASessionData[i] = latestEASessionData[oldLen + i]; @@ -830,14 +818,14 @@ void processUart1Message(SEMP_PARSE_STATE *parse, uint16_t type) latestEASessionData[dataLen] = 0; // NULL terminate if (latestEASessionData[dataLen - 1] != '\n') { - latestEASessionData[dataLen] = '\r'; // Add CR + latestEASessionData[dataLen] = '\r'; // Add CR latestEASessionData[dataLen + 1] = '\n'; // Add LF - latestEASessionData[dataLen + 2] = 0; // NULL terminate + latestEASessionData[dataLen + 2] = 0; // NULL terminate } } else if (settings.debugNetworkLayer) systemPrintf("Discarding %d GSA/GSV bytes - latestEASessionDataIsBlocking\r\n", parse->length); -#endif //COMPILE_AUTHENTICATION +#endif // COMPILE_AUTHENTICATION } } @@ -1014,8 +1002,8 @@ void processUart1Message(SEMP_PARSE_STATE *parse, uint16_t type) // Use a semaphore to prevent handleGnssDataTask from gatecrashing if (ringBufferSemaphore == NULL) - ringBufferSemaphore = xSemaphoreCreateMutex(); // Create the mutex - + ringBufferSemaphore = xSemaphoreCreateMutex(); // Create the mutex + // Take the semaphore. Long wait. handleGnssDataTask could block // Enable printing of the ring buffer offsets (s d 10) and the SD buffer sizes (s h 7) // to see this in action. No more gatecrashing! @@ -1044,54 +1032,54 @@ void processUart1Message(SEMP_PARSE_STATE *parse, uint16_t type) previousTail -= settings.gnssHandlerBufferSize; /* The rbOffsetArray holds the offsets into the ring buffer of the - * start of each of the parsed messages. A head (rbOffsetHead) and - * tail (rbOffsetTail) offsets are used for this array to insert and - * remove entries. Typically this task only manipulates the head as - * new messages are placed into the ring buffer. The handleGnssDataTask - * normally manipulates the tail as data is removed from the buffer. - * However this task will manipulate the tail under two conditions: - * - * 1. The ring buffer gets full and data must be discarded - * - * 2. The rbOffsetArray is too small to hold all of the message - * offsets for the data in the ring buffer. The array is full - * when (Head + 1) == Tail - * - * Notes: - * The rbOffsetArray is allocated along with the ring buffer in - * Begin.ino - * - * The first entry rbOffsetArray[0] is initialized to zero (0) - * in Begin.ino - * - * The array always has one entry in it containing the head offset - * which contains a valid offset into the ringBuffer, handled below - * - * The empty condition is Tail == Head - * - * The amount of data described by the rbOffsetArray is - * rbOffsetArray[Head] - rbOffsetArray[Tail] - * - * rbOffsetArray ringBuffer - * .-----------------. .-----------------. - * | | | | - * +-----------------+ | | - * Tail --> | Msg 1 Offset |---------->+-----------------+ <-- Tail n - * +-----------------+ | Msg 1 | - * | Msg 2 Offset |--------. | | - * +-----------------+ | | | - * | Msg 3 Offset |------. '->+-----------------+ - * +-----------------+ | | Msg 2 | - * Head --> | Head Offset |--. | | | - * +-----------------+ | | | | - * | | | | | | - * +-----------------+ | | | | - * | | | '--->+-----------------+ - * +-----------------+ | | Msg 3 | - * | | | | | - * +-----------------+ '------->+-----------------+ <-- dataHead - * | | | | - */ + * start of each of the parsed messages. A head (rbOffsetHead) and + * tail (rbOffsetTail) offsets are used for this array to insert and + * remove entries. Typically this task only manipulates the head as + * new messages are placed into the ring buffer. The handleGnssDataTask + * normally manipulates the tail as data is removed from the buffer. + * However this task will manipulate the tail under two conditions: + * + * 1. The ring buffer gets full and data must be discarded + * + * 2. The rbOffsetArray is too small to hold all of the message + * offsets for the data in the ring buffer. The array is full + * when (Head + 1) == Tail + * + * Notes: + * The rbOffsetArray is allocated along with the ring buffer in + * Begin.ino + * + * The first entry rbOffsetArray[0] is initialized to zero (0) + * in Begin.ino + * + * The array always has one entry in it containing the head offset + * which contains a valid offset into the ringBuffer, handled below + * + * The empty condition is Tail == Head + * + * The amount of data described by the rbOffsetArray is + * rbOffsetArray[Head] - rbOffsetArray[Tail] + * + * rbOffsetArray ringBuffer + * .-----------------. .-----------------. + * | | | | + * +-----------------+ | | + * Tail --> | Msg 1 Offset |---------->+-----------------+ <-- Tail n + * +-----------------+ | Msg 1 | + * | Msg 2 Offset |--------. | | + * +-----------------+ | | | + * | Msg 3 Offset |------. '->+-----------------+ + * +-----------------+ | | Msg 2 | + * Head --> | Head Offset |--. | | | + * +-----------------+ | | | | + * | | | | | | + * +-----------------+ | | | | + * | | | '--->+-----------------+ + * +-----------------+ | | Msg 3 | + * | | | | | + * +-----------------+ '------->+-----------------+ <-- dataHead + * | | | | + */ // Determine the index for the end of the circular ring buffer // offset list @@ -1200,7 +1188,8 @@ void processUart1Message(SEMP_PARSE_STATE *parse, uint16_t type) if (!inMainMenu) { if (consumer) - systemPrintf("Ring buffer full: discarding %d bytes, %s could be slow\r\n", discardedBytes, consumer); + systemPrintf("Ring buffer full: discarding %d bytes, %s could be slow\r\n", discardedBytes, + consumer); else systemPrintf("Ring buffer full: discarding %d bytes\r\n", discardedBytes); Serial.flush(); // TODO - delete me! @@ -1213,10 +1202,10 @@ void processUart1Message(SEMP_PARSE_STATE *parse, uint16_t type) if (bytesToCopy > (space + discardedBytes - 1)) // Sanity check { systemPrintf("Ring buffer update error %s: bytesToCopy (%d) is > space (%d) + discardedBytes (%d) - 1\r\n", - getTimeStamp(), bytesToCopy, space, discardedBytes); + getTimeStamp(), bytesToCopy, space, discardedBytes); Serial.flush(); // Flush Serial - the code is about to go bang...! } - + // Add another message to the ring buffer // Account for this message // Diagnostic prints are provided by settings.enablePrintSDBuffers and the handleGnssDataTask @@ -1269,7 +1258,8 @@ void processUart1Message(SEMP_PARSE_STATE *parse, uint16_t type) } else { - systemPrintf("processUart1Message could not get ringBuffer semaphore - held by %s\r\n", ringBufferSemaphoreHolder); + systemPrintf("processUart1Message could not get ringBuffer semaphore - held by %s\r\n", + ringBufferSemaphoreHolder); } } @@ -1364,8 +1354,8 @@ void handleGnssDataTask(void *e) // Use a semaphore to prevent handleGnssDataTask from gatecrashing if (ringBufferSemaphore == NULL) - ringBufferSemaphore = xSemaphoreCreateMutex(); // Create the mutex - + ringBufferSemaphore = xSemaphoreCreateMutex(); // Create the mutex + // Take the semaphore. Short wait. processUart1Message shouldn't block for long if (xSemaphoreTake(ringBufferSemaphore, ringBuffer_shortWait_ms) == pdPASS) { @@ -1554,7 +1544,7 @@ void handleGnssDataTask(void *e) // Block logging during Web Config to avoid SD collisions // See issue: https://github.com/sparkfun/SparkFun_RTK_Everywhere_Firmware/issues/693 - if(webServerIsRunning() == true) + if (webServerIsRunning() == true) connected = false; // If user wants to log, record to SD @@ -1583,15 +1573,17 @@ void handleGnssDataTask(void *e) int availableUARTSpace = settings.uartReceiveBufferSize - bufferAvailable; - systemPrintf("SD Incoming Serial @ %s: %04d\tToRead: %04d\tMovedToBuffer: %04d\tavailableUARTSpace: " - "%04d\tavailableHandlerSpace: %04d\tToRecord: %04d\tRecorded: %04d\tBO: %d\r\n", - getTimeStamp(), bufferAvailable, 0, 0, availableUARTSpace, availableHandlerSpace, - bytesToSend, 0, bufferOverruns); + systemPrintf( + "SD Incoming Serial @ %s: %04d\tToRead: %04d\tMovedToBuffer: " + "%04d\tavailableUARTSpace: " + "%04d\tavailableHandlerSpace: %04d\tToRecord: %04d\tRecorded: %04d\tBO: %d\r\n", + getTimeStamp(), bufferAvailable, 0, 0, availableUARTSpace, availableHandlerSpace, + bytesToSend, 0, bufferOverruns); } // For the SD card, we need to write everything we've got // to prevent the ARP Write and Events from gatecrashing... - + int32_t sendTheseBytes = bytesToSend; // Reduce bytes to record if we have more then the end of the buffer @@ -1610,8 +1602,8 @@ void handleGnssDataTask(void *e) if (bytesSent != sendTheseBytes) { - systemPrintf("SD write mismatch (1) @ %s: wrote %d bytes of %d\r\n", - getTimeStamp(), bytesSent, sendTheseBytes); + systemPrintf("SD write mismatch (1) @ %s: wrote %d bytes of %d\r\n", getTimeStamp(), + bytesSent, sendTheseBytes); break; // Exit the do loop } @@ -1629,8 +1621,8 @@ void handleGnssDataTask(void *e) if (bytesSent != sendTheseBytes) { - systemPrintf("SD write mismatch (2) @ %s: wrote %d bytes of %d\r\n", - getTimeStamp(), bytesSent, sendTheseBytes); + systemPrintf("SD write mismatch (2) @ %s: wrote %d bytes of %d\r\n", getTimeStamp(), + bytesSent, sendTheseBytes); break; // Exit the do loop } } @@ -1651,15 +1643,15 @@ void handleGnssDataTask(void *e) if ((settings.enablePrintLogFileStatus) && (!inMainMenu)) systemPrintln("Log file: recording event"); - // Record trigger count with Time Of Week of rising edge (ms), Millisecond fraction of Time Of Week of - // rising edge (ns), and accuracy estimate (ns) + // Record trigger count with Time Of Week of rising edge (ms), Millisecond fraction of + // Time Of Week of rising edge (ns), and accuracy estimate (ns) char eventData[82]; // Max NMEA sentence length is 82 - snprintf(eventData, sizeof(eventData), "%d,%d,%d,%d", triggerCount, triggerTowMsR, triggerTowSubMsR, - triggerAccEst); + snprintf(eventData, sizeof(eventData), "%d,%d,%d,%d", triggerCount, triggerTowMsR, + triggerTowSubMsR, triggerAccEst); char nmeaMessage[82]; // Max NMEA sentence length is 82 createNMEASentence(CUSTOM_NMEA_TYPE_EVENT, nmeaMessage, sizeof(nmeaMessage), - eventData); // textID, buffer, sizeOfBuffer, text + eventData); // textID, buffer, sizeOfBuffer, text logFile->write(nmeaMessage, strlen(nmeaMessage)); const char *crlf = "\r\n"; @@ -1691,7 +1683,7 @@ void handleGnssDataTask(void *e) char nmeaMessage[82]; // Max NMEA sentence length is 82 createNMEASentence(CUSTOM_NMEA_TYPE_ARP_ECEF_XYZH, nmeaMessage, sizeof(nmeaMessage), - ARPData); // textID, buffer, sizeOfBuffer, text + ARPData); // textID, buffer, sizeOfBuffer, text logFile->write(nmeaMessage, strlen(nmeaMessage)); const char *crlf = "\r\n"; @@ -1724,10 +1716,10 @@ void handleGnssDataTask(void *e) { if (deltaMillis > 150) systemPrintf("Long Write! Time: %ld ms / Location: %ld / Recorded %d bytes / " - "spaceRemaining %d bytes\r\n", - deltaMillis, logFileSize, bytesToSend, combinedSpaceRemaining); + "spaceRemaining %d bytes\r\n", + deltaMillis, logFileSize, bytesToSend, combinedSpaceRemaining); } - } while(0); + } while (0); xSemaphoreGive(sdCardSemaphore); } // End sdCardSemaphore @@ -1736,7 +1728,7 @@ void handleGnssDataTask(void *e) char semaphoreHolder[50]; getSemaphoreFunction(semaphoreHolder); log_w("sdCardSemaphore failed to yield for SD write, held by %s, Tasks.ino line %d", - semaphoreHolder, __LINE__); + semaphoreHolder, __LINE__); feedWdt(); taskYIELD(); @@ -1795,7 +1787,8 @@ void handleGnssDataTask(void *e) } else { - systemPrintf("handleGnssDataTask could not get ringBuffer semaphore - held by %s\r\n", ringBufferSemaphoreHolder); + systemPrintf("handleGnssDataTask could not get ringBuffer semaphore - held by %s\r\n", + ringBufferSemaphoreHolder); } //---------------------------------------------------------------------- @@ -2071,7 +2064,7 @@ void buttonCheckTask(void *e) // End button checking - // If in direct connect mode. Note: this is just a flag not a STATE. + // If in direct connect mode. Note: this is just a flag not a STATE. if (inDirectConnectMode) { // TODO: check if this works on both Torch and Flex. Note: Flex does not yet support buttons @@ -2171,7 +2164,7 @@ void buttonCheckTask(void *e) // If we have fast power off, use it if (present.fastPowerOff == true) - powerDown(false); //Don't display info + powerDown(false); // Don't display info while (1) ; @@ -2296,8 +2289,7 @@ void buttonCheckTask(void *e) { switch (systemState) { - case STATE_DISPLAY_SETUP: - { + case STATE_DISPLAY_SETUP: { // If we are displaying the setup menu, a single tap will cycle through possible system states - see // above Exit into new system state on double tap Exit display setup into previous state after ~10s // - see updateSystemState() @@ -2624,10 +2616,10 @@ void beginRtcmParse() { // Begin the RTCM parser - which will extract the base location from RTCM1005 / 1006 rtcmParse = sempBeginParser(rtcmParserTable, rtcmParserCount, rtcmParserNames, rtcmParserNameCount, - 0, // Scratchpad bytes - 1050, // Buffer length - processRTCMMessage, // eom Call Back - "rtcmParse"); // Parser Name + 0, // Scratchpad bytes + 1050, // Buffer length + processRTCMMessage, // eom Call Back + "rtcmParse"); // Parser Name if (!rtcmParse) reportFatalError("Failed to initialize the RTCM parser"); From 66d86d47e5ecffe3b1363362e21e7b2bb69ba1eb Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Fri, 7 Nov 2025 15:18:07 -0700 Subject: [PATCH 64/68] Update Flex with v1.1 hardware --- Firmware/RTK_Everywhere/Begin.ino | 14 ++++++++++---- Firmware/RTK_Everywhere/RTK_Everywhere.ino | 2 +- Firmware/RTK_Everywhere/System.ino | 5 ++--- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Firmware/RTK_Everywhere/Begin.ino b/Firmware/RTK_Everywhere/Begin.ino index 2f95d1ec9..ba2d4ed89 100644 --- a/Firmware/RTK_Everywhere/Begin.ino +++ b/Firmware/RTK_Everywhere/Begin.ino @@ -780,7 +780,7 @@ void beginBoard() present.charger_mp2762a = true; present.button_powerLow = true; // Button is pressed when high - // present.button_mode = true; //TODO remove comment. This won't be available until v1.1 of hardware + present.button_mode = true; present.beeper = true; present.gnss_to_uart = true; @@ -795,6 +795,9 @@ void beginBoard() present.displayInverted = true; present.tiltPossible = true; + present.fastPowerOff = true; + present.invertedFastPowerOff = true; // Drive POWER_KILL high to cause powerdown + pin_I2C0_SDA = 15; pin_I2C0_SCL = 4; @@ -802,7 +805,8 @@ void beginBoard() pin_GnssUart_TX = 27; pin_powerSenseAndControl = 34; - // pin_modeButton = 25; //TODO remove comment. This won't be available until v1.1 of hardware + pin_powerFastOff = 23; + pin_modeButton = 25; pin_IMU_RX = 14; // ESP32 UART2 pin_IMU_TX = 17; @@ -823,6 +827,9 @@ void beginBoard() pin_gpioExpanderInterrupt = 2; // TODO remove on v1.1 hardware. Not used since all GPIO expanded pins are outputs + digitalWrite(pin_powerFastOff, LOW); // Low = Stay on. High = turn off. + pinMode(pin_powerFastOff, OUTPUT); + DMW_if systemPrintf("pin_bluetoothStatusLED: %d\r\n", pin_bluetoothStatusLED); pinMode(pin_bluetoothStatusLED, OUTPUT); @@ -866,13 +873,12 @@ void beginBoard() present.gnss_lg290p = true; present.antennaPhaseCenter_mm = 116.5; // Default to Torch helical APC, average of L1/L2 present.fuelgauge_bq40z50 = true; - present.charger_mp2762a = true; present.button_powerLow = true; // Button is pressed when low present.beeper = true; present.gnss_to_uart = true; present.needsExternalPpl = true; // Uses the PointPerfect Library present.fastPowerOff = true; - present.invertedFastPowerOff = true; // Driving PWRKILL high will cause powerdown + present.invertedFastPowerOff = true; // Drive PWRKILL high to cause powerdown // We can't enable GNSS features here because we don't know if lg290pFirmwareVersion is >= v05 // present.minElevation = true; diff --git a/Firmware/RTK_Everywhere/RTK_Everywhere.ino b/Firmware/RTK_Everywhere/RTK_Everywhere.ino index f9cd11c3d..bd46a7c83 100644 --- a/Firmware/RTK_Everywhere/RTK_Everywhere.ino +++ b/Firmware/RTK_Everywhere/RTK_Everywhere.ino @@ -292,7 +292,7 @@ const int gpioExpanderSwitch_S4 = 3; // Controls U19 switch 4: connect GNSS UART const int gpioExpanderSwitch_LoraEnable = 4; // LoRa_EN const int gpioExpanderSwitch_GNSS_Reset = 5; // RST_GNSS const int gpioExpanderSwitch_LoraBoot = 6; // LoRa_BOOT0 - Used for bootloading the STM32 radio IC -const int gpioExpanderSwitch_PowerFastOff = 7; // PWRKILL +const int gpioExpanderSwitch_S5 = 7; // Controls U61 switch 5: connect GNSS UART1 to Port A of CH342 const int gpioExpanderNumSwitches = 8; //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= diff --git a/Firmware/RTK_Everywhere/System.ino b/Firmware/RTK_Everywhere/System.ino index 94f67353c..ecb13e160 100644 --- a/Firmware/RTK_Everywhere/System.ino +++ b/Firmware/RTK_Everywhere/System.ino @@ -920,11 +920,10 @@ void beginGpioExpanderSwitches() // SW1 is on pin 0. Driving it high will disconnect the ESP32 from USB // GNSS_RST is on pin 5. Driving it low when an LG290P is connected will kill the I2C bus. - // PWRKILL is on pin 7. Driving it low will turn off the system for (int i = 0; i < gpioExpanderNumSwitches; i++) { - // Set all pins to low except GNSS RESET and PWRKILL - if (i == gpioExpanderSwitch_GNSS_Reset || i == gpioExpanderSwitch_PowerFastOff) + // Set all pins to low except GNSS RESET + if (i == gpioExpanderSwitch_GNSS_Reset) gpioExpanderSwitches->digitalWrite(i, HIGH); else gpioExpanderSwitches->digitalWrite(i, LOW); From a647e0e800dad2fa354bbee0702f7a8691820367 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Fri, 7 Nov 2025 16:16:45 -0700 Subject: [PATCH 65/68] Add Flex v1.1 support for LG290P --- Firmware/RTK_Everywhere/Begin.ino | 12 +++--- Firmware/RTK_Everywhere/GNSS.ino | 12 ++---- Firmware/RTK_Everywhere/GNSS_LG290P.ino | 43 +++++++++++++++------- Firmware/RTK_Everywhere/RTK_Everywhere.ino | 3 -- 4 files changed, 39 insertions(+), 31 deletions(-) diff --git a/Firmware/RTK_Everywhere/Begin.ino b/Firmware/RTK_Everywhere/Begin.ino index ba2d4ed89..c20f49852 100644 --- a/Firmware/RTK_Everywhere/Begin.ino +++ b/Firmware/RTK_Everywhere/Begin.ino @@ -158,11 +158,6 @@ void identifyBoard() // Torch X2: 8.2/3.3 --> 836mV < 947mV < 1067mV (8.5% tolerance) else if (idWithAdc(idValue, 8.2, 3.3, 8.5)) productVariant = RTK_TORCH_X2; - -#ifdef FLEX_OVERRIDE - systemPrintln("<<<<<<<<<< !!!!!!!!!! FLEX OVERRIDE !!!!!!!!!! >>>>>>>>>>"); - productVariant = RTK_FLEX; // TODO remove once v1.1 Flex has ID resistors -#endif } if (ENABLE_DEVELOPER) @@ -777,7 +772,6 @@ void beginBoard() present.antennaPhaseCenter_mm = 62.0; // APC from drawings present.radio_lora = true; present.fuelgauge_bq40z50 = true; - present.charger_mp2762a = true; present.button_powerLow = true; // Button is pressed when high present.button_mode = true; @@ -1526,6 +1520,12 @@ void beginButtons() buttonCount++; if (present.gpioExpanderButtons == true) buttonCount++; + if (productVariant == RTK_FLEX) + { + Serial.println("<<<<<<<<<<<<<<<<<<<< Deal with Flex buttons >>>>>>>>>>>>>>"); + buttonCount = 1; + } + if (buttonCount > 1) reportFatalError("Illegal button assignment."); diff --git a/Firmware/RTK_Everywhere/GNSS.ino b/Firmware/RTK_Everywhere/GNSS.ino index 7eaaa89d9..9d86d314e 100644 --- a/Firmware/RTK_Everywhere/GNSS.ino +++ b/Firmware/RTK_Everywhere/GNSS.ino @@ -558,14 +558,6 @@ void gnssDetectReceiverType() gnssBoot(); // Tell GNSS to run - // TODO remove after testing, force retest on each boot - // Note: with this in place, the X5 detection will take a lot longer due to the baud rate change -#ifdef FLEX_OVERRIDE - systemPrintln("<<<<<<<<<< !!!!!!!!!! FLEX FORCED !!!!!!!!!! >>>>>>>>>>"); - // settings.detectedGnssReceiver = GNSS_RECEIVER_UNKNOWN; // This may be causing weirdness on the LG290P. - // Commenting for now -#endif - // Start auto-detect if NVM is not yet set if (settings.detectedGnssReceiver == GNSS_RECEIVER_UNKNOWN) { @@ -574,7 +566,8 @@ void gnssDetectReceiverType() do { #ifdef COMPILE_LG290P - if (lg290pIsPresent() == true) + systemPrintln("Testing for LG290P"); + if (lg290pIsPresentOnFlex() == true) { systemPrintln("Auto-detected GNSS receiver: LG290P"); settings.detectedGnssReceiver = GNSS_RECEIVER_LG290P; @@ -586,6 +579,7 @@ void gnssDetectReceiverType() #endif // COMPILE_LGP290P #ifdef COMPILE_MOSAICX5 + systemPrintln("Testing for mosaic-X5"); if (mosaicIsPresentOnFlex() == true) // Note: this changes the COM1 baud from 115200 to 460800 { systemPrintln("Auto-detected GNSS receiver: mosaic-X5"); diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.ino b/Firmware/RTK_Everywhere/GNSS_LG290P.ino index e7205ad9b..6d547d4a3 100644 --- a/Firmware/RTK_Everywhere/GNSS_LG290P.ino +++ b/Firmware/RTK_Everywhere/GNSS_LG290P.ino @@ -668,6 +668,12 @@ uint32_t GNSS_LG290P::getDataBaudRate() // This is nicknamed the DATA port dataUart = 1; } + else if (productVariant == RTK_FLEX) + { + // On the Flex, the DATA connector is not connected to the GNSS + // Return 0. + return (0); + } else if (productVariant == RTK_TORCH_X2) { // UART3 of the LG290P is connected to USB CH342 (Port A) @@ -675,9 +681,8 @@ uint32_t GNSS_LG290P::getDataBaudRate() dataUart = 3; } else - { systemPrintln("getDataBaudRate: Uncaught platform"); - } + return (getBaudRate(dataUart)); } @@ -700,20 +705,20 @@ bool GNSS_LG290P::setBaudRateData(uint32_t baud) // This is nicknamed the DATA port return (setBaudRate(1, baud)); } - else if (productVariant == RTK_TORCH_X2) + else if (productVariant == RTK_FLEX) { - if (getDataBaudRate() != baud) - { - // UART3 of the LG290P is connected to USB CH342 (Port A) - // This is nicknamed the DATA port - return (setBaudRate(3, baud)); - } + // On the Flex, the DATA connector is not connected to the GNSS + // Return true so that configuration can proceed. + return (true); } - else + else if (productVariant == RTK_TORCH_X2) { - // On products that don't have a DATA port (Flex), act as if we have set the baud successfully - return (true); + // UART3 of the LG290P is connected to USB CH342 (Port A) + // This is nicknamed the DATA port + return (setBaudRate(3, baud)); } + else + systemPrintln("setDataBaudRate: Uncaught platform"); } } return (false); @@ -741,6 +746,9 @@ uint32_t GNSS_LG290P::getRadioBaudRate() // Not really used at this time but available for configuration radioUart = 1; } + else + systemPrintln("getDataBaudRate: Uncaught platform"); + return (getBaudRate(radioUart)); } @@ -774,6 +782,9 @@ bool GNSS_LG290P::setBaudRateRadio(uint32_t baud) // Not really used at this time but available for configuration radioUart = 1; } + else + systemPrintln("setBaudRateRadio: Uncaught platform"); + return (setBaudRate(radioUart, baud)); } } @@ -1781,6 +1792,9 @@ bool GNSS_LG290P::setBaudRateComm(uint32_t baud) // UART1 of the LG290P is connected to the ESP32 for the main config/comm commUart = 1; } + else + systemPrintln("setBaudRateComm: Uncaught platform"); + return (setBaudRate(commUart, baud)); } } @@ -1803,6 +1817,9 @@ uint32_t GNSS_LG290P::getCommBaudRate() // On the Flex, the ESP32 UART1 is connected to LG290P UART1 commUart = 1; } + else + systemPrintln("getCommBaudRate: Uncaught platform"); + return (getBaudRate(commUart)); } @@ -2630,7 +2647,7 @@ bool lg290pMessageEnabled(char *nmeaSentence, int sentenceLength) } // Return true if we detect this receiver type -bool lg290pIsPresent() +bool lg290pIsPresentOnFlex() { // Locally instantiate the hardware and library so it will release on exit diff --git a/Firmware/RTK_Everywhere/RTK_Everywhere.ino b/Firmware/RTK_Everywhere/RTK_Everywhere.ino index bd46a7c83..a52ad7ec3 100644 --- a/Firmware/RTK_Everywhere/RTK_Everywhere.ino +++ b/Firmware/RTK_Everywhere/RTK_Everywhere.ino @@ -78,9 +78,6 @@ */ -// While we wait for the next hardware revisions, Flex and Torch can be manually enabled: -//#define FLEX_OVERRIDE // Uncomment to force support for Flex - // To reduce compile times, various parts of the firmware can be disabled/removed if they are not // needed during development #define COMPILE_BT // Comment out to remove Bluetooth functionality From 629161dede11a5915597a68e3e19abccd4cf8792 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Fri, 7 Nov 2025 16:48:05 -0700 Subject: [PATCH 66/68] Add non-compile guard warning --- Firmware/RTK_Everywhere/Tilt.ino | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Firmware/RTK_Everywhere/Tilt.ino b/Firmware/RTK_Everywhere/Tilt.ino index e129012f7..0cb59abcc 100644 --- a/Firmware/RTK_Everywhere/Tilt.ino +++ b/Firmware/RTK_Everywhere/Tilt.ino @@ -301,8 +301,9 @@ void beginTilt() { result &= tiltSensor->sendCommand("LEVER_ARM=0.03391,0.00272,0.02370"); // -28.2, 0. -23.7mm - //Send AT+INSTALL_ANGLE=180,0,0 if the IM19 module is mounted on the back of the GNSS receiver (so the IM19 faces downward instead of upward), before sending the save command. - result &= tiltSensor->sendCommand("INSTALL_ANGLE=180,0,-90"); //IMU is mounted facing down + // Send AT+INSTALL_ANGLE=180,0,0 if the IM19 module is mounted on the back of the GNSS receiver (so the IM19 + // faces downward instead of upward), before sending the save command. + result &= tiltSensor->sendCommand("INSTALL_ANGLE=180,0,-90"); // IMU is mounted facing down } // Set the overall length of the GNSS setup in meters: rod length 1800mm + internal length 96.45mm + antenna @@ -1072,11 +1073,12 @@ void tiltDetect() } SerialTiltTest.end(); // Release UART1 for reuse - +#else + systemPrintln("<<<<<<<<<< !!!!!!!!!! TILT NOT COMPILED !!!!!!!!!! >>>>>>>>>>"); #endif // COMPILE_IM19_IMU systemPrintf("Tilt sensor %sdetected\r\n", settings.detectedTilt ? "" : "not "); - settings.testedTilt = true; //Record this test so we don't do it again + settings.testedTilt = true; // Record this test so we don't do it again recordSystemSettings(); return; } From f98dfd6b5b4ba80d670db2df93a4233c4b903b74 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Fri, 7 Nov 2025 16:48:17 -0700 Subject: [PATCH 67/68] Add microSD back to Flex --- Firmware/RTK_Everywhere/Begin.ino | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Firmware/RTK_Everywhere/Begin.ino b/Firmware/RTK_Everywhere/Begin.ino index c20f49852..a169c44f4 100644 --- a/Firmware/RTK_Everywhere/Begin.ino +++ b/Firmware/RTK_Everywhere/Begin.ino @@ -779,8 +779,7 @@ void beginBoard() present.gnss_to_uart = true; present.gpioExpanderSwitches = true; - // present.microSd = true; // TODO remove comment out - v1.0 hardware does not have pullup on #CD so card - // detection does not work + present.microSd = true; present.microSdCardDetectLow = true; present.display_i2c0 = true; @@ -818,11 +817,8 @@ void beginBoard() pin_microSD_CS = 22; pin_microSD_CardDetect = 39; - pin_gpioExpanderInterrupt = - 2; // TODO remove on v1.1 hardware. Not used since all GPIO expanded pins are outputs - - digitalWrite(pin_powerFastOff, LOW); // Low = Stay on. High = turn off. pinMode(pin_powerFastOff, OUTPUT); + digitalWrite(pin_powerFastOff, LOW); // Low = Stay on. High = turn off. DMW_if systemPrintf("pin_bluetoothStatusLED: %d\r\n", pin_bluetoothStatusLED); pinMode(pin_bluetoothStatusLED, OUTPUT); From 5a81bbde60b83eaf9d26d7c4697a86a0f3adb6b3 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Fri, 14 Nov 2025 15:12:56 -0700 Subject: [PATCH 68/68] Increase version number --- .github/workflows/compile-rtk-everywhere.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/compile-rtk-everywhere.yml b/.github/workflows/compile-rtk-everywhere.yml index e17b5047e..c056656e1 100644 --- a/.github/workflows/compile-rtk-everywhere.yml +++ b/.github/workflows/compile-rtk-everywhere.yml @@ -5,8 +5,8 @@ on: env: FILENAME_PREFIX: RTK_Everywhere_Firmware - FIRMWARE_VERSION_MAJOR: 2 - FIRMWARE_VERSION_MINOR: 3 + FIRMWARE_VERSION_MAJOR: 3 + FIRMWARE_VERSION_MINOR: 0 CORE_VERSION: 3.0.7 jobs: