Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 52 additions & 39 deletions src/helpers/ui/SH1106Display.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
#include "SH1106Display.h"
#include <Adafruit_GrayOLED.h>
#include "Adafruit_SH110X.h"

bool SH1106Display::i2c_probe(TwoWire &wire, uint8_t addr)
{
Expand All @@ -9,16 +7,28 @@ bool SH1106Display::i2c_probe(TwoWire &wire, uint8_t addr)
return (error == 0);
}

// Color scheme
ColorVal UIColor::window_bkg = SH110X_BLACK;
ColorVal UIColor::title_bkg = SH110X_BLACK;
ColorVal UIColor::title_txt = SH110X_WHITE;
ColorVal UIColor::primary_txt = SH110X_WHITE;
ColorVal UIColor::secondary_txt = SH110X_WHITE;
ColorVal UIColor::warning_txt = SH110X_WHITE;
ColorVal UIColor::popup_bkg = SH110X_BLACK;
ColorVal UIColor::popup_txt = SH110X_WHITE;
ColorVal UIColor::corp_blue = SH110X_WHITE;
// Color scheme (monochrome: 0 = off, 1 = on)
ColorVal UIColor::window_bkg = 0;
ColorVal UIColor::title_bkg = 0;
ColorVal UIColor::title_txt = 1;
ColorVal UIColor::primary_txt = 1;
ColorVal UIColor::secondary_txt = 1;
ColorVal UIColor::warning_txt = 1;
ColorVal UIColor::popup_bkg = 0;
ColorVal UIColor::popup_txt = 1;
ColorVal UIColor::corp_blue = 1;

void SH1106Display::applyFont(int sz)
{
// Both fonts are the X11 "fixed" family (public domain, ISO10646-encoded)
// with full Basic Latin + Cyrillic glyph coverage, so message text and
// node names render correctly regardless of script.
if (sz >= 2) {
_u8g2.setFont(u8g2_font_10x20_t_cyrillic);
} else {
_u8g2.setFont(u8g2_font_6x12_t_cyrillic);
}
}

bool SH1106Display::begin()
{
Expand All @@ -33,86 +43,89 @@ bool SH1106Display::begin()
} else if (i2c_probe(Wire, DISPLAY_ADDRESS ^ 1)) {
addr = DISPLAY_ADDRESS ^ 1;
}
// Run the Adafruit init even when no panel answered: it is what allocates
// the frame buffer and the I2C device. Skipping it leaves i2c_dev and
// spi_dev NULL, and UITask::begin() calls turnOn() regardless of our
// return value, which then dereferences the null spi_dev.
bool ok = display.begin(addr ? addr : DISPLAY_ADDRESS, true);
_u8g2.setI2CAddress((addr ? addr : DISPLAY_ADDRESS) << 1); // u8g2 wants 8-bit address
bool ok = _u8g2.begin();
if (ok) {
_u8g2.setFontPosTop(); // y coordinate = top of text, not baseline
_u8g2.setFontMode(1); // transparent background
applyFont(1);
}
return addr != 0 && ok;
}

void SH1106Display::turnOn()
{
display.oled_command(SH110X_DISPLAYON);
_u8g2.setPowerSave(0);
_isOn = true;
}

void SH1106Display::turnOff()
{
display.oled_command(SH110X_DISPLAYOFF);
_u8g2.setPowerSave(1);
_isOn = false;
}

void SH1106Display::clear()
{
display.clearDisplay();
display.display();
_u8g2.clearBuffer();
_u8g2.sendBuffer();
}

void SH1106Display::startFrame(ColorVal bkg)
{
display.clearDisplay(); // TODO: apply 'bkg'
_color = SH110X_WHITE;
display.setTextColor(_color);
display.setTextSize(1);
display.cp437(true); // Use full 256 char 'Code Page 437' font
_u8g2.clearBuffer(); // TODO: apply 'bkg'
_drawColor = UIColor::primary_txt;
_u8g2.setDrawColor(_drawColor);
applyFont(1);
}

void SH1106Display::setTextSize(int sz)
{
display.setTextSize(sz);
applyFont(sz);
}

void SH1106Display::setColor(ColorVal c)
{
_color = c;
display.setTextColor(_color);
_drawColor = c;
_u8g2.setDrawColor(_drawColor);
}

void SH1106Display::setCursor(int x, int y)
{
display.setCursor(x, y);
_cursorX = x;
_cursorY = y;
}

void SH1106Display::print(const char *str)
{
display.print(str);
_u8g2.drawUTF8(_cursorX, _cursorY, str);
}

void SH1106Display::fillRect(int x, int y, int w, int h)
{
display.fillRect(x, y, w, h, _color);
_u8g2.drawBox(x, y, w, h);
}

void SH1106Display::drawRect(int x, int y, int w, int h)
{
display.drawRect(x, y, w, h, _color);
_u8g2.drawFrame(x, y, w, h);
}

void SH1106Display::drawXbm(int x, int y, const uint8_t *bits, int w, int h)
{
display.drawBitmap(x, y, bits, w, h, _color);
// Icon/logo data in this codebase is packed MSB-first per row (the
// Adafruit_GFX::drawBitmap() convention), not U8g2's own LSB-first XBM
// format, so use U8g2's u8glib-compatible drawBitmap() instead of
// drawXBM() to avoid every byte's bits coming out mirrored/garbled.
_u8g2.drawBitmap(x, y, (w + 7) / 8, h, bits);
}

uint16_t SH1106Display::getTextWidth(const char *str)
{
int16_t x1, y1;
uint16_t w, h;
display.getTextBounds(str, 0, 0, &x1, &y1, &w, &h);
return w;
return _u8g2.getUTF8Width(str);
}

