#![no_std]
extern crate embedded_hal as hal;
use hal::blocking::delay::DelayMs;
#[derive(Debug)]
pub enum Error<CommE> {
Comm(CommE),
OutOfRange,
Configuration
}
pub const ADDR_0_0_7BIT:u8 = 0x0C;
pub const ADDR_0_1_7BIT:u8 = 0x0D;
pub const ADDR_1_0_7BIT:u8 = 0x0E;
pub const ADDR_1_1_7BIT:u8 = 0x0F;
pub const ADDR_7BIT_DEFAULT:u8 = 0x0E;
pub const ADDR_0_0_8BIT:u8 = 0x18;
pub const ADDR_0_1_8BIT:u8 = 0x1A;
pub const ADDR_1_0_8BIT:u8 = 0x1C;
pub const ADDR_1_1_8BIT:u8 = 0x1E;
pub const ADDR_8BIT_DEFAULT:u8 = 0x1C;
pub const DEFAULT_ADDRESS:u8 = ADDR_7BIT_DEFAULT;
pub const REG_WAI:u8 = 0x00;
const REG_DATA_X:u8 = 0x03;
const REG_MAG_DATA_START:u8 = REG_DATA_X;
const REG_CTRL1: u8 = 0x0A;
pub const REG_CTRL2: u8 = 0x0B;
pub const REG_AVG_CTRL:u8 = 0x41;
pub const REG_SENS_MODE_SELECT:u8 = 0x42;
const AVG_CTRL_16X: u8 = 0x24;
const SRPD_MODE_LOW_POWER: u8 = 0xC0;
const BLOCK_BUF_LEN: usize = 32;
pub struct IST8310<I2C> {
i2c_port: I2C,
address: u8,
block_buf: [u8; BLOCK_BUF_LEN],
avg_ctrl_reg_set: u8,
srpd_ctrl_reg_set: u8,
}
impl<I2C, CommE> IST8310<I2C>
where
I2C: hal::blocking::i2c::Write<Error = CommE>
+ hal::blocking::i2c::Read<Error = CommE>
+ hal::blocking::i2c::WriteRead<Error = CommE>,
{
pub fn default(i2c: I2C) -> Result<Self, Error<CommE>> {
Self::new(i2c, DEFAULT_ADDRESS)
}
pub fn new(i2c_port: I2C, address: u8) -> Result<Self, Error<CommE>> {
let mut inst = Self {
i2c_port,
address,
block_buf: [0; BLOCK_BUF_LEN],
avg_ctrl_reg_set: 0,
srpd_ctrl_reg_set: 0,
};
inst.reset()?;
Ok(inst)
}
fn reset(&mut self) -> Result<(), Error<CommE>> {
const SRST_POR_FLAG: u8 = 0x01 << 0;
self.write_reg(REG_CTRL2, SRST_POR_FLAG)?;
self.avg_ctrl_reg_set = AVG_CTRL_16X;
self.write_reg(REG_AVG_CTRL, self.avg_ctrl_reg_set)?;
self.srpd_ctrl_reg_set = SRPD_MODE_LOW_POWER;
self.write_reg(REG_SENS_MODE_SELECT, self.srpd_ctrl_reg_set)?;
let product_id = self.read_reg(REG_WAI)?;
assert!(product_id == 0x10);
Ok(())
}
fn read_block(&mut self, reg: u8, recv_count: usize) -> Result<(), Error<CommE>> {
let cmd_buf = [reg];
self.i2c_port
.write_read(self.address, &cmd_buf, &mut self.block_buf[..recv_count])
.map_err(Error::Comm)?;
Ok(())
}
fn read_reg(&mut self, reg: u8 ) -> Result<u8, Error<CommE>> {
self.read_block(reg,1)?;
Ok(self.block_buf[0])
}
fn write_reg(&mut self, reg: u8, val: u8) -> Result<(), Error<CommE>> {
self.block_buf[0] = reg;
self.block_buf[1] = val;
self.i2c_port
.write(self.address, &self.block_buf[..2])
.map_err(Error::Comm)?;
Ok(())
}
fn reading_in_range(sample: &[i16; 3]) -> bool {
const MDR_XY_AXES: i16 = 1600;
const MDR_Z_AXIS: i16 = 2500;
const RESO_PER_BIT: f32 = 0.3;
const MAX_VAL_XY: i16 = (((MDR_XY_AXES as f32) / RESO_PER_BIT) as i16) + 1;
const MAX_VAL_Z: i16 = (((MDR_Z_AXIS as f32) / RESO_PER_BIT) as i16) + 1;
sample[0].abs() < MAX_VAL_XY &&
sample[1].abs() < MAX_VAL_XY &&
sample[2].abs() < MAX_VAL_Z
}
fn raw_reading_to_i16(buf: &[u8], idx: usize) -> i16 {
let val: i16 = (buf[idx] as i16) | ((buf[idx+1] as i16) << 8) ;
val
}
pub fn get_mag_vector(&mut self, delay_source: &mut impl DelayMs<u8>) -> Result<[i16; 3], Error<CommE>> {
const SINGLE_MEASURE_MODE: u8 = 0x01;
const XYZ_DATA_LEN: usize = 6;
self.write_reg(REG_CTRL1, SINGLE_MEASURE_MODE)?;
delay_source.delay_ms(6);
self.read_block(REG_MAG_DATA_START, XYZ_DATA_LEN)?;
let sample_i16 = [
Self::raw_reading_to_i16(&self.block_buf, 0),
Self::raw_reading_to_i16(&self.block_buf, 2),
Self::raw_reading_to_i16(&self.block_buf, 4)
];
if !Self::reading_in_range(&sample_i16) {
return Err(Error::OutOfRange)
}
Ok(sample_i16)
}
}