1
0
mirror of https://github.com/thooge/esp32-nmea2000-obp60.git synced 2025-12-28 13:13:07 +01:00

5 Commits

Author SHA1 Message Date
norbert-walter
4a273d2c93 Add hibernate in full page refresh 2025-08-12 15:37:22 +02:00
Norbert Walter
9be1b864f4 Merge pull request #192 from thooge/scripts
Automate gen_set.py with page detection and command line parameters
2025-08-12 15:32:51 +02:00
Norbert Walter
bfc4337417 Merge pull request #191 from thooge/precision
Added config option for display precision and formatter code improvement
2025-08-12 15:31:28 +02:00
28a7e58e27 Automate gen_set.py with page detection and command line parameters 2025-08-01 11:01:23 +02:00
eb51092b23 Added config option for display precision and formatter code improvements 2025-07-31 12:31:57 +02:00
14 changed files with 726 additions and 1138 deletions

View File

@@ -1,204 +0,0 @@
/*
Menu system for online configuration
*/
#include "ConfigMenu.h"
ConfigMenuItem::ConfigMenuItem(String itemtype, String itemlabel, uint16_t itemval, String itemunit) {
if (! (itemtype == "int" or itemtype == "bool")) {
valtype = "int";
} else {
valtype = itemtype;
}
label = itemlabel;
min = 0;
max = std::numeric_limits<uint16_t>::max();
value = itemval;
unit = itemunit;
}
void ConfigMenuItem::setRange(uint16_t valmin, uint16_t valmax, std::vector<uint16_t> valsteps) {
min = valmin;
max = valmax;
steps = valsteps;
};
bool ConfigMenuItem::checkRange(uint16_t checkval) {
return (checkval >= min) and (checkval <= max);
}
String ConfigMenuItem::getLabel() {
return label;
};
uint16_t ConfigMenuItem::getValue() {
return value;
}
bool ConfigMenuItem::setValue(uint16_t newval) {
if (valtype == "int") {
if (newval >= min and newval <= max) {
value = newval;
return true;
}
return false; // out of range
} else if (valtype == "bool") {
value = (newval != 0) ? 1 : 0;
return true;
}
return false; // invalid type
};
void ConfigMenuItem::incValue() {
// increase value by step
if (valtype == "int") {
if (value + step < max) {
value += step;
} else {
value = max;
}
} else if (valtype == "bool") {
value = !value;
}
};
void ConfigMenuItem::decValue() {
// decrease value by step
if (valtype == "int") {
if (value - step > min) {
value -= step;
} else {
value = min;
}
} else if (valtype == "bool") {
value = !value;
}
};
String ConfigMenuItem::getUnit() {
return unit;
}
uint16_t ConfigMenuItem::getStep() {
return step;
}
void ConfigMenuItem::setStep(uint16_t newstep) {
if (std::find(steps.begin(), steps.end(), newstep) == steps.end()) {
return; // invalid step: not in list of possible steps
}
step = newstep;
}
int8_t ConfigMenuItem::getPos() {
return position;
};
void ConfigMenuItem::setPos(int8_t newpos) {
position = newpos;
};
String ConfigMenuItem::getType() {
return valtype;
}
ConfigMenu::ConfigMenu(String menutitle, uint16_t menu_x, uint16_t menu_y) {
title = menutitle;
x = menu_x;
y = menu_y;
};
ConfigMenuItem* ConfigMenu::addItem(String key, String label, String valtype, uint16_t val, String valunit) {
if (items.find(key) != items.end()) {
// duplicate keys not allowed
return nullptr;
}
ConfigMenuItem *itm = new ConfigMenuItem(valtype, label, val, valunit);
items.insert(std::pair<String, ConfigMenuItem*>(key, itm));
// Append key to index, index starting with 0
int8_t ix = items.size() - 1;
index[ix] = key;
itm->setPos(ix);
return itm;
};
void ConfigMenu::setItemDimension(uint16_t itemwidth, uint16_t itemheight) {
w = itemwidth;
h = itemheight;
};
void ConfigMenu::setItemActive(String key) {
if (items.find(key) != items.end()) {
activeitem = items[key]->getPos();
} else {
activeitem = -1;
}
};
int8_t ConfigMenu::getActiveIndex() {
return activeitem;
}
ConfigMenuItem* ConfigMenu::getActiveItem() {
if (activeitem < 0) {
return nullptr;
}
return items[index[activeitem]];
};
ConfigMenuItem* ConfigMenu::getItemByIndex(uint8_t ix) {
if (ix > index.size() - 1) {
return nullptr;
}
return items[index[ix]];
};
ConfigMenuItem* ConfigMenu::getItemByKey(String key) {
if (items.find(key) == items.end()) {
return nullptr;
}
return items[key];
};
uint8_t ConfigMenu::getItemCount() {
return items.size();
};
void ConfigMenu::goPrev() {
if (activeitem == 0) {
activeitem = items.size() - 1;
} else {
activeitem--;
}
}
void ConfigMenu::goNext() {
if (activeitem == items.size() - 1) {
activeitem = 0;
} else {
activeitem++;
}
}
Point ConfigMenu::getXY() {
return {static_cast<double>(x), static_cast<double>(y)};
}
Rect ConfigMenu::getRect() {
return {static_cast<double>(x), static_cast<double>(y),
static_cast<double>(w), static_cast<double>(h)};
}
Rect ConfigMenu::getItemRect(int8_t index) {
return {static_cast<double>(x), static_cast<double>(y + index * h),
static_cast<double>(w), static_cast<double>(h)};
}
void ConfigMenu::setCallback(void (*callback)()) {
fptrCallback = callback;
}
void ConfigMenu::storeValues() {
if (fptrCallback) {
fptrCallback();
}
}

View File

@@ -1,66 +0,0 @@
#pragma once
#include <Arduino.h>
#include <vector>
#include <map>
#include "Graphics.h" // for Point and Rect
class ConfigMenuItem {
private:
String label;
uint16_t value;
String unit;
String valtype; // "int" | "bool"
uint16_t min;
uint16_t max;
std::vector<uint16_t> steps;
uint16_t step;
int8_t position; // counted fom 0
public:
ConfigMenuItem(String itemtype, String itemlabel, uint16_t itemval, String itemunit);
void setRange(uint16_t valmin, uint16_t valmax, std::vector<uint16_t> steps);
bool checkRange(uint16_t checkval);
String getLabel();
uint16_t getValue();
bool setValue(uint16_t newval);
void incValue();
void decValue();
String getUnit();
uint16_t getStep();
void setStep(uint16_t newstep);
int8_t getPos();
void setPos(int8_t newpos);
String getType();
};
class ConfigMenu {
private:
String title;
std::map <String,ConfigMenuItem*> items;
std::map <uint8_t,String> index;
int8_t activeitem = -1; // refers to position of item
uint16_t x;
uint16_t y;
uint16_t w;
uint16_t h;
void (*fptrCallback)();
public:
ConfigMenu(String title, uint16_t menu_x, uint16_t menu_y);
ConfigMenuItem* addItem(String key, String label, String valtype, uint16_t val, String valunit);
void setItemDimension(uint16_t itemwidth, uint16_t itemheight);
int8_t getActiveIndex();
void setItemActive(String key);
ConfigMenuItem* getActiveItem();
ConfigMenuItem* getItemByIndex(uint8_t index);
ConfigMenuItem* getItemByKey(String key);
uint8_t getItemCount();
void goPrev();
void goNext();
Point getXY();
Rect getRect();
Rect getItemRect(int8_t index);
void setCallback(void (*callback)());
void storeValues();
};

View File

@@ -1,25 +0,0 @@
/*
Generic graphics functions
*/
#include <math.h>
#include "Graphics.h"
Point rotatePoint(const Point& origin, const Point& p, double angle) {
// rotate poind around origin by degrees
Point rotated;
double phi = angle * M_PI / 180.0;
double dx = p.x - origin.x;
double dy = p.y - origin.y;
rotated.x = origin.x + cos(phi) * dx - sin(phi) * dy;
rotated.y = origin.y + sin(phi) * dx + cos(phi) * dy;
return rotated;
}
std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle) {
std::vector<Point> rotatedPoints;
for (const auto& p : pts) {
rotatedPoints.push_back(rotatePoint(origin, p, angle));
}
return rotatedPoints;
}

View File

@@ -1,17 +0,0 @@
#pragma once
#include <vector>
struct Point {
double x;
double y;
};
struct Rect {
double x;
double y;
double w;
double h;
};
Point rotatePoint(const Point& origin, const Point& p, double angle);
std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle);

View File

