Codex added unified library, all work

This commit is contained in:
John Poole 2026-04-19 10:20:35 -07:00
commit 8370e546ff
25 changed files with 2935 additions and 0 deletions

View file

@ -0,0 +1,14 @@
{
"name": "tbeam_display",
"version": "0.1.0",
"description": "Reusable SH1106 OLED display service for LilyGO T-Beam Supreme exercises.",
"frameworks": "arduino",
"platforms": "espressif32",
"dependencies": [
{
"name": "U8g2",
"owner": "olikraus",
"version": "^2.36.4"
}
]
}

View file

@ -0,0 +1,204 @@
#include "TBeamDisplay.h"
#ifndef OLED_SDA
#define OLED_SDA 17
#endif
#ifndef OLED_SCL
#define OLED_SCL 18
#endif
#ifndef OLED_ADDR
#define OLED_ADDR 0x3C
#endif
namespace tbeam {
TBeamDisplay::TBeamDisplay(TwoWire& wire) : wire_(wire) {}
bool TBeamDisplay::begin(const DisplayConfig& config) {
config_ = config;
clearError();
if (config_.sda < 0) {
config_.sda = OLED_SDA;
}
if (config_.scl < 0) {
config_.scl = OLED_SCL;
}
if (config_.address == 0) {
config_.address = OLED_ADDR;
}
if (config_.beginWire) {
wire_.begin(config_.sda, config_.scl);
}
oled_.setI2CAddress(config_.address << 1);
if (!oled_.begin()) {
ready_ = false;
setError("OLED begin failed");
return false;
}
ready_ = true;
setPowerSave(config_.powerSave);
setFont(DisplayFont::NORMAL);
clear();
return true;
}
void TBeamDisplay::update() {
}
void TBeamDisplay::clear() {
if (!ready_) {
return;
}
oled_.clearBuffer();
oled_.sendBuffer();
}
void TBeamDisplay::clearBuffer() {
for (uint8_t i = 0; i < kMaxLines; ++i) {
lines_[i][0] = '\0';
}
}
void TBeamDisplay::setPowerSave(bool enabled) {
if (!ready_) {
return;
}
oled_.setPowerSave(enabled ? 1 : 0);
powerSave_ = enabled;
}
void TBeamDisplay::setFont(DisplayFont font) {
font_ = font;
if (ready_) {
oled_.setFont(fontFor(font_));
}
}
void TBeamDisplay::showLines(const char* l1,
const char* l2,
const char* l3,
const char* l4,
const char* l5,
const char* l6) {
setLine(0, l1);
setLine(1, l2);
setLine(2, l3);
setLine(3, l4);
setLine(4, l5);
setLine(5, l6);
renderLines();
}
void TBeamDisplay::setLine(uint8_t index, const char* text) {
if (index >= kMaxLines) {
return;
}
strlcpy(lines_[index], text ? text : "", sizeof(lines_[index]));
}
void TBeamDisplay::renderLines(uint8_t lineCount) {
if (!ready_) {
return;
}
if (lineCount > kMaxLines) {
lineCount = kMaxLines;
}
oled_.clearBuffer();
oled_.setFont(fontFor(font_));
uint8_t yStart = 12;
uint8_t yStep = 12;
if (font_ == DisplayFont::SMALL) {
yStart = 10;
yStep = 10;
} else if (font_ == DisplayFont::LARGE) {
yStart = 15;
yStep = 16;
if (lineCount > 4) {
lineCount = 4;
}
}
for (uint8_t i = 0; i < lineCount; ++i) {
if (lines_[i][0] == '\0') {
continue;
}
oled_.drawUTF8(0, yStart + (i * yStep), lines_[i]);
}
oled_.sendBuffer();
}
void TBeamDisplay::appendLine(const char* text) {
for (uint8_t i = 0; i < kMaxLines - 1; ++i) {
strlcpy(lines_[i], lines_[i + 1], sizeof(lines_[i]));
}
setLine(kMaxLines - 1, text);
renderLines();
}
void TBeamDisplay::showBoot(const char* title, const char* subtitle, const char* detail) {
setFont(DisplayFont::NORMAL);
showLines(title ? title : "T-Beam", subtitle, detail);
}
void TBeamDisplay::showStatus(const char* title, const char* left, const char* right, const char* footer) {
if (!ready_) {
return;
}
oled_.clearBuffer();
oled_.setFont(u8g2_font_6x10_tf);
if (title) {
oled_.drawUTF8(0, 10, title);
}
oled_.drawHLine(0, 13, 128);
oled_.setFont(u8g2_font_7x14B_tf);
if (left) {
oled_.drawUTF8(0, 34, left);
}
if (right) {
const int width = oled_.getUTF8Width(right);
int x = 128 - width;
if (x < 0) {
x = 0;
}
oled_.drawUTF8(x, 34, right);
}
oled_.setFont(u8g2_font_6x10_tf);
if (footer) {
oled_.drawUTF8(0, 60, footer);
}
oled_.sendBuffer();
}
void TBeamDisplay::setError(const char* message) {
strlcpy(lastError_, message ? message : "", sizeof(lastError_));
}
void TBeamDisplay::clearError() {
lastError_[0] = '\0';
}
const uint8_t* TBeamDisplay::fontFor(DisplayFont font) const {
switch (font) {
case DisplayFont::SMALL:
return u8g2_font_5x8_tf;
case DisplayFont::LARGE:
return u8g2_font_7x14B_tf;
case DisplayFont::NORMAL:
default:
return u8g2_font_6x10_tf;
}
}
} // namespace tbeam

View file

@ -0,0 +1,70 @@
#pragma once
#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>
namespace tbeam {
struct DisplayConfig {
int sda = -1;
int scl = -1;
uint8_t address = 0x3C;
bool beginWire = true;
bool powerSave = false;
};
enum class DisplayFont : uint8_t {
SMALL = 0,
NORMAL,
LARGE
};
class TBeamDisplay {
public:
static constexpr uint8_t kMaxLines = 6;
static constexpr uint8_t kLineBytes = 32;
explicit TBeamDisplay(TwoWire& wire = Wire);
bool begin(const DisplayConfig& config = DisplayConfig{});
void update();
bool ready() const { return ready_; }
bool powerSave() const { return powerSave_; }
const char* lastError() const { return lastError_; }
void clear();
void clearBuffer();
void setPowerSave(bool enabled);
void setFont(DisplayFont font);
void showLines(const char* l1,
const char* l2 = nullptr,
const char* l3 = nullptr,
const char* l4 = nullptr,
const char* l5 = nullptr,
const char* l6 = nullptr);
void setLine(uint8_t index, const char* text);
void renderLines(uint8_t lineCount = kMaxLines);
void appendLine(const char* text);
void showBoot(const char* title, const char* subtitle = nullptr, const char* detail = nullptr);
void showStatus(const char* title, const char* left, const char* right = nullptr, const char* footer = nullptr);
U8G2& raw() { return oled_; }
private:
void setError(const char* message);
void clearError();
const uint8_t* fontFor(DisplayFont font) const;
TwoWire& wire_;
DisplayConfig config_{};
U8G2_SH1106_128X64_NONAME_F_HW_I2C oled_{U8G2_R0, U8X8_PIN_NONE};
bool ready_ = false;
bool powerSave_ = false;
DisplayFont font_ = DisplayFont::NORMAL;
char lines_[kMaxLines][kLineBytes] = {};
char lastError_[96] = {};
};
} // namespace tbeam