pokeys_thread/
controller.rs

1//! # Thread Controller
2//!
3//! The thread controller is the main interface for managing device threads.
4//! It provides methods for discovering devices, starting threads, and
5//! performing 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()
14//!     .default_refresh_interval(100)
15//!     .build();
16//!
17//! // Discover USB devices
18//! let devices = controller.discover_usb_devices().unwrap();
19//!
20//! if !devices.is_empty() {
21//!     // Start a thread for the first device
22//!     let thread_id = controller.start_usb_device_thread(devices[0]).unwrap();
23//!
24//!     // Perform device operations
25//!     controller.set_digital_output(thread_id, 1, true).unwrap();
26//! }
27//! ```
28
29use crate::builder::ThreadWorkerBuilder;
30use crate::commands::DeviceCommand;
31use crate::error::{Result, ThreadError};
32use crate::logging::{Logger, ThreadLogger};
33use crate::observer::StateObserver;
34use crate::operations::DeviceOperations;
35use crate::state::{DeviceState, SharedDeviceState, ThreadStatus};
36use crate::worker::DeviceWorker;
37use log::{debug, error, info, LevelFilter};
38use pokeys_lib::{enumerate_network_devices, enumerate_usb_devices, NetworkDeviceSummary};
39use pokeys_lib::{PinCapability, ServoConfig, USPIBridgeConfig};
40use std::collections::HashMap;
41use std::sync::Arc;
42
43/// Thread controller for managing device threads.
44///
45/// The thread controller is responsible for:
46/// - Discovering devices
47/// - Starting and stopping device threads
48/// - Sending commands to device threads
49/// - Retrieving device state
50/// - Creating state observers
51/// - Performing device operations
52pub trait ThreadController {
53    /// Discover USB devices connected to the system.
54    ///
55    /// # Returns
56    ///
57    /// A vector of device indices that can be used to connect to the devices.
58    ///
59    /// # Errors
60    ///
61    /// Returns an error if the device enumeration fails.
62    fn discover_usb_devices(&mut self) -> Result<Vec<u32>>;
63
64    /// Discover network devices on the local network.
65    ///
66    /// # Parameters
67    ///
68    /// * `timeout_ms` - The timeout in milliseconds for the discovery process.
69    ///
70    /// # Returns
71    ///
72    /// A vector of network device summaries that can be used to connect to the devices.
73    ///
74    /// # Errors
75    ///
76    /// Returns an error if the device enumeration fails.
77    fn discover_network_devices(&mut self, timeout_ms: u32) -> Result<Vec<NetworkDeviceSummary>>;
78
79    /// Start a thread for a USB device.
80    ///
81    /// # Parameters
82    ///
83    /// * `device_index` - The index of the USB device to connect to.
84    ///
85    /// # Returns
86    ///
87    /// The thread ID of the newly created thread.
88    ///
89    /// # Errors
90    ///
91    /// Returns an error if the thread creation fails or if the device connection fails.
92    fn start_usb_device_thread(&mut self, device_index: u32) -> Result<u32>;
93
94    /// Start a thread for a network device.
95    ///
96    /// # Parameters
97    ///
98    /// * `device_summary` - The network device summary to connect to.
99    ///
100    /// # Returns
101    ///
102    /// The thread ID of the newly created thread.
103    ///
104    /// # Errors
105    ///
106    /// Returns an error if the thread creation fails or if the device connection fails.
107    fn start_network_device_thread(&mut self, device_summary: NetworkDeviceSummary) -> Result<u32>;
108
109    /// Start a thread for a device with a specific serial number.
110    ///
111    /// # Parameters
112    ///
113    /// * `serial_number` - The serial number of the device to connect to.
114    /// * `check_network` - Whether to check for network devices.
115    /// * `timeout_ms` - The timeout in milliseconds for network device discovery.
116    ///
117    /// # Returns
118    ///
119    /// The thread ID of the newly created thread.
120    ///
121    /// # Errors
122    ///
123    /// Returns an error if the thread creation fails or if the device connection fails.
124    fn start_device_thread_by_serial(
125        &mut self,
126        serial_number: u32,
127        check_network: bool,
128        timeout_ms: u32,
129    ) -> Result<u32>;
130
131    /// Send a command to a device thread.
132    ///
133    /// # Parameters
134    ///
135    /// * `thread_id` - The ID of the thread to send the command to.
136    /// * `command` - The command to send.
137    ///
138    /// # Errors
139    ///
140    /// Returns an error if the thread is not found or if the command send fails.
141    fn send_command(&self, thread_id: u32, command: DeviceCommand) -> Result<()>;
142
143    /// Get the status of a device thread.
144    ///
145    /// # Parameters
146    ///
147    /// * `thread_id` - The ID of the thread to get the status of.
148    ///
149    /// # Returns
150    ///
151    /// The status of the thread.
152    ///
153    /// # Errors
154    ///
155    /// Returns an error if the thread is not found.
156    fn get_status(&self, thread_id: u32) -> Result<ThreadStatus>;
157
158    /// Get the state of a device thread.
159    ///
160    /// # Parameters
161    ///
162    /// * `thread_id` - The ID of the thread to get the state of.
163    ///
164    /// # Returns
165    ///
166    /// The state of the device.
167    ///
168    /// # Errors
169    ///
170    /// Returns an error if the thread is not found.
171    fn get_state(&self, thread_id: u32) -> Result<DeviceState>;
172
173    /// Get the shared state of a device thread.
174    ///
175    /// # Parameters
176    ///
177    /// * `thread_id` - The ID of the thread to get the shared state of.
178    ///
179    /// # Returns
180    ///
181    /// The shared state of the device.
182    ///
183    /// # Errors
184    ///
185    /// Returns an error if the thread is not found.
186    fn get_shared_state(&self, thread_id: u32) -> Result<Arc<SharedDeviceState>>;
187
188    /// Create a state observer for a device thread.
189    ///
190    /// # Parameters
191    ///
192    /// * `thread_id` - The ID of the thread to create an observer for.
193    ///
194    /// # Returns
195    ///
196    /// A state observer for the thread.
197    ///
198    /// # Errors
199    ///
200    /// Returns an error if the thread is not found.
201    fn create_observer(&self, thread_id: u32) -> Result<StateObserver>;
202
203    /// Stop all device threads.
204    ///
205    /// # Errors
206    ///
207    /// Returns an error if any thread fails to stop.
208    fn stop_all(&mut self) -> Result<()>;
209
210    /// Set the log level for a specific thread.
211    ///
212    /// # Parameters
213    ///
214    /// * `thread_id` - The ID of the thread to set the log level for.
215    /// * `level` - The log level to set.
216    ///
217    /// # Errors
218    ///
219    /// Returns an error if the thread is not found or if the log level set fails.
220    fn set_thread_log_level(&mut self, thread_id: u32, level: LevelFilter) -> Result<()>;
221
222    /// Set the log level for all threads and the controller.
223    ///
224    /// # Parameters
225    ///
226    /// * `level` - The log level to set.
227    ///
228    /// # Errors
229    ///
230    /// Returns an error if any thread fails to set the log level.
231    fn set_global_log_level(&mut self, level: LevelFilter) -> Result<()>;
232
233    /// Start model monitoring for a device thread.
234    ///
235    /// This method starts monitoring the device model file for changes and
236    /// updates the device model when changes are detected.
237    ///
238    /// # Parameters
239    ///
240    /// * `thread_id` - The ID of the thread to monitor.
241    /// * `model_dir` - Optional custom directory for model files.
242    ///
243    /// # Errors
244    ///
245    /// Returns an error if the thread is not found or if monitoring fails to start.
246    fn start_model_monitoring(
247        &mut self,
248        thread_id: u32,
249        model_dir: Option<std::path::PathBuf>,
250    ) -> Result<()>;
251
252    /// Stop model monitoring for a device thread.
253    ///
254    /// # Parameters
255    ///
256    /// * `thread_id` - The ID of the thread to stop monitoring.
257    ///
258    /// # Errors
259    ///
260    /// Returns an error if the thread is not found or if monitoring fails to stop.
261    fn stop_model_monitoring(&mut self, thread_id: u32) -> Result<()>;
262
263    /// Update the device model for a thread.
264    ///
265    /// # Parameters
266    ///
267    /// * `thread_id` - The ID of the thread to update.
268    /// * `model` - The new device model.
269    ///
270    /// # Errors
271    ///
272    /// Returns an error if the thread is not found or if the model update fails.
273    fn update_device_model(
274        &self,
275        thread_id: u32,
276        model: pokeys_lib::models::DeviceModel,
277    ) -> Result<()>;
278
279    /// Check if a thread is currently running.
280    ///
281    /// # Parameters
282    ///
283    /// * `thread_id` - The ID of the thread to check.
284    ///
285    /// # Returns
286    ///
287    /// True if the thread is running, false otherwise.
288    ///
289    /// # Errors
290    ///
291    /// Returns an error if the thread is not found.
292    fn is_thread_running(&self, thread_id: u32) -> Result<bool> {
293        let status = self.get_status(thread_id)?;
294        Ok(status == ThreadStatus::Running)
295    }
296
297    /// Get a list of all active thread IDs.
298    ///
299    /// # Returns
300    ///
301    /// A vector of thread IDs that are currently active.
302    fn list_active_threads(&self) -> Result<Vec<u32>>;
303
304    /// Stop a specific thread.
305    ///
306    /// # Parameters
307    ///
308    /// * `thread_id` - The ID of the thread to stop.
309    ///
310    /// # Errors
311    ///
312    /// Returns an error if the thread is not found or fails to stop.
313    fn stop_thread(&mut self, thread_id: u32) -> Result<()>;
314}
315
316/// Thread controller implementation.
317///
318/// This is the main implementation of the `ThreadController` trait.
319/// It manages device threads and provides methods for device operations.
320/// Thread controller implementation.
321///
322/// This is the main implementation of the `ThreadController` trait.
323/// It manages device threads and provides methods for device operations.
324pub struct ThreadControllerImpl {
325    /// Device threads
326    threads: HashMap<u32, Box<dyn DeviceWorker>>,
327    /// Next thread ID
328    next_thread_id: u32,
329    /// Default refresh interval in milliseconds
330    default_refresh_interval: u64,
331    /// Logger
332    logger: Option<Arc<dyn Logger>>,
333    /// Model monitors
334    model_monitors: HashMap<u32, pokeys_lib::models::ModelMonitor>,
335}
336
337impl Default for ThreadControllerImpl {
338    fn default() -> Self {
339        Self::new()
340    }
341}
342
343impl ThreadControllerImpl {
344    /// Create a new thread controller.
345    ///
346    /// # Returns
347    ///
348    /// A new thread controller with default settings.
349    pub fn new() -> Self {
350        Self {
351            threads: HashMap::new(),
352            next_thread_id: 1,
353            default_refresh_interval: 100, // Default refresh interval: 100ms
354            logger: None,
355            model_monitors: HashMap::new(),
356        }
357    }
358
359    /// Create a new thread controller with a logger.
360    ///
361    /// # Parameters
362    ///
363    /// * `logger` - The logger to use.
364    ///
365    /// # Returns
366    ///
367    /// A new thread controller with the specified logger.
368    pub fn with_logger(logger: Arc<dyn Logger>) -> Self {
369        Self {
370            threads: HashMap::new(),
371            next_thread_id: 1,
372            default_refresh_interval: 100,
373            logger: Some(logger),
374            model_monitors: HashMap::new(),
375        }
376    }
377
378    /// Set the default refresh interval.
379    ///
380    /// # Parameters
381    ///
382    /// * `interval_ms` - The refresh interval in milliseconds.
383    pub fn set_default_refresh_interval(&mut self, interval_ms: u64) {
384        self.default_refresh_interval = interval_ms;
385    }
386
387    /// Set the logger.
388    ///
389    /// # Parameters
390    ///
391    /// * `logger` - The logger to use.
392    pub fn set_logger(&mut self, logger: Arc<dyn Logger>) {
393        self.logger = Some(logger);
394    }
395
396    /// Get the next thread ID.
397    ///
398    /// # Returns
399    ///
400    /// The next available thread ID.
401    fn next_thread_id(&mut self) -> u32 {
402        let id = self.next_thread_id;
403        self.next_thread_id += 1;
404        id
405    }
406
407    /// Get a device thread by ID.
408    ///
409    /// # Parameters
410    ///
411    /// * `thread_id` - The ID of the thread to get.
412    ///
413    /// # Returns
414    ///
415    /// A reference to the thread.
416    ///
417    /// # Errors
418    ///
419    /// Returns an error if the thread is not found.
420    fn get_thread(&self, thread_id: u32) -> Result<&dyn DeviceWorker> {
421        self.threads
422            .get(&thread_id)
423            .ok_or(ThreadError::ThreadNotFound(thread_id))
424            .map(|boxed| boxed.as_ref())
425    }
426
427    /// Get a mutable device thread by ID.
428    ///
429    /// # Parameters
430    ///
431    /// * `thread_id` - The ID of the thread to get.
432    ///
433    /// # Returns
434    ///
435    /// A mutable reference to the thread.
436    ///
437    /// # Errors
438    ///
439    /// Returns an error if the thread is not found.
440    fn get_thread_mut(&mut self, thread_id: u32) -> Result<&mut Box<dyn DeviceWorker>> {
441        self.threads
442            .get_mut(&thread_id)
443            .ok_or(ThreadError::ThreadNotFound(thread_id))
444    }
445
446    /// Log a message.
447    ///
448    /// # Parameters
449    ///
450    /// * `level` - The log level.
451    /// * `message` - The message to log.
452    fn log(&self, level: log::Level, message: &str) {
453        if let Some(logger) = &self.logger {
454            logger.log(level, "ThreadController", message);
455        } else {
456            match level {
457                log::Level::Error => error!("{message}"),
458                log::Level::Warn => log::warn!("{message}"),
459                log::Level::Info => info!("{message}"),
460                log::Level::Debug => debug!("{message}"),
461                log::Level::Trace => log::trace!("{message}"),
462            }
463        }
464    }
465}
466
467impl ThreadController for ThreadControllerImpl {
468    fn discover_usb_devices(&mut self) -> Result<Vec<u32>> {
469        self.log(log::Level::Info, "Discovering USB devices");
470
471        let device_count = enumerate_usb_devices().map_err(ThreadError::DeviceError)?;
472
473        let mut device_indices = Vec::new();
474        for i in 0..device_count {
475            device_indices.push(i as u32);
476        }
477
478        Ok(device_indices)
479    }
480
481    fn discover_network_devices(&mut self, timeout_ms: u32) -> Result<Vec<NetworkDeviceSummary>> {
482        self.log(
483            log::Level::Info,
484            &format!("Discovering network devices with timeout {timeout_ms}ms"),
485        );
486
487        let devices = enumerate_network_devices(timeout_ms).map_err(ThreadError::DeviceError)?;
488
489        Ok(devices)
490    }
491
492    fn start_usb_device_thread(&mut self, device_index: u32) -> Result<u32> {
493        self.log(
494            log::Level::Info,
495            &format!("Starting USB device thread for device index {device_index}"),
496        );
497
498        // Generate a new thread ID
499        let thread_id = self.next_thread_id();
500
501        // Create a device worker
502        let mut builder =
503            ThreadWorkerBuilder::new(thread_id).refresh_interval(self.default_refresh_interval);
504
505        // Add logger if available
506        if let Some(logger) = &self.logger {
507            let thread_logger = Arc::new(ThreadLogger::new(thread_id, logger.clone()));
508            builder = builder.with_logger(thread_logger);
509        }
510
511        let worker = builder.build_usb_device(device_index)?;
512
513        // Store the worker
514        self.threads.insert(thread_id, worker);
515
516        // Automatically start model monitoring
517        if let Err(e) = self.start_model_monitoring(thread_id, None) {
518            self.log(
519                log::Level::Warn,
520                &format!("Failed to start model monitoring for thread {thread_id}: {e}"),
521            );
522            // Continue even if model monitoring fails
523        }
524
525        Ok(thread_id)
526    }
527
528    fn start_network_device_thread(&mut self, device_summary: NetworkDeviceSummary) -> Result<u32> {
529        self.log(
530            log::Level::Info,
531            &format!(
532                "Starting network device thread for device with serial {}",
533                device_summary.serial_number
534            ),
535        );
536
537        // Generate a new thread ID
538        let thread_id = self.next_thread_id();
539
540        // Create a device worker
541        let mut builder =
542            ThreadWorkerBuilder::new(thread_id).refresh_interval(self.default_refresh_interval);
543
544        // Add logger if available
545        if let Some(logger) = &self.logger {
546            let thread_logger = Arc::new(ThreadLogger::new(thread_id, logger.clone()));
547            builder = builder.with_logger(thread_logger);
548        }
549
550        let worker = builder.build_network_device(device_summary)?;
551
552        // Store the worker
553        self.threads.insert(thread_id, worker);
554
555        // Automatically start model monitoring
556        if let Err(e) = self.start_model_monitoring(thread_id, None) {
557            self.log(
558                log::Level::Warn,
559                &format!("Failed to start model monitoring for thread {thread_id}: {e}"),
560            );
561            // Continue even if model monitoring fails
562        }
563
564        Ok(thread_id)
565    }
566
567    fn start_device_thread_by_serial(
568        &mut self,
569        serial_number: u32,
570        check_network: bool,
571        timeout_ms: u32,
572    ) -> Result<u32> {
573        self.log(
574            log::Level::Info,
575            &format!("Starting device thread for device with serial {serial_number}"),
576        );
577
578        // Generate a new thread ID
579        let thread_id = self.next_thread_id();
580
581        // Create a device worker
582        let mut builder =
583            ThreadWorkerBuilder::new(thread_id).refresh_interval(self.default_refresh_interval);
584
585        // Add logger if available
586        if let Some(logger) = &self.logger {
587            let thread_logger = Arc::new(ThreadLogger::new(thread_id, logger.clone()));
588            builder = builder.with_logger(thread_logger);
589        }
590
591        let worker = builder.build_device_by_serial(serial_number, check_network, timeout_ms)?;
592
593        // Store the worker
594        self.threads.insert(thread_id, worker);
595
596        // Automatically start model monitoring
597        if let Err(e) = self.start_model_monitoring(thread_id, None) {
598            self.log(
599                log::Level::Warn,
600                &format!("Failed to start model monitoring for thread {thread_id}: {e}"),
601            );
602            // Continue even if model monitoring fails
603        }
604
605        Ok(thread_id)
606    }
607
608    fn send_command(&self, thread_id: u32, command: DeviceCommand) -> Result<()> {
609        self.log(
610            log::Level::Debug,
611            &format!("Sending command {command:?} to thread {thread_id}"),
612        );
613
614        let thread = self.get_thread(thread_id)?;
615        thread.send_command(command)
616    }
617
618    fn get_status(&self, thread_id: u32) -> Result<ThreadStatus> {
619        let thread = self.get_thread(thread_id)?;
620        Ok(thread.status())
621    }
622
623    fn get_state(&self, thread_id: u32) -> Result<DeviceState> {
624        let thread = self.get_thread(thread_id)?;
625        let shared_state = thread.shared_state();
626
627        Ok(shared_state.read(|state| state.clone()))
628    }
629
630    fn get_shared_state(&self, thread_id: u32) -> Result<Arc<SharedDeviceState>> {
631        let thread = self.get_thread(thread_id)?;
632        Ok(thread.shared_state())
633    }
634
635    fn create_observer(&self, thread_id: u32) -> Result<StateObserver> {
636        let thread = self.get_thread(thread_id)?;
637        let shared_state = thread.shared_state();
638        Ok(StateObserver::new(thread_id, shared_state))
639    }
640
641    fn stop_all(&mut self) -> Result<()> {
642        self.log(log::Level::Info, "Stopping all device threads");
643
644        let mut errors = Vec::new();
645
646        // Send terminate command to all threads
647        for (thread_id, thread) in &self.threads {
648            if let Err(e) = thread.send_command(DeviceCommand::Terminate) {
649                let error_msg = format!("Failed to terminate thread {thread_id}: {e}");
650                self.log(log::Level::Error, &error_msg);
651                errors.push(e);
652            }
653        }
654
655        // Wait for all threads to finish
656        // In a real implementation, we would join all threads here
657
658        // Clear the threads map
659        self.threads.clear();
660
661        if errors.is_empty() {
662            Ok(())
663        } else {
664            Err(ThreadError::ThreadJoinError)
665        }
666    }
667
668    fn set_thread_log_level(&mut self, thread_id: u32, level: LevelFilter) -> Result<()> {
669        self.log(
670            log::Level::Info,
671            &format!("Setting log level for thread {thread_id} to {level:?}"),
672        );
673
674        let thread = self.get_thread_mut(thread_id)?;
675        thread.set_log_level(level)
676    }
677
678    fn set_global_log_level(&mut self, level: LevelFilter) -> Result<()> {
679        self.log(
680            log::Level::Info,
681            &format!("Setting global log level to {level:?}"),
682        );
683
684        // Set log level for the controller logger
685        if let Some(ref mut logger) = self.logger {
686            let mut_logger: &mut dyn Logger = Arc::get_mut(logger).ok_or_else(|| {
687                ThreadError::LockPoisoned("Failed to get mutable reference to logger".to_string())
688            })?;
689            mut_logger.set_level(level);
690        }
691
692        // Set log level for all threads
693        let mut errors = Vec::new();
694        let thread_ids: Vec<u32> = self.threads.keys().cloned().collect();
695
696        for thread_id in thread_ids {
697            if let Err(e) = self.set_thread_log_level(thread_id, level) {
698                let error_msg = format!("Failed to set log level for thread {thread_id}: {e}");
699                self.log(log::Level::Error, &error_msg);
700                errors.push(e);
701            }
702        }
703
704        if errors.is_empty() {
705            Ok(())
706        } else {
707            Err(ThreadError::OperationFailed(format!(
708                "Failed to set log level for {} threads",
709                errors.len()
710            )))
711        }
712    }
713
714    fn start_model_monitoring(
715        &mut self,
716        thread_id: u32,
717        model_dir: Option<std::path::PathBuf>,
718    ) -> Result<()> {
719        self.log(
720            log::Level::Info,
721            &format!("Starting model monitoring for thread {thread_id}"),
722        );
723
724        // Check if the thread exists
725        let thread = self.get_thread(thread_id)?;
726
727        // Get the device state
728        let state = thread.shared_state().read(|state| state.clone());
729
730        // Get the device model name based on device type
731        match state.device_data.device_type_id {
732            10 => {} // DeviceTypeId::Device56U
733            30 => {} // DeviceTypeId::Device57U
734            31 => {} // DeviceTypeId::Device57E
735            11 => {} // DeviceTypeId::Device56E
736            _ => return Err(ThreadError::UnsupportedDevice),
737        };
738
739        // Create a model monitor
740        let dir = model_dir.unwrap_or_else(|| {
741            let mut path = dirs::home_dir().unwrap_or_else(|| std::path::PathBuf::from("."));
742            path.push(".config/pokeys/models");
743            path
744        });
745
746        // Create the directory if it doesn't exist
747        if !dir.exists() {
748            std::fs::create_dir_all(&dir).map_err(|e| {
749                ThreadError::Other(format!("Failed to create model directory: {}", e))
750            })?;
751        }
752
753        // Copy default models to the user's directory
754        if let Err(e) = pokeys_lib::models::copy_default_models_to_user_dir(Some(&dir)) {
755            self.log(
756                log::Level::Warn,
757                &format!("Failed to copy default models: {}", e),
758            );
759            // Continue even if copying fails
760        }
761
762        // Create a thread-safe command sender
763        let (tx, rx) = crossbeam_channel::unbounded::<DeviceCommand>();
764
765        // Create a callback that sends model updates to the device thread
766        let tx_clone = tx.clone();
767        let callback = move |_: String, model: pokeys_lib::models::DeviceModel| {
768            // Send the model update command through the channel
769            let _ = tx_clone.send(DeviceCommand::UpdateModel(model.clone()));
770        };
771
772        // Create and start the model monitor
773        let mut monitor = pokeys_lib::models::ModelMonitor::new(dir, callback);
774        monitor
775            .start()
776            .map_err(|e| ThreadError::Other(format!("Failed to start model monitoring: {}", e)))?;
777
778        // Store the monitor
779        self.model_monitors.insert(thread_id, monitor);
780
781        // Create a thread to forward commands from the channel to the device thread
782        let thread_sender = self.get_thread(thread_id)?.command_sender().clone();
783        std::thread::spawn(move || {
784            while let Ok(command) = rx.recv() {
785                // Send the command directly to the thread
786                let _ = thread_sender.send(command);
787            }
788        });
789
790        Ok(())
791    }
792
793    fn stop_model_monitoring(&mut self, thread_id: u32) -> Result<()> {
794        self.log(
795            log::Level::Info,
796            &format!("Stopping model monitoring for thread {thread_id}"),
797        );
798
799        // Check if the thread exists
800        if !self.threads.contains_key(&thread_id) {
801            return Err(ThreadError::ThreadNotFound(thread_id));
802        }
803
804        // Stop and remove the monitor
805        if let Some(mut monitor) = self.model_monitors.remove(&thread_id) {
806            monitor.stop().map_err(|e| {
807                ThreadError::Other(format!("Failed to stop model monitoring: {}", e))
808            })?;
809        }
810
811        Ok(())
812    }
813
814    fn update_device_model(
815        &self,
816        thread_id: u32,
817        model: pokeys_lib::models::DeviceModel,
818    ) -> Result<()> {
819        self.log(
820            log::Level::Info,
821            &format!(
822                "Updating device model for thread {thread_id} to {}",
823                model.name
824            ),
825        );
826
827        // Send the model update command to the device thread
828        self.send_command(thread_id, DeviceCommand::UpdateModel(model))
829    }
830
831    fn list_active_threads(&self) -> Result<Vec<u32>> {
832        let thread_ids: Vec<u32> = self.threads.keys().copied().collect();
833        Ok(thread_ids)
834    }
835
836    fn stop_thread(&mut self, thread_id: u32) -> Result<()> {
837        self.log(log::Level::Info, &format!("Stopping thread {thread_id}"));
838
839        if let Some(mut worker) = self.threads.remove(&thread_id) {
840            worker.stop()?;
841            self.log(
842                log::Level::Info,
843                &format!("Thread {thread_id} stopped successfully"),
844            );
845            Ok(())
846        } else {
847            Err(ThreadError::ThreadNotFound(thread_id))
848        }
849    }
850}
851
852impl DeviceOperations for ThreadControllerImpl {
853    fn set_digital_output(&self, thread_id: u32, pin: u32, value: bool) -> Result<()> {
854        self.log(
855            log::Level::Debug,
856            &format!("Setting digital output pin {pin} to {value} on thread {thread_id}"),
857        );
858        self.send_command(thread_id, DeviceCommand::SetDigitalOutput { pin, value })
859    }
860
861    fn get_digital_input(&self, thread_id: u32, pin: u32) -> Result<bool> {
862        self.log(
863            log::Level::Debug,
864            &format!("Getting digital input pin {pin} from thread {thread_id}"),
865        );
866        let shared_state = self.get_shared_state(thread_id)?;
867        shared_state
868            .get_digital_input(pin)
869            .ok_or_else(|| ThreadError::InvalidParameter(format!("Invalid pin: {pin}")))
870    }
871
872    fn set_analog_output(&self, thread_id: u32, pin: u32, value: u32) -> Result<()> {
873        self.log(
874            log::Level::Debug,
875            &format!("Setting analog output pin {pin} to {value} on thread {thread_id}"),
876        );
877        self.send_command(thread_id, DeviceCommand::SetAnalogOutput { pin, value })
878    }
879
880    fn get_analog_input(&self, thread_id: u32, pin: u32) -> Result<u32> {
881        self.log(
882            log::Level::Debug,
883            &format!("Getting analog input pin {pin} from thread {thread_id}"),
884        );
885        let shared_state = self.get_shared_state(thread_id)?;
886        shared_state
887            .get_analog_input(pin)
888            .ok_or_else(|| ThreadError::InvalidParameter(format!("Invalid pin: {pin}")))
889    }
890
891    fn set_pwm_duty_cycle(&self, thread_id: u32, channel: usize, duty: u32) -> Result<()> {
892        self.log(
893            log::Level::Debug,
894            &format!("Setting PWM channel {channel} duty to {duty} on thread {thread_id}"),
895        );
896        self.send_command(thread_id, DeviceCommand::SetPwmDuty { channel, duty })
897    }
898
899    fn set_pwm_duty_cycle_percent(
900        &self,
901        thread_id: u32,
902        channel: usize,
903        duty_percent: f32,
904    ) -> Result<()> {
905        self.log(
906            log::Level::Debug,
907            &format!("Setting PWM channel {channel} duty to {duty_percent}% on thread {thread_id}"),
908        );
909
910        // Convert percentage to raw duty cycle value (0-4095 for 12-bit)
911        let duty = ((duty_percent / 100.0) * 4095.0) as u32;
912        self.set_pwm_duty_cycle(thread_id, channel, duty)
913    }
914
915    fn configure_servo(&self, thread_id: u32, pin: u8, servo_config: ServoConfig) -> Result<()> {
916        self.log(
917            log::Level::Debug,
918            &format!("Configuring servo on pin {pin} for thread {thread_id}"),
919        );
920        self.send_command(
921            thread_id,
922            DeviceCommand::ConfigureServo {
923                pin,
924                config: servo_config,
925            },
926        )
927    }
928
929    fn set_servo_angle(&self, thread_id: u32, pin: u8, angle: f32) -> Result<()> {
930        self.log(
931            log::Level::Debug,
932            &format!("Setting servo angle on pin {pin} to {angle}° for thread {thread_id}"),
933        );
934        self.send_command(thread_id, DeviceCommand::SetServoAngle { pin, angle })
935    }
936
937    fn set_servo_speed(&self, thread_id: u32, pin: u8, speed: f32) -> Result<()> {
938        self.log(
939            log::Level::Debug,
940            &format!("Setting servo speed on pin {pin} to {speed} for thread {thread_id}"),
941        );
942        self.send_command(thread_id, DeviceCommand::SetServoSpeed { pin, speed })
943    }
944
945    fn stop_servo(&self, thread_id: u32, pin: u8) -> Result<()> {
946        self.log(
947            log::Level::Debug,
948            &format!("Stopping servo on pin {pin} for thread {thread_id}"),
949        );
950        self.send_command(thread_id, DeviceCommand::StopServo { pin })
951    }
952
953    fn i2c_write(&self, thread_id: u32, address: u8, data: Vec<u8>) -> Result<()> {
954        self.log(
955            log::Level::Debug,
956            &format!(
957                "I2C write to address 0x{:02X} on thread {}",
958                address, thread_id
959            ),
960        );
961        self.send_command(thread_id, DeviceCommand::I2cWrite { address, data })
962    }
963
964    fn i2c_read(&self, thread_id: u32, address: u8, length: u8) -> Result<Vec<u8>> {
965        self.log(
966            log::Level::Debug,
967            &format!(
968                "I2C read from address 0x{:02X} on thread {}",
969                address, thread_id
970            ),
971        );
972        // For now, return empty vector - full implementation would need response channel
973        self.send_command(thread_id, DeviceCommand::I2cRead { address, length })?;
974        Ok(Vec::new())
975    }
976
977    fn i2c_write_read(
978        &self,
979        thread_id: u32,
980        address: u8,
981        write_data: Vec<u8>,
982        read_length: u8,
983    ) -> Result<Vec<u8>> {
984        self.log(
985            log::Level::Debug,
986            &format!(
987                "I2C write-read to address 0x{:02X} on thread {}",
988                address, thread_id
989            ),
990        );
991        // For now, return empty vector - full implementation would need response channel
992        self.send_command(
993            thread_id,
994            DeviceCommand::I2cWriteRead {
995                address,
996                write_data,
997                read_length,
998            },
999        )?;
1000        Ok(Vec::new())
1001    }
1002
1003    fn i2c_scan(&self, thread_id: u32) -> Result<Vec<u8>> {
1004        self.log(
1005            log::Level::Debug,
1006            &format!("I2C scan on thread {}", thread_id),
1007        );
1008        // For now, return empty vector - full implementation would need response channel
1009        self.send_command(thread_id, DeviceCommand::I2cScan)?;
1010        Ok(Vec::new())
1011    }
1012
1013    fn configure_uspibridge(&self, thread_id: u32, config: USPIBridgeConfig) -> Result<()> {
1014        self.log(
1015            log::Level::Debug,
1016            &format!("Configuring uSPIBridge on thread {}", thread_id),
1017        );
1018        self.send_command(thread_id, DeviceCommand::ConfigureUSPIBridge { config })
1019    }
1020
1021    fn uspibridge_command(&self, thread_id: u32, command: Vec<u8>) -> Result<Vec<u8>> {
1022        self.log(
1023            log::Level::Debug,
1024            &format!("Sending uSPIBridge command on thread {}", thread_id),
1025        );
1026        // For now, return empty vector - full implementation would need response channel
1027        self.send_command(thread_id, DeviceCommand::USPIBridgeCommand { command })?;
1028        Ok(Vec::new())
1029    }
1030
1031    fn check_pin_capability(
1032        &self,
1033        thread_id: u32,
1034        pin: u8,
1035        capability: PinCapability,
1036    ) -> Result<bool> {
1037        let _shared_state = self.get_shared_state(thread_id)?;
1038
1039        // For now, return basic capability check based on common PoKeys device capabilities
1040        // Full implementation would use device model database
1041        match capability {
1042            PinCapability::DigitalOutput => Ok(pin <= 55), // Most pins support digital output
1043            PinCapability::DigitalInput => Ok(pin <= 55),
1044            PinCapability::AnalogInput => Ok(pin <= 7), // Typically pins 0-7 for analog
1045            PinCapability::PwmOutput => Ok((17..=22).contains(&pin)), // PWM pins 17-22
1046            _ => Ok(false),                             // Conservative default
1047        }
1048    }
1049
1050    fn get_device_model(&self, thread_id: u32) -> Result<Option<String>> {
1051        let shared_state = self.get_shared_state(thread_id)?;
1052
1053        // Try to get device name from device_data.device_name field (byte array)
1054        let device_name = shared_state.read(|state| {
1055            let name_bytes = &state.device_data.device_name;
1056            // Convert byte array to string, stopping at first null byte
1057            let end = name_bytes
1058                .iter()
1059                .position(|&b| b == 0)
1060                .unwrap_or(name_bytes.len());
1061            String::from_utf8_lossy(&name_bytes[..end]).to_string()
1062        });
1063
1064        if device_name.is_empty() {
1065            Ok(None)
1066        } else {
1067            Ok(Some(device_name))
1068        }
1069    }
1070
1071    fn validate_pin_operation(&self, thread_id: u32, pin: u8, operation: &str) -> Result<()> {
1072        let capability = match operation {
1073            "digital_output" => PinCapability::DigitalOutput,
1074            "digital_input" => PinCapability::DigitalInput,
1075            "analog_input" => PinCapability::AnalogInput,
1076            "pwm" => PinCapability::PwmOutput,
1077            "servo" => PinCapability::PwmOutput, // Servos use PWM pins
1078            _ => {
1079                return Err(ThreadError::validation_error(
1080                    "Unknown operation type",
1081                    operation,
1082                    Some("Use: digital_output, digital_input, analog_input, pwm, or servo"),
1083                ))
1084            }
1085        };
1086
1087        if !self.check_pin_capability(thread_id, pin, capability)? {
1088            return Err(ThreadError::pin_capability_error(
1089                pin,
1090                operation,
1091                Some(format!(
1092                    "Check device model for supported pins for {}",
1093                    operation
1094                )),
1095            ));
1096        }
1097
1098        Ok(())
1099    }
1100
1101    fn set_digital_outputs_bulk(&self, thread_id: u32, pin_states: Vec<(u32, bool)>) -> Result<()> {
1102        self.log(
1103            log::Level::Debug,
1104            &format!(
1105                "Bulk setting {} digital outputs on thread {}",
1106                pin_states.len(),
1107                thread_id
1108            ),
1109        );
1110        self.send_command(
1111            thread_id,
1112            DeviceCommand::SetDigitalOutputsBulk { pin_states },
1113        )
1114    }
1115
1116    fn set_pwm_duties_bulk(&self, thread_id: u32, channel_duties: Vec<(usize, u32)>) -> Result<()> {
1117        self.log(
1118            log::Level::Debug,
1119            &format!(
1120                "Bulk setting {} PWM duties on thread {}",
1121                channel_duties.len(),
1122                thread_id
1123            ),
1124        );
1125        self.send_command(
1126            thread_id,
1127            DeviceCommand::SetPwmDutiesBulk { channel_duties },
1128        )
1129    }
1130
1131    fn read_analog_inputs_bulk(&self, thread_id: u32, pins: Vec<u32>) -> Result<Vec<u32>> {
1132        self.log(
1133            log::Level::Debug,
1134            &format!(
1135                "Bulk reading {} analog inputs on thread {}",
1136                pins.len(),
1137                thread_id
1138            ),
1139        );
1140
1141        // For now, read individual pins and collect results
1142        let shared_state = self.get_shared_state(thread_id)?;
1143        let mut results = Vec::new();
1144
1145        for pin in pins {
1146            if let Some(value) = shared_state.get_analog_input(pin) {
1147                results.push(value);
1148            } else {
1149                results.push(0); // Default value for invalid pins
1150            }
1151        }
1152
1153        Ok(results)
1154    }
1155
1156    fn get_encoder_value(&self, thread_id: u32, encoder_index: u32) -> Result<i32> {
1157        self.log(
1158            log::Level::Debug,
1159            &format!("Getting encoder {encoder_index} value from thread {thread_id}"),
1160        );
1161        let shared_state = self.get_shared_state(thread_id)?;
1162        shared_state
1163            .get_encoder_value(encoder_index)
1164            .ok_or_else(|| {
1165                ThreadError::InvalidParameter(format!("Invalid encoder index: {encoder_index}"))
1166            })
1167    }
1168
1169    fn configure_encoder(
1170        &self,
1171        thread_id: u32,
1172        encoder_index: u32,
1173        pin_a: u32,
1174        pin_b: u32,
1175        enabled: bool,
1176        sampling_4x: bool,
1177    ) -> Result<()> {
1178        self.log(
1179            log::Level::Debug,
1180            &format!(
1181                "Configuring encoder {encoder_index} on pins {pin_a} and {pin_b} (enabled: {enabled}, 4x: {sampling_4x}) on thread {thread_id}"
1182            ),
1183        );
1184
1185        self.send_command(
1186            thread_id,
1187            DeviceCommand::ConfigureEncoder {
1188                encoder_index,
1189                pin_a,
1190                pin_b,
1191                enabled,
1192                sampling_4x,
1193            },
1194        )
1195    }
1196
1197    fn reset_digital_counter(&self, thread_id: u32, pin: u32) -> Result<()> {
1198        self.log(
1199            log::Level::Debug,
1200            &format!("Resetting digital counter for pin {pin} on thread {thread_id}"),
1201        );
1202        self.send_command(thread_id, DeviceCommand::ResetDigitalCounter { pin })
1203    }
1204
1205    fn send_custom_request(
1206        &self,
1207        thread_id: u32,
1208        request_type: u8,
1209        param1: u8,
1210        param2: u8,
1211        param3: u8,
1212        param4: u8,
1213    ) -> Result<()> {
1214        self.log(
1215            log::Level::Debug,
1216            &format!(
1217                "Sending custom request: {request_type:02X} {param1:02X} {param2:02X} {param3:02X} {param4:02X} to thread {thread_id}"
1218            ),
1219        );
1220
1221        self.send_command(
1222            thread_id,
1223            DeviceCommand::Custom {
1224                request_type,
1225                param1,
1226                param2,
1227                param3,
1228                param4,
1229            },
1230        )
1231    }
1232
1233    fn set_pin_function(
1234        &self,
1235        thread_id: u32,
1236        pin: u32,
1237        pin_function: pokeys_lib::PinFunction,
1238    ) -> Result<()> {
1239        self.log(
1240            log::Level::Debug,
1241            &format!(
1242                "Setting pin {pin} function to {:?} on thread {thread_id}",
1243                pin_function
1244            ),
1245        );
1246        self.send_command(
1247            thread_id,
1248            DeviceCommand::SetPinFunction { pin, pin_function },
1249        )
1250    }
1251}
1252
1253impl Drop for ThreadControllerImpl {
1254    fn drop(&mut self) {
1255        // Try to stop all threads when the controller is dropped
1256        if let Err(e) = self.stop_all() {
1257            self.log(
1258                log::Level::Error,
1259                &format!("Failed to stop all threads during controller drop: {e}"),
1260            );
1261        }
1262    }
1263}