Compare commits
No commits in common. "d1c620a85839b2f104f99ae5a7cb74adf3d99081" and "c5a1244519d4724e4854e96c369b5af2dd1e49ec" have entirely different histories.
d1c620a858
...
c5a1244519
10
Readme.md
10
Readme.md
|
@ -68,12 +68,12 @@ Initial Flash
|
|||
__Browser__
|
||||
|
||||
If you run a system with a modern Chrome or Edge Browser you can directly flash your device from within the browser.
|
||||
Just go to the [Flash Page](https://wellenvogel.de/software/esp32/install.html) and select the "Initial" flash for your Hardware. This will install the most current software to your device. If you are using a forked project (like OBP60) refer to the documentation of the fork. You can just install any flash binary from your local computer with the browser based installation using the "upload" button.<br>
|
||||
Just go to the [Flash Page](https://wellenvogel.github.io/esp32-nmea2000/install.html) and select the "Initial" flash for your Hardware. This will install the most current software to your device.
|
||||
If you are on Windows you will need to have the correct driver installed before (see below at [windows users](#windows) - only install the driver, not the flashtool).
|
||||
|
||||
You can also install an update from the flash page but normally it is easier to do this from the Web Gui of the device (see [below](#update)).
|
||||
|
||||
The [Flash Page](https://wellenvogel.de/software/esp32/install.html) will also allow you to open a console window to your ESP32.
|
||||
The [Flash Page](https://wellenvogel.github.io/esp32-nmea2000/install.html) will also allow you to open a console window to your ESP32.
|
||||
|
||||
__Tool based__
|
||||
|
||||
|
@ -170,12 +170,6 @@ For details refer to the [example description](lib/exampletask/Readme.md).
|
|||
|
||||
Changelog
|
||||
---------
|
||||
[20250305](../../releases/tag/20250305)
|
||||
*********
|
||||
* better handling for reconnect to a raspberry pi after reset [#102](../../issues/102)
|
||||
* introduce _custom_config_, _custom_js_, _custom_css_, refer to [extending the core](lib/exampletask/Readme.md) [#100](../../pull/100)
|
||||
* create VWR [#103](../../issues/103)
|
||||
|
||||
[20241128](../../releases/tag/20241128)
|
||||
*********
|
||||
* additional correction for: USB connection on S3 stops [#81](../../issues/81)
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -14,7 +14,7 @@ Files
|
|||
* [platformio.ini](platformio.ini)<br>
|
||||
This file is completely optional.
|
||||
You only need this if you want to
|
||||
extend the base configuration - we add a dummy library here and define additional build environments (boards)
|
||||
extend the base configuration - we add a dummy library here and define one additional build environment (board)
|
||||
* [GwExampleTask.h](GwExampleTask.h) the name of this include must match the name of the directory (ignoring case) with a "gw" in front. This file includes our special hardware definitions and registers our task at the core.<br>
|
||||
This registration can be done statically using [DECLARE_USERTASK](https://github.com/wellenvogel/esp32-nmea2000/blob/9b955d135d74937a60f2926e8bfb9395585ff8cd/lib/api/GwApi.h#L202) in the header file. <br>
|
||||
As an alternative we just only register an [initialization function](https://github.com/wellenvogel/esp32-nmea2000/blob/9b955d135d74937a60f2926e8bfb9395585ff8cd/lib/exampletask/GwExampleTask.h#L19) using DECLARE_INITFUNCTION and later on register the task function itself via the [API](https://github.com/wellenvogel/esp32-nmea2000/blob/9b955d135d74937a60f2926e8bfb9395585ff8cd/lib/exampletask/GwExampleTask.cpp#L32).<br>
|
||||
|
@ -28,13 +28,11 @@ Files
|
|||
|
||||
* [GwExampleTaks.cpp](GwExampleTask.cpp) includes the implementation of our task. This tasks runs in an own thread - see the comments in the code.
|
||||
We can have as many cpp (and header files) as we need to structure our code.
|
||||
* [config.json](exampleConfig.json)<br>
|
||||
* [config.json](config.json)<br>
|
||||
This file allows to add some config definitions that are needed for our task. For the possible options have a look at the global [config.json](../../web/config.json). Be careful not to overwrite config defitions from the global file. A good practice wood be to prefix the names of definitions with parts of the library name. Always put them in a separate category so that they do not interfere with the system ones.
|
||||
The defined config items can later be accessed in the code (see the example in [GwExampleTask.cpp](GwExampleTask.cpp)).<br>
|
||||
|
||||
Starting from Version 20250305 you should normally not use this file name any more as those configs would be added for all build environments. Instead define a parameter _custom_config_ in your [platformio.ini](platformio.ini) for the environments you would like to add some configurations for. This parameter accepts a list of file names (relative to the project root, separated by ,).
|
||||
The defined config items can later be accessed in the code (see the example in [GwExampleTask.cpp](GwExampleTask.cpp)).
|
||||
|
||||
* [index.js](example.js)<br>
|
||||
* [index.js](index.js)<br>
|
||||
You can add javascript code that will contribute to the UI of the system. The WebUI provides a small API that allows you to "hook" into some functions to include your own parts of the UI. This includes adding new tabs, modifying/replacing the data display items, modifying the status display or accessing the config items.
|
||||
For the API refer to [../../web/index.js](../../web/index.js#L2001).
|
||||
To start interacting just register for some events like api.EVENTS.init. You can check the capabilities you have defined to see if your task is active.
|
||||
|
@ -48,14 +46,10 @@ Files
|
|||
tools/testServer.py nnn http://x.x.x.x/api
|
||||
```
|
||||
with nnn being the local port and x.x.x.x the address of a running system. Open `http://localhost:nnn` in your browser.<br>
|
||||
After a change just start the compilation and reload the page.<br>
|
||||
|
||||
Starting from Version 20250305 you should normally not use this file name any more as those js code would be added for all build environments. Instead define a parameter _custom_js_ in your [platformio.ini](platformio.ini) for the environments you would like to add the js code for. This parameter accepts a list of file names (relative to the project root, separated by ,). This will also allow you to skip the check for capabilities in your code.
|
||||
After a change just start the compilation and reload the page.
|
||||
|
||||
* [index.css](index.css)<br>
|
||||
You can add own css to influence the styling of the display.<br>
|
||||
|
||||
Starting from Version 20250305 you should normally not use this file name any more as those styles would be added for all build environments. Instead define a parameter _custom_css_ in your [platformio.ini](platformio.ini) for the environments you would like to add some styles for. This parameter accepts a list of file names (relative to the project root, separated by , or as multi line entry)
|
||||
You can add own css to influence the styling of the display.
|
||||
|
||||
|
||||
Interfaces
|
||||
|
|
|
@ -10,9 +10,5 @@ lib_deps =
|
|||
build_flags=
|
||||
-D BOARD_TEST
|
||||
${env.build_flags}
|
||||
custom_config=
|
||||
lib/exampletask/exampleConfig.json
|
||||
custom_js=lib/exampletask/example.js
|
||||
custom_css=lib/exampletask/example.css
|
||||
upload_port = /dev/esp32
|
||||
upload_protocol = esptool
|
|
@ -351,8 +351,8 @@ private:
|
|||
rmb.vmg
|
||||
);
|
||||
send(n2kMsg,msg.sourceId);
|
||||
SetN2kRouteWPInfo(n2kMsg,sourceId,1,1,N2kdir_forward,"default");
|
||||
AppendN2kRouteWPInfo(n2kMsg,destinationId,rmb.destID,rmb.latitude,rmb.longitude);
|
||||
SetN2kPGN129285(n2kMsg,sourceId,1,1,true,true,"default");
|
||||
AppendN2kPGN129285(n2kMsg,destinationId,rmb.destID,rmb.latitude,rmb.longitude);
|
||||
send(n2kMsg,msg.sourceId);
|
||||
}
|
||||
}
|
||||
|
@ -638,8 +638,8 @@ private:
|
|||
for (int i=0;i< 3;i++){
|
||||
if (msg.FieldLen(0)>0){
|
||||
Depth=atof(msg.Field(0));
|
||||
char du=msg.Field(i+1)[0];
|
||||
switch(du){
|
||||
char dt=msg.Field(i+1)[0];
|
||||
switch(dt){
|
||||
case 'f':
|
||||
Depth=Depth/mToFeet;
|
||||
break;
|
||||
|
@ -662,9 +662,8 @@ private:
|
|||
//we can only send if we have a valid depth beloww tranducer
|
||||
//to compute the offset
|
||||
if (! boatData->DBT->isValid()) return;
|
||||
double dbt=boatData->DBT->getData();
|
||||
double offset=Depth-dbt;
|
||||
if (offset >= 0 && dt == DBK){
|
||||
double offset=Depth-boatData->DBT->getData();
|
||||
if (offset >= 0 && dt == DBT){
|
||||
logger->logDebug(GwLog::DEBUG, "strange DBK - more depth then transducer %s", msg.line);
|
||||
return;
|
||||
}
|
||||
|
@ -676,8 +675,8 @@ private:
|
|||
if (! boatData->DBS->update(Depth,msg.sourceId)) return;
|
||||
}
|
||||
tN2kMsg n2kMsg;
|
||||
SetN2kWaterDepth(n2kMsg,1,dbt,offset); //on the N2K side we always have depth below transducer
|
||||
send(n2kMsg,msg.sourceId,(n2kMsg.PGN)+String((offset >=0)?1:0));
|
||||
SetN2kWaterDepth(n2kMsg,1,Depth,offset);
|
||||
send(n2kMsg,msg.sourceId,(n2kMsg.PGN)+String((offset != N2kDoubleNA)?1:0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -267,29 +267,21 @@ private:
|
|||
double DepthBelowTransducer;
|
||||
double Offset;
|
||||
double Range;
|
||||
double WaterDepth;
|
||||
if (ParseN2kWaterDepth(N2kMsg, SID, DepthBelowTransducer, Offset, Range))
|
||||
{
|
||||
if (updateDouble(boatData->DBT, DepthBelowTransducer))
|
||||
|
||||
WaterDepth = DepthBelowTransducer + Offset;
|
||||
updateDouble(boatData->DBS, WaterDepth);
|
||||
updateDouble(boatData->DBT,DepthBelowTransducer);
|
||||
tNMEA0183Msg NMEA0183Msg;
|
||||
if (NMEA0183SetDPT(NMEA0183Msg, DepthBelowTransducer, Offset,talkerId))
|
||||
{
|
||||
tNMEA0183Msg NMEA0183Msg;
|
||||
bool offsetValid=true;
|
||||
if (N2kIsNA(Offset)) {
|
||||
Offset=NMEA0183DoubleNA;
|
||||
offsetValid=false;
|
||||
}
|
||||
if (NMEA0183SetDPT(NMEA0183Msg, DepthBelowTransducer, Offset, talkerId))
|
||||
{
|
||||
SendMessage(NMEA0183Msg);
|
||||
}
|
||||
if (offsetValid)
|
||||
{
|
||||
double WaterDepth = DepthBelowTransducer + Offset;
|
||||
updateDouble(boatData->DBS, WaterDepth);
|
||||
}
|
||||
if (NMEA0183SetDBx(NMEA0183Msg, DepthBelowTransducer, Offset, talkerId))
|
||||
{
|
||||
SendMessage(NMEA0183Msg);
|
||||
}
|
||||
SendMessage(NMEA0183Msg);
|
||||
}
|
||||
if (NMEA0183SetDBx(NMEA0183Msg, DepthBelowTransducer, Offset,talkerId))
|
||||
{
|
||||
SendMessage(NMEA0183Msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,13 +6,12 @@
|
|||
#include <unordered_map>
|
||||
|
||||
CalibrationDataList calibrationData;
|
||||
std::unordered_map<std::string, TypeCalibData> CalibrationDataList::calibMap; // list of calibration data instances
|
||||
|
||||
void CalibrationDataList::readConfig(GwConfigHandler* config, GwLog* logger)
|
||||
// Initial load of calibration data into internal list
|
||||
// This method is called once at init phase of <obp60task> to read the configuration values
|
||||
// This method is called once at init phase of <OBP60task> to read the configuration values
|
||||
{
|
||||
std::string instance;
|
||||
String instance;
|
||||
double offset;
|
||||
double slope;
|
||||
double smooth;
|
||||
|
@ -30,21 +29,21 @@ void CalibrationDataList::readConfig(GwConfigHandler* config, GwLog* logger)
|
|||
String tempFormat = config->getString(config->tempFormat); // [K|C|F]
|
||||
|
||||
// Read calibration settings for data instances
|
||||
for (int i = 0; i < MAX_CALIBRATION_DATA; i++) {
|
||||
for (int i = 0; i < maxCalibrationData; i++) {
|
||||
calInstance = "calInstance" + String(i + 1);
|
||||
calOffset = "calOffset" + String(i + 1);
|
||||
calSlope = "calSlope" + String(i + 1);
|
||||
calSmooth = "calSmooth" + String(i + 1);
|
||||
calibrationData.list[i] = { "---", 0.0f, 1.0f, 1, 0.0f, false };
|
||||
|
||||
instance = std::string(config->getString(calInstance, "---").c_str());
|
||||
instance = config->getString(calInstance, "---");
|
||||
if (instance == "---") {
|
||||
LOG_DEBUG(GwLog::LOG, "no calibration data for instance no. %d", i + 1);
|
||||
continue;
|
||||
}
|
||||
calibMap[instance] = { 0.0f, 1.0f, 1.0f, 0.0f, false };
|
||||
offset = (config->getString(calOffset, "")).toFloat();
|
||||
slope = (config->getString(calSlope, "")).toFloat();
|
||||
smooth = (config->getString(calSmooth, "")).toInt(); // user input is int; further math is done with double
|
||||
smooth = (config->getString(calSmooth, "")).toInt();
|
||||
|
||||
// Convert calibration values to internal standard formats
|
||||
if (instance == "AWS" || instance == "TWS") {
|
||||
|
@ -55,10 +54,10 @@ void CalibrationDataList::readConfig(GwConfigHandler* config, GwLog* logger)
|
|||
} else if (windspeedFormat == "kn") {
|
||||
offset /= 1.94384; // Convert kn to m/s
|
||||
} else if (windspeedFormat == "bft") {
|
||||
offset *= 2 + (offset / 2); // Convert Bft to m/s (approx) -> to be improved
|
||||
offset *= 0.5; // Convert Bft to m/s (approx) -> to be improved
|
||||
}
|
||||
|
||||
} else if (instance == "AWA" || instance == "COG" || instance == "TWA" || instance == "TWD" || instance == "HDM" || instance == "PRPOS" || instance == "RPOS") {
|
||||
} else if (instance == "AWA" || instance == "TWA" || instance == "TWD" || instance == "HDM" || instance == "PRPOS" || instance == "RPOS") {
|
||||
offset *= M_PI / 180; // Convert deg to rad
|
||||
|
||||
} else if (instance == "DBT") {
|
||||
|
@ -68,7 +67,7 @@ void CalibrationDataList::readConfig(GwConfigHandler* config, GwLog* logger)
|
|||
offset /= 3.28084; // Convert ft to m
|
||||
}
|
||||
|
||||
} else if (instance == "SOG" || instance == "STW") {
|
||||
} else if (instance == "STW") {
|
||||
if (speedFormat == "m/s") {
|
||||
// No conversion needed
|
||||
} else if (speedFormat == "km/h") {
|
||||
|
@ -93,100 +92,112 @@ void CalibrationDataList::readConfig(GwConfigHandler* config, GwLog* logger)
|
|||
if (smooth > 10) {
|
||||
smooth = 10;
|
||||
}
|
||||
// calibrationData.list[i].smooth = 1 - (smooth / 10.0); // smooth factor is between 0 and 1
|
||||
smooth = 0.3 + ((smooth - 0.01) * (0.95 - 0.3) / (10 - 0.01));
|
||||
}
|
||||
smooth = 1 - smooth;
|
||||
|
||||
calibMap[instance].offset = offset;
|
||||
calibMap[instance].slope = slope;
|
||||
calibMap[instance].smooth = smooth;
|
||||
calibMap[instance].isCalibrated = false;
|
||||
LOG_DEBUG(GwLog::LOG, "stored calibration data: %s, offset: %f, slope: %f, smoothing: %f", instance.c_str(),
|
||||
calibMap[instance].offset, calibMap[instance].slope, calibMap[instance].smooth);
|
||||
calibrationData.list[i].instance = instance;
|
||||
calibrationData.list[i].offset = offset;
|
||||
calibrationData.list[i].slope = slope;
|
||||
calibrationData.list[i].smooth = smooth;
|
||||
calibrationData.list[i].isCalibrated = false;
|
||||
LOG_DEBUG(GwLog::LOG, "stored calibration data: %s, offset: %f, slope: %f, smoothing: %f", calibrationData.list[i].instance.c_str(),
|
||||
calibrationData.list[i].offset, calibrationData.list[i].slope, calibrationData.list[i].smooth);
|
||||
}
|
||||
LOG_DEBUG(GwLog::LOG, "all calibration data read");
|
||||
}
|
||||
|
||||
void CalibrationDataList::calibrateInstance(GwApi::BoatValue* boatDataValue, GwLog* logger)
|
||||
int CalibrationDataList::getInstanceListNo(String instance)
|
||||
// Method 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)
|
||||
// Method to calibrate the boat data value
|
||||
{
|
||||
std::string instance = boatDataValue->getName().c_str();
|
||||
double offset = 0;
|
||||
double slope = 1.0;
|
||||
double dataValue = 0;
|
||||
std::string format = "";
|
||||
|
||||
if (calibMap.find(instance) == calibMap.end()) {
|
||||
int listNo = getInstanceListNo(instance);
|
||||
if (listNo < 0) {
|
||||
LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s not found in calibration data list", instance.c_str());
|
||||
return;
|
||||
} else if (!boatDataValue->valid) { // no valid boat data value, so we don't want to apply calibration data
|
||||
calibMap[instance].isCalibrated = false;
|
||||
return;
|
||||
} else {
|
||||
offset = calibMap[instance].offset;
|
||||
slope = calibMap[instance].slope;
|
||||
dataValue = boatDataValue->value;
|
||||
format = boatDataValue->getFormat().c_str();
|
||||
LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s: value: %f, format: %s", instance.c_str(), dataValue, format.c_str());
|
||||
offset = calibrationData.list[listNo].offset;
|
||||
slope = calibrationData.list[listNo].slope;
|
||||
|
||||
if (format == "formatWind") { // instance is of type angle
|
||||
dataValue = (dataValue * slope) + offset;
|
||||
dataValue = fmod(dataValue, 2 * M_PI);
|
||||
if (dataValue > (M_PI)) {
|
||||
dataValue -= (2 * M_PI);
|
||||
} else if (dataValue < (M_PI * -1)) {
|
||||
dataValue += (2 * M_PI);
|
||||
}
|
||||
} else if (format == "formatCourse") { // instance is of type direction
|
||||
dataValue = (dataValue * slope) + offset;
|
||||
dataValue = fmod(dataValue, 2 * M_PI);
|
||||
if (dataValue < 0) {
|
||||
dataValue += (2 * M_PI);
|
||||
}
|
||||
} else if (format == "kelvinToC") { // instance is of type temperature
|
||||
dataValue = ((dataValue - 273.15) * slope) + offset + 273.15;
|
||||
if (!boatDataValue->valid) { // no valid boat data value, so we don't want to apply calibration data
|
||||
return;
|
||||
} else {
|
||||
dataValue = boatDataValue->value;
|
||||
LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s: value: %f, format: %s", boatDataValue->getName().c_str(), boatDataValue->value, boatDataValue->getFormat().c_str());
|
||||
|
||||
dataValue = (dataValue * slope) + offset;
|
||||
if (boatDataValue->getFormat() == "formatWind") { // instance is of type angle
|
||||
dataValue = (dataValue * slope) + offset;
|
||||
dataValue = fmod(dataValue, 2 * M_PI);
|
||||
if (dataValue > (M_PI)) {
|
||||
dataValue -= (2 * M_PI);
|
||||
} else if (dataValue < (M_PI * -1)) {
|
||||
dataValue += (2 * M_PI);
|
||||
}
|
||||
} else if (boatDataValue->getFormat() == "formatCourse") { // instance is of type direction
|
||||
dataValue = (dataValue * slope) + offset;
|
||||
dataValue = fmod(dataValue, 2 * M_PI);
|
||||
if (dataValue < 0) {
|
||||
dataValue += (2 * M_PI);
|
||||
}
|
||||
} else if (boatDataValue->getFormat() == "kelvinToC") { // instance is of type temperature
|
||||
dataValue = ((dataValue - 273.15) * slope) + offset + 273.15;
|
||||
} else {
|
||||
dataValue = (dataValue * slope) + offset;
|
||||
}
|
||||
|
||||
calibrationData.smoothInstance(instance, dataValue, logger); // smooth the boat data value
|
||||
calibrationData.list[listNo].value = dataValue;
|
||||
calibrationData.list[listNo].isCalibrated = true;
|
||||
boatDataValue->value = dataValue;
|
||||
LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s: Offset: %f, Slope: %f, Result: %f", instance.c_str(), offset, slope, boatDataValue->value);
|
||||
}
|
||||
|
||||
calibMap[instance].isCalibrated = true;
|
||||
boatDataValue->value = dataValue;
|
||||
|
||||
calibrationData.smoothInstance(boatDataValue, logger); // smooth the boat data value
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void CalibrationDataList::smoothInstance(GwApi::BoatValue* boatDataValue, GwLog* logger)
|
||||
void CalibrationDataList::smoothInstance(String instance, double& dataValue, GwLog* logger)
|
||||
// Method to smoothen the boat data value
|
||||
{
|
||||
static std::unordered_map<std::string, double> lastValue; // array for last values of smoothed boat data values
|
||||
// array for last values of smoothed boat data values
|
||||
static std::unordered_map<std::string, double> lastValue;
|
||||
|
||||
std::string instance = boatDataValue->getName().c_str();
|
||||
double oldValue = 0;
|
||||
double dataValue = boatDataValue->value;
|
||||
double smoothFactor = 0;
|
||||
double smoothFactor = calibrationData.list[getInstanceListNo(instance)].smooth;
|
||||
|
||||
if (!boatDataValue->valid) { // no valid boat data value, so we don't want to smoothen value
|
||||
return;
|
||||
} 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());
|
||||
return;
|
||||
} else {
|
||||
smoothFactor = calibMap[instance].smooth;
|
||||
if (lastValue.find(instance.c_str()) != lastValue.end()) {
|
||||
oldValue = lastValue[instance.c_str()];
|
||||
|
||||
if (lastValue.find(instance) != lastValue.end()) {
|
||||
oldValue = lastValue[instance];
|
||||
dataValue = oldValue + (smoothFactor * (dataValue - oldValue)); // exponential smoothing algorithm
|
||||
}
|
||||
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
|
||||
|
||||
LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s: Smoothing factor: %f, Smoothed value: %f", instance.c_str(), smoothFactor, dataValue);
|
||||
dataValue = oldValue + (smoothFactor * (dataValue - oldValue)); // exponential smoothing algorithm
|
||||
}
|
||||
lastValue[instance.c_str()] = dataValue; // store the new value for next cycle; first time, store only the current value and return
|
||||
|
||||
LOG_DEBUG(GwLog::DEBUG, "BoatDataCalibration: %s: Smoothing factor: %f, Smoothed value: %f", instance.c_str(), smoothFactor, dataValue);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -4,26 +4,27 @@
|
|||
#define _BOATDATACALIBRATION_H
|
||||
|
||||
#include "Pagedata.h"
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#define MAX_CALIBRATION_DATA 3 // maximum number of calibration data instances
|
||||
#include "WString.h"
|
||||
|
||||
typedef struct {
|
||||
String instance; // data type/instance to be calibrated
|
||||
double offset; // calibration offset
|
||||
double slope; // calibration slope
|
||||
double smooth; // smoothing factor
|
||||
double value; // calibrated data value
|
||||
bool isCalibrated; // is data instance value calibrated?
|
||||
} TypeCalibData;
|
||||
} CalibData;
|
||||
|
||||
const int maxCalibrationData = 3; // maximum number of calibration data instances
|
||||
|
||||
class CalibrationDataList {
|
||||
public:
|
||||
static std::unordered_map<std::string, TypeCalibData> calibMap; // list of calibration data instances
|
||||
CalibData list[maxCalibrationData]; // list of calibration data instances
|
||||
|
||||
void readConfig(GwConfigHandler* config, GwLog* logger);
|
||||
void calibrateInstance(GwApi::BoatValue* boatDataValue, GwLog* logger);
|
||||
void smoothInstance(GwApi::BoatValue* boatDataValue, GwLog* logger);
|
||||
static void readConfig(GwConfigHandler* config, GwLog* logger);
|
||||
static int getInstanceListNo(String instance);
|
||||
static void calibrateInstance(String instance, GwApi::BoatValue* boatDataValue, GwLog* logger);
|
||||
void smoothInstance(String instance, double &dataValue, GwLog* logger);
|
||||
|
||||
private:
|
||||
};
|
||||
|
|
|
@ -498,12 +498,10 @@ void sensorTask(void *param){
|
|||
// Send supply voltage value all 1s
|
||||
if(millis() > starttime5 + 1000 && String(powsensor1) == "off"){
|
||||
starttime5 = millis();
|
||||
float rawVoltage = 0;
|
||||
#ifdef BOARD_OBP40S3 && VOLTAGE_SENSOR
|
||||
rawVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40
|
||||
#endif
|
||||
#ifdef BOARD_OBP60S3
|
||||
rawVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60
|
||||
#ifdef VOLTAGE_SENSOR
|
||||
float rawVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40
|
||||
#else
|
||||
float rawVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60
|
||||
#endif
|
||||
sensors.batteryVoltage = rawVoltage * vslope + voffset; // Calibration
|
||||
// Save new data in average array
|
||||
|
@ -512,7 +510,7 @@ void sensorTask(void *param){
|
|||
sensors.batteryVoltage10 = batV.getAvg(10) / 100.0;
|
||||
sensors.batteryVoltage60 = batV.getAvg(60) / 100.0;
|
||||
sensors.batteryVoltage300 = batV.getAvg(300) / 100.0;
|
||||
#if BOARD_OBP40S3 && defined LIPO_ACCU_1200 && defined VOLTAGE_SENSOR
|
||||
#if defined LIPO_ACCU_1200 && defined VOLTAGE_SENSOR
|
||||
// Polynomfit for LiPo capacity calculation for 3,7V LiPo accus, 0...100%
|
||||
sensors.batteryLevelLiPo = sensors.batteryVoltage60 * 203.8312 -738.1635;
|
||||
// Limiter
|
||||
|
|
|
@ -1,261 +0,0 @@
|
|||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Extensions.h"
|
||||
|
||||
// these constants have to match the declaration below in :
|
||||
// PageDescription registerPageCompass(
|
||||
// {"COG","HDT", "HDM"}, // Bus values we need in the page
|
||||
const int HowManyValues = 6;
|
||||
|
||||
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 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
|
||||
|
||||
class PageCompass : public Page
|
||||
{
|
||||
int WhichDataCompass = ShowHDM;
|
||||
int WhichDataDisplay = ShowHDM;
|
||||
|
||||
public:
|
||||
PageCompass(CommonData &common){
|
||||
commonData = &common;
|
||||
common.logger->logDebug(GwLog::LOG,"Instantiate PageCompass");
|
||||
}
|
||||
|
||||
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 > ShowDBS)
|
||||
WhichDataDisplay = ShowHDM;
|
||||
}
|
||||
|
||||
if(key == 11){
|
||||
commonData->keylock = !commonData->keylock;
|
||||
return 0; // Commit the key
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
virtual void 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];
|
||||
FormatedData 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 PageCompass: %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;
|
||||
|
||||
//***********************************************************
|
||||
|
||||
// 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_Bold20pt7b);
|
||||
getdisplay().setCursor(10, 70);
|
||||
getdisplay().print(DataName[WhichDataDisplay]); // Page name
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt7b);
|
||||
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_Bold16pt7b);
|
||||
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;
|
||||
|
||||
// Update display
|
||||
getdisplay().nextPage(); // Partial update (fast)
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
static Page *createPage(CommonData &common){
|
||||
return new PageCompass(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 registerPageCompass(
|
||||
"Compass", // Page name
|
||||
createPage, // Action
|
||||
0, // Number of bus values depends on selection in Web configuration
|
||||
{"HDM","HDT", "COG", "STW", "SOG", "DBS"}, // Bus values we need in the page
|
||||
true // Show display header on/off
|
||||
);
|
||||
|
||||
#endif
|
|
@ -46,9 +46,9 @@ class PageFourValues : public Page
|
|||
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
|
||||
String name1 = xdrDelete(bvalue1->getName()); // Value name
|
||||
name1 = name1.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
|
||||
double value1 = bvalue1->value; // Value as double in SI unit
|
||||
bool valid1 = bvalue1->valid; // Valid information
|
||||
calibrationData.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,9 +56,9 @@ class PageFourValues : public Page
|
|||
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
|
||||
String name2 = xdrDelete(bvalue2->getName()); // Value name
|
||||
name2 = name2.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated
|
||||
double value2 = bvalue2->value; // Value as double in SI unit
|
||||
bool valid2 = bvalue2->valid; // Valid information
|
||||
calibrationData.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
|
||||
|
||||
|
@ -66,9 +66,9 @@ class PageFourValues : public Page
|
|||
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
|
||||
String name3 = xdrDelete(bvalue3->getName()); // Value name
|
||||
name3 = name3.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated
|
||||
double value3 = bvalue3->value; // Value as double in SI unit
|
||||
bool valid3 = bvalue3->valid; // Valid information
|
||||
calibrationData.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
|
||||
|
||||
|
@ -76,9 +76,9 @@ class PageFourValues : public Page
|
|||
GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue)
|
||||
String name4 = xdrDelete(bvalue4->getName()); // Value name
|
||||
name4 = name4.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue4, logger); // Check if boat data value is to be calibrated
|
||||
double value4 = bvalue4->value; // Value as double in SI unit
|
||||
bool valid4 = bvalue4->valid; // Valid information
|
||||
calibrationData.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
|
||||
|
||||
|
|
|
@ -46,9 +46,9 @@ class PageFourValues2 : public Page
|
|||
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
|
||||
String name1 = xdrDelete(bvalue1->getName()); // Value name
|
||||
name1 = name1.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
|
||||
double value1 = bvalue1->value; // Value as double in SI unit
|
||||
bool valid1 = bvalue1->valid; // Valid information
|
||||
calibrationData.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,9 +56,9 @@ class PageFourValues2 : public Page
|
|||
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
|
||||
String name2 = xdrDelete(bvalue2->getName()); // Value name
|
||||
name2 = name2.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated
|
||||
double value2 = bvalue2->value; // Value as double in SI unit
|
||||
bool valid2 = bvalue2->valid; // Valid information
|
||||
calibrationData.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
|
||||
|
||||
|
@ -66,9 +66,9 @@ class PageFourValues2 : public Page
|
|||
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
|
||||
String name3 = xdrDelete(bvalue3->getName()); // Value name
|
||||
name3 = name3.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated
|
||||
double value3 = bvalue3->value; // Value as double in SI unit
|
||||
bool valid3 = bvalue3->valid; // Valid information
|
||||
calibrationData.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
|
||||
|
||||
|
@ -76,9 +76,9 @@ class PageFourValues2 : public Page
|
|||
GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue)
|
||||
String name4 = xdrDelete(bvalue4->getName()); // Value name
|
||||
name4 = name4.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue4, logger); // Check if boat data value is to be calibrated
|
||||
double value4 = bvalue4->value; // Value as double in SI unit
|
||||
bool valid4 = bvalue4->valid; // Valid information
|
||||
calibrationData.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
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ class PageOneValue : public Page
|
|||
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
|
||||
String name1 = xdrDelete(bvalue1->getName()); // Value name
|
||||
name1 = name1.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
|
||||
calibrationData.calibrateInstance(name1, bvalue1, logger); // Check if boat data value is to be calibrated
|
||||
double value1 = bvalue1->value; // Value as double in SI unit
|
||||
bool valid1 = bvalue1->valid; // Valid information
|
||||
String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
|
|
|
@ -41,7 +41,7 @@ public:
|
|||
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list
|
||||
String name1 = bvalue1->getName().c_str(); // Value name
|
||||
name1 = name1.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
|
||||
calibrationData.calibrateInstance(name1, bvalue1, logger); // Check if boat data value is to be calibrated
|
||||
value1 = bvalue1->value; // Raw value without unit convertion
|
||||
bool valid1 = bvalue1->valid; // Valid information
|
||||
String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
|
|
|
@ -61,8 +61,8 @@ class PageSixValues : public Page
|
|||
bvalue = pageData.values[i];
|
||||
DataName[i] = xdrDelete(bvalue->getName());
|
||||
DataName[i] = DataName[i].substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue, logger); // Check if boat data value is to be calibrated
|
||||
DataValue[i] = bvalue->value; // Value as double in SI unit
|
||||
calibrationData.calibrateInstance(DataName[i], bvalue, logger); // Check if boat data value is to be calibrated
|
||||
DataValid[i] = bvalue->valid;
|
||||
DataText[i] = formatValue(bvalue, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
DataUnits[i] = formatValue(bvalue, *commonData).unit;
|
||||
|
@ -85,10 +85,9 @@ class PageSixValues : public Page
|
|||
getdisplay().setTextColor(commonData->fgcolor);
|
||||
|
||||
for (int i = 0; i < ( HowManyValues / 2 ); i++){
|
||||
if (i < (HowManyValues / 2) - 1) { // Don't draw horizontal line after last line of values -> standard design
|
||||
// Horizontal line 3 pix
|
||||
getdisplay().fillRect(0, SixValues_y1+(i+1)*SixValues_DeltaY, 400, 3, commonData->fgcolor);
|
||||
}
|
||||
// Horizontal line 3 pix
|
||||
getdisplay().fillRect(0, SixValues_y1+i*SixValues_DeltaY, 400, 3, commonData->fgcolor);
|
||||
|
||||
for (int j = 0; j < 2; j++){
|
||||
int ValueIndex = i * 2 + j;
|
||||
int x0 = SixValues_x1 + j * SixValues_DeltaX;
|
||||
|
@ -152,6 +151,7 @@ class PageSixValues : public Page
|
|||
// Vertical line 3 pix
|
||||
getdisplay().fillRect(SixValues_x1+SixValues_DeltaX-8, SixValues_y1+i*SixValues_DeltaY, 3, SixValues_DeltaY, commonData->fgcolor);
|
||||
}
|
||||
getdisplay().fillRect(0, SixValues_y1+3*SixValues_DeltaY, 400, 3, commonData->fgcolor);
|
||||
|
||||
// Update display
|
||||
getdisplay().nextPage(); // Partial update (fast)
|
||||
|
|
|
@ -44,9 +44,9 @@ class PageThreeValues : public Page
|
|||
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
|
||||
String name1 = xdrDelete(bvalue1->getName()); // Value name
|
||||
name1 = name1.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
|
||||
double value1 = bvalue1->value; // Value as double in SI unit
|
||||
bool valid1 = bvalue1->valid; // Valid information
|
||||
calibrationData.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,9 +54,9 @@ class PageThreeValues : public Page
|
|||
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
|
||||
String name2 = xdrDelete(bvalue2->getName()); // Value name
|
||||
name2 = name2.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated
|
||||
double value2 = bvalue2->value; // Value as double in SI unit
|
||||
bool valid2 = bvalue2->valid; // Valid information
|
||||
calibrationData.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
|
||||
|
||||
|
@ -64,9 +64,9 @@ class PageThreeValues : public Page
|
|||
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
|
||||
String name3 = xdrDelete(bvalue3->getName()); // Value name
|
||||
name3 = name3.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated
|
||||
double value3 = bvalue3->value; // Value as double in SI unit
|
||||
bool valid3 = bvalue3->valid; // Valid information
|
||||
calibrationData.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
|
||||
|
||||
|
|
|
@ -42,9 +42,9 @@ class PageTwoValues : public Page
|
|||
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
|
||||
String name1 = xdrDelete(bvalue1->getName()); // Value name
|
||||
name1 = name1.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
|
||||
double value1 = bvalue1->value; // Value as double in SI unit
|
||||
bool valid1 = bvalue1->valid; // Valid information
|
||||
calibrationData.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,9 +52,9 @@ class PageTwoValues : public Page
|
|||
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
|
||||
String name2 = xdrDelete(bvalue2->getName()); // Value name
|
||||
name2 = name2.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated
|
||||
double value2 = bvalue2->value; // Value as double in SI unit
|
||||
bool valid2 = bvalue2->valid; // Valid information
|
||||
calibrationData.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
|
||||
|
||||
|
|
|
@ -324,7 +324,7 @@ public:
|
|||
}
|
||||
String name1 = bvalue1->getName().c_str(); // Value name
|
||||
name1 = name1.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
|
||||
calibrationData.calibrateInstance(name1, bvalue1, logger); // Check if boat data value is to be calibrated
|
||||
double value1 = bvalue1->value; // Value as double in SI unit
|
||||
// bool valid1 = bvalue1->valid; // Valid information
|
||||
String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
|
@ -338,7 +338,7 @@ public:
|
|||
}
|
||||
String name2 = bvalue2->getName().c_str(); // Value name
|
||||
name2 = name2.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated
|
||||
calibrationData.calibrateInstance(name2, bvalue2, logger); // Check if boat data value is to be calibrated
|
||||
double value2 = bvalue2->value; // Value as double in SI unit
|
||||
// bool valid2 = bvalue2->valid; // Valid information
|
||||
if (simulation) {
|
||||
|
|
|
@ -52,7 +52,7 @@ public:
|
|||
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
|
||||
String name1 = xdrDelete(bvalue1->getName()); // Value name
|
||||
name1 = name1.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
|
||||
calibrationData.calibrateInstance(name1, bvalue1, logger); // Check if boat data value is to be calibrated
|
||||
double value1 = bvalue1->value; // Value as double in SI unit
|
||||
bool valid1 = bvalue1->valid; // Valid information
|
||||
value1 = formatValue(bvalue1, *commonData).value;// Format only nesaccery for simulation data for pointer
|
||||
|
@ -67,7 +67,7 @@ public:
|
|||
GwApi::BoatValue *bvalue2 = pageData.values[1]; // First element in list (only one value by PageOneValue)
|
||||
String name2 = xdrDelete(bvalue2->getName()); // Value name
|
||||
name2 = name2.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated
|
||||
calibrationData.calibrateInstance(name2, bvalue2, logger); // Check if boat data value is to be calibrated
|
||||
double value2 = bvalue2->value; // Value as double in SI unit
|
||||
bool valid2 = bvalue2->valid; // Valid information
|
||||
String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
|
@ -81,7 +81,7 @@ public:
|
|||
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
|
||||
String name3 = xdrDelete(bvalue3->getName()); // Value name
|
||||
name3 = name3.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated
|
||||
calibrationData.calibrateInstance(name3, bvalue3, logger); // Check if boat data value is to be calibrated
|
||||
double value3 = bvalue3->value; // Value as double in SI unit
|
||||
bool valid3 = bvalue3->valid; // Valid information
|
||||
String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
|
@ -95,7 +95,7 @@ public:
|
|||
GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue)
|
||||
String name4 = xdrDelete(bvalue4->getName()); // Value name
|
||||
name4 = name4.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue4, logger); // Check if boat data value is to be calibrated
|
||||
calibrationData.calibrateInstance(name4, bvalue4, logger); // Check if boat data value is to be calibrated
|
||||
double value4 = bvalue4->value; // Value as double in SI unit
|
||||
bool valid4 = bvalue4->valid; // Valid information
|
||||
String svalue4 = formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
|
@ -109,7 +109,7 @@ public:
|
|||
GwApi::BoatValue *bvalue5 = pageData.values[4]; // Second element in list (only one value by PageOneValue)
|
||||
String name5 = xdrDelete(bvalue5->getName()); // Value name
|
||||
name5 = name5.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue5, logger); // Check if boat data value is to be calibrated
|
||||
calibrationData.calibrateInstance(name5, bvalue5, logger); // Check if boat data value is to be calibrated
|
||||
double value5 = bvalue5->value; // Value as double in SI unit
|
||||
bool valid5 = bvalue5->valid; // Valid information
|
||||
String svalue5 = formatValue(bvalue5, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
|
@ -123,7 +123,7 @@ public:
|
|||
GwApi::BoatValue *bvalue6 = pageData.values[5]; // Second element in list (only one value by PageOneValue)
|
||||
String name6 = xdrDelete(bvalue6->getName()); // Value name
|
||||
name6 = name6.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue6, logger); // Check if boat data value is to be calibrated
|
||||
calibrationData.calibrateInstance(name6, bvalue6, logger); // Check if boat data value is to be calibrated
|
||||
double value6 = bvalue6->value; // Value as double in SI unit
|
||||
bool valid6 = bvalue6->valid; // Valid information
|
||||
String svalue6 = formatValue(bvalue6, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
|
|
|
@ -52,7 +52,7 @@ public:
|
|||
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
|
||||
String name1 = xdrDelete(bvalue1->getName()); // Value name
|
||||
name1 = name1.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue1, logger); // Check if boat data value is to be calibrated
|
||||
calibrationData.calibrateInstance(name1, bvalue1, logger); // Check if boat data value is to be calibrated
|
||||
double value1 = bvalue1->value; // Value as double in SI unit
|
||||
bool valid1 = bvalue1->valid; // Valid information
|
||||
value1 = formatValue(bvalue1, *commonData).value;// Format only nesaccery for simulation data for pointer
|
||||
|
@ -67,7 +67,7 @@ public:
|
|||
GwApi::BoatValue *bvalue2 = pageData.values[1]; // First element in list (only one value by PageOneValue)
|
||||
String name2 = xdrDelete(bvalue2->getName()); // Value name
|
||||
name2 = name2.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue2, logger); // Check if boat data value is to be calibrated
|
||||
calibrationData.calibrateInstance(name2, bvalue2, logger); // Check if boat data value is to be calibrated
|
||||
double value2 = bvalue2->value; // Value as double in SI unit
|
||||
bool valid2 = bvalue2->valid; // Valid information
|
||||
String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
|
@ -81,7 +81,7 @@ public:
|
|||
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
|
||||
String name3 = xdrDelete(bvalue3->getName()); // Value name
|
||||
name3 = name3.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue3, logger); // Check if boat data value is to be calibrated
|
||||
calibrationData.calibrateInstance(name3, bvalue3, logger); // Check if boat data value is to be calibrated
|
||||
double value3 = bvalue3->value; // Value as double in SI unit
|
||||
bool valid3 = bvalue3->valid; // Valid information
|
||||
String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
|
@ -95,7 +95,7 @@ public:
|
|||
GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue)
|
||||
String name4 = xdrDelete(bvalue4->getName()); // Value name
|
||||
name4 = name4.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue4, logger); // Check if boat data value is to be calibrated
|
||||
calibrationData.calibrateInstance(name4, bvalue4, logger); // Check if boat data value is to be calibrated
|
||||
double value4 = bvalue4->value; // Value as double in SI unit
|
||||
bool valid4 = bvalue4->valid; // Valid information
|
||||
String svalue4 = formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
|
@ -109,7 +109,7 @@ public:
|
|||
GwApi::BoatValue *bvalue5 = pageData.values[4]; // Second element in list (only one value by PageOneValue)
|
||||
String name5 = xdrDelete(bvalue5->getName()); // Value name
|
||||
name5 = name5.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue5, logger); // Check if boat data value is to be calibrated
|
||||
calibrationData.calibrateInstance(name5, bvalue5, logger); // Check if boat data value is to be calibrated
|
||||
double value5 = bvalue5->value; // Value as double in SI unit
|
||||
bool valid5 = bvalue5->valid; // Valid information
|
||||
String svalue5 = formatValue(bvalue5, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
|
@ -123,7 +123,7 @@ public:
|
|||
GwApi::BoatValue *bvalue6 = pageData.values[5]; // Second element in list (only one value by PageOneValue)
|
||||
String name6 = xdrDelete(bvalue6->getName()); // Value name
|
||||
name6 = name6.substring(0, 6); // String length limit for value name
|
||||
calibrationData.calibrateInstance(bvalue6, logger); // Check if boat data value is to be calibrated
|
||||
calibrationData.calibrateInstance(name6, bvalue6, logger); // Check if boat data value is to be calibrated
|
||||
double value6 = bvalue6->value; // Value as double in SI unit
|
||||
bool valid6 = bvalue6->valid; // Valid information
|
||||
String svalue6 = formatValue(bvalue6, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
|
||||
|
|
|
@ -696,12 +696,10 @@
|
|||
"---",
|
||||
"AWA",
|
||||
"AWS",
|
||||
"COG",
|
||||
"DBT",
|
||||
"HDM",
|
||||
"PRPOS",
|
||||
"RPOS",
|
||||
"SOG",
|
||||
"STW",
|
||||
"TWA",
|
||||
"TWS",
|
||||
|
@ -722,21 +720,7 @@
|
|||
"category": "OBP60 Calibrations",
|
||||
"capabilities": {
|
||||
"obp60":"true"
|
||||
},
|
||||
"condition": [
|
||||
{ "calInstance1": "AWA" },
|
||||
{ "calInstance1": "AWS" },
|
||||
{ "calInstance2": "COG" },
|
||||
{ "calInstance1": "DBT" },
|
||||
{ "calInstance1": "HDM" },
|
||||
{ "calInstance1": "PRPOS" },
|
||||
{ "calInstance1": "RPOS" },
|
||||
{ "calInstance1": "SOG" },
|
||||
{ "calInstance1": "STW" },
|
||||
{ "calInstance1": "TWA" },
|
||||
{ "calInstance1": "TWS" },
|
||||
{ "calInstance1": "TWD" },
|
||||
{ "calInstance1": "WTemp" } ]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "calSlope1",
|
||||
|
@ -747,21 +731,7 @@
|
|||
"category": "OBP60 Calibrations",
|
||||
"capabilities": {
|
||||
"obp60":"true"
|
||||
},
|
||||
"condition": [
|
||||
{ "calInstance1": "AWA" },
|
||||
{ "calInstance1": "AWS" },
|
||||
{ "calInstance2": "COG" },
|
||||
{ "calInstance1": "DBT" },
|
||||
{ "calInstance1": "HDM" },
|
||||
{ "calInstance1": "PRPOS" },
|
||||
{ "calInstance1": "RPOS" },
|
||||
{ "calInstance1": "SOG" },
|
||||
{ "calInstance1": "STW" },
|
||||
{ "calInstance1": "TWA" },
|
||||
{ "calInstance1": "TWS" },
|
||||
{ "calInstance1": "TWD" },
|
||||
{ "calInstance1": "WTemp" } ]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "calSmooth1",
|
||||
|
@ -771,25 +741,11 @@
|
|||
"check": "checkMinMax",
|
||||
"min": 0,
|
||||
"max": 10,
|
||||
"description": "Smoothing factor [0..10]; 0 = no smoothing",
|
||||
"description": "Smoothing factor for data instance 1",
|
||||
"category": "OBP60 Calibrations",
|
||||
"capabilities": {
|
||||
"obp60":"true"
|
||||
},
|
||||
"condition": [
|
||||
{ "calInstance1": "AWA" },
|
||||
{ "calInstance1": "AWS" },
|
||||
{ "calInstance2": "COG" },
|
||||
{ "calInstance1": "DBT" },
|
||||
{ "calInstance1": "HDM" },
|
||||
{ "calInstance1": "PRPOS" },
|
||||
{ "calInstance1": "RPOS" },
|
||||
{ "calInstance1": "SOG" },
|
||||
{ "calInstance1": "STW" },
|
||||
{ "calInstance1": "TWA" },
|
||||
{ "calInstance1": "TWS" },
|
||||
{ "calInstance1": "TWD" },
|
||||
{ "calInstance1": "WTemp" } ]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "calInstance2",
|
||||
|
@ -801,12 +757,10 @@
|
|||
"---",
|
||||
"AWA",
|
||||
"AWS",
|
||||
"COG",
|
||||
"DBT",
|
||||
"HDM",
|
||||
"PRPOS",
|
||||
"RPOS",
|
||||
"SOG",
|
||||
"STW",
|
||||
"TWA",
|
||||
"TWS",
|
||||
|
@ -827,21 +781,7 @@
|
|||
"category": "OBP60 Calibrations",
|
||||
"capabilities": {
|
||||
"obp60":"true"
|
||||
},
|
||||
"condition": [
|
||||
{ "calInstance2": "AWA" },
|
||||
{ "calInstance2": "AWS" },
|
||||
{ "calInstance2": "COG" },
|
||||
{ "calInstance2": "DBT" },
|
||||
{ "calInstance2": "HDM" },
|
||||
{ "calInstance2": "PRPOS" },
|
||||
{ "calInstance2": "RPOS" },
|
||||
{ "calInstance2": "SOG" },
|
||||
{ "calInstance2": "STW" },
|
||||
{ "calInstance2": "TWA" },
|
||||
{ "calInstance2": "TWS" },
|
||||
{ "calInstance2": "TWD" },
|
||||
{ "calInstance2": "WTemp" } ]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "calSlope2",
|
||||
|
@ -852,21 +792,7 @@
|
|||
"category": "OBP60 Calibrations",
|
||||
"capabilities": {
|
||||
"obp60":"true"
|
||||
},
|
||||
"condition": [
|
||||
{ "calInstance2": "AWA" },
|
||||
{ "calInstance2": "AWS" },
|
||||
{ "calInstance2": "COG" },
|
||||
{ "calInstance2": "DBT" },
|
||||
{ "calInstance2": "HDM" },
|
||||
{ "calInstance2": "PRPOS" },
|
||||
{ "calInstance2": "RPOS" },
|
||||
{ "calInstance2": "SOG" },
|
||||
{ "calInstance2": "STW" },
|
||||
{ "calInstance2": "TWA" },
|
||||
{ "calInstance2": "TWS" },
|
||||
{ "calInstance2": "TWD" },
|
||||
{ "calInstance2": "WTemp" } ]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "calSmooth2",
|
||||
|
@ -876,25 +802,11 @@
|
|||
"check": "checkMinMax",
|
||||
"min": 0,
|
||||
"max": 10,
|
||||
"description": "Smoothing factor [0..10]; 0 = no smoothing",
|
||||
"description": "Smoothing factor for data instance 2",
|
||||
"category": "OBP60 Calibrations",
|
||||
"capabilities": {
|
||||
"obp60":"true"
|
||||
},
|
||||
"condition": [
|
||||
{ "calInstance2": "AWA" },
|
||||
{ "calInstance2": "AWS" },
|
||||
{ "calInstance2": "COG" },
|
||||
{ "calInstance2": "DBT" },
|
||||
{ "calInstance2": "HDM" },
|
||||
{ "calInstance2": "PRPOS" },
|
||||
{ "calInstance2": "RPOS" },
|
||||
{ "calInstance2": "SOG" },
|
||||
{ "calInstance2": "STW" },
|
||||
{ "calInstance2": "TWA" },
|
||||
{ "calInstance2": "TWS" },
|
||||
{ "calInstance2": "TWD" },
|
||||
{ "calInstance2": "WTemp" } ]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "calInstance3",
|
||||
|
@ -906,12 +818,10 @@
|
|||
"---",
|
||||
"AWA",
|
||||
"AWS",
|
||||
"COG",
|
||||
"DBT",
|
||||
"HDM",
|
||||
"PRPOS",
|
||||
"RPOS",
|
||||
"SOG",
|
||||
"STW",
|
||||
"TWA",
|
||||
"TWS",
|
||||
|
@ -932,21 +842,7 @@
|
|||
"category": "OBP60 Calibrations",
|
||||
"capabilities": {
|
||||
"obp60":"true"
|
||||
},
|
||||
"condition": [
|
||||
{ "calInstance3": "AWA" },
|
||||
{ "calInstance3": "AWS" },
|
||||
{ "calInstance3": "COG" },
|
||||
{ "calInstance3": "DBT" },
|
||||
{ "calInstance3": "HDM" },
|
||||
{ "calInstance3": "PRPOS" },
|
||||
{ "calInstance3": "RPOS" },
|
||||
{ "calInstance3": "SOG" },
|
||||
{ "calInstance3": "STW" },
|
||||
{ "calInstance3": "TWA" },
|
||||
{ "calInstance3": "TWS" },
|
||||
{ "calInstance3": "TWD" },
|
||||
{ "calInstance3": "WTemp" } ]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "calSlope3",
|
||||
|
@ -957,21 +853,7 @@
|
|||
"category": "OBP60 Calibrations",
|
||||
"capabilities": {
|
||||
"obp60":"true"
|
||||
},
|
||||
"condition": [
|
||||
{ "calInstance3": "AWA" },
|
||||
{ "calInstance3": "AWS" },
|
||||
{ "calInstance3": "COG" },
|
||||
{ "calInstance3": "DBT" },
|
||||
{ "calInstance3": "HDM" },
|
||||
{ "calInstance3": "PRPOS" },
|
||||
{ "calInstance3": "RPOS" },
|
||||
{ "calInstance3": "SOG" },
|
||||
{ "calInstance3": "STW" },
|
||||
{ "calInstance3": "TWA" },
|
||||
{ "calInstance3": "TWS" },
|
||||
{ "calInstance3": "TWD" },
|
||||
{ "calInstance3": "WTemp" } ]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "calSmooth3",
|
||||
|
@ -981,25 +863,11 @@
|
|||
"check": "checkMinMax",
|
||||
"min": 0,
|
||||
"max": 10,
|
||||
"description": "Smoothing factor [0..10]; 0 = no smoothing",
|
||||
"description": "Smoothing factor for data instance 3",
|
||||
"category": "OBP60 Calibrations",
|
||||
"capabilities": {
|
||||
"obp60":"true"
|
||||
},
|
||||
"condition": [
|
||||
{ "calInstance3": "AWA" },
|
||||
{ "calInstance3": "AWS" },
|
||||
{ "calInstance3": "COG" },
|
||||
{ "calInstance3": "DBT" },
|
||||
{ "calInstance3": "HDM" },
|
||||
{ "calInstance3": "PRPOS" },
|
||||
{ "calInstance3": "RPOS" },
|
||||
{ "calInstance3": "SOG" },
|
||||
{ "calInstance3": "STW" },
|
||||
{ "calInstance3": "TWA" },
|
||||
{ "calInstance3": "TWS" },
|
||||
{ "calInstance3": "TWD" },
|
||||
{ "calInstance3": "WTemp" } ]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "display",
|
||||
|
@ -1286,7 +1154,6 @@
|
|||
}
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"name": "page1type",
|
||||
"label": "Type",
|
||||
|
@ -1298,7 +1165,6 @@
|
|||
"Battery",
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
|
@ -1578,7 +1444,6 @@
|
|||
"Battery",
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
|
@ -1855,7 +1720,6 @@
|
|||
"Battery",
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
|
@ -2129,7 +1993,6 @@
|
|||
"Battery",
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
|
@ -2400,7 +2263,6 @@
|
|||
"Battery",
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
|
@ -2668,7 +2530,6 @@
|
|||
"Battery",
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
|
@ -2933,7 +2794,6 @@
|
|||
"Battery",
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
|
@ -3195,7 +3055,6 @@
|
|||
"Battery",
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
|
@ -3454,7 +3313,6 @@
|
|||
"Battery",
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
|
@ -3710,7 +3568,6 @@
|
|||
"Battery",
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
|
|
|
@ -1187,7 +1187,6 @@
|
|||
"Battery",
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
|
@ -1467,7 +1466,6 @@
|
|||
"Battery",
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
|
@ -1744,7 +1742,6 @@
|
|||
"Battery",
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
|
@ -2018,7 +2015,6 @@
|
|||
"Battery",
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
|
@ -2289,7 +2285,6 @@
|
|||
"Battery",
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
|
@ -2557,7 +2552,6 @@
|
|||
"Battery",
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
|
@ -2822,7 +2816,6 @@
|
|||
"Battery",
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
|
@ -3084,7 +3077,6 @@
|
|||
"Battery",
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
|
@ -3343,7 +3335,6 @@
|
|||
"Battery",
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
|
@ -3599,7 +3590,6 @@
|
|||
"Battery",
|
||||
"Battery2",
|
||||
"Clock",
|
||||
"Compass",
|
||||
"DST810",
|
||||
"Fluid",
|
||||
"FourValues",
|
||||
|
|
|
@ -15,7 +15,6 @@ no_of_fields_per_page = {
|
|||
"Battery": 0,
|
||||
"BME280": 0,
|
||||
"Clock": 0,
|
||||
"Compass" : 0,
|
||||
"DST810": 0,
|
||||
"Fluid": 1,
|
||||
"FourValues2": 4,
|
||||
|
@ -25,7 +24,6 @@ no_of_fields_per_page = {
|
|||
"OneValue": 1,
|
||||
"RollPitch": 2,
|
||||
"RudderPosition": 0,
|
||||
"SixValues" : 6,
|
||||
"Solar": 0,
|
||||
"ThreeValues": 3,
|
||||
"TwoValues": 2,
|
||||
|
@ -33,6 +31,7 @@ no_of_fields_per_page = {
|
|||
"WhitePage": 0,
|
||||
"WindRose": 0,
|
||||
"WindRoseFlex": 6,
|
||||
"SixValues" : 6,
|
||||
}
|
||||
|
||||
# No changes needed beyond this point
|
||||
|
|
|
@ -285,8 +285,6 @@ void registerAllPages(PageList &list){
|
|||
list.add(®isterPageDST810);
|
||||
extern PageDescription registerPageClock;
|
||||
list.add(®isterPageClock);
|
||||
extern PageDescription registerPageCompass;
|
||||
list.add(®isterPageCompass);
|
||||
extern PageDescription registerPageWhite;
|
||||
list.add(®isterPageWhite);
|
||||
extern PageDescription registerPageBME280;
|
||||
|
|
|
@ -112,7 +112,7 @@ class SSISensor : public SensorTemplate<BUSTYPE,SensorBase::SPI>{
|
|||
.flags = SPI_TRANS_USE_RXDATA,
|
||||
.cmd = 0,
|
||||
.addr = 0,
|
||||
.length = (size_t)bits+1,
|
||||
.length = bits+1,
|
||||
.rxlength = 0};
|
||||
esp_err_t ret = spi_device_queue_trans(device->device(), &ta, portMAX_DELAY);
|
||||
if (ret != ESP_OK) return ret;
|
||||
|
@ -138,4 +138,4 @@ class SSISensor : public SensorTemplate<BUSTYPE,SensorBase::SPI>{
|
|||
using SpiSensorList=SensorList;
|
||||
#define GWSPI1_HOST SPI2_HOST
|
||||
#define GWSPI2_HOST SPI3_HOST
|
||||
#endif
|
||||
#endif
|
853
obp60task.cpp
853
obp60task.cpp
|
@ -1,853 +0,0 @@
|
|||
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
|
||||
#include "obp60task.h"
|
||||
#include "Pagedata.h" // Data exchange for pages
|
||||
#include "OBP60Hardware.h" // PIN definitions
|
||||
#include <Wire.h> // I2C connections
|
||||
#include <MCP23017.h> // MCP23017 extension Port
|
||||
#include <N2kTypes.h> // NMEA2000
|
||||
#include <N2kMessages.h>
|
||||
#include <NMEA0183.h> // NMEA0183
|
||||
#include <NMEA0183Msg.h>
|
||||
#include <NMEA0183Messages.h>
|
||||
#include <GxEPD2_BW.h> // GxEPD2 lib for b/w E-Ink displays
|
||||
#include "OBP60Extensions.h" // Functions lib for extension board
|
||||
#include "OBP60Keypad.h" // Functions for keypad
|
||||
|
||||
#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
|
||||
|
||||
// True type character sets includes
|
||||
// See OBP60ExtensionPort.cpp
|
||||
|
||||
// Pictures
|
||||
//#include GxEPD_BitmapExamples // Example picture
|
||||
#include "MFD_OBP60_400x300_sw.h" // MFD with logo
|
||||
#include "Logo_OBP_400x300_sw.h" // OBP Logo
|
||||
#include "images/unknown.xbm" // unknown page indicator
|
||||
#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
|
||||
|
||||
// Hardware initialization before start all services
|
||||
//####################################################################################
|
||||
void OBP60Init(GwApi *api){
|
||||
|
||||
GwLog *logger = api->getLogger();
|
||||
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);
|
||||
|
||||
api->getLogger()->logDebug(GwLog::LOG,"obp60init running");
|
||||
|
||||
// Check I2C devices
|
||||
|
||||
|
||||
// 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
|
||||
String sdcard = config->getConfigItem(config->useSDCard, true)->asString();
|
||||
if (sdcard == "on") {
|
||||
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
|
||||
rtc_gpio_pulldown_dis(OBP_WAKEWUP_PIN); // Disable pulldown resistor
|
||||
#endif
|
||||
|
||||
// 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());
|
||||
#ifdef DISPLAY_GDEY042T81
|
||||
if(fastrefresh == "true"){
|
||||
static const bool useFastFullUpdate = true; // Enable fast full display update only for GDEY042T81
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BOARD_OBP60S3
|
||||
touchSleepWakeUpEnable(TP1, 45); // TODO sensitivity should be configurable via web interface
|
||||
touchSleepWakeUpEnable(TP2, 45);
|
||||
touchSleepWakeUpEnable(TP3, 45);
|
||||
touchSleepWakeUpEnable(TP4, 45);
|
||||
touchSleepWakeUpEnable(TP5, 45);
|
||||
touchSleepWakeUpEnable(TP6, 45);
|
||||
esp_sleep_enable_touchpad_wakeup();
|
||||
#endif
|
||||
|
||||
// Get CPU speed
|
||||
int freq = getCpuFrequencyMhz();
|
||||
api->getLogger()->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());
|
||||
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"){
|
||||
setBacklightLED(brightness, colorMapping(backlightColor));
|
||||
}
|
||||
else if(String(backlightMode) == "Off"){
|
||||
setBacklightLED(0, COLOR_BLACK); // Backlight LEDs off (blue without britghness)
|
||||
}
|
||||
else if(String(backlightMode) == "Control by Key"){
|
||||
setBacklightLED(0, COLOR_BLUE); // Backlight LEDs off (blue without britghness)
|
||||
}
|
||||
|
||||
// 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());
|
||||
if(String(ledMode) == "Off"){
|
||||
setBlinkingLED(false);
|
||||
}
|
||||
|
||||
// Marker for init complete
|
||||
// Used in OBP60Task()
|
||||
initComplete = true;
|
||||
|
||||
// Buzzer tone for initialization finish
|
||||
setBuzzerPower(uint(api->getConfig()->getConfigItem(api->getConfig()->buzzerPower,true)->asInt()));
|
||||
buzzer(TONE4, 500);
|
||||
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int page0=0;
|
||||
QueueHandle_t queue;
|
||||
GwLog* logger = NULL;
|
||||
// GwApi* api = NULL;
|
||||
uint sensitivity = 100;
|
||||
bool use_syspage = true;
|
||||
} MyData;
|
||||
|
||||
// Keyboard Task
|
||||
void keyboardTask(void *param){
|
||||
MyData *data=(MyData *)param;
|
||||
|
||||
int keycode = 0;
|
||||
data->logger->logDebug(GwLog::LOG,"Start keyboard task");
|
||||
|
||||
// Loop for keyboard task
|
||||
while (true){
|
||||
keycode = readKeypad(data->logger, data->sensitivity, data->use_syspage);
|
||||
//send a key event
|
||||
if(keycode != 0){
|
||||
xQueueSend(data->queue, &keycode, 0);
|
||||
data->logger->logDebug(GwLog::LOG,"Send keycode: %d", keycode);
|
||||
}
|
||||
delay(20); // 50Hz update rate (20ms)
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
class BoatValueList{
|
||||
public:
|
||||
static const int MAXVALUES=100;
|
||||
//we create a list containing all our BoatValues
|
||||
//this is the list we later use to let the api fill all the values
|
||||
//additionally we put the necessary values into the paga data - see below
|
||||
GwApi::BoatValue *allBoatValues[MAXVALUES];
|
||||
int numValues=0;
|
||||
|
||||
bool addValueToList(GwApi::BoatValue *v){
|
||||
for (int i=0;i<numValues;i++){
|
||||
if (allBoatValues[i] == v){
|
||||
//already in list...
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (numValues >= MAXVALUES) return false;
|
||||
allBoatValues[numValues]=v;
|
||||
numValues++;
|
||||
return true;
|
||||
}
|
||||
//helper to ensure that each BoatValue is only queried once
|
||||
GwApi::BoatValue *findValueOrCreate(String name){
|
||||
for (int i=0;i<numValues;i++){
|
||||
if (allBoatValues[i]->getName() == name) {
|
||||
return allBoatValues[i];
|
||||
}
|
||||
}
|
||||
GwApi::BoatValue *rt=new GwApi::BoatValue(name);
|
||||
addValueToList(rt);
|
||||
return rt;
|
||||
}
|
||||
};
|
||||
|
||||
//we want to have a list that has all our page definitions
|
||||
//this way each page can easily be added here
|
||||
//needs some minor tricks for the safe static initialization
|
||||
typedef std::vector<PageDescription*> Pages;
|
||||
//the page list class
|
||||
class PageList{
|
||||
public:
|
||||
Pages pages;
|
||||
void add(PageDescription *p){
|
||||
pages.push_back(p);
|
||||
}
|
||||
PageDescription *find(String name){
|
||||
for (auto it=pages.begin();it != pages.end();it++){
|
||||
if ((*it)->pageName == name){
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* this function will add all the pages we know to the pagelist
|
||||
* each page should have defined a registerXXXPage variable of type
|
||||
* PageData that describes what it needs
|
||||
*/
|
||||
void registerAllPages(PageList &list){
|
||||
//the next line says that this variable is defined somewhere else
|
||||
//in our case in a separate C++ source file
|
||||
//this way this separate source file can be compiled by it's own
|
||||
//and has no access to any of our data except the one that we
|
||||
//give as a parameter to the page function
|
||||
extern PageDescription registerPageSystem;
|
||||
//we add the variable to our list
|
||||
list.add(®isterPageSystem);
|
||||
extern PageDescription registerPageOneValue;
|
||||
list.add(®isterPageOneValue);
|
||||
extern PageDescription registerPageTwoValues;
|
||||
list.add(®isterPageTwoValues);
|
||||
extern PageDescription registerPageThreeValues;
|
||||
list.add(®isterPageThreeValues);
|
||||
extern PageDescription registerPageSixValues;
|
||||
list.add(®isterPageSixValues);
|
||||
extern PageDescription registerPageFourValues;
|
||||
list.add(®isterPageFourValues);
|
||||
extern PageDescription registerPageFourValues2;
|
||||
list.add(®isterPageFourValues2);
|
||||
extern PageDescription registerPageWind;
|
||||
list.add(®isterPageWind);
|
||||
extern PageDescription registerPageWindRose;
|
||||
list.add(®isterPageWindRose);
|
||||
extern PageDescription registerPageWindRoseFlex;
|
||||
list.add(®isterPageWindRoseFlex); //
|
||||
extern PageDescription registerPageVoltage;
|
||||
list.add(®isterPageVoltage);
|
||||
extern PageDescription registerPageDST810;
|
||||
list.add(®isterPageDST810);
|
||||
extern PageDescription registerPageClock;
|
||||
list.add(®isterPageClock);
|
||||
extern PageDescription registerPageWhite;
|
||||
list.add(®isterPageWhite);
|
||||
extern PageDescription registerPageBME280;
|
||||
list.add(®isterPageBME280);
|
||||
extern PageDescription registerPageRudderPosition;
|
||||
list.add(®isterPageRudderPosition);
|
||||
extern PageDescription registerPageKeelPosition;
|
||||
list.add(®isterPageKeelPosition);
|
||||
extern PageDescription registerPageBattery;
|
||||
list.add(®isterPageBattery);
|
||||
extern PageDescription registerPageBattery2;
|
||||
list.add(®isterPageBattery2);
|
||||
extern PageDescription registerPageRollPitch;
|
||||
list.add(®isterPageRollPitch);
|
||||
extern PageDescription registerPageSolar;
|
||||
list.add(®isterPageSolar);
|
||||
extern PageDescription registerPageGenerator;
|
||||
list.add(®isterPageGenerator);
|
||||
extern PageDescription registerPageXTETrack;
|
||||
list.add(®isterPageXTETrack);
|
||||
extern PageDescription registerPageFluid;
|
||||
list.add(®isterPageFluid);
|
||||
extern PageDescription registerPageCompass;
|
||||
list.add(®isterPageCompass);
|
||||
}
|
||||
|
||||
// Undervoltage detection for shutdown display
|
||||
void underVoltageDetection(GwApi *api, CommonData &common){
|
||||
// Read settings
|
||||
double voffset = (api->getConfig()->getConfigItem(api->getConfig()->vOffset,true)->asString()).toFloat();
|
||||
double vslope = (api->getConfig()->getConfigItem(api->getConfig()->vSlope,true)->asString()).toFloat();
|
||||
// Read supply voltage
|
||||
#if defined VOLTAGE_SENSOR && defined LIPO_ACCU_1200
|
||||
float actVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40
|
||||
float minVoltage = 3.65; // Absolut minimum volatge for 3,7V LiPo accu
|
||||
#else
|
||||
float actVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60
|
||||
float minVoltage = MIN_VOLTAGE;
|
||||
#endif
|
||||
double calVoltage = actVoltage * vslope + voffset; // Calibration
|
||||
if(calVoltage < minVoltage){
|
||||
#if defined VOLTAGE_SENSOR && defined LIPO_ACCU_1200
|
||||
// Switch off all power lines
|
||||
setPortPin(OBP_BACKLIGHT_LED, false); // Backlight Off
|
||||
setFlashLED(false); // Flash LED Off
|
||||
buzzer(TONE4, 20); // Buzzer tone 4kHz 20ms
|
||||
// Shutdown EInk display
|
||||
getdisplay().setFullWindow(); // Set full Refresh
|
||||
//getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
getdisplay().fillScreen(common.bgcolor);// Clear screen
|
||||
getdisplay().setTextColor(common.fgcolor);
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt7b);
|
||||
getdisplay().setCursor(65, 150);
|
||||
getdisplay().print("Undervoltage");
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
||||
getdisplay().setCursor(65, 175);
|
||||
getdisplay().print("Charge battery and restart system");
|
||||
getdisplay().nextPage(); // Partial update
|
||||
getdisplay().powerOff(); // Display power off
|
||||
setPortPin(OBP_POWER_EPD, false); // Power off ePaper display
|
||||
setPortPin(OBP_POWER_SD, false); // Power off SD card
|
||||
#else
|
||||
// Switch off all power lines
|
||||
setPortPin(OBP_BACKLIGHT_LED, false); // Backlight Off
|
||||
setFlashLED(false); // Flash LED Off
|
||||
buzzer(TONE4, 20); // Buzzer tone 4kHz 20ms
|
||||
setPortPin(OBP_POWER_50, false); // Power rail 5.0V Off
|
||||
// Shutdown EInk display
|
||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
getdisplay().fillScreen(common.bgcolor);// Clear screen
|
||||
getdisplay().setTextColor(common.fgcolor);
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt7b);
|
||||
getdisplay().setCursor(65, 150);
|
||||
getdisplay().print("Undervoltage");
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
||||
getdisplay().setCursor(65, 175);
|
||||
getdisplay().print("To wake up repower system");
|
||||
getdisplay().nextPage(); // Partial update
|
||||
getdisplay().powerOff(); // Display power off
|
||||
#endif
|
||||
// Stop system
|
||||
while(true){
|
||||
esp_deep_sleep_start(); // Deep Sleep without weakup. Weakup only after power cycle (restart).
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OBP60 Task
|
||||
//####################################################################################
|
||||
void OBP60Task(GwApi *api){
|
||||
// vTaskDelete(NULL);
|
||||
// return;
|
||||
GwLog *logger=api->getLogger();
|
||||
GwConfigHandler *config=api->getConfig();
|
||||
#ifdef HARDWARE_V21
|
||||
startLedTask(api);
|
||||
#endif
|
||||
PageList allPages;
|
||||
registerAllPages(allPages);
|
||||
CommonData commonData;
|
||||
commonData.logger=logger;
|
||||
commonData.config=config;
|
||||
|
||||
#ifdef HARDWARE_V21
|
||||
// Keyboard coordinates for page footer
|
||||
initKeys(commonData);
|
||||
#endif
|
||||
|
||||
tN2kMsg N2kMsg;
|
||||
|
||||
LOG_DEBUG(GwLog::LOG,"obp60task started");
|
||||
for (auto it=allPages.pages.begin();it != allPages.pages.end();it++){
|
||||
LOG_DEBUG(GwLog::LOG,"found registered page %s",(*it)->pageName.c_str());
|
||||
}
|
||||
|
||||
// Init E-Ink display
|
||||
String displaymode = api->getConfig()->getConfigItem(api->getConfig()->display,true)->asString();
|
||||
String displaycolor = api->getConfig()->getConfigItem(api->getConfig()->displaycolor,true)->asString();
|
||||
if (displaycolor == "Normal") {
|
||||
commonData.fgcolor = GxEPD_BLACK;
|
||||
commonData.bgcolor = GxEPD_WHITE;
|
||||
}
|
||||
else{
|
||||
commonData.fgcolor = GxEPD_WHITE;
|
||||
commonData.bgcolor = GxEPD_BLACK;
|
||||
}
|
||||
String systemname = api->getConfig()->getConfigItem(api->getConfig()->systemName,true)->asString();
|
||||
String wifipass = api->getConfig()->getConfigItem(api->getConfig()->apPassword,true)->asString();
|
||||
bool refreshmode = api->getConfig()->getConfigItem(api->getConfig()->refresh,true)->asBoolean();
|
||||
String fastrefresh = api->getConfig()->getConfigItem(api->getConfig()->fastRefresh,true)->asString();
|
||||
uint fullrefreshtime = uint(api->getConfig()->getConfigItem(api->getConfig()->fullRefreshTime,true)->asInt());
|
||||
#ifdef BOARD_OBP40S3
|
||||
bool syspage_enabled = config->getBool(config->systemPage);
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_GDEY042T81
|
||||
getdisplay().init(115200, true, 2, false); // Use this for Waveshare boards with "clever" reset circuit, 2ms reset pulse
|
||||
#else
|
||||
getdisplay().init(115200); // Init for normal displays
|
||||
#endif
|
||||
|
||||
getdisplay().setRotation(0); // Set display orientation (horizontal)
|
||||
getdisplay().setFullWindow(); // Set full Refresh
|
||||
getdisplay().firstPage(); // set first page
|
||||
getdisplay().fillScreen(commonData.bgcolor);
|
||||
getdisplay().setTextColor(commonData.fgcolor);
|
||||
getdisplay().nextPage(); // Full Refresh
|
||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
getdisplay().fillScreen(commonData.bgcolor);
|
||||
getdisplay().nextPage(); // Fast Refresh
|
||||
getdisplay().nextPage(); // Fast Refresh
|
||||
if(String(displaymode) == "Logo + QR Code" || String(displaymode) == "Logo"){
|
||||
getdisplay().fillScreen(commonData.bgcolor);
|
||||
getdisplay().drawBitmap(0, 0, gImage_Logo_OBP_400x300_sw, getdisplay().width(), getdisplay().height(), commonData.fgcolor); // Draw start logo
|
||||
getdisplay().nextPage(); // Fast Refresh
|
||||
getdisplay().nextPage(); // Fast Refresh
|
||||
delay(SHOW_TIME); // Logo show time
|
||||
if(String(displaymode) == "Logo + QR Code"){
|
||||
getdisplay().fillScreen(commonData.bgcolor);
|
||||
qrWiFi(systemname, wifipass, commonData.fgcolor, commonData.bgcolor); // Show QR code for WiFi connection
|
||||
getdisplay().nextPage(); // Fast Refresh
|
||||
getdisplay().nextPage(); // Fast Refresh
|
||||
delay(SHOW_TIME); // QR code show time
|
||||
}
|
||||
getdisplay().fillScreen(commonData.bgcolor);
|
||||
getdisplay().nextPage(); // Fast Refresh
|
||||
getdisplay().nextPage(); // Fast Refresh
|
||||
}
|
||||
|
||||
// Init pages
|
||||
int numPages=1;
|
||||
PageStruct pages[MAX_PAGE_NUMBER];
|
||||
// Set start page
|
||||
int pageNumber = int(api->getConfig()->getConfigItem(api->getConfig()->startPage,true)->asInt()) - 1;
|
||||
|
||||
LOG_DEBUG(GwLog::LOG,"Checking wakeup...");
|
||||
#ifdef BOARD_OBP60S3
|
||||
if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_TOUCHPAD) {
|
||||
LOG_DEBUG(GwLog::LOG,"Wake up by touch pad %d",esp_sleep_get_touchpad_wakeup_status());
|
||||
pageNumber = getLastPage();
|
||||
} else {
|
||||
LOG_DEBUG(GwLog::LOG,"Other wakeup reason");
|
||||
}
|
||||
#endif
|
||||
#ifdef BOARD_OBP40S3
|
||||
if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_EXT0) {
|
||||
LOG_DEBUG(GwLog::LOG,"Wake up by key");
|
||||
pageNumber = getLastPage();
|
||||
} else {
|
||||
LOG_DEBUG(GwLog::LOG,"Other wakeup reason");
|
||||
}
|
||||
#endif
|
||||
LOG_DEBUG(GwLog::LOG,"...done");
|
||||
|
||||
int lastPage=pageNumber;
|
||||
|
||||
BoatValueList boatValues; //all the boat values for the api query
|
||||
//commonData.distanceformat=config->getString(xxx);
|
||||
//add all necessary data to common data
|
||||
|
||||
//fill the page data from config
|
||||
numPages=config->getInt(config->visiblePages,1);
|
||||
if (numPages < 1) numPages=1;
|
||||
if (numPages >= MAX_PAGE_NUMBER) numPages=MAX_PAGE_NUMBER;
|
||||
LOG_DEBUG(GwLog::LOG,"Number of pages %d",numPages);
|
||||
String configPrefix="page";
|
||||
for (int i=0;i< numPages;i++){
|
||||
String prefix=configPrefix+String(i+1); //e.g. page1
|
||||
String configName=prefix+String("type");
|
||||
LOG_DEBUG(GwLog::DEBUG,"asking for page config %s",configName.c_str());
|
||||
String pageType=config->getString(configName,"");
|
||||
PageDescription *description=allPages.find(pageType);
|
||||
if (description == NULL){
|
||||
LOG_DEBUG(GwLog::ERROR,"page description for %s not found",pageType.c_str());
|
||||
continue;
|
||||
}
|
||||
pages[i].description=description;
|
||||
pages[i].page=description->creator(commonData);
|
||||
pages[i].parameters.pageName=pageType;
|
||||
pages[i].parameters.pageNumber = i + 1;
|
||||
LOG_DEBUG(GwLog::DEBUG,"found page %s for number %d",pageType.c_str(),i);
|
||||
//fill in all the user defined parameters
|
||||
for (int uid=0;uid<description->userParam;uid++){
|
||||
String cfgName=prefix+String("value")+String(uid+1);
|
||||
GwApi::BoatValue *value=boatValues.findValueOrCreate(config->getString(cfgName,""));
|
||||
LOG_DEBUG(GwLog::DEBUG,"add user input cfg=%s,value=%s for page %d",
|
||||
cfgName.c_str(),
|
||||
value->getName().c_str(),
|
||||
i
|
||||
);
|
||||
pages[i].parameters.values.push_back(value);
|
||||
}
|
||||
//now add the predefined values
|
||||
for (auto it=description->fixedParam.begin();it != description->fixedParam.end();it++){
|
||||
GwApi::BoatValue *value=boatValues.findValueOrCreate(*it);
|
||||
LOG_DEBUG(GwLog::DEBUG,"added fixed value %s to page %d",value->getName().c_str(),i);
|
||||
pages[i].parameters.values.push_back(value);
|
||||
}
|
||||
}
|
||||
// add out of band system page (always available)
|
||||
Page *syspage = allPages.pages[0]->creator(commonData);
|
||||
|
||||
// Display screenshot handler for HTTP request
|
||||
// http://192.168.15.1/api/user/OBP60Task/screenshot
|
||||
api->registerRequestHandler("screenshot", [api, &pageNumber, pages](AsyncWebServerRequest *request) {
|
||||
doImageRequest(api, &pageNumber, pages, request);
|
||||
});
|
||||
|
||||
//now we have prepared the page data
|
||||
//we start a separate task that will fetch our keys...
|
||||
MyData allParameters;
|
||||
allParameters.logger=api->getLogger();
|
||||
allParameters.page0=3;
|
||||
allParameters.queue=xQueueCreate(10,sizeof(int));
|
||||
allParameters.sensitivity= api->getConfig()->getInt(GwConfigDefinitions::tSensitivity);
|
||||
#ifdef BOARD_OBP40S3
|
||||
allParameters.use_syspage = syspage_enabled;
|
||||
#endif
|
||||
xTaskCreate(keyboardTask,"keyboard",2000,&allParameters,configMAX_PRIORITIES-1,NULL);
|
||||
SharedData *shared=new SharedData(api);
|
||||
createSensorTask(shared);
|
||||
|
||||
// Task Loop
|
||||
//####################################################################################
|
||||
|
||||
// Configuration values for main loop
|
||||
String gpsFix = api->getConfig()->getConfigItem(api->getConfig()->flashLED,true)->asString();
|
||||
String gpsOn=api->getConfig()->getConfigItem(api->getConfig()->useGPS,true)->asString();
|
||||
float tz = api->getConfig()->getConfigItem(api->getConfig()->timeZone,true)->asFloat();
|
||||
|
||||
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.powermode = api->getConfig()->getConfigItem(api->getConfig()->powerMode,true)->asString();
|
||||
|
||||
bool uvoltage = api->getConfig()->getConfigItem(api->getConfig()->underVoltage,true)->asBoolean();
|
||||
String cpuspeed = api->getConfig()->getConfigItem(api->getConfig()->cpuSpeed,true)->asString();
|
||||
uint hdopAccuracy = uint(api->getConfig()->getConfigItem(api->getConfig()->hdopAccuracy,true)->asInt());
|
||||
|
||||
double homelat = commonData.config->getString(commonData.config->homeLAT).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;
|
||||
if (homevalid) {
|
||||
LOG_DEBUG(GwLog::LOG, "Home location set to %f : %f", homelat, homelon);
|
||||
} else {
|
||||
LOG_DEBUG(GwLog::LOG, "No valid home location found");
|
||||
}
|
||||
|
||||
// refreshmode defined in init section
|
||||
|
||||
// Boat values for main loop
|
||||
GwApi::BoatValue *date = boatValues.findValueOrCreate("GPSD"); // Load GpsDate
|
||||
GwApi::BoatValue *time = boatValues.findValueOrCreate("GPST"); // Load GpsTime
|
||||
GwApi::BoatValue *lat = boatValues.findValueOrCreate("LAT"); // Load GpsLatitude
|
||||
GwApi::BoatValue *lon = boatValues.findValueOrCreate("LON"); // Load GpsLongitude
|
||||
GwApi::BoatValue *hdop = boatValues.findValueOrCreate("HDOP"); // Load GpsHDOP
|
||||
|
||||
LOG_DEBUG(GwLog::LOG,"obp60task: start mainloop");
|
||||
|
||||
commonData.time = boatValues.findValueOrCreate("GPST"); // Load GpsTime
|
||||
commonData.date = boatValues.findValueOrCreate("GPSD"); // Load GpsTime
|
||||
bool delayedDisplayUpdate = false; // If select a new pages then make a delayed full display update
|
||||
bool cpuspeedsetted = false; // Marker for change CPU speed
|
||||
long firststart = millis(); // First start
|
||||
long starttime0 = millis(); // Mainloop
|
||||
long starttime1 = millis(); // Full display refresh for the first 5 min (more often as normal)
|
||||
long starttime2 = millis(); // Full display refresh after 5 min
|
||||
long starttime3 = millis(); // Display update all 1s
|
||||
long starttime4 = millis(); // Delayed display update after 4s when select a new page
|
||||
long starttime5 = millis(); // Calculate sunrise and sunset all 1s
|
||||
|
||||
pages[pageNumber].page->setupKeys(); // Initialize keys for first page
|
||||
|
||||
// Main loop runs with 100ms
|
||||
//####################################################################################
|
||||
|
||||
bool systemPage = false;
|
||||
Page *currentPage;
|
||||
while (true){
|
||||
delay(100); // Delay 100ms (loop time)
|
||||
bool keypressed = false;
|
||||
|
||||
// Undervoltage detection
|
||||
if(uvoltage == true){
|
||||
underVoltageDetection(api, commonData);
|
||||
}
|
||||
|
||||
// Set CPU speed after boot after 1min
|
||||
if(millis() > firststart + (1 * 60 * 1000) && cpuspeedsetted == false){
|
||||
if(String(cpuspeed) == "80"){
|
||||
setCpuFrequencyMhz(80);
|
||||
}
|
||||
if(String(cpuspeed) == "160"){
|
||||
setCpuFrequencyMhz(160);
|
||||
}
|
||||
if(String(cpuspeed) == "240"){
|
||||
setCpuFrequencyMhz(240);
|
||||
}
|
||||
int freq = getCpuFrequencyMhz();
|
||||
api->getLogger()->logDebug(GwLog::LOG,"CPU speed: %i MHz", freq);
|
||||
cpuspeedsetted = true;
|
||||
}
|
||||
|
||||
if(millis() > starttime0 + 100){
|
||||
starttime0 = millis();
|
||||
commonData.data=shared->getSensorData();
|
||||
commonData.data.actpage = pageNumber + 1;
|
||||
commonData.data.maxpage = numPages;
|
||||
|
||||
// If GPS fix then LED off (HDOP)
|
||||
if(String(gpsFix) == "GPS Fix Lost" && hdop->value <= hdopAccuracy && hdop->valid == true){
|
||||
setFlashLED(false);
|
||||
}
|
||||
// If missing GPS fix then LED on
|
||||
if((String(gpsFix) == "GPS Fix Lost" && hdop->value > hdopAccuracy && hdop->valid == true) || (String(gpsFix) == "GPS Fix Lost" && hdop->valid == false)){
|
||||
setFlashLED(true);
|
||||
}
|
||||
|
||||
// Check the keyboard message
|
||||
int keyboardMessage=0;
|
||||
while (xQueueReceive(allParameters.queue,&keyboardMessage,0)){
|
||||
LOG_DEBUG(GwLog::LOG,"new key from keyboard %d",keyboardMessage);
|
||||
keypressed = true;
|
||||
|
||||
if (keyboardMessage == 12 and !systemPage) {
|
||||
LOG_DEBUG(GwLog::LOG, "Calling system page");
|
||||
systemPage = true; // System page is out of band
|
||||
syspage->setupKeys();
|
||||
keyboardMessage = 0;
|
||||
}
|
||||
else {
|
||||
currentPage = pages[pageNumber].page;
|
||||
if (systemPage && keyboardMessage == 1) {
|
||||
// exit system mode with exit key number 1
|
||||
systemPage = false;
|
||||
currentPage->setupKeys();
|
||||
keyboardMessage = 0;
|
||||
}
|
||||
}
|
||||
if (systemPage) {
|
||||
keyboardMessage = syspage->handleKey(keyboardMessage);
|
||||
} else if (currentPage) {
|
||||
keyboardMessage = currentPage->handleKey(keyboardMessage);
|
||||
}
|
||||
if (keyboardMessage > 0) // not handled by page
|
||||
{
|
||||
// Decoding all key codes
|
||||
// #6 Backlight on if key controled
|
||||
if (commonData.backlight.mode == BacklightMode::KEY) {
|
||||
// if(String(backlight) == "Control by Key"){
|
||||
if(keyboardMessage == 6){
|
||||
LOG_DEBUG(GwLog::LOG,"Toggle Backlight LED");
|
||||
toggleBacklightLED(commonData.backlight.brightness, commonData.backlight.color);
|
||||
}
|
||||
}
|
||||
#ifdef BOARD_OBP40S3
|
||||
// #3 Deep sleep mode for OBP40
|
||||
if ((keyboardMessage == 3) and !syspage_enabled){
|
||||
deepSleep(commonData);
|
||||
}
|
||||
#endif
|
||||
// #9 Swipe right or #4 key right
|
||||
if ((keyboardMessage == 9) or (keyboardMessage == 4))
|
||||
{
|
||||
pageNumber++;
|
||||
if (pageNumber >= numPages){
|
||||
pageNumber = 0;
|
||||
}
|
||||
commonData.data.actpage = pageNumber + 1;
|
||||
commonData.data.maxpage = numPages;
|
||||
}
|
||||
// #10 Swipe left or #3 key left
|
||||
if ((keyboardMessage == 10) or (keyboardMessage == 3))
|
||||
{
|
||||
pageNumber--;
|
||||
if (pageNumber < 0){
|
||||
pageNumber = numPages - 1;
|
||||
}
|
||||
commonData.data.actpage = pageNumber + 1;
|
||||
commonData.data.maxpage = numPages;
|
||||
}
|
||||
|
||||
// #9 or #10 Refresh display after a new page after 4s waiting time and if refresh is disabled
|
||||
if(refreshmode == true && (keyboardMessage == 9 || keyboardMessage == 10)){
|
||||
starttime4 = millis();
|
||||
starttime2 = millis(); // Reset the timer for full display update
|
||||
delayedDisplayUpdate = true;
|
||||
}
|
||||
}
|
||||
LOG_DEBUG(GwLog::LOG,"set pagenumber to %d",pageNumber);
|
||||
}
|
||||
|
||||
// Calculate sunrise, sunset and backlight control with sun status all 1s
|
||||
if(millis() > starttime5 + 1000){
|
||||
starttime5 = millis();
|
||||
if(time->valid == true && date->valid == true && lat->valid == true && lon->valid == true){
|
||||
// Provide sundata to all pages
|
||||
commonData.sundata = calcSunsetSunrise(time->value , date->value, lat->value, lon->value, tz);
|
||||
// Backlight with sun control
|
||||
if (commonData.backlight.mode == BacklightMode::SUN) {
|
||||
// if(String(backlight) == "Control by Sun"){
|
||||
if(commonData.sundata.sunDown == true){
|
||||
setBacklightLED(commonData.backlight.brightness, commonData.backlight.color);
|
||||
}
|
||||
else{
|
||||
setBacklightLED(0, COLOR_BLUE); // Backlight LEDs off (blue without britghness)
|
||||
}
|
||||
}
|
||||
} else if (homevalid and commonData.data.rtcValid) {
|
||||
// No gps fix but valid home location and time configured
|
||||
commonData.sundata = calcSunsetSunriseRTC(&commonData.data.rtcTime, homelat, homelon, tz);
|
||||
}
|
||||
}
|
||||
|
||||
// Full display update afer a new selected page and 4s wait time
|
||||
if(millis() > starttime4 + 4000 && delayedDisplayUpdate == true){
|
||||
starttime1 = millis();
|
||||
starttime2 = millis();
|
||||
getdisplay().setFullWindow(); // Set full update
|
||||
getdisplay().nextPage();
|
||||
if(fastrefresh == "false"){
|
||||
getdisplay().fillScreen(commonData.fgcolor); // Clear display
|
||||
getdisplay().nextPage(); // Full update
|
||||
getdisplay().fillScreen(commonData.bgcolor); // Clear display
|
||||
getdisplay().nextPage(); // Full update
|
||||
}
|
||||
delayedDisplayUpdate = false;
|
||||
}
|
||||
|
||||
// Subtask E-Ink full refresh all 1 min for the first 5 min after power on or restart
|
||||
// This needs for a better display contrast after power on in cold or warm environments
|
||||
if(millis() < firststart + (5 * 60 * 1000) && millis() > starttime1 + (60 * 1000)){
|
||||
starttime1 = millis();
|
||||
starttime2 = millis();
|
||||
LOG_DEBUG(GwLog::DEBUG,"E-Ink full refresh first 5 min");
|
||||
getdisplay().setFullWindow(); // Set full update
|
||||
getdisplay().nextPage();
|
||||
if(fastrefresh == "false"){
|
||||
getdisplay().fillScreen(commonData.fgcolor); // Clear display
|
||||
getdisplay().nextPage(); // Full update
|
||||
getdisplay().fillScreen(commonData.bgcolor); // Clear display
|
||||
getdisplay().nextPage(); // Full update
|
||||
}
|
||||
}
|
||||
|
||||
// Subtask E-Ink full refresh
|
||||
if(millis() > starttime2 + fullrefreshtime * 60 * 1000){
|
||||
starttime2 = millis();
|
||||
LOG_DEBUG(GwLog::DEBUG,"E-Ink full refresh");
|
||||
getdisplay().setFullWindow(); // Set full update
|
||||
getdisplay().nextPage();
|
||||
if(fastrefresh == "false"){
|
||||
getdisplay().fillScreen(commonData.fgcolor); // Clear display
|
||||
getdisplay().nextPage(); // Full update
|
||||
getdisplay().fillScreen(commonData.bgcolor); // Clear display
|
||||
getdisplay().nextPage(); // Full update
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh display data, default all 1s
|
||||
currentPage = pages[pageNumber].page;
|
||||
int pagetime = 1000;
|
||||
if ((lastPage == pageNumber) and (!keypressed)) {
|
||||
// same page we use page defined time
|
||||
pagetime = currentPage->refreshtime;
|
||||
}
|
||||
if(millis() > starttime3 + pagetime){
|
||||
LOG_DEBUG(GwLog::DEBUG,"Page with refreshtime=%d", pagetime);
|
||||
starttime3 = millis();
|
||||
|
||||
//refresh data from api
|
||||
api->getBoatDataValues(boatValues.numValues,boatValues.allBoatValues);
|
||||
api->getStatus(commonData.status);
|
||||
|
||||
// Clear display
|
||||
// getdisplay().fillRect(0, 0, getdisplay().width(), getdisplay().height(), commonData.bgcolor);
|
||||
getdisplay().fillScreen(commonData.bgcolor); // Clear display
|
||||
|
||||
// Show header if enabled
|
||||
if (pages[pageNumber].description && pages[pageNumber].description->header or systemPage){
|
||||
// build header using commonData
|
||||
displayHeader(commonData, date, time, hdop); // Show page header
|
||||
}
|
||||
|
||||
// Call the particular page
|
||||
if (systemPage) {
|
||||
displayFooter(commonData);
|
||||
PageData sysparams; // empty
|
||||
syspage->displayPage(sysparams);
|
||||
}
|
||||
else {
|
||||
if (currentPage == NULL){
|
||||
LOG_DEBUG(GwLog::ERROR,"page number %d not found", pageNumber);
|
||||
// Error handling for missing page
|
||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
getdisplay().fillScreen(commonData.bgcolor); // Clear display
|
||||
getdisplay().drawXBitmap(200 - unknown_width / 2, 150 - unknown_height / 2, unknown_bits, unknown_width, unknown_height, commonData.fgcolor);
|
||||
getdisplay().setCursor(140, 250);
|
||||
getdisplay().setFont(&Atari16px);
|
||||
getdisplay().print("Here be dragons!");
|
||||
getdisplay().nextPage(); // Partial update (fast)
|
||||
}
|
||||
else{
|
||||
if (lastPage != pageNumber){
|
||||
if (hasFRAM) fram.write(FRAM_PAGE_NO, pageNumber); // remember page for device restart
|
||||
currentPage->setupKeys();
|
||||
currentPage->displayNew(pages[pageNumber].parameters);
|
||||
lastPage=pageNumber;
|
||||
}
|
||||
//call the page code
|
||||
LOG_DEBUG(GwLog::DEBUG,"calling page %d",pageNumber);
|
||||
// Show footer if enabled (together with header)
|
||||
if (pages[pageNumber].description && pages[pageNumber].description->header){
|
||||
displayFooter(commonData);
|
||||
}
|
||||
currentPage->displayPage(pages[pageNumber].parameters);
|
||||
}
|
||||
|
||||
}
|
||||
} // refresh display all 1s
|
||||
}
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -917,7 +917,7 @@ void setup() {
|
|||
logger.flush();
|
||||
NMEA2000.SetMode(tNMEA2000::N2km_ListenAndNode, NodeAddress);
|
||||
NMEA2000.SetForwardOwnMessages(false);
|
||||
NMEA2000.SetHeartbeatIntervalAndOffset(NMEA2000_HEARTBEAT_INTERVAL);
|
||||
NMEA2000.SetHeartbeatInterval(NMEA2000_HEARTBEAT_INTERVAL);
|
||||
if (sendOutN2k){
|
||||
// Set the information for other bus devices, which messages we support
|
||||
unsigned long *pgns=toN2KConverter->handledPgns();
|
||||
|
|
Loading…
Reference in New Issue