1pub mod comm;
4pub mod gpio;
5pub mod rt;
6
7#[cfg(not(test))]
8use std::sync::OnceLock;
9#[allow(unused_imports)]
10use std::{cell::RefCell, mem::size_of};
11
12use self::{
13 gpio::SimGPIODriver,
14 rt::{
15 station_interface::{StationInterfaceDriver, StationInterfaceVTable},
16 watchdog::SimWatchdogDriver,
17 },
18};
19#[allow(unused_imports)]
20use self::{
21 gpio::{GPIODriver, GPIOVTable},
22 rt::{
23 notifier::{NotifierDriver, NotifierVTable},
24 time::{initialize_time_callbacks, ClockDriver},
25 watchdog::{WatchdogDriver, WatchdogVTable},
26 },
27};
28
29#[cfg(not(test))]
30static HAL_INSTANCE: OnceLock<HAL> = OnceLock::new();
31
32#[cfg(test)]
33thread_local! {
34 static HAL_INSTANCE_LOCAL: RefCell<Option<HAL>> = const { RefCell::new(None) };
35}
36
37pub trait HALDriver:
40 GPIODriver
41 + ClockDriver
42 + NotifierDriver
43 + WatchdogDriver
44 + StationInterfaceDriver
45 + 'static {
52 const NAME: &'static str;
54
55 fn init();
58
59 fn cleanup();
63}
64
65pub trait SimHALDriver: HALDriver + SimGPIODriver + SimWatchdogDriver {}
71
72#[allow(clippy::upper_case_acronyms)]
79#[derive(Debug, Clone, Copy)]
80pub struct HAL {
81 driver_name: &'static str,
82 cleanup: fn(),
83 gpio: GPIOVTable,
84 notifier: NotifierVTable,
85 watchdog: WatchdogVTable,
86 station_interface: StationInterfaceVTable,
87}
88
89impl HAL {
90 pub fn init<Driver: HALDriver>() {
96 assert!(size_of::<Driver>() == 0, "Driver must be zero sized");
97 Driver::init();
98 initialize_time_callbacks::<Driver>(Driver::NAME);
99 Self {
100 driver_name: Driver::NAME,
101 cleanup: Driver::cleanup,
102 gpio: GPIOVTable::from_driver::<Driver>(),
103 notifier: NotifierVTable::from_driver::<Driver>(),
104 watchdog: WatchdogVTable::from_driver::<Driver>(),
105 station_interface: StationInterfaceVTable::from_driver::<Driver>(),
106 }
107 .set_hal();
108 }
109
110 pub fn init_sim<Driver: SimHALDriver>() {
116 assert!(size_of::<Driver>() == 0, "Driver must be zero sized");
117 Driver::init();
118 #[cfg(not(test))]
119 initialize_time_callbacks::<Driver>(Driver::NAME);
120 Self {
121 driver_name: Driver::NAME,
122 cleanup: Driver::cleanup,
123 gpio: GPIOVTable::from_sim_driver::<Driver>(),
124 notifier: NotifierVTable::from_driver::<Driver>(),
125 watchdog: WatchdogVTable::from_sim_driver::<Driver>(),
126 station_interface: StationInterfaceVTable::from_driver::<Driver>(),
127 }
128 .set_hal();
129 }
130
131 fn set_hal(self) {
132 #[cfg(not(test))]
133 {
134 assert!(
135 HAL_INSTANCE.get().is_none(),
136 "HAL has already been initialized"
137 );
138 let _ = HAL_INSTANCE.set(self);
139 }
140 #[cfg(test)]
141 {
142 assert!(
143 HAL_INSTANCE_LOCAL.with(|inst| inst.borrow().is_none()),
144 "HAL has already been initialized"
145 );
146 HAL_INSTANCE_LOCAL.with(|local_hal_instance| {
147 *local_hal_instance.borrow_mut() = Some(self);
148 });
149 }
150 }
151
152 pub fn cleanup(&self) {
154 (self.cleanup)();
155 }
156
157 #[must_use]
159 pub const fn driver_name(&self) -> &'static str {
160 self.driver_name
161 }
162
163 #[must_use]
165 pub const fn notifier_api(&self) -> NotifierVTable {
166 self.notifier
167 }
168
169 #[must_use]
171 pub const fn watchdog_api(&self) -> WatchdogVTable {
172 self.watchdog
173 }
174
175 #[must_use]
177 pub const fn gpio_api(&self) -> GPIOVTable {
178 self.gpio
179 }
180
181 #[must_use]
183 pub const fn station_interface_api(&self) -> StationInterfaceVTable {
184 self.station_interface
185 }
186}
187
188pub fn get_hal() -> Result<HAL, HALNotInitializedError> {
193 #[cfg(not(test))]
194 {
195 HAL_INSTANCE.get().copied().ok_or(HALNotInitializedError)
196 }
197 #[cfg(test)]
198 {
199 HAL_INSTANCE_LOCAL
200 .with(|local_hal_instance| *local_hal_instance.borrow())
201 .ok_or(HALNotInitializedError)
202 }
203}
204
205#[derive(Debug, Clone, Copy, PartialEq, Eq)]
208pub struct NotSimError;
209impl std::fmt::Display for NotSimError {
210 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211 write!(
212 f,
213 "This function is only available when the HAL is initialized with sim support"
214 )
215 }
216}
217impl std::error::Error for NotSimError {}
218
219#[derive(Debug, Clone, Copy, PartialEq, Eq)]
221pub struct HALNotInitializedError;
222impl std::fmt::Display for HALNotInitializedError {
223 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
224 write!(f, "`HAL` has not been initialized")
225 }
226}
227impl std::error::Error for HALNotInitializedError {}
228
229