1use byteorder::ByteOrder;
2use byteorder::LittleEndian;
3use core::fmt::Debug;
4use hal::blocking::delay::DelayUs;
5
6use crate::Device;
7use crate::Error;
8use crate::OneWire;
9use crate::Sensor;
10
11pub const FAMILY_CODE: u8 = 0x28;
12
13#[repr(u8)]
14pub enum Command {
15 Convert = 0x44,
16 WriteScratchpad = 0x4e,
17 ReadScratchpad = 0xBE,
18 CopyScratchpad = 0x48,
19 RecallE2 = 0xB8,
20 ReadPowerSupply = 0xB4,
21}
22
23#[repr(u8)]
24#[derive(Debug, Copy, Clone)]
25pub enum MeasureResolution {
26 TC8 = 0b0001_1111,
27 TC4 = 0b0011_1111,
28 TC2 = 0b0101_1111,
29 TC = 0b0111_1111,
30}
31
32impl MeasureResolution {
33 pub fn time_ms(&self) -> u16 {
34 match self {
35 &MeasureResolution::TC8 => 94,
36 &MeasureResolution::TC4 => 188,
37 &MeasureResolution::TC2 => 375,
38 &MeasureResolution::TC => 750,
39 }
40 }
41}
42
43pub struct DS18B20 {
44 device: Device,
45 resolution: MeasureResolution,
46}
47
48impl DS18B20 {
49 pub fn new<E: Debug>(device: Device) -> Result<DS18B20, Error<E>> {
50 if device.address[0] != FAMILY_CODE {
51 Err(Error::FamilyCodeMismatch(FAMILY_CODE, device.address[0]))
52 } else {
53 Ok(DS18B20 {
54 device,
55 resolution: MeasureResolution::TC,
56 })
57 }
58 }
59
60 pub unsafe fn new_forced(device: Device) -> DS18B20 {
61 DS18B20 {
62 device,
63 resolution: MeasureResolution::TC,
64 }
65 }
66
67 pub fn measure_temperature<E: Debug>(
68 &self,
69 wire: &mut OneWire<E>,
70 delay: &mut dyn DelayUs<u16>,
71 ) -> Result<MeasureResolution, Error<E>> {
72 wire.reset_select_write_only(delay, &self.device, &[Command::Convert as u8])?;
73 Ok(self.resolution)
74 }
75
76 pub fn read_temperature<E: Debug>(
77 &self,
78 wire: &mut OneWire<E>,
79 delay: &mut dyn DelayUs<u16>,
80 ) -> Result<u16, Error<E>> {
81 let mut scratchpad = [0u8; 9];
82 wire.reset_select_write_read(
83 delay,
84 &self.device,
85 &[Command::ReadScratchpad as u8],
86 &mut scratchpad[..],
87 )?;
88 super::ensure_correct_rcr8(&self.device, &scratchpad[..8], scratchpad[8])?;
89 Ok(DS18B20::read_temperature_from_scratchpad(&scratchpad))
90 }
91
92 fn read_temperature_from_scratchpad(scratchpad: &[u8]) -> u16 {
93 LittleEndian::read_u16(&scratchpad[0..2])
94 }
95}
96
97impl Sensor for DS18B20 {
98 fn family_code() -> u8 {
99 FAMILY_CODE
100 }
101
102 fn start_measurement<E: Debug>(
103 &self,
104 wire: &mut OneWire<E>,
105 delay: &mut dyn DelayUs<u16>,
106 ) -> Result<u16, Error<E>> {
107 Ok(self.measure_temperature(wire, delay)?.time_ms())
108 }
109
110 fn read_measurement<E: Debug>(
111 &self,
112 wire: &mut OneWire<E>,
113 delay: &mut dyn DelayUs<u16>,
114 ) -> Result<f32, Error<E>> {
115 self.read_temperature(wire, delay)
116 .map(|t| t as i16 as f32 / 16_f32)
117 }
118
119 fn read_measurement_raw<E: Debug>(
120 &self,
121 wire: &mut OneWire<E>,
122 delay: &mut dyn DelayUs<u16>,
123 ) -> Result<u16, Error<E>> {
124 self.read_temperature(wire, delay)
125 }
126}
127
128pub fn split_temp(temperature: u16) -> (i16, i16) {
131 if temperature < 0x8000 {
132 (temperature as i16 >> 4, (temperature as i16 & 0xF) * 625)
133 } else {
134 let abs = -(temperature as i16);
135 (-(abs >> 4), -625 * (abs & 0xF))
136 }
137}
138
139#[cfg(test)]
140mod tests {
141 use super::split_temp;
142 #[test]
143 fn test_temp_conv() {
144 assert_eq!(split_temp(0x07d0), (125, 0));
145 assert_eq!(split_temp(0x0550), (85, 0));
146 assert_eq!(split_temp(0x0191), (25, 625)); assert_eq!(split_temp(0x00A2), (10, 1250)); assert_eq!(split_temp(0x0008), (0, 5000)); assert_eq!(split_temp(0x0000), (0, 0)); assert_eq!(split_temp(0xfff8), (0, -5000)); assert_eq!(split_temp(0xFF5E), (-10, -1250)); assert_eq!(split_temp(0xFE6F), (-25, -625)); assert_eq!(split_temp(0xFC90), (-55, 0)); }
155}