#![deny(missing_docs)]
#![no_std]
#![cfg_attr(feature = "never_type", feature(never_type))]
#![cfg_attr(all(feature = "never_type", test), feature(unwrap_infallible))]
extern crate embedded_hal as hal;
extern crate nb;
#[cfg(feature = "never_type")]
use core::convert::Infallible;
use hal::delay::DelayNs;
use hal::digital::{InputPin, OutputPin};
pub const MAX_VALUE: i32 = (1 << 23) - 1;
pub const MIN_VALUE: i32 = 1 << 23;
#[allow(dead_code)]
const TIME_TO_SLEEP: u32 = 70;
const TIME_BEFORE_READOUT: u32 = 1;
const TIME_SCK_HIGH: u32 = 1;
const TIME_SCK_LOW: u32 = 1;
pub struct Hx711<D, IN, OUT> {
delay: D,
dout: IN,
pd_sck: OUT,
mode: Mode,
}
#[derive(Debug)]
pub enum Error<EIN, EOUT> {
Input(EIN),
Output(EOUT),
}
#[cfg(feature = "never_type")]
impl Into<!> for Error<!, !> {
fn into(self) -> ! {
panic!()
}
}
#[cfg(feature = "never_type")]
impl Into<!> for Error<Infallible, Infallible> {
fn into(self) -> ! {
panic!()
}
}
impl<D, IN, OUT, EIN, EOUT> Hx711<D, IN, OUT>
where
D: DelayNs,
IN: InputPin<Error = EIN>,
OUT: OutputPin<Error = EOUT>,
{
pub fn new(delay: D, dout: IN, mut pd_sck: OUT) -> Result<Self, Error<EIN, EOUT>> {
pd_sck.set_low().map_err(Error::Output)?;
let mut hx711 = Hx711 {
delay,
dout,
pd_sck,
mode: Mode::ChAGain128,
};
hx711.reset()?;
Ok(hx711)
}
pub fn get_mode(&self) -> Mode {
self.mode
}
pub fn set_mode(&mut self, mode: Mode) -> nb::Result<(), Error<EIN, EOUT>> {
self.mode = mode;
self.retrieve().and(Ok(()))
}
pub fn disable(&mut self) -> Result<(), Error<EIN, EOUT>> {
self.pd_sck.set_high().map_err(Error::Output)?;
self.delay.delay_us(TIME_TO_SLEEP);
Ok(())
}
pub fn enable(&mut self) -> Result<(), Error<EIN, EOUT>> {
self.pd_sck.set_low().map_err(Error::Output)?;
self.delay.delay_us(TIME_SCK_LOW);
nb::block! {self.set_mode(self.mode)}
}
pub fn reset(&mut self) -> Result<(), Error<EIN, EOUT>> {
self.disable()?;
self.enable()
}
pub fn retrieve(&mut self) -> nb::Result<i32, Error<EIN, EOUT>> {
self.pd_sck.set_low().map_err(Error::Output)?;
if self.dout.is_high().map_err(Error::Input)? {
return Err(nb::Error::WouldBlock);
}
self.delay.delay_us(TIME_BEFORE_READOUT);
let mut count: i32 = 0;
for _ in 0..24 {
count <<= 1;
self.pd_sck.set_high().map_err(Error::Output)?;
self.delay.delay_us(TIME_SCK_HIGH);
self.pd_sck.set_low().map_err(Error::Output)?;
if self.dout.is_high().map_err(Error::Input)? {
count += 1;
}
self.delay.delay_us(TIME_SCK_LOW);
}
let n_reads = self.mode as u16;
for _ in 0..n_reads {
self.pd_sck.set_high().map_err(Error::Output)?;
self.delay.delay_us(TIME_SCK_HIGH);
self.pd_sck.set_low().map_err(Error::Output)?;
self.delay.delay_us(TIME_SCK_LOW);
}
Ok(i24_to_i32(count))
}
}
#[derive(Copy, Clone)]
pub enum Mode {
ChAGain128 = 1,
ChBGain32 = 2,
ChAGain64 = 3,
}
fn i24_to_i32(x: i32) -> i32 {
if x >= 0x800000 {
x | !0xFFFFFF
} else {
x
}
}
#[cfg(test)]
mod tests {
use crate::*;
#[cfg(feature = "never_type")]
use core::convert::Infallible;
#[test]
fn convert() {
assert_eq!(i24_to_i32(0x000001), 1);
assert_eq!(i24_to_i32(0x000002), 2);
assert_eq!(i24_to_i32(0xFFFFFF), -1);
assert_eq!(i24_to_i32(0xFFFFF3), -13);
assert_eq!(i24_to_i32(0xF00000), -1048576);
assert_eq!(i24_to_i32(0x800000), -8388608);
assert_eq!(i24_to_i32(0x7FFFFF), 8388607);
}
#[test]
#[cfg(feature = "never_type")]
fn infallible_into_ok() {
let this_is_ok: Result<usize, Error<Infallible, Infallible>> = Ok(77);
assert_eq!(this_is_ok.into_ok(), 77);
}
#[test]
#[cfg(feature = "never_type")]
fn never_fail_into_ok() {
let this_is_ok: Result<usize, Error<!, !>> = Ok(77);
assert_eq!(this_is_ok.into_ok(), 77);
}
}