The boards
xpui-boards
Seven devices — six e-ink panels and one LCD — as data: panel size, orientation, key row, refresh time, and the body in tenths of a millimetre. Nothing here draws anything. A board is what an application injects into a backend and a simulator, which is why the framework can describe a device it has never heard of and why adding one is a literal rather than a patch.
Which crate you want
pimoroni | Badger 2040, Tufty 2040, Inky Frame. The first two ship firmware and have been run over a debug probe; the Inky Frame's 600 × 448 seven-colour panel is described so a screen can be laid out for it and seen in the simulator |
xteink | X3, X4, X4 Pro |
seeed | Sticky |
core | Board, Orientation, Bezel, and the Plan/Run/Key const DSL. Describes no device at all |
Take the vendors you target and none of the others. That is why there is a crate per manufacturer rather than one list: a firmware for a Badger has no reason to compile an X4's dimensions into its image, and one crate cannot be taken a vendor at a time.
Using it
[dependencies]
xpui-boards-core = { git = "https://github.com/XPUI-Framework/xpui-boards", branch = "main" }
xpui-boards-pimoroni = { git = "https://github.com/XPUI-Framework/xpui-boards", branch = "main" }
xpui-boards-seeed = { git = "https://github.com/XPUI-Framework/xpui-boards", branch = "main" }
xpui-boards-xteink = { git = "https://github.com/XPUI-Framework/xpui-boards", branch = "main" }
There is deliberately no ALL across vendors. An application that ships
against more than one assembles its own list from the vendors it takes:
use xpui_boards_core::Board;
use xpui_boards_pimoroni as pimoroni;
use xpui_boards_seeed as seeed;
use xpui_boards_xteink as xteink;
/// Every board this application is built for, in the order a key cycles them.
const ALL: [Board; 7] = [
pimoroni::BADGER_2040,
pimoroni::TUFTY_2040,
pimoroni::INKY_FRAME,
xteink::X3,
xteink::X4,
xteink::X4_PRO,
seeed::STICKY,
];
// A vendor that gains a board stops this compiling until the list follows.
const _: () = assert!(ALL.len() == pimoroni::ALL.len() + xteink::ALL.len() + seeed::ALL.len());
xpui-gallery
is the worked example across all three vendors. The crates depend only on
xpui, for Button and
KeyRow — a key is a fact about hardware, and the crate describing a device
should not have to depend on the one drawing it to say so. Nothing is on
crates.io yet, which is what the banner above is about.
Checking it
./build-and-test.sh
The checks themselves are in xtask/ — this repository's own list,
in Rust, holding nothing it does not run. ./build-and-test.sh fix formats
in place first. How a change is reviewed is in
docs/contributing.md.
Where next
| docs/adding-a-board.md | your board is not here: the three numbers from the datasheet, the key row, the body, and what proves it |
| docs/boards.md | the seven, vendor by vendor: what runs on hardware, and how a screen reaches each panel |
| docs/design.md | the arguments behind choices the code states in one sentence |
| docs/contributing.md | building it, the gate, the five review steps, and how a commit is written |
Where it sits
Every arrow is a dependency in a Cargo.toml, and they all point inward
toward xpui, which depends on nothing at all. That is the rule the
organisation is arranged around: a backend can be written without the framework
knowing it exists, and a firmware reaches whatever it needs directly rather
than through whoever happens to sit above it.
Edit this page on GitHubIt lives in xpui-boards; a correction goes there.