Skip to main content

Step

Struct Step 

Source
pub struct Step { /* private fields */ }
Expand description

One step of a sequence (Step).

Built by Engine::new_step and placed with Sequence::insert_step.

This type carries the properties every step has, whatever its type. Anything specific to a step type, a numeric limit test’s limits, for instance, /// lives in the property tree reached through as_property_object.

Implementations§

Source§

impl Step

Source

pub fn name(&self) -> Result<String, Error>

The step’s name (Step.Name).

§Errors

Error if the COM call fails or returns an unexpected type.

Examples found in repository?
examples/step_insert.rs (line 66)
64fn index_of(sequence: &Sequence, name: &str, group: StepGroup) -> Result<Option<i32>, Error> {
65    for index in 0..sequence.get_num_steps(group)? {
66        if sequence.get_step(index, group)?.name()? == name {
67            return Ok(Some(index));
68        }
69    }
70    Ok(None)
71}
72
73fn main() -> Result<(), Box<dyn std::error::Error>> {
74    let engine = Engine::new()?;
75
76    // A file to insert into. Built here so the example depends on nothing that
77    // has to exist on the station first.
78    let sequence_file = engine.new_sequence_file()?;
79    let subsequence = engine.new_sequence()?;
80    subsequence.set_name("CustomSubsequence")?;
81    let existing = engine.new_step(AdapterKeyName::NoneAdapter.as_str(), "Action")?;
82    existing.set_name(TARGET_STEP)?;
83    subsequence.insert_step(&existing, 0, StepGroup::Main)?;
84    sequence_file.insert_sequence(&subsequence)?;
85
86    // Where to insert: in front of the target, or at the end if it is absent.
87    let insert_at = if let Some(index) = index_of(&subsequence, TARGET_STEP, StepGroup::Main)? {
88        println!("Found {TARGET_STEP} at index {index}; inserting in front of it.");
89        index
90    } else {
91        let end = subsequence.get_num_steps(StepGroup::Main)?;
92        println!("{TARGET_STEP} not found; appending at index {end}.");
93        end
94    };
95
96    for (offset, (name, vi, project, mode)) in [
97        (
98            "Measure Voltage (VI)",
99            r"instruments.lvlibp\measure_voltage.vi",
100            "",
101            RunMode::Normal,
102        ),
103        (
104            "Measure Current (VI)",
105            r"instruments.lvlibp\measure_current.vi",
106            r"instruments.lvproj",
107            RunMode::Skip,
108        ),
109    ]
110    .into_iter()
111    .enumerate()
112    {
113        let step = vi_call_step(&engine, name, vi, project, mode)?;
114        let at = insert_at + i32::try_from(offset).unwrap_or(0);
115        subsequence.insert_step(&step, at, StepGroup::Main)?;
116    }
117
118    println!(
119        "\n{} now holds {} step(s):",
120        subsequence.name()?,
121        subsequence.get_num_steps(StepGroup::Main)?
122    );
123    for index in 0..subsequence.get_num_steps(StepGroup::Main)? {
124        let step = subsequence.get_step(index, StepGroup::Main)?;
125        let properties = step.as_property_object()?;
126        let vi = properties
127            .get_val_string(VI_PATH, none())
128            .unwrap_or_else(|_| "<no VI>".to_owned());
129        println!(
130            "  [{index}] {} - {:?}, run mode {:?}, records {:?}",
131            step.name()?,
132            step.adapter_key_name()?,
133            step.run_mode()?,
134            step.result_recording_option()?
135        );
136        if vi != "<no VI>" {
137            println!("        calls {vi}");
138        }
139    }
140
141    let path = std::env::temp_dir().join("rs_teststand_step_insert.seq");
142    let path = path.to_string_lossy().into_owned();
143    sequence_file.save(&path)?;
144    println!("\nSaved to {path}");
145    Ok(())
146}
More examples
Hide additional examples
examples/sequence_build.rs (line 52)
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}
examples/template_manage_complex.rs (line 145)
131fn apply_templates(
132    sequence_file: &SequenceFile,
133    step: &PropertyObject,
134    sequence: &PropertyObject,
135    variable: &PropertyObject,
136) -> Result<(), Error> {
137    let main_sequence = sequence_file.get_sequence_by_name(MAIN_SEQUENCE)?;
138
139    // Inserting returns the copy on the Step interface, so it can be renamed
140    // and re-identified straight away. Without a new step ID the copy would go
141    // on claiming the prototype's identity.
142    let inserted_step = main_sequence.insert_step_from_template(step, 0, StepGroup::Main)?;
143    inserted_step.set_name("Step From Template")?;
144    inserted_step.create_new_unique_step_id()?;
145    println!("  step:     {}", inserted_step.name()?);
146
147    let inserted_sequence = sequence_file.insert_sequence_from_template(sequence)?;
148    inserted_sequence.create_new_unique_step_ids()?;
149    println!(
150        "  sequence: {} ({} step(s))",
151        inserted_sequence.name()?,
152        inserted_sequence.get_num_steps(StepGroup::Main)?
153    );
154
155    // A variable is the easy case: Locals is a property tree, so a clone drops
156    // straight in under the template's own name.
157    let locals = main_sequence.locals()?;
158    locals.set_property_object(
159        &variable.name()?,
160        PropertyOptions::INSERT_IF_MISSING.bits(),
161        &variable.clone_property("", PropertyOptions::NONE.bits())?,
162    )?;
163    println!(
164        "  variable: {} = {:?}",
165        variable.name()?,
166        locals.get_val_string(&variable.name()?, PropertyOptions::NONE.bits())?
167    );
168
169    // A file that does not believe it changed will not write anything.
170    sequence_file
171        .as_property_object_file()?
172        .inc_change_count()?;
173    Ok(())
174}
examples/step_insert_from_template.rs (line 72)
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}
Source

