capsules_extra/
chirp_i2c_moisture.rs
1use core::cell::Cell;
12use kernel::hil::i2c::{self, I2CClient, I2CDevice};
13use kernel::hil::sensors::{MoistureClient, MoistureDriver};
14use kernel::utilities::cells::{OptionalCell, TakeCell};
15use kernel::ErrorCode;
16
17pub const BUFFER_SIZE: usize = 2;
18
19const GET_CAPACITANCE: u8 = 0x00;
20#[allow(dead_code)]
21const SET_ADDRESS: u8 = 0x01;
22#[allow(dead_code)]
23const GET_ADDRESS: u8 = 0x02;
24#[allow(dead_code)]
25const MEASURE_LIGHT: u8 = 0x03;
26#[allow(dead_code)]
27const GET_LIGHT: u8 = 0x04;
28#[allow(dead_code)]
29const GET_TEMPERATURE: u8 = 0x05;
30#[allow(dead_code)]
31const RESET: u8 = 0x06;
32#[allow(dead_code)]
33const GET_VERSION: u8 = 0x07;
34#[allow(dead_code)]
35const SLEEP: u8 = 0x08;
36#[allow(dead_code)]
37const GET_BUSY: u8 = 0x09;
38
39#[derive(Clone, Copy, PartialEq)]
40enum DeviceState {
41 Normal,
42 StartMoisture,
43 FinalMoisture,
44}
45
46#[allow(dead_code)]
47#[derive(Clone, Copy, PartialEq)]
48enum Operation {
49 None,
50 Moisture,
51}
52
53pub struct ChirpI2cMoisture<'a, I: I2CDevice> {
54 buffer: TakeCell<'static, [u8]>,
55 i2c: &'a I,
56 moisture_client: OptionalCell<&'a dyn MoistureClient>,
57 state: Cell<DeviceState>,
58 op: Cell<Operation>,
59}
60
61impl<'a, I: I2CDevice> ChirpI2cMoisture<'a, I> {
62 pub fn new(i2c: &'a I, buffer: &'static mut [u8]) -> Self {
63 ChirpI2cMoisture {
64 buffer: TakeCell::new(buffer),
65 i2c,
66 moisture_client: OptionalCell::empty(),
67 state: Cell::new(DeviceState::Normal),
68 op: Cell::new(Operation::None),
69 }
70 }
71}
72
73impl<'a, I: I2CDevice> MoistureDriver<'a> for ChirpI2cMoisture<'a, I> {
74 fn set_client(&self, client: &'a dyn MoistureClient) {
75 self.moisture_client.set(client);
76 }
77
78 fn read_moisture(&self) -> Result<(), ErrorCode> {
79 if self.state.get() != DeviceState::Normal {
80 return Err(ErrorCode::BUSY);
81 }
82
83 if self.op.get() != Operation::None {
84 return Err(ErrorCode::BUSY);
85 }
86
87 self.buffer.take().map_or(Err(ErrorCode::BUSY), |buffer| {
88 buffer[0] = GET_CAPACITANCE;
89
90 self.op.set(Operation::Moisture);
91 self.state.set(DeviceState::StartMoisture);
92 if let Err((e, buf)) = self.i2c.write_read(buffer, 1, 2) {
93 self.buffer.replace(buf);
94 return Err(e.into());
95 }
96
97 Ok(())
98 })
99 }
100}
101
102impl<I: I2CDevice> I2CClient for ChirpI2cMoisture<'_, I> {
103 fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), i2c::Error>) {
104 if let Err(i2c_err) = status {
105 self.buffer.replace(buffer);
106
107 match self.op.get() {
108 Operation::None => (),
109 Operation::Moisture => {
110 self.op.set(Operation::None);
111
112 self.moisture_client
113 .map(|client| client.callback(Err(i2c_err.into())));
114 }
115 }
116
117 return;
118 }
119
120 match self.state.get() {
121 DeviceState::StartMoisture => match self.op.get() {
122 Operation::None => (),
123 Operation::Moisture => {
124 self.state.set(DeviceState::FinalMoisture);
125 buffer[0] = GET_CAPACITANCE;
126 if let Err((e, buf)) = self.i2c.write_read(buffer, 1, 2) {
127 self.buffer.replace(buf);
128 self.op.set(Operation::None);
129
130 self.moisture_client
131 .map(|client| client.callback(Err(e.into())));
132 }
133 }
134 },
135 DeviceState::FinalMoisture => {
136 match self.op.get() {
137 Operation::None => (),
138 Operation::Moisture => {
139 let capacitance = (((buffer[0] as u32) << 8) | (buffer[1] as u32)) as f32;
140
141 let moisture_content = ((capacitance - 240.0) / (400.0 - 240.0)) * 10000.0;
147
148 self.state.set(DeviceState::Normal);
149 self.buffer.replace(buffer);
150 self.op.set(Operation::None);
151
152 self.moisture_client
153 .map(|client| client.callback(Ok(moisture_content as usize)));
154 }
155 }
156 }
157 DeviceState::Normal => {}
158 }
159 }
160}