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 {
82 multi_device: false,
83 can_block: false,
84 destructible: true,
85 }
86 }
87}
88
89pub struct PortDriverBase {
101 pub port_name: String,
102 pub max_addr: usize,
103 pub flags: PortFlags,
104 pub params: ParamList,
105 pub interrupts: InterruptManager,
106 pub connected: bool,
107 pub enabled: bool,
108 pub auto_connect: bool,
109 pub exception_sink: Option<Arc<ExceptionManager>>,
111 pub options: HashMap<String, String>,
112 pub interpose_octet: OctetInterposeStack,
113 pub trace: Option<Arc<TraceManager>>,
114 pub device_states: HashMap<i32, DeviceState>,
116 pub timestamp_source: Option<Arc<dyn Fn() -> SystemTime + Send + Sync>>,
118}
119
120impl PortDriverBase {
121 pub fn new(port_name: &str, max_addr: usize, flags: PortFlags) -> Self {
122 Self {
123 port_name: port_name.to_string(),
124 max_addr: max_addr.max(1),
125 flags,
126 params: ParamList::new(max_addr, flags.multi_device),
127 interrupts: InterruptManager::new(256),
128 connected: true,
129 enabled: true,
130 auto_connect: true,
131 exception_sink: None,
132 options: HashMap::new(),
133 interpose_octet: OctetInterposeStack::new(),
134 trace: None,
135 device_states: HashMap::new(),
136 timestamp_source: None,
137 }
138 }
139
140 pub fn announce_exception(&self, exception: AsynException, addr: i32) {
142 if let Some(ref sink) = self.exception_sink {
143 sink.announce(&ExceptionEvent {
144 port_name: self.port_name.clone(),
145 exception,
146 addr,
147 });
148 }
149 }
150
151 pub fn check_ready(&self) -> AsynResult<()> {
154 if !self.enabled {
155 return Err(AsynError::Status {
156 status: AsynStatus::Disabled,
157 message: format!("port {} is disabled", self.port_name),
158 });
159 }
160 if !self.connected {
161 return Err(AsynError::Status {
162 status: AsynStatus::Disconnected,
163 message: format!("port {} is disconnected", self.port_name),
164 });
165 }
166 Ok(())
167 }
168
169 pub fn check_ready_addr(&self, addr: i32) -> AsynResult<()> {
172 self.check_ready()?;
173 if self.flags.multi_device {
174 if let Some(ds) = self.device_states.get(&addr) {
175 if !ds.enabled {
176 return Err(AsynError::Status {
177 status: AsynStatus::Disabled,
178 message: format!("port {} addr {} is disabled", self.port_name, addr),
179 });
180 }
181 if !ds.connected {
182 return Err(AsynError::Status {
183 status: AsynStatus::Disconnected,
184 message: format!("port {} addr {} is disconnected", self.port_name, addr),
185 });
186 }
187 }
188 }
189 Ok(())
190 }
191
192 pub fn device_state(&mut self, addr: i32) -> &mut DeviceState {
194 self.device_states.entry(addr).or_default()
195 }
196
197 pub fn is_device_connected(&self, addr: i32) -> bool {
199 self.device_states
200 .get(&addr)
201 .map_or(true, |ds| ds.connected)
202 }
203
204 pub fn connect_addr(&mut self, addr: i32) {
206 self.device_state(addr).connected = true;
207 self.announce_exception(AsynException::Connect, addr);
208 }
209
210 pub fn disconnect_addr(&mut self, addr: i32) {
212 self.device_state(addr).connected = false;
213 self.announce_exception(AsynException::Connect, addr);
214 }
215
216 pub fn enable_addr(&mut self, addr: i32) {
218 self.device_state(addr).enabled = true;
219 self.announce_exception(AsynException::Enable, addr);
220 }
221
222 pub fn disable_addr(&mut self, addr: i32) {
224 self.device_state(addr).enabled = false;
225 self.announce_exception(AsynException::Enable, addr);
226 }
227
228 pub fn register_timestamp_source<F>(&mut self, source: F)
230 where
231 F: Fn() -> SystemTime + Send + Sync + 'static,
232 {
233 self.timestamp_source = Some(Arc::new(source));
234 }
235
236 pub fn current_timestamp(&self) -> SystemTime {
238 self.timestamp_source
239 .as_ref()
240 .map_or_else(SystemTime::now, |f| f())
241 }
242
243 pub fn create_param(&mut self, name: &str, param_type: ParamType) -> AsynResult<usize> {
244 self.params.create_param(name, param_type)
245 }
246
247 pub fn find_param(&self, name: &str) -> Option<usize> {
248 self.params.find_param(name)
249 }
250
251 pub fn set_int32_param(&mut self, index: usize, addr: i32, value: i32) -> AsynResult<()> {
254 self.params.set_int32(index, addr, value)
255 }
256
257 pub fn get_int32_param(&self, index: usize, addr: i32) -> AsynResult<i32> {
258 self.params.get_int32(index, addr)
259 }
260
261 pub fn set_int64_param(&mut self, index: usize, addr: i32, value: i64) -> AsynResult<()> {
262 self.params.set_int64(index, addr, value)
263 }
264
265 pub fn get_int64_param(&self, index: usize, addr: i32) -> AsynResult<i64> {
266 self.params.get_int64(index, addr)
267 }
268
269 pub fn set_float64_param(&mut self, index: usize, addr: i32, value: f64) -> AsynResult<()> {
270 self.params.set_float64(index, addr, value)
271 }
272
273 pub fn get_float64_param(&self, index: usize, addr: i32) -> AsynResult<f64> {
274 self.params.get_float64(index, addr)
275 }
276
277 pub fn set_string_param(&mut self, index: usize, addr: i32, value: String) -> AsynResult<()> {
278 self.params.set_string(index, addr, value)
279 }
280
281 pub fn get_string_param(&self, index: usize, addr: i32) -> AsynResult<&str> {
282 self.params.get_string(index, addr)
283 }
284
285 pub fn set_uint32_param(
286 &mut self,
287 index: usize,
288 addr: i32,
289 value: u32,
290 mask: u32,
291 ) -> AsynResult<()> {
292 self.params.set_uint32(index, addr, value, mask)
293 }
294
295 pub fn get_uint32_param(&self, index: usize, addr: i32) -> AsynResult<u32> {
296 self.params.get_uint32(index, addr)
297 }
298
299 pub fn get_enum_param(&self, index: usize, addr: i32) -> AsynResult<(usize, Arc<[EnumEntry]>)> {
300 self.params.get_enum(index, addr)
301 }
302
303 pub fn set_enum_index_param(
304 &mut self,
305 index: usize,
306 addr: i32,
307 value: usize,
308 ) -> AsynResult<()> {
309 self.params.set_enum_index(index, addr, value)
310 }
311
312 pub fn set_enum_choices_param(
313 &mut self,
314 index: usize,
315 addr: i32,
316 choices: Arc<[EnumEntry]>,
317 ) -> AsynResult<()> {
318 self.params.set_enum_choices(index, addr, choices)
319 }
320
321 pub fn get_generic_pointer_param(
322 &self,
323 index: usize,
324 addr: i32,
325 ) -> AsynResult<Arc<dyn Any + Send + Sync>> {
326 self.params.get_generic_pointer(index, addr)
327 }
328
329 pub fn set_generic_pointer_param(
330 &mut self,
331 index: usize,
332 addr: i32,
333 value: Arc<dyn Any + Send + Sync>,
334 ) -> AsynResult<()> {
335 self.params.set_generic_pointer(index, addr, value)
336 }
337
338 pub fn set_param_timestamp(
339 &mut self,
340 index: usize,
341 addr: i32,
342 ts: SystemTime,
343 ) -> AsynResult<()> {
344 self.params.set_timestamp(index, addr, ts)
345 }
346
347 pub fn push_octet_interpose(&mut self, layer: Box<dyn OctetInterpose>) {
353 self.interpose_octet.push(layer);
354 }
355
356 pub fn call_param_callbacks(&mut self, addr: i32) -> AsynResult<()> {
359 let changed = self.params.take_changed(addr)?;
360 let now = self.current_timestamp();
361 for reason in changed {
362 let value = self.params.get_value(reason, addr)?.clone();
363 let ts = self.params.get_timestamp(reason, addr)?.unwrap_or(now);
364 self.interrupts.notify(InterruptValue {
365 reason,
366 addr,
367 value,
368 timestamp: ts,
369 });
370 }
371 Ok(())
372 }
373
374 pub fn call_param_callback(&mut self, addr: i32, reason: usize) -> AsynResult<()> {
378 if self.params.take_changed_single(reason, addr)? {
379 let now = self.current_timestamp();
380 let value = self.params.get_value(reason, addr)?.clone();
381 let ts = self.params.get_timestamp(reason, addr)?.unwrap_or(now);
382 self.interrupts.notify(InterruptValue {
383 reason,
384 addr,
385 value,
386 timestamp: ts,
387 });
388 }
389 Ok(())
390 }
391
392 pub fn mark_param_changed(&mut self, index: usize, addr: i32) -> AsynResult<()> {
397 self.params.mark_changed(index, addr)
398 }
399}
400
401pub trait PortDriver: Send + Sync + 'static {
416 fn base(&self) -> &PortDriverBase;
417 fn base_mut(&mut self) -> &mut PortDriverBase;
418
419 fn connect(&mut self, _user: &AsynUser) -> AsynResult<()> {
422 self.base_mut().connected = true;
423 self.base().announce_exception(AsynException::Connect, -1);
424 Ok(())
425 }
426
427 fn disconnect(&mut self, _user: &AsynUser) -> AsynResult<()> {
428 self.base_mut().connected = false;
429 self.base().announce_exception(AsynException::Connect, -1);
430 Ok(())
431 }
432
433 fn enable(&mut self, _user: &AsynUser) -> AsynResult<()> {
434 self.base_mut().enabled = true;
435 self.base().announce_exception(AsynException::Enable, -1);
436 Ok(())
437 }
438
439 fn disable(&mut self, _user: &AsynUser) -> AsynResult<()> {
440 self.base_mut().enabled = false;
441 self.base().announce_exception(AsynException::Enable, -1);
442 Ok(())
443 }
444
445 fn connect_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
446 self.base_mut().connect_addr(user.addr);
447 Ok(())
448 }
449
450 fn disconnect_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
451 self.base_mut().disconnect_addr(user.addr);
452 Ok(())
453 }
454
455 fn enable_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
456 self.base_mut().enable_addr(user.addr);
457 Ok(())
458 }
459
460 fn disable_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
461 self.base_mut().disable_addr(user.addr);
462 Ok(())
463 }
464
465 fn get_option(&self, key: &str) -> AsynResult<String> {
466 self.base()
467 .options
468 .get(key)
469 .cloned()
470 .ok_or_else(|| AsynError::OptionNotFound(key.to_string()))
471 }
472
473 fn set_option(&mut self, key: &str, value: &str) -> AsynResult<()> {
474 self.base_mut()
475 .options
476 .insert(key.to_string(), value.to_string());
477 Ok(())
478 }
479
480 fn report(&self, level: i32) {
481 let base = self.base();
482 eprintln!("Port: {}", base.port_name);
483 eprintln!(
484 " connected: {}, max_addr: {}, params: {}, options: {}",
485 base.connected,
486 base.max_addr,
487 base.params.len(),
488 base.options.len()
489 );
490 if level >= 1 {
491 for i in 0..base.params.len() {
492 if let (Some(name), Some(ptype)) =
493 (base.params.param_name(i), base.params.param_type(i))
494 {
495 if level >= 3 {
496 let val = base
497 .params
498 .get_value(i, 0)
499 .map(|v| format!("{v:?}"))
500 .unwrap_or("?".into());
501 eprintln!(" param[{i}]: {name} ({ptype:?}) = {val}");
502 } else {
503 eprintln!(" param[{i}]: {name} ({ptype:?})");
504 }
505 }
506 }
507 }
508 if level >= 2 {
509 for (k, v) in &base.options {
510 eprintln!(" option: {k} = {v}");
511 }
512 }
513 }
514
515 fn read_int32(&mut self, user: &AsynUser) -> AsynResult<i32> {
518 self.base().check_ready()?;
519 self.base().params.get_int32(user.reason, user.addr)
520 }
521
522 fn write_int32(&mut self, user: &mut AsynUser, value: i32) -> AsynResult<()> {
523 self.base().check_ready()?;
524 self.base_mut()
525 .params
526 .set_int32(user.reason, user.addr, value)?;
527 self.base_mut().call_param_callbacks(user.addr)
528 }
529
530 fn read_int64(&mut self, user: &AsynUser) -> AsynResult<i64> {
531 self.base().check_ready()?;
532 self.base().params.get_int64(user.reason, user.addr)
533 }
534
535 fn write_int64(&mut self, user: &mut AsynUser, value: i64) -> AsynResult<()> {
536 self.base().check_ready()?;
537 self.base_mut()
538 .params
539 .set_int64(user.reason, user.addr, value)?;
540 self.base_mut().call_param_callbacks(user.addr)
541 }
542
543 fn get_bounds_int64(&self, _user: &AsynUser) -> AsynResult<(i64, i64)> {
544 Ok((i64::MIN, i64::MAX))
545 }
546
547 fn read_float64(&mut self, user: &AsynUser) -> AsynResult<f64> {
548 self.base().check_ready()?;
549 self.base().params.get_float64(user.reason, user.addr)
550 }
551
552 fn write_float64(&mut self, user: &mut AsynUser, value: f64) -> AsynResult<()> {
553 self.base().check_ready()?;
554 self.base_mut()
555 .params
556 .set_float64(user.reason, user.addr, value)?;
557 self.base_mut().call_param_callbacks(user.addr)
558 }
559
560 fn read_octet(&mut self, user: &AsynUser, buf: &mut [u8]) -> AsynResult<usize> {
561 self.base().check_ready()?;
562 let s = self.base().params.get_string(user.reason, user.addr)?;
563 let bytes = s.as_bytes();
564 let n = bytes.len().min(buf.len());
565 buf[..n].copy_from_slice(&bytes[..n]);
566 Ok(n)
567 }
568
569 fn write_octet(&mut self, user: &mut AsynUser, data: &[u8]) -> AsynResult<()> {
570 self.base().check_ready()?;
571 let s = String::from_utf8_lossy(data).into_owned();
572 self.base_mut()
573 .params
574 .set_string(user.reason, user.addr, s)?;
575 self.base_mut().call_param_callbacks(user.addr)
576 }
577
578 fn read_uint32_digital(&mut self, user: &AsynUser, mask: u32) -> AsynResult<u32> {
579 self.base().check_ready()?;
580 let val = self.base().params.get_uint32(user.reason, user.addr)?;
581 Ok(val & mask)
582 }
583
584 fn write_uint32_digital(
585 &mut self,
586 user: &mut AsynUser,
587 value: u32,
588 mask: u32,
589 ) -> AsynResult<()> {
590 self.base().check_ready()?;
591 self.base_mut()
592 .params
593 .set_uint32(user.reason, user.addr, value, mask)?;
594 self.base_mut().call_param_callbacks(user.addr)
595 }
596
597 fn read_enum(&mut self, user: &AsynUser) -> AsynResult<(usize, Arc<[EnumEntry]>)> {
600 self.base().check_ready()?;
601 self.base().params.get_enum(user.reason, user.addr)
602 }
603
604 fn write_enum(&mut self, user: &mut AsynUser, index: usize) -> AsynResult<()> {
605 self.base().check_ready()?;
606 self.base_mut()
607 .params
608 .set_enum_index(user.reason, user.addr, index)?;
609 self.base_mut().call_param_callbacks(user.addr)
610 }
611
612 fn write_enum_choices(
613 &mut self,
614 user: &mut AsynUser,
615 choices: Arc<[EnumEntry]>,
616 ) -> AsynResult<()> {
617 self.base().check_ready()?;
618 self.base_mut()
619 .params
620 .set_enum_choices(user.reason, user.addr, choices)?;
621 self.base_mut().call_param_callbacks(user.addr)
622 }
623
624 fn read_generic_pointer(&mut self, user: &AsynUser) -> AsynResult<Arc<dyn Any + Send + Sync>> {
627 self.base().check_ready()?;
628 self.base()
629 .params
630 .get_generic_pointer(user.reason, user.addr)
631 }
632
633 fn write_generic_pointer(
634 &mut self,
635 user: &mut AsynUser,
636 value: Arc<dyn Any + Send + Sync>,
637 ) -> AsynResult<()> {
638 self.base().check_ready()?;
639 self.base_mut()
640 .params
641 .set_generic_pointer(user.reason, user.addr, value)?;
642 self.base_mut().call_param_callbacks(user.addr)
643 }
644
645 fn read_float64_array(&mut self, _user: &AsynUser, _buf: &mut [f64]) -> AsynResult<usize> {
648 Err(AsynError::InterfaceNotSupported("asynFloat64Array".into()))
649 }
650
651 fn write_float64_array(&mut self, user: &AsynUser, data: &[f64]) -> AsynResult<()> {
652 self.base_mut()
653 .params
654 .set_float64_array(user.reason, user.addr, data.to_vec())?;
655 self.base_mut().call_param_callbacks(user.addr)
656 }
657
658 fn read_int32_array(&mut self, _user: &AsynUser, _buf: &mut [i32]) -> AsynResult<usize> {
659 Err(AsynError::InterfaceNotSupported("asynInt32Array".into()))
660 }
661
662 fn write_int32_array(&mut self, user: &AsynUser, data: &[i32]) -> AsynResult<()> {
663 self.base_mut()
664 .params
665 .set_int32_array(user.reason, user.addr, data.to_vec())?;
666 self.base_mut().call_param_callbacks(user.addr)
667 }
668
669 fn read_int8_array(&mut self, _user: &AsynUser, _buf: &mut [i8]) -> AsynResult<usize> {
670 Err(AsynError::InterfaceNotSupported("asynInt8Array".into()))
671 }
672
673 fn write_int8_array(&mut self, user: &AsynUser, data: &[i8]) -> AsynResult<()> {
674 self.base_mut()
675 .params
676 .set_int8_array(user.reason, user.addr, data.to_vec())?;
677 self.base_mut().call_param_callbacks(user.addr)
678 }
679
680 fn read_int16_array(&mut self, _user: &AsynUser, _buf: &mut [i16]) -> AsynResult<usize> {
681 Err(AsynError::InterfaceNotSupported("asynInt16Array".into()))
682 }
683
684 fn write_int16_array(&mut self, user: &AsynUser, data: &[i16]) -> AsynResult<()> {
685 self.base_mut()
686 .params
687 .set_int16_array(user.reason, user.addr, data.to_vec())?;
688 self.base_mut().call_param_callbacks(user.addr)
689 }
690
691 fn read_int64_array(&mut self, _user: &AsynUser, _buf: &mut [i64]) -> AsynResult<usize> {
692 Err(AsynError::InterfaceNotSupported("asynInt64Array".into()))
693 }
694
695 fn write_int64_array(&mut self, user: &AsynUser, data: &[i64]) -> AsynResult<()> {
696 self.base_mut()
697 .params
698 .set_int64_array(user.reason, user.addr, data.to_vec())?;
699 self.base_mut().call_param_callbacks(user.addr)
700 }
701
702 fn read_float32_array(&mut self, _user: &AsynUser, _buf: &mut [f32]) -> AsynResult<usize> {
703 Err(AsynError::InterfaceNotSupported("asynFloat32Array".into()))
704 }
705
706 fn write_float32_array(&mut self, user: &AsynUser, data: &[f32]) -> AsynResult<()> {
707 self.base_mut()
708 .params
709 .set_float32_array(user.reason, user.addr, data.to_vec())?;
710 self.base_mut().call_param_callbacks(user.addr)
711 }
712
713 fn io_read_octet(&mut self, user: &AsynUser, buf: &mut [u8]) -> AsynResult<usize> {
718 self.read_octet(user, buf)
719 }
720
721 fn io_write_octet(&mut self, user: &mut AsynUser, data: &[u8]) -> AsynResult<()> {
722 self.write_octet(user, data)
723 }
724
725 fn io_read_int32(&mut self, user: &AsynUser) -> AsynResult<i32> {
726 self.read_int32(user)
727 }
728
729 fn io_write_int32(&mut self, user: &mut AsynUser, value: i32) -> AsynResult<()> {
730 self.write_int32(user, value)
731 }
732
733 fn io_read_int64(&mut self, user: &AsynUser) -> AsynResult<i64> {
734 self.read_int64(user)
735 }
736
737 fn io_write_int64(&mut self, user: &mut AsynUser, value: i64) -> AsynResult<()> {
738 self.write_int64(user, value)
739 }
740
741 fn io_read_float64(&mut self, user: &AsynUser) -> AsynResult<f64> {
742 self.read_float64(user)
743 }
744
745 fn io_write_float64(&mut self, user: &mut AsynUser, value: f64) -> AsynResult<()> {
746 self.write_float64(user, value)
747 }
748
749 fn io_read_uint32_digital(&mut self, user: &AsynUser, mask: u32) -> AsynResult<u32> {
750 self.read_uint32_digital(user, mask)
751 }
752
753 fn io_write_uint32_digital(
754 &mut self,
755 user: &mut AsynUser,
756 value: u32,
757 mask: u32,
758 ) -> AsynResult<()> {
759 self.write_uint32_digital(user, value, mask)
760 }
761
762 fn io_flush(&mut self, _user: &mut AsynUser) -> AsynResult<()> {
763 Ok(())
764 }
765
766 fn drv_user_create(&self, drv_info: &str) -> AsynResult<usize> {
771 self.base()
772 .params
773 .find_param(drv_info)
774 .ok_or_else(|| AsynError::ParamNotFound(drv_info.to_string()))
775 }
776
777 fn capabilities(&self) -> Vec<crate::interfaces::Capability> {
782 crate::interfaces::default_capabilities()
783 }
784
785 fn supports(&self, cap: crate::interfaces::Capability) -> bool {
787 self.capabilities().contains(&cap)
788 }
789
790 fn init(&mut self) -> AsynResult<()> {
793 Ok(())
794 }
795}
796
797#[cfg(test)]
798mod tests {
799 use super::*;
800 struct TestDriver {
801 base: PortDriverBase,
802 }
803
804 impl TestDriver {
805 fn new() -> Self {
806 let mut base = PortDriverBase::new("test", 1, PortFlags::default());
807 base.create_param("VAL", ParamType::Int32).unwrap();
808 base.create_param("TEMP", ParamType::Float64).unwrap();
809 base.create_param("MSG", ParamType::Octet).unwrap();
810 base.create_param("BITS", ParamType::UInt32Digital).unwrap();
811 Self { base }
812 }
813 }
814
815 impl PortDriver for TestDriver {
816 fn base(&self) -> &PortDriverBase {
817 &self.base
818 }
819 fn base_mut(&mut self) -> &mut PortDriverBase {
820 &mut self.base
821 }
822 }
823
824 #[test]
825 fn test_default_read_write_int32() {
826 let mut drv = TestDriver::new();
827 let mut user = AsynUser::new(0);
828 drv.write_int32(&mut user, 42).unwrap();
829 let user = AsynUser::new(0);
830 assert_eq!(drv.read_int32(&user).unwrap(), 42);
831 }
832
833 #[test]
834 fn test_default_read_write_float64() {
835 let mut drv = TestDriver::new();
836 let mut user = AsynUser::new(1);
837 drv.write_float64(&mut user, 3.14).unwrap();
838 let user = AsynUser::new(1);
839 assert!((drv.read_float64(&user).unwrap() - 3.14).abs() < 1e-10);
840 }
841
842 #[test]
843 fn test_default_read_write_octet() {
844 let mut drv = TestDriver::new();
845 let mut user = AsynUser::new(2);
846 drv.write_octet(&mut user, b"hello").unwrap();
847 let user = AsynUser::new(2);
848 let mut buf = [0u8; 32];
849 let n = drv.read_octet(&user, &mut buf).unwrap();
850 assert_eq!(&buf[..n], b"hello");
851 }
852
853 #[test]
854 fn test_default_read_write_uint32() {
855 let mut drv = TestDriver::new();
856 let mut user = AsynUser::new(3);
857 drv.write_uint32_digital(&mut user, 0xFF, 0x0F).unwrap();
858 let user = AsynUser::new(3);
859 assert_eq!(drv.read_uint32_digital(&user, 0xFF).unwrap(), 0x0F);
860 }
861
862 #[test]
863 fn test_connect_disconnect() {
864 let mut drv = TestDriver::new();
865 let user = AsynUser::default();
866 assert!(drv.base().connected);
867 drv.disconnect(&user).unwrap();
868 assert!(!drv.base().connected);
869 drv.connect(&user).unwrap();
870 assert!(drv.base().connected);
871 }
872
873 #[test]
874 fn test_drv_user_create() {
875 let drv = TestDriver::new();
876 assert_eq!(drv.drv_user_create("VAL").unwrap(), 0);
877 assert_eq!(drv.drv_user_create("TEMP").unwrap(), 1);
878 assert!(drv.drv_user_create("NOPE").is_err());
879 }
880
881 #[test]
882 fn test_call_param_callbacks() {
883 let mut drv = TestDriver::new();
884 let mut rx = drv.base_mut().interrupts.subscribe_async();
885
886 drv.base_mut().set_int32_param(0, 0, 100).unwrap();
887 drv.base_mut().set_float64_param(1, 0, 2.0).unwrap();
888 drv.base_mut().call_param_callbacks(0).unwrap();
889
890 let v1 = rx.try_recv().unwrap();
891 assert_eq!(v1.reason, 0);
892 let v2 = rx.try_recv().unwrap();
893 assert_eq!(v2.reason, 1);
894 assert!(rx.try_recv().is_err());
895 }
896
897 #[test]
898 fn test_no_callback_for_unchanged() {
899 let mut drv = TestDriver::new();
900 let mut rx = drv.base_mut().interrupts.subscribe_async();
901
902 drv.base_mut().set_int32_param(0, 0, 5).unwrap();
903 drv.base_mut().call_param_callbacks(0).unwrap();
904 let _ = rx.try_recv().unwrap(); drv.base_mut().set_int32_param(0, 0, 5).unwrap();
908 drv.base_mut().call_param_callbacks(0).unwrap();
909 assert!(rx.try_recv().is_err());
910 }
911
912 #[test]
913 fn test_array_not_supported_by_default() {
914 let mut drv = TestDriver::new();
915 let user = AsynUser::new(0);
916 let mut buf = [0f64; 10];
917 assert!(drv.read_float64_array(&user, &mut buf).is_err());
918 assert!(drv.write_float64_array(&user, &[1.0]).is_err());
919 }
920
921 #[test]
922 fn test_option_set_get() {
923 let mut drv = TestDriver::new();
924 drv.set_option("baud", "9600").unwrap();
925 assert_eq!(drv.get_option("baud").unwrap(), "9600");
926 drv.set_option("baud", "115200").unwrap();
927 assert_eq!(drv.get_option("baud").unwrap(), "115200");
928 }
929
930 #[test]
931 fn test_option_not_found() {
932 let drv = TestDriver::new();
933 let err = drv.get_option("nonexistent").unwrap_err();
934 assert!(matches!(err, AsynError::OptionNotFound(_)));
935 }
936
937 #[test]
938 fn test_report_no_panic() {
939 let mut drv = TestDriver::new();
940 drv.set_option("testkey", "testval").unwrap();
941 drv.base_mut().set_int32_param(0, 0, 42).unwrap();
942 for level in 0..=3 {
943 drv.report(level);
944 }
945 }
946
947 #[test]
948 fn test_callback_uses_param_timestamp() {
949 let mut drv = TestDriver::new();
950 let mut rx = drv.base_mut().interrupts.subscribe_async();
951
952 let custom_ts = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_000_000);
953 drv.base_mut().set_int32_param(0, 0, 77).unwrap();
954 drv.base_mut().set_param_timestamp(0, 0, custom_ts).unwrap();
955 drv.base_mut().call_param_callbacks(0).unwrap();
956
957 let v = rx.try_recv().unwrap();
958 assert_eq!(v.reason, 0);
959 assert_eq!(v.timestamp, custom_ts);
960 }
961
962 #[test]
963 fn test_default_read_write_enum() {
964 use crate::param::EnumEntry;
965
966 let mut base = PortDriverBase::new("test_enum", 1, PortFlags::default());
967 base.create_param("MODE", ParamType::Enum).unwrap();
968
969 struct EnumDriver {
970 base: PortDriverBase,
971 }
972 impl PortDriver for EnumDriver {
973 fn base(&self) -> &PortDriverBase {
974 &self.base
975 }
976 fn base_mut(&mut self) -> &mut PortDriverBase {
977 &mut self.base
978 }
979 }
980
981 let mut drv = EnumDriver { base };
982 let choices: Arc<[EnumEntry]> = Arc::from(vec![
983 EnumEntry {
984 string: "Off".into(),
985 value: 0,
986 severity: 0,
987 },
988 EnumEntry {
989 string: "On".into(),
990 value: 1,
991 severity: 0,
992 },
993 ]);
994 let mut user = AsynUser::new(0);
995 drv.write_enum_choices(&mut user, choices).unwrap();
996 drv.write_enum(&mut user, 1).unwrap();
997 let (idx, ch) = drv.read_enum(&AsynUser::new(0)).unwrap();
998 assert_eq!(idx, 1);
999 assert_eq!(ch[1].string, "On");
1000 }
1001
1002 #[test]
1003 fn test_enum_callback() {
1004 use crate::param::{EnumEntry, ParamValue};
1005
1006 let mut base = PortDriverBase::new("test_enum_cb", 1, PortFlags::default());
1007 base.create_param("MODE", ParamType::Enum).unwrap();
1008 let mut rx = base.interrupts.subscribe_async();
1009
1010 struct EnumDriver {
1011 base: PortDriverBase,
1012 }
1013 impl PortDriver for EnumDriver {
1014 fn base(&self) -> &PortDriverBase {
1015 &self.base
1016 }
1017 fn base_mut(&mut self) -> &mut PortDriverBase {
1018 &mut self.base
1019 }
1020 }
1021
1022 let mut drv = EnumDriver { base };
1023 let choices: Arc<[EnumEntry]> = Arc::from(vec![
1024 EnumEntry {
1025 string: "A".into(),
1026 value: 0,
1027 severity: 0,
1028 },
1029 EnumEntry {
1030 string: "B".into(),
1031 value: 1,
1032 severity: 0,
1033 },
1034 ]);
1035 drv.base_mut()
1036 .set_enum_choices_param(0, 0, choices)
1037 .unwrap();
1038 drv.base_mut().set_enum_index_param(0, 0, 1).unwrap();
1039 drv.base_mut().call_param_callbacks(0).unwrap();
1040
1041 let v = rx.try_recv().unwrap();
1042 assert_eq!(v.reason, 0);
1043 assert!(matches!(v.value, ParamValue::Enum { index: 1, .. }));
1044 }
1045
1046 #[test]
1047 fn test_default_read_write_generic_pointer() {
1048 let mut base = PortDriverBase::new("test_gp", 1, PortFlags::default());
1049 base.create_param("PTR", ParamType::GenericPointer).unwrap();
1050
1051 struct GpDriver {
1052 base: PortDriverBase,
1053 }
1054 impl PortDriver for GpDriver {
1055 fn base(&self) -> &PortDriverBase {
1056 &self.base
1057 }
1058 fn base_mut(&mut self) -> &mut PortDriverBase {
1059 &mut self.base
1060 }
1061 }
1062
1063 let mut drv = GpDriver { base };
1064 let data: Arc<dyn std::any::Any + Send + Sync> = Arc::new(99i32);
1065 let mut user = AsynUser::new(0);
1066 drv.write_generic_pointer(&mut user, data).unwrap();
1067 let val = drv.read_generic_pointer(&AsynUser::new(0)).unwrap();
1068 assert_eq!(*val.downcast_ref::<i32>().unwrap(), 99);
1069 }
1070
1071 #[test]
1072 fn test_generic_pointer_callback() {
1073 use crate::param::ParamValue;
1074
1075 let mut base = PortDriverBase::new("test_gp_cb", 1, PortFlags::default());
1076 base.create_param("PTR", ParamType::GenericPointer).unwrap();
1077 let mut rx = base.interrupts.subscribe_async();
1078
1079 struct GpDriver {
1080 base: PortDriverBase,
1081 }
1082 impl PortDriver for GpDriver {
1083 fn base(&self) -> &PortDriverBase {
1084 &self.base
1085 }
1086 fn base_mut(&mut self) -> &mut PortDriverBase {
1087 &mut self.base
1088 }
1089 }
1090
1091 let mut drv = GpDriver { base };
1092 let data: Arc<dyn std::any::Any + Send + Sync> = Arc::new(vec![1, 2, 3]);
1093 drv.base_mut()
1094 .set_generic_pointer_param(0, 0, data)
1095 .unwrap();
1096 drv.base_mut().call_param_callbacks(0).unwrap();
1097
1098 let v = rx.try_recv().unwrap();
1099 assert_eq!(v.reason, 0);
1100 assert!(matches!(v.value, ParamValue::GenericPointer(_)));
1101 }
1102
1103 #[test]
1104 fn test_interpose_push_requires_lock() {
1105 use crate::interpose::{OctetInterpose, OctetNext, OctetReadResult};
1106 use parking_lot::Mutex;
1107 use std::sync::Arc;
1108
1109 struct NoopInterpose;
1110 impl OctetInterpose for NoopInterpose {
1111 fn read(
1112 &mut self,
1113 user: &AsynUser,
1114 buf: &mut [u8],
1115 next: &mut dyn OctetNext,
1116 ) -> AsynResult<OctetReadResult> {
1117 next.read(user, buf)
1118 }
1119 fn write(
1120 &mut self,
1121 user: &mut AsynUser,
1122 data: &[u8],
1123 next: &mut dyn OctetNext,
1124 ) -> AsynResult<usize> {
1125 next.write(user, data)
1126 }
1127 fn flush(&mut self, user: &mut AsynUser, next: &mut dyn OctetNext) -> AsynResult<()> {
1128 next.flush(user)
1129 }
1130 }
1131
1132 let port: Arc<Mutex<dyn PortDriver>> = Arc::new(Mutex::new(TestDriver::new()));
1133
1134 {
1135 let mut guard = port.lock();
1136 guard
1137 .base_mut()
1138 .push_octet_interpose(Box::new(NoopInterpose));
1139 assert_eq!(guard.base().interpose_octet.len(), 1);
1140 }
1141 }
1142
1143 #[test]
1144 fn test_default_read_write_int64() {
1145 let mut base = PortDriverBase::new("test_i64", 1, PortFlags::default());
1146 base.create_param("BIG", ParamType::Int64).unwrap();
1147
1148 struct I64Driver {
1149 base: PortDriverBase,
1150 }
1151 impl PortDriver for I64Driver {
1152 fn base(&self) -> &PortDriverBase {
1153 &self.base
1154 }
1155 fn base_mut(&mut self) -> &mut PortDriverBase {
1156 &mut self.base
1157 }
1158 }
1159
1160 let mut drv = I64Driver { base };
1161 let mut user = AsynUser::new(0);
1162 drv.write_int64(&mut user, i64::MAX).unwrap();
1163 assert_eq!(drv.read_int64(&AsynUser::new(0)).unwrap(), i64::MAX);
1164 }
1165
1166 #[test]
1167 fn test_get_bounds_int64_default() {
1168 let base = PortDriverBase::new("test_bounds", 1, PortFlags::default());
1169 struct BoundsDriver {
1170 base: PortDriverBase,
1171 }
1172 impl PortDriver for BoundsDriver {
1173 fn base(&self) -> &PortDriverBase {
1174 &self.base
1175 }
1176 fn base_mut(&mut self) -> &mut PortDriverBase {
1177 &mut self.base
1178 }
1179 }
1180 let drv = BoundsDriver { base };
1181 let (lo, hi) = drv.get_bounds_int64(&AsynUser::default()).unwrap();
1182 assert_eq!(lo, i64::MIN);
1183 assert_eq!(hi, i64::MAX);
1184 }
1185
1186 #[test]
1187 fn test_per_addr_device_state() {
1188 let mut base = PortDriverBase::new(
1189 "multi",
1190 4,
1191 PortFlags {
1192 multi_device: true,
1193 can_block: false,
1194 destructible: true,
1195 },
1196 );
1197 base.create_param("V", ParamType::Int32).unwrap();
1198
1199 assert!(base.is_device_connected(0));
1201 assert!(base.is_device_connected(1));
1202
1203 base.device_state(1).enabled = false;
1205 assert!(base.check_ready_addr(0).is_ok());
1206 let err = base.check_ready_addr(1).unwrap_err();
1207 assert!(format!("{err}").contains("disabled"));
1208
1209 base.device_state(2).connected = false;
1211 let err = base.check_ready_addr(2).unwrap_err();
1212 assert!(format!("{err}").contains("disconnected"));
1213 }
1214
1215 #[test]
1216 fn test_per_addr_single_device_ignored() {
1217 let mut base = PortDriverBase::new("single", 1, PortFlags::default());
1218 base.create_param("V", ParamType::Int32).unwrap();
1219 assert!(base.check_ready_addr(0).is_ok());
1221 }
1222
1223 #[test]
1224 fn test_timestamp_source() {
1225 let mut base = PortDriverBase::new("ts_test", 1, PortFlags::default());
1226 base.create_param("V", ParamType::Int32).unwrap();
1227
1228 let fixed_ts = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(999999);
1229 base.register_timestamp_source(move || fixed_ts);
1230
1231 assert_eq!(base.current_timestamp(), fixed_ts);
1232 }
1233
1234 #[test]
1235 fn test_timestamp_source_in_callbacks() {
1236 let mut base = PortDriverBase::new("ts_cb", 1, PortFlags::default());
1237 base.create_param("V", ParamType::Int32).unwrap();
1238 let mut rx = base.interrupts.subscribe_async();
1239
1240 let fixed_ts = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(123456);
1241 base.register_timestamp_source(move || fixed_ts);
1242
1243 struct TsDriver {
1244 base: PortDriverBase,
1245 }
1246 impl PortDriver for TsDriver {
1247 fn base(&self) -> &PortDriverBase {
1248 &self.base
1249 }
1250 fn base_mut(&mut self) -> &mut PortDriverBase {
1251 &mut self.base
1252 }
1253 }
1254 let mut drv = TsDriver { base };
1255 drv.base_mut().set_int32_param(0, 0, 42).unwrap();
1256 drv.base_mut().call_param_callbacks(0).unwrap();
1257
1258 let v = rx.try_recv().unwrap();
1259 assert_eq!(v.timestamp, fixed_ts);
1261 }
1262
1263 #[test]
1264 fn test_queue_priority_connect() {
1265 assert!(QueuePriority::Connect > QueuePriority::High);
1266 }
1267
1268 #[test]
1269 fn test_port_flags_destructible_default() {
1270 let flags = PortFlags::default();
1271 assert!(flags.destructible);
1272 }
1273
1274 #[test]
1277 fn test_connect_addr() {
1278 let mut base = PortDriverBase::new(
1279 "multi_conn",
1280 4,
1281 PortFlags {
1282 multi_device: true,
1283 can_block: false,
1284 destructible: true,
1285 },
1286 );
1287 base.create_param("V", ParamType::Int32).unwrap();
1288
1289 base.disconnect_addr(1);
1290 assert!(!base.is_device_connected(1));
1291 assert!(base.check_ready_addr(1).is_err());
1292
1293 base.connect_addr(1);
1294 assert!(base.is_device_connected(1));
1295 assert!(base.check_ready_addr(1).is_ok());
1296 }
1297
1298 #[test]
1299 fn test_enable_disable_addr() {
1300 let mut base = PortDriverBase::new(
1301 "multi_en",
1302 4,
1303 PortFlags {
1304 multi_device: true,
1305 can_block: false,
1306 destructible: true,
1307 },
1308 );
1309 base.create_param("V", ParamType::Int32).unwrap();
1310
1311 base.disable_addr(2);
1312 let err = base.check_ready_addr(2).unwrap_err();
1313 assert!(format!("{err}").contains("disabled"));
1314
1315 base.enable_addr(2);
1316 assert!(base.check_ready_addr(2).is_ok());
1317 }
1318
1319 #[test]
1320 fn test_port_level_overrides_addr() {
1321 let mut base = PortDriverBase::new(
1322 "multi_override",
1323 4,
1324 PortFlags {
1325 multi_device: true,
1326 can_block: false,
1327 destructible: true,
1328 },
1329 );
1330 base.create_param("V", ParamType::Int32).unwrap();
1331
1332 base.enabled = false;
1334 base.enable_addr(0); let err = base.check_ready_addr(0).unwrap_err();
1336 assert!(format!("{err}").contains("disabled"));
1337 }
1338
1339 #[test]
1340 fn test_per_addr_exception_announced() {
1341 use std::sync::atomic::{AtomicI32, Ordering};
1342
1343 let mut base = PortDriverBase::new(
1344 "multi_exc",
1345 4,
1346 PortFlags {
1347 multi_device: true,
1348 can_block: false,
1349 destructible: true,
1350 },
1351 );
1352 base.create_param("V", ParamType::Int32).unwrap();
1353
1354 let exc_mgr = Arc::new(crate::exception::ExceptionManager::new());
1355 base.exception_sink = Some(exc_mgr.clone());
1356
1357 let last_addr = Arc::new(AtomicI32::new(-99));
1358 let last_addr2 = last_addr.clone();
1359 exc_mgr.add_callback(move |event| {
1360 last_addr2.store(event.addr, Ordering::Relaxed);
1361 });
1362
1363 base.disconnect_addr(3);
1364 assert_eq!(last_addr.load(Ordering::Relaxed), 3);
1365
1366 base.enable_addr(2);
1367 assert_eq!(last_addr.load(Ordering::Relaxed), 2);
1368 }
1369}