1use 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
43pub trait ThreadController {
53 fn discover_usb_devices(&mut self) -> Result<Vec<u32>>;
63
64 fn discover_network_devices(&mut self, timeout_ms: u32) -> Result<Vec<NetworkDeviceSummary>>;
78
79 fn start_usb_device_thread(&mut self, device_index: u32) -> Result<u32>;
93
94 fn start_network_device_thread(&mut self, device_summary: NetworkDeviceSummary) -> Result<u32>;
108
109 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 fn send_command(&self, thread_id: u32, command: DeviceCommand) -> Result<()>;
142
143 fn get_status(&self, thread_id: u32) -> Result<ThreadStatus>;
157
158 fn get_state(&self, thread_id: u32) -> Result<DeviceState>;
172
173 fn get_shared_state(&self, thread_id: u32) -> Result<Arc<SharedDeviceState>>;
187
188 fn create_observer(&self, thread_id: u32) -> Result<StateObserver>;
202
203 fn stop_all(&mut self) -> Result<()>;
209
210 fn set_thread_log_level(&mut self, thread_id: u32, level: LevelFilter) -> Result<()>;
221
222 fn set_global_log_level(&mut self, level: LevelFilter) -> Result<()>;
232
233 fn start_model_monitoring(
247 &mut self,
248 thread_id: u32,
249 model_dir: Option<std::path::PathBuf>,
250 ) -> Result<()>;
251
252 fn stop_model_monitoring(&mut self, thread_id: u32) -> Result<()>;
262
263 fn update_device_model(
274 &self,
275 thread_id: u32,
276 model: pokeys_lib::models::DeviceModel,
277 ) -> Result<()>;
278
279 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 fn list_active_threads(&self) -> Result<Vec<u32>>;
303
304 fn stop_thread(&mut self, thread_id: u32) -> Result<()>;
314}
315
316pub struct ThreadControllerImpl {
325 threads: HashMap<u32, Box<dyn DeviceWorker>>,
327 next_thread_id: u32,
329 default_refresh_interval: u64,
331 logger: Option<Arc<dyn Logger>>,
333 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 pub fn new() -> Self {
350 Self {
351 threads: HashMap::new(),
352 next_thread_id: 1,
353 default_refresh_interval: 100, logger: None,
355 model_monitors: HashMap::new(),
356 }
357 }
358
359 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 pub fn set_default_refresh_interval(&mut self, interval_ms: u64) {
384 self.default_refresh_interval = interval_ms;
385 }
386
387 pub fn set_logger(&mut self, logger: Arc<dyn Logger>) {
393 self.logger = Some(logger);
394 }
395
396 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 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 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 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 let thread_id = self.next_thread_id();
500
501 let mut builder =
503 ThreadWorkerBuilder::new(thread_id).refresh_interval(self.default_refresh_interval);
504
505 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 self.threads.insert(thread_id, worker);
515
516 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 }
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 let thread_id = self.next_thread_id();
539
540 let mut builder =
542 ThreadWorkerBuilder::new(thread_id).refresh_interval(self.default_refresh_interval);
543
544 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 self.threads.insert(thread_id, worker);
554
555 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 }
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 let thread_id = self.next_thread_id();
580
581 let mut builder =
583 ThreadWorkerBuilder::new(thread_id).refresh_interval(self.default_refresh_interval);
584
585 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 self.threads.insert(thread_id, worker);
595
596 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 }
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 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 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 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 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 let thread = self.get_thread(thread_id)?;
726
727 let state = thread.shared_state().read(|state| state.clone());
729
730 match state.device_data.device_type_id {
732 10 => {} 30 => {} 31 => {} 11 => {} _ => return Err(ThreadError::UnsupportedDevice),
737 };
738
739 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 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 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 }
761
762 let (tx, rx) = crossbeam_channel::unbounded::<DeviceCommand>();
764
765 let tx_clone = tx.clone();
767 let callback = move |_: String, model: pokeys_lib::models::DeviceModel| {
768 let _ = tx_clone.send(DeviceCommand::UpdateModel(model.clone()));
770 };
771
772 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 self.model_monitors.insert(thread_id, monitor);
780
781 let thread_sender = self.get_thread(thread_id)?.command_sender().clone();
783 std::thread::spawn(move || {
784 while let Ok(command) = rx.recv() {
785 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 if !self.threads.contains_key(&thread_id) {
801 return Err(ThreadError::ThreadNotFound(thread_id));
802 }
803
804 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 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 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 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 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 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 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 match capability {
1042 PinCapability::DigitalOutput => Ok(pin <= 55), PinCapability::DigitalInput => Ok(pin <= 55),
1044 PinCapability::AnalogInput => Ok(pin <= 7), PinCapability::PwmOutput => Ok((17..=22).contains(&pin)), _ => Ok(false), }
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 let device_name = shared_state.read(|state| {
1055 let name_bytes = &state.device_data.device_name;
1056 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, _ => {
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 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); }
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 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}