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