skf_rs/engine/
manager.rs

1use crate::engine::device::SkfDeviceImpl;
2use crate::engine::symbol::ModMag;
3use crate::error::SkfErr;
4use crate::helper::{mem, param};
5use crate::{DeviceManager, PluginEvent, SkfDevice};
6use crate::{Error, Result};
7use skf_api::native::error::SAR_OK;
8use skf_api::native::types::{BOOL, CHAR, HANDLE, ULONG};
9use std::fmt::Debug;
10use std::sync::Arc;
11use tracing::{instrument, trace};
12
13pub(crate) struct ManagerImpl {
14    lib: Arc<libloading::Library>,
15    symbols: ModMag,
16}
17
18impl ManagerImpl {
19    /// Initialize
20    ///
21    /// [lib] - The library handle
22    pub fn new(lib: &Arc<libloading::Library>) -> Result<Self> {
23        let lc = Arc::clone(lib);
24        let symbols = ModMag::load_symbols(lib)?;
25        Ok(Self { lib: lc, symbols })
26    }
27}
28
29impl Debug for ManagerImpl {
30    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
31        write!(f, "ManagerImpl")
32    }
33}
34
35impl DeviceManager for ManagerImpl {
36    #[instrument]
37    fn enumerate_device_name(&self, presented_only: bool) -> Result<Vec<String>> {
38        let func = self.symbols.enum_dev.as_ref().expect("Symbol not load");
39        let mut len: ULONG = 0;
40        let ret = unsafe { func(presented_only as BOOL, std::ptr::null_mut(), &mut len) };
41        if ret != SAR_OK {
42            return Err(Error::Skf(SkfErr::of_code(ret)));
43        }
44        trace!("[SKF_EnumDev]: desired len = {}", len);
45        if len == 0 {
46            return Ok(vec![]);
47        }
48        let mut buff = Vec::<CHAR>::with_capacity(len as usize);
49        let ret = unsafe { func(presented_only as BOOL, buff.as_mut_ptr(), &mut len) };
50        trace!("[SKF_EnumDev]: ret = {}", ret);
51        if ret != SAR_OK {
52            return Err(Error::Skf(SkfErr::of_code(ret)));
53        }
54        unsafe { buff.set_len(len as usize) };
55        trace!(
56            "[SKF_EnumDev]: device list = {}",
57            String::from_utf8_lossy(&buff)
58        );
59        // The spec says string list end with two '\0',but vendor may not do it
60        let list = unsafe { mem::parse_cstr_list_lossy(buff.as_ptr(), buff.len()) };
61        Ok(list)
62    }
63
64    #[instrument]
65    fn device_state(&self, device_name: &str) -> Result<u32> {
66        let func = self
67            .symbols
68            .get_dev_state
69            .as_ref()
70            .expect("Symbol not load");
71        let device_name = param::as_cstring("device_name", device_name)?;
72        let mut satate: ULONG = 0;
73        let ret = unsafe { func(device_name.as_ptr() as *const CHAR, &mut satate) };
74        if ret != SAR_OK {
75            return Err(Error::Skf(SkfErr::of_code(ret)));
76        }
77        Ok(satate as u32)
78    }
79
80    #[instrument]
81    fn wait_plug_event(&self) -> Result<Option<PluginEvent>> {
82        let func = self
83            .symbols
84            .wait_plug_event
85            .as_ref()
86            .expect("Symbol not load");
87        let mut buff = Vec::<CHAR>::with_capacity(1024);
88        let mut len: ULONG = buff.capacity() as ULONG;
89        let mut event: ULONG = 0;
90        let ret = unsafe { func(buff.as_mut_ptr(), &mut len, &mut event) };
91        trace!("[SKF_WaitForDevEvent]: ret = {}", ret);
92        if ret != SAR_OK {
93            return Err(Error::Skf(SkfErr::of_code(ret)));
94        }
95        trace!(
96            "[SKF_WaitForDevEvent]: event = {},data len = {}",
97            event,
98            len
99        );
100        let name = unsafe { mem::parse_cstr_lossy(buff.as_ptr(), len as usize) };
101        let name = name.unwrap_or("".to_string());
102        let event = event as u8;
103        match event {
104            PluginEvent::EVENT_PLUGGED_IN | PluginEvent::EVENT_UNPLUGGED => {
105                Ok(Some(PluginEvent::new(name, event)))
106            }
107            _ => Ok(None),
108        }
109    }
110
111    #[instrument]
112    fn cancel_wait_plug_event(&self) -> Result<()> {
113        let func = self
114            .symbols
115            .cancel_wait_plug_event
116            .as_ref()
117            .expect("Symbol not load");
118        let ret = unsafe { func() };
119        trace!("[SKF_CancelWaitForDevEvent]: ret = {}", ret);
120        if ret != SAR_OK {
121            return Err(Error::Skf(SkfErr::of_code(ret)));
122        }
123        Ok(())
124    }
125
126    #[instrument]
127    fn connect(&self, device_name: &str) -> Result<Box<dyn SkfDevice>> {
128        let func = self.symbols.connect_dev.as_ref().expect("Symbol not load");
129        let c_name = param::as_cstring("device_name", device_name)?;
130        let mut handle: HANDLE = std::ptr::null_mut();
131        let ret = unsafe { func(c_name.as_ptr() as *const CHAR, &mut handle) };
132        trace!("[SKF_ConnectDev]: ret = {}", ret);
133        if ret != SAR_OK {
134            return Err(Error::Skf(SkfErr::of_code(ret)));
135        }
136        let dev = SkfDeviceImpl::new(handle, device_name, &self.lib)?;
137        Ok(Box::new(dev))
138    }
139
140    fn connect_selected(
141        &self,
142        selector: fn(Vec<&str>) -> Option<&str>,
143    ) -> Result<Box<dyn SkfDevice>> {
144        let list = self.enumerate_device_name(true)?;
145        if list.is_empty() {
146            Err(Error::NotFound("No device found".to_string()))
147        } else {
148            let names: Vec<&str> = list.iter().map(|x| &**x).collect();
149            if let Some(name) = selector(names) {
150                let dev = self.connect(name)?;
151                return Ok(dev);
152            }
153            Err(Error::NotFound("No matched device".to_string()))
154        }
155    }
156}
157
158impl PluginEvent {
159    /// The device is plugged in
160    pub const EVENT_PLUGGED_IN: u8 = 1;
161
162    /// The device is unplugged
163    pub const EVENT_UNPLUGGED: u8 = 2;
164
165    pub fn new(device_name: impl Into<String>, event: u8) -> Self {
166        Self {
167            device_name: device_name.into(),
168            event,
169        }
170    }
171
172    pub fn plugged_in(device_name: impl AsRef<str>) -> Self {
173        Self {
174            device_name: device_name.as_ref().to_string(),
175            event: Self::EVENT_PLUGGED_IN,
176        }
177    }
178
179    pub fn unplugged(device_name: impl AsRef<str>) -> Self {
180        Self {
181            device_name: device_name.as_ref().to_string(),
182            event: Self::EVENT_UNPLUGGED,
183        }
184    }
185
186    pub fn is_plugged_in(&self) -> bool {
187        self.event == Self::EVENT_PLUGGED_IN
188    }
189
190    pub fn is_unplugged(&self) -> bool {
191        self.event == Self::EVENT_UNPLUGGED
192    }
193
194    pub fn event_description(&self) -> &'static str {
195        match self.event {
196            Self::EVENT_PLUGGED_IN => "plugged in",
197            Self::EVENT_UNPLUGGED => "unplugged",
198            _ => "unknown",
199        }
200    }
201}