diff --git a/lib/gwwifi/GWWifi.h b/lib/gwwifi/GWWifi.h index cb5c980..c9fe262 100644 --- a/lib/gwwifi/GWWifi.h +++ b/lib/gwwifi/GWWifi.h @@ -34,6 +34,6 @@ class GwWifi{ bool connectClientAsync(); // Non-blocking version for other tasks String apIP(); bool isApActive(){return apActive;} - bool isClientActive(){return wifiClient->asBoolean();}} + bool isClientActive(){return wifiClient->asBoolean();} }; #endif \ No newline at end of file diff --git a/lib/obp60task/NetworkClient.cpp b/lib/obp60task/NetworkClient.cpp index 66b973d..c6a7962 100644 --- a/lib/obp60task/NetworkClient.cpp +++ b/lib/obp60task/NetworkClient.cpp @@ -1,4 +1,7 @@ #include "NetworkClient.h" +#include "GWWifi.h" // WiFi management (thread-safe) + +extern GwWifi gwWifi; // Extern declaration of global WiFi instance extern "C" { #include "puff.h" @@ -51,8 +54,13 @@ bool NetworkClient::httpGetGzip(const String& url, uint8_t*& outData, size_t& ou const size_t capacity = READLIMIT; // Read limit for data (can be adjusted in NetworkClient.h) uint8_t* buffer = (uint8_t*)malloc(capacity); + if (!gwWifi.clientConnected()) { + if (DEBUGING) {Serial.println("No WiFi connection");} + return false; + } + if (!buffer) { - if (DEBUG) {Serial.println("Malloc failed (buffer");} + if (DEBUGING) {Serial.println("Malloc failed buffer");} return false; } @@ -106,7 +114,7 @@ bool NetworkClient::httpGetGzip(const String& url, uint8_t*& outData, size_t& ou len += read; lastData = millis(); - if (DEBUG) {Serial.printf("Read chunk: %d (total: %d)\n", read, (int)len);} + if (DEBUGING) {Serial.printf("Read chunk: %d (total: %d)\n", read, (int)len);} if (len < 20) continue; // Not enough data for header @@ -122,7 +130,7 @@ bool NetworkClient::httpGetGzip(const String& url, uint8_t*& outData, size_t& ou int res = puff(test, &testLen, buffer + headerOffset, &srcLen); if (res == 0) { - if (DEBUG) {Serial.printf("Decompress OK! Size: %lu bytes\n", testLen);} + if (DEBUGING) {Serial.printf("Decompress OK! Size: %lu bytes\n", testLen);} outData = test; outLen = testLen; complete = true; @@ -167,7 +175,7 @@ bool NetworkClient::fetchAndDecompressJson(const String& url) { return false; } - if (DEBUG) {Serial.println("JSON OK!");} + if (DEBUGING) {Serial.println("JSON OK!");} _valid = true; return true; } diff --git a/lib/obp60task/NetworkClient.h b/lib/obp60task/NetworkClient.h index 84d7a87..03e7f83 100644 --- a/lib/obp60task/NetworkClient.h +++ b/lib/obp60task/NetworkClient.h @@ -3,7 +3,7 @@ #include #include -#define DEBUG false // Debug flag for NetworkClient for more live information +#define DEBUGING false // Debug flag for NetworkClient for more live information #define READLIMIT 200000 // HTTP read limit in byte for gzip content (can be adjusted) #define CONNECTIONTIMEOUT 3000 // Timeout in ms for HTTP connection #define TCPREADTIMEOUT 2000 // Timeout in ms for read HTTP client stack diff --git a/lib/obp60task/PageNavigation.cpp b/lib/obp60task/PageNavigation.cpp index 550d70c..bd4adf1 100644 --- a/lib/obp60task/PageNavigation.cpp +++ b/lib/obp60task/PageNavigation.cpp @@ -4,13 +4,9 @@ #include "OBP60Extensions.h" #include "NetworkClient.h" // Network connection #include "ImageDecoder.h" // Image decoder for navigation map -#include "GWWifi.h" // WiFi management (thread-safe) #include "Logo_OBP_400x300_sw.h" -// Extern declaration of global WiFi instance -extern GwWifi gwWifi; - // Defines for reading of navigation map #define JSON_BUFFER 30000 // Max buffer size for JSON content (30 kB picture + values) NetworkClient net(JSON_BUFFER); // Define network client @@ -29,7 +25,6 @@ bool showValues = false; // Show values HDT, SOG, DBT in navigation map int imageBackupHeight = 0; size_t imageBackupSize = 0; bool hasImageBackup = false; - static bool wifiConnectRequested; // Track if WiFi connection was requested public: PageNavigation(CommonData &common){ @@ -60,15 +55,12 @@ bool showValues = false; // Show values HDT, SOG, DBT in navigation map } return 0; // Commit the key } - // Code for zoom + + // Code for zoom - if(key == 2){ zoom ++; // Zoom + if(zoom >17){ zoom = 17; } - // Optional: Versuche WiFi-Verbindung nach Zoom-Änderung - // Dies ermöglicht eine neue Kartendarstellung - gwWifi.connectClientAsync(); return 0; // Commit the key } if(key == 5){ @@ -103,13 +95,6 @@ bool showValues = false; // Show values HDT, SOG, DBT in navigation map zoom = zoomLevel; // Over write zoom level with setup value showValues = showValuesMap; // Over write showValues with setup value firstRun = false; // Restet variable - - // Versuche beim ersten Laden eine WiFi-Verbindung herzustellen (non-blocking) - // Dies ist thread-safe und blockiert das UI nicht - if (!gwWifi.clientConnected()) { - LOG_DEBUG(GwLog::LOG, "PageNavigation: Initiating WiFi connection for map download"); - gwWifi.connectClientAsync(); - } } // Local variables @@ -359,16 +344,6 @@ bool showValues = false; // Show values HDT, SOG, DBT in navigation map // Load navigation map //*********************************************************** - // Prüfe WiFi-Verbindung (Thread-Safe) - // Diese Methode ist synchronisiert und blockiert maximal 1 Sekunde - bool wifiConnected = gwWifi.clientConnected(); - - if (!wifiConnected && !wifiConnectRequested) { - LOG_DEBUG(GwLog::LOG, "PageNavigation: WiFi not connected, attempting async connect"); - gwWifi.connectClientAsync(); - wifiConnectRequested = true; - } - // URL to OBP Maps Converter // For more details see: https://github.com/norbert-walter/maps-converter String url = String("http://") + server + ":" + port + // OBP Server @@ -400,8 +375,7 @@ bool showValues = false; // Show values HDT, SOG, DBT in navigation map getdisplay().setTextColor(commonData->fgcolor); // If a network connection to URL then load the navigation map - if (wifiConnected && net.fetchAndDecompressJson(url)) { - wifiConnectRequested = false; // Reset flag after successful connection + if (net.fetchAndDecompressJson(url)) { auto& json = net.json(); // Extract JSON content int numPix = json["number_pixels"] | 0; // Read number of pixels @@ -468,12 +442,6 @@ bool showValues = false; // Show values HDT, SOG, DBT in navigation map } lostCounter++; // Increment lost counter - - // Nur einmal pro Sekunde einen neuen Verbindungsversuch machen - if (!wifiConnectRequested) { - gwWifi.connectClientAsync(); - wifiConnectRequested = true; - } } @@ -520,9 +488,6 @@ bool showValues = false; // Show values HDT, SOG, DBT in navigation map }; }; -// Initialize static member variable -bool PageNavigation::wifiConnectRequested = false; - static Page *createPage(CommonData &common){ return new PageNavigation(common); }/** diff --git a/lib/obp60task/PageNavigation_old.cpp b/lib/obp60task/PageNavigation_old.cpp new file mode 100644 index 0000000..550d70c --- /dev/null +++ b/lib/obp60task/PageNavigation_old.cpp @@ -0,0 +1,543 @@ +#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3 + +#include "Pagedata.h" +#include "OBP60Extensions.h" +#include "NetworkClient.h" // Network connection +#include "ImageDecoder.h" // Image decoder for navigation map +#include "GWWifi.h" // WiFi management (thread-safe) + +#include "Logo_OBP_400x300_sw.h" + +// Extern declaration of global WiFi instance +extern GwWifi gwWifi; + +// Defines for reading of navigation map +#define JSON_BUFFER 30000 // Max buffer size for JSON content (30 kB picture + values) +NetworkClient net(JSON_BUFFER); // Define network client +ImageDecoder decoder; // Define image decoder + +class PageNavigation : public Page +{ +// Values for buttons +bool firstRun = true; // Detect the first page run +int zoom = 15; // Default zoom level +bool showValues = false; // Show values HDT, SOG, DBT in navigation map + + private: + uint8_t* imageBackupData = nullptr; + int imageBackupWidth = 0; + int imageBackupHeight = 0; + size_t imageBackupSize = 0; + bool hasImageBackup = false; + static bool wifiConnectRequested; // Track if WiFi connection was requested + + public: + PageNavigation(CommonData &common){ + commonData = &common; + common.logger->logDebug(GwLog::LOG,"Instantiate PageNavigation"); + imageBackupData = (uint8_t*)heap_caps_malloc((GxEPD_WIDTH * GxEPD_HEIGHT), MALLOC_CAP_SPIRAM); + } + + // Set botton labels + virtual void setupKeys(){ + Page::setupKeys(); + commonData->keydata[0].label = "ZOOM -"; + commonData->keydata[1].label = "ZOOM +"; + commonData->keydata[4].label = "VALUES"; + } + + virtual int handleKey(int key){ + // Code for keylock + if(key == 11){ + commonData->keylock = !commonData->keylock; + return 0; // Commit the key + } + // Code for zoom - + if(key == 1){ + zoom --; // Zoom - + if(zoom <7){ + zoom = 7; + } + return 0; // Commit the key + } + // Code for zoom + + if(key == 2){ + zoom ++; // Zoom + + if(zoom >17){ + zoom = 17; + } + // Optional: Versuche WiFi-Verbindung nach Zoom-Änderung + // Dies ermöglicht eine neue Kartendarstellung + gwWifi.connectClientAsync(); + return 0; // Commit the key + } + if(key == 5){ + showValues = !showValues; // Toggle show values + return 0; // Commit the key + } + return key; + } + + int displayPage(PageData &pageData){ + GwConfigHandler *config = commonData->config; + GwLog *logger = commonData->logger; + + // Get config data + String lengthformat = config->getString(config->lengthFormat); + bool simulation = config->getBool(config->useSimuData); + bool holdvalues = config->getBool(config->holdvalues); + String flashLED = config->getString(config->flashLED); + String backlightMode = config->getString(config->backlight); + String mapsource = config->getString(config->mapsource); + String ipAddress = config->getString(config->ipAddress); + int localPort = config->getInt(config->localPort); + String mapType = config->getString(config->maptype); + int zoomLevel = config->getInt(config->zoomlevel); + bool grid = config->getBool(config->grid); + String orientation = config->getString(config->orientation); + int refreshDistance = config->getInt(config->refreshDistance); + bool showValuesMap = config->getBool(config->showvalues); + bool ownHeading = config->getBool(config->ownheading); + + if(firstRun == true){ + zoom = zoomLevel; // Over write zoom level with setup value + showValues = showValuesMap; // Over write showValues with setup value + firstRun = false; // Restet variable + + // Versuche beim ersten Laden eine WiFi-Verbindung herzustellen (non-blocking) + // Dies ist thread-safe und blockiert das UI nicht + if (!gwWifi.clientConnected()) { + LOG_DEBUG(GwLog::LOG, "PageNavigation: Initiating WiFi connection for map download"); + gwWifi.connectClientAsync(); + } + } + + // Local variables + String server = "norbert-walter.dnshome.de"; + int port = 80; + int mType = 1; + int dType = 1; + int mapRot = 0; + int symbolRot = 0; + int mapGrid = 0; + + + // Old values for hold function + static double value1old = 0; + static String svalue1old = ""; + static String unit1old = ""; + static double value2old = 0; + static String svalue2old = ""; + static String unit2old = ""; + static double value3old = 0; // Deg + static String svalue3old = ""; + static String unit3old = ""; + static double value4old = 0; + static String svalue4old = ""; + static String unit4old = ""; + static double value5old = 0; + static String svalue5old = ""; + static String unit5old = ""; + static double value6old = 0; + static String svalue6old = ""; + static String unit6old = ""; + + static double latitude = 0; + static double latitudeold = 0; + static double longitude = 0; + static double longitudeold = 0; + static double trueHeading = 0; + static double magneticHeading = 0; + static double speedOverGround = 0; + static double depthBelowTransducer = 0; + static int lostCounter = 0; // Counter for connection lost to the map server (increment by each page refresh) + int imgWidth = 0; + int imgHeight = 0; + + // Get boat values #1 Latitude + GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue) + String name1 = xdrDelete(bvalue1->getName()); // Value name + name1 = name1.substring(0, 6); // String length limit for value name + double value1 = bvalue1->value; // Value as double in SI unit + bool valid1 = bvalue1->valid; // Valid information + String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places + String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value + + // Get boat values #2 Longitude + GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue) + String name2 = xdrDelete(bvalue2->getName()); // Value name + name2 = name2.substring(0, 6); // String length limit for value name + double value2 = bvalue2->value; // Value as double in SI unit + bool valid2 = bvalue2->valid; // Valid information + String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places + String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value + + // Get boat values #3 HDT + GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue) + String name3 = xdrDelete(bvalue3->getName()); // Value name + name3 = name3.substring(0, 6); // String length limit for value name + double value3 = bvalue3->value; // Value as double in SI unit + bool valid3 = bvalue3->valid; // Valid information + String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places + String unit3 = formatValue(bvalue3, *commonData).unit; // Unit of value + + // Get boat values #4 HDM + GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue) + String name4 = xdrDelete(bvalue4->getName()); // Value name + name4 = name4.substring(0, 6); // String length limit for value name + double value4 = bvalue4->value; // Value as double in SI unit + bool valid4 = bvalue4->valid; // Valid information + String svalue4 = formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places + String unit4 = formatValue(bvalue4, *commonData).unit; // Unit of value + + // Get boat values #5 SOG + GwApi::BoatValue *bvalue5 = pageData.values[4]; // Second element in list (only one value by PageOneValue) + String name5 = xdrDelete(bvalue5->getName()); // Value name + name5 = name5.substring(0, 6); // String length limit for value name + double value5 = bvalue5->value; // Value as double in SI unit + bool valid5 = bvalue5->valid; // Valid information + String svalue5 = formatValue(bvalue5, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places + String unit5 = formatValue(bvalue5, *commonData).unit; // Unit of value + + // Get boat values #6 DBT + GwApi::BoatValue *bvalue6 = pageData.values[5]; // Second element in list (only one value by PageOneValue) + String name6 = xdrDelete(bvalue6->getName()); // Value name + name6 = name6.substring(0, 6); // String length limit for value name + double value6 = bvalue6->value; // Value as double in SI unit + bool valid6 = bvalue6->valid; // Valid information + String svalue6 = formatValue(bvalue6, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places + String unit6 = formatValue(bvalue6, *commonData).unit; // Unit of value + + // Optical warning by limit violation (unused) + if(String(flashLED) == "Limit Violation"){ + setBlinkingLED(false); + setFlashLED(false); + } + + // Logging boat values + if (bvalue1 == NULL) return PAGE_OK; // WTF why this statement? + LOG_DEBUG(GwLog::LOG,"Drawing at PageNavigation, %s: %f, %s: %f, %s: %f, %s: %f, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3, name4.c_str(), value4, name5.c_str(), value5, name6.c_str(), value6); + + // Set variables + //*********************************************************** + + // Latitude + if(valid1){ + latitude = value1; + latitudeold = value1; + value3old = value1; + } + else{ + latitude = value1old; + } + // Longitude + if(valid2){ + longitude = value2; + longitudeold = value2; + value2old = value2; + } + else{ + longitude = value2old; + } + // HDT value (True Heading, GPS) + if(valid3){ + trueHeading = (value3 * 360) / (2 * PI); + value3old = trueHeading; + } + else{ + trueHeading = value3old; + } + // HDM value (Magnetic Heading) + if(valid4){ + magneticHeading = (value4 * 360) / (2 * PI); + value4old = magneticHeading; + } + else{ + speedOverGround = value4old; + } + // SOG value (Speed Over Ground) + if(valid5){ + speedOverGround = value5; + value5old = value5; + } + else{ + speedOverGround = value5old; + } + // DBT value (Depth Below Transducer) + if(valid6){ + depthBelowTransducer = value6; + value6old = value6; + } + else{ + depthBelowTransducer = value6old; + } + + // Prepare config values for URL + //*********************************************************** + + // Server settings + if(mapsource == "OBP Service"){ + server = "norbert-walter.dnshome.de"; + port = 80; + } + else if(mapsource == "Local Service"){ + server = String(ipAddress); + port = localPort; + } + else{ + server = "norbert-walter.dnshome.de"; + port = 80; + } + + // Type of navigation map + if(mapType == "Open Street Map"){ + mType = 1; // Map type + dType = 1; // Dithering type + } + else if(mapType == "Google Street"){ + mType = 3; + dType = 2; + } + else if(mapType == "Open Topo Map"){ + mType = 5; + dType = 2; + } + else if(mapType == "Stadimaps Toner"){ + mType = 7; + dType = 1; + } + else if(mapType == "Free Nautical Chart"){ + mType = 9; + dType = 1; + } + else{ + mType = 1; + dType = 1; + } + + // Map grid on/off + if(grid == true){ + mapGrid = 1; + } + else{ + mapGrid = 0; + } + + // Map orientation + if(orientation == "North Direction"){ + mapRot = 0; + // If true heading available then use HDT oterwise HDM + if(valid3 == true){ + symbolRot = trueHeading; + } + else{ + symbolRot = magneticHeading; + } + } + else if(orientation == "Travel Direction"){ + // If true heading available then use HDT oterwise HDM + if(valid3 == true){ + mapRot = trueHeading; + symbolRot = trueHeading; + } + else{ + mapRot = magneticHeading; + symbolRot = magneticHeading; + } + } + else{ + mapRot = 0; + // If true heading available then use HDT oterwise HDM + if(valid3 == true){ + symbolRot = trueHeading; + } + else{ + symbolRot = magneticHeading; + } + } + + // Load navigation map + //*********************************************************** + + // Prüfe WiFi-Verbindung (Thread-Safe) + // Diese Methode ist synchronisiert und blockiert maximal 1 Sekunde + bool wifiConnected = gwWifi.clientConnected(); + + if (!wifiConnected && !wifiConnectRequested) { + LOG_DEBUG(GwLog::LOG, "PageNavigation: WiFi not connected, attempting async connect"); + gwWifi.connectClientAsync(); + wifiConnectRequested = true; + } + + // URL to OBP Maps Converter + // For more details see: https://github.com/norbert-walter/maps-converter + String url = String("http://") + server + ":" + port + // OBP Server + String("/get_image_json?") + // Service: Output B&W picture as JSON (Base64 + gzip) + "zoom=" + zoom + // Default zoom level: 15 + "&lat=" + String(latitude, 6) + // Latitude + "&lon=" + String(longitude, 6) + // Longitude + "&mrot=" + mapRot + // Rotation angle navigation map in degree + "&mtype=" + mType + // Default Map: Open Street Map + "&dtype=" + dType + // Dithering type: Atkinson dithering + "&width=400" + // With navigation map + "&height=250" + // Height navigation map + "&cutout=0" + // No picture cutouts + "&tab=0" + // No tab size + "&border=2" + // Border line size: 2 pixel + "&symbol=2" + // Symbol: Triangle + "&srot=" + symbolRot + // Symbol rotation angle + "&ssize=15" + // Symbole size: 15 pixel + "&grid=" + mapGrid // Show grid: On + ; + + // Draw page + //*********************************************************** + + // ############### Draw Navigation Map ################ + + // Set display in partial refresh mode + getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update + getdisplay().setTextColor(commonData->fgcolor); + + // If a network connection to URL then load the navigation map + if (wifiConnected && net.fetchAndDecompressJson(url)) { + wifiConnectRequested = false; // Reset flag after successful connection + + auto& json = net.json(); // Extract JSON content + int numPix = json["number_pixels"] | 0; // Read number of pixels + imgWidth = json["width"] | 0; // Read width of image + imgHeight = json["height"] | 0; // Read height og image + + const char* b64src = json["picture_base64"].as(); // Read picture as Base64 content + size_t b64len = strlen(b64src); // Calculate length of Base64 content + // Copy Base64 content in PSRAM + char* b64 = (char*) heap_caps_malloc(b64len + 1, MALLOC_CAP_SPIRAM); // Allcate PSRAM for Base64 content + if (!b64) { + LOG_DEBUG(GwLog::ERROR,"Error PageNavigation: PSRAM alloc base64 failed"); + return PAGE_UPDATE; + } + memcpy(b64, b64src, b64len + 1); // Copy Base64 content in PSRAM + + // Set image buffer in PSRAM + //size_t imgSize = getdisplay().width() * getdisplay().height(); + size_t imgSize = numPix; // Calculate image size + uint8_t* imageData = (uint8_t*) heap_caps_malloc(imgSize, MALLOC_CAP_SPIRAM); // Allocate PSRAM for image + if (!imageData) { + LOG_DEBUG(GwLog::ERROR,"Error PageNavigation: PPSRAM alloc image buffer failed"); + free(b64); + return PAGE_UPDATE; + } + + // Decode Base64 content to image + size_t decodedSize = 0; + decoder.decodeBase64(b64, imageData, imgSize, decodedSize); + + // Copy actual navigation man to ackup map + imageBackupWidth = imgWidth; + imageBackupHeight = imgHeight; + imageBackupSize = imgSize; + if (decodedSize > 0) { + memcpy(imageBackupData, imageData, decodedSize); + imageBackupSize = decodedSize; + } + hasImageBackup = true; + lostCounter = 0; + + // Show image (navigation map) + getdisplay().drawBitmap(0, 25, imageData, imgWidth, imgHeight, commonData->fgcolor); + + // Clean PSRAM + free(b64); + free(imageData); + } + // If no network connection then use backup navigation map + else{ + // Show backup image (backup navigation map) + if (hasImageBackup) { + getdisplay().drawBitmap(0, 25, imageBackupData, imageBackupWidth, imageBackupHeight, commonData->fgcolor); + } + + // Show info: Connection lost when 5 page refreshes has a connection lost to the map server + // Short connection losts are uncritical + if(lostCounter >= 5){ + getdisplay().setFont(&Ubuntu_Bold12pt8b); + getdisplay().fillRect(200, 250 , 200, 25, commonData->fgcolor); // Black rect + getdisplay().fillRect(202, 252 , 196, 21, commonData->bgcolor); // White rect + getdisplay().setCursor(210, 270); + getdisplay().print("Map server lost"); + } + + lostCounter++; // Increment lost counter + + // Nur einmal pro Sekunde einen neuen Verbindungsversuch machen + if (!wifiConnectRequested) { + gwWifi.connectClientAsync(); + wifiConnectRequested = true; + } + } + + + // ############### Draw Values ################ + getdisplay().setFont(&Ubuntu_Bold12pt8b); + + // Show zoom level + getdisplay().fillRect(355, 25 , 45, 25, commonData->fgcolor); // Black rect + getdisplay().fillRect(357, 27 , 41, 21, commonData->bgcolor); // White rect + getdisplay().setCursor(364, 45); + getdisplay().print(zoom); + // If true heading available then use HDT oterwise HDM + if(showValues == true){ + // Frame + getdisplay().fillRect(0, 25 , 130, 65, commonData->fgcolor); // Black rect + getdisplay().fillRect(2, 27 , 126, 61, commonData->bgcolor); // White rect + if(valid3 == true){ + // HDT + getdisplay().setCursor(10, 45); + getdisplay().print(name3); + getdisplay().setCursor(70, 45); + getdisplay().print(svalue3); + } + else{ + // HDM + getdisplay().setCursor(10, 45); + getdisplay().print(name4); + getdisplay().setCursor(70, 45); + getdisplay().print(svalue4); + } + // SOG + getdisplay().setCursor(10, 65); + getdisplay().print(name5); + getdisplay().setCursor(70, 65); + getdisplay().print(svalue5); + // DBT + getdisplay().setCursor(10, 85); + getdisplay().print(name6); + getdisplay().setCursor(70, 85); + getdisplay().print(svalue6); + } + + return PAGE_UPDATE; + }; +}; + +// Initialize static member variable +bool PageNavigation::wifiConnectRequested = false; + +static Page *createPage(CommonData &common){ + return new PageNavigation(common); +}/** + * with the code below we make this page known to the PageTask + * we give it a type (name) that can be selected in the config + * we define which function is to be called + * and we provide the number of user parameters we expect + * this will be number of BoatValue pointers in pageData.values + */ +PageDescription registerPageNavigation( + "Navigation", // Page name + createPage, // Action + 0, // Number of bus values depends on selection in Web configuration + {"LAT","LON","HDT","HDM","SOG","DBT"}, // Bus values we need in the page + true // Show display header on/off +); + +#endif