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}