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