embedded_drivers/onewire/
mod.rs

1//! The Dallas 1-wire driver.
2
3use embedded_hal::blocking::delay::DelayUs;
4use embedded_hal::digital::v2::{InputPin, OutputPin};
5
6pub use self::ds18b20::DS18B20;
7
8pub mod ds18b20;
9
10const ADDRESS_BYTES: u8 = 8;
11const ADDRESS_BITS: u8 = ADDRESS_BYTES * 8;
12
13pub const ROM_CMD_SEARCH_ROM: u8 = 0xf0;
14pub const ROM_CMD_READ_ROM: u8 = 0x33;
15pub const ROM_CMD_MATCH_ROM: u8 = 0x55;
16pub const ROM_CMD_SKIP_ROM: u8 = 0xcc;
17pub const ROM_CMD_ALARM_SEARCH: u8 = 0xec;
18
19// TODO, handle errors
20pub trait OneWirePinExt {
21    fn to_input(&mut self) -> &mut dyn InputPin<Error = core::convert::Infallible>;
22    fn to_output(&mut self) -> &mut dyn OutputPin<Error = core::convert::Infallible>;
23}
24
25#[derive(Debug)]
26pub enum Error {
27    WireNotLow,
28    WireNotHigh,
29    CrcMismatch(u8, u8),
30    FamilyCodeMismatch(u8, u8),
31    Debug(Option<u8>),
32    PortError,
33}
34
35#[derive(Clone, PartialOrd, PartialEq)]
36pub struct Device {
37    pub address: [u8; 8],
38}
39
40impl Device {
41    pub fn family_code(&self) -> u8 {
42        self.address[0]
43    }
44
45    pub fn is_crc_ok(&self) -> bool {
46        ensure_crc(&self.address[..])
47    }
48}
49
50impl ::core::fmt::Debug for Device {
51    fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
52        write!(
53            f,
54            "{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
55            self.address[0],
56            self.address[6],
57            self.address[5],
58            self.address[4],
59            self.address[3],
60            self.address[2],
61            self.address[1],
62            // self.address[7],
63        )
64    }
65}
66
67impl core::str::FromStr for Device {
68    type Err = core::num::ParseIntError;
69
70    fn from_str(s: &str) -> Result<Self, Self::Err> {
71        if s.len() < 23 {
72            let _ = u8::from_str_radix("", 16)?; // this causes a ParseIntError::Empty
73        }
74        Ok(Device {
75            address: [
76                u8::from_str_radix(&s[0..2], 16)?,
77                u8::from_str_radix(&s[3..5], 16)?,
78                u8::from_str_radix(&s[6..8], 16)?,
79                u8::from_str_radix(&s[9..11], 16)?,
80                u8::from_str_radix(&s[12..14], 16)?,
81                u8::from_str_radix(&s[15..17], 16)?,
82                u8::from_str_radix(&s[18..20], 16)?,
83                u8::from_str_radix(&s[21..23], 16)?,
84            ],
85        })
86    }
87}
88
89impl core::ops::Deref for Device {
90    type Target = [u8];
91
92    fn deref(&self) -> &[u8] {
93        &self.address[..]
94    }
95}
96
97#[derive(Debug, Clone, Copy, PartialEq)]
98enum SearchState {
99    Initialized,
100    DeviceFound,
101    End,
102}
103
104pub struct DeviceSearch<'a, P: OneWirePinExt, D: DelayUs<u16>> {
105    address: [u8; 8],
106    discrepancies: [u8; 8],
107    state: SearchState,
108    port: &'a mut OneWire<P>,
109    delay: &'a mut D,
110}
111
112impl<'a, P: OneWirePinExt, D: DelayUs<u16>> DeviceSearch<'a, P, D> {
113    fn is_bit_set(array: &[u8], bit: u8) -> bool {
114        if bit / 8 >= array.len() as u8 {
115            return false;
116        }
117        let index = bit / 8;
118        let offset = bit % 8;
119        array[index as usize] & (0x01 << offset) != 0x00
120    }
121
122    fn is_bit_set_in_address(&self, bit: u8) -> bool {
123        Self::is_bit_set(&self.address, bit)
124    }
125
126    fn set_bit_in_address(&mut self, bit: u8) {
127        Self::set_bit(&mut self.address, bit);
128    }
129
130    fn reset_bit_in_address(&mut self, bit: u8) {
131        Self::reset_bit(&mut self.address, bit);
132    }
133
134    fn write_bit_in_address(&mut self, bit: u8, value: bool) {
135        if value {
136            self.set_bit_in_address(bit);
137        } else {
138            self.reset_bit_in_address(bit);
139        }
140    }
141
142    fn is_bit_set_in_discrepancies(&self, bit: u8) -> bool {
143        Self::is_bit_set(&self.discrepancies, bit)
144    }
145
146    fn set_bit_in_discrepancy(&mut self, bit: u8) {
147        Self::set_bit(&mut self.discrepancies, bit);
148    }
149
150    fn reset_bit_in_discrepancy(&mut self, bit: u8) {
151        Self::reset_bit(&mut self.discrepancies, bit);
152    }
153
154    fn last_discrepancy(&self) -> Option<u8> {
155        let mut result = None;
156        for i in 0..ADDRESS_BITS {
157            if self.is_bit_set_in_discrepancies(i) {
158                result = Some(i);
159            }
160        }
161        result
162    }
163
164    fn set_bit(array: &mut [u8], bit: u8) {
165        if bit / 8 >= array.len() as u8 {
166            return;
167        }
168        let index = bit / 8;
169        let offset = bit % 8;
170        array[index as usize] |= 0x01 << offset
171    }
172
173    fn reset_bit(array: &mut [u8], bit: u8) {
174        if bit / 8 >= array.len() as u8 {
175            return;
176        }
177        let index = bit / 8;
178        let offset = bit % 8;
179        array[index as usize] &= !(0x01 << offset)
180    }
181}
182
183impl<'a, P: OneWirePinExt, D: DelayUs<u16>> core::iter::Iterator for DeviceSearch<'a, P, D> {
184    type Item = Device;
185
186    fn next(&mut self) -> Option<Self::Item> {
187        if self.state == SearchState::End {
188            return None;
189        }
190
191        let mut discrepancy_found = false;
192        let last_discrepancy = self.last_discrepancy();
193
194        if !self.port.reset(self.delay).is_ok() {
195            return None;
196        }
197
198        self.port.write_byte(self.delay, ROM_CMD_SEARCH_ROM).ok()?;
199
200        if let Some(last_discrepancy) = last_discrepancy {
201            // walk previous path
202            for i in 0..last_discrepancy {
203                let bit0 = self.port.read_bit(self.delay).ok()?;
204                let bit1 = self.port.read_bit(self.delay).ok()?;
205
206                if bit0 && bit1 {
207                    // no device responded
208                    return None;
209                } else {
210                    let bit = self.is_bit_set_in_address(i);
211                    // rom.write_bit_in_address(i, bit0);
212                    // rom.write_bit_in_discrepancy(i, bit);
213                    self.port.write_bit(self.delay, bit).ok()?;
214                }
215            }
216        } else {
217            // no discrepancy and device found, meaning the one found is the only one
218            if self.state == SearchState::DeviceFound {
219                self.state = SearchState::End;
220                return None;
221            }
222        }
223
224        for i in last_discrepancy.unwrap_or(0)..ADDRESS_BITS {
225            let bit0 = self.port.read_bit(self.delay).ok()?; // normal bit
226            let bit1 = self.port.read_bit(self.delay).ok()?; // complementar bit
227
228            if last_discrepancy.eq(&Some(i)) {
229                // be sure to go different path from before (go second path, thus writing 1)
230                self.reset_bit_in_discrepancy(i);
231                self.set_bit_in_address(i);
232                self.port.write_bit(self.delay, true).ok()?;
233            } else {
234                if bit0 && bit1 {
235                    // no response received
236                    return None;
237                }
238
239                if !bit0 && !bit1 {
240                    // addresses with 0 and 1
241                    // found new path, go first path by default (thus writing 0)
242                    discrepancy_found |= true;
243                    self.set_bit_in_discrepancy(i);
244                    self.reset_bit_in_address(i);
245                    self.port.write_bit(self.delay, false).ok();
246                } else {
247                    // addresses only with bit0
248                    self.write_bit_in_address(i, bit0);
249                    self.port.write_bit(self.delay, bit0).ok();
250                }
251            }
252        }
253
254        if !discrepancy_found && self.last_discrepancy().is_none() {
255            self.state = SearchState::End;
256        } else {
257            self.state = SearchState::DeviceFound;
258        }
259        Some(Device { address: self.address })
260    }
261}
262
263pub struct OneWire<P: OneWirePinExt> {
264    pin: P,
265}
266
267impl<P: OneWirePinExt> OneWire<P> {
268    pub fn new(mut pin: P) -> Self {
269        pin.to_output().set_high().unwrap();
270        OneWire { pin }
271    }
272
273    pub fn reset(&mut self, delay: &mut impl DelayUs<u16>) -> Result<(), Error> {
274        // let mut cli = DisableInterrupts::new();
275        self.pin.to_output().set_high().unwrap();
276        self.pin.to_output().set_low().unwrap();
277
278        delay.delay_us(480);
279        // self.pin.to_output().set_high().unwrap();
280        let pin = self.pin.to_input();
281
282        // Master Rx
283        let mut val = false;
284        for _ in 0..24 {
285            if pin.is_low().unwrap() {
286                val |= true;
287            }
288            delay.delay_us(10);
289        }
290        if !val {
291            return Err(Error::WireNotLow);
292        }
293        val = false;
294        for _ in 0..24 {
295            if pin.is_high().unwrap() {
296                val |= true;
297            }
298            delay.delay_us(10);
299        }
300        if !val {
301            return Err(Error::WireNotHigh);
302        }
303
304        Ok(())
305    }
306
307    /// This command can only be used when there is one slave
308    /// on the bus. It allows the bus master to read the slave’s
309    /// 64-bit ROM code without using the Search ROM procedure.
310    pub fn read_rom(&mut self, delay: &mut impl DelayUs<u16>) -> Result<Device, Error> {
311        self.reset(delay)?;
312        self.write_byte(delay, ROM_CMD_READ_ROM)?;
313        let mut rom = [0u8; 8];
314        self.read_bytes(delay, &mut rom)?;
315        Ok(Device { address: rom })
316    }
317
318    /// To identify all of the slave devices
319    pub fn search_device<'a, D: DelayUs<u16>>(&'a mut self, delay: &'a mut D) -> DeviceSearch<'a, P, D> {
320        DeviceSearch {
321            address: [0u8; 8],
322            discrepancies: [0u8; 8],
323            state: SearchState::Initialized,
324            port: self,
325            delay,
326        }
327    }
328
329    /// Strong pullup to allow parasite_mode
330    pub fn pullup(&mut self) {
331        self.pin.to_output().set_high().unwrap();
332    }
333
334    pub fn write_bytes(&mut self, delay: &mut impl DelayUs<u16>, bytes: &[u8]) -> Result<(), Error> {
335        for b in bytes {
336            self.write_byte(delay, *b)?;
337        }
338        Ok(())
339    }
340
341    pub fn write_byte(&mut self, delay: &mut impl DelayUs<u16>, mut byte: u8) -> Result<(), Error> {
342        for _ in 0..8 {
343            self.write_bit(delay, (byte & 0x01) == 0x01)?;
344            byte >>= 1;
345        }
346        Ok(())
347    }
348
349    pub fn read_bytes(&mut self, delay: &mut impl DelayUs<u16>, dst: &mut [u8]) -> Result<(), Error> {
350        for d in dst {
351            *d = self.read_byte(delay)?;
352        }
353        Ok(())
354    }
355
356    pub fn read_bit(&mut self, delay: &mut impl DelayUs<u16>) -> Result<bool, Error> {
357        self.pin.to_output().set_low().unwrap();
358        delay.delay_us(3);
359        let pin = self.pin.to_input();
360        delay.delay_us(2);
361        let val = pin.is_high().unwrap();
362        delay.delay_us(61);
363        Ok(val)
364    }
365
366    pub fn read_byte(&mut self, delay: &mut impl DelayUs<u16>) -> Result<u8, Error> {
367        let mut byte = 0_u8;
368        for _ in 0..8 {
369            byte >>= 1;
370            if self.read_bit(delay)? {
371                byte |= 0x80;
372            }
373        }
374        Ok(byte)
375    }
376
377    fn write_bit(&mut self, delay: &mut impl DelayUs<u16>, high: bool) -> Result<(), Error> {
378        // master write
379        let pin = self.pin.to_output();
380        pin.set_low().unwrap();
381        delay.delay_us(if high { 10 } else { 65 });
382        pin.set_high().unwrap();
383        delay.delay_us(if high { 55 } else { 5 });
384        Ok(())
385    }
386}
387
388/// A device on wire.
389pub struct OneWireDevice<'a, P: OneWirePinExt> {
390    wire: &'a mut OneWire<P>,
391    dev: Option<Device>,
392}
393
394impl<P: OneWirePinExt> OneWireDevice<'_, P> {
395    fn select_device<D: DelayUs<u16>>(&mut self, delay: &mut D) -> Result<(), Error> {
396        if let Some(ref dev) = self.dev {
397            self.wire.reset(delay)?;
398            self.wire.write_byte(delay, ROM_CMD_MATCH_ROM)?; // match rom
399            self.wire.write_bytes(delay, dev)?;
400            Ok(())
401        } else {
402            self.wire.reset(delay)?;
403            self.wire.write_byte(delay, ROM_CMD_SKIP_ROM)?;
404            Ok(())
405        }
406    }
407
408    pub fn release(self) {}
409}
410
411pub fn ensure_crc(data: &[u8]) -> bool {
412    compute_partial_crc8(0, data) == 0
413}
414
415fn compute_partial_crc8(crc: u8, data: &[u8]) -> u8 {
416    let mut crc = crc;
417    for byte in data.iter() {
418        let mut byte = *byte;
419        for _ in 0..8 {
420            let mix = (crc ^ byte) & 0x01;
421            crc >>= 1;
422            if mix != 0x00 {
423                crc ^= 0x8C;
424            }
425            byte >>= 1;
426        }
427    }
428    crc
429}