pub fn set_name(&self, name: &str) -> Result<(), Error>

Sets the step’s name (Step.Name).

§Errors

Error if the COM call fails.

Examples found in repository?
examples/template_manage_complex.rs (line 104)
102fn step_template(engine: &Engine) -> Result<PropertyObject, Error> {
103    let step = engine.new_step(NO_ADAPTER, "Statement")?;
104    step.set_name(STEP_TEMPLATE)?;
105    step.set_post_expression(r#"Locals.Result = "Hello from step template!""#)?;
106    step.as_property_object()
107}
108
109/// A whole sequence, one step included, as a single prototype.
110fn sequence_template(engine: &Engine) -> Result<PropertyObject, Error> {
111    let sequence = engine.new_sequence()?;
112    sequence.set_name(SEQUENCE_TEMPLATE)?;
113
114    let step = engine.new_step(NO_ADAPTER, "Statement")?;
115    step.set_name("Inside_Sequence_Template")?;
116    sequence.insert_step(&step, 0, StepGroup::Main)?;
117
118    sequence.as_property_object()
119}
120
121/// A string variable carrying its default value.
122fn variable_template(engine: &Engine) -> Result<PropertyObject, Error> {
123    let variable =
124        engine.new_property_object(PropValType::String, false, "", PropertyOptions::NONE.bits())?;
125    variable.set_name(VARIABLE_TEMPLATE)?;
126    variable.set_val_string("", PropertyOptions::NONE.bits(), "Template Variable Value")?;
127    Ok(variable)
128}
129
130/// Stamps one copy of each template into a file that is already on disk.
131fn apply_templates(
132    sequence_file: &SequenceFile,
133    step: &PropertyObject,
134    sequence: &PropertyObject,
135    variable: &PropertyObject,
136) -> Result<(), Error> {
137    let main_sequence = sequence_file.get_sequence_by_name(MAIN_SEQUENCE)?;
138
139    // Inserting returns the copy on the Step interface, so it can be renamed
140    // and re-identified straight away. Without a new step ID the copy would go
141    // on claiming the prototype's identity.
142    let inserted_step = main_sequence.insert_step_from_template(step, 0, StepGroup::Main)?;
143    inserted_step.set_name("Step From Template")?;
144    inserted_step.create_new_unique_step_id()?;
145    println!("  step:     {}", inserted_step.name()?);
146
147    let inserted_sequence = sequence_file.insert_sequence_from_template(sequence)?;
148    inserted_sequence.create_new_unique_step_ids()?;
149    println!(
150        "  sequence: {} ({} step(s))",
151        inserted_sequence.name()?,
152        inserted_sequence.get_num_steps(StepGroup::Main)?
153    );
154
155    // A variable is the easy case: Locals is a property tree, so a clone drops
156    // straight in under the template's own name.
157    let locals = main_sequence.locals()?;
158    locals.set_property_object(
159        &variable.name()?,
160        PropertyOptions::INSERT_IF_MISSING.bits(),
161        &variable.clone_property("", PropertyOptions::NONE.bits())?,
162    )?;
163    println!(
164        "  variable: {} = {:?}",
165        variable.name()?,
166        locals.get_val_string(&variable.name()?, PropertyOptions::NONE.bits())?
167    );
168
169    // A file that does not believe it changed will not write anything.
170    sequence_file
171        .as_property_object_file()?
172        .inc_change_count()?;
173    Ok(())
174}
More examples
Hide additional examples
examples/result_list_parse.rs (line 43)
36fn add_pass_fail(
37    engine: &Engine,
38    sequence: &Sequence,
39    name: &str,
40    source: &str,
41) -> Result<(), Error> {
42    let step = engine.new_step(AdapterKeyName::NoneAdapter.as_str(), "PassFailTest")?;
43    step.set_name(name)?;
44    step.as_property_object()?
45        .set_val_string("DataSource", insert_if_missing(), source)?;
46    sequence.insert_step(
47        &step,
48        sequence.get_num_steps(StepGroup::Main)?,
49        StepGroup::Main,
50    )
51}
52
53/// Adds a numeric limit test with a fixed measurement.
54fn add_numeric(
55    engine: &Engine,
56    sequence: &Sequence,
57    name: &str,
58    source: &str,
59    low: f64,
60    high: f64,
61) -> Result<(), Error> {
62    let step = engine.new_step(AdapterKeyName::NoneAdapter.as_str(), "NumericLimitTest")?;
63    step.set_name(name)?;
64    let properties = step.as_property_object()?;
65    properties.set_val_string("DataSource", insert_if_missing(), source)?;
66    properties.set_val_number("Limits.Low", insert_if_missing(), low)?;
67    properties.set_val_number("Limits.High", insert_if_missing(), high)?;
68    sequence.insert_step(
69        &step,
70        sequence.get_num_steps(StepGroup::Main)?,
71        StepGroup::Main,
72    )
73}
74
75/// Adds a statement step that records nothing, to show the gap it leaves.
76fn add_unrecorded_filler(engine: &Engine, sequence: &Sequence, name: &str) -> Result<(), Error> {
77    let step = engine.new_step(AdapterKeyName::NoneAdapter.as_str(), "Statement")?;
78    step.set_name(name)?;
79    step.set_result_recording_option(ResultRecordingOption::Disabled)?;
80    sequence.insert_step(
81        &step,
82        sequence.get_num_steps(StepGroup::Main)?,
83        StepGroup::Main,
84    )
85}
examples/ui_messages_handle.rs (line 29)
22fn add_statement(
23    engine: &Engine,
24    sequence: &Sequence,
25    name: &str,
26    expression: &str,
27) -> Result<(), rs_teststand::Error> {
28    let step = engine.new_step(NO_ADAPTER, "Statement")?;
29    step.set_name(name)?;
30    step.as_property_object()?
31        .set_val_string("TS.PostExpr", INSERT_IF_MISSING, expression)?;
32    sequence.insert_step(
33        &step,
34        sequence.get_num_steps(StepGroup::Main)?,
35        StepGroup::Main,
36    )?;
37    Ok(())
38}
examples/sequence_build.rs (line 36)
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}
examples/step_insert_from_template.rs (line 55)
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}
examples/execution_run_subsequence.rs (line 49)
44fn add_action(engine: &Engine, sequence: &Sequence, name: &str) -> Result<(), Error> {
45    // The None adapter is what actually means "no code module"; an empty key
46    // would let the step type pick, and a step on a real adapter fails at run
47    // time with "module has not yet been specified".
48    let step = engine.new_step(AdapterKeyName::NoneAdapter.as_str(), "Action")?;
49    step.set_name(name)?;
50    step.set_record_result(true)?;
51    sequence.insert_step(
52        &step,
53        sequence.get_num_steps(StepGroup::Main)?,
54        StepGroup::Main,
55    )
56}
Source

