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