From b75f937603429fe5f591f102d118e3de1e3aaf9d Mon Sep 17 00:00:00 2001 From: PaulZC Date: Wed, 3 Jul 2024 16:55:08 +0100 Subject: [PATCH 01/10] Revamp MQTT_Client. Add localised distribution --- Firmware/RTK_Everywhere/MQTT_Client.ino | 316 ++++++++++++++++----- Firmware/RTK_Everywhere/RTK_Everywhere.ino | 1 + Firmware/RTK_Everywhere/menuPP.ino | 31 +- Firmware/RTK_Everywhere/settings.h | 18 ++ 4 files changed, 287 insertions(+), 79 deletions(-) diff --git a/Firmware/RTK_Everywhere/MQTT_Client.ino b/Firmware/RTK_Everywhere/MQTT_Client.ino index e2ef52f87..e2b63f1a0 100644 --- a/Firmware/RTK_Everywhere/MQTT_Client.ino +++ b/Firmware/RTK_Everywhere/MQTT_Client.ino @@ -60,19 +60,16 @@ MQTT_Client.ino ------------------------------------------------------------------------------*/ -// TODO -// We should restructure this. -// The hard-coded MQTT_CLIENT_SUBSCRIBE_KEY/SPARTN/ASSIST states are problematic. -// We should have a vector of topics to be subscribed to. -// Code will add/erase topics to/from the vector as needed. -// If the MQTT Client is OFF and it sees that the vector has at least one entry, -// the client starts, connects and subscribes. -// While connected and subscribed, the MQTT Client keeps checking the vector. -// Topics which are subscribed to but are no longer in the vector are unsubscribed. -// If the vector becomes empty, the MQTT Client disconnects and goes back to OFF. -// This would make it a lot easier to: only subscribe to the key topic when needed; -// subscribe to the localized distribution topic. See #150 -// (This is how Michael's hpg does it...) +// How this works: +// There are two vectors of topics: +// mqttSubscribeTopics contains the topics we should be subscribed to +// mqttClientSubscribedTopics contains the topics we are currently subscribed to +// While connected, the mqttClientUpdate state machine compares mqttClientSubscribedTopics to mqttSubscribeTopics +// New topics on mqttSubscribeTopics are subscribed to one at a time (one topic per call of mqttClientUpdate) +// Topics no longer on mqttSubscribeTopics are unsubscribed one at a time (one topic per call of mqttClientUpdate) +// Initially we subscribe to the key distribution topic and the continental correction topic (if available) +// If localised distribution is enabled and we have a 3D fix, we subscribe to the dict topic +// When the dict is received, we subscribe to the nearest localised topic and unsubscribe from the continental topic #ifdef COMPILE_MQTT_CLIENT @@ -94,9 +91,6 @@ enum MQTTClientState MQTT_CLIENT_ON, // WIFI_STATE_START state MQTT_CLIENT_NETWORK_STARTED, // Connecting to WiFi access point or Ethernet MQTT_CLIENT_CONNECTING_2_SERVER, // Connecting to the MQTT server - MQTT_CLIENT_SUBSCRIBE_KEY, // Subscribe to the MQTT_TOPIC_KEY - MQTT_CLIENT_SUBSCRIBE_SPARTN, // Subscribe to the MQTT_TOPIC_SPARTN - MQTT_CLIENT_SUBSCRIBE_ASSIST, // Subscribe to the MQTT_TOPIC_ASSISTNOW MQTT_CLIENT_SERVICES_CONNECTED, // Connected to the MQTT services // Insert new states here MQTT_CLIENT_STATE_MAX // Last entry in the state list @@ -107,9 +101,6 @@ const char *const mqttClientStateName[] = { "MQTT_CLIENT_ON", "MQTT_CLIENT_NETWORK_STARTED", "MQTT_CLIENT_CONNECTING_2_SERVER", - "MQTT_CLIENT_SUBSCRIBE_KEY", - "MQTT_CLIENT_SUBSCRIBE_SPARTN", - "MQTT_CLIENT_SUBSCRIBE_ASSIST", "MQTT_CLIENT_SERVICES_CONNECTED", }; @@ -119,11 +110,18 @@ const RtkMode_t mqttClientMode = RTK_MODE_ROVER | RTK_MODE_BASE_SURVEY_IN; const char MQTT_TOPIC_ASSISTNOW[] = "/pp/ubx/mga"; // AssistNow (MGA) topic // Note: the key and correction topics are now stored in settings - extracted from ZTP +const char localizedPrefix[] = "pp/ip/L"; // The localized distribution topic prefix. Note: starts with "pp", not "/pp" //---------------------------------------- // Locals //---------------------------------------- +std::vector mqttSubscribeTopics; // List of MQTT topics to be subscribed to +std::vector mqttClientSubscribedTopics; // List of topics currently subscribed to + +String localisedDistributionDictTopic = ""; +String localisedDistributionTileTopic = ""; + static MqttClient *mqttClient; static char *mqttClientCertificateBuffer = nullptr; // Buffer for client certificate @@ -225,9 +223,6 @@ void mqttClientPrintStateSummary() break; case MQTT_CLIENT_CONNECTING_2_SERVER: - case MQTT_CLIENT_SUBSCRIBE_KEY: - case MQTT_CLIENT_SUBSCRIBE_SPARTN: - case MQTT_CLIENT_SUBSCRIBE_ASSIST: systemPrint("Connecting"); break; @@ -289,7 +284,7 @@ void mqttClientPrintStatus() // Called when a subscribed message arrives void mqttClientReceiveMessage(int messageSize) { - const uint16_t mqttLimit = 2048; + const uint16_t mqttLimit = 26000; // The Level 3 localised distribution dictionary topic can be up to 25KB static uint8_t *mqttData = nullptr; // Allocate memory to hold the MQTT data. Never freed if (mqttData == nullptr) { @@ -325,8 +320,76 @@ void mqttClientReceiveMessage(int messageSize) if (mqttCount > 0) { + // Check for localisedDistributionDictTopic + if ((localisedDistributionDictTopic.length() > 0) + && (strcmp(topic, localisedDistributionDictTopic.c_str()) == 0)) + { + // We should be using a JSON library to read the nodes. But JSON is + // heavy on RAM and the dict could be 25KB for Level 3. + // Use sscanf instead. + // + // { + // "tile": "L2N5375W00125", + // "nodeprefix": "pp/ip/L2N5375W00125/", + // "nodes": [ + // "N5200W00300", + // "N5200W00200", + // "N5200W00100", + // "N5200E00000", + // "N5200E00100", + // "N5300W00300", + // "N5300W00200", + // "N5300W00100", + // "N5300E00000", + // "N5400W00200", + // "N5400W00100", + // "N5500W00300", + // "N5500W00200" + // ], + // "endpoint": "pp-eu.services.u-blox.com" + // } + char *nodes = strstr((const char *)mqttData, "\"nodes\":["); + if (nodes != nullptr) + { + nodes += strlen("\"nodes\":["); // Point to the first node + float minDist = 99999.0; // Minimum distance to tile center in centidegrees + char *preservedTile; + char *tile = strtok_r(nodes, ",", &preservedTile); + int latitude = int(gnssGetLatitude() * 100.0); // Centidegrees + int longitude = int(gnssGetLongitude() * 100.0); // Centidegrees + while (tile != nullptr) + { + char ns, ew; + int lat, lon; + if (sscanf(tile, "\"%c%d%c%d\"", &ns, &lat, &ew, &lon) == 4) + { + if (ns == 'S') + lat = 0 - lat; + if (ew == 'W') + lon = 0 - lon; + float factorLon = cos(radians(latitude / 100.0)); // Scale lon by the lat + float distScaled = pow(pow(lat - latitude, 2) + pow((lon - longitude) * factorLon, 2), 0.5); // Calculate distance to tile center in centidegrees + if (distScaled < minDist) + { + minDist = distScaled; + tile[12] = 0; // Convert the second quote to NULL for snprintf + char tileTopic[50]; + snprintf(tileTopic, sizeof(tileTopic), "%s", localisedDistributionDictTopic.c_str()); + snprintf(&tileTopic[strlen(localizedPrefix) + 13], sizeof(tileTopic) - (strlen(localizedPrefix) + 13), "%s", tile + 1); // Start after the first quote + localisedDistributionTileTopic = tileTopic; + } + } + tile = strtok_r(nullptr, ",", &preservedTile); + } + } + + mqttClientLastDataReceived = millis(); + break; // Break now - the dict topic should not be pushed + } + // Are these keys? If so, update our local copy - if (strstr(topic, settings.pointPerfectKeyDistributionTopic) != nullptr) + if ((strlen(settings.pointPerfectKeyDistributionTopic) > 0 ) + && (strcmp(topic, settings.pointPerfectKeyDistributionTopic) == 0)) { // Separate the UBX message into its constituent Key/ToW/Week parts uint8_t *payLoad = &mqttData[6]; @@ -389,7 +452,15 @@ void mqttClientReceiveMessage(int messageSize) if (present.gnss_zedf9p) { // Only push SPARTN if the priority says we can - if (strstr(topic, settings.regionalCorrectionTopics[settings.geographicRegion]) != nullptr) + if ( + // We can get correction data from the continental topic + ((strlen(settings.regionalCorrectionTopics[settings.geographicRegion]) > 0) + && (strcmp(topic, settings.regionalCorrectionTopics[settings.geographicRegion]) == 0)) + || + // Or from the localised distribution tile topic + ((localisedDistributionTileTopic.length() > 0) + && (strcmp(topic, localisedDistributionTileTopic.c_str()) == 0)) + ) { // SPARTN updateCorrectionsLastSeen(CORR_IP); @@ -581,6 +652,7 @@ void mqttClientUpdate() // Shutdown the MQTT client when the mode or setting changes DMW_st(mqttClientSetState, mqttClientState); + if (NEQ_RTK_MODE(mqttClientMode) || (!enableMqttClient)) { if (mqttClientState > MQTT_CLIENT_OFF) @@ -735,70 +807,31 @@ void mqttClientUpdate() // The MQTT server is now connected mqttClient->onMessage(mqttClientReceiveMessage); - reportHeapNow(settings.debugMqttClientState); - mqttClientSetState(MQTT_CLIENT_SUBSCRIBE_KEY); - break; - } + mqttSubscribeTopics.clear(); // Clear the list of MQTT topics to be subscribed to + mqttClientSubscribedTopics.clear(); // Clear the list of topics currently subscribed to + localisedDistributionDictTopic = ""; + localisedDistributionTileTopic = ""; - // Subscribe to the topic key - case MQTT_CLIENT_SUBSCRIBE_KEY: { - // Determine if the network has failed - if (networkIsShuttingDown(NETWORK_USER_MQTT_CLIENT)) - { - // Failed to connect to the network, attempt to restart the network - mqttClientStop(true); // Was mqttClientRestart(); - #StopVsRestart - break; - } - - // Subscribe to the key distribution topic. This is provided during ZTP - if (!mqttClient->subscribe(settings.pointPerfectKeyDistributionTopic)) - { - mqttClientRestart(); - systemPrintln("ERROR: Subscription to key distribution topic failed!!"); - //mqttClientRestart(); // Why twice? TODO - break; - } - - if (settings.debugMqttClientState) - systemPrintln("MQTT client subscribed to key distribution topic"); - - mqttClientSetState(MQTT_CLIENT_SUBSCRIBE_SPARTN); - break; - } - - // Subscribe to the topic SPARTN - case MQTT_CLIENT_SUBSCRIBE_SPARTN: { - // Determine if the network has failed - if (networkIsShuttingDown(NETWORK_USER_MQTT_CLIENT)) - { - // Failed to connect to the network, attempt to restart the network - mqttClientStop(true); // Was mqttClientRestart(); - #StopVsRestart - break; - } - - // Subscribe to the correction topic for our region - if we have one. L-Band-only does not. + // Subscribe to the key distribution topic + mqttSubscribeTopics.push_back(String(settings.pointPerfectKeyDistributionTopic)); + // Subscribe to the continental correction topic for our region - if we have one. L-Band-only does not. if (strlen(settings.regionalCorrectionTopics[settings.geographicRegion]) > 0) { - if (!mqttClient->subscribe(settings.regionalCorrectionTopics[settings.geographicRegion])) - { - mqttClientRestart(); - systemPrintln("ERROR: Subscription to corrections topic failed!!"); - //mqttClientRestart(); // Why twice? TODO - break; - } - - if (settings.debugMqttClientState) - systemPrintln("MQTT client subscribed to corrections topic"); + mqttSubscribeTopics.push_back(String(settings.regionalCorrectionTopics[settings.geographicRegion])); } else { if (settings.debugMqttClientState) systemPrintln("MQTT client - no corrections topic. Continuing..."); } + // Subscribing to the localized distribution dictionary and local tile is handled by MQTT_CLIENT_SERVICES_CONNECTED + // since we need a 3D fix for those + reportHeapNow(settings.debugMqttClientState); mqttClientSetState(MQTT_CLIENT_SERVICES_CONNECTED); + break; - } + } // /case MQTT_CLIENT_CONNECTING_2_SERVER case MQTT_CLIENT_SERVICES_CONNECTED: { // Determine if the network has failed @@ -817,9 +850,136 @@ void mqttClientUpdate() { systemPrintln("MQTT client data timeout. Disconnecting..."); mqttClientRestart(); + break; } + + // Check if there are any new topics that should be subscribed to + bool breakOut = false; + for (auto it = mqttSubscribeTopics.begin(); it != mqttSubscribeTopics.end(); it = std::next(it)) + { + String topic = *it; + std::vector::iterator pos = std::find(mqttClientSubscribedTopics.begin(), mqttClientSubscribedTopics.end(), topic); + if (pos == mqttClientSubscribedTopics.end()) // The mqttSubscribeTopics is not in mqttClientSubscribedTopics, so subscribe + { + if (settings.debugMqttClientState) + systemPrintf("MQTT_Client subscribing to topic %s\r\n", topic.c_str()); + if (mqttClient->subscribe(topic.c_str())) + { + breakOut = true; // Break out of this state as we have successfully subscribed + mqttClientSubscribedTopics.push_back(topic); + } + else + { + mqttClientRestart(); + if (settings.debugMqttClientState) + systemPrintf("MQTT_Client subscription to topic %s failed. Restarting\r\n", topic.c_str()); + breakOut = true; // Break out of this state as the subscribe failed and a restart is needed + } + } + if (breakOut) + break; // Break out of the first for loop + } + if (breakOut) + break; // Break out of this state + + // Check if there are any obsolete topics that should be unsubscribed + for (auto it = mqttClientSubscribedTopics.begin(); it != mqttClientSubscribedTopics.end(); it = std::next(it)) + { + String topic = *it; + std::vector::iterator pos = std::find(mqttSubscribeTopics.begin(), mqttSubscribeTopics.end(), topic); + if (pos == mqttSubscribeTopics.end()) // The mqttClientSubscribedTopics is not in mqttSubscribeTopics, so unsubscribe + { + if (settings.debugMqttClientState) + systemPrintf("MQTT_Client unsubscribing from topic %s\r\n", topic.c_str()); + if (mqttClient->unsubscribe(topic.c_str())) + { + breakOut = true; // Break out of this state as we have successfully unsubscribed + mqttClientSubscribedTopics.erase(it); + } + else + { + mqttClientRestart(); + if (settings.debugMqttClientState) + systemPrintf("MQTT_Client unsubscribe from topic %s failed. Restarting\r\n", topic.c_str()); + breakOut = true; // Break out of this state as the subscribe failed and a restart is needed + } + } + if (breakOut) + break; // Break out of the first for loop + } + if (breakOut) + break; // Break out of this state + + // Check if localised distribution is enabled + if ((strlen(settings.regionalCorrectionTopics[settings.geographicRegion]) > 0) && (settings.useLocalisedDistribution)) + { + uint8_t fixType = gnssGetFixType(); + double latitude = gnssGetLatitude(); // degrees + double longitude = gnssGetLongitude(); // degrees + if (fixType >= 3) // If we have a 3D fix + { + // If both the dict and tile topics are empty, prepare to subscribe to the dict topic + if ((localisedDistributionDictTopic.length() == 0) && (localisedDistributionTileTopic.length() == 0)) + { + float tileDelta = 2.5; // 2.5 degrees (10 degrees and 5 degrees are also possible) + if ((settings.localisedDistributionTileLevel == 0) || (settings.localisedDistributionTileLevel == 3)) + tileDelta = 10.0; + if ((settings.localisedDistributionTileLevel == 1) || (settings.localisedDistributionTileLevel == 4)) + tileDelta = 5.0; + + float lat = latitude; // Degrees + lat = floor(lat / tileDelta) * tileDelta; // Calculate the tile center in degrees + lat += tileDelta / 2.0; + int lat_i = round(lat * 100.0); // integer centidegrees + + float lon = longitude; // Degrees + lon = floor(lon / tileDelta) * tileDelta; // Calculate the tile center in degrees + lon += tileDelta / 2.0; + int lon_i = round(lon * 100.0); // integer centidegrees + + char dictTopic[50]; + snprintf(dictTopic, sizeof(dictTopic), "%s%c%c%04d%c%05d/dict", + localizedPrefix, char(0x30 + settings.localisedDistributionTileLevel), + (lat_i < 0) ? 'S' : 'N', abs(lat_i), + (lon_i < 0) ? 'W' : 'E', abs(lon_i)); + + + localisedDistributionDictTopic = dictTopic; + mqttSubscribeTopics.push_back(localisedDistributionDictTopic); + + breakOut = true; + } + + // localisedDistributionTileTopic is populated by mqttClientReceiveMessage + // If both the dict and tile topics are populated, prepare to subscribe to the localised tile topic + // Empty localisedDistributionDictTopic afterwardds to prevent this state being repeated + if ((localisedDistributionDictTopic.length() > 0) && (localisedDistributionTileTopic.length() > 0)) + { + // Subscribe to the localisedDistributionTileTopic + mqttSubscribeTopics.push_back(localisedDistributionTileTopic); + // Unsubscribe from the localisedDistributionDictTopic + std::vector::iterator pos = std::find(mqttSubscribeTopics.begin(), mqttSubscribeTopics.end(), localisedDistributionDictTopic); + if (pos != mqttSubscribeTopics.end()) + mqttSubscribeTopics.erase(pos); + // Unsubscribe from the continental corrections + pos = std::find(mqttSubscribeTopics.begin(), mqttSubscribeTopics.end(), String(settings.regionalCorrectionTopics[settings.geographicRegion])); + if (pos != mqttSubscribeTopics.end()) + mqttSubscribeTopics.erase(pos); + + localisedDistributionDictTopic = ""; // Empty localisedDistributionDictTopic to prevent this state being repeated + breakOut = true; + } + + + } + } + if (breakOut) + break; // Break out of this state + + + // Add any new state checking above this line break; - } + } // /case MQTT_CLIENT_SERVICES_CONNECTED } // Periodically display the MQTT client state diff --git a/Firmware/RTK_Everywhere/RTK_Everywhere.ino b/Firmware/RTK_Everywhere/RTK_Everywhere.ino index ac08aa92b..60ecb7b6a 100644 --- a/Firmware/RTK_Everywhere/RTK_Everywhere.ino +++ b/Firmware/RTK_Everywhere/RTK_Everywhere.ino @@ -816,6 +816,7 @@ int commandCount; int16_t *commandIndex; volatile bool forceKeyAttempt = false; // Set to true to force a key provisioning attempt + //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- // Display boot times diff --git a/Firmware/RTK_Everywhere/menuPP.ino b/Firmware/RTK_Everywhere/menuPP.ino index 903257014..851357976 100644 --- a/Firmware/RTK_Everywhere/menuPP.ino +++ b/Firmware/RTK_Everywhere/menuPP.ino @@ -911,6 +911,12 @@ void menuPointPerfect() else systemPrintln("No keys"); + if ((settings.useLocalisedDistribution) && (localisedDistributionTileTopic.length() > 0)) + { + systemPrint("Most recent localised distribution topic: "); + systemPrintln(localisedDistributionTileTopic.c_str()); // From MQTT_Client.ino + } + // How this works: // There are three PointPerfect corrections plans: IP-only, L-Band-only, L-Band+IP // For IP-only - e.g. Torch: @@ -956,6 +962,19 @@ void menuPointPerfect() systemPrintln("Requested"); else systemPrintln("Not requested"); + systemPrint("4) Use localised distribution: "); + if (settings.useLocalisedDistribution == true) + systemPrintln("Enabled"); + else + systemPrintln("Disabled"); + if (settings.useLocalisedDistribution) + { + systemPrint("5) Localised distribution tile level: "); + systemPrint(settings.localisedDistributionTileLevel); + systemPrint(" ("); + systemPrint(localisedDistributionTileLevelNames[settings.localisedDistributionTileLevel]); + systemPrintln(")"); + } #endif // COMPILE_NETWORK systemPrintln("c) Clear the Keys"); @@ -987,7 +1006,17 @@ void menuPointPerfect() } else if (incoming == 3 && pointPerfectIsEnabled()) { - forceKeyAttempt ^= 1; + forceKeyAttempt = forceKeyAttempt ^ 1; + } + else if (incoming == 4 && pointPerfectIsEnabled()) + { + settings.useLocalisedDistribution ^= 1; + } + else if (incoming == 5 && pointPerfectIsEnabled() && settings.useLocalisedDistribution) + { + settings.localisedDistributionTileLevel++; + if (settings.localisedDistributionTileLevel >= LOCALISED_DISTRIBUTION_TILE_LEVELS) + settings.localisedDistributionTileLevel = 0; } #endif // COMPILE_NETWORK else if (incoming == 'c' && pointPerfectIsEnabled()) diff --git a/Firmware/RTK_Everywhere/settings.h b/Firmware/RTK_Everywhere/settings.h index d36e08d07..e35e40b78 100644 --- a/Firmware/RTK_Everywhere/settings.h +++ b/Firmware/RTK_Everywhere/settings.h @@ -1369,10 +1369,24 @@ struct Settings bool outputTipAltitude = false; // If enabled, subtract the pole length and APC from the GNSS receiver's reported altitude + // Localised distribution + bool useLocalisedDistribution = false; + uint8_t localisedDistributionTileLevel = 5; + // Add new settings to appropriate group above or create new group // Then also add to the same group in rtkSettingsEntries below } settings; +const uint8_t LOCALISED_DISTRIBUTION_TILE_LEVELS = 6; +const char *localisedDistributionTileLevelNames[LOCALISED_DISTRIBUTION_TILE_LEVELS] = { + "1000 x 1000km sparse", + "500 x 500km sparse", + "250 x 250km sparse", + "1000 x 1000km high density", + "500 x 500km high density", + "250 x 250km high density", +}; + typedef enum { _bool = 0, _int, @@ -1863,6 +1877,10 @@ const RTK_Settings_Entry rtkSettingsEntries[] = { 0, 0, 1, 0, 1, 1, 1, 1, _uint32_t, 0, & settings.outputTipAltitude, "outputTipAltitude", }, + // Localised distribution + { 0, 1, 1, 0, 1, 1, 1, 1, _bool, 0, & settings.useLocalisedDistribution, "useLocalisedDistribution", }, + { 0, 1, 1, 0, 1, 1, 1, 1, _uint8_t, 0, & settings.localisedDistributionTileLevel, "localisedDistributionTileLevel", }, + // Add new settings to appropriate group above or create new group // Then also add to the same group in settings above // F From 55daec655d70d34c1f5739d2d3689d9b24c8f220 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Thu, 4 Jul 2024 10:55:20 +0100 Subject: [PATCH 02/10] Add support for AssistNow --- Firmware/RTK_Everywhere/MQTT_Client.ino | 34 ++++++++++++++++++++++--- Firmware/RTK_Everywhere/menuPP.ino | 12 +++++++++ Firmware/RTK_Everywhere/settings.h | 2 ++ 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/Firmware/RTK_Everywhere/MQTT_Client.ino b/Firmware/RTK_Everywhere/MQTT_Client.ino index e2b63f1a0..19543549a 100644 --- a/Firmware/RTK_Everywhere/MQTT_Client.ino +++ b/Firmware/RTK_Everywhere/MQTT_Client.ino @@ -66,10 +66,14 @@ MQTT_Client.ino // mqttClientSubscribedTopics contains the topics we are currently subscribed to // While connected, the mqttClientUpdate state machine compares mqttClientSubscribedTopics to mqttSubscribeTopics // New topics on mqttSubscribeTopics are subscribed to one at a time (one topic per call of mqttClientUpdate) +// (this will make things easier for cellular - the LARA-R6 can only subscribe to one topic at once) // Topics no longer on mqttSubscribeTopics are unsubscribed one at a time (one topic per call of mqttClientUpdate) +// (ditto) // Initially we subscribe to the key distribution topic and the continental correction topic (if available) +// If enabled, we also subscribe to the AssistNow MGA topic // If localised distribution is enabled and we have a 3D fix, we subscribe to the dict topic // When the dict is received, we subscribe to the nearest localised topic and unsubscribe from the continental topic +// When the AssistNow MGA data arrives, we unsubscribe and subscribe to AssistNow updates #ifdef COMPILE_MQTT_CLIENT @@ -108,7 +112,8 @@ const int mqttClientStateNameEntries = sizeof(mqttClientStateName) / sizeof(mqtt const RtkMode_t mqttClientMode = RTK_MODE_ROVER | RTK_MODE_BASE_SURVEY_IN; -const char MQTT_TOPIC_ASSISTNOW[] = "/pp/ubx/mga"; // AssistNow (MGA) topic +const String MQTT_TOPIC_ASSISTNOW = "/pp/ubx/mga"; // AssistNow (MGA) topic +const String MQTT_TOPIC_ASSISTNOW_UPDATES = "/pp/ubx/mga/updates"; // AssistNow (MGA) topic - updates only // Note: the key and correction topics are now stored in settings - extracted from ZTP const char localizedPrefix[] = "pp/ip/L"; // The localized distribution topic prefix. Note: starts with "pp", not "/pp" @@ -284,9 +289,11 @@ void mqttClientPrintStatus() // Called when a subscribed message arrives void mqttClientReceiveMessage(int messageSize) { - const uint16_t mqttLimit = 26000; // The Level 3 localised distribution dictionary topic can be up to 25KB - static uint8_t *mqttData = nullptr; // Allocate memory to hold the MQTT data. Never freed - if (mqttData == nullptr) + // The Level 3 localised distribution dictionary topic can be up to 25KB + // The full AssistNow (MGA) topic can be ~11KB + const uint16_t mqttLimit = 26000; + static uint8_t *mqttData = nullptr; + if (mqttData == nullptr) // Allocate memory to hold the MQTT data. Never freed { if (online.psram == true) mqttData = (uint8_t *)ps_malloc(mqttLimit); @@ -387,6 +394,16 @@ void mqttClientReceiveMessage(int messageSize) break; // Break now - the dict topic should not be pushed } + // Is this the full AssistNow MGA data? If so, unsubscribe and subscribe to updates + if (strcmp(topic, MQTT_TOPIC_ASSISTNOW.c_str()) == 0) + { + std::vector::iterator pos = std::find(mqttSubscribeTopics.begin(), mqttSubscribeTopics.end(), MQTT_TOPIC_ASSISTNOW); + if (pos != mqttSubscribeTopics.end()) + mqttSubscribeTopics.erase(pos); + + mqttSubscribeTopics.push_back(MQTT_TOPIC_ASSISTNOW_UPDATES); + } + // Are these keys? If so, update our local copy if ((strlen(settings.pointPerfectKeyDistributionTopic) > 0 ) && (strcmp(topic, settings.pointPerfectKeyDistributionTopic) == 0)) @@ -487,6 +504,10 @@ void mqttClientReceiveMessage(int messageSize) else { // KEYS or MGA + if (((settings.debugMqttClientData == true) || (settings.debugCorrections == true)) && + !inMainMenu) + systemPrintf("Pushing %d bytes from %s topic to GNSS\r\n", mqttCount, topic); + gnssPushRawData(mqttData, mqttCount); bytesPushed += mqttCount; } @@ -812,6 +833,11 @@ void mqttClientUpdate() localisedDistributionDictTopic = ""; localisedDistributionTileTopic = ""; + // Subscribe to AssistNow MGA if enabled + if (settings.useAssistNow) + { + mqttSubscribeTopics.push_back(MQTT_TOPIC_ASSISTNOW); + } // Subscribe to the key distribution topic mqttSubscribeTopics.push_back(String(settings.pointPerfectKeyDistributionTopic)); // Subscribe to the continental correction topic for our region - if we have one. L-Band-only does not. diff --git a/Firmware/RTK_Everywhere/menuPP.ino b/Firmware/RTK_Everywhere/menuPP.ino index 851357976..374a0c55d 100644 --- a/Firmware/RTK_Everywhere/menuPP.ino +++ b/Firmware/RTK_Everywhere/menuPP.ino @@ -975,6 +975,14 @@ void menuPointPerfect() systemPrint(localisedDistributionTileLevelNames[settings.localisedDistributionTileLevel]); systemPrintln(")"); } + if (productVariant != RTK_FACET_MOSAIC) + { + systemPrint("a) Use AssistNow: "); + if (settings.useAssistNow == true) + systemPrintln("Enabled"); + else + systemPrintln("Disabled"); + } #endif // COMPILE_NETWORK systemPrintln("c) Clear the Keys"); @@ -1018,6 +1026,10 @@ void menuPointPerfect() if (settings.localisedDistributionTileLevel >= LOCALISED_DISTRIBUTION_TILE_LEVELS) settings.localisedDistributionTileLevel = 0; } + else if (incoming == 'a' && pointPerfectIsEnabled() && (productVariant != RTK_FACET_MOSAIC)) + { + settings.useAssistNow ^= 1; + } #endif // COMPILE_NETWORK else if (incoming == 'c' && pointPerfectIsEnabled()) { diff --git a/Firmware/RTK_Everywhere/settings.h b/Firmware/RTK_Everywhere/settings.h index e35e40b78..c7b1cc2cb 100644 --- a/Firmware/RTK_Everywhere/settings.h +++ b/Firmware/RTK_Everywhere/settings.h @@ -1372,6 +1372,7 @@ struct Settings // Localised distribution bool useLocalisedDistribution = false; uint8_t localisedDistributionTileLevel = 5; + bool useAssistNow = false; // Add new settings to appropriate group above or create new group // Then also add to the same group in rtkSettingsEntries below @@ -1880,6 +1881,7 @@ const RTK_Settings_Entry rtkSettingsEntries[] = // Localised distribution { 0, 1, 1, 0, 1, 1, 1, 1, _bool, 0, & settings.useLocalisedDistribution, "useLocalisedDistribution", }, { 0, 1, 1, 0, 1, 1, 1, 1, _uint8_t, 0, & settings.localisedDistributionTileLevel, "localisedDistributionTileLevel", }, + { 0, 1, 1, 0, 1, 1, 0, 1, _bool, 0, & settings.useAssistNow, "useAssistNow", }, // Add new settings to appropriate group above or create new group // Then also add to the same group in settings above From 157b9d534069f675ac5e366d18784eaeb1c193dd Mon Sep 17 00:00:00 2001 From: PaulZC Date: Thu, 4 Jul 2024 11:44:20 +0100 Subject: [PATCH 03/10] Add web config support for localised distribution and AssistNow --- Firmware/RTK_Everywhere/AP-Config/index.html | 39 +++++++++++++++++++ Firmware/RTK_Everywhere/AP-Config/src/main.js | 15 +++++++ 2 files changed, 54 insertions(+) diff --git a/Firmware/RTK_Everywhere/AP-Config/index.html b/Firmware/RTK_Everywhere/AP-Config/index.html index 2308b95e0..3d9f96999 100644 --- a/Firmware/RTK_Everywhere/AP-Config/index.html +++ b/Firmware/RTK_Everywhere/AP-Config/index.html @@ -1168,6 +1168,45 @@

