mirror of
https://github.com/thooge/esp32-nmea2000-obp60.git
synced 2025-12-23 18:53:06 +01:00
Compare commits
34 Commits
barograph
...
2fd11c72b6
| Author | SHA1 | Date | |
|---|---|---|---|
| 2fd11c72b6 | |||
| 235cfd1c9c | |||
| 16e7b80230 | |||
| 5f5c520714 | |||
|
|
47db247471 | ||
|
|
6ffa974354 | ||
|
|
d2ee05a353 | ||
|
|
574deac6f8 | ||
|
|
bbdbe47972 | ||
|
|
9fc090a5a8 | ||
|
|
71673e78bd | ||
| 970d05191c | |||
|
|
695013cb88 | ||
| 81a6c05b55 | |||
|
|
bedb8338ab | ||
| 8d43189140 | |||
| be48929c40 | |||
|
|
1a43fe29e9 | ||
|
|
9930769073 | ||
|
|
83f3e6f24b | ||
|
|
a8d1080429 | ||
|
|
b142470c1d | ||
|
|
b91f345d25 | ||
| 6637b80400 | |||
|
|
707ac9b84f | ||
|
|
2808c56a37 | ||
| 319f3f3e68 | |||
| 6e256e136a | |||
| daaefc7eba | |||
| 3bc0082bb8 | |||
| 0274b5d755 | |||
|
|
df5ff1c91a | ||
| c7b6bafde8 | |||
| 21ae96c8d7 |
56
boards/obp60_s3_light_n8r8.json
Normal file
56
boards/obp60_s3_light_n8r8.json
Normal file
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino":{
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"partitions": "default_8MB.csv",
|
||||
"memory_type": "qio_opi"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DBOARD_HAS_PSRAM",
|
||||
"-DARDUINO_ESP32S3_DEV",
|
||||
"-DARDUINO_USB_MODE=1",
|
||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||
"-DARDUINO_RUNNING_CORE=1",
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"hwids": [
|
||||
[
|
||||
"0x303A",
|
||||
"0x1001"
|
||||
]
|
||||
],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "obp60s3_light"
|
||||
},
|
||||
"connectivity": [
|
||||
"bluetooth",
|
||||
"wifi"
|
||||
],
|
||||
"debug": {
|
||||
"default_tool": "esp-builtin",
|
||||
"onboard_tools": [
|
||||
"esp-builtin"
|
||||
],
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino",
|
||||
"espidf"
|
||||
],
|
||||
"name": "OBP60 Light ESP32-S3-N8R8 (8 MB QD, 8 MB PSRAM)",
|
||||
"upload": {
|
||||
"flash_size": "8MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 8388608,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": true,
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"url": "https://open-boat-projects.org/en/diy-multifunktionsdisplay-obp-60/",
|
||||
"vendor": "Open Boat Projects"
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "GwApi.h"
|
||||
#include "OBP60Hardware.h"
|
||||
|
||||
|
||||
class Color{
|
||||
public:
|
||||
uint8_t r;
|
||||
@@ -92,5 +91,4 @@ class LedTaskData{
|
||||
//task function
|
||||
void createSpiLedTask(LedTaskData *param);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,9 +1,6 @@
|
||||
#ifdef BOARD_OBP60S3
|
||||
|
||||
#include <Arduino.h>
|
||||
#define FASTLED_ALL_PINS_HARDWARE_SPI
|
||||
#define FASTLED_ESP32_SPI_BUS FSPI
|
||||
#define FASTLED_ESP32_FLASH_LOCK 1
|
||||
#include <PCF8574.h> // Driver for PCF8574 output modul from Horter
|
||||
#include <Wire.h> // I2C
|
||||
#include <RTClib.h> // Driver for DS1388 RTC
|
||||
@@ -11,6 +8,7 @@
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Hardware.h"
|
||||
#include "OBP60Extensions.h"
|
||||
#include "imglib.h"
|
||||
|
||||
// Character sets
|
||||
#include "Ubuntu_Bold8pt7b.h"
|
||||
@@ -60,6 +58,10 @@ GxEPD2_BW<GxEPD2_420_SE0420NQ04, GxEPD2_420_SE0420NQ04::HEIGHT> & getdisplay(){r
|
||||
// Horter I2C moduls
|
||||
PCF8574 pcf8574_Out(PCF8574_I2C_ADDR1); // First digital output modul PCF8574 from Horter
|
||||
|
||||
// FRAM
|
||||
Adafruit_FRAM_I2C fram;
|
||||
bool hasFRAM = false;
|
||||
|
||||
// Global vars
|
||||
bool blinkingLED = false; // Enable / disable blinking flash LED
|
||||
bool statusLED = false; // Actual status of flash LED on/off
|
||||
@@ -69,7 +71,7 @@ int uvDuration = 0; // Under voltage duration in n x 100ms
|
||||
|
||||
LedTaskData *ledTaskData=nullptr;
|
||||
|
||||
void hardwareInit()
|
||||
void hardwareInit(GwApi *api)
|
||||
{
|
||||
Wire.begin();
|
||||
// Init PCF8574 digital outputs
|
||||
@@ -77,12 +79,27 @@ void hardwareInit()
|
||||
if(pcf8574_Out.begin()){ // Initialize PCF8574
|
||||
pcf8574_Out.write8(255); // Clear all outputs
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void startLedTask(GwApi *api){
|
||||
ledTaskData=new LedTaskData(api);
|
||||
createSpiLedTask(ledTaskData);
|
||||
fram = Adafruit_FRAM_I2C();
|
||||
if (esp_reset_reason() == ESP_RST_POWERON) {
|
||||
// help initialize FRAM
|
||||
api->getLogger()->logDebug(GwLog::LOG,"Delaying I2C init for 250ms due to cold boot");
|
||||
delay(250);
|
||||
}
|
||||
// FRAM (e.g. MB85RC256V)
|
||||
if (fram.begin(FRAM_I2C_ADDR)) {
|
||||
hasFRAM = true;
|
||||
uint16_t manufacturerID;
|
||||
uint16_t productID;
|
||||
fram.getDeviceID(&manufacturerID, &productID);
|
||||
// Boot counter
|
||||
uint8_t framcounter = fram.read(0x0000);
|
||||
fram.write(0x0000, framcounter+1);
|
||||
api->getLogger()->logDebug(GwLog::LOG,"FRAM detected: 0x%04x/0x%04x (counter=%d)", manufacturerID, productID, framcounter);
|
||||
}
|
||||
else {
|
||||
hasFRAM = false;
|
||||
api->getLogger()->logDebug(GwLog::LOG,"NO FRAM detected");
|
||||
}
|
||||
}
|
||||
|
||||
void setPortPin(uint pin, bool value){
|
||||
@@ -95,6 +112,11 @@ void togglePortPin(uint pin){
|
||||
digitalWrite(pin, !digitalRead(pin));
|
||||
}
|
||||
|
||||
void startLedTask(GwApi *api){
|
||||
ledTaskData=new LedTaskData(api);
|
||||
createSpiLedTask(ledTaskData);
|
||||
}
|
||||
|
||||
// Valid colors see hue
|
||||
Color colorMapping(const String &colorString){
|
||||
Color color = COLOR_RED;
|
||||
@@ -179,6 +201,30 @@ String xdrDelete(String input){
|
||||
return input;
|
||||
}
|
||||
|
||||
Point rotatePoint(const Point& origin, const Point& p, double angle) {
|
||||
// rotate poind around origin by degrees
|
||||
Point rotated;
|
||||
double phi = angle * M_PI / 180.0;
|
||||
double dx = p.x - origin.x;
|
||||
double dy = p.y - origin.y;
|
||||
rotated.x = origin.x + cos(phi) * dx - sin(phi) * dy;
|
||||
rotated.y = origin.y + sin(phi) * dx + cos(phi) * dy;
|
||||
return rotated;
|
||||
}
|
||||
|
||||
std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle) {
|
||||
std::vector<Point> rotatedPoints;
|
||||
for (const auto& p : pts) {
|
||||
rotatedPoints.push_back(rotatePoint(origin, p, angle));
|
||||
}
|
||||
return rotatedPoints;
|
||||
}
|
||||
|
||||
void fillPoly4(const std::vector<Point>& p4, uint16_t color) {
|
||||
getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[1].x, p4[1].y, p4[2].x, p4[2].y, color);
|
||||
getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[2].x, p4[2].y, p4[3].x, p4[3].y, color);
|
||||
}
|
||||
|
||||
// Draw centered text
|
||||
void drawTextCenter(int16_t cx, int16_t cy, String text) {
|
||||
int16_t x1, y1;
|
||||
@@ -422,4 +468,45 @@ void generatorGraphic(uint x, uint y, int pcolor, int bcolor){
|
||||
getdisplay().print("G");
|
||||
}
|
||||
|
||||
// Function to handle HTTP image request
|
||||
// http://192.168.15.1/api/user/OBP60Task/screenshot
|
||||
void doImageRequest(GwApi *api, int *pageno, const PageStruct pages[MAX_PAGE_NUMBER], AsyncWebServerRequest *request) {
|
||||
GwLog *logger = api->getLogger();
|
||||
|
||||
String imgformat = api->getConfig()->getConfigItem(api->getConfig()->imageFormat,true)->asString();
|
||||
imgformat.toLowerCase();
|
||||
String filename = "Page" + String(*pageno) + "_" + pages[*pageno].description->pageName + "." + imgformat;
|
||||
|
||||
logger->logDebug(GwLog::LOG,"handle image request [%s]: %s", imgformat, filename);
|
||||
|
||||
uint8_t *fb = getdisplay().getBuffer(); // EPD framebuffer
|
||||
std::vector<uint8_t> imageBuffer; // image in webserver transferbuffer
|
||||
String mimetype;
|
||||
|
||||
if (imgformat == "gif") {
|
||||
// GIF is commpressed with LZW, so small
|
||||
mimetype = "image/gif";
|
||||
if (!createGIF(fb, &imageBuffer, GxEPD_WIDTH, GxEPD_HEIGHT)) {
|
||||
logger->logDebug(GwLog::LOG,"GIF creation failed: Hashtable init error!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (imgformat == "bmp") {
|
||||
// Microsoft BMP bitmap
|
||||
mimetype = "image/bmp";
|
||||
createBMP(fb, &imageBuffer, GxEPD_WIDTH, GxEPD_HEIGHT);
|
||||
}
|
||||
else {
|
||||
// PBM simple portable bitmap
|
||||
mimetype = "image/x-portable-bitmap";
|
||||
createPBM(fb, &imageBuffer, GxEPD_WIDTH, GxEPD_HEIGHT);
|
||||
}
|
||||
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, mimetype, (const uint8_t*)imageBuffer.data(), imageBuffer.size());
|
||||
response->addHeader("Content-Disposition", "inline; filename=" + filename);
|
||||
request->send(response);
|
||||
|
||||
imageBuffer.clear();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,11 +3,24 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "OBP60Hardware.h"
|
||||
#define FASTLED_ALL_PINS_HARDWARE_SPI
|
||||
#define FASTLED_ESP32_SPI_BUS FSPI
|
||||
#define FASTLED_ESP32_FLASH_LOCK 1
|
||||
#include "LedSpiTask.h"
|
||||
#include <GxEPD2_BW.h> // E-paper lib V2
|
||||
#include <Adafruit_FRAM_I2C.h> // I2C FRAM
|
||||
|
||||
// FRAM address reservations 32kB: 0x0000 - 0x7FFF
|
||||
// 0x0000 - 0x03ff: single variables
|
||||
#define FRAM_VOLTAGE_AVG 0x000A
|
||||
#define FRAM_VOLTAGE_TREND 0x000B
|
||||
#define FRAM_VOLTAGE_MODE 0x000C
|
||||
#define FRAM_WIND_SIZE 0x000D
|
||||
#define FRAM_WIND_SRC 0x000E
|
||||
#define FRAM_WIND_MODE 0x000F
|
||||
// Barograph history data
|
||||
#define FRAM_BAROGRAPH_START 0x0400
|
||||
#define FRAM_BAROGRAPH_END 0x13FF
|
||||
|
||||
extern Adafruit_FRAM_I2C fram;
|
||||
extern bool hasFRAM;
|
||||
|
||||
// Fonts declarations for display (#inclues see OBP60Extensions.cpp)
|
||||
extern const GFXfont Ubuntu_Bold8pt7b;
|
||||
@@ -39,7 +52,15 @@ GxEPD2_BW<GxEPD2_420_GYE042A87, GxEPD2_420_GYE042A87::HEIGHT> & getdisplay();
|
||||
GxEPD2_BW<GxEPD2_420_SE0420NQ04, GxEPD2_420_SE0420NQ04::HEIGHT> & getdisplay();
|
||||
#endif
|
||||
|
||||
void hardwareInit();
|
||||
struct Point {
|
||||
double x;
|
||||
double y;
|
||||
};
|
||||
Point rotatePoint(const Point& origin, const Point& p, double angle);
|
||||
std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle);
|
||||
void fillPoly4(const std::vector<Point>& p4, uint16_t color);
|
||||
|
||||
void hardwareInit(GwApi *api);
|
||||
|
||||
void setPortPin(uint pin, bool value); // Set port pin for extension port
|
||||
|
||||
@@ -73,4 +94,13 @@ void solarGraphic(uint x, uint y, int pcolor, int bcolor); // S
|
||||
void generatorGraphic(uint x, uint y, int pcolor, int bcolor); // Generator graphic with fill level
|
||||
void startLedTask(GwApi *api);
|
||||
|
||||
void doImageRequest(GwApi *api, int *pageno, const PageStruct pages[MAX_PAGE_NUMBER], AsyncWebServerRequest *request);
|
||||
|
||||
#define fram_width 16
|
||||
#define fram_height 16
|
||||
static unsigned char fram_bits[] = {
|
||||
0xf8, 0x1f, 0xff, 0xff, 0x9f, 0xff, 0x98, 0x1f, 0xf8, 0x1f, 0xff, 0xff,
|
||||
0xff, 0xff, 0xf8, 0x1f, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f,
|
||||
0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f };
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// General hardware definitions
|
||||
// CAN and RS485 bus pin definitions see obp60task.h
|
||||
|
||||
#ifdef HARDWARE_V21
|
||||
// Direction pin for RS485 NMEA0183
|
||||
#define OBP_DIRECTION_PIN 18
|
||||
// I2C
|
||||
@@ -30,6 +31,8 @@
|
||||
#define INA226_I2C_ADDR3 0x45 // Addr. 0x45 (fix A0 = 5V, A1 = 5V) for generator
|
||||
// Horter modules
|
||||
#define PCF8574_I2C_ADDR1 0x20 // First digital out module
|
||||
// FRAM (e.g. MB85RC256V)
|
||||
#define FRAM_I2C_ADDR 0x50
|
||||
// SPI (E-Ink display, Extern Bus)
|
||||
#define OBP_SPI_CS 39
|
||||
#define OBP_SPI_DC 40
|
||||
@@ -39,11 +42,6 @@
|
||||
#define OBP_SPI_DIN 48
|
||||
#define SHOW_TIME 6000 // Show time in [ms] for logo and WiFi QR code
|
||||
#define FULL_REFRESH_TIME 600 // Refresh cycle time in [s][600...3600] for full display update (very important healcy function)
|
||||
#define MAX_PAGE_NUMBER 10 // Max number of pages for show data
|
||||
#define FONT1 "Ubuntu_Bold8pt7b"
|
||||
#define FONT2 "Ubuntu_Bold24pt7b"
|
||||
#define FONT3 "Ubuntu_Bold32pt7b"
|
||||
#define FONT4 "DSEG7Classic_BoldItalic80pt7b"
|
||||
|
||||
// GPS (NEO-6M, NEO-M8N, ATGM336H)
|
||||
#define OBP_GPS_RX 2
|
||||
@@ -57,7 +55,7 @@
|
||||
#define TONE3 3500 // 3500Hz
|
||||
#define TONE4 4000 // 4000Hz
|
||||
// Analog Input
|
||||
#define OBP_ANALOG0 4 // Analog input for voltage power supplay
|
||||
#define OBP_ANALOG0 4 // Analog input for voltage power supply
|
||||
#define MIN_VOLTAGE 10.0 // Min voltage for under voltage detection (then goto deep sleep)
|
||||
#define POWER_FAIL_TIME 2 // in [ms] Accept min voltage until 2 x 1ms (for under voltage gaps by engine start)
|
||||
// Touch buttons
|
||||
@@ -72,9 +70,92 @@
|
||||
#define NUM_FLASH_LED 1 // Number of flash LED
|
||||
#define OBP_FLASH_LED 7 // GPIO port
|
||||
// Backlight LEDs (6x WS2812B)
|
||||
#define NUM_BACKLIGHT_LED 6 // Numebr of Backlight LEDs
|
||||
#define NUM_BACKLIGHT_LED 6 // Number of Backlight LEDs
|
||||
#define OBP_BACKLIGHT_LED 15 // GPIO port
|
||||
// Power Rail
|
||||
#define OBP_POWER_50 5 // 5.0V power rail
|
||||
#endif
|
||||
|
||||
// Hardware configuration for OBP60 LIGHT
|
||||
|
||||
#ifdef HARDWARE_LIGHT
|
||||
// Direction pin for RS485 NMEA0183
|
||||
#define OBP_DIRECTION_PIN 8
|
||||
// I2C
|
||||
#define I2C_SPEED 10000UL // 10kHz clock speed on I2C bus
|
||||
#define OBP_I2C_SDA 21
|
||||
#define OBP_I2C_SCL 38
|
||||
// DS1388 RTC
|
||||
#define DS1388_I2C_ADDR 0x68 // Addr. 0x68
|
||||
// BME280
|
||||
#define BME280_I2C_ADDR 0x76 // Addr. 0x76 (0x77)
|
||||
// BMP280
|
||||
#define BMP280_I2C_ADDR 0x77 // Addr. 0x77 (0x76) Attention: Pull up resistor
|
||||
// BMP085 / BMP180
|
||||
#define BMP180_I2C_ADDR 0x77 // Addr. 0x77 (fix)
|
||||
// SHT21 / HUT21
|
||||
#define SHT21_I2C_ADDR 0x40 // Addr. 0x40 (fix)
|
||||
// AS5600
|
||||
#define AS5600_I2C_ADDR 0x36 // Addr. 0x36 (fix)
|
||||
// INA219
|
||||
#define SHUNT_VOLTAGE 0.075 // Shunt voltage in V by max. current (75mV)
|
||||
#define INA219_I2C_ADDR1 0x40 // Addr. 0x41 (fix A0 = 5V, A1 = GND) for battery
|
||||
#define INA219_I2C_ADDR2 0x41 // Addr. 0x44 (fix A0 = GND, A1 = 5V) for solar panels
|
||||
#define INA219_I2C_ADDR3 0x45 // Addr. 0x45 (fix A0 = 5V, A1 = 5V) for generator
|
||||
// INA226
|
||||
#define INA226_I2C_ADDR1 0x41 // Addr. 0x41 (fix A0 = 5V, A1 = GND) for battery
|
||||
#define INA226_I2C_ADDR2 0x44 // Addr. 0x44 (fix A0 = GND, A1 = 5V) for solar panels
|
||||
#define INA226_I2C_ADDR3 0x45 // Addr. 0x45 (fix A0 = 5V, A1 = 5V) for generator
|
||||
// Horter modules
|
||||
#define PCF8574_I2C_ADDR1 0x20 // First digital out module
|
||||
// FRAM (e.g. MB85RC256V)
|
||||
#define FRAM_I2C_ADDR 0x50
|
||||
// SPI (E-Ink display, Extern Bus)
|
||||
#define OBP_SPI_CS 45
|
||||
#define OBP_SPI_DC 46
|
||||
#define OBP_SPI_RST 47
|
||||
#define OBP_SPI_BUSY 48
|
||||
#define OBP_SPI_CLK 12
|
||||
#define OBP_SPI_DIN 11
|
||||
#define SHOW_TIME 6000 // Show time in [ms] for logo and WiFi QR code
|
||||
#define FULL_REFRESH_TIME 600 // Refresh cycle time in [s][600...3600] for full display update (very important healcy function)
|
||||
// SPI SD-Card
|
||||
#define SD_SPI_CS 10
|
||||
#define SD_SPI_MOSI 40
|
||||
#define SD_SPI_CLK 39
|
||||
#define SD_SPI_MISO 13
|
||||
|
||||
// GPS (NEO-6M, NEO-M8N, ATGM336H)
|
||||
#define OBP_GPS_RX 19
|
||||
#define OBP_GPS_TX 20
|
||||
// 1Wire (DS18B20)
|
||||
#define OBP_1WIRE 17 // External 1Wire
|
||||
// Buzzer
|
||||
#define OBP_BUZZER 18
|
||||
#define TONE1 1500 // 1500Hz
|
||||
#define TONE2 2500 // 2500Hz
|
||||
#define TONE3 3500 // 3500Hz
|
||||
#define TONE4 4000 // 4000Hz
|
||||
// Analog Input
|
||||
#define OBP_ANALOG0 3 // Analog input for voltage power supply
|
||||
#define MIN_VOLTAGE 10.0 // Min voltage for under voltage detection (then goto deep sleep)
|
||||
#define POWER_FAIL_TIME 2 // in [ms] Accept min voltage until 2 x 1ms (for under voltage gaps by engine start)
|
||||
// Buttons
|
||||
#define UP 6 // Wheel up
|
||||
#define DOWN 4 // Wheel down
|
||||
#define CONF 5 // Wheel press
|
||||
#define MENUE 2 // Button top
|
||||
#define EXIT 1 // Button bottom
|
||||
|
||||
// Flash LED (1x WS2812B)
|
||||
#define NUM_FLASH_LED 1 // Number of flash LED
|
||||
#define OBP_FLASH_LED 10 // GPIO port
|
||||
// Backlight LEDs (6x WS2812B)
|
||||
#define NUM_BACKLIGHT_LED 6 // Number of Backlight LEDs
|
||||
#define OBP_BACKLIGHT_LED 40 // GPIO port
|
||||
// Power Rail
|
||||
#define OBP_POWER_50 41 // Power LED
|
||||
#define OBP_POWER_EPD 7 // ePaper power
|
||||
#define OBP_POWER_SD 42 // SD card power
|
||||
#endif
|
||||
|
||||
|
||||
@@ -14,167 +14,223 @@ int keycode = 0; // Keycode of pressed key [0...8], 0 = nothing touched
|
||||
int keycode2 = 0; // Keycode of very short pressed key [0...8], 0 = nothing touched
|
||||
int keycodeold = 0; // Old keycode
|
||||
int keycodeold2 = 0; // Old keycode for short pressed key
|
||||
int keystatus = 0; // Status of key [0...11]
|
||||
bool keyoff = false; // Disable all keys
|
||||
int keydelay = 250; // Delay after key pressed in [ms]
|
||||
bool keylock = false; // Key lock after pressed key is valid (repeat protection by conginous pressing)
|
||||
long starttime = 0; // Start time point for pressed key
|
||||
|
||||
#ifdef HARDWARE_V21
|
||||
// Keypad functions for original OBP60 hardware
|
||||
int readKeypad(uint thSensitivity) {
|
||||
|
||||
// Touch sensor values
|
||||
// 35000 - Not touched
|
||||
// 50000 - Light toched with fingertip
|
||||
// 70000 - Touched
|
||||
// 170000 - Strong touched
|
||||
uint32_t touchthreshold = (thSensitivity * -1200) + 170000; // thSensitivity 0...100%
|
||||
|
||||
int readKeypad(uint thSensitivity) {
|
||||
|
||||
// Touch sensor values
|
||||
// 35000 - Not touched
|
||||
// 50000 - Light toched with fingertip
|
||||
// 70000 - Touched
|
||||
// 170000 - Strong touched
|
||||
uint32_t touchthreshold = (thSensitivity * -1200) + 170000; // thSensitivity 0...100%
|
||||
keystatus = 0; // Status of key [0...11], 0 = processed, 1...8 = key 1..8, 9 = right swipe , 10 = left swipe, 11 keys disabled
|
||||
keycode = 0;
|
||||
|
||||
int keystatus = 0; // Status of key [0...11], 0 = processed, 1...8 = key 1..8, 9 = right swipe , 10 = left swipe, 11 keys disabled
|
||||
keycode = 0;
|
||||
|
||||
// Read key code
|
||||
if(touchRead(14) > touchthreshold){ // Touch pad 1
|
||||
keypad[1] = 1;
|
||||
}
|
||||
else{
|
||||
keypad[1] = 0;
|
||||
}
|
||||
if(touchRead(13) > touchthreshold){ // Touch pad 2
|
||||
keypad[2] = 1;
|
||||
}
|
||||
else{
|
||||
keypad[2] = 0;
|
||||
}
|
||||
if(touchRead(12) > touchthreshold){ // Touch pad 3
|
||||
keypad[3] = 1;
|
||||
}
|
||||
else{
|
||||
keypad[3] = 0;
|
||||
}
|
||||
if(touchRead(11) > touchthreshold){ // Touch pad 4
|
||||
keypad[4] = 1;
|
||||
}
|
||||
else{
|
||||
keypad[4] = 0;
|
||||
}
|
||||
if(touchRead(10) > touchthreshold){ // Touch pad 5
|
||||
keypad[5] = 1;
|
||||
}
|
||||
else{
|
||||
keypad[5] = 0;
|
||||
}
|
||||
if(touchRead(9) > touchthreshold){ // Touch pad 6
|
||||
keypad[6] = 1;
|
||||
}
|
||||
else{
|
||||
keypad[6] = 0;
|
||||
}
|
||||
// Nothing touched
|
||||
if(keypad[1] == 0 && keypad[2] == 0 && keypad[3] == 0 && keypad[4] == 0 && keypad[5] == 0 && keypad[6] == 0){
|
||||
keypad[0] = 1;
|
||||
}
|
||||
else{
|
||||
keypad[0] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 9; i++) {
|
||||
if(i > 0){
|
||||
// Convert keypad to keycode
|
||||
if(keypad[i] == 1){
|
||||
key = 1;
|
||||
}
|
||||
else{
|
||||
key = 0;
|
||||
}
|
||||
keycode += key * i;
|
||||
}
|
||||
}
|
||||
|
||||
// Detect short keynumber
|
||||
if (keycode > 0 ){
|
||||
if(keylock == false){
|
||||
starttime = millis();
|
||||
keylock = true;
|
||||
// Read key code
|
||||
if(touchRead(14) > touchthreshold){ // Touch pad 1
|
||||
keypad[1] = 1;
|
||||
}
|
||||
if (keycode != keycodeold){
|
||||
keylock = false;
|
||||
else{
|
||||
keypad[1] = 0;
|
||||
}
|
||||
// Detect a very short keynumber (10ms)
|
||||
if (millis() > starttime + 10 && keycode == keycodeold && keylock == true) {
|
||||
// Process only valid keys
|
||||
if(keycode == 1 || keycode == 6){
|
||||
keycode2 = keycode;
|
||||
if(touchRead(13) > touchthreshold){ // Touch pad 2
|
||||
keypad[2] = 1;
|
||||
}
|
||||
else{
|
||||
keypad[2] = 0;
|
||||
}
|
||||
if(touchRead(12) > touchthreshold){ // Touch pad 3
|
||||
keypad[3] = 1;
|
||||
}
|
||||
else{
|
||||
keypad[3] = 0;
|
||||
}
|
||||
if(touchRead(11) > touchthreshold){ // Touch pad 4
|
||||
keypad[4] = 1;
|
||||
}
|
||||
else{
|
||||
keypad[4] = 0;
|
||||
}
|
||||
if(touchRead(10) > touchthreshold){ // Touch pad 5
|
||||
keypad[5] = 1;
|
||||
}
|
||||
else{
|
||||
keypad[5] = 0;
|
||||
}
|
||||
if(touchRead(9) > touchthreshold){ // Touch pad 6
|
||||
keypad[6] = 1;
|
||||
}
|
||||
else{
|
||||
keypad[6] = 0;
|
||||
}
|
||||
// Nothing touched
|
||||
if(keypad[1] == 0 && keypad[2] == 0 && keypad[3] == 0 && keypad[4] == 0 && keypad[5] == 0 && keypad[6] == 0){
|
||||
keypad[0] = 1;
|
||||
}
|
||||
else{
|
||||
keypad[0] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 9; i++) {
|
||||
if(i > 0){
|
||||
// Convert keypad to keycode
|
||||
if(keypad[i] == 1){
|
||||
key = 1;
|
||||
}
|
||||
else{
|
||||
key = 0;
|
||||
}
|
||||
keycode += key * i;
|
||||
}
|
||||
}
|
||||
|
||||
// Detect short keynumber
|
||||
if (keycode > 0 ){
|
||||
if(keylock == false){
|
||||
starttime = millis();
|
||||
keylock = true;
|
||||
}
|
||||
// Clear by unvalid keys
|
||||
else{
|
||||
if (keycode != keycodeold){
|
||||
keylock = false;
|
||||
}
|
||||
// Detect a very short keynumber (10ms)
|
||||
if (millis() > starttime + 10 && keycode == keycodeold && keylock == true) {
|
||||
// Process only valid keys
|
||||
if(keycode == 1 || keycode == 6){
|
||||
keycode2 = keycode;
|
||||
}
|
||||
// Clear by unvalid keys
|
||||
else{
|
||||
keycode2 = 0;
|
||||
keycodeold2 = 0;
|
||||
}
|
||||
}
|
||||
// Timeout for very short pressed key
|
||||
if(millis() > starttime + 200){
|
||||
keycode2 = 0;
|
||||
}
|
||||
// Detect a short keynumber (200ms)
|
||||
if (keyoff == false && millis() > starttime + 200 && keycode == keycodeold && keylock == true) {
|
||||
keystatus = keycode;
|
||||
keycode = 0;
|
||||
keycodeold = 0;
|
||||
keycode2 = 0;
|
||||
keycodeold2 = 0;
|
||||
buzzer(TONE4, 100);
|
||||
keylock = false;
|
||||
delay(keydelay);
|
||||
}
|
||||
}
|
||||
// Timeout for very short pressed key
|
||||
if(millis() > starttime + 200){
|
||||
keycode2 = 0;
|
||||
}
|
||||
// Detect a short keynumber (200ms)
|
||||
if (keyoff == false && millis() > starttime + 200 && keycode == keycodeold && keylock == true) {
|
||||
keystatus = keycode;
|
||||
|
||||
// Key lock with key 1 and 6 or 6 and 1 in fast series
|
||||
if((keycode2 == 1 && keycodeold2 == 6) || (keycode2 == 6 && keycodeold2 == 1)) {
|
||||
keycode = 0;
|
||||
keycodeold = 0;
|
||||
keycode2 = 0;
|
||||
keycodeold2 = 0;
|
||||
buzzer(TONE4, 100);
|
||||
buzzer(TONE4, 1000);
|
||||
keylock = false;
|
||||
delay(keydelay);
|
||||
keyoff = !keyoff;
|
||||
keystatus = 11;
|
||||
}
|
||||
|
||||
// Detect swipe right
|
||||
if (keyoff == false && keycode > 0 && keycodeold > 0 && keycode > keycodeold && !((keycode == 1 && keycodeold == 6) || (keycode == 6 && keycodeold == 1))){
|
||||
//if (keycode > 0 && keycodeold > 0 && keycode > keycodeold){
|
||||
keycode = 0;
|
||||
keycodeold = 0;
|
||||
keycode2 = 0;
|
||||
keycodeold2 = 0;
|
||||
keystatus = 9;
|
||||
buzzer(TONE3, 150);
|
||||
buzzer(TONE4, 150);
|
||||
}
|
||||
|
||||
// Detect swipe left
|
||||
if (keyoff == false && keycode > 0 && keycodeold > 0 && keycode < keycodeold && !((keycode == 1 && keycodeold == 6) || (keycode == 6 && keycodeold == 1))){
|
||||
//if (keycode > 0 && keycodeold > 0 && keycode < keycodeold){
|
||||
keycode = 0;
|
||||
keycodeold = 0;
|
||||
keycode2 = 0;
|
||||
keycodeold2 = 0;
|
||||
keystatus = 10;
|
||||
buzzer(TONE4, 150);
|
||||
buzzer(TONE3, 150);
|
||||
}
|
||||
|
||||
// Reset keylock after release
|
||||
if (keycode == 0){
|
||||
keylock = false;
|
||||
}
|
||||
|
||||
// Copy keycode
|
||||
keycodeold = keycode;
|
||||
keycodeold2 = keycode2;
|
||||
|
||||
return keystatus;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Key lock with key 1 and 6 or 6 and 1 in fast series
|
||||
if((keycode2 == 1 && keycodeold2 == 6) || (keycode2 == 6 && keycodeold2 == 1)) {
|
||||
keycode = 0;
|
||||
keycodeold = 0;
|
||||
keycode2 = 0;
|
||||
keycodeold2 = 0;
|
||||
buzzer(TONE4, 1000);
|
||||
keylock = false;
|
||||
delay(keydelay);
|
||||
keyoff = !keyoff;
|
||||
keystatus = 11;
|
||||
#ifdef HARDWARE_LIGHT
|
||||
// Keypad functions for OBP60 clone (thSensitivity is inactiv)
|
||||
int readKeypad(uint thSensitivity) {
|
||||
pinMode(UP, INPUT);
|
||||
pinMode(DOWN, INPUT);
|
||||
pinMode(CONF, INPUT);
|
||||
pinMode(MENUE, INPUT);
|
||||
pinMode(EXIT, INPUT);
|
||||
|
||||
// Read key code
|
||||
if(digitalRead(UP) == LOW){
|
||||
keycode = 10; // Left swipe
|
||||
}
|
||||
else if(digitalRead(DOWN) == LOW){
|
||||
keycode = 9; // Right swipe
|
||||
}
|
||||
else if(digitalRead(CONF) == LOW){
|
||||
keycode = 3; // Key 3
|
||||
}
|
||||
else if(digitalRead(MENUE) == LOW){
|
||||
keycode = 1; // Key 1
|
||||
}
|
||||
else if(digitalRead(EXIT) == LOW){
|
||||
keycode = 2; // Key 2
|
||||
}
|
||||
else{
|
||||
keycode = 0; // No key activ
|
||||
}
|
||||
|
||||
// Detect key
|
||||
if (keycode > 0 ){
|
||||
if(keycode != keycodeold){
|
||||
starttime = millis(); // Start key pressed
|
||||
keycodeold = keycode;
|
||||
}
|
||||
// If key pressed longer than 200ms
|
||||
if(millis() > starttime + 200 && keycode == keycodeold) {
|
||||
keystatus = keycode;
|
||||
// Copy keycode
|
||||
keycodeold = keycode;
|
||||
delay(keydelay);
|
||||
}
|
||||
}
|
||||
else{
|
||||
keycode = 0;
|
||||
keycodeold = 0;
|
||||
keystatus = 0;
|
||||
}
|
||||
|
||||
return keystatus;
|
||||
}
|
||||
|
||||
// Detect swipe right
|
||||
if (keyoff == false && keycode > 0 && keycodeold > 0 && keycode > keycodeold && !((keycode == 1 && keycodeold == 6) || (keycode == 6 && keycodeold == 1))){
|
||||
//if (keycode > 0 && keycodeold > 0 && keycode > keycodeold){
|
||||
keycode = 0;
|
||||
keycodeold = 0;
|
||||
keycode2 = 0;
|
||||
keycodeold2 = 0;
|
||||
keystatus = 9;
|
||||
buzzer(TONE3, 150);
|
||||
buzzer(TONE4, 150);
|
||||
}
|
||||
|
||||
// Detect swipe left
|
||||
if (keyoff == false && keycode > 0 && keycodeold > 0 && keycode < keycodeold && !((keycode == 1 && keycodeold == 6) || (keycode == 6 && keycodeold == 1))){
|
||||
//if (keycode > 0 && keycodeold > 0 && keycode < keycodeold){
|
||||
keycode = 0;
|
||||
keycodeold = 0;
|
||||
keycode2 = 0;
|
||||
keycodeold2 = 0;
|
||||
keystatus = 10;
|
||||
buzzer(TONE4, 150);
|
||||
buzzer(TONE3, 150);
|
||||
}
|
||||
|
||||
// Reset keylock after release
|
||||
if (keycode == 0){
|
||||
keylock = false;
|
||||
}
|
||||
|
||||
// Copy keycode
|
||||
keycodeold = keycode;
|
||||
keycodeold2 = keycode2;
|
||||
|
||||
return keystatus;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -456,7 +456,7 @@ void sensorTask(void *param){
|
||||
}
|
||||
}
|
||||
|
||||
// Send supplay voltage value all 1s
|
||||
// Send supply voltage value all 1s
|
||||
if(millis() > starttime5 + 1000 && String(powsensor1) == "off"){
|
||||
starttime5 = millis();
|
||||
sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
#ifdef BOARD_OBP60S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Extensions.h"
|
||||
|
||||
class PageApparentWind : public Page
|
||||
{
|
||||
bool keylock = false; // Keylock
|
||||
int16_t lp = 80; // Pointer length
|
||||
|
||||
public:
|
||||
PageApparentWind(CommonData &common){
|
||||
common.logger->logDebug(GwLog::LOG,"Show PageApparentWind");
|
||||
}
|
||||
|
||||
// Key functions
|
||||
virtual int handleKey(int key){
|
||||
// Reduce instrument size
|
||||
if(key == 2){ // Code for reduce
|
||||
lp = lp - 10;
|
||||
if(lp < 10){
|
||||
lp = 10;
|
||||
}
|
||||
return 0; // Commit the key
|
||||
}
|
||||
|
||||
// Enlarge instrument size
|
||||
if(key == 5){ // Code for enlarge
|
||||
lp = lp + 10;
|
||||
if(lp > 80){
|
||||
lp = 80;
|
||||
}
|
||||
return 0; // Commit the key
|
||||
}
|
||||
|
||||
// Keylock function
|
||||
if(key == 11){ // Code for keylock
|
||||
keylock = !keylock; // Toggle keylock
|
||||
return 0; // Commit the key
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
virtual void displayPage(CommonData &commonData, PageData &pageData)
|
||||
{
|
||||
GwConfigHandler *config = commonData.config;
|
||||
GwLog *logger=commonData.logger;
|
||||
|
||||
static String svalue1old = "";
|
||||
static String unit1old = "";
|
||||
static String svalue2old = "";
|
||||
static String unit2old = "";
|
||||
|
||||
// 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);
|
||||
|
||||
// Get boat values for AWS
|
||||
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
|
||||
String name1 = bvalue1->getName().c_str(); // Value name
|
||||
name1 = name1.substring(0, 6); // String length limit for value name
|
||||
double value1 = bvalue1->value; // Value as double in SI unit
|
||||
// bool valid1 = bvalue1->valid; // Valid information
|
||||
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
|
||||
|
||||
// Get boat values for AWD
|
||||
GwApi::BoatValue *bvalue2 = pageData.values[1]; // First element in list (only one value by PageOneValue)
|
||||
String name2 = bvalue2->getName().c_str(); // Value name
|
||||
name2 = name2.substring(0, 6); // String length limit for value name
|
||||
double value2 = bvalue2->value; // Value as double in SI unit
|
||||
// bool valid2 = bvalue2->valid; // Valid information
|
||||
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
|
||||
|
||||
// Optical warning by limit violation (unused)
|
||||
if(String(flashLED) == "Limit Violation"){
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
|
||||
// Logging boat values
|
||||
if (bvalue1 == NULL) return;
|
||||
LOG_DEBUG(GwLog::LOG,"Drawing at PageApparentWind, %s:%f, %s:%f", name1.c_str(), value1, name2.c_str(), value2);
|
||||
|
||||
// Draw page
|
||||
//***********************************************************
|
||||
|
||||
// Set display in partial refresh mode
|
||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
|
||||
getdisplay().setTextColor(commonData.fgcolor);
|
||||
|
||||
// Show values AWS
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt7b);
|
||||
getdisplay().setCursor(20, 50);
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(name1); // Value name
|
||||
getdisplay().print(": ");
|
||||
getdisplay().print(svalue1); // Value
|
||||
getdisplay().print(" ");
|
||||
getdisplay().print(unit1); // Unit
|
||||
}
|
||||
else{
|
||||
getdisplay().print(name1); // Value name
|
||||
getdisplay().print(": ");
|
||||
getdisplay().print(svalue1old); // Value old
|
||||
getdisplay().print(" ");
|
||||
getdisplay().print(unit1old); // Unit old
|
||||
}
|
||||
|
||||
// Show values AWD
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt7b);
|
||||
getdisplay().setCursor(20, 260);
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(name2); // Value name
|
||||
getdisplay().print(": ");
|
||||
getdisplay().print(svalue2); // Value
|
||||
getdisplay().print(" ");
|
||||
getdisplay().print(unit2); // Unit
|
||||
}
|
||||
else{
|
||||
getdisplay().print(name2); // Value name
|
||||
getdisplay().print(": ");
|
||||
getdisplay().print(svalue2old); // Value old
|
||||
getdisplay().print(" ");
|
||||
getdisplay().print(unit2old); // Unit old
|
||||
}
|
||||
|
||||
// Draw wind pointer
|
||||
static int16_t x0 = 200; // Center point
|
||||
static int16_t y0 = 145;
|
||||
static int16_t x1 = x0; // Start point for pointer
|
||||
static int16_t y1 = y0;
|
||||
static int16_t x2 = x0; // End point for pointer
|
||||
static int16_t y2 = y0;
|
||||
|
||||
//Draw instrument
|
||||
getdisplay().fillCircle(x0, y0, lp + 5, commonData.fgcolor);
|
||||
getdisplay().fillCircle(x0, y0, lp + 1, commonData.bgcolor);
|
||||
|
||||
// Calculation end point of pointer
|
||||
value2 = value2 - 3.14 / 2;
|
||||
x1 = x0 + cos(value2) * lp * 0.6;
|
||||
y1 = y0 + sin(value2) * lp * 0.6;
|
||||
x2 = x0 + cos(value2) * lp;
|
||||
y2 = y0 + sin(value2) * lp;
|
||||
getdisplay().drawLine(x1, y1, x2, y2, commonData.fgcolor);
|
||||
|
||||
// Key Layout
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
||||
if(keylock == false){
|
||||
getdisplay().setCursor(130, 290);
|
||||
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
|
||||
if(String(backlightMode) == "Control by Key"){ // Key for illumination
|
||||
getdisplay().setCursor(343, 290);
|
||||
getdisplay().print("[ILUM]");
|
||||
}
|
||||
}
|
||||
else{
|
||||
getdisplay().setCursor(130, 290);
|
||||
getdisplay().print(" [ Keylock active ]");
|
||||
}
|
||||
|
||||
// Update display
|
||||
getdisplay().nextPage(); // Partial update (fast)
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
static Page *createPage(CommonData &common){
|
||||
return new PageApparentWind(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 (0 here)
|
||||
* and will will provide the names of the fixed values we need
|
||||
*/
|
||||
PageDescription registerPageApparentWind(
|
||||
"ApparentWind", // Page name
|
||||
createPage, // Action
|
||||
0, // Number of bus values depends on selection in Web configuration
|
||||
{"AWS","AWA"}, // Bus values we need in the page
|
||||
true // Show display header on/off
|
||||
);
|
||||
|
||||
#endif
|
||||
@@ -1,228 +0,0 @@
|
||||
#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
|
||||
@@ -22,43 +22,6 @@ TODO
|
||||
|
||||
*/
|
||||
|
||||
struct Point {
|
||||
double x;
|
||||
double y;
|
||||
};
|
||||
|
||||
Point rotatePoint(const Point& origin, const Point& p, double angle) {
|
||||
// rotate poind around origin by degrees
|
||||
Point rotated;
|
||||
double phi = angle * M_PI / 180.0;
|
||||
double dx = p.x - origin.x;
|
||||
double dy = p.y - origin.y;
|
||||
rotated.x = origin.x + cos(phi) * dx - sin(phi) * dy;
|
||||
rotated.y = origin.y + sin(phi) * dx + cos(phi) * dy;
|
||||
return rotated;
|
||||
}
|
||||
|
||||
std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle) {
|
||||
std::vector<Point> rotatedPoints;
|
||||
for (const auto& p : pts) {
|
||||
rotatedPoints.push_back(rotatePoint(origin, p, angle));
|
||||
}
|
||||
return rotatedPoints;
|
||||
}
|
||||
|
||||
void fillPoly4(const std::vector<Point>& p4, uint16_t color) {
|
||||
getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[1].x, p4[1].y, p4[2].x, p4[2].y, color);
|
||||
getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[2].x, p4[2].y, p4[3].x, p4[3].y, color);
|
||||
}
|
||||
|
||||
void drawTextCentered(int16_t tx, int16_t ty, String text) {
|
||||
int16_t x, y;
|
||||
uint16_t w, h;
|
||||
getdisplay().getTextBounds(text, 0, 0, &x, &y, &w, &h);
|
||||
getdisplay().setCursor(tx - w / 2, ty + h / 2);
|
||||
getdisplay().print(text);
|
||||
}
|
||||
|
||||
#define fuel_width 16
|
||||
#define fuel_height 16
|
||||
static unsigned char fuel_bits[] = {
|
||||
@@ -96,12 +59,13 @@ static unsigned char gasoline_bits[] = {
|
||||
|
||||
class PageFluid : public Page{
|
||||
bool keylock = false; // Keylock
|
||||
bool holdvalues = false;
|
||||
int fluidtype;
|
||||
|
||||
public:
|
||||
PageFluid(CommonData &common){
|
||||
common.logger->logDebug(GwLog::LOG,"Show PageFluid");
|
||||
fluidtype = common.config->getInt("page" + String(common.data.actpage) + "fluid", 0);
|
||||
common.logger->logDebug(GwLog::LOG,"Instantiate PageFluid");
|
||||
holdvalues = common.config->getBool(common.config->holdvalues);
|
||||
}
|
||||
|
||||
virtual int handleKey(int key){
|
||||
@@ -112,10 +76,18 @@ class PageFluid : public Page{
|
||||
return key;
|
||||
}
|
||||
|
||||
virtual void displayNew(CommonData &commonData, PageData &pageData){
|
||||
fluidtype = commonData.config->getInt("page" + String(pageData.pageNumber) + "fluid", 0);
|
||||
commonData.logger->logDebug(GwLog::LOG,"New PageFluid: fluidtype=%d", fluidtype);
|
||||
}
|
||||
|
||||
virtual void displayPage(CommonData &commonData, PageData &pageData){
|
||||
GwConfigHandler *config = commonData.config;
|
||||
GwLog *logger=commonData.logger;
|
||||
|
||||
// Old values for hold function
|
||||
static double value1old;
|
||||
|
||||
// Get config data
|
||||
String flashLED = config->getString(config->flashLED);
|
||||
String backlightMode = config->getString(config->backlight);
|
||||
@@ -126,13 +98,14 @@ class PageFluid : public Page{
|
||||
setFlashLED(false);
|
||||
}
|
||||
|
||||
// Logging boat values
|
||||
LOG_DEBUG(GwLog::LOG,"Drawing at PageFluid");
|
||||
|
||||
GwApi::BoatValue *bvalue1 = pageData.values[0];
|
||||
String name1 = bvalue1->getName();
|
||||
double value1 = bvalue1->value;
|
||||
bool valid1 = bvalue1->valid;
|
||||
if (holdvalues and bvalue1->valid) {
|
||||
value1old = bvalue1->value;
|
||||
}
|
||||
|
||||
// Logging boat values
|
||||
LOG_DEBUG(GwLog::LOG,"Drawing at PageFluid: value=%f", bvalue1->value);
|
||||
|
||||
// Draw page
|
||||
//***********************************************************
|
||||
@@ -171,7 +144,7 @@ class PageFluid : public Page{
|
||||
} else {
|
||||
strcpy(buffer, "---");
|
||||
}
|
||||
drawTextCentered(c.x, c.y + r - 20, String(buffer));
|
||||
drawTextCenter(c.x, c.y + r - 20, String(buffer));
|
||||
|
||||
// draw symbol (as bitmap)
|
||||
switch (fluidtype) {
|
||||
@@ -197,18 +170,18 @@ class PageFluid : public Page{
|
||||
// scale texts
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
||||
p = {c.x, c.y - r + 30};
|
||||
drawTextCentered(p.x, p.y, "1/2");
|
||||
drawTextCenter(p.x, p.y, "1/2");
|
||||
pr = rotatePoint(c, p, -60);
|
||||
drawTextCentered(pr.x, pr.y, "1/4");
|
||||
drawTextCenter(pr.x, pr.y, "1/4");
|
||||
pr = rotatePoint(c, p, 60);
|
||||
drawTextCentered(pr.x, pr.y, "3/4");
|
||||
drawTextCenter(pr.x, pr.y, "3/4");
|
||||
|
||||
// empty and full
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt7b);
|
||||
p = rotatePoint(c, {c.x, c.y - r + 30}, -130);
|
||||
drawTextCentered(p.x, p.y, "E");
|
||||
drawTextCenter(p.x, p.y, "E");
|
||||
p = rotatePoint(c, {c.x, c.y - r + 30}, 130);
|
||||
drawTextCentered(p.x, p.y, "F");
|
||||
drawTextCenter(p.x, p.y, "F");
|
||||
|
||||
// lines
|
||||
std::vector<Point> pts = {
|
||||
|
||||
@@ -342,9 +342,9 @@ static Page *createPage(CommonData &common){
|
||||
PageDescription registerPageRollPitch(
|
||||
"RollPitch", // Page name
|
||||
createPage, // Action
|
||||
0, // Number of bus values depends on selection in Web configuration
|
||||
2, // Number of bus values depends on selection in Web configuration
|
||||
// {"xdrROLL", "xdrPTCH"},// Bus values we need in the page
|
||||
{"xdrRoll", "xdrPitch"},// Bus values we need in the page
|
||||
//{"xdrRoll", "xdrPitch"},// Bus values we need in the page
|
||||
true // Show display header on/off
|
||||
);
|
||||
|
||||
|
||||
@@ -8,25 +8,44 @@ class PageVoltage : public Page
|
||||
{
|
||||
bool init = false; // Marker for init done
|
||||
bool keylock = false; // Keylock
|
||||
int average = 0; // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
|
||||
uint8_t average = 0; // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
|
||||
bool trend = true; // Trend indicator [0|1], 0=off, 1=on
|
||||
double raw = 0;
|
||||
char mode = 'D'; // display mode (A)nalog | (D)igital
|
||||
|
||||
public:
|
||||
PageVoltage(CommonData &common){
|
||||
common.logger->logDebug(GwLog::LOG,"Show PageVoltage");
|
||||
common.logger->logDebug(GwLog::LOG,"Instantiate PageVoltage");
|
||||
if (hasFRAM) {
|
||||
average = fram.read(FRAM_VOLTAGE_AVG);
|
||||
trend = fram.read(FRAM_VOLTAGE_TREND);
|
||||
mode = fram.read(FRAM_VOLTAGE_MODE);
|
||||
}
|
||||
}
|
||||
virtual int handleKey(int key){
|
||||
// Change average
|
||||
if(key == 1){
|
||||
average ++;
|
||||
average = average % 4; // Modulo 4
|
||||
if (hasFRAM) fram.write(FRAM_VOLTAGE_AVG, average);
|
||||
return 0; // Commit the key
|
||||
}
|
||||
|
||||
// Switch display mode
|
||||
if (key == 2) {
|
||||
if (mode == 'A') {
|
||||
mode = 'D';
|
||||
} else {
|
||||
mode = 'A';
|
||||
}
|
||||
if (hasFRAM) fram.write(FRAM_VOLTAGE_MODE, mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Trend indicator
|
||||
if(key == 5){
|
||||
trend = !trend;
|
||||
if (hasFRAM) fram.write(FRAM_VOLTAGE_TREND, trend);
|
||||
return 0; // Commit the key
|
||||
}
|
||||
|
||||
@@ -38,6 +57,41 @@ public:
|
||||
return key;
|
||||
}
|
||||
|
||||
void printAvg(int avg, uint16_t x, uint16_t y, bool prefix) {
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
||||
getdisplay().setCursor(x, y);
|
||||
if (prefix) {
|
||||
getdisplay().print("Avg: ");
|
||||
}
|
||||
switch (average) {
|
||||
case 0:
|
||||
getdisplay().print("1s");
|
||||
break;
|
||||
case 1:
|
||||
getdisplay().print("10s");
|
||||
break;
|
||||
case 2:
|
||||
getdisplay().print("60s");
|
||||
break;
|
||||
case 3:
|
||||
getdisplay().print("300s");
|
||||
break;
|
||||
default:
|
||||
getdisplay().print("1s");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void printVoltageSymbol(uint16_t x, uint16_t y, uint16_t color) {
|
||||
getdisplay().setFont(&Ubuntu_Bold16pt7b);
|
||||
getdisplay().setCursor(x, y);
|
||||
getdisplay().print("V");
|
||||
getdisplay().fillRect(x, y + 6, 22, 3, color);
|
||||
getdisplay().fillRect(x, y + 11, 6, 3, color);
|
||||
getdisplay().fillRect(x + 8, y + 11, 6, 3, color);
|
||||
getdisplay().fillRect(x + 16, y + 11, 6, 3, color);
|
||||
}
|
||||
|
||||
virtual void displayPage(CommonData &commonData, PageData &pageData)
|
||||
{
|
||||
GwConfigHandler *config = commonData.config;
|
||||
@@ -135,92 +189,182 @@ public:
|
||||
// Set display in partial refresh mode
|
||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
|
||||
// Show name
|
||||
getdisplay().setTextColor(commonData.fgcolor);
|
||||
getdisplay().setFont(&Ubuntu_Bold32pt7b);
|
||||
getdisplay().setCursor(20, 100);
|
||||
getdisplay().print(name1); // Value name
|
||||
if (mode == 'D') {
|
||||
// Display mode digital
|
||||
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt7b);
|
||||
getdisplay().setCursor(270, 100);
|
||||
getdisplay().print("V");
|
||||
// Show name
|
||||
getdisplay().setTextColor(commonData.fgcolor);
|
||||
getdisplay().setFont(&Ubuntu_Bold32pt7b);
|
||||
getdisplay().setCursor(20, 100);
|
||||
getdisplay().print(name1); // Value name
|
||||
|
||||
// Show battery type
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
||||
getdisplay().setCursor(295, 100);
|
||||
getdisplay().print(batType);
|
||||
// Show unit
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt7b);
|
||||
getdisplay().setCursor(270, 100);
|
||||
getdisplay().print("V");
|
||||
|
||||
// Show average settings
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
||||
getdisplay().setCursor(320, 84);
|
||||
switch (average) {
|
||||
case 0:
|
||||
getdisplay().print("Avg: 1s");
|
||||
break;
|
||||
case 1:
|
||||
getdisplay().print("Avg: 10s");
|
||||
break;
|
||||
case 2:
|
||||
getdisplay().print("Avg: 60s");
|
||||
break;
|
||||
case 3:
|
||||
getdisplay().print("Avg: 300s");
|
||||
break;
|
||||
default:
|
||||
getdisplay().print("Avg: 1s");
|
||||
break;
|
||||
}
|
||||
// Show battery type
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
||||
getdisplay().setCursor(295, 100);
|
||||
getdisplay().print(batType);
|
||||
|
||||
// Reading bus data or using simulation data
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic60pt7b);
|
||||
getdisplay().setCursor(20, 240);
|
||||
if(simulation == true){
|
||||
if(batVoltage == "12V"){
|
||||
value1 = 12.0;
|
||||
}
|
||||
if(batVoltage == "24V"){
|
||||
value1 = 24.0;
|
||||
}
|
||||
value1 += float(random(0, 5)) / 10; // Simulation data
|
||||
getdisplay().print(value1,1);
|
||||
}
|
||||
else{
|
||||
// Check for valid real data, display also if hold values activated
|
||||
if(valid1 == true || holdvalues == true){
|
||||
// Resolution switching
|
||||
if(value1 < 10){
|
||||
getdisplay().print(value1,2);
|
||||
// Show average settings
|
||||
printAvg(average, 320, 84, true);
|
||||
|
||||
// Reading bus data or using simulation data
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic60pt7b);
|
||||
getdisplay().setCursor(20, 240);
|
||||
if(simulation == true){
|
||||
if(batVoltage == "12V"){
|
||||
value1 = 12.0;
|
||||
}
|
||||
if(value1 >= 10 && value1 < 100){
|
||||
getdisplay().print(value1,1);
|
||||
}
|
||||
if(value1 >= 100){
|
||||
getdisplay().print(value1,0);
|
||||
if(batVoltage == "24V"){
|
||||
value1 = 24.0;
|
||||
}
|
||||
value1 += float(random(0, 5)) / 10; // Simulation data
|
||||
getdisplay().print(value1,1);
|
||||
}
|
||||
else{
|
||||
getdisplay().print("---"); // Missing bus data
|
||||
}
|
||||
}
|
||||
|
||||
// Trend indicator
|
||||
// Show trend indicator
|
||||
if(trend == true){
|
||||
getdisplay().fillRect(310, 240, 40, 120, commonData.bgcolor); // Clear area
|
||||
getdisplay().fillRect(315, 183, 35, 4, commonData.fgcolor); // Draw separator
|
||||
if(int(raw * 10) > int(valueTrend * 10)){
|
||||
displayTrendHigh(320, 174, 11, commonData.fgcolor); // Show high indicator
|
||||
// Check for valid real data, display also if hold values activated
|
||||
if(valid1 == true || holdvalues == true){
|
||||
// Resolution switching
|
||||
if(value1 < 10){
|
||||
getdisplay().print(value1,2);
|
||||
}
|
||||
if(value1 >= 10 && value1 < 100){
|
||||
getdisplay().print(value1,1);
|
||||
}
|
||||
if(value1 >= 100){
|
||||
getdisplay().print(value1,0);
|
||||
}
|
||||
}
|
||||
else{
|
||||
getdisplay().print("---"); // Missing bus data
|
||||
}
|
||||
}
|
||||
if(int(raw * 10) < int(valueTrend * 10)){
|
||||
displayTrendLow(320, 195, 11, commonData.fgcolor); // Show low indicator
|
||||
}
|
||||
}
|
||||
// No trend indicator
|
||||
else{
|
||||
getdisplay().fillRect(310, 240, 40, 120, commonData.bgcolor); // Clear area
|
||||
}
|
||||
|
||||
// Trend indicator
|
||||
// Show trend indicator
|
||||
if(trend == true){
|
||||
getdisplay().fillRect(310, 240, 40, 120, commonData.bgcolor); // Clear area
|
||||
getdisplay().fillRect(315, 183, 35, 4, commonData.fgcolor); // Draw separator
|
||||
if(int(raw * 10) > int(valueTrend * 10)){
|
||||
displayTrendHigh(320, 174, 11, commonData.fgcolor); // Show high indicator
|
||||
}
|
||||
if(int(raw * 10) < int(valueTrend * 10)){
|
||||
displayTrendLow(320, 195, 11, commonData.fgcolor); // Show low indicator
|
||||
}
|
||||
}
|
||||
// No trend indicator
|
||||
else{
|
||||
getdisplay().fillRect(310, 240, 40, 120, commonData.bgcolor); // Clear area
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
// Display mode analog
|
||||
|
||||
// center
|
||||
Point c = {260, 270};
|
||||
uint8_t r = 240;
|
||||
|
||||
Point p1, p2;
|
||||
std::vector<Point> pts;
|
||||
|
||||
// Instrument
|
||||
getdisplay().drawCircleHelper(c.x, c.y, r + 2, 0x01, commonData.fgcolor);
|
||||
getdisplay().drawCircleHelper(c.x, c.y, r + 1, 0x01, commonData.fgcolor);
|
||||
getdisplay().drawCircleHelper(c.x, c.y, r , 0x01, commonData.fgcolor);
|
||||
|
||||
// Scale
|
||||
// angle to voltage scale mapping
|
||||
std::map<int, String> mapping = {
|
||||
{15, "10"}, {30, "11"}, {45, "12"}, {60, "13"}, {75, "14"}
|
||||
};
|
||||
pts = {
|
||||
{c.x - r, c.y - 1},
|
||||
{c.x - r + 12, c.y - 1},
|
||||
{c.x - r + 12, c.y + 1},
|
||||
{c.x - r, c.y + 1}
|
||||
};
|
||||
getdisplay().setFont(&Ubuntu_Bold10pt7b);
|
||||
for (int angle = 3; angle < 90; angle += 3) {
|
||||
if (angle % 15 == 0) {
|
||||
fillPoly4(rotatePoints(c, pts, angle), commonData.fgcolor);
|
||||
p1 = rotatePoint(c, {c.x - r + 30, c.y}, angle);
|
||||
drawTextCenter(p1.x, p1.y, mapping[angle]);
|
||||
}
|
||||
else {
|
||||
p1 = rotatePoint(c, {c.x - r, c.y}, angle);
|
||||
p2 = rotatePoint(c, {c.x - r + 6, c.y}, angle);
|
||||
getdisplay().drawLine(p1.x, p1.y, p2.x, p2.y, commonData.fgcolor);
|
||||
}
|
||||
}
|
||||
|
||||
// Pointer rotation and limits
|
||||
double angle;
|
||||
if (not valid1) {
|
||||
angle = -0.5;
|
||||
}
|
||||
else {
|
||||
if (value1 > 15.0) {
|
||||
angle = 91;
|
||||
}
|
||||
else if (value1 <= 9) {
|
||||
angle = -0.5;
|
||||
}
|
||||
else {
|
||||
angle = (value1 - 9) * 15;
|
||||
}
|
||||
}
|
||||
|
||||
// Pointer
|
||||
// thick part
|
||||
pts = {
|
||||
{c.x - 2, c.y + 3},
|
||||
{c.x - r + 38, c.y + 2},
|
||||
{c.x - r + 38, c.y - 2},
|
||||
{c.x - 2, c.y - 3}
|
||||
};
|
||||
fillPoly4(rotatePoints(c, pts, angle), commonData.fgcolor);
|
||||
// thin part
|
||||
pts = {
|
||||
{c.x - r + 40, c.y + 1},
|
||||
{c.x - r + 5, c.y + 1},
|
||||
{c.x - r + 5, c.y -1},
|
||||
{c.x - r + 40, c.y - 1},
|
||||
};
|
||||
fillPoly4(rotatePoints(c, pts, angle), commonData.fgcolor);
|
||||
|
||||
// base
|
||||
getdisplay().fillCircle(c.x, c.y, 7, commonData.fgcolor);
|
||||
getdisplay().fillCircle(c.x, c.y, 4, commonData.bgcolor);
|
||||
|
||||
// Symbol
|
||||
printVoltageSymbol(40, 60, commonData.fgcolor);
|
||||
|
||||
// Additional information at right side
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
||||
getdisplay().setCursor(300, 60);
|
||||
getdisplay().print("Source:");
|
||||
getdisplay().setCursor(300, 80);
|
||||
getdisplay().print(name1);
|
||||
|
||||
getdisplay().setCursor(300, 110);
|
||||
getdisplay().print("Type:");
|
||||
getdisplay().setCursor(300, 130);
|
||||
getdisplay().print(batType);
|
||||
|
||||
getdisplay().setCursor(300, 160);
|
||||
getdisplay().print("Avg:");
|
||||
printAvg(average, 300, 180, false);
|
||||
|
||||
// FRAM indicator
|
||||
if (hasFRAM) {
|
||||
getdisplay().drawXBitmap(300, 240, fram_bits, fram_width, fram_height, commonData.fgcolor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Key Layout
|
||||
getdisplay().setTextColor(commonData.fgcolor);
|
||||
@@ -228,6 +372,8 @@ public:
|
||||
if(keylock == false){
|
||||
getdisplay().setCursor(10, 290);
|
||||
getdisplay().print("[AVG]");
|
||||
getdisplay().setCursor(62, 290);
|
||||
getdisplay().print("[MODE]");
|
||||
getdisplay().setCursor(130, 290);
|
||||
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
|
||||
getdisplay().setCursor(293, 290);
|
||||
|
||||
650
lib/obp60task/PageWind.cpp
Normal file
650
lib/obp60task/PageWind.cpp
Normal file
@@ -0,0 +1,650 @@
|
||||
#ifdef BOARD_OBP60S3
|
||||
|
||||
#include "Pagedata.h"
|
||||
#include "OBP60Extensions.h"
|
||||
#include "N2kMessages.h"
|
||||
|
||||
#define front_width 120
|
||||
#define front_height 162
|
||||
static unsigned char front_bits[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x80, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x03,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xf0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xf0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x1f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xfc, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xfe, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf7, 0x7f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
|
||||
0xff, 0xf3, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xc0, 0xff, 0xe1, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xc1, 0xff, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x80, 0xff,
|
||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
|
||||
0x7f, 0x80, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xf0, 0x7f, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0xfe, 0x0f, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0xfe,
|
||||
0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
|
||||
0x1f, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xfc, 0x0f, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0xf8, 0x3f, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0xf0,
|
||||
0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
0x03, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x80, 0xff, 0x03, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0xc0, 0xff, 0x01, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0x80,
|
||||
0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff,
|
||||
0x00, 0x00, 0x80, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0x00,
|
||||
0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1f,
|
||||
0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xf8, 0x1f, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00,
|
||||
0xf0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x07,
|
||||
0x00, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xfe, 0x03, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00,
|
||||
0xc0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x00,
|
||||
0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xc0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xfe, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xfe, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80,
|
||||
0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
|
||||
0x03, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0xe0,
|
||||
0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00,
|
||||
0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
|
||||
0x07, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0,
|
||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x00,
|
||||
0x00, 0x00, 0xf8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
||||
0x1f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xfc,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00,
|
||||
0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x7f, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x3f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xfc, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x80, 0x0f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00,
|
||||
0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xf0, 0x03, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x03,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00,
|
||||
0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xe0, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0xf0, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00,
|
||||
0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x80, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x78, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00,
|
||||
0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3e, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x3c, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00,
|
||||
0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x7c, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x0e, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00,
|
||||
0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xf8, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x07, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01,
|
||||
0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xe0, 0x01, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x80, 0x03, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03,
|
||||
0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xc0, 0x03, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0xc0, 0x01, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07,
|
||||
0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x80, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0xe0, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
|
||||
0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x0f, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x70, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e,
|
||||
0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x0e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
|
||||
0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x1c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x18, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
|
||||
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
|
||||
0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x38, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
|
||||
0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
|
||||
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
|
||||
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
|
||||
0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
|
||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0 };
|
||||
|
||||
class PageWind : public Page
|
||||
{
|
||||
bool keylock = false; // Keylock
|
||||
int8_t lp = 80; // Pointer length
|
||||
char mode = 'N'; // page mode (N)ormal | (L)ens | e(X)ample
|
||||
char source = 'A'; // data source (A)pparent | (T)rue
|
||||
|
||||
public:
|
||||
PageWind(CommonData &common){
|
||||
common.logger->logDebug(GwLog::LOG,"Instantiate PageWind");
|
||||
if (hasFRAM) {
|
||||
lp = fram.read(FRAM_WIND_SIZE);
|
||||
source = fram.read(FRAM_WIND_SRC);
|
||||
mode = fram.read(FRAM_WIND_MODE);
|
||||
}
|
||||
}
|
||||
|
||||
// Key functions
|
||||
virtual int handleKey(int key){
|
||||
|
||||
if(key == 1){ // Mode switch
|
||||
if(mode == 'N'){
|
||||
mode = 'L';
|
||||
} else if (mode == 'L') {
|
||||
mode = 'X';
|
||||
} else {
|
||||
mode = 'N';
|
||||
}
|
||||
if (hasFRAM) fram.write(FRAM_WIND_MODE, mode);
|
||||
return 0; // Commit the key
|
||||
}
|
||||
|
||||
if(key == 3){ // Source switch
|
||||
if(source == 'A'){
|
||||
source = 'T';
|
||||
} else {
|
||||
source = 'A';
|
||||
}
|
||||
if (hasFRAM) fram.write(FRAM_WIND_SRC, source);
|
||||
return 0; // Commit the key
|
||||
}
|
||||
|
||||
// Reduce instrument size
|
||||
if(key == 2 && mode == 'X'){ // Code for reduce
|
||||
lp = lp - 10;
|
||||
if(lp < 10){
|
||||
lp = 10;
|
||||
}
|
||||
if (hasFRAM) fram.write(FRAM_WIND_SIZE, lp);
|
||||
return 0; // Commit the key
|
||||
}
|
||||
|
||||
// Enlarge instrument size
|
||||
if(key == 5 && mode == 'X'){ // Code for enlarge
|
||||
lp = lp + 10;
|
||||
if(lp > 80){
|
||||
lp = 80;
|
||||
}
|
||||
if (hasFRAM) fram.write(FRAM_WIND_SIZE, lp);
|
||||
return 0; // Commit the key
|
||||
}
|
||||
|
||||
// Keylock function
|
||||
if(key == 11){ // Code for keylock
|
||||
keylock = !keylock; // Toggle keylock
|
||||
return 0; // Commit the key
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
virtual void displayPage(CommonData &commonData, PageData &pageData)
|
||||
{
|
||||
GwConfigHandler *config = commonData.config;
|
||||
GwLog *logger=commonData.logger;
|
||||
|
||||
static String svalue1old = "";
|
||||
static String unit1old = "";
|
||||
static String svalue2old = "";
|
||||
static String unit2old = "";
|
||||
|
||||
// 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 *bvalue1; // Value 1 for speed on top
|
||||
GwApi::BoatValue *bvalue2; // Value 2 for angle on bottom
|
||||
|
||||
// Get boat values for speed (AWS/TWS)
|
||||
if (source == 'A') {
|
||||
bvalue1 = pageData.values[0];
|
||||
} else {
|
||||
bvalue1 = pageData.values[2];
|
||||
}
|
||||
String name1 = bvalue1->getName().c_str(); // Value name
|
||||
name1 = name1.substring(0, 6); // String length limit for value name
|
||||
double value1 = bvalue1->value; // Value as double in SI unit
|
||||
// bool valid1 = bvalue1->valid; // Valid information
|
||||
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
|
||||
|
||||
// Get boat values for angle (AWD/TWD)
|
||||
if (source == 'A') {
|
||||
bvalue2 = pageData.values[1];
|
||||
} else {
|
||||
bvalue2 = pageData.values[3];
|
||||
}
|
||||
String name2 = bvalue2->getName().c_str(); // Value name
|
||||
name2 = name2.substring(0, 6); // String length limit for value name
|
||||
double value2 = bvalue2->value; // Value as double in SI unit
|
||||
// bool valid2 = bvalue2->valid; // Valid information
|
||||
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
|
||||
|
||||
// Optical warning by limit violation (unused)
|
||||
if(String(flashLED) == "Limit Violation"){
|
||||
setBlinkingLED(false);
|
||||
setFlashLED(false);
|
||||
}
|
||||
|
||||
// Logging boat values
|
||||
if (bvalue1 == NULL) return;
|
||||
LOG_DEBUG(GwLog::LOG,"Drawing at PageWind, %s:%f, %s:%f", name1.c_str(), value1, name2.c_str(), value2);
|
||||
|
||||
// Draw page
|
||||
//***********************************************************
|
||||
|
||||
// Set display in partial refresh mode
|
||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||
|
||||
getdisplay().setTextColor(commonData.fgcolor);
|
||||
|
||||
|
||||
if (mode == 'X') {
|
||||
// Original example code with scaling circle
|
||||
|
||||
// Show values AWS/TWS
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt7b);
|
||||
getdisplay().setCursor(20, 50);
|
||||
getdisplay().print(name1); // Value name
|
||||
getdisplay().print(": ");
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue1); // Value
|
||||
getdisplay().print(" ");
|
||||
getdisplay().print(unit1); // Unit
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue1old); // Value old
|
||||
getdisplay().print(" ");
|
||||
getdisplay().print(unit1old); // Unit old
|
||||
}
|
||||
|
||||
// Show values AWD/TWD
|
||||
getdisplay().setFont(&Ubuntu_Bold20pt7b);
|
||||
getdisplay().setCursor(20, 260);
|
||||
getdisplay().print(name2); // Value name
|
||||
getdisplay().print(": ");
|
||||
if(holdvalues == false){
|
||||
getdisplay().print(svalue2); // Value
|
||||
getdisplay().print(" ");
|
||||
getdisplay().print(unit2); // Unit
|
||||
}
|
||||
else{
|
||||
getdisplay().print(svalue2old); // Value old
|
||||
getdisplay().print(" ");
|
||||
getdisplay().print(unit2old); // Unit old
|
||||
}
|
||||
|
||||
Point c = {200, 145};
|
||||
|
||||
// Draw instrument
|
||||
getdisplay().fillCircle(c.x, c.y, lp + 5, commonData.fgcolor);
|
||||
getdisplay().fillCircle(c.x, c.y, lp + 1, commonData.bgcolor);
|
||||
|
||||
// Wind pointer
|
||||
if (bvalue2->valid) {
|
||||
uint8_t lp0 = lp * 0.6; // effective pointer outside size
|
||||
uint8_t lp1 = lp * 0.4; // effective pointer inside size
|
||||
// zero position
|
||||
std::vector<Point> pts = {
|
||||
{c.x, c.y - lp},
|
||||
{c.x - 7, c.y - lp + lp0},
|
||||
{c.x, c.y - lp + lp1},
|
||||
{c.x + 7, c.y - lp + lp0}
|
||||
};
|
||||
fillPoly4(rotatePoints(c, pts, RadToDeg(value2)), commonData.fgcolor);
|
||||
} else {
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt7b);
|
||||
drawTextCenter(c.x, c.y, "no data");
|
||||
}
|
||||
|
||||
} else if (mode == 'L') { // Mode (L)ens
|
||||
|
||||
Point c = {200, 155};
|
||||
uint16_t r = 150;
|
||||
|
||||
Point p;
|
||||
std::vector<Point> pts = { // polygon lines
|
||||
{c.x - 2, c.y - r},
|
||||
{c.x + 2, c.y - r},
|
||||
{c.x + 2, c.y - (r - 16)},
|
||||
{c.x - 2, c.y - (r - 16)}
|
||||
};
|
||||
int angle;
|
||||
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt7b);
|
||||
|
||||
// starbord
|
||||
// text with line
|
||||
angle = 20;
|
||||
for (int i = 30; i < 150; i += 30) {
|
||||
p = rotatePoint(c, {c.x, c.y - r + 40}, i);
|
||||
drawTextCenter(p.x, p.y, String(angle));
|
||||
angle += 10;
|
||||
fillPoly4(rotatePoints(c, pts, i), commonData.fgcolor);
|
||||
}
|
||||
// dots
|
||||
for (int i = 30; i < 138; i += 6) {
|
||||
if (i % 15 != 0) {
|
||||
p = rotatePoint(c, {c.x, c.y - r + 5}, i);
|
||||
getdisplay().fillCircle(p.x, p.y, 2, commonData.fgcolor);
|
||||
}
|
||||
}
|
||||
|
||||
// port
|
||||
angle = 50;
|
||||
// text with line
|
||||
for (int i = 240; i <= 330; i += 30) {
|
||||
p = rotatePoint(c, {c.x, c.y - r + 40}, i);
|
||||
drawTextCenter(p.x, p.y, String(angle));
|
||||
angle -= 10;
|
||||
fillPoly4(rotatePoints(c, pts, i), commonData.fgcolor);
|
||||
}
|
||||
// dots
|
||||
for (int i = 228; i < 330; i += 6) {
|
||||
if (i % 15 != 0) {
|
||||
p = rotatePoint(c, {c.x, c.y - r + 5}, i);
|
||||
getdisplay().fillCircle(p.x, p.y, 2, commonData.fgcolor);
|
||||
}
|
||||
}
|
||||
|
||||
// data source
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt7b);
|
||||
getdisplay().setCursor(8, 50);
|
||||
if (source == 'A') {
|
||||
getdisplay().print("APP");
|
||||
} else {
|
||||
getdisplay().print("TRUE");
|
||||
}
|
||||
|
||||
// Wind pointer (angle)
|
||||
if (bvalue2->valid) {
|
||||
float alpha = RadToDeg(value2);
|
||||
bool port = (alpha > 180);
|
||||
if (port) {
|
||||
alpha = 360 - alpha;
|
||||
}
|
||||
if (alpha < 15) {
|
||||
alpha = 15; // stop at start of scale
|
||||
} else if (alpha > 55) {
|
||||
alpha = 55; // stop at end of scale
|
||||
}
|
||||
alpha = 3 * alpha - 30; // convert to lens scale
|
||||
if (port) {
|
||||
alpha *= -1;
|
||||
}
|
||||
|
||||
getdisplay().fillCircle(c.x, c.y, 8, commonData.fgcolor);
|
||||
pts = {
|
||||
{c.x - 1, c.y - (r - 20)},
|
||||
{c.x + 1, c.y - (r - 20)},
|
||||
{c.x + 6, c.y + 15},
|
||||
{c.x - 6, c.y + 15}
|
||||
};
|
||||
fillPoly4(rotatePoints(c, pts, alpha), commonData.fgcolor);
|
||||
getdisplay().fillCircle(c.x, c.y, 6, commonData.bgcolor);
|
||||
} else {
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt7b);
|
||||
drawTextCenter(c.x, c.y, "no data");
|
||||
}
|
||||
|
||||
// Wind speed as decimal number
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(150, 250);
|
||||
if (holdvalues == false) {
|
||||
getdisplay().print(svalue1);
|
||||
} else {
|
||||
getdisplay().print(svalue1old);
|
||||
}
|
||||
// unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
||||
getdisplay().setCursor(220, 265);
|
||||
getdisplay().print("kts");
|
||||
}
|
||||
else {
|
||||
// Normal mode
|
||||
|
||||
// data source
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt7b);
|
||||
getdisplay().setCursor(8, 50);
|
||||
if (source == 'A') {
|
||||
getdisplay().print("APP");
|
||||
} else {
|
||||
getdisplay().print("TRUE");
|
||||
}
|
||||
|
||||
// draw ship front symbol (as bitmap)
|
||||
getdisplay().drawXBitmap(140, 30, front_bits, front_width, front_height, commonData.fgcolor);
|
||||
|
||||
Point c = {200, 155};
|
||||
uint16_t r = 150;
|
||||
|
||||
Point p;
|
||||
std::vector<Point> pts = { // polygon lines
|
||||
{c.x - 2, c.y - r},
|
||||
{c.x + 2, c.y - r},
|
||||
{c.x + 2, c.y - (r - 16)},
|
||||
{c.x - 2, c.y - (r - 16)}
|
||||
};
|
||||
int angle;
|
||||
|
||||
// starbord
|
||||
// text with line
|
||||
for (int i = 30; i < 150; i += 30) {
|
||||
p = rotatePoint(c, {c.x, c.y - r + 40}, i);
|
||||
drawTextCenter(p.x, p.y, String(i));
|
||||
fillPoly4(rotatePoints(c, pts, i), commonData.fgcolor);
|
||||
}
|
||||
// dots
|
||||
for (int i = 30; i < 150; i += 10) {
|
||||
if (i % 30 != 0) {
|
||||
p = rotatePoint(c, {c.x, c.y - r + 5}, i);
|
||||
getdisplay().fillCircle(p.x, p.y, 3, commonData.fgcolor);
|
||||
}
|
||||
}
|
||||
|
||||
// port
|
||||
// text with line
|
||||
angle = 120;
|
||||
for (int i = 240; i <= 330; i += 30) {
|
||||
p = rotatePoint(c, {c.x, c.y - r + 40}, i);
|
||||
drawTextCenter(p.x, p.y, String(angle));
|
||||
angle -= 30;
|
||||
fillPoly4(rotatePoints(c, pts, i), commonData.fgcolor);
|
||||
}
|
||||
// dots
|
||||
for (int i = 210; i < 340; i += 10) {
|
||||
if (i % 30 != 0) {
|
||||
p = rotatePoint(c, {c.x, c.y - r + 5}, i);
|
||||
getdisplay().fillCircle(p.x, p.y, 3, commonData.fgcolor);
|
||||
}
|
||||
}
|
||||
|
||||
// Wind speed as decimal number
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(150, 250);
|
||||
if (holdvalues == false) {
|
||||
getdisplay().print(svalue1);
|
||||
} else {
|
||||
getdisplay().print(svalue1old);
|
||||
}
|
||||
// unit
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
||||
getdisplay().setCursor(220, 265);
|
||||
getdisplay().print("kts");
|
||||
|
||||
// Wind pointer (angle)
|
||||
if (bvalue2->valid) {
|
||||
float alpha = RadToDeg(value2);
|
||||
getdisplay().fillCircle(c.x, c.y, 8, commonData.fgcolor);
|
||||
pts = {
|
||||
{c.x - 1, c.y - (r - 20)},
|
||||
{c.x + 1, c.y - (r - 20)},
|
||||
{c.x + 6, c.y + 15},
|
||||
{c.x - 6, c.y + 15}
|
||||
};
|
||||
fillPoly4(rotatePoints(c, pts, alpha), commonData.fgcolor);
|
||||
getdisplay().fillCircle(c.x, c.y, 6, commonData.bgcolor);
|
||||
} else {
|
||||
getdisplay().setFont(&Ubuntu_Bold12pt7b);
|
||||
drawTextCenter(c.x, c.y, "no data");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Key Layout
|
||||
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
||||
if(keylock == false){
|
||||
getdisplay().setCursor(10, 290);
|
||||
getdisplay().print("[MODE]");
|
||||
getdisplay().setCursor(130, 290);
|
||||
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
|
||||
|
||||
if (mode == 'X') {
|
||||
getdisplay().setCursor(85, 290);
|
||||
getdisplay().print("[ - ]");
|
||||
getdisplay().setCursor(295, 290);
|
||||
getdisplay().print("[ + ]");
|
||||
}
|
||||
|
||||
if(String(backlightMode) == "Control by Key"){ // Key for illumination
|
||||
getdisplay().setCursor(343, 290);
|
||||
getdisplay().print("[ILUM]");
|
||||
}
|
||||
}
|
||||
else{
|
||||
getdisplay().setCursor(130, 290);
|
||||
getdisplay().print(" [ Keylock active ]");
|
||||
}
|
||||
|
||||
// Update display
|
||||
getdisplay().nextPage(); // Partial update (fast)
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
static Page *createPage(CommonData &common){
|
||||
return new PageWind(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 (0 here)
|
||||
* and will will provide the names of the fixed values we need
|
||||
*/
|
||||
PageDescription registerPageWind(
|
||||
"Wind", // Page name
|
||||
createPage, // Action
|
||||
0, // Number of bus values depends on selection in Web configuration
|
||||
{"AWS","AWA", "TWS", "TWA"}, // Bus values we need in the page
|
||||
true // Show display header on/off
|
||||
);
|
||||
|
||||
#endif
|
||||
@@ -186,7 +186,8 @@ public:
|
||||
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
|
||||
getdisplay().setCursor(295, 65);
|
||||
if(valid3 == true){
|
||||
getdisplay().print(abs(value3 * 180 / PI), 0); // Value
|
||||
// getdisplay().print(abs(value3 * 180 / PI), 0); // Value
|
||||
getdisplay().print(svalue3); // Value
|
||||
}
|
||||
else{
|
||||
getdisplay().print("---"); // Value
|
||||
|
||||
@@ -4,9 +4,12 @@
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#define MAX_PAGE_NUMBER 10 // Max number of pages for show data
|
||||
|
||||
typedef std::vector<GwApi::BoatValue *> ValueList;
|
||||
typedef struct{
|
||||
String pageName;
|
||||
uint8_t pageNumber; // page number in sequence of visible pages
|
||||
//the values will always contain the user defined values first
|
||||
ValueList values;
|
||||
} PageData;
|
||||
@@ -114,6 +117,13 @@ class PageDescription{
|
||||
}
|
||||
};
|
||||
|
||||
class PageStruct{
|
||||
public:
|
||||
Page *page=NULL;
|
||||
PageData parameters;
|
||||
PageDescription *description=NULL;
|
||||
};
|
||||
|
||||
// Structure for formated boat values
|
||||
typedef struct{
|
||||
double value;
|
||||
|
||||
11
lib/obp60task/README
Normal file
11
lib/obp60task/README
Normal file
@@ -0,0 +1,11 @@
|
||||
OBP40
|
||||
=====
|
||||
|
||||
Important information:
|
||||
|
||||
***************************************************
|
||||
THIS BRANCH IS NOT INTENDED TO MERGE INTO "master"!
|
||||
***************************************************
|
||||
|
||||
platformio.ini adapted to compile directly
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
#!/bin/perl -w
|
||||
#A tool to generate the part of config.json that deals with pages and fields.
|
||||
|
||||
#DEPRECATED, moved to get_set.py
|
||||
die "Please use gen_set.py instead";
|
||||
#List of all pages and the number of parameters they expect.
|
||||
%NoOfFieldsPerPage=qw(
|
||||
ApparentWind 0
|
||||
@@ -81,7 +82,7 @@ for ($PageNo=1;$PageNo<=$NoOfPages;$PageNo++){
|
||||
print "\t",'"condition":[';
|
||||
foreach $page (@Pages) {
|
||||
if($NoOfFieldsPerPage{$page}>=$FieldNo){
|
||||
print '{"page1type":"',$page,'"},';
|
||||
print '{"page',$PageNo,'type":"',$page,'"},';
|
||||
}
|
||||
}
|
||||
print "\b],\n";
|
||||
|
||||
123
lib/obp60task/gen_set.py
Executable file
123
lib/obp60task/gen_set.py
Executable file
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env python3
|
||||
# A tool to generate that part of config.json that deals with pages and fields.
|
||||
|
||||
import json
|
||||
|
||||
# List of all pages and the number of parameters they expect.
|
||||
no_of_fields_per_page = {
|
||||
"ApparentWind": 0,
|
||||
"XTETrack": 0,
|
||||
"Battery2": 0,
|
||||
"Battery": 0,
|
||||
"BME280": 0,
|
||||
"Clock": 0,
|
||||
"DST810": 0,
|
||||
"Fluid": 0,
|
||||
"FourValues2": 4,
|
||||
"FourValues": 4,
|
||||
"Generator": 0,
|
||||
"KeelPosition": 0,
|
||||
"OneValue": 1,
|
||||
"RollPitch": 2,
|
||||
"RudderPosition": 0,
|
||||
"Solar": 0,
|
||||
"ThreeValues": 3,
|
||||
"TwoValues": 2,
|
||||
"Voltage": 0,
|
||||
"White": 0,
|
||||
"WindRose": 0,
|
||||
"WindRoseFlex": 6,
|
||||
}
|
||||
|
||||
# No changes needed beyond this point
|
||||
# max number of pages supported by OBP60
|
||||
no_of_pages = 10
|
||||
# Default selection for each page
|
||||
default_pages = [
|
||||
"Voltage",
|
||||
"WindRose",
|
||||
"OneValue",
|
||||
"TwoValues",
|
||||
"ThreeValues",
|
||||
"FourValues",
|
||||
"FourValues2",
|
||||
"Clock",
|
||||
"RollPitch",
|
||||
"Battery2",
|
||||
]
|
||||
numbers = [
|
||||
"one",
|
||||
"two",
|
||||
"three",
|
||||
"four",
|
||||
"five",
|
||||
"six",
|
||||
"seven",
|
||||
"eight",
|
||||
"nine",
|
||||
"ten",
|
||||
]
|
||||
pages = sorted(no_of_fields_per_page.keys())
|
||||
max_no_of_fields_per_page = max(no_of_fields_per_page.values())
|
||||
|
||||
output = []
|
||||
|
||||
for page_no in range(1, no_of_pages + 1):
|
||||
page_data = {
|
||||
"name": f"page{page_no}type",
|
||||
"label": "Type",
|
||||
"type": "list",
|
||||
"default": default_pages[page_no - 1],
|
||||
"description": f"Type of page for page {page_no}",
|
||||
"list": pages,
|
||||
"category": f"OBP60 Page {page_no}",
|
||||
"capabilities": {"obp60": "true"},
|
||||
"condition": [{"visiblePages": vp} for vp in range(page_no, no_of_pages + 1)],
|
||||
#"fields": [],
|
||||
}
|
||||
output.append(page_data)
|
||||
|
||||
for field_no in range(1, max_no_of_fields_per_page + 1):
|
||||
field_data = {
|
||||
"name": f"page{page_no}value{field_no}",
|
||||
"label": f"Field {field_no}",
|
||||
"type": "boatData",
|
||||
"default": "",
|
||||
"description": f"The display for field {numbers[field_no - 1]}",
|
||||
"category": f"OBP60 Page {page_no}",
|
||||
"capabilities": {"obp60": "true"},
|
||||
"condition": [
|
||||
{f"page{page_no}type": page}
|
||||
for page in pages
|
||||
if no_of_fields_per_page[page] >= field_no
|
||||
],
|
||||
}
|
||||
output.append(field_data)
|
||||
|
||||
fluid_data ={
|
||||
"name": f"page{page_no}fluid",
|
||||
"label": "Fluid type",
|
||||
"type": "list",
|
||||
"default": "0",
|
||||
"list": [
|
||||
{"l":"Fuel (0)","v":"0"},
|
||||
{"l":"Water (1)","v":"1"},
|
||||
{"l":"Gray Water (2)","v":"2"},
|
||||
{"l":"Live Well (3)","v":"3"},
|
||||
{"l":"Oil (4)","v":"4"},
|
||||
{"l":"Black Water (5)","v":"5"},
|
||||
{"l":"Fuel Gasoline (6)","v":"6"}
|
||||
],
|
||||
"description": "Fluid type in tank",
|
||||
"category": f"OBP60 Page {page_no}",
|
||||
"capabilities": {
|
||||
"obp60":"true"
|
||||
},
|
||||
"condition":[{f"page{page_no}type":"Fluid"}]
|
||||
}
|
||||
output.append(fluid_data)
|
||||
|
||||
json_output = json.dumps(output, indent=4)
|
||||
# print omitting first and last line containing [ ] of JSON array
|
||||
print(json_output[1:-1])
|
||||
# print(",")
|
||||
@@ -1,84 +0,0 @@
|
||||
/* 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() {
|
||||
}
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
#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
|
||||
347
lib/obp60task/imglib.cpp
Normal file
347
lib/obp60task/imglib.cpp
Normal file
@@ -0,0 +1,347 @@
|
||||
/******************************************************************************
|
||||
* Image functions:
|
||||
* - Convert a 1bit framebuffer in RAM to
|
||||
* - GIF, compressed, based on giflib and gif_hash
|
||||
* - PBM, portable bitmap, very simple copy
|
||||
* - BMP, bigger with a little bit fiddling around
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*****************************************************************************/
|
||||
|
||||
#include <Arduino.h> // needed for PROGMEM
|
||||
#include <vector>
|
||||
#include "GwLog.h" // needed for logger
|
||||
#include "imglib.h"
|
||||
|
||||
GifFilePrivateType gifprivate;
|
||||
|
||||
void ClearHashTable(GifHashTableType *HashTable) {
|
||||
memset(HashTable->HTable, 0xFF, HT_SIZE * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
GifHashTableType *InitHashTable(void) {
|
||||
GifHashTableType *HashTable;
|
||||
if ((HashTable = (GifHashTableType *)ps_malloc(sizeof(GifHashTableType))) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ClearHashTable(HashTable);
|
||||
return HashTable;
|
||||
}
|
||||
|
||||
static int KeyItem(uint32_t Item) {
|
||||
return ((Item >> 12) ^ Item) & HT_KEY_MASK;
|
||||
}
|
||||
|
||||
void InsertHashTable(GifHashTableType *HashTable, uint32_t Key, int Code) {
|
||||
int HKey = KeyItem(Key);
|
||||
uint32_t *HTable = HashTable->HTable;
|
||||
while (HT_GET_KEY(HTable[HKey]) != 0xFFFFFL) {
|
||||
HKey = (HKey + 1) & HT_KEY_MASK;
|
||||
}
|
||||
HTable[HKey] = HT_PUT_KEY(Key) | HT_PUT_CODE(Code);
|
||||
}
|
||||
|
||||
int ExistsHashTable(GifHashTableType *HashTable, uint32_t Key) {
|
||||
int HKey = KeyItem(Key);
|
||||
uint32_t *HTable = HashTable->HTable, HTKey;
|
||||
while ((HTKey = HT_GET_KEY(HTable[HKey])) != 0xFFFFFL) {
|
||||
if (Key == HTKey) {
|
||||
return HT_GET_CODE(HTable[HKey]);
|
||||
}
|
||||
HKey = (HKey + 1) & HT_KEY_MASK;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Put 2 bytes (a word) into the given file in little-endian order:
|
||||
******************************************************************************/
|
||||
void GifPutWord(std::vector<uint8_t>* gifBuffer, uint16_t Word) {
|
||||
/*cuint8_t c[2];
|
||||
[0] = LOBYTE(Word);
|
||||
c[1] = HIBYTE(Word);
|
||||
gifBuffer->push_back(c[0]);
|
||||
gifBuffer->push_back(c[1]); */
|
||||
gifBuffer->push_back(LOBYTE(Word));
|
||||
gifBuffer->push_back(HIBYTE(Word));
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
This routines buffers the given characters until 255 characters are ready
|
||||
to be output. If Code is equal to -1 the buffer is flushed (EOF).
|
||||
The buffer is Dumped with first byte as its size, as GIF format requires.
|
||||
******************************************************************************/
|
||||
void GifBufferedOutput(std::vector<uint8_t>* gifBuffer, GifByteType *Buf, int c) {
|
||||
if (c == FLUSH_OUTPUT) {
|
||||
// Flush everything out.
|
||||
for (int i = 0; i < Buf[0] + 1; i++) {
|
||||
gifBuffer->push_back(Buf[i]);
|
||||
}
|
||||
// Mark end of compressed data, by an empty block (see GIF doc):
|
||||
Buf[0] = 0;
|
||||
gifBuffer->push_back(0);
|
||||
} else {
|
||||
if (Buf[0] == 255) {
|
||||
// Dump out this buffer - it is full:
|
||||
for (int i = 0; i < Buf[0] + 1; i++) {
|
||||
gifBuffer->push_back(Buf[i]);
|
||||
}
|
||||
Buf[0] = 0;
|
||||
}
|
||||
Buf[++Buf[0]] = c;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
The LZ compression output routine:
|
||||
This routine is responsible for the compression of the bit stream into
|
||||
8 bits (bytes) packets.
|
||||
******************************************************************************/
|
||||
void GifCompressOutput(std::vector<uint8_t>* gifBuffer, const int Code) {
|
||||
|
||||
if (Code == FLUSH_OUTPUT) {
|
||||
while (gifprivate.CrntShiftState > 0) {
|
||||
// Get Rid of what is left in DWord, and flush it.
|
||||
GifBufferedOutput(gifBuffer, gifprivate.Buf, gifprivate.CrntShiftDWord & 0xff);
|
||||
gifprivate.CrntShiftDWord >>= 8;
|
||||
gifprivate.CrntShiftState -= 8;
|
||||
}
|
||||
gifprivate.CrntShiftState = 0; // For next time.
|
||||
GifBufferedOutput(gifBuffer, gifprivate.Buf, FLUSH_OUTPUT);
|
||||
} else {
|
||||
gifprivate.CrntShiftDWord |= ((long)Code) << gifprivate.CrntShiftState;
|
||||
gifprivate.CrntShiftState += gifprivate.RunningBits;
|
||||
while (gifprivate.CrntShiftState >= 8) {
|
||||
// Dump out full bytes:
|
||||
GifBufferedOutput(gifBuffer, gifprivate.Buf, gifprivate.CrntShiftDWord & 0xff);
|
||||
gifprivate.CrntShiftDWord >>= 8;
|
||||
gifprivate.CrntShiftState -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
/* If code cannt fit into RunningBits bits, must raise its size. Note */
|
||||
/* however that codes above LZ_MAX_CODE are used for special signaling. */
|
||||
if (gifprivate.RunningCode >= gifprivate.MaxCode1 && Code <= LZ_MAX_CODE) {
|
||||
gifprivate.MaxCode1 = 1 << ++gifprivate.RunningBits;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Setup the LZ compression for this image:
|
||||
******************************************************************************/
|
||||
void GifSetupCompress(std::vector<uint8_t>* gifBuffer) {
|
||||
gifBuffer->push_back(0x02);// Bits per pixel wit minimum 2
|
||||
|
||||
gifprivate.Buf[0] = 0; // Nothing was output yet
|
||||
gifprivate.BitsPerPixel = 2; // Minimum is 2
|
||||
gifprivate.ClearCode = (1 << 2);
|
||||
gifprivate.EOFCode = gifprivate.ClearCode + 1;
|
||||
gifprivate.RunningCode = gifprivate.EOFCode + 1;
|
||||
gifprivate.RunningBits = 2 + 1; // Number of bits per code
|
||||
gifprivate.MaxCode1 = 1 << gifprivate.RunningBits; // Max. code + 1
|
||||
gifprivate.CrntCode = FIRST_CODE; // Signal that this is first one!
|
||||
gifprivate.CrntShiftState = 0; // No information in CrntShiftDWord
|
||||
gifprivate.CrntShiftDWord = 0;
|
||||
|
||||
GifCompressOutput(gifBuffer, gifprivate.ClearCode);
|
||||
}
|
||||
|
||||
void createGifHeader(std::vector<uint8_t>* gifBuffer, uint16_t width, uint16_t height) {
|
||||
|
||||
// SCREEN DESCRIPTOR
|
||||
gifBuffer->push_back('G');
|
||||
gifBuffer->push_back('I');
|
||||
gifBuffer->push_back('F');
|
||||
gifBuffer->push_back('8');
|
||||
gifBuffer->push_back('7');
|
||||
gifBuffer->push_back('a');
|
||||
|
||||
GifPutWord(gifBuffer, width);
|
||||
GifPutWord(gifBuffer, height);
|
||||
|
||||
gifBuffer->push_back(0x80 | (1 << 4));
|
||||
gifBuffer->push_back(0x00); // Index into the ColorTable for background color
|
||||
gifBuffer->push_back(0x00); // Pixel Aspect Ratio
|
||||
|
||||
// Colormap
|
||||
gifBuffer->push_back(0xff); // Color 0
|
||||
gifBuffer->push_back(0xff);
|
||||
gifBuffer->push_back(0xff);
|
||||
gifBuffer->push_back(0x00); // Color 1
|
||||
gifBuffer->push_back(0x00);
|
||||
gifBuffer->push_back(0x00);
|
||||
|
||||
// IMAGE DESCRIPTOR
|
||||
gifBuffer->push_back(DESCRIPTOR_INTRODUCER);
|
||||
|
||||
GifPutWord(gifBuffer, 0);
|
||||
GifPutWord(gifBuffer, 0);
|
||||
GifPutWord(gifBuffer, width);
|
||||
GifPutWord(gifBuffer, height);
|
||||
|
||||
gifBuffer->push_back(0x00); // No colormap here , we use the global one
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
The LZ compression routine:
|
||||
This version compresses the given buffer Line of length LineLen.
|
||||
This routine can be called a few times (one per scan line, for example), in
|
||||
order to complete the whole image.
|
||||
******************************************************************************/
|
||||
void GifCompressLine(std::vector<uint8_t>* gifBuffer, const GifPixelType *Line, const int LineLen) {
|
||||
int i = 0, CrntCode;
|
||||
GifHashTableType *HashTable;
|
||||
|
||||
HashTable = gifprivate.HashTable;
|
||||
|
||||
if (gifprivate.CrntCode == FIRST_CODE) { // Its first time!
|
||||
CrntCode = Line[i++];
|
||||
} else {
|
||||
CrntCode =
|
||||
gifprivate.CrntCode; // Get last code in compression
|
||||
}
|
||||
while (i < LineLen) { // Decode LineLen items
|
||||
GifPixelType Pixel = Line[i++]; // Get next pixel from stream.
|
||||
/* Form a new unique key to search hash table for the code
|
||||
* combines CrntCode as Prefix string with Pixel as postfix
|
||||
* char.
|
||||
*/
|
||||
int NewCode;
|
||||
unsigned long NewKey = (((uint32_t)CrntCode) << 8) + Pixel;
|
||||
if ((NewCode = ExistsHashTable(HashTable, NewKey)) >= 0) {
|
||||
/* This Key is already there, or the string is old one,
|
||||
* so simple take new code as our CrntCode:
|
||||
*/
|
||||
CrntCode = NewCode;
|
||||
} else {
|
||||
/* Put it in hash table, output the prefix code, and
|
||||
* make our CrntCode equal to Pixel.
|
||||
*/
|
||||
GifCompressOutput(gifBuffer, CrntCode);
|
||||
CrntCode = Pixel;
|
||||
|
||||
/* If however the HashTable if full, we send a clear
|
||||
* first and Clear the hash table.
|
||||
*/
|
||||
if (gifprivate.RunningCode >= LZ_MAX_CODE) {
|
||||
// Time to do some clearance:
|
||||
GifCompressOutput(gifBuffer, gifprivate.ClearCode);
|
||||
gifprivate.RunningCode = gifprivate.EOFCode + 1;
|
||||
gifprivate.RunningBits = gifprivate.BitsPerPixel + 1;
|
||||
gifprivate.MaxCode1 = 1 << gifprivate.RunningBits;
|
||||
ClearHashTable(HashTable);
|
||||
} else {
|
||||
// Put this unique key with its relative Code in hash table:
|
||||
InsertHashTable(HashTable, NewKey, gifprivate.RunningCode++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Preserve the current state of the compression algorithm:
|
||||
gifprivate.CrntCode = CrntCode;
|
||||
|
||||
if (gifprivate.PixelCount == 0) {
|
||||
// We are done - output last Code and flush output buffers:
|
||||
GifCompressOutput(gifBuffer, CrntCode);
|
||||
GifCompressOutput(gifBuffer, gifprivate.EOFCode);
|
||||
GifCompressOutput(gifBuffer, FLUSH_OUTPUT);
|
||||
}
|
||||
}
|
||||
|
||||
bool createBMP(uint8_t *frameBuffer, std::vector<uint8_t>* imageBuffer, uint16_t width, uint16_t height) {
|
||||
// For BMP the line size has to be a multiple of 4 bytes.
|
||||
// So padding is needed. Also the lines have to be in reverded
|
||||
// order compared to plain buffer
|
||||
|
||||
// BMP header for black-and-white image (1 bit per pixel)
|
||||
const uint8_t bmp_header[] PROGMEM = {
|
||||
// BITMAPFILEHEADER (14 Bytes)
|
||||
0x42, 0x4D, // bfType: 'BM' signature
|
||||
0x2e, 0x3d, 0x00, 0x00, // bfSize: file size in bytes
|
||||
0x00, 0x00, // bfReserved1
|
||||
0x00, 0x00, // bfReserved2
|
||||
0x3e, 0x00, 0x00, 0x00, // bfOffBits: offset in bytes to pixeldata
|
||||
// BITMAPINFOHEADER (40 Bytes)
|
||||
0x28, 0x00, 0x00, 0x00, // biSize: DIB header size
|
||||
(uint8_t)LOBYTE(width), (uint8_t)HIBYTE(width), 0x00, 0x00, // biWidth
|
||||
(uint8_t)LOBYTE(height), (uint8_t)HIBYTE(height), 0x00, 0x00, // biHeight
|
||||
0x01, 0x00, // biPlanes: Number of color planes (1)
|
||||
0x01, 0x00, // biBitCount: Color depth (1 bit per pixel)
|
||||
0x00, 0x00, 0x00, 0x00, // biCompression: Compression (none)
|
||||
0xf0, 0x3c, 0x00, 0x00, // biSizeImage: Image data size (calculate)
|
||||
0x13, 0x0b, 0x00, 0x00, // biXPelsPerMeter: Horizontal resolution (2835 pixels/meter)
|
||||
0x13, 0x0b, 0x00, 0x00, // biYPelsPerMeter: Vertical resolution (2835 pixels/meter)
|
||||
0x02, 0x00, 0x00, 0x00, // biClrUsed: Colors in color palette (2)
|
||||
0x00, 0x00, 0x00, 0x00, // biClrImportant: Important colors (all)
|
||||
// PALETTE: COLORTRIPLES of RGBQUAD (n * 4 Bytes)
|
||||
0x00, 0x00, 0x00, 0x00, // Color palette: Black
|
||||
0xff, 0xff, 0xff, 0x00 // Color palette: White
|
||||
};
|
||||
size_t bmp_headerSize = sizeof(bmp_header);
|
||||
|
||||
size_t lineSize = (width / 8);
|
||||
size_t paddingSize = 0;
|
||||
if (lineSize % 4 != 0) {
|
||||
paddingSize = 4 - lineSize % 4;
|
||||
}
|
||||
size_t imageSize = bmp_headerSize + (lineSize + paddingSize) * height;
|
||||
|
||||
imageBuffer->resize(imageSize);
|
||||
memcpy(imageBuffer->data(), bmp_header, bmp_headerSize);
|
||||
for (int y = 0; y < height; y++) {
|
||||
uint8_t* srcRow = frameBuffer + (y * lineSize);
|
||||
uint8_t* destRow = imageBuffer->data() + bmp_headerSize + ((height - 1 - y) * (lineSize + paddingSize));
|
||||
memcpy(destRow, srcRow, lineSize);
|
||||
for (int j = 0; j < paddingSize; j++) {
|
||||
destRow[lineSize + j] = 0x00;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool createPBM(uint8_t *frameBuffer, std::vector<uint8_t>* imageBuffer, uint16_t width, uint16_t height) {
|
||||
// creates binary PBM image inside imagebuffer
|
||||
// returns bytesize of created image
|
||||
const char pbm_header[] PROGMEM = "P4\n#Created by OBP60\n400 300\n";
|
||||
size_t pbm_headerSize = sizeof(pbm_header) - 1; // We don't want trailing zero
|
||||
size_t imageSize = pbm_headerSize + width / 8 * height;
|
||||
imageBuffer->resize(imageSize);
|
||||
memcpy(imageBuffer->data(), pbm_header, pbm_headerSize);
|
||||
memcpy(imageBuffer->data() + pbm_headerSize, frameBuffer, width / 8 * height);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool createGIF(uint8_t *framebuffer, std::vector<uint8_t>* gifBuffer, uint16_t width, uint16_t height) {
|
||||
|
||||
size_t imageSize = 0;
|
||||
uint16_t bufOffset = 0; // Offset into imageBuffer for next write access
|
||||
|
||||
gifprivate.HashTable = InitHashTable();
|
||||
if (gifprivate.HashTable == NULL) {
|
||||
return false;
|
||||
}
|
||||
gifprivate.PixelCount = width * height;
|
||||
|
||||
createGifHeader(gifBuffer, width, height);
|
||||
|
||||
// Reset compress algorithm parameters.
|
||||
GifSetupCompress(gifBuffer);
|
||||
|
||||
gifBuffer->reserve(4096); // to avoid lots of alloactions
|
||||
GifPixelType line[width];
|
||||
for (int y = 0; y < height; y++) {
|
||||
// convert uint8_t pixels to single pixels
|
||||
for (int x = 0; x < width; x++) {
|
||||
int byteIndex = (y * width + x) / 8;
|
||||
uint8_t bitIndex = 7 - ((y * width + x) % 8);
|
||||
line[x] = (framebuffer[byteIndex] & (uint8_t)(1 << bitIndex)) == 0;
|
||||
}
|
||||
gifprivate.PixelCount -= width;
|
||||
GifCompressLine(gifBuffer, line, width);
|
||||
}
|
||||
|
||||
gifBuffer->push_back(TERMINATOR_INTRODUCER);
|
||||
free((GifHashTableType *)gifprivate.HashTable);
|
||||
|
||||
return true;
|
||||
}
|
||||
70
lib/obp60task/imglib.h
Normal file
70
lib/obp60task/imglib.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* imglib.h
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef _IMGLIB_H_
|
||||
#define _IMGLIB_H_ 1
|
||||
|
||||
// extract bytes from an unsigned word
|
||||
#define LOBYTE(x) ((x)&0xff)
|
||||
#define HIBYTE(x) (((x) >> 8) & 0xff)
|
||||
|
||||
// GIF encoding constants
|
||||
#define DESCRIPTOR_INTRODUCER 0x2c
|
||||
#define TERMINATOR_INTRODUCER 0x3b
|
||||
|
||||
#define LZ_MAX_CODE 4095 // Biggest code possible in 12 bits
|
||||
#define LZ_BITS 12
|
||||
|
||||
#define FLUSH_OUTPUT 4096 // Impossible code, to signal flush
|
||||
#define FIRST_CODE 4097 // Impossible code, to signal first
|
||||
#define NO_SUCH_CODE 4098 // Impossible code, to signal empty
|
||||
|
||||
// magfic constants and declarations for GIF LZW
|
||||
|
||||
#define HT_SIZE 8192 /* 12bits = 4096 or twice as big! */
|
||||
#define HT_KEY_MASK 0x1FFF /* 13bits keys */
|
||||
#define HT_KEY_NUM_BITS 13 /* 13bits keys */
|
||||
#define HT_MAX_KEY 8191 /* 13bits - 1, maximal code possible */
|
||||
#define HT_MAX_CODE 4095 /* Biggest code possible in 12 bits. */
|
||||
|
||||
/* The 32 bits of the long are divided into two parts for the key & code: */
|
||||
/* 1. The code is 12 bits as our compression algorithm is limited to 12bits */
|
||||
/* 2. The key is 12 bits Prefix code + 8 bit new char or 20 bits. */
|
||||
/* The key is the upper 20 bits. The code is the lower 12. */
|
||||
#define HT_GET_KEY(l) (l >> 12)
|
||||
#define HT_GET_CODE(l) (l & 0x0FFF)
|
||||
#define HT_PUT_KEY(l) (l << 12)
|
||||
#define HT_PUT_CODE(l) (l & 0x0FFF)
|
||||
|
||||
typedef unsigned char GifPixelType;
|
||||
typedef unsigned char GifByteType;
|
||||
|
||||
typedef struct GifHashTableType {
|
||||
uint32_t HTable[HT_SIZE];
|
||||
} GifHashTableType;
|
||||
|
||||
typedef struct GifFilePrivateType {
|
||||
uint8_t BitsPerPixel; // Bits per pixel (Codes uses at least this + 1)
|
||||
uint16_t ClearCode; // The CLEAR LZ code
|
||||
uint16_t EOFCode; // The EOF LZ code
|
||||
uint16_t RunningCode; // The next code algorithm can generate
|
||||
uint16_t RunningBits; // The number of bits required to represent RunningCode
|
||||
uint16_t MaxCode1; // 1 bigger than max. possible code, in RunningBits bits
|
||||
uint16_t LastCode; // The code before the current code.
|
||||
uint16_t CrntCode; // Current algorithm code
|
||||
uint16_t CrntShiftState; // Number of bits in CrntShiftDWord
|
||||
uint32_t CrntShiftDWord; // For bytes decomposition into codes
|
||||
uint32_t PixelCount; // Number of pixels in image
|
||||
GifByteType Buf[256]; // Compressed input is buffered here
|
||||
GifHashTableType *HashTable;
|
||||
} GifFilePrivateType;
|
||||
|
||||
bool createGIF(uint8_t *framebuffer, std::vector<uint8_t>* imageBuffer, uint16_t width, uint16_t height);
|
||||
bool createBMP(uint8_t *framebuffer, std::vector<uint8_t>* imageBuffer, uint16_t width, uint16_t height);
|
||||
bool createPBM(uint8_t *framebuffer, std::vector<uint8_t>* gifBuffer, uint16_t width, uint16_t height);
|
||||
|
||||
#endif /* _IMGLIB_H */
|
||||
@@ -13,6 +13,10 @@
|
||||
#include "OBP60Extensions.h" // Functions lib for extension board
|
||||
#include "OBP60Keypad.h" // Functions for keypad
|
||||
|
||||
#include <FS.h> // SD-Card access
|
||||
#include <SD.h>
|
||||
#include <SPI.h>
|
||||
|
||||
// True type character sets includes
|
||||
// See OBP60ExtensionPort.cpp
|
||||
|
||||
@@ -43,16 +47,26 @@ void OBP60Init(GwApi *api){
|
||||
|
||||
|
||||
// Init hardware
|
||||
hardwareInit();
|
||||
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 HARDWARE_LIGHT
|
||||
setPortPin(OBP_POWER_EPD, true);// Power on ePaper display
|
||||
#endif
|
||||
}
|
||||
else{
|
||||
#ifdef HARDWARE_V21
|
||||
setPortPin(OBP_POWER_50, false); // Power off 5.0V rail
|
||||
#endif
|
||||
#ifdef HARDWARE_LIGHT
|
||||
setPortPin(OBP_POWER_EPD, false);// Power off ePaper display
|
||||
#endif
|
||||
}
|
||||
|
||||
// Settings for e-paper display
|
||||
@@ -183,13 +197,6 @@ class PageList{
|
||||
}
|
||||
};
|
||||
|
||||
class PageStruct{
|
||||
public:
|
||||
Page *page=NULL;
|
||||
PageData parameters;
|
||||
PageDescription *description=NULL;
|
||||
};
|
||||
|
||||
/**
|
||||
* this function will add all the pages we know to the pagelist
|
||||
* each page should have defined a registerXXXPage variable of type
|
||||
@@ -212,8 +219,8 @@ void registerAllPages(PageList &list){
|
||||
list.add(®isterPageFourValues);
|
||||
extern PageDescription registerPageFourValues2;
|
||||
list.add(®isterPageFourValues2);
|
||||
extern PageDescription registerPageApparentWind;
|
||||
list.add(®isterPageApparentWind);
|
||||
extern PageDescription registerPageWind;
|
||||
list.add(®isterPageWind);
|
||||
extern PageDescription registerPageWindRose;
|
||||
list.add(®isterPageWindRose);
|
||||
extern PageDescription registerPageWindRoseFlex;
|
||||
@@ -246,8 +253,6 @@ void registerAllPages(PageList &list){
|
||||
list.add(®isterPageXTETrack);
|
||||
extern PageDescription registerPageFluid;
|
||||
list.add(®isterPageFluid);
|
||||
extern PageDescription registerPageBarograph;
|
||||
list.add(®isterPageBarograph);
|
||||
}
|
||||
|
||||
// Undervoltage detection for shutdown display
|
||||
@@ -255,7 +260,7 @@ void underVoltageDetection(GwApi *api, CommonData &common){
|
||||
// Read settings
|
||||
float vslope = uint(api->getConfig()->getConfigItem(api->getConfig()->vSlope,true)->asFloat());
|
||||
float voffset = uint(api->getConfig()->getConfigItem(api->getConfig()->vOffset,true)->asFloat());
|
||||
// Read supplay voltage
|
||||
// Read supply voltage
|
||||
float actVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // V = 1/20 * Vin
|
||||
actVoltage = actVoltage * vslope + voffset;
|
||||
if(actVoltage < MIN_VOLTAGE){
|
||||
@@ -355,6 +360,10 @@ void OBP60Task(GwApi *api){
|
||||
// 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;
|
||||
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
|
||||
@@ -378,6 +387,7 @@ void OBP60Task(GwApi *api){
|
||||
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++){
|
||||
@@ -397,6 +407,33 @@ void OBP60Task(GwApi *api){
|
||||
pages[i].parameters.values.push_back(value);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
});
|
||||
|
||||
// SD-Card: init an check
|
||||
SPI.begin(SD_SPI_CLK, SD_SPI_MISO, SD_SPI_MOSI, SD_SPI_CS);
|
||||
if (SD.begin(SD_SPI_CS)) {
|
||||
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::DEBUG,"SD card type %s of size %d MB detected", sdtype, cardSize);
|
||||
}
|
||||
|
||||
//now we have prepared the page data
|
||||
//we start a separate task that will fetch our keys...
|
||||
MyData allParameters;
|
||||
@@ -433,9 +470,6 @@ void OBP60Task(GwApi *api){
|
||||
GwApi::BoatValue *hdop = boatValues.findValueOrCreate("HDOP"); // Load GpsHDOP
|
||||
|
||||
LOG_DEBUG(GwLog::LOG,"obp60task: start mainloop");
|
||||
// Set start page
|
||||
int pageNumber = int(api->getConfig()->getConfigItem(api->getConfig()->startPage,true)->asInt()) - 1;
|
||||
int lastPage=pageNumber;
|
||||
|
||||
commonData.time = boatValues.findValueOrCreate("GPST"); // Load GpsTime
|
||||
commonData.date = boatValues.findValueOrCreate("GPSD"); // Load GpsTime
|
||||
|
||||
@@ -3,15 +3,28 @@
|
||||
//we only compile for some boards
|
||||
#ifdef BOARD_OBP60S3
|
||||
#define USBSerial Serial
|
||||
// CAN NMEA2000
|
||||
#define ESP32_CAN_TX_PIN 46
|
||||
#define ESP32_CAN_RX_PIN 3
|
||||
// Bus load in 50mA steps
|
||||
#define N2K_LOAD_LEVEL 5 // 5x50mA = 250mA max bus load with back light on
|
||||
// RS485 NMEA0183
|
||||
#define GWSERIAL_TX 17
|
||||
#define GWSERIAL_RX 8
|
||||
#define GWSERIAL_MODE "UNI"
|
||||
#ifdef HARDWARE_V21
|
||||
// CAN NMEA2000
|
||||
#define ESP32_CAN_TX_PIN 46
|
||||
#define ESP32_CAN_RX_PIN 3
|
||||
// Bus load in 50mA steps
|
||||
#define N2K_LOAD_LEVEL 5 // 5x50mA = 250mA max bus load with back light on
|
||||
// RS485 NMEA0183
|
||||
#define GWSERIAL_TX 17
|
||||
#define GWSERIAL_RX 8
|
||||
#define GWSERIAL_MODE "UNI"
|
||||
#endif
|
||||
#ifdef HARDWARE_LIGHT
|
||||
// CAN NMEA2000
|
||||
#define ESP32_CAN_TX_PIN 15
|
||||
#define ESP32_CAN_RX_PIN 16
|
||||
// Bus load in 50mA steps
|
||||
#define N2K_LOAD_LEVEL 2 // 5x50mA = 100mA max bus load with back light on
|
||||
// RS485 NMEA0183
|
||||
#define GWSERIAL_TX 9
|
||||
#define GWSERIAL_RX 14
|
||||
#define GWSERIAL_MODE "UNI"
|
||||
#endif
|
||||
// Allowed to set a new password for access point
|
||||
#define FORCE_AP_PWCHANGE
|
||||
|
||||
|
||||
@@ -9,22 +9,25 @@ board_build.variants_dir = variants
|
||||
#board = obp60_s3_n8 #ESP32-S3 N8, 8MB flash, no PSRAM
|
||||
#board = obp60_s3_n16 #ESP32-S3 N16,16MB flash, no PSRAM, zero series
|
||||
#board = obp60_s3_n8r8 #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM
|
||||
board = obp60_s3_n16r8 #ESP32-S3 N16R8, 16MB flash, 8MB PSRAM, production series
|
||||
#board_build.partitions = default_8MB.csv #ESP32-S3 N8, 8MB flash
|
||||
board_build.partitions = default_16MB.csv #ESP32-S3 N16, 16MB flash
|
||||
#board = obp60_s3_n16r8 #ESP32-S3 N16R8, 16MB flash, 8MB PSRAM, production series
|
||||
board = obp60_s3_light_n8r8 #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM, OBP60 clone
|
||||
board_build.partitions = default_8MB.csv #ESP32-S3 N8, 8MB flash
|
||||
#board_build.partitions = default_16MB.csv #ESP32-S3 N16, 16MB flash
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
${basedeps.lib_deps}
|
||||
Wire
|
||||
SPI
|
||||
SD
|
||||
esphome/AsyncTCP-esphome@2.0.1
|
||||
robtillaart/PCF8574@0.3.9
|
||||
adafruit/Adafruit Unified Sensor @ 1.1.13
|
||||
blemasle/MCP23017@2.0.0
|
||||
adafruit/Adafruit BusIO@1.5.0
|
||||
adafruit/Adafruit GFX Library@1.11.9
|
||||
zinggjm/GxEPD2@1.5.8
|
||||
#zinggjm/GxEPD2@1.5.8
|
||||
#https://github.com/ZinggJM/GxEPD2
|
||||
https://github.com/thooge/GxEPD2
|
||||
sstaub/Ticker@4.4.0
|
||||
adafruit/Adafruit BMP280 Library@2.6.2
|
||||
adafruit/Adafruit BME280 Library@2.2.2
|
||||
@@ -34,23 +37,26 @@ lib_deps =
|
||||
paulstoffregen/OneWire@2.3.8
|
||||
milesburton/DallasTemperature@3.11.0
|
||||
signetica/SunRise@2.0.2
|
||||
adafruit/Adafruit FRAM I2C@^2.0.3
|
||||
build_flags=
|
||||
#https://thingpulse.com/usb-settings-for-logging-with-the-esp32-s3-in-platformio/?srsltid=AfmBOopGskbkr4GoeVkNlFaZXe_zXkLceKF6Rn-tmoXABCeAR2vWsdHL
|
||||
# -D ARDUINO_USB_MODE=1 #0=OTG (to implement other external devices), 1=CDC (is a serial device)
|
||||
# -D ARDUINO_USB_CDC_ON_BOOT=1 #0=JTAG, 1=CDC (serial device)
|
||||
-D ARDUINO_USB_CDC_ON_BOOT=0 #0=JTAG, 1=CDC (serial device)
|
||||
# -D CORE_DEBUG_LEVEL=1 #Debug level for CPU core via CDC (seral device)
|
||||
# -D TIME=$UNIX_TIME #Set PC time for RTC (only settable via VSC)
|
||||
-D DISABLE_DIAGNOSTIC_OUTPUT #Disable diagnostic output for GxEPD2 lib
|
||||
-D BOARD_OBP60S3 #Board OBP60 V2.1 with ESP32S3
|
||||
# -D HARDWARE_V20 #Hardware revision V2.0
|
||||
-D HARDWARE_V21 #Hardware revision V2.1
|
||||
# -D HARDWARE_V20 #OBP60 hardware revision V2.0
|
||||
# -D HARDWARE_V21 #OBP60 hardware revision V2.1
|
||||
-D HARDWARE_LIGHT #OBP60 hardware clone
|
||||
# -D DISPLAY_GDEW042T2 #old E-Ink display from Waveshare, R10 0.47 ohm
|
||||
-D DISPLAY_GDEY042T81 #new E-Ink display from Waveshare, R10 2.2 ohm
|
||||
# -D DISPLAY_GYE042A87 #alternativ E-Ink display from Genyo Optical, R10 2.2 ohm
|
||||
# -D DISPLAY_SE0420NQ04 #alternativ E-Ink display from SID Technology, R10 2.2 ohm
|
||||
${env.build_flags}
|
||||
#CONFIG_ESP_TASK_WDT_TIMEOUT_S = 10 #Task Watchdog timeout period (seconds) [1...60] 5 default
|
||||
upload_port = /dev/ttyACM0
|
||||
#upload_port = /dev/ttyACM0 #OBP60 original
|
||||
upload_port = /dev/ttyUSB0 #OBP60 clone
|
||||
upload_protocol = esptool #firmware upload via USB OTG seriell, by first upload need to set the ESP32-S3 in the upload mode with shortcut GND to Pin27
|
||||
upload_speed = 230400
|
||||
monitor_speed = 115200
|
||||
|
||||
61
lib/obp60task/platformio.ini.light
Normal file
61
lib/obp60task/platformio.ini.light
Normal file
@@ -0,0 +1,61 @@
|
||||
[platformio]
|
||||
#if you want a pio run to only build
|
||||
#your special environments you can set this here
|
||||
#by uncommenting the next line
|
||||
default_envs = obp60_s3
|
||||
[env:obp60_s3]
|
||||
platform = espressif32@6.8.1
|
||||
board_build.variants_dir = variants
|
||||
#board = obp60_s3_n8 #ESP32-S3 N8, 8MB flash, no PSRAM
|
||||
#board = obp60_s3_n16 #ESP32-S3 N16,16MB flash, no PSRAM, zero series
|
||||
#board = obp60_s3_n8r8 #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM
|
||||
#board = obp60_s3_n16r8 #ESP32-S3 N16R8, 16MB flash, 8MB PSRAM, production series
|
||||
board = obp60_s3_light_n8r8 #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM, OBP60 clone
|
||||
board_build.partitions = default_8MB.csv #ESP32-S3 N8, 8MB flash
|
||||
#board_build.partitions = default_16MB.csv #ESP32-S3 N16, 16MB flash
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
${basedeps.lib_deps}
|
||||
Wire
|
||||
SPI
|
||||
esphome/AsyncTCP-esphome@2.0.1
|
||||
robtillaart/PCF8574@0.3.9
|
||||
adafruit/Adafruit Unified Sensor @ 1.1.13
|
||||
blemasle/MCP23017@2.0.0
|
||||
adafruit/Adafruit BusIO@1.5.0
|
||||
adafruit/Adafruit GFX Library@1.11.9
|
||||
#zinggjm/GxEPD2@1.5.8
|
||||
#https://github.com/ZinggJM/GxEPD2
|
||||
https://github.com/thooge/GxEPD2
|
||||
sstaub/Ticker@4.4.0
|
||||
adafruit/Adafruit BMP280 Library@2.6.2
|
||||
adafruit/Adafruit BME280 Library@2.2.2
|
||||
adafruit/Adafruit BMP085 Library@1.2.1
|
||||
enjoyneering/HTU21D@1.2.1
|
||||
robtillaart/INA226@0.2.0
|
||||
paulstoffregen/OneWire@2.3.8
|
||||
milesburton/DallasTemperature@3.11.0
|
||||
signetica/SunRise@2.0.2
|
||||
adafruit/Adafruit FRAM I2C@^2.0.3
|
||||
build_flags=
|
||||
#https://thingpulse.com/usb-settings-for-logging-with-the-esp32-s3-in-platformio/?srsltid=AfmBOopGskbkr4GoeVkNlFaZXe_zXkLceKF6Rn-tmoXABCeAR2vWsdHL
|
||||
# -D ARDUINO_USB_MODE=1 #0=OTG (to implement other external devices), 1=CDC (is a serial device)
|
||||
# -D ARDUINO_USB_CDC_ON_BOOT=1 #0=JTAG, 1=CDC (serial device)
|
||||
# -D CORE_DEBUG_LEVEL=1 #Debug level for CPU core via CDC (seral device)
|
||||
# -D TIME=$UNIX_TIME #Set PC time for RTC (only settable via VSC)
|
||||
-D DISABLE_DIAGNOSTIC_OUTPUT #Disable diagnostic output for GxEPD2 lib
|
||||
-D BOARD_OBP60S3 #Board OBP60 V2.1 with ESP32S3
|
||||
# -D HARDWARE_V20 #OBP60 hardware revision V2.0
|
||||
# -D HARDWARE_V21 #OBP60 hardware revision V2.1
|
||||
-D HARDWARE_LIGHT #OBP60 hardware clone
|
||||
# -D DISPLAY_GDEW042T2 #old E-Ink display from Waveshare, R10 0.47 ohm
|
||||
-D DISPLAY_GDEY042T81 #new E-Ink display from Waveshare, R10 2.2 ohm
|
||||
# -D DISPLAY_GYE042A87 #alternativ E-Ink display from Genyo Optical, R10 2.2 ohm
|
||||
# -D DISPLAY_SE0420NQ04 #alternativ E-Ink display from SID Technology, R10 2.2 ohm
|
||||
${env.build_flags}
|
||||
#CONFIG_ESP_TASK_WDT_TIMEOUT_S = 10 #Task Watchdog timeout period (seconds) [1...60] 5 default
|
||||
#upload_port = /dev/ttyACM0 #OBP60 original
|
||||
upload_port = /dev/ttyUSB0 #OBP60 clone
|
||||
upload_protocol = esptool #firmware upload via USB OTG seriell, by first upload need to set the ESP32-S3 in the upload mode with shortcut GND to Pin27
|
||||
upload_speed = 230400
|
||||
monitor_speed = 115200
|
||||
61
lib/obp60task/platformio.ini.orig
Normal file
61
lib/obp60task/platformio.ini.orig
Normal file
@@ -0,0 +1,61 @@
|
||||
[platformio]
|
||||
#if you want a pio run to only build
|
||||
#your special environments you can set this here
|
||||
#by uncommenting the next line
|
||||
default_envs = obp60_s3
|
||||
[env:obp60_s3]
|
||||
platform = espressif32@6.8.1
|
||||
board_build.variants_dir = variants
|
||||
#board = obp60_s3_n8 #ESP32-S3 N8, 8MB flash, no PSRAM
|
||||
#board = obp60_s3_n16 #ESP32-S3 N16,16MB flash, no PSRAM, zero series
|
||||
#board = obp60_s3_n8r8 #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM
|
||||
board = obp60_s3_n16r8 #ESP32-S3 N16R8, 16MB flash, 8MB PSRAM, production series
|
||||
#board = obp60_s3_light_n8r8 #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM, OBP60 clone
|
||||
#board_build.partitions = default_8MB.csv #ESP32-S3 N8, 8MB flash
|
||||
board_build.partitions = default_16MB.csv #ESP32-S3 N16, 16MB flash
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
${basedeps.lib_deps}
|
||||
Wire
|
||||
SPI
|
||||
esphome/AsyncTCP-esphome@2.0.1
|
||||
robtillaart/PCF8574@0.3.9
|
||||
adafruit/Adafruit Unified Sensor @ 1.1.13
|
||||
blemasle/MCP23017@2.0.0
|
||||
adafruit/Adafruit BusIO@1.5.0
|
||||
adafruit/Adafruit GFX Library@1.11.9
|
||||
#zinggjm/GxEPD2@1.5.8
|
||||
#https://github.com/ZinggJM/GxEPD2
|
||||
https://github.com/thooge/GxEPD2
|
||||
sstaub/Ticker@4.4.0
|
||||
adafruit/Adafruit BMP280 Library@2.6.2
|
||||
adafruit/Adafruit BME280 Library@2.2.2
|
||||
adafruit/Adafruit BMP085 Library@1.2.1
|
||||
enjoyneering/HTU21D@1.2.1
|
||||
robtillaart/INA226@0.2.0
|
||||
paulstoffregen/OneWire@2.3.8
|
||||
milesburton/DallasTemperature@3.11.0
|
||||
signetica/SunRise@2.0.2
|
||||
adafruit/Adafruit FRAM I2C@^2.0.3
|
||||
build_flags=
|
||||
#https://thingpulse.com/usb-settings-for-logging-with-the-esp32-s3-in-platformio/?srsltid=AfmBOopGskbkr4GoeVkNlFaZXe_zXkLceKF6Rn-tmoXABCeAR2vWsdHL
|
||||
# -D ARDUINO_USB_MODE=1 #0=OTG (to implement other external devices), 1=CDC (is a serial device)
|
||||
# -D ARDUINO_USB_CDC_ON_BOOT=1 #0=JTAG, 1=CDC (serial device)
|
||||
# -D CORE_DEBUG_LEVEL=1 #Debug level for CPU core via CDC (seral device)
|
||||
# -D TIME=$UNIX_TIME #Set PC time for RTC (only settable via VSC)
|
||||
-D DISABLE_DIAGNOSTIC_OUTPUT #Disable diagnostic output for GxEPD2 lib
|
||||
-D BOARD_OBP60S3 #Board OBP60 V2.1 with ESP32S3
|
||||
# -D HARDWARE_V20 #OBP60 hardware revision V2.0
|
||||
-D HARDWARE_V21 #OBP60 hardware revision V2.1
|
||||
# -D HARDWARE_LIGHT #OBP60 hardware clone
|
||||
# -D DISPLAY_GDEW042T2 #old E-Ink display from Waveshare, R10 0.47 ohm
|
||||
-D DISPLAY_GDEY042T81 #new E-Ink display from Waveshare, R10 2.2 ohm
|
||||
# -D DISPLAY_GYE042A87 #alternativ E-Ink display from Genyo Optical, R10 2.2 ohm
|
||||
# -D DISPLAY_SE0420NQ04 #alternativ E-Ink display from SID Technology, R10 2.2 ohm
|
||||
${env.build_flags}
|
||||
#CONFIG_ESP_TASK_WDT_TIMEOUT_S = 10 #Task Watchdog timeout period (seconds) [1...60] 5 default
|
||||
upload_port = /dev/ttyACM0 #OBP60 original
|
||||
#upload_port = /dev/ttyUSB0 #OBP60 clone
|
||||
upload_protocol = esptool #firmware upload via USB OTG seriell, by first upload need to set the ESP32-S3 in the upload mode with shortcut GND to Pin27
|
||||
upload_speed = 230400
|
||||
monitor_speed = 115200
|
||||
74
variants/obp60s3_light/pins_arduino.h
Normal file
74
variants/obp60s3_light/pins_arduino.h
Normal file
@@ -0,0 +1,74 @@
|
||||
#ifndef Pins_Arduino_h
|
||||
#define Pins_Arduino_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#define USB_VID 0x303a
|
||||
#define USB_PID 0x1001
|
||||
|
||||
/*
|
||||
#define EXTERNAL_NUM_INTERRUPTS 46
|
||||
#define NUM_DIGITAL_PINS 48
|
||||
#define NUM_ANALOG_INPUTS 20
|
||||
|
||||
// Multi Function Display OBP60 V2.0
|
||||
static const uint8_t LED_BUILTIN = SOC_GPIO_PIN_COUNT+48;
|
||||
#define BUILTIN_LED LED_BUILTIN // backward compatibility
|
||||
#define LED_BUILTIN LED_BUILTIN
|
||||
#define RGB_BUILTIN LED_BUILTIN
|
||||
#define RGB_BRIGHTNESS 64
|
||||
|
||||
#define analogInputToDigitalPin(p) (((p)<20)?(analogChannelToDigitalPin(p)):-1)
|
||||
#define digitalPinToInterrupt(p) (((p)<48)?(p):-1)
|
||||
#define digitalPinHasPWM(p) (p < 46)
|
||||
*/
|
||||
|
||||
static const uint8_t TX = 43;
|
||||
static const uint8_t RX = 44;
|
||||
|
||||
static const uint8_t SDA = 21;
|
||||
static const uint8_t SCL = 38;
|
||||
|
||||
static const uint8_t SS = 45;
|
||||
static const uint8_t MOSI = 11;
|
||||
static const uint8_t MISO = 13;
|
||||
static const uint8_t SCK = 12;
|
||||
|
||||
static const uint8_t A0 = 1;
|
||||
static const uint8_t A1 = 2;
|
||||
static const uint8_t A2 = 3;
|
||||
static const uint8_t A3 = 4;
|
||||
static const uint8_t A4 = 5;
|
||||
static const uint8_t A5 = 6;
|
||||
static const uint8_t A6 = 7;
|
||||
static const uint8_t A7 = 8;
|
||||
static const uint8_t A8 = 9;
|
||||
static const uint8_t A9 = 10;
|
||||
static const uint8_t A10 = 11;
|
||||
static const uint8_t A11 = 12;
|
||||
static const uint8_t A12 = 13;
|
||||
static const uint8_t A13 = 14;
|
||||
static const uint8_t A14 = 15;
|
||||
static const uint8_t A15 = 16;
|
||||
static const uint8_t A16 = 17;
|
||||
static const uint8_t A17 = 18;
|
||||
static const uint8_t A18 = 19;
|
||||
static const uint8_t A19 = 20;
|
||||
|
||||
static const uint8_t T1 = 1;
|
||||
static const uint8_t T2 = 2;
|
||||
static const uint8_t T3 = 3;
|
||||
static const uint8_t T4 = 4;
|
||||
static const uint8_t T5 = 5;
|
||||
static const uint8_t T6 = 6;
|
||||
static const uint8_t T7 = 7;
|
||||
static const uint8_t T8 = 8;
|
||||
static const uint8_t T9 = 9;
|
||||
static const uint8_t T10 = 10;
|
||||
static const uint8_t T11 = 11;
|
||||
static const uint8_t T12 = 12;
|
||||
static const uint8_t T13 = 13;
|
||||
static const uint8_t T14 = 14;
|
||||
|
||||
#endif /* Pins_Arduino_h */
|
||||
Reference in New Issue
Block a user