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