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