use core::num::NonZeroU32;
use core::slice;
use std::io::{Result, Write};
use super::consts::*;
const SYNC_PULSE_TOLERANCE: u32 = (SYNC_PULSE2_LENGTH.get() - SYNC_PULSE1_LENGTH.get())/2;
const SYNC_PULSE1_MIN: u32 = SYNC_PULSE1_LENGTH.get() - SYNC_PULSE_TOLERANCE;
const SYNC_PULSE1_MAX: u32 = SYNC_PULSE1_LENGTH.get() + SYNC_PULSE_TOLERANCE - 1;
const SYNC_PULSE2_MIN: u32 = SYNC_PULSE2_LENGTH.get() - SYNC_PULSE_TOLERANCE;
const SYNC_PULSE2_MAX: u32 = SYNC_PULSE2_LENGTH.get() + SYNC_PULSE_TOLERANCE - 1;
const LEAD_PULSE_TOLERANCE: u32 = 250;
const LEAD_PULSE_MIN: u32 = LEAD_PULSE_LENGTH.get() - LEAD_PULSE_TOLERANCE;
const LEAD_PULSE_MAX: u32 = LEAD_PULSE_LENGTH.get() + LEAD_PULSE_TOLERANCE - 1;
const DATA_PULSE_TOLERANCE: u32 = 250;
const DATA_PULSE_MIN: u32 = ZERO_PULSE_LENGTH.get() - DATA_PULSE_TOLERANCE;
const DATA_PULSE_MAX: u32 = ONE_PULSE_LENGTH.get() + DATA_PULSE_TOLERANCE - 1;
const DATA_PULSE_THRESHOLD: u32 = (ZERO_PULSE_LENGTH.get() + ONE_PULSE_LENGTH.get())/2;
const MIN_LEAD_COUNT: u32 = 16;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PulseDecodeState {
Idle,
Lead {
counter: u32
},
Sync1,
Sync2,
Data{
current: u8,
pulse: u8,
written: u32
},
}
#[derive(Debug)]
pub struct PulseDecodeWriter<W> {
state: PulseDecodeState,
wr: W,
}
impl PulseDecodeState {
pub fn is_idle(&self) -> bool {
matches!(self, PulseDecodeState::Idle)
}
pub fn is_lead(&self) -> bool {
matches!(self, PulseDecodeState::Lead {..})
}
pub fn is_data(&self) -> bool {
matches!(self, PulseDecodeState::Data {..})
}
pub fn is_sync1(&self) -> bool {
matches!(self, PulseDecodeState::Sync1)
}
pub fn is_sync2(&self) -> bool {
matches!(self, PulseDecodeState::Sync2)
}
}
impl<W> PulseDecodeWriter<W> {
pub fn reset(&mut self) {
self.state = PulseDecodeState::Idle;
}
pub fn is_idle(&self) -> bool {
self.state.is_idle()
}
pub fn into_inner(self) -> W {
self.wr
}
pub fn state(&self) -> PulseDecodeState {
self.state
}
pub fn get_mut(&mut self) -> &mut W {
&mut self.wr
}
pub fn get_ref(&self) -> &W {
&self.wr
}
pub fn data_size(&self) -> Option<NonZeroU32> {
NonZeroU32::new(if let PulseDecodeState::Data { written, .. } = self.state {
written
}
else {
0
})
}
pub fn with_state(mut self, state: PulseDecodeState) -> Self {
self.state = state;
self
}
}
impl<W: Write> PulseDecodeWriter<W> {
pub fn new(wr: W) -> Self {
PulseDecodeWriter { state: PulseDecodeState::Idle, wr }
}
pub fn end(&mut self) -> Result<Option<NonZeroU32>> {
let res = if let PulseDecodeState::Data { mut current, pulse, written } = self.state {
NonZeroU32::new(if pulse <= 1 {
written
}
else {
if pulse & 1 == 1 {
current &= !1;
}
current <<= (16 - (pulse & 15)) >> 1;
self.write_byte(current)?;
written + 1
})
}
else {
None
};
self.state = PulseDecodeState::Idle;
Ok(res)
}
pub fn write_decoded_pulses<I>(&mut self, iter: I) -> Result<Option<NonZeroU32>>
where I: Iterator<Item=NonZeroU32>
{
let mut iter = iter.peekable();
if iter.peek().is_none() {
return self.end(); }
for delta in iter {
match self.state {
PulseDecodeState::Idle => {
if let LEAD_PULSE_MIN..=LEAD_PULSE_MAX = delta.get() {
self.state = PulseDecodeState::Lead { counter: 1 };
}
}
PulseDecodeState::Lead { counter } => match delta.get() {
SYNC_PULSE1_MIN..=SYNC_PULSE1_MAX if counter >= MIN_LEAD_COUNT => {
self.state = PulseDecodeState::Sync1;
}
LEAD_PULSE_MIN..=LEAD_PULSE_MAX => {
self.state = PulseDecodeState::Lead { counter: counter.saturating_add(1) };
}
_ => { self.state = PulseDecodeState::Idle },
}
PulseDecodeState::Sync1 => match delta.get() {
SYNC_PULSE2_MIN..=SYNC_PULSE2_MAX => {
self.state = PulseDecodeState::Sync2;
}
_ => { self.state = PulseDecodeState::Idle },
}
PulseDecodeState::Sync2 => match delta.get() {
delta @ DATA_PULSE_MIN..=DATA_PULSE_MAX => {
let current = (delta > DATA_PULSE_THRESHOLD) as u8;
self.state = PulseDecodeState::Data { current, pulse: 1, written: 0 }
}
_ => { self.state = PulseDecodeState::Idle },
}
PulseDecodeState::Data { current, pulse, written } => match delta.get() {
delta @ DATA_PULSE_MIN..=DATA_PULSE_MAX => {
let bit = (delta > DATA_PULSE_THRESHOLD) as u8;
let current = if pulse & 1 == 1 {
if (current ^ bit) & 1 == 1 {
return self.end();
}
if pulse == 15 {
self.state = PulseDecodeState::Data { current: 0, pulse: 0, written: written + 1 };
self.write_byte(current)?;
continue;
}
current
}
else {
(current << 1) | bit
};
self.state = PulseDecodeState::Data { current, pulse: pulse + 1, written }
}
_ => return self.end()
}
}
}
Ok(None)
}
#[inline]
fn write_byte(&mut self, byte: u8) -> Result<()> {
if let Err(e) = self.wr.write_all(slice::from_ref(&byte)) {
self.state = PulseDecodeState::Idle;
return Err(e);
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[test]
fn write_mic_works() {
let wr = Cursor::new(Vec::new());
let mut mpw = PulseDecodeWriter::new(wr);
let pulses = [];
assert_eq!(PulseDecodeState::Idle, mpw.state());
assert_eq!(None, mpw.write_decoded_pulses(&mut pulses.iter().copied()).unwrap());
assert_eq!(PulseDecodeState::Idle, mpw.state());
assert_eq!(None, mpw.data_size());
let pulses = [PAUSE_PULSE_LENGTH, LEAD_PULSE_LENGTH];
assert_eq!(None, mpw.write_decoded_pulses(&mut pulses.iter().copied()).unwrap());
assert_eq!(PulseDecodeState::Lead {counter:1} , mpw.state());
assert_eq!(None, mpw.data_size());
let pulses = vec![LEAD_PULSE_LENGTH;LEAD_PULSES_HEAD as usize];
assert_eq!(None, mpw.write_decoded_pulses(&mut pulses.into_iter()).unwrap());
assert_eq!(PulseDecodeState::Lead {counter:LEAD_PULSES_HEAD as u32 + 1} , mpw.state());
assert_eq!(None, mpw.data_size());
let pulses = [SYNC_PULSE1_LENGTH, SYNC_PULSE2_LENGTH,
ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH,
ONE_PULSE_LENGTH, ONE_PULSE_LENGTH];
assert_eq!(None, mpw.write_decoded_pulses(&mut pulses.iter().copied()).unwrap());
assert_eq!(PulseDecodeState::Data {current: 0b0000_0001, pulse: 4, written: 0} , mpw.state());
assert_eq!(None, mpw.data_size());
assert_eq!(0, mpw.get_ref().position());
let pulses = [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,
ONE_PULSE_LENGTH, ONE_PULSE_LENGTH];
assert_eq!(None, mpw.write_decoded_pulses(&mut pulses.iter().copied()).unwrap());
assert_eq!(PulseDecodeState::Data {current: 0, pulse: 0, written: 1} , mpw.state());
assert_eq!(NonZeroU32::new(1), mpw.data_size());
assert_eq!(1, mpw.get_ref().position());
assert_eq!(&[0b0101_0101], &mpw.get_ref().get_ref()[..]);
assert_eq!(NonZeroU32::new(1), mpw.end().unwrap());
assert_eq!(PulseDecodeState::Idle, mpw.state());
assert_eq!(None, mpw.data_size());
}
#[test]
fn write_mic_missing_bits_works() {
let wr = Cursor::new(Vec::new());
let mut mpw = PulseDecodeWriter::new(wr);
let pulses = vec![LEAD_PULSE_LENGTH;LEAD_PULSES_DATA as usize];
assert_eq!(None, mpw.write_decoded_pulses(&mut pulses.into_iter()).unwrap());
assert_eq!(PulseDecodeState::Lead {counter:LEAD_PULSES_DATA as u32} , mpw.state());
assert_eq!(None, mpw.data_size());
let pulses = [SYNC_PULSE1_LENGTH, SYNC_PULSE2_LENGTH,
ONE_PULSE_LENGTH, ONE_PULSE_LENGTH,
ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH,
ONE_PULSE_LENGTH];
assert_eq!(None, mpw.write_decoded_pulses(&mut pulses.iter().copied()).unwrap());
assert_eq!(PulseDecodeState::Data {current: 0b0000_0101, pulse: 5, written: 0} , mpw.state());
assert_eq!(None, mpw.data_size());
assert_eq!(NonZeroU32::new(1), mpw.end().unwrap());
assert_eq!(1, mpw.get_ref().position());
assert_eq!(&[0b1000_0000], &mpw.get_ref().get_ref()[..]);
assert_eq!(PulseDecodeState::Idle, mpw.state());
assert_eq!(None, mpw.data_size());
}
}