]> code.octet-stream.net Git - m17rt/blob - m17core/src/encode.rs
54f5bc2db2d6c7928c9e87087221e8df8a0cbdb6
[m17rt] / m17core / src / encode.rs
1 use 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
11 pub(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
16 pub(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
29 pub(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) << 3;
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) << 3 | 0x04;
39 }
40 }
41 let type3 = fec::encode(&type1, 206, p_3);
42 interleave_to_dibits(type3, PACKET_SYNC)
43 }
44
45 pub(crate) fn encode_lich(counter: u8, part: &[u8; 5]) -> [u8; 12] {
46 let mut out = [0u8; 12];
47 let to_encode = [
48 ((part[0] as u16) << 4) | ((part[1] as u16) >> 4),
49 ((part[1] as u16 & 0x000f) << 8) | part[2] as u16,
50 ((part[3] as u16) << 4) | ((part[4] as u16) >> 4),
51 ((part[4] as u16 & 0x000f) << 8) | ((counter as u16) << 5),
52 ];
53 for (i, o) in to_encode.into_iter().zip(out.chunks_mut(3)) {
54 let encoded = cai_golay::extended::encode(i).to_be_bytes();
55 o[0..3].copy_from_slice(&encoded[1..4]);
56 }
57 out
58 }
59
60 fn interleave_to_dibits(combined: [u8; 46], sync_burst: [i8; 8]) -> [f32; 192] {
61 let mut interleaved = interleave(&combined);
62 random_xor(&mut interleaved);
63 let mut out = [0f32; 192];
64 for (val, o) in sync_burst.iter().zip(out.iter_mut()) {
65 *o = *val as f32;
66 }
67 let bits = Bits::new(&interleaved);
68 let mut out_bits = bits.iter();
69 for o in out[8..].iter_mut() {
70 *o = match (out_bits.next().unwrap(), out_bits.next().unwrap()) {
71 (0, 1) => 1.0,
72 (0, 0) => 1.0 / 3.0,
73 (1, 0) => -1.0 / 3.0,
74 (1, 1) => -1.0,
75 _ => unreachable!(),
76 };
77 }
78 out
79 }
80
81 #[cfg(test)]
82 mod tests {
83 use super::*;
84
85 #[test]
86 fn lsf_round_trip() {
87 let lsf = LsfFrame([
88 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
89 0, 0, 0, 0, 0, 131, 53,
90 ]);
91 let encoded = encode_lsf(&lsf);
92 let decoded = crate::decode::parse_lsf(&encoded);
93 assert_eq!(decoded, Some(lsf));
94 }
95
96 #[test]
97 fn stream_round_trip() {
98 let stream = StreamFrame {
99 lich_idx: 5,
100 lich_part: [1, 2, 3, 4, 5],
101 frame_number: 50,
102 end_of_stream: false,
103 stream_data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
104 };
105 let encoded = encode_stream(&stream);
106 let decoded = crate::decode::parse_stream(&encoded);
107 assert_eq!(decoded, Some(stream));
108 }
109
110 #[test]
111 fn packet_round_trip() {
112 let packet = PacketFrame {
113 payload: [41u8; 25],
114 counter: PacketFrameCounter::Frame { index: 3 },
115 };
116 let encoded = encode_packet(&packet);
117 let decoded = crate::decode::parse_packet(&encoded);
118 assert_eq!(decoded, Some(packet));
119
120 let packet = PacketFrame {
121 payload: [0u8; 25],
122 counter: PacketFrameCounter::FinalFrame { payload_len: 10 },
123 };
124 let encoded = encode_packet(&packet);
125 let decoded = crate::decode::parse_packet(&encoded);
126 assert_eq!(decoded, Some(packet));
127 }
128
129 #[test]
130 fn lich_encode() {
131 let input = [221, 81, 5, 5, 0];
132 let counter = 2;
133 let expected_output = [221, 82, 162, 16, 85, 200, 5, 14, 254, 4, 13, 153];
134 assert_eq!(encode_lich(counter, &input), expected_output);
135 }
136
137 #[test]
138 fn lich_round_trip() {
139 let input = [1, 255, 0, 90, 10];
140 let counter = 0;
141 assert_eq!(
142 crate::decode::decode_lich(&encode_lich(counter, &input)),
143 Some((counter, input))
144 );
145 }
146 }