use std::ffi::CStr;
use std::os::raw::c_char;
use orbbec_sys::{ob_context, ob_device, ob_device_info, ob_device_list};
use crate::error::{check_error, Error};
#[derive(Debug, Clone)]
pub struct DeviceInfo {
pub name: String,
pub pid: u32,
pub vid: u32,
pub uid: String,
pub serial_number: String,
pub firmware_version: String,
pub connection_type: String,
pub ip_address: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SensorType {
Unknown,
Ir,
Color,
Depth,
Accel,
Gyro,
IrLeft,
IrRight,
RawPhase,
Confidence,
Lidar,
ColorLeft,
ColorRight,
}
impl SensorType {
pub fn from_raw(v: u32) -> Self {
match v {
orbbec_sys::OBSensorType_OB_SENSOR_IR => SensorType::Ir,
orbbec_sys::OBSensorType_OB_SENSOR_COLOR => SensorType::Color,
orbbec_sys::OBSensorType_OB_SENSOR_DEPTH => SensorType::Depth,
orbbec_sys::OBSensorType_OB_SENSOR_ACCEL => SensorType::Accel,
orbbec_sys::OBSensorType_OB_SENSOR_GYRO => SensorType::Gyro,
orbbec_sys::OBSensorType_OB_SENSOR_IR_LEFT => SensorType::IrLeft,
orbbec_sys::OBSensorType_OB_SENSOR_IR_RIGHT => SensorType::IrRight,
orbbec_sys::OBSensorType_OB_SENSOR_RAW_PHASE => SensorType::RawPhase,
orbbec_sys::OBSensorType_OB_SENSOR_CONFIDENCE => SensorType::Confidence,
orbbec_sys::OBSensorType_OB_SENSOR_LIDAR => SensorType::Lidar,
orbbec_sys::OBSensorType_OB_SENSOR_COLOR_LEFT => SensorType::ColorLeft,
orbbec_sys::OBSensorType_OB_SENSOR_COLOR_RIGHT => SensorType::ColorRight,
_ => SensorType::Unknown,
}
}
}
impl std::fmt::Display for SensorType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
SensorType::Unknown => "unknown",
SensorType::Ir => "ir",
SensorType::Color => "color",
SensorType::Depth => "depth",
SensorType::Accel => "accel",
SensorType::Gyro => "gyro",
SensorType::IrLeft => "ir-left",
SensorType::IrRight => "ir-right",
SensorType::RawPhase => "raw-phase",
SensorType::Confidence => "confidence",
SensorType::Lidar => "lidar",
SensorType::ColorLeft => "color-left",
SensorType::ColorRight => "color-right",
})
}
}
pub struct Device {
raw: *mut ob_device,
}
unsafe impl Send for Device {}
impl Device {
pub(crate) fn from_list(
_context: *mut ob_context,
list: *const ob_device_list,
index: u32,
) -> Result<Self, Error> {
let raw = unsafe { check_error(|e| orbbec_sys::ob_device_list_get_device(list, index, e))? };
Ok(Self { raw })
}
pub fn as_raw(&self) -> *mut ob_device {
self.raw
}
pub fn sensors(&self) -> Result<Vec<SensorType>, Error> {
let list =
unsafe { check_error(|e| orbbec_sys::ob_device_get_sensor_list(self.raw, e))? };
let result = (|| {
let count =
unsafe { check_error(|e| orbbec_sys::ob_sensor_list_get_count(list, e))? };
let mut sensors = Vec::with_capacity(count as usize);
for i in 0..count {
let t =
unsafe { check_error(|e| orbbec_sys::ob_sensor_list_get_sensor_type(list, i, e))? };
sensors.push(SensorType::from_raw(t));
}
Ok(sensors)
})();
let _ = unsafe { check_error(|e| orbbec_sys::ob_delete_sensor_list(list, e)) };
result
}
pub fn info(&self) -> Result<DeviceInfo, Error> {
let info =
unsafe { check_error(|e| orbbec_sys::ob_device_get_device_info(self.raw, e))? };
let result = Self::device_info(info);
let _ = unsafe { check_error(|e| orbbec_sys::ob_delete_device_info(info, e)) };
result
}
fn device_info(info: *const ob_device_info) -> Result<DeviceInfo, Error> {
let name = unsafe { get_string(info, orbbec_sys::ob_device_info_get_name) };
let pid = unsafe { check_error(|e| orbbec_sys::ob_device_info_get_pid(info, e))? };
let vid = unsafe { check_error(|e| orbbec_sys::ob_device_info_get_vid(info, e))? };
let uid = unsafe { get_string(info, orbbec_sys::ob_device_info_get_uid) };
let serial_number =
unsafe { get_string(info, orbbec_sys::ob_device_info_get_serial_number) };
let firmware_version =
unsafe { get_string(info, orbbec_sys::ob_device_info_get_firmware_version) };
let connection_type =
unsafe { get_string(info, orbbec_sys::ob_device_info_get_connection_type) };
let ip_address = if connection_type.starts_with("USB") {
String::new()
} else {
unsafe { get_string(info, orbbec_sys::ob_device_info_get_ip_address) }
};
Ok(DeviceInfo {
name,
pid: pid as u32,
vid: vid as u32,
uid,
serial_number,
firmware_version,
connection_type,
ip_address,
})
}
}
impl Drop for Device {
fn drop(&mut self) {
let _ = unsafe { check_error(|e| orbbec_sys::ob_delete_device(self.raw, e)) };
}
}
unsafe fn get_string(
info: *const ob_device_info,
getter: unsafe extern "C" fn(*const ob_device_info, *mut *mut orbbec_sys::ob_error)
-> *const c_char,
) -> String {
unsafe {
check_error(|e| getter(info, e))
.map(|ptr| {
if ptr.is_null() {
String::new()
} else {
CStr::from_ptr(ptr).to_string_lossy().into_owned()
}
})
.unwrap_or_default()
}
}