nanonis_rs/client/dig_lines.rs
1use super::NanonisClient;
2use crate::error::NanonisError;
3use crate::types::NanonisValue;
4
5/// Digital port selection.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
7pub enum DigitalPort {
8 /// Port A
9 #[default]
10 PortA = 0,
11 /// Port B
12 PortB = 1,
13 /// Port C
14 PortC = 2,
15 /// Port D
16 PortD = 3,
17}
18
19impl From<DigitalPort> for u32 {
20 fn from(port: DigitalPort) -> Self {
21 port as u32
22 }
23}
24
25impl From<DigitalPort> for u16 {
26 fn from(port: DigitalPort) -> Self {
27 port as u16
28 }
29}
30
31/// Digital line direction.
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
33pub enum DigitalDirection {
34 /// Input direction
35 #[default]
36 Input = 0,
37 /// Output direction
38 Output = 1,
39}
40
41impl From<DigitalDirection> for u32 {
42 fn from(dir: DigitalDirection) -> Self {
43 dir as u32
44 }
45}
46
47/// Digital line polarity.
48#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
49pub enum DigitalPolarity {
50 /// Low active
51 #[default]
52 LowActive = 0,
53 /// High active
54 HighActive = 1,
55}
56
57impl From<DigitalPolarity> for u32 {
58 fn from(pol: DigitalPolarity) -> Self {
59 pol as u32
60 }
61}
62
63/// Digital line configuration.
64#[derive(Debug, Clone, Copy)]
65pub struct DigitalLineConfig {
66 /// Digital line number (1-8)
67 pub line: u32,
68 /// Port selection
69 pub port: DigitalPort,
70 /// Line direction (input/output)
71 pub direction: DigitalDirection,
72 /// Line polarity
73 pub polarity: DigitalPolarity,
74}
75
76impl Default for DigitalLineConfig {
77 fn default() -> Self {
78 Self {
79 line: 1,
80 port: DigitalPort::PortA,
81 direction: DigitalDirection::Input,
82 polarity: DigitalPolarity::LowActive,
83 }
84 }
85}
86
87/// Pulse generator configuration.
88#[derive(Debug, Clone)]
89pub struct PulseConfig {
90 /// Port selection
91 pub port: DigitalPort,
92 /// Digital lines to pulse (1-8)
93 pub lines: Vec<u8>,
94 /// Pulse width in seconds
95 pub pulse_width_s: f32,
96 /// Pulse pause in seconds
97 pub pulse_pause_s: f32,
98 /// Number of pulses (1-32767)
99 pub num_pulses: i32,
100 /// Wait until all pulses are generated before returning
101 pub wait_until_finished: bool,
102}
103
104impl Default for PulseConfig {
105 fn default() -> Self {
106 Self {
107 port: DigitalPort::PortA,
108 lines: vec![1],
109 pulse_width_s: 0.001,
110 pulse_pause_s: 0.001,
111 num_pulses: 1,
112 wait_until_finished: true,
113 }
114 }
115}
116
117impl NanonisClient {
118 /// Configure the properties of a digital line.
119 ///
120 /// # Arguments
121 /// * `config` - A [`DigitalLineConfig`] struct with line configuration
122 ///
123 /// # Errors
124 /// Returns `NanonisError` if communication fails.
125 ///
126 /// # Examples
127 /// ```no_run
128 /// use nanonis_rs::NanonisClient;
129 /// use nanonis_rs::dig_lines::{DigitalLineConfig, DigitalPort, DigitalDirection, DigitalPolarity};
130 ///
131 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
132 /// let config = DigitalLineConfig {
133 /// line: 1,
134 /// port: DigitalPort::PortA,
135 /// direction: DigitalDirection::Output,
136 /// polarity: DigitalPolarity::HighActive,
137 /// };
138 /// client.dig_lines_props_set(&config)?;
139 /// # Ok::<(), Box<dyn std::error::Error>>(())
140 /// ```
141 pub fn dig_lines_props_set(&mut self, config: &DigitalLineConfig) -> Result<(), NanonisError> {
142 self.quick_send(
143 "DigLines.PropsSet",
144 vec![
145 NanonisValue::U32(config.line),
146 NanonisValue::U32(config.port.into()),
147 NanonisValue::U32(config.direction.into()),
148 NanonisValue::U32(config.polarity.into()),
149 ],
150 vec!["I", "I", "I", "I"],
151 vec![],
152 )?;
153 Ok(())
154 }
155
156 /// Set the status of a digital output line.
157 ///
158 /// # Arguments
159 /// * `port` - Port selection
160 /// * `line` - Digital line number (1-8)
161 /// * `active` - True for active, false for inactive
162 ///
163 /// # Errors
164 /// Returns `NanonisError` if communication fails.
165 pub fn dig_lines_out_status_set(
166 &mut self,
167 port: DigitalPort,
168 line: u32,
169 active: bool,
170 ) -> Result<(), NanonisError> {
171 let status = if active { 1u32 } else { 0u32 };
172 self.quick_send(
173 "DigLines.OutStatusSet",
174 vec![
175 NanonisValue::U32(port.into()),
176 NanonisValue::U32(line),
177 NanonisValue::U32(status),
178 ],
179 vec!["I", "I", "I"],
180 vec![],
181 )?;
182 Ok(())
183 }
184
185 /// Read the TTL voltages present at the pins of the selected port.
186 ///
187 /// # Arguments
188 /// * `port` - Port selection
189 ///
190 /// # Returns
191 /// A vector of TTL values for each line (0 = inactive, 1 = active).
192 ///
193 /// # Errors
194 /// Returns `NanonisError` if communication fails.
195 pub fn dig_lines_ttl_val_get(&mut self, port: DigitalPort) -> Result<Vec<u32>, NanonisError> {
196 let result = self.quick_send(
197 "DigLines.TTLValGet",
198 vec![NanonisValue::U16(port.into())],
199 vec!["H"],
200 vec!["i", "*I"],
201 )?;
202
203 if result.len() >= 2 {
204 Ok(result[1].as_u32_array()?.to_vec())
205 } else {
206 Err(NanonisError::Protocol("Invalid response".to_string()))
207 }
208 }
209
210 /// Configure and start the pulse generator on the selected digital outputs.
211 ///
212 /// # Arguments
213 /// * `config` - A [`PulseConfig`] struct with pulse configuration
214 ///
215 /// # Errors
216 /// Returns `NanonisError` if communication fails.
217 ///
218 /// # Examples
219 /// ```no_run
220 /// use nanonis_rs::NanonisClient;
221 /// use nanonis_rs::dig_lines::{PulseConfig, DigitalPort};
222 ///
223 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
224 /// let config = PulseConfig {
225 /// port: DigitalPort::PortA,
226 /// lines: vec![1, 2],
227 /// pulse_width_s: 0.001,
228 /// pulse_pause_s: 0.001,
229 /// num_pulses: 10,
230 /// wait_until_finished: true,
231 /// };
232 /// client.dig_lines_pulse(&config)?;
233 /// # Ok::<(), Box<dyn std::error::Error>>(())
234 /// ```
235 pub fn dig_lines_pulse(&mut self, config: &PulseConfig) -> Result<(), NanonisError> {
236 let wait_flag = if config.wait_until_finished {
237 1u32
238 } else {
239 0u32
240 };
241
242 self.quick_send(
243 "DigLines.Pulse",
244 vec![
245 NanonisValue::U16(config.port.into()),
246 NanonisValue::ArrayU8(config.lines.clone()),
247 NanonisValue::F32(config.pulse_width_s),
248 NanonisValue::F32(config.pulse_pause_s),
249 NanonisValue::I32(config.num_pulses),
250 NanonisValue::U32(wait_flag),
251 ],
252 vec!["H", "+*b", "f", "f", "i", "I"],
253 vec![],
254 )?;
255 Ok(())
256 }
257}