Skip to content

Repository files navigation

embedded-linux-bench

Twenty embedded Linux projects on one bench, in one repository. They share a Yocto layer, a cross SDK, a set of boards and a single entry point, because they are one body of work rather than twenty unrelated demos.

Project 1 builds the foundation the rest stand on: an image built entirely from source, a layer that later projects extend, and an SDK that cross-compiles their code against the exact sysroot on the target.

./go                 # the task list
./go setup           # prepare a Linux or WSL2 build host
./go check           # everything provable without a board, about 2 minutes
./go build           # bench-image for the Raspberry Pi 4

What a clone gives you

Source, not images. Nothing flashable is published here. There are no release assets, and .gitignore excludes *.wic, *.wic.bz2 and *.wic.bmap deliberately, so ./go flash on a fresh clone looks into a build tree that does not exist yet and refuses rather than writing something wrong to a card.

If you are interested in the software, you need no hardware and no build. ./go check runs everything provable without a board in about two minutes: six C programs compiled with -Werror, four of them against libgpiod v2, every Python program byte-compiled, the static layer checks and every suite in tests/. CI runs the same set on every push. The applications, the recipes, the kernel fragments, the systemd units, the test suites and the whole walkthrough/ read on any machine.

If you want a card that boots, you build one. That is the honest cost and it is not a first-run penalty: Project 1's first build succeeded, 5095 tasks, no failures, in 194 minutes on eight cores, plus about 10 GB of downloads. A second build with nothing changed is 21 seconds from shared state, and a one-recipe change is under three minutes. The three hours are a cross toolchain, glibc and a kernel compiled from source, and no amount of fixing this repository makes them shorter.

An identical board is not sufficient on its own. These images are built for one bench and the assumptions are listed under what this image assumes: the console is a 7 inch DSI panel, the console keymap is German, networking is wireless because no cable reaches the bench, and debug-tweaks leaves root without a password. Each row says where to change it. No credential is ever in this repository; SSIDs, passphrases and APNs are written to the FAT boot partition after flashing.

Why an image is not offered for download. Two reasons, both substantive. The image has passwordless root, which is correct for an isolated bench and wrong on anyone else's network. And distributing a binary attaches a corresponding-source obligation that building it yourself does not; ./go release exists to produce the licence manifest, the SPDX SBOM and the source archive that a published image would have to carry. If that changes, those four artefacts ship together or not at all.

What is offered instead is the reproducibility claim, stated narrowly and backed by evidence: a clean build from the same commit produces the same package list. ./go reproduce checks it with its own separate sstate cache, so it genuinely rebuilds and costs about as long as the first build again. Project 1's result is 95 packages and 95 packages, identical.

Why it is built this way

walkthrough/ explains the reasoning end to end: what embedded Linux is and what these projects are for, why Yocto rather than Buildroot, what BitBake does during those three hours, how a layer is put together, why the status daemon is two programs, what each check proves and what it cannot, and where every piece belongs across a product lifecycle from first bring-up to a version still being patched years later. It ends with a decision log, each entry naming the alternative that was rejected.

It is written so that it applies to the other nineteen projects, not only to this one.

Why one repository

The twenty projects are not independent. Project 5 writes a kernel driver that Project 10 then exercises; Projects 11 and 12 cross-compile with the SDK that Project 1 produces; Projects 5 and 6 want the identical rootfs on a different board, and Project 19 shares that board while needing a different one. Twenty repositories would mean twenty copies of the same layer pins, and a reader would have to reconstruct the order.

So the layer is shared and the projects are directories inside it:

embedded-linux-bench/
  meta-bench/          the Yocto layer every project extends
    conf/layer.conf
    recipes-core/images/       bench-image and its variants
    recipes-bench/             applications, one directory per program
    recipes-kernel/linux/      kernel configuration fragments
  kas/                 build configurations: machine, distro, layer pins
  projects/
    01-yocto-image/    what each project adds, how to run it, its evidence
    15-lte-router/
  sdk/                 programs that prove the cross SDK works
  scripts/             build, flash, SDK, reproducibility, checks
  tests/               what can be tested without hardware
  docs/                bench-wide notes
  go                   one entry point

Recipes live in the layer because Yocto requires it. Everything that is not a recipe, the narrative, the wiring, the measurements and the evidence, lives under projects/NN-slug/, so each project reads as a unit while the build stays a single coherent tree.

How each project is written

