blob: e69d5ee8c99b3e139a94868372897bd8d520d930 [file] [log] [blame]
Woytenb50a9872019-12-01 01:12:57 +01001use crate::callback::CallbackSubscription;
2use crate::callback::Consumer;
torfmasterd03f0f42019-12-27 14:08:18 +01003use crate::result::OtherError;
Woyten22bc2542019-11-15 23:18:40 +01004use crate::result::TockResult;
Woyten30fc95b2019-01-10 21:09:46 +01005use crate::syscalls;
torfmasterd03f0f42019-12-27 14:08:18 +01006use core::marker::PhantomData;
Philipp Vollmer714b3462018-01-07 19:12:00 +01007
Woyten9567d792018-02-04 00:11:39 +01008const DRIVER_NUMBER: usize = 0x00004;
Woytenb50a9872019-12-01 01:12:57 +01009
torfmasterd03f0f42019-12-27 14:08:18 +010010mod command_nr {
Woytenb50a9872019-12-01 01:12:57 +010011 pub const COUNT: usize = 0;
Woyten9567d792018-02-04 00:11:39 +010012 pub const ENABLE_OUTPUT: usize = 1;
13 pub const SET_HIGH: usize = 2;
14 pub const SET_LOW: usize = 3;
15 pub const TOGGLE: usize = 4;
16 pub const ENABLE_INPUT: usize = 5;
17 pub const READ: usize = 6;
18 pub const ENABLE_INTERRUPT: usize = 7;
19 pub const DISABLE_INTERRUPT: usize = 8;
20 pub const DISABLE: usize = 9;
Philipp Vollmer714b3462018-01-07 19:12:00 +010021}
22
torfmasterd03f0f42019-12-27 14:08:18 +010023mod subscribe_nr {
24 pub const SUBSCRIBE_CALLBACK: usize = 0;
25}
26
torfmaster97c5e722020-01-02 21:30:16 +010027#[non_exhaustive]
Woytenb50a9872019-12-01 01:12:57 +010028pub struct GpioDriverFactory;
torfmasterd03f0f42019-12-27 14:08:18 +010029
Woytenb50a9872019-12-01 01:12:57 +010030impl GpioDriverFactory {
31 pub fn init_driver(&mut self) -> TockResult<GpioDriver> {
32 let driver = GpioDriver {
33 num_gpios: syscalls::command(DRIVER_NUMBER, command_nr::COUNT, 0, 0)?,
34 lifetime: PhantomData,
35 };
36 Ok(driver)
37 }
38}
39
40pub struct GpioDriver<'a> {
41 num_gpios: usize,
42 lifetime: PhantomData<&'a ()>,
43}
44
45impl<'a> GpioDriver<'a> {
46 pub fn num_gpios(&self) -> usize {
47 self.num_gpios
torfmasterd03f0f42019-12-27 14:08:18 +010048 }
49
Woytenb50a9872019-12-01 01:12:57 +010050 pub fn gpios(&mut self) -> Gpios {
51 Gpios {
52 num_gpios: self.num_gpios(),
53 curr_gpio: 0,
54 lifetime: PhantomData,
torfmasterd03f0f42019-12-27 14:08:18 +010055 }
56 }
57
Woytenb50a9872019-12-01 01:12:57 +010058 pub fn subscribe<CB: Fn(usize, GpioState)>(
59 &self,
60 callback: &'a mut CB,
61 ) -> TockResult<CallbackSubscription> {
62 syscalls::subscribe::<GpioEventConsumer, _>(
63 DRIVER_NUMBER,
64 subscribe_nr::SUBSCRIBE_CALLBACK,
65 callback,
66 )
67 .map_err(Into::into)
torfmasterd03f0f42019-12-27 14:08:18 +010068 }
69}
70
Woytenb50a9872019-12-01 01:12:57 +010071struct GpioEventConsumer;
72
73impl<CB: Fn(usize, GpioState)> Consumer<CB> for GpioEventConsumer {
74 fn consume(callback: &mut CB, gpio_num: usize, gpio_state: usize, _: usize) {
75 let gpio_state = match gpio_state {
76 0 => GpioState::Low,
77 1 => GpioState::High,
78 _ => return,
79 };
80 callback(gpio_num, gpio_state);
81 }
torfmasterd03f0f42019-12-27 14:08:18 +010082}
83
Woytenb50a9872019-12-01 01:12:57 +010084#[derive(Copy, Clone, Debug, Eq, PartialEq)]
85pub enum GpioState {
86 Low,
87 High,
88}
89
90impl From<GpioState> for bool {
91 fn from(gpio_state: GpioState) -> Self {
92 match gpio_state {
93 GpioState::Low => false,
94 GpioState::High => true,
95 }
96 }
97}
98
99impl From<bool> for GpioState {
100 fn from(from_value: bool) -> Self {
101 if from_value {
102 GpioState::Low
103 } else {
104 GpioState::High
105 }
106 }
107}
108
109pub struct Gpios<'a> {
110 num_gpios: usize,
111 curr_gpio: usize,
112 lifetime: PhantomData<&'a ()>,
113}
114
115impl<'a> Iterator for Gpios<'a> {
116 type Item = Gpio<'a>;
torfmasterd03f0f42019-12-27 14:08:18 +0100117
118 fn next(&mut self) -> Option<Self::Item> {
Woytenb50a9872019-12-01 01:12:57 +0100119 if self.curr_gpio < self.num_gpios {
120 let item = Gpio {
121 gpio_num: self.curr_gpio,
122 lifetime: PhantomData,
torfmasterd03f0f42019-12-27 14:08:18 +0100123 };
124 self.curr_gpio += 1;
125 Some(item)
126 } else {
127 None
128 }
129 }
130}
131
Woytenb50a9872019-12-01 01:12:57 +0100132pub struct Gpio<'a> {
133 gpio_num: usize,
134 lifetime: PhantomData<&'a ()>,
Philipp Vollmer714b3462018-01-07 19:12:00 +0100135}
136
Woytenb50a9872019-12-01 01:12:57 +0100137impl<'a> Gpio<'a> {
138 pub fn enable_output(&mut self) -> TockResult<GpioWrite> {
139 syscalls::command(DRIVER_NUMBER, command_nr::ENABLE_OUTPUT, self.gpio_num, 0)?;
140 let gpio_write = GpioWrite {
141 gpio_num: self.gpio_num,
142 lifetime: PhantomData,
143 };
144 Ok(gpio_write)
Philipp Vollmer51948b02018-01-04 09:03:45 +0100145 }
Philipp Vollmer714b3462018-01-07 19:12:00 +0100146
Woytenb50a9872019-12-01 01:12:57 +0100147 pub fn enable_input(&mut self, resistor_mode: ResistorMode) -> TockResult<GpioRead> {
Woyten22bc2542019-11-15 23:18:40 +0100148 syscalls::command(
Woyten4f5bc412019-11-21 23:36:58 +0100149 DRIVER_NUMBER,
torfmasterd03f0f42019-12-27 14:08:18 +0100150 command_nr::ENABLE_INPUT,
Woytenb50a9872019-12-01 01:12:57 +0100151 self.gpio_num,
152 resistor_mode as usize,
Woyten22bc2542019-11-15 23:18:40 +0100153 )?;
Woytenb50a9872019-12-01 01:12:57 +0100154 let gpio_read = GpioRead {
155 gpio_num: self.gpio_num,
156 lifetime: PhantomData,
157 };
158 Ok(gpio_read)
159 }
160}
161
162pub struct GpioWrite<'a> {
163 gpio_num: usize,
164 lifetime: PhantomData<&'a ()>,
165}
166
167impl<'a> GpioWrite<'a> {
168 pub fn gpio_num(&self) -> usize {
169 self.gpio_num
Philipp Vollmer714b3462018-01-07 19:12:00 +0100170 }
171
Woytenb50a9872019-12-01 01:12:57 +0100172 pub fn set(&self, state: impl Into<GpioState>) -> TockResult<()> {
173 match state.into() {
174 GpioState::Low => self.set_low(),
175 GpioState::High => self.set_high(),
176 }
177 }
178
179 pub fn set_low(&self) -> TockResult<()> {
180 syscalls::command(DRIVER_NUMBER, command_nr::SET_LOW, self.gpio_num, 0)?;
181 Ok(())
182 }
183
184 pub fn set_high(&self) -> TockResult<()> {
185 syscalls::command(DRIVER_NUMBER, command_nr::SET_HIGH, self.gpio_num, 0)?;
186 Ok(())
187 }
188
189 pub fn toggle(&self) -> TockResult<()> {
190 syscalls::command(DRIVER_NUMBER, command_nr::TOGGLE, self.gpio_num, 0)?;
191 Ok(())
192 }
193}
194
195impl<'a> Drop for GpioWrite<'a> {
196 fn drop(&mut self) {
197 let _ = syscalls::command(DRIVER_NUMBER, command_nr::DISABLE, self.gpio_num, 0);
198 }
199}
200
201pub struct GpioRead<'a> {
202 gpio_num: usize,
203 lifetime: PhantomData<&'a ()>,
204}
205
206impl<'a> GpioRead<'a> {
207 pub fn gpio_num(&self) -> usize {
208 self.gpio_num
209 }
210
211 pub fn read(&self) -> TockResult<GpioState> {
212 let button_state = syscalls::command(DRIVER_NUMBER, command_nr::READ, self.gpio_num, 0)?;
213 match button_state {
214 0 => Ok(GpioState::Low),
215 1 => Ok(GpioState::High),
216 _ => Err(OtherError::GpioDriverInvalidState.into()),
217 }
218 }
219
220 pub fn enable_interrupt(&self, trigger_type: TriggerType) -> TockResult<()> {
Woyten22bc2542019-11-15 23:18:40 +0100221 syscalls::command(
Woyten4f5bc412019-11-21 23:36:58 +0100222 DRIVER_NUMBER,
torfmasterd03f0f42019-12-27 14:08:18 +0100223 command_nr::ENABLE_INTERRUPT,
Woytenb50a9872019-12-01 01:12:57 +0100224 self.gpio_num,
225 trigger_type as usize,
Woyten22bc2542019-11-15 23:18:40 +0100226 )?;
Woytenb50a9872019-12-01 01:12:57 +0100227 Ok(())
Philipp Vollmer714b3462018-01-07 19:12:00 +0100228 }
Philipp Vollmer51948b02018-01-04 09:03:45 +0100229
Woytenb50a9872019-12-01 01:12:57 +0100230 pub fn disable_interrupt(&self, trigger_type: TriggerType) -> TockResult<()> {
231 syscalls::command(
232 DRIVER_NUMBER,
233 command_nr::DISABLE_INTERRUPT,
234 self.gpio_num,
235 trigger_type as usize,
236 )?;
Woyten22bc2542019-11-15 23:18:40 +0100237 Ok(())
Philipp Vollmer714b3462018-01-07 19:12:00 +0100238 }
239}
240
Woytenb50a9872019-12-01 01:12:57 +0100241impl<'a> Drop for GpioRead<'a> {
Philipp Vollmer51948b02018-01-04 09:03:45 +0100242 fn drop(&mut self) {
Woytenb50a9872019-12-01 01:12:57 +0100243 let _ = syscalls::command(DRIVER_NUMBER, command_nr::DISABLE, self.gpio_num, 0);
Philipp Vollmer51948b02018-01-04 09:03:45 +0100244 }
245}
Philipp Vollmer714b3462018-01-07 19:12:00 +0100246
Woytenb50a9872019-12-01 01:12:57 +0100247#[derive(Copy, Clone, Debug, Eq, PartialEq)]
248pub enum ResistorMode {
249 PullNone = 0,
250 PullUp = 1,
251 PullDown = 2,
Philipp Vollmer714b3462018-01-07 19:12:00 +0100252}
253
Woytenb50a9872019-12-01 01:12:57 +0100254#[derive(Copy, Clone, Debug, Eq, PartialEq)]
255pub enum TriggerType {
256 EitherEdge = 0,
257 RisingEdge = 1,
258 FallingEdge = 2,
259}