pub fn precondition(&self) -> Result<String, Error>

The expression deciding whether the step runs (Step.Precondition).

An empty precondition means the step always runs.

§Errors

Error if the COM call fails or returns an unexpected type.

Examples found in repository?
examples/sequence_build.rs (line 60)
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}
Source

pub fn set_precondition(&self, expression: &str) -> Result<(), Error>

Sets the precondition expression (Step.Precondition).

The text is not checked here; a precondition that does not parse fails when the sequence runs, not when it is set.

§Errors

Error if the COM call fails.

Examples found in repository?
examples/sequence_build.rs (line 37)
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}
Source

pub fn run_mode(&self) -> Result<Option<RunMode>, Error>

What the engine does with the step when it reaches it (Step.RunMode).

None means the engine reported a mode this build does not name, which is worth telling apart from a failure to read it at all.

§Errors

Error if the COM call fails or returns an unexpected type.

Examples found in repository?
examples/step_insert_from_template.rs (line 74)
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}
More examples
Hide additional examples
examples/step_insert.rs (line 133)
73fn main() -> Result<(), Box<dyn std::error::Error>> {
74    let engine = Engine::new()?;
75
76    // A file to insert into. Built here so the example depends on nothing that
77    // has to exist on the station first.
78    let sequence_file = engine.new_sequence_file()?;
79    let subsequence = engine.new_sequence()?;
80    subsequence.set_name("CustomSubsequence")?;
81    let existing = engine.new_step(AdapterKeyName::NoneAdapter.as_str(), "Action")?;
82    existing.set_name(TARGET_STEP)?;
83    subsequence.insert_step(&existing, 0, StepGroup::Main)?;
84    sequence_file.insert_sequence(&subsequence)?;
85
86    // Where to insert: in front of the target, or at the end if it is absent.
87    let insert_at = if let Some(index) = index_of(&subsequence, TARGET_STEP, StepGroup::Main)? {
88        println!("Found {TARGET_STEP} at index {index}; inserting in front of it.");
89        index
90    } else {
91        let end = subsequence.get_num_steps(StepGroup::Main)?;
92        println!("{TARGET_STEP} not found; appending at index {end}.");
93        end
94    };
95
96    for (offset, (name, vi, project, mode)) in [
97        (
98            "Measure Voltage (VI)",
99            r"instruments.lvlibp\measure_voltage.vi",
100            "",
101            RunMode::Normal,
102        ),
103        (
104            "Measure Current (VI)",
105            r"instruments.lvlibp\measure_current.vi",
106            r"instruments.lvproj",
107            RunMode::Skip,
108        ),
109    ]
110    .into_iter()
111    .enumerate()
112    {
113        let step = vi_call_step(&engine, name, vi, project, mode)?;
114        let at = insert_at + i32::try_from(offset).unwrap_or(0);
115        subsequence.insert_step(&step, at, StepGroup::Main)?;
116    }
117
118    println!(
119        "\n{} now holds {} step(s):",
120        subsequence.name()?,
121        subsequence.get_num_steps(StepGroup::Main)?
122    );
123    for index in 0..subsequence.get_num_steps(StepGroup::Main)? {
124        let step = subsequence.get_step(index, StepGroup::Main)?;
125        let properties = step.as_property_object()?;
126        let vi = properties
127            .get_val_string(VI_PATH, none())
128            .unwrap_or_else(|_| "<no VI>".to_owned());
129        println!(
130            "  [{index}] {} - {:?}, run mode {:?}, records {:?}",
131            step.name()?,
132            step.adapter_key_name()?,
133            step.run_mode()?,
134            step.result_recording_option()?
135        );
136        if vi != "<no VI>" {
137            println!("        calls {vi}");
138        }
139    }
140
141    let path = std::env::temp_dir().join("rs_teststand_step_insert.seq");
142    let path = path.to_string_lossy().into_owned();
143    sequence_file.save(&path)?;
144    println!("\nSaved to {path}");
145    Ok(())
146}
Source

