1use std::collections::HashMap;
17use std::sync::Arc;
18use std::time::{Duration, Instant, SystemTime};
19
20use std::any::Any;
21
22const AUTO_CONNECT_THROTTLE: Duration = Duration::from_secs(2);
28
29#[derive(Debug, Clone)]
31pub struct DeviceState {
32 pub connected: bool,
33 pub enabled: bool,
34 pub auto_connect: bool,
35 pub last_connect_disconnect: Option<Instant>,
41}
42
43impl Default for DeviceState {
44 fn default() -> Self {
45 Self {
46 connected: true,
47 enabled: true,
48 auto_connect: true,
49 last_connect_disconnect: None,
50 }
51 }
52}
53
54use crate::error::{AsynError, AsynResult, AsynStatus};
55use crate::exception::{AsynException, ExceptionEvent, ExceptionManager};
56use crate::interfaces::InterfaceType;
57use crate::interpose::{EomReason, OctetInterpose, OctetInterposeStack};
58use crate::interrupt::{InterruptManager, InterruptValue};
59use crate::param::{EnumEntry, InterruptReason, ParamList, ParamType, ParamValue};
60use crate::trace::TraceManager;
61use crate::user::AsynUser;
62
63#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
67pub enum QueuePriority {
68 Low = 0,
69 #[default]
70 Medium = 1,
71 High = 2,
72 Connect = 3,
74}
75
76#[derive(Debug, Clone, Copy)]
78pub struct PortFlags {
79 pub multi_device: bool,
81 pub can_block: bool,
90 pub destructible: bool,
92}
93
94impl Default for PortFlags {
95 fn default() -> Self {
96 Self {
104 multi_device: false,
105 can_block: false,
106 destructible: false,
107 }
108 }
109}
110
111pub struct PortDriverBase {
123 pub port_name: String,
124 pub max_addr: usize,
125 pub flags: PortFlags,
126 pub params: ParamList,
127 pub interrupts: InterruptManager,
128 pub connected: bool,
129 pub enabled: bool,
130 pub auto_connect: bool,
131 pub defunct: bool,
137 pub exception_sink: Option<Arc<ExceptionManager>>,
139 pub options: HashMap<String, String>,
140 pub input_eos: Vec<u8>,
142 pub output_eos: Vec<u8>,
144 pub interpose_octet: OctetInterposeStack,
145 pub trace: Option<Arc<TraceManager>>,
146 pub device_states: HashMap<i32, DeviceState>,
148 pub timestamp_source: Option<Arc<dyn Fn() -> SystemTime + Send + Sync>>,
150 pub last_connect_disconnect: Option<Instant>,
155}
156
157impl PortDriverBase {
158 pub fn new(port_name: &str, max_addr: usize, flags: PortFlags) -> Self {
159 Self {
160 port_name: port_name.to_string(),
161 max_addr: max_addr.max(1),
162 flags,
163 params: ParamList::new(max_addr, flags.multi_device),
164 interrupts: InterruptManager::new(256),
165 connected: true,
166 enabled: true,
167 auto_connect: true,
168 defunct: false,
169 exception_sink: None,
170 options: HashMap::new(),
171 input_eos: Vec::new(),
172 output_eos: Vec::new(),
173 interpose_octet: OctetInterposeStack::new(),
174 trace: None,
175 device_states: HashMap::new(),
176 timestamp_source: None,
177 last_connect_disconnect: None,
178 }
179 }
180
181 pub fn announce_exception(&self, exception: AsynException, addr: i32) {
183 if let Some(ref sink) = self.exception_sink {
184 sink.announce(&ExceptionEvent {
185 port_name: self.port_name.clone(),
186 exception,
187 addr,
188 });
189 }
190 }
191
192 pub fn is_connected(&self) -> bool {
194 self.connected
195 }
196
197 pub fn set_connected(&mut self, connected: bool) -> bool {
211 if self.connected == connected {
212 return false;
213 }
214 self.connected = connected;
215 if !connected {
216 self.last_connect_disconnect = Some(Instant::now());
220 }
221 self.announce_exception(AsynException::Connect, -1);
222 true
223 }
224
225 pub fn set_addr_connected(&mut self, addr: i32, connected: bool) -> bool {
228 let was = self.device_state(addr).connected;
229 if was == connected {
230 return false;
231 }
232 self.device_state(addr).connected = connected;
233 if !connected {
234 self.device_state(addr).last_connect_disconnect = Some(Instant::now());
237 }
238 self.announce_exception(AsynException::Connect, addr);
239 true
240 }
241
242 pub fn auto_connect_throttle_ok(&self, addr: i32, now: Instant) -> bool {
260 let last = if self.flags.multi_device {
261 self.device_states
262 .get(&addr)
263 .and_then(|d| d.last_connect_disconnect)
264 } else {
265 self.last_connect_disconnect
266 };
267 match last {
268 None => true,
269 Some(t) => now.saturating_duration_since(t) >= AUTO_CONNECT_THROTTLE,
270 }
271 }
272
273 pub fn stamp_auto_connect_attempt(&mut self, addr: i32, now: Instant) {
279 if self.flags.multi_device {
280 self.device_state(addr).last_connect_disconnect = Some(now);
281 } else {
282 self.last_connect_disconnect = Some(now);
283 }
284 }
285
286 pub fn is_enabled(&self) -> bool {
288 self.enabled
289 }
290
291 pub fn set_enabled(&mut self, enabled: bool) -> AsynResult<()> {
303 if self.defunct {
304 return Err(AsynError::Status {
305 status: AsynStatus::Disabled,
306 message: format!("port {} has been shut down (defunct)", self.port_name),
307 });
308 }
309 self.enabled = enabled;
310 self.announce_exception(AsynException::Enable, -1);
311 Ok(())
312 }
313
314 pub fn set_addr_enabled(&mut self, addr: i32, enabled: bool) -> AsynResult<()> {
319 if self.defunct {
320 return Err(AsynError::Status {
321 status: AsynStatus::Disabled,
322 message: format!("port {} has been shut down (defunct)", self.port_name),
323 });
324 }
325 self.device_state(addr).enabled = enabled;
326 self.announce_exception(AsynException::Enable, addr);
327 Ok(())
328 }
329
330 pub fn is_auto_connect(&self) -> bool {
332 self.auto_connect
333 }
334
335 pub fn set_auto_connect(&mut self, yes: bool) {
344 self.auto_connect = yes;
345 self.announce_exception(AsynException::AutoConnect, -1);
346 }
347
348 pub fn set_auto_connect_addr(&mut self, addr: i32, yes: bool) {
353 self.device_state(addr).auto_connect = yes;
354 self.announce_exception(AsynException::AutoConnect, addr);
355 }
356
357 pub fn is_defunct(&self) -> bool {
361 self.defunct
362 }
363
364 pub fn check_ready(&self) -> AsynResult<()> {
368 if self.defunct {
373 return Err(AsynError::Status {
374 status: AsynStatus::Disabled,
375 message: format!("port {} has been shut down (defunct)", self.port_name),
376 });
377 }
378 if !self.enabled {
379 return Err(AsynError::Status {
380 status: AsynStatus::Disabled,
381 message: format!("port {} is disabled", self.port_name),
382 });
383 }
384 if !self.connected {
385 return Err(AsynError::Status {
386 status: AsynStatus::Disconnected,
387 message: format!("port {} is disconnected", self.port_name),
388 });
389 }
390 Ok(())
391 }
392
393 pub fn shutdown_lifecycle(&mut self) -> AsynResult<()> {
409 if self.defunct {
410 return Ok(());
412 }
413 if !self.flags.destructible {
414 return Err(AsynError::Status {
415 status: AsynStatus::Error,
416 message: format!(
417 "port {} does not support shutting down (ASYN_DESTRUCTIBLE not set)",
418 self.port_name
419 ),
420 });
421 }
422 self.enabled = false;
423 self.defunct = true;
424 self.announce_exception(AsynException::Shutdown, -1);
425 Ok(())
426 }
427
428 pub fn check_ready_addr(&self, addr: i32) -> AsynResult<()> {
431 self.check_ready()?;
432 if self.flags.multi_device {
433 if let Some(ds) = self.device_states.get(&addr) {
434 if !ds.enabled {
435 return Err(AsynError::Status {
436 status: AsynStatus::Disabled,
437 message: format!("port {} addr {} is disabled", self.port_name, addr),
438 });
439 }
440 if !ds.connected {
441 return Err(AsynError::Status {
442 status: AsynStatus::Disconnected,
443 message: format!("port {} addr {} is disconnected", self.port_name, addr),
444 });
445 }
446 }
447 }
448 Ok(())
449 }
450
451 pub fn device_state(&mut self, addr: i32) -> &mut DeviceState {
453 self.device_states.entry(addr).or_default()
454 }
455
456 pub fn is_device_connected(&self, addr: i32) -> bool {
458 self.device_states
459 .get(&addr)
460 .map_or(true, |ds| ds.connected)
461 }
462
463 pub fn connect_addr(&mut self, addr: i32) {
473 self.set_addr_connected(addr, true);
474 }
475
476 pub fn disconnect_addr(&mut self, addr: i32) {
482 self.set_addr_connected(addr, false);
483 }
484
485 pub fn enable_addr(&mut self, addr: i32) {
488 let _ = self.set_addr_enabled(addr, true);
489 }
490
491 pub fn disable_addr(&mut self, addr: i32) {
494 let _ = self.set_addr_enabled(addr, false);
495 }
496
497 pub fn register_timestamp_source<F>(&mut self, source: F)
499 where
500 F: Fn() -> SystemTime + Send + Sync + 'static,
501 {
502 self.timestamp_source = Some(Arc::new(source));
503 }
504
505 pub fn current_timestamp(&self) -> SystemTime {
507 self.timestamp_source
508 .as_ref()
509 .map_or_else(SystemTime::now, |f| f())
510 }
511
512 pub fn create_param(&mut self, name: &str, param_type: ParamType) -> AsynResult<usize> {
513 self.params.create_param(name, param_type)
514 }
515
516 pub fn find_param(&self, name: &str) -> Option<usize> {
517 self.params.find_param(name)
518 }
519
520 pub fn set_int32_param(&mut self, index: usize, addr: i32, value: i32) -> AsynResult<()> {
523 self.params.set_int32(index, addr, value)
524 }
525
526 pub fn get_int32_param(&self, index: usize, addr: i32) -> AsynResult<i32> {
527 self.params.get_int32(index, addr)
528 }
529
530 pub fn get_int32_param_strict(&self, index: usize, addr: i32) -> AsynResult<i32> {
534 self.params.get_int32_strict(index, addr)
535 }
536
537 pub fn set_int64_param(&mut self, index: usize, addr: i32, value: i64) -> AsynResult<()> {
538 self.params.set_int64(index, addr, value)
539 }
540
541 pub fn get_int64_param(&self, index: usize, addr: i32) -> AsynResult<i64> {
542 self.params.get_int64(index, addr)
543 }
544
545 pub fn get_int64_param_strict(&self, index: usize, addr: i32) -> AsynResult<i64> {
547 self.params.get_int64_strict(index, addr)
548 }
549
550 pub fn set_float64_param(&mut self, index: usize, addr: i32, value: f64) -> AsynResult<()> {
551 self.params.set_float64(index, addr, value)
552 }
553
554 pub fn get_float64_param(&self, index: usize, addr: i32) -> AsynResult<f64> {
555 self.params.get_float64(index, addr)
556 }
557
558 pub fn get_float64_param_strict(&self, index: usize, addr: i32) -> AsynResult<f64> {
560 self.params.get_float64_strict(index, addr)
561 }
562
563 pub fn set_string_param(&mut self, index: usize, addr: i32, value: String) -> AsynResult<()> {
564 self.params.set_string(index, addr, value)
565 }
566
567 pub fn get_string_param(&self, index: usize, addr: i32) -> AsynResult<&str> {
568 self.params.get_string(index, addr)
569 }
570
571 pub fn get_string_param_strict(&self, index: usize, addr: i32) -> AsynResult<&str> {
573 self.params.get_string_strict(index, addr)
574 }
575
576 pub fn set_uint32_param(
582 &mut self,
583 index: usize,
584 addr: i32,
585 value: u32,
586 mask: u32,
587 interrupt_mask: u32,
588 ) -> AsynResult<()> {
589 self.params
590 .set_uint32(index, addr, value, mask, interrupt_mask)
591 }
592
593 pub fn get_uint32_param(&self, index: usize, addr: i32) -> AsynResult<u32> {
594 self.params.get_uint32(index, addr)
595 }
596
597 pub fn get_uint32_param_strict(&self, index: usize, addr: i32) -> AsynResult<u32> {
599 self.params.get_uint32_strict(index, addr)
600 }
601
602 pub fn get_enum_param(&self, index: usize, addr: i32) -> AsynResult<(usize, Arc<[EnumEntry]>)> {
603 self.params.get_enum(index, addr)
604 }
605
606 pub fn set_enum_index_param(
607 &mut self,
608 index: usize,
609 addr: i32,
610 value: usize,
611 ) -> AsynResult<()> {
612 self.params.set_enum_index(index, addr, value)
613 }
614
615 pub fn set_enum_choices_param(
616 &mut self,
617 index: usize,
618 addr: i32,
619 choices: Arc<[EnumEntry]>,
620 ) -> AsynResult<()> {
621 self.params.set_enum_choices(index, addr, choices)
622 }
623
624 pub fn get_generic_pointer_param(
625 &self,
626 index: usize,
627 addr: i32,
628 ) -> AsynResult<Arc<dyn Any + Send + Sync>> {
629 self.params.get_generic_pointer(index, addr)
630 }
631
632 pub fn set_generic_pointer_param(
633 &mut self,
634 index: usize,
635 addr: i32,
636 value: Arc<dyn Any + Send + Sync>,
637 ) -> AsynResult<()> {
638 self.params.set_generic_pointer(index, addr, value)
639 }
640
641 pub fn set_param_timestamp(
642 &mut self,
643 index: usize,
644 addr: i32,
645 ts: SystemTime,
646 ) -> AsynResult<()> {
647 self.params.set_timestamp(index, addr, ts)
648 }
649
650 pub fn set_param_status(
651 &mut self,
652 index: usize,
653 addr: i32,
654 status: AsynStatus,
655 alarm_status: u16,
656 alarm_severity: u16,
657 ) -> AsynResult<()> {
658 self.params
659 .set_param_status(index, addr, status, alarm_status, alarm_severity)
660 }
661
662 pub fn get_param_status(&self, index: usize, addr: i32) -> AsynResult<(AsynStatus, u16, u16)> {
663 self.params.get_param_status(index, addr)
664 }
665
666 pub fn report_params(&self, level: i32) {
668 eprintln!(" Number of parameters is {}", self.params.len());
669 if level < 1 {
670 return;
671 }
672 for i in 0..self.params.len() {
673 let name = self.params.param_name(i).unwrap_or("?");
674 let ptype = self
675 .params
676 .param_type(i)
677 .map(|t| format!("{t:?}"))
678 .unwrap_or("?".into());
679 if level >= 2 {
680 for addr in 0..self.max_addr.max(1) {
681 let val = self
682 .params
683 .get_value(i, addr as i32)
684 .map(|v| format!("{v:?}"))
685 .unwrap_or("undefined".into());
686 let (status, alarm_st, alarm_sev) = self
687 .params
688 .get_param_status(i, addr as i32)
689 .unwrap_or((AsynStatus::Success, 0, 0));
690 eprintln!(
691 " param[{i}] name={name} type={ptype} addr={addr} val={val} status={status:?} alarm=({alarm_st},{alarm_sev})"
692 );
693 }
694 } else {
695 eprintln!(" param[{i}] name={name} type={ptype}");
696 }
697 }
698 }
699
700 pub fn push_octet_interpose(&mut self, layer: Box<dyn OctetInterpose>) {
706 self.interpose_octet.push(layer);
707 }
708
709 pub fn call_param_callbacks(&mut self, addr: i32) -> AsynResult<()> {
712 let changed = self.params.take_changed(addr)?;
713 let now = self.current_timestamp();
714 for reason in changed {
715 let value = self.params.get_value(reason, addr)?.clone();
716 if !value.is_array() && !self.params.is_param_defined(reason, addr).unwrap_or(false) {
724 continue;
725 }
726 let ts = self.params.get_timestamp(reason, addr)?.unwrap_or(now);
727 let uint32_mask = self
732 .params
733 .take_uint32_interrupt_mask(reason, addr)
734 .unwrap_or(0);
735 let (aux_status, alarm_status, alarm_severity) = self
741 .params
742 .get_param_status(reason, addr)
743 .unwrap_or((AsynStatus::Success, 0, 0));
744 self.interrupts.notify(InterruptValue {
745 reason,
746 addr,
747 value,
748 timestamp: ts,
749 uint32_changed_mask: uint32_mask,
750 aux_status,
751 alarm_status,
752 alarm_severity,
753 iface: None,
756 });
757 }
758 Ok(())
759 }
760
761 pub fn call_param_callback(&mut self, addr: i32, reason: usize) -> AsynResult<()> {
765 if self.params.take_changed_single(reason, addr)? {
766 let value = self.params.get_value(reason, addr)?.clone();
767 if !value.is_array() && !self.params.is_param_defined(reason, addr).unwrap_or(false) {
771 return Ok(());
772 }
773 let now = self.current_timestamp();
774 let ts = self.params.get_timestamp(reason, addr)?.unwrap_or(now);
775 let uint32_mask = self
780 .params
781 .take_uint32_interrupt_mask(reason, addr)
782 .unwrap_or(0);
783 let (aux_status, alarm_status, alarm_severity) = self
785 .params
786 .get_param_status(reason, addr)
787 .unwrap_or((AsynStatus::Success, 0, 0));
788 self.interrupts.notify(InterruptValue {
789 reason,
790 addr,
791 value,
792 timestamp: ts,
793 uint32_changed_mask: uint32_mask,
794 aux_status,
795 alarm_status,
796 alarm_severity,
797 iface: None,
799 });
800 }
801 Ok(())
802 }
803
804 pub fn mark_param_changed(&mut self, index: usize, addr: i32) -> AsynResult<()> {
809 self.params.mark_changed(index, addr)
810 }
811
812 pub fn notify_interface_value(
831 &self,
832 reason: usize,
833 addr: i32,
834 iface: InterfaceType,
835 value: ParamValue,
836 uint32_changed_mask: u32,
837 ) {
838 let ts = self.current_timestamp();
839 self.interrupts.notify(InterruptValue {
840 reason,
841 addr,
842 value,
843 timestamp: ts,
844 uint32_changed_mask,
845 aux_status: AsynStatus::Success,
849 alarm_status: 0,
850 alarm_severity: 0,
851 iface: Some(iface),
852 });
853 }
854}
855
856#[derive(Debug, Default)]
864pub struct DrvUserInfo {
865 pub reason: usize,
867 pub max_octet_len: Option<usize>,
873}
874
875impl DrvUserInfo {
876 pub fn from_reason(reason: usize) -> Self {
879 Self {
880 reason,
881 ..Self::default()
882 }
883 }
884}
885
886pub trait PortDriver: Send + Sync + 'static {
901 fn base(&self) -> &PortDriverBase;
902 fn base_mut(&mut self) -> &mut PortDriverBase;
903
904 fn connect(&mut self, _user: &AsynUser) -> AsynResult<()> {
907 self.base_mut().set_connected(true);
909 Ok(())
910 }
911
912 fn disconnect(&mut self, _user: &AsynUser) -> AsynResult<()> {
913 self.base_mut().set_connected(false);
914 Ok(())
915 }
916
917 fn enable(&mut self, _user: &AsynUser) -> AsynResult<()> {
918 self.base_mut().set_enabled(true)
921 }
922
923 fn disable(&mut self, _user: &AsynUser) -> AsynResult<()> {
924 self.base_mut().set_enabled(false)
925 }
926
927 fn connect_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
928 self.base_mut().connect_addr(user.addr);
929 Ok(())
930 }
931
932 fn disconnect_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
933 self.base_mut().disconnect_addr(user.addr);
934 Ok(())
935 }
936
937 fn enable_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
938 self.base_mut().set_addr_enabled(user.addr, true)
940 }
941
942 fn disable_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
943 self.base_mut().set_addr_enabled(user.addr, false)
944 }
945
946 fn get_option(&self, key: &str) -> AsynResult<String> {
947 self.base()
948 .options
949 .get(key)
950 .cloned()
951 .ok_or_else(|| AsynError::OptionNotFound(key.to_string()))
952 }
953
954 fn set_option(&mut self, key: &str, value: &str) -> AsynResult<()> {
955 self.base_mut()
956 .options
957 .insert(key.to_string(), value.to_string());
958 Ok(())
959 }
960
961 fn report(&self, level: i32) {
962 let base = self.base();
963 eprintln!("Port: {}", base.port_name);
964 eprintln!(
965 " connected: {}, max_addr: {}, params: {}, options: {}",
966 base.connected,
967 base.max_addr,
968 base.params.len(),
969 base.options.len()
970 );
971 if level >= 1 {
972 base.report_params(level.saturating_sub(1));
973 }
974 if level >= 2 {
975 for (k, v) in &base.options {
976 eprintln!(" option: {k} = {v}");
977 }
978 }
979 }
980
981 fn read_int32(&mut self, user: &AsynUser) -> AsynResult<i32> {
1000 self.base().params.get_int32_strict(user.reason, user.addr)
1001 }
1002
1003 fn write_int32(&mut self, user: &mut AsynUser, value: i32) -> AsynResult<()> {
1004 self.base_mut()
1005 .params
1006 .set_int32(user.reason, user.addr, value)?;
1007 self.base_mut().call_param_callbacks(user.addr)
1008 }
1009
1010 fn read_int64(&mut self, user: &AsynUser) -> AsynResult<i64> {
1011 self.base().params.get_int64_strict(user.reason, user.addr)
1012 }
1013
1014 fn write_int64(&mut self, user: &mut AsynUser, value: i64) -> AsynResult<()> {
1015 self.base_mut()
1016 .params
1017 .set_int64(user.reason, user.addr, value)?;
1018 self.base_mut().call_param_callbacks(user.addr)
1019 }
1020
1021 fn get_bounds_int32(&self, _user: &AsynUser) -> AsynResult<(i32, i32)> {
1025 Ok((0, 0))
1026 }
1027
1028 fn get_bounds_int64(&self, _user: &AsynUser) -> AsynResult<(i64, i64)> {
1031 Ok((0, 0))
1032 }
1033
1034 fn read_float64(&mut self, user: &AsynUser) -> AsynResult<f64> {
1035 self.base()
1036 .params
1037 .get_float64_strict(user.reason, user.addr)
1038 }
1039
1040 fn write_float64(&mut self, user: &mut AsynUser, value: f64) -> AsynResult<()> {
1041 self.base_mut()
1042 .params
1043 .set_float64(user.reason, user.addr, value)?;
1044 self.base_mut().call_param_callbacks(user.addr)
1045 }
1046
1047 fn read_octet(&mut self, user: &AsynUser, buf: &mut [u8]) -> AsynResult<usize> {
1048 let s = self
1049 .base()
1050 .params
1051 .get_string_strict(user.reason, user.addr)?;
1052 let bytes = s.as_bytes();
1053 let n = bytes.len().min(buf.len());
1054 buf[..n].copy_from_slice(&bytes[..n]);
1055 Ok(n)
1056 }
1057
1058 fn write_octet(&mut self, user: &mut AsynUser, data: &[u8]) -> AsynResult<usize> {
1059 let s = String::from_utf8_lossy(data).into_owned();
1060 self.base_mut()
1061 .params
1062 .set_string(user.reason, user.addr, s)?;
1063 self.base_mut().call_param_callbacks(user.addr)?;
1064 Ok(data.len())
1065 }
1066
1067 fn read_uint32_digital(&mut self, user: &AsynUser, mask: u32) -> AsynResult<u32> {
1068 let val = self
1069 .base()
1070 .params
1071 .get_uint32_strict(user.reason, user.addr)?;
1072 Ok(val & mask)
1073 }
1074
1075 fn write_uint32_digital(
1076 &mut self,
1077 user: &mut AsynUser,
1078 value: u32,
1079 mask: u32,
1080 ) -> AsynResult<()> {
1081 self.base_mut()
1084 .params
1085 .set_uint32(user.reason, user.addr, value, mask, 0)?;
1086 self.base_mut().call_param_callbacks(user.addr)
1087 }
1088
1089 fn set_interrupt_uint32_digital(
1098 &mut self,
1099 user: &AsynUser,
1100 mask: u32,
1101 reason: InterruptReason,
1102 ) -> AsynResult<()> {
1103 self.base_mut()
1104 .params
1105 .set_uint32_interrupt(user.reason, user.addr, mask, reason)
1106 }
1107
1108 fn clear_interrupt_uint32_digital(&mut self, user: &AsynUser, mask: u32) -> AsynResult<()> {
1113 self.base_mut()
1114 .params
1115 .clear_uint32_interrupt(user.reason, user.addr, mask)
1116 }
1117
1118 fn get_interrupt_uint32_digital(
1122 &self,
1123 user: &AsynUser,
1124 reason: InterruptReason,
1125 ) -> AsynResult<u32> {
1126 self.base()
1127 .params
1128 .get_uint32_interrupt(user.reason, user.addr, reason)
1129 }
1130
1131 fn read_enum(&mut self, user: &AsynUser) -> AsynResult<(usize, Arc<[EnumEntry]>)> {
1134 self.base().params.get_enum(user.reason, user.addr)
1135 }
1136
1137 fn write_enum(&mut self, user: &mut AsynUser, index: usize) -> AsynResult<()> {
1138 self.base_mut()
1139 .params
1140 .set_enum_index(user.reason, user.addr, index)?;
1141 self.base_mut().call_param_callbacks(user.addr)
1142 }
1143
1144 fn write_enum_choices(
1145 &mut self,
1146 user: &mut AsynUser,
1147 choices: Arc<[EnumEntry]>,
1148 ) -> AsynResult<()> {
1149 self.base_mut()
1150 .params
1151 .set_enum_choices(user.reason, user.addr, choices)?;
1152 self.base_mut().call_param_callbacks(user.addr)
1153 }
1154
1155 fn read_generic_pointer(&mut self, user: &AsynUser) -> AsynResult<Arc<dyn Any + Send + Sync>> {
1158 self.base()
1159 .params
1160 .get_generic_pointer(user.reason, user.addr)
1161 }
1162
1163 fn write_generic_pointer(
1164 &mut self,
1165 user: &mut AsynUser,
1166 value: Arc<dyn Any + Send + Sync>,
1167 ) -> AsynResult<()> {
1168 self.base_mut()
1169 .params
1170 .set_generic_pointer(user.reason, user.addr, value)?;
1171 self.base_mut().call_param_callbacks(user.addr)
1172 }
1173
1174 fn read_float64_array(&mut self, _user: &AsynUser, _buf: &mut [f64]) -> AsynResult<usize> {
1177 Err(AsynError::InterfaceNotSupported("asynFloat64Array".into()))
1178 }
1179
1180 fn write_float64_array(&mut self, user: &AsynUser, data: &[f64]) -> AsynResult<()> {
1181 self.base_mut()
1182 .params
1183 .set_float64_array(user.reason, user.addr, data.to_vec())?;
1184 self.base_mut().call_param_callbacks(user.addr)
1185 }
1186
1187 fn read_int32_array(&mut self, _user: &AsynUser, _buf: &mut [i32]) -> AsynResult<usize> {
1188 Err(AsynError::InterfaceNotSupported("asynInt32Array".into()))
1189 }
1190
1191 fn write_int32_array(&mut self, user: &AsynUser, data: &[i32]) -> AsynResult<()> {
1192 self.base_mut()
1193 .params
1194 .set_int32_array(user.reason, user.addr, data.to_vec())?;
1195 self.base_mut().call_param_callbacks(user.addr)
1196 }
1197
1198 fn read_int8_array(&mut self, _user: &AsynUser, _buf: &mut [i8]) -> AsynResult<usize> {
1199 Err(AsynError::InterfaceNotSupported("asynInt8Array".into()))
1200 }
1201
1202 fn write_int8_array(&mut self, user: &AsynUser, data: &[i8]) -> AsynResult<()> {
1203 self.base_mut()
1204 .params
1205 .set_int8_array(user.reason, user.addr, data.to_vec())?;
1206 self.base_mut().call_param_callbacks(user.addr)
1207 }
1208
1209 fn read_int16_array(&mut self, _user: &AsynUser, _buf: &mut [i16]) -> AsynResult<usize> {
1210 Err(AsynError::InterfaceNotSupported("asynInt16Array".into()))
1211 }
1212
1213 fn write_int16_array(&mut self, user: &AsynUser, data: &[i16]) -> AsynResult<()> {
1214 self.base_mut()
1215 .params
1216 .set_int16_array(user.reason, user.addr, data.to_vec())?;
1217 self.base_mut().call_param_callbacks(user.addr)
1218 }
1219
1220 fn read_int64_array(&mut self, _user: &AsynUser, _buf: &mut [i64]) -> AsynResult<usize> {
1221 Err(AsynError::InterfaceNotSupported("asynInt64Array".into()))
1222 }
1223
1224 fn write_int64_array(&mut self, user: &AsynUser, data: &[i64]) -> AsynResult<()> {
1225 self.base_mut()
1226 .params
1227 .set_int64_array(user.reason, user.addr, data.to_vec())?;
1228 self.base_mut().call_param_callbacks(user.addr)
1229 }
1230
1231 fn read_float32_array(&mut self, _user: &AsynUser, _buf: &mut [f32]) -> AsynResult<usize> {
1232 Err(AsynError::InterfaceNotSupported("asynFloat32Array".into()))
1233 }
1234
1235 fn write_float32_array(&mut self, user: &AsynUser, data: &[f32]) -> AsynResult<()> {
1236 self.base_mut()
1237 .params
1238 .set_float32_array(user.reason, user.addr, data.to_vec())?;
1239 self.base_mut().call_param_callbacks(user.addr)
1240 }
1241
1242 fn io_read_octet(&mut self, user: &AsynUser, buf: &mut [u8]) -> AsynResult<usize> {
1247 self.read_octet(user, buf)
1248 }
1249
1250 fn io_read_octet_eom(
1260 &mut self,
1261 user: &AsynUser,
1262 buf: &mut [u8],
1263 ) -> AsynResult<(usize, EomReason)> {
1264 let cap = buf.len();
1265 let n = self.io_read_octet(user, buf)?;
1266 let eom = if n >= cap && cap > 0 {
1267 EomReason::CNT
1268 } else {
1269 EomReason::empty()
1270 };
1271 Ok((n, eom))
1272 }
1273
1274 fn io_write_octet(&mut self, user: &mut AsynUser, data: &[u8]) -> AsynResult<usize> {
1275 self.write_octet(user, data)
1276 }
1277
1278 fn io_read_int32(&mut self, user: &AsynUser) -> AsynResult<i32> {
1279 self.read_int32(user)
1280 }
1281
1282 fn io_write_int32(&mut self, user: &mut AsynUser, value: i32) -> AsynResult<()> {
1283 self.write_int32(user, value)
1284 }
1285
1286 fn io_read_int64(&mut self, user: &AsynUser) -> AsynResult<i64> {
1287 self.read_int64(user)
1288 }
1289
1290 fn io_write_int64(&mut self, user: &mut AsynUser, value: i64) -> AsynResult<()> {
1291 self.write_int64(user, value)
1292 }
1293
1294 fn io_read_float64(&mut self, user: &AsynUser) -> AsynResult<f64> {
1295 self.read_float64(user)
1296 }
1297
1298 fn io_write_float64(&mut self, user: &mut AsynUser, value: f64) -> AsynResult<()> {
1299 self.write_float64(user, value)
1300 }
1301
1302 fn io_read_uint32_digital(&mut self, user: &AsynUser, mask: u32) -> AsynResult<u32> {
1303 self.read_uint32_digital(user, mask)
1304 }
1305
1306 fn io_write_uint32_digital(
1307 &mut self,
1308 user: &mut AsynUser,
1309 value: u32,
1310 mask: u32,
1311 ) -> AsynResult<()> {
1312 self.write_uint32_digital(user, value, mask)
1313 }
1314
1315 fn io_flush(&mut self, _user: &mut AsynUser) -> AsynResult<()> {
1316 Ok(())
1317 }
1318
1319 fn set_input_eos(&mut self, eos: &[u8]) -> AsynResult<()> {
1345 if eos.len() > 2 {
1346 return Err(AsynError::Status {
1347 status: AsynStatus::Error,
1348 message: format!("illegal eoslen {}", eos.len()),
1349 });
1350 }
1351 let base = self.base_mut();
1357 base.input_eos = eos.to_vec();
1358 base.interpose_octet.set_input_eos(eos);
1359 Ok(())
1360 }
1361
1362 fn get_input_eos(&self) -> Vec<u8> {
1363 self.base().input_eos.clone()
1364 }
1365
1366 fn set_output_eos(&mut self, eos: &[u8]) -> AsynResult<()> {
1367 if eos.len() > 2 {
1368 return Err(AsynError::Status {
1369 status: AsynStatus::Error,
1370 message: format!("illegal eoslen {}", eos.len()),
1371 });
1372 }
1373 let base = self.base_mut();
1377 base.output_eos = eos.to_vec();
1378 base.interpose_octet.set_output_eos(eos);
1379 Ok(())
1380 }
1381
1382 fn get_output_eos(&self) -> Vec<u8> {
1383 self.base().output_eos.clone()
1384 }
1385
1386 fn shutdown(&mut self) -> AsynResult<()> {
1391 Ok(())
1392 }
1393
1394 fn drv_user_create(&mut self, drv_info: &str, _addr: i32) -> AsynResult<DrvUserInfo> {
1407 let reason = self
1408 .base()
1409 .params
1410 .find_param(drv_info)
1411 .ok_or_else(|| AsynError::ParamNotFound(drv_info.to_string()))?;
1412 Ok(DrvUserInfo::from_reason(reason))
1413 }
1414
1415 fn capabilities(&self) -> Vec<crate::interfaces::Capability> {
1420 crate::interfaces::default_capabilities()
1421 }
1422
1423 fn supports(&self, cap: crate::interfaces::Capability) -> bool {
1425 self.capabilities().contains(&cap)
1426 }
1427
1428 fn init(&mut self) -> AsynResult<()> {
1429 Ok(())
1430 }
1431}
1432
1433#[cfg(test)]
1434mod tests {
1435 use super::*;
1436 struct TestDriver {
1437 base: PortDriverBase,
1438 }
1439
1440 impl TestDriver {
1441 fn new() -> Self {
1442 let mut base = PortDriverBase::new("test", 1, PortFlags::default());
1443 base.create_param("VAL", ParamType::Int32).unwrap();
1444 base.create_param("TEMP", ParamType::Float64).unwrap();
1445 base.create_param("MSG", ParamType::Octet).unwrap();
1446 base.create_param("BITS", ParamType::UInt32Digital).unwrap();
1447 Self { base }
1448 }
1449 }
1450
1451 impl PortDriver for TestDriver {
1452 fn base(&self) -> &PortDriverBase {
1453 &self.base
1454 }
1455 fn base_mut(&mut self) -> &mut PortDriverBase {
1456 &mut self.base
1457 }
1458 }
1459
1460 #[test]
1461 fn test_default_read_write_int32() {
1462 let mut drv = TestDriver::new();
1463 let mut user = AsynUser::new(0);
1464 drv.write_int32(&mut user, 42).unwrap();
1465 let user = AsynUser::new(0);
1466 assert_eq!(drv.read_int32(&user).unwrap(), 42);
1467 }
1468
1469 #[test]
1470 fn test_default_read_write_float64() {
1471 let mut drv = TestDriver::new();
1472 let mut user = AsynUser::new(1);
1473 drv.write_float64(&mut user, 3.14).unwrap();
1474 let user = AsynUser::new(1);
1475 assert!((drv.read_float64(&user).unwrap() - 3.14).abs() < 1e-10);
1476 }
1477
1478 #[test]
1479 fn test_default_read_write_octet() {
1480 let mut drv = TestDriver::new();
1481 let mut user = AsynUser::new(2);
1482 drv.write_octet(&mut user, b"hello").unwrap();
1483 let user = AsynUser::new(2);
1484 let mut buf = [0u8; 32];
1485 let n = drv.read_octet(&user, &mut buf).unwrap();
1486 assert_eq!(&buf[..n], b"hello");
1487 }
1488
1489 #[test]
1490 fn test_default_read_write_uint32() {
1491 let mut drv = TestDriver::new();
1492 let mut user = AsynUser::new(3);
1493 drv.write_uint32_digital(&mut user, 0xFF, 0x0F).unwrap();
1494 let user = AsynUser::new(3);
1495 assert_eq!(drv.read_uint32_digital(&user, 0xFF).unwrap(), 0x0F);
1496 }
1497
1498 #[test]
1499 fn test_connect_disconnect() {
1500 let mut drv = TestDriver::new();
1501 let user = AsynUser::default();
1502 assert!(drv.base().connected);
1503 drv.disconnect(&user).unwrap();
1504 assert!(!drv.base().connected);
1505 drv.connect(&user).unwrap();
1506 assert!(drv.base().connected);
1507 }
1508
1509 #[test]
1510 fn test_drv_user_create() {
1511 let mut drv = TestDriver::new();
1512 assert_eq!(drv.drv_user_create("VAL", 0).unwrap().reason, 0);
1513 assert_eq!(drv.drv_user_create("TEMP", 0).unwrap().reason, 1);
1514 assert!(drv.drv_user_create("NOPE", 0).is_err());
1515 }
1516
1517 #[test]
1518 fn test_call_param_callbacks() {
1519 let mut drv = TestDriver::new();
1520 let mut rx = drv.base_mut().interrupts.subscribe_async();
1521
1522 drv.base_mut().set_int32_param(0, 0, 100).unwrap();
1523 drv.base_mut().set_float64_param(1, 0, 2.0).unwrap();
1524 drv.base_mut().call_param_callbacks(0).unwrap();
1525
1526 let v1 = rx.try_recv().unwrap();
1527 assert_eq!(v1.reason, 0);
1528 let v2 = rx.try_recv().unwrap();
1529 assert_eq!(v2.reason, 1);
1530 assert!(rx.try_recv().is_err());
1531 }
1532
1533 #[test]
1534 fn flush_skips_undefined_scalar_but_keeps_array_trigger() {
1535 let mut drv = TestDriver::new();
1541 let arr = drv
1542 .base_mut()
1543 .create_param("ARR", ParamType::Int32Array)
1544 .unwrap();
1545 let mut rx = drv.base_mut().interrupts.subscribe_async();
1546
1547 drv.base_mut()
1550 .params
1551 .set_param_status(0, 0, AsynStatus::Error, 0, 0)
1552 .unwrap();
1553 drv.base_mut().mark_param_changed(arr, 0).unwrap();
1555
1556 drv.base_mut().call_param_callbacks(0).unwrap();
1557
1558 let iv = rx.try_recv().unwrap();
1560 assert_eq!(
1561 iv.reason, arr,
1562 "array trigger must still fire while undefined"
1563 );
1564 assert!(
1565 rx.try_recv().is_err(),
1566 "undefined scalar must not emit an I/O Intr"
1567 );
1568
1569 drv.base_mut().set_int32_param(0, 0, 7).unwrap();
1571 drv.base_mut().call_param_callbacks(0).unwrap();
1572 let iv2 = rx.try_recv().unwrap();
1573 assert_eq!(iv2.reason, 0, "defined scalar must fire");
1574 }
1575
1576 #[test]
1577 fn uint32_callback_mask_does_not_leak_across_flushes() {
1578 let mut drv = TestDriver::new();
1582 let mut rx = drv.base_mut().interrupts.subscribe_async();
1583
1584 drv.base_mut()
1586 .params
1587 .set_uint32(3, 0, 0x01, 0x01, 0)
1588 .unwrap();
1589 drv.base_mut().call_param_callbacks(0).unwrap();
1590 let iv1 = rx.try_recv().unwrap();
1591 assert_eq!(iv1.reason, 3);
1592 assert_eq!(iv1.uint32_changed_mask, 0x01);
1593
1594 drv.base_mut()
1596 .params
1597 .set_uint32(3, 0, 0x02, 0x02, 0)
1598 .unwrap();
1599 drv.base_mut().call_param_callbacks(0).unwrap();
1600 let iv2 = rx.try_recv().unwrap();
1601 assert_eq!(
1602 iv2.uint32_changed_mask, 0x02,
1603 "second flush must not leak flush-1 bits via an un-reset mask"
1604 );
1605 assert_eq!(
1606 drv.base().params.get_uint32_interrupt_mask(3, 0).unwrap(),
1607 0,
1608 "the flush must consume (reset) the callback mask"
1609 );
1610 }
1611
1612 #[test]
1613 fn test_call_param_callbacks_propagates_aux_status_and_alarm() {
1614 let mut drv = TestDriver::new();
1619 let mut rx = drv.base_mut().interrupts.subscribe_async();
1620
1621 drv.base_mut().set_int32_param(0, 0, 99).unwrap();
1622 drv.base_mut()
1623 .params
1624 .set_param_status(0, 0, crate::error::AsynStatus::Timeout, 4, 2)
1625 .unwrap();
1626 drv.base_mut().call_param_callbacks(0).unwrap();
1627
1628 let iv = rx.try_recv().unwrap();
1629 assert_eq!(iv.reason, 0);
1630 assert!(matches!(iv.aux_status, crate::error::AsynStatus::Timeout));
1631 assert_eq!(iv.alarm_status, 4);
1632 assert_eq!(iv.alarm_severity, 2);
1633 }
1634
1635 #[test]
1636 fn test_call_param_callback_single_propagates_aux_status() {
1637 let mut drv = TestDriver::new();
1639 let mut rx = drv.base_mut().interrupts.subscribe_async();
1640
1641 drv.base_mut().set_int32_param(0, 0, 1).unwrap();
1642 drv.base_mut()
1643 .params
1644 .set_param_status(0, 0, crate::error::AsynStatus::Disconnected, 7, 3)
1645 .unwrap();
1646 drv.base_mut().call_param_callback(0, 0).unwrap();
1647
1648 let iv = rx.try_recv().unwrap();
1649 assert!(matches!(
1650 iv.aux_status,
1651 crate::error::AsynStatus::Disconnected
1652 ));
1653 assert_eq!(iv.alarm_status, 7);
1654 assert_eq!(iv.alarm_severity, 3);
1655 }
1656
1657 #[test]
1658 fn test_no_callback_for_unchanged() {
1659 let mut drv = TestDriver::new();
1660 let mut rx = drv.base_mut().interrupts.subscribe_async();
1661
1662 drv.base_mut().set_int32_param(0, 0, 5).unwrap();
1663 drv.base_mut().call_param_callbacks(0).unwrap();
1664 let _ = rx.try_recv().unwrap(); drv.base_mut().set_int32_param(0, 0, 5).unwrap();
1668 drv.base_mut().call_param_callbacks(0).unwrap();
1669 assert!(rx.try_recv().is_err());
1670 }
1671
1672 #[test]
1673 fn test_array_not_supported_by_default() {
1674 let mut drv = TestDriver::new();
1675 let user = AsynUser::new(0);
1676 let mut buf = [0f64; 10];
1677 assert!(drv.read_float64_array(&user, &mut buf).is_err());
1678 assert!(drv.write_float64_array(&user, &[1.0]).is_err());
1679 }
1680
1681 #[test]
1682 fn test_option_set_get() {
1683 let mut drv = TestDriver::new();
1684 drv.set_option("baud", "9600").unwrap();
1685 assert_eq!(drv.get_option("baud").unwrap(), "9600");
1686 drv.set_option("baud", "115200").unwrap();
1687 assert_eq!(drv.get_option("baud").unwrap(), "115200");
1688 }
1689
1690 #[test]
1691 fn test_option_not_found() {
1692 let drv = TestDriver::new();
1693 let err = drv.get_option("nonexistent").unwrap_err();
1694 assert!(matches!(err, AsynError::OptionNotFound(_)));
1695 }
1696
1697 #[test]
1698 fn test_report_no_panic() {
1699 let mut drv = TestDriver::new();
1700 drv.set_option("testkey", "testval").unwrap();
1701 drv.base_mut().set_int32_param(0, 0, 42).unwrap();
1702 for level in 0..=3 {
1703 drv.report(level);
1704 }
1705 }
1706
1707 #[test]
1708 fn test_callback_uses_param_timestamp() {
1709 let mut drv = TestDriver::new();
1710 let mut rx = drv.base_mut().interrupts.subscribe_async();
1711
1712 let custom_ts = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_000_000);
1713 drv.base_mut().set_int32_param(0, 0, 77).unwrap();
1714 drv.base_mut().set_param_timestamp(0, 0, custom_ts).unwrap();
1715 drv.base_mut().call_param_callbacks(0).unwrap();
1716
1717 let v = rx.try_recv().unwrap();
1718 assert_eq!(v.reason, 0);
1719 assert_eq!(v.timestamp, custom_ts);
1720 }
1721
1722 #[test]
1723 fn test_default_read_write_enum() {
1724 use crate::param::EnumEntry;
1725
1726 let mut base = PortDriverBase::new("test_enum", 1, PortFlags::default());
1727 base.create_param("MODE", ParamType::Enum).unwrap();
1728
1729 struct EnumDriver {
1730 base: PortDriverBase,
1731 }
1732 impl PortDriver for EnumDriver {
1733 fn base(&self) -> &PortDriverBase {
1734 &self.base
1735 }
1736 fn base_mut(&mut self) -> &mut PortDriverBase {
1737 &mut self.base
1738 }
1739 }
1740
1741 let mut drv = EnumDriver { base };
1742 let choices: Arc<[EnumEntry]> = Arc::from(vec![
1743 EnumEntry {
1744 string: "Off".into(),
1745 value: 0,
1746 severity: 0,
1747 },
1748 EnumEntry {
1749 string: "On".into(),
1750 value: 1,
1751 severity: 0,
1752 },
1753 ]);
1754 let mut user = AsynUser::new(0);
1755 drv.write_enum_choices(&mut user, choices).unwrap();
1756 drv.write_enum(&mut user, 1).unwrap();
1757 let (idx, ch) = drv.read_enum(&AsynUser::new(0)).unwrap();
1758 assert_eq!(idx, 1);
1759 assert_eq!(ch[1].string, "On");
1760 }
1761
1762 #[test]
1763 fn test_enum_callback() {
1764 use crate::param::{EnumEntry, ParamValue};
1765
1766 let mut base = PortDriverBase::new("test_enum_cb", 1, PortFlags::default());
1767 base.create_param("MODE", ParamType::Enum).unwrap();
1768 let mut rx = base.interrupts.subscribe_async();
1769
1770 struct EnumDriver {
1771 base: PortDriverBase,
1772 }
1773 impl PortDriver for EnumDriver {
1774 fn base(&self) -> &PortDriverBase {
1775 &self.base
1776 }
1777 fn base_mut(&mut self) -> &mut PortDriverBase {
1778 &mut self.base
1779 }
1780 }
1781
1782 let mut drv = EnumDriver { base };
1783 let choices: Arc<[EnumEntry]> = Arc::from(vec![
1784 EnumEntry {
1785 string: "A".into(),
1786 value: 0,
1787 severity: 0,
1788 },
1789 EnumEntry {
1790 string: "B".into(),
1791 value: 1,
1792 severity: 0,
1793 },
1794 ]);
1795 drv.base_mut()
1796 .set_enum_choices_param(0, 0, choices)
1797 .unwrap();
1798 drv.base_mut().set_enum_index_param(0, 0, 1).unwrap();
1799 drv.base_mut().call_param_callbacks(0).unwrap();
1800
1801 let v = rx.try_recv().unwrap();
1802 assert_eq!(v.reason, 0);
1803 assert!(matches!(v.value, ParamValue::Enum { index: 1, .. }));
1804 }
1805
1806 #[test]
1807 fn test_default_read_write_generic_pointer() {
1808 let mut base = PortDriverBase::new("test_gp", 1, PortFlags::default());
1809 base.create_param("PTR", ParamType::GenericPointer).unwrap();
1810
1811 struct GpDriver {
1812 base: PortDriverBase,
1813 }
1814 impl PortDriver for GpDriver {
1815 fn base(&self) -> &PortDriverBase {
1816 &self.base
1817 }
1818 fn base_mut(&mut self) -> &mut PortDriverBase {
1819 &mut self.base
1820 }
1821 }
1822
1823 let mut drv = GpDriver { base };
1824 let data: Arc<dyn std::any::Any + Send + Sync> = Arc::new(99i32);
1825 let mut user = AsynUser::new(0);
1826 drv.write_generic_pointer(&mut user, data).unwrap();
1827 let val = drv.read_generic_pointer(&AsynUser::new(0)).unwrap();
1828 assert_eq!(*val.downcast_ref::<i32>().unwrap(), 99);
1829 }
1830
1831 #[test]
1832 fn test_generic_pointer_callback() {
1833 use crate::param::ParamValue;
1834
1835 let mut base = PortDriverBase::new("test_gp_cb", 1, PortFlags::default());
1836 base.create_param("PTR", ParamType::GenericPointer).unwrap();
1837 let mut rx = base.interrupts.subscribe_async();
1838
1839 struct GpDriver {
1840 base: PortDriverBase,
1841 }
1842 impl PortDriver for GpDriver {
1843 fn base(&self) -> &PortDriverBase {
1844 &self.base
1845 }
1846 fn base_mut(&mut self) -> &mut PortDriverBase {
1847 &mut self.base
1848 }
1849 }
1850
1851 let mut drv = GpDriver { base };
1852 let data: Arc<dyn std::any::Any + Send + Sync> = Arc::new(vec![1, 2, 3]);
1853 drv.base_mut()
1854 .set_generic_pointer_param(0, 0, data)
1855 .unwrap();
1856 drv.base_mut().call_param_callbacks(0).unwrap();
1857
1858 let v = rx.try_recv().unwrap();
1859 assert_eq!(v.reason, 0);
1860 assert!(matches!(v.value, ParamValue::GenericPointer(_)));
1861 }
1862
1863 #[test]
1864 fn test_interpose_push_requires_lock() {
1865 use crate::interpose::{OctetInterpose, OctetNext, OctetReadResult};
1866 use parking_lot::Mutex;
1867 use std::sync::Arc;
1868
1869 struct NoopInterpose;
1870 impl OctetInterpose for NoopInterpose {
1871 fn read(
1872 &mut self,
1873 user: &AsynUser,
1874 buf: &mut [u8],
1875 next: &mut dyn OctetNext,
1876 ) -> AsynResult<OctetReadResult> {
1877 next.read(user, buf)
1878 }
1879 fn write(
1880 &mut self,
1881 user: &mut AsynUser,
1882 data: &[u8],
1883 next: &mut dyn OctetNext,
1884 ) -> AsynResult<usize> {
1885 next.write(user, data)
1886 }
1887 fn flush(&mut self, user: &mut AsynUser, next: &mut dyn OctetNext) -> AsynResult<()> {
1888 next.flush(user)
1889 }
1890 }
1891
1892 let port: Arc<Mutex<dyn PortDriver>> = Arc::new(Mutex::new(TestDriver::new()));
1893
1894 {
1895 let mut guard = port.lock();
1896 guard
1897 .base_mut()
1898 .push_octet_interpose(Box::new(NoopInterpose));
1899 assert_eq!(guard.base().interpose_octet.len(), 1);
1900 }
1901 }
1902
1903 #[test]
1907 fn test_set_input_eos_reaches_installed_interpose() {
1908 use crate::interpose::eos::EosInterpose;
1909 use crate::interpose::{EomReason, OctetNext, OctetReadResult};
1910
1911 struct RawSource {
1912 data: Vec<u8>,
1913 pos: usize,
1914 }
1915 impl OctetNext for RawSource {
1916 fn read(&mut self, _u: &AsynUser, buf: &mut [u8]) -> AsynResult<OctetReadResult> {
1917 let avail = self.data.len() - self.pos;
1918 let n = avail.min(buf.len());
1919 buf[..n].copy_from_slice(&self.data[self.pos..self.pos + n]);
1920 self.pos += n;
1921 Ok(OctetReadResult {
1922 nbytes_transferred: n,
1923 eom_reason: EomReason::CNT,
1924 })
1925 }
1926 fn write(&mut self, _u: &mut AsynUser, data: &[u8]) -> AsynResult<usize> {
1927 Ok(data.len())
1928 }
1929 fn flush(&mut self, _u: &mut AsynUser) -> AsynResult<()> {
1930 Ok(())
1931 }
1932 }
1933
1934 let mut drv = TestDriver::new();
1935 drv.base_mut()
1936 .push_octet_interpose(Box::new(EosInterpose::default()));
1937
1938 drv.set_input_eos(b"\n").unwrap();
1941 assert_eq!(drv.base().input_eos, b"\n");
1942
1943 let user = AsynUser::default();
1944 let mut src = RawSource {
1948 data: b"ab\n".to_vec(),
1949 pos: 0,
1950 };
1951 let mut buf = [0u8; 16];
1952 let r = drv
1953 .base_mut()
1954 .interpose_octet
1955 .dispatch_read(&user, &mut buf, &mut src)
1956 .unwrap();
1957 assert_eq!(&buf[..r.nbytes_transferred], b"ab");
1958 assert!(r.eom_reason.contains(EomReason::EOS));
1959
1960 drv.set_input_eos(b"").unwrap();
1963 assert_eq!(drv.base().input_eos, b"");
1964 let mut src2 = RawSource {
1965 data: b"xy\nz".to_vec(),
1966 pos: 0,
1967 };
1968 let mut buf2 = [0u8; 16];
1969 let r2 = drv
1970 .base_mut()
1971 .interpose_octet
1972 .dispatch_read(&user, &mut buf2, &mut src2)
1973 .unwrap();
1974 assert_eq!(&buf2[..r2.nbytes_transferred], b"xy\nz");
1975 assert!(!r2.eom_reason.contains(EomReason::EOS));
1976 }
1977
1978 #[test]
1979 fn test_default_read_write_int64() {
1980 let mut base = PortDriverBase::new("test_i64", 1, PortFlags::default());
1981 base.create_param("BIG", ParamType::Int64).unwrap();
1982
1983 struct I64Driver {
1984 base: PortDriverBase,
1985 }
1986 impl PortDriver for I64Driver {
1987 fn base(&self) -> &PortDriverBase {
1988 &self.base
1989 }
1990 fn base_mut(&mut self) -> &mut PortDriverBase {
1991 &mut self.base
1992 }
1993 }
1994
1995 let mut drv = I64Driver { base };
1996 let mut user = AsynUser::new(0);
1997 drv.write_int64(&mut user, i64::MAX).unwrap();
1998 assert_eq!(drv.read_int64(&AsynUser::new(0)).unwrap(), i64::MAX);
1999 }
2000
2001 #[test]
2002 fn test_get_bounds_int64_default() {
2003 let base = PortDriverBase::new("test_bounds", 1, PortFlags::default());
2004 struct BoundsDriver {
2005 base: PortDriverBase,
2006 }
2007 impl PortDriver for BoundsDriver {
2008 fn base(&self) -> &PortDriverBase {
2009 &self.base
2010 }
2011 fn base_mut(&mut self) -> &mut PortDriverBase {
2012 &mut self.base
2013 }
2014 }
2015 let drv = BoundsDriver { base };
2016 let (lo, hi) = drv.get_bounds_int64(&AsynUser::default()).unwrap();
2017 assert_eq!(lo, 0);
2020 assert_eq!(hi, 0);
2021 }
2022
2023 #[test]
2024 fn test_per_addr_device_state() {
2025 let mut base = PortDriverBase::new(
2026 "multi",
2027 4,
2028 PortFlags {
2029 multi_device: true,
2030 can_block: false,
2031 destructible: true,
2032 },
2033 );
2034 base.create_param("V", ParamType::Int32).unwrap();
2035
2036 assert!(base.is_device_connected(0));
2038 assert!(base.is_device_connected(1));
2039
2040 base.device_state(1).enabled = false;
2042 assert!(base.check_ready_addr(0).is_ok());
2043 let err = base.check_ready_addr(1).unwrap_err();
2044 assert!(format!("{err}").contains("disabled"));
2045
2046 base.device_state(2).connected = false;
2048 let err = base.check_ready_addr(2).unwrap_err();
2049 assert!(format!("{err}").contains("disconnected"));
2050 }
2051
2052 #[test]
2053 fn test_per_addr_single_device_ignored() {
2054 let mut base = PortDriverBase::new("single", 1, PortFlags::default());
2055 base.create_param("V", ParamType::Int32).unwrap();
2056 assert!(base.check_ready_addr(0).is_ok());
2058 }
2059
2060 #[test]
2061 fn test_timestamp_source() {
2062 let mut base = PortDriverBase::new("ts_test", 1, PortFlags::default());
2063 base.create_param("V", ParamType::Int32).unwrap();
2064
2065 let fixed_ts = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(999999);
2066 base.register_timestamp_source(move || fixed_ts);
2067
2068 assert_eq!(base.current_timestamp(), fixed_ts);
2069 }
2070
2071 #[test]
2072 fn test_timestamp_source_in_callbacks() {
2073 let mut base = PortDriverBase::new("ts_cb", 1, PortFlags::default());
2074 base.create_param("V", ParamType::Int32).unwrap();
2075 let mut rx = base.interrupts.subscribe_async();
2076
2077 let fixed_ts = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(123456);
2078 base.register_timestamp_source(move || fixed_ts);
2079
2080 struct TsDriver {
2081 base: PortDriverBase,
2082 }
2083 impl PortDriver for TsDriver {
2084 fn base(&self) -> &PortDriverBase {
2085 &self.base
2086 }
2087 fn base_mut(&mut self) -> &mut PortDriverBase {
2088 &mut self.base
2089 }
2090 }
2091 let mut drv = TsDriver { base };
2092 drv.base_mut().set_int32_param(0, 0, 42).unwrap();
2093 drv.base_mut().call_param_callbacks(0).unwrap();
2094
2095 let v = rx.try_recv().unwrap();
2096 assert_eq!(v.timestamp, fixed_ts);
2098 }
2099
2100 #[test]
2101 fn test_queue_priority_connect() {
2102 assert!(QueuePriority::Connect > QueuePriority::High);
2103 }
2104
2105 #[test]
2106 fn test_port_flags_destructible_default_is_opt_in() {
2107 let flags = PortFlags::default();
2113 assert!(
2114 !flags.destructible,
2115 "destructible must be opt-in (C parity)"
2116 );
2117 }
2118
2119 #[test]
2120 fn shutdown_lifecycle_refuses_non_destructible() {
2121 let mut base = PortDriverBase::new(
2122 "p_nondestr",
2123 1,
2124 PortFlags {
2125 multi_device: false,
2126 can_block: false,
2127 destructible: false,
2128 },
2129 );
2130 match base.shutdown_lifecycle() {
2131 Err(AsynError::Status { message, .. }) => {
2132 assert!(message.contains("ASYN_DESTRUCTIBLE"), "msg={message}");
2133 }
2134 other => panic!("expected ASYN_DESTRUCTIBLE refusal, got {other:?}"),
2135 }
2136 assert!(
2137 !base.is_defunct(),
2138 "non-destructible port must not flip defunct"
2139 );
2140 assert!(base.is_enabled(), "non-destructible port must stay enabled");
2141 }
2142
2143 #[test]
2144 fn shutdown_lifecycle_marks_destructible_defunct_and_idempotent() {
2145 let mut base = PortDriverBase::new(
2146 "p_destr",
2147 1,
2148 PortFlags {
2149 multi_device: false,
2150 can_block: false,
2151 destructible: true,
2152 },
2153 );
2154 assert!(base.is_enabled());
2155 assert!(!base.is_defunct());
2156 base.shutdown_lifecycle().unwrap();
2157 assert!(
2158 !base.is_enabled(),
2159 "shutdown_lifecycle must flip enabled=false"
2160 );
2161 assert!(
2162 base.is_defunct(),
2163 "shutdown_lifecycle must flip defunct=true"
2164 );
2165 base.shutdown_lifecycle().unwrap();
2167 assert!(base.is_defunct());
2168 match base.check_ready() {
2170 Err(AsynError::Status { message, .. }) => {
2171 assert!(message.contains("defunct"), "msg={message}");
2172 }
2173 other => panic!("expected defunct error, got {other:?}"),
2174 }
2175 }
2176
2177 #[test]
2180 fn test_connect_addr() {
2181 let mut base = PortDriverBase::new(
2182 "multi_conn",
2183 4,
2184 PortFlags {
2185 multi_device: true,
2186 can_block: false,
2187 destructible: true,
2188 },
2189 );
2190 base.create_param("V", ParamType::Int32).unwrap();
2191
2192 base.disconnect_addr(1);
2193 assert!(!base.is_device_connected(1));
2194 assert!(base.check_ready_addr(1).is_err());
2195
2196 base.connect_addr(1);
2197 assert!(base.is_device_connected(1));
2198 assert!(base.check_ready_addr(1).is_ok());
2199 }
2200
2201 #[test]
2202 fn test_enable_disable_addr() {
2203 let mut base = PortDriverBase::new(
2204 "multi_en",
2205 4,
2206 PortFlags {
2207 multi_device: true,
2208 can_block: false,
2209 destructible: true,
2210 },
2211 );
2212 base.create_param("V", ParamType::Int32).unwrap();
2213
2214 base.disable_addr(2);
2215 let err = base.check_ready_addr(2).unwrap_err();
2216 assert!(format!("{err}").contains("disabled"));
2217
2218 base.enable_addr(2);
2219 assert!(base.check_ready_addr(2).is_ok());
2220 }
2221
2222 #[test]
2223 fn test_port_level_overrides_addr() {
2224 let mut base = PortDriverBase::new(
2225 "multi_override",
2226 4,
2227 PortFlags {
2228 multi_device: true,
2229 can_block: false,
2230 destructible: true,
2231 },
2232 );
2233 base.create_param("V", ParamType::Int32).unwrap();
2234
2235 base.enabled = false;
2237 base.enable_addr(0); let err = base.check_ready_addr(0).unwrap_err();
2239 assert!(format!("{err}").contains("disabled"));
2240 }
2241
2242 #[test]
2243 fn test_per_addr_exception_announced() {
2244 use std::sync::atomic::{AtomicI32, Ordering};
2245
2246 let mut base = PortDriverBase::new(
2247 "multi_exc",
2248 4,
2249 PortFlags {
2250 multi_device: true,
2251 can_block: false,
2252 destructible: true,
2253 },
2254 );
2255 base.create_param("V", ParamType::Int32).unwrap();
2256
2257 let exc_mgr = Arc::new(crate::exception::ExceptionManager::new());
2258 base.exception_sink = Some(exc_mgr.clone());
2259
2260 let last_addr = Arc::new(AtomicI32::new(-99));
2261 let last_addr2 = last_addr.clone();
2262 exc_mgr.add_callback(move |event| {
2263 last_addr2.store(event.addr, Ordering::Relaxed);
2264 });
2265
2266 base.disconnect_addr(3);
2267 assert_eq!(last_addr.load(Ordering::Relaxed), 3);
2268
2269 base.enable_addr(2);
2270 assert_eq!(last_addr.load(Ordering::Relaxed), 2);
2271 }
2272
2273 #[test]
2280 fn test_connect_disconnect_announce_only_on_transition() {
2281 use std::sync::atomic::{AtomicUsize, Ordering};
2282
2283 let mut base = PortDriverBase::new(
2284 "edge",
2285 4,
2286 PortFlags {
2287 multi_device: true,
2288 can_block: false,
2289 destructible: true,
2290 },
2291 );
2292 base.create_param("V", ParamType::Int32).unwrap();
2293 let exc_mgr = Arc::new(crate::exception::ExceptionManager::new());
2294 base.exception_sink = Some(exc_mgr.clone());
2295
2296 let connect_hits = Arc::new(AtomicUsize::new(0));
2297 let hits2 = connect_hits.clone();
2298 exc_mgr.add_callback(move |event| {
2299 if event.exception == AsynException::Connect {
2300 hits2.fetch_add(1, Ordering::Relaxed);
2301 }
2302 });
2303
2304 base.connect_addr(2);
2307 assert_eq!(
2308 connect_hits.load(Ordering::Relaxed),
2309 0,
2310 "redundant connect_addr must not fan out"
2311 );
2312
2313 base.disconnect_addr(2);
2315 assert_eq!(connect_hits.load(Ordering::Relaxed), 1);
2316
2317 base.disconnect_addr(2);
2319 assert_eq!(
2320 connect_hits.load(Ordering::Relaxed),
2321 1,
2322 "redundant disconnect_addr must not fan out"
2323 );
2324
2325 base.connect_addr(2);
2327 assert_eq!(connect_hits.load(Ordering::Relaxed), 2);
2328 }
2329
2330 #[test]
2335 fn test_set_auto_connect_fires_unconditionally() {
2336 use std::sync::atomic::{AtomicUsize, Ordering};
2337
2338 let mut base = PortDriverBase::new("ac", 1, PortFlags::default());
2339 let exc_mgr = Arc::new(crate::exception::ExceptionManager::new());
2340 base.exception_sink = Some(exc_mgr.clone());
2341 let hits = Arc::new(AtomicUsize::new(0));
2342 let hits2 = hits.clone();
2343 exc_mgr.add_callback(move |event| {
2344 if event.exception == AsynException::AutoConnect {
2345 hits2.fetch_add(1, Ordering::Relaxed);
2346 }
2347 });
2348 base.set_auto_connect(true);
2351 base.set_auto_connect(false);
2352 base.set_auto_connect(false);
2353 assert_eq!(hits.load(Ordering::Relaxed), 3);
2354 }
2355
2356 #[test]
2357 fn auto_connect_throttle_gate_boundaries() {
2358 let mut base = PortDriverBase::new("thr", 1, PortFlags::default());
2361
2362 let t0 = Instant::now();
2365 assert!(base.auto_connect_throttle_ok(-1, t0));
2366
2367 base.last_connect_disconnect = Some(t0);
2370 assert!(!base.auto_connect_throttle_ok(-1, t0));
2372 assert!(!base.auto_connect_throttle_ok(-1, t0 + Duration::from_millis(1999)));
2374 assert!(base.auto_connect_throttle_ok(-1, t0 + Duration::from_secs(2)));
2376 assert!(base.auto_connect_throttle_ok(-1, t0 + Duration::from_secs(5)));
2378 }
2379
2380 #[test]
2381 fn auto_connect_throttle_stamps_on_disconnect_not_connect() {
2382 let mut base = PortDriverBase::new("thr", 1, PortFlags::default());
2385 assert!(base.last_connect_disconnect.is_none());
2387
2388 assert!(base.set_connected(false));
2390 assert!(base.last_connect_disconnect.is_some());
2391
2392 base.last_connect_disconnect = None;
2394 assert!(base.set_connected(true));
2395 assert!(base.last_connect_disconnect.is_none());
2396 }
2397
2398 #[test]
2399 fn auto_connect_throttle_per_device_anchor() {
2400 let flags = PortFlags {
2402 multi_device: true,
2403 ..PortFlags::default()
2404 };
2405 let mut base = PortDriverBase::new("thr", 4, flags);
2406 let t0 = Instant::now();
2407
2408 assert!(base.set_addr_connected(1, false));
2410 assert!(base.device_state(1).last_connect_disconnect.is_some());
2411 assert!(!base.auto_connect_throttle_ok(1, t0));
2413 assert!(base.auto_connect_throttle_ok(2, t0));
2414
2415 base.stamp_auto_connect_attempt(2, t0);
2417 assert!(!base.auto_connect_throttle_ok(2, t0));
2418 assert!(base.auto_connect_throttle_ok(2, t0 + Duration::from_secs(2)));
2419 }
2420
2421 #[test]
2422 fn set_enabled_refuses_defunct_port() {
2423 use std::sync::atomic::{AtomicUsize, Ordering};
2424 let flags = PortFlags {
2427 destructible: true,
2428 ..PortFlags::default()
2429 };
2430 let mut base = PortDriverBase::new("def", 1, flags);
2431 let exc_mgr = Arc::new(crate::exception::ExceptionManager::new());
2432 base.exception_sink = Some(exc_mgr.clone());
2433 let enable_hits = Arc::new(AtomicUsize::new(0));
2434 let h = enable_hits.clone();
2435 exc_mgr.add_callback(move |event| {
2436 if event.exception == AsynException::Enable {
2437 h.fetch_add(1, Ordering::Relaxed);
2438 }
2439 });
2440
2441 base.shutdown_lifecycle().unwrap();
2443 assert!(base.is_defunct());
2444 assert!(!base.is_enabled());
2445
2446 let err = base.set_enabled(true).unwrap_err();
2447 match err {
2448 AsynError::Status { status, .. } => assert_eq!(status, AsynStatus::Disabled),
2449 other => panic!("expected Disabled, got {other:?}"),
2450 }
2451 assert!(!base.is_enabled(), "defunct port must not re-enable");
2452 assert_eq!(
2453 enable_hits.load(Ordering::Relaxed),
2454 0,
2455 "no Enable exception may fire on a defunct port"
2456 );
2457 }
2458
2459 #[test]
2460 fn set_addr_enabled_refuses_defunct_port() {
2461 use std::sync::atomic::{AtomicUsize, Ordering};
2462 let flags = PortFlags {
2463 multi_device: true,
2464 destructible: true,
2465 ..PortFlags::default()
2466 };
2467 let mut base = PortDriverBase::new("def", 4, flags);
2468 let exc_mgr = Arc::new(crate::exception::ExceptionManager::new());
2469 base.exception_sink = Some(exc_mgr.clone());
2470 let enable_hits = Arc::new(AtomicUsize::new(0));
2471 let h = enable_hits.clone();
2472 exc_mgr.add_callback(move |event| {
2473 if event.exception == AsynException::Enable {
2474 h.fetch_add(1, Ordering::Relaxed);
2475 }
2476 });
2477
2478 base.shutdown_lifecycle().unwrap();
2479
2480 let err = base.set_addr_enabled(1, false).unwrap_err();
2481 match err {
2482 AsynError::Status { status, .. } => assert_eq!(status, AsynStatus::Disabled),
2483 other => panic!("expected Disabled, got {other:?}"),
2484 }
2485 assert!(
2488 !base.device_states.contains_key(&1),
2489 "refused per-device enable must not create device state"
2490 );
2491 base.disable_addr(1);
2493 assert!(!base.device_states.contains_key(&1));
2494 assert_eq!(
2495 enable_hits.load(Ordering::Relaxed),
2496 0,
2497 "no Enable exception may fire on a defunct port"
2498 );
2499 }
2500
2501 #[test]
2507 fn test_port_driver_uint32_interrupt_round_trip() {
2508 struct UInt32Drv {
2509 base: PortDriverBase,
2510 }
2511 impl PortDriver for UInt32Drv {
2512 fn base(&self) -> &PortDriverBase {
2513 &self.base
2514 }
2515 fn base_mut(&mut self) -> &mut PortDriverBase {
2516 &mut self.base
2517 }
2518 }
2519
2520 let mut base = PortDriverBase::new("uint32_int", 1, PortFlags::default());
2521 let idx = base
2522 .params
2523 .create_param("BITS", ParamType::UInt32Digital)
2524 .unwrap();
2525 let mut drv = UInt32Drv { base };
2526 let user = AsynUser::new(idx).with_addr(0);
2527
2528 drv.set_interrupt_uint32_digital(&user, 0xF0, InterruptReason::ZeroToOne)
2529 .unwrap();
2530 drv.set_interrupt_uint32_digital(&user, 0x0F, InterruptReason::OneToZero)
2531 .unwrap();
2532 assert_eq!(
2533 drv.get_interrupt_uint32_digital(&user, InterruptReason::Both)
2534 .unwrap(),
2535 0xFF
2536 );
2537 drv.clear_interrupt_uint32_digital(&user, 0x11).unwrap();
2538 assert_eq!(
2539 drv.get_interrupt_uint32_digital(&user, InterruptReason::ZeroToOne)
2540 .unwrap(),
2541 0xE0
2542 );
2543 assert_eq!(
2544 drv.get_interrupt_uint32_digital(&user, InterruptReason::OneToZero)
2545 .unwrap(),
2546 0x0E
2547 );
2548 }
2549
2550 #[test]
2561 fn default_scalar_reads_report_undefined_until_set() {
2562 struct AllTypesDrv {
2563 base: PortDriverBase,
2564 }
2565 impl PortDriver for AllTypesDrv {
2566 fn base(&self) -> &PortDriverBase {
2567 &self.base
2568 }
2569 fn base_mut(&mut self) -> &mut PortDriverBase {
2570 &mut self.base
2571 }
2572 }
2573
2574 let mut base = PortDriverBase::new("undef_read", 1, PortFlags::default());
2575 let i32_idx = base.params.create_param("I32", ParamType::Int32).unwrap();
2576 let i64_idx = base.params.create_param("I64", ParamType::Int64).unwrap();
2577 let f64_idx = base.params.create_param("F64", ParamType::Float64).unwrap();
2578 let oct_idx = base.params.create_param("OCT", ParamType::Octet).unwrap();
2579 let u32_idx = base
2580 .params
2581 .create_param("BITS", ParamType::UInt32Digital)
2582 .unwrap();
2583 let mut drv = AllTypesDrv { base };
2584
2585 assert!(matches!(
2587 drv.read_int32(&AsynUser::new(i32_idx).with_addr(0)),
2588 Err(AsynError::ParamUndefined(_))
2589 ));
2590 assert!(matches!(
2591 drv.read_int64(&AsynUser::new(i64_idx).with_addr(0)),
2592 Err(AsynError::ParamUndefined(_))
2593 ));
2594 assert!(matches!(
2595 drv.read_float64(&AsynUser::new(f64_idx).with_addr(0)),
2596 Err(AsynError::ParamUndefined(_))
2597 ));
2598 let mut buf = [0u8; 16];
2599 assert!(matches!(
2600 drv.read_octet(&AsynUser::new(oct_idx).with_addr(0), &mut buf),
2601 Err(AsynError::ParamUndefined(_))
2602 ));
2603 assert!(matches!(
2604 drv.read_uint32_digital(&AsynUser::new(u32_idx).with_addr(0), 0xFFFF_FFFF),
2605 Err(AsynError::ParamUndefined(_))
2606 ));
2607
2608 drv.base_mut().params.set_int32(i32_idx, 0, 7).unwrap();
2610 drv.base_mut().params.set_int64(i64_idx, 0, 9).unwrap();
2611 drv.base_mut().params.set_float64(f64_idx, 0, 1.5).unwrap();
2612 drv.base_mut()
2613 .params
2614 .set_string(oct_idx, 0, "hi".to_string())
2615 .unwrap();
2616 drv.base_mut()
2617 .params
2618 .set_uint32(u32_idx, 0, 0x05, 0xFFFF_FFFF, 0)
2619 .unwrap();
2620
2621 assert_eq!(
2622 drv.read_int32(&AsynUser::new(i32_idx).with_addr(0))
2623 .unwrap(),
2624 7
2625 );
2626 assert_eq!(
2627 drv.read_int64(&AsynUser::new(i64_idx).with_addr(0))
2628 .unwrap(),
2629 9
2630 );
2631 assert_eq!(
2632 drv.read_float64(&AsynUser::new(f64_idx).with_addr(0))
2633 .unwrap(),
2634 1.5
2635 );
2636 let n = drv
2637 .read_octet(&AsynUser::new(oct_idx).with_addr(0), &mut buf)
2638 .unwrap();
2639 assert_eq!(&buf[..n], b"hi");
2640 assert_eq!(
2641 drv.read_uint32_digital(&AsynUser::new(u32_idx).with_addr(0), 0xFFFF_FFFF)
2642 .unwrap(),
2643 0x05
2644 );
2645 }
2646}