diff --git a/Firmware/Dockerfile b/Firmware/Dockerfile index 91eab12df..e687f0841 100644 --- a/Firmware/Dockerfile +++ b/Firmware/Dockerfile @@ -17,6 +17,9 @@ ARG DEBUG_LEVEL=error # Set to false for releases ARG ENABLE_DEVELOPER=true +# arduino-cli warnings: none default more all +ARG WARNINGS=default + # If you have your own u-blox PointPerfect token(s), define them here # or pass in as args when building the Dockerfile # POINTPERFECT_LBAND_TOKEN is the token for the deprecated u-blox L-band SPARTN service @@ -116,6 +119,7 @@ RUN cp RTKEverywhere.csv "/root/.arduino15/packages/esp32/hardware/esp32/${CORE_ # Compile Sketch RUN cd ./RTK_Everywhere \ && arduino-cli compile --fqbn "esp32:esp32:esp32":DebugLevel=${DEBUG_LEVEL},PSRAM=enabled \ + --warnings ${WARNINGS} \ ./RTK_Everywhere.ino \ --build-property build.partitions=RTKEverywhere \ --build-property upload.maximum_size=4055040 \ diff --git a/Firmware/RTK_Everywhere/Developer.ino b/Firmware/RTK_Everywhere/Developer.ino index 42677f2f4..75ce977f5 100644 --- a/Firmware/RTK_Everywhere/Developer.ino +++ b/Firmware/RTK_Everywhere/Developer.ino @@ -9,8 +9,9 @@ // Ethernet //---------------------------------------- -bool ethernetLinkUp() {return false;} -void menuEthernet() {systemPrintln("**Ethernet not compiled**");} +bool ethernetLinkUp() {return false;} +void menuEthernet() {systemPrintln("**Ethernet not compiled**");} +void ethernetUpdate() {} bool ntpLogIncreasing = false; diff --git a/Firmware/RTK_Everywhere/Display.ino b/Firmware/RTK_Everywhere/Display.ino index 8de0a1c5e..bcb1ef59a 100644 --- a/Firmware/RTK_Everywhere/Display.ino +++ b/Firmware/RTK_Everywhere/Display.ino @@ -1992,7 +1992,7 @@ void paintIPAddress() char ipAddress[16]; snprintf(ipAddress, sizeof(ipAddress), "%s", #ifdef COMPILE_ETHERNET - ETH.localIP().toString()); + ETH.localIP().toString().c_str()); #else // COMPILE_ETHERNET "0.0.0.0"); #endif // COMPILE_ETHERNET @@ -2032,7 +2032,7 @@ void displayFullIPAddress(std::vector *iconList) // Bottom { static IPAddress ipAddress; NetPriority_t priority; - static NetPriority_t previousPriority; + static NetPriority_t previousPriority = NETWORK_NONE; // Max width: 15*6 = 90 pixels (6 pixels per character, nnn.nnn.nnn.nnn) if (present.display_type == DISPLAY_128x64) @@ -2052,7 +2052,7 @@ void displayFullIPAddress(std::vector *iconList) // Bottom // Display the IP address when it is available if (ipAddress != IPAddress((uint32_t)0)) { - snprintf(myAddress, sizeof(myAddress), "%s", ipAddress.toString()); + snprintf(myAddress, sizeof(myAddress), "%s", ipAddress.toString().c_str()); oled->setFont(QW_FONT_5X7); // Set font to smallest oled->setCursor(0, 55); diff --git a/Firmware/RTK_Everywhere/Ethernet.ino b/Firmware/RTK_Everywhere/Ethernet.ino index 387037fed..3469dafe7 100644 --- a/Firmware/RTK_Everywhere/Ethernet.ino +++ b/Firmware/RTK_Everywhere/Ethernet.ino @@ -188,6 +188,9 @@ void ethernetEvent(arduino_event_id_t event, arduino_event_info_t info) case ARDUINO_EVENT_ETH_DISCONNECTED: if (settings.enablePrintEthernetDiag && (!inMainMenu)) systemPrintln("ETH Disconnected"); + + ethernetRestartRequested = true; // Perform ETH.end() to disconnect TCP resources + break; case ARDUINO_EVENT_ETH_STOP: @@ -236,6 +239,20 @@ const char *ethernetGetEventName(arduino_event_id_t event) } } +//---------------------------------------- +// Update Ethernet. Restart if requested +//---------------------------------------- +void ethernetUpdate() +{ + if (ethernetRestartRequested) + { + if (settings.enablePrintEthernetDiag && (!inMainMenu)) + systemPrintln("Restarting Ethernet"); + ethernetRestart(); + ethernetRestartRequested = false; + } +} + //---------------------------------------- // Restart the Ethernet controller //---------------------------------------- diff --git a/Firmware/RTK_Everywhere/NTP.ino b/Firmware/RTK_Everywhere/NTP.ino index ee392b811..8a8c1878d 100644 --- a/Firmware/RTK_Everywhere/NTP.ino +++ b/Firmware/RTK_Everywhere/NTP.ino @@ -609,7 +609,7 @@ bool ntpProcessOneRequest(bool process, const timeval *recTv, const timeval *syn if (ntpDiag != nullptr) { char tmpbuf[128]; - snprintf(tmpbuf, sizeof(tmpbuf), "Originate Timestamp (Client Transmit): %u.%06u\r\n", + snprintf(tmpbuf, sizeof(tmpbuf), "Originate Timestamp (Client Transmit): %lu.%06lu\r\n", packet.transmitTimestampSeconds, packet.convertFractionToMicros(packet.transmitTimestampFraction)); strlcat(ntpDiag, tmpbuf, ntpDiagSize); @@ -631,7 +631,7 @@ bool ntpProcessOneRequest(bool process, const timeval *recTv, const timeval *syn if (ntpDiag != nullptr) { char tmpbuf[128]; - snprintf(tmpbuf, sizeof(tmpbuf), "Received Timestamp: %u.%06u\r\n", + snprintf(tmpbuf, sizeof(tmpbuf), "Received Timestamp: %lu.%06lu\r\n", packet.receiveTimestampSeconds, packet.convertFractionToMicros(packet.receiveTimestampFraction)); strlcat(ntpDiag, tmpbuf, ntpDiagSize); @@ -649,7 +649,7 @@ bool ntpProcessOneRequest(bool process, const timeval *recTv, const timeval *syn if (ntpDiag != nullptr) { char tmpbuf[128]; - snprintf(tmpbuf, sizeof(tmpbuf), "Reference Timestamp (Last Sync): %u.%06u\r\n", + snprintf(tmpbuf, sizeof(tmpbuf), "Reference Timestamp (Last Sync): %lu.%06lu\r\n", packet.referenceTimestampSeconds, packet.convertFractionToMicros(packet.referenceTimestampFraction)); strlcat(ntpDiag, tmpbuf, ntpDiagSize); @@ -677,7 +677,7 @@ bool ntpProcessOneRequest(bool process, const timeval *recTv, const timeval *syn if (ntpDiag != nullptr) { char tmpbuf[128]; - snprintf(tmpbuf, sizeof(tmpbuf), "Transmit Timestamp: %u.%06u\r\n", + snprintf(tmpbuf, sizeof(tmpbuf), "Transmit Timestamp: %lu.%06lu\r\n", packet.transmitTimestampSeconds, packet.convertFractionToMicros(packet.transmitTimestampFraction)); strlcat(ntpDiag, tmpbuf, ntpDiagSize); diff --git a/Firmware/RTK_Everywhere/NVM.ino b/Firmware/RTK_Everywhere/NVM.ino index c5d6fbc8b..ed0fdf70e 100644 --- a/Firmware/RTK_Everywhere/NVM.ino +++ b/Firmware/RTK_Everywhere/NVM.ino @@ -279,7 +279,7 @@ void recordSystemSettingsToFile(File *settingsFile) break; case _uint32_t: { uint32_t *ptr = (uint32_t *)rtkSettingsEntries[i].var; - settingsFile->printf("%s=%d\r\n", rtkSettingsEntries[i].name, *ptr); + settingsFile->printf("%s=%lu\r\n", rtkSettingsEntries[i].name, *ptr); } break; case _uint64_t: { diff --git a/Firmware/RTK_Everywhere/Network.ino b/Firmware/RTK_Everywhere/Network.ino index 32a98faa1..7a8a531c6 100644 --- a/Firmware/RTK_Everywhere/Network.ino +++ b/Firmware/RTK_Everywhere/Network.ino @@ -2453,10 +2453,12 @@ void networkUpdate() // Update the WiFi state wifiStationUpdate(); + // Update Ethernet + ethernetUpdate(); + // Update the network services // Start or stop mDNS - if (networkMdnsRequests != networkMdnsRunning) - networkMulticastDNSUpdate(); + networkMulticastDNSUpdate(); // Update the network services DMW_c("mqttClientUpdate"); diff --git a/Firmware/RTK_Everywhere/NtripServer.ino b/Firmware/RTK_Everywhere/NtripServer.ino index 3e30beb1f..1353783ac 100644 --- a/Firmware/RTK_Everywhere/NtripServer.ino +++ b/Firmware/RTK_Everywhere/NtripServer.ino @@ -173,7 +173,7 @@ const RtkMode_t ntripServerMode = RTK_MODE_BASE_FIXED; //---------------------------------------- // NTRIP Servers -volatile static NTRIP_SERVER_DATA ntripServerArray[NTRIP_SERVER_MAX]; +static NTRIP_SERVER_DATA ntripServerArray[NTRIP_SERVER_MAX]; //---------------------------------------- // NTRIP Server Routines @@ -184,7 +184,7 @@ volatile static NTRIP_SERVER_DATA ntripServerArray[NTRIP_SERVER_MAX]; //---------------------------------------- bool ntripServerConnectCaster(int serverIndex) { - volatile NTRIP_SERVER_DATA *ntripServer = &ntripServerArray[serverIndex]; + NTRIP_SERVER_DATA *ntripServer = &ntripServerArray[serverIndex]; const int SERVER_BUFFER_SIZE = 512; char serverBuffer[SERVER_BUFFER_SIZE]; @@ -240,7 +240,7 @@ bool ntripServerConnectLimitReached(int serverIndex) { bool limitReached; int minutes; - volatile NTRIP_SERVER_DATA *ntripServer = &ntripServerArray[serverIndex]; + NTRIP_SERVER_DATA *ntripServer = &ntripServerArray[serverIndex]; int seconds; // Retry the connection a few times @@ -312,9 +312,9 @@ bool ntripServerEnabled(int serverIndex, const char ** line) { if (line) { - if (settings.ntripServer_CasterHost[0] == 0) + if (settings.ntripServer_CasterHost[serverIndex][0] == 0) *line = ", Caster host not specified!"; - else if (settings.ntripServer_CasterPort == 0) + else if (settings.ntripServer_CasterPort[serverIndex] == 0) *line = ", Caster port not specified!"; else *line = ", Mount point not specified!"; @@ -335,7 +335,7 @@ bool ntripServerEnabled(int serverIndex, const char ** line) //---------------------------------------- void ntripServerPrintStateSummary(int serverIndex) { - volatile NTRIP_SERVER_DATA *ntripServer = &ntripServerArray[serverIndex]; + NTRIP_SERVER_DATA *ntripServer = &ntripServerArray[serverIndex]; switch (ntripServer->state) { @@ -363,7 +363,7 @@ void ntripServerPrintStateSummary(int serverIndex) //---------------------------------------- void ntripServerPrintStatus(int serverIndex) { - volatile NTRIP_SERVER_DATA *ntripServer = &ntripServerArray[serverIndex]; + NTRIP_SERVER_DATA *ntripServer = &ntripServerArray[serverIndex]; uint64_t milliseconds; uint32_t days; byte hours; @@ -380,7 +380,7 @@ void ntripServerPrintStatus(int serverIndex) if (ntripServer->state == NTRIP_SERVER_CASTING) // Use ntripServer->timer since it gets reset after each successful data // reception from the NTRIP caster - milliseconds = ntripServer->timer - ntripServer->startTime; + milliseconds = ntripServer->getUptime(); else { milliseconds = ntripServer->startTime; @@ -411,7 +411,7 @@ void ntripServerPrintStatus(int serverIndex) //---------------------------------------- void ntripServerProcessRTCM(int serverIndex, uint8_t incoming) { - volatile NTRIP_SERVER_DATA *ntripServer = &ntripServerArray[serverIndex]; + NTRIP_SERVER_DATA *ntripServer = &ntripServerArray[serverIndex]; if (ntripServer->state == NTRIP_SERVER_CASTING) { @@ -434,22 +434,27 @@ void ntripServerProcessRTCM(int serverIndex, uint8_t incoming) } // If we have not gotten new RTCM bytes for a period of time, assume end of frame - if (((millis() - ntripServer->timer) > 100) && (ntripServer->bytesSent > 0)) - { - if ((!inMainMenu) && settings.debugNtripServerRtcm) - systemPrintf("NTRIP Server %d transmitted %d RTCM bytes to Caster\r\n", serverIndex, - ntripServer->bytesSent); - - ntripServer->bytesSent = 0; - } + if (ntripServer->checkBytesSentAndReset(100) && (!inMainMenu) && settings.debugNtripServerRtcm) + systemPrintf("NTRIP Server %d transmitted %d RTCM bytes to Caster\r\n", serverIndex, + ntripServer->bytesSent); if (ntripServer->networkClient && ntripServer->networkClient->connected()) { - ntripServer->networkClient->write(incoming); // Send this byte to socket - ntripServer->bytesSent = ntripServer->bytesSent + 1; - ntripServer->rtcmBytesSent = ntripServer->rtcmBytesSent + 1; - ntripServer->timer = millis(); - netOutgoingRTCM = true; + if (ntripServer->networkClient->write(incoming) == 1) // Send this byte to socket + { + ntripServer->updateTimerAndBytesSent(); + netOutgoingRTCM = true; + while (ntripServer->networkClient->available()) + ntripServer->networkClient->read(); // Absorb any unwanted incoming traffic + } + // Failed to write the data + else + { + // Done with this client connection + if (settings.debugNtripServerRtcm && (!inMainMenu)) + systemPrintf("NTRIP Server %d broken connection to %s\r\n", serverIndex, + settings.ntripServer_CasterHost[serverIndex]); + } } } @@ -465,7 +470,7 @@ void ntripServerProcessRTCM(int serverIndex, uint8_t incoming) //---------------------------------------- void ntripServerResponse(int serverIndex, char *response, size_t maxLength) { - volatile NTRIP_SERVER_DATA *ntripServer = &ntripServerArray[serverIndex]; + NTRIP_SERVER_DATA *ntripServer = &ntripServerArray[serverIndex]; char *responseEnd; // Make sure that we can zero terminate the response @@ -484,11 +489,11 @@ void ntripServerResponse(int serverIndex, char *response, size_t maxLength) //---------------------------------------- void ntripServerRestart(int serverIndex) { - volatile NTRIP_SERVER_DATA *ntripServer = &ntripServerArray[serverIndex]; + NTRIP_SERVER_DATA *ntripServer = &ntripServerArray[serverIndex]; // Save the previous uptime value if (ntripServer->state == NTRIP_SERVER_CASTING) - ntripServer->startTime = ntripServer->timer - ntripServer->startTime; + ntripServer->startTime = ntripServer->getUptime(); ntripServerConnectLimitReached(serverIndex); } @@ -497,7 +502,7 @@ void ntripServerRestart(int serverIndex) //---------------------------------------- void ntripServerSetState(int serverIndex, uint8_t newState) { - volatile NTRIP_SERVER_DATA * ntripServer; + NTRIP_SERVER_DATA * ntripServer; ntripServer = &ntripServerArray[serverIndex]; if (settings.debugNtripServerState) @@ -549,7 +554,7 @@ void ntripServerStop(int serverIndex, bool shutdown) { bool enabled; int index; - volatile NTRIP_SERVER_DATA *ntripServer = &ntripServerArray[serverIndex]; + NTRIP_SERVER_DATA *ntripServer = &ntripServerArray[serverIndex]; if (ntripServer->networkClient) { @@ -566,7 +571,7 @@ void ntripServerStop(int serverIndex, bool shutdown) // Increase timeouts if we started the network if (ntripServer->state > NTRIP_SERVER_OFF) // Mark the Server stop so that we don't immediately attempt re-connect to Caster - ntripServer->timer = millis(); + ntripServer->setTimerToMillis(); // Determine the next NTRIP server state online.ntripServer[serverIndex] = false; @@ -613,7 +618,7 @@ void ntripServerUpdate(int serverIndex) const char * line = ""; // Get the NTRIP data structure - volatile NTRIP_SERVER_DATA *ntripServer = &ntripServerArray[serverIndex]; + NTRIP_SERVER_DATA *ntripServer = &ntripServerArray[serverIndex]; // Shutdown the NTRIP server when the mode or setting changes DMW_if @@ -678,8 +683,7 @@ void ntripServerUpdate(int serverIndex) // Failed to connect to to the network, attempt to restart the network ntripServerRestart(serverIndex); - else if (settings.enableNtripServer && - ((millis() - ntripServer->lastConnectionAttempt) > ntripServer->connectionAttemptTimeout)) + else if (settings.enableNtripServer) { // No RTCM correction data sent yet rtcmPacketsSent = 0; @@ -697,7 +701,7 @@ void ntripServerUpdate(int serverIndex) // Initiate the connection to the NTRIP caster case NTRIP_SERVER_CONNECTING: // Delay before opening the NTRIP server connection - if ((millis() - ntripServer->timer) >= ntripServer->connectionAttemptTimeout) + if (ntripServer->checkConnectionAttemptTimeout()) { // Attempt a connection to the NTRIP caster if (!ntripServerConnectCaster(serverIndex)) @@ -711,7 +715,7 @@ void ntripServerUpdate(int serverIndex) else { // Connection open to NTRIP caster, wait for the authorization response - ntripServer->timer = millis(); + ntripServer->setTimerToMillis(); ntripServerSetState(serverIndex, NTRIP_SERVER_AUTHORIZATION); } } @@ -724,7 +728,7 @@ void ntripServerUpdate(int serverIndex) strlen("ICY 200 OK")) // Wait until at least a few bytes have arrived { // Check for response timeout - if ((millis() - ntripServer->timer) > 10000) + if (ntripServer->millisSinceTimer() > 10000) { if (ntripServerConnectLimitReached(serverIndex)) systemPrintf( @@ -771,7 +775,7 @@ void ntripServerUpdate(int serverIndex) settings.ntripServer_MountPoint[serverIndex]); // Connection is now open, start the RTCM correction data timer - ntripServer->timer = millis(); + ntripServer->setTimerToMillis(); // We don't use a task because we use I2C hardware (and don't have a semaphore). online.ntripServer[serverIndex] = true; @@ -816,7 +820,7 @@ void ntripServerUpdate(int serverIndex) settings.ntripServer_CasterHost[serverIndex]); ntripServerRestart(serverIndex); } - else if ((millis() - ntripServer->timer) > (10 * 1000)) + else if (ntripServer->millisSinceTimer() > (10 * 1000)) { // GNSS stopped sending RTCM correction data systemPrintf("NTRIP Server %d breaking connection to %s due to lack of RTCM data!\r\n", serverIndex, @@ -831,7 +835,7 @@ void ntripServerUpdate(int serverIndex) // connection. However increasing backoff delays should be // added when the NTRIP caster fails after a short connection // interval. - if (((millis() - ntripServer->startTime) > NTRIP_SERVER_CONNECTION_TIME) && + if ((ntripServer->millisSinceStartTime() > NTRIP_SERVER_CONNECTION_TIME) && (ntripServer->connectionAttempts || ntripServer->connectionAttemptTimeout)) { // After a long connection period, reset the attempt counter diff --git a/Firmware/RTK_Everywhere/RTK_Everywhere.ino b/Firmware/RTK_Everywhere/RTK_Everywhere.ino index 2bb55c1d2..20cdf21b7 100644 --- a/Firmware/RTK_Everywhere/RTK_Everywhere.ino +++ b/Firmware/RTK_Everywhere/RTK_Everywhere.ino @@ -607,7 +607,7 @@ uint8_t *ringBuffer; // Buffer for reading from GNSS receiver. At 230400bps, 230 const int gnssReadTaskStackSize = 8000; const size_t sempGnssReadBufferSize = 8000; // Make the SEMP buffer size the ~same -const int handleGnssDataTaskStackSize = 3000; +const int handleGnssDataTaskStackSize = 4000; TaskHandle_t pinBluetoothTaskHandle; // Dummy task to start hardware on an assigned core volatile bool bluetoothPinned; // This variable is touched by core 0 but checked by core 1. Must be volatile. @@ -737,6 +737,7 @@ IPAddress ethernetSubnetMask; // }; volatile struct timeval ethernetNtpTv; // This will hold the time the Ethernet NTP packet arrived bool ntpLogIncreasing; +bool ethernetRestartRequested = false; // Perform ETH.end() to disconnect TCP resources #endif // COMPILE_ETHERNET unsigned long lastEthernetCheck; // Prevents cable checking from continually happening @@ -871,7 +872,42 @@ uint32_t rtcmLastPacketSent; // Time stamp of RTCM going out (to NTRIP Server, E uint32_t maxSurveyInWait_s = 60L * 15L; // Re-start survey-in after X seconds -uint32_t lastSetupMenuChange; // Limits how much time is spent in the setup menu +typedef struct { + volatile unsigned long timer; + + SemaphoreHandle_t updateSemaphore = NULL; + + void setTimerToMillis() + { + if (updateSemaphore == NULL) + updateSemaphore = xSemaphoreCreateMutex(); + if (xSemaphoreTake(updateSemaphore, 10 / portTICK_PERIOD_MS) == pdPASS) + { + timer = millis(); + xSemaphoreGive(updateSemaphore); + } + } + + unsigned long millisSinceUpdate() + { + unsigned long retVal = 0; + if (updateSemaphore == NULL) + updateSemaphore = xSemaphoreCreateMutex(); + if (xSemaphoreTake(updateSemaphore, 10 / portTICK_PERIOD_MS) == pdPASS) + { + // The semaphore prevents the race condition where timer is updated after + // millis() is read but before the subtraction. It prevents retVal from underflowing + retVal = millis() - timer; + xSemaphoreGive(updateSemaphore); + } + return retVal; + } +} semaphoreProtectedTimer; +// Needs a mutex because the timer is updated by the button task +// but read by stateUpdate the loop. Prevents a race condition +// and the occasional glitching seen in the button menu +semaphoreProtectedTimer lastSetupMenuChange; // Limits how much time is spent in the setup menu + uint32_t lastTestMenuChange; // Avoids exiting the test menu for at least 1 second uint8_t setupSelectedButton = 0; // In Display Setup, start displaying at this button. This is the selected (highlighted) button. @@ -910,7 +946,7 @@ uint32_t max_idle_count = MAX_IDLE_TIME_COUNT; bool bluetoothIncomingRTCM; bool bluetoothOutgoingRTCM; bool netIncomingRTCM; -bool netOutgoingRTCM; +volatile bool netOutgoingRTCM; volatile bool mqttClientDataReceived; // Flag for display uint16_t failedParserMessages_UBX; @@ -1635,7 +1671,7 @@ void logUpdate() { // Calculate generation and write speeds every 5 seconds uint64_t fileSizeDelta = logFileSize - lastLogSize; - systemPrintf(" - Generation rate: %0.1fkB/s", ((float)fileSizeDelta) / 5.0 / 1000.0); + systemPrintf(" - Generation rate: %0.1fkB/s", ((double)fileSizeDelta) / 5.0 / 1000.0); } else { @@ -1652,7 +1688,8 @@ void logUpdate() } else { - log_d("No increase in file size"); + if ((settings.enablePrintLogFileStatus) && (!inMainMenu)) + systemPrintf("No increase in file size: %llu -> %llu\r\n", lastLogSize, logFileSize); logIncreasing = false; endSD(false, true); // alreadyHaveSemaphore, releaseSemaphore diff --git a/Firmware/RTK_Everywhere/States.ino b/Firmware/RTK_Everywhere/States.ino index aa8e473f5..b66a06661 100644 --- a/Firmware/RTK_Everywhere/States.ino +++ b/Firmware/RTK_Everywhere/States.ino @@ -399,7 +399,7 @@ void stateUpdate() break; case (STATE_DISPLAY_SETUP): { - if ((millis() - lastSetupMenuChange) > 10000) // Exit Setup after 10s + if (lastSetupMenuChange.millisSinceUpdate() > 10000) // Exit Setup after 10s { firstButtonThrownOut = false; changeState(lastSystemState); // Return to the last system state @@ -686,6 +686,7 @@ const char *getState(SystemState state, char *buffer) return "STATE_DISPLAY_SETUP"; case (STATE_WEB_CONFIG_NOT_STARTED): return "STATE_WEB_CONFIG_NOT_STARTED"; + case (STATE_WEB_CONFIG_WAIT_FOR_NETWORK): case (STATE_WEB_CONFIG): return "STATE_WEB_CONFIG"; case (STATE_TEST): diff --git a/Firmware/RTK_Everywhere/Tasks.ino b/Firmware/RTK_Everywhere/Tasks.ino index fcb07f309..c651537bd 100644 --- a/Firmware/RTK_Everywhere/Tasks.ino +++ b/Firmware/RTK_Everywhere/Tasks.ino @@ -1645,7 +1645,7 @@ void handleGnssDataTask(void *e) // Record trigger count with Time Of Week of rising edge (ms), Millisecond fraction of Time Of Week of // rising edge (ns), and accuracy estimate (ns) char eventData[82]; // Max NMEA sentence length is 82 - snprintf(eventData, sizeof(eventData), "%d,%d,%d,%d", triggerCount, triggerTowMsR, triggerTowSubMsR, + snprintf(eventData, sizeof(eventData), "%lu,%lu,%lu,%lu", triggerCount, triggerTowMsR, triggerTowSubMsR, triggerAccEst); char nmeaMessage[82]; // Max NMEA sentence length is 82 @@ -1693,8 +1693,9 @@ void handleGnssDataTask(void *e) logFileSize = logFile->fileSize(); // Update file size - // Force file sync every 60s - if ((millis() - lastUBXLogSyncTime) > 60000) + // Force file sync every 60s - or every two seconds if the size is not increasing + if (((logFileSize == lastLogSize) && ((millis() - lastUBXLogSyncTime) > 2000)) + || ((millis() - lastUBXLogSyncTime) > 60000)) { baseStatusLedBlink(); // Blink LED to indicate logging activity @@ -2183,7 +2184,7 @@ void buttonCheckTask(void *e) else if ((systemState == STATE_BASE_NOT_STARTED) && (firstRoverStart == true) && (buttonPressedFor(500) == true)) { - lastSetupMenuChange = millis(); // Prevent a timeout during state change + lastSetupMenuChange.setTimerToMillis(); // Prevent a timeout during state change forceSystemStateUpdate = true; requestChangeState(STATE_TEST); } @@ -2216,7 +2217,7 @@ void buttonCheckTask(void *e) case STATE_NTPSERVER_SYNC: lastSystemState = systemState; // Remember this state to return if needed requestChangeState(STATE_DISPLAY_SETUP); - lastSetupMenuChange = millis(); + lastSetupMenuChange.setTimerToMillis(); setupSelectedButton = 0; // Highlight the first button showMenu = false; break; @@ -2225,7 +2226,7 @@ void buttonCheckTask(void *e) // If we are displaying the setup menu, a single tap will cycle through possible system states // Exit into new system state on double tap - see below // Exit display setup into previous state after ~10s - see updateSystemState() - lastSetupMenuChange = millis(); + lastSetupMenuChange.setTimerToMillis(); forceDisplayUpdate = true; // User is interacting so repaint display quickly @@ -2262,7 +2263,7 @@ void buttonCheckTask(void *e) case STATE_TESTING: // If we are in testing, return to Base Not Started - lastSetupMenuChange = millis(); // Prevent a timeout during state change + lastSetupMenuChange.setTimerToMillis(); // Prevent a timeout during state change baseCasterDisableOverride(); // Leave Caster mode requestChangeState(STATE_BASE_NOT_STARTED); break; @@ -2287,7 +2288,7 @@ void buttonCheckTask(void *e) // 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() - lastSetupMenuChange = millis(); // Prevent a timeout during state change + lastSetupMenuChange.setTimerToMillis(); // Prevent a timeout during state change uint8_t thisIsButton = 0; for (auto it = setupButtons.begin(); it != setupButtons.end(); it = std::next(it)) { diff --git a/Firmware/RTK_Everywhere/TcpClient.ino b/Firmware/RTK_Everywhere/TcpClient.ino index 690e872ac..e45def741 100644 --- a/Firmware/RTK_Everywhere/TcpClient.ino +++ b/Firmware/RTK_Everywhere/TcpClient.ino @@ -249,6 +249,9 @@ int32_t tcpClientSendData(uint16_t dataHead) bytesToSend = dataHead - tcpClientTail; if (bytesToSend < 0) bytesToSend += settings.gnssHandlerBufferSize; + + while(tcpClient->available()) + tcpClient->read(); // Absorb any unwanted incoming traffic } // Failed to write the data diff --git a/Firmware/RTK_Everywhere/menuCommands.ino b/Firmware/RTK_Everywhere/menuCommands.ino index 8cca343af..91d81ae88 100644 --- a/Firmware/RTK_Everywhere/menuCommands.ino +++ b/Firmware/RTK_Everywhere/menuCommands.ino @@ -2447,7 +2447,7 @@ void stringRecord(char *settingsCSV, const char *id, int settingValue) void stringRecord(char *settingsCSV, const char *id, uint32_t settingValue) { char record[100]; - snprintf(record, sizeof(record), "%s,%d,", id, settingValue); + snprintf(record, sizeof(record), "%s,%lu,", id, settingValue); strcat(settingsCSV, record); } @@ -4138,7 +4138,7 @@ void printAvailableSettings() // Convert int to string char batteryChargingPercentStr[3] = {0}; // 45 - snprintf(batteryChargingPercentStr, sizeof(batteryChargingPercentStr), "%0.0f", batteryChargingPercentStr); + snprintf(batteryChargingPercentStr, sizeof(batteryChargingPercentStr), "%0.0f", batteryChargingPercentPerHour); // Create the settingType based on the length of the firmware version char settingType[100]; diff --git a/Firmware/RTK_Everywhere/settings.h b/Firmware/RTK_Everywhere/settings.h index d1bbda9ea..b99209dac 100644 --- a/Firmware/RTK_Everywhere/settings.h +++ b/Firmware/RTK_Everywhere/settings.h @@ -385,34 +385,135 @@ enum PeriodDisplayValues #ifdef COMPILE_NETWORK -// NTRIP Server data - the array is declared volatile in NtripServer.ino +// NTRIP Server data typedef struct { // Network connection used to push RTCM to NTRIP caster NetworkClient *networkClient; - uint8_t state; + volatile uint8_t state; // Count of bytes sent by the NTRIP server to the NTRIP caster - uint32_t bytesSent; + volatile uint32_t bytesSent; // Throttle the time between connection attempts // ms - Max of 4,294,967,295 or 4.3M seconds or 71,000 minutes or 1193 hours or 49 days between attempts - uint32_t connectionAttemptTimeout; - uint32_t lastConnectionAttempt; - int connectionAttempts; // Count the number of connection attempts between restarts + volatile uint32_t connectionAttemptTimeout; + volatile int connectionAttempts; // Count the number of connection attempts between restarts // NTRIP server timer usage: // * Reconnection delay // * Measure the connection response time // * Receive RTCM correction data timeout // * Monitor last RTCM byte received for frame counting - uint32_t timer; - uint32_t startTime; - int connectionAttemptsTotal; // Count the number of connection attempts absolutely + volatile uint32_t timer; + volatile uint32_t startTime; + volatile int connectionAttemptsTotal; // Count the number of connection attempts absolutely // Better debug printing by ntripServerProcessRTCM - uint32_t rtcmBytesSent; - uint32_t previousMilliseconds; + volatile uint32_t rtcmBytesSent; + volatile uint32_t previousMilliseconds; + + + // Protect all methods that manipulate timer with a mutex - to avoid race conditions + // Remember that data is pushed to the servers by + // gnssReadTask -> processUart1Message -> processRTCM -> ntripServerProcessRTCM + SemaphoreHandle_t serverSemaphore = NULL; + + unsigned long millisSinceTimer() + { + unsigned long retVal = 0; + if (serverSemaphore == NULL) + serverSemaphore = xSemaphoreCreateMutex(); + if (xSemaphoreTake(serverSemaphore, 10 / portTICK_PERIOD_MS) == pdPASS) + { + retVal = millis() - timer; + xSemaphoreGive(serverSemaphore); + } + return retVal; + } + + unsigned long millisSinceStartTime() + { + unsigned long retVal = 0; + if (serverSemaphore == NULL) + serverSemaphore = xSemaphoreCreateMutex(); + if (xSemaphoreTake(serverSemaphore, 10 / portTICK_PERIOD_MS) == pdPASS) + { + retVal = millis() - startTime; + xSemaphoreGive(serverSemaphore); + } + return retVal; + } + + void updateTimerAndBytesSent() + { + if (serverSemaphore == NULL) + serverSemaphore = xSemaphoreCreateMutex(); + if (xSemaphoreTake(serverSemaphore, 10 / portTICK_PERIOD_MS) == pdPASS) + { + bytesSent = bytesSent + 1; + rtcmBytesSent = rtcmBytesSent + 1; + timer = millis(); + xSemaphoreGive(serverSemaphore); + } + } + + bool checkBytesSentAndReset(uint32_t timerLimit) + { + bool retVal = false; + if (serverSemaphore == NULL) + serverSemaphore = xSemaphoreCreateMutex(); + if (xSemaphoreTake(serverSemaphore, 10 / portTICK_PERIOD_MS) == pdPASS) + { + if (((millis() - timer) > timerLimit) && (bytesSent > 0)) + { + retVal = true; + bytesSent = 0; + } + xSemaphoreGive(serverSemaphore); + } + return retVal; + } + + unsigned long getUptime() + { + unsigned long retVal = 0; + if (serverSemaphore == NULL) + serverSemaphore = xSemaphoreCreateMutex(); + if (xSemaphoreTake(serverSemaphore, 10 / portTICK_PERIOD_MS) == pdPASS) + { + retVal = timer - startTime; + xSemaphoreGive(serverSemaphore); + } + return retVal; + } + + void setTimerToMillis() + { + if (serverSemaphore == NULL) + serverSemaphore = xSemaphoreCreateMutex(); + if (xSemaphoreTake(serverSemaphore, 10 / portTICK_PERIOD_MS) == pdPASS) + { + timer = millis(); + xSemaphoreGive(serverSemaphore); + } + } + + bool checkConnectionAttemptTimeout() + { + bool retVal = false; + if (serverSemaphore == NULL) + serverSemaphore = xSemaphoreCreateMutex(); + if (xSemaphoreTake(serverSemaphore, 10 / portTICK_PERIOD_MS) == pdPASS) + { + if ((millis() - timer) >= connectionAttemptTimeout) + { + retVal = true; + } + xSemaphoreGive(serverSemaphore); + } + return retVal; + } } NTRIP_SERVER_DATA; #endif // COMPILE_NETWORK @@ -760,11 +861,11 @@ struct Settings // GNSS UART uint16_t serialGNSSRxFullThreshold = 50; // RX FIFO full interrupt. Max of ~128. See pinUART2Task(). - int uartReceiveBufferSize = 1024 * 2; // This buffer is filled automatically as the UART receives characters. + int uartReceiveBufferSize = 1024 * 4; // This buffer is filled automatically as the UART receives characters. EVK needs 4K // Hardware - bool enableExternalHardwareEventLogging = false; // Log when INT/TM2 pin goes low - uint16_t spiFrequency = 16; // By default, use 16MHz SPI + bool enableExternalHardwareEventLogging = false; // Log when INT/TM2 pin goes low + uint16_t spiFrequency = 16; // By default, use 16MHz SPI // HTTP bool debugHttpClientData = false; // Debug the HTTP Client (ZTP) data flow