1#[cfg(feature = "std")]
2use core::sync::atomic::{AtomicU32, Ordering};
3#[cfg(feature = "std")]
4static REFCOUNT: AtomicU32 = AtomicU32::new(0);
5
6#[cfg(feature = "std")]
7use num_traits::ToPrimitive;
8
9#[cfg(feature = "std")]
10use super::*;
11
12#[cfg_attr(feature = "derive-rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
13#[derive(Debug, Copy, Clone, num_derive::FromPrimitive, num_derive::ToPrimitive)]
14#[repr(u32)]
15pub enum IoxPort {
16 PA = 0,
17 PB = 1,
18 PC = 2,
19 PD = 3,
20 PE = 4,
21 PF = 5,
22}
23
24#[cfg_attr(feature = "derive-rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
25#[derive(Debug)]
26#[repr(u32)]
27pub enum IoxFunction {
28 Gpio = 0b00,
29 AF1 = 0b01,
30 AF2 = 0b10,
31 AF3 = 0b11,
32}
33
34#[cfg_attr(feature = "derive-rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
35#[derive(Debug)]
36#[repr(u32)]
37pub enum IoxDriveStrength {
38 Drive2mA = 0b00,
39 Drive4mA = 0b01,
40 Drive8mA = 0b10,
41 Drive12mA = 0b11,
42}
43
44#[cfg_attr(feature = "derive-rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
45#[derive(Debug)]
46#[repr(u32)]
47pub enum IoxDir {
48 Input = 0,
49 Output = 1,
50}
51
52#[cfg_attr(feature = "derive-rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
53#[derive(Debug)]
54#[repr(u32)]
55pub enum IoxEnable {
56 Disable = 0,
57 Enable = 1,
58}
59
60#[cfg_attr(feature = "derive-rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
61#[derive(Debug, Copy, Clone, PartialEq, Eq)]
62#[repr(u32)]
63pub enum IoxValue {
64 Low = 0,
65 High = 1,
66}
67impl From<u32> for IoxValue {
69 fn from(value: u32) -> Self { if value == 0 { IoxValue::Low } else { IoxValue::High } }
70}
71
72pub trait IoSetup {
74 fn setup_pin(
75 &self,
76 port: IoxPort,
77 pin: u8,
78 direction: Option<IoxDir>,
79 function: Option<IoxFunction>,
80 schmitt_trigger: Option<IoxEnable>,
81 pullup: Option<IoxEnable>,
82 slow_slew: Option<IoxEnable>,
83 strength: Option<IoxDriveStrength>,
84 );
85 fn set_bio_bit_from_port_and_pin(&self, port: IoxPort, pin: u8) -> Option<u8>;
86 fn set_ports_from_bio_bitmask(&self, enable_bitmask: u32, io_mode: crate::bio::IoConfigMode);
87}
88
89pub trait IoGpio {
91 fn set_gpio_pin_value(&self, port: IoxPort, pin: u8, value: IoxValue);
92 fn get_gpio_pin_value(&self, port: IoxPort, pin: u8) -> IoxValue;
93 fn set_gpio_pin_dir(&self, port: IoxPort, pin: u8, dir: IoxDir);
94}
95
96pub trait IoIrq {
97 fn set_irq_pin(&self, port: IoxPort, pin: u8, active: IoxValue, server: &str, opcode: usize);
102}
103
104#[cfg_attr(feature = "derive-rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
105#[derive(Debug)]
106pub struct IoxConfigMessage {
107 pub port: IoxPort,
108 pub pin: u8,
109 pub direction: Option<IoxDir>,
110 pub function: Option<IoxFunction>,
111 pub schmitt_trigger: Option<IoxEnable>,
112 pub pullup: Option<IoxEnable>,
113 pub slow_slew: Option<IoxEnable>,
114 pub strength: Option<IoxDriveStrength>,
115}
116
117#[cfg_attr(feature = "derive-rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
118#[derive(Debug)]
119#[cfg(feature = "std")]
120pub struct IoxIrqRegistration {
121 pub server: String,
122 pub opcode: usize,
123 pub port: IoxPort,
124 pub pin: u8,
125 pub active: IoxValue,
126}
127
128#[cfg(feature = "std")]
129pub struct IoxHal {
130 conn: xous::CID,
131}
132
133#[cfg(feature = "std")]
134impl IoxHal {
135 pub fn new() -> Self {
136 REFCOUNT.fetch_add(1, Ordering::Relaxed);
137 let xns = xous_names::XousNames::new().unwrap();
138 let conn =
139 xns.request_connection(SERVER_NAME_BAO1X_HAL).expect("Couldn't connect to bao1x HAL server");
140 IoxHal { conn }
141 }
142
143 pub fn set_gpio_pin_value(&self, port: IoxPort, pin: u8, value: IoxValue) {
144 xous::send_message(
145 self.conn,
146 xous::Message::new_blocking_scalar(
147 HalOpcode::SetGpioBank.to_usize().unwrap(),
148 port as usize,
149 (value as usize) << (pin as usize),
151 1 << pin as usize,
153 0,
154 ),
155 )
156 .expect("Couldn't set GPIO pin value");
157 }
158
159 pub fn set_gpio_bank_value(&self, port: IoxPort, value: u16, bitmask: u16) {
160 xous::send_message(
161 self.conn,
162 xous::Message::new_blocking_scalar(
163 HalOpcode::SetGpioBank.to_usize().unwrap(),
164 port as usize,
165 value as usize,
167 bitmask as usize,
169 0,
170 ),
171 )
172 .expect("Couldn't set GPIO pin value");
173 }
174
175 pub fn get_gpio_pin_value(&self, port: IoxPort, pin: u8) -> IoxValue {
176 match xous::send_message(
177 self.conn,
178 xous::Message::new_blocking_scalar(
179 HalOpcode::GetGpioBank.to_usize().unwrap(),
180 port as usize,
181 0,
182 0,
183 0,
184 ),
185 ) {
186 Ok(xous::Result::Scalar5(_, value, _, _, _)) => {
187 if value & (1 << pin as usize) != 0 {
188 IoxValue::High
189 } else {
190 IoxValue::Low
191 }
192 }
193 _ => panic!("Internal Error: Couldn't get GPIO pin value"),
194 }
195 }
196
197 pub fn get_gpio_bank_value(&self, port: IoxPort) -> u32 {
198 match xous::send_message(
199 self.conn,
200 xous::Message::new_blocking_scalar(
201 HalOpcode::GetGpioBank.to_usize().unwrap(),
202 port as usize,
203 0,
204 0,
205 0,
206 ),
207 ) {
208 Ok(xous::Result::Scalar5(_, value, _, _, _)) => value as u32,
209 _ => panic!("Internal Error: Couldn't get GPIO pin value"),
210 }
211 }
212
213 pub fn set_ports_from_bio_bitmask(&self, enable_bitmask: u32, io_mode: crate::bio::IoConfigMode) {
231 xous::send_message(
232 self.conn,
233 xous::Message::new_blocking_scalar(
234 HalOpcode::ConfigureBio.to_usize().unwrap(),
235 enable_bitmask as usize,
236 0,
237 1,
238 io_mode as usize,
239 ),
240 )
241 .expect("Internal error setting up BIO");
242 }
243
244 pub fn unset_bio_bit_from_port_and_pin(&self, _port: IoxPort, _pin: u8) -> Option<u8> {
248 todo!("Do this when we get around to filling in the BIO drivers")
249 }
250}
251
252#[cfg(feature = "std")]
253impl IoSetup for IoxHal {
254 fn setup_pin(
255 &self,
256 port: IoxPort,
257 pin: u8,
258 direction: Option<IoxDir>,
259 function: Option<IoxFunction>,
260 schmitt_trigger: Option<IoxEnable>,
261 pullup: Option<IoxEnable>,
262 slow_slew: Option<IoxEnable>,
263 strength: Option<IoxDriveStrength>,
264 ) {
265 let msg =
266 IoxConfigMessage { port, pin, direction, function, schmitt_trigger, pullup, slow_slew, strength };
267 let buf = xous_ipc::Buffer::into_buf(msg).unwrap();
268 buf.lend(self.conn, HalOpcode::ConfigureIox as u32).expect("Couldn't set up IO");
269 }
270
271 fn set_bio_bit_from_port_and_pin(&self, port: IoxPort, pin: u8) -> Option<u8> {
272 match xous::send_message(
273 self.conn,
274 xous::Message::new_blocking_scalar(
275 HalOpcode::ConfigureBio.to_usize().unwrap(),
276 port as usize,
277 pin as usize,
278 0,
279 0,
280 ),
281 ) {
282 Ok(xous::Result::Scalar5(_, code, ok, _, _)) => {
283 if ok != 0 {
284 Some(code as u8)
285 } else {
286 None
287 }
288 }
289 _ => panic!("Internal error setting up BIO"),
290 }
291 }
292
293 fn set_ports_from_bio_bitmask(&self, enable_bitmask: u32, io_mode: crate::bio::IoConfigMode) {
294 xous::send_message(
295 self.conn,
296 xous::Message::new_blocking_scalar(
297 HalOpcode::ConfigureBio.to_usize().unwrap(),
298 enable_bitmask as usize,
299 0,
300 1,
301 io_mode as usize,
302 ),
303 )
304 .expect("Internal error setting up BIO");
305 }
306}
307
308#[cfg(feature = "std")]
309impl IoGpio for IoxHal {
310 fn get_gpio_pin_value(&self, port: IoxPort, pin: u8) -> IoxValue { self.get_gpio_pin_value(port, pin) }
311
312 fn set_gpio_pin_dir(&self, port: IoxPort, pin: u8, dir: IoxDir) {
313 let msg = IoxConfigMessage {
314 port,
315 pin,
316 direction: Some(dir),
317 function: None,
318 schmitt_trigger: None,
319 pullup: None,
320 slow_slew: None,
321 strength: None,
322 };
323 let buf = xous_ipc::Buffer::into_buf(msg).unwrap();
324 buf.lend(self.conn, HalOpcode::ConfigureIox as u32).expect("Couldn't set up IO");
325 }
326
327 fn set_gpio_pin_value(&self, port: IoxPort, pin: u8, value: IoxValue) {
328 self.set_gpio_pin_value(port, pin, value);
329 }
330}
331
332#[cfg(feature = "std")]
333impl Drop for IoxHal {
334 fn drop(&mut self) {
335 if REFCOUNT.fetch_sub(1, Ordering::Relaxed) == 1 {
338 unsafe {
339 xous::disconnect(self.conn).ok();
340 }
341 }
342 }
343}
344
345#[cfg(feature = "std")]
346impl IoIrq for IoxHal {
347 fn set_irq_pin(&self, port: IoxPort, pin: u8, active: IoxValue, server: &str, opcode: usize) {
348 let msg = IoxIrqRegistration { server: server.to_owned(), opcode, port, pin, active };
349 let buf = xous_ipc::Buffer::into_buf(msg).unwrap();
350 buf.lend(self.conn, HalOpcode::ConfigureIoxIrq as u32).expect("Couldn't set up IRQ");
351 }
352}