pub fn set_run_mode(&self, mode: RunMode) -> Result<(), Error>

Sets the run mode (Step.RunMode).

§Errors

Error if the COM call fails.

Examples found in repository?
examples/step_insert_from_template.rs (line 56)
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}
More examples
Hide additional examples
examples/step_insert.rs (line 46)
37fn vi_call_step(
38    engine: &Engine,
39    name: &str,
40    vi_path: &str,
41    project_path: &str,
42    run_mode: RunMode,
43) -> Result<Step, Error> {
44    let step = engine.new_step(AdapterKeyName::LabView.as_str(), "Action")?;
45    step.set_name(name)?;
46    step.set_run_mode(run_mode)?;
47    // Recorded explicitly rather than left to the default, so the step shows up
48    // in the result list a report is built from.
49    step.set_result_recording_option(ResultRecordingOption::Enabled)?;
50
51    let properties = step.as_property_object()?;
52    properties.set_val_string(VI_PATH, insert_if_missing(), vi_path)?;
53    if !project_path.is_empty() {
54        properties.set_val_string(PROJECT_PATH, insert_if_missing(), project_path)?;
55    }
56    Ok(step)
57}
Source

pub fn adapter_key_name(&self) -> Result<Option<AdapterKeyName>, Error>

The adapter the step calls its code module through (Step.AdapterKeyName).

None means the engine reported a key this build does not name, or the step calls no code module at all.

§Errors

Error if the COM call fails or returns an unexpected type.