Every project is self-contained. Nothing here cites a document that is not in this repository. There is no companion text to fetch, no figure to look up elsewhere and no acceptance criterion you have to take on trust: what a project was asked to do is written out where the project is, in words, and a reader who arrives at this URL with no other context can read it end to end and judge it.

That rule shapes what each projects/NN-slug/ directory contains, and the same four files are expected of all twenty:

File What it holds
README.md What the project is, what it adds to the layer, how to run it, its acceptance criteria written out in full, and what was measured against each
docs/DESIGN.md The methodology before the results: system architecture, the wiring and its pin table, the bench layout, and the software's structure, all drawn as ASCII or mermaid so they diff and grep
JOURNAL.md What actually happened in order, failures included. Each entry says what happened, what was done, and why that rather than the alternative
docs/evidence/ The raw output behind every number claimed: build logs, boot timings, package manifests, reproducibility diffs
results/ Where a project measures something: the board's own CSV, the per-run instrument files behind it, and any figure drawn from them

A figure is generated from a file the board produced, or it is not in the repository. Plots come from the instruments' own output through ./go plot and ./go matrix, and are committed as ASCII SVG, which renders on GitHub and still diffs and greps like the text it is. Explanatory diagrams stay ASCII or mermaid in docs/DESIGN.md. A photograph is allowed as evidence of assembled hardware and is never the diagram of record. Nothing is hosted anywhere but here.

Choices that outlive one project go in walkthrough/DECISIONS.md instead, each entry naming the alternative that was rejected. Where a project departs from what it was originally scoped to do, it says what the difference is and why, rather than pointing at where the original lives.

The twenty projects

The state column is a ladder, and each rung is a claim about evidence rather than about effort:

State What it means
Planned Not started. The row names the board and the theme, nothing more
Written, not yet built The recipes, programs and documents exist and the suites pass, and no build has been run, so nothing has checked that BitBake can parse them. A rung that exists because the one below it claims more than it should
In progress Between two rungs and saying which. Used where part of the work is at one rung and part at another, so the row names both rather than rounding to the lower one
Software complete It builds and its tests pass on a machine with no board attached. Nothing has been powered on. A project whose work is split across two processors says which half is done, so Project 12 reads "Linux side complete"
Built and running on the board The image was flashed, the hardware works and the thing does its job. Named measurements are still outstanding, and the row says which
Measured The measurement the project exists to make has been taken, on the board, with its provenance recorded. Not the same as Complete: a criterion can be measured and not met, which is a result rather than a gap, and Project 8 has two of those
Complete Every acceptance criterion in that project's README is met, each with evidence in its docs/evidence/, or deferred with a written reason

The gap between the last two rungs is deliberate. A router that routes traffic is not the same as a router whose failover has been timed, and only the second is what the project was specified to produce. Each project's README carries the full criteria table, marked criterion by criterion, so the claim can be checked rather than taken.

