They were committed from Windows, which records no execute bit, so on
the device `scripts/cardputer-zero/launcher-entry.sh` -- run by path, as
its own usage line and the Cardputer guide say -- was refused with
"Permission denied" while the file sat right there. Every script under
scripts/ that starts with #! is now 100755, as the uConsole bridge
already was.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The launcher entry carried a placeholder. Its icon is now meshterm.net's
logo, the red skyline, resized to the launcher's 100x100 the way the
site makes its own small icons (Lanczos from the 410 px source).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
On the device MeshTerm ran, drew every frame, and stayed invisible: the
panel kept the launcher's last frame while a splash nobody could see
waited for a key. The panel is a DRM driver whose /dev/fb0 is fbdev
emulation, and the kernel copies to the glass only what it sees change
through the *mapping*. pwrite() put the pixels in the buffer, where
reading /dev/fb0 back showed them, and never on the panel. The frame
now goes through an mmap, as M5's own LVGL apps write theirs. Checked
on the panel.
Also scripts/cardputer-zero/type-text.py: paste a long string (an API
key, a Wi-Fi password) on another computer and it is typed on the
Cardputer's keyboard over SSH, into whatever app has the screen. Input
is hidden and travels on stdin, never on a command line.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Tried on a real Cardputer Zero for the first time. It draws on the
panel, takes the keyboard, and opens from M5's app launcher:
scripts/cardputer-zero/launcher-entry.sh puts a source checkout there
(and `remove` takes it off) until there is a store package.
Three things the hardware showed:
- The splash opened with the highlight on /dev/ttyS0, the Cap's GPS
UART, because serial is listed first as found. Below the companions
we've used, anything that looks like one now comes before a port
nothing vouches for, across transports.
- The title bar's battery is the handheld's own BQ27220, as the
PicoCalc's is. The host pack is now found by what it is (a Battery
supply that isn't a peripheral's), not by the PicoCalc's name.
- While the Cap is powered, I2C bus 1 turns noisy: a quarter to three
quarters of the gauge's reads fail with an I/O error (one in ten of
the clock's), none with the header off. A failed read is asked again,
a status that won't read keeps its last verdict, and a good reading
stands through six failed polls instead of blinking out.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
`meshterm emulate cardputer-zero --mock` and `meshterm emulate picocalc-lyra --mock`
open a desktop window drawing MeshTerm as that device's own screen draws it. An
EmulatedDevice (emulator/devices.py) holds what differs per handheld: the panel, a
Linux console's top-left grid and bold-as-bright 4-bit palette for the PicoCalc, the
lane keys drawn under the Cardputer's panel, and how each keyboard spells Shift with
an F-key (the PicoCalc's F6-F10, the Cardputer's xterm-shifted F4-F8).
It is not a strict emulator, and the docs say so wherever they offer it: MeshTerm runs
on the desktop as itself, and the window mimics the display's and keyboard's
constraints, never the CPU or the OS. Inside it the platform resolves with own_display
(platforms.drawn_by_meshterm), so nothing offers to move to another terminal.
Global options typed anywhere (--mock, --port, --db...) reach the emulated MeshTerm.
The command refuses --json like specimen. The Terminus fetch moved into the package as
`meshterm emulate --fetch-fonts` (with --archive for a copy fetched another way),
replacing scripts/cardputer-zero/fetch-terminus.py. A build without Tk says to install
with pip or pipx instead of failing.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
"Host" already meant two things here: a TCP companion's network host,
and battery="host" for this machine itself. And with a PicoCalc preview
coming, the package is less a console host than an emulator of a
handheld's display: its panel, grid, font, colours and keys. So it is
meshterm.emulator, Platform.console_host is own_display, its desktop
window is window.py (EmulatorWindow) and its device front end
framebuffer.py, since "sim" and "device" now mean the radio simulator and
the device being emulated. MESHTERM_HOST_FONTS is MESHTERM_EMULATOR_FONTS.
The package's own description opens on what it is not: nothing runs the
handheld's processor or operating system; it mimics the display's
constraints so the window obeys the device's.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
M5Stack makes three Cardputers and only the Zero runs Linux; the PicoCalc
takes several cores and only the Luckfox Lyra runs MeshTerm. So the bare
names were ambiguous, and every reference to the two devices now carries
the variant: the --platform values and MESHTERM_PLATFORM, the Platform
constants (PICOCALC_LYRA, CARDPUTER_ZERO), their lane decks and every
screen's picocalc_lyra_lane / cardputer_zero_lane, the font inventories,
the lane chips' theme styles, the scripts/ folders, the two chrome test
files, and the docs and CLAUDE.md that name them.
There is no alias: --platform picocalc is refused with the three real
choices listed, rather than falling back to the desktop layout. The
PicoCalc is auto-detected from its device tree, so it needs nothing.
What names hardware or a user's data keeps its name: the PicoCalc
keyboard's input-device name, its battery's sysfs supply, and the serial
profile the Lyra setup script writes. .gitignore follows the firmware's
folder, and the changelog keeps the words each release used.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>