Provides utilities to create wasm blocks for MicroRTU.
Documentation can be generated via cargo doc --open command.
To generate a simple project, use that command. You should have cargo-generate installed.
cargo generate --git https://github.com/t-industry/micrortu_sdkThis is a basic example of a block that adds two numbers.
use micrortu_sdk::{BlockPorts, FactoryInput, Shared, StepResult, params, ports, register_block};
use static_cell::StaticCell;
pub struct Counter;
ports! {
#[block_names(counter)]
pub struct Ports {
count: TI13 InOut 1 1,
}
}
params! {
#[block_names(counter)]
pub struct Params {}
}
pub fn factory(_: &FactoryInput) -> Option<&'static mut Counter> {
static COUTNER: StaticCell<Counter> = StaticCell::new();
Some(COUTNER.init(Counter))
}
pub fn init(_: &mut Shared, _: &mut Counter) -> StepResult {
0
}
pub fn step(shared: &mut Shared, _: &mut Counter) -> StepResult {
let ports = Ports::parse(&mut shared.latched_ports[..]);
ports.count.value += 1.;
0
}
register_block!(Counter, counter, factory, init, step);The final crate must also call micrortu_sdk::finalize!(); at the top level,
after all block registrations. It embeds the metadata and binding tables the
firmware reads.
Blocks can live in ordinary library crates and be reused from other crates. A
library defines blocks as in the example above and closes with
export_blocks!() instead of finalize!(). The consuming crate registers
them with import_blocks!:
// in the library crate, after the block definitions
micrortu_sdk::export_blocks!(counter);
// in the final crate
micrortu_sdk::import_blocks!(my_library::counter);
micrortu_sdk::finalize!(counter);Both closing macros optionally take the complete list of block names and fail the build unless it matches the registered blocks. Libraries can also import blocks from other libraries and re-export them alongside their own.
If you don't want to use Rust and micrortu_sdk macros, you can still create a
wasm block for MicroRTU. The binary layout of the wasm blob must be as follows:
To define block block_name, that can be later referenced in MicroRTU
configuration, you need export 3 functions from your final wasm blob.
init function with signature () -> ().
SHARED symbol, aligned to 8 bytes, and must be valid for reads and writes for
at least 512 bytes.
It should be &[u8], which is a pointer to the start and length of the slice.
It should point to all names of the ports and params, concatenated.
name_offset and name_len are relative to this slice.
factory_{block_name} is a function that will be called to produce a wasm
block. It's signature should be (i32) -> i32 and code must ensure it follows
Rust's semantics of that signagure:
for<'a> extern "C" fn(&'a FactoryInput) -> Option<&'static mut BlockName>;Where BlockName is your block's type.
init_{block_name} is a function that will be called before step. It's
signature should be (i32, i32) -> i32 and code must ensure it follows Rust's
semantics of that signagure:
for<'a> extern "C" fn(&'a mut Shared, &'a mut BlockName) -> StepResult;step_{block_name} is a function that will be called to make a "step". It's
signature should be (i32, i32) -> i32 and code must ensure it follows Rust's
semantics of that signature:
for<'a> extern "C" fn(&'a mut Shared, &'a mut BlockName) -> StepResult;There also must be exports for ports and params of type &[BindingDefinition],
which is [i32; 2] in memory - pointer to the start and length of the slice.
MICRORTU_BAIL_ON_DUPLICATES - if set, compiler will check for duplicate
port/param definitions, confs and blocks themselves. If not set, last definition
would be used.