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