use core::num::NonZeroU32;
use std::io::{Error, Read};
use super::consts::*;
#[derive(Debug)]
pub enum PulseIterState {
Lead{
countdown: u16
},
Sync1,
Sync2,
Data{
current: u8,
pulse: u8 },
Done,
Error(Error)
}
#[derive(Debug)]
pub struct ReadEncPulseIter<R> {
rd: R,
state: PulseIterState,
flag: u8,
}
impl PulseIterState {
pub fn err(&self) -> Option<&Error> {
match self {
PulseIterState::Error(ref error) => Some(error),
_ => None
}
}
pub fn is_done(&self) -> bool {
matches!(self, PulseIterState::Done|PulseIterState::Error(..))
}
pub fn is_lead(&self) -> bool {
matches!(self, PulseIterState::Lead {..})
}
pub fn is_data(&self) -> bool {
matches!(self, PulseIterState::Data {..})
}
pub fn is_sync1(&self) -> bool {
matches!(self, PulseIterState::Sync1)
}
pub fn is_sync2(&self) -> bool {
matches!(self, PulseIterState::Sync2)
}
}
impl<R> ReadEncPulseIter<R> {
pub fn state(&self) -> &PulseIterState {
&self.state
}
pub fn flag(&self) -> u8 {
self.flag
}
pub fn err(&self) -> Option<&Error> {
self.state.err()
}
pub fn is_done(&self) -> bool {
self.state.is_done()
}
pub fn get_mut(&mut self) -> &mut R {
&mut self.rd
}
pub fn get_ref(&self) -> &R {
&self.rd
}
pub fn into_inner(self) -> R {
self.rd
}
pub fn with_state_and_flag(mut self, state: PulseIterState, flag: u8) -> Self {
self.state = state;
self.flag = flag;
self
}
}
impl<R: Read> ReadEncPulseIter<R> {
pub fn new(rd: R) -> Self {
let mut epi = ReadEncPulseIter { rd, state: PulseIterState::Done, flag: 0 };
epi.reset();
epi
}
pub fn reset(&mut self) {
let (flag, state) = match self.rd.by_ref().bytes().next() {
Some(Ok(flag)) => (flag, PulseIterState::Lead {
countdown: if flag & 0x80 == 0 {
LEAD_PULSES_HEAD
} else {
LEAD_PULSES_DATA
}
}),
Some(Err(error)) => (0, PulseIterState::Error(error)),
None => (0, PulseIterState::Done)
};
self.flag = flag;
self.state = state;
}
pub fn data_from_next(&mut self) {
self.state = match self.rd.by_ref().bytes().next() {
Some(Ok(current)) => PulseIterState::Data { current, pulse: 0 },
Some(Err(error)) => PulseIterState::Error(error),
None => PulseIterState::Done
};
}
}
impl<R: Read> Iterator for ReadEncPulseIter<R> {
type Item = NonZeroU32;
fn next(&mut self) -> Option<NonZeroU32> {
match self.state {
PulseIterState::Lead {ref mut countdown} => {
match *countdown - 1 {
0 => {
self.state = PulseIterState::Sync1
}
res => {
*countdown = res
}
}
Some(LEAD_PULSE_LENGTH)
}
PulseIterState::Sync1 => {
self.state = PulseIterState::Sync2;
Some(SYNC_PULSE1_LENGTH)
}
PulseIterState::Sync2 => {
self.state = PulseIterState::Data { current: self.flag, pulse: 0 };
Some(SYNC_PULSE2_LENGTH)
}
PulseIterState::Data { ref mut current, ref mut pulse } => {
let bit_one: bool = *current & 0x80 != 0;
if *pulse == 15 {
self.state = match self.rd.by_ref().bytes().next() {
Some(Ok(current)) => PulseIterState::Data { current, pulse: 0 },
Some(Err(error)) => PulseIterState::Error(error),
None => PulseIterState::Done
};
}
else {
if *pulse & 1 == 1 {
*current = current.rotate_left(1);
}
*pulse += 1;
}
Some(if bit_one { ONE_PULSE_LENGTH } else { ZERO_PULSE_LENGTH })
}
_ => None
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[test]
fn read_enc_pulse_iter_works() {
let data = [0xFF, 0xA5, 0x00];
let mut iter = ReadEncPulseIter::new(Cursor::new(data));
assert_eq!(false, iter.is_done());
for delta in iter.by_ref().take(LEAD_PULSES_DATA as usize) {
assert_eq!(LEAD_PULSE_LENGTH, delta);
}
assert_eq!(false, iter.is_done());
assert_eq!(Some(SYNC_PULSE1_LENGTH), iter.next());
assert_eq!(Some(SYNC_PULSE2_LENGTH), iter.next());
assert_eq!(false, iter.is_done());
assert_eq!(vec![
ONE_PULSE_LENGTH, ONE_PULSE_LENGTH, ONE_PULSE_LENGTH, ONE_PULSE_LENGTH,
ONE_PULSE_LENGTH, ONE_PULSE_LENGTH, ONE_PULSE_LENGTH, ONE_PULSE_LENGTH,
ONE_PULSE_LENGTH, ONE_PULSE_LENGTH, ONE_PULSE_LENGTH, ONE_PULSE_LENGTH,
ONE_PULSE_LENGTH, ONE_PULSE_LENGTH, ONE_PULSE_LENGTH, ONE_PULSE_LENGTH,
ONE_PULSE_LENGTH, ONE_PULSE_LENGTH, ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH,
ONE_PULSE_LENGTH, ONE_PULSE_LENGTH, ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH,
ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH, ONE_PULSE_LENGTH, ONE_PULSE_LENGTH,
ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH, ONE_PULSE_LENGTH, ONE_PULSE_LENGTH,
ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH,
ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH,
ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH,
ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH,
], iter.by_ref().collect::<Vec<_>>());
assert_eq!(true, iter.is_done());
let data = [0x00];
let mut iter = ReadEncPulseIter::new(Cursor::new(data));
assert_eq!(false, iter.is_done());
for delta in iter.by_ref().take(LEAD_PULSES_HEAD as usize) {
assert_eq!(LEAD_PULSE_LENGTH, delta);
}
assert_eq!(false, iter.is_done());
assert_eq!(Some(SYNC_PULSE1_LENGTH), iter.next());
assert_eq!(Some(SYNC_PULSE2_LENGTH), iter.next());
assert_eq!(false, iter.is_done());
assert_eq!(vec![ZERO_PULSE_LENGTH; 16], iter.by_ref().collect::<Vec<_>>());
assert_eq!(true, iter.is_done());
let mut iter = ReadEncPulseIter::new(Cursor::new([]));
assert_eq!(true, iter.is_done());
assert_eq!(None, iter.next());
}
}