Build system
One build from the stock image
design/build.py makes the firmware images. It reads the stock image x91_dump/x91_lfi_verified.bin (and checks
its sha256), and for each theme applies every part of the design (design/graphite/) to a copy of it in memory, one
after the other, and writes the image once:
x91_lfi_verified.bin ─ typeface ─ mainmenu ─ pictures ─ screensaver ─ music ─ settings ─ reader ─ statusbar
─ lists ─ playlists ─ sideways copies ─ x91_lfi_<theme>.bin
Before the themes it compiles and runs the host test of the new C code (New program code (design/playlist)) once; it does not depend on the theme. A build of all four themes takes about a minute.
python3 -I design/build.py
Option |
Does |
|---|---|
|
build only these themes ( |
|
write somewhere else than |
|
stop with an error unless every image built is the release image ( |
The images are byte-for-byte reproducible: the same stock image, sources and tools give the same bytes. RELEASE
holds the sha256 of the 1.0.0 images; they are the stage 27 images that were flashed and tested on the player
(History).
The parts
Each module of design/graphite/ changes one area of the firmware and has a build(b) function; build.py runs them
in the order of STEPS.
Module |
Files it changes |
What |
|---|---|---|
|
paths, the theme’s colours |
|
|
|
Ubuntu 12 px in one bit, hand-drawn glyphs ( |
|
|
start-up picture, shut-down animation, the six tiles, the Playlists tile ( |
|
|
status icons, battery, charging, list rows and marks, scroll bar, neutral icons, key lock, notices, volume pop-up, brightness, Bluetooth search |
|
|
meadow and animation, clock digits, |
|
|
Playlists first in the music menu, the playing screen’s pictures and layout, “Favorites”, |
|
|
Sound settings, lyrics off, the volume curve |
|
|
the reader in landscape ( |
|
|
the playing screen’s bar background and card marks, the main menu clock, |
|
|
list styles, short menu names and titles, |
|
the new code: host test, compile, plan helpers, link, put into bank tails |
|
|
|
“Searching…”, the library builder, the option lists, the new code’s placement and callers |
After the parts, base.refresh_copies brings every sideways copy in line with its picture
(Resources, menus and fonts).
Each part works the same way:
it checks that what it is about to change is what it expects (stock bytes, record values, texts, picture sizes) and stops otherwise;
it takes colours from
base.T, the theme being built with the background forced to black;it changes files with
b.get(name)andb.put(name, data)(same length, checksums recomputed); program code only with checked byte changes and patches that pass their checker (Program patches), or through the new code’s placement (New program code (design/playlist));it notes what it did (
b.note), which ends up inTHEME/build.txt.
The order matters where two parts touch the same bytes or one reads what another wrote:
musicpacks the string tables ofMUSIC.STYanew where it writes “Favorites”;listsandplaylistschange English texts in place afterwards.musictakes the red glow out of every playing-screen picture;statusbardraws the note on that background.statusbarborders the status bar’s marks aspicturesandstatusbardrew them.screensaversets the colour key afterclock_sprite.Sis in (the key sits inside that routine in seven programs).listsputslist_boxandmenu_boxat the ends of their banks beforeplaylistsplaces the new code, which leaves those banks out.The sideways copies come last.
Changing the design
Change the module of the area (a new area is a new module, added to
STEPSinbuild.py).Check before changing; take colours from
base.T; note what was done.Build every theme. The images change, so
--checkfails untilRELEASEholds the next release’s hashes.Flash and test one change at a time;
x91_tool.pykeeps the image the last write replaced as “Previous firmware”.
Helpers worth knowing
Helper |
Does |
|---|---|
|
the stock image as |
|
SVG → RGB565 bytes through |
|
SVG pieces in the theme; RGB565 of a colour |
|
|
|
replace a picture of the same size; declare one smaller; read them |
|
pixel digits in the font’s hand-drawn shapes, dot pictures, plain pictures |
|
find and refresh the sideways copies |
|
layout tables and their records |
|
texts: a language’s table packed anew; English texts in place; a text’s width in the interface font |
|
a menu file’s list table; a list’s header and rows |
|
replace bytes after checking the old ones |
|
assemble a patch; disassemble a bank for a checker |
|
run a checker on the old and new bank, stop if it fails |
|
check the stock bytes, run the checker, put the new code in |
|
find a stretch of shared code in any program with its calls masked; list its calls |
|
encode and decode a Thumb |
|
a program’s banks; the room of a bank’s file slot |
|
the new code (New program code (design/playlist)) |
|
one function on its own, at the end of one bank ( |
|
a bank’s room in its group; the list box calls of a program; |
|
the status bar’s marks with their black border, stored in picture 240 |
|
the music lists’ option lists; the placement of the new code |
|
pictures of the search and name screens from the host test’s draw log ( |
Outputs
Path |
Content |
|---|---|
|
the flashable image |
|
the list |
|
the image’s files ( |
|
per part: rendered SVG and PNG, compiled code, linker scripts, disassemblies, checker listings |
|
what each part did, the code’s placement, the image’s sha256 |
|
the host test’s program |
Before 1.0: the stages
Up to stage 27 the design was built as a chain of 27 builders, design/build_stageN.py, each reading the image of
the stage before and writing its own, with frozen copies of the C sources per stage so that every intermediate image
stayed reproducible (The stages, History). Release 1.0 merged them into this build:
each change is applied in its final form only, code a later stage took out again is never placed, and the frozen
sources and the intermediate images are gone. The result is the stage 27 image, byte for byte, in every theme. The
stage builders are in the git history (the last one at commit 1e2be06, “Stage 27 rebuilt”).