From e817897ad826661a7a0ea407db9019018d6c59b6 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Fri, 20 Sep 2024 16:24:26 +0100 Subject: [PATCH] Add support for FugroTimeOffset --- Firmware/RTK_mosaic-T_Firmware/Begin.ino | 43 +++++- Firmware/RTK_mosaic-T_Firmware/Display.ino | 15 +- Firmware/RTK_mosaic-T_Firmware/GNSS.ino | 20 ++- Firmware/RTK_mosaic-T_Firmware/NVM.ino | 6 + .../RTK_mosaic-T_Firmware.ino | 45 ++++-- Firmware/RTK_mosaic-T_Firmware/States.ino | 63 ++++++-- Firmware/RTK_mosaic-T_Firmware/Tasks.ino | 29 ++++ Firmware/RTK_mosaic-T_Firmware/menuSystem.ino | 146 +++++++++++------- Firmware/RTK_mosaic-T_Firmware/settings.h | 2 + 9 files changed, 286 insertions(+), 83 deletions(-) diff --git a/Firmware/RTK_mosaic-T_Firmware/Begin.ino b/Firmware/RTK_mosaic-T_Firmware/Begin.ino index 3c74b93..0050683 100644 --- a/Firmware/RTK_mosaic-T_Firmware/Begin.ino +++ b/Firmware/RTK_mosaic-T_Firmware/Begin.ino @@ -273,7 +273,7 @@ void updateErrorLED() void updateLockLED() { - digitalWrite(pin_lockLED, (fabs(gnssClockBias_ms) < settings.rxClkBiasLockLimit_ms) ? HIGH : LOW); + digitalWrite(pin_lockLED, (fabs(tcxoClockBias_ms) < settings.rxClkBiasLockLimit_ms) ? HIGH : LOW); } // Depending on platform and previous power down state, set system state @@ -507,6 +507,45 @@ void updateTCXO() { if (online.tcxo) { - myTCXO.setFrequencyByBiasMillis(gnssClockBias_ms, settings.Pk, settings.Ik); + myTCXO.setFrequencyByBiasMillis(tcxoClockBias_ms, settings.Pk, settings.Ik); } } + +// This function updates the tcxoClockBias_ms used to discipline the TCXO frequency +// updateTCXOClockBias is only called by STATE_GNSS_FINETIME when gnssPVTUpdated was true +// So we know that gnssClockBias_ms is valid +// Use gnssClockBias_ms as the default +// If we have Fugro from FugroTimeOffset, use that +// If we have Galileo from FugroTimeOffset, use that +void updateTCXOClockBias() +{ + tcxoClockBias_ms = gnssClockBias_ms; // Default to the PVTGeodetic RxClkBias + snprintf(rxClkBiasSource, sizeof(rxClkBiasSource), "PVT"); + + int ts = getFugroTimeSystemFromName("Fugro"); + if (fugroClkBiases[ts].updated) // If we have the Fugro bias, use that + { + tcxoClockBias_ms = fugroClkBiases[ts].RxClkBias_ms; + fugroClkBiases[ts].updated = false; + snprintf(rxClkBiasSource, sizeof(rxClkBiasSource), "Fugro"); + } + + ts = getFugroTimeSystemFromName("Galileo"); + if (fugroClkBiases[ts].updated) // If we have the Galileo bias, use that + { + tcxoClockBias_ms = fugroClkBiases[ts].RxClkBias_ms; + fugroClkBiases[ts].updated = false; + snprintf(rxClkBiasSource, sizeof(rxClkBiasSource), "Galileo"); + } +} + +int getFugroTimeSystemFromName(const char *name) +{ + for (int i = 0; i < NUM_FUGRO_CLK_BIASES; i++) + { + if (strcmp(name, fugroClkBiases[i].name) == 0) + return i; + } + + return 0; // Should never happen! +} \ No newline at end of file diff --git a/Firmware/RTK_mosaic-T_Firmware/Display.ino b/Firmware/RTK_mosaic-T_Firmware/Display.ino index 1230a62..72f158e 100644 --- a/Firmware/RTK_mosaic-T_Firmware/Display.ino +++ b/Firmware/RTK_mosaic-T_Firmware/Display.ino @@ -161,15 +161,15 @@ void updateDisplay() oled->print(textLine); yPos += 8; - if ((gnssClockBias_ms >= 1.0) || (gnssClockBias_ms <= -1.0)) + if ((tcxoClockBias_ms >= 1.0) || (tcxoClockBias_ms <= -1.0)) snprintf(textLine, sizeof(textLine), "Bias %.3fms", - (float)gnssClockBias_ms); - else if ((gnssClockBias_ms >= 0.001) || (gnssClockBias_ms <= -0.001)) + (float)tcxoClockBias_ms); + else if ((tcxoClockBias_ms >= 0.001) || (tcxoClockBias_ms <= -0.001)) snprintf(textLine, sizeof(textLine), "Bias %.3fus", - (float)(gnssClockBias_ms * 1000.0)); + (float)(tcxoClockBias_ms * 1000.0)); else snprintf(textLine, sizeof(textLine), "Bias %.3fns", - (float)(gnssClockBias_ms * 1000000.0)); + (float)(tcxoClockBias_ms * 1000000.0)); oled->setCursor(0, yPos); oled->print(textLine); @@ -217,6 +217,11 @@ void displayGNSSFail(uint16_t displayTime) displayMessage("GNSS Failed", displayTime); } +void displayBadBias(uint16_t displayTime) +{ + displayMessage("Bad RxClkBias Restarting", displayTime); +} + void displayNoRingBuffer(uint16_t displayTime) { if (online.display == true) diff --git a/Firmware/RTK_mosaic-T_Firmware/GNSS.ino b/Firmware/RTK_mosaic-T_Firmware/GNSS.ino index 53e6b9a..8812fa4 100644 --- a/Firmware/RTK_mosaic-T_Firmware/GNSS.ino +++ b/Firmware/RTK_mosaic-T_Firmware/GNSS.ino @@ -108,6 +108,24 @@ void beginGNSS() online.gnss = true; } +// Kickstart the GNSS timing system - e.g. to resync on bad bias +bool setTimingSystem() +{ + if (!online.gnss) + return false; + + int retries = 3; // GNSS is already begun. We shouldn't need to retry. + + while (!sendWithResponse("sts,auto\n\r", "TimingSystem") && (retries > 0)) // Set timing system to auto + { + systemPrintln("No response from mosaic. Retrying - with escape sequence..."); + sendWithResponse("SSSSSSSSSSSSSSSSSSSS\n\r", "COM4>"); // Send escape sequence + retries--; + } + + return (retries > 0); +} + // Initialize GNSS // Disable PPS. Set clock sync threshold. Set output messages. Copy config file. // This only needs to be done once. @@ -159,7 +177,7 @@ bool initializeGNSS() return false; } - if (!sendWithResponse("sso, Stream2, COM1, IPStatus, OnChange\n\r", "SBFOutput")) + if (!sendWithResponse("sso, Stream2, COM1, IPStatus+FugroTimeOffset, OnChange\n\r", "SBFOutput")) { systemPrintln("GNSS FAIL (SBFOutput Stream2)"); return false; diff --git a/Firmware/RTK_mosaic-T_Firmware/NVM.ino b/Firmware/RTK_mosaic-T_Firmware/NVM.ino index 506f123..98847bd 100644 --- a/Firmware/RTK_mosaic-T_Firmware/NVM.ino +++ b/Firmware/RTK_mosaic-T_Firmware/NVM.ino @@ -91,7 +91,9 @@ void recordSystemSettingsToFile(File *settingsFile) settingsFile->printf("%s=%0.6f\r\n", "ppsPulseWidth_ms", settings.ppsPulseWidth_ms); settingsFile->printf("%s=%ld\r\n", "tcxoControl", settings.tcxoControl); + settingsFile->printf("%s=%0.3e\r\n", "rxClkBiasInitialLimit_ms", settings.rxClkBiasInitialLimit_ms); settingsFile->printf("%s=%0.3e\r\n", "rxClkBiasLockLimit_ms", settings.rxClkBiasLockLimit_ms); + settingsFile->printf("%s=%d\r\n", "rxClkBiasLimitCount", settings.rxClkBiasLimitCount); settingsFile->printf("%s=%0.3e\r\n", "Pk", settings.Pk); settingsFile->printf("%s=%0.3e\r\n", "Ik", settings.Ik); @@ -348,8 +350,12 @@ bool parseLine(char *str, Settings *settings) else if (strcmp(settingName, "tcxoControl") == 0) settings->tcxoControl = d; + else if (strcmp(settingName, "rxClkBiasInitialLimit_ms") == 0) + settings->rxClkBiasInitialLimit_ms = d; else if (strcmp(settingName, "rxClkBiasLockLimit_ms") == 0) settings->rxClkBiasLockLimit_ms = d; + else if (strcmp(settingName, "rxClkBiasLimitCount") == 0) + settings->rxClkBiasLimitCount = d; else if (strcmp(settingName, "Pk") == 0) settings->Pk = d; else if (strcmp(settingName, "Ik") == 0) diff --git a/Firmware/RTK_mosaic-T_Firmware/RTK_mosaic-T_Firmware.ino b/Firmware/RTK_mosaic-T_Firmware/RTK_mosaic-T_Firmware.ino index 39119a4..5006fe4 100644 --- a/Firmware/RTK_mosaic-T_Firmware/RTK_mosaic-T_Firmware.ino +++ b/Firmware/RTK_mosaic-T_Firmware/RTK_mosaic-T_Firmware.ino @@ -90,14 +90,11 @@ unsigned long syncRTCInterval = 1000; // To begin, sync RTC every second. Interv //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -// These globals are updated regularly via the storePVTdata callback -unsigned long gnssPVTArrivalMillis = 0; -bool gnssPVTUpdated = false; +// These globals are updated regularly via the SBF parser + +// ReceiverTime 5914 unsigned long gnssTimeArrivalMillis = 0; bool gnssTimeUpdated[2] = { false, false }; // RTC, TCXO -double gnssLatitude_d = 0.0; -double gnssLongitude_d = 0.0; -float gnssAltitude_m = 0.0; uint32_t gnssTOW_ms = 0; uint8_t gnssDay = 0; uint8_t gnssMonth = 0; @@ -105,14 +102,43 @@ uint16_t gnssYear = 0; uint8_t gnssHour = 0; uint8_t gnssMinute = 0; uint8_t gnssSecond = 0; -uint8_t gnssTimeSys = 255; // Unknown -uint8_t gnssError = 255; // Unknown bool gnssWNSet = false; bool gnssToWSet = false; bool gnssFineTime = false; + +// PVTGeodetic 4007 +unsigned long gnssPVTArrivalMillis = 0; +bool gnssPVTUpdated = false; +double gnssLatitude_d = 0.0; +double gnssLongitude_d = 0.0; +float gnssAltitude_m = 0.0; +uint8_t gnssTimeSys = 255; // Unknown +uint8_t gnssError = 255; // Unknown double gnssClockBias_ms = 0.0; + +// IPStatus 4058 IPAddress gnssIP = IPAddress((uint32_t)0); +// FugroTimeOffset 4255 +typedef struct { + const uint8_t TimeSystem; + const char name[8]; + double RxClkBias_ms; + bool updated; +} fugroClkBias; +fugroClkBias fugroClkBiases[] = { + { 0, "GPS", 0.0, false }, + { 1, "Galileo", 0.0, false }, + { 3, "GLONASS", 0.0, false }, + { 4, "BeiDou", 0.0, false }, + { 5, "QZSS", 0.0, false }, + { 100, "Fugro", 0.0, false }, +}; +#define NUM_FUGRO_CLK_BIASES (sizeof(fugroClkBiases) / sizeof(fugroClkBias)) + +double tcxoClockBias_ms; // Updated by updateTCXOClockBias +char rxClkBiasSource[8]; // PVT or Fugro or Galileo + //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // GPS parse table @@ -235,7 +261,6 @@ uint16_t failedParserMessages_SBF = 0; bool rtcSyncd = false; // Set to true when the RTC has been sync'd bool ppsStarted = false; // Set to true when PPS have started. Cleared by menu changes. -int tcxoUpdates = 0; // Keep count of TCXO control word updates. Save the control word every hour //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- @@ -264,7 +289,7 @@ volatile bool deadManWalking; settings.enableHeapReport = true; \ settings.enableTaskReports = true; \ settings.enablePrintState = true; \ - settings.enablePrintConditions = 1; \ + settings.enablePrintConditions = 2; \ settings.enablePrintIdleTime = true; \ settings.enablePrintBadMessages = true; \ settings.enablePrintRingBufferOffsets = true; \ diff --git a/Firmware/RTK_mosaic-T_Firmware/States.ino b/Firmware/RTK_mosaic-T_Firmware/States.ino index ec2f929..4614b51 100644 --- a/Firmware/RTK_mosaic-T_Firmware/States.ino +++ b/Firmware/RTK_mosaic-T_Firmware/States.ino @@ -89,26 +89,54 @@ void updateSystemState() { gnssPVTUpdated = false; - updateLockLED(); + updateTCXOClockBias(); // Update the tcxoClockBias_ms from the best source + + updateLockLED(); // Update Lock LED based on tcxoClockBias_ms updateErrorLED(); + static uint8_t clkBiasLimitCount = 0; + // If the clock bias is < the lock limit, start PPS - if ((fabs(gnssClockBias_ms) < settings.rxClkBiasLockLimit_ms) - && !ppsStarted && !gnssError) + if (fabs(tcxoClockBias_ms) < settings.rxClkBiasLockLimit_ms) { - if (configureGNSSPPS()) + if (clkBiasLimitCount < settings.rxClkBiasLimitCount) + clkBiasLimitCount++; + if (!ppsStarted && !gnssError && (clkBiasLimitCount >= settings.rxClkBiasLimitCount) && configureGNSSPPS()) + { ppsStarted = true; + } + } + else + { + clkBiasLimitCount = 0; } - if (gnssError) - changeState(STATE_GNSS_ERROR_AFTER_FINETIME); - } - else if (gnssTimeUpdated[1]) // Wait for the time to be updated - { - gnssTimeUpdated[1] = false; + static uint8_t badBiasCount = 0; + + // If the clock bias is > rxClkBiasInitialLimit_ms, reinitialize + if (fabs(tcxoClockBias_ms) > settings.rxClkBiasInitialLimit_ms) + { + if (badBiasCount < settings.rxClkBiasLimitCount) + badBiasCount++; + if (badBiasCount >= settings.rxClkBiasLimitCount) + { + clkBiasLimitCount = 0; // Reset the counts before changing state + badBiasCount = 0; + displayBadBias(1000); + setTimingSystem(); // Kickstart the timing system + changeState(STATE_GNSS_CONFIGURED); + } + } + else + { + badBiasCount = 0; + } - // The message rate limits this to 1Hz - updateTCXO(); + // Update the TCXO if the bias is OK. The message rate limits this to 1Hz + if (badBiasCount == 0) + updateTCXO(); + + static int tcxoUpdates = 0; // Keep count of TCXO control word updates. Save the control word every hour if (ppsStarted) { @@ -126,7 +154,18 @@ void updateSystemState() } } else + { tcxoUpdates = 0; + } + + // Change state on error - stop updating the TCXO + if (gnssError) + { + clkBiasLimitCount = 0; // Reset the counts before changing state + badBiasCount = 0; + tcxoUpdates = 0; + changeState(STATE_GNSS_ERROR_AFTER_FINETIME); + } } } break; diff --git a/Firmware/RTK_mosaic-T_Firmware/Tasks.ino b/Firmware/RTK_mosaic-T_Firmware/Tasks.ino index 92df88f..a0ce7ff 100644 --- a/Firmware/RTK_mosaic-T_Firmware/Tasks.ino +++ b/Firmware/RTK_mosaic-T_Firmware/Tasks.ino @@ -661,6 +661,35 @@ void processConsumerMessage(PARSE_STATE *parse, uint8_t type) theIP |= ((uint32_t)parse->buffer[35]) << 24; gnssIP = IPAddress(theIP); } + else if ((parse->message & 0x1FFF) == 4255) // FugroTimeOffset + { + int N = parse->buffer[14]; // Number of FugroTOSub sub-blocks in this block + int SBLength = parse->buffer[15]; // Length of a FugroTOSub sub-block + + for (int b = 0; b < N; b++) // For each block + { + uint8_t TimeSystem = parse->buffer[20 + (b * SBLength) + 2]; + + union { + double dbl; + uint64_t unsigned64; + } dblUnsigned64; + + dblUnsigned64.unsigned64 = 0; + for (int i = 0; i < 8; i++) + dblUnsigned64.unsigned64 |= ((uint64_t)parse->buffer[20 + (b * SBLength) + 4 + i]) << (i * 8); + + for (int TS = 0; TS < NUM_FUGRO_CLK_BIASES; TS++) + { + if (fugroClkBiases[TS].TimeSystem == TimeSystem) + { + fugroClkBiases[TS].RxClkBias_ms = dblUnsigned64.dbl; + fugroClkBiases[TS].updated = true; + break; + } + } + } + } } } diff --git a/Firmware/RTK_mosaic-T_Firmware/menuSystem.ino b/Firmware/RTK_mosaic-T_Firmware/menuSystem.ino index 27c1de2..1957bc7 100644 --- a/Firmware/RTK_mosaic-T_Firmware/menuSystem.ino +++ b/Firmware/RTK_mosaic-T_Firmware/menuSystem.ino @@ -361,30 +361,36 @@ void menuOperation() systemPrint("1) RX Clock Bias Lock Limit (ms): "); systemPrintf("%.3e\r\n", settings.rxClkBiasLockLimit_ms); - systemPrint("2) Pulse-Per-Second Interval: "); + systemPrint("2) RX Clock Bias Initial Limit (ms): "); + systemPrintf("%.3e\r\n", settings.rxClkBiasInitialLimit_ms); + + systemPrint("3) RX Clock Bias Limit Count: "); + systemPrintf("%d\r\n", settings.rxClkBiasLimitCount); + + systemPrint("4) Pk (PI P term): "); + systemPrintf("%.3e\r\n", settings.Pk); + + systemPrint("5) Ik (PI I term): "); + systemPrintf("%.3e\r\n", settings.Ik); + + systemPrint("6) Pulse-Per-Second Interval: "); systemPrintln(mosaicPPSParametersInterval[settings.ppsInterval]); - systemPrint("3) Pulse-Per-Second Polarity: "); + systemPrint("7) Pulse-Per-Second Polarity: "); systemPrintln(mosaicPPSParametersPolarity[settings.ppsPolarity]); - systemPrint("4) Pulse-Per-Second Delay (ns): "); + systemPrint("8) Pulse-Per-Second Delay (ns): "); systemPrintln(settings.ppsDelay_ns); - systemPrint("5) Pulse-Per-Second Time Scale: "); + systemPrint("9) Pulse-Per-Second Time Scale: "); systemPrintln(mosaicPPSParametersTimeScale[settings.ppsTimeScale]); - systemPrint("6) Pulse-Per-Second Max Sync Age (s): "); + systemPrint("10) Pulse-Per-Second Max Sync Age (s): "); systemPrintln(settings.ppsMaxSyncAge_s); - systemPrint("7) Pulse-Per-Second Pulse Width (ms): "); + systemPrint("11) Pulse-Per-Second Pulse Width (ms): "); systemPrintln(settings.ppsPulseWidth_ms); - systemPrint("8) Pk (PI P term): "); - systemPrintf("%.3e\r\n", settings.Pk); - - systemPrint("9) Ik (PI I term): "); - systemPrintf("%.3e\r\n", settings.Ik); - systemPrintln("\r\nx) Exit"); byte incoming = getCharacterNumber(); @@ -392,30 +398,79 @@ void menuOperation() if (incoming == 1) { systemPrint("Enter RX Clock Bias Lock Limit in milliseconds: "); - double lockLimit = getDouble(); - if (lockLimit <= 0.0 || lockLimit >= 1000.0) // Arbitrary 1s limit + double limit = getDouble(); + if (limit <= 0.0 || limit >= 1000.0) // Arbitrary 1s limit systemPrintln("Error: Lock Limit is out of range"); else { - settings.rxClkBiasLockLimit_ms = lockLimit; // Recorded to NVM at main menu exit - ppsStarted = false; // Restart PPS afterwards + settings.rxClkBiasLockLimit_ms = limit; // Recorded to NVM at main menu exit } } else if (incoming == 2) + { + systemPrint("Enter RX Clock Bias Initial Limit in milliseconds: "); + double limit = getDouble(); + if (limit <= 0.0 || limit >= 1000.0) // Arbitrary 1s limit + systemPrintln("Error: Initial Limit is out of range"); + else + { + settings.rxClkBiasInitialLimit_ms = limit; // Recorded to NVM at main menu exit + } + } + else if (incoming == 3) + { + systemPrint("Enter the RX Clock Bias Limit Count: "); + int count = getNumber(); // Returns EXIT, TIMEOUT, or long + if ((count != INPUT_RESPONSE_GETNUMBER_EXIT) && + (count != INPUT_RESPONSE_GETNUMBER_TIMEOUT)) + { + if (count < 1 || count > 3600) + systemPrintln("Error: Count is out of range"); + else + { + settings.rxClkBiasLimitCount = count; + } + } + } + else if (incoming == 4) + { + systemPrint("Enter the PI P term: "); + double p = getDouble(); + if (p <= 0.0 || p >= 10.0) // Arbitrary limits + systemPrintln("Error: term is out of range"); + else + { + settings.Pk = p; // Recorded to NVM at main menu exit + ppsStarted = false; // Restart PPS afterwards + } + } + else if (incoming == 5) + { + systemPrint("Enter the PI I term: "); + double i = getDouble(); + if (i < 0.0 || i >= 10.0) // Arbitrary limits + systemPrintln("Error: term is out of range"); + else + { + settings.Ik = i; // Recorded to NVM at main menu exit + ppsStarted = false; // Restart PPS afterwards + } + } + else if (incoming == 6) { settings.ppsInterval++; if ((settings.ppsInterval >= mosaicPPSParametersIntervalEntries) || (settings.ppsInterval < 0)) settings.ppsInterval = 0; ppsStarted = false; // Restart PPS afterwards } - else if (incoming == 3) + else if (incoming == 7) { settings.ppsPolarity++; if ((settings.ppsPolarity >= mosaicPPSParametersPolarityEntries) || (settings.ppsPolarity < 0)) settings.ppsPolarity = 0; ppsStarted = false; // Restart PPS afterwards } - else if (incoming == 4) + else if (incoming == 8) { systemPrint("Enter Pulse-Per-Second Delay in nanoseconds: "); double dly = getDouble(); @@ -427,14 +482,14 @@ void menuOperation() ppsStarted = false; // Restart PPS afterwards } } - else if (incoming == 5) + else if (incoming == 9) { settings.ppsTimeScale++; if ((settings.ppsTimeScale >= mosaicPPSParametersTimeScaleEntries) || (settings.ppsTimeScale < 0)) settings.ppsPolarity = 0; ppsStarted = false; // Restart PPS afterwards } - else if (incoming == 6) + else if (incoming == 10) { systemPrint("Enter Max Sync Age in seconds (0 to 3600): "); int syncAge = getNumber(); // Returns EXIT, TIMEOUT, or long @@ -450,7 +505,7 @@ void menuOperation() } } } - else if (incoming == 7) + else if (incoming == 11) { systemPrint("Enter Pulse Width in milliseconds: "); double width = getDouble(); @@ -462,30 +517,6 @@ void menuOperation() ppsStarted = false; // Restart PPS afterwards } } - else if (incoming == 8) - { - systemPrint("Enter the PI P term: "); - double p = getDouble(); - if (p <= 0.0 || p >= 10.0) // Arbitrary limits - systemPrintln("Error: term is out of range"); - else - { - settings.Pk = p; // Recorded to NVM at main menu exit - ppsStarted = false; // Restart PPS afterwards - } - } - else if (incoming == 9) - { - systemPrint("Enter the PI I term: "); - double i = getDouble(); - if (i < 0.0 || i >= 10.0) // Arbitrary limits - systemPrintln("Error: term is out of range"); - else - { - settings.Ik = i; // Recorded to NVM at main menu exit - ppsStarted = false; // Restart PPS afterwards - } - } // Menu exit control else if (incoming == 'x') break; @@ -511,14 +542,17 @@ void printCurrentConditions(bool CSV) { if (firstTime) { - systemPrintln("YYYY/MM/DD,HH:MM:SS,TOW(ms),Lat,Lon,Alt,TimeSys,Error,Fine,PPS,Bias,TCXO,Pk,Ik"); + systemPrintln("YYYY/MM/DD,HH:MM:SS,Epoch,Lat,Lon,Alt,TimeSys,Error,Fine,PPS,Bias,Source,TCXO,Pk,Ik"); firstTime = false; } systemPrintf("%04d/%02d/%02d,%02d:%02d:%02d", gnssYear, gnssMonth, gnssDay, gnssHour, gnssMinute, gnssSecond); - systemPrintf(",%lu", gnssTOW_ms); + uint32_t epochSecs; + uint32_t epochMillis; + convertGnssTimeToEpoch(&epochSecs, &epochMillis); + systemPrintf(",%lu.%03lu", epochSecs, epochMillis); systemPrint(","); systemPrint(gnssLatitude_d, 7); @@ -541,7 +575,10 @@ void printCurrentConditions(bool CSV) systemPrint(","); systemPrint(ppsStarted); - systemPrintf(",%.3e", gnssClockBias_ms / 1000.0); // Display clock bias in seconds + systemPrintf(",%.3e", tcxoClockBias_ms / 1000.0); // Display clock bias in seconds + + systemPrint(","); + systemPrint((const char *)rxClkBiasSource), systemPrintf(",%ld", myTCXO.getFrequencyControlWord()); @@ -579,15 +616,18 @@ void printCurrentConditions(bool CSV) systemPrint(", PPS: "); systemPrint(ppsStarted ? "On" : "Off"); - if ((gnssClockBias_ms >= 1.0) || (gnssClockBias_ms <= -1.0)) + if ((tcxoClockBias_ms >= 1.0) || (tcxoClockBias_ms <= -1.0)) systemPrintf(", Bias: %.3fms", - (float)gnssClockBias_ms); - else if ((gnssClockBias_ms >= 0.001) || (gnssClockBias_ms <= -0.001)) + (float)tcxoClockBias_ms); + else if ((tcxoClockBias_ms >= 0.001) || (tcxoClockBias_ms <= -0.001)) systemPrintf(", Bias: %.3fus", - (float)(gnssClockBias_ms * 1000.0)); + (float)(tcxoClockBias_ms * 1000.0)); else systemPrintf(", Bias: %.3fns", - (float)(gnssClockBias_ms * 1000000.0)); + (float)(tcxoClockBias_ms * 1000000.0)); + + systemPrint(", Source: "); + systemPrint((const char *)rxClkBiasSource), systemPrint(", TCXO Control: "); systemPrint(myTCXO.getFrequencyControlWord()); diff --git a/Firmware/RTK_mosaic-T_Firmware/settings.h b/Firmware/RTK_mosaic-T_Firmware/settings.h index 00f1b7c..5121e3d 100644 --- a/Firmware/RTK_mosaic-T_Firmware/settings.h +++ b/Firmware/RTK_mosaic-T_Firmware/settings.h @@ -246,7 +246,9 @@ typedef struct float ppsPulseWidth_ms = 5.0; int32_t tcxoControl = 0; // Store the TCXO control word - to aid locking after power off + double rxClkBiasInitialLimit_ms = 1.0e-3; // Consider the clock bias 'bad' when > this many ms. Default: 1.0us (1.0e-3ms) double rxClkBiasLockLimit_ms = 10.0e-6; // Consider the clock locked when the bias is <= this many ms. Default: 10.0ns (10.0e-6ms) + int rxClkBiasLimitCount = 3; // Consider the clock locked when the bias is <= rxClkBiasLockLimit_ms for this many successive readings. Default: 3 double Pk = 0.25; // PI P term double Ik = 0.01; // PI I term