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(
462 &mut self,
463 index: usize,
464 addr: i32,
465 value: u32,
466 mask: u32,
467 ) -> AsynResult<()> {
468 self.params.set_uint32(index, addr, value, mask)
469 }
470
471 pub fn get_uint32_param(&self, index: usize, addr: i32) -> AsynResult<u32> {
472 self.params.get_uint32(index, addr)
473 }
474
475 pub fn get_uint32_param_strict(&self, index: usize, addr: i32) -> AsynResult<u32> {
477 self.params.get_uint32_strict(index, addr)
478 }
479
480 pub fn get_enum_param(&self, index: usize, addr: i32) -> AsynResult<(usize, Arc<[EnumEntry]>)> {
481 self.params.get_enum(index, addr)
482 }
483
484 pub fn set_enum_index_param(
485 &mut self,
486 index: usize,
487 addr: i32,
488 value: usize,
489 ) -> AsynResult<()> {
490 self.params.set_enum_index(index, addr, value)
491 }
492
493 pub fn set_enum_choices_param(
494 &mut self,
495 index: usize,
496 addr: i32,
497 choices: Arc<[EnumEntry]>,
498 ) -> AsynResult<()> {
499 self.params.set_enum_choices(index, addr, choices)
500 }
501
502 pub fn get_generic_pointer_param(
503 &self,
504 index: usize,
505 addr: i32,
506 ) -> AsynResult<Arc<dyn Any + Send + Sync>> {
507 self.params.get_generic_pointer(index, addr)
508 }
509
510 pub fn set_generic_pointer_param(
511 &mut self,
512 index: usize,
513 addr: i32,
514 value: Arc<dyn Any + Send + Sync>,
515 ) -> AsynResult<()> {
516 self.params.set_generic_pointer(index, addr, value)
517 }
518
519 pub fn set_param_timestamp(
520 &mut self,
521 index: usize,
522 addr: i32,
523 ts: SystemTime,
524 ) -> AsynResult<()> {
525 self.params.set_timestamp(index, addr, ts)
526 }
527
528 pub fn set_param_status(
529 &mut self,
530 index: usize,
531 addr: i32,
532 status: AsynStatus,
533 alarm_status: u16,
534 alarm_severity: u16,
535 ) -> AsynResult<()> {
536 self.params
537 .set_param_status(index, addr, status, alarm_status, alarm_severity)
538 }
539
540 pub fn get_param_status(&self, index: usize, addr: i32) -> AsynResult<(AsynStatus, u16, u16)> {
541 self.params.get_param_status(index, addr)
542 }
543
544 pub fn report_params(&self, level: i32) {
546 eprintln!(" Number of parameters is {}", self.params.len());
547 if level < 1 {
548 return;
549 }
550 for i in 0..self.params.len() {
551 let name = self.params.param_name(i).unwrap_or("?");
552 let ptype = self
553 .params
554 .param_type(i)
555 .map(|t| format!("{t:?}"))
556 .unwrap_or("?".into());
557 if level >= 2 {
558 for addr in 0..self.max_addr.max(1) {
559 let val = self
560 .params
561 .get_value(i, addr as i32)
562 .map(|v| format!("{v:?}"))
563 .unwrap_or("undefined".into());
564 let (status, alarm_st, alarm_sev) = self
565 .params
566 .get_param_status(i, addr as i32)
567 .unwrap_or((AsynStatus::Success, 0, 0));
568 eprintln!(
569 " param[{i}] name={name} type={ptype} addr={addr} val={val} status={status:?} alarm=({alarm_st},{alarm_sev})"
570 );
571 }
572 } else {
573 eprintln!(" param[{i}] name={name} type={ptype}");
574 }
575 }
576 }
577
578 pub fn push_octet_interpose(&mut self, layer: Box<dyn OctetInterpose>) {
584 self.interpose_octet.push(layer);
585 }
586
587 pub fn call_param_callbacks(&mut self, addr: i32) -> AsynResult<()> {
590 let changed = self.params.take_changed(addr)?;
591 let now = self.current_timestamp();
592 for reason in changed {
593 let value = self.params.get_value(reason, addr)?.clone();
594 let ts = self.params.get_timestamp(reason, addr)?.unwrap_or(now);
595 let uint32_mask = self
596 .params
597 .get_uint32_interrupt_mask(reason, addr)
598 .unwrap_or(0);
599 let (aux_status, alarm_status, alarm_severity) = self
605 .params
606 .get_param_status(reason, addr)
607 .unwrap_or((AsynStatus::Success, 0, 0));
608 self.interrupts.notify(InterruptValue {
609 reason,
610 addr,
611 value,
612 timestamp: ts,
613 uint32_changed_mask: uint32_mask,
614 aux_status,
615 alarm_status,
616 alarm_severity,
617 });
618 }
619 Ok(())
620 }
621
622 pub fn call_param_callback(&mut self, addr: i32, reason: usize) -> AsynResult<()> {
626 if self.params.take_changed_single(reason, addr)? {
627 let now = self.current_timestamp();
628 let value = self.params.get_value(reason, addr)?.clone();
629 let ts = self.params.get_timestamp(reason, addr)?.unwrap_or(now);
630 let uint32_mask = self
631 .params
632 .get_uint32_interrupt_mask(reason, addr)
633 .unwrap_or(0);
634 let (aux_status, alarm_status, alarm_severity) = self
636 .params
637 .get_param_status(reason, addr)
638 .unwrap_or((AsynStatus::Success, 0, 0));
639 self.interrupts.notify(InterruptValue {
640 reason,
641 addr,
642 value,
643 timestamp: ts,
644 uint32_changed_mask: uint32_mask,
645 aux_status,
646 alarm_status,
647 alarm_severity,
648 });
649 }
650 Ok(())
651 }
652
653 pub fn mark_param_changed(&mut self, index: usize, addr: i32) -> AsynResult<()> {
658 self.params.mark_changed(index, addr)
659 }
660}
661
662pub trait PortDriver: Send + Sync + 'static {
677 fn base(&self) -> &PortDriverBase;
678 fn base_mut(&mut self) -> &mut PortDriverBase;
679
680 fn connect(&mut self, _user: &AsynUser) -> AsynResult<()> {
683 self.base_mut().set_connected(true);
685 Ok(())
686 }
687
688 fn disconnect(&mut self, _user: &AsynUser) -> AsynResult<()> {
689 self.base_mut().set_connected(false);
690 Ok(())
691 }
692
693 fn enable(&mut self, _user: &AsynUser) -> AsynResult<()> {
694 self.base_mut().enabled = true;
695 self.base().announce_exception(AsynException::Enable, -1);
696 Ok(())
697 }
698
699 fn disable(&mut self, _user: &AsynUser) -> AsynResult<()> {
700 self.base_mut().enabled = false;
701 self.base().announce_exception(AsynException::Enable, -1);
702 Ok(())
703 }
704
705 fn connect_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
706 self.base_mut().connect_addr(user.addr);
707 Ok(())
708 }
709
710 fn disconnect_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
711 self.base_mut().disconnect_addr(user.addr);
712 Ok(())
713 }
714
715 fn enable_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
716 self.base_mut().enable_addr(user.addr);
717 Ok(())
718 }
719
720 fn disable_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
721 self.base_mut().disable_addr(user.addr);
722 Ok(())
723 }
724
725 fn get_option(&self, key: &str) -> AsynResult<String> {
726 self.base()
727 .options
728 .get(key)
729 .cloned()
730 .ok_or_else(|| AsynError::OptionNotFound(key.to_string()))
731 }
732
733 fn set_option(&mut self, key: &str, value: &str) -> AsynResult<()> {
734 self.base_mut()
735 .options
736 .insert(key.to_string(), value.to_string());
737 Ok(())
738 }
739
740 fn report(&self, level: i32) {
741 let base = self.base();
742 eprintln!("Port: {}", base.port_name);
743 eprintln!(
744 " connected: {}, max_addr: {}, params: {}, options: {}",
745 base.connected,
746 base.max_addr,
747 base.params.len(),
748 base.options.len()
749 );
750 if level >= 1 {
751 base.report_params(level.saturating_sub(1));
752 }
753 if level >= 2 {
754 for (k, v) in &base.options {
755 eprintln!(" option: {k} = {v}");
756 }
757 }
758 }
759
760 fn read_int32(&mut self, user: &AsynUser) -> AsynResult<i32> {
767 self.base().params.get_int32(user.reason, user.addr)
768 }
769
770 fn write_int32(&mut self, user: &mut AsynUser, value: i32) -> AsynResult<()> {
771 self.base_mut()
772 .params
773 .set_int32(user.reason, user.addr, value)?;
774 self.base_mut().call_param_callbacks(user.addr)
775 }
776
777 fn read_int64(&mut self, user: &AsynUser) -> AsynResult<i64> {
778 self.base().params.get_int64(user.reason, user.addr)
779 }
780
781 fn write_int64(&mut self, user: &mut AsynUser, value: i64) -> AsynResult<()> {
782 self.base_mut()
783 .params
784 .set_int64(user.reason, user.addr, value)?;
785 self.base_mut().call_param_callbacks(user.addr)
786 }
787
788 fn get_bounds_int32(&self, _user: &AsynUser) -> AsynResult<(i32, i32)> {
789 Ok((i32::MIN, i32::MAX))
790 }
791
792 fn get_bounds_int64(&self, _user: &AsynUser) -> AsynResult<(i64, i64)> {
793 Ok((i64::MIN, i64::MAX))
794 }
795
796 fn read_float64(&mut self, user: &AsynUser) -> AsynResult<f64> {
797 self.base().params.get_float64(user.reason, user.addr)
798 }
799
800 fn write_float64(&mut self, user: &mut AsynUser, value: f64) -> AsynResult<()> {
801 self.base_mut()
802 .params
803 .set_float64(user.reason, user.addr, value)?;
804 self.base_mut().call_param_callbacks(user.addr)
805 }
806
807 fn read_octet(&mut self, user: &AsynUser, buf: &mut [u8]) -> AsynResult<usize> {
808 let s = self.base().params.get_string(user.reason, user.addr)?;
809 let bytes = s.as_bytes();
810 let n = bytes.len().min(buf.len());
811 buf[..n].copy_from_slice(&bytes[..n]);
812 Ok(n)
813 }
814
815 fn write_octet(&mut self, user: &mut AsynUser, data: &[u8]) -> AsynResult<()> {
816 let s = String::from_utf8_lossy(data).into_owned();
817 self.base_mut()
818 .params
819 .set_string(user.reason, user.addr, s)?;
820 self.base_mut().call_param_callbacks(user.addr)
821 }
822
823 fn read_uint32_digital(&mut self, user: &AsynUser, mask: u32) -> AsynResult<u32> {
824 let val = self.base().params.get_uint32(user.reason, user.addr)?;
825 Ok(val & mask)
826 }
827
828 fn write_uint32_digital(
829 &mut self,
830 user: &mut AsynUser,
831 value: u32,
832 mask: u32,
833 ) -> AsynResult<()> {
834 self.base_mut()
835 .params
836 .set_uint32(user.reason, user.addr, value, mask)?;
837 self.base_mut().call_param_callbacks(user.addr)
838 }
839
840 fn set_interrupt_uint32_digital(
849 &mut self,
850 user: &AsynUser,
851 mask: u32,
852 reason: InterruptReason,
853 ) -> AsynResult<()> {
854 self.base_mut()
855 .params
856 .set_uint32_interrupt(user.reason, user.addr, mask, reason)
857 }
858
859 fn clear_interrupt_uint32_digital(&mut self, user: &AsynUser, mask: u32) -> AsynResult<()> {
864 self.base_mut()
865 .params
866 .clear_uint32_interrupt(user.reason, user.addr, mask)
867 }
868
869 fn get_interrupt_uint32_digital(
873 &self,
874 user: &AsynUser,
875 reason: InterruptReason,
876 ) -> AsynResult<u32> {
877 self.base()
878 .params
879 .get_uint32_interrupt(user.reason, user.addr, reason)
880 }
881
882 fn read_enum(&mut self, user: &AsynUser) -> AsynResult<(usize, Arc<[EnumEntry]>)> {
885 self.base().params.get_enum(user.reason, user.addr)
886 }
887
888 fn write_enum(&mut self, user: &mut AsynUser, index: usize) -> AsynResult<()> {
889 self.base_mut()
890 .params
891 .set_enum_index(user.reason, user.addr, index)?;
892 self.base_mut().call_param_callbacks(user.addr)
893 }
894
895 fn write_enum_choices(
896 &mut self,
897 user: &mut AsynUser,
898 choices: Arc<[EnumEntry]>,
899 ) -> AsynResult<()> {
900 self.base_mut()
901 .params
902 .set_enum_choices(user.reason, user.addr, choices)?;
903 self.base_mut().call_param_callbacks(user.addr)
904 }
905
906 fn read_generic_pointer(&mut self, user: &AsynUser) -> AsynResult<Arc<dyn Any + Send + Sync>> {
909 self.base()
910 .params
911 .get_generic_pointer(user.reason, user.addr)
912 }
913
914 fn write_generic_pointer(
915 &mut self,
916 user: &mut AsynUser,
917 value: Arc<dyn Any + Send + Sync>,
918 ) -> AsynResult<()> {
919 self.base_mut()
920 .params
921 .set_generic_pointer(user.reason, user.addr, value)?;
922 self.base_mut().call_param_callbacks(user.addr)
923 }
924
925 fn read_float64_array(&mut self, _user: &AsynUser, _buf: &mut [f64]) -> AsynResult<usize> {
928 Err(AsynError::InterfaceNotSupported("asynFloat64Array".into()))
929 }
930
931 fn write_float64_array(&mut self, user: &AsynUser, data: &[f64]) -> AsynResult<()> {
932 self.base_mut()
933 .params
934 .set_float64_array(user.reason, user.addr, data.to_vec())?;
935 self.base_mut().call_param_callbacks(user.addr)
936 }
937
938 fn read_int32_array(&mut self, _user: &AsynUser, _buf: &mut [i32]) -> AsynResult<usize> {
939 Err(AsynError::InterfaceNotSupported("asynInt32Array".into()))
940 }
941
942 fn write_int32_array(&mut self, user: &AsynUser, data: &[i32]) -> AsynResult<()> {
943 self.base_mut()
944 .params
945 .set_int32_array(user.reason, user.addr, data.to_vec())?;
946 self.base_mut().call_param_callbacks(user.addr)
947 }
948
949 fn read_int8_array(&mut self, _user: &AsynUser, _buf: &mut [i8]) -> AsynResult<usize> {
950 Err(AsynError::InterfaceNotSupported("asynInt8Array".into()))
951 }
952
953 fn write_int8_array(&mut self, user: &AsynUser, data: &[i8]) -> AsynResult<()> {
954 self.base_mut()
955 .params
956 .set_int8_array(user.reason, user.addr, data.to_vec())?;
957 self.base_mut().call_param_callbacks(user.addr)
958 }
959
960 fn read_int16_array(&mut self, _user: &AsynUser, _buf: &mut [i16]) -> AsynResult<usize> {
961 Err(AsynError::InterfaceNotSupported("asynInt16Array".into()))
962 }
963
964 fn write_int16_array(&mut self, user: &AsynUser, data: &[i16]) -> AsynResult<()> {
965 self.base_mut()
966 .params
967 .set_int16_array(user.reason, user.addr, data.to_vec())?;
968 self.base_mut().call_param_callbacks(user.addr)
969 }
970
971 fn read_int64_array(&mut self, _user: &AsynUser, _buf: &mut [i64]) -> AsynResult<usize> {
972 Err(AsynError::InterfaceNotSupported("asynInt64Array".into()))
973 }
974
975 fn write_int64_array(&mut self, user: &AsynUser, data: &[i64]) -> AsynResult<()> {
976 self.base_mut()
977 .params
978 .set_int64_array(user.reason, user.addr, data.to_vec())?;
979 self.base_mut().call_param_callbacks(user.addr)
980 }
981
982 fn read_float32_array(&mut self, _user: &AsynUser, _buf: &mut [f32]) -> AsynResult<usize> {
983 Err(AsynError::InterfaceNotSupported("asynFloat32Array".into()))
984 }
985
986 fn write_float32_array(&mut self, user: &AsynUser, data: &[f32]) -> AsynResult<()> {
987 self.base_mut()
988 .params
989 .set_float32_array(user.reason, user.addr, data.to_vec())?;
990 self.base_mut().call_param_callbacks(user.addr)
991 }
992
993 fn io_read_octet(&mut self, user: &AsynUser, buf: &mut [u8]) -> AsynResult<usize> {
998 self.read_octet(user, buf)
999 }
1000
1001 fn io_read_octet_eom(
1011 &mut self,
1012 user: &AsynUser,
1013 buf: &mut [u8],
1014 ) -> AsynResult<(usize, EomReason)> {
1015 let cap = buf.len();
1016 let n = self.io_read_octet(user, buf)?;
1017 let eom = if n >= cap && cap > 0 {
1018 EomReason::CNT
1019 } else {
1020 EomReason::empty()
1021 };
1022 Ok((n, eom))
1023 }
1024
1025 fn io_write_octet(&mut self, user: &mut AsynUser, data: &[u8]) -> AsynResult<()> {
1026 self.write_octet(user, data)
1027 }
1028
1029 fn io_read_int32(&mut self, user: &AsynUser) -> AsynResult<i32> {
1030 self.read_int32(user)
1031 }
1032
1033 fn io_write_int32(&mut self, user: &mut AsynUser, value: i32) -> AsynResult<()> {
1034 self.write_int32(user, value)
1035 }
1036
1037 fn io_read_int64(&mut self, user: &AsynUser) -> AsynResult<i64> {
1038 self.read_int64(user)
1039 }
1040
1041 fn io_write_int64(&mut self, user: &mut AsynUser, value: i64) -> AsynResult<()> {
1042 self.write_int64(user, value)
1043 }
1044
1045 fn io_read_float64(&mut self, user: &AsynUser) -> AsynResult<f64> {
1046 self.read_float64(user)
1047 }
1048
1049 fn io_write_float64(&mut self, user: &mut AsynUser, value: f64) -> AsynResult<()> {
1050 self.write_float64(user, value)
1051 }
1052
1053 fn io_read_uint32_digital(&mut self, user: &AsynUser, mask: u32) -> AsynResult<u32> {
1054 self.read_uint32_digital(user, mask)
1055 }
1056
1057 fn io_write_uint32_digital(
1058 &mut self,
1059 user: &mut AsynUser,
1060 value: u32,
1061 mask: u32,
1062 ) -> AsynResult<()> {
1063 self.write_uint32_digital(user, value, mask)
1064 }
1065
1066 fn io_flush(&mut self, _user: &mut AsynUser) -> AsynResult<()> {
1067 Ok(())
1068 }
1069
1070 fn set_input_eos(&mut self, eos: &[u8]) -> AsynResult<()> {
1096 if eos.len() > 2 {
1097 return Err(AsynError::Status {
1098 status: AsynStatus::Error,
1099 message: format!("illegal eoslen {}", eos.len()),
1100 });
1101 }
1102 self.base_mut().input_eos = eos.to_vec();
1103 Ok(())
1104 }
1105
1106 fn get_input_eos(&self) -> Vec<u8> {
1107 self.base().input_eos.clone()
1108 }
1109
1110 fn set_output_eos(&mut self, eos: &[u8]) -> AsynResult<()> {
1111 if eos.len() > 2 {
1112 return Err(AsynError::Status {
1113 status: AsynStatus::Error,
1114 message: format!("illegal eoslen {}", eos.len()),
1115 });
1116 }
1117 self.base_mut().output_eos = eos.to_vec();
1118 Ok(())
1119 }
1120
1121 fn get_output_eos(&self) -> Vec<u8> {
1122 self.base().output_eos.clone()
1123 }
1124
1125 fn shutdown(&mut self) -> AsynResult<()> {
1130 Ok(())
1131 }
1132
1133 fn drv_user_create(&self, drv_info: &str) -> AsynResult<usize> {
1138 self.base()
1139 .params
1140 .find_param(drv_info)
1141 .ok_or_else(|| AsynError::ParamNotFound(drv_info.to_string()))
1142 }
1143
1144 fn capabilities(&self) -> Vec<crate::interfaces::Capability> {
1149 crate::interfaces::default_capabilities()
1150 }
1151
1152 fn supports(&self, cap: crate::interfaces::Capability) -> bool {
1154 self.capabilities().contains(&cap)
1155 }
1156
1157 fn init(&mut self) -> AsynResult<()> {
1158 Ok(())
1159 }
1160}
1161
1162#[cfg(test)]
1163mod tests {
1164 use super::*;
1165 struct TestDriver {
1166 base: PortDriverBase,
1167 }
1168
1169 impl TestDriver {
1170 fn new() -> Self {
1171 let mut base = PortDriverBase::new("test", 1, PortFlags::default());
1172 base.create_param("VAL", ParamType::Int32).unwrap();
1173 base.create_param("TEMP", ParamType::Float64).unwrap();
1174 base.create_param("MSG", ParamType::Octet).unwrap();
1175 base.create_param("BITS", ParamType::UInt32Digital).unwrap();
1176 Self { base }
1177 }
1178 }
1179
1180 impl PortDriver for TestDriver {
1181 fn base(&self) -> &PortDriverBase {
1182 &self.base
1183 }
1184 fn base_mut(&mut self) -> &mut PortDriverBase {
1185 &mut self.base
1186 }
1187 }
1188
1189 #[test]
1190 fn test_default_read_write_int32() {
1191 let mut drv = TestDriver::new();
1192 let mut user = AsynUser::new(0);
1193 drv.write_int32(&mut user, 42).unwrap();
1194 let user = AsynUser::new(0);
1195 assert_eq!(drv.read_int32(&user).unwrap(), 42);
1196 }
1197
1198 #[test]
1199 fn test_default_read_write_float64() {
1200 let mut drv = TestDriver::new();
1201 let mut user = AsynUser::new(1);
1202 drv.write_float64(&mut user, 3.14).unwrap();
1203 let user = AsynUser::new(1);
1204 assert!((drv.read_float64(&user).unwrap() - 3.14).abs() < 1e-10);
1205 }
1206
1207 #[test]
1208 fn test_default_read_write_octet() {
1209 let mut drv = TestDriver::new();
1210 let mut user = AsynUser::new(2);
1211 drv.write_octet(&mut user, b"hello").unwrap();
1212 let user = AsynUser::new(2);
1213 let mut buf = [0u8; 32];
1214 let n = drv.read_octet(&user, &mut buf).unwrap();
1215 assert_eq!(&buf[..n], b"hello");
1216 }
1217
1218 #[test]
1219 fn test_default_read_write_uint32() {
1220 let mut drv = TestDriver::new();
1221 let mut user = AsynUser::new(3);
1222 drv.write_uint32_digital(&mut user, 0xFF, 0x0F).unwrap();
1223 let user = AsynUser::new(3);
1224 assert_eq!(drv.read_uint32_digital(&user, 0xFF).unwrap(), 0x0F);
1225 }
1226
1227 #[test]
1228 fn test_connect_disconnect() {
1229 let mut drv = TestDriver::new();
1230 let user = AsynUser::default();
1231 assert!(drv.base().connected);
1232 drv.disconnect(&user).unwrap();
1233 assert!(!drv.base().connected);
1234 drv.connect(&user).unwrap();
1235 assert!(drv.base().connected);
1236 }
1237
1238 #[test]
1239 fn test_drv_user_create() {
1240 let drv = TestDriver::new();
1241 assert_eq!(drv.drv_user_create("VAL").unwrap(), 0);
1242 assert_eq!(drv.drv_user_create("TEMP").unwrap(), 1);
1243 assert!(drv.drv_user_create("NOPE").is_err());
1244 }
1245
1246 #[test]
1247 fn test_call_param_callbacks() {
1248 let mut drv = TestDriver::new();
1249 let mut rx = drv.base_mut().interrupts.subscribe_async();
1250
1251 drv.base_mut().set_int32_param(0, 0, 100).unwrap();
1252 drv.base_mut().set_float64_param(1, 0, 2.0).unwrap();
1253 drv.base_mut().call_param_callbacks(0).unwrap();
1254
1255 let v1 = rx.try_recv().unwrap();
1256 assert_eq!(v1.reason, 0);
1257 let v2 = rx.try_recv().unwrap();
1258 assert_eq!(v2.reason, 1);
1259 assert!(rx.try_recv().is_err());
1260 }
1261
1262 #[test]
1263 fn test_call_param_callbacks_propagates_aux_status_and_alarm() {
1264 let mut drv = TestDriver::new();
1269 let mut rx = drv.base_mut().interrupts.subscribe_async();
1270
1271 drv.base_mut().set_int32_param(0, 0, 99).unwrap();
1272 drv.base_mut()
1273 .params
1274 .set_param_status(0, 0, crate::error::AsynStatus::Timeout, 4, 2)
1275 .unwrap();
1276 drv.base_mut().call_param_callbacks(0).unwrap();
1277
1278 let iv = rx.try_recv().unwrap();
1279 assert_eq!(iv.reason, 0);
1280 assert!(matches!(iv.aux_status, crate::error::AsynStatus::Timeout));
1281 assert_eq!(iv.alarm_status, 4);
1282 assert_eq!(iv.alarm_severity, 2);
1283 }
1284
1285 #[test]
1286 fn test_call_param_callback_single_propagates_aux_status() {
1287 let mut drv = TestDriver::new();
1289 let mut rx = drv.base_mut().interrupts.subscribe_async();
1290
1291 drv.base_mut().set_int32_param(0, 0, 1).unwrap();
1292 drv.base_mut()
1293 .params
1294 .set_param_status(0, 0, crate::error::AsynStatus::Disconnected, 7, 3)
1295 .unwrap();
1296 drv.base_mut().call_param_callback(0, 0).unwrap();
1297
1298 let iv = rx.try_recv().unwrap();
1299 assert!(matches!(
1300 iv.aux_status,
1301 crate::error::AsynStatus::Disconnected
1302 ));
1303 assert_eq!(iv.alarm_status, 7);
1304 assert_eq!(iv.alarm_severity, 3);
1305 }
1306
1307 #[test]
1308 fn test_no_callback_for_unchanged() {
1309 let mut drv = TestDriver::new();
1310 let mut rx = drv.base_mut().interrupts.subscribe_async();
1311
1312 drv.base_mut().set_int32_param(0, 0, 5).unwrap();
1313 drv.base_mut().call_param_callbacks(0).unwrap();
1314 let _ = rx.try_recv().unwrap(); drv.base_mut().set_int32_param(0, 0, 5).unwrap();
1318 drv.base_mut().call_param_callbacks(0).unwrap();
1319 assert!(rx.try_recv().is_err());
1320 }
1321
1322 #[test]
1323 fn test_array_not_supported_by_default() {
1324 let mut drv = TestDriver::new();
1325 let user = AsynUser::new(0);
1326 let mut buf = [0f64; 10];
1327 assert!(drv.read_float64_array(&user, &mut buf).is_err());
1328 assert!(drv.write_float64_array(&user, &[1.0]).is_err());
1329 }
1330
1331 #[test]
1332 fn test_option_set_get() {
1333 let mut drv = TestDriver::new();
1334 drv.set_option("baud", "9600").unwrap();
1335 assert_eq!(drv.get_option("baud").unwrap(), "9600");
1336 drv.set_option("baud", "115200").unwrap();
1337 assert_eq!(drv.get_option("baud").unwrap(), "115200");
1338 }
1339
1340 #[test]
1341 fn test_option_not_found() {
1342 let drv = TestDriver::new();
1343 let err = drv.get_option("nonexistent").unwrap_err();
1344 assert!(matches!(err, AsynError::OptionNotFound(_)));
1345 }
1346
1347 #[test]
1348 fn test_report_no_panic() {
1349 let mut drv = TestDriver::new();
1350 drv.set_option("testkey", "testval").unwrap();
1351 drv.base_mut().set_int32_param(0, 0, 42).unwrap();
1352 for level in 0..=3 {
1353 drv.report(level);
1354 }
1355 }
1356
1357 #[test]
1358 fn test_callback_uses_param_timestamp() {
1359 let mut drv = TestDriver::new();
1360 let mut rx = drv.base_mut().interrupts.subscribe_async();
1361
1362 let custom_ts = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_000_000);
1363 drv.base_mut().set_int32_param(0, 0, 77).unwrap();
1364 drv.base_mut().set_param_timestamp(0, 0, custom_ts).unwrap();
1365 drv.base_mut().call_param_callbacks(0).unwrap();
1366
1367 let v = rx.try_recv().unwrap();
1368 assert_eq!(v.reason, 0);
1369 assert_eq!(v.timestamp, custom_ts);
1370 }
1371
1372 #[test]
1373 fn test_default_read_write_enum() {
1374 use crate::param::EnumEntry;
1375
1376 let mut base = PortDriverBase::new("test_enum", 1, PortFlags::default());
1377 base.create_param("MODE", ParamType::Enum).unwrap();
1378
1379 struct EnumDriver {
1380 base: PortDriverBase,
1381 }
1382 impl PortDriver for EnumDriver {
1383 fn base(&self) -> &PortDriverBase {
1384 &self.base
1385 }
1386 fn base_mut(&mut self) -> &mut PortDriverBase {
1387 &mut self.base
1388 }
1389 }
1390
1391 let mut drv = EnumDriver { base };
1392 let choices: Arc<[EnumEntry]> = Arc::from(vec![
1393 EnumEntry {
1394 string: "Off".into(),
1395 value: 0,
1396 severity: 0,
1397 },
1398 EnumEntry {
1399 string: "On".into(),
1400 value: 1,
1401 severity: 0,
1402 },
1403 ]);
1404 let mut user = AsynUser::new(0);
1405 drv.write_enum_choices(&mut user, choices).unwrap();
1406 drv.write_enum(&mut user, 1).unwrap();
1407 let (idx, ch) = drv.read_enum(&AsynUser::new(0)).unwrap();
1408 assert_eq!(idx, 1);
1409 assert_eq!(ch[1].string, "On");
1410 }
1411
1412 #[test]
1413 fn test_enum_callback() {
1414 use crate::param::{EnumEntry, ParamValue};
1415
1416 let mut base = PortDriverBase::new("test_enum_cb", 1, PortFlags::default());
1417 base.create_param("MODE", ParamType::Enum).unwrap();
1418 let mut rx = base.interrupts.subscribe_async();
1419
1420 struct EnumDriver {
1421 base: PortDriverBase,
1422 }
1423 impl PortDriver for EnumDriver {
1424 fn base(&self) -> &PortDriverBase {
1425 &self.base
1426 }
1427 fn base_mut(&mut self) -> &mut PortDriverBase {
1428 &mut self.base
1429 }
1430 }
1431
1432 let mut drv = EnumDriver { base };
1433 let choices: Arc<[EnumEntry]> = Arc::from(vec![
1434 EnumEntry {
1435 string: "A".into(),
1436 value: 0,
1437 severity: 0,
1438 },
1439 EnumEntry {
1440 string: "B".into(),
1441 value: 1,
1442 severity: 0,
1443 },
1444 ]);
1445 drv.base_mut()
1446 .set_enum_choices_param(0, 0, choices)
1447 .unwrap();
1448 drv.base_mut().set_enum_index_param(0, 0, 1).unwrap();
1449 drv.base_mut().call_param_callbacks(0).unwrap();
1450
1451 let v = rx.try_recv().unwrap();
1452 assert_eq!(v.reason, 0);
1453 assert!(matches!(v.value, ParamValue::Enum { index: 1, .. }));
1454 }
1455
1456 #[test]
1457 fn test_default_read_write_generic_pointer() {
1458 let mut base = PortDriverBase::new("test_gp", 1, PortFlags::default());
1459 base.create_param("PTR", ParamType::GenericPointer).unwrap();
1460
1461 struct GpDriver {
1462 base: PortDriverBase,
1463 }
1464 impl PortDriver for GpDriver {
1465 fn base(&self) -> &PortDriverBase {
1466 &self.base
1467 }
1468 fn base_mut(&mut self) -> &mut PortDriverBase {
1469 &mut self.base
1470 }
1471 }
1472
1473 let mut drv = GpDriver { base };
1474 let data: Arc<dyn std::any::Any + Send + Sync> = Arc::new(99i32);
1475 let mut user = AsynUser::new(0);
1476 drv.write_generic_pointer(&mut user, data).unwrap();
1477 let val = drv.read_generic_pointer(&AsynUser::new(0)).unwrap();
1478 assert_eq!(*val.downcast_ref::<i32>().unwrap(), 99);
1479 }
1480
1481 #[test]
1482 fn test_generic_pointer_callback() {
1483 use crate::param::ParamValue;
1484
1485 let mut base = PortDriverBase::new("test_gp_cb", 1, PortFlags::default());
1486 base.create_param("PTR", ParamType::GenericPointer).unwrap();
1487 let mut rx = base.interrupts.subscribe_async();
1488
1489 struct GpDriver {
1490 base: PortDriverBase,
1491 }
1492 impl PortDriver for GpDriver {
1493 fn base(&self) -> &PortDriverBase {
1494 &self.base
1495 }
1496 fn base_mut(&mut self) -> &mut PortDriverBase {
1497 &mut self.base
1498 }
1499 }
1500
1501 let mut drv = GpDriver { base };
1502 let data: Arc<dyn std::any::Any + Send + Sync> = Arc::new(vec![1, 2, 3]);
1503 drv.base_mut()
1504 .set_generic_pointer_param(0, 0, data)
1505 .unwrap();
1506 drv.base_mut().call_param_callbacks(0).unwrap();
1507
1508 let v = rx.try_recv().unwrap();
1509 assert_eq!(v.reason, 0);
1510 assert!(matches!(v.value, ParamValue::GenericPointer(_)));
1511 }
1512
1513 #[test]
1514 fn test_interpose_push_requires_lock() {
1515 use crate::interpose::{OctetInterpose, OctetNext, OctetReadResult};
1516 use parking_lot::Mutex;
1517 use std::sync::Arc;
1518
1519 struct NoopInterpose;
1520 impl OctetInterpose for NoopInterpose {
1521 fn read(
1522 &mut self,
1523 user: &AsynUser,
1524 buf: &mut [u8],
1525 next: &mut dyn OctetNext,
1526 ) -> AsynResult<OctetReadResult> {
1527 next.read(user, buf)
1528 }
1529 fn write(
1530 &mut self,
1531 user: &mut AsynUser,
1532 data: &[u8],
1533 next: &mut dyn OctetNext,
1534 ) -> AsynResult<usize> {
1535 next.write(user, data)
1536 }
1537 fn flush(&mut self, user: &mut AsynUser, next: &mut dyn OctetNext) -> AsynResult<()> {
1538 next.flush(user)
1539 }
1540 }
1541
1542 let port: Arc<Mutex<dyn PortDriver>> = Arc::new(Mutex::new(TestDriver::new()));
1543
1544 {
1545 let mut guard = port.lock();
1546 guard
1547 .base_mut()
1548 .push_octet_interpose(Box::new(NoopInterpose));
1549 assert_eq!(guard.base().interpose_octet.len(), 1);
1550 }
1551 }
1552
1553 #[test]
1554 fn test_default_read_write_int64() {
1555 let mut base = PortDriverBase::new("test_i64", 1, PortFlags::default());
1556 base.create_param("BIG", ParamType::Int64).unwrap();
1557
1558 struct I64Driver {
1559 base: PortDriverBase,
1560 }
1561 impl PortDriver for I64Driver {
1562 fn base(&self) -> &PortDriverBase {
1563 &self.base
1564 }
1565 fn base_mut(&mut self) -> &mut PortDriverBase {
1566 &mut self.base
1567 }
1568 }
1569
1570 let mut drv = I64Driver { base };
1571 let mut user = AsynUser::new(0);
1572 drv.write_int64(&mut user, i64::MAX).unwrap();
1573 assert_eq!(drv.read_int64(&AsynUser::new(0)).unwrap(), i64::MAX);
1574 }
1575
1576 #[test]
1577 fn test_get_bounds_int64_default() {
1578 let base = PortDriverBase::new("test_bounds", 1, PortFlags::default());
1579 struct BoundsDriver {
1580 base: PortDriverBase,
1581 }
1582 impl PortDriver for BoundsDriver {
1583 fn base(&self) -> &PortDriverBase {
1584 &self.base
1585 }
1586 fn base_mut(&mut self) -> &mut PortDriverBase {
1587 &mut self.base
1588 }
1589 }
1590 let drv = BoundsDriver { base };
1591 let (lo, hi) = drv.get_bounds_int64(&AsynUser::default()).unwrap();
1592 assert_eq!(lo, i64::MIN);
1593 assert_eq!(hi, i64::MAX);
1594 }
1595
1596 #[test]
1597 fn test_per_addr_device_state() {
1598 let mut base = PortDriverBase::new(
1599 "multi",
1600 4,
1601 PortFlags {
1602 multi_device: true,
1603 can_block: false,
1604 destructible: true,
1605 },
1606 );
1607 base.create_param("V", ParamType::Int32).unwrap();
1608
1609 assert!(base.is_device_connected(0));
1611 assert!(base.is_device_connected(1));
1612
1613 base.device_state(1).enabled = false;
1615 assert!(base.check_ready_addr(0).is_ok());
1616 let err = base.check_ready_addr(1).unwrap_err();
1617 assert!(format!("{err}").contains("disabled"));
1618
1619 base.device_state(2).connected = false;
1621 let err = base.check_ready_addr(2).unwrap_err();
1622 assert!(format!("{err}").contains("disconnected"));
1623 }
1624
1625 #[test]
1626 fn test_per_addr_single_device_ignored() {
1627 let mut base = PortDriverBase::new("single", 1, PortFlags::default());
1628 base.create_param("V", ParamType::Int32).unwrap();
1629 assert!(base.check_ready_addr(0).is_ok());
1631 }
1632
1633 #[test]
1634 fn test_timestamp_source() {
1635 let mut base = PortDriverBase::new("ts_test", 1, PortFlags::default());
1636 base.create_param("V", ParamType::Int32).unwrap();
1637
1638 let fixed_ts = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(999999);
1639 base.register_timestamp_source(move || fixed_ts);
1640
1641 assert_eq!(base.current_timestamp(), fixed_ts);
1642 }
1643
1644 #[test]
1645 fn test_timestamp_source_in_callbacks() {
1646 let mut base = PortDriverBase::new("ts_cb", 1, PortFlags::default());
1647 base.create_param("V", ParamType::Int32).unwrap();
1648 let mut rx = base.interrupts.subscribe_async();
1649
1650 let fixed_ts = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(123456);
1651 base.register_timestamp_source(move || fixed_ts);
1652
1653 struct TsDriver {
1654 base: PortDriverBase,
1655 }
1656 impl PortDriver for TsDriver {
1657 fn base(&self) -> &PortDriverBase {
1658 &self.base
1659 }
1660 fn base_mut(&mut self) -> &mut PortDriverBase {
1661 &mut self.base
1662 }
1663 }
1664 let mut drv = TsDriver { base };
1665 drv.base_mut().set_int32_param(0, 0, 42).unwrap();
1666 drv.base_mut().call_param_callbacks(0).unwrap();
1667
1668 let v = rx.try_recv().unwrap();
1669 assert_eq!(v.timestamp, fixed_ts);
1671 }
1672
1673 #[test]
1674 fn test_queue_priority_connect() {
1675 assert!(QueuePriority::Connect > QueuePriority::High);
1676 }
1677
1678 #[test]
1679 fn test_port_flags_destructible_default_is_opt_in() {
1680 let flags = PortFlags::default();
1686 assert!(
1687 !flags.destructible,
1688 "destructible must be opt-in (C parity)"
1689 );
1690 }
1691
1692 #[test]
1693 fn shutdown_lifecycle_refuses_non_destructible() {
1694 let mut base = PortDriverBase::new(
1695 "p_nondestr",
1696 1,
1697 PortFlags {
1698 multi_device: false,
1699 can_block: false,
1700 destructible: false,
1701 },
1702 );
1703 match base.shutdown_lifecycle() {
1704 Err(AsynError::Status { message, .. }) => {
1705 assert!(message.contains("ASYN_DESTRUCTIBLE"), "msg={message}");
1706 }
1707 other => panic!("expected ASYN_DESTRUCTIBLE refusal, got {other:?}"),
1708 }
1709 assert!(
1710 !base.is_defunct(),
1711 "non-destructible port must not flip defunct"
1712 );
1713 assert!(base.is_enabled(), "non-destructible port must stay enabled");
1714 }
1715
1716 #[test]
1717 fn shutdown_lifecycle_marks_destructible_defunct_and_idempotent() {
1718 let mut base = PortDriverBase::new(
1719 "p_destr",
1720 1,
1721 PortFlags {
1722 multi_device: false,
1723 can_block: false,
1724 destructible: true,
1725 },
1726 );
1727 assert!(base.is_enabled());
1728 assert!(!base.is_defunct());
1729 base.shutdown_lifecycle().unwrap();
1730 assert!(
1731 !base.is_enabled(),
1732 "shutdown_lifecycle must flip enabled=false"
1733 );
1734 assert!(
1735 base.is_defunct(),
1736 "shutdown_lifecycle must flip defunct=true"
1737 );
1738 base.shutdown_lifecycle().unwrap();
1740 assert!(base.is_defunct());
1741 match base.check_ready() {
1743 Err(AsynError::Status { message, .. }) => {
1744 assert!(message.contains("defunct"), "msg={message}");
1745 }
1746 other => panic!("expected defunct error, got {other:?}"),
1747 }
1748 }
1749
1750 #[test]
1753 fn test_connect_addr() {
1754 let mut base = PortDriverBase::new(
1755 "multi_conn",
1756 4,
1757 PortFlags {
1758 multi_device: true,
1759 can_block: false,
1760 destructible: true,
1761 },
1762 );
1763 base.create_param("V", ParamType::Int32).unwrap();
1764
1765 base.disconnect_addr(1);
1766 assert!(!base.is_device_connected(1));
1767 assert!(base.check_ready_addr(1).is_err());
1768
1769 base.connect_addr(1);
1770 assert!(base.is_device_connected(1));
1771 assert!(base.check_ready_addr(1).is_ok());
1772 }
1773
1774 #[test]
1775 fn test_enable_disable_addr() {
1776 let mut base = PortDriverBase::new(
1777 "multi_en",
1778 4,
1779 PortFlags {
1780 multi_device: true,
1781 can_block: false,
1782 destructible: true,
1783 },
1784 );
1785 base.create_param("V", ParamType::Int32).unwrap();
1786
1787 base.disable_addr(2);
1788 let err = base.check_ready_addr(2).unwrap_err();
1789 assert!(format!("{err}").contains("disabled"));
1790
1791 base.enable_addr(2);
1792 assert!(base.check_ready_addr(2).is_ok());
1793 }
1794
1795 #[test]
1796 fn test_port_level_overrides_addr() {
1797 let mut base = PortDriverBase::new(
1798 "multi_override",
1799 4,
1800 PortFlags {
1801 multi_device: true,
1802 can_block: false,
1803 destructible: true,
1804 },
1805 );
1806 base.create_param("V", ParamType::Int32).unwrap();
1807
1808 base.enabled = false;
1810 base.enable_addr(0); let err = base.check_ready_addr(0).unwrap_err();
1812 assert!(format!("{err}").contains("disabled"));
1813 }
1814
1815 #[test]
1816 fn test_per_addr_exception_announced() {
1817 use std::sync::atomic::{AtomicI32, Ordering};
1818
1819 let mut base = PortDriverBase::new(
1820 "multi_exc",
1821 4,
1822 PortFlags {
1823 multi_device: true,
1824 can_block: false,
1825 destructible: true,
1826 },
1827 );
1828 base.create_param("V", ParamType::Int32).unwrap();
1829
1830 let exc_mgr = Arc::new(crate::exception::ExceptionManager::new());
1831 base.exception_sink = Some(exc_mgr.clone());
1832
1833 let last_addr = Arc::new(AtomicI32::new(-99));
1834 let last_addr2 = last_addr.clone();
1835 exc_mgr.add_callback(move |event| {
1836 last_addr2.store(event.addr, Ordering::Relaxed);
1837 });
1838
1839 base.disconnect_addr(3);
1840 assert_eq!(last_addr.load(Ordering::Relaxed), 3);
1841
1842 base.enable_addr(2);
1843 assert_eq!(last_addr.load(Ordering::Relaxed), 2);
1844 }
1845
1846 #[test]
1853 fn test_connect_disconnect_announce_only_on_transition() {
1854 use std::sync::atomic::{AtomicUsize, Ordering};
1855
1856 let mut base = PortDriverBase::new(
1857 "edge",
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 let exc_mgr = Arc::new(crate::exception::ExceptionManager::new());
1867 base.exception_sink = Some(exc_mgr.clone());
1868
1869 let connect_hits = Arc::new(AtomicUsize::new(0));
1870 let hits2 = connect_hits.clone();
1871 exc_mgr.add_callback(move |event| {
1872 if event.exception == AsynException::Connect {
1873 hits2.fetch_add(1, Ordering::Relaxed);
1874 }
1875 });
1876
1877 base.connect_addr(2);
1880 assert_eq!(
1881 connect_hits.load(Ordering::Relaxed),
1882 0,
1883 "redundant connect_addr must not fan out"
1884 );
1885
1886 base.disconnect_addr(2);
1888 assert_eq!(connect_hits.load(Ordering::Relaxed), 1);
1889
1890 base.disconnect_addr(2);
1892 assert_eq!(
1893 connect_hits.load(Ordering::Relaxed),
1894 1,
1895 "redundant disconnect_addr must not fan out"
1896 );
1897
1898 base.connect_addr(2);
1900 assert_eq!(connect_hits.load(Ordering::Relaxed), 2);
1901 }
1902
1903 #[test]
1908 fn test_set_auto_connect_fires_unconditionally() {
1909 use std::sync::atomic::{AtomicUsize, Ordering};
1910
1911 let mut base = PortDriverBase::new("ac", 1, PortFlags::default());
1912 let exc_mgr = Arc::new(crate::exception::ExceptionManager::new());
1913 base.exception_sink = Some(exc_mgr.clone());
1914 let hits = Arc::new(AtomicUsize::new(0));
1915 let hits2 = hits.clone();
1916 exc_mgr.add_callback(move |event| {
1917 if event.exception == AsynException::AutoConnect {
1918 hits2.fetch_add(1, Ordering::Relaxed);
1919 }
1920 });
1921 base.set_auto_connect(true);
1924 base.set_auto_connect(false);
1925 base.set_auto_connect(false);
1926 assert_eq!(hits.load(Ordering::Relaxed), 3);
1927 }
1928
1929 #[test]
1935 fn test_port_driver_uint32_interrupt_round_trip() {
1936 struct UInt32Drv {
1937 base: PortDriverBase,
1938 }
1939 impl PortDriver for UInt32Drv {
1940 fn base(&self) -> &PortDriverBase {
1941 &self.base
1942 }
1943 fn base_mut(&mut self) -> &mut PortDriverBase {
1944 &mut self.base
1945 }
1946 }
1947
1948 let mut base = PortDriverBase::new("uint32_int", 1, PortFlags::default());
1949 let idx = base
1950 .params
1951 .create_param("BITS", ParamType::UInt32Digital)
1952 .unwrap();
1953 let mut drv = UInt32Drv { base };
1954 let user = AsynUser::new(idx).with_addr(0);
1955
1956 drv.set_interrupt_uint32_digital(&user, 0xF0, InterruptReason::ZeroToOne)
1957 .unwrap();
1958 drv.set_interrupt_uint32_digital(&user, 0x0F, InterruptReason::OneToZero)
1959 .unwrap();
1960 assert_eq!(
1961 drv.get_interrupt_uint32_digital(&user, InterruptReason::Both)
1962 .unwrap(),
1963 0xFF
1964 );
1965 drv.clear_interrupt_uint32_digital(&user, 0x11).unwrap();
1966 assert_eq!(
1967 drv.get_interrupt_uint32_digital(&user, InterruptReason::ZeroToOne)
1968 .unwrap(),
1969 0xE0
1970 );
1971 assert_eq!(
1972 drv.get_interrupt_uint32_digital(&user, InterruptReason::OneToZero)
1973 .unwrap(),
1974 0x0E
1975 );
1976 }
1977}