@@ -14,30 +14,6 @@ https://controllerstech.com/ws2812-leds-using-spi/
*/ */
String Color::toHex() {
char hexColor[8];
sprintf(hexColor, "#%02X%02X%02X", r, g, b);
return String(hexColor);
}
String Color::toName() {
static std::map<int, String> const names = {
{0xff0000, "Red"},
{0x00ff00, "Green"},
{0x0000ff, "Blue",},
{0xff9900, "Orange"},
{0xffff00, "Yellow"},
{0x3366ff, "Aqua"},
{0xff0066, "Violet"},
{0xffffff, "White"}
};
int color = (r << 16) + (g << 8) + b;
auto it = names.find(color);
if (it == names.end()) {
return toHex();
}
return it->second;
}
static uint8_t mulcolor(uint8_t f1, uint8_t f2){ static uint8_t mulcolor(uint8_t f1, uint8_t f2){
uint16_t rt=f1; uint16_t rt=f1;

View File

@@ -10,7 +10,7 @@ class Color{
uint8_t g; uint8_t g;
uint8_t b; uint8_t b;
Color():r(0),g(0),b(0){} Color():r(0),g(0),b(0){}
Color(uint8_t cr, uint8_t cg, uint8_t cb): Color(uint8_t cr, uint8_t cg,uint8_t cb):
b(cb),g(cg),r(cr){} b(cb),g(cg),r(cr){}
Color(const Color &o):b(o.b),g(o.g),r(o.r){} Color(const Color &o):b(o.b),g(o.g),r(o.r){}
bool equal(const Color &o) const{ bool equal(const Color &o) const{
@@ -22,8 +22,6 @@ class Color{
bool operator != (const Color &other) const{ bool operator != (const Color &other) const{
return ! equal(other); return ! equal(other);
} }
String toHex();
String toName();
}; };
static Color COLOR_GREEN=Color(0,255,0); static Color COLOR_GREEN=Color(0,255,0);

View File

@@ -107,27 +107,6 @@ void hardwareInit(GwApi *api)
} }
} }
void powerInit(String powermode) {
// Max Power | Only 5.0V | Min Power
if (powermode == "Max Power" || powermode == "Only 5.0V") {
#ifdef HARDWARE_V21
setPortPin(OBP_POWER_50, true); // Power on 5.0V rail
#endif
#ifdef BOARD_OBP40S3
setPortPin(OBP_POWER_EPD, true);// Power on ePaper display
setPortPin(OBP_POWER_SD, true); // Power on SD card
#endif
} else { // Min Power
#ifdef HARDWARE_V21
setPortPin(OBP_POWER_50, false); // Power off 5.0V rail
#endif
#ifdef BOARD_OBP40S3
setPortPin(OBP_POWER_EPD, false);// Power off ePaper display
setPortPin(OBP_POWER_SD, false); // Power off SD card
#endif
}
}
void setPortPin(uint pin, bool value){ void setPortPin(uint pin, bool value){
pinMode(pin, OUTPUT); pinMode(pin, OUTPUT);
digitalWrite(pin, value); digitalWrite(pin, value);
@@ -297,20 +276,30 @@ String xdrDelete(String input){
return input; return input;
} }
Point rotatePoint(const Point& origin, const Point& p, double angle) {
// rotate poind around origin by degrees
Point rotated;
double phi = angle * M_PI / 180.0;
double dx = p.x - origin.x;
double dy = p.y - origin.y;
rotated.x = origin.x + cos(phi) * dx - sin(phi) * dy;
rotated.y = origin.y + sin(phi) * dx + cos(phi) * dy;
return rotated;
}
std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle) {
std::vector<Point> rotatedPoints;
for (const auto& p : pts) {
rotatedPoints.push_back(rotatePoint(origin, p, angle));
}
return rotatedPoints;
}
void fillPoly4(const std::vector<Point>& p4, uint16_t color) { void fillPoly4(const std::vector<Point>& p4, uint16_t color) {
getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[1].x, p4[1].y, p4[2].x, p4[2].y, color); getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[1].x, p4[1].y, p4[2].x, p4[2].y, color);
getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[2].x, p4[2].y, p4[3].x, p4[3].y, color); getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[2].x, p4[2].y, p4[3].x, p4[3].y, color);
} }
void drawPoly(const std::vector<Point>& points, uint16_t color) {
size_t polysize = points.size();
for (size_t i = 0; i < polysize - 1; i++) {
getdisplay().drawLine(points[i].x, points[i].y, points[i+1].x, points[i+1].y, color);
}
// close path
getdisplay().drawLine(points[polysize-1].x, points[polysize-1].y, points[0].x, points[0].y, color);
}
// Split string into words, whitespace separated // Split string into words, whitespace separated
std::vector<String> split(const String &s) { std::vector<String> split(const String &s) {
std::vector<String> words; std::vector<String> words;
@@ -372,24 +361,6 @@ void drawTextRalign(int16_t x, int16_t y, String text) {
getdisplay().print(text); getdisplay().print(text);
} }
// Draw text inside box, normal or inverted
void drawTextBoxed(Rect box, String text, uint16_t fg, uint16_t bg, bool inverted, bool border) {
if (inverted) {
getdisplay().fillRect(box.x, box.y, box.w, box.h, fg);
getdisplay().setTextColor(bg);
} else {
if (border) {
getdisplay().fillRect(box.x + 1, box.y + 1, box.w - 2, box.h - 2, bg);
getdisplay().drawRect(box.x, box.y, box.w, box.h, fg);
}
getdisplay().setTextColor(fg);
}
uint16_t border_offset = box.h / 4; // 25% of box height
getdisplay().setCursor(box.x + border_offset, box.y + box.h - border_offset);
getdisplay().print(text);
getdisplay().setTextColor(fg);
}
// Show a triangle for trend direction high (x, y is the left edge) // Show a triangle for trend direction high (x, y is the left edge)
void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color){ void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color){
getdisplay().fillTriangle(x, y, x+size*2, y, x+size, y-size*2, color); getdisplay().fillTriangle(x, y, x+size*2, y, x+size, y-size*2, color);

View File

@@ -4,7 +4,6 @@
#include <Arduino.h> #include <Arduino.h>
#include "OBP60Hardware.h" #include "OBP60Hardware.h"
#include "LedSpiTask.h" #include "LedSpiTask.h"
#include "Graphics.h"
#include <GxEPD2_BW.h> // E-paper lib V2 #include <GxEPD2_BW.h> // E-paper lib V2
#include <Adafruit_FRAM_I2C.h> // I2C FRAM #include <Adafruit_FRAM_I2C.h> // I2C FRAM
@@ -63,15 +62,19 @@ GxEPD2_BW<GxEPD2_420_SE0420NQ04, GxEPD2_420_SE0420NQ04::HEIGHT> & getdisplay();
#define PAGE_UPDATE 1 // page wants display to update #define PAGE_UPDATE 1 // page wants display to update
#define PAGE_HIBERNATE 2 // page wants displey to hibernate #define PAGE_HIBERNATE 2 // page wants displey to hibernate
struct Point {
double x;
double y;
};
Point rotatePoint(const Point& origin, const Point& p, double angle);
std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle);
void fillPoly4(const std::vector<Point>& p4, uint16_t color); void fillPoly4(const std::vector<Point>& p4, uint16_t color);
void drawPoly(const std::vector<Point>& points, uint16_t color);
void deepSleep(CommonData &common); void deepSleep(CommonData &common);
uint8_t getLastPage(); uint8_t getLastPage();
void hardwareInit(GwApi *api); void hardwareInit(GwApi *api);
void powerInit(String powermode);
void setPortPin(uint pin, bool value); // Set port pin for extension port void setPortPin(uint pin, bool value); // Set port pin for extension port
@@ -93,7 +96,6 @@ String xdrDelete(String input); // Delete xdr prefix from string
void drawTextCenter(int16_t cx, int16_t cy, String text); void drawTextCenter(int16_t cx, int16_t cy, String text);
void drawTextRalign(int16_t x, int16_t y, String text); void drawTextRalign(int16_t x, int16_t y, String text);
void drawTextBoxed(Rect box, String text, uint16_t fg, uint16_t bg, bool inverted, bool border);
void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color); 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); void displayTrendLow(int16_t x, int16_t y, uint16_t size, uint16_t color);

View File

