Add gpio to drivers singleton
diff --git a/src/gpio.rs b/src/gpio.rs
index d416632..e8e0373 100644
--- a/src/gpio.rs
+++ b/src/gpio.rs
@@ -1,9 +1,12 @@
+use crate::result::OtherError;
+use crate::result::TockError;
use crate::result::TockResult;
use crate::syscalls;
+use core::marker::PhantomData;
const DRIVER_NUMBER: usize = 0x00004;
-mod gpio_commands {
- pub const SUBSCRIBE_CALLBACK: usize = 0;
+mod command_nr {
+ pub const NUMBER_PINS: usize = 0;
pub const ENABLE_OUTPUT: usize = 1;
pub const SET_HIGH: usize = 2;
pub const SET_LOW: usize = 3;
@@ -15,6 +18,65 @@
pub const DISABLE: usize = 9;
}
+mod subscribe_nr {
+ pub const SUBSCRIBE_CALLBACK: usize = 0;
+}
+
+pub struct GpioDriver {
+ pub(crate) _unconstructible: (),
+}
+
+impl GpioDriver {
+ pub fn all_pins<'a>(&'a mut self) -> TockResult<GpioIter<'a>> {
+ let number = self.number_of_pins()?;
+ Ok(GpioIter {
+ curr_gpio: 0,
+ gpio_count: number,
+ phantom: PhantomData,
+ })
+ }
+
+ pub fn pin<'a>(&'a mut self, pin: usize) -> TockResult<GpioPinUnitialized<'a>> {
+ let number = self.number_of_pins()?;
+ if pin < number {
+ Ok(GpioPinUnitialized {
+ number: pin,
+ phantom: PhantomData,
+ })
+ } else {
+ Err(TockError::Other(OtherError::NotEnoughGpioPins))
+ }
+ }
+
+ fn number_of_pins(&self) -> TockResult<usize> {
+ syscalls::command(DRIVER_NUMBER, command_nr::NUMBER_PINS, 0, 0).map_err(Into::into)
+ }
+}
+
+#[derive(Copy, Clone)]
+pub struct GpioIter<'a> {
+ curr_gpio: usize,
+ gpio_count: usize,
+ phantom: PhantomData<&'a mut ()>,
+}
+
+impl<'a> Iterator for GpioIter<'a> {
+ type Item = GpioPinUnitialized<'a>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.curr_gpio < self.gpio_count {
+ let item = GpioPinUnitialized {
+ number: self.curr_gpio,
+ phantom: PhantomData,
+ };
+ self.curr_gpio += 1;
+ Some(item)
+ } else {
+ None
+ }
+ }
+}
+
pub enum InputMode {
PullUp,
PullDown,
@@ -47,27 +109,34 @@
}
}
-pub struct GpioPinUnitialized {
+pub struct GpioPinUnitialized<'a> {
number: usize,
+ phantom: PhantomData<&'a mut ()>,
}
-pub struct GpioPinWrite {
+pub struct GpioPinWrite<'a> {
number: usize,
+ phantom: PhantomData<&'a mut ()>,
}
-pub struct GpioPinRead {
+pub struct GpioPinRead<'a> {
number: usize,
+ phantom: PhantomData<&'a mut ()>,
}
-impl GpioPinUnitialized {
- pub fn new(number: usize) -> GpioPinUnitialized {
- GpioPinUnitialized { number }
+impl<'a> GpioPinUnitialized<'a> {
+ pub fn new(number: usize) -> GpioPinUnitialized<'a> {
+ GpioPinUnitialized {
+ number,
+ phantom: PhantomData,
+ }
}
- pub fn open_for_write(self) -> TockResult<GpioPinWrite> {
- syscalls::command(DRIVER_NUMBER, gpio_commands::ENABLE_OUTPUT, self.number, 0)?;
+ pub fn open_for_write(self) -> TockResult<GpioPinWrite<'a>> {
+ syscalls::command(DRIVER_NUMBER, command_nr::ENABLE_OUTPUT, self.number, 0)?;
Ok(GpioPinWrite {
number: self.number,
+ phantom: PhantomData,
})
}
@@ -75,85 +144,81 @@
self,
callback: Option<(extern "C" fn(usize, usize, usize, usize), IrqMode)>,
input_mode: InputMode,
- ) -> TockResult<GpioPinRead> {
+ ) -> TockResult<GpioPinRead<'a>> {
let (callback, irq_mode) = callback.unwrap_or((noop_callback, IrqMode::EitherEdge));
self.enable_input(input_mode)
.and_then(|pin| pin.subscribe_callback(callback))
- .and_then(|pin| pin.enable_callback(irq_mode))
+ .and_then(move |pin| pin.enable_callback(irq_mode))
}
fn subscribe_callback(
self,
callback: extern "C" fn(usize, usize, usize, usize),
- ) -> TockResult<GpioPinUnitialized> {
+ ) -> TockResult<GpioPinUnitialized<'a>> {
syscalls::subscribe_fn(
DRIVER_NUMBER,
- gpio_commands::SUBSCRIBE_CALLBACK,
+ subscribe_nr::SUBSCRIBE_CALLBACK,
callback,
self.number,
)?;
Ok(self)
}
- fn enable_input(self, mode: InputMode) -> TockResult<GpioPinUnitialized> {
+ fn enable_input(self, mode: InputMode) -> TockResult<GpioPinUnitialized<'a>> {
syscalls::command(
DRIVER_NUMBER,
- gpio_commands::ENABLE_INPUT,
+ command_nr::ENABLE_INPUT,
self.number,
mode.to_num(),
)?;
Ok(self)
}
- fn enable_callback(self, irq_mode: IrqMode) -> TockResult<GpioPinRead> {
+ fn enable_callback(self, irq_mode: IrqMode) -> TockResult<GpioPinRead<'a>> {
syscalls::command(
DRIVER_NUMBER,
- gpio_commands::ENABLE_INTERRUPT,
+ command_nr::ENABLE_INTERRUPT,
self.number,
irq_mode.to_num(),
)?;
Ok(GpioPinRead {
number: self.number,
+ phantom: PhantomData,
})
}
}
-impl GpioPinWrite {
- pub fn set_low(&self) -> TockResult<()> {
- syscalls::command(DRIVER_NUMBER, gpio_commands::SET_LOW, self.number, 0)?;
+impl<'a> GpioPinWrite<'a> {
+ pub fn set_low(&mut self) -> TockResult<()> {
+ syscalls::command(DRIVER_NUMBER, command_nr::SET_LOW, self.number, 0)?;
Ok(())
}
- pub fn set_high(&self) -> TockResult<()> {
- syscalls::command(DRIVER_NUMBER, gpio_commands::SET_HIGH, self.number, 0)?;
+ pub fn set_high(&mut self) -> TockResult<()> {
+ syscalls::command(DRIVER_NUMBER, command_nr::SET_HIGH, self.number, 0)?;
Ok(())
}
- pub fn toggle(&self) -> TockResult<()> {
- syscalls::command(DRIVER_NUMBER, gpio_commands::TOGGLE, self.number, 0)?;
+ pub fn toggle(&mut self) -> TockResult<()> {
+ syscalls::command(DRIVER_NUMBER, command_nr::TOGGLE, self.number, 0)?;
Ok(())
}
}
-impl GpioPinRead {
- pub fn read(&self) -> bool {
- syscalls::command(DRIVER_NUMBER, gpio_commands::READ, self.number, 0).ok() == Some(1)
+impl<'a> GpioPinRead<'a> {
+ pub fn read(&'a self) -> bool {
+ syscalls::command(DRIVER_NUMBER, command_nr::READ, self.number, 0).ok() == Some(1)
}
}
-impl Drop for GpioPinWrite {
+impl<'a> Drop for GpioPinWrite<'a> {
fn drop(&mut self) {
- let _ = syscalls::command(DRIVER_NUMBER, gpio_commands::DISABLE, self.number, 0);
+ let _ = syscalls::command(DRIVER_NUMBER, command_nr::DISABLE, self.number, 0);
}
}
-impl Drop for GpioPinRead {
+impl<'a> Drop for GpioPinRead<'a> {
fn drop(&mut self) {
- let _ = syscalls::command(
- DRIVER_NUMBER,
- gpio_commands::DISABLE_INTERRUPT,
- self.number,
- 0,
- );
- let _ = syscalls::command(DRIVER_NUMBER, gpio_commands::DISABLE, self.number, 0);
+ let _ = syscalls::command(DRIVER_NUMBER, command_nr::DISABLE_INTERRUPT, self.number, 0);
+ let _ = syscalls::command(DRIVER_NUMBER, command_nr::DISABLE, self.number, 0);
}
}