use crate::{Error, H10MeasurementType, PolarResult};
fn bytes_to_data(data: &[u8], len: usize) -> i32 {
if len == 3 {
let mut buf = [0u8; 4];
buf[..len].copy_from_slice(&data[..len]);
if (data[len - 1] & 0x80) > 0 {
for i in buf[len..].iter_mut() {
*i = 0xff;
}
}
i32::from_le_bytes(buf)
} else if len == 2 {
let mut buf = [0u8; 2];
buf[..len].copy_from_slice(&data[..len]);
if (data[len - 1] & 0x80) > 0 {
for i in buf[len..].iter_mut() {
*i = 0xff;
}
}
let small = i16::from_le_bytes(buf);
i32::from(small)
} else {
let mut buf = [0u8; 1];
buf[..len].copy_from_slice(&data[..len]);
let small = i8::from_le_bytes(buf);
i32::from(small)
}
}
#[derive(Debug)]
pub struct PmdRead {
data_type: H10MeasurementType,
time_stamp: u64,
data: Vec<PmdData>,
}
impl PmdRead {
pub fn new(data_stream: Vec<u8>) -> PolarResult<PmdRead> {
let data_type = H10MeasurementType::try_from(data_stream[0]);
if let Err(_e) = data_type {
return Err(Error::InvalidData);
}
let data_type = data_type.unwrap();
let time_stamp = u64::from_le_bytes(
data_stream[1..9]
.try_into()
.expect("Timestamp slice could not be converted to u64"),
);
let frame_length = data_type.as_bytes() as usize;
let samples = data_stream[10..].len() / frame_length;
let mut data: Vec<PmdData> = Vec::new();
let mut current_pos = 10;
for _ in 0..samples {
data.push(match data_type {
H10MeasurementType::Ecg => PmdData::Ecg(Ecg::new(
&data_stream[current_pos..current_pos + frame_length].to_vec(),
)?),
H10MeasurementType::Acc => PmdData::Acc(Acc::new(
&data_stream[current_pos..current_pos + frame_length].to_vec(),
)?),
});
current_pos += frame_length;
}
Ok(PmdRead {
data_type,
time_stamp,
data,
})
}
pub fn data_type(&self) -> &H10MeasurementType {
&self.data_type
}
pub fn time_stamp(&self) -> u64 {
self.time_stamp
}
pub fn data(self) -> Vec<PmdData> {
self.data
}
}
#[derive(Debug)]
pub enum PmdData {
Ecg(Ecg),
Acc(Acc),
}
#[derive(Debug)]
pub struct Ecg {
val: i32,
}
impl Ecg {
fn new(data: &Vec<u8>) -> PolarResult<Ecg> {
if data.len() < 3 {
eprintln!("ECG expects 3 bytes of data, got {}.", data.len());
return Err(Error::InvalidLength);
}
let mut mag = [0u8; 4];
mag[1..4].clone_from_slice(&data[..3]);
let val = bytes_to_data(&data[..3], 3);
Ok(Ecg { val })
}
pub fn val(&self) -> &i32 {
&self.val
}
}
#[derive(Debug)]
pub struct Acc {
x: i32,
y: i32,
z: i32,
}
impl Acc {
fn new(data: &Vec<u8>) -> PolarResult<Acc> {
if data.len() < 2 {
eprintln!("Acceleration expects 2 bytes of data, got {}", data.len());
return Err(Error::InvalidLength);
}
let frame_size = 6;
Ok(Acc {
x: bytes_to_data(&data[..frame_size / 3], frame_size / 3),
y: bytes_to_data(&data[frame_size / 3..(frame_size / 3) * 2], frame_size / 3),
z: bytes_to_data(
&data[(frame_size / 3) * 2..(frame_size / 3) * 3],
frame_size / 3,
),
})
}
pub fn data(&self) -> (i32, i32, i32) {
(self.x, self.y, self.z)
}
}
#[derive(Debug)]
pub struct HeartRate {
bpm: u8,
rr: Option<Vec<u16>>,
}
impl HeartRate {
pub fn new(data: Vec<u8>) -> PolarResult<HeartRate> {
if data.len() < 2 {
eprintln!(
"Heart rate expects atleast 2 bytes of data, got {}",
data.len()
);
return Err(Error::InvalidLength);
}
let flags = data[0];
let samples = if flags & 0b00010000 == 16 {
(data.len() - 2) / 2
} else {
0
};
let bpm = data[1];
let mut rr_samp = vec![];
for i in 0..samples {
rr_samp.push(((bytes_to_data(&data[i * 2 + 2..i * 2 + 4], 2) as u32 * 128) / 125) as u16); }
let rr = if !rr_samp.is_empty() {
Some(rr_samp)
} else {
None
};
Ok(HeartRate { bpm, rr })
}
pub fn bpm(&self) -> &u8 {
&self.bpm
}
pub fn rr(&self) -> &Option<Vec<u16>> {
&self.rr
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn pmd_read_acc_new() {
let response = PmdRead::new(vec![
0x02, 0xea, 0x54, 0xa2, 0x42, 0x8b, 0x45, 0x52, 0x08, 0x01, 0x45, 0xff, 0xe4, 0xff,
0xb5, 0x03, 0x45, 0xff, 0xe4, 0xff, 0xb8, 03,
])
.unwrap();
assert_eq!(*response.data_type(), H10MeasurementType::Acc);
assert_eq!(response.time_stamp(), 599618164814402794u64);
let the_data = response.data();
match &the_data[0] {
PmdData::Acc(thing) => {
let (x, y, z) = thing.data();
assert_eq!(x, -187);
assert_eq!(y, -28);
assert_eq!(z, 949);
}
_ => panic!("Instantiated object of wrong type, expected Acc"),
}
}
#[test]
fn pmd_read_ecg_new() {
let response = PmdRead::new(vec![
0x00, 0xea, 0x54, 0xa2, 0x42, 0x8b, 0x45, 0x52, 0x08, 0x00, 0xff, 0xff, 0xff,
])
.unwrap();
assert_eq!(*response.data_type(), H10MeasurementType::Ecg);
assert_eq!(response.time_stamp(), 599618164814402794u64);
let the_data = response.data();
match &the_data[0] {
PmdData::Ecg(thing) => assert_eq!(*thing.val(), -1),
_ => panic!("Instantiated object of wrong type, expected Ecg"),
}
}
#[test]
fn convert_i24_to_i32() {
let data = [0xff, 0xff, 0xff];
assert_eq!(-1, bytes_to_data(&data[..], 3));
let data = [0x00, 0x00, 0x10];
assert_eq!(1_048_576, bytes_to_data(&data[..], 3));
}
#[test]
fn convert_i16_to_i32() {
let data = [0xff, 0xff];
assert_eq!(-1, bytes_to_data(&data[..], 2));
let data = [0x00, 0x10];
assert_eq!(4096, bytes_to_data(&data[..], 2));
}
#[test]
fn convert_i8_to_i32() {
let data = [0xff];
assert_eq!(-1, bytes_to_data(&data[..], 1));
let data = [0x10];
assert_eq!(16, bytes_to_data(&data[..], 1));
}
#[test]
fn hr_new() {
let hr = HeartRate::new(vec![16, 60, 55, 4, 7, 3]).unwrap();
assert_eq!(*hr.bpm(), 60);
assert_eq!(*hr.rr(), Some(vec![1104, 793]));
}
}