diff --git a/Firmware/RTK_Surveyor/NVM.ino b/Firmware/RTK_Surveyor/NVM.ino index 74c7bd612..8fe015623 100644 --- a/Firmware/RTK_Surveyor/NVM.ino +++ b/Firmware/RTK_Surveyor/NVM.ino @@ -430,6 +430,10 @@ void recordSystemSettingsToFile(File *settingsFile) settingsFile->printf("%s=%d\r\n", "gnssUartInterruptsCore", settings.gnssUartInterruptsCore); settingsFile->printf("%s=%d\r\n", "bluetoothInterruptsCore", settings.bluetoothInterruptsCore); settingsFile->printf("%s=%d\r\n", "i2cInterruptsCore", settings.i2cInterruptsCore); + settingsFile->printf("%s=%d\r\n", "rtcmTimeoutBeforeUsingLBand_s", settings.rtcmTimeoutBeforeUsingLBand_s); + + //Add new settings above + //<------------------------------------------------------------> } // Given a fileName, parse the file and load the given settings struct @@ -1328,6 +1332,11 @@ bool parseLine(char *str, Settings *settings) settings->enableNetworkFailover = d; else if (strcmp(settingName, "printNetworkStatus") == 0) settings->printNetworkStatus = d; + else if (strcmp(settingName, "rtcmTimeoutBeforeUsingLBand_s") == 0) + settings->rtcmTimeoutBeforeUsingLBand_s = d; + + //Add new settings above + //<------------------------------------------------------------> // Check for bulk settings (WiFi credentials, constellations, message rates, ESPNOW Peers) // Must be last on else list diff --git a/Firmware/RTK_Surveyor/NtripClient.ino b/Firmware/RTK_Surveyor/NtripClient.ino index f6ad1549e..d6a20c149 100644 --- a/Firmware/RTK_Surveyor/NtripClient.ino +++ b/Firmware/RTK_Surveyor/NtripClient.ino @@ -840,6 +840,9 @@ void ntripClientUpdate() // Restart the NTRIP receive data timer ntripClientTimer = millis(); + // Record the arrival of RTCM from the WiFi connection. This resets the RTCM timeout used on the L-Band. + rtcmLastPacketReceived = millis(); + // Push RTCM to GNSS module over I2C / SPI theGNSS.pushRawData(rtcmData, rtcmCount); netIncomingRTCM = true; diff --git a/Firmware/RTK_Surveyor/RTK_Surveyor.ino b/Firmware/RTK_Surveyor/RTK_Surveyor.ino index d59c0beb2..cd73c3608 100644 --- a/Firmware/RTK_Surveyor/RTK_Surveyor.ino +++ b/Firmware/RTK_Surveyor/RTK_Surveyor.ino @@ -316,6 +316,12 @@ class SFE_UBLOX_GNSS_SUPER_DERIVED : public SFE_UBLOX_GNSS_SUPER SFE_UBLOX_GNSS_SUPER_DERIVED theGNSS; +#ifdef COMPILE_L_BAND +static SFE_UBLOX_GNSS_SUPER i2cLBand; // NEO-D9S + +void checkRXMCOR(UBX_RXM_COR_data_t *ubxDataStruct); +#endif + volatile struct timeval gnssSyncTv; // This holds the time the RTC was sync'd to GNSS time via Time Pulse interrupt - used by NTP struct timeval previousGnssSyncTv; // This holds the time of the previous RTC sync @@ -360,6 +366,8 @@ int64_t ARPECEFZ = 0; uint16_t ARPECEFH = 0; const byte haeNumberOfDecimals = 8; // Used for printing and transmitting lat/lon +bool lBandCommunicationEnabled = false; +unsigned long rtcmLastPacketReceived = 0; //Monitors the last time we received RTCM. Proctors PMP vs RTCM prioritization. //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // Battery fuel gauge and PWM LEDs diff --git a/Firmware/RTK_Surveyor/Tasks.ino b/Firmware/RTK_Surveyor/Tasks.ino index ab41a518d..9f87b9a91 100644 --- a/Firmware/RTK_Surveyor/Tasks.ino +++ b/Firmware/RTK_Surveyor/Tasks.ino @@ -180,6 +180,11 @@ void btReadTask(void *e) btEscapeCharsReceived = 0; // Update timeout check for escape char and partial frame bluetoothIncomingRTCM = true; + + // Record the arrival of RTCM from the Bluetooth connection (a phone or tablet is providing the RTCM + // via NTRIP). This resets the RTCM timeout used on the L-Band. + rtcmLastPacketReceived = millis(); + } // End just a character in the stream } // End btPrintEcho == false && bluetoothRxDataAvailable() diff --git a/Firmware/RTK_Surveyor/ZED.ino b/Firmware/RTK_Surveyor/ZED.ino new file mode 100644 index 000000000..e2e2ae25a --- /dev/null +++ b/Firmware/RTK_Surveyor/ZED.ino @@ -0,0 +1,109 @@ +// Enable data output from the NEO +bool zedEnableLBandCommunication() +{ + bool response = true; + +#ifdef COMPILE_L_BAND + + response &= theGNSS.setRXMCORcallbackPtr(&checkRXMCOR); // Enable callback to check if the PMP data is being decrypted successfully + + if (productVariant == RTK_FACET_LBAND_DIRECT) + { + // Setup for ZED to NEO serial communication + response &= theGNSS.setVal32(UBLOX_CFG_UART2INPROT_UBX, true); // Configure ZED for UBX input on UART2 + + // Disable PMP callback over I2C. Enable UARTs. + response &= i2cLBand.setRXMPMPmessageCallbackPtr(nullptr); // Disable PMP callback to push raw PMP over I2C + + response &= i2cLBand.newCfgValset(); + response &= i2cLBand.addCfgValset(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_I2C, 0); // Disable UBX-RXM-PMP on NEO's I2C port + + response &= i2cLBand.addCfgValset(UBLOX_CFG_UART2OUTPROT_UBX, 1); // Enable UBX output on NEO's UART2 + response &= i2cLBand.addCfgValset(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_UART2, 1); // Output UBX-RXM-PMP on NEO's UART2 + response &= i2cLBand.addCfgValset(UBLOX_CFG_UART2_BAUDRATE, settings.radioPortBaud); // Match baudrate with ZED + } + else if (productVariant == RTK_FACET_LBAND) + { + // Older versions of the Facet L-Band had solder jumpers that could be closed to directly connect the NEO + // to the ZED. If the user has explicitly disabled I2C corrections, enable a UART connection. + if (settings.useI2cForLbandCorrections == true) + { + response &= theGNSS.setVal32(UBLOX_CFG_UART2INPROT_UBX, settings.enableUART2UBXIn); + + i2cLBand.setRXMPMPmessageCallbackPtr(&pushRXMPMP); // Enable PMP callback to push raw PMP over I2C + + response &= i2cLBand.newCfgValset(); + response &= i2cLBand.addCfgValset(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_I2C, 1); // Enable UBX-RXM-PMP on NEO's I2C port + + response &= i2cLBand.addCfgValset(UBLOX_CFG_UART2OUTPROT_UBX, 0); // Disable UBX output on NEO's UART2 + response &= i2cLBand.addCfgValset(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_UART2, 0); // Disable UBX-RXM-PMP on NEO's UART2 + } + else // Setup ZED to NEO serial communication + { + response &= theGNSS.setVal32(UBLOX_CFG_UART2INPROT_UBX, true); // Configure ZED for UBX input on UART2 + + i2cLBand.setRXMPMPmessageCallbackPtr(nullptr); // Disable PMP callback to push raw PMP over I2C + + response &= i2cLBand.newCfgValset(); + response &= i2cLBand.addCfgValset(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_I2C, 0); // Disable UBX-RXM-PMP on NEO's I2C port + + response &= i2cLBand.addCfgValset(UBLOX_CFG_UART2OUTPROT_UBX, 1); // Enable UBX output on UART2 + response &= i2cLBand.addCfgValset(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_UART2, 1); // Output UBX-RXM-PMP on UART2 + response &= + i2cLBand.addCfgValset(UBLOX_CFG_UART2_BAUDRATE, settings.radioPortBaud); // Match baudrate with ZED + } + } + else + { + systemPrintln("zedEnableLBandCorrections: Unknown platform"); + return (false); + } + + response &= i2cLBand.sendCfgValset(); + +#endif + + return (response); +} + +// Disable data output from the NEO +bool zedDisableLBandCommunication() +{ + bool response = true; + +#ifdef COMPILE_L_BAND + response &= i2cLBand.setRXMPMPmessageCallbackPtr(nullptr); // Disable PMP callback no matter the platform + response &= theGNSS.setRXMCORcallbackPtr(nullptr); // Disable callback to check if the PMP data is being decrypted successfully + + if (productVariant == RTK_FACET_LBAND_DIRECT) + { + response &= i2cLBand.newCfgValset(); + response &= i2cLBand.addCfgValset(UBLOX_CFG_UART2OUTPROT_UBX, 0); // Disable UBX output from NEO's UART2 + } + else if (productVariant == RTK_FACET_LBAND) + { + // Older versions of the Facet L-Band had solder jumpers that could be closed to directly connect the NEO + // to the ZED. Check if the user has explicitly set I2C corrections. + if (settings.useI2cForLbandCorrections == true) + { + response &= i2cLBand.newCfgValset(); + response &= i2cLBand.addCfgValset(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_I2C, 0); // Disable UBX-RXM-PMP from NEO's I2C port + } + else // Setup ZED to NEO serial communication + { + response &= i2cLBand.newCfgValset(); + response &= i2cLBand.addCfgValset(UBLOX_CFG_UART2OUTPROT_UBX, 0); // Disable UBX output from NEO's UART2 + } + } + else + { + systemPrintln("zedEnableLBandCorrections: Unknown platform"); + return (false); + } + + response &= i2cLBand.sendCfgValset(); + +#endif + + return (response); +} \ No newline at end of file diff --git a/Firmware/RTK_Surveyor/menuPP.ino b/Firmware/RTK_Surveyor/menuPP.ino index f6666d48b..cc5bde3c4 100644 --- a/Firmware/RTK_Surveyor/menuPP.ino +++ b/Firmware/RTK_Surveyor/menuPP.ino @@ -8,8 +8,6 @@ #define MQTT_CERT_SIZE 2000 -static SFE_UBLOX_GNSS_SUPER i2cLBand; // NEO-D9S - // The PointPerfect token is provided at compile time via build flags #ifndef POINTPERFECT_TOKEN #define POINTPERFECT_TOKEN \ @@ -1031,38 +1029,9 @@ void beginLBand() response &= i2cLBand.addCfgValset(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_UART1, 0); // Diasable UBX-RXM-PMP on UART1. Not used. - // Determine if we should use callback to harvest/sent encrypted messages over I2C - // If not, it is assumed the ZED UART2 is directly connected to NEO UART2 - if (settings.useI2cForLbandCorrections == true) - { - // Enable PMP over I2C. Disable UARTs - response &= theGNSS.setVal32(UBLOX_CFG_UART2INPROT_UBX, settings.enableUART2UBXIn); - - i2cLBand.setRXMPMPmessageCallbackPtr(&pushRXMPMP); // Enable PMP callback - - response &= - i2cLBand.addCfgValset(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_I2C, 1); // Ensure UBX-RXM-PMP is enabled on I2C port - - response &= i2cLBand.addCfgValset(UBLOX_CFG_UART2OUTPROT_UBX, 0); // Disable UBX output on UART2 - response &= i2cLBand.addCfgValset(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_UART2, 0); // Disable UBX-RXM-PMP on UART2 - response &= i2cLBand.addCfgValset(UBLOX_CFG_UART2_BAUDRATE, settings.radioPortBaud); // match baudrate with ZED - } - else // Setup for ZED to NEO serial communication - { - response &= theGNSS.setVal32(UBLOX_CFG_UART2INPROT_UBX, true); // Configure ZED for UBX input on UART2 - - // Disable PMP callback over I2C. Enable UARTs. - i2cLBand.setRXMPMPmessageCallbackPtr(nullptr); // Enable PMP callback - response &= i2cLBand.addCfgValset(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_I2C, 0); // Disable UBX-RXM-PMP on I2C port - - response &= i2cLBand.addCfgValset(UBLOX_CFG_UART2OUTPROT_UBX, 1); // Enable UBX output on UART2 - response &= i2cLBand.addCfgValset(UBLOX_CFG_MSGOUT_UBX_RXM_PMP_UART2, 1); // Output UBX-RXM-PMP on UART2 - response &= i2cLBand.addCfgValset(UBLOX_CFG_UART2_BAUDRATE, settings.radioPortBaud); // match baudrate with ZED - } - response &= i2cLBand.sendCfgValset(); - theGNSS.setRXMCORcallbackPtr(&checkRXMCOR); // Callback to check if the PMP data is being decrypted successfully + lBandCommunicationEnabled = zedEnableLBandCommunication(); if (response == false) systemPrintln("L-Band failed to configure"); @@ -1277,6 +1246,28 @@ void updateLBand() lbandTimeToFix = millis(); log_d("Time to first L-Band fix: %ds", lbandTimeToFix / 1000); } + + if ((millis() - rtcmLastPacketReceived) / 1000 > settings.rtcmTimeoutBeforeUsingLBand_s) + { + // If we have not received RTCM in a certain amount of time, + // and if communication was disabled because RTCM was being received at some point, + // re-enableL-Band communcation + if (lBandCommunicationEnabled == false) + { + log_d("Enabling L-Band communication due to RTCM timeout"); + lBandCommunicationEnabled = zedEnableLBandCommunication(); + } + } + else + { + // If we *have* recently received RTCM then disable corrections from then NEO-D9S L-Band receiver + if (lBandCommunicationEnabled == true) + { + log_d("Disabling L-Band communication due to RTCM reception"); + lBandCommunicationEnabled = !zedDisableLBandCommunication(); //zedDisableLBandCommunication() returns true if we successfully disabled + } + } } + #endif // COMPILE_L_BAND } diff --git a/Firmware/RTK_Surveyor/menuSystem.ino b/Firmware/RTK_Surveyor/menuSystem.ino index 83d655247..7063f4090 100644 --- a/Firmware/RTK_Surveyor/menuSystem.ino +++ b/Firmware/RTK_Surveyor/menuSystem.ino @@ -778,6 +778,8 @@ void menuOperation() systemPrint("11) Use I2C for L-Band Corrections: "); systemPrintf("%s\r\n", settings.useI2cForLbandCorrections ? "Enabled" : "Disabled"); + systemPrintf("12) RTCM timeout before L-Band override (seconds): %d\r\n", settings.rtcmTimeoutBeforeUsingLBand_s); + systemPrintln("---- Interrupts ----"); systemPrint("30) Bluetooth Interrupts Core: "); systemPrintln(settings.bluetoothInterruptsCore); @@ -948,6 +950,18 @@ void menuOperation() settings.useI2cForLbandCorrectionsConfigured = true; //Record that the user has manually modified the settings. settings.useI2cForLbandCorrections ^= 1; } + else if (incoming == 12) + { + systemPrint("Enter the number of seconds before L-Band is used once RTCM is absent (1 to 255): "); + int rtcmTimeoutBeforeUsingLBand_s = getNumber(); // Returns EXIT, TIMEOUT, or long + if ((rtcmTimeoutBeforeUsingLBand_s != INPUT_RESPONSE_GETNUMBER_EXIT) && (rtcmTimeoutBeforeUsingLBand_s != INPUT_RESPONSE_GETNUMBER_TIMEOUT)) + { + if (rtcmTimeoutBeforeUsingLBand_s < 1 || rtcmTimeoutBeforeUsingLBand_s > 255) + systemPrintln("Error: RTCM timeout out of range"); + else + settings.rtcmTimeoutBeforeUsingLBand_s = rtcmTimeoutBeforeUsingLBand_s; // Recorded to NVM and file + } + } else if (incoming == 30) { diff --git a/Firmware/RTK_Surveyor/settings.h b/Firmware/RTK_Surveyor/settings.h index 5ef87a36d..f658771eb 100644 --- a/Firmware/RTK_Surveyor/settings.h +++ b/Firmware/RTK_Surveyor/settings.h @@ -1060,6 +1060,12 @@ typedef struct bool debugPvtServer = false; bool enablePvtServer = false; uint16_t pvtServerPort = 2948; // PVT server port, 2948 is GPS Daemon: http://tcp-udp-ports.com/port-2948.htm + + uint8_t rtcmTimeoutBeforeUsingLBand_s = 10; //If 10s have passed without RTCM, enable PMP corrections over L-Band if available + + //Add new settings above + //<------------------------------------------------------------> + } Settings; Settings settings;