mirror of
https://github.com/thooge/esp32-nmea2000-obp60.git
synced 2026-02-25 05:03:07 +01:00
Fix for GwWifi
This commit is contained in:
@@ -34,6 +34,6 @@ class GwWifi{
|
|||||||
bool connectClientAsync(); // Non-blocking version for other tasks
|
bool connectClientAsync(); // Non-blocking version for other tasks
|
||||||
String apIP();
|
String apIP();
|
||||||
bool isApActive(){return apActive;}
|
bool isApActive(){return apActive;}
|
||||||
bool isClientActive(){return wifiClient->asBoolean();}}
|
bool isClientActive(){return wifiClient->asBoolean();}
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
#include "NetworkClient.h"
|
#include "NetworkClient.h"
|
||||||
|
#include "GWWifi.h" // WiFi management (thread-safe)
|
||||||
|
|
||||||
|
extern GwWifi gwWifi; // Extern declaration of global WiFi instance
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "puff.h"
|
#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)
|
const size_t capacity = READLIMIT; // Read limit for data (can be adjusted in NetworkClient.h)
|
||||||
uint8_t* buffer = (uint8_t*)malloc(capacity);
|
uint8_t* buffer = (uint8_t*)malloc(capacity);
|
||||||
|
|
||||||
|
if (!gwWifi.clientConnected()) {
|
||||||
|
if (DEBUGING) {Serial.println("No WiFi connection");}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
if (DEBUG) {Serial.println("Malloc failed (buffer");}
|
if (DEBUGING) {Serial.println("Malloc failed buffer");}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +114,7 @@ bool NetworkClient::httpGetGzip(const String& url, uint8_t*& outData, size_t& ou
|
|||||||
len += read;
|
len += read;
|
||||||
lastData = millis();
|
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
|
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);
|
int res = puff(test, &testLen, buffer + headerOffset, &srcLen);
|
||||||
if (res == 0) {
|
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;
|
outData = test;
|
||||||
outLen = testLen;
|
outLen = testLen;
|
||||||
complete = true;
|
complete = true;
|
||||||
@@ -167,7 +175,7 @@ bool NetworkClient::fetchAndDecompressJson(const String& url) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DEBUG) {Serial.println("JSON OK!");}
|
if (DEBUGING) {Serial.println("JSON OK!");}
|
||||||
_valid = true;
|
_valid = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <HTTPClient.h>
|
#include <HTTPClient.h>
|
||||||
|
|
||||||
#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 READLIMIT 200000 // HTTP read limit in byte for gzip content (can be adjusted)
|
||||||
#define CONNECTIONTIMEOUT 3000 // Timeout in ms for HTTP connection
|
#define CONNECTIONTIMEOUT 3000 // Timeout in ms for HTTP connection
|
||||||
#define TCPREADTIMEOUT 2000 // Timeout in ms for read HTTP client stack
|
#define TCPREADTIMEOUT 2000 // Timeout in ms for read HTTP client stack
|
||||||
|
|||||||
@@ -4,13 +4,9 @@
|
|||||||
#include "OBP60Extensions.h"
|
#include "OBP60Extensions.h"
|
||||||
#include "NetworkClient.h" // Network connection
|
#include "NetworkClient.h" // Network connection
|
||||||
#include "ImageDecoder.h" // Image decoder for navigation map
|
#include "ImageDecoder.h" // Image decoder for navigation map
|
||||||
#include "GWWifi.h" // WiFi management (thread-safe)
|
|
||||||
|
|
||||||
#include "Logo_OBP_400x300_sw.h"
|
#include "Logo_OBP_400x300_sw.h"
|
||||||
|
|
||||||
// Extern declaration of global WiFi instance
|
|
||||||
extern GwWifi gwWifi;
|
|
||||||
|
|
||||||
// Defines for reading of navigation map
|
// Defines for reading of navigation map
|
||||||
#define JSON_BUFFER 30000 // Max buffer size for JSON content (30 kB picture + values)
|
#define JSON_BUFFER 30000 // Max buffer size for JSON content (30 kB picture + values)
|
||||||
NetworkClient net(JSON_BUFFER); // Define network client
|
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;
|
int imageBackupHeight = 0;
|
||||||
size_t imageBackupSize = 0;
|
size_t imageBackupSize = 0;
|
||||||
bool hasImageBackup = false;
|
bool hasImageBackup = false;
|
||||||
static bool wifiConnectRequested; // Track if WiFi connection was requested
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PageNavigation(CommonData &common){
|
PageNavigation(CommonData &common){
|
||||||
@@ -60,15 +55,12 @@ bool showValues = false; // Show values HDT, SOG, DBT in navigation map
|
|||||||
}
|
}
|
||||||
return 0; // Commit the key
|
return 0; // Commit the key
|
||||||
}
|
}
|
||||||
// Code for zoom +
|
// Code for zoom -
|
||||||
if(key == 2){
|
if(key == 2){
|
||||||
zoom ++; // Zoom +
|
zoom ++; // Zoom +
|
||||||
if(zoom >17){
|
if(zoom >17){
|
||||||
zoom = 17;
|
zoom = 17;
|
||||||
}
|
}
|
||||||
// Optional: Versuche WiFi-Verbindung nach Zoom-Änderung
|
|
||||||
// Dies ermöglicht eine neue Kartendarstellung
|
|
||||||
gwWifi.connectClientAsync();
|
|
||||||
return 0; // Commit the key
|
return 0; // Commit the key
|
||||||
}
|
}
|
||||||
if(key == 5){
|
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
|
zoom = zoomLevel; // Over write zoom level with setup value
|
||||||
showValues = showValuesMap; // Over write showValues with setup value
|
showValues = showValuesMap; // Over write showValues with setup value
|
||||||
firstRun = false; // Restet variable
|
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
|
// Local variables
|
||||||
@@ -359,16 +344,6 @@ bool showValues = false; // Show values HDT, SOG, DBT in navigation map
|
|||||||
// Load 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
|
// URL to OBP Maps Converter
|
||||||
// For more details see: https://github.com/norbert-walter/maps-converter
|
// For more details see: https://github.com/norbert-walter/maps-converter
|
||||||
String url = String("http://") + server + ":" + port + // OBP Server
|
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);
|
getdisplay().setTextColor(commonData->fgcolor);
|
||||||
|
|
||||||
// If a network connection to URL then load the navigation map
|
// If a network connection to URL then load the navigation map
|
||||||
if (wifiConnected && net.fetchAndDecompressJson(url)) {
|
if (net.fetchAndDecompressJson(url)) {
|
||||||
wifiConnectRequested = false; // Reset flag after successful connection
|
|
||||||
|
|
||||||
auto& json = net.json(); // Extract JSON content
|
auto& json = net.json(); // Extract JSON content
|
||||||
int numPix = json["number_pixels"] | 0; // Read number of pixels
|
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
|
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){
|
static Page *createPage(CommonData &common){
|
||||||
return new PageNavigation(common);
|
return new PageNavigation(common);
|
||||||
}/**
|
}/**
|
||||||
|
|||||||
543
lib/obp60task/PageNavigation_old.cpp
Normal file
543
lib/obp60task/PageNavigation_old.cpp
Normal file
@@ -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<const char*>(); // 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
|
||||||
Reference in New Issue
Block a user