Crate micrortu_sdk

source ·
Expand description

§MicroRTU SDK

Provides utilities to create wasm blocks for MicroRTU.

§Example

This is a basic example of a block that adds two numbers.

use micrortu_sdk::{
    params, ports, register_block, Shared, StepResult, FactoryInput
};
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(_: &mut 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 mut ports = Ports::parse(&mut shared.latched_ports[..]);

    ports.count.value += 1.;

    0
}

register_block!(Counter, counter, factory, init, step);

§WASM Binary Layout

To define block block_name, that can be later referenced in MicroRTU configuration, you need export 3 functions from your final wasm blob.

§Required Exports

§init

init function with signature () -> ().

§SHARED

SHARED symbol, aligned to 8 bytes, and must be valid for reads and writes for at least 512 bytes.

§COLLECTED_STRINGS

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}

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}

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}

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;

§ports_{block_name} and params_{block_name}

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.

Re-exports§

Modules§

Macros§

  • Macros for generating parser of arguments block requires. Finalize the build process. That macro must be called at the end to embed metadata into the binary. It creates a link section “metadata” with json data of all registered blocks and exported symbol COLLECTED_STRINGS with all strings from the build. BindingDefinition’s name_offset and name_len are referencing COLLECTED_STRINGS.
  • Macros for generating parser of arguments block requires.
  • Macros for generating parser of arguments block requires.
  • Macros for generating parser of arguments block requires. Register block. That macro should be called for each block to register it.

Structs§

Enums§

  • Erorrs that can occur while parsing genarated ports from Shared, written by MicroRTU. Indicates misconfiguration of MicroRTU or a bug in ports! macro or MicroRTU firmware.

Constants§

  • Represents an input binding.
  • Represents an input-output binding.
  • Represents an output binding.

Traits§

Functions§

Type Aliases§

  • The result of a step. 0 means success, anything else is an error. Implementation could also trap, but it’s not recommended. Any error would be logged.

Derive Macros§

  • Macros for generating parser of arguments block requires. Derive macro for Config trait. If block requires some configuration, it should be derived from Config trait. It requires type to be AsBytes and FromBytes. Firmware will pass slice of bytes and you should be able to call from_bytes method on it to get the configuration. For C code you should be able to cast a pointer to your struct.