use crate::{Phidget, Result, ReturnCode};
use phidget_sys::{self as ffi, PhidgetDigitalOutputHandle, PhidgetHandle};
use std::{
ffi::{c_int, c_void},
mem, ptr,
};
pub type AttachCallback = dyn Fn(&mut DigitalOutput) + Send + 'static;
pub type DetachCallback = dyn Fn(&mut DigitalOutput) + Send + 'static;
pub struct DigitalOutput {
chan: PhidgetDigitalOutputHandle,
attach_cb: Option<*mut c_void>,
detach_cb: Option<*mut c_void>,
}
impl DigitalOutput {
pub fn new() -> Self {
let mut chan: PhidgetDigitalOutputHandle = ptr::null_mut();
unsafe {
ffi::PhidgetDigitalOutput_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 PhidgetDigitalOutputHandle);
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 PhidgetDigitalOutputHandle);
cb(&mut sensor);
mem::forget(sensor);
}
}
pub fn as_channel(&self) -> &PhidgetDigitalOutputHandle {
&self.chan
}
pub fn set_enable_failsafe(&self, failsafe_time: u32) -> Result<()> {
ReturnCode::result(unsafe {
ffi::PhidgetDigitalOutput_enableFailsafe(self.chan, failsafe_time)
})?;
Ok(())
}
pub fn set_reset_failsafe(&self) -> Result<()> {
ReturnCode::result(unsafe { ffi::PhidgetDigitalOutput_resetFailsafe(self.chan) })?;
Ok(())
}
pub fn set_duty_cycle(&self, duty_cycle: f64) -> Result<()> {
ReturnCode::result(unsafe {
ffi::PhidgetDigitalOutput_setDutyCycle(self.chan, duty_cycle)
})?;
Ok(())
}
pub fn duty_cycle(&self) -> Result<f64> {
let mut value = 0.0;
ReturnCode::result(unsafe {
ffi::PhidgetDigitalOutput_getDutyCycle(self.chan, &mut value)
})?;
Ok(value)
}
pub fn min_duty_cycle(&self) -> Result<f64> {
let mut value = 0.0;
ReturnCode::result(unsafe {
ffi::PhidgetDigitalOutput_getMinDutyCycle(self.chan, &mut value)
})?;
Ok(value)
}
pub fn max_duty_cycle(&self) -> Result<f64> {
let mut value = 0.0;
ReturnCode::result(unsafe {
ffi::PhidgetDigitalOutput_getMaxDutyCycle(self.chan, &mut value)
})?;
Ok(value)
}
pub fn min_failsafe_time(&self) -> Result<u32> {
let mut value = 0;
ReturnCode::result(unsafe {
ffi::PhidgetDigitalOutput_getMinFailsafeTime(self.chan, &mut value)
})?;
Ok(value)
}
pub fn max_failsafe_time(&self) -> Result<u32> {
let mut value = 0;
ReturnCode::result(unsafe {
ffi::PhidgetDigitalOutput_getMaxFailsafeTime(self.chan, &mut value)
})?;
Ok(value)
}
pub fn set_frequency(&self, frequency: f64) -> Result<()> {
ReturnCode::result(unsafe {
ffi::PhidgetDigitalOutput_setFrequency(self.chan, frequency)
})?;
Ok(())
}
pub fn frequency(&self) -> Result<f64> {
let mut value = 0.0;
ReturnCode::result(unsafe {
ffi::PhidgetDigitalOutput_getFrequency(self.chan, &mut value)
})?;
Ok(value)
}
pub fn min_frequency(&self) -> Result<f64> {
let mut value = 0.0;
ReturnCode::result(unsafe {
ffi::PhidgetDigitalOutput_getMinFrequency(self.chan, &mut value)
})?;
Ok(value)
}
pub fn max_frequency(&self) -> Result<f64> {
let mut value = 0.0;
ReturnCode::result(unsafe {
ffi::PhidgetDigitalOutput_getMaxFrequency(self.chan, &mut value)
})?;
Ok(value)
}
pub fn set_led_current_limit(&self, led_current_limit: f64) -> Result<()> {
ReturnCode::result(unsafe {
ffi::PhidgetDigitalOutput_setLEDCurrentLimit(self.chan, led_current_limit)
})?;
Ok(())
}
pub fn led_current_limit(&self) -> Result<f64> {
let mut value = 0.0;
ReturnCode::result(unsafe {
ffi::PhidgetDigitalOutput_getLEDCurrentLimit(self.chan, &mut value)
})?;
Ok(value)
}
pub fn min_led_current_limit(&self) -> Result<f64> {
let mut value = 0.0;
ReturnCode::result(unsafe {
ffi::PhidgetDigitalOutput_getMinLEDCurrentLimit(self.chan, &mut value)
})?;
Ok(value)
}
pub fn max_led_current_limit(&self) -> Result<f64> {
let mut value = 0.0;
ReturnCode::result(unsafe {
ffi::PhidgetDigitalOutput_getMaxLEDCurrentLimit(self.chan, &mut value)
})?;
Ok(value)
}
pub fn led_forward_voltage(&self) -> Result<u32> {
let mut value: ffi::PhidgetDigitalOutput_LEDForwardVoltage = 0;
ReturnCode::result(unsafe {
ffi::PhidgetDigitalOutput_getLEDForwardVoltage(self.chan, &mut value)
})?;
Ok(value)
}
pub fn set_state(&self, state: u8) -> Result<()> {
ReturnCode::result(unsafe { ffi::PhidgetDigitalOutput_setState(self.chan, state as c_int) })
}
pub fn state(&self) -> Result<u8> {
let mut value = 0;
ReturnCode::result(unsafe { ffi::PhidgetDigitalOutput_getState(self.chan, &mut value) })?;
Ok(value as u8)
}
pub fn set_on_attach_handler<F>(&mut self, cb: F) -> Result<()>
where
F: Fn(&mut DigitalOutput) + 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 DigitalOutput) + 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 DigitalOutput {
fn as_mut_handle(&mut self) -> PhidgetHandle {
self.chan as PhidgetHandle
}
fn as_handle(&self) -> PhidgetHandle {
self.chan as PhidgetHandle
}
}
unsafe impl Send for DigitalOutput {}
impl Default for DigitalOutput {
fn default() -> Self {
Self::new()
}
}
impl From<PhidgetDigitalOutputHandle> for DigitalOutput {
fn from(chan: PhidgetDigitalOutputHandle) -> Self {
Self {
chan,
attach_cb: None,
detach_cb: None,
}
}
}
impl Drop for DigitalOutput {
fn drop(&mut self) {
if let Ok(true) = self.is_open() {
let _ = self.close();
}
unsafe {
ffi::PhidgetDigitalOutput_delete(&mut self.chan);
crate::drop_cb::<AttachCallback>(self.attach_cb.take());
crate::drop_cb::<DetachCallback>(self.detach_cb.take());
}
}
}