86 lines
2.7 KiB
C++
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.
|