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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
//! Status symbol interleaving and deinterleaving.

use bits;
use consts::SYNC_SYMBOLS;

use self::StatusCode::*;
use self::StreamSymbol::*;

/// Number of dibits output per status period, including the status symbol.
const DIBITS_PER_UPDATE: u32 = 70 / 2 + 1;

/// Interleaves status symbols into a stream of dibits.
pub struct StatusInterleaver<T: Iterator<Item = bits::Dibit>> {
    /// Source of dibits to interleave status symbols into.
    src: T,
    /// Current status to be output.
    status: StatusCode,
    /// Current dibit index in output stream.
    pos: u32,
}

impl<T: Iterator<Item = bits::Dibit>> StatusInterleaver<T> {
    /// Create a new `StatusInterleaver` that will interleave status symbols into the
    /// given source of data symbols, using the given initial status code.
    pub fn new(src: T, status: StatusCode) -> StatusInterleaver<T> {
        StatusInterleaver {
            src: src,
            status: status,
            pos: 0,
        }
    }

    /// Update current output status to the given status code.
    pub fn update_status(&mut self, status: StatusCode) { self.status = status; }
}

impl<T: Iterator<Item = bits::Dibit>> Iterator for StatusInterleaver<T> {
    type Item = bits::Dibit;

    fn next(&mut self) -> Option<Self::Item> {
        self.pos += 1;
        self.pos %= DIBITS_PER_UPDATE;

        if self.pos == 0 {
            return Some(self.status.to_dibit());
        }

        match self.src.next() {
            Some(d) => Some(d),
            // If just after an update and no more source dibits, end the iteration.
            None if self.pos == 1 => None,
            // Pad until the next update.
            None => Some(bits::Dibit::new(0b00)),
        }
    }
}

/// A P25 status symbol.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum StatusCode {
    /// Used by a repeater when the inbound channel is idle.
    InboundIdle,
    /// Used by a repeater when the inbound channel is busy.
    InboundBusy,
    /// Used when a subscriber is transmitting to a repeater.
    SubscriberRepeater,
    /// Used when a subscriber is transmitting directly to another subscriber.
    SubscriberDirect,
}

impl StatusCode {
    /// Parse a status code from the given dibit.
    pub fn from_dibit(d: bits::Dibit) -> StatusCode {
        match d.bits() {
            0b01 => InboundBusy,
            0b00 => SubscriberDirect,
            0b10 => SubscriberRepeater,
            0b11 => InboundIdle,
            _ => unreachable!(),
        }
    }

    /// Convert the current status code into a dibit.
    pub fn to_dibit(self) -> bits::Dibit {
        bits::Dibit::new(match self {
            InboundBusy => 0b01,
            SubscriberDirect => 0b00,
            SubscriberRepeater => 0b10,
            InboundIdle => 0b11,
        })
    }
}

/// A symbol in a transmitted P25 stream.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum StreamSymbol {
    /// Current symbol is a status code.
    Status(StatusCode),
    /// Current symbol is a data dibit.
    Data(bits::Dibit),
}

/// Deinterleave a P25 transmitted stream into status codes and data symbols.
#[derive(Copy, Clone)]
pub struct StatusDeinterleaver {
    /// Current dibit position in current status period.
    pos: u32,
}

impl StatusDeinterleaver {
    /// Create a new `StatusDeinterleaver` for deinterlacing immediately after the frame sync
    /// sequence.
    pub fn new() -> StatusDeinterleaver {
        StatusDeinterleaver {
            // Since stream deinterleaving is started after the frame sync, and the frame sync
            // symbols count towards the first status symbol period, start the counter with those
            // symbols taken into account.
            pos: SYNC_SYMBOLS as u32,
        }
    }

    /// Parse the given symbol as a status or data symbol.
    pub fn feed(&mut self, d: bits::Dibit) -> StreamSymbol {
        self.pos += 1;
        self.pos %= DIBITS_PER_UPDATE;

        if self.pos == 0 {
            Status(StatusCode::from_dibit(d))
        } else {
            Data(d)
        }
    }
}

#[cfg(test)]
mod test {
    use bits;
    use super::*;
    use std;

    #[test]
    fn test_interleave() {
        let src = std::iter::repeat(bits::Dibit::new(0b10));
        let mut i = StatusInterleaver::new(src, StatusCode::InboundBusy);

        for _ in 0..35 {
            assert_eq!(i.next(), Some(bits::Dibit::new(0b10)));
        }

        assert_eq!(i.next(), Some(bits::Dibit::new(0b01)));

        for _ in 0..35 {
            assert_eq!(i.next(), Some(bits::Dibit::new(0b10)));
        }

        assert_eq!(i.next(), Some(bits::Dibit::new(0b01)));
    }

    #[test]
    fn test_deinterleave() {
        let mut d = StatusDeinterleaver::new();

        for _ in 0..11 {
            assert_eq!(d.feed(bits::Dibit::new(0)),
                StreamSymbol::Data(bits::Dibit::new(0)));
        }

        assert_eq!(d.feed(bits::Dibit::new(0)), StreamSymbol::Status(
                StatusCode::SubscriberDirect));

        for _ in 0..35 {
            assert_eq!(d.feed(bits::Dibit::new(0)),
                StreamSymbol::Data(bits::Dibit::new(0)));
        }

        assert_eq!(d.feed(bits::Dibit::new(0)), StreamSymbol::Status(
                StatusCode::SubscriberDirect));

        for _ in 0..35 {
            assert_eq!(d.feed(bits::Dibit::new(0)),
                StreamSymbol::Data(bits::Dibit::new(0)));
        }

        assert_eq!(d.feed(bits::Dibit::new(0)), StreamSymbol::Status(
                StatusCode::SubscriberDirect));
    }
}