From a5494ccee46e98434d7205becc8167a6b70a7546 Mon Sep 17 00:00:00 2001 From: Ulrich Meine Date: Sat, 10 May 2025 01:59:19 +0200 Subject: [PATCH] Initial commit - principle working --- lib/obp60task/BoatDataCalibration.cpp | 123 ++++++++++++++++++++++++++ lib/obp60task/BoatDataCalibration.h | 33 +++++++ lib/obp60task/PageFourValues.cpp | 5 ++ lib/obp60task/PageFourValues2.cpp | 5 ++ lib/obp60task/PageOneValue.cpp | 2 + lib/obp60task/PageThreeValues.cpp | 4 + lib/obp60task/PageTwoValues.cpp | 3 + lib/obp60task/config.json | 91 +++++++++++++++++++ lib/obp60task/obp60task.cpp | 5 ++ 9 files changed, 271 insertions(+) create mode 100644 lib/obp60task/BoatDataCalibration.cpp create mode 100644 lib/obp60task/BoatDataCalibration.h diff --git a/lib/obp60task/BoatDataCalibration.cpp b/lib/obp60task/BoatDataCalibration.cpp new file mode 100644 index 0000000..379e7dd --- /dev/null +++ b/lib/obp60task/BoatDataCalibration.cpp @@ -0,0 +1,123 @@ +#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3 + +#include "BoatDataCalibration.h" + +CalibrationDataList calibrationData; + +void CalibrationDataList::readConfig(GwConfigHandler* config, GwLog* logger) +// Initial load of calibration data into internal list +// This function is called once at init phase of to read the configuration values +{ + // Load user configuration values + String lengthFormat = config->getString(config->lengthFormat); // [m|ft] + String distanceFormat = config->getString(config->distanceFormat); // [m|km|nm] + String speedFormat = config->getString(config->speedFormat); // [m/s|km/h|kn] + String windspeedFormat = config->getString(config->windspeedFormat); // [m/s|km/h|kn|bft] + String tempFormat = config->getString(config->tempFormat); // [K|°C|°F] + + // Read calibration settings for DBT + calibrationData.list[0].instance = "DBT"; + calibrationData.list[0].offset = (config->getString(config->calOffsetDBT)).toFloat(); + if (lengthFormat == "ft") { // Convert DBT to SI standard meters + calibrationData.list[0].offset *= 0.3048; + } + calibrationData.list[0].slope = 1.0; // No slope for DBT + calibrationData.list[0].isCalibrated = false; + + // Read calibration settings for other data instances + for (int i = 1; i < maxCalibrationData; i++) { + String instance = "calInstance" + String(i); + String offset = "calOffset" + String(i); + String slope = "calSlope" + String(i); + +// calibrationData = new CalibrationDataList; + calibrationData.list[i].instance = config->getString(instance, ""); + calibrationData.list[i].offset = (config->getString(offset, "")).toFloat(); + calibrationData.list[i].slope = (config->getString(slope, "")).toFloat(); + if (calibrationData.list[i].instance == "AWA" || calibrationData.list[i].instance == "AWS") { + if (windspeedFormat == "m/s") { // Convert calibration values to SI standard m/s + // No conversion needed + } else if (windspeedFormat == "km/h") { + calibrationData.list[i].offset /= 3.6; // Convert km/h to m/s + calibrationData.list[i].slope /= 3.6; // Convert km/h to m/s + } else if (windspeedFormat == "kn") { + calibrationData.list[i].offset /= 1.94384; // Convert kn to m/s + calibrationData.list[i].slope /= 1.94384; // Convert kn to m/s + } else if (windspeedFormat == "bft") { + calibrationData.list[i].offset *= 0.5; // Convert Bft to m/s (approx) -> to be improved + calibrationData.list[i].slope *= 0.5; // Convert km/h to m/s + } + } else if (calibrationData.list[i].instance == "STW") { + if (speedFormat == "m/s") { + // No conversion needed + } else if (speedFormat == "km/h") { + calibrationData.list[i].offset /= 3.6; // Convert km/h to m/s + calibrationData.list[i].slope /= 3.6; // Convert km/h to m/s + } else if (speedFormat == "kn") { + calibrationData.list[i].offset /= 1.94384; // Convert kn to m/s + calibrationData.list[i].slope /= 1.94384; // Convert kn to m/s + } + } else if (calibrationData.list[i].instance == "WTemp") { + if (tempFormat == "K" || tempFormat == "C") { + // No conversion needed + } else if (tempFormat == "F") { + calibrationData.list[i].offset *= 5.0 / 9.0; // Convert °F to K + calibrationData.list[i].slope *= 5.0 / 9.0; // Convert °F to K + } + } + calibrationData.list[i].isCalibrated = false; + + LOG_DEBUG(GwLog::LOG, "stored calibration data: %s, offset: %f, slope: %f", calibrationData.list[i].instance.c_str(), calibrationData.list[i].offset, calibrationData.list[i].slope); + } +} + +int CalibrationDataList::getInstanceListNo(String instance) +// Function to get the index of the requested instance in the list +{ + + // Check if instance is in the list + for (int i = 0; i < maxCalibrationData; i++) { + if (calibrationData.list[i].instance == instance) { + return i; + } + } + return -1; // instance not found +} + +/* void CalibrationDataList::updateBoatDataValidity(String instance) +{ + for (int i = 0; i < maxCalibrationData; i++) { + if (calibrationData.list[i].instance == instance) { + // test for boat data value validity - to be implemented + calibrationData.list[i].isValid = true; + return; + } + } +} */ + +void CalibrationDataList::calibrateInstance(String instance, GwApi::BoatValue* boatDataValue, GwLog* logger) +// Function to calibrate the boat data value +{ + double offset = 0; + double slope = 1.0; + + int listNo = getInstanceListNo(instance); + if (listNo >= 0) { + offset = calibrationData.list[listNo].offset; + slope = calibrationData.list[listNo].slope; + + if (!boatDataValue->valid) { // no valid boat data value, so we don't want to apply calibration data + return; + } else { + boatDataValue->value = (boatDataValue->value * slope) + offset; + calibrationData.list[listNo].value = boatDataValue->value; + calibrationData.list[listNo].isCalibrated = true; + LOG_DEBUG(GwLog::LOG, "BoatDataCalibration: %s: Offset: %f Slope: %f Result: %f", instance.c_str(), offset, slope, boatDataValue->value); + + } + } else { + LOG_DEBUG(GwLog::LOG, "BoatDataCalibration: %s not found in calibration data list", instance.c_str()); + } +} + +#endif \ No newline at end of file diff --git a/lib/obp60task/BoatDataCalibration.h b/lib/obp60task/BoatDataCalibration.h new file mode 100644 index 0000000..61db4db --- /dev/null +++ b/lib/obp60task/BoatDataCalibration.h @@ -0,0 +1,33 @@ +// Functions lib for data instance calibration + +#ifndef _BOATDATACALIBRATION_H +#define _BOATDATACALIBRATION_H + +#include "Pagedata.h" +#include "WString.h" + +typedef struct { + String instance; // data type/instance to be calibrated + double offset; // calibration offset + double slope; // calibration slope + double value; // calibrated data value + bool isCalibrated; // is data instance value calibrated? +} CalibData; + +const int maxCalibrationData = 3; // maximum number of calibration data instances + +class CalibrationDataList { +public: + CalibData list[maxCalibrationData]; // list of calibration data instances + + static void readConfig(GwConfigHandler* config, GwLog* logger); + static int getInstanceListNo(String instance); + static void calibrateInstance(String instance, GwApi::BoatValue* boatDataValue, GwLog* logger); + +private: +// GwLog* logger; +}; + +extern CalibrationDataList calibrationData; // this list holds all calibration data + +#endif \ No newline at end of file diff --git a/lib/obp60task/PageFourValues.cpp b/lib/obp60task/PageFourValues.cpp index e8e1024..fa0d61b 100644 --- a/lib/obp60task/PageFourValues.cpp +++ b/lib/obp60task/PageFourValues.cpp @@ -2,6 +2,7 @@ #include "Pagedata.h" #include "OBP60Extensions.h" +#include "BoatDataCalibration.h" class PageFourValues : public Page { @@ -47,6 +48,7 @@ class PageFourValues : public Page name1 = name1.substring(0, 6); // String length limit for value name double value1 = bvalue1->value; // Value as double in SI unit bool valid1 = bvalue1->valid; // Valid information + CalibrationDataList::calibrateInstance(name1, bvalue1, logger); // Check if boat data value is to be calibrated String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value @@ -56,6 +58,7 @@ class PageFourValues : public Page name2 = name2.substring(0, 6); // String length limit for value name double value2 = bvalue2->value; // Value as double in SI unit bool valid2 = bvalue2->valid; // Valid information + CalibrationDataList::calibrateInstance(name2, bvalue2, logger); // Check if boat data value is to be calibrated String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value @@ -65,6 +68,7 @@ class PageFourValues : public Page name3 = name3.substring(0, 6); // String length limit for value name double value3 = bvalue3->value; // Value as double in SI unit bool valid3 = bvalue3->valid; // Valid information + CalibrationDataList::calibrateInstance(name3, bvalue3, logger); // Check if boat data value is to be calibrated String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String unit3 = formatValue(bvalue3, *commonData).unit; // Unit of value @@ -74,6 +78,7 @@ class PageFourValues : public Page name4 = name4.substring(0, 6); // String length limit for value name double value4 = bvalue4->value; // Value as double in SI unit bool valid4 = bvalue4->valid; // Valid information + CalibrationDataList::calibrateInstance(name4, bvalue4, logger); // Check if boat data value is to be calibrated String svalue4 = formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String unit4 = formatValue(bvalue4, *commonData).unit; // Unit of value diff --git a/lib/obp60task/PageFourValues2.cpp b/lib/obp60task/PageFourValues2.cpp index 61a5f6f..3e84611 100644 --- a/lib/obp60task/PageFourValues2.cpp +++ b/lib/obp60task/PageFourValues2.cpp @@ -2,6 +2,7 @@ #include "Pagedata.h" #include "OBP60Extensions.h" +#include "BoatDataCalibration.h" class PageFourValues2 : public Page { @@ -47,6 +48,7 @@ class PageFourValues2 : public Page name1 = name1.substring(0, 6); // String length limit for value name double value1 = bvalue1->value; // Value as double in SI unit bool valid1 = bvalue1->valid; // Valid information + CalibrationDataList::calibrateInstance(name1, bvalue1, logger); // Check if boat data value is to be calibrated String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value @@ -56,6 +58,7 @@ class PageFourValues2 : public Page name2 = name2.substring(0, 6); // String length limit for value name double value2 = bvalue2->value; // Value as double in SI unit bool valid2 = bvalue2->valid; // Valid information + CalibrationDataList::calibrateInstance(name2, bvalue2, logger); // Check if boat data value is to be calibrated String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value @@ -65,6 +68,7 @@ class PageFourValues2 : public Page name3 = name3.substring(0, 6); // String length limit for value name double value3 = bvalue3->value; // Value as double in SI unit bool valid3 = bvalue3->valid; // Valid information + CalibrationDataList::calibrateInstance(name3, bvalue3, logger); // Check if boat data value is to be calibrated String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String unit3 = formatValue(bvalue3, *commonData).unit; // Unit of value @@ -74,6 +78,7 @@ class PageFourValues2 : public Page name4 = name4.substring(0, 6); // String length limit for value name double value4 = bvalue4->value; // Value as double in SI unit bool valid4 = bvalue4->valid; // Valid information + CalibrationDataList::calibrateInstance(name4, bvalue4, logger); // Check if boat data value is to be calibrated String svalue4 = formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String unit4 = formatValue(bvalue4, *commonData).unit; // Unit of value diff --git a/lib/obp60task/PageOneValue.cpp b/lib/obp60task/PageOneValue.cpp index 0d2a879..e839e79 100644 --- a/lib/obp60task/PageOneValue.cpp +++ b/lib/obp60task/PageOneValue.cpp @@ -2,6 +2,7 @@ #include "Pagedata.h" #include "OBP60Extensions.h" +#include "BoatDataCalibration.h" class PageOneValue : public Page { @@ -41,6 +42,7 @@ class PageOneValue : public Page name1 = name1.substring(0, 6); // String length limit for value name double value1 = bvalue1->value; // Value as double in SI unit bool valid1 = bvalue1->valid; // Valid information + CalibrationDataList::calibrateInstance(name1, bvalue1, logger); // Check if boat data value is to be calibrated String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value diff --git a/lib/obp60task/PageThreeValues.cpp b/lib/obp60task/PageThreeValues.cpp index 71e1df1..c4b9702 100644 --- a/lib/obp60task/PageThreeValues.cpp +++ b/lib/obp60task/PageThreeValues.cpp @@ -2,6 +2,7 @@ #include "Pagedata.h" #include "OBP60Extensions.h" +#include "BoatDataCalibration.h" class PageThreeValues : public Page { @@ -45,6 +46,7 @@ class PageThreeValues : public Page name1 = name1.substring(0, 6); // String length limit for value name double value1 = bvalue1->value; // Value as double in SI unit bool valid1 = bvalue1->valid; // Valid information + CalibrationDataList::calibrateInstance(name1, bvalue1, logger); // Check if boat data value is to be calibrated String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value @@ -54,6 +56,7 @@ class PageThreeValues : public Page name2 = name2.substring(0, 6); // String length limit for value name double value2 = bvalue2->value; // Value as double in SI unit bool valid2 = bvalue2->valid; // Valid information + CalibrationDataList::calibrateInstance(name2, bvalue2, logger); // Check if boat data value is to be calibrated String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value @@ -63,6 +66,7 @@ class PageThreeValues : public Page name3 = name3.substring(0, 6); // String length limit for value name double value3 = bvalue3->value; // Value as double in SI unit bool valid3 = bvalue3->valid; // Valid information + CalibrationDataList::calibrateInstance(name3, bvalue3, logger); // Check if boat data value is to be calibrated String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String unit3 = formatValue(bvalue3, *commonData).unit; // Unit of value diff --git a/lib/obp60task/PageTwoValues.cpp b/lib/obp60task/PageTwoValues.cpp index 673ab8f..481b6ba 100644 --- a/lib/obp60task/PageTwoValues.cpp +++ b/lib/obp60task/PageTwoValues.cpp @@ -2,6 +2,7 @@ #include "Pagedata.h" #include "OBP60Extensions.h" +#include "BoatDataCalibration.h" class PageTwoValues : public Page { @@ -43,6 +44,7 @@ class PageTwoValues : public Page name1 = name1.substring(0, 6); // String length limit for value name double value1 = bvalue1->value; // Value as double in SI unit bool valid1 = bvalue1->valid; // Valid information + CalibrationDataList::calibrateInstance(name1, bvalue1, logger); // Check if boat data value is to be calibrated String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value @@ -52,6 +54,7 @@ class PageTwoValues : public Page name2 = name2.substring(0, 6); // String length limit for value name double value2 = bvalue2->value; // Value as double in SI unit bool valid2 = bvalue2->valid; // Valid information + CalibrationDataList::calibrateInstance(name2, bvalue2, logger); // Check if boat data value is to be calibrated String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value diff --git a/lib/obp60task/config.json b/lib/obp60task/config.json index a4233ae..60c627a 100644 --- a/lib/obp60task/config.json +++ b/lib/obp60task/config.json @@ -219,6 +219,17 @@ "obp60":"true" } }, + { + "name": "calOffsetDBT", + "label": "Offset DBT", + "type": "number", + "default": "0.00", + "description": "Offset for depth transducer; positive for depth from surface, negative for depth below keel", + "category": "OBP60 Settings", + "capabilities": { + "obp60":"true" + } + }, { "name": "lengthFormat", "label": "Length Format", @@ -687,6 +698,86 @@ } }, { + "name": "calInstance1", + "label": "Calibration Data Instance 1", + "type": "list", + "default": "", + "description": "Data instance for calibration", + "list": [ + "AWA", + "AWS", + "HDM", + "STW", + "WTemp" + ], + "category": "OBP60 Calibrations", + "capabilities": { + "obp60":"true" + } + }, + { + "name": "calOffset1", + "label": "Calibration Data Instance 1 Offset", + "type": "number", + "default": "0.00", + "description": "Offset for data instance 1", + "category": "OBP60 Calibrations", + "capabilities": { + "obp60":"true" + } + }, + { + "name": "calSlope1", + "label": "Calibration Data Instance 1 Slope", + "type": "number", + "default": "1.00", + "description": "Slope for data instance 1", + "category": "OBP60 Calibrations", + "capabilities": { + "obp60":"true" + } + }, + { + "name": "calInstance2", + "label": "Calibration Data Instance 2", + "type": "list", + "default": "", + "description": "Data instance for calibration", + "list": [ + "AWA", + "AWS", + "HDM", + "STW", + "WTemp" + ], + "category": "OBP60 Calibrations", + "capabilities": { + "obp60":"true" + } + }, + { + "name": "calOffset2", + "label": "Calibration Data Instance 2 Offset", + "type": "number", + "default": "0.00", + "description": "Offset for data instance 2", + "category": "OBP60 Calibrations", + "capabilities": { + "obp60":"true" + } + }, + { + "name": "calSlope2", + "label": "Calibration Data Instance 2 Slope", + "type": "number", + "default": "1.00", + "description": "Slope for data instance 2", + "category": "OBP60 Calibrations", + "capabilities": { + "obp60":"true" + } + }, +{ "name": "display", "label": "Display Mode", "type": "list", diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp index 6073f9f..a84f247 100644 --- a/lib/obp60task/obp60task.cpp +++ b/lib/obp60task/obp60task.cpp @@ -12,6 +12,7 @@ #include // GxEPD2 lib for b/w E-Ink displays #include "OBP60Extensions.h" // Functions lib for extension board #include "OBP60Keypad.h" // Functions for keypad +#include "BoatDataCalibration.h" // Functions lib for data instance calibration #ifdef BOARD_OBP40S3 #include "driver/rtc_io.h" // Needs for weakup from deep sleep @@ -385,6 +386,10 @@ void OBP60Task(GwApi *api){ commonData.logger=logger; commonData.config=config; + // Read all calibration data settings from config + CalibrationDataList::readConfig(config, logger); + LOG_DEBUG(GwLog::LOG,"Calibration data read from config"); + #ifdef HARDWARE_V21 // Keyboard coordinates for page footer initKeys(commonData);