Examples found in repository?
examples/step_insert_from_template.rs (line 73)
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}
More examples
Hide additional examples
examples/step_insert.rs (line 132)
73fn main() -> Result<(), Box<dyn std::error::Error>> {
74    let engine = Engine::new()?;
75
76    // A file to insert into. Built here so the example depends on nothing that
77    // has to exist on the station first.
78    let sequence_file = engine.new_sequence_file()?;
79    let subsequence = engine.new_sequence()?;
80    subsequence.set_name("CustomSubsequence")?;
81    let existing = engine.new_step(AdapterKeyName::NoneAdapter.as_str(), "Action")?;
82    existing.set_name(TARGET_STEP)?;
83    subsequence.insert_step(&existing, 0, StepGroup::Main)?;
84    sequence_file.insert_sequence(&subsequence)?;
85
86    // Where to insert: in front of the target, or at the end if it is absent.
87    let insert_at = if let Some(index) = index_of(&subsequence, TARGET_STEP, StepGroup::Main)? {
88        println!("Found {TARGET_STEP} at index {index}; inserting in front of it.");
89        index
90    } else {
91        let end = subsequence.get_num_steps(StepGroup::Main)?;
92        println!("{TARGET_STEP} not found; appending at index {end}.");
93        end
94    };
95
96    for (offset, (name, vi, project, mode)) in [
97        (
98            "Measure Voltage (VI)",
99            r"instruments.lvlibp\measure_voltage.vi",
100            "",
101            RunMode::Normal,
102        ),
103        (
104            "Measure Current (VI)",
105            r"instruments.lvlibp\measure_current.vi",
106            r"instruments.lvproj",
107            RunMode::Skip,
108        ),
109    ]
110    .into_iter()
111    .enumerate()
112    {
113        let step = vi_call_step(&engine, name, vi, project, mode)?;
114        let at = insert_at + i32::try_from(offset).unwrap_or(0);
115        subsequence.insert_step(&step, at, StepGroup::Main)?;
116    }
117
118    println!(
119        "\n{} now holds {} step(s):",
120        subsequence.name()?,
121        subsequence.get_num_steps(StepGroup::Main)?
122    );
123    for index in 0..subsequence.get_num_steps(StepGroup::Main)? {
124        let step = subsequence.get_step(index, StepGroup::Main)?;
125        let properties = step.as_property_object()?;
126        let vi = properties
127            .get_val_string(VI_PATH, none())
128            .unwrap_or_else(|_| "<no VI>".to_owned());
129        println!(
130            "  [{index}] {} - {:?}, run mode {:?}, records {:?}",
131            step.name()?,
132            step.adapter_key_name()?,
133            step.run_mode()?,
134            step.result_recording_option()?
135        );
136        if vi != "<no VI>" {
137            println!("        calls {vi}");
138        }
139    }
140
141    let path = std::env::temp_dir().join("rs_teststand_step_insert.seq");
142    let path = path.to_string_lossy().into_owned();
143    sequence_file.save(&path)?;
144    println!("\nSaved to {path}");
145    Ok(())
146}
Source

pub fn post_expression(&self) -> Result<String, Error>

The expression evaluated after the step runs (Step.PostExpression).

An empty expression means nothing runs afterwards.

§Errors

Error if the COM call fails or returns an unexpected type.

Source

pub fn set_post_expression(&self, expression: &str) -> Result<(), Error>

Sets the post expression (Step.PostExpression).

Like a precondition, the text is not checked here: an expression that does not parse fails when the sequence runs, not when it is set.

§Errors

Error if the COM call fails.

Examples found in repository?
examples/template_manage_complex.rs (line 105)
102fn step_template(engine: &Engine) -> Result<PropertyObject, Error> {
103    let step = engine.new_step(NO_ADAPTER, "Statement")?;
104    step.set_name(STEP_TEMPLATE)?;
105    step.set_post_expression(r#"Locals.Result = "Hello from step template!""#)?;
106    step.as_property_object()
107}
Source

pub fn create_new_unique_step_id(&self) -> Result<(), Error>

Gives the step a fresh unique identity (Step.CreateNewUniqueStepId).

A copy of a step carries the original’s step ID, so a sequence built by cloning a prototype ends up with several steps claiming the same identity. Anything that refers to a step by ID, a result, a report entry, a GoTo, then cannot tell them apart. Call this on each copy.

§Errors

Error if the COM call fails.

Examples found in repository?
examples/template_manage_complex.rs (line 144)
131fn apply_templates(
132    sequence_file: &SequenceFile,
133    step: &PropertyObject,
134    sequence: &PropertyObject,
135    variable: &PropertyObject,
136) -> Result<(), Error> {
137    let main_sequence = sequence_file.get_sequence_by_name(MAIN_SEQUENCE)?;
138
139    // Inserting returns the copy on the Step interface, so it can be renamed
140    // and re-identified straight away. Without a new step ID the copy would go
141    // on claiming the prototype's identity.
142    let inserted_step = main_sequence.insert_step_from_template(step, 0, StepGroup::Main)?;
143    inserted_step.set_name("Step From Template")?;
144    inserted_step.create_new_unique_step_id()?;
145    println!("  step:     {}", inserted_step.name()?);
146
147    let inserted_sequence = sequence_file.insert_sequence_from_template(sequence)?;
148    inserted_sequence.create_new_unique_step_ids()?;
149    println!(
150        "  sequence: {} ({} step(s))",
151        inserted_sequence.name()?,
152        inserted_sequence.get_num_steps(StepGroup::Main)?
153    );
154
155    // A variable is the easy case: Locals is a property tree, so a clone drops
156    // straight in under the template's own name.
157    let locals = main_sequence.locals()?;
158    locals.set_property_object(
159        &variable.name()?,
160        PropertyOptions::INSERT_IF_MISSING.bits(),
161        &variable.clone_property("", PropertyOptions::NONE.bits())?,
162    )?;
163    println!(
164        "  variable: {} = {:?}",
165        variable.name()?,
166        locals.get_val_string(&variable.name()?, PropertyOptions::NONE.bits())?
167    );
168
169    // A file that does not believe it changed will not write anything.
170    sequence_file
171        .as_property_object_file()?
172        .inc_change_count()?;
173    Ok(())
174}
More examples
Hide additional examples
examples/step_insert_from_template.rs (line 88)
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}
Source