# Project Board Theme State
01 A Yocto image that owns the whole stack Raspberry Pi 4 Build systems, layers, recipes, SDK Complete: built, booted, reproducible, SDK verified on the board
02 NanoPi NEO Air on mainline: U-Boot, kernel, device tree, eMMC NanoPi NEO Air Board bring-up, bootloader, sunxi mainline Complete: U-Boot v2025.10, a 6.12 kernel with the board device tree and brcmfmac as a module, and a Debian bookworm armhf root filesystem carrying the modules and the AP6212 firmware, with 69 assertions covering the two tools that can destroy something. All six criteria met on hardware: U-Boot sees both media, the card boots to a login, Wi-Fi associates and takes a DHCP lease, the board boots its own eMMC with no card in the slot, provisioning is idempotent across three consecutive runs, and a board with its bootloader erased from both media was recovered over USB in FEL mode and wrote its own bootloader back. Boot logs for both media are in docs/
03 Boot time and energy per boot, measured NanoPi NEO Air + PPK2 Boot-time optimisation, systemd-analyze, power Baseline measured, one variant of six: five kept runs give 15.431 s to boot complete with a spread of 0.281 s, 14.42 J per boot, and the first console byte at 1.083 s with a spread of 0.3 ms. Both electrical markers fire, and no reported number comes from the board's own clock. The first working measurement immediately falsified two things the design had written down before it had data: a 0.5 s deadline that discarded every healthy run, and a phase order that ran backwards, because the SPL prints before U-Boot exists to run a preboot hook. Both are corrected in the open with the old values kept. The other five variants are not built
04 A network-boot hardware-in-the-loop lab Pi 4 server + Pi 3B+ DUT TFTP/NFS root, udev, serial consoles, automated tests Software complete: server configuration, console framing, fixtures and the DUT image, with 47 assertions that need no boards. Nothing has netbooted yet
05 An IIO driver for the ADXL345 written from scratch Raspberry Pi 3 Kernel driver model, regmap, threaded IRQ, IIO events Written, not yet built: the driver, its recipe, the kernel fragment, the image and the build configuration, with 43 assertions that need no board and no kernel tree
06 Explorer 700: every peripheral in one device-tree overlay Raspberry Pi 3 Device tree composition, sysfs, hwmon, rtc, w1, drm, input Written, not yet built: one overlay binding eleven peripherals, a 26 symbol kernel fragment, the verifier and two demonstration tools, with 96 assertions that need no hardware. The vendor manual overturned five rows of the specification, one of them a driver that cannot bind this board's display at all. BitBake has never parsed these recipes and dtc has never compiled the overlay, so this is a rung below Software complete on purpose
07 A 3.5 inch SPI display as a DRM panel with touch Raspberry Pi 3B+ DRM/KMS tiny drivers, input subsystem, fbcon Written, not yet built: the overlay, the kernel fragment, three programs and 63 assertions, plus the overlay compiled by dtc in CI and drmfill compiled with -Werror. No image has been built and no board powered on
08 PREEMPT_RT latency lab with the MCC 118 as instrument Raspberry Pi 4, and a 3B v1.2 as second board Real-time kernel, cyclictest, IRQ affinity, jitter Measured: 18 matched rows on the board, generic against PREEMPT_RT, with an MCC 118 as the external instrument. PREEMPT_RT changed nothing at the pin until the core was isolated, then improved p99.9 by a third to a half. Two force_turbo rows not taken, and why, in results
09 Kernel debugging lab: kgdb, ftrace, perf, pstore Raspberry Pi 3B+ Debugging and tracing over the serial console Written, not yet built: a deliberately faulty module, the debug and KASAN fragments behind two switches, two images, the host proxy and decode tools with 37 assertions, and a six-part notebook. No image built, no fault triggered
10 IIO in depth with the X-NUCLEO-IKS4A1 Raspberry Pi 3B+ IIO buffers and triggers, libiio, iiod, AHRS Measured on the board: eight of nine acceptance criteria met. Six IIO devices from one overlay across two IMUs, a magnetometer and a barometer; a software trigger at 3.341 us; libiio reading the same columns through local: and through ip: with the sample counts equal; and a 142-fold cut in interrupt load from one word in the device tree, level instead of edge. The ninth is 0.3 degrees short on a fixture rather than on the measurement
11 A userspace driver packaged as a library Raspberry Pi 4 Userspace drivers over i2c-dev, shared library hygiene, two packaging systems Built, packaged and tested on a host, never run on a board: three of six acceptance criteria met without a sensor. The library builds with -Werror, nm -D counts exactly the six symbols the packaging pins, ctest passes under ASan and UBSan, and the three Debian packages build and clear lintian. 133 assertions. Getting the packaging there cost five defects that no file-against-file assertion could see, because no file disagreed with any other file. The row said "nothing has been compiled on any machine" for eleven days while CI compiled it 103 times
12 A sensor-hub D-Bus service over UART Raspberry Pi 4 CBOR wire protocols, sd-bus, polkit, socket activation Linux side complete: wire protocol, daemon, policy, activation, client and three test suites; firmware specified, no board work yet
13 A Wayland kiosk HMI on the 7 inch touchscreen Raspberry Pi 4 DRM/KMS with vc4 and v3d, weston kiosk shell, libinput, LVGL Written, not yet built: the compositor configuration, an LVGL dashboard as a Wayland client with LVGL vendored at 9.3, a layer-by-layer graphics diagnostic, and 20 assertions that run on a laptop plus 21 more that need a compiler. Nothing has been compiled on any machine
14 The Pi as a USB gadget: Ethernet, serial and HID Raspberry Pi 4 USB gadget configfs, libcomposite, dwc2 in peripheral mode, evdev to HID Written, not yet built: the composite gadget as a configfs script and a unit, a keyboard bridge whose usage table is generated from the kernel's own source, the endpoint budget written before the build, and 51 assertions. Nothing has been compiled on any machine
15 An LTE router with failover and GNSS Raspberry Pi 4 ModemManager, NetworkManager, QMI, nftables, gpsd Built and running on the board: live LTE bearer at metric 700, NAT and DHCP for the bench LAN, a firewall that drops by default, metrics with real signal, and both uplink radios up. Failover timings are the measurement outstanding; GNSS is deferred, because the bench is an indoor desk and the antenna needs sky
16 A low-power Cat-M and NB-IoT tracker Raspberry Pi 3 AT state machines, CoAP/LwM2M, PSM/eDRX, current budget Written, not yet built: the AT state machine, the power key and instrument marker tool, the recipe, the image and the build configuration, with 75 assertions that need no modem. No ModemManager and no network interface at all, so the CoAP datagram is built on the host and handed to the modem's own IP stack. The kernel fragment and the udev rule are deliberately unfinished until lsusb has been read on the board, and the whole AT command table is provisional until a real transcript replaces it
17 A BLE gateway for the STWIN.box with BlueZ Raspberry Pi 3B+ BLE central on Linux, BlueZ D-Bus GATT, pipelines Software complete: kernel fragment, BlueZ configuration, the gateway and three test suites; no board work yet
18 An edge access point with a broker nobody can join by accident Raspberry Pi 3 hostapd, dnsmasq, Mosquitto, X.509 Written, not yet built: a private certificate authority with revocation that is actually enforced, both configurations, the image and the build configuration, with 197 assertions that need no board. The subject is the PKI rather than the access point: the broker takes the certificate's common name as the username, so the access list is enforced against something the CA vouched for, and publishers can write and not read. An island by design, with no uplink, no DNS and no plaintext listener, which makes the access point the only way onto the board. The radio firmware and whether this FullMAC part will run an access point at all are both open until one boot answers them
19 A/B updates with RAUC Raspberry Pi 3 OTA with RAUC, U-Boot bootcount, read-only rootfs, overlayfs-etc, SoC watchdog Software complete: a four partition card, the A/B boot script, the RAUC configuration and bundle recipe, a health check gated on boot-complete.target, a failsafe timer, the SoC watchdog, slot LEDs, and the two bundles that are meant to fail. 119 assertions that need no hardware, thirty of them proved by injecting the fault they catch. Nothing has been built and no board has seen any of it; dm-verity stays a stretch goal
20 OP-TEE on the Pi 3: a trusted application for key storage Raspberry Pi 3 TrustZone, OP-TEE OS, TEE Client API, secure storage In progress, between Software complete and Built and running on the board: both halves are built and the board has booted them, and the thing does not yet do its job. The image is 58 MB at 4f84a65 with the trusted application linked and signed. The secure world is armstub8.bin, 1,261,624 bytes, TF-A v2.6 carrying OP-TEE 4.1.0 and U-Boot 2021.10 as BL33, built on Tuesday 22 September 2026 once two host prerequisites were known. On the board, TF-A, OP-TEE and U-Boot print their banners in order, Linux comes up under PSCI with all four CPUs once the device tree is patched in RAM at the U-Boot prompt, because the firmware's tree has no /psci and no /firmware/optee, and on the first boot the kernel reported optee: revision 4.1. Then the driver's first call into the secure world never returns, and within one second the VideoCore firmware mailbox stops answering unrelated, healthy CPUs: seen six times across two days, on every one of the four CPUs, at uptimes from twenty seconds to 551. Every SD failure of those two days was a consequence of that, proven by a 207 second control boot; the card was never at fault. The driver is now selectable as a module by ./go tee-mod so the call can be made from a login on a read-only root, and the console of the last two runs is in docs/evidence/. The mechanism is not known. Next is putting OP-TEE's console and Linux's on the same UART, since the secure world has been printing through all six hangs into a PL011 nothing is wired to. No acceptance criterion is met on hardware; criterion 1 was reached once and not held

