use crate::{Error, Phidget, Result, ReturnCode};
use phidget_sys::{self as ffi, PhidgetDigitalInputHandle, PhidgetHandle};
use std::{
ffi::{c_int, c_uint, c_void},
mem, ptr,
};
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum InputMode {
NPN = ffi::Phidget_InputMode_INPUT_MODE_NPN,
PNP = ffi::Phidget_InputMode_INPUT_MODE_PNP,
}
impl TryFrom<u32> for InputMode {
type Error = Error;
fn try_from(value: u32) -> Result<Self> {
use InputMode::*;
match value {
ffi::Phidget_InputMode_INPUT_MODE_NPN => Ok(NPN),
ffi::Phidget_InputMode_INPUT_MODE_PNP => Ok(PNP),
_ => Err(ReturnCode::UnknownVal),
}
}
}
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum PowerSupply {
OFF = ffi::Phidget_PowerSupply_POWER_SUPPLY_OFF,
V12 = ffi::Phidget_PowerSupply_POWER_SUPPLY_12V,
V24 = ffi::Phidget_PowerSupply_POWER_SUPPLY_24V,
}
impl TryFrom<u32> for PowerSupply {
type Error = Error;
fn try_from(value: u32) -> Result<Self> {
use PowerSupply::*;
match value {
ffi::Phidget_PowerSupply_POWER_SUPPLY_OFF => Ok(OFF),
ffi::Phidget_PowerSupply_POWER_SUPPLY_12V => Ok(V12),
ffi::Phidget_PowerSupply_POWER_SUPPLY_24V => Ok(V24),
_ => Err(ReturnCode::UnknownVal),
}
}
}
pub type AttachCallback = dyn Fn(&mut DigitalInput) + Send + 'static;
pub type DetachCallback = dyn Fn(&mut DigitalInput) + Send + 'static;
pub type DigitalInputCallback = dyn Fn(&DigitalInput, u8) + Send + 'static;
pub struct DigitalInput {
chan: PhidgetDigitalInputHandle,
cb: Option<*mut c_void>,
attach_cb: Option<*mut c_void>,
detach_cb: Option<*mut c_void>,
}
impl DigitalInput {
pub fn new() -> Self {
let mut chan: PhidgetDigitalInputHandle = ptr::null_mut();
unsafe {
ffi::PhidgetDigitalInput_create(&mut chan);
}
Self::from(chan)
}
unsafe extern "C" fn on_attach(phid: PhidgetHandle, ctx: *mut c_void) {
if !ctx.is_null() {
let cb: &mut Box<AttachCallback> = &mut *(ctx as *mut _);
let mut sensor = Self::from(phid as PhidgetDigitalInputHandle);
cb(&mut sensor);
mem::forget(sensor);
}
}
unsafe extern "C" fn on_detach(phid: PhidgetHandle, ctx: *mut c_void) {
if !ctx.is_null() {
let cb: &mut Box<DetachCallback> = &mut *(ctx as *mut _);
let mut sensor = Self::from(phid as PhidgetDigitalInputHandle);
cb(&mut sensor);
mem::forget(sensor);
}
}
unsafe extern "C" fn on_state_change(
chan: PhidgetDigitalInputHandle,
ctx: *mut c_void,
state: c_int,
) {
if !ctx.is_null() {
let cb: &mut Box<DigitalInputCallback> = &mut *(ctx as *mut _);
let sensor = Self::from(chan);
cb(&sensor, state as u8);
mem::forget(sensor);
}
}
pub fn as_channel(&self) -> &PhidgetDigitalInputHandle {
&self.chan
}
pub fn set_input_mode(&self, input_mode: InputMode) -> Result<()> {
ReturnCode::result(unsafe {
ffi::PhidgetDigitalInput_setInputMode(self.chan, input_mode as c_uint)
})?;
Ok(())
}
pub fn input_mode(&self) -> Result<InputMode> {
let mut im: ffi::Phidget_InputMode = 0;
ReturnCode::result(unsafe { ffi::PhidgetDigitalInput_getInputMode(self.chan, &mut im) })?;
InputMode::try_from(im)
}
pub fn set_power_supply(&self, power_supply: PowerSupply) -> Result<()> {
ReturnCode::result(unsafe {
ffi::PhidgetDigitalInput_setPowerSupply(self.chan, power_supply as c_uint)
})?;
Ok(())
}
pub fn power_supply(&self) -> Result<PowerSupply> {
let mut ps: ffi::Phidget_PowerSupply = 0;
ReturnCode::result(unsafe { ffi::PhidgetDigitalInput_getPowerSupply(self.chan, &mut ps) })?;
PowerSupply::try_from(ps)
}
pub fn state(&self) -> Result<u8> {
let mut value = 0;
ReturnCode::result(unsafe { ffi::PhidgetDigitalInput_getState(self.chan, &mut value) })?;
Ok(value as u8)
}
pub fn set_on_state_change_handler<F>(&mut self, cb: F) -> Result<()>
where
F: Fn(&DigitalInput, u8) + Send + 'static,
{
let cb: Box<Box<DigitalInputCallback>> = Box::new(Box::new(cb));
let ctx = Box::into_raw(cb) as *mut c_void;
self.cb = Some(ctx);
ReturnCode::result(unsafe {
ffi::PhidgetDigitalInput_setOnStateChangeHandler(
self.chan,
Some(Self::on_state_change),
ctx,
)
})
}
pub fn set_on_attach_handler<F>(&mut self, cb: F) -> Result<()>
where
F: Fn(&mut DigitalInput) + Send + 'static,
{
let cb: Box<Box<AttachCallback>> = Box::new(Box::new(cb));
let ctx = Box::into_raw(cb) as *mut c_void;
ReturnCode::result(unsafe {
ffi::Phidget_setOnAttachHandler(self.as_mut_handle(), Some(Self::on_attach), ctx)
})?;
self.attach_cb = Some(ctx);
Ok(())
}
pub fn set_on_detach_handler<F>(&mut self, cb: F) -> Result<()>
where
F: Fn(&mut DigitalInput) + Send + 'static,
{
let cb: Box<Box<DetachCallback>> = Box::new(Box::new(cb));
let ctx = Box::into_raw(cb) as *mut c_void;
ReturnCode::result(unsafe {
ffi::Phidget_setOnDetachHandler(self.as_mut_handle(), Some(Self::on_detach), ctx)
})?;
self.detach_cb = Some(ctx);
Ok(())
}
}
impl Phidget for DigitalInput {
fn as_mut_handle(&mut self) -> PhidgetHandle {
self.chan as PhidgetHandle
}
fn as_handle(&self) -> PhidgetHandle {
self.chan as PhidgetHandle
}
}
unsafe impl Send for DigitalInput {}
impl Default for DigitalInput {
fn default() -> Self {
Self::new()
}
}
impl From<PhidgetDigitalInputHandle> for DigitalInput {
fn from(chan: PhidgetDigitalInputHandle) -> Self {
Self {
chan,
cb: None,
attach_cb: None,
detach_cb: None,
}
}
}
impl Drop for DigitalInput {
fn drop(&mut self) {
if let Ok(true) = self.is_open() {
let _ = self.close();
}
unsafe {
ffi::PhidgetDigitalInput_delete(&mut self.chan);
crate::drop_cb::<DigitalInputCallback>(self.cb.take());
crate::drop_cb::<AttachCallback>(self.attach_cb.take());
crate::drop_cb::<DetachCallback>(self.detach_cb.take());
}
}
}