pub fn result_recording_option(&self) -> Result<ResultRecordingOption, Error>

Whether this step contributes an entry to the result list (Step.ResultRecordingOption).

Distinct from record_result, the plain on/off switch: this one can also say “record even when the sequence says not to”. A step set to Disabled leaves no entry in ResultList, which is the usual reason a parsed report is shorter than the sequence that produced it.

§Errors

Error if the COM call fails or the engine reports an unnamed value.

Examples found in repository?
examples/step_insert.rs (line 134)
73fn main() -> Result<(), Box<dyn std::error::Error>> {
74    let engine = Engine::new()?;
75
76    // A file to insert into. Built here so the example depends on nothing that
77    // has to exist on the station first.
78    let sequence_file = engine.new_sequence_file()?;
79    let subsequence = engine.new_sequence()?;
80    subsequence.set_name("CustomSubsequence")?;
81    let existing = engine.new_step(AdapterKeyName::NoneAdapter.as_str(), "Action")?;
82    existing.set_name(TARGET_STEP)?;
83    subsequence.insert_step(&existing, 0, StepGroup::Main)?;
84    sequence_file.insert_sequence(&subsequence)?;
85
86    // Where to insert: in front of the target, or at the end if it is absent.
87    let insert_at = if let Some(index) = index_of(&subsequence, TARGET_STEP, StepGroup::Main)? {
88        println!("Found {TARGET_STEP} at index {index}; inserting in front of it.");
89        index
90    } else {
91        let end = subsequence.get_num_steps(StepGroup::Main)?;
92        println!("{TARGET_STEP} not found; appending at index {end}.");
93        end
94    };
95
96    for (offset, (name, vi, project, mode)) in [
97        (
98            "Measure Voltage (VI)",
99            r"instruments.lvlibp\measure_voltage.vi",
100            "",
101            RunMode::Normal,
102        ),
103        (
104            "Measure Current (VI)",
105            r"instruments.lvlibp\measure_current.vi",
106            r"instruments.lvproj",
107            RunMode::Skip,
108        ),
109    ]
110    .into_iter()
111    .enumerate()
112    {
113        let step = vi_call_step(&engine, name, vi, project, mode)?;
114        let at = insert_at + i32::try_from(offset).unwrap_or(0);
115        subsequence.insert_step(&step, at, StepGroup::Main)?;
116    }
117
118    println!(
119        "\n{} now holds {} step(s):",
120        subsequence.name()?,
121        subsequence.get_num_steps(StepGroup::Main)?
122    );
123    for index in 0..subsequence.get_num_steps(StepGroup::Main)? {
124        let step = subsequence.get_step(index, StepGroup::Main)?;
125        let properties = step.as_property_object()?;
126        let vi = properties
127            .get_val_string(VI_PATH, none())
128            .unwrap_or_else(|_| "<no VI>".to_owned());
129        println!(
130            "  [{index}] {} - {:?}, run mode {:?}, records {:?}",
131            step.name()?,
132            step.adapter_key_name()?,
133            step.run_mode()?,
134            step.result_recording_option()?
135        );
136        if vi != "<no VI>" {
137            println!("        calls {vi}");
138        }
139    }
140
141    let path = std::env::temp_dir().join("rs_teststand_step_insert.seq");
142    let path = path.to_string_lossy().into_owned();
143    sequence_file.save(&path)?;
144    println!("\nSaved to {path}");
145    Ok(())
146}
Source

pub fn set_result_recording_option( &self, option: ResultRecordingOption, ) -> Result<(), Error>

Sets whether this step records a result (Step.ResultRecordingOption).

§Errors

Error if the COM call fails.

