spectrusty_formats/tap/pulse/
decoding.rs

1/*
2    Copyright (C) 2020-2022  Rafal Michalski
3
4    This file is part of SPECTRUSTY, a Rust library for building emulators.
5
6    For the full copyright notice, see the lib.rs file.
7*/
8use core::num::NonZeroU32;
9use core::slice;
10use std::io::{Result, Write};
11
12use super::consts::*;
13
14const SYNC_PULSE_TOLERANCE: u32 = (SYNC_PULSE2_LENGTH.get() - SYNC_PULSE1_LENGTH.get())/2;
15const SYNC_PULSE1_MIN: u32 = SYNC_PULSE1_LENGTH.get() - SYNC_PULSE_TOLERANCE;
16const SYNC_PULSE1_MAX: u32 = SYNC_PULSE1_LENGTH.get() + SYNC_PULSE_TOLERANCE - 1;
17const SYNC_PULSE2_MIN: u32 = SYNC_PULSE2_LENGTH.get() - SYNC_PULSE_TOLERANCE;
18const SYNC_PULSE2_MAX: u32 = SYNC_PULSE2_LENGTH.get() + SYNC_PULSE_TOLERANCE - 1;
19const LEAD_PULSE_TOLERANCE: u32 = 250;
20const LEAD_PULSE_MIN: u32 = LEAD_PULSE_LENGTH.get() - LEAD_PULSE_TOLERANCE;
21const LEAD_PULSE_MAX: u32 = LEAD_PULSE_LENGTH.get() + LEAD_PULSE_TOLERANCE - 1;
22const DATA_PULSE_TOLERANCE: u32 = 250;
23const DATA_PULSE_MIN: u32 = ZERO_PULSE_LENGTH.get() - DATA_PULSE_TOLERANCE;
24const DATA_PULSE_MAX: u32 = ONE_PULSE_LENGTH.get() + DATA_PULSE_TOLERANCE - 1;
25const DATA_PULSE_THRESHOLD: u32 = (ZERO_PULSE_LENGTH.get() + ONE_PULSE_LENGTH.get())/2;
26const MIN_LEAD_COUNT: u32 = 16;
27
28/// The current state of the [PulseDecodeWriter].
29#[derive(Clone, Copy, Debug, PartialEq, Eq)]
30pub enum PulseDecodeState {
31    /// Initial state, waiting for lead pulses.
32    Idle,
33    /// Receiving lead pulses.
34    Lead {
35        counter: u32
36    },
37    /// Received the 1st sync pulse.
38    Sync1,
39    /// Received the 2nd sync pulse.
40    Sync2,
41    /// Receiving data pulses.
42    Data{
43        /// A data byte being received currently.
44        current: u8,
45        /// A pulse counter for the current byte.
46        pulse: u8,
47        /// How many bytes written.
48        written: u32
49    },
50}
51
52/// Provides a decoder of *TAPE* T-state pulse intervals.
53///
54/// The timing of the pulses should match those produced by ZX Spectrum's ROM loading routines.
55///
56/// After invoking [PulseDecodeWriter::end] or [PulseDecodeWriter::new] [PulseDecodeWriter] expects
57/// a data transfer which consists of:
58///
59/// * lead pulses followed by
60/// * two synchronization pulses followed by 
61/// * data pulses
62///
63/// Provide pulse iterators to [PulseDecodeWriter::write_decoded_pulses] method to write interpreted data
64/// to the underlying writer.
65///
66/// Best used with [tap][crate::tap] utilities.
67#[derive(Debug)]
68pub struct PulseDecodeWriter<W> {
69    state: PulseDecodeState,
70    wr: W,
71}
72
73impl PulseDecodeState {
74    /// Returns `true` if the state is [PulseDecodeState::Idle].
75    pub fn is_idle(&self) -> bool {
76        matches!(self, PulseDecodeState::Idle)
77    }
78    /// Returns `true` if receiving lead pulses.
79    pub fn is_lead(&self) -> bool {
80        matches!(self, PulseDecodeState::Lead {..})
81    }
82    /// Returns `true` if receiving data pulses.
83    pub fn is_data(&self) -> bool {
84        matches!(self, PulseDecodeState::Data {..})
85    }
86    /// Returns `true` if received sync1 pulse.
87    pub fn is_sync1(&self) -> bool {
88        matches!(self, PulseDecodeState::Sync1)
89    }
90    /// Returns `true` if received sync2 pulse.
91    pub fn is_sync2(&self) -> bool {
92        matches!(self, PulseDecodeState::Sync2)
93    }
94}
95
96impl<W> PulseDecodeWriter<W> {
97    /// Resets the state of the [PulseDecodeWriter] to `Idle`, discarding any partially received byte.
98    ///
99    /// The information about the number of bytes written so far is lost.
100    pub fn reset(&mut self) {
101        self.state = PulseDecodeState::Idle;
102    }
103    /// Returns `true` if the state is [PulseDecodeState::Idle].
104    pub fn is_idle(&self) -> bool {
105        self.state.is_idle()
106    }
107    /// Returns the underlying writer.
108    pub fn into_inner(self) -> W {
109        self.wr
110    }
111    /// Returns a reference to the current state.
112    pub fn state(&self) -> PulseDecodeState {
113        self.state
114    }
115    /// Returns a mutable reference to the inner writer.
116    pub fn get_mut(&mut self) -> &mut W {
117        &mut self.wr
118    }
119    /// Returns a shared reference to the inner writer.
120    pub fn get_ref(&self) -> &W {
121        &self.wr
122    }
123    /// Returns a number of bytes written during current data transfer
124    /// if a data transfer is in progress.
125    pub fn data_size(&self) -> Option<NonZeroU32> {
126        NonZeroU32::new(if let PulseDecodeState::Data { written, .. } = self.state {
127            written
128        }
129        else {
130            0
131        })
132    }
133    /// Allows to manually assign `state`.
134    /// Can be used to deserialize PulseDecodeWriter.
135    pub fn with_state(mut self, state: PulseDecodeState) -> Self {
136        self.state = state;
137        self
138    }
139}
140
141impl<W: Write> PulseDecodeWriter<W> {
142    /// Creates a new `PulseDecodeWriter` from a given [Writer][Write].
143    pub fn new(wr: W) -> Self {
144        PulseDecodeWriter { state: PulseDecodeState::Idle, wr }
145    }
146    /// Optionally writes a partially received data byte and ensures the state of [PulseDecodeWriter] is `Idle`.
147    ///
148    /// After calling this method, regardless of the return value, the state is changed to [PulseDecodeState::Idle].
149    ///
150    /// Returns `Ok(None)` if there was no data written in the current transfer.
151    ///
152    /// Returns `Ok(Some(size))` if data has been written, providing the number of written bytes.
153    ///
154    /// In the case of [std::io::Error] the information about the number of bytes written is lost.
155    pub fn end(&mut self) -> Result<Option<NonZeroU32>> {
156        let res = if let PulseDecodeState::Data { mut current, pulse, written } = self.state {
157            NonZeroU32::new(if pulse <= 1 {
158                written
159            }
160            else {
161                if pulse & 1 == 1 {
162                    current &= !1;
163                }
164                current <<= (16 - (pulse & 15)) >> 1;
165                self.write_byte(current)?;
166                written + 1
167            })
168        }
169        else {
170            None
171        };
172        self.state = PulseDecodeState::Idle;
173        Ok(res)
174    }
175    /// Interprets pulse intervals from the provided pulse iterator as data bytes, writing them to
176    /// the underlying writer.
177    ///
178    /// The pulse iterator is expected to provide only a fragment of pulses needed for the complete
179    /// transfer such as an iterator returned from [MicOut::mic_out_pulse_iter].
180    /// Providing an empty iterator is equivalent to calling [PulseDecodeWriter::end] thus ending
181    /// the current transfer in progress if there is any.
182    ///
183    /// Returns `Ok(None)` if there was no data or more pulses are being expected.
184    ///
185    /// Returns `Ok(Some(size))` if data block has been written, providing the number of written bytes.
186    /// In this instance, there can still be some pulses left in the iterator, e.g. for the next
187    /// incoming transfer.
188    ///
189    /// In the case of [std::io::Error] the information about the number of bytes written is lost.
190    ///
191    /// [MicOut::mic_out_pulse_iter]: spectrusty_core::chip::MicOut::mic_out_pulse_iter
192    pub fn write_decoded_pulses<I>(&mut self, iter: I) -> Result<Option<NonZeroU32>>
193        where I: Iterator<Item=NonZeroU32>
194    {
195        let mut iter = iter.peekable();
196        if iter.peek().is_none() {
197            return self.end(); // empty frame
198        }
199
200        for delta in iter {
201            match self.state {
202                PulseDecodeState::Idle => {
203                    if let LEAD_PULSE_MIN..=LEAD_PULSE_MAX = delta.get() {
204                        self.state = PulseDecodeState::Lead { counter: 1 };
205                    }
206                }
207                PulseDecodeState::Lead { counter } => match delta.get() {
208                    SYNC_PULSE1_MIN..=SYNC_PULSE1_MAX if counter >= MIN_LEAD_COUNT => {
209                        self.state = PulseDecodeState::Sync1;
210                    }
211                    LEAD_PULSE_MIN..=LEAD_PULSE_MAX => {
212                        self.state = PulseDecodeState::Lead { counter: counter.saturating_add(1) };
213                    }
214                    _ => { self.state = PulseDecodeState::Idle },
215                }
216                PulseDecodeState::Sync1 => match delta.get() {
217                    SYNC_PULSE2_MIN..=SYNC_PULSE2_MAX => {
218                        self.state = PulseDecodeState::Sync2;
219                    }                    
220                    _ => { self.state = PulseDecodeState::Idle },
221                }
222                PulseDecodeState::Sync2 => match delta.get() {
223                    delta @ DATA_PULSE_MIN..=DATA_PULSE_MAX => {
224                        let current = (delta > DATA_PULSE_THRESHOLD) as u8;
225                        self.state = PulseDecodeState::Data { current, pulse: 1, written: 0 }
226                    }
227                    _ => { self.state = PulseDecodeState::Idle },
228                }
229                PulseDecodeState::Data { current, pulse, written } => match delta.get() {
230                    delta @ DATA_PULSE_MIN..=DATA_PULSE_MAX => {
231                        let bit = (delta > DATA_PULSE_THRESHOLD) as u8;
232                        let current = if pulse & 1 == 1 {
233                            if (current ^ bit) & 1 == 1 {
234                                return self.end();
235                            }
236                            if pulse == 15 {
237                                self.state = PulseDecodeState::Data { current: 0, pulse: 0, written: written + 1 };
238                                self.write_byte(current)?;
239                                continue;
240                            }
241                            current
242                        }
243                        else {
244                            (current << 1) | bit
245                        };
246                        self.state = PulseDecodeState::Data { current, pulse: pulse + 1, written }
247                    }
248                    _ => return self.end()
249                }
250            }
251        }
252        Ok(None)
253    }
254
255    #[inline]
256    fn write_byte(&mut self, byte: u8) -> Result<()> {
257        // eprint!("{:02x} ", byte);
258        if let Err(e) = self.wr.write_all(slice::from_ref(&byte)) {
259            self.state = PulseDecodeState::Idle;
260            return Err(e);
261        }
262        Ok(())
263    }
264}
265
266#[cfg(test)]
267mod tests {
268    use super::*;
269    use std::io::Cursor;
270
271    #[test]
272    fn write_mic_works() {
273        let wr = Cursor::new(Vec::new());
274        let mut mpw = PulseDecodeWriter::new(wr);
275        let pulses = [];
276        assert_eq!(PulseDecodeState::Idle, mpw.state());
277        assert_eq!(None, mpw.write_decoded_pulses(&mut pulses.iter().copied()).unwrap());
278        assert_eq!(PulseDecodeState::Idle, mpw.state());
279        assert_eq!(None, mpw.data_size());
280        let pulses = [PAUSE_PULSE_LENGTH, LEAD_PULSE_LENGTH];
281        assert_eq!(None, mpw.write_decoded_pulses(&mut pulses.iter().copied()).unwrap());
282        assert_eq!(PulseDecodeState::Lead {counter:1} , mpw.state());
283        assert_eq!(None, mpw.data_size());
284        let pulses = vec![LEAD_PULSE_LENGTH;LEAD_PULSES_HEAD as usize];
285        assert_eq!(None, mpw.write_decoded_pulses(&mut pulses.into_iter()).unwrap());
286        assert_eq!(PulseDecodeState::Lead {counter:LEAD_PULSES_HEAD as u32 + 1} , mpw.state());
287        assert_eq!(None, mpw.data_size());
288        let pulses = [SYNC_PULSE1_LENGTH, SYNC_PULSE2_LENGTH,
289                      ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH,
290                      ONE_PULSE_LENGTH, ONE_PULSE_LENGTH];
291        assert_eq!(None, mpw.write_decoded_pulses(&mut pulses.iter().copied()).unwrap());
292        assert_eq!(PulseDecodeState::Data {current: 0b0000_0001, pulse: 4, written: 0} , mpw.state());
293        assert_eq!(None, mpw.data_size());
294        assert_eq!(0, mpw.get_ref().position());
295        let pulses = [ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH,
296                      ONE_PULSE_LENGTH, ONE_PULSE_LENGTH,
297                      ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH,
298                      ONE_PULSE_LENGTH, ONE_PULSE_LENGTH,
299                      ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH,
300                      ONE_PULSE_LENGTH, ONE_PULSE_LENGTH];
301        assert_eq!(None, mpw.write_decoded_pulses(&mut pulses.iter().copied()).unwrap());
302        assert_eq!(PulseDecodeState::Data {current: 0, pulse: 0, written: 1} , mpw.state());
303        assert_eq!(NonZeroU32::new(1), mpw.data_size());
304        assert_eq!(1, mpw.get_ref().position());
305        assert_eq!(&[0b0101_0101], &mpw.get_ref().get_ref()[..]);
306        assert_eq!(NonZeroU32::new(1), mpw.end().unwrap());
307        assert_eq!(PulseDecodeState::Idle, mpw.state());
308        assert_eq!(None, mpw.data_size());
309    }
310
311    #[test]
312    fn write_mic_missing_bits_works() {
313        let wr = Cursor::new(Vec::new());
314        let mut mpw = PulseDecodeWriter::new(wr);
315        let pulses = vec![LEAD_PULSE_LENGTH;LEAD_PULSES_DATA as usize];
316        assert_eq!(None, mpw.write_decoded_pulses(&mut pulses.into_iter()).unwrap());
317        assert_eq!(PulseDecodeState::Lead {counter:LEAD_PULSES_DATA as u32} , mpw.state());
318        assert_eq!(None, mpw.data_size());
319        let pulses = [SYNC_PULSE1_LENGTH, SYNC_PULSE2_LENGTH,
320                      ONE_PULSE_LENGTH, ONE_PULSE_LENGTH,
321                      ZERO_PULSE_LENGTH, ZERO_PULSE_LENGTH,
322                      ONE_PULSE_LENGTH];
323        assert_eq!(None, mpw.write_decoded_pulses(&mut pulses.iter().copied()).unwrap());
324        assert_eq!(PulseDecodeState::Data {current: 0b0000_0101, pulse: 5, written: 0} , mpw.state());
325        assert_eq!(None, mpw.data_size());
326        assert_eq!(NonZeroU32::new(1), mpw.end().unwrap());
327        assert_eq!(1, mpw.get_ref().position());
328        assert_eq!(&[0b1000_0000], &mpw.get_ref().get_ref()[..]);
329        assert_eq!(PulseDecodeState::Idle, mpw.state());
330        assert_eq!(None, mpw.data_size());
331    }
332}