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:
diff --git a/Firmware/RTK_Everywhere/AP-Config/index.html b/Firmware/RTK_Everywhere/AP-Config/index.html
index 9e7c8c0a8..c16fc0aaa 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 20d0e4088..f373f1ce5 100644
--- a/Firmware/RTK_Everywhere/AP-Config/src/main.js
+++ b/Firmware/RTK_Everywhere/AP-Config/src/main.js
@@ -278,8 +278,8 @@ function parseIncoming(msg) {
show("constellationNavic");
hide("dynamicModelDropdown"); //Not supported on LG290P
- show("minElevConfig");
- show("minCNOConfig");
+ hide("minElevConfig"); //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.');
@@ -346,8 +346,8 @@ function parseIncoming(msg) {
hide("enableNmeaOnRadio");
hide("dynamicModelDropdown"); //Not supported on LG290P
- show("minElevConfig");
- show("minCNOConfig");
+ hide("minElevConfig"); //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.');
@@ -930,7 +930,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 (isElementShown("lg290pGnssSettings") == true) {
checkElementValue("rtcmMinElev", -90, 90, "Must be between -90 and 90", "collapseGNSSConfig");
}
diff --git a/Firmware/RTK_Everywhere/Begin.ino b/Firmware/RTK_Everywhere/Begin.ino
index 1d206d6c8..8ca6fef21 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();
@@ -158,16 +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
-
-#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)
@@ -237,9 +227,10 @@ 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;
+ present.display_type = DISPLAY_MAX_NONE;
#ifdef COMPILE_IM19_IMU
present.imu_im19 = true; // Allow tiltUpdate() to run
@@ -354,7 +345,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;
@@ -451,7 +442,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
@@ -479,7 +469,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 +551,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 +650,7 @@ void beginBoard()
present.mosaicMicroSd = true;
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 +724,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;
@@ -782,15 +772,14 @@ 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; //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;
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;
@@ -799,6 +788,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;
@@ -806,7 +798,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;
@@ -824,8 +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
+ 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);
@@ -870,15 +863,16 @@ 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_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
+ present.fastPowerOff = true;
+ 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;
- // present.minCno = true;
+ // present.minCN0 = true;
pin_I2C0_SDA = 15;
pin_I2C0_SCL = 4;
@@ -887,7 +881,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
@@ -899,12 +893,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);
@@ -1504,6 +1500,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.");
@@ -1523,9 +1525,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)
@@ -1789,6 +1797,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/Bluetooth.ino b/Firmware/RTK_Everywhere/Bluetooth.ino
index c8e333d67..e94f73323 100644
--- a/Firmware/RTK_Everywhere/Bluetooth.ino
+++ b/Firmware/RTK_Everywhere/Bluetooth.ino
@@ -19,6 +19,8 @@
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+BluetoothRadioType_e bluetoothRadioPreviousOnType = BLUETOOTH_RADIO_OFF;
+
#ifdef COMPILE_BT
//----------------------------------------
@@ -386,7 +388,10 @@ void BTConfirmRequestCallback(uint32_t numVal) {
// TODO: if the RTK device has an OLED, we should display the PIN so user can confirm
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
}
void deviceNameSpacesToUnderscores()
@@ -556,14 +561,14 @@ void bluetoothStart(bool skipOnlineCheck)
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,
@@ -595,9 +600,9 @@ void bluetoothStart(bool skipOnlineCheck)
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 +677,7 @@ void bluetoothStart(bool skipOnlineCheck)
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 +687,11 @@ void bluetoothStart(bool skipOnlineCheck)
{
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
}
diff --git a/Firmware/RTK_Everywhere/Developer.ino b/Firmware/RTK_Everywhere/Developer.ino
index 59cb82bc9..88b36c8e6 100644
--- a/Firmware/RTK_Everywhere/Developer.ino
+++ b/Firmware/RTK_Everywhere/Developer.ino
@@ -290,7 +290,7 @@ void wifiVerifyTables() {}
void menuTilt() {}
void nmeaApplyCompensation(char *nmeaSentence, int arraySize) {}
-void tiltDetect() {}
+void tiltDetect() {systemPrintln("**Tilt Not Compiled**");}
bool tiltIsCorrecting() {return(false);}
void tiltRequestStop() {}
void tiltSensorFactoryReset() {}
diff --git a/Firmware/RTK_Everywhere/Display.ino b/Firmware/RTK_Everywhere/Display.ino
index bcb1ef59a..d70336ac5 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();
@@ -283,13 +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);
+ // 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);
+ displayRoverStart(0);
break;
case (STATE_ROVER_NO_FIX):
displayHorizontalAccuracy(&iconPropertyList, &CrossHairProperties,
@@ -332,7 +343,8 @@ void displayUpdate()
case (STATE_BASE_CASTER_NOT_STARTED):
case (STATE_BASE_NOT_STARTED):
- // Do nothing. Static display shown during state change.
+ case (STATE_BASE_CONFIG_WAIT):
+ displayBaseStart(0); // Show 'Base' while the system configures the Base
break;
// Start of base / survey in / NTRIP mode
@@ -364,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);
@@ -378,8 +391,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 +412,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 +928,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 +1261,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 +1278,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 +1305,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];
@@ -2101,8 +2108,6 @@ void displayBaseStart(uint16_t displayTime)
oled->display();
- oled->display();
-
delay(displayTime);
}
}
@@ -2462,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(
@@ -2601,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)
@@ -2672,8 +2648,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 +2663,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 #
@@ -3102,6 +3074,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 5628a90a4..a1045380f 100644
--- a/Firmware/RTK_Everywhere/GNSS.h
+++ b/Firmware/RTK_Everywhere/GNSS.h
@@ -9,397 +9,403 @@ 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();
-
- // Set the minimum satellite signal level for navigation.
- virtual bool setMinCnoRadio(uint8_t cnoValue);
+ 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;
-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();
+ uint8_t _satellitesInView;
+ uint8_t _fixType;
+ uint8_t _carrierSolution;
- // Set RTCM for base mode to defaults (1005/1074/1084/1094/1124 1Hz & 1230 0.1Hz)
- virtual void baseRtcmDefault();
+ bool _validDate; // True when date is valid
+ bool _validTime; // True when time is valid
+ bool _confirmedDate;
+ bool _confirmedTime;
+ bool _fullyResolved;
+ uint32_t _tAcc;
- // Reset to Low Bandwidth Link (1074/1084/1094/1124 0.5Hz & 1005/1230 0.1Hz)
- virtual void baseRtcmLowDataRate();
+ unsigned long _pvtArrivalMillis;
+ bool _pvtUpdated;
- // 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();
+ bool _corrRadioExtPortEnabled = false;
- // Connect to GNSS and identify particulars
- virtual void begin();
+ unsigned long _autoBaseStartTimer; // Tracks how long the base auto / averaging mode has been running
- // Setup TM2 time stamp input as need
- // Outputs:
- // Returns true when an external event occurs and false if no event
- virtual bool beginExternalEvent();
+ public:
+ // Constructor
+ GNSS() : _leapSeconds(18), _pvtArrivalMillis(0), _pvtUpdated(0), _satellitesInView(0)
+ {
+ }
- // 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();
+ // If we have decryption keys, configure module
+ // Note: don't check online.lband_neo here. We could be using ip corrections
+ virtual void applyPointPerfectKeys();
- virtual bool checkNMEARates();
+ // Set RTCM for base mode to defaults (1005/1074/1084/1094/1124 1Hz & 1230 0.1Hz)
+ virtual void baseRtcmDefault();
- virtual bool checkPPPRates();
+ // Reset to Low Bandwidth Link (1074/1084/1094/1124 0.5Hz & 1005/1230 0.1Hz)
+ virtual void baseRtcmLowDataRate();
- // 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();
+ // 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();
- // Configure the Base
- // Outputs:
- // Returns true if successfully configured and false upon failure
- virtual bool configureBase();
+ // Connect to GNSS and identify particulars
+ virtual void begin();
- // Configure specific aspects of the receiver for NTP mode
- virtual bool configureNtpMode();
+ // Setup TM2 time stamp input as need
+ // Outputs:
+ // Returns true when an external event occurs and false if no event
+ virtual bool beginExternalEvent();
- // Configure the Rover
- // Outputs:
- // Returns true if successfully configured and false upon failure
- virtual bool configureRover();
+ virtual bool checkNMEARates();
- // 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 bool checkPPPRates();
- // 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);
+ // 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 configure();
- virtual void debuggingDisable();
+ // Configure the Base
+ // Outputs:
+ // Returns true if successfully configured and false upon failure
+ virtual bool configureBase();
- virtual void debuggingEnable();
+ // Configure specific aspects of the receiver for NTP mode
+ virtual bool configureNtpMode();
- virtual void enableGgaForNtrip();
+ // Configure the Rover
+ // Outputs:
+ // Returns true if successfully configured and false upon failure
+ virtual bool configureRover();
- // 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();
+ // 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);
- // Restore the GNSS to the factory settings
- virtual void factoryReset();
+ // 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 uint16_t fileBufferAvailable();
+ virtual void debuggingDisable();
- virtual uint16_t fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead);
+ virtual void debuggingEnable();
- // Start the base using fixed coordinates
- // Outputs:
- // Returns true if successfully started and false upon failure
- virtual bool fixedBaseStart();
+ // Restore the GNSS to the factory settings
+ virtual void factoryReset();
- // Return the number of active/enabled messages
- virtual uint8_t getActiveMessageCount();
+ virtual uint16_t fileBufferAvailable();
- // Return the number of active/enabled RTCM messages
- virtual uint8_t getActiveRtcmMessageCount();
+ virtual uint16_t fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead);
- // Get the altitude
- // Outputs:
- // Returns the altitude in meters or zero if the GNSS is offline
- virtual double getAltitude();
+ // Start the base using fixed coordinates
+ // Outputs:
+ // Returns true if successfully started and false upon failure
+ virtual bool fixedBaseStart();
- // Returns the carrier solution or zero if not online
- virtual uint8_t getCarrierSolution();
+ virtual bool fixRateIsAllowed(uint32_t fixRateMs);
- virtual uint32_t getDataBaudRate();
+ //Return min/max rate in ms
+ virtual uint32_t fixRateGetMinimumMs();
- // Returns the day number or zero if not online
- virtual uint8_t getDay();
+ virtual uint32_t fixRateGetMaximumMs();
- // Return the number of milliseconds since GNSS data was last updated
- virtual uint16_t getFixAgeMilliseconds();
+ // Return the number of active/enabled messages
+ virtual uint8_t getActiveMessageCount();
- // Returns the fix type or zero if not online
- virtual uint8_t getFixType();
+ // Return the number of active/enabled RTCM messages
+ virtual uint8_t getActiveRtcmMessageCount();
- // Returns the hours of 24 hour clock or zero if not online
- virtual uint8_t getHour();
+ // Get the altitude
+ // Outputs:
+ // Returns the altitude in meters or zero if the GNSS is offline
+ virtual double getAltitude();
- // Get the horizontal position accuracy
- // Outputs:
- // Returns the horizontal position accuracy or zero if offline
- virtual float getHorizontalAccuracy();
+ // Returns the carrier solution or zero if not online
+ virtual uint8_t getCarrierSolution();
- virtual const char *getId();
+ virtual uint32_t getDataBaudRate();
- // Get the latitude value
- // Outputs:
- // Returns the latitude value or zero if not online
- virtual double getLatitude();
+ // Returns the day number or zero if not online
+ virtual uint8_t getDay();
- // Query GNSS for current leap seconds
- virtual uint8_t getLeapSeconds();
+ // Return the number of milliseconds since GNSS data was last updated
+ virtual uint16_t getFixAgeMilliseconds();
- // Return the type of logging that matches the enabled messages - drives the logging icon
- virtual uint8_t getLoggingType();
+ // Returns the fix type or zero if not online
+ virtual uint8_t getFixType();
- // Get the longitude value
- // Outputs:
- // Returns the longitude value or zero if not online
- virtual double getLongitude();
+ // Returns the hours of 24 hour clock or zero if not online
+ virtual uint8_t getHour();
- // Returns two digits of milliseconds or zero if not online
- virtual uint8_t getMillisecond();
+ // Get the horizontal position accuracy
+ // Outputs:
+ // Returns the horizontal position accuracy or zero if offline
+ virtual float getHorizontalAccuracy();
- // Get the minimum satellite signal level for navigation.
- uint8_t getMinCno();
+ virtual const char *getId();
- // Returns minutes or zero if not online
- virtual uint8_t getMinute();
+ // Get the latitude value
+ // Outputs:
+ // Returns the latitude value or zero if not online
+ virtual double getLatitude();
- // Returns month number or zero if not online
- virtual uint8_t getMonth();
+ // Query GNSS for current leap seconds
+ virtual uint8_t getLeapSeconds();
- // Returns nanoseconds or zero if not online
- virtual uint32_t getNanosecond();
+ // Return the type of logging that matches the enabled messages - drives the logging icon
+ virtual uint8_t getLoggingType();
- virtual uint32_t getRadioBaudRate();
+ // Get the longitude value
+ // Outputs:
+ // Returns the longitude value or zero if not online
+ virtual double getLongitude();
- // Returns the seconds between solutions
- virtual double getRateS();
+ // Returns two digits of milliseconds or zero if not online
+ virtual uint8_t getMillisecond();
- virtual const char *getRtcmDefaultString();
+ // Returns minutes or zero if not online
+ virtual uint8_t getMinute();
- virtual const char *getRtcmLowDataRateString();
+ // Returns the current mode: Base/Rover/etc
+ virtual uint8_t getMode();
- // Returns the number of satellites in view or zero if offline
- virtual uint8_t getSatellitesInView();
+ // Returns month number or zero if not online
+ virtual uint8_t getMonth();
- // Returns seconds or zero if not online
- virtual uint8_t getSecond();
+ // Returns nanoseconds or zero if not online
+ virtual uint32_t getNanosecond();
- // Get the survey-in mean accuracy
- // Outputs:
- // Returns the mean accuracy or zero (0)
- virtual float getSurveyInMeanAccuracy();
+ virtual uint32_t getRadioBaudRate();
- // Return the number of seconds the survey-in process has been running
- virtual int getSurveyInObservationTime();
+ // Returns the seconds between solutions
+ virtual double getRateS();
- float getSurveyInStartingAccuracy();
+ virtual const char *getRtcmDefaultString();
- // Returns timing accuracy or zero if not online
- virtual uint32_t getTimeAccuracy();
+ virtual const char *getRtcmLowDataRateString();
- // Returns full year, ie 2023, not 23.
- virtual uint16_t getYear();
+ // Returns the number of satellites in view or zero if offline
+ virtual uint8_t getSatellitesInView();
- // Antenna Short / Open detection
- virtual bool isAntennaShorted();
- virtual bool isAntennaOpen();
+ // Returns seconds or zero if not online
+ virtual uint8_t getSecond();
- virtual bool isBlocking();
+ // Get the survey-in mean accuracy
+ // Outputs:
+ // Returns the mean accuracy or zero (0)
+ virtual float getSurveyInMeanAccuracy();
- // Date is confirmed once we have GNSS fix
- virtual bool isConfirmedDate();
+ // Return the number of seconds the survey-in process has been running
+ virtual int getSurveyInObservationTime();
- // Date is confirmed once we have GNSS fix
- virtual bool isConfirmedTime();
+ // Returns timing accuracy or zero if not online
+ virtual uint32_t getTimeAccuracy();
- // Returns true if data is arriving on the Radio Ext port
- virtual bool isCorrRadioExtPortActive();
+ // Returns full year, ie 2023, not 23.
+ virtual uint16_t getYear();
- // Return true if GNSS receiver has a higher quality DGPS fix than 3D
- virtual bool isDgpsFixed();
+ // 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();
- // 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();
+ // Antenna Short / Open detection
+ virtual bool isAntennaShorted();
+ virtual bool isAntennaOpen();
- // Used in tpISR() for time pulse synchronization
- virtual bool isFullyResolved();
+ virtual bool isBlocking();
- virtual bool isPppConverged();
+ // Date is confirmed once we have GNSS fix
+ virtual bool isConfirmedDate();
- virtual bool isPppConverging();
+ // Date is confirmed once we have GNSS fix
+ virtual bool isConfirmedTime();
- // 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();
+ // 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 an RTK Float. This function checks to see if
- // the given platform has reached sufficient fix type to be considered
- // valid
- virtual bool isRTKFloat();
+ // Return true if GNSS receiver has a higher quality DGPS fix than 3D
+ virtual bool isDgpsFixed();
- // 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 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();
- // Date will be valid if the RTC is reporting (regardless of GNSS fix)
- virtual bool isValidDate();
+ // Used in tpISR() for time pulse synchronization
+ virtual bool isFullyResolved();
- // Time will be valid if the RTC is reporting (regardless of GNSS fix)
- virtual bool isValidTime();
+ virtual bool isPppConverged();
- // Controls the constellations that are used to generate a fix and logged
- virtual void menuConstellations();
+ virtual bool isPppConverging();
- virtual void menuMessageBaseRtcm();
+ // 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();
- // Control the messages that get broadcast over Bluetooth and logged (if enabled)
- virtual void menuMessages();
+ // 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();
- // Print the module type and firmware version
- virtual void printModuleInfo();
+ // 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();
- // 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);
+ // Date will be valid if the RTC is reporting (regardless of GNSS fix)
+ virtual bool isValidDate();
- virtual uint16_t rtcmBufferAvailable();
+ // Time will be valid if the RTC is reporting (regardless of GNSS fix)
+ virtual bool isValidTime();
- // If LBand is being used, ignore any RTCM that may come in from the GNSS
- virtual void rtcmOnGnssDisable();
+ // Controls the constellations that are used to generate a fix and logged
+ virtual void menuConstellations();
- // If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver
- virtual void rtcmOnGnssEnable();
+ virtual void menuMessageBaseRtcm();
- virtual uint16_t rtcmRead(uint8_t *rtcmBuffer, int rtcmBytesToRead);
+ // Control the messages that get broadcast over Bluetooth and logged (if enabled)
+ virtual void menuMessages();
- // Save the current configuration
- // Outputs:
- // Returns true when the configuration was saved and false upon failure
- virtual bool saveConfiguration();
+ // Print the module type and firmware version
+ virtual void printModuleInfo();
- // Enable all the valid constellations and bands for this platform
- virtual bool setConstellations();
+ // 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);
- // 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);
+ // Hardware or software reset the GNSS receiver
+ virtual bool reset();
- virtual bool setBaudRate(uint8_t uartNumber, uint32_t baudRate);
+ virtual uint16_t rtcmBufferAvailable();
- virtual bool setDataBaudRate(uint32_t baud);
+ // If LBand is being used, ignore any RTCM that may come in from the GNSS
+ virtual void rtcmOnGnssDisable();
- // Set the elevation in degrees
- // Inputs:
- // elevationDegrees: The elevation value in degrees
- virtual bool setElevation(uint8_t elevationDegrees);
+ // If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver
+ virtual void rtcmOnGnssEnable();
- // Enable all the valid messages for this platform
- virtual bool setMessages(int maxRetries);
+ virtual uint16_t rtcmRead(uint8_t *rtcmBuffer, int rtcmBytesToRead);
- // Enable all the valid messages for this platform over the USB port
- virtual bool setMessagesUsb(int maxRetries);
+ // Save the current configuration
+ // Outputs:
+ // Returns true when the configuration was saved and false upon failure
+ virtual bool saveConfiguration();
- // Set the minimum satellite signal level for navigation.
- bool setMinCno(uint8_t cnoValue);
+ // Enable all the valid constellations and bands for this platform
+ virtual bool setConstellations();
- // 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);
+ // 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 setRadioBaudRate(uint32_t baud);
+ virtual bool setBaudRate(uint8_t uartNumber, uint32_t baudRate);
- // 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 setBaudRateComm(uint32_t baud);
- virtual bool setTalkerGNGGA();
+ virtual bool setBaudRateData(uint32_t baud);
- // Hotstart GNSS to try to get RTK lock
- virtual bool softwareReset();
+ virtual bool setBaudRateRadio(uint32_t baud);
- virtual bool standby();
+ // Set the elevation in degrees
+ // Inputs:
+ // elevationDegrees: The elevation value in degrees
+ virtual bool setElevation(uint8_t elevationDegrees);
- // Antenna Short / Open detection
- virtual bool supportsAntennaShortOpen();
+ virtual bool setHighAccuracyService(bool enableGalileoHas);
- // Reset the survey-in operation
- // Outputs:
- // Returns true if the survey-in operation was reset successfully
- // and false upon failure
- virtual bool surveyInReset();
+ // Configure any logging settings - currently mosaic-X5 specific
+ virtual bool setLogging();
- // Start the survey-in operation
- // Outputs:
- // Return true if successful and false upon failure
- virtual bool surveyInStart();
+ virtual bool setNmeaMessageRateByName(const char *msgName, uint8_t msgRate);
- // Poll routine to update the GNSS state
- virtual void update();
+ // Enable/disable messages according to the NMEA array
+ virtual bool setMessagesNMEA();
+
+ // Enable/disable messages according to the RTCM Base array
+ virtual bool setMessagesRTCMBase();
+
+ // Enable/disable messages according to the NMEA array
+ virtual bool setMessagesRTCMRover();
+
+ // Set the minimum satellite signal level for navigation.
+ virtual bool setMinCN0(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);
+
+ virtual bool setMultipathMitigation(bool enableMultipathMitigation);
+
+ // 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);
+
+ // Enable/disable any output needed for tilt compensation
+ virtual bool setTilt();
+
+ virtual bool standby();
+
+ // 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();
+
+ // 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
-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 2f3e361c1..2991fd731 100644
--- a/Firmware/RTK_Everywhere/GNSS.ino
+++ b/Firmware/RTK_Everywhere/GNSS.ino
@@ -2,71 +2,489 @@
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
+// 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, // 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,
+ GNSS_CONFIG_CONSTELLATION, // Turn on/off a constellation
+ GNSS_CONFIG_ELEVATION,
+ GNSS_CONFIG_CN0,
+ GNSS_CONFIG_PPS,
+ GNSS_CONFIG_MODEL,
+ 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
+ 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
+
+ // Add new entries above here
+ GNSS_CONFIG_MAX,
+};
+
+static const char *gnssConfigDisplayNames[] = {
+ "ONCE",
+ "ROVER",
+ "BASE",
+ "BASE SURVEY",
+ "BASE FIXED",
+ "BAUD_RATE_RADIO",
+ "BAUD_RATE_DATA",
+ "RATE",
+ "CONSTELLATION",
+ "ELEVATION",
+ "CN0",
+ "PPS",
+ "MODEL",
+ "MESSAGE_RATE_NMEA",
+ "MESSAGE_RATE_RTCM_ROVER",
+ "MESSAGE_RATE_RTCM_BASE",
+ "MESSAGE_RATE_RTCM_OTHER",
+ "HAS_E6",
+ "MULTIPATH",
+ "TILT",
+ "EXT_CORRECTIONS",
+ "LOGGING",
+ "SAVE",
+ "RESET",
+};
+
+static const int gnssConfigStateEntries = sizeof(gnssConfigDisplayNames) / sizeof(gnssConfigDisplayNames[0]);
+
+//----------------------------------------
+// Returns true if the antenna is shorted
+//----------------------------------------
+bool GNSS::isAntennaShorted()
+{
+ return false;
+}
//----------------------------------------
-// Setup the general configuration of the GNSS
-// Not Rover or Base specific (ie, baud rates)
-// Returns true if successfully configured and false otherwise
+// Returns true if the antenna is shorted
//----------------------------------------
-bool GNSS::configure()
+bool GNSS::isAntennaOpen()
+{
+ return false;
+}
+
+// Antenna Short / Open detection
+bool GNSS::supportsAntennaShortOpen()
+{
+ return false;
+}
+
+void gnssUpdate()
{
if (online.gnss == false)
- return (false);
+ return;
+
+ // Belt and suspender
+ if (gnss == nullptr)
+ return;
+
+ // Allow the GNSS platform to update itself
+ gnss->update();
+
+ 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
+ // This is to avoid multiple reconfigure delays when multiple commands are received, ie enable GPS, disable Galileo,
+ // should only trigger one GNSS reconfigure
+ 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 (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
+ }
+ }
+
+ if (gnssConfigureRequested(GNSS_CONFIG_BASE))
+ {
+ if (gnss->configureBase() == true)
+ {
+ gnssConfigureClear(GNSS_CONFIG_BASE);
+ gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM
+ }
+ }
+
+ if (gnssConfigureRequested(GNSS_CONFIG_BASE_SURVEY))
+ {
+ if (gnss->surveyInStart() == true)
+ {
+ 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
+ }
+ }
+
+ 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->setModel(settings.dynamicModel) == true)
+ {
+ gnssConfigureClear(GNSS_CONFIG_MODEL);
+ gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM
+ }
+ }
+
+ if (gnssConfigureRequested(GNSS_CONFIG_FIX_RATE))
+ {
+ if (gnss->setRate(settings.measurementRateMs / 1000.0) == true)
+ {
+ gnssConfigureClear(GNSS_CONFIG_FIX_RATE);
+ gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM
+ }
+ }
+
+ if (gnssConfigureRequested(GNSS_CONFIG_CONSTELLATION))
+ {
+ if (gnss->setConstellations() == true)
+ {
+ gnssConfigureClear(GNSS_CONFIG_CONSTELLATION);
+ gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM
+ }
+ }
+
+ if (gnssConfigureRequested(GNSS_CONFIG_ELEVATION))
+ {
+ if (gnss->setElevation(settings.minElev) == true)
+ {
+ gnssConfigureClear(GNSS_CONFIG_ELEVATION);
+ gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM
+ }
+ }
+
+ if (gnssConfigureRequested(GNSS_CONFIG_CN0))
+ {
+ if (gnss->setMinCN0(settings.minCN0) == true)
+ {
+ gnssConfigureClear(GNSS_CONFIG_CN0);
+ gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM
+ }
+ }
+
+ if (gnssConfigureRequested(GNSS_CONFIG_PPS))
+ {
+ if (gnss->setPPS() == true)
+ {
+ gnssConfigureClear(GNSS_CONFIG_PPS);
+ gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM
+ }
+ }
+
+ if (gnssConfigureRequested(GNSS_CONFIG_HAS_E6))
+ {
+ if (gnss->setHighAccuracyService(settings.enableGalileoHas) == true)
+ {
+ gnssConfigureClear(GNSS_CONFIG_HAS_E6);
+ gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM
+ }
+ }
+
+ if (gnssConfigureRequested(GNSS_CONFIG_MULTIPATH))
+ {
+ if (gnss->setMultipathMitigation(settings.enableMultipathMitigation) == true)
+ {
+ gnssConfigureClear(GNSS_CONFIG_MULTIPATH);
+ gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM
+ }
+ }
+
+ 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
+ setLoggingType(); // Update Standard, PPP, or custom for icon selection
+ }
+ }
+
+ if (gnssConfigureRequested(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER))
+ {
+ if (settings.debugGnssConfig == true && gnss->gnssInRoverMode() == false)
+ systemPrintln("Warning: Change to RTCM Rover rates requested but not in Rover mode.");
+
+ 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
+ }
+ }
+
+ if (gnssConfigureRequested(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE))
+ {
+ 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)
+ {
+ 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
+ }
+ }
+
+ 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
+ setLoggingType(); // Update Standard, PPP, or custom for icon selection
+ }
+
+ if (gnssConfigureRequested(GNSS_CONFIG_TILT))
+ {
+ if (gnss->setTilt() == true)
+ {
+ gnssConfigureClear(GNSS_CONFIG_TILT);
+ gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM
+ }
+ }
- // Check various setting arrays (message rates, etc) to see if they need to be reset to defaults
- checkGNSSArrayDefaults();
+ 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
+ }
+ }
+
+ if (gnssConfigureRequested(GNSS_CONFIG_LOGGING))
+ {
+ if (gnss->setLogging() == true)
+ {
+ gnssConfigureClear(GNSS_CONFIG_LOGGING);
+ gnssConfigure(GNSS_CONFIG_SAVE); // Request receiver commit this change to NVM
+ }
+ }
- // Configure the GNSS receiver
- return configureGNSS();
+ // Save changes to NVM
+ if (gnssConfigureRequested(GNSS_CONFIG_SAVE))
+ {
+ if (gnss->saveConfiguration())
+ 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
+ recordSystemSettings();
+ } // end bluetoothCommandIsConnected(), inMainMenu, inWebConfigMode()
}
//----------------------------------------
-// Get the minimum satellite signal level for navigation.
+// Verify the GNSS tables
//----------------------------------------
-uint8_t GNSS::getMinCno()
+void gnssVerifyTables()
{
- return (settings.minCNO);
+ if (gnssConfigStateEntries != GNSS_CONFIG_MAX)
+ reportFatalError("Fix gnssConfigStateEntries to match GNSS Config Enum");
}
-//----------------------------------------
-float GNSS::getSurveyInStartingAccuracy()
+// Given a bit to configure, set that bit in the overall bitfield
+void gnssConfigure(uint8_t configureBit)
{
- return (settings.surveyInStartingAccuracy);
+ uint32_t mask = (1 << configureBit);
+ settings.gnssConfigureRequest |= mask; // Set the bit
}
-//----------------------------------------
-// Returns true if the antenna is shorted
-//----------------------------------------
-bool GNSS::isAntennaShorted()
+// Given a bit to configure, clear that bit from the overall bitfield
+void gnssConfigureClear(uint8_t configureBit)
{
- return false;
+ uint32_t mask = (1 << configureBit);
+
+ if (settings.debugGnssConfig && (settings.gnssConfigureRequest & mask))
+ systemPrintf("GNSS Config Clear: %s\r\n", gnssConfigDisplayNames[configureBit]);
+
+ settings.gnssConfigureRequest &= ~mask; // Clear the bit
+}
+
+// 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 gnssConfigureDefaults()
+{
+ for (int x = 0; x < GNSS_CONFIG_MAX; x++)
+ gnssConfigure(x);
+
+ // 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);
+}
+
+// Returns true once all configuration requests are cleared
+bool gnssConfigureComplete()
+{
+ if (settings.gnssConfigureRequest == 0)
+ return (true);
+ return (false);
}
//----------------------------------------
-// Returns true if the antenna is shorted
+// Update the constellations following a set command
//----------------------------------------
-bool GNSS::isAntennaOpen()
+bool gnssCmdUpdateConstellations(const char *settingName, void *settingData, int settingType)
{
- return false;
+ gnssConfigure(GNSS_CONFIG_CONSTELLATION); // Request receiver to use new settings
+
+ return (true);
}
//----------------------------------------
-// Set the minimum satellite signal level for navigation.
+// Update the message rates following a set command
//----------------------------------------
-bool GNSS::setMinCno(uint8_t cnoValue)
+// TODO make RTCM and NMEA specific call backs
+bool gnssCmdUpdateMessageRates(const char *settingName, void *settingData, int settingType)
{
- // Update the setting
- settings.minCNO = cnoValue;
-
- // Pass the value to the GNSS receiver
- return gnss->setMinCnoRadio(cnoValue);
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings
+ return (true);
}
-// Antenna Short / Open detection
-bool GNSS::supportsAntennaShortOpen()
+//----------------------------------------
+// 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)
{
- return false;
+ // Require a rover restart to enable / disable RTCM for PPL
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA);
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER);
+ return (true);
}
// Periodically push GGA sentence over NTRIP Client, to Caster, if enabled
@@ -114,13 +532,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)
{
@@ -129,7 +540,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;
@@ -141,6 +553,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");
@@ -161,7 +574,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
@@ -173,7 +586,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;
@@ -208,6 +621,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
@@ -229,6 +644,8 @@ void gnssReset()
{
digitalWrite(pin_GNSS_Reset, LOW); // Tell LG290P to reset
}
+ else
+ systemPrintln("Uncaught gnssReset()");
}
//----------------------------------------
@@ -239,6 +656,7 @@ bool createGNSSPassthrough()
{
return createPassthrough("/updateGnssFirmware.txt");
}
+
bool createPassthrough(const char *filename)
{
if (online.fs == false)
@@ -246,18 +664,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;
}
@@ -392,46 +813,23 @@ 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);
}
}
-
-//----------------------------------------
-// Update the constellations following a set command
-//----------------------------------------
-bool gnssCmdUpdateConstellations(int commandIndex)
-{
- if (gnss == nullptr)
- return false;
-
- //return gnss->setConstellations();
- // setConstellations() can take multiple seconds. Avoid calling during WebConfig
- // as this can lead to >10 seconds required for parsing of the incoming settings blob
- return true;
-}
-
-//----------------------------------------
-// Update the message rates following a set command
-//----------------------------------------
-bool gnssCmdUpdateMessageRates(int commandIndex)
-{
- if (gnss == nullptr)
- return false;
-
- //return gnss->setMessages(MAX_SET_MESSAGES_RETRIES);
- return true;
-}
-
-//----------------------------------------
diff --git a/Firmware/RTK_Everywhere/GNSS_LG290P.h b/Firmware/RTK_Everywhere/GNSS_LG290P.h
index 541f1435b..70fb9692b 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,64 +64,52 @@ 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
-
-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();
-
- // Turn on all the enabled NMEA messages on COM3
- bool enableNMEA();
+ private:
+ LG290P *_lg290p; // Library class instance
- // Turn on all the enabled RTCM Rover messages on COM3
- bool enableRTCMRover();
+ protected:
+ bool configureOnce();
- // Turn on all the enabled RTCM Base messages on COM3
- bool enableRTCMBase();
+ // 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();
- 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 setMinCnoRadio(uint8_t cnoValue);
+ // Set the minimum satellite signal level for navigation.
+ bool setMinCN0(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);
- // 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
@@ -150,353 +117,356 @@ 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();
+
+ // 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();
- // Set RTCM for base mode to defaults (1005/1074/1084/1094/1124 1Hz & 1230 0.1Hz)
- void baseRtcmDefault();
+ // Connect to GNSS and identify particulars
+ void begin();
- // Reset to Low Bandwidth Link (1074/1084/1094/1124 0.5Hz & 1005/1230 0.1Hz)
- void baseRtcmLowDataRate();
+ // Setup TM2 time stamp input as need
+ // Outputs:
+ // Returns true when an external event occurs and false if no event
+ bool beginExternalEvent();
- // Check if a given baud rate is supported by this module
- bool baudIsAllowed(uint32_t baudRate);
- uint32_t baudGetMinimum();
- uint32_t baudGetMaximum();
+ // Setup the PPS pin for PPS LED
+ bool setPPS();
- // Connect to GNSS and identify particulars
- void begin();
+ bool checkNMEARates();
- // Setup TM2 time stamp input as need
- // Outputs:
- // Returns true when an external event occurs and false if no event
- bool beginExternalEvent();
+ bool checkPPPRates();
- // 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();
+ // Configure the Base
+ // Outputs:
+ // Returns true if successfully configured and false upon failure
+ bool configureBase();
- bool checkNMEARates();
+ // Configure specific aspects of the receiver for NTP mode
+ bool configureNtpMode();
- bool checkPPPRates();
+ // Configure the Rover
+ // Outputs:
+ // Returns true if successfully configured and false upon failure
+ bool configureRover();
- // Configure the Base
- // Outputs:
- // Returns true if successfully configured and false upon failure
- bool configureBase();
+ // 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);
- // Configure specific aspects of the receiver for NTP mode
- bool configureNtpMode();
+ // 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);
- // Configure the Rover
- // Outputs:
- // Returns true if successfully configured and false upon failure
- bool configureRover();
+ void debuggingDisable();
- // 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);
+ void debuggingEnable();
- // 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);
+ bool disableSurveyIn(bool saveAndReset);
- void debuggingDisable();
+ bool enterConfigMode(unsigned long waitForSemaphoreTimeout_millis);
- void debuggingEnable();
+ bool exitConfigMode();
- bool disableSurveyIn(bool saveAndReset);
+ // Restore the GNSS to the factory settings
+ void factoryReset();
- void enableGgaForNtrip();
+ uint16_t fileBufferAvailable();
- // 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();
+ uint16_t fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead);
- bool enterConfigMode(unsigned long waitForSemaphoreTimeout_millis);
+ // Start the base using fixed coordinates
+ // Outputs:
+ // Returns true if successfully started and false upon failure
+ bool fixedBaseStart();
- bool exitConfigMode();
+ bool fixRateIsAllowed(uint32_t fixRateMs);
- // Restore the GNSS to the factory settings
- void factoryReset();
+ // Return min/max rate in ms
+ uint32_t fixRateGetMinimumMs();
- uint16_t fileBufferAvailable();
+ uint32_t fixRateGetMaximumMs();
- uint16_t fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead);
+ // Return the number of active/enabled messages
+ uint8_t getActiveMessageCount();
- // Start the base using fixed coordinates
- // Outputs:
- // Returns true if successfully started and false upon failure
- bool fixedBaseStart();
+ // Return the number of active/enabled RTCM messages
+ uint8_t getActiveRtcmMessageCount();
- // Return the number of active/enabled messages
- uint8_t getActiveMessageCount();
+ // Get the altitude
+ // Outputs:
+ // Returns the altitude in meters or zero if the GNSS is offline
+ double getAltitude();
- // Return the number of active/enabled RTCM messages
- uint8_t getActiveRtcmMessageCount();
+ uint32_t getBaudRate(uint8_t uartNumber);
- // 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();
- uint32_t getBaudRate(uint8_t uartNumber);
+ uint32_t getCommBaudRate();
- // Returns the carrier solution or zero if not online
- uint8_t getCarrierSolution();
+ uint32_t getDataBaudRate();
- uint32_t getCommBaudRate();
+ // Returns the day number or zero if not online
+ uint8_t getDay();
- uint32_t getDataBaudRate();
+ // Return the number of milliseconds since GNSS data was last updated
+ uint16_t getFixAgeMilliseconds();
- // Returns the day number or zero if not online
- uint8_t getDay();
+ // Returns the fix type or zero if not online
+ uint8_t getFixType();
- // Return the number of milliseconds since GNSS data was last updated
- uint16_t getFixAgeMilliseconds();
+ // Returns the hours of 24 hour clock or zero if not online
+ uint8_t getHour();
- // Returns the fix type or zero if not online
- uint8_t getFixType();
+ // Get the horizontal position accuracy
+ // Outputs:
+ // Returns the horizontal position accuracy or zero if offline
+ float getHorizontalAccuracy();
- // Returns the hours of 24 hour clock or zero if not online
- uint8_t getHour();
+ const char *getId();
- // Get the horizontal position accuracy
- // Outputs:
- // Returns the horizontal position accuracy or zero if offline
- float getHorizontalAccuracy();
+ // Get the latitude value
+ // Outputs:
+ // Returns the latitude value or zero if not online
+ double getLatitude();
- const char *getId();
+ // Query GNSS for current leap seconds
+ uint8_t getLeapSeconds();
- // Get the latitude value
- // Outputs:
- // Returns the latitude value or zero if not online
- double getLatitude();
+ // Return the type of logging that matches the enabled messages - drives the logging icon
+ uint8_t getLoggingType();
- // Query GNSS for current leap seconds
- uint8_t getLeapSeconds();
+ // Get the longitude value
+ // Outputs:
+ // Returns the longitude value or zero if not online
+ double getLongitude();
- // Return the type of logging that matches the enabled messages - drives the logging icon
- uint8_t getLoggingType();
+ // Returns two digits of milliseconds or zero if not online
+ uint8_t getMillisecond();
- // Get the longitude value
- // Outputs:
- // Returns the longitude value or zero if not online
- double getLongitude();
+ // Returns minutes or zero if not online
+ uint8_t getMinute();
- // Returns two digits of milliseconds or zero if not online
- uint8_t getMillisecond();
+ // Returns 0 - Unknown, 1 - Rover, 2 - Base
+ uint8_t getMode();
- // Get the minimum satellite signal level for navigation.
- uint8_t getMinCno();
+ // Returns month number or zero if not online
+ uint8_t getMonth();
- // Returns minutes or zero if not online
- uint8_t getMinute();
+ // Returns nanoseconds or zero if not online
+ uint32_t getNanosecond();
- // Returns 0 - Unknown, 1 - Rover, 2 - Base
- uint8_t getMode();
+ uint32_t getRadioBaudRate();
- // Returns month number or zero if not online
- uint8_t getMonth();
+ // Returns the seconds between solutions
+ double getRateS();
- // Returns nanoseconds or zero if not online
- uint32_t getNanosecond();
+ const char *getRtcmDefaultString();
- uint32_t getRadioBaudRate();
+ const char *getRtcmLowDataRateString();
- // Returns the seconds between solutions
- double getRateS();
+ // Returns the number of satellites in view or zero if offline
+ uint8_t getSatellitesInView();
- const char *getRtcmDefaultString();
+ // Returns seconds or zero if not online
+ uint8_t getSecond();
- const char *getRtcmLowDataRateString();
+ // Get the survey-in mean accuracy
+ // Outputs:
+ // Returns the mean accuracy or zero (0)
+ float getSurveyInMeanAccuracy();
- // Returns the number of satellites in view or zero if offline
- uint8_t getSatellitesInView();
+ uint8_t getSurveyInMode();
- // Returns seconds or zero if not online
- uint8_t getSecond();
+ // Return the number of seconds the survey-in process has been running
+ int getSurveyInObservationTime();
- // Get the survey-in mean accuracy
- // Outputs:
- // Returns the mean accuracy or zero (0)
- float getSurveyInMeanAccuracy();
+ // Returns timing accuracy or zero if not online
+ uint32_t getTimeAccuracy();
- uint8_t getSurveyInMode();
+ // Returns full year, ie 2023, not 23.
+ uint16_t getYear();
- // Return the number of seconds the survey-in process has been running
- int getSurveyInObservationTime();
+ // Helper functions for the current mode as read from the GNSS receiver
+ bool gnssInBaseFixedMode();
+ bool gnssInBaseSurveyInMode();
+ bool gnssInRoverMode();
- float getSurveyInStartingAccuracy();
+ bool isBlocking();
- // Returns timing accuracy or zero if not online
- uint32_t getTimeAccuracy();
+ // Date is confirmed once we have GNSS fix
+ bool isConfirmedDate();
- // Returns full year, ie 2023, not 23.
- uint16_t getYear();
+ // Date is confirmed once we have GNSS fix
+ bool isConfirmedTime();
- // Returns true if the device is in Rover mode
- // Currently the only two modes are Rover or Base
- bool inRoverMode();
+ // Returns true if data is arriving on the Radio Ext port
+ bool isCorrRadioExtPortActive();
- bool isBlocking();
+ // Return true if GNSS receiver has a higher quality DGPS fix than 3D
+ bool isDgpsFixed();
- // Date is confirmed once we have GNSS fix
- bool isConfirmedDate();
+ // 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();
- // Date is confirmed once we have GNSS fix
- bool isConfirmedTime();
+ // Used in tpISR() for time pulse synchronization
+ bool isFullyResolved();
- // Returns true if data is arriving on the Radio Ext port
- bool isCorrRadioExtPortActive();
+ bool isPppConverged();
- // Return true if GNSS receiver has a higher quality DGPS fix than 3D
- bool isDgpsFixed();
+ bool isPppConverging();
- // 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 an RTK Fix. This function checks to see if the
+ // given platform has reached sufficient fix type to be considered valid
+ bool isRTKFix();
- // Used in tpISR() for time pulse synchronization
- bool isFullyResolved();
+ // 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();
- bool isPppConverged();
+ // 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();
- bool isPppConverging();
+ // Date will be valid if the RTC is reporting (regardless of GNSS fix)
+ bool isValidDate();
- // 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();
+ // Time will be valid if the RTC is reporting (regardless of GNSS fix)
+ bool isValidTime();
- // 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();
+ // Controls the constellations that are used to generate a fix and logged
+ void menuConstellations();
- // 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();
+ void menuMessageBaseRtcm();
- // Date will be valid if the RTC is reporting (regardless of GNSS fix)
- bool isValidDate();
+ // Control the messages that get broadcast over Bluetooth and logged (if enabled)
+ void menuMessages();
- // Time will be valid if the RTC is reporting (regardless of GNSS fix)
- bool isValidTime();
+ // Print the module type and firmware version
+ void printModuleInfo();
- // Controls the constellations that are used to generate a fix and logged
- void menuConstellations();
+ // 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);
- void menuMessageBaseRtcm();
+ // Hardware or software reset the GNSS
+ bool reset();
- // Control the messages that get broadcast over Bluetooth and logged (if enabled)
- void menuMessages();
+ uint16_t rtcmBufferAvailable();
- // Print the module type and firmware version
- void printModuleInfo();
+ // If LBand is being used, ignore any RTCM that may come in from the GNSS
+ void rtcmOnGnssDisable();
- // 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);
+ // If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver
+ void rtcmOnGnssEnable();
- uint16_t rtcmBufferAvailable();
+ uint16_t rtcmRead(uint8_t *rtcmBuffer, int rtcmBytesToRead);
- // If LBand is being used, ignore any RTCM that may come in from the GNSS
- void rtcmOnGnssDisable();
+ // Save the current configuration
+ // Outputs:
+ // Returns true when the configuration was saved and false upon failure
+ bool saveConfiguration();
- // If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver
- void rtcmOnGnssEnable();
+ bool setBaudRate(uint8_t uartNumber, uint32_t baudRate);
- uint16_t rtcmRead(uint8_t *rtcmBuffer, int rtcmBytesToRead);
+ bool setBaudRateComm(uint32_t baudRate);
- // Save the current configuration
- // Outputs:
- // Returns true when the configuration was saved and false upon failure
- bool saveConfiguration();
+ bool setBaudRateData(uint32_t baudRate);
- bool setBaudRate(uint8_t uartNumber, uint32_t baudRate);
+ bool setBaudRateRadio(uint32_t baudRate);
- bool setCommBaudrate(uint32_t baud);
+ // 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);
- bool setDataBaudRate(uint32_t baud);
+ bool setHighAccuracyService(bool enableGalileoHas, const char *configurePPP);
- // 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, const char *configurePPP);
+ // Configure any logging settings - currently mosaic-X5 specific
+ bool setLogging();
- // Enable all the valid messages for this platform
- bool setMessages(int maxRetries);
+ // Set the NMEA messages
+ bool setMessagesNMEA();
- // Enable all the valid messages for this platform over the USB port
- bool setMessagesUsb(int maxRetries);
+ // Set then RTCM Base messages
+ 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 RTCM Rover messages
+ bool setMessagesRTCMRover();
- bool setRadioBaudRate(uint32_t baud);
+ // 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);
- // 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 setMultipathMitigation(bool enableMultipathMitigation);
- 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
+ bool setRate(double secondsBetweenSolutions);
- // Hotstart GNSS to try to get RTK lock
- bool softwareReset();
+ // Enable/disable any output needed for tilt compensation
+ bool setTilt();
- 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 4c44e68ae..6d547d4a3 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,10 +92,21 @@ void GNSS_LG290P::begin()
return;
}
}
- systemPrintln("GNSS LG290P online");
online.gnss = true;
+ systemPrintln("GNSS LG290P online");
+
+ // Turn on debug messages if needed
+ 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;
+
// Check firmware version and print info
_lg290p->getFirmwareVersion(lg290pFirmwareVersion); // Needs LG290P library v1.0.7
@@ -138,7 +145,7 @@ void GNSS_LG290P::begin()
{
// Supported starting in v05
present.minElevation = true;
- present.minCno = true;
+ present.minCN0 = true;
}
// Determine if PPP temp firmware is detected.
@@ -175,10 +182,13 @@ 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);
+ bool response = _lg290p->setPPS(200, false, true); // duration time ms, alwaysOutput, polarity
+ if (settings.debugGnssConfig && response == false)
+ systemPrintln("setPPS failed");
+
+ return (response);
}
//----------------------------------------
@@ -194,255 +204,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.
-//----------------------------------------
-bool GNSS_LG290P::configureGNSS()
-{
- 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 (configureOnce())
- return (true);
-
- // If we fail, reset LG290P
- systemPrintln("Resetting LG290P to complete configuration");
-
- gnssReset();
- delay(500);
- gnssBoot();
- }
-
- systemPrintln("LG290P failed to configure");
- return (false);
-}
-
-//----------------------------------------
-// Configure the basic LG290P settings (rover/base agnostic)
-//----------------------------------------
-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
-*/
-
- 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)))
- {
- 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");
-
- // 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 &= setDataBaudRate(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
-
- response &= setRadioBaudRate(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");
- }
-
- // 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");
-
- // Save the current configuration into non-volatile memory (NVM)
- response &= saveConfiguration();
- }
- else
- online.gnss = false; // Take it offline
-
- settings.gnssConfiguredOnce = response;
-
- return (response);
-}
-
-//----------------------------------------
-// Configure specific aspects of the receiver for rover mode
+// begin() has already established communication. There are no one-time config requirements for the LG290P
//----------------------------------------
-bool GNSS_LG290P::configureRover()
+bool GNSS_LG290P::configure()
{
- /*
- Set mode to Rover
- 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;
-
- serialGNSS->flush(); // Remove any incoming characters
-
- uint8_t retries = 4;
-
- while ((retries > 0) && (!enterConfigMode(500)))
- {
- retries--;
- systemPrintf("configureRover: Enter config mode failed. %d retries remaining\r\n", retries);
- }
-
- response &= (retries > 0);
- 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 &= setMinCnoRadio(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 enableNMEA()
- }
- }
-
- // 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");
-
- response &= setHighAccuracyService(settings.enableGalileoHas, (const char *)settings.configurePPP);
-
- response &= enableRTCMRover();
- if (settings.debugGnss && response == false)
- systemPrintln("configureRover: Enable RTCM failed");
-
- response &= enableNMEA();
- 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
- softwareReset();
-
- if (settings.debugGnss && response)
- systemPrintln("LG290P Rover configured");
- }
-
- settings.gnssConfiguredRover = response;
-
- return (response);
+ return (true);
}
//----------------------------------------
@@ -450,46 +216,23 @@ bool GNSS_LG290P::configureRover()
//----------------------------------------
bool GNSS_LG290P::configureBase()
{
- /*
- Disable all messages
- Enable RTCM Base messages
- Enable NMEA messages
- */
-
- if (online.gnss == false)
- {
- systemPrintln("GNSS not online");
- return (false);
- }
+ bool response = true;
- // 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 (settings.fixedBase == false && gnssInBaseSurveyInMode())
{
- if (settings.gnssConfiguredBase)
- {
- if (settings.debugGnss)
- systemPrintln("Skipping LG290P Base configuration");
- return true;
- }
+ if (settings.debugGnssConfig)
+ systemPrintln("Skipping - LG290P is already in 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)))
+ if (settings.fixedBase == true && gnssInBaseFixedMode())
{
- retries--;
- systemPrintf("configureBase: Enter config mode failed. %d retries remaining\r\n", retries);
+ if (settings.debugGnssConfig)
+ systemPrintln("Skipping - LG290P is already in Fixed Base configuration");
+ return (true); // No changes needed
}
- response &= (retries > 0);
- if (settings.debugGnss && response == false)
- systemPrintln("configureBase: Enter config mode failed");
+ // Assume we are changing from Rover to Base, request any additional config changes
// "When set to Base Station mode, the receiver will automatically disable NMEA message output and enable RTCM MSM4
// and RTCM3-1005 message output."
@@ -499,67 +242,70 @@ 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
+ if (gnssInRoverMode() == true) // 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
- if (surveyInMode == 1 || surveyInMode == 2)
+ // 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 (gnss->gnssInBaseSurveyInMode() || gnss->gnssInBaseFixedMode())
{
- // 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 &= setMinCnoRadio(settings.minCNO);
-
- response &= setHighAccuracyService(settings.enableGalileoHas, (const char *)settings.configurePPP);
-
- response &= enableRTCMBase(); // Set RTCM messages
- if (settings.debugGnss && response == false)
- systemPrintln("configureBase: Enable RTCM failed");
-
- response &= enableNMEA(); // 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();
- softwareReset();
+ reset();
+
+ // When a device is changed from Rover to Base, NMEA messages are disabled. Turn them back on.
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA);
- // 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
+ // 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.debugGnss && response)
+ if (settings.debugGnssConfig && response)
systemPrintln("LG290P Base configured");
}
- settings.gnssConfiguredBase = response;
+ 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 Rover configuration");
+ 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
+
+ gnssConfigure(GNSS_CONFIG_FIX_RATE);
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER);
+ gnssConfigure(GNSS_CONFIG_RESET); // Mode change requires reset
return (response);
}
@@ -617,60 +363,30 @@ void GNSS_LG290P::createMessageListBase(String &returnText)
//----------------------------------------
uint8_t GNSS_LG290P::getSurveyInMode()
{
- if (online.gnss)
- return (_lg290p->getSurveyMode());
- return (false);
-}
-
-//----------------------------------------
-// Configure specific aspects of the receiver for NTP mode
-//----------------------------------------
-bool GNSS_LG290P::configureNtpMode()
-{
- return false;
-}
+ // Note: _lg290p->getSurveyMode() returns 0 while a survey-in is *running*
+ // so we check PQTMSVINSTATUS to see if a survey is in progress.
-//----------------------------------------
-// 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"));
+ 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 (false);
+ return (0);
}
//----------------------------------------
-// Enable NMEA and RTCM on UART2
+// Configure specific aspects of the receiver for NTP mode
//----------------------------------------
-bool GNSS_LG290P::exitConfigMode()
+bool GNSS_LG290P::configureNtpMode()
{
- 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);
+ return false;
}
//----------------------------------------
@@ -690,7 +406,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");
}
@@ -717,436 +433,59 @@ void GNSS_LG290P::debuggingEnable()
}
//----------------------------------------
-void GNSS_LG290P::enableGgaForNtrip()
+// Restore the GNSS to the factory settings
+//----------------------------------------
+void GNSS_LG290P::factoryReset()
+{
+ if (online.gnss)
+ {
+ _lg290p->factoryRestore(); // Restores the parameters configured by all commands to their default values.
+ // This command takes effect after restarting.
+
+ reset(); // Reboot the receiver.
+
+ systemPrintln("Waiting for LG290P to reboot");
+ while (1)
+ {
+ delay(1000); // Wait for device to reboot
+ if (_lg290p->isConnected())
+ break;
+ else
+ systemPrintln("Device still rebooting");
+ }
+ systemPrintln("LG290P has been factory reset");
+ }
+}
+
+//----------------------------------------
+uint16_t GNSS_LG290P::fileBufferAvailable()
+{
+ // TODO return(lg290pFileBufferAvailable());
+ return (0);
+}
+
+//----------------------------------------
+uint16_t GNSS_LG290P::fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead)
{
- // TODO lg290pEnableGgaForNtrip();
+ // TODO return(lg290pFileBufferAvailable());
+ return (0);
}
//----------------------------------------
-// Turn on all the enabled NMEA messages
+// Start the base using fixed coordinates
//----------------------------------------
-bool GNSS_LG290P::enableNMEA()
+bool GNSS_LG290P::fixedBaseStart()
{
bool response = true;
- bool gpggaEnabled = false;
- int portNumber = 1;
+ if (online.gnss == false)
+ return (false);
- 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;
-
- int minimumRtcmRate = 1000;
-
- 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;
- // Capture the message with the lowest rate
- if (settings.lg290pMessageRatesRTCMBase[messageNumber] < minimumRtcmRate)
- minimumRtcmRate = settings.lg290pMessageRatesRTCMBase[messageNumber];
- }
- }
- }
-
- portNumber++;
-
- // setMessageRateOnPort only supported on v4 and above
- if (lg290pFirmwareVersion < 4)
- break; // Don't step through portNumbers
- }
-
- if (enableRTCM == true)
- {
- if (settings.debugGnss)
- systemPrintf("Enabling Base RTCM MSM%c output with rate of %d\r\n", settings.useMSM7 ? '7' : '4',
- minimumRtcmRate);
-
- // 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,%d,07,06,2,%d", settings.useMSM7 ? '7' : '4',
- settings.rtcmMinElev, minimumRtcmRate);
- _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%c output with rate of %d\r\n", settings.useMSM7 ? '7' : '4',
- 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,%d,07,06,2,%d", settings.useMSM7 ? '7' : '4',
- settings.rtcmMinElev, 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.
-// 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
-//----------------------------------------
-void GNSS_LG290P::factoryReset()
-{
- if (online.gnss)
- {
- _lg290p->factoryRestore(); // Restores the parameters configured by all commands to their default values.
- // This command takes effect after restarting.
-
- softwareReset(); // Reboot the receiver.
-
- systemPrintln("Waiting for LG290P to reboot");
- while (1)
- {
- delay(1000); // Wait for device to reboot
- if (_lg290p->isConnected())
- break;
- else
- systemPrintln("Device still rebooting");
- }
- systemPrintln("LG290P has been factory reset");
- }
-}
-
-//----------------------------------------
-uint16_t GNSS_LG290P::fileBufferAvailable()
-{
- // TODO return(lg290pFileBufferAvailable());
- return (0);
-}
-
-//----------------------------------------
-uint16_t GNSS_LG290P::fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead)
-{
- // TODO return(lg290pFileBufferAvailable());
- return (0);
-}
-
-//----------------------------------------
-// Start the base using fixed coordinates
-//----------------------------------------
-bool GNSS_LG290P::fixedBaseStart()
-{
- bool response = true;
-
- if (online.gnss == false)
- return (false);
-
- if (settings.fixedBaseCoordinateType == COORD_TYPE_ECEF)
+ // 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)
{
// Waits for save and reset
response &= _lg290p->setSurveyFixedMode(settings.fixedEcefX, settings.fixedEcefY, settings.fixedEcefZ);
@@ -1173,6 +512,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[lgAllowedFixRatesCount - 1]); // The max Hz value is the min ms value
+}
+
+// Return maximum in milliseconds
+uint32_t GNSS_LG290P::fixRateGetMaximumMs()
+{
+ return (1000.0 / lgAllowedFixRatesHz[0]);
+}
+
//----------------------------------------
// Return the number of active/enabled messages
//----------------------------------------
@@ -1302,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)
@@ -1309,16 +681,15 @@ uint32_t GNSS_LG290P::getDataBaudRate()
dataUart = 3;
}
else
- {
systemPrintln("getDataBaudRate: Uncaught platform");
- }
+
return (getBaudRate(dataUart));
}
//----------------------------------------
// 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)
{
@@ -1334,20 +705,20 @@ bool GNSS_LG290P::setDataBaudRate(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);
@@ -1375,13 +746,16 @@ 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));
}
//----------------------------------------
// 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)
{
@@ -1408,6 +782,9 @@ bool GNSS_LG290P::setRadioBaudRate(uint32_t baud)
// Not really used at this time but available for configuration
radioUart = 1;
}
+ else
+ systemPrintln("setBaudRateRadio: Uncaught platform");
+
return (setBaudRate(radioUart, baud));
}
}
@@ -1682,22 +1059,48 @@ uint32_t GNSS_LG290P::getTimeAccuracy()
//----------------------------------------
uint16_t GNSS_LG290P::getYear()
{
- if (online.gnss)
- return (_lg290p->getYear());
- return 0;
+ if (online.gnss)
+ return (_lg290p->getYear());
+ return 0;
+}
+
+//----------------------------------------
+// Returns true if the device is in Base Fixed mode
+//----------------------------------------
+bool GNSS_LG290P::gnssInBaseFixedMode()
+{
+ // 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);
+}
+
+//----------------------------------------
+// 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
-// Currently the only two modes are Rover or Base
//----------------------------------------
-bool GNSS_LG290P::inRoverMode()
+bool GNSS_LG290P::gnssInRoverMode()
{
- // Determine which state we are in
- if (settings.lastState == STATE_BASE_NOT_STARTED)
- return (false);
-
- return (true); // Default to Rover
+ // 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
@@ -1913,8 +1316,7 @@ void GNSS_LG290P::menuConstellations()
systemPrintf("%d) Galileo E6 Corrections: %s\r\n", MAX_LG290P_CONSTELLATIONS + 1,
settings.enableGalileoHas ? "Enabled" : "Disabled");
if (settings.enableGalileoHas)
- systemPrintf("%d) PPP Configuration: \"%s\"\r\n", MAX_LG290P_CONSTELLATIONS + 2,
- settings.configurePPP);
+ systemPrintf("%d) PPP Configuration: \"%s\"\r\n", MAX_LG290P_CONSTELLATIONS + 2, settings.configurePPP);
}
systemPrintln("x) Exit");
@@ -1926,10 +1328,12 @@ void GNSS_LG290P::menuConstellations()
incoming--; // Align choice to constellation array of 0 to 5
settings.lg290pConstellations[incoming] ^= 1;
+ gnssConfigure(GNSS_CONFIG_CONSTELLATION); // Request receiver to use new settings
}
else if ((incoming == MAX_LG290P_CONSTELLATIONS + 1) && present.galileoHasCapable)
{
settings.enableGalileoHas ^= 1;
+ gnssConfigure(GNSS_CONFIG_HAS_E6); // Request receiver to use new settings
}
else if ((incoming == MAX_LG290P_CONSTELLATIONS + 2) && present.galileoHasCapable && settings.enableGalileoHas)
{
@@ -1964,11 +1368,6 @@ void GNSS_LG290P::menuConstellations()
printUnknown(incoming);
}
- // Apply current settings to module
- gnss->setConstellations();
-
- setHighAccuracyService(settings.enableGalileoHas, (const char *)settings.configurePPP);
-
clearBuffer(); // Empty buffer of any newline chars
}
@@ -2034,6 +1433,12 @@ 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_NMEA);
+ if (inBaseMode()) // If the system is in Base mode
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE);
+ else
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER);
+
systemPrintln("Reset to Defaults");
}
else if (incoming == 11 || incoming == 12)
@@ -2060,26 +1465,30 @@ 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);
- setMinCnoRadio(30);
+ settings.minElev = 15; // Degrees
+ gnssConfigure(GNSS_CONFIG_ELEVATION);
+ settings.minCN0 = 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)");
- }
}
else if ((incoming == 13) &&
(namedSettingAvailableOnPlatform("useMSM7"))) // Redundant - but good practice for code reuse)
+ {
settings.useMSM7 ^= 1;
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings
+ }
else if ((incoming == 14) && (namedSettingAvailableOnPlatform("rtcmMinElev")))
{
systemPrintf("Enter minimum elevation for RTCM: ");
@@ -2089,6 +1498,7 @@ void GNSS_LG290P::menuMessages()
if (elevation >= -90 && elevation <= 90)
{
settings.rtcmMinElev = elevation;
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings
}
}
@@ -2101,14 +1511,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.
}
//----------------------------------------
@@ -2215,22 +1617,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;
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Configure receiver to use new setting
+ }
}
if (strcmp(messageType, "RTCMRover") == 0)
{
if (getNewSetting(messageString, 0, 1200, &newSetting) == INPUT_RESPONSE_VALID)
+ {
settings.lg290pMessageRatesRTCMRover[incoming] = newSetting;
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Configure receiver to use new setting
+ }
}
if (strcmp(messageType, "RTCMBase") == 0)
{
if (getNewSetting(messageString, 0, 1200, &newSetting) == INPUT_RESPONSE_VALID)
+ {
settings.lg290pMessageRatesRTCMBase[incoming] = newSetting;
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE); // Configure receiver to use new setting
+ }
}
if (strcmp(messageType, "PQTM") == 0)
{
if (getNewSetting(messageString, 0, 1, &newSetting) == INPUT_RESPONSE_VALID)
+ {
settings.lg290pMessageRatesPQTM[incoming] = newSetting;
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_OTHER); // Configure receiver to use new setting
+ }
}
}
else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT)
@@ -2241,10 +1655,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
}
@@ -2283,260 +1693,668 @@ int GNSS_LG290P::pushRawData(uint8_t *dataToSend, int dataLength)
return (0);
}
-//----------------------------------------
-uint16_t GNSS_LG290P::rtcmBufferAvailable()
-{
- // TODO return(lg290pRtcmBufferAvailable());
- return (0);
+//----------------------------------------
+// Hardware or software reset the GNSS receiver
+// Reset GNSS via software command
+// Poll for isConnected()
+//----------------------------------------
+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
+ 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()
+{
+ // 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;
+ }
+ else
+ systemPrintln("setBaudRateComm: Uncaught platform");
+
+ 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;
+ }
+ else
+ systemPrintln("getCommBaudRate: Uncaught platform");
+
+ 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
+ }
+
+ gnssConfigure(GNSS_CONFIG_RESET); // Constellation changes require device save/restart
+
+ 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)
+ {
+ // Someday, read/modify/write setPortInputProtocols
+
+ 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;
+}
+
+//----------------------------------------
+// Control whether HAS E6 is used in location fixes or not
+//----------------------------------------
+bool GNSS_LG290P::setHighAccuracyService(bool enableGalileoHas)
+{
+ // E6 reception requires version v03/v06 with 'PPP_TEMP' in firmware title
+ // Present is set during LG290P begin()
+ if (present.galileoHasCapable == false)
+ return (true); // Return true to clear gnssConfigure test
+
+ // TODO - We should read/modify/write on PQTMCFGPPP
+
+ bool result = true;
+
+ // 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
+ char paramConfigurePPP[sizeof(settings.configurePPP) + 4];
+ snprintf(paramConfigurePPP, sizeof(paramConfigurePPP), ",W,%s", configPppSpacesToCommas(settings.configurePPP));
+ if (_lg290p->sendOkCommand("$PQTMCFGPPP", paramConfigurePPP) == true)
+ {
+ systemPrintln("Galileo E6 HAS service enabled");
+ }
+ else
+ {
+ systemPrintln("Galileo E6 HAS service failed to enable");
+ result = false;
+ }
+ }
+ else
+ {
+ // Turn off HAS/E6
+ // $PQTMCFGPPP,W,0*
+ if (_lg290p->sendOkCommand("$PQTMCFGPPP", ",W,0") == true)
+ {
+ systemPrintln("Galileo E6 HAS service disabled");
+ }
+ else
+ {
+ systemPrintln("Galileo E6 HAS service failed to disable");
+ result = false;
+ }
+ }
+
+ return (result);
}
//----------------------------------------
-// If LBand is being used, ignore any RTCM that may come in from the GNSS
+// Configure device-direct logging. Currently mosaic-X5 specific.
//----------------------------------------
-void GNSS_LG290P::rtcmOnGnssDisable()
+bool GNSS_LG290P::setLogging()
{
- // LG290P does not have a separate interface for RTCM
+ // Not supported on this platform
+ return (true); // Return true to clear gnssConfigure test
}
//----------------------------------------
-// If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver
+// Set the minimum satellite signal level for navigation.
//----------------------------------------
-void GNSS_LG290P::rtcmOnGnssEnable()
+bool GNSS_LG290P::setMinCN0(uint8_t cnoValue)
{
- // LG290P does not have a separate interface for RTCM
-}
+ // Present on >= v05
+ if (lg290pFirmwareVersion >= 5)
+ return (_lg290p->setCNR((float)cnoValue)); // 0.0 to 99.0
-//----------------------------------------
-uint16_t GNSS_LG290P::rtcmRead(uint8_t *rtcmBuffer, int rtcmBytesToRead)
-{
- // TODO return(lg290pRtcmRead(rtcmBuffer, rtcmBytesToRead));
- return (0);
+ // Because we call this during module setup we rely on a positive result
+ return true;
}
//----------------------------------------
-// Save the current configuration
-// Returns true when the configuration was saved and false upon failure
+// Enable/disable NMEA messages according to the NMEA array
//----------------------------------------
-bool GNSS_LG290P::saveConfiguration()
+bool GNSS_LG290P::setMessagesNMEA()
{
- if (online.gnss)
- return (_lg290p->save());
+ bool response = true;
+ bool gpggaEnabled = false;
- return false;
-}
+ int portNumber = 1;
-//----------------------------------------
-// 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)
-{
- if (online.gnss)
+ while (portNumber < 4)
{
- if (getCommBaudRate() == baud)
+ for (int messageNumber = 0; messageNumber < MAX_LG290P_NMEA_MSG; messageNumber++)
{
- return (true); // Baud is set!
+ // 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);
+
+ // Mark messages needed for other services (NTRIP Client, PointPerfect, etc) as enabled if rate > 0
+ if (settings.lg290pMessageRatesNMEA[messageNumber] > 0)
+ {
+ if (strcmp(lgMessagesNMEA[messageNumber].msgTextName, "GGA") == 0)
+ gpggaEnabled = true;
+ }
+ }
}
- else
+
+ portNumber++;
+
+ // setMessageRateOnPort only supported on v4 and above
+ if (lg290pFirmwareVersion < 4)
+ break; // Don't step through portNumbers
+ }
+
+ // Enable GGA if needed for other services
+ if (gpggaEnabled == false)
+ {
+ // Force on any messages that are needed for PPL
+ // Enable GGA for NTRIP
+ if (pointPerfectServiceUsesKeys() ||
+ (settings.enableNtripClient == true && settings.ntripClient_TransmitGGA == true))
{
- uint8_t commUart = 0;
- if (productVariant == RTK_POSTCARD)
+ if (settings.debugGnssConfig)
+ systemPrintln("Enabling GGA for NTRIP and PointPerfect");
+
+ // 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 on a specific port
+ // On Torch X2 and Postcard, the LG290P UART 2 is connected to ESP32.
+ response &= _lg290p->setMessageRateOnPort("GGA", 1, 2);
}
- else if (productVariant == RTK_FLEX)
+ else
+ // Enable GGA on all UARTs. It's the best we can do.
+ 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)
{
- // UART1 of the LG290P is connected to the ESP32 for the main config/comm
- commUart = 1;
+ // 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 (setBaudRate(commUart, baud));
}
}
- return (false);
+
+ // Messages take effect immediately. Save/Reset is not needed.
+
+ 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));
+
+ // Messages take effect immediately. Save/Reset is not needed.
+
+ 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)
+ int portNumber = 1;
+
+ int minimumRtcmRate = 1000;
+
+ while (portNumber < 4)
{
- 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
- }
+ 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
- return (response);
-}
+ // 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;
-// 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))
+ // 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;
-//----------------------------------------
-bool GNSS_LG290P::setHighAccuracyService(bool enableGalileoHas, const char *configurePPP)
-{
- 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 v03/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
+ portNumber++;
- // Enable E6 and PPP if enabled
- if (settings.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
- char paramConfigurePPP[sizeof(settings.configurePPP) + 4];
- snprintf(paramConfigurePPP, sizeof(paramConfigurePPP), ",W,%s", configPppSpacesToCommas(configurePPP));
- if (_lg290p->sendOkCommand("$PQTMCFGPPP", paramConfigurePPP) == 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");
+ 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");
+ 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);
+
+ // PQTMCFGRTCM fails to respond with OK over UART2 of LG290P, so don't look for it
+ _lg290p->sendOkCommand(msmCommand);
+ }
+
+ // Messages take effect immediately. Save/Reset is not needed.
+
+ return (response);
}
//----------------------------------------
-// Set the minimum satellite signal level for navigation.
+// Set the dynamic model to use for RTK
//----------------------------------------
-bool GNSS_LG290P::setMinCnoRadio(uint8_t cnoValue)
+bool GNSS_LG290P::setModel(uint8_t modelNumber)
{
- // Present on >= v05
- if (lg290pFirmwareVersion >= 5)
- return (_lg290p->setCNR((float)cnoValue)); // 0.0 to 99.0
-
- // Because we call this during module setup we rely on a positive result
+ // Not a feature on LG290p
return true;
}
//----------------------------------------
-// Set the dynamic model to use for RTK
+// Configure multipath mitigation
//----------------------------------------
-bool GNSS_LG290P::setModel(uint8_t modelNumber)
+bool GNSS_LG290P::setMultipathMitigation(bool enableMultipathMitigation)
{
- // Not a feature on LG290p
- return (false);
+ // Does not exist on this platform
+ return true;
}
//----------------------------------------
-// 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);
@@ -2551,13 +2369,21 @@ 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.
- int currentMode = getMode();
- if (currentMode == 2) // Base
+ // 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.
+ if (gnss->gnssInBaseSurveyInMode() || gnss->gnssInBaseFixedMode()) // Base
+ return (true); // Nothing to modify at this time
+
+ bool response = true;
+
+ // Change to rover mode
+ if (gnssInRoverMode() == false)
{
- if (settings.debugGnss || settings.debugCorrections)
- systemPrintln("Error: setRate can only be used in Rover mode");
- return (false);
+ response &= _lg290p->setModeRover(); // Wait for save and reset
+ if (response == false && settings.debugGnssConfig)
+ systemPrintln("setRate: Set mode rover failed");
}
// The LG290P has a fix interval and a message output rate
@@ -2567,8 +2393,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;
@@ -2582,76 +2406,53 @@ 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 &= softwareReset();
-
- 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);
- }
-
- return (true);
-}
+ if (response == false)
+ systemPrintln("Failed to set measurement rate");
-//----------------------------------------
-bool GNSS_LG290P::setTalkerGNGGA()
-{
- // TODO lg290pSetTalkerGNGGA();
- return false;
+ return (response);
}
//----------------------------------------
-// Reset GNSS via software command
-// Poll for isConnected()
+// Enable/disable any output needed for tilt compensation
//----------------------------------------
-bool GNSS_LG290P::softwareReset()
+bool GNSS_LG290P::setTilt()
{
- if (online.gnss)
+ 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.
+
+ 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_FIX_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("setTilt: setBaud failed.");
+
+ // Enable of GGA, RMC, GST for tilt sensor is done in setMessagesNMEA()
}
- return (false);
+
+ return response;
}
//----------------------------------------
@@ -2677,24 +2478,24 @@ bool GNSS_LG290P::surveyInReset()
//----------------------------------------
bool GNSS_LG290P::surveyInStart()
{
- if (online.gnss)
- {
- bool response = true;
+ _autoBaseStartTimer = millis(); // Stamp when averaging began
- response &=
- _lg290p->setSurveyInMode(settings.observationSeconds); // Average for a number of seconds (default is 60)
+ // We may have already started a survey-in from GNSS's previous NVM settings
+ 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;
+
+ return (response);
}
//----------------------------------------
@@ -2753,13 +2554,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)
{
@@ -2853,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/GNSS_Mosaic.h b/Firmware/RTK_Everywhere/GNSS_Mosaic.h
index a2cace644..f3a3ac0c0 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
@@ -584,18 +524,17 @@ 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 setMinCnoRadio (uint8_t cnoValue);
+ bool setMinCN0(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();
@@ -658,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();
@@ -679,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();
@@ -710,23 +644,6 @@ class GNSS_MOSAIC : GNSS
void debuggingEnable();
- 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:
- // Returns true if successfully started and false upon failure
- bool enableRTCMTest();
-
// Restore the GNSS to the factory settings
void factoryReset();
@@ -739,11 +656,21 @@ 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();
// Return the number of active/enabled RTCM messages
- uint8_t getActiveRtcmMessageCount() {return(0);}
+ uint8_t getActiveRtcmMessageCount()
+ {
+ return (0);
+ }
// Get the altitude
// Outputs:
@@ -780,7 +707,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:
@@ -804,6 +731,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();
@@ -821,9 +751,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);
@@ -848,9 +778,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();
@@ -887,7 +818,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
@@ -936,6 +868,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
@@ -965,21 +900,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 +920,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 +937,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 +956,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
@@ -1060,6 +969,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();
@@ -1067,25 +982,41 @@ 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
bool setElevation(uint8_t elevationDegrees);
- // Enable all the valid messages for this platform
- bool setMessages(int maxRetries);
+ // 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();
+
+ // Turn on all the enabled RTCM Base messages on COM1, COM2 and USB1 (if enabled)
+ bool setMessagesRTCMBase();
- // Enable all the valid messages for this platform over the USB port
- bool setMessagesUsb(int maxRetries);
+ // 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:
// modelNumber: Number of the model to use, provided by radio library
bool setModel(uint8_t modelNumber);
- bool setRadioBaudRate(uint32_t baud);
+ 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
+ // Outputs
+ // Returns true if the pin was successfully setup and false upon
+ // failure
+ bool setPPS();
// Specify the interval between solutions
// Inputs:
@@ -1095,10 +1026,8 @@ class GNSS_MOSAIC : GNSS
// failure
bool setRate(double secondsBetweenSolutions);
- bool setTalkerGNGGA();
-
- // Hotstart GNSS to try to get RTK lock
- bool softwareReset();
+ // Enable/disable any output needed for tilt compensation
+ bool setTilt();
bool standby();
@@ -1142,4 +1071,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_Mosaic.ino b/Firmware/RTK_Everywhere/GNSS_Mosaic.ino
index 063b0cbf3..48ce17524 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,17 +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->enableNMEA(); // 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
}
@@ -251,14 +240,14 @@ 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;
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;
@@ -272,13 +261,6 @@ void GNSS_MOSAIC::begin()
return;
}
- // Set COM2 (Radio) and COM3 (Data) baud rates
- setRadioBaudRate(settings.radioPortBaud);
- setDataBaudRate(settings.dataPortBaud);
-
- // Set COM2 (Radio) protocol(s)
- setCorrRadioExtPort(settings.enableExtCorrRadio, true); // Force the setting
-
updateSD(); // Check card size and free space
_receiverSetupSeen = false;
@@ -309,13 +291,9 @@ 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
- setRadioBaudRate(settings.radioPortBaud);
- setDataBaudRate(settings.dataPortBaud); // Probably redundant
-
// Set COM2 (Radio) protocol(s)
setCorrRadioExtPort(settings.enableExtCorrRadio, true); // Force the setting
@@ -363,9 +341,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
@@ -384,11 +359,8 @@ 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);
-
if (settings.dataPortChannel != MUX_PPS_EVENTTRIGGER)
return (true); // No need to configure PPS if port is not selected
@@ -436,68 +408,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);
- }
-
- if (settings.gnssConfiguredBase)
- {
- systemPrintln("Skipping mosaic Base configuration");
- setLoggingType(); // Needed because logUpdate exits early and never calls setLoggingType
- return true;
- }
-
- bool response = true;
-
- response &= setModel(MOSAIC_DYN_MODEL_STATIC);
-
- response &= setElevation(settings.minElev);
-
- response &= setMinCnoRadio(settings.minCNO);
-
- response &= setConstellations();
-
- response &= enableRTCMBase();
-
- response &= enableNMEA();
-
- response &= configureLogging();
-
- setLoggingType(); // Update Standard, PPP, or custom for icon selection
-
- // Save the current configuration into non-volatile memory (NVM)
- response &= saveConfiguration();
-
- if (response == false)
- {
- systemPrintln("mosaic-X5 Base failed to configure");
- }
-
- settings.gnssConfiguredBase = response;
-
- return (response);
-}
-
-//----------------------------------------
-bool GNSS_MOSAIC::configureLogging()
+bool GNSS_MOSAIC::setLogging()
{
bool response = true;
String setting;
@@ -588,6 +501,62 @@ 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()
+{
+ 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
+
+ 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:
@@ -597,20 +566,14 @@ bool GNSS_MOSAIC::configureOnce()
{
/*
Configure COM1
- Set minCNO
+ Set minCN0
Set elevationAngle
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)
- {
- systemPrintln("mosaic configuration maintained");
- return (true);
- }
-
bool response = true;
// Configure COM1. NMEA and RTCMv3 will be encapsulated in SBF format
@@ -645,44 +608,18 @@ 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
- settings.gnssConfiguredOnce = response;
-
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::configureGNSS()
-{
- // 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:
@@ -690,55 +627,21 @@ bool GNSS_MOSAIC::configureGNSS()
//----------------------------------------
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);
- }
+ if (gnssInRoverMode())
+ return (true); // No changes needed
- // If our settings haven't changed, trust GNSS's settings
- if (settings.gnssConfiguredRover)
- {
- systemPrintln("Skipping mosaic Rover configuration");
- setLoggingType(); // Needed because logUpdate exits early and never calls setLoggingType
- return (true);
- }
+ // 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 &= setMinCnoRadio(settings.minCNO);
-
- response &= setConstellations();
-
- response &= enableRTCMRover();
-
- response &= enableNMEA();
-
- response &= configureLogging();
-
- setLoggingType(); // Update Standard, PPP, or custom for icon selection
-
- // 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");
- }
-
- settings.gnssConfiguredRover = response;
return (response);
}
@@ -806,386 +709,108 @@ void GNSS_MOSAIC::debuggingEnable()
}
//----------------------------------------
-void GNSS_MOSAIC::enableGgaForNtrip()
+// Restore the GNSS to the factory settings
+//----------------------------------------
+void GNSS_MOSAIC::factoryReset()
{
- // Set the talker ID to GP
- // enableNMEA() will enable GGA if needed
- sendWithResponse("snti,GP\n\r", "NMEATalkerID");
+ 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);
}
//----------------------------------------
-// Turn on all the enabled NMEA messages on COM1
-//----------------------------------------
-bool GNSS_MOSAIC::enableNMEA()
+uint16_t GNSS_MOSAIC::fileBufferAvailable()
{
- 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--;
+ // TODO
+ return 0;
+}
- if (streams[stream].length() > 0)
- streams[stream] += String("+");
- streams[stream] += String(mosaicMessagesNMEA[messageNumber].msgTextName);
+//----------------------------------------
+uint16_t GNSS_MOSAIC::fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead)
+{
+ // TODO
+ return 0;
+}
- // 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;
- }
+//----------------------------------------
+// Start the base using fixed coordinates
+// Outputs:
+// Returns true if successfully started and false upon failure
+//----------------------------------------
+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
- if (strcmp(mosaicMessagesNMEA[messageNumber].msgTextName, "GST") == 0)
- gpgstEnabled = true;
- }
- }
+ bool response = true;
- if (pointPerfectIsEnabled())
+ // TODO: support alternate Datums (ETRS89, NAD83, NAD83_PA, NAD83_MA, GDA94, GDA2020)
+ if (settings.fixedBaseCoordinateType == COORD_TYPE_ECEF)
{
- // 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;
- }
+ 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");
}
-
- if (settings.ntripClient_TransmitGGA == true)
+ else if (settings.fixedBaseCoordinateType == COORD_TYPE_GEODETIC)
{
- // Force on GGA if needed for NTRIP
- if (gpggaEnabled == false)
- {
- if (streams[0].length() > 0)
- streams[0] += String("+");
- streams[0] += String("GGA");
- gpggaEnabled = true;
- }
+ // 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");
}
- // 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);
-}
-
-//----------------------------------------
-// Turn on all the enabled RTCM Base messages on COM1, COM2 and USB1 (if enabled)
-//----------------------------------------
-bool GNSS_MOSAIC::enableRTCMBase()
-{
- 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::enableRTCMRover()
-{
- 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");
- }
+ if (response == false)
+ systemPrintln("Fixed base start failed");
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
+// Check if given GNSS fix rate is allowed
+// Rates are expressed in ms between fixes.
//----------------------------------------
-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()
+bool GNSS_MOSAIC::fixRateIsAllowed(uint32_t fixRateMs)
{
// TODO
- return 0;
+ if (fixRateMs != 1000)
+ return (false);
+ return (true);
}
-//----------------------------------------
-uint16_t GNSS_MOSAIC::fileBufferExtractData(uint8_t *fileBuffer, int fileBytesToRead)
+// Return minimum in milliseconds
+uint32_t GNSS_MOSAIC::fixRateGetMinimumMs()
{
// TODO
- return 0;
+ return (1000);
}
-//----------------------------------------
-// Start the base using fixed coordinates
-// Outputs:
-// Returns true if successfully started and false upon failure
-//----------------------------------------
-bool GNSS_MOSAIC::fixedBaseStart()
+// Return maximum in milliseconds
+uint32_t GNSS_MOSAIC::fixRateGetMaximumMs()
{
- 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);
+ // TODO
+ return (1000);
}
//----------------------------------------
@@ -1415,6 +1040,47 @@ uint8_t GNSS_MOSAIC::getMinute()
return _minute;
}
+//----------------------------------------
+// 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()
+{
+ // 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
+}
+
//----------------------------------------
// Returns month number or zero if not online
//----------------------------------------
@@ -1554,17 +1220,36 @@ uint16_t GNSS_MOSAIC::getYear()
return _year;
}
+//----------------------------------------
+// Returns true if the device is in Base Fixed mode
+//----------------------------------------
+bool GNSS_MOSAIC::gnssInBaseFixedMode()
+{
+ // 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);
+}
+//----------------------------------------
+// Returns true if the device is in Base Survey In mode
+//----------------------------------------
+bool GNSS_MOSAIC::gnssInBaseSurveyInMode()
+{
+ // 0 - Unknown, 1 - Rover, 2 - Base Survey In, 3 - Base Fixed Geodetic, 4 - Base Fixed Cartesian
+ if (getMode() == 2)
+ return (true);
+ 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
+ // 0 - Unknown, 1 - Rover, 2 - Base Survey In, 3 - Base Fixed Geodetic, 4 - Base Fixed Cartesian
+ if (getMode() == 1)
+ return (true);
+ return (false);
}
//----------------------------------------
@@ -1773,6 +1458,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;
@@ -1782,11 +1468,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
}
@@ -1833,6 +1514,8 @@ void GNSS_MOSAIC::menuMessagesNMEA()
settings.mosaicMessageStreamNMEA[incoming] += 1;
if (settings.mosaicMessageStreamNMEA[incoming] > MOSAIC_NUM_NMEA_STREAMS)
settings.mosaicMessageStreamNMEA[incoming] = 0; // Wrap around
+
+ 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
@@ -1851,6 +1534,7 @@ void GNSS_MOSAIC::menuMessagesNMEA()
if (interval >= 1 && interval <= MAX_MOSAIC_MSG_RATES)
{
settings.mosaicStreamIntervalsNMEA[incoming] = interval - 1;
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request receiver to use new settings
}
}
else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT)
@@ -1861,9 +1545,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 +1594,13 @@ 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;
+ 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
systemPrintln("Invalid interval: Min 0.1; Max 600.0");
}
@@ -1924,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;
@@ -1933,9 +1625,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 +1680,12 @@ 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()) // 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
+
systemPrintln("Reset to Defaults");
}
@@ -2003,14 +1698,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;
}
//----------------------------------------
@@ -2021,113 +1708,238 @@ void GNSS_MOSAIC::printModuleInfo()
systemPrintf("mosaic-X5 firmware: %s\r\n", gnssFirmwareVersion);
}
-//----------------------------------------
-// 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 GNSS_MOSAIC::pushRawData(uint8_t *dataToSend, int dataLength)
-{
- // Send data directly from ESP GNSS UART1 to mosaic-X5 COM1
- return (serialGNSS->write(dataToSend, 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 GNSS_MOSAIC::pushRawData(uint8_t *dataToSend, int dataLength)
+{
+ // Send data directly from ESP GNSS UART1 to mosaic-X5 COM1
+ return (serialGNSS->write(dataToSend, dataLength));
+}
+
+//----------------------------------------
+uint16_t GNSS_MOSAIC::rtcmBufferAvailable()
+{
+ // TODO
+ 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
+//----------------------------------------
+void GNSS_MOSAIC::rtcmOnGnssDisable()
+{
+ // TODO: is this needed?
+}
+
+//----------------------------------------
+// If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver
+//----------------------------------------
+void GNSS_MOSAIC::rtcmOnGnssEnable()
+{
+ // TODO: is this needed?
+}
+
+//----------------------------------------
+uint16_t GNSS_MOSAIC::rtcmRead(uint8_t *rtcmBuffer, int rtcmBytesToRead)
+{
+ // TODO
+ return 0;
+}
+
+//----------------------------------------
+// Save the current configuration
+// Outputs:
+// Returns true when the configuration was saved and false upon failure
+//----------------------------------------
+bool GNSS_MOSAIC::saveConfiguration()
+{
+ unsigned long start = millis();
+ bool result = sendWithResponse("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);
+ return result;
+}
+
+//----------------------------------------
+// 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
+// been idle for idle millis
+// If response is defined, copy up to responseSize bytes
+// Inputs:
+// message: Zero terminated string of characters containing the message
+// to send to the GNSS
+// reply: String containing the first portion of the expected response
+// timeout: Number of milliseconds to wat for the reply to arrive
+// idle: Number of milliseconds to wait after last reply character is received
+// response: Address of buffer to receive the response
+// responseSize: Maximum number of bytes to copy
+// Outputs:
+// 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)
+{
+ 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)
+{
+ if (strlen(reply) == 0) // Reply can't be zero-length
+ return false;
+
+ _isBlocking = true; // Suspend the GNSS read task
+
+ if (debug && (settings.debugGnss == true) && (!inMainMenu))
+ systemPrintf("sendAndWaitForIdle: sending %s\r\n", message);
+
+ if (strlen(message) > 0)
+ serialPort->write(message, strlen(message)); // Send the message
+
+ unsigned long startTime = millis();
+ size_t replySeen = 0;
+
+ while (((millis() - startTime) < timeout) && (replySeen < strlen(reply))) // While not timed out and reply not seen
+ {
+ 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 (c == *(reply + replySeen)) // Is it a char from reply?
+ {
+ if (response && (replySeen < (responseSize - 1)))
+ {
+ *(response + replySeen) = c;
+ *(response + replySeen + 1) = 0;
+ }
+ replySeen++;
+ }
+ else
+ replySeen = 0; // Reset replySeen on an unexpected char
+ }
+ }
+
+ if (replySeen == strlen(reply)) // If the reply was seen
+ {
+ startTime = millis();
+ while ((millis() - startTime) < idle)
+ {
+ if (serialPort->available())
+ {
+ uint8_t c = serialPort->read();
+ // if (debug && (settings.debugGnss == true) && (!inMainMenu))
+ // systemPrintf("%c", (char)c);
+ if (response && (replySeen < (responseSize - 1)))
+ {
+ *(response + replySeen) = c;
+ *(response + replySeen + 1) = 0;
+ }
+ replySeen++;
+ startTime = millis();
+ }
+ }
-//----------------------------------------
-uint16_t GNSS_MOSAIC::rtcmBufferAvailable()
-{
- // TODO
- return 0;
-}
+ _isBlocking = false;
-//----------------------------------------
-// If LBand is being used, ignore any RTCM that may come in from the GNSS
-//----------------------------------------
-void GNSS_MOSAIC::rtcmOnGnssDisable()
-{
- // TODO: is this needed?
-}
+ return true;
+ }
-//----------------------------------------
-// If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver
-//----------------------------------------
-void GNSS_MOSAIC::rtcmOnGnssEnable()
-{
- // TODO: is this needed?
-}
+ _isBlocking = false;
-//----------------------------------------
-uint16_t GNSS_MOSAIC::rtcmRead(uint8_t *rtcmBuffer, int rtcmBytesToRead)
-{
- // TODO
- return 0;
+ return false;
}
//----------------------------------------
-// Save the current configuration
+// 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
+// been idle for idle millis
+// If response is defined, copy up to responseSize bytes
+// Inputs:
+// message: String containing the message to send to the GNSS
+// reply: String containing the first portion of the expected response
+// timeout: Number of milliseconds to wat for the reply to arrive
+// idle: Number of milliseconds to wait after last reply character is received
+// response: Address of buffer to receive the response
+// responseSize: Maximum number of bytes to copy
// Outputs:
-// Returns true when the configuration was saved and false upon failure
+// Returns true if the response was received and false upon failure
//----------------------------------------
-bool GNSS_MOSAIC::saveConfiguration()
+bool GNSS_MOSAIC::sendAndWaitForIdle(String message, const char *reply, unsigned long timeout, unsigned long idle,
+ char *response, size_t responseSize, bool debug)
{
- unsigned long start = millis();
- bool result = sendWithResponse("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);
- return result;
+ return sendAndWaitForIdle(message.c_str(), reply, timeout, idle, response, responseSize, debug);
}
//----------------------------------------
// 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
-// been idle for idle millis
-// If response is defined, copy up to responseSize bytes
+// If the reply has started to be received when timeout is reached, wait for a further wait millis
+// If the reply is seen, wait for a further wait millis
+// During wait, keep reading incoming serial. If response is defined, copy up to responseSize bytes
// Inputs:
// message: Zero terminated string of characters containing the message
// to send to the GNSS
// reply: String containing the first portion of the expected response
// timeout: Number of milliseconds to wat for the reply to arrive
-// idle: Number of milliseconds to wait after last reply character is received
+// wait: Number of additional milliseconds if the reply is detected
// response: Address of buffer to receive the response
// responseSize: Maximum number of bytes to copy
// Outputs:
// 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)
+bool GNSS_MOSAIC::sendWithResponse(const char *message, const char *reply, unsigned long timeout, unsigned long wait,
+ char *response, size_t responseSize)
{
if (productVariant == RTK_FACET_MOSAIC)
- return sendAndWaitForIdle(serial2GNSS, message, reply, timeout, wait, response, responseSize, debug);
+ return sendWithResponse(serial2GNSS, message, reply, timeout, wait, response, responseSize);
else
- return sendAndWaitForIdle(serialGNSS, message, reply, timeout, wait, response, responseSize, debug);
+ return sendWithResponse(serialGNSS, message, reply, timeout, wait, response, responseSize);
}
-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::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;
_isBlocking = true; // Suspend the GNSS read task
- if (debug && (settings.debugGnss == true) && (!inMainMenu))
- systemPrintf("sendAndWaitForIdle: sending %s\r\n", message);
+ if ((settings.debugGnss == true) && (!inMainMenu))
+ systemPrintf("sendWithResponse: sending %s\r\n", message);
if (strlen(message) > 0)
serialPort->write(message, strlen(message)); // Send the message
unsigned long startTime = millis();
size_t replySeen = 0;
+ bool keepGoing = true;
- while (((millis() - startTime) < timeout) && (replySeen < strlen(reply))) // While not timed out and reply not seen
+ while ((keepGoing) && (replySeen < strlen(reply))) // While not timed out and reply not seen
{
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 ((settings.debugGnss == true) && (!inMainMenu))
+ // systemPrintf("%c", (char)c);
if (c == *(reply + replySeen)) // Is it a char from reply?
{
if (response && (replySeen < (responseSize - 1)))
@@ -2140,339 +1952,495 @@ bool GNSS_MOSAIC::sendAndWaitForIdle(HardwareSerial *serialPort, const char *mes
else
replySeen = 0; // Reset replySeen on an unexpected char
}
+
+ // If the reply has started to arrive at the timeout, allow extra time
+ if ((millis() - startTime) > timeout) // Have we timed out?
+ if (replySeen == 0) // If replySeen is zero, don't keepGoing
+ keepGoing = false;
+
+ if ((millis() - startTime) > (timeout + wait)) // Have we really timed out?
+ keepGoing = false; // Don't keepGoing
}
if (replySeen == strlen(reply)) // If the reply was seen
{
startTime = millis();
- while ((millis() - startTime) < idle)
+ while ((millis() - startTime) < wait)
+ {
+ if (serialPort->available())
+ {
+ uint8_t c = serialPort->read();
+ if ((settings.debugGnss == true) && (!inMainMenu))
+ systemPrintf("%c", (char)c);
+ if (response && (replySeen < (responseSize - 1)))
+ {
+ *(response + replySeen) = c;
+ *(response + replySeen + 1) = 0;
+ }
+ replySeen++;
+ }
+ }
+
+ _isBlocking = false;
+
+ return true;
+ }
+
+ _isBlocking = false;
+
+ return false;
+}
+
+//----------------------------------------
+// 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
+// If the reply is seen, wait for a further wait millis
+// During wait, keep reading incoming serial. If response is defined, copy up to responseSize bytes
+// Inputs:
+// message: String containing the message to send to the GNSS
+// reply: String containing the first portion of the expected response
+// timeout: Number of milliseconds to wat for the reply to arrive
+// wait: Number of additional milliseconds if the reply is detected
+// response: Address of buffer to receive the response
+// responseSize: Maximum number of bytes to copy
+// Outputs:
+// Returns true if the response was received and false upon failure
+//----------------------------------------
+bool GNSS_MOSAIC::sendWithResponse(String message, const char *reply, unsigned long timeout, unsigned long wait,
+ char *response, size_t responseSize)
+{
+ return sendWithResponse(message.c_str(), reply, timeout, wait, response, responseSize);
+}
+
+//----------------------------------------
+// Set the baud rate of mosaic-X5 COMn - from the super class
+// Inputs:
+// port: COM port number
+// baudRate: New baud rate for the COM port
+// Outputs:
+// Returns true if the baud rate was set and false upon failure
+//----------------------------------------
+bool GNSS_MOSAIC::setBaudRate(uint8_t port, uint32_t baudRate)
+{
+ if (port < 1 || port > 4)
+ {
+ systemPrintln("setBaudRate error: out of range");
+ return (false);
+ }
+
+ 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
+// Inputs:
+// port: COM port number
+// baudRate: New baud rate for the COM port
+// Outputs:
+// Returns true if the baud rate was set and false upon failure
+//----------------------------------------
+bool GNSS_MOSAIC::setBaudRateCOM(uint8_t port, uint32_t baudRate)
+{
+ for (int i = 0; i < MAX_MOSAIC_COM_RATES; i++)
+ {
+ if (baudRate == mosaicComRates[i].rate)
+ {
+ String setting =
+ String("scs,COM" + String(port) + "," + String(mosaicComRates[i].name) + ",bits8,No,bit1,none\n\r");
+ return (sendWithResponse(setting, "COMSettings"));
+ }
+ }
+
+ return false; // Invalid baud
+}
+
+//----------------------------------------
+// Enable all the valid constellations and bands for this platform
+//----------------------------------------
+bool GNSS_MOSAIC::setConstellations()
+{
+ String enabledConstellations = "";
+
+ for (int constellation = 0; constellation < MAX_MOSAIC_CONSTELLATIONS; constellation++)
+ {
+ if (settings.mosaicConstellations[constellation] > 0) // == true
+ {
+ if (enabledConstellations.length() > 0)
+ enabledConstellations += String("+");
+ enabledConstellations += String(mosaicSignalConstellations[constellation].name);
+ }
+ }
+
+ if (enabledConstellations.length() == 0)
+ enabledConstellations = String("none");
+
+ String setting = String("sst," + enabledConstellations + "\n\r");
+ return (sendWithResponse(setting, "SatelliteTracking", 1000, 200));
+}
+
+// Enable / disable corrections protocol(s) on the Radio External port
+// Always update if force is true. Otherwise, only update if enable has changed state
+// Notes:
+// NrBytesReceived is reset when sdio,COM2 is sent. This causes NrBytesReceived to
+// be less than previousNrBytesReceived, which in turn causes a corrections timeout.
+// So, we need to reset previousNrBytesReceived and firstTimeNrBytesReceived here.
+bool GNSS_MOSAIC::setCorrRadioExtPort(bool enable, bool force)
+{
+ if (force || (enable != _corrRadioExtPortEnabled))
+ {
+ String setting = String("sdio,COM2,");
+ if (enable)
+ setting += String("RTCMv3,");
+ else
+ setting += String("none,");
+ // Configure COM2 for NMEA and RTCMv3 output. No L-Band. Not encapsulated.
+ setting += String("RTCMv3+NMEA\n\r");
+
+ if (sendWithResponse(setting, "DataInOut"))
{
- if (serialPort->available())
+ if ((settings.debugCorrections == true) && !inMainMenu)
{
- uint8_t c = serialPort->read();
- //if (debug && (settings.debugGnss == true) && (!inMainMenu))
- // systemPrintf("%c", (char)c);
- if (response && (replySeen < (responseSize - 1)))
- {
- *(response + replySeen) = c;
- *(response + replySeen + 1) = 0;
- }
- replySeen++;
- startTime = millis();
+ systemPrintf("Radio Ext corrections: %s -> %s%s\r\n", _corrRadioExtPortEnabled ? "enabled" : "disabled",
+ enable ? "enabled" : "disabled", force ? " (Forced)" : "");
}
- }
- _isBlocking = false;
-
- return true;
+ _corrRadioExtPortEnabled = enable;
+ previousNrBytesReceived = 0;
+ firstTimeNrBytesReceived = true;
+ return true;
+ }
+ else
+ {
+ systemPrintf("Radio Ext corrections FAILED: %s -> %s%s\r\n",
+ _corrRadioExtPortEnabled ? "enabled" : "disabled", enable ? "enabled" : "disabled",
+ force ? " (Forced)" : "");
+ }
}
- _isBlocking = false;
-
return false;
}
//----------------------------------------
-// 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
-// been idle for idle millis
-// If response is defined, copy up to responseSize bytes
+// Set the elevation in degrees
// Inputs:
-// message: String containing the message to send to the GNSS
-// reply: String containing the first portion of the expected response
-// timeout: Number of milliseconds to wat for the reply to arrive
-// idle: Number of milliseconds to wait after last reply character is received
-// response: Address of buffer to receive the response
-// responseSize: Maximum number of bytes to copy
-// Outputs:
-// Returns true if the response was received and false upon failure
+// elevationDegrees: The elevation value in degrees
+// Notes:
+// mosaic supports negative elevations, but our firmware only support 0-90
//----------------------------------------
-bool GNSS_MOSAIC::sendAndWaitForIdle(String message, const char *reply, unsigned long timeout, unsigned long idle,
- char *response, size_t responseSize, bool debug)
+bool GNSS_MOSAIC::setElevation(uint8_t elevationDegrees)
{
- return sendAndWaitForIdle(message.c_str(), reply, timeout, idle, response, responseSize, debug);
+ if (elevationDegrees > 90)
+ elevationDegrees = 90;
+ String elev = String(elevationDegrees);
+ String setting = String("sem,PVT," + elev + "\n\r");
+ return (sendWithResponse(setting, "ElevationMask"));
}
//----------------------------------------
-// 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
-// If the reply is seen, wait for a further wait millis
-// During wait, keep reading incoming serial. If response is defined, copy up to responseSize bytes
-// Inputs:
-// message: Zero terminated string of characters containing the message
-// to send to the GNSS
-// reply: String containing the first portion of the expected response
-// timeout: Number of milliseconds to wat for the reply to arrive
-// wait: Number of additional milliseconds if the reply is detected
-// response: Address of buffer to receive the response
-// responseSize: Maximum number of bytes to copy
-// Outputs:
-// Returns true if the response was received and false upon failure
+// Control whether HAS E6 is used in location fixes or not
//----------------------------------------
-bool GNSS_MOSAIC::sendWithResponse(const char *message, const char *reply, unsigned long timeout, unsigned long wait,
- char *response, size_t responseSize)
+bool GNSS_MOSAIC::setHighAccuracyService(bool enableGalileoHas)
{
- if (productVariant == RTK_FACET_MOSAIC)
- return sendWithResponse(serial2GNSS, message, reply, timeout, wait, response, responseSize);
- else
- return sendWithResponse(serialGNSS, message, reply, timeout, wait, response, responseSize);
+ // Not yet supported on this platform
+ return (true); // Return true to clear gnssConfigure test
}
-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;
-
- _isBlocking = true; // Suspend the GNSS read task
-
- if ((settings.debugGnss == true) && (!inMainMenu))
- systemPrintf("sendWithResponse: sending %s\r\n", message);
- if (strlen(message) > 0)
- serialPort->write(message, strlen(message)); // Send the message
+//----------------------------------------
+// Set the minimum satellite signal level for navigation.
+//----------------------------------------
+bool GNSS_MOSAIC::setMinCN0(uint8_t cnoValue)
+{
+ if (cnoValue > 60)
+ cnoValue = 60;
+ String cn0 = String(cnoValue);
+ String setting = String("scm,all," + cn0 + "\n\r");
+ return (sendWithResponse(setting, "CN0Mask", 1000, 200));
+}
- unsigned long startTime = millis();
- size_t replySeen = 0;
- bool keepGoing = true;
+//----------------------------------------
+// Turn on all the enabled NMEA messages on COM1
+//----------------------------------------
+bool GNSS_MOSAIC::setMessagesNMEA()
+{
+ bool gpggaEnabled = false;
+ bool gpzdaEnabled = false;
+ bool gpgstEnabled = false;
- while ((keepGoing) && (replySeen < strlen(reply))) // While not timed out and reply not seen
+ 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
{
- if (serialPort->available()) // If a char is available
+ int stream = settings.mosaicMessageStreamNMEA[messageNumber];
+ if (stream > 0)
{
- uint8_t c = serialPort->read(); // Read it
- //if ((settings.debugGnss == true) && (!inMainMenu))
- // systemPrintf("%c", (char)c);
- if (c == *(reply + replySeen)) // Is it a char from reply?
+ 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)
{
- if (response && (replySeen < (responseSize - 1)))
- {
- *(response + replySeen) = c;
- *(response + replySeen + 1) = 0;
- }
- replySeen++;
+ // 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;
}
- else
- replySeen = 0; // Reset replySeen on an unexpected char
- }
-
- // If the reply has started to arrive at the timeout, allow extra time
- if ((millis() - startTime) > timeout) // Have we timed out?
- if (replySeen == 0) // If replySeen is zero, don't keepGoing
- keepGoing = false;
- if ((millis() - startTime) > (timeout + wait)) // Have we really timed out?
- keepGoing = false; // Don't keepGoing
+ if (strcmp(mosaicMessagesNMEA[messageNumber].msgTextName, "GST") == 0)
+ gpgstEnabled = true;
+ }
}
- if (replySeen == strlen(reply)) // If the reply was seen
+ if (pointPerfectIsEnabled())
{
- startTime = millis();
- while ((millis() - startTime) < wait)
+ // Force on any messages that are needed for PPL
+ if (gpggaEnabled == false)
{
- if (serialPort->available())
- {
- uint8_t c = serialPort->read();
- //if ((settings.debugGnss == true) && (!inMainMenu))
- // systemPrintf("%c", (char)c);
- if (response && (replySeen < (responseSize - 1)))
- {
- *(response + replySeen) = c;
- *(response + replySeen + 1) = 0;
- }
- replySeen++;
- }
+ // 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;
}
+ }
- _isBlocking = false;
+ if (settings.ntripClient_TransmitGGA == true && settings.enableNtripClient == 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;
+ }
+ }
- return 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;
}
- _isBlocking = false;
+ bool response = true;
- return false;
-}
+ for (int stream = 0; stream < MOSAIC_NUM_NMEA_STREAMS; stream++)
+ {
+ if (streams[stream].length() == 0)
+ streams[stream] = String("none");
-//----------------------------------------
-// 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
-// If the reply is seen, wait for a further wait millis
-// During wait, keep reading incoming serial. If response is defined, copy up to responseSize bytes
-// Inputs:
-// message: String containing the message to send to the GNSS
-// reply: String containing the first portion of the expected response
-// timeout: Number of milliseconds to wat for the reply to arrive
-// wait: Number of additional milliseconds if the reply is detected
-// response: Address of buffer to receive the response
-// responseSize: Maximum number of bytes to copy
-// Outputs:
-// Returns true if the response was received and false upon failure
-//----------------------------------------
-bool GNSS_MOSAIC::sendWithResponse(String message, const char *reply, unsigned long timeout, unsigned long wait,
- char *response, size_t responseSize)
-{
- return sendWithResponse(message.c_str(), reply, timeout, wait, response, responseSize);
+ 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 baud rate of mosaic-X5 COMn - from the super class
-// Inputs:
-// port: COM port number
-// baudRate: New baud rate for the COM port
-// Outputs:
-// Returns true if the baud rate was set and false upon failure
+// Turn on all the enabled RTCM Base messages on COM1, COM2 and USB1 (if enabled)
//----------------------------------------
-bool GNSS_MOSAIC::setBaudRate(uint8_t port, uint32_t baudRate)
+bool GNSS_MOSAIC::setMessagesRTCMBase()
{
- if (port < 1 || port > 4)
+ bool response = true;
+
+ // Set RTCMv3 Intervals
+ for (int group = 0; group < MAX_MOSAIC_RTCM_V3_INTERVAL_GROUPS; group++)
{
- systemPrintln("setBaudRate error: out of range");
- return (false);
+ 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");
}
- return setBaudRateCOM(port, baudRate);
-}
-
-//----------------------------------------
-// Set the baud rate of mosaic-X5 COM1
-// This is used during the Bluetooth test
-// Inputs:
-// port: COM port number
-// baudRate: New baud rate for the COM port
-// Outputs:
-// Returns true if the baud rate was set and false upon failure
-//----------------------------------------
-bool GNSS_MOSAIC::setBaudRateCOM(uint8_t port, uint32_t baudRate)
-{
- for (int i = 0; i < MAX_MOSAIC_COM_RATES; i++)
+ // Enable RTCMv3
+ String messages = String("");
+ for (int message = 0; message < MAX_MOSAIC_RTCM_V3_MSG; message++)
{
- if (baudRate == mosaicComRates[i].rate)
+ if (settings.mosaicMessageEnabledRTCMv3Base[message])
{
- String setting =
- String("scs,COM" + String(port) + "," + String(mosaicComRates[i].name) + ",bits8,No,bit1,none\n\r");
- return (sendWithResponse(setting, "COMSettings"));
+ if (messages.length() > 0)
+ messages += String("+");
+ messages += String(mosaicMessagesRTCMv3[message].name);
}
}
- return false; // Invalid baud
-}
+ if (messages.length() == 0)
+ messages = String("none");
-//----------------------------------------
-// Enable all the valid constellations and bands for this platform
-//----------------------------------------
-bool GNSS_MOSAIC::setConstellations()
-{
- String enabledConstellations = "";
+ String setting = String("sr3o,COM1+COM2");
+ if (settings.enableGnssToUsbSerial)
+ setting += String("+USB1");
+ setting += String("," + messages + "\n\r");
+ response &= sendWithResponse(setting, "RTCMv3Output");
- for (int constellation = 0; constellation < MAX_MOSAIC_CONSTELLATIONS; constellation++)
+ if (!settings.enableGnssToUsbSerial)
{
- if (settings.mosaicConstellations[constellation] > 0) // == true
- {
- if (enabledConstellations.length() > 0)
- enabledConstellations += String("+");
- enabledConstellations += String(mosaicSignalConstellations[constellation].name);
- }
+ response &= sendWithResponse("sr3o,USB1,none\n\r", "RTCMv3Output");
}
- if (enabledConstellations.length() == 0)
- enabledConstellations = String("none");
-
- String setting = String("sst," + enabledConstellations + "\n\r");
- return (sendWithResponse(setting, "SatelliteTracking", 1000, 200));
+ 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
-// Notes:
-// NrBytesReceived is reset when sdio,COM2 is sent. This causes NrBytesReceived to
-// be less than previousNrBytesReceived, which in turn causes a corrections timeout.
-// So, we need to reset previousNrBytesReceived and firstTimeNrBytesReceived here.
-bool GNSS_MOSAIC::setCorrRadioExtPort(bool enable, bool force)
+//----------------------------------------
+// Turn on all the enabled RTCM Rover messages on COM1, COM2 and USB1 (if enabled)
+//----------------------------------------
+bool GNSS_MOSAIC::setMessagesRTCMRover()
{
- if (force || (enable != _corrRadioExtPortEnabled))
+ 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++)
{
- String setting = String("sdio,COM2,");
- if (enable)
- setting += String("RTCMv3,");
- else
- setting += String("none,");
- // Configure COM2 for NMEA and RTCMv3 output. No L-Band. Not encapsulated.
- setting += String("RTCMv3+NMEA\n\r");
+ 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");
+ }
- if (sendWithResponse(setting, "DataInOut"))
+ // Enable RTCMv3
+ String messages = String("");
+ for (int message = 0; message < MAX_MOSAIC_RTCM_V3_MSG; message++)
+ {
+ if (settings.mosaicMessageEnabledRTCMv3Rover[message])
{
- if ((settings.debugCorrections == true) && !inMainMenu)
+ 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())
{
- systemPrintf("Radio Ext corrections: %s -> %s%s\r\n", _corrRadioExtPortEnabled ? "enabled" : "disabled",
- enable ? "enabled" : "disabled", force ? " (Forced)" : "");
+ // 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;
}
+ }
+ }
- _corrRadioExtPortEnabled = enable;
- previousNrBytesReceived = 0;
- firstTimeNrBytesReceived = true;
- return true;
+ if (pointPerfectIsEnabled())
+ {
+ // Force on any messages that are needed for PPL
+ if (rtcm1019Enabled == false)
+ {
+ if (messages.length() > 0)
+ messages += String("+");
+ messages += String("RTCM1019");
}
- else
+ if (rtcm1020Enabled == false)
{
- systemPrintf("Radio Ext corrections FAILED: %s -> %s%s\r\n",
- _corrRadioExtPortEnabled ? "enabled" : "disabled", enable ? "enabled" : "disabled",
- force ? " (Forced)" : "");
+ 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");
}
}
- return false;
-}
-
-//----------------------------------------
-bool GNSS_MOSAIC::setDataBaudRate(uint32_t baud)
-{
- return setBaudRateCOM(3, baud);
-}
-
-//----------------------------------------
-// Set the elevation in degrees
-// Inputs:
-// elevationDegrees: The elevation value in degrees
-// Notes:
-// mosaic supports negative elevations, but our firmware only support 0-90
-//----------------------------------------
-bool GNSS_MOSAIC::setElevation(uint8_t elevationDegrees)
-{
- if (elevationDegrees > 90)
- elevationDegrees = 90;
- String elev = String(elevationDegrees);
- String setting = String("sem,PVT," + elev + "\n\r");
- return (sendWithResponse(setting, "ElevationMask"));
-}
+ if (messages.length() == 0)
+ messages = String("none");
-//----------------------------------------
-// Enable all the valid messages for this platform
-//----------------------------------------
-bool GNSS_MOSAIC::setMessages(int maxRetries)
-{
- // TODO : do we need this?
- return true;
-}
+ String setting = String("sr3o,COM1+COM2");
+ if (settings.enableGnssToUsbSerial)
+ setting += String("+USB1");
+ setting += String("," + messages + "\n\r");
+ response &= sendWithResponse(setting, "RTCMv3Output");
-//----------------------------------------
-// Enable all the valid messages for this platform over the USB port
-//----------------------------------------
-bool GNSS_MOSAIC::setMessagesUsb(int maxRetries)
-{
- // TODO : do we need this?
- return true;
-}
+ if (!settings.enableGnssToUsbSerial)
+ {
+ response &= sendWithResponse("sr3o,USB1,none\n\r", "RTCMv3Output");
+ }
-//----------------------------------------
-// Set the minimum satellite signal level for navigation.
-//----------------------------------------
-bool GNSS_MOSAIC::setMinCnoRadio(uint8_t cnoValue)
-{
- if (cnoValue > 60)
- cnoValue = 60;
- String cn0 = String(cnoValue);
- String setting = String("scm,all," + cn0 + "\n\r");
- return (sendWithResponse(setting, "CN0Mask", 1000, 200));
+ return (response);
}
//----------------------------------------
@@ -2495,9 +2463,19 @@ bool GNSS_MOSAIC::setModel(uint8_t modelNumber)
}
//----------------------------------------
-bool GNSS_MOSAIC::setRadioBaudRate(uint32_t baud)
+// Configure multipath mitigation
+//----------------------------------------
+bool GNSS_MOSAIC::setMultipathMitigation(bool enableMultipathMitigation)
{
- return setBaudRateCOM(2, baud);
+ // 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)
+{
+ // TODO
+ return (false);
}
//----------------------------------------
@@ -2521,19 +2499,12 @@ bool GNSS_MOSAIC::setRate(double secondsBetweenSolutions)
}
//----------------------------------------
-bool GNSS_MOSAIC::setTalkerGNGGA()
-{
- return sendWithResponse("snti,GN\n\r", "NMEATalkerID");
-}
-
-//----------------------------------------
-// Hotstart GNSS to try to get RTK lock
+// Enable/disable any output needed for tilt compensation
//----------------------------------------
-bool GNSS_MOSAIC::softwareReset()
+bool GNSS_MOSAIC::setTilt()
{
- // 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;
+ // Not yet supported on this platform
+ return (true); // Return true to clear gnssConfigure test
}
//----------------------------------------
@@ -2595,7 +2566,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
@@ -2608,7 +2580,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);
}
@@ -2621,7 +2594,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
@@ -2657,7 +2631,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;
@@ -2765,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);
}
@@ -2955,9 +2931,12 @@ 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()
{
+ systemPrintln("Starting communication with mosaic-X5");
+ paintMosaicBooting();
+
if (productVariant != RTK_FLEX) // productVariant == RTK_FACET_MOSAIC
{
// Set COM4 to: CMD input (only), SBF output (only)
@@ -2968,12 +2947,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;
@@ -3005,7 +2986,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);
}
}
@@ -3277,7 +3258,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");
@@ -3297,14 +3279,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_None.h b/Firmware/RTK_Everywhere/GNSS_None.h
index 879804b6e..dd5e94b10 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 setMinCnoRadio(uint8_t cnoValue)
+ bool setMinCN0(uint8_t cnoValue)
{
return false;
}
-public:
+ public:
// Constructor
GNSS_None() : GNSS()
{
@@ -74,21 +65,21 @@ 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()
+ bool checkNMEARates()
{
return false;
}
- bool checkNMEARates()
+ bool checkPPPRates()
{
return false;
}
- 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()
{
return false;
}
@@ -155,19 +146,6 @@ class GNSS_None : public 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()
- {
- return false;
- }
-
// Restore the GNSS to the factory settings
void factoryReset()
{
@@ -191,6 +169,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()
{
@@ -299,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()
{
@@ -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()
{
@@ -375,6 +370,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;
@@ -501,6 +510,12 @@ class GNSS_None : public GNSS
return dataLength;
}
+ // Hardware or software reset the GNSS receiver
+ bool reset()
+ {
+ return true;
+ }
+
uint16_t rtcmBufferAvailable()
{
return 0;
@@ -534,19 +549,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;
}
@@ -559,14 +584,32 @@ class GNSS_None : public GNSS
return true;
}
- // Enable all the valid messages for this platform
- bool setMessages(int maxRetries)
+ // Control whether HAS E6 is used in location fixes or not
+ bool setHighAccuracyService(bool enableGalileoHas)
+ {
+ return true;
+ }
+
+ // Configure device-direct logging. Currently mosaic-X5 specific.
+ bool setLogging()
+ {
+ return true;
+ }
+
+ // Configure NMEA messages
+ bool setMessagesNMEA()
+ {
+ return true;
+ }
+
+ // Configure RTCM Base messages
+ bool setMessagesRTCMBase()
{
return true;
}
- // Enable all the valid messages for this platform over the USB port
- bool setMessagesUsb(int maxRetries)
+ // Configure RTCM Base messages
+ bool setMessagesRTCMRover()
{
return true;
}
@@ -579,11 +622,23 @@ class GNSS_None : public GNSS
return true;
}
- bool setRadioBaudRate(uint32_t baud)
+ 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;
+ }
+
+ // 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
@@ -595,13 +650,7 @@ class GNSS_None : public GNSS
return true;
}
- bool setTalkerGNGGA()
- {
- return true;
- }
-
- // Hotstart GNSS to try to get RTK lock
- bool softwareReset()
+ bool setTilt()
{
return true;
}
diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.h b/Firmware/RTK_Everywhere/GNSS_UM980.h
index 588f228c1..3d28b6e8f 100644
--- a/Firmware/RTK_Everywhere/GNSS_UM980.h
+++ b/Firmware/RTK_Everywhere/GNSS_UM980.h
@@ -111,23 +111,11 @@ class GNSS_UM980 : GNSS
// Not Rover or Base specific (ie, baud rates)
// Outputs:
// Returns true if successfully configured and false upon failure
- bool configureGNSS();
+ bool configure();
// Turn off all NMEA and RTCM
void disableAllOutput();
- // Disable all output, then re-enable
- void disableRTCM();
-
- // 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
@@ -143,19 +131,10 @@ 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.
- bool setMinCnoRadio(uint8_t cnoValue);
-
- bool setMultipathMitigation(bool enableMultipathMitigation);
+ bool setMinCN0(uint8_t cnoValue);
public:
// Constructor
@@ -186,12 +165,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();
@@ -225,14 +198,6 @@ class GNSS_UM980 : GNSS
void debuggingEnable();
- 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();
@@ -245,6 +210,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();
@@ -299,12 +271,13 @@ 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 getMinCno();
-
// 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();
@@ -334,17 +307,16 @@ 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();
// 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();
@@ -420,6 +392,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();
@@ -433,6 +408,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,38 +428,42 @@ class GNSS_UM980 : GNSS
return true;
}
- bool setDataBaudRate(uint32_t baud);
-
// Set the elevation in degrees
// Inputs:
// elevationDegrees: The elevation value in degrees
bool setElevation(uint8_t elevationDegrees);
- // Enable all the valid messages for this platform
- bool setMessages(int maxRetries);
+ // Configure any logging settings - currently mosaic-X5 specific
+ bool setLogging();
+
+ // Turn on all the enabled NMEA messages on COM3
+ bool setMessagesNMEA();
- // Enable all the valid messages for this platform over the USB port
- bool setMessagesUsb(int maxRetries);
+ // Turn on all the enabled RTCM Rover messages on COM3
+ bool setMessagesRTCMRover();
+
+ // 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 all NMEA message report rates to one value
- void setNmeaMessageRates(uint8_t msgRate);
+ bool setMultipathMitigation(bool enableMultipathMitigation);
// 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);
// 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
@@ -482,10 +472,8 @@ class GNSS_UM980 : GNSS
// failure
bool setRate(double secondsBetweenSolutions);
- bool setTalkerGNGGA();
-
- // Hotstart GNSS to try to get RTK lock
- bool softwareReset();
+ // Enable/disable any output needed for tilt compensation
+ bool setTilt();
bool standby();
diff --git a/Firmware/RTK_Everywhere/GNSS_UM980.ino b/Firmware/RTK_Everywhere/GNSS_UM980.ino
index 9a67c9757..1614794f7 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
@@ -70,7 +74,7 @@ void GNSS_UM980::begin()
_um980 = new UM980();
// 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();
@@ -81,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
@@ -98,11 +102,9 @@ void GNSS_UM980::begin()
systemPrintln("GNSS UM980 online");
+ // Turn on/off debug messages
if (settings.debugGnss)
- debuggingEnable(); // Print all debug to Serial
-
- // Check firmware version and print info
- printModuleInfo();
+ debuggingEnable();
// 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());
@@ -112,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;
@@ -124,8 +127,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 +134,19 @@ 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
+
+ // Read, modify, write
+ // 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.
+
+ // 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
}
//----------------------------------------
@@ -159,130 +166,57 @@ bool GNSS_UM980::checkPPPRates()
//----------------------------------------
bool GNSS_UM980::configureBase()
{
- /*
- Disable all messages
- Start base
- 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;
- // }
+ // If we are already in the appropriate base mode, no changes needed
+ if (settings.fixedBase == false && gnssInBaseSurveyInMode())
+ return (true);
+ if (settings.fixedBase == true && gnssInBaseFixedMode())
+ return (true);
- disableAllOutput();
-
- bool response = 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
- // um980BaseAverageStart().
- response &= setModel(settings.dynamicModel);
-
- response &= setMultipathMitigation(settings.enableMultipathMitigation);
-
- response &= setHighAccuracyService(settings.enableGalileoHas);
-
- response &= enableRTCMBase(); // Only turn on messages, do not turn off messages. We assume the caller has
- // UNLOG or similar.
+ // a surveyInStart().
+ gnssConfigure(GNSS_CONFIG_MODEL);
- // Only turn on messages, do not turn off messages. We assume the caller has UNLOG or similar.
- response &= enableNMEA();
+ // Request a change to Base RTCM
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE);
- // 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;
-
- return (response);
+ return (true);
}
//----------------------------------------
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 COM3 - BT, config and LoRa Radio. Configured for 115200 from begin().
- Set minCNO
- Set elevationAngle
- Set Constellations
- Set messages
- 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 &= _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
-
- // // 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
- // 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.
+ if (settings.debugGnssConfig)
+ systemPrintln("Configuring UM980");
- response &= setMinCnoRadio(settings.minCNO);
+ // Read, modify, write
- response &= setConstellations();
+ // Output must be disabled before sending SIGNALGROUP command in order to get the OK response
+ disableAllOutput(); // Disable COM1/2/3
- if (_um980->isConfigurationPresent("CONFIG SIGNALGROUP 2") == false)
+ if (_um980->sendCommand("CONFIG SIGNALGROUP 2") == false)
{
- if (_um980->sendCommand("CONFIG SIGNALGROUP 2") == false)
- systemPrintln("Signal group 2 command failed");
- 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("Signal group 2 command failed");
+ response = false;
+ }
+ else
+ {
+ systemPrintln("Enabling additional reception on UM980. This can take a few seconds.");
- systemPrintln("UM980 has completed reboot.");
+ while (1)
+ {
+ delay(1000); // Wait for device to reboot
+ if (_um980->isConnected())
+ break;
+ else
+ systemPrintln("UM980 rebooting");
}
+
+ systemPrintln("UM980 has completed reboot.");
}
if (response)
@@ -290,15 +224,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);
}
@@ -314,7 +243,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++)
{
@@ -324,10 +253,7 @@ bool GNSS_UM980::configureGNSS()
// 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");
@@ -339,70 +265,25 @@ bool GNSS_UM980::configureGNSS()
//----------------------------------------
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
- */
- 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);
-
- 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.
+ // 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);
- // Only turn on messages, do not turn off messages. We assume the caller has UNLOG or similar.
- response &= enableRTCMRover();
- // TODO consider reducing the GSV sentence to 1/4 of the GPGGA setting
+ // Assume we are changing from Base to Rover, request any additional config changes
- // Only turn on messages, do not turn off messages. We assume the caller has UNLOG or similar.
- response &= enableNMEA();
+ // Sets the dynamic model (Survey/UAV/Automotive) and puts the device into Rover mode
+ gnssConfigure(GNSS_CONFIG_MODEL);
- // Save the current configuration into non-volatile memory (NVM)
- response &= _um980->saveConfiguration();
+ // Request a change to Rover RTCM
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER);
- if (response == false)
- {
- systemPrintln("UM980 Rover failed to configure");
- }
-
- settings.gnssConfiguredRover = response;
-
- return (response);
+ return (true);
}
//----------------------------------------
@@ -440,6 +321,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()
{
@@ -461,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
@@ -481,171 +364,6 @@ void GNSS_UM980::disableAllOutput()
systemPrintln("UM980 failed to disable output");
}
-//----------------------------------------
-// Disable all output, then re-enable NMEA
-//----------------------------------------
-void GNSS_UM980::disableRTCM()
-{
- disableAllOutput();
- enableNMEA();
-}
-
-//----------------------------------------
-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);
- }
-
- 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);
- }
-
- 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.
-// 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
//----------------------------------------
@@ -685,11 +403,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);
@@ -708,6 +430,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
//----------------------------------------
@@ -939,6 +687,23 @@ 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)
+ {
+ int mode = _um980->getMode();
+ if (settings.debugGnssConfig)
+ systemPrintf("getMode(): %d\r\n", mode);
+
+ return (mode);
+ }
+ return (0);
+}
+
//----------------------------------------
// Returns month number or zero if not online
//----------------------------------------
@@ -1085,17 +850,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
@@ -1291,10 +1079,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;
@@ -1304,9 +1094,6 @@ void GNSS_UM980::menuConstellations()
printUnknown(incoming);
}
- // Apply current settings to module
- gnss->setConstellations();
-
clearBuffer(); // Empty buffer of any newline chars
}
@@ -1361,6 +1148,12 @@ void GNSS_UM980::menuMessages()
settings.um980MessageRatesRTCMBase[x] = umMessagesRTCM[x].msgDefaultRate;
systemPrintln("Reset to Defaults");
+
+ 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
}
else if (incoming == 11 || incoming == 12)
{
@@ -1388,13 +1181,15 @@ 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()) // 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
}
else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT)
@@ -1406,12 +1201,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;
}
//----------------------------------------
@@ -1505,11 +1294,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_RTCM_BASE); // Request receiver to use new settings
+ }
}
}
else if (incoming == INPUT_RESPONSE_GETNUMBER_EXIT)
@@ -1520,10 +1318,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
}
@@ -1602,54 +1396,80 @@ 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 setBaudRateCOM3(baudRate);
+ // 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);
+ 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::setBaudRateCOM3(uint32_t baudRate)
+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 (setBaudRate(1, baudRate)); // The DATA port on the Torch is the USB C connector
+}
+
+bool GNSS_UM980::setBaudRateRadio(uint32_t baudRate)
+{
+ return true; // UM980 has no RADIO port
}
//----------------------------------------
// 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()
{
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])
+ 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
+ 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
}
}
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
+ 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
}
}
}
@@ -1657,22 +1477,25 @@ bool GNSS_UM980::setConstellations()
return (response);
}
-//----------------------------------------
-bool GNSS_UM980::setDataBaudRate(uint32_t baud)
-{
- return false; // UM980 has no multiplexer
-}
-
//----------------------------------------
// Set the elevation in degrees
//----------------------------------------
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
+
return _um980->setElevationAngle(elevationDegrees);
+ }
return false;
}
+//----------------------------------------
+// Control whether HAS E6 is used in location fixes or not
//----------------------------------------
bool GNSS_UM980::setHighAccuracyService(bool enableGalileoHas)
{
@@ -1685,10 +1508,13 @@ 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"))
+ {
systemPrintln("Galileo E6 HAS service enabled");
+ }
else
{
systemPrintln("Galileo E6 HAS service failed to enable");
@@ -1696,7 +1522,9 @@ bool GNSS_UM980::setHighAccuracyService(bool enableGalileoHas)
}
if (_um980->sendCommand("CONFIG PPP DATUM WGS84"))
+ {
systemPrintln("WGS84 Datum applied");
+ }
else
{
systemPrintln("WGS84 Datum failed to apply");
@@ -1708,7 +1536,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.
}
@@ -1719,7 +1548,9 @@ 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");
+ }
else
{
systemPrintln("Galileo E6 HAS service failed to disable");
@@ -1731,39 +1562,229 @@ 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
+// Configure device-direct logging. Currently mosaic-X5 specific.
//----------------------------------------
-bool GNSS_UM980::setMessages(int maxRetries)
+bool GNSS_UM980::setLogging()
{
- // We probably don't need this for the UM980
- // TODO return(um980SetMessages(maxRetries));
- return (true);
+ // Not supported on this platform
+ return (true); // Return true to clear gnssConfigure test
}
//----------------------------------------
-// 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.
+// Set the minimum satellite signal level (carrier to noise ratio) for navigation.
//----------------------------------------
-bool GNSS_UM980::setMessagesUsb(int maxRetries)
+bool GNSS_UM980::setMinCN0(uint8_t cn0Value)
{
- // We probably don't need this for the UM980
- // TODO return(um980SetMessagesUsb(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;
}
//----------------------------------------
-// Set the minimum satellite signal level for navigation.
+// Turn on all the enabled NMEA messages on COM3
//----------------------------------------
-bool GNSS_UM980::setMinCnoRadio(uint8_t cnoValue)
+bool GNSS_UM980::setMessagesNMEA()
{
- if (online.gnss)
+ 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)
{
- _um980->setMinCNO(cnoValue);
- return true;
+ um980MessagesEnabled_RTCM_Rover = false;
+ um980MessagesEnabled_RTCM_Base = false;
+
+ // Request reconfigure of RTCM
+ if (inBaseMode()) // If the current system state is Base
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_BASE);
+ else
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER);
}
- return false;
+
+ for (int messageNumber = 0; messageNumber < MAX_UM980_NMEA_MSG; 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)
+ {
+ if (settings.debugGnssConfig)
+ 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
+ }
+ }
+
+ // 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
+ // Enable GGA for NTRIP
+ if (pointPerfectServiceUsesKeys() ||
+ (settings.enableNtripClient == true && settings.ntripClient_TransmitGGA == true))
+ {
+ response &= _um980->setNMEAPortMessage("GPGGA", "COM3", 1);
+ }
+ }
+
+ if (gpzdaEnabled == false)
+ {
+ if (pointPerfectServiceUsesKeys())
+ {
+ response &= _um980->setNMEAPortMessage("GPZDA", "COM3", 1);
+ }
+ }
+
+ if (response == true)
+ um980MessagesEnabled_NMEA = true;
+
+ return (response);
+}
+
+//----------------------------------------
+// Configure RTCM Base messages on COM3 (the connection between ESP32 and UM980)
+//----------------------------------------
+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 (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)
+ {
+ if (settings.debugGnssConfig)
+ 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);
+}
+
+//----------------------------------------
+// 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;
+
+ 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 (settings.um980MessageRatesRTCMRover[messageNumber] > 0)
+ {
+ response &= _um980->setRTCMPortMessage(umMessagesRTCM[messageNumber].msgTextName, "COM3",
+ settings.um980MessageRatesRTCMRover[messageNumber]);
+ if (response == false)
+ {
+ if (settings.debugGnssConfig)
+ 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
+ // 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)
+ um980MessagesEnabled_RTCM_Rover = true;
+
+ return (response);
}
//----------------------------------------
@@ -1773,16 +1794,26 @@ bool GNSS_UM980::setModel(uint8_t modelNumber)
{
if (online.gnss)
{
+ // 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());
else if (modelNumber == UM980_DYN_MODEL_UAV)
return (_um980->setModeRoverUAV());
else if (modelNumber == UM980_DYN_MODEL_AUTOMOTIVE)
return (_um980->setModeRoverAutomotive());
+ else
+ {
+ systemPrintf("Uncaught model: %d\r\n", modelNumber);
+ }
}
return (false);
}
+//----------------------------------------
+// Configure multipath mitigation
//----------------------------------------
bool GNSS_UM980::setMultipathMitigation(bool enableMultipathMitigation)
{
@@ -1794,7 +1825,9 @@ bool GNSS_UM980::setMultipathMitigation(bool enableMultipathMitigation)
if (_um980->isConfigurationPresent("CONFIG MMP ENABLE") == false)
{
if (_um980->sendCommand("CONFIG MMP ENABLE"))
+ {
systemPrintln("Multipath Mitigation enabled");
+ }
else
{
systemPrintln("Multipath Mitigation failed to enable");
@@ -1808,7 +1841,9 @@ bool GNSS_UM980::setMultipathMitigation(bool enableMultipathMitigation)
if (_um980->isConfigurationPresent("CONFIG MMP ENABLE"))
{
if (_um980->sendCommand("CONFIG MMP DISABLE"))
+ {
systemPrintln("Multipath Mitigation disabled");
+ }
else
{
systemPrintln("Multipath Mitigation failed to disable");
@@ -1820,13 +1855,7 @@ bool GNSS_UM980::setMultipathMitigation(bool enableMultipathMitigation)
}
//----------------------------------------
-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
+// Given the number of seconds between desired solution reports, determine measurementRateMs
//----------------------------------------
bool GNSS_UM980::setRate(double secondsBetweenSolutions)
{
@@ -1838,62 +1867,84 @@ 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).
- bool response = true;
- disableAllOutput();
+ // Read/Modify/Write
+ // Determine if we need to modify the setting at all
+ bool changeRequired = false;
- // Overwrite any enabled messages with this rate
+ // 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)
- {
- settings.um980MessageRatesNMEA[messageNumber] = secondsBetweenSolutions;
- }
+ if (settings.um980MessageRatesNMEA[messageNumber] != secondsBetweenSolutions)
+ changeRequired = true;
}
- response &= enableNMEA(); // 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;
- }
+ if (settings.um980MessageRatesRTCMRover[messageNumber] != secondsBetweenSolutions)
+ changeRequired = true;
}
- response &= enableRTCMRover(); // Enact these rates
- // If we successfully set rates, only then record to settings
- if (response)
- {
- uint16_t msBetweenSolutions = secondsBetweenSolutions * 1000;
- settings.measurementRateMs = msBetweenSolutions;
- }
- else
+ if (changeRequired == false)
{
- systemPrintln("Failed to set measurement and navigation rates");
- return (false);
+ if (settings.debugGnssConfig)
+ systemPrintln("setRate: No change required");
+ return (true); // Success
}
+ if (settings.debugGnssConfig)
+ systemPrintln("setRate: Modifying rates");
+
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA);
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER);
+
return (true);
}
//----------------------------------------
-bool GNSS_UM980::setTalkerGNGGA()
+// Enable/disable any output needed for tilt compensation
+//----------------------------------------
+bool GNSS_UM980::setTilt()
{
- // TODO um980SetTalkerGNGGA();
- return false;
+ 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
+ response &= setBaudRate(2, 115200); // UM980 UART2 is connected to the IMU
+ }
+ 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
-// Not used on UM980 based devices
+// Reset the GNSS receiver either through hardware or software
//----------------------------------------
-bool GNSS_UM980::softwareReset()
+bool GNSS_UM980::reset()
{
- return false;
+ // 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 true;
}
//----------------------------------------
@@ -1920,14 +1971,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)
{
@@ -1945,25 +2001,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]);
}
//----------------------------------------
@@ -1993,13 +2049,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)
{
@@ -2041,15 +2090,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()
{
@@ -2062,7 +2102,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
@@ -2070,10 +2110,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();
@@ -2107,8 +2147,8 @@ void um980FirmwareBeginUpdate()
while (!task.endDirectConnectMode)
{
// 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
@@ -2124,14 +2164,36 @@ void um980FirmwareBeginUpdate()
{
// Reset UM980
gnssReset();
- delay(25);
+ delay(500);
gnssBoot();
-
+ delay(500);
inBootMode = true;
}
}
}
+ // 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 set task.endDirectConnectMode true
}
@@ -2143,12 +2205,22 @@ void um980FirmwareBeginUpdate()
ESP.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);
}
//----------------------------------------
@@ -2156,7 +2228,7 @@ bool um980FirmwareCheckUpdate()
//----------------------------------------
void um980FirmwareRemoveUpdate()
{
- gnssFirmwareRemoveUpdateFile("/updateUm980Firmware.txt");
+ gnssFirmwareRemoveUpdateFile(um980FirmwareFileName);
}
//----------------------------------------
diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.h b/Firmware/RTK_Everywhere/GNSS_ZED.h
index 5da4d942f..5a236d5ef 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();
@@ -430,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:
@@ -453,14 +447,6 @@ class GNSS_ZED : GNSS
void debuggingEnable();
- 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();
@@ -473,6 +459,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();
@@ -538,6 +531,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();
@@ -577,6 +574,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();
@@ -662,6 +664,12 @@ 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();
+
uint16_t rtcmBufferAvailable();
// If L-Band is available, but encrypted, allow RTCM through other sources (radio, ESP-NOW) to GNSS receiver
@@ -680,6 +688,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();
@@ -687,34 +701,50 @@ 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
bool setElevation(uint8_t elevationDegrees);
+ // 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);
// 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);
+ // Set the minimum satellite signal level for navigation.
+ bool setMinCN0(uint8_t cnoValue);
+
+ // Set the NMEA messages
+ bool setMessagesNMEA();
- // Enable all the valid messages for this platform over the USB port
- bool setMessagesUsb(int maxRetries);
+ // Set then RTCM Base messages
+ bool setMessagesRTCMBase();
- // Set the minimum satellite signal level for navigation.
- bool setMinCnoRadio(uint8_t cnoValue);
+ // 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
bool setModel(uint8_t modelNumber);
- bool setRadioBaudRate(uint32_t baud);
+ 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
+ // Outputs
+ // Returns true if the pin was successfully setup and false upon
+ // failure
+ bool setPPS();
// Specify the interval between solutions
// Inputs:
@@ -724,10 +754,8 @@ class GNSS_ZED : GNSS
// failure
bool setRate(double secondsBetweenSolutions);
- bool setTalkerGNGGA();
-
- // Hotstart GNSS to try to get RTK lock
- bool softwareReset();
+ // Enable/disable any output needed for tilt compensation
+ bool setTilt();
bool standby();
diff --git a/Firmware/RTK_Everywhere/GNSS_ZED.ino b/Firmware/RTK_Everywhere/GNSS_ZED.ino
index 089d6b377..ca20e2aa5 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,
@@ -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;
@@ -170,10 +174,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;
@@ -214,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);
}
@@ -243,7 +253,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
{
@@ -262,7 +273,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);
@@ -277,7 +288,7 @@ bool GNSS_ZED::beginPPS()
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,15 +298,16 @@ bool GNSS_ZED::beginPPS()
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();
}
if (response == false)
- systemPrintln("beginPPS failed");
+ systemPrintln("setPPS failed");
return (response);
}
@@ -320,291 +332,38 @@ 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
-
- _zed->setNMEAGPGGAcallbackPtr(
- nullptr); // Disable GPGGA call back that may have been set during Rover NTRIP Client mode
-
- 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.
//----------------------------------------
-bool GNSS_ZED::configureGNSS()
+bool GNSS_ZED::configure()
{
if (online.gnss == false)
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);
+ // // 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;
+ // }
+ // }
- // Enable RTCM3 if needed - if not enable NMEA IN to keep skipped updated
- response &= setCorrRadioExtPort(settings.enableExtCorrRadio, true); // Force the setting
-
- 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::configureGNSS()
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::configureGNSS()
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::configureGNSS()
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 &= setMessages(MAX_SET_MESSAGES_RETRIES); // 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,76 @@ bool GNSS_ZED::configureGNSS()
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 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)
{
- systemPrintln("GNSS not online");
- return (false);
+ // 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 our settings haven't changed, trust GNSS's settings
- if (settings.gnssConfiguredRover)
+ // Assume we are changing from Rover to Base, request any additional config changes
+
+ bool response = true;
+
+ 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
+ // 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()
}
- 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 +561,91 @@ 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 Rover configuration");
+ 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);
+ 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,42 +696,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
- }
-}
-
-//----------------------------------------
-// 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
//----------------------------------------
@@ -951,13 +704,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)
@@ -992,10 +745,16 @@ bool GNSS_ZED::fixedBaseStart()
bool response = true;
if (online.gnss == false)
- {
- systemPrintln("GNSS not online");
return (false);
- }
+
+ // If we are already in the appropriate base mode, 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
if (settings.fixedBaseCoordinateType == COORD_TYPE_ECEF)
{
@@ -1016,7 +775,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);
@@ -1056,7 +815,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);
@@ -1067,9 +826,39 @@ 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);
}
+//----------------------------------------
+// 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 >= fixRateGetMinimumMs() && fixRateMs <= fixRateGetMaximumMs())
+ return (true);
+ return (false);
+}
+
+// Return minimum in milliseconds
+uint32_t GNSS_ZED::fixRateGetMinimumMs()
+{
+ return (1000.0 / f9pMaxRateHz); // Max Hz is min ms
+}
+
+// Return maximum in milliseconds
+uint32_t GNSS_ZED::fixRateGetMaximumMs()
+{
+ return (1000.0 / f9pMinRateHz); // Min Hz is max ms
+}
+
//----------------------------------------
// Return the number of active/enabled messages
//----------------------------------------
@@ -1277,6 +1066,37 @@ uint8_t GNSS_ZED::getMinute()
return (_minute);
}
+//----------------------------------------
+// Returns the current mode
+// 0 - Rover, 1 - Base Survey-In, 2 - Base Fixed ECEF, 3 - Base Fixed LLH
+//----------------------------------------
+uint8_t GNSS_ZED::getMode()
+{
+ if (online.gnss)
+ {
+ // Survey mode is only available on ZED-F9P modules
+ if (commandSupported(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
+}
+
//----------------------------------------
// Returns month number or zero if not online
//----------------------------------------
@@ -1338,7 +1158,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);
@@ -1404,6 +1224,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)
@@ -1430,6 +1253,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 || getMode() == 3) // 0 - Rover, 1 - Base Survey-In, 2 - Base Fixed ECEF, 3 - Base Fixed LLH
+ 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 ECEF, 3 - Base Fixed LLH
+ 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
//----------------------------------------
@@ -1769,6 +1625,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;
@@ -1778,9 +1636,6 @@ void GNSS_ZED::menuConstellations()
printUnknown(incoming);
}
- // Apply current settings to module
- setConstellations();
-
clearBuffer(); // Empty buffer of any newline chars
}
@@ -1848,13 +1703,15 @@ 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
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)
{
@@ -1864,7 +1721,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
@@ -1874,16 +1731,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;
@@ -1894,15 +1757,6 @@ 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
- 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
@@ -1949,7 +1803,19 @@ 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);
+
+ // 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);
}
@@ -1983,6 +1849,44 @@ 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
+//----------------------------------------
+bool GNSS_ZED::reset()
+{
+ if (online.gnss == false)
+ return false;
+ _zed->softwareResetGNSSOnly();
+ return true;
+}
+
//----------------------------------------
uint16_t GNSS_ZED::rtcmBufferAvailable()
{
@@ -2034,11 +1938,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
@@ -2170,14 +2093,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
//----------------------------------------
@@ -2191,6 +2106,24 @@ 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 (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
//----------------------------------------
@@ -2239,117 +2172,193 @@ 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
-// Uses dummy newCfg and sendCfg values to be sure we open/close a complete set
+// 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 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()
{
- bool success = false;
+ int maxRetries = MAX_SET_MESSAGES_RETRIES;
- if (online.gnss)
+ bool gpggaEnabled = false;
+
+ bool success = true;
+
+ 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)
+ 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];
-
- response &= _zed->addCfgValset(ubxMessages[messageNumber].msgConfigKey, rate);
- }
- 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
}
}
- return (success);
+
+ // 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);
+ 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);
+ 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)
+ response &= _zed->setNMEAGPGGAcallbackPtr(&zedPushGPGGA);
+ else
+ response &= _zed->setNMEAGPGGAcallbackPtr(nullptr);
+
+ return (response);
}
//----------------------------------------
-// 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;
+ // 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
- if (online.gnss)
+ // 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++)
{
- int tryNo = -1;
+ 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
+ }
- // 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;
+ response &= _zed->sendCfgValset(); // Closing value
- while (messageNumber < MAX_UBX_MSG)
- {
- response &= _zed->newCfgValset(VAL_LAYER_ALL);
+ return (response);
+}
- 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();
- }
+//----------------------------------------
+// Configure RTCM Base messages
+//----------------------------------------
+bool GNSS_ZED::setMessagesRTCMRover()
+{
+ // 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).
- if (response)
- success = true;
- }
+ // 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
}
- return (success);
+
+ response &= _zed->sendCfgValset(); // Closing
+
+ return (response);
}
//----------------------------------------
// Set the minimum satellite signal level for navigation.
//----------------------------------------
-bool GNSS_ZED::setMinCnoRadio(uint8_t cnoValue)
+bool GNSS_ZED::setMinCN0(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->setVal8(UBLOX_CFG_NAVSPG_INFIL_MINCNO,
+ settings.minCN0) ==
+ 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
}
//----------------------------------------
@@ -2366,27 +2375,35 @@ bool GNSS_ZED::setModel(uint8_t modelNumber)
}
//----------------------------------------
-bool GNSS_ZED::setRadioBaudRate(uint32_t baud)
+// Configure multipath mitigation
+//----------------------------------------
+bool GNSS_ZED::setMultipathMitigation(bool enableMultipathMitigation)
{
- if (online.gnss)
- return _zed->setVal32(UBLOX_CFG_UART2_BAUDRATE, baud, VAL_LAYER_ALL);
- return false;
+ // 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
-// 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);
+ // 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)
{
@@ -2437,8 +2454,8 @@ bool GNSS_ZED::setRate(double secondsBetweenSolutions)
// If we successfully set rates, only then record to settings
if (response)
{
- settings.measurementRateMs = measRate;
- settings.navigationRate = navRate;
+ if (baseOverride == false)
+ settings.measurementRateMs = secondsBetweenSolutions * 1000;
}
else
{
@@ -2450,27 +2467,11 @@ bool GNSS_ZED::setRate(double secondsBetweenSolutions)
}
//----------------------------------------
-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;
-}
-
-//----------------------------------------
-// Hotstart GNSS to try to get RTK lock
+// Enable/disable any output needed for tilt compensation
//----------------------------------------
-bool GNSS_ZED::softwareReset()
+bool GNSS_ZED::setTilt()
{
- if (online.gnss == false)
- return false;
- _zed->softwareResetGNSSOnly();
+ // Not yet available on this platform
return true;
}
@@ -2552,8 +2553,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;
@@ -2687,13 +2688,17 @@ 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
+
_zed->setVal8(UBLOX_CFG_TMODE_MODE, 0, VAL_LAYER_ALL); // Disable survey-in mode
delay(100);
@@ -2723,7 +2728,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)
@@ -2746,6 +2752,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);
}
@@ -2813,7 +2826,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/NVM.ino b/Firmware/RTK_Everywhere/NVM.ino
index ed0fdf70e..94dc3f771 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
@@ -1752,29 +1748,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/NtripClient.ino b/Firmware/RTK_Everywhere/NtripClient.ino
index 7c4ff0a3d..9dedcb419 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 settingsChanged = false; // Goes true when a menu or command modified the client credentials
+
//----------------------------------------
// NTRIP Client Routines
//----------------------------------------
@@ -229,7 +231,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)
{
@@ -392,6 +395,13 @@ bool ntripClientEnabled(const char **line)
// Verify still enabled
enabled = settings.enableNtripClient;
+ // Allow restart if settings change
+ if(settingsChanged == true)
+ {
+ settingsChanged = false;
+ ntripClientForcedShutdown = false;
+ }
+
// Determine if the shutdown is being forced
if (enabled && ntripClientForcedShutdown)
{
@@ -587,6 +597,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
//----------------------------------------
@@ -624,8 +640,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;
@@ -823,9 +840,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
@@ -900,8 +915,14 @@ void ntripClientUpdate()
systemPrintln("NTRIP Client resetting connection attempt counter and timeout");
}
+ // Check if the there have been changes to the client settings
+ if(settingsChanged == true)
+ {
+ settingsChanged = 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)
@@ -954,7 +975,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);
@@ -964,7 +985,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);
diff --git a/Firmware/RTK_Everywhere/RTK_Everywhere.ino b/Firmware/RTK_Everywhere/RTK_Everywhere.ino
index 4c1b31ef1..1e700c93b 100644
--- a/Firmware/RTK_Everywhere/RTK_Everywhere.ino
+++ b/Firmware/RTK_Everywhere/RTK_Everywhere.ino
@@ -78,10 +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
-//#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
#define COMPILE_BT // Comment out to remove Bluetooth functionality
@@ -304,7 +300,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;
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
@@ -629,7 +625,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
@@ -936,8 +931,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
@@ -1402,6 +1395,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();
@@ -1421,14 +1417,14 @@ 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
- 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
@@ -1515,9 +1511,6 @@ void loop()
DMW_c("periodicDisplay");
updatePeriodicDisplay();
- DMW_c("gnss->update");
- gnss->update();
-
DMW_c("stateUpdate");
stateUpdate();
@@ -1527,6 +1520,9 @@ void loop()
DMW_c("displayUpdate");
displayUpdate();
+ DMW_c("gnssUpdate");
+ gnssUpdate();
+
DMW_c("rtcUpdate");
rtcUpdate(); // Set system time to GNSS once we have fix
@@ -1643,8 +1639,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)
{
@@ -1665,7 +1659,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.
}
}
diff --git a/Firmware/RTK_Everywhere/States.ino b/Firmware/RTK_Everywhere/States.ino
index a5c3be861..2b7892256 100644
--- a/Firmware/RTK_Everywhere/States.ino
+++ b/Firmware/RTK_Everywhere/States.ino
@@ -96,17 +96,7 @@ void stateUpdate()
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;
- }
+ gnssConfigure(GNSS_CONFIG_ROVER); // Request reconfigure to rover mode
setMuxport(settings.dataPortChannel); // Return mux to original channel
@@ -116,23 +106,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);
@@ -221,38 +217,42 @@ void stateUpdate()
baseStatusLedOff();
- displayBaseStart(0); // Show 'Base'
+ gnssConfigure(GNSS_CONFIG_BASE); // Request reconfigure to base mode
bluetoothStart(); // Start Bluetooth if it is not already started
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)
changeState(STATE_BASE_TEMP_SETTLE);
else
+ {
+ gnssConfigure(GNSS_CONFIG_BASE_FIXED); // Request start of fixed base
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);
+ RTK_MODE(RTK_MODE_BASE_FIXED);
+ }
}
}
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)
@@ -265,29 +265,27 @@ 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);
+
+ // 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 : "",
(accUnits != units) ? ")" : "", siv);
// 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;
@@ -374,22 +372,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;
@@ -461,9 +450,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
@@ -512,11 +501,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);
}
@@ -578,8 +562,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)
@@ -660,6 +644,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):
@@ -672,6 +658,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/System.ino b/Firmware/RTK_Everywhere/System.ino
index 5a94befe1..e991487a3 100644
--- a/Firmware/RTK_Everywhere/System.ino
+++ b/Firmware/RTK_Everywhere/System.ino
@@ -924,11 +924,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);
diff --git a/Firmware/RTK_Everywhere/Tasks.ino b/Firmware/RTK_Everywhere/Tasks.ino
index c651537bd..7b2509362 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
}
}
@@ -865,8 +853,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;
+ }
}
}
}
@@ -1005,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!
@@ -1035,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
@@ -1191,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!
@@ -1204,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
@@ -1260,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);
}
}
@@ -1355,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)
{
@@ -1545,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
@@ -1574,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
@@ -1601,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
}
@@ -1620,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
}
}
@@ -1642,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), "%lu,%lu,%lu,%lu", 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";
@@ -1682,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";
@@ -1716,10 +1717,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
@@ -1728,7 +1729,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();
@@ -1787,7 +1788,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);
}
//----------------------------------------------------------------------
@@ -2036,7 +2038,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;
@@ -2063,7 +2065,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
@@ -2086,10 +2088,9 @@ 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
+ 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))
@@ -2162,10 +2163,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)
@@ -2198,11 +2203,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:
@@ -2283,8 +2290,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()
@@ -2326,7 +2332,7 @@ void buttonCheckTask(void *e)
break;
} // End doubleTap switch (systemState)
} // End doubleTap
- } // End productVariant != Torch
+ } // End productVariant != (Torch | Torch X2)
feedWdt();
taskYIELD();
@@ -2611,10 +2617,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");
diff --git a/Firmware/RTK_Everywhere/Tilt.ino b/Firmware/RTK_Everywhere/Tilt.ino
index f02b15fb7..bda374d6e 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
@@ -1063,14 +1064,14 @@ 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;
}
}
SerialTiltTest.end(); // Release UART1 for reuse
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;
}
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/bluetoothSelect.h b/Firmware/RTK_Everywhere/bluetoothSelect.h
index cb74ea5ee..0f3dbd1c1 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"
@@ -170,14 +171,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;
}
@@ -189,7 +194,8 @@ class BTLESerial : public virtual BTSerialInterface, public BleSerial
void end()
{
- BleSerial::end();
+ BleBufferedSerial::end();
+ // BleSerial::end();
}
esp_err_t register_callback(void * callback)
@@ -199,42 +205,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)
@@ -244,7 +258,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) {}
diff --git a/Firmware/RTK_Everywhere/menuBase.ino b/Firmware/RTK_Everywhere/menuBase.ino
index 4fb9e4937..8c279198c 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: ");
@@ -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);
}
}
@@ -142,12 +142,20 @@ void menuBase()
if (incoming == 1)
{
settings.fixedBase ^= 1;
- restartBase = true;
+
+ // 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;
- restartBase = true;
+
+ // 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)
@@ -174,7 +182,15 @@ void menuBase()
systemPrint("\nECEF Z in meters (ex: 4086669.6393): ");
double fixedEcefZ;
if (getUserInputDouble(&fixedEcefZ) == INPUT_RESPONSE_VALID)
+ {
settings.fixedEcefZ = fixedEcefZ;
+
+ // 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
+ }
}
}
}
@@ -214,7 +230,15 @@ void menuBase()
systemPrint("\r\nAltitude in meters (ex: 1560.2284): ");
double fixedAltitude;
if (getUserInputDouble(&fixedAltitude) == INPUT_RESPONSE_VALID)
+ {
settings.fixedAltitude = fixedAltitude;
+
+ // 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
{
@@ -233,36 +257,69 @@ 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)
+ {
+ // 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?
+ }
}
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)
+ {
+ // 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 == 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)
+ {
+ // 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 == 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)
+ {
+ // 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 == 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)
+ {
+ // 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 (incoming == 7)
@@ -273,7 +330,6 @@ void menuBase()
else if (incoming == 8)
{
settings.enableNtripServer ^= 1;
- restartBase = true;
}
// NTRIP Server entries
@@ -290,7 +346,9 @@ 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)
{
@@ -303,7 +361,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 +374,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 +387,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 +400,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 +413,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 +453,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/menuCommands.ino b/Firmware/RTK_Everywhere/menuCommands.ino
index 91d81ae88..cdac62c90 100644
--- a/Firmware/RTK_Everywhere/menuCommands.ino
+++ b/Firmware/RTK_Everywhere/menuCommands.ino
@@ -1324,14 +1324,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);
}
}
@@ -1363,7 +1363,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);
@@ -1373,8 +1374,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
@@ -1393,10 +1392,11 @@ 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)
{
- // Note: this sends the Min CNO to the GNSS, as well as saving it in settings...
- gnss->setMinCno(settingValue);
+ settings.minCN0 = settingValue;
+ gnssConfigure(GNSS_CONFIG_CN0); // Request receiver to use new settings
+
knownSetting = true;
}
else if (strcmp(settingName, "fixedHAEAPC") == 0)
@@ -1542,7 +1542,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);
@@ -2252,7 +2251,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", settings.minCN0);
stringRecord(newSettings, "enableRCFirmware", enableRCFirmware);
// Add SD Characteristics
@@ -3210,7 +3209,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 259d65ba1..8d5e046c7 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();
@@ -129,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", settings.minCN0);
systemPrint("7) Toggle NTRIP Client: ");
if (settings.enableNtripClient == true)
@@ -178,59 +174,38 @@ 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->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) // 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_FIX_RATE);
+ }
+ 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)
+ if (getNewSetting("Enter GNSS measurement rate in seconds between measurements", minRateS, maxRateS,
+ &requestedRateS) == INPUT_RESPONSE_VALID)
{
- 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)
- {
- 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_FIX_RATE);
+ }
+ else
+ systemPrintln("Error: Illegal rate for this platform");
}
}
else if (incoming == 3 && present.dynamicModel)
@@ -279,7 +254,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
}
@@ -292,7 +267,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)
@@ -304,7 +279,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
}
}
}
@@ -319,30 +294,29 @@ 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)
+ else if (incoming == 6 && present.minCN0)
{
- 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.minCN0) ==
+ INPUT_RESPONSE_VALID)
{
- gnss->setMinCno(minCNO); // Set the setting and configure the GNSS receiver
+ gnssConfigure(GNSS_CONFIG_CN0); // Request receiver to use new settings
}
}
else if (incoming == 7)
{
settings.enableNtripClient ^= 1;
- restartRover = true;
}
else if ((incoming == 8) && settings.enableNtripClient == true)
{
systemPrint("Enter new Caster Address: ");
getUserInputString(settings.ntripClient_CasterHost, sizeof(settings.ntripClient_CasterHost));
- restartRover = true;
+
+ ntripClientSettingsChanged(); // Notify the NTRIP Client state machine of new credentials
}
else if ((incoming == 9) && settings.enableNtripClient == true)
{
@@ -350,43 +324,45 @@ void menuGNSS()
if (getNewSetting("Enter new Caster Port", 1, 99999, &settings.ntripClient_CasterPort) ==
INPUT_RESPONSE_VALID)
{
- restartRover = true;
+ 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));
- restartRover = true;
+ 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));
- restartRover = true;
+ 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));
- restartRover = true;
+ 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));
- restartRover = true;
+ ntripClientSettingsChanged(); // Notify the NTRIP Client state machine of new credentials
}
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.
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_NMEA); // Request update
}
else if ((incoming == 15) && present.multipathMitigation)
{
settings.enableMultipathMitigation ^= 1;
- restartRover = true;
+ gnssConfigure(GNSS_CONFIG_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 486900d01..377208c9f 100644
--- a/Firmware/RTK_Everywhere/menuMain.ino
+++ b/Firmware/RTK_Everywhere/menuMain.ino
@@ -274,31 +274,14 @@ 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
inMainMenu = false;
@@ -473,9 +456,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;
@@ -588,8 +571,7 @@ BluetoothRadioType_e mmChangeBluetoothProtocol(BluetoothRadioType_e bluetoothUse
// Update 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))
{
// To avoid connection failures, we may need to restart the ESP32
@@ -806,8 +788,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/menuMessages.ino b/Firmware/RTK_Everywhere/menuMessages.ino
index f7730f1ab..345c921c9 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)
{
@@ -242,26 +241,25 @@ void menuMessagesBaseRTCM()
if (incoming == 1)
{
gnss->menuMessageBaseRtcm();
- restartBase = true;
}
else if (incoming == 2)
{
gnss->baseRtcmDefault();
+ gnssConfigure(GNSS_CONFIG_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();
+ gnssConfigure(GNSS_CONFIG_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;
+ gnssConfigure(GNSS_CONFIG_MESSAGE_RATE_RTCM_ROVER); // Request receiver to use new settings
}
else if ((incoming == 5) && (namedSettingAvailableOnPlatform("rtcmMinElev")))
{
@@ -272,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
}
}
@@ -693,11 +691,14 @@ void checkGNSSArrayDefaults()
settings.dynamicModel = UM980_DYN_MODEL_SURVEY;
}
- if (settings.enableExtCorrRadio == 254)
- {
- defaultsApplied = true;
- settings.enableExtCorrRadio = false;
- }
+ // 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)
{
@@ -772,6 +773,7 @@ void checkGNSSArrayDefaults()
if (settings.mosaicMessageIntervalsRTCMv3Rover[0] == 0.0)
{
+
defaultsApplied = true;
for (int x = 0; x < MAX_MOSAIC_RTCM_V3_INTERVAL_GROUPS; x++)
@@ -807,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;
}
@@ -874,26 +880,29 @@ 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; // Default 10 dBHz
+ settings.minCN0 = 10; // Default 10 dBHz
settings.surveyInStartingAccuracy = 2.0; // Default 2m
settings.measurementRateMs = 500; // Default 2Hz.
}
}
if (defaultsApplied == true)
+ {
+ gnssConfigureDefaults(); // 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 76028074c..e4c94c2ea 100644
--- a/Firmware/RTK_Everywhere/menuPP.ino
+++ b/Firmware/RTK_Everywhere/menuPP.ino
@@ -340,7 +340,10 @@ void menuPointPerfectSelectService()
{
settings.pointPerfectService = incoming - 1; // Align incoming to array
- restartRover = true; // Require a rover restart to enable / disable RTCM for PPL
+ // 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
@@ -781,7 +784,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);
diff --git a/Firmware/RTK_Everywhere/menuPorts.ino b/Firmware/RTK_Everywhere/menuPorts.ino
index 598e14295..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",
@@ -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");
@@ -96,8 +97,7 @@ void menuPortsNoMux()
if (gnss->baudIsAllowed(newBaud))
{
settings.radioPortBaud = newBaud;
- if (online.gnss == true)
- gnss->setRadioBaudRate(newBaud);
+ gnssConfigure(GNSS_CONFIG_BAUD_RATE_RADIO); // Request receiver to use new settings
}
else
{
@@ -114,8 +114,7 @@ void menuPortsNoMux()
if (gnss->baudIsAllowed(newBaud))
{
settings.dataPortBaud = newBaud;
- if (online.gnss == true)
- gnss->setDataBaudRate(newBaud);
+ gnssConfigure(GNSS_CONFIG_BAUD_RATE_DATA); // Request receiver to use new settings
}
else
{
@@ -133,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))
{
@@ -154,18 +153,6 @@ 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;
- }
-#endif // COMPILE_LG290P
-
clearBuffer(); // Empty buffer of any newline chars
}
@@ -178,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: ");
@@ -194,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)
@@ -218,7 +205,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");
@@ -234,8 +222,7 @@ void menuPortsMultiplexed()
if (gnss->baudIsAllowed(newBaud))
{
settings.radioPortBaud = newBaud;
- if (online.gnss == true)
- gnss->setRadioBaudRate(newBaud);
+ gnssConfigure(GNSS_CONFIG_BAUD_RATE_RADIO); // Request receiver to use new settings
}
else
{
@@ -260,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)
@@ -271,8 +261,7 @@ void menuPortsMultiplexed()
if (gnss->baudIsAllowed(newBaud))
{
settings.dataPortBaud = newBaud;
- if (online.gnss == true)
- gnss->setDataBaudRate(newBaud);
+ gnssConfigure(GNSS_CONFIG_BAUD_RATE_DATA); // Request receiver to use new settings
}
else
{
@@ -288,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))
{
@@ -315,27 +304,13 @@ 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;
- }
-#endif // COMPILE_MOSAICX5
-
- gnss->beginExternalEvent(); // Update with new settings
- gnss->beginPPS();
+ gnss->beginExternalEvent(); // Update with 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/menuSystem.ino b/Firmware/RTK_Everywhere/menuSystem.ino
index 6b686890c..1b78af4b3 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");
@@ -568,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.");
@@ -643,6 +646,11 @@ void menuDebugHardware()
}
}
+ else if (incoming == 21)
+ {
+ settings.debugGnssConfig ^= 1;
+ }
+
else if (incoming == 'e')
{
systemPrintln("Erasing LittleFS and resetting");
@@ -993,10 +1001,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 +1099,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,
diff --git a/Firmware/RTK_Everywhere/settings.h b/Firmware/RTK_Everywhere/settings.h
index b99209dac..d69450b55 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;
@@ -848,16 +850,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).
-
- // 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().
@@ -1037,7 +1029,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
@@ -1049,7 +1041,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;
@@ -1221,6 +1213,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
@@ -1310,10 +1304,10 @@ typedef enum
HAS = L29, // Platforms which support Galileo HAS
} Facet_Flex_Variant;
-typedef bool (* AFTER_CMD)(int cmdIndex);
+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
{
@@ -1554,12 +1548,9 @@ 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, },
- { 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, },
@@ -1769,7 +1760,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)
@@ -1890,13 +1881,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, },
@@ -1910,10 +1901,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, },
@@ -1960,7 +1951,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
@@ -2092,7 +2083,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
diff --git a/Firmware/RTK_Everywhere/support.ino b/Firmware/RTK_Everywhere/support.ino
index 5240641bb..0a9c2f07f 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");
}
@@ -915,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);
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();
-}