xiapi/camera.rs
1/*
2 * Copyright (c) 2022. XIMEA GmbH - All Rights Reserved
3 */
4use std::ffi::CStr;
5use std::marker::PhantomData;
6use std::mem::size_of;
7use std::mem::MaybeUninit;
8use std::ops::Deref;
9use std::os::raw::c_char;
10use std::str::from_utf8;
11
12use paste::paste;
13use xiapi_sys::*;
14
15use crate::Image;
16use crate::Roi;
17
18/// This macro is used to generate getters and setters for xiAPI parameters.
19/// The parameters are specified using the following syntax: \[mut\] <ParamName>: <Type>
20/// Documentation on the parameter will be added to the getter.
21/// Generic documentation is always added to the setter.
22///
23/// ## Examples:
24///
25/// ```ignore
26/// param!(
27/// mut exposure: f32;
28/// )
29/// ```
30macro_rules! param {
31 // This rule follows the Incremental TT muncher pattern.
32 () => {};
33 // For mutable parameters:
34 (
35 $(#[doc = $doc:expr])*
36 mut $prm:ident : $type:ty;
37 $($tail:tt)*
38 ) => {
39 paste! {
40 // Generate a getter with custom documentation
41 $(#[doc = $doc])*
42 pub fn $prm(&self) -> Result<$type, XI_RETURN>{
43 unsafe {self.param([<XI_PRM_ $prm:upper>]) }
44 }
45
46 // Generate a getter for the increment
47 #[doc = "Get the increment for the `" $prm "` parameter. See also [Self::" $prm "()]"]
48 pub fn [<$prm _increment>](& self) -> Result<$type, XI_RETURN>{
49 unsafe {self.param_increment([<XI_PRM_ $prm:upper>])}
50 }
51
52 // Generate getter for the minimum
53 #[doc = "Get the minimum for the `" $prm "` parameter. See also [Self::" $prm "()]"]
54 pub fn [<$prm _minimum>](& self) -> Result<$type, XI_RETURN>{
55 unsafe {self.param_min([<XI_PRM_ $prm:upper>])}
56 }
57
58 // Generate getter for the maximum
59 #[doc = "Get the maximum for the `" $prm "` parameter. See also [Self::" $prm "()]"]
60 pub fn [<$prm _maximum>](& self) -> Result<$type, XI_RETURN>{
61 unsafe {self.param_max([<XI_PRM_ $prm:upper>])}
62 }
63
64 // Generate a setter
65 // TODO: Customizable documentation for setters
66 #[doc = "Set the `" $prm "` parameter. See also [Self::" $prm "()]"]
67 pub fn [<set_ $prm>](& mut self, value: $type ) -> Result<(), XI_RETURN>{
68 unsafe {self.set_param([<XI_PRM_ $prm:upper>], value)}
69 }
70 param!($($tail)*);
71 }
72 };
73 // For immutable parameters
74 (
75 $(#[doc = $doc:expr])*
76 $prm:ident : $type:ty;
77 $($tail:tt)*
78 ) => {
79 paste! {
80 // Generate a getter with custom documentation
81 $(#[doc = $doc])*
82 pub fn $prm( &self) -> Result < $type, XI_RETURN >{
83 unsafe {self.param(paste ! ([ < XI_PRM_ $prm: upper > ]))}
84 }
85 param!($($tail)*);
86 }
87 };
88}
89/// Connected and initialized XIMEA camera.
90///
91/// Must be mutable to allow changing any parameters. A non-mutable Camera can be used from
92/// multiple threads or processes safely.
93pub struct Camera {
94 device_handle: HANDLE,
95}
96
97/// Buffer that is used by the camera to transfer images to the host system.
98///
99/// The AcquisitionBuffer is the primary way to communicate with the camera while it is actively
100/// acquiring images.
101/// It is generated when the image acquisition is started and destroyed when the image acquisition
102/// is stopped.
103///
104/// **Important difference to the C/C++ xiAPI:**
105/// The AcquisitionBuffer temporarily consumes the Camera during acquisition, to prevent any
106/// interactions that may change parameters that are fixed while the image acquisition is running.
107/// Trying to change an parameter that is not changeable during acquisition is therefore an error at
108/// compile time (as opposed to runtime in C/C++).
109pub struct AcquisitionBuffer {
110 camera: Camera,
111}
112
113/// Initializes a camera and returns it.
114///
115/// If successful, this function returns a Camera object that represents the camera which was
116/// initialized.
117/// If an error occurs, the Result contains the error code.
118///
119/// It is possible but not recommended to open the same camera from different processes at the same
120/// time.
121/// The device is automatically closed when the Camera object is dropped.
122///
123/// The automatic bandwidth calculation is enabled by default when using this method.
124///
125/// # Arguments
126///
127/// * `dev_id`: The device ID for the device to be initialized. Usually device IDs are sequential
128/// and start at 0 for the first device in the system. Default value: 0
129///
130/// # Examples
131///
132/// ```
133/// # #[serial_test::file_serial]
134/// # fn main() -> Result<(), xiapi_sys::XI_RETURN>{
135/// let mut cam = xiapi::open_device(None)?;
136/// cam.set_exposure(10000 as f32);
137/// // Do more stuff with the camera ...
138/// # Ok(())
139/// # }
140/// ```
141pub fn open_device(dev_id: Option<u32>) -> Result<Camera, XI_RETURN> {
142 let mut device_handle: HANDLE = std::ptr::null_mut();
143 let dev_id = dev_id.unwrap_or(0);
144 let err = unsafe { xiapi_sys::xiOpenDevice(dev_id, &mut device_handle) };
145 match err as XI_RET::Type {
146 XI_RET::XI_OK => Ok(Camera { device_handle }),
147 _ => Err(err),
148 }
149}
150
151/// Initialize the camera with the given bandwidth and return it.
152///
153/// If successful, this function returns a Camera object that represents the camera which was
154/// initialized.
155/// If an error occurs, the Result contains the error code.
156///
157/// The automatic bandwidth measurement is disabled when using this method. This can lead to faster device initialization.
158///
159/// # Arguments
160///
161/// *`dev_id`: The device ID for the device to be initialized. Usually device IDs are sequential
162/// and start at 0 for the first device in the system. Default value: 0
163/// *`bandwidth`: Transport layer bandwidth for this camera in MBit/s
164///
165/// # Examples
166///
167/// ```
168/// # #[serial_test::file_serial]
169/// # fn main() -> Result<(), xiapi_sys::XI_RETURN>{
170/// let mut cam = xiapi::open_device_manual_bandwidth(None, 1000)?;
171/// cam.set_exposure(10000 as f32);
172/// // Do more stuff with the camera ...
173/// # Ok(())
174/// # }
175/// ```
176pub fn open_device_manual_bandwidth(
177 dev_id: Option<u32>,
178 bandwidth: i32,
179) -> Result<Camera, XI_RETURN> {
180 let cam = unsafe {
181 let bandwidth_param_c = match CStr::from_bytes_with_nul(XI_PRM_AUTO_BANDWIDTH_CALCULATION) {
182 Ok(c) => c,
183 Err(_) => return Err(XI_RET::XI_INVALID_ARG as XI_RETURN),
184 };
185 match i32::set_param(
186 std::ptr::null_mut(),
187 bandwidth_param_c.as_ptr(),
188 XI_SWITCH::XI_OFF as i32,
189 ) as XI_RET::Type
190 {
191 XI_RET::XI_OK => {}
192 err => return Err(err as i32),
193 };
194
195 let cam = open_device(dev_id);
196 match i32::set_param(
197 std::ptr::null_mut(),
198 bandwidth_param_c.as_ptr(),
199 XI_SWITCH::XI_ON as i32,
200 ) as XI_RET::Type
201 {
202 XI_RET::XI_OK => {}
203 _ => panic!("Could not enable auto bandwidth calculation!"),
204 }
205 cam
206 };
207 match cam {
208 Ok(mut cam) => {
209 cam.set_limit_bandwidth(bandwidth)?;
210 Ok(cam)
211 }
212 Err(err) => Err(err),
213 }
214}
215
216/// Returns the number of available cameras.
217///
218/// # Examples
219///
220/// ```
221/// # #[serial_test::file_serial]
222/// # fn main() -> Result<(), xiapi::XI_RETURN>{
223/// let number_devices = xiapi::number_devices()?;
224/// let mut cameras = Vec::with_capacity(number_devices as usize);
225/// for i in 0..number_devices {
226/// cameras.push(xiapi::open_device(Some(i))?);
227/// }
228/// # Ok(())
229/// # }
230pub fn number_devices() -> Result<u32, XI_RETURN> {
231 unsafe {
232 let mut value = 0u32;
233 let res = xiapi_sys::xiGetNumberDevices(&mut value);
234 match res as XI_RET::Type {
235 XI_RET::XI_OK => Ok(value),
236 _ => Err(res),
237 }
238 }
239}
240
241impl Drop for Camera {
242 fn drop(&mut self) {
243 unsafe {
244 xiapi_sys::xiCloseDevice(self.device_handle);
245 }
246 }
247}
248
249trait ParamType: Default {
250 unsafe fn get_param(
251 handle: xiapi_sys::HANDLE,
252 prm: *const std::os::raw::c_char,
253 value: &mut Self,
254 ) -> XI_RETURN;
255 unsafe fn set_param(
256 handle: xiapi_sys::HANDLE,
257 prm: *const std::os::raw::c_char,
258 value: Self,
259 ) -> XI_RETURN;
260}
261
262impl ParamType for f32 {
263 unsafe fn get_param(handle: HANDLE, prm: *const c_char, value: &mut Self) -> XI_RETURN {
264 xiapi_sys::xiGetParamFloat(handle, prm, value)
265 }
266
267 unsafe fn set_param(handle: HANDLE, prm: *const c_char, value: Self) -> XI_RETURN {
268 xiapi_sys::xiSetParamFloat(handle, prm, value)
269 }
270}
271
272impl ParamType for i32 {
273 unsafe fn get_param(handle: HANDLE, prm: *const c_char, value: &mut Self) -> XI_RETURN {
274 xiapi_sys::xiGetParamInt(handle, prm, value)
275 }
276
277 unsafe fn set_param(handle: HANDLE, prm: *const c_char, value: Self) -> XI_RETURN {
278 xiapi_sys::xiSetParamInt(handle, prm, value)
279 }
280}
281
282impl ParamType for u32 {
283 // Selectors in xiAPI are defined as unsigned int, but treated as if they were signed
284 unsafe fn get_param(handle: HANDLE, prm: *const c_char, value: &mut Self) -> XI_RETURN {
285 xiapi_sys::xiGetParamInt(handle, prm, value as *mut u32 as *mut i32)
286 }
287
288 unsafe fn set_param(handle: HANDLE, prm: *const c_char, value: Self) -> XI_RETURN {
289 xiapi_sys::xiSetParamInt(handle, prm, value as i32)
290 }
291}
292
293impl Camera {
294 /// Starts the image acquisition on this camera
295 ///
296 /// This function creates the AcquisitionBuffer and tells the camera to start streaming data
297 /// to this buffer.
298 /// The camera is temporarily consumed by the AcquisitionBuffer, so you can only interact with
299 /// it through the AcquisitionBuffer.
300 ///
301 /// # Examples
302 /// ```
303 /// # #[serial_test::file_serial]
304 /// # fn main() -> Result<(), xiapi_sys::XI_RETURN> {
305 /// let cam = xiapi::open_device(None)?;
306 /// let buffer = cam.start_acquisition()?;
307 /// let image = buffer.next_image::<u8>(None)?;
308 /// // Do something with the image;
309 /// let cam = buffer.stop_acquisition()?;
310 /// # Ok(())
311 /// # }
312 pub fn start_acquisition(self) -> Result<AcquisitionBuffer, XI_RETURN> {
313 let err = unsafe { xiapi_sys::xiStartAcquisition(self.device_handle) };
314 match err as XI_RET::Type {
315 XI_RET::XI_OK => Ok(AcquisitionBuffer { camera: self }),
316 _ => Err(err),
317 }
318 }
319
320 unsafe fn set_param<T: ParamType>(&mut self, param: &[u8], value: T) -> Result<(), XI_RETURN> {
321 let param_c = match CStr::from_bytes_with_nul(param) {
322 Ok(c) => c,
323 Err(_) => return Err(XI_RET::XI_INVALID_ARG as XI_RETURN),
324 };
325 let err = T::set_param(self.device_handle, param_c.as_ptr(), value);
326 match err as XI_RET::Type {
327 XI_RET::XI_OK => Ok(()),
328 _ => Err(err),
329 }
330 }
331
332 unsafe fn param<T: ParamType>(&self, param: &[u8]) -> Result<T, XI_RETURN> {
333 let mut value = T::default();
334 let param_c = match CStr::from_bytes_with_nul(param) {
335 Ok(c) => c,
336 Err(_) => return Err(XI_RET::XI_INVALID_ARG as XI_RETURN),
337 };
338 let err = T::get_param(self.device_handle, param_c.as_ptr(), &mut value);
339 match err as XI_RET::Type {
340 XI_RET::XI_OK => Ok(value),
341 _ => Err(err),
342 }
343 }
344
345 unsafe fn param_increment<T: ParamType>(&self, param: &'static [u8]) -> Result<T, XI_RETURN> {
346 self.param_info(param, XI_PRM_INFO_INCREMENT)
347 }
348
349 unsafe fn param_min<T: ParamType>(&self, param: &'static [u8]) -> Result<T, XI_RETURN> {
350 self.param_info(param, XI_PRM_INFO_MIN)
351 }
352
353 unsafe fn param_max<T: ParamType>(&self, param: &'static [u8]) -> Result<T, XI_RETURN> {
354 self.param_info(param, XI_PRM_INFO_MAX)
355 }
356
357 unsafe fn param_info<T: ParamType>(
358 &self,
359 param: &'static [u8],
360 info_modifier: &'static [u8],
361 ) -> Result<T, XI_RETURN> {
362 // Strings need to be sanitized and then concatenated
363 let param_utf8 = from_utf8(param).or(Err(XI_RET::XI_INVALID_ARG as i32))?;
364 let modifier_utf8 =
365 from_utf8(info_modifier).expect("UTF8 error on API constant -> Unreachable");
366 // We have to specifically trim the null character from the first string
367 let modified_param = format!(
368 "{}{}",
369 param_utf8.trim_matches(char::from(0)),
370 modifier_utf8
371 );
372 self.param(modified_param.as_bytes())
373 }
374
375 /// Set the region of interest on this camera.
376 ///
377 /// Return the region of interest that was actually set to the camera.
378 ///
379 /// # Examples
380 ///
381 /// ```
382 /// # #[serial_test::file_serial]
383 /// # fn main() -> Result<(), xiapi_sys::XI_RETURN> {
384 /// let mut cam = xiapi::open_device(None)?;
385 /// let roi = xiapi::Roi{
386 /// offset_x: 100,
387 /// offset_y: 100,
388 /// width: 100,
389 /// height: 100
390 /// };
391 /// let actual_roi = cam.set_roi(&roi)?;
392 /// # Ok(())
393 /// # }
394 ///
395 pub fn set_roi(&mut self, roi: &Roi) -> Result<Roi, XI_RETURN> {
396 self.set_offset_x(0)?;
397 self.set_offset_y(0)?;
398
399 let width_inc = self.width_increment()?;
400 let width = roi.width - (roi.width % width_inc);
401 self.set_width(width)?;
402
403 let height_inc = self.height_increment()?;
404 let height = roi.height - (roi.height % height_inc);
405 self.set_height(height)?;
406
407 let offset_x_inc = self.offset_x_increment()?;
408 let offset_x = roi.offset_x - (roi.offset_x % offset_x_inc);
409 self.set_offset_x(offset_x)?;
410
411 let offset_y_inc = self.offset_y_increment()?;
412 let offset_y = roi.offset_y - (roi.offset_y % offset_y_inc);
413 self.set_offset_y(offset_y)?;
414
415 let actual_roi = Roi {
416 offset_x,
417 offset_y,
418 width,
419 height,
420 };
421 Ok(actual_roi)
422 }
423
424 /// Returns the current roi from this camera
425 pub fn roi(&self) -> Result<Roi, XI_RETURN> {
426 let width = self.width()?;
427 let height = self.height()?;
428 let offset_x = self.offset_x()?;
429 let offset_y = self.offset_y()?;
430 let result = Roi {
431 offset_x,
432 offset_y,
433 width,
434 height,
435 };
436 Ok(result)
437 }
438
439 /// Convenience method to read counters from the camera with a single call
440 /// See also [Self.counter_selector] and [Self.counter_value]
441 pub fn counter(
442 &mut self,
443 counter_selector: XI_COUNTER_SELECTOR::Type,
444 ) -> Result<i32, XI_RETURN> {
445 let prev_selector = self.counter_selector()?;
446 self.set_counter_selector(counter_selector)?;
447 let result = self.counter_value()?;
448 self.set_counter_selector(prev_selector)?;
449 Ok(result)
450 }
451
452 param! {
453 /// Current exposure time in microseconds.
454 mut exposure: f32;
455
456 /// Sets the number of times of exposure in one frame.
457 mut exposure_burst_count: i32;
458
459 /// Set the gain in dB.
460 /// If the camera has more than one type of gain, you can use [Self::set_gain_selector()] to
461 /// select a gain.
462 mut gain: f32;
463
464 /// The currently selected type of gain for [Self::gain()] and [Self::set_gain()]
465 mut gain_selector: XI_GAIN_SELECTOR_TYPE::Type;
466
467 /// Changes image resolution by binning or skipping
468 mut downsampling: XI_DOWNSAMPLING_VALUE::Type;
469
470 /// Changes the downsampling type between binning and skipping
471 mut downsampling_type: XI_DOWNSAMPLING_TYPE::Type;
472
473 /// Format of the image data
474 mut image_data_format: XI_IMG_FORMAT::Type;
475
476 /// Selects the Test Pattern Generator Engine
477 mut test_pattern_generator_selector: XI_TEST_PATTERN_GENERATOR::Type;
478
479 /// Selects the Test Pattern to be generated by selected Generator Engine
480 mut test_pattern: XI_TEST_PATTERN::Type;
481
482 /// Immage ROI height (number of lines)
483 mut height: u32;
484
485 /// Image ROI width (number of columns)
486 mut width: u32;
487
488 /// Image ROI offset in the horizontal direction
489 mut offset_x: u32;
490
491 /// Image ROI offset in the vertical direction
492 mut offset_y: u32;
493
494 /// Camera acquisition data-rate limit on transport layer in Megabits per second.
495 mut limit_bandwidth: i32;
496
497 /// Available interface bandwidth measured by automatic bandwidth measurement.
498 available_bandwidth: i32;
499
500 /// Defines the source of trigger
501 mut trg_source: XI_TRG_SOURCE::Type;
502
503 /// Selects the type of trigger
504 mut trg_selector: XI_TRG_SELECTOR::Type;
505
506 /// Selects the type of trigger overlap
507 mut trg_overlap: XI_TRG_OVERLAP::Type;
508
509 /// Sets the number of frames to be triggered for each trigger signal.
510 /// This setting is only valid if the trigger selector is set to XI_TRG_SEL_FRAME_BURST_START
511 mut acq_frame_burst_count: u32;
512
513 /// Selects a GPI
514 mut gpi_selector: XI_GPI_SELECTOR::Type;
515
516 /// Defines functionality for the selected GPI
517 mut gpi_mode: XI_GPI_MODE::Type;
518
519 /// Selects a GPO
520 mut gpo_selector: XI_GPO_SELECTOR::Type;
521
522 /// Defines functionality for the selected GPO
523 mut gpo_mode: XI_GPO_MODE::Type;
524
525 /// Selects a LED
526 mut led_selector: XI_LED_SELECTOR::Type;
527
528 /// Defines functionality for the selected LED
529 mut led_mode: XI_LED_MODE::Type;
530
531 /// Enable or disable signal debounce for selected GPI
532 mut debounce_en: XI_SWITCH::Type;
533
534 /// Set user data to be stored in the image header
535 mut image_user_data: u32;
536
537 /// Set the bit depth for the ADCs on the sensor
538 /// # Examples
539 /// ```
540 /// # #[serial_test::file_serial()]
541 /// # fn main() -> Result<(), xiapi::XI_RETURN>{
542 /// # use xiapi_sys::XI_IMG_FORMAT::XI_RAW16;
543 /// # use xiapi::XI_BIT_DEPTH::XI_BPP_12;
544 /// let mut cam = xiapi::open_device(None)?;
545 /// cam.set_image_data_format(XI_RAW16)?;
546 /// cam.set_sensor_data_bit_depth(XI_BPP_12)?;
547 /// cam.set_output_data_bit_depth(XI_BPP_12)?;
548 /// cam.set_image_data_bit_depth(XI_BPP_12)?;
549 /// # assert_eq!(cam.sensor_data_bit_depth()?, XI_BPP_12);
550 /// # assert_eq!(cam.output_data_bit_depth()?, XI_BPP_12);
551 /// # assert_eq!(cam.image_data_bit_depth()?, XI_BPP_12);
552 /// # Ok(())
553 /// }
554 mut sensor_data_bit_depth: XI_BIT_DEPTH::Type;
555
556 /// Set the bit depth send from the camera to the PC
557 mut output_data_bit_depth: XI_BIT_DEPTH::Type;
558
559 /// Bit depth of the image returned by [Self::next_image()]
560 mut image_data_bit_depth: XI_BIT_DEPTH::Type;
561
562 /// Enable column fpn correction in camera
563 mut column_fpn_correction: XI_SWITCH::Type;
564
565 /// Enable row fpn correction in camera
566 mut row_fpn_correction: XI_SWITCH::Type;
567
568 /// Enable column black offset correction
569 mut column_black_offset_correction: XI_SWITCH::Type;
570
571 /// Enable row black offset correction
572 mut row_black_offset_correction: XI_SWITCH::Type;
573
574 /// Select the frame counter to read
575 mut counter_selector: XI_COUNTER_SELECTOR::Type;
576
577 /// Read the value of a frame counter selected with [Self::set_counter_selector]
578 counter_value: i32;
579
580 /// Select a sensor specific feature
581 mut sensor_feature_selector: XI_SENSOR_FEATURE_SELECTOR::Type;
582
583 /// Set a value for the feature selected with [Self::set_sensor_feature_selector]
584 mut sensor_feature_value: i32;
585
586 /// Read the sensor clock frequency in Hz
587 sensor_clock_freq_hz: f32;
588
589 /// Data move policy
590 mut buffer_policy: i32;
591
592 /// Auto white balance mode.
593 mut auto_wb: XI_SWITCH::Type;
594
595 /// White balance Red coefficient.
596 mut wb_kr: f32;
597
598 /// White balance Green coefficient.
599 mut wb_kg: f32;
600
601 /// White balance Blue coefficient.
602 mut wb_kb: f32;
603
604 /// Recent Frame mode.
605 mut recent_frame: XI_SWITCH::Type;
606 }
607}
608
609impl Deref for Camera {
610 type Target = HANDLE;
611
612 /// Returns a reference to the wrapped device handle.
613 ///
614 /// While getting the handle itself is safe, everything that can practically be done with it
615 /// should be considered unsafe. Especially operations that change the state of the camera
616 /// (e.g. setting parameters) are undefined behavior.
617 fn deref(&self) -> &Self::Target {
618 &self.device_handle
619 }
620}
621
622unsafe impl Send for Camera {
623}
624
625impl AcquisitionBuffer {
626 /// Stop the image acquisition.
627 ///
628 /// This function consumes the acquisition buffer and returns the contained camera.
629 /// All resources acquired when creating this AcquisitionBuffer using
630 /// [Camera::start_acquisition()] will be freed again.
631 ///
632 /// When this is called, the camera will stop acquiring images and images previously acquired
633 /// but not retrieved from the acquisition buffer can no longer be accessed.
634 pub fn stop_acquisition(self) -> Result<Camera, XI_RETURN> {
635 let err = unsafe { xiapi_sys::xiStopAcquisition(self.camera.device_handle) };
636 match err as XI_RET::Type {
637 XI_RET::XI_OK => Ok(self.camera),
638 _ => Err(err),
639 }
640 }
641
642 /// Get the next image.
643 ///
644 /// Returns an [Image] which refers to memory in this [AcquisitionBuffer].
645 /// The image will have a reference with the same lifetime as the AcquisitionBuffer making sure
646 /// that it is always "safe" to use (However, it may still be overwritten in unsafe buffer mode).
647 pub fn next_image<'a, T>(&'a self, timeout: Option<u32>) -> Result<Image<'a, T>, XI_RETURN> {
648 let timeout = timeout.unwrap_or(u32::MAX);
649 let xi_img = unsafe {
650 let mut img = MaybeUninit::<XI_IMG>::zeroed().assume_init();
651 img.size = size_of::<XI_IMG>() as u32;
652 img
653 };
654 let mut image = Image::<'a, T> {
655 xi_img,
656 pix_type: PhantomData::default(),
657 };
658 let ret = unsafe {
659 xiapi_sys::xiGetImage(self.camera.device_handle, timeout, &mut image.xi_img)
660 };
661
662 match ret as XI_RET::Type{
663 XI_RET::XI_OK => {
664 Ok(image)
665 }
666 x => {
667 Err(x as XI_RETURN)
668 }
669 }
670
671 }
672
673 /// Send a software trigger signal to the camera.
674 ///
675 /// Trigger source has to be set to XI_TRG_SOFTWARE for this to take effect
676 ///
677 /// # Examples
678 /// ```
679 /// # #[serial_test::file_serial]
680 /// # fn main() -> Result<(), xiapi_sys::XI_RETURN> {
681 /// let mut cam = xiapi::open_device(None)?;
682 /// cam.set_trg_source(xiapi_sys::XI_TRG_SOURCE::XI_TRG_SOFTWARE)?;
683 /// let mut acq_buffer = cam.start_acquisition()?;
684 /// acq_buffer.software_trigger()?;
685 /// let img = acq_buffer.next_image::<u8>(None)?;
686 /// # Ok(())
687 /// # }
688 /// ```
689 pub fn software_trigger(&mut self) -> Result<(), XI_RETURN> {
690 unsafe { self.camera.set_param(XI_PRM_TRG_SOFTWARE, XI_SWITCH::XI_ON) }
691 }
692}
693
694unsafe impl Send for AcquisitionBuffer{
695
696}