nanonis_rs/client/signals/mod.rs
1mod types;
2pub use types::*;
3
4use super::NanonisClient;
5use crate::error::NanonisError;
6use crate::types::NanonisValue;
7
8impl NanonisClient {
9 /// Get available signal names
10 pub fn signal_names_get(&mut self) -> Result<Vec<String>, NanonisError> {
11 let result = self.quick_send("Signals.NamesGet", vec![], vec![], vec!["+*c"])?;
12 match result.first() {
13 Some(value) => {
14 let signal_names = value.as_string_array()?.to_vec();
15
16 Ok(signal_names)
17 }
18 None => Err(NanonisError::Protocol(
19 "No signal names returned".to_string(),
20 )),
21 }
22 }
23
24 /// Get calibration and offset of a signal by index
25 pub fn signals_calibr_get(
26 &mut self,
27 signal_index: SignalIndex,
28 ) -> Result<(f32, f32), NanonisError> {
29 let result = self.quick_send(
30 "Signals.CalibrGet",
31 vec![NanonisValue::I32(signal_index.into())],
32 vec!["i"],
33 vec!["f", "f"],
34 )?;
35 if result.len() >= 2 {
36 Ok((result[0].as_f32()?, result[1].as_f32()?))
37 } else {
38 Err(NanonisError::Protocol(
39 "Invalid calibration response".to_string(),
40 ))
41 }
42 }
43
44 /// Get range limits of a signal by index
45 pub fn signals_range_get(
46 &mut self,
47 signal_index: SignalIndex,
48 ) -> Result<(f32, f32), NanonisError> {
49 let result = self.quick_send(
50 "Signals.RangeGet",
51 vec![NanonisValue::I32(signal_index.into())],
52 vec!["i"],
53 vec!["f", "f"],
54 )?;
55 if result.len() >= 2 {
56 Ok((result[0].as_f32()?, result[1].as_f32()?)) // (max, min)
57 } else {
58 Err(NanonisError::Protocol("Invalid range response".to_string()))
59 }
60 }
61
62 /// Get current values of signals by index(es)
63 pub fn signals_vals_get(
64 &mut self,
65 signal_indexes: Vec<i32>,
66 wait_for_newest_data: bool,
67 ) -> Result<Vec<f32>, NanonisError> {
68 let indexes = signal_indexes;
69 let wait_flag = if wait_for_newest_data { 1u32 } else { 0u32 };
70
71 let result = self.quick_send(
72 "Signals.ValsGet",
73 vec![
74 NanonisValue::ArrayI32(indexes),
75 NanonisValue::U32(wait_flag),
76 ],
77 vec!["+*i", "I"],
78 vec!["i", "*f"],
79 )?;
80
81 if result.len() >= 2 {
82 match &result[1] {
83 NanonisValue::ArrayF32(values) => Ok(values.clone()),
84 _ => Err(NanonisError::Protocol(
85 "Invalid signal values response".to_string(),
86 )),
87 }
88 } else {
89 Err(NanonisError::Protocol(
90 "Incomplete signal values response".to_string(),
91 ))
92 }
93 }
94
95 /// Get the current value of a single selected signal.
96 ///
97 /// Returns the current value of the selected signal, oversampled during the
98 /// Acquisition Period time (Tap). The signal is continuously oversampled and published
99 /// every Tap seconds.
100 ///
101 /// # Signal Measurement Principle
102 /// This function waits for the next oversampled data to be published and returns its value.
103 /// It does not trigger a measurement but waits for data to be published. The function
104 /// returns a value 0 to Tap seconds after being called.
105 ///
106 /// **Important**: If you change a signal and immediately call this function, you might
107 /// get "old" data measured before the signal change. Set `wait_for_newest_data` to `true`
108 /// to ensure you get only fresh data.
109 ///
110 /// # Arguments
111 /// * `signal_index` - Signal index (0-127)
112 /// * `wait_for_newest_data` - If `true`, discards first value and waits for fresh data.
113 /// Takes Tap to 2*Tap seconds. If `false`, returns next available value (0 to Tap seconds).
114 ///
115 /// # Returns
116 /// The signal value in physical units.
117 ///
118 /// # Errors
119 /// Returns `NanonisError` if:
120 /// - Invalid signal index provided
121 /// - Communication timeout or protocol error
122 ///
123 /// # Examples
124 /// ```no_run
125 /// use nanonis_rs::NanonisClient;
126 /// use nanonis_rs::signals::SignalIndex;
127 ///
128 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
129 ///
130 /// // Read bias signal immediately
131 /// let bias_value = client.signal_val_get(SignalIndex(24), false)?;
132 ///
133 /// // Wait for fresh data after signal change
134 /// let fresh_value = client.signal_val_get(SignalIndex(24), true)?;
135 /// # Ok::<(), Box<dyn std::error::Error>>(())
136 /// ```
137 pub fn signal_val_get(
138 &mut self,
139 signal_index: impl Into<SignalIndex>,
140 wait_for_newest_data: bool,
141 ) -> Result<f32, NanonisError> {
142 let wait_flag = if wait_for_newest_data { 1u32 } else { 0u32 };
143
144 let result = self.quick_send(
145 "Signals.ValGet",
146 vec![
147 NanonisValue::I32(signal_index.into().into()),
148 NanonisValue::U32(wait_flag),
149 ],
150 vec!["i", "I"],
151 vec!["f"],
152 )?;
153
154 match result.first() {
155 Some(value) => Ok(value.as_f32()?),
156 None => Err(NanonisError::Protocol(
157 "No signal value returned".to_string(),
158 )),
159 }
160 }
161
162 /// Get the list of measurement channels names available in the software.
163 ///
164 /// Returns the names of measurement channels used in sweepers and other measurement modules.
165 ///
166 /// **Important Note**: Measurement channels are different from Signals. Measurement channels
167 /// are used in sweepers, while Signals are used by graphs and other modules. The indexes
168 /// returned here are used for sweeper channel configuration (e.g., `GenSwp.ChannelsGet/Set`).
169 ///
170 /// # Returns
171 /// A vector of measurement channel names where each name corresponds to an index
172 /// that can be used in sweeper functions.
173 ///
174 /// # Errors
175 /// Returns `NanonisError` if communication fails or protocol error occurs.
176 ///
177 /// # Examples
178 /// ```no_run
179 /// use nanonis_rs::NanonisClient;
180 ///
181 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
182 ///
183 /// let meas_channels = client.signals_meas_names_get()?;
184 /// println!("Available measurement channels: {}", meas_channels.len());
185 ///
186 /// for (index, name) in meas_channels.iter().enumerate() {
187 /// println!(" {}: {}", index, name);
188 /// }
189 /// # Ok::<(), Box<dyn std::error::Error>>(())
190 /// ```
191 pub fn signals_meas_names_get(&mut self) -> Result<Vec<String>, NanonisError> {
192 let result = self.quick_send(
193 "Signals.MeasNamesGet",
194 vec![],
195 vec![],
196 vec!["i", "i", "*+c"],
197 )?;
198
199 if result.len() >= 3 {
200 let meas_names = result[2].as_string_array()?.to_vec();
201 Ok(meas_names)
202 } else {
203 Err(NanonisError::Protocol(
204 "Invalid measurement names response".to_string(),
205 ))
206 }
207 }
208
209 /// Get the list of additional Real-Time (RT) signals and current assignments.
210 ///
211 /// Returns the list of additional RT signals available for assignment to Internal 23 and 24,
212 /// plus the names of signals currently assigned to these internal channels.
213 ///
214 /// **Note**: This assignment in the Signals Manager doesn't automatically make them available
215 /// in graphs and modules. Internal 23 and 24 must be assigned to one of the 24 display slots
216 /// using functions like `Signals.InSlotSet` to be visible in the software.
217 ///
218 /// # Returns
219 /// A tuple containing:
220 /// - `Vec<String>` - List of additional RT signals that can be assigned to Internal 23/24
221 /// - `String` - Name of RT signal currently assigned to Internal 23
222 /// - `String` - Name of RT signal currently assigned to Internal 24
223 ///
224 /// # Errors
225 /// Returns `NanonisError` if communication fails or protocol error occurs.
226 ///
227 /// # Examples
228 /// ```no_run
229 /// use nanonis_rs::NanonisClient;
230 ///
231 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
232 ///
233 /// let (available_signals, internal_23, internal_24) = client.signals_add_rt_get()?;
234 ///
235 /// println!("Available additional RT signals: {}", available_signals.len());
236 /// for (i, signal) in available_signals.iter().enumerate() {
237 /// println!(" {}: {}", i, signal);
238 /// }
239 ///
240 /// println!("Internal 23 assigned to: {}", internal_23);
241 /// println!("Internal 24 assigned to: {}", internal_24);
242 /// # Ok::<(), Box<dyn std::error::Error>>(())
243 /// ```
244 pub fn signals_add_rt_get(&mut self) -> Result<(Vec<String>, String, String), NanonisError> {
245 let result = self.quick_send(
246 "Signals.AddRTGet",
247 vec![],
248 vec![],
249 vec!["i", "i", "*+c", "i", "*-c", "i", "*-c"],
250 )?;
251
252 if result.len() >= 7 {
253 let available_signals = result[2].as_string_array()?.to_vec();
254 let internal_23 = result[4].as_string()?.to_string();
255 let internal_24 = result[6].as_string()?.to_string();
256 Ok((available_signals, internal_23, internal_24))
257 } else {
258 Err(NanonisError::Protocol(
259 "Invalid additional RT signals response".to_string(),
260 ))
261 }
262 }
263
264 /// Assign additional Real-Time (RT) signals to Internal 23 and 24 signals.
265 ///
266 /// Links advanced RT signals to Internal 23 and Internal 24 in the Signals Manager.
267 /// This enables routing of specialized real-time signals through the internal channel system.
268 ///
269 /// **Important Note**: This assignment only links the RT signals to Internal 23/24.
270 /// To make them visible in graphs and available for acquisition in modules, Internal 23 and 24
271 /// must be assigned to one of the 24 display slots using functions like `Signals.InSlotSet`.
272 ///
273 /// # Arguments
274 /// * `additional_rt_signal_1` - Index of the RT signal to assign to Internal 23 (from `signals_add_rt_get()`)
275 /// * `additional_rt_signal_2` - Index of the RT signal to assign to Internal 24 (from `signals_add_rt_get()`)
276 ///
277 /// # Errors
278 /// Returns `NanonisError` if:
279 /// - Invalid RT signal indices provided
280 /// - RT signals are not available or accessible
281 /// - Communication fails or protocol error occurs
282 ///
283 /// # Examples
284 /// ```no_run
285 /// use nanonis_rs::NanonisClient;
286 ///
287 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
288 ///
289 /// // First, get the available RT signals
290 /// let (available_signals, current_23, current_24) = client.signals_add_rt_get()?;
291 ///
292 /// println!("Available RT signals:");
293 /// for (i, signal) in available_signals.iter().enumerate() {
294 /// println!(" {}: {}", i, signal);
295 /// }
296 ///
297 /// // Assign RT signal index 0 to Internal 23 and index 1 to Internal 24
298 /// client.signals_add_rt_set(0, 1)?;
299 ///
300 /// // Verify the assignment
301 /// let (_, new_23, new_24) = client.signals_add_rt_get()?;
302 /// println!("Internal 23 now assigned to: {}", new_23);
303 /// println!("Internal 24 now assigned to: {}", new_24);
304 /// # Ok::<(), Box<dyn std::error::Error>>(())
305 /// ```
306 pub fn signals_add_rt_set(
307 &mut self,
308 additional_rt_signal_1: i32,
309 additional_rt_signal_2: i32,
310 ) -> Result<(), NanonisError> {
311 self.quick_send(
312 "Signals.AddRTSet",
313 vec![
314 NanonisValue::I32(additional_rt_signal_1),
315 NanonisValue::I32(additional_rt_signal_2),
316 ],
317 vec!["i", "i"],
318 vec![],
319 )?;
320 Ok(())
321 }
322
323 /// Get the input slot assignments for each signal.
324 ///
325 /// Returns the hardware input slot index for each signal in the system.
326 /// Input slots represent the physical or virtual input sources that feed
327 /// into each signal channel.
328 ///
329 /// # Returns
330 /// Vector of input slot indices, one for each signal in the system.
331 ///
332 /// # Errors
333 /// Returns `NanonisError` if communication fails or protocol error occurs.
334 ///
335 /// # Examples
336 /// ```no_run
337 /// use nanonis_rs::NanonisClient;
338 ///
339 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
340 ///
341 /// let input_slots = client.signals_in_slots_get()?;
342 /// println!("Input slot assignments for {} signals:", input_slots.len());
343 /// for (signal_idx, slot_idx) in input_slots.iter().enumerate() {
344 /// println!(" Signal {}: Input slot {}", signal_idx, slot_idx);
345 /// }
346 /// # Ok::<(), Box<dyn std::error::Error>>(())
347 /// ```
348 pub fn signals_in_slots_get(&mut self) -> Result<Vec<i32>, NanonisError> {
349 let result = self.quick_send(
350 "Signals.InSlotsGet",
351 vec![],
352 vec![],
353 vec!["i", "*i"],
354 )?;
355
356 if result.len() >= 2 {
357 Ok(result[1].as_i32_array()?.to_vec())
358 } else {
359 Err(NanonisError::Protocol(
360 "Invalid input slots response".to_string(),
361 ))
362 }
363 }
364}