├── .gitignore ├── .vscode └── settings.json ├── README.md ├── async-guest ├── Cargo.toml ├── empty.wasm ├── empty.wat └── src │ ├── bindings.rs │ └── lib.rs ├── guest ├── Cargo.toml ├── empty.wasm ├── empty.wat └── src │ ├── bindings.rs │ └── lib.rs ├── host ├── Cargo.toml └── src │ └── main.rs ├── linux-host ├── Cargo.toml └── src │ └── main.rs └── wit ├── async.wit ├── blink.wit ├── deps └── io │ ├── error.wit │ ├── poll.wit │ ├── streams.wit │ └── world.wit └── embedded.wit /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.check.overrideCommand": [ 3 | "cargo", 4 | "component", 5 | "check", 6 | "--workspace", 7 | "--all-targets", 8 | "--message-format=json" 9 | ], 10 | } 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hello Embedded! 👋 2 | 3 | This repository contains a sketch of an embedded API described in [Wit], 4 | and a simple example Wasm application that builds with it that blinks 5 | an LED, and a Wasmtime-based simulator that can run it. This is a super 6 | early demo, and hasn't been optimized at all for code size yet. Its 7 | purpose right now is to start some discussions. 8 | 9 | [Wit]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md 10 | 11 | ## The Wits 12 | 13 | The API is described in Wit interfaces in the wit directory, and is based off 14 | of the [embedded-hal] API. 15 | 16 | ## The guest 17 | 18 | The example application is in the guest directory. Building it currently 19 | requires [cargo component 0.8]. Build with `cargo component build`. 20 | 21 | [cargo component 0.8]: https://github.com/bytecodealliance/cargo-component/releases/tag/v0.8.0 22 | 23 | ```sh 24 | $ cd guest 25 | $ cargo component build --release 26 | [...] 27 | $ cd .. 28 | ``` 29 | 30 | That produces a component in `guest/target/wasm32-wasi/release/hello_embedded.wasm`. 31 | We can examine it with `wasm-tools`: 32 | 33 | ```sh 34 | $ wasm-tools component wit guest/target/wasm32-wasi/release/hello_embedded.wasm 35 | package root:component; 36 | 37 | world root { 38 | import sketch:embedded/delay@0.0.0; 39 | import sketch:embedded/digital@0.0.0; 40 | 41 | export sketch:embedded/run@0.0.0; 42 | } 43 | ``` 44 | 45 | Here we can see it's exporting the `run` interface, which has the `run` 46 | entrypoint function, and importing the `digital` and `delay` and interfaces, 47 | which it uses to set the led and control its speed, respectively. 48 | 49 | ## The host simulator 50 | 51 | Once the guest is built, it can be run in the host simulator: 52 | ```sh 53 | $ cd host 54 | $ cargo run 55 | [...] 56 | ``` 57 | 58 | ``` 59 | 💡 60 | ``` 61 | ``` 62 | 63 | ``` 64 | ``` 65 | 💡 66 | ``` 67 | ``` 68 | 69 | ``` 70 | ``` 71 | 💡 72 | ``` 73 | ... 74 | 75 | ## The Linux host 76 | 77 | ⚠ The following is *entirely untested* at this time!!! ⚠ 78 | 79 | If you can run this on a Linux board with a GPIO pin 0 wired up to 80 | an LED, and if luck smiles on us, this should run the guest which 81 | should make that LED blink: 82 | 83 | ```sh 84 | $ cd linux-host 85 | $ cargo run 86 | [...] 87 | ``` 88 | 89 | ## Bonus points 90 | 91 | This example also demonstrates [Typed Main]. The `run` function takes 92 | two handle arguments, providing the component with exactly what it 93 | needs. 94 | 95 | [Typed Main]: https://sunfishcode.github.io/typed-main-wasi-presentation/chapter_1.html 96 | 97 | [embedded-hal]: https://docs.rs/embedded-hal/latest/embedded_hal/ 98 | -------------------------------------------------------------------------------- /async-guest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-embedded" 3 | version = "0.0.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | lol_alloc = "0.4.1" 12 | wit-bindgen = { version = "0.18.0", default-features = false, features = ["realloc"] } 13 | compiler_builtins = { version = "0.1.108", features = ["mem"] } 14 | wasi-async-runtime = { path = "/home/dev/wasm-http-tools/crates/wasi-async-runtime", default-features = false } 15 | wasi = { version = "0.12.1", default-features = false } 16 | futures-util = { version = "0.3.30", default-features = false, features = ["async-await-macro"] } 17 | 18 | [package.metadata.component] 19 | # We don't need an adapter, but cargo-component doesn't yet have an option to 20 | # disable the adapter. As a workaround, use an empty adapter. 21 | adapter = "empty.wasm" 22 | 23 | [package.metadata.component.target] 24 | path = "../wit" 25 | world = "async-blink" 26 | 27 | [package.metadata.component.target.dependencies] 28 | # The async interfaces depend on wasi-io. 29 | "wasi:io" = { path = "../wit/deps/io" } 30 | 31 | [package.metadata.component.bindings] 32 | # Enable this to put `std` usage behind a feature, so that we can use `no_std`. 33 | std_feature = true 34 | 35 | [profile.release] 36 | # Strip out debug info to produce a small component. 37 | strip = true 38 | -------------------------------------------------------------------------------- /async-guest/empty.wasm: -------------------------------------------------------------------------------- 1 | asm -------------------------------------------------------------------------------- /async-guest/empty.wat: -------------------------------------------------------------------------------- 1 | (module) 2 | -------------------------------------------------------------------------------- /async-guest/src/bindings.rs: -------------------------------------------------------------------------------- 1 | // Generated by `wit-bindgen` 0.18.0. DO NOT EDIT! 2 | pub mod sketch { 3 | pub mod embedded { 4 | 5 | #[allow(clippy::all)] 6 | pub mod async_delay { 7 | #[used] 8 | #[doc(hidden)] 9 | #[cfg(target_arch = "wasm32")] 10 | static __FORCE_SECTION_REF: fn() = super::super::super::__link_section; 11 | pub type Pollable = super::super::super::wasi::io::poll::Pollable; 12 | /// Delay with up to nanosecond precision. 13 | 14 | #[derive(Debug)] 15 | #[repr(transparent)] 16 | pub struct Delay{ 17 | handle: wit_bindgen::rt::Resource, 18 | } 19 | 20 | impl Delay{ 21 | #[doc(hidden)] 22 | pub unsafe fn from_handle(handle: u32) -> Self { 23 | Self { 24 | handle: wit_bindgen::rt::Resource::from_handle(handle), 25 | } 26 | } 27 | 28 | #[doc(hidden)] 29 | pub fn into_handle(self) -> u32 { 30 | wit_bindgen::rt::Resource::into_handle(self.handle) 31 | } 32 | 33 | #[doc(hidden)] 34 | pub fn handle(&self) -> u32 { 35 | wit_bindgen::rt::Resource::handle(&self.handle) 36 | } 37 | } 38 | 39 | 40 | unsafe impl wit_bindgen::rt::WasmResource for Delay{ 41 | #[inline] 42 | unsafe fn drop(_handle: u32) { 43 | #[cfg(not(target_arch = "wasm32"))] 44 | unreachable!(); 45 | 46 | #[cfg(target_arch = "wasm32")] 47 | { 48 | #[link(wasm_import_module = "sketch:embedded/async-delay@0.0.0")] 49 | extern "C" { 50 | #[link_name = "[resource-drop]delay"] 51 | fn drop(_: u32); 52 | } 53 | 54 | drop(_handle); 55 | } 56 | } 57 | } 58 | 59 | impl Delay { 60 | #[allow(unused_unsafe, clippy::all)] 61 | /// Returns a pollable that resultls after minimum `ns` nanoseconds. 62 | /// The delay can be longer if the implementation requires it due to 63 | /// precision/timing issues. 64 | pub fn subscribe_to_delay_ns(&self,ns: u32,) -> Pollable{ 65 | 66 | #[allow(unused_imports)] 67 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 68 | unsafe { 69 | 70 | #[cfg(target_arch = "wasm32")] 71 | #[link(wasm_import_module = "sketch:embedded/async-delay@0.0.0")] 72 | extern "C" { 73 | #[link_name = "[method]delay.subscribe-to-delay-ns"] 74 | fn wit_import(_: i32, _: i32, ) -> i32; 75 | } 76 | 77 | #[cfg(not(target_arch = "wasm32"))] 78 | fn wit_import(_: i32, _: i32, ) -> i32{ unreachable!() } 79 | let ret = wit_import((self).handle() as i32, wit_bindgen::rt::as_i32(ns)); 80 | super::super::super::wasi::io::poll::Pollable::from_handle(ret as u32) 81 | } 82 | } 83 | } 84 | 85 | } 86 | 87 | 88 | #[allow(clippy::all)] 89 | pub mod digital { 90 | #[used] 91 | #[doc(hidden)] 92 | #[cfg(target_arch = "wasm32")] 93 | static __FORCE_SECTION_REF: fn() = super::super::super::__link_section; 94 | /// Operation errors. 95 | #[repr(u8)] 96 | #[derive(Clone, Copy, Eq, PartialEq)] 97 | pub enum ErrorCode { 98 | /// An error occurred. 99 | Other, 100 | } 101 | impl ErrorCode{ 102 | pub fn name(&self) -> &'static str { 103 | match self { 104 | ErrorCode::Other => "other", 105 | } 106 | } 107 | pub fn message(&self) -> &'static str { 108 | match self { 109 | ErrorCode::Other => "An error occurred.", 110 | } 111 | } 112 | } 113 | impl ::core::fmt::Debug for ErrorCode{ 114 | fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 115 | f.debug_struct("ErrorCode") 116 | .field("code", &(*self as i32)) 117 | .field("name", &self.name()) 118 | .field("message", &self.message()) 119 | .finish() 120 | } 121 | } 122 | impl ::core::fmt::Display for ErrorCode{ 123 | fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 124 | write!(f, "{} (error {})", self.name(), *self as i32) 125 | } 126 | } 127 | 128 | #[cfg(feature = "std")]impl std::error::Error for ErrorCode{} 129 | 130 | impl ErrorCode{ 131 | pub(crate) unsafe fn _lift(val: u8) -> ErrorCode{ 132 | if !cfg!(debug_assertions) { 133 | return ::core::mem::transmute(val); 134 | } 135 | 136 | match val { 137 | 0 => ErrorCode::Other, 138 | 139 | _ => panic!("invalid enum discriminant"), 140 | } 141 | } 142 | } 143 | 144 | /// Digital output pin state. 145 | #[repr(u8)] 146 | #[derive(Clone, Copy, Eq, PartialEq)] 147 | pub enum PinState { 148 | Low, 149 | High, 150 | } 151 | impl ::core::fmt::Debug for PinState { 152 | fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 153 | match self { 154 | PinState::Low => { 155 | f.debug_tuple("PinState::Low").finish() 156 | } 157 | PinState::High => { 158 | f.debug_tuple("PinState::High").finish() 159 | } 160 | } 161 | } 162 | } 163 | 164 | impl PinState{ 165 | pub(crate) unsafe fn _lift(val: u8) -> PinState{ 166 | if !cfg!(debug_assertions) { 167 | return ::core::mem::transmute(val); 168 | } 169 | 170 | match val { 171 | 0 => PinState::Low, 172 | 1 => PinState::High, 173 | 174 | _ => panic!("invalid enum discriminant"), 175 | } 176 | } 177 | } 178 | 179 | /// Single digital input pin. 180 | 181 | #[derive(Debug)] 182 | #[repr(transparent)] 183 | pub struct InputPin{ 184 | handle: wit_bindgen::rt::Resource, 185 | } 186 | 187 | impl InputPin{ 188 | #[doc(hidden)] 189 | pub unsafe fn from_handle(handle: u32) -> Self { 190 | Self { 191 | handle: wit_bindgen::rt::Resource::from_handle(handle), 192 | } 193 | } 194 | 195 | #[doc(hidden)] 196 | pub fn into_handle(self) -> u32 { 197 | wit_bindgen::rt::Resource::into_handle(self.handle) 198 | } 199 | 200 | #[doc(hidden)] 201 | pub fn handle(&self) -> u32 { 202 | wit_bindgen::rt::Resource::handle(&self.handle) 203 | } 204 | } 205 | 206 | 207 | unsafe impl wit_bindgen::rt::WasmResource for InputPin{ 208 | #[inline] 209 | unsafe fn drop(_handle: u32) { 210 | #[cfg(not(target_arch = "wasm32"))] 211 | unreachable!(); 212 | 213 | #[cfg(target_arch = "wasm32")] 214 | { 215 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 216 | extern "C" { 217 | #[link_name = "[resource-drop]input-pin"] 218 | fn drop(_: u32); 219 | } 220 | 221 | drop(_handle); 222 | } 223 | } 224 | } 225 | 226 | /// Single digital input pin. 227 | 228 | #[derive(Debug)] 229 | #[repr(transparent)] 230 | pub struct OutputPin{ 231 | handle: wit_bindgen::rt::Resource, 232 | } 233 | 234 | impl OutputPin{ 235 | #[doc(hidden)] 236 | pub unsafe fn from_handle(handle: u32) -> Self { 237 | Self { 238 | handle: wit_bindgen::rt::Resource::from_handle(handle), 239 | } 240 | } 241 | 242 | #[doc(hidden)] 243 | pub fn into_handle(self) -> u32 { 244 | wit_bindgen::rt::Resource::into_handle(self.handle) 245 | } 246 | 247 | #[doc(hidden)] 248 | pub fn handle(&self) -> u32 { 249 | wit_bindgen::rt::Resource::handle(&self.handle) 250 | } 251 | } 252 | 253 | 254 | unsafe impl wit_bindgen::rt::WasmResource for OutputPin{ 255 | #[inline] 256 | unsafe fn drop(_handle: u32) { 257 | #[cfg(not(target_arch = "wasm32"))] 258 | unreachable!(); 259 | 260 | #[cfg(target_arch = "wasm32")] 261 | { 262 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 263 | extern "C" { 264 | #[link_name = "[resource-drop]output-pin"] 265 | fn drop(_: u32); 266 | } 267 | 268 | drop(_handle); 269 | } 270 | } 271 | } 272 | 273 | /// Push-pull output pin that can read its output state. 274 | 275 | #[derive(Debug)] 276 | #[repr(transparent)] 277 | pub struct StatefulOutputPin{ 278 | handle: wit_bindgen::rt::Resource, 279 | } 280 | 281 | impl StatefulOutputPin{ 282 | #[doc(hidden)] 283 | pub unsafe fn from_handle(handle: u32) -> Self { 284 | Self { 285 | handle: wit_bindgen::rt::Resource::from_handle(handle), 286 | } 287 | } 288 | 289 | #[doc(hidden)] 290 | pub fn into_handle(self) -> u32 { 291 | wit_bindgen::rt::Resource::into_handle(self.handle) 292 | } 293 | 294 | #[doc(hidden)] 295 | pub fn handle(&self) -> u32 { 296 | wit_bindgen::rt::Resource::handle(&self.handle) 297 | } 298 | } 299 | 300 | 301 | unsafe impl wit_bindgen::rt::WasmResource for StatefulOutputPin{ 302 | #[inline] 303 | unsafe fn drop(_handle: u32) { 304 | #[cfg(not(target_arch = "wasm32"))] 305 | unreachable!(); 306 | 307 | #[cfg(target_arch = "wasm32")] 308 | { 309 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 310 | extern "C" { 311 | #[link_name = "[resource-drop]stateful-output-pin"] 312 | fn drop(_: u32); 313 | } 314 | 315 | drop(_handle); 316 | } 317 | } 318 | } 319 | 320 | impl InputPin { 321 | #[allow(unused_unsafe, clippy::all)] 322 | /// Is the input pin low? 323 | pub fn is_low(&self,) -> Result{ 324 | 325 | #[allow(unused_imports)] 326 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 327 | unsafe { 328 | 329 | #[repr(align(1))] 330 | struct RetArea([u8; 2]); 331 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 332 | let ptr0 = ret_area.as_mut_ptr() as i32; 333 | #[cfg(target_arch = "wasm32")] 334 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 335 | extern "C" { 336 | #[link_name = "[method]input-pin.is-low"] 337 | fn wit_import(_: i32, _: i32, ); 338 | } 339 | 340 | #[cfg(not(target_arch = "wasm32"))] 341 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 342 | wit_import((self).handle() as i32, ptr0); 343 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 344 | match l1 { 345 | 0 => { 346 | let e = { 347 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 348 | 349 | wit_bindgen::rt::bool_lift(l2 as u8) 350 | }; 351 | Ok(e) 352 | } 353 | 1 => { 354 | let e = { 355 | let l3 = i32::from(*((ptr0 + 1) as *const u8)); 356 | 357 | ErrorCode::_lift(l3 as u8) 358 | }; 359 | Err(e) 360 | } 361 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 362 | } 363 | } 364 | } 365 | } 366 | impl InputPin { 367 | #[allow(unused_unsafe, clippy::all)] 368 | /// Is the input pin high? 369 | pub fn is_high(&self,) -> Result{ 370 | 371 | #[allow(unused_imports)] 372 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 373 | unsafe { 374 | 375 | #[repr(align(1))] 376 | struct RetArea([u8; 2]); 377 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 378 | let ptr0 = ret_area.as_mut_ptr() as i32; 379 | #[cfg(target_arch = "wasm32")] 380 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 381 | extern "C" { 382 | #[link_name = "[method]input-pin.is-high"] 383 | fn wit_import(_: i32, _: i32, ); 384 | } 385 | 386 | #[cfg(not(target_arch = "wasm32"))] 387 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 388 | wit_import((self).handle() as i32, ptr0); 389 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 390 | match l1 { 391 | 0 => { 392 | let e = { 393 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 394 | 395 | wit_bindgen::rt::bool_lift(l2 as u8) 396 | }; 397 | Ok(e) 398 | } 399 | 1 => { 400 | let e = { 401 | let l3 = i32::from(*((ptr0 + 1) as *const u8)); 402 | 403 | ErrorCode::_lift(l3 as u8) 404 | }; 405 | Err(e) 406 | } 407 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 408 | } 409 | } 410 | } 411 | } 412 | impl InputPin { 413 | #[allow(unused_unsafe, clippy::all)] 414 | /// Wait until the pin is high. If it is already high, resolve 415 | /// immediately. 416 | pub fn wait_for_high(&self,) -> Result<(),ErrorCode>{ 417 | 418 | #[allow(unused_imports)] 419 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 420 | unsafe { 421 | 422 | #[repr(align(1))] 423 | struct RetArea([u8; 2]); 424 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 425 | let ptr0 = ret_area.as_mut_ptr() as i32; 426 | #[cfg(target_arch = "wasm32")] 427 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 428 | extern "C" { 429 | #[link_name = "[method]input-pin.wait-for-high"] 430 | fn wit_import(_: i32, _: i32, ); 431 | } 432 | 433 | #[cfg(not(target_arch = "wasm32"))] 434 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 435 | wit_import((self).handle() as i32, ptr0); 436 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 437 | match l1 { 438 | 0 => { 439 | let e = (); 440 | Ok(e) 441 | } 442 | 1 => { 443 | let e = { 444 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 445 | 446 | ErrorCode::_lift(l2 as u8) 447 | }; 448 | Err(e) 449 | } 450 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 451 | } 452 | } 453 | } 454 | } 455 | impl InputPin { 456 | #[allow(unused_unsafe, clippy::all)] 457 | /// Wait until the pin is low. If it is already low, resolve 458 | /// immediately. 459 | pub fn wait_for_low(&self,) -> Result<(),ErrorCode>{ 460 | 461 | #[allow(unused_imports)] 462 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 463 | unsafe { 464 | 465 | #[repr(align(1))] 466 | struct RetArea([u8; 2]); 467 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 468 | let ptr0 = ret_area.as_mut_ptr() as i32; 469 | #[cfg(target_arch = "wasm32")] 470 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 471 | extern "C" { 472 | #[link_name = "[method]input-pin.wait-for-low"] 473 | fn wit_import(_: i32, _: i32, ); 474 | } 475 | 476 | #[cfg(not(target_arch = "wasm32"))] 477 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 478 | wit_import((self).handle() as i32, ptr0); 479 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 480 | match l1 { 481 | 0 => { 482 | let e = (); 483 | Ok(e) 484 | } 485 | 1 => { 486 | let e = { 487 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 488 | 489 | ErrorCode::_lift(l2 as u8) 490 | }; 491 | Err(e) 492 | } 493 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 494 | } 495 | } 496 | } 497 | } 498 | impl InputPin { 499 | #[allow(unused_unsafe, clippy::all)] 500 | /// Wait for the pin to undergo a transition from low to high. 501 | /// 502 | /// If the pin is already high, this does *not* resolve immediately, 503 | /// it’ll wait for the pin to go low and then high again. 504 | pub fn wait_for_rising_edge(&self,) -> Result<(),ErrorCode>{ 505 | 506 | #[allow(unused_imports)] 507 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 508 | unsafe { 509 | 510 | #[repr(align(1))] 511 | struct RetArea([u8; 2]); 512 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 513 | let ptr0 = ret_area.as_mut_ptr() as i32; 514 | #[cfg(target_arch = "wasm32")] 515 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 516 | extern "C" { 517 | #[link_name = "[method]input-pin.wait-for-rising-edge"] 518 | fn wit_import(_: i32, _: i32, ); 519 | } 520 | 521 | #[cfg(not(target_arch = "wasm32"))] 522 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 523 | wit_import((self).handle() as i32, ptr0); 524 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 525 | match l1 { 526 | 0 => { 527 | let e = (); 528 | Ok(e) 529 | } 530 | 1 => { 531 | let e = { 532 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 533 | 534 | ErrorCode::_lift(l2 as u8) 535 | }; 536 | Err(e) 537 | } 538 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 539 | } 540 | } 541 | } 542 | } 543 | impl InputPin { 544 | #[allow(unused_unsafe, clippy::all)] 545 | /// Wait for the pin to undergo a transition from high to low. 546 | /// 547 | /// If the pin is already low, this does *not* return immediately, 548 | /// it’ll wait for the pin to go high and then low again. 549 | pub fn wait_for_falling_edge(&self,) -> Result<(),ErrorCode>{ 550 | 551 | #[allow(unused_imports)] 552 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 553 | unsafe { 554 | 555 | #[repr(align(1))] 556 | struct RetArea([u8; 2]); 557 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 558 | let ptr0 = ret_area.as_mut_ptr() as i32; 559 | #[cfg(target_arch = "wasm32")] 560 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 561 | extern "C" { 562 | #[link_name = "[method]input-pin.wait-for-falling-edge"] 563 | fn wit_import(_: i32, _: i32, ); 564 | } 565 | 566 | #[cfg(not(target_arch = "wasm32"))] 567 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 568 | wit_import((self).handle() as i32, ptr0); 569 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 570 | match l1 { 571 | 0 => { 572 | let e = (); 573 | Ok(e) 574 | } 575 | 1 => { 576 | let e = { 577 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 578 | 579 | ErrorCode::_lift(l2 as u8) 580 | }; 581 | Err(e) 582 | } 583 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 584 | } 585 | } 586 | } 587 | } 588 | impl InputPin { 589 | #[allow(unused_unsafe, clippy::all)] 590 | /// Wait for the pin to undergo any transition, i.e low to high OR high 591 | /// to low. 592 | pub fn wait_for_any_edge(&self,) -> Result<(),ErrorCode>{ 593 | 594 | #[allow(unused_imports)] 595 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 596 | unsafe { 597 | 598 | #[repr(align(1))] 599 | struct RetArea([u8; 2]); 600 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 601 | let ptr0 = ret_area.as_mut_ptr() as i32; 602 | #[cfg(target_arch = "wasm32")] 603 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 604 | extern "C" { 605 | #[link_name = "[method]input-pin.wait-for-any-edge"] 606 | fn wit_import(_: i32, _: i32, ); 607 | } 608 | 609 | #[cfg(not(target_arch = "wasm32"))] 610 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 611 | wit_import((self).handle() as i32, ptr0); 612 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 613 | match l1 { 614 | 0 => { 615 | let e = (); 616 | Ok(e) 617 | } 618 | 1 => { 619 | let e = { 620 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 621 | 622 | ErrorCode::_lift(l2 as u8) 623 | }; 624 | Err(e) 625 | } 626 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 627 | } 628 | } 629 | } 630 | } 631 | impl OutputPin { 632 | #[allow(unused_unsafe, clippy::all)] 633 | /// Drives the pin low. 634 | pub fn set_low(&self,) -> Result<(),ErrorCode>{ 635 | 636 | #[allow(unused_imports)] 637 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 638 | unsafe { 639 | 640 | #[repr(align(1))] 641 | struct RetArea([u8; 2]); 642 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 643 | let ptr0 = ret_area.as_mut_ptr() as i32; 644 | #[cfg(target_arch = "wasm32")] 645 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 646 | extern "C" { 647 | #[link_name = "[method]output-pin.set-low"] 648 | fn wit_import(_: i32, _: i32, ); 649 | } 650 | 651 | #[cfg(not(target_arch = "wasm32"))] 652 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 653 | wit_import((self).handle() as i32, ptr0); 654 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 655 | match l1 { 656 | 0 => { 657 | let e = (); 658 | Ok(e) 659 | } 660 | 1 => { 661 | let e = { 662 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 663 | 664 | ErrorCode::_lift(l2 as u8) 665 | }; 666 | Err(e) 667 | } 668 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 669 | } 670 | } 671 | } 672 | } 673 | impl OutputPin { 674 | #[allow(unused_unsafe, clippy::all)] 675 | /// Drives the pin high. 676 | pub fn set_high(&self,) -> Result<(),ErrorCode>{ 677 | 678 | #[allow(unused_imports)] 679 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 680 | unsafe { 681 | 682 | #[repr(align(1))] 683 | struct RetArea([u8; 2]); 684 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 685 | let ptr0 = ret_area.as_mut_ptr() as i32; 686 | #[cfg(target_arch = "wasm32")] 687 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 688 | extern "C" { 689 | #[link_name = "[method]output-pin.set-high"] 690 | fn wit_import(_: i32, _: i32, ); 691 | } 692 | 693 | #[cfg(not(target_arch = "wasm32"))] 694 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 695 | wit_import((self).handle() as i32, ptr0); 696 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 697 | match l1 { 698 | 0 => { 699 | let e = (); 700 | Ok(e) 701 | } 702 | 1 => { 703 | let e = { 704 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 705 | 706 | ErrorCode::_lift(l2 as u8) 707 | }; 708 | Err(e) 709 | } 710 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 711 | } 712 | } 713 | } 714 | } 715 | impl OutputPin { 716 | #[allow(unused_unsafe, clippy::all)] 717 | /// Drives the pin high or low depending on the provided value. 718 | pub fn set_state(&self,state: PinState,) -> Result<(),ErrorCode>{ 719 | 720 | #[allow(unused_imports)] 721 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 722 | unsafe { 723 | 724 | #[repr(align(1))] 725 | struct RetArea([u8; 2]); 726 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 727 | let ptr0 = ret_area.as_mut_ptr() as i32; 728 | #[cfg(target_arch = "wasm32")] 729 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 730 | extern "C" { 731 | #[link_name = "[method]output-pin.set-state"] 732 | fn wit_import(_: i32, _: i32, _: i32, ); 733 | } 734 | 735 | #[cfg(not(target_arch = "wasm32"))] 736 | fn wit_import(_: i32, _: i32, _: i32, ){ unreachable!() } 737 | wit_import((self).handle() as i32, state.clone() as i32, ptr0); 738 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 739 | match l1 { 740 | 0 => { 741 | let e = (); 742 | Ok(e) 743 | } 744 | 1 => { 745 | let e = { 746 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 747 | 748 | ErrorCode::_lift(l2 as u8) 749 | }; 750 | Err(e) 751 | } 752 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 753 | } 754 | } 755 | } 756 | } 757 | impl StatefulOutputPin { 758 | #[allow(unused_unsafe, clippy::all)] 759 | /// Is the pin in drive high mode? 760 | pub fn is_set_high(&self,) -> Result{ 761 | 762 | #[allow(unused_imports)] 763 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 764 | unsafe { 765 | 766 | #[repr(align(1))] 767 | struct RetArea([u8; 2]); 768 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 769 | let ptr0 = ret_area.as_mut_ptr() as i32; 770 | #[cfg(target_arch = "wasm32")] 771 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 772 | extern "C" { 773 | #[link_name = "[method]stateful-output-pin.is-set-high"] 774 | fn wit_import(_: i32, _: i32, ); 775 | } 776 | 777 | #[cfg(not(target_arch = "wasm32"))] 778 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 779 | wit_import((self).handle() as i32, ptr0); 780 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 781 | match l1 { 782 | 0 => { 783 | let e = { 784 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 785 | 786 | wit_bindgen::rt::bool_lift(l2 as u8) 787 | }; 788 | Ok(e) 789 | } 790 | 1 => { 791 | let e = { 792 | let l3 = i32::from(*((ptr0 + 1) as *const u8)); 793 | 794 | ErrorCode::_lift(l3 as u8) 795 | }; 796 | Err(e) 797 | } 798 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 799 | } 800 | } 801 | } 802 | } 803 | impl StatefulOutputPin { 804 | #[allow(unused_unsafe, clippy::all)] 805 | /// Is the pin in drive low mode? 806 | pub fn is_set_low(&self,) -> Result{ 807 | 808 | #[allow(unused_imports)] 809 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 810 | unsafe { 811 | 812 | #[repr(align(1))] 813 | struct RetArea([u8; 2]); 814 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 815 | let ptr0 = ret_area.as_mut_ptr() as i32; 816 | #[cfg(target_arch = "wasm32")] 817 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 818 | extern "C" { 819 | #[link_name = "[method]stateful-output-pin.is-set-low"] 820 | fn wit_import(_: i32, _: i32, ); 821 | } 822 | 823 | #[cfg(not(target_arch = "wasm32"))] 824 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 825 | wit_import((self).handle() as i32, ptr0); 826 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 827 | match l1 { 828 | 0 => { 829 | let e = { 830 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 831 | 832 | wit_bindgen::rt::bool_lift(l2 as u8) 833 | }; 834 | Ok(e) 835 | } 836 | 1 => { 837 | let e = { 838 | let l3 = i32::from(*((ptr0 + 1) as *const u8)); 839 | 840 | ErrorCode::_lift(l3 as u8) 841 | }; 842 | Err(e) 843 | } 844 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 845 | } 846 | } 847 | } 848 | } 849 | impl StatefulOutputPin { 850 | #[allow(unused_unsafe, clippy::all)] 851 | /// Toggle pin output. 852 | pub fn toggle(&self,) -> Result<(),ErrorCode>{ 853 | 854 | #[allow(unused_imports)] 855 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 856 | unsafe { 857 | 858 | #[repr(align(1))] 859 | struct RetArea([u8; 2]); 860 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 861 | let ptr0 = ret_area.as_mut_ptr() as i32; 862 | #[cfg(target_arch = "wasm32")] 863 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 864 | extern "C" { 865 | #[link_name = "[method]stateful-output-pin.toggle"] 866 | fn wit_import(_: i32, _: i32, ); 867 | } 868 | 869 | #[cfg(not(target_arch = "wasm32"))] 870 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 871 | wit_import((self).handle() as i32, ptr0); 872 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 873 | match l1 { 874 | 0 => { 875 | let e = (); 876 | Ok(e) 877 | } 878 | 1 => { 879 | let e = { 880 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 881 | 882 | ErrorCode::_lift(l2 as u8) 883 | }; 884 | Err(e) 885 | } 886 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 887 | } 888 | } 889 | } 890 | } 891 | 892 | } 893 | 894 | } 895 | } 896 | pub mod wasi { 897 | pub mod io { 898 | 899 | #[allow(clippy::all)] 900 | pub mod poll { 901 | #[used] 902 | #[doc(hidden)] 903 | #[cfg(target_arch = "wasm32")] 904 | static __FORCE_SECTION_REF: fn() = super::super::super::__link_section; 905 | /// `pollable` represents a single I/O event which may be ready, or not. 906 | 907 | #[derive(Debug)] 908 | #[repr(transparent)] 909 | pub struct Pollable{ 910 | handle: wit_bindgen::rt::Resource, 911 | } 912 | 913 | impl Pollable{ 914 | #[doc(hidden)] 915 | pub unsafe fn from_handle(handle: u32) -> Self { 916 | Self { 917 | handle: wit_bindgen::rt::Resource::from_handle(handle), 918 | } 919 | } 920 | 921 | #[doc(hidden)] 922 | pub fn into_handle(self) -> u32 { 923 | wit_bindgen::rt::Resource::into_handle(self.handle) 924 | } 925 | 926 | #[doc(hidden)] 927 | pub fn handle(&self) -> u32 { 928 | wit_bindgen::rt::Resource::handle(&self.handle) 929 | } 930 | } 931 | 932 | 933 | unsafe impl wit_bindgen::rt::WasmResource for Pollable{ 934 | #[inline] 935 | unsafe fn drop(_handle: u32) { 936 | #[cfg(not(target_arch = "wasm32"))] 937 | unreachable!(); 938 | 939 | #[cfg(target_arch = "wasm32")] 940 | { 941 | #[link(wasm_import_module = "wasi:io/poll@0.2.0")] 942 | extern "C" { 943 | #[link_name = "[resource-drop]pollable"] 944 | fn drop(_: u32); 945 | } 946 | 947 | drop(_handle); 948 | } 949 | } 950 | } 951 | 952 | impl Pollable { 953 | #[allow(unused_unsafe, clippy::all)] 954 | /// Return the readiness of a pollable. This function never blocks. 955 | /// 956 | /// Returns `true` when the pollable is ready, and `false` otherwise. 957 | pub fn ready(&self,) -> bool{ 958 | 959 | #[allow(unused_imports)] 960 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 961 | unsafe { 962 | 963 | #[cfg(target_arch = "wasm32")] 964 | #[link(wasm_import_module = "wasi:io/poll@0.2.0")] 965 | extern "C" { 966 | #[link_name = "[method]pollable.ready"] 967 | fn wit_import(_: i32, ) -> i32; 968 | } 969 | 970 | #[cfg(not(target_arch = "wasm32"))] 971 | fn wit_import(_: i32, ) -> i32{ unreachable!() } 972 | let ret = wit_import((self).handle() as i32); 973 | wit_bindgen::rt::bool_lift(ret as u8) 974 | } 975 | } 976 | } 977 | impl Pollable { 978 | #[allow(unused_unsafe, clippy::all)] 979 | /// `block` returns immediately if the pollable is ready, and otherwise 980 | /// blocks until ready. 981 | /// 982 | /// This function is equivalent to calling `poll.poll` on a list 983 | /// containing only this pollable. 984 | pub fn block(&self,){ 985 | 986 | #[allow(unused_imports)] 987 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 988 | unsafe { 989 | 990 | #[cfg(target_arch = "wasm32")] 991 | #[link(wasm_import_module = "wasi:io/poll@0.2.0")] 992 | extern "C" { 993 | #[link_name = "[method]pollable.block"] 994 | fn wit_import(_: i32, ); 995 | } 996 | 997 | #[cfg(not(target_arch = "wasm32"))] 998 | fn wit_import(_: i32, ){ unreachable!() } 999 | wit_import((self).handle() as i32); 1000 | } 1001 | } 1002 | } 1003 | #[allow(unused_unsafe, clippy::all)] 1004 | /// Poll for completion on a set of pollables. 1005 | /// 1006 | /// This function takes a list of pollables, which identify I/O sources of 1007 | /// interest, and waits until one or more of the events is ready for I/O. 1008 | /// 1009 | /// The result `list` contains one or more indices of handles in the 1010 | /// argument list that is ready for I/O. 1011 | /// 1012 | /// If the list contains more elements than can be indexed with a `u32` 1013 | /// value, this function traps. 1014 | /// 1015 | /// A timeout can be implemented by adding a pollable from the 1016 | /// wasi-clocks API to the list. 1017 | /// 1018 | /// This function does not return a `result`; polling in itself does not 1019 | /// do any I/O so it doesn't fail. If any of the I/O sources identified by 1020 | /// the pollables has an error, it is indicated by marking the source as 1021 | /// being reaedy for I/O. 1022 | pub fn poll(in_: &[&Pollable],) -> wit_bindgen::rt::vec::Vec::{ 1023 | 1024 | #[allow(unused_imports)] 1025 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 1026 | unsafe { 1027 | 1028 | #[repr(align(4))] 1029 | struct RetArea([u8; 8]); 1030 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 1031 | let vec0 = in_; 1032 | let len0 = vec0.len() as i32; 1033 | let layout0 = alloc::Layout::from_size_align_unchecked(vec0.len() * 4, 4); 1034 | let result0 = if layout0.size() != 0 1035 | { 1036 | let ptr = alloc::alloc(layout0); 1037 | if ptr.is_null() 1038 | { 1039 | alloc::handle_alloc_error(layout0); 1040 | } 1041 | ptr 1042 | }else {{ 1043 | ::core::ptr::null_mut() 1044 | }}; 1045 | for (i, e) in vec0.into_iter().enumerate() { 1046 | let base = result0 as i32 + (i as i32) * 4; 1047 | { 1048 | *((base + 0) as *mut i32) = (e).handle() as i32; 1049 | } 1050 | } 1051 | let ptr1 = ret_area.as_mut_ptr() as i32; 1052 | #[cfg(target_arch = "wasm32")] 1053 | #[link(wasm_import_module = "wasi:io/poll@0.2.0")] 1054 | extern "C" { 1055 | #[link_name = "poll"] 1056 | fn wit_import(_: i32, _: i32, _: i32, ); 1057 | } 1058 | 1059 | #[cfg(not(target_arch = "wasm32"))] 1060 | fn wit_import(_: i32, _: i32, _: i32, ){ unreachable!() } 1061 | wit_import(result0 as i32, len0, ptr1); 1062 | let l2 = *((ptr1 + 0) as *const i32); 1063 | let l3 = *((ptr1 + 4) as *const i32); 1064 | let len4 = l3 as usize; 1065 | if layout0.size() != 0 { 1066 | alloc::dealloc(result0, layout0); 1067 | } 1068 | Vec::from_raw_parts(l2 as *mut _, len4, len4) 1069 | } 1070 | } 1071 | 1072 | } 1073 | 1074 | } 1075 | } 1076 | pub mod exports { 1077 | pub mod sketch { 1078 | pub mod embedded { 1079 | 1080 | #[allow(clippy::all)] 1081 | pub mod async_run { 1082 | #[used] 1083 | #[doc(hidden)] 1084 | #[cfg(target_arch = "wasm32")] 1085 | static __FORCE_SECTION_REF: fn() = super::super::super::super::__link_section; 1086 | pub type OutputPin = super::super::super::super::sketch::embedded::digital::OutputPin; 1087 | pub type Delay = super::super::super::super::sketch::embedded::async_delay::Delay; 1088 | const _: () = { 1089 | 1090 | #[doc(hidden)] 1091 | #[export_name = "sketch:embedded/async-run@0.0.0#run"] 1092 | #[allow(non_snake_case)] 1093 | unsafe extern "C" fn __export_run(arg0: i32,arg1: i32,arg2: i32,) { 1094 | #[allow(unused_imports)] 1095 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 1096 | 1097 | // Before executing any other code, use this function to run all static 1098 | // constructors, if they have not yet been run. This is a hack required 1099 | // to work around wasi-libc ctors calling import functions to initialize 1100 | // the environment. 1101 | // 1102 | // This functionality will be removed once rust 1.69.0 is stable, at which 1103 | // point wasi-libc will no longer have this behavior. 1104 | // 1105 | // See 1106 | // https://github.com/bytecodealliance/preview2-prototyping/issues/99 1107 | // for more details. 1108 | #[cfg(target_arch="wasm32")] 1109 | wit_bindgen::rt::run_ctors_once(); 1110 | 1111 | <_GuestImpl as Guest>::run(super::super::super::super::sketch::embedded::digital::OutputPin::from_handle(arg0 as u32), super::super::super::super::sketch::embedded::digital::OutputPin::from_handle(arg1 as u32), super::super::super::super::sketch::embedded::async_delay::Delay::from_handle(arg2 as u32)); 1112 | } 1113 | }; 1114 | use super::super::super::super::super::Component as _GuestImpl; 1115 | pub trait Guest { 1116 | /// Start the program, with an output pin and a delay mechanism. 1117 | fn run(led0: OutputPin,led1: OutputPin,delay: Delay,); 1118 | } 1119 | 1120 | } 1121 | 1122 | } 1123 | } 1124 | } 1125 | 1126 | #[cfg(target_arch = "wasm32")] 1127 | #[link_section = "component-type:async-blink"] 1128 | #[doc(hidden)] 1129 | pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 1312] = [0, 97, 115, 109, 13, 0, 1, 0, 0, 25, 22, 119, 105, 116, 45, 99, 111, 109, 112, 111, 110, 101, 110, 116, 45, 101, 110, 99, 111, 100, 105, 110, 103, 4, 0, 7, 159, 9, 1, 65, 2, 1, 65, 11, 1, 66, 10, 4, 0, 8, 112, 111, 108, 108, 97, 98, 108, 101, 3, 1, 1, 104, 0, 1, 64, 1, 4, 115, 101, 108, 102, 1, 0, 127, 4, 0, 22, 91, 109, 101, 116, 104, 111, 100, 93, 112, 111, 108, 108, 97, 98, 108, 101, 46, 114, 101, 97, 100, 121, 1, 2, 1, 64, 1, 4, 115, 101, 108, 102, 1, 1, 0, 4, 0, 22, 91, 109, 101, 116, 104, 111, 100, 93, 112, 111, 108, 108, 97, 98, 108, 101, 46, 98, 108, 111, 99, 107, 1, 3, 1, 112, 1, 1, 112, 121, 1, 64, 1, 2, 105, 110, 4, 0, 5, 4, 0, 4, 112, 111, 108, 108, 1, 6, 3, 1, 18, 119, 97, 115, 105, 58, 105, 111, 47, 112, 111, 108, 108, 64, 48, 46, 50, 46, 48, 5, 0, 2, 3, 0, 0, 8, 112, 111, 108, 108, 97, 98, 108, 101, 1, 66, 7, 2, 3, 2, 1, 1, 4, 0, 8, 112, 111, 108, 108, 97, 98, 108, 101, 3, 0, 0, 4, 0, 5, 100, 101, 108, 97, 121, 3, 1, 1, 104, 2, 1, 105, 1, 1, 64, 2, 4, 115, 101, 108, 102, 3, 2, 110, 115, 121, 0, 4, 4, 0, 35, 91, 109, 101, 116, 104, 111, 100, 93, 100, 101, 108, 97, 121, 46, 115, 117, 98, 115, 99, 114, 105, 98, 101, 45, 116, 111, 45, 100, 101, 108, 97, 121, 45, 110, 115, 1, 5, 3, 1, 33, 115, 107, 101, 116, 99, 104, 58, 101, 109, 98, 101, 100, 100, 101, 100, 47, 97, 115, 121, 110, 99, 45, 100, 101, 108, 97, 121, 64, 48, 46, 48, 46, 48, 5, 2, 1, 66, 31, 1, 109, 1, 5, 111, 116, 104, 101, 114, 4, 0, 10, 101, 114, 114, 111, 114, 45, 99, 111, 100, 101, 3, 0, 0, 1, 109, 2, 3, 108, 111, 119, 4, 104, 105, 103, 104, 4, 0, 9, 112, 105, 110, 45, 115, 116, 97, 116, 101, 3, 0, 2, 4, 0, 9, 105, 110, 112, 117, 116, 45, 112, 105, 110, 3, 1, 4, 0, 10, 111, 117, 116, 112, 117, 116, 45, 112, 105, 110, 3, 1, 4, 0, 19, 115, 116, 97, 116, 101, 102, 117, 108, 45, 111, 117, 116, 112, 117, 116, 45, 112, 105, 110, 3, 1, 1, 104, 4, 1, 106, 1, 127, 1, 1, 1, 64, 1, 4, 115, 101, 108, 102, 7, 0, 8, 4, 0, 24, 91, 109, 101, 116, 104, 111, 100, 93, 105, 110, 112, 117, 116, 45, 112, 105, 110, 46, 105, 115, 45, 108, 111, 119, 1, 9, 4, 0, 25, 91, 109, 101, 116, 104, 111, 100, 93, 105, 110, 112, 117, 116, 45, 112, 105, 110, 46, 105, 115, 45, 104, 105, 103, 104, 1, 9, 1, 106, 0, 1, 1, 1, 64, 1, 4, 115, 101, 108, 102, 7, 0, 10, 4, 0, 31, 91, 109, 101, 116, 104, 111, 100, 93, 105, 110, 112, 117, 116, 45, 112, 105, 110, 46, 119, 97, 105, 116, 45, 102, 111, 114, 45, 104, 105, 103, 104, 1, 11, 4, 0, 30, 91, 109, 101, 116, 104, 111, 100, 93, 105, 110, 112, 117, 116, 45, 112, 105, 110, 46, 119, 97, 105, 116, 45, 102, 111, 114, 45, 108, 111, 119, 1, 11, 4, 0, 38, 91, 109, 101, 116, 104, 111, 100, 93, 105, 110, 112, 117, 116, 45, 112, 105, 110, 46, 119, 97, 105, 116, 45, 102, 111, 114, 45, 114, 105, 115, 105, 110, 103, 45, 101, 100, 103, 101, 1, 11, 4, 0, 39, 91, 109, 101, 116, 104, 111, 100, 93, 105, 110, 112, 117, 116, 45, 112, 105, 110, 46, 119, 97, 105, 116, 45, 102, 111, 114, 45, 102, 97, 108, 108, 105, 110, 103, 45, 101, 100, 103, 101, 1, 11, 4, 0, 35, 91, 109, 101, 116, 104, 111, 100, 93, 105, 110, 112, 117, 116, 45, 112, 105, 110, 46, 119, 97, 105, 116, 45, 102, 111, 114, 45, 97, 110, 121, 45, 101, 100, 103, 101, 1, 11, 1, 104, 5, 1, 64, 1, 4, 115, 101, 108, 102, 12, 0, 10, 4, 0, 26, 91, 109, 101, 116, 104, 111, 100, 93, 111, 117, 116, 112, 117, 116, 45, 112, 105, 110, 46, 115, 101, 116, 45, 108, 111, 119, 1, 13, 4, 0, 27, 91, 109, 101, 116, 104, 111, 100, 93, 111, 117, 116, 112, 117, 116, 45, 112, 105, 110, 46, 115, 101, 116, 45, 104, 105, 103, 104, 1, 13, 1, 64, 2, 4, 115, 101, 108, 102, 12, 5, 115, 116, 97, 116, 101, 3, 0, 10, 4, 0, 28, 91, 109, 101, 116, 104, 111, 100, 93, 111, 117, 116, 112, 117, 116, 45, 112, 105, 110, 46, 115, 101, 116, 45, 115, 116, 97, 116, 101, 1, 14, 1, 104, 6, 1, 64, 1, 4, 115, 101, 108, 102, 15, 0, 8, 4, 0, 39, 91, 109, 101, 116, 104, 111, 100, 93, 115, 116, 97, 116, 101, 102, 117, 108, 45, 111, 117, 116, 112, 117, 116, 45, 112, 105, 110, 46, 105, 115, 45, 115, 101, 116, 45, 104, 105, 103, 104, 1, 16, 4, 0, 38, 91, 109, 101, 116, 104, 111, 100, 93, 115, 116, 97, 116, 101, 102, 117, 108, 45, 111, 117, 116, 112, 117, 116, 45, 112, 105, 110, 46, 105, 115, 45, 115, 101, 116, 45, 108, 111, 119, 1, 16, 1, 64, 1, 4, 115, 101, 108, 102, 15, 0, 10, 4, 0, 34, 91, 109, 101, 116, 104, 111, 100, 93, 115, 116, 97, 116, 101, 102, 117, 108, 45, 111, 117, 116, 112, 117, 116, 45, 112, 105, 110, 46, 116, 111, 103, 103, 108, 101, 1, 17, 3, 1, 29, 115, 107, 101, 116, 99, 104, 58, 101, 109, 98, 101, 100, 100, 101, 100, 47, 100, 105, 103, 105, 116, 97, 108, 64, 48, 46, 48, 46, 48, 5, 3, 2, 3, 0, 2, 10, 111, 117, 116, 112, 117, 116, 45, 112, 105, 110, 2, 3, 0, 1, 5, 100, 101, 108, 97, 121, 1, 66, 8, 2, 3, 2, 1, 4, 4, 0, 10, 111, 117, 116, 112, 117, 116, 45, 112, 105, 110, 3, 0, 0, 2, 3, 2, 1, 5, 4, 0, 5, 100, 101, 108, 97, 121, 3, 0, 2, 1, 105, 1, 1, 105, 3, 1, 64, 3, 4, 108, 101, 100, 48, 4, 4, 108, 101, 100, 49, 4, 5, 100, 101, 108, 97, 121, 5, 1, 0, 4, 0, 3, 114, 117, 110, 1, 6, 4, 1, 31, 115, 107, 101, 116, 99, 104, 58, 101, 109, 98, 101, 100, 100, 101, 100, 47, 97, 115, 121, 110, 99, 45, 114, 117, 110, 64, 48, 46, 48, 46, 48, 5, 6, 4, 1, 33, 115, 107, 101, 116, 99, 104, 58, 101, 109, 98, 101, 100, 100, 101, 100, 47, 97, 115, 121, 110, 99, 45, 98, 108, 105, 110, 107, 64, 48, 46, 48, 46, 48, 4, 0, 11, 17, 1, 0, 11, 97, 115, 121, 110, 99, 45, 98, 108, 105, 110, 107, 3, 0, 0, 0, 70, 9, 112, 114, 111, 100, 117, 99, 101, 114, 115, 1, 12, 112, 114, 111, 99, 101, 115, 115, 101, 100, 45, 98, 121, 2, 13, 119, 105, 116, 45, 99, 111, 109, 112, 111, 110, 101, 110, 116, 6, 48, 46, 50, 49, 46, 48, 16, 119, 105, 116, 45, 98, 105, 110, 100, 103, 101, 110, 45, 114, 117, 115, 116, 6, 48, 46, 49, 56, 46, 48]; 1130 | 1131 | #[inline(never)] 1132 | #[doc(hidden)] 1133 | #[cfg(target_arch = "wasm32")] 1134 | pub fn __link_section() {} 1135 | -------------------------------------------------------------------------------- /async-guest/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use wasi_async_runtime::{block_on, Reactor}; 5 | 6 | // Import the types from the bindings that we use. 7 | use crate::bindings::exports::sketch::embedded::async_run::Guest; 8 | use crate::bindings::sketch::embedded::async_delay::Delay; 9 | use crate::bindings::sketch::embedded::digital::OutputPin; 10 | use wasi::io::poll::Pollable; 11 | use futures_util::join; 12 | use lol_alloc::{AssumeSingleThreaded, FreeListAllocator}; 13 | 14 | mod bindings; 15 | 16 | struct Component; 17 | 18 | /// This is the main implementation code. 19 | impl Guest for Component { 20 | fn run(pin0: OutputPin, pin1: OutputPin, delay: Delay) { 21 | block_on(|reactor| async move { 22 | let a = blink(1_000_000_000, pin0, &delay, &reactor); 23 | let b = blink(300_000_00, pin1, &delay, &reactor); 24 | join!(a, b); 25 | }) 26 | } 27 | } 28 | 29 | async fn blink(ns: u32, pin: OutputPin, delay: &Delay, reactor: &Reactor) { 30 | loop { 31 | pin.set_high().ok(); 32 | 33 | let pollable = delay.subscribe_to_delay_ns(ns); 34 | let pollable = unsafe { Pollable::from_handle(pollable.into_handle()) }; 35 | reactor.wait_for(pollable).await; 36 | 37 | pin.set_low().ok(); 38 | 39 | let pollable = delay.subscribe_to_delay_ns(ns); 40 | let pollable = unsafe { Pollable::from_handle(pollable.into_handle()) }; 41 | reactor.wait_for(pollable).await; 42 | } 43 | } 44 | 45 | /// Define a global allocator, since we're using `no_std`. 46 | /// SAFETY: We're single-threaded. 47 | #[global_allocator] 48 | static GLOBAL_ALLOCATOR: AssumeSingleThreaded = 49 | unsafe { AssumeSingleThreaded::new(FreeListAllocator::new()) }; 50 | 51 | /// Define a panic handler, since we're using `no_std`. Just infloop for 52 | /// now and hope we don't panic. 53 | #[panic_handler] 54 | fn panic(_panic: &core::panic::PanicInfo<'_>) -> ! { 55 | // Don't panic ;-). 56 | loop {} 57 | } 58 | -------------------------------------------------------------------------------- /guest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-embedded" 3 | version = "0.0.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | lol_alloc = "0.4.1" 12 | wit-bindgen = { version = "0.18.0", default-features = false, features = ["realloc"] } 13 | compiler_builtins = { version = "0.1.108", features = ["mem"] } 14 | 15 | [package.metadata.component] 16 | # We don't need an adapter, but cargo-component doesn't yet have an option to 17 | # disable the adapter. As a workaround, use an empty adapter. 18 | adapter = "empty.wasm" 19 | 20 | [package.metadata.component.target] 21 | path = "../wit" 22 | world = "blink" 23 | 24 | [package.metadata.component.target.dependencies] 25 | # The async interfaces depend on wasi-io. 26 | "wasi:io" = { path = "../wit/deps/io" } 27 | 28 | [package.metadata.component.bindings] 29 | # Enable this to put `std` usage behind a feature, so that we can use `no_std`. 30 | std_feature = true 31 | 32 | [profile.release] 33 | # Strip out debug info to produce a small component. 34 | strip = true 35 | -------------------------------------------------------------------------------- /guest/empty.wasm: -------------------------------------------------------------------------------- 1 | asm -------------------------------------------------------------------------------- /guest/empty.wat: -------------------------------------------------------------------------------- 1 | (module) 2 | -------------------------------------------------------------------------------- /guest/src/bindings.rs: -------------------------------------------------------------------------------- 1 | // Generated by `wit-bindgen` 0.18.0. DO NOT EDIT! 2 | pub mod sketch { 3 | pub mod embedded { 4 | 5 | #[allow(clippy::all)] 6 | pub mod delay { 7 | #[used] 8 | #[doc(hidden)] 9 | #[cfg(target_arch = "wasm32")] 10 | static __FORCE_SECTION_REF: fn() = super::super::super::__link_section; 11 | /// Delay with up to nanosecond precision. 12 | 13 | #[derive(Debug)] 14 | #[repr(transparent)] 15 | pub struct Delay{ 16 | handle: wit_bindgen::rt::Resource, 17 | } 18 | 19 | impl Delay{ 20 | #[doc(hidden)] 21 | pub unsafe fn from_handle(handle: u32) -> Self { 22 | Self { 23 | handle: wit_bindgen::rt::Resource::from_handle(handle), 24 | } 25 | } 26 | 27 | #[doc(hidden)] 28 | pub fn into_handle(self) -> u32 { 29 | wit_bindgen::rt::Resource::into_handle(self.handle) 30 | } 31 | 32 | #[doc(hidden)] 33 | pub fn handle(&self) -> u32 { 34 | wit_bindgen::rt::Resource::handle(&self.handle) 35 | } 36 | } 37 | 38 | 39 | unsafe impl wit_bindgen::rt::WasmResource for Delay{ 40 | #[inline] 41 | unsafe fn drop(_handle: u32) { 42 | #[cfg(not(target_arch = "wasm32"))] 43 | unreachable!(); 44 | 45 | #[cfg(target_arch = "wasm32")] 46 | { 47 | #[link(wasm_import_module = "sketch:embedded/delay@0.0.0")] 48 | extern "C" { 49 | #[link_name = "[resource-drop]delay"] 50 | fn drop(_: u32); 51 | } 52 | 53 | drop(_handle); 54 | } 55 | } 56 | } 57 | 58 | impl Delay { 59 | #[allow(unused_unsafe, clippy::all)] 60 | /// Pauses execution for at minimum `ns` nanoseconds. Pause can be 61 | /// longer if the implementation requires it due to precision/timing 62 | /// issues. 63 | pub fn delay_ns(&self,ns: u32,){ 64 | 65 | #[allow(unused_imports)] 66 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 67 | unsafe { 68 | 69 | #[cfg(target_arch = "wasm32")] 70 | #[link(wasm_import_module = "sketch:embedded/delay@0.0.0")] 71 | extern "C" { 72 | #[link_name = "[method]delay.delay-ns"] 73 | fn wit_import(_: i32, _: i32, ); 74 | } 75 | 76 | #[cfg(not(target_arch = "wasm32"))] 77 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 78 | wit_import((self).handle() as i32, wit_bindgen::rt::as_i32(ns)); 79 | } 80 | } 81 | } 82 | 83 | } 84 | 85 | 86 | #[allow(clippy::all)] 87 | pub mod digital { 88 | #[used] 89 | #[doc(hidden)] 90 | #[cfg(target_arch = "wasm32")] 91 | static __FORCE_SECTION_REF: fn() = super::super::super::__link_section; 92 | /// Operation errors. 93 | #[repr(u8)] 94 | #[derive(Clone, Copy, Eq, PartialEq)] 95 | pub enum ErrorCode { 96 | /// An error occurred. 97 | Other, 98 | } 99 | impl ErrorCode{ 100 | pub fn name(&self) -> &'static str { 101 | match self { 102 | ErrorCode::Other => "other", 103 | } 104 | } 105 | pub fn message(&self) -> &'static str { 106 | match self { 107 | ErrorCode::Other => "An error occurred.", 108 | } 109 | } 110 | } 111 | impl ::core::fmt::Debug for ErrorCode{ 112 | fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 113 | f.debug_struct("ErrorCode") 114 | .field("code", &(*self as i32)) 115 | .field("name", &self.name()) 116 | .field("message", &self.message()) 117 | .finish() 118 | } 119 | } 120 | impl ::core::fmt::Display for ErrorCode{ 121 | fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 122 | write!(f, "{} (error {})", self.name(), *self as i32) 123 | } 124 | } 125 | 126 | #[cfg(feature = "std")]impl std::error::Error for ErrorCode{} 127 | 128 | impl ErrorCode{ 129 | pub(crate) unsafe fn _lift(val: u8) -> ErrorCode{ 130 | if !cfg!(debug_assertions) { 131 | return ::core::mem::transmute(val); 132 | } 133 | 134 | match val { 135 | 0 => ErrorCode::Other, 136 | 137 | _ => panic!("invalid enum discriminant"), 138 | } 139 | } 140 | } 141 | 142 | /// Digital output pin state. 143 | #[repr(u8)] 144 | #[derive(Clone, Copy, Eq, PartialEq)] 145 | pub enum PinState { 146 | Low, 147 | High, 148 | } 149 | impl ::core::fmt::Debug for PinState { 150 | fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 151 | match self { 152 | PinState::Low => { 153 | f.debug_tuple("PinState::Low").finish() 154 | } 155 | PinState::High => { 156 | f.debug_tuple("PinState::High").finish() 157 | } 158 | } 159 | } 160 | } 161 | 162 | impl PinState{ 163 | pub(crate) unsafe fn _lift(val: u8) -> PinState{ 164 | if !cfg!(debug_assertions) { 165 | return ::core::mem::transmute(val); 166 | } 167 | 168 | match val { 169 | 0 => PinState::Low, 170 | 1 => PinState::High, 171 | 172 | _ => panic!("invalid enum discriminant"), 173 | } 174 | } 175 | } 176 | 177 | /// Single digital input pin. 178 | 179 | #[derive(Debug)] 180 | #[repr(transparent)] 181 | pub struct InputPin{ 182 | handle: wit_bindgen::rt::Resource, 183 | } 184 | 185 | impl InputPin{ 186 | #[doc(hidden)] 187 | pub unsafe fn from_handle(handle: u32) -> Self { 188 | Self { 189 | handle: wit_bindgen::rt::Resource::from_handle(handle), 190 | } 191 | } 192 | 193 | #[doc(hidden)] 194 | pub fn into_handle(self) -> u32 { 195 | wit_bindgen::rt::Resource::into_handle(self.handle) 196 | } 197 | 198 | #[doc(hidden)] 199 | pub fn handle(&self) -> u32 { 200 | wit_bindgen::rt::Resource::handle(&self.handle) 201 | } 202 | } 203 | 204 | 205 | unsafe impl wit_bindgen::rt::WasmResource for InputPin{ 206 | #[inline] 207 | unsafe fn drop(_handle: u32) { 208 | #[cfg(not(target_arch = "wasm32"))] 209 | unreachable!(); 210 | 211 | #[cfg(target_arch = "wasm32")] 212 | { 213 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 214 | extern "C" { 215 | #[link_name = "[resource-drop]input-pin"] 216 | fn drop(_: u32); 217 | } 218 | 219 | drop(_handle); 220 | } 221 | } 222 | } 223 | 224 | /// Single digital input pin. 225 | 226 | #[derive(Debug)] 227 | #[repr(transparent)] 228 | pub struct OutputPin{ 229 | handle: wit_bindgen::rt::Resource, 230 | } 231 | 232 | impl OutputPin{ 233 | #[doc(hidden)] 234 | pub unsafe fn from_handle(handle: u32) -> Self { 235 | Self { 236 | handle: wit_bindgen::rt::Resource::from_handle(handle), 237 | } 238 | } 239 | 240 | #[doc(hidden)] 241 | pub fn into_handle(self) -> u32 { 242 | wit_bindgen::rt::Resource::into_handle(self.handle) 243 | } 244 | 245 | #[doc(hidden)] 246 | pub fn handle(&self) -> u32 { 247 | wit_bindgen::rt::Resource::handle(&self.handle) 248 | } 249 | } 250 | 251 | 252 | unsafe impl wit_bindgen::rt::WasmResource for OutputPin{ 253 | #[inline] 254 | unsafe fn drop(_handle: u32) { 255 | #[cfg(not(target_arch = "wasm32"))] 256 | unreachable!(); 257 | 258 | #[cfg(target_arch = "wasm32")] 259 | { 260 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 261 | extern "C" { 262 | #[link_name = "[resource-drop]output-pin"] 263 | fn drop(_: u32); 264 | } 265 | 266 | drop(_handle); 267 | } 268 | } 269 | } 270 | 271 | /// Push-pull output pin that can read its output state. 272 | 273 | #[derive(Debug)] 274 | #[repr(transparent)] 275 | pub struct StatefulOutputPin{ 276 | handle: wit_bindgen::rt::Resource, 277 | } 278 | 279 | impl StatefulOutputPin{ 280 | #[doc(hidden)] 281 | pub unsafe fn from_handle(handle: u32) -> Self { 282 | Self { 283 | handle: wit_bindgen::rt::Resource::from_handle(handle), 284 | } 285 | } 286 | 287 | #[doc(hidden)] 288 | pub fn into_handle(self) -> u32 { 289 | wit_bindgen::rt::Resource::into_handle(self.handle) 290 | } 291 | 292 | #[doc(hidden)] 293 | pub fn handle(&self) -> u32 { 294 | wit_bindgen::rt::Resource::handle(&self.handle) 295 | } 296 | } 297 | 298 | 299 | unsafe impl wit_bindgen::rt::WasmResource for StatefulOutputPin{ 300 | #[inline] 301 | unsafe fn drop(_handle: u32) { 302 | #[cfg(not(target_arch = "wasm32"))] 303 | unreachable!(); 304 | 305 | #[cfg(target_arch = "wasm32")] 306 | { 307 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 308 | extern "C" { 309 | #[link_name = "[resource-drop]stateful-output-pin"] 310 | fn drop(_: u32); 311 | } 312 | 313 | drop(_handle); 314 | } 315 | } 316 | } 317 | 318 | impl InputPin { 319 | #[allow(unused_unsafe, clippy::all)] 320 | /// Is the input pin low? 321 | pub fn is_low(&self,) -> Result{ 322 | 323 | #[allow(unused_imports)] 324 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 325 | unsafe { 326 | 327 | #[repr(align(1))] 328 | struct RetArea([u8; 2]); 329 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 330 | let ptr0 = ret_area.as_mut_ptr() as i32; 331 | #[cfg(target_arch = "wasm32")] 332 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 333 | extern "C" { 334 | #[link_name = "[method]input-pin.is-low"] 335 | fn wit_import(_: i32, _: i32, ); 336 | } 337 | 338 | #[cfg(not(target_arch = "wasm32"))] 339 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 340 | wit_import((self).handle() as i32, ptr0); 341 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 342 | match l1 { 343 | 0 => { 344 | let e = { 345 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 346 | 347 | wit_bindgen::rt::bool_lift(l2 as u8) 348 | }; 349 | Ok(e) 350 | } 351 | 1 => { 352 | let e = { 353 | let l3 = i32::from(*((ptr0 + 1) as *const u8)); 354 | 355 | ErrorCode::_lift(l3 as u8) 356 | }; 357 | Err(e) 358 | } 359 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 360 | } 361 | } 362 | } 363 | } 364 | impl InputPin { 365 | #[allow(unused_unsafe, clippy::all)] 366 | /// Is the input pin high? 367 | pub fn is_high(&self,) -> Result{ 368 | 369 | #[allow(unused_imports)] 370 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 371 | unsafe { 372 | 373 | #[repr(align(1))] 374 | struct RetArea([u8; 2]); 375 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 376 | let ptr0 = ret_area.as_mut_ptr() as i32; 377 | #[cfg(target_arch = "wasm32")] 378 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 379 | extern "C" { 380 | #[link_name = "[method]input-pin.is-high"] 381 | fn wit_import(_: i32, _: i32, ); 382 | } 383 | 384 | #[cfg(not(target_arch = "wasm32"))] 385 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 386 | wit_import((self).handle() as i32, ptr0); 387 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 388 | match l1 { 389 | 0 => { 390 | let e = { 391 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 392 | 393 | wit_bindgen::rt::bool_lift(l2 as u8) 394 | }; 395 | Ok(e) 396 | } 397 | 1 => { 398 | let e = { 399 | let l3 = i32::from(*((ptr0 + 1) as *const u8)); 400 | 401 | ErrorCode::_lift(l3 as u8) 402 | }; 403 | Err(e) 404 | } 405 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 406 | } 407 | } 408 | } 409 | } 410 | impl InputPin { 411 | #[allow(unused_unsafe, clippy::all)] 412 | /// Wait until the pin is high. If it is already high, resolve 413 | /// immediately. 414 | pub fn wait_for_high(&self,) -> Result<(),ErrorCode>{ 415 | 416 | #[allow(unused_imports)] 417 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 418 | unsafe { 419 | 420 | #[repr(align(1))] 421 | struct RetArea([u8; 2]); 422 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 423 | let ptr0 = ret_area.as_mut_ptr() as i32; 424 | #[cfg(target_arch = "wasm32")] 425 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 426 | extern "C" { 427 | #[link_name = "[method]input-pin.wait-for-high"] 428 | fn wit_import(_: i32, _: i32, ); 429 | } 430 | 431 | #[cfg(not(target_arch = "wasm32"))] 432 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 433 | wit_import((self).handle() as i32, ptr0); 434 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 435 | match l1 { 436 | 0 => { 437 | let e = (); 438 | Ok(e) 439 | } 440 | 1 => { 441 | let e = { 442 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 443 | 444 | ErrorCode::_lift(l2 as u8) 445 | }; 446 | Err(e) 447 | } 448 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 449 | } 450 | } 451 | } 452 | } 453 | impl InputPin { 454 | #[allow(unused_unsafe, clippy::all)] 455 | /// Wait until the pin is low. If it is already low, resolve 456 | /// immediately. 457 | pub fn wait_for_low(&self,) -> Result<(),ErrorCode>{ 458 | 459 | #[allow(unused_imports)] 460 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 461 | unsafe { 462 | 463 | #[repr(align(1))] 464 | struct RetArea([u8; 2]); 465 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 466 | let ptr0 = ret_area.as_mut_ptr() as i32; 467 | #[cfg(target_arch = "wasm32")] 468 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 469 | extern "C" { 470 | #[link_name = "[method]input-pin.wait-for-low"] 471 | fn wit_import(_: i32, _: i32, ); 472 | } 473 | 474 | #[cfg(not(target_arch = "wasm32"))] 475 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 476 | wit_import((self).handle() as i32, ptr0); 477 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 478 | match l1 { 479 | 0 => { 480 | let e = (); 481 | Ok(e) 482 | } 483 | 1 => { 484 | let e = { 485 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 486 | 487 | ErrorCode::_lift(l2 as u8) 488 | }; 489 | Err(e) 490 | } 491 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 492 | } 493 | } 494 | } 495 | } 496 | impl InputPin { 497 | #[allow(unused_unsafe, clippy::all)] 498 | /// Wait for the pin to undergo a transition from low to high. 499 | /// 500 | /// If the pin is already high, this does *not* resolve immediately, 501 | /// it’ll wait for the pin to go low and then high again. 502 | pub fn wait_for_rising_edge(&self,) -> Result<(),ErrorCode>{ 503 | 504 | #[allow(unused_imports)] 505 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 506 | unsafe { 507 | 508 | #[repr(align(1))] 509 | struct RetArea([u8; 2]); 510 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 511 | let ptr0 = ret_area.as_mut_ptr() as i32; 512 | #[cfg(target_arch = "wasm32")] 513 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 514 | extern "C" { 515 | #[link_name = "[method]input-pin.wait-for-rising-edge"] 516 | fn wit_import(_: i32, _: i32, ); 517 | } 518 | 519 | #[cfg(not(target_arch = "wasm32"))] 520 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 521 | wit_import((self).handle() as i32, ptr0); 522 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 523 | match l1 { 524 | 0 => { 525 | let e = (); 526 | Ok(e) 527 | } 528 | 1 => { 529 | let e = { 530 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 531 | 532 | ErrorCode::_lift(l2 as u8) 533 | }; 534 | Err(e) 535 | } 536 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 537 | } 538 | } 539 | } 540 | } 541 | impl InputPin { 542 | #[allow(unused_unsafe, clippy::all)] 543 | /// Wait for the pin to undergo a transition from high to low. 544 | /// 545 | /// If the pin is already low, this does *not* return immediately, 546 | /// it’ll wait for the pin to go high and then low again. 547 | pub fn wait_for_falling_edge(&self,) -> Result<(),ErrorCode>{ 548 | 549 | #[allow(unused_imports)] 550 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 551 | unsafe { 552 | 553 | #[repr(align(1))] 554 | struct RetArea([u8; 2]); 555 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 556 | let ptr0 = ret_area.as_mut_ptr() as i32; 557 | #[cfg(target_arch = "wasm32")] 558 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 559 | extern "C" { 560 | #[link_name = "[method]input-pin.wait-for-falling-edge"] 561 | fn wit_import(_: i32, _: i32, ); 562 | } 563 | 564 | #[cfg(not(target_arch = "wasm32"))] 565 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 566 | wit_import((self).handle() as i32, ptr0); 567 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 568 | match l1 { 569 | 0 => { 570 | let e = (); 571 | Ok(e) 572 | } 573 | 1 => { 574 | let e = { 575 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 576 | 577 | ErrorCode::_lift(l2 as u8) 578 | }; 579 | Err(e) 580 | } 581 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 582 | } 583 | } 584 | } 585 | } 586 | impl InputPin { 587 | #[allow(unused_unsafe, clippy::all)] 588 | /// Wait for the pin to undergo any transition, i.e low to high OR high 589 | /// to low. 590 | pub fn wait_for_any_edge(&self,) -> Result<(),ErrorCode>{ 591 | 592 | #[allow(unused_imports)] 593 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 594 | unsafe { 595 | 596 | #[repr(align(1))] 597 | struct RetArea([u8; 2]); 598 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 599 | let ptr0 = ret_area.as_mut_ptr() as i32; 600 | #[cfg(target_arch = "wasm32")] 601 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 602 | extern "C" { 603 | #[link_name = "[method]input-pin.wait-for-any-edge"] 604 | fn wit_import(_: i32, _: i32, ); 605 | } 606 | 607 | #[cfg(not(target_arch = "wasm32"))] 608 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 609 | wit_import((self).handle() as i32, ptr0); 610 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 611 | match l1 { 612 | 0 => { 613 | let e = (); 614 | Ok(e) 615 | } 616 | 1 => { 617 | let e = { 618 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 619 | 620 | ErrorCode::_lift(l2 as u8) 621 | }; 622 | Err(e) 623 | } 624 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 625 | } 626 | } 627 | } 628 | } 629 | impl OutputPin { 630 | #[allow(unused_unsafe, clippy::all)] 631 | /// Drives the pin low. 632 | pub fn set_low(&self,) -> Result<(),ErrorCode>{ 633 | 634 | #[allow(unused_imports)] 635 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 636 | unsafe { 637 | 638 | #[repr(align(1))] 639 | struct RetArea([u8; 2]); 640 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 641 | let ptr0 = ret_area.as_mut_ptr() as i32; 642 | #[cfg(target_arch = "wasm32")] 643 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 644 | extern "C" { 645 | #[link_name = "[method]output-pin.set-low"] 646 | fn wit_import(_: i32, _: i32, ); 647 | } 648 | 649 | #[cfg(not(target_arch = "wasm32"))] 650 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 651 | wit_import((self).handle() as i32, ptr0); 652 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 653 | match l1 { 654 | 0 => { 655 | let e = (); 656 | Ok(e) 657 | } 658 | 1 => { 659 | let e = { 660 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 661 | 662 | ErrorCode::_lift(l2 as u8) 663 | }; 664 | Err(e) 665 | } 666 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 667 | } 668 | } 669 | } 670 | } 671 | impl OutputPin { 672 | #[allow(unused_unsafe, clippy::all)] 673 | /// Drives the pin high. 674 | pub fn set_high(&self,) -> Result<(),ErrorCode>{ 675 | 676 | #[allow(unused_imports)] 677 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 678 | unsafe { 679 | 680 | #[repr(align(1))] 681 | struct RetArea([u8; 2]); 682 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 683 | let ptr0 = ret_area.as_mut_ptr() as i32; 684 | #[cfg(target_arch = "wasm32")] 685 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 686 | extern "C" { 687 | #[link_name = "[method]output-pin.set-high"] 688 | fn wit_import(_: i32, _: i32, ); 689 | } 690 | 691 | #[cfg(not(target_arch = "wasm32"))] 692 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 693 | wit_import((self).handle() as i32, ptr0); 694 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 695 | match l1 { 696 | 0 => { 697 | let e = (); 698 | Ok(e) 699 | } 700 | 1 => { 701 | let e = { 702 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 703 | 704 | ErrorCode::_lift(l2 as u8) 705 | }; 706 | Err(e) 707 | } 708 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 709 | } 710 | } 711 | } 712 | } 713 | impl OutputPin { 714 | #[allow(unused_unsafe, clippy::all)] 715 | /// Drives the pin high or low depending on the provided value. 716 | pub fn set_state(&self,state: PinState,) -> Result<(),ErrorCode>{ 717 | 718 | #[allow(unused_imports)] 719 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 720 | unsafe { 721 | 722 | #[repr(align(1))] 723 | struct RetArea([u8; 2]); 724 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 725 | let ptr0 = ret_area.as_mut_ptr() as i32; 726 | #[cfg(target_arch = "wasm32")] 727 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 728 | extern "C" { 729 | #[link_name = "[method]output-pin.set-state"] 730 | fn wit_import(_: i32, _: i32, _: i32, ); 731 | } 732 | 733 | #[cfg(not(target_arch = "wasm32"))] 734 | fn wit_import(_: i32, _: i32, _: i32, ){ unreachable!() } 735 | wit_import((self).handle() as i32, state.clone() as i32, ptr0); 736 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 737 | match l1 { 738 | 0 => { 739 | let e = (); 740 | Ok(e) 741 | } 742 | 1 => { 743 | let e = { 744 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 745 | 746 | ErrorCode::_lift(l2 as u8) 747 | }; 748 | Err(e) 749 | } 750 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 751 | } 752 | } 753 | } 754 | } 755 | impl StatefulOutputPin { 756 | #[allow(unused_unsafe, clippy::all)] 757 | /// Is the pin in drive high mode? 758 | pub fn is_set_high(&self,) -> Result{ 759 | 760 | #[allow(unused_imports)] 761 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 762 | unsafe { 763 | 764 | #[repr(align(1))] 765 | struct RetArea([u8; 2]); 766 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 767 | let ptr0 = ret_area.as_mut_ptr() as i32; 768 | #[cfg(target_arch = "wasm32")] 769 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 770 | extern "C" { 771 | #[link_name = "[method]stateful-output-pin.is-set-high"] 772 | fn wit_import(_: i32, _: i32, ); 773 | } 774 | 775 | #[cfg(not(target_arch = "wasm32"))] 776 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 777 | wit_import((self).handle() as i32, ptr0); 778 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 779 | match l1 { 780 | 0 => { 781 | let e = { 782 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 783 | 784 | wit_bindgen::rt::bool_lift(l2 as u8) 785 | }; 786 | Ok(e) 787 | } 788 | 1 => { 789 | let e = { 790 | let l3 = i32::from(*((ptr0 + 1) as *const u8)); 791 | 792 | ErrorCode::_lift(l3 as u8) 793 | }; 794 | Err(e) 795 | } 796 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 797 | } 798 | } 799 | } 800 | } 801 | impl StatefulOutputPin { 802 | #[allow(unused_unsafe, clippy::all)] 803 | /// Is the pin in drive low mode? 804 | pub fn is_set_low(&self,) -> Result{ 805 | 806 | #[allow(unused_imports)] 807 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 808 | unsafe { 809 | 810 | #[repr(align(1))] 811 | struct RetArea([u8; 2]); 812 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 813 | let ptr0 = ret_area.as_mut_ptr() as i32; 814 | #[cfg(target_arch = "wasm32")] 815 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 816 | extern "C" { 817 | #[link_name = "[method]stateful-output-pin.is-set-low"] 818 | fn wit_import(_: i32, _: i32, ); 819 | } 820 | 821 | #[cfg(not(target_arch = "wasm32"))] 822 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 823 | wit_import((self).handle() as i32, ptr0); 824 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 825 | match l1 { 826 | 0 => { 827 | let e = { 828 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 829 | 830 | wit_bindgen::rt::bool_lift(l2 as u8) 831 | }; 832 | Ok(e) 833 | } 834 | 1 => { 835 | let e = { 836 | let l3 = i32::from(*((ptr0 + 1) as *const u8)); 837 | 838 | ErrorCode::_lift(l3 as u8) 839 | }; 840 | Err(e) 841 | } 842 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 843 | } 844 | } 845 | } 846 | } 847 | impl StatefulOutputPin { 848 | #[allow(unused_unsafe, clippy::all)] 849 | /// Toggle pin output. 850 | pub fn toggle(&self,) -> Result<(),ErrorCode>{ 851 | 852 | #[allow(unused_imports)] 853 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 854 | unsafe { 855 | 856 | #[repr(align(1))] 857 | struct RetArea([u8; 2]); 858 | let mut ret_area = ::core::mem::MaybeUninit::::uninit(); 859 | let ptr0 = ret_area.as_mut_ptr() as i32; 860 | #[cfg(target_arch = "wasm32")] 861 | #[link(wasm_import_module = "sketch:embedded/digital@0.0.0")] 862 | extern "C" { 863 | #[link_name = "[method]stateful-output-pin.toggle"] 864 | fn wit_import(_: i32, _: i32, ); 865 | } 866 | 867 | #[cfg(not(target_arch = "wasm32"))] 868 | fn wit_import(_: i32, _: i32, ){ unreachable!() } 869 | wit_import((self).handle() as i32, ptr0); 870 | let l1 = i32::from(*((ptr0 + 0) as *const u8)); 871 | match l1 { 872 | 0 => { 873 | let e = (); 874 | Ok(e) 875 | } 876 | 1 => { 877 | let e = { 878 | let l2 = i32::from(*((ptr0 + 1) as *const u8)); 879 | 880 | ErrorCode::_lift(l2 as u8) 881 | }; 882 | Err(e) 883 | } 884 | _ => wit_bindgen::rt::invalid_enum_discriminant(), 885 | } 886 | } 887 | } 888 | } 889 | 890 | } 891 | 892 | } 893 | } 894 | pub mod exports { 895 | pub mod sketch { 896 | pub mod embedded { 897 | 898 | #[allow(clippy::all)] 899 | pub mod run { 900 | #[used] 901 | #[doc(hidden)] 902 | #[cfg(target_arch = "wasm32")] 903 | static __FORCE_SECTION_REF: fn() = super::super::super::super::__link_section; 904 | pub type OutputPin = super::super::super::super::sketch::embedded::digital::OutputPin; 905 | pub type Delay = super::super::super::super::sketch::embedded::delay::Delay; 906 | const _: () = { 907 | 908 | #[doc(hidden)] 909 | #[export_name = "sketch:embedded/run@0.0.0#run"] 910 | #[allow(non_snake_case)] 911 | unsafe extern "C" fn __export_run(arg0: i32,arg1: i32,) { 912 | #[allow(unused_imports)] 913 | use wit_bindgen::rt::{alloc, vec::Vec, string::String}; 914 | 915 | // Before executing any other code, use this function to run all static 916 | // constructors, if they have not yet been run. This is a hack required 917 | // to work around wasi-libc ctors calling import functions to initialize 918 | // the environment. 919 | // 920 | // This functionality will be removed once rust 1.69.0 is stable, at which 921 | // point wasi-libc will no longer have this behavior. 922 | // 923 | // See 924 | // https://github.com/bytecodealliance/preview2-prototyping/issues/99 925 | // for more details. 926 | #[cfg(target_arch="wasm32")] 927 | wit_bindgen::rt::run_ctors_once(); 928 | 929 | <_GuestImpl as Guest>::run(super::super::super::super::sketch::embedded::digital::OutputPin::from_handle(arg0 as u32), super::super::super::super::sketch::embedded::delay::Delay::from_handle(arg1 as u32)); 930 | } 931 | }; 932 | use super::super::super::super::super::Component as _GuestImpl; 933 | pub trait Guest { 934 | /// Start the program, with an output pin and a delay mechanism. 935 | fn run(led: OutputPin,delay: Delay,); 936 | } 937 | 938 | } 939 | 940 | } 941 | } 942 | } 943 | 944 | #[cfg(target_arch = "wasm32")] 945 | #[link_section = "component-type:blink"] 946 | #[doc(hidden)] 947 | pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 1091] = [0, 97, 115, 109, 13, 0, 1, 0, 0, 25, 22, 119, 105, 116, 45, 99, 111, 109, 112, 111, 110, 101, 110, 116, 45, 101, 110, 99, 111, 100, 105, 110, 103, 4, 0, 7, 200, 7, 1, 65, 2, 1, 65, 8, 1, 66, 4, 4, 0, 5, 100, 101, 108, 97, 121, 3, 1, 1, 104, 0, 1, 64, 2, 4, 115, 101, 108, 102, 1, 2, 110, 115, 121, 1, 0, 4, 0, 22, 91, 109, 101, 116, 104, 111, 100, 93, 100, 101, 108, 97, 121, 46, 100, 101, 108, 97, 121, 45, 110, 115, 1, 2, 3, 1, 27, 115, 107, 101, 116, 99, 104, 58, 101, 109, 98, 101, 100, 100, 101, 100, 47, 100, 101, 108, 97, 121, 64, 48, 46, 48, 46, 48, 5, 0, 1, 66, 31, 1, 109, 1, 5, 111, 116, 104, 101, 114, 4, 0, 10, 101, 114, 114, 111, 114, 45, 99, 111, 100, 101, 3, 0, 0, 1, 109, 2, 3, 108, 111, 119, 4, 104, 105, 103, 104, 4, 0, 9, 112, 105, 110, 45, 115, 116, 97, 116, 101, 3, 0, 2, 4, 0, 9, 105, 110, 112, 117, 116, 45, 112, 105, 110, 3, 1, 4, 0, 10, 111, 117, 116, 112, 117, 116, 45, 112, 105, 110, 3, 1, 4, 0, 19, 115, 116, 97, 116, 101, 102, 117, 108, 45, 111, 117, 116, 112, 117, 116, 45, 112, 105, 110, 3, 1, 1, 104, 4, 1, 106, 1, 127, 1, 1, 1, 64, 1, 4, 115, 101, 108, 102, 7, 0, 8, 4, 0, 24, 91, 109, 101, 116, 104, 111, 100, 93, 105, 110, 112, 117, 116, 45, 112, 105, 110, 46, 105, 115, 45, 108, 111, 119, 1, 9, 4, 0, 25, 91, 109, 101, 116, 104, 111, 100, 93, 105, 110, 112, 117, 116, 45, 112, 105, 110, 46, 105, 115, 45, 104, 105, 103, 104, 1, 9, 1, 106, 0, 1, 1, 1, 64, 1, 4, 115, 101, 108, 102, 7, 0, 10, 4, 0, 31, 91, 109, 101, 116, 104, 111, 100, 93, 105, 110, 112, 117, 116, 45, 112, 105, 110, 46, 119, 97, 105, 116, 45, 102, 111, 114, 45, 104, 105, 103, 104, 1, 11, 4, 0, 30, 91, 109, 101, 116, 104, 111, 100, 93, 105, 110, 112, 117, 116, 45, 112, 105, 110, 46, 119, 97, 105, 116, 45, 102, 111, 114, 45, 108, 111, 119, 1, 11, 4, 0, 38, 91, 109, 101, 116, 104, 111, 100, 93, 105, 110, 112, 117, 116, 45, 112, 105, 110, 46, 119, 97, 105, 116, 45, 102, 111, 114, 45, 114, 105, 115, 105, 110, 103, 45, 101, 100, 103, 101, 1, 11, 4, 0, 39, 91, 109, 101, 116, 104, 111, 100, 93, 105, 110, 112, 117, 116, 45, 112, 105, 110, 46, 119, 97, 105, 116, 45, 102, 111, 114, 45, 102, 97, 108, 108, 105, 110, 103, 45, 101, 100, 103, 101, 1, 11, 4, 0, 35, 91, 109, 101, 116, 104, 111, 100, 93, 105, 110, 112, 117, 116, 45, 112, 105, 110, 46, 119, 97, 105, 116, 45, 102, 111, 114, 45, 97, 110, 121, 45, 101, 100, 103, 101, 1, 11, 1, 104, 5, 1, 64, 1, 4, 115, 101, 108, 102, 12, 0, 10, 4, 0, 26, 91, 109, 101, 116, 104, 111, 100, 93, 111, 117, 116, 112, 117, 116, 45, 112, 105, 110, 46, 115, 101, 116, 45, 108, 111, 119, 1, 13, 4, 0, 27, 91, 109, 101, 116, 104, 111, 100, 93, 111, 117, 116, 112, 117, 116, 45, 112, 105, 110, 46, 115, 101, 116, 45, 104, 105, 103, 104, 1, 13, 1, 64, 2, 4, 115, 101, 108, 102, 12, 5, 115, 116, 97, 116, 101, 3, 0, 10, 4, 0, 28, 91, 109, 101, 116, 104, 111, 100, 93, 111, 117, 116, 112, 117, 116, 45, 112, 105, 110, 46, 115, 101, 116, 45, 115, 116, 97, 116, 101, 1, 14, 1, 104, 6, 1, 64, 1, 4, 115, 101, 108, 102, 15, 0, 8, 4, 0, 39, 91, 109, 101, 116, 104, 111, 100, 93, 115, 116, 97, 116, 101, 102, 117, 108, 45, 111, 117, 116, 112, 117, 116, 45, 112, 105, 110, 46, 105, 115, 45, 115, 101, 116, 45, 104, 105, 103, 104, 1, 16, 4, 0, 38, 91, 109, 101, 116, 104, 111, 100, 93, 115, 116, 97, 116, 101, 102, 117, 108, 45, 111, 117, 116, 112, 117, 116, 45, 112, 105, 110, 46, 105, 115, 45, 115, 101, 116, 45, 108, 111, 119, 1, 16, 1, 64, 1, 4, 115, 101, 108, 102, 15, 0, 10, 4, 0, 34, 91, 109, 101, 116, 104, 111, 100, 93, 115, 116, 97, 116, 101, 102, 117, 108, 45, 111, 117, 116, 112, 117, 116, 45, 112, 105, 110, 46, 116, 111, 103, 103, 108, 101, 1, 17, 3, 1, 29, 115, 107, 101, 116, 99, 104, 58, 101, 109, 98, 101, 100, 100, 101, 100, 47, 100, 105, 103, 105, 116, 97, 108, 64, 48, 46, 48, 46, 48, 5, 1, 2, 3, 0, 1, 10, 111, 117, 116, 112, 117, 116, 45, 112, 105, 110, 2, 3, 0, 0, 5, 100, 101, 108, 97, 121, 1, 66, 8, 2, 3, 2, 1, 2, 4, 0, 10, 111, 117, 116, 112, 117, 116, 45, 112, 105, 110, 3, 0, 0, 2, 3, 2, 1, 3, 4, 0, 5, 100, 101, 108, 97, 121, 3, 0, 2, 1, 105, 1, 1, 105, 3, 1, 64, 2, 3, 108, 101, 100, 4, 5, 100, 101, 108, 97, 121, 5, 1, 0, 4, 0, 3, 114, 117, 110, 1, 6, 4, 1, 25, 115, 107, 101, 116, 99, 104, 58, 101, 109, 98, 101, 100, 100, 101, 100, 47, 114, 117, 110, 64, 48, 46, 48, 46, 48, 5, 4, 4, 1, 27, 115, 107, 101, 116, 99, 104, 58, 101, 109, 98, 101, 100, 100, 101, 100, 47, 98, 108, 105, 110, 107, 64, 48, 46, 48, 46, 48, 4, 0, 11, 11, 1, 0, 5, 98, 108, 105, 110, 107, 3, 0, 0, 0, 70, 9, 112, 114, 111, 100, 117, 99, 101, 114, 115, 1, 12, 112, 114, 111, 99, 101, 115, 115, 101, 100, 45, 98, 121, 2, 13, 119, 105, 116, 45, 99, 111, 109, 112, 111, 110, 101, 110, 116, 6, 48, 46, 50, 49, 46, 48, 16, 119, 105, 116, 45, 98, 105, 110, 100, 103, 101, 110, 45, 114, 117, 115, 116, 6, 48, 46, 49, 56, 46, 48]; 948 | 949 | #[inline(never)] 950 | #[doc(hidden)] 951 | #[cfg(target_arch = "wasm32")] 952 | pub fn __link_section() {} 953 | -------------------------------------------------------------------------------- /guest/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | // Import the types from the bindings that we use. 5 | use crate::bindings::exports::sketch::embedded::run::Guest; 6 | use crate::bindings::sketch::embedded::delay::Delay; 7 | use crate::bindings::sketch::embedded::digital::OutputPin; 8 | use lol_alloc::{AssumeSingleThreaded, FreeListAllocator}; 9 | 10 | mod bindings; 11 | 12 | struct Component; 13 | 14 | /// This is the main implementation code. 15 | impl Guest for Component { 16 | fn run(led: OutputPin, delay: Delay) { 17 | // Turn the led on. Wait. Turn it off. Wait. Repeat! 18 | loop { 19 | led.set_high().ok(); 20 | delay.delay_ns(1_000_000_000); 21 | led.set_low().ok(); 22 | delay.delay_ns(1_000_000_000); 23 | } 24 | } 25 | } 26 | 27 | /// Define a global allocator, since we're using `no_std`. 28 | /// SAFETY: We're single-threaded. 29 | #[global_allocator] 30 | static GLOBAL_ALLOCATOR: AssumeSingleThreaded = 31 | unsafe { AssumeSingleThreaded::new(FreeListAllocator::new()) }; 32 | 33 | /// Define a panic handler, since we're using `no_std`. Just infloop for 34 | /// now and hope we don't panic. 35 | #[panic_handler] 36 | fn panic(_panic: &core::panic::PanicInfo<'_>) -> ! { 37 | // Don't panic ;-). 38 | loop {} 39 | } 40 | -------------------------------------------------------------------------------- /host/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "embedded-host" 3 | version = "0.0.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [dependencies] 8 | anyhow = "1.0.79" 9 | wasmtime = { version = "18.0.1", features = ["component-model"] } 10 | -------------------------------------------------------------------------------- /host/src/main.rs: -------------------------------------------------------------------------------- 1 | use crate::sketch::embedded::{delay, digital}; 2 | use anyhow::Context; 3 | use std::fs; 4 | use std::io::Write; 5 | use wasmtime::{ 6 | component::{bindgen, Component, Linker, ResourceTable}, 7 | Config, Engine, Result, Store, 8 | }; 9 | 10 | // Generate bindings of the guest and host components. 11 | bindgen!({ 12 | world: "blink", 13 | path: "../wit", 14 | with: { 15 | "sketch:embedded/delay/delay": Delay, 16 | "sketch:embedded/digital/output-pin": OutputPin, 17 | }, 18 | }); 19 | 20 | pub struct Delay; 21 | pub struct OutputPin; 22 | 23 | struct HostComponent { 24 | table: ResourceTable, 25 | } 26 | 27 | impl digital::Host for HostComponent {} 28 | impl delay::Host for HostComponent {} 29 | 30 | impl digital::HostInputPin for HostComponent { 31 | fn is_low( 32 | &mut self, 33 | _self_: wasmtime::component::Resource, 34 | ) -> wasmtime::Result> { 35 | todo!() 36 | } 37 | fn is_high( 38 | &mut self, 39 | _self_: wasmtime::component::Resource, 40 | ) -> wasmtime::Result> { 41 | todo!() 42 | } 43 | fn wait_for_high( 44 | &mut self, 45 | _self_: wasmtime::component::Resource, 46 | ) -> wasmtime::Result> { 47 | todo!() 48 | } 49 | fn wait_for_low( 50 | &mut self, 51 | _self_: wasmtime::component::Resource, 52 | ) -> wasmtime::Result> { 53 | todo!() 54 | } 55 | fn wait_for_rising_edge( 56 | &mut self, 57 | _self_: wasmtime::component::Resource, 58 | ) -> wasmtime::Result> { 59 | todo!() 60 | } 61 | fn wait_for_falling_edge( 62 | &mut self, 63 | _self_: wasmtime::component::Resource, 64 | ) -> wasmtime::Result> { 65 | todo!() 66 | } 67 | fn wait_for_any_edge( 68 | &mut self, 69 | _self_: wasmtime::component::Resource, 70 | ) -> wasmtime::Result> { 71 | todo!() 72 | } 73 | 74 | fn drop( 75 | &mut self, 76 | _self_: wasmtime::component::Resource, 77 | ) -> wasmtime::Result<()> { 78 | todo!() 79 | } 80 | } 81 | 82 | impl digital::HostOutputPin for HostComponent { 83 | fn set_low( 84 | &mut self, 85 | _self_: wasmtime::component::Resource, 86 | ) -> wasmtime::Result> { 87 | print!(" \r"); 88 | std::io::stdout().flush().unwrap(); 89 | Ok(Ok(())) 90 | } 91 | 92 | fn set_high( 93 | &mut self, 94 | _self_: wasmtime::component::Resource, 95 | ) -> wasmtime::Result> { 96 | print!(" 💡\r"); 97 | std::io::stdout().flush().unwrap(); 98 | Ok(Ok(())) 99 | } 100 | 101 | fn set_state( 102 | &mut self, 103 | _self_: wasmtime::component::Resource, 104 | _state: digital::PinState, 105 | ) -> wasmtime::Result> { 106 | todo!() 107 | } 108 | 109 | fn drop( 110 | &mut self, 111 | _self_: wasmtime::component::Resource, 112 | ) -> wasmtime::Result<()> { 113 | Ok(()) 114 | } 115 | } 116 | 117 | impl digital::HostStatefulOutputPin for HostComponent { 118 | fn is_set_high( 119 | &mut self, 120 | _self_: wasmtime::component::Resource, 121 | ) -> wasmtime::Result> { 122 | todo!() 123 | } 124 | 125 | fn is_set_low( 126 | &mut self, 127 | _self_: wasmtime::component::Resource, 128 | ) -> wasmtime::Result> { 129 | todo!() 130 | } 131 | 132 | fn toggle( 133 | &mut self, 134 | _self_: wasmtime::component::Resource, 135 | ) -> wasmtime::Result> { 136 | todo!() 137 | } 138 | 139 | fn drop( 140 | &mut self, 141 | _self_: wasmtime::component::Resource, 142 | ) -> wasmtime::Result<()> { 143 | todo!() 144 | } 145 | } 146 | 147 | impl delay::HostDelay for HostComponent { 148 | fn delay_ns( 149 | &mut self, 150 | _self_: wasmtime::component::Resource, 151 | ns: u32, 152 | ) -> wasmtime::Result<()> { 153 | std::thread::sleep(std::time::Duration::from_nanos(ns.into())); 154 | Ok(()) 155 | } 156 | 157 | fn drop( 158 | &mut self, 159 | _self_: wasmtime::component::Resource, 160 | ) -> wasmtime::Result<()> { 161 | Ok(()) 162 | } 163 | } 164 | 165 | struct MyState { 166 | host: HostComponent, 167 | } 168 | 169 | fn main() -> Result<()> { 170 | // Create the engine and the linker. 171 | let engine = Engine::new(Config::new().wasm_component_model(true))?; 172 | let mut linker = Linker::new(&engine); 173 | Blink::add_to_linker(&mut linker, |state: &mut MyState| &mut state.host)?; 174 | 175 | // Read the guest component file. 176 | let path = "../guest/target/wasm32-wasi/release/hello_embedded.wasm"; 177 | let component_bytes = fs::read(path).context("failed to read input file")?; 178 | let component = Component::from_binary(&engine, &component_bytes)?; 179 | 180 | // Create the state that will be stored in the store, and link it in. 181 | let mut my_state = MyState { 182 | host: HostComponent { 183 | table: ResourceTable::new(), 184 | }, 185 | }; 186 | 187 | // Create the resources we'll pass into the `run` function. 188 | let led = my_state.host.table.push(OutputPin)?; 189 | let delay = my_state.host.table.push(Delay)?; 190 | 191 | // Create the store and instantiate the component. 192 | let mut store = Store::new(&engine, my_state); 193 | let (blink, _instance) = Blink::instantiate(&mut store, &component, &linker)?; 194 | 195 | // Run! 196 | blink 197 | .sketch_embedded_run() 198 | .call_run(&mut store, led, delay)?; 199 | 200 | Ok(()) 201 | } 202 | -------------------------------------------------------------------------------- /linux-host/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "embedded-host" 3 | version = "0.0.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [dependencies] 8 | anyhow = "1.0.79" 9 | embedded-hal = "1.0.0" 10 | gpio-cdev = "0.6.0" 11 | linux-embedded-hal = "0.4.0" 12 | wasmtime = { version = "18.0.1", features = ["component-model"] } 13 | -------------------------------------------------------------------------------- /linux-host/src/main.rs: -------------------------------------------------------------------------------- 1 | use crate::sketch::embedded::{delay, digital}; 2 | use anyhow::Context; 3 | use gpio_cdev::{Chip, EventRequestFlags, LineRequestFlags}; 4 | use linux_embedded_hal::CdevPin; 5 | use std::fs; 6 | use wasmtime::{ 7 | component::{bindgen, Component, Linker, ResourceTable}, 8 | Config, Engine, Result, Store, 9 | }; 10 | 11 | // Generate bindings of the guest and host components. 12 | bindgen!({ 13 | world: "blink", 14 | path: "../wit", 15 | with: { 16 | "sketch:embedded/delay/delay": Delay, 17 | "sketch:embedded/digital/input-pin": InputPin, 18 | "sketch:embedded/digital/output-pin": OutputPin, 19 | }, 20 | }); 21 | 22 | pub struct Delay; 23 | pub struct InputPin(CdevPin); 24 | pub struct OutputPin(CdevPin); 25 | 26 | struct HostComponent { 27 | table: ResourceTable, 28 | } 29 | 30 | impl digital::Host for HostComponent {} 31 | impl delay::Host for HostComponent {} 32 | 33 | impl digital::HostInputPin for HostComponent { 34 | fn is_low( 35 | &mut self, 36 | self_: wasmtime::component::Resource, 37 | ) -> wasmtime::Result> { 38 | let self_ = self.table.get_mut(&self_)?; 39 | match embedded_hal::digital::InputPin::is_low(&mut self_.0) { 40 | Ok(value) => Ok(Ok(value)), 41 | Err(_) => Ok(Err(digital::ErrorCode::Other)), 42 | } 43 | } 44 | 45 | fn is_high( 46 | &mut self, 47 | self_: wasmtime::component::Resource, 48 | ) -> wasmtime::Result> { 49 | let self_ = self.table.get_mut(&self_)?; 50 | match embedded_hal::digital::InputPin::is_high(&mut self_.0) { 51 | Ok(value) => Ok(Ok(value)), 52 | Err(_) => Ok(Err(digital::ErrorCode::Other)), 53 | } 54 | } 55 | 56 | fn wait_for_high( 57 | &mut self, 58 | _self_: wasmtime::component::Resource, 59 | ) -> wasmtime::Result> { 60 | todo!("InputPin::wait_for_high") 61 | } 62 | 63 | fn wait_for_low( 64 | &mut self, 65 | _self_: wasmtime::component::Resource, 66 | ) -> wasmtime::Result> { 67 | todo!("InputPin::wait_for_low") 68 | } 69 | 70 | fn wait_for_rising_edge( 71 | &mut self, 72 | self_: wasmtime::component::Resource, 73 | ) -> wasmtime::Result> { 74 | let self_ = self.table.get_mut(&self_)?; 75 | let mut events = self_.0.line().events( 76 | LineRequestFlags::INPUT, 77 | EventRequestFlags::RISING_EDGE, 78 | "hello-embedded", 79 | )?; 80 | match events.next() { 81 | Some(Ok(_)) => Ok(Ok(())), 82 | _ => Ok(Err(digital::ErrorCode::Other)), 83 | } 84 | } 85 | 86 | fn wait_for_falling_edge( 87 | &mut self, 88 | self_: wasmtime::component::Resource, 89 | ) -> wasmtime::Result> { 90 | let self_ = self.table.get_mut(&self_)?; 91 | let mut events = self_.0.line().events( 92 | LineRequestFlags::INPUT, 93 | EventRequestFlags::FALLING_EDGE, 94 | "hello-embedded", 95 | )?; 96 | match events.next() { 97 | Some(Ok(_)) => Ok(Ok(())), 98 | _ => Ok(Err(digital::ErrorCode::Other)), 99 | } 100 | } 101 | 102 | fn wait_for_any_edge( 103 | &mut self, 104 | self_: wasmtime::component::Resource, 105 | ) -> wasmtime::Result> { 106 | let self_ = self.table.get_mut(&self_)?; 107 | let mut events = self_.0.line().events( 108 | LineRequestFlags::INPUT, 109 | EventRequestFlags::BOTH_EDGES, 110 | "hello-embedded", 111 | )?; 112 | match events.next() { 113 | Some(Ok(_)) => Ok(Ok(())), 114 | _ => Ok(Err(digital::ErrorCode::Other)), 115 | } 116 | } 117 | 118 | fn drop( 119 | &mut self, 120 | self_: wasmtime::component::Resource, 121 | ) -> wasmtime::Result<()> { 122 | self.table.delete(self_)?; 123 | Ok(()) 124 | } 125 | } 126 | 127 | impl digital::HostOutputPin for HostComponent { 128 | fn set_low( 129 | &mut self, 130 | self_: wasmtime::component::Resource, 131 | ) -> wasmtime::Result> { 132 | let self_ = self.table.get_mut(&self_)?; 133 | match embedded_hal::digital::OutputPin::set_low(&mut self_.0) { 134 | Ok(()) => Ok(Ok(())), 135 | Err(_) => Ok(Err(digital::ErrorCode::Other)), 136 | } 137 | } 138 | 139 | fn set_high( 140 | &mut self, 141 | self_: wasmtime::component::Resource, 142 | ) -> wasmtime::Result> { 143 | let self_ = self.table.get_mut(&self_)?; 144 | match embedded_hal::digital::OutputPin::set_high(&mut self_.0) { 145 | Ok(()) => Ok(Ok(())), 146 | Err(_) => Ok(Err(digital::ErrorCode::Other)), 147 | } 148 | } 149 | 150 | fn set_state( 151 | &mut self, 152 | self_: wasmtime::component::Resource, 153 | state: digital::PinState, 154 | ) -> wasmtime::Result> { 155 | let self_ = self.table.get_mut(&self_)?; 156 | 157 | let state = match state { 158 | digital::PinState::Low => embedded_hal::digital::PinState::Low, 159 | digital::PinState::High => embedded_hal::digital::PinState::High, 160 | }; 161 | 162 | match embedded_hal::digital::OutputPin::set_state(&mut self_.0, state) { 163 | Ok(()) => Ok(Ok(())), 164 | Err(_) => Ok(Err(digital::ErrorCode::Other)), 165 | } 166 | } 167 | 168 | fn drop( 169 | &mut self, 170 | self_: wasmtime::component::Resource, 171 | ) -> wasmtime::Result<()> { 172 | self.table.delete(self_)?; 173 | Ok(()) 174 | } 175 | } 176 | 177 | impl digital::HostStatefulOutputPin for HostComponent { 178 | fn is_set_high( 179 | &mut self, 180 | _self_: wasmtime::component::Resource, 181 | ) -> wasmtime::Result> { 182 | todo!("StatefulOutputLin::is_set_high") 183 | } 184 | 185 | fn is_set_low( 186 | &mut self, 187 | _self_: wasmtime::component::Resource, 188 | ) -> wasmtime::Result> { 189 | todo!("StatefulOutputLin::is_set_low") 190 | } 191 | 192 | fn toggle( 193 | &mut self, 194 | _self_: wasmtime::component::Resource, 195 | ) -> wasmtime::Result> { 196 | todo!("StatefulOutputLin::toggle") 197 | } 198 | 199 | fn drop( 200 | &mut self, 201 | self_: wasmtime::component::Resource, 202 | ) -> wasmtime::Result<()> { 203 | self.table.delete(self_)?; 204 | Ok(()) 205 | } 206 | } 207 | 208 | impl delay::HostDelay for HostComponent { 209 | fn delay_ns( 210 | &mut self, 211 | self_: wasmtime::component::Resource, 212 | ns: u32, 213 | ) -> wasmtime::Result<()> { 214 | let _self_ = self.table.get_mut(&self_)?; 215 | std::thread::sleep(std::time::Duration::from_nanos(ns.into())); 216 | Ok(()) 217 | } 218 | 219 | fn drop(&mut self, self_: wasmtime::component::Resource) -> wasmtime::Result<()> { 220 | self.table.delete(self_)?; 221 | Ok(()) 222 | } 223 | } 224 | 225 | struct MyState { 226 | host: HostComponent, 227 | } 228 | 229 | fn main() -> Result<()> { 230 | // Create the engine and the linker. 231 | let engine = Engine::new(Config::new().wasm_component_model(true))?; 232 | let mut linker = Linker::new(&engine); 233 | Blink::add_to_linker(&mut linker, |state: &mut MyState| &mut state.host)?; 234 | 235 | // Read the guest component file. 236 | let path = "../guest/target/wasm32-wasi/release/hello_embedded.wasm"; 237 | let component_bytes = fs::read(path).context("failed to read input file")?; 238 | let component = Component::from_binary(&engine, &component_bytes)?; 239 | 240 | // Create the state that will be stored in the store, and link it in. 241 | let mut my_state = MyState { 242 | host: HostComponent { 243 | table: ResourceTable::new(), 244 | }, 245 | }; 246 | 247 | // Open the GPIO device. 248 | let mut chip = Chip::new("/dev/gpiochip0") 249 | .context("opening gpio device /dev/gpiochip0")?; 250 | 251 | // Request pin 0 as output. 252 | let output = CdevPin::new(chip.get_line(0)?.request( 253 | LineRequestFlags::OUTPUT, 254 | 0, 255 | "write-output", 256 | )?)?; 257 | 258 | // Create the resources we'll pass into the `run` function. 259 | let led = my_state.host.table.push(OutputPin(output))?; 260 | let delay = my_state.host.table.push(Delay)?; 261 | 262 | // Create the store and instantiate the component. 263 | let mut store = Store::new(&engine, my_state); 264 | let (blink, _instance) = Blink::instantiate(&mut store, &component, &linker)?; 265 | 266 | // Run! 267 | blink 268 | .sketch_embedded_run() 269 | .call_run(&mut store, led, delay)?; 270 | 271 | Ok(()) 272 | } 273 | -------------------------------------------------------------------------------- /wit/async.wit: -------------------------------------------------------------------------------- 1 | package sketch:embedded@0.0.0; 2 | 3 | /// Async interfaces for Inter-Integrated Circuit (I²C). 4 | interface async-i2c { 5 | use wasi:io/poll@0.2.0.{pollable}; 6 | use i2c.{address, error-code, no-acknowledge-source, operation}; 7 | 8 | resource async-i2c { 9 | /// Execute the provided `operation`s on the I²C bus. 10 | transaction: func( 11 | address: address, 12 | operations: list 13 | ) -> transaction-result; 14 | 15 | /// Reads `len` bytes from address `address`. 16 | read: func(address: address, len: u64) -> read-result; 17 | 18 | /// Writes bytes to target with address `address`. 19 | write: func(address: address, data: list) -> write-result; 20 | 21 | /// Writes bytes to address `address` and then reads `read-len` bytes 22 | /// in a single transaction. 23 | write-read: func( 24 | address: address, 25 | write: list, 26 | read-len: u64, 27 | ) -> read-result; 28 | } 29 | 30 | resource transaction-result { 31 | /// Read the result of the transaction, if it is complete. 32 | /// 33 | /// Return none if the transaction is still in progress, or some with 34 | /// the result of the transaction if it's complete. 35 | transaction: func() -> option>, error-code>>; 36 | 37 | /// Create a `pollable` which will resolve once the transaction is 38 | /// complete. 39 | subscribe: func() -> pollable; 40 | } 41 | 42 | resource read-result { 43 | /// Read the result of the read, if it is complete. 44 | /// 45 | /// Return none if the read is still in progress, or some with 46 | /// the result of the read if it's complete. 47 | read: func() -> option, error-code>>; 48 | 49 | /// Create a `pollable` which will resolve once the read is 50 | /// complete. 51 | subscribe: func() -> pollable; 52 | } 53 | 54 | resource write-result { 55 | /// Read the result of the write, if it is complete. 56 | /// 57 | /// Return none if the write is still in progress, or some with 58 | /// the result of the write if it's complete. 59 | write: func() -> option>; 60 | 61 | /// Create a `pollable` which will resolve once the write is 62 | /// complete. 63 | subscribe: func() -> pollable; 64 | } 65 | } 66 | 67 | /// Async interfaces for Digital I/O, for example GPIO pins. 68 | interface async-digital { 69 | use wasi:io/poll@0.2.0.{pollable}; 70 | use digital.{error-code, pin-state}; 71 | 72 | /// Single digital input pin. 73 | resource async-input-pin { 74 | /// Is the input pin low? 75 | is-low: func() -> result; 76 | 77 | /// Is the input pin high? 78 | is-high: func() -> result; 79 | 80 | /// Wait until the pin is high. If it is already high, resolve 81 | /// immediately. 82 | wait-for-high: func() -> pin-result; 83 | 84 | /// Wait until the pin is low. If it is already low, resolve 85 | /// immediately. 86 | wait-for-low: func() -> pin-result; 87 | 88 | /// Wait for the pin to undergo a transition from low to high. 89 | /// 90 | /// If the pin is already high, this does *not* resolve immediately, 91 | /// it’ll wait for the pin to go low and then high again. 92 | wait-for-rising-edge: func() -> pin-result; 93 | 94 | /// Wait for the pin to undergo a transition from high to low. 95 | /// 96 | /// If the pin is already low, this does *not* return immediately, 97 | /// it’ll wait for the pin to go high and then low again. 98 | wait-for-falling-edge: func() -> pin-result; 99 | 100 | /// Wait for the pin to undergo any transition, i.e low to high OR high 101 | /// to low. 102 | wait-for-any-edge: func() -> pin-result; 103 | } 104 | 105 | resource pin-result { 106 | /// Report the result of waiting, if the condition is realized. 107 | /// 108 | /// Return none if the condition hasn't happened yet, or some with 109 | /// the result indicating success or failure. 110 | complete: func() -> option>; 111 | 112 | /// Create a `pollable` which will resolve once the desired condition 113 | /// is realized. 114 | subscribe: func() -> pollable; 115 | } 116 | } 117 | 118 | /// Async interfaces for delays. 119 | interface async-delay { 120 | use wasi:io/poll@0.2.0.{pollable}; 121 | 122 | /// Delay with up to nanosecond precision. 123 | resource delay { 124 | /// Returns a pollable that resultls after minimum `ns` nanoseconds. 125 | /// The delay can be longer if the implementation requires it due to 126 | /// precision/timing issues. 127 | subscribe-to-delay-ns: func(ns: u32) -> pollable; 128 | } 129 | } 130 | 131 | /// Async interfaces for Serial Peripheral Interface (SPI) controller mode. 132 | /// 133 | /// This specifiation follows [OSHWA's recommended terminology]. 134 | /// 135 | /// [OSHWA's recommended terminology]: https://www.oshwa.org/a-resolution-to-redefine-spi-signal-names/ 136 | interface async-spi { 137 | use wasi:io/poll@0.2.0.{pollable}; 138 | use spi.{error-code, mode, polarity, phase, word, operation}; 139 | 140 | /// SPI bus. 141 | /// 142 | /// `bus` represents exclusive ownership over the whole SPI bus, with 143 | /// serial clock (SCK), peripheral in/controller out (PICO), and 144 | /// peripheral out/controller in (POCI) pins. 145 | resource bus { 146 | /// Read words from the peripheral. 147 | /// 148 | /// The word value sent on PICO during reading is 149 | /// implementation-defined, typically 0x00, 0xFF, or configurable. 150 | /// 151 | /// Implementations are allowed to return before the operation is complete. 152 | read: func(len: u64) -> bus-read-result; 153 | 154 | /// Write `words` to the peripheral, ignoring all the incoming words. 155 | /// 156 | /// Implementations are allowed to return before the operation is complete. 157 | write: func(words: list) -> bus-write-result; 158 | 159 | /// Write and read simultaneously. `write` is written to the peripheral 160 | /// on PICO and words received on POCI are returned. 161 | /// 162 | /// It is allowed for `read-len` and `write`'s length to be different, 163 | /// even zero length. The transfer runs for `max(read-len, write.len())` 164 | /// words. If `read-len` is shorter, incoming words after `read-len` has 165 | /// been filled will be discarded. If `write` is shorter, the value of 166 | /// words sent in PICO after all `write` has been sent is 167 | /// implementation-defined, typically `0x00`, `0xFF`, or configurable. 168 | /// 169 | /// Implementations are allowed to return before the operation is complete. 170 | transfer: func( 171 | read-len: u64, 172 | write: list 173 | ) -> bus-transfer-result; 174 | 175 | /// Wait until all operations have completed and the bus is idle. 176 | flush: func() -> bus-flush-result; 177 | } 178 | 179 | resource bus-read-result { 180 | /// Read the result of the read, if it is complete. 181 | /// 182 | /// Return none if the read is still in progress, or some with 183 | /// the result of the read if it's complete. 184 | read: func() -> result, error-code>; 185 | 186 | /// Create a `pollable` which will resolve once the read is 187 | /// complete. 188 | subscribe: func() -> pollable; 189 | } 190 | 191 | resource bus-write-result { 192 | /// Read the result of the write, if it is complete. 193 | /// 194 | /// Return none if the write is still in progress, or some with 195 | /// the result of the write if it's complete. 196 | write: func() -> result<_, error-code>; 197 | 198 | /// Create a `pollable` which will resolve once the write is 199 | /// complete. 200 | subscribe: func() -> pollable; 201 | } 202 | 203 | resource bus-transfer-result { 204 | /// Read the result of the transfer, if it is complete. 205 | /// 206 | /// Return none if the transfer is still in progress, or some with 207 | /// the result of the transfer if it's complete. 208 | transfer: func() -> result, error-code>; 209 | 210 | /// Create a `pollable` which will resolve once the transfer is 211 | /// complete. 212 | subscribe: func() -> pollable; 213 | } 214 | 215 | resource bus-flush-result { 216 | /// Read the result of the flush, if it is complete. 217 | /// 218 | /// Return none if the flush is still in progress, or some with 219 | /// the result of the flush if it's complete. 220 | flush: func() -> result<_, error-code>; 221 | 222 | /// Create a `pollable` which will resolve once the flush is 223 | /// complete. 224 | subscribe: func() -> pollable; 225 | } 226 | 227 | /// SPI device. 228 | /// 229 | /// `device` represents ownership over a single SPI device on a (possibly 230 | /// shared) bus, selected with a CS (Chip Select) pin. 231 | resource device { 232 | /// Perform a transaction against the device. 233 | /// 234 | /// - Locks the bus 235 | /// - Asserts the CS (Chip Select) pin. 236 | /// - Performs all the operations. 237 | /// - Flushes the bus. 238 | /// - Deasserts the CS pin. 239 | /// - Unlocks the bus. 240 | /// 241 | /// The locking mechanism is implementation-defined. The only 242 | /// requirement is it must prevent two transactions from executing 243 | /// concurrently against the same bus. Examples of implementations are: 244 | /// critical sections, blocking mutexes, returning an error or 245 | /// panicking if the bus is already busy. On bus errors the 246 | /// implementation should try to deassert CS. If an error occurs while 247 | /// deasserting CS the bus error should take priority as the return 248 | /// value. 249 | transaction: func( 250 | operations: list 251 | ) -> device-transaction-result; 252 | 253 | /// Do a read within a transaction. 254 | read: func(len: u64) -> device-read-result; 255 | 256 | /// Do a write within a transaction. 257 | write: func(buf: list) -> device-write-result; 258 | 259 | /// Do a transfer within a transaction. 260 | transfer: func( 261 | read-len: u64, 262 | write: list 263 | ) -> device-transfer-result; 264 | } 265 | 266 | resource device-transaction-result { 267 | /// Read the result of the transaction, if it is complete. 268 | /// 269 | /// Return none if the transaction is still in progress, or some with 270 | /// the result of the transaction if it's complete. 271 | transaction: func() -> result>, error-code>; 272 | 273 | /// Create a `pollable` which will resolve once the transaction is 274 | /// complete. 275 | subscribe: func() -> pollable; 276 | } 277 | 278 | resource device-read-result { 279 | /// Read the result of the read, if it is complete. 280 | /// 281 | /// Return none if the read is still in progress, or some with 282 | /// the result of the read if it's complete. 283 | read: func() -> result, error-code>; 284 | 285 | /// Create a `pollable` which will resolve once the read is 286 | /// complete. 287 | subscribe: func() -> pollable; 288 | } 289 | 290 | resource device-write-result { 291 | /// Read the result of the write, if it is complete. 292 | /// 293 | /// Return none if the write is still in progress, or some with 294 | /// the result of the write if it's complete. 295 | write: func() -> result<_, error-code>; 296 | 297 | /// Create a `pollable` which will resolve once the write is 298 | /// complete. 299 | subscribe: func() -> pollable; 300 | } 301 | 302 | resource device-transfer-result { 303 | /// Read the result of the transfer, if it is complete. 304 | /// 305 | /// Return none if the transfer is still in progress, or some with 306 | /// the result of the transfer if it's complete. 307 | transfer: func() -> result, error-code>; 308 | 309 | /// Create a `pollable` which will resolve once the transfer is 310 | /// complete. 311 | subscribe: func() -> pollable; 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /wit/blink.wit: -------------------------------------------------------------------------------- 1 | package sketch:embedded@0.0.0; 2 | 3 | /// An interface to run our "blink" program. 4 | /// 5 | /// The `run` function takes the expected hardware resources as parameters. 6 | interface run { 7 | use digital.{output-pin}; 8 | use delay.{delay}; 9 | 10 | /// Start the program, with an output pin and a delay mechanism. 11 | run: func(led: output-pin, delay: delay); 12 | } 13 | 14 | /// A world to blink in. We import the embedded APIs we need for blinking, 15 | /// and export the run interface we declared above to run. 16 | world blink { 17 | import delay; 18 | import digital; 19 | 20 | export run; 21 | } 22 | 23 | /// An interface to run our "blink" program. 24 | /// 25 | /// The `run` function takes the expected hardware resources as parameters. 26 | interface async-run { 27 | use digital.{output-pin}; 28 | use async-delay.{delay}; 29 | 30 | /// Start the program, with an output pin and a delay mechanism. 31 | run: func(led0: output-pin, led1: output-pin, delay: delay); 32 | } 33 | 34 | /// A world to blink in. We import the embedded APIs we need for blinking, 35 | /// and export the run interface we declared above to run. 36 | world async-blink { 37 | import async-delay; 38 | import digital; 39 | 40 | export async-run; 41 | } 42 | -------------------------------------------------------------------------------- /wit/deps/io/error.wit: -------------------------------------------------------------------------------- 1 | package wasi:io@0.2.0; 2 | 3 | 4 | interface error { 5 | /// A resource which represents some error information. 6 | /// 7 | /// The only method provided by this resource is `to-debug-string`, 8 | /// which provides some human-readable information about the error. 9 | /// 10 | /// In the `wasi:io` package, this resource is returned through the 11 | /// `wasi:io/streams/stream-error` type. 12 | /// 13 | /// To provide more specific error information, other interfaces may 14 | /// provide functions to further "downcast" this error into more specific 15 | /// error information. For example, `error`s returned in streams derived 16 | /// from filesystem types to be described using the filesystem's own 17 | /// error-code type, using the function 18 | /// `wasi:filesystem/types/filesystem-error-code`, which takes a parameter 19 | /// `borrow` and returns 20 | /// `option`. 21 | /// 22 | /// The set of functions which can "downcast" an `error` into a more 23 | /// concrete type is open. 24 | resource error { 25 | /// Returns a string that is suitable to assist humans in debugging 26 | /// this error. 27 | /// 28 | /// WARNING: The returned string should not be consumed mechanically! 29 | /// It may change across platforms, hosts, or other implementation 30 | /// details. Parsing this string is a major platform-compatibility 31 | /// hazard. 32 | to-debug-string: func() -> string; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /wit/deps/io/poll.wit: -------------------------------------------------------------------------------- 1 | package wasi:io@0.2.0; 2 | 3 | /// A poll API intended to let users wait for I/O events on multiple handles 4 | /// at once. 5 | interface poll { 6 | /// `pollable` represents a single I/O event which may be ready, or not. 7 | resource pollable { 8 | 9 | /// Return the readiness of a pollable. This function never blocks. 10 | /// 11 | /// Returns `true` when the pollable is ready, and `false` otherwise. 12 | ready: func() -> bool; 13 | 14 | /// `block` returns immediately if the pollable is ready, and otherwise 15 | /// blocks until ready. 16 | /// 17 | /// This function is equivalent to calling `poll.poll` on a list 18 | /// containing only this pollable. 19 | block: func(); 20 | } 21 | 22 | /// Poll for completion on a set of pollables. 23 | /// 24 | /// This function takes a list of pollables, which identify I/O sources of 25 | /// interest, and waits until one or more of the events is ready for I/O. 26 | /// 27 | /// The result `list` contains one or more indices of handles in the 28 | /// argument list that is ready for I/O. 29 | /// 30 | /// If the list contains more elements than can be indexed with a `u32` 31 | /// value, this function traps. 32 | /// 33 | /// A timeout can be implemented by adding a pollable from the 34 | /// wasi-clocks API to the list. 35 | /// 36 | /// This function does not return a `result`; polling in itself does not 37 | /// do any I/O so it doesn't fail. If any of the I/O sources identified by 38 | /// the pollables has an error, it is indicated by marking the source as 39 | /// being reaedy for I/O. 40 | poll: func(in: list>) -> list; 41 | } 42 | -------------------------------------------------------------------------------- /wit/deps/io/streams.wit: -------------------------------------------------------------------------------- 1 | package wasi:io@0.2.0; 2 | 3 | /// WASI I/O is an I/O abstraction API which is currently focused on providing 4 | /// stream types. 5 | /// 6 | /// In the future, the component model is expected to add built-in stream types; 7 | /// when it does, they are expected to subsume this API. 8 | interface streams { 9 | use error.{error}; 10 | use poll.{pollable}; 11 | 12 | /// An error for input-stream and output-stream operations. 13 | variant stream-error { 14 | /// The last operation (a write or flush) failed before completion. 15 | /// 16 | /// More information is available in the `error` payload. 17 | last-operation-failed(error), 18 | /// The stream is closed: no more input will be accepted by the 19 | /// stream. A closed output-stream will return this error on all 20 | /// future operations. 21 | closed 22 | } 23 | 24 | /// An input bytestream. 25 | /// 26 | /// `input-stream`s are *non-blocking* to the extent practical on underlying 27 | /// platforms. I/O operations always return promptly; if fewer bytes are 28 | /// promptly available than requested, they return the number of bytes promptly 29 | /// available, which could even be zero. To wait for data to be available, 30 | /// use the `subscribe` function to obtain a `pollable` which can be polled 31 | /// for using `wasi:io/poll`. 32 | resource input-stream { 33 | /// Perform a non-blocking read from the stream. 34 | /// 35 | /// When the source of a `read` is binary data, the bytes from the source 36 | /// are returned verbatim. When the source of a `read` is known to the 37 | /// implementation to be text, bytes containing the UTF-8 encoding of the 38 | /// text are returned. 39 | /// 40 | /// This function returns a list of bytes containing the read data, 41 | /// when successful. The returned list will contain up to `len` bytes; 42 | /// it may return fewer than requested, but not more. The list is 43 | /// empty when no bytes are available for reading at this time. The 44 | /// pollable given by `subscribe` will be ready when more bytes are 45 | /// available. 46 | /// 47 | /// This function fails with a `stream-error` when the operation 48 | /// encounters an error, giving `last-operation-failed`, or when the 49 | /// stream is closed, giving `closed`. 50 | /// 51 | /// When the caller gives a `len` of 0, it represents a request to 52 | /// read 0 bytes. If the stream is still open, this call should 53 | /// succeed and return an empty list, or otherwise fail with `closed`. 54 | /// 55 | /// The `len` parameter is a `u64`, which could represent a list of u8 which 56 | /// is not possible to allocate in wasm32, or not desirable to allocate as 57 | /// as a return value by the callee. The callee may return a list of bytes 58 | /// less than `len` in size while more bytes are available for reading. 59 | read: func( 60 | /// The maximum number of bytes to read 61 | len: u64 62 | ) -> result, stream-error>; 63 | 64 | /// Read bytes from a stream, after blocking until at least one byte can 65 | /// be read. Except for blocking, behavior is identical to `read`. 66 | blocking-read: func( 67 | /// The maximum number of bytes to read 68 | len: u64 69 | ) -> result, stream-error>; 70 | 71 | /// Skip bytes from a stream. Returns number of bytes skipped. 72 | /// 73 | /// Behaves identical to `read`, except instead of returning a list 74 | /// of bytes, returns the number of bytes consumed from the stream. 75 | skip: func( 76 | /// The maximum number of bytes to skip. 77 | len: u64, 78 | ) -> result; 79 | 80 | /// Skip bytes from a stream, after blocking until at least one byte 81 | /// can be skipped. Except for blocking behavior, identical to `skip`. 82 | blocking-skip: func( 83 | /// The maximum number of bytes to skip. 84 | len: u64, 85 | ) -> result; 86 | 87 | /// Create a `pollable` which will resolve once either the specified stream 88 | /// has bytes available to read or the other end of the stream has been 89 | /// closed. 90 | /// The created `pollable` is a child resource of the `input-stream`. 91 | /// Implementations may trap if the `input-stream` is dropped before 92 | /// all derived `pollable`s created with this function are dropped. 93 | subscribe: func() -> pollable; 94 | } 95 | 96 | 97 | /// An output bytestream. 98 | /// 99 | /// `output-stream`s are *non-blocking* to the extent practical on 100 | /// underlying platforms. Except where specified otherwise, I/O operations also 101 | /// always return promptly, after the number of bytes that can be written 102 | /// promptly, which could even be zero. To wait for the stream to be ready to 103 | /// accept data, the `subscribe` function to obtain a `pollable` which can be 104 | /// polled for using `wasi:io/poll`. 105 | resource output-stream { 106 | /// Check readiness for writing. This function never blocks. 107 | /// 108 | /// Returns the number of bytes permitted for the next call to `write`, 109 | /// or an error. Calling `write` with more bytes than this function has 110 | /// permitted will trap. 111 | /// 112 | /// When this function returns 0 bytes, the `subscribe` pollable will 113 | /// become ready when this function will report at least 1 byte, or an 114 | /// error. 115 | check-write: func() -> result; 116 | 117 | /// Perform a write. This function never blocks. 118 | /// 119 | /// When the destination of a `write` is binary data, the bytes from 120 | /// `contents` are written verbatim. When the destination of a `write` is 121 | /// known to the implementation to be text, the bytes of `contents` are 122 | /// transcoded from UTF-8 into the encoding of the destination and then 123 | /// written. 124 | /// 125 | /// Precondition: check-write gave permit of Ok(n) and contents has a 126 | /// length of less than or equal to n. Otherwise, this function will trap. 127 | /// 128 | /// returns Err(closed) without writing if the stream has closed since 129 | /// the last call to check-write provided a permit. 130 | write: func( 131 | contents: list 132 | ) -> result<_, stream-error>; 133 | 134 | /// Perform a write of up to 4096 bytes, and then flush the stream. Block 135 | /// until all of these operations are complete, or an error occurs. 136 | /// 137 | /// This is a convenience wrapper around the use of `check-write`, 138 | /// `subscribe`, `write`, and `flush`, and is implemented with the 139 | /// following pseudo-code: 140 | /// 141 | /// ```text 142 | /// let pollable = this.subscribe(); 143 | /// while !contents.is_empty() { 144 | /// // Wait for the stream to become writable 145 | /// pollable.block(); 146 | /// let Ok(n) = this.check-write(); // eliding error handling 147 | /// let len = min(n, contents.len()); 148 | /// let (chunk, rest) = contents.split_at(len); 149 | /// this.write(chunk ); // eliding error handling 150 | /// contents = rest; 151 | /// } 152 | /// this.flush(); 153 | /// // Wait for completion of `flush` 154 | /// pollable.block(); 155 | /// // Check for any errors that arose during `flush` 156 | /// let _ = this.check-write(); // eliding error handling 157 | /// ``` 158 | blocking-write-and-flush: func( 159 | contents: list 160 | ) -> result<_, stream-error>; 161 | 162 | /// Request to flush buffered output. This function never blocks. 163 | /// 164 | /// This tells the output-stream that the caller intends any buffered 165 | /// output to be flushed. the output which is expected to be flushed 166 | /// is all that has been passed to `write` prior to this call. 167 | /// 168 | /// Upon calling this function, the `output-stream` will not accept any 169 | /// writes (`check-write` will return `ok(0)`) until the flush has 170 | /// completed. The `subscribe` pollable will become ready when the 171 | /// flush has completed and the stream can accept more writes. 172 | flush: func() -> result<_, stream-error>; 173 | 174 | /// Request to flush buffered output, and block until flush completes 175 | /// and stream is ready for writing again. 176 | blocking-flush: func() -> result<_, stream-error>; 177 | 178 | /// Create a `pollable` which will resolve once the output-stream 179 | /// is ready for more writing, or an error has occured. When this 180 | /// pollable is ready, `check-write` will return `ok(n)` with n>0, or an 181 | /// error. 182 | /// 183 | /// If the stream is closed, this pollable is always ready immediately. 184 | /// 185 | /// The created `pollable` is a child resource of the `output-stream`. 186 | /// Implementations may trap if the `output-stream` is dropped before 187 | /// all derived `pollable`s created with this function are dropped. 188 | subscribe: func() -> pollable; 189 | 190 | /// Write zeroes to a stream. 191 | /// 192 | /// This should be used precisely like `write` with the exact same 193 | /// preconditions (must use check-write first), but instead of 194 | /// passing a list of bytes, you simply pass the number of zero-bytes 195 | /// that should be written. 196 | write-zeroes: func( 197 | /// The number of zero-bytes to write 198 | len: u64 199 | ) -> result<_, stream-error>; 200 | 201 | /// Perform a write of up to 4096 zeroes, and then flush the stream. 202 | /// Block until all of these operations are complete, or an error 203 | /// occurs. 204 | /// 205 | /// This is a convenience wrapper around the use of `check-write`, 206 | /// `subscribe`, `write-zeroes`, and `flush`, and is implemented with 207 | /// the following pseudo-code: 208 | /// 209 | /// ```text 210 | /// let pollable = this.subscribe(); 211 | /// while num_zeroes != 0 { 212 | /// // Wait for the stream to become writable 213 | /// pollable.block(); 214 | /// let Ok(n) = this.check-write(); // eliding error handling 215 | /// let len = min(n, num_zeroes); 216 | /// this.write-zeroes(len); // eliding error handling 217 | /// num_zeroes -= len; 218 | /// } 219 | /// this.flush(); 220 | /// // Wait for completion of `flush` 221 | /// pollable.block(); 222 | /// // Check for any errors that arose during `flush` 223 | /// let _ = this.check-write(); // eliding error handling 224 | /// ``` 225 | blocking-write-zeroes-and-flush: func( 226 | /// The number of zero-bytes to write 227 | len: u64 228 | ) -> result<_, stream-error>; 229 | 230 | /// Read from one stream and write to another. 231 | /// 232 | /// The behavior of splice is equivelant to: 233 | /// 1. calling `check-write` on the `output-stream` 234 | /// 2. calling `read` on the `input-stream` with the smaller of the 235 | /// `check-write` permitted length and the `len` provided to `splice` 236 | /// 3. calling `write` on the `output-stream` with that read data. 237 | /// 238 | /// Any error reported by the call to `check-write`, `read`, or 239 | /// `write` ends the splice and reports that error. 240 | /// 241 | /// This function returns the number of bytes transferred; it may be less 242 | /// than `len`. 243 | splice: func( 244 | /// The stream to read from 245 | src: borrow, 246 | /// The number of bytes to splice 247 | len: u64, 248 | ) -> result; 249 | 250 | /// Read from one stream and write to another, with blocking. 251 | /// 252 | /// This is similar to `splice`, except that it blocks until the 253 | /// `output-stream` is ready for writing, and the `input-stream` 254 | /// is ready for reading, before performing the `splice`. 255 | blocking-splice: func( 256 | /// The stream to read from 257 | src: borrow, 258 | /// The number of bytes to splice 259 | len: u64, 260 | ) -> result; 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /wit/deps/io/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:io@0.2.0; 2 | 3 | world imports { 4 | import streams; 5 | import poll; 6 | } 7 | -------------------------------------------------------------------------------- /wit/embedded.wit: -------------------------------------------------------------------------------- 1 | /// Embedded APIs. 2 | /// 3 | /// These APIs are based on [embedded-hal]. 4 | /// 5 | /// TODO? 6 | /// - embedded-hal-bus: Sharing SPI and I2C buses 7 | /// - embedded-can: Controller Area Network (CAN) 8 | /// 9 | /// [embedded-hal]: https://crates.io/crates/embedded-hal 10 | package sketch:embedded@0.0.0; 11 | 12 | /// Inter-Integrated Circuit (I²C). 13 | interface i2c { 14 | /// An address value, in either 7-bit or 10-bit form, depending on the device. 15 | type address = u16; 16 | 17 | /// Operation errors. 18 | variant error-code { 19 | /// Bus error occurred. e.g. A START or a STOP condition is detected and 20 | /// is not located after a multiple of 9 SCL clock pulses. 21 | bus, 22 | 23 | /// The arbitration was lost, e.g. electrical problems with the clock signal. 24 | arbitration-loss, 25 | 26 | /// A bus operation was not acknowledged, e.g. due to the addressed 27 | /// device not being available on the bus or the device not being ready 28 | /// to process requests at the moment. 29 | no-acknowledge(no-acknowledge-source), 30 | 31 | /// The peripheral receive buffer was overrun. 32 | overrun, 33 | 34 | /// A different error occurred. 35 | other, 36 | } 37 | 38 | /// No-acknowledge error source. 39 | /// 40 | /// In cases where it is possible, a device should indicate if a no 41 | /// acknowledge response was received to an address versus a no acknowledge 42 | /// to a data byte. Where it is not possible to differentiate, Unknown 43 | /// should be indicated. 44 | enum no-acknowledge-source { 45 | /// The device did not acknowledge its address. The device may be 46 | /// missing. 47 | address, 48 | 49 | /// The device did not acknowledge the data. It may not be ready to 50 | /// process requests at the moment. 51 | data, 52 | 53 | /// Either the device did not acknowledge its address or the data, but 54 | /// it is unknown which. 55 | unknown, 56 | } 57 | 58 | /// An operation used by the `transaction` method. 59 | variant operation { 60 | /// Read the give number of bytes. 61 | read(u64), 62 | 63 | /// Write the given bytes. 64 | write(list) 65 | } 66 | 67 | resource i2c { 68 | /// Execute the provided `operation`s on the I²C bus. 69 | transaction: func( 70 | address: address, 71 | operations: list 72 | ) -> result>, error-code>; 73 | 74 | /// Reads `len` bytes from address `address`. 75 | read: func(address: address, len: u64) -> result, error-code>; 76 | 77 | /// Writes bytes to target with address `address`. 78 | write: func(address: address, data: list) -> result<_, error-code>; 79 | 80 | /// Writes bytes to address `address` and then reads `read-len` bytes 81 | /// in a single transaction. 82 | write-read: func( 83 | address: address, 84 | write: list, 85 | read-len: u64, 86 | ) -> result<_, error-code>; 87 | } 88 | } 89 | 90 | /// Digital I/O, for example GPIO pins. 91 | interface digital { 92 | /// Operation errors. 93 | enum error-code { 94 | /// An error occurred. 95 | other, 96 | } 97 | 98 | /// Digital output pin state. 99 | enum pin-state { 100 | low, 101 | high, 102 | } 103 | 104 | /// Single digital input pin. 105 | resource input-pin { 106 | /// Is the input pin low? 107 | is-low: func() -> result; 108 | 109 | /// Is the input pin high? 110 | is-high: func() -> result; 111 | 112 | /// Wait until the pin is high. If it is already high, resolve 113 | /// immediately. 114 | wait-for-high: func() -> result<_, error-code>; 115 | 116 | /// Wait until the pin is low. If it is already low, resolve 117 | /// immediately. 118 | wait-for-low: func() -> result<_, error-code>; 119 | 120 | /// Wait for the pin to undergo a transition from low to high. 121 | /// 122 | /// If the pin is already high, this does *not* resolve immediately, 123 | /// it’ll wait for the pin to go low and then high again. 124 | wait-for-rising-edge: func() -> result<_, error-code>; 125 | 126 | /// Wait for the pin to undergo a transition from high to low. 127 | /// 128 | /// If the pin is already low, this does *not* return immediately, 129 | /// it’ll wait for the pin to go high and then low again. 130 | wait-for-falling-edge: func() -> result<_, error-code>; 131 | 132 | /// Wait for the pin to undergo any transition, i.e low to high OR high 133 | /// to low. 134 | wait-for-any-edge: func() -> result<_, error-code>; 135 | } 136 | 137 | /// Single digital input pin. 138 | resource output-pin { 139 | /// Drives the pin low. 140 | set-low: func() -> result<_, error-code>; 141 | 142 | /// Drives the pin high. 143 | set-high: func() -> result<_, error-code>; 144 | 145 | /// Drives the pin high or low depending on the provided value. 146 | set-state: func(state: pin-state) -> result<_, error-code>; 147 | } 148 | 149 | /// Push-pull output pin that can read its output state. 150 | resource stateful-output-pin { 151 | /// Is the pin in drive high mode? 152 | is-set-high: func() -> result; 153 | 154 | /// Is the pin in drive low mode? 155 | is-set-low: func() -> result; 156 | 157 | /// Toggle pin output. 158 | toggle: func() -> result<_, error-code>; 159 | } 160 | } 161 | 162 | /// Delays. 163 | interface delay { 164 | /// Delay with up to nanosecond precision. 165 | resource delay { 166 | /// Pauses execution for at minimum `ns` nanoseconds. Pause can be 167 | /// longer if the implementation requires it due to precision/timing 168 | /// issues. 169 | delay-ns: func(ns: u32); 170 | } 171 | } 172 | 173 | /// Pulse Width Modulation (PWM). 174 | interface pwm { 175 | /// Operation errors. 176 | enum error-code { 177 | /// An error occurred. 178 | other, 179 | } 180 | 181 | /// Single PWM channel / pin. 182 | resource set-duty-cycle { 183 | /// Get the maximum duty cycle value. 184 | /// 185 | /// This value corresponds to a 100% duty cycle. 186 | max-duty-cycle: func() -> u16; 187 | 188 | /// Set the duty cycle to `duty / max_duty`. 189 | /// 190 | /// Traps if the duty cycle value is greater than the maximum duty 191 | /// cycle value, as reported by `max-duty-cycle`. 192 | /// 193 | /// Passing the value 0 turns the duty cycle to always inactive. 194 | /// Passing the value returned by `max-duty-cycle` sets the duty cycle 195 | /// to always acctive. 196 | set-duty-cycle: func(duty: u16) -> result<_, error-code>; 197 | } 198 | } 199 | 200 | /// Serial Peripheral Interface (SPI) controller mode. 201 | /// 202 | /// This specifiation follows [OSHWA's recommended terminology]. 203 | /// 204 | /// [OSHWA's recommended terminology]: https://www.oshwa.org/a-resolution-to-redefine-spi-signal-names/ 205 | interface spi { 206 | /// SPI mode. 207 | record mode { 208 | /// Clock polarity. 209 | polarity: polarity, 210 | 211 | // Clock phase. 212 | phase: phase, 213 | } 214 | 215 | /// Clock polarity. 216 | enum polarity { 217 | /// Clock signal low when idle. 218 | idle-low, 219 | 220 | /// Clock signal high when idle. 221 | idle-high, 222 | } 223 | 224 | /// Clock phase. 225 | enum phase { 226 | /// Data in “captured” on the first clock transition. 227 | capture-on-first-transition, 228 | 229 | /// Data in “captured” on the second clock transition. 230 | capture-on-second-transition, 231 | } 232 | 233 | /// SPI error kind. 234 | enum error-code { 235 | /// The peripheral receive buffer was overrun. 236 | overrun, 237 | 238 | /// Multiple devices on the SPI bus are trying to drive the chip 239 | /// select pin. 240 | mode-fault, 241 | 242 | /// Received data does not conform to the peripheral configuration. 243 | frame-format, 244 | 245 | /// An error occurred while asserting or deasserting the 246 | /// Chip Select pin. 247 | chip-select-fault, 248 | 249 | /// A different error occurred. 250 | other, 251 | } 252 | 253 | /// Word size. 254 | /// 255 | /// TODO: Support up to `u16` word sizes? 256 | type word = u8; 257 | 258 | /// SPI transaction operation. 259 | /// 260 | /// This allows composition of SPI operations into a single bus transaction. 261 | variant operation { 262 | /// Read data. 263 | read(u64), 264 | 265 | /// Write data from the provided list, discarding read data. 266 | write(list), 267 | 268 | /// Read data, while writing data from the buffer. 269 | transfer(tuple>), 270 | 271 | /// Delay for at least the specified number of nanoseconds. 272 | delay-ns(u32), 273 | } 274 | 275 | /// Helper for CPOL = 0, CPHA = 0. 276 | mode0: func() -> mode; 277 | 278 | /// Helper for CPOL = 0, CPHA = 1. 279 | mode1: func() -> mode; 280 | 281 | /// Helper for CPOL = 1, CPHA = 0. 282 | mode2: func() -> mode; 283 | 284 | /// Helper for CPOL = 1, CPHA = 1. 285 | mode3: func() -> mode; 286 | 287 | /// SPI bus. 288 | /// 289 | /// `bus` represents exclusive ownership over the whole SPI bus, with 290 | /// serial clock (SCK), peripheral in/controller out (PICO), and 291 | /// peripheral out/controller in (POCI) pins. 292 | resource bus { 293 | /// Read words from the peripheral. 294 | /// 295 | /// The word value sent on PICO during reading is 296 | /// implementation-defined, typically 0x00, 0xFF, or configurable. 297 | /// 298 | /// Implementations are allowed to return before the operation is complete. 299 | read: func(len: u64) -> result, error-code>; 300 | 301 | /// Write `words` to the peripheral, ignoring all the incoming words. 302 | /// 303 | /// Implementations are allowed to return before the operation is complete. 304 | write: func(words: list) -> result<_, error-code>; 305 | 306 | /// Write and read simultaneously. `write` is written to the peripheral 307 | /// on PICO and words received on POCI are returned. 308 | /// 309 | /// It is allowed for `read-len` and `write`'s length to be different, 310 | /// even zero length. The transfer runs for `max(read-len, write.len())` 311 | /// words. If `read-len` is shorter, incoming words after `read-len` has 312 | /// been filled will be discarded. If `write` is shorter, the value of 313 | /// words sent in PICO after all `write` has been sent is 314 | /// implementation-defined, typically `0x00`, `0xFF`, or configurable. 315 | /// 316 | /// Implementations are allowed to return before the operation is complete. 317 | transfer: func( 318 | read-len: u64, 319 | write: list 320 | ) -> result, error-code>; 321 | 322 | /// Wait until all operations have completed and the bus is idle. 323 | flush: func() -> result<_, error-code>; 324 | } 325 | 326 | /// SPI device. 327 | /// 328 | /// `device` represents ownership over a single SPI device on a (possibly 329 | /// shared) bus, selected with a CS (Chip Select) pin. 330 | resource device { 331 | /// Perform a transaction against the device. 332 | /// 333 | /// - Locks the bus 334 | /// - Asserts the CS (Chip Select) pin. 335 | /// - Performs all the operations. 336 | /// - Flushes the bus. 337 | /// - Deasserts the CS pin. 338 | /// - Unlocks the bus. 339 | /// 340 | /// The locking mechanism is implementation-defined. The only 341 | /// requirement is it must prevent two transactions from executing 342 | /// concurrently against the same bus. Examples of implementations are: 343 | /// critical sections, blocking mutexes, returning an error or 344 | /// panicking if the bus is already busy. On bus errors the 345 | /// implementation should try to deassert CS. If an error occurs while 346 | /// deasserting CS the bus error should take priority as the return 347 | /// value. 348 | transaction: func( 349 | operations: list 350 | ) -> result>, error-code>; 351 | 352 | /// Do a read within a transaction. 353 | read: func(len: u64) -> result, error-code>; 354 | 355 | /// Do a write within a transaction. 356 | write: func(buf: list) -> result<_, error-code>; 357 | 358 | /// Do a transfer within a transaction. 359 | transfer: func( 360 | read-len: u64, 361 | write: list 362 | ) -> result, error-code>; 363 | } 364 | } 365 | --------------------------------------------------------------------------------