std_rs/device_support/epid_soft_callback.rs
1use epics_base_rs::error::CaResult;
2use epics_base_rs::server::device_support::{DeviceReadOutcome, DeviceSupport};
3use epics_base_rs::server::record::Record;
4
5use crate::records::epid::EpidRecord;
6
7/// Async Soft Channel device support for the epid record
8/// (`devEpidSoftCallback.c`, DSET `devEpidSoftCB`).
9///
10/// Same PID algorithm as `EpidSoftDeviceSupport`, plus the asynchronous
11/// readback trigger on the TRIG link. The trigger itself is NOT emitted
12/// from here: `stdSupport.dbd:14` selects this DSET with DTYP
13/// `"Async Soft Channel"`, which `is_soft_dtyp` classifies as a soft
14/// channel, so the framework never attaches a device for it and this
15/// `read()` never runs for a record loaded from a `.db`. Both TRIG link
16/// types are therefore fired by [`EpidRecord::pre_input_link_actions`],
17/// which is reached on the record-internal soft path — one owner, one
18/// push site. This impl stays as the record type's declared DSET (the
19/// same vestigial role `EpidSoftDeviceSupport` plays for
20/// `"Soft Channel"`) and runs the PID if something does attach it.
21pub struct EpidSoftCallbackDeviceSupport;
22
23impl Default for EpidSoftCallbackDeviceSupport {
24 fn default() -> Self {
25 Self::new()
26 }
27}
28
29impl EpidSoftCallbackDeviceSupport {
30 pub fn new() -> Self {
31 Self
32 }
33}
34
35impl DeviceSupport for EpidSoftCallbackDeviceSupport {
36 fn dtyp(&self) -> &str {
37 "Async Soft Channel"
38 }
39
40 fn read(&mut self, record: &mut dyn Record) -> CaResult<DeviceReadOutcome> {
41 let epid = record
42 .as_any_mut()
43 .and_then(|a| a.downcast_mut::<EpidRecord>())
44 .expect("EpidSoftCallbackDeviceSupport requires an EpidRecord");
45 super::epid_soft::EpidSoftDeviceSupport::do_pid(epid);
46 Ok(DeviceReadOutcome::computed())
47 }
48
49 fn write(&mut self, _record: &mut dyn Record) -> CaResult<()> {
50 Ok(())
51 }
52}