Archived
1
This repository has been archived on 2021-06-01. You can view files and clone it, but cannot push or open issues or pull requests.
2021-05-29 10:58:02 -04:00

147 lines
4.3 KiB
Rust

//! Defines an interface for LeapMotion cameras
use std::time::{Duration, SystemTime};
use crate::image::Image;
use super::ffi;
/// Defines some errors that can come from the device
#[derive(Debug)]
pub enum DeviceError {
/// An error caused by too many instances being created
InstanceError,
/// An error caused by a timeout being reached
Timeout,
/// An error caused when no data is being sent by the device
NoData,
}
/// Represents a single data frame generated by the LeapMotion device
#[derive(Debug)]
pub struct DeviceFrame {
/// Number of bytes per pixel
pub bytes_per_pixel: u8,
/// Image from the left camera
pub left_camera: Image,
/// Image from the right camera
pub right_camera: Image,
}
/// Represents a LeapMotion device, and provides safe wrappers around its FFI
#[derive(Debug)]
pub struct LeapMotionDevice {
cameras_flipped: bool,
}
impl LeapMotionDevice {
/// Creates a LeapMotionDevice by talking to the device driver. This can only be called once
pub fn create_device(timeout: Duration) -> Result<Self, DeviceError> {
log::debug!("Creating LeapMotion device access");
// Handle possible error with multiple instances
unsafe {
if ffi::isControllerCreated() {
log::error!(
"Tried to create access to a LeapMotion device when an instance already exists"
);
return Err(DeviceError::InstanceError);
}
}
// Create an instance along with its handlers
unsafe {
ffi::beginEventLoop();
}
// Pause a small amount of time for the device to finish init or for the timeout to be hit
let time_now = SystemTime::now();
loop {
// Handle timeout
if time_now.elapsed().unwrap() > timeout {
log::error!("Hit device init timeout");
return Err(DeviceError::Timeout);
}
// Handle device connect
unsafe {
if ffi::isControllerCreated() && ffi::imageExists() {
break;
}
}
}
log::debug!("Device created");
Ok(Self {
cameras_flipped: false,
})
}
/// Configure the camera to flip its cameras. In normal configuration, the green light is facing the user, while the device is laying flat
pub fn set_cameras_flipped(&mut self, flipped: bool) {
self.cameras_flipped = flipped;
}
/// Get if the cameras are flipped
pub fn cameras_flipped(&self) -> bool {
self.cameras_flipped
}
/// Get if the device has a frame to be read
pub fn has_frame(&mut self) -> bool {
unsafe {
return ffi::isControllerCreated() && ffi::imageExists();
}
}
/// Get the latest frame from the device
pub fn get_frame(&mut self) -> Result<DeviceFrame, DeviceError> {
if !self.has_frame() {
return Err(DeviceError::NoData);
}
// Read raw data from the device
let image_width;
let image_height;
let bytes_per_pixel;
let left_image_raw;
let right_image_raw;
unsafe {
image_width = ffi::getImageWidth();
image_height = ffi::getImageHeight();
bytes_per_pixel = ffi::getImageBPP();
left_image_raw = std::slice::from_raw_parts(
ffi::getImageLeft(),
(image_width * image_height * bytes_per_pixel) as usize,
);
right_image_raw = std::slice::from_raw_parts(
ffi::getImageRight(),
(image_width * image_height * bytes_per_pixel) as usize,
);
}
// Build two images
let left_image = Image::new(image_width, image_height, left_image_raw);
let right_image = Image::new(image_width, image_height, right_image_raw);
Ok(DeviceFrame {
bytes_per_pixel: bytes_per_pixel as u8,
left_camera: left_image,
right_camera: right_image,
})
}
}
impl Drop for LeapMotionDevice {
fn drop(&mut self) {
log::debug!("Informing wrapper to deallocate LeapMotion device");
unsafe {
ffi::endEventLoop();
}
}
}