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::{OctetInterpose, OctetInterposeStack};
43use crate::interrupt::{InterruptManager, InterruptValue};
44use crate::param::{EnumEntry, 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 is_enabled(&self) -> bool {
178 self.enabled
179 }
180
181 pub fn is_auto_connect(&self) -> bool {
183 self.auto_connect
184 }
185
186 pub fn is_defunct(&self) -> bool {
190 self.defunct
191 }
192
193 pub fn check_ready(&self) -> AsynResult<()> {
197 if self.defunct {
202 return Err(AsynError::Status {
203 status: AsynStatus::Disabled,
204 message: format!("port {} has been shut down (defunct)", self.port_name),
205 });
206 }
207 if !self.enabled {
208 return Err(AsynError::Status {
209 status: AsynStatus::Disabled,
210 message: format!("port {} is disabled", self.port_name),
211 });
212 }
213 if !self.connected {
214 return Err(AsynError::Status {
215 status: AsynStatus::Disconnected,
216 message: format!("port {} is disconnected", self.port_name),
217 });
218 }
219 Ok(())
220 }
221
222 pub fn shutdown_lifecycle(&mut self) -> AsynResult<()> {
238 if self.defunct {
239 return Ok(());
241 }
242 if !self.flags.destructible {
243 return Err(AsynError::Status {
244 status: AsynStatus::Error,
245 message: format!(
246 "port {} does not support shutting down (ASYN_DESTRUCTIBLE not set)",
247 self.port_name
248 ),
249 });
250 }
251 self.enabled = false;
252 self.defunct = true;
253 self.announce_exception(AsynException::Shutdown, -1);
254 Ok(())
255 }
256
257 pub fn check_ready_addr(&self, addr: i32) -> AsynResult<()> {
260 self.check_ready()?;
261 if self.flags.multi_device {
262 if let Some(ds) = self.device_states.get(&addr) {
263 if !ds.enabled {
264 return Err(AsynError::Status {
265 status: AsynStatus::Disabled,
266 message: format!("port {} addr {} is disabled", self.port_name, addr),
267 });
268 }
269 if !ds.connected {
270 return Err(AsynError::Status {
271 status: AsynStatus::Disconnected,
272 message: format!("port {} addr {} is disconnected", self.port_name, addr),
273 });
274 }
275 }
276 }
277 Ok(())
278 }
279
280 pub fn device_state(&mut self, addr: i32) -> &mut DeviceState {
282 self.device_states.entry(addr).or_default()
283 }
284
285 pub fn is_device_connected(&self, addr: i32) -> bool {
287 self.device_states
288 .get(&addr)
289 .map_or(true, |ds| ds.connected)
290 }
291
292 pub fn connect_addr(&mut self, addr: i32) {
294 self.device_state(addr).connected = true;
295 self.announce_exception(AsynException::Connect, addr);
296 }
297
298 pub fn disconnect_addr(&mut self, addr: i32) {
300 self.device_state(addr).connected = false;
301 self.announce_exception(AsynException::Connect, addr);
302 }
303
304 pub fn enable_addr(&mut self, addr: i32) {
306 self.device_state(addr).enabled = true;
307 self.announce_exception(AsynException::Enable, addr);
308 }
309
310 pub fn disable_addr(&mut self, addr: i32) {
312 self.device_state(addr).enabled = false;
313 self.announce_exception(AsynException::Enable, addr);
314 }
315
316 pub fn register_timestamp_source<F>(&mut self, source: F)
318 where
319 F: Fn() -> SystemTime + Send + Sync + 'static,
320 {
321 self.timestamp_source = Some(Arc::new(source));
322 }
323
324 pub fn current_timestamp(&self) -> SystemTime {
326 self.timestamp_source
327 .as_ref()
328 .map_or_else(SystemTime::now, |f| f())
329 }
330
331 pub fn create_param(&mut self, name: &str, param_type: ParamType) -> AsynResult<usize> {
332 self.params.create_param(name, param_type)
333 }
334
335 pub fn find_param(&self, name: &str) -> Option<usize> {
336 self.params.find_param(name)
337 }
338
339 pub fn set_int32_param(&mut self, index: usize, addr: i32, value: i32) -> AsynResult<()> {
342 self.params.set_int32(index, addr, value)
343 }
344
345 pub fn get_int32_param(&self, index: usize, addr: i32) -> AsynResult<i32> {
346 self.params.get_int32(index, addr)
347 }
348
349 pub fn set_int64_param(&mut self, index: usize, addr: i32, value: i64) -> AsynResult<()> {
350 self.params.set_int64(index, addr, value)
351 }
352
353 pub fn get_int64_param(&self, index: usize, addr: i32) -> AsynResult<i64> {
354 self.params.get_int64(index, addr)
355 }
356
357 pub fn set_float64_param(&mut self, index: usize, addr: i32, value: f64) -> AsynResult<()> {
358 self.params.set_float64(index, addr, value)
359 }
360
361 pub fn get_float64_param(&self, index: usize, addr: i32) -> AsynResult<f64> {
362 self.params.get_float64(index, addr)
363 }
364
365 pub fn set_string_param(&mut self, index: usize, addr: i32, value: String) -> AsynResult<()> {
366 self.params.set_string(index, addr, value)
367 }
368
369 pub fn get_string_param(&self, index: usize, addr: i32) -> AsynResult<&str> {
370 self.params.get_string(index, addr)
371 }
372
373 pub fn set_uint32_param(
374 &mut self,
375 index: usize,
376 addr: i32,
377 value: u32,
378 mask: u32,
379 ) -> AsynResult<()> {
380 self.params.set_uint32(index, addr, value, mask)
381 }
382
383 pub fn get_uint32_param(&self, index: usize, addr: i32) -> AsynResult<u32> {
384 self.params.get_uint32(index, addr)
385 }
386
387 pub fn get_enum_param(&self, index: usize, addr: i32) -> AsynResult<(usize, Arc<[EnumEntry]>)> {
388 self.params.get_enum(index, addr)
389 }
390
391 pub fn set_enum_index_param(
392 &mut self,
393 index: usize,
394 addr: i32,
395 value: usize,
396 ) -> AsynResult<()> {
397 self.params.set_enum_index(index, addr, value)
398 }
399
400 pub fn set_enum_choices_param(
401 &mut self,
402 index: usize,
403 addr: i32,
404 choices: Arc<[EnumEntry]>,
405 ) -> AsynResult<()> {
406 self.params.set_enum_choices(index, addr, choices)
407 }
408
409 pub fn get_generic_pointer_param(
410 &self,
411 index: usize,
412 addr: i32,
413 ) -> AsynResult<Arc<dyn Any + Send + Sync>> {
414 self.params.get_generic_pointer(index, addr)
415 }
416
417 pub fn set_generic_pointer_param(
418 &mut self,
419 index: usize,
420 addr: i32,
421 value: Arc<dyn Any + Send + Sync>,
422 ) -> AsynResult<()> {
423 self.params.set_generic_pointer(index, addr, value)
424 }
425
426 pub fn set_param_timestamp(
427 &mut self,
428 index: usize,
429 addr: i32,
430 ts: SystemTime,
431 ) -> AsynResult<()> {
432 self.params.set_timestamp(index, addr, ts)
433 }
434
435 pub fn set_param_status(
436 &mut self,
437 index: usize,
438 addr: i32,
439 status: AsynStatus,
440 alarm_status: u16,
441 alarm_severity: u16,
442 ) -> AsynResult<()> {
443 self.params
444 .set_param_status(index, addr, status, alarm_status, alarm_severity)
445 }
446
447 pub fn get_param_status(&self, index: usize, addr: i32) -> AsynResult<(AsynStatus, u16, u16)> {
448 self.params.get_param_status(index, addr)
449 }
450
451 pub fn report_params(&self, level: i32) {
453 eprintln!(" Number of parameters is {}", self.params.len());
454 if level < 1 {
455 return;
456 }
457 for i in 0..self.params.len() {
458 let name = self.params.param_name(i).unwrap_or("?");
459 let ptype = self
460 .params
461 .param_type(i)
462 .map(|t| format!("{t:?}"))
463 .unwrap_or("?".into());
464 if level >= 2 {
465 for addr in 0..self.max_addr.max(1) {
466 let val = self
467 .params
468 .get_value(i, addr as i32)
469 .map(|v| format!("{v:?}"))
470 .unwrap_or("undefined".into());
471 let (status, alarm_st, alarm_sev) = self
472 .params
473 .get_param_status(i, addr as i32)
474 .unwrap_or((AsynStatus::Success, 0, 0));
475 eprintln!(
476 " param[{i}] name={name} type={ptype} addr={addr} val={val} status={status:?} alarm=({alarm_st},{alarm_sev})"
477 );
478 }
479 } else {
480 eprintln!(" param[{i}] name={name} type={ptype}");
481 }
482 }
483 }
484
485 pub fn push_octet_interpose(&mut self, layer: Box<dyn OctetInterpose>) {
491 self.interpose_octet.push(layer);
492 }
493
494 pub fn call_param_callbacks(&mut self, addr: i32) -> AsynResult<()> {
497 let changed = self.params.take_changed(addr)?;
498 let now = self.current_timestamp();
499 for reason in changed {
500 let value = self.params.get_value(reason, addr)?.clone();
501 let ts = self.params.get_timestamp(reason, addr)?.unwrap_or(now);
502 let uint32_mask = self
503 .params
504 .get_uint32_interrupt_mask(reason, addr)
505 .unwrap_or(0);
506 self.interrupts.notify(InterruptValue {
507 reason,
508 addr,
509 value,
510 timestamp: ts,
511 uint32_changed_mask: uint32_mask,
512 });
513 }
514 Ok(())
515 }
516
517 pub fn call_param_callback(&mut self, addr: i32, reason: usize) -> AsynResult<()> {
521 if self.params.take_changed_single(reason, addr)? {
522 let now = self.current_timestamp();
523 let value = self.params.get_value(reason, addr)?.clone();
524 let ts = self.params.get_timestamp(reason, addr)?.unwrap_or(now);
525 let uint32_mask = self
526 .params
527 .get_uint32_interrupt_mask(reason, addr)
528 .unwrap_or(0);
529 self.interrupts.notify(InterruptValue {
530 reason,
531 addr,
532 value,
533 timestamp: ts,
534 uint32_changed_mask: uint32_mask,
535 });
536 }
537 Ok(())
538 }
539
540 pub fn mark_param_changed(&mut self, index: usize, addr: i32) -> AsynResult<()> {
545 self.params.mark_changed(index, addr)
546 }
547}
548
549pub trait PortDriver: Send + Sync + 'static {
564 fn base(&self) -> &PortDriverBase;
565 fn base_mut(&mut self) -> &mut PortDriverBase;
566
567 fn connect(&mut self, _user: &AsynUser) -> AsynResult<()> {
570 self.base_mut().connected = true;
571 self.base().announce_exception(AsynException::Connect, -1);
572 Ok(())
573 }
574
575 fn disconnect(&mut self, _user: &AsynUser) -> AsynResult<()> {
576 self.base_mut().connected = false;
577 self.base().announce_exception(AsynException::Connect, -1);
578 Ok(())
579 }
580
581 fn enable(&mut self, _user: &AsynUser) -> AsynResult<()> {
582 self.base_mut().enabled = true;
583 self.base().announce_exception(AsynException::Enable, -1);
584 Ok(())
585 }
586
587 fn disable(&mut self, _user: &AsynUser) -> AsynResult<()> {
588 self.base_mut().enabled = false;
589 self.base().announce_exception(AsynException::Enable, -1);
590 Ok(())
591 }
592
593 fn connect_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
594 self.base_mut().connect_addr(user.addr);
595 Ok(())
596 }
597
598 fn disconnect_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
599 self.base_mut().disconnect_addr(user.addr);
600 Ok(())
601 }
602
603 fn enable_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
604 self.base_mut().enable_addr(user.addr);
605 Ok(())
606 }
607
608 fn disable_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
609 self.base_mut().disable_addr(user.addr);
610 Ok(())
611 }
612
613 fn get_option(&self, key: &str) -> AsynResult<String> {
614 self.base()
615 .options
616 .get(key)
617 .cloned()
618 .ok_or_else(|| AsynError::OptionNotFound(key.to_string()))
619 }
620
621 fn set_option(&mut self, key: &str, value: &str) -> AsynResult<()> {
622 self.base_mut()
623 .options
624 .insert(key.to_string(), value.to_string());
625 Ok(())
626 }
627
628 fn report(&self, level: i32) {
629 let base = self.base();
630 eprintln!("Port: {}", base.port_name);
631 eprintln!(
632 " connected: {}, max_addr: {}, params: {}, options: {}",
633 base.connected,
634 base.max_addr,
635 base.params.len(),
636 base.options.len()
637 );
638 if level >= 1 {
639 base.report_params(level.saturating_sub(1));
640 }
641 if level >= 2 {
642 for (k, v) in &base.options {
643 eprintln!(" option: {k} = {v}");
644 }
645 }
646 }
647
648 fn read_int32(&mut self, user: &AsynUser) -> AsynResult<i32> {
655 self.base().params.get_int32(user.reason, user.addr)
656 }
657
658 fn write_int32(&mut self, user: &mut AsynUser, value: i32) -> AsynResult<()> {
659 self.base_mut()
660 .params
661 .set_int32(user.reason, user.addr, value)?;
662 self.base_mut().call_param_callbacks(user.addr)
663 }
664
665 fn read_int64(&mut self, user: &AsynUser) -> AsynResult<i64> {
666 self.base().params.get_int64(user.reason, user.addr)
667 }
668
669 fn write_int64(&mut self, user: &mut AsynUser, value: i64) -> AsynResult<()> {
670 self.base_mut()
671 .params
672 .set_int64(user.reason, user.addr, value)?;
673 self.base_mut().call_param_callbacks(user.addr)
674 }
675
676 fn get_bounds_int32(&self, _user: &AsynUser) -> AsynResult<(i32, i32)> {
677 Ok((i32::MIN, i32::MAX))
678 }
679
680 fn get_bounds_int64(&self, _user: &AsynUser) -> AsynResult<(i64, i64)> {
681 Ok((i64::MIN, i64::MAX))
682 }
683
684 fn read_float64(&mut self, user: &AsynUser) -> AsynResult<f64> {
685 self.base().params.get_float64(user.reason, user.addr)
686 }
687
688 fn write_float64(&mut self, user: &mut AsynUser, value: f64) -> AsynResult<()> {
689 self.base_mut()
690 .params
691 .set_float64(user.reason, user.addr, value)?;
692 self.base_mut().call_param_callbacks(user.addr)
693 }
694
695 fn read_octet(&mut self, user: &AsynUser, buf: &mut [u8]) -> AsynResult<usize> {
696 let s = self.base().params.get_string(user.reason, user.addr)?;
697 let bytes = s.as_bytes();
698 let n = bytes.len().min(buf.len());
699 buf[..n].copy_from_slice(&bytes[..n]);
700 Ok(n)
701 }
702
703 fn write_octet(&mut self, user: &mut AsynUser, data: &[u8]) -> AsynResult<()> {
704 let s = String::from_utf8_lossy(data).into_owned();
705 self.base_mut()
706 .params
707 .set_string(user.reason, user.addr, s)?;
708 self.base_mut().call_param_callbacks(user.addr)
709 }
710
711 fn read_uint32_digital(&mut self, user: &AsynUser, mask: u32) -> AsynResult<u32> {
712 let val = self.base().params.get_uint32(user.reason, user.addr)?;
713 Ok(val & mask)
714 }
715
716 fn write_uint32_digital(
717 &mut self,
718 user: &mut AsynUser,
719 value: u32,
720 mask: u32,
721 ) -> AsynResult<()> {
722 self.base_mut()
723 .params
724 .set_uint32(user.reason, user.addr, value, mask)?;
725 self.base_mut().call_param_callbacks(user.addr)
726 }
727
728 fn read_enum(&mut self, user: &AsynUser) -> AsynResult<(usize, Arc<[EnumEntry]>)> {
731 self.base().params.get_enum(user.reason, user.addr)
732 }
733
734 fn write_enum(&mut self, user: &mut AsynUser, index: usize) -> AsynResult<()> {
735 self.base_mut()
736 .params
737 .set_enum_index(user.reason, user.addr, index)?;
738 self.base_mut().call_param_callbacks(user.addr)
739 }
740
741 fn write_enum_choices(
742 &mut self,
743 user: &mut AsynUser,
744 choices: Arc<[EnumEntry]>,
745 ) -> AsynResult<()> {
746 self.base_mut()
747 .params
748 .set_enum_choices(user.reason, user.addr, choices)?;
749 self.base_mut().call_param_callbacks(user.addr)
750 }
751
752 fn read_generic_pointer(&mut self, user: &AsynUser) -> AsynResult<Arc<dyn Any + Send + Sync>> {
755 self.base()
756 .params
757 .get_generic_pointer(user.reason, user.addr)
758 }
759
760 fn write_generic_pointer(
761 &mut self,
762 user: &mut AsynUser,
763 value: Arc<dyn Any + Send + Sync>,
764 ) -> AsynResult<()> {
765 self.base_mut()
766 .params
767 .set_generic_pointer(user.reason, user.addr, value)?;
768 self.base_mut().call_param_callbacks(user.addr)
769 }
770
771 fn read_float64_array(&mut self, _user: &AsynUser, _buf: &mut [f64]) -> AsynResult<usize> {
774 Err(AsynError::InterfaceNotSupported("asynFloat64Array".into()))
775 }
776
777 fn write_float64_array(&mut self, user: &AsynUser, data: &[f64]) -> AsynResult<()> {
778 self.base_mut()
779 .params
780 .set_float64_array(user.reason, user.addr, data.to_vec())?;
781 self.base_mut().call_param_callbacks(user.addr)
782 }
783
784 fn read_int32_array(&mut self, _user: &AsynUser, _buf: &mut [i32]) -> AsynResult<usize> {
785 Err(AsynError::InterfaceNotSupported("asynInt32Array".into()))
786 }
787
788 fn write_int32_array(&mut self, user: &AsynUser, data: &[i32]) -> AsynResult<()> {
789 self.base_mut()
790 .params
791 .set_int32_array(user.reason, user.addr, data.to_vec())?;
792 self.base_mut().call_param_callbacks(user.addr)
793 }
794
795 fn read_int8_array(&mut self, _user: &AsynUser, _buf: &mut [i8]) -> AsynResult<usize> {
796 Err(AsynError::InterfaceNotSupported("asynInt8Array".into()))
797 }
798
799 fn write_int8_array(&mut self, user: &AsynUser, data: &[i8]) -> AsynResult<()> {
800 self.base_mut()
801 .params
802 .set_int8_array(user.reason, user.addr, data.to_vec())?;
803 self.base_mut().call_param_callbacks(user.addr)
804 }
805
806 fn read_int16_array(&mut self, _user: &AsynUser, _buf: &mut [i16]) -> AsynResult<usize> {
807 Err(AsynError::InterfaceNotSupported("asynInt16Array".into()))
808 }
809
810 fn write_int16_array(&mut self, user: &AsynUser, data: &[i16]) -> AsynResult<()> {
811 self.base_mut()
812 .params
813 .set_int16_array(user.reason, user.addr, data.to_vec())?;
814 self.base_mut().call_param_callbacks(user.addr)
815 }
816
817 fn read_int64_array(&mut self, _user: &AsynUser, _buf: &mut [i64]) -> AsynResult<usize> {
818 Err(AsynError::InterfaceNotSupported("asynInt64Array".into()))
819 }
820
821 fn write_int64_array(&mut self, user: &AsynUser, data: &[i64]) -> AsynResult<()> {
822 self.base_mut()
823 .params
824 .set_int64_array(user.reason, user.addr, data.to_vec())?;
825 self.base_mut().call_param_callbacks(user.addr)
826 }
827
828 fn read_float32_array(&mut self, _user: &AsynUser, _buf: &mut [f32]) -> AsynResult<usize> {
829 Err(AsynError::InterfaceNotSupported("asynFloat32Array".into()))
830 }
831
832 fn write_float32_array(&mut self, user: &AsynUser, data: &[f32]) -> AsynResult<()> {
833 self.base_mut()
834 .params
835 .set_float32_array(user.reason, user.addr, data.to_vec())?;
836 self.base_mut().call_param_callbacks(user.addr)
837 }
838
839 fn io_read_octet(&mut self, user: &AsynUser, buf: &mut [u8]) -> AsynResult<usize> {
844 self.read_octet(user, buf)
845 }
846
847 fn io_write_octet(&mut self, user: &mut AsynUser, data: &[u8]) -> AsynResult<()> {
848 self.write_octet(user, data)
849 }
850
851 fn io_read_int32(&mut self, user: &AsynUser) -> AsynResult<i32> {
852 self.read_int32(user)
853 }
854
855 fn io_write_int32(&mut self, user: &mut AsynUser, value: i32) -> AsynResult<()> {
856 self.write_int32(user, value)
857 }
858
859 fn io_read_int64(&mut self, user: &AsynUser) -> AsynResult<i64> {
860 self.read_int64(user)
861 }
862
863 fn io_write_int64(&mut self, user: &mut AsynUser, value: i64) -> AsynResult<()> {
864 self.write_int64(user, value)
865 }
866
867 fn io_read_float64(&mut self, user: &AsynUser) -> AsynResult<f64> {
868 self.read_float64(user)
869 }
870
871 fn io_write_float64(&mut self, user: &mut AsynUser, value: f64) -> AsynResult<()> {
872 self.write_float64(user, value)
873 }
874
875 fn io_read_uint32_digital(&mut self, user: &AsynUser, mask: u32) -> AsynResult<u32> {
876 self.read_uint32_digital(user, mask)
877 }
878
879 fn io_write_uint32_digital(
880 &mut self,
881 user: &mut AsynUser,
882 value: u32,
883 mask: u32,
884 ) -> AsynResult<()> {
885 self.write_uint32_digital(user, value, mask)
886 }
887
888 fn io_flush(&mut self, _user: &mut AsynUser) -> AsynResult<()> {
889 Ok(())
890 }
891
892 fn set_input_eos(&mut self, eos: &[u8]) -> AsynResult<()> {
918 if eos.len() > 2 {
919 return Err(AsynError::Status {
920 status: AsynStatus::Error,
921 message: format!("illegal eoslen {}", eos.len()),
922 });
923 }
924 self.base_mut().input_eos = eos.to_vec();
925 Ok(())
926 }
927
928 fn get_input_eos(&self) -> Vec<u8> {
929 self.base().input_eos.clone()
930 }
931
932 fn set_output_eos(&mut self, eos: &[u8]) -> AsynResult<()> {
933 if eos.len() > 2 {
934 return Err(AsynError::Status {
935 status: AsynStatus::Error,
936 message: format!("illegal eoslen {}", eos.len()),
937 });
938 }
939 self.base_mut().output_eos = eos.to_vec();
940 Ok(())
941 }
942
943 fn get_output_eos(&self) -> Vec<u8> {
944 self.base().output_eos.clone()
945 }
946
947 fn shutdown(&mut self) -> AsynResult<()> {
952 Ok(())
953 }
954
955 fn drv_user_create(&self, drv_info: &str) -> AsynResult<usize> {
960 self.base()
961 .params
962 .find_param(drv_info)
963 .ok_or_else(|| AsynError::ParamNotFound(drv_info.to_string()))
964 }
965
966 fn capabilities(&self) -> Vec<crate::interfaces::Capability> {
971 crate::interfaces::default_capabilities()
972 }
973
974 fn supports(&self, cap: crate::interfaces::Capability) -> bool {
976 self.capabilities().contains(&cap)
977 }
978
979 fn init(&mut self) -> AsynResult<()> {
980 Ok(())
981 }
982}
983
984#[cfg(test)]
985mod tests {
986 use super::*;
987 struct TestDriver {
988 base: PortDriverBase,
989 }
990
991 impl TestDriver {
992 fn new() -> Self {
993 let mut base = PortDriverBase::new("test", 1, PortFlags::default());
994 base.create_param("VAL", ParamType::Int32).unwrap();
995 base.create_param("TEMP", ParamType::Float64).unwrap();
996 base.create_param("MSG", ParamType::Octet).unwrap();
997 base.create_param("BITS", ParamType::UInt32Digital).unwrap();
998 Self { base }
999 }
1000 }
1001
1002 impl PortDriver for TestDriver {
1003 fn base(&self) -> &PortDriverBase {
1004 &self.base
1005 }
1006 fn base_mut(&mut self) -> &mut PortDriverBase {
1007 &mut self.base
1008 }
1009 }
1010
1011 #[test]
1012 fn test_default_read_write_int32() {
1013 let mut drv = TestDriver::new();
1014 let mut user = AsynUser::new(0);
1015 drv.write_int32(&mut user, 42).unwrap();
1016 let user = AsynUser::new(0);
1017 assert_eq!(drv.read_int32(&user).unwrap(), 42);
1018 }
1019
1020 #[test]
1021 fn test_default_read_write_float64() {
1022 let mut drv = TestDriver::new();
1023 let mut user = AsynUser::new(1);
1024 drv.write_float64(&mut user, 3.14).unwrap();
1025 let user = AsynUser::new(1);
1026 assert!((drv.read_float64(&user).unwrap() - 3.14).abs() < 1e-10);
1027 }
1028
1029 #[test]
1030 fn test_default_read_write_octet() {
1031 let mut drv = TestDriver::new();
1032 let mut user = AsynUser::new(2);
1033 drv.write_octet(&mut user, b"hello").unwrap();
1034 let user = AsynUser::new(2);
1035 let mut buf = [0u8; 32];
1036 let n = drv.read_octet(&user, &mut buf).unwrap();
1037 assert_eq!(&buf[..n], b"hello");
1038 }
1039
1040 #[test]
1041 fn test_default_read_write_uint32() {
1042 let mut drv = TestDriver::new();
1043 let mut user = AsynUser::new(3);
1044 drv.write_uint32_digital(&mut user, 0xFF, 0x0F).unwrap();
1045 let user = AsynUser::new(3);
1046 assert_eq!(drv.read_uint32_digital(&user, 0xFF).unwrap(), 0x0F);
1047 }
1048
1049 #[test]
1050 fn test_connect_disconnect() {
1051 let mut drv = TestDriver::new();
1052 let user = AsynUser::default();
1053 assert!(drv.base().connected);
1054 drv.disconnect(&user).unwrap();
1055 assert!(!drv.base().connected);
1056 drv.connect(&user).unwrap();
1057 assert!(drv.base().connected);
1058 }
1059
1060 #[test]
1061 fn test_drv_user_create() {
1062 let drv = TestDriver::new();
1063 assert_eq!(drv.drv_user_create("VAL").unwrap(), 0);
1064 assert_eq!(drv.drv_user_create("TEMP").unwrap(), 1);
1065 assert!(drv.drv_user_create("NOPE").is_err());
1066 }
1067
1068 #[test]
1069 fn test_call_param_callbacks() {
1070 let mut drv = TestDriver::new();
1071 let mut rx = drv.base_mut().interrupts.subscribe_async();
1072
1073 drv.base_mut().set_int32_param(0, 0, 100).unwrap();
1074 drv.base_mut().set_float64_param(1, 0, 2.0).unwrap();
1075 drv.base_mut().call_param_callbacks(0).unwrap();
1076
1077 let v1 = rx.try_recv().unwrap();
1078 assert_eq!(v1.reason, 0);
1079 let v2 = rx.try_recv().unwrap();
1080 assert_eq!(v2.reason, 1);
1081 assert!(rx.try_recv().is_err());
1082 }
1083
1084 #[test]
1085 fn test_no_callback_for_unchanged() {
1086 let mut drv = TestDriver::new();
1087 let mut rx = drv.base_mut().interrupts.subscribe_async();
1088
1089 drv.base_mut().set_int32_param(0, 0, 5).unwrap();
1090 drv.base_mut().call_param_callbacks(0).unwrap();
1091 let _ = rx.try_recv().unwrap(); drv.base_mut().set_int32_param(0, 0, 5).unwrap();
1095 drv.base_mut().call_param_callbacks(0).unwrap();
1096 assert!(rx.try_recv().is_err());
1097 }
1098
1099 #[test]
1100 fn test_array_not_supported_by_default() {
1101 let mut drv = TestDriver::new();
1102 let user = AsynUser::new(0);
1103 let mut buf = [0f64; 10];
1104 assert!(drv.read_float64_array(&user, &mut buf).is_err());
1105 assert!(drv.write_float64_array(&user, &[1.0]).is_err());
1106 }
1107
1108 #[test]
1109 fn test_option_set_get() {
1110 let mut drv = TestDriver::new();
1111 drv.set_option("baud", "9600").unwrap();
1112 assert_eq!(drv.get_option("baud").unwrap(), "9600");
1113 drv.set_option("baud", "115200").unwrap();
1114 assert_eq!(drv.get_option("baud").unwrap(), "115200");
1115 }
1116
1117 #[test]
1118 fn test_option_not_found() {
1119 let drv = TestDriver::new();
1120 let err = drv.get_option("nonexistent").unwrap_err();
1121 assert!(matches!(err, AsynError::OptionNotFound(_)));
1122 }
1123
1124 #[test]
1125 fn test_report_no_panic() {
1126 let mut drv = TestDriver::new();
1127 drv.set_option("testkey", "testval").unwrap();
1128 drv.base_mut().set_int32_param(0, 0, 42).unwrap();
1129 for level in 0..=3 {
1130 drv.report(level);
1131 }
1132 }
1133
1134 #[test]
1135 fn test_callback_uses_param_timestamp() {
1136 let mut drv = TestDriver::new();
1137 let mut rx = drv.base_mut().interrupts.subscribe_async();
1138
1139 let custom_ts = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_000_000);
1140 drv.base_mut().set_int32_param(0, 0, 77).unwrap();
1141 drv.base_mut().set_param_timestamp(0, 0, custom_ts).unwrap();
1142 drv.base_mut().call_param_callbacks(0).unwrap();
1143
1144 let v = rx.try_recv().unwrap();
1145 assert_eq!(v.reason, 0);
1146 assert_eq!(v.timestamp, custom_ts);
1147 }
1148
1149 #[test]
1150 fn test_default_read_write_enum() {
1151 use crate::param::EnumEntry;
1152
1153 let mut base = PortDriverBase::new("test_enum", 1, PortFlags::default());
1154 base.create_param("MODE", ParamType::Enum).unwrap();
1155
1156 struct EnumDriver {
1157 base: PortDriverBase,
1158 }
1159 impl PortDriver for EnumDriver {
1160 fn base(&self) -> &PortDriverBase {
1161 &self.base
1162 }
1163 fn base_mut(&mut self) -> &mut PortDriverBase {
1164 &mut self.base
1165 }
1166 }
1167
1168 let mut drv = EnumDriver { base };
1169 let choices: Arc<[EnumEntry]> = Arc::from(vec![
1170 EnumEntry {
1171 string: "Off".into(),
1172 value: 0,
1173 severity: 0,
1174 },
1175 EnumEntry {
1176 string: "On".into(),
1177 value: 1,
1178 severity: 0,
1179 },
1180 ]);
1181 let mut user = AsynUser::new(0);
1182 drv.write_enum_choices(&mut user, choices).unwrap();
1183 drv.write_enum(&mut user, 1).unwrap();
1184 let (idx, ch) = drv.read_enum(&AsynUser::new(0)).unwrap();
1185 assert_eq!(idx, 1);
1186 assert_eq!(ch[1].string, "On");
1187 }
1188
1189 #[test]
1190 fn test_enum_callback() {
1191 use crate::param::{EnumEntry, ParamValue};
1192
1193 let mut base = PortDriverBase::new("test_enum_cb", 1, PortFlags::default());
1194 base.create_param("MODE", ParamType::Enum).unwrap();
1195 let mut rx = base.interrupts.subscribe_async();
1196
1197 struct EnumDriver {
1198 base: PortDriverBase,
1199 }
1200 impl PortDriver for EnumDriver {
1201 fn base(&self) -> &PortDriverBase {
1202 &self.base
1203 }
1204 fn base_mut(&mut self) -> &mut PortDriverBase {
1205 &mut self.base
1206 }
1207 }
1208
1209 let mut drv = EnumDriver { base };
1210 let choices: Arc<[EnumEntry]> = Arc::from(vec![
1211 EnumEntry {
1212 string: "A".into(),
1213 value: 0,
1214 severity: 0,
1215 },
1216 EnumEntry {
1217 string: "B".into(),
1218 value: 1,
1219 severity: 0,
1220 },
1221 ]);
1222 drv.base_mut()
1223 .set_enum_choices_param(0, 0, choices)
1224 .unwrap();
1225 drv.base_mut().set_enum_index_param(0, 0, 1).unwrap();
1226 drv.base_mut().call_param_callbacks(0).unwrap();
1227
1228 let v = rx.try_recv().unwrap();
1229 assert_eq!(v.reason, 0);
1230 assert!(matches!(v.value, ParamValue::Enum { index: 1, .. }));
1231 }
1232
1233 #[test]
1234 fn test_default_read_write_generic_pointer() {
1235 let mut base = PortDriverBase::new("test_gp", 1, PortFlags::default());
1236 base.create_param("PTR", ParamType::GenericPointer).unwrap();
1237
1238 struct GpDriver {
1239 base: PortDriverBase,
1240 }
1241 impl PortDriver for GpDriver {
1242 fn base(&self) -> &PortDriverBase {
1243 &self.base
1244 }
1245 fn base_mut(&mut self) -> &mut PortDriverBase {
1246 &mut self.base
1247 }
1248 }
1249
1250 let mut drv = GpDriver { base };
1251 let data: Arc<dyn std::any::Any + Send + Sync> = Arc::new(99i32);
1252 let mut user = AsynUser::new(0);
1253 drv.write_generic_pointer(&mut user, data).unwrap();
1254 let val = drv.read_generic_pointer(&AsynUser::new(0)).unwrap();
1255 assert_eq!(*val.downcast_ref::<i32>().unwrap(), 99);
1256 }
1257
1258 #[test]
1259 fn test_generic_pointer_callback() {
1260 use crate::param::ParamValue;
1261
1262 let mut base = PortDriverBase::new("test_gp_cb", 1, PortFlags::default());
1263 base.create_param("PTR", ParamType::GenericPointer).unwrap();
1264 let mut rx = base.interrupts.subscribe_async();
1265
1266 struct GpDriver {
1267 base: PortDriverBase,
1268 }
1269 impl PortDriver for GpDriver {
1270 fn base(&self) -> &PortDriverBase {
1271 &self.base
1272 }
1273 fn base_mut(&mut self) -> &mut PortDriverBase {
1274 &mut self.base
1275 }
1276 }
1277
1278 let mut drv = GpDriver { base };
1279 let data: Arc<dyn std::any::Any + Send + Sync> = Arc::new(vec![1, 2, 3]);
1280 drv.base_mut()
1281 .set_generic_pointer_param(0, 0, data)
1282 .unwrap();
1283 drv.base_mut().call_param_callbacks(0).unwrap();
1284
1285 let v = rx.try_recv().unwrap();
1286 assert_eq!(v.reason, 0);
1287 assert!(matches!(v.value, ParamValue::GenericPointer(_)));
1288 }
1289
1290 #[test]
1291 fn test_interpose_push_requires_lock() {
1292 use crate::interpose::{OctetInterpose, OctetNext, OctetReadResult};
1293 use parking_lot::Mutex;
1294 use std::sync::Arc;
1295
1296 struct NoopInterpose;
1297 impl OctetInterpose for NoopInterpose {
1298 fn read(
1299 &mut self,
1300 user: &AsynUser,
1301 buf: &mut [u8],
1302 next: &mut dyn OctetNext,
1303 ) -> AsynResult<OctetReadResult> {
1304 next.read(user, buf)
1305 }
1306 fn write(
1307 &mut self,
1308 user: &mut AsynUser,
1309 data: &[u8],
1310 next: &mut dyn OctetNext,
1311 ) -> AsynResult<usize> {
1312 next.write(user, data)
1313 }
1314 fn flush(&mut self, user: &mut AsynUser, next: &mut dyn OctetNext) -> AsynResult<()> {
1315 next.flush(user)
1316 }
1317 }
1318
1319 let port: Arc<Mutex<dyn PortDriver>> = Arc::new(Mutex::new(TestDriver::new()));
1320
1321 {
1322 let mut guard = port.lock();
1323 guard
1324 .base_mut()
1325 .push_octet_interpose(Box::new(NoopInterpose));
1326 assert_eq!(guard.base().interpose_octet.len(), 1);
1327 }
1328 }
1329
1330 #[test]
1331 fn test_default_read_write_int64() {
1332 let mut base = PortDriverBase::new("test_i64", 1, PortFlags::default());
1333 base.create_param("BIG", ParamType::Int64).unwrap();
1334
1335 struct I64Driver {
1336 base: PortDriverBase,
1337 }
1338 impl PortDriver for I64Driver {
1339 fn base(&self) -> &PortDriverBase {
1340 &self.base
1341 }
1342 fn base_mut(&mut self) -> &mut PortDriverBase {
1343 &mut self.base
1344 }
1345 }
1346
1347 let mut drv = I64Driver { base };
1348 let mut user = AsynUser::new(0);
1349 drv.write_int64(&mut user, i64::MAX).unwrap();
1350 assert_eq!(drv.read_int64(&AsynUser::new(0)).unwrap(), i64::MAX);
1351 }
1352
1353 #[test]
1354 fn test_get_bounds_int64_default() {
1355 let base = PortDriverBase::new("test_bounds", 1, PortFlags::default());
1356 struct BoundsDriver {
1357 base: PortDriverBase,
1358 }
1359 impl PortDriver for BoundsDriver {
1360 fn base(&self) -> &PortDriverBase {
1361 &self.base
1362 }
1363 fn base_mut(&mut self) -> &mut PortDriverBase {
1364 &mut self.base
1365 }
1366 }
1367 let drv = BoundsDriver { base };
1368 let (lo, hi) = drv.get_bounds_int64(&AsynUser::default()).unwrap();
1369 assert_eq!(lo, i64::MIN);
1370 assert_eq!(hi, i64::MAX);
1371 }
1372
1373 #[test]
1374 fn test_per_addr_device_state() {
1375 let mut base = PortDriverBase::new(
1376 "multi",
1377 4,
1378 PortFlags {
1379 multi_device: true,
1380 can_block: false,
1381 destructible: true,
1382 },
1383 );
1384 base.create_param("V", ParamType::Int32).unwrap();
1385
1386 assert!(base.is_device_connected(0));
1388 assert!(base.is_device_connected(1));
1389
1390 base.device_state(1).enabled = false;
1392 assert!(base.check_ready_addr(0).is_ok());
1393 let err = base.check_ready_addr(1).unwrap_err();
1394 assert!(format!("{err}").contains("disabled"));
1395
1396 base.device_state(2).connected = false;
1398 let err = base.check_ready_addr(2).unwrap_err();
1399 assert!(format!("{err}").contains("disconnected"));
1400 }
1401
1402 #[test]
1403 fn test_per_addr_single_device_ignored() {
1404 let mut base = PortDriverBase::new("single", 1, PortFlags::default());
1405 base.create_param("V", ParamType::Int32).unwrap();
1406 assert!(base.check_ready_addr(0).is_ok());
1408 }
1409
1410 #[test]
1411 fn test_timestamp_source() {
1412 let mut base = PortDriverBase::new("ts_test", 1, PortFlags::default());
1413 base.create_param("V", ParamType::Int32).unwrap();
1414
1415 let fixed_ts = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(999999);
1416 base.register_timestamp_source(move || fixed_ts);
1417
1418 assert_eq!(base.current_timestamp(), fixed_ts);
1419 }
1420
1421 #[test]
1422 fn test_timestamp_source_in_callbacks() {
1423 let mut base = PortDriverBase::new("ts_cb", 1, PortFlags::default());
1424 base.create_param("V", ParamType::Int32).unwrap();
1425 let mut rx = base.interrupts.subscribe_async();
1426
1427 let fixed_ts = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(123456);
1428 base.register_timestamp_source(move || fixed_ts);
1429
1430 struct TsDriver {
1431 base: PortDriverBase,
1432 }
1433 impl PortDriver for TsDriver {
1434 fn base(&self) -> &PortDriverBase {
1435 &self.base
1436 }
1437 fn base_mut(&mut self) -> &mut PortDriverBase {
1438 &mut self.base
1439 }
1440 }
1441 let mut drv = TsDriver { base };
1442 drv.base_mut().set_int32_param(0, 0, 42).unwrap();
1443 drv.base_mut().call_param_callbacks(0).unwrap();
1444
1445 let v = rx.try_recv().unwrap();
1446 assert_eq!(v.timestamp, fixed_ts);
1448 }
1449
1450 #[test]
1451 fn test_queue_priority_connect() {
1452 assert!(QueuePriority::Connect > QueuePriority::High);
1453 }
1454
1455 #[test]
1456 fn test_port_flags_destructible_default_is_opt_in() {
1457 let flags = PortFlags::default();
1463 assert!(
1464 !flags.destructible,
1465 "destructible must be opt-in (C parity)"
1466 );
1467 }
1468
1469 #[test]
1470 fn shutdown_lifecycle_refuses_non_destructible() {
1471 let mut base = PortDriverBase::new(
1472 "p_nondestr",
1473 1,
1474 PortFlags {
1475 multi_device: false,
1476 can_block: false,
1477 destructible: false,
1478 },
1479 );
1480 match base.shutdown_lifecycle() {
1481 Err(AsynError::Status { message, .. }) => {
1482 assert!(message.contains("ASYN_DESTRUCTIBLE"), "msg={message}");
1483 }
1484 other => panic!("expected ASYN_DESTRUCTIBLE refusal, got {other:?}"),
1485 }
1486 assert!(
1487 !base.is_defunct(),
1488 "non-destructible port must not flip defunct"
1489 );
1490 assert!(base.is_enabled(), "non-destructible port must stay enabled");
1491 }
1492
1493 #[test]
1494 fn shutdown_lifecycle_marks_destructible_defunct_and_idempotent() {
1495 let mut base = PortDriverBase::new(
1496 "p_destr",
1497 1,
1498 PortFlags {
1499 multi_device: false,
1500 can_block: false,
1501 destructible: true,
1502 },
1503 );
1504 assert!(base.is_enabled());
1505 assert!(!base.is_defunct());
1506 base.shutdown_lifecycle().unwrap();
1507 assert!(
1508 !base.is_enabled(),
1509 "shutdown_lifecycle must flip enabled=false"
1510 );
1511 assert!(
1512 base.is_defunct(),
1513 "shutdown_lifecycle must flip defunct=true"
1514 );
1515 base.shutdown_lifecycle().unwrap();
1517 assert!(base.is_defunct());
1518 match base.check_ready() {
1520 Err(AsynError::Status { message, .. }) => {
1521 assert!(message.contains("defunct"), "msg={message}");
1522 }
1523 other => panic!("expected defunct error, got {other:?}"),
1524 }
1525 }
1526
1527 #[test]
1530 fn test_connect_addr() {
1531 let mut base = PortDriverBase::new(
1532 "multi_conn",
1533 4,
1534 PortFlags {
1535 multi_device: true,
1536 can_block: false,
1537 destructible: true,
1538 },
1539 );
1540 base.create_param("V", ParamType::Int32).unwrap();
1541
1542 base.disconnect_addr(1);
1543 assert!(!base.is_device_connected(1));
1544 assert!(base.check_ready_addr(1).is_err());
1545
1546 base.connect_addr(1);
1547 assert!(base.is_device_connected(1));
1548 assert!(base.check_ready_addr(1).is_ok());
1549 }
1550
1551 #[test]
1552 fn test_enable_disable_addr() {
1553 let mut base = PortDriverBase::new(
1554 "multi_en",
1555 4,
1556 PortFlags {
1557 multi_device: true,
1558 can_block: false,
1559 destructible: true,
1560 },
1561 );
1562 base.create_param("V", ParamType::Int32).unwrap();
1563
1564 base.disable_addr(2);
1565 let err = base.check_ready_addr(2).unwrap_err();
1566 assert!(format!("{err}").contains("disabled"));
1567
1568 base.enable_addr(2);
1569 assert!(base.check_ready_addr(2).is_ok());
1570 }
1571
1572 #[test]
1573 fn test_port_level_overrides_addr() {
1574 let mut base = PortDriverBase::new(
1575 "multi_override",
1576 4,
1577 PortFlags {
1578 multi_device: true,
1579 can_block: false,
1580 destructible: true,
1581 },
1582 );
1583 base.create_param("V", ParamType::Int32).unwrap();
1584
1585 base.enabled = false;
1587 base.enable_addr(0); let err = base.check_ready_addr(0).unwrap_err();
1589 assert!(format!("{err}").contains("disabled"));
1590 }
1591
1592 #[test]
1593 fn test_per_addr_exception_announced() {
1594 use std::sync::atomic::{AtomicI32, Ordering};
1595
1596 let mut base = PortDriverBase::new(
1597 "multi_exc",
1598 4,
1599 PortFlags {
1600 multi_device: true,
1601 can_block: false,
1602 destructible: true,
1603 },
1604 );
1605 base.create_param("V", ParamType::Int32).unwrap();
1606
1607 let exc_mgr = Arc::new(crate::exception::ExceptionManager::new());
1608 base.exception_sink = Some(exc_mgr.clone());
1609
1610 let last_addr = Arc::new(AtomicI32::new(-99));
1611 let last_addr2 = last_addr.clone();
1612 exc_mgr.add_callback(move |event| {
1613 last_addr2.store(event.addr, Ordering::Relaxed);
1614 });
1615
1616 base.disconnect_addr(3);
1617 assert_eq!(last_addr.load(Ordering::Relaxed), 3);
1618
1619 base.enable_addr(2);
1620 assert_eq!(last_addr.load(Ordering::Relaxed), 2);
1621 }
1622}