spectro_rs/
device.rs

1//! High-level spectrometer device abstraction.
2//!
3//! This module defines the [`Spectrometer`] trait, which provides a unified
4//! interface for all supported spectrometer devices, regardless of their
5//! underlying hardware or communication protocol.
6
7use crate::spectrum::SpectralData;
8use crate::{MeasurementMode, Result};
9
10/// Information about a spectrometer device.
11#[derive(Debug, Clone)]
12pub struct DeviceInfo {
13    /// Human-readable device model name (e.g., "ColorMunki", "i1Display Pro").
14    pub model: String,
15    /// Device serial number.
16    pub serial: String,
17    /// Firmware version string.
18    pub firmware: String,
19}
20
21/// The current status of a spectrometer device.
22#[derive(Debug, Clone)]
23pub struct DeviceStatus {
24    /// The current physical position/mode of the device dial.
25    pub position: DevicePosition,
26    /// Whether a button is currently pressed.
27    pub button_pressed: bool,
28    /// Whether the device is calibrated and ready for measurement.
29    pub is_calibrated: bool,
30}
31
32/// Physical position/mode selector on the device.
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum DevicePosition {
35    /// Projector/display measurement position.
36    Projector,
37    /// Surface/reflective measurement position.
38    Surface,
39    /// Calibration tile position.
40    Calibration,
41    /// Ambient light measurement position (with diffuser).
42    Ambient,
43    /// Unknown or unsupported position.
44    Unknown(u8),
45}
46
47impl DevicePosition {
48    /// Returns a human-readable name for this position.
49    pub fn name(&self) -> &'static str {
50        match self {
51            DevicePosition::Projector => "Projector",
52            DevicePosition::Surface => "Surface",
53            DevicePosition::Calibration => "Calibration",
54            DevicePosition::Ambient => "Ambient",
55            DevicePosition::Unknown(_) => "Unknown",
56        }
57    }
58}
59
60/// A unified interface for spectrometer devices.
61///
62/// This trait abstracts the differences between various spectrometer models
63/// (ColorMunki, i1Display Pro, Spyder, etc.), allowing application code to
64/// work with any supported device through a common API.
65///
66/// # Example
67///
68/// ```ignore
69/// use spectro_rs::{discover, MeasurementMode, Spectrometer};
70///
71/// let mut device = discover()?;
72/// println!("Found: {}", device.info()?.model);
73///
74/// device.calibrate()?;
75/// let spectrum = device.measure(MeasurementMode::Emissive)?;
76/// println!("Luminance: {:.2} cd/m²", spectrum.to_xyz().y);
77/// ```
78pub trait Spectrometer {
79    /// Returns information about the connected device.
80    fn info(&self) -> Result<DeviceInfo>;
81
82    /// Returns the current status of the device.
83    fn status(&self) -> Result<DeviceStatus>;
84
85    /// Performs device calibration.
86    ///
87    /// For reflective measurements, this typically involves measuring a white
88    /// reference tile. For emissive/ambient modes, a dark calibration may be
89    /// performed.
90    ///
91    /// # Errors
92    ///
93    /// Returns an error if the device is not in the correct physical position
94    /// for calibration, or if the calibration measurement fails.
95    fn calibrate(&mut self) -> Result<()>;
96
97    /// Performs a single-point measurement in the specified mode.
98    ///
99    /// # Arguments
100    ///
101    /// * `mode` - The type of measurement to perform.
102    ///
103    /// # Returns
104    ///
105    /// The measured spectral data, which can be converted to various color
106    /// spaces (XYZ, Lab, etc.) using the methods on [`SpectralData`].
107    ///
108    /// # Errors
109    ///
110    /// Returns an error if the device is not calibrated (for modes that require
111    /// calibration), or if the measurement fails.
112    fn measure(&mut self, mode: MeasurementMode) -> Result<SpectralData>;
113
114    /// Returns the supported measurement modes for this device.
115    fn supported_modes(&self) -> Vec<MeasurementMode>;
116
117    /// Returns whether the device is currently calibrated for the given mode.
118    fn is_calibrated(&self, mode: MeasurementMode) -> bool;
119}
120
121/// A boxed spectrometer for dynamic dispatch.
122///
123/// This type alias makes it convenient to store different spectrometer
124/// implementations in the same collection or return them from factory functions.
125pub type BoxedSpectrometer = Box<dyn Spectrometer + Send>;