1#![deny(missing_docs)]
8#![no_std]
9#![cfg_attr(feature = "never_type", feature(never_type))]
10#![cfg_attr(all(feature = "never_type", test), feature(unwrap_infallible))]
11
12extern crate embedded_hal as hal;
13
14extern crate nb;
15
16use hal::blocking::delay::DelayUs;
17use hal::digital::v2::InputPin;
18use hal::digital::v2::OutputPin;
19
20#[cfg(feature = "never_type")]
21use core::convert::Infallible;
22
23pub const MAX_VALUE: i32 = (1 << 23) - 1;
25
26pub const MIN_VALUE: i32 = 1 << 23;
28
29#[allow(dead_code)]
31const TIME_TO_SLEEP: u32 = 70;
32
33const TIME_BEFORE_READOUT: u32 = 1;
35
36const TIME_SCK_HIGH: u32 = 1;
38
39const TIME_SCK_LOW: u32 = 1;
41
42pub struct Hx711<D, IN, OUT> {
44 delay: D,
45 dout: IN,
46 pd_sck: OUT,
47 mode: Mode,
48}
49
50#[derive(Debug)]
55pub enum Error<EIN, EOUT> {
56 Input(EIN),
58 Output(EOUT),
60}
61
62#[cfg(feature = "never_type")]
65impl Into<!> for Error<!, !> {
66 fn into(self) -> ! {
67 panic!()
68 }
69}
70
71#[cfg(feature = "never_type")]
74impl Into<!> for Error<Infallible, Infallible> {
75 fn into(self) -> ! {
76 panic!()
77 }
78}
79
80impl<D, IN, OUT, EIN, EOUT> Hx711<D, IN, OUT>
81where
82 D: DelayUs<u32>,
83 IN: InputPin<Error = EIN>,
84 OUT: OutputPin<Error = EOUT>,
85{
86 pub fn new(delay: D, dout: IN, mut pd_sck: OUT) -> Result<Self, Error<EIN, EOUT>> {
88 pd_sck.set_low().map_err(Error::Output)?;
89 let mut hx711 = Hx711 {
90 delay,
91 dout,
92 pd_sck,
93 mode: Mode::ChAGain128,
94 };
95 hx711.reset()?;
96 Ok(hx711)
97 }
98
99 pub fn get_mode(&self) -> Mode {
101 self.mode
102 }
103
104 pub fn set_mode(&mut self, mode: Mode) -> nb::Result<(), Error<EIN, EOUT>> {
106 self.mode = mode;
107 self.retrieve().and(Ok(()))
108 }
109 pub fn disable(&mut self) -> Result<(), Error<EIN, EOUT>> {
111 self.pd_sck.set_high().map_err(Error::Output)?;
112 self.delay.delay_us(TIME_TO_SLEEP);
113 Ok(())
114 }
115
116 pub fn enable(&mut self) -> Result<(), Error<EIN, EOUT>> {
118 self.pd_sck.set_low().map_err(Error::Output)?;
119 self.delay.delay_us(TIME_SCK_LOW);
120 nb::block! {self.set_mode(self.mode)}
121 }
122
123 pub fn reset(&mut self) -> Result<(), Error<EIN, EOUT>> {
125 self.disable()?;
126 self.enable()
127 }
128
129 pub fn retrieve(&mut self) -> nb::Result<i32, Error<EIN, EOUT>> {
131 self.pd_sck.set_low().map_err(Error::Output)?;
132 if self.dout.is_high().map_err(Error::Input)? {
133 return Err(nb::Error::WouldBlock);
135 }
136 self.delay.delay_us(TIME_BEFORE_READOUT);
137
138 let mut count: i32 = 0;
139 for _ in 0..24 {
140 count <<= 1;
142 self.pd_sck.set_high().map_err(Error::Output)?;
143 self.delay.delay_us(TIME_SCK_HIGH);
144 self.pd_sck.set_low().map_err(Error::Output)?;
145
146 if self.dout.is_high().map_err(Error::Input)? {
147 count += 1;
148 }
149 self.delay.delay_us(TIME_SCK_LOW);
150 }
151
152 let n_reads = self.mode as u16;
154 for _ in 0..n_reads {
155 self.pd_sck.set_high().map_err(Error::Output)?;
156 self.delay.delay_us(TIME_SCK_HIGH);
157 self.pd_sck.set_low().map_err(Error::Output)?;
158 self.delay.delay_us(TIME_SCK_LOW);
159 }
160
161 Ok(i24_to_i32(count))
162 }
163}
164
165#[derive(Copy, Clone)]
167pub enum Mode {
168 ChAGain128 = 1,
170 ChBGain32 = 2,
172 ChBGain64 = 3,
174}
175
176fn i24_to_i32(x: i32) -> i32 {
178 if x >= 0x800000 {
179 x | !0xFFFFFF
180 } else {
181 x
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use crate::*;
188
189 #[cfg(feature = "never_type")]
190 use core::convert::Infallible;
191
192 #[test]
193 fn convert() {
194 assert_eq!(i24_to_i32(0x000001), 1);
195 assert_eq!(i24_to_i32(0x000002), 2);
196 assert_eq!(i24_to_i32(0xFFFFFF), -1);
197 assert_eq!(i24_to_i32(0xFFFFF3), -13);
198 assert_eq!(i24_to_i32(0xF00000), -1048576);
199 assert_eq!(i24_to_i32(0x800000), -8388608);
200 assert_eq!(i24_to_i32(0x7FFFFF), 8388607);
201 }
202
203 #[test]
204 #[cfg(feature = "never_type")]
205 fn infallible_into_ok() {
206 let this_is_ok: Result<usize, Error<Infallible, Infallible>> = Ok(77);
207 assert_eq!(this_is_ok.into_ok(), 77);
208 }
209
210 #[test]
211 #[cfg(feature = "never_type")]
212 fn never_fail_into_ok() {
213 let this_is_ok: Result<usize, Error<!, !>> = Ok(77);
214 assert_eq!(this_is_ok.into_ok(), 77);
215 }
216}