vexide_devices/smart/
expander.rs

1//! ADI Expander
2//!
3//! The ADI expander (3-Wire Expander) API is very similar to that of [`Peripherals`](crate::peripherals::Peripherals);
4//! however, it can only give access to ADI ports.
5//! Unlike devices created from the ADI ports on the Brain,
6//! devices created through an ADI expander can error if their associated expander is not connected to the Brain.
7//!
8//! # Hardware Overview
9//!
10//! The ADI expander plugs into the Brain over a Smart Port and provides an additional eight ADI ports.
11//! Just like the builtin ADI ports, these ports update every 10ms.
12//!
13//! The ADI expander is 3 inches long and 1 inch wide, with a height of 0.8 inches.
14//! The 8 additional ports are located long side across from the Smart Port on the opposite side.
15//!
16//! According to the [BLRS wiki](https://wiki.purduesigbots.com/vex-electronics/vex-sensors/smart-port-sensors/3-wire-expander#behavior),
17//! the ADI expander is more prone to damage from electrostatic discharge than other devices.
18//!
19//! # Examples
20//!
21//! ```
22//! use vexide_devices::{smart::AdiExpander, adi::AdiAnalogIn, peripherals::Peripherals};
23//!
24//! let peripherals = Peripherals::take().unwrap();
25//!
26//! let expander = AdiExpander::new(peripherals.port_1);
27//! let analog_in = AdiAnalogIn::new(expander.adi_a);
28//!
29//! println!("Analog in voltage: {:?}", analog_in.voltage());
30//! ```
31
32use super::{SmartDevice, SmartDeviceType, SmartPort};
33use crate::adi::AdiPort;
34
35/// An ADI expander module plugged into a Smart Port.
36///
37/// ADI Expanders allow a Smart Port to be used as an "adapter" for eight additional ADI slots
38/// if all onboard [`AdiPort`]s are used.
39///
40/// This struct gives access to [`AdiPort`]s similarly to how [`Peripherals`](crate::peripherals::Peripherals) works. Ports may
41/// be partially moved out of this struct to create devices.
42#[derive(Debug, Eq, PartialEq)]
43pub struct AdiExpander {
44    /// ADI port A on the expander.
45    pub adi_a: AdiPort,
46    /// ADI port B on the expander.
47    pub adi_b: AdiPort,
48    /// ADI Port C on the expander.
49    pub adi_c: AdiPort,
50    /// ADI Port D on the expander.
51    pub adi_d: AdiPort,
52    /// ADI Port E on the expander.
53    pub adi_e: AdiPort,
54    /// ADI Port F on the expander.
55    pub adi_f: AdiPort,
56    /// ADI Port G on the expander.
57    pub adi_g: AdiPort,
58    /// ADI Port H on the expander.
59    pub adi_h: AdiPort,
60
61    port: SmartPort,
62}
63
64impl AdiExpander {
65    /// Creates a new expander from a [`SmartPort`].
66    ///
67    /// An ADI expander does not return port errors itself if it is unplugged. Any disconnect
68    /// handling is done by devices created from the ports on the expander.
69    ///
70    /// # Examples
71    ///
72    /// Creating an analog input from a port on the expander:
73    ///
74    /// ```
75    /// use vexide::prelude::*;
76    ///
77    /// #[vexide::main]
78    /// async fn main(peripherals: Peripherals) {
79    ///     let expander = AdiExpander::new(peripherals.port_1);
80    ///     let analog_in = AdiAnalogIn::new(expander.adi_a);
81    ///
82    ///     println!("Analog in voltage: {:?}", analog_in.voltage());
83    /// }
84    /// ```
85    #[must_use]
86    pub const fn new(port: SmartPort) -> Self {
87        unsafe {
88            Self {
89                adi_a: AdiPort::new(1, Some(port.number())),
90                adi_b: AdiPort::new(2, Some(port.number())),
91                adi_c: AdiPort::new(3, Some(port.number())),
92                adi_d: AdiPort::new(4, Some(port.number())),
93                adi_e: AdiPort::new(5, Some(port.number())),
94                adi_f: AdiPort::new(6, Some(port.number())),
95                adi_g: AdiPort::new(7, Some(port.number())),
96                adi_h: AdiPort::new(8, Some(port.number())),
97                port,
98            }
99        }
100    }
101}
102
103impl SmartDevice for AdiExpander {
104    fn port_number(&self) -> u8 {
105        self.port.number()
106    }
107
108    fn device_type(&self) -> SmartDeviceType {
109        SmartDeviceType::Adi
110    }
111}
112impl From<AdiExpander> for SmartPort {
113    fn from(device: AdiExpander) -> Self {
114        device.port
115    }
116}