@@ -65,6 +65,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
String tempFormat = commondata.config->getString(commondata.config->tempFormat); // [K|°C|°F] String tempFormat = commondata.config->getString(commondata.config->tempFormat); // [K|°C|°F]
String dateFormat = commondata.config->getString(commondata.config->dateFormat); // [DE|GB|US] String dateFormat = commondata.config->getString(commondata.config->dateFormat); // [DE|GB|US]
bool usesimudata = commondata.config->getBool(commondata.config->useSimuData); // [on|off] bool usesimudata = commondata.config->getBool(commondata.config->useSimuData); // [on|off]
String precision = commondata.config->getString(commondata.config->valueprecision); // [1|2]
// If boat value not valid // If boat value not valid
if (! value->valid && !usesimudata){ if (! value->valid && !usesimudata){
@@ -72,6 +73,19 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
return result; return result;
} }
const char* fmt_dec_1;
const char* fmt_dec_10;
const char* fmt_dec_100;
if (precision == "1") {
fmt_dec_1 = "%3.1f";
fmt_dec_10 = "%3.0f";
fmt_dec_100 = "%3.0f";
} else {
fmt_dec_1 = "%3.2f";
fmt_dec_10 = "%3.1f";
fmt_dec_100 = "%3.0f";
}
// LOG_DEBUG(GwLog::DEBUG,"formatValue init: getFormat: %s date->value: %f time->value: %f", value->getFormat(), commondata.date->value, commondata.time->value); // LOG_DEBUG(GwLog::DEBUG,"formatValue init: getFormat: %s date->value: %f time->value: %f", value->getFormat(), commondata.date->value, commondata.time->value);
static const int bsize = 30; static const int bsize = 30;
char buffer[bsize+1]; char buffer[bsize+1];
@@ -91,25 +105,25 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
tmElements_t parts; tmElements_t parts;
time_t tv=tNMEA0183Msg::daysToTime_t(value->value + dayoffset); time_t tv=tNMEA0183Msg::daysToTime_t(value->value + dayoffset);
tNMEA0183Msg::breakTime(tv,parts); tNMEA0183Msg::breakTime(tv,parts);
if(usesimudata == false) { if (usesimudata == false) {
if(String(dateFormat) == "DE"){ if (String(dateFormat) == "DE") {
snprintf(buffer,bsize,"%02d.%02d.%04d",parts.tm_mday,parts.tm_mon+1,parts.tm_year+1900); snprintf(buffer,bsize, "%02d.%02d.%04d", parts.tm_mday, parts.tm_mon+1, parts.tm_year+1900);
} }
else if(String(dateFormat) == "GB"){ else if(String(dateFormat) == "GB") {
snprintf(buffer,bsize,"%02d/%02d/%04d",parts.tm_mday,parts.tm_mon+1,parts.tm_year+1900); snprintf(buffer, bsize, "%02d/%02d/%04d", parts.tm_mday, parts.tm_mon+1, parts.tm_year+1900);
} }
else if(String(dateFormat) == "US"){ else if(String(dateFormat) == "US") {
snprintf(buffer,bsize,"%02d/%02d/%04d",parts.tm_mon+1,parts.tm_mday,parts.tm_year+1900); snprintf(buffer, bsize, "%02d/%02d/%04d", parts.tm_mon+1, parts.tm_mday, parts.tm_year+1900);
} }
else if(String(dateFormat) == "ISO"){ else if(String(dateFormat) == "ISO") {
snprintf(buffer,bsize,"%04d-%02d-%02d",parts.tm_year+1900,parts.tm_mon+1,parts.tm_mday); snprintf(buffer, bsize, "%04d-%02d-%02d", parts.tm_year+1900, parts.tm_mon+1, parts.tm_mday);
} }
else{ else {
snprintf(buffer,bsize,"%02d.%02d.%04d",parts.tm_mday,parts.tm_mon+1,parts.tm_year+1900); snprintf(buffer, bsize, "%02d.%02d.%04d", parts.tm_mday, parts.tm_mon+1, parts.tm_year+1900);
} }
} }
else{ else{
snprintf(buffer,bsize,"01.01.2022"); snprintf(buffer, bsize, "01.01.2022");
} }
if(timeZone == 0){ if(timeZone == 0){
result.unit = "UTC"; result.unit = "UTC";
@@ -130,11 +144,11 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
if (timeInSeconds > 86400) {timeInSeconds = timeInSeconds - 86400;} if (timeInSeconds > 86400) {timeInSeconds = timeInSeconds - 86400;}
if (timeInSeconds < 0) {timeInSeconds = timeInSeconds + 86400;} if (timeInSeconds < 0) {timeInSeconds = timeInSeconds + 86400;}
// LOG_DEBUG(GwLog::DEBUG,"... formatTime value: %f tz: %f corrected timeInSeconds: %f ", value->value, timeZone, timeInSeconds); // LOG_DEBUG(GwLog::DEBUG,"... formatTime value: %f tz: %f corrected timeInSeconds: %f ", value->value, timeZone, timeInSeconds);
if(usesimudata == false) { if (usesimudata == false) {
val=modf(timeInSeconds/3600.0,&inthr); val = modf(timeInSeconds/3600.0, &inthr);
val=modf(val*3600.0/60.0,&intmin); val = modf(val*3600.0/60.0, &intmin);
modf(val*60.0,&intsec); modf(val*60.0,&intsec);
snprintf(buffer,bsize,"%02.0f:%02.0f:%02.0f",inthr,intmin,intsec); snprintf(buffer, bsize, "%02.0f:%02.0f:%02.0f", inthr, intmin, intsec);
} }
else{ else{
static long sec; static long sec;
@@ -143,7 +157,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
sec ++; sec ++;
} }
sec = sec % 60; sec = sec % 60;
snprintf(buffer,bsize,"11:36:%02i", int(sec)); snprintf(buffer, bsize, "11:36:%02i", int(sec));
lasttime = millis(); lasttime = millis();
} }
if(timeZone == 0){ if(timeZone == 0){
@@ -156,23 +170,23 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
//######################################################## //########################################################
else if (value->getFormat() == "formatFixed0"){ else if (value->getFormat() == "formatFixed0"){
if(usesimudata == false) { if(usesimudata == false) {
snprintf(buffer,bsize,"%3.0f",value->value); snprintf(buffer, bsize, "%3.0f", value->value);
rawvalue = value->value; rawvalue = value->value;
} }
else{ else{
rawvalue = 8.0 + float(random(0, 10)) / 10.0; rawvalue = 8.0 + float(random(0, 10)) / 10.0;
snprintf(buffer,bsize,"%3.0f", rawvalue); snprintf(buffer, bsize, "%3.0f", rawvalue);
} }
result.unit = ""; result.unit = "";
} }
//######################################################## //########################################################
else if (value->getFormat() == "formatCourse" || value->getFormat() == "formatWind"){ else if (value->getFormat() == "formatCourse" || value->getFormat() == "formatWind"){
double course = 0; double course = 0;
if(usesimudata == false) { if (usesimudata == false) {
course = value->value; course = value->value;
rawvalue = value->value; rawvalue = value->value;
} }
else{ else {
course = 2.53 + float(random(0, 10) / 100.0); course = 2.53 + float(random(0, 10) / 100.0);
rawvalue = course; rawvalue = course;
} }
@@ -185,7 +199,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
//######################################################## //########################################################
else if (value->getFormat() == "formatKnots" && (value->getName() == "SOG" || value->getName() == "STW")){ else if (value->getFormat() == "formatKnots" && (value->getName() == "SOG" || value->getName() == "STW")){
double speed = 0; double speed = 0;
if(usesimudata == false) { if (usesimudata == false) {
speed = value->value; speed = value->value;
rawvalue = value->value; rawvalue = value->value;
} }
@@ -193,85 +207,85 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
rawvalue = 4.0 + float(random(0, 40)); rawvalue = 4.0 + float(random(0, 40));
speed = rawvalue; speed = rawvalue;
} }
if(String(speedFormat) == "km/h"){ if (String(speedFormat) == "km/h"){
speed = speed * 3.6; // Unit conversion form m/s to km/h speed = speed * 3.6; // Unit conversion form m/s to km/h
result.unit = "km/h"; result.unit = "km/h";
} }
else if(String(speedFormat) == "kn"){ else if (String(speedFormat) == "kn"){
speed = speed * 1.94384; // Unit conversion form m/s to kn speed = speed * 1.94384; // Unit conversion form m/s to kn
result.unit = "kn"; result.unit = "kn";
} }
else{ else {
speed = speed; // Unit conversion form m/s to m/s speed = speed; // Unit conversion form m/s to m/s
result.unit = "m/s"; result.unit = "m/s";
} }
if(speed < 10){ if(speed < 10) {
snprintf(buffer,bsize,"%3.2f",speed); snprintf(buffer, bsize, fmt_dec_1, speed);
} }
if(speed >= 10 && speed < 100){ else if (speed < 100) {
snprintf(buffer,bsize,"%3.1f",speed); snprintf(buffer, bsize, fmt_dec_10, speed);
} }
if(speed >= 100){ else {
snprintf(buffer,bsize,"%3.0f",speed); snprintf(buffer, bsize, fmt_dec_100, speed);
} }
} }
//######################################################## //########################################################
else if (value->getFormat() == "formatKnots" && (value->getName() == "AWS" || value->getName() == "TWS" || value->getName() == "MaxAws" || value->getName() == "MaxTws")){ else if (value->getFormat() == "formatKnots" && (value->getName() == "AWS" || value->getName() == "TWS" || value->getName() == "MaxAws" || value->getName() == "MaxTws")){
double speed = 0; double speed = 0;
if(usesimudata == false) { if (usesimudata == false) {
speed = value->value; speed = value->value;
rawvalue = value->value; rawvalue = value->value;
} }
else{ else {
rawvalue = 4.0 + float(random(0, 40)); rawvalue = 4.0 + float(random(0, 40));
speed = rawvalue; speed = rawvalue;
} }
if(String(windspeedFormat) == "km/h"){ if (String(windspeedFormat) == "km/h"){
speed = speed * 3.6; // Unit conversion form m/s to km/h speed = speed * 3.6; // Unit conversion form m/s to km/h
result.unit = "km/h"; result.unit = "km/h";
} }
else if(String(windspeedFormat) == "kn"){ else if (String(windspeedFormat) == "kn"){
speed = speed * 1.94384; // Unit conversion form m/s to kn speed = speed * 1.94384; // Unit conversion form m/s to kn
result.unit = "kn"; result.unit = "kn";
} }
else if(String(windspeedFormat) == "bft"){ else if(String(windspeedFormat) == "bft"){
if(speed < 0.3){ if (speed < 0.3) {
speed = 0; speed = 0;
} }
if(speed >=0.3 && speed < 1.5){ else if (speed < 1.5) {
speed = 1; speed = 1;
} }
if(speed >=1.5 && speed < 3.3){ else if (speed < 3.3) {
speed = 2; speed = 2;
} }
if(speed >=3.3 && speed < 5.4){ else if (speed < 5.4) {
speed = 3; speed = 3;
} }
if(speed >=5.4 && speed < 7.9){ else if (speed < 7.9) {
speed = 4; speed = 4;
} }
if(speed >=7.9 && speed < 10.7){ else if (speed < 10.7) {
speed = 5; speed = 5;
} }
if(speed >=10.7 && speed < 13.8){ else if (speed < 13.8) {
speed = 6; speed = 6;
} }
if(speed >=13.8 && speed < 17.1){ else if (speed < 17.1) {
speed = 7; speed = 7;
} }
if(speed >=17.1 && speed < 20.7){ else if (speed < 20.7) {
speed = 8; speed = 8;
} }
if(speed >=20.7 && speed < 24.4){ else if (speed < 24.4) {
speed = 9; speed = 9;
} }
if(speed >=24.4 && speed < 28.4){ else if (speed < 28.4) {
speed = 10; speed = 10;
} }
if(speed >=28.4 && speed < 32.6){ else if (speed < 32.6) {
speed = 11; speed = 11;
} }
if(speed >=32.6){ else {
speed = 12; speed = 12;
} }
result.unit = "bft"; result.unit = "bft";
@@ -280,82 +294,85 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
speed = speed; // Unit conversion form m/s to m/s speed = speed; // Unit conversion form m/s to m/s
result.unit = "m/s"; result.unit = "m/s";
} }
if(String(windspeedFormat) == "bft"){ if (String(windspeedFormat) == "bft"){
snprintf(buffer,bsize,"%2.0f",speed); snprintf(buffer, bsize, "%2.0f", speed);
} }
else{ else{
if(speed < 10){ if (speed < 10){
snprintf(buffer,bsize,"%3.2f",speed); snprintf(buffer, bsize, fmt_dec_1, speed);
} }
if(speed >= 10 && speed < 100){ else if (speed < 100){
snprintf(buffer,bsize,"%3.1f",speed); snprintf(buffer, bsize, fmt_dec_10, speed);
} }
if(speed >= 100){ else {
snprintf(buffer,bsize,"%3.0f",speed); snprintf(buffer, bsize, fmt_dec_100, speed);
} }
} }
} }
//######################################################## //########################################################
else if (value->getFormat() == "formatRot"){ else if (value->getFormat() == "formatRot"){
double rotation = 0; double rotation = 0;
if(usesimudata == false) { if (usesimudata == false) {
rotation = value->value; rotation = value->value;
rawvalue = value->value; rawvalue = value->value;
} }
else{ else {
rawvalue = 0.04 + float(random(0, 10)) / 100.0; rawvalue = 0.04 + float(random(0, 10)) / 100.0;
rotation = rawvalue; rotation = rawvalue;
} }
rotation = rotation * 57.2958; // Unit conversion form rad/s to deg/s rotation = rotation * 57.2958; // Unit conversion form rad/s to deg/s
result.unit = "Deg/s"; result.unit = "Deg/s";
if(rotation < -100){ if (rotation < -100){
rotation = -99; rotation = -99;
} }
if(rotation > 100){ if (rotation > 100){
rotation = 99; rotation = 99;
} }
if(rotation > -10 && rotation < 10){ if (rotation > -10 && rotation < 10){
snprintf(buffer,bsize,"%3.2f",rotation); snprintf(buffer, bsize, "%3.2f", rotation);
} }
if(rotation <= -10 || rotation >= 10){ if (rotation <= -10 || rotation >= 10){
snprintf(buffer,bsize,"%3.0f",rotation); snprintf(buffer, bsize, "%3.0f", rotation);
} }
} }
//######################################################## //########################################################
else if (value->getFormat() == "formatDop"){ else if (value->getFormat() == "formatDop"){
double dop = 0; double dop = 0;
if(usesimudata == false) { if (usesimudata == false) {
dop = value->value; dop = value->value;
rawvalue = value->value; rawvalue = value->value;
} }
else{ else {
rawvalue = 2.0 + float(random(0, 40)) / 10.0; rawvalue = 2.0 + float(random(0, 40)) / 10.0;
dop = rawvalue; dop = rawvalue;
} }
result.unit = "m"; result.unit = "m";
if(dop > 99.9){ if (dop > 99.9){
dop = 99.9; dop = 99.9;
} }
if(dop < 10){ if (dop < 10){
snprintf(buffer,bsize,"%3.2f",dop); snprintf(buffer, bsize, fmt_dec_1, dop);
} }
if(dop >= 10 && dop < 100){ else if(dop < 100){
snprintf(buffer,bsize,"%3.1f",dop); snprintf(buffer, bsize, fmt_dec_10, dop);
}
else {
snprintf(buffer, bsize, fmt_dec_100, dop);
} }
} }
//######################################################## //########################################################
else if (value->getFormat() == "formatLatitude"){ else if (value->getFormat() == "formatLatitude"){
if(usesimudata == false) { if (usesimudata == false) {
double lat = value->value; double lat = value->value;
rawvalue = value->value; rawvalue = value->value;
String latitude = ""; String latitude = "";
String latdir = ""; String latdir = "";
float degree = abs(int(lat)); float degree = abs(int(lat));
float minute = abs((lat - int(lat)) * 60); float minute = abs((lat - int(lat)) * 60);
if(lat > 0){ if (lat > 0){
latdir = "N"; latdir = "N";
} }
else{ else {
latdir = "S"; latdir = "S";
} }
latitude = String(degree,0) + "\x90 " + String(minute,4) + "' " + latdir; latitude = String(degree,0) + "\x90 " + String(minute,4) + "' " + latdir;
@@ -364,41 +381,41 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
} }
else{ else{
rawvalue = 35.0 + float(random(0, 10)) / 10000.0; rawvalue = 35.0 + float(random(0, 10)) / 10000.0;
snprintf(buffer,bsize," 51\" %2.4f' N", rawvalue); snprintf(buffer, bsize, " 51\" %2.4f' N", rawvalue);
} }
} }
//######################################################## //########################################################
else if (value->getFormat() == "formatLongitude"){ else if (value->getFormat() == "formatLongitude"){
if(usesimudata == false) { if (usesimudata == false) {
double lon = value->value; double lon = value->value;
rawvalue = value->value; rawvalue = value->value;
String longitude = ""; String longitude = "";
String londir = ""; String londir = "";
float degree = abs(int(lon)); float degree = abs(int(lon));
float minute = abs((lon - int(lon)) * 60); float minute = abs((lon - int(lon)) * 60);
if(lon > 0){ if (lon > 0){
londir = "E"; londir = "E";
} }
else{ else {
londir = "W"; londir = "W";
} }
longitude = String(degree,0) + "\x90 " + String(minute,4) + "' " + londir; longitude = String(degree,0) + "\x90 " + String(minute,4) + "' " + londir;
result.unit = ""; result.unit = "";
strcpy(buffer, longitude.c_str()); strcpy(buffer, longitude.c_str());
} }
else{ else {
rawvalue = 6.0 + float(random(0, 10)) / 100000.0; rawvalue = 6.0 + float(random(0, 10)) / 100000.0;
snprintf(buffer,bsize," 15\" %2.4f'", rawvalue); snprintf(buffer, bsize, " 15\" %2.4f'", rawvalue);
} }
} }
//######################################################## //########################################################
else if (value->getFormat() == "formatDepth"){ else if (value->getFormat() == "formatDepth"){
double depth = 0; double depth = 0;
if(usesimudata == false) { if (usesimudata == false) {
depth = value->value; depth = value->value;
rawvalue = value->value; rawvalue = value->value;
} }
else{ else {
rawvalue = 18.0 + float(random(0, 100)) / 10.0; rawvalue = 18.0 + float(random(0, 100)) / 10.0;
depth = rawvalue; depth = rawvalue;
} }
@@ -409,14 +426,14 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
else{ else{
result.unit = "m"; result.unit = "m";
} }
if(depth < 10){ if (depth < 10) {
snprintf(buffer,bsize,"%3.2f",depth); snprintf(buffer, bsize, fmt_dec_1, depth);
} }
if(depth >= 10 && depth < 100){ else if (depth < 100){
snprintf(buffer,bsize,"%3.1f",depth); snprintf(buffer, bsize, fmt_dec_10, depth);
} }
if(depth >= 100){ else {
snprintf(buffer,bsize,"%3.0f",depth); snprintf(buffer, bsize, fmt_dec_100, depth);
} }
} }
//######################################################## //########################################################
@@ -430,50 +447,50 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
xte = rawvalue; xte = rawvalue;
} }
if (xte >= 100) { if (xte >= 100) {
snprintf(buffer,bsize,"%3.0f",value->value); snprintf(buffer, bsize, fmt_dec_100, value->value);
} else if (xte >= 10) { } else if (xte >= 10) {
snprintf(buffer,bsize,"%3.1f",value->value); snprintf(buffer, bsize, fmt_dec_10, value->value);
} else { } else {
snprintf(buffer,bsize,"%3.2f",value->value); snprintf(buffer, bsize, fmt_dec_1, value->value);
} }
result.unit = "nm"; result.unit = "nm";
} }
//######################################################## //########################################################
else if (value->getFormat() == "kelvinToC"){ else if (value->getFormat() == "kelvinToC"){
double temp = 0; double temp = 0;
if(usesimudata == false) { if (usesimudata == false) {
temp = value->value; temp = value->value;
rawvalue = value->value; rawvalue = value->value;
} }
else{ else {
rawvalue = 296.0 + float(random(0, 10)) / 10.0; rawvalue = 296.0 + float(random(0, 10)) / 10.0;
temp = rawvalue; temp = rawvalue;
} }
if(String(tempFormat) == "C"){ if (String(tempFormat) == "C") {
temp = temp - 273.15; temp = temp - 273.15;
result.unit = "C"; result.unit = "C";
} }
else if(String(tempFormat) == "F"){ else if (String(tempFormat) == "F") {
temp = (temp - 273.15) * 9 / 5 + 32; temp = (temp - 273.15) * 9 / 5 + 32;
result.unit = "F"; result.unit = "F";
} }
else{ else{
result.unit = "K"; result.unit = "K";
} }
if(temp < 10){ if(temp < 10) {
snprintf(buffer,bsize,"%3.2f",temp); snprintf(buffer, bsize, fmt_dec_1, temp);
} }
if(temp >= 10 && temp < 100){ else if (temp < 100) {
snprintf(buffer,bsize,"%3.1f",temp); snprintf(buffer, bsize, fmt_dec_10, temp);
} }
if(temp >= 100){ else {
snprintf(buffer,bsize,"%3.0f",temp); snprintf(buffer, bsize, fmt_dec_100, temp);
} }
} }
//######################################################## //########################################################
else if (value->getFormat() == "mtr2nm"){ else if (value->getFormat() == "mtr2nm"){
double distance = 0; double distance = 0;
if(usesimudata == false) { if (usesimudata == false) {
distance = value->value; distance = value->value;
rawvalue = value->value; rawvalue = value->value;
} }
@@ -481,25 +498,25 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
rawvalue = 2960.0 + float(random(0, 10)); rawvalue = 2960.0 + float(random(0, 10));
distance = rawvalue; distance = rawvalue;
} }
if(String(distanceFormat) == "km"){ if (String(distanceFormat) == "km") {
distance = distance * 0.001; distance = distance * 0.001;
result.unit = "km"; result.unit = "km";
} }
else if(String(distanceFormat) == "nm"){ else if (String(distanceFormat) == "nm") {
distance = distance * 0.000539957; distance = distance * 0.000539957;
result.unit = "nm"; result.unit = "nm";
} }
else{; else {
result.unit = "m"; result.unit = "m";
} }
if(distance < 10){ if (distance < 10){
snprintf(buffer,bsize,"%3.2f",distance); snprintf(buffer, bsize, fmt_dec_1, distance);
} }
if(distance >= 10 && distance < 100){ else if (distance < 100){
snprintf(buffer,bsize,"%3.1f",distance); snprintf(buffer, bsize, fmt_dec_10, distance);
} }
if(distance >= 100){ else {
snprintf(buffer,bsize,"%3.0f",distance); snprintf(buffer, bsize, fmt_dec_100, distance);
} }
} }
//######################################################## //########################################################
@@ -508,122 +525,122 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
//######################################################## //########################################################
else if (value->getFormat() == "formatXdr:P:P"){ else if (value->getFormat() == "formatXdr:P:P"){
double pressure = 0; double pressure = 0;
if(usesimudata == false) { if (usesimudata == false) {
pressure = value->value; pressure = value->value;
rawvalue = value->value; rawvalue = value->value;
pressure = pressure / 100.0; // Unit conversion form Pa to hPa pressure = pressure / 100.0; // Unit conversion form Pa to hPa
} }
else{ else {
rawvalue = 968 + float(random(0, 10)); rawvalue = 968 + float(random(0, 10));
pressure = rawvalue; pressure = rawvalue;
} }
snprintf(buffer,bsize,"%4.0f",pressure); snprintf(buffer, bsize, "%4.0f", pressure);
result.unit = "hPa"; result.unit = "hPa";
} }
//######################################################## //########################################################
else if (value->getFormat() == "formatXdr:P:B"){ else if (value->getFormat() == "formatXdr:P:B"){
double pressure = 0; double pressure = 0;
if(usesimudata == false) { if (usesimudata == false) {
pressure = value->value; pressure = value->value;
rawvalue = value->value; rawvalue = value->value;
pressure = pressure / 100.0; // Unit conversion form Pa to mBar pressure = pressure / 100.0; // Unit conversion form Pa to mBar
} }
else{ else {
rawvalue = value->value; rawvalue = value->value;
pressure = 968 + float(random(0, 10)); pressure = 968 + float(random(0, 10));
} }
snprintf(buffer,bsize,"%4.0f",pressure); snprintf(buffer, bsize, "%4.0f", pressure);
result.unit = "mBar"; result.unit = "mBar";
} }
//######################################################## //########################################################
else if (value->getFormat() == "formatXdr:U:V"){ else if (value->getFormat() == "formatXdr:U:V"){
double voltage = 0; double voltage = 0;
if(usesimudata == false) { if (usesimudata == false) {
voltage = value->value; voltage = value->value;
rawvalue = value->value; rawvalue = value->value;
} }
else{ else {
rawvalue = 12 + float(random(0, 30)) / 10.0; rawvalue = 12 + float(random(0, 30)) / 10.0;
voltage = rawvalue; voltage = rawvalue;
} }
if(voltage < 10){ if (voltage < 10) {
snprintf(buffer,bsize,"%3.2f",voltage); snprintf(buffer, bsize, fmt_dec_1, voltage);
} }
else{ else {
snprintf(buffer,bsize,"%3.1f",voltage); snprintf(buffer, bsize, fmt_dec_10, voltage);
} }
result.unit = "V"; result.unit = "V";
} }
//######################################################## //########################################################
else if (value->getFormat() == "formatXdr:I:A"){ else if (value->getFormat() == "formatXdr:I:A"){
double current = 0; double current = 0;
if(usesimudata == false) { if (usesimudata == false) {
current = value->value; current = value->value;
rawvalue = value->value; rawvalue = value->value;
} }
else{ else {
rawvalue = 8.2 + float(random(0, 50)) / 10.0; rawvalue = 8.2 + float(random(0, 50)) / 10.0;
current = rawvalue; current = rawvalue;
} }
if(current < 10){ if (current < 10) {
snprintf(buffer,bsize,"%3.2f",current); snprintf(buffer, bsize, fmt_dec_1, current);
} }
if(current >= 10 && current < 100){ else if(current < 100) {
snprintf(buffer,bsize,"%3.1f",current); snprintf(buffer, bsize, fmt_dec_10, current);
} }
if(current >= 100){ else {
snprintf(buffer,bsize,"%3.0f",current); snprintf(buffer, bsize, fmt_dec_100, current);
} }
result.unit = "A"; result.unit = "A";
} }
//######################################################## //########################################################
else if (value->getFormat() == "formatXdr:C:K"){ else if (value->getFormat() == "formatXdr:C:K"){
double temperature = 0; double temperature = 0;
if(usesimudata == false) { if (usesimudata == false) {
temperature = value->value - 273.15; // Convert K to C temperature = value->value - 273.15; // Convert K to C
rawvalue = value->value - 273.15; rawvalue = value->value - 273.15;
} }
else{ else {
rawvalue = 21.8 + float(random(0, 50)) / 10.0; rawvalue = 21.8 + float(random(0, 50)) / 10.0;
temperature = rawvalue; temperature = rawvalue;
} }
if(temperature < 10){ if (temperature < 10) {
snprintf(buffer,bsize,"%3.2f",temperature); snprintf(buffer, bsize, fmt_dec_1, temperature);
} }
if(temperature >= 10 && temperature < 100){ else if (temperature < 100) {
snprintf(buffer,bsize,"%3.1f",temperature); snprintf(buffer, bsize, fmt_dec_10, temperature);
} }
if(temperature >= 100){ else {
snprintf(buffer,bsize,"%3.0f",temperature); snprintf(buffer, bsize, fmt_dec_100, temperature);
} }
result.unit = "Deg C"; result.unit = "Deg C";
} }
//######################################################## //########################################################
else if (value->getFormat() == "formatXdr:C:C"){ else if (value->getFormat() == "formatXdr:C:C"){
double temperature = 0; double temperature = 0;
if(usesimudata == false) { if (usesimudata == false) {
temperature = value->value; // Value in C temperature = value->value; // Value in C
rawvalue = value->value; rawvalue = value->value;
} }
else{ else {
rawvalue = 21.8 + float(random(0, 50)) / 10.0; rawvalue = 21.8 + float(random(0, 50)) / 10.0;
temperature = rawvalue; temperature = rawvalue;
} }
if(temperature < 10){ if (temperature < 10) {
snprintf(buffer,bsize,"%3.2f",temperature); snprintf(buffer, bsize, fmt_dec_1, temperature);
} }
if(temperature >= 10 && temperature < 100){ else if(temperature < 100) {
snprintf(buffer,bsize,"%3.1f",temperature); snprintf(buffer, bsize, fmt_dec_10, temperature);
} }
if(temperature >= 100){ else {
snprintf(buffer,bsize,"%3.0f",temperature); snprintf(buffer, bsize, fmt_dec_100, temperature);
} }
result.unit = "Deg C"; result.unit = "Deg C";
} }
//######################################################## //########################################################
else if (value->getFormat() == "formatXdr:H:P"){ else if (value->getFormat() == "formatXdr:H:P"){
double humidity = 0; double humidity = 0;
if(usesimudata == false) { if (usesimudata == false) {
humidity = value->value; // Value in % humidity = value->value; // Value in %
rawvalue = value->value; rawvalue = value->value;
} }
@@ -631,143 +648,143 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
rawvalue = 41.3 + float(random(0, 50)) / 10.0; rawvalue = 41.3 + float(random(0, 50)) / 10.0;
humidity = rawvalue; humidity = rawvalue;
} }
if(humidity < 10){ if (humidity < 10) {
snprintf(buffer,bsize,"%3.2f",humidity); snprintf(buffer, bsize, fmt_dec_1, humidity);
} }
if(humidity >= 10 && humidity < 100){ else if(humidity < 100) {
snprintf(buffer,bsize,"%3.1f",humidity); snprintf(buffer, bsize, fmt_dec_10, humidity);
} }
if(humidity >= 100){ else {
snprintf(buffer,bsize,"%3.0f",humidity); snprintf(buffer, bsize, fmt_dec_100, humidity);
} }
result.unit = "%"; result.unit = "%";
} }
//######################################################## //########################################################
else if (value->getFormat() == "formatXdr:V:P"){ else if (value->getFormat() == "formatXdr:V:P"){
double volume = 0; double volume = 0;
if(usesimudata == false) { if (usesimudata == false) {
volume = value->value; // Value in % volume = value->value; // Value in %
rawvalue = value->value; rawvalue = value->value;
} }
else{ else {
rawvalue = 85.8 + float(random(0, 50)) / 10.0; rawvalue = 85.8 + float(random(0, 50)) / 10.0;
volume = rawvalue; volume = rawvalue;
} }
if(volume < 10){ if (volume < 10) {
snprintf(buffer,bsize,"%3.2f",volume); snprintf(buffer, bsize, fmt_dec_1, volume);
} }
if(volume >= 10 && volume < 100){ else if (volume < 100) {
snprintf(buffer,bsize,"%3.1f",volume); snprintf(buffer, bsize, fmt_dec_10, volume);
} }
if(volume >= 100){ else if (volume >= 100) {
snprintf(buffer,bsize,"%3.0f",volume); snprintf(buffer, bsize, fmt_dec_100, volume);
} }
result.unit = "%"; result.unit = "%";
} }
//######################################################## //########################################################
else if (value->getFormat() == "formatXdr:V:M"){ else if (value->getFormat() == "formatXdr:V:M"){
double volume = 0; double volume = 0;
if(usesimudata == false) { if (usesimudata == false) {
volume = value->value; // Value in l volume = value->value; // Value in l
rawvalue = value->value; rawvalue = value->value;
} }
else{ else {
rawvalue = 75.2 + float(random(0, 50)) / 10.0; rawvalue = 75.2 + float(random(0, 50)) / 10.0;
volume = rawvalue; volume = rawvalue;
} }
if(volume < 10){ if (volume < 10) {
snprintf(buffer,bsize,"%3.2f",volume); snprintf(buffer, bsize, fmt_dec_1, volume);
} }
if(volume >= 10 && volume < 100){ else if (volume < 100) {
snprintf(buffer,bsize,"%3.1f",volume); snprintf(buffer, bsize, fmt_dec_10, volume);
} }
if(volume >= 100){ else {
snprintf(buffer,bsize,"%3.0f",volume); snprintf(buffer, bsize, fmt_dec_100, volume);
} }
result.unit = "l"; result.unit = "l";
} }
//######################################################## //########################################################
else if (value->getFormat() == "formatXdr:R:I"){ else if (value->getFormat() == "formatXdr:R:I"){
double flow = 0; double flow = 0;
if(usesimudata == false) { if (usesimudata == false) {
flow = value->value; // Value in l/min flow = value->value; // Value in l/min
rawvalue = value->value; rawvalue = value->value;
} }
else{ else {
rawvalue = 7.5 + float(random(0, 20)) / 10.0; rawvalue = 7.5 + float(random(0, 20)) / 10.0;
flow = rawvalue; flow = rawvalue;
} }
if(flow < 10){ if (flow < 10) {
snprintf(buffer,bsize,"%3.2f",flow); snprintf(buffer, bsize, fmt_dec_1, flow);
} }
if(flow >= 10 && flow < 100){ else if (flow < 100) {
snprintf(buffer,bsize,"%3.1f",flow); snprintf(buffer, bsize, fmt_dec_10, flow);
} }
if(flow >= 100){ else {
snprintf(buffer,bsize,"%3.0f",flow); snprintf(buffer, bsize, fmt_dec_100, flow);
} }
result.unit = "l/min"; result.unit = "l/min";
} }
//######################################################## //########################################################
else if (value->getFormat() == "formatXdr:G:"){ else if (value->getFormat() == "formatXdr:G:"){
double generic = 0; double generic = 0;
if(usesimudata == false) { if (usesimudata == false) {
generic = value->value; // Value in l/min generic = value->value;
rawvalue = value->value; rawvalue = value->value;
} }
else{ else {
rawvalue = 18.5 + float(random(0, 20)) / 10.0; rawvalue = 18.5 + float(random(0, 20)) / 10.0;
generic = rawvalue; generic = rawvalue;
} }
if(generic < 10){ if (generic < 10) {
snprintf(buffer,bsize,"%3.2f",generic); snprintf(buffer, bsize, fmt_dec_1, generic);
} }
if(generic >= 10 && generic < 100){ else if (generic < 100) {
snprintf(buffer,bsize,"%3.1f",generic); snprintf(buffer, bsize, fmt_dec_10, generic);
} }
if(generic >= 100){ else {
snprintf(buffer,bsize,"%3.0f",generic); snprintf(buffer, bsize, fmt_dec_100, generic);
} }
result.unit = ""; result.unit = "";
} }
//######################################################## //########################################################
else if (value->getFormat() == "formatXdr:A:P"){ else if (value->getFormat() == "formatXdr:A:P"){
double dplace = 0; double dplace = 0;
if(usesimudata == false) { if (usesimudata == false) {
dplace = value->value; // Value in % dplace = value->value; // Value in %
rawvalue = value->value; rawvalue = value->value;
} }
else{ else {
rawvalue = 55.3 + float(random(0, 20)) / 10.0; rawvalue = 55.3 + float(random(0, 20)) / 10.0;
dplace = rawvalue; dplace = rawvalue;
} }
if(dplace < 10){ if (dplace < 10) {
snprintf(buffer,bsize,"%3.2f",dplace); snprintf(buffer, bsize, fmt_dec_1, dplace);
} }
if(dplace >= 10 && dplace < 100){ else if (dplace < 100) {
snprintf(buffer,bsize,"%3.1f",dplace); snprintf(buffer, bsize, fmt_dec_10, dplace);
} }
if(dplace >= 100){ else {
snprintf(buffer,bsize,"%3.0f",dplace); snprintf(buffer, bsize, fmt_dec_100, dplace);
} }
result.unit = "%"; result.unit = "%";
} }
//######################################################## //########################################################
else if (value->getFormat() == "formatXdr:A:D"){ else if (value->getFormat() == "formatXdr:A:D"){
double angle = 0; double angle = 0;
if(usesimudata == false) { if (usesimudata == false) {
angle = value->value; angle = value->value;
angle = angle * 57.2958; // Unit conversion form rad to deg angle = angle * 57.2958; // Unit conversion form rad to deg
rawvalue = value->value; rawvalue = value->value;
} }
else{ else {
rawvalue = PI / 100 + (random(-5, 5) / 360 * 2* PI); rawvalue = PI / 100 + (random(-5, 5) / 360 * 2* PI);
angle = rawvalue * 57.2958; angle = rawvalue * 57.2958;
} }
if(angle > -10 && angle < 10){ if (angle > -10 && angle < 10) {
snprintf(buffer,bsize,"%3.1f",angle); snprintf(buffer,bsize,"%3.1f",angle);
} }
else{ else {
snprintf(buffer,bsize,"%3.0f",angle); snprintf(buffer,bsize,"%3.0f",angle);
} }
result.unit = "Deg"; result.unit = "Deg";
@@ -775,41 +792,41 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
//######################################################## //########################################################
else if (value->getFormat() == "formatXdr:T:R"){ else if (value->getFormat() == "formatXdr:T:R"){
double rpm = 0; double rpm = 0;
if(usesimudata == false) { if (usesimudata == false) {
rpm = value->value; // Value in rpm rpm = value->value; // Value in rpm
rawvalue = value->value; rawvalue = value->value;
} }
else{ else {
rawvalue = 2505 + random(0, 20); rawvalue = 2505 + random(0, 20);
rpm = rawvalue; rpm = rawvalue;
} }
if(rpm < 10){ if (rpm < 10) {
snprintf(buffer,bsize,"%3.2f",rpm); snprintf(buffer, bsize, fmt_dec_1, rpm);
} }
if(rpm >= 10 && rpm < 100){ else if (rpm < 100) {
snprintf(buffer,bsize,"%3.1f",rpm); snprintf(buffer, bsize, fmt_dec_10, rpm);
} }
if(rpm >= 100){ else {
snprintf(buffer,bsize,"%3.0f",rpm); snprintf(buffer, bsize, fmt_dec_100, rpm);
} }
result.unit = "rpm"; result.unit = "rpm";
} }
//######################################################## //########################################################
// Default format // Default format
//######################################################## //########################################################
else{ else {
if(value->value < 10){ if (value->value < 10) {
snprintf(buffer,bsize,"%3.2f",value->value); snprintf(buffer, bsize, fmt_dec_1, value->value);
} }
if(value->value >= 10 && value->value < 100){ else if (value->value < 100) {
snprintf(buffer,bsize,"%3.1f",value->value); snprintf(buffer, bsize, fmt_dec_10, value->value);
} }
if(value->value >= 100){ else {
snprintf(buffer,bsize,"%3.0f",value->value); snprintf(buffer, bsize, fmt_dec_100, value->value);
} }
result.unit = ""; result.unit = "";
} }
buffer[bsize]=0; buffer[bsize] = 0;
result.value = rawvalue; // Return value is only necessary in case of simulation of graphic pointer result.value = rawvalue; // Return value is only necessary in case of simulation of graphic pointer
result.svalue = String(buffer); result.svalue = String(buffer);
return result; return result;

View File

@@ -2,7 +2,6 @@
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
#include "ConfigMenu.h"
#include "images/logo64.xbm" #include "images/logo64.xbm"
#include <esp32/clk.h> #include <esp32/clk.h>
#include "qrcode.h" #include "qrcode.h"
@@ -26,377 +25,37 @@
* Consists of some sub-pages with following content: * Consists of some sub-pages with following content:
* 1. Hard and software information * 1. Hard and software information
* 2. System settings * 2. System settings
* 3. System configuration: running and NVRAM * 3. NMEA2000 device list
* 4. NMEA2000 device list
* 5. SD Card information if available
*
* TODO
* - setCpuFrequencyMhz(80|160|240);
* - Accesspoint / ! Änderung im Gatewaycode erforderlich?
* if (! isApActive()) {
* wifiSSID = config->getString(config->wifiSSID);
* wifiPass = config->getString(config->wifiPass);
* wifiSoftAP(wifiSSID, wifiPass);
* }
* - Power mode
* powerInit(powermode);
*/ */
class PageSystem : public Page class PageSystem : public Page
{ {
private: uint64_t chipid;
GwConfigHandler *config; bool simulation;
GwLog *logger; bool sdcard;
String buzzer_mode;
uint8_t buzzer_power;
String cpuspeed;
String rtc_module;
String gps_module;
String env_module;
// NVRAM config options String batt_sensor;
String flashLED; String solar_sensor;
String gen_sensor;
String rot_sensor;
double homelat;
double homelon;
// Generic data access char mode = 'N'; // (N)ormal, (S)ettings, (D)evice list, (C)ard
uint64_t chipid;
bool simulation;
bool sdcard;
String buzzer_mode;
uint8_t buzzer_power;
String cpuspeed;
String rtc_module;
String gps_module;
String env_module;
String batt_sensor;
String solar_sensor;
String gen_sensor;
String rot_sensor;
double homelat;
double homelon;
char mode = 'N'; // (N)ormal, (S)ettings, (C)onfiguration, (D)evice list, c(A)rd
int8_t editmode = -1; // marker for menu/edit/set function
ConfigMenu *menu;
void incMode() {
if (mode == 'N') { // Normal
mode = 'S';
} else if (mode == 'S') { // Settings
mode = 'C';
} else if (mode == 'C') { // Config
mode = 'D';
} else if (mode == 'D') { // Device list
if (sdcard) {
mode = 'A'; // SD-Card
} else {
mode = 'N';
}
} else {
mode = 'N';
}
}
void decMode() {
if (mode == 'N') {
if (sdcard) {
mode = 'A';
} else {
mode = 'D';
}
} else if (mode == 'S') { // Settings
mode = 'N';
} else if (mode == 'C') { // Config
mode = 'S';
} else if (mode == 'D') { // Device list
mode = 'C';
} else {
mode = 'D';
}
}
void displayModeNormal() {
// Default system page view
uint16_t y0 = 155;
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(8, 48);
getdisplay().print("System information");
getdisplay().drawXBitmap(320, 25, logo64_bits, logo64_width, logo64_height, commonData->fgcolor);
getdisplay().setFont(&Ubuntu_Bold8pt8b);
char ssid[13];
snprintf(ssid, 13, "%04X%08X", (uint16_t)(chipid >> 32), (uint32_t)chipid);
displayBarcode(String(ssid), 320, 200, 2);
getdisplay().setCursor(8, 70);
getdisplay().print(String("MCUDEVICE-") + String(ssid));
getdisplay().setCursor(8, 95);
getdisplay().print("Firmware version: ");
getdisplay().setCursor(150, 95);
getdisplay().print(VERSINFO);
getdisplay().setCursor(8, 113);
getdisplay().print("Board version: ");
getdisplay().setCursor(150, 113);
getdisplay().print(BOARDINFO);
getdisplay().print(String(" HW ") + String(PCBINFO));
getdisplay().setCursor(8, 131);
getdisplay().print("Display version: ");
getdisplay().setCursor(150, 131);
getdisplay().print(DISPLAYINFO);
getdisplay().print("; GxEPD2 v");
getdisplay().print(GXEPD2INFO);
getdisplay().setCursor(8, 265);
#ifdef BOARD_OBP60S3
getdisplay().print("Press STBY to enter deep sleep mode");
#endif
#ifdef BOARD_OBP40S3
getdisplay().print("Press wheel to enter deep sleep mode");
#endif
// Flash memory size
uint32_t flash_size = ESP.getFlashChipSize();
getdisplay().setCursor(8, y0);
getdisplay().print("FLASH:");
getdisplay().setCursor(90, y0);
getdisplay().print(String(flash_size / 1024) + String(" kB"));
// PSRAM memory size
uint32_t psram_size = ESP.getPsramSize();
getdisplay().setCursor(8, y0 + 16);
getdisplay().print("PSRAM:");
getdisplay().setCursor(90, y0 + 16);
getdisplay().print(String(psram_size / 1024) + String(" kB"));
// FRAM available / status
getdisplay().setCursor(8, y0 + 32);
getdisplay().print("FRAM:");
getdisplay().setCursor(90, y0 + 32);
getdisplay().print(hasFRAM ? "available" : "not found");
#ifdef BOARD_OBP40S3
// SD-Card
getdisplay().setCursor(8, y0 + 48);
getdisplay().print("SD-Card:");
getdisplay().setCursor(90, y0 + 48);
if (sdcard) {
uint64_t cardsize = SD.cardSize() / (1024 * 1024);
getdisplay().print(String(cardsize) + String(" MB"));
} else {
getdisplay().print("off");
}
#endif
// CPU speed config / active
getdisplay().setCursor(202, y0);
getdisplay().print("CPU speed:");
getdisplay().setCursor(300, y0);
getdisplay().print(cpuspeed);
getdisplay().print(" / ");
int cpu_freq = esp_clk_cpu_freq() / 1000000;
getdisplay().print(String(cpu_freq));
// total RAM free
int Heap_free = esp_get_free_heap_size();
getdisplay().setCursor(202, y0 + 16);
getdisplay().print("Total free:");
getdisplay().setCursor(300, y0 + 16);
getdisplay().print(String(Heap_free));
// RAM free for task
int RAM_free = uxTaskGetStackHighWaterMark(NULL);
getdisplay().setCursor(202, y0 + 32);
getdisplay().print("Task free:");
getdisplay().setCursor(300, y0 + 32);
getdisplay().print(String(RAM_free));
}
void displayModeConfig() {
// Configuration interface
uint16_t x0 = 16;
uint16_t y0 = 80;
uint16_t dy = 20;
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(8, 48);
getdisplay().print("System configuration");
getdisplay().setFont(&Ubuntu_Bold8pt8b);
/*getdisplay().setCursor(x0, y0);
getdisplay().print("CPU speed: 80 | 160 | 240");
getdisplay().setCursor(x0, y0 + 1 * dy);
getdisplay().print("Power mode: Max | 5V | Min");
getdisplay().setCursor(x0, y0 + 2 * dy);
getdisplay().print("Accesspoint: On | Off");
// TODO Change NVRAM-preferences settings here
getdisplay().setCursor(x0, y0 + 4 * dy);
getdisplay().print("Simulation: On | Off"); */
getdisplay().setFont(&Ubuntu_Bold8pt8b);
for (int i = 0 ; i < menu->getItemCount(); i++) {
ConfigMenuItem *itm = menu->getItemByIndex(i);
if (!itm) {
LOG_DEBUG(GwLog::ERROR, "Menu item not found: %d", i);
} else {
Rect r = menu->getItemRect(i);
bool inverted = (i == menu->getActiveIndex());
drawTextBoxed(r, itm->getLabel(), commonData->fgcolor, commonData->bgcolor, inverted, false);
if (inverted and editmode > 0) {
// triangle as edit marker
getdisplay().fillTriangle(r.x + r.w + 20, r.y, r.x + r.w + 30, r.y + r.h / 2, r.x + r.w + 20, r.y + r.h, commonData->fgcolor);
}
getdisplay().setCursor(r.x + r.w + 40, r.y + r.h - 4);
if (itm->getType() == "int") {
getdisplay().print(itm->getValue());
getdisplay().print(itm->getUnit());
} else {
getdisplay().print(itm->getValue() == 0 ? "No" : "Yes");
}
}
}
}
void displayModeSettings() {
// View some of the current settings
const uint16_t x0 = 8;
const uint16_t y0 = 72;
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(x0, 48);
getdisplay().print("System settings");
getdisplay().setFont(&Ubuntu_Bold8pt8b);
// left column
getdisplay().setCursor(x0, y0);
getdisplay().print("Simulation:");
getdisplay().setCursor(120, y0);
getdisplay().print(simulation ? "on" : "off");
getdisplay().setCursor(x0, y0 + 16);
getdisplay().print("Environment:");
getdisplay().setCursor(120, y0 + 16);
getdisplay().print(env_module);
getdisplay().setCursor(x0, y0 + 32);
getdisplay().print("Buzzer:");
getdisplay().setCursor(120, y0 + 32);
getdisplay().print(buzzer_mode);
getdisplay().setCursor(x0, y0 + 64);
getdisplay().print("GPS:");
getdisplay().setCursor(120, y0 + 64);
getdisplay().print(gps_module);
getdisplay().setCursor(x0, y0 + 80);
getdisplay().print("RTC:");
getdisplay().setCursor(120, y0 + 80);
getdisplay().print(rtc_module);
getdisplay().setCursor(x0, y0 + 96);
getdisplay().print("Wifi:");
getdisplay().setCursor(120, y0 + 96);
getdisplay().print(commonData->status.wifiApOn ? "on" : "off");
// Home location
getdisplay().setCursor(x0, y0 + 128);
getdisplay().print("Home Lat.:");
drawTextRalign(230, y0 + 128, formatLatitude(homelat));
getdisplay().setCursor(x0, y0 + 144);
getdisplay().print("Home Lon.:");
drawTextRalign(230, y0 + 144, formatLongitude(homelon));
// right column
getdisplay().setCursor(202, y0);
getdisplay().print("Batt. sensor:");
getdisplay().setCursor(320, y0);
getdisplay().print(batt_sensor);
// Solar sensor
getdisplay().setCursor(202, y0 + 16);
getdisplay().print("Solar sensor:");
getdisplay().setCursor(320, y0 + 16);
getdisplay().print(solar_sensor);
// Generator sensor
getdisplay().setCursor(202, y0 + 32);
getdisplay().print("Gen. sensor:");
getdisplay().setCursor(320, y0 + 32);
getdisplay().print(gen_sensor);
#ifdef BOARD_OBP60S3
// Backlight infos
getdisplay().setCursor(202, y0 + 64);
getdisplay().print("Backlight:");
getdisplay().setCursor(320, y0 + 64);
getdisplay().printf("%d%%", commonData->backlight.brightness);
// TODO test function with OBP60 device
getdisplay().setCursor(202, y0 + 80);
getdisplay().print("Bl color:");
getdisplay().setCursor(320, y0 + 80);
getdisplay().print(commonData->backlight.color.toName());
getdisplay().setCursor(202, y0 + 96);
getdisplay().print("Bl mode:");
getdisplay().setCursor(320, y0 + 96);
getdisplay().print(commonData->backlight.mode);
// TODO Buzzer mode and power
#endif
// Gyro sensor
// WIP / FEATURE
}
void displayModeSDCard() {
// SD card info
uint16_t x0 = 20;
uint16_t y0 = 72;
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(8, 48);
getdisplay().print("SD Card info");
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(x0, y0);
getdisplay().print("Work in progress...");
}
void displayModeDevicelist() {
// NMEA2000 device list
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(8, 48);
getdisplay().print("NMEA2000 device list");
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(20, 80);
getdisplay().print("RxD: ");
getdisplay().print(String(commonData->status.n2kRx));
getdisplay().setCursor(20, 100);
getdisplay().print("TxD: ");
getdisplay().print(String(commonData->status.n2kTx));
}
void storeConfig() {
menu->storeValues();
}
public: public:
PageSystem(CommonData &common){ PageSystem(CommonData &common){
commonData = &common; commonData = &common;
config = commonData->config; common.logger->logDebug(GwLog::LOG,"Instantiate PageSystem");
logger = commonData->logger;
logger->logDebug(GwLog::LOG,"Instantiate PageSystem");
if (hasFRAM) { if (hasFRAM) {
mode = fram.read(FRAM_SYSTEM_MODE); mode = fram.read(FRAM_SYSTEM_MODE);
} }
flashLED = common.config->getString(common.config->flashLED);
chipid = ESP.getEfuseMac(); chipid = ESP.getEfuseMac();
simulation = common.config->getBool(common.config->useSimuData); simulation = common.config->getBool(common.config->useSimuData);
#ifdef BOARD_OBP40S3 #ifdef BOARD_OBP40S3
@@ -415,24 +74,6 @@ public:
rot_sensor = common.config->getString(common.config->useRotSensor); rot_sensor = common.config->getString(common.config->useRotSensor);
homelat = common.config->getString(common.config->homeLAT).toDouble(); homelat = common.config->getString(common.config->homeLAT).toDouble();
homelon = common.config->getString(common.config->homeLON).toDouble(); homelon = common.config->getString(common.config->homeLON).toDouble();
// CPU speed: 80 | 160 | 240
// Power mode: Max | 5V | Min
// Accesspoint: On | Off
// TODO Change NVRAM-preferences settings here
// getdisplay().setCursor(x0, y0 + 4 * dy);
// getdisplay().print("Simulation: On | Off");
// Initialize config menu
menu = new ConfigMenu("Options", 40, 80);
menu->setItemDimension(150, 20);
ConfigMenuItem *newitem;
newitem = menu->addItem("accesspoint", "Accesspoint", "bool", 0, "");
newitem = menu->addItem("simulation", "Simulation", "on/off", 0, "");
menu->setItemActive("accesspoint");
} }
virtual void setupKeys(){ virtual void setupKeys(){
@@ -449,7 +90,19 @@ public:
// Switch display mode // Switch display mode
commonData->logger->logDebug(GwLog::LOG, "System keyboard handler"); commonData->logger->logDebug(GwLog::LOG, "System keyboard handler");
if (key == 2) { if (key == 2) {
incMode(); if (mode == 'N') {
mode = 'S';
} else if (mode == 'S') {
mode = 'D';
} else if (mode == 'D') {
if (sdcard) {
mode = 'C';
} else {
mode = 'N';
}
} else {
mode = 'N';
}
if (hasFRAM) fram.write(FRAM_SYSTEM_MODE, mode); if (hasFRAM) fram.write(FRAM_SYSTEM_MODE, mode);
return 0; return 0;
} }
@@ -473,13 +126,8 @@ public:
} }
#endif #endif
#ifdef BOARD_OBP40S3 #ifdef BOARD_OBP40S3
// use cursor keys for local mode navigation // grab cursor keys to disable page navigation
if (key == 9) { if (key == 9 or key == 10) {
incMode();
return 0;
}
if (key == 10) {
decMode();
return 0; return 0;
} }
// standby / deep sleep // standby / deep sleep
@@ -520,35 +168,225 @@ public:
GwConfigHandler *config = commonData->config; GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger; GwLog *logger = commonData->logger;
// Get config data
String flashLED = config->getString(config->flashLED);
// Optical warning by limit violation (unused) // Optical warning by limit violation (unused)
if(flashLED == "Limit Violation"){ if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false); setBlinkingLED(false);
setFlashLED(false); setFlashLED(false);
} }
// Logging page information // Logging boat values
LOG_DEBUG(GwLog::LOG,"Drawing at PageSystem, Mode=%c", mode); LOG_DEBUG(GwLog::LOG,"Drawing at PageSystem");
// Draw page
//***********************************************************
uint16_t x0 = 8; // left column
uint16_t y0 = 48; // data table starts here
// Set display in partial refresh mode // Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// call current system page if (mode == 'N') {
switch (mode) {
case 'N': getdisplay().setFont(&Ubuntu_Bold12pt8b);
displayModeNormal(); getdisplay().setCursor(8, 48);
break; getdisplay().print("System Information");
case 'S':
displayModeSettings(); getdisplay().drawXBitmap(320, 25, logo64_bits, logo64_width, logo64_height, commonData->fgcolor);
break;
case 'C': getdisplay().setFont(&Ubuntu_Bold8pt8b);
displayModeConfig(); y0 = 155;
break;
case 'A': char ssid[13];
displayModeSDCard(); snprintf(ssid, 13, "%04X%08X", (uint16_t)(chipid >> 32), (uint32_t)chipid);
break; displayBarcode(String(ssid), 320, 200, 2);
case 'D': getdisplay().setCursor(8, 70);
displayModeDevicelist(); getdisplay().print(String("MCUDEVICE-") + String(ssid));
break;
getdisplay().setCursor(8, 95);
getdisplay().print("Firmware version: ");
getdisplay().setCursor(150, 95);
getdisplay().print(VERSINFO);
getdisplay().setCursor(8, 113);
getdisplay().print("Board version: ");
getdisplay().setCursor(150, 113);
getdisplay().print(BOARDINFO);
getdisplay().print(String(" HW ") + String(PCBINFO));
getdisplay().setCursor(8, 131);
getdisplay().print("Display version: ");
getdisplay().setCursor(150, 131);
getdisplay().print(DISPLAYINFO);
getdisplay().print("; GxEPD2 v");
getdisplay().print(GXEPD2INFO);
getdisplay().setCursor(8, 265);
#ifdef BOARD_OBP60S3
getdisplay().print("Press STBY to enter deep sleep mode");
#endif
#ifdef BOARD_OBP40S3
getdisplay().print("Press wheel to enter deep sleep mode");
#endif
// Flash memory size
uint32_t flash_size = ESP.getFlashChipSize();
getdisplay().setCursor(8, y0);
getdisplay().print("FLASH:");
getdisplay().setCursor(90, y0);
getdisplay().print(String(flash_size / 1024) + String(" kB"));
// PSRAM memory size
uint32_t psram_size = ESP.getPsramSize();
getdisplay().setCursor(8, y0 + 16);
getdisplay().print("PSRAM:");
getdisplay().setCursor(90, y0 + 16);
getdisplay().print(String(psram_size / 1024) + String(" kB"));
// FRAM available / status
getdisplay().setCursor(8, y0 + 32);
getdisplay().print("FRAM:");
getdisplay().setCursor(90, y0 + 32);
getdisplay().print(hasFRAM ? "available" : "not found");
#ifdef BOARD_OBP40S3
// SD-Card
getdisplay().setCursor(8, y0 + 48);
getdisplay().print("SD-Card:");
getdisplay().setCursor(90, y0 + 48);
if (sdcard) {
uint64_t cardsize = SD.cardSize() / (1024 * 1024);
getdisplay().print(String(cardsize) + String(" MB"));
} else {
getdisplay().print("off");
}
#endif
// CPU speed config / active
getdisplay().setCursor(202, y0);
getdisplay().print("CPU speed:");
getdisplay().setCursor(300, y0);
getdisplay().print(cpuspeed);
getdisplay().print(" / ");
int cpu_freq = esp_clk_cpu_freq() / 1000000;
getdisplay().print(String(cpu_freq));
// total RAM free
int Heap_free = esp_get_free_heap_size();
getdisplay().setCursor(202, y0 + 16);
getdisplay().print("Total free:");
getdisplay().setCursor(300, y0 + 16);
getdisplay().print(String(Heap_free));
// RAM free for task
int RAM_free = uxTaskGetStackHighWaterMark(NULL);
getdisplay().setCursor(202, y0 + 32);
getdisplay().print("Task free:");
getdisplay().setCursor(300, y0 + 32);
getdisplay().print(String(RAM_free));
} else if (mode == 'S') {
// Settings
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(x0, 48);
getdisplay().print("System settings");
getdisplay().setFont(&Ubuntu_Bold8pt8b);
x0 = 8;
y0 = 72;
// left column
getdisplay().setCursor(x0, y0);
getdisplay().print("Simulation:");
getdisplay().setCursor(120, y0);
getdisplay().print(simulation ? "on" : "off");
getdisplay().setCursor(x0, y0 + 16);
getdisplay().print("Environment:");
getdisplay().setCursor(120, y0 + 16);
getdisplay().print(env_module);
getdisplay().setCursor(x0, y0 + 32);
getdisplay().print("Buzzer:");
getdisplay().setCursor(120, y0 + 32);
getdisplay().print(buzzer_mode);
getdisplay().setCursor(x0, y0 + 64);
getdisplay().print("GPS:");
getdisplay().setCursor(120, y0 + 64);
getdisplay().print(gps_module);
getdisplay().setCursor(x0, y0 + 80);
getdisplay().print("RTC:");
getdisplay().setCursor(120, y0 + 80);
getdisplay().print(rtc_module);
getdisplay().setCursor(x0, y0 + 96);
getdisplay().print("Wifi:");
getdisplay().setCursor(120, y0 + 96);
getdisplay().print(commonData->status.wifiApOn ? "on" : "off");
// Home location
getdisplay().setCursor(x0, y0 + 128);
getdisplay().print("Home Lat.:");
getdisplay().setCursor(120, y0 + 128);
getdisplay().print(formatLatitude(homelat));
getdisplay().setCursor(x0, y0 + 144);
getdisplay().print("Home Lon.:");
getdisplay().setCursor(120, y0 + 144);
getdisplay().print(formatLongitude(homelon));
// right column
getdisplay().setCursor(202, y0);
getdisplay().print("Batt. sensor:");
getdisplay().setCursor(320, y0);
getdisplay().print(batt_sensor);
// Solar sensor
getdisplay().setCursor(202, y0 + 16);
getdisplay().print("Solar sensor:");
getdisplay().setCursor(320, y0 + 16);
getdisplay().print(solar_sensor);
// Generator sensor
getdisplay().setCursor(202, y0 + 32);
getdisplay().print("Gen. sensor:");
getdisplay().setCursor(320, y0 + 32);
getdisplay().print(gen_sensor);
// Gyro sensor
} else if (mode == 'C') {
// Card info
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(8, 48);
getdisplay().print("SD Card info");
getdisplay().setFont(&Ubuntu_Bold8pt8b);
x0 = 20;
y0 = 72;
getdisplay().setCursor(x0, y0);
getdisplay().print("Work in progress...");
} else {
// NMEA2000 device list
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(8, 48);
getdisplay().print("NMEA2000 device list");
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(20, 80);
getdisplay().print("RxD: ");
getdisplay().print(String(commonData->status.n2kRx));
getdisplay().setCursor(20, 100);
getdisplay().print("TxD: ");
getdisplay().print(String(commonData->status.n2kTx));
} }
// Update display // Update display

View File

@@ -1117,6 +1117,21 @@
"obp60":"true" "obp60":"true"
} }
}, },
{
"name": "valueprecision",
"label": "Display value precision",
"type": "list",
"default": "2",
"description": "Maximum number of decimal places to display [1|2]",
"list": [
"1",
"2"
],
"category": "OBP60 Display",
"capabilities": {
"obp60":"true"
}
},
{ {
"name": "backlight", "name": "backlight",
"label": "Backlight Mode", "label": "Backlight Mode",

View File

@@ -1129,6 +1129,21 @@
"obp40": "true" "obp40": "true"
} }
}, },
{
"name": "valueprecision",
"label": "Display value precision",
"type": "list",
"default": "2",
"description": "Maximum number of decimal places to display [1|2]",
"list": [
"1",
"2"
],
"category": "OBP40 Display",
"capabilities": {
"obp40":"true"
}
},
{ {
"name": "backlight", "name": "backlight",
"label": "Backlight Mode", "label": "Backlight Mode",

View File

@@ -1,132 +1,179 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# A tool to generate that part of config.json that deals with pages and fields.
#
#Usage: 1. modify this script (e.g.add a page, change number of fields, etc.)
# 2. Delete all lines from config.json from the curly backet before "name": "page1type" to o the end of the file (as of today, delete from line 917 to the end of the File)
# 3. run ./gen_set.py >> config.json
"""
A tool to generate that part of config.json that deals with pages and fields.
Usage example:
1. Delete all lines from config.json from the curly backet before
"name": "page1type" to the end of the file
2. run ./gen_set.py -d obp60 -p 10 >> config.json
TODO Better handling of default pages
"""
import os
import sys
import getopt
import re
import json import json
# List of all pages and the number of parameters they expect. __version__ = "0.2"
no_of_fields_per_page = {
"Wind": 0,
"XTETrack": 0,
"Battery2": 0,
"Battery": 0,
"BME280": 0,
"Clock": 0,
"Compass" : 0,
"DST810": 0,
"Fluid": 1,
"FourValues2": 4,
"FourValues": 4,
"Generator": 0,
"KeelPosition": 0,
"OneValue": 1,
"RollPitch": 2,
"RudderPosition": 0,
"SixValues" : 6,
"Solar": 0,
"ThreeValues": 3,
"TwoValues": 2,
"Voltage": 0,
"WhitePage": 0,
"WindPlot": 0,
"WindRose": 0,
"WindRoseFlex": 6,
}
# No changes needed beyond this point def detect_pages(filename):
# max number of pages supported by OBP60 # returns a dictionary with page name and the number of gui fields
no_of_pages = 10 pagefiles = []
# Default selection for each page with open(filename, 'r') as fh:
default_pages = [ pattern = r'extern PageDescription\s*register(Page[^;\s]*)'
"Voltage", for line in fh:
"WindRose", if "extern PageDescription" in line:
"OneValue", match = re.search(pattern, line)
"TwoValues", if match:
"ThreeValues", pagefiles.append(match.group(1))
"FourValues", try:
"FourValues2", pagefiles.remove('PageSystem')
"Clock", except ValueError:
"RollPitch", pass
"Battery2", pagedata = {}
] for pf in pagefiles:
numbers = [ filename = pf + ".cpp"
"one", with open(filename, 'r') as fh:
"two", content = fh.read()
"three", pattern = r'PageDescription\s*?register' + pf + r'\s*\(\s*"([^"]+)".*?\n\s*(\d+)'
"four", match = re.search(pattern, content, re.DOTALL)
"five", if match:
"six", pagedata[match.group(1)] = int(match.group(2))
"seven", return pagedata
"eight",
"nine",
"ten",
]
pages = sorted(no_of_fields_per_page.keys())
max_no_of_fields_per_page = max(no_of_fields_per_page.values())
output = [] def get_default_page(pageno):
# Default selection for each page
default_pages = (
"Voltage",
"WindRose",
"OneValue",
"TwoValues",
"ThreeValues",
"FourValues",
"FourValues2",
"Clock",
"RollPitch",
"Battery2"
)
if pageno > len(default_pages):
return "OneValue"
return default_pages[pageno - 1]
for page_no in range(1, no_of_pages + 1): def number_to_text(number):
page_data = { if number < 0 or number > 99:
"name": f"page{page_no}type", raise ValueError("Only numbers from 0 to 99 are allowed.")
"label": "Type", numbers = ("zero", "one", "two", "three", "four", "five", "six", "seven",
"type": "list", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen",
"default": default_pages[page_no - 1], "fifteen", "sixteen", "seventeen", "eighteen", "nineteen")
"description": f"Type of page for page {page_no}", tens = ("", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy",
"list": pages, "eighty", "ninety")
"category": f"OBP60 Page {page_no}", if number < 20:
"capabilities": {"obp60": "true"}, return numbers[number]
"condition": [{"visiblePages": vp} for vp in range(page_no, no_of_pages + 1)], else:
#"fields": [], q, r = divmod(number, 10)
} return tens[q] + numbers[r]
output.append(page_data)
for field_no in range(1, max_no_of_fields_per_page + 1): def create_json(device, no_of_pages, pagedata):
field_data = {
"name": f"page{page_no}value{field_no}", pages = sorted(pagedata.keys())
"label": f"Field {field_no}", max_no_of_fields_per_page = max(pagedata.values())
"type": "boatData",
"default": "", output = []
"description": f"The display for field {numbers[field_no - 1]}",
"category": f"OBP60 Page {page_no}", for page_no in range(1, no_of_pages + 1):
"capabilities": {"obp60": "true"}, page_data = {
"condition": [ "name": f"page{page_no}type",
{f"page{page_no}type": page} "label": "Type",
for page in pages "type": "list",
if no_of_fields_per_page[page] >= field_no "default": get_default_page(page_no),
"description": f"Type of page for page {page_no}",
"list": pages,
"category": f"{device.upper()} Page {page_no}",
"capabilities": {device.lower(): "true"},
"condition": [{"visiblePages": vp} for vp in range(page_no, no_of_pages + 1)],
#"fields": [],
}
output.append(page_data)
for field_no in range(1, max_no_of_fields_per_page + 1):
field_data = {
"name": f"page{page_no}value{field_no}",
"label": f"Field {field_no}",
"type": "boatData",
"default": "",
"description": "The display for field {}".format(number_to_text(field_no)),
"category": f"{device.upper()} Page {page_no}",
"capabilities": {device.lower(): "true"},
"condition": [
{f"page{page_no}type": page}
for page in pages
if pagedata[page] >= field_no
],
}
output.append(field_data)
fluid_data ={
"name": f"page{page_no}fluid",
"label": "Fluid type",
"type": "list",
"default": "0",
"list": [
{"l":"Fuel (0)","v":"0"},
{"l":"Water (1)","v":"1"},
{"l":"Gray Water (2)","v":"2"},
{"l":"Live Well (3)","v":"3"},
{"l":"Oil (4)","v":"4"},
{"l":"Black Water (5)","v":"5"},
{"l":"Fuel Gasoline (6)","v":"6"}
], ],
} "description": "Fluid type in tank",
output.append(field_data) "category": f"{device.upper()} Page {page_no}",
"capabilities": {
device.lower(): "true"
},
"condition":[{f"page{page_no}type":"Fluid"}]
}
output.append(fluid_data)
fluid_data ={ return json.dumps(output, indent=4)
"name": f"page{page_no}fluid",
"label": "Fluid type",
"type": "list",
"default": "0",
"list": [
{"l":"Fuel (0)","v":"0"},
{"l":"Water (1)","v":"1"},
{"l":"Gray Water (2)","v":"2"},
{"l":"Live Well (3)","v":"3"},
{"l":"Oil (4)","v":"4"},
{"l":"Black Water (5)","v":"5"},
{"l":"Fuel Gasoline (6)","v":"6"}
],
"description": "Fluid type in tank",
"category": f"OBP60 Page {page_no}",
"capabilities": {
"obp60":"true"
},
"condition":[{f"page{page_no}type":"Fluid"}]
}
output.append(fluid_data)
json_output = json.dumps(output, indent=4) def usage():
# print omitting first and last line containing [ ] of JSON array print("{} v{}".format(os.path.basename(__file__), __version__))
#print(json_output[1:-1]) print()
# print omitting first line containing [ of JSON array print("Command line options")
print(json_output[1:]) print(" -d --device device name to use e.g. obp60")
# print(",") print(" -p --pages number of pages to create")
print(" -h show this help")
print()
if __name__ == '__main__':
try:
options, remainder = getopt.getopt(sys.argv[1:], 'd:p:', ['device=','--pages='])
except getopt.GetoptError as err:
print(err)
usage()
sys.exit(2)
device = "obp60"
no_of_pages = 10
for opt, arg in options:
if opt in ('-d', '--device'):
device = arg
elif opt in ('-p', '--pages'):
no_of_pages = int(arg)
elif opt == '-h':
usage()
sys.exit(0)
# automatic detect pages and number of fields from sourcecode
pagedata = detect_pages("obp60task.cpp")
json_output = create_json(device, no_of_pages, pagedata)
# print omitting first line containing [ of JSON array
print(json_output[1:])

View File

@@ -54,13 +54,31 @@ void OBP60Init(GwApi *api){
// Check I2C devices // Check I2C devices
// Init hardware // Init hardware
hardwareInit(api); hardwareInit(api);
// Init power // Init power rail 5.0V
String powermode = api->getConfig()->getConfigItem(api->getConfig()->powerMode,true)->asString(); String powermode = api->getConfig()->getConfigItem(api->getConfig()->powerMode,true)->asString();
api->getLogger()->logDebug(GwLog::DEBUG,"Power Mode is: %s", powermode.c_str()); api->getLogger()->logDebug(GwLog::DEBUG,"Power Mode is: %s", powermode.c_str());
powerInit(powermode); if(powermode == "Max Power" || powermode == "Only 5.0V"){
#ifdef HARDWARE_V21
setPortPin(OBP_POWER_50, true); // Power on 5.0V rail
#endif
#ifdef BOARD_OBP40S3
setPortPin(OBP_POWER_EPD, true);// Power on ePaper display
setPortPin(OBP_POWER_SD, true); // Power on SD card
#endif
}
else{
#ifdef HARDWARE_V21
setPortPin(OBP_POWER_50, false); // Power off 5.0V rail
#endif
#ifdef BOARD_OBP40S3
setPortPin(OBP_POWER_EPD, false);// Power off ePaper display
setPortPin(OBP_POWER_SD, false); // Power off SD card
#endif
}
#ifdef BOARD_OBP40S3 #ifdef BOARD_OBP40S3
bool sdcard = config->getBool(config->useSDCard); bool sdcard = config->getBool(config->useSDCard);
@@ -873,6 +891,7 @@ void OBP60Task(GwApi *api){
else{ else{
getdisplay().fillScreen(commonData.fgcolor); // Clear display getdisplay().fillScreen(commonData.fgcolor); // Clear display
#ifdef DISPLAY_GDEY042T81 #ifdef DISPLAY_GDEY042T81
getdisplay().hibernate(); // Set display in hybenate mode
getdisplay().init(115200, true, 2, false); // Init for Waveshare boards with "clever" reset circuit, 2ms reset pulse getdisplay().init(115200, true, 2, false); // Init for Waveshare boards with "clever" reset circuit, 2ms reset pulse
#else #else
getdisplay().init(115200); // Init for normal displays getdisplay().init(115200); // Init for normal displays
@@ -900,6 +919,7 @@ void OBP60Task(GwApi *api){
else{ else{
getdisplay().fillScreen(commonData.fgcolor); // Clear display getdisplay().fillScreen(commonData.fgcolor); // Clear display
#ifdef DISPLAY_GDEY042T81 #ifdef DISPLAY_GDEY042T81
getdisplay().hibernate(); // Set display in hybenate mode
getdisplay().init(115200, true, 2, false); // Init for Waveshare boards with "clever" reset circuit, 2ms reset pulse getdisplay().init(115200, true, 2, false); // Init for Waveshare boards with "clever" reset circuit, 2ms reset pulse
#else #else
getdisplay().init(115200); // Init for normal displays getdisplay().init(115200); // Init for normal displays
@@ -924,6 +944,7 @@ void OBP60Task(GwApi *api){
else{ else{
getdisplay().fillScreen(commonData.fgcolor); // Clear display getdisplay().fillScreen(commonData.fgcolor); // Clear display
#ifdef DISPLAY_GDEY042T81 #ifdef DISPLAY_GDEY042T81
getdisplay().hibernate(); // Set display in hybenate mode
getdisplay().init(115200, true, 2, false); // Init for Waveshare boards with "clever" reset circuit, 2ms reset pulse getdisplay().init(115200, true, 2, false); // Init for Waveshare boards with "clever" reset circuit, 2ms reset pulse
#else #else
getdisplay().init(115200); // Init for normal displays getdisplay().init(115200); // Init for normal displays