+ +
+
+ + + + + +
+
+ +
+ + + + + +
+ +
+ + + + + +
+
+ + diff --git a/Firmware/RTK_Everywhere/AP-Config/src/main.js b/Firmware/RTK_Everywhere/AP-Config/src/main.js index c8e1c761a..ce516c4cc 100644 --- a/Firmware/RTK_Everywhere/AP-Config/src/main.js +++ b/Firmware/RTK_Everywhere/AP-Config/src/main.js @@ -108,6 +108,7 @@ function parseIncoming(msg) { hide("galileoHasSetting"); hide("tiltConfig"); hide("beeperControl"); + show("useAssistNowCheckbox"); } else if (platformPrefix == "Facet v2") { show("baseConfig"); @@ -120,6 +121,7 @@ function parseIncoming(msg) { hide("galileoHasSetting"); hide("tiltConfig"); hide("beeperControl"); + show("useAssistNowCheckbox"); } else if (platformPrefix == "Facet mosaic") { show("baseConfig"); @@ -131,6 +133,7 @@ function parseIncoming(msg) { show("logToSDCard"); hide("tiltConfig"); hide("beeperControl"); + hide("useAssistNowCheckbox"); } else if (platformPrefix == "Torch") { show("baseConfig"); @@ -146,6 +149,8 @@ function parseIncoming(msg) { hide("constellationSbas"); //Not supported on UM980 + show("useAssistNowCheckbox"); //Does the PPL use MGA? Not sure... + select = ge("dynamicModel"); let newOption = new Option('Survey', '0'); select.add(newOption, undefined); @@ -435,6 +440,7 @@ function parseIncoming(msg) { ge("enableARPLogging").dispatchEvent(new CustomEvent('change')); ge("enableAutoFirmwareUpdate").dispatchEvent(new CustomEvent('change')); ge("enableAutoReset").dispatchEvent(new CustomEvent('change')); + ge("useLocalisedDistribution").dispatchEvent(new CustomEvent('change')); updateECEFList(); updateGeodeticList(); @@ -1384,6 +1390,15 @@ document.addEventListener("DOMContentLoaded", (event) => { } }); + ge("useLocalisedDistribution").addEventListener("change", function () { + if (ge("useLocalisedDistribution").checked) { + show("localisedDistributionTileLevelDropdown"); + } + else { + hide("localisedDistributionTileLevelDropdown"); + } + }); + ge("enableExternalPulse").addEventListener("change", function () { if (ge("enableExternalPulse").checked == true) { show("externalPulseConfigDetails"); From b4aca7c479ee9ac79637c7657a210007da8ed6ec Mon Sep 17 00:00:00 2001 From: PaulZC Date: Thu, 4 Jul 2024 11:53:19 +0100 Subject: [PATCH 04/10] Fix duplicate form field --- Firmware/RTK_Everywhere/AP-Config/index.html | 30 ++++++------------- Firmware/RTK_Everywhere/AP-Config/src/main.js | 9 +++--- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/Firmware/RTK_Everywhere/AP-Config/index.html b/Firmware/RTK_Everywhere/AP-Config/index.html index 3d9f96999..7b23f823e 100644 --- a/Firmware/RTK_Everywhere/AP-Config/index.html +++ b/Firmware/RTK_Everywhere/AP-Config/index.html @@ -1348,29 +1348,17 @@ - -
- - - - - -
- -
-
- - - - - -
+ +
+ + + + +
diff --git a/Firmware/RTK_Everywhere/AP-Config/src/main.js b/Firmware/RTK_Everywhere/AP-Config/src/main.js index ce516c4cc..6599a09bc 100644 --- a/Firmware/RTK_Everywhere/AP-Config/src/main.js +++ b/Firmware/RTK_Everywhere/AP-Config/src/main.js @@ -103,7 +103,8 @@ function parseIncoming(msg) { show("ppConfig"); show("ethernetConfig"); show("ntpConfig"); - hide("portsConfig"); + show("portsConfig"); + hide("externalPortOptions"); show("logToSDCard"); hide("galileoHasSetting"); hide("tiltConfig"); @@ -116,7 +117,7 @@ function parseIncoming(msg) { hide("ethernetConfig"); hide("ntpConfig"); show("portsConfig"); - hide("noExternalPortOptions"); + show("externalPortOptions"); show("logToSDCard"); hide("galileoHasSetting"); hide("tiltConfig"); @@ -129,7 +130,7 @@ function parseIncoming(msg) { hide("ethernetConfig"); hide("ntpConfig"); show("portsConfig"); - hide("noExternalPortOptions"); + show("externalPortOptions"); show("logToSDCard"); hide("tiltConfig"); hide("beeperControl"); @@ -141,9 +142,7 @@ function parseIncoming(msg) { hide("ethernetConfig"); hide("ntpConfig"); show("portsConfig"); - hide("externalPortOptions"); - show("noExternalPortOptions"); hide("logToSDCard"); From 92ed63250e89c106a0ef388a182472b52e5037a5 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Thu, 4 Jul 2024 12:24:50 +0100 Subject: [PATCH 05/10] Change localised to localized --- Firmware/RTK_Everywhere/AP-Config/index.html | 14 ++-- Firmware/RTK_Everywhere/AP-Config/src/main.js | 10 +-- Firmware/RTK_Everywhere/MQTT_Client.ino | 64 +++++++++---------- Firmware/RTK_Everywhere/menuPP.ino | 28 ++++---- Firmware/RTK_Everywhere/settings.h | 16 ++--- 5 files changed, 66 insertions(+), 66 deletions(-) diff --git a/Firmware/RTK_Everywhere/AP-Config/index.html b/Firmware/RTK_Everywhere/AP-Config/index.html index 7b23f823e..dac4438d5 100644 --- a/Firmware/RTK_Everywhere/AP-Config/index.html +++ b/Firmware/RTK_Everywhere/AP-Config/index.html @@ -1181,17 +1181,17 @@
- - + + + title="When enabled, localized corrections for your location will be used instead of the continental corrections. Default: Disabled">
-
- - @@ -1200,7 +1200,7 @@ + title="Select the localized distribution tile level. High Density is recommended. Sparse may be deprecated. Default: 250 x 250km High Density">
diff --git a/Firmware/RTK_Everywhere/AP-Config/src/main.js b/Firmware/RTK_Everywhere/AP-Config/src/main.js index 6599a09bc..24fa64a56 100644 --- a/Firmware/RTK_Everywhere/AP-Config/src/main.js +++ b/Firmware/RTK_Everywhere/AP-Config/src/main.js @@ -439,7 +439,7 @@ function parseIncoming(msg) { ge("enableARPLogging").dispatchEvent(new CustomEvent('change')); ge("enableAutoFirmwareUpdate").dispatchEvent(new CustomEvent('change')); ge("enableAutoReset").dispatchEvent(new CustomEvent('change')); - ge("useLocalisedDistribution").dispatchEvent(new CustomEvent('change')); + ge("useLocalizedDistribution").dispatchEvent(new CustomEvent('change')); updateECEFList(); updateGeodeticList(); @@ -1389,12 +1389,12 @@ document.addEventListener("DOMContentLoaded", (event) => { } }); - ge("useLocalisedDistribution").addEventListener("change", function () { - if (ge("useLocalisedDistribution").checked) { - show("localisedDistributionTileLevelDropdown"); + ge("useLocalizedDistribution").addEventListener("change", function () { + if (ge("useLocalizedDistribution").checked) { + show("localizedDistributionTileLevelDropdown"); } else { - hide("localisedDistributionTileLevelDropdown"); + hide("localizedDistributionTileLevelDropdown"); } }); diff --git a/Firmware/RTK_Everywhere/MQTT_Client.ino b/Firmware/RTK_Everywhere/MQTT_Client.ino index 19543549a..5fba8a09e 100644 --- a/Firmware/RTK_Everywhere/MQTT_Client.ino +++ b/Firmware/RTK_Everywhere/MQTT_Client.ino @@ -71,8 +71,8 @@ MQTT_Client.ino // (ditto) // Initially we subscribe to the key distribution topic and the continental correction topic (if available) // If enabled, we also subscribe to the AssistNow MGA topic -// If localised distribution is enabled and we have a 3D fix, we subscribe to the dict topic -// When the dict is received, we subscribe to the nearest localised topic and unsubscribe from the continental topic +// If localized distribution is enabled and we have a 3D fix, we subscribe to the dict topic +// When the dict is received, we subscribe to the nearest localized topic and unsubscribe from the continental topic // When the AssistNow MGA data arrives, we unsubscribe and subscribe to AssistNow updates #ifdef COMPILE_MQTT_CLIENT @@ -124,8 +124,8 @@ const char localizedPrefix[] = "pp/ip/L"; // The localized distribution topic pr std::vector mqttSubscribeTopics; // List of MQTT topics to be subscribed to std::vector mqttClientSubscribedTopics; // List of topics currently subscribed to -String localisedDistributionDictTopic = ""; -String localisedDistributionTileTopic = ""; +String localizedDistributionDictTopic = ""; +String localizedDistributionTileTopic = ""; static MqttClient *mqttClient; @@ -289,7 +289,7 @@ void mqttClientPrintStatus() // Called when a subscribed message arrives void mqttClientReceiveMessage(int messageSize) { - // The Level 3 localised distribution dictionary topic can be up to 25KB + // The Level 3 localized distribution dictionary topic can be up to 25KB // The full AssistNow (MGA) topic can be ~11KB const uint16_t mqttLimit = 26000; static uint8_t *mqttData = nullptr; @@ -327,9 +327,9 @@ void mqttClientReceiveMessage(int messageSize) if (mqttCount > 0) { - // Check for localisedDistributionDictTopic - if ((localisedDistributionDictTopic.length() > 0) - && (strcmp(topic, localisedDistributionDictTopic.c_str()) == 0)) + // Check for localizedDistributionDictTopic + if ((localizedDistributionDictTopic.length() > 0) + && (strcmp(topic, localizedDistributionDictTopic.c_str()) == 0)) { // We should be using a JSON library to read the nodes. But JSON is // heavy on RAM and the dict could be 25KB for Level 3. @@ -381,9 +381,9 @@ void mqttClientReceiveMessage(int messageSize) minDist = distScaled; tile[12] = 0; // Convert the second quote to NULL for snprintf char tileTopic[50]; - snprintf(tileTopic, sizeof(tileTopic), "%s", localisedDistributionDictTopic.c_str()); + snprintf(tileTopic, sizeof(tileTopic), "%s", localizedDistributionDictTopic.c_str()); snprintf(&tileTopic[strlen(localizedPrefix) + 13], sizeof(tileTopic) - (strlen(localizedPrefix) + 13), "%s", tile + 1); // Start after the first quote - localisedDistributionTileTopic = tileTopic; + localizedDistributionTileTopic = tileTopic; } } tile = strtok_r(nullptr, ",", &preservedTile); @@ -474,9 +474,9 @@ void mqttClientReceiveMessage(int messageSize) ((strlen(settings.regionalCorrectionTopics[settings.geographicRegion]) > 0) && (strcmp(topic, settings.regionalCorrectionTopics[settings.geographicRegion]) == 0)) || - // Or from the localised distribution tile topic - ((localisedDistributionTileTopic.length() > 0) - && (strcmp(topic, localisedDistributionTileTopic.c_str()) == 0)) + // Or from the localized distribution tile topic + ((localizedDistributionTileTopic.length() > 0) + && (strcmp(topic, localizedDistributionTileTopic.c_str()) == 0)) ) { // SPARTN @@ -830,8 +830,8 @@ void mqttClientUpdate() mqttSubscribeTopics.clear(); // Clear the list of MQTT topics to be subscribed to mqttClientSubscribedTopics.clear(); // Clear the list of topics currently subscribed to - localisedDistributionDictTopic = ""; - localisedDistributionTileTopic = ""; + localizedDistributionDictTopic = ""; + localizedDistributionTileTopic = ""; // Subscribe to AssistNow MGA if enabled if (settings.useAssistNow) @@ -936,8 +936,8 @@ void mqttClientUpdate() if (breakOut) break; // Break out of this state - // Check if localised distribution is enabled - if ((strlen(settings.regionalCorrectionTopics[settings.geographicRegion]) > 0) && (settings.useLocalisedDistribution)) + // Check if localized distribution is enabled + if ((strlen(settings.regionalCorrectionTopics[settings.geographicRegion]) > 0) && (settings.useLocalizedDistribution)) { uint8_t fixType = gnssGetFixType(); double latitude = gnssGetLatitude(); // degrees @@ -945,12 +945,12 @@ void mqttClientUpdate() if (fixType >= 3) // If we have a 3D fix { // If both the dict and tile topics are empty, prepare to subscribe to the dict topic - if ((localisedDistributionDictTopic.length() == 0) && (localisedDistributionTileTopic.length() == 0)) + if ((localizedDistributionDictTopic.length() == 0) && (localizedDistributionTileTopic.length() == 0)) { float tileDelta = 2.5; // 2.5 degrees (10 degrees and 5 degrees are also possible) - if ((settings.localisedDistributionTileLevel == 0) || (settings.localisedDistributionTileLevel == 3)) + if ((settings.localizedDistributionTileLevel == 0) || (settings.localizedDistributionTileLevel == 3)) tileDelta = 10.0; - if ((settings.localisedDistributionTileLevel == 1) || (settings.localisedDistributionTileLevel == 4)) + if ((settings.localizedDistributionTileLevel == 1) || (settings.localizedDistributionTileLevel == 4)) tileDelta = 5.0; float lat = latitude; // Degrees @@ -965,26 +965,26 @@ void mqttClientUpdate() char dictTopic[50]; snprintf(dictTopic, sizeof(dictTopic), "%s%c%c%04d%c%05d/dict", - localizedPrefix, char(0x30 + settings.localisedDistributionTileLevel), + localizedPrefix, char(0x30 + settings.localizedDistributionTileLevel), (lat_i < 0) ? 'S' : 'N', abs(lat_i), (lon_i < 0) ? 'W' : 'E', abs(lon_i)); - localisedDistributionDictTopic = dictTopic; - mqttSubscribeTopics.push_back(localisedDistributionDictTopic); + localizedDistributionDictTopic = dictTopic; + mqttSubscribeTopics.push_back(localizedDistributionDictTopic); breakOut = true; } - // localisedDistributionTileTopic is populated by mqttClientReceiveMessage - // If both the dict and tile topics are populated, prepare to subscribe to the localised tile topic - // Empty localisedDistributionDictTopic afterwardds to prevent this state being repeated - if ((localisedDistributionDictTopic.length() > 0) && (localisedDistributionTileTopic.length() > 0)) + // localizedDistributionTileTopic is populated by mqttClientReceiveMessage + // If both the dict and tile topics are populated, prepare to subscribe to the localized tile topic + // Empty localizedDistributionDictTopic afterwardds to prevent this state being repeated + if ((localizedDistributionDictTopic.length() > 0) && (localizedDistributionTileTopic.length() > 0)) { - // Subscribe to the localisedDistributionTileTopic - mqttSubscribeTopics.push_back(localisedDistributionTileTopic); - // Unsubscribe from the localisedDistributionDictTopic - std::vector::iterator pos = std::find(mqttSubscribeTopics.begin(), mqttSubscribeTopics.end(), localisedDistributionDictTopic); + // Subscribe to the localizedDistributionTileTopic + mqttSubscribeTopics.push_back(localizedDistributionTileTopic); + // Unsubscribe from the localizedDistributionDictTopic + std::vector::iterator pos = std::find(mqttSubscribeTopics.begin(), mqttSubscribeTopics.end(), localizedDistributionDictTopic); if (pos != mqttSubscribeTopics.end()) mqttSubscribeTopics.erase(pos); // Unsubscribe from the continental corrections @@ -992,7 +992,7 @@ void mqttClientUpdate() if (pos != mqttSubscribeTopics.end()) mqttSubscribeTopics.erase(pos); - localisedDistributionDictTopic = ""; // Empty localisedDistributionDictTopic to prevent this state being repeated + localizedDistributionDictTopic = ""; // Empty localizedDistributionDictTopic to prevent this state being repeated breakOut = true; } diff --git a/Firmware/RTK_Everywhere/menuPP.ino b/Firmware/RTK_Everywhere/menuPP.ino index 374a0c55d..216e7fb00 100644 --- a/Firmware/RTK_Everywhere/menuPP.ino +++ b/Firmware/RTK_Everywhere/menuPP.ino @@ -911,10 +911,10 @@ void menuPointPerfect() else systemPrintln("No keys"); - if ((settings.useLocalisedDistribution) && (localisedDistributionTileTopic.length() > 0)) + if ((settings.useLocalizedDistribution) && (localizedDistributionTileTopic.length() > 0)) { - systemPrint("Most recent localised distribution topic: "); - systemPrintln(localisedDistributionTileTopic.c_str()); // From MQTT_Client.ino + systemPrint("Most recent localized distribution topic: "); + systemPrintln(localizedDistributionTileTopic.c_str()); // From MQTT_Client.ino } // How this works: @@ -962,17 +962,17 @@ void menuPointPerfect() systemPrintln("Requested"); else systemPrintln("Not requested"); - systemPrint("4) Use localised distribution: "); - if (settings.useLocalisedDistribution == true) + systemPrint("4) Use localized distribution: "); + if (settings.useLocalizedDistribution == true) systemPrintln("Enabled"); else systemPrintln("Disabled"); - if (settings.useLocalisedDistribution) + if (settings.useLocalizedDistribution) { - systemPrint("5) Localised distribution tile level: "); - systemPrint(settings.localisedDistributionTileLevel); + systemPrint("5) Localized distribution tile level: "); + systemPrint(settings.localizedDistributionTileLevel); systemPrint(" ("); - systemPrint(localisedDistributionTileLevelNames[settings.localisedDistributionTileLevel]); + systemPrint(localizedDistributionTileLevelNames[settings.localizedDistributionTileLevel]); systemPrintln(")"); } if (productVariant != RTK_FACET_MOSAIC) @@ -1018,13 +1018,13 @@ void menuPointPerfect() } else if (incoming == 4 && pointPerfectIsEnabled()) { - settings.useLocalisedDistribution ^= 1; + settings.useLocalizedDistribution ^= 1; } - else if (incoming == 5 && pointPerfectIsEnabled() && settings.useLocalisedDistribution) + else if (incoming == 5 && pointPerfectIsEnabled() && settings.useLocalizedDistribution) { - settings.localisedDistributionTileLevel++; - if (settings.localisedDistributionTileLevel >= LOCALISED_DISTRIBUTION_TILE_LEVELS) - settings.localisedDistributionTileLevel = 0; + settings.localizedDistributionTileLevel++; + if (settings.localizedDistributionTileLevel >= LOCALIZED_DISTRIBUTION_TILE_LEVELS) + settings.localizedDistributionTileLevel = 0; } else if (incoming == 'a' && pointPerfectIsEnabled() && (productVariant != RTK_FACET_MOSAIC)) { diff --git a/Firmware/RTK_Everywhere/settings.h b/Firmware/RTK_Everywhere/settings.h index c7b1cc2cb..1c19e3292 100644 --- a/Firmware/RTK_Everywhere/settings.h +++ b/Firmware/RTK_Everywhere/settings.h @@ -1369,17 +1369,17 @@ struct Settings bool outputTipAltitude = false; // If enabled, subtract the pole length and APC from the GNSS receiver's reported altitude - // Localised distribution - bool useLocalisedDistribution = false; - uint8_t localisedDistributionTileLevel = 5; + // Localized distribution + bool useLocalizedDistribution = false; + uint8_t localizedDistributionTileLevel = 5; bool useAssistNow = false; // Add new settings to appropriate group above or create new group // Then also add to the same group in rtkSettingsEntries below } settings; -const uint8_t LOCALISED_DISTRIBUTION_TILE_LEVELS = 6; -const char *localisedDistributionTileLevelNames[LOCALISED_DISTRIBUTION_TILE_LEVELS] = { +const uint8_t LOCALIZED_DISTRIBUTION_TILE_LEVELS = 6; +const char *localizedDistributionTileLevelNames[LOCALIZED_DISTRIBUTION_TILE_LEVELS] = { "1000 x 1000km sparse", "500 x 500km sparse", "250 x 250km sparse", @@ -1878,9 +1878,9 @@ const RTK_Settings_Entry rtkSettingsEntries[] = { 0, 0, 1, 0, 1, 1, 1, 1, _uint32_t, 0, & settings.outputTipAltitude, "outputTipAltitude", }, - // Localised distribution - { 0, 1, 1, 0, 1, 1, 1, 1, _bool, 0, & settings.useLocalisedDistribution, "useLocalisedDistribution", }, - { 0, 1, 1, 0, 1, 1, 1, 1, _uint8_t, 0, & settings.localisedDistributionTileLevel, "localisedDistributionTileLevel", }, + // Localized distribution + { 0, 1, 1, 0, 1, 1, 1, 1, _bool, 0, & settings.useLocalizedDistribution, "useLocalizedDistribution", }, + { 0, 1, 1, 0, 1, 1, 1, 1, _uint8_t, 0, & settings.localizedDistributionTileLevel, "localizedDistributionTileLevel", }, { 0, 1, 1, 0, 1, 1, 0, 1, _bool, 0, & settings.useAssistNow, "useAssistNow", }, // Add new settings to appropriate group above or create new group From b7c0d96098ccf0a7ee0b522e146884e950b65a07 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Thu, 4 Jul 2024 12:29:47 +0100 Subject: [PATCH 06/10] Disable ENABLE_DEVELOPER 15min key attempt --- Firmware/RTK_Everywhere/menuPP.ino | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Firmware/RTK_Everywhere/menuPP.ino b/Firmware/RTK_Everywhere/menuPP.ino index 216e7fb00..10efbf3ec 100644 --- a/Firmware/RTK_Everywhere/menuPP.ino +++ b/Firmware/RTK_Everywhere/menuPP.ino @@ -1441,7 +1441,9 @@ void updateProvisioning() else if (!settings.enablePointPerfectCorrections || !settings.autoKeyRenewal) provisioningSetState(PROVISIONING_OFF); // When did we last try to get keys? Attempt every 24 hours - or every 15 mins for DEVELOPER - else if (online.rtc && (rtc.getEpoch() - settings.lastKeyAttempt > ( ENABLE_DEVELOPER ? (15 * 60) : (60 * 60 * 24)))) + //else if (online.rtc && (rtc.getEpoch() - settings.lastKeyAttempt > ( ENABLE_DEVELOPER ? (15 * 60) : (60 * 60 * 24)))) + // When did we last try to get keys? Attempt every 24 hours + else if (online.rtc && (rtc.getEpoch() - settings.lastKeyAttempt > (60 * 60 * 24))) { settings.lastKeyAttempt = rtc.getEpoch(); // Mark it recordSystemSettings(); // Record these settings to unit From 01e30051f2ec83741a202c6cb7f0a874f6db87c4 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Thu, 4 Jul 2024 15:18:52 +0100 Subject: [PATCH 07/10] forceKeyAttempt becomes settings.requestKeyUpdate. Add to web config --- Firmware/RTK_Everywhere/AP-Config/index.html | 9 +++++++++ Firmware/RTK_Everywhere/RTK_Everywhere.ino | 2 -- Firmware/RTK_Everywhere/States.ino | 2 +- Firmware/RTK_Everywhere/menuPP.ino | 17 +++++++++-------- Firmware/RTK_Everywhere/settings.h | 4 ++++ 5 files changed, 23 insertions(+), 11 deletions(-) diff --git a/Firmware/RTK_Everywhere/AP-Config/index.html b/Firmware/RTK_Everywhere/AP-Config/index.html index dac4438d5..797aa3c92 100644 --- a/Firmware/RTK_Everywhere/AP-Config/index.html +++ b/Firmware/RTK_Everywhere/AP-Config/index.html @@ -1169,6 +1169,15 @@
+
+ + + + + +
+
diff --git a/Firmware/RTK_Everywhere/RTK_Everywhere.ino b/Firmware/RTK_Everywhere/RTK_Everywhere.ino index 60ecb7b6a..763fe443b 100644 --- a/Firmware/RTK_Everywhere/RTK_Everywhere.ino +++ b/Firmware/RTK_Everywhere/RTK_Everywhere.ino @@ -815,8 +815,6 @@ unsigned long lastGnssToPpl = 0; int commandCount; int16_t *commandIndex; -volatile bool forceKeyAttempt = false; // Set to true to force a key provisioning attempt - //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- // Display boot times diff --git a/Firmware/RTK_Everywhere/States.ino b/Firmware/RTK_Everywhere/States.ino index e0bec2aa1..8f7494157 100644 --- a/Firmware/RTK_Everywhere/States.ino +++ b/Firmware/RTK_Everywhere/States.ino @@ -503,7 +503,7 @@ void stateUpdate() break; case (STATE_KEYS_REQUESTED): { - forceKeyAttempt = true; // Force a key update + settings.requestKeyUpdate = true; // Force a key update changeState(lastSystemState); // Return to the last system state } break; diff --git a/Firmware/RTK_Everywhere/menuPP.ino b/Firmware/RTK_Everywhere/menuPP.ino index 10efbf3ec..f36d58def 100644 --- a/Firmware/RTK_Everywhere/menuPP.ino +++ b/Firmware/RTK_Everywhere/menuPP.ino @@ -958,7 +958,7 @@ void menuPointPerfect() else systemPrintln("Disabled"); systemPrint("3) Request Key Update: "); - if (forceKeyAttempt == true) + if (settings.requestKeyUpdate == true) systemPrintln("Requested"); else systemPrintln("Not requested"); @@ -1003,18 +1003,18 @@ void menuPointPerfect() { settings.enablePointPerfectCorrections ^= 1; restartRover = true; // Require a rover restart to enable / disable RTCM for PPL - forceKeyAttempt = settings.enablePointPerfectCorrections; // Force a key update - or don't + settings.requestKeyUpdate = settings.enablePointPerfectCorrections; // Force a key update - or don't } #ifdef COMPILE_NETWORK else if (incoming == 2 && pointPerfectIsEnabled()) { settings.autoKeyRenewal ^= 1; - forceKeyAttempt = settings.autoKeyRenewal; // Force a key update - or don't + settings.requestKeyUpdate = settings.autoKeyRenewal; // Force a key update - or don't } else if (incoming == 3 && pointPerfectIsEnabled()) { - forceKeyAttempt = forceKeyAttempt ^ 1; + settings.requestKeyUpdate ^= 1; } else if (incoming == 4 && pointPerfectIsEnabled()) { @@ -1238,13 +1238,13 @@ void updateProvisioning() { if ((online.rtc) || (millis() > (provisioningStartTime + provisioningTimeout)) - || (forceKeyAttempt)) + || (settings.requestKeyUpdate)) provisioningSetState(PROVISIONING_NOT_STARTED); } break; case PROVISIONING_NOT_STARTED: { - if (settings.enablePointPerfectCorrections && (settings.autoKeyRenewal || forceKeyAttempt)) + if (settings.enablePointPerfectCorrections && (settings.autoKeyRenewal || settings.requestKeyUpdate)) { provisioningSetState(PROVISIONING_CHECK_REMAINING); } @@ -1314,7 +1314,8 @@ void updateProvisioning() break; case PROVISIONING_STARTING: { - forceKeyAttempt = false; + settings.requestKeyUpdate = false; + recordSystemSettings(); // Record these settings to unit ztpResponse = ZTP_NOT_STARTED; // HTTP_Client will update this httpClientModeNeeded = true; // This will start the HTTP_Client provisioningStartTime = millis(); // Record the start time so we can timeout @@ -1436,7 +1437,7 @@ void updateProvisioning() break; case PROVISIONING_WAIT_ATTEMPT: { - if (forceKeyAttempt) + if (settings.requestKeyUpdate) provisioningSetState(PROVISIONING_STARTING); else if (!settings.enablePointPerfectCorrections || !settings.autoKeyRenewal) provisioningSetState(PROVISIONING_OFF); diff --git a/Firmware/RTK_Everywhere/settings.h b/Firmware/RTK_Everywhere/settings.h index 1c19e3292..535ef7b1e 100644 --- a/Firmware/RTK_Everywhere/settings.h +++ b/Firmware/RTK_Everywhere/settings.h @@ -1374,6 +1374,8 @@ struct Settings uint8_t localizedDistributionTileLevel = 5; bool useAssistNow = false; + bool requestKeyUpdate = false; // Set to true to force a key provisioning attempt + // Add new settings to appropriate group above or create new group // Then also add to the same group in rtkSettingsEntries below } settings; @@ -1883,6 +1885,8 @@ const RTK_Settings_Entry rtkSettingsEntries[] = { 0, 1, 1, 0, 1, 1, 1, 1, _uint8_t, 0, & settings.localizedDistributionTileLevel, "localizedDistributionTileLevel", }, { 0, 1, 1, 0, 1, 1, 0, 1, _bool, 0, & settings.useAssistNow, "useAssistNow", }, + { 0, 1, 1, 0, 1, 1, 1, 1, _bool, 0, & settings.requestKeyUpdate, "requestKeyUpdate", }, + // Add new settings to appropriate group above or create new group // Then also add to the same group in settings above // F From d93d2b07c54b68616617c81c49fd5f668dceb987 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Sat, 6 Jul 2024 16:10:04 +0100 Subject: [PATCH 08/10] Increase provisioningTimeout to 2 mins. Maybe it should be even longer? --- Firmware/RTK_Everywhere/menuPP.ino | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Firmware/RTK_Everywhere/menuPP.ino b/Firmware/RTK_Everywhere/menuPP.ino index f36d58def..e42c4da77 100644 --- a/Firmware/RTK_Everywhere/menuPP.ino +++ b/Firmware/RTK_Everywhere/menuPP.ino @@ -1211,7 +1211,7 @@ void provisioningSetState(uint8_t newState) } unsigned long provisioningStartTime; -const unsigned long provisioningTimeout = 20000; +const unsigned long provisioningTimeout = 120000; void updateProvisioning() { @@ -1402,6 +1402,14 @@ void updateProvisioning() httpClientModeNeeded = false; // Tell HTTP_Client to give up. (But it probably already has...) displayAlreadyRegistered(5000); + provisioningSetState(PROVISIONING_KEYS_REMAINING); + } + else if (ztpResponse == ZTP_UNKNOWN_ERROR) + { + systemPrintln("updateProvisioning: ZTP_UNKNOWN_ERROR"); + + httpClientModeNeeded = false; // Tell HTTP_Client to give up. (But it probably already has...) + provisioningSetState(PROVISIONING_KEYS_REMAINING); } } From 988ca7ce4f47279651328ca0f3ea438df388ba88 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Sat, 6 Jul 2024 16:11:09 +0100 Subject: [PATCH 09/10] Update mqttClientLastDataReceived when the connection is made --- Firmware/RTK_Everywhere/MQTT_Client.ino | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Firmware/RTK_Everywhere/MQTT_Client.ino b/Firmware/RTK_Everywhere/MQTT_Client.ino index 5fba8a09e..434f193fb 100644 --- a/Firmware/RTK_Everywhere/MQTT_Client.ino +++ b/Firmware/RTK_Everywhere/MQTT_Client.ino @@ -853,6 +853,8 @@ void mqttClientUpdate() // Subscribing to the localized distribution dictionary and local tile is handled by MQTT_CLIENT_SERVICES_CONNECTED // since we need a 3D fix for those + mqttClientLastDataReceived = millis(); // Prevent MQTT_CLIENT_SERVICES_CONNECTED from going immediately into timeout + reportHeapNow(settings.debugMqttClientState); mqttClientSetState(MQTT_CLIENT_SERVICES_CONNECTED); From e2cec320f4c48d1d87c6011ef290ecfbd78e92dc Mon Sep 17 00:00:00 2001 From: PaulZC Date: Mon, 8 Jul 2024 15:26:37 +0100 Subject: [PATCH 10/10] Better corrections debugging --- Firmware/RTK_Everywhere/NtripClient.ino | 4 ++-- Firmware/RTK_Everywhere/Tasks.ino | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Firmware/RTK_Everywhere/NtripClient.ino b/Firmware/RTK_Everywhere/NtripClient.ino index d58f6edb9..1f5b9dad2 100644 --- a/Firmware/RTK_Everywhere/NtripClient.ino +++ b/Firmware/RTK_Everywhere/NtripClient.ino @@ -833,7 +833,7 @@ void ntripClientUpdate() // Push RTCM to GNSS module over I2C / SPI gnssPushRawData(rtcmData, rtcmCount); - if ((settings.debugNtripClientRtcm || PERIODIC_DISPLAY(PD_NTRIP_CLIENT_DATA)) && + if ((settings.debugCorrections || settings.debugNtripClientRtcm || PERIODIC_DISPLAY(PD_NTRIP_CLIENT_DATA)) && (!inMainMenu)) { PERIODIC_CLEAR(PD_NTRIP_CLIENT_DATA); @@ -842,7 +842,7 @@ void ntripClientUpdate() } else { - if ((settings.debugNtripClientRtcm || PERIODIC_DISPLAY(PD_NTRIP_CLIENT_DATA)) && + if ((settings.debugCorrections || settings.debugNtripClientRtcm || PERIODIC_DISPLAY(PD_NTRIP_CLIENT_DATA)) && (!inMainMenu)) { PERIODIC_CLEAR(PD_NTRIP_CLIENT_DATA); diff --git a/Firmware/RTK_Everywhere/Tasks.ino b/Firmware/RTK_Everywhere/Tasks.ino index 59cd243a9..76402334b 100644 --- a/Firmware/RTK_Everywhere/Tasks.ino +++ b/Firmware/RTK_Everywhere/Tasks.ino @@ -270,7 +270,7 @@ void sendGnssBuffer() { if (gnssPushRawData(bluetoothOutgoingToGnss, bluetoothOutgoingToGnssHead)) { - if (PERIODIC_DISPLAY(PD_ZED_DATA_TX)) + if (settings.debugCorrections || PERIODIC_DISPLAY(PD_ZED_DATA_TX)) { PERIODIC_CLEAR(PD_ZED_DATA_TX); systemPrintf("Sent %d BT bytes to GNSS\r\n", bluetoothOutgoingToGnssHead); @@ -280,7 +280,7 @@ void sendGnssBuffer() } else { - if (PERIODIC_DISPLAY(PD_ZED_DATA_TX)) + if (settings.debugCorrections || PERIODIC_DISPLAY(PD_ZED_DATA_TX)) { PERIODIC_CLEAR(PD_ZED_DATA_TX); systemPrintf("%d BT bytes NOT sent due to priority\r\n", bluetoothOutgoingToGnssHead);