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

5 Commits

Author SHA1 Message Date
779f557d47 Fixed and finished SD card code. Added uptime feature to system page. 2025-08-14 10:19:15 +02:00
norbert-walter
4a273d2c93 Add hibernate in full page refresh 2025-08-12 15:37:22 +02:00
Norbert Walter
9be1b864f4 Merge pull request #192 from thooge/scripts
Automate gen_set.py with page detection and command line parameters
2025-08-12 15:32:51 +02:00
Norbert Walter
bfc4337417 Merge pull request #191 from thooge/precision
Added config option for display precision and formatter code improvement
2025-08-12 15:31:28 +02:00
eb51092b23 Added config option for display precision and formatter code improvements 2025-07-31 12:31:57 +02:00
8 changed files with 506 additions and 321 deletions

View File

@@ -64,6 +64,12 @@ PCF8574 pcf8574_Out(PCF8574_I2C_ADDR1); // First digital output modul PCF8574 fr
Adafruit_FRAM_I2C fram;
bool hasFRAM = false;
// SD Card
#ifdef BOARD_OBP40S3
sdmmc_card_t *sdcard;
#endif
bool hasSDCard = false;
// Global vars
bool blinkingLED = false; // Enable / disable blinking flash LED
bool statusLED = false; // Actual status of flash LED on/off
@@ -78,6 +84,9 @@ LedTaskData *ledTaskData=nullptr;
void hardwareInit(GwApi *api)
{
GwLog *logger = api->getLogger();
GwConfigHandler *config = api->getConfig();
Wire.begin();
// Init PCF8574 digital outputs
Wire.setClock(I2C_SPEED); // Set I2C clock on 10 kHz
@@ -87,7 +96,7 @@ void hardwareInit(GwApi *api)
fram = Adafruit_FRAM_I2C();
if (esp_reset_reason() == ESP_RST_POWERON) {
// help initialize FRAM
api->getLogger()->logDebug(GwLog::LOG,"Delaying I2C init for 250ms due to cold boot");
logger->logDebug(GwLog::LOG, "Delaying I2C init for 250ms due to cold boot");
delay(250);
}
// FRAM (e.g. MB85RC256V)
@@ -99,11 +108,88 @@ void hardwareInit(GwApi *api)
// Boot counter
uint8_t framcounter = fram.read(0x0000);
fram.write(0x0000, framcounter+1);
api->getLogger()->logDebug(GwLog::LOG,"FRAM detected: 0x%04x/0x%04x (counter=%d)", manufacturerID, productID, framcounter);
logger->logDebug(GwLog::LOG, "FRAM detected: 0x%04x/0x%04x (counter=%d)", manufacturerID, productID, framcounter);
}
else {
hasFRAM = false;
api->getLogger()->logDebug(GwLog::LOG,"NO FRAM detected");
logger->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) {
// Max Power | Only 5.0V | Min Power
if (powermode == "Max Power" || powermode == "Only 5.0V") {
#ifdef HARDWARE_V21
setPortPin(OBP_POWER_50, true); // Power on 5.0V rail
#endif
#ifdef BOARD_OBP40S3
setPortPin(OBP_POWER_EPD, true);// Power on ePaper display
setPortPin(OBP_POWER_SD, true); // Power on SD card
#endif
} else { // Min Power
#ifdef HARDWARE_V21
setPortPin(OBP_POWER_50, false); // Power off 5.0V rail
#endif
#ifdef BOARD_OBP40S3
setPortPin(OBP_POWER_EPD, false);// Power off ePaper display
setPortPin(OBP_POWER_SD, false); // Power off SD card
#endif
}
}

View File

