Skip to main content

sequence_build/
sequence_build.rs

1//! Example: build a sequence file from scratch.
2//!
3//! ```text
4//! cargo run --example sequence_build
5//! ```
6//!
7//! Creates a file, fills `MainSequence` with two numeric limit tests whose limits
8//! are set through the step's property tree, adds a subsequence with an action
9//! step, then saves.
10//!
11//! The file it writes is what `step_insert` and `variables_manage` expect, so
12//! the path is also recorded next to it.
13
14use rs_teststand::{Engine, Sequence, Step, StepGroup};
15
16/// `PropOption_InsertIfMissing`.
17const INSERT_IF_MISSING: i32 = 1;
18/// `PropOption_NoOptions`.
19const NO_OPTIONS: i32 = 0;
20/// An empty adapter key: let the step type choose its own adapter.
21const NO_ADAPTER: &str = "";
22
23/// Builds a numeric limit test with its limits set.
24///
25/// Name, precondition and result recording are properties every step has.
26/// Limits are specific to this step type, so they are reached through the
27/// step's property tree by lookup path.
28fn numeric_limit_test(
29    engine: &Engine,
30    name: &str,
31    precondition: &str,
32    low: f64,
33    high: f64,
34) -> Result<Step, rs_teststand::Error> {
35    let step = engine.new_step(NO_ADAPTER, "NumericLimitTest")?;
36    step.set_name(name)?;
37    step.set_precondition(precondition)?;
38    step.set_record_result(true)?;
39
40    let properties = step.as_property_object()?;
41    properties.set_val_number("Limits.High", INSERT_IF_MISSING, high)?;
42    properties.set_val_number("Limits.Low", INSERT_IF_MISSING, low)?;
43    Ok(step)
44}
45
46fn describe(sequence: &Sequence) -> Result<(), rs_teststand::Error> {
47    let count = sequence.get_num_steps(StepGroup::Main)?;
48    println!("{} holds {count} step(s) in Main:", sequence.name()?);
49    for index in 0..count {
50        let step = sequence.get_step(index, StepGroup::Main)?;
51        let properties = step.as_property_object()?;
52        println!("  [{index}] {}", step.name()?);
53        if properties.exists("Limits.Low", NO_OPTIONS)? {
54            println!(
55                "      limits: low={}, high={}",
56                properties.get_val_number("Limits.Low", NO_OPTIONS)?,
57                properties.get_val_number("Limits.High", NO_OPTIONS)?
58            );
59        }
60        let precondition = step.precondition()?;
61        if !precondition.is_empty() {
62            println!("      runs when: {precondition}");
63        }
64    }
65    Ok(())
66}
67
68fn main() -> Result<(), Box<dyn std::error::Error>> {
69    let engine = Engine::new()?;
70    let sequence_file = engine.new_sequence_file()?;
71    let main_sequence = sequence_file.get_sequence_by_name("MainSequence")?;
72
73    // Steps are placed by group and index, so order is explicit.
74    main_sequence.insert_step(
75        &numeric_limit_test(
76            &engine,
77            "Temperature Check",
78            "Locals.TempSensorPresent == True",
79            15.0,
80            85.0,
81        )?,
82        0,
83        StepGroup::Main,
84    )?;
85    main_sequence.insert_step(
86        &numeric_limit_test(
87            &engine,
88            "Voltage Monitor",
89            "Locals.DUTPowered == True",
90            4.75,
91            5.25,
92        )?,
93        1,
94        StepGroup::Main,
95    )?;
96
97    // A subsequence, so a later example has something to call.
98    let subsequence = engine.new_sequence()?;
99    subsequence.set_name("CustomSubsequence")?;
100    sequence_file.insert_sequence(&subsequence)?;
101
102    let init_step = engine.new_step(NO_ADAPTER, "Action")?;
103    init_step.set_name("Initialize Hardware")?;
104    subsequence.insert_step(&init_step, 0, StepGroup::Main)?;
105
106    describe(&main_sequence)?;
107    println!();
108    describe(&subsequence)?;
109
110    // Cleanup runs even when Main fails, which is why it is worth showing.
111    println!(
112        "\nGroup sizes in MainSequence: setup={}, main={}, cleanup={}",
113        main_sequence.get_num_steps(StepGroup::Setup)?,
114        main_sequence.get_num_steps(StepGroup::Main)?,
115        main_sequence.get_num_steps(StepGroup::Cleanup)?
116    );
117
118    let path = std::env::temp_dir().join("rs_teststand_built_sequence.seq");
119    sequence_file.save(&path.to_string_lossy())?;
120    println!("\nSaved to {}", path.display());
121
122    engine.release_sequence_file_ex(sequence_file, NO_OPTIONS)?;
123    Ok(())
124}