Examples found in repository?
examples/result_list_parse.rs (line 79)
76fn add_unrecorded_filler(engine: &Engine, sequence: &Sequence, name: &str) -> Result<(), Error> {
77    let step = engine.new_step(AdapterKeyName::NoneAdapter.as_str(), "Statement")?;
78    step.set_name(name)?;
79    step.set_result_recording_option(ResultRecordingOption::Disabled)?;
80    sequence.insert_step(
81        &step,
82        sequence.get_num_steps(StepGroup::Main)?,
83        StepGroup::Main,
84    )
85}
More examples
Hide additional examples
examples/step_insert.rs (line 49)
37fn vi_call_step(
38    engine: &Engine,
39    name: &str,
40    vi_path: &str,
41    project_path: &str,
42    run_mode: RunMode,
43) -> Result<Step, Error> {
44    let step = engine.new_step(AdapterKeyName::LabView.as_str(), "Action")?;
45    step.set_name(name)?;
46    step.set_run_mode(run_mode)?;
47    // Recorded explicitly rather than left to the default, so the step shows up
48    // in the result list a report is built from.
49    step.set_result_recording_option(ResultRecordingOption::Enabled)?;
50
51    let properties = step.as_property_object()?;
52    properties.set_val_string(VI_PATH, insert_if_missing(), vi_path)?;
53    if !project_path.is_empty() {
54        properties.set_val_string(PROJECT_PATH, insert_if_missing(), project_path)?;
55    }
56    Ok(step)
57}
Source

pub fn record_result(&self) -> Result<bool, Error>

Whether the step’s result is recorded (Step.RecordResult).

§Errors

Error if the COM call fails or returns an unexpected type.

Source

pub fn set_record_result(&self, record: bool) -> Result<(), Error>

Sets whether the step’s result is recorded (Step.RecordResult).

§Errors

Error if the COM call fails.

Examples found in repository?
examples/sequence_build.rs (line 38)
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}
More examples
Hide additional examples
examples/execution_run_subsequence.rs (line 50)
44fn add_action(engine: &Engine, sequence: &Sequence, name: &str) -> Result<(), Error> {
45    // The None adapter is what actually means "no code module"; an empty key
46    // would let the step type pick, and a step on a real adapter fails at run
47    // time with "module has not yet been specified".
48    let step = engine.new_step(AdapterKeyName::NoneAdapter.as_str(), "Action")?;
49    step.set_name(name)?;
50    step.set_record_result(true)?;
51    sequence.insert_step(
52        &step,
53        sequence.get_num_steps(StepGroup::Main)?,
54        StepGroup::Main,
55    )
56}
examples/execution_run_test_headless.rs (line 72)
62fn add_numeric_limit_test(
63    engine: &Engine,
64    sequence: &Sequence,
65    name: &str,
66    data_source: &str,
67    low: f64,
68    high: f64,
69) -> Result<(), Error> {
70    let step = engine.new_step(AdapterKeyName::NoneAdapter.as_str(), "NumericLimitTest")?;
71    step.set_name(name)?;
72    step.set_record_result(true)?;
73
74    let properties = step.as_property_object()?;
75    properties.set_val_string("DataSource", insert_if_missing(), data_source)?;
76    properties.set_val_number("Limits.Low", insert_if_missing(), low)?;
77    properties.set_val_number("Limits.High", insert_if_missing(), high)?;
78
79    sequence.insert_step(
80        &step,
81        sequence.get_num_steps(StepGroup::Main)?,
82        StepGroup::Main,
83    )
84}
Source

pub fn as_property_object(&self) -> Result<PropertyObject, Error>

The step as a property tree (Step.AsPropertyObject).

Type-specific settings live here, addressed by lookup path, /// Limits.High on a numeric limit test, for instance.

§Errors

Error if the COM call fails or returns an unexpected type.

