#![no_std]
use embedded_hal::blocking::delay::DelayUs;
use embedded_hal::digital::v2::{InputPin, OutputPin};
mod address;
pub mod commands;
pub mod crc;
mod error;
pub use address::Address;
pub use error::{OneWireError, OneWireResult};
pub const READ_SLOT_DURATION_MICROS: u16 = 70;
#[derive(Debug)]
pub struct SearchState {
address: u64,
discrepancies: u64,
last_discrepancy_index: u8,
}
pub struct OneWire<T> {
pin: T,
}
impl<T, E> OneWire<T>
where
T: InputPin<Error = E>,
T: OutputPin<Error = E>,
{
pub fn new(pin: T) -> OneWireResult<OneWire<T>, E> {
let mut one_wire = OneWire { pin };
one_wire.release_bus()?;
Ok(one_wire)
}
pub fn into_inner(self) -> T {
self.pin
}
pub fn release_bus(&mut self) -> OneWireResult<(), E> {
self.pin
.set_high()
.map_err(|err| OneWireError::PinError(err))
}
pub fn set_bus_low(&mut self) -> OneWireResult<(), E> {
self.pin
.set_low()
.map_err(|err| OneWireError::PinError(err))
}
pub fn is_bus_high(&self) -> OneWireResult<bool, E> {
self.pin
.is_high()
.map_err(|err| OneWireError::PinError(err))
}
pub fn is_bus_low(&self) -> OneWireResult<bool, E> {
self.pin.is_low().map_err(|err| OneWireError::PinError(err))
}
fn wait_for_high(&self, delay: &mut impl DelayUs<u16>) -> OneWireResult<(), E> {
for _ in 0..125 {
if self.is_bus_high()? {
return Ok(());
}
delay.delay_us(2);
}
Err(OneWireError::BusNotHigh)
}
pub fn reset(&mut self, delay: &mut impl DelayUs<u16>) -> OneWireResult<bool, E> {
self.wait_for_high(delay)?;
self.set_bus_low()?;
delay.delay_us(480);
self.release_bus()?;
delay.delay_us(70);
let device_present = self.is_bus_low()?;
delay.delay_us(410);
Ok(device_present)
}
pub fn read_bit(&mut self, delay: &mut impl DelayUs<u16>) -> OneWireResult<bool, E> {
self.set_bus_low()?;
delay.delay_us(6);
self.release_bus()?;
delay.delay_us(9);
let bit_value = self.is_bus_high()?;
delay.delay_us(55);
Ok(bit_value)
}
pub fn read_byte(&mut self, delay: &mut impl DelayUs<u16>) -> OneWireResult<u8, E> {
let mut output: u8 = 0;
for _ in 0..8 {
output >>= 1;
if self.read_bit(delay)? {
output |= 0x80;
}
}
Ok(output)
}
pub fn read_bytes(
&mut self,
output: &mut [u8],
delay: &mut impl DelayUs<u16>,
) -> OneWireResult<(), E> {
for i in 0..output.len() {
output[i] = self.read_byte(delay)?;
}
Ok(())
}
pub fn write_1_bit(&mut self, delay: &mut impl DelayUs<u16>) -> OneWireResult<(), E> {
self.set_bus_low()?;
delay.delay_us(6);
self.release_bus()?;
delay.delay_us(64);
Ok(())
}
pub fn write_0_bit(&mut self, delay: &mut impl DelayUs<u16>) -> OneWireResult<(), E> {
self.set_bus_low()?;
delay.delay_us(60);
self.release_bus()?;
delay.delay_us(10);
Ok(())
}
pub fn write_bit(
&mut self,
value: bool,
delay: &mut impl DelayUs<u16>,
) -> OneWireResult<(), E> {
if value {
self.write_1_bit(delay)
} else {
self.write_0_bit(delay)
}
}
pub fn write_byte(
&mut self,
mut value: u8,
delay: &mut impl DelayUs<u16>,
) -> OneWireResult<(), E> {
for _ in 0..8 {
self.write_bit(value & 0x01 == 0x01, delay)?;
value >>= 1;
}
Ok(())
}
pub fn write_bytes(
&mut self,
bytes: &[u8],
delay: &mut impl DelayUs<u16>,
) -> OneWireResult<(), E> {
for i in 0..bytes.len() {
self.write_byte(bytes[i], delay)?;
}
Ok(())
}
pub fn match_address(
&mut self,
address: &Address,
delay: &mut impl DelayUs<u16>,
) -> OneWireResult<(), E> {
self.write_byte(commands::MATCH_ROM, delay)?;
self.write_bytes(&address.0.to_le_bytes(), delay)?;
Ok(())
}
pub fn skip_address(&mut self, delay: &mut impl DelayUs<u16>) -> OneWireResult<(), E> {
self.write_byte(commands::SKIP_ROM, delay)?;
Ok(())
}
pub fn send_command(
&mut self,
command: u8,
address: Option<&Address>,
delay: &mut impl DelayUs<u16>,
) -> OneWireResult<(), E> {
self.reset(delay)?;
if let Some(address) = address {
self.match_address(address, delay)?;
} else {
self.skip_address(delay)?;
}
self.write_byte(command, delay)?;
Ok(())
}
pub fn devices<'a, 'b, D>(
&'a mut self,
only_alarming: bool,
delay: &'b mut D,
) -> DeviceSearch<'a, 'b, T, D>
where
D: DelayUs<u16>,
{
DeviceSearch {
onewire: self,
delay,
state: None,
finished: false,
only_alarming,
}
}
pub fn device_search(
&mut self,
search_state: Option<&SearchState>,
only_alarming: bool,
delay: &mut impl DelayUs<u16>,
) -> OneWireResult<Option<(Address, SearchState)>, E> {
if let Some(search_state) = search_state {
if search_state.discrepancies == 0 {
return Ok(None);
}
}
if !self.reset(delay)? {
return Ok(None);
}
if only_alarming {
self.write_byte(commands::SEARCH_ALARM, delay)?;
} else {
self.write_byte(commands::SEARCH_NORMAL, delay)?;
}
let mut last_discrepancy_index: u8 = 0;
let mut address;
let mut discrepancies;
let continue_start_bit;
if let Some(search_state) = search_state {
for bit_index in 0..search_state.last_discrepancy_index {
let _false_bit = !self.read_bit(delay)?;
let _true_bit = !self.read_bit(delay)?;
let was_discrepancy_bit =
(search_state.discrepancies & (1_u64 << (bit_index as u64))) != 0;
if was_discrepancy_bit {
last_discrepancy_index = bit_index;
}
let previous_chosen_bit =
(search_state.address & (1_u64 << (bit_index as u64))) != 0;
self.write_bit(previous_chosen_bit, delay)?;
}
address = search_state.address;
{
let false_bit = !self.read_bit(delay)?;
let true_bit = !self.read_bit(delay)?;
if !(false_bit && true_bit) {
return Err(OneWireError::UnexpectedResponse);
}
let address_mask = 1_u64 << (search_state.last_discrepancy_index as u64);
address |= address_mask;
self.write_bit(true, delay)?;
}
discrepancies = search_state.discrepancies
& !(1_u64 << (search_state.last_discrepancy_index as u64));
continue_start_bit = search_state.last_discrepancy_index + 1;
} else {
address = 0;
discrepancies = 0;
continue_start_bit = 0;
}
for bit_index in continue_start_bit..64 {
let false_bit = !self.read_bit(delay)?;
let true_bit = !self.read_bit(delay)?;
let chosen_bit = match (false_bit, true_bit) {
(false, false) => {
return Err(OneWireError::UnexpectedResponse);
}
(false, true) => {
true
}
(true, false) => {
false
}
(true, true) => {
discrepancies |= 1_u64 << (bit_index as u64);
last_discrepancy_index = bit_index;
false
}
};
let address_mask = 1_u64 << (bit_index as u64);
if chosen_bit {
address |= address_mask;
} else {
address &= !address_mask;
}
self.write_bit(chosen_bit, delay)?;
}
crc::check_crc8(&address.to_le_bytes())?;
Ok(Some((
Address(address),
SearchState {
address,
discrepancies,
last_discrepancy_index,
},
)))
}
}
pub struct DeviceSearch<'a, 'b, T, D> {
onewire: &'a mut OneWire<T>,
delay: &'b mut D,
state: Option<SearchState>,
finished: bool,
only_alarming: bool,
}
impl<'a, 'b, T, E, D> Iterator for DeviceSearch<'a, 'b, T, D>
where
T: InputPin<Error = E>,
T: OutputPin<Error = E>,
D: DelayUs<u16>,
{
type Item = OneWireResult<Address, E>;
fn next(&mut self) -> Option<Self::Item> {
if self.finished {
return None;
}
let result =
self.onewire
.device_search(self.state.as_ref(), self.only_alarming, self.delay);
match result {
Ok(Some((address, search_state))) => {
self.state = Some(search_state);
Some(Ok(address))
}
Ok(None) => {
self.state = None;
self.finished = true;
None
}
Err(err) => {
self.state = None;
self.finished = true;
Some(Err(err))
}
}
}
}