Fixed SD card initialization and added some code to system page

This commit is contained in:
Thomas Hooge 2025-08-13 17:41:06 +02:00
parent 1ada6e5a82
commit 54b4954797
8 changed files with 197 additions and 101 deletions

View File

@ -38,7 +38,7 @@ void CalibrationDataList::readConfig(GwConfigHandler* config, GwLog* logger)
instance = std::string(config->getString(calInstance, "---").c_str()); instance = std::string(config->getString(calInstance, "---").c_str());
if (instance == "---") { if (instance == "---") {
LOG_DEBUG(GwLog::LOG, "no calibration data for instance no. %d", i + 1); logger->logDebug(GwLog::LOG, "no calibration data for instance no. %d", i + 1);
continue; continue;
} }
calibMap[instance] = { 0.0f, 1.0f, 1.0f, 0.0f, false }; calibMap[instance] = { 0.0f, 1.0f, 1.0f, 0.0f, false };
@ -101,10 +101,10 @@ void CalibrationDataList::readConfig(GwConfigHandler* config, GwLog* logger)
calibMap[instance].slope = slope; calibMap[instance].slope = slope;
calibMap[instance].smooth = smooth; calibMap[instance].smooth = smooth;
calibMap[instance].isCalibrated = false; calibMap[instance].isCalibrated = false;
LOG_DEBUG(GwLog::LOG, "stored calibration data: %s, offset: %f, slope: %f, smoothing: %f", instance.c_str(), logger->logDebug(GwLog::LOG, "stored calibration data: %s, offset: %f, slope: %f, smoothing: %f", instance.c_str(),
calibMap[instance].offset, calibMap[instance].slope, calibMap[instance].smooth); calibMap[instance].offset, calibMap[instance].slope, calibMap[instance].smooth);
} }
LOG_DEBUG(GwLog::LOG, "all calibration data read"); logger->logDebug(GwLog::LOG, "all calibration data read");
} }
void CalibrationDataList::calibrateInstance(GwApi::BoatValue* boatDataValue, GwLog* logger) void CalibrationDataList::calibrateInstance(GwApi::BoatValue* boatDataValue, GwLog* logger)
@ -117,7 +117,7 @@ void CalibrationDataList::calibrateInstance(GwApi::BoatValue* boatDataValue, GwL
std::string format = ""; std::string format = "";
if (calibMap.find(instance) == calibMap.end()) { if (calibMap.find(instance) == calibMap.end()) {
LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s not found in calibration data list", instance.c_str()); logger->logDebug(GwLog::DEBUG, "BoatDataCalibration: %s not found in calibration data list", instance.c_str());
return; return;
} else if (!boatDataValue->valid) { // no valid boat data value, so we don't want to apply calibration data } else if (!boatDataValue->valid) { // no valid boat data value, so we don't want to apply calibration data
calibMap[instance].isCalibrated = false; calibMap[instance].isCalibrated = false;
@ -127,7 +127,7 @@ void CalibrationDataList::calibrateInstance(GwApi::BoatValue* boatDataValue, GwL
slope = calibMap[instance].slope; slope = calibMap[instance].slope;
dataValue = boatDataValue->value; dataValue = boatDataValue->value;
format = boatDataValue->getFormat().c_str(); format = boatDataValue->getFormat().c_str();
LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s: value: %f, format: %s", instance.c_str(), dataValue, format.c_str()); logger->logDebug(GwLog::DEBUG, "BoatDataCalibration: %s: value: %f, format: %s", instance.c_str(), dataValue, format.c_str());
if (format == "formatWind") { // instance is of type angle if (format == "formatWind") { // instance is of type angle
dataValue = (dataValue * slope) + offset; dataValue = (dataValue * slope) + offset;
@ -156,7 +156,7 @@ void CalibrationDataList::calibrateInstance(GwApi::BoatValue* boatDataValue, GwL
calibrationData.smoothInstance(boatDataValue, logger); // smooth the boat data value calibrationData.smoothInstance(boatDataValue, logger); // smooth the boat data value
calibMap[instance].value = boatDataValue->value; // store the calibrated + smoothed value in the list calibMap[instance].value = boatDataValue->value; // store the calibrated + smoothed value in the list
LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s: Offset: %f, Slope: %f, Result: %f", instance.c_str(), offset, slope, calibMap[instance].value); logger->logDebug(GwLog::DEBUG, "BoatDataCalibration: %s: Offset: %f, Slope: %f, Result: %f", instance.c_str(), offset, slope, calibMap[instance].value);
} }
} }
@ -173,7 +173,7 @@ void CalibrationDataList::smoothInstance(GwApi::BoatValue* boatDataValue, GwLog*
if (!boatDataValue->valid) { // no valid boat data value, so we don't want to smoothen value if (!boatDataValue->valid) { // no valid boat data value, so we don't want to smoothen value
return; return;
} else if (calibMap.find(instance) == calibMap.end()) { } else if (calibMap.find(instance) == calibMap.end()) {
LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: smooth factor for %s not found in calibration data list", instance.c_str()); logger->logDebug(GwLog::DEBUG, "BoatDataCalibration: smooth factor for %s not found in calibration data list", instance.c_str());
return; return;
} else { } else {
smoothFactor = calibMap[instance].smooth; smoothFactor = calibMap[instance].smooth;
@ -185,7 +185,7 @@ void CalibrationDataList::smoothInstance(GwApi::BoatValue* boatDataValue, GwLog*
lastValue[instance] = dataValue; // store the new value for next cycle; first time, store only the current value and return lastValue[instance] = dataValue; // store the new value for next cycle; first time, store only the current value and return
boatDataValue->value = dataValue; // set the smoothed value to the boat data value boatDataValue->value = dataValue; // set the smoothed value to the boat data value
LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s: Smoothing factor: %f, Smoothed value: %f", instance.c_str(), smoothFactor, dataValue); logger->logDebug(GwLog::DEBUG, "BoatDataCalibration: %s: Smoothing factor: %f, Smoothed value: %f", instance.c_str(), smoothFactor, dataValue);
} }
} }

View File

@ -83,12 +83,12 @@ static size_t ledsToBuffer(int numLeds,const Color *leds,uint8_t *buffer){
bool prepareGpio(GwLog *logger, uint8_t pin){ bool prepareGpio(GwLog *logger, uint8_t pin){
esp_err_t err=gpio_set_direction((gpio_num_t)pin,GPIO_MODE_OUTPUT); esp_err_t err=gpio_set_direction((gpio_num_t)pin,GPIO_MODE_OUTPUT);
if (err != ESP_OK){ if (err != ESP_OK){
LOG_DEBUG(GwLog::ERROR,"unable to set gpio mode for %d: %d",pin,(int)err); logger->logDebug(GwLog::ERROR, "unable to set gpio mode for %d: %d", pin, (int)err);
return false; return false;
} }
err=gpio_set_level((gpio_num_t)pin,0); err=gpio_set_level((gpio_num_t)pin,0);
if (err != ESP_OK){ if (err != ESP_OK){
LOG_DEBUG(GwLog::ERROR,"unable to set gpio level for %d: %d",pin,(int)err); logger->logDebug(GwLog::ERROR, "unable to set gpio level for %d: %d", pin, (int)err);
return false; return false;
} }
return true; return true;
@ -114,8 +114,8 @@ bool prepareSpi(GwLog *logger,spi_host_device_t bus,spi_device_handle_t *device)
}; };
esp_err_t err=spi_bus_initialize(bus,&buscfg,SPI_DMA_CH_AUTO); esp_err_t err=spi_bus_initialize(bus,&buscfg,SPI_DMA_CH_AUTO);
if (err != ESP_OK){ if (err != ESP_OK){
LOG_DEBUG(GwLog::ERROR,"unable to initialize SPI bus %d,mosi=%d, error=%d", logger->logDebug(GwLog::ERROR, "unable to initialize SPI bus %d,mosi=%d, error=%d",
(int)bus,-1,(int)err); (int)bus, -1, (int)err);
return false; return false;
} }
spi_device_interface_config_t devcfg = { spi_device_interface_config_t devcfg = {
@ -133,16 +133,16 @@ bool prepareSpi(GwLog *logger,spi_host_device_t bus,spi_device_handle_t *device)
}; };
err=spi_bus_add_device(bus,&devcfg,device); err=spi_bus_add_device(bus,&devcfg,device);
if (err != ESP_OK){ if (err != ESP_OK){
LOG_DEBUG(GwLog::ERROR,"unable to add device to SPI bus %d,mosi=%d, error=%d", logger->logDebug(GwLog::ERROR, "unable to add device to SPI bus %d,mosi=%d, error=%d",
(int)bus,-1,(int)err); (int)bus, -1, (int)err);
return false; return false;
} }
//slightly speed up the transactions //slightly speed up the transactions
//as we are the only ones using the bus we can safely acquire it forever //as we are the only ones using the bus we can safely acquire it forever
err=spi_device_acquire_bus(*device,portMAX_DELAY); err=spi_device_acquire_bus(*device,portMAX_DELAY);
if (err != ESP_OK){ if (err != ESP_OK){
LOG_DEBUG(GwLog::ERROR,"unable to acquire SPI bus %d,mosi=%d, error=%d", logger->logDebug(GwLog::ERROR,"unable to acquire SPI bus %d,mosi=%d, error=%d",
(int)bus,-1,(int)err); (int)bus, -1, (int)err);
return false; return false;
} }
return true; return true;
@ -172,7 +172,7 @@ bool sendToLeds(GwLog *logger, uint8_t pin, int numLeds, Color *leds, spi_host_d
buffer = (uint8_t *)heap_caps_malloc(bufferSize, MALLOC_CAP_DMA|MALLOC_CAP_32BIT); buffer = (uint8_t *)heap_caps_malloc(bufferSize, MALLOC_CAP_DMA|MALLOC_CAP_32BIT);
if (!buffer) if (!buffer)
{ {
LOG_DEBUG(GwLog::ERROR, "unable to allocate %d bytes of DMA buffer", (int)bufferSize); logger->logDebug(GwLog::ERROR, "unable to allocate %d bytes of DMA buffer", (int)bufferSize);
return false; return false;
} }
} }
@ -193,12 +193,12 @@ bool sendToLeds(GwLog *logger, uint8_t pin, int numLeds, Color *leds, spi_host_d
int64_t end = esp_timer_get_time(); int64_t end = esp_timer_get_time();
if (ret != ESP_OK) if (ret != ESP_OK)
{ {
LOG_DEBUG(GwLog::ERROR, "unable to send led data: %d", (int)ret); logger->logDebug(GwLog::ERROR, "unable to send led data: %d", (int)ret);
rv = false; rv = false;
} }
else else
{ {
LOG_DEBUG(GwLog::DEBUG, "successfully send led data for %d leds, %lld us", numLeds, end - now); logger->logDebug(GwLog::DEBUG, "successfully send led data for %d leds, %lld us", numLeds, end - now);
} }
if (ownsBuffer) if (ownsBuffer)
{ {
@ -211,10 +211,10 @@ bool sendToLeds(GwLog *logger, uint8_t pin, int numLeds, Color *leds, spi_host_d
void handleSpiLeds(void *param){ void handleSpiLeds(void *param){
LedTaskData *taskData=(LedTaskData*)param; LedTaskData *taskData=(LedTaskData*)param;
GwLog *logger=taskData->api->getLogger(); GwLog *logger=taskData->api->getLogger();
LOG_DEBUG(GwLog::ERROR,"spi led task initialized"); logger->logDebug(GwLog::ERROR, "spi led task initialized");
spi_host_device_t bus=SPI3_HOST; spi_host_device_t bus=SPI3_HOST;
bool spiValid=false; bool spiValid=false;
LOG_DEBUG(GwLog::ERROR,"SpiLed task started"); LOG_DEBUG(GwLog::ERROR, "SpiLed task started");
if (! prepareGpio(logger,OBP_FLASH_LED)){ if (! prepareGpio(logger,OBP_FLASH_LED)){
EXIT_TASK; EXIT_TASK;
@ -233,14 +233,14 @@ void handleSpiLeds(void *param){
LedInterface newLeds=taskData->getLedData(); LedInterface newLeds=taskData->getLedData();
if (first || current.backlightChanged(newLeds) || current.flasChanged(newLeds)){ if (first || current.backlightChanged(newLeds) || current.flasChanged(newLeds)){
first=false; first=false;
LOG_DEBUG(GwLog::ERROR,"handle SPI leds"); logger->logDebug(GwLog::ERROR, "handle SPI leds");
if (current.backlightChanged(newLeds) || first){ if (current.backlightChanged(newLeds) || first){
LOG_DEBUG(GwLog::ERROR,"setting backlight r=%02d,g=%02d,b=%02d", logger->logDebug(GwLog::ERROR, "setting backlight r=%02d,g=%02d,b=%02d",
newLeds.backlight[0].r,newLeds.backlight[0].g,newLeds.backlight[0].b); newLeds.backlight[0].r,newLeds.backlight[0].g,newLeds.backlight[0].b);
sendToLeds(logger,OBP_BACKLIGHT_LED,newLeds.backlightLen(),newLeds.backlight,bus,device); sendToLeds(logger,OBP_BACKLIGHT_LED,newLeds.backlightLen(),newLeds.backlight,bus,device);
} }
if (current.flasChanged(newLeds) || first){ if (current.flasChanged(newLeds) || first){
LOG_DEBUG(GwLog::ERROR,"setting flashr=%02d,g=%02d,b=%02d", logger->logDebug(GwLog::ERROR, "setting flashr=%02d,g=%02d,b=%02d",
newLeds.flash[0].r,newLeds.flash[0].g,newLeds.flash[0].b); newLeds.flash[0].r,newLeds.flash[0].g,newLeds.flash[0].b);
sendToLeds(logger,OBP_FLASH_LED,newLeds.flashLen(),newLeds.flash,bus,device); sendToLeds(logger,OBP_FLASH_LED,newLeds.flashLen(),newLeds.flash,bus,device);
} }

View File

@ -75,8 +75,8 @@ LedTaskData *ledTaskData=nullptr;
void hardwareInit(GwApi *api) void hardwareInit(GwApi *api)
{ {
GwLog *logger=api->getLogger(); GwLog *logger = api->getLogger();
GwConfigHandler *config=api->getConfig(); GwConfigHandler *config = api->getConfig();
Wire.begin(); Wire.begin();
// Init PCF8574 digital outputs // Init PCF8574 digital outputs
@ -87,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
LOG_DEBUG(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); delay(250);
} }
// FRAM (e.g. MB85RC256V) // FRAM (e.g. MB85RC256V)
@ -99,11 +99,11 @@ 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);
LOG_DEBUG(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 { else {
hasFRAM = false; hasFRAM = false;
LOG_DEBUG(GwLog::LOG,"NO FRAM detected"); logger->logDebug(GwLog::LOG, "NO FRAM detected");
} }
// SD Card // SD Card
hasSDCard = false; hasSDCard = false;
@ -112,6 +112,7 @@ void hardwareInit(GwApi *api)
esp_err_t ret; esp_err_t ret;
sdmmc_host_t host = SDSPI_HOST_DEFAULT(); sdmmc_host_t host = SDSPI_HOST_DEFAULT();
host.slot = SPI3_HOST; host.slot = SPI3_HOST;
logger->logDebug(GwLog::DEBUG, "SDSPI_HOST: max_freq_khz=%d" , host.max_freq_khz);
spi_bus_config_t bus_cfg = { spi_bus_config_t bus_cfg = {
.mosi_io_num = SD_SPI_MOSI, .mosi_io_num = SD_SPI_MOSI,
.miso_io_num = SD_SPI_MISO, .miso_io_num = SD_SPI_MISO,
@ -122,7 +123,7 @@ void hardwareInit(GwApi *api)
}; };
ret = spi_bus_initialize((spi_host_device_t) host.slot, &bus_cfg, SDSPI_DEFAULT_DMA); ret = spi_bus_initialize((spi_host_device_t) host.slot, &bus_cfg, SDSPI_DEFAULT_DMA);
if (ret != ESP_OK) { if (ret != ESP_OK) {
LOG_DEBUG(GwLog::ERROR,"Failed to initialize SPI bus for SD card"); logger->logDebug(GwLog::ERROR, "Failed to initialize SPI bus for SD card");
} else { } else {
sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT(); sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
slot_config.gpio_cs = SD_SPI_CS; slot_config.gpio_cs = SD_SPI_CS;
@ -135,15 +136,29 @@ void hardwareInit(GwApi *api)
ret = esp_vfs_fat_sdspi_mount(MOUNT_POINT, &host, &slot_config, &mount_config, &sdcard); ret = esp_vfs_fat_sdspi_mount(MOUNT_POINT, &host, &slot_config, &mount_config, &sdcard);
if (ret != ESP_OK) { if (ret != ESP_OK) {
if (ret == ESP_FAIL) { if (ret == ESP_FAIL) {
LOG_DEBUG(GwLog::ERROR,"Failed to mount SD card filesystem"); logger->logDebug(GwLog::ERROR, "Failed to mount SD card filesystem");
} else { } else {
LOG_DEBUG(GwLog::ERROR,"Failed to initialize SD card"); // ret == 263 could be not powered up yet
logger->logDebug(GwLog::ERROR, "Failed to initialize SD card (error #%d)", ret);
} }
} else { } else {
LOG_DEBUG(GwLog::ERROR,"SD card filesystem mounted"); logger->logDebug(GwLog::LOG, "SD card filesystem mounted at '%s'", MOUNT_POINT);
hasSDCard = true; 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 #endif
} }
@ -276,31 +291,31 @@ void setBacklightLED(uint brightness, const Color &color){
ledTaskData->setLedData(current); ledTaskData->setLedData(current);
} }
void toggleBacklightLED(uint brightness, const Color &color){ void toggleBacklightLED(uint brightness, const Color &color) {
if (ledTaskData == nullptr) return; if (ledTaskData == nullptr) return;
statusBacklightLED = !statusBacklightLED; statusBacklightLED = !statusBacklightLED;
Color nv=setBrightness(statusBacklightLED?color:COLOR_BLACK,brightness); Color nv = setBrightness(statusBacklightLED ? color : COLOR_BLACK, brightness);
LedInterface current=ledTaskData->getLedData(); LedInterface current = ledTaskData->getLedData();
current.setBacklight(nv); current.setBacklight(nv);
ledTaskData->setLedData(current); ledTaskData->setLedData(current);
} }
void setFlashLED(bool status){ void setFlashLED(bool status) {
if (ledTaskData == nullptr) return; if (ledTaskData == nullptr) return;
Color c=status?COLOR_RED:COLOR_BLACK; Color c = status?COLOR_RED:COLOR_BLACK;
LedInterface current=ledTaskData->getLedData(); LedInterface current=ledTaskData->getLedData();
current.setFlash(c); current.setFlash(c);
ledTaskData->setLedData(current); ledTaskData->setLedData(current);
} }
void blinkingFlashLED(){ void blinkingFlashLED() {
if(blinkingLED == true){ if (blinkingLED == true) {
statusLED = !statusLED; // Toggle LED for each run statusLED = !statusLED; // Toggle LED for each run
setFlashLED(statusLED); setFlashLED(statusLED);
} }
} }
void setBlinkingLED(bool status){ void setBlinkingLED(bool status) {
blinkingLED = status; blinkingLED = status;
} }

View File

@ -23,6 +23,7 @@
#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
@ -32,6 +33,10 @@
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;

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 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_SDA 21
#define OBP_I2C_SCL 38 #define OBP_I2C_SCL 38
// DS1388 RTC // DS1388 RTC

View File

@ -9,9 +9,11 @@
#include "qrcode.h" #include "qrcode.h"
#include "Nmea2kTwai.h" #include "Nmea2kTwai.h"
#ifdef BOARD_OBP40S3 #ifdef BOARD_OBP40S3
#include <SD.h> // #include <SD.h>
#include <FS.h> // #include <FS.h>
#include "dirent.h"
#endif #endif
#define STRINGIZE_IMPL(x) #x #define STRINGIZE_IMPL(x) #x
@ -54,7 +56,7 @@ private:
uint64_t chipid; uint64_t chipid;
bool simulation; bool simulation;
bool sdcard; bool use_sdcard;
String buzzer_mode; String buzzer_mode;
uint8_t buzzer_power; uint8_t buzzer_power;
String cpuspeed; String cpuspeed;
@ -84,7 +86,7 @@ private:
} else if (mode == 'C') { // Config } else if (mode == 'C') { // Config
mode = 'D'; mode = 'D';
} else if (mode == 'D') { // Device list } else if (mode == 'D') { // Device list
if (sdcard) { if (use_sdcard) {
mode = 'A'; // SD-Card mode = 'A'; // SD-Card
} else { } else {
mode = 'N'; mode = 'N';
@ -97,7 +99,7 @@ private:
void decMode() { void decMode() {
if (mode == 'N') { if (mode == 'N') {
if (sdcard) { if (use_sdcard) {
mode = 'A'; mode = 'A';
} else { } else {
mode = 'D'; mode = 'D';
@ -184,9 +186,10 @@ private:
epd->setCursor(8, y0 + 48); epd->setCursor(8, y0 + 48);
epd->print("SD-Card:"); epd->print("SD-Card:");
epd->setCursor(90, y0 + 48); epd->setCursor(90, y0 + 48);
if (sdcard) { if (hasSDCard) {
uint64_t cardsize = SD.cardSize() / (1024 * 1024); uint64_t cardsize = ((uint64_t) sdcard->csd.capacity) * sdcard->csd.sector_size / (1024 * 1024);
epd->print(String(cardsize) + String(" MB")); // epd->print(String(cardsize) + String(" MB"));
epd->printf("%llu MB", cardsize);
} else { } else {
epd->print("off"); epd->print("off");
} }
@ -385,11 +388,98 @@ private:
epd->setFont(&Ubuntu_Bold12pt8b); epd->setFont(&Ubuntu_Bold12pt8b);
epd->setCursor(8, 48); epd->setCursor(8, 48);
epd->print("SD Card info"); epd->print("SD card info");
epd->setFont(&Ubuntu_Bold8pt8b); epd->setFont(&Ubuntu_Bold8pt8b);
epd->setCursor(x0, y0); epd->setCursor(x0, y0);
epd->print("Work in progress..."); epd->print("Work in progress...");
// TODO directories IMG, MAP, HIST should exist.
// Show state: Files and used size
// Simple test for one file in root
epd->setCursor(x0, y0 + 32);
String file_test = MOUNT_POINT "/IMG/icon-settings2.pbm";
logger->logDebug(GwLog::LOG, "Testfile: %s", file_test.c_str());
struct stat st;
if (stat(file_test.c_str(), &st) == 0) {
epd->printf("File %s exists", file_test.c_str());
} else {
epd->printf("File %s not found", file_test.c_str());
}
// Root directory check
DIR* dir = opendir(MOUNT_POINT);
if (dir != NULL) {
logger->logDebug(GwLog::LOG, "Root directory: %s", MOUNT_POINT);
struct dirent* entry;
while ((entry = readdir(dir)) != NULL) {
logger->logDebug(GwLog::LOG, " %s type %d", entry->d_name, entry->d_type);
// type 1 is file
// type 2 is dir
}
closedir(dir);
} else {
logger->logDebug(GwLog::LOG, "Failed to open root directory");
}
// try to load example pbm file
// TODO create PBM load function in imglib
String filepath = MOUNT_POINT "/IMG/icon-settings2.pbm";
const char* file_img = filepath.c_str();
FILE* fh = fopen(file_img, "r");
if (fh != NULL) {
logger->logDebug(GwLog::LOG, "Open file for reading: %s", file_img);
char magic[3];
char buffer[80];
// 2 Byte Magic: P1=ASCII, P4=Binary
fgets(magic, sizeof(magic), fh);
if (strcmp(magic, "P1") != 0) {
logger->logDebug(GwLog::LOG, "Not a valid PBM file of type P1 (%s)", magic);
} else {
uint16_t width = 0;
uint16_t height = 0;
while (fgets(buffer, sizeof(buffer), fh)) {
// logger->logDebug(GwLog::LOG, "%s", buffer);
if (buffer[0] == '#') {
continue; // skip comment
}
if (sscanf(buffer, "%d %d", &width, &height) == 2) {
break;
}
}
logger->logDebug(GwLog::LOG, "Image: %dx%d", width, height);
}
/*size_t bytesRead = fread(buffer, sizeof(char), sizeof(buffer) - 1, fh);
buffer[bytesRead] = '\0'; // Null-terminate the string
if (bytesRead > 0) {
logger->logDebug(GwLog::LOG, "Read %d bytes", bytesRead);
logger->logDebug(GwLog::LOG, ">%s<", buffer);
} */
/* WIP
// Read pixel data and pack into the buffer
for (int i = 0; i < width * height; i++) {
int pixel;
fscanf(file, "%d", &pixel);
// Calculate the byte index and bit position
int byteIndex = i / 8;
int bitPosition = 7 - (i % 8); // Store MSB first
// Set the corresponding bit in the byte
if (pixel == 1) {
buffer[byteIndex] |= (1 << bitPosition);
}
}
*/
fclose(fh);
// epd->drawXBitmap(20, 200, buffer, width, height, commonData.fgcolor);
}
} }
void displayModeDevicelist() { void displayModeDevicelist() {
@ -428,7 +518,7 @@ public:
chipid = ESP.getEfuseMac(); chipid = ESP.getEfuseMac();
simulation = config->getBool(config->useSimuData); simulation = config->getBool(config->useSimuData);
#ifdef BOARD_OBP40S3 #ifdef BOARD_OBP40S3
sdcard = config->getBool(config->useSDCard); use_sdcard = config->getBool(config->useSDCard);
#endif #endif
buzzer_mode = config->getString(config->buzzerMode); buzzer_mode = config->getString(config->buzzerMode);
buzzer_mode.toLowerCase(); buzzer_mode.toLowerCase();
@ -461,9 +551,12 @@ public:
newitem = menu->addItem("simulation", "Simulation", "on/off", 0, ""); newitem = menu->addItem("simulation", "Simulation", "on/off", 0, "");
menu->setItemActive("accesspoint"); menu->setItemActive("accesspoint");
// Create info-file if not exists
// TODO
} }
virtual void setupKeys(){ void setupKeys() {
commonData->keydata[0].label = "EXIT"; commonData->keydata[0].label = "EXIT";
commonData->keydata[1].label = "MODE"; commonData->keydata[1].label = "MODE";
commonData->keydata[2].label = ""; commonData->keydata[2].label = "";
@ -472,7 +565,7 @@ public:
commonData->keydata[5].label = "ILUM"; 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 // do *NOT* handle key #1 this handled by obp60task as exit
// Switch display mode // Switch display mode
logger->logDebug(GwLog::LOG, "System keyboard handler"); logger->logDebug(GwLog::LOG, "System keyboard handler");
@ -491,6 +584,7 @@ public:
} }
// standby / deep sleep // standby / deep sleep
if (key == 5) { if (key == 5) {
logger->logDebug(GwLog::LOG, "System going into deep sleep mode...");
deepSleep(*commonData); deepSleep(*commonData);
} }
// Code for keylock // Code for keylock
@ -511,6 +605,7 @@ public:
} }
// standby / deep sleep // standby / deep sleep
if (key == 12) { if (key == 12) {
logger->logDebug(GwLog::LOG, "System going into deep sleep mode...");
deepSleep(*commonData); deepSleep(*commonData);
} }
#endif #endif
@ -543,13 +638,13 @@ public:
} }
} }
void displayNew(PageData &pageData){ void displayNew(PageData &pageData) {
// Get references from API // Get references from API
logger->logDebug(GwLog::LOG, "New page display: PageSystem");
NMEA2000 = pageData.api->getNMEA2000(); NMEA2000 = pageData.api->getNMEA2000();
}; };
int displayPage(PageData &pageData){ int displayPage(PageData &pageData) {
// Optical warning by limit violation (unused) // Optical warning by limit violation (unused)
if(flashLED == "Limit Violation"){ if(flashLED == "Limit Violation"){

View File

@ -19,8 +19,6 @@
#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
@ -42,45 +40,23 @@ 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 = api->getConfig()->getConfigItem(api->getConfig()->deviceName,true)->asString(); String devicename = config->getConfigItem(config->deviceName, true)->asString();
api->getConfig()->setValue(GwConfigDefinitions::systemName, devicename, GwConfigInterface::ConfigType::HIDDEN); config->setValue(GwConfigDefinitions::systemName, devicename, GwConfigInterface::ConfigType::HIDDEN);
logger->prefix = devicename + ":";
logger->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 #ifdef BOARD_OBP40S3
String powermode = api->getConfig()->getConfigItem(api->getConfig()->powerMode,true)->asString();
logger->logDebug(GwLog::DEBUG,"Power Mode is: %s", powermode.c_str());
powerInit(powermode);
#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);
logger->logDebug(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
@ -695,9 +671,9 @@ void OBP60Task(GwApi *api){
double homelon = commonData.config->getString(commonData.config->homeLON).toDouble(); double homelon = commonData.config->getString(commonData.config->homeLON).toDouble();
bool homevalid = homelat >= -180.0 and homelat <= 180 and homelon >= -90.0 and homelon <= 90.0; bool homevalid = homelat >= -180.0 and homelat <= 180 and homelon >= -90.0 and homelon <= 90.0;
if (homevalid) { if (homevalid) {
LOG_DEBUG(GwLog::LOG, "Home location set to %f : %f", homelat, homelon); logger->logDebug(GwLog::LOG, "Home location set to lat=%f, lon=%f", homelat, homelon);
} else { } else {
LOG_DEBUG(GwLog::LOG, "No valid home location found"); logger->logDebug(GwLog::LOG, "No valid home location found");
} }
// refreshmode defined in init section // refreshmode defined in init section
@ -729,6 +705,7 @@ void OBP60Task(GwApi *api){
//#################################################################################### //####################################################################################
bool systemPage = false; bool systemPage = false;
bool systemPageNew = false;
Page *currentPage; Page *currentPage;
while (true){ while (true){
delay(100); // Delay 100ms (loop time) delay(100); // Delay 100ms (loop time)
@ -781,6 +758,7 @@ void OBP60Task(GwApi *api){
systemPage = true; // System page is out of band systemPage = true; // System page is out of band
syspage->setupKeys(); syspage->setupKeys();
keyboardMessage = 0; keyboardMessage = 0;
systemPageNew = true;
} }
else { else {
currentPage = pages[pageNumber].page; currentPage = pages[pageNumber].page;
@ -977,6 +955,10 @@ void OBP60Task(GwApi *api){
displayFooter(commonData); displayFooter(commonData);
PageData sysparams; // empty PageData sysparams; // empty
sysparams.api = api; sysparams.api = api;
if (systemPageNew) {
syspage->displayNew(sysparams);
systemPageNew = false;
}
syspage->displayPage(sysparams); syspage->displayPage(sysparams);
} }
else { else {

View File

@ -72,7 +72,6 @@ lib_deps =
${basedeps.lib_deps} ${basedeps.lib_deps}
Wire Wire
SPI SPI
SD
ESP32time ESP32time
esphome/AsyncTCP-esphome@2.0.1 esphome/AsyncTCP-esphome@2.0.1
robtillaart/PCF8574@0.3.9 robtillaart/PCF8574@0.3.9