v2 Phase 5: Now Playing — Windows media session on the watch
The daemon reads the Windows "now playing" media session (WinRT SMTC) and
adds np/nt/na to the BLE payload; the watch shows a play/pause glyph, a
scrolling title, artist and status. Best-effort and token-independent, so
it works even when the rate-limit data is unavailable.
Cyrillic titles: Styrene B has no Cyrillic glyphs, so the title/artist use
new composite fonts (font_styrene_cyr_{28,20}) — Latin from Styrene B,
Cyrillic + typographic punctuation from Montserrat, merged by lv_font_conv.
Latin titles stay on-brand; only Cyrillic falls back to Montserrat.
- daemon: read_now_playing() via winrt-Windows.Media.Control (lazy import,
never raises; PLAYING->1, PAUSED->2, else 0; title/artist truncated,
empty fields omitted)
- firmware: UsageData np_state/np_title/np_artist + parser; the real Now
Playing screen replaces the shared stub (SCREEN_NOWPLAYING)
- fonts: assets/Montserrat-Medium.ttf, font_styrene_cyr_{28,20}.c
- tools: patch_lvgl9_font.py (automates the 4 LVGL 9 font patches),
screenshot_win.py (Windows serial screenshot via pyserial + Pillow)
- README: document Cyrillic composite font generation
Verified on hardware (waveshare_amoled_206): idle state, a live Latin
title (scrolling), and Cyrillic (Prohozhdenie / Dunduk) all render.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Patch lv_font_conv output for LVGL 9.
|
||||
|
||||
`lv_font_conv` emits font .c files wrapped in `#if LVGL_VERSION_MAJOR` guards and
|
||||
(for v8) a `.cache` field. On LVGL 9 the project wants the plain, unguarded struct
|
||||
with `.release_glyph` / `.kerning` / `.static_bitmap` present (see the "LVGL 9 font
|
||||
patching" note in README.md). Without this the font compiles but renders invisible.
|
||||
|
||||
Usage:
|
||||
python tools/patch_lvgl9_font.py firmware/src/font_foo.c [more.c ...]
|
||||
|
||||
Idempotent: running it on an already-patched file is a no-op.
|
||||
"""
|
||||
import re
|
||||
import sys
|
||||
|
||||
SUBS = [
|
||||
# drop the v8-only glyph cache declaration
|
||||
(r'#if LVGL_VERSION_MAJOR == 8\n/\*Store all the custom data of the font\*/\n'
|
||||
r'static lv_font_fmt_txt_glyph_cache_t cache;\n#endif\n\n', ''),
|
||||
# collapse the font_dsc storage-class guard
|
||||
(r'#if LVGL_VERSION_MAJOR >= 8\nstatic const lv_font_fmt_txt_dsc_t font_dsc = \{\n'
|
||||
r'#else\nstatic lv_font_fmt_txt_dsc_t font_dsc = \{\n#endif\n',
|
||||
'static const lv_font_fmt_txt_dsc_t font_dsc = {\n'),
|
||||
# drop the v8 .cache member
|
||||
(r'#if LVGL_VERSION_MAJOR == 8\n \.cache = &cache\n#endif\n', ''),
|
||||
# collapse the public-font const guard
|
||||
(r'#if LVGL_VERSION_MAJOR >= 8\n(const lv_font_t \w+ = \{)\n'
|
||||
r'#else\nlv_font_t \w+ = \{\n#endif\n', r'\1\n'),
|
||||
# keep .subpx and add the three LVGL 9 fields
|
||||
(r'#if !\(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0\)\n'
|
||||
r' \.subpx = LV_FONT_SUBPX_NONE,\n#endif\n',
|
||||
' .subpx = LV_FONT_SUBPX_NONE,\n .release_glyph = NULL,\n'
|
||||
' .kerning = 0,\n .static_bitmap = 0,\n'),
|
||||
# unwrap underline fields
|
||||
(r'#if LV_VERSION_CHECK\(7, 4, 0\) \|\| LVGL_VERSION_MAJOR >= 8\n'
|
||||
r'( \.underline_position = -1,\n \.underline_thickness = 2,\n)#endif\n', r'\1'),
|
||||
# unwrap .fallback
|
||||
(r'#if LV_VERSION_CHECK\(8, 2, 0\) \|\| LVGL_VERSION_MAJOR >= 9\n'
|
||||
r'( \.fallback = NULL,\n)#endif\n', r'\1'),
|
||||
]
|
||||
|
||||
|
||||
def patch(path: str) -> None:
|
||||
s = open(path, encoding="utf-8").read()
|
||||
for pat, repl in SUBS:
|
||||
s = re.sub(pat, repl, s)
|
||||
open(path, "w", encoding="utf-8").write(s)
|
||||
leftover = len(re.findall(r'LVGL_VERSION_MAJOR|LV_VERSION_CHECK|\.cache = &cache', s))
|
||||
print(f"patched {path} leftover_guards={leftover}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
sys.exit(__doc__)
|
||||
for p in sys.argv[1:]:
|
||||
patch(p)
|
||||
Reference in New Issue
Block a user