First design experiments for barograph

This commit is contained in:
Thomas Hooge 2024-12-21 10:25:53 +01:00
parent 2a19a2e615
commit c5e346f4eb
7 changed files with 368 additions and 12 deletions

View File

@ -179,6 +179,24 @@ String xdrDelete(String input){
return input; return input;
} }
// Draw centered text
void drawTextCenter(int16_t cx, int16_t cy, String text) {
int16_t x1, y1;
uint16_t w, h;
getdisplay().getTextBounds(text, 0, 150, &x1, &y1, &w, &h);
getdisplay().setCursor(cx - w / 2, cy + h / 2);
getdisplay().print(text);
}
// Draw right aligned text
void drawTextRalign(int16_t x, int16_t y, String text) {
int16_t x1, y1;
uint16_t w, h;
getdisplay().getTextBounds(text, 0, 150, &x1, &y1, &w, &h);
getdisplay().setCursor(x - w, y);
getdisplay().print(text);
}
// Show a triangle for trend direction high (x, y is the left edge) // Show a triangle for trend direction high (x, y is the left edge)
void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color){ void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color){
getdisplay().fillTriangle(x, y, x+size*2, y, x+size, y-size*2, color); getdisplay().fillTriangle(x, y, x+size*2, y, x+size, y-size*2, color);

View File

@ -58,6 +58,9 @@ void setBuzzerPower(uint power); // Set buzzer power
String xdrDelete(String input); // Delete xdr prefix from string String xdrDelete(String input); // Delete xdr prefix from string
void drawTextCenter(int16_t cx, int16_t cy, String text);
void drawTextRalign(int16_t x, int16_t y, String text);
void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color); void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color);
void displayTrendLow(int16_t x, int16_t y, uint16_t size, uint16_t color); void displayTrendLow(int16_t x, int16_t y, uint16_t size, uint16_t color);

View File

