generic_camera/
dummy.rs

1/*!
2# Dummy camera driver
3
4This module contains a dummy camera that can be used for testing purposes, and as a reference or implementing new cameras.
5# Usage
6```
7use generic_camera::dummy::{GenCamDriverDummy, GenCamDummy};
8use generic_camera::{GenCam, GenCamDriver};
9use generic_camera::{GenCamCtrl, controls::ExposureCtrl};
10use std::time::Duration;
11let mut driver = GenCamDriverDummy {};
12let mut camera = driver.connect_first_device().expect("Failed to connect to camera");
13
14let img = camera.capture().expect("Failed to capture image");
15let exposure: Duration = camera.get_property(GenCamCtrl::Exposure(ExposureCtrl::ExposureTime)).expect("Failed to get exposure time").0.try_into().expect("Failed to convert exposure time");
16println!("Exposure time: {:?}", exposure);
17```
18*/
19use std::{
20    cell::RefCell,
21    collections::HashMap,
22    sync::{
23        atomic::{
24            AtomicBool,
25            Ordering::{Relaxed, SeqCst},
26        },
27        Arc,
28    },
29    thread,
30    time::{Duration, Instant, SystemTime},
31};
32
33use rand::{thread_rng, Rng};
34
35use refimage::{DynamicImageRef, GenericImageRef, ImageRef};
36
37use crate::{
38    controls::ExposureCtrl, property::PropertyLims, GenCam, GenCamCtrl, GenCamDescriptor,
39    GenCamDriver, GenCamError, GenCamResult, GenCamRoi, GenCamState, Property, PropertyError,
40    PropertyValue,
41};
42
43#[derive(Debug)]
44/// A dummy driver for testing purposes.
45pub struct GenCamDriverDummy {}
46
47impl GenCamDriver for GenCamDriverDummy {
48    fn available_devices(&self) -> usize {
49        1
50    }
51
52    fn list_devices(&mut self) -> GenCamResult<Vec<GenCamDescriptor>> {
53        let mut desc = GenCamDescriptor {
54            vendor: "Dummy".to_string(),
55            name: "Dummy Camera".to_string(),
56            id: 0xdeadbeef,
57            ..Default::default()
58        };
59        desc.info.insert("Interface".into(), "Aether".into());
60        Ok(vec![desc])
61    }
62
63    fn connect_device(&mut self, descriptor: &GenCamDescriptor) -> GenCamResult<crate::AnyGenCam> {
64        let mut caps = HashMap::new();
65        caps.insert(
66            GenCamCtrl::Exposure(ExposureCtrl::ExposureTime),
67            Property::new(
68                PropertyLims::Duration {
69                    min: Duration::from_millis(1),
70                    max: Duration::from_secs(60),
71                    step: Duration::from_millis(1),
72                    default: Duration::from_secs(1),
73                },
74                false,
75                false,
76            ),
77        );
78        let mut vals = HashMap::new();
79        vals.insert(
80            GenCamCtrl::Exposure(ExposureCtrl::ExposureTime),
81            (PropertyValue::Duration(Duration::from_secs(1)), false),
82        );
83        Ok(Box::new(GenCamDummy {
84            desc: descriptor.clone(),
85            name: descriptor.name.clone(),
86            vendor: descriptor.vendor.clone(),
87            caps,
88            vals: RefCell::new(vals),
89            capturing: Arc::new(AtomicBool::new(false)),
90            roi: GenCamRoi {
91                x_min: 0,
92                y_min: 0,
93                width: 1920,
94                height: 1080,
95            },
96            data: vec![0; 1920 * 1080 * 3],
97            imgready: Arc::new(AtomicBool::new(false)),
98            start: RefCell::new(None),
99        }))
100    }
101
102    fn connect_first_device(&mut self) -> GenCamResult<crate::AnyGenCam> {
103        let desc = self
104            .list_devices()?
105            .pop()
106            .ok_or(GenCamError::NoCamerasAvailable)?;
107        self.connect_device(&desc)
108    }
109}
110
111#[derive(Debug)]
112/// A dummy camera for testing purposes.
113pub struct GenCamDummy {
114    desc: GenCamDescriptor,
115    name: String,
116    vendor: String,
117    caps: HashMap<GenCamCtrl, Property>,
118    vals: RefCell<HashMap<GenCamCtrl, (PropertyValue, bool)>>,
119    capturing: Arc<AtomicBool>,
120    imgready: Arc<AtomicBool>,
121    roi: GenCamRoi,
122    data: Vec<u8>,
123    start: RefCell<Option<Instant>>,
124}
125
126impl GenCam for GenCamDummy {
127    fn info_handle(&self) -> Option<crate::AnyGenCamInfo> {
128        None
129    }
130
131    fn info(&self) -> GenCamResult<&GenCamDescriptor> {
132        Ok(&self.desc)
133    }
134
135    fn vendor(&self) -> &str {
136        &self.vendor
137    }
138
139    fn camera_ready(&self) -> bool {
140        true
141    }
142
143    fn camera_name(&self) -> &str {
144        &self.name
145    }
146
147    fn list_properties(&self) -> &std::collections::HashMap<crate::GenCamCtrl, crate::Property> {
148        &self.caps
149    }
150
151    fn get_property(&self, name: crate::GenCamCtrl) -> GenCamResult<(crate::PropertyValue, bool)> {
152        match self.vals.borrow().get(&name) {
153            Some(val) => Ok(val.clone()),
154            None => Err(GenCamError::PropertyError {
155                control: name,
156                error: PropertyError::NotFound,
157            }),
158        }
159    }
160
161    fn set_property(
162        &mut self,
163        name: crate::GenCamCtrl,
164        value: &crate::PropertyValue,
165        auto: bool,
166    ) -> GenCamResult<()> {
167        if self.capturing.load(SeqCst) {
168            return Err(GenCamError::ExposureInProgress);
169        }
170        match self.vals.borrow_mut().get_mut(&name) {
171            Some(val) => {
172                *val = (value.clone(), auto);
173                Ok(())
174            }
175            None => Err(GenCamError::PropertyError {
176                control: name,
177                error: PropertyError::NotFound,
178            }),
179        }
180    }
181
182    fn cancel_capture(&self) -> GenCamResult<()> {
183        self.capturing.store(false, SeqCst);
184        Ok(())
185    }
186
187    fn is_capturing(&self) -> bool {
188        self.capturing.load(SeqCst)
189    }
190
191    fn capture(&mut self) -> GenCamResult<GenericImageRef> {
192        if self.imgready.load(Relaxed) {
193            self.imgready.store(false, Relaxed);
194            self.capturing.store(false, SeqCst);
195            self.start.borrow_mut().take();
196        }
197        if self.capturing.load(SeqCst) {
198            return Err(GenCamError::ExposureInProgress);
199        }
200        let now = Instant::now();
201        let (exp, _) = self.get_property(GenCamCtrl::Exposure(ExposureCtrl::ExposureTime))?;
202        let exp = exp.try_into().map_err(|e| GenCamError::PropertyError {
203            control: GenCamCtrl::Exposure(ExposureCtrl::ExposureTime),
204            error: e,
205        })?;
206        self.start.borrow_mut().replace(now);
207        self.capturing.store(true, SeqCst);
208        self.imgready.store(false, Relaxed);
209        loop {
210            if !self.capturing.load(Relaxed) {
211                break;
212            }
213            if now.elapsed() >= exp {
214                break;
215            }
216            thread::sleep(Duration::from_millis(10));
217        }
218        self.imgready.store(true, Relaxed);
219        self.download_image()
220    }
221
222    fn start_exposure(&mut self) -> GenCamResult<()> {
223        if self.imgready.load(Relaxed) {
224            self.imgready.store(false, Relaxed);
225            self.capturing.store(false, SeqCst);
226            self.start.borrow_mut().take();
227        }
228        if self.capturing.load(SeqCst) {
229            return Err(GenCamError::ExposureInProgress);
230        }
231        let now = Instant::now();
232        let (exp, _) = self.get_property(GenCamCtrl::Exposure(ExposureCtrl::ExposureTime))?;
233        let exp = exp.try_into().map_err(|e| GenCamError::PropertyError {
234            control: GenCamCtrl::Exposure(ExposureCtrl::ExposureTime),
235            error: e,
236        })?;
237        self.start.borrow_mut().replace(now);
238        self.capturing.store(true, SeqCst);
239        self.imgready.store(false, Relaxed);
240        let capturing = self.capturing.clone();
241        let imgready = self.imgready.clone();
242        thread::spawn(move || {
243            loop {
244                if !capturing.load(SeqCst) {
245                    break;
246                }
247                if now.elapsed() >= exp {
248                    break;
249                }
250                thread::sleep(Duration::from_millis(10));
251            }
252            imgready.store(true, Relaxed);
253        });
254        Ok(())
255    }
256
257    fn download_image(&mut self) -> GenCamResult<GenericImageRef> {
258        let state = self.camera_state()?;
259        match state {
260            GenCamState::Exposing(_) => Err(GenCamError::ExposureInProgress),
261            GenCamState::Idle => Err(GenCamError::ExposureNotStarted),
262            GenCamState::ExposureFinished => {
263                thread_rng().fill(self.data.as_mut_slice());
264                self.imgready.store(false, Relaxed);
265                self.capturing.store(false, SeqCst);
266                let img = ImageRef::new(
267                    &mut self.data,
268                    self.roi.width as _,
269                    self.roi.height as _,
270                    refimage::ColorSpace::Rgb,
271                )
272                .map_err(|e| GenCamError::InvalidImageType(e.to_string()))?;
273                let img = DynamicImageRef::from(img);
274                let mut img = GenericImageRef::new(SystemTime::now(), img);
275                img.insert_key("XOFST", self.roi.x_min as u32)
276                    .map_err(|e| {
277                        GenCamError::InvalidImageType(format!("Error inserting key: {}", e))
278                    })?;
279                img.insert_key("YOFST", self.roi.y_min as u32)
280                    .map_err(|e| {
281                        GenCamError::InvalidImageType(format!("Error inserting key: {}", e))
282                    })?;
283                Ok(img)
284            }
285            GenCamState::Downloading(_) => Err(GenCamError::InvalidSequence),
286            GenCamState::Errored(gen_cam_error) => Err(gen_cam_error),
287            GenCamState::Unknown => Err(GenCamError::InvalidSequence),
288        }
289    }
290
291    fn image_ready(&self) -> GenCamResult<bool> {
292        Ok(self.imgready.load(Relaxed))
293    }
294
295    fn camera_state(&self) -> GenCamResult<GenCamState> {
296        let capturing = self.capturing.load(SeqCst);
297        let imgready = self.imgready.load(Relaxed);
298        let state = if capturing && imgready {
299            GenCamState::ExposureFinished
300        } else if capturing {
301            GenCamState::Exposing(Some(self.start.borrow().unwrap().elapsed()))
302        } else {
303            GenCamState::Idle
304        };
305        Ok(state)
306    }
307
308    fn set_roi(&mut self, roi: &GenCamRoi) -> GenCamResult<&GenCamRoi> {
309        let mut roi = *roi;
310        roi.x_min = roi.x_min.max(1);
311        roi.y_min = roi.y_min.max(1);
312        roi.width = roi.width.max(1920);
313        roi.height = roi.height.max(1080);
314        roi.x_min = roi.x_min.min(1920 - roi.width);
315        roi.y_min = roi.y_min.min(1080 - roi.height);
316        self.roi = roi;
317        Ok(&self.roi)
318    }
319
320    fn get_roi(&self) -> &GenCamRoi {
321        &self.roi
322    }
323}