Building

Every build configuration is a kas file, and every external layer is pinned there. Moving to the next Yocto LTS means editing three branch names in one file.

Command Configuration Result
./go build kas/bench-rpi4.yml bench-image for raspberrypi4-64
./go rpi3 kas/bench-rpi3.yml The same image for raspberrypi3-64
./go dev kas/bench-dev.yml bench-image-dev, with gdbserver and perf
./go router kas/bench-router.yml bench-router-image, the gateway of Project 15: two uplinks, NAT, a cellular watchdog
./go release kas/bench-release.yml The same image plus an SPDX bill of materials, a CVE report and the corresponding source archive
./go rt kas/bench-rt.yml bench-rt-image, the latency lab of Project 8: a PREEMPT_RT kernel, cyclictest, stress-ng and an MCC 118 DAQ HAT
./go ble kas/bench-ble.yml bench-ble-image, the BLE gateway of Project 17: BlueZ, the radio firmware, a Python BLE client and a local broker
./go tee kas/bench-tee.yml bench-tee-image, the OP-TEE keystore of Project 20: the TEE subsystem, tee-supplicant, the conformance suite and a trusted application. The secure world itself is added to the card by ./go armstub
./go tee-mod kas/bench-tee-modular.yml The same image with the OP-TEE driver built as a module and kernel-module-optee installed, so a driver that hangs at probe can be loaded from a login instead of at boot. A debugging image, to be deleted when the hang is understood
./go hub kas/bench-hub.yml bench-hub-image, the sensor hub of Project 12: the system bus, polkit, the D-Bus service and OpenOCD
./go iio kas/bench-iio.yml bench-iio-image, the IIO sensor lab of Project 10: four in-tree sensor drivers, the software triggers, libiio with its network daemon, and the three-path rate comparison

