use crate::{
Ds2484Error, Ds2484Result, InteractAsync,
traits::{Addressing, Interact},
};
use bitfield_struct::bitfield;
use embedded_hal::{
delay::DelayNs,
i2c::{I2c, SevenBitAddress},
};
use embedded_hal_async::{
delay::DelayNs as DelayNsAsync,
i2c::{I2c as I2cAsync, SevenBitAddress as SevenBitAddressAsync},
};
use embedded_onewire::OneWireStatus;
pub(crate) const READ_PTR_CMD: u8 = 0xe1; pub(crate) const DEVICE_STATUS_PTR: u8 = 0xf0; pub(crate) const DEVICE_RST_CMD: u8 = 0xf0;
pub struct Ds2484<I, D> {
pub(crate) i2c: I,
pub(crate) addr: u8,
pub(crate) delay: D,
pub(crate) retries: u8,
pub(crate) reset: bool, pub(crate) overdrive: bool,
}
pub struct Ds2484Builder {
pub(crate) retries: u8,
pub(crate) config: DeviceConfiguration,
}
impl Default for Ds2484Builder {
fn default() -> Self {
Ds2484Builder {
retries: 100,
config: DeviceConfiguration::new(),
}
}
}
impl Ds2484Builder {
pub fn with_retries(mut self, retries: u8) -> Self {
self.retries = retries;
self
}
pub fn with_config(mut self, config: DeviceConfiguration) -> Self {
self.config = config;
self
}
pub fn build<I: I2c<SevenBitAddress>, D: DelayNs>(
mut self,
i2c: I,
delay: D,
) -> Ds2484Result<Ds2484<I, D>, I::Error> {
let mut dev = Ds2484 {
i2c,
addr: 0x18,
delay,
retries: self.retries,
reset: false,
overdrive: false,
};
dev.bus_reset()?;
self.config.write(&mut dev)?;
dev.overdrive = self.config.onewire_speed();
Ok(dev)
}
pub async fn build_async<I: I2cAsync<SevenBitAddressAsync>, D: DelayNsAsync>(
mut self,
i2c: I,
delay: D,
) -> Ds2484Result<Ds2484<I, D>, I::Error> {
let mut dev = Ds2484 {
i2c,
addr: 0x18,
delay,
retries: self.retries,
reset: false,
overdrive: false,
};
dev.bus_reset_async().await?;
self.config.async_write(&mut dev).await?;
dev.overdrive = self.config.onewire_speed();
Ok(dev)
}
}
impl<I: I2c<SevenBitAddress>, D: DelayNs> Ds2484<I, D> {
pub fn get_status(&mut self) -> Ds2484Result<DeviceStatus, I::Error> {
let mut stat = DeviceStatus::default();
stat.read(self)?;
Ok(stat)
}
}
impl<I2C: I2c<SevenBitAddress>, D: DelayNs> Ds2484<I2C, D> {
pub fn bus_reset(&mut self) -> Ds2484Result<DeviceStatus, I2C::Error> {
self.i2c.write(self.addr, &[DEVICE_RST_CMD])?;
self.reset = true;
let mut tries = 0;
let mut status = DeviceStatus::default();
loop {
status.read(self)?;
if status.device_reset() || tries > self.retries {
break;
}
tries += 1;
self.delay.delay_ms(1);
}
if tries > self.retries {
Err(Ds2484Error::RetriesExceeded)
} else {
Ok(status)
}
}
pub(crate) fn onewire_wait(&mut self) -> Ds2484Result<DeviceStatus, I2C::Error> {
let mut tries = 0;
let mut status = DeviceStatus::default();
let mut buf = [0; 1];
self.i2c
.write(self.addr, &[READ_PTR_CMD, DEVICE_STATUS_PTR])?;
loop {
self.i2c.read(self.addr, &mut buf)?;
status.0 = buf[0];
if !status.onewire_busy() || tries > self.retries {
break;
}
tries += 1;
if !self.overdrive {
self.delay.delay_ms(1);
} else {
self.delay.delay_us(100);
}
}
if status.onewire_busy() && tries > self.retries {
Err(Ds2484Error::RetriesExceeded)
} else {
Ok(status)
}
}
}
#[bitfield(u8)]
pub struct DeviceStatus {
pub(crate) onewire_busy: bool,
pub(crate) present_pulse_detect: bool,
pub(crate) short_detect: bool,
#[bits(1, access = RO)]
pub logic_level: bool,
#[bits(1, access = RO)]
pub device_reset: bool,
pub(crate) single_bit_result: bool,
pub(crate) triplet_second_bit: bool,
pub(crate) branch_dir_taken: bool,
}
impl OneWireStatus for DeviceStatus {
fn presence(&self) -> bool {
self.present_pulse_detect()
}
fn shortcircuit(&self) -> bool {
self.short_detect()
}
fn logic_level(&self) -> Option<bool> {
Some(self.logic_level())
}
#[cfg(feature = "triplet-read")]
fn direction(&self) -> Option<bool> {
Some(self.branch_dir_taken())
}
}
impl Addressing for DeviceStatus {
const WRITE_ADDR: u8 = 0x0;
const READ_PTR: u8 = 0xf0;
}
impl Interact for DeviceStatus {
fn read<I: I2c<SevenBitAddress>, D>(
&mut self,
dev: &mut Ds2484<I, D>,
) -> Result<(), Ds2484Error<I::Error>> {
let mut val = [0; 1];
dev.i2c
.write_read(dev.addr, &[READ_PTR_CMD, Self::READ_PTR], &mut val)?;
self.0 = val[0];
Ok(())
}
fn write<I: I2c<SevenBitAddress>, D>(
&mut self,
_dev: &mut Ds2484<I, D>,
) -> Result<(), Ds2484Error<I::Error>> {
Ok(())
}
}
#[bitfield(u8)]
pub struct DeviceConfiguration {
pub active_pullup: bool,
pub power_down_1wire: bool,
pub strong_pullup: bool,
pub(crate) onewire_speed: bool,
#[bits(4)]
reserved: u8,
}
impl Addressing for DeviceConfiguration {
const WRITE_ADDR: u8 = 0xd2;
const READ_PTR: u8 = 0xc3;
}
impl Interact for DeviceConfiguration {
fn read<I: I2c<SevenBitAddress>, D: DelayNs>(
&mut self,
dev: &mut Ds2484<I, D>,
) -> Result<(), Ds2484Error<I::Error>> {
let mut buf = [0; 1];
dev.i2c
.write_read(dev.addr, &[READ_PTR_CMD, Self::READ_PTR], &mut buf)?;
self.0 = buf[0];
Ok(())
}
fn write<I: I2c<SevenBitAddress>, D: DelayNs>(
&mut self,
dev: &mut Ds2484<I, D>,
) -> Result<(), Ds2484Error<I::Error>> {
dev.onewire_wait()?;
let out = (self.0 & 0x0f) | ((!self.0 & 0x0f) << 4);
let mut buf = [0; 1];
dev.i2c.write(dev.addr, &[Self::WRITE_ADDR, out])?;
dev.i2c.read(dev.addr, &mut buf)?;
dev.reset = false; self.0 = buf[0];
Ok(())
}
}
#[derive(Debug, PartialEq)]
pub struct OneWirePortConfiguration {
t_rstl: u8, t_rstl_od: u8, t_msp: u8, t_msp_od: u8, t_w0l: u8, t_w0l_od: u8, t_rec0: u8, r_wpu: u8, }
impl Addressing for OneWirePortConfiguration {
const WRITE_ADDR: u8 = 0xc3;
const READ_PTR: u8 = 0xb4;
}
impl Interact for OneWirePortConfiguration {
fn read<I: I2c<SevenBitAddress>, D: DelayNs>(
&mut self,
dev: &mut Ds2484<I, D>,
) -> Result<(), Ds2484Error<I::Error>> {
let mut buf = [0; 8];
dev.i2c
.write_read(dev.addr, &[READ_PTR_CMD, Self::READ_PTR], &mut buf)?;
*self = Self::from_bytes(buf);
Ok(())
}
fn write<I: I2c<SevenBitAddress>, D: DelayNs>(
&mut self,
dev: &mut Ds2484<I, D>,
) -> Result<(), Ds2484Error<I::Error>> {
dev.onewire_wait()?;
dev.i2c.write(dev.addr, &self.to_bytes())?;
self.read(dev)
}
}
impl OneWirePortConfiguration {
pub fn reset_time(&self) -> u32 {
(self.t_rstl & 0x0f) as u32 * 20000 + 440000
}
pub fn reset_time_overdrive(&self) -> u32 {
(self.t_rstl_od & 0x0f) as u32 * 2000 + 44000
}
pub fn presence_detect_time(&self) -> u32 {
(match (self.t_msp & 0x0f) as u32 {
0..=1 => 58,
13..=u32::MAX => 76,
val => 60 + (val - 2) * 2,
}) * 100
}
pub fn presence_detect_time_overdrive(&self) -> u32 {
(match (self.t_msp_od & 0x0f) as u32 {
0..=1 => 55,
13..=u32::MAX => 110,
val => 60 + (val - 2) * 5,
}) * 100
}
pub fn write_zero_low_time(&self) -> u32 {
match (self.t_w0l & 0x0f) as u32 {
10..=u32::MAX => 70000,
val => 52000 + val * 2000,
}
}
pub fn write_zero_low_time_overdrive(&self) -> u32 {
match (self.t_w0l_od & 0x0f) as u32 {
10..=u32::MAX => 10000,
val => 5000 + val * 500,
}
}
pub fn write_zero_recovery_time(&self) -> u32 {
match (self.t_rec0 & 0x0f) as u32 {
0..=4 => 2750,
15..=u32::MAX => 25250,
val => 2750 + (val - 5) * 2500,
}
}
pub fn weak_pullup_resistor(&self) -> u16 {
if self.r_wpu & 0x0f < 0b0110 {
500 } else {
1000 }
}
pub(crate) fn to_bytes(&self) -> [u8; 9] {
[
0xc3,
self.t_rstl,
self.t_rstl_od,
self.t_msp,
self.t_msp_od,
self.t_w0l,
self.t_w0l_od,
self.t_rec0,
self.r_wpu,
]
}
pub(crate) fn from_bytes(bytes: [u8; 8]) -> Self {
OneWirePortConfiguration {
t_rstl: (bytes[0] & 0x0f),
t_rstl_od: (bytes[1] & 0x0f) | 0b0001_0000,
t_msp: (bytes[2] & 0x0f) | 0b0010_0000,
t_msp_od: (bytes[3] & 0x0f) | 0b0011_0000,
t_w0l: (bytes[4] & 0x0f) | 0b0100_0000,
t_w0l_od: (bytes[5] & 0x0f) | 0b0101_0000,
t_rec0: (bytes[6] & 0x0f) | 0b0110_0000,
r_wpu: (bytes[7] & 0x0f) | 0b1000_0000,
}
}
}
impl Default for OneWirePortConfiguration {
fn default() -> Self {
OneWirePortConfiguration {
t_rstl: 0b0000_0110,
t_rstl_od: 0b0001_0110,
t_msp: 0b0010_0110,
t_msp_od: 0b0011_0110,
t_w0l: 0b0100_0110,
t_w0l_od: 0b0101_0110,
t_rec0: 0b0110_0110,
r_wpu: 0b1000_0110,
}
}
}
#[derive(Debug, Default)]
pub struct OneWireConfigurationBuilder {
cfg: OneWirePortConfiguration,
}
#[allow(clippy::from_over_into)]
impl Into<OneWireConfigurationBuilder> for OneWirePortConfiguration {
fn into(self) -> OneWireConfigurationBuilder {
OneWireConfigurationBuilder { cfg: self }
}
}
impl OneWireConfigurationBuilder {
pub fn reset_pulse(mut self, normal: u32, overdrive: u32) -> Self {
const NORMAL: [u32; 16] = [
440000, 460000, 480000, 500000, 520000, 540000, 560000, 580000, 600000, 620000, 640000,
660000, 680000, 700000, 720000, 740000,
];
let index = NORMAL.iter().position(|&v| v >= normal).unwrap_or(0);
self.cfg.t_rstl = (self.cfg.t_rstl & 0xf0) | (index as u8);
const OVERDRIVE: [u32; 16] = [
44000, 46000, 48000, 50000, 52000, 54000, 56000, 58000, 60000, 62000, 64000, 66000,
68000, 70000, 72000, 74000,
];
let index = OVERDRIVE.iter().position(|&v| v >= overdrive).unwrap_or(0);
self.cfg.t_rstl_od = (self.cfg.t_rstl_od & 0xf0) | (index as u8);
self
}
pub fn presence_detect_time(mut self, normal: u32, overdrive: u32) -> Self {
const NORMAL: [u32; 16] = [
58000, 58000, 60000, 62000, 64000, 66000, 68000, 70000, 72000, 74000, 76000, 76000,
76000, 76000, 76000, 76000,
];
let index = NORMAL.iter().position(|&v| v >= normal).unwrap_or(0);
self.cfg.t_msp = (self.cfg.t_msp & 0xf0) | (index as u8);
const OVERDRIVE: [u32; 16] = [
5500, 5500, 6000, 6500, 7000, 7500, 8000, 8500, 9000, 9500, 10000, 10500, 11000, 11000,
11000, 11000,
];
let index = OVERDRIVE.iter().position(|&v| v >= overdrive).unwrap_or(0);
self.cfg.t_msp_od = (self.cfg.t_msp_od & 0xf0) | (index as u8);
self
}
pub fn write_zero_low_time(mut self, normal: u32, overdrive: u32) -> Self {
const NORMAL: [u32; 16] = [
52000, 54000, 56000, 58000, 60000, 62000, 64000, 66000, 68000, 70000, 70000, 70000,
70000, 70000, 70000, 70000,
];
let index = NORMAL.iter().position(|&v| v >= normal).unwrap_or(0);
self.cfg.t_w0l = (self.cfg.t_w0l & 0xf0) | (index as u8);
const OVERDRIVE: [u32; 16] = [
5000, 5500, 6000, 6500, 7000, 7500, 8000, 8500, 9000, 9500, 10000, 10000, 10000, 10000,
10000, 10000,
];
let index = OVERDRIVE.iter().position(|&v| v >= overdrive).unwrap_or(0);
self.cfg.t_w0l_od = (self.cfg.t_w0l_od & 0xf0) | (index as u8);
self
}
pub fn write_zero_recovery_time(mut self, value: u16) -> Self {
const VALUES: [u16; 16] = [
275, 275, 275, 275, 275, 275, 525, 775, 1025, 1275, 1525, 1775, 2025, 2275, 2525, 2525,
];
let index = VALUES.iter().position(|&v| v >= value).unwrap_or(0);
self.cfg.t_rec0 = (self.cfg.t_rec0 & 0xf0) | (index as u8);
self
}
pub fn weak_pullup_resistor(mut self, value: u16) -> Self {
if value < 1000 {
self.cfg.r_wpu &= 0xf0; } else {
self.cfg.r_wpu &= 0xff; }
self
}
pub fn build(self) -> OneWirePortConfiguration {
self.cfg
}
}