1#![forbid(unsafe_code)]
2
3use parking_lot::Mutex;
32use pico_common::{PicoChannel, PicoInfo, PicoRange, PicoResult};
33use pico_driver::{ArcDriver, PicoDriver};
34use std::{
35 collections::HashMap,
36 fmt,
37 fmt::{Debug, Display},
38 sync::Arc,
39};
40
41pub type HandleMutex = Arc<Mutex<Option<i16>>>;
42
43#[cfg_attr(feature = "serde", derive(serde::Serialize))]
45#[derive(Clone)]
46pub struct PicoDevice {
47 #[cfg_attr(feature = "serde", serde(skip))]
48 pub handle: HandleMutex,
49 #[cfg_attr(feature = "serde", serde(skip))]
50 pub driver: ArcDriver,
51 pub variant: String,
52 pub serial: String,
53 pub usb_version: String,
54 #[cfg_attr(feature = "serde", serde(skip))]
55 pub max_adc_value: i16,
56 pub channel_ranges: HashMap<PicoChannel, Vec<PicoRange>>,
57}
58
59impl Debug for PicoDevice {
60 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
61 f.debug_struct("PicoDevice")
62 .field("variant", &self.variant)
63 .field("serial", &self.serial)
64 .finish()
65 }
66}
67
68impl Display for PicoDevice {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 write!(f, "{} ({})", self.variant, self.serial)
71 }
72}
73
74impl PicoDevice {
75 pub fn try_open(driver: &Arc<dyn PicoDriver>, serial: Option<&str>) -> PicoResult<PicoDevice> {
92 let handle = driver.open_unit(serial)?;
93
94 let serial = match serial {
95 Some(s) => s.to_string(),
96 None => driver.get_unit_info(handle, PicoInfo::BATCH_AND_SERIAL)?,
97 };
98
99 let variant = driver.get_unit_info(handle, PicoInfo::VARIANT_INFO)?;
100 let usb_version = driver.get_unit_info(handle, PicoInfo::USB_VERSION)?;
101
102 let ch_count = variant[1..2]
104 .parse::<i32>()
105 .expect("Could not parse device variant for number of channels");
106
107 let channel_ranges = (0..ch_count)
108 .map(|ch| -> PicoResult<(PicoChannel, Vec<_>)> {
109 let ch: PicoChannel = ch.into();
110 Ok((ch, driver.get_channel_ranges(handle, ch)?))
111 })
112 .flatten()
114 .collect();
115
116 let max_adc_value = driver.maximum_value(handle)?;
117
118 Ok(PicoDevice {
119 handle: Arc::new(Mutex::new(Some(handle))),
120 driver: driver.clone(),
121 serial,
122 variant,
123 usb_version,
124 max_adc_value,
125 channel_ranges,
126 })
127 }
128
129 pub fn get_channels(&self) -> Vec<PicoChannel> {
130 self.channel_ranges.keys().copied().collect()
131 }
132}
133
134impl Drop for PicoDevice {
135 #[tracing::instrument(level = "trace", skip(self))]
136 fn drop(&mut self) {
137 if let Some(handle) = self.handle.lock().take() {
138 let _ = self.driver.close(handle);
139 }
140 }
141}