use std::ffi::CStr;
use std::marker::PhantomData;
use std::mem::size_of;
use std::mem::MaybeUninit;
use std::ops::Deref;
use std::os::raw::c_char;
use std::str::from_utf8;
use paste::paste;
use xiapi_sys::*;
use crate::Image;
use crate::Roi;
macro_rules! param {
() => {};
(
$(#[doc = $doc:expr])*
mut $prm:ident : $type:ty;
$($tail:tt)*
) => {
paste! {
$(#[doc = $doc])*
pub fn $prm(&self) -> Result<$type, XI_RETURN>{
unsafe {self.param([<XI_PRM_ $prm:upper>]) }
}
#[doc = "Get the increment for the `" $prm "` parameter. See also [Self::" $prm "()]"]
pub fn [<$prm _increment>](& self) -> Result<$type, XI_RETURN>{
unsafe {self.param_increment([<XI_PRM_ $prm:upper>])}
}
#[doc = "Get the minimum for the `" $prm "` parameter. See also [Self::" $prm "()]"]
pub fn [<$prm _minimum>](& self) -> Result<$type, XI_RETURN>{
unsafe {self.param_min([<XI_PRM_ $prm:upper>])}
}
#[doc = "Get the maximum for the `" $prm "` parameter. See also [Self::" $prm "()]"]
pub fn [<$prm _maximum>](& self) -> Result<$type, XI_RETURN>{
unsafe {self.param_max([<XI_PRM_ $prm:upper>])}
}
#[doc = "Set the `" $prm "` parameter. See also [Self::" $prm "()]"]
pub fn [<set_ $prm>](& mut self, value: $type ) -> Result<(), XI_RETURN>{
unsafe {self.set_param([<XI_PRM_ $prm:upper>], value)}
}
param!($($tail)*);
}
};
(
$(#[doc = $doc:expr])*
$prm:ident : $type:ty;
$($tail:tt)*
) => {
paste! {
$(#[doc = $doc])*
pub fn $prm( &self) -> Result < $type, XI_RETURN >{
unsafe {self.param(paste ! ([ < XI_PRM_ $prm: upper > ]))}
}
param!($($tail)*);
}
};
}
pub struct Camera {
device_handle: HANDLE,
}
pub struct AcquisitionBuffer {
camera: Camera,
}
pub fn open_device(dev_id: Option<u32>) -> Result<Camera, XI_RETURN> {
let mut device_handle: HANDLE = std::ptr::null_mut();
let dev_id = dev_id.unwrap_or(0);
let err = unsafe { xiapi_sys::xiOpenDevice(dev_id, &mut device_handle) };
match err as XI_RET::Type {
XI_RET::XI_OK => Ok(Camera { device_handle }),
_ => Err(err),
}
}
pub fn open_device_manual_bandwidth(
dev_id: Option<u32>,
bandwidth: i32,
) -> Result<Camera, XI_RETURN> {
let cam = unsafe {
let bandwidth_param_c = match CStr::from_bytes_with_nul(XI_PRM_AUTO_BANDWIDTH_CALCULATION) {
Ok(c) => c,
Err(_) => return Err(XI_RET::XI_INVALID_ARG as XI_RETURN),
};
match i32::set_param(
std::ptr::null_mut(),
bandwidth_param_c.as_ptr(),
XI_SWITCH::XI_OFF as i32,
) as XI_RET::Type
{
XI_RET::XI_OK => {}
err => return Err(err as i32),
};
let cam = open_device(dev_id);
match i32::set_param(
std::ptr::null_mut(),
bandwidth_param_c.as_ptr(),
XI_SWITCH::XI_ON as i32,
) as XI_RET::Type
{
XI_RET::XI_OK => {}
_ => panic!("Could not enable auto bandwidth calculation!"),
}
cam
};
match cam {
Ok(mut cam) => {
cam.set_limit_bandwidth(bandwidth)?;
Ok(cam)
}
Err(err) => Err(err),
}
}
pub fn number_devices() -> Result<u32, XI_RETURN> {
unsafe {
let mut value = 0u32;
let res = xiapi_sys::xiGetNumberDevices(&mut value);
match res as XI_RET::Type {
XI_RET::XI_OK => Ok(value),
_ => Err(res),
}
}
}
impl Drop for Camera {
fn drop(&mut self) {
unsafe {
xiapi_sys::xiCloseDevice(self.device_handle);
}
}
}
trait ParamType: Default {
unsafe fn get_param(
handle: xiapi_sys::HANDLE,
prm: *const std::os::raw::c_char,
value: &mut Self,
) -> XI_RETURN;
unsafe fn set_param(
handle: xiapi_sys::HANDLE,
prm: *const std::os::raw::c_char,
value: Self,
) -> XI_RETURN;
}
impl ParamType for f32 {
unsafe fn get_param(handle: HANDLE, prm: *const c_char, value: &mut Self) -> XI_RETURN {
xiapi_sys::xiGetParamFloat(handle, prm, value)
}
unsafe fn set_param(handle: HANDLE, prm: *const c_char, value: Self) -> XI_RETURN {
xiapi_sys::xiSetParamFloat(handle, prm, value)
}
}
impl ParamType for i32 {
unsafe fn get_param(handle: HANDLE, prm: *const c_char, value: &mut Self) -> XI_RETURN {
xiapi_sys::xiGetParamInt(handle, prm, value)
}
unsafe fn set_param(handle: HANDLE, prm: *const c_char, value: Self) -> XI_RETURN {
xiapi_sys::xiSetParamInt(handle, prm, value)
}
}
impl ParamType for u32 {
unsafe fn get_param(handle: HANDLE, prm: *const c_char, value: &mut Self) -> XI_RETURN {
xiapi_sys::xiGetParamInt(handle, prm, value as *mut u32 as *mut i32)
}
unsafe fn set_param(handle: HANDLE, prm: *const c_char, value: Self) -> XI_RETURN {
xiapi_sys::xiSetParamInt(handle, prm, value as i32)
}
}
impl Camera {
pub fn start_acquisition(self) -> Result<AcquisitionBuffer, XI_RETURN> {
let err = unsafe { xiapi_sys::xiStartAcquisition(self.device_handle) };
match err as XI_RET::Type {
XI_RET::XI_OK => Ok(AcquisitionBuffer { camera: self }),
_ => Err(err),
}
}
unsafe fn set_param<T: ParamType>(&mut self, param: &[u8], value: T) -> Result<(), XI_RETURN> {
let param_c = match CStr::from_bytes_with_nul(param) {
Ok(c) => c,
Err(_) => return Err(XI_RET::XI_INVALID_ARG as XI_RETURN),
};
let err = T::set_param(self.device_handle, param_c.as_ptr(), value);
match err as XI_RET::Type {
XI_RET::XI_OK => Ok(()),
_ => Err(err),
}
}
unsafe fn param<T: ParamType>(&self, param: &[u8]) -> Result<T, XI_RETURN> {
let mut value = T::default();
let param_c = match CStr::from_bytes_with_nul(param) {
Ok(c) => c,
Err(_) => return Err(XI_RET::XI_INVALID_ARG as XI_RETURN),
};
let err = T::get_param(self.device_handle, param_c.as_ptr(), &mut value);
match err as XI_RET::Type {
XI_RET::XI_OK => Ok(value),
_ => Err(err),
}
}
unsafe fn param_increment<T: ParamType>(&self, param: &'static [u8]) -> Result<T, XI_RETURN> {
self.param_info(param, XI_PRM_INFO_INCREMENT)
}
unsafe fn param_min<T: ParamType>(&self, param: &'static [u8]) -> Result<T, XI_RETURN> {
self.param_info(param, XI_PRM_INFO_MIN)
}
unsafe fn param_max<T: ParamType>(&self, param: &'static [u8]) -> Result<T, XI_RETURN> {
self.param_info(param, XI_PRM_INFO_MAX)
}
unsafe fn param_info<T: ParamType>(
&self,
param: &'static [u8],
info_modifier: &'static [u8],
) -> Result<T, XI_RETURN> {
let param_utf8 = from_utf8(param).or(Err(XI_RET::XI_INVALID_ARG as i32))?;
let modifier_utf8 =
from_utf8(info_modifier).expect("UTF8 error on API constant -> Unreachable");
let modified_param = format!(
"{}{}",
param_utf8.trim_matches(char::from(0)),
modifier_utf8
);
self.param(modified_param.as_bytes())
}
pub fn set_roi(&mut self, roi: &Roi) -> Result<Roi, XI_RETURN> {
self.set_offset_x(0)?;
self.set_offset_y(0)?;
let width_inc = self.width_increment()?;
let width = roi.width - (roi.width % width_inc);
self.set_width(width)?;
let height_inc = self.height_increment()?;
let height = roi.height - (roi.height % height_inc);
self.set_height(height)?;
let offset_x_inc = self.offset_x_increment()?;
let offset_x = roi.offset_x - (roi.offset_x % offset_x_inc);
self.set_offset_x(offset_x)?;
let offset_y_inc = self.offset_y_increment()?;
let offset_y = roi.offset_y - (roi.offset_y % offset_y_inc);
self.set_offset_y(offset_y)?;
let actual_roi = Roi {
offset_x,
offset_y,
width,
height,
};
Ok(actual_roi)
}
pub fn roi(&self) -> Result<Roi, XI_RETURN> {
let width = self.width()?;
let height = self.height()?;
let offset_x = self.offset_x()?;
let offset_y = self.offset_y()?;
let result = Roi {
offset_x,
offset_y,
width,
height,
};
Ok(result)
}
pub fn counter(
&mut self,
counter_selector: XI_COUNTER_SELECTOR::Type,
) -> Result<i32, XI_RETURN> {
let prev_selector = self.counter_selector()?;
self.set_counter_selector(counter_selector)?;
let result = self.counter_value()?;
self.set_counter_selector(prev_selector)?;
Ok(result)
}
param! {
mut exposure: f32;
mut exposure_burst_count: i32;
mut gain: f32;
mut gain_selector: XI_GAIN_SELECTOR_TYPE::Type;
mut downsampling: XI_DOWNSAMPLING_VALUE::Type;
mut downsampling_type: XI_DOWNSAMPLING_TYPE::Type;
mut image_data_format: XI_IMG_FORMAT::Type;
mut test_pattern_generator_selector: XI_TEST_PATTERN_GENERATOR::Type;
mut test_pattern: XI_TEST_PATTERN::Type;
mut height: u32;
mut width: u32;
mut offset_x: u32;
mut offset_y: u32;
mut limit_bandwidth: i32;
available_bandwidth: i32;
mut trg_source: XI_TRG_SOURCE::Type;
mut trg_selector: XI_TRG_SELECTOR::Type;
mut trg_overlap: XI_TRG_OVERLAP::Type;
mut acq_frame_burst_count: u32;
mut gpi_selector: XI_GPI_SELECTOR::Type;
mut gpi_mode: XI_GPI_MODE::Type;
mut gpo_selector: XI_GPO_SELECTOR::Type;
mut gpo_mode: XI_GPO_MODE::Type;
mut led_selector: XI_LED_SELECTOR::Type;
mut led_mode: XI_LED_MODE::Type;
mut debounce_en: XI_SWITCH::Type;
mut image_user_data: u32;
mut sensor_data_bit_depth: XI_BIT_DEPTH::Type;
mut output_data_bit_depth: XI_BIT_DEPTH::Type;
mut image_data_bit_depth: XI_BIT_DEPTH::Type;
mut column_fpn_correction: XI_SWITCH::Type;
mut row_fpn_correction: XI_SWITCH::Type;
mut column_black_offset_correction: XI_SWITCH::Type;
mut row_black_offset_correction: XI_SWITCH::Type;
mut counter_selector: XI_COUNTER_SELECTOR::Type;
counter_value: i32;
mut sensor_feature_selector: XI_SENSOR_FEATURE_SELECTOR::Type;
mut sensor_feature_value: i32;
sensor_clock_freq_hz: f32;
mut buffer_policy: i32;
mut auto_wb: XI_SWITCH::Type;
mut wb_kr: f32;
mut wb_kg: f32;
mut wb_kb: f32;
mut recent_frame: XI_SWITCH::Type;
}
}
impl Deref for Camera {
type Target = HANDLE;
fn deref(&self) -> &Self::Target {
&self.device_handle
}
}
unsafe impl Send for Camera {
}
impl AcquisitionBuffer {
pub fn stop_acquisition(self) -> Result<Camera, XI_RETURN> {
let err = unsafe { xiapi_sys::xiStopAcquisition(self.camera.device_handle) };
match err as XI_RET::Type {
XI_RET::XI_OK => Ok(self.camera),
_ => Err(err),
}
}
pub fn next_image<'a, T>(&'a self, timeout: Option<u32>) -> Result<Image<'a, T>, XI_RETURN> {
let timeout = timeout.unwrap_or(u32::MAX);
let xi_img = unsafe {
let mut img = MaybeUninit::<XI_IMG>::zeroed().assume_init();
img.size = size_of::<XI_IMG>() as u32;
img
};
let mut image = Image::<'a, T> {
xi_img,
pix_type: PhantomData::default(),
};
let ret = unsafe {
xiapi_sys::xiGetImage(self.camera.device_handle, timeout, &mut image.xi_img)
};
match ret as XI_RET::Type{
XI_RET::XI_OK => {
Ok(image)
}
x => {
Err(x as XI_RETURN)
}
}
}
pub fn software_trigger(&mut self) -> Result<(), XI_RETURN> {
unsafe { self.camera.set_param(XI_PRM_TRG_SOFTWARE, XI_SWITCH::XI_ON) }
}
}
unsafe impl Send for AcquisitionBuffer{
}