]> code.octet-stream.net Git - m17rt/blob - m17core/src/kiss.rs
Initial public commit - basic demod and high level structure in place
[m17rt] / m17core / src / kiss.rs
1 // Note FEND and FESC both have the top two bits set. In the header byte this corresponds
2 // to high port numbers which are never used by M17 so we needn't bother (un)escaping it.
3
4 const FEND: u8 = 0xC0;
5 const FESC: u8 = 0xDB;
6 const TFEND: u8 = 0xDC;
7 const TFESC: u8 = 0xDD;
8
9 pub const PORT_PACKET_BASIC: u8 = 0;
10 pub const PORT_PACKET_FULL: u8 = 1;
11 pub const PORT_STREAM: u8 = 2;
12
13 /// Maximum theoretical frame size for any valid M17 KISS frame.
14 ///
15 /// In M17 Full Packet Mode a 30-byte LSF is merged with a packet which may be up to
16 /// 825 bytes in length. Supposing an (impossible) worst case that every byte is FEND
17 /// or FESC, 1710 bytes is the maximum expected payload. With a FEND at each end and
18 /// the KISS frame header byte we get 1713.
19 pub const MAX_FRAME_LEN: usize = 1713;
20
21 /// Holder for any valid M17 KISS frame.
22 ///
23 /// For efficiency, `data` and `len` are exposed directly and received KISS data may
24 /// be streamed directly into a pre-allocated `KissFrame`.
25 pub struct KissFrame {
26 pub data: [u8; MAX_FRAME_LEN],
27 pub len: usize,
28 }
29
30 impl KissFrame {
31 /// Request to transmit a data packet (basic mode).
32 ///
33 /// A raw payload up to 822 bytes can be provided. The TNC will mark it as Raw format
34 /// and automatically calculate the checksum. If required it will also chunk the packet
35 /// into individual frames and transmit them sequentially.
36 pub fn new_basic_packet(payload: &[u8]) -> Result<Self, KissError> {
37 // M17 packet payloads can be up to 825 bytes in length
38 // Type prefix (RAW = 0x00) occupies the first byte
39 // Last 2 bytes are checksum
40 if payload.len() > 822 {
41 return Err(KissError::PayloadTooBig);
42 }
43 let mut data = [0u8; MAX_FRAME_LEN];
44 let mut i = 0;
45 push(&mut data, &mut i, FEND);
46 push(
47 &mut data,
48 &mut i,
49 kiss_header(PORT_PACKET_BASIC, KissCommand::DataFrame.proto_value()),
50 );
51
52 i += escape(payload, &mut data[i..]);
53 push(&mut data, &mut i, FEND);
54
55 Ok(KissFrame { data, len: i })
56 }
57
58 /// Request to transmit a data packet (full mode).
59 ///
60 /// Sender must provide a 30-byte LSF and a full packet payload (up to 825 bytes)
61 /// that will be combined into the frame. The packet payload must include the type
62 /// code prefix and the CRC, both of which would have been calculated by the TNC if
63 /// it was basic mode.
64 pub fn new_full_packet(lsf: &[u8], packet: &[u8]) -> Result<Self, KissError> {
65 if lsf.len() != 30 {
66 return Err(KissError::LsfWrongSize);
67 }
68 if packet.len() > 825 {
69 return Err(KissError::PayloadTooBig);
70 }
71 let mut data = [0u8; MAX_FRAME_LEN];
72 let mut i = 0;
73 push(&mut data, &mut i, FEND);
74 push(
75 &mut data,
76 &mut i,
77 kiss_header(PORT_PACKET_FULL, KissCommand::DataFrame.proto_value()),
78 );
79 i += escape(lsf, &mut data[i..]);
80 i += escape(packet, &mut data[i..]);
81 push(&mut data, &mut i, FEND);
82
83 Ok(KissFrame { data, len: i })
84 }
85
86 /// Request to begin a stream data transfer (e.g. voice).
87 ///
88 /// An LSF payload of exactly 30 bytes must be provided.
89 ///
90 /// This must be followed by at least one stream data payload, ending with one that
91 /// has the end of stream (EOS) bit set.
92 pub fn new_stream_setup(lsf: &[u8]) -> Result<Self, KissError> {
93 if lsf.len() != 30 {
94 return Err(KissError::LsfWrongSize);
95 }
96 let mut data = [0u8; MAX_FRAME_LEN];
97 let mut i = 0;
98 push(&mut data, &mut i, FEND);
99 push(
100 &mut data,
101 &mut i,
102 kiss_header(PORT_STREAM, KissCommand::DataFrame.proto_value()),
103 );
104 i += escape(lsf, &mut data[i..]);
105 push(&mut data, &mut i, FEND);
106
107 Ok(KissFrame { data, len: i })
108 }
109
110 /// Transmit a segment of data in a stream transfer (e.g. voice).
111 ///
112 /// A data payload of 26 bytes including metadata must be provided. This must follow
113 /// exactly the prescribed format (H.5.2 in the spec). The TNC will be watching for
114 /// the EOS flag to know that this transmission has ended.
115 pub fn new_stream_data(stream_data: &[u8]) -> Result<Self, KissError> {
116 if stream_data.len() != 26 {
117 return Err(KissError::StreamDataWrongSize);
118 }
119 let mut data = [0u8; MAX_FRAME_LEN];
120 let mut i = 0;
121 push(&mut data, &mut i, FEND);
122 push(
123 &mut data,
124 &mut i,
125 kiss_header(PORT_STREAM, KissCommand::DataFrame.proto_value()),
126 );
127 i += escape(stream_data, &mut data[i..]);
128 push(&mut data, &mut i, FEND);
129
130 Ok(KissFrame { data, len: i })
131 }
132
133 /// Request to set the TxDelay
134 pub fn new_set_tx_delay(port: u8, units: u8) -> Self {
135 let mut data = [0u8; MAX_FRAME_LEN];
136 let mut i = 0;
137 push(&mut data, &mut i, FEND);
138 push(
139 &mut data,
140 &mut i,
141 kiss_header(port, KissCommand::TxDelay.proto_value()),
142 );
143 push(&mut data, &mut i, units);
144 push(&mut data, &mut i, FEND);
145
146 KissFrame { data, len: i }
147 }
148
149 /// Request to set the persistence parameter P
150 pub fn new_set_p(port: u8, units: u8) -> Self {
151 let mut data = [0u8; MAX_FRAME_LEN];
152 let mut i = 0;
153 push(&mut data, &mut i, FEND);
154 push(
155 &mut data,
156 &mut i,
157 kiss_header(port, KissCommand::P.proto_value()),
158 );
159 push(&mut data, &mut i, units);
160 push(&mut data, &mut i, FEND);
161
162 KissFrame { data, len: i }
163 }
164
165 /// Request to set full duplex or not
166 pub fn set_full_duplex(port: u8, full_duplex: bool) -> Self {
167 let mut data = [0u8; MAX_FRAME_LEN];
168 let mut i = 0;
169 push(&mut data, &mut i, FEND);
170 push(
171 &mut data,
172 &mut i,
173 kiss_header(port, KissCommand::FullDuplex.proto_value()),
174 );
175 push(&mut data, &mut i, if full_duplex { 1 } else { 0 });
176 push(&mut data, &mut i, FEND);
177
178 KissFrame { data, len: i }
179 }
180
181 /// Return this frame's KISS command type.
182 pub fn command(&self) -> Result<KissCommand, KissError> {
183 KissCommand::from_proto(self.header_byte()? & 0x0f)
184 }
185
186 /// Return the KISS port to which this frame relates. Should be 0, 1 or 2.
187 pub fn port(&self) -> Result<u8, KissError> {
188 Ok(self.header_byte()? >> 4)
189 }
190
191 /// Payload part of the frame between the header byte and the trailing FEND, unescaped.
192 pub fn decode_payload(&self, out: &mut [u8]) -> Result<usize, KissError> {
193 let start = self
194 .data
195 .iter()
196 .enumerate()
197 .skip_while(|(_, b)| **b == FEND)
198 .skip(1)
199 .next()
200 .ok_or(KissError::MalformedKissFrame)?
201 .0;
202 let end = self.data[start..]
203 .iter()
204 .enumerate()
205 .skip_while(|(_, b)| **b != FEND)
206 .next()
207 .ok_or(KissError::MalformedKissFrame)?
208 .0
209 + start;
210 Ok(unescape(&self.data[start..end], out))
211 }
212
213 /// Borrow the frame as a slice
214 pub fn as_bytes(&self) -> &[u8] {
215 &self.data[..self.len]
216 }
217
218 /// Return the header byte of the KISS frame, skipping over 0 or more prepended FENDs.
219 fn header_byte(&self) -> Result<u8, KissError> {
220 Ok(self
221 .data
222 .iter()
223 .skip_while(|b| **b == FEND)
224 .next()
225 .cloned()
226 .ok_or(KissError::MalformedKissFrame)?)
227 }
228 }
229
230 fn kiss_header(port: u8, command: u8) -> u8 {
231 (port << 4) | (command & 0x0f)
232 }
233
234 fn push(data: &mut [u8], idx: &mut usize, value: u8) {
235 data[*idx] = value;
236 *idx += 1;
237 }
238
239 pub enum KissCommand {
240 DataFrame,
241 TxDelay,
242 P,
243 FullDuplex,
244 }
245
246 impl KissCommand {
247 fn from_proto(value: u8) -> Result<Self, KissError> {
248 Ok(match value {
249 0 => KissCommand::DataFrame,
250 1 => KissCommand::TxDelay,
251 2 => KissCommand::P,
252 5 => KissCommand::FullDuplex,
253 _ => return Err(KissError::UnsupportedKissCommand),
254 })
255 }
256
257 fn proto_value(&self) -> u8 {
258 match self {
259 KissCommand::DataFrame => 0,
260 KissCommand::TxDelay => 1,
261 KissCommand::P => 2,
262 KissCommand::FullDuplex => 5,
263 }
264 }
265 }
266
267 #[derive(Debug)]
268 pub enum KissError {
269 MalformedKissFrame,
270 UnsupportedKissCommand,
271 PayloadTooBig,
272 LsfWrongSize,
273 StreamDataWrongSize,
274 }
275
276 fn escape(src: &[u8], dst: &mut [u8]) -> usize {
277 let mut i = 0;
278 let mut j = 0;
279 while i < src.len() && j < dst.len() {
280 if src[i] == FEND {
281 dst[j] = FESC;
282 j += 1;
283 dst[j] = TFEND;
284 } else if src[i] == FESC {
285 dst[j] = FESC;
286 j += 1;
287 dst[j] = TFESC;
288 } else {
289 dst[j] = src[i];
290 }
291 i += 1;
292 j += 1;
293 }
294 j
295 }
296
297 fn unescape(src: &[u8], dst: &mut [u8]) -> usize {
298 let mut i = 0;
299 let mut j = 0;
300 while i < src.len() && j < dst.len() {
301 if src[i] == FESC {
302 if i == src.len() - 1 {
303 break;
304 }
305 i += 1;
306 if src[i] == TFEND {
307 dst[j] = FEND;
308 } else if src[i] == TFESC {
309 dst[j] = FESC;
310 }
311 } else {
312 dst[j] = src[i];
313 }
314 i += 1;
315 j += 1;
316 }
317 j
318 }
319
320 #[cfg(test)]
321 mod tests {
322 use super::*;
323
324 #[test]
325 fn test_escape() {
326 let mut buf = [0u8; 1024];
327
328 let src = [0, 1, 2, 3, 4, 5];
329 let n = escape(&src, &mut buf);
330 assert_eq!(n, 6);
331 assert_eq!(&buf[0..6], src);
332
333 let src = [0, 1, TFESC, 3, TFEND, 5];
334 let n = escape(&src, &mut buf);
335 assert_eq!(n, 6);
336 assert_eq!(&buf[0..6], src);
337
338 let src = [0, 1, FEND, 3, 4, 5];
339 let n = escape(&src, &mut buf);
340 assert_eq!(n, 7);
341 assert_eq!(&buf[0..7], &[0, 1, FESC, TFEND, 3, 4, 5]);
342
343 let src = [0, 1, 2, 3, 4, FESC];
344 let n = escape(&src, &mut buf);
345 assert_eq!(n, 7);
346 assert_eq!(&buf[0..7], &[0, 1, 2, 3, 4, FESC, TFESC]);
347 }
348
349 #[test]
350 fn test_unescape() {
351 let mut buf = [0u8; 1024];
352
353 let src = [0, 1, 2, 3, 4, 5];
354 let n = unescape(&src, &mut buf);
355 assert_eq!(n, 6);
356 assert_eq!(&buf[0..6], src);
357
358 let src = [0, 1, TFESC, 3, TFEND, 5];
359 let n = unescape(&src, &mut buf);
360 assert_eq!(n, 6);
361 assert_eq!(&buf[0..6], src);
362
363 let src = [0, 1, FESC, TFEND, 3, 4, 5];
364 let n = unescape(&src, &mut buf);
365 assert_eq!(n, 6);
366 assert_eq!(&buf[0..6], &[0, 1, FEND, 3, 4, 5]);
367
368 let src = [0, 1, 2, 3, 4, FESC, TFESC];
369 let n = unescape(&src, &mut buf);
370 assert_eq!(n, 6);
371 assert_eq!(&buf[0..6], &[0, 1, 2, 3, 4, FESC]);
372 }
373
374 #[test]
375 fn basic_packet_roundtrip() {
376 let f = KissFrame::new_basic_packet(&[0, 1, 2, 3]).unwrap();
377 assert_eq!(f.as_bytes(), &[FEND, 0, 0, 1, 2, 3, FEND]);
378 let mut buf = [0u8; 1024];
379 let n = f.decode_payload(&mut buf).unwrap();
380 assert_eq!(&buf[..n], &[0, 1, 2, 3]);
381 }
382 }