Files
eink-dairy/display.cpp
2025-11-19 22:26:52 -05:00

86 lines
2.7 KiB
C++

#include <ctype.h>
#include <cstring>
#include "hardware/i2c.h"
#include "pico-ssd1306/ssd1306.h"
#include "pico-ssd1306/textRenderer/TextRenderer.h"
#include "hardware/gpio.h"
#include "display.h"
#include <new>
using namespace pico_ssd1306;
// Implement the methods declared in `display.h`.
// Use in-place storage for the SSD1306 object to avoid heap allocation on
// constrained embedded systems. The storage is sized using the complete
// `SSD1306` type (this file includes the concrete header), and the object
// is constructed with placement-new during `init()` and explicitly destroyed
// in the destructor.
namespace {
alignas(SSD1306) unsigned char display_storage[sizeof(SSD1306)];
bool display_constructed = false;
}
DisplayManager::DisplayManager()
: display_(nullptr)
{
last_echo_[0] = '\0';
}
DisplayManager::~DisplayManager() {
if (display_constructed && display_) {
// Call destructor explicitly since we used placement-new.
display_->~SSD1306();
display_constructed = false;
}
display_ = nullptr;
}
// (No singleton accessor — the DisplayManager is constructed explicitly by callers.)
void DisplayManager::init(uint8_t i2c_addr) {
if (display_) return; // already initialized
// Initialize I2C for the SSD1306 display (common pins: SDA=GPIO4, SCL=GPIO5)
i2c_init(i2c0, 400 * 1000);
gpio_set_function(4, GPIO_FUNC_I2C);
gpio_set_function(5, GPIO_FUNC_I2C);
gpio_pull_up(4);
gpio_pull_up(5);
// Construct the display object in pre-allocated storage to avoid heap use.
display_ = reinterpret_cast<SSD1306 *>(display_storage);
new (display_) SSD1306(i2c0, i2c_addr, Size::W128xH64);
display_constructed = true;
display_->setOrientation(false);
display_->clear();
display_->sendBuffer();
last_echo_[0] = '\0';
refresh("> ", nullptr);
}
void DisplayManager::refresh(const char *current_input, const char *last_echo) {
if (!display_) return;
display_->clear();
size_t input_len = current_input ? strlen(current_input) : 0;
const unsigned char *input_font = (input_len > LAST_ECHO_VISIBLE_CHARS) ? font_5x8 : font_12x16;
pico_ssd1306::drawText(display_, input_font, current_input ? current_input : "", 0, 0);
const char *echo_to_draw = last_echo ? last_echo : (last_echo_[0] ? last_echo_ : "");
pico_ssd1306::drawText(display_, font_12x16, echo_to_draw, 0, 20);
display_->sendBuffer();
}
void DisplayManager::set_last_echo(const char *text) {
if (!text) return;
strncpy(last_echo_, text, sizeof(last_echo_) - 1);
last_echo_[sizeof(last_echo_) - 1] = '\0';
}
// No C-compatible wrappers: prefer `DisplayManager::instance()` API directly.