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.get(&addr).map_or(true, |ds| ds.connected)
200 }
201
202 pub fn connect_addr(&mut self, addr: i32) {
204 self.device_state(addr).connected = true;
205 self.announce_exception(AsynException::Connect, addr);
206 }
207
208 pub fn disconnect_addr(&mut self, addr: i32) {
210 self.device_state(addr).connected = false;
211 self.announce_exception(AsynException::Connect, addr);
212 }
213
214 pub fn enable_addr(&mut self, addr: i32) {
216 self.device_state(addr).enabled = true;
217 self.announce_exception(AsynException::Enable, addr);
218 }
219
220 pub fn disable_addr(&mut self, addr: i32) {
222 self.device_state(addr).enabled = false;
223 self.announce_exception(AsynException::Enable, addr);
224 }
225
226 pub fn register_timestamp_source<F>(&mut self, source: F)
228 where
229 F: Fn() -> SystemTime + Send + Sync + 'static,
230 {
231 self.timestamp_source = Some(Arc::new(source));
232 }
233
234 pub fn current_timestamp(&self) -> SystemTime {
236 self.timestamp_source.as_ref().map_or_else(SystemTime::now, |f| f())
237 }
238
239 pub fn create_param(&mut self, name: &str, param_type: ParamType) -> AsynResult<usize> {
240 self.params.create_param(name, param_type)
241 }
242
243 pub fn find_param(&self, name: &str) -> Option<usize> {
244 self.params.find_param(name)
245 }
246
247 pub fn set_int32_param(&mut self, index: usize, addr: i32, value: i32) -> AsynResult<()> {
250 self.params.set_int32(index, addr, value)
251 }
252
253 pub fn get_int32_param(&self, index: usize, addr: i32) -> AsynResult<i32> {
254 self.params.get_int32(index, addr)
255 }
256
257 pub fn set_int64_param(&mut self, index: usize, addr: i32, value: i64) -> AsynResult<()> {
258 self.params.set_int64(index, addr, value)
259 }
260
261 pub fn get_int64_param(&self, index: usize, addr: i32) -> AsynResult<i64> {
262 self.params.get_int64(index, addr)
263 }
264
265 pub fn set_float64_param(&mut self, index: usize, addr: i32, value: f64) -> AsynResult<()> {
266 self.params.set_float64(index, addr, value)
267 }
268
269 pub fn get_float64_param(&self, index: usize, addr: i32) -> AsynResult<f64> {
270 self.params.get_float64(index, addr)
271 }
272
273 pub fn set_string_param(&mut self, index: usize, addr: i32, value: String) -> AsynResult<()> {
274 self.params.set_string(index, addr, value)
275 }
276
277 pub fn get_string_param(&self, index: usize, addr: i32) -> AsynResult<&str> {
278 self.params.get_string(index, addr)
279 }
280
281 pub fn set_uint32_param(
282 &mut self,
283 index: usize,
284 addr: i32,
285 value: u32,
286 mask: u32,
287 ) -> AsynResult<()> {
288 self.params.set_uint32(index, addr, value, mask)
289 }
290
291 pub fn get_uint32_param(&self, index: usize, addr: i32) -> AsynResult<u32> {
292 self.params.get_uint32(index, addr)
293 }
294
295 pub fn get_enum_param(&self, index: usize, addr: i32) -> AsynResult<(usize, Arc<[EnumEntry]>)> {
296 self.params.get_enum(index, addr)
297 }
298
299 pub fn set_enum_index_param(&mut self, index: usize, addr: i32, value: usize) -> AsynResult<()> {
300 self.params.set_enum_index(index, addr, value)
301 }
302
303 pub fn set_enum_choices_param(&mut self, index: usize, addr: i32, choices: Arc<[EnumEntry]>) -> AsynResult<()> {
304 self.params.set_enum_choices(index, addr, choices)
305 }
306
307 pub fn get_generic_pointer_param(&self, index: usize, addr: i32) -> AsynResult<Arc<dyn Any + Send + Sync>> {
308 self.params.get_generic_pointer(index, addr)
309 }
310
311 pub fn set_generic_pointer_param(&mut self, index: usize, addr: i32, value: Arc<dyn Any + Send + Sync>) -> AsynResult<()> {
312 self.params.set_generic_pointer(index, addr, value)
313 }
314
315 pub fn set_param_timestamp(&mut self, index: usize, addr: i32, ts: SystemTime) -> AsynResult<()> {
316 self.params.set_timestamp(index, addr, ts)
317 }
318
319 pub fn push_octet_interpose(&mut self, layer: Box<dyn OctetInterpose>) {
325 self.interpose_octet.push(layer);
326 }
327
328 pub fn call_param_callbacks(&mut self, addr: i32) -> AsynResult<()> {
331 let changed = self.params.take_changed(addr)?;
332 let now = self.current_timestamp();
333 for reason in changed {
334 let value = self.params.get_value(reason, addr)?.clone();
335 let ts = self.params.get_timestamp(reason, addr)?.unwrap_or(now);
336 self.interrupts.notify(InterruptValue {
337 reason,
338 addr,
339 value,
340 timestamp: ts,
341 });
342 }
343 Ok(())
344 }
345}
346
347pub trait PortDriver: Send + Sync + 'static {
362 fn base(&self) -> &PortDriverBase;
363 fn base_mut(&mut self) -> &mut PortDriverBase;
364
365 fn connect(&mut self, _user: &AsynUser) -> AsynResult<()> {
368 self.base_mut().connected = true;
369 self.base().announce_exception(AsynException::Connect, -1);
370 Ok(())
371 }
372
373 fn disconnect(&mut self, _user: &AsynUser) -> AsynResult<()> {
374 self.base_mut().connected = false;
375 self.base().announce_exception(AsynException::Connect, -1);
376 Ok(())
377 }
378
379 fn enable(&mut self, _user: &AsynUser) -> AsynResult<()> {
380 self.base_mut().enabled = true;
381 self.base().announce_exception(AsynException::Enable, -1);
382 Ok(())
383 }
384
385 fn disable(&mut self, _user: &AsynUser) -> AsynResult<()> {
386 self.base_mut().enabled = false;
387 self.base().announce_exception(AsynException::Enable, -1);
388 Ok(())
389 }
390
391 fn connect_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
392 self.base_mut().connect_addr(user.addr);
393 Ok(())
394 }
395
396 fn disconnect_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
397 self.base_mut().disconnect_addr(user.addr);
398 Ok(())
399 }
400
401 fn enable_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
402 self.base_mut().enable_addr(user.addr);
403 Ok(())
404 }
405
406 fn disable_addr(&mut self, user: &AsynUser) -> AsynResult<()> {
407 self.base_mut().disable_addr(user.addr);
408 Ok(())
409 }
410
411 fn get_option(&self, key: &str) -> AsynResult<String> {
412 self.base().options.get(key)
413 .cloned()
414 .ok_or_else(|| AsynError::OptionNotFound(key.to_string()))
415 }
416
417 fn set_option(&mut self, key: &str, value: &str) -> AsynResult<()> {
418 self.base_mut().options.insert(key.to_string(), value.to_string());
419 Ok(())
420 }
421
422 fn report(&self, level: i32) {
423 let base = self.base();
424 eprintln!("Port: {}", base.port_name);
425 eprintln!(" connected: {}, max_addr: {}, params: {}, options: {}",
426 base.connected, base.max_addr, base.params.len(), base.options.len());
427 if level >= 1 {
428 for i in 0..base.params.len() {
429 if let (Some(name), Some(ptype)) = (base.params.param_name(i), base.params.param_type(i)) {
430 if level >= 3 {
431 let val = base.params.get_value(i, 0)
432 .map(|v| format!("{v:?}")).unwrap_or("?".into());
433 eprintln!(" param[{i}]: {name} ({ptype:?}) = {val}");
434 } else {
435 eprintln!(" param[{i}]: {name} ({ptype:?})");
436 }
437 }
438 }
439 }
440 if level >= 2 {
441 for (k, v) in &base.options {
442 eprintln!(" option: {k} = {v}");
443 }
444 }
445 }
446
447 fn read_int32(&mut self, user: &AsynUser) -> AsynResult<i32> {
450 self.base().check_ready()?;
451 self.base().params.get_int32(user.reason, user.addr)
452 }
453
454 fn write_int32(&mut self, user: &mut AsynUser, value: i32) -> AsynResult<()> {
455 self.base().check_ready()?;
456 self.base_mut()
457 .params
458 .set_int32(user.reason, user.addr, value)?;
459 self.base_mut().call_param_callbacks(user.addr)
460 }
461
462 fn read_int64(&mut self, user: &AsynUser) -> AsynResult<i64> {
463 self.base().check_ready()?;
464 self.base().params.get_int64(user.reason, user.addr)
465 }
466
467 fn write_int64(&mut self, user: &mut AsynUser, value: i64) -> AsynResult<()> {
468 self.base().check_ready()?;
469 self.base_mut()
470 .params
471 .set_int64(user.reason, user.addr, value)?;
472 self.base_mut().call_param_callbacks(user.addr)
473 }
474
475 fn get_bounds_int64(&self, _user: &AsynUser) -> AsynResult<(i64, i64)> {
476 Ok((i64::MIN, i64::MAX))
477 }
478
479 fn read_float64(&mut self, user: &AsynUser) -> AsynResult<f64> {
480 self.base().check_ready()?;
481 self.base().params.get_float64(user.reason, user.addr)
482 }
483
484 fn write_float64(&mut self, user: &mut AsynUser, value: f64) -> AsynResult<()> {
485 self.base().check_ready()?;
486 self.base_mut()
487 .params
488 .set_float64(user.reason, user.addr, value)?;
489 self.base_mut().call_param_callbacks(user.addr)
490 }
491
492 fn read_octet(&mut self, user: &AsynUser, buf: &mut [u8]) -> AsynResult<usize> {
493 self.base().check_ready()?;
494 let s = self.base().params.get_string(user.reason, user.addr)?;
495 let bytes = s.as_bytes();
496 let n = bytes.len().min(buf.len());
497 buf[..n].copy_from_slice(&bytes[..n]);
498 Ok(n)
499 }
500
501 fn write_octet(&mut self, user: &mut AsynUser, data: &[u8]) -> AsynResult<()> {
502 self.base().check_ready()?;
503 let s = String::from_utf8_lossy(data).into_owned();
504 self.base_mut()
505 .params
506 .set_string(user.reason, user.addr, s)?;
507 self.base_mut().call_param_callbacks(user.addr)
508 }
509
510 fn read_uint32_digital(&mut self, user: &AsynUser, mask: u32) -> AsynResult<u32> {
511 self.base().check_ready()?;
512 let val = self.base().params.get_uint32(user.reason, user.addr)?;
513 Ok(val & mask)
514 }
515
516 fn write_uint32_digital(
517 &mut self,
518 user: &mut AsynUser,
519 value: u32,
520 mask: u32,
521 ) -> AsynResult<()> {
522 self.base().check_ready()?;
523 self.base_mut()
524 .params
525 .set_uint32(user.reason, user.addr, value, mask)?;
526 self.base_mut().call_param_callbacks(user.addr)
527 }
528
529 fn read_enum(&mut self, user: &AsynUser) -> AsynResult<(usize, Arc<[EnumEntry]>)> {
532 self.base().check_ready()?;
533 self.base().params.get_enum(user.reason, user.addr)
534 }
535
536 fn write_enum(&mut self, user: &mut AsynUser, index: usize) -> AsynResult<()> {
537 self.base().check_ready()?;
538 self.base_mut().params.set_enum_index(user.reason, user.addr, index)?;
539 self.base_mut().call_param_callbacks(user.addr)
540 }
541
542 fn write_enum_choices(&mut self, user: &mut AsynUser, choices: Arc<[EnumEntry]>) -> AsynResult<()> {
543 self.base().check_ready()?;
544 self.base_mut().params.set_enum_choices(user.reason, user.addr, choices)?;
545 self.base_mut().call_param_callbacks(user.addr)
546 }
547
548 fn read_generic_pointer(&mut self, user: &AsynUser) -> AsynResult<Arc<dyn Any + Send + Sync>> {
551 self.base().check_ready()?;
552 self.base().params.get_generic_pointer(user.reason, user.addr)
553 }
554
555 fn write_generic_pointer(&mut self, user: &mut AsynUser, value: Arc<dyn Any + Send + Sync>) -> AsynResult<()> {
556 self.base().check_ready()?;
557 self.base_mut().params.set_generic_pointer(user.reason, user.addr, value)?;
558 self.base_mut().call_param_callbacks(user.addr)
559 }
560
561 fn read_float64_array(&mut self, _user: &AsynUser, _buf: &mut [f64]) -> AsynResult<usize> {
564 Err(AsynError::InterfaceNotSupported(
565 "asynFloat64Array".into(),
566 ))
567 }
568
569 fn write_float64_array(&mut self, _user: &AsynUser, _data: &[f64]) -> AsynResult<()> {
570 Err(AsynError::InterfaceNotSupported(
571 "asynFloat64Array".into(),
572 ))
573 }
574
575 fn read_int32_array(&mut self, _user: &AsynUser, _buf: &mut [i32]) -> AsynResult<usize> {
576 Err(AsynError::InterfaceNotSupported("asynInt32Array".into()))
577 }
578
579 fn write_int32_array(&mut self, _user: &AsynUser, _data: &[i32]) -> AsynResult<()> {
580 Err(AsynError::InterfaceNotSupported("asynInt32Array".into()))
581 }
582
583 fn read_int8_array(&mut self, _user: &AsynUser, _buf: &mut [i8]) -> AsynResult<usize> {
584 Err(AsynError::InterfaceNotSupported("asynInt8Array".into()))
585 }
586
587 fn write_int8_array(&mut self, _user: &AsynUser, _data: &[i8]) -> AsynResult<()> {
588 Err(AsynError::InterfaceNotSupported("asynInt8Array".into()))
589 }
590
591 fn read_int16_array(&mut self, _user: &AsynUser, _buf: &mut [i16]) -> AsynResult<usize> {
592 Err(AsynError::InterfaceNotSupported("asynInt16Array".into()))
593 }
594
595 fn write_int16_array(&mut self, _user: &AsynUser, _data: &[i16]) -> AsynResult<()> {
596 Err(AsynError::InterfaceNotSupported("asynInt16Array".into()))
597 }
598
599 fn read_int64_array(&mut self, _user: &AsynUser, _buf: &mut [i64]) -> AsynResult<usize> {
600 Err(AsynError::InterfaceNotSupported("asynInt64Array".into()))
601 }
602
603 fn write_int64_array(&mut self, _user: &AsynUser, _data: &[i64]) -> AsynResult<()> {
604 Err(AsynError::InterfaceNotSupported("asynInt64Array".into()))
605 }
606
607 fn read_float32_array(&mut self, _user: &AsynUser, _buf: &mut [f32]) -> AsynResult<usize> {
608 Err(AsynError::InterfaceNotSupported("asynFloat32Array".into()))
609 }
610
611 fn write_float32_array(&mut self, _user: &AsynUser, _data: &[f32]) -> AsynResult<()> {
612 Err(AsynError::InterfaceNotSupported("asynFloat32Array".into()))
613 }
614
615 fn io_read_octet(&mut self, user: &AsynUser, buf: &mut [u8]) -> AsynResult<usize> {
620 self.read_octet(user, buf)
621 }
622
623 fn io_write_octet(&mut self, user: &mut AsynUser, data: &[u8]) -> AsynResult<()> {
624 self.write_octet(user, data)
625 }
626
627 fn io_read_int32(&mut self, user: &AsynUser) -> AsynResult<i32> {
628 self.read_int32(user)
629 }
630
631 fn io_write_int32(&mut self, user: &mut AsynUser, value: i32) -> AsynResult<()> {
632 self.write_int32(user, value)
633 }
634
635 fn io_read_int64(&mut self, user: &AsynUser) -> AsynResult<i64> {
636 self.read_int64(user)
637 }
638
639 fn io_write_int64(&mut self, user: &mut AsynUser, value: i64) -> AsynResult<()> {
640 self.write_int64(user, value)
641 }
642
643 fn io_read_float64(&mut self, user: &AsynUser) -> AsynResult<f64> {
644 self.read_float64(user)
645 }
646
647 fn io_write_float64(&mut self, user: &mut AsynUser, value: f64) -> AsynResult<()> {
648 self.write_float64(user, value)
649 }
650
651 fn io_read_uint32_digital(&mut self, user: &AsynUser, mask: u32) -> AsynResult<u32> {
652 self.read_uint32_digital(user, mask)
653 }
654
655 fn io_write_uint32_digital(
656 &mut self,
657 user: &mut AsynUser,
658 value: u32,
659 mask: u32,
660 ) -> AsynResult<()> {
661 self.write_uint32_digital(user, value, mask)
662 }
663
664 fn io_flush(&mut self, _user: &mut AsynUser) -> AsynResult<()> {
665 Ok(())
666 }
667
668 fn drv_user_create(&self, drv_info: &str) -> AsynResult<usize> {
673 self.base()
674 .params
675 .find_param(drv_info)
676 .ok_or_else(|| AsynError::ParamNotFound(drv_info.to_string()))
677 }
678
679 fn capabilities(&self) -> Vec<crate::interfaces::Capability> {
684 crate::interfaces::default_capabilities()
685 }
686
687 fn supports(&self, cap: crate::interfaces::Capability) -> bool {
689 self.capabilities().contains(&cap)
690 }
691
692 fn init(&mut self) -> AsynResult<()> {
695 Ok(())
696 }
697}
698
699#[cfg(test)]
700mod tests {
701 use super::*;
702 struct TestDriver {
703 base: PortDriverBase,
704 }
705
706 impl TestDriver {
707 fn new() -> Self {
708 let mut base = PortDriverBase::new("test", 1, PortFlags::default());
709 base.create_param("VAL", ParamType::Int32).unwrap();
710 base.create_param("TEMP", ParamType::Float64).unwrap();
711 base.create_param("MSG", ParamType::Octet).unwrap();
712 base.create_param("BITS", ParamType::UInt32Digital).unwrap();
713 Self { base }
714 }
715 }
716
717 impl PortDriver for TestDriver {
718 fn base(&self) -> &PortDriverBase {
719 &self.base
720 }
721 fn base_mut(&mut self) -> &mut PortDriverBase {
722 &mut self.base
723 }
724 }
725
726 #[test]
727 fn test_default_read_write_int32() {
728 let mut drv = TestDriver::new();
729 let mut user = AsynUser::new(0);
730 drv.write_int32(&mut user, 42).unwrap();
731 let user = AsynUser::new(0);
732 assert_eq!(drv.read_int32(&user).unwrap(), 42);
733 }
734
735 #[test]
736 fn test_default_read_write_float64() {
737 let mut drv = TestDriver::new();
738 let mut user = AsynUser::new(1);
739 drv.write_float64(&mut user, 3.14).unwrap();
740 let user = AsynUser::new(1);
741 assert!((drv.read_float64(&user).unwrap() - 3.14).abs() < 1e-10);
742 }
743
744 #[test]
745 fn test_default_read_write_octet() {
746 let mut drv = TestDriver::new();
747 let mut user = AsynUser::new(2);
748 drv.write_octet(&mut user, b"hello").unwrap();
749 let user = AsynUser::new(2);
750 let mut buf = [0u8; 32];
751 let n = drv.read_octet(&user, &mut buf).unwrap();
752 assert_eq!(&buf[..n], b"hello");
753 }
754
755 #[test]
756 fn test_default_read_write_uint32() {
757 let mut drv = TestDriver::new();
758 let mut user = AsynUser::new(3);
759 drv.write_uint32_digital(&mut user, 0xFF, 0x0F).unwrap();
760 let user = AsynUser::new(3);
761 assert_eq!(drv.read_uint32_digital(&user, 0xFF).unwrap(), 0x0F);
762 }
763
764 #[test]
765 fn test_connect_disconnect() {
766 let mut drv = TestDriver::new();
767 let user = AsynUser::default();
768 assert!(drv.base().connected);
769 drv.disconnect(&user).unwrap();
770 assert!(!drv.base().connected);
771 drv.connect(&user).unwrap();
772 assert!(drv.base().connected);
773 }
774
775 #[test]
776 fn test_drv_user_create() {
777 let drv = TestDriver::new();
778 assert_eq!(drv.drv_user_create("VAL").unwrap(), 0);
779 assert_eq!(drv.drv_user_create("TEMP").unwrap(), 1);
780 assert!(drv.drv_user_create("NOPE").is_err());
781 }
782
783 #[test]
784 fn test_call_param_callbacks() {
785 let mut drv = TestDriver::new();
786 let rx = drv.base_mut().interrupts.subscribe_sync().unwrap();
787
788 drv.base_mut().set_int32_param(0, 0, 100).unwrap();
789 drv.base_mut().set_float64_param(1, 0, 2.0).unwrap();
790 drv.base_mut().call_param_callbacks(0).unwrap();
791
792 let v1 = rx.try_recv().unwrap();
793 assert_eq!(v1.reason, 0);
794 let v2 = rx.try_recv().unwrap();
795 assert_eq!(v2.reason, 1);
796 assert!(rx.try_recv().is_err());
797 }
798
799 #[test]
800 fn test_no_callback_for_unchanged() {
801 let mut drv = TestDriver::new();
802 let rx = drv.base_mut().interrupts.subscribe_sync().unwrap();
803
804 drv.base_mut().set_int32_param(0, 0, 5).unwrap();
805 drv.base_mut().call_param_callbacks(0).unwrap();
806 let _ = rx.try_recv().unwrap(); drv.base_mut().set_int32_param(0, 0, 5).unwrap();
810 drv.base_mut().call_param_callbacks(0).unwrap();
811 assert!(rx.try_recv().is_err());
812 }
813
814 #[test]
815 fn test_array_not_supported_by_default() {
816 let mut drv = TestDriver::new();
817 let user = AsynUser::new(0);
818 let mut buf = [0f64; 10];
819 assert!(drv.read_float64_array(&user, &mut buf).is_err());
820 assert!(drv.write_float64_array(&user, &[1.0]).is_err());
821 }
822
823 #[test]
824 fn test_option_set_get() {
825 let mut drv = TestDriver::new();
826 drv.set_option("baud", "9600").unwrap();
827 assert_eq!(drv.get_option("baud").unwrap(), "9600");
828 drv.set_option("baud", "115200").unwrap();
829 assert_eq!(drv.get_option("baud").unwrap(), "115200");
830 }
831
832 #[test]
833 fn test_option_not_found() {
834 let drv = TestDriver::new();
835 let err = drv.get_option("nonexistent").unwrap_err();
836 assert!(matches!(err, AsynError::OptionNotFound(_)));
837 }
838
839 #[test]
840 fn test_report_no_panic() {
841 let mut drv = TestDriver::new();
842 drv.set_option("testkey", "testval").unwrap();
843 drv.base_mut().set_int32_param(0, 0, 42).unwrap();
844 for level in 0..=3 {
845 drv.report(level);
846 }
847 }
848
849 #[test]
850 fn test_callback_uses_param_timestamp() {
851 let mut drv = TestDriver::new();
852 let rx = drv.base_mut().interrupts.subscribe_sync().unwrap();
853
854 let custom_ts = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_000_000);
855 drv.base_mut().set_int32_param(0, 0, 77).unwrap();
856 drv.base_mut().set_param_timestamp(0, 0, custom_ts).unwrap();
857 drv.base_mut().call_param_callbacks(0).unwrap();
858
859 let v = rx.try_recv().unwrap();
860 assert_eq!(v.reason, 0);
861 assert_eq!(v.timestamp, custom_ts);
862 }
863
864 #[test]
865 fn test_default_read_write_enum() {
866 use crate::param::EnumEntry;
867
868 let mut base = PortDriverBase::new("test_enum", 1, PortFlags::default());
869 base.create_param("MODE", ParamType::Enum).unwrap();
870
871 struct EnumDriver { base: PortDriverBase }
872 impl PortDriver for EnumDriver {
873 fn base(&self) -> &PortDriverBase { &self.base }
874 fn base_mut(&mut self) -> &mut PortDriverBase { &mut self.base }
875 }
876
877 let mut drv = EnumDriver { base };
878 let choices: Arc<[EnumEntry]> = Arc::from(vec![
879 EnumEntry { string: "Off".into(), value: 0, severity: 0 },
880 EnumEntry { string: "On".into(), value: 1, severity: 0 },
881 ]);
882 let mut user = AsynUser::new(0);
883 drv.write_enum_choices(&mut user, choices).unwrap();
884 drv.write_enum(&mut user, 1).unwrap();
885 let (idx, ch) = drv.read_enum(&AsynUser::new(0)).unwrap();
886 assert_eq!(idx, 1);
887 assert_eq!(ch[1].string, "On");
888 }
889
890 #[test]
891 fn test_enum_callback() {
892 use crate::param::{EnumEntry, ParamValue};
893
894 let mut base = PortDriverBase::new("test_enum_cb", 1, PortFlags::default());
895 base.create_param("MODE", ParamType::Enum).unwrap();
896 let rx = base.interrupts.subscribe_sync().unwrap();
897
898 struct EnumDriver { base: PortDriverBase }
899 impl PortDriver for EnumDriver {
900 fn base(&self) -> &PortDriverBase { &self.base }
901 fn base_mut(&mut self) -> &mut PortDriverBase { &mut self.base }
902 }
903
904 let mut drv = EnumDriver { base };
905 let choices: Arc<[EnumEntry]> = Arc::from(vec![
906 EnumEntry { string: "A".into(), value: 0, severity: 0 },
907 EnumEntry { string: "B".into(), value: 1, severity: 0 },
908 ]);
909 drv.base_mut().set_enum_choices_param(0, 0, choices).unwrap();
910 drv.base_mut().set_enum_index_param(0, 0, 1).unwrap();
911 drv.base_mut().call_param_callbacks(0).unwrap();
912
913 let v = rx.try_recv().unwrap();
914 assert_eq!(v.reason, 0);
915 assert!(matches!(v.value, ParamValue::Enum { index: 1, .. }));
916 }
917
918 #[test]
919 fn test_default_read_write_generic_pointer() {
920 let mut base = PortDriverBase::new("test_gp", 1, PortFlags::default());
921 base.create_param("PTR", ParamType::GenericPointer).unwrap();
922
923 struct GpDriver { base: PortDriverBase }
924 impl PortDriver for GpDriver {
925 fn base(&self) -> &PortDriverBase { &self.base }
926 fn base_mut(&mut self) -> &mut PortDriverBase { &mut self.base }
927 }
928
929 let mut drv = GpDriver { base };
930 let data: Arc<dyn std::any::Any + Send + Sync> = Arc::new(99i32);
931 let mut user = AsynUser::new(0);
932 drv.write_generic_pointer(&mut user, data).unwrap();
933 let val = drv.read_generic_pointer(&AsynUser::new(0)).unwrap();
934 assert_eq!(*val.downcast_ref::<i32>().unwrap(), 99);
935 }
936
937 #[test]
938 fn test_generic_pointer_callback() {
939 use crate::param::ParamValue;
940
941 let mut base = PortDriverBase::new("test_gp_cb", 1, PortFlags::default());
942 base.create_param("PTR", ParamType::GenericPointer).unwrap();
943 let rx = base.interrupts.subscribe_sync().unwrap();
944
945 struct GpDriver { base: PortDriverBase }
946 impl PortDriver for GpDriver {
947 fn base(&self) -> &PortDriverBase { &self.base }
948 fn base_mut(&mut self) -> &mut PortDriverBase { &mut self.base }
949 }
950
951 let mut drv = GpDriver { base };
952 let data: Arc<dyn std::any::Any + Send + Sync> = Arc::new(vec![1, 2, 3]);
953 drv.base_mut().set_generic_pointer_param(0, 0, data).unwrap();
954 drv.base_mut().call_param_callbacks(0).unwrap();
955
956 let v = rx.try_recv().unwrap();
957 assert_eq!(v.reason, 0);
958 assert!(matches!(v.value, ParamValue::GenericPointer(_)));
959 }
960
961 #[test]
962 fn test_interpose_push_requires_lock() {
963 use crate::interpose::{OctetInterpose, OctetNext, OctetReadResult};
964 use std::sync::Arc;
965 use parking_lot::Mutex;
966
967 struct NoopInterpose;
968 impl OctetInterpose for NoopInterpose {
969 fn read(&mut self, user: &AsynUser, buf: &mut [u8], next: &mut dyn OctetNext) -> AsynResult<OctetReadResult> {
970 next.read(user, buf)
971 }
972 fn write(&mut self, user: &mut AsynUser, data: &[u8], next: &mut dyn OctetNext) -> AsynResult<usize> {
973 next.write(user, data)
974 }
975 fn flush(&mut self, user: &mut AsynUser, next: &mut dyn OctetNext) -> AsynResult<()> {
976 next.flush(user)
977 }
978 }
979
980 let port: Arc<Mutex<dyn PortDriver>> = Arc::new(Mutex::new(TestDriver::new()));
981
982 {
983 let mut guard = port.lock();
984 guard.base_mut().push_octet_interpose(Box::new(NoopInterpose));
985 assert_eq!(guard.base().interpose_octet.len(), 1);
986 }
987 }
988
989 #[test]
990 fn test_default_read_write_int64() {
991 let mut base = PortDriverBase::new("test_i64", 1, PortFlags::default());
992 base.create_param("BIG", ParamType::Int64).unwrap();
993
994 struct I64Driver { base: PortDriverBase }
995 impl PortDriver for I64Driver {
996 fn base(&self) -> &PortDriverBase { &self.base }
997 fn base_mut(&mut self) -> &mut PortDriverBase { &mut self.base }
998 }
999
1000 let mut drv = I64Driver { base };
1001 let mut user = AsynUser::new(0);
1002 drv.write_int64(&mut user, i64::MAX).unwrap();
1003 assert_eq!(drv.read_int64(&AsynUser::new(0)).unwrap(), i64::MAX);
1004 }
1005
1006 #[test]
1007 fn test_get_bounds_int64_default() {
1008 let base = PortDriverBase::new("test_bounds", 1, PortFlags::default());
1009 struct BoundsDriver { base: PortDriverBase }
1010 impl PortDriver for BoundsDriver {
1011 fn base(&self) -> &PortDriverBase { &self.base }
1012 fn base_mut(&mut self) -> &mut PortDriverBase { &mut self.base }
1013 }
1014 let drv = BoundsDriver { base };
1015 let (lo, hi) = drv.get_bounds_int64(&AsynUser::default()).unwrap();
1016 assert_eq!(lo, i64::MIN);
1017 assert_eq!(hi, i64::MAX);
1018 }
1019
1020 #[test]
1021 fn test_per_addr_device_state() {
1022 let mut base = PortDriverBase::new("multi", 4, PortFlags {
1023 multi_device: true,
1024 can_block: false,
1025 destructible: true,
1026 });
1027 base.create_param("V", ParamType::Int32).unwrap();
1028
1029 assert!(base.is_device_connected(0));
1031 assert!(base.is_device_connected(1));
1032
1033 base.device_state(1).enabled = false;
1035 assert!(base.check_ready_addr(0).is_ok());
1036 let err = base.check_ready_addr(1).unwrap_err();
1037 assert!(format!("{err}").contains("disabled"));
1038
1039 base.device_state(2).connected = false;
1041 let err = base.check_ready_addr(2).unwrap_err();
1042 assert!(format!("{err}").contains("disconnected"));
1043 }
1044
1045 #[test]
1046 fn test_per_addr_single_device_ignored() {
1047 let mut base = PortDriverBase::new("single", 1, PortFlags::default());
1048 base.create_param("V", ParamType::Int32).unwrap();
1049 assert!(base.check_ready_addr(0).is_ok());
1051 }
1052
1053 #[test]
1054 fn test_timestamp_source() {
1055 let mut base = PortDriverBase::new("ts_test", 1, PortFlags::default());
1056 base.create_param("V", ParamType::Int32).unwrap();
1057
1058 let fixed_ts = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(999999);
1059 base.register_timestamp_source(move || fixed_ts);
1060
1061 assert_eq!(base.current_timestamp(), fixed_ts);
1062 }
1063
1064 #[test]
1065 fn test_timestamp_source_in_callbacks() {
1066 let mut base = PortDriverBase::new("ts_cb", 1, PortFlags::default());
1067 base.create_param("V", ParamType::Int32).unwrap();
1068 let rx = base.interrupts.subscribe_sync().unwrap();
1069
1070 let fixed_ts = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(123456);
1071 base.register_timestamp_source(move || fixed_ts);
1072
1073 struct TsDriver { base: PortDriverBase }
1074 impl PortDriver for TsDriver {
1075 fn base(&self) -> &PortDriverBase { &self.base }
1076 fn base_mut(&mut self) -> &mut PortDriverBase { &mut self.base }
1077 }
1078 let mut drv = TsDriver { base };
1079 drv.base_mut().set_int32_param(0, 0, 42).unwrap();
1080 drv.base_mut().call_param_callbacks(0).unwrap();
1081
1082 let v = rx.try_recv().unwrap();
1083 assert_eq!(v.timestamp, fixed_ts);
1085 }
1086
1087 #[test]
1088 fn test_queue_priority_connect() {
1089 assert!(QueuePriority::Connect > QueuePriority::High);
1090 }
1091
1092 #[test]
1093 fn test_port_flags_destructible_default() {
1094 let flags = PortFlags::default();
1095 assert!(flags.destructible);
1096 }
1097
1098 #[test]
1101 fn test_connect_addr() {
1102 let mut base = PortDriverBase::new("multi_conn", 4, PortFlags {
1103 multi_device: true,
1104 can_block: false,
1105 destructible: true,
1106 });
1107 base.create_param("V", ParamType::Int32).unwrap();
1108
1109 base.disconnect_addr(1);
1110 assert!(!base.is_device_connected(1));
1111 assert!(base.check_ready_addr(1).is_err());
1112
1113 base.connect_addr(1);
1114 assert!(base.is_device_connected(1));
1115 assert!(base.check_ready_addr(1).is_ok());
1116 }
1117
1118 #[test]
1119 fn test_enable_disable_addr() {
1120 let mut base = PortDriverBase::new("multi_en", 4, PortFlags {
1121 multi_device: true,
1122 can_block: false,
1123 destructible: true,
1124 });
1125 base.create_param("V", ParamType::Int32).unwrap();
1126
1127 base.disable_addr(2);
1128 let err = base.check_ready_addr(2).unwrap_err();
1129 assert!(format!("{err}").contains("disabled"));
1130
1131 base.enable_addr(2);
1132 assert!(base.check_ready_addr(2).is_ok());
1133 }
1134
1135 #[test]
1136 fn test_port_level_overrides_addr() {
1137 let mut base = PortDriverBase::new("multi_override", 4, PortFlags {
1138 multi_device: true,
1139 can_block: false,
1140 destructible: true,
1141 });
1142 base.create_param("V", ParamType::Int32).unwrap();
1143
1144 base.enabled = false;
1146 base.enable_addr(0); let err = base.check_ready_addr(0).unwrap_err();
1148 assert!(format!("{err}").contains("disabled"));
1149 }
1150
1151 #[test]
1152 fn test_per_addr_exception_announced() {
1153 use std::sync::atomic::{AtomicI32, Ordering};
1154
1155 let mut base = PortDriverBase::new("multi_exc", 4, PortFlags {
1156 multi_device: true,
1157 can_block: false,
1158 destructible: true,
1159 });
1160 base.create_param("V", ParamType::Int32).unwrap();
1161
1162 let exc_mgr = Arc::new(crate::exception::ExceptionManager::new());
1163 base.exception_sink = Some(exc_mgr.clone());
1164
1165 let last_addr = Arc::new(AtomicI32::new(-99));
1166 let last_addr2 = last_addr.clone();
1167 exc_mgr.add_callback(move |event| {
1168 last_addr2.store(event.addr, Ordering::Relaxed);
1169 });
1170
1171 base.disconnect_addr(3);
1172 assert_eq!(last_addr.load(Ordering::Relaxed), 3);
1173
1174 base.enable_addr(2);
1175 assert_eq!(last_addr.load(Ordering::Relaxed), 2);
1176 }
1177}