@ -0,0 +1,228 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageBarograph : public Page{
bool keylock = false;
bool has_fram = false;
String flashLED;
String useenvsensor;
char source = 'I'; // (I)nternal, e(X)ternal
const int series[5] = {75, 150, 300, 600, 900};
const int zoom[5] = {1, 2, 3, 6, 12};
int zoomindex = 4;
uint16_t data[336] = {0}; // current data to display
// y-axis
uint16_t vmin;
uint16_t vmax;
uint16_t scalemin = 1000;
uint16_t scalemax = 1020;
uint16_t scalestep = 5;
int hist1 = 0; // one hour trend
int hist3 = 0; // three hours trend
long refresh = 0; // millis
void loadData() {
// Transfer data from history to page buffer,
// set y-axis according to data
int i = zoom[zoomindex];
// get min and max values of measured data
vmin = data[0];
vmax = data[0];
for (int x = 0; x < 336; x++) {
if (data[x] != 0) {
if (data[x] < vmin) {
vmin = data[x];
} else if (data[x] > vmax) {
vmax = data[x];
}
}
}
// calculate y-axis scale
uint16_t diff = vmax - vmin;
if (diff < 20) {
scalestep = 5;
} else if (diff < 40) {
scalestep = 10;
} else {
scalestep = 15;
}
scalemin = vmin - (vmin % scalestep);
scalemax = vmax + scalestep - (vmax % scalestep);
// TODO implement history buffer
};
public:
PageBarograph(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Instantiate PageBarograph");
// Get config data
flashLED = common.config->getString(common.config->flashLED);
useenvsensor = common.config->getString(common.config->useEnvSensor);
// possible values for internal sensor
static std::vector<String> sensorList = {
"BME280", "BMP280", "BMP180", "BMP085", "HTU21", "SHT21"
};
if (std::find(sensorList.begin(), sensorList.end(), useenvsensor) != sensorList.end()) {
source = 'I';
} else {
// "off" means user external data if available
source = 'X';
}
//common.logger->logDebug(GwLog::LOG,"Source=%s (%s)", source, useenvsensor);
loadData(); // initial load
}
virtual int handleKey(int key) {
if (key == 1) {
// zoom in
if (zoomindex > 0) {
zoomindex -= 1;
}
return 0;
}
if (key == 2) {
// zoom out
if (zoomindex < sizeof(zoom)) {
zoomindex += 1;
}
return 0;
}
if (key == 11) {
keylock = !keylock;
return 0;
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwLog *logger=commonData.logger;
// Optical warning by limit violation (unused)
if (String(flashLED) == "Limit Violation") {
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
LOG_DEBUG(GwLog::LOG,"Drawing at PageBarograph");
// Draw page
//***********************************************************
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// Frames
getdisplay().fillRect(0, 75, 400, 2, commonData.fgcolor); // fillRect: x, y, w, h
getdisplay().fillRect(130, 20, 2, 55, commonData.fgcolor);
getdisplay().fillRect(270, 20, 2, 55, commonData.fgcolor);
getdisplay().fillRect(325, 20, 2, 55, commonData.fgcolor);
getdisplay().setTextColor(commonData.fgcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if (source == 'I') {
drawTextCenter(360, 40, useenvsensor);
} else {
drawTextCenter(360, 40, "ext.");
}
// Trend
drawTextCenter(295, 62, "0.0");
// Alarm placeholder
drawTextCenter(70, 62, "Alarm Off");
// Zoom
int datastep = series[zoomindex];
String fmt;
if (datastep > 120) {
if (datastep % 60 == 0) {
fmt = String(datastep / 60.0, 0) + " min";
} else {
fmt = String(datastep / 60.0, 1) + " min";
}
} else {
fmt = String(datastep) + " s";
}
drawTextCenter(360, 62, fmt);
// Current measurement
getdisplay().setFont(&Ubuntu_Bold16pt7b);
drawTextCenter(200, 40, String(commonData.data.airPressure / 100, 1));
getdisplay().setFont(&Ubuntu_Bold8pt7b);
drawTextCenter(200, 62, "hPa"); // Unit
// Diagram
const int xstep = 48; // x-axis-grid
const int x0 = 350; // origin
const int y0 = 270;
const int w = 7 * 48;
const int h = 180;
// getdisplay().drawRect(x0 - w, y0 - h, w, h, commonData.fgcolor);
// x-axis are hours
for (int i = 1; i <= 6; i++) {
String label = String(-1 * zoom[zoomindex] * i);
getdisplay().drawLine(x0 - i * xstep, y0, x0 - i * xstep, y0 - h, commonData.fgcolor);
drawTextCenter(x0 - i * xstep, y0 - 10, label);
}
// y-axis
getdisplay().drawLine(x0 + 5, y0, x0 + 5, y0 - h, commonData.fgcolor); // drawLine: x1, y1, x2, y2
getdisplay().drawLine(x0 - w, y0, x0 - w, y0 - h, commonData.fgcolor);
getdisplay().drawLine(x0 - w - 5, y0, x0 - w - 5, y0 - h, commonData.fgcolor);
getdisplay().drawLine(x0, y0, x0, y0 - h, commonData.fgcolor);
int16_t dy = 9; // px for one hPa
int16_t y = y0;
int16_t ys = scalemin;
while (y >= y0 - h) {
if (y % scalestep == 0) {
// big step, show label and long line
getdisplay().setCursor(x0 + 10, y + 5);
getdisplay().print(String(ys));
getdisplay().drawLine(x0 + 5, y, x0 - w - 5, y, commonData.fgcolor);
} else {
// small step, only short lines left and right
getdisplay().drawLine(x0 + 5, y, x0, y, commonData.fgcolor);
getdisplay().drawLine(x0 - w - 5, y, x0 - w, y, commonData.fgcolor);
}
y -= dy;
ys += 1;
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page* createPage(CommonData &common){
return new PageBarograph(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 registerPageBarograph(
"Barograph", // Page name
createPage, // Action
0, // No bus values needed
true // Show display header on/off
);
#endif

View File

@ -904,7 +904,7 @@
"type": "list", "type": "list",
"default": "Voltage", "default": "Voltage",
"description": "Type of page for page 1", "description": "Type of page for page 1",
"list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"], "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid","Barograph"],
"category": "OBP60 Page 1", "category": "OBP60 Page 1",
"capabilities": { "capabilities": {
"obp60":"true" "obp60":"true"
@ -1009,7 +1009,7 @@
"type": "list", "type": "list",
"default": "WindRose", "default": "WindRose",
"description": "Type of page for page 2", "description": "Type of page for page 2",
"list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"], "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid","Barograph"],
"category": "OBP60 Page 2", "category": "OBP60 Page 2",
"capabilities": { "capabilities": {
"obp60":"true" "obp60":"true"
@ -1115,7 +1115,7 @@
"type": "list", "type": "list",
"default": "OneValue", "default": "OneValue",
"description": "Type of page for page 3", "description": "Type of page for page 3",
"list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"], "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid","Barograph"],
"category": "OBP60 Page 3", "category": "OBP60 Page 3",
"capabilities": { "capabilities": {
"obp60":"true" "obp60":"true"
@ -1221,7 +1221,7 @@
"type": "list", "type": "list",
"default": "TwoValues", "default": "TwoValues",
"description": "Type of page for page 4", "description": "Type of page for page 4",
"list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"], "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid","Barograph"],
"category": "OBP60 Page 4", "category": "OBP60 Page 4",
"capabilities": { "capabilities": {
"obp60":"true" "obp60":"true"
@ -1327,7 +1327,7 @@
"type": "list", "type": "list",
"default": "ThreeValues", "default": "ThreeValues",
"description": "Type of page for page 5", "description": "Type of page for page 5",
"list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"], "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid","Barograph"],
"category": "OBP60 Page 5", "category": "OBP60 Page 5",
"capabilities": { "capabilities": {
"obp60":"true" "obp60":"true"
@ -1433,7 +1433,7 @@
"type": "list", "type": "list",
"default": "FourValues", "default": "FourValues",
"description": "Type of page for page 6", "description": "Type of page for page 6",
"list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"], "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid","Barograph"],
"category": "OBP60 Page 6", "category": "OBP60 Page 6",
"capabilities": { "capabilities": {
"obp60":"true" "obp60":"true"
@ -1539,7 +1539,7 @@
"type": "list", "type": "list",
"default": "FourValues2", "default": "FourValues2",
"description": "Type of page for page 7", "description": "Type of page for page 7",
"list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"], "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid","Barograph"],
"category": "OBP60 Page 7", "category": "OBP60 Page 7",
"capabilities": { "capabilities": {
"obp60":"true" "obp60":"true"
@ -1645,7 +1645,7 @@
"type": "list", "type": "list",
"default": "Clock", "default": "Clock",
"description": "Type of page for page 8", "description": "Type of page for page 8",
"list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"], "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid","Barograph"],
"category": "OBP60 Page 8", "category": "OBP60 Page 8",
"capabilities": { "capabilities": {
"obp60":"true" "obp60":"true"
@ -1751,7 +1751,7 @@
"type": "list", "type": "list",
"default": "RollPitch", "default": "RollPitch",
"description": "Type of page for page 9", "description": "Type of page for page 9",
"list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"], "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid","Barograph"],
"category": "OBP60 Page 9", "category": "OBP60 Page 9",
"capabilities": { "capabilities": {
"obp60":"true" "obp60":"true"
@ -1857,7 +1857,7 @@
"type": "list", "type": "list",
"default": "Battery2", "default": "Battery2",
"description": "Type of page for page 10", "description": "Type of page for page 10",
"list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"], "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid","Barograph"],
"category": "OBP60 Page 10", "category": "OBP60 Page 10",
"capabilities": { "capabilities": {
"obp60":"true" "obp60":"true"

84
lib/obp60task/hbuffer.cpp Normal file
View File

@ -0,0 +1,84 @@
/* History Buffer
*
* Storage backed buffer for sensordata
* Permanent storage only supported type: FRAM on I2C-Bus
*
* Values can be 1 to 4 bytes in length
*
* Header: 32 bytes of size
* 0 0x00 HB00 4 magic number
* 4 0x04 xxxxxxxxxxxxxxxx 16 name, space padded
* 20 0x14 n 1 byte size of values in buffer
* 21 0x15 mm 2 buffer size in count of values
* 23 0x17 dd 2 time step in seconds between values
* 25 0x19 tttt 4 unix timestamp of head
* 29 0x1d hh 2 head pointer
* 31 0x1f 0xff 1 header end sign
*
* 32 0x20 ... start of buffer data
*
* Usage example: 7 hours of data collected every 75 seconds
* TODO
*
*/
#include <stdint.h>
#include <time.h>
class HistoryBuffer {
private:
// Header prototype for permanent storage
uint8_t header[32] = {
0x41, 0x48, 0x30, 0x30, // magic: HB00
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, // empty name
0x01, // byte size
0x50, 0x01, // value count
0x4b, 0x00, // time step
0x00, 0x00, 0x00, 0x00, // unix time stamp
0x00, 0x00, // head pointer
0xff // end sign
};
uint16_t head = 0; // head pointer to next new value position
time_t timestamp; // last modification time of head
uint16_t delta_t; // time step in seconds
public:
HistoryBuffer(uint16_t size) {
}
~HistoryBuffer() {
// free memory
}
void begin() {
//
}
void finish() {
}
uint16_t add() {
// returns new head value pointer
}
uint8_t* get() {
// returns complete buffer in order new to old
}
uint8_t getvalue(uint16_t dt) {
// Return a single value delta seconds ago
uint16_t index = head - abs(dt) / delta_t;
return 0;
}
uint8_t getvalue3() {
}
bool clear() {
// clears buffer and permanent storage
return true;
}
};
class History {
public:
History() {
}
~History() {
}
void *addSeries() {
}
};

21
lib/obp60task/hbuffer.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef __HBUFFER_H__
#define __HBUFFER_H__
class HistoryBuffer {
public:
HistoryBuffer(uint16_t size);
void begin();
void finish();
uint16_t add();
uint8_t* get() ;
uint8_t getvalue(uint16_t dt);
uint8_t getvalue3();
void clear();
};
class History {
public:
History();
void *addSeries();
};
#endif

View File

@ -246,6 +246,8 @@ void registerAllPages(PageList &list){
list.add(&registerPageXTETrack); list.add(&registerPageXTETrack);
extern PageDescription registerPageFluid; extern PageDescription registerPageFluid;
list.add(&registerPageFluid); list.add(&registerPageFluid);
extern PageDescription registerPageBarograph;
list.add(&registerPageBarograph);
} }
// Undervoltage detection for shutdown display // Undervoltage detection for shutdown display