1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98

use byteorder::ByteOrder;
use byteorder::LittleEndian;
use hal::blocking::delay::DelayUs;

use Error;
use Device;
use Sensor;
use OneWire;

pub const FAMILY_CODE : u8 = 0x28;

#[repr(u8)]
pub enum Command {
    Convert = 0x44,
    WriteScratchpad = 0x4e,
    ReadScratchpad = 0xBE,
    CopyScratchpad = 0x48,
    RecallE2 = 0xB8,
    ReadPowerSupply = 0xB4,
}

#[repr(u8)]
#[derive(Debug, Copy, Clone)]
pub enum MeasureResolution {
    TC8 = 0b0001_1111,
    TC4 = 0b0011_1111,
    TC2 = 0b0101_1111,
    TC  = 0b0111_1111,
}

impl MeasureResolution {
    pub fn time_ms(&self) -> u16 {
        match self {
            &MeasureResolution::TC8 => 94,
            &MeasureResolution::TC4 => 188,
            &MeasureResolution::TC2 => 375,
            &MeasureResolution::TC  => 750,
        }
    }
}

pub struct DS18B20 {
    device: Device,
    resolution: MeasureResolution,
}

impl DS18B20 {
    pub fn new(device: Device) -> Result<DS18B20, Error> {
        if device.address[0] != FAMILY_CODE {
            Err(Error::FamilyCodeMismatch(FAMILY_CODE, device.address[0]))
        } else {
            Ok(DS18B20 {
                device,
                resolution: MeasureResolution::TC,
            })
        }
    }

    pub unsafe fn new_forced(device: Device) -> DS18B20 {
        DS18B20 {
            device,
            resolution: MeasureResolution::TC
        }
    }

    pub fn measure_temperature(&self, wire: &mut OneWire, delay: &mut DelayUs<u16>) -> Result<MeasureResolution, Error> {
        wire.reset_select_write_only(delay, &self.device, &[Command::Convert as u8])?;
        Ok(self.resolution)
    }

    pub fn read_temperature(&self, wire: &mut OneWire, delay: &mut DelayUs<u16>) -> Result<f32, Error> {
        let mut scratchpad = [0u8; 9];
        wire.reset_select_write_read(delay, &self.device, &[Command::ReadScratchpad as u8], &mut scratchpad[..])?;
        super::ensure_correct_rcr8(&self.device,&scratchpad[..8], scratchpad[8])?;
        Ok(DS18B20::read_temperature_from_scratchpad(&scratchpad))
    }

    fn read_temperature_from_scratchpad(scratchpad: &[u8]) -> f32 {
        let temp_u16 = LittleEndian::read_u16(&scratchpad[0..2]);
        let temp_f32 = temp_u16 as i16 as f32 / 16_f32;
        temp_f32
    }
}

impl Sensor for DS18B20 {
    fn family_code() -> u8 {
        FAMILY_CODE
    }

    fn start_measurement(&self, wire: &mut OneWire, delay: &mut DelayUs<u16>) -> Result<u16, Error> {
        Ok(self.measure_temperature(wire, delay)?.time_ms())
    }

    fn read_measurement(&self, wire: &mut OneWire, delay: &mut DelayUs<u16>) -> Result<f32, Error> {
        self.read_temperature(wire, delay)
    }
}