1use crate::{addr_size, page_size, private, unique_serial, Eeprom24x, Error, SlaveAddr};
2use core::marker::PhantomData;
3use embedded_hal::i2c::I2c;
4pub trait MultiSizeAddr: private::Sealed {
5 const ADDRESS_BYTES: usize;
6
7 fn fill_address(address: u32, payload: &mut [u8]);
8}
9
10impl MultiSizeAddr for addr_size::OneByte {
11 const ADDRESS_BYTES: usize = 1;
12
13 fn fill_address(address: u32, payload: &mut [u8]) {
14 payload[0] = address as u8;
15 }
16}
17
18impl MultiSizeAddr for addr_size::TwoBytes {
19 const ADDRESS_BYTES: usize = 2;
20
21 fn fill_address(address: u32, payload: &mut [u8]) {
22 payload[0] = (address >> 8) as u8;
23 payload[1] = address as u8;
24 }
25}
26
27impl<I2C, PS, AS, SN> Eeprom24x<I2C, PS, AS, SN> {
29 pub fn destroy(self) -> I2C {
31 self.i2c
32 }
33}
34
35impl<I2C, PS, AS, SN> Eeprom24x<I2C, PS, AS, SN>
36where
37 AS: MultiSizeAddr,
38{
39 fn get_device_address<E>(&self, memory_address: u32) -> Result<u8, Error<E>> {
40 if memory_address >= (1 << self.address_bits) {
41 return Err(Error::InvalidAddr);
42 }
43 let addr = self.address.devaddr(
44 memory_address,
45 self.address_bits,
46 AS::ADDRESS_BYTES as u8 * 8,
47 );
48 Ok(addr)
49 }
50}
51
52impl<I2C, E, PS, AS, SN> Eeprom24x<I2C, PS, AS, SN>
54where
55 I2C: I2c<Error = E>,
56 AS: MultiSizeAddr,
57{
58 pub fn write_byte(&mut self, address: u32, data: u8) -> Result<(), Error<E>> {
65 let devaddr = self.get_device_address(address)?;
66 let mut payload = [0; 3];
67 AS::fill_address(address, &mut payload);
68 payload[AS::ADDRESS_BYTES] = data;
69 self.i2c
70 .write(devaddr, &payload[..=AS::ADDRESS_BYTES])
71 .map_err(Error::I2C)
72 }
73
74 pub fn read_byte(&mut self, address: u32) -> Result<u8, Error<E>> {
76 let devaddr = self.get_device_address(address)?;
77 let mut memaddr = [0; 2];
78 AS::fill_address(address, &mut memaddr);
79 let mut data = [0; 1];
80 self.i2c
81 .write_read(devaddr, &memaddr[..AS::ADDRESS_BYTES], &mut data)
82 .map_err(Error::I2C)
83 .and(Ok(data[0]))
84 }
85
86 pub fn read_data(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error<E>> {
88 let devaddr = self.get_device_address(address)?;
89 let mut memaddr = [0; 2];
90 AS::fill_address(address, &mut memaddr);
91 self.i2c
92 .write_read(devaddr, &memaddr[..AS::ADDRESS_BYTES], data)
93 .map_err(Error::I2C)
94 }
95}
96
97impl<I2C, E, PS, AS, SN> Eeprom24x<I2C, PS, AS, SN>
99where
100 I2C: I2c<Error = E>,
101{
102 pub fn read_current_address(&mut self) -> Result<u8, Error<E>> {
107 let mut data = [0];
108 self.i2c
109 .read(self.address.addr(), &mut data)
110 .map_err(Error::I2C)
111 .and(Ok(data[0]))
112 }
113}
114
115impl<I2C, E> Eeprom24x<I2C, page_size::No, addr_size::OneByte, unique_serial::No>
117where
118 I2C: I2c<Error = E>,
119{
120 pub fn new_24x00(i2c: I2C, address: SlaveAddr) -> Self {
122 Eeprom24x {
123 i2c,
124 address,
125 address_bits: 4,
126 _ps: PhantomData,
127 _as: PhantomData,
128 _sn: PhantomData,
129 }
130 }
131}
132
133macro_rules! impl_create {
134 ( $dev:expr, $part:expr, $address_bits:expr, $create:ident ) => {
135 impl_create! {
136 @gen [$create, $address_bits,
137 concat!("Create a new instance of a ", $dev, " device (e.g. ", $part, ")")]
138 }
139 };
140
141 (@gen [$create:ident, $address_bits:expr, $doc:expr] ) => {
142 #[doc = $doc]
143 pub fn $create(i2c: I2C, address: SlaveAddr) -> Self {
144 Self::new(i2c, address, $address_bits)
145 }
146 };
147}
148
149macro_rules! impl_for_page_size {
151 ( $AS:ident, $addr_bytes:expr, $PS:ident, $page_size:expr,
152 $( [ $dev:expr, $part:expr, $address_bits:expr, $SN:ident, $create:ident ] ),* ) => {
153 impl_for_page_size!{
154 @gen [$AS, $addr_bytes, $PS, $page_size,
155 concat!("Specialization for devices with a page size of ", stringify!($page_size), " bytes."),
156 concat!("Create generic instance for devices with a page size of ", stringify!($page_size), " bytes."),
157 $( [ $dev, $part, $address_bits, $SN, $create ] ),* ]
158 }
159 };
160
161 (@gen [$AS:ident, $addr_bytes:expr, $PS:ident, $page_size:expr, $doc_impl:expr, $doc_new:expr,
162 $( [ $dev:expr, $part:expr, $address_bits:expr, $SN:ident, $create:ident ] ),* ] ) => {
163
164 $(
165 impl<I2C, E> Eeprom24x<I2C, page_size::$PS, addr_size::$AS, unique_serial::$SN>
166 where
167 I2C: I2c<Error = E>
168 {
169 impl_create!($dev, $part, $address_bits, $create);
170 }
171 )*
172
173 #[doc = $doc_impl]
174 impl<I2C, E, SN> Eeprom24x<I2C, page_size::$PS, addr_size::$AS, SN>
175 where
176 I2C: I2c<Error = E>
177 {
178 #[doc = $doc_new]
179 fn new(i2c: I2C, address: SlaveAddr, address_bits: u8) -> Self {
180 Eeprom24x {
181 i2c,
182 address,
183 address_bits,
184 _ps: PhantomData,
185 _as: PhantomData,
186 _sn: PhantomData,
187 }
188 }
189 }
190
191 impl<I2C, E, AS, SN> Eeprom24x<I2C, page_size::$PS, AS, SN>
192 where
193 I2C: I2c<Error = E>,
194 AS: MultiSizeAddr,
195 {
196 pub fn write_page(&mut self, address: u32, data: &[u8]) -> Result<(), Error<E>> {
207 if data.len() == 0 {
208 return Ok(());
209 }
210
211 if data.len() > $page_size {
214 return Err(Error::TooMuchData);
217 }
218
219 let page_boundary = address | ($page_size as u32 - 1);
220 if address + data.len() as u32 > page_boundary + 1 {
221 return Err(Error::TooMuchData);
224 }
225
226 let devaddr = self.get_device_address(address)?;
227 let mut payload: [u8; $addr_bytes + $page_size] = [0; $addr_bytes + $page_size];
228 AS::fill_address(address, &mut payload);
229 payload[$addr_bytes..$addr_bytes + data.len()].copy_from_slice(&data);
231 self.i2c
233 .write(devaddr, &payload[..$addr_bytes + data.len()])
234 .map_err(Error::I2C)
235 }
236 }
237
238 impl<I2C, E, AS, SN> PageWrite<E> for Eeprom24x<I2C, page_size::$PS, AS, SN>
239 where
240 I2C: I2c<Error = E>,
241 AS: MultiSizeAddr,
242 {
243 fn page_write(&mut self, address: u32, data: &[u8]) -> Result<(), Error<E>> {
244 self.write_page(address, data)
245 }
246
247 fn page_size(&self) -> usize {
248 $page_size
249 }
250 }
251
252 impl<I2C, E, AS, SN> crate::Eeprom24xTrait for Eeprom24x<I2C, page_size::$PS, AS, SN>
253 where
254 I2C: I2c<Error = E>,
255 AS: MultiSizeAddr
256 {
257 type Error = E;
258
259 fn write_byte(&mut self, address: u32, data: u8) -> Result<(), Error<Self::Error>>
260 {
261 self.write_byte(address, data)
262 }
263
264 fn read_byte(&mut self, address: u32) -> Result<u8, Error<Self::Error>>
265 {
266 self.read_byte(address)
267 }
268
269 fn read_data(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error<Self::Error>>
270 {
271 self.read_data(address, data)
272 }
273
274 fn read_current_address(&mut self) -> Result<u8, Error<Self::Error>>
275 {
276 self.read_current_address()
277 }
278
279 fn write_page(&mut self, address: u32, data: &[u8]) -> Result<(), Error<Self::Error>>
280 {
281 self.write_page(address, &data)
282 }
283
284 fn page_size(&self) -> usize
285 {
286 $page_size
287 }
288 }
289 };
290}
291
292pub trait PageWrite<E> {
297 fn page_write(&mut self, address: u32, data: &[u8]) -> Result<(), Error<E>>;
298 fn page_size(&self) -> usize;
299}
300
301impl_for_page_size!(
302 OneByte,
303 1,
304 B8,
305 8,
306 ["24x01", "AT24C01", 7, No, new_24x01],
307 ["24x02", "AT24C02", 8, No, new_24x02],
308 ["24CSx01", "24CS01", 7, Yes, new_24csx01],
309 ["24CSx02", "24CS02", 8, Yes, new_24csx02],
310 ["24x02E48", "24AA02E48", 8, No, new_24x02e48],
311 ["24x02E64", "24AA02E64", 8, No, new_24x02e64]
312);
313impl_for_page_size!(
314 OneByte,
315 1,
316 B16,
317 16,
318 ["24x04", "AT24C04", 9, No, new_24x04],
319 ["24x08", "AT24C08", 10, No, new_24x08],
320 ["24x16", "AT24C16", 11, No, new_24x16],
321 ["24CSx04", "AT24CS04", 9, Yes, new_24csx04],
322 ["24CSx08", "AT24CS08", 10, Yes, new_24csx08],
323 ["24CSx16", "AT24CS16", 11, Yes, new_24csx16],
324 ["24x025E48", "24AA025E48", 8, No, new_24x025e48],
325 ["24x025E64", "24AA025E64", 8, No, new_24x025e64],
326 ["M24C01", "M24C01", 7, No, new_m24x01],
327 ["M24C02", "M24C02", 8, No, new_m24x02]
328);
329impl_for_page_size!(
330 TwoBytes,
331 2,
332 B32,
333 32,
334 ["24x32", "AT24C32", 12, No, new_24x32],
335 ["24x64", "AT24C64", 13, No, new_24x64],
336 ["24CSx32", "AT24CS32", 12, Yes, new_24csx32],
337 ["24CSx64", "AT24CS64", 13, Yes, new_24csx64]
338);
339impl_for_page_size!(
340 TwoBytes,
341 2,
342 B64,
343 64,
344 ["24x128", "AT24C128", 14, No, new_24x128],
345 ["24x256", "AT24C256", 15, No, new_24x256]
346);
347impl_for_page_size!(
348 TwoBytes,
349 2,
350 B128,
351 128,
352 ["24x512", "AT24C512", 16, No, new_24x512]
353);
354impl_for_page_size!(
355 TwoBytes,
356 2,
357 B256,
358 256,
359 ["24xM01", "AT24CM01", 17, No, new_24xm01],
360 ["24xM02", "AT24CM02", 18, No, new_24xm02]
361);