void SH1106Display::endFrame()
{
display.display();
_u8g2.sendBuffer();
}
26 changes: 16 additions & 10 deletions src/helpers/ui/SH1106Display.h
Original file line number Diff line number Diff line change
@@ -1,29 +1,26 @@
#pragma once

#include "DisplayDriver.h"
#include <U8g2lib.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#define SH110X_NO_SPLASH
#include <Adafruit_SH110X.h>

#ifndef PIN_OLED_RESET
#define PIN_OLED_RESET -1
#endif

#ifndef DISPLAY_ADDRESS
#define DISPLAY_ADDRESS 0x3C
#endif

class SH1106Display : public DisplayDriver
{
Adafruit_SH1106G display;
U8G2_SH1106_128X64_NONAME_F_HW_I2C _u8g2;
bool _isOn;
uint8_t _color;
uint8_t _drawColor;
int _cursorX, _cursorY;

bool i2c_probe(TwoWire &wire, uint8_t addr);
void applyFont(int sz);

public:
SH1106Display() : DisplayDriver(128, 64), display(128, 64, &Wire, PIN_OLED_RESET) { _isOn = false; }
SH1106Display() : DisplayDriver(128, 64), _u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE),
_isOn(false), _drawColor(1), _cursorX(0), _cursorY(0) {}
bool begin();

bool isOn() override { return _isOn; }
Expand All @@ -40,4 +37,13 @@ class SH1106Display : public DisplayDriver
void drawXbm(int x, int y, const uint8_t *bits, int w, int h) override;
uint16_t getTextWidth(const char *str) override;
void endFrame() override;

// The Cyrillic-capable U8g2 fonts used below can render the real UTF-8 text
// directly, so skip the base class's default block-character fallback.
void translateUTF8ToBlocks(char* dest, const char* src, size_t dest_size) override {
size_t len = strlen(src);
if (len >= dest_size) len = dest_size - 1;
memcpy(dest, src, len);
dest[len] = 0;
}
};
2 changes: 1 addition & 1 deletion variants/lilygo_tbeam_1w/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ build_src_filter = ${esp32_base.build_src_filter}

lib_deps =
${esp32_base.lib_deps}
adafruit/Adafruit SH110X @ ~2.1.13
olikraus/U8g2 @ ^2.35.19
stevemarple/MicroNMEA @ ~2.0.6

; === LILYGO T-Beam 1W Repeater ===
Expand Down
2 changes: 1 addition & 1 deletion variants/lilygo_tbeam_supreme_SX1262/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ board_upload.maximum_size = 8388608
lib_deps =
${esp32_base.lib_deps}
lewisxhe/XPowersLib @ ^0.2.7
adafruit/Adafruit SH110X @ ^2.1.13
olikraus/U8g2 @ ^2.35.19
stevemarple/MicroNMEA @ ^2.0.6
adafruit/Adafruit BME280 Library @ ^2.3.0

Expand Down
3 changes: 1 addition & 2 deletions variants/nano_g2_ultra/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ build_src_filter = ${nrf52_base.build_src_filter}
debug_tool = jlink
upload_protocol = nrfutil
lib_deps = ${nrf52_base.lib_deps}
adafruit/Adafruit SH110X @ ~2.1.13
adafruit/Adafruit GFX Library @ ^1.12.1
olikraus/U8g2 @ ^2.35.19
stevemarple/MicroNMEA @ ^2.0.6

[env:Nano_G2_Ultra_repeater]
Expand Down
3 changes: 1 addition & 2 deletions variants/station_g2/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ build_src_filter = ${esp32_base.build_src_filter}
lib_deps =
${esp32_base.lib_deps}
${sensor_base.lib_deps}
adafruit/Adafruit SH110X @ ~2.1.13
adafruit/Adafruit GFX Library @ ^1.12.1
olikraus/U8g2 @ ^2.35.19

[env:Station_G2_repeater]
extends = Station_G2
Expand Down
3 changes: 1 addition & 2 deletions variants/station_g3_esp32/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ build_src_filter = ${esp32_base.build_src_filter}
lib_deps =
${esp32_base.lib_deps}
${sensor_base.lib_deps}
adafruit/Adafruit SH110X @ ~2.1.13
adafruit/Adafruit GFX Library @ ^1.12.1
olikraus/U8g2 @ ^2.35.19

[env:Station_G3_ESP32_repeater]
extends = Station_G3_ESP32
Expand Down
3 changes: 1 addition & 2 deletions variants/thinknode_m2/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ build_src_filter = ${esp32_base.build_src_filter}
+<helpers/ui/MomentaryButton.cpp>
+<../variants/thinknode_m2>
lib_deps = ${esp32_base.lib_deps}
adafruit/Adafruit SH110X @ ~2.1.13
adafruit/Adafruit GFX Library @ ^1.12.1
olikraus/U8g2 @ ^2.35.19

[env:ThinkNode_M2_Repeater]
extends = ThinkNode_M2
Expand Down
3 changes: 1 addition & 2 deletions variants/wio-tracker-l1/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ build_src_filter = ${nrf52_base.build_src_filter}
+<helpers/sensors>
lib_deps= ${nrf52_base.lib_deps}
${sensor_base.lib_deps}
adafruit/Adafruit SH110X @ ^2.1.13
adafruit/Adafruit GFX Library @ ^1.12.1
olikraus/U8g2 @ ^2.35.19

[env:WioTrackerL1_repeater]
extends = WioTrackerL1
Expand Down