1mod platform;
22pub use platform::*;
23
24mod gpio;
25pub use gpio::*;
26
27mod i2c;
28pub use i2c::*;
29
30mod pwm;
31pub use pwm::*;
32
33mod spi;
34pub use spi::*;
35
36pub use uart::*;
37mod uart;
38
39use thiserror::Error;
40
41use std::{
42 any::TypeId,
43 collections::HashSet,
44 io,
45 os::fd::RawFd,
46 path::PathBuf,
47 sync::{Arc, OnceLock},
48 time::Duration,
49};
50
51use parking_lot::Mutex;
52
53use wiringx_sys::{
54 pinMode, pinmode_t_PINMODE_INPUT, pinmode_t_PINMODE_OUTPUT, wiringXGC, wiringXSelectableFd,
55 wiringXSetup, wiringXValidGPIO,
56};
57
58static WIRINGX: OnceLock<WiringX> = OnceLock::new();
59
60type Hand<T> = Arc<Mutex<HashSet<T>>>;
62
63#[derive(Clone, Debug)]
71pub struct WiringX {
72 platform: Platform,
73 gpio_handles: Hand<i32>,
74 pwm_handles: Hand<i32>,
75 i2c_handles: Hand<(PathBuf, i32)>,
76 spi_handles: Hand<i32>,
77 uart_handles: Hand<PathBuf>,
78}
79
80impl WiringX {
81 pub fn new(platform: Platform) -> Result<&'static Self, WiringXError> {
86 let error = OnceLock::new();
87
88 let wiringx = WIRINGX.get_or_init(|| {
89 let result = unsafe { wiringXSetup(platform.as_c_addr(), None) };
90
91 if result != 0 {
92 error.get_or_init(|| "Failed to initialize WiringX");
93 };
94
95 WiringX {
96 platform,
97 gpio_handles: Mutex::new(HashSet::new()).into(),
98 pwm_handles: Mutex::new(HashSet::new()).into(),
99 i2c_handles: Mutex::new(HashSet::new()).into(),
100 spi_handles: Mutex::new(HashSet::new()).into(),
101 uart_handles: Mutex::new(HashSet::new()).into(),
102 }
103 });
104
105 if let Some(error) = error.get() {
106 Err(WiringXError::InitError(error.to_string()))
107 } else {
108 Ok(wiringx)
109 }
110 }
111
112 #[inline]
114 pub fn platform(&self) -> Platform {
115 self.platform
116 }
117
118 pub fn valid_gpio(&self, gpio_pin: i32) -> bool {
120 let result = unsafe { wiringXValidGPIO(gpio_pin) };
121
122 result == 0
123 }
124
125 pub fn selectable_fd(&self, gpio_pin: i32) -> Result<RawFd, WiringXError> {
127 if !self.valid_gpio(gpio_pin) {
128 return Err(WiringXError::InvalidPin);
129 }
130
131 let fd = unsafe { wiringXSelectableFd(gpio_pin) };
132 if fd < 0 {
133 Err(WiringXError::Io(io::Error::last_os_error()))
134 } else {
135 Ok(fd)
136 }
137 }
138
139 pub fn gpio_pin<State: 'static + Default>(
141 &self,
142 pin_number: i32,
143 ) -> Result<Pin<State>, WiringXError> {
144 if self.gpio_handles.lock().contains(&pin_number) {
145 return Err(WiringXError::PinUsed);
146 }
147
148 if !self.valid_gpio(pin_number) {
149 return Err(WiringXError::InvalidPin);
150 }
151
152 let type_id = TypeId::of::<State>();
153
154 if type_id == TypeId::of::<Input>() {
155 unsafe { pinMode(pin_number, pinmode_t_PINMODE_INPUT) }
156 } else if type_id == TypeId::of::<Output>() {
157 unsafe { pinMode(pin_number, pinmode_t_PINMODE_OUTPUT) }
158 } else {
159 return Err(WiringXError::InvalidStateType);
160 };
161
162 self.gpio_handles.lock().insert(pin_number);
163
164 Ok(Pin::new(pin_number, self.gpio_handles.clone()))
165 }
166
167 #[inline]
169 pub fn pwm_pin(
170 &self,
171 pin_number: i32,
172 period: Duration,
173 duty_cycle: f32,
174 polarity: Polarity,
175 ) -> Result<PwmPin, WiringXError> {
176 PwmPin::new(
177 pin_number,
178 self.pwm_handles.clone(),
179 period,
180 duty_cycle,
181 polarity,
182 )
183 }
184
185 #[inline]
187 pub fn setup_i2c(&self, dev: PathBuf, addr: i32) -> Result<I2C, WiringXError> {
188 I2C::new(dev, addr, self.i2c_handles.clone())
189 }
190
191 #[inline]
195 pub fn setup_spi(&self, channel: i32, speed: u32) -> Result<Spi, WiringXError> {
196 Spi::new(channel, speed as i32, self.spi_handles.clone())
197 }
198
199 #[inline]
201 pub fn setup_uart(&self, dev: PathBuf, config: SerialConfig) -> Result<Uart, WiringXError> {
202 Uart::new(dev, config, self.uart_handles.clone())
203 }
204}
205
206impl Drop for WiringX {
207 #[inline]
208 fn drop(&mut self) {
209 unsafe {
210 wiringXGC();
211 }
212 }
213}
214
215#[derive(Debug, Error)]
217pub enum WiringXError {
218 #[error("Failed to initialize wiringX: {0}")]
222 InitError(String),
223 #[error("An unexpected error occured: {0}")]
224 Other(String),
225 #[error("The given pin does not exist for this platform.")]
227 InvalidPin,
228 #[error("The given pin is already used. Pin instances can only exist once.")]
230 PinUsed,
231 #[error("A pin can not be created with generics other than `Input` or `Output`.")]
233 InvalidStateType,
234 #[error("The function you are trying to call is not supported on your platform.")]
236 Unsupported,
237 #[error("The provided UART config is not valid: {0}")]
239 InvalidUARTConfig(InvalidUARTConfig),
240 #[error("Failed to write value: Invalid argument")]
242 InvalidArgument,
243 #[error("IO error: {0}")]
245 Io(io::Error),
246}