use core::fmt;
use core::fmt::Display;
use core::mem::transmute;
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::{InputPin, OutputPin};
use crate::LoadCell;
#[repr(u8)]
#[derive(Clone, Copy)]
pub enum GainMode {
A128 = 1, B32 = 2,
A64 = 3,
}
pub const HX711_MINIMUM: i32 = -(2i32.saturating_pow(24 - 1));
pub const HX711_MAXIMUM: i32 = 2i32.saturating_pow(24 - 1) - 1;
const HX711_DELAY_TIME_US: u32 = 1;
const HX711_TARE_DELAY_TIME_US: u32 = 5000;
const HX711_TARE_SLEEP_TIME_US: u32 = 10000;
pub struct HX711<SckPin, DTPin, Delay> {
sck_pin: SckPin,
dt_pin: DTPin,
delay: Delay,
last_reading: i32,
gain_mode: GainMode,
offset: i32, scale: f32, }
#[derive(Debug)]
pub struct NotReadyError;
impl Display for NotReadyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Device not ready to read")
}
}
impl<SckPin, DTPin, Delay, ESCK, EDT> HX711<SckPin, DTPin, Delay>
where
SckPin: OutputPin<Error = ESCK>,
DTPin: InputPin<Error = EDT>,
Delay: DelayNs,
EDT: fmt::Debug,
ESCK: fmt::Debug,
{
pub fn new(mut sck_pin: SckPin, dt_pin: DTPin, delay: Delay) -> Self {
sck_pin.set_low().unwrap();
Self {
sck_pin,
dt_pin,
delay,
last_reading: 0,
gain_mode: GainMode::A64,
offset: 0,
scale: 1.0,
}
}
pub fn is_ready(&mut self) -> bool {
self.dt_pin.is_low().unwrap()
}
fn read_hx711_bit(&mut self, hx711_delay_time_us: u32) -> bool {
self.sck_pin.set_high().unwrap();
self.delay.delay_us(hx711_delay_time_us);
let mut pin_state = true;
if self.dt_pin.is_low().unwrap() {
pin_state = false;
}
self.sck_pin.set_low().unwrap();
self.delay.delay_us(hx711_delay_time_us);
pin_state
}
fn toggle_sck_bit(&mut self, hx711_delay_time_us: u32) {
critical_section::with(|_| {
self.sck_pin.set_high().unwrap();
self.delay.delay_us(hx711_delay_time_us);
self.sck_pin.set_low().unwrap();
self.delay.delay_us(hx711_delay_time_us);
});
}
pub fn set_gain_mode(&mut self, gain_mode: GainMode) {
self.gain_mode = gain_mode;
}
pub fn get_gain_mode(&self) -> GainMode {
self.gain_mode
}
fn read_bits(&mut self) -> i32 {
let mut value = critical_section::with(|_| {
let mut value: u32 = 0;
let mut current_bit: u32;
for _ in 0..24 {
current_bit = self.read_hx711_bit(HX711_DELAY_TIME_US) as u32;
value = (value << 1) | current_bit;
}
value
});
let current_gain_mode = self.gain_mode as u8;
for _ in 0..current_gain_mode {
self.toggle_sck_bit(HX711_DELAY_TIME_US);
}
if value & 0b10000000_00000000_00000000 >= 1 {
value |= 0b11111111_00000000_00000000_00000000_u32;
}
let mut signed = unsafe { transmute::<u32, i32>(value) };
signed = signed.clamp(HX711_MINIMUM, HX711_MAXIMUM);
signed
}
}
impl<SckPin, DTPin, Delay, ESCK, EDT> LoadCell for HX711<SckPin, DTPin, Delay>
where
SckPin: OutputPin<Error = ESCK>,
DTPin: InputPin<Error = EDT>,
Delay: DelayNs,
ESCK: fmt::Debug,
EDT: fmt::Debug,
{
type Offset = i32;
type Scale = f32;
type NotReadyError = NotReadyError;
fn read(&mut self) -> Result<i32, Self::NotReadyError> {
if !self.is_ready() {
return Err(NotReadyError);
}
let signed = self.read_bits();
self.last_reading = signed - self.offset;
Ok(self.last_reading)
}
fn get_offset(&self) -> Self::Offset {
self.offset as Self::Offset
}
fn get_scale(&self) -> Self::Scale {
self.scale as Self::Scale
}
fn read_scaled(&mut self) -> Result<Self::Scale, NotReadyError> {
let raw = self.read()?;
Ok(raw as f32 * self.scale)
}
fn set_offset(&mut self, offset: Self::Offset) {
self.offset = offset;
}
fn set_scale(&mut self, scale: Self::Scale) {
self.scale = scale;
}
fn tare(&mut self, num_samples: usize) {
let mut current;
let mut average: f32 = 0.0;
for n in 1..=num_samples {
while !self.is_ready() {
self.delay.delay_us(HX711_TARE_DELAY_TIME_US);
}
current = self.read_bits() as f32;
self.delay.delay_us(HX711_TARE_SLEEP_TIME_US);
average += (current - average) / (n as f32);
}
self.offset = average as Self::Offset;
}
}