feat(eink): lettering clock on the portrait e-ink, 4.2" and 4.26" simulator builds in the release workflow

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-10-12 22:34:05 +02:00
co-authored by Claude Opus 5.5
parent a7b1c3417b
commit b41d77fbb2
3 changed files with 33 additions and 21 deletions
+16
View File
@@ -89,6 +89,20 @@ jobs:
SIM_EINK: portrait SIM_EINK: portrait
run: variants/sim/build_wasm.sh run: variants/sim/build_wasm.sh
# The 4.2" 400x300 build (the site's "E-ink · 4.2″").
- name: Build E-ink WASM (4.2")
env:
FIRMWARE_VERSION: ${{ env.BUILD_VERSION }}
SIM_EINK: wide
run: variants/sim/build_wasm.sh
# The 4.26" 800x480 build (the site's "E-ink · Large").
- name: Build E-ink WASM (4.26")
env:
FIRMWARE_VERSION: ${{ env.BUILD_VERSION }}
SIM_EINK: big
run: variants/sim/build_wasm.sh
- name: Build repeater WASM - name: Build repeater WASM
run: variants/sim/build_wasm_repeater.sh run: variants/sim/build_wasm_repeater.sh
@@ -99,6 +113,8 @@ jobs:
cp variants/sim/web/build/meshcore_sim_lvgl.js variants/sim/web/build/meshcore_sim_lvgl.wasm out/wasm/lvgl/ cp variants/sim/web/build/meshcore_sim_lvgl.js variants/sim/web/build/meshcore_sim_lvgl.wasm out/wasm/lvgl/
cp variants/sim/web/build/meshcore_sim_eink_landscape.js variants/sim/web/build/meshcore_sim_eink_landscape.wasm out/wasm/eink/ cp variants/sim/web/build/meshcore_sim_eink_landscape.js variants/sim/web/build/meshcore_sim_eink_landscape.wasm out/wasm/eink/
cp variants/sim/web/build/meshcore_sim_eink_portrait.js variants/sim/web/build/meshcore_sim_eink_portrait.wasm out/wasm/eink/ cp variants/sim/web/build/meshcore_sim_eink_portrait.js variants/sim/web/build/meshcore_sim_eink_portrait.wasm out/wasm/eink/
cp variants/sim/web/build/meshcore_sim_eink_wide.js variants/sim/web/build/meshcore_sim_eink_wide.wasm out/wasm/eink/
cp variants/sim/web/build/meshcore_sim_eink_big.js variants/sim/web/build/meshcore_sim_eink_big.wasm out/wasm/eink/
cp variants/sim/web/build/repeater/meshcore_sim_repeater.js variants/sim/web/build/repeater/meshcore_sim_repeater.wasm out/wasm/repeater/ cp variants/sim/web/build/repeater/meshcore_sim_repeater.js variants/sim/web/build/repeater/meshcore_sim_repeater.wasm out/wasm/repeater/
cd out && zip -r solo-sim-wasm.zip wasm cd out && zip -r solo-sim-wasm.zip wasm
+11 -16
View File
@@ -3,31 +3,26 @@
// Home: the clock, favourites, status, Bluetooth ... pages, and the lock screen. // Home: the clock, favourites, status, Bluetooth ... pages, and the lock screen.
// The time on a tall portrait panel (e-ink in portrait -- height > width): HH // The time on a tall portrait panel (e-ink in portrait -- height > width): HH
// and MM stacked on two lines in the huge built-in font (size 4, ~56 px tall) // and MM stacked on two lines in the splash's slanted lettering, as the wide
// so the digits fill the narrow width. Returns the y just below it. // panels' big clock: as wide as the panel allows, the two lines no more than
// ~45% of its height (the date and the month go under them). Returns the y
// just below it.
static int drawClockTall(DisplayDriver& d, int top_y, const struct tm* ti, bool h12) { static int drawClockTall(DisplayDriver& d, int top_y, const struct tm* ti, bool h12) {
int hh = ti->tm_hour; int hh = ti->tm_hour;
const char* ap = nullptr; const char* ap = nullptr;
if (h12) { ap = (hh < 12) ? "AM" : "PM"; hh %= 12; if (hh == 0) hh = 12; } if (h12) { ap = (hh < 12) ? "AM" : "PM"; hh %= 12; if (hh == 0) hh = 12; }
const int cx = d.width() / 2; const int cx = d.width() / 2;
char hbuf[4], mbuf[4]; char hbuf[4], mbuf[4];
snprintf(hbuf, sizeof(hbuf), "%02d", hh); snprintf(hbuf, sizeof(hbuf), h12 ? "%d" : "%02d", hh);
snprintf(mbuf, sizeof(mbuf), "%02d", ti->tm_min); snprintf(mbuf, sizeof(mbuf), "%02d", ti->tm_min);
int sc = (d.height() * 45 / 100) / (2 * lettering::LOGO_H);
while (sc > 1 && info::letteringW("00", sc, sc + 1) > d.width() - 2 * sc) sc--;
if (sc < 1) sc = 1;
const int h = lettering::LOGO_H * sc, gap = sc + 1;
int y = top_y; int y = top_y;
d.setTextSize(4); info::lettering(d, cx - info::letteringW(hbuf, sc, gap) / 2, y, hbuf, sc, gap); y += h + 2 * sc;
const int lhb = d.getLineHeight(); info::lettering(d, cx - info::letteringW(mbuf, sc, gap) / 2, y, mbuf, sc, gap); y += h + sc;
// The built-in GFX font advances 6 px per char but the glyph is only 5 px
// wide, so getTextWidth() over-reports by one trailing blank column and
// drawTextCentered() would bias the digits ~half a column to the left.
// Centre on the visible width (minus that trailing column) instead.
const int trail = d.getCharWidth() / 6; // one built-in column at this size
auto drawBig = [&](const char* s, int yy) {
d.setCursor(cx - ((int)d.getTextWidth(s) - trail) / 2, yy);
d.print(s);
};
drawBig(hbuf, y); y += lhb + 2;
drawBig(mbuf, y); y += lhb + 2;
if (ap) { if (ap) {
d.setTextSize(2); d.setTextSize(2);
d.drawTextCentered(cx, y, ap); d.drawTextCentered(cx, y, ap);
+6 -5
View File
@@ -194,17 +194,18 @@ if [ "$SIM_UI" = "lvgl" ]; then
LINK_EXTRA=(-sFETCH=1) # map downloads (LvglPort.h) go through emscripten_fetch LINK_EXTRA=(-sFETCH=1) # map downloads (LvglPort.h) go through emscripten_fetch
fi fi
# SIM_EINK=landscape|portrait|wide: ui-new on the Wio Tracker L1 E-ink's 2.13" # SIM_EINK=landscape|portrait|wide|big: ui-new on the Wio Tracker L1 E-ink's
# panel (122x250, solo/wio-tracker-l1-eink's two builds) or the 4.2" one # 2.13" panel (122x250, solo/wio-tracker-l1-eink's two builds), the 4.2" one
# (400x300, its third) instead of the OLED -> # (400x300, its third) or the 4.26" one (800x480, its fourth) instead of the
# web/index.html?build=meshcore_sim_eink_landscape (or _portrait, _wide). # OLED -> web/index.html?build=meshcore_sim_eink_landscape (or _portrait, ...).
SIM_EINK="${SIM_EINK:-}" SIM_EINK="${SIM_EINK:-}"
if [ -n "$SIM_EINK" ]; then if [ -n "$SIM_EINK" ]; then
case "$SIM_EINK" in case "$SIM_EINK" in
landscape) EINK_DEFS=(-DDISPLAY_ROTATION=1 -DEINK_LARGE_FONT=1 -DSIM_EINK_PANEL_W=122 -DSIM_EINK_PANEL_H=250); EXPORT_NAME=MeshCoreSimEinkLandscape ;; landscape) EINK_DEFS=(-DDISPLAY_ROTATION=1 -DEINK_LARGE_FONT=1 -DSIM_EINK_PANEL_W=122 -DSIM_EINK_PANEL_H=250); EXPORT_NAME=MeshCoreSimEinkLandscape ;;
portrait) EINK_DEFS=(-DDISPLAY_ROTATION=0 -DSIM_EINK_PANEL_W=122 -DSIM_EINK_PANEL_H=250); EXPORT_NAME=MeshCoreSimEinkPortrait ;; portrait) EINK_DEFS=(-DDISPLAY_ROTATION=0 -DSIM_EINK_PANEL_W=122 -DSIM_EINK_PANEL_H=250); EXPORT_NAME=MeshCoreSimEinkPortrait ;;
wide) EINK_DEFS=(-DDISPLAY_ROTATION=0 -DEINK_LARGE_FONT=2 -DSIM_EINK_PANEL_W=400 -DSIM_EINK_PANEL_H=300); EXPORT_NAME=MeshCoreSimEinkWide ;; wide) EINK_DEFS=(-DDISPLAY_ROTATION=0 -DEINK_LARGE_FONT=2 -DSIM_EINK_PANEL_W=400 -DSIM_EINK_PANEL_H=300); EXPORT_NAME=MeshCoreSimEinkWide ;;
*) echo "error: SIM_EINK must be landscape, portrait or wide" >&2; exit 1 ;; big) EINK_DEFS=(-DDISPLAY_ROTATION=0 -DEINK_LARGE_FONT=2 -DEINK_FONT_SCALE=2 -DSTATUS_ICON_SCALE=0 -DSIM_EINK_PANEL_W=800 -DSIM_EINK_PANEL_H=480); EXPORT_NAME=MeshCoreSimEinkBig ;;
*) echo "error: SIM_EINK must be landscape, portrait, wide or big" >&2; exit 1 ;;
esac esac
OUT_NAME="meshcore_sim_eink_$SIM_EINK" OUT_NAME="meshcore_sim_eink_$SIM_EINK"
# Distinct factories (set above): web/mesh.html?a=... loads one beside # Distinct factories (set above): web/mesh.html?a=... loads one beside