use crate::{
adi::AdiExpander,
bindings,
distance::DistanceSensor,
error::Error,
imu::InertialSensor,
motor::{Gearset, Motor, MotorError, MotorGroup},
rotation::{RotationSensor, RotationSensorError},
serial::Serial,
};
use core::convert::{TryFrom, TryInto};
pub struct SmartPort {
port: u8,
}
impl SmartPort {
pub unsafe fn new(port: u8) -> Self {
assert!(
(1..22).contains(&port),
"Cannot construct a smart port on port {}",
port
);
Self { port }
}
#[inline]
pub fn plugged_type(&self) -> DeviceType {
unsafe { smart_port_type(self.port) }
}
pub fn into_motor(self, gearset: Gearset, reverse: bool) -> Result<Motor, MotorError> {
(self, gearset, reverse).try_into()
}
pub fn into_serial(self, baudrate: i32) -> Result<Serial, Error> {
(self, baudrate).try_into()
}
pub fn into_expander(self) -> AdiExpander {
self.into()
}
pub fn into_distance(self) -> DistanceSensor {
self.into()
}
pub fn into_imu(self) -> InertialSensor {
self.into()
}
#[inline]
pub fn into_rotation(self, reversed: bool) -> Result<RotationSensor, RotationSensorError> {
(self, reversed).try_into()
}
}
impl TryFrom<(SmartPort, Gearset, bool)> for Motor {
type Error = MotorError;
fn try_from((port, gearset, reverse): (SmartPort, Gearset, bool)) -> Result<Self, Self::Error> {
unsafe { Self::new(port.port, gearset, reverse) }
}
}
impl<const N: usize> TryFrom<[(SmartPort, Gearset, bool); N]> for MotorGroup<N> {
type Error = MotorError;
fn try_from(value: [(SmartPort, Gearset, bool); N]) -> Result<Self, Self::Error> {
Ok(MotorGroup::new(value.try_map(Motor::try_from)?))
}
}
impl TryFrom<(SmartPort, i32)> for Serial {
type Error = Error;
fn try_from((port, baudrate): (SmartPort, i32)) -> Result<Self, Self::Error> {
unsafe { Self::new(port.port, baudrate) }
}
}
impl From<SmartPort> for AdiExpander {
fn from(port: SmartPort) -> Self {
unsafe { AdiExpander::new(port.port) }
}
}
impl From<SmartPort> for DistanceSensor {
fn from(port: SmartPort) -> Self {
unsafe { DistanceSensor::new(port.port) }
}
}
impl From<SmartPort> for InertialSensor {
fn from(port: SmartPort) -> Self {
unsafe { InertialSensor::new(port.port) }
}
}
impl TryFrom<(SmartPort, bool)> for RotationSensor {
type Error = RotationSensorError;
#[inline]
fn try_from((port, reversed): (SmartPort, bool)) -> Result<Self, Self::Error> {
unsafe { RotationSensor::new(port.port, reversed) }
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DeviceType {
None,
Motor,
Rotation,
Imu,
Distance,
Radio,
Vision,
Adi,
Optical,
Serial,
Undefined,
Unknown(u32),
}
impl From<bindings::v5_device_e_t> for DeviceType {
fn from(t: bindings::v5_device_e_t) -> Self {
match t {
bindings::v5_device_e_E_DEVICE_NONE => Self::None,
bindings::v5_device_e_E_DEVICE_MOTOR => Self::Motor,
bindings::v5_device_e_E_DEVICE_ROTATION => Self::Rotation,
bindings::v5_device_e_E_DEVICE_IMU => Self::Imu,
bindings::v5_device_e_E_DEVICE_DISTANCE => Self::Distance,
bindings::v5_device_e_E_DEVICE_RADIO => Self::Radio,
bindings::v5_device_e_E_DEVICE_VISION => Self::Vision,
bindings::v5_device_e_E_DEVICE_ADI => Self::Adi,
bindings::v5_device_e_E_DEVICE_OPTICAL => Self::Optical,
bindings::v5_device_e_E_DEVICE_GENERIC => Self::Serial,
bindings::v5_device_e_E_DEVICE_UNDEFINED => Self::Undefined,
_ => Self::Unknown(t),
}
}
}
pub unsafe fn smart_port_type(port: u8) -> DeviceType {
bindings::registry_get_plugged_type(port - 1).into()
}