use std::io;
use std::time::Duration;
use byteorder::{ReadBytesExt, LE};
use crate::client::AMS_HEADER_SIZE;
use crate::errors::ErrContext;
use crate::{Error, Result};
pub type Handle = u32;
pub struct Attributes {
pub length: usize,
pub trans_mode: TransmissionMode,
pub max_delay: Duration,
pub cycle_time: Duration,
}
impl Attributes {
pub fn new(length: usize, trans_mode: TransmissionMode,
max_delay: Duration, cycle_time: Duration) -> Self {
Self { length, trans_mode, max_delay, cycle_time }
}
}
#[repr(u32)]
#[derive(Clone, Copy, Debug)]
pub enum TransmissionMode {
NoTrans = 0,
ServerCycle = 3,
ServerOnChange = 4,
}
pub struct Notification {
data: Vec<u8>,
nstamps: u32,
}
impl std::fmt::Debug for Notification {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "Notification [")?;
for sample in self.samples() {
writeln!(f, " {:?}", sample)?;
}
write!(f, "]")
}
}
impl Notification {
pub fn new(data: impl Into<Vec<u8>>) -> Result<Self> {
let data = data.into();
if data.len() < AMS_HEADER_SIZE + 8 { return Err(Error::Io("parsing notification",
io::ErrorKind::UnexpectedEof.into()));
}
let mut ptr = &data[AMS_HEADER_SIZE + 4..];
let nstamps = ptr.read_u32::<LE>().ctx("parsing notification")?;
for _ in 0..nstamps {
let _timestamp = ptr.read_u64::<LE>().ctx("parsing notification")?;
let nsamples = ptr.read_u32::<LE>().ctx("parsing notification")?;
for _ in 0..nsamples {
let _handle = ptr.read_u32::<LE>().ctx("parsing notification")?;
let length = ptr.read_u32::<LE>().ctx("parsing notification")? as usize;
if ptr.len() >= length {
ptr = &ptr[length..];
} else {
return Err(Error::Io("parsing notification",
io::ErrorKind::UnexpectedEof.into()));
}
}
}
if ptr.is_empty() {
Ok(Self { data, nstamps })
} else {
Err(Error::Io("parsing notification",
io::ErrorKind::UnexpectedEof.into()))
}
}
pub fn samples(&self) -> SampleIter<'_> {
SampleIter { data: &self.data[46..], cur_timestamp: 0,
stamps_left: self.nstamps, samples_left: 0 }
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Sample<'a> {
pub handle: Handle,
pub timestamp: u64, pub data: &'a [u8],
}
pub struct SampleIter<'a> {
data: &'a [u8],
cur_timestamp: u64,
stamps_left: u32,
samples_left: u32,
}
impl<'a> Iterator for SampleIter<'a> {
type Item = Sample<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.samples_left > 0 {
let handle = self.data.read_u32::<LE>().expect("size");
let length = self.data.read_u32::<LE>().expect("size") as usize;
let (data, rest) = self.data.split_at(length);
self.data = rest;
self.samples_left -= 1;
Some(Sample { handle, data, timestamp: self.cur_timestamp })
} else if self.stamps_left > 0 {
self.cur_timestamp = self.data.read_u64::<LE>().expect("size");
self.samples_left = self.data.read_u32::<LE>().expect("size");
self.stamps_left -= 1;
self.next()
} else {
None
}
}
}