Public Access
Driver (components/el512/el512_panel.*, ESP-IDF only): - DMA ring of 8 x 4 lines (17 KB) refilled from the I2S EOF interrupt (IRAM) instead of a 142 KB full-frame stream; ~107 KB heap freed. - 256-entry lookup table encodes 8 pixels per step. - Back buffer + displayed buffer, swapped at the start of a frame. - PlatformIO builds it via lib_extra_dirs (EL512Core); lib/EL512 keeps the Adafruit GFX front end. ESPHome external component (platform: el512): - DisplayBuffer with optional ENABLE / _LOWPWR pins, set_enabled(), set_low_power(), helper functions for page lambdas. - still_alive_page: plays the Portal end-credits show, then returns to the previous page. Still Alive engine moved to components/el512/still_alive.* with a built-in 5x7 font (from Adafruit GFX, BSD); the PlatformIO demo uses the same code. The importer writes components/el512/still_alive_data.h and stops at 200 s (--until-ms), matching the hand-trimmed data. esphome/el512-panel.yaml: 8 pages (clock, forecast, agenda, dashboard, now playing, Plex, solar, Still Alive), page select, rotation, display and low-power switches, message text. home_assistant/packages/el512_panel.yaml: helper template sensors for forecast, agenda, now playing and Plex streams. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
111 lines
3.2 KiB
C++
111 lines
3.2 KiB
C++
// Portal-style end-credits show for the EL512.256-H: timed song text typed into
|
|
// a console on the left, credits typed top right, ASCII art bottom right.
|
|
//
|
|
// Framework-agnostic: draws straight into an EL512Panel with the built-in 5x7
|
|
// font, so the PlatformIO demo (src/still_alive) and the ESPHome component use
|
|
// the same code. The content is in still_alive_data.h, generated by
|
|
// tools/import_still_alive.py.
|
|
#pragma once
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
class EL512Panel;
|
|
|
|
namespace el512sa {
|
|
|
|
enum : uint8_t {
|
|
STEP_NEWLINE = 1 << 0, // start a new line after the text is typed
|
|
STEP_CLEAR = 1 << 1, // clear the console before typing
|
|
};
|
|
|
|
// One timed piece of console text. Steps are sorted by startMs.
|
|
struct LyricStep {
|
|
uint32_t startMs; // from the start of the show
|
|
uint16_t durMs; // the text is typed out evenly over this time
|
|
uint8_t flags;
|
|
int8_t art; // picture to show (index into ARTS), or ART_KEEP
|
|
const char *text;
|
|
};
|
|
|
|
struct Art {
|
|
const char *const *lines;
|
|
uint8_t count;
|
|
};
|
|
|
|
static constexpr int8_t ART_KEEP = -1; // leave the current picture
|
|
static constexpr int8_t ART_NONE = 0; // ARTS[0] is always the empty picture
|
|
|
|
// Fixed-size character console in the 5x7 font (6x8 cells), optionally inside a
|
|
// dashed frame. Text wraps at the right edge and scrolls up past the bottom row.
|
|
class TextBox {
|
|
public:
|
|
static constexpr uint8_t MAX_COLS = 48;
|
|
static constexpr uint8_t MAX_ROWS = 32;
|
|
static constexpr int16_t PAD = 4;
|
|
static constexpr int16_t CHAR_W = 6;
|
|
static constexpr int16_t CHAR_H = 8;
|
|
|
|
TextBox(int16_t x, int16_t y, int16_t w, int16_t h);
|
|
|
|
uint8_t cols() const { return cols_; }
|
|
uint8_t rows() const { return rows_; }
|
|
|
|
void clear();
|
|
void put(char c);
|
|
void print(const char *s);
|
|
void draw(EL512Panel &panel, bool cursor, bool frame = true) const;
|
|
|
|
private:
|
|
void newLine();
|
|
|
|
int16_t x_, y_, w_, h_;
|
|
uint8_t cols_, rows_;
|
|
uint8_t row_ = 0, col_ = 0;
|
|
char text_[MAX_ROWS][MAX_COLS + 1];
|
|
};
|
|
|
|
class StillAlivePlayer {
|
|
public:
|
|
static constexpr uint32_t START_DELAY_MS = 1000; // after start()
|
|
static constexpr uint32_t CURSOR_BLINK_MS = 300;
|
|
static constexpr uint32_t HOLD_MS = 10000; // after the last step, before finished()
|
|
|
|
StillAlivePlayer();
|
|
|
|
// Restart the show; it begins START_DELAY_MS after nowMs.
|
|
void start(uint32_t nowMs);
|
|
// Advance to nowMs; true if the screen changed (text, picture or cursor).
|
|
bool update(uint32_t nowMs);
|
|
// Draw the whole show; the caller clears the panel first and shows it after.
|
|
void draw(EL512Panel &panel) const;
|
|
// True once the last step has been typed and HOLD_MS has passed.
|
|
bool finished(uint32_t nowMs) const;
|
|
// When to start the music, relative to start().
|
|
static uint32_t songStartMs();
|
|
|
|
private:
|
|
bool updateLyrics(uint32_t t, uint32_t nowMs);
|
|
bool updateCredits(uint32_t t);
|
|
void showArt(int8_t id);
|
|
|
|
TextBox lyrics_;
|
|
TextBox credits_;
|
|
TextBox art_;
|
|
uint32_t showStart_ = 0;
|
|
size_t step_ = 0;
|
|
size_t charIdx_ = 0;
|
|
bool stepStarted_ = false;
|
|
bool done_ = false;
|
|
uint32_t doneAt_ = 0;
|
|
size_t creditIdx_ = 0;
|
|
size_t creditChar_ = 0;
|
|
bool creditLineOpen_ = false;
|
|
bool creditsDone_ = false;
|
|
uint32_t creditLineAt_ = 0;
|
|
bool cursor_ = false;
|
|
bool creditsCursor_ = false;
|
|
};
|
|
|
|
} // namespace el512sa
|