diff --git a/Firmware/RTK_Surveyor/Developer.ino b/Firmware/RTK_Surveyor/Developer.ino index 9098cf439..7c8c75297 100644 --- a/Firmware/RTK_Surveyor/Developer.ino +++ b/Firmware/RTK_Surveyor/Developer.ino @@ -30,6 +30,7 @@ void ethernetWebServerStopESP32W5500() {} void menuNTP() {systemPrint("NOT compiled");} void ntpServerBegin() {} void ntpServerUpdate() {} +void ntpValidateTables() {} #endif // COMPILE_ETHERNET diff --git a/Firmware/RTK_Surveyor/NTP.ino b/Firmware/RTK_Surveyor/NTP.ino index 59b04ce51..f851d2ce0 100644 --- a/Firmware/RTK_Surveyor/NTP.ino +++ b/Firmware/RTK_Surveyor/NTP.ino @@ -52,11 +52,35 @@ NTP.ino #ifdef COMPILE_ETHERNET +//---------------------------------------- +// Constants +//---------------------------------------- + +enum NTP_STATE +{ + NTP_STATE_OFF, + NTP_STATE_NETWORK_STARTING, + NTP_STATE_NETWORK_CONNECTED, + NTP_STATE_SERVER_RUNNING, + // Insert new states here + NTP_STATE_MAX +}; + +const char * const ntpServerStateName[] = +{ + "NTP_STATE_OFF", + "NTP_STATE_NETWORK_STARTING", + "NTP_STATE_NETWORK_CONNECTED", + "NTP_STATE_SERVER_RUNNING" +}; +const int ntpServerStateNameEntries = sizeof(ntpServerStateName) / sizeof(ntpServerStateName[0]); + //---------------------------------------- // Locals //---------------------------------------- static derivedEthernetUDP *ntpServer; // This will be instantiated when we know the NTP port +static uint8_t ntpServerState; static volatile uint8_t ntpSockIndex; // The W5500 socket index for NTP - so we can enable and read the correct interrupt static uint32_t lastLoggedNTPRequest; @@ -738,36 +762,64 @@ bool configureUbloxModuleNTP() // NTP Server routines //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -// Start the NTP server -void ntpServerBegin() +// Stop the NTP server +void ntpServerEnd() { - // Skip if not in NTPSERVER mode - if (systemState < STATE_NTPSERVER_NOT_STARTED || systemState > STATE_NTPSERVER_SYNC) - return; +} - if ((online.ethernetStatus == ETH_CONNECTED) && (online.NTPServer == false)) - { - if (ntpServer == nullptr) - ntpServer = new derivedEthernetUDP; - ntpServer->begin(settings.ethernetNtpPort); - ntpSockIndex = ntpServer->getSockIndex(); // Get the socket index - w5500ClearSocketInterrupts(); // Clear all interrupts - w5500EnableSocketInterrupt(ntpSockIndex); // Enable the RECV interrupt for the desired socket index - online.NTPServer = true; - } +// Determine if the NTP server is enabled +bool ntpServerIsEnabled() +{ + return (systemState >= STATE_NTPSERVER_NOT_STARTED) && (systemState <= STATE_NTPSERVER_SYNC); } -// Stop the NTP server -void ntpServerEnd() +// Update the state of the NTP server state machine +void ntpServerSetState(uint8_t newState) { + if ((settings.debugNtp || PERIODIC_DISPLAY(PD_NTP_SERVER_STATE)) && (!inMainMenu)) + { + if (ntpServerState == newState) + systemPrint("*"); + else + systemPrintf("%s --> ", ntpServerStateName[ntpServerState]); + } + ntpServerState = newState; + if (settings.debugNtp || PERIODIC_DISPLAY(PD_NTP_SERVER_STATE)) + { + PERIODIC_CLEAR(PD_NTP_SERVER_STATE); + if (newState >= NTP_STATE_MAX) + { + systemPrintf("Unknown NTP Server state: %d\r\n", newState); + reportFatalError("Unknown NTP Server state"); + } + else if (!inMainMenu) + systemPrintln(ntpServerStateName[ntpServerState]); + } } // Stop the NTP server void ntpServerStop() { + // Mark the NTP server as off + online.NTPServer = false; + + // Release the NTP server memory if (ntpServer) + { + w5500DisableSocketInterrupt(ntpSockIndex); // Disable the receive interrupt ntpServer->stop(); - online.NTPServer = false; + delete ntpServer; + ntpServer = nullptr; + if (!inMainMenu) + reportHeapNow(settings.debugNtp); + } + + // Release the network resources + if (networkGetUserNetwork(NETWORK_USER_NTP_SERVER)) + networkUserClose(NETWORK_USER_NTP_SERVER); + + // Stop the NTP server + ntpServerSetState(NTP_STATE_OFF); } // Update the NTP server state @@ -778,118 +830,193 @@ void ntpServerUpdate() if (!HAS_ETHERNET) return; - if (online.NTPServer == false) - ntpServerBegin(); - - if (online.NTPServer == false) - return; + // Process the NTP state + switch (ntpServerState) + { + default: + break; - if (w5500CheckSocketInterrupt(ntpSockIndex)) - w5500ClearSocketInterrupt(ntpSockIndex); // Clear the socket interrupt here + case NTP_STATE_OFF: + // Determine if the NTP server is enabled + if (ntpServerIsEnabled()) + { + // Start the network + if (networkUserOpen(NETWORK_USER_NTP_SERVER, NETWORK_TYPE_ETHERNET)) + ntpServerSetState(NTP_STATE_NETWORK_STARTING); + } + break; + + // Wait for the network conection + case NTP_STATE_NETWORK_STARTING: + // Determine if the network has failed + if (networkIsShuttingDown(NETWORK_USER_NTP_SERVER) || (!ntpServerIsEnabled())) + // Stop the NTP server, restart it if possible + ntpServerStop(); + + // Determine if the network is connected + else if (networkUserConnected(NETWORK_USER_NTP_SERVER)) + ntpServerSetState(NTP_STATE_NETWORK_CONNECTED); + break; + + case NTP_STATE_NETWORK_CONNECTED: + // Determine if the network has failed + if (networkIsShuttingDown(NETWORK_USER_NTP_SERVER) || (!ntpServerIsEnabled())) + // Stop the NTP server, restart it if possible + ntpServerStop(); + + // Attempt to start the NTP server + else + { + ntpServer = new derivedEthernetUDP; + if (!ntpServer) + // Insufficient memory to start the NTP server + ntpServerStop(); + else + { + // Start the NTP server + ntpServer->begin(settings.ethernetNtpPort); + ntpSockIndex = ntpServer->getSockIndex(); // Get the socket index + w5500ClearSocketInterrupts(); // Clear all interrupts + w5500EnableSocketInterrupt(ntpSockIndex); // Enable the RECV interrupt for the desired socket index + online.NTPServer = true; + if (!inMainMenu) + reportHeapNow(settings.debugNtp); + ntpServerSetState(NTP_STATE_SERVER_RUNNING); + } + } + break; - // Check for new NTP requests - if the time has been sync'd - bool processed = ntpProcessOneRequest(systemState == STATE_NTPSERVER_SYNC, (const timeval *)ðernetNtpTv, - (const timeval *)&gnssSyncTv, ntpDiag, sizeof(ntpDiag)); - if (processed) - { - // Print the diagnostics - if enabled - if (settings.enablePrintNTPDiag && (!inMainMenu)) - systemPrint(ntpDiag); + case NTP_STATE_SERVER_RUNNING: + // Determine if the network has failed + if (networkIsShuttingDown(NETWORK_USER_NTP_SERVER) || (!ntpServerIsEnabled())) + // Stop the NTP server, restart it if possible + ntpServerStop(); - // Log the NTP request to file - if enabled - if (settings.enableNTPFile) + else { - // Gain access to the SPI controller for the microSD card - if (xSemaphoreTake(sdCardSemaphore, fatSemaphore_longWait_ms) == pdPASS) + if (w5500CheckSocketInterrupt(ntpSockIndex)) + w5500ClearSocketInterrupt(ntpSockIndex); // Clear the socket interrupt here + + // Check for new NTP requests - if the time has been sync'd + bool processed = ntpProcessOneRequest(systemState == STATE_NTPSERVER_SYNC, (const timeval *)ðernetNtpTv, + (const timeval *)&gnssSyncTv, ntpDiag, sizeof(ntpDiag)); + if (processed) { - markSemaphore(FUNCTION_NTPEVENT); - - // Get the marks file name - char fileName[32]; - bool fileOpen = false; - bool sdCardWasOnline; - int year; - int month; - int day; - - // Get the date - year = rtc.getYear(); - month = rtc.getMonth() + 1; - day = rtc.getDay(); - - // Build the file name - snprintf(fileName, sizeof(fileName), "/NTP_Requests_%04d_%02d_%02d.txt", year, month, day); - - // Try to gain access the SD card - sdCardWasOnline = online.microSD; - if (online.microSD != true) - beginSD(); - - if (online.microSD == true) + // Print the diagnostics - if enabled + if ((settings.debugNtp || PERIODIC_DISPLAY(PD_NTP_SERVER_DATA)) && (!inMainMenu)) { - // Check if the NTP file already exists - bool ntpFileExists = false; - if (USE_SPI_MICROSD) - { - ntpFileExists = sd->exists(fileName); - } -#ifdef COMPILE_SD_MMC - else - { - ntpFileExists = SD_MMC.exists(fileName); - } -#endif // COMPILE_SD_MMC - - // Open the NTP file - FileSdFatMMC ntpFile; + PERIODIC_CLEAR(PD_NTP_SERVER_DATA); + systemPrint(ntpDiag); + } - if (ntpFileExists) - { - if (ntpFile && ntpFile.open(fileName, O_APPEND | O_WRITE)) - { - fileOpen = true; - ntpFile.updateFileCreateTimestamp(); - } - } - else + // Log the NTP request to file - if enabled + if (settings.enableNTPFile) + { + // Gain access to the SPI controller for the microSD card + if (xSemaphoreTake(sdCardSemaphore, fatSemaphore_longWait_ms) == pdPASS) { - if (ntpFile && ntpFile.open(fileName, O_CREAT | O_WRITE)) + markSemaphore(FUNCTION_NTPEVENT); + + // Get the marks file name + char fileName[32]; + bool fileOpen = false; + bool sdCardWasOnline; + int year; + int month; + int day; + + // Get the date + year = rtc.getYear(); + month = rtc.getMonth() + 1; + day = rtc.getDay(); + + // Build the file name + snprintf(fileName, sizeof(fileName), "/NTP_Requests_%04d_%02d_%02d.txt", year, month, day); + + // Try to gain access the SD card + sdCardWasOnline = online.microSD; + if (online.microSD != true) + beginSD(); + + if (online.microSD == true) { - fileOpen = true; - ntpFile.updateFileAccessTimestamp(); - - // If you want to add a file header, do it here + // Check if the NTP file already exists + bool ntpFileExists = false; + if (USE_SPI_MICROSD) + { + ntpFileExists = sd->exists(fileName); + } + #ifdef COMPILE_SD_MMC + else + { + ntpFileExists = SD_MMC.exists(fileName); + } + #endif // COMPILE_SD_MMC + + // Open the NTP file + FileSdFatMMC ntpFile; + + if (ntpFileExists) + { + if (ntpFile && ntpFile.open(fileName, O_APPEND | O_WRITE)) + { + fileOpen = true; + ntpFile.updateFileCreateTimestamp(); + } + } + else + { + if (ntpFile && ntpFile.open(fileName, O_CREAT | O_WRITE)) + { + fileOpen = true; + ntpFile.updateFileAccessTimestamp(); + + // If you want to add a file header, do it here + } + } + + if (fileOpen) + { + // Write the NTP request to the file + ntpFile.write((const uint8_t *)ntpDiag, strlen(ntpDiag)); + + // Update the file to create time & date + ntpFile.updateFileCreateTimestamp(); + + // Close the mark file + ntpFile.close(); + } + + // Dismount the SD card + if (!sdCardWasOnline) + endSD(true, false); } - } - if (fileOpen) - { - // Write the NTP request to the file - ntpFile.write((const uint8_t *)ntpDiag, strlen(ntpDiag)); - - // Update the file to create time & date - ntpFile.updateFileCreateTimestamp(); + // Done with the SPI controller + xSemaphoreGive(sdCardSemaphore); - // Close the mark file - ntpFile.close(); - } - - // Dismount the SD card - if (!sdCardWasOnline) - endSD(true, false); + lastLoggedNTPRequest = millis(); + ntpLogIncreasing = true; + } // End sdCardSemaphore } + } - // Done with the SPI controller - xSemaphoreGive(sdCardSemaphore); - - lastLoggedNTPRequest = millis(); - ntpLogIncreasing = true; - } // End sdCardSemaphore + if (millis() > (lastLoggedNTPRequest + 5000)) + ntpLogIncreasing = false; } + break; } - if (millis() > (lastLoggedNTPRequest + 5000)) - ntpLogIncreasing = false; + // Periodically display the NTP server state + if (PERIODIC_DISPLAY(PD_NTP_SERVER_STATE)) + ntpServerSetState(ntpServerState); +} + +// Verify the NTP tables +void ntpValidateTables() +{ + if (ntpServerStateNameEntries != NTP_STATE_MAX) + reportFatalError("Fix ntpServerStateNameEntries to match NTP_STATE"); } #endif // COMPILE_ETHERNET diff --git a/Firmware/RTK_Surveyor/NVM.ino b/Firmware/RTK_Surveyor/NVM.ino index 695d0a010..ffec31624 100644 --- a/Firmware/RTK_Surveyor/NVM.ino +++ b/Firmware/RTK_Surveyor/NVM.ino @@ -299,7 +299,7 @@ void recordSystemSettingsToFile(File *settingsFile) settingsFile->printf("%s=%d\r\n", "enablePrintStates", settings.enablePrintStates); settingsFile->printf("%s=%d\r\n", "enablePrintDuplicateStates", settings.enablePrintDuplicateStates); settingsFile->printf("%s=%d\r\n", "enablePrintRtcSync", settings.enablePrintRtcSync); - settingsFile->printf("%s=%d\r\n", "enablePrintNTPDiag", settings.enablePrintNTPDiag); + settingsFile->printf("%s=%d\r\n", "debugNtp", settings.debugNtp); settingsFile->printf("%s=%d\r\n", "enablePrintEthernetDiag", settings.enablePrintEthernetDiag); settingsFile->printf("%s=%d\r\n", "radioType", settings.radioType); @@ -1103,8 +1103,8 @@ bool parseLine(char *str, Settings *settings) settings->enablePrintDuplicateStates = d; else if (strcmp(settingName, "enablePrintRtcSync") == 0) settings->enablePrintRtcSync = d; - else if (strcmp(settingName, "enablePrintNTPDiag") == 0) - settings->enablePrintNTPDiag = d; + else if (strcmp(settingName, "debugNtp") == 0) + settings->debugNtp = d; else if (strcmp(settingName, "enablePrintEthernetDiag") == 0) settings->enablePrintEthernetDiag = d; else if (strcmp(settingName, "radioType") == 0) diff --git a/Firmware/RTK_Surveyor/Network.ino b/Firmware/RTK_Surveyor/Network.ino index 15ae9a444..94a6f6679 100644 --- a/Firmware/RTK_Surveyor/Network.ino +++ b/Firmware/RTK_Surveyor/Network.ino @@ -184,6 +184,7 @@ const char * const networkUser[] = "NTRIP Client", "NTRIP Server", "PVT Client", + "NTP Server", }; const int networkUserEntries = sizeof(networkUser) / sizeof(networkUser[0]); @@ -523,14 +524,21 @@ void networkInitialize(NETWORK_DATA * network) //---------------------------------------- bool networkIsConnected(NETWORK_DATA * network) { - bool isConnected; - // Determine the network is connected - if (network->state == NETWORK_STATE_IN_USE) + if (network && (network->state == NETWORK_STATE_IN_USE)) return networkIsMediaConnected(network); return false; } +//---------------------------------------- +// Determine if the network is connected to the media +//---------------------------------------- +bool networkIsTypeConnected(uint8_t networkType) +{ + // Determine the network is connected + return networkIsConnected(networkGet(networkType, false)); +} + //---------------------------------------- // Determine if the network is connected to the media //---------------------------------------- diff --git a/Firmware/RTK_Surveyor/RTK_Surveyor.ino b/Firmware/RTK_Surveyor/RTK_Surveyor.ino index e8be1352a..d2e2398d1 100644 --- a/Firmware/RTK_Surveyor/RTK_Surveyor.ino +++ b/Firmware/RTK_Surveyor/RTK_Surveyor.ino @@ -797,8 +797,6 @@ void setup() ethernetBegin(); // Start-up the Ethernet connection - ntpServerBegin(); // Start the NTP server - beginAccelerometer(); beginLBand(); // Begin L-Band diff --git a/Firmware/RTK_Surveyor/States.ino b/Firmware/RTK_Surveyor/States.ino index 965c6136b..1b8119e46 100644 --- a/Firmware/RTK_Surveyor/States.ino +++ b/Firmware/RTK_Surveyor/States.ino @@ -997,17 +997,23 @@ void updateSystemState() if (online.NTPServer) { + if (settings.debugNtp) + systemPrintln("NTP Server started"); displayNtpStarted(500); // Show 'NTP Started' changeState(STATE_NTPSERVER_NO_SYNC); } else { + if (settings.debugNtp) + systemPrintln("NTP Server waiting for Ethernet"); displayNtpNotReady(1000); // Show 'Ethernet Not Ready' changeState(STATE_NTPSERVER_NO_SYNC); } } else { + if (settings.debugNtp) + systemPrintln("NTP Server ZED configuration failed"); displayNTPFail(1000); // Show 'NTP Failed' // Do we stay in STATE_NTPSERVER_NOT_STARTED? Or should we reset? } @@ -1017,6 +1023,8 @@ void updateSystemState() case (STATE_NTPSERVER_NO_SYNC): { if (rtcSyncd) { + if (settings.debugNtp) + systemPrintln("NTP Server RTC synchronized"); changeState(STATE_NTPSERVER_SYNC); } } diff --git a/Firmware/RTK_Surveyor/W5500.ino b/Firmware/RTK_Surveyor/W5500.ino index d4cb7ccd1..09fe09e24 100644 --- a/Firmware/RTK_Surveyor/W5500.ino +++ b/Firmware/RTK_Surveyor/W5500.ino @@ -146,4 +146,16 @@ void w5500EnableSocketInterrupt(uint8_t sockIndex) w5500write(SPI, pin_Ethernet_CS, w5500SIMR, w5500CommonRegister, &SIMR, 1); // Enable the socket interrupt } +void w5500DisableSocketInterrupt(uint8_t sockIndex) +{ + w5500write(SPI, pin_Ethernet_CS, w5500SnIMR, w5500SocketRegisters[sockIndex], (uint8_t *)&w5500SnIMR_RECV, + 1); // Enable the RECV interrupt for sockIndex only + + // Read-Modify-Write + uint8_t SIMR; + w5500read(SPI, pin_Ethernet_CS, w5500SIMR, w5500CommonRegister, &SIMR, 1); + SIMR &= ~(1 << sockIndex); + w5500write(SPI, pin_Ethernet_CS, w5500SIMR, w5500CommonRegister, &SIMR, 1); // Disable the socket interrupt +} + #endif // COMPILE_ETHERNET diff --git a/Firmware/RTK_Surveyor/menuSystem.ino b/Firmware/RTK_Surveyor/menuSystem.ino index 38f35bb1f..1ad6a9093 100644 --- a/Firmware/RTK_Surveyor/menuSystem.ino +++ b/Firmware/RTK_Surveyor/menuSystem.ino @@ -422,8 +422,8 @@ void menuDebug() systemPrint("37) Print RTC resyncs: "); systemPrintf("%s\r\n", settings.enablePrintRtcSync ? "Enabled" : "Disabled"); - systemPrint("38) Print NTP Request diagnostics: "); - systemPrintf("%s\r\n", settings.enablePrintNTPDiag ? "Enabled" : "Disabled"); + systemPrint("38) Debug NTP: "); + systemPrintf("%s\r\n", settings.debugNtp ? "Enabled" : "Disabled"); systemPrint("39) Print Ethernet diagnostics: "); systemPrintf("%s\r\n", settings.enablePrintEthernetDiag ? "Enabled" : "Disabled"); @@ -537,6 +537,12 @@ void menuDebug() systemPrint("75) Print network layer status: "); systemPrintf("%s\r\n", settings.printNetworkStatus ? "Enabled" : "Disabled"); + systemPrint("76) Periodically print NTP server data: "); + systemPrintf("%s\r\n", PERIODIC_SETTING(PD_NTP_SERVER_DATA) ? "Enabled" : "Disabled"); + + systemPrint("77) Periodically print NTP server state: "); + systemPrintf("%s\r\n", PERIODIC_SETTING(PD_NTP_SERVER_STATE) ? "Enabled" : "Disabled"); + systemPrintln("t) Enter Test Screen"); systemPrintln("e) Erase LittleFS"); @@ -785,7 +791,7 @@ void menuDebug() } else if (incoming == 38) { - settings.enablePrintNTPDiag ^= 1; + settings.debugNtp ^= 1; } else if (incoming == 39) { @@ -1048,6 +1054,14 @@ void menuDebug() { settings.printNetworkStatus ^= 1; } + else if (incoming == 76) + { + PERIODIC_TOGGLE(PD_NTP_SERVER_DATA); + } + else if (incoming == 77) + { + PERIODIC_TOGGLE(PD_NTP_SERVER_STATE); + } else if (incoming == 'e') { systemPrintln("Erasing LittleFS and resetting"); diff --git a/Firmware/RTK_Surveyor/settings.h b/Firmware/RTK_Surveyor/settings.h index 917c15481..b9296ab74 100644 --- a/Firmware/RTK_Surveyor/settings.h +++ b/Firmware/RTK_Surveyor/settings.h @@ -181,6 +181,7 @@ enum NetworkUsers NETWORK_USER_NTRIP_CLIENT = 0, // NTRIP client NETWORK_USER_NTRIP_SERVER, // NTRIP server NETWORK_USER_PVT_CLIENT, // PVT client + NETWORK_USER_NTP_SERVER, // NTP server // Last network user NETWORK_USER_MAX }; @@ -471,6 +472,8 @@ enum PeriodDisplayValues PD_ZED_DATA_TX, //19 PD_RING_BUFFER_MILLIS, //20 + PD_NTP_SERVER_DATA, //21 + PD_NTP_SERVER_STATE, //22 }; #define PERIODIC_MASK(x) (1 << x) @@ -989,9 +992,9 @@ typedef struct bool mdnsEnable = true; // Allows locating of device from browser address 'rtk.local' // NTP + bool debugNtp = false; uint16_t ethernetNtpPort = 123; bool enableNTPFile = false; // Log NTP requests to file - bool enablePrintNTPDiag = false; uint8_t ntpPollExponent = 6; // NTPpacket::defaultPollExponent 2^6 = 64 seconds int8_t ntpPrecision = -20; // NTPpacket::defaultPrecision 2^-20 = 0.95us uint32_t ntpRootDelay = 0; // NTPpacket::defaultRootDelay = 0. ntpRootDelay is defined in microseconds. diff --git a/Firmware/RTK_Surveyor/support.ino b/Firmware/RTK_Surveyor/support.ino index 4ff323dc6..a0731d874 100644 --- a/Firmware/RTK_Surveyor/support.ino +++ b/Firmware/RTK_Surveyor/support.ino @@ -1129,6 +1129,7 @@ void verifyTables () // Verify the consistency of the internal tables ethernetVerifyTables(); networkVerifyTables(); + ntpValidateTables(); ntripClientValidateTables(); ntripServerValidateTables(); pvtClientValidateTables();