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}