hardlabs
v0.3.3
Published
Run HardLabs board simulations from your terminal
Readme
hardlabs
Run your firmware on a simulated HardLabs board from the terminal. Watch its console, check the board's state, and plug in power, move the IMU or flip a line while it runs.
npm install -g hardlabs
hardlabs login
hardlabs sims
hardlabs --simulation acme/sensor-board --firmware build/zephyr/zephyr.elfThe simulation runs on HardLabs' servers. Your source code stays on your
machine: the only upload is the firmware image you pass, and it is used for
your session alone. (hardlabs create, below, is the exception: it uploads
the design files and firmware you show it, to build a new simulation.)
Signing in
hardlabs login opens hardlabs.io in your browser with a short code. Sign in
if you need to, check the code matches the one in your terminal, and approve.
The terminal finishes by itself. On a machine without a browser (over SSH),
open the printed link anywhere, or pass --no-browser.
The token is saved to ~/.config/hardlabs/config.json, readable only by you,
and shows up as "CLI on " under hardlabs.io → Settings → CLI
access, where you can revoke it. hardlabs whoami shows which account you
are logged in as. In CI, create a token on that Settings page and set
HARDLABS_TOKEN, or run hardlabs login --token <token>. A token can list
and run the simulations you have access to, and nothing else.
Choosing a simulation
Simulations are named owner/project@version:
| You type | You get |
|---|---|
| acme/[email protected] | exactly that version |
| acme/sensor-board | its latest published version |
| sensor-board or SensorBoard | the one project that name matches, latest version |
A name that matches projects from two owners is an error listing both; the
CLI never guesses. To keep a team and CI on one board revision, put a
hardlabs.json at the root of your firmware repo:
{ "simulation": "acme/[email protected]" }Then plain hardlabs --firmware build/zephyr/zephyr.elf uses it, and you
are told when a newer version exists.
In the shell
| Command | |
|---|---|
| status [panel] | the board's panels, as the website shows them |
| watch [seconds] | redraw them every few seconds until Ctrl-C |
| controls [panel] | what you can change, and how |
| do <control> [values] | e.g. do input-source.bench-supply volts=5.08 |
| fw <text> | type into the firmware's own shell (Tab completes suggestions) |
| shortcuts | the firmware commands this board suggests |
| console [n] | the last n console lines |
| follow on\|off | stream console lines as they arrive |
| gdb [port\|off] | let GDB connect on localhost (default 3333), see below |
| quit | stop the simulation (also Ctrl-D, or Ctrl-C twice) |
Firmware console output streams in above the prompt without disturbing what you are typing.
Debugging with GDB
Type gdb in the shell, or start with --gdb, and point your debugger at
localhost:
hardlabs -s acme/sensor-board -f build/zephyr/zephyr.elf --gdb
# in another terminal
arm-none-eabi-gdb build/zephyr/zephyr.elf -ex "target remote localhost:3333"The CLI prints the command for your ELF, and a Cortex-Debug launch.json
entry for VS Code ("servertype": "external", "gdbTarget":
"localhost:3333"). Symbols come from your local ELF; nothing extra is
uploaded.
- Connecting halts the CPU. While the debugger holds it, simulated time stands still: timers, peripherals and the console do not move under a breakpoint. The website shows the board as halted.
- When GDB detaches or quits, the board runs on.
monitor helplists the board commands GDB can send, such asmonitor press <button>. The rest of the board's controls are in the shell.- One debugger at a time per session.
Creating a simulation from your design files
hardlabs create # in your board or firmware repo
hardlabs create hw/ --firmware build/zephyr/zephyr.elfhardlabs create [dir] uploads a board's design files and its firmware in
one request, has HardLabs build a simulation of the board from them, and
follows the build in your terminal (Ctrl-C cancels it). It needs a netlist;
everything else helps. With firmware, HardLabs builds the board, runs your
firmware on it and checks every part against it (usually 5–25 minutes).
Without firmware, each part gets a model checked against its datasheet and
nothing is run (usually 5–20 minutes); create it again with --firmware
once you have a build.
Any signed-in HardLabs user can create simulations, up to 3 a day. Over the limit, or when HardLabs is busy, the command says so and when to try again, and exits 1. Boards whose microcontroller HardLabs does not support yet are refused with a message saying so. Without flags it looks in the directory (default: the current one) for:
| File | Found as |
|---|---|
| netlist (required) | a .net file, or a KiCad XML netlist export (<export>); the shallowest one |
| BOM | a .csv/.tsv/.xlsx/.xls/.xml/.txt named like bom, else a .csv/.tsv with a reference column and an MPN/value/quantity column |
| schematic | .kicad_sch, .sch, or a PDF named like schematic |
| datasheets | other PDFs at the top level or under datasheets/ or docs/ |
| firmware | an ELF such as build/zephyr/zephyr.elf (build intermediates skipped) |
| parts | parts.json at the top level |
It shows what it picked and asks before uploading (skip with --yes). With
several firmware images it lists them, newest first, and asks which, or,
outside a terminal, wants --firmware. Flags override what is found:
--netlist, --bom, --schematic, --doc (repeatable; replaces the found
datasheets), --firmware, --parts, --platform, and --name for the
simulation's title. Firmware may be up to 64 MB, other files 32 MB each, and
one upload 200 MB in all.
When the build ends it prints the three checks (runtime, interfaces,
behaviour; without firmware: loads, wiring, datasheets) with the first
reasons for any that fail, and how each part fared, then pins the new simulation in hardlabs.json in that
directory, keeping any other keys there (it asks before replacing a different
pin; --yes replaces it). Open it with plain hardlabs, or
hardlabs -s <id>.
| Exit status | | |---|---| | 0 | ready | | 2 | built, but some checks fail | | 1 | failed, cancelled, refused (daily limit, unsupported board), or an error |
--max-usd <n> caps what the build may spend, --no-wait starts it and
prints its id without following it, and --json prints the result as one
JSON document on stdout (progress goes to stderr). When the server refuses
the build, that document is {"status": "refused", "error": "quota" | "busy" |
"budget" | "forbidden" | …, "detail": …, "retry_after": <seconds or null>}.
Options
-s, --simulation <name> which simulation (default: hardlabs.json)
-f, --firmware <file> ELF to run (default: the simulation's own firmware)
--gdb [port] let GDB connect on localhost:3333 (or port)
--api <url> API address (or HARDLABS_API_URL)
--no-color plain output (or NO_COLOR=1)
hardlabs create [dir]
--netlist <file> KiCad netlist, .net or .xml (required)
--bom <file> bill of materials
--schematic <file> schematic (.pdf .kicad_sch .sch)
--doc <file> a datasheet or note; repeat for more
-f, --firmware <file> firmware (.elf, or .bin .hex)
--parts <file> parts.json
--platform <file> a platform description (.repl)
--name <title> what to call the simulation
--max-usd <n> stop building once it has cost this much
-y, --yes do not ask
--no-wait start the build and exit
--json machine-readable resultNeeds Node.js 18.17 or later.
