one_wire_bus/
lib.rs

1#![no_std]
2
3use embedded_hal::blocking::delay::DelayUs;
4use embedded_hal::digital::v2::{InputPin, OutputPin};
5
6mod address;
7pub mod commands;
8pub mod crc;
9mod error;
10
11pub use address::Address;
12pub use error::{OneWireError, OneWireResult};
13
14pub const READ_SLOT_DURATION_MICROS: u16 = 70;
15
16/// Implementation of the 1-Wire protocol.
17/// https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/126.html
18#[derive(Debug)]
19pub struct SearchState {
20    // The address of the last found device
21    address: u64,
22
23    // bitflags of discrepancies found
24    discrepancies: u64,
25
26    // index of the last (leftmost / closest to MSB) discrepancy bit. This can be calculated from the
27    // discrepancy bitflags, but it's cheaper to just save it. Index is an offset from the LSB
28    last_discrepancy_index: u8,
29}
30
31pub struct OneWire<T> {
32    pin: T,
33}
34
35impl<T, E> OneWire<T>
36where
37    T: InputPin<Error = E>,
38    T: OutputPin<Error = E>,
39{
40    pub fn new(pin: T) -> OneWireResult<OneWire<T>, E> {
41        let mut one_wire = OneWire { pin };
42        // Pin should be high during idle.
43        one_wire.release_bus()?;
44        Ok(one_wire)
45    }
46
47    pub fn into_inner(self) -> T {
48        self.pin
49    }
50
51    /// Disconnects the bus, letting another device (or the pull-up resistor) set the bus value
52    pub fn release_bus(&mut self) -> OneWireResult<(), E> {
53        self.pin
54            .set_high()
55            .map_err(|err| OneWireError::PinError(err))
56    }
57
58    /// Drives the bus low
59    pub fn set_bus_low(&mut self) -> OneWireResult<(), E> {
60        self.pin
61            .set_low()
62            .map_err(|err| OneWireError::PinError(err))
63    }
64
65    pub fn is_bus_high(&self) -> OneWireResult<bool, E> {
66        self.pin
67            .is_high()
68            .map_err(|err| OneWireError::PinError(err))
69    }
70
71    pub fn is_bus_low(&self) -> OneWireResult<bool, E> {
72        self.pin.is_low().map_err(|err| OneWireError::PinError(err))
73    }
74
75    fn wait_for_high(&self, delay: &mut impl DelayUs<u16>) -> OneWireResult<(), E> {
76        // wait up to 250 µs for the bus to become high (from the pull-up resistor)
77        for _ in 0..125 {
78            if self.is_bus_high()? {
79                return Ok(());
80            }
81            delay.delay_us(2);
82        }
83        Err(OneWireError::BusNotHigh)
84    }
85
86    /// Sends a reset pulse, then returns true if a device is present
87    pub fn reset(&mut self, delay: &mut impl DelayUs<u16>) -> OneWireResult<bool, E> {
88        self.wait_for_high(delay)?;
89
90        self.set_bus_low()?;
91        delay.delay_us(480); // Maxim recommended wait time
92
93        self.release_bus()?;
94        delay.delay_us(70); // Maxim recommended wait time
95
96        let device_present = self.is_bus_low()?;
97
98        delay.delay_us(410); // Maxim recommended wait time
99        Ok(device_present)
100    }
101
102    pub fn read_bit(&mut self, delay: &mut impl DelayUs<u16>) -> OneWireResult<bool, E> {
103        self.set_bus_low()?;
104        delay.delay_us(6); // Maxim recommended wait time
105
106        self.release_bus()?;
107        delay.delay_us(9); // Maxim recommended wait time
108
109        let bit_value = self.is_bus_high()?;
110        delay.delay_us(55); // Maxim recommended wait time
111        Ok(bit_value)
112    }
113
114    pub fn read_byte(&mut self, delay: &mut impl DelayUs<u16>) -> OneWireResult<u8, E> {
115        let mut output: u8 = 0;
116        for _ in 0..8 {
117            output >>= 1;
118            if self.read_bit(delay)? {
119                output |= 0x80;
120            }
121        }
122        Ok(output)
123    }
124    pub fn read_bytes(
125        &mut self,
126        output: &mut [u8],
127        delay: &mut impl DelayUs<u16>,
128    ) -> OneWireResult<(), E> {
129        for i in 0..output.len() {
130            output[i] = self.read_byte(delay)?;
131        }
132        Ok(())
133    }
134
135    pub fn write_1_bit(&mut self, delay: &mut impl DelayUs<u16>) -> OneWireResult<(), E> {
136        self.set_bus_low()?;
137        delay.delay_us(6); // Maxim recommended wait time
138
139        self.release_bus()?;
140        delay.delay_us(64); // Maxim recommended wait time
141        Ok(())
142    }
143
144    pub fn write_0_bit(&mut self, delay: &mut impl DelayUs<u16>) -> OneWireResult<(), E> {
145        self.set_bus_low()?;
146        delay.delay_us(60); // Maxim recommended wait time
147
148        self.release_bus()?;
149        delay.delay_us(10); // Maxim recommended wait time
150        Ok(())
151    }
152
153    pub fn write_bit(
154        &mut self,
155        value: bool,
156        delay: &mut impl DelayUs<u16>,
157    ) -> OneWireResult<(), E> {
158        if value {
159            self.write_1_bit(delay)
160        } else {
161            self.write_0_bit(delay)
162        }
163    }
164
165    pub fn write_byte(
166        &mut self,
167        mut value: u8,
168        delay: &mut impl DelayUs<u16>,
169    ) -> OneWireResult<(), E> {
170        for _ in 0..8 {
171            self.write_bit(value & 0x01 == 0x01, delay)?;
172            value >>= 1;
173        }
174        Ok(())
175    }
176
177    pub fn write_bytes(
178        &mut self,
179        bytes: &[u8],
180        delay: &mut impl DelayUs<u16>,
181    ) -> OneWireResult<(), E> {
182        for i in 0..bytes.len() {
183            self.write_byte(bytes[i], delay)?;
184        }
185        Ok(())
186    }
187
188    /// Address a specific device. All others will wait for a reset pulse.
189    /// This should only be called after a reset, and should be immediately followed by another command
190    pub fn match_address(
191        &mut self,
192        address: &Address,
193        delay: &mut impl DelayUs<u16>,
194    ) -> OneWireResult<(), E> {
195        self.write_byte(commands::MATCH_ROM, delay)?;
196        self.write_bytes(&address.0.to_le_bytes(), delay)?;
197        Ok(())
198    }
199
200    /// Address all devices on the bus simultaneously.
201    /// This should only be called after a reset, and should be immediately followed by another command
202    pub fn skip_address(&mut self, delay: &mut impl DelayUs<u16>) -> OneWireResult<(), E> {
203        self.write_byte(commands::SKIP_ROM, delay)?;
204        Ok(())
205    }
206
207    /// Sends a reset, followed with either a SKIP_ROM or MATCH_ROM (with an address), and then the supplied command
208    /// This should be followed by any reading/writing, if needed by the command used
209    pub fn send_command(
210        &mut self,
211        command: u8,
212        address: Option<&Address>,
213        delay: &mut impl DelayUs<u16>,
214    ) -> OneWireResult<(), E> {
215        self.reset(delay)?;
216        if let Some(address) = address {
217            self.match_address(address, delay)?;
218        } else {
219            self.skip_address(delay)?;
220        }
221        self.write_byte(command, delay)?;
222        Ok(())
223    }
224
225    /// Returns an iterator that iterates over all device addresses on the bus
226    /// They can be filtered to only alarming devices if needed
227    /// There is no requirement to immediately finish iterating all devices, but if devices are
228    /// added / removed / change alarm state, the search may return an error or fail to find a device
229    /// Device addresses will always be returned in the same order (lowest to highest, Little Endian)
230    pub fn devices<'a, 'b, D>(
231        &'a mut self,
232        only_alarming: bool,
233        delay: &'b mut D,
234    ) -> DeviceSearch<'a, 'b, T, D>
235    where
236        D: DelayUs<u16>,
237    {
238        DeviceSearch {
239            onewire: self,
240            delay,
241            state: None,
242            finished: false,
243            only_alarming,
244        }
245    }
246
247    /// Search for device addresses on the bus
248    /// They can be filtered to only alarming devices if needed
249    /// Start the first search with a search_state of `None`, then use the returned state for subsequent searches
250    /// There is no time limit for continuing a search, but if devices are
251    /// added / removed / change alarm state, the search may return an error or fail to find a device
252    /// Device addresses will always be returned in the same order (lowest to highest, Little Endian)
253    pub fn device_search(
254        &mut self,
255        search_state: Option<&SearchState>,
256        only_alarming: bool,
257        delay: &mut impl DelayUs<u16>,
258    ) -> OneWireResult<Option<(Address, SearchState)>, E> {
259        if let Some(search_state) = search_state {
260            if search_state.discrepancies == 0 {
261                return Ok(None);
262            }
263        }
264
265        if !self.reset(delay)? {
266            return Ok(None);
267        }
268        if only_alarming {
269            self.write_byte(commands::SEARCH_ALARM, delay)?;
270        } else {
271            self.write_byte(commands::SEARCH_NORMAL, delay)?;
272        }
273
274        let mut last_discrepancy_index: u8 = 0;
275        let mut address;
276        let mut discrepancies;
277        let continue_start_bit;
278
279        if let Some(search_state) = search_state {
280            // follow up to the last discrepancy
281            for bit_index in 0..search_state.last_discrepancy_index {
282                let _false_bit = !self.read_bit(delay)?;
283                let _true_bit = !self.read_bit(delay)?;
284                let was_discrepancy_bit =
285                    (search_state.discrepancies & (1_u64 << (bit_index as u64))) != 0;
286                if was_discrepancy_bit {
287                    last_discrepancy_index = bit_index;
288                }
289                let previous_chosen_bit =
290                    (search_state.address & (1_u64 << (bit_index as u64))) != 0;
291
292                // choose the same as last time
293                self.write_bit(previous_chosen_bit, delay)?;
294            }
295            address = search_state.address;
296            // This is the discrepancy bit. False is always chosen to start, so choose true this time
297            {
298                let false_bit = !self.read_bit(delay)?;
299                let true_bit = !self.read_bit(delay)?;
300                if !(false_bit && true_bit) {
301                    // A different response was received than last search
302                    return Err(OneWireError::UnexpectedResponse);
303                }
304                let address_mask = 1_u64 << (search_state.last_discrepancy_index as u64);
305                address |= address_mask;
306                self.write_bit(true, delay)?;
307            }
308
309            //keep all discrepancies except the last one
310            discrepancies = search_state.discrepancies
311                & !(1_u64 << (search_state.last_discrepancy_index as u64));
312            continue_start_bit = search_state.last_discrepancy_index + 1;
313        } else {
314            address = 0;
315            discrepancies = 0;
316            continue_start_bit = 0;
317        }
318        for bit_index in continue_start_bit..64 {
319            let false_bit = !self.read_bit(delay)?;
320            let true_bit = !self.read_bit(delay)?;
321            let chosen_bit = match (false_bit, true_bit) {
322                (false, false) => {
323                    // No devices responded to the search request
324                    return Err(OneWireError::UnexpectedResponse);
325                }
326                (false, true) => {
327                    // All remaining devices have the true bit set
328                    true
329                }
330                (true, false) => {
331                    // All remaining devices have the false bit set
332                    false
333                }
334                (true, true) => {
335                    // Discrepancy, multiple values reported
336                    // choosing the lower value here
337                    discrepancies |= 1_u64 << (bit_index as u64);
338                    last_discrepancy_index = bit_index;
339                    false
340                }
341            };
342            let address_mask = 1_u64 << (bit_index as u64);
343            if chosen_bit {
344                address |= address_mask;
345            } else {
346                address &= !address_mask;
347            }
348            self.write_bit(chosen_bit, delay)?;
349        }
350        crc::check_crc8(&address.to_le_bytes())?;
351        Ok(Some((
352            Address(address),
353            SearchState {
354                address,
355                discrepancies,
356                last_discrepancy_index,
357            },
358        )))
359    }
360}
361
362pub struct DeviceSearch<'a, 'b, T, D> {
363    onewire: &'a mut OneWire<T>,
364    delay: &'b mut D,
365    state: Option<SearchState>,
366    finished: bool,
367    only_alarming: bool,
368}
369
370impl<'a, 'b, T, E, D> Iterator for DeviceSearch<'a, 'b, T, D>
371where
372    T: InputPin<Error = E>,
373    T: OutputPin<Error = E>,
374    D: DelayUs<u16>,
375{
376    type Item = OneWireResult<Address, E>;
377
378    fn next(&mut self) -> Option<Self::Item> {
379        if self.finished {
380            return None;
381        }
382        let result =
383            self.onewire
384                .device_search(self.state.as_ref(), self.only_alarming, self.delay);
385        match result {
386            Ok(Some((address, search_state))) => {
387                self.state = Some(search_state);
388                Some(Ok(address))
389            }
390            Ok(None) => {
391                self.state = None;
392                self.finished = true;
393                None
394            }
395            Err(err) => {
396                self.state = None;
397                self.finished = true;
398                Some(Err(err))
399            }
400        }
401    }
402}