Skip to content

Commit

Permalink
Switch to proper wit deps handling (#10)
Browse files Browse the repository at this point in the history
* guest works

* working version

* actually it's kinda works

* add some docs
  • Loading branch information
Zelzahn authored Mar 22, 2024
1 parent 7b9648b commit 6785fe1
Show file tree
Hide file tree
Showing 27 changed files with 775 additions and 1,050 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: CI
on:
push:
branches: [root]
pull_request:
branches: [root]

jobs:
deps-up-to-date:
name: Check I2C dependency is up-to-date
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: ensure `./wit/deps` are in sync
run: |
curl -Lo 'wit-deps' https://github.com/bytecodealliance/wit-deps/releases/download/v0.3.2/wit-deps-x86_64-unknown-linux-musl
chmod +x ./wit-deps
./wit-deps lock --check
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
**/target

# Ignore all wasm files, except the empty ones
*.wasm
!empty.wasm

# Added by cargo

Expand Down
20 changes: 20 additions & 0 deletions Justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
default: hat host

hat: build-hat cp-hat
lcd: build-lcd cp-lcd
host: build-host

build-hat:
cd guest/hat && cargo +nightly component build --release

cp-hat:
cp guest/target/wasm32-wasi/release/hat.wasm hat.wasm

build-lcd:
cd guest/lcd && cargo +nightly component build --release

cp-lcd:
cp guest/target/wasm32-wasi/release/lcd.wasm lcd.wasm

build-host:
cd host && cargo build --release --target aarch64-unknown-linux-gnu
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ The purpose of this repository is to serve as a proof of concept of a potential

Currently, the setup is as follows: Raspberry Pi 4 Model B → I2C Interface → HD44780 LCD. It is my intention to switch out the Pi for a Pi Pico microcontroller, to have a proof of concept for a more constrained piece of hardware. I also have a Pi 3 Model B hooked up with a HTS221.

## Just

To make building easier [just](https://just.systems/man/en/) is used, see `Justfile`.

## Host
To compile for Raspberry Pi make sure to have the corresponding target and linker installed.

Expand All @@ -12,6 +16,12 @@ rustup target add aarch64-unknown-linux-gnu
yay -S aarch64-linux-gnu-gcc
```

### Switching guest

1. Change the `included` guest in the wit.
2. Change the method invocations in the `run` function inside `device.rs`.
3. Change the used `wasm` file inside `main`.

## Guest
### Screen
This guest component is written in Rust and uses the received I²C connection to display `hello world` to the HD44780 LCD screen.
Expand All @@ -32,9 +42,15 @@ cargo +nightly component build
```

## WIT
`embedded.wit` comes from [hello-embedded](https://github.com/sunfishcode/hello-embedded) by sunfishcode. Only the `i2c` and `delay` interfaces are used from this.
See [wasi-i2c](https://github.com/WebAssembly/wasi-i2c) for the source of the wit files.

### `app` world and how I tried to make a generic interface for the host

As I currently have multiple guest components, I would like to use whichever in the host via a CLI. Problem is that the [bindgen](https://docs.rs/wasmtime/latest/wasmtime/component/macro.bindgen.html) macro is quite restrictive, e.g. it's not possible to have one for each world or to define a wrapper around the guest components and then call that one (see [this commit](https://github.com/Zelzahn/i2c-wasm-components/pull/10/commits/5ea3c0f43e3e46022cf8d05a31e439431b359e2d)).

So I came to the `app` world, it includes one of the guest components. The benefit of this wrapper is that the world itself does not change, thus limiting the number of changes required to switch the linked guest in the host.

I had to use the same package for my `screen.wit` to make the `bindgen` in the host work, more specifically the `with`.
Another solution would be to define a host for each guest component, see [this commit](https://github.com/Zelzahn/i2c-wasm-components/commit/7b9648b57c24aad50015215e89f6b6db9342f19e), but this leads to loads of code duplication.

## Embedded HAL
The [embedded-hal](https://crates.io/crates/embedded-hal) crate is the main inspiration for the design of the API. But I currently have not found a way to package a crate that uses this API into a WASM module.
Binary file added empty.wasm
Binary file not shown.
1 change: 1 addition & 0 deletions empty.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(module)
9 changes: 5 additions & 4 deletions guest/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions guest/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ members = ["lcd", "hat"]
resolver = "2"

[workspace.dependencies]
lol_alloc = "0.4.0"
bitflags = "2.4.2"
lol_alloc = "0.4.1"
bitflags = "2.5.0"
wit-bindgen-rt = { version = "0.22.0", default-features = false }
compiler_builtins = { version = "0.1.108", features = ["mem"] }
9 changes: 6 additions & 3 deletions guest/hat/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,22 @@ bitflags = { workspace = true }
wit-bindgen-rt = { workspace = true }
compiler_builtins = { workspace = true }
embedded-hal = "1.0.0"
wasi-embedded-hal = { git = "https://github.com/Zelzahn/wasi-embedded-hal", default-features = false, features = [ "use_alloc" ] }
wasi-embedded-hal = { version = "0.2.0", default-features = false, features = [
"use_alloc",
] }

[package.metadata.component]
package = "embedded:hat"
package = "sketch:implementation"
# We don't need an adapter, but cargo-component doesn't yet have an option to
# disable the adapter. As a workaround, use an empty adapter.
adapter = "../empty.wasm"

[package.metadata.component.target]
path = "../../wit"
world = "sensor"
world = "app"

[package.metadata.component.target.dependencies]
"wasi:i2c" = { path = "../../wit/deps/i2c" }

[package.metadata.component.bindings]
# Enable this to put `std` usage behind a feature, so that we can use `no_std`.
Expand Down
Loading

0 comments on commit 6785fe1

Please sign in to comment.