mirror of
https://github.com/thooge/esp32-nmea2000-obp60.git
synced 2026-03-28 18:06:37 +01:00
More work on page anchor
This commit is contained in:
217
lib/obp60task/ConfigMenu.cpp
Normal file
217
lib/obp60task/ConfigMenu.cpp
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
/*
|
||||||
|
Menu system for online configuration
|
||||||
|
|
||||||
|
A menu consists of a list of menuitems.
|
||||||
|
|
||||||
|
Graphical representation is stored:
|
||||||
|
upper left corner: x, y
|
||||||
|
bounding box:
|
||||||
|
A menu consists of three columns
|
||||||
|
- menu text, if selected highlighted
|
||||||
|
- menu value with optional unit
|
||||||
|
- menu description or additional data for value
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "ConfigMenu.h"
|
||||||
|
|
||||||
|
ConfigMenuItem::ConfigMenuItem(String itemtype, String itemlabel, uint16_t itemval, String itemunit) {
|
||||||
|
if (! (itemtype == "int" or itemtype == "bool")) {
|
||||||
|
valtype = "int";
|
||||||
|
} else {
|
||||||
|
valtype = itemtype;
|
||||||
|
}
|
||||||
|
label = itemlabel;
|
||||||
|
min = 0;
|
||||||
|
max = std::numeric_limits<uint16_t>::max();
|
||||||
|
value = itemval;
|
||||||
|
unit = itemunit;
|
||||||
|
step = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigMenuItem::setRange(uint16_t valmin, uint16_t valmax, std::vector<uint16_t> valsteps) {
|
||||||
|
min = valmin;
|
||||||
|
max = valmax;
|
||||||
|
steps = valsteps;
|
||||||
|
step = steps[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ConfigMenuItem::checkRange(uint16_t checkval) {
|
||||||
|
return (checkval >= min) and (checkval <= max);
|
||||||
|
}
|
||||||
|
|
||||||
|
String ConfigMenuItem::getLabel() {
|
||||||
|
return label;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint16_t ConfigMenuItem::getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConfigMenuItem::setValue(uint16_t newval) {
|
||||||
|
if (valtype == "int") {
|
||||||
|
if (newval >= min and newval <= max) {
|
||||||
|
value = newval;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false; // out of range
|
||||||
|
} else if (valtype == "bool") {
|
||||||
|
value = (newval != 0) ? 1 : 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false; // invalid type
|
||||||
|
};
|
||||||
|
|
||||||
|
void ConfigMenuItem::incValue() {
|
||||||
|
// increase value by step
|
||||||
|
if (valtype == "int") {
|
||||||
|
if (value + step < max) {
|
||||||
|
value += step;
|
||||||
|
} else {
|
||||||
|
value = max;
|
||||||
|
}
|
||||||
|
} else if (valtype == "bool") {
|
||||||
|
value = !value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void ConfigMenuItem::decValue() {
|
||||||
|
// decrease value by step
|
||||||
|
if (valtype == "int") {
|
||||||
|
if (value - step > min) {
|
||||||
|
value -= step;
|
||||||
|
} else {
|
||||||
|
value = min;
|
||||||
|
}
|
||||||
|
} else if (valtype == "bool") {
|
||||||
|
value = !value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
String ConfigMenuItem::getUnit() {
|
||||||
|
return unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t ConfigMenuItem::getStep() {
|
||||||
|
return step;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigMenuItem::setStep(uint16_t newstep) {
|
||||||
|
if (std::find(steps.begin(), steps.end(), newstep) == steps.end()) {
|
||||||
|
return; // invalid step: not in list of possible steps
|
||||||
|
}
|
||||||
|
step = newstep;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t ConfigMenuItem::getPos() {
|
||||||
|
return position;
|
||||||
|
};
|
||||||
|
|
||||||
|
void ConfigMenuItem::setPos(int8_t newpos) {
|
||||||
|
position = newpos;
|
||||||
|
};
|
||||||
|
|
||||||
|
String ConfigMenuItem::getType() {
|
||||||
|
return valtype;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigMenu::ConfigMenu(String menutitle, uint16_t menu_x, uint16_t menu_y) {
|
||||||
|
title = menutitle;
|
||||||
|
x = menu_x;
|
||||||
|
y = menu_y;
|
||||||
|
};
|
||||||
|
|
||||||
|
ConfigMenuItem* ConfigMenu::addItem(String key, String label, String valtype, uint16_t val, String valunit) {
|
||||||
|
if (items.find(key) != items.end()) {
|
||||||
|
// duplicate keys not allowed
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
ConfigMenuItem *itm = new ConfigMenuItem(valtype, label, val, valunit);
|
||||||
|
items.insert(std::pair<String, ConfigMenuItem*>(key, itm));
|
||||||
|
// Append key to index, index starting with 0
|
||||||
|
int8_t ix = items.size() - 1;
|
||||||
|
index[ix] = key;
|
||||||
|
itm->setPos(ix);
|
||||||
|
return itm;
|
||||||
|
};
|
||||||
|
|
||||||
|
void ConfigMenu::setItemDimension(uint16_t itemwidth, uint16_t itemheight) {
|
||||||
|
w = itemwidth;
|
||||||
|
h = itemheight;
|
||||||
|
};
|
||||||
|
|
||||||
|
void ConfigMenu::setItemActive(String key) {
|
||||||
|
if (items.find(key) != items.end()) {
|
||||||
|
activeitem = items[key]->getPos();
|
||||||
|
} else {
|
||||||
|
activeitem = -1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int8_t ConfigMenu::getActiveIndex() {
|
||||||
|
return activeitem;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigMenuItem* ConfigMenu::getActiveItem() {
|
||||||
|
if (activeitem < 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return items[index[activeitem]];
|
||||||
|
};
|
||||||
|
|
||||||
|
ConfigMenuItem* ConfigMenu::getItemByIndex(uint8_t ix) {
|
||||||
|
if (ix > index.size() - 1) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return items[index[ix]];
|
||||||
|
};
|
||||||
|
|
||||||
|
ConfigMenuItem* ConfigMenu::getItemByKey(String key) {
|
||||||
|
if (items.find(key) == items.end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return items[key];
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t ConfigMenu::getItemCount() {
|
||||||
|
return items.size();
|
||||||
|
};
|
||||||
|
|
||||||
|
void ConfigMenu::goPrev() {
|
||||||
|
if (activeitem == 0) {
|
||||||
|
activeitem = items.size() - 1;
|
||||||
|
} else {
|
||||||
|
activeitem--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigMenu::goNext() {
|
||||||
|
if (activeitem == items.size() - 1) {
|
||||||
|
activeitem = 0;
|
||||||
|
} else {
|
||||||
|
activeitem++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Point ConfigMenu::getXY() {
|
||||||
|
return {static_cast<double>(x), static_cast<double>(y)};
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect ConfigMenu::getRect() {
|
||||||
|
return {static_cast<double>(x), static_cast<double>(y),
|
||||||
|
static_cast<double>(w), static_cast<double>(h)};
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect ConfigMenu::getItemRect(int8_t index) {
|
||||||
|
return {static_cast<double>(x), static_cast<double>(y + index * h),
|
||||||
|
static_cast<double>(w), static_cast<double>(h)};
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigMenu::setCallback(void (*callback)()) {
|
||||||
|
fptrCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigMenu::storeValues() {
|
||||||
|
if (fptrCallback) {
|
||||||
|
fptrCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
67
lib/obp60task/ConfigMenu.h
Normal file
67
lib/obp60task/ConfigMenu.h
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include "Graphics.h" // for Point and Rect
|
||||||
|
|
||||||
|
class ConfigMenuItem {
|
||||||
|
private:
|
||||||
|
String label;
|
||||||
|
uint16_t value;
|
||||||
|
String unit;
|
||||||
|
String desc; // optional data to display
|
||||||
|
String valtype; // "int" | "bool" -> TODO "list"
|
||||||
|
uint16_t min;
|
||||||
|
uint16_t max;
|
||||||
|
std::vector<uint16_t> steps;
|
||||||
|
uint16_t step;
|
||||||
|
int8_t position; // counted fom 0
|
||||||
|
|
||||||
|
public:
|
||||||
|
ConfigMenuItem(String itemtype, String itemlabel, uint16_t itemval, String itemunit);
|
||||||
|
void setRange(uint16_t valmin, uint16_t valmax, std::vector<uint16_t> steps);
|
||||||
|
bool checkRange(uint16_t checkval);
|
||||||
|
String getLabel();
|
||||||
|
uint16_t getValue();
|
||||||
|
bool setValue(uint16_t newval);
|
||||||
|
void incValue();
|
||||||
|
void decValue();
|
||||||
|
String getUnit();
|
||||||
|
uint16_t getStep();
|
||||||
|
void setStep(uint16_t newstep);
|
||||||
|
int8_t getPos();
|
||||||
|
void setPos(int8_t newpos);
|
||||||
|
String getType();
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConfigMenu {
|
||||||
|
private:
|
||||||
|
String title;
|
||||||
|
std::map <String,ConfigMenuItem*> items;
|
||||||
|
std::map <uint8_t,String> index;
|
||||||
|
int8_t activeitem = -1; // refers to position of item
|
||||||
|
uint16_t x;
|
||||||
|
uint16_t y;
|
||||||
|
uint16_t w;
|
||||||
|
uint16_t h;
|
||||||
|
void (*fptrCallback)();
|
||||||
|
|
||||||
|
public:
|
||||||
|
ConfigMenu(String title, uint16_t menu_x, uint16_t menu_y);
|
||||||
|
ConfigMenuItem* addItem(String key, String label, String valtype, uint16_t val, String valunit);
|
||||||
|
void setItemDimension(uint16_t itemwidth, uint16_t itemheight);
|
||||||
|
int8_t getActiveIndex();
|
||||||
|
void setItemActive(String key);
|
||||||
|
ConfigMenuItem* getActiveItem();
|
||||||
|
ConfigMenuItem* getItemByIndex(uint8_t index);
|
||||||
|
ConfigMenuItem* getItemByKey(String key);
|
||||||
|
uint8_t getItemCount();
|
||||||
|
void goPrev();
|
||||||
|
void goNext();
|
||||||
|
Point getXY();
|
||||||
|
Rect getRect();
|
||||||
|
Rect getItemRect(int8_t index);
|
||||||
|
void setCallback(void (*callback)());
|
||||||
|
void storeValues();
|
||||||
|
};
|
||||||
@@ -475,6 +475,30 @@ std::vector<String> wordwrap(String &line, uint16_t maxwidth) {
|
|||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function to just get the exact width of a string
|
||||||
|
uint16_t getStringPixelWidth(const char* str, const GFXfont* font) {
|
||||||
|
int16_t minx = INT16_MAX;
|
||||||
|
int16_t maxx = INT16_MIN;
|
||||||
|
int16_t cursor_x = 0;
|
||||||
|
while (*str) {
|
||||||
|
char c = *str++;
|
||||||
|
if (c < font->first || c > font->last) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
GFXglyph* glyph = &font->glyph[c - font->first];
|
||||||
|
if (glyph->width > 0) {
|
||||||
|
int16_t glyphStart = cursor_x + glyph->xOffset;
|
||||||
|
int16_t glyphEnd = glyphStart + glyph->width;
|
||||||
|
if (glyphStart < minx) minx = glyphStart;
|
||||||
|
if (glyphEnd > maxx) maxx = glyphEnd;
|
||||||
|
}
|
||||||
|
cursor_x += glyph->xAdvance;
|
||||||
|
}
|
||||||
|
if (minx > maxx)
|
||||||
|
return 0;
|
||||||
|
return maxx - minx;
|
||||||
|
}
|
||||||
|
|
||||||
// Draw centered text
|
// Draw centered text
|
||||||
void drawTextCenter(int16_t cx, int16_t cy, String text) {
|
void drawTextCenter(int16_t cx, int16_t cy, String text) {
|
||||||
int16_t x1, y1;
|
int16_t x1, y1;
|
||||||
@@ -638,20 +662,19 @@ void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatVa
|
|||||||
// Date and time
|
// Date and time
|
||||||
String fmttype = commonData.config->getString(commonData.config->dateFormat);
|
String fmttype = commonData.config->getString(commonData.config->dateFormat);
|
||||||
String timesource = commonData.config->getString(commonData.config->timeSource);
|
String timesource = commonData.config->getString(commonData.config->timeSource);
|
||||||
double tz = commonData.config->getString(commonData.config->timeZone).toDouble();
|
|
||||||
getdisplay().setTextColor(commonData.fgcolor);
|
getdisplay().setTextColor(commonData.fgcolor);
|
||||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||||
getdisplay().setCursor(230, 15);
|
getdisplay().setCursor(230, 15);
|
||||||
if (timesource == "RTC" or timesource == "iRTC") {
|
if (timesource == "RTC" or timesource == "iRTC") {
|
||||||
// TODO take DST into account
|
// TODO take DST into account
|
||||||
if (commonData.data.rtcValid) {
|
if (commonData.data.rtcValid) {
|
||||||
time_t tv = mktime(&commonData.data.rtcTime) + (int)(tz * 3600);
|
time_t tv = mktime(&commonData.data.rtcTime) + (int)(commonData.tz * 3600);
|
||||||
struct tm *local_tm = localtime(&tv);
|
struct tm *local_tm = localtime(&tv);
|
||||||
getdisplay().print(formatTime('m', local_tm->tm_hour, local_tm->tm_min, 0));
|
getdisplay().print(formatTime('m', local_tm->tm_hour, local_tm->tm_min, 0));
|
||||||
getdisplay().print(" ");
|
getdisplay().print(" ");
|
||||||
getdisplay().print(formatDate(fmttype, local_tm->tm_year + 1900, local_tm->tm_mon + 1, local_tm->tm_mday));
|
getdisplay().print(formatDate(fmttype, local_tm->tm_year + 1900, local_tm->tm_mon + 1, local_tm->tm_mday));
|
||||||
getdisplay().print(" ");
|
getdisplay().print(" ");
|
||||||
getdisplay().print(tz == 0 ? "UTC" : "LOT");
|
getdisplay().print(commonData.tz == 0 ? "UTC" : "LOT");
|
||||||
} else {
|
} else {
|
||||||
drawTextRalign(396, 15, "RTC invalid");
|
drawTextRalign(396, 15, "RTC invalid");
|
||||||
}
|
}
|
||||||
@@ -666,7 +689,7 @@ void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatVa
|
|||||||
getdisplay().print(" ");
|
getdisplay().print(" ");
|
||||||
getdisplay().print(actdate);
|
getdisplay().print(actdate);
|
||||||
getdisplay().print(" ");
|
getdisplay().print(" ");
|
||||||
getdisplay().print(tz == 0 ? "UTC" : "LOT");
|
getdisplay().print(commonData.tz == 0 ? "UTC" : "LOT");
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if(commonData.config->getBool(commonData.config->useSimuData) == true){
|
if(commonData.config->getBool(commonData.config->useSimuData) == true){
|
||||||
|
|||||||
@@ -8,36 +8,40 @@
|
|||||||
|
|
||||||
Boatdata used
|
Boatdata used
|
||||||
DBS - Water depth
|
DBS - Water depth
|
||||||
HDT - Boat heading
|
HDT - Boat heading, true
|
||||||
AWS - Wind strength; Boat not moving so we assume AWS=TWS and AWD=TWD
|
AWS - Wind strength; Boat not moving so we assume AWS=TWS and AWD=TWD
|
||||||
AWD - Wind direction
|
AWD - Wind direction
|
||||||
LAT/LON - Boat position, current
|
LAT/LON - Boat position, current
|
||||||
HDOP - Position error
|
HDOP - Position error, horizontal
|
||||||
|
|
||||||
Drop / raise function in device OBP40 has to be done inside
|
Raise function in device OBP40 has to be done inside config mode
|
||||||
config mode because of limited number of buttons.
|
because of limited number of buttons.
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
gzip for data transfer,
|
gzip for data transfer,
|
||||||
|
miniz.c from ROM?
|
||||||
manually inflating with tinflate from ROM
|
manually inflating with tinflate from ROM
|
||||||
Save position in FRAM
|
Save position in FRAM
|
||||||
Alarm: gps fix lost
|
Alarm: gps fix lost
|
||||||
switch unit feet/meter
|
switch unit feet/meter
|
||||||
force map update if new position is different from old position by
|
force map update if new position is different from old position by
|
||||||
a certain level (e.g. 10m)
|
a certain level (e.g. 10m)
|
||||||
|
windlass integration
|
||||||
|
chain counter
|
||||||
|
|
||||||
Map service options / URL parameters
|
Map service options / URL parameters
|
||||||
- mandatory
|
- mandatory
|
||||||
lat: latitude
|
lat: latitude
|
||||||
lon: longitude
|
lon: longitude
|
||||||
width: image width in px
|
width: image width in px (400)
|
||||||
height: image height in px
|
height: image height in px (300)
|
||||||
- optional
|
- optional
|
||||||
zoom: zoom level, default 15
|
zoom: zoom level, default 15
|
||||||
mrot: map rotation angle in degrees
|
mrot: map rotation angle in degrees
|
||||||
mtype: map type, default="Open Street Map"
|
mtype: map type, default="Open Street Map"
|
||||||
dtype: dithering type, default="Atkinson"
|
dtype: dithering type, default="Atkinson"
|
||||||
cutout: image cutout type 0=none
|
cutout: image cutout type 0=none
|
||||||
|
alpha: alpha blending for cutout
|
||||||
tab: tab size, 0=none
|
tab: tab size, 0=none
|
||||||
border: border line zize in px, default 2
|
border: border line zize in px, default 2
|
||||||
symbol: synmol number, default=2 triangle
|
symbol: synmol number, default=2 triangle
|
||||||
@@ -51,6 +55,12 @@
|
|||||||
#include <HTTPClient.h>
|
#include <HTTPClient.h>
|
||||||
#include "Pagedata.h"
|
#include "Pagedata.h"
|
||||||
#include "OBP60Extensions.h"
|
#include "OBP60Extensions.h"
|
||||||
|
#include "ConfigMenu.h"
|
||||||
|
// #include "miniz.h" // devices without PSRAM use <rom/miniz.h>
|
||||||
|
|
||||||
|
// extern "C" {
|
||||||
|
#include "rom/miniz.h"
|
||||||
|
// }
|
||||||
|
|
||||||
#define anchor_width 16
|
#define anchor_width 16
|
||||||
#define anchor_height 16
|
#define anchor_height 16
|
||||||
@@ -64,6 +74,7 @@ class PageAnchor : public Page
|
|||||||
private:
|
private:
|
||||||
char mode = 'N'; // (N)ormal, (C)onfig
|
char mode = 'N'; // (N)ormal, (C)onfig
|
||||||
int8_t editmode = -1; // marker for menu/edit/set function
|
int8_t editmode = -1; // marker for menu/edit/set function
|
||||||
|
ConfigMenu *menu;
|
||||||
|
|
||||||
//uint8_t *mapbuf = new uint8_t[10000]; // 8450 Byte without header
|
//uint8_t *mapbuf = new uint8_t[10000]; // 8450 Byte without header
|
||||||
//int mapbuf_size = 10000;
|
//int mapbuf_size = 10000;
|
||||||
@@ -97,24 +108,38 @@ private:
|
|||||||
double anchor_depth;
|
double anchor_depth;
|
||||||
int anchor_ts; // time stamp anchor dropped
|
int anchor_ts; // time stamp anchor dropped
|
||||||
|
|
||||||
|
GwApi::BoatValue *bv_dbs; // depth below surface
|
||||||
|
GwApi::BoatValue *bv_hdt; // true heading
|
||||||
|
GwApi::BoatValue *bv_aws; // apparent wind speed
|
||||||
|
GwApi::BoatValue *bv_awd; // apparent wind direction
|
||||||
|
GwApi::BoatValue *bv_lat; // latitude, current
|
||||||
|
GwApi::BoatValue *bv_lon; // longitude, current
|
||||||
|
GwApi::BoatValue *bv_hdop; // horizontal position error
|
||||||
|
|
||||||
|
bool simulation = false;
|
||||||
|
int last_mapsize = 0;
|
||||||
|
String errmsg = "";
|
||||||
|
int loops;
|
||||||
|
int readbytes = 0;
|
||||||
|
|
||||||
void displayModeNormal(PageData &pageData) {
|
void displayModeNormal(PageData &pageData) {
|
||||||
|
|
||||||
// Boatvalues: DBS, HDT, AWS, AWD, LAT, LON, HDOP
|
// get currrent boatvalues
|
||||||
GwApi::BoatValue *bv_dbs = pageData.values[0]; // DBS
|
bv_dbs = pageData.values[0]; // DBS
|
||||||
String sval_dbs = formatValue(bv_dbs, *commonData).svalue;
|
String sval_dbs = formatValue(bv_dbs, *commonData).svalue;
|
||||||
String sunit_dbs = formatValue(bv_dbs, *commonData).unit;
|
String sunit_dbs = formatValue(bv_dbs, *commonData).unit;
|
||||||
GwApi::BoatValue *bv_hdt = pageData.values[1]; // HDT
|
bv_hdt = pageData.values[1]; // HDT
|
||||||
String sval_hdt = formatValue(bv_hdt, *commonData).svalue;
|
String sval_hdt = formatValue(bv_hdt, *commonData).svalue;
|
||||||
GwApi::BoatValue *bv_aws = pageData.values[2]; // AWS
|
bv_aws = pageData.values[2]; // AWS
|
||||||
String sval_aws = formatValue(bv_aws, *commonData).svalue;
|
String sval_aws = formatValue(bv_aws, *commonData).svalue;
|
||||||
String sunit_aws = formatValue(bv_aws, *commonData).unit;
|
String sunit_aws = formatValue(bv_aws, *commonData).unit;
|
||||||
GwApi::BoatValue *bv_awd = pageData.values[3]; // AWD
|
bv_awd = pageData.values[3]; // AWD
|
||||||
String sval_awd = formatValue(bv_awd, *commonData).svalue;
|
String sval_awd = formatValue(bv_awd, *commonData).svalue;
|
||||||
GwApi::BoatValue *bv_lat = pageData.values[4]; // LAT
|
bv_lat = pageData.values[4]; // LAT
|
||||||
String sval_lat = formatValue(bv_lat, *commonData).svalue;
|
String sval_lat = formatValue(bv_lat, *commonData).svalue;
|
||||||
GwApi::BoatValue *bv_lon = pageData.values[5]; // LON
|
bv_lon = pageData.values[5]; // LON
|
||||||
String sval_lon = formatValue(bv_lon, *commonData).svalue;
|
String sval_lon = formatValue(bv_lon, *commonData).svalue;
|
||||||
GwApi::BoatValue *bv_hdop = pageData.values[6]; // HDOP
|
bv_hdop = pageData.values[6]; // HDOP
|
||||||
String sval_hdop = formatValue(bv_hdop, *commonData).svalue;
|
String sval_hdop = formatValue(bv_hdop, *commonData).svalue;
|
||||||
String sunit_hdop = formatValue(bv_hdop, *commonData).unit;
|
String sunit_hdop = formatValue(bv_hdop, *commonData).unit;
|
||||||
|
|
||||||
@@ -156,7 +181,7 @@ private:
|
|||||||
{b.x + 5, b.y - 10},
|
{b.x + 5, b.y - 10},
|
||||||
{b.x + 5, b.y}
|
{b.x + 5, b.y}
|
||||||
};
|
};
|
||||||
//rotatePoints und dann Linien zeichnen
|
//rotatePoints then draw lines
|
||||||
// TODO rotate boat according to current heading
|
// TODO rotate boat according to current heading
|
||||||
if (bv_hdt->valid) {
|
if (bv_hdt->valid) {
|
||||||
if (map_valid) {
|
if (map_valid) {
|
||||||
@@ -165,7 +190,7 @@ private:
|
|||||||
}
|
}
|
||||||
drawPoly(rotatePoints(c, pts_boat, bv_hdt->value * RAD_TO_DEG), commonData->fgcolor);
|
drawPoly(rotatePoints(c, pts_boat, bv_hdt->value * RAD_TO_DEG), commonData->fgcolor);
|
||||||
} else {
|
} else {
|
||||||
// no heading available draw north oriented
|
// no heading available: draw north oriented
|
||||||
if (map_valid) {
|
if (map_valid) {
|
||||||
getdisplay().fillCircle(b.x, b.y - 8, 10, commonData->bgcolor);
|
getdisplay().fillCircle(b.x, b.y - 8, 10, commonData->bgcolor);
|
||||||
}
|
}
|
||||||
@@ -276,23 +301,54 @@ private:
|
|||||||
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||||
|
|
||||||
getdisplay().setCursor(8, 250);
|
getdisplay().setCursor(8, 260);
|
||||||
getdisplay().print("Press MODE to leave config");
|
getdisplay().print("Press BACK to leave config");
|
||||||
|
|
||||||
getdisplay().setCursor(8, 68);
|
/* getdisplay().setCursor(8, 68);
|
||||||
getdisplay().printf("Server: %s", server_name.c_str());
|
getdisplay().printf("Server: %s", server_name.c_str());
|
||||||
getdisplay().setCursor(8, 88);
|
getdisplay().setCursor(8, 88);
|
||||||
getdisplay().printf("Port: %d", server_port);
|
getdisplay().printf("Port: %d", server_port);
|
||||||
getdisplay().setCursor(8, 108);
|
getdisplay().setCursor(8, 108);
|
||||||
getdisplay().printf("Tilepath: %s", tile_path.c_str());
|
getdisplay().printf("Tilepath: %s", tile_path.c_str());
|
||||||
|
getdisplay().setCursor(8, 128);
|
||||||
|
getdisplay().printf("Last mapsize: %d", last_mapsize);
|
||||||
|
getdisplay().setCursor(8, 148);
|
||||||
|
getdisplay().printf("Last error: %s", errmsg);
|
||||||
|
getdisplay().setCursor(8, 168);
|
||||||
|
getdisplay().printf("Loops: %d, Readbytes: %d", loops, readbytes);
|
||||||
|
*/
|
||||||
|
|
||||||
GwApi::BoatValue *bv_lat = pageData.values[4]; // LAT
|
GwApi::BoatValue *bv_lat = pageData.values[4]; // LAT
|
||||||
GwApi::BoatValue *bv_lon = pageData.values[5]; // LON
|
GwApi::BoatValue *bv_lon = pageData.values[5]; // LON
|
||||||
if (!bv_lat->valid or !bv_lon->valid) {
|
if (!bv_lat->valid or !bv_lon->valid) {
|
||||||
getdisplay().setCursor(8, 128);
|
getdisplay().setCursor(8, 228);
|
||||||
getdisplay().printf("No valid position: background map disabled");
|
getdisplay().printf("No valid position: background map disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Display menu
|
||||||
|
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||||
|
for (int i = 0 ; i < menu->getItemCount(); i++) {
|
||||||
|
ConfigMenuItem *itm = menu->getItemByIndex(i);
|
||||||
|
if (!itm) {
|
||||||
|
commonData->logger->logDebug(GwLog::ERROR, "Menu item not found: %d", i);
|
||||||
|
} else {
|
||||||
|
Rect r = menu->getItemRect(i);
|
||||||
|
bool inverted = (i == menu->getActiveIndex());
|
||||||
|
drawTextBoxed(r, itm->getLabel(), commonData->fgcolor, commonData->bgcolor, inverted, false);
|
||||||
|
if (inverted and editmode > 0) {
|
||||||
|
// triangle as edit marker
|
||||||
|
getdisplay().fillTriangle(r.x + r.w + 20, r.y, r.x + r.w + 30, r.y + r.h / 2, r.x + r.w + 20, r.y + r.h, commonData->fgcolor);
|
||||||
|
}
|
||||||
|
getdisplay().setCursor(r.x + r.w + 40, r.y + r.h - 4);
|
||||||
|
if (itm->getType() == "int") {
|
||||||
|
getdisplay().print(itm->getValue());
|
||||||
|
getdisplay().print(itm->getUnit());
|
||||||
|
} else {
|
||||||
|
getdisplay().print(itm->getValue() == 0 ? "No" : "Yes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -321,12 +377,32 @@ public:
|
|||||||
lengthformat = common.config->getString(common.config->lengthFormat);
|
lengthformat = common.config->getString(common.config->lengthFormat);
|
||||||
chain_length = common.config->getInt(common.config->chainLength);
|
chain_length = common.config->getInt(common.config->chainLength);
|
||||||
|
|
||||||
|
if (simulation) {
|
||||||
|
map_lat = 53.56938345759218;
|
||||||
|
map_lon = 9.679658234303275;
|
||||||
|
}
|
||||||
|
|
||||||
canvas = new GFXcanvas1(264, 260); // Byte aligned, no padding!
|
canvas = new GFXcanvas1(264, 260); // Byte aligned, no padding!
|
||||||
|
|
||||||
|
// Initialize config menu
|
||||||
|
menu = new ConfigMenu("Options", 40, 80);
|
||||||
|
menu->setItemDimension(150, 20);
|
||||||
|
ConfigMenuItem *newitem;
|
||||||
|
newitem = menu->addItem("chain", "Chain out", "int", 0, "m");
|
||||||
|
newitem->setRange(0, 200, {1, 2, 5, 10});
|
||||||
|
newitem = menu->addItem("alarm", "Alarm", "bool", 0, "");
|
||||||
|
newitem = menu->addItem("alarm", "Alarm range", "int", 50, "m");
|
||||||
|
newitem->setRange(0, 200, {1, 2, 5, 10});
|
||||||
|
newitem = menu->addItem("raise", "Raise Anchor", "bool", 0, "");
|
||||||
|
newitem = menu->addItem("zoom", "Zoom", "int", 15, "");
|
||||||
|
newitem->setRange(14, 17, {1});
|
||||||
|
menu->setItemActive("chain");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupKeys(){
|
void setupKeys(){
|
||||||
Page::setupKeys();
|
Page::setupKeys();
|
||||||
commonData->keydata[0].label = "MODE";
|
commonData->keydata[0].label = "CFG";
|
||||||
#ifdef BOARD_OBP40S3
|
#ifdef BOARD_OBP40S3
|
||||||
commonData->keydata[1].label = "DROP";
|
commonData->keydata[1].label = "DROP";
|
||||||
#endif
|
#endif
|
||||||
@@ -337,13 +413,18 @@ public:
|
|||||||
|
|
||||||
// TODO OBP40 / OBP60 different handling
|
// TODO OBP40 / OBP60 different handling
|
||||||
int handleKey(int key) {
|
int handleKey(int key) {
|
||||||
|
commonData->logger->logDebug(GwLog::LOG, "Page Anchor handle key %d", key);
|
||||||
if (key == 1) { // Switch between normal and config mode
|
if (key == 1) { // Switch between normal and config mode
|
||||||
if (mode == 'N') {
|
if (mode == 'N') {
|
||||||
mode = 'C';
|
mode = 'C';
|
||||||
|
#ifdef BOARD_OBP40S3
|
||||||
|
commonData->keydata[0].label = "BACK";
|
||||||
commonData->keydata[1].label = "EDIT";
|
commonData->keydata[1].label = "EDIT";
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
mode = 'N';
|
mode = 'N';
|
||||||
#ifdef BOARD_OBP40S3
|
#ifdef BOARD_OBP40S3
|
||||||
|
commonData->keydata[0].label = "CFG";
|
||||||
commonData->keydata[1].label = anchor_set ? "RAISE": "DROP";
|
commonData->keydata[1].label = anchor_set ? "RAISE": "DROP";
|
||||||
#endif
|
#endif
|
||||||
#ifdef BOARD_OBP60S3
|
#ifdef BOARD_OBP60S3
|
||||||
@@ -353,9 +434,55 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (key == 2) {
|
if (key == 2) {
|
||||||
|
if (mode == 'N') {
|
||||||
anchor_set = !anchor_set;
|
anchor_set = !anchor_set;
|
||||||
commonData->keydata[1].label = anchor_set ? "RAISE": "DROP";
|
commonData->keydata[1].label = anchor_set ? "ALARM": "DROP";
|
||||||
|
if (anchor_set) {
|
||||||
|
anchor_lat = bv_lat->value;
|
||||||
|
anchor_lon = bv_lon->value;
|
||||||
|
anchor_depth = bv_dbs->value;
|
||||||
|
// TODO set timestamp
|
||||||
|
// anchor_ts =
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (mode == 'C') {
|
||||||
|
// Change edit mode
|
||||||
|
if (editmode > 0) {
|
||||||
|
editmode = 0;
|
||||||
|
commonData->keydata[1].label = "EDIT";
|
||||||
|
} else {
|
||||||
|
editmode = 1;
|
||||||
|
commonData->keydata[1].label = "OK";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (key == 9) {
|
||||||
|
// OBP40 Down
|
||||||
|
if (mode == 'C') {
|
||||||
|
if (editmode > 0) {
|
||||||
|
// decrease current menu item
|
||||||
|
menu->getActiveItem()->decValue();
|
||||||
|
} else {
|
||||||
|
// move to next menu item
|
||||||
|
menu->goNext();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (key == 10) {
|
||||||
|
// OBP40 Up
|
||||||
|
if (mode == 'C') {
|
||||||
|
if (editmode > 0) {
|
||||||
|
// increase current menu item
|
||||||
|
ConfigMenuItem *itm = menu->getActiveItem();
|
||||||
|
commonData->logger->logDebug(GwLog::LOG, "step = %d", itm->getStep());
|
||||||
|
itm->incValue();
|
||||||
|
} else {
|
||||||
|
// move to previous menu item
|
||||||
|
menu->goPrev();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Code for keylock
|
// Code for keylock
|
||||||
if (key == 11) {
|
if (key == 11) {
|
||||||
@@ -386,26 +513,167 @@ public:
|
|||||||
}
|
}
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
HTTPClient http;
|
HTTPClient http;
|
||||||
|
const char* headerKeys[] = { "Content-Encoding", "Content-Length" };
|
||||||
|
http.collectHeaders(headerKeys, 2);
|
||||||
String url = "http://" + server_name + "/" + tile_path;
|
String url = "http://" + server_name + "/" + tile_path;
|
||||||
String parameter = "?lat=" + String(lat, 6) + "&lon=" + String(lon, 6)+ "&zoom=" + String(zoom)
|
String parameter = "?lat=" + String(lat, 6) + "&lon=" + String(lon, 6)+ "&zoom=" + String(zoom)
|
||||||
+ "&width=" + String(map_width) + "&height=" + String(map_height);
|
+ "&width=" + String(map_width) + "&height=" + String(map_height);
|
||||||
commonData->logger->logDebug(GwLog::LOG, "HTTP query: %s", String(url + parameter).c_str());
|
commonData->logger->logDebug(GwLog::LOG, "HTTP query: %s", String(url + parameter).c_str());
|
||||||
http.begin(url + parameter);
|
http.begin(url + parameter);
|
||||||
// http.SetAcceptEncoding("gzip");
|
http.addHeader("Accept-Encoding", "deflate");
|
||||||
// TODO miniz.c from ROM
|
|
||||||
int httpCode = http.GET();
|
int httpCode = http.GET();
|
||||||
if (httpCode > 0) {
|
if (httpCode > 0) {
|
||||||
|
commonData->logger->logDebug(GwLog::LOG, "HTTP GET result code: %d", httpCode);
|
||||||
if (httpCode == HTTP_CODE_OK) {
|
if (httpCode == HTTP_CODE_OK) {
|
||||||
WiFiClient* stream = http.getStreamPtr();
|
WiFiClient* stream = http.getStreamPtr();
|
||||||
int size = http.getSize();
|
int size = http.getSize();
|
||||||
commonData->logger->logDebug(GwLog::LOG, "HTTP get size: %d", size);
|
String encoding = http.header("Content-Encoding");
|
||||||
// header: P4<LF><width> <height><LF> (e.g. 11 byte)
|
commonData->logger->logDebug(GwLog::LOG, "HTTP size: %d, encoding: '%s'", size, encoding);
|
||||||
|
bool is_gzip = encoding.equalsIgnoreCase("deflate");
|
||||||
|
|
||||||
uint8_t header[14]; // max: P4<LF>wwww wwww<LF>
|
uint8_t header[14]; // max: P4<LF>wwww wwww<LF>
|
||||||
bool header_read = false;
|
|
||||||
int header_size = 0;
|
int header_size = 0;
|
||||||
uint8_t* buf = canvas->getBuffer();
|
bool header_read = false;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
int ix = 0;
|
int ix = 0;
|
||||||
|
|
||||||
|
uint8_t* buf = canvas->getBuffer();
|
||||||
|
|
||||||
|
if (is_gzip) {
|
||||||
|
/* gzip compressed data
|
||||||
|
* has to be decompressed into a buffer big enough
|
||||||
|
* to hold the whole data.
|
||||||
|
* so the PBM header is included
|
||||||
|
* search a method to use that as canvas without
|
||||||
|
* additional copy
|
||||||
|
*/
|
||||||
|
commonData->logger->logDebug(GwLog::LOG, "Map received in gzip encoding");
|
||||||
|
|
||||||
|
#define HEADER_MAX 24
|
||||||
|
#define HTTP_CHUNK 512
|
||||||
|
uint8_t in_buf[HTTP_CHUNK];
|
||||||
|
uint8_t header_buf[HEADER_MAX];
|
||||||
|
tinfl_decompressor decomp;
|
||||||
|
tinfl_init(&decomp);
|
||||||
|
size_t bitmap_written = 0;
|
||||||
|
size_t header_written = 0;
|
||||||
|
bool header_done = false;
|
||||||
|
int row_bytes = 0;
|
||||||
|
size_t expected_bitmap = 0;
|
||||||
|
|
||||||
|
while (stream->connected() || stream->available()) {
|
||||||
|
int bytes_read = stream->read(in_buf, HTTP_CHUNK);
|
||||||
|
if (bytes_read <= 0) break;
|
||||||
|
commonData->logger->logDebug(GwLog::LOG, "stream: bytes_read=%d", bytes_read);
|
||||||
|
size_t in_ofs = 0; // offset
|
||||||
|
while (in_ofs < (size_t)bytes_read) {
|
||||||
|
size_t in_size = bytes_read - in_ofs;
|
||||||
|
size_t out_size;
|
||||||
|
uint8_t *out_ptr;
|
||||||
|
uint8_t *out_ptr_next;
|
||||||
|
if (!header_done) {
|
||||||
|
if (header_written >= HEADER_MAX) {
|
||||||
|
commonData->logger->logDebug(GwLog::LOG, "PBM header too large");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
out_ptr = header_buf + header_written;
|
||||||
|
out_size = HEADER_MAX - header_written;
|
||||||
|
} else {
|
||||||
|
out_ptr = buf + bitmap_written;
|
||||||
|
out_size = expected_bitmap - bitmap_written;
|
||||||
|
}
|
||||||
|
commonData->logger->logDebug(GwLog::LOG, "in_size=%d, out_size=%d", in_size, out_size);
|
||||||
|
// TODO correct loop !!!
|
||||||
|
// tinfl_status tinfl_decompress(
|
||||||
|
// tinfl_decompressor *r,
|
||||||
|
// const mz_uint8 *pIn_buf_next,
|
||||||
|
// size_t *pIn_buf_size,
|
||||||
|
// mz_uint8 *pOut_buf_start
|
||||||
|
// mz_uint8 *pOut_buf_next,
|
||||||
|
// size_t *pOut_buf_size,
|
||||||
|
// const mz_uint32 decomp_flags)
|
||||||
|
tinfl_status status = tinfl_decompress(
|
||||||
|
&decomp,
|
||||||
|
in_buf + in_ofs, // start address in input buffer
|
||||||
|
&in_size, // number of bytes to process
|
||||||
|
out_ptr, // start of output buffer
|
||||||
|
out_ptr, // next write position in output buffer
|
||||||
|
&out_size, // free size in output buffer
|
||||||
|
// TINFL_FLAG_PARSE_ZLIB_HEADER |
|
||||||
|
TINFL_FLAG_HAS_MORE_INPUT |
|
||||||
|
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF
|
||||||
|
);
|
||||||
|
if (status < 0) {
|
||||||
|
commonData->logger->logDebug(GwLog::LOG, "Decompression error (%d)", status);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
in_ofs += in_size;
|
||||||
|
commonData->logger->logDebug(GwLog::LOG, "in_size=%d, in_ofs=%d", in_size, in_ofs);
|
||||||
|
|
||||||
|
if (!header_done) {
|
||||||
|
commonData->logger->logDebug(GwLog::LOG, "Decoding header");
|
||||||
|
header_written += out_size;
|
||||||
|
|
||||||
|
// Detect header end: two '\n'
|
||||||
|
char *first_nl = strchr((char*)header_buf, '\n');
|
||||||
|
if (!first_nl) continue;
|
||||||
|
|
||||||
|
char *second_nl = strchr(first_nl + 1, '\n');
|
||||||
|
if (!second_nl) continue;
|
||||||
|
|
||||||
|
// Null-terminate header for sscanf
|
||||||
|
header_buf[header_written < HEADER_MAX ? header_written : HEADER_MAX - 1] = 0;
|
||||||
|
|
||||||
|
// Check magic
|
||||||
|
if (strncmp((char*)header_buf, "P4", 2) != 0) {
|
||||||
|
commonData->logger->logDebug(GwLog::LOG, "Invalid PBM magic");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse width and height strictly
|
||||||
|
int header_width = 0, header_height = 0;
|
||||||
|
if (sscanf((char*)header_buf, "P4\n%d %d", &header_width, &header_height) != 2) {
|
||||||
|
commonData->logger->logDebug(GwLog::LOG, "Failed to parse PBM dimensions");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header_width != map_width || header_height != map_height) {
|
||||||
|
commonData->logger->logDebug(GwLog::LOG, "PBM size mismatch: header %dx%d, requested %dx%d\n",
|
||||||
|
header_width, header_height, map_width, map_height);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
commonData->logger->logDebug(GwLog::LOG, "Header: %dx%d", header_width, header_height);
|
||||||
|
|
||||||
|
// Compute row bytes and expected bitmap size
|
||||||
|
row_bytes = (header_width + 7) / 8;
|
||||||
|
commonData->logger->logDebug(GwLog::LOG, "row_bytes=%d", row_bytes);
|
||||||
|
expected_bitmap = (size_t)row_bytes * header_height;
|
||||||
|
commonData->logger->logDebug(GwLog::LOG, "expected_bitmap=%d", expected_bitmap);
|
||||||
|
|
||||||
|
// Copy any extra decompressed bitmap after header
|
||||||
|
size_t header_size = (second_nl + 1) - (char*)header_buf;
|
||||||
|
commonData->logger->logDebug(GwLog::LOG, "header_size=%d", header_size);
|
||||||
|
size_t extra_bitmap = header_written - header_size;
|
||||||
|
commonData->logger->logDebug(GwLog::LOG, "extra bitmap=%d", extra_bitmap);
|
||||||
|
|
||||||
|
header_done = true;
|
||||||
|
|
||||||
|
if (extra_bitmap > 0) {
|
||||||
|
memcpy(buf, header_buf + header_size, extra_bitmap);
|
||||||
|
bitmap_written = extra_bitmap;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bitmap_written += out_size;
|
||||||
|
if (bitmap_written >= expected_bitmap) {
|
||||||
|
commonData->logger->logDebug(GwLog::LOG, "Image fully received");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
commonData->logger->logDebug(GwLog::LOG, "bitmap_written=%d", bitmap_written);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// uncompressed data
|
||||||
|
commonData->logger->logDebug(GwLog::LOG, "Map received uncompressed");
|
||||||
while (stream->available()) {
|
while (stream->available()) {
|
||||||
uint8_t b = stream->read();
|
uint8_t b = stream->read();
|
||||||
n += 1;
|
n += 1;
|
||||||
@@ -424,6 +692,7 @@ public:
|
|||||||
if (n == size) {
|
if (n == size) {
|
||||||
valid = true;
|
valid = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
commonData->logger->logDebug(GwLog::LOG, "HTTP: final bytesRead=%d, header-size=%d", n, header_size);
|
commonData->logger->logDebug(GwLog::LOG, "HTTP: final bytesRead=%d, header-size=%d", n, header_size);
|
||||||
} else {
|
} else {
|
||||||
commonData->logger->logDebug(GwLog::LOG, "HTTP result #%d", httpCode);
|
commonData->logger->logDebug(GwLog::LOG, "HTTP result #%d", httpCode);
|
||||||
@@ -446,6 +715,8 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errmsg = "";
|
||||||
|
|
||||||
map_lat = bv_lat->value; // save for later comparison
|
map_lat = bv_lat->value; // save for later comparison
|
||||||
map_lon = bv_lon->value;
|
map_lon = bv_lon->value;
|
||||||
map_valid = getBackgroundMap(map_lat, map_lon, zoom);
|
map_valid = getBackgroundMap(map_lat, map_lon, zoom);
|
||||||
@@ -456,11 +727,14 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void display_side_keys() {
|
||||||
|
// An rechter Seite neben dem Rad inc, dec, set etc ?
|
||||||
|
}
|
||||||
|
|
||||||
int displayPage(PageData &pageData) {
|
int displayPage(PageData &pageData) {
|
||||||
GwLog *logger = commonData->logger;
|
|
||||||
|
|
||||||
// Logging boat values
|
// Logging boat values
|
||||||
logger->logDebug(GwLog::LOG, "Drawing at PageAnchor; Mode=%c", mode);
|
commonData->logger->logDebug(GwLog::LOG, "Drawing at PageAnchor; Mode=%c", mode);
|
||||||
|
|
||||||
// Set display in partial refresh mode
|
// Set display in partial refresh mode
|
||||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ typedef struct{
|
|||||||
AlarmData alarm;
|
AlarmData alarm;
|
||||||
GwApi::BoatValue *time = nullptr;
|
GwApi::BoatValue *time = nullptr;
|
||||||
GwApi::BoatValue *date = nullptr;
|
GwApi::BoatValue *date = nullptr;
|
||||||
|
float tz = 0.0; // timezone from config
|
||||||
uint16_t fgcolor;
|
uint16_t fgcolor;
|
||||||
uint16_t bgcolor;
|
uint16_t bgcolor;
|
||||||
bool keylock = false;
|
bool keylock = false;
|
||||||
|
|||||||
@@ -19,28 +19,6 @@
|
|||||||
"obp40": "true"
|
"obp40": "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "mapServer",
|
|
||||||
"label": "map server",
|
|
||||||
"type": "string",
|
|
||||||
"default": "",
|
|
||||||
"description": "Server for converting map tiles. Use only one hostname or IP address",
|
|
||||||
"category": "wifi client",
|
|
||||||
"capabilities": {
|
|
||||||
"obp40": "true"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "mapTilePath",
|
|
||||||
"label": "map tile path",
|
|
||||||
"type": "string",
|
|
||||||
"default": "map.php",
|
|
||||||
"description": "Path to converter access e.g. index.php or map.php",
|
|
||||||
"category": "wifi client",
|
|
||||||
"capabilities": {
|
|
||||||
"obp40": "true"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "timeZone",
|
"name": "timeZone",
|
||||||
"label": "Time Zone",
|
"label": "Time Zone",
|
||||||
@@ -1574,7 +1552,6 @@
|
|||||||
"obp40": "true"
|
"obp40": "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"name": "page1type",
|
"name": "page1type",
|
||||||
"label": "Type",
|
"label": "Type",
|
||||||
|
|||||||
@@ -19,28 +19,6 @@
|
|||||||
"obp60": "true"
|
"obp60": "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "mapServer",
|
|
||||||
"label": "map server",
|
|
||||||
"type": "string",
|
|
||||||
"default": "",
|
|
||||||
"description": "Server for converting map tiles. Use only one hostname or IP address",
|
|
||||||
"category": "wifi client",
|
|
||||||
"capabilities": {
|
|
||||||
"obp40": "true"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "mapTilePath",
|
|
||||||
"label": "map tile path",
|
|
||||||
"type": "string",
|
|
||||||
"default": "map.php",
|
|
||||||
"description": "Path to converter access e.g. index.php or map.php",
|
|
||||||
"category": "wifi client",
|
|
||||||
"capabilities": {
|
|
||||||
"obp40": "true"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "timeZone",
|
"name": "timeZone",
|
||||||
"label": "Time Zone",
|
"label": "Time Zone",
|
||||||
@@ -1129,6 +1107,34 @@
|
|||||||
{ "mapsource": ["Local Service"] }
|
{ "mapsource": ["Local Service"] }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "mapServer",
|
||||||
|
"label": "map server",
|
||||||
|
"type": "string",
|
||||||
|
"default": "",
|
||||||
|
"description": "Server for converting map tiles. Use only one hostname or IP address",
|
||||||
|
"category": "OBP60 Navigation",
|
||||||
|
"capabilities": {
|
||||||
|
"obp60": "true"
|
||||||
|
},
|
||||||
|
"condition": [
|
||||||
|
{ "mapsource": ["Remote Service"] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mapTilePath",
|
||||||
|
"label": "map tile path",
|
||||||
|
"type": "string",
|
||||||
|
"default": "map.php",
|
||||||
|
"description": "Path to converter access e.g. index.php or map.php",
|
||||||
|
"category": "OBP40 Navigation",
|
||||||
|
"capabilities": {
|
||||||
|
"obp40": "true"
|
||||||
|
},
|
||||||
|
"condition": [
|
||||||
|
{ "mapsource": ["Remote Service"] }
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "maptype",
|
"name": "maptype",
|
||||||
"label": "Map Type",
|
"label": "Map Type",
|
||||||
|
|||||||
@@ -527,8 +527,8 @@ void OBP60Task(GwApi *api){
|
|||||||
// Configuration values for main loop
|
// Configuration values for main loop
|
||||||
String gpsFix = api->getConfig()->getConfigItem(api->getConfig()->flashLED,true)->asString();
|
String gpsFix = api->getConfig()->getConfigItem(api->getConfig()->flashLED,true)->asString();
|
||||||
String gpsOn=api->getConfig()->getConfigItem(api->getConfig()->useGPS,true)->asString();
|
String gpsOn=api->getConfig()->getConfigItem(api->getConfig()->useGPS,true)->asString();
|
||||||
float tz = api->getConfig()->getConfigItem(api->getConfig()->timeZone,true)->asFloat();
|
|
||||||
|
|
||||||
|
commonData.tz = api->getConfig()->getConfigItem(api->getConfig()->timeZone,true)->asFloat();
|
||||||
commonData.backlight.mode = backlightMapping(config->getConfigItem(config->backlight,true)->asString());
|
commonData.backlight.mode = backlightMapping(config->getConfigItem(config->backlight,true)->asString());
|
||||||
commonData.backlight.color = colorMapping(config->getConfigItem(config->blColor,true)->asString());
|
commonData.backlight.color = colorMapping(config->getConfigItem(config->blColor,true)->asString());
|
||||||
commonData.backlight.brightness = uint(config->getConfigItem(config->blBrightness,true)->asInt());
|
commonData.backlight.brightness = uint(config->getConfigItem(config->blBrightness,true)->asInt());
|
||||||
@@ -703,7 +703,7 @@ void OBP60Task(GwApi *api){
|
|||||||
starttime5 = millis();
|
starttime5 = millis();
|
||||||
if(time->valid == true && date->valid == true && lat->valid == true && lon->valid == true){
|
if(time->valid == true && date->valid == true && lat->valid == true && lon->valid == true){
|
||||||
// Provide sundata to all pages
|
// Provide sundata to all pages
|
||||||
commonData.sundata = calcSunsetSunrise(time->value , date->value, lat->value, lon->value, tz);
|
commonData.sundata = calcSunsetSunrise(time->value , date->value, lat->value, lon->value, commonData.tz);
|
||||||
// Backlight with sun control
|
// Backlight with sun control
|
||||||
if (commonData.backlight.mode == BacklightMode::SUN) {
|
if (commonData.backlight.mode == BacklightMode::SUN) {
|
||||||
// if(String(backlight) == "Control by Sun"){
|
// if(String(backlight) == "Control by Sun"){
|
||||||
@@ -716,7 +716,7 @@ void OBP60Task(GwApi *api){
|
|||||||
}
|
}
|
||||||
} else if (homevalid and commonData.data.rtcValid) {
|
} else if (homevalid and commonData.data.rtcValid) {
|
||||||
// No gps fix but valid home location and time configured
|
// No gps fix but valid home location and time configured
|
||||||
commonData.sundata = calcSunsetSunriseRTC(&commonData.data.rtcTime, homelat, homelon, tz);
|
commonData.sundata = calcSunsetSunriseRTC(&commonData.data.rtcTime, homelat, homelon, commonData.tz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,8 +45,6 @@ lib_deps =
|
|||||||
milesburton/DallasTemperature@3.11.0
|
milesburton/DallasTemperature@3.11.0
|
||||||
signetica/SunRise@2.0.2
|
signetica/SunRise@2.0.2
|
||||||
adafruit/Adafruit FRAM I2C@2.0.3
|
adafruit/Adafruit FRAM I2C@2.0.3
|
||||||
WifiClientSecure
|
|
||||||
HTTPClient
|
|
||||||
build_flags=
|
build_flags=
|
||||||
#https://thingpulse.com/usb-settings-for-logging-with-the-esp32-s3-in-platformio/?srsltid=AfmBOopGskbkr4GoeVkNlFaZXe_zXkLceKF6Rn-tmoXABCeAR2vWsdHL
|
#https://thingpulse.com/usb-settings-for-logging-with-the-esp32-s3-in-platformio/?srsltid=AfmBOopGskbkr4GoeVkNlFaZXe_zXkLceKF6Rn-tmoXABCeAR2vWsdHL
|
||||||
# -D CORE_DEBUG_LEVEL=1 #Debug level for CPU core via CDC (serial device)
|
# -D CORE_DEBUG_LEVEL=1 #Debug level for CPU core via CDC (serial device)
|
||||||
@@ -103,16 +101,14 @@ lib_deps =
|
|||||||
milesburton/DallasTemperature@3.11.0
|
milesburton/DallasTemperature@3.11.0
|
||||||
signetica/SunRise@2.0.2
|
signetica/SunRise@2.0.2
|
||||||
adafruit/Adafruit FRAM I2C@2.0.3
|
adafruit/Adafruit FRAM I2C@2.0.3
|
||||||
WifiClientSecure
|
|
||||||
HTTPClient
|
|
||||||
build_flags=
|
build_flags=
|
||||||
-D DISABLE_DIAGNOSTIC_OUTPUT #Disable diagnostic output for GxEPD2 lib
|
-D DISABLE_DIAGNOSTIC_OUTPUT #Disable diagnostic output for GxEPD2 lib
|
||||||
-D BOARD_OBP40S3 #Board OBP40 with ESP32S3
|
-D BOARD_OBP40S3 #Board OBP40 with ESP32S3
|
||||||
-D HARDWARE_V10 #OBP40 hardware revision V1.0 SKU:DIE07300S V1.1 (CrowPanel 4.2)
|
-D HARDWARE_V10 #OBP40 hardware revision V1.0 SKU:DIE07300S V1.1 (CrowPanel 4.2)
|
||||||
-D DISPLAY_GDEY042T81 #new E-Ink display from Good Display (Waveshare), R10 2.2 ohm - good (contast lost by shunshine)
|
-D DISPLAY_GDEY042T81 #new E-Ink display from Good Display (Waveshare), R10 2.2 ohm - good (contast lost by shunshine)
|
||||||
#-D DISPLAY_ZJY400300-042CAAMFGN #alternativ E-Ink display from ZZE Technology, R10 2.2 ohm - very good
|
#-D DISPLAY_ZJY400300-042CAAMFGN #alternativ E-Ink display from ZZE Technology, R10 2.2 ohm - very good
|
||||||
-D LIPO_ACCU_1200 #Hardware extension, LiPo accu 3,7V 1200mAh
|
#-D LIPO_ACCU_1200 #Hardware extension, LiPo accu 3,7V 1200mAh
|
||||||
-D VOLTAGE_SENSOR #Hardware extension, LiPo voltage sensor with two resistors
|
#-D VOLTAGE_SENSOR #Hardware extension, LiPo voltage sensor with two resistors
|
||||||
#-D ENABLE_PATCHES #enable patching of gateway code
|
#-D ENABLE_PATCHES #enable patching of gateway code
|
||||||
${env.build_flags}
|
${env.build_flags}
|
||||||
upload_port = /dev/ttyUSB0 #OBP40 download via external USB/Serail converter
|
upload_port = /dev/ttyUSB0 #OBP40 download via external USB/Serail converter
|
||||||
|
|||||||
Reference in New Issue
Block a user