use crate::PinFunction;
use crate::device::PoKeysDevice;
use crate::error::{PoKeysError, Result};
pub(crate) enum Command {
SetInputOutput = 16, ReadDigitalInput = 48, SetPinOutput = 64, InputOutputExtended = 192, }
pub(crate) const INVERT_PIN_BIT: u8 = 0x80;
pub(crate) fn compose_pin_function_byte(f: PinFunction, inverted: bool) -> u8 {
(f as u8) | if inverted { INVERT_PIN_BIT } else { 0 }
}
impl PoKeysDevice {
pub(crate) fn get_pin_index(&self, pin: u32) -> usize {
let pin_index: usize = (pin - 1) as usize;
pin_index
}
pub(crate) fn check_pin_range(&self, pin: u32) -> Result<usize> {
if pin == 0 || pin as usize > self.pins.len() {
Err(PoKeysError::Parameter("Invalid pin number".to_string()))
} else {
Ok(self.get_pin_index(pin))
}
}
pub(crate) fn write_pin_function(
&mut self,
pin: u32,
pin_function: crate::io::PinFunction,
inverted: bool,
) -> Result<(u32, PinFunction)> {
match self.check_pin_range(pin) {
Ok(pin_index) => {
let wire_byte = compose_pin_function_byte(pin_function, inverted);
if self.pins[pin_index].pin_function == wire_byte {
return Ok((pin, pin_function));
}
let capability = match pin_function {
PinFunction::DigitalInput => "DigitalInput",
PinFunction::DigitalOutput => "DigitalOutput",
PinFunction::AnalogInput => "AnalogInput",
PinFunction::AnalogOutput => "AnalogOutput",
_ => "", };
if !capability.is_empty() && !self.is_pin_capability_supported(pin, capability) {
log::warn!("Pin {} does not support capability: {}", pin, capability);
if let Some(model) = &mut self.model {
if let Some(pin_model) = model.pins.get_mut(&(pin as u8)) {
pin_model.active = false;
log::warn!("Pin {} marked as inactive", pin);
}
}
return Err(PoKeysError::UnsupportedPinCapability(
pin as u8,
capability.to_string(),
));
}
if inverted {
match pin_function {
PinFunction::DigitalInput
| PinFunction::DigitalOutput
| PinFunction::TriggeredInput => {}
other => log::warn!(
"Pin {}: invert flag has no effect on {:?}; firmware will ignore bit 7",
pin,
other
),
}
}
let res = self.send_request(
Command::SetInputOutput as u8,
pin_index as u8,
wire_byte,
self.pins[pin_index].counter_options,
0,
)?;
if res[2] != 0 {
Err(PoKeysError::InternalError(
"Invalid pin or configuration locked".to_string(),
))
} else {
self.pins[pin_index].pin_function = wire_byte;
Ok((pin, pin_function))
}
}
Err(e) => Err(e),
}
}
pub(crate) fn read_digital_input(&mut self, pin: u32) -> Result<u8> {
match self.check_pin_range(pin) {
Ok(pin_index) => {
let res =
self.send_request(Command::ReadDigitalInput as u8, pin_index as u8, 0, 0, 0)?;
if res[2] != 0 {
Err(PoKeysError::InternalError(
"Invalid pin or configuration locked".to_string(),
))
} else {
Ok(res[3])
}
}
Err(e) => Err(e),
}
}
pub(crate) fn write_digital_output(&mut self, pin: u32, value: bool) -> Result<bool> {
match self.check_pin_range(pin) {
Ok(pin_index) => {
let res = self.send_request(
Command::SetPinOutput as u8,
pin_index as u8,
if value { 1 } else { 0 },
0,
0,
)?;
if res[2] != 0 || res[1] != Command::SetPinOutput as u8 {
Err(PoKeysError::InternalError(
"Invalid pin or configuration locked".to_string(),
))
} else {
Ok(true)
}
}
Err(e) => Err(e),
}
}
}