]> code.octet-stream.net Git - m17rt/blob - m17core/src/kiss.rs
Fix packet encoding
[m17rt] / m17core / src / kiss.rs
1 use crate::protocol::StreamFrame;
2
3 // Note FEND and FESC both have the top two bits set. In the header byte this corresponds
4 // to high port numbers which are never used by M17 so we needn't bother (un)escaping it.
5
6 const FEND: u8 = 0xC0;
7 const FESC: u8 = 0xDB;
8 const TFEND: u8 = 0xDC;
9 const TFESC: u8 = 0xDD;
10
11 pub const PORT_PACKET_BASIC: u8 = 0;
12 pub const PORT_PACKET_FULL: u8 = 1;
13 pub const PORT_STREAM: u8 = 2;
14
15 /// Maximum theoretical frame size for any valid M17 KISS frame.
16 ///
17 /// In M17 Full Packet Mode a 30-byte LSF is merged with a packet which may be up to
18 /// 825 bytes in length. Supposing an (impossible) worst case that every byte is FEND
19 /// or FESC, 1710 bytes is the maximum expected payload. With a FEND at each end and
20 /// the KISS frame header byte we get 1713.
21 pub const MAX_FRAME_LEN: usize = 1713;
22
23 /// Holder for any valid M17 KISS frame.
24 ///
25 /// For efficiency, `data` and `len` are exposed directly and received KISS data may
26 /// be streamed directly into a pre-allocated `KissFrame`.
27 #[derive(Debug, PartialEq, Eq, Clone)]
28 pub struct KissFrame {
29 pub data: [u8; MAX_FRAME_LEN],
30 pub len: usize,
31 }
32
33 impl KissFrame {
34 /// Construct empty frame
35 pub fn new_empty() -> Self {
36 Self {
37 data: [0u8; MAX_FRAME_LEN],
38 len: 0,
39 }
40 }
41
42 /// Request to transmit a data packet (basic mode).
43 ///
44 /// A raw payload up to 822 bytes can be provided. The TNC will mark it as Raw format
45 /// and automatically calculate the checksum. If required it will also chunk the packet
46 /// into individual frames and transmit them sequentially.
47 pub fn new_basic_packet(payload: &[u8]) -> Result<Self, KissError> {
48 // M17 packet payloads can be up to 825 bytes in length
49 // Type prefix (RAW = 0x00) occupies the first byte
50 // Last 2 bytes are checksum
51 if payload.len() > 822 {
52 return Err(KissError::PayloadTooBig);
53 }
54 let mut data = [0u8; MAX_FRAME_LEN];
55 let mut i = 0;
56 push(&mut data, &mut i, FEND);
57 push(
58 &mut data,
59 &mut i,
60 kiss_header(PORT_PACKET_BASIC, KissCommand::DataFrame.proto_value()),
61 );
62
63 i += escape(payload, &mut data[i..]);
64 push(&mut data, &mut i, FEND);
65
66 Ok(KissFrame { data, len: i })
67 }
68
69 /// Request to transmit a data packet (full mode).
70 ///
71 /// Sender must provide a 30-byte LSF and a full packet payload (up to 825 bytes)
72 /// that will be combined into the frame. The packet payload must include the type
73 /// code prefix and the CRC, both of which would have been calculated by the TNC if
74 /// it was basic mode.
75 pub fn new_full_packet(lsf: &[u8], packet: &[u8]) -> Result<Self, KissError> {
76 if lsf.len() != 30 {
77 return Err(KissError::LsfWrongSize);
78 }
79 if packet.len() > 825 {
80 return Err(KissError::PayloadTooBig);
81 }
82 let mut data = [0u8; MAX_FRAME_LEN];
83 let mut i = 0;
84 push(&mut data, &mut i, FEND);
85 push(
86 &mut data,
87 &mut i,
88 kiss_header(PORT_PACKET_FULL, KissCommand::DataFrame.proto_value()),
89 );
90 i += escape(lsf, &mut data[i..]);
91 i += escape(packet, &mut data[i..]);
92 push(&mut data, &mut i, FEND);
93
94 Ok(KissFrame { data, len: i })
95 }
96
97 /// Request to begin a stream data transfer (e.g. voice).
98 ///
99 /// An LSF payload of exactly 30 bytes must be provided.
100 ///
101 /// This must be followed by at least one stream data payload, ending with one that
102 /// has the end of stream (EOS) bit set.
103 pub fn new_stream_setup(lsf: &[u8]) -> Result<Self, KissError> {
104 if lsf.len() != 30 {
105 return Err(KissError::LsfWrongSize);
106 }
107 let mut data = [0u8; MAX_FRAME_LEN];
108 let mut i = 0;
109 push(&mut data, &mut i, FEND);
110 push(
111 &mut data,
112 &mut i,
113 kiss_header(PORT_STREAM, KissCommand::DataFrame.proto_value()),
114 );
115 i += escape(lsf, &mut data[i..]);
116 push(&mut data, &mut i, FEND);
117
118 Ok(KissFrame { data, len: i })
119 }
120
121 /// Transmit a segment of data in a stream transfer (e.g. voice).
122 pub fn new_stream_data(frame: &StreamFrame) -> Result<Self, KissError> {
123 let mut data = [0u8; MAX_FRAME_LEN];
124 let mut i = 0;
125 push(&mut data, &mut i, FEND);
126 push(
127 &mut data,
128 &mut i,
129 kiss_header(PORT_STREAM, KissCommand::DataFrame.proto_value()),
130 );
131
132 // 5 bytes LICH content
133 i += escape(&frame.lich_part, &mut data[i..]);
134 // 1 byte LICH metadata
135 i += escape(&[frame.lich_idx << 5], &mut data[i..]);
136
137 // 2 bytes frame number/EOS + 16 bytes payload + 2 bytes CRC
138 let mut inner_data = [0u8; 20];
139 let frame_num = frame.frame_number.to_be_bytes();
140 inner_data[0] = frame_num[0] | if frame.end_of_stream { 0x80 } else { 0 };
141 inner_data[1] = frame_num[1];
142 inner_data[2..18].copy_from_slice(&frame.stream_data);
143 let crc = crate::crc::m17_crc(&inner_data[0..18]);
144 let crc_be = crc.to_be_bytes();
145 inner_data[18] = crc_be[0];
146 inner_data[19] = crc_be[1];
147 i += escape(&inner_data, &mut data[i..]);
148
149 push(&mut data, &mut i, FEND);
150 Ok(KissFrame { data, len: i })
151 }
152
153 /// Request to set the TxDelay
154 pub fn new_set_tx_delay(port: u8, units: u8) -> Self {
155 let mut data = [0u8; MAX_FRAME_LEN];
156 let mut i = 0;
157 push(&mut data, &mut i, FEND);
158 push(
159 &mut data,
160 &mut i,
161 kiss_header(port, KissCommand::TxDelay.proto_value()),
162 );
163 push(&mut data, &mut i, units);
164 push(&mut data, &mut i, FEND);
165
166 KissFrame { data, len: i }
167 }
168
169 /// Request to set the persistence parameter P
170 pub fn new_set_p(port: u8, units: u8) -> Self {
171 let mut data = [0u8; MAX_FRAME_LEN];
172 let mut i = 0;
173 push(&mut data, &mut i, FEND);
174 push(
175 &mut data,
176 &mut i,
177 kiss_header(port, KissCommand::P.proto_value()),
178 );
179 push(&mut data, &mut i, units);
180 push(&mut data, &mut i, FEND);
181
182 KissFrame { data, len: i }
183 }
184
185 /// Request to set full duplex or not
186 pub fn set_full_duplex(port: u8, full_duplex: bool) -> Self {
187 let mut data = [0u8; MAX_FRAME_LEN];
188 let mut i = 0;
189 push(&mut data, &mut i, FEND);
190 push(
191 &mut data,
192 &mut i,
193 kiss_header(port, KissCommand::FullDuplex.proto_value()),
194 );
195 push(&mut data, &mut i, if full_duplex { 1 } else { 0 });
196 push(&mut data, &mut i, FEND);
197
198 KissFrame { data, len: i }
199 }
200
201 /// Return this frame's KISS command type.
202 pub fn command(&self) -> Result<KissCommand, KissError> {
203 KissCommand::from_proto(self.header_byte()? & 0x0f)
204 }
205
206 /// Return the KISS port to which this frame relates. Should be 0, 1 or 2.
207 pub fn port(&self) -> Result<u8, KissError> {
208 Ok(self.header_byte()? >> 4)
209 }
210
211 /// Payload part of the frame between the header byte and the trailing FEND, unescaped.
212 pub fn decode_payload(&self, out: &mut [u8]) -> Result<usize, KissError> {
213 let start = self
214 .data
215 .iter()
216 .enumerate()
217 .skip_while(|(_, b)| **b == FEND)
218 .skip(1)
219 .next()
220 .ok_or(KissError::MalformedKissFrame)?
221 .0;
222 let end = self.data[start..]
223 .iter()
224 .enumerate()
225 .skip_while(|(_, b)| **b != FEND)
226 .next()
227 .ok_or(KissError::MalformedKissFrame)?
228 .0
229 + start;
230 Ok(unescape(&self.data[start..end], out))
231 }
232
233 /// Borrow the frame as a slice
234 pub fn as_bytes(&self) -> &[u8] {
235 &self.data[..self.len]
236 }
237
238 /// Return the header byte of the KISS frame, skipping over 0 or more prepended FENDs.
239 fn header_byte(&self) -> Result<u8, KissError> {
240 Ok(self
241 .data
242 .iter()
243 .skip_while(|b| **b == FEND)
244 .next()
245 .cloned()
246 .ok_or(KissError::MalformedKissFrame)?)
247 }
248 }
249
250 fn kiss_header(port: u8, command: u8) -> u8 {
251 (port << 4) | (command & 0x0f)
252 }
253
254 fn push(data: &mut [u8], idx: &mut usize, value: u8) {
255 data[*idx] = value;
256 *idx += 1;
257 }
258
259 #[derive(Debug, PartialEq, Eq, Clone)]
260 pub enum KissCommand {
261 DataFrame,
262 TxDelay,
263 P,
264 FullDuplex,
265 }
266
267 impl KissCommand {
268 fn from_proto(value: u8) -> Result<Self, KissError> {
269 Ok(match value {
270 0 => KissCommand::DataFrame,
271 1 => KissCommand::TxDelay,
272 2 => KissCommand::P,
273 5 => KissCommand::FullDuplex,
274 _ => return Err(KissError::UnsupportedKissCommand),
275 })
276 }
277
278 fn proto_value(&self) -> u8 {
279 match self {
280 KissCommand::DataFrame => 0,
281 KissCommand::TxDelay => 1,
282 KissCommand::P => 2,
283 KissCommand::FullDuplex => 5,
284 }
285 }
286 }
287
288 /// Accepts raw KISS data and emits one frame at a time.
289 ///
290 /// A frame will be emitted if there is at least one byte between FEND markers. It is up to the consumer
291 /// to determine whether it's actually a valid frame.
292 pub struct KissBuffer {
293 /// Provisional frame, whose buffer might contain more than one sequential frame at a time
294 frame: KissFrame,
295 /// Number of bytes that have been written into `frame.data`, which may be more than the the length
296 /// of the first valid frame, `frame.len`.
297 written: usize,
298 /// Whether we have emitted the first frame in `frame`'s buffer and now need to flush it out.
299 first_frame_returned: bool,
300 }
301
302 impl KissBuffer {
303 /// Create new buffer
304 pub fn new() -> Self {
305 Self {
306 frame: KissFrame::new_empty(),
307 written: 0,
308 first_frame_returned: false,
309 }
310 }
311
312 /// Return the space remaining for more data
313 pub fn buf_remaining(&mut self) -> &mut [u8] {
314 self.flush_first_frame();
315 if self.written == self.frame.data.len() {
316 // full buffer with no data means oversized frame
317 // sender is doing something weird or a FEND got dropped
318 // either way: flush it all and try to sync up again
319 self.written = 0;
320 }
321 &mut self.frame.data[self.written..]
322 }
323
324 /// Indicate how much data was written into the buffer provided by `buf_remaining()`.
325 pub fn did_write(&mut self, len: usize) {
326 self.written += len;
327 }
328
329 /// Try to construct and retrieve the next frame in the buffer
330 pub fn next_frame(&mut self) -> Option<&KissFrame> {
331 self.flush_first_frame();
332
333 // If we have any data without a leading FEND, scan past it
334 let mut i = 0;
335 while i < self.written && self.frame.data[i] != FEND {
336 i += 1;
337 }
338 self.move_to_start(i);
339
340 // If we do have a leading FEND, scan up up to the last one in the series
341 i = 0;
342 while (i + 1) < self.written && self.frame.data[i + 1] == FEND {
343 i += 1;
344 }
345 if i != 0 {
346 self.move_to_start(i);
347 }
348
349 // Now, if we have FEND-something-FEND, return it
350 if self.written >= 2 && self.frame.data[0] == FEND && self.frame.data[1] != FEND {
351 i = 2;
352 while i < self.written && self.frame.data[i] != FEND {
353 i += 1;
354 }
355 if i < self.written && self.frame.data[i] == FEND {
356 self.frame.len = i + 1;
357 self.first_frame_returned = true;
358 return Some(&self.frame);
359 }
360 }
361
362 None
363 }
364
365 /// Check if we just returned a frame; if so, clear it out and position the buffer for the next frame.
366 fn flush_first_frame(&mut self) {
367 if !self.first_frame_returned {
368 return;
369 }
370 self.first_frame_returned = false;
371 // If we have previously returned a valid frame, in the simplest case `frame.data` contains FEND-something-FEND
372 // So to find the trailing FEND we can start at index 2
373 // Loop forward until we find that FEND, which must exist, and leave its index in `i`
374 let mut i = 2;
375 while self.frame.data[i] != FEND {
376 i += 1;
377 }
378 // However if we have consecutive trailing FENDs we want to ignore them
379 // Having found the trailing FEND, increment past any additional FENDs until we reach the end or something else
380 while (i + 1) < self.written && self.frame.data[i + 1] == FEND {
381 i += 1;
382 }
383 // Now take that final FEND and make it the start of our frame
384 self.move_to_start(i);
385 }
386
387 /// Shift all data in the buffer back to the beginning starting from the given index.
388 fn move_to_start(&mut self, idx: usize) {
389 for i in idx..self.written {
390 self.frame.data[i - idx] = self.frame.data[i];
391 }
392 self.written -= idx;
393 }
394 }
395
396 #[derive(Debug, PartialEq, Eq, Clone)]
397 pub enum KissError {
398 MalformedKissFrame,
399 UnsupportedKissCommand,
400 PayloadTooBig,
401 LsfWrongSize,
402 }
403
404 fn escape(src: &[u8], dst: &mut [u8]) -> usize {
405 let mut i = 0;
406 let mut j = 0;
407 while i < src.len() && j < dst.len() {
408 if src[i] == FEND {
409 dst[j] = FESC;
410 j += 1;
411 dst[j] = TFEND;
412 } else if src[i] == FESC {
413 dst[j] = FESC;
414 j += 1;
415 dst[j] = TFESC;
416 } else {
417 dst[j] = src[i];
418 }
419 i += 1;
420 j += 1;
421 }
422 j
423 }
424
425 fn unescape(src: &[u8], dst: &mut [u8]) -> usize {
426 let mut i = 0;
427 let mut j = 0;
428 while i < src.len() && j < dst.len() {
429 if src[i] == FESC {
430 if i == src.len() - 1 {
431 break;
432 }
433 i += 1;
434 if src[i] == TFEND {
435 dst[j] = FEND;
436 } else if src[i] == TFESC {
437 dst[j] = FESC;
438 }
439 } else {
440 dst[j] = src[i];
441 }
442 i += 1;
443 j += 1;
444 }
445 j
446 }
447
448 #[cfg(test)]
449 mod tests {
450 use super::*;
451
452 #[test]
453 fn test_escape() {
454 let mut buf = [0u8; 1024];
455
456 let src = [0, 1, 2, 3, 4, 5];
457 let n = escape(&src, &mut buf);
458 assert_eq!(n, 6);
459 assert_eq!(&buf[0..6], src);
460
461 let src = [0, 1, TFESC, 3, TFEND, 5];
462 let n = escape(&src, &mut buf);
463 assert_eq!(n, 6);
464 assert_eq!(&buf[0..6], src);
465
466 let src = [0, 1, FEND, 3, 4, 5];
467 let n = escape(&src, &mut buf);
468 assert_eq!(n, 7);
469 assert_eq!(&buf[0..7], &[0, 1, FESC, TFEND, 3, 4, 5]);
470
471 let src = [0, 1, 2, 3, 4, FESC];
472 let n = escape(&src, &mut buf);
473 assert_eq!(n, 7);
474 assert_eq!(&buf[0..7], &[0, 1, 2, 3, 4, FESC, TFESC]);
475 }
476
477 #[test]
478 fn test_unescape() {
479 let mut buf = [0u8; 1024];
480
481 let src = [0, 1, 2, 3, 4, 5];
482 let n = unescape(&src, &mut buf);
483 assert_eq!(n, 6);
484 assert_eq!(&buf[0..6], src);
485
486 let src = [0, 1, TFESC, 3, TFEND, 5];
487 let n = unescape(&src, &mut buf);
488 assert_eq!(n, 6);
489 assert_eq!(&buf[0..6], src);
490
491 let src = [0, 1, FESC, TFEND, 3, 4, 5];
492 let n = unescape(&src, &mut buf);
493 assert_eq!(n, 6);
494 assert_eq!(&buf[0..6], &[0, 1, FEND, 3, 4, 5]);
495
496 let src = [0, 1, 2, 3, 4, FESC, TFESC];
497 let n = unescape(&src, &mut buf);
498 assert_eq!(n, 6);
499 assert_eq!(&buf[0..6], &[0, 1, 2, 3, 4, FESC]);
500 }
501
502 #[test]
503 fn basic_packet_roundtrip() {
504 let f = KissFrame::new_basic_packet(&[0, 1, 2, 3]).unwrap();
505 assert_eq!(f.as_bytes(), &[FEND, 0, 0, 1, 2, 3, FEND]);
506 let mut buf = [0u8; 1024];
507 let n = f.decode_payload(&mut buf).unwrap();
508 assert_eq!(&buf[..n], &[0, 1, 2, 3]);
509 }
510
511 #[test]
512 fn test_buffer_basic() {
513 let mut buffer = KissBuffer::new();
514
515 // initial write is not a complete frame
516 let buf = buffer.buf_remaining();
517 buf[0] = FEND;
518 buffer.did_write(1);
519 assert!(buffer.next_frame().is_none());
520
521 // complete the frame
522 let buf = buffer.buf_remaining();
523 buf[0] = 0x10;
524 buf[1] = 0x01;
525 buf[2] = FEND;
526 buffer.did_write(3);
527
528 // everything should parse
529 let next = buffer.next_frame().unwrap();
530 assert_eq!(next.len, 4);
531 assert_eq!(&next.data[0..4], &[FEND, 0x10, 0x01, FEND]);
532 assert_eq!(next.port().unwrap(), 1);
533 assert_eq!(next.command().unwrap(), KissCommand::DataFrame);
534 let mut payload_buf = [0u8; 1024];
535 let n = next.decode_payload(&mut payload_buf).unwrap();
536 assert_eq!(n, 1);
537 assert_eq!(&payload_buf[0..n], &[0x01]);
538 }
539
540 #[test]
541 fn test_buffer_double() {
542 let mut buffer = KissBuffer::new();
543 let buf = buffer.buf_remaining();
544 buf[0..8].copy_from_slice(&[FEND, 0x10, 0x01, FEND, FEND, 0x20, 02, FEND]);
545 buffer.did_write(8);
546
547 let next = buffer.next_frame().unwrap();
548 assert_eq!(next.port().unwrap(), 1);
549 let next = buffer.next_frame().unwrap();
550 assert_eq!(next.port().unwrap(), 2);
551 assert!(buffer.next_frame().is_none());
552 }
553
554 #[test]
555 fn test_buffer_double_shared_fend() {
556 let mut buffer = KissBuffer::new();
557 let buf = buffer.buf_remaining();
558 buf[0..7].copy_from_slice(&[FEND, 0x10, 0x01, FEND, 0x20, 02, FEND]);
559 buffer.did_write(7);
560
561 let next = buffer.next_frame().unwrap();
562 assert_eq!(next.port().unwrap(), 1);
563 let next = buffer.next_frame().unwrap();
564 assert_eq!(next.port().unwrap(), 2);
565 assert!(buffer.next_frame().is_none());
566 }
567
568 #[test]
569 fn test_buffer_extra_fend() {
570 let mut buffer = KissBuffer::new();
571 let buf = buffer.buf_remaining();
572 buf[0..10].copy_from_slice(&[FEND, FEND, FEND, 0x10, 0x01, FEND, FEND, 0x20, 02, FEND]);
573 buffer.did_write(10);
574
575 let next = buffer.next_frame().unwrap();
576 assert_eq!(next.port().unwrap(), 1);
577 let next = buffer.next_frame().unwrap();
578 assert_eq!(next.port().unwrap(), 2);
579 assert!(buffer.next_frame().is_none());
580 }
581
582 #[test]
583 fn test_buffer_oversize_frame() {
584 let mut buffer = KissBuffer::new();
585 let buf = buffer.buf_remaining();
586 buf[0] = FEND;
587 let len = buf.len();
588 assert_eq!(len, MAX_FRAME_LEN);
589 buffer.did_write(len);
590 assert!(buffer.next_frame().is_none());
591
592 let buf = buffer.buf_remaining();
593 let len = buf.len();
594 assert_eq!(len, MAX_FRAME_LEN); // should have flushed
595 for i in 0..len / 2 {
596 buf[i] = 0x00;
597 }
598 buffer.did_write(len / 2);
599 assert!(buffer.next_frame().is_none());
600
601 // confirm we resync if input goes back to normal
602 let buf = buffer.buf_remaining();
603 buf[0..4].copy_from_slice(&[FEND, 0x10, 0x01, FEND]);
604 buffer.did_write(4);
605 let next = buffer.next_frame().unwrap();
606 assert_eq!(next.port().unwrap(), 1);
607 assert!(buffer.next_frame().is_none());
608 }
609 }