use std::ffi::CStr;
use std::os::raw::{c_char, c_int};
fn chars_to_string(buf: &[c_char]) -> String {
unsafe { CStr::from_ptr(buf.as_ptr()) }
.to_string_lossy()
.into_owned()
}
macro_rules! c_enum {
(
$(#[$meta:meta])*
$vis:vis enum $name:ident {
$($(#[$vmeta:meta])* $variant:ident = $val:expr),+ $(,)?
}
) => {
$(#[$meta])*
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(i32)]
$vis enum $name {
$($(#[$vmeta])* $variant = $val),+
}
impl TryFrom<c_int> for $name {
type Error = crate::Error;
fn try_from(v: c_int) -> crate::Result<Self> {
match v {
$($val => Ok(Self::$variant),)+
_ => Err(crate::Error::Unknown(v as i32)),
}
}
}
};
}
c_enum! {
pub enum ImageType {
Raw8 = 0,
Raw10 = 1,
Raw12 = 2,
Raw14 = 3,
Raw16 = 4,
Y8 = 5,
Y10 = 6,
Y12 = 7,
Y14 = 8,
Y16 = 9,
Rgb24 = 10,
Rgb32 = 11,
}
}
c_enum! {
pub enum BayerPattern {
Rg = 0,
Bg = 1,
Gr = 2,
Gb = 3,
}
}
c_enum! {
pub enum ControlType {
Gain = 0,
Exposure = 1,
Gamma = 2,
GammaContrast = 3,
WbR = 4,
WbG = 5,
WbB = 6,
Flip = 7,
FrameSpeedMode = 8,
Contrast = 9,
Sharpness = 10,
Saturation = 11,
AutoTargetBrightness = 12,
BlackLevel = 13,
CoolerEnable = 14,
TargetTemperature = 15,
CurrentTemperature = 16,
CoolerPower = 17,
BadPixelCorrEnable = 18,
BadPixelCorrThreshold = 19,
}
}
c_enum! {
pub enum CameraMode {
Normal = 0,
TrigSoft = 1,
TrigRiseEdge = 2,
TrigFallEdge = 3,
TrigDoubleEdge = 4,
TrigHighLevel = 5,
TrigLowLevel = 6,
}
}
c_enum! {
pub enum FlipStatus {
None = 0,
Horizontal = 1,
Vertical = 2,
Both = 3,
}
}
c_enum! {
pub enum GuideDirection {
North = 0,
South = 1,
East = 2,
West = 3,
}
}
c_enum! {
pub enum TrigOutputPin {
PinA = 0,
PinB = 1,
}
}
c_enum! {
pub enum ExposureStatus {
Idle = 0,
Working = 1,
Success = 2,
Failed = 3,
}
}
impl ImageType {
pub fn bytes_per_pixel(&self) -> usize {
match self {
Self::Raw8 | Self::Y8 => 1,
Self::Raw10 | Self::Raw12 | Self::Raw14 | Self::Raw16 => 2,
Self::Y10 | Self::Y12 | Self::Y14 | Self::Y16 => 2,
Self::Rgb24 => 3,
Self::Rgb32 => 4,
}
}
}
#[derive(Debug, Clone)]
pub struct CameraInfo {
pub name: String,
pub serial: String,
pub port_type: String,
pub device_id: u32,
pub camera_id: i32,
}
impl From<&svbony_sys::SVB_CAMERA_INFO> for CameraInfo {
fn from(c: &svbony_sys::SVB_CAMERA_INFO) -> Self {
Self {
name: chars_to_string(&c.FriendlyName),
serial: chars_to_string(&c.CameraSN),
port_type: chars_to_string(&c.PortType),
device_id: c.DeviceID,
camera_id: c.CameraID,
}
}
}
#[derive(Debug, Clone)]
pub struct CameraProperty {
pub max_width: i64,
pub max_height: i64,
pub is_color: bool,
pub bayer_pattern: BayerPattern,
pub supported_bins: Vec<i32>,
pub supported_formats: Vec<ImageType>,
pub max_bit_depth: i32,
pub is_trigger_cam: bool,
}
impl From<&svbony_sys::SVB_CAMERA_PROPERTY> for CameraProperty {
fn from(c: &svbony_sys::SVB_CAMERA_PROPERTY) -> Self {
let supported_bins = c
.SupportedBins
.iter()
.copied()
.take_while(|&b| b != 0)
.collect();
let supported_formats = c
.SupportedVideoFormat
.iter()
.copied()
.take_while(|&f| f != svbony_sys::SVB_IMG_END)
.filter_map(|f| ImageType::try_from(f).ok())
.collect();
Self {
max_width: c.MaxWidth as i64,
max_height: c.MaxHeight as i64,
is_color: c.IsColorCam != 0,
bayer_pattern: BayerPattern::try_from(c.BayerPattern).unwrap_or(BayerPattern::Rg),
supported_bins,
supported_formats,
max_bit_depth: c.MaxBitDepth,
is_trigger_cam: c.IsTriggerCam != 0,
}
}
}
#[derive(Debug, Clone)]
pub struct CameraPropertyEx {
pub supports_pulse_guide: bool,
pub supports_temp_control: bool,
}
impl From<&svbony_sys::SVB_CAMERA_PROPERTY_EX> for CameraPropertyEx {
fn from(c: &svbony_sys::SVB_CAMERA_PROPERTY_EX) -> Self {
Self {
supports_pulse_guide: c.bSupportPulseGuide != 0,
supports_temp_control: c.bSupportControlTemp != 0,
}
}
}
#[derive(Debug, Clone)]
pub struct ControlCaps {
pub name: String,
pub description: String,
pub max_value: i64,
pub min_value: i64,
pub default_value: i64,
pub is_auto_supported: bool,
pub is_writable: bool,
pub control_type: ControlType,
}
impl From<&svbony_sys::SVB_CONTROL_CAPS> for ControlCaps {
fn from(c: &svbony_sys::SVB_CONTROL_CAPS) -> Self {
Self {
name: chars_to_string(&c.Name),
description: chars_to_string(&c.Description),
max_value: c.MaxValue as i64,
min_value: c.MinValue as i64,
default_value: c.DefaultValue as i64,
is_auto_supported: c.IsAutoSupported != 0,
is_writable: c.IsWritable != 0,
control_type: ControlType::try_from(c.ControlType).unwrap_or(ControlType::Gain),
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct RoiFormat {
pub start_x: i32,
pub start_y: i32,
pub width: i32,
pub height: i32,
pub bin: i32,
}
#[derive(Debug, Clone, Copy)]
pub struct RoiFormatEx {
pub start_x: i32,
pub start_y: i32,
pub width: i32,
pub height: i32,
pub bin: i32,
pub bin_mode: i32,
}