extern crate cast;
#[cfg(feature = "with_floating_point")]
use cast::f32;
#[cfg(feature = "with_floating_point")]
use core::f32;
use cast::i16;
use prelude::Read;
use prelude::Write;
use reg::Register;
use reg_res::ResolutionVal;
const RANGE_LIMIT: i16 = 256;
const BIT_SIGN: u8 = 0x10;
pub trait ReadableTempRegister: Read {
#[cfg(feature = "with_floating_point")]
fn get_celsius(&self, res: ResolutionVal) -> f32;
fn get_milli_celsius(&self, res: ResolutionVal) -> i32;
fn get_raw_value(&self) -> u16;
}
impl ReadableTempRegister for Register {
#[cfg(feature = "with_floating_point")]
fn get_celsius(&self, res: ResolutionVal) -> f32 {
let high = self.get_msb() & 0x1f; let low: u8 = self.get_lsb().unwrap();
let temp_dec = get_decimal_part(high, low);
let mut ftemp = f32(temp_dec);
ftemp += get_fractional_part_float(res, low);
ftemp
}
fn get_milli_celsius(&self, res: ResolutionVal) -> i32 {
if res == ResolutionVal::Deg_0_0625C {
panic!("precision invalid for milli C°")
}
let high = self.get_msb() & 0x1f; let low: u8 = self.get_lsb().unwrap();
let mut temp_dec = get_decimal_part(high, low) as i32 * 1000;
temp_dec += get_fractional_part_dec(res, low) as i32;
temp_dec
}
fn get_raw_value(&self) -> u16 {
self.as_u16()
}
}
pub trait WritableTempRegister: ReadableTempRegister + Write {
#[cfg(feature = "with_floating_point")]
fn set_celsius(&mut self, val: f32);
fn set_milli_celsius(&mut self, val: i32);
}
impl WritableTempRegister for Register {
#[cfg(feature = "with_floating_point")]
fn set_celsius(&mut self, val: f32) {
if val >= f32(RANGE_LIMIT) || val <= -f32(RANGE_LIMIT) {
panic!(
"temperature {} exceeds valid range of +-{}",
val, RANGE_LIMIT
)
}
let temp_dec: u16 = val as u16;
let mut high = (temp_dec / 16) as u8;
let mut low = (temp_dec * 16) as u8;
if val < 0.0 {
high |= BIT_SIGN; }
let fract: f32 = val - (temp_dec as f32);
let mut fract_bits: u8 =
(fract / get_precision_factor_float(ResolutionVal::Deg_0_0625C)) as u8;
fract_bits &= 0b1100; low += fract_bits;
self.set_msb(high);
self.set_lsb(low);
}
fn set_milli_celsius(&mut self, val: i32) {
if val.abs() >= 1000 * RANGE_LIMIT as i32 {
panic!(
"temperature {} exceeds valid range of +-{}",
val, RANGE_LIMIT
)
}
let temp_dec: i32 = val / 1000;
let mut high = (temp_dec / 16) as u8;
let mut low = (temp_dec * 16) as u8;
if val < 0 {
high |= BIT_SIGN; }
let fract: i32 = val - (temp_dec * 1000);
let mut fract_bits: u8 =
(fract / get_precision_factor_dec(ResolutionVal::Deg_0_0625C) as i32) as u8;
fract_bits &= 0b1100; low += fract_bits;
self.set_msb(high);
self.set_lsb(low);
}
}
fn get_decimal_part(mut high: u8, low: u8) -> i16 {
high &= 0x1f;
if high & BIT_SIGN == BIT_SIGN {
high &= 0x0f; 256 - (i16(high) * 16 + i16(low) / 16)
} else {
i16(high) * 16 + i16(low) / 16
}
}
fn get_fractional_part_dec(res: ResolutionVal, low: u8) -> u16 {
let fract: u16 = (low & 0x000F).into(); (fract >> (3 - res as u16)) * get_precision_factor_dec(res)
}
#[cfg(feature = "with_floating_point")]
fn get_fractional_part_float(res: ResolutionVal, low: u8) -> f32 {
let fract = low & 0x000F; f32(fract >> (3 - res as u8)) * get_precision_factor_float(res)
}
#[cfg(feature = "with_floating_point")]
fn get_precision_factor_float(res: ResolutionVal) -> f32 {
match res {
ResolutionVal::Deg_0_0625C => 0.0625,
ResolutionVal::Deg_0_125C => 0.125,
ResolutionVal::Deg_0_25C => 0.25,
ResolutionVal::Deg_0_5C => 0.5,
}
}
fn get_precision_factor_dec(res: ResolutionVal) -> u16 {
match res {
ResolutionVal::Deg_0_0625C => 62,
ResolutionVal::Deg_0_125C => 125,
ResolutionVal::Deg_0_25C => 250,
ResolutionVal::Deg_0_5C => 500,
}
}
#[cfg(test)]
mod tests {
use super::*;
use reg_res::ResolutionVal;
#[test]
fn read_sensor_value() {
let msb: u8 = 0b00000001;
let lsb: u8 = 0b10010100;
let mut reg = Register::new(1, 2);
reg.set_buf([msb, lsb]);
let temp = reg.get_celsius(ResolutionVal::Deg_0_0625C);
assert_eq!(temp, 25.25);
let temp = reg.get_milli_celsius(ResolutionVal::Deg_0_125C);
assert_eq!(temp, 25250);
}
#[test]
fn set_celsius_integer() {
let mut reg = Register::new(1, 2);
reg.set_celsius(90.0);
assert_eq!(0b00000101, reg.get_msb());
assert_eq!(0b10100000, reg.get_lsb().unwrap());
let temp = reg.get_celsius(ResolutionVal::Deg_0_25C);
assert_eq!(temp, 90.00);
let temp = reg.get_milli_celsius(ResolutionVal::Deg_0_25C);
assert_eq!(temp, 90000);
}
#[test]
fn set_celsius_fractional() {
let mut reg = Register::new(1, 2);
reg.set_celsius(90.75);
assert_eq!(0b00000101, reg.get_msb());
assert_eq!(0b10101100, reg.get_lsb().unwrap());
let temp = reg.get_celsius(ResolutionVal::Deg_0_25C);
assert_eq!(temp, 90.75);
let temp = reg.get_milli_celsius(ResolutionVal::Deg_0_25C);
assert_eq!(temp, 90750);
reg.set_celsius(90.25);
assert_eq!(0b00000101, reg.get_msb());
assert_eq!(0b10100100, reg.get_lsb().unwrap());
}
#[test]
fn set_milli_celsius() {
let mut reg = Register::new(1, 2);
reg.set_milli_celsius(90000);
assert_eq!(0b00000101, reg.get_msb());
assert_eq!(0b10100000, reg.get_lsb().unwrap());
let temp = reg.get_celsius(ResolutionVal::Deg_0_25C);
assert_eq!(temp, 90.00);
let temp = reg.get_milli_celsius(ResolutionVal::Deg_0_25C);
assert_eq!(temp, 90000);
}
#[test]
fn set_milli_celsius_fractional() {
let mut reg = Register::new(1, 2);
reg.set_milli_celsius(90250);
assert_eq!(0b00000101, reg.get_msb());
assert_eq!(0b10100100, reg.get_lsb().unwrap());
let temp = reg.get_celsius(ResolutionVal::Deg_0_25C);
assert_eq!(temp, 90.25);
let temp = reg.get_milli_celsius(ResolutionVal::Deg_0_25C);
assert_eq!(temp, 90250);
}
}