The simulator¶
The interface is pure code, so it can be looked at on the host. oxinode-sim
renders any screen to a PNG, plays the menus in a terminal, and holds every
screen and menu to a committed golden image. Without it, a change to a menu's
centring is a flash, a squint at a 1.12-inch panel, and a photograph; with it,
the change is a red patch on a diff image in the test output.
The crate needs the host target named, because the workspace defaults to the Cortex-M:
alias sim='cargo run -q -p oxinode-sim --target "$(rustc -vV | sed -n "s/^host: //p")" --'
oxinode-sim render [--script S] [--state F] [--panel WxH] [--text] -o out.png
oxinode-sim steps [--script S] [--state F] [--panel WxH] --out DIR
oxinode-sim tty [--script S] [--state F] [--braille | --half]
oxinode-sim golden [--update] [--dir DIR] [--diff DIR]
oxinode-sim raw FILE -o out.png
A picture of a screen¶
A script is the keys you would press: right right select down select, with
word*N for repeats and # for comments. The result is a PNG at 4× with a
one-pixel grid between cells, which at 128 × 128 reads better than the panel
does. The grid is not decoration: the only kind of layout bug this interface
has is a one-pixel misalignment, and at 4× without a grid that is a faint
smudge.
sim render --script "right*4 select down" -o system-reboot.png
A picture per step, to see a path through the menus as a strip:
sim steps --script "right select down select" --out /tmp/steps
In the terminal¶
Arrow keys move, Enter selects, Esc or Backspace goes back, q quits. The
panel is drawn in braille, or in half blocks on a terminal tall enough for 64
rows of them. The actions a menu item would fire are shown on the status line
rather than performed, exactly as the core hands them to the firmware; so is
what is being edited and whether it was refused. Raw mode comes from stty,
not a crate.
sim tty
What the screens draw from¶
The screens draw from a State, the same plain values the board copies out
of its modem loop, and the simulator has four fixtures for it:
--state |
What it is |
|---|---|
populated (default) |
a board mid-session with every field known and a host on USB |
empty |
a board that knows nothing yet, so every screen shows how it says so |
standalone |
a TNC with no host attached, which is the one whose settings the panel may change |
2g4 |
that TNC on the other band: 2478 MHz, 812.5 kHz, 11 dBm on the u.FL |
The populated Radio screen is longer than the panel, which is what exercises scrolling and the scrollbar:
sim render --script "right down*3" -o radio-scrolled.png
sim render --state empty --script "right*4" -o system-empty.png
Editing a setting¶
The Radio menu's first five items open an editor. The scene plays the board's
part: with nobody on the line it opens the editor and a confirmed value lands
in the state, so the next picture shows it; with a host on the line it opens
the notice instead. The scene applies the same Action::changes_the_radio
the firmware does, so the golden images of the notice are the board's
behaviour and not an impersonation of it. Here the fifth press is TX Power,
up*4 takes 17 dBm to 21, and the last select is refused:
sim render --state standalone --script "right select down*5 select up*4 select" -o refused.png
sim render --script "right select down select" -o locked.png
Another panel¶
The interface draws on any size of canvas, and --panel WxH renders on one
the board does not have. 128 × 64 is the size the golden set is also held at,
with four lines between the bars and the nine-item Radio menu shown two rows
at a time:
sim render --panel 128x64 --script "right select down*4" -o radio-menu-wide.png
A frame from the board¶
A 2048-byte dump of the controller's RAM renders the same way, through the same address arithmetic the firmware draws with:
sim raw frame.bin -o frame.png
The product image's CMD_DISP_READ returns the panel folded to 128 × 64 in
the SSD1306 layout the hosts expect (1024 bytes); rendering that with
--panel 128x64 is how a screenshot is taken from a board over USB with no
eyes involved.
Golden images¶
sim golden # what tools/test.sh runs
sim golden --update # after an intended change; commit the result
The set under sim/golden/ is generated from the screen list and the field
list: every screen empty and populated, every item of every menu, a scrolled
page at the top, the middle and the bottom, every editor open, the refusals
that can be reached, the frequency editor with its cursor moved, the screen
after a confirmed edit, the notice for USB and for a phone, a pairing in
progress, and the receiver searching. sim/golden/128x64/ holds the same
screens on the other panel. On a mismatch the rendering and a diff land in
target/golden-diff/.
What it does not tell you¶
Anything electrical: the pad's debounce and auto-repeat (tested in the core with a clock that is a number and measured on the board by the driver), I²C timing, the panel's own refresh, and anything about real modem state, which the caller supplies here exactly as it does on the board. The simulator's input script is the gestures after the pad driver, which is the right seam: the simulator tests what a gesture does, and the board tests when one happens.