2026-09-11 16:38:28 +02:00
|
|
|
#include "LcdDisplay.h"
|
|
|
|
|
|
2026-09-12 21:53:16 +02:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
// Classic 5x8 dot-matrix LCD character generator ROM (HD44780-style),
|
|
|
|
|
// rows top-to-bottom, bit 4 = leftmost column. Index = ASCII - 32.
|
|
|
|
|
constexpr uint8_t kFont[95][8] =
|
|
|
|
|
{
|
|
|
|
|
{0,0,0,0,0,0,0,0}, // space
|
|
|
|
|
{4,4,4,4,4,0,4,0}, // !
|
|
|
|
|
{10,10,10,0,0,0,0,0}, // "
|
|
|
|
|
{0,10,31,10,31,10,0,0}, // #
|
|
|
|
|
{4,15,20,14,5,30,4,0}, // $
|
|
|
|
|
{2,4,8,16,14,17,14,0}, // %
|
|
|
|
|
{8,20,20,8,21,18,13,0}, // &
|
|
|
|
|
{4,4,4,0,0,0,0,0}, // '
|
|
|
|
|
{2,4,8,8,8,4,2,0}, // (
|
|
|
|
|
{8,4,2,2,2,4,8,0}, // )
|
|
|
|
|
{0,10,4,31,4,10,0,0}, // *
|
|
|
|
|
{0,4,4,31,4,4,0,0}, // +
|
|
|
|
|
{0,0,0,0,6,2,4,0}, // ,
|
|
|
|
|
{0,0,0,31,0,0,0,0}, // -
|
|
|
|
|
{0,0,0,0,0,0,12,0}, // .
|
|
|
|
|
{1,2,4,8,16,0,0,0}, // /
|
|
|
|
|
{14,17,19,21,25,17,14,0}, // 0
|
|
|
|
|
{4,12,4,4,4,4,14,0}, // 1
|
|
|
|
|
{14,17,1,2,4,8,31,0}, // 2
|
|
|
|
|
{14,17,1,6,1,17,14,0}, // 3
|
|
|
|
|
{2,6,10,18,31,2,2,0}, // 4
|
|
|
|
|
{31,16,30,1,1,17,14,0}, // 5
|
|
|
|
|
{6,8,16,30,17,17,14,0}, // 6
|
|
|
|
|
{31,1,2,4,8,8,8,0}, // 7
|
|
|
|
|
{14,17,17,14,17,17,14,0}, // 8
|
|
|
|
|
{14,17,17,15,1,2,12,0}, // 9
|
|
|
|
|
{0,0,6,0,0,6,0,0}, // :
|
|
|
|
|
{0,0,6,0,0,6,2,4}, // ;
|
|
|
|
|
{2,4,8,16,8,4,2,0}, // <
|
|
|
|
|
{0,0,31,0,31,0,0,0}, // =
|
|
|
|
|
{8,4,2,1,2,4,8,0}, // >
|
|
|
|
|
{14,17,1,2,4,0,4,0}, // ?
|
|
|
|
|
{14,17,1,13,21,17,14,0}, // @
|
|
|
|
|
{14,17,17,31,17,17,17,0}, // A
|
|
|
|
|
{30,17,17,30,17,17,30,0}, // B
|
|
|
|
|
{14,17,16,16,16,17,14,0}, // C
|
|
|
|
|
{30,17,17,17,17,17,30,0}, // D
|
|
|
|
|
{31,16,16,30,16,16,31,0}, // E
|
|
|
|
|
{31,16,16,30,16,16,16,0}, // F
|
|
|
|
|
{14,17,16,23,17,17,15,0}, // G
|
|
|
|
|
{17,17,17,31,17,17,17,0}, // H
|
|
|
|
|
{14,4,4,4,4,4,14,0}, // I
|
|
|
|
|
{7,2,2,2,2,18,12,0}, // J
|
|
|
|
|
{17,18,20,24,20,18,17,0}, // K
|
|
|
|
|
{16,16,16,16,16,16,31,0}, // L
|
|
|
|
|
{17,27,21,21,17,17,17,0}, // M
|
|
|
|
|
{17,25,21,19,17,17,17,0}, // N
|
|
|
|
|
{14,17,17,17,17,17,14,0}, // O
|
|
|
|
|
{30,17,17,30,16,16,16,0}, // P
|
|
|
|
|
{14,17,17,17,21,18,13,0}, // Q
|
|
|
|
|
{30,17,17,30,20,18,17,0}, // R
|
|
|
|
|
{15,16,16,14,1,1,30,0}, // S
|
|
|
|
|
{31,4,4,4,4,4,4,0}, // T
|
|
|
|
|
{17,17,17,17,17,17,14,0}, // U
|
|
|
|
|
{17,17,17,17,17,10,4,0}, // V
|
|
|
|
|
{17,17,17,21,21,27,17,0}, // W
|
|
|
|
|
{17,17,10,4,10,17,17,0}, // X
|
|
|
|
|
{17,17,17,10,4,4,4,0}, // Y
|
|
|
|
|
{31,1,2,4,8,16,31,0}, // Z
|
|
|
|
|
{14,8,8,8,8,8,14,0}, // [
|
|
|
|
|
{16,8,4,2,1,0,0,0}, // backslash
|
|
|
|
|
{14,2,2,2,2,2,14,0}, // ]
|
|
|
|
|
{4,10,17,0,0,0,0,0}, // ^
|
|
|
|
|
{0,0,0,0,0,0,31,0}, // _
|
|
|
|
|
{8,4,2,0,0,0,0,0}, // `
|
|
|
|
|
{0,0,14,1,15,17,15,0}, // a
|
|
|
|
|
{16,16,30,17,17,17,30,0}, // b
|
|
|
|
|
{0,0,14,16,16,17,14,0}, // c
|
|
|
|
|
{1,1,15,17,17,17,15,0}, // d
|
|
|
|
|
{0,0,14,17,31,16,14,0}, // e
|
|
|
|
|
{2,4,4,14,4,4,4,0}, // f
|
|
|
|
|
{0,0,15,17,17,15,1,14}, // g
|
|
|
|
|
{16,16,30,17,17,17,17,0}, // h
|
|
|
|
|
{0,6,0,4,4,4,4,0}, // i
|
|
|
|
|
{0,6,0,4,4,4,8,0}, // j
|
|
|
|
|
{0,0,16,18,20,24,20,0}, // k
|
|
|
|
|
{0,0,12,4,4,4,4,0}, // l
|
|
|
|
|
{0,0,26,21,21,21,21,0}, // m
|
|
|
|
|
{0,0,18,29,17,17,17,0}, // n
|
|
|
|
|
{0,0,14,17,17,17,14,0}, // o
|
|
|
|
|
{0,30,17,17,30,16,16,0}, // p
|
|
|
|
|
{0,0,15,17,17,15,1,1}, // q
|
|
|
|
|
{0,0,30,17,16,16,16,0}, // r
|
|
|
|
|
{0,0,15,16,14,1,30,0}, // s
|
|
|
|
|
{0,4,4,14,4,4,2,0}, // t
|
|
|
|
|
{0,0,17,17,17,19,13,0}, // u
|
|
|
|
|
{0,0,17,17,17,10,4,0}, // v
|
|
|
|
|
{0,0,17,17,21,21,10,0}, // w
|
|
|
|
|
{0,0,17,10,4,10,17,0}, // x
|
|
|
|
|
{0,0,17,17,17,10,12,0}, // y
|
|
|
|
|
{0,0,31,2,4,8,31,0}, // z
|
|
|
|
|
{4,8,8,16,8,8,4,0}, // {
|
|
|
|
|
{4,4,4,4,4,4,4,0}, // |
|
|
|
|
|
{8,4,4,2,4,4,8,0}, // }
|
|
|
|
|
{13,18,0,0,0,0,0,0}, // ~
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
2026-09-11 16:38:28 +02:00
|
|
|
LcdDisplay::LcdDisplay()
|
|
|
|
|
{
|
|
|
|
|
clear();
|
|
|
|
|
startTimerHz (30);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LcdDisplay::setLine (int row, const juce::String& s)
|
|
|
|
|
{
|
|
|
|
|
if (row >= 0 && row < kRows)
|
|
|
|
|
lines[row] = s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LcdDisplay::showCursor (bool show) { cursorVisible = show; }
|
|
|
|
|
|
|
|
|
|
void LcdDisplay::clear()
|
|
|
|
|
{
|
|
|
|
|
for (int r = 0; r < kRows; ++r)
|
|
|
|
|
lines[r] = "";
|
|
|
|
|
cursorCol = 0;
|
|
|
|
|
cursorRow = 0;
|
|
|
|
|
cursorVisible = false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-12 21:53:16 +02:00
|
|
|
const uint8_t* LcdDisplay::getGlyph (juce::uint32 c) const
|
|
|
|
|
{
|
|
|
|
|
if (c < 32 || c > 126)
|
|
|
|
|
c = '?';
|
|
|
|
|
return kFont[c - 32];
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-11 16:38:28 +02:00
|
|
|
void LcdDisplay::paint (juce::Graphics& g)
|
|
|
|
|
{
|
|
|
|
|
const float w = (float) getWidth();
|
|
|
|
|
const float h = (float) getHeight();
|
|
|
|
|
|
|
|
|
|
const juce::Colour bgCol (0xFF0D1A05);
|
|
|
|
|
const juce::Colour pixOn (0xFF4AE038);
|
|
|
|
|
const juce::Colour pixOnDim (0xFF1E3A12);
|
|
|
|
|
const juce::Colour pixOff (0xFF0F1C07);
|
|
|
|
|
|
|
|
|
|
g.fillAll (bgCol);
|
|
|
|
|
|
2026-09-11 17:06:23 +02:00
|
|
|
float cw = w / (float) kCols;
|
|
|
|
|
float ch = h / (float) kRows;
|
|
|
|
|
float ox = 0.0f;
|
|
|
|
|
float oy = 0.0f;
|
2026-09-11 16:38:28 +02:00
|
|
|
|
2026-09-12 21:53:16 +02:00
|
|
|
float padX = cw * 0.18f;
|
|
|
|
|
float padY = ch * 0.10f;
|
|
|
|
|
float gw = cw - padX * 2.0f;
|
|
|
|
|
float gh = ch - padY * 2.0f;
|
|
|
|
|
|
|
|
|
|
constexpr float kAspect = 2.0f;
|
|
|
|
|
constexpr float kGapCol = 0.22f;
|
|
|
|
|
constexpr float kGapRow = 0.12f;
|
|
|
|
|
|
|
|
|
|
const float gridW = 5.0f + 4.0f * kGapCol;
|
|
|
|
|
const float gridH = kAspect * (8.0f + 7.0f * kGapRow);
|
|
|
|
|
const float cellW = juce::jmax (0.0f, juce::jmin (gw / gridW, gh / gridH));
|
|
|
|
|
const float cellH = cellW * kAspect;
|
|
|
|
|
const float stepX = cellW * (1.0f + kGapCol);
|
|
|
|
|
const float stepY = cellH * (1.0f + kGapRow);
|
|
|
|
|
|
2026-09-11 16:38:28 +02:00
|
|
|
bool blinkOn = cursorVisible &&
|
|
|
|
|
((int) (juce::Time::getMillisecondCounterHiRes() / 400.0) % 2 == 0);
|
|
|
|
|
|
|
|
|
|
for (int row = 0; row < kRows; ++row)
|
|
|
|
|
{
|
|
|
|
|
const juce::String& line = lines[row];
|
|
|
|
|
for (int col = 0; col < kCols; ++col)
|
|
|
|
|
{
|
|
|
|
|
juce_wchar ch2 = col < line.length() ? line [(size_t) col] : (juce_wchar) ' ';
|
2026-09-12 21:53:16 +02:00
|
|
|
const uint8_t* glyph = getGlyph ((juce::uint32) ch2);
|
2026-09-11 16:38:28 +02:00
|
|
|
|
|
|
|
|
float cx = ox + (float) col * cw;
|
|
|
|
|
float cy = oy + (float) row * ch;
|
|
|
|
|
|
|
|
|
|
g.setColour (pixOff);
|
|
|
|
|
g.fillRect (cx + 0.5f, cy + 0.5f, cw - 1.0f, ch - 1.0f);
|
|
|
|
|
|
2026-09-12 21:53:16 +02:00
|
|
|
float gridX = cx + padX + (gw - cellW * gridW) * 0.5f;
|
|
|
|
|
float gridY = cy + padY + (gh - cellW * gridH) * 0.5f;
|
2026-09-11 17:06:23 +02:00
|
|
|
|
2026-09-11 16:38:28 +02:00
|
|
|
for (int gRow = 0; gRow < 8; ++gRow)
|
|
|
|
|
{
|
|
|
|
|
uint8_t bits = glyph[gRow];
|
|
|
|
|
if (bits == 0) continue;
|
|
|
|
|
for (int gCol = 0; gCol < 5; ++gCol)
|
|
|
|
|
{
|
|
|
|
|
if (bits & (1u << (4 - gCol)))
|
|
|
|
|
{
|
2026-09-12 21:53:16 +02:00
|
|
|
float px = gridX + (float) gCol * stepX;
|
|
|
|
|
float py = gridY + (float) gRow * stepY;
|
2026-09-11 16:38:28 +02:00
|
|
|
|
|
|
|
|
g.setColour (pixOnDim);
|
2026-09-12 21:53:16 +02:00
|
|
|
g.fillRect (px - cellW * 0.10f, py - cellH * 0.05f,
|
|
|
|
|
cellW * 1.20f, cellH * 1.10f);
|
2026-09-11 16:38:28 +02:00
|
|
|
g.setColour (pixOn);
|
2026-09-12 21:53:16 +02:00
|
|
|
g.fillRect (px, py, cellW, cellH);
|
2026-09-11 16:38:28 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (blinkOn && col == cursorCol && row == cursorRow)
|
|
|
|
|
{
|
|
|
|
|
g.setColour (pixOn);
|
2026-09-11 17:06:23 +02:00
|
|
|
g.fillRect (cx + padX, cy + ch - padY - ch * 0.22f, cw - padX * 2.0f, ch * 0.18f);
|
2026-09-11 16:38:28 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-12 21:53:16 +02:00
|
|
|
void LcdDisplay::timerCallback() { repaint(); }
|