]> code.octet-stream.net Git - m17rt/blob - m17core/src/tnc.rs
93a4363ae62f0939100ee51a04166fc548595edd
[m17rt] / m17core / src / tnc.rs
1 use crate::address::{Address, Callsign};
2 use crate::kiss::{
3 KissBuffer, KissCommand, KissFrame, PORT_PACKET_BASIC, PORT_PACKET_FULL, PORT_STREAM,
4 };
5 use crate::modem::ModulatorFrame;
6 use crate::protocol::{
7 Frame, LichCollection, LsfFrame, Mode, PacketFrame, PacketFrameCounter, StreamFrame,
8 };
9
10 /// Handles the KISS protocol and frame management for `SoftModulator` and `SoftDemodulator`.
11 ///
12 /// These components work alongside each other. User is responsible for chaining them together
13 /// or doing something else with the data.
14 pub struct SoftTnc {
15 /// Handle framing of KISS commands from the host, which may arrive in arbitrary binary blobs.
16 kiss_buffer: KissBuffer,
17
18 /// Kiss message that needs to be sent to the host.
19 outgoing_kiss: Option<OutgoingKiss>,
20
21 /// Current RX or TX function of the TNC.
22 state: State,
23
24 /// Latest state of data carrier detect from demodulator - controls whether we can go to TX
25 dcd: bool,
26
27 /// If CSMA declined to transmit into an idle slot, at what point do we next check it?
28 next_csma_check: Option<u64>,
29
30 /// Current monotonic time, counted in samples
31 now: u64,
32
33 // TODO: use a static ring buffer crate of some sort?
34 /// Circular buffer of packets enqueued for transmission
35 packet_queue: [PendingPacket; 4],
36
37 /// Next slot to fill
38 packet_next: usize,
39
40 /// Current packet index, which is either partly transmitted or not transmitted at all.
41 packet_curr: usize,
42
43 /// If true, packet_next == packet_curr implies full queue. packet_next is invalid.
44 /// If false, it implies empty queue.
45 packet_full: bool,
46
47 /// The LSF for a stream we are going to start transmitting.
48 ///
49 /// This serves as a general indicator that we want to tx a stream.
50 stream_pending_lsf: Option<LsfFrame>,
51
52 /// Circular buffer of stream data enqueued for transmission.
53 ///
54 /// When the queue empties out, we hope that the last one has the end-of-stream flag set.
55 /// Otherwise a buffer underrun has occurred.
56 ///
57 /// Overruns are less troublesome - we can drop frames and receiving stations should cope.
58 stream_queue: [StreamFrame; 8],
59
60 /// Next slot to fill
61 stream_next: usize,
62
63 /// Current unsent stream frame index
64 stream_curr: usize,
65
66 /// True if stream_next == stream_curr because the queue is full. stream_next is invalid.
67 stream_full: bool,
68
69 /// Should PTT be on right now? Polled by external
70 ptt: bool,
71
72 /// TxDelay raw value, number of 10ms units. We will optimistically start with default 0.
73 tx_delay: u8,
74
75 /// This is a full duplex channel so we do not need to monitor DCD or use CSMA. Default false.
76 full_duplex: bool,
77 }
78
79 impl SoftTnc {
80 pub fn new() -> Self {
81 Self {
82 kiss_buffer: KissBuffer::new(),
83 outgoing_kiss: None,
84 state: State::Idle,
85 dcd: false,
86 next_csma_check: None,
87 now: 0,
88 packet_queue: Default::default(),
89 packet_next: 0,
90 packet_curr: 0,
91 packet_full: false,
92 stream_pending_lsf: None,
93 stream_queue: Default::default(),
94 stream_next: 0,
95 stream_curr: 0,
96 stream_full: false,
97 ptt: false,
98 tx_delay: 0,
99 full_duplex: false,
100 }
101 }
102
103 /// Process an individual `Frame` that has been decoded by the modem.
104 pub fn handle_frame(&mut self, frame: Frame) {
105 match frame {
106 Frame::Lsf(lsf) => {
107 // A new LSF implies a clean slate.
108 // If we were partway through decoding something else then we missed it.
109 match lsf.mode() {
110 Mode::Packet => {
111 self.state = State::RxPacket(RxPacketState {
112 lsf,
113 packet: [0u8; 825],
114 count: 0,
115 })
116 }
117 Mode::Stream => {
118 let kiss = KissFrame::new_stream_setup(&lsf.0).unwrap();
119 self.kiss_to_host(kiss);
120 self.state = State::RxStream(RxStreamState {
121 _lsf: lsf,
122 index: 0,
123 });
124 }
125 }
126 }
127 Frame::Packet(packet) => {
128 match &mut self.state {
129 State::RxPacket(ref mut rx) => {
130 match packet.counter {
131 PacketFrameCounter::Frame { index } => {
132 if index == rx.count && index < 32 {
133 let start = 25 * index;
134 rx.packet[start..(start + 25)].copy_from_slice(&packet.payload);
135 rx.count += 1;
136 } else {
137 // unexpected order - something has gone wrong
138 self.state = State::Idle;
139 }
140 }
141 PacketFrameCounter::FinalFrame { payload_len } => {
142 let start = 25 * rx.count;
143 let end = start + payload_len;
144 rx.packet[start..(start + payload_len)]
145 .copy_from_slice(&packet.payload[0..payload_len]);
146 // TODO: compatible packets should be sent on port 0 too
147 let kiss =
148 KissFrame::new_full_packet(&rx.lsf.0, &rx.packet[0..end])
149 .unwrap();
150 self.kiss_to_host(kiss);
151 self.state = State::Idle;
152 }
153 }
154 }
155 _ => {
156 // Invalid transition
157 self.state = State::Idle;
158 }
159 }
160 }
161 Frame::Stream(stream) => {
162 match &mut self.state {
163 State::RxStream(ref mut rx) => {
164 // TODO: consider wraparound from 0x7fff
165 if stream.frame_number < rx.index {
166 let mut lich = LichCollection::new();
167 lich.set_segment(stream.lich_idx, stream.lich_part);
168 self.state = State::RxAcquiringStream(RxAcquiringStreamState { lich });
169 } else {
170 rx.index = stream.frame_number + 1;
171 let kiss = KissFrame::new_stream_data(&stream).unwrap();
172 self.kiss_to_host(kiss);
173 // TODO: end stream if LICH updates indicate non-META part has changed
174 // (this implies a new station)
175 if stream.end_of_stream {
176 self.state = State::Idle;
177 }
178 }
179 }
180 State::RxAcquiringStream(ref mut rx) => {
181 rx.lich.set_segment(stream.lich_idx, stream.lich_part);
182 if let Some(maybe_lsf) = rx.lich.try_assemble() {
183 let lsf = LsfFrame(maybe_lsf);
184 // LICH can change mid-transmission so wait until the CRC is correct
185 // to ensure (to high probability) we haven't done a "torn read"
186 if lsf.check_crc() == 0 {
187 let kiss = KissFrame::new_stream_setup(&lsf.0).unwrap();
188 self.kiss_to_host(kiss);
189 // TODO: avoid discarding the first data payload here
190 // need a queue depth of 2 for outgoing kiss
191 self.state = State::RxStream(RxStreamState {
192 _lsf: lsf,
193 index: stream.frame_number + 1,
194 });
195 }
196 }
197 }
198 _ => {
199 // If coming from another state, we have missed something.
200 // Never mind, let's start tracking LICH.
201 let mut lich = LichCollection::new();
202 lich.set_segment(stream.lich_idx, stream.lich_part);
203 self.state = State::RxAcquiringStream(RxAcquiringStreamState { lich })
204 }
205 }
206 }
207 }
208 }
209
210 pub fn set_data_carrier_detect(&mut self, dcd: bool) {
211 self.dcd = dcd;
212 }
213
214 pub fn set_now(&mut self, now_samples: u64) {
215 self.now = now_samples;
216 match self.state {
217 State::TxEndingAtTime(time) => {
218 if now_samples >= time {
219 self.ptt = false;
220 self.state = State::Idle;
221 }
222 }
223 _ => (),
224 }
225 }
226
227 pub fn ptt(&self) -> bool {
228 self.ptt
229 }
230
231 pub fn set_tx_end_time(&mut self, in_samples: usize) {
232 log::debug!("tnc has been told that tx will complete in {in_samples} samples");
233 match self.state {
234 State::TxEnding => {
235 self.state = State::TxEndingAtTime(self.now + in_samples as u64);
236 }
237 _ => (),
238 }
239 }
240
241 pub fn read_tx_frame(&mut self) -> Option<ModulatorFrame> {
242 match self.state {
243 State::Idle | State::RxAcquiringStream(_) | State::RxStream(_) | State::RxPacket(_) => {
244 let stream_wants_to_tx = self.stream_pending_lsf.is_some();
245 let packet_wants_to_tx = self.packet_full || (self.packet_next != self.packet_curr);
246 if !stream_wants_to_tx && !packet_wants_to_tx {
247 return None;
248 }
249
250 // We have something we might send if the channel is free
251
252 // TODO: Proper full duplex support
253 // A true full duplex TNC should be able to rx and tx concurrently, implying
254 // separate states.
255 if !self.full_duplex {
256 match self.next_csma_check {
257 None => {
258 if self.dcd {
259 self.next_csma_check = Some(self.now + 1920);
260 return None;
261 } else {
262 // channel is idle at the moment we get a frame to send
263 // go right ahead
264 }
265 }
266 Some(at_time) => {
267 if self.now < at_time {
268 return None;
269 }
270 // 25% chance that we'll transmit this slot.
271 // Using self.now as random is probably fine so long as it's not being set in
272 // a lumpy manner. m17app's soundmodem should be fine.
273 // TODO: bring in prng to help in cases where `now` never ends in 0b11
274 let p1_4 = (self.now & 3) == 3;
275 if !self.dcd || !p1_4 {
276 self.next_csma_check = Some(self.now + 1920);
277 return None;
278 } else {
279 self.next_csma_check = None;
280 }
281 }
282 }
283 }
284
285 if stream_wants_to_tx {
286 self.state = State::TxStream;
287 } else {
288 self.state = State::TxPacket;
289 }
290 self.ptt = true;
291 Some(ModulatorFrame::Preamble {
292 tx_delay: self.tx_delay,
293 })
294 }
295 State::TxStream => {
296 if !self.stream_full && self.stream_next == self.stream_curr {
297 return None;
298 }
299 if let Some(lsf) = self.stream_pending_lsf.take() {
300 return Some(ModulatorFrame::Lsf(lsf));
301 }
302 let frame = self.stream_queue[self.stream_curr].clone();
303 if self.stream_full {
304 self.stream_full = false;
305 }
306 self.stream_curr = (self.stream_curr + 1) % 8;
307 if frame.end_of_stream {
308 self.state = State::TxStreamSentEndOfStream;
309 }
310 Some(ModulatorFrame::Stream(frame))
311 }
312 State::TxStreamSentEndOfStream => {
313 self.state = State::TxEnding;
314 Some(ModulatorFrame::EndOfTransmission)
315 }
316 State::TxPacket => {
317 if !self.packet_full && self.packet_next == self.packet_curr {
318 return None;
319 }
320 while self.packet_next != self.packet_curr {
321 match self.packet_queue[self.packet_curr].next_frame() {
322 Some(frame) => {
323 return Some(frame);
324 }
325 None => {
326 self.packet_curr = (self.packet_curr + 1) % 4;
327 }
328 }
329 }
330 self.state = State::TxEnding;
331 Some(ModulatorFrame::EndOfTransmission)
332 }
333 State::TxEnding | State::TxEndingAtTime(_) => {
334 // Once we have signalled EOT we withold any new frames until
335 // the channel fully clears and we are ready to TX again
336 None
337 }
338 }
339 }
340
341 /// Read KISS message to be sent to host.
342 ///
343 /// After each frame input, this should be consumed in a loop until length 0 is returned.
344 /// This component will never block. Upstream interface can provide blocking `read()` if desired.
345 pub fn read_kiss(&mut self, target_buf: &mut [u8]) -> usize {
346 match self.outgoing_kiss.as_mut() {
347 Some(outgoing) => {
348 let n = (outgoing.kiss_frame.len - outgoing.sent).min(target_buf.len());
349 target_buf[0..n]
350 .copy_from_slice(&outgoing.kiss_frame.data[outgoing.sent..(outgoing.sent + n)]);
351 outgoing.sent += n;
352 if outgoing.sent == outgoing.kiss_frame.len {
353 self.outgoing_kiss = None;
354 }
355 n
356 }
357 None => 0,
358 }
359 }
360
361 /// Host sends in some KISS data.
362 pub fn write_kiss(&mut self, buf: &[u8]) -> usize {
363 let target_buf = self.kiss_buffer.buf_remaining();
364 let n = buf.len().min(target_buf.len());
365 target_buf[0..n].copy_from_slice(&buf[0..n]);
366 self.kiss_buffer.did_write(n);
367 while let Some(kiss_frame) = self.kiss_buffer.next_frame() {
368 let Ok(port) = kiss_frame.port() else {
369 continue;
370 };
371 let Ok(command) = kiss_frame.command() else {
372 continue;
373 };
374 if port != PORT_PACKET_BASIC && port != PORT_PACKET_FULL && port != PORT_STREAM {
375 continue;
376 }
377 if command == KissCommand::TxDelay {
378 let mut new_delay = [0u8; 1];
379 if kiss_frame.decode_payload(&mut new_delay) == Ok(1) {
380 self.tx_delay = new_delay[0];
381 }
382 continue;
383 }
384 if command == KissCommand::FullDuplex {
385 let mut new_duplex = [0u8; 1];
386 if kiss_frame.decode_payload(&mut new_duplex) == Ok(1) {
387 self.full_duplex = new_duplex[0] != 0;
388 }
389 continue;
390 }
391 if command != KissCommand::DataFrame {
392 // Not supporting any other settings yet
393 // TODO: allow adjusting P persistence parameter for CSMA
394 continue;
395 }
396 if port == PORT_PACKET_BASIC {
397 if self.packet_full {
398 continue;
399 }
400 let mut pending = PendingPacket::new();
401 pending.app_data[0] = 0x00; // RAW
402 let Ok(mut len) = kiss_frame.decode_payload(&mut pending.app_data[1..]) else {
403 continue;
404 };
405 len += 1; // for RAW prefix
406 let packet_crc = crate::crc::m17_crc(&pending.app_data[0..len]);
407 pending.app_data[len..len + 2].copy_from_slice(&packet_crc.to_be_bytes());
408 pending.app_data_len = len + 2;
409 pending.lsf = Some(LsfFrame::new_packet(
410 &Address::Callsign(Callsign(b"M17RT-PKT".clone())),
411 &Address::Broadcast,
412 ));
413 self.packet_queue[self.packet_next] = pending;
414 self.packet_next = (self.packet_next + 1) % 4;
415 if self.packet_next == self.packet_curr {
416 self.packet_full = true;
417 }
418 } else if port == PORT_PACKET_FULL {
419 if self.packet_full {
420 continue;
421 }
422 let mut pending = PendingPacket::new();
423 let mut payload = [0u8; 855];
424 let Ok(len) = kiss_frame.decode_payload(&mut payload) else {
425 continue;
426 };
427 if len < 33 {
428 continue;
429 }
430 let mut lsf = LsfFrame([0u8; 30]);
431 lsf.0.copy_from_slice(&payload[0..30]);
432 if lsf.check_crc() != 0 {
433 continue;
434 }
435 pending.lsf = Some(lsf);
436 let app_data_len = len - 30;
437 pending.app_data[0..app_data_len].copy_from_slice(&payload[30..len]);
438 pending.app_data_len = app_data_len;
439 self.packet_queue[self.packet_next] = pending;
440 self.packet_next = (self.packet_next + 1) % 4;
441 if self.packet_next == self.packet_curr {
442 self.packet_full = true;
443 }
444 } else if port == PORT_STREAM {
445 let mut payload = [0u8; 30];
446 let Ok(len) = kiss_frame.decode_payload(&mut payload) else {
447 continue;
448 };
449 if len < 26 {
450 log::debug!("payload len too short");
451 continue;
452 }
453 if len == 30 {
454 let lsf = LsfFrame(payload);
455 if lsf.check_crc() != 0 {
456 continue;
457 }
458 self.stream_pending_lsf = Some(lsf);
459 } else {
460 if self.stream_full {
461 log::debug!("stream full");
462 continue;
463 }
464 let frame_num_part = u16::from_be_bytes([payload[6], payload[7]]);
465 self.stream_queue[self.stream_next] = StreamFrame {
466 lich_idx: payload[5] >> 5,
467 lich_part: payload[0..5].try_into().unwrap(),
468 frame_number: frame_num_part & 0x7fff,
469 end_of_stream: frame_num_part & 0x8000 > 0,
470 stream_data: payload[8..24].try_into().unwrap(),
471 };
472 self.stream_next = (self.stream_next + 1) % 8;
473 if self.stream_next == self.stream_curr {
474 self.stream_full = true;
475 }
476 }
477 }
478 }
479 n
480 }
481
482 fn kiss_to_host(&mut self, kiss_frame: KissFrame) {
483 self.outgoing_kiss = Some(OutgoingKiss {
484 kiss_frame,
485 sent: 0,
486 });
487 }
488 }
489
490 #[derive(Debug, PartialEq, Eq, Clone)]
491 pub enum SoftTncError {
492 General(&'static str),
493 InvalidState,
494 }
495
496 struct OutgoingKiss {
497 kiss_frame: KissFrame,
498 sent: usize,
499 }
500
501 enum State {
502 /// Nothing happening. We may have TX data queued but we won't act on it until CSMA opens up.
503 Idle,
504
505 /// We received some stream data but missed the leading LSF so we are trying to assemble from LICH.
506 RxAcquiringStream(RxAcquiringStreamState),
507
508 /// We have acquired an identified stream transmission and are sending data payloads to the host.
509 RxStream(RxStreamState),
510
511 /// We are receiving a packet. All is well so far, and there is more data to come before we tell the host.
512 RxPacket(RxPacketState),
513
514 /// PTT is on and this is a stream-type transmission. New data may be added.
515 TxStream,
516
517 /// We have delivered the last frame in the current stream
518 TxStreamSentEndOfStream,
519
520 /// PTT is on and this is a packet-type transmission. New packets may be enqueued.
521 TxPacket,
522
523 /// We gave modulator an EndOfTransmission. PTT is still on, waiting for modulator to advise end time.
524 TxEnding,
525
526 /// Ending transmission, PTT remains on, but we know the timestamp at which we should disengage it.
527 TxEndingAtTime(u64),
528 }
529
530 struct RxAcquiringStreamState {
531 /// Partial assembly of LSF by accumulating LICH fields.
532 lich: LichCollection,
533 }
534
535 struct RxStreamState {
536 /// Track identifying information for this transmission so we can tell if it changes.
537 _lsf: LsfFrame,
538
539 /// Expected next frame number. Allowed to skip values on RX, but not go backwards.
540 index: u16,
541 }
542
543 struct RxPacketState {
544 /// Initial LSF
545 lsf: LsfFrame,
546
547 /// Accumulation of packet data that we have received so far.
548 packet: [u8; 825],
549
550 /// Number of payload frames we have received. If we are stably in the RxPacket state,
551 /// this will be between 0 and 32 inclusive.
552 count: usize,
553 }
554
555 struct PendingPacket {
556 lsf: Option<LsfFrame>,
557
558 app_data: [u8; 825],
559 app_data_len: usize,
560 app_data_transmitted: usize,
561 }
562
563 impl PendingPacket {
564 fn new() -> Self {
565 Self {
566 lsf: None,
567 app_data: [0u8; 825],
568 app_data_len: 0,
569 app_data_transmitted: 0,
570 }
571 }
572
573 /// Returns next frame, not including preamble or EOT.
574 ///
575 /// False means all data frames have been sent.
576 fn next_frame(&mut self) -> Option<ModulatorFrame> {
577 if let Some(lsf) = self.lsf.take() {
578 return Some(ModulatorFrame::Lsf(lsf));
579 }
580 if self.app_data_len == self.app_data_transmitted {
581 return None;
582 }
583 let remaining = self.app_data_len - self.app_data_transmitted;
584 let (counter, data_len) = if remaining <= 25 {
585 (
586 PacketFrameCounter::FinalFrame {
587 payload_len: remaining,
588 },
589 remaining,
590 )
591 } else {
592 (
593 PacketFrameCounter::Frame {
594 index: self.app_data_transmitted / 25,
595 },
596 25,
597 )
598 };
599 let mut payload = [0u8; 25];
600 payload[0..data_len].copy_from_slice(
601 &self.app_data[self.app_data_transmitted..(self.app_data_transmitted + data_len)],
602 );
603 self.app_data_transmitted += data_len;
604 Some(ModulatorFrame::Packet(PacketFrame { payload, counter }))
605 }
606 }
607
608 impl Default for PendingPacket {
609 fn default() -> Self {
610 Self {
611 lsf: None,
612 app_data: [0u8; 825],
613 app_data_len: 0,
614 app_data_transmitted: 0,
615 }
616 }
617 }
618
619 #[cfg(test)]
620 mod tests {
621 use super::*;
622 use crate::kiss::{KissCommand, PORT_STREAM};
623 use crate::protocol::StreamFrame;
624
625 // TODO: finish all handle_frame tests as below
626 // this will be much more straightforward when we have a way to create LSFs programatically
627
628 // receiving a single-frame packet
629
630 // receiving a multi-frame packet
631
632 // part of one packet and then another
633
634 #[test]
635 fn tnc_receive_stream() {
636 let lsf = LsfFrame([
637 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
638 0, 0, 0, 0, 0, 131, 53,
639 ]);
640 let stream1 = StreamFrame {
641 lich_idx: 0,
642 lich_part: [255, 255, 255, 255, 255],
643 frame_number: 0,
644 end_of_stream: false,
645 stream_data: [
646 128, 0, 119, 115, 220, 252, 41, 235, 8, 0, 116, 195, 94, 244, 45, 75,
647 ],
648 };
649 let stream2 = StreamFrame {
650 lich_idx: 1,
651 lich_part: [255, 0, 0, 0, 159],
652 frame_number: 1,
653 end_of_stream: true,
654 stream_data: [
655 17, 0, 94, 82, 216, 135, 181, 15, 30, 0, 125, 195, 152, 183, 41, 57,
656 ],
657 };
658 let mut tnc = SoftTnc::new();
659 let mut kiss = KissFrame::new_empty();
660 assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
661
662 tnc.handle_frame(Frame::Lsf(lsf));
663 kiss.len = tnc.read_kiss(&mut kiss.data);
664 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
665 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
666
667 let mut payload_buf = [0u8; 2048];
668 let n = kiss.decode_payload(&mut payload_buf).unwrap();
669 assert_eq!(n, 30);
670
671 tnc.handle_frame(Frame::Stream(stream1));
672 kiss.len = tnc.read_kiss(&mut kiss.data);
673 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
674 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
675
676 let n = kiss.decode_payload(&mut payload_buf).unwrap();
677 assert_eq!(n, 26);
678
679 tnc.handle_frame(Frame::Stream(stream2));
680 kiss.len = tnc.read_kiss(&mut kiss.data);
681 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
682 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
683
684 let n = kiss.decode_payload(&mut payload_buf).unwrap();
685 assert_eq!(n, 26);
686 }
687
688 #[test]
689 fn tnc_acquire_stream() {
690 let frames = [
691 StreamFrame {
692 lich_idx: 0,
693 lich_part: [255, 255, 255, 255, 255],
694 frame_number: 0,
695 end_of_stream: false,
696 stream_data: [
697 128, 0, 119, 115, 220, 252, 41, 235, 8, 0, 116, 195, 94, 244, 45, 75,
698 ],
699 },
700 StreamFrame {
701 lich_idx: 1,
702 lich_part: [255, 0, 0, 0, 159],
703 frame_number: 1,
704 end_of_stream: false,
705 stream_data: [
706 17, 0, 94, 82, 216, 135, 181, 15, 30, 0, 125, 195, 152, 183, 41, 57,
707 ],
708 },
709 StreamFrame {
710 lich_idx: 2,
711 lich_part: [221, 81, 5, 5, 0],
712 frame_number: 2,
713 end_of_stream: false,
714 stream_data: [
715 17, 128, 93, 74, 154, 167, 169, 11, 20, 0, 116, 91, 158, 220, 45, 111,
716 ],
717 },
718 StreamFrame {
719 lich_idx: 3,
720 lich_part: [0, 0, 0, 0, 0],
721 frame_number: 3,
722 end_of_stream: false,
723 stream_data: [
724 15, 128, 114, 83, 218, 252, 59, 111, 31, 128, 116, 91, 84, 231, 45, 105,
725 ],
726 },
727 StreamFrame {
728 lich_idx: 4,
729 lich_part: [0, 0, 0, 0, 0],
730 frame_number: 4,
731 end_of_stream: false,
732 stream_data: [
733 9, 128, 119, 115, 220, 220, 57, 15, 48, 128, 124, 83, 158, 236, 181, 91,
734 ],
735 },
736 StreamFrame {
737 lich_idx: 5,
738 lich_part: [0, 0, 0, 131, 53],
739 frame_number: 5,
740 end_of_stream: false,
741 stream_data: [
742 52, 0, 116, 90, 152, 167, 225, 216, 32, 0, 116, 83, 156, 212, 33, 216,
743 ],
744 },
745 ];
746
747 let mut tnc = SoftTnc::new();
748 let mut kiss = KissFrame::new_empty();
749 for f in frames {
750 tnc.handle_frame(Frame::Stream(f));
751 }
752 kiss.len = tnc.read_kiss(&mut kiss.data);
753 let mut payload_buf = [0u8; 2048];
754 let n = kiss.decode_payload(&mut payload_buf).unwrap();
755 assert_eq!(n, 30);
756 assert_eq!(
757 &payload_buf[0..30],
758 [
759 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0,
760 0, 0, 0, 0, 0, 0, 131, 53,
761 ]
762 );
763 }
764
765 #[test]
766 fn tnc_handle_skipped_stream_frame() {
767 let lsf = LsfFrame([
768 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
769 0, 0, 0, 0, 0, 131, 53,
770 ]);
771 let stream1 = StreamFrame {
772 lich_idx: 0,
773 lich_part: [255, 255, 255, 255, 255],
774 frame_number: 0,
775 end_of_stream: false,
776 stream_data: [
777 128, 0, 119, 115, 220, 252, 41, 235, 8, 0, 116, 195, 94, 244, 45, 75,
778 ],
779 };
780 let stream3 = StreamFrame {
781 lich_idx: 2,
782 lich_part: [221, 81, 5, 5, 0],
783 frame_number: 2,
784 end_of_stream: false,
785 stream_data: [
786 17, 128, 93, 74, 154, 167, 169, 11, 20, 0, 116, 91, 158, 220, 45, 111,
787 ],
788 };
789 let mut tnc = SoftTnc::new();
790 let mut kiss = KissFrame::new_empty();
791 assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
792
793 tnc.handle_frame(Frame::Lsf(lsf));
794 kiss.len = tnc.read_kiss(&mut kiss.data);
795 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
796 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
797
798 let mut payload_buf = [0u8; 2048];
799 let n = kiss.decode_payload(&mut payload_buf).unwrap();
800 assert_eq!(n, 30);
801
802 tnc.handle_frame(Frame::Stream(stream1));
803 kiss.len = tnc.read_kiss(&mut kiss.data);
804 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
805 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
806
807 let n = kiss.decode_payload(&mut payload_buf).unwrap();
808 assert_eq!(n, 26);
809
810 tnc.handle_frame(Frame::Stream(stream3));
811 kiss.len = tnc.read_kiss(&mut kiss.data);
812 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
813 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
814
815 let n = kiss.decode_payload(&mut payload_buf).unwrap();
816 assert_eq!(n, 26);
817 }
818 }