1#![no_std]
2
3use embedded_hal::blocking::delay::DelayUs;
6use embedded_hal::digital::v2::{InputPin, OutputPin};
7use one_wire_bus::{self, Address, OneWire, OneWireError, OneWireResult};
8
9pub const FAMILY_CODE: u8 = 0x28;
10
11pub mod commands;
12mod resolution;
13
14use one_wire_bus::crc::check_crc8;
15pub use resolution::Resolution;
16
17#[derive(Debug)]
19pub struct SensorData {
20 pub temperature: f32,
22
23 pub resolution: Resolution,
25
26 pub alarm_temp_low: i8,
28
29 pub alarm_temp_high: i8,
31}
32
33pub struct Ds18b20 {
34 address: Address,
35}
36
37impl Ds18b20 {
38 pub fn new<E>(address: Address) -> OneWireResult<Ds18b20, E> {
41 if address.family_code() == FAMILY_CODE {
42 Ok(Ds18b20 { address })
43 } else {
44 Err(OneWireError::FamilyCodeMismatch)
45 }
46 }
47
48 pub fn address(&self) -> &Address {
50 &self.address
51 }
52
53 pub fn start_temp_measurement<T, E>(
57 &self,
58 onewire: &mut OneWire<T>,
59 delay: &mut impl DelayUs<u16>,
60 ) -> OneWireResult<(), E>
61 where
62 T: InputPin<Error = E>,
63 T: OutputPin<Error = E>,
64 {
65 onewire.send_command(commands::CONVERT_TEMP, Some(&self.address), delay)?;
66 Ok(())
67 }
68
69 pub fn read_data<T, E>(
70 &self,
71 onewire: &mut OneWire<T>,
72 delay: &mut impl DelayUs<u16>,
73 ) -> OneWireResult<SensorData, E>
74 where
75 T: InputPin<Error = E>,
76 T: OutputPin<Error = E>,
77 {
78 let data = read_data(&self.address, onewire, delay)?;
79 Ok(data)
80 }
81
82 pub fn set_config<T, E>(
83 &self,
84 alarm_temp_low: i8,
85 alarm_temp_high: i8,
86 resolution: Resolution,
87 onewire: &mut OneWire<T>,
88 delay: &mut impl DelayUs<u16>,
89 ) -> OneWireResult<(), E>
90 where
91 T: InputPin<Error = E>,
92 T: OutputPin<Error = E>,
93 {
94 onewire.send_command(commands::WRITE_SCRATCHPAD, Some(&self.address), delay)?;
95 onewire.write_byte(alarm_temp_high.to_ne_bytes()[0], delay)?;
96 onewire.write_byte(alarm_temp_low.to_ne_bytes()[0], delay)?;
97 onewire.write_byte(resolution.to_config_register(), delay)?;
98 Ok(())
99 }
100
101 pub fn save_to_eeprom<T, E>(
102 &self,
103 onewire: &mut OneWire<T>,
104 delay: &mut impl DelayUs<u16>,
105 ) -> OneWireResult<(), E>
106 where
107 T: InputPin<Error = E>,
108 T: OutputPin<Error = E>,
109 {
110 save_to_eeprom(Some(&self.address), onewire, delay)
111 }
112
113 pub fn recall_from_eeprom<T, E>(
114 &self,
115 onewire: &mut OneWire<T>,
116 delay: &mut impl DelayUs<u16>,
117 ) -> OneWireResult<(), E>
118 where
119 T: InputPin<Error = E>,
120 T: OutputPin<Error = E>,
121 {
122 recall_from_eeprom(Some(&self.address), onewire, delay)
123 }
124}
125
126pub fn start_simultaneous_temp_measurement<T, E>(
128 onewire: &mut OneWire<T>,
129 delay: &mut impl DelayUs<u16>,
130) -> OneWireResult<(), E>
131where
132 T: InputPin<Error = E>,
133 T: OutputPin<Error = E>,
134{
135 onewire.reset(delay)?;
136 onewire.skip_address(delay)?;
137 onewire.write_byte(commands::CONVERT_TEMP, delay)?;
138 Ok(())
139}
140
141pub fn simultaneous_recall_from_eeprom<T, E>(
143 onewire: &mut OneWire<T>,
144 delay: &mut impl DelayUs<u16>,
145) -> OneWireResult<(), E>
146where
147 T: InputPin<Error = E>,
148 T: OutputPin<Error = E>,
149{
150 recall_from_eeprom(None, onewire, delay)
151}
152
153pub fn simultaneous_save_to_eeprom<T, E>(
155 onewire: &mut OneWire<T>,
156 delay: &mut impl DelayUs<u16>,
157) -> OneWireResult<(), E>
158where
159 T: InputPin<Error = E>,
160 T: OutputPin<Error = E>,
161{
162 save_to_eeprom(None, onewire, delay)
163}
164
165pub fn read_scratchpad<T, E>(
166 address: &Address,
167 onewire: &mut OneWire<T>,
168 delay: &mut impl DelayUs<u16>,
169) -> OneWireResult<[u8; 9], E>
170where
171 T: InputPin<Error = E>,
172 T: OutputPin<Error = E>,
173{
174 onewire.reset(delay)?;
175 onewire.match_address(address, delay)?;
176 onewire.write_byte(commands::READ_SCRATCHPAD, delay)?;
177 let mut scratchpad = [0; 9];
178 onewire.read_bytes(&mut scratchpad, delay)?;
179 check_crc8(&scratchpad)?;
180 Ok(scratchpad)
181}
182
183fn read_data<T, E>(
184 address: &Address,
185 onewire: &mut OneWire<T>,
186 delay: &mut impl DelayUs<u16>,
187) -> OneWireResult<SensorData, E>
188where
189 T: InputPin<Error = E>,
190 T: OutputPin<Error = E>,
191{
192 let scratchpad = read_scratchpad(address, onewire, delay)?;
193
194 let resolution = if let Some(resolution) = Resolution::from_config_register(scratchpad[4]) {
195 resolution
196 } else {
197 return Err(OneWireError::CrcMismatch);
198 };
199 let raw_temp = u16::from_le_bytes([scratchpad[0], scratchpad[1]]);
200 let temperature = match resolution {
201 Resolution::Bits12 => (raw_temp as f32) / 16.0,
202 Resolution::Bits11 => (raw_temp as f32) / 8.0,
203 Resolution::Bits10 => (raw_temp as f32) / 4.0,
204 Resolution::Bits9 => (raw_temp as f32) / 2.0,
205 };
206 Ok(SensorData {
207 temperature,
208 resolution,
209 alarm_temp_high: i8::from_le_bytes([scratchpad[2]]),
210 alarm_temp_low: i8::from_le_bytes([scratchpad[3]]),
211 })
212}
213
214fn recall_from_eeprom<T, E>(
215 address: Option<&Address>,
216 onewire: &mut OneWire<T>,
217 delay: &mut impl DelayUs<u16>,
218) -> OneWireResult<(), E>
219where
220 T: InputPin<Error = E>,
221 T: OutputPin<Error = E>,
222{
223 onewire.send_command(commands::RECALL_EEPROM, address, delay)?;
224
225 let max_retries = (10000 / one_wire_bus::READ_SLOT_DURATION_MICROS) + 1;
227 for _ in 0..max_retries {
228 if onewire.read_bit(delay)? == true {
229 return Ok(());
230 }
231 }
232 Err(OneWireError::Timeout)
233}
234
235fn save_to_eeprom<T, E>(
236 address: Option<&Address>,
237 onewire: &mut OneWire<T>,
238 delay: &mut impl DelayUs<u16>,
239) -> OneWireResult<(), E>
240where
241 T: InputPin<Error = E>,
242 T: OutputPin<Error = E>,
243{
244 onewire.send_command(commands::COPY_SCRATCHPAD, address, delay)?;
245 delay.delay_us(10000); Ok(())
247}