1use crate::I2cExt;
14
15pub struct Mcp23x17<M>(M);
17
18impl<I2C> Mcp23x17<core::cell::RefCell<Driver<Mcp23017Bus<I2C>>>>
19where
20 I2C: crate::I2cBus,
21{
22 pub fn new_mcp23017(bus: I2C, a0: bool, a1: bool, a2: bool) -> Self {
24 Self::with_mutex(Mcp23017Bus(bus), a0, a1, a2)
25 }
26}
27
28impl<SPI> Mcp23x17<core::cell::RefCell<Driver<Mcp23S17Bus<SPI>>>>
29where
30 SPI: crate::SpiBus,
31{
32 pub fn new_mcp23s17(bus: SPI) -> Self {
34 Self::with_mutex(Mcp23S17Bus(bus), false, false, false)
35 }
36}
37
38impl<B, M> Mcp23x17<M>
39where
40 B: Mcp23x17Bus,
41 M: crate::PortMutex<Port = Driver<B>>,
42{
43 pub fn with_mutex(bus: B, a0: bool, a1: bool, a2: bool) -> Self {
44 Self(crate::PortMutex::create(Driver::new(bus, a0, a1, a2)))
45 }
46
47 pub fn split<'a>(&'a mut self) -> Parts<'a, B, M> {
48 Parts {
49 gpa0: crate::Pin::new(0, &self.0),
50 gpa1: crate::Pin::new(1, &self.0),
51 gpa2: crate::Pin::new(2, &self.0),
52 gpa3: crate::Pin::new(3, &self.0),
53 gpa4: crate::Pin::new(4, &self.0),
54 gpa5: crate::Pin::new(5, &self.0),
55 gpa6: crate::Pin::new(6, &self.0),
56 gpa7: crate::Pin::new(7, &self.0),
57 gpb0: crate::Pin::new(8, &self.0),
58 gpb1: crate::Pin::new(9, &self.0),
59 gpb2: crate::Pin::new(10, &self.0),
60 gpb3: crate::Pin::new(11, &self.0),
61 gpb4: crate::Pin::new(12, &self.0),
62 gpb5: crate::Pin::new(13, &self.0),
63 gpb6: crate::Pin::new(14, &self.0),
64 gpb7: crate::Pin::new(15, &self.0),
65 }
66 }
67}
68
69pub struct Parts<'a, B, M = core::cell::RefCell<Driver<B>>>
70where
71 B: Mcp23x17Bus,
72 M: crate::PortMutex<Port = Driver<B>>,
73{
74 pub gpa0: crate::Pin<'a, crate::mode::Input, M>,
75 pub gpa1: crate::Pin<'a, crate::mode::Input, M>,
76 pub gpa2: crate::Pin<'a, crate::mode::Input, M>,
77 pub gpa3: crate::Pin<'a, crate::mode::Input, M>,
78 pub gpa4: crate::Pin<'a, crate::mode::Input, M>,
79 pub gpa5: crate::Pin<'a, crate::mode::Input, M>,
80 pub gpa6: crate::Pin<'a, crate::mode::Input, M>,
81 pub gpa7: crate::Pin<'a, crate::mode::Input, M>,
82 pub gpb0: crate::Pin<'a, crate::mode::Input, M>,
83 pub gpb1: crate::Pin<'a, crate::mode::Input, M>,
84 pub gpb2: crate::Pin<'a, crate::mode::Input, M>,
85 pub gpb3: crate::Pin<'a, crate::mode::Input, M>,
86 pub gpb4: crate::Pin<'a, crate::mode::Input, M>,
87 pub gpb5: crate::Pin<'a, crate::mode::Input, M>,
88 pub gpb6: crate::Pin<'a, crate::mode::Input, M>,
89 pub gpb7: crate::Pin<'a, crate::mode::Input, M>,
90}
91
92#[allow(dead_code)]
93#[derive(Debug, Clone, Copy, PartialEq, Eq)]
94enum Regs {
100 IODIRA = 0x00,
102 IPOLA = 0x02,
104 GPINTENA = 0x04,
106 DEFVALA = 0x06,
108 INTCONA = 0x08,
111 IOCONA = 0x0a,
123 GPPUA = 0x0c,
126 INTFA = 0x0e,
128 INTCAPA = 0x10,
131 GPIOA = 0x12,
133 OLATA = 0x14,
135 IODIRB = 0x01,
137 IPOLB = 0x03,
139 GPINTENB = 0x05,
141 DEFVALB = 0x07,
143 INTCONB = 0x09,
146 IOCONB = 0x0b,
158 GPPUB = 0x0d,
161 INTFB = 0x0f,
163 INTCAPB = 0x11,
166 GPIOB = 0x13,
168 OLATB = 0x15,
170}
171
172impl From<Regs> for u8 {
173 fn from(r: Regs) -> u8 {
174 r as u8
175 }
176}
177
178pub struct Driver<B> {
179 bus: B,
180 out: u16,
181 addr: u8,
182}
183
184impl<B> Driver<B> {
185 pub fn new(bus: B, a0: bool, a1: bool, a2: bool) -> Self {
186 let addr = 0x20 | ((a2 as u8) << 2) | ((a1 as u8) << 1) | (a0 as u8);
187 Self {
188 bus,
189 out: 0x0000,
190 addr,
191 }
192 }
193}
194
195impl<B: Mcp23x17Bus> crate::PortDriver for Driver<B> {
196 type Error = B::BusError;
197
198 fn set(&mut self, mask_high: u32, mask_low: u32) -> Result<(), Self::Error> {
199 self.out |= mask_high as u16;
200 self.out &= !mask_low as u16;
201 if (mask_high | mask_low) & 0x00FF != 0 {
202 self.bus
203 .write_reg(self.addr, Regs::GPIOA, (self.out & 0xFF) as u8)?;
204 }
205 if (mask_high | mask_low) & 0xFF00 != 0 {
206 self.bus
207 .write_reg(self.addr, Regs::GPIOB, (self.out >> 8) as u8)?;
208 }
209 Ok(())
210 }
211
212 fn is_set(&mut self, mask_high: u32, mask_low: u32) -> Result<u32, Self::Error> {
213 Ok(((self.out as u32) & mask_high) | (!(self.out as u32) & mask_low))
214 }
215
216 fn get(&mut self, mask_high: u32, mask_low: u32) -> Result<u32, Self::Error> {
217 let io0 = if (mask_high | mask_low) & 0x00FF != 0 {
218 self.bus.read_reg(self.addr, Regs::GPIOA)?
219 } else {
220 0
221 };
222 let io1 = if (mask_high | mask_low) & 0xFF00 != 0 {
223 self.bus.read_reg(self.addr, Regs::GPIOB)?
224 } else {
225 0
226 };
227 let in_ = ((io1 as u32) << 8) | io0 as u32;
228 Ok((in_ & mask_high) | (!in_ & mask_low))
229 }
230}
231
232impl<B: Mcp23x17Bus> crate::PortDriverTotemPole for Driver<B> {
233 fn set_direction(
234 &mut self,
235 mask: u32,
236 dir: crate::Direction,
237 _state: bool,
238 ) -> Result<(), Self::Error> {
239 let (mask_set, mask_clear) = match dir {
240 crate::Direction::Input => (mask as u16, 0),
241 crate::Direction::Output => (0, mask as u16),
242 };
243 if mask & 0x00FF != 0 {
244 self.bus.update_reg(
245 self.addr,
246 Regs::IODIRA,
247 (mask_set & 0xFF) as u8,
248 (mask_clear & 0xFF) as u8,
249 )?;
250 }
251 if mask & 0xFF00 != 0 {
252 self.bus.update_reg(
253 self.addr,
254 Regs::IODIRB,
255 (mask_set >> 8) as u8,
256 (mask_clear >> 8) as u8,
257 )?;
258 }
259 Ok(())
260 }
261}
262
263impl<B: Mcp23x17Bus> crate::PortDriverPullUp for Driver<B> {
264 fn set_pull_up(&mut self, mask: u32, enable: bool) -> Result<(), Self::Error> {
265 let (mask_set, mask_clear) = match enable {
266 true => (mask as u16, 0),
267 false => (0, mask as u16),
268 };
269 if mask & 0x00FF != 0 {
270 self.bus.update_reg(
271 self.addr,
272 Regs::GPPUA,
273 (mask_set & 0xFF) as u8,
274 (mask_clear & 0xFF) as u8,
275 )?;
276 }
277 if mask & 0xFF00 != 0 {
278 self.bus.update_reg(
279 self.addr,
280 Regs::GPPUB,
281 (mask_set >> 8) as u8,
282 (mask_clear >> 8) as u8,
283 )?;
284 }
285 Ok(())
286 }
287}
288
289impl<B: Mcp23x17Bus> crate::PortDriverPolarity for Driver<B> {
290 fn set_polarity(&mut self, mask: u32, inverted: bool) -> Result<(), Self::Error> {
291 let (mask_set, mask_clear) = match inverted {
292 true => (mask as u16, 0),
293 false => (0, mask as u16),
294 };
295 if mask & 0x00FF != 0 {
296 self.bus.update_reg(
297 self.addr,
298 Regs::IPOLA,
299 (mask_set & 0xFF) as u8,
300 (mask_clear & 0xFF) as u8,
301 )?;
302 }
303 if mask & 0xFF00 != 0 {
304 self.bus.update_reg(
305 self.addr,
306 Regs::IPOLB,
307 (mask_set >> 8) as u8,
308 (mask_clear >> 8) as u8,
309 )?;
310 }
311 Ok(())
312 }
313}
314
315pub struct Mcp23017Bus<I2C>(I2C);
318pub struct Mcp23S17Bus<SPI>(SPI);
319
320pub trait Mcp23x17Bus {
323 type BusError;
324
325 fn write_reg<R: Into<u8>>(&mut self, addr: u8, reg: R, value: u8)
326 -> Result<(), Self::BusError>;
327 fn read_reg<R: Into<u8>>(&mut self, addr: u8, reg: R) -> Result<u8, Self::BusError>;
328
329 fn update_reg<R: Into<u8>>(
330 &mut self,
331 addr: u8,
332 reg: R,
333 mask_set: u8,
334 mask_clear: u8,
335 ) -> Result<(), Self::BusError> {
336 let reg = reg.into();
337 let mut val = self.read_reg(addr, reg)?;
338 val |= mask_set;
339 val &= !mask_clear;
340 self.write_reg(addr, reg, val)?;
341 Ok(())
342 }
343}
344
345impl<SPI: crate::SpiBus> Mcp23x17Bus for Mcp23S17Bus<SPI> {
346 type BusError = SPI::BusError;
347
348 fn write_reg<R: Into<u8>>(
349 &mut self,
350 addr: u8,
351 reg: R,
352 value: u8,
353 ) -> Result<(), Self::BusError> {
354 self.0.write(&[0x40 | addr << 1, reg.into(), value])?;
355
356 Ok(())
357 }
358
359 fn read_reg<R: Into<u8>>(&mut self, addr: u8, reg: R) -> Result<u8, Self::BusError> {
360 let mut val = [0; 1];
361 let write = [0x40 | addr << 1 | 0x1, reg.into()];
362 let mut tx = [
363 embedded_hal::spi::Operation::Write(&write),
364 embedded_hal::spi::Operation::Read(&mut val),
365 ];
366 self.0.transaction(&mut tx)?;
367
368 Ok(val[0])
369 }
370}
371
372impl<I2C: crate::I2cBus> Mcp23x17Bus for Mcp23017Bus<I2C> {
373 type BusError = I2C::BusError;
374
375 fn write_reg<R: Into<u8>>(
376 &mut self,
377 addr: u8,
378 reg: R,
379 value: u8,
380 ) -> Result<(), Self::BusError> {
381 self.0.write_reg(addr, reg, value)
382 }
383
384 fn read_reg<R: Into<u8>>(&mut self, addr: u8, reg: R) -> Result<u8, Self::BusError> {
385 self.0.read_reg(addr, reg)
386 }
387}
388
389#[cfg(test)]
390mod tests {
391 use embedded_hal_mock::eh1::{i2c as mock_i2c, spi as mock_spi};
392
393 #[test]
394 fn mcp23017() {
395 let expectations = [
396 mock_i2c::Transaction::write_read(0x22, vec![0x00], vec![0xff]),
398 mock_i2c::Transaction::write(0x22, vec![0x00, 0xfe]),
399 mock_i2c::Transaction::write_read(0x22, vec![0x00], vec![0xfe]),
401 mock_i2c::Transaction::write(0x22, vec![0x00, 0x7e]),
402 mock_i2c::Transaction::write_read(0x22, vec![0x00], vec![0x7e]),
403 mock_i2c::Transaction::write(0x22, vec![0x00, 0xfe]),
404 mock_i2c::Transaction::write_read(0x22, vec![0x01], vec![0xff]),
406 mock_i2c::Transaction::write(0x22, vec![0x01, 0xfe]),
407 mock_i2c::Transaction::write_read(0x22, vec![0x01], vec![0xfe]),
409 mock_i2c::Transaction::write(0x22, vec![0x01, 0x7e]),
410 mock_i2c::Transaction::write_read(0x22, vec![0x01], vec![0x7e]),
411 mock_i2c::Transaction::write(0x22, vec![0x01, 0xfe]),
412 mock_i2c::Transaction::write(0x22, vec![0x12, 0x01]),
414 mock_i2c::Transaction::write(0x22, vec![0x12, 0x00]),
415 mock_i2c::Transaction::write(0x22, vec![0x13, 0x01]),
416 mock_i2c::Transaction::write(0x22, vec![0x13, 0x00]),
417 mock_i2c::Transaction::write_read(0x22, vec![0x12], vec![0x80]),
419 mock_i2c::Transaction::write_read(0x22, vec![0x12], vec![0x7f]),
420 mock_i2c::Transaction::write_read(0x22, vec![0x13], vec![0x80]),
421 mock_i2c::Transaction::write_read(0x22, vec![0x13], vec![0x7f]),
422 ];
423 let mut bus = mock_i2c::Mock::new(&expectations);
424
425 let mut pca = super::Mcp23x17::new_mcp23017(bus.clone(), false, true, false);
426 let pca_pins = pca.split();
427
428 let mut gpa0 = pca_pins.gpa0.into_output().unwrap();
429 let gpa7 = pca_pins.gpa7.into_output().unwrap();
430 let gpa7 = gpa7.into_input().unwrap();
431
432 let mut gpb0 = pca_pins.gpb0.into_output().unwrap();
433 let gpb7 = pca_pins.gpb7.into_output().unwrap();
434 let gpb7 = gpb7.into_input().unwrap();
435
436 gpa0.set_high().unwrap();
438 gpa0.set_low().unwrap();
439 gpb0.set_high().unwrap();
440 gpb0.set_low().unwrap();
441
442 assert!(gpa7.is_high().unwrap());
444 assert!(gpa7.is_low().unwrap());
445 assert!(gpb7.is_high().unwrap());
446 assert!(gpb7.is_low().unwrap());
447
448 bus.done();
449 }
450
451 #[test]
452 fn mcp23s17() {
453 let expectations = [
454 mock_spi::Transaction::transaction_start(),
456 mock_spi::Transaction::write_vec(vec![0x41, 0x00]),
457 mock_spi::Transaction::read(0xff),
458 mock_spi::Transaction::transaction_end(),
459 mock_spi::Transaction::transaction_start(),
460 mock_spi::Transaction::write_vec(vec![0x40, 0x00, 0xfe]),
461 mock_spi::Transaction::transaction_end(),
462 mock_spi::Transaction::transaction_start(),
464 mock_spi::Transaction::write_vec(vec![0x41, 0x00]),
465 mock_spi::Transaction::read(0xfe),
466 mock_spi::Transaction::transaction_end(),
467 mock_spi::Transaction::transaction_start(),
468 mock_spi::Transaction::write_vec(vec![0x40, 0x00, 0x7e]),
469 mock_spi::Transaction::transaction_end(),
470 mock_spi::Transaction::transaction_start(),
471 mock_spi::Transaction::write_vec(vec![0x41, 0x00]),
472 mock_spi::Transaction::read(0x7e),
473 mock_spi::Transaction::transaction_end(),
474 mock_spi::Transaction::transaction_start(),
475 mock_spi::Transaction::write_vec(vec![0x40, 0x00, 0xfe]),
476 mock_spi::Transaction::transaction_end(),
477 mock_spi::Transaction::transaction_start(),
479 mock_spi::Transaction::write_vec(vec![0x41, 0x01]),
480 mock_spi::Transaction::read(0xff),
481 mock_spi::Transaction::transaction_end(),
482 mock_spi::Transaction::transaction_start(),
483 mock_spi::Transaction::write_vec(vec![0x40, 0x01, 0xfe]),
484 mock_spi::Transaction::transaction_end(), mock_spi::Transaction::transaction_start(),
486 mock_spi::Transaction::write_vec(vec![0x41, 0x01]),
487 mock_spi::Transaction::read(0xfe),
488 mock_spi::Transaction::transaction_end(),
489 mock_spi::Transaction::transaction_start(),
490 mock_spi::Transaction::write_vec(vec![0x40, 0x01, 0x7e]),
491 mock_spi::Transaction::transaction_end(),
492 mock_spi::Transaction::transaction_start(),
493 mock_spi::Transaction::write_vec(vec![0x41, 0x01]),
494 mock_spi::Transaction::read(0x7e),
495 mock_spi::Transaction::transaction_end(),
496 mock_spi::Transaction::transaction_start(),
497 mock_spi::Transaction::write_vec(vec![0x40, 0x01, 0xfe]),
498 mock_spi::Transaction::transaction_end(),
499 mock_spi::Transaction::transaction_start(),
501 mock_spi::Transaction::write_vec(vec![0x40, 0x12, 0x01]),
502 mock_spi::Transaction::transaction_end(),
503 mock_spi::Transaction::transaction_start(),
504 mock_spi::Transaction::write_vec(vec![0x40, 0x12, 0x00]),
505 mock_spi::Transaction::transaction_end(),
506 mock_spi::Transaction::transaction_start(),
507 mock_spi::Transaction::write_vec(vec![0x40, 0x13, 0x01]),
508 mock_spi::Transaction::transaction_end(),
509 mock_spi::Transaction::transaction_start(),
510 mock_spi::Transaction::write_vec(vec![0x40, 0x13, 0x00]),
511 mock_spi::Transaction::transaction_end(),
512 mock_spi::Transaction::transaction_start(),
514 mock_spi::Transaction::write_vec(vec![0x41, 0x12]),
515 mock_spi::Transaction::read(0x80),
516 mock_spi::Transaction::transaction_end(),
517 mock_spi::Transaction::transaction_start(),
518 mock_spi::Transaction::write_vec(vec![0x41, 0x12]),
519 mock_spi::Transaction::read(0x7f),
520 mock_spi::Transaction::transaction_end(),
521 mock_spi::Transaction::transaction_start(),
522 mock_spi::Transaction::write_vec(vec![0x41, 0x13]),
523 mock_spi::Transaction::read(0x80),
524 mock_spi::Transaction::transaction_end(),
525 mock_spi::Transaction::transaction_start(),
526 mock_spi::Transaction::write_vec(vec![0x41, 0x13]),
527 mock_spi::Transaction::read(0x7f),
528 mock_spi::Transaction::transaction_end(),
529 ];
530 let mut bus = mock_spi::Mock::new(&expectations);
531
532 let mut pca = super::Mcp23x17::new_mcp23s17(bus.clone());
533 let pca_pins = pca.split();
534
535 let mut gpa0 = pca_pins.gpa0.into_output().unwrap();
536 let gpa7 = pca_pins.gpa7.into_output().unwrap();
537 let gpa7 = gpa7.into_input().unwrap();
538
539 let mut gpb0 = pca_pins.gpb0.into_output().unwrap();
540 let gpb7 = pca_pins.gpb7.into_output().unwrap();
541 let gpb7 = gpb7.into_input().unwrap();
542
543 gpa0.set_high().unwrap();
545 gpa0.set_low().unwrap();
546 gpb0.set_high().unwrap();
547 gpb0.set_low().unwrap();
548
549 assert!(gpa7.is_high().unwrap());
551 assert!(gpa7.is_low().unwrap());
552 assert!(gpb7.is_high().unwrap());
553 assert!(gpb7.is_low().unwrap());
554
555 bus.done();
556 }
557}