Commit Graph
9 Commits
Author SHA1 Message Date
Kaj SchittecatandClaude Opus 5 0ad28ce7db feat(lua): wada.sys.epoch, datetime and beep (#245)
pisti87 asked for time and buzzer access from Lua. wada.sys had millis, toast,
board and random -- an app could measure elapsed time but never say what time
it was, and could not make a sound at all.

  wada.sys.epoch()     -> Unix seconds, or nil
  wada.sys.datetime()  -> { year month day hour min sec wday }, or nil
  wada.sys.beep()      -> true if a sound was actually produced

Three decisions worth recording:

nil, not 0, when the clock has never been set. The device genuinely boots
without a clock until GPS, NTP or a mesh peer supplies one, and an app stamping
a log needs to tell "no clock yet" from "1970". Uses the same sane-clock floor
the mesh already applies.

datetime() is LOCAL time, in the timezone the user picked, because every use for
it is display. epoch() stays UTC seconds for arithmetic.

beep() is one chime, not the melody player the issue sketched. What exists is a
single per-board notification chime -- and some boards have no sounder. Routing
Lua through the same uiPlaySlot() the UI uses means an app cannot be louder or
different from the rest of the firmware, and it honours the user's sound setting
instead of overriding it. Returning whether sound actually happened lets an app
fall back to a visual cue rather than silently doing nothing, which a fake
melody API could not.

All 8 S3 envs build -- the beep path is per-board, so that matters here.

Requested by pisti87.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 12:26:40 +02:00
Kaj SchittecatandClaude Opus 4.8 9b8daea0df store: fit the Store to any panel, show downloads running, and link on P4/Tanmatsu
Three things, all "the Store only ever ran on a 320 px T-Deck".

LINK FIX (supersedes 7e5eac4, which treated the symptom). LuaAppHost.cpp
forward-declared `class WiFiClient;`. That declares a BRAND NEW incomplete
class, which is only correct where WiFiClient really is a class of that name --
it is a #define to C6Client on the T-Display P4 and a `using WiFiClient =
NetworkClient` alias under arduino-esp32 3.x on the Tanmatsu. So the file
emitted luaNetWorkerService under a signature the caller never referenced and
BOTH P4 targets failed to link, with three different mangled names, while all 8
S3 envs built clean -- which is why it stayed hidden until the first P4 build.
The TU now refuses to name the type at all: UITask owns the networking and
passes the objects as opaque handles through luaStoreHttpGetOpaque, casting
them back on its side. This kills the whole class of bug rather than adding a
third per-board alias.

LAYOUT. Cards measure their text instead of assuming "title + two description
lines" -- lv_txt_get_size on both title and description, height floored so it
can never be shorter than the icon chip or the action button. The title wraps
instead of truncating and the description sits below its ACTUAL height, which
is what was overlapping. Measuring beats reading geometry back, which returns 0
before layout. This fixes every board for translations longer than the English.
LV_LABEL_LONG_DOT only ellipsizes when the HEIGHT is bounded; with just a width
it silently wraps, which hit the card title, the language rows, the sideloaded
rows and the tab labels. Tab cells are now sized in proportion to their text,
not even thirds: an even third on the P4 (284 px logical, scaled fonts) is
~90 px and "Languages" does not fit that, while "Apps" left half its cell
empty. The bar height follows the font, floored at 30 so S3 stays identical.

FEEDBACK. The pressed button's caption becomes a spinner for the whole
download, not a 1.2 s toast, so a slow link no longer reads as a dead tap. It
is repainted from the in-flight id after a rebuild, since a card scan finishing
mid-download would otherwise restore a plain Get button. The caption is hidden
rather than deleted -- this runs inside the button's own event.

Drawer tile is "Store", short enough for every panel.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-05 00:11:43 +02:00
Kaj SchittecatandClaude Opus 4.8 7e5eac4675 lua: mirror the P4's WiFiClient->C6Client alias so the host links
The T-Display P4 failed to link with an undefined reference to
luaNetWorkerService(C6Client&, HTTPClient&).

On that board the C6 runs ESP-AT, so UITask.cpp does #define WiFiClient
C6Client to route sockets through AT-over-SDIO. LuaAppHost.cpp forward-declares
WiFiClient without the alias, so it emitted the definition as
_Z19luaNetWorkerServiceR10WiFiClientR10HTTPClient while the caller referenced
the C6Client& overload -- the symbol was present, just under the wrong type.
Confirmed by reading both object files.

Mirroring the alias fixes it. This TU only forwards the reference to
luaStoreHttpGet, so an incomplete type is sufficient. Every S3 board built
fine throughout, which is why it went unnoticed until the first P4 build of
the Lua work.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-04 23:18:35 +02:00
Kaj SchittecatandClaude Opus 4.8 68f66556d0 lua: Lua Store looks like a store — cards with icon chips, header counts, refresh, real empty states
Catalog rows are cards now (icon chip with the app initial, name, version
badge that turns accent when installed, wrapped description, rounded action
button tinted by action: teal Get, blue Update, red Remove). Section
headers are small-caps accent. A header strip shows 'N apps / M installed'
with a refresh control that re-fetches the catalog on demand — before this
the list was only ever fetched once per session. Loading and unavailable
states are proper cards explaining what to do instead of one dim line, and
sideloaded apps get their own 'Your own apps' section.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 14:28:29 +02:00
Kaj SchittecatandClaude Opus 4.8 ea58ff3d9a lua: scrollable app pages + real line heights; Monitor scrolls, Airtime gets a Reset button
Two API gaps the ports exposed: wada.ui.scroll(true) makes the app body
scroll vertically (games leave it off so swipes still steer), and
wada.ui.text_h(size) returns the actual font line height — the overlapping
labels came from stacking rows on guessed heights.

Monitor 1.3 lays every row out from measured heights, scrolls, and shows
the full 16-entry heard ring. Airtime 1.3 replaces tap-to-reset with a
Reset button top-right (a tap was too easy to trigger by accident).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 13:45:53 +02:00
Kaj SchittecatandClaude Opus 4.8 8f174c63b7 lua: chart matches the built-in styling + Y-axis labels; app layouts stop overflowing
wada.ui.chart now uses the same recipe as the built-in Monitor/Airtime
charts (panel fill, 1px dark border, radius 6, dim grid, no point dots,
2px series) and gains chart:axis(ticks, gutter) for LVGL's Y value labels
— which draw to the LEFT of the chart, so the apps inset it by the gutter.
Labels gain label:width(px) to wrap instead of running off the screen.

Monitor 1.2: dBm axis, 72-point history, wrapped metrics/feed rows.
Airtime 1.2: % axis, and the chart height is now whatever is left after
the detail block is reserved — the text that fell off the bottom was the
chart claiming a fixed height on short screens.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 13:41:19 +02:00
Kaj SchittecatandClaude Opus 4.8 fd4659f4ce lua: wada.ui.chart + full radio stats, and RF Monitor/Airtime rebuilt to parity (1.1)
Adds the primitive the ports were missing: wada.ui.chart (two shifting
series, line or bar, settable range) plus rx_events/rx_dropped/tx_pkts/
freq/bw/sf/duty_pct on wada.mesh.stats.

RF Monitor 1.1: live RSSI + noise-floor chart, peak with tap-to-reset,
link-margin grade, RX/min, radio params, colour-coded heard feed, narrow
and wide layouts. Airtime 1.1: live + average utilization bars, peak,
rx/tx air split, duty ceiling, tx budget, packet counters, tap to restart
the window. Native versions stay compiled in until these are field-proven.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 13:34:06 +02:00
Kaj SchittecatandClaude Opus 4.8 14d5b06560 lua: Phase 3 — wada.mesh + wada.net, RF Monitor + Airtime as catalog apps, IDF wiring
wada.mesh: read-only contacts/rx_log/stats/self via thin UITask bridges
(no mesh types cross into the host TU). wada.net.http_get: async on the
existing net worker, http-only, 32 KB cap, one in flight per app, callback
delivered on the UI thread under the guarded pcall. RF Monitor and Airtime
rewritten as Lua catalog apps (live on the VPS with snake); their native
versions deliberately stay compiled in for beta_59 until the ports are
field-proven. lib/lua joined both IDF component builds (P4 verified on
RISC-V). Catalog source tracked at deploy/apps/.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 13:18:12 +02:00
Kaj SchittecatandClaude Opus 4.8 322e4dd6f2 lua: Phase 1 — app host + wada.* v1 + Snake in Lua (hardware-verified)
LuaAppHost: one sandboxed app at a time as an AppPage overlay, every
callback under a 100k-instruction budget + traceback pcall (an app error
is a toast and a clean close, never a reset — proven live when the first
Snake build errored: 4 contained retries, zero leak). Bindings: wada.ui
canvas/label/button + theme colors, hardware-swipe/trackball/touch input,
timer, sys (millis/toast/board/random), per-app KV store under the data
root. Snake rewritten in Lua as the embedded reference app; the drawer
launches it via the host and prefers a user-editable /apps/snake.lua.
CAP_LUA_APPS defaults on for all touch boards. T-Deck: 85.1% flash
(host layer = 13 KB over the VM), app opens at 19 KB PSRAM.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 12:23:11 +02:00