Custom I/O

rPLC allows to spawn custom input and output tasks for unsupported-out-of-the-box I/O protocols.

Let us review an example of a custom I/O which handles GPIO bus on Raspberry Pi-compatible boards which simply routes GPIO #1 input signal to GPIO output #3 and GPIO #2 input to GPIO #4.

plc.yml

version: 1
context:
  fields:
    in1: BOOL
    in2: BOOL
    out1: BOOL
    out2: BOOL

main.rs

Note

As well as program threads, I/O threads can not have names longer than 14 symbols.

use rplc::prelude::*;
use rppal::gpio::Gpio;
use std::time::Duration;

mod plc;

const GPIO_IN1: u8 = 1;
const GPIO_IN2: u8 = 2;

const GPIO_OUT1: u8 = 3;
const GPIO_OUT2: u8 = 4;

#[plc_program(loop = "500ms")]
fn pinroute() {
    let mut ctx = plc_context_mut!();
    ctx.out1 = ctx.in1;
    ctx.out2 = ctx.in2;
}

fn gpio_input_spawn() {
    let pin_in1 = Gpio::new().unwrap().get(GPIO_IN1).unwrap().into_input();
    let pin_in2 = Gpio::new().unwrap().get(GPIO_IN2).unwrap().into_input();
    rplc::tasks::spawn_input_loop(
        "gpio",
        Duration::from_millis(500),
        Duration::default(),
        move || {
            let in1 = pin_in1.is_high();
            let in2 = pin_in2.is_high();
            let mut ctx = plc_context_mut!();
            ctx.in1 = in1;
            ctx.in2 = in2;
        },
    );
}

fn gpio_output_spawn() {
    let mut pin_out1 = Gpio::new().unwrap().get(GPIO_OUT1).unwrap().into_output();
    let mut pin_out2 = Gpio::new().unwrap().get(GPIO_OUT2).unwrap().into_output();
    rplc::tasks::spawn_output_loop(
        "gpio",
        Duration::from_millis(500),
        Duration::default(),
        move || {
            let (out1, out2) = {
                let ctx = plc_context!();
                (ctx.out1, ctx.out2)
            };
            pin_out1.write(out1.into());
            pin_out2.write(out2.into());
        },
    );
}

fn main() {
    init_plc!();
    gpio_input_spawn();
    gpio_output_spawn();
    pinroute_spawn();
    run_plc!();
}

Cargo.toml

[package]
name = "custom_io_rpi_gpio"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rplc = "0.3.0"
rppal = "0.14.1"

[build-dependencies]
rplc = "0.3.0"

build.rs

fn main() {
    rplc::builder::generate("plc.yml").unwrap();
}