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