capsules_extra/
moisture.rs1use core::cell::Cell;
48
49use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
50use kernel::hil;
51use kernel::syscall::{CommandReturn, SyscallDriver};
52use kernel::{ErrorCode, ProcessId};
53
54use capsules_core::driver;
56pub const DRIVER_NUM: usize = driver::NUM::Moisture as usize;
57
58#[derive(Clone, Copy, PartialEq)]
59enum MoistureCommand {
60    ReadMoisture,
61}
62
63#[derive(Default)]
64pub struct App {
65    subscribed: bool,
66}
67
68pub struct MoistureSensor<'a, H: hil::sensors::MoistureDriver<'a>> {
69    driver: &'a H,
70    apps: Grant<App, UpcallCount<1>, AllowRoCount<0>, AllowRwCount<0>>,
71    busy: Cell<bool>,
72}
73
74impl<'a, H: hil::sensors::MoistureDriver<'a>> MoistureSensor<'a, H> {
75    pub fn new(
76        driver: &'a H,
77        grant: Grant<App, UpcallCount<1>, AllowRoCount<0>, AllowRwCount<0>>,
78    ) -> MoistureSensor<'a, H> {
79        MoistureSensor {
80            driver,
81            apps: grant,
82            busy: Cell::new(false),
83        }
84    }
85
86    fn enqueue_command(
87        &self,
88        command: MoistureCommand,
89        _arg1: usize,
90        processid: ProcessId,
91    ) -> CommandReturn {
92        self.apps
93            .enter(processid, |app, _| {
94                app.subscribed = true;
95
96                if !self.busy.get() {
97                    self.busy.set(true);
98                    self.call_driver(command)
99                } else {
100                    CommandReturn::success()
101                }
102            })
103            .unwrap_or_else(|err| CommandReturn::failure(err.into()))
104    }
105
106    fn call_driver(&self, command: MoistureCommand) -> CommandReturn {
107        match command {
108            MoistureCommand::ReadMoisture => {
109                let ret = self.driver.read_moisture();
110                if ret.is_err() {
111                    self.busy.set(false);
112                }
113                ret.into()
114            }
115        }
116    }
117}
118
119impl<'a, H: hil::sensors::MoistureDriver<'a>> hil::sensors::MoistureClient
120    for MoistureSensor<'a, H>
121{
122    fn callback(&self, value: Result<usize, ErrorCode>) {
123        self.busy.set(false);
124
125        for cntr in self.apps.iter() {
126            cntr.enter(|app, upcalls| {
127                if app.subscribed {
128                    app.subscribed = false;
129                    match value {
130                        Ok(moisture_val) => upcalls
131                            .schedule_upcall(
132                                0,
133                                (kernel::errorcode::into_statuscode(Ok(())), moisture_val, 0),
134                            )
135                            .ok(),
136                        Err(e) => upcalls
137                            .schedule_upcall(0, (kernel::errorcode::into_statuscode(Err(e)), 0, 0))
138                            .ok(),
139                    };
140                }
141            });
142        }
143    }
144}
145
146impl<'a, H: hil::sensors::MoistureDriver<'a>> SyscallDriver for MoistureSensor<'a, H> {
147    fn command(
148        &self,
149        command_num: usize,
150        arg1: usize,
151        _: usize,
152        processid: ProcessId,
153    ) -> CommandReturn {
154        match command_num {
155            0 => CommandReturn::success(),
157
158            1 => self.enqueue_command(MoistureCommand::ReadMoisture, arg1, processid),
160
161            _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
162        }
163    }
164
165    fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
166        self.apps.enter(processid, |_, _| {})
167    }
168}