pub struct SignalConfig(/* private fields */);Expand description
The configuration component of a Signal. Allows for configuration of its properties, managing its streaming sources, and sending packets through its connections.
The Signal config is most often accessible only to the devices or function blocks that own
the signal. They react on property, or input signal changes to modify a signal’s data descriptor,
and send processed/acquired data down its signal path.
Wrapper over the openDAQ daqSignalConfig interface.
Implementations§
Source§impl SignalConfig
impl SignalConfig
Clears the list of related signals.
Calls the openDAQ C function daqSignalConfig_clearRelatedSignals().
Sourcepub fn signal(
context: &Context,
parent: Option<&Component>,
local_id: &str,
class_name: Option<&str>,
) -> Result<SignalConfig>
pub fn signal( context: &Context, parent: Option<&Component>, local_id: &str, class_name: Option<&str>, ) -> Result<SignalConfig>
Calls the openDAQ C function daqSignalConfig_createSignal().
Examples found in repository?
62fn main() -> opendaq::Result<()> {
63 let instance = Instance::new()?;
64 let context = instance.context()?.expect("instance context");
65
66 let domain_descriptor = {
67 let builder = DataDescriptorBuilder::new()?;
68 builder.set_sample_type(SampleType::Int64)?;
69 builder.set_name("time")?;
70 // Origin stays at the epoch; the wall-clock time lives in the ticks.
71 builder.set_origin("1970-01-01T00:00:00Z")?;
72 builder.set_tick_resolution(TICK_RESOLUTION)?;
73 builder.set_unit(&Unit::new(-1, "s", "second", "time")?)?;
74 builder.set_rule(&DataRule::linear(TICKS_PER_SAMPLE, 0)?)?;
75 builder.build()?.expect("domain descriptor")
76 };
77 let value_descriptor = {
78 let builder = DataDescriptorBuilder::new()?;
79 builder.set_sample_type(SampleType::Float64)?;
80 builder.set_name("values")?;
81 builder.build()?.expect("value descriptor")
82 };
83
84 let domain_signal = SignalConfig::signal(&context, None, "time", None)?;
85 domain_signal.set_descriptor(&domain_descriptor)?;
86 let signal = SignalConfig::signal(&context, None, "values", None)?;
87 signal.set_descriptor(&value_descriptor)?;
88 signal.set_domain_signal(&domain_signal)?;
89
90 let reader = StreamReader::<f64, i64>::with_options(
91 &signal,
92 StreamReaderOptions {
93 timeout_type: ReadTimeoutType::Any,
94 ..Default::default()
95 },
96 )?;
97
98 // Stream a few seconds of a 5 Hz signal in real time. Each one-second
99 // batch is one packet of 5 samples; the ticks stay contiguous across
100 // batches (batch k starts at start_tick + k*1000 ms), so the whole run is
101 // an unbroken 5 Hz stream anchored to when the program started.
102 let batches = 3;
103 let start_tick = now_ticks();
104 let to_timestamp = TickConverter::from_signal(&signal)?;
105 println!(
106 "Streaming {SAMPLES_PER_SECOND} samples/second, starting at {}",
107 time_of_day(to_timestamp.tick_to_unix_nanos(start_tick))
108 );
109 for batch in 0..batches {
110 let base_sample = batch * SAMPLES_PER_SECOND;
111 let offset = start_tick + base_sample as i64 * TICKS_PER_SAMPLE;
112 let samples: Vec<f64> = (0..SAMPLES_PER_SECOND)
113 .map(|i| (2.0 * PI * ((base_sample + i) as f64 / 25.0)).sin())
114 .collect();
115 send_chunk(
116 &signal,
117 &domain_descriptor,
118 &value_descriptor,
119 offset,
120 &samples,
121 )?;
122
123 let (values, ticks) = reader.read_with_domain(100, 1000)?;
124 for (value, tick) in values.iter().zip(&ticks) {
125 println!(
126 " {} -> {value:.4}",
127 time_of_day(to_timestamp.tick_to_unix_nanos(*tick))
128 );
129 }
130 std::thread::sleep(Duration::from_secs(1));
131 }
132 Ok(())
133}Sourcepub fn with_descriptor(
context: &Context,
descriptor: &DataDescriptor,
parent: Option<&Component>,
local_id: &str,
class_name: Option<&str>,
) -> Result<SignalConfig>
pub fn with_descriptor( context: &Context, descriptor: &DataDescriptor, parent: Option<&Component>, local_id: &str, class_name: Option<&str>, ) -> Result<SignalConfig>
Calls the openDAQ C function daqSignalConfig_createSignalWithDescriptor().
Sourcepub fn send_packet(&self, packet: &Packet) -> Result<()>
pub fn send_packet(&self, packet: &Packet) -> Result<()>
Sends a packet through all connections of the signal.
§Parameters
packet: The packet to be sent.
Calls the openDAQ C function daqSignalConfig_sendPacket().
Examples found in repository?
48fn send_chunk(
49 signal: &SignalConfig,
50 domain_descriptor: &DataDescriptor,
51 value_descriptor: &DataDescriptor,
52 offset: i64,
53 samples: &[f64],
54) -> opendaq::Result<()> {
55 let count = samples.len();
56 let domain_packet = DataPacket::new(domain_descriptor, count, offset)?;
57 let packet = DataPacket::with_domain(&domain_packet, value_descriptor, count, 0)?;
58 packet.set_data::<f64>(samples)?;
59 signal.send_packet(&packet)
60}Sourcepub fn send_packet_and_steal_ref(&self, packet: &Packet) -> Result<()>
pub fn send_packet_and_steal_ref(&self, packet: &Packet) -> Result<()>
Sends a packet through all connections of the signal. Ownership of the packet is transfered.
§Parameters
packet: The packet to be sent. After calling the method, the packet should not be touched again. The ownership of the packet is taken by underlying connections and it could be destroyed before the function returns.
Calls the openDAQ C function daqSignalConfig_sendPacketAndStealRef().
Sourcepub fn send_packets(&self, packets: &[Packet]) -> Result<()>
pub fn send_packets(&self, packets: &[Packet]) -> Result<()>
Sends multiple packets through all connections of the signal.
§Parameters
packets: The packets to be sent. Sending multiple packets creates a single notification to input port.
Calls the openDAQ C function daqSignalConfig_sendPackets().
Sourcepub fn send_packets_and_steal_ref(&self, packets: &[Packet]) -> Result<()>
pub fn send_packets_and_steal_ref(&self, packets: &[Packet]) -> Result<()>
Sends multiple packets through all connections of the signal. Ownership of the packets is transfered.
§Parameters
packets: The packets to be sent. After calling the method, the packets should not be touched again. The ownership of the packets is taken by underlying connections and they could be destroyed before the function returns.
Calls the openDAQ C function daqSignalConfig_sendPacketsAndStealRef().
Sourcepub fn set_descriptor(&self, descriptor: &DataDescriptor) -> Result<()>
pub fn set_descriptor(&self, descriptor: &DataDescriptor) -> Result<()>
Sets the data descriptor.
§Parameters
descriptor: The data descriptor. Setting the data descriptor triggers a Descriptor changed event packet to be sent to all connections of the signal. If the signal is a domain signal of another, that signal also sends a Descriptor changed event to all its connections.
Calls the openDAQ C function daqSignalConfig_setDescriptor().
Examples found in repository?
62fn main() -> opendaq::Result<()> {
63 let instance = Instance::new()?;
64 let context = instance.context()?.expect("instance context");
65
66 let domain_descriptor = {
67 let builder = DataDescriptorBuilder::new()?;
68 builder.set_sample_type(SampleType::Int64)?;
69 builder.set_name("time")?;
70 // Origin stays at the epoch; the wall-clock time lives in the ticks.
71 builder.set_origin("1970-01-01T00:00:00Z")?;
72 builder.set_tick_resolution(TICK_RESOLUTION)?;
73 builder.set_unit(&Unit::new(-1, "s", "second", "time")?)?;
74 builder.set_rule(&DataRule::linear(TICKS_PER_SAMPLE, 0)?)?;
75 builder.build()?.expect("domain descriptor")
76 };
77 let value_descriptor = {
78 let builder = DataDescriptorBuilder::new()?;
79 builder.set_sample_type(SampleType::Float64)?;
80 builder.set_name("values")?;
81 builder.build()?.expect("value descriptor")
82 };
83
84 let domain_signal = SignalConfig::signal(&context, None, "time", None)?;
85 domain_signal.set_descriptor(&domain_descriptor)?;
86 let signal = SignalConfig::signal(&context, None, "values", None)?;
87 signal.set_descriptor(&value_descriptor)?;
88 signal.set_domain_signal(&domain_signal)?;
89
90 let reader = StreamReader::<f64, i64>::with_options(
91 &signal,
92 StreamReaderOptions {
93 timeout_type: ReadTimeoutType::Any,
94 ..Default::default()
95 },
96 )?;
97
98 // Stream a few seconds of a 5 Hz signal in real time. Each one-second
99 // batch is one packet of 5 samples; the ticks stay contiguous across
100 // batches (batch k starts at start_tick + k*1000 ms), so the whole run is
101 // an unbroken 5 Hz stream anchored to when the program started.
102 let batches = 3;
103 let start_tick = now_ticks();
104 let to_timestamp = TickConverter::from_signal(&signal)?;
105 println!(
106 "Streaming {SAMPLES_PER_SECOND} samples/second, starting at {}",
107 time_of_day(to_timestamp.tick_to_unix_nanos(start_tick))
108 );
109 for batch in 0..batches {
110 let base_sample = batch * SAMPLES_PER_SECOND;
111 let offset = start_tick + base_sample as i64 * TICKS_PER_SAMPLE;
112 let samples: Vec<f64> = (0..SAMPLES_PER_SECOND)
113 .map(|i| (2.0 * PI * ((base_sample + i) as f64 / 25.0)).sin())
114 .collect();
115 send_chunk(
116 &signal,
117 &domain_descriptor,
118 &value_descriptor,
119 offset,
120 &samples,
121 )?;
122
123 let (values, ticks) = reader.read_with_domain(100, 1000)?;
124 for (value, tick) in values.iter().zip(&ticks) {
125 println!(
126 " {} -> {value:.4}",
127 time_of_day(to_timestamp.tick_to_unix_nanos(*tick))
128 );
129 }
130 std::thread::sleep(Duration::from_secs(1));
131 }
132 Ok(())
133}Sourcepub fn set_domain_signal(&self, signal: &Signal) -> Result<()>
pub fn set_domain_signal(&self, signal: &Signal) -> Result<()>
Sets the domain signal reference.
§Parameters
signal: The domain signal. Setting a new domain signal triggers a Descriptor changed event packet to be sent to all connections of the signal.
Calls the openDAQ C function daqSignalConfig_setDomainSignal().
Examples found in repository?
62fn main() -> opendaq::Result<()> {
63 let instance = Instance::new()?;
64 let context = instance.context()?.expect("instance context");
65
66 let domain_descriptor = {
67 let builder = DataDescriptorBuilder::new()?;
68 builder.set_sample_type(SampleType::Int64)?;
69 builder.set_name("time")?;
70 // Origin stays at the epoch; the wall-clock time lives in the ticks.
71 builder.set_origin("1970-01-01T00:00:00Z")?;
72 builder.set_tick_resolution(TICK_RESOLUTION)?;
73 builder.set_unit(&Unit::new(-1, "s", "second", "time")?)?;
74 builder.set_rule(&DataRule::linear(TICKS_PER_SAMPLE, 0)?)?;
75 builder.build()?.expect("domain descriptor")
76 };
77 let value_descriptor = {
78 let builder = DataDescriptorBuilder::new()?;
79 builder.set_sample_type(SampleType::Float64)?;
80 builder.set_name("values")?;
81 builder.build()?.expect("value descriptor")
82 };
83
84 let domain_signal = SignalConfig::signal(&context, None, "time", None)?;
85 domain_signal.set_descriptor(&domain_descriptor)?;
86 let signal = SignalConfig::signal(&context, None, "values", None)?;
87 signal.set_descriptor(&value_descriptor)?;
88 signal.set_domain_signal(&domain_signal)?;
89
90 let reader = StreamReader::<f64, i64>::with_options(
91 &signal,
92 StreamReaderOptions {
93 timeout_type: ReadTimeoutType::Any,
94 ..Default::default()
95 },
96 )?;
97
98 // Stream a few seconds of a 5 Hz signal in real time. Each one-second
99 // batch is one packet of 5 samples; the ticks stay contiguous across
100 // batches (batch k starts at start_tick + k*1000 ms), so the whole run is
101 // an unbroken 5 Hz stream anchored to when the program started.
102 let batches = 3;
103 let start_tick = now_ticks();
104 let to_timestamp = TickConverter::from_signal(&signal)?;
105 println!(
106 "Streaming {SAMPLES_PER_SECOND} samples/second, starting at {}",
107 time_of_day(to_timestamp.tick_to_unix_nanos(start_tick))
108 );
109 for batch in 0..batches {
110 let base_sample = batch * SAMPLES_PER_SECOND;
111 let offset = start_tick + base_sample as i64 * TICKS_PER_SAMPLE;
112 let samples: Vec<f64> = (0..SAMPLES_PER_SECOND)
113 .map(|i| (2.0 * PI * ((base_sample + i) as f64 / 25.0)).sin())
114 .collect();
115 send_chunk(
116 &signal,
117 &domain_descriptor,
118 &value_descriptor,
119 offset,
120 &samples,
121 )?;
122
123 let (values, ticks) = reader.read_with_domain(100, 1000)?;
124 for (value, tick) in values.iter().zip(&ticks) {
125 println!(
126 " {} -> {value:.4}",
127 time_of_day(to_timestamp.tick_to_unix_nanos(*tick))
128 );
129 }
130 std::thread::sleep(Duration::from_secs(1));
131 }
132 Ok(())
133}Sourcepub fn set_last_value(&self, last_value: impl Into<Value>) -> Result<()>
pub fn set_last_value(&self, last_value: impl Into<Value>) -> Result<()>
Sets the last value of the signal.
§Parameters
last_value: The lastValue. This method is used to manually set the last value of the signal. Useful when automatic calculation of last value is disabled, usually due to performance reasons.
Calls the openDAQ C function daqSignalConfig_setLastValue().
Sets the list of related signals.
§Parameters
signals: The list of related signals.
Calls the openDAQ C function daqSignalConfig_setRelatedSignals().
Methods from Deref<Target = Signal>§
Sourcepub fn connections(&self) -> Result<Vec<Connection>>
pub fn connections(&self) -> Result<Vec<Connection>>
Gets the list of connections to input ports formed by the signal.
§Returns
connections: The list of connections.
Calls the openDAQ C function daqSignal_getConnections().
Sourcepub fn descriptor(&self) -> Result<Option<DataDescriptor>>
pub fn descriptor(&self) -> Result<Option<DataDescriptor>>
Gets the signal’s data descriptor.
§Returns
descriptor: The signal’s data descriptor. The descriptor contains metadata about the signal, providing information about its name, description,… and defines how the data in it’s packet’s buffers should be interpreted.
Calls the openDAQ C function daqSignal_getDescriptor().
Examples found in repository?
7fn main() -> opendaq::Result<()> {
8 let instance = Instance::new()?;
9 instance.add_device("daqref://device0")?;
10
11 let channel = instance
12 .find_component("Dev/RefDev0/IO/AI/RefCh0")?
13 .expect("reference channel not found")
14 .cast::<Channel>()?;
15 channel.set_property_value("Waveform", 0)?; // 0 = Sine
16 channel.set_property_value("Frequency", 125.0)?;
17 channel.set_property_value("Amplitude", 5.0)?;
18 channel.set_property_value("NoiseAmplitude", 0.1)?;
19
20 let fft = instance
21 .add_function_block("RefFBModuleFFT")?
22 .expect("FFT function block not found");
23 fft.set_property_value("BlockSize", 16)?;
24 fft.input_ports()?[0].connect(&channel.signals()?[0])?;
25 let signal = &fft.signals()?[0];
26
27 // Wait for the block to publish its output descriptor, then read the
28 // frequency axis off the value descriptor's single dimension.
29 std::thread::sleep(std::time::Duration::from_secs(1));
30 let descriptor = signal
31 .descriptor()?
32 .expect("output descriptor not published");
33 let dimension = &descriptor.dimensions()?[0];
34 let axis: Vec<f64> = dimension
35 .labels()?
36 .iter()
37 .map(|label| label.as_f64().expect("numeric frequency label"))
38 .collect();
39
40 // Read 5 samples. Each sample is a full spectrum, so `read` returns a
41 // (samples x bins) matrix; retry until 5 rows have arrived (the first
42 // reads may come back short while the stream warms up).
43 let reader = StreamReader::<f64>::new(signal)?;
44 let mut spectra = reader.read(5, 1000)?;
45 for _ in 0..50 {
46 if spectra.sample_count() == 5 {
47 break;
48 }
49 spectra = reader.read(5, 1000)?;
50 }
51
52 // Print the axis down the rows and one column of amplitudes per sample.
53 // The 125 Hz tone dominates a single bin (~5, our amplitude) while noise
54 // fills the rest with small values. The reference block labels its bins
55 // one step (31.25 Hz) below the true bin centre, so the tone lands in the
56 // 93.75 Hz row.
57 println!(
58 "{} spectrum, {} bins, {}\n",
59 dimension.name()?,
60 axis.len(),
61 dimension.unit()?.expect("dimension unit").symbol()?
62 );
63 print!("{:>12}", "freq (Hz)");
64 for sample in 1..=spectra.sample_count() {
65 print!("{:>14}", format!("sample {sample}"));
66 }
67 println!();
68 let rows: Vec<&[f64]> = spectra.rows().collect();
69 for (bin, frequency) in axis.iter().enumerate() {
70 print!("{frequency:>12.2}");
71 for row in &rows {
72 print!("{:>14.4}", row[bin]);
73 }
74 println!();
75 }
76 Ok(())
77}Sourcepub fn domain_signal(&self) -> Result<Option<Signal>>
pub fn domain_signal(&self) -> Result<Option<Signal>>
Gets the signal that carries its domain data.
§Returns
signal: The domain signal. The domain signal contains domain (most often time) data that is used to interpret a signal’s data in a given domain. It has the same sampling rate as the signal.
Calls the openDAQ C function daqSignal_getDomainSignal().
Sourcepub fn last_value(&self) -> Result<Value>
pub fn last_value(&self) -> Result<Value>
Gets the signal last value.
§Returns
value: The IBaseObject value can be a nullptr if there is no value, or if the data type is not supported by the function. If a value is assigned, it can be cast based on the signal description to IFloat if the type is Float32 or Float64, to IInteger if the type is Int8 through Int64 or UInt8 through UInt64, to IComplexNumber if the type is ComplexFloat32 or ComplexFloat64, to IRange if the type is RangeInt64, to IString if the type is String, to IStruct if the type is Struct, and to IList of the forementioned types if there is exactly one dimension. For String type signals in binary data packets, the string data must be encoded as UTF-8 strings. The string length is determined by the sample size, and the string does not need to be null-terminated. The method extracts the string value from the packet data and returns it as an IString object.
Calls the openDAQ C function daqSignal_getLastValue().
Sourcepub fn public(&self) -> Result<bool>
pub fn public(&self) -> Result<bool>
Returns true if the signal is public; false otherwise.
§Returns
is_public: True if the signal is public; false otherwise. Public signals are visible to clients connected to the device, and are streamed.
Calls the openDAQ C function daqSignal_getPublic().
Gets a list of related signals.
§Returns
signals: The list of related signals. Signals within the related signals list are facilitate the interpretation of a given signal’s data, or are otherwise relevant when working with the signal.
Calls the openDAQ C function daqSignal_getRelatedSignals().
Sourcepub fn streamed(&self) -> Result<bool>
pub fn streamed(&self) -> Result<bool>
Returns true if the signal is streamed; false otherwise.
§Returns
streamed: True if the signal is streamed; false otherwise. A streamed signal receives packets from a streaming server and forwards packets on the signal path. Method always setsstreamedparameter to False if the signal is local to the current Instance.
Calls the openDAQ C function daqSignal_getStreamed().
Sourcepub fn set_public(&self, is_public: bool) -> Result<()>
pub fn set_public(&self, is_public: bool) -> Result<()>
Sets the signal to be either public or private.
§Parameters
is_public: If false, the signal is set to private; if true, the signal is set to be public. Public signals are visible to clients connected to the device, and are streamed.
Calls the openDAQ C function daqSignal_setPublic().
Sourcepub fn set_streamed(&self, streamed: bool) -> Result<()>
pub fn set_streamed(&self, streamed: bool) -> Result<()>
Sets the signal to be either streamed or not.
§Parameters
streamed: The new streamed state of the signal. A streamed signal receives packets from a streaming server and forwards packets on the signal path. Setting the “Streamed” flag has no effect if the signal is local to the current Instance. Method returns OPENDAQ_IGNORED if that is the case.
Calls the openDAQ C function daqSignal_setStreamed().
Methods from Deref<Target = Component>§
Sourcepub fn find_component(&self, id: &str) -> Result<Option<Component>>
pub fn find_component(&self, id: &str) -> Result<Option<Component>>
Finds the component (signal/device/function block) with the specified (global) id.
§Parameters
id: The id of the component to search for.
§Returns
out_component: The resulting component. If the component parameter is true, the starting component is the root device. The id provided should be in relative form from the starting component. E.g., to find a signal in the starting component, the id should be in the form of “Dev/dev_id/Ch/ch_id/Sig/sig_id.
Calls the openDAQ C function daqComponent_findComponent().
Examples found in repository?
More examples
8fn main() -> opendaq::Result<()> {
9 let instance = Instance::new()?;
10 instance.add_device("daqref://device0")?;
11
12 let channel = instance
13 .find_component("Dev/RefDev0/IO/AI/RefCh0")?
14 .expect("reference channel not found")
15 .cast::<Channel>()?;
16 let signal = &channel.signals()?[0];
17
18 let reader = StreamReader::<f64>::new(signal)?;
19 println!("some samples: {:?}", reader.read(100, 1000)?.values());
20 println!("and more samples: {:?}", reader.read(100, 1000)?.values());
21 println!("and more still: {:?}", reader.read(100, 1000)?.values());
22 Ok(())
23}39fn main() -> opendaq::Result<()> {
40 let instance = Instance::new()?;
41 instance.add_device("daqref://device0")?;
42
43 let channel = instance
44 .find_component("Dev/RefDev0/IO/AI/RefCh0")?
45 .expect("reference channel not found")
46 .cast::<Channel>()?;
47 let signal = &channel.signals()?[0];
48
49 let reader = StreamReader::<f64>::new(signal)?;
50 let converter = TickConverter::from_signal(signal)?;
51
52 let (values, ticks) = reader.read_with_domain(10, 2000)?;
53 println!("Read {} samples:", values.sample_count());
54 for (value, tick) in values.iter().zip(&ticks) {
55 println!(
56 " {value:.6} @ {}",
57 timestamp_to_string(converter.tick_to_unix_nanos(*tick))
58 );
59 }
60 Ok(())
61}10fn main() -> opendaq::Result<()> {
11 let instance = Instance::new()?;
12 instance.add_device("daqref://device0")?;
13
14 let channel = instance
15 .find_component("Dev/RefDev0/IO/AI/RefCh0")?
16 .expect("reference channel not found")
17 .cast::<Channel>()?;
18
19 let core_event = instance
20 .context()?
21 .expect("context")
22 .on_core_event()?
23 .expect("core event");
24
25 // The handler may run on openDAQ's own threads. Its args come in as a
26 // generic object; cast to CoreEventArgs for the event name and the
27 // per-event-type parameters ("Name" holds the changed property's name).
28 let handler = core_event.subscribe(|_sender, args| {
29 let Some(args) = args else { return };
30 let Ok(event) = args.cast::<CoreEventArgs>() else {
31 return;
32 };
33 let name = event.event_name().unwrap_or_default();
34 let parameters = event.parameters().unwrap_or_default();
35 let changed = parameters
36 .get("Name")
37 .map(ToString::to_string)
38 .unwrap_or_default();
39 println!(" {name}: {changed}");
40 })?;
41
42 // While subscribed, each property change is reported by the handler above.
43 println!("subscribed:");
44 channel.set_property_value("Frequency", 25.0)?;
45 channel.set_property_value("Amplitude", 7.5)?;
46
47 // Unsubscribing removes the handler; further changes fire nothing.
48 core_event.unsubscribe(&handler)?;
49 println!("unsubscribed (no lines expected below):");
50 channel.set_property_value("Frequency", 50.0)?;
51
52 Ok(())
53}7fn main() -> opendaq::Result<()> {
8 let instance = Instance::new()?;
9
10 println!("Available devices:");
11 for info in instance.available_devices()? {
12 println!(" - {}: {}", info.connection_string()?, info.name()?);
13 }
14
15 let device = instance.add_device("daqref://device0")?.expect("device");
16 println!("Added device: {}", device.name()?);
17
18 let channel = instance
19 .find_component("Dev/RefDev0/IO/AI/RefCh0")?
20 .expect("reference channel not found")
21 .cast::<Channel>()?;
22 let signal = &channel.signals()?[0];
23
24 // Batched property updates.
25 {
26 let batch = BatchedPropertyUpdate::new(&[&device, &channel])?;
27 device.set_property_value("GlobalSampleRate", 1000)?;
28 channel.set_property_value("Frequency", 50.0)?;
29 batch.commit()?;
30 }
31 println!(
32 "GlobalSampleRate = {}",
33 device.property_value("GlobalSampleRate")?
34 );
35
36 // Stream reading with domain + tick conversion.
37 let reader = StreamReader::<f64>::new(signal)?;
38 let (samples, ticks) = reader.read_with_domain(100, 2000)?;
39 println!(
40 "read {} samples, {} ticks",
41 samples.sample_count(),
42 ticks.len()
43 );
44 let converter = TickConverter::from_signal(signal)?;
45 if let Some(first) = ticks.first() {
46 println!(
47 "first tick {} -> {:?}",
48 first,
49 converter.tick_to_system_time(*first)
50 );
51 }
52
53 // Callables: a Rust closure as an openDAQ function, called through openDAQ.
54 let sum = FunctionObject::from_fn(|args| {
55 let a = args[0].as_i64().unwrap_or(0);
56 let b = args[1].as_i64().unwrap_or(0);
57 Ok(Value::from(a + b))
58 })?;
59 let result = sum.call(&[Value::from(20), Value::from(22)])?;
60 println!("sum(20, 22) = {result}");
61
62 // Events: subscribe to property changes on the channel.
63 let events = channel
64 .on_property_value_write("Amplitude")?
65 .expect("event");
66 let handler = events.subscribe(|_sender, args| {
67 if let Some(args) = args {
68 println!(" event fired: {args}");
69 }
70 })?;
71 channel.set_property_value("Amplitude", 2.5)?;
72 events.unsubscribe(&handler)?;
73 channel.set_property_value("Amplitude", 1.0)?;
74 println!("Amplitude = {}", channel.property_value("Amplitude")?);
75
76 Ok(())
77}18fn main() -> opendaq::Result<()> {
19 // Instance::new() already loads the bundled modules; build from an
20 // InstanceBuilder when you want to control the module search path.
21 let builder = InstanceBuilder::new()?;
22 // The bundled modules (reference device, function blocks, streaming):
23 let bundled = opendaq::native_library_directory().expect("native libraries");
24 builder.set_module_path(&bundled.to_string_lossy())?;
25 // Your own modules folder:
26 // builder.add_module_path("/path/to/your/modules")?;
27 let instance = Instance::from_builder(&builder)?;
28 instance.add_device("daqref://device0")?;
29
30 let channel = instance
31 .find_component("Dev/RefDev0/IO/AI/RefCh0")?
32 .expect("reference channel not found")
33 .cast::<Channel>()?;
34 channel.set_property_value("Amplitude", 5.0)?;
35 channel.set_property_value("DC", 1.0)?;
36
37 let statistics = instance
38 .add_function_block("RefFBModuleStatistics")?
39 .expect("statistics function block");
40 statistics.set_property_value("BlockSize", 100)?;
41
42 let status = statistics.status_container()?.expect("status container");
43 println!(
44 "Before connect: {} ({})",
45 status.status("ComponentStatus")?.expect("status").value()?,
46 status.status_message("ComponentStatus")?
47 );
48
49 let port = &statistics.input_ports()?[0];
50 let signal = &channel.signals()?[0];
51 port.connect(signal)?;
52
53 println!(
54 "After connect: {} ({})",
55 status.status("ComponentStatus")?.expect("status").value()?,
56 status.status_message("ComponentStatus")?
57 );
58
59 let outputs = statistics.signals()?;
60 let avg = signal_by_local_id(&outputs, "avg")?.expect("avg signal");
61 let rms = signal_by_local_id(&outputs, "rms")?.expect("rms signal");
62 let reader = MultiReader::<f64>::new(&[avg, rms])?;
63
64 // The first reads may return nothing while the block waits for a complete
65 // input descriptor (the multi reader by default doesn't skip events), so
66 // retry until samples arrive.
67 for _attempt in 0..20 {
68 let values = reader.read(5, 1000)?;
69 if !values[0].is_empty() {
70 println!("{:>10}{:>12}", "avg", "rms");
71 for (a, r) in values[0].iter().zip(&values[1]) {
72 println!("{a:>10.4}{r:>12.4}");
73 }
74 return Ok(());
75 }
76 }
77 println!("Statistics block produced no samples in time.");
78 Ok(())
79}Sourcepub fn active(&self) -> Result<bool>
pub fn active(&self) -> Result<bool>
Returns true if the component is active; false otherwise.
§Returns
active: True if the component is active; false otherwise. A component is active if its local active state is true and its parent is active. An active component acquires data, performs calculations and send packets on the signal path.
Calls the openDAQ C function daqComponent_getActive().
Sourcepub fn context(&self) -> Result<Option<Context>>
pub fn context(&self) -> Result<Option<Context>>
Gets the context object.
§Returns
context: The context object.
Calls the openDAQ C function daqComponent_getContext().
Examples found in repository?
10fn main() -> opendaq::Result<()> {
11 let instance = Instance::new()?;
12 instance.add_device("daqref://device0")?;
13
14 let channel = instance
15 .find_component("Dev/RefDev0/IO/AI/RefCh0")?
16 .expect("reference channel not found")
17 .cast::<Channel>()?;
18
19 let core_event = instance
20 .context()?
21 .expect("context")
22 .on_core_event()?
23 .expect("core event");
24
25 // The handler may run on openDAQ's own threads. Its args come in as a
26 // generic object; cast to CoreEventArgs for the event name and the
27 // per-event-type parameters ("Name" holds the changed property's name).
28 let handler = core_event.subscribe(|_sender, args| {
29 let Some(args) = args else { return };
30 let Ok(event) = args.cast::<CoreEventArgs>() else {
31 return;
32 };
33 let name = event.event_name().unwrap_or_default();
34 let parameters = event.parameters().unwrap_or_default();
35 let changed = parameters
36 .get("Name")
37 .map(ToString::to_string)
38 .unwrap_or_default();
39 println!(" {name}: {changed}");
40 })?;
41
42 // While subscribed, each property change is reported by the handler above.
43 println!("subscribed:");
44 channel.set_property_value("Frequency", 25.0)?;
45 channel.set_property_value("Amplitude", 7.5)?;
46
47 // Unsubscribing removes the handler; further changes fire nothing.
48 core_event.unsubscribe(&handler)?;
49 println!("unsubscribed (no lines expected below):");
50 channel.set_property_value("Frequency", 50.0)?;
51
52 Ok(())
53}More examples
19fn main() -> opendaq::Result<()> {
20 let work_dir = std::env::temp_dir().join("opendaq-rs-log-example");
21 let downloads = work_dir.join("downloads");
22 fs::create_dir_all(&downloads).expect("create working directories");
23 let device_log = work_dir.join("ref_device_simulator.log");
24 let device_log_path = device_log.to_string_lossy().into_owned();
25
26 // Start from a clean log so the reported size reflects only this run.
27 let _ = fs::remove_file(&device_log);
28
29 let builder = InstanceBuilder::new()?;
30 // Find the bundled modules.
31 let modules = opendaq::native_library_directory().expect("bundled native modules");
32 builder.set_module_path(&modules.to_string_lossy())?;
33 builder.add_logger_sink(&LoggerSink::basic_file(&device_log_path)?)?;
34 let instance = Instance::from_builder(&builder)?;
35
36 // The reference device reads these two properties from its add-device config.
37 let config = PropertyObject::new()?;
38 config.add_property(&Property::bool("EnableLogging", true, true)?)?;
39 config.add_property(&Property::string("LoggingPath", &device_log_path, true)?)?;
40
41 let device = instance
42 .add_device_with("daqref://device0", Some(&config))?
43 .expect("reference device");
44
45 // Flush the logger so everything buffered so far is actually on disk
46 // before we read it.
47 let context = instance.context()?.expect("instance context");
48 context.logger()?.expect("instance logger").flush()?;
49
50 let infos = device.log_file_infos()?;
51 if infos.is_empty() {
52 println!("Device exposes no log files.");
53 return Ok(());
54 }
55 println!("Device exposes {} log file(s):", infos.len());
56 println!();
57 for info in infos {
58 let id = info.id()?;
59 let destination = downloads.join(info.name()?);
60 println!("- {}", info.name()?);
61 println!(" id: {id}");
62 println!(" size: {} bytes", info.size()?);
63 println!(" encoding: {}", info.encoding()?);
64 println!(" last-modified: {}", info.last_modified()?);
65 // Size/offset let you fetch just part of a file; here, a short head preview.
66 println!(" preview: {:?}", device.log_with(&id, 60, 0)?);
67 // Plain `log` fetches the whole file in one call.
68 let content = device.log(&id)?;
69 fs::write(&destination, &content).expect("write the downloaded log");
70 println!(
71 " downloaded {} chars -> {}",
72 content.len(),
73 destination.display()
74 );
75 println!();
76 }
77 Ok(())
78}62fn main() -> opendaq::Result<()> {
63 let instance = Instance::new()?;
64 let context = instance.context()?.expect("instance context");
65
66 let domain_descriptor = {
67 let builder = DataDescriptorBuilder::new()?;
68 builder.set_sample_type(SampleType::Int64)?;
69 builder.set_name("time")?;
70 // Origin stays at the epoch; the wall-clock time lives in the ticks.
71 builder.set_origin("1970-01-01T00:00:00Z")?;
72 builder.set_tick_resolution(TICK_RESOLUTION)?;
73 builder.set_unit(&Unit::new(-1, "s", "second", "time")?)?;
74 builder.set_rule(&DataRule::linear(TICKS_PER_SAMPLE, 0)?)?;
75 builder.build()?.expect("domain descriptor")
76 };
77 let value_descriptor = {
78 let builder = DataDescriptorBuilder::new()?;
79 builder.set_sample_type(SampleType::Float64)?;
80 builder.set_name("values")?;
81 builder.build()?.expect("value descriptor")
82 };
83
84 let domain_signal = SignalConfig::signal(&context, None, "time", None)?;
85 domain_signal.set_descriptor(&domain_descriptor)?;
86 let signal = SignalConfig::signal(&context, None, "values", None)?;
87 signal.set_descriptor(&value_descriptor)?;
88 signal.set_domain_signal(&domain_signal)?;
89
90 let reader = StreamReader::<f64, i64>::with_options(
91 &signal,
92 StreamReaderOptions {
93 timeout_type: ReadTimeoutType::Any,
94 ..Default::default()
95 },
96 )?;
97
98 // Stream a few seconds of a 5 Hz signal in real time. Each one-second
99 // batch is one packet of 5 samples; the ticks stay contiguous across
100 // batches (batch k starts at start_tick + k*1000 ms), so the whole run is
101 // an unbroken 5 Hz stream anchored to when the program started.
102 let batches = 3;
103 let start_tick = now_ticks();
104 let to_timestamp = TickConverter::from_signal(&signal)?;
105 println!(
106 "Streaming {SAMPLES_PER_SECOND} samples/second, starting at {}",
107 time_of_day(to_timestamp.tick_to_unix_nanos(start_tick))
108 );
109 for batch in 0..batches {
110 let base_sample = batch * SAMPLES_PER_SECOND;
111 let offset = start_tick + base_sample as i64 * TICKS_PER_SAMPLE;
112 let samples: Vec<f64> = (0..SAMPLES_PER_SECOND)
113 .map(|i| (2.0 * PI * ((base_sample + i) as f64 / 25.0)).sin())
114 .collect();
115 send_chunk(
116 &signal,
117 &domain_descriptor,
118 &value_descriptor,
119 offset,
120 &samples,
121 )?;
122
123 let (values, ticks) = reader.read_with_domain(100, 1000)?;
124 for (value, tick) in values.iter().zip(&ticks) {
125 println!(
126 " {} -> {value:.4}",
127 time_of_day(to_timestamp.tick_to_unix_nanos(*tick))
128 );
129 }
130 std::thread::sleep(Duration::from_secs(1));
131 }
132 Ok(())
133}Sourcepub fn description(&self) -> Result<String>
pub fn description(&self) -> Result<String>
Gets the description of the component.
§Returns
description: The description of the component. Empty if not configured. The object that implements this interface defines how the description is specified.
Calls the openDAQ C function daqComponent_getDescription().
Sourcepub fn global_id(&self) -> Result<String>
pub fn global_id(&self) -> Result<String>
Gets the global ID of the component.
§Returns
global_id: The global ID of the component. Represents the identifier that is globally unique. Globally unique identifier is composed from local identifiers from the parent components separated by ‘/’ character. Device component must make sure that its ID is globally unique.
Calls the openDAQ C function daqComponent_getGlobalId().
Sourcepub fn local_active(&self) -> Result<bool>
pub fn local_active(&self) -> Result<bool>
Returns true if the component is local active; false otherwise.
§Returns
local_active: True if the component is local active; false otherwise. An active component acquires data, performs calculations and send packets on the signal path. Note that is local active is True, the component may still be inactive if its parents are inactive.
Calls the openDAQ C function daqComponent_getLocalActive().
Sourcepub fn local_id(&self) -> Result<String>
pub fn local_id(&self) -> Result<String>
Gets the local ID of the component.
§Returns
local_id: The local ID of the component. Represents the identifier that is unique in a relation to the parent component. There is no predefined format for local ID. It is a string defined by its parent component.
Calls the openDAQ C function daqComponent_getLocalId().
Examples found in repository?
More examples
22fn show<T: Interface>(label: &str, components: Vec<T>) -> opendaq::Result<()> {
23 let ids = components
24 .iter()
25 .map(|c| c.to_base_object().cast::<Component>()?.local_id())
26 .collect::<opendaq::Result<Vec<_>>>()?;
27 let listing = if ids.is_empty() {
28 "(none)".to_string()
29 } else {
30 ids.join(", ")
31 };
32 println!("{label}\n => {listing}\n");
33 Ok(())
34}
35
36fn main() -> opendaq::Result<()> {
37 let instance = Instance::new()?;
38 instance.add_device("daqref://device0")?;
39 let root = instance.root_device()?.expect("root device");
40
41 // Give a couple of channels some tags, so the tag filter has something to
42 // match. (RefCh0 and RefCh1 come from the reference device unlabelled.)
43 let everything = SearchFilter::recursive(&SearchFilter::any()?)?;
44 for channel in root.channels_with(Some(&everything))? {
45 let tags = channel.tags()?.expect("tags").cast::<TagsPrivate>()?;
46 tags.add("analog")?;
47 if channel.local_id()? == "RefCh0" {
48 tags.add("primary")?;
49 }
50 }
51
52 show(
53 "channels, no filter (immediate children only)",
54 root.channels()?,
55 )?;
56
57 show(
58 "channels, recursive(any)",
59 root.channels_with(Some(&SearchFilter::recursive(&SearchFilter::any()?)?))?,
60 )?;
61
62 show(
63 "channels, recursive(id = RefCh1)",
64 root.channels_with(Some(&SearchFilter::recursive(&SearchFilter::local_id(
65 "RefCh1",
66 )?)?))?,
67 )?;
68
69 let ai0_or_ai1 = SearchFilter::or(
70 &SearchFilter::local_id("AI0")?,
71 &SearchFilter::local_id("AI1")?,
72 )?;
73 show(
74 "signals, recursive(id = AI0 OR id = AI1)",
75 root.signals_with(Some(&SearchFilter::recursive(&ai0_or_ai1)?))?,
76 )?;
77
78 let not_ref_ch1 = SearchFilter::not(&SearchFilter::local_id("RefCh1")?)?;
79 show(
80 "channels, recursive(NOT id = RefCh1)",
81 root.channels_with(Some(&SearchFilter::recursive(¬_ref_ch1)?))?,
82 )?;
83
84 let analog_and_not_ref_ch1 = SearchFilter::and(
85 &SearchFilter::required_tags(vec!["analog"])?,
86 &SearchFilter::not(&SearchFilter::local_id("RefCh1")?)?,
87 )?;
88 show(
89 "channels, recursive(tag = analog AND NOT id = RefCh1)",
90 root.channels_with(Some(&SearchFilter::recursive(&analog_and_not_ref_ch1)?))?,
91 )?;
92
93 Ok(())
94}54fn draw_children(component: &Component, prefix: &str) -> opendaq::Result<()> {
55 let kids = children(component)?;
56 for (index, child) in kids.iter().enumerate() {
57 let last = index + 1 == kids.len();
58 let child_prefix = format!("{prefix}{}", if last { " " } else { "│ " });
59 println!(
60 "{prefix}{}{} : {} ({})",
61 if last { "└─ " } else { "├─ " },
62 child.name()?,
63 type_label(child),
64 child.local_id()?
65 );
66 draw_properties(child, &child_prefix)?;
67 draw_children(child, &child_prefix)?;
68 }
69 Ok(())
70}
71
72fn main() -> opendaq::Result<()> {
73 let instance = Instance::new()?;
74 instance.add_device("daqref://device0")?;
75
76 let root = instance.root_device()?.expect("root device");
77 println!(
78 "{} : {} ({})",
79 root.name()?,
80 type_label(&root),
81 root.local_id()?
82 );
83 draw_properties(&root, "")?;
84 draw_children(&root, "")
85}Sourcepub fn locked_attributes(&self) -> Result<Vec<String>>
pub fn locked_attributes(&self) -> Result<Vec<String>>
Gets a list of the component’s locked attributes. The locked attributes cannot be modified via their respective setters.
§Returns
attributes: A list of strings containing the names of locked attributes in capital case (eg. “Name”, “Description”).
Calls the openDAQ C function daqComponent_getLockedAttributes().
Sourcepub fn name(&self) -> Result<String>
pub fn name(&self) -> Result<String>
Gets the name of the component.
§Returns
name: The name of the component. Local ID if name is not configured. The object that implements this interface defines how the name is specified.
Calls the openDAQ C function daqComponent_getName().
Examples found in repository?
More examples
54fn draw_children(component: &Component, prefix: &str) -> opendaq::Result<()> {
55 let kids = children(component)?;
56 for (index, child) in kids.iter().enumerate() {
57 let last = index + 1 == kids.len();
58 let child_prefix = format!("{prefix}{}", if last { " " } else { "│ " });
59 println!(
60 "{prefix}{}{} : {} ({})",
61 if last { "└─ " } else { "├─ " },
62 child.name()?,
63 type_label(child),
64 child.local_id()?
65 );
66 draw_properties(child, &child_prefix)?;
67 draw_children(child, &child_prefix)?;
68 }
69 Ok(())
70}
71
72fn main() -> opendaq::Result<()> {
73 let instance = Instance::new()?;
74 instance.add_device("daqref://device0")?;
75
76 let root = instance.root_device()?.expect("root device");
77 println!(
78 "{} : {} ({})",
79 root.name()?,
80 type_label(&root),
81 root.local_id()?
82 );
83 draw_properties(&root, "")?;
84 draw_children(&root, "")
85}27fn probe_view_only_device(device: &Device) -> opendaq::Result<()> {
28 println!("Connected to {} as a view-only client.", device.name()?);
29 println!("Visible signals: {}", device.signals_recursive()?.len());
30 match first_writable_property_name(device)? {
31 Some(name) => {
32 // Write the property's current value back to itself: harmless if
33 // it were allowed, but a view-only connection must reject it.
34 let value = device.property_value(&name)?;
35 match device.set_property_value(&name, value) {
36 Ok(()) => println!("Unexpected: writing {name:?} was allowed."),
37 Err(err) => {
38 println!("Write to {name:?} refused, as expected for view-only: {err}")
39 }
40 }
41 }
42 None => println!("Device exposes no writable property to probe."),
43 }
44 Ok(())
45}7fn main() -> opendaq::Result<()> {
8 let instance = Instance::new()?;
9
10 println!("Available devices:");
11 for info in instance.available_devices()? {
12 println!(" - {}: {}", info.connection_string()?, info.name()?);
13 }
14
15 let device = instance.add_device("daqref://device0")?.expect("device");
16 println!("Added device: {}", device.name()?);
17
18 let channel = instance
19 .find_component("Dev/RefDev0/IO/AI/RefCh0")?
20 .expect("reference channel not found")
21 .cast::<Channel>()?;
22 let signal = &channel.signals()?[0];
23
24 // Batched property updates.
25 {
26 let batch = BatchedPropertyUpdate::new(&[&device, &channel])?;
27 device.set_property_value("GlobalSampleRate", 1000)?;
28 channel.set_property_value("Frequency", 50.0)?;
29 batch.commit()?;
30 }
31 println!(
32 "GlobalSampleRate = {}",
33 device.property_value("GlobalSampleRate")?
34 );
35
36 // Stream reading with domain + tick conversion.
37 let reader = StreamReader::<f64>::new(signal)?;
38 let (samples, ticks) = reader.read_with_domain(100, 2000)?;
39 println!(
40 "read {} samples, {} ticks",
41 samples.sample_count(),
42 ticks.len()
43 );
44 let converter = TickConverter::from_signal(signal)?;
45 if let Some(first) = ticks.first() {
46 println!(
47 "first tick {} -> {:?}",
48 first,
49 converter.tick_to_system_time(*first)
50 );
51 }
52
53 // Callables: a Rust closure as an openDAQ function, called through openDAQ.
54 let sum = FunctionObject::from_fn(|args| {
55 let a = args[0].as_i64().unwrap_or(0);
56 let b = args[1].as_i64().unwrap_or(0);
57 Ok(Value::from(a + b))
58 })?;
59 let result = sum.call(&[Value::from(20), Value::from(22)])?;
60 println!("sum(20, 22) = {result}");
61
62 // Events: subscribe to property changes on the channel.
63 let events = channel
64 .on_property_value_write("Amplitude")?
65 .expect("event");
66 let handler = events.subscribe(|_sender, args| {
67 if let Some(args) = args {
68 println!(" event fired: {args}");
69 }
70 })?;
71 channel.set_property_value("Amplitude", 2.5)?;
72 events.unsubscribe(&handler)?;
73 channel.set_property_value("Amplitude", 1.0)?;
74 println!("Amplitude = {}", channel.property_value("Amplitude")?);
75
76 Ok(())
77}Sourcepub fn on_component_core_event(&self) -> Result<Option<Event>>
pub fn on_component_core_event(&self) -> Result<Option<Event>>
Gets the Core Event object that triggers whenever a change to this component happens within the openDAQ core structure.
§Returns
event: The Core Event object. The event triggers with a Component reference and a CoreEventArgs object as arguments. The Core Event is triggered on various changes to the openDAQ Components. This includes changes to property values, addition/removal of child components, connecting signals to input ports and others. The event type can be identified via the event ID available within the CoreEventArgs object. Each event type has a set of predetermined parameters available in theparametersfield of the arguments. These can be used by any openDAQ server, or other listener to react to changes within the core structure.
Calls the openDAQ C function daqComponent_getOnComponentCoreEvent().
Sourcepub fn operation_mode(&self) -> Result<OperationModeType>
pub fn operation_mode(&self) -> Result<OperationModeType>
Gets the operation mode of the device.
§Returns
mode_type: The current operation mode.
Calls the openDAQ C function daqComponent_getOperationMode().
Examples found in repository?
5fn main() -> opendaq::Result<()> {
6 let instance = Instance::new()?;
7 let device = instance
8 .add_device("daqref://device0")?
9 .expect("reference device");
10
11 let modes: Vec<String> = device
12 .available_operation_modes()?
13 .into_iter()
14 .filter_map(|mode| OperationModeType::from_raw(mode as u32))
15 .map(|mode| format!("{mode:?}"))
16 .collect();
17 println!("Available operation modes: {}", modes.join(", "));
18 println!("Current operation mode: {:?}", device.operation_mode()?);
19
20 device.set_operation_mode(OperationModeType::Operation)?;
21 device.lock()?;
22 println!("After setting Operation: {:?}", device.operation_mode()?);
23 println!("Device locked: {}", device.is_locked()?);
24
25 device.unlock()?;
26 device.set_operation_mode(OperationModeType::SafeOperation)?;
27 println!();
28 println!("Device locked: {}", device.is_locked()?);
29 println!("Final operation mode: {:?}", device.operation_mode()?);
30 Ok(())
31}Sourcepub fn parent(&self) -> Result<Option<Component>>
pub fn parent(&self) -> Result<Option<Component>>
Gets the parent of the component.
§Returns
parent: The parent of the component. Every openDAQ component has a parent, except for instance. Parent should be passed as a parameter to the constructor/factory. Once the component is created, the parent cannot be changed.
Calls the openDAQ C function daqComponent_getParent().
Sourcepub fn parent_active(&self) -> Result<bool>
pub fn parent_active(&self) -> Result<bool>
Returns true if the component’s parent is active; false otherwise.
§Returns
parent_active: True if the component’s parent is active; false otherwise.
Calls the openDAQ C function daqComponent_getParentActive().
Sourcepub fn status_container(&self) -> Result<Option<ComponentStatusContainer>>
pub fn status_container(&self) -> Result<Option<ComponentStatusContainer>>
Gets the container of Component statuses.
§Returns
status_container: The container of Component statuses.
Calls the openDAQ C function daqComponent_getStatusContainer().
Examples found in repository?
18fn main() -> opendaq::Result<()> {
19 // Instance::new() already loads the bundled modules; build from an
20 // InstanceBuilder when you want to control the module search path.
21 let builder = InstanceBuilder::new()?;
22 // The bundled modules (reference device, function blocks, streaming):
23 let bundled = opendaq::native_library_directory().expect("native libraries");
24 builder.set_module_path(&bundled.to_string_lossy())?;
25 // Your own modules folder:
26 // builder.add_module_path("/path/to/your/modules")?;
27 let instance = Instance::from_builder(&builder)?;
28 instance.add_device("daqref://device0")?;
29
30 let channel = instance
31 .find_component("Dev/RefDev0/IO/AI/RefCh0")?
32 .expect("reference channel not found")
33 .cast::<Channel>()?;
34 channel.set_property_value("Amplitude", 5.0)?;
35 channel.set_property_value("DC", 1.0)?;
36
37 let statistics = instance
38 .add_function_block("RefFBModuleStatistics")?
39 .expect("statistics function block");
40 statistics.set_property_value("BlockSize", 100)?;
41
42 let status = statistics.status_container()?.expect("status container");
43 println!(
44 "Before connect: {} ({})",
45 status.status("ComponentStatus")?.expect("status").value()?,
46 status.status_message("ComponentStatus")?
47 );
48
49 let port = &statistics.input_ports()?[0];
50 let signal = &channel.signals()?[0];
51 port.connect(signal)?;
52
53 println!(
54 "After connect: {} ({})",
55 status.status("ComponentStatus")?.expect("status").value()?,
56 status.status_message("ComponentStatus")?
57 );
58
59 let outputs = statistics.signals()?;
60 let avg = signal_by_local_id(&outputs, "avg")?.expect("avg signal");
61 let rms = signal_by_local_id(&outputs, "rms")?.expect("rms signal");
62 let reader = MultiReader::<f64>::new(&[avg, rms])?;
63
64 // The first reads may return nothing while the block waits for a complete
65 // input descriptor (the multi reader by default doesn't skip events), so
66 // retry until samples arrive.
67 for _attempt in 0..20 {
68 let values = reader.read(5, 1000)?;
69 if !values[0].is_empty() {
70 println!("{:>10}{:>12}", "avg", "rms");
71 for (a, r) in values[0].iter().zip(&values[1]) {
72 println!("{a:>10.4}{r:>12.4}");
73 }
74 return Ok(());
75 }
76 }
77 println!("Statistics block produced no samples in time.");
78 Ok(())
79}Gets the tags of the component.
§Returns
tags: The tags of the component. Tags are user definable labels that can be attached to the component.
Calls the openDAQ C function daqComponent_getTags().
Examples found in repository?
36fn main() -> opendaq::Result<()> {
37 let instance = Instance::new()?;
38 instance.add_device("daqref://device0")?;
39 let root = instance.root_device()?.expect("root device");
40
41 // Give a couple of channels some tags, so the tag filter has something to
42 // match. (RefCh0 and RefCh1 come from the reference device unlabelled.)
43 let everything = SearchFilter::recursive(&SearchFilter::any()?)?;
44 for channel in root.channels_with(Some(&everything))? {
45 let tags = channel.tags()?.expect("tags").cast::<TagsPrivate>()?;
46 tags.add("analog")?;
47 if channel.local_id()? == "RefCh0" {
48 tags.add("primary")?;
49 }
50 }
51
52 show(
53 "channels, no filter (immediate children only)",
54 root.channels()?,
55 )?;
56
57 show(
58 "channels, recursive(any)",
59 root.channels_with(Some(&SearchFilter::recursive(&SearchFilter::any()?)?))?,
60 )?;
61
62 show(
63 "channels, recursive(id = RefCh1)",
64 root.channels_with(Some(&SearchFilter::recursive(&SearchFilter::local_id(
65 "RefCh1",
66 )?)?))?,
67 )?;
68
69 let ai0_or_ai1 = SearchFilter::or(
70 &SearchFilter::local_id("AI0")?,
71 &SearchFilter::local_id("AI1")?,
72 )?;
73 show(
74 "signals, recursive(id = AI0 OR id = AI1)",
75 root.signals_with(Some(&SearchFilter::recursive(&ai0_or_ai1)?))?,
76 )?;
77
78 let not_ref_ch1 = SearchFilter::not(&SearchFilter::local_id("RefCh1")?)?;
79 show(
80 "channels, recursive(NOT id = RefCh1)",
81 root.channels_with(Some(&SearchFilter::recursive(¬_ref_ch1)?))?,
82 )?;
83
84 let analog_and_not_ref_ch1 = SearchFilter::and(
85 &SearchFilter::required_tags(vec!["analog"])?,
86 &SearchFilter::not(&SearchFilter::local_id("RefCh1")?)?,
87 )?;
88 show(
89 "channels, recursive(tag = analog AND NOT id = RefCh1)",
90 root.channels_with(Some(&SearchFilter::recursive(&analog_and_not_ref_ch1)?))?,
91 )?;
92
93 Ok(())
94}Sourcepub fn visible(&self) -> Result<bool>
pub fn visible(&self) -> Result<bool>
Gets visible metadata state of the component
§Returns
visible: True if the component is visible; False otherwise. Visible determines whether search/getter methods return find the component by default.
Calls the openDAQ C function daqComponent_getVisible().
Sourcepub fn set_active(&self, active: bool) -> Result<()>
pub fn set_active(&self, active: bool) -> Result<()>
Sets the component to be either active or inactive. Sets the local active state and notifies children about the parent active state change.
§Parameters
active: The new local active state of the component.
§Errors
OPENDAQ_IGNORED: if “Active” is part of the component’s list of locked attributes, or if the new active value is equal to the previous. An active component acquires data, performs calculations and send packets on the signal path.
Calls the openDAQ C function daqComponent_setActive().
Sourcepub fn set_description(&self, description: &str) -> Result<()>
pub fn set_description(&self, description: &str) -> Result<()>
Sets the description of the component.
§Parameters
description: The description of the component.
§Errors
OPENDAQ_IGNORED: if “Description” is part of the component’s list of locked attributes, or if the new description value is equal to the previous. The object that implements this interface defines how the description is specified.
Calls the openDAQ C function daqComponent_setDescription().
Sourcepub fn set_name(&self, name: &str) -> Result<()>
pub fn set_name(&self, name: &str) -> Result<()>
Sets the name of the component.
§Parameters
name: The name of the component.
§Errors
OPENDAQ_IGNORED: if “Name” is part of the component’s list of locked attributes, or if the new name value is equal to the previous. The object that implements this interface defines how the name is specified.
Calls the openDAQ C function daqComponent_setName().
Sourcepub fn set_visible(&self, visible: bool) -> Result<()>
pub fn set_visible(&self, visible: bool) -> Result<()>
Sets visible attribute state of the component
§Parameters
visible: True if the component is visible; False otherwise.
§Errors
OPENDAQ_IGNORED: if “Visible” is part of the component’s list of locked attributes. Visible determines whether search/getter methods return find the component by default.
Calls the openDAQ C function daqComponent_setVisible().
Methods from Deref<Target = PropertyObject>§
Sourcepub fn add_property(&self, property: &Property) -> Result<()>
pub fn add_property(&self, property: &Property) -> Result<()>
Adds the property to the Property object.
§Parameters
property: The property to be added.
§Errors
OPENDAQ_ERR_INVALIDVALUE: if the property has no name.OPENDAQ_ERR_ALREADYEXISTS: if a property with the same name is already part of the Property object.OPENDAQ_ERR_FROZEN: if the Property object is frozen. The Property is frozen once added to the Property object, making it immutable. The same Property cannot be added to multiple different Property objects.
Calls the openDAQ C function daqPropertyObject_addProperty().
Examples found in repository?
19fn main() -> opendaq::Result<()> {
20 let work_dir = std::env::temp_dir().join("opendaq-rs-log-example");
21 let downloads = work_dir.join("downloads");
22 fs::create_dir_all(&downloads).expect("create working directories");
23 let device_log = work_dir.join("ref_device_simulator.log");
24 let device_log_path = device_log.to_string_lossy().into_owned();
25
26 // Start from a clean log so the reported size reflects only this run.
27 let _ = fs::remove_file(&device_log);
28
29 let builder = InstanceBuilder::new()?;
30 // Find the bundled modules.
31 let modules = opendaq::native_library_directory().expect("bundled native modules");
32 builder.set_module_path(&modules.to_string_lossy())?;
33 builder.add_logger_sink(&LoggerSink::basic_file(&device_log_path)?)?;
34 let instance = Instance::from_builder(&builder)?;
35
36 // The reference device reads these two properties from its add-device config.
37 let config = PropertyObject::new()?;
38 config.add_property(&Property::bool("EnableLogging", true, true)?)?;
39 config.add_property(&Property::string("LoggingPath", &device_log_path, true)?)?;
40
41 let device = instance
42 .add_device_with("daqref://device0", Some(&config))?
43 .expect("reference device");
44
45 // Flush the logger so everything buffered so far is actually on disk
46 // before we read it.
47 let context = instance.context()?.expect("instance context");
48 context.logger()?.expect("instance logger").flush()?;
49
50 let infos = device.log_file_infos()?;
51 if infos.is_empty() {
52 println!("Device exposes no log files.");
53 return Ok(());
54 }
55 println!("Device exposes {} log file(s):", infos.len());
56 println!();
57 for info in infos {
58 let id = info.id()?;
59 let destination = downloads.join(info.name()?);
60 println!("- {}", info.name()?);
61 println!(" id: {id}");
62 println!(" size: {} bytes", info.size()?);
63 println!(" encoding: {}", info.encoding()?);
64 println!(" last-modified: {}", info.last_modified()?);
65 // Size/offset let you fetch just part of a file; here, a short head preview.
66 println!(" preview: {:?}", device.log_with(&id, 60, 0)?);
67 // Plain `log` fetches the whole file in one call.
68 let content = device.log(&id)?;
69 fs::write(&destination, &content).expect("write the downloaded log");
70 println!(
71 " downloaded {} chars -> {}",
72 content.len(),
73 destination.display()
74 );
75 println!();
76 }
77 Ok(())
78}Sourcepub fn begin_update(&self) -> Result<()>
pub fn begin_update(&self) -> Result<()>
Begins batch configuration of the object.
Batched configuration is used to apply several settings at once. To begin batch configuration, call beginUpdate.
When the setPropertyValue is called on the object, the changes are not immediately applied to it. When endUpdate
is called, the property values set between the beginUpdate and endUpdate method calls are
applied. It triggers the ˙OnPropertyWriteEventfor each property value set, and theOnEndUpdateevent.beginUpdate` is called recursively for each child property object.
Calls the openDAQ C function daqPropertyObject_beginUpdate().
Sourcepub fn clear_property_value(&self, property_name: &str) -> Result<()>
pub fn clear_property_value(&self, property_name: &str) -> Result<()>
Clears the Property value from the Property object
§Parameters
property_name: The name of the Property of which value should be cleared.
§Errors
OPENDAQ_ERR_NOTFOUND: if a Property with givenpropertyNameis not part of the Property object.OPENDAQ_ERR_FROZEN: if the Property object is frozen. When a Property value is set, the value is written in the internal dictionary of Property values. This function will remove said value from the dictionary. If the tries to obtain the Property value of a property that does not have a set Property value, then the default value is returned. Importantly, clearing the value of an Object-type property will callclearon all the child object’s properties.
Calls the openDAQ C function daqPropertyObject_clearPropertyValue().
Sourcepub fn clear_property_values(&self) -> Result<()>
pub fn clear_property_values(&self) -> Result<()>
Clears values of all properties contained in the Property object, including nested child properties.
This function clears the values by internally invoking clearPropertyValue(...) for all properties returned by
getAllProperties(); for object-type properties it therefore clears their child properties as well.
Read-only properties and frozen objects are skipped.
Calls the openDAQ C function daqPropertyObject_clearPropertyValues().
Sourcepub fn end_update(&self) -> Result<()>
pub fn end_update(&self) -> Result<()>
Ends batch configuration of the object.
Batched configuration is used to apply several settings at once. To begin batch configuration, call beginUpdate.
When the setPropertyValue is called on the object, the changes are not immediately applied to it. When endUpdate
is called, the property values set between the beginUpdate and endUpdate method calls are
applied. It triggers the ˙OnPropertyWriteEventfor each property value set, and theOnEndUpdateevent.endUpdate` is called recursively for each child property object.
Calls the openDAQ C function daqPropertyObject_endUpdate().
Sourcepub fn find_properties(
&self,
property_filter: &SearchFilter,
) -> Result<Vec<Property>>
pub fn find_properties( &self, property_filter: &SearchFilter, ) -> Result<Vec<Property>>
Retrieves a list of properties from the Property object that match the given property filter.
§Parameters
property_filter: A filter used to select relevant properties. Can include a recursive wrapper to search thru nested property objects.component_filter: An optional filter to determine which components’ properties are included in the search. A recursive wrapper can be used to enable tree-traversal search.
§Returns
properties: The list containing the matching properties. If the propertyFilter is nullptr, only the visible properties directly associated with the current object are retrieved. When searching for properties within a component, if no componentFilter is provided, only the current component is searched. If a componentFilter is provided but the current component does not match it, the result will be an empty list.
Calls the openDAQ C function daqPropertyObject_findProperties().
Sourcepub fn find_properties_with(
&self,
property_filter: &SearchFilter,
component_filter: Option<&SearchFilter>,
) -> Result<Vec<Property>>
pub fn find_properties_with( &self, property_filter: &SearchFilter, component_filter: Option<&SearchFilter>, ) -> Result<Vec<Property>>
Retrieves a list of properties from the Property object that match the given property filter.
§Parameters
property_filter: A filter used to select relevant properties. Can include a recursive wrapper to search thru nested property objects.component_filter: An optional filter to determine which components’ properties are included in the search. A recursive wrapper can be used to enable tree-traversal search.
§Returns
properties: The list containing the matching properties. If the propertyFilter is nullptr, only the visible properties directly associated with the current object are retrieved. When searching for properties within a component, if no componentFilter is provided, only the current component is searched. If a componentFilter is provided but the current component does not match it, the result will be an empty list.
Calls the openDAQ C function daqPropertyObject_findProperties().
Sourcepub fn all_properties(&self) -> Result<Vec<Property>>
pub fn all_properties(&self) -> Result<Vec<Property>>
Returns a list of all properties contained in the Property object.
§Returns
properties: The List of properties. Properties are retrieved regardless of their visibility. They are sorted in insertion order unless a custom order is specified. This function returns both the properties added to the Property object, as well as those of its class.
Calls the openDAQ C function daqPropertyObject_getAllProperties().
Sourcepub fn class_name(&self) -> Result<String>
pub fn class_name(&self) -> Result<String>
Gets the name of the class the Property object was constructed with.
§Returns
class_name: The class’s name. Contains an empty string if the class name is not configured. A Property object inherits all properties of the Property object class of the same name. Such Property objects have access to the Type manager from which they can retrieve its class type and its properties.
Calls the openDAQ C function daqPropertyObject_getClassName().
Sourcepub fn on_any_property_value_read(&self) -> Result<Option<Event>>
pub fn on_any_property_value_read(&self) -> Result<Option<Event>>
Gets the Event that is triggered whenever any Property value is read.The event is triggered after the specific Property event.
§Returns
event: The read Event. A handler can be added to the event containing a callback function which is invoked whenever the event is triggered. The callback function requires two parameters - a Property object, as well as a “Property value event args” object. The callback will be invoked with the Property object holding the read value as the first argument. The second argument holds an event args object that contains the read Property value, event type (Read), and a method of overriding the read value. If the read value is overridden, the overridden value is read instead.
Calls the openDAQ C function daqPropertyObject_getOnAnyPropertyValueRead().
Sourcepub fn on_any_property_value_write(&self) -> Result<Option<Event>>
pub fn on_any_property_value_write(&self) -> Result<Option<Event>>
Gets the Event that is triggered whenever any Property value is written. The event is triggered after the specific Property event.
§Returns
event: The write Event. A handler can be added to the event containing a callback function which is invoked whenever the event is triggered. The callback function requires two parameters - a Property object, as well as a “Property value event args” object. The callback will be invoked with the Property object holding the written-to property as the first argument The second argument holds an event args object that contains the written value, event type (Update), and a method of overriding the written value. If the written value is overridden, the overridden value is stored in the Property object instead.
Calls the openDAQ C function daqPropertyObject_getOnAnyPropertyValueWrite().
Sourcepub fn on_end_update(&self) -> Result<Option<Event>>
pub fn on_end_update(&self) -> Result<Option<Event>>
Gets the Event that is triggered whenever the batch configuration is applied.
§Returns
event: The Event. A handler can be added to the event containing a callback function which is invoked whenever the event is triggered. The callback function requires one parameter - a “End update value event args” object. The callback will be invoked with the batch configuration is applied, i.e. from theendUpdatemethod. The first argument holds an event args object that contains a list of properties updated.
Calls the openDAQ C function daqPropertyObject_getOnEndUpdate().
Sourcepub fn on_property_value_read(
&self,
property_name: &str,
) -> Result<Option<Event>>
pub fn on_property_value_read( &self, property_name: &str, ) -> Result<Option<Event>>
Gets the Event that is triggered whenever a Property value of a Property named propertyName is read.
§Parameters
property_name: The name of the property.
§Returns
event: The read Event.
§Errors
OPENDAQ_ERR_NOTFOUND: if the Property object does not contain a Property namedpropertyName. A handler can be added to the event containing a callback function which is invoked whenever the event is triggered. The callback function requires two parameters - a Property object, as well as a “Property value event args” object. The callback will be invoked with the Property object holding the read value as the first argument. The second argument holds an event args object that contains the read Property value, event type (Read), and a method of overriding the read value. If the read value is overridden, the overridden value is read instead.
Calls the openDAQ C function daqPropertyObject_getOnPropertyValueRead().
Sourcepub fn on_property_value_write(
&self,
property_name: &str,
) -> Result<Option<Event>>
pub fn on_property_value_write( &self, property_name: &str, ) -> Result<Option<Event>>
Gets the Event that is triggered whenever a Property value is written to the Property named propertyName.
§Parameters
property_name: The name of the property.
§Returns
event: The write Event.
§Errors
OPENDAQ_ERR_NOTFOUND: if the Property object does not contain a Property namedpropertyName. A handler can be added to the event containing a callback function which is invoked whenever the event is triggered. The callback function requires two parameters - a Property object, as well as a “Property value event args” object. The callback will be invoked with the Property object holding the written-to property as the first argument The second argument holds an event args object that contains the written value, event type (Update), and a method of overriding the written value. If the written value is overridden, the overridden value is stored in the Property object instead.
Calls the openDAQ C function daqPropertyObject_getOnPropertyValueWrite().
Examples found in repository?
7fn main() -> opendaq::Result<()> {
8 let instance = Instance::new()?;
9
10 println!("Available devices:");
11 for info in instance.available_devices()? {
12 println!(" - {}: {}", info.connection_string()?, info.name()?);
13 }
14
15 let device = instance.add_device("daqref://device0")?.expect("device");
16 println!("Added device: {}", device.name()?);
17
18 let channel = instance
19 .find_component("Dev/RefDev0/IO/AI/RefCh0")?
20 .expect("reference channel not found")
21 .cast::<Channel>()?;
22 let signal = &channel.signals()?[0];
23
24 // Batched property updates.
25 {
26 let batch = BatchedPropertyUpdate::new(&[&device, &channel])?;
27 device.set_property_value("GlobalSampleRate", 1000)?;
28 channel.set_property_value("Frequency", 50.0)?;
29 batch.commit()?;
30 }
31 println!(
32 "GlobalSampleRate = {}",
33 device.property_value("GlobalSampleRate")?
34 );
35
36 // Stream reading with domain + tick conversion.
37 let reader = StreamReader::<f64>::new(signal)?;
38 let (samples, ticks) = reader.read_with_domain(100, 2000)?;
39 println!(
40 "read {} samples, {} ticks",
41 samples.sample_count(),
42 ticks.len()
43 );
44 let converter = TickConverter::from_signal(signal)?;
45 if let Some(first) = ticks.first() {
46 println!(
47 "first tick {} -> {:?}",
48 first,
49 converter.tick_to_system_time(*first)
50 );
51 }
52
53 // Callables: a Rust closure as an openDAQ function, called through openDAQ.
54 let sum = FunctionObject::from_fn(|args| {
55 let a = args[0].as_i64().unwrap_or(0);
56 let b = args[1].as_i64().unwrap_or(0);
57 Ok(Value::from(a + b))
58 })?;
59 let result = sum.call(&[Value::from(20), Value::from(22)])?;
60 println!("sum(20, 22) = {result}");
61
62 // Events: subscribe to property changes on the channel.
63 let events = channel
64 .on_property_value_write("Amplitude")?
65 .expect("event");
66 let handler = events.subscribe(|_sender, args| {
67 if let Some(args) = args {
68 println!(" event fired: {args}");
69 }
70 })?;
71 channel.set_property_value("Amplitude", 2.5)?;
72 events.unsubscribe(&handler)?;
73 channel.set_property_value("Amplitude", 1.0)?;
74 println!("Amplitude = {}", channel.property_value("Amplitude")?);
75
76 Ok(())
77}Sourcepub fn permission_manager(&self) -> Result<Option<PermissionManager>>
pub fn permission_manager(&self) -> Result<Option<PermissionManager>>
Gets the permission manager of property object.
§Returns
permission_manager: The permission manager of property object.
Calls the openDAQ C function daqPropertyObject_getPermissionManager().
Sourcepub fn property(&self, property_name: &str) -> Result<Option<Property>>
pub fn property(&self, property_name: &str) -> Result<Option<Property>>
Gets the Property with the given propertyName.
§Parameters
property_name: The name of the property.
§Returns
property: The retrieved Property.
§Errors
OPENDAQ_ERR_NOTFOUND: if the Property object does not contain the requested Property. The property is obtained from either the Property object class of the Property object, or the object’s local list of properties. The Property held by the object/class is not returned directly, but is instead cloned, and bound to the Property object. This allows for evaluation of Property metadata that depends on other properties of the Property object. For example, a Property’s visibility might depend on the value of another Property. To make evaluation of the visibility parameter possible, the Property must be able to access its owning Property object. Likewise, Reference properties always point at another Property of a Property object. Again, for this to be possible, the Property must be able to access its owning Property object, to be able to retrieve its referenced Property.
Calls the openDAQ C function daqPropertyObject_getProperty().
Examples found in repository?
47fn main() -> opendaq::Result<()> {
48 let instance = Instance::new()?;
49
50 let config = instance
51 .create_default_add_device_config()?
52 .expect("default add-device config");
53
54 // The "General" child object holds the protocol-independent options,
55 // ClientType among them; its selection values name the available modes.
56 let general = config
57 .property_value("General")?
58 .into_object()?
59 .cast::<PropertyObject>()?;
60 let client_type = general
61 .property("ClientType")?
62 .expect("ClientType property");
63 println!("Available ClientType options:");
64 if let Value::Dict(mut options) = client_type.selection_values()? {
65 options.sort_by_key(|(key, _)| key.as_i64());
66 for (key, name) in options {
67 println!(" {key} = {name}");
68 }
69 }
70
71 config.set_property_value("General.ClientType", 2)?; // 2 = view-only
72 let connection_string =
73 std::env::var("OPENDAQ_DEVICE").unwrap_or_else(|_| "daq.nd://127.0.0.1".into());
74
75 match instance.add_device_with(&connection_string, Some(&config)) {
76 Ok(Some(device)) => probe_view_only_device(&device)?,
77 Ok(None) => println!("Could not connect to {connection_string}: no device returned."),
78 Err(err) => {
79 println!("Could not connect to {connection_string}: {err}");
80 println!("Start an openDAQ device/simulator there, or set OPENDAQ_DEVICE.");
81 }
82 }
83 Ok(())
84}More examples
17fn main() -> opendaq::Result<()> {
18 let instance = Instance::new()?;
19 let device = instance.add_device("daqref://device0")?.expect("device");
20
21 let sum = function_property(&device, "Protected.Sum")?;
22 println!(
23 "Protected.Sum(7, 5) = {}",
24 sum.call(&[Value::from(7), Value::from(5)])?
25 );
26 println!(
27 "Protected.Sum(40, 2) = {}",
28 sum.call(&[Value::from(40), Value::from(2)])?
29 );
30 println!(
31 "Protected.Sum(100, 1) = {}",
32 function_property(&device, "Protected.Sum")?.call(&[Value::from(100), Value::from(1)])?
33 );
34
35 // SumList takes a single argument: a list of numbers.
36 let sum_list = function_property(&device, "Protected.SumList")?;
37 println!(
38 "Protected.SumList([1, 2, 3, 4]) = {}",
39 sum_list.call(&[Value::from(vec![1, 2, 3, 4])])?
40 );
41 println!(
42 "Protected.SumList([]) = {}",
43 sum_list.call(&[Value::List(Vec::new())])?
44 );
45
46 // `call` passes arguments straight through, and an implementation is free
47 // to ignore extras (the reference device's Sum does). The declared
48 // signature lives in the property's callable info -- check the arity
49 // there before calling when it matters.
50 let info = device
51 .property("Protected.Sum")?
52 .expect("Sum property")
53 .callable_info()?
54 .expect("callable info");
55 let expected = info.arguments()?.len();
56 let args = [Value::from(1), Value::from(2), Value::from(3)];
57 if args.len() == expected {
58 println!("\nProtected.Sum(1, 2, 3) = {}", sum.call(&args)?);
59 } else {
60 println!(
61 "\nWrong arity is rejected: Protected.Sum expects {expected} arguments, got {}.",
62 args.len()
63 );
64 }
65 Ok(())
66}Sourcepub fn property_selection_value(&self, property_name: &str) -> Result<Value>
pub fn property_selection_value(&self, property_name: &str) -> Result<Value>
Gets the selected value of the Property, if the Property is a Selection property.
§Parameters
property_name: The name of the Property.
§Returns
value: The selected value.
§Errors
OPENDAQ_ERR_NOTFOUND: if a Property with givenpropertyNameis not part of the Property object.OPENDAQ_ERR_INVALIDPROPERTY: if the Property either has no Selection values, or the Selection values are not a list or dictionary.OPENDAQ_ERR_INVALIDTYPE: if the retrieved value does not match the Property’s item type. This function serves as a shortcut to obtaining the Property value of a Property, and using it to retrieve the currently selected value from the Selection values of the Property. For example, if the Selection values contain the following list “[“banana”, “apple”, “pear”]“, and the corresponding Property value is set to 1, retrieving the Property selection value will return the string “apple”.
Calls the openDAQ C function daqPropertyObject_getPropertySelectionValue().
Sourcepub fn property_value(&self, property_name: &str) -> Result<Value>
pub fn property_value(&self, property_name: &str) -> Result<Value>
Gets the value of the Property with the given name.
§Parameters
property_name: The name of the Property.
§Returns
value: The returned Property value.
§Errors
OPENDAQ_ERR_NOTFOUND: if a property with givenpropertyNameis not part of the Property object.OPENDAQ_ERR_INVALIDPARAMETER: if attempting to get a value at an index of a non-list Property.OPENDAQ_ERR_OUTOFRANGE: if attempting to get a value of a list Property at an out-of-bounds index. The value is retrieved from a local dictionary of Property values where they are stored when set. If a value is not present under thepropertyNamekey, the default value of the corresponding Property is returned. If said property is not part of the Property object, an error occurs. @subsection value_get_child_property_objects Child Property objects The Property value getter allows for direct retrieval of values of child Property objects. To get the Property value of a child Property object, thepropertyNameparameter should be of the format: “childName.propertyName”. This pattern can also be used to access nested properties - for example “childName1.childName2.childName3.propertyName”. @subsection value_get_list_properties List properties If the requested Property is a list-type object, an item of the list at a selected index can be retrieved instead of the list itself. To do so, add a [index] suffix to thepropertyNameparameter. For example “ListProperty[1]” retrieves the 2nd item stored in the list Property value of the Property named “ListProperty”. @subsection value_get_selection_properties Selection properties If the requested Property has the Selection values fields configured, the Property value getter returns an index/key of the selected item in the Selection values list/dictionary.
Calls the openDAQ C function daqPropertyObject_getPropertyValue().
Examples found in repository?
More examples
17fn property_value_string(object: &PropertyObject, property: &Property) -> opendaq::Result<String> {
18 Ok(match property.value_type()? {
19 CoreType::Bool
20 | CoreType::Int
21 | CoreType::Float
22 | CoreType::String
23 | CoreType::Ratio
24 | CoreType::ComplexNumber => match object.property_value(&property.name()?)? {
25 Value::Str(text) => format!("{text:?}"),
26 value => value.to_string(),
27 },
28 other => format!("<{other:?}>"),
29 })
30}27fn probe_view_only_device(device: &Device) -> opendaq::Result<()> {
28 println!("Connected to {} as a view-only client.", device.name()?);
29 println!("Visible signals: {}", device.signals_recursive()?.len());
30 match first_writable_property_name(device)? {
31 Some(name) => {
32 // Write the property's current value back to itself: harmless if
33 // it were allowed, but a view-only connection must reject it.
34 let value = device.property_value(&name)?;
35 match device.set_property_value(&name, value) {
36 Ok(()) => println!("Unexpected: writing {name:?} was allowed."),
37 Err(err) => {
38 println!("Write to {name:?} refused, as expected for view-only: {err}")
39 }
40 }
41 }
42 None => println!("Device exposes no writable property to probe."),
43 }
44 Ok(())
45}
46
47fn main() -> opendaq::Result<()> {
48 let instance = Instance::new()?;
49
50 let config = instance
51 .create_default_add_device_config()?
52 .expect("default add-device config");
53
54 // The "General" child object holds the protocol-independent options,
55 // ClientType among them; its selection values name the available modes.
56 let general = config
57 .property_value("General")?
58 .into_object()?
59 .cast::<PropertyObject>()?;
60 let client_type = general
61 .property("ClientType")?
62 .expect("ClientType property");
63 println!("Available ClientType options:");
64 if let Value::Dict(mut options) = client_type.selection_values()? {
65 options.sort_by_key(|(key, _)| key.as_i64());
66 for (key, name) in options {
67 println!(" {key} = {name}");
68 }
69 }
70
71 config.set_property_value("General.ClientType", 2)?; // 2 = view-only
72 let connection_string =
73 std::env::var("OPENDAQ_DEVICE").unwrap_or_else(|_| "daq.nd://127.0.0.1".into());
74
75 match instance.add_device_with(&connection_string, Some(&config)) {
76 Ok(Some(device)) => probe_view_only_device(&device)?,
77 Ok(None) => println!("Could not connect to {connection_string}: no device returned."),
78 Err(err) => {
79 println!("Could not connect to {connection_string}: {err}");
80 println!("Start an openDAQ device/simulator there, or set OPENDAQ_DEVICE.");
81 }
82 }
83 Ok(())
84}7fn main() -> opendaq::Result<()> {
8 let instance = Instance::new()?;
9
10 println!("Available devices:");
11 for info in instance.available_devices()? {
12 println!(" - {}: {}", info.connection_string()?, info.name()?);
13 }
14
15 let device = instance.add_device("daqref://device0")?.expect("device");
16 println!("Added device: {}", device.name()?);
17
18 let channel = instance
19 .find_component("Dev/RefDev0/IO/AI/RefCh0")?
20 .expect("reference channel not found")
21 .cast::<Channel>()?;
22 let signal = &channel.signals()?[0];
23
24 // Batched property updates.
25 {
26 let batch = BatchedPropertyUpdate::new(&[&device, &channel])?;
27 device.set_property_value("GlobalSampleRate", 1000)?;
28 channel.set_property_value("Frequency", 50.0)?;
29 batch.commit()?;
30 }
31 println!(
32 "GlobalSampleRate = {}",
33 device.property_value("GlobalSampleRate")?
34 );
35
36 // Stream reading with domain + tick conversion.
37 let reader = StreamReader::<f64>::new(signal)?;
38 let (samples, ticks) = reader.read_with_domain(100, 2000)?;
39 println!(
40 "read {} samples, {} ticks",
41 samples.sample_count(),
42 ticks.len()
43 );
44 let converter = TickConverter::from_signal(signal)?;
45 if let Some(first) = ticks.first() {
46 println!(
47 "first tick {} -> {:?}",
48 first,
49 converter.tick_to_system_time(*first)
50 );
51 }
52
53 // Callables: a Rust closure as an openDAQ function, called through openDAQ.
54 let sum = FunctionObject::from_fn(|args| {
55 let a = args[0].as_i64().unwrap_or(0);
56 let b = args[1].as_i64().unwrap_or(0);
57 Ok(Value::from(a + b))
58 })?;
59 let result = sum.call(&[Value::from(20), Value::from(22)])?;
60 println!("sum(20, 22) = {result}");
61
62 // Events: subscribe to property changes on the channel.
63 let events = channel
64 .on_property_value_write("Amplitude")?
65 .expect("event");
66 let handler = events.subscribe(|_sender, args| {
67 if let Some(args) = args {
68 println!(" event fired: {args}");
69 }
70 })?;
71 channel.set_property_value("Amplitude", 2.5)?;
72 events.unsubscribe(&handler)?;
73 channel.set_property_value("Amplitude", 1.0)?;
74 println!("Amplitude = {}", channel.property_value("Amplitude")?);
75
76 Ok(())
77}Sourcepub fn updating(&self) -> Result<bool>
pub fn updating(&self) -> Result<bool>
Returns the state of batch configuration.
§Returns
updating: True if the object is performing batch update of its properties. Batched configuration is used to apply several settings at once. To begin batch configuration, callbeginUpdate. When thesetPropertyValueis called on the object, the changes are not immediately applied. WhenendUpdateis called, the property values set between thebeginUpdateandendUpdatemethod calls are applied. This method returns True ifbeginUpdatemethod has been called on the objectandendUpdate` has not been called yet.
Calls the openDAQ C function daqPropertyObject_getUpdating().
Sourcepub fn visible_properties(&self) -> Result<Vec<Property>>
pub fn visible_properties(&self) -> Result<Vec<Property>>
Returns a list of visible properties contained in the Property object.
§Returns
properties: The List of properties. A Property is visible if both the Visible parameter is set totrue, and IsReferenced isfalse. The properties are sorted in insertion order unless a custom order is specified. This function returns both the properties added to the Property object, as well as those of its class.
Calls the openDAQ C function daqPropertyObject_getVisibleProperties().
Examples found in repository?
More examples
14fn first_writable_property_name(object: &PropertyObject) -> opendaq::Result<Option<String>> {
15 for property in object.visible_properties()? {
16 if property.read_only()? {
17 continue;
18 }
19 if matches!(property.value_type()?, CoreType::Func | CoreType::Proc) {
20 continue;
21 }
22 return Ok(Some(property.name()?));
23 }
24 Ok(None)
25}Sourcepub fn has_property(&self, property_name: &str) -> Result<bool>
pub fn has_property(&self, property_name: &str) -> Result<bool>
Sourcepub fn remove_property(&self, property_name: &str) -> Result<()>
pub fn remove_property(&self, property_name: &str) -> Result<()>
Removes the Property named propertyName from the Property object.
§Parameters
property_name: The name of the Property to be removed.
§Errors
OPENDAQ_ERR_NOTFOUND: if the Property object does not contain a Property namedpropertyName, or the Property is part of the Property object’s Property object class.OPENDAQ_ERR_FROZEN: if the Property object is frozen. A property can only be removed from a Property object, if it was added to the object, and not inherited from its class.
Calls the openDAQ C function daqPropertyObject_removeProperty().
Sourcepub fn set_property_order(&self, ordered_property_names: &[&str]) -> Result<()>
pub fn set_property_order(&self, ordered_property_names: &[&str]) -> Result<()>
Sets a custom order of properties as defined in the list of property names.
§Parameters
ordered_property_names: A list of names of properties. The order of the list is applied to the object’s properties.
§Errors
OPENDAQ_ERR_FROZEN: if the Property object is frozen. The list should contain names of properties available in the object. When retrieving the Property object’s properties, they will be sorted in the order in which the names appear in the provided list. Any properties not in the custom order are kept in insertion order at the end of the Property object’s list of properties.
Calls the openDAQ C function daqPropertyObject_setPropertyOrder().
Sourcepub fn set_property_selection_value(
&self,
property_name: &str,
value: impl Into<Value>,
) -> Result<()>
pub fn set_property_selection_value( &self, property_name: &str, value: impl Into<Value>, ) -> Result<()>
Sets the value of a Selection property by the selection item value (e.g. string, float, or list/dict value).
§Parameters
property_name: The name of the Property.value: The selection value to set (must be one of the Property’s selection values). Cannot be null.
§Errors
OPENDAQ_ERR_NOTFOUND: if a Property with givenpropertyNameis not part of the Property object, or the value is not in the selection.OPENDAQ_ERR_INVALIDPROPERTY: if the Property has no Selection values.OPENDAQ_ERR_ACCESSDENIED: if the property is Read-only.OPENDAQ_ERR_FROZEN: if the Property object is frozen. Works for all Selection properties (list or dictionary): the value is the actual selection item (e.g. a string from the list, or the value part of a key-value pair in the dictionary). Use setPropertyValue when setting by index/key.
Calls the openDAQ C function daqPropertyObject_setPropertySelectionValue().
Sourcepub fn set_property_value(
&self,
property_name: &str,
value: impl Into<Value>,
) -> Result<()>
pub fn set_property_value( &self, property_name: &str, value: impl Into<Value>, ) -> Result<()>
Sets the value of the Property with the given name.
§Parameters
property_name: The name of the Property.value: The Property value to be set. Cannot be null.
§Errors
OPENDAQ_ERR_NOTFOUND: if a property with givenpropertyNameis not part of the Property object.OPENDAQ_ERR_ACCESSDENIED: if the property is Read-only.OPENDAQ_ERR_CONVERSIONFAILED: if thevaluecannot be converted to the Value type of the Property.OPENDAQ_ERR_INVALIDTYPE: if thevalueis a list/dictionary/object with invalid keys/items/fields.OPENDAQ_ERR_VALIDATE_FAILED: if the Validator fails to validate thevalue.OPENDAQ_ERR_COERCION_FAILED: if the Coercer fails to coerce thevalue.OPENDAQ_ERR_FROZEN: if the Property object is frozen.OPENDAQ_ERR_IGNORED: if thevalueis the same as the default, or the previously written value. Stores the providedvalueinto an internal dictionary of property name and value pairs. This property value can later be retrieved through the corresponding getter method when invoked with the samepropertyName. The providedvaluemust adhere to the restrictions of the corresponding Property (that bears the namepropertyName). If such a Property is part of the Property object, the setter call will fail. Some restrictions include: - The core type of the value must match that of the Property Value type. - If the Property is a numeric type, the value must be equal or greater than the Min value, and equal or smaller than the Max value. - If the Property is Read-only, the setter will fail. - The value will be validated by the Property validator causing the setter method to fail if validation is unsuccessful. - The value will be coerced to fit the coercion expression of the Property coercer before being written into the local dictionary of property values. Setting the value of a Property will override either its default value or the value that was set beforehand. @subsection patterns Behaviour patterns of note - When setting the value of a Property with the Selection values field configured (a Selection property), thevaluemust be an integer type, and acts as an index/key into the list/dictionary of Selection values. - If the Property is a Reference property (the Referenced property field is configured), thevalueis actually written under the key of the referenced Property, not the one specified through thepropertyNameargument. - When setting a list or dictionary type property, the list items and dictionary keys and items must be homogeneous, and of the same type as specified by the item and key type of the Property. - Setting a Property value will invoke the correspondingonPropertyValueWriteevent. @subsection value_set_child_property_objects Child Property objects The Property value setter allows for direct configuration of any child Property objects. To set the Property value of a child Property object, thepropertyNameparameter should be of the format: “childName.propertyName”. This pattern can also be used to access nested properties - for example “childName1.childName2.childName3.propertyName”.
Calls the openDAQ C function daqPropertyObject_setPropertyValue().
Examples found in repository?
27fn probe_view_only_device(device: &Device) -> opendaq::Result<()> {
28 println!("Connected to {} as a view-only client.", device.name()?);
29 println!("Visible signals: {}", device.signals_recursive()?.len());
30 match first_writable_property_name(device)? {
31 Some(name) => {
32 // Write the property's current value back to itself: harmless if
33 // it were allowed, but a view-only connection must reject it.
34 let value = device.property_value(&name)?;
35 match device.set_property_value(&name, value) {
36 Ok(()) => println!("Unexpected: writing {name:?} was allowed."),
37 Err(err) => {
38 println!("Write to {name:?} refused, as expected for view-only: {err}")
39 }
40 }
41 }
42 None => println!("Device exposes no writable property to probe."),
43 }
44 Ok(())
45}
46
47fn main() -> opendaq::Result<()> {
48 let instance = Instance::new()?;
49
50 let config = instance
51 .create_default_add_device_config()?
52 .expect("default add-device config");
53
54 // The "General" child object holds the protocol-independent options,
55 // ClientType among them; its selection values name the available modes.
56 let general = config
57 .property_value("General")?
58 .into_object()?
59 .cast::<PropertyObject>()?;
60 let client_type = general
61 .property("ClientType")?
62 .expect("ClientType property");
63 println!("Available ClientType options:");
64 if let Value::Dict(mut options) = client_type.selection_values()? {
65 options.sort_by_key(|(key, _)| key.as_i64());
66 for (key, name) in options {
67 println!(" {key} = {name}");
68 }
69 }
70
71 config.set_property_value("General.ClientType", 2)?; // 2 = view-only
72 let connection_string =
73 std::env::var("OPENDAQ_DEVICE").unwrap_or_else(|_| "daq.nd://127.0.0.1".into());
74
75 match instance.add_device_with(&connection_string, Some(&config)) {
76 Ok(Some(device)) => probe_view_only_device(&device)?,
77 Ok(None) => println!("Could not connect to {connection_string}: no device returned."),
78 Err(err) => {
79 println!("Could not connect to {connection_string}: {err}");
80 println!("Start an openDAQ device/simulator there, or set OPENDAQ_DEVICE.");
81 }
82 }
83 Ok(())
84}More examples
18fn main() -> opendaq::Result<()> {
19 let instance = Instance::new()?;
20 let device = instance.add_device("daqref://device0")?.expect("device");
21 let channels = device.channels()?;
22 let (ch0, ch1) = (&channels[0], &channels[1]);
23
24 show_settings("Before: ", ch0)?;
25 show_settings("Before: ", ch1)?;
26
27 let batch = BatchedPropertyUpdate::new(&[ch0, ch1])?;
28 ch0.set_property_value("Amplitude", 2.5)?;
29 ch0.set_property_value("Frequency", 25.0)?;
30 ch0.set_property_value("Waveform", 1)?;
31 ch1.set_property_value("Amplitude", 4.0)?;
32 ch1.set_property_value("Frequency", 50.0)?;
33 ch1.set_property_value("Waveform", 2)?;
34 // Still inside the batch: the writes above are staged but not yet applied.
35 show_settings("During (staged): ", ch0)?;
36 show_settings("During (staged): ", ch1)?;
37 batch.commit()?;
38
39 show_settings("After the batch: ", ch0)?;
40 show_settings("After the batch: ", ch1)?;
41 Ok(())
42}27fn main() -> opendaq::Result<()> {
28 let instance = Instance::new()?;
29 instance.add_device("daqref://device0")?;
30
31 let channels = [
32 find_channel(&instance, "Dev/RefDev0/IO/AI/RefCh0")?,
33 find_channel(&instance, "Dev/RefDev0/IO/AI/RefCh1")?,
34 ];
35 channels[0].set_property_value("Frequency", 0.5)?;
36 channels[1].set_property_value("Frequency", 2.0)?;
37
38 let signals = [
39 channels[0].signals()?[0].clone(),
40 channels[1].signals()?[0].clone(),
41 ];
42 let reader = MultiReader::<f64>::new(&signals)?;
43
44 // The first reads can return nothing while the reader synchronises the
45 // signals onto the common domain; retry until rows arrive.
46 for _ in 0..10 {
47 let (values, domain) = reader.read_with_domain(8, 1000)?;
48 if domain[0].is_empty() {
49 continue;
50 }
51 let converter = TickConverter::from_multi_reader(&reader)?;
52 print!("{:<16}", "timestamp");
53 for index in 0..values.len() {
54 print!("{:>14}", format!("signal {index}"));
55 }
56 println!();
57 for (row, tick) in domain[0].iter().enumerate() {
58 print!("{:<16}", time_of_day(converter.tick_to_unix_nanos(*tick)));
59 for signal_values in &values {
60 print!("{:>14.6}", signal_values[row]);
61 }
62 println!();
63 }
64 return Ok(());
65 }
66 println!("Multi reader did not synchronise in time.");
67 Ok(())
68}10fn main() -> opendaq::Result<()> {
11 let instance = Instance::new()?;
12 instance.add_device("daqref://device0")?;
13
14 let channel = instance
15 .find_component("Dev/RefDev0/IO/AI/RefCh0")?
16 .expect("reference channel not found")
17 .cast::<Channel>()?;
18
19 let core_event = instance
20 .context()?
21 .expect("context")
22 .on_core_event()?
23 .expect("core event");
24
25 // The handler may run on openDAQ's own threads. Its args come in as a
26 // generic object; cast to CoreEventArgs for the event name and the
27 // per-event-type parameters ("Name" holds the changed property's name).
28 let handler = core_event.subscribe(|_sender, args| {
29 let Some(args) = args else { return };
30 let Ok(event) = args.cast::<CoreEventArgs>() else {
31 return;
32 };
33 let name = event.event_name().unwrap_or_default();
34 let parameters = event.parameters().unwrap_or_default();
35 let changed = parameters
36 .get("Name")
37 .map(ToString::to_string)
38 .unwrap_or_default();
39 println!(" {name}: {changed}");
40 })?;
41
42 // While subscribed, each property change is reported by the handler above.
43 println!("subscribed:");
44 channel.set_property_value("Frequency", 25.0)?;
45 channel.set_property_value("Amplitude", 7.5)?;
46
47 // Unsubscribing removes the handler; further changes fire nothing.
48 core_event.unsubscribe(&handler)?;
49 println!("unsubscribed (no lines expected below):");
50 channel.set_property_value("Frequency", 50.0)?;
51
52 Ok(())
53}7fn main() -> opendaq::Result<()> {
8 let instance = Instance::new()?;
9
10 println!("Available devices:");
11 for info in instance.available_devices()? {
12 println!(" - {}: {}", info.connection_string()?, info.name()?);
13 }
14
15 let device = instance.add_device("daqref://device0")?.expect("device");
16 println!("Added device: {}", device.name()?);
17
18 let channel = instance
19 .find_component("Dev/RefDev0/IO/AI/RefCh0")?
20 .expect("reference channel not found")
21 .cast::<Channel>()?;
22 let signal = &channel.signals()?[0];
23
24 // Batched property updates.
25 {
26 let batch = BatchedPropertyUpdate::new(&[&device, &channel])?;
27 device.set_property_value("GlobalSampleRate", 1000)?;
28 channel.set_property_value("Frequency", 50.0)?;
29 batch.commit()?;
30 }
31 println!(
32 "GlobalSampleRate = {}",
33 device.property_value("GlobalSampleRate")?
34 );
35
36 // Stream reading with domain + tick conversion.
37 let reader = StreamReader::<f64>::new(signal)?;
38 let (samples, ticks) = reader.read_with_domain(100, 2000)?;
39 println!(
40 "read {} samples, {} ticks",
41 samples.sample_count(),
42 ticks.len()
43 );
44 let converter = TickConverter::from_signal(signal)?;
45 if let Some(first) = ticks.first() {
46 println!(
47 "first tick {} -> {:?}",
48 first,
49 converter.tick_to_system_time(*first)
50 );
51 }
52
53 // Callables: a Rust closure as an openDAQ function, called through openDAQ.
54 let sum = FunctionObject::from_fn(|args| {
55 let a = args[0].as_i64().unwrap_or(0);
56 let b = args[1].as_i64().unwrap_or(0);
57 Ok(Value::from(a + b))
58 })?;
59 let result = sum.call(&[Value::from(20), Value::from(22)])?;
60 println!("sum(20, 22) = {result}");
61
62 // Events: subscribe to property changes on the channel.
63 let events = channel
64 .on_property_value_write("Amplitude")?
65 .expect("event");
66 let handler = events.subscribe(|_sender, args| {
67 if let Some(args) = args {
68 println!(" event fired: {args}");
69 }
70 })?;
71 channel.set_property_value("Amplitude", 2.5)?;
72 events.unsubscribe(&handler)?;
73 channel.set_property_value("Amplitude", 1.0)?;
74 println!("Amplitude = {}", channel.property_value("Amplitude")?);
75
76 Ok(())
77}18fn main() -> opendaq::Result<()> {
19 // Instance::new() already loads the bundled modules; build from an
20 // InstanceBuilder when you want to control the module search path.
21 let builder = InstanceBuilder::new()?;
22 // The bundled modules (reference device, function blocks, streaming):
23 let bundled = opendaq::native_library_directory().expect("native libraries");
24 builder.set_module_path(&bundled.to_string_lossy())?;
25 // Your own modules folder:
26 // builder.add_module_path("/path/to/your/modules")?;
27 let instance = Instance::from_builder(&builder)?;
28 instance.add_device("daqref://device0")?;
29
30 let channel = instance
31 .find_component("Dev/RefDev0/IO/AI/RefCh0")?
32 .expect("reference channel not found")
33 .cast::<Channel>()?;
34 channel.set_property_value("Amplitude", 5.0)?;
35 channel.set_property_value("DC", 1.0)?;
36
37 let statistics = instance
38 .add_function_block("RefFBModuleStatistics")?
39 .expect("statistics function block");
40 statistics.set_property_value("BlockSize", 100)?;
41
42 let status = statistics.status_container()?.expect("status container");
43 println!(
44 "Before connect: {} ({})",
45 status.status("ComponentStatus")?.expect("status").value()?,
46 status.status_message("ComponentStatus")?
47 );
48
49 let port = &statistics.input_ports()?[0];
50 let signal = &channel.signals()?[0];
51 port.connect(signal)?;
52
53 println!(
54 "After connect: {} ({})",
55 status.status("ComponentStatus")?.expect("status").value()?,
56 status.status_message("ComponentStatus")?
57 );
58
59 let outputs = statistics.signals()?;
60 let avg = signal_by_local_id(&outputs, "avg")?.expect("avg signal");
61 let rms = signal_by_local_id(&outputs, "rms")?.expect("rms signal");
62 let reader = MultiReader::<f64>::new(&[avg, rms])?;
63
64 // The first reads may return nothing while the block waits for a complete
65 // input descriptor (the multi reader by default doesn't skip events), so
66 // retry until samples arrive.
67 for _attempt in 0..20 {
68 let values = reader.read(5, 1000)?;
69 if !values[0].is_empty() {
70 println!("{:>10}{:>12}", "avg", "rms");
71 for (a, r) in values[0].iter().zip(&values[1]) {
72 println!("{a:>10.4}{r:>12.4}");
73 }
74 return Ok(());
75 }
76 }
77 println!("Statistics block produced no samples in time.");
78 Ok(())
79}Methods from Deref<Target = BaseObject>§
Sourcepub fn cast<T: Interface>(&self) -> Result<T>
pub fn cast<T: Interface>(&self) -> Result<T>
Query this object for interface T, returning a wrapper that owns its
own reference.
This is a genuine queryInterface: an object’s interfaces live at
different virtual-table offsets, so the pointer for one interface is
not binary-compatible with another and must be queried, not merely
reinterpreted. Fails with an openDAQ error when the object does not
implement T (use BaseObject::try_cast / BaseObject::is_a to
probe first).
For the few interfaces the C API exposes no GUID for (T::interface_id()
is None), the pointer is reinterpreted unchecked, which is sound only
when the object really lies on T’s inheritance chain.
Examples found in repository?
More examples
22fn show<T: Interface>(label: &str, components: Vec<T>) -> opendaq::Result<()> {
23 let ids = components
24 .iter()
25 .map(|c| c.to_base_object().cast::<Component>()?.local_id())
26 .collect::<opendaq::Result<Vec<_>>>()?;
27 let listing = if ids.is_empty() {
28 "(none)".to_string()
29 } else {
30 ids.join(", ")
31 };
32 println!("{label}\n => {listing}\n");
33 Ok(())
34}
35
36fn main() -> opendaq::Result<()> {
37 let instance = Instance::new()?;
38 instance.add_device("daqref://device0")?;
39 let root = instance.root_device()?.expect("root device");
40
41 // Give a couple of channels some tags, so the tag filter has something to
42 // match. (RefCh0 and RefCh1 come from the reference device unlabelled.)
43 let everything = SearchFilter::recursive(&SearchFilter::any()?)?;
44 for channel in root.channels_with(Some(&everything))? {
45 let tags = channel.tags()?.expect("tags").cast::<TagsPrivate>()?;
46 tags.add("analog")?;
47 if channel.local_id()? == "RefCh0" {
48 tags.add("primary")?;
49 }
50 }
51
52 show(
53 "channels, no filter (immediate children only)",
54 root.channels()?,
55 )?;
56
57 show(
58 "channels, recursive(any)",
59 root.channels_with(Some(&SearchFilter::recursive(&SearchFilter::any()?)?))?,
60 )?;
61
62 show(
63 "channels, recursive(id = RefCh1)",
64 root.channels_with(Some(&SearchFilter::recursive(&SearchFilter::local_id(
65 "RefCh1",
66 )?)?))?,
67 )?;
68
69 let ai0_or_ai1 = SearchFilter::or(
70 &SearchFilter::local_id("AI0")?,
71 &SearchFilter::local_id("AI1")?,
72 )?;
73 show(
74 "signals, recursive(id = AI0 OR id = AI1)",
75 root.signals_with(Some(&SearchFilter::recursive(&ai0_or_ai1)?))?,
76 )?;
77
78 let not_ref_ch1 = SearchFilter::not(&SearchFilter::local_id("RefCh1")?)?;
79 show(
80 "channels, recursive(NOT id = RefCh1)",
81 root.channels_with(Some(&SearchFilter::recursive(¬_ref_ch1)?))?,
82 )?;
83
84 let analog_and_not_ref_ch1 = SearchFilter::and(
85 &SearchFilter::required_tags(vec!["analog"])?,
86 &SearchFilter::not(&SearchFilter::local_id("RefCh1")?)?,
87 )?;
88 show(
89 "channels, recursive(tag = analog AND NOT id = RefCh1)",
90 root.channels_with(Some(&SearchFilter::recursive(&analog_and_not_ref_ch1)?))?,
91 )?;
92
93 Ok(())
94}8fn main() -> opendaq::Result<()> {
9 let instance = Instance::new()?;
10 instance.add_device("daqref://device0")?;
11
12 let channel = instance
13 .find_component("Dev/RefDev0/IO/AI/RefCh0")?
14 .expect("reference channel not found")
15 .cast::<Channel>()?;
16 let signal = &channel.signals()?[0];
17
18 let reader = StreamReader::<f64>::new(signal)?;
19 println!("some samples: {:?}", reader.read(100, 1000)?.values());
20 println!("and more samples: {:?}", reader.read(100, 1000)?.values());
21 println!("and more still: {:?}", reader.read(100, 1000)?.values());
22 Ok(())
23}39fn main() -> opendaq::Result<()> {
40 let instance = Instance::new()?;
41 instance.add_device("daqref://device0")?;
42
43 let channel = instance
44 .find_component("Dev/RefDev0/IO/AI/RefCh0")?
45 .expect("reference channel not found")
46 .cast::<Channel>()?;
47 let signal = &channel.signals()?[0];
48
49 let reader = StreamReader::<f64>::new(signal)?;
50 let converter = TickConverter::from_signal(signal)?;
51
52 let (values, ticks) = reader.read_with_domain(10, 2000)?;
53 println!("Read {} samples:", values.sample_count());
54 for (value, tick) in values.iter().zip(&ticks) {
55 println!(
56 " {value:.6} @ {}",
57 timestamp_to_string(converter.tick_to_unix_nanos(*tick))
58 );
59 }
60 Ok(())
61}Sourcepub fn try_cast<T: Interface>(&self) -> Option<T>
pub fn try_cast<T: Interface>(&self) -> Option<T>
Like BaseObject::cast, but returns None when the object does not
implement T.
Sourcepub fn is_a<T: Interface>(&self) -> bool
pub fn is_a<T: Interface>(&self) -> bool
True when the object implements interface T (a borrowInterface
probe; adds no reference). Returns false for interfaces without a
GUID in the C API, which cannot be probed.
Sourcepub fn equals<T: Interface>(&self, other: &T) -> Result<bool>
pub fn equals<T: Interface>(&self, other: &T) -> Result<bool>
True when openDAQ considers the two objects equal.
Sourcepub fn ptr_eq<T: Interface>(&self, other: &T) -> bool
pub fn ptr_eq<T: Interface>(&self, other: &T) -> bool
Identity comparison: both wrappers refer to the same native object. (Note that pointers to different interfaces of one object differ; this compares the raw interface pointers.)
Sourcepub fn dispose(&self) -> Result<()>
pub fn dispose(&self) -> Result<()>
Release the object’s internal resources early (openDAQ dispose).
The wrapper itself stays alive; most callers never need this.
Sourcepub fn component_kind(&self) -> Option<ComponentKind>
pub fn component_kind(&self) -> Option<ComponentKind>
The most-derived component interface this object implements (probed
most-derived first), or None when it is not a component.
Sourcepub fn to_value(&self) -> Result<Value>
pub fn to_value(&self) -> Result<Value>
The natural Rust value of this object: a boxed scalar yields its
native value, a daq list a Vec, a daq dict key/value pairs – with
elements converted recursively – and an object with no natural Rust
form (a device, a property object, …) comes back as
Value::Object, for the caller to BaseObject::cast.
Trait Implementations§
Source§impl Clone for SignalConfig
impl Clone for SignalConfig
Source§fn clone(&self) -> SignalConfig
fn clone(&self) -> SignalConfig
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for SignalConfig
impl Debug for SignalConfig
Source§impl Deref for SignalConfig
impl Deref for SignalConfig
Source§impl Display for SignalConfig
impl Display for SignalConfig
Source§impl From<&SignalConfig> for Value
impl From<&SignalConfig> for Value
Source§fn from(value: &SignalConfig) -> Value
fn from(value: &SignalConfig) -> Value
Source§impl From<SignalConfig> for Value
impl From<SignalConfig> for Value
Source§fn from(value: SignalConfig) -> Value
fn from(value: SignalConfig) -> Value
Source§impl Interface for SignalConfig
impl Interface for SignalConfig
Source§fn interface_id() -> Option<IntfID>
fn interface_id() -> Option<IntfID>
None for the few coretypes interfaces the
C API exposes no id for (IBaseObject, IFunction, IProcedure, …).Source§unsafe fn from_raw(ptr: *mut c_void) -> Option<Self>
unsafe fn from_raw(ptr: *mut c_void) -> Option<Self>
None for null. Read moreSource§fn as_base_object(&self) -> &BaseObject
fn as_base_object(&self) -> &BaseObject
IBaseObject interface.Source§fn to_base_object(&self) -> BaseObject
fn to_base_object(&self) -> BaseObject
BaseObject handle to the same underlying object.