1#![no_std]
2#[cfg(feature = "async")]
27#[allow(unused_imports)]
28use embedded_hal_async::i2c::I2c as AsyncI2c;
29use embedded_hal::i2c::I2c;
30
31const REG_CONVERSION: u8 = 0x00;
33const REG_CONFIG: u8 = 0x01;
34const REG_LO_THRESH: u8 = 0x02;
35const REG_HI_THRESH: u8 = 0x03;
36
37const OS_MASK: u8 = 0x80;
39#[inline]
41pub fn conversion_complete(cfg_hi: u8) -> bool {
42 cfg_hi & OS_MASK != 0
43}
44
45pub struct ADS111x<I2C, const MODEL: u8> {
46 address: Address,
47 i2c: I2C,
48 pub config: Config,
49}
50
51pub type ADS1115<I2C> = ADS111x<I2C, 5>;
52pub type ADS1114<I2C> = ADS111x<I2C, 4>;
53pub type ADS1113<I2C> = ADS111x<I2C, 3>;
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub enum Error<I2cError, WaitError = ()> {
62 I2c(I2cError),
63 Wait(WaitError),
64}
65
66impl<I2cError, WaitError> From<I2cError> for Error<I2cError, WaitError> {
67 fn from(e: I2cError) -> Self {
68 Self::I2c(e)
69 }
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74#[repr(u8)]
75pub enum Mux {
76 A0N1 = 0b000,
77 A0N3 = 0b001,
78 A1N3 = 0b010,
79 A2N3 = 0b011,
80 A0 = 0b100,
81 A1 = 0b101,
82 A2 = 0b110,
83 A3 = 0b111,
84}
85
86#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
88pub enum Mode {
89 #[default]
90 SingleShot,
91 Continuous,
92}
93
94#[derive(Debug, Clone, Copy, PartialEq, Eq)]
97pub enum ConversionReadyPolarity {
98 ActiveLow,
99 ActiveHigh,
100}
101
102impl From<CompPol> for ConversionReadyPolarity {
103 fn from(p: CompPol) -> Self {
104 match p {
105 CompPol::ActiveLow => Self::ActiveLow,
106 CompPol::ActiveHigh => Self::ActiveHigh,
107 }
108 }
109}
110
111pub trait ConversionReady {
115 type Error;
116 type WaitFuture<'a>: core::future::Future<Output = Result<(), Self::Error>> + 'a
117 where
118 Self: 'a;
119 fn arm(&mut self, polarity: ConversionReadyPolarity);
135 fn wait_for_ready(&mut self, polarity: ConversionReadyPolarity) -> Self::WaitFuture<'_>;
140}
141
142pub trait BlockingReady {
148 type Error;
149 fn arm(&mut self, polarity: ConversionReadyPolarity);
155 fn wait_for_ready(&mut self, polarity: ConversionReadyPolarity) -> Result<(), Self::Error>;
157}
158
159#[cfg(feature = "async")]
176pub fn wait_all_ready<R: ConversionReady, const N: usize>(
177 rdy: &mut [R; N],
178 pol: [ConversionReadyPolarity; N],
179) -> JoinAllReady<'_, R, N> { let ptr = rdy.as_mut_ptr();
181 let futs = core::array::from_fn(|i| unsafe { (&mut *ptr.add(i)).wait_for_ready(pol[i]) });
182 JoinAllReady { futs, done: [false; N], remaining: N }
183}
184
185#[cfg(feature = "async")]
188#[derive(Debug, Clone, Copy, PartialEq, Eq)]
189pub struct WaitFailed<E> {
190 pub index: usize,
191 pub error: E,
192}
193
194#[cfg(feature = "async")]
196pub struct JoinAllReady<'r, R: ConversionReady + 'r, const N: usize> {
197 futs: [R::WaitFuture<'r>; N],
198 done: [bool; N],
199 remaining: usize,
200}
201
202#[cfg(feature = "async")]
203impl<R: ConversionReady, const N: usize> core::future::Future for JoinAllReady<'_, R, N> { type Output = Result<(), WaitFailed<R::Error>>;
204 fn poll(
205 self: core::pin::Pin<&mut Self>,
206 cx: &mut core::task::Context<'_>,
207 ) -> core::task::Poll<Self::Output> {
208 let this = unsafe { self.get_unchecked_mut() };
210 let mut i = 0;
211 while i < N {
212 if !this.done[i] {
213 let f = unsafe { core::pin::Pin::new_unchecked(&mut this.futs[i]) };
214 match f.poll(cx) {
215 core::task::Poll::Ready(Ok(())) => {
216 this.done[i] = true;
217 this.remaining -= 1;
218 }
219 core::task::Poll::Ready(Err(error)) => {
220 return core::task::Poll::Ready(Err(WaitFailed { index: i, error }))
221 }
222 core::task::Poll::Pending => {}
223 }
224 }
225 i += 1;
226 }
227 if this.remaining == 0 {
228 core::task::Poll::Ready(Ok(()))
229 } else {
230 core::task::Poll::Pending
231 }
232 }
233}
234
235pub trait AsyncDelayUs {
240 type DelayFuture<'a>: core::future::Future<Output = ()> + 'a
241 where
242 Self: 'a;
243 fn delay_us(&mut self, us: u32) -> Self::DelayFuture<'_>;
244}
245
246fn build_config_bytes(cfg: &Config, mux_bits: u8, os_start: bool, mode: Mode) -> [u8; 2] {
252 debug_assert!(!(mode == Mode::Continuous && os_start), "continuous must not set OS=1");
253 let os = if os_start { 1u8 << 7 } else { 0 };
254 let mode_bit = match mode {
255 Mode::SingleShot => 1u8,
256 Mode::Continuous => 0u8,
257 };
258 let hi = os | ((mux_bits & 0x07) << 4) | (cfg.gain as u8) | mode_bit;
259 let lo = (cfg.data_rate as u8)
260 | (cfg.comp_mode as u8)
261 | (cfg.comp_pol as u8)
262 | (cfg.comp_lat as u8)
263 | (cfg.comp_que as u8);
264 [hi, lo]
265}
266
267fn build_config_bytes_ads1113(data_rate: DataRate, os_start: bool) -> [u8; 2] {
269 let os = if os_start { 1u8 << 7 } else { 0 };
270 let hi = os | 1u8;
272 let lo = data_rate as u8 | 0x03; [hi, lo]
274}
275
276#[cfg(feature = "embassy")]
279fn build_config_bytes_ads1113_continuous(data_rate: DataRate) -> [u8; 2] {
280 [0u8, data_rate as u8 | 0x03]
281}
282
283fn write_config<I2C: I2c>(i2c: &mut I2C, addr: u8, bytes: [u8; 2]) -> Result<(), I2C::Error> {
284 i2c.write(addr, &[REG_CONFIG, bytes[0], bytes[1]])
285}
286
287fn read_conversion<I2C: I2c>(i2c: &mut I2C, addr: u8) -> Result<i16, I2C::Error> {
288 let mut data = [0u8; 2];
289 i2c.write_read(addr, &[REG_CONVERSION], &mut data)?;
290 Ok(i16::from_be_bytes(data))
291}
292
293pub fn conversion_period_us(dr: DataRate) -> u32 {
302 let sps = match dr {
303 DataRate::SPS8 => 8,
304 DataRate::SPS16 => 16,
305 DataRate::SPS32 => 32,
306 DataRate::SPS64 => 64,
307 DataRate::SPS128 => 128,
308 DataRate::SPS250 => 250,
309 DataRate::SPS475 => 475,
310 DataRate::SPS860 => 860,
311 };
312 let nominal = 1_000_000 / sps as u32;
313 nominal + nominal / 8 + 100
314}
315
316impl<I2C> ADS1113<I2C> {
319 pub fn new(i2c: I2C, config: Config) -> Self {
320 Self { address: Address::Ground, i2c, config }
321 }
322 pub fn release(self) -> I2C { self.i2c }
323}
324
325impl<I2C> ADS1114<I2C> {
326 pub fn new(i2c: I2C, config: Config) -> Self {
327 Self { address: Address::Ground, i2c, config }
328 }
329 pub fn release(self) -> I2C { self.i2c }
330}
331
332impl<I2C> ADS1115<I2C> {
333 pub fn new(address: Address, i2c: I2C, config: Config) -> Self {
334 Self { address, i2c, config }
335 }
336 pub fn release(self) -> I2C { self.i2c }
337}
338
339fn wait_complete_sync<I2C: I2c>(i2c: &mut I2C, addr: u8) -> Result<(), I2C::Error> {
346 let mut buf = [0u8; 2];
347 loop {
348 i2c.write_read(addr, &[REG_CONFIG], &mut buf)?;
349 if conversion_complete(buf[0]) { break; }
350 }
351 Ok(())
352}
353
354impl<I2C: I2c> ADS1113<I2C> {
355 fn read_channel_raw(&mut self) -> Result<i16, I2C::Error> {
357 let b = build_config_bytes_ads1113(self.config.data_rate, true);
358 write_config(&mut self.i2c, self.address as u8, b)?;
359 wait_complete_sync(&mut self.i2c, self.address as u8)?;
360 read_conversion(&mut self.i2c, self.address as u8)
361 }
362 pub fn read_adc(&mut self) -> Result<i16, I2C::Error> { self.read_channel_raw() }
363 pub fn read_adc_timed(&mut self, mut delay_us: impl FnMut(u32)) -> Result<i16, I2C::Error> {
365 let b = build_config_bytes_ads1113(self.config.data_rate, true);
366 write_config(&mut self.i2c, self.address as u8, b)?;
367 delay_us(conversion_period_us(self.config.data_rate));
368 read_conversion(&mut self.i2c, self.address as u8)
369 }
370}
371
372impl<I2C: I2c> ADS1114<I2C> {
373 pub fn enable_conversion_ready_pin(&mut self) -> Result<(), I2C::Error> {
384 enable_rdy_registers(&mut self.i2c, self.address as u8)?;
385 self.config = self.config.as_conversion_ready();
386 Ok(())
387 }
388 pub fn start_conversion(&mut self) -> Result<(), I2C::Error> {
390 let b = build_config_bytes(&self.config, 0b100, true, Mode::SingleShot);
391 write_config(&mut self.i2c, self.address as u8, b)
392 }
393 pub fn read_conversion(&mut self) -> Result<i16, I2C::Error> {
395 read_conversion(&mut self.i2c, self.address as u8)
396 }
397 pub fn start_continuous(&mut self) -> Result<(), I2C::Error> {
402 let b = build_config_bytes(&self.config, 0b100, false, Mode::Continuous);
403 write_config(&mut self.i2c, self.address as u8, b)
404 }
405 pub fn next_conversion_blocking<R: BlockingReady>(
413 &mut self,
414 rdy: &mut R,
415 ) -> Result<i16, Error<I2C::Error, R::Error>> {
416 debug_assert_rdy(&self.config, "ADS1114::next_conversion_blocking");
417 let pol = ConversionReadyPolarity::from(self.config.comp_pol);
418 rdy.arm(pol);
419 rdy.wait_for_ready(pol).map_err(Error::Wait)?;
420 self.read_conversion().map_err(Error::I2c)
421 }
422 pub fn next_conversion_timed(
427 &mut self,
428 mut delay_us: impl FnMut(u32),
429 ) -> Result<i16, I2C::Error> {
430 delay_us(conversion_period_us(self.config.data_rate));
431 self.read_conversion()
432 }
433 fn read_channel_raw(&mut self) -> Result<i16, I2C::Error> {
434 self.start_conversion()?;
435 wait_complete_sync(&mut self.i2c, self.address as u8)?;
436 self.read_conversion()
437 }
438 pub fn read_adc(&mut self) -> Result<i16, I2C::Error> { self.read_channel_raw() }
439}
440
441#[inline]
444pub fn signed_to_polarity_magnitude(value: i16) -> (bool, u16) {
445 if value < 0 { (true, value.unsigned_abs()) } else { (false, value as u16) }
446}
447
448#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
450pub struct Channel0(pub u16);
451#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
452pub struct Channel1(pub u16);
453#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
454pub struct Channel2(pub u16);
455#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
456pub struct Channel3(pub u16);
457
458fn enable_rdy_registers<I2C: I2c>(i2c: &mut I2C, addr: u8) -> Result<(), I2C::Error> {
459 i2c.write(addr, &[REG_HI_THRESH, 0x80, 0x00])?;
461 i2c.write(addr, &[REG_LO_THRESH, 0x00, 0x00])?;
462 Ok(())
463}
464
465impl<I2C: I2c> ADS1115<I2C> {
466 pub fn enable_conversion_ready_pin(&mut self) -> Result<(), I2C::Error> {
470 enable_rdy_registers(&mut self.i2c, self.address as u8)?;
471 self.config = self.config.as_conversion_ready();
472 Ok(())
473 }
474 pub fn start_conversion(&mut self, mux: Mux) -> Result<(), I2C::Error> {
475 let b = build_config_bytes(&self.config, mux as u8, true, Mode::SingleShot);
476 write_config(&mut self.i2c, self.address as u8, b)
477 }
478 pub fn read_conversion(&mut self) -> Result<i16, I2C::Error> {
479 read_conversion(&mut self.i2c, self.address as u8)
480 }
481 pub fn start_continuous(&mut self, mux: Mux) -> Result<(), I2C::Error> {
482 let b = build_config_bytes(&self.config, mux as u8, false, Mode::Continuous);
485 write_config(&mut self.i2c, self.address as u8, b)
486 }
487 pub fn next_conversion_blocking<R: BlockingReady>(
494 &mut self,
495 rdy: &mut R,
496 ) -> Result<i16, Error<I2C::Error, R::Error>> {
497 debug_assert_rdy(&self.config, "ADS1115::next_conversion_blocking");
498 let pol = ConversionReadyPolarity::from(self.config.comp_pol);
499 rdy.arm(pol);
500 rdy.wait_for_ready(pol).map_err(Error::Wait)?;
501 self.read_conversion().map_err(Error::I2c)
502 }
503 pub fn next_conversion_timed(
508 &mut self,
509 mut delay_us: impl FnMut(u32),
510 ) -> Result<i16, I2C::Error> {
511 delay_us(conversion_period_us(self.config.data_rate));
512 self.read_conversion()
513 }
514 fn read_channel_raw(&mut self, mux: Mux) -> Result<i16, I2C::Error> {
515 self.start_conversion(mux)?;
517 wait_complete_sync(&mut self.i2c, self.address as u8)?;
518 self.read_conversion()
519 }
520 pub fn read_channel(&mut self, mux: Mux) -> Result<i16, I2C::Error> { self.read_channel_raw(mux) }
522 pub fn read_channel_raw_bits(&mut self, mux: u8) -> Result<i16, MuxOrI2c<I2C::Error>> {
523 Ok(self.read_channel_raw(match_mux(mux).map_err(|_| MuxOrI2c::Mux(MuxError(mux)))?).map_err(MuxOrI2c::I2c)?)
524 }
525 pub fn read_adc_a0(&mut self) -> Result<i16, I2C::Error> { self.read_channel_raw(Mux::A0) }
526 pub fn read_adc_a1(&mut self) -> Result<i16, I2C::Error> { self.read_channel_raw(Mux::A1) }
527 pub fn read_adc_a2(&mut self) -> Result<i16, I2C::Error> { self.read_channel_raw(Mux::A2) }
528 pub fn read_adc_a3(&mut self) -> Result<i16, I2C::Error> { self.read_channel_raw(Mux::A3) }
529 pub fn read_adc_a0n1(&mut self) -> Result<i16, I2C::Error> { self.read_channel_raw(Mux::A0N1) }
530 pub fn read_adc_a0n3(&mut self) -> Result<i16, I2C::Error> { self.read_channel_raw(Mux::A0N3) }
531 pub fn read_adc_a1n3(&mut self) -> Result<i16, I2C::Error> { self.read_channel_raw(Mux::A1N3) }
532 pub fn read_adc_a2n3(&mut self) -> Result<i16, I2C::Error> { self.read_channel_raw(Mux::A2N3) }
533 pub fn read_4adc(&mut self) -> Result<[i16; 4], I2C::Error> {
535 Ok([self.read_adc_a0()?, self.read_adc_a1()?, self.read_adc_a2()?, self.read_adc_a3()?])
536 }
537 pub fn read_channels(&mut self) -> Result<(Channel0, Channel1, Channel2, Channel3), I2C::Error> {
539 Ok((Channel0(self.read_adc_a0()? as u16), Channel1(self.read_adc_a1()? as u16),
540 Channel2(self.read_adc_a2()? as u16), Channel3(self.read_adc_a3()? as u16)))
541 }
542 pub fn read_a0_a1(&mut self) -> Result<(bool, u16), I2C::Error> {
545 Ok(signed_to_polarity_magnitude(self.read_channel_raw(Mux::A0N1)?))
546 }
547 pub fn read_a0_a3(&mut self) -> Result<(bool, u16), I2C::Error> {
548 Ok(signed_to_polarity_magnitude(self.read_channel_raw(Mux::A0N3)?))
549 }
550 pub fn read_a1_a3(&mut self) -> Result<(bool, u16), I2C::Error> {
551 Ok(signed_to_polarity_magnitude(self.read_channel_raw(Mux::A1N3)?))
552 }
553 pub fn read_a2_a3(&mut self) -> Result<(bool, u16), I2C::Error> {
554 Ok(signed_to_polarity_magnitude(self.read_channel_raw(Mux::A2N3)?))
555 }
556}
557
558#[derive(Debug, Clone, Copy, PartialEq, Eq)]
560pub struct MuxError(pub u8);
561
562#[derive(Debug, Clone, Copy, PartialEq, Eq)]
564pub enum MuxOrI2c<E> {
565 Mux(MuxError),
566 I2c(E),
567}
568
569fn match_mux(bits: u8) -> Result<Mux, MuxError> {
570 match bits {
571 0 => Ok(Mux::A0N1), 1 => Ok(Mux::A0N3), 2 => Ok(Mux::A1N3), 3 => Ok(Mux::A2N3),
572 4 => Ok(Mux::A0), 5 => Ok(Mux::A1), 6 => Ok(Mux::A2), 7 => Ok(Mux::A3),
573 b => Err(MuxError(b)),
574 }
575}
576
577#[cfg(feature = "async")]
580mod async_api {
581 use super::*;
582 use embedded_hal_async::i2c::I2c as AsyncI2c;
583
584 async fn write_config_async<I2C: AsyncI2c>(i2c: &mut I2C, addr: u8, b: [u8; 2]) -> Result<(), I2C::Error> {
585 i2c.write(addr, &[REG_CONFIG, b[0], b[1]]).await
586 }
587 async fn read_conv_async<I2C: AsyncI2c>(i2c: &mut I2C, addr: u8) -> Result<i16, I2C::Error> {
588 let mut d = [0u8; 2];
589 i2c.write_read(addr, &[REG_CONVERSION], &mut d).await?;
590 Ok(i16::from_be_bytes(d))
591 }
592
593 impl<I2C: AsyncI2c> ADS1113<I2C> {
594 pub async fn read_adc_async<D: AsyncDelayUs>(&mut self, delay: &mut D) -> Result<i16, I2C::Error> {
596 self.start_conversion_async().await?;
597 delay.delay_us(conversion_period_us(self.config.data_rate)).await;
598 self.read_conversion_async().await
599 }
600 pub async fn start_conversion_async(&mut self) -> Result<(), I2C::Error> {
601 let b = build_config_bytes_ads1113(self.config.data_rate, true);
602 write_config_async(&mut self.i2c, self.address as u8, b).await
603 }
604 pub async fn read_conversion_async(&mut self) -> Result<i16, I2C::Error> {
605 read_conv_async(&mut self.i2c, self.address as u8).await
606 }
607 }
608
609 impl<I2C: AsyncI2c> ADS1114<I2C> {
610 pub async fn enable_conversion_ready_pin_async(&mut self) -> Result<(), I2C::Error> {
614 self.i2c.write(self.address as u8, &[REG_HI_THRESH, 0x80, 0x00]).await?;
615 self.i2c.write(self.address as u8, &[REG_LO_THRESH, 0x00, 0x00]).await?;
616 self.config = self.config.as_conversion_ready();
619 Ok(())
620 }
621 pub async fn start_conversion_async(&mut self) -> Result<(), I2C::Error> {
622 let b = build_config_bytes(&self.config, 0b100, true, Mode::SingleShot);
623 write_config_async(&mut self.i2c, self.address as u8, b).await
624 }
625 pub async fn start_continuous_async_unchecked(&mut self) -> Result<(), I2C::Error> {
626 let b = build_config_bytes(&self.config, 0b100, false, Mode::Continuous);
630 write_config_async(&mut self.i2c, self.address as u8, b).await
631 }
632 pub async fn read_conversion_async(&mut self) -> Result<i16, I2C::Error> {
633 read_conv_async(&mut self.i2c, self.address as u8).await
634 }
635 pub async fn read_adc_event<R: ConversionReady>(&mut self, rdy: &mut R) -> Result<i16, Error<I2C::Error, R::Error>> {
645 debug_assert_rdy(&self.config, "ADS1114::read_adc_event");
646 let pol = ConversionReadyPolarity::from(self.config.comp_pol);
647 rdy.arm(pol);
648 self.start_conversion_async().await.map_err(Error::I2c)?;
649 rdy.wait_for_ready(pol).await.map_err(Error::Wait)?;
650 self.read_conversion_async().await.map_err(Error::I2c)
651 }
652 pub async fn read_adc_timed<D: AsyncDelayUs>(&mut self, delay: &mut D) -> Result<i16, I2C::Error> {
654 self.start_conversion_async().await?;
655 delay.delay_us(conversion_period_us(self.config.data_rate)).await;
656 self.read_conversion_async().await
657 }
658 pub async fn next_conversion<R: ConversionReady>(&mut self, rdy: &mut R) -> Result<i16, Error<I2C::Error, R::Error>> {
666 debug_assert_rdy(&self.config, "ADS1114::next_conversion");
667 let pol = ConversionReadyPolarity::from(self.config.comp_pol);
668 rdy.arm(pol);
669 rdy.wait_for_ready(pol).await.map_err(Error::Wait)?;
670 self.read_conversion_async().await.map_err(Error::I2c)
671 }
672 pub async fn continuous<'a, 'r, R: ConversionReady>(&'a mut self, rdy: &'r mut R) -> Result<Continuous<'a, 'r, I2C, R, 4>, I2C::Error> {
679 debug_assert_rdy(&self.config, "ADS1114::continuous");
680 rdy.arm(ConversionReadyPolarity::from(self.config.comp_pol));
681 self.start_continuous_async_unchecked().await?;
682 Ok(Continuous { adc: self, rdy })
683 }
684 }
685
686 impl<I2C: AsyncI2c> ADS1115<I2C> {
687 pub async fn enable_conversion_ready_pin_async(&mut self) -> Result<(), I2C::Error> {
690 self.i2c.write(self.address as u8, &[REG_HI_THRESH, 0x80, 0x00]).await?;
691 self.i2c.write(self.address as u8, &[REG_LO_THRESH, 0x00, 0x00]).await?;
692 self.config = self.config.as_conversion_ready();
694 Ok(())
695 }
696 pub async fn start_conversion_async(&mut self, mux: Mux) -> Result<(), I2C::Error> {
697 let b = build_config_bytes(&self.config, mux as u8, true, Mode::SingleShot);
698 write_config_async(&mut self.i2c, self.address as u8, b).await
699 }
700 pub async fn start_continuous_async_unchecked(&mut self, mux: Mux) -> Result<(), I2C::Error> {
701 let b = build_config_bytes(&self.config, mux as u8, false, Mode::Continuous);
706 write_config_async(&mut self.i2c, self.address as u8, b).await
707 }
708 pub async fn read_conversion_async(&mut self) -> Result<i16, I2C::Error> {
709 read_conv_async(&mut self.i2c, self.address as u8).await
710 }
711 pub async fn read_channel_event<R: ConversionReady>(&mut self, mux: Mux, rdy: &mut R) -> Result<i16, Error<I2C::Error, R::Error>> {
717 debug_assert_rdy(&self.config, "ADS1115::read_channel_event");
718 let pol = ConversionReadyPolarity::from(self.config.comp_pol);
719 rdy.arm(pol);
720 self.start_conversion_async(mux).await.map_err(Error::I2c)?;
721 rdy.wait_for_ready(pol).await.map_err(Error::Wait)?;
722 self.read_conversion_async().await.map_err(Error::I2c)
723 }
724 pub async fn read_channel_timed<D: AsyncDelayUs>(&mut self, mux: Mux, delay: &mut D) -> Result<i16, I2C::Error> {
726 self.start_conversion_async(mux).await?;
727 delay.delay_us(conversion_period_us(self.config.data_rate)).await;
728 self.read_conversion_async().await
729 }
730 pub async fn read_adc_a0_async<R: ConversionReady>(&mut self, rdy: &mut R) -> Result<i16, Error<I2C::Error, R::Error>> { self.read_channel_event(Mux::A0, rdy).await }
732 pub async fn read_adc_a1_async<R: ConversionReady>(&mut self, rdy: &mut R) -> Result<i16, Error<I2C::Error, R::Error>> { self.read_channel_event(Mux::A1, rdy).await }
733 pub async fn read_adc_a2_async<R: ConversionReady>(&mut self, rdy: &mut R) -> Result<i16, Error<I2C::Error, R::Error>> { self.read_channel_event(Mux::A2, rdy).await }
734 pub async fn read_adc_a3_async<R: ConversionReady>(&mut self, rdy: &mut R) -> Result<i16, Error<I2C::Error, R::Error>> { self.read_channel_event(Mux::A3, rdy).await }
735 pub async fn read_4adc_event<R: ConversionReady>(&mut self, rdy: &mut R) -> Result<[i16; 4], Error<I2C::Error, R::Error>> {
737 Ok([self.read_channel_event(Mux::A0, rdy).await?, self.read_channel_event(Mux::A1, rdy).await?,
738 self.read_channel_event(Mux::A2, rdy).await?, self.read_channel_event(Mux::A3, rdy).await?])
739 }
740 pub async fn read_4adc_timed<D: AsyncDelayUs>(&mut self, delay: &mut D) -> Result<[i16; 4], I2C::Error> {
741 Ok([self.read_channel_timed(Mux::A0, delay).await?, self.read_channel_timed(Mux::A1, delay).await?,
742 self.read_channel_timed(Mux::A2, delay).await?, self.read_channel_timed(Mux::A3, delay).await?])
743 }
744 async fn read_diff_event<R: ConversionReady>(&mut self, mux: Mux, rdy: &mut R) -> Result<(bool, u16), Error<I2C::Error, R::Error>> {
746 Ok(signed_to_polarity_magnitude(self.read_channel_event(mux, rdy).await?))
747 }
748 pub async fn read_a0_a1_async<R: ConversionReady>(&mut self, rdy: &mut R) -> Result<(bool, u16), Error<I2C::Error, R::Error>> { self.read_diff_event(Mux::A0N1, rdy).await }
749 pub async fn read_a0_a3_async<R: ConversionReady>(&mut self, rdy: &mut R) -> Result<(bool, u16), Error<I2C::Error, R::Error>> { self.read_diff_event(Mux::A0N3, rdy).await }
750 pub async fn read_a1_a3_async<R: ConversionReady>(&mut self, rdy: &mut R) -> Result<(bool, u16), Error<I2C::Error, R::Error>> { self.read_diff_event(Mux::A1N3, rdy).await }
751 pub async fn read_a2_a3_async<R: ConversionReady>(&mut self, rdy: &mut R) -> Result<(bool, u16), Error<I2C::Error, R::Error>> { self.read_diff_event(Mux::A2N3, rdy).await }
752 pub async fn next_conversion<R: ConversionReady>(&mut self, rdy: &mut R) -> Result<i16, Error<I2C::Error, R::Error>> {
761 debug_assert_rdy(&self.config, "ADS1115::next_conversion");
762 let pol = ConversionReadyPolarity::from(self.config.comp_pol);
763 rdy.arm(pol);
764 rdy.wait_for_ready(pol).await.map_err(Error::Wait)?;
765 self.read_conversion_async().await.map_err(Error::I2c)
766 }
767 pub async fn continuous<'a, 'r, R: ConversionReady>(&'a mut self, mux: Mux, rdy: &'r mut R) -> Result<Continuous<'a, 'r, I2C, R, 5>, I2C::Error> {
774 debug_assert_rdy(&self.config, "ADS1115::continuous");
775 rdy.arm(ConversionReadyPolarity::from(self.config.comp_pol));
776 self.start_continuous_async_unchecked(mux).await?;
777 Ok(Continuous { adc: self, rdy })
778 }
779 }
780
781 pub struct Continuous<'a, 'r, I2C, RDY, const MODEL: u8> {
787 adc: &'a mut ADS111x<I2C, MODEL>,
788 rdy: &'r mut RDY,
789 }
790
791 impl<I2C: AsyncI2c, RDY: ConversionReady> Continuous<'_, '_, I2C, RDY, 5> {
792 pub async fn next(&mut self) -> Result<i16, Error<I2C::Error, RDY::Error>> {
799 self.adc.next_conversion(self.rdy).await
800 }
801 }
802
803 impl<I2C: AsyncI2c, RDY: ConversionReady> Continuous<'_, '_, I2C, RDY, 4> {
804 pub async fn next(&mut self) -> Result<i16, Error<I2C::Error, RDY::Error>> {
807 self.adc.next_conversion(self.rdy).await
808 }
809 }
810
811 #[cfg(feature = "embassy")]
815 async fn timer_wait_us(us: u32) {
816 embassy_time::Timer::after(embassy_time::Duration::from_micros(us as u64)).await
817 }
818
819 #[cfg(feature = "embassy")]
820 impl<I2C: AsyncI2c> ADS1113<I2C> {
821 pub async fn read_adc_timer(&mut self) -> Result<i16, I2C::Error> {
823 self.start_conversion_async().await?;
824 timer_wait_us(conversion_period_us(self.config.data_rate)).await;
825 self.read_conversion_async().await
826 }
827 pub async fn start_continuous_timer(&mut self) -> Result<(), I2C::Error> {
830 let b = build_config_bytes_ads1113_continuous(self.config.data_rate);
831 write_config_async(&mut self.i2c, self.address as u8, b).await
832 }
833 pub async fn next_timer(&mut self) -> Result<i16, I2C::Error> {
834 timer_wait_us(conversion_period_us(self.config.data_rate)).await;
835 self.read_conversion_async().await
836 }
837 }
838
839 #[cfg(feature = "embassy")]
840 impl<I2C: AsyncI2c> ADS1114<I2C> {
841 pub async fn read_adc_timer(&mut self) -> Result<i16, I2C::Error> {
842 self.start_conversion_async().await?;
843 timer_wait_us(conversion_period_us(self.config.data_rate)).await;
844 self.read_conversion_async().await
845 }
846 pub async fn continuous_timer(&mut self) -> Result<ContinuousTimer<'_, I2C, 4>, I2C::Error> {
847 let dr = self.config.data_rate;
848 self.start_continuous_async_unchecked().await?;
849 Ok(ContinuousTimer { adc: self, period_us: conversion_period_us(dr) })
851 }
852 }
853
854 #[cfg(feature = "embassy")]
855 impl<I2C: AsyncI2c> ADS1115<I2C> {
856 pub async fn read_channel_timer(&mut self, mux: Mux) -> Result<i16, I2C::Error> {
858 self.start_conversion_async(mux).await?;
859 timer_wait_us(conversion_period_us(self.config.data_rate)).await;
860 self.read_conversion_async().await
861 }
862 pub async fn read_adc_a0_timer(&mut self) -> Result<i16, I2C::Error> { self.read_channel_timer(Mux::A0).await }
863 pub async fn read_adc_a1_timer(&mut self) -> Result<i16, I2C::Error> { self.read_channel_timer(Mux::A1).await }
864 pub async fn read_adc_a2_timer(&mut self) -> Result<i16, I2C::Error> { self.read_channel_timer(Mux::A2).await }
865 pub async fn read_adc_a3_timer(&mut self) -> Result<i16, I2C::Error> { self.read_channel_timer(Mux::A3).await }
866 async fn read_diff_timer(&mut self, mux: Mux) -> Result<(bool, u16), I2C::Error> {
867 Ok(signed_to_polarity_magnitude(self.read_channel_timer(mux).await?))
868 }
869 pub async fn read_a0_a1_timer(&mut self) -> Result<(bool, u16), I2C::Error> { self.read_diff_timer(Mux::A0N1).await }
870 pub async fn read_a0_a3_timer(&mut self) -> Result<(bool, u16), I2C::Error> { self.read_diff_timer(Mux::A0N3).await }
871 pub async fn read_a1_a3_timer(&mut self) -> Result<(bool, u16), I2C::Error> { self.read_diff_timer(Mux::A1N3).await }
872 pub async fn read_a2_a3_timer(&mut self) -> Result<(bool, u16), I2C::Error> { self.read_diff_timer(Mux::A2N3).await }
873 pub async fn continuous_timer(&mut self, mux: Mux) -> Result<ContinuousTimer<'_, I2C, 5>, I2C::Error> {
878 let dr = self.config.data_rate;
879 self.start_continuous_async_unchecked(mux).await?;
880 Ok(ContinuousTimer { adc: self, period_us: conversion_period_us(dr) })
881 }
882 }
883
884 #[cfg(feature = "embassy")]
886 pub struct ContinuousTimer<'a, I2C, const MODEL: u8> {
887 adc: &'a mut ADS111x<I2C, MODEL>,
888 period_us: u32,
889 }
890
891 #[cfg(feature = "embassy")]
892 impl<I2C: AsyncI2c> ContinuousTimer<'_, I2C, 5> {
893 pub async fn next(&mut self) -> Result<i16, I2C::Error> {
900 timer_wait_us(self.period_us).await;
901 self.adc.read_conversion_async().await
902 }
903 }
904
905 #[cfg(feature = "embassy")]
906 impl<I2C: AsyncI2c> ContinuousTimer<'_, I2C, 4> {
907 pub async fn next(&mut self) -> Result<i16, I2C::Error> {
908 timer_wait_us(self.period_us).await;
909 self.adc.read_conversion_async().await
910 }
911 }
912}
913
914#[derive(Debug, Clone, Copy, Default)]
976pub struct Config {
977 pub gain: Gain,
978 pub data_rate: DataRate,
979 pub comp_mode: CompMode,
980 pub comp_pol: CompPol,
981 pub comp_lat: CompLat,
982 pub comp_que: CompQue,
983}
984
985impl Config {
986 pub fn with_gain(self, gain: Gain) -> Self { Self { gain, ..self } }
987 pub fn with_data_rate(self, data_rate: DataRate) -> Self { Self { data_rate, ..self } }
988 pub fn with_comp_mode(self, comp_mode: CompMode) -> Self { Self { comp_mode, ..self } }
989 pub fn with_comp_pol(self, comp_pol: CompPol) -> Self { Self { comp_pol, ..self } }
990 pub fn with_comp_lat(self, comp_lat: CompLat) -> Self { Self { comp_lat, ..self } }
991 pub fn with_comp_que(self, comp_que: CompQue) -> Self { Self { comp_que, ..self } }
992 pub fn as_conversion_ready(&self) -> Self {
1005 Self { comp_que: CompQue::OneConversion, comp_lat: CompLat::NonLatching, ..*self }
1006 }
1007 pub fn is_conversion_ready(&self) -> bool {
1012 !matches!(self.comp_que, CompQue::DisableComparator)
1013 }
1014}
1015
1016#[inline]
1019fn debug_assert_rdy(config: &Config, what: &str) {
1020 debug_assert!(
1021 config.is_conversion_ready(),
1022 "{what}: COMP_QUE == DisableComparator; call enable_conversion_ready_pin*() or as_conversion_ready() first, else the RDY wait never completes"
1023 );
1024}
1025
1026#[derive(Debug, Clone, Copy, Default)]
1028#[repr(u8)]
1029pub enum Gain {
1030 #[default]
1031 V6_144 = 0,
1032 V4_096 = 1 << 1,
1033 V2_048 = 2 << 1,
1034 V1_024 = 3 << 1,
1035 V0_512 = 4 << 1,
1036 V0_256 = 5 << 1,
1037}
1038
1039#[derive(Debug, Clone, Copy, Default)]
1041#[repr(u8)]
1042pub enum DataRate {
1043 SPS8 = 0,
1044 SPS16 = 1 << 5,
1045 SPS32 = 2 << 5,
1046 SPS64 = 3 << 5,
1047 SPS128 = 4 << 5,
1048 SPS250 = 5 << 5,
1049 SPS475 = 6 << 5,
1050 #[default]
1051 SPS860 = 7 << 5,
1052}
1053
1054#[derive(Debug, Clone, Copy, Default)]
1056#[repr(u8)]
1057pub enum CompMode {
1058 #[default]
1059 Traditional = 0,
1060 Window = 1 << 4,
1061}
1062
1063#[derive(Debug, Clone, Copy, Default)]
1065#[repr(u8)]
1066pub enum CompPol {
1067 #[default]
1068 ActiveLow = 0,
1069 ActiveHigh = 1 << 3,
1070}
1071
1072#[derive(Debug, Clone, Copy, Default)]
1074#[repr(u8)]
1075pub enum CompLat {
1076 #[default]
1077 NonLatching = 0,
1078 Latching = 1 << 2,
1079}
1080
1081#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
1083#[repr(u8)]
1084pub enum CompQue {
1085 OneConversion = 0,
1086 TwoConversions = 1,
1087 FourConversions = 2,
1088 #[default]
1089 DisableComparator = 3,
1090}
1091
1092#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
1093#[repr(u8)]
1094pub enum Address {
1095 #[default]
1096 Ground = 0b1001000,
1097 VDD = 0b1001001,
1098 SDA = 0b1001010,
1099 SCL = 0b1001011,
1100}
1101
1102#[derive(Debug, Clone, Copy)]
1128pub struct DeviceConfig {
1129 pub address: Address,
1130 pub config: Config,
1131 pub mux: Mux,
1132}
1133
1134impl DeviceConfig {
1135 pub fn new(address: Address, config: Config, mux: Mux) -> Self {
1136 Self { address, config, mux }
1137 }
1138}
1139
1140#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1142pub struct Sample {
1143 pub index: usize,
1144 pub address: Address,
1145 pub value: i16,
1146}
1147
1148#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1150pub struct DiffSample {
1151 pub index: usize,
1152 pub address: Address,
1153 pub negative: bool,
1154 pub magnitude: u16,
1155}
1156
1157#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1160pub enum MultiError<I2cError, WaitError = ()> {
1161 DuplicateAddress { first: usize, second: usize, address: Address },
1162 InvalidIndex(usize),
1163 I2c { index: usize, address: Address, error: I2cError },
1164 Wait { index: usize, address: Address, error: WaitError },
1165}
1166
1167pub struct MultiADS1115<I2C, const N: usize> {
1170 i2c: I2C,
1171 devices: [DeviceConfig; N],
1172}
1173
1174pub type ADS1115Array<I2C> = MultiADS1115<I2C, 4>;
1176
1177impl<I2C: embedded_hal::i2c::ErrorType, const N: usize> MultiADS1115<I2C, N> {
1178 pub fn new(i2c: I2C, devices: [DeviceConfig; N]) -> Result<Self, MultiError<I2cErrorOf<I2C>, ()>> {
1181 let _ = &i2c;
1182 let me = Self { i2c, devices };
1183 me.check_unique()?;
1184 Ok(me)
1185 }
1186
1187 fn check_unique(&self) -> Result<(), MultiError<I2cErrorOf<I2C>, ()>> {
1188 let mut i = 0;
1189 while i < N {
1190 let mut j = i + 1;
1191 while j < N {
1192 if self.devices[i].address as u8 == self.devices[j].address as u8 {
1193 return Err(MultiError::DuplicateAddress {
1194 first: i, second: j, address: self.devices[i].address,
1195 });
1196 }
1197 j += 1;
1198 }
1199 i += 1;
1200 }
1201 Ok(())
1202 }
1203
1204 pub fn device(&self, index: usize) -> Option<&DeviceConfig> { self.devices.get(index) }
1205 pub fn device_mut(&mut self, index: usize) -> Option<&mut DeviceConfig> { self.devices.get_mut(index) }
1206 pub fn release(self) -> I2C { self.i2c }
1207}
1208
1209pub trait BusError {
1211 type Error;
1212}
1213impl<T: embedded_hal::i2c::ErrorType> BusError for T {
1214 type Error = T::Error;
1215}
1216type I2cErrorOf<B> = <B as BusError>::Error;
1217
1218fn multi_write_config<I2C: I2c>(i2c: &mut I2C, addr: u8, b: [u8; 2]) -> Result<(), I2C::Error> {
1219 i2c.write(addr, &[REG_CONFIG, b[0], b[1]])
1220}
1221fn multi_read_conv<I2C: I2c>(i2c: &mut I2C, addr: u8) -> Result<i16, I2C::Error> {
1222 let mut d = [0u8; 2];
1223 i2c.write_read(addr, &[REG_CONVERSION], &mut d)?;
1224 Ok(i16::from_be_bytes(d))
1225}
1226fn multi_wait<I2C: I2c>(i2c: &mut I2C, addr: u8) -> Result<(), I2C::Error> {
1227 let mut buf = [0u8; 2];
1228 loop {
1229 i2c.write_read(addr, &[REG_CONFIG], &mut buf)?;
1230 if conversion_complete(buf[0]) { break; }
1231 }
1232 Ok(())
1233}
1234
1235impl<I2C: I2c, const N: usize> MultiADS1115<I2C, N> {
1236 fn start_idx(&mut self, index: usize, mux: Mux) -> Result<(), MultiError<I2C::Error, ()>> {
1237 let dev = *self.devices.get(index).ok_or(MultiError::InvalidIndex(index))?;
1238 let (addr, cfg) = (dev.address, dev.config);
1239 let b = build_config_bytes(&cfg, mux as u8, true, Mode::SingleShot);
1240 multi_write_config(&mut self.i2c, addr as u8, b)
1241 .map_err(|e| MultiError::I2c { index, address: addr, error: e })
1242 }
1243
1244 pub fn start_conversion(&mut self, index: usize, mux: Mux) -> Result<(), MultiError<I2C::Error, ()>> {
1246 self.start_idx(index, mux)
1247 }
1248
1249 pub fn start_all(&mut self, muxes: [Mux; N]) -> Result<(), MultiError<I2C::Error, ()>> {
1261 let mut i = 0;
1262 while i < N {
1263 self.start_idx(i, muxes[i])?;
1264 i += 1;
1265 }
1266 Ok(())
1267 }
1268
1269 fn read_idx(&mut self, index: usize) -> Result<Sample, MultiError<I2C::Error, ()>> {
1270 let addr = self.devices.get(index).map(|d| d.address).ok_or(MultiError::InvalidIndex(index))?;
1271 multi_wait(&mut self.i2c, addr as u8)
1272 .map_err(|e| MultiError::I2c { index, address: addr, error: e })?;
1273 let v = multi_read_conv(&mut self.i2c, addr as u8)
1274 .map_err(|e| MultiError::I2c { index, address: addr, error: e })?;
1275 Ok(Sample { index, address: addr, value: v })
1276 }
1277
1278 pub fn capture_parallel(&mut self, muxes: [Mux; N]) -> Result<[Sample; N], MultiError<I2C::Error, ()>>
1281 where [Sample; N]: Default {
1282 self.start_all(muxes)?;
1283 let mut out: [Sample; N] = Default::default();
1284 let mut i = 0;
1285 while i < N {
1286 out.as_mut()[i] = self.read_idx(i)?;
1287 i += 1;
1288 }
1289 Ok(out)
1290 }
1291
1292 pub fn capture_all(&mut self) -> Result<[Sample; N], MultiError<I2C::Error, ()>>
1294 where [Sample; N]: Default {
1295 let mut muxes: [Mux; N] = [Mux::A0; N];
1296 let mut i = 0;
1297 while i < N {
1298 muxes[i] = self.devices[i].mux;
1299 i += 1;
1300 }
1301 self.capture_parallel(muxes)
1302 }
1303
1304 pub fn capture_parallel_diff(&mut self, muxes: [Mux; N]) -> Result<[DiffSample; N], MultiError<I2C::Error, ()>>
1306 where [DiffSample; N]: Default {
1307 self.start_all(muxes)?;
1308 let mut out: [DiffSample; N] = Default::default();
1309 let mut i = 0;
1310 while i < N {
1311 let s = self.read_idx(i)?;
1312 let (negative, magnitude) = signed_to_polarity_magnitude(s.value);
1313 out.as_mut()[i] = DiffSample { index: i, address: s.address, negative, magnitude };
1314 i += 1;
1315 }
1316 Ok(out)
1317 }
1318
1319 pub fn start_continuous_all(&mut self, muxes: [Mux; N]) -> Result<(), MultiError<I2C::Error, ()>> {
1326 let mut i = 0;
1327 while i < N {
1328 let (addr, cfg) = (self.devices[i].address, self.devices[i].config);
1329 let b = build_config_bytes(&cfg, muxes[i] as u8, false, Mode::Continuous);
1330 multi_write_config(&mut self.i2c, addr as u8, b)
1331 .map_err(|e| MultiError::I2c { index: i, address: addr, error: e })?;
1332 i += 1;
1333 }
1334 Ok(())
1335 }
1336
1337 pub fn next_all_timed(
1348 &mut self,
1349 mut delay_us: impl FnMut(u32),
1350 ) -> Result<[Sample; N], MultiError<I2C::Error, ()>>
1351 where [Sample; N]: Default {
1352 let mut period = 0;
1353 let mut i = 0;
1354 while i < N {
1355 let p = conversion_period_us(self.devices[i].config.data_rate);
1356 if p > period {
1357 period = p;
1358 }
1359 i += 1;
1360 }
1361 delay_us(period);
1362 let mut out: [Sample; N] = Default::default();
1363 let mut i = 0;
1364 while i < N {
1365 let dev = self.devices[i];
1366 let v = multi_read_conv(&mut self.i2c, dev.address as u8)
1367 .map_err(|e| MultiError::I2c { index: i, address: dev.address, error: e })?;
1368 out.as_mut()[i] = Sample { index: i, address: dev.address, value: v };
1369 i += 1;
1370 }
1371 Ok(out)
1372 }
1373
1374 }
1376
1377impl Default for Sample {
1378 fn default() -> Self { Self { index: 0, address: Address::Ground, value: 0 } }
1379}
1380impl Default for DiffSample {
1381 fn default() -> Self { Self { index: 0, address: Address::Ground, negative: false, magnitude: 0 } }
1382}
1383
1384#[cfg(feature = "async")]
1388impl<I2C: embedded_hal::i2c::ErrorType, const N: usize> MultiADS1115<I2C, N> {
1389 fn polarities(&self) -> [ConversionReadyPolarity; N] {
1390 core::array::from_fn(|i| {
1391 ConversionReadyPolarity::from(self.devices.get(i).map(|d| d.config.comp_pol).unwrap_or(CompPol::ActiveLow))
1392 })
1393 }
1394 pub fn arm_all_ready<R: ConversionReady>(&self, rdy: &mut [R; N]) {
1404 let mut i = 0;
1405 while i < N {
1406 if let Some(dev) = self.devices.get(i) {
1407 debug_assert_rdy(&dev.config, "MultiADS1115::arm_all_ready");
1408 }
1409 let pol = ConversionReadyPolarity::from(
1410 self.devices.get(i).map(|d| d.config.comp_pol).unwrap_or(CompPol::ActiveLow),
1411 );
1412 rdy[i].arm(pol);
1413 i += 1;
1414 }
1415 }
1416 pub async fn wait_all_ready_async<R: ConversionReady>(
1425 &self,
1426 rdy: &mut [R; N],
1427 ) -> Result<(), MultiError<I2C::Error, R::Error>> {
1428 let mut i = 0;
1429 while i < N {
1430 if let Some(dev) = self.devices.get(i) {
1431 debug_assert_rdy(&dev.config, "MultiADS1115::wait_all_ready_async");
1432 }
1433 i += 1;
1434 }
1435 let pol = self.polarities();
1436 wait_all_ready(rdy, pol).await.map_err(|e| {
1437 let address = self
1438 .devices
1439 .get(e.index)
1440 .map(|d| d.address)
1441 .unwrap_or(Address::Ground);
1442 MultiError::Wait { index: e.index, address, error: e.error }
1443 })
1444 }
1445}
1446
1447#[cfg(feature = "async")]
1448mod multi_async {
1449 use super::*;
1450 use embedded_hal_async::i2c::I2c as AsyncI2c;
1451 async fn mstart<I2C: AsyncI2c>(i2c: &mut I2C, addr: u8, cfg: &Config, mux: Mux) -> Result<(), I2C::Error> {
1452 let b = build_config_bytes(cfg, mux as u8, true, Mode::SingleShot);
1453 i2c.write(addr, &[REG_CONFIG, b[0], b[1]]).await
1454 }
1455 async fn mread<I2C: AsyncI2c>(i2c: &mut I2C, addr: u8) -> Result<i16, I2C::Error> {
1456 let mut d = [0u8; 2];
1457 i2c.write_read(addr, &[REG_CONVERSION], &mut d).await?;
1458 Ok(i16::from_be_bytes(d))
1459 }
1460
1461 fn lift_no_wait<I2cError, WaitError>(
1464 e: MultiError<I2cError, ()>,
1465 ) -> MultiError<I2cError, WaitError> {
1466 match e {
1467 MultiError::DuplicateAddress { first, second, address } => {
1468 MultiError::DuplicateAddress { first, second, address }
1469 }
1470 MultiError::InvalidIndex(i) => MultiError::InvalidIndex(i),
1471 MultiError::I2c { index, address, error } => MultiError::I2c { index, address, error },
1472 MultiError::Wait { .. } => unreachable!("pure read path never waits"),
1473 }
1474 }
1475
1476 impl<I2C: AsyncI2c, const N: usize> MultiADS1115<I2C, N> {
1477 async fn start_idx_a(&mut self, index: usize, mux: Mux) -> Result<(), MultiError<I2C::Error, ()>> {
1478 let dev = *self.devices.get(index).ok_or(MultiError::InvalidIndex(index))?;
1479 mstart(&mut self.i2c, dev.address as u8, &dev.config, mux).await
1480 .map_err(|e| MultiError::I2c { index, address: dev.address, error: e })
1481 }
1482 pub async fn start_all_async(&mut self, muxes: [Mux; N]) -> Result<(), MultiError<I2C::Error, ()>> {
1490 let mut i = 0;
1491 while i < N {
1492 self.start_idx_a(i, muxes[i]).await?;
1493 i += 1;
1494 }
1495 Ok(())
1496 }
1497 async fn read_started_idx(
1498 &mut self,
1499 index: usize,
1500 ) -> Result<Sample, MultiError<I2C::Error, ()>> {
1501 let dev = *self.devices.get(index).ok_or(MultiError::InvalidIndex(index))?;
1502 let v = mread(&mut self.i2c, dev.address as u8).await
1503 .map_err(|e| MultiError::I2c { index, address: dev.address, error: e })?;
1504 Ok(Sample { index, address: dev.address, value: v })
1505 }
1506 pub async fn read_all_async(
1510 &mut self,
1511 ) -> Result<[Sample; N], MultiError<I2C::Error, ()>>
1512 where [Sample; N]: Default {
1513 let mut out: [Sample; N] = Default::default();
1514 let mut i = 0;
1515 while i < N {
1516 out.as_mut()[i] = self.read_started_idx(i).await?;
1517 i += 1;
1518 }
1519 Ok(out)
1520 }
1521 pub async fn capture_parallel_event<R: ConversionReady>(
1536 &mut self, muxes: [Mux; N], rdy: &mut [R; N],
1537 ) -> Result<[Sample; N], MultiError<I2C::Error, R::Error>>
1538 where [Sample; N]: Default {
1539 self.arm_all_ready(rdy);
1540 self.start_all_async(muxes).await.map_err(|e| match e {
1541 MultiError::InvalidIndex(i) => MultiError::InvalidIndex(i),
1542 MultiError::DuplicateAddress { first, second, address } => MultiError::DuplicateAddress { first, second, address },
1543 MultiError::I2c { index, address, error } => MultiError::I2c { index, address, error },
1544 MultiError::Wait { .. } => unreachable!(),
1545 })?;
1546 self.wait_all_ready_async(rdy).await?;
1547 self.read_all_async().await.map_err(lift_no_wait)
1548 }
1549 pub async fn capture_parallel_diff_event<R: ConversionReady>(
1554 &mut self, muxes: [Mux; N], rdy: &mut [R; N],
1555 ) -> Result<[DiffSample; N], MultiError<I2C::Error, R::Error>>
1556 where [DiffSample; N]: Default, [Sample; N]: Default {
1557 let samples = self.capture_parallel_event(muxes, rdy).await?;
1558 let mut out: [DiffSample; N] = Default::default();
1559 let mut i = 0;
1560 while i < N {
1561 let (negative, magnitude) = signed_to_polarity_magnitude(samples[i].value);
1562 out.as_mut()[i] = DiffSample { index: i, address: samples[i].address, negative, magnitude };
1563 i += 1;
1564 }
1565 Ok(out)
1566 }
1567 pub async fn start_continuous_all_async_unchecked(&mut self, muxes: [Mux; N]) -> Result<(), MultiError<I2C::Error, ()>> {
1578 let mut i = 0;
1579 while i < N {
1580 let dev = *self.devices.get(i).ok_or(MultiError::InvalidIndex(i))?;
1581 let b = build_config_bytes(&dev.config, muxes[i] as u8, false, Mode::Continuous);
1582 self.i2c.write(dev.address as u8, &[REG_CONFIG, b[0], b[1]]).await
1583 .map_err(|e| MultiError::I2c { index: i, address: dev.address, error: e })?;
1584 i += 1;
1585 }
1586 Ok(())
1587 }
1588 pub async fn continuous_all_event<R: ConversionReady>(
1603 &mut self,
1604 muxes: [Mux; N],
1605 rdy: &mut [R; N],
1606 ) -> Result<(), MultiError<I2C::Error, ()>> {
1607 self.arm_all_ready(rdy);
1608 self.start_continuous_all_async_unchecked(muxes).await
1609 }
1610 pub async fn next_all_event<R: ConversionReady>(
1620 &mut self, rdy: &mut [R; N],
1621 ) -> Result<[Sample; N], MultiError<I2C::Error, R::Error>>
1622 where [Sample; N]: Default {
1623 self.arm_all_ready(rdy);
1624 self.wait_all_ready_async(rdy).await?;
1625 self.read_all_async().await.map_err(lift_no_wait)
1626 }
1627 }
1628
1629 #[cfg(feature = "embassy")]
1631 impl<I2C: AsyncI2c, const N: usize> MultiADS1115<I2C, N> {
1632 fn max_period_us(&self) -> u32 {
1633 let mut m = 0;
1634 let mut i = 0;
1635 while i < N {
1636 let p = conversion_period_us(self.devices[i].config.data_rate);
1637 if p > m { m = p; }
1638 i += 1;
1639 }
1640 m
1641 }
1642 pub async fn capture_parallel_timer(&mut self, muxes: [Mux; N]) -> Result<[Sample; N], MultiError<I2C::Error, ()>>
1648 where [Sample; N]: Default {
1649 self.start_all_async(muxes).await?;
1650 let period = self.max_period_us();
1651 embassy_time::Timer::after(embassy_time::Duration::from_micros(period as u64)).await;
1652 let mut out: [Sample; N] = Default::default();
1653 let mut i = 0;
1654 while i < N {
1655 let dev = self.devices[i];
1656 let v = mread(&mut self.i2c, dev.address as u8).await
1657 .map_err(|e| MultiError::I2c { index: i, address: dev.address, error: e })?;
1658 out.as_mut()[i] = Sample { index: i, address: dev.address, value: v };
1659 i += 1;
1660 }
1661 Ok(out)
1662 }
1663 pub async fn capture_all_timer(&mut self) -> Result<[Sample; N], MultiError<I2C::Error, ()>>
1664 where [Sample; N]: Default {
1665 let mut muxes: [Mux; N] = [Mux::A0; N];
1666 let mut i = 0;
1667 while i < N {
1668 muxes[i] = self.devices[i].mux;
1669 i += 1;
1670 }
1671 self.capture_parallel_timer(muxes).await
1672 }
1673 pub async fn capture_parallel_diff_timer(&mut self, muxes: [Mux; N]) -> Result<[DiffSample; N], MultiError<I2C::Error, ()>>
1674 where [DiffSample; N]: Default {
1675 self.start_all_async(muxes).await?;
1676 let period = self.max_period_us();
1677 embassy_time::Timer::after(embassy_time::Duration::from_micros(period as u64)).await;
1678 let mut out: [DiffSample; N] = Default::default();
1679 let mut i = 0;
1680 while i < N {
1681 let dev = self.devices[i];
1682 let v = mread(&mut self.i2c, dev.address as u8).await
1683 .map_err(|e| MultiError::I2c { index: i, address: dev.address, error: e })?;
1684 let (negative, magnitude) = signed_to_polarity_magnitude(v);
1685 out.as_mut()[i] = DiffSample { index: i, address: dev.address, negative, magnitude };
1686 i += 1;
1687 }
1688 Ok(out)
1689 }
1690 pub async fn start_continuous_all_timer(&mut self, muxes: [Mux; N]) -> Result<(), MultiError<I2C::Error, ()>> {
1693 self.start_continuous_all_async_unchecked(muxes).await
1694 }
1695 pub async fn next_all_timer(&mut self) -> Result<[Sample; N], MultiError<I2C::Error, ()>>
1696 where [Sample; N]: Default {
1697 let period = self.max_period_us();
1698 embassy_time::Timer::after(embassy_time::Duration::from_micros(period as u64)).await;
1699 let mut out: [Sample; N] = Default::default();
1700 let mut i = 0;
1701 while i < N {
1702 let dev = self.devices[i];
1703 let v = mread(&mut self.i2c, dev.address as u8).await
1704 .map_err(|e| MultiError::I2c { index: i, address: dev.address, error: e })?;
1705 out.as_mut()[i] = Sample { index: i, address: dev.address, value: v };
1706 i += 1;
1707 }
1708 Ok(out)
1709 }
1710 }
1711}
1712
1713#[cfg(test)]
1714mod tests {
1715 extern crate std;
1716 use super::*;
1717
1718 #[test]
1719 fn config_bytes_mux_gain_dr() {
1720 let cfg = Config { gain: Gain::V2_048, data_rate: DataRate::SPS128, ..Default::default() };
1721 let b = build_config_bytes(&cfg, Mux::A0 as u8, true, Mode::SingleShot);
1723 assert_eq!(b[0], 0x80 | (0b100 << 4) | 0x04 | 0x01);
1724 assert_eq!(b[1], (4 << 5) | 3); assert!(conversion_complete(0x80) && !conversion_complete(0x00));
1726 }
1727
1728 #[test]
1729 fn all_mux_bits() {
1730 for (m, bits) in [(Mux::A0N1,0),(Mux::A0N3,1),(Mux::A1N3,2),(Mux::A2N3,3),(Mux::A0,4),(Mux::A1,5),(Mux::A2,6),(Mux::A3,7)] {
1731 let b = build_config_bytes(&Config::default(), m as u8, true, Mode::SingleShot);
1732 assert_eq!((b[0] >> 4) & 7, bits);
1733 }
1734 }
1735
1736 #[test]
1737 fn ads1113_ignores_pga() {
1738 let b = build_config_bytes_ads1113(DataRate::SPS860, true);
1739 assert_eq!(b[0] & 0x0E, 0); assert_eq!(b[1] & 3, 3); }
1742
1743 #[test]
1744 fn continuous_clears_mode_bit() {
1745 let b = build_config_bytes(&Config::default(), Mux::A0 as u8, false, Mode::Continuous);
1746 assert_eq!(b[0] & 1, 0);
1747 assert_eq!(b[0] & 0x80, 0, "continuous must not set OS=1");
1748 let s = build_config_bytes(&Config::default(), Mux::A0 as u8, true, Mode::SingleShot);
1749 assert_eq!(s[0] & 1, 1);
1750 assert_ne!(s[0] & 0x80, 0);
1751 #[cfg(feature = "embassy")]
1753 {
1754 let c = build_config_bytes_ads1113_continuous(DataRate::SPS128);
1755 assert_eq!(c, [0, DataRate::SPS128 as u8 | 0x03]);
1756 }
1757 }
1758
1759 #[cfg(feature = "embassy")]
1760 #[test]
1761 fn embassy_timer_api_no_poll() {
1762 let src = include_str!("lib.rs");
1765 for name in ["fn read_channel_timer", "fn continuous_timer", "fn read_a0_a1_timer",
1766 "fn read_adc_a0_timer", "Timer::after", "ContinuousTimer"] {
1767 assert!(src.contains(name), "missing {name}");
1768 }
1769 let m = src.find("mod async_api").expect("async_api");
1770 let end = src[m..].find("/// Embassy integration").map(|e| m + e).unwrap_or(src.len());
1771 assert!(!src[m..end].contains("read_asyncadc"));
1772 }
1773
1774 #[test]
1775 fn rdy_threshold_values() {
1776 let cfg = Config::default().as_conversion_ready();
1778 assert_ne!(cfg.comp_que as u8, 3);
1779 assert_eq!([0x80u8, 0x00u8], [0x80, 0x00]); assert_eq!([0x00u8, 0x00u8], [0x00, 0x00]); }
1782
1783 #[test]
1784 fn polarity_matches_comp_pol() {
1785 assert_eq!(ConversionReadyPolarity::from(CompPol::ActiveLow), ConversionReadyPolarity::ActiveLow);
1786 assert_eq!(ConversionReadyPolarity::from(CompPol::ActiveHigh), ConversionReadyPolarity::ActiveHigh);
1787 assert!(conversion_period_us(DataRate::SPS8) > conversion_period_us(DataRate::SPS860));
1788 }
1789
1790 #[test]
1791 fn polarity_magnitude() {
1792 assert_eq!(signed_to_polarity_magnitude(0), (false, 0));
1793 assert_eq!(signed_to_polarity_magnitude(123), (false, 123));
1794 assert_eq!(signed_to_polarity_magnitude(-123), (true, 123));
1795 assert_eq!(signed_to_polarity_magnitude(i16::MAX), (false, 32767));
1796 assert_eq!(signed_to_polarity_magnitude(i16::MIN), (true, 32768));
1797 }
1798
1799 #[test]
1800 fn diff_mux_mappings() {
1801 assert_eq!(Mux::A0N1 as u8, 0b000);
1802 assert_eq!(Mux::A0N3 as u8, 0b001);
1803 assert_eq!(Mux::A1N3 as u8, 0b010);
1804 assert_eq!(Mux::A2N3 as u8, 0b011);
1805 for (m, bits) in [(Mux::A0N1, 0), (Mux::A0N3, 1), (Mux::A1N3, 2), (Mux::A2N3, 3)] {
1806 let b = build_config_bytes(&Config::default(), m as u8, true, Mode::SingleShot);
1807 assert_eq!((b[0] >> 4) & 7, bits);
1808 }
1809 let c = Config::default().as_conversion_ready();
1811 assert_ne!(c.comp_que as u8, 3);
1812 assert_eq!(c.comp_lat as u8, 0);
1813 }
1814
1815 #[cfg(feature = "async")]
1816 #[test]
1817 fn async_recommended_api_has_no_poll_loop() { let src = include_str!("lib.rs");
1820 let m = src.find("mod async_api").expect("async_api");
1821 let end = src[m..].find("mod tests").map(|e| m + e).unwrap_or(src.len());
1822 let body = &src[m..end];
1823 for name in ["fn read_channel_event", "fn read_channel_timed", "fn next_conversion", "fn continuous",
1827 "fn start_all_async", "fn capture_parallel_event", "fn capture_parallel_timer", "fn next_all_timer",
1828 "fn wait_all_ready_async", "fn read_all_async", "fn next_all_event"] {
1829 let i = body.find(name).unwrap_or_else(|| panic!("missing {name}"));
1830 let fn_body = &body[i..body[i..].find("/// ").map(|e| i + e).unwrap_or(body.len())];
1831 let fn_body = &fn_body[..fn_body.find("\n }\n").unwrap_or(fn_body.len())];
1832 assert!(!fn_body.contains("loop {"), "{name} must not poll");
1833 }
1834 assert!(!body.contains("read_asyncadc") && !body.contains("read_async_adc") && !body.contains("read_async_4adc"));
1835 for must in ["wait_all_ready(", "JoinAllReady", "read_all_async"] {
1839 assert!(src.contains(must), "missing concurrent primitive {must}");
1840 }
1841 }
1842
1843 #[cfg(feature = "async")]
1845 struct PulseRdy<'c> {
1846 clock: &'c std::cell::Cell<u32>,
1847 log: &'c std::cell::RefCell<std::vec::Vec<(u8, usize)>>,
1848 id: usize,
1849 armed_at: std::cell::Cell<Option<u32>>,
1850 arms: std::cell::Cell<u32>,
1851 polls: std::cell::Cell<u32>,
1852 fire_after: u32,
1853 deadline: u32,
1854 }
1855 #[cfg(feature = "async")]
1856 struct PulseFut<'a, 'c> {
1857 rdy: &'a PulseRdy<'c>,
1858 }
1859 #[cfg(feature = "async")]
1860 impl<'c> ConversionReady for PulseRdy<'c> {
1861 type Error = core::convert::Infallible;
1862 type WaitFuture<'a> = PulseFut<'a, 'c> where Self: 'a;
1863 fn arm(&mut self, _pol: ConversionReadyPolarity) {
1864 self.armed_at.set(Some(self.clock.get()));
1870 self.arms.set(self.arms.get() + 1);
1871 self.log.borrow_mut().push((0, self.id));
1872 }
1873 fn wait_for_ready(&mut self, _pol: ConversionReadyPolarity) -> Self::WaitFuture<'_> {
1874 self.log.borrow_mut().push((2, self.id));
1876 PulseFut { rdy: self }
1877 }
1878 }
1879 #[cfg(feature = "async")]
1880 impl core::future::Future for PulseFut<'_, '_> {
1881 type Output = Result<(), core::convert::Infallible>;
1882 fn poll(
1883 self: core::pin::Pin<&mut Self>,
1884 cx: &mut core::task::Context<'_>,
1885 ) -> core::task::Poll<Self::Output> {
1886 let r = self.rdy;
1887 let armed = match r.armed_at.get() {
1890 Some(t) => t,
1891 None => return core::task::Poll::Pending,
1892 };
1893 if armed > r.deadline {
1895 return core::task::Poll::Pending; }
1897 let p = r.polls.get() + 1;
1898 r.polls.set(p);
1899 if p >= r.fire_after {
1900 core::task::Poll::Ready(Ok(()))
1901 } else {
1902 cx.waker().wake_by_ref();
1903 core::task::Poll::Pending
1904 }
1905 }
1906 }
1907
1908 #[cfg(feature = "async")]
1909 #[test]
1910 fn wait_all_ready_arms_every_detector_upfront() {
1911 use std::sync::Arc;
1912 struct Noop;
1913 impl std::task::Wake for Noop {
1914 fn wake(self: Arc<Self>) {}
1915 }
1916 let waker = std::task::Waker::from(Arc::new(Noop));
1917 let clock = std::cell::Cell::new(0u32);
1918 let log = std::cell::RefCell::new(std::vec::Vec::new());
1919 let mut rdy: [PulseRdy; 4] = core::array::from_fn(|id| PulseRdy {
1925 clock: &clock,
1926 log: &log,
1927 id,
1928 armed_at: std::cell::Cell::new(None),
1929 arms: std::cell::Cell::new(0),
1930 polls: std::cell::Cell::new(0),
1931 fire_after: 2,
1932 deadline: 0,
1933 });
1934 for r in rdy.iter_mut() {
1935 r.arm(ConversionReadyPolarity::ActiveLow);
1936 }
1937 assert_eq!(log.borrow().len(), 4, "all detectors armed before first poll");
1938 let mut join = wait_all_ready(&mut rdy, [ConversionReadyPolarity::ActiveLow; 4]);
1939 let mut join = unsafe { core::pin::Pin::new_unchecked(&mut join) };
1940 let mut cx = core::task::Context::from_waker(&waker);
1941 let mut rounds = 0;
1942 let done = loop {
1943 clock.set(rounds);
1944 match join.as_mut().poll(&mut cx) {
1945 core::task::Poll::Ready(r) => break r,
1946 core::task::Poll::Pending => {}
1947 }
1948 rounds += 1;
1949 assert!(rounds < 100, "RDY pulse missed: detectors not observed concurrently");
1950 };
1951 assert!(done.is_ok());
1952 for r in rdy.iter() {
1953 assert_eq!(r.armed_at.get(), Some(0), "every detector armed before START");
1954 }
1955 }
1956
1957 #[cfg(feature = "async")]
1958 #[test]
1959 fn unarmed_join_observes_nothing() {
1960 use std::sync::Arc;
1964 struct Noop;
1965 impl std::task::Wake for Noop {
1966 fn wake(self: Arc<Self>) {}
1967 }
1968 let waker = std::task::Waker::from(Arc::new(Noop));
1969 let clock = std::cell::Cell::new(0u32);
1970 let log = std::cell::RefCell::new(std::vec::Vec::new());
1971 let mut rdy: [PulseRdy; 2] = core::array::from_fn(|id| PulseRdy {
1972 clock: &clock,
1973 log: &log,
1974 id,
1975 armed_at: std::cell::Cell::new(None),
1976 arms: std::cell::Cell::new(0),
1977 polls: std::cell::Cell::new(0),
1978 fire_after: 1,
1979 deadline: u32::MAX,
1980 });
1981 let mut join = wait_all_ready(&mut rdy, [ConversionReadyPolarity::ActiveLow; 2]);
1982 let mut join = unsafe { core::pin::Pin::new_unchecked(&mut join) };
1983 let mut cx = core::task::Context::from_waker(&waker);
1984 let mut ready = false;
1985 for _ in 0..20 {
1986 if matches!(join.as_mut().poll(&mut cx), core::task::Poll::Ready(_)) {
1987 ready = true;
1988 break;
1989 }
1990 }
1991 assert!(!ready, "un-armed detectors must observe nothing");
1992 }
1993
1994 #[cfg(feature = "async")]
1996 struct FailRdy {
1997 fail: bool,
1998 armed: std::cell::Cell<bool>,
1999 }
2000 #[cfg(feature = "async")]
2001 struct FailFut<'a> {
2002 rdy: &'a FailRdy,
2003 }
2004 #[cfg(feature = "async")]
2005 impl ConversionReady for FailRdy {
2006 type Error = MockErr;
2007 type WaitFuture<'a> = FailFut<'a> where Self: 'a;
2008 fn arm(&mut self, _pol: ConversionReadyPolarity) {
2009 self.armed.set(true);
2010 }
2011 fn wait_for_ready(&mut self, _pol: ConversionReadyPolarity) -> Self::WaitFuture<'_> {
2012 FailFut { rdy: self }
2013 }
2014 }
2015 #[cfg(feature = "async")]
2016 impl core::future::Future for FailFut<'_> {
2017 type Output = Result<(), MockErr>;
2018 fn poll(
2019 self: core::pin::Pin<&mut Self>,
2020 cx: &mut core::task::Context<'_>,
2021 ) -> core::task::Poll<Self::Output> {
2022 if self.rdy.fail {
2023 return core::task::Poll::Ready(Err(MockErr));
2024 }
2025 if self.rdy.armed.get() {
2026 core::task::Poll::Ready(Ok(()))
2027 } else {
2028 cx.waker().wake_by_ref();
2029 core::task::Poll::Pending
2030 }
2031 }
2032 }
2033
2034 #[cfg(feature = "async")]
2035 #[test]
2036 fn wait_failure_attributes_correct_device() {
2037 let mut rdy = [
2040 FailRdy { fail: false, armed: std::cell::Cell::new(false) },
2041 FailRdy { fail: false, armed: std::cell::Cell::new(false) },
2042 FailRdy { fail: true, armed: std::cell::Cell::new(false) },
2043 FailRdy { fail: false, armed: std::cell::Cell::new(false) },
2044 ];
2045 for r in rdy.iter_mut() {
2046 r.arm(ConversionReadyPolarity::ActiveLow);
2047 }
2048 let err = block_on(wait_all_ready(&mut rdy, [ConversionReadyPolarity::ActiveLow; 4]));
2049 match err {
2050 Err(WaitFailed { index: 2, .. }) => {}
2051 other => panic!("expected failure at index 2, got {other:?}"),
2052 }
2053
2054 let cfg = Config::default().as_conversion_ready();
2055 let multi = MultiADS1115::new(
2056 MockI2c::new(),
2057 [
2058 DeviceConfig::new(Address::Ground, cfg, Mux::A0),
2059 DeviceConfig::new(Address::VDD, cfg, Mux::A1),
2060 DeviceConfig::new(Address::SDA, cfg, Mux::A2),
2061 DeviceConfig::new(Address::SCL, cfg, Mux::A3),
2062 ],
2063 )
2064 .unwrap();
2065 let mut rdy = [
2066 FailRdy { fail: false, armed: std::cell::Cell::new(false) },
2067 FailRdy { fail: false, armed: std::cell::Cell::new(false) },
2068 FailRdy { fail: true, armed: std::cell::Cell::new(false) },
2069 FailRdy { fail: false, armed: std::cell::Cell::new(false) },
2070 ];
2071 let err = block_on(multi.wait_all_ready_async(&mut rdy));
2072 match err {
2073 Err(MultiError::Wait { index: 2, address: Address::SDA, .. }) => {}
2074 other => panic!("expected Wait{{index 2, SDA}}, got {other:?}"),
2075 }
2076 }
2077
2078 #[cfg(feature = "async")]
2080 struct AsyncMockI2c<'c> {
2081 log: &'c std::cell::RefCell<std::vec::Vec<(u8, usize)>>,
2082 canned: [(u8, i16); 2],
2083 }
2084 #[cfg(feature = "async")]
2085 impl embedded_hal::i2c::ErrorType for AsyncMockI2c<'_> {
2086 type Error = MockErr;
2087 }
2088 #[cfg(feature = "async")]
2089 impl embedded_hal_async::i2c::I2c for AsyncMockI2c<'_> {
2090 async fn read(&mut self, _a: u8, _b: &mut [u8]) -> Result<(), Self::Error> { Ok(()) }
2091 async fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> {
2092 if !bytes.is_empty() && bytes[0] == REG_CONFIG {
2093 self.log.borrow_mut().push((1, (addr - 0x48) as usize));
2096 }
2097 Ok(())
2098 }
2099 async fn write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
2100 if write == [REG_CONVERSION] {
2101 let v = self.canned.iter().find(|(a, _)| *a == addr).map(|(_, v)| *v).unwrap_or(0);
2102 read.copy_from_slice(&v.to_be_bytes()[..read.len().min(2)]);
2103 }
2104 Ok(())
2105 }
2106 async fn transaction(
2107 &mut self,
2108 _a: u8,
2109 _o: &mut [embedded_hal::i2c::Operation<'_>],
2110 ) -> Result<(), Self::Error> {
2111 Ok(())
2112 }
2113 }
2114
2115 #[cfg(feature = "async")]
2116 fn block_on<F: core::future::Future>(mut f: F) -> F::Output {
2117 use std::sync::Arc;
2118 struct Noop;
2119 impl std::task::Wake for Noop {
2120 fn wake(self: Arc<Self>) {}
2121 }
2122 let waker = std::task::Waker::from(Arc::new(Noop));
2123 let mut cx = core::task::Context::from_waker(&waker);
2124 let mut f = unsafe { core::pin::Pin::new_unchecked(&mut f) };
2126 let mut rounds = 0u32;
2127 loop {
2128 match f.as_mut().poll(&mut cx) {
2129 core::task::Poll::Ready(v) => return v,
2130 core::task::Poll::Pending => {}
2131 }
2132 rounds += 1;
2133 assert!(rounds < 1000, "async test future stalled");
2134 }
2135 }
2136
2137 #[cfg(feature = "async")]
2138 #[test]
2139 fn capture_parallel_event_arms_before_any_start() {
2140 let clock = std::cell::Cell::new(0u32);
2141 let log = std::cell::RefCell::new(std::vec::Vec::new());
2142 let i2c = AsyncMockI2c { log: &log, canned: [(0x48, 1000), (0x49, -2000)] };
2143 let cfg = Config::default().with_data_rate(DataRate::SPS860).as_conversion_ready();
2144 let mut multi = MultiADS1115::new(
2145 i2c,
2146 [DeviceConfig::new(Address::Ground, cfg, Mux::A0), DeviceConfig::new(Address::VDD, cfg, Mux::A1)],
2147 )
2148 .unwrap();
2149 let mut rdy: [PulseRdy; 2] = core::array::from_fn(|id| PulseRdy {
2150 clock: &clock,
2151 log: &log,
2152 id,
2153 armed_at: std::cell::Cell::new(None),
2154 arms: std::cell::Cell::new(0),
2155 polls: std::cell::Cell::new(0),
2156 fire_after: 1,
2157 deadline: u32::MAX,
2158 });
2159 let samples = block_on(multi.capture_parallel_event([Mux::A0, Mux::A1], &mut rdy)).unwrap();
2160 assert_eq!([samples[0].value, samples[1].value], [1000, -2000]);
2161 assert_eq!([samples[0].address, samples[1].address], [Address::Ground, Address::VDD]);
2162 let log = log.borrow();
2164 let first_start = log.iter().position(|(t, _)| *t == 1).expect("starts logged");
2165 assert!(log.iter().take(first_start).all(|(t, _)| *t == 0));
2166 assert_eq!(log.iter().filter(|(t, _)| *t == 0).count(), 2, "both detectors armed");
2167 assert_eq!(log.iter().filter(|(t, _)| *t == 1).count(), 2, "both ADCs started");
2168 }
2169
2170 #[cfg(feature = "async")]
2171 #[test]
2172 fn continuous_all_event_arms_before_any_start() {
2173 let clock = std::cell::Cell::new(0u32);
2177 let log = std::cell::RefCell::new(std::vec::Vec::new());
2178 let i2c = AsyncMockI2c { log: &log, canned: [(0x48, 1000), (0x49, -2000)] };
2179 let cfg = Config::default().with_data_rate(DataRate::SPS860).as_conversion_ready();
2180 let mut multi = MultiADS1115::new(
2181 i2c,
2182 [DeviceConfig::new(Address::Ground, cfg, Mux::A0), DeviceConfig::new(Address::VDD, cfg, Mux::A1)],
2183 )
2184 .unwrap();
2185 let mut rdy: [PulseRdy; 2] = core::array::from_fn(|id| PulseRdy {
2186 clock: &clock,
2187 log: &log,
2188 id,
2189 armed_at: std::cell::Cell::new(None),
2190 arms: std::cell::Cell::new(0),
2191 polls: std::cell::Cell::new(0),
2192 fire_after: 1,
2193 deadline: u32::MAX,
2194 });
2195 block_on(multi.continuous_all_event([Mux::A0, Mux::A1], &mut rdy)).unwrap();
2196 {
2199 let log = log.borrow();
2200 let first_start = log.iter().position(|(t, _)| *t == 1).expect("starts logged");
2201 assert!(log.iter().take(first_start).all(|(t, _)| *t == 0));
2202 assert_eq!(log.iter().filter(|(t, _)| *t == 0).count(), 2, "both detectors armed");
2203 assert_eq!(log.iter().filter(|(t, _)| *t == 1).count(), 2, "both ADCs started once");
2204 }
2205 let samples = block_on(multi.next_all_event(&mut rdy)).unwrap();
2207 assert_eq!([samples[0].value, samples[1].value], [1000, -2000]);
2208 let log = log.borrow();
2209 let tags: std::vec::Vec<u8> = log.iter().map(|(t, _)| *t).collect();
2210 assert_eq!(&tags[..6], &[0, 0, 1, 1, 0, 0], "arm,arm,start,start then re-arm,re-arm");
2211 assert_eq!(tags.iter().filter(|t| **t == 2).count(), 2, "both waits observed");
2212 }
2213
2214 #[cfg(feature = "async")]
2215 #[test]
2216 fn single_shot_event_arms_before_start() {
2217 let clock = std::cell::Cell::new(0u32);
2220 let log = std::cell::RefCell::new(std::vec::Vec::new());
2221 let i2c = AsyncMockI2c { log: &log, canned: [(0x48, 555), (0x49, 0)] };
2222 let mut adc = ADS1115::new(Address::Ground, i2c, Config::default().with_data_rate(DataRate::SPS860).as_conversion_ready());
2223 let mut rdy = PulseRdy {
2224 clock: &clock,
2225 log: &log,
2226 id: 0,
2227 armed_at: std::cell::Cell::new(None),
2228 arms: std::cell::Cell::new(0),
2229 polls: std::cell::Cell::new(0),
2230 fire_after: 1,
2231 deadline: u32::MAX,
2232 };
2233 let v = block_on(adc.read_channel_event(Mux::A0, &mut rdy)).unwrap();
2234 assert_eq!(v, 555);
2235 let log = log.borrow();
2236 assert_eq!(log.as_slice(), &[(0, 0), (1, 0), (2, 0)], "arm must precede CONFIG START");
2238 }
2239
2240 #[cfg(feature = "async")]
2241 #[test]
2242 fn continuous_next_rearms_every_cycle() {
2243 let clock = std::cell::Cell::new(0u32);
2248 let log = std::cell::RefCell::new(std::vec::Vec::new());
2249 let i2c = AsyncMockI2c { log: &log, canned: [(0x48, 111), (0x49, 0)] };
2251 let mut adc = ADS1115::new(Address::Ground, i2c, Config::default().as_conversion_ready());
2252 let mut rdy = PulseRdy {
2253 clock: &clock,
2254 log: &log,
2255 id: 0,
2256 armed_at: std::cell::Cell::new(None),
2257 arms: std::cell::Cell::new(0),
2258 polls: std::cell::Cell::new(0),
2259 fire_after: 1,
2260 deadline: u32::MAX,
2261 };
2262 let mut stream = block_on(adc.continuous(Mux::A0, &mut rdy)).unwrap();
2263 assert_eq!(block_on(stream.next()).unwrap(), 111);
2264 assert_eq!(block_on(stream.next()).unwrap(), 111);
2265 drop(stream);
2266 assert_eq!(
2267 log.borrow().as_slice(),
2268 &[(0, 0), (1, 0), (0, 0), (2, 0), (0, 0), (2, 0)],
2269 "continuous() arms before START; every next() re-arms before waiting"
2270 );
2271 assert_eq!(rdy.arms.get(), 3, "constructor + one re-arm per next()");
2272 log.borrow_mut().clear();
2274 let i2c = AsyncMockI2c { log: &log, canned: [(0x48, 222), (0x49, 0)] };
2275 let mut adc = ADS1114::new(i2c, Config::default().as_conversion_ready());
2276 let mut rdy = PulseRdy {
2277 clock: &clock,
2278 log: &log,
2279 id: 0,
2280 armed_at: std::cell::Cell::new(None),
2281 arms: std::cell::Cell::new(0),
2282 polls: std::cell::Cell::new(0),
2283 fire_after: 1,
2284 deadline: u32::MAX,
2285 };
2286 let mut stream = block_on(adc.continuous(&mut rdy)).unwrap();
2287 assert_eq!(block_on(stream.next()).unwrap(), 222);
2288 drop(stream);
2289 assert_eq!(
2290 log.borrow().as_slice(),
2291 &[(0, 0), (1, 0), (0, 0), (2, 0)],
2292 "ADS1114 continuous() arms before START; next() re-arms"
2293 );
2294 assert_eq!(rdy.arms.get(), 2);
2295 }
2296
2297 #[test]
2298 fn enable_rdy_upgrades_comparator_config() {
2299 let mut adc = ADS1115::new(Address::Ground, MockI2c::new(), Config::default());
2302 assert_eq!(adc.config.comp_que as u8, CompQue::DisableComparator as u8);
2303 adc.enable_conversion_ready_pin().unwrap();
2304 assert_ne!(adc.config.comp_que as u8, CompQue::DisableComparator as u8);
2305 assert_eq!(adc.config.comp_lat as u8, CompLat::NonLatching as u8);
2306 let thresh: std::vec::Vec<(u8, std::vec::Vec<u8>)> =
2308 adc.i2c.writes.iter().cloned().collect();
2309 assert_eq!(thresh.len(), 2);
2310 assert_eq!(thresh[0].1.as_slice(), &[REG_HI_THRESH, 0x80, 0x00]);
2311 assert_eq!(thresh[1].1.as_slice(), &[REG_LO_THRESH, 0x00, 0x00]);
2312 }
2313
2314 #[test]
2315 fn rdy_precondition_predicate_and_guard() {
2316 assert!(!Config::default().is_conversion_ready());
2319 assert!(Config::default().as_conversion_ready().is_conversion_ready());
2320 }
2321
2322 #[test]
2323 #[should_panic(expected = "COMP_QUE == DisableComparator")]
2324 fn event_api_rejects_disabled_comparator_in_debug() {
2325 let mut adc = ADS1115::new(Address::Ground, MockI2c::new(), Config::default());
2328 adc.start_continuous(Mux::A0).unwrap();
2329 let mut rdy = MockBlockingRdy { waited: std::cell::Cell::new(0), armed: std::cell::Cell::new(0) };
2330 let _ = adc.next_conversion_blocking(&mut rdy);
2331 }
2332
2333 #[test]
2334 fn timer_margin_is_proportional_not_blanket() {
2335 assert_eq!(conversion_period_us(DataRate::SPS860), 1162 + 145 + 100);
2338 assert_eq!(conversion_period_us(DataRate::SPS8), 125_000 + 15_625 + 100);
2339 for dr in [DataRate::SPS8, DataRate::SPS128, DataRate::SPS860] {
2340 let nominal = 1_000_000
2341 / match dr {
2342 DataRate::SPS8 => 8,
2343 DataRate::SPS128 => 128,
2344 DataRate::SPS860 => 860,
2345 _ => unreachable!(),
2346 };
2347 assert!(conversion_period_us(dr) > nominal);
2348 }
2349 }
2350
2351 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
2353 struct MockErr;
2354 impl embedded_hal::i2c::Error for MockErr {
2355 fn kind(&self) -> embedded_hal::i2c::ErrorKind { embedded_hal::i2c::ErrorKind::Other }
2356 }
2357
2358 struct MockI2c {
2359 writes: std::vec::Vec<(u8, std::vec::Vec<u8>)>,
2361 canned: [(u8, i16); 4],
2363 config_reads: usize,
2364 fail_write: Option<usize>,
2366 write_count: usize,
2367 }
2368 impl MockI2c {
2369 fn new() -> Self {
2370 Self {
2371 writes: std::vec::Vec::new(),
2372 canned: [(0x48, 100), (0x49, -200), (0x4A, 300), (0x4B, i16::MIN)],
2373 config_reads: 0,
2374 fail_write: None,
2375 write_count: 0,
2376 }
2377 }
2378 fn canned(&self, addr: u8) -> i16 {
2379 self.canned.iter().find(|(a, _)| *a == addr).map(|(_, v)| *v).unwrap_or(0)
2380 }
2381 fn config_writes(&self) -> usize {
2382 self.writes.iter().filter(|(_, b)| !b.is_empty() && b[0] == REG_CONFIG).count()
2383 }
2384 }
2385 impl embedded_hal::i2c::ErrorType for MockI2c {
2386 type Error = MockErr;
2387 }
2388 impl embedded_hal::i2c::I2c for MockI2c {
2389 fn read(&mut self, _a: u8, _b: &mut [u8]) -> Result<(), Self::Error> { Ok(()) }
2390 fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> {
2391 if self.fail_write == Some(self.write_count) {
2392 self.write_count += 1;
2393 return Err(MockErr);
2394 }
2395 self.write_count += 1;
2396 self.writes.push((addr, bytes.to_vec()));
2397 Ok(())
2398 }
2399 fn write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
2400 match write {
2401 [REG_CONVERSION] => {
2402 read.copy_from_slice(&self.canned(addr).to_be_bytes()[..read.len().min(2)]);
2403 Ok(())
2404 }
2405 [REG_CONFIG] => {
2406 self.config_reads += 1;
2407 read[0] = 0x80;
2409 if read.len() > 1 { read[1] = 0; }
2410 Ok(())
2411 }
2412 _ => Ok(()),
2413 }
2414 }
2415 fn transaction(&mut self, _a: u8, _o: &mut [embedded_hal::i2c::Operation<'_>]) -> Result<(), Self::Error> { Ok(()) }
2416 }
2417
2418 fn dev(address: Address, gain: Gain, dr: DataRate, mux: Mux) -> DeviceConfig {
2419 DeviceConfig::new(address, Config::default().with_gain(gain).with_data_rate(dr), mux)
2420 }
2421
2422 #[test]
2423 fn multi_partial_start_leaves_earlier_devices_running() {
2424 let mut bus = MockI2c::new();
2428 bus.fail_write = Some(2);
2429 let mut m = MultiADS1115::new(
2430 bus,
2431 [
2432 dev(Address::Ground, Gain::V2_048, DataRate::SPS128, Mux::A0),
2433 dev(Address::VDD, Gain::V2_048, DataRate::SPS128, Mux::A1),
2434 dev(Address::SDA, Gain::V2_048, DataRate::SPS128, Mux::A2),
2435 ],
2436 )
2437 .unwrap();
2438 let err = m.start_all([Mux::A0, Mux::A1, Mux::A2]).unwrap_err();
2439 match err {
2440 MultiError::I2c { index: 2, address: Address::SDA, .. } => {}
2441 other => panic!("expected I2c error at device 2/SDA, got {other:?}"),
2442 }
2443 let started: std::vec::Vec<u8> = m
2445 .i2c
2446 .writes
2447 .iter()
2448 .filter(|(_, b)| !b.is_empty() && b[0] == REG_CONFIG)
2449 .map(|(a, _)| *a)
2450 .collect();
2451 assert_eq!(started.as_slice(), &[0x48, 0x49]);
2452 }
2453
2454 #[test]
2455 fn multi_rejects_duplicate_addresses() { let r = MultiADS1115::new(MockI2c::new(), [
2456 dev(Address::Ground, Gain::V6_144, DataRate::SPS128, Mux::A0),
2457 dev(Address::Ground, Gain::V2_048, DataRate::SPS860, Mux::A1),
2458 ]);
2459 assert!(matches!(r, Err(MultiError::DuplicateAddress { first: 0, second: 1, .. })));
2460 }
2461
2462 #[test]
2463 fn multi_parallel_start_before_read_and_ordering() {
2464 let mut m = MultiADS1115::new(MockI2c::new(), [
2465 dev(Address::Ground, Gain::V6_144, DataRate::SPS128, Mux::A0),
2466 dev(Address::VDD, Gain::V2_048, DataRate::SPS860, Mux::A1),
2467 dev(Address::SDA, Gain::V1_024, DataRate::SPS250, Mux::A2),
2468 dev(Address::SCL, Gain::V0_512, DataRate::SPS64, Mux::A3),
2469 ]).unwrap();
2470 let s = m.capture_parallel([Mux::A0, Mux::A1, Mux::A2, Mux::A3]).unwrap();
2471 assert_eq!((s[0].address, s[0].value), (Address::Ground, 100));
2473 assert_eq!((s[1].address, s[1].value), (Address::VDD, -200));
2474 assert_eq!((s[2].address, s[2].value), (Address::SDA, 300));
2475 assert_eq!((s[3].address, s[3].value), (Address::SCL, i16::MIN));
2476 assert_eq!(m.i2c.config_writes(), 4);
2479 let cfgs: std::vec::Vec<[u8; 2]> = m.i2c.writes.iter()
2481 .filter(|(_, b)| b[0] == REG_CONFIG)
2482 .map(|(_, b)| [b[1], b[2]]).collect();
2483 assert_eq!(cfgs.len(), 4);
2484 assert!(cfgs[0][0] & 0x0E != cfgs[1][0] & 0x0E);
2485 for (i, c) in cfgs.iter().enumerate() {
2487 assert_eq!((c[0] >> 4) & 7, (0b100 + i as u8) & 7);
2488 }
2489 }
2490
2491 #[test]
2492 fn multi_diff_and_invalid() {
2493 let mut m = MultiADS1115::new(MockI2c::new(), [
2494 dev(Address::Ground, Gain::V2_048, DataRate::SPS128, Mux::A0N1),
2495 dev(Address::VDD, Gain::V2_048, DataRate::SPS128, Mux::A0N3),
2496 ]).unwrap();
2497 let d = m.capture_parallel_diff([Mux::A0N1, Mux::A0N3]).unwrap();
2498 assert_eq!((d[0].negative, d[0].magnitude), (false, 100));
2499 assert_eq!((d[1].negative, d[1].magnitude), (true, 200));
2500 assert!(matches!(m.start_conversion(9, Mux::A0), Err(MultiError::InvalidIndex(9))));
2501 let mut single = ADS1115::new(Address::Ground, MockI2c::new(), Config::default());
2503 assert!(matches!(single.read_channel_raw_bits(8), Err(MuxOrI2c::Mux(MuxError(8)))));
2504 assert!(matches!(single.read_channel_raw_bits(255), Err(MuxOrI2c::Mux(_))));
2505 assert!(single.read_channel_raw_bits(4).is_ok());
2506 }
2507
2508 #[test]
2509 fn multi_continuous_writes_once() {
2510 let mut m = MultiADS1115::new(MockI2c::new(), [
2511 dev(Address::Ground, Gain::V2_048, DataRate::SPS128, Mux::A0),
2512 dev(Address::VDD, Gain::V2_048, DataRate::SPS128, Mux::A1),
2513 ]).unwrap();
2514 m.start_continuous_all([Mux::A0, Mux::A1]).unwrap();
2515 for (_, b) in m.i2c.writes.iter().filter(|(_, b)| b[0] == REG_CONFIG) {
2517 assert_eq!(b[1] & 1, 0);
2518 assert_eq!(b[1] & 0x80, 0);
2519 }
2520 let before = m.i2c.config_writes();
2521 let mut delays = std::vec::Vec::new();
2525 let s = m.next_all_timed(|us| delays.push(us)).unwrap();
2526 assert_eq!(m.i2c.config_writes(), before, "next_all must not rewrite CONFIG");
2527 assert_eq!(delays.len(), 1, "single shared delay, not per-device");
2528 assert_eq!(delays[0], conversion_period_us(DataRate::SPS128));
2529 assert_eq!(m.i2c.config_reads, 0, "no CONFIG polling in continuous mode");
2530 assert_eq!(s[0].value, 100);
2531 assert_eq!(s[1].value, -200);
2532 }
2533
2534 struct MockBlockingRdy {
2535 waited: std::cell::Cell<u32>,
2536 armed: std::cell::Cell<u32>,
2537 }
2538 impl BlockingReady for MockBlockingRdy {
2539 type Error = MockErr;
2540 fn arm(&mut self, _pol: ConversionReadyPolarity) {
2541 self.armed.set(self.armed.get() + 1);
2542 }
2543 fn wait_for_ready(&mut self, _pol: ConversionReadyPolarity) -> Result<(), Self::Error> {
2544 assert!(self.armed.get() > 0, "wait without arm");
2547 self.waited.set(self.waited.get() + 1);
2548 Ok(())
2549 }
2550 }
2551
2552 #[test]
2553 fn sync_continuous_uses_rdy_or_delay_not_os_poll() {
2554 let mut adc = ADS1115::new(Address::Ground, MockI2c::new(), Config::default());
2555 adc.enable_conversion_ready_pin().unwrap();
2558 assert!(adc.config.is_conversion_ready());
2559 adc.start_continuous(Mux::A0).unwrap();
2560 let mut rdy = MockBlockingRdy { waited: std::cell::Cell::new(0), armed: std::cell::Cell::new(0) };
2562 let v = adc.next_conversion_blocking(&mut rdy).unwrap();
2563 assert_eq!(v, 100);
2564 assert_eq!(rdy.waited.get(), 1);
2565 assert_eq!(rdy.armed.get(), 1, "single-ADC blocking path re-arms every sample");
2566 assert_eq!(adc.i2c.config_reads, 0, "OS polling invalid in continuous mode");
2567 let mut delays = std::vec::Vec::new();
2569 let v = adc.next_conversion_timed(|us| delays.push(us)).unwrap();
2570 assert_eq!(v, 100);
2571 assert_eq!(delays.as_slice(), &[conversion_period_us(DataRate::SPS860)]);
2572 assert_eq!(adc.i2c.config_reads, 0, "OS polling invalid in continuous mode");
2573 let src = include_str!("lib.rs");
2578 for name in ["fn next_conversion_blocking", "fn next_conversion_timed", "fn next_all_timed"] {
2579 let i = src.find(name).expect(name);
2580 let body = &src[i..src[i..].find("\n }\n").map(|e| i + e).unwrap_or(src.len())];
2581 assert!(!body.contains("wait_complete_sync") && !body.contains("multi_wait"),
2582 "{name} must not OS-poll in continuous mode");
2583 }
2584 let needle = std::string::String::from("pub fn next") + "_all_blocking";
2587 assert!(!src.contains(&needle[..]),
2588 "sequential blocking multi-RDY waits were removed as pulse-unsafe");
2589 }
2590}