Later projects that need a different kernel or a different image add their own kas file next to these rather than changing the shared one. Project 8 does exactly that for PREEMPT_RT, and it needs two lines rather than one: the fragment switch, and a kernel new enough to have the symbol at all. arch/arm64 gained ARCH_SUPPORTS_RT in 6.12 and the BSP still defaults to 6.6, so without the version pin the option is dropped without a word and the image boots a kernel that is not preemptible.

The build host needs a case-sensitive file system and about 60 GB. The scripts check both and refuse to start otherwise, because finding out three hours into a build is expensive.

docs/BUILD-HOST.md covers the host in full, including a table of every package ./go setup installs and why each one is needed.

Keeping a flashable copy

The build tree is disposable by design, which means the image in it is too: ./go clean deletes it, and so does anything else reclaiming disk. Losing it costs nothing except the ability to put that exact state back on a card without paying the hours again.

./go archive              # keep the image just built, with its provenance
./go archive router       # the same, for another configuration
./go archive list         # what has been kept, with board and commit
./go archive available    # what the build tree still holds, before it goes
./go flash /dev/sdX IMAGE.wic.bz2     # write a kept image back

The store is ~/bench/images by default, outside the repository and beside the caches, so it survives ./go clean. Set BENCH_IMAGE_DIR to put it on an external drive instead. Nothing in it is ever committed: these are build outputs, and the compressed images are 48 to 79 MB each.

Each saved image comes with a PROVENANCE.txt, and that is the point. An image on its own is a mystery card: it boots, and nothing about it says which commit produced it, which layer revisions were pinned, or which board it is for. The record carries the date, the kas configuration, the machine, the commit, a sha256 of each file, the command to flash it and the command to rebuild it, and it says plainly when the working tree was dirty at build time. kas dump --lock output is saved next to it, so the image can be rebuilt rather than only re-flashed.

Archiving under a configuration you did not just build is refused rather than filed, because the newest image in the tree may be for another board. A Pi 4 image written to a card for a Pi 3 does not warn and does not boot: the symptom is a dark board that reads as dead hardware.

What this image assumes about the bench

These are choices about one workshop, not defaults anyone should inherit silently. Each is one line, and each says where to change it.

Assumption Why Where it is set
The console is the official 7 inch DSI panel This bench has no micro-HDMI adapter and its USB/TTL cable is obsolete RPI_EXTRA_CONFIG and CMDLINE_CONSOLE in kas/bench-rpi4.yml
The console keymap is German The boards are used with a German keyboard, and a US map makes a shell unusable vconsole.conf in meta-bench/recipes-bench/bench-provision/files/
Networking is wireless There is no wired network within reach of the bench bench-net-wifi, plus the firmware named in bench-image.bb
The Pi 4 radio firmware is proprietary The radio does not initialise without it LICENSE_FLAGS_ACCEPTED in kas/bench-rpi4.yml
Root has no password debug-tweaks, right for an isolated bench and wrong for anything else IMAGE_FEATURES in bench-image.bb

Wired networking needs no changes at all. The image already runs DHCP on eth* and an SSH server, so a board with a cable gets an address and accepts ssh root@... out of the box. The wireless support exists because this bench has no cable, not because it is better.

