Basics

Function “main”

The main function should look like

use rplc::prelude::*;

fn main() {
    init_plc!();
    // spawn programs
    p1_spawn();
    p2_spawn();
    // spawn custom I/O
    run_plc!();
}

PLC status

When spawned, I/O and program threads do not start to run tasks in interval loops instantly, the tasks are waiting for the specific PLC status.

The current PLC status can be obtained with a method:

let status = rplc::tasks::status();

There is also a method to obtain is PLC active or not:

// equal to rplc::tasks::status() == rplc::tasks::Status::Active
let active = rplc::tasks::is_active();

Status

Code

Description

INACTIVE

0

PLC is launched

STARTING

1

run_plc!() is called

SYNCING

2

Input threads start running

PREPARING

3

Program threads start running

ACTIVE

100

All I/O threads and programs are active

STOPPING

-1

PLC is shutting down, all input and program threads must quit

STOPSYNCING

-2

All outputs must be executed once and quit

STOPPED

-100

All threads are stopped

Note

After PLC goes to SYNCING state, no new I/O or program threads can be spawned.

Stack size

By default threads use the default system stack size. This can be changed with:

version: 1
core:
  stack_size: 32000 # in kilobytes, 32000=32MB

Shutdown

Timeout

By default, PLC process has 30 seconds to stop. After the PLC process forcibly terminates itself. This timeout can be modified in PLC build config (e.g.) plc.yml:

version: 1
core:
  stop_timeout: 60 # prolong the timeout to 60 seconds

Custom shutdown function

A custom shutdown function can be defined. The function is called when PLC goes to STOPPING state. The function can modify the context, e.g. turn off the equipment. After the function call is finished, PLC ensures all output tasks are executed at least once to synchronize modified context variables with external equipment.

fn shutdown() {
    warn!("shutting down");
    let mut ctx = plc_context_mut!();
    ctx.fan = false;
    ctx.fan2 = false;
    ctx.fan3 = false;
    ctx.fan4 = false;
    warn!("shutdown program completed");
}

fn main() {
    init_plc!();
    rplc::tasks::on_shutdown(shutdown);
    // ......
}

Building PLC context and I/O

To automatically generate Rust code for PLC context and input/output operations, create a file named build.rs and put it into the project’s root directory:

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

Control files

When started, the process creates a “pid” file processname.pid and API socket processname.plcsock in the system temporary directory or in the directory specified in PLC_VAR_DIR system environment variable.

Error handling

  • Program and custom I/O tasks MUST NOT panic

  • Custom I/O launchers and the main function can panic on errors

  • rPLC panic handler immediately stops the whole process if any tread goes to panic