m17core/
encode.rs

1use crate::{
2    bits::Bits,
3    fec::{self, p_1, p_2, p_3},
4    interleave::interleave,
5    protocol::{
6        LsfFrame, PacketFrame, PacketFrameCounter, StreamFrame, LSF_SYNC, PACKET_SYNC, STREAM_SYNC,
7    },
8    random::random_xor,
9};
10
11pub(crate) fn encode_lsf(frame: &LsfFrame) -> [f32; 192] {
12    let type3 = fec::encode(&frame.0, 240, p_1);
13    interleave_to_dibits(type3, LSF_SYNC)
14}
15
16pub(crate) fn encode_stream(frame: &StreamFrame) -> [f32; 192] {
17    let lich = encode_lich(frame.lich_idx, &frame.lich_part);
18    let mut type1 = [0u8; 18];
19    let frame_number = frame.frame_number | if frame.end_of_stream { 0x8000 } else { 0x0000 };
20    type1[0..2].copy_from_slice(&frame_number.to_be_bytes());
21    type1[2..18].copy_from_slice(&frame.stream_data);
22    let type3 = fec::encode(&type1, 144, p_2);
23    let mut combined = [0u8; 46];
24    combined[0..12].copy_from_slice(&lich);
25    combined[12..46].copy_from_slice(&type3[0..34]);
26    interleave_to_dibits(combined, STREAM_SYNC)
27}
28
29pub(crate) fn encode_packet(frame: &PacketFrame) -> [f32; 192] {
30    let mut type1 = [0u8; 26]; // only 206 out of 208 bits filled
31    match frame.counter {
32        PacketFrameCounter::Frame { index } => {
33            type1[0..25].copy_from_slice(&frame.payload);
34            type1[25] = (index as u8) << 2;
35        }
36        PacketFrameCounter::FinalFrame { payload_len } => {
37            type1[0..payload_len].copy_from_slice(&frame.payload[0..payload_len]);
38            type1[25] = ((payload_len as u8) << 2) | 0x80;
39        }
40    }
41    let type3 = fec::encode(&type1, 206, p_3);
42    interleave_to_dibits(type3, PACKET_SYNC)
43}
44
45/// Generate a preamble suitable for placement before an LSF frame.
46///
47/// Polarity needs to be flipped for BERT, however we don't support this yet.
48/// STREAM and PACKET don't need to be considered as they are an invalid way to
49/// begin a transmission.
50pub(crate) fn generate_preamble() -> [f32; 192] {
51    // TODO: should all these encode/generate functions return owning iterators?
52    // Then I could avoid making this array which I'm just going to have to copy anyway
53    let mut out = [1.0f32; 192];
54    for n in out.iter_mut().skip(1).step_by(2) {
55        *n = -1.0;
56    }
57    out
58}
59
60pub(crate) fn generate_end_of_transmission() -> [f32; 192] {
61    let mut out = [1.0f32; 192];
62    for n in out.iter_mut().skip(6).step_by(8) {
63        *n = -1.0;
64    }
65    out
66}
67
68pub(crate) fn encode_lich(counter: u8, part: &[u8; 5]) -> [u8; 12] {
69    let mut out = [0u8; 12];
70    let to_encode = [
71        ((part[0] as u16) << 4) | ((part[1] as u16) >> 4),
72        ((part[1] as u16 & 0x000f) << 8) | part[2] as u16,
73        ((part[3] as u16) << 4) | ((part[4] as u16) >> 4),
74        ((part[4] as u16 & 0x000f) << 8) | ((counter as u16) << 5),
75    ];
76    for (i, o) in to_encode.into_iter().zip(out.chunks_mut(3)) {
77        let encoded = cai_golay::extended::encode(i).to_be_bytes();
78        o[0..3].copy_from_slice(&encoded[1..4]);
79    }
80    out
81}
82
83fn interleave_to_dibits(combined: [u8; 46], sync_burst: [i8; 8]) -> [f32; 192] {
84    let mut interleaved = interleave(&combined);
85    random_xor(&mut interleaved);
86    let mut out = [0f32; 192];
87    for (val, o) in sync_burst.iter().zip(out.iter_mut()) {
88        *o = *val as f32;
89    }
90    let bits = Bits::new(&interleaved);
91    let mut out_bits = bits.iter();
92    for o in out[8..].iter_mut() {
93        *o = match (out_bits.next().unwrap(), out_bits.next().unwrap()) {
94            (0, 1) => 1.0,
95            (0, 0) => 1.0 / 3.0,
96            (1, 0) => -1.0 / 3.0,
97            (1, 1) => -1.0,
98            _ => unreachable!(),
99        };
100    }
101    out
102}
103
104#[cfg(test)]
105mod tests {
106    use super::*;
107
108    #[test]
109    fn lsf_round_trip() {
110        let lsf = LsfFrame([
111            255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
112            0, 0, 0, 0, 0, 131, 53,
113        ]);
114        let encoded = encode_lsf(&lsf);
115        let decoded = crate::decode::parse_lsf(&encoded);
116        assert_eq!(decoded, Some(lsf));
117    }
118
119    #[test]
120    fn stream_round_trip() {
121        let stream = StreamFrame {
122            lich_idx: 5,
123            lich_part: [1, 2, 3, 4, 5],
124            frame_number: 50,
125            end_of_stream: false,
126            stream_data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
127        };
128        let encoded = encode_stream(&stream);
129        let decoded = crate::decode::parse_stream(&encoded);
130        assert_eq!(decoded, Some(stream));
131    }
132
133    #[test]
134    fn packet_round_trip() {
135        let packet = PacketFrame {
136            payload: [41u8; 25],
137            counter: PacketFrameCounter::Frame { index: 3 },
138        };
139        let encoded = encode_packet(&packet);
140        let decoded = crate::decode::parse_packet(&encoded);
141        assert_eq!(decoded, Some(packet));
142
143        let packet = PacketFrame {
144            payload: [0u8; 25],
145            counter: PacketFrameCounter::FinalFrame { payload_len: 10 },
146        };
147        let encoded = encode_packet(&packet);
148        let decoded = crate::decode::parse_packet(&encoded);
149        assert_eq!(decoded, Some(packet));
150    }
151
152    #[test]
153    fn lich_encode() {
154        let input = [221, 81, 5, 5, 0];
155        let counter = 2;
156        let expected_output = [221, 82, 162, 16, 85, 200, 5, 14, 254, 4, 13, 153];
157        assert_eq!(encode_lich(counter, &input), expected_output);
158    }
159
160    #[test]
161    fn lich_round_trip() {
162        let input = [1, 255, 0, 90, 10];
163        let counter = 0;
164        assert_eq!(
165            crate::decode::decode_lich(&encode_lich(counter, &input)),
166            Some((counter, input))
167        );
168    }
169}