1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
//! Clock recovery implementations
/*
* Much evolving clock sync.
*
* Study material:
* https://youtu.be/jag3btxSsig
*/
use anyhow::Result;

use crate::block::{Block, BlockRet};
use crate::stream::{InputStreams, OutputStreams};
use crate::{Error, Float};

trait Ted {
    fn error(&self, input: &[Float]) -> Float;
}

struct TedDeriv {}

impl TedDeriv {
    fn new() -> Self {
        Self {}
    }
}

impl Ted for TedDeriv {
    fn error(&self, input: &[Float]) -> Float {
        let sign = if input[0] > 0.0 { 1.0 } else { -1.0 };
        sign * input[input.len() - 1] - input[0]
    }
}

/// Broken, DO NOT USE.
pub struct SymbolSync {
    _sps: Float,
    _max_deviation: Float,
    clock: Float,
    ted: Box<dyn Ted>,
}

impl SymbolSync {
    /// Broken, DO NOT USE.
    pub fn new(sps: Float, max_deviation: Float) -> Self {
        assert!(sps > 1.0);
        Self {
            _sps: sps,
            _max_deviation: max_deviation,
            clock: sps,
            ted: Box::new(TedDeriv::new()),
        }
    }
}

/*
error = sign(x) * deriv(x)
positive error means "early", neagive error means "late"
*/

impl Block for SymbolSync {
    fn block_name(&self) -> &'static str {
        "SymbolSync"
    }
    fn work(&mut self, r: &mut InputStreams, w: &mut OutputStreams) -> Result<BlockRet, Error> {
        let input = r.get::<Float>(0);
        let mut v = Vec::new();
        let n = input.borrow().available();
        let mut pos = Float::default();
        loop {
            let i = pos as usize;
            if i + 1 >= n {
                break;
            }
            // TODO: needless copy.
            let t: Vec<Float> = input.borrow().data().clone().into();
            let error = self.ted.error(&t);
            if error > 0.0 {
                pos += 0.3;
            } else {
                pos -= 0.3;
            }
            v.push(input.borrow().data()[i]);
            pos += self.clock;
        }
        input.borrow_mut().clear();
        w.get::<Float>(0).borrow_mut().write_slice(&v);
        Ok(BlockRet::Ok)
    }
}

/** Very simple clock recovery by looking at zero crossings.

Every time the stream crosses 0, this is assumed to be right in the
middle of two symbols, and the next chosen sample to use as a symbol
will be the one `sps/2` samples later.

The one after that will be after `1.5*sps` samples. And so on, until
the next zero crossing happens, and the clock thus resets.

Future work in this block will be to adjust the sps according to when
the expected vs actual zero crossings happen, effectively phase lock
looping.

But for now it's "good enough" to get simple 2FSK decoded pretty
reliably.
*/
pub struct ZeroCrossing {
    sps: Float,
    max_deviation: Float,
    clock: Float,
    last_sign: bool,
    last_cross: f32,
    counter: u64,
}

impl ZeroCrossing {
    /** Create new ZeroCrossing block.

    # Args
    * `sps`: Samples per symbol. IOW `samp_rate / baud`.
    * `max_deviation`: Not currently used.
     */
    pub fn new(sps: Float, max_deviation: Float) -> Self {
        assert!(sps > 1.0);
        Self {
            sps,
            clock: sps,
            max_deviation,
            last_sign: false,
            last_cross: 0.0,
            counter: 0,
        }
    }
}

impl Block for ZeroCrossing {
    fn block_name(&self) -> &'static str {
        "ZeroCrossing"
    }
    fn work(&mut self, r: &mut InputStreams, w: &mut OutputStreams) -> Result<BlockRet, Error> {
        let mut v = Vec::new();
        let input = r.get(0);
        for sample in input.borrow().iter() {
            if self.counter == (self.last_cross + (self.clock / 2.0)) as u64 {
                v.push(*sample);
                self.last_cross += self.clock;
            }

            let sign = *sample > 0.0;
            if sign != self.last_sign {
                self.last_cross = self.counter as f32;
                // TODO: adjust clock, within sps. Here just shut up the linter.
                self.sps *= 1.0;
                self.max_deviation *= 1.0;
            }
            self.last_sign = sign;
            self.counter += 1;

            let step_back = (10.0 * self.clock) as u64;
            if self.counter > step_back && self.last_cross as u64 > step_back {
                self.counter -= step_back;
                self.last_cross -= step_back as f32;
            }
        }
        input.borrow_mut().clear();
        w.get::<Float>(0).borrow_mut().write_slice(&v);
        Ok(BlockRet::Ok)
    }
}