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}