From 1de936fd47711d9a573ce7e199331b916c52027d Mon Sep 17 00:00:00 2001 From: norbert-walter Date: Sun, 1 Feb 2026 18:09:44 +0100 Subject: [PATCH 1/4] Typo --- lib/obp60task/OBP60Extensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp index 29911dd..57c3701 100644 --- a/lib/obp60task/OBP60Extensions.cpp +++ b/lib/obp60task/OBP60Extensions.cpp @@ -205,7 +205,7 @@ void setPCF8574PortPinModul1(uint8_t pin, uint8_t value) if (pin > 7) return; Wire.setClock(I2C_SPEED_LOW); // Set I2C clock on 10 kHz for longer wires // Set bit - if (pcf8574_Modul1.begin(port1)) // Check module availability + if (pcf8574_Modul1.begin(port1)) // Check module availability and start it { if (value == LOW) port1 &= ~(1 << pin); // Set bit else port1 |= (1 << pin); From 576f0a0d4fc54db1b26d63eeb65ac18af19b0ffb Mon Sep 17 00:00:00 2001 From: norbert-walter Date: Mon, 2 Feb 2026 16:29:18 +0100 Subject: [PATCH 2/4] Fix for LED brightness and add Page Autopilot --- lib/obp60task/LedSpiTask.cpp | 4 +- lib/obp60task/PageAutopilot.cpp | 263 ++++++++++++++++++++++++++++++++ lib/obp60task/PageCompass.cpp | 8 +- lib/obp60task/obp60task.cpp | 4 +- 4 files changed, 273 insertions(+), 6 deletions(-) create mode 100644 lib/obp60task/PageAutopilot.cpp diff --git a/lib/obp60task/LedSpiTask.cpp b/lib/obp60task/LedSpiTask.cpp index fbbd640..74497e7 100644 --- a/lib/obp60task/LedSpiTask.cpp +++ b/lib/obp60task/LedSpiTask.cpp @@ -22,9 +22,11 @@ static uint8_t mulcolor(uint8_t f1, uint8_t f2){ } Color setBrightness(const Color &color,uint8_t brightness){ + if (brightness > 100) brightness = 100; + uint16_t br255=brightness*255; br255=br255/100; - //very simple for now + //Very simple for now Color rt=color; rt.g=mulcolor(rt.g,br255); rt.b=mulcolor(rt.b,br255); diff --git a/lib/obp60task/PageAutopilot.cpp b/lib/obp60task/PageAutopilot.cpp new file mode 100644 index 0000000..6cbf299 --- /dev/null +++ b/lib/obp60task/PageAutopilot.cpp @@ -0,0 +1,263 @@ +#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3 + +#include "Pagedata.h" +#include "OBP60Extensions.h" + +// These constants have to match the declaration below in : +// PageDescription registerPageAutopilot( +// {"HDM","HDT", "COG", "STW", "SOG", "DBT","XTE", "DTW", "BTW"}, // Bus values we need in the page +const int HowManyValues = 9; + +const int AverageValues = 4; + +const int ShowHDM = 0; +const int ShowHDT = 1; +const int ShowCOG = 2; +const int ShowSTW = 3; +const int ShowSOG = 4; +const int ShowDBT = 5; +const int ShowXTE = 6; +const int ShowDTW = 7; +const int ShowBTW = 8; + +const int Compass_X0 = 200; // X center point of compass band +const int Compass_Y0 = 220; // Y position of compass lines +const int Compass_LineLength = 22; // Length of compass lines +const float Compass_LineDelta = 8.0;// Compass band: 1deg = 5 Pixels, 10deg = 50 Pixels + +class PageAutopilot : public Page +{ + int WhichDataCompass = ShowHDM; // Start value + int WhichDataDisplay = ShowHDM; // Start value + + public: + PageAutopilot(CommonData &common){ + commonData = &common; + common.logger->logDebug(GwLog::LOG,"Instantiate PageAutopilot"); + } + + virtual void setupKeys(){ + Page::setupKeys(); + commonData->keydata[0].label = "CMP"; + commonData->keydata[1].label = "SRC"; + } + + virtual int handleKey(int key){ + // Code for keylock + + if ( key == 1 ) { + WhichDataCompass += 1; + if ( WhichDataCompass > ShowCOG) + WhichDataCompass = ShowHDM; + return 0; + } + if ( key == 2 ) { + WhichDataDisplay += 1; + if ( WhichDataDisplay > ShowDBT) + WhichDataDisplay = ShowHDM; + } + + if(key == 11){ + commonData->keylock = !commonData->keylock; + return 0; // Commit the key + } + return key; + } + + int displayPage(PageData &pageData){ + GwConfigHandler *config = commonData->config; + GwLog *logger = commonData->logger; + + // Old values for hold function + static String OldDataText[HowManyValues] = {"", "", "","", "", "","", "", ""}; + static String OldDataUnits[HowManyValues] = {"", "", "","", "", "","", "", ""}; + + // Get config data + String lengthformat = config->getString(config->lengthFormat); + // bool simulation = config->getBool(config->useSimuData); + bool holdvalues = config->getBool(config->holdvalues); + String flashLED = config->getString(config->flashLED); + String backlightMode = config->getString(config->backlight); + + GwApi::BoatValue *bvalue; + String DataName[HowManyValues]; + double DataValue[HowManyValues]; + bool DataValid[HowManyValues]; + String DataText[HowManyValues]; + String DataUnits[HowManyValues]; + String DataFormat[HowManyValues]; + FormattedData TheFormattedData; + + for (int i = 0; i < HowManyValues; i++){ + bvalue = pageData.values[i]; + TheFormattedData = formatValue(bvalue, *commonData); + DataName[i] = xdrDelete(bvalue->getName()); + DataName[i] = DataName[i].substring(0, 6); // String length limit for value name + DataUnits[i] = formatValue(bvalue, *commonData).unit; + DataText[i] = TheFormattedData.svalue; // Formatted value as string including unit conversion and switching decimal places + DataValue[i] = TheFormattedData.value; // Value as double in SI unit + DataValid[i] = bvalue->valid; + DataFormat[i] = bvalue->getFormat(); // Unit of value + LOG_DEBUG(GwLog::LOG,"Drawing at PageAutopilot: %d %s %f %s %s", i, DataName[i], DataValue[i], DataFormat[i], DataText[i] ); + } + + // Optical warning by limit violation (unused) + if(String(flashLED) == "Limit Violation"){ + setBlinkingLED(false); + setFlashLED(false); + } + + if (bvalue == NULL) return PAGE_OK; // WTF why this statement? + + //*********************************************************** + + // Set display in partial refresh mode + getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update + getdisplay().setTextColor(commonData->fgcolor); + + // Horizontal line 2 pix top & bottom + // Print data on top half + getdisplay().fillRect(0, 130, 400, 2, commonData->fgcolor); + getdisplay().setFont(&Ubuntu_Bold20pt8b); + getdisplay().setCursor(10, 70); + getdisplay().print(DataName[WhichDataDisplay]); // Page name + // Show unit + getdisplay().setFont(&Ubuntu_Bold12pt8b); + getdisplay().setCursor(10, 120); + getdisplay().print(DataUnits[WhichDataDisplay]); + getdisplay().setCursor(190, 120); + getdisplay().setFont(&DSEG7Classic_BoldItalic42pt7b); + + if(holdvalues == false){ + getdisplay().print(DataText[WhichDataDisplay]); // Real value as formated string + } + else{ + getdisplay().print(OldDataText[WhichDataDisplay]); // Old value as formated string + } + if(DataValid[WhichDataDisplay] == true){ + OldDataText[WhichDataDisplay] = DataText[WhichDataDisplay]; // Save the old value + OldDataUnits[WhichDataDisplay] = DataUnits[WhichDataDisplay]; // Save the old unit + } + + // Now draw compass band + // Get the data + double TheAngle = DataValue[WhichDataCompass]; + static double AvgAngle = 0; + AvgAngle = ( AvgAngle * AverageValues + TheAngle ) / (AverageValues + 1 ); + + int TheTrend = round( ( TheAngle - AvgAngle) * 180.0 / M_PI ); + + static const int bsize = 30; + char buffer[bsize+1]; + buffer[0]=0; + + getdisplay().setFont(&Ubuntu_Bold16pt8b); + getdisplay().setCursor(10, Compass_Y0-60); + getdisplay().print(DataName[WhichDataCompass]); // Page name + + + // Draw compass base line and pointer + getdisplay().fillRect(0, Compass_Y0, 400, 3, commonData->fgcolor); + getdisplay().fillTriangle(Compass_X0,Compass_Y0-40,Compass_X0-10,Compass_Y0-80,Compass_X0+10,Compass_Y0-80,commonData->fgcolor); + // Draw trendlines + for ( int i = 1; i < abs(TheTrend) / 2; i++){ + int x1; + if ( TheTrend < 0 ) + x1 = Compass_X0 + 20 * i; + else + x1 = Compass_X0 - 20 * ( i + 1 ); + + getdisplay().fillRect(x1, Compass_Y0 -55, 10, 6, commonData->fgcolor); + } + // Central line + satellite lines + double NextSector = round(TheAngle / ( M_PI / 9 )) * ( M_PI / 9 ); // Get the next 20degree value + double Offset = - ( NextSector - TheAngle); // Offest of the center line compared to TheAngle in Radian + + int Delta_X = int ( Offset * 180.0 / M_PI * Compass_LineDelta ); + for ( int i = 0; i <=4; i++ ){ + int x0; + x0 = Compass_X0 + Delta_X + 2 * i * 5 * Compass_LineDelta; + getdisplay().fillRect(x0-2, Compass_Y0 - 2 * Compass_LineLength, 5, 2 * Compass_LineLength, commonData->fgcolor); + x0 = Compass_X0 + Delta_X + ( 2 * i + 1 ) * 5 * Compass_LineDelta; + getdisplay().fillRect(x0-1, Compass_Y0 - Compass_LineLength, 3, Compass_LineLength, commonData->fgcolor); + + x0 = Compass_X0 + Delta_X - 2 * i * 5 * Compass_LineDelta; + getdisplay().fillRect(x0-2, Compass_Y0 - 2 * Compass_LineLength, 5, 2 * Compass_LineLength, commonData->fgcolor); + x0 = Compass_X0 + Delta_X - ( 2 * i + 1 ) * 5 * Compass_LineDelta; + getdisplay().fillRect(x0-1, Compass_Y0 - Compass_LineLength, 3, Compass_LineLength, commonData->fgcolor); + } + + getdisplay().fillRect(0, Compass_Y0, 400, 3, commonData->fgcolor); + // Add the numbers to the compass band + int x0; + float AngleToDisplay = NextSector * 180.0 / M_PI; + + x0 = Compass_X0 + Delta_X; + getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b); + + do { + getdisplay().setCursor(x0 - 40, Compass_Y0 + 40); + snprintf(buffer,bsize,"%03.0f", AngleToDisplay); + getdisplay().print(buffer); + AngleToDisplay += 20; + if ( AngleToDisplay >= 360.0 ) + AngleToDisplay -= 360.0; + x0 -= 4 * 5 * Compass_LineDelta; + } while ( x0 >= 0 - 60 ); + + AngleToDisplay = NextSector * 180.0 / M_PI - 20; + if ( AngleToDisplay < 0 ) + AngleToDisplay += 360.0; + + x0 = Compass_X0 + Delta_X + 4 * 5 * Compass_LineDelta; + do { + getdisplay().setCursor(x0 - 40, Compass_Y0 + 40); + snprintf(buffer,bsize,"%03.0f", AngleToDisplay); + // Quick and dirty way to prevent wrapping text in next line + if ( ( x0 - 40 ) > 380 ) + buffer[0] = 0; + else if ( ( x0 - 40 ) > 355 ) + buffer[1] = 0; + else if ( ( x0 - 40 ) > 325 ) + buffer[2] = 0; + + getdisplay().print(buffer); + + AngleToDisplay -= 20; + if ( AngleToDisplay < 0 ) + AngleToDisplay += 360.0; + x0 += 4 * 5 * Compass_LineDelta; + } while (x0 < ( 400 - 20 -40 ) ); + + // static int x_test = 320; + // x_test += 2; + + // snprintf(buffer,bsize,"%03d", x_test); + // getdisplay().setCursor(x_test, Compass_Y0 - 60); + // getdisplay().print(buffer); + // if ( x_test > 390) + // x_test = 320; + + return PAGE_UPDATE; + }; + +}; + +static Page *createPage(CommonData &common){ + return new PageAutopilot(common); +}/** + * with the code below we make this page known to the PageTask + * we give it a type (name) that can be selected in the config + * we define which function is to be called + * and we provide the number of user parameters we expect + * this will be number of BoatValue pointers in pageData.values + */ +PageDescription registerPageAutopilot( + "Autopilot", // Page name + createPage, // Action + 0, // Number of bus values depends on selection in Web configuration + {"HDM","HDT", "COG", "STW", "SOG", "DBT","XTE", "DTW", "BTW"}, // Bus values we need in the page + true // Show display header on/off +); + +#endif diff --git a/lib/obp60task/PageCompass.cpp b/lib/obp60task/PageCompass.cpp index db98c87..12281e9 100644 --- a/lib/obp60task/PageCompass.cpp +++ b/lib/obp60task/PageCompass.cpp @@ -17,10 +17,10 @@ const int ShowSTW = 3; const int ShowSOG = 4; const int ShowDBS = 5; -const int Compass_X0 = 200; // center point of compass band -const int Compass_Y0 = 220; // position of compass lines -const int Compass_LineLength = 22; // length of compass lines -const float Compass_LineDelta = 8.0;// compass band: 1deg = 5 Pixels, 10deg = 50 Pixels +const int Compass_X0 = 200; // X center point of compass band +const int Compass_Y0 = 220; // Y position of compass lines +const int Compass_LineLength = 22; // Length of compass lines +const float Compass_LineDelta = 8.0;// Compass band: 1deg = 5 Pixels, 10deg = 50 Pixels class PageCompass : public Page { diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp index 1058ae0..c213ba4 100644 --- a/lib/obp60task/obp60task.cpp +++ b/lib/obp60task/obp60task.cpp @@ -264,6 +264,8 @@ void registerAllPages(PageList &list){ list.add(®isterPageNavigation); extern PageDescription registerPageDigitalOut; list.add(®isterPageDigitalOut); + extern PageDescription registerPageAutopilot; + list.add(®isterPageAutopilot); } // Undervoltage detection for shutdown display @@ -531,7 +533,7 @@ void OBP60Task(GwApi *api){ commonData.backlight.mode = backlightMapping(config->getConfigItem(config->backlight,true)->asString()); commonData.backlight.color = colorMapping(config->getConfigItem(config->blColor,true)->asString()); - commonData.backlight.brightness = 2.55 * uint(config->getConfigItem(config->blBrightness,true)->asInt()); + commonData.backlight.brightness = uint(config->getConfigItem(config->blBrightness,true)->asInt()); commonData.powermode = api->getConfig()->getConfigItem(api->getConfig()->powerMode,true)->asString(); bool uvoltage = config->getConfigItem(config->underVoltage, true)->asBoolean(); From 6a56a8fb569ebb77eed40a092d30511cd2c7aa98 Mon Sep 17 00:00:00 2001 From: norbert-walter Date: Mon, 2 Feb 2026 17:00:27 +0100 Subject: [PATCH 3/4] Fix I2C adresses for INA219 --- lib/obp60task/OBP60Hardware.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/obp60task/OBP60Hardware.h b/lib/obp60task/OBP60Hardware.h index fa25e2d..8768e0f 100644 --- a/lib/obp60task/OBP60Hardware.h +++ b/lib/obp60task/OBP60Hardware.h @@ -23,8 +23,8 @@ #define AS5600_I2C_ADDR 0x36 // Addr. 0x36 (fix) // INA219 #define SHUNT_VOLTAGE 0.075 // Shunt voltage in V by max. current (75mV) - #define INA219_I2C_ADDR1 0x40 // Addr. 0x41 (fix A0 = 5V, A1 = GND) for battery - #define INA219_I2C_ADDR2 0x41 // Addr. 0x44 (fix A0 = GND, A1 = 5V) for solar panels + #define INA219_I2C_ADDR1 0x41 // Addr. 0x41 (fix A0 = 5V, A1 = GND) for battery + #define INA219_I2C_ADDR2 0x44 // Addr. 0x44 (fix A0 = GND, A1 = 5V) for solar panels #define INA219_I2C_ADDR3 0x45 // Addr. 0x45 (fix A0 = 5V, A1 = 5V) for generator // INA226 #define INA226_I2C_ADDR1 0x41 // Addr. 0x41 (fix A0 = 5V, A1 = GND) for battery @@ -103,8 +103,8 @@ #define AS5600_I2C_ADDR 0x36 // Addr. 0x36 (fix) // INA219 #define SHUNT_VOLTAGE 0.075 // Shunt voltage in V by max. current (75mV) - #define INA219_I2C_ADDR1 0x40 // Addr. 0x41 (fix A0 = 5V, A1 = GND) for battery - #define INA219_I2C_ADDR2 0x41 // Addr. 0x44 (fix A0 = GND, A1 = 5V) for solar panels + #define INA219_I2C_ADDR1 0x41 // Addr. 0x41 (fix A0 = 5V, A1 = GND) for battery + #define INA219_I2C_ADDR2 0x44 // Addr. 0x44 (fix A0 = GND, A1 = 5V) for solar panels #define INA219_I2C_ADDR3 0x45 // Addr. 0x45 (fix A0 = 5V, A1 = 5V) for generator // INA226 #define INA226_I2C_ADDR1 0x41 // Addr. 0x41 (fix A0 = 5V, A1 = GND) for battery From 753e87068fb586ab773c14a226ac03ecb800ccc0 Mon Sep 17 00:00:00 2001 From: norbert-walter Date: Mon, 2 Feb 2026 21:26:43 +0100 Subject: [PATCH 4/4] New function for backlight - 3 brigjhtness steps --- lib/obp60task/OBP60Extensions.cpp | 34 +++++++++++++++++++++++++++++++ lib/obp60task/OBP60Extensions.h | 1 + lib/obp60task/config.json | 4 ++-- lib/obp60task/config_obp40.json | 4 ++-- lib/obp60task/obp60task.cpp | 2 +- 5 files changed, 40 insertions(+), 5 deletions(-) diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp index 57c3701..76c6334 100644 --- a/lib/obp60task/OBP60Extensions.cpp +++ b/lib/obp60task/OBP60Extensions.cpp @@ -331,6 +331,40 @@ void toggleBacklightLED(uint brightness, const Color &color){ ledTaskData->setLedData(current); } +void stepsBacklightLED(uint brightness, const Color &color){ + static uint step = 0; + uint actBrightness = 0; + // Different brightness steps + if(step == 0){ + actBrightness = brightness; // 100% from brightess + statusBacklightLED = true; + } + if(step == 1){ + actBrightness = brightness * 0.5; // 50% from brightess + statusBacklightLED = true; + } + if(step == 2){ + actBrightness = brightness * 0.2; // 20% from brightess + statusBacklightLED = true; + } + if(step == 3){ + actBrightness = 0; // 0% + statusBacklightLED = false; + } + if(actBrightness < 5){ // Limiter if values too low + actBrightness = 5; + } + step = step + 1; // Increment step counter + if(step == 4){ // Reset counter + step = 0; + } + if (ledTaskData == nullptr) return; + Color nv=setBrightness(statusBacklightLED?color:COLOR_BLACK,actBrightness); + LedInterface current=ledTaskData->getLedData(); + current.setBacklight(nv); + ledTaskData->setLedData(current); +} + void setFlashLED(bool status){ if (ledTaskData == nullptr) return; Color c=status?COLOR_RED:COLOR_BLACK; diff --git a/lib/obp60task/OBP60Extensions.h b/lib/obp60task/OBP60Extensions.h index 5975456..604c356 100644 --- a/lib/obp60task/OBP60Extensions.h +++ b/lib/obp60task/OBP60Extensions.h @@ -96,6 +96,7 @@ void togglePortPin(uint pin); // Toggle extension port pin Color colorMapping(const String &colorString); // Color mapping string to CHSV colors void setBacklightLED(uint brightness, const Color &color);// Set backlight LEDs void toggleBacklightLED(uint brightness,const Color &color);// Toggle backlight LEDs +void stepsBacklightLED(uint brightness, const Color &color);// Set backlight LEDs in 4 steps (100%, 50%, 10%, 0%) BacklightMode backlightMapping(const String &backlightString);// Configuration string to value void setFlashLED(bool status); // Set flash LED diff --git a/lib/obp60task/config.json b/lib/obp60task/config.json index 70e842a..307f9f4 100644 --- a/lib/obp60task/config.json +++ b/lib/obp60task/config.json @@ -1273,9 +1273,9 @@ "type": "number", "default": "50", "check": "checkMinMax", - "min": 20, + "min": 5, "max": 100, - "description": "Backlight brightness [20...100%]", + "description": "Backlight brightness [5...100%]", "category": "OBP60 Display", "capabilities": { "obp60":"true" diff --git a/lib/obp60task/config_obp40.json b/lib/obp60task/config_obp40.json index ad7d880..9889b04 100644 --- a/lib/obp60task/config_obp40.json +++ b/lib/obp60task/config_obp40.json @@ -1285,9 +1285,9 @@ "type": "number", "default": "50", "check": "checkMinMax", - "min": 20, + "min": 5, "max": 100, - "description": "Backlight brightness [20...100%]", + "description": "Backlight brightness [5...100%]", "category": "OBP40 Display", "capabilities": { "obp40": "false" diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp index c213ba4..e206204 100644 --- a/lib/obp60task/obp60task.cpp +++ b/lib/obp60task/obp60task.cpp @@ -660,7 +660,7 @@ void OBP60Task(GwApi *api){ // if(String(backlight) == "Control by Key"){ if(keyboardMessage == 6){ LOG_DEBUG(GwLog::LOG,"Toggle Backlight LED"); - toggleBacklightLED(commonData.backlight.brightness, commonData.backlight.color); + stepsBacklightLED(commonData.backlight.brightness, commonData.backlight.color); } } #ifdef BOARD_OBP40S3