pokeys_thread/operations.rs
1//! # Device Operations
2//!
3//! This module provides a trait for performing device operations.
4//! The `DeviceOperations` trait is implemented by the `ThreadControllerImpl`
5//! to provide a high-level interface for device operations.
6//!
7//! ## Usage Example
8//!
9//! ```ignore
10//! use pokeys_thread::{ThreadControllerBuilder, ThreadController, DeviceOperations};
11//!
12//! // Create a thread controller
13//! let mut controller = ThreadControllerBuilder::new().build();
14//!
15//! // Discover USB devices
16//! let devices = controller.discover_usb_devices().unwrap();
17//!
18//! if !devices.is_empty() {
19//! // Start a thread for the first device
20//! let thread_id = controller.start_usb_device_thread(devices[0]).unwrap();
21//!
22//! // Set a digital output
23//! controller.set_digital_output(thread_id, 1, true).unwrap();
24//!
25//! // Get a digital input
26//! let input = controller.get_digital_input(thread_id, 2).unwrap();
27//! println!("Digital input 2: {}", input);
28//!
29//! // Set a PWM duty cycle
30//! controller.set_pwm_duty_cycle_percent(thread_id, 0, 50.0).unwrap();
31//!
32//! // Configure an encoder
33//! controller.configure_encoder(thread_id, 0, 1, 2, true, true).unwrap();
34//!
35//! // Get an encoder value
36//! let value = controller.get_encoder_value(thread_id, 0).unwrap();
37//! println!("Encoder 0 value: {}", value);
38//! }
39//! ```
40
41use crate::error::Result;
42use pokeys_lib::{PinCapability, ServoConfig, USPIBridgeConfig};
43
44/// Device operations trait for performing device-specific operations.
45///
46/// This trait provides a high-level interface for performing device operations
47/// such as setting digital outputs, reading digital inputs, configuring encoders,
48/// and more. It is implemented by the `ThreadControllerImpl` to provide a
49/// convenient way to interact with devices.
50pub trait DeviceOperations {
51 /// Set a digital output pin.
52 ///
53 /// # Parameters
54 ///
55 /// * `thread_id` - The ID of the thread to send the command to.
56 /// * `pin` - The pin number to set.
57 /// * `value` - The value to set (true for high, false for low).
58 ///
59 /// # Errors
60 ///
61 /// Returns an error if the thread is not found or if the command send fails.
62 fn set_digital_output(&self, thread_id: u32, pin: u32, value: bool) -> Result<()>;
63
64 /// Get a digital input pin.
65 ///
66 /// # Parameters
67 ///
68 /// * `thread_id` - The ID of the thread to get the input from.
69 /// * `pin` - The pin number to read.
70 ///
71 /// # Returns
72 ///
73 /// The value of the digital input (true for high, false for low).
74 ///
75 /// # Errors
76 ///
77 /// Returns an error if the thread is not found or if the pin is invalid.
78 fn get_digital_input(&self, thread_id: u32, pin: u32) -> Result<bool>;
79
80 /// Set an analog output.
81 ///
82 /// # Parameters
83 ///
84 /// * `thread_id` - The ID of the thread to send the command to.
85 /// * `pin` - The pin number to set.
86 /// * `value` - The value to set (0-4095 for 12-bit DAC).
87 ///
88 /// # Errors
89 ///
90 /// Returns an error if the thread is not found or if the command send fails.
91 fn set_analog_output(&self, thread_id: u32, pin: u32, value: u32) -> Result<()>;
92
93 /// Get an analog input.
94 ///
95 /// # Parameters
96 ///
97 /// * `thread_id` - The ID of the thread to get the input from.
98 /// * `pin` - The pin number to read.
99 ///
100 /// # Returns
101 ///
102 /// The value of the analog input (0-4095 for 12-bit ADC).
103 ///
104 /// # Errors
105 ///
106 /// Returns an error if the thread is not found or if the pin is invalid.
107 fn get_analog_input(&self, thread_id: u32, pin: u32) -> Result<u32>;
108
109 /// Set a PWM duty cycle.
110 ///
111 /// # Parameters
112 ///
113 /// * `thread_id` - The ID of the thread to send the command to.
114 /// * `channel` - The PWM channel to set.
115 /// * `duty` - The duty cycle to set (0-4095 for 12-bit PWM).
116 ///
117 /// # Errors
118 ///
119 /// Returns an error if the thread is not found or if the command send fails.
120 fn set_pwm_duty_cycle(&self, thread_id: u32, channel: usize, duty: u32) -> Result<()>;
121
122 /// Set a PWM duty cycle as a percentage.
123 ///
124 /// # Parameters
125 ///
126 /// * `thread_id` - The ID of the thread to send the command to.
127 /// * `channel` - The PWM channel to set.
128 /// * `duty_percent` - The duty cycle to set as a percentage (0.0-100.0).
129 ///
130 /// # Errors
131 ///
132 /// Returns an error if the thread is not found or if the command send fails.
133 fn set_pwm_duty_cycle_percent(
134 &self,
135 thread_id: u32,
136 channel: usize,
137 duty_percent: f32,
138 ) -> Result<()>;
139
140 /// Configure a servo on a PWM pin.
141 ///
142 /// # Parameters
143 ///
144 /// * `thread_id` - The ID of the thread to send the command to.
145 /// * `pin` - The PWM pin to configure (17-22).
146 /// * `servo_config` - The servo configuration.
147 ///
148 /// # Errors
149 ///
150 /// Returns an error if the thread is not found or if the command send fails.
151 fn configure_servo(&self, thread_id: u32, pin: u8, servo_config: ServoConfig) -> Result<()>;
152
153 /// Set servo angle (for 180° and 360° position servos).
154 ///
155 /// # Parameters
156 ///
157 /// * `thread_id` - The ID of the thread to send the command to.
158 /// * `pin` - The PWM pin (17-22).
159 /// * `angle` - The angle in degrees (0-180 for 180° servos, 0-360 for 360° position servos).
160 ///
161 /// # Errors
162 ///
163 /// Returns an error if the thread is not found or if the command send fails.
164 fn set_servo_angle(&self, thread_id: u32, pin: u8, angle: f32) -> Result<()>;
165
166 /// Set servo speed (for 360° speed servos).
167 ///
168 /// # Parameters
169 ///
170 /// * `thread_id` - The ID of the thread to send the command to.
171 /// * `pin` - The PWM pin (17-22).
172 /// * `speed` - The speed (-100.0 to 100.0, where 0 is stop, positive is clockwise).
173 ///
174 /// # Errors
175 ///
176 /// Returns an error if the thread is not found or if the command send fails.
177 fn set_servo_speed(&self, thread_id: u32, pin: u8, speed: f32) -> Result<()>;
178
179 /// Stop a servo (set to neutral position).
180 ///
181 /// # Parameters
182 ///
183 /// * `thread_id` - The ID of the thread to send the command to.
184 /// * `pin` - The PWM pin (17-22).
185 ///
186 /// # Errors
187 ///
188 /// Returns an error if the thread is not found or if the command send fails.
189 fn stop_servo(&self, thread_id: u32, pin: u8) -> Result<()>;
190
191 /// Write data to an I2C device.
192 ///
193 /// # Parameters
194 ///
195 /// * `thread_id` - The ID of the thread to send the command to.
196 /// * `address` - The I2C device address.
197 /// * `data` - The data to write.
198 ///
199 /// # Errors
200 ///
201 /// Returns an error if the thread is not found or if the command send fails.
202 fn i2c_write(&self, thread_id: u32, address: u8, data: Vec<u8>) -> Result<()>;
203
204 /// Read data from an I2C device.
205 ///
206 /// # Parameters
207 ///
208 /// * `thread_id` - The ID of the thread to send the command to.
209 /// * `address` - The I2C device address.
210 /// * `length` - The number of bytes to read.
211 ///
212 /// # Returns
213 ///
214 /// The data read from the device.
215 ///
216 /// # Errors
217 ///
218 /// Returns an error if the thread is not found or if the command send fails.
219 fn i2c_read(&self, thread_id: u32, address: u8, length: u8) -> Result<Vec<u8>>;
220
221 /// Write then read from an I2C device (combined operation).
222 ///
223 /// # Parameters
224 ///
225 /// * `thread_id` - The ID of the thread to send the command to.
226 /// * `address` - The I2C device address.
227 /// * `write_data` - The data to write first.
228 /// * `read_length` - The number of bytes to read after writing.
229 ///
230 /// # Returns
231 ///
232 /// The data read from the device.
233 ///
234 /// # Errors
235 ///
236 /// Returns an error if the thread is not found or if the command send fails.
237 fn i2c_write_read(
238 &self,
239 thread_id: u32,
240 address: u8,
241 write_data: Vec<u8>,
242 read_length: u8,
243 ) -> Result<Vec<u8>>;
244
245 /// Scan for I2C devices on the bus.
246 ///
247 /// # Parameters
248 ///
249 /// * `thread_id` - The ID of the thread to send the command to.
250 ///
251 /// # Returns
252 ///
253 /// A vector of found I2C device addresses.
254 ///
255 /// # Errors
256 ///
257 /// Returns an error if the thread is not found or if the command send fails.
258 fn i2c_scan(&self, thread_id: u32) -> Result<Vec<u8>>;
259
260 /// Configure uSPIBridge with custom pinout.
261 ///
262 /// # Parameters
263 ///
264 /// * `thread_id` - The ID of the thread to send the command to.
265 /// * `config` - The uSPIBridge configuration.
266 ///
267 /// # Errors
268 ///
269 /// Returns an error if the thread is not found or if the command send fails.
270 fn configure_uspibridge(&self, thread_id: u32, config: USPIBridgeConfig) -> Result<()>;
271
272 /// Send uSPIBridge command.
273 ///
274 /// # Parameters
275 ///
276 /// * `thread_id` - The ID of the thread to send the command to.
277 /// * `command` - The uSPIBridge command data.
278 ///
279 /// # Returns
280 ///
281 /// The response data from the uSPIBridge.
282 ///
283 /// # Errors
284 ///
285 /// Returns an error if the thread is not found or if the command send fails.
286 fn uspibridge_command(&self, thread_id: u32, command: Vec<u8>) -> Result<Vec<u8>>;
287
288 /// Check if a pin supports a specific capability.
289 ///
290 /// # Parameters
291 ///
292 /// * `thread_id` - The ID of the thread to check.
293 /// * `pin` - The pin number to check.
294 /// * `capability` - The capability to check for.
295 ///
296 /// # Returns
297 ///
298 /// True if the pin supports the capability, false otherwise.
299 ///
300 /// # Errors
301 ///
302 /// Returns an error if the thread is not found.
303 fn check_pin_capability(
304 &self,
305 thread_id: u32,
306 pin: u8,
307 capability: PinCapability,
308 ) -> Result<bool>;
309
310 /// Get device model information.
311 ///
312 /// # Parameters
313 ///
314 /// * `thread_id` - The ID of the thread to get model info from.
315 ///
316 /// # Returns
317 ///
318 /// Device model name if available.
319 ///
320 /// # Errors
321 ///
322 /// Returns an error if the thread is not found.
323 fn get_device_model(&self, thread_id: u32) -> Result<Option<String>>;
324
325 /// Validate pin configuration before operation.
326 ///
327 /// # Parameters
328 ///
329 /// * `thread_id` - The ID of the thread to validate.
330 /// * `pin` - The pin number to validate.
331 /// * `operation` - Description of the operation being attempted.
332 ///
333 /// # Errors
334 ///
335 /// Returns an error if the pin cannot perform the operation.
336 fn validate_pin_operation(&self, thread_id: u32, pin: u8, operation: &str) -> Result<()>;
337
338 /// Set multiple digital outputs in a single operation.
339 ///
340 /// # Parameters
341 ///
342 /// * `thread_id` - The ID of the thread to send the command to.
343 /// * `pin_states` - Vector of (pin, state) tuples.
344 ///
345 /// # Errors
346 ///
347 /// Returns an error if the thread is not found or if the command send fails.
348 fn set_digital_outputs_bulk(&self, thread_id: u32, pin_states: Vec<(u32, bool)>) -> Result<()>;
349
350 /// Set multiple PWM duty cycles in a single operation.
351 ///
352 /// # Parameters
353 ///
354 /// * `thread_id` - The ID of the thread to send the command to.
355 /// * `channel_duties` - Vector of (channel, duty) tuples.
356 ///
357 /// # Errors
358 ///
359 /// Returns an error if the thread is not found or if the command send fails.
360 fn set_pwm_duties_bulk(&self, thread_id: u32, channel_duties: Vec<(usize, u32)>) -> Result<()>;
361
362 /// Read multiple analog inputs in a single operation.
363 ///
364 /// # Parameters
365 ///
366 /// * `thread_id` - The ID of the thread to read from.
367 /// * `pins` - Vector of pin numbers to read.
368 ///
369 /// # Returns
370 ///
371 /// Vector of analog values corresponding to the requested pins.
372 ///
373 /// # Errors
374 ///
375 /// Returns an error if the thread is not found.
376 fn read_analog_inputs_bulk(&self, thread_id: u32, pins: Vec<u32>) -> Result<Vec<u32>>;
377
378 /// Get an encoder value.
379 ///
380 /// # Parameters
381 ///
382 /// * `thread_id` - The ID of the thread to get the encoder value from.
383 /// * `encoder_index` - The encoder index to read.
384 ///
385 /// # Returns
386 ///
387 /// The value of the encoder.
388 ///
389 /// # Errors
390 ///
391 /// Returns an error if the thread is not found or if the encoder index is invalid.
392 fn get_encoder_value(&self, thread_id: u32, encoder_index: u32) -> Result<i32>;
393
394 /// Configure an encoder.
395 ///
396 /// # Parameters
397 ///
398 /// * `thread_id` - The ID of the thread to send the command to.
399 /// * `encoder_index` - The encoder index to configure.
400 /// * `pin_a` - The pin number for encoder input A.
401 /// * `pin_b` - The pin number for encoder input B.
402 /// * `enabled` - Whether the encoder is enabled.
403 /// * `sampling_4x` - Whether to use 4x sampling.
404 ///
405 /// # Errors
406 ///
407 /// Returns an error if the thread is not found or if the command send fails.
408 fn configure_encoder(
409 &self,
410 thread_id: u32,
411 encoder_index: u32,
412 pin_a: u32,
413 pin_b: u32,
414 enabled: bool,
415 sampling_4x: bool,
416 ) -> Result<()>;
417
418 /// Reset a digital counter.
419 ///
420 /// # Parameters
421 ///
422 /// * `thread_id` - The ID of the thread to send the command to.
423 /// * `pin` - The pin number of the counter to reset.
424 ///
425 /// # Errors
426 ///
427 /// Returns an error if the thread is not found or if the command send fails.
428 fn reset_digital_counter(&self, thread_id: u32, pin: u32) -> Result<()>;
429
430 /// Send a custom request.
431 ///
432 /// # Parameters
433 ///
434 /// * `thread_id` - The ID of the thread to send the command to.
435 /// * `request_type` - The request type.
436 /// * `param1` - The first parameter.
437 /// * `param2` - The second parameter.
438 /// * `param3` - The third parameter.
439 /// * `param4` - The fourth parameter.
440 ///
441 /// # Errors
442 ///
443 /// Returns an error if the thread is not found or if the command send fails.
444 fn send_custom_request(
445 &self,
446 thread_id: u32,
447 request_type: u8,
448 param1: u8,
449 param2: u8,
450 param3: u8,
451 param4: u8,
452 ) -> Result<()>;
453
454 /// Configure a pin function.
455 ///
456 /// # Parameters
457 ///
458 /// * `thread_id` - The ID of the thread to send the command to.
459 /// * `pin` - The pin number to configure.
460 /// * `pin_function` - The function to set for the pin.
461 ///
462 /// # Errors
463 ///
464 /// Returns an error if the thread is not found or if the command send fails.
465 fn set_pin_function(
466 &self,
467 thread_id: u32,
468 pin: u32,
469 pin_function: pokeys_lib::PinFunction,
470 ) -> Result<()>;
471}