orbbec_sdk/
device.rs

1//! Device module
2mod device_property;
3use std::fmt;
4
5use crate::device::device_property::PropertyValue;
6use crate::error::{OrbbecError, OrbbecErrorData};
7use crate::{Context, DeviceType, PermissionType, sys};
8
9#[doc(inline)]
10pub use device_property::DeviceProperty;
11
12/// Device information
13pub struct DeviceInfo {
14    inner: sys::device::OBDeviceInfo,
15}
16
17impl DeviceInfo {
18    pub(crate) fn new(inner: sys::device::OBDeviceInfo) -> Self {
19        DeviceInfo { inner }
20    }
21
22    /// Get the device name
23    pub fn name(&self) -> String {
24        // Unwrap is safe here because internal pointer is guaranteed to be valid
25        // SDK only returns error for this function if pointer is NULL
26        // Ref: https://github.com/orbbec/OrbbecSDK_v2/blob/815ae047cc977a1f7edd2b97b69ff6cd29f510b3/src/impl/Device.cpp#L464
27        let cstr = self.inner.get_name().unwrap();
28
29        cstr.to_string_lossy().into_owned()
30    }
31
32    /// Get the device USB product ID
33    pub fn pid(&self) -> u16 {
34        // Unwrap is safe here because internal pointer is guaranteed to be valid
35        // SDK only returns error for this function if pointer is NULL
36        // Ref: https://github.com/orbbec/OrbbecSDK_v2/blob/815ae047cc977a1f7edd2b97b69ff6cd29f510b3/src/impl/Device.cpp#L471
37        self.inner.get_pid().unwrap() as u16
38    }
39
40    /// Get the device USB vendor ID
41    pub fn vid(&self) -> u16 {
42        // Unwrap is safe here because internal pointer is guaranteed to be valid
43        // SDK only returns error for this function if pointer is NULL
44        // Ref: https://github.com/orbbec/OrbbecSDK_v2/blob/815ae047cc977a1f7edd2b97b69ff6cd29f510b3/src/impl/Device.cpp#L477
45        self.inner.get_vid().unwrap() as u16
46    }
47
48    /// Get the device unique identifier (based on the port it is connected, platform specific)
49    pub fn uid(&self) -> String {
50        // Unwrap is safe here because internal pointer is guaranteed to be valid
51        // SDK only returns error for this function if pointer is NULL
52        // Ref: https://github.com/orbbec/OrbbecSDK_v2/blob/815ae047cc977a1f7edd2b97b69ff6cd29f510b3/src/impl/Device.cpp#L482
53        let cstr = self.inner.get_uid().unwrap();
54
55        cstr.to_string_lossy().into_owned()
56    }
57
58    /// Get the device serial number
59    pub fn serial_number(&self) -> String {
60        // Unwrap is safe here because internal pointer is guaranteed to be valid
61        // SDK only returns error for this function if pointer is NULL
62        // Ref: https://github.com/orbbec/OrbbecSDK_v2/blob/815ae047cc977a1f7edd2b97b69ff6cd29f510b3/src/impl/Device.cpp#L488
63        let cstr = self.inner.get_serial_number().unwrap();
64
65        cstr.to_string_lossy().into_owned()
66    }
67
68    /// Get the device firmware version
69    pub fn firmware_version(&self) -> String {
70        // Unwrap is safe here because internal pointer is guaranteed to be valid
71        // SDK only returns error for this function if pointer is NULL
72        // Ref: https://github.com/orbbec/OrbbecSDK_v2/blob/815ae047cc977a1f7edd2b97b69ff6cd29f510b3/src/impl/Device.cpp#L494
73        let cstr = self.inner.get_firmware_version().unwrap();
74
75        cstr.to_string_lossy().into_owned()
76    }
77
78    /// Get the device hardware version
79    pub fn hardware_version(&self) -> String {
80        // Unwrap is safe here because internal pointer is guaranteed to be valid
81        // SDK only returns error for this function if pointer is NULL
82        // Ref: https://github.com/orbbec/OrbbecSDK_v2/blob/815ae047cc977a1f7edd2b97b69ff6cd29f510b3/src/impl/Device.cpp#L500
83        let cstr = self.inner.get_hardware_version().unwrap();
84
85        cstr.to_string_lossy().into_owned()
86    }
87
88    /// Get the device connection type
89    pub fn connection_type(&self) -> String {
90        // Unwrap is safe here because internal pointer is guaranteed to be valid
91        // SDK only returns error for this function if pointer is NULL
92        // Ref: https://github.com/orbbec/OrbbecSDK_v2/blob/815ae047cc977a1f7edd2b97b69ff6cd29f510b3/src/impl/Device.cpp#L506
93        let cstr = self.inner.get_connection_type().unwrap();
94
95        cstr.to_string_lossy().into_owned()
96    }
97
98    /// Get the device minimum supported SDK version
99    pub fn minimum_supported_sdk_version(&self) -> String {
100        // Unwrap is safe here because internal pointer is guaranteed to be valid
101        // SDK only returns error for this function if pointer is NULL
102        // Ref: https://github.com/orbbec/OrbbecSDK_v2/blob/815ae047cc977a1f7edd2b97b69ff6cd29f510b3/src/impl/Device.cpp#L522
103        let cstr = self.inner.get_min_supported_sdk_version().unwrap();
104
105        cstr.to_string_lossy().into_owned()
106    }
107
108    /// Get the device ASIC name
109    pub fn asic_name(&self) -> String {
110        // Unwrap is safe here because internal pointer is guaranteed to be valid
111        // SDK only returns error for this function if pointer is NULL
112        // Ref: https://github.com/orbbec/OrbbecSDK_v2/blob/815ae047cc977a1f7edd2b97b69ff6cd29f510b3/src/impl/Device.cpp#L528
113        let cstr = self.inner.get_asic_name().unwrap();
114
115        cstr.to_string_lossy().into_owned()
116    }
117
118    /// Get the device type
119    pub fn device_type(&self) -> DeviceType {
120        // Unwrap is safe here because internal pointer is guaranteed to be valid
121        // SDK only returns error for this function if pointer is NULL
122        // Ref: https://github.com/orbbec/OrbbecSDK_v2/blob/815ae047cc977a1f7edd2b97b69ff6cd29f510b3/src/impl/Device.cpp#L534
123        self.inner.get_device_type().unwrap()
124    }
125}
126
127impl fmt::Debug for DeviceInfo {
128    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129        f.debug_struct("DeviceInfo")
130            .field("name", &self.name())
131            .field("pid", &format_args!("{:04X}", self.pid()))
132            .field("vid", &format_args!("{:04X}", self.vid()))
133            .field("uid", &self.uid())
134            .field("serial_number", &self.serial_number())
135            .field("firmware_version", &self.firmware_version())
136            .field("hardware_version", &self.hardware_version())
137            .field("connection_type", &self.connection_type())
138            .field(
139                "minimum_supported_sdk_version",
140                &self.minimum_supported_sdk_version(),
141            )
142            .field("asic_name", &self.asic_name())
143            .field("device_type", &self.device_type())
144            .finish()
145    }
146}
147
148/// A single Orbbec device
149pub struct Device {
150    inner: sys::device::OBDevice,
151}
152
153impl Device {
154    pub(crate) fn new(inner: sys::device::OBDevice) -> Self {
155        Device { inner }
156    }
157
158    pub(crate) fn inner(&self) -> &sys::device::OBDevice {
159        &self.inner
160    }
161
162    /// Get the device information
163    pub fn info(&self) -> Result<DeviceInfo, OrbbecError> {
164        let info = self.inner.get_info().map_err(OrbbecError::from)?;
165
166        Ok(DeviceInfo::new(info))
167    }
168
169    /// Load a preset configuration to the device
170    /// ### Arguments
171    /// * `preset_name` - The name of the preset to load
172    pub fn load_preset(&mut self, preset_name: &str) -> Result<(), OrbbecError> {
173        let cstr = std::ffi::CString::new(preset_name).map_err(|e| {
174            let err_data = OrbbecErrorData {
175                message: format!("Invalid preset name: {e}"),
176                function: "Device::load_preset".to_string(),
177                args: preset_name.to_string(),
178            };
179
180            OrbbecError::InvalidValue(err_data)
181        })?;
182
183        self.inner.load_preset(&cstr).map_err(OrbbecError::from)
184    }
185
186    /// Check if a device property is supported
187    /// ### Arguments
188    /// * `property_id` - The property to check
189    /// * `permission` - The permission type to check (read, write, or read/write)
190    pub fn is_property_supported(
191        &self,
192        property: DeviceProperty,
193        permission: PermissionType,
194    ) -> Result<bool, OrbbecError> {
195        let mut property = property;
196        let (prop_id, _) = property.decompose();
197
198        self.inner
199            .is_property_supported(prop_id, permission)
200            .map_err(OrbbecError::from)
201    }
202
203    /// Set a property value on the device
204    /// ### Arguments
205    /// * `property` - The property to set and its value
206    pub fn set_property(&mut self, property: DeviceProperty) -> Result<(), OrbbecError> {
207        let mut property = property;
208        let (prop_id, prop_type) = property.decompose();
209
210        match prop_type {
211            PropertyValue::Bool(value) => self
212                .inner
213                .set_bool_property(prop_id, *value)
214                .map_err(OrbbecError::from),
215            PropertyValue::Int(value) => self
216                .inner
217                .set_int_property(prop_id, *value)
218                .map_err(OrbbecError::from),
219            PropertyValue::Float(value) => self
220                .inner
221                .set_float_property(prop_id, *value)
222                .map_err(OrbbecError::from),
223        }
224    }
225
226    /// Get a property value from the device
227    /// ### Arguments
228    /// * `property` - The property to get
229    pub fn get_property(&self, property: &mut DeviceProperty) -> Result<(), OrbbecError> {
230        let (prop_id, prop_type) = property.decompose();
231
232        match prop_type {
233            PropertyValue::Bool(value) => {
234                *value = self
235                    .inner
236                    .get_bool_property(prop_id)
237                    .map_err(OrbbecError::from)?;
238            }
239            PropertyValue::Int(value) => {
240                *value = self
241                    .inner
242                    .get_int_property(prop_id)
243                    .map_err(OrbbecError::from)?;
244            }
245            PropertyValue::Float(value) => {
246                *value = self
247                    .inner
248                    .get_float_property(prop_id)
249                    .map_err(OrbbecError::from)?;
250            }
251        }
252        Ok(())
253    }
254}
255
256/// A list of Orbbec devices available
257pub struct DeviceList<'a> {
258    inner: sys::device::OBDeviceList,
259    /// We hold a reference to the context to ensure it lives as long as the device list
260    _context: &'a Context,
261}
262
263impl<'a> DeviceList<'a> {
264    pub(crate) fn new(inner: sys::device::OBDeviceList, context: &'a Context) -> Self {
265        DeviceList {
266            inner,
267            _context: context,
268        }
269    }
270
271    /// Get the number of devices in the list
272    pub fn len(&self) -> usize {
273        // Unwrap is safe here because internal pointer is guaranteed to be valid
274        // SDK only returns error for this function if pointer is NULL
275        // Ref: https://github.com/orbbec/OrbbecSDK_v2/blob/815ae047cc977a1f7edd2b97b69ff6cd29f510b3/src/impl/Device.cpp#L27
276        self.inner.get_count().unwrap() as usize
277    }
278
279    /// Check if the device list is empty
280    pub fn is_empty(&self) -> bool {
281        self.len() == 0
282    }
283
284    /// Get the device at the specified index
285    /// ### Arguments
286    /// * `index` - The index of the device to get
287    pub fn get(&self, index: usize) -> Result<Device, OrbbecError> {
288        let device = self.inner.get_device(index as u32);
289
290        device.map(Device::new).map_err(OrbbecError::from)
291    }
292}
293
294pub struct DeviceListIterator<'a, 'b> {
295    device_list: &'b DeviceList<'a>,
296    index: usize,
297    count: usize,
298}
299
300impl<'a, 'b> DeviceListIterator<'a, 'b> {
301    pub fn new(device_list: &'a DeviceList<'b>) -> Result<Self, OrbbecError> {
302        Ok(DeviceListIterator {
303            device_list,
304            index: 0,
305            count: device_list.len(),
306        })
307    }
308}
309
310impl<'a, 'b> Iterator for DeviceListIterator<'a, 'b> {
311    type Item = Result<Device, OrbbecError>;
312
313    fn next(&mut self) -> Option<Self::Item> {
314        if self.index >= self.count {
315            None
316        } else {
317            let device = self.device_list.get(self.index);
318            self.index += 1;
319            Some(device)
320        }
321    }
322}
323
324impl<'a, 'b> IntoIterator for &'b DeviceList<'a>
325where
326    'b: 'a,
327{
328    type Item = Result<Device, OrbbecError>;
329    type IntoIter = DeviceListIterator<'a, 'b>;
330
331    fn into_iter(self) -> Self::IntoIter {
332        DeviceListIterator::<'a, 'b>::new(self).unwrap()
333    }
334}