Attribute Macro a653rs::partition

source ·
#[partition]
Expand description

Convenience macro for simpler partition development with less pitfalls

For using this macro a module is annotated with the partition() attribute. Inside of this module, start functions, processes, as well as channels can be defined using attributes.

§Example

use a653rs::prelude::PartitionExt;
use a653rs_macros::partition;

mod dummy;

fn main() {
    example::Partition.run();
}

#[partition(crate::dummy::DummyHypervisor)]
mod example {
    #[sampling_out(name = "Ch1", msg_size = "10KB")]
    struct Channel1;

    #[sampling_in(refresh_period = "500ms")]
    #[sampling_in(name = "[ChannelTwo]", msg_size = "25KB")]
    struct ChannelTwo;

    #[queuing_out(msg_count = 20, msg_size = "12KB", discipline = "FIFO")]
    struct Channel3;

    #[start(cold)]
    fn cold_start(ctx: start::Context) {
        warm_start(ctx);
    }

    #[start(warm)]
    fn warm_start(mut ctx: start::Context) {
        ctx.create_aperiodic2().unwrap().start().unwrap();
        ctx.create_periodic3().unwrap().start().unwrap();
        ctx.create_channel_1().unwrap();
        ctx.create_channel_two().unwrap();

        // Maybe we do not always want to initialize channel3
        // ctx.create_channel_3().unwrap();
    }

    #[aperiodic(
        name = "ap2",
        time_capacity = "2ms",
        stack_size = "10KB",
        base_priority = 1,
        deadline = "Soft"
    )]
    fn aperiodic2(ctx: aperiodic2::Context) {
        ctx.get_time();
    }

    #[periodic(
        period = "10ms",
        time_capacity = "5ms",
        stack_size = "10KB",
        base_priority = 1,
        deadline = "Hard"
    )]
    fn periodic3(ctx: periodic3::Context) {}
}

§Attribute #[partition()]

The partition() attribute marks the entry point of this macro. It is meant to be used on a module containing the partition.

When the attribute is used correctly, inside of the module a Partition struct is made available. This Partition struct can then be used in i.e the main function for running the partition.

§Requirements

§#[partition(HYPERVISOR)]
  • HYPERVISOR: the full path to the used hypervisor
§Module
  • start(cold) and start(cold)
  • For calling run() on the Partition struct, HYPERVISOR must implement a653rs::prelude::PartitionExt

§Flexibility

  • The module name can be anything

§Example

use a653rs::prelude::PartitionExt;
use a653rs_macros::partition;

fn main() {
    example::Partition.run();
}

#[partition(crate::dummy::DummyHypervisor)]
mod example {
    #[start(cold)]
    fn cold_start(ctx: start::Context) { }

    #[start(warm)]
    fn warm_start(ctx: start::Context) { }
}

§Attributes start(cold) and start(warm)

start(cold) and start(warm) are used for the start functions of the partition. Inside these functions, the start::Context provides simple functions for initializing processes, channels and using apex functionalities of the provided hypervisor.

§Requirements

  • the start functions must require solely the Context parameter

§Flexibility

  • The identifier of the functions can be anything
  • The identifier of the start::Context can be anything

§Example

#[start(cold)]
fn cold_start(ctx: start::Context) {
    let status = ctx.get_partition_status();
}

#[start(warm)]
fn warm_start(ctx: start::Context) {
    cold_start(ctx);
}

§Attributes periodic() and aperiodic()

Two types of processes are available: periodic and aperiodic processes.

Functions with either the periodic() or aperiodic() attribute use a Context parameter for interacting with the rest of the partition. This Context contains fields for all defined channels and processes as well as functions provided by the used hypervisor.

When a process is defined, a create_NAME() function is made available on the start::Context struct in start(cold) and start(warm). This function must be called in order to initialize the process. Also, these create functions return a reference to the process on success. For the process to be scheduled, the start() function must be called on this reference.

§Requirements

  • the functions must require solely the Context parameter
    • the module path of the Context is the name of the function
§#[periodic(NAME, PERIOD, TIME_CAPACITY, STACK_SIZE, BASE_PRIORITY, DEADLINE)]
§#[aperiodic(NAME, TIME_CAPACITY, STACK_SIZE, BASE_PRIORITY, DEADLINE)]
  • NAME: name used for internal apex calls (optional)
  • TIME_CAPACITY: either “Infinite” or a time like “10ms”, “16s”, “18m”, …
    • Suggested value for P4: equal to the partition duration
  • STACK_SIZE: size like “10KB”, “16kiB”, “12Mb”, …
  • BASE_PRIORITY: i32
    • Suggested value for P4: higher than the base priority of the periodic process
  • DEADLINE: either “Hard” or “Soft”

§Flexibility

  • The identifier of the functions can be anything
  • The identifier of the Context can be anything

§Example

#[start(cold)]
fn cold_start(ctx: start::Context) {
    warm_start(ctx);
}

#[start(warm)]
fn warm_start(mut ctx: start::Context) {
    ctx.create_aperiodic2().unwrap().start().unwrap();
    ctx.create_periodic3().unwrap().start().unwrap();
}

#[aperiodic(
    name = "ap2",
    time_capacity = "Infinite",
    stack_size = "10KB",
    base_priority = 1,
    deadline = "Soft"
)]
fn aperiodic2(ctx: aperiodic2::Context) {
    ctx.get_time();
    ctx.periodic3.unwrap().stop();
}

#[periodic(
    period = "10ms",
    time_capacity = "Infinite",
    stack_size = "10KB",
    base_priority = 1,
    deadline = "Hard"
)]
fn periodic3(ctx: periodic3::Context) {
    let status = ctx.proc_self.status();
    ctx.report_application_message(b"Hello World").unwrap()
}

§Attributes sampling_out(), sampling_in(), queuing_out() and queuing_in()

Two types of channel are available: sampling and queuing ports.

Structs with sampling_out(), sampling_in(), queuing_out() and queuing_in() attribute define channel.

When a channel is defined, a create_NAME() function is made available on the start::Context struct in start(cold) and start(warm). This function must be called in order to initialize the channel. Also a field for each created channel is made available on the Context of each periodic() and aperiodic() process.

§Requirements

§#[sampling_out(NAME, MSG_SIZE)]
§#[sampling_in(NAME, MSG_SIZE, REFRESH_PERIOD)]
§#[queuing_out(NAME, MSG_COUNT, MSG_SIZE, DISCIPLINE)]
§#[queuing_in(NAME, MSG_COUNT, MSG_SIZE, DISCIPLINE)]

§Flexibility

  • The identifier of the struct can be anything

§Example

#[sampling_out(name = "Ch1", msg_size = "10KB")]
struct Channel1;

#[sampling_in(refresh_period = "500ms")]
#[sampling_in(msg_size = "25KB")]
struct ChannelTwo;

#[queuing_out(msg_count = 20, msg_size = "12KB", discipline = "FIFO")]
struct Channel3;

#[queuing_in(name = "ch_3", msg_count = 20, msg_size = "12KB", discipline = "Priority")]
struct LastChannel;

#[start(cold)]
fn cold_start(ctx: start::Context) {
    warm_start(ctx);
}

#[start(warm)]
fn warm_start(mut ctx: start::Context) {
    ctx.create_channel_1().unwrap();
    ctx.create_channel_two().unwrap();
    ctx.create_channel_3().unwrap();
    ctx.create_last_channel().unwrap();
}