From 494acbf0d056595857b456014c74abdc0855d032 Mon Sep 17 00:00:00 2001 From: Thomas Hooge Date: Mon, 25 Aug 2025 20:56:14 +0200 Subject: [PATCH] Work on system page --- lib/obp60task/OBPSensorTask.cpp | 16 ++++++-- lib/obp60task/OBPSensorTask.h | 1 + lib/obp60task/PageSystem.cpp | 65 +++++++++++++++++++++--------- lib/obp60task/PageWindRoseFlex.cpp | 12 +++--- lib/obp60task/obp60task.cpp | 25 ++++++++++++ 5 files changed, 93 insertions(+), 26 deletions(-) diff --git a/lib/obp60task/OBPSensorTask.cpp b/lib/obp60task/OBPSensorTask.cpp index 6b3114d..e6e4aa2 100644 --- a/lib/obp60task/OBPSensorTask.cpp +++ b/lib/obp60task/OBPSensorTask.cpp @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3 #include // Adafruit Lib for sensors #include // Adafruit Lib for BME280 @@ -568,6 +569,11 @@ void sensorTask(void *param){ // Send data from environment sensor all 2s if(millis() > starttime6 + 2000){ starttime6 = millis(); + + // DEBUG + UBaseType_t stackfree = uxTaskGetStackHighWaterMark(NULL); + api->getLogger()->logDebug(GwLog::LOG, "obpSensortask Stack=%d", stackfree); + unsigned char TempSource = 2; // Inside temperature unsigned char PressureSource = 0; // Atmospheric pressure unsigned char HumiditySource = 0; // Inside humidity @@ -785,8 +791,12 @@ void sensorTask(void *param){ vTaskDelete(NULL); } - -void createSensorTask(SharedData *shared){ - xTaskCreate(sensorTask,"readSensors",10000,shared,3,NULL); +void createSensorTask(SharedData *shared) { + TaskHandle_t xHandle = NULL; + GwLog *logger = shared->api->getLogger(); + esp_err_t err = xTaskCreate(sensorTask, "readSensors", configMINIMAL_STACK_SIZE + 2048, shared, 3, &xHandle); + if ( err != pdPASS) { + logger->logDebug(GwLog::ERROR, "Failed to create sensor task! (err=%d)", err); + }; } #endif diff --git a/lib/obp60task/OBPSensorTask.h b/lib/obp60task/OBPSensorTask.h index 7dd9f24..8207fa4 100644 --- a/lib/obp60task/OBPSensorTask.h +++ b/lib/obp60task/OBPSensorTask.h @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include "GwSynchronized.h" #include "GwApi.h" diff --git a/lib/obp60task/PageSystem.cpp b/lib/obp60task/PageSystem.cpp index 5767ffa..e9eb5ca 100644 --- a/lib/obp60task/PageSystem.cpp +++ b/lib/obp60task/PageSystem.cpp @@ -8,7 +8,7 @@ * 1. Hard and software information * 2. System settings * 3. System configuration: running and NVRAM - * 4. NMEA2000 device list + * 4. NMEA2000 device list if NMEA2000 enabled * 5. SD Card information if available * * TODO @@ -43,6 +43,8 @@ #define DISPLAYINFO STRINGIZE(EPDTYPE) #define GXEPD2INFO STRINGIZE(GXEPD2VERS) +#define N2K_INACTIVE_AGE 30000 + class PageSystem : public Page { private: @@ -68,6 +70,10 @@ private: double homelon; Nmea2kTwai *NMEA2000; + unsigned long n2kRxOld = 0; // to detect bus activity + unsigned long n2kTxOld = 0; + long n2k_ts = 0; // timestamp of last activity + bool n2k_active = false; 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 @@ -233,7 +239,7 @@ private: epd->print(String(Heap_free)); // RAM free for task - int RAM_free = uxTaskGetStackHighWaterMark(NULL); + UBaseType_t RAM_free = uxTaskGetStackHighWaterMark(NULL); epd->setCursor(202, y0 + 32); epd->print("Task free:"); epd->setCursor(300, y0 + 32); @@ -390,7 +396,6 @@ private: epd->setFont(&Ubuntu_Bold8pt8b); epd->setCursor(x0, y0); - epd->print("Work in progress..."); #ifdef BOARD_OBP60S3 // This mode should not be callable by devices without card hardware // In case of accidential reaching this, display a friendly message @@ -402,32 +407,39 @@ private: magic.dat version.dat readme.txt - IMAGES/ + BAK/ CHARTS/ - LOGS/ DATA/ + IMAGES/ + LOGS/ */ - // 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()); + // Simple test for magic file in root + epd->setCursor(x0, y0 + 16); + const char* file_magic = MOUNT_POINT "/magic.dat"; + logger->logDebug(GwLog::LOG, "Test magicfile: %s", file_magic); struct stat st; - if (stat(file_test.c_str(), &st) == 0) { - epd->printf("File %s exists", file_test.c_str()); + if (stat(file_magic, &st) == 0) { + epd->printf("Magicfile %s exists", file_magic); } else { - epd->printf("File %s not found", file_test.c_str()); + epd->printf("Magicfile %s not found", file_magic); } // 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) { + while (((entry = readdir(dir)) != NULL) and (dy < 140)) { + epd->setCursor(x0, y0 + 64 + dy); + epd->print(entry->d_name); + // type 1 is file, type 2 is dir + if (entry->d_type == 2) { + epd->print("/"); + } + dy += 20; logger->logDebug(GwLog::LOG, " %s type %d", entry->d_name, entry->d_type); - // type 1 is file - // type 2 is dir } closedir(dir); } else { @@ -436,7 +448,7 @@ private: // try to load example pbm file // TODO create PBM load function in imglib - String filepath = MOUNT_POINT "/IMG/icon-settings2.pbm"; + String filepath = MOUNT_POINT "/IMAGES/icon-settings2.pbm"; const char* file_img = filepath.c_str(); FILE* fh = fopen(file_img, "r"); if (fh != NULL) { @@ -494,8 +506,12 @@ private: #endif } - void displayModeDevicelist() { + void displayModeDevicelist(bool bus_active) { // NMEA2000 device list + + // TODO Check if NMEA2000 enabled globally + // if disabled this page should not be shown + epd->setFont(&Ubuntu_Bold12pt8b); epd->setCursor(8, 48); epd->print("NMEA2000 device list"); @@ -508,6 +524,11 @@ private: epd->print("TxD: "); epd->print(String(commonData->status.n2kTx)); + // show bus activity + epd->setCursor(20, 120); + epd->print("Bus: "); + epd->print(bus_active ? "active" : "inactive"); + epd->setCursor(20, 140); epd->printf("N2k source address: %d", NMEA2000->GetN2kSource()); @@ -685,7 +706,15 @@ public: displayModeSDCard(); break; case 'D': - displayModeDevicelist(); + // check bus status + if (commonData->status.n2kRx != n2kRxOld || commonData->status.n2kTx != n2kTxOld) { + n2kRxOld = commonData->status.n2kRx; + n2kTxOld = commonData->status.n2kTx; + n2k_ts = millis(); + } else { + n2k_active = (millis() - n2k_ts <= N2K_INACTIVE_AGE); + } + displayModeDevicelist(n2k_active); break; } diff --git a/lib/obp60task/PageWindRoseFlex.cpp b/lib/obp60task/PageWindRoseFlex.cpp index 41de2aa..117b697 100644 --- a/lib/obp60task/PageWindRoseFlex.cpp +++ b/lib/obp60task/PageWindRoseFlex.cpp @@ -331,7 +331,8 @@ public: //******************************************************************************************* // Show value6 (=fourth user-configured parameter) and ssource, so that they do not collide with the wind pointer - if (cos(value1) > 0) { + if (cos(value1) > 0) { + // pointer points upwards epd->setFont(&DSEG7Classic_BoldItalic16pt7b); epd->setCursor(160, 200); epd->print(svalue6); // Value @@ -346,7 +347,8 @@ public: } epd->print(ssource); // true or app. } - else { + else { + // pointer points downwards epd->setFont(&DSEG7Classic_BoldItalic16pt7b); epd->setCursor(160, 130); epd->print(svalue6); @@ -355,11 +357,11 @@ public: epd->print(" "); epd->print(holdvalues ? unit6old : unit6); if (sin(value1) > 0) { - epd->setCursor(160, 130); + epd->setCursor(160, 200); } else { - epd->setCursor(220, 130); + epd->setCursor(220, 200); } - epd->print(ssource); //true or app. + epd->print(ssource); //true or app. } return PAGE_UPDATE; diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp index fb6c5cb..93467f6 100644 --- a/lib/obp60task/obp60task.cpp +++ b/lib/obp60task/obp60task.cpp @@ -20,6 +20,8 @@ #include "OBP60QRWiFi.h" // Functions lib for WiFi QR code #include "OBPSensorTask.h" // Functions lib for sensor data +#include "freertos/task.h" // WIP possible unused + #ifdef BOARD_OBP40S3 #include "driver/rtc_io.h" // Needs for weakup from deep sleep #include @@ -119,6 +121,27 @@ void OBP60Init(GwApi *api){ } +/* ux-functions not working WTF? +bool listTasks(GwLog *logger) { + UBaseType_t taskCount = uxTaskGetNumberOfTasks(); + TaskStatus_t *taskStatusArray; + + taskStatusArray = (TaskStatus_t *)pvPortMalloc(taskCount * sizeof(TaskStatus_t)); + if (taskStatusArray != NULL) { + taskCount = uxTaskGetSystemState(taskStatusArray, taskCount, NULL); + for (UBaseType_t i = 0; i < taskCount; i++) { + logger->logDebug(GwLog::LOG, "Task Name: %s (Stack=%d)", taskStatusArray[i].pcTaskName, + taskStatusArray[i].usStackHighWaterMark); + // more fields in task status + // xHandle, uxCurrentPriority, uxBasePriority, usStackHighWaterMark + } + vPortFree(taskStatusArray); + return true; + } + logger->logDebug(GwLog::ERROR, "Failed to allocate memory for task list"); + return false; +} */ + class BoatValueList{ public: static const int MAXVALUES=100; @@ -756,6 +779,8 @@ void OBP60Task(GwApi *api){ pages[pageNumber].page->setupKeys(); // Initialize keys for first page + // listTasks(logger); + // Main loop runs with 100ms //####################################################################################