Examples found in repository?
examples/template_manage_complex.rs (line 106)
102fn step_template(engine: &Engine) -> Result<PropertyObject, Error> {
103    let step = engine.new_step(NO_ADAPTER, "Statement")?;
104    step.set_name(STEP_TEMPLATE)?;
105    step.set_post_expression(r#"Locals.Result = "Hello from step template!""#)?;
106    step.as_property_object()
107}
More examples
Hide additional examples
examples/result_list_parse.rs (line 44)
36fn add_pass_fail(
37    engine: &Engine,
38    sequence: &Sequence,
39    name: &str,
40    source: &str,
41) -> Result<(), Error> {
42    let step = engine.new_step(AdapterKeyName::NoneAdapter.as_str(), "PassFailTest")?;
43    step.set_name(name)?;
44    step.as_property_object()?
45        .set_val_string("DataSource", insert_if_missing(), source)?;
46    sequence.insert_step(
47        &step,
48        sequence.get_num_steps(StepGroup::Main)?,
49        StepGroup::Main,
50    )
51}
52
53/// Adds a numeric limit test with a fixed measurement.
54fn add_numeric(
55    engine: &Engine,
56    sequence: &Sequence,
57    name: &str,
58    source: &str,
59    low: f64,
60    high: f64,
61) -> Result<(), Error> {
62    let step = engine.new_step(AdapterKeyName::NoneAdapter.as_str(), "NumericLimitTest")?;
63    step.set_name(name)?;
64    let properties = step.as_property_object()?;
65    properties.set_val_string("DataSource", insert_if_missing(), source)?;
66    properties.set_val_number("Limits.Low", insert_if_missing(), low)?;
67    properties.set_val_number("Limits.High", insert_if_missing(), high)?;
68    sequence.insert_step(
69        &step,
70        sequence.get_num_steps(StepGroup::Main)?,
71        StepGroup::Main,
72    )
73}
examples/ui_messages_handle.rs (line 30)
22fn add_statement(
23    engine: &Engine,
24    sequence: &Sequence,
25    name: &str,
26    expression: &str,
27) -> Result<(), rs_teststand::Error> {
28    let step = engine.new_step(NO_ADAPTER, "Statement")?;
29    step.set_name(name)?;
30    step.as_property_object()?
31        .set_val_string("TS.PostExpr", INSERT_IF_MISSING, expression)?;
32    sequence.insert_step(
33        &step,
34        sequence.get_num_steps(StepGroup::Main)?,
35        StepGroup::Main,
36    )?;
37    Ok(())
38}
examples/sequence_build.rs (line 40)
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}
examples/step_insert_from_template.rs (line 57)
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}
examples/execution_run_test_headless.rs (line 74)
62fn add_numeric_limit_test(
63    engine: &Engine,
64    sequence: &Sequence,
65    name: &str,
66    data_source: &str,
67    low: f64,
68    high: f64,
69) -> Result<(), Error> {
70    let step = engine.new_step(AdapterKeyName::NoneAdapter.as_str(), "NumericLimitTest")?;
71    step.set_name(name)?;
72    step.set_record_result(true)?;
73
74    let properties = step.as_property_object()?;
75    properties.set_val_string("DataSource", insert_if_missing(), data_source)?;
76    properties.set_val_number("Limits.Low", insert_if_missing(), low)?;
77    properties.set_val_number("Limits.High", insert_if_missing(), high)?;
78
79    sequence.insert_step(
80        &step,
81        sequence.get_num_steps(StepGroup::Main)?,
82        StepGroup::Main,
83    )
84}
Source

pub fn step_type(&self) -> Result<PropertyObject, Error>

The step’s type definition (Step.StepType).

§Errors

Error if the COM call fails or returns an unexpected type.

Source

pub fn break_on_step(&self) -> Result<bool, Error>

Whether this step carries a breakpoint (Step.BreakOnStep).

Reads the step itself. To ask about one run instead, use break_on_step_for.

True here does not mean a run will stop. Breakpoints are only honored while they are switched on, which Engine::breakpoints_enabled controls for the session.

§Errors

Error if the COM call fails or returns an unexpected type.

Source

pub fn break_on_step_for( &self, scope: BreakpointScope<'_>, ) -> Result<bool, Error>

Whether this step carries a breakpoint in the given scope (Step.GetBreakOnStepEx).

§Errors

Error if the COM call fails or returns an unexpected type.

Source

pub fn set_break_on_step( &self, enabled: bool, scope: BreakpointScope<'_>, ) -> Result<(), Error>

Sets or clears the breakpoint on this step (Step.SetBreakOnStepEx).

The scope decides how long it lasts. BreakpointScope::Step writes it into the step, so it survives the run and is saved with the sequence file. BreakpointScope::Execution scopes it to one run and leaves the file alone, which is what a host debugging for a remote panel should use.

A stop announces itself as UIMessageCode::BreakOnBreakpoint, which arrived about 300 ms after the run started in a live measurement. Continue with Execution::resume, not Thread::resume, which does not release a breakpoint stop.

§Errors

Error if the COM call fails.

Source

pub fn set_break_settings( &self, is_set: bool, enabled: bool, pass_count: i32, condition: &str, scope: BreakpointScope<'_>, ) -> Result<(), Error>

Sets a breakpoint together with its pass count and condition (Step.SetBreakSettings).

is_set places or removes the breakpoint and enabled decides whether it is armed, so a breakpoint can stay in place while switched off. pass_count stops on the nth arrival rather than the first. condition is an expression the engine evaluates when it arrives; an empty string means stop unconditionally.

Reading these back needs Step.GetBreakSettings, which returns everything through [out] parameters and is not wrapped yet.

§Errors

Error if the COM call fails.

Trait Implementations§

Source§

impl Debug for Step

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl !RefUnwindSafe for Step

§

impl !Send for Step

§

impl !Sync for Step

§

impl !UnwindSafe for Step

§

impl Freeze for Step

§

impl Unpin for Step

§

impl UnsafeUnpin for Step

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.