1
0
mirror of https://github.com/thooge/esp32-nmea2000-obp60.git synced 2025-12-16 15:33:05 +01:00

5 Commits

15 changed files with 1163 additions and 886 deletions

View File

@@ -0,0 +1,204 @@
/*
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

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

@@ -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

@@ -14,6 +14,30 @@ 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

@@ -22,6 +22,8 @@ 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

@@ -64,12 +64,6 @@ PCF8574 pcf8574_Out(PCF8574_I2C_ADDR1); // First digital output modul PCF8574 fr
Adafruit_FRAM_I2C fram; Adafruit_FRAM_I2C fram;
bool hasFRAM = false; bool hasFRAM = false;
// SD Card
#ifdef BOARD_OBP40S3
sdmmc_card_t *sdcard;
#endif
bool hasSDCard = false;
// Global vars // Global vars
bool blinkingLED = false; // Enable / disable blinking flash LED bool blinkingLED = false; // Enable / disable blinking flash LED
bool statusLED = false; // Actual status of flash LED on/off bool statusLED = false; // Actual status of flash LED on/off
@@ -84,9 +78,6 @@ LedTaskData *ledTaskData=nullptr;
void hardwareInit(GwApi *api) void hardwareInit(GwApi *api)
{ {
GwLog *logger = api->getLogger();
GwConfigHandler *config = api->getConfig();
Wire.begin(); Wire.begin();
// Init PCF8574 digital outputs // Init PCF8574 digital outputs
Wire.setClock(I2C_SPEED); // Set I2C clock on 10 kHz Wire.setClock(I2C_SPEED); // Set I2C clock on 10 kHz
@@ -96,7 +87,7 @@ void hardwareInit(GwApi *api)
fram = Adafruit_FRAM_I2C(); fram = Adafruit_FRAM_I2C();
if (esp_reset_reason() == ESP_RST_POWERON) { if (esp_reset_reason() == ESP_RST_POWERON) {
// help initialize FRAM // help initialize FRAM
logger->logDebug(GwLog::LOG, "Delaying I2C init for 250ms due to cold boot"); api->getLogger()->logDebug(GwLog::LOG,"Delaying I2C init for 250ms due to cold boot");
delay(250); delay(250);
} }
// FRAM (e.g. MB85RC256V) // FRAM (e.g. MB85RC256V)
@@ -108,68 +99,12 @@ void hardwareInit(GwApi *api)
// Boot counter // Boot counter
uint8_t framcounter = fram.read(0x0000); uint8_t framcounter = fram.read(0x0000);
fram.write(0x0000, framcounter+1); fram.write(0x0000, framcounter+1);
logger->logDebug(GwLog::LOG, "FRAM detected: 0x%04x/0x%04x (counter=%d)", manufacturerID, productID, framcounter); api->getLogger()->logDebug(GwLog::LOG,"FRAM detected: 0x%04x/0x%04x (counter=%d)", manufacturerID, productID, framcounter);
} }
else { else {
hasFRAM = false; hasFRAM = false;
logger->logDebug(GwLog::LOG, "NO FRAM detected"); api->getLogger()->logDebug(GwLog::LOG,"NO FRAM detected");
} }
// SD Card
hasSDCard = false;
#ifdef BOARD_OBP40S3
if (config->getBool(config->useSDCard)) {
esp_err_t ret;
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
host.slot = SPI3_HOST;
logger->logDebug(GwLog::DEBUG, "SDSPI_HOST: max_freq_khz=%d" , host.max_freq_khz);
spi_bus_config_t bus_cfg = {
.mosi_io_num = SD_SPI_MOSI,
.miso_io_num = SD_SPI_MISO,
.sclk_io_num = SD_SPI_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4000,
};
ret = spi_bus_initialize((spi_host_device_t) host.slot, &bus_cfg, SDSPI_DEFAULT_DMA);
if (ret != ESP_OK) {
logger->logDebug(GwLog::ERROR, "Failed to initialize SPI bus for SD card");
} else {
sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
slot_config.gpio_cs = SD_SPI_CS;
slot_config.host_id = (spi_host_device_t) host.slot;
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = false,
.max_files = 5,
.allocation_unit_size = 16 * 1024
};
ret = esp_vfs_fat_sdspi_mount(MOUNT_POINT, &host, &slot_config, &mount_config, &sdcard);
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
logger->logDebug(GwLog::ERROR, "Failed to mount SD card filesystem");
} else {
// ret == 263 could be not powered up yet
logger->logDebug(GwLog::ERROR, "Failed to initialize SD card (error #%d)", ret);
}
} else {
logger->logDebug(GwLog::LOG, "SD card filesystem mounted at '%s'", MOUNT_POINT);
hasSDCard = true;
}
}
if (hasSDCard) {
// read some stats
String features = "";
if (sdcard->is_mem) features += "MEM "; // Memory card
if (sdcard->is_sdio) features += "IO "; // IO Card
if (sdcard->is_mmc) features += "MMC "; // MMC Card
if (sdcard->is_ddr) features += "DDR ";
// if (sdcard->is_uhs1) features += "UHS-1 ";
// ext_csd. Extended information
// uint8_t rev, uint8_t power_class
logger->logDebug(GwLog::LOG, "SD card features: %s", features);
logger->logDebug(GwLog::LOG, "SD card size: %lluMB", ((uint64_t) sdcard->csd.capacity) * sdcard->csd.sector_size / (1024 * 1024));
}
}
#endif
} }
void powerInit(String powermode) { void powerInit(String powermode) {
@@ -362,30 +297,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;
@@ -447,6 +372,24 @@ 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,15 +4,10 @@
#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
#ifdef BOARD_OBP40S3
#include "esp_vfs_fat.h"
#include "sdmmc_cmd.h"
#define MOUNT_POINT "/sdcard"
#endif
// FRAM address reservations 32kB: 0x0000 - 0x7FFF // FRAM address reservations 32kB: 0x0000 - 0x7FFF
// 0x0000 - 0x03ff: single variables // 0x0000 - 0x03ff: single variables
#define FRAM_PAGE_NO 0x0002 #define FRAM_PAGE_NO 0x0002
@@ -21,7 +16,6 @@
#define FRAM_VOLTAGE_AVG 0x000A #define FRAM_VOLTAGE_AVG 0x000A
#define FRAM_VOLTAGE_TREND 0x000B #define FRAM_VOLTAGE_TREND 0x000B
#define FRAM_VOLTAGE_MODE 0x000C #define FRAM_VOLTAGE_MODE 0x000C
// Wind page
#define FRAM_WIND_SIZE 0x000D #define FRAM_WIND_SIZE 0x000D
#define FRAM_WIND_SRC 0x000E #define FRAM_WIND_SRC 0x000E
#define FRAM_WIND_MODE 0x000F #define FRAM_WIND_MODE 0x000F
@@ -31,10 +25,6 @@
extern Adafruit_FRAM_I2C fram; extern Adafruit_FRAM_I2C fram;
extern bool hasFRAM; extern bool hasFRAM;
extern bool hasSDCard;
#ifdef BOARD_OBP40S3
extern sdmmc_card_t *sdcard;
#endif
// Fonts declarations for display (#includes see OBP60Extensions.cpp) // Fonts declarations for display (#includes see OBP60Extensions.cpp)
extern const GFXfont DSEG7Classic_BoldItalic16pt7b; extern const GFXfont DSEG7Classic_BoldItalic16pt7b;
@@ -73,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);
@@ -108,6 +93,7 @@ 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,7 +65,6 @@ 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){
@@ -73,19 +72,6 @@ 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];
@@ -220,13 +206,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
result.unit = "m/s"; result.unit = "m/s";
} }
if(speed < 10){ if(speed < 10){
snprintf(buffer, bsize, fmt_dec_1, speed); snprintf(buffer,bsize,"%3.2f",speed);
} }
else if (speed < 100) { if(speed >= 10 && speed < 100){
snprintf(buffer, bsize, fmt_dec_10, speed); snprintf(buffer,bsize,"%3.1f",speed);
} }
else { if(speed >= 100){
snprintf(buffer, bsize, fmt_dec_100, speed); snprintf(buffer,bsize,"%3.0f",speed);
} }
} }
//######################################################## //########################################################
@@ -252,40 +238,40 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
if(speed < 0.3){ if(speed < 0.3){
speed = 0; speed = 0;
} }
else if (speed < 1.5) { if(speed >=0.3 && speed < 1.5){
speed = 1; speed = 1;
} }
else if (speed < 3.3) { if(speed >=1.5 && speed < 3.3){
speed = 2; speed = 2;
} }
else if (speed < 5.4) { if(speed >=3.3 && speed < 5.4){
speed = 3; speed = 3;
} }
else if (speed < 7.9) { if(speed >=5.4 && speed < 7.9){
speed = 4; speed = 4;
} }
else if (speed < 10.7) { if(speed >=7.9 && speed < 10.7){
speed = 5; speed = 5;
} }
else if (speed < 13.8) { if(speed >=10.7 && speed < 13.8){
speed = 6; speed = 6;
} }
else if (speed < 17.1) { if(speed >=13.8 && speed < 17.1){
speed = 7; speed = 7;
} }
else if (speed < 20.7) { if(speed >=17.1 && speed < 20.7){
speed = 8; speed = 8;
} }
else if (speed < 24.4) { if(speed >=20.7 && speed < 24.4){
speed = 9; speed = 9;
} }
else if (speed < 28.4) { if(speed >=24.4 && speed < 28.4){
speed = 10; speed = 10;
} }
else if (speed < 32.6) { if(speed >=28.4 && speed < 32.6){
speed = 11; speed = 11;
} }
else { if(speed >=32.6){
speed = 12; speed = 12;
} }
result.unit = "bft"; result.unit = "bft";
@@ -299,13 +285,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
} }
else{ else{
if(speed < 10){ if(speed < 10){
snprintf(buffer, bsize, fmt_dec_1, speed); snprintf(buffer,bsize,"%3.2f",speed);
} }
else if (speed < 100){ if(speed >= 10 && speed < 100){
snprintf(buffer, bsize, fmt_dec_10, speed); snprintf(buffer,bsize,"%3.1f",speed);
} }
else { if(speed >= 100){
snprintf(buffer, bsize, fmt_dec_100, speed); snprintf(buffer,bsize,"%3.0f",speed);
} }
} }
} }
@@ -351,13 +337,10 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
dop = 99.9; dop = 99.9;
} }
if(dop < 10){ if(dop < 10){
snprintf(buffer, bsize, fmt_dec_1, dop); snprintf(buffer,bsize,"%3.2f",dop);
} }
else if(dop < 100){ if(dop >= 10 && dop < 100){
snprintf(buffer, bsize, fmt_dec_10, dop); snprintf(buffer,bsize,"%3.1f",dop);
}
else {
snprintf(buffer, bsize, fmt_dec_100, dop);
} }
} }
//######################################################## //########################################################
@@ -427,13 +410,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
result.unit = "m"; result.unit = "m";
} }
if(depth < 10){ if(depth < 10){
snprintf(buffer, bsize, fmt_dec_1, depth); snprintf(buffer,bsize,"%3.2f",depth);
} }
else if (depth < 100){ if(depth >= 10 && depth < 100){
snprintf(buffer, bsize, fmt_dec_10, depth); snprintf(buffer,bsize,"%3.1f",depth);
} }
else { if(depth >= 100){
snprintf(buffer, bsize, fmt_dec_100, depth); snprintf(buffer,bsize,"%3.0f",depth);
} }
} }
//######################################################## //########################################################
@@ -447,11 +430,11 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
xte = rawvalue; xte = rawvalue;
} }
if (xte >= 100) { if (xte >= 100) {
snprintf(buffer, bsize, fmt_dec_100, value->value); snprintf(buffer,bsize,"%3.0f",value->value);
} else if (xte >= 10) { } else if (xte >= 10) {
snprintf(buffer, bsize, fmt_dec_10, value->value); snprintf(buffer,bsize,"%3.1f",value->value);
} else { } else {
snprintf(buffer, bsize, fmt_dec_1, value->value); snprintf(buffer,bsize,"%3.2f",value->value);
} }
result.unit = "nm"; result.unit = "nm";
} }
@@ -478,13 +461,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
result.unit = "K"; result.unit = "K";
} }
if(temp < 10){ if(temp < 10){
snprintf(buffer, bsize, fmt_dec_1, temp); snprintf(buffer,bsize,"%3.2f",temp);
} }
else if (temp < 100) { if(temp >= 10 && temp < 100){
snprintf(buffer, bsize, fmt_dec_10, temp); snprintf(buffer,bsize,"%3.1f",temp);
} }
else { if(temp >= 100){
snprintf(buffer, bsize, fmt_dec_100, temp); snprintf(buffer,bsize,"%3.0f",temp);
} }
} }
//######################################################## //########################################################
@@ -506,17 +489,17 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
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, fmt_dec_1, distance); snprintf(buffer,bsize,"%3.2f",distance);
} }
else if (distance < 100){ if(distance >= 10 && distance < 100){
snprintf(buffer, bsize, fmt_dec_10, distance); snprintf(buffer,bsize,"%3.1f",distance);
} }
else { if(distance >= 100){
snprintf(buffer, bsize, fmt_dec_100, distance); snprintf(buffer,bsize,"%3.0f",distance);
} }
} }
//######################################################## //########################################################
@@ -564,10 +547,10 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
voltage = rawvalue; voltage = rawvalue;
} }
if(voltage < 10){ if(voltage < 10){
snprintf(buffer, bsize, fmt_dec_1, voltage); snprintf(buffer,bsize,"%3.2f",voltage);
} }
else{ else{
snprintf(buffer, bsize, fmt_dec_10, voltage); snprintf(buffer,bsize,"%3.1f",voltage);
} }
result.unit = "V"; result.unit = "V";
} }
@@ -583,13 +566,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
current = rawvalue; current = rawvalue;
} }
if(current < 10){ if(current < 10){
snprintf(buffer, bsize, fmt_dec_1, current); snprintf(buffer,bsize,"%3.2f",current);
} }
else if(current < 100) { if(current >= 10 && current < 100){
snprintf(buffer, bsize, fmt_dec_10, current); snprintf(buffer,bsize,"%3.1f",current);
} }
else { if(current >= 100){
snprintf(buffer, bsize, fmt_dec_100, current); snprintf(buffer,bsize,"%3.0f",current);
} }
result.unit = "A"; result.unit = "A";
} }
@@ -605,13 +588,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
temperature = rawvalue; temperature = rawvalue;
} }
if(temperature < 10){ if(temperature < 10){
snprintf(buffer, bsize, fmt_dec_1, temperature); snprintf(buffer,bsize,"%3.2f",temperature);
} }
else if (temperature < 100) { if(temperature >= 10 && temperature < 100){
snprintf(buffer, bsize, fmt_dec_10, temperature); snprintf(buffer,bsize,"%3.1f",temperature);
} }
else { if(temperature >= 100){
snprintf(buffer, bsize, fmt_dec_100, temperature); snprintf(buffer,bsize,"%3.0f",temperature);
} }
result.unit = "Deg C"; result.unit = "Deg C";
} }
@@ -627,13 +610,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
temperature = rawvalue; temperature = rawvalue;
} }
if(temperature < 10){ if(temperature < 10){
snprintf(buffer, bsize, fmt_dec_1, temperature); snprintf(buffer,bsize,"%3.2f",temperature);
} }
else if(temperature < 100) { if(temperature >= 10 && temperature < 100){
snprintf(buffer, bsize, fmt_dec_10, temperature); snprintf(buffer,bsize,"%3.1f",temperature);
} }
else { if(temperature >= 100){
snprintf(buffer, bsize, fmt_dec_100, temperature); snprintf(buffer,bsize,"%3.0f",temperature);
} }
result.unit = "Deg C"; result.unit = "Deg C";
} }
@@ -649,13 +632,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
humidity = rawvalue; humidity = rawvalue;
} }
if(humidity < 10){ if(humidity < 10){
snprintf(buffer, bsize, fmt_dec_1, humidity); snprintf(buffer,bsize,"%3.2f",humidity);
} }
else if(humidity < 100) { if(humidity >= 10 && humidity < 100){
snprintf(buffer, bsize, fmt_dec_10, humidity); snprintf(buffer,bsize,"%3.1f",humidity);
} }
else { if(humidity >= 100){
snprintf(buffer, bsize, fmt_dec_100, humidity); snprintf(buffer,bsize,"%3.0f",humidity);
} }
result.unit = "%"; result.unit = "%";
} }
@@ -671,13 +654,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
volume = rawvalue; volume = rawvalue;
} }
if(volume < 10){ if(volume < 10){
snprintf(buffer, bsize, fmt_dec_1, volume); snprintf(buffer,bsize,"%3.2f",volume);
} }
else if (volume < 100) { if(volume >= 10 && volume < 100){
snprintf(buffer, bsize, fmt_dec_10, volume); snprintf(buffer,bsize,"%3.1f",volume);
} }
else if (volume >= 100) { if(volume >= 100){
snprintf(buffer, bsize, fmt_dec_100, volume); snprintf(buffer,bsize,"%3.0f",volume);
} }
result.unit = "%"; result.unit = "%";
} }
@@ -693,13 +676,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
volume = rawvalue; volume = rawvalue;
} }
if(volume < 10){ if(volume < 10){
snprintf(buffer, bsize, fmt_dec_1, volume); snprintf(buffer,bsize,"%3.2f",volume);
} }
else if (volume < 100) { if(volume >= 10 && volume < 100){
snprintf(buffer, bsize, fmt_dec_10, volume); snprintf(buffer,bsize,"%3.1f",volume);
} }
else { if(volume >= 100){
snprintf(buffer, bsize, fmt_dec_100, volume); snprintf(buffer,bsize,"%3.0f",volume);
} }
result.unit = "l"; result.unit = "l";
} }
@@ -715,13 +698,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
flow = rawvalue; flow = rawvalue;
} }
if(flow < 10){ if(flow < 10){
snprintf(buffer, bsize, fmt_dec_1, flow); snprintf(buffer,bsize,"%3.2f",flow);
} }
else if (flow < 100) { if(flow >= 10 && flow < 100){
snprintf(buffer, bsize, fmt_dec_10, flow); snprintf(buffer,bsize,"%3.1f",flow);
} }
else { if(flow >= 100){
snprintf(buffer, bsize, fmt_dec_100, flow); snprintf(buffer,bsize,"%3.0f",flow);
} }
result.unit = "l/min"; result.unit = "l/min";
} }
@@ -729,7 +712,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
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; generic = value->value; // Value in l/min
rawvalue = value->value; rawvalue = value->value;
} }
else{ else{
@@ -737,13 +720,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
generic = rawvalue; generic = rawvalue;
} }
if(generic < 10){ if(generic < 10){
snprintf(buffer, bsize, fmt_dec_1, generic); snprintf(buffer,bsize,"%3.2f",generic);
} }
else if (generic < 100) { if(generic >= 10 && generic < 100){
snprintf(buffer, bsize, fmt_dec_10, generic); snprintf(buffer,bsize,"%3.1f",generic);
} }
else { if(generic >= 100){
snprintf(buffer, bsize, fmt_dec_100, generic); snprintf(buffer,bsize,"%3.0f",generic);
} }
result.unit = ""; result.unit = "";
} }
@@ -759,13 +742,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
dplace = rawvalue; dplace = rawvalue;
} }
if(dplace < 10){ if(dplace < 10){
snprintf(buffer, bsize, fmt_dec_1, dplace); snprintf(buffer,bsize,"%3.2f",dplace);
} }
else if (dplace < 100) { if(dplace >= 10 && dplace < 100){
snprintf(buffer, bsize, fmt_dec_10, dplace); snprintf(buffer,bsize,"%3.1f",dplace);
} }
else { if(dplace >= 100){
snprintf(buffer, bsize, fmt_dec_100, dplace); snprintf(buffer,bsize,"%3.0f",dplace);
} }
result.unit = "%"; result.unit = "%";
} }
@@ -801,13 +784,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
rpm = rawvalue; rpm = rawvalue;
} }
if(rpm < 10){ if(rpm < 10){
snprintf(buffer, bsize, fmt_dec_1, rpm); snprintf(buffer,bsize,"%3.2f",rpm);
} }
else if (rpm < 100) { if(rpm >= 10 && rpm < 100){
snprintf(buffer, bsize, fmt_dec_10, rpm); snprintf(buffer,bsize,"%3.1f",rpm);
} }
else { if(rpm >= 100){
snprintf(buffer, bsize, fmt_dec_100, rpm); snprintf(buffer,bsize,"%3.0f",rpm);
} }
result.unit = "rpm"; result.unit = "rpm";
} }
@@ -816,13 +799,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
//######################################################## //########################################################
else{ else{
if(value->value < 10){ if(value->value < 10){
snprintf(buffer, bsize, fmt_dec_1, value->value); snprintf(buffer,bsize,"%3.2f",value->value);
} }
else if (value->value < 100) { if(value->value >= 10 && value->value < 100){
snprintf(buffer, bsize, fmt_dec_10, value->value); snprintf(buffer,bsize,"%3.1f",value->value);
} }
else { if(value->value >= 100){
snprintf(buffer, bsize, fmt_dec_100, value->value); snprintf(buffer,bsize,"%3.0f",value->value);
} }
result.unit = ""; result.unit = "";
} }

View File

@@ -82,7 +82,7 @@
// Direction pin for RS485 NMEA0183 // Direction pin for RS485 NMEA0183
#define OBP_DIRECTION_PIN 8 #define OBP_DIRECTION_PIN 8
// I2C // I2C
#define I2C_SPEED 100000UL // 100kHz clock speed on I2C bus #define I2C_SPEED 10000UL // 10kHz clock speed on I2C bus
#define OBP_I2C_SDA 21 #define OBP_I2C_SDA 21
#define OBP_I2C_SCL 38 #define OBP_I2C_SCL 38
// DS1388 RTC // DS1388 RTC
@@ -120,10 +120,10 @@
#define SHOW_TIME 6000 // Show time in [ms] for logo and WiFi QR code #define SHOW_TIME 6000 // Show time in [ms] for logo and WiFi QR code
#define FULL_REFRESH_TIME 600 // Refresh cycle time in [s][600...3600] for full display update (very important healcy function) #define FULL_REFRESH_TIME 600 // Refresh cycle time in [s][600...3600] for full display update (very important healcy function)
// SPI SD-Card // SPI SD-Card
#define SD_SPI_CS GPIO_NUM_10 #define SD_SPI_CS 10
#define SD_SPI_MOSI GPIO_NUM_40 #define SD_SPI_MOSI 40
#define SD_SPI_CLK GPIO_NUM_39 #define SD_SPI_CLK 39
#define SD_SPI_MISO GPIO_NUM_13 #define SD_SPI_MISO 13
// GPS (NEO-6M, NEO-M8N, ATGM336H) // GPS (NEO-6M, NEO-M8N, ATGM336H)
#define OBP_GPS_RX 19 #define OBP_GPS_RX 19

View File

@@ -1,23 +1,15 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
/*
* Special system page, called directly with fast key sequence 5,4
* Out of normal page order.
* Consists of some sub-pages with following content:
* 1. Hard and software information
* 2. System settings
* 3. NMEA2000 device list
* 4. SD Card information if available
*/
#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"
#ifdef BOARD_OBP40S3 #ifdef BOARD_OBP40S3
#include "dirent.h" #include <SD.h>
#include <FS.h>
#endif #endif
#define STRINGIZE_IMPL(x) #x #define STRINGIZE_IMPL(x) #x
@@ -28,12 +20,42 @@
#define DISPLAYINFO STRINGIZE(EPDTYPE) #define DISPLAYINFO STRINGIZE(EPDTYPE)
#define GXEPD2INFO STRINGIZE(GXEPD2VERS) #define GXEPD2INFO STRINGIZE(GXEPD2VERS)
/*
* Special system page, called directly with fast key sequence 5,4
* Out of normal page order.
* Consists of some sub-pages with following content:
* 1. Hard and software information
* 2. System settings
* 3. System configuration: running and NVRAM
* 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: private:
GwConfigHandler *config;
GwLog *logger;
// NVRAM config options
String flashLED;
// Generic data access
uint64_t chipid; uint64_t chipid;
bool simulation; bool simulation;
bool use_sdcard; bool sdcard;
String buzzer_mode; String buzzer_mode;
uint8_t buzzer_power; uint8_t buzzer_power;
String cpuspeed; String cpuspeed;
@@ -48,161 +70,59 @@ private:
double homelat; double homelat;
double homelon; double homelon;
char mode = 'N'; // (N)ormal, (S)ettings, (D)evice list, (C)ard 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
public: ConfigMenu *menu;
PageSystem(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageSystem");
if (hasFRAM) {
mode = fram.read(FRAM_SYSTEM_MODE);
common.logger->logDebug(GwLog::DEBUG, "Loaded mode '%c' from FRAM", mode);
}
chipid = ESP.getEfuseMac();
simulation = common.config->getBool(common.config->useSimuData);
#ifdef BOARD_OBP40S3
use_sdcard = common.config->getBool(common.config->useSDCard);
#endif
buzzer_mode = common.config->getString(common.config->buzzerMode);
buzzer_mode.toLowerCase();
buzzer_power = common.config->getInt(common.config->buzzerPower);
cpuspeed = common.config->getString(common.config->cpuSpeed);
env_module = common.config->getString(common.config->useEnvSensor);
rtc_module = common.config->getString(common.config->useRTC);
gps_module = common.config->getString(common.config->useGPS);
batt_sensor = common.config->getString(common.config->usePowSensor1);
solar_sensor = common.config->getString(common.config->usePowSensor2);
gen_sensor = common.config->getString(common.config->usePowSensor3);
rot_sensor = common.config->getString(common.config->useRotSensor);
homelat = common.config->getString(common.config->homeLAT).toDouble();
homelon = common.config->getString(common.config->homeLON).toDouble();
}
void setupKeys() { void incMode() {
commonData->keydata[0].label = "EXIT"; if (mode == 'N') { // Normal
commonData->keydata[1].label = "MODE";
commonData->keydata[2].label = "";
commonData->keydata[3].label = "RST";
commonData->keydata[4].label = "STBY";
commonData->keydata[5].label = "ILUM";
}
int handleKey(int key) {
// do *NOT* handle key #1 this handled by obp60task as exit
// Switch display mode
commonData->logger->logDebug(GwLog::LOG, "System keyboard handler");
if (key == 2) {
if (mode == 'N') {
mode = 'S'; mode = 'S';
} else if (mode == 'S') { } else if (mode == 'S') { // Settings
mode = 'C';
} else if (mode == 'C') { // Config
mode = 'D'; mode = 'D';
} else if (mode == 'D') { } else if (mode == 'D') { // Device list
if (hasSDCard) { 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'; mode = 'C';
} else { } else {
mode = 'N'; mode = 'D';
}
} else {
mode = 'N';
}
if (hasFRAM) fram.write(FRAM_SYSTEM_MODE, mode);
return 0;
}
#ifdef BOARD_OBP60S3
// grab cursor key to disable page navigation
if (key == 3) {
return 0;
}
// soft reset
if (key == 4) {
ESP.restart();
}
// standby / deep sleep
if (key == 5) {
commonData->logger->logDebug(GwLog::LOG, "System going into deep sleep mode...");
deepSleep(*commonData);
}
// Code for keylock
if (key == 11) {
commonData->keylock = !commonData->keylock;
return 0;
}
#endif
#ifdef BOARD_OBP40S3
// grab cursor keys to disable page navigation
if (key == 9 or key == 10) {
return 0;
}
// standby / deep sleep
if (key == 12) {
commonData->logger->logDebug(GwLog::LOG, "System going into deep sleep mode...");
deepSleep(*commonData);
}
#endif
return key;
}
void displayBarcode(String serialno, uint16_t x, uint16_t y, uint16_t s) {
// Barcode with serial number
// x, y is top left corner
// s is pixel size of a single box
QRCode qrcode;
uint8_t qrcodeData[qrcode_getBufferSize(4)];
#ifdef BOARD_OBP40S3
String prefix = "OBP40:SN:";
#endif
#ifdef BOARD_OBP60S3
String prefix = "OBP60:SN:";
#endif
qrcode_initText(&qrcode, qrcodeData, 4, 0, (prefix + serialno).c_str());
int16_t x0 = x;
for (uint8_t j = 0; j < qrcode.size; j++) {
for (uint8_t i = 0; i < qrcode.size; i++) {
if (qrcode_getModule(&qrcode, i, j)) {
getdisplay().fillRect(x, y, s, s, commonData->fgcolor);
}
x += s;
}
y += s;
x = x0;
} }
} }
int displayPage(PageData &pageData){ void displayModeNormal() {
GwConfigHandler *config = commonData->config; // Default system page view
GwLog *logger = commonData->logger;
// Get config data uint16_t y0 = 155;
String flashLED = config->getString(config->flashLED);
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
logger->logDebug(GwLog::LOG, "Drawing at PageSystem, Mode=%c", mode);
// Draw page
//***********************************************************
uint16_t x0 = 8; // left column
uint16_t y0 = 48; // data table starts here
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
if (mode == 'N') {
getdisplay().setFont(&Ubuntu_Bold12pt8b); getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(8, 48); getdisplay().setCursor(8, 48);
getdisplay().print("System Information"); getdisplay().print("System information");
getdisplay().drawXBitmap(320, 25, logo64_bits, logo64_width, logo64_height, commonData->fgcolor); getdisplay().drawXBitmap(320, 25, logo64_bits, logo64_width, logo64_height, commonData->fgcolor);
getdisplay().setFont(&Ubuntu_Bold8pt8b); getdisplay().setFont(&Ubuntu_Bold8pt8b);
y0 = 155;
char ssid[13]; char ssid[13];
snprintf(ssid, 13, "%04X%08X", (uint16_t)(chipid >> 32), (uint32_t)chipid); snprintf(ssid, 13, "%04X%08X", (uint16_t)(chipid >> 32), (uint32_t)chipid);
@@ -261,37 +181,14 @@ public:
getdisplay().setCursor(8, y0 + 48); getdisplay().setCursor(8, y0 + 48);
getdisplay().print("SD-Card:"); getdisplay().print("SD-Card:");
getdisplay().setCursor(90, y0 + 48); getdisplay().setCursor(90, y0 + 48);
if (hasSDCard) { if (sdcard) {
uint64_t cardsize = ((uint64_t) sdcard->csd.capacity) * sdcard->csd.sector_size / (1024 * 1024); uint64_t cardsize = SD.cardSize() / (1024 * 1024);
getdisplay().printf("%llu MB", cardsize); getdisplay().print(String(cardsize) + String(" MB"));
} else { } else {
getdisplay().print("off"); getdisplay().print("off");
} }
#endif #endif
// Uptime
int64_t uptime = esp_timer_get_time() / 1000000;
String uptime_unit;
if (uptime < 120) {
uptime_unit = " seconds";
} else {
if (uptime < 2 * 3600) {
uptime /= 60;
uptime_unit = " minutes";
} else if (uptime < 2 * 3600 * 24) {
uptime /= 3600;
uptime_unit = " hours";
} else {
uptime /= 86400;
uptime_unit = " days";
}
}
getdisplay().setCursor(8, y0 + 80);
getdisplay().print("Uptime:");
getdisplay().setCursor(90, y0 + 80);
getdisplay().print(uptime);
getdisplay().print(uptime_unit);
// CPU speed config / active // CPU speed config / active
getdisplay().setCursor(202, y0); getdisplay().setCursor(202, y0);
getdisplay().print("CPU speed:"); getdisplay().print("CPU speed:");
@@ -314,17 +211,67 @@ public:
getdisplay().print("Task free:"); getdisplay().print("Task free:");
getdisplay().setCursor(300, y0 + 32); getdisplay().setCursor(300, y0 + 32);
getdisplay().print(String(RAM_free)); getdisplay().print(String(RAM_free));
}
} else if (mode == 'S') { void displayModeConfig() {
// Settings // 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().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(x0, 48); getdisplay().setCursor(x0, 48);
getdisplay().print("System settings"); getdisplay().print("System settings");
getdisplay().setFont(&Ubuntu_Bold8pt8b); getdisplay().setFont(&Ubuntu_Bold8pt8b);
x0 = 8;
y0 = 72;
// left column // left column
getdisplay().setCursor(x0, y0); getdisplay().setCursor(x0, y0);
@@ -360,12 +307,10 @@ public:
// Home location // Home location
getdisplay().setCursor(x0, y0 + 128); getdisplay().setCursor(x0, y0 + 128);
getdisplay().print("Home Lat.:"); getdisplay().print("Home Lat.:");
getdisplay().setCursor(120, y0 + 128); drawTextRalign(230, y0 + 128, formatLatitude(homelat));
getdisplay().print(formatLatitude(homelat));
getdisplay().setCursor(x0, y0 + 144); getdisplay().setCursor(x0, y0 + 144);
getdisplay().print("Home Lon.:"); getdisplay().print("Home Lon.:");
getdisplay().setCursor(120, y0 + 144); drawTextRalign(230, y0 + 144, formatLongitude(homelon));
getdisplay().print(formatLongitude(homelon));
// right column // right column
getdisplay().setCursor(202, y0); getdisplay().setCursor(202, y0);
@@ -385,76 +330,43 @@ public:
getdisplay().setCursor(320, y0 + 32); getdisplay().setCursor(320, y0 + 32);
getdisplay().print(gen_sensor); getdisplay().print(gen_sensor);
// Gyro 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;
} else if (mode == 'C') {
// Card info
getdisplay().setFont(&Ubuntu_Bold12pt8b); getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(8, 48); getdisplay().setCursor(8, 48);
getdisplay().print("SD Card info"); getdisplay().print("SD Card info");
getdisplay().setFont(&Ubuntu_Bold8pt8b); getdisplay().setFont(&Ubuntu_Bold8pt8b);
x0 = 20;
y0 = 72;
getdisplay().setCursor(x0, y0); getdisplay().setCursor(x0, y0);
#ifdef BOARD_OBP60S3
// This mode should not be callable by devices without card hardware
// In case of accidential reaching this, display a friendly message
getdisplay().print("This mode is not indended to be reached!\n");
getdisplay().print("There's nothing to see here. Move on.");
#endif
#ifdef BOARD_OBP40S3
getdisplay().print("Work in progress..."); getdisplay().print("Work in progress...");
/* TODO
this code should go somewhere else. only for testing purposes here
identify card as OBP-Card:
magic.dat
version.dat
readme.txt
IMAGES/
CHARTS/
LOGS/
DATA/
hint: file access with fopen, fgets, fread, fclose
*/
// Simple test for magic file in root
getdisplay().setCursor(x0, y0 + 32);
String file_magic = MOUNT_POINT "/magic.dat";
logger->logDebug(GwLog::LOG, "Test magicfile: %s", file_magic.c_str());
struct stat st;
if (stat(file_magic.c_str(), &st) == 0) {
getdisplay().printf("File %s exists", file_magic.c_str());
} else {
getdisplay().printf("File %s not found", file_magic.c_str());
} }
// Root directory check void displayModeDevicelist() {
DIR* dir = opendir(MOUNT_POINT);
int dy = 0;
if (dir != NULL) {
logger->logDebug(GwLog::LOG, "Root directory: %s", MOUNT_POINT);
struct dirent* entry;
while (((entry = readdir(dir)) != NULL) and (dy < 140)) {
getdisplay().setCursor(x0, y0 + 64 + dy);
getdisplay().print(entry->d_name);
// type 1 is file, type 2 is dir
if (entry->d_type == 2) {
getdisplay().print("/");
}
dy += 20;
logger->logDebug(GwLog::DEBUG, " %s type %d", entry->d_name, entry->d_type);
}
closedir(dir);
} else {
logger->logDebug(GwLog::LOG, "Failed to open root directory");
}
#endif
} else {
// NMEA2000 device list // NMEA2000 device list
getdisplay().setFont(&Ubuntu_Bold12pt8b); getdisplay().setFont(&Ubuntu_Bold12pt8b);
getdisplay().setCursor(8, 48); getdisplay().setCursor(8, 48);
@@ -469,6 +381,176 @@ public:
getdisplay().print(String(commonData->status.n2kTx)); getdisplay().print(String(commonData->status.n2kTx));
} }
void storeConfig() {
menu->storeValues();
}
public:
PageSystem(CommonData &common){
commonData = &common;
config = commonData->config;
logger = commonData->logger;
logger->logDebug(GwLog::LOG,"Instantiate PageSystem");
if (hasFRAM) {
mode = fram.read(FRAM_SYSTEM_MODE);
}
flashLED = common.config->getString(common.config->flashLED);
chipid = ESP.getEfuseMac();
simulation = common.config->getBool(common.config->useSimuData);
#ifdef BOARD_OBP40S3
sdcard = common.config->getBool(common.config->useSDCard);
#endif
buzzer_mode = common.config->getString(common.config->buzzerMode);
buzzer_mode.toLowerCase();
buzzer_power = common.config->getInt(common.config->buzzerPower);
cpuspeed = common.config->getString(common.config->cpuSpeed);
env_module = common.config->getString(common.config->useEnvSensor);
rtc_module = common.config->getString(common.config->useRTC);
gps_module = common.config->getString(common.config->useGPS);
batt_sensor = common.config->getString(common.config->usePowSensor1);
solar_sensor = common.config->getString(common.config->usePowSensor2);
gen_sensor = common.config->getString(common.config->usePowSensor3);
rot_sensor = common.config->getString(common.config->useRotSensor);
homelat = common.config->getString(common.config->homeLAT).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(){
commonData->keydata[0].label = "EXIT";
commonData->keydata[1].label = "MODE";
commonData->keydata[2].label = "";
commonData->keydata[3].label = "RST";
commonData->keydata[4].label = "STBY";
commonData->keydata[5].label = "ILUM";
}
virtual int handleKey(int key){
// do *NOT* handle key #1 this handled by obp60task as exit
// Switch display mode
commonData->logger->logDebug(GwLog::LOG, "System keyboard handler");
if (key == 2) {
incMode();
if (hasFRAM) fram.write(FRAM_SYSTEM_MODE, mode);
return 0;
}
#ifdef BOARD_OBP60S3
// grab cursor key to disable page navigation
if (key == 3) {
return 0;
}
// soft reset
if (key == 4) {
ESP.restart();
}
// standby / deep sleep
if (key == 5) {
deepSleep(*commonData);
}
// Code for keylock
if (key == 11) {
commonData->keylock = !commonData->keylock;
return 0;
}
#endif
#ifdef BOARD_OBP40S3
// use cursor keys for local mode navigation
if (key == 9) {
incMode();
return 0;
}
if (key == 10) {
decMode();
return 0;
}
// standby / deep sleep
if (key == 12) {
deepSleep(*commonData);
}
#endif
return key;
}
void displayBarcode(String serialno, uint16_t x, uint16_t y, uint16_t s) {
// Barcode with serial number
// x, y is top left corner
// s is pixel size of a single box
QRCode qrcode;
uint8_t qrcodeData[qrcode_getBufferSize(4)];
#ifdef BOARD_OBP40S3
String prefix = "OBP40:SN:";
#endif
#ifdef BOARD_OBP60S3
String prefix = "OBP60:SN:";
#endif
qrcode_initText(&qrcode, qrcodeData, 4, 0, (prefix + serialno).c_str());
int16_t x0 = x;
for (uint8_t j = 0; j < qrcode.size; j++) {
for (uint8_t i = 0; i < qrcode.size; i++) {
if (qrcode_getModule(&qrcode, i, j)) {
getdisplay().fillRect(x, y, s, s, commonData->fgcolor);
}
x += s;
}
y += s;
x = x0;
}
}
int displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
// Optical warning by limit violation (unused)
if(flashLED == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging page information
LOG_DEBUG(GwLog::LOG,"Drawing at PageSystem, Mode=%c", mode);
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height());
// call current system page
switch (mode) {
case 'N':
displayModeNormal();
break;
case 'S':
displayModeSettings();
break;
case 'C':
displayModeConfig();
break;
case 'A':
displayModeSDCard();
break;
case 'D':
displayModeDevicelist();
break;
}
// Update display // Update display
getdisplay().nextPage(); // Partial update (fast) getdisplay().nextPage(); // Partial update (fast)
return PAGE_OK; return PAGE_OK;

View File

@@ -1117,21 +1117,6 @@
"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,21 +1129,6 @@
"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,55 +1,46 @@
#!/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
__version__ = "0.2" # List of all pages and the number of parameters they expect.
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,
}
def detect_pages(filename): # No changes needed beyond this point
# returns a dictionary with page name and the number of gui fields # max number of pages supported by OBP60
pagefiles = [] no_of_pages = 10
with open(filename, 'r') as fh:
pattern = r'extern PageDescription\s*register(Page[^;\s]*)'
for line in fh:
if "extern PageDescription" in line:
match = re.search(pattern, line)
if match:
pagefiles.append(match.group(1))
try:
pagefiles.remove('PageSystem')
except ValueError:
pass
pagedata = {}
for pf in pagefiles:
filename = pf + ".cpp"
with open(filename, 'r') as fh:
content = fh.read()
pattern = r'PageDescription\s*?register' + pf + r'\s*\(\s*"([^"]+)".*?\n\s*(\d+)'
match = re.search(pattern, content, re.DOTALL)
if match:
pagedata[match.group(1)] = int(match.group(2))
return pagedata
def get_default_page(pageno):
# Default selection for each page # Default selection for each page
default_pages = ( default_pages = [
"Voltage", "Voltage",
"WindRose", "WindRose",
"OneValue", "OneValue",
@@ -59,30 +50,22 @@ def get_default_page(pageno):
"FourValues2", "FourValues2",
"Clock", "Clock",
"RollPitch", "RollPitch",
"Battery2" "Battery2",
) ]
if pageno > len(default_pages): numbers = [
return "OneValue" "one",
return default_pages[pageno - 1] "two",
"three",
def number_to_text(number): "four",
if number < 0 or number > 99: "five",
raise ValueError("Only numbers from 0 to 99 are allowed.") "six",
numbers = ("zero", "one", "two", "three", "four", "five", "six", "seven", "seven",
"eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "eight",
"fifteen", "sixteen", "seventeen", "eighteen", "nineteen") "nine",
tens = ("", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "ten",
"eighty", "ninety") ]
if number < 20: pages = sorted(no_of_fields_per_page.keys())
return numbers[number] max_no_of_fields_per_page = max(no_of_fields_per_page.values())
else:
q, r = divmod(number, 10)
return tens[q] + numbers[r]
def create_json(device, no_of_pages, pagedata):
pages = sorted(pagedata.keys())
max_no_of_fields_per_page = max(pagedata.values())
output = [] output = []
@@ -91,11 +74,11 @@ def create_json(device, no_of_pages, pagedata):
"name": f"page{page_no}type", "name": f"page{page_no}type",
"label": "Type", "label": "Type",
"type": "list", "type": "list",
"default": get_default_page(page_no), "default": default_pages[page_no - 1],
"description": f"Type of page for page {page_no}", "description": f"Type of page for page {page_no}",
"list": pages, "list": pages,
"category": f"{device.upper()} Page {page_no}", "category": f"OBP60 Page {page_no}",
"capabilities": {device.lower(): "true"}, "capabilities": {"obp60": "true"},
"condition": [{"visiblePages": vp} for vp in range(page_no, no_of_pages + 1)], "condition": [{"visiblePages": vp} for vp in range(page_no, no_of_pages + 1)],
#"fields": [], #"fields": [],
} }
@@ -107,13 +90,13 @@ def create_json(device, no_of_pages, pagedata):
"label": f"Field {field_no}", "label": f"Field {field_no}",
"type": "boatData", "type": "boatData",
"default": "", "default": "",
"description": "The display for field {}".format(number_to_text(field_no)), "description": f"The display for field {numbers[field_no - 1]}",
"category": f"{device.upper()} Page {page_no}", "category": f"OBP60 Page {page_no}",
"capabilities": {device.lower(): "true"}, "capabilities": {"obp60": "true"},
"condition": [ "condition": [
{f"page{page_no}type": page} {f"page{page_no}type": page}
for page in pages for page in pages
if pagedata[page] >= field_no if no_of_fields_per_page[page] >= field_no
], ],
} }
output.append(field_data) output.append(field_data)
@@ -133,47 +116,17 @@ def create_json(device, no_of_pages, pagedata):
{"l":"Fuel Gasoline (6)","v":"6"} {"l":"Fuel Gasoline (6)","v":"6"}
], ],
"description": "Fluid type in tank", "description": "Fluid type in tank",
"category": f"{device.upper()} Page {page_no}", "category": f"OBP60 Page {page_no}",
"capabilities": { "capabilities": {
device.lower(): "true" "obp60":"true"
}, },
"condition":[{f"page{page_no}type":"Fluid"}] "condition":[{f"page{page_no}type":"Fluid"}]
} }
output.append(fluid_data) output.append(fluid_data)
return json.dumps(output, indent=4) json_output = json.dumps(output, indent=4)
# print omitting first and last line containing [ ] of JSON array
def usage(): #print(json_output[1:-1])
print("{} v{}".format(os.path.basename(__file__), __version__))
print()
print("Command line options")
print(" -d --device device name to use e.g. obp60")
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 omitting first line containing [ of JSON array
print(json_output[1:]) print(json_output[1:])
# print(",")

View File

@@ -18,6 +18,8 @@
#ifdef BOARD_OBP40S3 #ifdef BOARD_OBP40S3
#include "driver/rtc_io.h" // Needs for weakup from deep sleep #include "driver/rtc_io.h" // Needs for weakup from deep sleep
#include <FS.h> // SD-Card access
#include <SD.h>
#include <SPI.h> #include <SPI.h>
#endif #endif
@@ -32,6 +34,7 @@
#include "OBP60QRWiFi.h" // Functions lib for WiFi QR code #include "OBP60QRWiFi.h" // Functions lib for WiFi QR code
#include "OBPSensorTask.h" // Functions lib for sensor data #include "OBPSensorTask.h" // Functions lib for sensor data
// Global vars // Global vars
bool initComplete = false; // Initialization complete bool initComplete = false; // Initialization complete
int taskRunCounter = 0; // Task couter for loop section int taskRunCounter = 0; // Task couter for loop section
@@ -44,23 +47,45 @@ void OBP60Init(GwApi *api){
GwConfigHandler *config = api->getConfig(); GwConfigHandler *config = api->getConfig();
// Set a new device name and hidden the original name in the main config // Set a new device name and hidden the original name in the main config
String devicename = config->getConfigItem(config->deviceName, true)->asString(); String devicename = api->getConfig()->getConfigItem(api->getConfig()->deviceName,true)->asString();
config->setValue(GwConfigDefinitions::systemName, devicename, GwConfigInterface::ConfigType::HIDDEN); api->getConfig()->setValue(GwConfigDefinitions::systemName, devicename, GwConfigInterface::ConfigType::HIDDEN);
logger->prefix = devicename + ":"; api->getLogger()->logDebug(GwLog::LOG,"obp60init running");
logger->logDebug(GwLog::LOG,"obp60init running");
// Check I2C devices // Check I2C devices
// Init power
String powermode = config->getConfigItem(config->powerMode,true)->asString();
logger->logDebug(GwLog::DEBUG, "Power Mode is: %s", powermode.c_str());
powerInit(powermode);
// Init hardware // Init hardware
hardwareInit(api); hardwareInit(api);
// Init power
String powermode = api->getConfig()->getConfigItem(api->getConfig()->powerMode,true)->asString();
api->getLogger()->logDebug(GwLog::DEBUG,"Power Mode is: %s", powermode.c_str());
powerInit(powermode);
#ifdef BOARD_OBP40S3 #ifdef BOARD_OBP40S3
bool sdcard = config->getBool(config->useSDCard);
if (sdcard) {
SPIClass SD_SPI = SPIClass(HSPI);
SD_SPI.begin(SD_SPI_CLK, SD_SPI_MISO, SD_SPI_MOSI);
if (SD.begin(SD_SPI_CS, SD_SPI, 80000000)) {
String sdtype = "unknown";
uint8_t cardType = SD.cardType();
switch (cardType) {
case CARD_MMC:
sdtype = "MMC";
break;
case CARD_SD:
sdtype = "SDSC";
break;
case CARD_SDHC:
sdtype = "SDHC";
break;
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
LOG_DEBUG(GwLog::LOG,"SD card type %s of size %d MB detected", sdtype, cardSize);
}
}
// Deep sleep wakeup configuration // Deep sleep wakeup configuration
esp_sleep_enable_ext0_wakeup(OBP_WAKEWUP_PIN, 0); // 1 = High, 0 = Low esp_sleep_enable_ext0_wakeup(OBP_WAKEWUP_PIN, 0); // 1 = High, 0 = Low
rtc_gpio_pullup_en(OBP_WAKEWUP_PIN); // Activate pullup resistor rtc_gpio_pullup_en(OBP_WAKEWUP_PIN); // Activate pullup resistor
@@ -69,7 +94,7 @@ void OBP60Init(GwApi *api){
// Settings for e-paper display // Settings for e-paper display
String fastrefresh = api->getConfig()->getConfigItem(api->getConfig()->fastRefresh,true)->asString(); String fastrefresh = api->getConfig()->getConfigItem(api->getConfig()->fastRefresh,true)->asString();
logger->logDebug(GwLog::DEBUG, "Fast Refresh Mode is: %s", fastrefresh.c_str()); api->getLogger()->logDebug(GwLog::DEBUG,"Fast Refresh Mode is: %s", fastrefresh.c_str());
#ifdef DISPLAY_GDEY042T81 #ifdef DISPLAY_GDEY042T81
if(fastrefresh == "true"){ if(fastrefresh == "true"){
static const bool useFastFullUpdate = true; // Enable fast full display update only for GDEY042T81 static const bool useFastFullUpdate = true; // Enable fast full display update only for GDEY042T81
@@ -88,11 +113,11 @@ void OBP60Init(GwApi *api){
// Get CPU speed // Get CPU speed
int freq = getCpuFrequencyMhz(); int freq = getCpuFrequencyMhz();
logger->logDebug(GwLog::LOG,"CPU speed at boot: %i MHz", freq); api->getLogger()->logDebug(GwLog::LOG,"CPU speed at boot: %i MHz", freq);
// Settings for backlight // Settings for backlight
String backlightMode = api->getConfig()->getConfigItem(api->getConfig()->backlight,true)->asString(); String backlightMode = api->getConfig()->getConfigItem(api->getConfig()->backlight,true)->asString();
logger->logDebug(GwLog::DEBUG,"Backlight Mode is: %s", backlightMode.c_str()); api->getLogger()->logDebug(GwLog::DEBUG,"Backlight Mode is: %s", backlightMode.c_str());
uint brightness = uint(api->getConfig()->getConfigItem(api->getConfig()->blBrightness,true)->asInt()); uint brightness = uint(api->getConfig()->getConfigItem(api->getConfig()->blBrightness,true)->asInt());
String backlightColor = api->getConfig()->getConfigItem(api->getConfig()->blColor,true)->asString(); String backlightColor = api->getConfig()->getConfigItem(api->getConfig()->blColor,true)->asString();
if(String(backlightMode) == "On"){ if(String(backlightMode) == "On"){
@@ -107,7 +132,7 @@ void OBP60Init(GwApi *api){
// Settings flash LED mode // Settings flash LED mode
String ledMode = api->getConfig()->getConfigItem(api->getConfig()->flashLED,true)->asString(); String ledMode = api->getConfig()->getConfigItem(api->getConfig()->flashLED,true)->asString();
logger->logDebug(GwLog::DEBUG,"LED Mode is: %s", ledMode.c_str()); api->getLogger()->logDebug(GwLog::DEBUG,"LED Mode is: %s", ledMode.c_str());
if(String(ledMode) == "Off"){ if(String(ledMode) == "Off"){
setBlinkingLED(false); setBlinkingLED(false);
} }
@@ -239,7 +264,7 @@ void registerAllPages(PageList &list){
extern PageDescription registerPageWindRose; extern PageDescription registerPageWindRose;
list.add(&registerPageWindRose); list.add(&registerPageWindRose);
extern PageDescription registerPageWindRoseFlex; extern PageDescription registerPageWindRoseFlex;
list.add(&registerPageWindRoseFlex); list.add(&registerPageWindRoseFlex); //
extern PageDescription registerPageVoltage; extern PageDescription registerPageVoltage;
list.add(&registerPageVoltage); list.add(&registerPageVoltage);
extern PageDescription registerPageDST810; extern PageDescription registerPageDST810;
@@ -848,7 +873,6 @@ 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
@@ -876,7 +900,6 @@ 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
@@ -901,7 +924,6 @@ 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