From 4b734f1bac022f8de3ef71cf49e60be583671369 Mon Sep 17 00:00:00 2001 From: pelgraine <140762863+pelgraine@users.noreply.github.com> Date: Tue, 5 May 2026 12:43:53 +1000 Subject: [PATCH] updated drivers for t-echo card --- src/helpers/ui/SSD1306Display.cpp | 20 ++++- src/helpers/ui/SSD1306Display.h | 9 ++- src/helpers/ui/U8g2Display.h | 127 ++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 src/helpers/ui/U8g2Display.h diff --git a/src/helpers/ui/SSD1306Display.cpp b/src/helpers/ui/SSD1306Display.cpp index c9da0cf8..464b2642 100644 --- a/src/helpers/ui/SSD1306Display.cpp +++ b/src/helpers/ui/SSD1306Display.cpp @@ -7,6 +7,10 @@ bool SSD1306Display::i2c_probe(TwoWire& wire, uint8_t addr) { } bool SSD1306Display::begin() { + if (!_isOn) { + if (_peripher_power) _peripher_power->claim(); + _isOn = true; + } #ifdef DISPLAY_ROTATION display.setRotation(DISPLAY_ROTATION); #endif @@ -14,13 +18,25 @@ bool SSD1306Display::begin() { } void SSD1306Display::turnOn() { + if (!_isOn) { + if (_peripher_power) _peripher_power->claim(); + _isOn = true; // set before begin() to prevent double claim + if (_peripher_power) begin(); // re-init display after power was cut + } display.ssd1306_command(SSD1306_DISPLAYON); - _isOn = true; } void SSD1306Display::turnOff() { display.ssd1306_command(SSD1306_DISPLAYOFF); - _isOn = false; + if (_isOn) { + if (_peripher_power) { +#if PIN_OLED_RESET >= 0 + digitalWrite(PIN_OLED_RESET, LOW); +#endif + _peripher_power->release(); + } + _isOn = false; + } } void SSD1306Display::clear() { diff --git a/src/helpers/ui/SSD1306Display.h b/src/helpers/ui/SSD1306Display.h index 1a3a9602..d843da85 100644 --- a/src/helpers/ui/SSD1306Display.h +++ b/src/helpers/ui/SSD1306Display.h @@ -5,6 +5,7 @@ #include #define SSD1306_NO_SPLASH #include +#include #ifndef PIN_OLED_RESET #define PIN_OLED_RESET 21 // Reset pin # (or -1 if sharing Arduino reset pin) @@ -18,10 +19,16 @@ class SSD1306Display : public DisplayDriver { Adafruit_SSD1306 display; bool _isOn; uint8_t _color; + RefCountedDigitalPin* _peripher_power; bool i2c_probe(TwoWire& wire, uint8_t addr); public: - SSD1306Display() : DisplayDriver(128, 64), display(128, 64, &Wire, PIN_OLED_RESET) { _isOn = false; } + SSD1306Display(RefCountedDigitalPin* peripher_power=NULL) : DisplayDriver(128, 64), + display(128, 64, &Wire, PIN_OLED_RESET), + _peripher_power(peripher_power) + { + _isOn = false; + } bool begin(); bool isOn() override { return _isOn; } diff --git a/src/helpers/ui/U8g2Display.h b/src/helpers/ui/U8g2Display.h new file mode 100644 index 00000000..5d736dc3 --- /dev/null +++ b/src/helpers/ui/U8g2Display.h @@ -0,0 +1,127 @@ +#pragma once + +#include "DisplayDriver.h" +#include +#include + +#ifndef DISPLAY_ADDRESS + #define DISPLAY_ADDRESS 0x3C +#endif + +#ifndef OLED_WIDTH + #define OLED_WIDTH 72 +#endif + +#ifndef OLED_HEIGHT + #define OLED_HEIGHT 40 +#endif + +class U8g2Display : public DisplayDriver { + // U8g2 constructor for SSD1306/SSD1315 72×40 panel — handles all + // GDDRAM column/page offsets, SETMULTIPLEX, SETDISPLAYOFFSET internally + U8G2_SSD1306_72X40_ER_F_HW_I2C _u8g2; + bool _isOn; + uint8_t _drawColor; + + // Font metrics for current font (cached on setTextSize) + uint8_t _fontAscent; + uint8_t _fontHeight; + + void applyFont(int sz) { + if (sz >= 2) { + _u8g2.setFont(u8g2_font_5x7_mr); // 5×7 — "large" for this display + } else { + _u8g2.setFont(u8g2_font_5x7_mr); + } + _fontAscent = _u8g2.getAscent(); + _fontHeight = _u8g2.getAscent() - _u8g2.getDescent(); + } + +public: + U8g2Display() : DisplayDriver(OLED_WIDTH, OLED_HEIGHT), + _u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE), + _isOn(false), _drawColor(1), _fontAscent(5), _fontHeight(6) {} + + bool begin() { + // Wire must already be initialised by board.begin() before this is called + bool ok = _u8g2.begin(); + if (ok) { + _u8g2.setI2CAddress(DISPLAY_ADDRESS * 2); // U8g2 uses 8-bit address + _u8g2.setFontPosTop(); // y coordinate = top of text, not baseline + _u8g2.setFontMode(1); // transparent background + applyFont(1); // default to compact font + _isOn = true; + } + return ok; + } + + bool isOn() override { return _isOn; } + + void turnOn() override { + _u8g2.setPowerSave(0); + _isOn = true; + } + + void turnOff() override { + _u8g2.setPowerSave(1); + _isOn = false; + } + + void clear() override { + _u8g2.clearBuffer(); + _u8g2.sendBuffer(); + } + + void startFrame(Color bkg = DARK) override { + _u8g2.clearBuffer(); + _drawColor = 1; + _u8g2.setDrawColor(1); + applyFont(1); + } + + void setTextSize(int sz) override { + applyFont(sz); + } + + void setColor(Color c) override { + _drawColor = (c != DARK) ? 1 : 0; + _u8g2.setDrawColor(_drawColor); + } + + void setCursor(int x, int y) override { + _cursorX = x; + _cursorY = y; + } + + void print(const char* str) override { + _u8g2.setDrawColor(_drawColor); + _u8g2.drawStr(_cursorX, _cursorY, str); + } + + void fillRect(int x, int y, int w, int h) override { + _u8g2.setDrawColor(_drawColor); + _u8g2.drawBox(x, y, w, h); + } + + void drawRect(int x, int y, int w, int h) override { + _u8g2.setDrawColor(_drawColor); + _u8g2.drawFrame(x, y, w, h); + } + + void drawXbm(int x, int y, const uint8_t* bits, int w, int h) override { + _u8g2.setDrawColor(1); + _u8g2.drawXBM(x, y, w, h, bits); + } + + uint16_t getTextWidth(const char* str) override { + return _u8g2.getStrWidth(str); + } + + void endFrame() override { + _u8g2.sendBuffer(); + } + +private: + int _cursorX = 0; + int _cursorY = 0; +};