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

4 Commits

Author SHA1 Message Date
fbe5e343b4 Page anchor ongoing work 2025-07-29 19:12:55 +02:00
1637bdf9ee Start implementing config menu with page anchor 2025-07-29 15:30:57 +02:00
c7a580612e More work on page anchor 2025-07-28 20:44:34 +02:00
a311f2f164 Preparation for new page "Anchor" 2025-07-28 13:14:06 +02:00
11 changed files with 597 additions and 27 deletions

View File

@@ -0,0 +1,101 @@
/*
Menu system for online configuration
*/
#include "ConfigMenu.h"
ConfigMenuItem::ConfigMenuItem(String itemtype, String itemlabel) {
if (! (itemtype == "int" or itemtype == "bool")) {
valtype = "int";
} else {
valtype = itemtype;
}
label = itemlabel;
min = 0;
max = std::numeric_limits<uint16_t>::max();
}
void ConfigMenuItem::setRange(uint16_t valmin, uint16_t valmax, std::vector<uint16_t> valsteps) {
min = valmin;
max = valmax;
steps = valsteps;
};
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::setPos(int8_t newpos) {
position = newpos;
};
int8_t ConfigMenuItem::getPos() {
return position;
};
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) {
if (items.find(key) != items.end()) {
// duplicate keys not allowed
return nullptr;
}
ConfigMenuItem itm(valtype, "Test1");
return &itm;
// map.insert(std::pair<String, ConfigMenuItem>(itm));
// Append key to index
int8_t ix = items.size();
index[ix] = key;
itm.setPos(ix);
};
void ConfigMenu::setItemDimension(uint16_t itemwidth, uint16_t itemheight) {
w = itemwidth;
h = itemheight;
};
void ConfigMenu::setItemActive(String key) {
uint8_t ix =
activeitem = ix;
};
ConfigMenuItem* ConfigMenu::getActiveItem() {
return nullptr;
};
ConfigMenuItem* ConfigMenu::getItemByIndex(uint8_t index) {
return nullptr;
};
ConfigMenuItem* ConfigMenu::getItemByKey(String Key) {
return nullptr;
};
uint8_t ConfigMenu::getItemCount() {
return items.size();
};
Point ConfigMenu::getXY() {
return {x, y};
}
/*
void getRect();
void getItemRect();
*/

View File

@@ -0,0 +1,51 @@
#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);
void setRange(uint16_t valmin, uint16_t valmax, std::vector<uint16_t> steps);
bool setValue(uint16_t newval);
void setPos(int8_t newpos);
int8_t getPos();
};
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;
public:
ConfigMenu(String title, uint16_t menu_x, uint16_t menu_y);
ConfigMenuItem* addItem(String key, String label, String valtype);
void setItemDimension(uint16_t itemwidth, uint16_t itemheight);
void setItemActive(String key);
ConfigMenuItem* getActiveItem();
ConfigMenuItem* getItemByIndex(uint8_t index);
ConfigMenuItem* getItemByKey(String key);
uint8_t getItemCount();
Point getXY();
/* void getRect();
void getItemRect(); */
};

View File

