1
0
mirror of https://github.com/thooge/esp32-nmea2000-obp60.git synced 2026-08-18 18:32:30 +02:00
Files
esp32-nmea2000-obp60/lib/obp60task/OBP60Extensions.h
T
2026-02-28 15:55:52 +00:00

414 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#ifndef _OBP60EXTENSIONPORT_H
#define _OBP60EXTENSIONPORT_H
#include <Arduino.h>
#include "OBP60Hardware.h"
#include "LedSpiTask.h"
#include "Graphics.h"
#include <GxEPD2_BW.h> // E-paper lib V2
#include <Adafruit_FRAM_I2C.h> // I2C FRAM
#include <math.h>
#ifdef DISPLAY_ST7796
#include <LovyanGFX.hpp> // TFT LCD lib for ST7796
#endif
#ifdef BOARD_OBP40S3
#include "esp_vfs_fat.h"
#include "sdmmc_cmd.h"
#define MOUNT_POINT "/sdcard"
#endif
// FRAM address reservations 32kB: 0x0000 - 0x7FFF
// 0x0000 - 0x03ff: single variables
#define FRAM_PAGE_NO 0x0002
#define FRAM_SYSTEM_MODE 0x009
// Voltage page
#define FRAM_VOLTAGE_AVG 0x000A
#define FRAM_VOLTAGE_TREND 0x000B
#define FRAM_VOLTAGE_MODE 0x000C
// Wind page
#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
#define PI 3.1415926535897932384626433832795
#define EARTH_RADIUS 6371000.0
extern Adafruit_FRAM_I2C fram;
extern bool hasFRAM;
extern bool hasSDCard;
#ifdef BOARD_OBP40S3
extern sdmmc_card_t *sdcard;
#endif
// Fonts declarations for display (#includes see OBP60Extensions.cpp)
extern const GFXfont DSEG7Classic_BoldItalic16pt7b;
extern const GFXfont DSEG7Classic_BoldItalic20pt7b;
extern const GFXfont DSEG7Classic_BoldItalic26pt7b;
extern const GFXfont DSEG7Classic_BoldItalic30pt7b;
extern const GFXfont DSEG7Classic_BoldItalic42pt7b;
extern const GFXfont DSEG7Classic_BoldItalic60pt7b;
extern const GFXfont Ubuntu_Bold8pt8b;
extern const GFXfont Ubuntu_Bold10pt8b;
extern const GFXfont Ubuntu_Bold12pt8b;
extern const GFXfont Ubuntu_Bold16pt8b;
extern const GFXfont Ubuntu_Bold20pt8b;
extern const GFXfont Ubuntu_Bold32pt8b;
extern const GFXfont Atari16px;
extern const GFXfont IBM8x8px;
// Global functions
#ifdef DISPLAY_GDEW042T2
GxEPD2_BW<GxEPD2_420, GxEPD2_420::HEIGHT> & getdisplay();
#endif
#ifdef DISPLAY_GDEY042T81
GxEPD2_BW<GxEPD2_420_GDEY042T81, GxEPD2_420_GDEY042T81::HEIGHT> & getdisplay();
#endif
#ifdef DISPLAY_GYE042A87
GxEPD2_BW<GxEPD2_420_GYE042A87, GxEPD2_420_GYE042A87::HEIGHT> & getdisplay();
#endif
#ifdef DISPLAY_SE0420NQ04
GxEPD2_BW<GxEPD2_420_SE0420NQ04, GxEPD2_420_SE0420NQ04::HEIGHT> & getdisplay();
#endif
#ifdef DISPLAY_ST7796
// LovyanGFX based display wrapper for ST7796
class LGFX : public lgfx::LGFX_Device {
public:
lgfx::Bus_SPI _bus_instance;
lgfx::Light_PWM _light_instance;
LGFX(void) {
{
auto cfg = _bus_instance.config();
cfg.spi_host = SPI2_HOST;
cfg.spi_mode = 0;
cfg.freq_write = 80000000;
cfg.freq_read = 16000000;
cfg.pin_sclk = OBP_SPI_CLK;
cfg.pin_mosi = OBP_SPI_DIN;
cfg.pin_miso = -1;
cfg.pin_dc = OBP_SPI_DC;
_bus_instance.config(cfg);
_panel_instance.setBus(&_bus_instance);
}
{
auto cfg = _panel_instance.config();
cfg.pin_cs = OBP_SPI_CS;
cfg.pin_rst = OBP_SPI_RST;
cfg.pin_busy = -1;
cfg.panel_width = 320; // Native width resolution
cfg.panel_height = 480; // Native hight resolution
cfg.offset_x = 10; // Display output 400x300 pix to housing center adjusted
cfg.offset_y = -20; // Display output 400x300 pix to housing center adjusted
cfg.offset_rotation = 3; // Rotate display content conter clock wise 90 deg
cfg.dummy_read_pixel = 8;
cfg.dummy_read_bits = 1;
cfg.memory_width = 320;
cfg.memory_height = 480;
// cfg.pwm_control not available in this LovyanGFX version
cfg.invert = false;
cfg.rgb_order = false;
cfg.dlen_16bit = false;
cfg.bus_shared = true;
_panel_instance.config(cfg);
}
{
auto cfg = _light_instance.config();
cfg.pin_bl = -1;
_light_instance.config(cfg);
_panel_instance.setLight(&_light_instance);
}
setPanel(&_panel_instance);
}
// compatibility helpers --------------------------------------------------
// Adafruit GFX fonts support: ignore on TFT, use base on E-Ink
void setFont(const GFXfont *font) { (void)font; }
// E-Ink interface compatibility
void setFullWindow() { /* no-op on TFT */ }
private:
lgfx::Panel_ST7796 _panel_instance;
};
LGFX & getdisplay();
#endif
// Page display return values
#define PAGE_OK 0 // all ok, do nothing
#define PAGE_UPDATE 1 // page wants display to update
#define PAGE_HIBERNATE 2 // page wants displey to hibernate
// Draw monochrome bitmap on both E-Ink and TFT displays
// supports various packing and bit orders; optional runtime conversion for TFT
inline void drawMonochromeBitmap(
int16_t x, int16_t y,
const uint8_t *bmp,
int16_t w, int16_t h,
uint16_t color,
bool vertical=false, // true: bytes run vertically (each byte 8 pixels down)
bool lsbFirst=false) // true: least significant bit = left/top pixel
{
#ifdef DISPLAY_ST7796
// TFT converts perpixel
for (int yy = 0; yy < h; yy++) {
for (int xx = 0; xx < w; xx++) {
int byteIdx;
int bitIdx;
if (vertical) {
byteIdx = xx * ((h + 7) / 8) + (yy / 8);
bitIdx = yy % 8;
} else {
byteIdx = yy * ((w + 7) / 8) + (xx / 8);
bitIdx = xx % 8;
}
uint8_t b = bmp[byteIdx];
bool pix;
if (lsbFirst) {
pix = b & (1 << bitIdx);
} else {
pix = b & (1 << (7 - bitIdx));
}
if (pix) {
getdisplay().drawPixel(x + xx, y + yy, color);
}
}
}
#else
// EPaper: just hand over to driver (expects MSBfirst horizontal)
getdisplay().drawBitmap(x, y, bmp, w, h, color);
#endif
}
// Display wrapper functions for E-Ink/TFT compatibility
inline void displayFirstPage() {
#ifdef DISPLAY_ST7796
// TFT LCD doesn't need firstPage()
#else
getdisplay().firstPage();
#endif
}
inline void displayNextPage() {
#ifdef DISPLAY_ST7796
// TFT LCD doesn't need nextPage() for refresh
#else
getdisplay().nextPage();
#endif
}
inline void displaySetPartialWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
#ifdef DISPLAY_ST7796
// TFT LCD doesn't use partial windows
(void)x; (void)y; (void)w; (void)h;
#else
getdisplay().setPartialWindow(x, y, w, h);
#endif
}
inline void displaySetFullWindow() {
#ifdef DISPLAY_ST7796
// TFT LCD doesn't need setFullWindow()
#else
getdisplay().setFullWindow();
#endif
}
// replacement for getTextBounds that works with both EPD and ST7796
inline void displayGetTextBounds(const String &txt, int16_t x, int16_t y,
int16_t *x0, int16_t *y0,
uint16_t *w, uint16_t *h) {
#ifdef DISPLAY_ST7796
// LovyanGFX doesn't expose getTextBounds; compute via helpers
*w = getdisplay().textWidth(txt);
*h = getdisplay().fontHeight();
if (x0) *x0 = 0;
if (y0) *y0 = 0;
#else
getdisplay().getTextBounds(txt, x, y, x0, y0, w, h);
#endif
}
void fillPoly4(const std::vector<Point>& p4, uint16_t color);
void drawPoly(const std::vector<Point>& points, uint16_t color);
void deepSleep(CommonData &common);
uint8_t getLastPage();
void hardwareInit(GwApi *api);
void powerInit(String powermode);
void setPCF8574PortPinModul1(uint8_t pin, uint8_t value);// Set PCF8574 port pin
void setPortPin(uint pin, bool value); // Set port pin for extension port
void togglePortPin(uint pin); // Toggle extension port pin
Color colorMapping(const String &colorString); // Color mapping string to CHSV colors
void setBacklightLED(uint brightness, const Color &color);// Set backlight LEDs
void toggleBacklightLED(uint brightness,const Color &color);// Toggle backlight LEDs
void stepsBacklightLED(uint brightness, const Color &color);// Set backlight LEDs in 4 steps (100%, 50%, 10%, 0%)
BacklightMode backlightMapping(const String &backlightString);// Configuration string to value
void setFlashLED(bool status); // Set flash LED
void blinkingFlashLED(); // Blinking function for flash LED
void setBlinkingLED(bool on); // Set blinking flash LED active
void buzzer(uint frequency, uint duration); // Buzzer function
void setBuzzerPower(uint power); // Set buzzer power
String xdrDelete(String input); // Delete xdr prefix from string
void drawTextCenter(int16_t cx, int16_t cy, String text);
void drawButtonCenter(int16_t cx, int16_t cy, int8_t sx, int8_t sy, String text, uint16_t fg, uint16_t bg, bool inverted);
void drawTextRalign(int16_t x, int16_t y, String text);
void drawTextBoxed(Rect box, String text, uint16_t fg, uint16_t bg, bool inverted, bool border);
void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color);
void displayTrendLow(int16_t x, int16_t y, uint16_t size, uint16_t color);
void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatValue *time, GwApi::BoatValue *hdop); // Draw display header
void displayFooter(CommonData &commonData);
void displayAlarm(CommonData &commonData);
SunData calcSunsetSunrise(double time, double date, double latitude, double longitude, float timezone); // Calulate sunset and sunrise
SunData calcSunsetSunriseRTC(struct tm *rtctime, double latitude, double longitude, float timezone);
void batteryGraphic(uint x, uint y, float percent, int pcolor, int bcolor); // Battery graphic with fill level
void solarGraphic(uint x, uint y, int pcolor, int bcolor); // Solar graphic
void generatorGraphic(uint x, uint y, int pcolor, int bcolor); // Generator graphic
void startLedTask(GwApi *api);
// Display rudder position as horizontal bargraph with configurable +/- range (degrees)
// 'rangeDeg' is unsigned and will be clamped to [10,45]
void displayRudderPosition(int rudderPosition, uint8_t rangeDeg, uint16_t cx, uint16_t cy, uint16_t fg, uint16_t bg);
void doImageRequest(GwApi *api, int *pageno, const PageStruct pages[MAX_PAGE_NUMBER], AsyncWebServerRequest *request);
// Icons
#define icon_width 16
#define icon_height 16
static unsigned char left_bits[] PROGMEM = {
0x00, 0x00, 0xc0, 0x01, 0xe0, 0x01, 0xf0, 0x01, 0xf8, 0x01, 0xfc, 0x7f,
0xfe, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xfe, 0x7f, 0xfc, 0x7f, 0xf8, 0x01,
0xf0, 0x01, 0xe0, 0x01, 0xc0, 0x01, 0x00, 0x00 };
static unsigned char right_bits[] PROGMEM = {
0x00, 0x00, 0x80, 0x03, 0x80, 0x07, 0x80, 0x0f, 0x80, 0x1f, 0xfe, 0x3f,
0xfe, 0x7f, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0x7f, 0xfe, 0x3f, 0x80, 0x1f,
0x80, 0x0f, 0x80, 0x07, 0x80, 0x03, 0x00, 0x00 };
static unsigned char lock_bits[] PROGMEM = {
0xc0, 0x03, 0x60, 0x06, 0x30, 0x0c, 0x10, 0x08, 0x10, 0x08, 0x10, 0x08,
0xfc, 0x3f, 0x04, 0x20, 0x04, 0x20, 0x84, 0x21, 0x84, 0x21, 0x84, 0x21,
0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0xfc, 0x3f };
static unsigned char plus_bits[] PROGMEM = {
0x00, 0x00, 0xe0, 0x01, 0x18, 0x06, 0x04, 0x08, 0xc4, 0x08, 0xc2, 0x10,
0xf2, 0x13, 0xf2, 0x13, 0xc2, 0x10, 0xc4, 0x08, 0x04, 0x0c, 0x18, 0x1e,
0xe0, 0x39, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0 };
static unsigned char minus_bits[] PROGMEM = {
0x00, 0x00, 0xe0, 0x01, 0x18, 0x06, 0x04, 0x08, 0x04, 0x08, 0x02, 0x10,
0xf2, 0x13, 0xf2, 0x13, 0x02, 0x10, 0x04, 0x08, 0x04, 0x0c, 0x18, 0x1e,
0xe0, 0x39, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0 };
static unsigned char fram_bits[] PROGMEM = {
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 };
static unsigned char ap_bits[] PROGMEM = {
0xe0, 0x03, 0x18, 0x0c, 0x04, 0x10, 0xc2, 0x21, 0x30, 0x06, 0x08, 0x08,
0xc0, 0x01, 0x20, 0x02, 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xc0, 0x01,
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
static unsigned char dish_bits[] PROGMEM = {
0x3c, 0x00, 0x42, 0x18, 0xfa, 0x1b, 0x02, 0x04, 0x02, 0x0a, 0x02, 0x09,
0x82, 0x08, 0x06, 0x0a, 0x0e, 0x1b, 0x9c, 0x2b, 0x38, 0x2b, 0x74, 0x20,
0xec, 0x1f, 0x1c, 0x00, 0xf4, 0x00, 0xfe, 0x03 };
static std::map<String, unsigned char *> iconmap = {
{"LEFT", left_bits},
{"RIGHT", right_bits},
{"LOCK", lock_bits},
{"PLUS", plus_bits},
{"MINUS", minus_bits},
{"DISH", dish_bits},
{"AP", ap_bits}
};
// Battery
#define battery_width 24
#define battery_height 16
static unsigned char battery_0_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0xff, 0xff, 0x1f,
0x03, 0x00, 0x18, 0x03, 0x00, 0x78, 0x03, 0x00, 0xf8, 0x03, 0x00, 0xd8,
0x03, 0x00, 0xd8, 0x03, 0x00, 0xd8, 0x03, 0x00, 0xf8, 0x03, 0x00, 0x78,
0x03, 0x00, 0x18, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0x0f, 0x00, 0x00, 0x00 };
static unsigned char battery_25_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0xff, 0xff, 0x1f,
0x03, 0x00, 0x18, 0x3b, 0x00, 0x78, 0x3b, 0x00, 0xf8, 0x3b, 0x00, 0xd8,
0x3b, 0x00, 0xd8, 0x3b, 0x00, 0xd8, 0x3b, 0x00, 0xf8, 0x3b, 0x00, 0x78,
0x03, 0x00, 0x18, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0x0f, 0x00, 0x00, 0x00 };
static unsigned char battery_50_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0xff, 0xff, 0x1f,
0x03, 0x00, 0x18, 0xbb, 0x03, 0x78, 0xbb, 0x03, 0xf8, 0xbb, 0x03, 0xd8,
0xbb, 0x03, 0xd8, 0xbb, 0x03, 0xd8, 0xbb, 0x03, 0xf8, 0xbb, 0x03, 0x78,
0x03, 0x00, 0x18, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0x0f, 0x00, 0x00, 0x00 };
static unsigned char battery_75_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0xff, 0xff, 0x1f,
0x03, 0x00, 0x18, 0xbb, 0x3b, 0x78, 0xbb, 0x3b, 0xf8, 0xbb, 0x3b, 0xd8,
0xbb, 0x3b, 0xd8, 0xbb, 0x3b, 0xd8, 0xbb, 0x3b, 0xf8, 0xbb, 0x3b, 0x78,
0x03, 0x00, 0x18, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0x0f, 0x00, 0x00, 0x00 };
static unsigned char battery_100_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0xff, 0xff, 0x1f,
0x03, 0x00, 0x18, 0xbb, 0xbb, 0x7b, 0xbb, 0xbb, 0xfb, 0xbb, 0xbb, 0xdb,
0xbb, 0xbb, 0xdb, 0xbb, 0xbb, 0xdb, 0xbb, 0xbb, 0xfb, 0xbb, 0xbb, 0x7b,
0x03, 0x00, 0x18, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0x0f, 0x00, 0x00, 0x00 };
static unsigned char battery_loading_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xfe, 0xe4, 0x0f, 0xff, 0xec, 0x1f,
0x03, 0x08, 0x18, 0x03, 0x18, 0x78, 0x03, 0x30, 0xf8, 0x83, 0x3f, 0xd8,
0x03, 0x7f, 0xd8, 0x03, 0x03, 0xd8, 0x03, 0x06, 0xf8, 0x03, 0x04, 0x78,
0x03, 0x0c, 0x18, 0xff, 0xcb, 0x1f, 0xfe, 0xd3, 0x0f, 0x00, 0x10, 0x00 };
// Other symbols
#define swipe_width 24
#define swipe_height 16
static unsigned char swipe_bits[] PROGMEM = {
0x00, 0x06, 0x00, 0x24, 0x09, 0x24, 0x12, 0x09, 0x48, 0x7f, 0x09, 0xfe,
0x12, 0xb9, 0x48, 0x24, 0xc9, 0x25, 0x40, 0x49, 0x02, 0xa0, 0x49, 0x06,
0x20, 0x01, 0x0a, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08,
0x80, 0x00, 0x04, 0x00, 0x01, 0x04, 0x00, 0x02, 0x02, 0x00, 0xfc, 0x01 };
#define exclamation_width 32
#define exclamation_height 32
static unsigned char exclamation_bits[] PROGMEM = {
0x00, 0xc0, 0x03, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0xb0, 0x0d, 0x00,
0x00, 0xd8, 0x1b, 0x00, 0x00, 0xec, 0x37, 0x00, 0x00, 0xf6, 0x6f, 0x00,
0x00, 0x3b, 0xdc, 0x00, 0x80, 0x3d, 0xbc, 0x01, 0xc0, 0x3e, 0x7c, 0x03,
0x60, 0x3f, 0xfc, 0x06, 0xb0, 0x3f, 0xfc, 0x0d, 0xd8, 0x3f, 0xfc, 0x1b,
0xec, 0x3f, 0xfc, 0x37, 0xf6, 0x3f, 0xfc, 0x6f, 0xfb, 0x3f, 0xfc, 0xdf,
0xfd, 0x3f, 0xfc, 0xbf, 0xfd, 0x3f, 0xfc, 0xbf, 0xfb, 0x3f, 0xfc, 0xdf,
0xf6, 0x3f, 0xfc, 0x6f, 0xec, 0x3f, 0xfc, 0x37, 0xd8, 0xff, 0xff, 0x1b,
0xb0, 0xff, 0xff, 0x0d, 0x60, 0x3f, 0xfc, 0x06, 0xc0, 0x3e, 0x7c, 0x03,
0x80, 0x3d, 0xbc, 0x01, 0x00, 0x3b, 0xdc, 0x00, 0x00, 0xf6, 0x6f, 0x00,
0x00, 0xec, 0x37, 0x00, 0x00, 0xd8, 0x1b, 0x00, 0x00, 0xb0, 0x0d, 0x00,
0x00, 0x60, 0x06, 0x00, 0x00, 0xc0, 0x03, 0x00 };
#endif