]> code.octet-stream.net Git - m17rt/blob - m17core/src/kiss.rs
4ada6dca77184ecad4508671a2de95b0b02c4deb
[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 .nth(1)
219 .ok_or(KissError::MalformedKissFrame)?
220 .0;
221 let end = self.data[start..]
222 .iter()
223 .enumerate()
224 .find(|(_, b)| **b == FEND)
225 .ok_or(KissError::MalformedKissFrame)?
226 .0
227 + start;
228 Ok(unescape(&self.data[start..end], out))
229 }
230
231 /// Borrow the frame as a slice
232 pub fn as_bytes(&self) -> &[u8] {
233 &self.data[..self.len]
234 }
235
236 /// Return the header byte of the KISS frame, skipping over 0 or more prepended FENDs.
237 fn header_byte(&self) -> Result<u8, KissError> {
238 self.data
239 .iter()
240 .find(|b| **b != FEND)
241 .cloned()
242 .ok_or(KissError::MalformedKissFrame)
243 }
244 }
245
246 fn kiss_header(port: u8, command: u8) -> u8 {
247 (port << 4) | (command & 0x0f)
248 }
249
250 fn push(data: &mut [u8], idx: &mut usize, value: u8) {
251 data[*idx] = value;
252 *idx += 1;
253 }
254
255 #[derive(Debug, PartialEq, Eq, Clone)]
256 pub enum KissCommand {
257 DataFrame,
258 TxDelay,
259 P,
260 FullDuplex,
261 }
262
263 impl KissCommand {
264 fn from_proto(value: u8) -> Result<Self, KissError> {
265 Ok(match value {
266 0 => KissCommand::DataFrame,
267 1 => KissCommand::TxDelay,
268 2 => KissCommand::P,
269 5 => KissCommand::FullDuplex,
270 _ => return Err(KissError::UnsupportedKissCommand),
271 })
272 }
273
274 fn proto_value(&self) -> u8 {
275 match self {
276 KissCommand::DataFrame => 0,
277 KissCommand::TxDelay => 1,
278 KissCommand::P => 2,
279 KissCommand::FullDuplex => 5,
280 }
281 }
282 }
283
284 /// Accepts raw KISS data and emits one frame at a time.
285 ///
286 /// A frame will be emitted if there is at least one byte between FEND markers. It is up to the consumer
287 /// to determine whether it's actually a valid frame.
288 pub struct KissBuffer {
289 /// Provisional frame, whose buffer might contain more than one sequential frame at a time
290 frame: KissFrame,
291 /// Number of bytes that have been written into `frame.data`, which may be more than the the length
292 /// of the first valid frame, `frame.len`.
293 written: usize,
294 /// Whether we have emitted the first frame in `frame`'s buffer and now need to flush it out.
295 first_frame_returned: bool,
296 }
297
298 impl KissBuffer {
299 /// Create new buffer
300 pub fn new() -> Self {
301 Self {
302 frame: KissFrame::new_empty(),
303 written: 0,
304 first_frame_returned: false,
305 }
306 }
307
308 /// Return the space remaining for more data
309 pub fn buf_remaining(&mut self) -> &mut [u8] {
310 self.flush_first_frame();
311 if self.written == self.frame.data.len() {
312 // full buffer with no data means oversized frame
313 // sender is doing something weird or a FEND got dropped
314 // either way: flush it all and try to sync up again
315 self.written = 0;
316 }
317 &mut self.frame.data[self.written..]
318 }
319
320 /// Indicate how much data was written into the buffer provided by `buf_remaining()`.
321 pub fn did_write(&mut self, len: usize) {
322 self.written += len;
323 }
324
325 /// Try to construct and retrieve the next frame in the buffer
326 pub fn next_frame(&mut self) -> Option<&KissFrame> {
327 self.flush_first_frame();
328
329 // If we have any data without a leading FEND, scan past it
330 let mut i = 0;
331 while i < self.written && self.frame.data[i] != FEND {
332 i += 1;
333 }
334 self.move_to_start(i);
335
336 // If we do have a leading FEND, scan up up to the last one in the series
337 i = 0;
338 while (i + 1) < self.written && self.frame.data[i + 1] == FEND {
339 i += 1;
340 }
341 if i != 0 {
342 self.move_to_start(i);
343 }
344
345 // Now, if we have FEND-something-FEND, return it
346 if self.written >= 2 && self.frame.data[0] == FEND && self.frame.data[1] != FEND {
347 i = 2;
348 while i < self.written && self.frame.data[i] != FEND {
349 i += 1;
350 }
351 if i < self.written && self.frame.data[i] == FEND {
352 self.frame.len = i + 1;
353 self.first_frame_returned = true;
354 return Some(&self.frame);
355 }
356 }
357
358 None
359 }
360
361 /// Check if we just returned a frame; if so, clear it out and position the buffer for the next frame.
362 fn flush_first_frame(&mut self) {
363 if !self.first_frame_returned {
364 return;
365 }
366 self.first_frame_returned = false;
367 // If we have previously returned a valid frame, in the simplest case `frame.data` contains FEND-something-FEND
368 // So to find the trailing FEND we can start at index 2
369 // Loop forward until we find that FEND, which must exist, and leave its index in `i`
370 let mut i = 2;
371 while self.frame.data[i] != FEND {
372 i += 1;
373 }
374 // However if we have consecutive trailing FENDs we want to ignore them
375 // Having found the trailing FEND, increment past any additional FENDs until we reach the end or something else
376 while (i + 1) < self.written && self.frame.data[i + 1] == FEND {
377 i += 1;
378 }
379 // Now take that final FEND and make it the start of our frame
380 self.move_to_start(i);
381 }
382
383 /// Shift all data in the buffer back to the beginning starting from the given index.
384 fn move_to_start(&mut self, idx: usize) {
385 for i in idx..self.written {
386 self.frame.data[i - idx] = self.frame.data[i];
387 }
388 self.written -= idx;
389 }
390 }
391
392 impl Default for KissBuffer {
393 fn default() -> Self {
394 Self::new()
395 }
396 }
397
398 #[derive(Debug, PartialEq, Eq, Clone)]
399 pub enum KissError {
400 MalformedKissFrame,
401 UnsupportedKissCommand,
402 PayloadTooBig,
403 LsfWrongSize,
404 }
405
406 fn escape(src: &[u8], dst: &mut [u8]) -> usize {
407 let mut i = 0;
408 let mut j = 0;
409 while i < src.len() && j < dst.len() {
410 if src[i] == FEND {
411 dst[j] = FESC;
412 j += 1;
413 dst[j] = TFEND;
414 } else if src[i] == FESC {
415 dst[j] = FESC;
416 j += 1;
417 dst[j] = TFESC;
418 } else {
419 dst[j] = src[i];
420 }
421 i += 1;
422 j += 1;
423 }
424 j
425 }
426
427 fn unescape(src: &[u8], dst: &mut [u8]) -> usize {
428 let mut i = 0;
429 let mut j = 0;
430 while i < src.len() && j < dst.len() {
431 if src[i] == FESC {
432 if i == src.len() - 1 {
433 break;
434 }
435 i += 1;
436 if src[i] == TFEND {
437 dst[j] = FEND;
438 } else if src[i] == TFESC {
439 dst[j] = FESC;
440 }
441 } else {
442 dst[j] = src[i];
443 }
444 i += 1;
445 j += 1;
446 }
447 j
448 }
449
450 #[cfg(test)]
451 mod tests {
452 use super::*;
453
454 #[test]
455 fn test_escape() {
456 let mut buf = [0u8; 1024];
457
458 let src = [0, 1, 2, 3, 4, 5];
459 let n = escape(&src, &mut buf);
460 assert_eq!(n, 6);
461 assert_eq!(&buf[0..6], src);
462
463 let src = [0, 1, TFESC, 3, TFEND, 5];
464 let n = escape(&src, &mut buf);
465 assert_eq!(n, 6);
466 assert_eq!(&buf[0..6], src);
467
468 let src = [0, 1, FEND, 3, 4, 5];
469 let n = escape(&src, &mut buf);
470 assert_eq!(n, 7);
471 assert_eq!(&buf[0..7], &[0, 1, FESC, TFEND, 3, 4, 5]);
472
473 let src = [0, 1, 2, 3, 4, FESC];
474 let n = escape(&src, &mut buf);
475 assert_eq!(n, 7);
476 assert_eq!(&buf[0..7], &[0, 1, 2, 3, 4, FESC, TFESC]);
477 }
478
479 #[test]
480 fn test_unescape() {
481 let mut buf = [0u8; 1024];
482
483 let src = [0, 1, 2, 3, 4, 5];
484 let n = unescape(&src, &mut buf);
485 assert_eq!(n, 6);
486 assert_eq!(&buf[0..6], src);
487
488 let src = [0, 1, TFESC, 3, TFEND, 5];
489 let n = unescape(&src, &mut buf);
490 assert_eq!(n, 6);
491 assert_eq!(&buf[0..6], src);
492
493 let src = [0, 1, FESC, TFEND, 3, 4, 5];
494 let n = unescape(&src, &mut buf);
495 assert_eq!(n, 6);
496 assert_eq!(&buf[0..6], &[0, 1, FEND, 3, 4, 5]);
497
498 let src = [0, 1, 2, 3, 4, FESC, TFESC];
499 let n = unescape(&src, &mut buf);
500 assert_eq!(n, 6);
501 assert_eq!(&buf[0..6], &[0, 1, 2, 3, 4, FESC]);
502 }
503
504 #[test]
505 fn basic_packet_roundtrip() {
506 let f = KissFrame::new_basic_packet(&[0, 1, 2, 3]).unwrap();
507 assert_eq!(f.as_bytes(), &[FEND, 0, 0, 1, 2, 3, FEND]);
508 let mut buf = [0u8; 1024];
509 let n = f.decode_payload(&mut buf).unwrap();
510 assert_eq!(&buf[..n], &[0, 1, 2, 3]);
511 }
512
513 #[test]
514 fn test_buffer_basic() {
515 let mut buffer = KissBuffer::new();
516
517 // initial write is not a complete frame
518 let buf = buffer.buf_remaining();
519 buf[0] = FEND;
520 buffer.did_write(1);
521 assert!(buffer.next_frame().is_none());
522
523 // complete the frame
524 let buf = buffer.buf_remaining();
525 buf[0] = 0x10;
526 buf[1] = 0x01;
527 buf[2] = FEND;
528 buffer.did_write(3);
529
530 // everything should parse
531 let next = buffer.next_frame().unwrap();
532 assert_eq!(next.len, 4);
533 assert_eq!(&next.data[0..4], &[FEND, 0x10, 0x01, FEND]);
534 assert_eq!(next.port().unwrap(), 1);
535 assert_eq!(next.command().unwrap(), KissCommand::DataFrame);
536 let mut payload_buf = [0u8; 1024];
537 let n = next.decode_payload(&mut payload_buf).unwrap();
538 assert_eq!(n, 1);
539 assert_eq!(&payload_buf[0..n], &[0x01]);
540 }
541
542 #[test]
543 fn test_buffer_double() {
544 let mut buffer = KissBuffer::new();
545 let buf = buffer.buf_remaining();
546 buf[0..8].copy_from_slice(&[FEND, 0x10, 0x01, FEND, FEND, 0x20, 02, FEND]);
547 buffer.did_write(8);
548
549 let next = buffer.next_frame().unwrap();
550 assert_eq!(next.port().unwrap(), 1);
551 let next = buffer.next_frame().unwrap();
552 assert_eq!(next.port().unwrap(), 2);
553 assert!(buffer.next_frame().is_none());
554 }
555
556 #[test]
557 fn test_buffer_double_shared_fend() {
558 let mut buffer = KissBuffer::new();
559 let buf = buffer.buf_remaining();
560 buf[0..7].copy_from_slice(&[FEND, 0x10, 0x01, FEND, 0x20, 02, FEND]);
561 buffer.did_write(7);
562
563 let next = buffer.next_frame().unwrap();
564 assert_eq!(next.port().unwrap(), 1);
565 let next = buffer.next_frame().unwrap();
566 assert_eq!(next.port().unwrap(), 2);
567 assert!(buffer.next_frame().is_none());
568 }
569
570 #[test]
571 fn test_buffer_extra_fend() {
572 let mut buffer = KissBuffer::new();
573 let buf = buffer.buf_remaining();
574 buf[0..10].copy_from_slice(&[FEND, FEND, FEND, 0x10, 0x01, FEND, FEND, 0x20, 02, FEND]);
575 buffer.did_write(10);
576
577 let next = buffer.next_frame().unwrap();
578 assert_eq!(next.port().unwrap(), 1);
579 let next = buffer.next_frame().unwrap();
580 assert_eq!(next.port().unwrap(), 2);
581 assert!(buffer.next_frame().is_none());
582 }
583
584 #[test]
585 fn test_buffer_oversize_frame() {
586 let mut buffer = KissBuffer::new();
587 let buf = buffer.buf_remaining();
588 buf[0] = FEND;
589 let len = buf.len();
590 assert_eq!(len, MAX_FRAME_LEN);
591 buffer.did_write(len);
592 assert!(buffer.next_frame().is_none());
593
594 let buf = buffer.buf_remaining();
595 let len = buf.len();
596 assert_eq!(len, MAX_FRAME_LEN); // should have flushed
597 for i in 0..len / 2 {
598 buf[i] = 0x00;
599 }
600 buffer.did_write(len / 2);
601 assert!(buffer.next_frame().is_none());
602
603 // confirm we resync if input goes back to normal
604 let buf = buffer.buf_remaining();
605 buf[0..4].copy_from_slice(&[FEND, 0x10, 0x01, FEND]);
606 buffer.did_write(4);
607 let next = buffer.next_frame().unwrap();
608 assert_eq!(next.port().unwrap(), 1);
609 assert!(buffer.next_frame().is_none());
610 }
611 }