1use std::collections::HashMap;
17use std::sync::Arc;
18use std::time::SystemTime;
19
20use std::any::Any;
21
22#[derive(Debug, Clone)]
24pub struct DeviceState {
25 pub connected: bool,
26 pub enabled: bool,
27 pub auto_connect: bool,
28}
29
30impl Default for DeviceState {
31 fn default() -> Self {
32 Self {
33 connected: true,
34 enabled: true,
35 auto_connect: true,
36 }
37 }
38}
39
40use crate::error::{AsynError, AsynResult, AsynStatus};
41use crate::exception::{AsynException, ExceptionEvent, ExceptionManager};
42use crate::interpose::{EomReason, OctetInterpose, OctetInterposeStack};
43use crate::interrupt::{InterruptManager, InterruptValue};
44use crate::param::{EnumEntry, InterruptReason, ParamList, ParamType};
45use crate::trace::TraceManager;
46use crate::user::AsynUser;
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
52pub enum QueuePriority {
53 Low = 0,
54 #[default]
55 Medium = 1,
56 High = 2,
57 Connect = 3,
59}
60
61#[derive(Debug, Clone, Copy)]
63pub struct PortFlags {
64 pub multi_device: bool,
66 pub can_block: bool,
75 pub destructible: bool,
77}
78
79impl Default for PortFlags {
80 fn default() -> Self {
81 Self {
89 multi_device: false,
90 can_block: false,
91 destructible: false,
92 }
93 }
94}
95
96pub struct PortDriverBase {
108 pub port_name: String,
109 pub max_addr: usize,
110 pub flags: PortFlags,
111 pub params: ParamList,
112 pub interrupts: InterruptManager,
113 pub connected: bool,
114 pub enabled: bool,
115 pub auto_connect: bool,
116 pub defunct: bool,
122 pub exception_sink: Option<Arc<ExceptionManager>>,
124 pub options: HashMap<String, String>,
125 pub input_eos: Vec<u8>,
127 pub output_eos: Vec<u8>,
129 pub interpose_octet: OctetInterposeStack,
130 pub trace: Option<Arc<TraceManager>>,
131 pub device_states: HashMap<i32, DeviceState>,
133 pub timestamp_source: Option<Arc<dyn Fn() -> SystemTime + Send + Sync>>,
135}
136
137impl PortDriverBase {
138 pub fn new(port_name: &str, max_addr: usize, flags: PortFlags) -> Self {
139 Self {
140 port_name: port_name.to_string(),
141 max_addr: max_addr.max(1),
142 flags,
143 params: ParamList::new(max_addr, flags.multi_device),
144 interrupts: InterruptManager::new(256),
145 connected: true,
146 enabled: true,
147 auto_connect: true,
148 defunct: false,
149 exception_sink: None,
150 options: HashMap::new(),
151 input_eos: Vec::new(),
152 output_eos: Vec::new(),
153 interpose_octet: OctetInterposeStack::new(),
154 trace: None,
155 device_states: HashMap::new(),
156 timestamp_source: None,
157 }
158 }
159
160 pub fn announce_exception(&self, exception: AsynException, addr: i32) {
162 if let Some(ref sink) = self.exception_sink {
163 sink.announce(&ExceptionEvent {
164 port_name: self.port_name.clone(),
165 exception,
166 addr,
167 });
168 }
169 }
170
171 pub fn is_connected(&self) -> bool {
173 self.connected
174 }
175
176 pub fn set_connected(&mut self, connected: bool) -> bool {
190 if self.connected == connected {
191 return false;
192 }
193 self.connected = connected;
194 self.announce_exception(AsynException::Connect, -1);
195 true
196 }
197
198 pub fn set_addr_connected(&mut self, addr: i32, connected: bool) -> bool {
201 let was = self.device_state(addr).connected;
202 if was == connected {
203 return false;
204 }
205 self.device_state(addr).connected = connected;
206 self.announce_exception(AsynException::Connect, addr);
207 true
208 }
209
210 pub fn is_enabled(&self) -> bool {
212 self.enabled
213 }
214
215 pub fn is_auto_connect(&self) -> bool {
217 self.auto_connect
218 }
219
220 pub fn set_auto_connect(&mut self, yes: bool) {
229 self.auto_connect = yes;
230 self.announce_exception(AsynException::AutoConnect, -1);
231 }
232
233 pub fn set_auto_connect_addr(&mut self, addr: i32, yes: bool) {
238 self.device_state(addr).auto_connect = yes;
239 self.announce_exception(AsynException::AutoConnect, addr);
240 }
241
242 pub fn is_defunct(&self) -> bool {
246 self.defunct
247 }
248
249 pub fn check_ready(&self) -> AsynResult<()> {
253 if self.defunct {
258 return Err(AsynError::Status {
259 status: AsynStatus::Disabled,
260 message: format!("port {} has been shut down (defunct)", self.port_name),
261 });
262 }
263 if !self.enabled {
264 return Err(AsynError::Status {
265 status: AsynStatus::Disabled,
266 message: format!("port {} is disabled", self.port_name),
267 });
268 }
269 if !self.connected {
270 return Err(AsynError::Status {
271 status: AsynStatus::Disconnected,
272 message: format!("port {} is disconnected", self.port_name),
273 });
274 }
275 Ok(())
276 }
277
278 pub fn shutdown_lifecycle(&mut self) -> AsynResult<()> {
294 if self.defunct {
295 return Ok(());
297 }
298 if !self.flags.destructible {
299 return Err(AsynError::Status {
300 status: AsynStatus::Error,
301 message: format!(
302 "port {} does not support shutting down (ASYN_DESTRUCTIBLE not set)",
303 self.port_name
304 ),
305 });
306 }
307 self.enabled = false;
308 self.defunct = true;
309 self.announce_exception(AsynException::Shutdown, -1);
310 Ok(())
311 }
312
313 pub fn check_ready_addr(&self, addr: i32) -> AsynResult<()> {
316 self.check_ready()?;
317 if self.flags.multi_device {
318 if let Some(ds) = self.device_states.get(&addr) {
319 if !ds.enabled {
320 return Err(AsynError::Status {
321 status: AsynStatus::Disabled,
322 message: format!("port {} addr {} is disabled", self.port_name, addr),
323 });
324 }
325 if !ds.connected {
326 return Err(AsynError::Status {
327 status: AsynStatus::Disconnected,
328 message: format!("port {} addr {} is disconnected", self.port_name, addr),
329 });
330 }
331 }
332 }
333 Ok(())
334 }
335
336 pub fn device_state(&mut self, addr: i32) -> &mut DeviceState {
338 self.device_states.entry(addr).or_default()
339 }
340
341 pub fn is_device_connected(&self, addr: i32) -> bool {
343 self.device_states
344 .get(&addr)
345 .map_or(true, |ds| ds.connected)
346 }
347
348 pub fn connect_addr(&mut self, addr: i32) {
358 self.set_addr_connected(addr, true);
359 }
360
361 pub fn disconnect_addr(&mut self, addr: i32) {
367 self.set_addr_connected(addr, false);
368 }
369
370 pub fn enable_addr(&mut self, addr: i32) {
372 self.device_state(addr).enabled = true;
373 self.announce_exception(AsynException::Enable, addr);
374 }
375
376 pub fn disable_addr(&mut self, addr: i32) {
378 self.device_state(addr).enabled = false;
379 self.announce_exception(AsynException::Enable, addr);
380 }
381
382 pub fn register_timestamp_source<F>(&mut self, source: F)
384 where
385 F: Fn() -> SystemTime + Send + Sync + 'static,
386 {
387 self.timestamp_source = Some(Arc::new(source));
388 }
389
390 pub fn current_timestamp(&self) -> SystemTime {
392 self.timestamp_source
393 .as_ref()
394 .map_or_else(SystemTime::now, |f| f())
395 }
396
397 pub fn create_param(&mut self, name: &str, param_type: ParamType) -> AsynResult<usize> {
398 self.params.create_param(name, param_type)
399 }
400
401 pub fn find_param(&self, name: &str) -> Option<usize> {
402 self.params.find_param(name)
403 }
404
405 pub fn set_int32_param(&mut self, index: usize, addr: i32, value: i32) -> AsynResult<()> {
408 self.params.set_int32(index, addr, value)
409 }
410
411 pub fn get_int32_param(&self, index: usize, addr: i32) -> AsynResult<i32> {
412 self.params.get_int32(index, addr)
413 }
414
415 pub fn get_int32_param_strict(&self, index: usize, addr: i32) -> AsynResult<i32> {
419 self.params.get_int32_strict(index, addr)
420 }
421
422 pub fn set_int64_param(&mut self, index: usize, addr: i32, value: i64) -> AsynResult<()> {
423 self.params.set_int64(index, addr, value)
424 }
425
426 pub fn get_int64_param(&self, index: usize, addr: i32) -> AsynResult<i64> {
427 self.params.get_int64(index, addr)
428 }
429
430 pub fn get_int64_param_strict(&self, index: usize, addr: i32) -> AsynResult<i64> {
432 self.params.get_int64_strict(index, addr)
433 }
434
435 pub fn set_float64_param(&mut self, index: usize, addr: i32, value: f64) -> AsynResult<()> {
436 self.params.set_float64(index, addr, value)
437 }
438
439 pub fn get_float64_param(&self, index: usize, addr: i32) -> AsynResult<f64> {
440 self.params.get_float64(index, addr)
441 }
442
443 pub fn get_float64_param_strict(&self, index: usize, addr: i32) -> AsynResult<f64> {
445 self.params.get_float64_strict(index, addr)
446 }
447
448 pub fn set_string_param(&mut self, index: usize, addr: i32, value: String) -> AsynResult<()> {
449 self.params.set_string(index, addr, value)
450 }
451
452 pub fn get_string_param(&self, index: usize, addr: i32) -> AsynResult<&str> {
453 self.params.get_string(index, addr)
454 }
455
456 pub fn get_string_param_strict(&self, index: usize, addr: i32) -> AsynResult<&str> {
458 self.params.get_string_strict(index, addr)
459 }
460
461 pub fn set_uint32_param(
467 &mut self,
468 index: usize,
469 addr: i32,
470 value: u32,
471 mask: u32,
472 interrupt_mask: u32,
473 ) -> AsynResult<()> {
474 self.params
475 .set_uint32(index, addr, value, mask, interrupt_mask)
476 }
477
478 pub fn get_uint32_param(&self, index: usize, addr: i32) -> AsynResult<u32> {
479 self.params.get_uint32(index, addr)
480 }
481
482 pub fn get_uint32_param_strict(&self, index: usize, addr: i32) -> AsynResult<u32> {
484 self.params.get_uint32_strict(index, addr)
485 }
486
487 pub fn get_enum_param(&self, index: usize, addr: i32) -> AsynResult<(usize, Arc<[EnumEntry]>)> {
488 self.params.get_enum(index, addr)
489 }
490
491 pub fn set_enum_index_param(
492 &mut self,
493 index: usize,
494 addr: i32,
495 value: usize,
496 ) -> AsynResult<()> {
497 self.params.set_enum_index(index, addr, value)
498 }
499
500 pub fn set_enum_choices_param(
501 &mut self,
502 index: usize,
503 addr: i32,
504 choices: Arc<[EnumEntry]>,
505 ) -> AsynResult<()> {
506 self.params.set_enum_choices(index, addr, choices)
507 }
508
509 pub fn get_generic_pointer_param(
510 &self,
511 index: usize,
512 addr: i32,
513 ) -> AsynResult<Arc<dyn Any + Send + Sync>> {
514 self.params.get_generic_pointer(index, addr)
515 }
516
517 pub fn set_generic_pointer_param(
518 &mut self,
519 index: usize,
520 addr: i32,
521 value: Arc<dyn Any + Send + Sync>,
522 ) -> AsynResult<()> {
523 self.params.set_generic_pointer(index, addr, value)
524 }
525
526 pub fn set_param_timestamp(
527 &mut self,
528 index: usize,
529 addr: i32,
530 ts: SystemTime,
531 ) -> AsynResult<()> {
532 self.params.set_timestamp(index, addr, ts)
533 }
534
535 pub fn set_param_status(
536 &mut self,
537 index: usize,
538 addr: i32,
539 status: AsynStatus,
540 alarm_status: u16,
541 alarm_severity: u16,
542 ) -> AsynResult<()> {
543 self.params
544 .set_param_status(index, addr, status, alarm_status, alarm_severity)
545 }
546
547 pub fn get_param_status(&self, index: usize, addr: i32) -> AsynResult<(AsynStatus, u16, u16)> {
548 self.params.get_param_status(index, addr)
549 }
550
551 pub fn report_params(&self, level: i32) {
553 eprintln!(" Number of parameters is {}", self.params.len());
554 if level < 1 {
555 return;
556 }
557 for i in 0..self.params.len() {
558 let name = self.params.param_name(i).unwrap_or("?");
559 let ptype = self
560 .params
561 .param_type(i)
562 .map(|t| format!("{t:?}"))
563 .unwrap_or("?".into());
564 if level >= 2 {
565 for addr in 0..self.max_addr.max(1) {
566 let val = self
567 .params
568 .get_value(i, addr as i32)
569 .map(|v| format!("{v:?}"))
570 .unwrap_or("undefined".into());
571 let (status, alarm_st, alarm_sev) = self
572 .params
573 .get_param_status(i, addr as i32)
574 .unwrap_or((AsynStatus::Success, 0, 0));
575 eprintln!(
576 " param[{i}] name={name} type={ptype} addr={addr} val={val} status={status:?} alarm=({alarm_st},{alarm_sev})"
577 );
578 }
579 } else {
580 eprintln!(" param[{i}] name={name} type={ptype}");
581 }
582 }
583 }
584
585 pub fn push_octet_interpose(&mut self, layer: Box<dyn OctetInterpose>) {
591 self.interpose_octet.push(layer);
592 }
593
594 pub fn call_param_callbacks(&mut self, addr: i32) -> AsynResult<()> {
597 let changed = self.params.take_changed(addr)?;
598 let now = self.current_timestamp();
599 for reason in changed {
600 let value = self.params.get_value(reason, addr)?.clone();
601 let ts = self.params.get_timestamp(reason, addr)?.unwrap_or(now);
602 let uint32_mask = self
607 .params
608 .take_uint32_interrupt_mask(reason, addr)
609 .unwrap_or(0);
610 let (aux_status, alarm_status, alarm_severity) = self
616 .params
617 .get_param_status(reason, addr)
618 .unwrap_or((AsynStatus::Success, 0, 0));
619 self.interrupts.notify(InterruptValue {
620 reason,
621 addr,
622 value,
623 timestamp: ts,
624 uint32_changed_mask: uint32_mask,
625 aux_status,
626 alarm_status,
627 alarm_severity,
628 });
629 }
630 Ok(())
631 }
632
633 pub fn call_param_callback(&mut self, addr: i32, reason: usize) -> AsynResult<()> {
637 if self.params.take_changed_single(reason, addr)? {
638 let now = self.current_timestamp();
639 let value = self.params.get_value(reason, addr)?.clone();
640 let ts = self.params.get_timestamp(reason, addr)?.unwrap_or(now);
641 let uint32_mask = self
646 .params
647 .take_uint32_interrupt_mask(reason, addr)
648 .unwrap_or(0);
649 let (aux_status, alarm_status, alarm_severity) = self
651 .params
652 .get_param_status(reason, addr)
653 .unwrap_or((AsynStatus::Success, 0, 0));
654 self.interrupts.notify(InterruptValue {
655 reason,
656 addr,
657 value,
658 timestamp: ts,
659 uint32_changed_mask: uint32_mask,
660 aux_status,
661 alarm_status,
662 alarm_severity,
663 });
664 }
665 Ok(())
666 }
667
668 pub fn mark_param_changed(&mut self, index: usize, addr: i32) -> AsynResult<()> {
673 self.params.mark_changed(index, addr)
674 }
675}
676
677pub trait PortDriver: Send + Sync + 'static {
692 fn base(&self) -> &PortDriverBase;
693 fn base_mut(&mut self) -> &mut PortDriverBase;
694
695 fn connect(&mut self, _user: &AsynUser) -> AsynResult<()> {
698 self.base_mut().set_connected(true);
700 Ok(())
701 }
702
703 fn disconnect(&mut self, _user: &AsynUser) -> AsynResult<()> {
704 self.base_mut().set_connected(false);
705 Ok(())
706 }
707
708 fn enable(&mut self, _user: &AsynUser) -> AsynResult<()> {
709 self.base_mut().enabled = true;
710 self.base().announce_exception(AsynException::Enable, -1);
711 Ok(())
712 }
713
714 fn disable(&mut self, _user: &AsynUser) -> AsynResult<()> {
715 self.base_mut().enabled = false;
716 self.base().announce_exception(AsynException::Enable, -1);
717 Ok(())
718 }
719
720 fn connect_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
721 self.base_mut().connect_addr(user.addr);
722 Ok(())
723 }
724
725 fn disconnect_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
726 self.base_mut().disconnect_addr(user.addr);
727 Ok(())
728 }
729
730 fn enable_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
731 self.base_mut().enable_addr(user.addr);
732 Ok(())
733 }
734
735 fn disable_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
736 self.base_mut().disable_addr(user.addr);
737 Ok(())
738 }
739
740 fn get_option(&self, key: &str) -> AsynResult<String> {
741 self.base()
742 .options
743 .get(key)
744 .cloned()
745 .ok_or_else(|| AsynError::OptionNotFound(key.to_string()))
746 }
747
748 fn set_option(&mut self, key: &str, value: &str) -> AsynResult<()> {
749 self.base_mut()
750 .options
751 .insert(key.to_string(), value.to_string());
752 Ok(())
753 }
754
755 fn report(&self, level: i32) {
756 let base = self.base();
757 eprintln!("Port: {}", base.port_name);
758 eprintln!(
759 " connected: {}, max_addr: {}, params: {}, options: {}",
760 base.connected,
761 base.max_addr,
762 base.params.len(),
763 base.options.len()
764 );
765 if level >= 1 {
766 base.report_params(level.saturating_sub(1));
767 }
768 if level >= 2 {
769 for (k, v) in &base.options {
770 eprintln!(" option: {k} = {v}");
771 }
772 }
773 }
774
775 fn read_int32(&mut self, user: &AsynUser) -> AsynResult<i32> {
794 self.base().params.get_int32_strict(user.reason, user.addr)
795 }
796
797 fn write_int32(&mut self, user: &mut AsynUser, value: i32) -> AsynResult<()> {
798 self.base_mut()
799 .params
800 .set_int32(user.reason, user.addr, value)?;
801 self.base_mut().call_param_callbacks(user.addr)
802 }
803
804 fn read_int64(&mut self, user: &AsynUser) -> AsynResult<i64> {
805 self.base().params.get_int64_strict(user.reason, user.addr)
806 }
807
808 fn write_int64(&mut self, user: &mut AsynUser, value: i64) -> AsynResult<()> {
809 self.base_mut()
810 .params
811 .set_int64(user.reason, user.addr, value)?;
812 self.base_mut().call_param_callbacks(user.addr)
813 }
814
815 fn get_bounds_int32(&self, _user: &AsynUser) -> AsynResult<(i32, i32)> {
819 Ok((0, 0))
820 }
821
822 fn get_bounds_int64(&self, _user: &AsynUser) -> AsynResult<(i64, i64)> {
825 Ok((0, 0))
826 }
827
828 fn read_float64(&mut self, user: &AsynUser) -> AsynResult<f64> {
829 self.base()
830 .params
831 .get_float64_strict(user.reason, user.addr)
832 }
833
834 fn write_float64(&mut self, user: &mut AsynUser, value: f64) -> AsynResult<()> {
835 self.base_mut()
836 .params
837 .set_float64(user.reason, user.addr, value)?;
838 self.base_mut().call_param_callbacks(user.addr)
839 }
840
841 fn read_octet(&mut self, user: &AsynUser, buf: &mut [u8]) -> AsynResult<usize> {
842 let s = self
843 .base()
844 .params
845 .get_string_strict(user.reason, user.addr)?;
846 let bytes = s.as_bytes();
847 let n = bytes.len().min(buf.len());
848 buf[..n].copy_from_slice(&bytes[..n]);
849 Ok(n)
850 }
851
852 fn write_octet(&mut self, user: &mut AsynUser, data: &[u8]) -> AsynResult<()> {
853 let s = String::from_utf8_lossy(data).into_owned();
854 self.base_mut()
855 .params
856 .set_string(user.reason, user.addr, s)?;
857 self.base_mut().call_param_callbacks(user.addr)
858 }
859
860 fn read_uint32_digital(&mut self, user: &AsynUser, mask: u32) -> AsynResult<u32> {
861 let val = self
862 .base()
863 .params
864 .get_uint32_strict(user.reason, user.addr)?;
865 Ok(val & mask)
866 }
867
868 fn write_uint32_digital(
869 &mut self,
870 user: &mut AsynUser,
871 value: u32,
872 mask: u32,
873 ) -> AsynResult<()> {
874 self.base_mut()
877 .params
878 .set_uint32(user.reason, user.addr, value, mask, 0)?;
879 self.base_mut().call_param_callbacks(user.addr)
880 }
881
882 fn set_interrupt_uint32_digital(
891 &mut self,
892 user: &AsynUser,
893 mask: u32,
894 reason: InterruptReason,
895 ) -> AsynResult<()> {
896 self.base_mut()
897 .params
898 .set_uint32_interrupt(user.reason, user.addr, mask, reason)
899 }
900
901 fn clear_interrupt_uint32_digital(&mut self, user: &AsynUser, mask: u32) -> AsynResult<()> {
906 self.base_mut()
907 .params
908 .clear_uint32_interrupt(user.reason, user.addr, mask)
909 }
910
911 fn get_interrupt_uint32_digital(
915 &self,
916 user: &AsynUser,
917 reason: InterruptReason,
918 ) -> AsynResult<u32> {
919 self.base()
920 .params
921 .get_uint32_interrupt(user.reason, user.addr, reason)
922 }
923
924 fn read_enum(&mut self, user: &AsynUser) -> AsynResult<(usize, Arc<[EnumEntry]>)> {
927 self.base().params.get_enum(user.reason, user.addr)
928 }
929
930 fn write_enum(&mut self, user: &mut AsynUser, index: usize) -> AsynResult<()> {
931 self.base_mut()
932 .params
933 .set_enum_index(user.reason, user.addr, index)?;
934 self.base_mut().call_param_callbacks(user.addr)
935 }
936
937 fn write_enum_choices(
938 &mut self,
939 user: &mut AsynUser,
940 choices: Arc<[EnumEntry]>,
941 ) -> AsynResult<()> {
942 self.base_mut()
943 .params
944 .set_enum_choices(user.reason, user.addr, choices)?;
945 self.base_mut().call_param_callbacks(user.addr)
946 }
947
948 fn read_generic_pointer(&mut self, user: &AsynUser) -> AsynResult<Arc<dyn Any + Send + Sync>> {
951 self.base()
952 .params
953 .get_generic_pointer(user.reason, user.addr)
954 }
955
956 fn write_generic_pointer(
957 &mut self,
958 user: &mut AsynUser,
959 value: Arc<dyn Any + Send + Sync>,
960 ) -> AsynResult<()> {
961 self.base_mut()
962 .params
963 .set_generic_pointer(user.reason, user.addr, value)?;
964 self.base_mut().call_param_callbacks(user.addr)
965 }
966
967 fn read_float64_array(&mut self, _user: &AsynUser, _buf: &mut [f64]) -> AsynResult<usize> {
970 Err(AsynError::InterfaceNotSupported("asynFloat64Array".into()))
971 }
972
973 fn write_float64_array(&mut self, user: &AsynUser, data: &[f64]) -> AsynResult<()> {
974 self.base_mut()
975 .params
976 .set_float64_array(user.reason, user.addr, data.to_vec())?;
977 self.base_mut().call_param_callbacks(user.addr)
978 }
979
980 fn read_int32_array(&mut self, _user: &AsynUser, _buf: &mut [i32]) -> AsynResult<usize> {
981 Err(AsynError::InterfaceNotSupported("asynInt32Array".into()))
982 }
983
984 fn write_int32_array(&mut self, user: &AsynUser, data: &[i32]) -> AsynResult<()> {
985 self.base_mut()
986 .params
987 .set_int32_array(user.reason, user.addr, data.to_vec())?;
988 self.base_mut().call_param_callbacks(user.addr)
989 }
990
991 fn read_int8_array(&mut self, _user: &AsynUser, _buf: &mut [i8]) -> AsynResult<usize> {
992 Err(AsynError::InterfaceNotSupported("asynInt8Array".into()))
993 }
994
995 fn write_int8_array(&mut self, user: &AsynUser, data: &[i8]) -> AsynResult<()> {
996 self.base_mut()
997 .params
998 .set_int8_array(user.reason, user.addr, data.to_vec())?;
999 self.base_mut().call_param_callbacks(user.addr)
1000 }
1001
1002 fn read_int16_array(&mut self, _user: &AsynUser, _buf: &mut [i16]) -> AsynResult<usize> {
1003 Err(AsynError::InterfaceNotSupported("asynInt16Array".into()))
1004 }
1005
1006 fn write_int16_array(&mut self, user: &AsynUser, data: &[i16]) -> AsynResult<()> {
1007 self.base_mut()
1008 .params
1009 .set_int16_array(user.reason, user.addr, data.to_vec())?;
1010 self.base_mut().call_param_callbacks(user.addr)
1011 }
1012
1013 fn read_int64_array(&mut self, _user: &AsynUser, _buf: &mut [i64]) -> AsynResult<usize> {
1014 Err(AsynError::InterfaceNotSupported("asynInt64Array".into()))
1015 }
1016
1017 fn write_int64_array(&mut self, user: &AsynUser, data: &[i64]) -> AsynResult<()> {
1018 self.base_mut()
1019 .params
1020 .set_int64_array(user.reason, user.addr, data.to_vec())?;
1021 self.base_mut().call_param_callbacks(user.addr)
1022 }
1023
1024 fn read_float32_array(&mut self, _user: &AsynUser, _buf: &mut [f32]) -> AsynResult<usize> {
1025 Err(AsynError::InterfaceNotSupported("asynFloat32Array".into()))
1026 }
1027
1028 fn write_float32_array(&mut self, user: &AsynUser, data: &[f32]) -> AsynResult<()> {
1029 self.base_mut()
1030 .params
1031 .set_float32_array(user.reason, user.addr, data.to_vec())?;
1032 self.base_mut().call_param_callbacks(user.addr)
1033 }
1034
1035 fn io_read_octet(&mut self, user: &AsynUser, buf: &mut [u8]) -> AsynResult<usize> {
1040 self.read_octet(user, buf)
1041 }
1042
1043 fn io_read_octet_eom(
1053 &mut self,
1054 user: &AsynUser,
1055 buf: &mut [u8],
1056 ) -> AsynResult<(usize, EomReason)> {
1057 let cap = buf.len();
1058 let n = self.io_read_octet(user, buf)?;
1059 let eom = if n >= cap && cap > 0 {
1060 EomReason::CNT
1061 } else {
1062 EomReason::empty()
1063 };
1064 Ok((n, eom))
1065 }
1066
1067 fn io_write_octet(&mut self, user: &mut AsynUser, data: &[u8]) -> AsynResult<()> {
1068 self.write_octet(user, data)
1069 }
1070
1071 fn io_read_int32(&mut self, user: &AsynUser) -> AsynResult<i32> {
1072 self.read_int32(user)
1073 }
1074
1075 fn io_write_int32(&mut self, user: &mut AsynUser, value: i32) -> AsynResult<()> {
1076 self.write_int32(user, value)
1077 }
1078
1079 fn io_read_int64(&mut self, user: &AsynUser) -> AsynResult<i64> {
1080 self.read_int64(user)
1081 }
1082
1083 fn io_write_int64(&mut self, user: &mut AsynUser, value: i64) -> AsynResult<()> {
1084 self.write_int64(user, value)
1085 }
1086
1087 fn io_read_float64(&mut self, user: &AsynUser) -> AsynResult<f64> {
1088 self.read_float64(user)
1089 }
1090
1091 fn io_write_float64(&mut self, user: &mut AsynUser, value: f64) -> AsynResult<()> {
1092 self.write_float64(user, value)
1093 }
1094
1095 fn io_read_uint32_digital(&mut self, user: &AsynUser, mask: u32) -> AsynResult<u32> {
1096 self.read_uint32_digital(user, mask)
1097 }
1098
1099 fn io_write_uint32_digital(
1100 &mut self,
1101 user: &mut AsynUser,
1102 value: u32,
1103 mask: u32,
1104 ) -> AsynResult<()> {
1105 self.write_uint32_digital(user, value, mask)
1106 }
1107
1108 fn io_flush(&mut self, _user: &mut AsynUser) -> AsynResult<()> {
1109 Ok(())
1110 }
1111
1112 fn set_input_eos(&mut self, eos: &[u8]) -> AsynResult<()> {
1138 if eos.len() > 2 {
1139 return Err(AsynError::Status {
1140 status: AsynStatus::Error,
1141 message: format!("illegal eoslen {}", eos.len()),
1142 });
1143 }
1144 self.base_mut().input_eos = eos.to_vec();
1145 Ok(())
1146 }
1147
1148 fn get_input_eos(&self) -> Vec<u8> {
1149 self.base().input_eos.clone()
1150 }
1151
1152 fn set_output_eos(&mut self, eos: &[u8]) -> AsynResult<()> {
1153 if eos.len() > 2 {
1154 return Err(AsynError::Status {
1155 status: AsynStatus::Error,
1156 message: format!("illegal eoslen {}", eos.len()),
1157 });
1158 }
1159 self.base_mut().output_eos = eos.to_vec();
1160 Ok(())
1161 }
1162
1163 fn get_output_eos(&self) -> Vec<u8> {
1164 self.base().output_eos.clone()
1165 }
1166
1167 fn shutdown(&mut self) -> AsynResult<()> {
1172 Ok(())
1173 }
1174
1175 fn drv_user_create(&self, drv_info: &str) -> AsynResult<usize> {
1180 self.base()
1181 .params
1182 .find_param(drv_info)
1183 .ok_or_else(|| AsynError::ParamNotFound(drv_info.to_string()))
1184 }
1185
1186 fn capabilities(&self) -> Vec<crate::interfaces::Capability> {
1191 crate::interfaces::default_capabilities()
1192 }
1193
1194 fn supports(&self, cap: crate::interfaces::Capability) -> bool {
1196 self.capabilities().contains(&cap)
1197 }
1198
1199 fn init(&mut self) -> AsynResult<()> {
1200 Ok(())
1201 }
1202}
1203
1204#[cfg(test)]
1205mod tests {
1206 use super::*;
1207 struct TestDriver {
1208 base: PortDriverBase,
1209 }
1210
1211 impl TestDriver {
1212 fn new() -> Self {
1213 let mut base = PortDriverBase::new("test", 1, PortFlags::default());
1214 base.create_param("VAL", ParamType::Int32).unwrap();
1215 base.create_param("TEMP", ParamType::Float64).unwrap();
1216 base.create_param("MSG", ParamType::Octet).unwrap();
1217 base.create_param("BITS", ParamType::UInt32Digital).unwrap();
1218 Self { base }
1219 }
1220 }
1221
1222 impl PortDriver for TestDriver {
1223 fn base(&self) -> &PortDriverBase {
1224 &self.base
1225 }
1226 fn base_mut(&mut self) -> &mut PortDriverBase {
1227 &mut self.base
1228 }
1229 }
1230
1231 #[test]
1232 fn test_default_read_write_int32() {
1233 let mut drv = TestDriver::new();
1234 let mut user = AsynUser::new(0);
1235 drv.write_int32(&mut user, 42).unwrap();
1236 let user = AsynUser::new(0);
1237 assert_eq!(drv.read_int32(&user).unwrap(), 42);
1238 }
1239
1240 #[test]
1241 fn test_default_read_write_float64() {
1242 let mut drv = TestDriver::new();
1243 let mut user = AsynUser::new(1);
1244 drv.write_float64(&mut user, 3.14).unwrap();
1245 let user = AsynUser::new(1);
1246 assert!((drv.read_float64(&user).unwrap() - 3.14).abs() < 1e-10);
1247 }
1248
1249 #[test]
1250 fn test_default_read_write_octet() {
1251 let mut drv = TestDriver::new();
1252 let mut user = AsynUser::new(2);
1253 drv.write_octet(&mut user, b"hello").unwrap();
1254 let user = AsynUser::new(2);
1255 let mut buf = [0u8; 32];
1256 let n = drv.read_octet(&user, &mut buf).unwrap();
1257 assert_eq!(&buf[..n], b"hello");
1258 }
1259
1260 #[test]
1261 fn test_default_read_write_uint32() {
1262 let mut drv = TestDriver::new();
1263 let mut user = AsynUser::new(3);
1264 drv.write_uint32_digital(&mut user, 0xFF, 0x0F).unwrap();
1265 let user = AsynUser::new(3);
1266 assert_eq!(drv.read_uint32_digital(&user, 0xFF).unwrap(), 0x0F);
1267 }
1268
1269 #[test]
1270 fn test_connect_disconnect() {
1271 let mut drv = TestDriver::new();
1272 let user = AsynUser::default();
1273 assert!(drv.base().connected);
1274 drv.disconnect(&user).unwrap();
1275 assert!(!drv.base().connected);
1276 drv.connect(&user).unwrap();
1277 assert!(drv.base().connected);
1278 }
1279
1280 #[test]
1281 fn test_drv_user_create() {
1282 let drv = TestDriver::new();
1283 assert_eq!(drv.drv_user_create("VAL").unwrap(), 0);
1284 assert_eq!(drv.drv_user_create("TEMP").unwrap(), 1);
1285 assert!(drv.drv_user_create("NOPE").is_err());
1286 }
1287
1288 #[test]
1289 fn test_call_param_callbacks() {
1290 let mut drv = TestDriver::new();
1291 let mut rx = drv.base_mut().interrupts.subscribe_async();
1292
1293 drv.base_mut().set_int32_param(0, 0, 100).unwrap();
1294 drv.base_mut().set_float64_param(1, 0, 2.0).unwrap();
1295 drv.base_mut().call_param_callbacks(0).unwrap();
1296
1297 let v1 = rx.try_recv().unwrap();
1298 assert_eq!(v1.reason, 0);
1299 let v2 = rx.try_recv().unwrap();
1300 assert_eq!(v2.reason, 1);
1301 assert!(rx.try_recv().is_err());
1302 }
1303
1304 #[test]
1305 fn uint32_callback_mask_does_not_leak_across_flushes() {
1306 let mut drv = TestDriver::new();
1310 let mut rx = drv.base_mut().interrupts.subscribe_async();
1311
1312 drv.base_mut()
1314 .params
1315 .set_uint32(3, 0, 0x01, 0x01, 0)
1316 .unwrap();
1317 drv.base_mut().call_param_callbacks(0).unwrap();
1318 let iv1 = rx.try_recv().unwrap();
1319 assert_eq!(iv1.reason, 3);
1320 assert_eq!(iv1.uint32_changed_mask, 0x01);
1321
1322 drv.base_mut()
1324 .params
1325 .set_uint32(3, 0, 0x02, 0x02, 0)
1326 .unwrap();
1327 drv.base_mut().call_param_callbacks(0).unwrap();
1328 let iv2 = rx.try_recv().unwrap();
1329 assert_eq!(
1330 iv2.uint32_changed_mask, 0x02,
1331 "second flush must not leak flush-1 bits via an un-reset mask"
1332 );
1333 assert_eq!(
1334 drv.base().params.get_uint32_interrupt_mask(3, 0).unwrap(),
1335 0,
1336 "the flush must consume (reset) the callback mask"
1337 );
1338 }
1339
1340 #[test]
1341 fn test_call_param_callbacks_propagates_aux_status_and_alarm() {
1342 let mut drv = TestDriver::new();
1347 let mut rx = drv.base_mut().interrupts.subscribe_async();
1348
1349 drv.base_mut().set_int32_param(0, 0, 99).unwrap();
1350 drv.base_mut()
1351 .params
1352 .set_param_status(0, 0, crate::error::AsynStatus::Timeout, 4, 2)
1353 .unwrap();
1354 drv.base_mut().call_param_callbacks(0).unwrap();
1355
1356 let iv = rx.try_recv().unwrap();
1357 assert_eq!(iv.reason, 0);
1358 assert!(matches!(iv.aux_status, crate::error::AsynStatus::Timeout));
1359 assert_eq!(iv.alarm_status, 4);
1360 assert_eq!(iv.alarm_severity, 2);
1361 }
1362
1363 #[test]
1364 fn test_call_param_callback_single_propagates_aux_status() {
1365 let mut drv = TestDriver::new();
1367 let mut rx = drv.base_mut().interrupts.subscribe_async();
1368
1369 drv.base_mut().set_int32_param(0, 0, 1).unwrap();
1370 drv.base_mut()
1371 .params
1372 .set_param_status(0, 0, crate::error::AsynStatus::Disconnected, 7, 3)
1373 .unwrap();
1374 drv.base_mut().call_param_callback(0, 0).unwrap();
1375
1376 let iv = rx.try_recv().unwrap();
1377 assert!(matches!(
1378 iv.aux_status,
1379 crate::error::AsynStatus::Disconnected
1380 ));
1381 assert_eq!(iv.alarm_status, 7);
1382 assert_eq!(iv.alarm_severity, 3);
1383 }
1384
1385 #[test]
1386 fn test_no_callback_for_unchanged() {
1387 let mut drv = TestDriver::new();
1388 let mut rx = drv.base_mut().interrupts.subscribe_async();
1389
1390 drv.base_mut().set_int32_param(0, 0, 5).unwrap();
1391 drv.base_mut().call_param_callbacks(0).unwrap();
1392 let _ = rx.try_recv().unwrap(); drv.base_mut().set_int32_param(0, 0, 5).unwrap();
1396 drv.base_mut().call_param_callbacks(0).unwrap();
1397 assert!(rx.try_recv().is_err());
1398 }
1399
1400 #[test]
1401 fn test_array_not_supported_by_default() {
1402 let mut drv = TestDriver::new();
1403 let user = AsynUser::new(0);
1404 let mut buf = [0f64; 10];
1405 assert!(drv.read_float64_array(&user, &mut buf).is_err());
1406 assert!(drv.write_float64_array(&user, &[1.0]).is_err());
1407 }
1408
1409 #[test]
1410 fn test_option_set_get() {
1411 let mut drv = TestDriver::new();
1412 drv.set_option("baud", "9600").unwrap();
1413 assert_eq!(drv.get_option("baud").unwrap(), "9600");
1414 drv.set_option("baud", "115200").unwrap();
1415 assert_eq!(drv.get_option("baud").unwrap(), "115200");
1416 }
1417
1418 #[test]
1419 fn test_option_not_found() {
1420 let drv = TestDriver::new();
1421 let err = drv.get_option("nonexistent").unwrap_err();
1422 assert!(matches!(err, AsynError::OptionNotFound(_)));
1423 }
1424
1425 #[test]
1426 fn test_report_no_panic() {
1427 let mut drv = TestDriver::new();
1428 drv.set_option("testkey", "testval").unwrap();
1429 drv.base_mut().set_int32_param(0, 0, 42).unwrap();
1430 for level in 0..=3 {
1431 drv.report(level);
1432 }
1433 }
1434
1435 #[test]
1436 fn test_callback_uses_param_timestamp() {
1437 let mut drv = TestDriver::new();
1438 let mut rx = drv.base_mut().interrupts.subscribe_async();
1439
1440 let custom_ts = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_000_000);
1441 drv.base_mut().set_int32_param(0, 0, 77).unwrap();
1442 drv.base_mut().set_param_timestamp(0, 0, custom_ts).unwrap();
1443 drv.base_mut().call_param_callbacks(0).unwrap();
1444
1445 let v = rx.try_recv().unwrap();
1446 assert_eq!(v.reason, 0);
1447 assert_eq!(v.timestamp, custom_ts);
1448 }
1449
1450 #[test]
1451 fn test_default_read_write_enum() {
1452 use crate::param::EnumEntry;
1453
1454 let mut base = PortDriverBase::new("test_enum", 1, PortFlags::default());
1455 base.create_param("MODE", ParamType::Enum).unwrap();
1456
1457 struct EnumDriver {
1458 base: PortDriverBase,
1459 }
1460 impl PortDriver for EnumDriver {
1461 fn base(&self) -> &PortDriverBase {
1462 &self.base
1463 }
1464 fn base_mut(&mut self) -> &mut PortDriverBase {
1465 &mut self.base
1466 }
1467 }
1468
1469 let mut drv = EnumDriver { base };
1470 let choices: Arc<[EnumEntry]> = Arc::from(vec![
1471 EnumEntry {
1472 string: "Off".into(),
1473 value: 0,
1474 severity: 0,
1475 },
1476 EnumEntry {
1477 string: "On".into(),
1478 value: 1,
1479 severity: 0,
1480 },
1481 ]);
1482 let mut user = AsynUser::new(0);
1483 drv.write_enum_choices(&mut user, choices).unwrap();
1484 drv.write_enum(&mut user, 1).unwrap();
1485 let (idx, ch) = drv.read_enum(&AsynUser::new(0)).unwrap();
1486 assert_eq!(idx, 1);
1487 assert_eq!(ch[1].string, "On");
1488 }
1489
1490 #[test]
1491 fn test_enum_callback() {
1492 use crate::param::{EnumEntry, ParamValue};
1493
1494 let mut base = PortDriverBase::new("test_enum_cb", 1, PortFlags::default());
1495 base.create_param("MODE", ParamType::Enum).unwrap();
1496 let mut rx = base.interrupts.subscribe_async();
1497
1498 struct EnumDriver {
1499 base: PortDriverBase,
1500 }
1501 impl PortDriver for EnumDriver {
1502 fn base(&self) -> &PortDriverBase {
1503 &self.base
1504 }
1505 fn base_mut(&mut self) -> &mut PortDriverBase {
1506 &mut self.base
1507 }
1508 }
1509
1510 let mut drv = EnumDriver { base };
1511 let choices: Arc<[EnumEntry]> = Arc::from(vec![
1512 EnumEntry {
1513 string: "A".into(),
1514 value: 0,
1515 severity: 0,
1516 },
1517 EnumEntry {
1518 string: "B".into(),
1519 value: 1,
1520 severity: 0,
1521 },
1522 ]);
1523 drv.base_mut()
1524 .set_enum_choices_param(0, 0, choices)
1525 .unwrap();
1526 drv.base_mut().set_enum_index_param(0, 0, 1).unwrap();
1527 drv.base_mut().call_param_callbacks(0).unwrap();
1528
1529 let v = rx.try_recv().unwrap();
1530 assert_eq!(v.reason, 0);
1531 assert!(matches!(v.value, ParamValue::Enum { index: 1, .. }));
1532 }
1533
1534 #[test]
1535 fn test_default_read_write_generic_pointer() {
1536 let mut base = PortDriverBase::new("test_gp", 1, PortFlags::default());
1537 base.create_param("PTR", ParamType::GenericPointer).unwrap();
1538
1539 struct GpDriver {
1540 base: PortDriverBase,
1541 }
1542 impl PortDriver for GpDriver {
1543 fn base(&self) -> &PortDriverBase {
1544 &self.base
1545 }
1546 fn base_mut(&mut self) -> &mut PortDriverBase {
1547 &mut self.base
1548 }
1549 }
1550
1551 let mut drv = GpDriver { base };
1552 let data: Arc<dyn std::any::Any + Send + Sync> = Arc::new(99i32);
1553 let mut user = AsynUser::new(0);
1554 drv.write_generic_pointer(&mut user, data).unwrap();
1555 let val = drv.read_generic_pointer(&AsynUser::new(0)).unwrap();
1556 assert_eq!(*val.downcast_ref::<i32>().unwrap(), 99);
1557 }
1558
1559 #[test]
1560 fn test_generic_pointer_callback() {
1561 use crate::param::ParamValue;
1562
1563 let mut base = PortDriverBase::new("test_gp_cb", 1, PortFlags::default());
1564 base.create_param("PTR", ParamType::GenericPointer).unwrap();
1565 let mut rx = base.interrupts.subscribe_async();
1566
1567 struct GpDriver {
1568 base: PortDriverBase,
1569 }
1570 impl PortDriver for GpDriver {
1571 fn base(&self) -> &PortDriverBase {
1572 &self.base
1573 }
1574 fn base_mut(&mut self) -> &mut PortDriverBase {
1575 &mut self.base
1576 }
1577 }
1578
1579 let mut drv = GpDriver { base };
1580 let data: Arc<dyn std::any::Any + Send + Sync> = Arc::new(vec![1, 2, 3]);
1581 drv.base_mut()
1582 .set_generic_pointer_param(0, 0, data)
1583 .unwrap();
1584 drv.base_mut().call_param_callbacks(0).unwrap();
1585
1586 let v = rx.try_recv().unwrap();
1587 assert_eq!(v.reason, 0);
1588 assert!(matches!(v.value, ParamValue::GenericPointer(_)));
1589 }
1590
1591 #[test]
1592 fn test_interpose_push_requires_lock() {
1593 use crate::interpose::{OctetInterpose, OctetNext, OctetReadResult};
1594 use parking_lot::Mutex;
1595 use std::sync::Arc;
1596
1597 struct NoopInterpose;
1598 impl OctetInterpose for NoopInterpose {
1599 fn read(
1600 &mut self,
1601 user: &AsynUser,
1602 buf: &mut [u8],
1603 next: &mut dyn OctetNext,
1604 ) -> AsynResult<OctetReadResult> {
1605 next.read(user, buf)
1606 }
1607 fn write(
1608 &mut self,
1609 user: &mut AsynUser,
1610 data: &[u8],
1611 next: &mut dyn OctetNext,
1612 ) -> AsynResult<usize> {
1613 next.write(user, data)
1614 }
1615 fn flush(&mut self, user: &mut AsynUser, next: &mut dyn OctetNext) -> AsynResult<()> {
1616 next.flush(user)
1617 }
1618 }
1619
1620 let port: Arc<Mutex<dyn PortDriver>> = Arc::new(Mutex::new(TestDriver::new()));
1621
1622 {
1623 let mut guard = port.lock();
1624 guard
1625 .base_mut()
1626 .push_octet_interpose(Box::new(NoopInterpose));
1627 assert_eq!(guard.base().interpose_octet.len(), 1);
1628 }
1629 }
1630
1631 #[test]
1632 fn test_default_read_write_int64() {
1633 let mut base = PortDriverBase::new("test_i64", 1, PortFlags::default());
1634 base.create_param("BIG", ParamType::Int64).unwrap();
1635
1636 struct I64Driver {
1637 base: PortDriverBase,
1638 }
1639 impl PortDriver for I64Driver {
1640 fn base(&self) -> &PortDriverBase {
1641 &self.base
1642 }
1643 fn base_mut(&mut self) -> &mut PortDriverBase {
1644 &mut self.base
1645 }
1646 }
1647
1648 let mut drv = I64Driver { base };
1649 let mut user = AsynUser::new(0);
1650 drv.write_int64(&mut user, i64::MAX).unwrap();
1651 assert_eq!(drv.read_int64(&AsynUser::new(0)).unwrap(), i64::MAX);
1652 }
1653
1654 #[test]
1655 fn test_get_bounds_int64_default() {
1656 let base = PortDriverBase::new("test_bounds", 1, PortFlags::default());
1657 struct BoundsDriver {
1658 base: PortDriverBase,
1659 }
1660 impl PortDriver for BoundsDriver {
1661 fn base(&self) -> &PortDriverBase {
1662 &self.base
1663 }
1664 fn base_mut(&mut self) -> &mut PortDriverBase {
1665 &mut self.base
1666 }
1667 }
1668 let drv = BoundsDriver { base };
1669 let (lo, hi) = drv.get_bounds_int64(&AsynUser::default()).unwrap();
1670 assert_eq!(lo, 0);
1673 assert_eq!(hi, 0);
1674 }
1675
1676 #[test]
1677 fn test_per_addr_device_state() {
1678 let mut base = PortDriverBase::new(
1679 "multi",
1680 4,
1681 PortFlags {
1682 multi_device: true,
1683 can_block: false,
1684 destructible: true,
1685 },
1686 );
1687 base.create_param("V", ParamType::Int32).unwrap();
1688
1689 assert!(base.is_device_connected(0));
1691 assert!(base.is_device_connected(1));
1692
1693 base.device_state(1).enabled = false;
1695 assert!(base.check_ready_addr(0).is_ok());
1696 let err = base.check_ready_addr(1).unwrap_err();
1697 assert!(format!("{err}").contains("disabled"));
1698
1699 base.device_state(2).connected = false;
1701 let err = base.check_ready_addr(2).unwrap_err();
1702 assert!(format!("{err}").contains("disconnected"));
1703 }
1704
1705 #[test]
1706 fn test_per_addr_single_device_ignored() {
1707 let mut base = PortDriverBase::new("single", 1, PortFlags::default());
1708 base.create_param("V", ParamType::Int32).unwrap();
1709 assert!(base.check_ready_addr(0).is_ok());
1711 }
1712
1713 #[test]
1714 fn test_timestamp_source() {
1715 let mut base = PortDriverBase::new("ts_test", 1, PortFlags::default());
1716 base.create_param("V", ParamType::Int32).unwrap();
1717
1718 let fixed_ts = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(999999);
1719 base.register_timestamp_source(move || fixed_ts);
1720
1721 assert_eq!(base.current_timestamp(), fixed_ts);
1722 }
1723
1724 #[test]
1725 fn test_timestamp_source_in_callbacks() {
1726 let mut base = PortDriverBase::new("ts_cb", 1, PortFlags::default());
1727 base.create_param("V", ParamType::Int32).unwrap();
1728 let mut rx = base.interrupts.subscribe_async();
1729
1730 let fixed_ts = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(123456);
1731 base.register_timestamp_source(move || fixed_ts);
1732
1733 struct TsDriver {
1734 base: PortDriverBase,
1735 }
1736 impl PortDriver for TsDriver {
1737 fn base(&self) -> &PortDriverBase {
1738 &self.base
1739 }
1740 fn base_mut(&mut self) -> &mut PortDriverBase {
1741 &mut self.base
1742 }
1743 }
1744 let mut drv = TsDriver { base };
1745 drv.base_mut().set_int32_param(0, 0, 42).unwrap();
1746 drv.base_mut().call_param_callbacks(0).unwrap();
1747
1748 let v = rx.try_recv().unwrap();
1749 assert_eq!(v.timestamp, fixed_ts);
1751 }
1752
1753 #[test]
1754 fn test_queue_priority_connect() {
1755 assert!(QueuePriority::Connect > QueuePriority::High);
1756 }
1757
1758 #[test]
1759 fn test_port_flags_destructible_default_is_opt_in() {
1760 let flags = PortFlags::default();
1766 assert!(
1767 !flags.destructible,
1768 "destructible must be opt-in (C parity)"
1769 );
1770 }
1771
1772 #[test]
1773 fn shutdown_lifecycle_refuses_non_destructible() {
1774 let mut base = PortDriverBase::new(
1775 "p_nondestr",
1776 1,
1777 PortFlags {
1778 multi_device: false,
1779 can_block: false,
1780 destructible: false,
1781 },
1782 );
1783 match base.shutdown_lifecycle() {
1784 Err(AsynError::Status { message, .. }) => {
1785 assert!(message.contains("ASYN_DESTRUCTIBLE"), "msg={message}");
1786 }
1787 other => panic!("expected ASYN_DESTRUCTIBLE refusal, got {other:?}"),
1788 }
1789 assert!(
1790 !base.is_defunct(),
1791 "non-destructible port must not flip defunct"
1792 );
1793 assert!(base.is_enabled(), "non-destructible port must stay enabled");
1794 }
1795
1796 #[test]
1797 fn shutdown_lifecycle_marks_destructible_defunct_and_idempotent() {
1798 let mut base = PortDriverBase::new(
1799 "p_destr",
1800 1,
1801 PortFlags {
1802 multi_device: false,
1803 can_block: false,
1804 destructible: true,
1805 },
1806 );
1807 assert!(base.is_enabled());
1808 assert!(!base.is_defunct());
1809 base.shutdown_lifecycle().unwrap();
1810 assert!(
1811 !base.is_enabled(),
1812 "shutdown_lifecycle must flip enabled=false"
1813 );
1814 assert!(
1815 base.is_defunct(),
1816 "shutdown_lifecycle must flip defunct=true"
1817 );
1818 base.shutdown_lifecycle().unwrap();
1820 assert!(base.is_defunct());
1821 match base.check_ready() {
1823 Err(AsynError::Status { message, .. }) => {
1824 assert!(message.contains("defunct"), "msg={message}");
1825 }
1826 other => panic!("expected defunct error, got {other:?}"),
1827 }
1828 }
1829
1830 #[test]
1833 fn test_connect_addr() {
1834 let mut base = PortDriverBase::new(
1835 "multi_conn",
1836 4,
1837 PortFlags {
1838 multi_device: true,
1839 can_block: false,
1840 destructible: true,
1841 },
1842 );
1843 base.create_param("V", ParamType::Int32).unwrap();
1844
1845 base.disconnect_addr(1);
1846 assert!(!base.is_device_connected(1));
1847 assert!(base.check_ready_addr(1).is_err());
1848
1849 base.connect_addr(1);
1850 assert!(base.is_device_connected(1));
1851 assert!(base.check_ready_addr(1).is_ok());
1852 }
1853
1854 #[test]
1855 fn test_enable_disable_addr() {
1856 let mut base = PortDriverBase::new(
1857 "multi_en",
1858 4,
1859 PortFlags {
1860 multi_device: true,
1861 can_block: false,
1862 destructible: true,
1863 },
1864 );
1865 base.create_param("V", ParamType::Int32).unwrap();
1866
1867 base.disable_addr(2);
1868 let err = base.check_ready_addr(2).unwrap_err();
1869 assert!(format!("{err}").contains("disabled"));
1870
1871 base.enable_addr(2);
1872 assert!(base.check_ready_addr(2).is_ok());
1873 }
1874
1875 #[test]
1876 fn test_port_level_overrides_addr() {
1877 let mut base = PortDriverBase::new(
1878 "multi_override",
1879 4,
1880 PortFlags {
1881 multi_device: true,
1882 can_block: false,
1883 destructible: true,
1884 },
1885 );
1886 base.create_param("V", ParamType::Int32).unwrap();
1887
1888 base.enabled = false;
1890 base.enable_addr(0); let err = base.check_ready_addr(0).unwrap_err();
1892 assert!(format!("{err}").contains("disabled"));
1893 }
1894
1895 #[test]
1896 fn test_per_addr_exception_announced() {
1897 use std::sync::atomic::{AtomicI32, Ordering};
1898
1899 let mut base = PortDriverBase::new(
1900 "multi_exc",
1901 4,
1902 PortFlags {
1903 multi_device: true,
1904 can_block: false,
1905 destructible: true,
1906 },
1907 );
1908 base.create_param("V", ParamType::Int32).unwrap();
1909
1910 let exc_mgr = Arc::new(crate::exception::ExceptionManager::new());
1911 base.exception_sink = Some(exc_mgr.clone());
1912
1913 let last_addr = Arc::new(AtomicI32::new(-99));
1914 let last_addr2 = last_addr.clone();
1915 exc_mgr.add_callback(move |event| {
1916 last_addr2.store(event.addr, Ordering::Relaxed);
1917 });
1918
1919 base.disconnect_addr(3);
1920 assert_eq!(last_addr.load(Ordering::Relaxed), 3);
1921
1922 base.enable_addr(2);
1923 assert_eq!(last_addr.load(Ordering::Relaxed), 2);
1924 }
1925
1926 #[test]
1933 fn test_connect_disconnect_announce_only_on_transition() {
1934 use std::sync::atomic::{AtomicUsize, Ordering};
1935
1936 let mut base = PortDriverBase::new(
1937 "edge",
1938 4,
1939 PortFlags {
1940 multi_device: true,
1941 can_block: false,
1942 destructible: true,
1943 },
1944 );
1945 base.create_param("V", ParamType::Int32).unwrap();
1946 let exc_mgr = Arc::new(crate::exception::ExceptionManager::new());
1947 base.exception_sink = Some(exc_mgr.clone());
1948
1949 let connect_hits = Arc::new(AtomicUsize::new(0));
1950 let hits2 = connect_hits.clone();
1951 exc_mgr.add_callback(move |event| {
1952 if event.exception == AsynException::Connect {
1953 hits2.fetch_add(1, Ordering::Relaxed);
1954 }
1955 });
1956
1957 base.connect_addr(2);
1960 assert_eq!(
1961 connect_hits.load(Ordering::Relaxed),
1962 0,
1963 "redundant connect_addr must not fan out"
1964 );
1965
1966 base.disconnect_addr(2);
1968 assert_eq!(connect_hits.load(Ordering::Relaxed), 1);
1969
1970 base.disconnect_addr(2);
1972 assert_eq!(
1973 connect_hits.load(Ordering::Relaxed),
1974 1,
1975 "redundant disconnect_addr must not fan out"
1976 );
1977
1978 base.connect_addr(2);
1980 assert_eq!(connect_hits.load(Ordering::Relaxed), 2);
1981 }
1982
1983 #[test]
1988 fn test_set_auto_connect_fires_unconditionally() {
1989 use std::sync::atomic::{AtomicUsize, Ordering};
1990
1991 let mut base = PortDriverBase::new("ac", 1, PortFlags::default());
1992 let exc_mgr = Arc::new(crate::exception::ExceptionManager::new());
1993 base.exception_sink = Some(exc_mgr.clone());
1994 let hits = Arc::new(AtomicUsize::new(0));
1995 let hits2 = hits.clone();
1996 exc_mgr.add_callback(move |event| {
1997 if event.exception == AsynException::AutoConnect {
1998 hits2.fetch_add(1, Ordering::Relaxed);
1999 }
2000 });
2001 base.set_auto_connect(true);
2004 base.set_auto_connect(false);
2005 base.set_auto_connect(false);
2006 assert_eq!(hits.load(Ordering::Relaxed), 3);
2007 }
2008
2009 #[test]
2015 fn test_port_driver_uint32_interrupt_round_trip() {
2016 struct UInt32Drv {
2017 base: PortDriverBase,
2018 }
2019 impl PortDriver for UInt32Drv {
2020 fn base(&self) -> &PortDriverBase {
2021 &self.base
2022 }
2023 fn base_mut(&mut self) -> &mut PortDriverBase {
2024 &mut self.base
2025 }
2026 }
2027
2028 let mut base = PortDriverBase::new("uint32_int", 1, PortFlags::default());
2029 let idx = base
2030 .params
2031 .create_param("BITS", ParamType::UInt32Digital)
2032 .unwrap();
2033 let mut drv = UInt32Drv { base };
2034 let user = AsynUser::new(idx).with_addr(0);
2035
2036 drv.set_interrupt_uint32_digital(&user, 0xF0, InterruptReason::ZeroToOne)
2037 .unwrap();
2038 drv.set_interrupt_uint32_digital(&user, 0x0F, InterruptReason::OneToZero)
2039 .unwrap();
2040 assert_eq!(
2041 drv.get_interrupt_uint32_digital(&user, InterruptReason::Both)
2042 .unwrap(),
2043 0xFF
2044 );
2045 drv.clear_interrupt_uint32_digital(&user, 0x11).unwrap();
2046 assert_eq!(
2047 drv.get_interrupt_uint32_digital(&user, InterruptReason::ZeroToOne)
2048 .unwrap(),
2049 0xE0
2050 );
2051 assert_eq!(
2052 drv.get_interrupt_uint32_digital(&user, InterruptReason::OneToZero)
2053 .unwrap(),
2054 0x0E
2055 );
2056 }
2057
2058 #[test]
2069 fn default_scalar_reads_report_undefined_until_set() {
2070 struct AllTypesDrv {
2071 base: PortDriverBase,
2072 }
2073 impl PortDriver for AllTypesDrv {
2074 fn base(&self) -> &PortDriverBase {
2075 &self.base
2076 }
2077 fn base_mut(&mut self) -> &mut PortDriverBase {
2078 &mut self.base
2079 }
2080 }
2081
2082 let mut base = PortDriverBase::new("undef_read", 1, PortFlags::default());
2083 let i32_idx = base.params.create_param("I32", ParamType::Int32).unwrap();
2084 let i64_idx = base.params.create_param("I64", ParamType::Int64).unwrap();
2085 let f64_idx = base.params.create_param("F64", ParamType::Float64).unwrap();
2086 let oct_idx = base.params.create_param("OCT", ParamType::Octet).unwrap();
2087 let u32_idx = base
2088 .params
2089 .create_param("BITS", ParamType::UInt32Digital)
2090 .unwrap();
2091 let mut drv = AllTypesDrv { base };
2092
2093 assert!(matches!(
2095 drv.read_int32(&AsynUser::new(i32_idx).with_addr(0)),
2096 Err(AsynError::ParamUndefined(_))
2097 ));
2098 assert!(matches!(
2099 drv.read_int64(&AsynUser::new(i64_idx).with_addr(0)),
2100 Err(AsynError::ParamUndefined(_))
2101 ));
2102 assert!(matches!(
2103 drv.read_float64(&AsynUser::new(f64_idx).with_addr(0)),
2104 Err(AsynError::ParamUndefined(_))
2105 ));
2106 let mut buf = [0u8; 16];
2107 assert!(matches!(
2108 drv.read_octet(&AsynUser::new(oct_idx).with_addr(0), &mut buf),
2109 Err(AsynError::ParamUndefined(_))
2110 ));
2111 assert!(matches!(
2112 drv.read_uint32_digital(&AsynUser::new(u32_idx).with_addr(0), 0xFFFF_FFFF),
2113 Err(AsynError::ParamUndefined(_))
2114 ));
2115
2116 drv.base_mut().params.set_int32(i32_idx, 0, 7).unwrap();
2118 drv.base_mut().params.set_int64(i64_idx, 0, 9).unwrap();
2119 drv.base_mut().params.set_float64(f64_idx, 0, 1.5).unwrap();
2120 drv.base_mut()
2121 .params
2122 .set_string(oct_idx, 0, "hi".to_string())
2123 .unwrap();
2124 drv.base_mut()
2125 .params
2126 .set_uint32(u32_idx, 0, 0x05, 0xFFFF_FFFF, 0)
2127 .unwrap();
2128
2129 assert_eq!(
2130 drv.read_int32(&AsynUser::new(i32_idx).with_addr(0))
2131 .unwrap(),
2132 7
2133 );
2134 assert_eq!(
2135 drv.read_int64(&AsynUser::new(i64_idx).with_addr(0))
2136 .unwrap(),
2137 9
2138 );
2139 assert_eq!(
2140 drv.read_float64(&AsynUser::new(f64_idx).with_addr(0))
2141 .unwrap(),
2142 1.5
2143 );
2144 let n = drv
2145 .read_octet(&AsynUser::new(oct_idx).with_addr(0), &mut buf)
2146 .unwrap();
2147 assert_eq!(&buf[..n], b"hi");
2148 assert_eq!(
2149 drv.read_uint32_digital(&AsynUser::new(u32_idx).with_addr(0), 0xFFFF_FFFF)
2150 .unwrap(),
2151 0x05
2152 );
2153 }
2154}