capsules_extra/
dfrobot_rainfall_sensor.rs
1use core::cell::Cell;
12use kernel::hil::i2c::{self, I2CClient, I2CDevice};
13use kernel::hil::sensors::{RainFallClient, RainFallDriver};
14use kernel::hil::time::{Alarm, AlarmClient, ConvertTicks};
15use kernel::utilities::cells::{OptionalCell, TakeCell};
16use kernel::ErrorCode;
17
18pub const BUFFER_SIZE: usize = 4;
19
20const PID_REGISTER: u8 = 0x00;
21const TIME_RAINFALL_REGISTER: u8 = 0x0C;
22const RAIN_HOUR_REGISTER: u8 = 0x26;
23
24#[derive(Clone, Copy, PartialEq)]
25enum DeviceState {
26 Identify,
27 Normal,
28 StartRainFall(usize),
29 ContinueRainFall,
30 FinalRainFall,
31 Broken,
32}
33
34#[derive(Clone, Copy, PartialEq)]
35enum Operation {
36 None,
37 RainFall,
38}
39
40pub struct DFRobotRainFall<'a, A: Alarm<'a>, I: I2CDevice> {
41 buffer: TakeCell<'static, [u8]>,
42 i2c: &'a I,
43 rainfall_client: OptionalCell<&'a dyn RainFallClient>,
44 state: Cell<DeviceState>,
45 op: Cell<Operation>,
46 alarm: &'a A,
47}
48
49impl<'a, A: Alarm<'a>, I: I2CDevice> DFRobotRainFall<'a, A, I> {
50 pub fn new(i2c: &'a I, buffer: &'static mut [u8], alarm: &'a A) -> Self {
51 DFRobotRainFall {
52 buffer: TakeCell::new(buffer),
53 i2c,
54 rainfall_client: OptionalCell::empty(),
55 state: Cell::new(DeviceState::Identify),
56 op: Cell::new(Operation::None),
57 alarm,
58 }
59 }
60
61 pub fn startup(&self) {
62 self.buffer.take().map(|buffer| {
63 if self.state.get() == DeviceState::Identify {
64 buffer[0] = PID_REGISTER;
66 if let Err((_e, buf)) = self.i2c.write_read(buffer, 1, 4) {
67 self.buffer.replace(buf);
68 }
69 } else {
70 self.buffer.replace(buffer);
71 }
72 });
73 }
74}
75
76impl<'a, A: Alarm<'a>, I: I2CDevice> RainFallDriver<'a> for DFRobotRainFall<'a, A, I> {
77 fn set_client(&self, client: &'a dyn RainFallClient) {
78 self.rainfall_client.set(client);
79 }
80
81 fn read_rainfall(&self, hours: usize) -> Result<(), ErrorCode> {
82 if self.state.get() == DeviceState::Broken {
83 return Err(ErrorCode::NOSUPPORT);
84 }
85
86 if self.state.get() != DeviceState::Normal {
87 return Err(ErrorCode::BUSY);
88 }
89
90 if self.op.get() != Operation::None {
91 return Err(ErrorCode::BUSY);
92 }
93
94 self.buffer.take().map_or(Err(ErrorCode::BUSY), |buffer| {
95 buffer[0] = RAIN_HOUR_REGISTER;
96 buffer[1] = hours as u8;
97
98 self.op.set(Operation::RainFall);
99 self.state.set(DeviceState::StartRainFall(hours));
100 if let Err((e, buf)) = self.i2c.write(buffer, 2) {
101 self.buffer.replace(buf);
102 return Err(e.into());
103 }
104
105 Ok(())
106 })
107 }
108}
109
110impl<'a, A: Alarm<'a>, I: I2CDevice> I2CClient for DFRobotRainFall<'a, A, I> {
111 fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), i2c::Error>) {
112 if let Err(i2c_err) = status {
113 self.buffer.replace(buffer);
114
115 match self.op.get() {
116 Operation::None => (),
117 Operation::RainFall => {
118 self.op.set(Operation::None);
119
120 self.rainfall_client
121 .map(|client| client.callback(Err(i2c_err.into())));
122 }
123 }
124
125 return;
126 }
127
128 match self.state.get() {
129 DeviceState::Identify => {
130 let pid =
131 buffer[0] as u32 | (buffer[1] as u32) << 8 | ((buffer[3] as u32) & 0xC0) << 10;
132 let vid = buffer[2] as u16 | ((buffer[3] as u16) & 0x3F) << 8;
133
134 if vid != 0x3343 || pid != 0x100C0 {
135 self.buffer.replace(buffer);
136 self.state.set(DeviceState::Broken);
137 self.op.set(Operation::None);
138 return;
139 }
140
141 self.buffer.replace(buffer);
142 self.state.set(DeviceState::Normal);
143 self.op.set(Operation::None);
144 }
145 DeviceState::StartRainFall(_hours) => match self.op.get() {
146 Operation::None => (),
147 Operation::RainFall => {
148 self.state.set(DeviceState::ContinueRainFall);
149 buffer[0] = TIME_RAINFALL_REGISTER;
150 if let Err((e, buf)) = self.i2c.write(buffer, 1) {
151 self.buffer.replace(buf);
152 self.op.set(Operation::None);
153
154 self.rainfall_client
155 .map(|client| client.callback(Err(e.into())));
156 }
157 }
158 },
159 DeviceState::ContinueRainFall => match self.op.get() {
160 Operation::None => (),
161 Operation::RainFall => {
162 self.buffer.replace(buffer);
163 let delay = self.alarm.ticks_from_us(6400);
164 self.alarm.set_alarm(self.alarm.now(), delay);
165 }
166 },
167 DeviceState::FinalRainFall => match self.op.get() {
168 Operation::None => (),
169 Operation::RainFall => {
170 let rainfall = (buffer[0] as u32
171 | (buffer[1] as u32) << 8
172 | (buffer[2] as u32) << 16
173 | (buffer[3] as u32) << 24)
174 / 10;
175
176 self.state.set(DeviceState::Normal);
177 self.buffer.replace(buffer);
178 self.op.set(Operation::None);
179
180 self.rainfall_client
181 .map(|client| client.callback(Ok(rainfall as usize)));
182 }
183 },
184 DeviceState::Normal | DeviceState::Broken => {}
185 }
186 }
187}
188
189impl<'a, A: Alarm<'a>, I: I2CDevice> AlarmClient for DFRobotRainFall<'a, A, I> {
190 fn alarm(&self) {
191 match self.op.get() {
192 Operation::None => (),
193 Operation::RainFall => {
194 self.state.set(DeviceState::FinalRainFall);
195 self.buffer.take().map(|buffer| {
196 if let Err((e, buf)) = self.i2c.read(buffer, 4) {
197 self.buffer.replace(buf);
198 self.op.set(Operation::None);
199
200 self.rainfall_client
201 .map(|client| client.callback(Err(e.into())));
202 }
203 });
204 }
205 }
206 }
207}