use pros_core::bail_on;
use pros_sys::PROS_ERR;
use super::{AdiDevice, AdiDeviceType, AdiError, AdiPort};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LogicLevel {
High,
Low,
}
impl LogicLevel {
pub const fn is_high(&self) -> bool {
match self {
Self::High => true,
Self::Low => false,
}
}
pub const fn is_low(&self) -> bool {
match self {
Self::High => false,
Self::Low => true,
}
}
}
impl core::ops::Not for LogicLevel {
type Output = Self;
fn not(self) -> Self::Output {
match self {
Self::Low => Self::High,
Self::High => Self::Low,
}
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct AdiDigitalIn {
port: AdiPort,
}
impl AdiDigitalIn {
pub fn new(port: AdiPort) -> Result<Self, AdiError> {
bail_on!(PROS_ERR, unsafe {
pros_sys::ext_adi_port_set_config(
port.internal_expander_index(),
port.index(),
pros_sys::E_ADI_DIGITAL_IN,
)
});
Ok(Self { port })
}
pub fn level(&self) -> Result<LogicLevel, AdiError> {
let value = bail_on!(PROS_ERR, unsafe {
pros_sys::ext_adi_digital_read(self.port.internal_expander_index(), self.port.index())
}) != 0;
Ok(match value {
true => LogicLevel::High,
false => LogicLevel::Low,
})
}
pub fn is_high(&self) -> Result<bool, AdiError> {
Ok(self.level()?.is_high())
}
pub fn is_low(&self) -> Result<bool, AdiError> {
Ok(self.level()?.is_high())
}
}
impl AdiDevice for AdiDigitalIn {
type PortIndexOutput = u8;
fn port_index(&self) -> Self::PortIndexOutput {
self.port.index()
}
fn expander_port_index(&self) -> Option<u8> {
self.port.expander_index()
}
fn device_type(&self) -> AdiDeviceType {
AdiDeviceType::DigitalIn
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct AdiDigitalOut {
port: AdiPort,
}
impl AdiDigitalOut {
pub fn new(port: AdiPort) -> Result<Self, AdiError> {
bail_on!(PROS_ERR, unsafe {
pros_sys::ext_adi_port_set_config(
port.internal_expander_index(),
port.index(),
pros_sys::E_ADI_DIGITAL_OUT,
)
});
Ok(Self { port })
}
pub fn set_level(&mut self, level: LogicLevel) -> Result<(), AdiError> {
bail_on!(PROS_ERR, unsafe {
pros_sys::ext_adi_digital_write(
self.port.internal_expander_index(),
self.port.index(),
level.is_high(),
)
});
Ok(())
}
pub fn set_high(&mut self) -> Result<(), AdiError> {
self.set_level(LogicLevel::High)
}
pub fn set_low(&mut self) -> Result<(), AdiError> {
self.set_level(LogicLevel::Low)
}
}
impl AdiDevice for AdiDigitalOut {
type PortIndexOutput = u8;
fn port_index(&self) -> Self::PortIndexOutput {
self.port.index()
}
fn expander_port_index(&self) -> Option<u8> {
self.port.expander_index()
}
fn device_type(&self) -> AdiDeviceType {
AdiDeviceType::DigitalOut
}
}