@@ -0,0 +1,25 @@
/*
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;
}

17
lib/obp60task/Graphics.h Normal file
View File

@@ -0,0 +1,17 @@
#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

@@ -276,30 +276,20 @@ 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;

View File

@@ -4,6 +4,7 @@
#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
@@ -62,13 +63,8 @@ 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);

View File

@@ -0,0 +1,339 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
#include "ConfigMenu.h"
/*
Anchor overview with additional associated data
This page is in experimental stage so be warned!
North is up.
Boatdata used
DBS - Water depth
HDT - Boat heading
AWS - Wind strength; Boat not moving so we assume AWS=TWS and AWD=TWD
AWD - Wind direction
LAT/LON - Boat position, current
HDOP - Position error
This is the fist page to contain a configuration page with
data entry option.
Also it will make use of the new alarm function.
Data
Anchor position lat/lon
Depth at anchor position
Chain length used
Boat position current
Depth at boat position
Boat heading
Wind direction
Wind strength
Alarm j/n
Alarm radius
GPS position error
Timestamp while dropping anchor
Drop / raise function in device OBP40 has to be done inside
config mode because of limited number of buttons.
*/
#define anchor_width 16
#define anchor_height 16
static unsigned char anchor_bits[] = {
0x80, 0x01, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, 0xf0, 0x0f, 0x80, 0x01,
0x80, 0x01, 0x88, 0x11, 0x8c, 0x31, 0x8e, 0x71, 0x84, 0x21, 0x86, 0x61,
0x86, 0x61, 0xfc, 0x3f, 0xf8, 0x1f, 0x80, 0x01 };
class PageAnchor : public Page
{
private:
GwConfigHandler *config;
GwLog *logger;
bool simulation = false;
bool holdvalues = false;
String flashLED;
String backlightMode;
String lengthformat;
int scale = 50; // Radius of display circle in meter
bool alarm = false;
bool alarm_enabled = false;
uint8_t alarm_range;
uint8_t chain_length;
uint8_t chain;
bool anchor_set = false;
double anchor_lat;
double anchor_lon;
double anchor_depth;
int anchor_ts; // time stamp anchor dropped
char mode = 'N'; // (N)ormal, (C)onfig
// ConfigMenu menu;
void displayModeNormal(PageData &pageData) {
// Boatvalues: DBS, HDT, AWS, AWD, LAT, LON, HDOP
GwApi::BoatValue *bv_dbs = pageData.values[0]; // DBS
String sval_dbs = formatValue(bv_dbs, *commonData).svalue;
String sunit_dbs = formatValue(bv_dbs, *commonData).unit;
GwApi::BoatValue *bv_hdt = pageData.values[1]; // HDT
String sval_hdt = formatValue(bv_hdt, *commonData).svalue;
GwApi::BoatValue *bv_aws = pageData.values[2]; // AWS
String sval_aws = formatValue(bv_aws, *commonData).svalue;
String sunit_aws = formatValue(bv_aws, *commonData).unit;
GwApi::BoatValue *bv_awd = pageData.values[3]; // AWD
String sval_awd = formatValue(bv_awd, *commonData).svalue;
GwApi::BoatValue *bv_lat = pageData.values[4]; // LAT
String sval_lat = formatValue(bv_lat, *commonData).svalue;
GwApi::BoatValue *bv_lon = pageData.values[5]; // LON
String sval_lon = formatValue(bv_lon, *commonData).svalue;
GwApi::BoatValue *bv_hdop = pageData.values[6]; // HDOP
String sval_hdop = formatValue(bv_hdop, *commonData).svalue;
String sunit_hdop = formatValue(bv_hdop, *commonData).unit;
LOG_DEBUG(GwLog::DEBUG,"Drawing at PageAnchor; DBS=%f, HDT=%f, AWS=%f", bv_dbs->value, bv_hdt->value, bv_aws->value);
Point c = {200, 150}; // center = anchor position
uint16_t r = 125;
Point b = {200, 180}; // boat position while dropping anchor
const std::vector<Point> pts_boat = { // polygon lines
{b.x - 5, b.y},
{b.x - 5, b.y - 10},
{b.x, b.y - 16},
{b.x + 5, b.y - 10},
{b.x + 5, b.y}
};
//rotatePoints und dann Linien zeichnen
// TODO rotate boat according to current heading
//drawPoly(rotatePoints(c, pts, RadToDeg(value2)), commonData->fgcolor);
drawPoly(pts_boat, commonData->fgcolor);
/*size_t polysize = pts_boat.size();
for (size_t i = 0; i < polysize - 1; i++) {
getdisplay().drawLine(pts_boat[i].x, pts_boat[i].y, pts_boat[i+1].x, pts_boat[i+1].y, commonData->fgcolor);
}
// close path
getdisplay().drawLine(pts_boat[polysize-1].x, pts_boat[polysize-1].y, pts_boat[0].x, pts_boat[0].y, commonData->fgcolor);
*/
// Draw wind arrow
const std::vector<Point> pts_wind = {
{c.x, c.y - r + 25},
{c.x - 12, c.y - r - 4},
{c.x, c.y - r + 6},
{c.x + 12, c.y - r - 4}
};
if (bv_awd->valid) {
fillPoly4(rotatePoints(c, pts_wind, bv_awd->value), commonData->fgcolor);
}
// Title and corner value headings
getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(8, 48);
getdisplay().print("Anchor");
getdisplay().setFont(&Ubuntu_Bold10pt8b);
getdisplay().setCursor(8, 200);
getdisplay().print("Depth");
drawTextRalign(392, 38, "Chain");
drawTextRalign(392, 200, "Wind");
// Units
getdisplay().setCursor(8, 272);
getdisplay().print(sunit_dbs);
drawTextRalign(392, 272, sunit_aws);
drawTextRalign(392, 100, lengthformat); // chain unit not implemented
// Corner values
getdisplay().setFont(&Ubuntu_Bold8pt8b);
getdisplay().setCursor(8, 70);
getdisplay().print("Alarm: ");
getdisplay().print(alarm_enabled ? "On" : "Off");
getdisplay().setCursor(8, 90);
getdisplay().print("HDOP");
getdisplay().setCursor(8, 106);
if (bv_hdop->valid) {
getdisplay().print(round(bv_hdop->value), 0);
getdisplay().print(sunit_hdop);
} else {
getdisplay().print("n/a");
}
// Values
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
// Current chain used
getdisplay().setCursor(328, 85);
getdisplay().print("27");
// Depth
getdisplay().setCursor(8, 250);
getdisplay().print(sval_dbs);
// Wind
getdisplay().setCursor(328, 250);
getdisplay().print(sval_aws);
getdisplay().drawCircle(c.x, c.y, r, commonData->fgcolor);
getdisplay().drawCircle(c.x, c.y, r + 1, commonData->fgcolor);
// zoom scale
getdisplay().drawLine(c.x + 10, c.y, c.x + r - 4, c.y, commonData->fgcolor);
// arrow left
getdisplay().drawLine(c.x + 10, c.y, c.x + 16, c.y - 4, commonData->fgcolor);
getdisplay().drawLine(c.x + 10, c.y, c.x + 16, c.y + 4, commonData->fgcolor);
// arrow right
getdisplay().drawLine(c.x + r - 4, c.y, c.x + r - 10, c.y - 4, commonData->fgcolor);
getdisplay().drawLine(c.x + r - 4, c.y, c.x + r - 10, c.y + 4, commonData->fgcolor);
getdisplay().setFont(&Ubuntu_Bold8pt8b);
drawTextCenter(c.x + r / 2, c.y + 8, String(scale) + "m");
// alarm range circle
if (alarm_enabled) {
// alarm range in meter has to be smaller than the scale in meter
// r and r_range are pixel values
uint16_t r_range = int(alarm_range * r / scale);
LOG_DEBUG(GwLog::LOG,"Drawing at PageAnchor; Alarm range = %d", r_range);
getdisplay().drawCircle(c.x, c.y, r_range, commonData->fgcolor);
}
// draw anchor symbol (as bitmap)
getdisplay().drawXBitmap(c.x - anchor_width / 2, c.y - anchor_height / 2,
anchor_bits, anchor_width, anchor_height, commonData->fgcolor);
}
void displayModeConfig() {
// LOG_DEBUG(GwLog::LOG,"Drawing at PageAnchor; Mode=%c", mode);
getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(8, 48);
getdisplay().print("Anchor configuration");
// TODO
// show lat/lon for anchor pos
// show lat/lon for boat pos
// show distance anchor <-> boat
}
public:
PageAnchor(CommonData &common)
// : menu("Options", 80, 20)
{
commonData = &common;
config = commonData->config;
logger = commonData->logger;
logger->logDebug(GwLog::LOG,"Instantiate PageAnchor");
// preload configuration data
simulation = config->getBool(config->useSimuData);
holdvalues = config->getBool(config->holdvalues);
flashLED = config->getString(config->flashLED);
backlightMode = config->getString(config->backlight);
lengthformat = config->getString(config->lengthFormat);
chain_length = config->getInt(config->chainLength);
chain = 0;
anchor_set = false;
alarm_range = 30;
/*
// Initialize config menu
ConfigMenuItem *newitem;
menu.setItemDimension(120, 20);
newitem = menu.addItem("chain", "Chain out", "int");
newitem->setRange(0, 200, {1, 5, 10});
newitem = menu.addItem("chainmax", "Chain max", "int");
newitem->setRange(0, 200, {1, 5, 10});
newitem = menu.addItem("zoom", "Zoom", "int");
newitem->setRange(0, 200, {1, });
newitem = menu.addItem("range", "Alarm range", "int");
newitem->setRange(0, 200, {1, 5, 10});
// START only for OBP40
newitem = menu.addItem("anchor", "Anchor down", "bool");
newitem = menu.addItem("anchor_lat", "Adjust anchor lat.", "int");
newitem->setRange(0, 200, {1, 5, 10});
newitem = menu.addItem("anchor_lon", "Adjust anchor lon.", "int");
newitem->setRange(0, 200, {1, 5, 10});
// STOP only for OBP40
menu.setItemActive("chain"); */
}
void setupKeys(){
Page::setupKeys();
commonData->keydata[0].label = "MODE";
commonData->keydata[1].label = "ALARM";
}
int handleKey(int key){
if (key == 1) { // Switch between normal and config mode
if (mode == 'N') {
mode = 'C';
} else {
mode = 'N';
}
return 0;
}
if (key == 2) { // Toggle alarm
alarm_enabled = !alarm_enabled;
return 0;
}
if (key == 11) { // Code for keylock
commonData->keylock = !commonData->keylock;
return 0;
}
return key;
}
void displayNew(PageData &pageData){
};
int displayPage(PageData &pageData){
// Logging boat values
LOG_DEBUG(GwLog::LOG,"Drawing at PageAnchor; Mode=%c", mode);
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
if (mode == 'N') {
displayModeNormal(pageData);
} else if (mode == 'C') {
displayModeConfig();
}
return PAGE_UPDATE;
};
};
static Page *createPage(CommonData &common){
return new PageAnchor(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 registerPageAnchor(
"Anchor", // Page name
createPage, // Action
0, // Number of bus values depends on selection in Web configuration
{"DBS", "HDT", "AWS", "AWD", "LAT", "LON", "HDOP"}, // Names of bus values undepends on selection in Web configuration (refer GwBoatData.h)
true // Show display header on/off
);
#endif

View File

@@ -75,6 +75,20 @@
"obp60":"true" "obp60":"true"
} }
}, },
{
"name": "chainLength",
"label": "Anchor Chain Length [m]",
"type": "number",
"default": 0,
"check": "checkMinMax",
"min": 0,
"max": 255,
"description": "The length of the anchor chain [0...255m]",
"category": "OBP60 Settings",
"capabilities": {
"obp60":"true"
}
},
{ {
"name": "fuelTank", "name": "fuelTank",
"label": "Fuel Tank [l]", "label": "Fuel Tank [l]",
@@ -1303,6 +1317,7 @@
"default": "Voltage", "default": "Voltage",
"description": "Type of page for page 1", "description": "Type of page for page 1",
"list": [ "list": [
"Anchor",
"BME280", "BME280",
"Battery", "Battery",
"Battery2", "Battery2",
@@ -1584,6 +1599,7 @@
"default": "WindRose", "default": "WindRose",
"description": "Type of page for page 2", "description": "Type of page for page 2",
"list": [ "list": [
"Anchor",
"BME280", "BME280",
"Battery", "Battery",
"Battery2", "Battery2",
@@ -1862,6 +1878,7 @@
"default": "OneValue", "default": "OneValue",
"description": "Type of page for page 3", "description": "Type of page for page 3",
"list": [ "list": [
"Anchor",
"BME280", "BME280",
"Battery", "Battery",
"Battery2", "Battery2",
@@ -2137,6 +2154,7 @@
"default": "TwoValues", "default": "TwoValues",
"description": "Type of page for page 4", "description": "Type of page for page 4",
"list": [ "list": [
"Anchor",
"BME280", "BME280",
"Battery", "Battery",
"Battery2", "Battery2",
@@ -2409,6 +2427,7 @@
"default": "ThreeValues", "default": "ThreeValues",
"description": "Type of page for page 5", "description": "Type of page for page 5",
"list": [ "list": [
"Anchor",
"BME280", "BME280",
"Battery", "Battery",
"Battery2", "Battery2",
@@ -2678,6 +2697,7 @@
"default": "FourValues", "default": "FourValues",
"description": "Type of page for page 6", "description": "Type of page for page 6",
"list": [ "list": [
"Anchor",
"BME280", "BME280",
"Battery", "Battery",
"Battery2", "Battery2",
@@ -2944,6 +2964,7 @@
"default": "FourValues2", "default": "FourValues2",
"description": "Type of page for page 7", "description": "Type of page for page 7",
"list": [ "list": [
"Anchor",
"BME280", "BME280",
"Battery", "Battery",
"Battery2", "Battery2",
@@ -3207,6 +3228,7 @@
"default": "Clock", "default": "Clock",
"description": "Type of page for page 8", "description": "Type of page for page 8",
"list": [ "list": [
"Anchor",
"BME280", "BME280",
"Battery", "Battery",
"Battery2", "Battery2",
@@ -3467,6 +3489,7 @@
"default": "RollPitch", "default": "RollPitch",
"description": "Type of page for page 9", "description": "Type of page for page 9",
"list": [ "list": [
"Anchor",
"BME280", "BME280",
"Battery", "Battery",
"Battery2", "Battery2",
@@ -3724,6 +3747,7 @@
"default": "Battery2", "default": "Battery2",
"description": "Type of page for page 10", "description": "Type of page for page 10",
"list": [ "list": [
"Anchor",
"BME280", "BME280",
"Battery", "Battery",
"Battery2", "Battery2",

View File

@@ -75,6 +75,20 @@
"obp40": "true" "obp40": "true"
} }
}, },
{
"name": "chainLength",
"label": "Anchor Chain Length [m]",
"type": "number",
"default": "0",
"check": "checkMinMax",
"min": 0,
"max": 255,
"description": "The length of the anchor chain [0...255m]",
"category": "OBP40 Settings",
"capabilities": {
"obp40":"true"
}
},
{ {
"name": "fuelTank", "name": "fuelTank",
"label": "Fuel Tank [l]", "label": "Fuel Tank [l]",
@@ -1326,6 +1340,7 @@
"default": "Clock", "default": "Clock",
"description": "Type of page for page 1", "description": "Type of page for page 1",
"list": [ "list": [
"Anchor",
"BME280", "BME280",
"Battery", "Battery",
"Battery2", "Battery2",
@@ -1607,6 +1622,7 @@
"default": "Wind", "default": "Wind",
"description": "Type of page for page 2", "description": "Type of page for page 2",
"list": [ "list": [
"Anchor",
"BME280", "BME280",
"Battery", "Battery",
"Battery2", "Battery2",
@@ -1885,6 +1901,7 @@
"default": "OneValue", "default": "OneValue",
"description": "Type of page for page 3", "description": "Type of page for page 3",
"list": [ "list": [
"Anchor",
"BME280", "BME280",
"Battery", "Battery",
"Battery2", "Battery2",
@@ -2160,6 +2177,7 @@
"default": "TwoValues", "default": "TwoValues",
"description": "Type of page for page 4", "description": "Type of page for page 4",
"list": [ "list": [
"Anchor",
"BME280", "BME280",
"Battery", "Battery",
"Battery2", "Battery2",
@@ -2432,6 +2450,7 @@
"default": "ThreeValues", "default": "ThreeValues",
"description": "Type of page for page 5", "description": "Type of page for page 5",
"list": [ "list": [
"Anchor",
"BME280", "BME280",
"Battery", "Battery",
"Battery2", "Battery2",
@@ -2701,6 +2720,7 @@
"default": "FourValues", "default": "FourValues",
"description": "Type of page for page 6", "description": "Type of page for page 6",
"list": [ "list": [
"Anchor",
"BME280", "BME280",
"Battery", "Battery",
"Battery2", "Battery2",
@@ -2967,6 +2987,7 @@
"default": "FourValues2", "default": "FourValues2",
"description": "Type of page for page 7", "description": "Type of page for page 7",
"list": [ "list": [
"Anchor",
"BME280", "BME280",
"Battery", "Battery",
"Battery2", "Battery2",
@@ -3230,6 +3251,7 @@
"default": "Fluid", "default": "Fluid",
"description": "Type of page for page 8", "description": "Type of page for page 8",
"list": [ "list": [
"Anchor",
"BME280", "BME280",
"Battery", "Battery",
"Battery2", "Battery2",
@@ -3490,6 +3512,7 @@
"default": "RollPitch", "default": "RollPitch",
"description": "Type of page for page 9", "description": "Type of page for page 9",
"list": [ "list": [
"Anchor",
"BME280", "BME280",
"Battery", "Battery",
"Battery2", "Battery2",
@@ -3747,6 +3770,7 @@
"default": "Battery2", "default": "Battery2",
"description": "Type of page for page 10", "description": "Type of page for page 10",
"list": [ "list": [
"Anchor",
"BME280", "BME280",
"Battery", "Battery",
"Battery2", "Battery2",

View File

@@ -34,6 +34,7 @@ no_of_fields_per_page = {
"WindPlot": 0, "WindPlot": 0,
"WindRose": 0, "WindRose": 0,
"WindRoseFlex": 6, "WindRoseFlex": 6,
"Anchor", 0
} }
# No changes needed beyond this point # No changes needed beyond this point

View File

@@ -17,7 +17,7 @@
#include "OBPDataOperations.h" // Functions lib for data operations such as true wind calculation #include "OBPDataOperations.h" // Functions lib for data operations such as true wind calculation
#ifdef BOARD_OBP40S3 #ifdef BOARD_OBP40S3
#include "driver/rtc_io.h" // Needs for weakup from deep sleep #include "driver/rtc_io.h" // Needs for wakeup from deep sleep
#include <FS.h> // SD-Card access #include <FS.h> // SD-Card access
#include <SD.h> #include <SD.h>
#include <SPI.h> #include <SPI.h>
@@ -313,6 +313,8 @@ void registerAllPages(PageList &list){
list.add(&registerPageXTETrack); list.add(&registerPageXTETrack);
extern PageDescription registerPageFluid; extern PageDescription registerPageFluid;
list.add(&registerPageFluid); list.add(&registerPageFluid);
extern PageDescription registerPageAnchor;
list.add(&registerPageAnchor);
} }
// Undervoltage detection for shutdown display // Undervoltage detection for shutdown display