WiFi credentials are never in this repository. The image carries the capability to join a network; the card carries the identity. A first-boot service reads SSID and PSK from wifi.conf on the FAT boot partition, which you write after flashing with any text editor. See the bring-up notes.

What is tested without hardware

Most of a Yocto project cannot be tested on a laptop, but the parts that usually break can be:

Check Command Covers
Signed-record contract sh tests/keystore-canonical-test.sh Project 20's canonical serialisation, which the signer on the board and the verifier on the host must agree on byte for byte
Trusted application policy sh tests/keystore-policy-test.sh The four TA commands against a model written from the documented rules: provisioning, a reboot, and both ways to lose a key
Cross-file constants sh tests/keystore-header-test.sh That a UUID written in five places, in two languages, a makefile and a recipe, has not drifted
Static layer checks ./go lint Files in SRC_URI that are missing, units in SYSTEMD_SERVICE that are never installed, layer.conf completeness, ASCII and line length
State machine sh tests/bench-state-test.sh The status logic, against a fake systemctl
WiFi provisioning sh tests/bench-wifi-setup-test.sh Credentials parsed from a file written on Windows, including CRLF endings, missing fields and file permissions
Router provisioning sh tests/bench-router-setup-test.sh The same three Windows text traps for the router's SSID, passphrase and APN, plus file modes and partial input
Cellular watchdog sh tests/lte-watchdog-test.sh The escalation ladder against stubbed mmcli, ping, nmcli and lte-gpio
Modem metrics sh tests/lte-exporter-test.sh Parsing and Prometheus text format, with no modem present
Firewall invariants sh tests/bench-router-nftables-test.sh Input policy drop, both uplinks masqueraded, the MSS clamp, no port opened towards an uplink
Edge timing arithmetic sh tests/rt-analyze-test.sh Project 8's period recovery, against a synthesised square wave with known edge times, in both edge regimes
Run protocol sh tests/rt-run-test.sh The measurement order, core confinement, the isolation claim in both directions, the throttle gate and every column of the results row
Interrupt affinity sh tests/rt-irq-affinity-test.sh Movable interrupts against kernel-owned ones, against a fake /proc/irq
Latency instrument comparison sh tests/rt-compare-test.sh Project 8's central claim, against a simulation: a constant GPIO write cost cancels in an interval measurement, and what survives is its variation
Kernel fragment symbols sh tests/kernel-symbols-test.sh That ./go ksym tells a real Kconfig symbol from a line that names nothing, and a settable one from a symbol only the kernel can select
Wire protocol sh tests/sensorhub-proto-test.sh Project 12's frame format against frozen vectors, and a parser fed garbage, split frames, corrupted CRCs, absurd lengths and a lost byte
Protocol, two implementations sh tests/sensorhub-cabi-test.sh The C compiled and driven through ctypes, compared byte for byte against an independent Python implementation over 900 randomised cases
A D-Bus service's eight files sh tests/sensorhub-policy-test.sh Interface name, object path, polkit action, device path and unit name compared across the daemon, the bus policy, the activation file, the polkit action and rule, the udev rule, the unit and the recipe
BlueST protocol sh tests/stwin-bluest-test.sh Project 17's decoder: masks read from UUIDs, both frame shapes, and an unknown mask bit stopping the walk rather than shifting every field after it
BLE connection ladder sh tests/stwin-supervisor-test.sh Scan, connect, resolve, stream and back off, with a fake link that can fail at any step
Gateway sinks sh tests/stwin-sinks-test.sh CSV columns fixed by the feature mask, daily rollover, the MQTT topic and payload, one LED per state
Host compile ./go check Six C programs built with -Werror: four against the host libgpiod v2, the sensor hub daemon against libsystemd and libcbor, which is the only check anywhere that reads a D-Bus vtable, and drmfill against libdrm. The SDK example is cross-compiled separately. Every Python program byte-compiled, found by shebang as well as by extension, so the ones with no .py are not missed

CI runs all of these on every push, on a pinned ubuntu-24.04 runner with libgpiod v2 built from a named tag, because no Ubuntu LTS image packages v2 and an unpinned runner is a moving dependency like any other. It does not build the image: that needs a self-hosted runner with a shared sstate mirror, which is an opt-in job.

Licence

MIT. See LICENSE.

About

Twenty embedded Linux projects on one bench: one Yocto layer, one cross SDK, one entry point. Source rather than images, and ./go check proves what needs no hardware in about two minutes. Board measurements are published with their provenance, including the criteria that were measured and not met.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages