mirror of
https://github.com/thooge/esp32-nmea2000-obp60.git
synced 2026-10-07 07:25:14 +02:00
Compare commits
74
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8287242bf9 | ||
|
|
6ee158519d | ||
|
|
933b1677f6 | ||
|
|
1ea63d7612 | ||
|
|
9186491b5e | ||
|
|
c1e69dd81b | ||
|
|
3dd13ae899 | ||
|
|
6c318d5a69 | ||
|
|
0202c5d82a | ||
|
|
d44dc94ec7 | ||
|
|
0f98331eb4 | ||
|
|
33768440b1 | ||
|
|
9eb0983ee4 | ||
|
|
93084c980a | ||
|
|
18c1da5991 | ||
|
|
99f88cca3f | ||
|
|
fecb9a8043 | ||
|
|
985d4ef3e6 | ||
|
|
50dc5955a0 | ||
|
|
aebc18a75d | ||
|
|
e60ead0455 | ||
|
|
eaa1f793ff | ||
|
|
88dfa84cc8 | ||
|
|
6c6557f54e | ||
|
|
58a0bbf0d4 | ||
|
|
f68e988736 | ||
|
|
807e4cec30 | ||
|
|
e129b18057 | ||
|
|
e757ac4016 | ||
|
|
71e3ba79f6 | ||
|
|
da4c66bec2 | ||
|
|
fb181c1b01 | ||
|
|
53cf497a70 | ||
|
|
92ee3a0c4f | ||
|
|
4e07e1d22e | ||
|
|
2a8558589b | ||
|
|
2da5ffc4ea | ||
|
|
4e8953ed2a | ||
|
|
83aae1ea81 | ||
|
|
82c0ce91a5 | ||
|
|
2e7b0435b2 | ||
|
|
b8e9e02617 | ||
|
|
fe05b734de | ||
|
|
a93f951f18 | ||
|
|
8ebde00676 | ||
|
|
2a98f49e40 | ||
|
|
d1b729a554 | ||
|
|
dac7459355 | ||
|
|
775d4456a2 | ||
|
|
04ea564bdb | ||
|
|
751f4e2296 | ||
|
|
3dd7f4751a | ||
|
|
a2822451c1 | ||
|
|
63af2807fb | ||
|
|
c17f8238a4 | ||
|
|
8f50c6a09c | ||
|
|
e906ad6d00 | ||
|
|
89482016db | ||
|
|
abfe68f963 | ||
|
|
01ff478c29 | ||
|
|
d0fe7a2d9b | ||
|
|
80800c32a3 | ||
|
|
a218da8948 | ||
|
|
1425297ef4 | ||
|
|
92a6266d71 | ||
|
|
7be6796a84 | ||
|
|
15c5c450a1 | ||
|
|
c0aa6b4010 | ||
|
|
9c9d435390 | ||
|
|
2d5838ebc8 | ||
|
|
2f30e858c8 | ||
|
|
1098afa8b2 | ||
|
|
cfac5b0a05 | ||
|
|
f84ef25a30 |
@@ -143,6 +143,7 @@ void GwWifi::loop(){
|
||||
|
||||
delay(300);
|
||||
|
||||
if (!apActive) {
|
||||
if (acquireMutex()){
|
||||
esp_err_t stopErr=esp_wifi_stop();
|
||||
releaseMutex();
|
||||
@@ -167,6 +168,9 @@ void GwWifi::loop(){
|
||||
else{
|
||||
LOG_DEBUG(GwLog::ERROR,"GwWifi: mutex timeout in loop (start)");
|
||||
}
|
||||
} else {
|
||||
connectInternal();
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include "imglib.h"
|
||||
|
||||
// Character sets
|
||||
#include "fonts/DSEG7Classic-BoldItalic10pt7b.h"
|
||||
#include "fonts/DSEG7Classic-BoldItalic12pt7b.h"
|
||||
#include "fonts/DSEG7Classic-BoldItalic16pt7b.h"
|
||||
#include "fonts/DSEG7Classic-BoldItalic20pt7b.h"
|
||||
#include "fonts/DSEG7Classic-BoldItalic26pt7b.h"
|
||||
@@ -539,17 +541,21 @@ std::vector<String> wordwrap(String &line, uint16_t maxwidth) {
|
||||
}
|
||||
|
||||
// Draw centered text
|
||||
void drawTextCenter(int16_t cx, int16_t cy, String text) {
|
||||
// bool dsegAdjust = false - optional, for adjustment of DSEG italic font
|
||||
// returns left <x> edge of printed string
|
||||
int16_t drawTextCenter(int16_t cx, int16_t cy, String text, bool dsegAdjust) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
displayGetTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
displayGetTextBounds(text, 0, 0, &x1, &y1, &w, &h, dsegAdjust);
|
||||
int16_t cursorX = cx - (x1 + static_cast<int16_t>(w / 2));
|
||||
int16_t cursorY = cy - (y1 + static_cast<int16_t>(h / 2));
|
||||
getdisplay().setCursor(cursorX, cursorY);
|
||||
getdisplay().print(text);
|
||||
|
||||
return cursorX;
|
||||
}
|
||||
|
||||
// Draw centered botton with centered text
|
||||
// Draw centered button with centered text
|
||||
void drawButtonCenter(int16_t cx, int16_t cy, int8_t sx, int8_t sy, String text, uint16_t fg, uint16_t bg, bool inverted) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
@@ -572,17 +578,155 @@ void drawButtonCenter(int16_t cx, int16_t cy, int8_t sx, int8_t sy, String text,
|
||||
}
|
||||
|
||||
// Draw right aligned text
|
||||
void drawTextRalign(int16_t x, int16_t y, String text) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
#ifdef TFT_DISPLAY
|
||||
w = getdisplay().textWidth(text);
|
||||
h = getdisplay().fontHeight();
|
||||
#else
|
||||
getdisplay().getTextBounds(text, 0, 150, &x1, &y1, &w, &h);
|
||||
#endif
|
||||
getdisplay().setCursor(x - w - 1, y); // '-1' required since some strings wrap around w/o it
|
||||
// int16_t x - upper right x position for text to start printing
|
||||
// int16_t y - upper right y position for text to start printing
|
||||
// const String& text - text to be printed
|
||||
// bool dsegAdjust = false - optional, for adjustment of DSEG italic font
|
||||
// returns left <x> edge of printed string
|
||||
int16_t drawTextRalign(int16_t x, int16_t y, const String& text, bool dsegAdjust) {
|
||||
int16_t x1 = 0, y1 = 0;
|
||||
uint16_t w = 0, h = 0;
|
||||
|
||||
displayGetTextBounds(text, 0, y, &x1, &y1, &w, &h, dsegAdjust);
|
||||
int16_t cursorX = x - x1 - w;
|
||||
getdisplay().setCursor(cursorX, y);
|
||||
getdisplay().print(text);
|
||||
|
||||
return cursorX; // currently visible left edge
|
||||
}
|
||||
|
||||
// Implementation of <printBoatValue()>; does the actual printing
|
||||
static void printBoatValueImpl(const String &sBoatValue, const int16_t x, const int16_t y,
|
||||
const int8_t align, const int8_t fontSize, bool smallDecs) {
|
||||
const GFXfont *mainFont = nullptr;
|
||||
const GFXfont *decimalFont = nullptr;
|
||||
constexpr bool dsegAdjust = true;
|
||||
|
||||
String integerPart = "";
|
||||
String decimalPart = "";
|
||||
int16_t dot = 0;
|
||||
|
||||
uint16_t intW = 0, decW = 0;
|
||||
int16_t decimalLeftX = 0;
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Font selection
|
||||
// -----------------------------------------------------------------
|
||||
if (sBoatValue.indexOf('"') != -1)
|
||||
{
|
||||
// LAT/LON values
|
||||
if (fontSize <= 12)
|
||||
mainFont = &Ubuntu_Bold12pt8b;
|
||||
else if (fontSize <= 16)
|
||||
mainFont = &Ubuntu_Bold16pt8b;
|
||||
else if (fontSize <= 20)
|
||||
mainFont = &Ubuntu_Bold20pt8b;
|
||||
else
|
||||
mainFont = &Ubuntu_Bold32pt8b;
|
||||
|
||||
smallDecs = false; // disable small decimals for LAT/LON in any case
|
||||
}
|
||||
else if (fontSize <= 12) {
|
||||
mainFont = &DSEG7Classic_BoldItalic12pt7b;
|
||||
decimalFont = &DSEG7Classic_BoldItalic10pt7b;
|
||||
} else if (fontSize <= 16) {
|
||||
mainFont = &DSEG7Classic_BoldItalic16pt7b;
|
||||
decimalFont = &DSEG7Classic_BoldItalic12pt7b;
|
||||
} else if (fontSize <= 20) {
|
||||
mainFont = &DSEG7Classic_BoldItalic20pt7b;
|
||||
decimalFont = &DSEG7Classic_BoldItalic16pt7b;
|
||||
} else if (fontSize <= 26) {
|
||||
mainFont = &DSEG7Classic_BoldItalic26pt7b;
|
||||
decimalFont = &DSEG7Classic_BoldItalic20pt7b;
|
||||
} else if (fontSize <= 30) {
|
||||
mainFont = &DSEG7Classic_BoldItalic30pt7b;
|
||||
decimalFont = &DSEG7Classic_BoldItalic26pt7b;
|
||||
} else if (fontSize <= 42) {
|
||||
mainFont = &DSEG7Classic_BoldItalic42pt7b;
|
||||
decimalFont = &DSEG7Classic_BoldItalic30pt7b;
|
||||
} else {
|
||||
mainFont = &DSEG7Classic_BoldItalic60pt7b;
|
||||
decimalFont = &DSEG7Classic_BoldItalic42pt7b;
|
||||
}
|
||||
|
||||
// separate integer and decimal part of the value
|
||||
dot = sBoatValue.indexOf('.');
|
||||
if (dot == -1) { // no decimal point found
|
||||
integerPart = sBoatValue;
|
||||
decimalPart = "";
|
||||
smallDecs = false; // print only integer part
|
||||
} else {
|
||||
integerPart = sBoatValue.substring(0, dot + 1); // keep decimal point
|
||||
decimalPart = sBoatValue.substring(dot + 1);
|
||||
}
|
||||
|
||||
// Measure integer part
|
||||
int16_t ix1, iy1;
|
||||
uint16_t iw, ih;
|
||||
display.setFont(mainFont);
|
||||
displayGetTextBounds(integerPart, 0, 0, &ix1, &iy1, &iw, &ih, dsegAdjust);
|
||||
intW = ix1 + iw;
|
||||
|
||||
// Measure decimal part only if one actually exists
|
||||
decW = 0;
|
||||
if (dot != -1 && decimalPart.length() > 0) {
|
||||
int16_t dx1, dy1;
|
||||
uint16_t dw, dh;
|
||||
display.setFont(smallDecs ? decimalFont : mainFont);
|
||||
displayGetTextBounds(decimalPart, 0, 0, &dx1, &dy1, &dw, &dh, dsegAdjust);
|
||||
decW = dx1 + dw;
|
||||
}
|
||||
|
||||
const int16_t totalWidth = intW + decW;
|
||||
int16_t startX;
|
||||
switch (align) {
|
||||
case 0: // LEFT
|
||||
startX = x;
|
||||
break;
|
||||
case 1: // CENTER
|
||||
startX = x - totalWidth / 2;
|
||||
break;
|
||||
case 2: // RIGHT
|
||||
default:
|
||||
startX = x - totalWidth;
|
||||
break;
|
||||
}
|
||||
decimalLeftX = startX + intW;
|
||||
|
||||
// Draw integer part
|
||||
display.setFont(mainFont);
|
||||
getdisplay().setCursor(startX, y);
|
||||
getdisplay().print(integerPart);
|
||||
|
||||
// Draw decimal part only when present
|
||||
if (dot != -1 && decimalPart.length() > 0) {
|
||||
display.setFont(smallDecs ? decimalFont : mainFont);
|
||||
getdisplay().setCursor(decimalLeftX, y);
|
||||
getdisplay().print(decimalPart);
|
||||
}
|
||||
}
|
||||
|
||||
// Print boat data value at x,y position with selectable alignment
|
||||
// Version with <GwApi::BoatValue *bValue>; formats the boat data value and then prints the formatted value
|
||||
// GwApi::BoatValue *bValue - boat value to print
|
||||
// CommonData &commondata - <commondata> required for <formatValue()> function
|
||||
// int16_t x - upper left/right x position for text to start printing
|
||||
// int16_t y - upper left/right y position for text to start printing
|
||||
// int8_t align - alignment [0,1,2] of the value: 0 = left, 1 = center, 2 = right
|
||||
// int8_t fontSize - font size for integer part of number or for full value, if <smallDecs> is <false>/not set
|
||||
// bool smallDecs - flag specifies if decimals will be printed in smaller fontsize [default = false]
|
||||
void printBoatValue(GwApi::BoatValue *bValue, CommonData &commondata, const int16_t x, const int16_t y,
|
||||
const int8_t align, const int8_t fontSize, const bool smallDecs)
|
||||
{
|
||||
String sBoatValue = formatValue(bValue, commondata).svalue;
|
||||
printBoatValueImpl(sBoatValue, x, y, align, fontSize, smallDecs);
|
||||
}
|
||||
|
||||
// Print boat data value at x,y position with selectable alignment; oerload with ready-to-print <String>; omits boat data value formatting
|
||||
void printBoatValue(const String &sBoatValue, const int16_t x, const int16_t y,
|
||||
const int8_t align, const int8_t fontSize, const bool smallDecs)
|
||||
{
|
||||
printBoatValueImpl(sBoatValue, x, y, align, fontSize, smallDecs);
|
||||
}
|
||||
|
||||
// Draw text inside box, normal or inverted
|
||||
|
||||
@@ -56,6 +56,8 @@ extern sdmmc_card_t *sdcard;
|
||||
#endif
|
||||
|
||||
// Fonts declarations for display (#includes see OBP60Extensions.cpp)
|
||||
extern const GFXfont DSEG7Classic_BoldItalic10pt7b;
|
||||
extern const GFXfont DSEG7Classic_BoldItalic12pt7b;
|
||||
extern const GFXfont DSEG7Classic_BoldItalic16pt7b;
|
||||
extern const GFXfont DSEG7Classic_BoldItalic20pt7b;
|
||||
extern const GFXfont DSEG7Classic_BoldItalic26pt7b;
|
||||
@@ -695,11 +697,17 @@ inline void displaySetFullWindow() {
|
||||
// replacement for getTextBounds that works with both EPD and TFT
|
||||
inline void displayGetTextBounds(const String &txt, int16_t x, int16_t y,
|
||||
int16_t *x0, int16_t *y0,
|
||||
uint16_t *w, uint16_t *h) {
|
||||
uint16_t *w, uint16_t *h, const bool dsegAdjust = false) {
|
||||
String str = txt;
|
||||
// make sure that we always have a char with max size at last position for boundary test
|
||||
// for monotype italic DSEG7 font to avoid text wobbling
|
||||
if (dsegAdjust && str.length() > 0 && isDigit(str[str.length() - 1])) {
|
||||
str.setCharAt(str.length() - 1, '8');
|
||||
}
|
||||
#ifdef TFT_DISPLAY
|
||||
getdisplay().getTextBounds(txt, x, y, x0, y0, w, h);
|
||||
getdisplay().getTextBounds(str, x, y, x0, y0, w, h);
|
||||
#else
|
||||
getdisplay().getTextBounds(txt, x, y, x0, y0, w, h);
|
||||
getdisplay().getTextBounds(str, x, y, x0, y0, w, h);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -732,10 +740,12 @@ void setBuzzerPower(uint power); // Set buzzer power
|
||||
|
||||
String xdrDelete(String input); // Delete xdr prefix from string
|
||||
|
||||
void drawTextCenter(int16_t cx, int16_t cy, String text);
|
||||
int16_t drawTextCenter(int16_t cx, int16_t cy, String text, bool dsegAdjust = false);
|
||||
void drawButtonCenter(int16_t cx, int16_t cy, int8_t sx, int8_t sy, String text, uint16_t fg, uint16_t bg, bool inverted);
|
||||
void drawTextRalign(int16_t x, int16_t y, String text);
|
||||
int16_t drawTextRalign(int16_t x, int16_t y, const String& text, bool dsegAdjust = false);
|
||||
void drawTextBoxed(Rect box, String text, uint16_t fg, uint16_t bg, bool inverted, bool border);
|
||||
void printBoatValue(GwApi::BoatValue *bValue, CommonData &commondata, const int16_t x, const int16_t y, const int8_t align, const int8_t fontSize, const bool smallDecs = false);
|
||||
void printBoatValue(const String &sBoatValue, const int16_t x, const int16_t y, const int8_t align, const int8_t fontSize, const bool smallDecs = false);
|
||||
|
||||
void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color);
|
||||
void displayTrendLow(int16_t x, int16_t y, uint16_t size, uint16_t color);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <Arduino.h>
|
||||
#include "GwApi.h"
|
||||
#include "Pagedata.h"
|
||||
#include "OBPDataOperations.h"
|
||||
|
||||
// ToDo
|
||||
// simulation data
|
||||
@@ -49,15 +50,10 @@ String formatLongitude(double lon) {
|
||||
return String(degree, 0) + "\x90 " + String(minute, 4) + "' " + ((lon > 0) ? "E" : "W");
|
||||
}
|
||||
|
||||
// Convert and format boat value from SI to user defined format (definition for compatibility purposes)
|
||||
FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata) {
|
||||
|
||||
return formatValue(value, commondata, false); // call <formatValue> with standard handling of user setting for simulation data
|
||||
}
|
||||
|
||||
// Convert and format boat value from SI to user defined format
|
||||
// generate random simulation data; can be deselected to use conversion+formatting function even in simulation mode
|
||||
FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool ignoreSimuDataSetting){
|
||||
// generates random simulation data; can be deselected to use conversion+formatting function even in simulation mode
|
||||
// String setPrecision - overrides precision setting from config; if not set, use config setting
|
||||
FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool ignoreSimuDataSetting, String setPrecision) {
|
||||
GwLog *logger = commondata.logger;
|
||||
FormattedData result;
|
||||
static int dayoffset = 0;
|
||||
@@ -75,12 +71,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
String tempFormat = commondata.config->getString(commondata.config->tempFormat); // [K|°C|°F]
|
||||
String dateFormat = commondata.config->getString(commondata.config->dateFormat); // [DE|GB|US]
|
||||
String precision = commondata.config->getString(commondata.config->valueprecision); // [1|2]
|
||||
bool usesimudata = commondata.config->getBool(commondata.config->useSimuData); // [on|off]
|
||||
|
||||
bool usesimudata;
|
||||
if (setPrecision == "1" || setPrecision == "2") {
|
||||
precision = setPrecision; // override precision setting from config
|
||||
}
|
||||
if (ignoreSimuDataSetting){
|
||||
usesimudata = false; // ignore user setting for simulation data; we want to format the boat value passed to this function
|
||||
} else {
|
||||
usesimudata = commondata.config->getBool(commondata.config->useSimuData); // [on|off]
|
||||
}
|
||||
|
||||
// If boat value not valid
|
||||
@@ -95,13 +92,12 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
double limit_dec_10;
|
||||
double limit_dec_100;
|
||||
if (precision == "1") {
|
||||
//
|
||||
//All values are displayed using a DSEG7* font. In this font, ' ' is a very short space, and '.' takes up no space at all.
|
||||
//For a space that is as long as a number, '!' is used. For details see https://www.keshikan.net/fonts-e.html
|
||||
//
|
||||
fmt_dec_1 = "!%1.1f"; //insert a blank digit and then display a two-digit number
|
||||
fmt_dec_10 = "!%2.0f"; //insert a blank digit and then display a two-digit number
|
||||
fmt_dec_100 = "%3.0f"; //dispay a three digit number
|
||||
|
||||
fmt_dec_1 = "!%1.1f"; // blank digit + 2 digit number, incl. 1 decimal
|
||||
fmt_dec_10 = "%3.1f"; // 3 digit number, incl. 1 decimal
|
||||
fmt_dec_100 = "%3.0f"; // 3 digit number, no decimal
|
||||
limit_dec_10=9.95; // use fmt_dec_1 below this number to avoid formatting 9.96 as 10.0 instead of 10
|
||||
limit_dec_100=99.5;
|
||||
} else {
|
||||
@@ -216,10 +212,10 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
rawvalue = value->value;
|
||||
}
|
||||
else {
|
||||
course = M_PI_2 + float(random(-17, 17) / 100.0); // create random course/wind values with 90° +/- 10°
|
||||
course = M_PI_2 + float(random(-26, 26) / 100.0); // create random course/wind values with 90° +/- 15°
|
||||
rawvalue = course;
|
||||
}
|
||||
course = course * RAD_TO_DEG; // Unit conversion form rad to deg
|
||||
course = WindUtils::to360(course * RAD_TO_DEG); // Unit conversion form rad to deg
|
||||
|
||||
// Format 3 numbers with prefix zero
|
||||
snprintf(buffer,bsize,"%03.0f",course);
|
||||
@@ -227,7 +223,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
result.cvalue = course;
|
||||
}
|
||||
//########################################################
|
||||
else if (value->getFormat() == "formatKnots" && (value->getName() == "SOG" || value->getName() == "STW")){
|
||||
else if (value->getFormat() == "formatKnots" && (value->getName() == "SOG" || value->getName() == "STW") || value->getName() == "DFT"){
|
||||
double speed = 0;
|
||||
if (usesimudata == false) {
|
||||
speed = value->value;
|
||||
@@ -519,11 +515,11 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
}
|
||||
if (String(tempFormat) == "C") {
|
||||
temp = temp - 273.15;
|
||||
result.unit = "C";
|
||||
result.unit = "Deg C";
|
||||
}
|
||||
else if (String(tempFormat) == "F") {
|
||||
temp = (temp - 273.15) * 9 / 5 + 32;
|
||||
result.unit = "F";
|
||||
result.unit = "Deg F";
|
||||
}
|
||||
else{
|
||||
result.unit = "K";
|
||||
@@ -587,7 +583,11 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
rawvalue = 968 + float(random(0, 10));
|
||||
pressure = rawvalue;
|
||||
}
|
||||
if (pressure < 999.5) {
|
||||
snprintf(buffer, bsize, "!%3.0f", pressure);
|
||||
} else {
|
||||
snprintf(buffer, bsize, "%4.0f", pressure);
|
||||
}
|
||||
result.unit = "hPa";
|
||||
result.cvalue = pressure;
|
||||
}
|
||||
@@ -603,7 +603,11 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
rawvalue = value->value;
|
||||
pressure = 968 + float(random(0, 10));
|
||||
}
|
||||
if (pressure < 999.5) {
|
||||
snprintf(buffer, bsize, "!%3.0f", pressure);
|
||||
} else {
|
||||
snprintf(buffer, bsize, "%4.0f", pressure);
|
||||
}
|
||||
result.unit = "mBar";
|
||||
result.cvalue = pressure;
|
||||
}
|
||||
@@ -900,6 +904,40 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool
|
||||
return result;
|
||||
}
|
||||
|
||||
// Convert and format boat value from SI to user defined format
|
||||
FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata) {
|
||||
|
||||
return formatValue(value, commondata, false, String("-1")); // call <formatValue> with standard setting for simulation data and precision setting from config
|
||||
}
|
||||
|
||||
// Convert and format boat value from SI to user defined format with simulation data setting and precision setting from config
|
||||
FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool ignoreSimuDataSetting) {
|
||||
|
||||
return formatValue(value, commondata, ignoreSimuDataSetting, String("-1"));
|
||||
}
|
||||
|
||||
// Convert and format boat value from SI to user defined format with standard setting for simulation data and specified precision
|
||||
FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, String setPrecision) {
|
||||
|
||||
return formatValue(value, commondata, false, setPrecision);
|
||||
}
|
||||
|
||||
// Format double value from SI to user defined format and convert to string user defined precision setting
|
||||
String formatValue(const double &value, const String &vFormat, CommonData &commondata)
|
||||
{
|
||||
GwApi::BoatValue tmpBVal("dummy"); // temporary boat value for string formatter
|
||||
String sVal;
|
||||
|
||||
tmpBVal.setFormat(vFormat);
|
||||
tmpBVal.valid = true;
|
||||
tmpBVal.value = value;
|
||||
sVal = formatValue(&tmpBVal, commondata, false, String("-1")).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
if (sVal.length() > 0 && sVal[0] == '!') {
|
||||
sVal = sVal.substring(1); // cut leading "!" created at OBPFormatter; doesn't work for other fonts than 7SEG
|
||||
}
|
||||
return sVal;
|
||||
}
|
||||
|
||||
// Helper method for conversion of any data value from SI to user defined format
|
||||
double convertValue(const double &value, const String &name, const String &format, CommonData &commondata)
|
||||
{
|
||||
|
||||
@@ -107,7 +107,6 @@ void CalibrationData::readConfig(GwConfigHandler* config)
|
||||
LOG_DEBUG(GwLog::LOG, "Calibration data type added: %s, offset: %f, slope: %f, smoothing: %f", instance.c_str(),
|
||||
calibrationMap[instance].offset, calibrationMap[instance].slope, calibrationMap[instance].smooth);
|
||||
}
|
||||
// LOG_DEBUG(GwLog::LOG, "All calibration data read");
|
||||
}
|
||||
|
||||
// Handle calibrationMap and calibrate all boat data values
|
||||
@@ -208,47 +207,71 @@ bool CalibrationData::smoothInstance(GwApi::BoatValue* boatDataValue)
|
||||
calibrationMap[instance].value = dataValue; // store the smoothed value in the list
|
||||
calibrationMap[instance].isCalibrated = true;
|
||||
|
||||
// LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s: smooth: %f, oldValue: %f, result: %f", instance.c_str(), smoothFactor, oldValue, calibrationMap[instance].value);
|
||||
|
||||
return true;
|
||||
}
|
||||
// --- End Class CalibrationData ---------------
|
||||
|
||||
// --- Class HstryBuf ---------------
|
||||
HstryBuf::HstryBuf(const String& name, int size, BoatValueList* boatValues, GwLog* log)
|
||||
HstryBuf::HstryBuf(const String& name, const int size, BoatValueList* boatValues, const bool smooth, GwLog* log)
|
||||
: logger(log)
|
||||
, smoothing(smooth)
|
||||
, boatDataName(name)
|
||||
{
|
||||
hstryBuf.resize(size);
|
||||
boatValue = boatValues->findValueOrCreate(name);
|
||||
}
|
||||
|
||||
void HstryBuf::init(const String& format, int updFreq, int mltplr, double minVal, double maxVal)
|
||||
void HstryBuf::init(const String& format, int updFreq, double mltplr, double minVal, double maxVal)
|
||||
{
|
||||
hstryBuf.setMetaData(boatDataName, format, updFreq, mltplr, minVal, maxVal);
|
||||
hstryMin = minVal;
|
||||
hstryMax = maxVal;
|
||||
bufUpdateTime = 0;
|
||||
if (!boatValue->valid) {
|
||||
boatValue->setFormat(format);
|
||||
boatValue->value = std::numeric_limits<double>::max(); // mark current value invalid
|
||||
}
|
||||
|
||||
isTypeAngle = format == "formatCourse" || format == "formatWind" || format == "formatRot";
|
||||
// initialize correct variant of buffer for averaging history data
|
||||
if (smoothing) {
|
||||
if (isTypeAngle) {
|
||||
chrtAvgAngle.begin();
|
||||
} else {
|
||||
chrtAvg.begin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HstryBuf::add(double value)
|
||||
void HstryBuf::add(const double value)
|
||||
{
|
||||
double bufVal = value;
|
||||
|
||||
if (value >= hstryMin && value <= hstryMax) {
|
||||
hstryBuf.add(value);
|
||||
// LOG_DEBUG(GwLog::DEBUG, "HstryBuf::add: name: %s, value: %.3f", hstryBuf.getName(), value);
|
||||
|
||||
if (smoothing) {
|
||||
if (isTypeAngle) {
|
||||
bufVal = chrtAvgAngle.reading(value);
|
||||
} else {
|
||||
bufVal = chrtAvg.reading(value);
|
||||
}
|
||||
}
|
||||
|
||||
void HstryBuf::handle(bool useSimuData, CommonData& common)
|
||||
hstryBuf.add(bufVal);
|
||||
// LOG_DEBUG(GwLog::DEBUG, "HstryBuf::add: name: %s, value: %.3f, value buffer: %.3f", hstryBuf.getName(), value, hstryBuf.getLast());
|
||||
}
|
||||
}
|
||||
|
||||
void HstryBuf::handle(const bool useSimuData, CommonData& common)
|
||||
{
|
||||
std::unique_ptr<GwApi::BoatValue> tmpBVal; // Temp variable to get formatted and converted data value from OBP60Formatter
|
||||
if ((millis() - bufUpdateTime) >= hstryBuf.getUpdFreq()) {
|
||||
|
||||
bufUpdateTime = millis();
|
||||
|
||||
if (boatValue->valid) {
|
||||
add(boatValue->value);
|
||||
|
||||
} else if (useSimuData) { // add simulated value to history buffer
|
||||
std::unique_ptr<GwApi::BoatValue> tmpBVal; // Temp variable to get formatted and converted data value from OBP60Formatter
|
||||
tmpBVal = std::unique_ptr<GwApi::BoatValue>(new GwApi::BoatValue(boatDataName)); // create temporary boat value for retrieval of simulation value
|
||||
tmpBVal->setFormat(boatValue->getFormat());
|
||||
tmpBVal->value = boatValue->value;
|
||||
@@ -256,38 +279,35 @@ void HstryBuf::handle(bool useSimuData, CommonData& common)
|
||||
double simSIValue = formatValue(tmpBVal.get(), common).value; // simulated value is generated at <formatValue>; here: retreive SI value
|
||||
add(simSIValue);
|
||||
} else {
|
||||
// here we will add invalid (DBL_MAX) value; this will mark periods of missing data in buffer together with a timestamp
|
||||
// TODO: add invalid (DBL_MAX) value; this will mark periods of missing data in buffer together with a timestamp
|
||||
}
|
||||
}
|
||||
}
|
||||
// --- End Class HstryBuf ---------------
|
||||
|
||||
// --- Class HstryBuffers ---------------
|
||||
HstryBuffers::HstryBuffers(int size, BoatValueList* boatValues, GwLog* log)
|
||||
HstryBuffers::HstryBuffers(const int size, BoatValueList* boatValues, GwLog* log)
|
||||
: size(size)
|
||||
, boatValueList(boatValues)
|
||||
, logger(log) { };
|
||||
|
||||
// Create history buffer for boat data type
|
||||
void HstryBuffers::addBuffer(const String& name)
|
||||
void HstryBuffers::addBuffer(const String& name, const bool smooth)
|
||||
{
|
||||
if (HstryBuffers::getBuffer(name) != nullptr) { // buffer for this data type already exists
|
||||
return;
|
||||
}
|
||||
if (bufferParams.find(name) == bufferParams.end()) { // requested boat data type is not supported in list of <bufferParams>
|
||||
|
||||
auto it = bufferParams.find(name);
|
||||
if (it == bufferParams.end() && !name.startsWith("xdr")) { // requested boat data type is not supported in list of <bufferParams>
|
||||
// we take any "XDR" type, though
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize metadata for buffer
|
||||
String valueFormat = bufferParams[name].format; // Data format of boat data type
|
||||
// String valueFormat = boatValueList->findValueOrCreate(name)->getFormat().c_str(); // Unfortunately, format is not yet available during system initialization
|
||||
int hstryUpdFreq = bufferParams[name].hstryUpdFreq; // Update frequency for history buffers in ms
|
||||
int mltplr = bufferParams[name].mltplr; // default multiplier which transforms original <double> value into buffer type format
|
||||
double bufferMinVal = bufferParams[name].bufferMinVal; // Min value for this history buffer
|
||||
double bufferMaxVal = bufferParams[name].bufferMaxVal; // Max value for this history buffer
|
||||
// create buffer only; initialization with metadata can only be done later after boat data have been updated first time
|
||||
hstryBuffers[name] = std::unique_ptr<HstryBuf>(new HstryBuf(name, size, boatValueList, smooth, logger));
|
||||
|
||||
hstryBuffers[name] = std::unique_ptr<HstryBuf>(new HstryBuf(name, size, boatValueList, logger));
|
||||
hstryBuffers[name]->init(valueFormat, hstryUpdFreq, mltplr, bufferMinVal, bufferMaxVal);
|
||||
LOG_DEBUG(GwLog::DEBUG, "HstryBuffers: new buffer added: name: %s, format: %s, multiplier: %d, min value: %.2f, max value: %.2f", name, valueFormat, mltplr, bufferMinVal, bufferMaxVal);
|
||||
LOG_DEBUG(GwLog::LOG, "HstryBuffers: new buffer added: name: %s", name);
|
||||
}
|
||||
|
||||
// Handle all registered history buffers
|
||||
@@ -295,6 +315,35 @@ void HstryBuffers::handleHstryBufs(bool useSimuData, CommonData& common)
|
||||
{
|
||||
for (auto& bufMap : hstryBuffers) {
|
||||
auto& buf = bufMap.second;
|
||||
|
||||
if (!buf->hasMetaData()) { // meta data initialization for buffer has not been done before
|
||||
|
||||
String valueFormat = boatValueList->findValueOrCreate(buf->boatDataName)->getFormat().c_str();
|
||||
// LOG_DEBUG(GwLog::DEBUG, "HstryBuffers: value name: %s, format: %s", boatValueList->findValueOrCreate(buf->boatDataName)->getName().c_str(), valueFormat);
|
||||
|
||||
if (!valueFormat.isEmpty()) {
|
||||
String lookupKey = buf->boatDataName;
|
||||
if (buf->boatDataName.startsWith("xdr")) { // current boat data is of type "XDR"
|
||||
lookupKey = valueFormat;
|
||||
}
|
||||
auto it = bufferParams.find(lookupKey);
|
||||
if (it == bufferParams.end()) { // requested boat data type is not supported in list of <bufferParams>
|
||||
return;
|
||||
}
|
||||
HistoryParams params = it->second; // this is the metadata for the new buffer
|
||||
|
||||
int hstryUpdFreq = params.hstryUpdFreq; // Update frequency for history buffers in ms
|
||||
double mltplr = params.mltplr; // default multiplier which transforms original <double> value into buffer type format
|
||||
double bufferMinVal = params.bufferMinVal; // Min value for this history buffer
|
||||
double bufferMaxVal = params.bufferMaxVal; // Max value for this history buffer
|
||||
|
||||
hstryBuffers[buf->boatDataName]->init(valueFormat, hstryUpdFreq, mltplr, bufferMinVal, bufferMaxVal);
|
||||
buf->metaDataDefined = true;
|
||||
LOG_DEBUG(GwLog::LOG, "HstryBuffers::handleBufs: metadata added: name: %s, format: %s, frequency: %d, multiplier: %f, min value: %.2f, max value: %.2f", buf->boatDataName, valueFormat, hstryUpdFreq,
|
||||
mltplr, bufferMinVal, bufferMaxVal);
|
||||
}
|
||||
}
|
||||
|
||||
buf->handle(useSimuData, common);
|
||||
}
|
||||
}
|
||||
@@ -402,8 +451,6 @@ bool WindUtils::calcHDT(const double* hdmVal, const double* varVal, const double
|
||||
*hdtVal = DBL_MAX; // Cannot calculate HDT without valid HDM or HDM+VAR or COG
|
||||
return false;
|
||||
}
|
||||
// LOG_DEBUG(GwLog::DEBUG, "WindUtils:calcHDT: HDT: %.1f, HDM %.1f, VAR %.1f, COG %.1f, SOG %.1f", *hdtVal * RAD_TO_DEG, *hdmVal * RAD_TO_DEG, *varVal * RAD_TO_DEG,
|
||||
// *cogVal * RAD_TO_DEG, *sogVal * 3.6 / 1.852);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -451,7 +498,6 @@ bool WindUtils::calcTrueWinds(const double* awaVal, const double* awsVal, const
|
||||
// If STW and SOG are not available, we cannot calculate true wind
|
||||
return false;
|
||||
}
|
||||
// LOG_DEBUG(GwLog::DEBUG, "WindUtils:calcTrueWinds: HDT: %.1f, CTW %.1f, STW %.1f", *hdtVal * RAD_TO_DEG, ctw * RAD_TO_DEG, stw * 3.6 / 1.852);
|
||||
|
||||
calcTwdSA(awaVal, awsVal, awd, &ctw, &stw, hdtVal, &twa, &tws, &twd);
|
||||
*twaVal = twa;
|
||||
@@ -461,10 +507,24 @@ bool WindUtils::calcTrueWinds(const double* awaVal, const double* awsVal, const
|
||||
return true;
|
||||
}
|
||||
|
||||
// Set max wind speed
|
||||
void WindUtils::setMaxWs(GwApi::BoatValue* wsMaxValue, const double* wsVal)
|
||||
{
|
||||
static double maxWs = 0.0; // maintain own maxTWS value in obp user task; core gateway would reset MaxTWS obp boat value if true wind data is not available
|
||||
|
||||
if (*wsVal != DBL_MAX && *wsVal > maxWs) {
|
||||
maxWs = *wsVal;
|
||||
}
|
||||
|
||||
if (maxWs > 0.0 && maxWs >= wsMaxValue->value) {
|
||||
wsMaxValue->value = maxWs; // overwrite core gateway value each second again with own user task value if that value is larger
|
||||
wsMaxValue->valid = true;
|
||||
}
|
||||
};
|
||||
|
||||
// Calculate true wind data and add to obp60task boat data list
|
||||
bool WindUtils::handleWinds(bool calcWinds)
|
||||
{
|
||||
double twd, tws, twa, awd;
|
||||
bool twCalculated = false;
|
||||
|
||||
double awaVal = awaBVal->valid ? awaBVal->value : DBL_MAX;
|
||||
@@ -477,8 +537,6 @@ bool WindUtils::handleWinds(bool calcWinds)
|
||||
double varVal = varBVal->valid ? varBVal->value : DBL_MAX;
|
||||
double twaVal = twaBVal->valid ? twaBVal->value : DBL_MAX;
|
||||
double twsVal = twsBVal->valid ? twsBVal->value : DBL_MAX;
|
||||
// LOG_DEBUG(GwLog::DEBUG, "WindUtils:handleWinds: AWA %.1f, AWS %.1f, AWD %.1f, COG %.1f, STW %.1f, SOG %.2f, HDT %.1f, HDM %.1f, VAR %.1f", awaVal * RAD_TO_DEG, awsVal * 3.6 / 1.852,
|
||||
// awd * RAD_TO_DEG, cogVal * RAD_TO_DEG, stwVal * 3.6 / 1.852, sogVal * 3.6 / 1.852, hdtVal * RAD_TO_DEG, hdmVal * RAD_TO_DEG, varVal * RAD_TO_DEG);
|
||||
|
||||
if (calcHDT(&hdmVal, &varVal, &cogVal, &sogVal, &hdtVal)) {
|
||||
hdtBVal->value = hdtVal;
|
||||
@@ -489,20 +547,18 @@ bool WindUtils::handleWinds(bool calcWinds)
|
||||
return false;
|
||||
}
|
||||
|
||||
// calculate AWD if not existing and if possible
|
||||
// calculate AWD if it does not exist yet and AWA is available
|
||||
if (!awdBVal->valid) {
|
||||
if (calcWD(&awaVal, &hdtVal, &awd)) {
|
||||
awdBVal->value = awd;
|
||||
awdBVal->valid = true;
|
||||
} else {
|
||||
awdBVal->valid = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// calculate TWD if not existing and if possible
|
||||
if (!twdBVal->valid) {
|
||||
// calculate TWD if it does not exist yet and TWA is available
|
||||
if (!twdBVal->valid) {
|
||||
if (calcWD(&twaVal, &hdtVal, &twd)) {
|
||||
twdBVal->value = twd;
|
||||
twdBVal->valid = true;
|
||||
@@ -511,8 +567,12 @@ bool WindUtils::handleWinds(bool calcWinds)
|
||||
}
|
||||
}
|
||||
|
||||
if (calcWinds && (!twaBVal->valid || !twsBVal->valid || !twdBVal->valid)) {
|
||||
// calculate true winds if user setting and at least one of three true wind values does not exist
|
||||
if (!calcWinds) { // don't calculate true winds from apparent winds if not set in configuration
|
||||
return twCalculated;
|
||||
}
|
||||
|
||||
if (!twaBVal->valid || !twsBVal->valid || !twdBVal->valid) {
|
||||
// calculate true winds at least one of three true wind values does not exist
|
||||
twCalculated = calcTrueWinds(&awaVal, &awsVal, &awd, &cogVal, &stwVal, &sogVal, &hdtVal, &twa, &tws, &twd);
|
||||
if (twCalculated) { // Replace values only, if successfully calculated and not already available
|
||||
if (!twaBVal->valid) {
|
||||
@@ -529,8 +589,6 @@ bool WindUtils::handleWinds(bool calcWinds)
|
||||
}
|
||||
}
|
||||
}
|
||||
// LOG_DEBUG(GwLog::DEBUG, "WindUtils:handleWinds: twCalculated %d, TWD %.1f, TWA %.1f, TWS %.2f kn, AWD: %.1f", twCalculated, twdBVal->value * RAD_TO_DEG,
|
||||
// twaBVal->value * RAD_TO_DEG, twsBVal->value * 3.6 / 1.852, awdBVal->value * RAD_TO_DEG);
|
||||
|
||||
return twCalculated;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "OBPRingBuffer.h"
|
||||
#include "Pagedata.h"
|
||||
#include "obp60task.h"
|
||||
#include "movingAvg.h"
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -36,17 +37,24 @@ public:
|
||||
class HstryBuf {
|
||||
private:
|
||||
RingBuffer<uint16_t> hstryBuf; // Circular buffer to store history values
|
||||
movingAvg<double> chrtAvg {6}; // Store average of the last 6 chart values if chart gradient shall be smoothed
|
||||
movingAvgAngle<double> chrtAvgAngle {6}; // Store average of the last 6 chart values (angle data) if chart gradient shall be smoothed
|
||||
String boatDataName;
|
||||
double hstryMin;
|
||||
double hstryMax;
|
||||
bool metaDataDefined = false;
|
||||
bool smoothing = false;
|
||||
bool isTypeAngle = false;
|
||||
unsigned long bufUpdateTime;
|
||||
GwApi::BoatValue* boatValue;
|
||||
GwLog* logger;
|
||||
|
||||
friend class HstryBuffers;
|
||||
|
||||
public:
|
||||
HstryBuf(const String& name, int size, BoatValueList* boatValues, GwLog* log);
|
||||
void init(const String& format, int updFreq, int mltplr, double minVal, double maxVal);
|
||||
HstryBuf(const String& name, const int size, BoatValueList* boatValues, const bool smooth, GwLog* log);
|
||||
bool hasMetaData() const { return metaDataDefined; };
|
||||
void init(const String& format, int updFreq, double mltplr, double minVal, double maxVal);
|
||||
void add(double value);
|
||||
void handle(bool useSimuData, CommonData& common);
|
||||
};
|
||||
@@ -61,70 +69,89 @@ private:
|
||||
|
||||
struct HistoryParams {
|
||||
int hstryUpdFreq; // update frequency of history buffer (documentation only)
|
||||
int mltplr; // specifies actual value precision being storable:
|
||||
// [10000: 0 - 6.5535 | 1000: 0 - 65.535 | 100: 0 - 650.35 | 10: 0 - 6503.5
|
||||
double mltplr; // specifies actual value precision being storable:
|
||||
// [10000: 0 - 6.5535 | 1000: 0 - 65.535 | 100: 0 - 655.35 | 10: 0 - 6553.5 | 1: 0 - 65535 | 0.1: 0 - 655350]
|
||||
double bufferMinVal; // minimum valid data value
|
||||
double bufferMaxVal; // maximum valid data value
|
||||
String format; // format of data type
|
||||
};
|
||||
|
||||
// Define buffer parameters for supported boat data type
|
||||
std::map<String, HistoryParams> bufferParams = {
|
||||
{ "AWA", { 1000, 10000, 0.0, M_TWOPI, "formatWind" } },
|
||||
{ "AWD", { 1000, 10000, 0.0, M_TWOPI, "formatCourse" } },
|
||||
{ "AWS", { 1000, 1000, 0.0, 65.0, "formatKnots" } },
|
||||
{ "COG", { 1000, 10000, 0.0, M_TWOPI, "formatCourse" } },
|
||||
{ "DBS", { 1000, 100, 0.0, 650.0, "formatDepth" } },
|
||||
{ "DBT", { 1000, 100, 0.0, 650.0, "formatDepth" } },
|
||||
{ "DPT", { 1000, 100, 0.0, 650.0, "formatDepth" } },
|
||||
{ "HDM", { 1000, 10000, 0.0, M_TWOPI, "formatCourse" } },
|
||||
{ "HDT", { 1000, 10000, 0.0, M_TWOPI, "formatCourse" } },
|
||||
{ "ROT", { 1000, 10000, -M_PI / 180.0 * 99.0, M_PI / 180.0 * 99.0, "formatRot" } }, // min/max is -/+ 99 degrees for "rate of turn"
|
||||
{ "SOG", { 1000, 1000, 0.0, 65.0, "formatKnots" } },
|
||||
{ "STW", { 1000, 1000, 0.0, 65.0, "formatKnots" } },
|
||||
{ "TWA", { 1000, 10000, 0.0, M_TWOPI, "formatWind" } },
|
||||
{ "TWD", { 1000, 10000, 0.0, M_TWOPI, "formatCourse" } },
|
||||
{ "TWS", { 1000, 1000, 0.0, 65.0, "formatKnots" } },
|
||||
{ "WTemp", { 1000, 100, 233.0, 650.0, "kelvinToC" } } // [-50..376] °C
|
||||
{ "AWA", { 1000, 10000, 0.0, M_TWOPI } },
|
||||
{ "AWD", { 1000, 10000, 0.0, M_TWOPI } },
|
||||
{ "AWS", { 1000, 1000, 0.0, 65.0 } },
|
||||
{ "COG", { 1000, 10000, 0.0, M_TWOPI } },
|
||||
{ "DBK", { 1000, 100, 0.0, 650.0 } },
|
||||
{ "DBS", { 1000, 100, 0.0, 650.0 } },
|
||||
{ "DBT", { 1000, 100, 0.0, 650.0 } },
|
||||
{ "DPT", { 1000, 100, 0.0, 650.0 } },
|
||||
{ "HDM", { 1000, 10000, 0.0, M_TWOPI } },
|
||||
{ "HDT", { 1000, 10000, 0.0, M_TWOPI } },
|
||||
{ "ROT", { 1000, 10000, -M_PI / 180.0 * 99.0, M_PI / 180.0 * 99.0 } }, // min/max is -/+ 99 degrees for "rate of turn"
|
||||
{ "SOG", { 1000, 1000, 0.0, 65.0 } },
|
||||
{ "STW", { 1000, 1000, 0.0, 65.0 } },
|
||||
{ "TWA", { 1000, 10000, 0.0, M_TWOPI } },
|
||||
{ "TWD", { 1000, 10000, 0.0, M_TWOPI } },
|
||||
{ "TWS", { 1000, 1000, 0.0, 65.0 } },
|
||||
{ "WTemp", { 1000, 100, 263.15, 403.15 } }, // water temp [-10..130] °C
|
||||
{ "formatXdr:C:K", { 1000, 100, 223.15, 423.15 } }, // temperature [-50..150] deg celsius
|
||||
{ "formatXdr:P:B", { 60000, 1000, 0, 65.0 } }, // pressure [0..65] bar
|
||||
{ "formatXdr:P:P", { 60000, 0.1, 0, 650000 } }, // pressure [0..6500] hPa
|
||||
{ "formatXdr:H:P", { 1000, 100, 0, 100 } }, // humidity [0..100] percent
|
||||
{ "formatXdr:I:A", { 1000, 100, 0, 650.0 } }, // current [0..650] amperes
|
||||
{ "formatXdr:U:V", { 1000, 1000, 0, 65.0 } }, // voltage [0..65] volts
|
||||
{ "formatXdr:T:R", { 1000, 1, 0, 30000 } }, // tachometer [0..30000] rpm
|
||||
{ "formatXdr:V:L", { 10000, 100, 0, 650 } }, // volume [0..650] litres
|
||||
{ "formatXdr:V:M", { 10000, 10000, 0, 6.50 } }, // volume [0..6.5] m^3
|
||||
};
|
||||
|
||||
public:
|
||||
HstryBuffers(int size, BoatValueList* boatValues, GwLog* log);
|
||||
void addBuffer(const String& name);
|
||||
void addBuffer(const String& name, const bool smooth);
|
||||
void handleHstryBufs(bool useSimuData, CommonData& common);
|
||||
RingBuffer<uint16_t>* getBuffer(const String& name);
|
||||
};
|
||||
|
||||
class WindUtils {
|
||||
private:
|
||||
GwApi::BoatValue *twaBVal, *twsBVal, *twdBVal;
|
||||
GwApi::BoatValue *twaBVal, *twsBVal, *twdBVal, *maxtwsBVal;
|
||||
GwApi::BoatValue *awaBVal, *awsBVal, *awdBVal;
|
||||
GwApi::BoatValue *cogBVal, *stwBVal, *sogBVal, *hdtBVal, *hdmBVal, *varBVal;
|
||||
double twd, tws, twa, awd;
|
||||
static constexpr double DBL_MAX = std::numeric_limits<double>::max();
|
||||
GwLog* logger;
|
||||
|
||||
// specify missing data for boat value type AWD; AWD is not available in core gateway and need to be specified here
|
||||
void defineAWD() {
|
||||
awdBVal->setFormat("formatCourse");
|
||||
awdBVal->valid = false;
|
||||
}
|
||||
|
||||
public:
|
||||
WindUtils(BoatValueList* boatValues, GwLog* log)
|
||||
: logger(log)
|
||||
{
|
||||
twaBVal = boatValues->findValueOrCreate("TWA");
|
||||
twsBVal = boatValues->findValueOrCreate("TWS");
|
||||
maxtwsBVal = boatValues->findValueOrCreate("MaxTws");
|
||||
twdBVal = boatValues->findValueOrCreate("TWD");
|
||||
awaBVal = boatValues->findValueOrCreate("AWA");
|
||||
awsBVal = boatValues->findValueOrCreate("AWS");
|
||||
awdBVal = boatValues->findValueOrCreate("AWD");
|
||||
cogBVal = boatValues->findValueOrCreate("COG");
|
||||
stwBVal = boatValues->findValueOrCreate("STW");
|
||||
sogBVal = boatValues->findValueOrCreate("SOG");
|
||||
hdtBVal = boatValues->findValueOrCreate("HDT");
|
||||
hdmBVal = boatValues->findValueOrCreate("HDM");
|
||||
varBVal = boatValues->findValueOrCreate("VAR");
|
||||
|
||||
awdBVal = boatValues->findValueOrCreate("AWD");
|
||||
defineAWD();
|
||||
};
|
||||
|
||||
static double to2PI(double a);
|
||||
static double toPI(double a);
|
||||
static double to360(double a);
|
||||
static double to180(double a);
|
||||
|
||||
void toCart(const double* phi, const double* r, double* x, double* y);
|
||||
void toPol(const double* x, const double* y, double* phi, double* r);
|
||||
void addPolar(const double* phi1, const double* r1,
|
||||
@@ -137,5 +164,7 @@ public:
|
||||
bool calcTrueWinds(const double* awaVal, const double* awsVal, const double* awd,
|
||||
const double* cogVal, const double* stwVal, const double* sogVal, const double* hdtVal,
|
||||
double* twdVal, double* twsVal, double* twaVal);
|
||||
void setMaxWs(GwApi::BoatValue *wsMaxValue, const double * wsVal);
|
||||
void setMaxWs() { setMaxWs(maxtwsBVal, &tws); };
|
||||
bool handleWinds(bool calcWinds);
|
||||
};
|
||||
@@ -45,9 +45,9 @@ private:
|
||||
size_t last; // Points to the last (newest) valid element
|
||||
size_t count; // Number of valid elements currently in buffer
|
||||
bool is_Full; // Indicates that all buffer elements are used and ringing is in use
|
||||
T MIN_VAL; // lowest possible value of buffer of type <T>
|
||||
T MAX_VAL; // highest possible value of buffer of type <T> -> indicates invalid value in buffer
|
||||
double dblMIN_VAL, dblMAX_VAL; // MIN_VAL, MAX_VAL in double format
|
||||
T NUMLIMIT_LOW; // internally lowest possible value of buffer of type <T>
|
||||
T NUMLIMIT_HIGH; // internally highest possible value of buffer of type <T>
|
||||
double BUFMIN_VAL, BUFMAX_VAL; // lowest/highest possible buffer value considering multiplier -> externally used
|
||||
mutable SemaphoreHandle_t bufLocker;
|
||||
|
||||
// metadata for buffer
|
||||
@@ -55,8 +55,8 @@ private:
|
||||
String dataFmt; // Format of boat data in buffer
|
||||
int updFreq; // Update frequency in milliseconds
|
||||
double mltplr; // Multiplier which transforms original <double> value into buffer type format
|
||||
double smallest; // Value range of buffer: smallest value; needs to be => MIN_VAL
|
||||
double largest; // Value range of buffer: biggest value; needs to be < MAX_VAL, since MAX_VAL indicates invalid entries
|
||||
double lowest; // low value range for boat data in this buffer; needs to be => BUFMIN_VAL
|
||||
double highest; // high value range for boat data in this buffer; needs to be < BUFMAX_VAL, since BUFMAX_VAL indicates invalid entries
|
||||
|
||||
void initCommon();
|
||||
|
||||
@@ -64,10 +64,12 @@ public:
|
||||
RingBuffer();
|
||||
RingBuffer(size_t size);
|
||||
void setMetaData(String name, String format, int updateFrequency, double multiplier, double minValue, double maxValue); // Set meta data for buffer
|
||||
void setFormat(String format); // Specify format of buffer
|
||||
bool getMetaData(String& name, String& format, int& updateFrequency, double& multiplier, double& minValue, double& maxValue); // Get meta data of buffer
|
||||
bool getMetaData(String& name, String& format);
|
||||
String getName() const; // Get buffer name
|
||||
String getFormat() const; // Get buffer data format
|
||||
int getUpdFreq() const; // Get buffer update frequency
|
||||
void add(const double& value); // Add a new value to buffer
|
||||
double get(size_t index) const; // Get value at specific position (0-based index from oldest to newest)
|
||||
double getFirst() const; // Get the first (oldest) value in buffer
|
||||
@@ -78,6 +80,8 @@ public:
|
||||
double getMax(size_t amount) const; // Get maximum value of the last <amount> values of buffer
|
||||
double getMid() const; // Get mid value between <min> and <max> value in buffer
|
||||
double getMid(size_t amount) const; // Get mid value between <min> and <max> value of the last <amount> values of buffer
|
||||
double getCircularMid() const; // Get mid value of circle (degree) values of buffer
|
||||
double getCircularMid(size_t amount) const; // Get mid value of circle (degree) values of the last <amount> values of buffer
|
||||
double getMedian() const; // Get the median value in buffer
|
||||
double getMedian(size_t amount) const; // Get the median value of the last <amount> values of buffer
|
||||
size_t getCapacity() const; // Get the buffer capacity (maximum size)
|
||||
|
||||
+134
-110
@@ -1,24 +1,7 @@
|
||||
#include "OBPRingBuffer.h"
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
|
||||
template <typename T>
|
||||
void RingBuffer<T>::initCommon()
|
||||
{
|
||||
MIN_VAL = std::numeric_limits<T>::lowest();
|
||||
MAX_VAL = std::numeric_limits<T>::max();
|
||||
dblMIN_VAL = static_cast<double>(MIN_VAL);
|
||||
dblMAX_VAL = static_cast<double>(MAX_VAL);
|
||||
dataName = "";
|
||||
dataFmt = "";
|
||||
updFreq = -1;
|
||||
mltplr = 1;
|
||||
smallest = dblMIN_VAL;
|
||||
largest = dblMAX_VAL;
|
||||
bufLocker = xSemaphoreCreateMutex();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
RingBuffer<T>::RingBuffer()
|
||||
: capacity(0)
|
||||
@@ -44,7 +27,23 @@ RingBuffer<T>::RingBuffer(size_t size)
|
||||
initCommon();
|
||||
|
||||
buffer.reserve(size);
|
||||
buffer.resize(size, MAX_VAL); // MAX_VAL indicate invalid values
|
||||
buffer.resize(size, NUMLIMIT_HIGH); // NUMLIMIT_HIGH indicate invalid values
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void RingBuffer<T>::initCommon()
|
||||
{
|
||||
NUMLIMIT_LOW = std::numeric_limits<T>::lowest();
|
||||
NUMLIMIT_HIGH = std::numeric_limits<T>::max();
|
||||
dataName = "";
|
||||
dataFmt = "";
|
||||
updFreq = -1;
|
||||
mltplr = 1;
|
||||
BUFMIN_VAL = static_cast<double>(NUMLIMIT_LOW);
|
||||
BUFMAX_VAL = static_cast<double>(NUMLIMIT_HIGH);
|
||||
lowest = BUFMIN_VAL;
|
||||
highest = BUFMAX_VAL;
|
||||
bufLocker = xSemaphoreCreateMutex();
|
||||
}
|
||||
|
||||
// Specify meta data of buffer content
|
||||
@@ -56,8 +55,18 @@ void RingBuffer<T>::setMetaData(String name, String format, int updateFrequency,
|
||||
dataFmt = format;
|
||||
updFreq = updateFrequency;
|
||||
mltplr = multiplier;
|
||||
smallest = std::max(dblMIN_VAL, minValue);
|
||||
largest = std::min(dblMAX_VAL, maxValue);
|
||||
BUFMIN_VAL = static_cast<double>(NUMLIMIT_LOW) / mltplr; // lowest possible buffer value; converted to external view
|
||||
BUFMAX_VAL = static_cast<double>(NUMLIMIT_HIGH) / mltplr; // highest possible buffer value; converted to external view
|
||||
lowest = std::max(BUFMIN_VAL, minValue); // low value range, set by user
|
||||
highest = std::min(std::nextafter(BUFMAX_VAL, -std::numeric_limits<double>::infinity()), maxValue); // high value range, set by user; maximum is 1 tick lower than BUFMAX_VAL
|
||||
}
|
||||
|
||||
// Specify format of buffer content
|
||||
template <typename T>
|
||||
void RingBuffer<T>::setFormat(String format)
|
||||
{
|
||||
GWSYNCHRONIZED(&bufLocker);
|
||||
dataFmt = format;
|
||||
}
|
||||
|
||||
// Get meta data of buffer content
|
||||
@@ -73,8 +82,8 @@ bool RingBuffer<T>::getMetaData(String& name, String& format, int& updateFrequen
|
||||
format = dataFmt;
|
||||
updateFrequency = updFreq;
|
||||
multiplier = mltplr;
|
||||
minValue = smallest;
|
||||
maxValue = largest;
|
||||
minValue = lowest;
|
||||
maxValue = highest;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -106,13 +115,20 @@ String RingBuffer<T>::getFormat() const
|
||||
return dataFmt;
|
||||
}
|
||||
|
||||
// Get buffer update frequency
|
||||
template <typename T>
|
||||
int RingBuffer<T>::getUpdFreq() const
|
||||
{
|
||||
return updFreq;
|
||||
}
|
||||
|
||||
// Add a new value to buffer
|
||||
template <typename T>
|
||||
void RingBuffer<T>::add(const double& value)
|
||||
{
|
||||
GWSYNCHRONIZED(&bufLocker);
|
||||
if (value < smallest || value > largest) {
|
||||
buffer[head] = MAX_VAL; // Store MAX_VAL if value is out of range
|
||||
if (value < lowest || value > highest) {
|
||||
buffer[head] = NUMLIMIT_HIGH; // Store maximum buffer value if data value is out of range
|
||||
} else {
|
||||
buffer[head] = static_cast<T>(std::round(value * mltplr));
|
||||
}
|
||||
@@ -136,11 +152,11 @@ double RingBuffer<T>::get(size_t index) const
|
||||
{
|
||||
GWSYNCHRONIZED(&bufLocker);
|
||||
if (isEmpty() || index < 0 || index >= count) {
|
||||
return dblMAX_VAL;
|
||||
return BUFMAX_VAL;
|
||||
}
|
||||
|
||||
size_t realIndex = (first + index) % capacity;
|
||||
return static_cast<double>(buffer[realIndex] / mltplr);
|
||||
return static_cast<double>(buffer[realIndex] / mltplr); // is BUFMAX_VAL if value is invalid
|
||||
}
|
||||
|
||||
// Operator[] for convenient access (same as get())
|
||||
@@ -155,7 +171,7 @@ template <typename T>
|
||||
double RingBuffer<T>::getFirst() const
|
||||
{
|
||||
if (isEmpty()) {
|
||||
return dblMAX_VAL;
|
||||
return BUFMAX_VAL;
|
||||
}
|
||||
return get(0);
|
||||
}
|
||||
@@ -165,7 +181,7 @@ template <typename T>
|
||||
double RingBuffer<T>::getLast() const
|
||||
{
|
||||
if (isEmpty()) {
|
||||
return dblMAX_VAL;
|
||||
return BUFMAX_VAL;
|
||||
}
|
||||
return get(count - 1);
|
||||
}
|
||||
@@ -174,19 +190,7 @@ double RingBuffer<T>::getLast() const
|
||||
template <typename T>
|
||||
double RingBuffer<T>::getMin() const
|
||||
{
|
||||
if (isEmpty()) {
|
||||
return dblMAX_VAL;
|
||||
}
|
||||
|
||||
double minVal = dblMAX_VAL;
|
||||
double value;
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
value = get(i);
|
||||
if (value < minVal && value != dblMAX_VAL) {
|
||||
minVal = value;
|
||||
}
|
||||
}
|
||||
return minVal;
|
||||
return getMin(getCurrentSize());
|
||||
}
|
||||
|
||||
// Get minimum value of the last <amount> values of buffer
|
||||
@@ -194,16 +198,16 @@ template <typename T>
|
||||
double RingBuffer<T>::getMin(size_t amount) const
|
||||
{
|
||||
if (isEmpty() || amount <= 0) {
|
||||
return dblMAX_VAL;
|
||||
return BUFMAX_VAL;
|
||||
}
|
||||
if (amount > count)
|
||||
amount = count;
|
||||
|
||||
double minVal = dblMAX_VAL;
|
||||
double minVal = BUFMAX_VAL;
|
||||
double value;
|
||||
for (size_t i = 0; i < amount; i++) {
|
||||
value = get(count - 1 - i);
|
||||
if (value < minVal && value != dblMAX_VAL) {
|
||||
if (value < minVal && value != BUFMAX_VAL) {
|
||||
minVal = value;
|
||||
}
|
||||
}
|
||||
@@ -214,22 +218,7 @@ double RingBuffer<T>::getMin(size_t amount) const
|
||||
template <typename T>
|
||||
double RingBuffer<T>::getMax() const
|
||||
{
|
||||
if (isEmpty()) {
|
||||
return dblMAX_VAL;
|
||||
}
|
||||
|
||||
double maxVal = dblMIN_VAL;
|
||||
double value;
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
value = get(i);
|
||||
if (value > maxVal && value != dblMAX_VAL) {
|
||||
maxVal = value;
|
||||
}
|
||||
}
|
||||
if (maxVal == dblMIN_VAL) { // no change of initial value -> buffer has only invalid values (MAX_VAL)
|
||||
maxVal = dblMAX_VAL;
|
||||
}
|
||||
return maxVal;
|
||||
return getMax(getCurrentSize());
|
||||
}
|
||||
|
||||
// Get maximum value of the last <amount> values of buffer
|
||||
@@ -237,21 +226,21 @@ template <typename T>
|
||||
double RingBuffer<T>::getMax(size_t amount) const
|
||||
{
|
||||
if (isEmpty() || amount <= 0) {
|
||||
return dblMAX_VAL;
|
||||
return BUFMAX_VAL;
|
||||
}
|
||||
if (amount > count)
|
||||
amount = count;
|
||||
|
||||
double maxVal = dblMIN_VAL;
|
||||
double maxVal = BUFMIN_VAL;
|
||||
double value;
|
||||
for (size_t i = 0; i < amount; i++) {
|
||||
value = get(count - 1 - i);
|
||||
if (value > maxVal && value != dblMAX_VAL) {
|
||||
if (value > maxVal && value != BUFMAX_VAL) {
|
||||
maxVal = value;
|
||||
}
|
||||
}
|
||||
if (maxVal == dblMIN_VAL) { // no change of initial value -> buffer has only invalid values (MAX_VAL)
|
||||
maxVal = dblMAX_VAL;
|
||||
if (maxVal == BUFMIN_VAL) { // no change of initial value -> buffer has only invalid values (BUFMAX_VAL)
|
||||
maxVal = BUFMAX_VAL;
|
||||
}
|
||||
return maxVal;
|
||||
}
|
||||
@@ -260,11 +249,7 @@ double RingBuffer<T>::getMax(size_t amount) const
|
||||
template <typename T>
|
||||
double RingBuffer<T>::getMid() const
|
||||
{
|
||||
if (isEmpty()) {
|
||||
return dblMAX_VAL;
|
||||
}
|
||||
|
||||
return (getMin() + getMax()) / 2;
|
||||
return getMid(getCurrentSize());
|
||||
}
|
||||
|
||||
// Get mid value between <min> and <max> value of the last <amount> values of buffer
|
||||
@@ -272,7 +257,7 @@ template <typename T>
|
||||
double RingBuffer<T>::getMid(size_t amount) const
|
||||
{
|
||||
if (isEmpty() || amount <= 0) {
|
||||
return dblMAX_VAL;
|
||||
return BUFMAX_VAL;
|
||||
}
|
||||
|
||||
if (amount > count)
|
||||
@@ -285,29 +270,7 @@ double RingBuffer<T>::getMid(size_t amount) const
|
||||
template <typename T>
|
||||
double RingBuffer<T>::getMedian() const
|
||||
{
|
||||
if (isEmpty()) {
|
||||
return dblMAX_VAL;
|
||||
}
|
||||
|
||||
// Create a temporary vector with current valid elements
|
||||
std::vector<T> temp;
|
||||
temp.reserve(count);
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
temp.push_back(get(i));
|
||||
}
|
||||
|
||||
// Sort to find median
|
||||
std::sort(temp.begin(), temp.end());
|
||||
|
||||
if (count % 2 == 1) {
|
||||
// Odd number of elements
|
||||
return static_cast<double>(temp[count / 2]);
|
||||
} else {
|
||||
// Even number of elements - return average of middle two
|
||||
// Note: For integer types, this truncates. For floating point, it's exact.
|
||||
return static_cast<double>((temp[count / 2 - 1] + temp[count / 2]) / 2);
|
||||
}
|
||||
return getMedian(getCurrentSize());
|
||||
}
|
||||
|
||||
// Get the median value of the last <amount> values of buffer
|
||||
@@ -315,13 +278,13 @@ template <typename T>
|
||||
double RingBuffer<T>::getMedian(size_t amount) const
|
||||
{
|
||||
if (isEmpty() || amount <= 0) {
|
||||
return dblMAX_VAL;
|
||||
return BUFMAX_VAL;
|
||||
}
|
||||
if (amount > count)
|
||||
amount = count;
|
||||
|
||||
// Create a temporary vector with current valid elements
|
||||
std::vector<T> temp;
|
||||
std::vector<double> temp;
|
||||
temp.reserve(amount);
|
||||
|
||||
for (size_t i = 0; i < amount; i++) {
|
||||
@@ -331,16 +294,84 @@ double RingBuffer<T>::getMedian(size_t amount) const
|
||||
// Sort to find median
|
||||
std::sort(temp.begin(), temp.end());
|
||||
|
||||
if (temp[0] == BUFMAX_VAL) { // 1st element of sorted vector is already BUFMAX_VAL -> only invalid entries in buffer, so we return invalid value
|
||||
return BUFMAX_VAL;
|
||||
}
|
||||
|
||||
if (amount % 2 == 1) {
|
||||
// Odd number of elements
|
||||
return static_cast<double>(temp[amount / 2]);
|
||||
return temp[amount / 2];
|
||||
} else {
|
||||
// Even number of elements - return average of middle two
|
||||
// Note: For integer types, this truncates. For floating point, it's exact.
|
||||
return static_cast<double>((temp[amount / 2 - 1] + temp[amount / 2]) / 2);
|
||||
return (temp[amount / 2 - 1] + temp[amount / 2]) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Get mid value of circle (degree) values of buffer
|
||||
template <typename T>
|
||||
double RingBuffer<T>::getCircularMid() const
|
||||
{
|
||||
return getCircularMid(getCurrentSize());
|
||||
}
|
||||
|
||||
// Get mid value of circle (degree) values of the last <amount> values of buffer
|
||||
template <typename T>
|
||||
double RingBuffer<T>::getCircularMid(size_t amount) const
|
||||
{
|
||||
if (isEmpty() || amount <= 0) {
|
||||
return BUFMAX_VAL;
|
||||
}
|
||||
if (amount > count)
|
||||
amount = count;
|
||||
|
||||
std::vector<double> a;
|
||||
// Create a temporary vector with current valid elements
|
||||
std::vector<double> temp;
|
||||
temp.reserve(amount);
|
||||
|
||||
for (size_t i = 0; i < amount; i++) {
|
||||
temp.push_back(get(count - 1 - i));
|
||||
}
|
||||
|
||||
// Sort to find largest gap
|
||||
std::sort(temp.begin(), temp.end());
|
||||
|
||||
if (temp[0] == BUFMAX_VAL) { // 1st element of sorted vector is already BUFMAX_VAL -> only invalid entries in buffer, so we return invalid value
|
||||
return BUFMAX_VAL;
|
||||
}
|
||||
|
||||
// Find the largest gap
|
||||
double largestGap = BUFMIN_VAL;
|
||||
std::size_t gapIndex = 0;
|
||||
|
||||
for (std::size_t i = 0; i < temp.size(); ++i)
|
||||
{
|
||||
std::size_t next = (i + 1) % temp.size();
|
||||
|
||||
double gap;
|
||||
if (next == 0)
|
||||
gap = (temp[0] + M_TWOPI) - temp[i];
|
||||
else
|
||||
gap = temp[next] - temp[i];
|
||||
|
||||
if (gap > largestGap)
|
||||
{
|
||||
largestGap = gap;
|
||||
gapIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
double start = temp[(gapIndex + 1) % temp.size()]; // Start of occupied arc = first angle after largest gap
|
||||
double arcWidth = M_TWOPI - largestGap; // Width of occupied arc
|
||||
arcWidth = start + arcWidth / 2.0;
|
||||
arcWidth = fmod(arcWidth, M_TWOPI);
|
||||
if (arcWidth < 0.0) {
|
||||
arcWidth += M_TWOPI;
|
||||
}
|
||||
|
||||
return arcWidth; // Midpoint of occupied arc
|
||||
}
|
||||
|
||||
// Get the buffer capacity (maximum size)
|
||||
template <typename T>
|
||||
size_t RingBuffer<T>::getCapacity() const
|
||||
@@ -387,14 +418,14 @@ bool RingBuffer<T>::isFull() const
|
||||
template <typename T>
|
||||
double RingBuffer<T>::getMinVal() const
|
||||
{
|
||||
return dblMIN_VAL;
|
||||
return BUFMIN_VAL;
|
||||
}
|
||||
|
||||
// Get highest possible value for buffer; used for unset/invalid buffer data
|
||||
template <typename T>
|
||||
double RingBuffer<T>::getMaxVal() const
|
||||
{
|
||||
return dblMAX_VAL;
|
||||
return BUFMAX_VAL;
|
||||
}
|
||||
|
||||
// Clear buffer
|
||||
@@ -423,21 +454,14 @@ void RingBuffer<T>::resize(size_t newSize)
|
||||
|
||||
buffer.clear();
|
||||
buffer.reserve(newSize);
|
||||
buffer.resize(newSize, MAX_VAL);
|
||||
buffer.resize(newSize, NUMLIMIT_HIGH);
|
||||
}
|
||||
|
||||
// Get all current values in native buffer format as a vector
|
||||
template <typename T>
|
||||
std::vector<double> RingBuffer<T>::getAllValues() const
|
||||
{
|
||||
std::vector<double> result;
|
||||
result.reserve(count);
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
result.push_back(get(i));
|
||||
}
|
||||
|
||||
return result;
|
||||
return getAllValues(getCurrentSize());
|
||||
}
|
||||
|
||||
// Get last <amount> values in native buffer format as a vector
|
||||
|
||||
+229
-187
@@ -3,14 +3,6 @@
|
||||
#include "OBPDataOperations.h"
|
||||
#include "OBPRingBuffer.h"
|
||||
|
||||
std::map<String, ChartProps> Chart::dfltChrtDta = {
|
||||
{ "formatWind", { 60.0 * DEG_TO_RAD, 10.0 * DEG_TO_RAD } }, // default course range 60 degrees
|
||||
{ "formatCourse", { 60.0 * DEG_TO_RAD, 10.0 * DEG_TO_RAD } }, // default course range 60 degrees
|
||||
{ "formatKnots", { 2.57, 2.57 } }, // default speed range in m/s
|
||||
{ "formatDepth", { 10.0, 5.0 } }, // default depth range in m
|
||||
{ "kelvinToC", { 20.0, 5.0 } } // default temp range in °C/K
|
||||
};
|
||||
|
||||
// --- Class Chart ---------------
|
||||
|
||||
// Chart - object holding the actual chart, incl. data buffer and format definition
|
||||
@@ -18,9 +10,8 @@ std::map<String, ChartProps> Chart::dfltChrtDta = {
|
||||
// <dfltRng> default range of chart, e.g. 30 = [0..30]
|
||||
// <common> common program data; required for logger and color data
|
||||
// <useSimuData> flag to indicate if simulation data is active
|
||||
Chart::Chart(RingBuffer<uint16_t>& dataBuf, double dfltRng, CommonData& common, bool useSimuData)
|
||||
Chart::Chart(RingBuffer<uint16_t>& dataBuf, CommonData& common, bool useSimuData)
|
||||
: dataBuf(dataBuf)
|
||||
, dfltRng(dfltRng)
|
||||
, commonData(&common)
|
||||
, useSimuData(useSimuData)
|
||||
{
|
||||
@@ -37,32 +28,46 @@ Chart::Chart(RingBuffer<uint16_t>& dataBuf, double dfltRng, CommonData& common,
|
||||
dHeight = getdisplay().height();
|
||||
#endif
|
||||
|
||||
init();
|
||||
};
|
||||
|
||||
Chart::~Chart()
|
||||
{
|
||||
}
|
||||
|
||||
bool Chart::init()
|
||||
{
|
||||
chrtMin = 0.0;
|
||||
chrtMax = 0.0;
|
||||
chrtMid = 0.0;
|
||||
chrtRng = 0.0;
|
||||
|
||||
dataBuf.getMetaData(dbName, dbFormat);
|
||||
dbMIN_VAL = dataBuf.getMinVal();
|
||||
dbMAX_VAL = dataBuf.getMaxVal();
|
||||
bufSize = dataBuf.getCapacity();
|
||||
|
||||
smoothCharts = common.config->getBool(common.config->smoothCharts);
|
||||
if (smoothCharts) {
|
||||
chrtAvg.begin();
|
||||
}
|
||||
// LOG_DEBUG(GwLog::DEBUG, "Chart Init: dbMIN_VAL: %.2f, dbMAX_VAL: %.2fd, bufSize: %d", dbMIN_VAL, dbMAX_VAL, bufSize);
|
||||
|
||||
// Initialize chart data format; shorter version of standard format indicator
|
||||
if (dbFormat == "formatCourse" || dbFormat == "formatWind" || dbFormat == "formatRot") {
|
||||
if (dbFormat == "formatCourse" || dbFormat == "formatWind") {
|
||||
chrtDataFmt = WIND; // Chart is showing data of course / wind <degree> format
|
||||
} else if (dbFormat == "formatRot") {
|
||||
chrtDataFmt = ROTATION; // Chart is showing data of rotational <degree> format
|
||||
} else if (dbFormat == "formatKnots") {
|
||||
chrtDataFmt = SPEED; // Chart is showing data of speed or windspeed format
|
||||
} else if (dbFormat == "formatDepth") {
|
||||
chrtDataFmt = DEPTH; // Chart ist showing data of <depth> format
|
||||
chrtDataFmt = DEPTH;
|
||||
} else if (dbFormat == "kelvinToC") {
|
||||
chrtDataFmt = TEMPERATURE; // Chart ist showing data of <temp> format
|
||||
chrtDataFmt = TEMPERATURE;
|
||||
} else if (dbFormat.startsWith("formatXdr:P")) {
|
||||
chrtDataFmt = PRESSURE;
|
||||
} else if (dbFormat.startsWith("formatXdr:H")) {
|
||||
chrtDataFmt = HUMIDITY;
|
||||
} else {
|
||||
chrtDataFmt = OTHER; // Chart is showing any other data format
|
||||
}
|
||||
|
||||
// "0" value is the same for any data format but for user defined temperature format
|
||||
// "0" value is the same for any data format but for user defined temperature and pressure format
|
||||
zeroValue = 0.0;
|
||||
if (chrtDataFmt == TEMPERATURE) {
|
||||
tempFormat = commonData->config->getString(commonData->config->tempFormat); // [K|°C|°F]
|
||||
@@ -73,6 +78,8 @@ Chart::Chart(RingBuffer<uint16_t>& dataBuf, double dfltRng, CommonData& common,
|
||||
} else if (tempFormat == "F") {
|
||||
zeroValue = 255.37;
|
||||
}
|
||||
} else if (chrtDataFmt == PRESSURE) {
|
||||
zeroValue = 98000.0; // typical low pressure area value
|
||||
}
|
||||
|
||||
// Read default range and range step for this chart type
|
||||
@@ -80,7 +87,7 @@ Chart::Chart(RingBuffer<uint16_t>& dataBuf, double dfltRng, CommonData& common,
|
||||
dfltRng = dfltChrtDta[dbFormat].range;
|
||||
rngStep = dfltChrtDta[dbFormat].step;
|
||||
} else {
|
||||
dfltRng = 15.0;
|
||||
dfltRng = 10.0;
|
||||
rngStep = 5.0;
|
||||
}
|
||||
|
||||
@@ -89,14 +96,19 @@ Chart::Chart(RingBuffer<uint16_t>& dataBuf, double dfltRng, CommonData& common,
|
||||
chrtMax = chrtMin + dfltRng;
|
||||
chrtMid = (chrtMin + chrtMax) / 2;
|
||||
chrtRng = dfltRng;
|
||||
recalcRngMid = true; // initialize <chrtMid> and chart borders on first screen call
|
||||
recalcRngMid = true; // initialize <chrtMid> and chart borders on first chart display call
|
||||
allLeft = true;
|
||||
allRight = true;
|
||||
|
||||
LOG_DEBUG(GwLog::DEBUG, "Chart Init: dWidth: %d, dHeight: %d, timAxis: %d, valAxis: %d, cRoot {x,y}: %d, %d, dbname: %s, rngStep: %.4f, chrtDataFmt: %d",
|
||||
dWidth, dHeight, timAxis, valAxis, cRoot.x, cRoot.y, dbName, rngStep, chrtDataFmt);
|
||||
};
|
||||
if (dbFormat.isEmpty()) { // data buffer may not exist yet, because boat data object is not available yet
|
||||
initValid = false; // chart object will get invalid data during initialization
|
||||
} else {
|
||||
initValid = true;
|
||||
}
|
||||
LOG_DEBUG(GwLog::DEBUG, "Chart Init: dWidth: %d, dHeight: %d, timAxis: %d, valAxis: %d, cRoot {x,y}: %d, %d, dbname: %s, rngStep: %.4f, chrtDataFmt: %d, initValid: %d",
|
||||
dWidth, dHeight, timAxis, valAxis, cRoot.x, cRoot.y, dbName, rngStep, chrtDataFmt, initValid);
|
||||
|
||||
Chart::~Chart()
|
||||
{
|
||||
return isValid();
|
||||
}
|
||||
|
||||
// Perform all actions to draw chart
|
||||
@@ -106,7 +118,7 @@ Chart::~Chart()
|
||||
// <prntName>; print data name on horizontal half chart [true|false]
|
||||
// <showCurrValue>: print current boat data value [true|false]
|
||||
// <currValue>: current boat data value; used only for test on valid data
|
||||
void Chart::showChrt(char chrtDir, int8_t chrtSz, const int8_t chrtIntv, bool prntName, bool showCurrValue, GwApi::BoatValue currValue)
|
||||
void Chart::showChrt(const ChrtDir chrtDir, ChrtSize chrtSz, const int8_t chrtIntv, bool prntName, bool showCurrValue, GwApi::BoatValue currValue)
|
||||
{
|
||||
if (!setChartDimensions(chrtDir, chrtSz)) {
|
||||
return; // wrong chart dimension parameters
|
||||
@@ -121,64 +133,74 @@ void Chart::showChrt(char chrtDir, int8_t chrtSz, const int8_t chrtIntv, bool pr
|
||||
return;
|
||||
}
|
||||
|
||||
if (showCurrValue) { // show latest value from history buffer; this should be the most current one
|
||||
currValue.value = dataBuf.getLast();
|
||||
if (showCurrValue) {
|
||||
currValue.value = dataBuf.getLast(); // show latest value from history buffer; this should be the most current one
|
||||
currValue.valid = currValue.value != dbMAX_VAL;
|
||||
prntCurrValue(chrtDir, currValue);
|
||||
}
|
||||
}
|
||||
|
||||
// define dimensions and start points for chart
|
||||
bool Chart::setChartDimensions(const char direction, const int8_t size)
|
||||
bool Chart::setChartDimensions(const ChrtDir chrtDir, const ChrtSize chrtSz)
|
||||
{
|
||||
if ((direction != HORIZONTAL && direction != VERTICAL) || (size < 0 || size > 2)) {
|
||||
if ((chrtDir != HORIZONTAL && chrtDir != VERTICAL) || (chrtSz < 0 || chrtSz > 3)) {
|
||||
LOG_DEBUG(GwLog::ERROR, "obp60:setChartDimensions %s: wrong parameters", dataBuf.getName());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (direction == HORIZONTAL) {
|
||||
if (chrtDir == HORIZONTAL) {
|
||||
// horizontal chart timeline direction
|
||||
timAxis = dWidth - 1;
|
||||
switch (size) {
|
||||
case 0:
|
||||
switch (chrtSz) {
|
||||
case ChrtSize::FULL_SIZE:
|
||||
valAxis = dHeight - top - bottom;
|
||||
cRoot = { 0, top - 1 };
|
||||
break;
|
||||
case 1:
|
||||
case HALF_SIZE_LEFT_TOP:
|
||||
valAxis = (dHeight - top - bottom) / 2 - hGap;
|
||||
cRoot = { 0, top - 1 };
|
||||
break;
|
||||
case 2:
|
||||
case HALF_SIZE_RIGHT_BOTTOM:
|
||||
valAxis = (dHeight - top - bottom) / 2 - hGap;
|
||||
cRoot = { 0, top + (valAxis + hGap) + hGap - 1 };
|
||||
break;
|
||||
case TWO_THIRD_TOP:
|
||||
valAxis = (dHeight - top - bottom) * 0.667 - hGap;
|
||||
cRoot = { 0, top - 1 };
|
||||
break;
|
||||
default: // same as case 0; should never happen
|
||||
valAxis = dHeight - top - bottom;
|
||||
cRoot = { 0, top - 1 };
|
||||
}
|
||||
|
||||
} else if (direction == VERTICAL) {
|
||||
} else {
|
||||
// vertical chart timeline direction
|
||||
timAxis = dHeight - top - bottom;
|
||||
switch (size) {
|
||||
case 0:
|
||||
switch (chrtSz) {
|
||||
case FULL_SIZE:
|
||||
valAxis = dWidth - 1;
|
||||
cRoot = { 0, top - 1 };
|
||||
break;
|
||||
case 1:
|
||||
case HALF_SIZE_LEFT_TOP:
|
||||
valAxis = dWidth / 2 - vGap;
|
||||
cRoot = { 0, top - 1 };
|
||||
break;
|
||||
case 2:
|
||||
case HALF_SIZE_RIGHT_BOTTOM:
|
||||
valAxis = dWidth / 2 - vGap;
|
||||
cRoot = { dWidth / 2 + vGap - 1, top - 1 };
|
||||
cRoot = { dWidth / 2 + vGap, top - 1 };
|
||||
break;
|
||||
default: // same as case 0; should never happen
|
||||
valAxis = dWidth - 1;
|
||||
cRoot = { 0, top - 1 };
|
||||
}
|
||||
}
|
||||
//LOG_DEBUG(GwLog::DEBUG, "obp60:setChartDimensions %s: direction: %c, size: %d, dWidth: %d, dHeight: %d, timAxis: %d, valAxis: %d, cRoot{%d, %d}, top: %d, bottom: %d, hGap: %d, vGap: %d",
|
||||
// dataBuf.getName(), direction, size, dWidth, dHeight, timAxis, valAxis, cRoot.x, cRoot.y, top, bottom, hGap, vGap);
|
||||
// LOG_DEBUG(GwLog::DEBUG, "obp60:setChartDimensions %s: chrtDir: %c, size: %d, dWidth: %d, dHeight: %d, timAxis: %d, valAxis: %d, cRoot{%d, %d}, top: %d, bottom: %d, hGap: %d, vGap: %d",
|
||||
// dataBuf.getName(), chrtDir, size, dWidth, dHeight, timAxis, valAxis, cRoot.x, cRoot.y, top, bottom, hGap, vGap);
|
||||
return true;
|
||||
}
|
||||
|
||||
// draw chart
|
||||
void Chart::drawChrt(const char chrtDir, const int8_t chrtIntv, GwApi::BoatValue& currValue)
|
||||
void Chart::drawChrt(const ChrtDir chrtDir, const int8_t chrtIntv, GwApi::BoatValue& currValue)
|
||||
{
|
||||
double chrtScale; // Scale for data values in pixels per value
|
||||
|
||||
@@ -187,7 +209,7 @@ void Chart::drawChrt(const char chrtDir, const int8_t chrtIntv, GwApi::BoatValue
|
||||
// LOG_DEBUG(GwLog::DEBUG, "Chart:drawChart: min: %.1f, mid: %.1f, max: %.1f, rng: %.1f", chrtMin, chrtMid, chrtMax, chrtRng);
|
||||
calcChrtBorders(chrtMin, chrtMid, chrtMax, chrtRng);
|
||||
chrtScale = double(valAxis) / chrtRng; // Chart scale: pixels per value step
|
||||
// LOG_DEBUG(GwLog::DEBUG, "Chart:drawChart: min: %.1f, mid: %.1f, max: %.1f, rng: %.1f", chrtMin, chrtMid, chrtMax, chrtRng);
|
||||
// LOG_DEBUG(GwLog::DEBUG, "Chart:drawChart: min: %.1f, mid: %.1f, max: %.1f, rng: %.1f, data valid: %d", chrtMin, chrtMid, chrtMax, chrtRng, currValue.valid);
|
||||
|
||||
// Do we have valid buffer data?
|
||||
if (dataBuf.getMax() == dbMAX_VAL) { // only <MAX_VAL> values in buffer -> no valid wind data available
|
||||
@@ -202,7 +224,7 @@ void Chart::drawChrt(const char chrtDir, const int8_t chrtIntv, GwApi::BoatValue
|
||||
numNoData++;
|
||||
bufDataValid = true;
|
||||
|
||||
if (numNoData > THRESHOLD_NO_DATA) { // If more than 4 invalid values in a row, flag for invalid data
|
||||
if (numNoData > THRESHOLD_NO_DATA * (dataBuf.getUpdFreq() / 1000)) { // If more than <THRESHOLD> invalid values in a row, flag for invalid data
|
||||
bufDataValid = false;
|
||||
return;
|
||||
}
|
||||
@@ -217,17 +239,15 @@ void Chart::getBufferStartNSize(const int8_t chrtIntv)
|
||||
count = dataBuf.getCurrentSize();
|
||||
currIdx = dataBuf.getLastIdx();
|
||||
numAddedBufVals = (currIdx - lastAddedIdx + bufSize) % bufSize; // Number of values added to buffer since last display
|
||||
lastAddedIdx = currIdx;
|
||||
|
||||
if (chrtIntv != oldChrtIntv || count == 1) {
|
||||
// new data interval selected by user; this is only x * 230 values instead of 240 seconds (4 minutes) per interval step
|
||||
if (chrtIntv != oldChrtIntv || count == 1) { // new data interval selected by user
|
||||
numBufVals = min(count, (timAxis - MIN_FREE_VALUES) * chrtIntv); // keep free or release MIN_FREE_VALUES on chart for plotting of new values
|
||||
bufStart = max(0, count - numBufVals);
|
||||
lastAddedIdx = currIdx;
|
||||
oldChrtIntv = chrtIntv;
|
||||
|
||||
} else {
|
||||
numBufVals = numBufVals + numAddedBufVals;
|
||||
lastAddedIdx = currIdx;
|
||||
if (count == bufSize) {
|
||||
bufStart = max(0, bufStart - numAddedBufVals);
|
||||
}
|
||||
@@ -239,6 +259,7 @@ void Chart::calcChrtBorders(double& rngMin, double& rngMid, double& rngMax, doub
|
||||
{
|
||||
if (chrtDataFmt == WIND || chrtDataFmt == ROTATION) {
|
||||
|
||||
// calculate rngMid
|
||||
if (chrtDataFmt == ROTATION) {
|
||||
// if chart data is of type 'rotation', we want to have <rndMid> always to be '0'
|
||||
rngMid = 0;
|
||||
@@ -253,22 +274,12 @@ void Chart::calcChrtBorders(double& rngMin, double& rngMid, double& rngMax, doub
|
||||
if (recalcRngMid) {
|
||||
// Set rngMid
|
||||
|
||||
rngMid = dataBuf.getMid(numBufVals);
|
||||
rngMid = dataBuf.getCircularMid(numBufVals);
|
||||
|
||||
if (rngMid == dbMAX_VAL) {
|
||||
rngMid = 0;
|
||||
} else {
|
||||
rngMid = std::round(rngMid / rngStep) * rngStep; // Set new center value; round to next <rngStep> value
|
||||
|
||||
// Check if range between 'min' and 'max' is > 180° or crosses '0'
|
||||
rngMin = dataBuf.getMin(numBufVals);
|
||||
rngMax = dataBuf.getMax(numBufVals);
|
||||
rng = (rngMax >= rngMin ? rngMax - rngMin : M_TWOPI - rngMin + rngMax);
|
||||
rng = std::max(rng, dfltRng); // keep at least default chart range
|
||||
|
||||
if (rng > M_PI) { // If wind range > 180°, adjust wndCenter to smaller wind range end
|
||||
rngMid = WindUtils::to2PI(rngMid + M_PI);
|
||||
}
|
||||
rngMid = std::round(rngMid / rngStep) * rngStep; // round new center value to next <rngStep> value
|
||||
}
|
||||
recalcRngMid = false; // Reset flag for <rngMid> determination
|
||||
|
||||
@@ -279,16 +290,11 @@ void Chart::calcChrtBorders(double& rngMin, double& rngMid, double& rngMax, doub
|
||||
|
||||
// check and adjust range between left, mid, and right chart limit
|
||||
double halfRng = rng / 2.0; // we calculate with range between <rngMid> and edges
|
||||
double tmpRng = getAngleRng(rngMid, numBufVals);
|
||||
double tmpRng = getCircularRng(rngMid, numBufVals);
|
||||
tmpRng = (tmpRng == dbMAX_VAL ? 0 : std::ceil(tmpRng / rngStep) * rngStep);
|
||||
|
||||
// LOG_DEBUG(GwLog::DEBUG, "calcChrtBorders: tmpRng: %.1f°, halfRng: %.1f°", tmpRng * RAD_TO_DEG, halfRng * RAD_TO_DEG);
|
||||
|
||||
if (tmpRng > halfRng) { // expand chart range to new value
|
||||
halfRng = tmpRng;
|
||||
}
|
||||
|
||||
else if (tmpRng + rngStep < halfRng) { // Contract chart range for higher resolution if possible
|
||||
} else if (tmpRng + rngStep < halfRng) { // Contract chart range for higher resolution if possible
|
||||
halfRng = std::max(dfltRng / 2.0, tmpRng);
|
||||
}
|
||||
|
||||
@@ -297,7 +303,6 @@ void Chart::calcChrtBorders(double& rngMin, double& rngMid, double& rngMax, doub
|
||||
rngMax = WindUtils::to2PI(rngMax);
|
||||
|
||||
rng = halfRng * 2.0;
|
||||
|
||||
// LOG_DEBUG(GwLog::DEBUG, "calcChrtBorders: rngMin: %.1f°, rngMid: %.1f°, rngMax: %.1f°, tmpRng: %.1f°, rng: %.1f°, rngStep: %.1f°", rngMin * RAD_TO_DEG, rngMid * RAD_TO_DEG, rngMax * RAD_TO_DEG,
|
||||
// tmpRng * RAD_TO_DEG, rng * RAD_TO_DEG, rngStep * RAD_TO_DEG);
|
||||
|
||||
@@ -306,8 +311,15 @@ void Chart::calcChrtBorders(double& rngMin, double& rngMid, double& rngMax, doub
|
||||
double currMinVal = dataBuf.getMin(numBufVals);
|
||||
double currMaxVal = dataBuf.getMax(numBufVals);
|
||||
|
||||
if (currMinVal == dbMAX_VAL || currMaxVal == dbMAX_VAL) {
|
||||
return; // no valid data
|
||||
if (currMinVal == dbMAX_VAL || currMaxVal == dbMAX_VAL) { // no valid data
|
||||
auto chkIsNaN = [](double& val) { if (std::isnan(val)) val = 0.0; }; // define inline function
|
||||
// range values can be undefined if boat data type has not been created at time of chart printing (e.g. XDR data types)
|
||||
// we set them to "0.0" then
|
||||
chkIsNaN(rngMin);
|
||||
chkIsNaN(rngMid);
|
||||
chkIsNaN(rngMax);
|
||||
chkIsNaN(rng);
|
||||
return;
|
||||
}
|
||||
|
||||
// check if current chart border have to be adjusted
|
||||
@@ -330,35 +342,17 @@ void Chart::calcChrtBorders(double& rngMin, double& rngMid, double& rngMax, doub
|
||||
|
||||
rngMid = (rngMin + rngMax) / 2.0;
|
||||
rng = rngMax - rngMin;
|
||||
|
||||
// LOG_DEBUG(GwLog::DEBUG, "calcChrtRange-end: currMinVal: %.1f, currMaxVal: %.1f, rngMin: %.1f, rngMid: %.1f, rngMax: %.1f, rng: %.1f, rngStep: %.1f, zeroValue: %.1f, dbMIN_VAL: %.1f",
|
||||
// currMinVal, currMaxVal, rngMin, rngMid, rngMax, rng, rngStep, zeroValue, dbMIN_VAL);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw chart graph
|
||||
void Chart::drawChartLines(const char direction, const int8_t chrtIntv, const double chrtScale)
|
||||
void Chart::drawChartLines(const ChrtDir chrtDir, const int8_t chrtIntv, const double chrtScale)
|
||||
{
|
||||
double chrtVal; // Current data value
|
||||
Pos point, prevPoint; // current and previous chart point
|
||||
|
||||
if (smoothCharts) {
|
||||
// prime moving average filter to ensure the first plotted point is already averaged
|
||||
|
||||
chrtAvg.reset();
|
||||
|
||||
// Feed the filter the 10 values preceding bufStart
|
||||
for (int p = 10; p > 0; p--) {
|
||||
// Calculate index with wrapping: (start - offset + size) % size
|
||||
int primeIdx = (bufStart - (p * chrtIntv));
|
||||
double primeVal = dataBuf.get(primeIdx);
|
||||
|
||||
if (primeVal != dbMAX_VAL) {
|
||||
chrtAvg.reading(primeVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < (numBufVals / chrtIntv); i++) {
|
||||
|
||||
chrtVal = dataBuf.get(bufStart + (i * chrtIntv)); // show the latest wind values in buffer; keep 1st value constant in a rolling buffer
|
||||
@@ -367,19 +361,12 @@ void Chart::drawChartLines(const char direction, const int8_t chrtIntv, const do
|
||||
chrtPrevVal = dbMAX_VAL;
|
||||
} else {
|
||||
|
||||
if (smoothCharts) {
|
||||
// if chart lines shall be smoothed, apply moving average filter of the last 10 values
|
||||
chrtVal = chrtAvg.reading(chrtVal);
|
||||
}
|
||||
|
||||
point = setCurrentChartPoint(i, direction, chrtVal, chrtScale);
|
||||
|
||||
// if (i >= (numBufVals / chrtIntv) - 5) // log chart data of 1 line (adjust for test purposes)
|
||||
// LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Chart: i: %d, chrtVal: %.2f, chrtMin: %.2f, {x,y} {%d,%d}", i, chrtVal, chrtMin, x, y);
|
||||
point = setChartPoint(i, chrtDir, chrtVal, chrtScale);
|
||||
// if (i >= (numBufVals / chrtIntv) - 5) // log chart data of x lines (adjust for test purposes)
|
||||
// LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Chart: i: %d, chrtVal: %.2f, chrtMin: %.2f, {x,y} {%d,%d}", i, chrtVal, chrtMin, point.x, point.y);
|
||||
|
||||
if ((i == 0) || (chrtPrevVal == dbMAX_VAL)) {
|
||||
// just a dot for 1st chart point or after some invalid values
|
||||
prevPoint = point;
|
||||
prevPoint = point; // just a dot for 1st chart point or after some invalid values
|
||||
|
||||
} else if (chrtDataFmt == WIND || chrtDataFmt == ROTATION) {
|
||||
// cross borders check for degree values; shift values to [-PI..0..PI]; when crossing borders, range is 2x PI degrees
|
||||
@@ -393,7 +380,7 @@ void Chart::drawChartLines(const char direction, const int8_t chrtIntv, const do
|
||||
// LOG_DEBUG(GwLog::DEBUG, "PageWindPlot Chart: crossedBorders: %d, chrtVal: %.2f, chrtPrevVal: %.2f", crossedBorders, chrtVal, chrtPrevVal);
|
||||
bool wrappingFromHighToLow = normCurrVal < normPrevVal; // Determine which edge we're crossing
|
||||
|
||||
if (direction == HORIZONTAL) {
|
||||
if (chrtDir == HORIZONTAL) {
|
||||
int ySplit = wrappingFromHighToLow ? (cRoot.y + valAxis) : cRoot.y;
|
||||
drawBoldLine(prevPoint.x, prevPoint.y, point.x, ySplit);
|
||||
prevPoint.y = wrappingFromHighToLow ? cRoot.y : (cRoot.y + valAxis);
|
||||
@@ -404,10 +391,19 @@ void Chart::drawChartLines(const char direction, const int8_t chrtIntv, const do
|
||||
prevPoint.x = wrappingFromHighToLow ? cRoot.x : (cRoot.x + valAxis);
|
||||
}
|
||||
}
|
||||
|
||||
// test position of chart point against chart middle; ignore first values which we don't show next time anyway
|
||||
if (i > MIN_FREE_VALUES) {
|
||||
double d = WindUtils::toPI(chrtVal - chrtMid);
|
||||
if (d > 0) // point is right of mid point
|
||||
allLeft = false;
|
||||
if (d < 0) // point is left of mid point
|
||||
allRight = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (chrtDataFmt == DEPTH) {
|
||||
if (direction == HORIZONTAL) { // horizontal chart
|
||||
if (chrtDir == HORIZONTAL) { // horizontal chart
|
||||
drawBoldLine(point.x, point.y, point.x, cRoot.y + valAxis);
|
||||
} else { // vertical chart
|
||||
drawBoldLine(point.x, point.y, cRoot.x + valAxis, point.y);
|
||||
@@ -424,31 +420,36 @@ void Chart::drawChartLines(const char direction, const int8_t chrtIntv, const do
|
||||
if (i >= timAxis - 1) {
|
||||
oldChrtIntv = 0; // force reset of buffer start and number of values to show in next display loop
|
||||
|
||||
if (chrtDataFmt == WIND) { // degree of course or wind
|
||||
if (chrtDataFmt == WIND) {
|
||||
if (allLeft || allRight || chrtRng == M_TWOPI) { // check if we should recalculate chart axis middle value
|
||||
recalcRngMid = true;
|
||||
// LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: chart end: timAxis: %d, i: %d, bufStart: %d, numBufVals: %d, recalcRngCntr: %d", timAxis, i, bufStart, numBufVals, recalcRngMid);
|
||||
}
|
||||
// LOG_DEBUG(GwLog::DEBUG, "OBPcharts: WIND chart end: timAxis: %d, i: %d, bufStart: %d, numBufVals: %d, recalcRngCntr: %d, allLeft: %d, allRight: %d", timAxis, i, bufStart,
|
||||
// numBufVals, recalcRngMid, allLeft, allRight);
|
||||
allLeft = true; // reset marker for all left/right chart points
|
||||
allRight = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
taskYIELD(); // we run for 50-150ms; be polite to other tasks with same priority
|
||||
taskYIELD(); // we run for 50-150ms, so we want to be polite to other tasks with same priority
|
||||
}
|
||||
}
|
||||
|
||||
// Set current chart point to draw
|
||||
Pos Chart::setCurrentChartPoint(const int i, const char direction, const double chrtVal, const double chrtScale)
|
||||
Pos Chart::setChartPoint(const int i, const ChrtDir chrtDir, const double chrtVal, const double chrtScale)
|
||||
{
|
||||
Pos currentPoint;
|
||||
|
||||
if (direction == HORIZONTAL) {
|
||||
if (chrtDir == HORIZONTAL) {
|
||||
currentPoint.x = cRoot.x + i; // Position in chart area
|
||||
|
||||
if (chrtDataFmt == WIND || chrtDataFmt == ROTATION) { // degree type value
|
||||
currentPoint.y = cRoot.y + static_cast<int>((WindUtils::to2PI(chrtVal - chrtMin) * chrtScale) + 0.5); // calculate chart point and round
|
||||
} else if (chrtDataFmt == SPEED or chrtDataFmt == TEMPERATURE) { // speed or temperature data format -> print low values at bottom
|
||||
currentPoint.y = cRoot.y + valAxis - static_cast<int>(((chrtVal - chrtMin) * chrtScale) + 0.5); // calculate chart point and round
|
||||
} else { // any other data format
|
||||
} else if (chrtDataFmt == WIND || chrtDataFmt == ROTATION || chrtDataFmt == DEPTH) { // print low values at bottom
|
||||
currentPoint.y = cRoot.y + static_cast<int>(((chrtVal - chrtMin) * chrtScale) + 0.5); // calculate chart point and round
|
||||
} else { // any other data format
|
||||
currentPoint.y = cRoot.y + valAxis - static_cast<int>(((chrtVal - chrtMin) * chrtScale) + 0.5); // calculate chart point and round
|
||||
}
|
||||
|
||||
} else { // vertical chart
|
||||
@@ -465,7 +466,7 @@ Pos Chart::setCurrentChartPoint(const int i, const char direction, const double
|
||||
}
|
||||
|
||||
// chart time axis label + lines
|
||||
void Chart::drawChrtTimeAxis(const char chrtDir, const int8_t chrtSz, const int8_t chrtIntv)
|
||||
void Chart::drawChrtTimeAxis(const ChrtDir chrtDir, const ChrtSize chrtSz, const int8_t chrtIntv)
|
||||
{
|
||||
int axSlots, intv, i, timeRng;
|
||||
char sTime[6];
|
||||
@@ -499,13 +500,13 @@ void Chart::drawChrtTimeAxis(const char chrtDir, const int8_t chrtSz, const int8
|
||||
for (float j = intv; j < timAxis - 1; j += intv) { // don't print time label at upper and lower end of time axis
|
||||
|
||||
snprintf(sTime, sizeof(sTime), "%d", i);
|
||||
getdisplay().drawLine(cRoot.x, cRoot.y + j, cRoot.x + valAxis, cRoot.y + j, fgColor); // Grid line
|
||||
getdisplay().drawLine(cRoot.x, cRoot.y + j, cRoot.x + valAxis - 2, cRoot.y + j, fgColor); // Grid line
|
||||
|
||||
if (chrtSz == FULL_SIZE) { // full size chart
|
||||
getdisplay().fillRect(0, cRoot.y + j - 9, 32, 15, bgColor); // clear small area to remove potential chart lines
|
||||
getdisplay().setCursor((4 - strlen(sTime)) * 7, cRoot.y + j + 3); // time value; print left screen; value right-formated
|
||||
getdisplay().printf("%s", sTime); // time value
|
||||
} else if (chrtSz == HALF_SIZE_RIGHT) { // half size chart; right side
|
||||
} else if (chrtSz == HALF_SIZE_RIGHT_BOTTOM) { // half size chart; right side
|
||||
drawTextCenter(dWidth / 2, cRoot.y + j, sTime); // time value; print mid screen
|
||||
}
|
||||
i -= chrtIntv;
|
||||
@@ -514,11 +515,11 @@ void Chart::drawChrtTimeAxis(const char chrtDir, const int8_t chrtSz, const int8
|
||||
}
|
||||
|
||||
// chart value axis labels + lines
|
||||
void Chart::drawChrtValAxis(const char chrtDir, const int8_t chrtSz, bool prntName)
|
||||
void Chart::drawChrtValAxis(const ChrtDir chrtDir, const ChrtSize chrtSz, const bool prntName)
|
||||
{
|
||||
const GFXfont* font;
|
||||
constexpr bool NO_LABEL = false;
|
||||
constexpr bool LABEL = true;
|
||||
// constexpr bool NO_LABEL = false;
|
||||
// constexpr bool LABEL = true;
|
||||
|
||||
getdisplay().setTextColor(fgColor);
|
||||
|
||||
@@ -526,18 +527,21 @@ void Chart::drawChrtValAxis(const char chrtDir, const int8_t chrtSz, bool prntNa
|
||||
|
||||
if (chrtSz == FULL_SIZE) {
|
||||
|
||||
if (prntName) {
|
||||
// print buffer data name on left hand side of time axis (max. size 5 characters)
|
||||
font = &Ubuntu_Bold12pt8b;
|
||||
getdisplay().setFont(font);
|
||||
getdisplay().fillRect(cRoot.x + timAxis - 57, cRoot.y + 2, 58, 20, bgColor); // clear small area to remove potential chart lines
|
||||
drawTextRalign(cRoot.x + timAxis, cRoot.y + 19, dbName.substring(0, 5));
|
||||
|
||||
String name = xdrDelete(dbName); // Value name
|
||||
drawTextRalign(cRoot.x + timAxis - 1, cRoot.y + 19, name.substring(0, 5));
|
||||
}
|
||||
if (chrtDataFmt == WIND) {
|
||||
prntHorizChartThreeValueAxisLabel(font);
|
||||
return;
|
||||
}
|
||||
|
||||
// for any other data formats print multiple axis value lines on full charts
|
||||
font = &Ubuntu_Bold10pt8b;
|
||||
prntHorizChartMultiValueAxisLabel(font);
|
||||
return;
|
||||
|
||||
@@ -545,10 +549,11 @@ void Chart::drawChrtValAxis(const char chrtDir, const int8_t chrtSz, bool prntNa
|
||||
|
||||
font = &Ubuntu_Bold10pt8b;
|
||||
if (prntName) {
|
||||
// print buffer data name on right hand side of time axis (max. size 5 characters)
|
||||
// print buffer data name on right hand side of time axis (max. size 6 characters)
|
||||
getdisplay().setFont(font);
|
||||
getdisplay().fillRect(cRoot.x + timAxis - 57, cRoot.y + 2, 58, 20, bgColor); // clear small area to remove potential chart lines
|
||||
drawTextRalign(cRoot.x + timAxis, cRoot.y + 16, dbName.substring(0, 5));
|
||||
getdisplay().fillRect(cRoot.x + timAxis - 57, cRoot.y + 2, 58, 16, bgColor); // clear small area to remove potential chart lines
|
||||
String name = xdrDelete(dbName); // Value name
|
||||
drawTextRalign(cRoot.x + timAxis - 1, cRoot.y + 16, name.substring(0, 6));
|
||||
}
|
||||
|
||||
prntHorizChartThreeValueAxisLabel(font);
|
||||
@@ -557,53 +562,67 @@ void Chart::drawChrtValAxis(const char chrtDir, const int8_t chrtSz, bool prntNa
|
||||
|
||||
} else { // vertical chart
|
||||
|
||||
if (prntName) {
|
||||
if (chrtSz == FULL_SIZE) {
|
||||
font = &Ubuntu_Bold12pt8b;
|
||||
getdisplay().setFont(font); // use larger font
|
||||
drawTextRalign(cRoot.x + (valAxis * 0.42), cRoot.y - 2, dbName.substring(0, 6)); // print buffer data name (max. size 5 characters)
|
||||
|
||||
} else {
|
||||
|
||||
font = &Ubuntu_Bold10pt8b;
|
||||
}
|
||||
getdisplay().setFont(font);
|
||||
String name = xdrDelete(dbName); // Value name
|
||||
drawTextRalign(cRoot.x + (valAxis * 0.42), cRoot.y - 2, name.substring(0, 6)); // print buffer data name (max. size 6 characters)
|
||||
}
|
||||
|
||||
font = &Ubuntu_Bold10pt8b;
|
||||
prntVerticChartThreeValueAxisLabel(font);
|
||||
}
|
||||
}
|
||||
|
||||
// Print current data value
|
||||
void Chart::prntCurrValue(const char direction, GwApi::BoatValue& currValue)
|
||||
void Chart::prntCurrValue(const ChrtDir chrtDir, GwApi::BoatValue& currValue)
|
||||
{
|
||||
const int xPosVal = (direction == HORIZONTAL) ? cRoot.x + (timAxis / 2) - 56 : cRoot.x + 32;
|
||||
const int yPosVal = (direction == HORIZONTAL) ? cRoot.y + valAxis - 7 : cRoot.y + timAxis - 7;
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
static constexpr bool smallDecimals = true; // print data value always with small decimals
|
||||
|
||||
const int xPosVal = (chrtDir == HORIZONTAL) ? cRoot.x + (timAxis / 2) - 74 : cRoot.x + 31;
|
||||
const int yPosVal = (chrtDir == HORIZONTAL) ? cRoot.y + valAxis : cRoot.y + timAxis;
|
||||
|
||||
FormattedData frmtDbData = formatValue(&currValue, *commonData, NO_SIMUDATA);
|
||||
String sdbValue = frmtDbData.svalue; // value as formatted string
|
||||
String dbUnit = frmtDbData.unit; // Unit of value; limit length to 3 characters
|
||||
|
||||
getdisplay().fillRect(xPosVal - 1, yPosVal - 35, 128, 41, bgColor); // Clear area for TWS value
|
||||
getdisplay().drawRect(xPosVal, yPosVal - 34, 126, 40, fgColor); // Draw box for TWS value
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
|
||||
getdisplay().setCursor(xPosVal + 1, yPosVal);
|
||||
getdisplay().print(sdbValue); // value
|
||||
// box
|
||||
getdisplay().fillRect(xPosVal - 1, yPosVal - 40, 148, 39, bgColor); // Clear area for value
|
||||
getdisplay().drawRect(xPosVal, yPosVal - 39, 146, 37, fgColor); // Draw box for value
|
||||
|
||||
// value
|
||||
printBoatValue(sdbValue, xPosVal + 93, yPosVal - 6, RIGHT, 16, smallDecimals);
|
||||
// getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
|
||||
// getdisplay().setCursor(xPosVal + 1, yPosVal - 6);
|
||||
// getdisplay().print(sdbValue);
|
||||
|
||||
// name
|
||||
getdisplay().setFont(&Ubuntu_Bold10pt8b);
|
||||
getdisplay().setCursor(xPosVal + 76, yPosVal - 17);
|
||||
getdisplay().print(dbName.substring(0, 3)); // Name, limited to 3 characters
|
||||
getdisplay().setCursor(xPosVal + 97, yPosVal - 23);
|
||||
String name = xdrDelete(dbName);
|
||||
getdisplay().print(name.substring(0, 3)); // Name, limited to 3 characters
|
||||
|
||||
// unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(xPosVal + 76, yPosVal + 0);
|
||||
getdisplay().print(dbUnit); // Unit
|
||||
getdisplay().setCursor(xPosVal + 98, yPosVal - 8);
|
||||
getdisplay().print(dbUnit);
|
||||
}
|
||||
|
||||
// print message for no valid data availabletemplate <typename T>
|
||||
void Chart::prntNoValidData(const char direction)
|
||||
void Chart::prntNoValidData(const ChrtDir chrtDir)
|
||||
{
|
||||
Pos p;
|
||||
|
||||
getdisplay().setFont(&Ubuntu_Bold10pt8b);
|
||||
|
||||
if (direction == HORIZONTAL) {
|
||||
if (chrtDir == HORIZONTAL) {
|
||||
p.x = cRoot.x + (timAxis / 2);
|
||||
p.y = cRoot.y + (valAxis / 2) - 10;
|
||||
} else {
|
||||
@@ -618,7 +637,7 @@ void Chart::prntNoValidData(const char direction)
|
||||
}
|
||||
|
||||
// Get maximum difference of last <amount> of dataBuf ringbuffer values to center chart; for angle data only
|
||||
double Chart::getAngleRng(const double center, size_t amount)
|
||||
double Chart::getCircularRng(const double center, size_t amount)
|
||||
{
|
||||
size_t count = dataBuf.getCurrentSize();
|
||||
|
||||
@@ -689,13 +708,13 @@ void Chart::prntHorizChartThreeValueAxisLabel(const GFXfont* font)
|
||||
double axLabel;
|
||||
double chrtMin, chrtMid, chrtMax;
|
||||
int xOffset, yOffset; // offset for text position of x axis label for different font sizes
|
||||
String sVal;
|
||||
char sVal[11]; // data value have max. 6 digits + decimal point + 2 decimals + sign
|
||||
|
||||
if (font == &Ubuntu_Bold10pt8b) {
|
||||
xOffset = 39;
|
||||
xOffset = 32;
|
||||
yOffset = 16;
|
||||
} else if (font == &Ubuntu_Bold12pt8b) {
|
||||
xOffset = 51;
|
||||
xOffset = 42;
|
||||
yOffset = 18;
|
||||
}
|
||||
getdisplay().setFont(font);
|
||||
@@ -704,77 +723,99 @@ void Chart::prntHorizChartThreeValueAxisLabel(const GFXfont* font)
|
||||
chrtMin = convertValue(this->chrtMin, dbName, dbFormat, *commonData);
|
||||
chrtMid = convertValue(this->chrtMid, dbName, dbFormat, *commonData);
|
||||
chrtMax = convertValue(this->chrtMax, dbName, dbFormat, *commonData);
|
||||
chrtMin = std::round(chrtMin * 100.0) / 100.0;
|
||||
chrtMid = std::round(chrtMid * 100.0) / 100.0;
|
||||
chrtMax = std::round(chrtMax * 100.0) / 100.0;
|
||||
|
||||
// print top axis label
|
||||
axLabel = (chrtDataFmt == SPEED || chrtDataFmt == TEMPERATURE) ? chrtMax : chrtMin;
|
||||
sVal = formatLabel(axLabel);
|
||||
axLabel = (chrtDataFmt == WIND || chrtDataFmt == ROTATION || chrtDataFmt == DEPTH) ? chrtMin : chrtMax;
|
||||
formatLabel(axLabel).toCharArray(sVal, 11);
|
||||
if (chrtDataFmt == PRESSURE) {
|
||||
snprintf(sVal, sizeof(sVal), "%4.0f", axLabel);
|
||||
getdisplay().fillRect(cRoot.x, cRoot.y + 2, xOffset + 12, yOffset, bgColor); // Clear small area to remove potential chart lines
|
||||
drawTextRalign(cRoot.x + xOffset + 11, cRoot.y + yOffset, sVal); // range value
|
||||
} else {
|
||||
if (char* dot = strchr(sVal, '.'))
|
||||
*dot = '\0'; // no decimal for top axis label
|
||||
getdisplay().fillRect(cRoot.x, cRoot.y + 2, xOffset + 3, yOffset, bgColor); // Clear small area to remove potential chart lines
|
||||
drawTextRalign(cRoot.x + xOffset, cRoot.y + yOffset, sVal); // range value
|
||||
}
|
||||
|
||||
// print mid axis label
|
||||
axLabel = chrtMid;
|
||||
sVal = formatLabel(axLabel);
|
||||
getdisplay().fillRect(cRoot.x, cRoot.y + (valAxis / 2) - 8, xOffset + 3, 16, bgColor); // Clear small area to remove potential chart lines
|
||||
formatLabel(axLabel).toCharArray(sVal, 11);
|
||||
if (chrtDataFmt == PRESSURE) { // print 4-digit value
|
||||
getdisplay().fillRect(cRoot.x, cRoot.y + (valAxis / 2) - 8, xOffset + 12, yOffset, bgColor); // Clear small area to remove potential chart lines
|
||||
drawTextRalign(cRoot.x + xOffset + 11, cRoot.y + (valAxis / 2) + 6, sVal); // range value
|
||||
getdisplay().drawLine(cRoot.x + xOffset + 14, cRoot.y + (valAxis / 2), cRoot.x + timAxis, cRoot.y + (valAxis / 2), fgColor);
|
||||
} else { // print 3-digit value
|
||||
getdisplay().fillRect(cRoot.x, cRoot.y + (valAxis / 2) - 8, xOffset + 3, yOffset, bgColor); // Clear small area to remove potential chart lines
|
||||
drawTextRalign(cRoot.x + xOffset, cRoot.y + (valAxis / 2) + 6, sVal); // range value
|
||||
getdisplay().drawLine(cRoot.x + xOffset + 3, cRoot.y + (valAxis / 2), cRoot.x + timAxis, cRoot.y + (valAxis / 2), fgColor);
|
||||
}
|
||||
|
||||
// print bottom axis label
|
||||
axLabel = (chrtDataFmt == SPEED || chrtDataFmt == TEMPERATURE) ? chrtMin : chrtMax;
|
||||
sVal = formatLabel(axLabel);
|
||||
getdisplay().fillRect(cRoot.x, cRoot.y + valAxis - 14, xOffset + 3, 15, bgColor); // Clear small area to remove potential chart lines
|
||||
axLabel = (chrtDataFmt == WIND || chrtDataFmt == ROTATION || chrtDataFmt == DEPTH) ? chrtMax : chrtMin;
|
||||
formatLabel(axLabel).toCharArray(sVal, 11);
|
||||
if (chrtDataFmt == PRESSURE) {
|
||||
getdisplay().fillRect(cRoot.x, cRoot.y + valAxis - 14, xOffset + 12, yOffset, bgColor); // Clear small area to remove potential chart lines
|
||||
drawTextRalign(cRoot.x + xOffset + 11, cRoot.y + valAxis, sVal); // range value
|
||||
getdisplay().drawLine(cRoot.x + xOffset + 14, cRoot.y + valAxis, cRoot.x + timAxis, cRoot.y + valAxis, fgColor);
|
||||
} else {
|
||||
if (char* dot = strchr(sVal, '.'))
|
||||
*dot = '\0'; // no decimal for bottom axis label
|
||||
getdisplay().fillRect(cRoot.x, cRoot.y + valAxis - 14, xOffset + 3, yOffset, bgColor); // Clear small area to remove potential chart lines
|
||||
drawTextRalign(cRoot.x + xOffset, cRoot.y + valAxis, sVal); // range value
|
||||
getdisplay().drawLine(cRoot.x + xOffset + 3, cRoot.y + valAxis, cRoot.x + timAxis, cRoot.y + valAxis, fgColor);
|
||||
}
|
||||
}
|
||||
|
||||
// print value axis label with multiple axis lines for horizontal chart
|
||||
void Chart::prntHorizChartMultiValueAxisLabel(const GFXfont* font)
|
||||
{
|
||||
double chrtMin, chrtMax, chrtRng;
|
||||
double axSlots, axIntv, axLabel;
|
||||
int xOffset; // offset for text position of x axis label for different font sizes
|
||||
String sVal;
|
||||
char sVal[11]; // data value have max. 6 digits + decimal point + 2 decimals + sign
|
||||
|
||||
if (font == &Ubuntu_Bold10pt8b) {
|
||||
xOffset = 38;
|
||||
xOffset = 32;
|
||||
} else if (font == &Ubuntu_Bold12pt8b) {
|
||||
xOffset = 50;
|
||||
xOffset = 42;
|
||||
}
|
||||
getdisplay().setFont(font);
|
||||
|
||||
chrtMin = convertValue(this->chrtMin, dbName, dbFormat, *commonData);
|
||||
// chrtMin = std::floor(chrtMin / rngStep) * rngStep;
|
||||
chrtMin = std::round(chrtMin * 100.0) / 100.0;
|
||||
chrtMax = convertValue(this->chrtMax, dbName, dbFormat, *commonData);
|
||||
// chrtMax = std::ceil(chrtMax / rngStep) * rngStep;
|
||||
chrtMax = std::round(chrtMax * 100.0) / 100.0;
|
||||
chrtRng = std::round((chrtMax - chrtMin) * 100) / 100;
|
||||
chrtRng = chrtMax - chrtMin;
|
||||
|
||||
axSlots = valAxis / static_cast<double>(VALAXIS_STEP); // number of axis labels (and we want to have a double calculation, no integer)
|
||||
axIntv = chrtRng / axSlots;
|
||||
axLabel = chrtMin + axIntv;
|
||||
// LOG_DEBUG(GwLog::DEBUG, "Chart::printHorizMultiValueAxisLabel: chrtRng: %.2f, th-chrtRng: %.2f, axSlots: %.2f, axIntv: %.2f, axLabel: %.2f, chrtMin: %.2f, chrtMid: %.2f, chrtMax: %.2f", chrtRng, this->chrtRng, axSlots, axIntv, axLabel, this->chrtMin, chrtMid, chrtMax);
|
||||
double axIntv = chrtRng / VALAXIS_SLOTS; // axis label interval
|
||||
double axLabel = chrtMin + axIntv; // current axis label
|
||||
double chrtScale = double(valAxis) / chrtRng; // Chart scale: pixels per value step
|
||||
double valAxisStep = axIntv * chrtScale; // pixel per axis label interval
|
||||
|
||||
// LOG_DEBUG(GwLog::DEBUG, "Chart::printHorizMultiValueAxisLabel: chrtRng: %.2f, th-chrtRng: %.2f, axSlots: %.2f, axIntv: %.2f, axLabel: %.2f, chrtMin: %.2f, chrtMid: %.2f, chrtMax: %.2f", chrtRng, this->chrtRng, VALAXIS_SLOTS, axIntv, axLabel, this->chrtMin, chrtMid, chrtMax);
|
||||
|
||||
int loopStrt, loopEnd, loopStp;
|
||||
if (chrtDataFmt == SPEED || chrtDataFmt == TEMPERATURE || chrtDataFmt == OTHER) {
|
||||
// High value at top
|
||||
loopStrt = valAxis - VALAXIS_STEP;
|
||||
loopEnd = VALAXIS_STEP / 2;
|
||||
loopStp = VALAXIS_STEP * -1;
|
||||
} else {
|
||||
if (chrtDataFmt == WIND || chrtDataFmt == ROTATION || chrtDataFmt == DEPTH) {
|
||||
// Low value at top
|
||||
loopStrt = VALAXIS_STEP;
|
||||
loopEnd = valAxis - (VALAXIS_STEP / 2);
|
||||
loopStp = VALAXIS_STEP;
|
||||
loopStrt = valAxisStep;
|
||||
loopEnd = valAxis - (valAxisStep / 2);
|
||||
loopStp = valAxisStep;
|
||||
} else {
|
||||
// high value at top
|
||||
loopStrt = valAxis - valAxisStep;
|
||||
loopEnd = valAxisStep / 2;
|
||||
loopStp = valAxisStep * -1;
|
||||
}
|
||||
|
||||
for (int j = loopStrt; (loopStp > 0) ? (j < loopEnd) : (j > loopEnd); j += loopStp) {
|
||||
sVal = formatLabel(axLabel);
|
||||
formatLabel(axLabel).toCharArray(sVal, 11);
|
||||
if (chrtDataFmt == PRESSURE) { // print 4-digit value
|
||||
getdisplay().fillRect(cRoot.x, cRoot.y + j - 11, xOffset + 12, 21, bgColor); // Clear small area to remove potential chart lines
|
||||
drawTextRalign(cRoot.x + xOffset + 11, cRoot.y + j + 7, sVal); // range value
|
||||
getdisplay().drawLine(cRoot.x + xOffset + 14, cRoot.y + j, cRoot.x + timAxis, cRoot.y + j, fgColor);
|
||||
} else { // print 3-digit value
|
||||
getdisplay().fillRect(cRoot.x, cRoot.y + j - 11, xOffset + 3, 21, bgColor); // Clear small area to remove potential chart lines
|
||||
drawTextRalign(cRoot.x + xOffset, cRoot.y + j + 7, sVal); // range value
|
||||
getdisplay().drawLine(cRoot.x + xOffset + 3, cRoot.y + j, cRoot.x + timAxis, cRoot.y + j, fgColor);
|
||||
}
|
||||
|
||||
axLabel += axIntv;
|
||||
}
|
||||
@@ -817,20 +858,21 @@ String Chart::formatLabel(const double& label)
|
||||
{
|
||||
char sVal[11];
|
||||
|
||||
if (dbFormat == "formatCourse" || dbFormat == "formatWind") {
|
||||
// Format 3 numbers with prefix zero
|
||||
snprintf(sVal, sizeof(sVal), "%03.0f", label);
|
||||
if (chrtDataFmt == WIND) {
|
||||
snprintf(sVal, sizeof(sVal), "%03.0f", label); // Format 3 numbers with prefix zero
|
||||
|
||||
} else if (dbFormat == "formatRot") {
|
||||
if (label > -10 && label < 10) {
|
||||
} else if (chrtDataFmt == ROTATION) {
|
||||
if (label > -9.995 && label < 9.995) {
|
||||
snprintf(sVal, sizeof(sVal), "%3.2f", label);
|
||||
} else {
|
||||
snprintf(sVal, sizeof(sVal), "%3.0f", label);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
if (label < 10) {
|
||||
} else if (chrtDataFmt == PRESSURE) {
|
||||
snprintf(sVal, sizeof(sVal), "%4.0f", label);
|
||||
|
||||
} else {
|
||||
if (label < 9.95) {
|
||||
snprintf(sVal, sizeof(sVal), "%3.1f", label);
|
||||
} else {
|
||||
snprintf(sVal, sizeof(sVal), "%3.0f", label);
|
||||
|
||||
+53
-30
@@ -19,6 +19,30 @@ class RingBuffer;
|
||||
class GwLog;
|
||||
|
||||
class Chart {
|
||||
public:
|
||||
enum ChrtDir {
|
||||
HORIZONTAL,
|
||||
VERTICAL
|
||||
};
|
||||
|
||||
enum ChrtSize {
|
||||
FULL_SIZE,
|
||||
HALF_SIZE_LEFT_TOP,
|
||||
HALF_SIZE_RIGHT_BOTTOM,
|
||||
TWO_THIRD_TOP
|
||||
};
|
||||
|
||||
static constexpr bool PRNT_NAME = true;
|
||||
static constexpr bool NO_PRNT_NAME = false;
|
||||
static constexpr bool PRNT_VALUE = true;
|
||||
static constexpr bool NO_PRNT_VALUE = false;
|
||||
|
||||
Chart(RingBuffer<uint16_t>& dataBuf, CommonData& common, bool useSimuData); // Chart object of data chart
|
||||
~Chart();
|
||||
bool init(); // initialize chart object parameters
|
||||
bool isValid() { return initValid; }; // Checks if chart object has been fully initialized
|
||||
void showChrt(const ChrtDir chrtDir, const ChrtSize chrtSz, const int8_t chrtIntv, bool prntName, bool showCurrValue, GwApi::BoatValue currValue); // Perform all actions to draw chart
|
||||
|
||||
protected:
|
||||
CommonData* commonData;
|
||||
GwLog* logger;
|
||||
@@ -29,22 +53,19 @@ protected:
|
||||
SPEED,
|
||||
DEPTH,
|
||||
TEMPERATURE,
|
||||
PRESSURE,
|
||||
HUMIDITY,
|
||||
OTHER
|
||||
};
|
||||
|
||||
static constexpr char HORIZONTAL = 'H';
|
||||
static constexpr char VERTICAL = 'V';
|
||||
static constexpr int8_t FULL_SIZE = 0;
|
||||
static constexpr int8_t HALF_SIZE_LEFT = 1;
|
||||
static constexpr int8_t HALF_SIZE_RIGHT = 2;
|
||||
|
||||
static constexpr int8_t MIN_FREE_VALUES = 60; // free 60 values when chart line reaches chart end
|
||||
static constexpr int8_t THRESHOLD_NO_DATA = 3; // max. seconds of invalid values in a row
|
||||
static constexpr int8_t VALAXIS_STEP = 60; // pixels between two chart value axis labels
|
||||
static constexpr int8_t VALAXIS_SLOTS = 5; // no. of value axis labels
|
||||
|
||||
static constexpr bool NO_SIMUDATA = true; // switch off simulation feature of <formatValue> function
|
||||
|
||||
RingBuffer<uint16_t>& dataBuf; // Buffer to display
|
||||
bool initValid = false; // indicates whether object holds valid initialization data or not
|
||||
double dfltRng; // Default range of chart, e.g. 30 = [0..30]
|
||||
uint16_t fgColor; // color code for any screen writing
|
||||
uint16_t bgColor; // color code for screen background
|
||||
@@ -66,7 +87,8 @@ protected:
|
||||
double chrtMax; // Range high end value
|
||||
double chrtMid; // Range mid value
|
||||
double rngStep; // Defines the step of adjustment (e.g. 10 m/s) for value axis range
|
||||
bool recalcRngMid = false; // Flag for re-calculation of mid value of chart for wind data types
|
||||
bool recalcRngMid; // Flag for re-calculation of mid value of chart for wind data types
|
||||
bool allLeft, allRight; // indicate whether all chart points are left or right of middle value (only for wind data type)
|
||||
|
||||
String dbName, dbFormat; // Name and format of data buffer
|
||||
ChrtDataFormat chrtDataFmt; // Data format of chart boat data type
|
||||
@@ -77,41 +99,42 @@ protected:
|
||||
int numBufVals; // number of wind values available for current interval selection
|
||||
int bufStart; // 1st data value in buffer to show
|
||||
int numAddedBufVals; // Number of values added to buffer since last display
|
||||
size_t currIdx; // Current index in TWD history buffer
|
||||
size_t lastIdx; // Last index of TWD history buffer
|
||||
size_t lastAddedIdx = 0; // Last index of TWD history buffer when new data was added
|
||||
size_t currIdx; // Current index in history buffer
|
||||
size_t lastIdx; // Last index of history buffer
|
||||
size_t lastAddedIdx = 0; // Last index of history buffer when new data was added
|
||||
int numNoData; // Counter for multiple invalid data values in a row
|
||||
bool bufDataValid = false; // Flag to indicate if buffer data is valid
|
||||
int oldChrtIntv = 0; // remember recent user selection of data interval
|
||||
|
||||
movingAvg<double> chrtAvg{7}; // Store average of the last 7 chart values if chart gradient shall be smoothed
|
||||
double chrtPrevVal; // Last data value in chart area
|
||||
int x, y; // x and y coordinates for drawing
|
||||
int prevX, prevY; // Last x and y coordinates for drawing
|
||||
|
||||
bool setChartDimensions(const char direction, const int8_t size); //define dimensions and start points for chart
|
||||
void drawChrt(const char chrtDir, const int8_t chrtIntv, GwApi::BoatValue& currValue); // Draw chart line
|
||||
// Default ranges for various boat data types
|
||||
// Parameters: <1st value> default range, <2nd value> step for range adjustment
|
||||
std::map<String, ChartProps> dfltChrtDta = {
|
||||
{ "formatWind", { 60.0 * DEG_TO_RAD, 10.0 * DEG_TO_RAD } }, // default wind range 60 degrees
|
||||
{ "formatCourse", { 60.0 * DEG_TO_RAD, 10.0 * DEG_TO_RAD } }, // default course range 60 degrees
|
||||
{ "formatKnots", { 2.572, 2.572 } }, // default speed range in m/s
|
||||
{ "formatDepth", { 10.0, 5.0 } }, // default depth range in m
|
||||
{ "kelvinToC", { 20.0, 5.0 } }, // default temp range in °C/K
|
||||
{ "formatXdr:P:P", { 4000.0, 1000.0 } } // default pressure range in Pascal (hPa * 100); XDR <B> (bar) format is represented in gateway in the same way
|
||||
};
|
||||
|
||||
bool setChartDimensions(const ChrtDir direction, const ChrtSize chrtSz); // define dimensions and start points for chart
|
||||
void drawChrt(const ChrtDir chrtDir, const int8_t chrtIntv, GwApi::BoatValue& currValue); // Draw chart line
|
||||
void getBufferStartNSize(const int8_t chrtIntv); // Identify buffer size and buffer start position for chart
|
||||
void calcChrtBorders(double& rngMin, double& rngMid, double& rngMax, double& rng); // Calculate chart points for value axis and return range between <min> and <max>
|
||||
void drawChartLines(const char direction, const int8_t chrtIntv, const double chrtScale); // Draw chart graph
|
||||
Pos setCurrentChartPoint(const int i, const char direction, const double chrtVal, const double chrtScale); // Set current chart point to draw
|
||||
void drawChrtTimeAxis(const char chrtDir, const int8_t chrtSz, const int8_t chrtIntv); // Draw time axis of chart, value and lines
|
||||
void drawChrtValAxis(const char chrtDir, const int8_t chrtSz, bool prntLabel); // Draw value axis of chart, value and lines
|
||||
void prntCurrValue(const char chrtDir, GwApi::BoatValue& currValue); // Add current boat data value to chart
|
||||
void prntNoValidData(const char chrtDir); // print message for no valid data available
|
||||
double getAngleRng(const double center, size_t amount); // Calculate range between chart center and edges
|
||||
void drawChartLines(const ChrtDir direction, const int8_t chrtIntv, const double chrtScale); // Draw chart graph
|
||||
Pos setChartPoint(const int i, const ChrtDir chrtDir, const double chrtVal, const double chrtScale); // Set current chart point to draw
|
||||
void drawChrtTimeAxis(const ChrtDir chrtDir, const ChrtSize chrtSz, const int8_t chrtIntv); // Draw time axis of chart, value and lines
|
||||
void drawChrtValAxis(const ChrtDir chrtDir, const ChrtSize chrtSz, const bool prntLabel); // Draw value axis of chart, value and lines
|
||||
void prntCurrValue(const ChrtDir chrtDir, GwApi::BoatValue& currValue); // Add current boat data value to chart
|
||||
void prntNoValidData(const ChrtDir chrtDir); // print message for no valid data available
|
||||
double getCircularRng(const double center, size_t amount); // Calculate range between chart center and edges
|
||||
void prntVerticChartThreeValueAxisLabel(const GFXfont* font); // print value axis label with only three values: top, mid, and bottom for vertical chart
|
||||
void prntHorizChartThreeValueAxisLabel(const GFXfont* font); // print value axis label with only three values: top, mid, and bottom for horizontal chart
|
||||
void prntHorizChartMultiValueAxisLabel(const GFXfont* font); // print value axis label with multiple axis lines for horizontal chart
|
||||
void drawBoldLine(const int16_t x1, const int16_t y1, const int16_t x2, const int16_t y2); // Draw chart line with thickness of 2px
|
||||
String convNformatLabel(const double& label); // Convert and format current axis label to user defined format; helper function for easier handling of OBP60Formatter
|
||||
String formatLabel(const double& label); // Format current axis label for printing w/o data format conversion (has been done earlier)
|
||||
|
||||
public:
|
||||
// Define default chart range and range step for each boat data type
|
||||
static std::map<String, ChartProps> dfltChrtDta;
|
||||
|
||||
Chart(RingBuffer<uint16_t>& dataBuf, double dfltRng, CommonData& common, bool useSimuData); // Chart object of data chart
|
||||
~Chart();
|
||||
void showChrt(char chrtDir, int8_t chrtSz, const int8_t chrtIntv, bool prntName, bool showCurrValue, GwApi::BoatValue currValue); // Perform all actions to draw chart
|
||||
};
|
||||
|
||||
@@ -31,6 +31,10 @@ const float Compass_LineDelta = 8.0;// Compass band: 1deg = 5 Pixels, 10deg = 50
|
||||
|
||||
class PageAutopilot : public Page
|
||||
{
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
|
||||
int WhichDataCompass = ShowHDM; // Start value
|
||||
int WhichDataDisplay = ShowHDM; // Start value
|
||||
|
||||
@@ -85,6 +89,7 @@ class PageAutopilot : public Page
|
||||
bool holdvalues = config->getBool(config->holdvalues);
|
||||
String flashLED = config->getString(config->flashLED);
|
||||
String backlightMode = config->getString(config->backlight);
|
||||
bool smallDecimals = config->getBool(config->smallDecimals);
|
||||
|
||||
GwApi::BoatValue *bvalue;
|
||||
String DataName[HowManyValues];
|
||||
@@ -130,14 +135,12 @@ class PageAutopilot : public Page
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(10, 120);
|
||||
getdisplay().print(DataUnits[WhichDataDisplay]);
|
||||
getdisplay().setCursor(190, 120);
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic42pt7b);
|
||||
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(DataText[WhichDataDisplay]); // Real value as formated string
|
||||
printBoatValue(DataText[WhichDataDisplay], 190, 120, LEFT, 42, smallDecimals); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(OldDataText[WhichDataDisplay]); // Old value as formated string
|
||||
printBoatValue(OldDataText[WhichDataDisplay], 190, 120, LEFT, 42, smallDecimals); // Old value as formated string
|
||||
}
|
||||
if(DataValid[WhichDataDisplay] == true){
|
||||
OldDataText[WhichDataDisplay] = DataText[WhichDataDisplay]; // Save the old value
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
|
||||
class PageBME280 : public Page
|
||||
{
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
|
||||
public:
|
||||
PageBME280(CommonData &common){
|
||||
commonData = &common;
|
||||
@@ -37,6 +41,7 @@ class PageBME280 : public Page
|
||||
String flashLED = config->getString(config->flashLED);
|
||||
String backlightMode = config->getString(config->backlight);
|
||||
String useenvsensor = config->getString(config->useEnvSensor);
|
||||
bool smallDecimals = config->getBool(config->smallDecimals);
|
||||
|
||||
// Get sensor values #1
|
||||
String name1 = "Temp"; // Value name
|
||||
@@ -121,12 +126,8 @@ class PageBME280 : public Page
|
||||
getdisplay().setCursor(20, 90);
|
||||
getdisplay().print(unit1); // Unit
|
||||
|
||||
// Switch font if format for any values
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(180, 90);
|
||||
|
||||
// Show bus data
|
||||
getdisplay().print(svalue1); // Real value as formated string
|
||||
printBoatValue(svalue1, 380, 90, RIGHT, 30, smallDecimals); // Real value as formated string
|
||||
|
||||
// ############### Horizontal Line ################
|
||||
|
||||
@@ -145,12 +146,8 @@ class PageBME280 : public Page
|
||||
getdisplay().setCursor(20, 180);
|
||||
getdisplay().print(unit2); // Unit
|
||||
|
||||
// Switch font if format for any values
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(180, 180);
|
||||
|
||||
// Show bus data
|
||||
getdisplay().print(svalue2); // Real value as formated string
|
||||
printBoatValue(svalue2, 380, 180, RIGHT, 30, smallDecimals); // Real value as formated string
|
||||
|
||||
// ############### Horizontal Line ################
|
||||
|
||||
@@ -169,12 +166,8 @@ class PageBME280 : public Page
|
||||
getdisplay().setCursor(20, 270);
|
||||
getdisplay().print(unit3); // Unit
|
||||
|
||||
// Switch font if format for any values
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(140, 270);
|
||||
|
||||
// Show bus data
|
||||
getdisplay().print(svalue3); // Real value as formated string
|
||||
printBoatValue(svalue3, 380, 270, RIGHT, 30, smallDecimals); // Real value as formated string
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
|
||||
class PageBattery : public Page
|
||||
{
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
|
||||
int average = 0; // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
|
||||
|
||||
public:
|
||||
@@ -56,6 +60,7 @@ class PageBattery : public Page
|
||||
String backlightMode = config->getString(config->backlight);
|
||||
String powsensor1 = config->getString(config->usePowSensor1);
|
||||
bool simulation = config->getBool(config->useSimuData);
|
||||
bool smallDecimals = config->getBool(config->smallDecimals);
|
||||
|
||||
// Get voltage value
|
||||
String name1 = "VBat"; // Value name
|
||||
@@ -218,17 +223,13 @@ class PageBattery : public Page
|
||||
getdisplay().setCursor(20, 90);
|
||||
getdisplay().print(unit1); // Unit
|
||||
|
||||
// Show value
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(180, 90);
|
||||
|
||||
// Show bus data
|
||||
// Show bus value
|
||||
if(String(powsensor1) != "off"){
|
||||
getdisplay().print(value1,2); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print("---"); // No sensor data (sensor is off)
|
||||
svalue1 = formatValue(value1, String("formatXdr:U:V"), *commonData);
|
||||
} else{
|
||||
svalue1 = "---";
|
||||
}
|
||||
printBoatValue(svalue1, 380, 90, RIGHT, 30, smallDecimals); // Real value as formated string
|
||||
|
||||
// ############### Horizontal Line ################
|
||||
|
||||
@@ -247,17 +248,13 @@ class PageBattery : public Page
|
||||
getdisplay().setCursor(20, 180);
|
||||
getdisplay().print(unit2); // Unit
|
||||
|
||||
// Show value
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(180, 180);
|
||||
|
||||
// Show bus data
|
||||
// Show bus value
|
||||
if(String(powsensor1) != "off"){
|
||||
getdisplay().print(value2,1); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print("---"); // No sensor data (sensor is off)
|
||||
svalue2 = formatValue(value2, String("formatXdr:U:V"), *commonData);
|
||||
} else{
|
||||
svalue2 = "---";
|
||||
}
|
||||
printBoatValue(svalue2, 380, 180, RIGHT, 30, smallDecimals); // Real value as formated string
|
||||
|
||||
// ############### Horizontal Line ################
|
||||
|
||||
@@ -276,17 +273,13 @@ class PageBattery : public Page
|
||||
getdisplay().setCursor(20, 270);
|
||||
getdisplay().print(unit3); // Unit
|
||||
|
||||
// Show value
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(180, 270);
|
||||
|
||||
// Show bus data
|
||||
// Show bus value
|
||||
if(String(powsensor1) != "off"){
|
||||
getdisplay().print(value3,1); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print("---"); // No sensor data (sensor is off)
|
||||
svalue3 = formatValue(value3, String("formatXdr:U:V"), *commonData);
|
||||
} else{
|
||||
svalue3 = "---";
|
||||
}
|
||||
printBoatValue(svalue3, 380, 270, RIGHT, 30, smallDecimals); // Real value as formated string
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
|
||||
class PageBattery2 : public Page
|
||||
{
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
|
||||
bool init = false; // Marker for init done
|
||||
int average = 0; // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
|
||||
bool trend = true; // Trend indicator [0|1], 0=off, 1=on
|
||||
@@ -65,6 +69,7 @@ public:
|
||||
String batType = config->getString(config->batteryType);
|
||||
String backlightMode = config->getString(config->backlight);
|
||||
String powerSensor = config->getString(config->usePowSensor1);
|
||||
bool smallDecimals = config->getBool(config->smallDecimals);
|
||||
|
||||
double value1 = 0; // Battery voltage
|
||||
double value2 = 0; // Battery current
|
||||
@@ -198,20 +203,16 @@ public:
|
||||
getdisplay().print(batType);
|
||||
|
||||
// Show voltage type
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(10, 140);
|
||||
int bvoltage = 0;
|
||||
if(String(batVoltage) == "12V") bvoltage = 12;
|
||||
else bvoltage = 24;
|
||||
getdisplay().print(bvoltage);
|
||||
printBoatValue(String(bvoltage), 10, 140, LEFT, 20, smallDecimals);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("V");
|
||||
|
||||
// Show battery capacity
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(10, 200);
|
||||
if(batCapacity <= 999) getdisplay().print(batCapacity, 0);
|
||||
if(batCapacity > 999) getdisplay().print(float(batCapacity/1000.0), 1);
|
||||
String svalueCapacity = (batCapacity <= 999) ? String(batCapacity) : String(float(batCapacity/1000.0), 1);
|
||||
printBoatValue(svalueCapacity, 10, 200, LEFT, 20, smallDecimals);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
if(batCapacity <= 999) getdisplay().print("Ah");
|
||||
if(batCapacity > 999) getdisplay().print("kAh");
|
||||
@@ -248,20 +249,19 @@ public:
|
||||
}
|
||||
|
||||
// Show fill level in percent
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(150, 200);
|
||||
getdisplay().print(batPercentage);
|
||||
printBoatValue(String(batPercentage), 150, 200, LEFT, 20, smallDecimals);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("%");
|
||||
|
||||
// Show time to full discharge
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(150, 260);
|
||||
String svalueRange;
|
||||
if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
|
||||
if(batRange < 9.9) getdisplay().print(batRange, 1);
|
||||
else getdisplay().print(batRange, 0);
|
||||
svalueRange = (batRange < 9.9) ? String(batRange, 1) : String(batRange, 0);
|
||||
}
|
||||
else getdisplay().print("--");
|
||||
else{
|
||||
svalueRange = "--";
|
||||
}
|
||||
printBoatValue(svalueRange, 150, 260, LEFT, 20, smallDecimals);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("h");
|
||||
|
||||
@@ -282,54 +282,38 @@ public:
|
||||
getdisplay().print("Sensor Modul");
|
||||
|
||||
// Reading bus data or using simulation data
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(260, 140);
|
||||
if(simulation == true){
|
||||
if(batVoltage == "12V"){
|
||||
value1 = 12.0;
|
||||
}
|
||||
if(batVoltage == "24V"){
|
||||
value1 = 24.0;
|
||||
}
|
||||
value1 += float(random(0, 5)) / 10; // Simulation data
|
||||
getdisplay().print(value1,1);
|
||||
}
|
||||
else{
|
||||
String svalue1;
|
||||
// Check for valid real data, display also if hold values activated
|
||||
if(valid1 == true || holdvalues == true){
|
||||
// Resolution switching
|
||||
if(value1 <= 9.9) getdisplay().print(value1, 2);
|
||||
if(value1 > 9.9 && value1 <= 99.9)getdisplay().print(value1, 1);
|
||||
if(value1 > 99.9) getdisplay().print(value1, 0);
|
||||
}
|
||||
else{
|
||||
getdisplay().print("---"); // Missing bus data
|
||||
}
|
||||
svalue1 = formatValue(value1, String("formatXdr:U:V"), *commonData);
|
||||
} else {
|
||||
svalue1 = "---"; // Missing bus data
|
||||
}
|
||||
printBoatValue(svalue1, 355, 140, RIGHT, 20, smallDecimals);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("V");
|
||||
|
||||
// Show actual current in A
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(260, 200);
|
||||
String svalue2;
|
||||
if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
|
||||
if(value2 <= 9.9) getdisplay().print(value2, 2);
|
||||
if(value2 > 9.9 && value2 <= 99.9)getdisplay().print(value2, 1);
|
||||
if(value2 > 99.9) getdisplay().print(value2, 0);
|
||||
svalue2 = formatValue(value2, String("formatXdr:I:A"), *commonData);
|
||||
}
|
||||
else getdisplay().print("---");
|
||||
else{
|
||||
svalue2 = "---";
|
||||
}
|
||||
printBoatValue(svalue2, 355, 200, RIGHT, 20, smallDecimals);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("A");
|
||||
|
||||
// Show actual consumption in W
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(260, 260);
|
||||
String svalue3;
|
||||
if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
|
||||
if(value3 <= 9.9) getdisplay().print(value3, 2);
|
||||
if(value3 > 9.9 && value3 <= 99.9)getdisplay().print(value3, 1);
|
||||
if(value3 > 99.9) getdisplay().print(value3, 0);
|
||||
svalue3 = formatValue(value3, String("formatXdr:G:"), *commonData);
|
||||
}
|
||||
else getdisplay().print("---");
|
||||
else{
|
||||
svalue3 = "---";
|
||||
}
|
||||
printBoatValue(svalue3, 355, 260, RIGHT, 20, smallDecimals);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("W");
|
||||
|
||||
|
||||
@@ -24,6 +24,10 @@ const float Compass_LineDelta = 8.0;// Compass band: 1deg = 5 Pixels, 10deg = 50
|
||||
|
||||
class PageCompass : public Page
|
||||
{
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
|
||||
int WhichDataCompass = ShowHDM;
|
||||
int WhichDataDisplay = ShowHDM;
|
||||
|
||||
@@ -75,6 +79,7 @@ class PageCompass : public Page
|
||||
bool holdvalues = config->getBool(config->holdvalues);
|
||||
String flashLED = config->getString(config->flashLED);
|
||||
String backlightMode = config->getString(config->backlight);
|
||||
bool smallDecimals = config->getBool(config->smallDecimals);
|
||||
|
||||
GwApi::BoatValue *bvalue;
|
||||
String DataName[HowManyValues];
|
||||
@@ -122,14 +127,12 @@ class PageCompass : public Page
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(10, 120);
|
||||
getdisplay().print(DataUnits[WhichDataDisplay]);
|
||||
getdisplay().setCursor(190, 120);
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic42pt7b);
|
||||
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(DataText[WhichDataDisplay]); // Real value as formated string
|
||||
printBoatValue(DataText[WhichDataDisplay], 190, 120, LEFT, 42, smallDecimals); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(OldDataText[WhichDataDisplay]); // Old value as formated string
|
||||
printBoatValue(OldDataText[WhichDataDisplay], 190, 120, LEFT, 42, smallDecimals); // Old value as formated string
|
||||
}
|
||||
if(DataValid[WhichDataDisplay] == true){
|
||||
OldDataText[WhichDataDisplay] = DataText[WhichDataDisplay]; // Save the old value
|
||||
|
||||
@@ -0,0 +1,519 @@
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Extensions.h"
|
||||
#include "OBPDataOperations.h"
|
||||
#include <unordered_map>
|
||||
|
||||
// leeway K coefficient selection options from OBP configuration page
|
||||
static const std::unordered_map<std::string, int> leeKMap = {
|
||||
{ "---", 0 },
|
||||
{ "Racer [2]", 2 },
|
||||
{ "Multihull Draggerboard [4]", 4 },
|
||||
{ "Performance Cruiser [6]", 6 },
|
||||
{ "Family Cruiser [9]", 9 },
|
||||
{ "Heavy Displacement [13]", 13 },
|
||||
{ "Multihull Fixed Keel [16]", 16 }
|
||||
};
|
||||
|
||||
enum bValueIdx {
|
||||
ROLL = 0,
|
||||
SET,
|
||||
DFT,
|
||||
HDT,
|
||||
STW,
|
||||
COG,
|
||||
SOG,
|
||||
HDM,
|
||||
VAR,
|
||||
AWA,
|
||||
NUM_VALS
|
||||
};
|
||||
|
||||
// Screen coordinates for boat value, name, unit
|
||||
struct Points {
|
||||
int16_t x1, y1;
|
||||
int16_t x2, y2;
|
||||
int16_t x3, y3;
|
||||
};
|
||||
|
||||
// Screen coordinates for four boat data values (top-left, bottom-left, top-right, bottom-right)
|
||||
static constexpr Points POS[] = {
|
||||
{ 101, 65, 10, 95, 10, 115 }, // Position top left for value, name, unit
|
||||
{ 101, 270, 10, 220, 10, 190 }, // Position bottom left
|
||||
{ 395, 65, 390, 95, 390, 115 }, // Position top right
|
||||
{ 395, 270, 390, 220, 390, 190 } // Position bottom right
|
||||
};
|
||||
|
||||
// Define wave visual (XBM Format)
|
||||
static constexpr int WAVE_W = 132;
|
||||
static constexpr int WAVE_H = 20;
|
||||
static const uint8_t wave_bitmap[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x80, 0x00, 0xff, 0xf8, 0x00, 0x00, 0xff, 0x80, 0x00,
|
||||
0x7f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xf0, 0x03, 0xff, 0xfe, 0x00, 0x01, 0xff, 0xf0,
|
||||
0x01, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xbf, 0xe0, 0x3f, 0xc0, 0xe2, 0x07,
|
||||
0xff, 0x1f, 0xf8, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x80, 0x07, 0xff, 0x80,
|
||||
0x00, 0xff, 0xff, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x07, 0xfe, 0x00, 0x00, 0x78,
|
||||
0x0f, 0x80, 0x3f, 0xff, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x0f, 0xfe, 0x00, 0x01, 0xff, 0x00,
|
||||
0x00, 0x3f, 0xf0, 0x07, 0xfe, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x3f, 0xff, 0x80, 0x07, 0xff,
|
||||
0xe0, 0x00, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x7e, 0x00, 0xff, 0xff, 0xf0, 0x3f,
|
||||
0xe3, 0xf8, 0x01, 0xc0, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xe7, 0xfc, 0x0f, 0xff,
|
||||
0xff, 0x00, 0x3f, 0x00, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xf0, 0x03,
|
||||
0xff, 0xfc, 0x00, 0x03, 0xf0, 0x00, 0x07, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0,
|
||||
0x00, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
|
||||
0x00, 0x00, 0x07, 0x80, 0xfc, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xe0, 0x00, 0x03, 0xff, 0x80, 0x01, 0xff, 0xf8, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1e, 0x00, 0x0f, 0xff, 0xf0, 0x07, 0xff, 0xff, 0x00, 0xfc, 0x0f, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x3e, 0x03, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xe0, 0x01, 0xe0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0x00, 0x07, 0xff, 0x80, 0x00,
|
||||
0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xe0, 0x00, 0x1f, 0xfc, 0x00, 0x00, 0xfe, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
class PageCurrent : public Page {
|
||||
private:
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
|
||||
GwLog* logger;
|
||||
|
||||
int width; // Screen width
|
||||
int height; // Screen height
|
||||
|
||||
bool keylock = false; // Keylock
|
||||
|
||||
bool useSimuData;
|
||||
bool holdValues;
|
||||
String flashLED;
|
||||
String backlightMode;
|
||||
bool smallDecimals;
|
||||
String leeKStd;
|
||||
double leeK;
|
||||
movingAvgAngle<double> SetAvg {8}; // Store average of the last 8 values of SET angle values
|
||||
movingAvg<double> DftAvg {8}; // Store average of the last 8 values of DFT speed value
|
||||
|
||||
// Old values for hold function
|
||||
String sValueOld[NUM_VALS] = { "", "", "", "", "", "", "", "", "", "" };
|
||||
String unitOld[NUM_VALS] = { "", "", "", "", "", "", "", "", "", "" };
|
||||
|
||||
struct Current {
|
||||
double set; // direction TO which current flows (0..2*PI, true dir)
|
||||
double dft; // current drift speed (m/s)
|
||||
};
|
||||
|
||||
double calcLeeway(
|
||||
double leeK, // leeway coefficient
|
||||
double roll, // heel of boat (rad)
|
||||
double stw // speed through water (m/s)
|
||||
)
|
||||
{
|
||||
static constexpr double MINSTW = 0.5; // minimum speed (m/s) for leeway calculation to prevent math explosion
|
||||
static constexpr double MAXLAY = 30.0 * DEG_TO_RAD; // cap leeway at this level of degree;
|
||||
|
||||
if (stw < MINSTW) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
double lay = leeK * roll / (stw * stw);
|
||||
return std::min(lay, MAXLAY);
|
||||
}
|
||||
|
||||
double calcCTW(
|
||||
double awa, // apparent wind angle (0..2PI -> representation within OBP60)
|
||||
double hdt, // heading true (rad)
|
||||
double lay // leeway angle (rad)
|
||||
)
|
||||
{
|
||||
double ctw; // course through water (rad true)
|
||||
|
||||
if (awa >= M_PI) { // apparent wind > 180° -> comes from port
|
||||
ctw = WindUtils::to2PI(hdt + lay);
|
||||
} else { // wind comes from starboard
|
||||
ctw = WindUtils::to2PI(hdt - lay);
|
||||
}
|
||||
|
||||
return ctw;
|
||||
}
|
||||
|
||||
Current calcSetAndDrift(
|
||||
double lay, // leeway angle (rad)
|
||||
double sog, // speed over ground (m/s)
|
||||
double cog, // course over ground (rad true)
|
||||
double stw, // speed through water (m/s)
|
||||
double hdt, // heading true (rad)
|
||||
double awa // apparent wind angle (rad)
|
||||
)
|
||||
{
|
||||
Current crnt;
|
||||
double ctw; // course through water (rad true)
|
||||
|
||||
ctw = calcCTW(awa, hdt, lay);
|
||||
|
||||
// Ground velocity vector (east, north)
|
||||
double vg_x = sog * std::sin(cog);
|
||||
double vg_y = sog * std::cos(cog);
|
||||
|
||||
// Water-relative velocity vector (east, north)
|
||||
double vw_x = stw * std::sin(ctw);
|
||||
double vw_y = stw * std::cos(ctw);
|
||||
|
||||
// Current vector = ground - water
|
||||
double vc_x = vg_x - vw_x;
|
||||
double vc_y = vg_y - vw_y;
|
||||
|
||||
crnt.dft = std::sqrt(vc_x * vc_x + vc_y * vc_y);
|
||||
|
||||
crnt.set = std::atan2(vc_x, vc_y); // atan2(x, y) because 0° = North, clockwise positive
|
||||
crnt.set = WindUtils::to2PI(crnt.set); // internal respresentation of wind is [0..2PI]
|
||||
|
||||
// LOG_DEBUG(GwLog::DEBUG, "PageCurrent-setDrift: sog: %.3f, ctw: %.3f, stw: %.3f, vc_x: %.3f, vc_y: %.3f, set: %.3f, drift: %.3f",
|
||||
// sog, ctw, stw, vc_x, vc_y, crnt.set, crnt.dft);
|
||||
|
||||
return crnt;
|
||||
};
|
||||
|
||||
// Draw compass rose with boat direction up; top heading of compass rose in degree [0..2PI]
|
||||
void drawCompassRose(double topHeading)
|
||||
{
|
||||
int radius = 110;
|
||||
String sDegree;
|
||||
int centerX = 200;
|
||||
int centerY = 150;
|
||||
|
||||
getdisplay().fillCircle(centerX, centerY, radius + 10, commonData->fgcolor);
|
||||
getdisplay().fillCircle(centerX, centerY, radius + 7, commonData->bgcolor);
|
||||
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
|
||||
for (int i = 0; i < 360; i += 10) {
|
||||
|
||||
float topAngle = (float)(i * DEG_TO_RAD - topHeading); // Calculate the relative angle for drawing; subtracting topHeading shifts the entire rose
|
||||
float sinVal = sin(topAngle);
|
||||
float cosVal = cos(topAngle);
|
||||
|
||||
// Coordinates for the labels (positioned slightly inside the rose)
|
||||
float xLabel = centerX + (radius - 27) * sinVal;
|
||||
float yLabel = centerY - (radius - 24) * cosVal;
|
||||
|
||||
if (i % 30 == 0) {
|
||||
// Draw scale markers (triangles)
|
||||
float dx = 1;
|
||||
float xx1 = -dx;
|
||||
float xx2 = +dx;
|
||||
float yy1 = -(radius - 10);
|
||||
float yy2 = -(radius + 10);
|
||||
|
||||
getdisplay().fillTriangle(centerX + (int)(cosVal * xx1 - sinVal * yy1), centerY + (int)(sinVal * xx1 + cosVal * yy1),
|
||||
centerX + (int)(cosVal * xx2 - sinVal * yy1), centerY + (int)(sinVal * xx2 + cosVal * yy1),
|
||||
centerX + (int)(cosVal * xx1 - sinVal * yy2), centerY + (int)(sinVal * xx1 + cosVal * yy2), commonData->fgcolor);
|
||||
getdisplay().fillTriangle(centerX + (int)(cosVal * xx2 - sinVal * yy1), centerY + (int)(sinVal * xx2 + cosVal * yy1),
|
||||
centerX + (int)(cosVal * xx1 - sinVal * yy2), centerY + (int)(sinVal * xx1 + cosVal * yy2),
|
||||
centerX + (int)(cosVal * xx2 - sinVal * yy2), centerY + (int)(sinVal * xx2 + cosVal * yy2), commonData->fgcolor);
|
||||
|
||||
// Print degree labels
|
||||
sDegree = String(i);
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
displayGetTextBounds(sDegree, (int)xLabel, (int)yLabel, &x1, &y1, &w, &h);
|
||||
getdisplay().setCursor(xLabel - w / 2, yLabel + h / 2);
|
||||
getdisplay().print(sDegree);
|
||||
|
||||
} else {
|
||||
// Draw dots for intermediate 10 degree steps
|
||||
float xDot = centerX + radius * sinVal;
|
||||
float yDot = centerY - radius * cosVal;
|
||||
getdisplay().fillCircle((int)xDot, (int)yDot, 2, commonData->fgcolor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawRotatedArrow(
|
||||
float size, // size of the arrow = speed in m/s [0.5..5.2]
|
||||
float direction // angle the arrow is pointing to [0..2PI]
|
||||
)
|
||||
{
|
||||
static constexpr double MINSIZE = 0.05; // minimum current set (size) (m/s) for arrow size
|
||||
|
||||
if (size < MINSIZE) { // no arrow for current set below 0.05 m/s
|
||||
return;
|
||||
}
|
||||
|
||||
// size [0.5 .. 5.2] -> length [60 .. 130]
|
||||
float maxsize = constrain(size, 0.5, 5.2);
|
||||
float length = 60.0 + ((maxsize - 0.5) / (5.2 - 0.5)) * (130.0 - 60.0);
|
||||
int16_t cx = width / 2;
|
||||
int16_t cy = height / 2;
|
||||
|
||||
// geometry (arrow upwards)
|
||||
float h = length / 2.0;
|
||||
float w = length / 4.0;
|
||||
float headW = length / 1.5;
|
||||
float splitY = -h / 3;
|
||||
|
||||
struct Pt {
|
||||
float x, y;
|
||||
};
|
||||
|
||||
// 7 edges of arrow
|
||||
Pt p[7] = {
|
||||
{ -w / 2, h }, { w / 2, h }, { w / 2, splitY }, { headW / 2, splitY },
|
||||
{ 0, -h }, { -headW / 2, splitY }, { -w / 2, splitY }
|
||||
};
|
||||
|
||||
// edges of arrow with reduced size of 1 px for thicker frame
|
||||
float offset = 1.0;
|
||||
Pt p_in[7] = {
|
||||
{ -w / 2 + offset, h - offset }, { w / 2 - offset, h - offset },
|
||||
{ w / 2 - offset, splitY + offset }, { headW / 2 - offset, splitY + offset },
|
||||
{ 0, -h + offset }, { -headW / 2 + offset, splitY + offset },
|
||||
{ -w / 2 + offset, splitY + offset }
|
||||
};
|
||||
|
||||
// calculate rotation
|
||||
float s = sin(direction);
|
||||
float c = cos(direction);
|
||||
int16_t rx[7], ry[7];
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
// rotate frame
|
||||
rx[i] = cx + (int16_t)(p[i].x * c - p[i].y * s);
|
||||
ry[i] = cy + (int16_t)(p[i].x * s + p[i].y * c);
|
||||
}
|
||||
|
||||
// fill arrow with white area to delete any background data
|
||||
getdisplay().fillTriangle(rx[0], ry[0], rx[1], ry[1], rx[2], ry[2], commonData->bgcolor);
|
||||
getdisplay().fillTriangle(rx[0], ry[0], rx[2], ry[2], rx[6], ry[6], commonData->bgcolor);
|
||||
getdisplay().fillTriangle(rx[5], ry[5], rx[4], ry[4], rx[3], ry[3], commonData->bgcolor);
|
||||
|
||||
// draw arrow frame with "overdraw" for constant thickness
|
||||
for (int i = 0; i < 7; i++) {
|
||||
int next = (i + 1) % 7;
|
||||
int16_t x0 = rx[i], y0 = ry[i];
|
||||
int16_t x1 = rx[next], y1 = ry[next];
|
||||
|
||||
// original line
|
||||
getdisplay().drawLine(x0, y0, x1, y1, commonData->fgcolor);
|
||||
|
||||
// offset by 1 pixel in x or y depending on delta
|
||||
if (abs(x1 - x0) > abs(y1 - y0)) {
|
||||
getdisplay().drawLine(x0, y0 + 1, x1, y1 + 1, commonData->fgcolor);
|
||||
} else {
|
||||
getdisplay().drawLine(x0 + 1, y0, x1 + 1, y1, commonData->fgcolor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
PageCurrent(CommonData& common)
|
||||
{
|
||||
commonData = &common;
|
||||
logger = commonData->logger;
|
||||
LOG_DEBUG(GwLog::LOG, "Instantiate PageCurrent");
|
||||
|
||||
width = getdisplay().width(); // Screen width
|
||||
height = getdisplay().height(); // Screen height
|
||||
|
||||
// Get config data
|
||||
useSimuData = commonData->config->getBool(commonData->config->useSimuData);
|
||||
holdValues = commonData->config->getBool(commonData->config->holdvalues);
|
||||
flashLED = commonData->config->getString(commonData->config->flashLED);
|
||||
backlightMode = commonData->config->getString(commonData->config->backlight);
|
||||
smallDecimals = commonData->config->getBool(commonData->config->smallDecimals);
|
||||
|
||||
leeKStd = commonData->config->getString(commonData->config->leeKStd);
|
||||
auto it = leeKMap.find(leeKStd.c_str());
|
||||
if (it != leeKMap.end()) {
|
||||
leeK = it->second;
|
||||
} else if (leeKStd == "Individual value") {
|
||||
leeK = (commonData->config->getString(commonData->config->leeK)).toDouble();
|
||||
}
|
||||
LOG_DEBUG(GwLog::DEBUG, "PageCurrent: leeKStd: %s, leeK: %.3f", leeKStd.c_str(), leeK);
|
||||
|
||||
// Initialize average buffer for SET and DFT
|
||||
SetAvg.begin();
|
||||
DftAvg.begin();
|
||||
}
|
||||
|
||||
virtual int handleKey(int key)
|
||||
{
|
||||
// Keylock function
|
||||
if (key == 11) { // Code for keylock
|
||||
commonData->keylock = !commonData->keylock;
|
||||
return 0; // Commit the key
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
virtual void displayNew(PageData& pageData)
|
||||
{
|
||||
#ifdef BOARD_OBP60S3
|
||||
// Clear optical warning
|
||||
if (flashLED == "Limit Violation") {
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int displayPage(PageData& pageData)
|
||||
{
|
||||
double lay;
|
||||
Current current;
|
||||
|
||||
LOG_DEBUG(GwLog::LOG, "Display PageCurrent");
|
||||
|
||||
// Get boat values for page
|
||||
// 0=ROLL, 1=SET, 2=DFT, 3=HDT, 4=STW, 5=COG, 6=SOG, 7=HDM, 8=VAR, 9=AWA
|
||||
std::vector<GwApi::BoatValue*> bValue(pageData.values.begin(), pageData.values.end());
|
||||
|
||||
LOG_DEBUG(GwLog::DEBUG, "PageCurrent: printing #1: %s, %.3f, valid: %d, #2: %s, %.3f, valid: %d, #3: %s, %.3f, valid: %d, #4: %s, %.3f, valid: %d, #5: %s, %.3f, valid: %d",
|
||||
bValue[ROLL]->getName().c_str(), bValue[ROLL]->value, bValue[ROLL]->valid, bValue[SET]->getName().c_str(), bValue[SET]->value, bValue[SET]->valid,
|
||||
bValue[DFT]->getName().c_str(), bValue[DFT]->value, bValue[DFT]->valid, bValue[HDT]->getName().c_str(), bValue[HDT]->value, bValue[HDT]->valid,
|
||||
bValue[STW]->getName().c_str(), bValue[STW]->value, bValue[STW]->valid);
|
||||
|
||||
// Calculate current
|
||||
//***********************************************************
|
||||
|
||||
if (!bValue[SET]->valid || !bValue[DFT]->valid) { // If SET or DRIFT not available, try to calculate them
|
||||
if (bValue[SOG]->valid && bValue[COG]->valid && bValue[STW]->valid) {
|
||||
// calculate current only if all required values are available; we accept missing AWA, because this is only required for leeway adjustment
|
||||
|
||||
if (!bValue[HDT]->valid) { // HDT not available
|
||||
if (bValue[HDM]->valid) {
|
||||
if (bValue[VAR]->valid) {
|
||||
bValue[HDT]->value = bValue[HDM]->value + bValue[VAR]->value; // Use corrected HDM if HDT is not available
|
||||
bValue[HDT]->value = WindUtils::to2PI(bValue[HDT]->value);
|
||||
} else {
|
||||
// if HDT cannot be fully substituted by HDM+VAR, continue with HDM only
|
||||
bValue[HDT] = bValue[HDM];
|
||||
}
|
||||
bValue[HDT]->valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bValue[ROLL]->valid || (bValue[ROLL]->getFormat() != "formatXdr:A:D" && bValue[ROLL]->getFormat() != "formatXdr:A:rd" && bValue[ROLL]->getFormat() != "formatCourse")) {
|
||||
bValue[ROLL]->value = 0; // delete last value if roll value is not valid anymore (gateway keeps last value) or wrong type selected by user
|
||||
}
|
||||
LOG_DEBUG(GwLog::DEBUG, "PageCurrent: Roll: %s, %.3f, valid: %d, format: %s",
|
||||
bValue[ROLL]->getName().c_str(), bValue[ROLL]->value, bValue[ROLL]->valid, bValue[ROLL]->getFormat().c_str());
|
||||
|
||||
lay = calcLeeway(leeK, bValue[ROLL]->value, bValue[STW]->value);
|
||||
|
||||
if (bValue[HDT]->valid) { // That's either HDT or HDM
|
||||
double awaVal = (bValue[AWA]->valid ? bValue[AWA]->value : 0.0); // catch potentially missing AWA
|
||||
current = calcSetAndDrift(lay, bValue[SOG]->value, bValue[COG]->value, bValue[STW]->value, bValue[HDT]->value, awaVal);
|
||||
bValue[SET]->value = current.set;
|
||||
bValue[SET]->setFormat("formatCourse");
|
||||
bValue[SET]->valid = true;
|
||||
bValue[DFT]->value = current.dft;
|
||||
bValue[DFT]->setFormat("formatKnots");
|
||||
bValue[DFT]->valid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// averaging current for smoother output
|
||||
if (bValue[SET]->valid && bValue[DFT]->valid) { // Are SET and DRIFT now available?
|
||||
bValue[SET]->value = SetAvg.reading(bValue[SET]->value);
|
||||
bValue[DFT]->value = DftAvg.reading(bValue[DFT]->value);
|
||||
}
|
||||
|
||||
LOG_DEBUG(GwLog::DEBUG, "PageCurrent: leeKStd: %s, leeK: %.3f, lay: %.3f, roll: %.3f, stw: %.3f, awa: %.3f, hdt: %.3f, cog: %.3f, sog: %.3f, set: %.3f, dft: %.3f",
|
||||
leeKStd.c_str(), leeK, lay, bValue[ROLL]->value, bValue[STW]->value, bValue[AWA]->value, bValue[HDT]->value, bValue[COG]->value, bValue[SOG]->value,
|
||||
bValue[SET]->value, bValue[DFT]->value);
|
||||
|
||||
// Draw page
|
||||
//***********************************************************
|
||||
|
||||
displaySetPartialWindow(0, 0, width, height); // Set partial update
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
|
||||
static const int bValType[] = { HDT, STW, SET, DFT }; // Sequence of boat data types to show on page
|
||||
for (int i = 0; i < 4; i++) {
|
||||
String name = xdrDelete(bValue[bValType[i]]->getName()); // Value name
|
||||
name = name.substring(0, 4); // String length limit for value name
|
||||
String sValue = formatValue(bValue[bValType[i]], *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
String unit = formatValue(bValue[bValType[i]], *commonData).unit; // Unit of value
|
||||
unit = unit.substring(0, 6); // String length limit for value unit
|
||||
|
||||
// Show boat data value
|
||||
if (!holdValues || useSimuData) {
|
||||
printBoatValue(sValue, POS[i].x1, POS[i].y1, RIGHT, 20, smallDecimals);
|
||||
} else {
|
||||
printBoatValue(sValueOld[i], POS[i].x1, POS[i].y1, RIGHT, 20, smallDecimals);
|
||||
}
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
if (i < 2) { // left side values
|
||||
getdisplay().setCursor(POS[i].x2, POS[i].y2);
|
||||
getdisplay().print(name);
|
||||
} else { // right side values
|
||||
drawTextRalign(POS[i].x2, POS[i].y2, name);
|
||||
}
|
||||
|
||||
String dUnit; // Unit to show
|
||||
if (holdValues) {
|
||||
dUnit = unitOld[i];
|
||||
} else {
|
||||
dUnit = unit;
|
||||
}
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
if (i < 2) { // left side values
|
||||
getdisplay().setCursor(POS[i].x3, POS[i].y3);
|
||||
getdisplay().print(dUnit);
|
||||
} else { // right side values
|
||||
drawTextRalign(POS[i].x3, POS[i].y3, dUnit);
|
||||
}
|
||||
|
||||
if (bValue[bValType[i]]->valid) {
|
||||
sValueOld[i] = sValue; // Save the old value
|
||||
unitOld[i] = unit; // Save the old unit
|
||||
}
|
||||
}
|
||||
|
||||
// Horizontal separator left
|
||||
getdisplay().fillRect(0, 149, 60, 2, commonData->fgcolor);
|
||||
// Horizontal separator right
|
||||
getdisplay().fillRect(339, 149, 60, 2, commonData->fgcolor);
|
||||
|
||||
if (bValue[HDT]->valid) {
|
||||
drawCompassRose(bValue[HDT]->value);
|
||||
} else {
|
||||
drawCompassRose(0.0);
|
||||
};
|
||||
getdisplay().drawBitmap((width - WAVE_W) / 2, (height - WAVE_H) / 2, wave_bitmap, WAVE_W, WAVE_H, commonData->fgcolor);
|
||||
if (bValue[SET]->valid && bValue[DFT]->valid) {
|
||||
drawRotatedArrow(bValue[DFT]->value, WindUtils::to2PI(bValue[SET]->value - bValue[HDT]->value));
|
||||
}
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
};
|
||||
|
||||
static Page* createPage(CommonData& common)
|
||||
{
|
||||
return new PageCurrent(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 registerPageCurrent(
|
||||
"Current", // Page name
|
||||
createPage, // Action
|
||||
1, // Number of bus values depends on selection in Web configuration -> boat value for ROLL
|
||||
{ "SET", "DFT", "HDT", "STW", "COG", "SOG", "HDM", "VAR", "AWA" }, // Bus values we need in the page
|
||||
true // Show display header on/off
|
||||
);
|
||||
|
||||
#endif
|
||||
@@ -5,6 +5,11 @@
|
||||
|
||||
class PageDST810 : public Page
|
||||
{
|
||||
private:
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
|
||||
public:
|
||||
PageDST810(CommonData &common){
|
||||
commonData = &common;
|
||||
@@ -24,6 +29,9 @@ public:
|
||||
GwConfigHandler *config = commonData->config;
|
||||
GwLog *logger = commonData->logger;
|
||||
|
||||
int valueX, valueY;
|
||||
int DsegFontSize;
|
||||
|
||||
// Old values for hold function
|
||||
static String svalue1old = "";
|
||||
static String unit1old = "";
|
||||
@@ -40,6 +48,7 @@ public:
|
||||
bool holdvalues = config->getBool(config->holdvalues);
|
||||
String flashLED = config->getString(config->flashLED);
|
||||
String backlightMode = config->getString(config->backlight);
|
||||
bool smallDecimals = config->getBool(config->smallDecimals);
|
||||
|
||||
// Get boat values #1
|
||||
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
|
||||
@@ -100,7 +109,8 @@ public:
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(20, 55);
|
||||
getdisplay().print("Depth"); // Page name
|
||||
// getdisplay().print("Depth"); // Page name
|
||||
getdisplay().print(name1); // Page name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
@@ -112,16 +122,15 @@ public:
|
||||
getdisplay().print(unit1old);
|
||||
}
|
||||
|
||||
// Set font
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(180, 90);
|
||||
|
||||
// Show bus data
|
||||
valueX = 380;
|
||||
valueY = 90;
|
||||
DsegFontSize = 30;
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue1); // Real value as formated string
|
||||
printBoatValue(svalue1, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue1old); // Old value as formated string
|
||||
printBoatValue(svalue1old, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Old value as formated string
|
||||
}
|
||||
if(valid1 == true){
|
||||
svalue1old = svalue1; // Save the old value
|
||||
@@ -138,7 +147,8 @@ public:
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(20, 145);
|
||||
getdisplay().print("Speed"); // Page name
|
||||
// getdisplay().print("Speed"); // Page name
|
||||
getdisplay().print(name2); // Page name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
@@ -150,16 +160,15 @@ public:
|
||||
getdisplay().print(unit2old);
|
||||
}
|
||||
|
||||
// Setfont
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(180, 180);
|
||||
|
||||
// Show bus data
|
||||
valueX = 380;
|
||||
valueY = 180;
|
||||
DsegFontSize = 30;
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue2); // Real value as formated string
|
||||
printBoatValue(svalue2, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue2old); // Old value as formated string
|
||||
printBoatValue(svalue2old, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Old value as formated string
|
||||
}
|
||||
if(valid2 == true){
|
||||
svalue2old = svalue2; // Save the old value
|
||||
@@ -176,7 +185,8 @@ public:
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(20, 220);
|
||||
getdisplay().print("Log"); // Page name
|
||||
// getdisplay().print("Log"); // Page name
|
||||
getdisplay().print(name3); // Page name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
@@ -188,16 +198,15 @@ public:
|
||||
getdisplay().print(unit3old);
|
||||
}
|
||||
|
||||
// Set font
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(80, 270);
|
||||
|
||||
// Show bus data
|
||||
valueX = 190;
|
||||
valueY = 270;
|
||||
DsegFontSize = 20;
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue3); // Real value as formated string
|
||||
printBoatValue(svalue3, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue3old); // Old value as formated string
|
||||
printBoatValue(svalue3old, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Old value as formated string
|
||||
}
|
||||
if(valid3 == true){
|
||||
svalue3old = svalue3; // Save the old value
|
||||
@@ -214,7 +223,8 @@ public:
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(220, 220);
|
||||
getdisplay().print("Temp"); // Page name
|
||||
// getdisplay().print("Temp"); // Page name
|
||||
getdisplay().print(name4); // Page name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
@@ -226,16 +236,15 @@ public:
|
||||
getdisplay().print(unit4old);
|
||||
}
|
||||
|
||||
// Set font
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(280, 270);
|
||||
|
||||
// Show bus data
|
||||
valueX = 390;
|
||||
valueY = 270;
|
||||
DsegFontSize = 20;
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue4); // Real value as formated string
|
||||
printBoatValue(svalue4, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue4old); // Old value as formated string
|
||||
printBoatValue(svalue4old, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Old value as formated string
|
||||
}
|
||||
if(valid4 == true){
|
||||
svalue4old = svalue4; // Save the old value
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
|
||||
class PageFourValues : public Page
|
||||
{
|
||||
private:
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
|
||||
public:
|
||||
PageFourValues(CommonData &common){
|
||||
commonData = &common;
|
||||
@@ -24,6 +29,9 @@ class PageFourValues : public Page
|
||||
GwConfigHandler *config = commonData->config;
|
||||
GwLog *logger = commonData->logger;
|
||||
|
||||
int valueX, valueY;
|
||||
int DsegFontSize;
|
||||
|
||||
// Old values for hold function
|
||||
static String svalue1old = "";
|
||||
static String unit1old = "";
|
||||
@@ -35,11 +43,9 @@ class PageFourValues : public Page
|
||||
static String unit4old = "";
|
||||
|
||||
// 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);
|
||||
bool smallDecimals = config->getBool(config->smallDecimals);
|
||||
|
||||
// Get boat values #1
|
||||
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
|
||||
@@ -104,7 +110,7 @@ class PageFourValues : public Page
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(20, 65);
|
||||
getdisplay().setCursor(20, 67);
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(unit1); // Unit
|
||||
}
|
||||
@@ -113,25 +119,26 @@ class PageFourValues : public Page
|
||||
}
|
||||
|
||||
// Switch font if format for any values
|
||||
valueX = 380;
|
||||
if(bvalue1->getFormat() == "formatLatitude" || bvalue1->getFormat() == "formatLongitude"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(120, 55);
|
||||
valueY = 55;
|
||||
DsegFontSize = 12;
|
||||
}
|
||||
else if(bvalue1->getFormat() == "formatTime" || bvalue1->getFormat() == "formatDate"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(150, 58);
|
||||
valueY = 67;
|
||||
DsegFontSize = 20;
|
||||
}
|
||||
else{
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(180, 65);
|
||||
valueY = 67;
|
||||
DsegFontSize = 20;
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue1); // Real value as formated string
|
||||
printBoatValue(svalue1, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue1old); // Old value as formated string
|
||||
printBoatValue(svalue1old, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Old value as formated string
|
||||
}
|
||||
if(valid1 == true){
|
||||
svalue1old = svalue1; // Save the old value
|
||||
@@ -152,7 +159,7 @@ class PageFourValues : public Page
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(20, 133);
|
||||
getdisplay().setCursor(20, 135);
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(unit2); // Unit
|
||||
}
|
||||
@@ -162,24 +169,24 @@ class PageFourValues : public Page
|
||||
|
||||
// Switch font if format for any values
|
||||
if(bvalue2->getFormat() == "formatLatitude" || bvalue2->getFormat() == "formatLongitude"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(120, 123);
|
||||
valueY = 123;
|
||||
DsegFontSize = 12;
|
||||
}
|
||||
else if(bvalue2->getFormat() == "formatTime" || bvalue2->getFormat() == "formatDate"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(150, 123);
|
||||
valueY = 135;
|
||||
DsegFontSize = 20;
|
||||
}
|
||||
else{
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(180, 133);
|
||||
valueY = 135;
|
||||
DsegFontSize = 20;
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue2); // Real value as formated string
|
||||
printBoatValue(svalue2, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue2old); // Old value as formated string
|
||||
printBoatValue(svalue2old, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Old value as formated string
|
||||
}
|
||||
if(valid2 == true){
|
||||
svalue2old = svalue2; // Save the old value
|
||||
@@ -200,7 +207,7 @@ class PageFourValues : public Page
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(20, 201);
|
||||
getdisplay().setCursor(20, 203);
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(unit3); // Unit
|
||||
}
|
||||
@@ -210,24 +217,24 @@ class PageFourValues : public Page
|
||||
|
||||
// Switch font if format for any values
|
||||
if(bvalue3->getFormat() == "formatLatitude" || bvalue3->getFormat() == "formatLongitude"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(120, 191);
|
||||
valueY = 191;
|
||||
DsegFontSize = 16;
|
||||
}
|
||||
else if(bvalue3->getFormat() == "formatTime" || bvalue3->getFormat() == "formatDate"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(150, 191);
|
||||
valueY = 203;
|
||||
DsegFontSize = 20;
|
||||
}
|
||||
else{
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(180, 201);
|
||||
valueY = 203;
|
||||
DsegFontSize = 20;
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue3); // Real value as formated string
|
||||
printBoatValue(svalue3, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue3old); // Old value as formated string
|
||||
printBoatValue(svalue3old, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Old value as formated string
|
||||
}
|
||||
if(valid3 == true){
|
||||
svalue3old = svalue3; // Save the old value
|
||||
@@ -248,7 +255,7 @@ class PageFourValues : public Page
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(20, 269);
|
||||
getdisplay().setCursor(20, 271);
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(unit4); // Unit
|
||||
}
|
||||
@@ -258,24 +265,24 @@ class PageFourValues : public Page
|
||||
|
||||
// Switch font if format for any values
|
||||
if(bvalue4->getFormat() == "formatLatitude" || bvalue4->getFormat() == "formatLongitude"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(120, 259);
|
||||
valueY = 271;
|
||||
DsegFontSize = 16;
|
||||
}
|
||||
else if(bvalue4->getFormat() == "formatTime" || bvalue4->getFormat() == "formatDate"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(150, 259);
|
||||
valueY = 271;
|
||||
DsegFontSize = 20;
|
||||
}
|
||||
else{
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(180, 269);
|
||||
valueY = 271;
|
||||
DsegFontSize = 20;
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue4); // Real value as formated string
|
||||
printBoatValue(svalue4, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue4old); // Old value as formated string
|
||||
printBoatValue(svalue4old, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Old value as formated string
|
||||
}
|
||||
if(valid4 == true){
|
||||
svalue4old = svalue4; // Save the old value
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
|
||||
class PageFourValues2 : public Page
|
||||
{
|
||||
private:
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
|
||||
public:
|
||||
PageFourValues2(CommonData &common){
|
||||
commonData = &common;
|
||||
@@ -24,6 +29,9 @@ class PageFourValues2 : public Page
|
||||
GwConfigHandler *config = commonData->config;
|
||||
GwLog *logger = commonData->logger;
|
||||
|
||||
int valueX, valueY;
|
||||
int DsegFontSize;
|
||||
|
||||
// Old values for hold function
|
||||
static String svalue1old = "";
|
||||
static String unit1old = "";
|
||||
@@ -35,11 +43,9 @@ class PageFourValues2 : public Page
|
||||
static String unit4old = "";
|
||||
|
||||
// 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);
|
||||
bool smallDecimals = config->getBool(config->smallDecimals);
|
||||
|
||||
// Get boat values #1
|
||||
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
|
||||
@@ -113,25 +119,26 @@ class PageFourValues2 : public Page
|
||||
}
|
||||
|
||||
// Switch font if format for any values
|
||||
valueX = 380;
|
||||
if(bvalue1->getFormat() == "formatLatitude" || bvalue1->getFormat() == "formatLongitude"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(100, 90);
|
||||
valueY = 90;
|
||||
DsegFontSize = 20;
|
||||
}
|
||||
else if(bvalue1->getFormat() == "formatTime" || bvalue1->getFormat() == "formatDate"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(180, 77);
|
||||
valueY = 80;
|
||||
DsegFontSize = 20;
|
||||
}
|
||||
else{
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(180, 90);
|
||||
valueY = 90;
|
||||
DsegFontSize = 30;
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue1); // Real value as formated string
|
||||
printBoatValue(svalue1, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue1old); // Old value as formated string
|
||||
printBoatValue(svalue1old, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Old value as formated string
|
||||
}
|
||||
if(valid1 == true){
|
||||
svalue1old = svalue1; // Save the old value
|
||||
@@ -162,24 +169,24 @@ class PageFourValues2 : public Page
|
||||
|
||||
// Switch font if format for any values
|
||||
if(bvalue2->getFormat() == "formatLatitude" || bvalue2->getFormat() == "formatLongitude"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(100, 180);
|
||||
valueY = 180;
|
||||
DsegFontSize = 20;
|
||||
}
|
||||
else if(bvalue2->getFormat() == "formatTime" || bvalue2->getFormat() == "formatDate"){
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(180, 158);
|
||||
valueY = 170;
|
||||
DsegFontSize = 20;
|
||||
}
|
||||
else{
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(180, 180);
|
||||
valueY = 180;
|
||||
DsegFontSize = 30;
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue2); // Real value as formated string
|
||||
printBoatValue(svalue2, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue2old); // Old value as formated string
|
||||
printBoatValue(svalue2old, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Old value as formated string
|
||||
}
|
||||
if(valid2 == true){
|
||||
svalue2old = svalue2; // Save the old value
|
||||
@@ -194,13 +201,13 @@ class PageFourValues2 : public Page
|
||||
// ############### Value 3 ################
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(20, 220);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().setCursor(20, 223);
|
||||
getdisplay().print(name3); // Page name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(20, 240);
|
||||
getdisplay().setFont(&Ubuntu_Bold10pt8b);
|
||||
getdisplay().setCursor(20, 270);
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(unit3); // Unit
|
||||
}
|
||||
@@ -209,25 +216,26 @@ class PageFourValues2 : public Page
|
||||
}
|
||||
|
||||
// Switch font if format for any values
|
||||
valueX = 190;
|
||||
if(bvalue3->getFormat() == "formatLatitude" || bvalue3->getFormat() == "formatLongitude"){
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(50, 240);
|
||||
valueY = 250;
|
||||
DsegFontSize = 10;
|
||||
}
|
||||
else if(bvalue3->getFormat() == "formatTime" || bvalue3->getFormat() == "formatDate"){
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(100, 240);
|
||||
valueY = 253;
|
||||
DsegFontSize = 10;
|
||||
}
|
||||
else{
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(80, 270);
|
||||
valueY = 270;
|
||||
DsegFontSize = 20;
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue3); // Real value as formated string
|
||||
printBoatValue(svalue3, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue3old); // Old value as formated string
|
||||
printBoatValue(svalue3old, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Old value as formated string
|
||||
}
|
||||
if(valid3 == true){
|
||||
svalue3old = svalue3; // Save the old value
|
||||
@@ -242,13 +250,13 @@ class PageFourValues2 : public Page
|
||||
// ############### Value 4 ################
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(220, 220);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().setCursor(220, 223);
|
||||
getdisplay().print(name4); // Page name
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(220, 240);
|
||||
getdisplay().setFont(&Ubuntu_Bold10pt8b);
|
||||
getdisplay().setCursor(220, 270);
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(unit4); // Unit
|
||||
}
|
||||
@@ -257,25 +265,26 @@ class PageFourValues2 : public Page
|
||||
}
|
||||
|
||||
// Switch font if format for any values
|
||||
valueX = 390;
|
||||
if(bvalue4->getFormat() == "formatLatitude" || bvalue4->getFormat() == "formatLongitude"){
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(250, 240);
|
||||
valueY = 250;
|
||||
DsegFontSize = 10;
|
||||
}
|
||||
else if(bvalue4->getFormat() == "formatTime" || bvalue4->getFormat() == "formatDate"){
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(300, 240);
|
||||
valueY = 253;
|
||||
DsegFontSize = 10;
|
||||
}
|
||||
else{
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(280, 270);
|
||||
valueY = 270;
|
||||
DsegFontSize = 20;
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue4); // Real value as formated string
|
||||
printBoatValue(svalue4, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue4old); // Old value as formated string
|
||||
printBoatValue(svalue4old, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Old value as formated string
|
||||
}
|
||||
if(valid4 == true){
|
||||
svalue4old = svalue4; // Save the old value
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
|
||||
class PageGenerator : public Page
|
||||
{
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
|
||||
public:
|
||||
PageGenerator(CommonData &common){
|
||||
commonData = &common;
|
||||
@@ -32,6 +36,7 @@ public:
|
||||
int genPower = config->getInt(config->genPower);
|
||||
String backlightMode = config->getString(config->backlight);
|
||||
String powerSensor = config->getString(config->usePowSensor3);
|
||||
bool smallDecimals = config->getBool(config->smallDecimals);
|
||||
|
||||
double value1 = 0; // Solar voltage
|
||||
double value2 = 0; // Solar current
|
||||
@@ -95,20 +100,16 @@ public:
|
||||
getdisplay().print("Generator");
|
||||
|
||||
// Show voltage type
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(10, 140);
|
||||
int bvoltage = 0;
|
||||
if(String(batVoltage) == "12V") bvoltage = 12;
|
||||
else bvoltage = 24;
|
||||
getdisplay().print(bvoltage);
|
||||
printBoatValue(String(bvoltage), 10, 140, LEFT, 20, smallDecimals);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("V");
|
||||
|
||||
// Show solar power
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(10, 200);
|
||||
if(genPower <= 999) getdisplay().print(genPower, 0);
|
||||
if(genPower > 999) getdisplay().print(float(genPower/1000.0), 1);
|
||||
String svalueGenPower = (genPower <= 999) ? String(genPower) : String(float(genPower/1000.0), 1);
|
||||
printBoatValue(svalueGenPower, 10, 200, LEFT, 20, smallDecimals);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
if(genPower <= 999) getdisplay().print("W");
|
||||
if(genPower > 999) getdisplay().print("kW");
|
||||
@@ -124,9 +125,7 @@ public:
|
||||
generatorGraphic(200, 95, commonData->fgcolor, commonData->bgcolor);
|
||||
|
||||
// Show load level in percent
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(150, 200);
|
||||
getdisplay().print(genPercentage);
|
||||
printBoatValue(String(genPercentage), 150, 200, LEFT, 20, smallDecimals);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("%");
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
@@ -151,54 +150,37 @@ public:
|
||||
getdisplay().print("Sensor Modul");
|
||||
|
||||
// Reading bus data or using simulation data
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(260, 140);
|
||||
if(simulation == true){
|
||||
if(batVoltage == "12V"){
|
||||
value1 = 12.0;
|
||||
}
|
||||
if(batVoltage == "24V"){
|
||||
value1 = 24.0;
|
||||
}
|
||||
value1 += float(random(0, 5)) / 10; // Simulation data
|
||||
getdisplay().print(value1,1);
|
||||
}
|
||||
else{
|
||||
// Check for valid real data, display also if hold values activated
|
||||
String svalue1;
|
||||
if(valid1 == true || holdvalues == true){
|
||||
// Resolution switching
|
||||
if(value1 <= 9.9) getdisplay().print(value1, 2);
|
||||
if(value1 > 9.9 && value1 <= 99.9)getdisplay().print(value1, 1);
|
||||
if(value1 > 99.9) getdisplay().print(value1, 0);
|
||||
}
|
||||
else{
|
||||
getdisplay().print("---"); // Missing bus data
|
||||
}
|
||||
svalue1 = formatValue(value1, String("formatXdr:U:V"), *commonData);
|
||||
} else {
|
||||
svalue1 = "---"; // Missing bus data
|
||||
}
|
||||
printBoatValue(svalue1, 355, 140, RIGHT, 20, smallDecimals);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("V");
|
||||
|
||||
// Show actual current in A
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(260, 200);
|
||||
String svalue2;
|
||||
if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
|
||||
if(value2 <= 9.9) getdisplay().print(value2, 2);
|
||||
if(value2 > 9.9 && value2 <= 99.9)getdisplay().print(value2, 1);
|
||||
if(value2 > 99.9) getdisplay().print(value2, 0);
|
||||
svalue2 = formatValue(value2, String("formatXdr:I:A"), *commonData);
|
||||
}
|
||||
else getdisplay().print("---");
|
||||
else{
|
||||
svalue2 = "---";
|
||||
}
|
||||
printBoatValue(svalue2, 355, 200, RIGHT, 20, smallDecimals);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("A");
|
||||
|
||||
// Show actual consumption in W
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(260, 260);
|
||||
String svalue3;
|
||||
if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
|
||||
if(value3 <= 9.9) getdisplay().print(value3, 2);
|
||||
if(value3 > 9.9 && value3 <= 99.9)getdisplay().print(value3, 1);
|
||||
if(value3 > 99.9) getdisplay().print(value3, 0);
|
||||
svalue3 = formatValue(value3, String("formatXdr:G:"), *commonData);
|
||||
}
|
||||
else getdisplay().print("---");
|
||||
else{
|
||||
svalue3 = "---";
|
||||
}
|
||||
printBoatValue(svalue3, 355, 260, RIGHT, 20, smallDecimals);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("W");
|
||||
|
||||
|
||||
@@ -19,17 +19,6 @@ private:
|
||||
HALF
|
||||
};
|
||||
|
||||
static constexpr char HORIZONTAL = 'H';
|
||||
static constexpr char VERTICAL = 'V';
|
||||
static constexpr int8_t FULL_SIZE = 0;
|
||||
static constexpr int8_t HALF_SIZE_TOP = 1;
|
||||
static constexpr int8_t HALF_SIZE_BOTTOM = 2;
|
||||
|
||||
static constexpr bool PRNT_NAME = true;
|
||||
static constexpr bool NO_PRNT_NAME = false;
|
||||
static constexpr bool PRNT_VALUE = true;
|
||||
static constexpr bool NO_PRNT_VALUE = false;
|
||||
|
||||
int width; // Screen width
|
||||
int height; // Screen height
|
||||
|
||||
@@ -42,8 +31,11 @@ private:
|
||||
bool useSimuData;
|
||||
bool holdValues;
|
||||
String flashLED;
|
||||
String backlightMode;
|
||||
String tempFormat;
|
||||
bool smallDecimals;
|
||||
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
|
||||
// Old values for hold function
|
||||
String sValue1Old = "";
|
||||
@@ -51,38 +43,41 @@ private:
|
||||
|
||||
// Data buffer pointer (owned by HstryBuffers)
|
||||
RingBuffer<uint16_t>* dataHstryBuf = nullptr;
|
||||
std::unique_ptr<Chart> dataChart; // Chart object
|
||||
std::unique_ptr<Chart> dataChart = nullptr; // Chart object
|
||||
|
||||
// display data value in display <mode> [FULL|HALF]
|
||||
void showData(GwApi::BoatValue* bValue1, DisplayMode mode)
|
||||
{
|
||||
int nameXoff, nameYoff, unitXoff, unitYoff, value1Xoff, value1Yoff;
|
||||
const GFXfont *nameFnt, *unitFnt, *valueFnt1, *valueFnt2, *valueFnt3;
|
||||
int nameXoff, nameYoff, unitX, unitY, unitXoff, unitYoff, valueX, valueY, valueXoff, valueYoff;
|
||||
const GFXfont *nameFnt, *unitFnt;
|
||||
int valueFontSize1, valueFontSize2, valueFontSize3, DsegFontSize;
|
||||
|
||||
if (mode == FULL) { // full size data display
|
||||
nameXoff = 0;
|
||||
nameYoff = 0;
|
||||
nameFnt = &Ubuntu_Bold32pt8b;
|
||||
unitX = 380;
|
||||
unitY = 100;
|
||||
unitXoff = 0;
|
||||
unitYoff = 0;
|
||||
unitFnt = &Ubuntu_Bold20pt8b;
|
||||
value1Xoff = 0;
|
||||
value1Yoff = 0;
|
||||
valueFnt1 = &Ubuntu_Bold20pt8b;
|
||||
valueFnt2 = &Ubuntu_Bold32pt8b;
|
||||
valueFnt3 = &DSEG7Classic_BoldItalic60pt7b;
|
||||
valueXoff = 0;
|
||||
valueYoff = 0;
|
||||
valueFontSize1 = 20;
|
||||
valueFontSize2 = 30;
|
||||
valueFontSize3 = 60;
|
||||
} else { // half size data and chart display
|
||||
nameXoff = -10;
|
||||
nameYoff = -34;
|
||||
nameFnt = &Ubuntu_Bold20pt8b;
|
||||
unitXoff = -295;
|
||||
unitYoff = -119;
|
||||
unitX = 10;
|
||||
unitY = 121;
|
||||
unitFnt = &Ubuntu_Bold12pt8b;
|
||||
valueFnt1 = &Ubuntu_Bold12pt8b;
|
||||
value1Xoff = 153;
|
||||
value1Yoff = -119;
|
||||
valueFnt2 = &Ubuntu_Bold20pt8b;
|
||||
valueFnt3 = &DSEG7Classic_BoldItalic42pt7b;
|
||||
valueXoff = 0;
|
||||
valueYoff = -119;
|
||||
valueFontSize1 = 12;
|
||||
valueFontSize2 = 20;
|
||||
valueFontSize3 = 42;
|
||||
}
|
||||
|
||||
String name1 = xdrDelete(bValue1->getName()); // Value name
|
||||
@@ -99,32 +94,38 @@ private:
|
||||
getdisplay().print(name1); // name
|
||||
|
||||
// Show unit
|
||||
String unitName;
|
||||
getdisplay().setFont(unitFnt);
|
||||
getdisplay().setCursor(305 + unitXoff, 240 + unitYoff);
|
||||
|
||||
if (holdValues) {
|
||||
getdisplay().print(unit1Old); // name
|
||||
unitName = unit1Old;
|
||||
} else {
|
||||
getdisplay().print(unit1); // name
|
||||
unitName = unit1;
|
||||
}
|
||||
if (mode == FULL) {
|
||||
drawTextRalign(unitX, unitY, unitName);
|
||||
} else {
|
||||
getdisplay().setCursor(unitX, unitY);
|
||||
getdisplay().print(unitName);
|
||||
}
|
||||
|
||||
// Switch font depending on value format and adjust position
|
||||
valueX = 380 + valueXoff;
|
||||
if (bValue1->getFormat() == "formatLatitude" || bValue1->getFormat() == "formatLongitude") {
|
||||
getdisplay().setFont(valueFnt1);
|
||||
getdisplay().setCursor(20 + value1Xoff, 180 + value1Yoff);
|
||||
valueY = 180 + valueYoff;
|
||||
DsegFontSize = valueFontSize1;
|
||||
} else if (bValue1->getFormat() == "formatTime" || bValue1->getFormat() == "formatDate") {
|
||||
getdisplay().setFont(valueFnt2);
|
||||
getdisplay().setCursor(20 + value1Xoff, 200 + value1Yoff);
|
||||
valueY = 200 + valueYoff;
|
||||
DsegFontSize = valueFontSize2;
|
||||
} else {
|
||||
getdisplay().setFont(valueFnt3);
|
||||
getdisplay().setCursor(20 + value1Xoff, 240 + value1Yoff);
|
||||
valueY = 240 + valueYoff;
|
||||
DsegFontSize = valueFontSize3;
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if (!holdValues || useSimuData) {
|
||||
getdisplay().print(sValue1); // Real value as formated string
|
||||
printBoatValue(sValue1, valueX, valueY, RIGHT, DsegFontSize, smallDecimals);
|
||||
} else {
|
||||
getdisplay().print(sValue1Old); // Old value as formated string
|
||||
printBoatValue(sValue1Old, valueX, valueY, RIGHT, DsegFontSize, smallDecimals);
|
||||
}
|
||||
|
||||
if (valid1 == true) {
|
||||
@@ -138,18 +139,19 @@ public:
|
||||
{
|
||||
commonData = &common;
|
||||
logger = commonData->logger;
|
||||
GwConfigHandler *config = commonData->config;
|
||||
|
||||
LOG_DEBUG(GwLog::LOG, "Instantiate PageOneValue");
|
||||
|
||||
width = getdisplay().width(); // Screen width
|
||||
height = getdisplay().height(); // Screen height
|
||||
getdisplay().setTextWrap(false);
|
||||
|
||||
// Get config data
|
||||
// lengthformat = commonData->config->getString(commonData->config->lengthFormat);
|
||||
useSimuData = commonData->config->getBool(commonData->config->useSimuData);
|
||||
useSimuData = config->getBool(config->useSimuData);
|
||||
holdValues = commonData->config->getBool(commonData->config->holdvalues);
|
||||
flashLED = commonData->config->getString(commonData->config->flashLED);
|
||||
backlightMode = commonData->config->getString(commonData->config->backlight);
|
||||
tempFormat = commonData->config->getString(commonData->config->tempFormat); // [K|°C|°F]
|
||||
smallDecimals = commonData->config->getBool(commonData->config->smallDecimals);
|
||||
}
|
||||
|
||||
virtual void setupKeys()
|
||||
@@ -243,10 +245,10 @@ public:
|
||||
dataHstryBuf = pageData.hstryBuffers->getBuffer(bValName1);
|
||||
|
||||
if (dataHstryBuf) {
|
||||
dataChart.reset(new Chart(*dataHstryBuf, Chart::dfltChrtDta[bValFormat].range, *commonData, useSimuData));
|
||||
LOG_DEBUG(GwLog::DEBUG, "PageOneValue: Created chart objects for %s", bValName1);
|
||||
dataChart.reset(new Chart(*dataHstryBuf, *commonData, useSimuData));
|
||||
LOG_DEBUG(GwLog::DEBUG, "PageOneValue: Created chart object for %s", bValName1);
|
||||
} else {
|
||||
LOG_DEBUG(GwLog::DEBUG, "PageOneValue: No chart objects available for %s", bValName1);
|
||||
LOG_DEBUG(GwLog::DEBUG, "PageOneValue: No chart object available for %s", bValName1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,12 +262,13 @@ public:
|
||||
// Get boat value for page
|
||||
GwApi::BoatValue* bValue1 = pageData.values[0]; // Page boat data element
|
||||
|
||||
#ifdef BOARD_OBP60S3
|
||||
// Optical warning by limit violation (unused)
|
||||
if (String(flashLED) == "Limit Violation") {
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
|
||||
#endif
|
||||
if (bValue1 == NULL)
|
||||
return PAGE_OK; // no data, no page to display
|
||||
|
||||
@@ -276,19 +279,25 @@ public:
|
||||
|
||||
displaySetPartialWindow(0, 0, width, height); // Set partial update
|
||||
|
||||
if (pageMode == VALUE || dataHstryBuf == nullptr) {
|
||||
if (dataChart) { // Check only if dataChart object exists at all
|
||||
if (!dataChart->isValid()) {
|
||||
dataChart->init(); // try late initialization if chart object could not be properly initialized earlier due to missing boat data
|
||||
}
|
||||
}
|
||||
|
||||
if (pageMode == VALUE || dataChart == nullptr) {
|
||||
// show only data value; ignore other pageMode options if no chart supported boat data history buffer is available
|
||||
showData(bValue1, FULL);
|
||||
|
||||
} else if (pageMode == CHART) { // show only data chart
|
||||
if (dataChart) {
|
||||
dataChart->showChrt(HORIZONTAL, FULL_SIZE, dataIntv, PRNT_NAME, PRNT_VALUE, *bValue1);
|
||||
dataChart->showChrt(Chart::HORIZONTAL, Chart::FULL_SIZE, dataIntv, Chart::PRNT_NAME, Chart::PRNT_VALUE, *bValue1);
|
||||
}
|
||||
|
||||
} else if (pageMode == BOTH) { // show data value and chart
|
||||
showData(bValue1, HALF);
|
||||
if (dataChart) {
|
||||
dataChart->showChrt(HORIZONTAL, HALF_SIZE_BOTTOM, dataIntv, NO_PRNT_NAME, NO_PRNT_VALUE, *bValue1);
|
||||
dataChart->showChrt(Chart::HORIZONTAL, Chart::HALF_SIZE_RIGHT_BOTTOM, dataIntv, Chart::NO_PRNT_NAME, Chart::NO_PRNT_VALUE, *bValue1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
|
||||
class PageRollPitch : public Page
|
||||
{
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
|
||||
public:
|
||||
PageRollPitch(CommonData &common){
|
||||
commonData = &common;
|
||||
@@ -44,12 +48,15 @@ public:
|
||||
double rolloffset = roffset.toFloat()/360*(2*M_PI);
|
||||
String poffset = config->getString(config->pitchOffset);
|
||||
double pitchoffset = poffset.toFloat()/360*(2*M_PI);
|
||||
bool smallDecimals = config->getBool(config->smallDecimals);
|
||||
|
||||
// Get boat values for roll
|
||||
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (xdrRoll)
|
||||
String name1 = xdrDelete(bvalue1->getName()); // Value name
|
||||
name1 = name1.substring(0, 6); // String length limit for value name
|
||||
name1 = name1.substring(0, 5); // String length limit for value name
|
||||
bool valid1 = bvalue1->valid; // Valid information
|
||||
String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
|
||||
unit1 = unit1.substring(0, 4); // String length limit for value unit
|
||||
if(valid1 == true){
|
||||
value1 = bvalue1->value + rolloffset; // Raw value for pitch
|
||||
}
|
||||
@@ -73,8 +80,10 @@ public:
|
||||
// Get boat values for pitch
|
||||
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (xdrPitch)
|
||||
String name2 = xdrDelete(bvalue2->getName()); // Value name
|
||||
name2 = name2.substring(0, 6); // String length limit for value name
|
||||
name2 = name2.substring(0, 5); // String length limit for value name
|
||||
bool valid2 = bvalue2->valid; // Valid information
|
||||
String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value
|
||||
unit2 = unit2.substring(0, 4); // String length limit for value unit
|
||||
if(valid2 == true){
|
||||
value2 = bvalue2->value + pitchoffset; // Raw value for pitch
|
||||
}
|
||||
@@ -86,7 +95,7 @@ public:
|
||||
value2 = 0;
|
||||
}
|
||||
}
|
||||
if(value2/(2*PI)*360 > -10 && value2/(2*M_PI)*360 < 10){
|
||||
if(value2/(2*M_PI)*360 > -10 && value2/(2*M_PI)*360 < 10){
|
||||
svalue2 = String(value2/(2*M_PI)*360,1); // Convert raw value to string
|
||||
}
|
||||
else{
|
||||
@@ -121,53 +130,44 @@ public:
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
|
||||
// Show roll limit
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(10, 65);
|
||||
getdisplay().print(rolllimit); // Value
|
||||
//getdisplay().print(svalue1); // Value
|
||||
printBoatValue(String(rolllimit), 10, 65, LEFT, 20, smallDecimals); // Value
|
||||
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(10, 95);
|
||||
getdisplay().print("Limit"); // Name
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(10, 115);
|
||||
getdisplay().print("DEG");
|
||||
getdisplay().print("Deg");
|
||||
|
||||
// Horizintal separator left
|
||||
getdisplay().fillRect(0, 149, 60, 3, commonData->fgcolor);
|
||||
|
||||
// Show roll value
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(10, 270);
|
||||
if(holdvalues == false) getdisplay().print(svalue1); // Value
|
||||
else getdisplay().print(svalue1old);
|
||||
if(holdvalues == false) printBoatValue(svalue1, 101, 270, RIGHT, 20, smallDecimals); // Value
|
||||
else printBoatValue(svalue1old, 101, 270, RIGHT, 20, smallDecimals);
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(10, 220);
|
||||
getdisplay().print(name1); // Name
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(10, 190);
|
||||
getdisplay().print("Deg");
|
||||
getdisplay().print(unit1); // Unit
|
||||
|
||||
// Horizintal separator right
|
||||
getdisplay().fillRect(340, 149, 80, 3, commonData->fgcolor);
|
||||
|
||||
// Show pitch value
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(295, 270);
|
||||
if(holdvalues == false) getdisplay().print(svalue2); // Value
|
||||
else getdisplay().print(svalue2old);
|
||||
if(holdvalues == false) printBoatValue(svalue2, 395, 270, RIGHT, 20, smallDecimals); // Value
|
||||
else printBoatValue(svalue2old, 395, 270, RIGHT, 20, smallDecimals);
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(335, 220);
|
||||
getdisplay().print(name2); // Name
|
||||
drawTextRalign(395, 220, name2); // Name
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(335, 190);
|
||||
getdisplay().print("Deg");
|
||||
getdisplay().print(unit2); // Unit
|
||||
|
||||
//*******************************************************************************************
|
||||
|
||||
// Draw instrument
|
||||
int rInstrument = 100; // Radius of instrument
|
||||
float pi = 3.141592;
|
||||
|
||||
getdisplay().fillCircle(200, 150, rInstrument + 10, commonData->fgcolor); // Outer circle
|
||||
getdisplay().fillCircle(200, 150, rInstrument + 7, commonData->bgcolor); // Outer circle
|
||||
@@ -264,11 +264,11 @@ public:
|
||||
int y0 = 150;
|
||||
int x1 = x0 + 50*cos(value1);
|
||||
int y1 = y0 + 50*sin(value1);
|
||||
int x2 = x0 + 50*cos(value1 - pi/2);
|
||||
int y2 = y0 + 50*sin(value1 - pi/2);
|
||||
int x2 = x0 + 50*cos(value1 - M_PI/2);
|
||||
int y2 = y0 + 50*sin(value1 - M_PI/2);
|
||||
getdisplay().fillTriangle(x0, y0, x1, y1, x2, y2, commonData->bgcolor); // Clear half top side of boat circle (right triangle)
|
||||
x1 = x0 + 50*cos(value1 + pi);
|
||||
y1 = y0 + 50*sin(value1 + pi);
|
||||
x1 = x0 + 50*cos(value1 + M_PI);
|
||||
y1 = y0 + 50*sin(value1 + M_PI);
|
||||
getdisplay().fillTriangle(x0, y0, x1, y1, x2, y2, commonData->bgcolor); // Clear half top side of boat circle (left triangle)
|
||||
getdisplay().fillRect(150, 160, 100, 4, commonData->fgcolor); // Water line
|
||||
|
||||
|
||||
@@ -3,23 +3,47 @@
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Extensions.h"
|
||||
|
||||
const int SixValues_x1 = 5;
|
||||
const int SixValues_DeltaX = 200;
|
||||
class PageSixValues : public Page {
|
||||
private:
|
||||
GwLog* logger;
|
||||
GwConfigHandler* config;
|
||||
|
||||
const int SixValues_y1 = 23;
|
||||
const int SixValues_DeltaY = 83;
|
||||
bool holdValues;
|
||||
String flashLED;
|
||||
String backlightMode;
|
||||
bool smallDecimals;
|
||||
|
||||
const int HowManyValues = 6;
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
|
||||
static constexpr int SixValues_x1 = 5;
|
||||
static constexpr int SixValues_DeltaX = 200;
|
||||
static constexpr int SixValues_y1 = 22;
|
||||
static constexpr int SixValues_DeltaY = 83;
|
||||
|
||||
static constexpr int HowManyValues = 6;
|
||||
// Old values for hold function
|
||||
String OldDataText[HowManyValues] = { "", "", "", "", "", "" };
|
||||
String OldDataUnit[HowManyValues] = { "", "", "", "", "", "" };
|
||||
|
||||
class PageSixValues : public Page
|
||||
{
|
||||
public:
|
||||
PageSixValues(CommonData &common){
|
||||
PageSixValues(CommonData& common)
|
||||
{
|
||||
commonData = &common;
|
||||
common.logger->logDebug(GwLog::LOG,"Instantiate PageSixValues");
|
||||
config = commonData->config;
|
||||
logger = commonData->logger;
|
||||
LOG_DEBUG(GwLog::LOG, "Instantiate PageSixValues");
|
||||
|
||||
// Get config data
|
||||
holdValues = config->getBool(config->holdvalues);
|
||||
flashLED = config->getString(config->flashLED);
|
||||
backlightMode = config->getString(config->backlight);
|
||||
smallDecimals = config->getBool(config->smallDecimals);
|
||||
}
|
||||
|
||||
virtual int handleKey(int key){
|
||||
virtual int handleKey(int key)
|
||||
{
|
||||
// Code for keylock
|
||||
if (key == 11) {
|
||||
commonData->keylock = !commonData->keylock;
|
||||
@@ -28,29 +52,16 @@ class PageSixValues : public Page
|
||||
return key;
|
||||
}
|
||||
|
||||
int displayPage(PageData &pageData){
|
||||
GwConfigHandler *config = commonData->config;
|
||||
GwLog *logger = commonData->logger;
|
||||
|
||||
|
||||
// Old values for hold function
|
||||
static String OldDataText[HowManyValues] = {"", "", "", "", "", ""};
|
||||
static String OldDataUnits[HowManyValues] = {"", "", "", "", "", ""};
|
||||
|
||||
// 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);
|
||||
|
||||
int displayPage(PageData& pageData)
|
||||
{
|
||||
GwApi::BoatValue* bvalue;
|
||||
String DataName[HowManyValues];
|
||||
double DataValue[HowManyValues];
|
||||
bool DataValid[HowManyValues];
|
||||
String DataText[HowManyValues];
|
||||
String DataUnits[HowManyValues];
|
||||
String DataUnit[HowManyValues];
|
||||
String DataFormat[HowManyValues];
|
||||
int8_t DsegFontSize = 0;
|
||||
|
||||
for (int i = 0; i < HowManyValues; i++) {
|
||||
bvalue = pageData.values[i];
|
||||
@@ -59,35 +70,40 @@ class PageSixValues : public Page
|
||||
DataValue[i] = bvalue->value; // Value as double in SI unit
|
||||
DataValid[i] = bvalue->valid;
|
||||
DataText[i] = formatValue(bvalue, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
DataUnits[i] = formatValue(bvalue, *commonData).unit;
|
||||
DataUnit[i] = formatValue(bvalue, *commonData).unit;
|
||||
DataFormat[i] = bvalue->getFormat(); // Unit of value
|
||||
}
|
||||
|
||||
#ifdef BOARD_OBP60S3
|
||||
// Optical warning by limit violation (unused)
|
||||
if (String(flashLED) == "Limit Violation") {
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
|
||||
if (bvalue == NULL) return PAGE_OK; // WTF why this statement?
|
||||
#endif
|
||||
if (bvalue == NULL)
|
||||
return PAGE_OK;
|
||||
|
||||
// Draw page
|
||||
//***********************************************************
|
||||
|
||||
// Set display in partial refresh mode
|
||||
displaySetPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
getdisplay().setTextWrap(false);
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
|
||||
for (int i = 0; i < (HowManyValues / 2); i++) {
|
||||
if (i < (HowManyValues / 2) - 1) { // Don't draw horizontal line after last line of values -> standard design
|
||||
// Horizontal line 3 pix
|
||||
if (i < (HowManyValues / 2) - 1) { // Don't draw horizontal line after last line of values
|
||||
// Horizontal line 3 px
|
||||
getdisplay().fillRect(0, SixValues_y1 + (i + 1) * SixValues_DeltaY, 400, 3, commonData->fgcolor);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 2; j++) {
|
||||
int ValueIndex = i * 2 + j;
|
||||
int x0 = SixValues_x1 + j * SixValues_DeltaX;
|
||||
int y0 = SixValues_y1 + i * SixValues_DeltaY;
|
||||
LOG_DEBUG(GwLog::LOG,"Drawing at PageSixValue: %d %s %f %s", ValueIndex, DataName[ValueIndex], DataValue[ValueIndex], DataFormat[ValueIndex] );
|
||||
//LOG_DEBUG(GwLog::DEBUG, "Drawing at PageSixValue: %d %s %f %s %s", ValueIndex, DataName[ValueIndex],
|
||||
// DataValue[ValueIndex], DataUnit[ValueIndex], DataFormat[ValueIndex]);
|
||||
|
||||
// Show name
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
@@ -96,62 +112,46 @@ class PageSixValues : public Page
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(x0, y0+72);
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(DataUnits[ValueIndex]); // Unit
|
||||
}
|
||||
else{
|
||||
getdisplay().print(OldDataUnits[ValueIndex]);
|
||||
if (holdValues == false) {
|
||||
drawTextRalign(x0 + 187, y0 + 19, DataUnit[ValueIndex]); // Unit
|
||||
} else {
|
||||
drawTextRalign(x0 + 187, y0 + 19, OldDataUnit[ValueIndex]);
|
||||
}
|
||||
|
||||
// Switch font if format for any values
|
||||
// Set font size depending on data type
|
||||
if (DataFormat[ValueIndex] == "formatLatitude" || DataFormat[ValueIndex] == "formatLongitude") {
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(x0+10, y0+60);
|
||||
DsegFontSize = 12;
|
||||
} else if (DataFormat[ValueIndex] == "formatTime" || DataFormat[ValueIndex] == "formatDate") {
|
||||
DsegFontSize = 16;
|
||||
}
|
||||
else if(DataFormat[ValueIndex] == "formatTime" || DataFormat[ValueIndex] == "formatDate"){
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().setCursor(x0+20,y0+55);
|
||||
}
|
||||
// pressure in hPa
|
||||
else if(DataFormat[ValueIndex] == "formatXdr:P:P"){
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic26pt7b);
|
||||
getdisplay().setCursor(x0+5, y0+70);
|
||||
}
|
||||
// RPM
|
||||
else if(DataFormat[ValueIndex] == "formatXdr:T:R"){
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
|
||||
getdisplay().setCursor(x0+25, y0+70);
|
||||
else if (DataFormat[ValueIndex] == "formatXdr:T:R") { // RPM
|
||||
DsegFontSize = 20;
|
||||
}
|
||||
else {
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic26pt7b);
|
||||
if ( DataText[ValueIndex][0] == '-' )
|
||||
getdisplay().setCursor(x0+25, y0+70);
|
||||
else
|
||||
getdisplay().setCursor(x0+65, y0+70);
|
||||
DsegFontSize = 26;
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(DataText[ValueIndex]); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(OldDataText[ValueIndex]); // Old value as formated string
|
||||
// Show bus data value
|
||||
if (holdValues == false) {
|
||||
printBoatValue(DataText[ValueIndex], x0 + 187, y0 + 79, RIGHT, DsegFontSize, smallDecimals);
|
||||
} else {
|
||||
printBoatValue(OldDataText[ValueIndex], x0 + 187, y0 + 79, RIGHT, DsegFontSize, smallDecimals);
|
||||
}
|
||||
|
||||
if (DataValid[ValueIndex] == true) {
|
||||
OldDataText[ValueIndex] = DataText[ValueIndex]; // Save the old value
|
||||
OldDataUnits[ValueIndex] = DataUnits[ValueIndex]; // Save the old unit
|
||||
OldDataUnit[ValueIndex] = DataUnit[ValueIndex]; // Save the old unit
|
||||
}
|
||||
}
|
||||
// Vertical line 3 pix
|
||||
// Vertical line 3 px
|
||||
getdisplay().fillRect(SixValues_x1 + SixValues_DeltaX - 8, SixValues_y1 + i * SixValues_DeltaY, 3, SixValues_DeltaY, commonData->fgcolor);
|
||||
}
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
|
||||
};
|
||||
static Page *createPage(CommonData &common){
|
||||
static Page* createPage(CommonData& common)
|
||||
{
|
||||
return new PageSixValues(common);
|
||||
} /**
|
||||
* with the code below we make this page known to the PageTask
|
||||
|
||||
+26
-44
@@ -5,6 +5,10 @@
|
||||
|
||||
class PageSolar : public Page
|
||||
{
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
|
||||
public:
|
||||
PageSolar(CommonData &common){
|
||||
commonData = &common;
|
||||
@@ -31,6 +35,7 @@ public:
|
||||
int solPower = config->getInt(config->solarPower);
|
||||
String backlightMode = config->getString(config->backlight);
|
||||
String powerSensor = config->getString(config->usePowSensor2);
|
||||
bool smallDecimals = config->getBool(config->smallDecimals);
|
||||
|
||||
double value1 = 0; // Solar voltage
|
||||
double value2 = 0; // Solar current
|
||||
@@ -91,20 +96,16 @@ public:
|
||||
getdisplay().print("Solar");
|
||||
|
||||
// Show voltage type
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(10, 140);
|
||||
int bvoltage = 0;
|
||||
if(String(batVoltage) == "12V") bvoltage = 12;
|
||||
else bvoltage = 24;
|
||||
getdisplay().print(bvoltage);
|
||||
printBoatValue(String(bvoltage), 10, 140, LEFT, 20, smallDecimals);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("V");
|
||||
|
||||
// Show solar power
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(10, 200);
|
||||
if(solPower <= 999) getdisplay().print(solPower, 0);
|
||||
if(solPower > 999) getdisplay().print(float(solPower/1000.0), 1);
|
||||
String svalueSolPower = (solPower <= 999) ? String(solPower) : String(float(solPower/1000.0), 1);
|
||||
printBoatValue(svalueSolPower, 10, 200, LEFT, 20, smallDecimals);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
if(solPower <= 999) getdisplay().print("W");
|
||||
if(solPower > 999) getdisplay().print("kW");
|
||||
@@ -120,9 +121,7 @@ public:
|
||||
solarGraphic(150, 45, commonData->fgcolor, commonData->bgcolor);
|
||||
|
||||
// Show load level in percent
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(150, 200);
|
||||
getdisplay().print(solPercentage);
|
||||
printBoatValue(String(solPercentage), 150, 200, LEFT, 20, smallDecimals);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("%");
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
@@ -147,54 +146,37 @@ public:
|
||||
getdisplay().print("Sensor Modul");
|
||||
|
||||
// Reading bus data or using simulation data
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(260, 140);
|
||||
if(simulation == true){
|
||||
if(batVoltage == "12V"){
|
||||
value1 = 12.0;
|
||||
}
|
||||
if(batVoltage == "24V"){
|
||||
value1 = 24.0;
|
||||
}
|
||||
value1 += float(random(0, 5)) / 10; // Simulation data
|
||||
getdisplay().print(value1,1);
|
||||
}
|
||||
else{
|
||||
// Check for valid real data, display also if hold values activated
|
||||
String svalue1;
|
||||
if(valid1 == true || holdvalues == true){
|
||||
// Resolution switching
|
||||
if(value1 <= 9.9) getdisplay().print(value1, 2);
|
||||
if(value1 > 9.9 && value1 <= 99.9)getdisplay().print(value1, 1);
|
||||
if(value1 > 99.9) getdisplay().print(value1, 0);
|
||||
}
|
||||
else{
|
||||
getdisplay().print("---"); // Missing bus data
|
||||
}
|
||||
svalue1 = formatValue(value1, String("formatXdr:U:V"), *commonData);
|
||||
} else {
|
||||
svalue1 = "---"; // Missing bus data
|
||||
}
|
||||
printBoatValue(svalue1, 355, 140, RIGHT, 20, smallDecimals);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("V");
|
||||
|
||||
// Show actual current in A
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(260, 200);
|
||||
String svalue2;
|
||||
if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
|
||||
if(value2 <= 9.9) getdisplay().print(value2, 2);
|
||||
if(value2 > 9.9 && value2 <= 99.9)getdisplay().print(value2, 1);
|
||||
if(value2 > 99.9) getdisplay().print(value2, 0);
|
||||
svalue2 = formatValue(value2, String("formatXdr:I:A"), *commonData);
|
||||
}
|
||||
else getdisplay().print("---");
|
||||
else{
|
||||
svalue2 = "---";
|
||||
}
|
||||
printBoatValue(svalue2, 355, 200, RIGHT, 20, smallDecimals);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("A");
|
||||
|
||||
// Show actual consumption in W
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(260, 260);
|
||||
String svalue3;
|
||||
if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
|
||||
if(value3 <= 9.9) getdisplay().print(value3, 2);
|
||||
if(value3 > 9.9 && value3 <= 99.9)getdisplay().print(value3, 1);
|
||||
if(value3 > 99.9) getdisplay().print(value3, 0);
|
||||
svalue3 = formatValue(value3, String("formatXdr:G:"), *commonData);
|
||||
}
|
||||
else getdisplay().print("---");
|
||||
else{
|
||||
svalue3 = "---";
|
||||
}
|
||||
printBoatValue(svalue3, 355, 260, RIGHT, 20, smallDecimals);
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt8b);
|
||||
getdisplay().print("W");
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
* Consists of some sub-pages with following content:
|
||||
* 1. Hard and software information
|
||||
* 2. System settings
|
||||
* 3. NMEA2000 device list
|
||||
* 4. SD Card information if available
|
||||
* 3. WiFi settings + message info
|
||||
* 4. NMEA2000 device list
|
||||
* 5. SD Card information if available
|
||||
*/
|
||||
|
||||
#include "Pagedata.h"
|
||||
@@ -51,6 +52,9 @@ private:
|
||||
double homelat;
|
||||
double homelon;
|
||||
|
||||
String systemName;
|
||||
String apPasswd;
|
||||
|
||||
char mode = 'N'; // (N)ormal, (S)ettings, (C)onfiguration, (D)evice list, c(A)rd
|
||||
|
||||
#ifdef PATCH_N2K
|
||||
@@ -68,7 +72,10 @@ private:
|
||||
if (mode == 'N') { // Normal
|
||||
mode = 'S';
|
||||
} else if (mode == 'S') { // Settings
|
||||
mode = 'C';
|
||||
mode = 'W';
|
||||
} else if (mode == 'W') { // Wifi
|
||||
// mode = 'C';
|
||||
mode = 'D';
|
||||
} else if (mode == 'C') { // Config
|
||||
mode = 'D';
|
||||
} else if (mode == 'D') { // Device list
|
||||
@@ -91,10 +98,13 @@ private:
|
||||
}
|
||||
} else if (mode == 'S') { // Settings
|
||||
mode = 'N';
|
||||
} else if (mode == 'C') { // Config
|
||||
} else if (mode == 'W') { // Wifi
|
||||
mode = 'S';
|
||||
} else if (mode == 'C') { // Config
|
||||
mode = 'W';
|
||||
} else if (mode == 'D') { // Device list
|
||||
mode = 'C';
|
||||
// mode = 'C';
|
||||
mode = 'W';
|
||||
} else {
|
||||
mode = 'D';
|
||||
}
|
||||
@@ -235,7 +245,7 @@ private:
|
||||
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(8, 48);
|
||||
getdisplay().print("System configuration");
|
||||
getdisplay().print("System Configuration");
|
||||
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
|
||||
@@ -260,7 +270,7 @@ private:
|
||||
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(x0, 48);
|
||||
getdisplay().print("System settings");
|
||||
getdisplay().print("System Settings");
|
||||
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
|
||||
@@ -358,6 +368,101 @@ private:
|
||||
#endif
|
||||
}
|
||||
|
||||
void displayModeNetwork() {
|
||||
// View current network state
|
||||
|
||||
const uint16_t x0 = 5;
|
||||
const uint16_t x1 = 210;
|
||||
const uint16_t y0 = 72;
|
||||
const uint16_t y1 = 170;
|
||||
const uint16_t dy = 16;
|
||||
|
||||
String msgCount;
|
||||
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(x0, 48);
|
||||
getdisplay().print("Network Status");
|
||||
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
|
||||
getdisplay().setCursor(x0, y0);
|
||||
getdisplay().print("Messages in/out:");
|
||||
|
||||
// left column
|
||||
getdisplay().setCursor(x0, y0 + 1 * dy);
|
||||
getdisplay().print("N2k:");
|
||||
msgCount = String(commonData->status.n2kRx) + "/" + String(commonData->status.n2kTx);
|
||||
getdisplay().setCursor(x0 + 80, y0 + 1 * dy);
|
||||
getdisplay().print(msgCount);
|
||||
|
||||
getdisplay().setCursor(x0, y0 + 2 * dy);
|
||||
getdisplay().print("TCPsrv:");
|
||||
msgCount = String(commonData->status.tcpSerRx) + "/" + String(commonData->status.tcpSerTx);
|
||||
getdisplay().setCursor(x0 + 80, y0 + 2 * dy);
|
||||
getdisplay().print(msgCount);
|
||||
|
||||
getdisplay().setCursor(x0, y0 + 3 * dy);
|
||||
getdisplay().print("TCPclnt:");
|
||||
msgCount = String(commonData->status.tcpClRx) + "/" + String(commonData->status.tcpClTx);
|
||||
getdisplay().setCursor(x0 + 80, y0 + 3 * dy);
|
||||
getdisplay().print(msgCount);
|
||||
|
||||
// right column
|
||||
getdisplay().setCursor(x1, y0 + 1 * dy);
|
||||
getdisplay().print("UDP:");
|
||||
msgCount = String(commonData->status.udprRx) + "/" + String(commonData->status.udpwTx);
|
||||
getdisplay().setCursor(x1 + 80, y0 + 1 * dy);
|
||||
getdisplay().print(msgCount);
|
||||
|
||||
getdisplay().setCursor(x1, y0 + 2 * dy);
|
||||
getdisplay().print("Serial:");
|
||||
msgCount = String(commonData->status.serRx) + "/" + String(commonData->status.serTx);
|
||||
getdisplay().setCursor(x1 + 80, y0 + 2 * dy);
|
||||
getdisplay().print(msgCount);
|
||||
|
||||
getdisplay().setCursor(x1, y0 + 3 * dy);
|
||||
getdisplay().print("USB:");
|
||||
msgCount = String(commonData->status.usbRx) + "/" + String(commonData->status.usbTx);
|
||||
getdisplay().setCursor(x1 + 80, y0 + 3 * dy);
|
||||
getdisplay().print(msgCount);
|
||||
|
||||
// Wifi state
|
||||
getdisplay().setCursor(x0, y1 + 0 * dy);
|
||||
getdisplay().print("WiFi:");
|
||||
|
||||
getdisplay().setCursor(x0, y1 + 1 * dy);
|
||||
getdisplay().print("Access point:");
|
||||
getdisplay().setCursor(x0 + 120, y1 + 1 * dy);
|
||||
getdisplay().print(commonData->status.wifiApOn ? "on" : "off");
|
||||
|
||||
getdisplay().setCursor(x0, y1 + 2 * dy);
|
||||
getdisplay().print("SSID:");
|
||||
getdisplay().setCursor(x0 + 120, y1 + 2 * dy);
|
||||
getdisplay().print(systemName);
|
||||
|
||||
getdisplay().setCursor(x0, y1 + 3 * dy);
|
||||
getdisplay().print("IP address:");
|
||||
getdisplay().setCursor(x0 + 120, y1 + 3 * dy);
|
||||
getdisplay().print(commonData->status.wifiApIp);
|
||||
|
||||
getdisplay().setCursor(x0, y1 + 4 * dy + 5);
|
||||
getdisplay().print("Client WiFi:");
|
||||
getdisplay().setCursor(x0 + 120, y1 + 4 * dy + 5);
|
||||
getdisplay().print(commonData->status.wifiClientOn ? "on" : "off");
|
||||
|
||||
getdisplay().setCursor(x0, y1 + 5 * dy + 5);
|
||||
getdisplay().print("SSID:");
|
||||
getdisplay().setCursor(x0 + 120, y1 + 5 * dy + 5);
|
||||
getdisplay().print(commonData->status.wifiClientSSID);
|
||||
|
||||
getdisplay().setCursor(x0, y1 + 6 * dy + 5);
|
||||
getdisplay().print("IP address:");
|
||||
getdisplay().setCursor(x0+ 120, y1 + 6 * dy + 5);
|
||||
getdisplay().print(commonData->status.wifiClientIp);
|
||||
|
||||
displayWifiBarcode(systemName, apPasswd, 320, y1, 2);
|
||||
}
|
||||
|
||||
void displayModeSDCard() {
|
||||
|
||||
// SD Card info
|
||||
@@ -366,7 +471,7 @@ private:
|
||||
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(8, 48);
|
||||
getdisplay().print("SD Card info");
|
||||
getdisplay().print("SD Card Info");
|
||||
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(x0, y0);
|
||||
@@ -511,6 +616,8 @@ public:
|
||||
homelat = common.config->getString(common.config->homeLAT).toDouble();
|
||||
homelon = common.config->getString(common.config->homeLON).toDouble();
|
||||
flashLED = common.config->getString(common.config->flashLED);
|
||||
systemName = common.config->getString(common.config->systemName);
|
||||
apPasswd = common.config->getString(common.config->apPassword);
|
||||
}
|
||||
|
||||
void setupKeys() {
|
||||
@@ -596,6 +703,30 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void displayWifiBarcode(String ssid, String passwd, uint16_t x, uint16_t y, uint16_t s) {
|
||||
// Barcode for wifi access point
|
||||
// x, y is top left corner
|
||||
// s is pixel size of a single box
|
||||
|
||||
QRCode qrcode;
|
||||
uint8_t qrcodeData[qrcode_getBufferSize(4)];
|
||||
String text = "WIFI:S:" + String(ssid) + ";T:WPA;P:" + String(passwd) + ";;"; // Content for QR code: "WIFI:S:mySSID;T:WPA;P:myPASSWORD;;"
|
||||
const char *qrcodecontent = text.c_str();
|
||||
|
||||
qrcode_initText(&qrcode, qrcodeData, 4, 0, qrcodecontent);
|
||||
int16_t x0 = x;
|
||||
for (uint8_t j = 0; j < qrcode.size; j++) {
|
||||
for (uint8_t i = 0; i < qrcode.size; i++) {
|
||||
if (qrcode_getModule(&qrcode, i, j)) {
|
||||
getdisplay().fillRect(x, y, s, s, commonData->fgcolor);
|
||||
}
|
||||
x += s;
|
||||
}
|
||||
y += s;
|
||||
x = x0;
|
||||
}
|
||||
}
|
||||
|
||||
void displayNew(PageData &pageData) {
|
||||
#ifdef BOARD_OBP60S3
|
||||
// Clear optical warning
|
||||
@@ -645,6 +776,9 @@ public:
|
||||
case 'S':
|
||||
displayModeSettings();
|
||||
break;
|
||||
case 'W':
|
||||
displayModeNetwork();
|
||||
break;
|
||||
case 'C':
|
||||
displayModeConfig();
|
||||
break;
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
|
||||
class PageThreeValues : public Page
|
||||
{
|
||||
private:
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
|
||||
public:
|
||||
PageThreeValues(CommonData &common){
|
||||
commonData = &common;
|
||||
@@ -24,6 +29,9 @@ class PageThreeValues : public Page
|
||||
GwConfigHandler *config = commonData->config;
|
||||
GwLog *logger = commonData->logger;
|
||||
|
||||
int valueX, valueY;
|
||||
int DsegFontSize;
|
||||
|
||||
// Old values for hold function
|
||||
static String svalue1old = "";
|
||||
static String unit1old = "";
|
||||
@@ -33,11 +41,10 @@ class PageThreeValues : public Page
|
||||
static String unit3old = "";
|
||||
|
||||
// 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);
|
||||
bool smallDecimals = config->getBool(config->smallDecimals);
|
||||
|
||||
// Get boat values #1
|
||||
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
|
||||
@@ -101,25 +108,26 @@ class PageThreeValues : public Page
|
||||
}
|
||||
|
||||
// Switch font if format for any values
|
||||
valueX = 380;
|
||||
if(bvalue1->getFormat() == "formatLatitude" || bvalue1->getFormat() == "formatLongitude"){
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(50, 90);
|
||||
valueY = 90;
|
||||
DsegFontSize = 20;
|
||||
}
|
||||
else if(bvalue1->getFormat() == "formatTime" || bvalue1->getFormat() == "formatDate"){
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(170, 68);
|
||||
valueY = 80;
|
||||
DsegFontSize = 20;
|
||||
}
|
||||
else{
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(180, 90);
|
||||
valueY = 90;
|
||||
DsegFontSize = 30;
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue1); // Real value as formated string
|
||||
printBoatValue(svalue1, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue1old); // Old value as formated string
|
||||
printBoatValue(svalue1old, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Old value as formated string
|
||||
}
|
||||
if(valid1 == true){
|
||||
svalue1old = svalue1; // Save the old value
|
||||
@@ -150,24 +158,30 @@ class PageThreeValues : public Page
|
||||
|
||||
// Switch font if format for any values
|
||||
if(bvalue2->getFormat() == "formatLatitude" || bvalue2->getFormat() == "formatLongitude"){
|
||||
valueY = 180;
|
||||
DsegFontSize = 20;
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(50, 180);
|
||||
}
|
||||
else if(bvalue2->getFormat() == "formatTime" || bvalue2->getFormat() == "formatDate"){
|
||||
valueY = 170;
|
||||
DsegFontSize = 20;
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(170, 158);
|
||||
}
|
||||
else{
|
||||
valueY = 180;
|
||||
DsegFontSize = 30;
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(180, 180);
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue2); // Real value as formated string
|
||||
printBoatValue(svalue2, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue2old); // Old value as formated string
|
||||
printBoatValue(svalue2old, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Real value as formated string
|
||||
}
|
||||
if(valid2 == true){
|
||||
svalue2old = svalue2; // Save the old value
|
||||
@@ -198,24 +212,24 @@ class PageThreeValues : public Page
|
||||
|
||||
// Switch font if format for any values
|
||||
if(bvalue3->getFormat() == "formatLatitude" || bvalue3->getFormat() == "formatLongitude"){
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(50, 270);
|
||||
valueY = 270;
|
||||
DsegFontSize = 20;
|
||||
}
|
||||
else if(bvalue3->getFormat() == "formatTime" || bvalue3->getFormat() == "formatDate"){
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(170, 248);
|
||||
valueY = 260;
|
||||
DsegFontSize = 20;
|
||||
}
|
||||
else{
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
getdisplay().setCursor(180, 270);
|
||||
valueY = 270;
|
||||
DsegFontSize = 30;
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue3); // Real value as formated string
|
||||
printBoatValue(svalue3, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Real value as formated string
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue3old); // Old value as formated string
|
||||
printBoatValue(svalue3old, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Real value as formated string
|
||||
}
|
||||
if(valid3 == true){
|
||||
svalue3old = svalue3; // Save the old value
|
||||
|
||||
@@ -20,17 +20,6 @@ private:
|
||||
HALF
|
||||
};
|
||||
|
||||
static constexpr char HORIZONTAL = 'H';
|
||||
static constexpr char VERTICAL = 'V';
|
||||
static constexpr int8_t FULL_SIZE = 0;
|
||||
static constexpr int8_t HALF_SIZE_TOP = 1;
|
||||
static constexpr int8_t HALF_SIZE_BOTTOM = 2;
|
||||
|
||||
static constexpr bool PRNT_NAME = true;
|
||||
static constexpr bool NO_PRNT_NAME = false;
|
||||
static constexpr bool PRNT_VALUE = true;
|
||||
static constexpr bool NO_PRNT_VALUE = false;
|
||||
|
||||
static constexpr int YOFFSET = 130; // y offset for display of 2nd boat value
|
||||
|
||||
int width; // Screen width
|
||||
@@ -45,8 +34,11 @@ private:
|
||||
bool useSimuData;
|
||||
bool holdValues;
|
||||
String flashLED;
|
||||
String backlightMode;
|
||||
String tempFormat;
|
||||
bool smallDecimals;
|
||||
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
|
||||
// Data buffer pointer (owned by HstryBuffers)
|
||||
static constexpr int NUMVALUES = 2; // two data values in this page
|
||||
@@ -60,8 +52,10 @@ private:
|
||||
// display data values in display <mode> [FULL|HALF]
|
||||
void showData(const std::vector<GwApi::BoatValue*>& bValue, DisplayMode mode)
|
||||
{
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
int valueX, valueY;
|
||||
int DsegFontSize;
|
||||
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
int numValues = bValue.size(); // do we have to handle 1 or 2 values?
|
||||
|
||||
for (int i = 0; i < numValues; i++) {
|
||||
@@ -89,22 +83,23 @@ private:
|
||||
}
|
||||
|
||||
// Switch font depending on value format and adjust position
|
||||
valueX = 380;
|
||||
if (bValue[i]->getFormat() == "formatLatitude" || bValue[i]->getFormat() == "formatLongitude") {
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(50, 125 + yOffset);
|
||||
valueY = 125 + yOffset;
|
||||
DsegFontSize = 20;
|
||||
} else if (bValue[i]->getFormat() == "formatTime" || bValue[i]->getFormat() == "formatDate") {
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt8b);
|
||||
getdisplay().setCursor(170, 105 + yOffset);
|
||||
valueY = 105 + yOffset;
|
||||
DsegFontSize = 20;
|
||||
} else { // Default font for other formats
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic42pt7b);
|
||||
getdisplay().setCursor(180, 125 + yOffset);
|
||||
valueY = 125 + yOffset;
|
||||
DsegFontSize = 42;
|
||||
}
|
||||
|
||||
// Show bus data
|
||||
if (!holdValues || useSimuData) {
|
||||
getdisplay().print(sValue); // Real value as formated string
|
||||
printBoatValue(sValue, valueX, valueY, RIGHT, DsegFontSize, smallDecimals);
|
||||
} else {
|
||||
getdisplay().print(sValueOld[i]); // Old value as formated string
|
||||
printBoatValue(sValueOld[i], valueX, valueY, RIGHT, DsegFontSize, smallDecimals);
|
||||
}
|
||||
|
||||
if (valid == true) {
|
||||
@@ -127,14 +122,13 @@ public:
|
||||
|
||||
width = getdisplay().width(); // Screen width
|
||||
height = getdisplay().height(); // Screen height
|
||||
getdisplay().setTextWrap(false);
|
||||
|
||||
// Get config data
|
||||
// lengthformat = commonData->config->getString(commonData->config->lengthFormat);
|
||||
useSimuData = commonData->config->getBool(commonData->config->useSimuData);
|
||||
holdValues = commonData->config->getBool(commonData->config->holdvalues);
|
||||
flashLED = commonData->config->getString(commonData->config->flashLED);
|
||||
backlightMode = commonData->config->getString(commonData->config->backlight);
|
||||
tempFormat = commonData->config->getString(commonData->config->tempFormat); // [K|°C|°F]
|
||||
smallDecimals = commonData->config->getBool(commonData->config->smallDecimals);
|
||||
}
|
||||
|
||||
virtual void setupKeys()
|
||||
@@ -246,7 +240,7 @@ public:
|
||||
dataHstryBuf[i] = pageData.hstryBuffers->getBuffer(bValName);
|
||||
|
||||
if (dataHstryBuf[i]) {
|
||||
dataChart[i].reset(new Chart(*dataHstryBuf[i], Chart::dfltChrtDta[bValFormat].range, *commonData, useSimuData));
|
||||
dataChart[i].reset(new Chart(*dataHstryBuf[i], *commonData, useSimuData));
|
||||
LOG_DEBUG(GwLog::DEBUG, "PageTwoValues: Created chart object %d for %s", i, bValName.c_str());
|
||||
} else {
|
||||
LOG_DEBUG(GwLog::DEBUG, "PageTwoValues: No chart object available for %s", bValName.c_str());
|
||||
@@ -266,12 +260,13 @@ public:
|
||||
bValue.push_back(pageData.values[0]); // Page boat data element 1
|
||||
bValue.push_back(pageData.values[1]); // Page boat data element 2
|
||||
|
||||
#ifdef BOARD_OBP60S3
|
||||
// Optical warning by limit violation (unused)
|
||||
if (String(flashLED) == "Limit Violation") {
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
|
||||
#endif
|
||||
if (bValue[0] == NULL && bValue[1] == NULL)
|
||||
return PAGE_OK; // no data, no page to display
|
||||
|
||||
@@ -283,35 +278,43 @@ public:
|
||||
|
||||
displaySetPartialWindow(0, 0, width, height); // Set partial update
|
||||
|
||||
if (pageMode == VALUES || (dataHstryBuf[0] == nullptr && dataHstryBuf[1] == nullptr)) {
|
||||
for (int i = 0; i < NUMVALUES; i++) {
|
||||
if (dataChart[i]) { // Check only if dataChart object exists at all
|
||||
if (!dataChart[i]->isValid()) {
|
||||
dataChart[i]->init(); // try late initialization if chart object could not be properly initialized earlier due to missing boat data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pageMode == VALUES || (dataChart[0] == nullptr && dataChart[1] == nullptr)) {
|
||||
// show only data value; ignore other pageMode options if no chart supported boat data history buffer is available
|
||||
showData(bValue, FULL);
|
||||
|
||||
} else if (pageMode == VAL1_CHART) { // show data value 1 and chart
|
||||
showData({ bValue[0] }, HALF);
|
||||
if (dataChart[0]) {
|
||||
dataChart[0]->showChrt(HORIZONTAL, HALF_SIZE_BOTTOM, dataIntv, NO_PRNT_NAME, NO_PRNT_VALUE, *bValue[0]);
|
||||
dataChart[0]->showChrt(Chart::HORIZONTAL, Chart::HALF_SIZE_RIGHT_BOTTOM, dataIntv, Chart::NO_PRNT_NAME, Chart::NO_PRNT_VALUE, *bValue[0]);
|
||||
}
|
||||
|
||||
} else if (pageMode == VAL2_CHART) { // show data value 2 and chart
|
||||
showData({ bValue[1] }, HALF);
|
||||
if (dataChart[1]) {
|
||||
dataChart[1]->showChrt(HORIZONTAL, HALF_SIZE_BOTTOM, dataIntv, NO_PRNT_NAME, NO_PRNT_VALUE, *bValue[1]);
|
||||
dataChart[1]->showChrt(Chart::HORIZONTAL, Chart::HALF_SIZE_RIGHT_BOTTOM, dataIntv, Chart::NO_PRNT_NAME, Chart::NO_PRNT_VALUE, *bValue[1]);
|
||||
}
|
||||
|
||||
} else if (pageMode == CHARTS) { // show both data charts
|
||||
if (dataChart[0]) {
|
||||
if (dataChart[1]) {
|
||||
dataChart[0]->showChrt(HORIZONTAL, HALF_SIZE_TOP, dataIntv, PRNT_NAME, PRNT_VALUE, *bValue[0]);
|
||||
dataChart[0]->showChrt(Chart::HORIZONTAL, Chart::HALF_SIZE_LEFT_TOP, dataIntv, Chart::PRNT_NAME, Chart::PRNT_VALUE, *bValue[0]);
|
||||
} else {
|
||||
dataChart[0]->showChrt(HORIZONTAL, FULL_SIZE, dataIntv, PRNT_NAME, PRNT_VALUE, *bValue[0]);
|
||||
dataChart[0]->showChrt(Chart::HORIZONTAL, Chart::FULL_SIZE, dataIntv, Chart::PRNT_NAME, Chart::PRNT_VALUE, *bValue[0]);
|
||||
}
|
||||
}
|
||||
if (dataChart[1]) {
|
||||
if (dataChart[0]) {
|
||||
dataChart[1]->showChrt(HORIZONTAL, HALF_SIZE_BOTTOM, dataIntv, PRNT_NAME, PRNT_VALUE, *bValue[1]);
|
||||
dataChart[1]->showChrt(Chart::HORIZONTAL, Chart::HALF_SIZE_RIGHT_BOTTOM, dataIntv, Chart::PRNT_NAME, Chart::PRNT_VALUE, *bValue[1]);
|
||||
} else {
|
||||
dataChart[1]->showChrt(HORIZONTAL, FULL_SIZE, dataIntv, PRNT_NAME, PRNT_VALUE, *bValue[1]);
|
||||
dataChart[1]->showChrt(Chart::HORIZONTAL, Chart::FULL_SIZE, dataIntv, Chart::PRNT_NAME, Chart::PRNT_VALUE, *bValue[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,10 @@ bool trend = true; // Trend indicator [0|1], 0=off, 1=on
|
||||
double raw = 0;
|
||||
char mode = 'D'; // display mode (A)nalog | (D)igital
|
||||
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
|
||||
public:
|
||||
PageVoltage(CommonData &common){
|
||||
commonData = &common;
|
||||
@@ -110,8 +114,10 @@ public:
|
||||
String batVoltage = config->getString(config->batteryVoltage);
|
||||
String batType = config->getString(config->batteryType);
|
||||
String backlightMode = config->getString(config->backlight);
|
||||
bool smallDecimals = config->getBool(config->smallDecimals);
|
||||
|
||||
double value1 = 0;
|
||||
String svalue = "---";
|
||||
double valueTrend = 0; // Average over 10 values
|
||||
|
||||
// Get voltage value
|
||||
@@ -234,36 +240,12 @@ public:
|
||||
printAvg(average, 320, 84, true);
|
||||
|
||||
// Reading bus data or using simulation data
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic60pt7b);
|
||||
getdisplay().setCursor(20, 240);
|
||||
if(simulation == true){
|
||||
if(batVoltage == "12V"){
|
||||
value1 = 12.0;
|
||||
}
|
||||
if(batVoltage == "24V"){
|
||||
value1 = 24.0;
|
||||
}
|
||||
value1 += float(random(0, 5)) / 10; // Simulation data
|
||||
getdisplay().print(value1,1);
|
||||
}
|
||||
else{
|
||||
// Check for valid real data, display also if hold values activated
|
||||
if(valid1 == true || holdvalues == true){
|
||||
// Resolution switching
|
||||
if(value1 < 10){
|
||||
getdisplay().print(value1,2);
|
||||
}
|
||||
if(value1 >= 10 && value1 < 100){
|
||||
getdisplay().print(value1,1);
|
||||
}
|
||||
if(value1 >= 100){
|
||||
getdisplay().print(value1,0);
|
||||
}
|
||||
}
|
||||
else{
|
||||
getdisplay().print("---"); // Missing bus data
|
||||
}
|
||||
svalue = formatValue(value1, String("formatXdr:U:V"), *commonData);
|
||||
} else {
|
||||
svalue = "---"; // Missing bus data
|
||||
}
|
||||
printBoatValue(svalue, 300, 240, RIGHT, 60, smallDecimals);
|
||||
|
||||
// Show trend indicator
|
||||
if(trend == true){
|
||||
|
||||
@@ -0,0 +1,280 @@
|
||||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Extensions.h"
|
||||
#include "OBPDataOperations.h"
|
||||
#include "OBPcharts.h"
|
||||
|
||||
class PageWeather : public Page {
|
||||
private:
|
||||
GwLog* logger;
|
||||
|
||||
enum PageMode {
|
||||
VAL_CHART,
|
||||
CHART
|
||||
};
|
||||
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
|
||||
static constexpr int XOFFSET = 133; // x offset for display of boat values
|
||||
|
||||
int width; // Screen width
|
||||
int height; // Screen height
|
||||
|
||||
bool keylock = false; // Keylock
|
||||
PageMode pageMode = VAL_CHART; // Page display mode
|
||||
int8_t dataIntv = 1; // Update interval for barograph history chart:
|
||||
// (1)|(3)|(6)|(12)|(24) x 60 min. for 1, 3, 6, 12, 24 hours history chart
|
||||
|
||||
// String lengthformat;
|
||||
bool useSimuData;
|
||||
bool holdValues;
|
||||
String flashLED;
|
||||
bool smallDecimals;
|
||||
|
||||
static constexpr int NUMVALUES = 4; // number of boat values used on this page
|
||||
static constexpr int NUMCHARTS = 1; // one data buffer used on this page
|
||||
|
||||
// Data buffer pointer (owned by HstryBuffers)
|
||||
RingBuffer<uint16_t>* dataHstryBuf[NUMCHARTS] = { nullptr };
|
||||
std::unique_ptr<Chart> dataChart[NUMCHARTS]; // Chart object
|
||||
|
||||
// Old values for hold function
|
||||
String sValueOld[NUMVALUES] = { "", "", "", "" };
|
||||
String unitOld[NUMVALUES] = { "", "", "", "" };
|
||||
|
||||
// display data values in display mode <HALF>
|
||||
void showData(const std::vector<GwApi::BoatValue*>& bValue)
|
||||
{
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
|
||||
int numValues = bValue.size(); // How many values do we have to handle? We will ignore value no. 1
|
||||
|
||||
for (int i = 1; i < numValues; i++) {
|
||||
String name = xdrDelete(bValue[i]->getName()); // Value name
|
||||
name = name.substring(0, 7); // String length limit for value name
|
||||
double value = bValue[i]->value; // Value as double in SI unit
|
||||
bool valid = bValue[i]->valid; // Valid information
|
||||
String sValue = formatValue(bValue[i], *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
String unit = formatValue(bValue[i], *commonData).unit; // Unit of value
|
||||
|
||||
int xOffset = XOFFSET * (i - 1);
|
||||
|
||||
// Print name
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(5 + xOffset, 213);
|
||||
getdisplay().print(name); // name
|
||||
|
||||
// Print unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(5 + xOffset, 229);
|
||||
if (holdValues) {
|
||||
getdisplay().print(unitOld[i]); // name
|
||||
} else {
|
||||
getdisplay().print(unit); // name
|
||||
}
|
||||
|
||||
// Print value
|
||||
int valueX = XOFFSET * i - 5;
|
||||
int valueY = 275;
|
||||
int DsegFontSize = 20;
|
||||
if (!holdValues || useSimuData) {
|
||||
printBoatValue(sValue, valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Real value as formated string
|
||||
} else {
|
||||
printBoatValue(sValueOld[i], valueX, valueY, RIGHT, DsegFontSize, smallDecimals); // Old value as formated string
|
||||
}
|
||||
|
||||
if (valid) { // Save value for hold function
|
||||
sValueOld[i] = sValue;
|
||||
unitOld[i] = unit;
|
||||
}
|
||||
}
|
||||
|
||||
// print lines for data separation of bottom data values
|
||||
getdisplay().fillRect(0, 191, 400, 2, commonData->fgcolor); // horizontal line
|
||||
getdisplay().fillRect(133, 192, 2, 84, commonData->fgcolor); // vertical lines
|
||||
getdisplay().fillRect(266, 192, 2, 84, commonData->fgcolor);
|
||||
}
|
||||
|
||||
public:
|
||||
PageWeather(CommonData& common)
|
||||
{
|
||||
commonData = &common;
|
||||
logger = commonData->logger;
|
||||
LOG_DEBUG(GwLog::LOG, "Instantiate PageWeather");
|
||||
|
||||
width = getdisplay().width(); // Screen width
|
||||
height = getdisplay().height(); // Screen height
|
||||
|
||||
// Get config data
|
||||
useSimuData = commonData->config->getBool(commonData->config->useSimuData);
|
||||
holdValues = commonData->config->getBool(commonData->config->holdvalues);
|
||||
flashLED = commonData->config->getString(commonData->config->flashLED);
|
||||
smallDecimals = commonData->config->getBool(commonData->config->smallDecimals);
|
||||
}
|
||||
|
||||
virtual void setupKeys()
|
||||
{
|
||||
Page::setupKeys();
|
||||
|
||||
#if defined BOARD_OBP60S3
|
||||
constexpr int ZOOM_KEY = 4;
|
||||
#elif defined BOARD_OBP40S3
|
||||
constexpr int ZOOM_KEY = 1;
|
||||
#endif
|
||||
|
||||
if (dataHstryBuf) { // show "Mode" key only if chart-supported boat data type is available
|
||||
commonData->keydata[0].label = "MODE";
|
||||
commonData->keydata[ZOOM_KEY].label = "ZOOM";
|
||||
} else {
|
||||
commonData->keydata[0].label = "";
|
||||
commonData->keydata[ZOOM_KEY].label = "";
|
||||
}
|
||||
}
|
||||
|
||||
// Key functions
|
||||
virtual int handleKey(int key)
|
||||
{
|
||||
if (dataHstryBuf) { // if boat data type supports charts
|
||||
|
||||
// Set page mode: value/half chart | full chart
|
||||
if (key == 1) {
|
||||
switch (pageMode) {
|
||||
case VAL_CHART:
|
||||
pageMode = CHART;
|
||||
break;
|
||||
case CHART:
|
||||
pageMode = VAL_CHART;
|
||||
break;
|
||||
}
|
||||
setupKeys(); // Adjust key definition depending on <pageMode> and chart-supported boat data type
|
||||
return 0; // Commit the key
|
||||
}
|
||||
|
||||
// Set time frame to show for chart
|
||||
#if defined BOARD_OBP60S3
|
||||
if (key == 5) {
|
||||
#elif defined BOARD_OBP40S3
|
||||
if (key == 2) {
|
||||
#endif
|
||||
if (dataIntv == 1) {
|
||||
dataIntv = 2;
|
||||
} else if (dataIntv == 2) {
|
||||
dataIntv = 4;
|
||||
} else if (dataIntv == 4) {
|
||||
dataIntv = 8;
|
||||
} else if (dataIntv == 8) {
|
||||
dataIntv = 12;
|
||||
} else {
|
||||
dataIntv = 1;
|
||||
}
|
||||
return 0; // Commit the key
|
||||
}
|
||||
}
|
||||
|
||||
// Keylock function
|
||||
if (key == 11) { // Code for keylock
|
||||
commonData->keylock = !commonData->keylock;
|
||||
return 0; // Commit the key
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
virtual void displayNew(PageData& pageData)
|
||||
{
|
||||
#ifdef BOARD_OBP60S3
|
||||
// Clear optical warning
|
||||
if (flashLED == "Limit Violation") {
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < NUMCHARTS; i++) {
|
||||
if (!dataChart[i]) { // Create chart objects if they don't exist
|
||||
|
||||
GwApi::BoatValue* bValue = pageData.values[i]; // Page boat data element
|
||||
String bValName = bValue->getName(); // Value name
|
||||
String bValFormat = bValue->getFormat(); // Value format
|
||||
|
||||
dataHstryBuf[i] = pageData.hstryBuffers->getBuffer(bValName);
|
||||
|
||||
if (dataHstryBuf[i]) {
|
||||
dataChart[i].reset(new Chart(*dataHstryBuf[i], *commonData, useSimuData));
|
||||
LOG_DEBUG(GwLog::DEBUG, "PageWeather: Created chart object %d for %s, format: %s", i, bValName.c_str(), dataHstryBuf[i]->getFormat().c_str());
|
||||
} else {
|
||||
LOG_DEBUG(GwLog::DEBUG, "PageWeather: No chart object available for %s", bValName.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int displayPage(PageData& pageData)
|
||||
{
|
||||
|
||||
LOG_DEBUG(GwLog::LOG, "Display PageWeather");
|
||||
|
||||
// Get latest boat values for page
|
||||
std::vector<GwApi::BoatValue*> bValue;
|
||||
for (int i = 0; i < NUMVALUES; i++) {
|
||||
bValue.push_back(pageData.values[i]);
|
||||
}
|
||||
|
||||
if (bValue[0] == NULL && bValue[1] == NULL && bValue[2] == NULL && bValue[3] == NULL) {
|
||||
return PAGE_OK; // no data, no page to display
|
||||
}
|
||||
if (dataHstryBuf == nullptr) { // no buffer for main boat data item, no page display
|
||||
return PAGE_OK;
|
||||
}
|
||||
|
||||
LOG_DEBUG(GwLog::DEBUG, "PageWeather: printing #1: %s, %.3f, %s, #2: %s, %.3f, %s, #3: %s, %.3f, %s, #4: %s, %.3f, %s",
|
||||
bValue[0]->getName().c_str(), bValue[0]->value, bValue[0]->getFormat().c_str(), bValue[1]->getName().c_str(), bValue[1]->value, bValue[1]->getFormat().c_str(),
|
||||
bValue[2]->getName().c_str(), bValue[2]->value, bValue[2]->getFormat().c_str(), bValue[3]->getName().c_str(), bValue[3]->value, bValue[3]->getFormat().c_str());
|
||||
|
||||
// Draw page
|
||||
//***********************************************************
|
||||
|
||||
displaySetPartialWindow(0, 0, width, height); // Set partial update
|
||||
|
||||
if (dataChart[0]) { // Check only if dataChart object exists at all
|
||||
if (!dataChart[0]->isValid()) {
|
||||
dataChart[0]->init(); // try late initialization if chart object could not be properly initialized earlier due to missing boat data
|
||||
}
|
||||
}
|
||||
|
||||
if (pageMode == VAL_CHART) {
|
||||
if (dataChart[0]) {
|
||||
dataChart[0]->showChrt(Chart::HORIZONTAL, Chart::TWO_THIRD_TOP, dataIntv, Chart::PRNT_NAME, Chart::PRNT_VALUE, *bValue[0]);
|
||||
}
|
||||
showData(bValue);
|
||||
|
||||
} else if (pageMode == CHART && dataChart[0]) { // show only data chart, but that has to exist
|
||||
dataChart[0]->showChrt(Chart::HORIZONTAL, Chart::FULL_SIZE, dataIntv, Chart::PRNT_NAME, Chart::PRNT_VALUE, *bValue[0]);
|
||||
}
|
||||
|
||||
return PAGE_UPDATE;
|
||||
};
|
||||
};
|
||||
|
||||
static Page* createPage(CommonData& common)
|
||||
{
|
||||
return new PageWeather(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 registerPageWeather(
|
||||
"Weather", // Page name
|
||||
createPage, // Action
|
||||
4, // Number of bus values depends on selection in Web configuration (air baro pressure, air temperature, humidity, true wind speed)
|
||||
{ }, // Bus values we need in the page
|
||||
true // Show display header on/off
|
||||
);
|
||||
#endif
|
||||
+11
-14
@@ -213,6 +213,10 @@ static unsigned char front_bits[] PROGMEM = {
|
||||
|
||||
class PageWind : public Page
|
||||
{
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
|
||||
bool keylock = false; // Keylock
|
||||
int8_t lp = 80; // Pointer length
|
||||
char mode = 'N'; // page mode (N)ormal | (L)ens | e(X)ample
|
||||
@@ -306,11 +310,10 @@ public:
|
||||
static String unit2old = "";
|
||||
|
||||
// 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);
|
||||
bool smallDecimals = config->getBool(config->smallDecimals);
|
||||
|
||||
GwApi::BoatValue *bvalue1; // Value 1 for speed on top
|
||||
GwApi::BoatValue *bvalue2; // Value 2 for angle on bottom
|
||||
@@ -512,17 +515,14 @@ public:
|
||||
}
|
||||
|
||||
// Wind speed as decimal number
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(150, 250);
|
||||
if (holdvalues == false) {
|
||||
getdisplay().print(svalue1);
|
||||
printBoatValue(svalue1, 260, 250, RIGHT, 26, smallDecimals);
|
||||
} else {
|
||||
getdisplay().print(svalue1old);
|
||||
printBoatValue(svalue1old, 260, 250, RIGHT, 26, smallDecimals);
|
||||
}
|
||||
// unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(220, 265);
|
||||
getdisplay().print("kts");
|
||||
drawTextRalign(260, 265, unit1);
|
||||
}
|
||||
else {
|
||||
// Normal mode
|
||||
@@ -584,17 +584,14 @@ public:
|
||||
}
|
||||
|
||||
// Wind speed as decimal number
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(150, 250);
|
||||
if (holdvalues == false) {
|
||||
getdisplay().print(svalue1);
|
||||
printBoatValue(svalue1, 260, 250, RIGHT, 26, smallDecimals);
|
||||
} else {
|
||||
getdisplay().print(svalue1old);
|
||||
printBoatValue(svalue1old, 260, 250, RIGHT, 26, smallDecimals);
|
||||
}
|
||||
// unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(220, 265);
|
||||
getdisplay().print("kts");
|
||||
drawTextRalign(260, 265, unit1);
|
||||
|
||||
// Wind pointer (angle)
|
||||
if (bvalue2->valid or simulation) {
|
||||
|
||||
@@ -11,28 +11,17 @@ class PageWindPlot : public Page {
|
||||
private:
|
||||
GwLog* logger;
|
||||
|
||||
enum ChartMode {
|
||||
enum PageMode {
|
||||
DIRECTION,
|
||||
SPEED,
|
||||
BOTH
|
||||
};
|
||||
|
||||
static constexpr char HORIZONTAL = 'H';
|
||||
static constexpr char VERTICAL = 'V';
|
||||
static constexpr int8_t FULL_SIZE = 0;
|
||||
static constexpr int8_t HALF_SIZE_LEFT = 1;
|
||||
static constexpr int8_t HALF_SIZE_RIGHT = 2;
|
||||
|
||||
static constexpr bool PRNT_NAME = true;
|
||||
static constexpr bool NO_PRNT_NAME = false;
|
||||
static constexpr bool PRNT_VALUE = true;
|
||||
static constexpr bool NO_PRNT_VALUE = false;
|
||||
|
||||
int width; // Screen width
|
||||
int height; // Screen height
|
||||
|
||||
bool keylock = false; // Keylock
|
||||
ChartMode chrtMode = DIRECTION;
|
||||
PageMode chrtMode = DIRECTION;
|
||||
bool showTruW = true; // Show true wind or apparent wind in chart area
|
||||
bool oldShowTruW = false; // remember recent user selection of wind data type
|
||||
|
||||
@@ -168,10 +157,10 @@ public:
|
||||
twsHstry = pageData.hstryBuffers->getBuffer("TWS");
|
||||
|
||||
if (twdHstry) {
|
||||
twdChart.reset(new Chart(*twdHstry, Chart::dfltChrtDta["formatCourse"].range, *commonData, useSimuData));
|
||||
twdChart.reset(new Chart(*twdHstry, *commonData, useSimuData));
|
||||
}
|
||||
if (twsHstry) {
|
||||
twsChart.reset(new Chart(*twsHstry, Chart::dfltChrtDta["formatKnots"].range, *commonData, useSimuData));
|
||||
twsChart.reset(new Chart(*twsHstry, *commonData, useSimuData));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,10 +169,10 @@ public:
|
||||
awsHstry = pageData.hstryBuffers->getBuffer("AWS");
|
||||
|
||||
if (awdHstry) {
|
||||
awdChart.reset(new Chart(*awdHstry, Chart::dfltChrtDta["formatCourse"].range, *commonData, useSimuData));
|
||||
awdChart.reset(new Chart(*awdHstry, *commonData, useSimuData));
|
||||
}
|
||||
if (awsHstry) {
|
||||
awsChart.reset(new Chart(*awsHstry, Chart::dfltChrtDta["formatKnots"].range, *commonData, useSimuData));
|
||||
awsChart.reset(new Chart(*awsHstry, *commonData, useSimuData));
|
||||
}
|
||||
if (twdHstry && twsHstry && awdHstry && awsHstry) {
|
||||
LOG_DEBUG(GwLog::DEBUG, "PageWindPlot: Created wind charts");
|
||||
@@ -226,7 +215,7 @@ public:
|
||||
|
||||
if (chrtMode == DIRECTION) {
|
||||
if (wdChart) {
|
||||
wdChart->showChrt(VERTICAL, FULL_SIZE, dataIntv, PRNT_NAME, PRNT_VALUE, *wdBVal);
|
||||
wdChart->showChrt(Chart::VERTICAL, Chart::FULL_SIZE, dataIntv, Chart::PRNT_NAME, Chart::PRNT_VALUE, *wdBVal);
|
||||
}
|
||||
|
||||
} else if (chrtMode == SPEED) {
|
||||
@@ -234,15 +223,15 @@ public:
|
||||
if (dataIntv == 8) {
|
||||
dataIntv = 1; // horizontal charts show max. 4 x 7 min. only; no factor 8 multiplier
|
||||
}
|
||||
wsChart->showChrt(HORIZONTAL, FULL_SIZE, dataIntv, PRNT_NAME, PRNT_VALUE, *wsBVal);
|
||||
wsChart->showChrt(Chart::HORIZONTAL, Chart::FULL_SIZE, dataIntv, Chart::PRNT_NAME, Chart::PRNT_VALUE, *wsBVal);
|
||||
}
|
||||
|
||||
} else if (chrtMode == BOTH) {
|
||||
if (wdChart) {
|
||||
wdChart->showChrt(VERTICAL, HALF_SIZE_LEFT, dataIntv, PRNT_NAME, PRNT_VALUE, *wdBVal);
|
||||
wdChart->showChrt(Chart::VERTICAL, Chart::HALF_SIZE_LEFT_TOP, dataIntv, Chart::NO_PRNT_NAME, Chart::PRNT_VALUE, *wdBVal);
|
||||
}
|
||||
if (wsChart) {
|
||||
wsChart->showChrt(VERTICAL, HALF_SIZE_RIGHT, dataIntv, PRNT_NAME, PRNT_VALUE, *wsBVal);
|
||||
wsChart->showChrt(Chart::VERTICAL, Chart::HALF_SIZE_RIGHT_BOTTOM, dataIntv, Chart::NO_PRNT_NAME, Chart::PRNT_VALUE, *wsBVal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,10 @@
|
||||
|
||||
class PageWindRose : public Page
|
||||
{
|
||||
int16_t lp = 80; // Pointer length
|
||||
private:
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
|
||||
public:
|
||||
PageWindRose(CommonData &common){
|
||||
@@ -27,6 +30,9 @@ public:
|
||||
GwConfigHandler *config = commonData->config;
|
||||
GwLog *logger = commonData->logger;
|
||||
|
||||
int valueX, valueY;
|
||||
int DsegFontSize;
|
||||
|
||||
static String svalue1old = "";
|
||||
static String unit1old = "";
|
||||
static String svalue2old = "";
|
||||
@@ -41,19 +47,18 @@ public:
|
||||
static String unit6old = "";
|
||||
|
||||
// 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);
|
||||
bool smallDecimals = config->getBool(config->smallDecimals);
|
||||
|
||||
// Get boat value for AWA
|
||||
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
|
||||
value1 = formatValue(bvalue1, *commonData).value;// Format only nesaccery for simulation data for pointer
|
||||
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
|
||||
if(valid1 == true){
|
||||
@@ -141,13 +146,10 @@ public:
|
||||
|
||||
// Set display in partial refresh mode
|
||||
displaySetPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
|
||||
// Show values AWA
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(10, 65);
|
||||
getdisplay().print(svalue1); // Value
|
||||
printBoatValue(svalue1, 101, 65, RIGHT, 20, smallDecimals); // value
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(10, 95);
|
||||
getdisplay().print(name1); // Name
|
||||
@@ -161,13 +163,11 @@ public:
|
||||
getdisplay().print(unit1old); // Unit
|
||||
}
|
||||
|
||||
// Horizintal separator left
|
||||
// Horizontal separator left
|
||||
getdisplay().fillRect(0, 149, 60, 3, commonData->fgcolor);
|
||||
|
||||
// Show values AWS
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(10, 270);
|
||||
getdisplay().print(svalue2); // Value
|
||||
printBoatValue(svalue2, 101, 270, RIGHT, 20, smallDecimals); // value
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(10, 220);
|
||||
getdisplay().print(name2); // Name
|
||||
@@ -182,14 +182,7 @@ public:
|
||||
}
|
||||
|
||||
// Show values TWD
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(295, 65);
|
||||
if(valid3 == true){
|
||||
getdisplay().print(abs(value3 * 180 / PI), 0); // Value
|
||||
}
|
||||
else{
|
||||
getdisplay().print("---"); // Value
|
||||
}
|
||||
printBoatValue(svalue3, 391, 65, RIGHT, 20, smallDecimals); // value
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(335, 95);
|
||||
getdisplay().print(name3); // Name
|
||||
@@ -207,9 +200,7 @@ public:
|
||||
getdisplay().fillRect(340, 149, 80, 3, commonData->fgcolor);
|
||||
|
||||
// Show values TWS
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(295, 270);
|
||||
getdisplay().print(svalue4); // Value
|
||||
printBoatValue(svalue4, 391, 270, RIGHT, 20, smallDecimals); // value
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(335, 220);
|
||||
getdisplay().print(name4); // Name
|
||||
@@ -227,7 +218,7 @@ public:
|
||||
|
||||
// Draw wind rose
|
||||
int rInstrument = 110; // Radius of grafic instrument
|
||||
float pi = 3.141592;
|
||||
String sDegree;
|
||||
|
||||
getdisplay().fillCircle(200, 150, rInstrument + 10, commonData->fgcolor); // Outer circle
|
||||
getdisplay().fillCircle(200, 150, rInstrument + 7, commonData->bgcolor); // Outer circle
|
||||
@@ -237,56 +228,38 @@ public:
|
||||
for(int i=0; i<360; i=i+10)
|
||||
{
|
||||
// Scaling values
|
||||
float x = 200 + (rInstrument-30)*sin(i/180.0*pi); // x-coordinate dots
|
||||
float y = 150 - (rInstrument-30)*cos(i/180.0*pi); // y-coordinate cots
|
||||
const char *ii = "";
|
||||
switch (i)
|
||||
{
|
||||
case 0: ii="0"; break;
|
||||
case 30 : ii="30"; break;
|
||||
case 60 : ii="60"; break;
|
||||
case 90 : ii="90"; break;
|
||||
case 120 : ii="120"; break;
|
||||
case 150 : ii="150"; break;
|
||||
case 180 : ii="180"; break;
|
||||
case 210 : ii="210"; break;
|
||||
case 240 : ii="240"; break;
|
||||
case 270 : ii="270"; break;
|
||||
case 300 : ii="300"; break;
|
||||
case 330 : ii="330"; break;
|
||||
default: break;
|
||||
}
|
||||
float x = 200 + (rInstrument-30)*sin(i/180.0*M_PI); // x-coordinate dots
|
||||
float y = 150 - (rInstrument-30)*cos(i/180.0*M_PI); // y-coordinate cots
|
||||
|
||||
if(i % 30 == 0){
|
||||
// Print text centered on position x, y
|
||||
int16_t x1, y1; // Return values of getTextBounds
|
||||
uint16_t w, h; // Return values of getTextBounds
|
||||
displayGetTextBounds(ii, int(x), int(y), &x1, &y1, &w, &h); // Calc width of new string
|
||||
getdisplay().setCursor(x-w/2, y+h/2);
|
||||
if(i % 30 == 0){
|
||||
sDegree = String(i);
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().print(ii);
|
||||
}
|
||||
|
||||
// Draw sub scale with dots
|
||||
float x1c = 200 + rInstrument*sin(i/180.0*pi);
|
||||
float y1c = 150 - rInstrument*cos(i/180.0*pi);
|
||||
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
|
||||
float sinx=sin(i/180.0*pi);
|
||||
float cosx=cos(i/180.0*pi);
|
||||
displayGetTextBounds(sDegree, int(x), int(y), &x1, &y1, &w, &h); // Calc width of new string
|
||||
getdisplay().setCursor(x-w/2, y+h/2);
|
||||
getdisplay().print(sDegree);
|
||||
|
||||
// Draw sub scale with lines (two triangles)
|
||||
if(i % 30 == 0){
|
||||
float dx=2; // Line thickness = 2*dx+1
|
||||
float xx1 = -dx;
|
||||
float xx2 = +dx;
|
||||
float yy1 = -(rInstrument-10);
|
||||
float yy2 = -(rInstrument+10);
|
||||
float sinx = sin(i/180.0*M_PI);
|
||||
float cosx = cos(i/180.0*M_PI);
|
||||
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
|
||||
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
|
||||
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData->fgcolor);
|
||||
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
|
||||
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
|
||||
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData->fgcolor);
|
||||
} else {
|
||||
// Draw sub scale with dots
|
||||
float x1c = 200 + rInstrument*sin(i/180.0*M_PI);
|
||||
float y1c = 150 - rInstrument*cos(i/180.0*M_PI);
|
||||
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,9 +296,7 @@ public:
|
||||
//*******************************************************************************************
|
||||
|
||||
// Show values DBT
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
|
||||
getdisplay().setCursor(160, 200);
|
||||
getdisplay().print(svalue5); // Value
|
||||
printBoatValue(svalue5, 200, 200, CENTER, 16, smallDecimals); // value
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(190, 215);
|
||||
getdisplay().print(" ");
|
||||
@@ -337,9 +308,7 @@ public:
|
||||
}
|
||||
|
||||
// Show values STW
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
|
||||
getdisplay().setCursor(160, 130);
|
||||
getdisplay().print(svalue6); // Value
|
||||
printBoatValue(svalue6, 200, 130, CENTER, 16, smallDecimals); // value
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(190, 90);
|
||||
getdisplay().print(" ");
|
||||
|
||||
@@ -5,7 +5,10 @@
|
||||
|
||||
class PageWindRoseFlex : public Page
|
||||
{
|
||||
int16_t lp = 80; // Pointer length
|
||||
private:
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
char source = 'A'; // data source (A)pparent | (T)rue
|
||||
|
||||
public:
|
||||
@@ -42,6 +45,9 @@ public:
|
||||
GwConfigHandler *config = commonData->config;
|
||||
GwLog *logger = commonData->logger;
|
||||
|
||||
int valueX, valueY;
|
||||
int DsegFontSize;
|
||||
|
||||
static String svalue1old = "";
|
||||
static String unit1old = "";
|
||||
static String svalue2old = "";
|
||||
@@ -61,11 +67,10 @@ public:
|
||||
|
||||
|
||||
// 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);
|
||||
bool smallDecimals = config->getBool(config->smallDecimals);
|
||||
|
||||
GwApi::BoatValue *bvalue1; // Value 1 for angle
|
||||
GwApi::BoatValue *bvalue2; // Value 2 for speed
|
||||
@@ -79,6 +84,7 @@ public:
|
||||
String name1 = bvalue1->getName().c_str(); // Value name
|
||||
name1 = name1.substring(0, 6); // String length limit for value name
|
||||
double value1 = bvalue1->value; // Value as double in SI unit
|
||||
value1 = formatValue(bvalue1, *commonData).value;// Format only nesaccery for simulation data for pointer
|
||||
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
|
||||
@@ -97,9 +103,6 @@ public:
|
||||
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
|
||||
if (simulation) {
|
||||
value2 = 0.62731; // some random value
|
||||
}
|
||||
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
|
||||
if(valid2 == true){
|
||||
@@ -185,7 +188,6 @@ public:
|
||||
unit6old = unit6; // Save old unit
|
||||
}
|
||||
|
||||
|
||||
// Optical warning by limit violation (unused)
|
||||
if(String(flashLED) == "Limit Violation"){
|
||||
setBlinkingLED(false);
|
||||
@@ -201,13 +203,10 @@ public:
|
||||
|
||||
// Set display in partial refresh mode
|
||||
displaySetPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
|
||||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
|
||||
// Show AWS or TWS top left
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(10, 65);
|
||||
getdisplay().print(svalue2); // Value
|
||||
printBoatValue(svalue2, 101, 65, RIGHT, 20, smallDecimals); // value
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt8b);
|
||||
getdisplay().setCursor(10, 95);
|
||||
getdisplay().print(name2); // Name
|
||||
@@ -225,9 +224,7 @@ public:
|
||||
getdisplay().fillRect(0, 149, 60, 3, commonData->fgcolor);
|
||||
|
||||
// Show value 3 (=first user-configured parameter) at bottom left
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(10, 270);
|
||||
getdisplay().print(svalue3); // Value
|
||||
printBoatValue(svalue3, 101, 270, RIGHT, 20, smallDecimals); // value
|
||||
getdisplay().setFont(&name3font);
|
||||
getdisplay().setCursor(10, 220);
|
||||
getdisplay().print(name3); // Name
|
||||
@@ -242,9 +239,7 @@ public:
|
||||
}
|
||||
|
||||
// Show value 4 (=second user-configured parameter) at top right
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(295, 65);
|
||||
getdisplay().print(svalue4); // Value
|
||||
printBoatValue(svalue4, 395, 65, RIGHT, 20, smallDecimals); // value
|
||||
getdisplay().setFont(&name4font);
|
||||
getdisplay().setCursor(325, 95);
|
||||
getdisplay().print(name4); // Name
|
||||
@@ -258,13 +253,11 @@ public:
|
||||
getdisplay().print(unit4old); // Unit
|
||||
}
|
||||
|
||||
// Horizintal separator right
|
||||
// Horizontal separator right
|
||||
getdisplay().fillRect(340, 149, 80, 3, commonData->fgcolor);
|
||||
|
||||
// Show value 5 (=third user-configured parameter) at bottom right
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(295, 270);
|
||||
getdisplay().print(svalue5); // Value
|
||||
printBoatValue(svalue5, 395, 270, RIGHT, 20, smallDecimals); // value
|
||||
getdisplay().setFont(&name5font);
|
||||
getdisplay().setCursor(325, 220);
|
||||
getdisplay().print(name5); // Name
|
||||
@@ -283,6 +276,7 @@ public:
|
||||
|
||||
// Draw wind rose
|
||||
int rInstrument = 110; // Radius of grafic instrument
|
||||
String sDegree;
|
||||
|
||||
getdisplay().fillCircle(200, 150, rInstrument + 10, commonData->fgcolor); // Outer circle
|
||||
getdisplay().fillCircle(200, 150, rInstrument + 7, commonData->bgcolor); // Outer circle
|
||||
@@ -294,53 +288,36 @@ public:
|
||||
// Scaling values
|
||||
float x = 200 + (rInstrument-30)*sin(i/180.0*M_PI); // x-coordinate dots
|
||||
float y = 150 - (rInstrument-30)*cos(i/180.0*M_PI); // y-coordinate dots
|
||||
const char *ii = "";
|
||||
switch (i) {
|
||||
case 0: ii="0"; break;
|
||||
case 30 : ii="30"; break;
|
||||
case 60 : ii="60"; break;
|
||||
case 90 : ii="90"; break;
|
||||
case 120 : ii="120"; break;
|
||||
case 150 : ii="150"; break;
|
||||
case 180 : ii="180"; break;
|
||||
case 210 : ii="210"; break;
|
||||
case 240 : ii="240"; break;
|
||||
case 270 : ii="270"; break;
|
||||
case 300 : ii="300"; break;
|
||||
case 330 : ii="330"; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if(i % 30 == 0){
|
||||
// Print text centered on position x, y
|
||||
int16_t x1, y1; // Return values of getTextBounds
|
||||
uint16_t w, h; // Return values of getTextBounds
|
||||
displayGetTextBounds(ii, int(x), int(y), &x1, &y1, &w, &h); // Calc width of new string
|
||||
getdisplay().setCursor(x-w/2, y+h/2);
|
||||
if(i % 30 == 0){
|
||||
sDegree = String(i);
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().print(ii);
|
||||
}
|
||||
|
||||
// Draw sub scale with dots
|
||||
float x1c = 200 + rInstrument*sin(i/180.0*M_PI);
|
||||
float y1c = 150 - rInstrument*cos(i/180.0*M_PI);
|
||||
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
|
||||
float sinx=sin(i/180.0*M_PI);
|
||||
float cosx=cos(i/180.0*M_PI);
|
||||
displayGetTextBounds(sDegree, int(x), int(y), &x1, &y1, &w, &h); // Calc width of new string
|
||||
getdisplay().setCursor(x-w/2, y+h/2);
|
||||
getdisplay().print(sDegree);
|
||||
|
||||
// Draw sub scale with lines (two triangles)
|
||||
if(i % 30 == 0){
|
||||
float dx=2; // Line thickness = 2*dx+1
|
||||
float xx1 = -dx;
|
||||
float xx2 = +dx;
|
||||
float yy1 = -(rInstrument-10);
|
||||
float yy2 = -(rInstrument+10);
|
||||
float sinx = sin(i/180.0*M_PI);
|
||||
float cosx = cos(i/180.0*M_PI);
|
||||
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
|
||||
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
|
||||
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData->fgcolor);
|
||||
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
|
||||
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
|
||||
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData->fgcolor);
|
||||
} else {
|
||||
// Draw sub scale with dots
|
||||
float x1c = 200 + rInstrument*sin(i/180.0*M_PI);
|
||||
float y1c = 150 - rInstrument*cos(i/180.0*M_PI);
|
||||
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,15 +360,12 @@ public:
|
||||
}
|
||||
getdisplay().print({source});
|
||||
|
||||
|
||||
//*******************************************************************************************
|
||||
|
||||
// Show value6 (=fourth user-configured parameter)
|
||||
if ( cos(value1) > 0){
|
||||
//pointer points upwards
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
|
||||
getdisplay().setCursor(160, 200);
|
||||
getdisplay().print(svalue6); // Value
|
||||
printBoatValue(svalue6, 200, 200, CENTER, 16, smallDecimals); // value
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(190, 215);
|
||||
getdisplay().print(" ");
|
||||
@@ -404,9 +378,7 @@ if ( cos(value1) > 0){
|
||||
}
|
||||
else{
|
||||
// pointer points downwards
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
|
||||
getdisplay().setCursor(160, 130);
|
||||
getdisplay().print(svalue6); // Value
|
||||
printBoatValue(svalue6, 200, 130, CENTER, 16, smallDecimals); // value
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(190, 90);
|
||||
getdisplay().print(" ");
|
||||
|
||||
@@ -28,8 +28,13 @@ static unsigned char ship_bits[] PROGMEM = {
|
||||
|
||||
class PageXTETrack : public Page
|
||||
{
|
||||
static constexpr int8_t LEFT = 0;
|
||||
static constexpr int8_t CENTER = 1;
|
||||
static constexpr int8_t RIGHT = 2;
|
||||
|
||||
bool simulation = false;
|
||||
bool holdvalues = false;
|
||||
bool smallDecimals = false;
|
||||
|
||||
public:
|
||||
PageXTETrack(CommonData &common){
|
||||
@@ -37,6 +42,7 @@ class PageXTETrack : public Page
|
||||
common.logger->logDebug(GwLog::LOG,"Instantiate PageXTETrack");
|
||||
simulation = common.config->getBool(common.config->useSimuData);
|
||||
holdvalues = common.config->getBool(common.config->holdvalues);
|
||||
smallDecimals = common.config->getBool(common.config->smallDecimals);
|
||||
}
|
||||
|
||||
void drawSegment(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1,
|
||||
@@ -95,44 +101,33 @@ class PageXTETrack : public Page
|
||||
|
||||
// descriptions
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt8b);
|
||||
getdisplay().setCursor(50, 188);
|
||||
getdisplay().setCursor(30, 188);
|
||||
getdisplay().print("Cross-track error");
|
||||
getdisplay().setCursor(270, 188);
|
||||
getdisplay().print("Track");
|
||||
getdisplay().setCursor(45, 275);
|
||||
getdisplay().setCursor(25, 275);
|
||||
getdisplay().print("Distance to waypoint");
|
||||
getdisplay().setCursor(260, 275);
|
||||
getdisplay().setCursor(280, 275);
|
||||
getdisplay().print("Bearing");
|
||||
|
||||
// values
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
|
||||
|
||||
int16_t x, y;
|
||||
uint16_t w, h;
|
||||
|
||||
GwApi::BoatValue *bv_xte = pageData.values[0]; // XTE
|
||||
String sval_xte = formatValue(bv_xte, *commonData).svalue;
|
||||
displayGetTextBounds(sval_xte, 0, 0, &x, &y, &w, &h);
|
||||
getdisplay().setCursor(160-w, 170);
|
||||
getdisplay().print(sval_xte);
|
||||
// printBoatValue(sval_xte, 160, 170, RIGHT, 30, smallDecimals);
|
||||
printBoatValue(sval_xte, 180, 170, RIGHT, 30, smallDecimals);
|
||||
|
||||
GwApi::BoatValue *bv_cog = pageData.values[1]; // COG
|
||||
String sval_cog = formatValue(bv_cog, *commonData).svalue;
|
||||
displayGetTextBounds(sval_cog, 0, 0, &x, &y, &w, &h);
|
||||
getdisplay().setCursor(360-w, 170);
|
||||
getdisplay().print(sval_cog);
|
||||
printBoatValue(sval_cog, 360, 170, RIGHT, 30, smallDecimals);
|
||||
|
||||
GwApi::BoatValue *bv_dtw = pageData.values[2]; // DTW
|
||||
String sval_dtw = formatValue(bv_dtw, *commonData).svalue;
|
||||
displayGetTextBounds(sval_dtw, 0, 0, &x, &y, &w, &h);
|
||||
getdisplay().setCursor(160-w, 257);
|
||||
getdisplay().print(sval_dtw);
|
||||
// printBoatValue(sval_dtw, 160, 257, RIGHT, 30, smallDecimals);
|
||||
printBoatValue(sval_dtw, 160, 257, RIGHT, 30, smallDecimals);
|
||||
|
||||
GwApi::BoatValue *bv_btw = pageData.values[3]; // BTW
|
||||
String sval_btw = formatValue(bv_btw, *commonData).svalue;
|
||||
displayGetTextBounds(sval_btw, 0, 0, &x, &y, &w, &h);
|
||||
getdisplay().setCursor(360-w, 257);
|
||||
getdisplay().print(sval_btw);
|
||||
printBoatValue(sval_btw, 368, 257, RIGHT, 30, smallDecimals);
|
||||
|
||||
bool valid = bv_cog->valid && bv_btw->valid;
|
||||
|
||||
@@ -148,6 +143,9 @@ class PageXTETrack : public Page
|
||||
sval_wpname = "Tonne 122";
|
||||
}
|
||||
|
||||
int16_t x, y;
|
||||
uint16_t w, h;
|
||||
|
||||
getdisplay().setFont(&Ubuntu_Bold10pt8b);
|
||||
displayGetTextBounds(sval_wpname, 0, 150, &x, &y, &w, &h);
|
||||
// TODO if text don't fix use smaller font size.
|
||||
|
||||
@@ -205,6 +205,8 @@ typedef struct{
|
||||
// Formatter for boat values
|
||||
FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata);
|
||||
FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, bool ignoreSimuDataSetting);
|
||||
FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata, String setPrecision);
|
||||
String formatValue(const double &value, const String &vFormat, CommonData &commondata);
|
||||
|
||||
// Helper method for conversion of any data value from SI to user defined format (defined in OBP60Formatter)
|
||||
double convertValue(const double &value, const String &format, CommonData &commondata);
|
||||
|
||||
@@ -75,6 +75,44 @@
|
||||
"obp40": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "leeKStd",
|
||||
"label": "Leeway Coefficient",
|
||||
"type": "list",
|
||||
"default": "---",
|
||||
"description": "Boat coefficient K for leeway",
|
||||
"list": [
|
||||
"---",
|
||||
"Racer [2]",
|
||||
"Multihull Draggerboard [4]",
|
||||
"Performance Cruiser [6]",
|
||||
"Family Cruiser [9]",
|
||||
"Heavy Displacement [13]",
|
||||
"Multihull Fixed Keel [16]",
|
||||
"Individual value"
|
||||
],
|
||||
"category": "OBP40 Settings",
|
||||
"capabilities": {
|
||||
"obp40": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "leeK",
|
||||
"label": "Leeway Coefficient",
|
||||
"type": "number",
|
||||
"default": "0.00",
|
||||
"check": "checkMinMax",
|
||||
"min": 0,
|
||||
"max": 20,
|
||||
"description": "Boat coefficient K for leeway - individual setting [0..20]",
|
||||
"category": "OBP40 Settings",
|
||||
"capabilities": {
|
||||
"obp40":"true"
|
||||
},
|
||||
"condition": [
|
||||
{ "leeKStd": ["Individual value"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fuelTank",
|
||||
"label": "Fuel Tank [l]",
|
||||
@@ -1317,10 +1355,10 @@
|
||||
},
|
||||
{
|
||||
"name": "valueprecision",
|
||||
"label": "Display value precision",
|
||||
"label": "Value precision",
|
||||
"type": "list",
|
||||
"default": "2",
|
||||
"description": "Maximum number of decimal places to display [1|2]",
|
||||
"description": "Number of decimal precision on display: [1|2] decimals",
|
||||
"list": [
|
||||
"1",
|
||||
"2"
|
||||
@@ -1330,6 +1368,17 @@
|
||||
"obp40":"true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "smallDecimals",
|
||||
"label": "Display small decimals",
|
||||
"type": "boolean",
|
||||
"default": "true",
|
||||
"description": "Show decimals of values in smaller size [on|off]",
|
||||
"category": "OBP40 Display",
|
||||
"capabilities": {
|
||||
"obp40": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "backlight",
|
||||
"label": "Backlight Mode",
|
||||
@@ -1534,6 +1583,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -1551,6 +1601,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -1589,6 +1640,7 @@
|
||||
},
|
||||
"condition": {
|
||||
"page1type": [
|
||||
"Current",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
@@ -1597,6 +1649,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -1631,6 +1684,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -1663,6 +1717,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -1694,6 +1749,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -1865,6 +1921,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -1882,6 +1939,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -1919,6 +1977,7 @@
|
||||
},
|
||||
"condition": {
|
||||
"page2type": [
|
||||
"Current",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
@@ -1927,6 +1986,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -1960,6 +2020,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -1991,6 +2052,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2021,6 +2083,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2187,6 +2250,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -2204,6 +2268,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -2240,6 +2305,7 @@
|
||||
},
|
||||
"condition": {
|
||||
"page3type": [
|
||||
"Current",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
@@ -2248,6 +2314,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2280,6 +2347,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2310,6 +2378,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2339,6 +2408,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2500,6 +2570,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -2517,6 +2588,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -2552,6 +2624,7 @@
|
||||
},
|
||||
"condition": {
|
||||
"page4type": [
|
||||
"Current",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
@@ -2560,6 +2633,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2591,6 +2665,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2620,6 +2695,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2648,6 +2724,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2804,6 +2881,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -2821,6 +2899,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -2855,6 +2934,7 @@
|
||||
},
|
||||
"condition": {
|
||||
"page5type": [
|
||||
"Current",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
@@ -2863,6 +2943,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2893,6 +2974,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2948,6 +3030,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3099,6 +3182,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -3116,6 +3200,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -3149,6 +3234,7 @@
|
||||
},
|
||||
"condition": {
|
||||
"page6type": [
|
||||
"Current",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
@@ -3157,6 +3243,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3186,6 +3273,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3213,6 +3301,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3239,6 +3328,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3385,6 +3475,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -3402,6 +3493,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -3434,6 +3526,7 @@
|
||||
},
|
||||
"condition": {
|
||||
"page7type": [
|
||||
"Current",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
@@ -3442,6 +3535,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3470,6 +3564,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3496,6 +3591,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3521,6 +3617,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3662,6 +3759,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -3679,6 +3777,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -3710,6 +3809,7 @@
|
||||
},
|
||||
"condition": {
|
||||
"page8type": [
|
||||
"Current",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
@@ -3718,6 +3818,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3745,6 +3846,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3770,6 +3872,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3794,6 +3897,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3930,6 +4034,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -3947,6 +4052,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -3977,6 +4083,7 @@
|
||||
},
|
||||
"condition": {
|
||||
"page9type": [
|
||||
"Current",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
@@ -3985,6 +4092,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -4011,6 +4119,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -4035,6 +4144,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -4058,6 +4168,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -4189,6 +4300,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -4206,6 +4318,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -4235,6 +4348,7 @@
|
||||
},
|
||||
"condition": {
|
||||
"page10type": [
|
||||
"Current",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
@@ -4243,6 +4357,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -4268,6 +4383,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -4291,6 +4407,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -4313,6 +4430,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
|
||||
@@ -75,6 +75,44 @@
|
||||
"obp60":"true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "leeKStd",
|
||||
"label": "Leeway Coefficient",
|
||||
"type": "list",
|
||||
"default": "---",
|
||||
"description": "Boat coefficient K for leeway",
|
||||
"list": [
|
||||
"---",
|
||||
"Racer [2]",
|
||||
"Multihull Draggerboard [4]",
|
||||
"Performance Cruiser [6]",
|
||||
"Family Cruiser [9]",
|
||||
"Heavy Displacement [13]",
|
||||
"Multihull Fixed Keel [16]",
|
||||
"Individual value"
|
||||
],
|
||||
"category": "OBP60 Settings",
|
||||
"capabilities": {
|
||||
"obp60": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "leeK",
|
||||
"label": "Leeway Coefficient",
|
||||
"type": "number",
|
||||
"default": "0.00",
|
||||
"check": "checkMinMax",
|
||||
"min": 0,
|
||||
"max": 20,
|
||||
"description": "Boat coefficient K for leeway - individual setting [0..20]",
|
||||
"category": "OBP60 Settings",
|
||||
"capabilities": {
|
||||
"obp60":"true"
|
||||
},
|
||||
"condition": [
|
||||
{ "leeKStd": ["Individual value"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fuelTank",
|
||||
"label": "Fuel Tank [l]",
|
||||
@@ -238,7 +276,7 @@
|
||||
"description": "Print chart lines with a smoothed gradient",
|
||||
"category": "OBP60 Settings",
|
||||
"capabilities": {
|
||||
"obp40": "true"
|
||||
"obp60": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1306,10 +1344,10 @@
|
||||
},
|
||||
{
|
||||
"name": "valueprecision",
|
||||
"label": "Display value precision",
|
||||
"label": "Value precision",
|
||||
"type": "list",
|
||||
"default": "2",
|
||||
"description": "Maximum number of decimal places to display [1|2]",
|
||||
"description": "Number of decimal precision on display: [1|2] decimals",
|
||||
"list": [
|
||||
"1",
|
||||
"2"
|
||||
@@ -1319,6 +1357,17 @@
|
||||
"obp60":"true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "smallDecimals",
|
||||
"label": "Display small decimals",
|
||||
"type": "boolean",
|
||||
"default": "true",
|
||||
"description": "Show decimals of values in smaller size [on|off]",
|
||||
"category": "OBP60 Display",
|
||||
"capabilities": {
|
||||
"obp60": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "backlight",
|
||||
"label": "Backlight Mode",
|
||||
@@ -1512,6 +1561,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -1529,6 +1579,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -1567,6 +1618,7 @@
|
||||
},
|
||||
"condition": {
|
||||
"page1type": [
|
||||
"Current",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
@@ -1575,6 +1627,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -1609,6 +1662,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -1641,6 +1695,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -1672,6 +1727,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -1813,6 +1869,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -1830,6 +1887,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -1867,6 +1925,7 @@
|
||||
},
|
||||
"condition": {
|
||||
"page2type": [
|
||||
"Current",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
@@ -1875,6 +1934,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -1908,6 +1968,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -1939,6 +2000,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -1969,6 +2031,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2106,6 +2169,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -2123,6 +2187,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -2159,6 +2224,7 @@
|
||||
},
|
||||
"condition": {
|
||||
"page3type": [
|
||||
"Current",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
@@ -2167,6 +2233,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2199,6 +2266,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2229,6 +2297,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2258,6 +2327,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2391,6 +2461,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -2408,6 +2479,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -2443,6 +2515,7 @@
|
||||
},
|
||||
"condition": {
|
||||
"page4type": [
|
||||
"Current",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
@@ -2451,6 +2524,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2482,6 +2556,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2511,6 +2586,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2539,6 +2615,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2668,6 +2745,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -2685,6 +2763,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -2719,6 +2798,7 @@
|
||||
},
|
||||
"condition": {
|
||||
"page5type": [
|
||||
"Current",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
@@ -2727,6 +2807,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2757,6 +2838,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2785,6 +2867,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2812,6 +2895,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2937,6 +3021,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -2954,6 +3039,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -2987,6 +3073,7 @@
|
||||
},
|
||||
"condition": {
|
||||
"page6type": [
|
||||
"Current",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
@@ -2995,6 +3082,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3024,6 +3112,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3051,6 +3140,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3077,6 +3167,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3198,6 +3289,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -3215,6 +3307,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -3247,6 +3340,7 @@
|
||||
},
|
||||
"condition": {
|
||||
"page7type": [
|
||||
"Current",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
@@ -3255,6 +3349,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3283,6 +3378,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3309,6 +3405,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3334,6 +3431,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3451,6 +3549,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -3468,6 +3567,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -3499,6 +3599,7 @@
|
||||
},
|
||||
"condition": {
|
||||
"page8type": [
|
||||
"Current",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
@@ -3507,6 +3608,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3534,6 +3636,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3559,6 +3662,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3583,6 +3687,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3696,6 +3801,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -3713,6 +3819,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -3743,6 +3850,7 @@
|
||||
},
|
||||
"condition": {
|
||||
"page9type": [
|
||||
"Current",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
@@ -3751,6 +3859,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3777,6 +3886,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3801,6 +3911,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3824,6 +3935,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3933,6 +4045,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -3950,6 +4063,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -3979,6 +4093,7 @@
|
||||
},
|
||||
"condition": {
|
||||
"page10type": [
|
||||
"Current",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
@@ -3987,6 +4102,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -4012,6 +4128,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -4035,6 +4152,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -4057,6 +4175,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
|
||||
@@ -1298,10 +1298,10 @@
|
||||
},
|
||||
{
|
||||
"name": "valueprecision",
|
||||
"label": "Display value precision",
|
||||
"label": "Value precision",
|
||||
"type": "list",
|
||||
"default": "2",
|
||||
"description": "Maximum number of decimal places to display [1|2]",
|
||||
"description": "Number of decimal precision on display: [1|2] decimals",
|
||||
"list": [
|
||||
"1",
|
||||
"2"
|
||||
@@ -1311,6 +1311,17 @@
|
||||
"obp70":"true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "smallDecimals",
|
||||
"label": "Display small decimals",
|
||||
"type": "boolean",
|
||||
"default": "true",
|
||||
"description": "Show decimals of values in smaller size [on|off]",
|
||||
"category": "OBP70 Display",
|
||||
"capabilities": {
|
||||
"obp70": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "backlight",
|
||||
"label": "Backlight Mode",
|
||||
@@ -1504,6 +1515,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -1521,6 +1533,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -1567,6 +1580,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -1601,6 +1615,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -1633,6 +1648,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -1664,6 +1680,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -1805,6 +1822,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -1822,6 +1840,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -1867,6 +1886,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -1900,6 +1920,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -1931,6 +1952,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -1961,6 +1983,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2098,6 +2121,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -2115,6 +2139,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -2159,6 +2184,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2191,6 +2217,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2221,6 +2248,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2250,6 +2278,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2383,6 +2412,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -2400,6 +2430,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -2443,6 +2474,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2474,6 +2506,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2503,6 +2536,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2531,6 +2565,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2660,6 +2695,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -2677,6 +2713,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -2719,6 +2756,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2749,6 +2787,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2777,6 +2816,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2804,6 +2844,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -2929,6 +2970,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -2946,6 +2988,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -2987,6 +3030,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3016,6 +3060,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3043,6 +3088,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3069,6 +3115,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3190,6 +3237,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -3207,6 +3255,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -3247,6 +3296,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3275,6 +3325,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3301,6 +3352,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3326,6 +3378,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3443,6 +3496,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -3460,6 +3514,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -3499,6 +3554,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3526,6 +3582,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3551,6 +3608,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3575,6 +3633,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3688,6 +3747,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -3705,6 +3765,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -3743,6 +3804,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3769,6 +3831,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3793,6 +3856,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3816,6 +3880,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -3925,6 +3990,7 @@
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"Current",
|
||||
"DigitalOut",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
@@ -3942,6 +4008,7 @@
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Voltage",
|
||||
"Weather",
|
||||
"WhitePage",
|
||||
"Wind",
|
||||
"WindPlot",
|
||||
@@ -3979,6 +4046,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -4004,6 +4072,7 @@
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"TwoValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -4027,6 +4096,7 @@
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"ThreeValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
@@ -4049,6 +4119,7 @@
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"SixValues",
|
||||
"Weather",
|
||||
"WindRoseFlex"
|
||||
],
|
||||
"visiblePages": [
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
const uint8_t DSEG7Classic_BoldItalic10pt7bBitmaps[] PROGMEM = {
|
||||
0xFE, 0x18, 0x61, 0x86, 0x18, 0x61, 0x86, 0x18, 0x61, 0x87, 0xF0, 0xFE,
|
||||
0x18, 0x61, 0x86, 0x18, 0x61, 0x86, 0x18, 0x61, 0x87, 0xF0, 0xFE, 0x18,
|
||||
0x61, 0x86, 0x18, 0x61, 0x86, 0x18, 0x61, 0x87, 0xF0, 0xFE, 0x18, 0x61,
|
||||
0x86, 0x18, 0x61, 0x86, 0x18, 0x61, 0x87, 0xF0, 0xFE, 0x18, 0x61, 0x86,
|
||||
0x18, 0x61, 0x86, 0x18, 0x61, 0x87, 0xF0, 0xFE, 0x18, 0x61, 0x86, 0x18,
|
||||
0x61, 0x86, 0x18, 0x61, 0x87, 0xF0, 0xFE, 0x18, 0x61, 0x86, 0x18, 0x61,
|
||||
0x86, 0x18, 0x61, 0x87, 0xF0, 0xFE, 0x18, 0x61, 0x86, 0x18, 0x61, 0x86,
|
||||
0x18, 0x61, 0x87, 0xF0, 0xFE, 0x18, 0x61, 0x86, 0x18, 0x61, 0x86, 0x18,
|
||||
0x61, 0x87, 0xF0, 0xFE, 0x18, 0x61, 0x86, 0x18, 0x61, 0x86, 0x18, 0x61,
|
||||
0x87, 0xF0, 0xFE, 0x18, 0x61, 0x86, 0x18, 0x61, 0x86, 0x18, 0x61, 0x87,
|
||||
0xF0, 0xFF, 0x7F, 0x80, 0xF0, 0xFE, 0x18, 0x61, 0x86, 0x18, 0x61, 0x86,
|
||||
0x18, 0x61, 0x87, 0xF0, 0x1F, 0xF8, 0xBF, 0xD3, 0x00, 0xCC, 0x07, 0x70,
|
||||
0x1D, 0xC0, 0x77, 0x01, 0xDC, 0x07, 0x70, 0x19, 0x00, 0x24, 0x00, 0x98,
|
||||
0x06, 0x60, 0x19, 0x80, 0x66, 0x03, 0xB8, 0x0E, 0xE0, 0x3B, 0x80, 0xEB,
|
||||
0xFF, 0x9F, 0xF8, 0x13, 0x77, 0x77, 0x76, 0x22, 0x66, 0x6E, 0xEE, 0xE6,
|
||||
0x1F, 0xF8, 0x3F, 0xD0, 0x00, 0xC0, 0x07, 0x00, 0x1C, 0x00, 0x70, 0x01,
|
||||
0xC0, 0x07, 0x00, 0x18, 0x7F, 0xA5, 0xFE, 0x18, 0x00, 0x60, 0x01, 0x80,
|
||||
0x06, 0x00, 0x38, 0x00, 0xE0, 0x03, 0x80, 0x0B, 0xFE, 0x1F, 0xF8, 0x3F,
|
||||
0xF0, 0xFF, 0x40, 0x06, 0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0xE0, 0x07,
|
||||
0x00, 0x31, 0xFE, 0x8F, 0xF4, 0x00, 0x60, 0x03, 0x00, 0x18, 0x01, 0xC0,
|
||||
0x0E, 0x00, 0x70, 0x03, 0x9F, 0xFD, 0xFF, 0x80, 0x40, 0x0B, 0x00, 0xD8,
|
||||
0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x06, 0xBF, 0xD1, 0xFE,
|
||||
0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x38, 0x01, 0xC0, 0x0E, 0x00, 0x70,
|
||||
0x01, 0x80, 0x3F, 0xF5, 0xFE, 0x60, 0x06, 0x00, 0xE0, 0x0E, 0x00, 0xE0,
|
||||
0x0E, 0x00, 0xE0, 0x0B, 0xFC, 0x3F, 0xD0, 0x03, 0x00, 0x30, 0x03, 0x00,
|
||||
0x70, 0x07, 0x00, 0x70, 0x07, 0x7F, 0xFF, 0xFC, 0x1F, 0xF9, 0x7F, 0x8C,
|
||||
0x00, 0x60, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x0E, 0x00, 0x70, 0x02, 0xFF,
|
||||
0x17, 0xFA, 0xC0, 0x36, 0x01, 0xB0, 0x0D, 0x80, 0xFC, 0x07, 0xE0, 0x3F,
|
||||
0x01, 0xEF, 0xFE, 0xFF, 0xC0, 0x3F, 0xF2, 0xFF, 0x58, 0x06, 0xC0, 0x7E,
|
||||
0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x34, 0x00, 0x80, 0x04, 0x00,
|
||||
0x60, 0x03, 0x00, 0x18, 0x01, 0xC0, 0x0E, 0x00, 0x70, 0x03, 0x80, 0x0C,
|
||||
0x1F, 0xF8, 0xBF, 0xD3, 0x00, 0xCC, 0x07, 0x70, 0x1D, 0xC0, 0x77, 0x01,
|
||||
0xDC, 0x07, 0x70, 0x19, 0x7F, 0xA5, 0xFE, 0x98, 0x06, 0x60, 0x19, 0x80,
|
||||
0x66, 0x03, 0xB8, 0x0E, 0xE0, 0x3B, 0x80, 0xEB, 0xFF, 0x9F, 0xF8, 0x3F,
|
||||
0xF2, 0xFF, 0x58, 0x06, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07,
|
||||
0xE0, 0x35, 0xFE, 0x8F, 0xF4, 0x00, 0x60, 0x03, 0x00, 0x18, 0x01, 0xC0,
|
||||
0x0E, 0x00, 0x70, 0x03, 0x9F, 0xFD, 0xFF, 0x80, 0x67, 0x00, 0x00, 0x00,
|
||||
0x4E, 0x40, 0xFE, 0x18, 0x61, 0x86, 0x18, 0x61, 0x86, 0x18, 0x61, 0x87,
|
||||
0xF0, 0xFE, 0x18, 0x61, 0x86, 0x18, 0x61, 0x86, 0x18, 0x61, 0x87, 0xF0,
|
||||
0xFE, 0x18, 0x61, 0x86, 0x18, 0x61, 0x86, 0x18, 0x61, 0x87, 0xF0, 0xFE,
|
||||
0x18, 0x61, 0x86, 0x18, 0x61, 0x86, 0x18, 0x61, 0x87, 0xF0, 0xFE, 0x18,
|
||||
0x61, 0x86, 0x18, 0x61, 0x86, 0x18, 0x61, 0x87, 0xF0, 0xFE, 0x18, 0x61,
|
||||
0x86, 0x18, 0x61, 0x86, 0x18, 0x61, 0x87, 0xF0, 0x1F, 0xF8, 0xBF, 0xD3,
|
||||
0x00, 0xCC, 0x07, 0x70, 0x1D, 0xC0, 0x77, 0x01, 0xDC, 0x07, 0x70, 0x19,
|
||||
0x7F, 0xA5, 0xFE, 0x98, 0x06, 0x60, 0x19, 0x80, 0x66, 0x03, 0xB8, 0x0E,
|
||||
0xE0, 0x3B, 0x80, 0xE8, 0x01, 0x80, 0x20, 0x01, 0x80, 0x0C, 0x00, 0xE0,
|
||||
0x07, 0x00, 0x38, 0x01, 0xC0, 0x0E, 0x00, 0x5F, 0xE2, 0xFF, 0x58, 0x06,
|
||||
0xC0, 0x36, 0x01, 0xB0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3D, 0xFF, 0xDF,
|
||||
0xF8, 0x1F, 0xE5, 0xFE, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0xE0, 0x0E,
|
||||
0x00, 0xE0, 0x0B, 0xFE, 0x7F, 0xE0, 0x00, 0x04, 0x00, 0x30, 0x01, 0xC0,
|
||||
0x07, 0x00, 0x1C, 0x00, 0x70, 0x01, 0xC0, 0x06, 0x1F, 0xE9, 0x7F, 0xA6,
|
||||
0x01, 0x98, 0x06, 0x60, 0x19, 0x80, 0xEE, 0x03, 0xB8, 0x0E, 0xE0, 0x3A,
|
||||
0xFF, 0xE7, 0xFE, 0x00, 0x1F, 0xF9, 0x7F, 0x8C, 0x00, 0x60, 0x07, 0x00,
|
||||
0x38, 0x01, 0xC0, 0x0E, 0x00, 0x70, 0x02, 0xFF, 0x17, 0xF8, 0xC0, 0x06,
|
||||
0x00, 0x30, 0x01, 0x80, 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x2F, 0xF8, 0xFF,
|
||||
0xC0, 0x1F, 0xF9, 0x7F, 0x8C, 0x00, 0x60, 0x07, 0x00, 0x38, 0x01, 0xC0,
|
||||
0x0E, 0x00, 0x70, 0x02, 0xFF, 0x17, 0xF8, 0xC0, 0x06, 0x00, 0x30, 0x01,
|
||||
0x80, 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x20, 0x00, 0x1F, 0xF9, 0x7F, 0x8C,
|
||||
0x00, 0x60, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x0E, 0x00, 0x70, 0x02, 0x00,
|
||||
0x10, 0x02, 0xC0, 0x36, 0x01, 0xB0, 0x0D, 0x80, 0xFC, 0x07, 0xE0, 0x3F,
|
||||
0x01, 0xEF, 0xFE, 0xFF, 0xC0, 0x20, 0x01, 0x80, 0x0C, 0x00, 0xE0, 0x07,
|
||||
0x00, 0x38, 0x01, 0xC0, 0x0E, 0x00, 0x5F, 0xE2, 0xFF, 0x58, 0x06, 0xC0,
|
||||
0x36, 0x01, 0xB0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3C, 0x00, 0xC0, 0x2D,
|
||||
0xBF, 0xFF, 0x60, 0x00, 0x04, 0x00, 0x30, 0x01, 0xC0, 0x07, 0x00, 0x1C,
|
||||
0x00, 0x70, 0x01, 0xC0, 0x06, 0x00, 0x09, 0x00, 0x26, 0x01, 0x98, 0x06,
|
||||
0x60, 0x19, 0x80, 0xEE, 0x03, 0xB8, 0x0E, 0xE0, 0x3A, 0xFF, 0xE7, 0xFE,
|
||||
0x00, 0x1F, 0xF9, 0x7F, 0x8C, 0x00, 0x60, 0x07, 0x00, 0x38, 0x01, 0xC0,
|
||||
0x0E, 0x00, 0x70, 0x02, 0xFF, 0x17, 0xFA, 0xC0, 0x36, 0x01, 0xB0, 0x0D,
|
||||
0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xE0, 0x06, 0x20, 0x03, 0x00, 0x30,
|
||||
0x07, 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, 0x00, 0x40, 0x04, 0x00, 0x60,
|
||||
0x06, 0x00, 0x60, 0x06, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0B, 0xFE, 0x7F,
|
||||
0xE0, 0x1F, 0xF8, 0xBF, 0xD3, 0x00, 0xCC, 0x07, 0x70, 0x1D, 0xC0, 0x77,
|
||||
0x01, 0xDC, 0x07, 0x70, 0x19, 0x00, 0x24, 0x00, 0x98, 0x06, 0x60, 0x19,
|
||||
0x80, 0x66, 0x03, 0xB8, 0x0E, 0xE0, 0x3B, 0x80, 0xE8, 0x01, 0x80, 0x1F,
|
||||
0xE2, 0xFF, 0x58, 0x06, 0xC0, 0x36, 0x01, 0xB0, 0x1F, 0x80, 0xFC, 0x07,
|
||||
0xE0, 0x3C, 0x00, 0xC0, 0x1F, 0xE2, 0xFF, 0x58, 0x06, 0xC0, 0x36, 0x01,
|
||||
0xB0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3D, 0xFF, 0xDF, 0xF8, 0x1F, 0xF8,
|
||||
0xBF, 0xD3, 0x00, 0xCC, 0x07, 0x70, 0x1D, 0xC0, 0x77, 0x01, 0xDC, 0x07,
|
||||
0x70, 0x19, 0x7F, 0xA5, 0xFE, 0x18, 0x00, 0x60, 0x01, 0x80, 0x06, 0x00,
|
||||
0x38, 0x00, 0xE0, 0x03, 0x80, 0x08, 0x00, 0x00, 0x3F, 0xF2, 0xFF, 0x58,
|
||||
0x06, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x35, 0xFE,
|
||||
0x8F, 0xF4, 0x00, 0x60, 0x03, 0x00, 0x18, 0x01, 0xC0, 0x0E, 0x00, 0x70,
|
||||
0x03, 0x80, 0x0C, 0x1F, 0xE5, 0xFE, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00,
|
||||
0xE0, 0x0E, 0x00, 0xE0, 0x08, 0x00, 0x40, 0x06, 0x00, 0x60, 0x0E, 0x00,
|
||||
0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0xBF, 0xC3, 0xFD, 0x00, 0x30, 0x03,
|
||||
0x00, 0x30, 0x07, 0x00, 0x70, 0x07, 0x00, 0x77, 0xFF, 0xFF, 0xC0, 0x20,
|
||||
0x03, 0x00, 0x30, 0x07, 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, 0x00, 0x5F,
|
||||
0xE5, 0xFE, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0xE0, 0x0E, 0x00, 0xE0,
|
||||
0x0B, 0xFE, 0x7F, 0xE0, 0x40, 0x0B, 0x00, 0xD8, 0x06, 0xC0, 0x36, 0x03,
|
||||
0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xBF, 0xFB, 0xFF, 0x00, 0x20, 0x04, 0xC0,
|
||||
0x33, 0x01, 0xDC, 0x07, 0x70, 0x1D, 0xC0, 0x77, 0x01, 0xDC, 0x06, 0x40,
|
||||
0x09, 0x00, 0x26, 0x01, 0x98, 0x06, 0x60, 0x19, 0x80, 0xEE, 0x03, 0xB8,
|
||||
0x0E, 0xE0, 0x3A, 0xFF, 0xE7, 0xFE, 0x00, 0x20, 0x04, 0xC0, 0x33, 0x01,
|
||||
0xDC, 0x07, 0x70, 0x1D, 0xC0, 0x77, 0x01, 0xDC, 0x06, 0x5F, 0xE9, 0x7F,
|
||||
0xA6, 0x01, 0x98, 0x06, 0x60, 0x19, 0x80, 0xEE, 0x03, 0xB8, 0x0E, 0xE0,
|
||||
0x3A, 0xFF, 0xE7, 0xFE, 0x00, 0x20, 0x04, 0xC0, 0x33, 0x01, 0xDC, 0x07,
|
||||
0x70, 0x1D, 0xC0, 0x77, 0x01, 0xDC, 0x06, 0x5F, 0xE9, 0x7F, 0xA6, 0x01,
|
||||
0x98, 0x06, 0x60, 0x19, 0x80, 0xEE, 0x03, 0xB8, 0x0E, 0xE0, 0x3A, 0x00,
|
||||
0x60, 0x40, 0x0B, 0x00, 0xD8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80,
|
||||
0xFC, 0x06, 0xBF, 0xD1, 0xFE, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x38,
|
||||
0x01, 0xC0, 0x0E, 0x00, 0x73, 0xFF, 0xBF, 0xF0, 0x1F, 0xF8, 0x3F, 0xD0,
|
||||
0x00, 0xC0, 0x07, 0x00, 0x1C, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, 0x18,
|
||||
0x00, 0x24, 0x00, 0x18, 0x00, 0x60, 0x01, 0x80, 0x06, 0x00, 0x38, 0x00,
|
||||
0xE0, 0x03, 0x80, 0x0B, 0xFE, 0x1F, 0xF8, 0xFE, 0x18, 0x61, 0x86, 0x18,
|
||||
0x61, 0x86, 0x18, 0x61, 0x87, 0xF0, 0xFE, 0x18, 0x61, 0x86, 0x18, 0x61,
|
||||
0x86, 0x18, 0x61, 0x87, 0xF0, 0xFE, 0x18, 0x61, 0x86, 0x18, 0x61, 0x86,
|
||||
0x18, 0x61, 0x87, 0xF0, 0xFE, 0x18, 0x61, 0x86, 0x18, 0x61, 0x86, 0x18,
|
||||
0x61, 0x87, 0xF0, 0x7F, 0xDF, 0xF8, 0xFE, 0x18, 0x61, 0x86, 0x18, 0x61,
|
||||
0x86, 0x18, 0x61, 0x87, 0xF0, 0x1F, 0xF8, 0xBF, 0xD3, 0x00, 0xCC, 0x07,
|
||||
0x70, 0x1D, 0xC0, 0x77, 0x01, 0xDC, 0x07, 0x70, 0x19, 0x7F, 0xA5, 0xFE,
|
||||
0x98, 0x06, 0x60, 0x19, 0x80, 0x66, 0x03, 0xB8, 0x0E, 0xE0, 0x3B, 0x80,
|
||||
0xE8, 0x01, 0x80, 0x20, 0x01, 0x80, 0x0C, 0x00, 0xE0, 0x07, 0x00, 0x38,
|
||||
0x01, 0xC0, 0x0E, 0x00, 0x5F, 0xE2, 0xFF, 0x58, 0x06, 0xC0, 0x36, 0x01,
|
||||
0xB0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3D, 0xFF, 0xDF, 0xF8, 0x1F, 0xE5,
|
||||
0xFE, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0B,
|
||||
0xFE, 0x7F, 0xE0, 0x00, 0x04, 0x00, 0x30, 0x01, 0xC0, 0x07, 0x00, 0x1C,
|
||||
0x00, 0x70, 0x01, 0xC0, 0x06, 0x1F, 0xE9, 0x7F, 0xA6, 0x01, 0x98, 0x06,
|
||||
0x60, 0x19, 0x80, 0xEE, 0x03, 0xB8, 0x0E, 0xE0, 0x3A, 0xFF, 0xE7, 0xFE,
|
||||
0x00, 0x1F, 0xF9, 0x7F, 0x8C, 0x00, 0x60, 0x07, 0x00, 0x38, 0x01, 0xC0,
|
||||
0x0E, 0x00, 0x70, 0x02, 0xFF, 0x17, 0xF8, 0xC0, 0x06, 0x00, 0x30, 0x01,
|
||||
0x80, 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x2F, 0xF8, 0xFF, 0xC0, 0x1F, 0xF9,
|
||||
0x7F, 0x8C, 0x00, 0x60, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x0E, 0x00, 0x70,
|
||||
0x02, 0xFF, 0x17, 0xF8, 0xC0, 0x06, 0x00, 0x30, 0x01, 0x80, 0x1C, 0x00,
|
||||
0xE0, 0x07, 0x00, 0x20, 0x00, 0x1F, 0xF9, 0x7F, 0x8C, 0x00, 0x60, 0x07,
|
||||
0x00, 0x38, 0x01, 0xC0, 0x0E, 0x00, 0x70, 0x02, 0x00, 0x10, 0x02, 0xC0,
|
||||
0x36, 0x01, 0xB0, 0x0D, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xEF, 0xFE,
|
||||
0xFF, 0xC0, 0x20, 0x01, 0x80, 0x0C, 0x00, 0xE0, 0x07, 0x00, 0x38, 0x01,
|
||||
0xC0, 0x0E, 0x00, 0x5F, 0xE2, 0xFF, 0x58, 0x06, 0xC0, 0x36, 0x01, 0xB0,
|
||||
0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3C, 0x00, 0xC0, 0x2D, 0xBF, 0xFF, 0x60,
|
||||
0x00, 0x04, 0x00, 0x30, 0x01, 0xC0, 0x07, 0x00, 0x1C, 0x00, 0x70, 0x01,
|
||||
0xC0, 0x06, 0x00, 0x09, 0x00, 0x26, 0x01, 0x98, 0x06, 0x60, 0x19, 0x80,
|
||||
0xEE, 0x03, 0xB8, 0x0E, 0xE0, 0x3A, 0xFF, 0xE7, 0xFE, 0x00, 0x1F, 0xF9,
|
||||
0x7F, 0x8C, 0x00, 0x60, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x0E, 0x00, 0x70,
|
||||
0x02, 0xFF, 0x17, 0xFA, 0xC0, 0x36, 0x01, 0xB0, 0x0D, 0x80, 0xFC, 0x07,
|
||||
0xE0, 0x3F, 0x01, 0xE0, 0x06, 0x20, 0x03, 0x00, 0x30, 0x07, 0x00, 0x70,
|
||||
0x07, 0x00, 0x70, 0x07, 0x00, 0x40, 0x04, 0x00, 0x60, 0x06, 0x00, 0x60,
|
||||
0x06, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0B, 0xFE, 0x7F, 0xE0, 0x1F, 0xF8,
|
||||
0xBF, 0xD3, 0x00, 0xCC, 0x07, 0x70, 0x1D, 0xC0, 0x77, 0x01, 0xDC, 0x07,
|
||||
0x70, 0x19, 0x00, 0x24, 0x00, 0x98, 0x06, 0x60, 0x19, 0x80, 0x66, 0x03,
|
||||
0xB8, 0x0E, 0xE0, 0x3B, 0x80, 0xE8, 0x01, 0x80, 0x1F, 0xE2, 0xFF, 0x58,
|
||||
0x06, 0xC0, 0x36, 0x01, 0xB0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3C, 0x00,
|
||||
0xC0, 0x1F, 0xE2, 0xFF, 0x58, 0x06, 0xC0, 0x36, 0x01, 0xB0, 0x1F, 0x80,
|
||||
0xFC, 0x07, 0xE0, 0x3D, 0xFF, 0xDF, 0xF8, 0x1F, 0xF8, 0xBF, 0xD3, 0x00,
|
||||
0xCC, 0x07, 0x70, 0x1D, 0xC0, 0x77, 0x01, 0xDC, 0x07, 0x70, 0x19, 0x7F,
|
||||
0xA5, 0xFE, 0x18, 0x00, 0x60, 0x01, 0x80, 0x06, 0x00, 0x38, 0x00, 0xE0,
|
||||
0x03, 0x80, 0x08, 0x00, 0x00, 0x3F, 0xF2, 0xFF, 0x58, 0x06, 0xC0, 0x7E,
|
||||
0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x35, 0xFE, 0x8F, 0xF4, 0x00,
|
||||
0x60, 0x03, 0x00, 0x18, 0x01, 0xC0, 0x0E, 0x00, 0x70, 0x03, 0x80, 0x0C,
|
||||
0x1F, 0xE5, 0xFE, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0xE0, 0x0E, 0x00,
|
||||
0xE0, 0x08, 0x00, 0x40, 0x06, 0x00, 0x60, 0x0E, 0x00, 0xE0, 0x0E, 0x00,
|
||||
0xE0, 0x0E, 0x00, 0xBF, 0xC3, 0xFD, 0x00, 0x30, 0x03, 0x00, 0x30, 0x07,
|
||||
0x00, 0x70, 0x07, 0x00, 0x77, 0xFF, 0xFF, 0xC0, 0x20, 0x03, 0x00, 0x30,
|
||||
0x07, 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, 0x00, 0x5F, 0xE5, 0xFE, 0x60,
|
||||
0x06, 0x00, 0x60, 0x06, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0B, 0xFE, 0x7F,
|
||||
0xE0, 0x40, 0x0B, 0x00, 0xD8, 0x06, 0xC0, 0x36, 0x03, 0xF0, 0x1F, 0x80,
|
||||
0xFC, 0x07, 0xBF, 0xFB, 0xFF, 0x00, 0x20, 0x04, 0xC0, 0x33, 0x01, 0xDC,
|
||||
0x07, 0x70, 0x1D, 0xC0, 0x77, 0x01, 0xDC, 0x06, 0x40, 0x09, 0x00, 0x26,
|
||||
0x01, 0x98, 0x06, 0x60, 0x19, 0x80, 0xEE, 0x03, 0xB8, 0x0E, 0xE0, 0x3A,
|
||||
0xFF, 0xE7, 0xFE, 0x00, 0x20, 0x04, 0xC0, 0x33, 0x01, 0xDC, 0x07, 0x70,
|
||||
0x1D, 0xC0, 0x77, 0x01, 0xDC, 0x06, 0x5F, 0xE9, 0x7F, 0xA6, 0x01, 0x98,
|
||||
0x06, 0x60, 0x19, 0x80, 0xEE, 0x03, 0xB8, 0x0E, 0xE0, 0x3A, 0xFF, 0xE7,
|
||||
0xFE, 0x00, 0x20, 0x04, 0xC0, 0x33, 0x01, 0xDC, 0x07, 0x70, 0x1D, 0xC0,
|
||||
0x77, 0x01, 0xDC, 0x06, 0x5F, 0xE9, 0x7F, 0xA6, 0x01, 0x98, 0x06, 0x60,
|
||||
0x19, 0x80, 0xEE, 0x03, 0xB8, 0x0E, 0xE0, 0x3A, 0x00, 0x60, 0x40, 0x0B,
|
||||
0x00, 0xD8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x06, 0xBF,
|
||||
0xD1, 0xFE, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x38, 0x01, 0xC0, 0x0E,
|
||||
0x00, 0x73, 0xFF, 0xBF, 0xF0, 0x1F, 0xF8, 0x3F, 0xD0, 0x00, 0xC0, 0x07,
|
||||
0x00, 0x1C, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, 0x18, 0x00, 0x24, 0x00,
|
||||
0x18, 0x00, 0x60, 0x01, 0x80, 0x06, 0x00, 0x38, 0x00, 0xE0, 0x03, 0x80,
|
||||
0x0B, 0xFE, 0x1F, 0xF8, 0xFE, 0x18, 0x61, 0x86, 0x18, 0x61, 0x86, 0x18,
|
||||
0x61, 0x87, 0xF0, 0xFE, 0x18, 0x61, 0x86, 0x18, 0x61, 0x86, 0x18, 0x61,
|
||||
0x87, 0xF0, 0xFE, 0x18, 0x61, 0x86, 0x18, 0x61, 0x86, 0x18, 0x61, 0x87,
|
||||
0xF0, 0xFE, 0x18, 0x61, 0x86, 0x18, 0x61, 0x86, 0x18, 0x61, 0x87, 0xF0 };
|
||||
|
||||
const GFXglyph DSEG7Classic_BoldItalic10pt7bGlyphs[] PROGMEM = {
|
||||
{ 0, 0, 0, 4, 0, 1 }, // 0x20 ' '
|
||||
{ 0, 0, 0, 16, 0, 1 }, // 0x21 '!'
|
||||
{ 0, 6, 14, 7, 1, -13 }, // 0x22 '"'
|
||||
{ 11, 6, 14, 7, 1, -13 }, // 0x23 '#'
|
||||
{ 22, 6, 14, 7, 1, -13 }, // 0x24 '$'
|
||||
{ 33, 6, 14, 7, 1, -13 }, // 0x25 '%'
|
||||
{ 44, 6, 14, 7, 1, -13 }, // 0x26 '&'
|
||||
{ 55, 6, 14, 7, 1, -13 }, // 0x27 '''
|
||||
{ 66, 6, 14, 7, 1, -13 }, // 0x28 '('
|
||||
{ 77, 6, 14, 7, 1, -13 }, // 0x29 ')'
|
||||
{ 88, 6, 14, 7, 1, -13 }, // 0x2A '*'
|
||||
{ 99, 6, 14, 7, 1, -13 }, // 0x2B '+'
|
||||
{ 110, 6, 14, 7, 1, -13 }, // 0x2C ','
|
||||
{ 121, 9, 2, 16, 4, -10 }, // 0x2D '-'
|
||||
{ 124, 2, 2, 0, -2, -1 }, // 0x2E '.'
|
||||
{ 125, 6, 14, 7, 1, -13 }, // 0x2F '/'
|
||||
{ 136, 14, 20, 16, 1, -19 }, // 0x30 '0'
|
||||
{ 171, 4, 18, 16, 11, -18 }, // 0x31 '1'
|
||||
{ 180, 14, 20, 16, 1, -19 }, // 0x32 '2'
|
||||
{ 215, 13, 20, 16, 2, -19 }, // 0x33 '3'
|
||||
{ 248, 13, 18, 16, 2, -18 }, // 0x34 '4'
|
||||
{ 278, 12, 20, 16, 2, -19 }, // 0x35 '5'
|
||||
{ 308, 13, 20, 16, 1, -19 }, // 0x36 '6'
|
||||
{ 341, 13, 19, 16, 2, -19 }, // 0x37 '7'
|
||||
{ 372, 14, 20, 16, 1, -19 }, // 0x38 '8'
|
||||
{ 407, 13, 20, 16, 2, -19 }, // 0x39 '9'
|
||||
{ 440, 4, 11, 4, 0, -14 }, // 0x3A ':'
|
||||
{ 446, 6, 14, 7, 1, -13 }, // 0x3B ';'
|
||||
{ 457, 6, 14, 7, 1, -13 }, // 0x3C '<'
|
||||
{ 468, 6, 14, 7, 1, -13 }, // 0x3D '='
|
||||
{ 479, 6, 14, 7, 1, -13 }, // 0x3E '>'
|
||||
{ 490, 6, 14, 7, 1, -13 }, // 0x3F '?'
|
||||
{ 501, 6, 14, 7, 1, -13 }, // 0x40 '@'
|
||||
{ 512, 14, 19, 16, 1, -19 }, // 0x41 'A'
|
||||
{ 546, 13, 19, 16, 1, -18 }, // 0x42 'B'
|
||||
{ 577, 12, 11, 16, 1, -10 }, // 0x43 'C'
|
||||
{ 594, 14, 19, 16, 1, -18 }, // 0x44 'D'
|
||||
{ 628, 13, 20, 16, 1, -19 }, // 0x45 'E'
|
||||
{ 661, 13, 19, 16, 1, -19 }, // 0x46 'F'
|
||||
{ 692, 13, 20, 16, 1, -19 }, // 0x47 'G'
|
||||
{ 725, 13, 18, 16, 1, -18 }, // 0x48 'H'
|
||||
{ 755, 3, 9, 16, 11, -9 }, // 0x49 'I'
|
||||
{ 759, 14, 19, 16, 1, -18 }, // 0x4A 'J'
|
||||
{ 793, 13, 19, 16, 1, -19 }, // 0x4B 'K'
|
||||
{ 824, 12, 19, 16, 1, -18 }, // 0x4C 'L'
|
||||
{ 853, 14, 19, 16, 1, -19 }, // 0x4D 'M'
|
||||
{ 887, 13, 10, 16, 1, -10 }, // 0x4E 'N'
|
||||
{ 904, 13, 11, 16, 1, -10 }, // 0x4F 'O'
|
||||
{ 922, 14, 19, 16, 1, -19 }, // 0x50 'P'
|
||||
{ 956, 13, 19, 16, 2, -19 }, // 0x51 'Q'
|
||||
{ 987, 12, 10, 16, 1, -10 }, // 0x52 'R'
|
||||
{ 1002, 12, 19, 16, 2, -18 }, // 0x53 'S'
|
||||
{ 1031, 12, 19, 16, 1, -18 }, // 0x54 'T'
|
||||
{ 1060, 13, 10, 16, 1, -9 }, // 0x55 'U'
|
||||
{ 1077, 14, 19, 16, 1, -18 }, // 0x56 'V'
|
||||
{ 1111, 14, 19, 16, 1, -18 }, // 0x57 'W'
|
||||
{ 1145, 14, 18, 16, 1, -18 }, // 0x58 'X'
|
||||
{ 1177, 13, 19, 16, 2, -18 }, // 0x59 'Y'
|
||||
{ 1208, 14, 20, 16, 1, -19 }, // 0x5A 'Z'
|
||||
{ 1243, 6, 14, 7, 1, -13 }, // 0x5B '['
|
||||
{ 1254, 6, 14, 7, 1, -13 }, // 0x5C '\'
|
||||
{ 1265, 6, 14, 7, 1, -13 }, // 0x5D ']'
|
||||
{ 1276, 6, 14, 7, 1, -13 }, // 0x5E '^'
|
||||
{ 1287, 11, 2, 16, 2, -1 }, // 0x5F '_'
|
||||
{ 1290, 6, 14, 7, 1, -13 }, // 0x60 '`'
|
||||
{ 1301, 14, 19, 16, 1, -19 }, // 0x61 'a'
|
||||
{ 1335, 13, 19, 16, 1, -18 }, // 0x62 'b'
|
||||
{ 1366, 12, 11, 16, 1, -10 }, // 0x63 'c'
|
||||
{ 1383, 14, 19, 16, 1, -18 }, // 0x64 'd'
|
||||
{ 1417, 13, 20, 16, 1, -19 }, // 0x65 'e'
|
||||
{ 1450, 13, 19, 16, 1, -19 }, // 0x66 'f'
|
||||
{ 1481, 13, 20, 16, 1, -19 }, // 0x67 'g'
|
||||
{ 1514, 13, 18, 16, 1, -18 }, // 0x68 'h'
|
||||
{ 1544, 3, 9, 16, 11, -9 }, // 0x69 'i'
|
||||
{ 1548, 14, 19, 16, 1, -18 }, // 0x6A 'j'
|
||||
{ 1582, 13, 19, 16, 1, -19 }, // 0x6B 'k'
|
||||
{ 1613, 12, 19, 16, 1, -18 }, // 0x6C 'l'
|
||||
{ 1642, 14, 19, 16, 1, -19 }, // 0x6D 'm'
|
||||
{ 1676, 13, 10, 16, 1, -10 }, // 0x6E 'n'
|
||||
{ 1693, 13, 11, 16, 1, -10 }, // 0x6F 'o'
|
||||
{ 1711, 14, 19, 16, 1, -19 }, // 0x70 'p'
|
||||
{ 1745, 13, 19, 16, 2, -19 }, // 0x71 'q'
|
||||
{ 1776, 12, 10, 16, 1, -10 }, // 0x72 'r'
|
||||
{ 1791, 12, 19, 16, 2, -18 }, // 0x73 's'
|
||||
{ 1820, 12, 19, 16, 1, -18 }, // 0x74 't'
|
||||
{ 1849, 13, 10, 16, 1, -9 }, // 0x75 'u'
|
||||
{ 1866, 14, 19, 16, 1, -18 }, // 0x76 'v'
|
||||
{ 1900, 14, 19, 16, 1, -18 }, // 0x77 'w'
|
||||
{ 1934, 14, 18, 16, 1, -18 }, // 0x78 'x'
|
||||
{ 1966, 13, 19, 16, 2, -18 }, // 0x79 'y'
|
||||
{ 1997, 14, 20, 16, 1, -19 }, // 0x7A 'z'
|
||||
{ 2032, 6, 14, 7, 1, -13 }, // 0x7B '{'
|
||||
{ 2043, 6, 14, 7, 1, -13 }, // 0x7C '|'
|
||||
{ 2054, 6, 14, 7, 1, -13 }, // 0x7D '}'
|
||||
{ 2065, 6, 14, 7, 1, -13 } }; // 0x7E '~'
|
||||
|
||||
const GFXfont DSEG7Classic_BoldItalic10pt7b PROGMEM = {
|
||||
(uint8_t *)DSEG7Classic_BoldItalic10pt7bBitmaps,
|
||||
(GFXglyph *)DSEG7Classic_BoldItalic10pt7bGlyphs,
|
||||
0x20, 0x7E, 22 };
|
||||
|
||||
// Approx. 2748 bytes
|
||||
@@ -0,0 +1,352 @@
|
||||
const uint8_t DSEG7Classic_BoldItalic12pt7bBitmaps[] PROGMEM = {
|
||||
0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30,
|
||||
0x60, 0xFF, 0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C,
|
||||
0x18, 0x30, 0x60, 0xFF, 0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83,
|
||||
0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60,
|
||||
0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFF, 0x06, 0x0C, 0x18,
|
||||
0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFF, 0x06,
|
||||
0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF,
|
||||
0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30,
|
||||
0x60, 0xFF, 0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C,
|
||||
0x18, 0x30, 0x60, 0xFF, 0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83,
|
||||
0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60,
|
||||
0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFF, 0x06, 0x0C, 0x18,
|
||||
0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF, 0x7F, 0xEF,
|
||||
0xFC, 0x7D, 0x80, 0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06,
|
||||
0x0C, 0x18, 0x30, 0x60, 0xFF, 0x0F, 0xFF, 0x07, 0xFF, 0x4D, 0xFF, 0x67,
|
||||
0x00, 0x73, 0x80, 0x39, 0xC0, 0x1C, 0xE0, 0x0E, 0x70, 0x07, 0x38, 0x03,
|
||||
0x9C, 0x03, 0x9C, 0x00, 0xCC, 0x00, 0x26, 0x00, 0x13, 0x80, 0x39, 0xC0,
|
||||
0x1C, 0xE0, 0x0E, 0x70, 0x07, 0x38, 0x03, 0x9C, 0x01, 0xCE, 0x00, 0xE7,
|
||||
0x00, 0xE3, 0xFF, 0xF1, 0xFF, 0xE8, 0x7F, 0xF8, 0x08, 0xCE, 0x73, 0x9C,
|
||||
0xE7, 0x71, 0x84, 0x27, 0x39, 0xCE, 0x73, 0x9D, 0xC6, 0x10, 0x0F, 0xFF,
|
||||
0x07, 0xFF, 0x41, 0xFF, 0x60, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00,
|
||||
0x0E, 0x00, 0x07, 0x00, 0x03, 0x80, 0x03, 0x80, 0x00, 0xC1, 0xFF, 0xA6,
|
||||
0xFF, 0xC3, 0x80, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00,
|
||||
0x1C, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x03, 0xFF, 0xC1, 0xFF, 0xE0, 0x7F,
|
||||
0xF8, 0x1F, 0xFE, 0x1F, 0xFD, 0x0F, 0xFB, 0x00, 0x07, 0x00, 0x07, 0x00,
|
||||
0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x0E, 0x00, 0x06, 0x1F,
|
||||
0xFA, 0x1F, 0xFA, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00,
|
||||
0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x1C, 0x3F, 0xFC, 0x7F, 0xF4, 0x7F,
|
||||
0xF8, 0x00, 0x01, 0x60, 0x03, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70,
|
||||
0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x0E, 0xE0, 0x06, 0xDF, 0xFA, 0x1F,
|
||||
0xFA, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00,
|
||||
0x0E, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x0C, 0x00, 0x04, 0x1F, 0xFE, 0x3F,
|
||||
0xF9, 0xBF, 0xE3, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00,
|
||||
0x70, 0x00, 0xE0, 0x03, 0x80, 0x06, 0xFF, 0xC1, 0xFF, 0xA0, 0x01, 0xC0,
|
||||
0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x01,
|
||||
0xC7, 0xFF, 0x9F, 0xFD, 0x3F, 0xFC, 0x0F, 0xFF, 0x0F, 0xFE, 0x37, 0xFC,
|
||||
0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00,
|
||||
0x38, 0x00, 0x70, 0x00, 0x6F, 0xFC, 0x6F, 0xFD, 0x70, 0x07, 0x70, 0x07,
|
||||
0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x0E,
|
||||
0x7F, 0xFE, 0x7F, 0xFA, 0x3F, 0xFC, 0x1F, 0xFE, 0x1F, 0xFD, 0x6F, 0xFB,
|
||||
0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07,
|
||||
0x70, 0x0E, 0xE0, 0x06, 0xC0, 0x02, 0x00, 0x02, 0x00, 0x0E, 0x00, 0x0E,
|
||||
0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x1C,
|
||||
0x00, 0x0C, 0x00, 0x04, 0x0F, 0xFF, 0x07, 0xFF, 0x4D, 0xFF, 0x67, 0x00,
|
||||
0x73, 0x80, 0x39, 0xC0, 0x1C, 0xE0, 0x0E, 0x70, 0x07, 0x38, 0x03, 0x9C,
|
||||
0x03, 0x9C, 0x00, 0xCD, 0xFF, 0xA6, 0xFF, 0xD3, 0x80, 0x39, 0xC0, 0x1C,
|
||||
0xE0, 0x0E, 0x70, 0x07, 0x38, 0x03, 0x9C, 0x01, 0xCE, 0x00, 0xE7, 0x00,
|
||||
0xE3, 0xFF, 0xF1, 0xFF, 0xE8, 0x7F, 0xF8, 0x1F, 0xFE, 0x1F, 0xFD, 0x6F,
|
||||
0xFB, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70,
|
||||
0x07, 0x70, 0x0E, 0xE0, 0x06, 0xDF, 0xFA, 0x1F, 0xFA, 0x00, 0x0E, 0x00,
|
||||
0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00,
|
||||
0x1C, 0x3F, 0xFC, 0x7F, 0xF4, 0x7F, 0xF8, 0x37, 0x30, 0x00, 0x00, 0x00,
|
||||
0x6E, 0x60, 0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C,
|
||||
0x18, 0x30, 0x60, 0xFF, 0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83,
|
||||
0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60,
|
||||
0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFF, 0x06, 0x0C, 0x18,
|
||||
0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFF, 0x06,
|
||||
0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF,
|
||||
0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30,
|
||||
0x60, 0xFF, 0x0F, 0xFF, 0x07, 0xFF, 0x4D, 0xFF, 0x67, 0x00, 0x73, 0x80,
|
||||
0x39, 0xC0, 0x1C, 0xE0, 0x0E, 0x70, 0x07, 0x38, 0x03, 0x9C, 0x03, 0x9C,
|
||||
0x00, 0xCD, 0xFF, 0xA6, 0xFF, 0xD3, 0x80, 0x39, 0xC0, 0x1C, 0xE0, 0x0E,
|
||||
0x70, 0x07, 0x38, 0x03, 0x9C, 0x01, 0xCE, 0x00, 0xE7, 0x00, 0xE3, 0x00,
|
||||
0x31, 0x00, 0x08, 0x00, 0x00, 0x30, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38,
|
||||
0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x70, 0x00, 0x6F,
|
||||
0xFC, 0x6F, 0xFD, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70,
|
||||
0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x0E, 0x7F, 0xFE, 0x7F, 0xFA, 0x3F,
|
||||
0xFC, 0x0F, 0xFD, 0xBF, 0xF7, 0x00, 0x1C, 0x00, 0x70, 0x01, 0xC0, 0x07,
|
||||
0x00, 0x1C, 0x00, 0x70, 0x01, 0xC0, 0x07, 0xFF, 0x9F, 0xFE, 0x3F, 0xFC,
|
||||
0x00, 0x00, 0x80, 0x00, 0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00,
|
||||
0x1C, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x07, 0x00, 0x01, 0x83, 0xFF, 0x4D,
|
||||
0xFF, 0xA7, 0x00, 0x73, 0x80, 0x39, 0xC0, 0x1C, 0xE0, 0x0E, 0x70, 0x07,
|
||||
0x38, 0x03, 0x9C, 0x01, 0xCE, 0x01, 0xC7, 0xFF, 0xE3, 0xFF, 0xD0, 0xFF,
|
||||
0xF0, 0x0F, 0xFF, 0x0F, 0xFE, 0x37, 0xFC, 0x38, 0x00, 0x38, 0x00, 0x38,
|
||||
0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x70, 0x00, 0x6F,
|
||||
0xFC, 0x6F, 0xFC, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70,
|
||||
0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x7F, 0xF8, 0x7F, 0xF8, 0x3F,
|
||||
0xFC, 0x0F, 0xFF, 0x0F, 0xFE, 0x37, 0xFC, 0x38, 0x00, 0x38, 0x00, 0x38,
|
||||
0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x70, 0x00, 0x6F,
|
||||
0xFC, 0x6F, 0xFC, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70,
|
||||
0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x60, 0x00, 0x40, 0x00, 0x0F,
|
||||
0xFF, 0x0F, 0xFE, 0x37, 0xFC, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38,
|
||||
0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x70, 0x00, 0x60, 0x00, 0x60,
|
||||
0x01, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70,
|
||||
0x07, 0x70, 0x07, 0x70, 0x0E, 0x7F, 0xFE, 0x7F, 0xFA, 0x3F, 0xFC, 0x00,
|
||||
0x00, 0x30, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38,
|
||||
0x00, 0x38, 0x00, 0x38, 0x00, 0x70, 0x00, 0x6F, 0xFC, 0x6F, 0xFD, 0x70,
|
||||
0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70,
|
||||
0x07, 0x70, 0x0E, 0x60, 0x06, 0x40, 0x02, 0x17, 0x77, 0x77, 0x77, 0xE6,
|
||||
0x20, 0x00, 0x00, 0x80, 0x00, 0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00, 0x38,
|
||||
0x00, 0x1C, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x07, 0x00, 0x01, 0x80, 0x00,
|
||||
0x4C, 0x00, 0x27, 0x00, 0x73, 0x80, 0x39, 0xC0, 0x1C, 0xE0, 0x0E, 0x70,
|
||||
0x07, 0x38, 0x03, 0x9C, 0x01, 0xCE, 0x01, 0xC7, 0xFF, 0xE3, 0xFF, 0xD0,
|
||||
0xFF, 0xF0, 0x0F, 0xFF, 0x0F, 0xFE, 0x37, 0xFC, 0x38, 0x00, 0x38, 0x00,
|
||||
0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x70, 0x00,
|
||||
0x6F, 0xFC, 0x6F, 0xFD, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07,
|
||||
0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x0E, 0x60, 0x06, 0x40, 0x02,
|
||||
0x00, 0x00, 0xC0, 0x03, 0x80, 0x0E, 0x00, 0x38, 0x00, 0xE0, 0x03, 0x80,
|
||||
0x0E, 0x00, 0x38, 0x01, 0xC0, 0x06, 0x00, 0x18, 0x00, 0x70, 0x01, 0xC0,
|
||||
0x07, 0x00, 0x1C, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, 0x1C, 0x00, 0x7F,
|
||||
0xF9, 0xFF, 0xE3, 0xFF, 0xC0, 0x0F, 0xFF, 0x07, 0xFF, 0x4D, 0xFF, 0x67,
|
||||
0x00, 0x73, 0x80, 0x39, 0xC0, 0x1C, 0xE0, 0x0E, 0x70, 0x07, 0x38, 0x03,
|
||||
0x9C, 0x03, 0x9C, 0x00, 0xCC, 0x00, 0x26, 0x00, 0x13, 0x80, 0x39, 0xC0,
|
||||
0x1C, 0xE0, 0x0E, 0x70, 0x07, 0x38, 0x03, 0x9C, 0x01, 0xCE, 0x00, 0xE7,
|
||||
0x00, 0xE3, 0x00, 0x31, 0x00, 0x08, 0x0F, 0xFC, 0x6F, 0xFD, 0x70, 0x07,
|
||||
0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07,
|
||||
0x70, 0x0E, 0x60, 0x06, 0x40, 0x02, 0x0F, 0xFC, 0x6F, 0xFD, 0x70, 0x07,
|
||||
0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07,
|
||||
0x70, 0x0E, 0x7F, 0xFE, 0x7F, 0xFA, 0x3F, 0xFC, 0x0F, 0xFF, 0x07, 0xFF,
|
||||
0x4D, 0xFF, 0x67, 0x00, 0x73, 0x80, 0x39, 0xC0, 0x1C, 0xE0, 0x0E, 0x70,
|
||||
0x07, 0x38, 0x03, 0x9C, 0x03, 0x9C, 0x00, 0xCD, 0xFF, 0xA6, 0xFF, 0xC3,
|
||||
0x80, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00,
|
||||
0x0E, 0x00, 0x07, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x1F, 0xFE, 0x1F,
|
||||
0xFD, 0x6F, 0xFB, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70,
|
||||
0x07, 0x70, 0x07, 0x70, 0x0E, 0xE0, 0x06, 0xDF, 0xFA, 0x1F, 0xFA, 0x00,
|
||||
0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00,
|
||||
0x0E, 0x00, 0x1C, 0x00, 0x0C, 0x00, 0x04, 0x0F, 0xFD, 0xBF, 0xF7, 0x00,
|
||||
0x1C, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, 0x1C, 0x00, 0x70, 0x01, 0xC0,
|
||||
0x06, 0x00, 0x10, 0x00, 0x00, 0x00, 0xC0, 0x01, 0xC0, 0x03, 0x80, 0x07,
|
||||
0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x01, 0xC0, 0x03, 0x7F,
|
||||
0xE0, 0xFF, 0xD0, 0x00, 0xE0, 0x01, 0xC0, 0x03, 0x80, 0x07, 0x00, 0x0E,
|
||||
0x00, 0x1C, 0x00, 0x38, 0x00, 0xE3, 0xFF, 0xCF, 0xFE, 0x9F, 0xFE, 0x00,
|
||||
0x00, 0x00, 0xC0, 0x03, 0x80, 0x0E, 0x00, 0x38, 0x00, 0xE0, 0x03, 0x80,
|
||||
0x0E, 0x00, 0x38, 0x01, 0xC0, 0x06, 0xFF, 0xDB, 0xFF, 0x70, 0x01, 0xC0,
|
||||
0x07, 0x00, 0x1C, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, 0x1C, 0x00, 0x7F,
|
||||
0xF9, 0xFF, 0xE3, 0xFF, 0xC0, 0x60, 0x01, 0x70, 0x07, 0x70, 0x07, 0x70,
|
||||
0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x0E, 0x7F,
|
||||
0xFE, 0x7F, 0xFA, 0x3F, 0xFC, 0x00, 0x00, 0x98, 0x00, 0xCE, 0x00, 0xE7,
|
||||
0x00, 0x73, 0x80, 0x39, 0xC0, 0x1C, 0xE0, 0x0E, 0x70, 0x07, 0x38, 0x07,
|
||||
0x38, 0x01, 0x98, 0x00, 0x4C, 0x00, 0x27, 0x00, 0x73, 0x80, 0x39, 0xC0,
|
||||
0x1C, 0xE0, 0x0E, 0x70, 0x07, 0x38, 0x03, 0x9C, 0x01, 0xCE, 0x01, 0xC7,
|
||||
0xFF, 0xE3, 0xFF, 0xD0, 0xFF, 0xF0, 0x00, 0x00, 0x98, 0x00, 0xCE, 0x00,
|
||||
0xE7, 0x00, 0x73, 0x80, 0x39, 0xC0, 0x1C, 0xE0, 0x0E, 0x70, 0x07, 0x38,
|
||||
0x07, 0x38, 0x01, 0x9B, 0xFF, 0x4D, 0xFF, 0xA7, 0x00, 0x73, 0x80, 0x39,
|
||||
0xC0, 0x1C, 0xE0, 0x0E, 0x70, 0x07, 0x38, 0x03, 0x9C, 0x01, 0xCE, 0x01,
|
||||
0xC7, 0xFF, 0xE3, 0xFF, 0xD0, 0xFF, 0xF0, 0x00, 0x00, 0x98, 0x00, 0xCE,
|
||||
0x00, 0xE7, 0x00, 0x73, 0x80, 0x39, 0xC0, 0x1C, 0xE0, 0x0E, 0x70, 0x07,
|
||||
0x38, 0x07, 0x38, 0x01, 0x9B, 0xFF, 0x4D, 0xFF, 0xA7, 0x00, 0x73, 0x80,
|
||||
0x39, 0xC0, 0x1C, 0xE0, 0x0E, 0x70, 0x07, 0x38, 0x03, 0x9C, 0x01, 0xCE,
|
||||
0x01, 0xC6, 0x00, 0x62, 0x00, 0x10, 0x00, 0x01, 0x60, 0x03, 0x70, 0x07,
|
||||
0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x0E,
|
||||
0xE0, 0x06, 0xDF, 0xFA, 0x1F, 0xFA, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E,
|
||||
0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x1C, 0x3F, 0xFC,
|
||||
0x7F, 0xF4, 0x7F, 0xF8, 0x0F, 0xFF, 0x07, 0xFF, 0x41, 0xFF, 0x60, 0x00,
|
||||
0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x03, 0x80,
|
||||
0x03, 0x80, 0x00, 0xC0, 0x00, 0x26, 0x00, 0x03, 0x80, 0x01, 0xC0, 0x00,
|
||||
0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x07, 0x00,
|
||||
0x03, 0xFF, 0xC1, 0xFF, 0xE0, 0x7F, 0xF8, 0xFF, 0x06, 0x0C, 0x18, 0x30,
|
||||
0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFF, 0x06, 0x0C,
|
||||
0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFF,
|
||||
0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60,
|
||||
0xFF, 0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18,
|
||||
0x30, 0x60, 0xFF, 0x3F, 0xF3, 0xFF, 0x9F, 0xFE, 0xFF, 0x06, 0x0C, 0x18,
|
||||
0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF, 0x0F, 0xFF,
|
||||
0x07, 0xFF, 0x4D, 0xFF, 0x67, 0x00, 0x73, 0x80, 0x39, 0xC0, 0x1C, 0xE0,
|
||||
0x0E, 0x70, 0x07, 0x38, 0x03, 0x9C, 0x03, 0x9C, 0x00, 0xCD, 0xFF, 0xA6,
|
||||
0xFF, 0xD3, 0x80, 0x39, 0xC0, 0x1C, 0xE0, 0x0E, 0x70, 0x07, 0x38, 0x03,
|
||||
0x9C, 0x01, 0xCE, 0x00, 0xE7, 0x00, 0xE3, 0x00, 0x31, 0x00, 0x08, 0x00,
|
||||
0x00, 0x30, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38,
|
||||
0x00, 0x38, 0x00, 0x38, 0x00, 0x70, 0x00, 0x6F, 0xFC, 0x6F, 0xFD, 0x70,
|
||||
0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70,
|
||||
0x07, 0x70, 0x0E, 0x7F, 0xFE, 0x7F, 0xFA, 0x3F, 0xFC, 0x0F, 0xFD, 0xBF,
|
||||
0xF7, 0x00, 0x1C, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, 0x1C, 0x00, 0x70,
|
||||
0x01, 0xC0, 0x07, 0xFF, 0x9F, 0xFE, 0x3F, 0xFC, 0x00, 0x00, 0x80, 0x00,
|
||||
0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00,
|
||||
0x07, 0x00, 0x07, 0x00, 0x01, 0x83, 0xFF, 0x4D, 0xFF, 0xA7, 0x00, 0x73,
|
||||
0x80, 0x39, 0xC0, 0x1C, 0xE0, 0x0E, 0x70, 0x07, 0x38, 0x03, 0x9C, 0x01,
|
||||
0xCE, 0x01, 0xC7, 0xFF, 0xE3, 0xFF, 0xD0, 0xFF, 0xF0, 0x0F, 0xFF, 0x0F,
|
||||
0xFE, 0x37, 0xFC, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38,
|
||||
0x00, 0x38, 0x00, 0x38, 0x00, 0x70, 0x00, 0x6F, 0xFC, 0x6F, 0xFC, 0x70,
|
||||
0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70,
|
||||
0x00, 0x70, 0x00, 0x7F, 0xF8, 0x7F, 0xF8, 0x3F, 0xFC, 0x0F, 0xFF, 0x0F,
|
||||
0xFE, 0x37, 0xFC, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38,
|
||||
0x00, 0x38, 0x00, 0x38, 0x00, 0x70, 0x00, 0x6F, 0xFC, 0x6F, 0xFC, 0x70,
|
||||
0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70,
|
||||
0x00, 0x70, 0x00, 0x60, 0x00, 0x40, 0x00, 0x0F, 0xFF, 0x0F, 0xFE, 0x37,
|
||||
0xFC, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38,
|
||||
0x00, 0x38, 0x00, 0x70, 0x00, 0x60, 0x00, 0x60, 0x01, 0x70, 0x07, 0x70,
|
||||
0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70,
|
||||
0x0E, 0x7F, 0xFE, 0x7F, 0xFA, 0x3F, 0xFC, 0x00, 0x00, 0x30, 0x00, 0x38,
|
||||
0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38,
|
||||
0x00, 0x70, 0x00, 0x6F, 0xFC, 0x6F, 0xFD, 0x70, 0x07, 0x70, 0x07, 0x70,
|
||||
0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x0E, 0x60,
|
||||
0x06, 0x40, 0x02, 0x17, 0x77, 0x77, 0x77, 0xE6, 0x20, 0x00, 0x00, 0x80,
|
||||
0x00, 0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E,
|
||||
0x00, 0x07, 0x00, 0x07, 0x00, 0x01, 0x80, 0x00, 0x4C, 0x00, 0x27, 0x00,
|
||||
0x73, 0x80, 0x39, 0xC0, 0x1C, 0xE0, 0x0E, 0x70, 0x07, 0x38, 0x03, 0x9C,
|
||||
0x01, 0xCE, 0x01, 0xC7, 0xFF, 0xE3, 0xFF, 0xD0, 0xFF, 0xF0, 0x0F, 0xFF,
|
||||
0x0F, 0xFE, 0x37, 0xFC, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00,
|
||||
0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x70, 0x00, 0x6F, 0xFC, 0x6F, 0xFD,
|
||||
0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07,
|
||||
0x70, 0x07, 0x70, 0x0E, 0x60, 0x06, 0x40, 0x02, 0x00, 0x00, 0xC0, 0x03,
|
||||
0x80, 0x0E, 0x00, 0x38, 0x00, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0x38, 0x01,
|
||||
0xC0, 0x06, 0x00, 0x18, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, 0x1C, 0x00,
|
||||
0x70, 0x01, 0xC0, 0x07, 0x00, 0x1C, 0x00, 0x7F, 0xF9, 0xFF, 0xE3, 0xFF,
|
||||
0xC0, 0x0F, 0xFF, 0x07, 0xFF, 0x4D, 0xFF, 0x67, 0x00, 0x73, 0x80, 0x39,
|
||||
0xC0, 0x1C, 0xE0, 0x0E, 0x70, 0x07, 0x38, 0x03, 0x9C, 0x03, 0x9C, 0x00,
|
||||
0xCC, 0x00, 0x26, 0x00, 0x13, 0x80, 0x39, 0xC0, 0x1C, 0xE0, 0x0E, 0x70,
|
||||
0x07, 0x38, 0x03, 0x9C, 0x01, 0xCE, 0x00, 0xE7, 0x00, 0xE3, 0x00, 0x31,
|
||||
0x00, 0x08, 0x0F, 0xFC, 0x6F, 0xFD, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07,
|
||||
0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x0E, 0x60, 0x06,
|
||||
0x40, 0x02, 0x0F, 0xFC, 0x6F, 0xFD, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07,
|
||||
0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x0E, 0x7F, 0xFE,
|
||||
0x7F, 0xFA, 0x3F, 0xFC, 0x0F, 0xFF, 0x07, 0xFF, 0x4D, 0xFF, 0x67, 0x00,
|
||||
0x73, 0x80, 0x39, 0xC0, 0x1C, 0xE0, 0x0E, 0x70, 0x07, 0x38, 0x03, 0x9C,
|
||||
0x03, 0x9C, 0x00, 0xCD, 0xFF, 0xA6, 0xFF, 0xC3, 0x80, 0x01, 0xC0, 0x00,
|
||||
0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x07, 0x00,
|
||||
0x03, 0x00, 0x01, 0x00, 0x00, 0x1F, 0xFE, 0x1F, 0xFD, 0x6F, 0xFB, 0x70,
|
||||
0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70,
|
||||
0x0E, 0xE0, 0x06, 0xDF, 0xFA, 0x1F, 0xFA, 0x00, 0x0E, 0x00, 0x0E, 0x00,
|
||||
0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x1C, 0x00,
|
||||
0x0C, 0x00, 0x04, 0x0F, 0xFD, 0xBF, 0xF7, 0x00, 0x1C, 0x00, 0x70, 0x01,
|
||||
0xC0, 0x07, 0x00, 0x1C, 0x00, 0x70, 0x01, 0xC0, 0x06, 0x00, 0x10, 0x00,
|
||||
0x00, 0x00, 0xC0, 0x01, 0xC0, 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x1C,
|
||||
0x00, 0x38, 0x00, 0x70, 0x01, 0xC0, 0x03, 0x7F, 0xE0, 0xFF, 0xD0, 0x00,
|
||||
0xE0, 0x01, 0xC0, 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38,
|
||||
0x00, 0xE3, 0xFF, 0xCF, 0xFE, 0x9F, 0xFE, 0x00, 0x00, 0x00, 0xC0, 0x03,
|
||||
0x80, 0x0E, 0x00, 0x38, 0x00, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0x38, 0x01,
|
||||
0xC0, 0x06, 0xFF, 0xDB, 0xFF, 0x70, 0x01, 0xC0, 0x07, 0x00, 0x1C, 0x00,
|
||||
0x70, 0x01, 0xC0, 0x07, 0x00, 0x1C, 0x00, 0x7F, 0xF9, 0xFF, 0xE3, 0xFF,
|
||||
0xC0, 0x60, 0x01, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70,
|
||||
0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x0E, 0x7F, 0xFE, 0x7F, 0xFA, 0x3F,
|
||||
0xFC, 0x00, 0x00, 0x98, 0x00, 0xCE, 0x00, 0xE7, 0x00, 0x73, 0x80, 0x39,
|
||||
0xC0, 0x1C, 0xE0, 0x0E, 0x70, 0x07, 0x38, 0x07, 0x38, 0x01, 0x98, 0x00,
|
||||
0x4C, 0x00, 0x27, 0x00, 0x73, 0x80, 0x39, 0xC0, 0x1C, 0xE0, 0x0E, 0x70,
|
||||
0x07, 0x38, 0x03, 0x9C, 0x01, 0xCE, 0x01, 0xC7, 0xFF, 0xE3, 0xFF, 0xD0,
|
||||
0xFF, 0xF0, 0x00, 0x00, 0x98, 0x00, 0xCE, 0x00, 0xE7, 0x00, 0x73, 0x80,
|
||||
0x39, 0xC0, 0x1C, 0xE0, 0x0E, 0x70, 0x07, 0x38, 0x07, 0x38, 0x01, 0x9B,
|
||||
0xFF, 0x4D, 0xFF, 0xA7, 0x00, 0x73, 0x80, 0x39, 0xC0, 0x1C, 0xE0, 0x0E,
|
||||
0x70, 0x07, 0x38, 0x03, 0x9C, 0x01, 0xCE, 0x01, 0xC7, 0xFF, 0xE3, 0xFF,
|
||||
0xD0, 0xFF, 0xF0, 0x00, 0x00, 0x98, 0x00, 0xCE, 0x00, 0xE7, 0x00, 0x73,
|
||||
0x80, 0x39, 0xC0, 0x1C, 0xE0, 0x0E, 0x70, 0x07, 0x38, 0x07, 0x38, 0x01,
|
||||
0x9B, 0xFF, 0x4D, 0xFF, 0xA7, 0x00, 0x73, 0x80, 0x39, 0xC0, 0x1C, 0xE0,
|
||||
0x0E, 0x70, 0x07, 0x38, 0x03, 0x9C, 0x01, 0xCE, 0x01, 0xC6, 0x00, 0x62,
|
||||
0x00, 0x10, 0x00, 0x01, 0x60, 0x03, 0x70, 0x07, 0x70, 0x07, 0x70, 0x07,
|
||||
0x70, 0x07, 0x70, 0x07, 0x70, 0x07, 0x70, 0x0E, 0xE0, 0x06, 0xDF, 0xFA,
|
||||
0x1F, 0xFA, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E,
|
||||
0x00, 0x0E, 0x00, 0x0E, 0x00, 0x1C, 0x3F, 0xFC, 0x7F, 0xF4, 0x7F, 0xF8,
|
||||
0x0F, 0xFF, 0x07, 0xFF, 0x41, 0xFF, 0x60, 0x00, 0x70, 0x00, 0x38, 0x00,
|
||||
0x1C, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x03, 0x80, 0x03, 0x80, 0x00, 0xC0,
|
||||
0x00, 0x26, 0x00, 0x03, 0x80, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00,
|
||||
0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x03, 0xFF, 0xC1, 0xFF,
|
||||
0xE0, 0x7F, 0xF8, 0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06,
|
||||
0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1,
|
||||
0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFF, 0x06, 0x0C, 0x18, 0x30,
|
||||
0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFF, 0x06, 0x0C,
|
||||
0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xFF };
|
||||
|
||||
const GFXglyph DSEG7Classic_BoldItalic12pt7bGlyphs[] PROGMEM = {
|
||||
{ 0, 0, 0, 5, 0, 1 }, // 0x20 ' '
|
||||
{ 0, 0, 0, 20, 0, 1 }, // 0x21 '!'
|
||||
{ 0, 7, 16, 9, 1, -15 }, // 0x22 '"'
|
||||
{ 14, 7, 16, 9, 1, -15 }, // 0x23 '#'
|
||||
{ 28, 7, 16, 9, 1, -15 }, // 0x24 '$'
|
||||
{ 42, 7, 16, 9, 1, -15 }, // 0x25 '%'
|
||||
{ 56, 7, 16, 9, 1, -15 }, // 0x26 '&'
|
||||
{ 70, 7, 16, 9, 1, -15 }, // 0x27 '''
|
||||
{ 84, 7, 16, 9, 1, -15 }, // 0x28 '('
|
||||
{ 98, 7, 16, 9, 1, -15 }, // 0x29 ')'
|
||||
{ 112, 7, 16, 9, 1, -15 }, // 0x2A '*'
|
||||
{ 126, 7, 16, 9, 1, -15 }, // 0x2B '+'
|
||||
{ 140, 7, 16, 9, 1, -15 }, // 0x2C ','
|
||||
{ 154, 11, 2, 20, 4, -12 }, // 0x2D '-'
|
||||
{ 157, 3, 3, 0, -3, -2 }, // 0x2E '.'
|
||||
{ 159, 7, 16, 9, 1, -15 }, // 0x2F '/'
|
||||
{ 173, 17, 24, 20, 1, -23 }, // 0x30 '0'
|
||||
{ 224, 5, 22, 20, 13, -22 }, // 0x31 '1'
|
||||
{ 238, 17, 24, 20, 1, -23 }, // 0x32 '2'
|
||||
{ 289, 16, 24, 20, 2, -23 }, // 0x33 '3'
|
||||
{ 337, 16, 22, 20, 2, -22 }, // 0x34 '4'
|
||||
{ 381, 15, 24, 20, 2, -23 }, // 0x35 '5'
|
||||
{ 426, 16, 24, 20, 1, -23 }, // 0x36 '6'
|
||||
{ 474, 16, 23, 20, 2, -23 }, // 0x37 '7'
|
||||
{ 520, 17, 24, 20, 1, -23 }, // 0x38 '8'
|
||||
{ 571, 16, 24, 20, 2, -23 }, // 0x39 '9'
|
||||
{ 619, 4, 13, 5, 0, -17 }, // 0x3A ':'
|
||||
{ 626, 7, 16, 9, 1, -15 }, // 0x3B ';'
|
||||
{ 640, 7, 16, 9, 1, -15 }, // 0x3C '<'
|
||||
{ 654, 7, 16, 9, 1, -15 }, // 0x3D '='
|
||||
{ 668, 7, 16, 9, 1, -15 }, // 0x3E '>'
|
||||
{ 682, 7, 16, 9, 1, -15 }, // 0x3F '?'
|
||||
{ 696, 7, 16, 9, 1, -15 }, // 0x40 '@'
|
||||
{ 710, 17, 23, 20, 1, -23 }, // 0x41 'A'
|
||||
{ 759, 16, 23, 20, 1, -22 }, // 0x42 'B'
|
||||
{ 805, 14, 13, 20, 1, -12 }, // 0x43 'C'
|
||||
{ 828, 17, 23, 20, 1, -22 }, // 0x44 'D'
|
||||
{ 877, 16, 24, 20, 1, -23 }, // 0x45 'E'
|
||||
{ 925, 16, 23, 20, 1, -23 }, // 0x46 'F'
|
||||
{ 971, 16, 24, 20, 1, -23 }, // 0x47 'G'
|
||||
{ 1019, 16, 22, 20, 1, -22 }, // 0x48 'H'
|
||||
{ 1063, 4, 11, 20, 13, -11 }, // 0x49 'I'
|
||||
{ 1069, 17, 23, 20, 1, -22 }, // 0x4A 'J'
|
||||
{ 1118, 16, 23, 20, 1, -23 }, // 0x4B 'K'
|
||||
{ 1164, 14, 23, 20, 1, -22 }, // 0x4C 'L'
|
||||
{ 1205, 17, 23, 20, 1, -23 }, // 0x4D 'M'
|
||||
{ 1254, 16, 12, 20, 1, -12 }, // 0x4E 'N'
|
||||
{ 1278, 16, 13, 20, 1, -12 }, // 0x4F 'O'
|
||||
{ 1304, 17, 23, 20, 1, -23 }, // 0x50 'P'
|
||||
{ 1353, 16, 23, 20, 2, -23 }, // 0x51 'Q'
|
||||
{ 1399, 14, 12, 20, 1, -12 }, // 0x52 'R'
|
||||
{ 1420, 15, 23, 20, 2, -22 }, // 0x53 'S'
|
||||
{ 1464, 14, 23, 20, 1, -22 }, // 0x54 'T'
|
||||
{ 1505, 16, 12, 20, 1, -11 }, // 0x55 'U'
|
||||
{ 1529, 17, 23, 20, 1, -22 }, // 0x56 'V'
|
||||
{ 1578, 17, 23, 20, 1, -22 }, // 0x57 'W'
|
||||
{ 1627, 17, 22, 20, 1, -22 }, // 0x58 'X'
|
||||
{ 1674, 16, 23, 20, 2, -22 }, // 0x59 'Y'
|
||||
{ 1720, 17, 24, 20, 1, -23 }, // 0x5A 'Z'
|
||||
{ 1771, 7, 16, 9, 1, -15 }, // 0x5B '['
|
||||
{ 1785, 7, 16, 9, 1, -15 }, // 0x5C '\'
|
||||
{ 1799, 7, 16, 9, 1, -15 }, // 0x5D ']'
|
||||
{ 1813, 7, 16, 9, 1, -15 }, // 0x5E '^'
|
||||
{ 1827, 13, 3, 20, 2, -2 }, // 0x5F '_'
|
||||
{ 1832, 7, 16, 9, 1, -15 }, // 0x60 '`'
|
||||
{ 1846, 17, 23, 20, 1, -23 }, // 0x61 'a'
|
||||
{ 1895, 16, 23, 20, 1, -22 }, // 0x62 'b'
|
||||
{ 1941, 14, 13, 20, 1, -12 }, // 0x63 'c'
|
||||
{ 1964, 17, 23, 20, 1, -22 }, // 0x64 'd'
|
||||
{ 2013, 16, 24, 20, 1, -23 }, // 0x65 'e'
|
||||
{ 2061, 16, 23, 20, 1, -23 }, // 0x66 'f'
|
||||
{ 2107, 16, 24, 20, 1, -23 }, // 0x67 'g'
|
||||
{ 2155, 16, 22, 20, 1, -22 }, // 0x68 'h'
|
||||
{ 2199, 4, 11, 20, 13, -11 }, // 0x69 'i'
|
||||
{ 2205, 17, 23, 20, 1, -22 }, // 0x6A 'j'
|
||||
{ 2254, 16, 23, 20, 1, -23 }, // 0x6B 'k'
|
||||
{ 2300, 14, 23, 20, 1, -22 }, // 0x6C 'l'
|
||||
{ 2341, 17, 23, 20, 1, -23 }, // 0x6D 'm'
|
||||
{ 2390, 16, 12, 20, 1, -12 }, // 0x6E 'n'
|
||||
{ 2414, 16, 13, 20, 1, -12 }, // 0x6F 'o'
|
||||
{ 2440, 17, 23, 20, 1, -23 }, // 0x70 'p'
|
||||
{ 2489, 16, 23, 20, 2, -23 }, // 0x71 'q'
|
||||
{ 2535, 14, 12, 20, 1, -12 }, // 0x72 'r'
|
||||
{ 2556, 15, 23, 20, 2, -22 }, // 0x73 's'
|
||||
{ 2600, 14, 23, 20, 1, -22 }, // 0x74 't'
|
||||
{ 2641, 16, 12, 20, 1, -11 }, // 0x75 'u'
|
||||
{ 2665, 17, 23, 20, 1, -22 }, // 0x76 'v'
|
||||
{ 2714, 17, 23, 20, 1, -22 }, // 0x77 'w'
|
||||
{ 2763, 17, 22, 20, 1, -22 }, // 0x78 'x'
|
||||
{ 2810, 16, 23, 20, 2, -22 }, // 0x79 'y'
|
||||
{ 2856, 17, 24, 20, 1, -23 }, // 0x7A 'z'
|
||||
{ 2907, 7, 16, 9, 1, -15 }, // 0x7B '{'
|
||||
{ 2921, 7, 16, 9, 1, -15 }, // 0x7C '|'
|
||||
{ 2935, 7, 16, 9, 1, -15 }, // 0x7D '}'
|
||||
{ 2949, 7, 16, 9, 1, -15 } }; // 0x7E '~'
|
||||
|
||||
const GFXfont DSEG7Classic_BoldItalic12pt7b PROGMEM = {
|
||||
(uint8_t *)DSEG7Classic_BoldItalic12pt7bBitmaps,
|
||||
(GFXglyph *)DSEG7Classic_BoldItalic12pt7bGlyphs,
|
||||
0x20, 0x7E, 26 };
|
||||
|
||||
// Approx. 3635 bytes
|
||||
@@ -22,6 +22,7 @@ class movingAvg
|
||||
int getCount() { return m_nbrReadings; }
|
||||
void reset();
|
||||
T* getReadings() { return m_readings; }
|
||||
T to2PI(T a);
|
||||
|
||||
private:
|
||||
int m_interval; // number of data points for the moving average
|
||||
@@ -33,6 +34,32 @@ class movingAvg
|
||||
T* m_readings; // pointer to the dynamically allocated interval array
|
||||
};
|
||||
|
||||
// moving average for angle type of data (wind, course, rotation)
|
||||
// makes sense for data types double and float; angle in radians [0..2pi]
|
||||
template <typename T>
|
||||
class movingAvgAngle
|
||||
{
|
||||
public:
|
||||
movingAvgAngle(int interval)
|
||||
: m_interval{interval}, m_nbrReadings{0}, m_sumSin{0}, m_sumCos{0}, m_next{0}, m_buffer{nullptr} {}
|
||||
~movingAvgAngle() { delete[] m_buffer; }
|
||||
void begin();
|
||||
T reading(T newReading);
|
||||
T getAvg();
|
||||
T getAvg(int nPoints);
|
||||
int getCount() { return m_nbrReadings; }
|
||||
void reset();
|
||||
T* getReadings() { return m_buffer; }
|
||||
T to2PI(T a);
|
||||
|
||||
private:
|
||||
int m_interval; // number of data points for the moving average
|
||||
int m_nbrReadings; // number of readings
|
||||
double m_sumSin, m_sumCos; // sum for angle values should always be double for precision reasons, regardless of class type
|
||||
int m_next; // index to the next reading
|
||||
T* m_buffer; // pointer to the dynamically allocated interval array
|
||||
};
|
||||
|
||||
// Include the implementation to satisfy template instantiation requirements
|
||||
#include "movingAvg.tpp"
|
||||
|
||||
|
||||
+100
-5
@@ -5,11 +5,6 @@
|
||||
|
||||
// Extended to template class for handling of multiple data types
|
||||
|
||||
//template <typename T>
|
||||
//movingAvg<T>::movingAvg(int interval)
|
||||
// : m_interval{interval}, m_nbrReadings{0}, m_sum{0}, m_next{0}, m_readings{nullptr}
|
||||
//{}
|
||||
|
||||
// initialize - allocate the interval array
|
||||
template <typename T>
|
||||
void movingAvg<T>::begin()
|
||||
@@ -86,3 +81,103 @@ void movingAvg<T>::reset()
|
||||
m_sum = 0;
|
||||
m_next = 0;
|
||||
}
|
||||
// --- End Class movingAvg ---------------
|
||||
|
||||
// --- Class MovingAvgAngle ---------------
|
||||
template <typename T>
|
||||
void movingAvgAngle<T>::begin()
|
||||
{
|
||||
m_buffer = new T[m_interval];
|
||||
}
|
||||
|
||||
// add a new reading and return the new moving average
|
||||
template <typename T>
|
||||
T movingAvgAngle<T>::reading(T newReading)
|
||||
{
|
||||
double s = std::sin(newReading);
|
||||
double c = std::cos(newReading);
|
||||
|
||||
// add each new data point to the sum until the m_readings array is filled
|
||||
if (m_nbrReadings < m_interval) {
|
||||
++m_nbrReadings;
|
||||
m_sumSin += s;
|
||||
m_sumCos += c;
|
||||
|
||||
} else {
|
||||
// array is filled; subtract the oldest data point and add the new one
|
||||
m_sumSin = m_sumSin - sin(m_buffer[m_next]) + s;
|
||||
m_sumCos = m_sumCos - cos(m_buffer[m_next]) + c;
|
||||
}
|
||||
m_buffer[m_next] = newReading;
|
||||
|
||||
if (++m_next >= m_interval)
|
||||
m_next = 0;
|
||||
|
||||
return getAvg();
|
||||
}
|
||||
|
||||
// return the current moving average
|
||||
template <typename T>
|
||||
T movingAvgAngle<T>::getAvg()
|
||||
{
|
||||
if (m_nbrReadings == 0)
|
||||
return 0;
|
||||
|
||||
// check size of vector; if near 0, set it to 0
|
||||
const double len = m_sumSin * m_sumSin + m_sumCos * m_sumCos;
|
||||
if (len < 1e-24)
|
||||
return 0.0; // average direction undefined
|
||||
|
||||
return static_cast<T>(to2PI(std::atan2(m_sumSin, m_sumCos)));
|
||||
}
|
||||
|
||||
// return the current moving average for a subset of the data, the most recent nPoints readings.
|
||||
// for invalid values of nPoints, return zero.
|
||||
template <typename T>
|
||||
T movingAvgAngle<T>::getAvg(int nPoints)
|
||||
{
|
||||
if (nPoints < 1 || nPoints > m_interval || nPoints > m_nbrReadings)
|
||||
return 0;
|
||||
|
||||
double sumSin = 0.0;
|
||||
double sumCos = 0.0;
|
||||
|
||||
int i = m_next;
|
||||
for (int n = 0; n < nPoints; ++n) {
|
||||
if (i == 0)
|
||||
i = m_interval - 1;
|
||||
else
|
||||
--i;
|
||||
|
||||
sumSin += std::sin(m_buffer[i]);
|
||||
sumCos += std::cos(m_buffer[i]);
|
||||
}
|
||||
|
||||
// check size of vector; if near 0, set it to 0
|
||||
const double len = m_sumSin * m_sumSin + m_sumCos * m_sumCos;
|
||||
if (len < 1e-24)
|
||||
return 0.0; // average direction undefined
|
||||
|
||||
return static_cast<T>(to2PI(std::atan2(sumSin, sumCos)));
|
||||
}
|
||||
|
||||
// start the moving average over again
|
||||
template <typename T>
|
||||
void movingAvgAngle<T>::reset()
|
||||
{
|
||||
m_nbrReadings = 0;
|
||||
m_sumSin = 0;
|
||||
m_sumCos = 0;
|
||||
m_next = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T movingAvgAngle<T>::to2PI(T a)
|
||||
{
|
||||
a = fmod(a, M_TWOPI);
|
||||
if (a < 0.0) {
|
||||
a += M_TWOPI;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
// --- End class MovingAvgAngle ---------------
|
||||
|
||||
+18
-10
@@ -233,6 +233,8 @@ void registerAllPages(PageList &list){
|
||||
list.add(®isterPageClock);
|
||||
extern PageDescription registerPageCompass;
|
||||
list.add(®isterPageCompass);
|
||||
extern PageDescription registerPageCurrent;
|
||||
list.add(®isterPageCurrent);
|
||||
extern PageDescription registerPageWhite;
|
||||
list.add(®isterPageWhite);
|
||||
extern PageDescription registerPageBME280;
|
||||
@@ -263,6 +265,8 @@ void registerAllPages(PageList &list){
|
||||
list.add(®isterPageDigitalOut);
|
||||
extern PageDescription registerPageAutopilot;
|
||||
list.add(®isterPageAutopilot);
|
||||
extern PageDescription registerPageWeather;
|
||||
list.add(®isterPageWeather);
|
||||
}
|
||||
|
||||
// Undervoltage detection for shutdown display
|
||||
@@ -458,6 +462,13 @@ void OBP60Task(GwApi *api){
|
||||
WindUtils trueWind(&boatValues, logger); // Create helper object for true wind calculation
|
||||
CalibrationData calibrationDataList(logger); // all boat data types which are supposed to be calibrated
|
||||
|
||||
// Read user settings from config file
|
||||
bool calcTrueWnds = api->getConfig()->getBool(api->getConfig()->calcTrueWnds, false);
|
||||
bool smoothCharts = api->getConfig()->getBool(api->getConfig()->smoothCharts, false);
|
||||
bool useSimuData = api->getConfig()->getBool(api->getConfig()->useSimuData, false);
|
||||
// Read user calibration data settings from config file
|
||||
calibrationDataList.readConfig(config);
|
||||
|
||||
//fill the page data from config
|
||||
numPages=config->getInt(config->visiblePages,1);
|
||||
if (numPages < 1) numPages=1;
|
||||
@@ -499,26 +510,20 @@ void OBP60Task(GwApi *api){
|
||||
}
|
||||
|
||||
// Read the specified boat data types of relevant pages and create a history buffer for each type for later use in charts
|
||||
// applies only for pages that uses charts
|
||||
if (pages[i].parameters.pageName == "OneValue" || pages[i].parameters.pageName == "TwoValues" || pages[i].parameters.pageName == "WindPlot") {
|
||||
// applies only to pages that uses charts
|
||||
if (pages[i].parameters.pageName == "OneValue" || pages[i].parameters.pageName == "TwoValues"
|
||||
|| pages[i].parameters.pageName == "WindPlot" || pages[i].parameters.pageName == "Weather") {
|
||||
for (auto pVal : pages[i].parameters.values) {
|
||||
hstryBufferList.addBuffer(pVal->getName());
|
||||
hstryBufferList.addBuffer(pVal->getName(), smoothCharts);
|
||||
}
|
||||
}
|
||||
// Add list of history buffers to page parameters
|
||||
pages[i].parameters.hstryBuffers = &hstryBufferList;
|
||||
|
||||
}
|
||||
|
||||
// add out of band system page (always available)
|
||||
Page *syspage = allPages.pages[0]->creator(commonData);
|
||||
|
||||
// Read user settings from config file
|
||||
bool calcTrueWnds = api->getConfig()->getBool(api->getConfig()->calcTrueWnds, false);
|
||||
bool useSimuData = api->getConfig()->getBool(api->getConfig()->useSimuData, false);
|
||||
// Read user calibration data settings from config file
|
||||
calibrationDataList.readConfig(config);
|
||||
|
||||
// Display screenshot handler for HTTP request
|
||||
// http://192.168.15.1/api/user/OBP60Task/screenshot
|
||||
api->registerRequestHandler("screenshot", [api, &pageNumber, pages](AsyncWebServerRequest *request) {
|
||||
@@ -844,9 +849,12 @@ void OBP60Task(GwApi *api){
|
||||
api->getBoatDataValues(boatValues.numValues,boatValues.allBoatValues);
|
||||
api->getStatus(commonData.status);
|
||||
|
||||
// ulong startHandl = millis();
|
||||
trueWind.handleWinds(calcTrueWnds); // calculate true wind data from apparent wind values
|
||||
trueWind.setMaxWs(); // maintain MaxTWS value in any case; invalid TWS value is considered automatically; MaxAWS is provided by core gateway if AWS is available
|
||||
calibrationDataList.handleCalibration(&boatValues); // Process calibration for all boat data in <calibrationDataList>
|
||||
hstryBufferList.handleHstryBufs(useSimuData, commonData); // Handle history buffers for certain boat data for charts and other usage
|
||||
// LOG_DEBUG(GwLog::DEBUG, "obp60task: data handling: %d ms", millis() - startHandl);
|
||||
|
||||
// Clear display
|
||||
// getdisplay().fillRect(0, 0, getdisplay().width(), getdisplay().height(), commonData.bgcolor);
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
diff --git a/lib/api/GwApi.h b/lib/api/GwApi.h
|
||||
index 88f9690..bde7670 100644
|
||||
--- a/lib/api/GwApi.h
|
||||
+++ b/lib/api/GwApi.h
|
||||
@@ -137,6 +137,7 @@ class GwApi{
|
||||
* thread safe methods - can directly be called from a user task
|
||||
*/
|
||||
virtual GwRequestQueue *getQueue()=0;
|
||||
+ virtual QueueHandle_t getKbQueue()=0;
|
||||
virtual void sendN2kMessage(const tN2kMsg &msg, bool convert=true)=0;
|
||||
/**
|
||||
* deprecated - sourceId will be ignored
|
||||
diff --git a/lib/config/GwConverterConfig.h b/lib/config/GwConverterConfig.h
|
||||
index 4a93a71..34ed7bf 100644
|
||||
--- a/lib/config/GwConverterConfig.h
|
||||
+++ b/lib/config/GwConverterConfig.h
|
||||
@@ -71,6 +71,7 @@ class GwConverterConfig{
|
||||
int rmcInterval=1000;
|
||||
int rmcCheckTime=4000;
|
||||
int winst312=256;
|
||||
+ int swBankInstance=0;
|
||||
bool unmappedXdr=false;
|
||||
unsigned long xdrTimeout=60000;
|
||||
std::vector<WindMapping> windMappings;
|
||||
@@ -113,4 +114,4 @@ class GwConverterConfig{
|
||||
|
||||
|
||||
};
|
||||
-#endif
|
||||
\ No newline at end of file
|
||||
+#endif
|
||||
diff --git a/lib/nmea2kto0183/N2kDataToNMEA0183.cpp b/lib/nmea2kto0183/N2kDataToNMEA0183.cpp
|
||||
index dbf6af5..9fe405b 100644
|
||||
--- a/lib/nmea2kto0183/N2kDataToNMEA0183.cpp
|
||||
+++ b/lib/nmea2kto0183/N2kDataToNMEA0183.cpp
|
||||
@@ -1572,6 +1572,29 @@ private:
|
||||
finalizeXdr();
|
||||
}
|
||||
|
||||
+ void Handle127502(const tN2kMsg &msg){
|
||||
+ // switch bank control / receive remote key strokes
|
||||
+ unsigned char instance=-1;
|
||||
+ tN2kBinaryStatus bankstatus;
|
||||
+ LOG_DEBUG(GwLog::LOG,"received switch bank control");
|
||||
+ // check if we are addressed and our configured instance is used
|
||||
+ if (! ParseN2kPGN127502(msg,instance,bankstatus)) {
|
||||
+ LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN);
|
||||
+ return;
|
||||
+ }
|
||||
+ if (! (instance == config.swBankInstance)) {
|
||||
+ LOG_DEBUG(GwLog::DEBUG,"switch bank instance #%d ignored",instance);
|
||||
+ return;
|
||||
+ }
|
||||
+ for (uint8_t i=1; i<=28; i++) {
|
||||
+ tN2kOnOff keystatus = N2kGetStatusOnBinaryStatus(bankstatus, i);
|
||||
+ if (keystatus == 1) {
|
||||
+ // key pressed: send key to queue
|
||||
+ xQueueSend(keyboardQueue, &i, 0);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
void registerConverters()
|
||||
{
|
||||
//register all converter functions
|
||||
@@ -1607,6 +1630,7 @@ private:
|
||||
converters.registerConverter(127488UL, &N2kToNMEA0183Functions::Handle127488);
|
||||
converters.registerConverter(130316UL, &N2kToNMEA0183Functions::Handle130316);
|
||||
converters.registerConverter(127257UL, &N2kToNMEA0183Functions::Handle127257);
|
||||
+ converters.registerConverter(127502UL, &N2kToNMEA0183Functions::Handle127502);
|
||||
#define HANDLE_AIS
|
||||
#ifdef HANDLE_AIS
|
||||
converters.registerConverter(129038UL, &N2kToNMEA0183Functions::HandleAISClassAPosReport); // AIS Class A Position Report, Message Type 1
|
||||
@@ -1620,13 +1644,15 @@ private:
|
||||
public:
|
||||
N2kToNMEA0183Functions(GwLog *logger, GwBoatData *boatData,
|
||||
SendNMEA0183MessageCallback callback,
|
||||
- String talkerId, GwXDRMappings *xdrMappings, const GwConverterConfig &cfg)
|
||||
+ String talkerId, GwXDRMappings *xdrMappings, const GwConverterConfig &cfg,
|
||||
+ QueueHandle_t kbQueue)
|
||||
: N2kDataToNMEA0183(logger, boatData, callback,talkerId)
|
||||
{
|
||||
this->logger = logger;
|
||||
this->boatData = boatData;
|
||||
this->xdrMappings=xdrMappings;
|
||||
this->config=cfg;
|
||||
+ this->keyboardQueue=kbQueue;
|
||||
registerConverters();
|
||||
}
|
||||
virtual void loop(unsigned long lastExtRmc) override
|
||||
@@ -1642,8 +1668,8 @@ private:
|
||||
|
||||
N2kDataToNMEA0183* N2kDataToNMEA0183::create(GwLog *logger, GwBoatData *boatData,
|
||||
SendNMEA0183MessageCallback callback, String talkerId, GwXDRMappings *xdrMappings,
|
||||
- const GwConverterConfig &cfg){
|
||||
- LOG_DEBUG(GwLog::LOG,"creating N2kToNMEA0183");
|
||||
- return new N2kToNMEA0183Functions(logger,boatData,callback, talkerId,xdrMappings,cfg);
|
||||
+ const GwConverterConfig &cfg, QueueHandle_t kbQueue){
|
||||
+ LOG_DEBUG(GwLog::LOG,"creating N2kToNMEA0183");
|
||||
+ return new N2kToNMEA0183Functions(logger,boatData,callback, talkerId,xdrMappings,cfg,kbQueue);
|
||||
}
|
||||
//*****************************************************************************
|
||||
diff --git a/lib/nmea2kto0183/N2kDataToNMEA0183.h b/lib/nmea2kto0183/N2kDataToNMEA0183.h
|
||||
index 61e8ee2..f7d8c75 100644
|
||||
--- a/lib/nmea2kto0183/N2kDataToNMEA0183.h
|
||||
+++ b/lib/nmea2kto0183/N2kDataToNMEA0183.h
|
||||
@@ -43,6 +43,7 @@ protected:
|
||||
GwBoatData *boatData;
|
||||
int sourceId=0;
|
||||
char talkerId[3];
|
||||
+ QueueHandle_t keyboardQueue;
|
||||
SendNMEA0183MessageCallback sendNMEA0183MessageCallback;
|
||||
void SendMessage(const tNMEA0183Msg &NMEA0183Msg);
|
||||
N2kDataToNMEA0183(GwLog *logger, GwBoatData *boatData,
|
||||
@@ -50,7 +51,8 @@ protected:
|
||||
|
||||
public:
|
||||
static N2kDataToNMEA0183* create(GwLog *logger, GwBoatData *boatData, SendNMEA0183MessageCallback callback,
|
||||
- String talkerId, GwXDRMappings *xdrMappings,const GwConverterConfig &cfg);
|
||||
+ String talkerId, GwXDRMappings *xdrMappings,const GwConverterConfig &cfg,
|
||||
+ QueueHandle_t kbQueue);
|
||||
virtual void HandleMsg(const tN2kMsg &N2kMsg, int sourceId) = 0;
|
||||
virtual void loop(unsigned long lastRmc);
|
||||
virtual ~N2kDataToNMEA0183(){}
|
||||
@@ -59,4 +61,4 @@ public:
|
||||
virtual void toJson(GwJsonDocument *json)=0;
|
||||
virtual String handledKeys()=0;
|
||||
};
|
||||
-#endif
|
||||
\ No newline at end of file
|
||||
+#endif
|
||||
diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp
|
||||
index 1058ae0..ae11a81 100644
|
||||
--- a/lib/obp60task/obp60task.cpp
|
||||
+++ b/lib/obp60task/obp60task.cpp
|
||||
@@ -348,6 +348,8 @@ void OBP60Task(GwApi *api){
|
||||
|
||||
tN2kMsg N2kMsg;
|
||||
|
||||
+ QueueHandle_t keyboardQueue = api->getKbQueue();
|
||||
+
|
||||
LOG_DEBUG(GwLog::LOG,"obp60task started");
|
||||
for (auto it=allPages.pages.begin();it != allPages.pages.end();it++){
|
||||
LOG_DEBUG(GwLog::LOG,"found registered page %s",(*it)->pageName.c_str());
|
||||
@@ -622,7 +624,16 @@ void OBP60Task(GwApi *api){
|
||||
if((String(gpsFix) == "GPS Fix Lost" && hdop->value > hdopAccuracy && hdop->valid == true) || (String(gpsFix) == "GPS Fix Lost" && hdop->valid == false)){
|
||||
setFlashLED(true);
|
||||
}
|
||||
-
|
||||
+
|
||||
+ // Keyboard messages from remote
|
||||
+ uint8_t remotekey = 0;
|
||||
+ if (xQueueReceive(keyboardQueue, &remotekey, 0) == pdPASS) {
|
||||
+ LOG_DEBUG(GwLog::LOG, "OBP received remote key: %d", remotekey);
|
||||
+ // inject into internal keyboard queue
|
||||
+ int injectkey = static_cast<int>(remotekey);
|
||||
+ xQueueSend(allParameters.queue, &injectkey, 0);
|
||||
+ }
|
||||
+
|
||||
// Check the keyboard message
|
||||
int keyboardMessage=0;
|
||||
while (xQueueReceive(allParameters.queue,&keyboardMessage,0)){
|
||||
diff --git a/lib/usercode/GwUserCode.cpp b/lib/usercode/GwUserCode.cpp
|
||||
index 1b007f8..b891422 100644
|
||||
--- a/lib/usercode/GwUserCode.cpp
|
||||
+++ b/lib/usercode/GwUserCode.cpp
|
||||
@@ -189,6 +189,10 @@ public:
|
||||
{
|
||||
return api->getQueue();
|
||||
}
|
||||
+ virtual QueueHandle_t getKbQueue()
|
||||
+ {
|
||||
+ return api->getKbQueue();
|
||||
+ }
|
||||
virtual void sendN2kMessage(const tN2kMsg &msg,bool convert)
|
||||
{
|
||||
GWSYNCHRONIZED(mainLock);
|
||||
@@ -428,4 +432,4 @@ void GwUserCode::handleWebRequest(const String &url,AsyncWebServerRequest *req){
|
||||
}
|
||||
LOG_DEBUG(GwLog::DEBUG,"no task found for web request %s[%s]",url.c_str(),tname.c_str());
|
||||
req->send(404, "text/plain", "not found");
|
||||
-}
|
||||
\ No newline at end of file
|
||||
+}
|
||||
diff --git a/src/main.cpp b/src/main.cpp
|
||||
index 6daaa51..50625d8 100644
|
||||
--- a/src/main.cpp
|
||||
+++ b/src/main.cpp
|
||||
@@ -158,6 +158,8 @@ GwCounter<unsigned long> countNMEA2KIn("countNMEA2000in");
|
||||
GwCounter<unsigned long> countNMEA2KOut("countNMEA2000out");
|
||||
GwIntervalRunner timers;
|
||||
|
||||
+QueueHandle_t keyboardQueue = NULL;
|
||||
+
|
||||
bool checkPass(String hash){
|
||||
return config.checkPass(hash);
|
||||
}
|
||||
@@ -269,6 +271,10 @@ public:
|
||||
{
|
||||
return &mainQueue;
|
||||
}
|
||||
+ virtual QueueHandle_t getKbQueue()
|
||||
+ {
|
||||
+ return keyboardQueue;
|
||||
+ }
|
||||
virtual void sendN2kMessage(const tN2kMsg &msg,bool convert)
|
||||
{
|
||||
handleN2kMessage(msg,sourceId,!convert);
|
||||
@@ -860,6 +866,8 @@ void setup() {
|
||||
webserver.begin();
|
||||
xdrMappings.begin();
|
||||
logger.flush();
|
||||
+ // remote keyboard support
|
||||
+ keyboardQueue = xQueueCreate(10, sizeof(uint8_t));
|
||||
GwConverterConfig converterConfig;
|
||||
converterConfig.init(&config,&logger);
|
||||
nmea0183Converter= N2kDataToNMEA0183::create(&logger, &boatData,
|
||||
@@ -869,7 +877,8 @@ void setup() {
|
||||
,
|
||||
config.getString(config.talkerId,String("GP")),
|
||||
&xdrMappings,
|
||||
- converterConfig
|
||||
+ converterConfig,
|
||||
+ keyboardQueue
|
||||
);
|
||||
|
||||
toN2KConverter= NMEA0183DataToN2K::create(&logger,&boatData,[](const tN2kMsg &msg, int sourceId)->bool{
|
||||
diff --git a/web/config.json b/web/config.json
|
||||
index 26d3166..bef7790 100644
|
||||
--- a/web/config.json
|
||||
+++ b/web/config.json
|
||||
@@ -88,6 +88,16 @@
|
||||
"description":"the brightness of the led (0..255)",
|
||||
"category":"system"
|
||||
},
|
||||
+ {
|
||||
+ "name": "swBankInstance",
|
||||
+ "type": "number",
|
||||
+ "default": 0,
|
||||
+ "min": 0,
|
||||
+ "max": 252,
|
||||
+ "check": "checkMinMax",
|
||||
+ "description": "the instance of switch bank to receive data for (0..252)",
|
||||
+ "category": "system"
|
||||
+ },
|
||||
{
|
||||
"name": "talkerId",
|
||||
"label": "NMEA0183 ID",
|
||||
@@ -1287,4 +1297,4 @@
|
||||
"check": "checkXDR",
|
||||
"category": "xdr30"
|
||||
}
|
||||
-]
|
||||
\ No newline at end of file
|
||||
+]
|
||||
Reference in New Issue
Block a user