Skip to main content

step_insert_from_template/
step_insert_from_template.rs

1//! Example: stamp several copies of one configured step into a sequence.
2//!
3//! ```text
4//! cargo run --example step_insert_from_template
5//! ```
6//!
7//! The editor's Templates pane holds reusable step prototypes, reached with
8//! `Engine.GetTemplatesFile`. It is empty on a station nobody has saved one on,
9//! so this reports what is there and then builds its own prototype, a VI-call
10//! step, which exercises the part of the workflow that applies whatever the
11//! template came from.
12//!
13//! The one thing a copy does not bring with it is a distinct identity. Every
14//! copy arrives holding the prototype's step ID, so each needs
15//! `create_new_unique_step_id`; without it the sequence contains several steps
16//! that anything working by ID cannot tell apart.
17//!
18//! The adapter key names an adapter the engine knows, not one this station can
19//! necessarily run. Building the step succeeds without `LabVIEW` installed;
20//! only executing it would need it.
21
22use rs_teststand::{
23    AdapterKeyName, Engine, Error, GetTemplatesFileOptions, PropertyOptions, RunMode, Step,
24    StepGroup,
25};
26
27/// Where a VI-call step keeps the path of the VI it calls.
28const VI_PATH: &str = "TS.SData.ViCall.VIPath";
29/// How many copies to stamp out.
30const COPIES: i32 = 2;
31
32/// Reports what the station's Templates pane holds.
33fn describe_templates(engine: &Engine) -> Result<(), Error> {
34    let templates_file = engine.get_templates_file(GetTemplatesFileOptions::LOAD_IF_NOT_LOADED)?;
35    let root = templates_file
36        .data()?
37        .get_property_object("Root", PropertyOptions::NONE.bits())?;
38    for index in 0..root.get_num_elements()? {
39        let category = root.get_property_object_by_offset(index, PropertyOptions::NONE.bits())?;
40        if category.name()? == "Steps" {
41            println!(
42                "Step templates defined on this station: {}",
43                category.get_num_elements()?
44            );
45        }
46    }
47    Ok(())
48}
49
50/// One configured VI-call step, to act as the prototype.
51fn build_prototype(engine: &Engine) -> Result<Step, Error> {
52    // The maintained LabVIEW adapter. The standard-prototype key still exists
53    // but the documentation marks it obsolete in favour of this one.
54    let step = engine.new_step(AdapterKeyName::LabView.as_str(), "Action")?;
55    step.set_name("Measure (VI)")?;
56    step.set_run_mode(RunMode::Normal)?;
57    step.as_property_object()?.set_val_string(
58        VI_PATH,
59        PropertyOptions::INSERT_IF_MISSING.bits(),
60        r"example.lvlibp\measure.vi",
61    )?;
62    Ok(step)
63}
64
65fn main() -> Result<(), Box<dyn std::error::Error>> {
66    let engine = Engine::new()?;
67    describe_templates(&engine)?;
68
69    let prototype = build_prototype(&engine)?;
70    println!(
71        "Prototype: {} via {:?}, run mode {:?}",
72        prototype.name()?,
73        prototype.adapter_key_name()?,
74        prototype.run_mode()?
75    );
76
77    let sequence_file = engine.new_sequence_file()?;
78    let main_sequence = sequence_file.get_sequence_by_name("MainSequence")?;
79    let template = prototype.as_property_object()?;
80
81    for copy_number in 1..=COPIES {
82        let index = main_sequence.get_num_steps(StepGroup::Main)?;
83        let inserted =
84            main_sequence.insert_step_from_template(&template, index, StepGroup::Main)?;
85        inserted.set_name(&format!("Measure {copy_number} (from template)"))?;
86        // Each copy needs an identity of its own; the clone brought the
87        // prototype's.
88        inserted.create_new_unique_step_id()?;
89    }
90
91    println!(
92        "\nMainSequence now holds {} step(s):",
93        main_sequence.get_num_steps(StepGroup::Main)?
94    );
95    for index in 0..main_sequence.get_num_steps(StepGroup::Main)? {
96        let step = main_sequence.get_step(index, StepGroup::Main)?;
97        println!(
98            "  [{index}] {} -> {}",
99            step.name()?,
100            step.as_property_object()?
101                .get_val_string(VI_PATH, PropertyOptions::NONE.bits())?
102        );
103    }
104
105    // The prototype is untouched and can go on producing copies.
106    println!("\nPrototype still named: {}", prototype.name()?);
107
108    let path = std::env::temp_dir().join("rs_teststand_from_template.seq");
109    let path = path.to_string_lossy().into_owned();
110    sequence_file.save(&path)?;
111    println!("Saved to {path}");
112    Ok(())
113}