pros_devices/peripherals.rs
1//! Peripherals implementations.
2//!
3//! Peripherals are the best way to create devices because they allow you to do it safely.
4//! Both kinds of peripherals, [`Peripherals`] and [`DynamicPeripherals`], guarentee that a given port is only used to create one device.
5//! This is important because creating multiple devices on the same port can cause bugs and unexpected behavior.
6//! Devices can still be created unsafely without using peripherals, but it isn't recommended.
7//!
8//! ## Examples
9//!
10//! ### Using [`Peripherals`]
11//! ```rust
12//! # use pros::prelude::*;
13//! let mut peripherals = Peripherals::take().unwrap();
14//! let motor = Motor::new(peripherals.port_1);
15//! let adi_digital_in = AdiDigitalIn::new(peripherals.adi_d);
16//! ```
17//! ### Using [`DynamicPeripherals`]
18//! ```rust
19//! # use pros::prelude::*;
20//! let mut peripherals = DynamicPeripherals::new(Peripherals::take().unwrap());
21//! let motor = peripherals.take_smart_port(1).unwrap();
22//! let adi_digital_in = peripherals.take_adi_port(4).unwrap();
23//! ```
24
25use core::sync::atomic::AtomicBool;
26
27use crate::{adi::AdiPort, screen::Screen, smart::SmartPort};
28
29static PERIPHERALS_TAKEN: AtomicBool = AtomicBool::new(false);
30
31#[derive(Debug)]
32/// A struct that contains all ports on the V5 Brain
33/// and guarentees **at compile time** that each port is only used once.
34/// Because of the fact that this checks at compile time, it cannot be moved once it has been used to create a device.
35/// If you need to store a peripherals struct for use in multiple functions, use [`DynamicPeripherals`] instead.
36/// This struct is always preferred over [`DynamicPeripherals`] when possible.
37pub struct Peripherals {
38 /// Brain screen
39 pub screen: Screen,
40
41 /// Smart port 1 on the brain
42 pub port_1: SmartPort,
43 /// Smart port 2 on the brain
44 pub port_2: SmartPort,
45 /// Smart port 3 on the brain
46 pub port_3: SmartPort,
47 /// Smart port 4 on the brain
48 pub port_4: SmartPort,
49 /// Smart port 5 on the brain
50 pub port_5: SmartPort,
51 /// Smart port 6 on the brain
52 pub port_6: SmartPort,
53 /// Smart port 7 on the brain
54 pub port_7: SmartPort,
55 /// Smart port 8 on the brain
56 pub port_8: SmartPort,
57 /// Smart port 9 on the brain
58 pub port_9: SmartPort,
59 /// Smart port 10 on the brain
60 pub port_10: SmartPort,
61 /// Smart port 11 on the brain
62 pub port_11: SmartPort,
63 /// Smart port 12 on the brain
64 pub port_12: SmartPort,
65 /// Smart port 13 on the brain
66 pub port_13: SmartPort,
67 /// Smart port 14 on the brain
68 pub port_14: SmartPort,
69 /// Smart port 15 on the brain
70 pub port_15: SmartPort,
71 /// Smart port 16 on the brain
72 pub port_16: SmartPort,
73 /// Smart port 17 on the brain
74 pub port_17: SmartPort,
75 /// Smart port 18 on the brain
76 pub port_18: SmartPort,
77 /// Smart port 19 on the brain
78 pub port_19: SmartPort,
79 /// Smart port 20 on the brain
80 pub port_20: SmartPort,
81 /// Smart port 21 on the brain
82 pub port_21: SmartPort,
83
84 /// Adi port A on the brain.
85 pub adi_a: AdiPort,
86 /// Adi port B on the brain.
87 pub adi_b: AdiPort,
88 /// Adi port C on the brain.
89 pub adi_c: AdiPort,
90 /// Adi port D on the brain.
91 pub adi_d: AdiPort,
92 /// Adi port E on the brain.
93 pub adi_e: AdiPort,
94 /// Adi port F on the brain.
95 pub adi_f: AdiPort,
96 /// Adi port G on the brain.
97 pub adi_g: AdiPort,
98 /// Adi port H on the brain.
99 pub adi_h: AdiPort,
100}
101
102impl Peripherals {
103 // SAFETY: caller must ensure that the SmartPorts and AdiPorts created are unique
104 unsafe fn new() -> Self {
105 // SAFETY: caller must ensure that this function is only called once
106 unsafe {
107 Self {
108 screen: Screen::new(),
109
110 port_1: SmartPort::new(1),
111 port_2: SmartPort::new(2),
112 port_3: SmartPort::new(3),
113 port_4: SmartPort::new(4),
114 port_5: SmartPort::new(5),
115 port_6: SmartPort::new(6),
116 port_7: SmartPort::new(7),
117 port_8: SmartPort::new(8),
118 port_9: SmartPort::new(9),
119 port_10: SmartPort::new(10),
120 port_11: SmartPort::new(11),
121 port_12: SmartPort::new(12),
122 port_13: SmartPort::new(13),
123 port_14: SmartPort::new(14),
124 port_15: SmartPort::new(15),
125 port_16: SmartPort::new(16),
126 port_17: SmartPort::new(17),
127 port_18: SmartPort::new(18),
128 port_19: SmartPort::new(19),
129 port_20: SmartPort::new(20),
130 port_21: SmartPort::new(21),
131
132 adi_a: AdiPort::new(1, None),
133 adi_b: AdiPort::new(2, None),
134 adi_c: AdiPort::new(3, None),
135 adi_d: AdiPort::new(4, None),
136 adi_e: AdiPort::new(5, None),
137 adi_f: AdiPort::new(6, None),
138 adi_g: AdiPort::new(7, None),
139 adi_h: AdiPort::new(8, None),
140 }
141 }
142 }
143
144 /// Attempts to create a new [`Peripherals`] struct, returning `None` if one has already been created.
145 ///
146 /// After calling this function, future calls to [`Peripherals::take`] will return `None`.
147 pub fn take() -> Option<Self> {
148 if PERIPHERALS_TAKEN.swap(true, core::sync::atomic::Ordering::AcqRel) {
149 None
150 } else {
151 Some(unsafe { Self::new() })
152 }
153 }
154
155 /// Creates a new [`Peripherals`] struct without ensuring that is the only unique instance.
156 ///
157 /// After calling this function, future calls to [`Peripherals::take`] will return `None`.
158 ///
159 /// # Safety
160 ///
161 /// Creating new [`SmartPort`]s and [`Peripherals`] instances is inherently unsafe due to the possibility of constructing more than
162 /// one device on the same port index and allowing multiple mutable references to the same hardware device.
163 /// The caller must ensure that only one mutable reference to each port is used.
164 pub unsafe fn steal() -> Self {
165 PERIPHERALS_TAKEN.store(true, core::sync::atomic::Ordering::Release);
166 // SAFETY: caller must ensure that this call is safe
167 unsafe { Self::new() }
168 }
169}
170
171/// Guarentees that ports are only used once **at runtime**
172/// This is useful for when you want to store a peripherals struct for use in multiple functions.
173/// When possible, use [`Peripherals`] instead.
174#[derive(Debug)]
175pub struct DynamicPeripherals {
176 screen: bool,
177 smart_ports: [bool; 21],
178 adi_slots: [bool; 8],
179}
180impl DynamicPeripherals {
181 /// Creates a new dynamic peripherals
182 /// In order to guarentee that no ports created by this struct,
183 /// this function takes a [`Peripherals`].
184 /// This guarentees safety because [`Peripherals`] cannot be passed by value
185 /// after they have been used to create devices.
186 pub fn new(_peripherals: Peripherals) -> Self {
187 let smart_ports = [false; 21];
188 let adi_slots = [false; 8];
189 Self {
190 screen: false,
191 smart_ports,
192 adi_slots,
193 }
194 }
195
196 /// Creates a [`SmartPort`] only if one has not been created on the given port before.
197 ///
198 /// # Panics
199 ///
200 /// This function panics if the provided port is outside the range 1-21.
201 /// Ports outside of this range are invalid and cannot be created.
202 pub fn take_smart_port(&mut self, port_index: u8) -> Option<SmartPort> {
203 let port_index = port_index as usize - 1;
204 if self.smart_ports[port_index] {
205 return None;
206 };
207 self.smart_ports[port_index] = true;
208 Some(unsafe { SmartPort::new(port_index as u8 + 1) })
209 }
210
211 /// Creates an [`AdiPort`] only if one has not been created on the given slot before.
212 ///
213 /// # Panics
214 ///
215 /// This function panics if the provided port is outside the range 1-8.
216 /// Slots outside of this range are invalid and cannot be created.
217 pub fn take_adi_port(&mut self, port_index: u8) -> Option<AdiPort> {
218 let port_index = port_index as usize - 1;
219 if self.adi_slots[port_index] {
220 return None;
221 }
222 self.smart_ports[port_index] = true;
223 Some(unsafe { AdiPort::new(port_index as u8 + 1, None) })
224 }
225
226 /// Creates a [`Screen`] only if one has not been created before.
227 pub fn take_screen(&mut self) -> Option<Screen> {
228 if self.screen {
229 return None;
230 }
231 self.screen = true;
232 Some(unsafe { Screen::new() })
233 }
234}
235impl From<Peripherals> for DynamicPeripherals {
236 fn from(peripherals: Peripherals) -> Self {
237 Self::new(peripherals)
238 }
239}