capsules_extra/
at24c_eeprom.rs1use core::cell::Cell;
46use core::cmp;
47
48use kernel::hil::i2c::{Error, I2CClient, I2CDevice};
49use kernel::utilities::cells::{OptionalCell, TakeCell};
50use kernel::{hil, ErrorCode};
51
52const PAGE_SIZE: usize = 32;
53
54pub struct EEPROMPage(pub [u8; PAGE_SIZE]);
55
56impl Default for EEPROMPage {
57 fn default() -> Self {
58 Self([0; PAGE_SIZE])
59 }
60}
61
62impl AsMut<[u8]> for EEPROMPage {
63 fn as_mut(&mut self) -> &mut [u8] {
64 &mut self.0
65 }
66}
67
68#[derive(Copy, Clone, Debug)]
69enum State {
70 Idle,
71 Reading,
72 Writing,
73 Erasing,
74}
75
76pub struct AT24C<'a> {
77 i2c: &'a dyn I2CDevice,
78 buffer: TakeCell<'static, [u8]>,
79 client_page: TakeCell<'a, EEPROMPage>,
80 flash_client: OptionalCell<&'a dyn hil::flash::Client<AT24C<'a>>>,
81 state: Cell<State>,
82}
83
84impl<'a> AT24C<'a> {
85 pub fn new(i2c: &'a dyn I2CDevice, buffer: &'static mut [u8]) -> Self {
86 Self {
87 i2c,
88 buffer: TakeCell::new(buffer),
89 client_page: TakeCell::empty(),
90 flash_client: OptionalCell::empty(),
91 state: Cell::new(State::Idle),
92 }
93 }
94
95 fn read_sector(
96 &self,
97 page_number: usize,
98 buf: &'static mut EEPROMPage,
99 ) -> Result<(), (ErrorCode, &'static mut EEPROMPage)> {
100 let address = page_number * PAGE_SIZE;
101 if let Some(rxbuffer) = self.buffer.take() {
102 rxbuffer[0] = ((address >> 8) & 0x00ff) as u8;
103 rxbuffer[1] = (address & 0x00ff) as u8;
104
105 self.i2c.enable();
106 self.state.set(State::Reading);
107 if let Err((error, local_buffer)) = self.i2c.write_read(rxbuffer, 2, PAGE_SIZE) {
108 self.buffer.replace(local_buffer);
109 self.i2c.disable();
110 Err((error.into(), buf))
111 } else {
112 self.client_page.replace(buf);
113 Ok(())
114 }
115 } else {
116 Err((ErrorCode::RESERVE, buf))
117 }
118 }
119
120 fn write_sector(
121 &self,
122 page_number: usize,
123 buf: &'static mut EEPROMPage,
124 ) -> Result<(), (ErrorCode, &'static mut EEPROMPage)> {
125 let address = page_number * PAGE_SIZE;
126 if let Some(txbuffer) = self.buffer.take() {
128 txbuffer[0] = ((address >> 8) & 0x00ff) as u8;
129 txbuffer[1] = (address & 0x00ff) as u8;
130
131 let write_len = cmp::min(txbuffer.len() - 2, buf.0.len());
132
133 txbuffer[2..(write_len + 2)].copy_from_slice(&buf.0[..write_len]);
134
135 self.i2c.enable();
136 self.state.set(State::Writing);
137 if let Err((error, txbuffer)) = self.i2c.write(txbuffer, write_len + 2) {
138 self.buffer.replace(txbuffer);
139 self.i2c.disable();
140 Err((error.into(), buf))
141 } else {
142 self.client_page.replace(buf);
143 Ok(())
144 }
145 } else {
146 Err((ErrorCode::RESERVE, buf))
147 }
148 }
149
150 fn erase_sector(&self, page_number: usize) -> Result<(), ErrorCode> {
151 let address = page_number * PAGE_SIZE;
152 if let Some(txbuffer) = self.buffer.take() {
154 txbuffer[0] = ((address >> 8) & 0x00ff) as u8;
155 txbuffer[1] = (address & 0x00ff) as u8;
156
157 let write_len = cmp::min(txbuffer.len() - 2, PAGE_SIZE);
158
159 for i in 0..write_len {
160 txbuffer[i + 2] = 0;
161 }
162
163 self.i2c.enable();
164 self.state.set(State::Erasing);
165 if let Err((error, txbuffer)) = self.i2c.write(txbuffer, write_len + 2) {
166 self.buffer.replace(txbuffer);
167 self.i2c.disable();
168 Err(error.into())
169 } else {
170 Ok(())
171 }
172 } else {
173 Err(ErrorCode::RESERVE)
174 }
175 }
176}
177
178impl I2CClient for AT24C<'static> {
179 fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), Error>) {
180 match self.state.get() {
181 State::Reading => {
182 self.state.set(State::Idle);
183 self.i2c.disable();
184 if let Some(client_page) = self.client_page.take() {
185 client_page.0[..PAGE_SIZE].copy_from_slice(&buffer[..PAGE_SIZE]);
186 self.buffer.replace(buffer);
187 self.flash_client.map(|client| {
188 if status.is_err() {
189 client.read_complete(client_page, Err(hil::flash::Error::FlashError));
190 } else {
191 client.read_complete(client_page, Ok(()));
192 }
193 });
194 }
195 }
196 State::Writing => {
197 self.state.set(State::Idle);
198 self.buffer.replace(buffer);
199 self.i2c.disable();
200 self.flash_client.map(|client| {
201 if let Some(client_page) = self.client_page.take() {
202 if status.is_err() {
203 client.write_complete(client_page, Err(hil::flash::Error::FlashError));
204 } else {
205 client.write_complete(client_page, Ok(()));
206 }
207 }
208 });
209 }
210 State::Erasing => {
211 self.state.set(State::Idle);
212 self.buffer.replace(buffer);
213 self.i2c.disable();
214 self.flash_client.map(move |client| {
215 if status.is_err() {
216 client.erase_complete(Err(hil::flash::Error::FlashError));
217 } else {
218 client.erase_complete(Ok(()));
219 }
220 });
221 }
222 State::Idle => {}
223 }
224 }
225}
226
227impl hil::flash::Flash for AT24C<'_> {
228 type Page = EEPROMPage;
229
230 fn read_page(
231 &self,
232 page_number: usize,
233 buf: &'static mut Self::Page,
234 ) -> Result<(), (ErrorCode, &'static mut Self::Page)> {
235 self.read_sector(page_number, buf)
236 }
237
238 fn write_page(
239 &self,
240 page_number: usize,
241 buf: &'static mut Self::Page,
242 ) -> Result<(), (ErrorCode, &'static mut Self::Page)> {
243 self.write_sector(page_number, buf)
244 }
245
246 fn erase_page(&self, page_number: usize) -> Result<(), ErrorCode> {
247 self.erase_sector(page_number)
248 }
249}
250
251impl<'a, C: hil::flash::Client<Self>> hil::flash::HasClient<'a, C> for AT24C<'a> {
252 fn set_client(&'a self, client: &'a C) {
253 self.flash_client.set(client);
254 }
255}