use rs_teststand::{Engine, PropValType, PropertyObject, TypeCategory, TypeUsageList};
const INSERT_IF_MISSING: i32 = 1;
const NO_OPTIONS: i32 = 0;
const COERCE_TO_NUMBER: i32 = 64;
const IS_STRICT_ATTRIBUTE: &str = "TestStand.Enum.IsStrict";
fn build_multimeter_type(engine: &Engine) -> Result<PropertyObject, rs_teststand::Error> {
let data_type = engine.new_property_object(PropValType::Container, false, "", NO_OPTIONS)?;
data_type.set_val_number("Resolution", INSERT_IF_MISSING, 6.5)?;
data_type.set_val_bool("AutoZero", INSERT_IF_MISSING, false)?;
data_type.set_val_string("Mode", INSERT_IF_MISSING, "Voltage")?;
data_type.set_val_number("Range", INSERT_IF_MISSING, 100.0)?;
data_type.set_name("DigitalMultimeter")?;
Ok(data_type)
}
fn enumerator_array(
engine: &Engine,
named_values: &[(&str, f64)],
strict: bool,
) -> Result<PropertyObject, rs_teststand::Error> {
let array = engine.new_property_object(PropValType::Container, true, "", NO_OPTIONS)?;
array.set_num_elements(i32::try_from(named_values.len()).unwrap_or(0), NO_OPTIONS)?;
for (index, (name, value)) in named_values.iter().enumerate() {
let element =
array.get_property_object_by_offset(i32::try_from(index).unwrap_or(0), NO_OPTIONS)?;
element.set_val_string("EnumeratorName", INSERT_IF_MISSING, name)?;
element.set_val_number("EnumeratorValue", INSERT_IF_MISSING, *value)?;
}
array
.attributes()?
.set_val_bool(IS_STRICT_ATTRIBUTE, INSERT_IF_MISSING, strict)?;
Ok(array)
}
fn register_enum(
engine: &Engine,
types: &TypeUsageList,
name: &str,
named_values: &[(&str, f64)],
strict: bool,
) -> Result<PropertyObject, rs_teststand::Error> {
let enum_type = engine.new_property_object(PropValType::Enum, false, "", NO_OPTIONS)?;
enum_type.set_name(name)?;
types.insert_type(
&enum_type,
types.num_types()?,
TypeCategory::CustomDataTypes,
)?;
let definition = types.get_type_definition(types.get_type_index(name)?)?;
definition.update_enumerators(&enumerator_array(engine, named_values, strict)?)?;
Ok(definition)
}
fn print_enumerators(definition: &PropertyObject) -> Result<(), rs_teststand::Error> {
let enumerators = definition.enumerators()?;
let strict = enumerators
.attributes()?
.get_val_bool(IS_STRICT_ATTRIBUTE, NO_OPTIONS)?;
println!(
" {} v{} (strict={strict}):",
definition.name()?,
definition.type_version()?
);
for index in 0..enumerators.get_num_elements()? {
let element = enumerators.get_property_object_by_offset(index, NO_OPTIONS)?;
let value = element.get_val_number("", COERCE_TO_NUMBER)?;
println!(
" {} -> {value}",
element.get_value_display_name("", NO_OPTIONS)?
);
}
Ok(())
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let engine = Engine::new()?;
let sequence_file = engine.new_sequence_file()?;
let file = sequence_file.as_property_object_file()?;
let types = file.type_usage_list()?;
types.insert_type(
&build_multimeter_type(&engine)?,
types.num_types()?,
TypeCategory::CustomDataTypes,
)?;
let coupling = register_enum(
&engine,
&types,
"Coupling",
&[("AC", 0.0), ("DC", 1.0)],
true,
)?;
let main_sequence = sequence_file.get_sequence_by_name("MainSequence")?;
main_sequence.locals()?.new_sub_property(
"InputCoupling",
PropValType::NamedType,
false,
"Coupling",
INSERT_IF_MISSING,
)?;
println!(
"Registered custom data types ({} in file):",
types.num_types()?
);
print_enumerators(&coupling)?;
println!(
"\nCoupling version before update: {}",
coupling.type_version()?
);
coupling.update_enumerators(&enumerator_array(
&engine,
&[("AC", 0.0), ("DC", 1.0), ("GND", 2.0)],
true,
)?)?;
let version = coupling.type_version()?;
let mut fields = version.split('.');
let major: u32 = fields.next().unwrap_or("0").parse().unwrap_or(0);
let minor: u32 = fields.next().unwrap_or("0").parse().unwrap_or(0);
coupling.set_type_version(&format!("{major}.{}.0.0", minor + 1))?;
println!(
"Coupling version after update: {}",
coupling.type_version()?
);
println!("\nCoupling now defines (InputCoupling reflects this):");
print_enumerators(&coupling)?;
file.inc_change_count()?;
let path = std::env::temp_dir().join("rs_teststand_with_custom_types.seq");
sequence_file.save(&path.to_string_lossy())?;
println!("\nSaved to {}", path.display());
engine.release_sequence_file_ex(sequence_file, NO_OPTIONS)?;
Ok(())
}