]> code.octet-stream.net Git - m17rt/blob - m17core/src/protocol.rs
96def5b8913ffdcc245baa7998a934ff470043d9
[m17rt] / m17core / src / protocol.rs
1 use crate::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
8 #[derive(Debug, Clone, PartialEq, Eq)]
9 pub enum Mode {
10 Packet,
11 Stream,
12 }
13 #[derive(Debug, Clone, PartialEq, Eq)]
14 pub enum DataType {
15 Reserved,
16 Data,
17 Voice,
18 VoiceAndData,
19 }
20 #[derive(Debug, Clone, PartialEq, Eq)]
21 pub enum EncryptionType {
22 None,
23 Scrambler,
24 Aes,
25 Other,
26 }
27
28 #[derive(Debug, Clone, PartialEq, Eq)]
29 pub enum Frame {
30 Lsf(LsfFrame),
31 Stream(StreamFrame),
32 // Packet
33 // BERT
34 }
35
36 pub enum PacketType {
37 /// RAW
38 Raw,
39 /// AX.25
40 Ax25,
41 /// APRS
42 Aprs,
43 /// 6LoWPAN
44 SixLowPan,
45 /// IPv4
46 Ipv4,
47 /// SMS
48 Sms,
49 /// Winlink
50 Winlink,
51 /// Custom identifier
52 Other(char),
53 }
54
55 impl PacketType {
56 pub fn as_proto(&self) -> ([u8; 4], usize) {
57 match self {
58 PacketType::Raw => ([0, 0, 0, 0], 1),
59 PacketType::Ax25 => ([1, 0, 0, 0], 1),
60 PacketType::Aprs => ([2, 0, 0, 0], 1),
61 PacketType::SixLowPan => ([3, 0, 0, 0], 1),
62 PacketType::Ipv4 => ([4, 0, 0, 0], 1),
63 PacketType::Sms => ([5, 0, 0, 0], 1),
64 PacketType::Winlink => ([6, 0, 0, 0], 1),
65 PacketType::Other(c) => {
66 let mut buf = [0u8; 4];
67 let s = c.encode_utf8(&mut buf);
68 let len = s.len();
69 (buf, len)
70 }
71 }
72 }
73
74 pub fn from_proto(&self, buf: &[u8]) -> Option<PacketType> {
75 buf.utf8_chunks()
76 .next()
77 .and_then(|chunk| chunk.valid().chars().next())
78 .map(|c| match c as u32 {
79 0x00 => PacketType::Raw,
80 0x01 => PacketType::Ax25,
81 0x02 => PacketType::Aprs,
82 0x03 => PacketType::SixLowPan,
83 0x04 => PacketType::Ipv4,
84 0x05 => PacketType::Sms,
85 0x06 => PacketType::Winlink,
86 _ => PacketType::Other(c),
87 })
88 }
89 }
90
91 #[derive(Debug, Clone, PartialEq, Eq)]
92 pub struct LsfFrame(pub [u8; 30]);
93
94 impl LsfFrame {
95 pub fn crc(&self) -> u16 {
96 crate::crc::m17_crc(&self.0)
97 }
98
99 pub fn destination(&self) -> Address {
100 crate::address::decode_address((&self.0[0..6]).try_into().unwrap())
101 }
102
103 pub fn source(&self) -> Address {
104 crate::address::decode_address((&self.0[6..12]).try_into().unwrap())
105 }
106
107 pub fn mode(&self) -> Mode {
108 if self.0[12] & 0x01 > 0 {
109 Mode::Stream
110 } else {
111 Mode::Packet
112 }
113 }
114
115 pub fn data_type(&self) -> DataType {
116 match (self.0[12] >> 1) & 0x03 {
117 0b00 => DataType::Reserved,
118 0b01 => DataType::Data,
119 0b10 => DataType::Voice,
120 0b11 => DataType::VoiceAndData,
121 _ => unreachable!(),
122 }
123 }
124
125 pub fn encryption_type(&self) -> EncryptionType {
126 match (self.0[12] >> 3) & 0x03 {
127 0b00 => EncryptionType::None,
128 0b01 => EncryptionType::Scrambler,
129 0b10 => EncryptionType::Aes,
130 0b11 => EncryptionType::Other,
131 _ => unreachable!(),
132 }
133 }
134
135 pub fn channel_access_number(&self) -> u8 {
136 (self.0[12] >> 7) & 0x0f
137 }
138
139 pub fn meta(&self) -> [u8; 14] {
140 self.0[14..28].try_into().unwrap()
141 }
142 }
143
144 #[derive(Debug, Clone, PartialEq, Eq)]
145 pub struct StreamFrame {
146 /// Which LICH segment is given in this frame, from 0 to 5 inclusive
147 pub lich_idx: u8,
148 /// Decoded LICH segment
149 pub lich_part: [u8; 5],
150 /// Which frame in the transmission this is, starting from 0
151 pub frame_number: u16,
152 /// Is this the last frame in the transmission?
153 pub end_of_stream: bool,
154 /// Raw application data in this frame
155 pub stream_data: [u8; 16],
156 }
157
158 pub struct LichCollection([Option<[u8; 5]>; 6]);
159
160 impl LichCollection {
161 pub fn new() -> Self {
162 Self([None; 6])
163 }
164
165 pub fn valid_segments(&self) -> usize {
166 self.0.iter().filter(|s| s.is_some()).count()
167 }
168
169 pub fn set_segment(&mut self, counter: u8, part: [u8; 5]) {
170 self.0[counter as usize] = Some(part);
171 }
172
173 pub fn try_assemble(&self) -> Option<[u8; 30]> {
174 let mut out = [0u8; 30];
175 for (i, segment) in self.0.iter().enumerate() {
176 let Some(segment) = segment else {
177 return None;
178 };
179 for (j, seg_val) in segment.iter().enumerate() {
180 out[i * 5 + j] = *seg_val;
181 }
182 }
183 Some(out)
184 }
185 }
186
187 impl Default for LichCollection {
188 fn default() -> Self {
189 Self::new()
190 }
191 }