generic_camera/
lib.rs

1#![deny(missing_docs)]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3/*!
4 * # Generic Camera Interface
5 * This crate provides a generic interface for controlling cameras.
6 *
7 * ## Features
8 * - `server`: Enables the generic camera server.
9 * - `dummy`: Enables the dummy camera implementation.
10 *
11 * ## Usage
12 * To use the crate, add the following to your `Cargo.toml`:
13 * ```toml
14 * [dependencies]
15 * generic-camera = "0.0"
16 * ```
17 */
18
19pub use controls::GenCamCtrl;
20pub use refimage::GenericImage;
21use refimage::GenericImageRef;
22use serde::{Deserialize, Serialize};
23use std::collections::HashMap;
24use std::hash::Hash;
25use std::{fmt::Display, time::Duration};
26use thiserror::Error;
27
28pub use crate::property::{Property, PropertyError, PropertyType, PropertyValue};
29
30pub mod controls;
31#[cfg(feature = "dummy")]
32#[cfg_attr(docsrs, doc(cfg(feature = "dummy")))]
33pub mod dummy;
34pub mod property;
35#[cfg(feature = "server")]
36#[cfg_attr(docsrs, doc(cfg(feature = "server")))]
37pub mod server;
38
39/// The version of the `generic_cam` crate.
40pub type GenCamResult<T> = std::result::Result<T, GenCamError>;
41
42#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Hash, Default)]
43/// This structure defines a region of interest.
44/// The region of interest is defined in the binned pixel space.
45pub struct GenCamRoi {
46    /// The minimum X coordinate (upper left, in binned pixel space).
47    pub x_min: u16,
48    /// The minimum Y coordinate (upper left, in binned pixel space).
49    pub y_min: u16,
50    /// The image width (X axis, in binned pixel space).
51    pub width: u16,
52    /// The image height (Y axis, in binned pixel space).
53    pub height: u16,
54}
55
56impl Display for GenCamRoi {
57    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58        write!(
59            f,
60            "ROI: Origin = ({}, {}), Image Size = ({} x {})",
61            self.x_min, self.y_min, self.width, self.height
62        )
63    }
64}
65
66#[derive(Clone, Debug, Serialize, Deserialize)]
67/// Defines the state of the camera.
68pub enum GenCamState {
69    /// Camera is idle.
70    Idle,
71    /// Camera is exposing.
72    ///
73    /// Contains the elapsed exposure time, if available.
74    Exposing(Option<Duration>),
75    /// Exposure finished.
76    ExposureFinished,
77    /// Camera is downloading image.
78    ///
79    /// Contains the percentage of the image downloaded, if available.
80    Downloading(Option<u32>),
81    /// Error occurred.
82    Errored(GenCamError),
83    /// Camera is in an unknown state.
84    Unknown,
85}
86
87/// A trait object for a camera unit.
88pub type AnyGenCam = Box<dyn GenCam>;
89/// A trait object for a camera info.
90pub type AnyGenCamInfo = Box<dyn GenCamInfo>;
91
92/// Trait for camera drivers. Provides functions to
93/// list available devices and connect to a device.
94pub trait GenCamDriver {
95    /// Get the number of available devices.
96    fn available_devices(&self) -> usize;
97    /// List available devices.
98    fn list_devices(&mut self) -> GenCamResult<Vec<GenCamDescriptor>>;
99    /// Connect to a device.
100    fn connect_device(&mut self, descriptor: &GenCamDescriptor) -> GenCamResult<AnyGenCam>;
101    /// Connect to the first available device.
102    fn connect_first_device(&mut self) -> GenCamResult<AnyGenCam>;
103}
104
105#[derive(Clone, PartialEq, Debug, Serialize, Deserialize, Default)]
106/// A structure to hold information about a camera device.
107pub struct GenCamDescriptor {
108    /// The camera ID.
109    pub id: usize,
110    /// The camera name.
111    pub name: String,
112    /// The camera vendor.
113    pub vendor: String,
114    /// Additional info
115    pub info: HashMap<String, PropertyValue>,
116}
117
118/// Trait for controlling the camera. This trait is intended to be applied to a
119/// non-clonable object that is used to capture images and can not be shared across
120/// threads.
121pub trait GenCam: Send + std::fmt::Debug {
122    /// Get the [`GenCamInfo`] object, if available.
123    fn info_handle(&self) -> Option<AnyGenCamInfo>;
124
125    /// Get the camera descriptor.
126    fn info(&self) -> GenCamResult<&GenCamDescriptor>;
127
128    /// Get the camera vendor.
129    fn vendor(&self) -> &str;
130
131    /// Check if camera is ready.
132    fn camera_ready(&self) -> bool;
133
134    /// Get the camera name.
135    fn camera_name(&self) -> &str;
136
137    /// Get optional capabilities of the camera.
138    fn list_properties(&self) -> &HashMap<GenCamCtrl, Property>;
139
140    /// Get a property by name.
141    fn get_property(&self, name: GenCamCtrl) -> GenCamResult<(PropertyValue, bool)>;
142
143    /// Set a property by name.
144    fn set_property(
145        &mut self,
146        name: GenCamCtrl,
147        value: &PropertyValue,
148        auto: bool,
149    ) -> GenCamResult<()>;
150
151    /// Cancel an ongoing exposure.
152    fn cancel_capture(&self) -> GenCamResult<()>;
153
154    /// Check if the camera is currently capturing an image.
155    fn is_capturing(&self) -> bool;
156
157    /// Capture an image.
158    /// This is a blocking call.
159    ///
160    /// Raises a `Message` with the message `"Not implemented"` if unimplemented.
161    fn capture(&mut self) -> GenCamResult<GenericImageRef>;
162
163    /// Start an exposure and return. This function does NOT block, but may not return immediately (e.g. if the camera is busy).
164    fn start_exposure(&mut self) -> GenCamResult<()>;
165
166    /// Download the image captured in [`GenCam::start_exposure`].
167    fn download_image(&mut self) -> GenCamResult<GenericImageRef>;
168
169    /// Get exposure status. This function is useful for checking if a
170    /// non-blocking exposure has finished running.
171    fn image_ready(&self) -> GenCamResult<bool>;
172
173    /// Get the camera state.
174    fn camera_state(&self) -> GenCamResult<GenCamState>;
175
176    /// Set the image region of interest (ROI).
177    ///
178    /// # Arguments
179    /// - `roi` - The region of interest.
180    ///
181    /// Note:
182    /// - The region of interest is defined in the binned pixel space.
183    /// - Setting all values to `0` will set the ROI to the full detector size.
184    ///
185    ///
186    /// # Returns
187    /// The region of interest that was set, or error.
188    fn set_roi(&mut self, roi: &GenCamRoi) -> GenCamResult<&GenCamRoi>;
189
190    /// Get the region of interest.
191    ///
192    /// # Returns
193    /// - The region of interest.
194    fn get_roi(&self) -> &GenCamRoi;
195}
196
197/// Trait for obtaining camera information and cancelling any ongoing image capture.
198/// This trait is intended to be exclusively applied to a clonable object that can
199/// be passed to other threads for housekeeping purposes.
200pub trait GenCamInfo: Send + Sync + std::fmt::Debug {
201    /// Check if camera is ready.
202    fn camera_ready(&self) -> bool;
203
204    /// Get the camera name.
205    fn camera_name(&self) -> &str;
206
207    /// Cancel an ongoing exposure.
208    fn cancel_capture(&self) -> GenCamResult<()>;
209
210    /// Check if the camera is currently capturing an image.
211    fn is_capturing(&self) -> bool;
212
213    /// Get the camera state.
214    fn camera_state(&self) -> GenCamResult<GenCamState>;
215
216    /// Get optional capabilities of the camera.
217    fn list_properties(&self) -> &HashMap<GenCamCtrl, Property>;
218
219    /// Get a property by name.
220    fn get_property(&self, name: GenCamCtrl) -> GenCamResult<(PropertyValue, bool)>;
221
222    /// Set a property by name.
223    fn set_property(
224        &mut self,
225        name: GenCamCtrl,
226        value: &PropertyValue,
227        auto: bool,
228    ) -> GenCamResult<()>;
229}
230
231#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)]
232#[non_exhaustive]
233/// Pixel bit depth.
234pub enum GenCamPixelBpp {
235    /// 8 bits per pixel. This is the default.
236    Bpp8 = 8,
237    /// 10 bits per pixel.
238    Bpp10 = 10,
239    /// 12 bits per pixel.
240    Bpp12 = 12,
241    /// 14 bits per pixel.
242    Bpp16 = 16,
243    /// 16 bits per pixel.
244    Bpp24 = 24,
245    /// 32 bits per pixel.
246    Bpp32 = 32,
247}
248
249impl From<u32> for GenCamPixelBpp {
250    /// Convert from `u32` to [`GenCamPixelBpp`].
251    ///
252    /// # Arguments
253    /// - `value` - The value to convert.
254    ///   Note: If the value is not one of the known values, `Bpp8` is returned.
255    ///
256    /// # Returns
257    /// The corresponding [`GenCamPixelBpp`] value.
258    fn from(value: u32) -> Self {
259        match value {
260            8 => GenCamPixelBpp::Bpp8,
261            10 => GenCamPixelBpp::Bpp10,
262            12 => GenCamPixelBpp::Bpp12,
263            16 => GenCamPixelBpp::Bpp16,
264            24 => GenCamPixelBpp::Bpp24,
265            32 => GenCamPixelBpp::Bpp32,
266            _ => GenCamPixelBpp::Bpp8,
267        }
268    }
269}
270
271#[derive(Error, Debug, Clone, PartialEq, Serialize, Deserialize)]
272/// Errors returned by camera operations.
273pub enum GenCamError {
274    /// Error message.
275    #[error("Error: {0}")]
276    Message(String),
277    /// Access violation.
278    #[error("Access violation")]
279    AccessViolation,
280    /// Invalid index.
281    #[error("Invalid index: {0}")]
282    InvalidIndex(i32),
283    /// Invalid ID.
284    #[error("Invalid ID: {0}")]
285    InvalidId(i32),
286    /// Invalid control type.
287    #[error("Invalid control type: {0}")]
288    InvalidControlType(String),
289    /// No cameras available.
290    #[error("No cameras available")]
291    NoCamerasAvailable,
292    /// Camera not open for access.
293    #[error("Camera not open for access")]
294    CameraClosed,
295    /// Camera already removed.
296    #[error("Camera already removed")]
297    CameraRemoved,
298    /// Invalid path.
299    #[error("Invalid path: {0}")]
300    InvalidPath(String),
301    /// Invalid format.
302    #[error("Invalid format: {0}")]
303    InvalidFormat(String),
304    /// Invalid size.
305    #[error("Invalid size: {0}")]
306    InvalidSize(usize),
307    /// Invalid image type.
308    #[error("Invalid image type: {0}")]
309    InvalidImageType(String),
310    /// Operation timed out.
311    #[error("Operation timed out")]
312    TimedOut,
313    /// Invalid sequence.
314    #[error("Invalid sequence")]
315    InvalidSequence,
316    /// Buffer too small.
317    #[error("Buffer too small: {0}")]
318    BufferTooSmall(usize),
319    /// Exposure in progress.
320    #[error("Exposure already in progress")]
321    ExposureInProgress,
322    /// General error.
323    #[error("General error: {0}")]
324    GeneralError(String),
325    /// Invalid mode.
326    #[error("Invalid mode: {0}")]
327    InvalidMode(String),
328    /// Exposure failed.
329    #[error("Exposure failed: {0}")]
330    ExposureFailed(String),
331    /// Invalid value.
332    #[error("Invalid value: {0}")]
333    InvalidValue(String),
334    /// Out of bounds.
335    #[error("Out of bounds: {0}")]
336    OutOfBounds(String),
337    /// Exposure not started.
338    #[error("Exposure not started.")]
339    ExposureNotStarted,
340    /// Property related error.
341    #[error("Property error: {control:?} - {error:?}")]
342    PropertyError {
343        /// The control that caused the error.
344        control: GenCamCtrl,
345        /// The error message.
346        error: PropertyError,
347    },
348}