@@ -7,6 +7,12 @@
#include <GxEPD2_BW.h> // E-paper lib V2
#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
// 0x0000 - 0x03ff: single variables
#define FRAM_PAGE_NO 0x0002
@@ -15,6 +21,7 @@
#define FRAM_VOLTAGE_AVG 0x000A
#define FRAM_VOLTAGE_TREND 0x000B
#define FRAM_VOLTAGE_MODE 0x000C
// Wind page
#define FRAM_WIND_SIZE 0x000D
#define FRAM_WIND_SRC 0x000E
#define FRAM_WIND_MODE 0x000F
@@ -24,6 +31,10 @@
extern Adafruit_FRAM_I2C fram;
extern bool hasFRAM;
extern bool hasSDCard;
#ifdef BOARD_OBP40S3
extern sdmmc_card_t *sdcard;
#endif
// Fonts declarations for display (#includes see OBP60Extensions.cpp)
extern const GFXfont DSEG7Classic_BoldItalic16pt7b;
@@ -75,6 +86,7 @@ void deepSleep(CommonData &common);
uint8_t getLastPage();
void hardwareInit(GwApi *api);
void powerInit(String powermode);
void setPortPin(uint pin, bool value); // Set port pin for extension port

View File

@@ -65,6 +65,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
String tempFormat = commondata.config->getString(commondata.config->tempFormat); // [K|°C|°F]
String dateFormat = commondata.config->getString(commondata.config->dateFormat); // [DE|GB|US]
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 (! value->valid && !usesimudata){
@@ -72,6 +73,19 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
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);
static const int bsize = 30;
char buffer[bsize+1];
@@ -206,13 +220,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
result.unit = "m/s";
}
if(speed < 10) {
snprintf(buffer,bsize,"%3.2f",speed);
snprintf(buffer, bsize, fmt_dec_1, speed);
}
if(speed >= 10 && speed < 100){
snprintf(buffer,bsize,"%3.1f",speed);
else if (speed < 100) {
snprintf(buffer, bsize, fmt_dec_10, speed);
}
if(speed >= 100){
snprintf(buffer,bsize,"%3.0f",speed);
else {
snprintf(buffer, bsize, fmt_dec_100, speed);
}
}
//########################################################
@@ -238,40 +252,40 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
if (speed < 0.3) {
speed = 0;
}
if(speed >=0.3 && speed < 1.5){
else if (speed < 1.5) {
speed = 1;
}
if(speed >=1.5 && speed < 3.3){
else if (speed < 3.3) {
speed = 2;
}
if(speed >=3.3 && speed < 5.4){
else if (speed < 5.4) {
speed = 3;
}
if(speed >=5.4 && speed < 7.9){
else if (speed < 7.9) {
speed = 4;
}
if(speed >=7.9 && speed < 10.7){
else if (speed < 10.7) {
speed = 5;
}
if(speed >=10.7 && speed < 13.8){
else if (speed < 13.8) {
speed = 6;
}
if(speed >=13.8 && speed < 17.1){
else if (speed < 17.1) {
speed = 7;
}
if(speed >=17.1 && speed < 20.7){
else if (speed < 20.7) {
speed = 8;
}
if(speed >=20.7 && speed < 24.4){
else if (speed < 24.4) {
speed = 9;
}
if(speed >=24.4 && speed < 28.4){
else if (speed < 28.4) {
speed = 10;
}
if(speed >=28.4 && speed < 32.6){
else if (speed < 32.6) {
speed = 11;
}
if(speed >=32.6){
else {
speed = 12;
}
result.unit = "bft";
@@ -285,13 +299,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
}
else{
if (speed < 10){
snprintf(buffer,bsize,"%3.2f",speed);
snprintf(buffer, bsize, fmt_dec_1, speed);
}
if(speed >= 10 && speed < 100){
snprintf(buffer,bsize,"%3.1f",speed);
else if (speed < 100){
snprintf(buffer, bsize, fmt_dec_10, speed);
}
if(speed >= 100){
snprintf(buffer,bsize,"%3.0f",speed);
else {
snprintf(buffer, bsize, fmt_dec_100, speed);
}
}
}
@@ -337,10 +351,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
dop = 99.9;
}
if (dop < 10){
snprintf(buffer,bsize,"%3.2f",dop);
snprintf(buffer, bsize, fmt_dec_1, dop);
}
if(dop >= 10 && dop < 100){
snprintf(buffer,bsize,"%3.1f",dop);
else if(dop < 100){
snprintf(buffer, bsize, fmt_dec_10, dop);
}
else {
snprintf(buffer, bsize, fmt_dec_100, dop);
}
}
//########################################################
@@ -410,13 +427,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
result.unit = "m";
}
if (depth < 10) {
snprintf(buffer,bsize,"%3.2f",depth);
snprintf(buffer, bsize, fmt_dec_1, depth);
}
if(depth >= 10 && depth < 100){
snprintf(buffer,bsize,"%3.1f",depth);
else if (depth < 100){
snprintf(buffer, bsize, fmt_dec_10, depth);
}
if(depth >= 100){
snprintf(buffer,bsize,"%3.0f",depth);
else {
snprintf(buffer, bsize, fmt_dec_100, depth);
}
}
//########################################################
@@ -430,11 +447,11 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
xte = rawvalue;
}
if (xte >= 100) {
snprintf(buffer,bsize,"%3.0f",value->value);
snprintf(buffer, bsize, fmt_dec_100, value->value);
} else if (xte >= 10) {
snprintf(buffer,bsize,"%3.1f",value->value);
snprintf(buffer, bsize, fmt_dec_10, value->value);
} else {
snprintf(buffer,bsize,"%3.2f",value->value);
snprintf(buffer, bsize, fmt_dec_1, value->value);
}
result.unit = "nm";
}
@@ -461,13 +478,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
result.unit = "K";
}
if(temp < 10) {
snprintf(buffer,bsize,"%3.2f",temp);
snprintf(buffer, bsize, fmt_dec_1, temp);
}
if(temp >= 10 && temp < 100){
snprintf(buffer,bsize,"%3.1f",temp);
else if (temp < 100) {
snprintf(buffer, bsize, fmt_dec_10, temp);
}
if(temp >= 100){
snprintf(buffer,bsize,"%3.0f",temp);
else {
snprintf(buffer, bsize, fmt_dec_100, temp);
}
}
//########################################################
@@ -489,17 +506,17 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
distance = distance * 0.000539957;
result.unit = "nm";
}
else{;
else {
result.unit = "m";
}
if (distance < 10){
snprintf(buffer,bsize,"%3.2f",distance);
snprintf(buffer, bsize, fmt_dec_1, distance);
}
if(distance >= 10 && distance < 100){
snprintf(buffer,bsize,"%3.1f",distance);
else if (distance < 100){
snprintf(buffer, bsize, fmt_dec_10, distance);
}
if(distance >= 100){
snprintf(buffer,bsize,"%3.0f",distance);
else {
snprintf(buffer, bsize, fmt_dec_100, distance);
}
}
//########################################################
@@ -547,10 +564,10 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
voltage = rawvalue;
}
if (voltage < 10) {
snprintf(buffer,bsize,"%3.2f",voltage);
snprintf(buffer, bsize, fmt_dec_1, voltage);
}
else {
snprintf(buffer,bsize,"%3.1f",voltage);
snprintf(buffer, bsize, fmt_dec_10, voltage);
}
result.unit = "V";
}
@@ -566,13 +583,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
current = rawvalue;
}
if (current < 10) {
snprintf(buffer,bsize,"%3.2f",current);
snprintf(buffer, bsize, fmt_dec_1, current);
}
if(current >= 10 && current < 100){
snprintf(buffer,bsize,"%3.1f",current);
else if(current < 100) {
snprintf(buffer, bsize, fmt_dec_10, current);
}
if(current >= 100){
snprintf(buffer,bsize,"%3.0f",current);
else {
snprintf(buffer, bsize, fmt_dec_100, current);
}
result.unit = "A";
}
@@ -588,13 +605,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
temperature = rawvalue;
}
if (temperature < 10) {
snprintf(buffer,bsize,"%3.2f",temperature);
snprintf(buffer, bsize, fmt_dec_1, temperature);
}
if(temperature >= 10 && temperature < 100){
snprintf(buffer,bsize,"%3.1f",temperature);
else if (temperature < 100) {
snprintf(buffer, bsize, fmt_dec_10, temperature);
}
if(temperature >= 100){
snprintf(buffer,bsize,"%3.0f",temperature);
else {
snprintf(buffer, bsize, fmt_dec_100, temperature);
}
result.unit = "Deg C";
}
@@ -610,13 +627,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
temperature = rawvalue;
}
if (temperature < 10) {
snprintf(buffer,bsize,"%3.2f",temperature);
snprintf(buffer, bsize, fmt_dec_1, temperature);
}
if(temperature >= 10 && temperature < 100){
snprintf(buffer,bsize,"%3.1f",temperature);
else if(temperature < 100) {
snprintf(buffer, bsize, fmt_dec_10, temperature);
}
if(temperature >= 100){
snprintf(buffer,bsize,"%3.0f",temperature);
else {
snprintf(buffer, bsize, fmt_dec_100, temperature);
}
result.unit = "Deg C";
}
@@ -632,13 +649,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
humidity = rawvalue;
}
if (humidity < 10) {
snprintf(buffer,bsize,"%3.2f",humidity);
snprintf(buffer, bsize, fmt_dec_1, humidity);
}
if(humidity >= 10 && humidity < 100){
snprintf(buffer,bsize,"%3.1f",humidity);
else if(humidity < 100) {
snprintf(buffer, bsize, fmt_dec_10, humidity);
}
if(humidity >= 100){
snprintf(buffer,bsize,"%3.0f",humidity);
else {
snprintf(buffer, bsize, fmt_dec_100, humidity);
}
result.unit = "%";
}
@@ -654,13 +671,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
volume = rawvalue;
}
if (volume < 10) {
snprintf(buffer,bsize,"%3.2f",volume);
snprintf(buffer, bsize, fmt_dec_1, volume);
}
if(volume >= 10 && volume < 100){
snprintf(buffer,bsize,"%3.1f",volume);
else if (volume < 100) {
snprintf(buffer, bsize, fmt_dec_10, volume);
}
if(volume >= 100){
snprintf(buffer,bsize,"%3.0f",volume);
else if (volume >= 100) {
snprintf(buffer, bsize, fmt_dec_100, volume);
}
result.unit = "%";
}
@@ -676,13 +693,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
volume = rawvalue;
}
if (volume < 10) {
snprintf(buffer,bsize,"%3.2f",volume);
snprintf(buffer, bsize, fmt_dec_1, volume);
}
if(volume >= 10 && volume < 100){
snprintf(buffer,bsize,"%3.1f",volume);
else if (volume < 100) {
snprintf(buffer, bsize, fmt_dec_10, volume);
}
if(volume >= 100){
snprintf(buffer,bsize,"%3.0f",volume);
else {
snprintf(buffer, bsize, fmt_dec_100, volume);
}
result.unit = "l";
}
@@ -698,13 +715,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
flow = rawvalue;
}
if (flow < 10) {
snprintf(buffer,bsize,"%3.2f",flow);
snprintf(buffer, bsize, fmt_dec_1, flow);
}
if(flow >= 10 && flow < 100){
snprintf(buffer,bsize,"%3.1f",flow);
else if (flow < 100) {
snprintf(buffer, bsize, fmt_dec_10, flow);
}
if(flow >= 100){
snprintf(buffer,bsize,"%3.0f",flow);
else {
snprintf(buffer, bsize, fmt_dec_100, flow);
}
result.unit = "l/min";
}
@@ -712,7 +729,7 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
else if (value->getFormat() == "formatXdr:G:"){
double generic = 0;
if (usesimudata == false) {
generic = value->value; // Value in l/min
generic = value->value;
rawvalue = value->value;
}
else {
@@ -720,13 +737,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
generic = rawvalue;
}
if (generic < 10) {
snprintf(buffer,bsize,"%3.2f",generic);
snprintf(buffer, bsize, fmt_dec_1, generic);
}
if(generic >= 10 && generic < 100){
snprintf(buffer,bsize,"%3.1f",generic);
else if (generic < 100) {
snprintf(buffer, bsize, fmt_dec_10, generic);
}
if(generic >= 100){
snprintf(buffer,bsize,"%3.0f",generic);
else {
snprintf(buffer, bsize, fmt_dec_100, generic);
}
result.unit = "";
}
@@ -742,13 +759,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
dplace = rawvalue;
}
if (dplace < 10) {
snprintf(buffer,bsize,"%3.2f",dplace);
snprintf(buffer, bsize, fmt_dec_1, dplace);
}
if(dplace >= 10 && dplace < 100){
snprintf(buffer,bsize,"%3.1f",dplace);
else if (dplace < 100) {
snprintf(buffer, bsize, fmt_dec_10, dplace);
}
if(dplace >= 100){
snprintf(buffer,bsize,"%3.0f",dplace);
else {
snprintf(buffer, bsize, fmt_dec_100, dplace);
}
result.unit = "%";
}
@@ -784,13 +801,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
rpm = rawvalue;
}
if (rpm < 10) {
snprintf(buffer,bsize,"%3.2f",rpm);
snprintf(buffer, bsize, fmt_dec_1, rpm);
}
if(rpm >= 10 && rpm < 100){
snprintf(buffer,bsize,"%3.1f",rpm);
else if (rpm < 100) {
snprintf(buffer, bsize, fmt_dec_10, rpm);
}
if(rpm >= 100){
snprintf(buffer,bsize,"%3.0f",rpm);
else {
snprintf(buffer, bsize, fmt_dec_100, rpm);
}
result.unit = "rpm";
}
@@ -799,13 +816,13 @@ FormattedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
//########################################################
else {
if (value->value < 10) {
snprintf(buffer,bsize,"%3.2f",value->value);
snprintf(buffer, bsize, fmt_dec_1, value->value);
}
if(value->value >= 10 && value->value < 100){
snprintf(buffer,bsize,"%3.1f",value->value);
else if (value->value < 100) {
snprintf(buffer, bsize, fmt_dec_10, value->value);
}
if(value->value >= 100){
snprintf(buffer,bsize,"%3.0f",value->value);
else {
snprintf(buffer, bsize, fmt_dec_100, value->value);
}
result.unit = "";
}

View File

@@ -82,7 +82,7 @@
// Direction pin for RS485 NMEA0183
#define OBP_DIRECTION_PIN 8
// I2C
#define I2C_SPEED 10000UL // 10kHz clock speed on I2C bus
#define I2C_SPEED 100000UL // 100kHz clock speed on I2C bus
#define OBP_I2C_SDA 21
#define OBP_I2C_SCL 38
// DS1388 RTC
@@ -120,10 +120,10 @@
#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)
// SPI SD-Card
#define SD_SPI_CS 10
#define SD_SPI_MOSI 40
#define SD_SPI_CLK 39
#define SD_SPI_MISO 13
#define SD_SPI_CS GPIO_NUM_10
#define SD_SPI_MOSI GPIO_NUM_40
#define SD_SPI_CLK GPIO_NUM_39
#define SD_SPI_MISO GPIO_NUM_13
// GPS (NEO-6M, NEO-M8N, ATGM336H)
#define OBP_GPS_RX 19

View File

@@ -1,5 +1,15 @@
#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 "OBP60Extensions.h"
#include "images/logo64.xbm"
@@ -7,8 +17,7 @@
#include "qrcode.h"
#ifdef BOARD_OBP40S3
#include <SD.h>
#include <FS.h>
#include "dirent.h"
#endif
#define STRINGIZE_IMPL(x) #x
@@ -19,20 +28,12 @@
#define DISPLAYINFO STRINGIZE(EPDTYPE)
#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. NMEA2000 device list
*/
class PageSystem : public Page
{
private:
uint64_t chipid;
bool simulation;
bool sdcard;
bool use_sdcard;
String buzzer_mode;
uint8_t buzzer_power;
String cpuspeed;
@@ -55,11 +56,12 @@ public:
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
sdcard = common.config->getBool(common.config->useSDCard);
use_sdcard = common.config->getBool(common.config->useSDCard);
#endif
buzzer_mode = common.config->getString(common.config->buzzerMode);
buzzer_mode.toLowerCase();
@@ -76,7 +78,7 @@ public:
homelon = common.config->getString(common.config->homeLON).toDouble();
}
virtual void setupKeys(){
void setupKeys() {
commonData->keydata[0].label = "EXIT";
commonData->keydata[1].label = "MODE";
commonData->keydata[2].label = "";
@@ -85,7 +87,7 @@ public:
commonData->keydata[5].label = "ILUM";
}
virtual int handleKey(int key){
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");
@@ -95,7 +97,7 @@ public:
} else if (mode == 'S') {
mode = 'D';
} else if (mode == 'D') {
if (sdcard) {
if (hasSDCard) {
mode = 'C';
} else {
mode = 'N';
@@ -117,6 +119,7 @@ public:
}
// standby / deep sleep
if (key == 5) {
commonData->logger->logDebug(GwLog::LOG, "System going into deep sleep mode...");
deepSleep(*commonData);
}
// Code for keylock
@@ -132,6 +135,7 @@ public:
}
// standby / deep sleep
if (key == 12) {
commonData->logger->logDebug(GwLog::LOG, "System going into deep sleep mode...");
deepSleep(*commonData);
}
#endif
@@ -178,7 +182,7 @@ public:
}
// Logging boat values
LOG_DEBUG(GwLog::LOG,"Drawing at PageSystem");
logger->logDebug(GwLog::LOG, "Drawing at PageSystem, Mode=%c", mode);
// Draw page
//***********************************************************
@@ -257,14 +261,37 @@ public:
getdisplay().setCursor(8, y0 + 48);
getdisplay().print("SD-Card:");
getdisplay().setCursor(90, y0 + 48);
if (sdcard) {
uint64_t cardsize = SD.cardSize() / (1024 * 1024);
getdisplay().print(String(cardsize) + String(" MB"));
if (hasSDCard) {
uint64_t cardsize = ((uint64_t) sdcard->csd.capacity) * sdcard->csd.sector_size / (1024 * 1024);
getdisplay().printf("%llu MB", cardsize);
} else {
getdisplay().print("off");
}
#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
getdisplay().setCursor(202, y0);
getdisplay().print("CPU speed:");
@@ -371,8 +398,61 @@ public:
x0 = 20;
y0 = 72;
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...");
/* 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
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

View File

@@ -1117,6 +1117,21 @@
"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",
"label": "Backlight Mode",

View File

@@ -1129,6 +1129,21 @@
"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",
"label": "Backlight Mode",

View File

@@ -18,8 +18,6 @@
#ifdef BOARD_OBP40S3
#include "driver/rtc_io.h" // Needs for weakup from deep sleep
#include <FS.h> // SD-Card access
#include <SD.h>
#include <SPI.h>
#endif
@@ -34,7 +32,6 @@
#include "OBP60QRWiFi.h" // Functions lib for WiFi QR code
#include "OBPSensorTask.h" // Functions lib for sensor data
// Global vars
bool initComplete = false; // Initialization complete
int taskRunCounter = 0; // Task couter for loop section
@@ -47,63 +44,23 @@ void OBP60Init(GwApi *api){
GwConfigHandler *config = api->getConfig();
// Set a new device name and hidden the original name in the main config
String devicename = api->getConfig()->getConfigItem(api->getConfig()->deviceName,true)->asString();
api->getConfig()->setValue(GwConfigDefinitions::systemName, devicename, GwConfigInterface::ConfigType::HIDDEN);
String devicename = config->getConfigItem(config->deviceName, true)->asString();
config->setValue(GwConfigDefinitions::systemName, devicename, GwConfigInterface::ConfigType::HIDDEN);
api->getLogger()->logDebug(GwLog::LOG,"obp60init running");
logger->prefix = devicename + ":";
logger->logDebug(GwLog::LOG,"obp60init running");
// 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
hardwareInit(api);
// Init power rail 5.0V
String powermode = api->getConfig()->getConfigItem(api->getConfig()->powerMode,true)->asString();
api->getLogger()->logDebug(GwLog::DEBUG,"Power Mode is: %s", powermode.c_str());
if(powermode == "Max Power" || powermode == "Only 5.0V"){
#ifdef HARDWARE_V21
setPortPin(OBP_POWER_50, true); // Power on 5.0V rail
#endif
#ifdef BOARD_OBP40S3
setPortPin(OBP_POWER_EPD, true);// Power on ePaper display
setPortPin(OBP_POWER_SD, true); // Power on SD card
#endif
}
else{
#ifdef HARDWARE_V21
setPortPin(OBP_POWER_50, false); // Power off 5.0V rail
#endif
#ifdef BOARD_OBP40S3
setPortPin(OBP_POWER_EPD, false);// Power off ePaper display
setPortPin(OBP_POWER_SD, false); // Power off SD card
#endif
}
#ifdef BOARD_OBP40S3
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
esp_sleep_enable_ext0_wakeup(OBP_WAKEWUP_PIN, 0); // 1 = High, 0 = Low
rtc_gpio_pullup_en(OBP_WAKEWUP_PIN); // Activate pullup resistor
@@ -112,7 +69,7 @@ void OBP60Init(GwApi *api){
// Settings for e-paper display
String fastrefresh = api->getConfig()->getConfigItem(api->getConfig()->fastRefresh,true)->asString();
api->getLogger()->logDebug(GwLog::DEBUG,"Fast Refresh Mode is: %s", fastrefresh.c_str());
logger->logDebug(GwLog::DEBUG, "Fast Refresh Mode is: %s", fastrefresh.c_str());
#ifdef DISPLAY_GDEY042T81
if(fastrefresh == "true"){
static const bool useFastFullUpdate = true; // Enable fast full display update only for GDEY042T81
@@ -131,11 +88,11 @@ void OBP60Init(GwApi *api){
// Get CPU speed
int freq = getCpuFrequencyMhz();
api->getLogger()->logDebug(GwLog::LOG,"CPU speed at boot: %i MHz", freq);
logger->logDebug(GwLog::LOG,"CPU speed at boot: %i MHz", freq);
// Settings for backlight
String backlightMode = api->getConfig()->getConfigItem(api->getConfig()->backlight,true)->asString();
api->getLogger()->logDebug(GwLog::DEBUG,"Backlight Mode is: %s", backlightMode.c_str());
logger->logDebug(GwLog::DEBUG,"Backlight Mode is: %s", backlightMode.c_str());
uint brightness = uint(api->getConfig()->getConfigItem(api->getConfig()->blBrightness,true)->asInt());
String backlightColor = api->getConfig()->getConfigItem(api->getConfig()->blColor,true)->asString();
if(String(backlightMode) == "On"){
@@ -150,7 +107,7 @@ void OBP60Init(GwApi *api){
// Settings flash LED mode
String ledMode = api->getConfig()->getConfigItem(api->getConfig()->flashLED,true)->asString();
api->getLogger()->logDebug(GwLog::DEBUG,"LED Mode is: %s", ledMode.c_str());
logger->logDebug(GwLog::DEBUG,"LED Mode is: %s", ledMode.c_str());
if(String(ledMode) == "Off"){
setBlinkingLED(false);
}
@@ -282,7 +239,7 @@ void registerAllPages(PageList &list){
extern PageDescription registerPageWindRose;
list.add(&registerPageWindRose);
extern PageDescription registerPageWindRoseFlex;
list.add(&registerPageWindRoseFlex); //
list.add(&registerPageWindRoseFlex);
extern PageDescription registerPageVoltage;
list.add(&registerPageVoltage);
extern PageDescription registerPageDST810;
@@ -891,6 +848,7 @@ void OBP60Task(GwApi *api){
else{
getdisplay().fillScreen(commonData.fgcolor); // Clear display
#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
#else
getdisplay().init(115200); // Init for normal displays
@@ -918,6 +876,7 @@ void OBP60Task(GwApi *api){
else{
getdisplay().fillScreen(commonData.fgcolor); // Clear display
#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
#else
getdisplay().init(115200); // Init for normal displays
@@ -942,6 +901,7 @@ void OBP60Task(GwApi *api){
else{
getdisplay().fillScreen(commonData.fgcolor); // Clear display
#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
#else
getdisplay().init(115200); // Init for normal displays