execution_run_subsequence/
execution_run_subsequence.rs1use std::time::{Duration, Instant};
22
23use rs_teststand::{
24 AdapterKeyName, Engine, Error, PropValType, PropertyOptions, Sequence, SequenceFile, StepGroup,
25 UIMessageCode, pump_thread_messages,
26};
27
28const SUBSEQUENCE: &str = "Diagnostics";
30const PARAMETER: &str = "FixtureId";
32const RUN_DEADLINE: Duration = Duration::from_secs(60);
34
35const fn none() -> i32 {
36 PropertyOptions::NONE.bits()
37}
38
39const fn insert_if_missing() -> i32 {
40 PropertyOptions::INSERT_IF_MISSING.bits()
41}
42
43fn add_action(engine: &Engine, sequence: &Sequence, name: &str) -> Result<(), Error> {
45 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}
57
58fn build(engine: &Engine) -> Result<SequenceFile, Error> {
60 let sequence_file = engine.new_sequence_file()?;
61
62 let main_sequence = sequence_file.get_sequence_by_name("MainSequence")?;
63 for name in ["Initialize", "Run Test", "Shut Down"] {
64 add_action(engine, &main_sequence, name)?;
65 }
66
67 let diagnostics = engine.new_sequence()?;
68 diagnostics.set_name(SUBSEQUENCE)?;
69 diagnostics.parameters()?.new_sub_property(
71 PARAMETER,
72 PropValType::String,
73 false,
74 "",
75 insert_if_missing(),
76 )?;
77 for name in ["Check Power Rails", "Check Clock"] {
78 add_action(engine, &diagnostics, name)?;
79 }
80 sequence_file.insert_sequence(&diagnostics)?;
81
82 Ok(sequence_file)
83}
84
85fn wait_for_end(engine: &Engine, deadline: Duration) -> Result<bool, Error> {
87 let started = Instant::now();
88 while started.elapsed() < deadline {
89 if pump_thread_messages() {
90 return Ok(false);
91 }
92 while !engine.is_ui_message_queue_empty()? {
93 let message = engine.get_ui_message()?;
94 let ended = matches!(
95 UIMessageCode::from_bits(message.event()?),
96 Ok(UIMessageCode::EndExecution)
97 );
98 message.acknowledge()?;
99 if ended {
100 return Ok(true);
101 }
102 }
103 }
104 Ok(false)
105}
106
107fn run(engine: &Engine, sequence_file: &SequenceFile, entry_point: &str) -> Result<(), Error> {
109 let execution = engine.new_execution(sequence_file, entry_point, None, false, 0)?;
110 println!("\nRunning {entry_point}...");
111
112 if !wait_for_end(engine, RUN_DEADLINE)? {
113 println!(" did not finish within {RUN_DEADLINE:?}; terminating");
114 execution.terminate()?;
115 return Ok(());
116 }
117 println!(" status: {}", execution.result_status()?);
118
119 let results = execution.result_object()?;
120 if !results.exists("ResultList", none())? {
121 println!(" no results recorded");
122 return Ok(());
123 }
124 let result_list = results.get_property_object("ResultList", none())?;
125 for index in 0..result_list.get_num_elements()? {
126 let entry = result_list.get_property_object_by_offset(index, none())?;
127 println!(
128 " {}: {}",
129 entry
130 .get_val_string("TS.StepName", none())
131 .unwrap_or_else(|_| "<unnamed>".to_owned()),
132 entry
133 .get_val_string("Status", none())
134 .unwrap_or_else(|_| "<no status>".to_owned())
135 );
136 }
137 Ok(())
138}
139
140fn main() -> Result<(), Box<dyn std::error::Error>> {
141 let engine = Engine::new()?;
142 engine.set_ui_message_polling_enabled(true)?;
143
144 let sequence_file = build(&engine)?;
145 println!("File holds {} sequence(s).", sequence_file.num_sequences()?);
146
147 run(&engine, &sequence_file, "MainSequence")?;
149
150 let diagnostics = sequence_file.get_sequence_by_name(SUBSEQUENCE)?;
154 diagnostics
155 .parameters()?
156 .set_val_string(PARAMETER, none(), "FIXTURE-07")?;
157 println!(
158 "\n{SUBSEQUENCE}.{PARAMETER} default is now {:?}",
159 diagnostics
160 .parameters()?
161 .get_val_string(PARAMETER, none())?
162 );
163
164 run(&engine, &sequence_file, SUBSEQUENCE)?;
165
166 engine.release_sequence_file_ex(sequence_file, none())?;
167 Ok(())
168}