use std::f32;
use std::thread;
use std::time::Duration;
use std::mem;
extern crate byteorder;
use byteorder::{ByteOrder, LittleEndian};
extern crate i2cdev;
use self::i2cdev::core::*;
use self::i2cdev::linux::{LinuxI2CDevice, LinuxI2CError};
const EC_MEASURE_EC: u8 = 80;
const EC_MEASURE_SW: u8 = 40;
const EC_MEASURE_TEMP: u8 = 20;
const EC_CALIBRATE_EC: u8 = 10;
const EC_CALIBRATE_SW: u8 = 8;
const EC_I2C: u8 = 4;
const EC_READ: u8 = 2;
const EC_WRITE: u8 = 1;
const EC_VERSION_REGISTER: u8 = 0;
const EC_FW_VERSION_REGISTER: u8 = 1;
const EC_MS_REGISTER: u8 = 2;
const EC_SALINITY_PSU: u8 = 6;
const EC_TEMP_REGISTER: u8 = 10;
const EC_RAW_REGISTER: u8 = 14;
const EC_SOLUTION_REGISTER: u8 = 18;
const EC_CALIBRATE_EC_REGISTER: u8 = 22;
const EC_CALIBRATE_SW_REGISTER: u8 = 26;
const EC_TEMP_COMPENSATION_REGISTER: u8 = 30;
const EC_BUFFER_REGISTER: u8 = 34;
const EC_CONFIG_REGISTER: u8 = 38;
const EC_TASK_REGISTER: u8 = 39;
const EC_TEMP_COMPENSATION_CONFIG_BIT: u8 = 0;
const EC_EC_MEASUREMENT_TIME: u64 = 250;
const EC_TEMP_MEASURE_TIME: u64 = 750;
pub struct EcProbe {
dev: Box<LinuxI2CDevice>,
}
impl EcProbe {
pub fn new(filename: &'static str, address: u16) -> Result<Self, Box<LinuxI2CError>> {
let dev = LinuxI2CDevice::new(filename, address)?;
Ok(EcProbe { dev: Box::new(dev) })
}
pub fn measure_temp(&mut self) -> Result<(f32), Box<LinuxI2CError>> {
self.dev.smbus_write_byte_data(EC_TASK_REGISTER, EC_MEASURE_TEMP)?;
thread::sleep(Duration::from_millis(EC_TEMP_MEASURE_TIME));
Ok(self._read_register(EC_TEMP_REGISTER)?)
}
pub fn set_temp(&mut self, temp_c: f32) -> Result<(), Box<LinuxI2CError>> {
self._write_register(EC_TEMP_REGISTER, temp_c)?;
Ok(())
}
pub fn calibrate_ec(&mut self, solution_ec: f32) -> Result<(), Box<LinuxI2CError>> {
self._write_register(EC_SOLUTION_REGISTER, solution_ec)?;
self.dev.smbus_write_byte_data(EC_TASK_REGISTER, EC_CALIBRATE_EC)?;
thread::sleep(Duration::from_millis(EC_EC_MEASUREMENT_TIME));
Ok(())
}
pub fn calibrate_sw(&mut self, solution_sw: f32) -> Result<(), Box<LinuxI2CError>> {
self._write_register(EC_SOLUTION_REGISTER, solution_sw)?;
self.dev.smbus_write_byte_data(EC_TASK_REGISTER, EC_CALIBRATE_SW)?;
thread::sleep(Duration::from_millis(EC_EC_MEASUREMENT_TIME));
Ok(())
}
pub fn measure_ec(&mut self, new_temp: bool) -> Result<(f32), Box<LinuxI2CError>> {
self.dev.smbus_write_byte_data(EC_TASK_REGISTER, EC_MEASURE_EC)?;
thread::sleep(Duration::from_millis(EC_EC_MEASUREMENT_TIME));
if new_temp == true {
self.measure_temp()?;
}
Ok(self._read_register(EC_MS_REGISTER)?)
}
pub fn measure_raw(&mut self) -> Result<(f32), Box<LinuxI2CError>> {
self.dev.smbus_write_byte_data(EC_TASK_REGISTER, EC_MEASURE_EC)?;
thread::sleep(Duration::from_millis(EC_EC_MEASUREMENT_TIME));
Ok(self._read_register(EC_RAW_REGISTER)?)
}
pub fn measure_sw(&mut self) -> Result<(f32), Box<LinuxI2CError>> {
self.dev
.smbus_write_byte_data(EC_TASK_REGISTER, EC_MEASURE_SW)?;
thread::sleep(Duration::from_millis(EC_EC_MEASUREMENT_TIME));
Ok(self._read_register(EC_SALINITY_PSU)?)
}
pub fn set_temp_constant(&mut self, temp_constant: u8) -> Result<(), Box<LinuxI2CError>> {
self.dev
.smbus_write_byte_data(EC_TEMP_COMPENSATION_REGISTER, temp_constant)?;
Ok(())
}
pub fn get_temp_constant(&mut self) -> Result<(u8), Box<LinuxI2CError>> {
self._change_register(EC_TEMP_COMPENSATION_REGISTER)?;
Ok(self.dev.smbus_read_byte()?)
}
pub fn get_calibration_ec(&mut self) -> Result<(f32), Box<LinuxI2CError>> {
Ok(self._read_register(EC_CALIBRATE_EC_REGISTER)?)
}
pub fn get_calibration_sw(&mut self) -> Result<(f32), Box<LinuxI2CError>> {
Ok(self._read_register(EC_CALIBRATE_SW_REGISTER)?)
}
pub fn read_eeprom(&mut self, address: f32) -> Result<(f32), Box<LinuxI2CError>> {
self._write_register(EC_SOLUTION_REGISTER, address)?;
self.dev.smbus_write_byte_data(EC_TASK_REGISTER, EC_READ)?;
Ok(self._read_register(EC_BUFFER_REGISTER)?)
}
pub fn write_eeprom(&mut self, address: f32, value: f32) -> Result<(f32), Box<LinuxI2CError>> {
self._write_register(EC_SOLUTION_REGISTER, address)?;
self._write_register(EC_BUFFER_REGISTER, value)?;
self.dev.smbus_write_byte_data(EC_TASK_REGISTER, EC_WRITE)?;
Ok(self._read_register(EC_BUFFER_REGISTER)?)
}
pub fn use_temperature_compensation(&mut self, b: bool) -> Result<(), Box<LinuxI2CError>> {
self._change_register(EC_CONFIG_REGISTER)?;
let mut config: u8 = self.dev.smbus_read_byte()?;
thread::sleep(Duration::from_millis(10));
if b {
config |= 1 << EC_TEMP_COMPENSATION_CONFIG_BIT;
} else {
config &= !(1 << EC_TEMP_COMPENSATION_CONFIG_BIT);
}
self.dev.smbus_write_byte_data(EC_CONFIG_REGISTER, config)?;
thread::sleep(Duration::from_millis(10));
Ok(())
}
pub fn get_version(&mut self) -> Result<(u8), Box<LinuxI2CError>> {
self._change_register(EC_VERSION_REGISTER)?;
Ok(self.dev.smbus_read_byte()?)
}
pub fn get_firmware(&mut self) -> Result<(u8), Box<LinuxI2CError>> {
self._change_register(EC_FW_VERSION_REGISTER)?;
Ok(self.dev.smbus_read_byte()?)
}
pub fn reset(&mut self) -> Result<(), Box<LinuxI2CError>> {
self._write_register(EC_CALIBRATE_EC_REGISTER, f32::NAN)?;
self._write_register(EC_CALIBRATE_SW_REGISTER, f32::NAN)?;
Ok(())
}
pub fn using_temperature_compensation(&mut self) -> Result<(u8), Box<LinuxI2CError>> {
self._change_register(EC_CONFIG_REGISTER)?;
let config: u8 = self.dev.smbus_read_byte()?;
Ok((config >> EC_TEMP_COMPENSATION_CONFIG_BIT) & 1)
}
pub fn set_i2c_address(&mut self, i2c_address: u8) -> Result<(), Box<LinuxI2CError>> {
self._write_register(EC_BUFFER_REGISTER, i2c_address as f32)?;
self.dev.smbus_write_byte_data(EC_TASK_REGISTER, EC_I2C)?;
Ok(())
}
pub fn _write_register(&mut self, register: u8, f_val: f32) -> Result<(), Box<LinuxI2CError>> {
unsafe {
let buf: [u8; 4] = mem::transmute(f_val);
self._change_register(register)?;
self.dev.smbus_write_byte_data(register + 0, buf[0])?;
thread::sleep(Duration::from_millis(10));
self.dev.smbus_write_byte_data(register + 1, buf[1])?;
thread::sleep(Duration::from_millis(10));
self.dev.smbus_write_byte_data(register + 2, buf[2])?;
thread::sleep(Duration::from_millis(10));
self.dev.smbus_write_byte_data(register + 3, buf[3])?;
thread::sleep(Duration::from_millis(10));
Ok(())
}
}
pub fn _read_register(&mut self, register: u8) -> Result<(f32), Box<LinuxI2CError>> {
let mut buf: [u8; 4] = [0; 4];
self._change_register(register)?;
buf[0] = self.dev.smbus_read_byte()?;
thread::sleep(Duration::from_millis(10));
buf[1] = self.dev.smbus_read_byte()?;
thread::sleep(Duration::from_millis(10));
buf[2] = self.dev.smbus_read_byte()?;
thread::sleep(Duration::from_millis(10));
buf[3] = self.dev.smbus_read_byte()?;
thread::sleep(Duration::from_millis(10));
Ok(LittleEndian::read_f32(&buf))
}
pub fn _change_register(&mut self, register: u8) -> Result<(), Box<LinuxI2CError>> {
self.dev.smbus_write_byte(register)?;
thread::sleep(Duration::from_millis(10));
Ok(())
}
}