#include #include #include "hardware/i2c.h" #include "pico-ssd1306/ssd1306.h" #include "pico-ssd1306/textRenderer/TextRenderer.h" #include "hardware/gpio.h" #include "display.h" #include 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(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.