]> code.octet-stream.net Git - m17rt/blob - m17core/src/protocol.rs
1c9fa13a9bb9e1605e8e32bbf81f941587cd5ecf
[m17rt] / m17core / src / protocol.rs
1 use crate::{
2 address::{encode_address, Address},
3 bits::BitsMut,
4 };
5
6 pub(crate) const LSF_SYNC: [i8; 8] = [1, 1, 1, 1, -1, -1, 1, -1];
7 pub(crate) const BERT_SYNC: [i8; 8] = [-1, 1, -1, -1, 1, 1, 1, 1];
8 pub(crate) const STREAM_SYNC: [i8; 8] = [-1, -1, -1, -1, 1, 1, -1, 1];
9 pub(crate) const PACKET_SYNC: [i8; 8] = [1, -1, 1, 1, -1, -1, -1, -1];
10 pub(crate) const PREAMBLE: [i8; 8] = [1, -1, 1, -1, 1, -1, 1, -1];
11 pub(crate) const END_OF_TRANSMISSION: [i8; 8] = [1, 1, 1, 1, 1, 1, -1, 1];
12
13 #[derive(Debug, Clone, PartialEq, Eq, Copy)]
14 pub enum Mode {
15 Packet,
16 Stream,
17 }
18 #[derive(Debug, Clone, PartialEq, Eq, Copy)]
19 pub enum DataType {
20 Reserved,
21 Data,
22 Voice,
23 VoiceAndData,
24 }
25 #[derive(Debug, Clone, PartialEq, Eq, Copy)]
26 pub enum EncryptionType {
27 None,
28 Scrambler,
29 Aes,
30 Other,
31 }
32
33 #[derive(Debug, Clone, PartialEq, Eq)]
34 pub enum Frame {
35 Lsf(LsfFrame),
36 Stream(StreamFrame),
37 Packet(PacketFrame),
38 // BERT
39 }
40
41 #[derive(Debug, Clone, PartialEq, Eq, Copy)]
42 pub enum PacketType {
43 /// RAW
44 Raw,
45 /// AX.25
46 Ax25,
47 /// APRS
48 Aprs,
49 /// 6LoWPAN
50 SixLowPan,
51 /// IPv4
52 Ipv4,
53 /// SMS
54 Sms,
55 /// Winlink
56 Winlink,
57 /// Custom identifier
58 Other(char),
59 }
60
61 impl PacketType {
62 pub fn from_proto(buf: &[u8]) -> Option<(Self, usize)> {
63 buf.utf8_chunks()
64 .next()
65 .and_then(|chunk| chunk.valid().chars().next())
66 .map(|c| match c as u32 {
67 0x00 => (PacketType::Raw, 1),
68 0x01 => (PacketType::Ax25, 1),
69 0x02 => (PacketType::Aprs, 1),
70 0x03 => (PacketType::SixLowPan, 1),
71 0x04 => (PacketType::Ipv4, 1),
72 0x05 => (PacketType::Sms, 1),
73 0x06 => (PacketType::Winlink, 1),
74 _ => (PacketType::Other(c), c.len_utf8()),
75 })
76 }
77
78 pub fn as_proto(&self) -> ([u8; 4], usize) {
79 match self {
80 PacketType::Raw => ([0, 0, 0, 0], 1),
81 PacketType::Ax25 => ([1, 0, 0, 0], 1),
82 PacketType::Aprs => ([2, 0, 0, 0], 1),
83 PacketType::SixLowPan => ([3, 0, 0, 0], 1),
84 PacketType::Ipv4 => ([4, 0, 0, 0], 1),
85 PacketType::Sms => ([5, 0, 0, 0], 1),
86 PacketType::Winlink => ([6, 0, 0, 0], 1),
87 PacketType::Other(c) => {
88 let mut buf = [0u8; 4];
89 let s = c.encode_utf8(&mut buf);
90 let len = s.len();
91 (buf, len)
92 }
93 }
94 }
95 }
96
97 #[derive(Debug, Clone, PartialEq, Eq)]
98 pub struct LsfFrame(pub [u8; 30]);
99
100 impl LsfFrame {
101 pub fn new_voice(source: &Address, destination: &Address) -> Self {
102 let mut out = Self([0u8; 30]);
103 out.set_source(source);
104 out.set_destination(destination);
105 out.set_mode(Mode::Stream);
106 out.set_data_type(DataType::Voice);
107 out.set_encryption_type(EncryptionType::None);
108 out
109 }
110
111 pub fn new_packet(source: &Address, destination: &Address) -> Self {
112 let mut out = Self([0u8; 30]);
113 out.set_source(source);
114 out.set_destination(destination);
115 out.set_mode(Mode::Packet);
116 out.set_data_type(DataType::Data);
117 out.set_encryption_type(EncryptionType::None);
118 out
119 }
120
121 /// Calculate crc of entire frame. If zero, it is a valid frame.
122 pub fn check_crc(&self) -> u16 {
123 crate::crc::m17_crc(&self.0)
124 }
125
126 pub fn destination(&self) -> Address {
127 crate::address::decode_address((&self.0[0..6]).try_into().unwrap())
128 }
129
130 pub fn source(&self) -> Address {
131 crate::address::decode_address((&self.0[6..12]).try_into().unwrap())
132 }
133
134 pub fn mode(&self) -> Mode {
135 if self.lsf_type() & 0x0001 > 0 {
136 Mode::Stream
137 } else {
138 Mode::Packet
139 }
140 }
141
142 pub fn data_type(&self) -> DataType {
143 match (self.0[12] >> 1) & 0x03 {
144 0b00 => DataType::Reserved,
145 0b01 => DataType::Data,
146 0b10 => DataType::Voice,
147 0b11 => DataType::VoiceAndData,
148 _ => unreachable!(),
149 }
150 }
151
152 pub fn encryption_type(&self) -> EncryptionType {
153 match (self.lsf_type() >> 3) & 0x0003 {
154 0b00 => EncryptionType::None,
155 0b01 => EncryptionType::Scrambler,
156 0b10 => EncryptionType::Aes,
157 0b11 => EncryptionType::Other,
158 _ => unreachable!(),
159 }
160 }
161
162 // TODO: encryption sub-type
163
164 pub fn channel_access_number(&self) -> u8 {
165 ((self.lsf_type() >> 7) & 0x000f) as u8
166 }
167
168 pub fn meta(&self) -> [u8; 14] {
169 self.0[14..28].try_into().unwrap()
170 }
171
172 pub fn set_destination(&mut self, destination: &Address) {
173 self.0[0..6].copy_from_slice(&encode_address(&destination));
174 self.recalculate_crc();
175 }
176
177 pub fn set_source(&mut self, source: &Address) {
178 self.0[6..12].copy_from_slice(&encode_address(&source));
179 self.recalculate_crc();
180 }
181
182 pub fn set_mode(&mut self, mode: Mode) {
183 let existing_type = self.lsf_type();
184 let new_type = (existing_type & !0x0001) | if mode == Mode::Stream { 1 } else { 0 };
185 self.0[12..14].copy_from_slice(&new_type.to_be_bytes());
186 self.recalculate_crc();
187 }
188
189 pub fn set_data_type(&mut self, data_type: DataType) {
190 let type_part = match data_type {
191 DataType::Reserved => 0b00 << 1,
192 DataType::Data => 0b01 << 1,
193 DataType::Voice => 0b10 << 1,
194 DataType::VoiceAndData => 0b11 << 1,
195 };
196 let existing_type = self.lsf_type();
197 let new_type = (existing_type & !0x0006) | type_part;
198 self.0[12..14].copy_from_slice(&new_type.to_be_bytes());
199 self.recalculate_crc();
200 }
201
202 pub fn set_encryption_type(&mut self, encryption_type: EncryptionType) {
203 let type_part = match encryption_type {
204 EncryptionType::None => 0b00 << 3,
205 EncryptionType::Scrambler => 0b01 << 3,
206 EncryptionType::Aes => 0b10 << 3,
207 EncryptionType::Other => 0b11 << 3,
208 };
209 let existing_type = self.lsf_type();
210 let new_type = (existing_type & !0x0018) | type_part;
211 self.0[12..14].copy_from_slice(&new_type.to_be_bytes());
212 self.recalculate_crc();
213 }
214
215 pub fn set_channel_access_number(&mut self, number: u8) {
216 let mut bits = BitsMut::new(&mut self.0);
217 bits.set_bit(12 * 8 + 5, (number >> 3) & 1);
218 bits.set_bit(12 * 8 + 6, (number >> 2) & 1);
219 bits.set_bit(12 * 8 + 7, (number >> 1) & 1);
220 bits.set_bit(13 * 8 + 0, number & 1);
221 self.recalculate_crc();
222 }
223
224 fn recalculate_crc(&mut self) {
225 let new_crc = crate::crc::m17_crc(&self.0[0..28]);
226 self.0[28..30].copy_from_slice(&new_crc.to_be_bytes());
227 debug_assert_eq!(self.check_crc(), 0);
228 }
229
230 fn lsf_type(&self) -> u16 {
231 u16::from_be_bytes([self.0[12], self.0[13]])
232 }
233 }
234
235 #[derive(Debug, Clone, PartialEq, Eq, Default)]
236 pub struct StreamFrame {
237 /// Which LICH segment is given in this frame, from 0 to 5 inclusive
238 pub lich_idx: u8,
239 /// Decoded LICH segment
240 pub lich_part: [u8; 5],
241 /// Which frame in the transmission this is, starting from 0
242 pub frame_number: u16,
243 /// Is this the last frame in the transmission?
244 pub end_of_stream: bool,
245 /// Raw application data in this frame
246 pub stream_data: [u8; 16],
247 }
248
249 #[derive(Debug, Clone, PartialEq, Eq)]
250 pub struct PacketFrame {
251 /// Application packet payload (chunk)
252 pub payload: [u8; 25],
253
254 /// Frame counter, which provides different information depending on whether this is the last frame or not.
255 pub counter: PacketFrameCounter,
256 }
257
258 #[derive(Debug, Clone, PartialEq, Eq)]
259 pub enum PacketFrameCounter {
260 /// Any packet frame that comes after the LSF and is not the final frame.
261 Frame {
262 /// Which frame this is in the superframe, from 0 to 31 inclusive.
263 ///
264 /// If a 33rd frame exists (index 32), it will be a `FinalFrame` instead.
265 ///
266 /// All 25 bytes of of `payload` are filled and valid.
267 index: usize,
268 },
269 /// The final frame in the packet superframe.
270 FinalFrame {
271 /// The number of bytes in `payload` that are filled.
272 payload_len: usize,
273 },
274 }
275
276 pub struct LichCollection([Option<[u8; 5]>; 6]);
277
278 impl LichCollection {
279 pub fn new() -> Self {
280 Self([None; 6])
281 }
282
283 pub fn valid_segments(&self) -> usize {
284 self.0.iter().filter(|s| s.is_some()).count()
285 }
286
287 pub fn set_segment(&mut self, counter: u8, part: [u8; 5]) {
288 self.0[counter as usize] = Some(part);
289 }
290
291 pub fn try_assemble(&self) -> Option<[u8; 30]> {
292 let mut out = [0u8; 30];
293 for (i, segment) in self.0.iter().enumerate() {
294 let Some(segment) = segment else {
295 return None;
296 };
297 for (j, seg_val) in segment.iter().enumerate() {
298 out[i * 5 + j] = *seg_val;
299 }
300 }
301 Some(out)
302 }
303 }
304
305 impl Default for LichCollection {
306 fn default() -> Self {
307 Self::new()
308 }
309 }
310
311 #[cfg(test)]
312 mod tests {
313 use super::*;
314
315 #[test]
316 fn set_can() {
317 let mut frame = LsfFrame([0u8; 30]);
318 frame.set_channel_access_number(11);
319 assert_eq!(frame.channel_access_number(), 11);
320 }
321 }