]> code.octet-stream.net Git - m17rt/blob - m17core/src/tnc.rs
Add metadata to m17rt-mod Cargo.toml
[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 match self.state {
216 State::TxEnding => {
217 self.state = State::TxEndingAtTime(self.now + in_samples as u64);
218 }
219 _ => (),
220 }
221 }
222
223 pub fn read_tx_frame(&mut self) -> Option<ModulatorFrame> {
224 match self.state {
225 State::Idle | State::RxAcquiringStream(_) | State::RxStream(_) | State::RxPacket(_) => {
226 // We will let CSMA decide whether to actually go ahead.
227 // That's not implemented yet, so let's just check DCD.
228 let channel_free = !self.dcd;
229 let stream_wants_to_tx = self.stream_pending_lsf.is_some();
230 let packet_wants_to_tx = self.packet_full || (self.packet_next != self.packet_curr);
231 if channel_free && stream_wants_to_tx {
232 self.state = State::TxStream;
233 } else if channel_free && packet_wants_to_tx {
234 self.state = State::TxPacket;
235 } else {
236 return None;
237 }
238 self.ptt = true;
239 // TODO: true txdelay
240 Some(ModulatorFrame::Preamble { tx_delay: 0 })
241 }
242 State::TxStream => {
243 if !self.stream_full && self.stream_next == self.stream_curr {
244 return None;
245 }
246 if let Some(lsf) = self.stream_pending_lsf.take() {
247 return Some(ModulatorFrame::Lsf(lsf));
248 }
249 let frame = self.stream_queue[self.stream_curr].clone();
250 if self.stream_full {
251 self.stream_full = false;
252 }
253 self.stream_curr = (self.stream_curr + 1) % 8;
254 if frame.end_of_stream {
255 self.state = State::TxStreamSentEndOfStream;
256 }
257 Some(ModulatorFrame::Stream(frame))
258 }
259 State::TxStreamSentEndOfStream => {
260 self.state = State::TxEnding;
261 Some(ModulatorFrame::EndOfTransmission)
262 }
263 State::TxPacket => {
264 if !self.packet_full && self.packet_next == self.packet_curr {
265 return None;
266 }
267 while self.packet_next != self.packet_curr {
268 match self.packet_queue[self.packet_curr].next_frame() {
269 Some(frame) => {
270 return Some(frame);
271 }
272 None => {
273 self.packet_curr = (self.packet_curr + 1) % 4;
274 }
275 }
276 }
277 self.state = State::TxEnding;
278 Some(ModulatorFrame::EndOfTransmission)
279 }
280 State::TxEnding | State::TxEndingAtTime(_) => {
281 // Once we have signalled EOT we withold any new frames until
282 // the channel fully clears and we are ready to TX again
283 None
284 }
285 }
286 }
287
288 /// Read KISS message to be sent to host.
289 ///
290 /// After each frame input, this should be consumed in a loop until length 0 is returned.
291 /// This component will never block. Upstream interface can provide blocking `read()` if desired.
292 pub fn read_kiss(&mut self, target_buf: &mut [u8]) -> usize {
293 match self.outgoing_kiss.as_mut() {
294 Some(outgoing) => {
295 let n = (outgoing.kiss_frame.len - outgoing.sent).min(target_buf.len());
296 target_buf[0..n]
297 .copy_from_slice(&outgoing.kiss_frame.data[outgoing.sent..(outgoing.sent + n)]);
298 outgoing.sent += n;
299 if outgoing.sent == outgoing.kiss_frame.len {
300 self.outgoing_kiss = None;
301 }
302 n
303 }
304 None => 0,
305 }
306 }
307
308 /// Host sends in some KISS data.
309 pub fn write_kiss(&mut self, buf: &[u8]) -> usize {
310 let target_buf = self.kiss_buffer.buf_remaining();
311 let n = buf.len().min(target_buf.len());
312 target_buf[0..n].copy_from_slice(&buf[0..n]);
313 self.kiss_buffer.did_write(n);
314 while let Some(kiss_frame) = self.kiss_buffer.next_frame() {
315 let Ok(port) = kiss_frame.port() else {
316 continue;
317 };
318 if port == PORT_PACKET_BASIC {
319 if self.packet_full {
320 continue;
321 }
322 let mut pending = PendingPacket::new();
323 pending.app_data[0] = 0x00; // RAW
324 let Ok(mut len) = kiss_frame.decode_payload(&mut pending.app_data[1..]) else {
325 continue;
326 };
327 len += 1; // for RAW prefix
328 let packet_crc = crate::crc::m17_crc(&pending.app_data[0..len]);
329 pending.app_data[len..len + 2].copy_from_slice(&packet_crc.to_be_bytes());
330 pending.app_data_len = len + 2;
331 pending.lsf = Some(LsfFrame::new_packet(
332 &Address::Callsign(Callsign(b"M17RT-PKT".clone())),
333 &Address::Broadcast,
334 ));
335 self.packet_queue[self.packet_next] = pending;
336 self.packet_next = (self.packet_next + 1) % 4;
337 if self.packet_next == self.packet_curr {
338 self.packet_full = true;
339 }
340 } else if port == PORT_PACKET_FULL {
341 if self.packet_full {
342 continue;
343 }
344 let mut pending = PendingPacket::new();
345 let mut payload = [0u8; 855];
346 let Ok(len) = kiss_frame.decode_payload(&mut payload) else {
347 continue;
348 };
349 if len < 33 {
350 continue;
351 }
352 let mut lsf = LsfFrame([0u8; 30]);
353 lsf.0.copy_from_slice(&payload[0..30]);
354 if lsf.check_crc() != 0 {
355 continue;
356 }
357 pending.lsf = Some(lsf);
358 let app_data_len = len - 30;
359 pending.app_data[0..app_data_len].copy_from_slice(&payload[30..]);
360 pending.app_data_len = app_data_len;
361 self.packet_queue[self.packet_next] = pending;
362 self.packet_next = (self.packet_next + 1) % 4;
363 if self.packet_next == self.packet_curr {
364 self.packet_full = true;
365 }
366 } else if port == PORT_STREAM {
367 let mut payload = [0u8; 30];
368 let Ok(len) = kiss_frame.decode_payload(&mut payload) else {
369 continue;
370 };
371 if len < 26 {
372 log::debug!("payload len too short");
373 continue;
374 }
375 if len == 30 {
376 let lsf = LsfFrame(payload);
377 if lsf.check_crc() != 0 {
378 continue;
379 }
380 self.stream_pending_lsf = Some(lsf);
381 } else {
382 if self.stream_full {
383 log::debug!("stream full");
384 continue;
385 }
386 let frame_num_part = u16::from_be_bytes([payload[6], payload[7]]);
387 self.stream_queue[self.stream_next] = StreamFrame {
388 lich_idx: payload[5] >> 5,
389 lich_part: payload[0..5].try_into().unwrap(),
390 frame_number: frame_num_part & 0x7fff,
391 end_of_stream: frame_num_part & 0x8000 > 0,
392 stream_data: payload[8..24].try_into().unwrap(),
393 };
394 self.stream_next = (self.stream_next + 1) % 8;
395 if self.stream_next == self.stream_curr {
396 self.stream_full = true;
397 }
398 }
399 }
400 }
401 n
402 }
403
404 fn kiss_to_host(&mut self, kiss_frame: KissFrame) {
405 self.outgoing_kiss = Some(OutgoingKiss {
406 kiss_frame,
407 sent: 0,
408 });
409 }
410 }
411
412 #[derive(Debug, PartialEq, Eq, Clone)]
413 pub enum SoftTncError {
414 General(&'static str),
415 InvalidState,
416 }
417
418 struct OutgoingKiss {
419 kiss_frame: KissFrame,
420 sent: usize,
421 }
422
423 enum State {
424 /// Nothing happening. We may have TX data queued but we won't act on it until CSMA opens up.
425 Idle,
426
427 /// We received some stream data but missed the leading LSF so we are trying to assemble from LICH.
428 RxAcquiringStream(RxAcquiringStreamState),
429
430 /// We have acquired an identified stream transmission and are sending data payloads to the host.
431 RxStream(RxStreamState),
432
433 /// We are receiving a packet. All is well so far, and there is more data to come before we tell the host.
434 RxPacket(RxPacketState),
435
436 /// PTT is on and this is a stream-type transmission. New data may be added.
437 TxStream,
438
439 /// We have delivered the last frame in the current stream
440 TxStreamSentEndOfStream,
441
442 /// PTT is on and this is a packet-type transmission. New packets may be enqueued.
443 TxPacket,
444
445 /// We gave modulator an EndOfTransmission. PTT is still on, waiting for modulator to advise end time.
446 TxEnding,
447
448 /// Ending transmission, PTT remains on, but we know the timestamp at which we should disengage it.
449 TxEndingAtTime(u64),
450 }
451
452 struct RxAcquiringStreamState {
453 /// Partial assembly of LSF by accumulating LICH fields.
454 lich: LichCollection,
455 }
456
457 struct RxStreamState {
458 /// Track identifying information for this transmission so we can tell if it changes.
459 lsf: LsfFrame,
460
461 /// Expected next frame number. Allowed to skip values on RX, but not go backwards.
462 index: u16,
463 }
464
465 struct RxPacketState {
466 /// Initial LSF
467 lsf: LsfFrame,
468
469 /// Accumulation of packet data that we have received so far.
470 packet: [u8; 825],
471
472 /// Number of payload frames we have received. If we are stably in the RxPacket state,
473 /// this will be between 0 and 32 inclusive.
474 count: usize,
475 }
476
477 struct PendingPacket {
478 lsf: Option<LsfFrame>,
479
480 app_data: [u8; 825],
481 app_data_len: usize,
482 app_data_transmitted: usize,
483 }
484
485 impl PendingPacket {
486 fn new() -> Self {
487 Self {
488 lsf: None,
489 app_data: [0u8; 825],
490 app_data_len: 0,
491 app_data_transmitted: 0,
492 }
493 }
494
495 /// Returns next frame, not including preamble or EOT.
496 ///
497 /// False means all data frames have been sent.
498 fn next_frame(&mut self) -> Option<ModulatorFrame> {
499 if let Some(lsf) = self.lsf.take() {
500 return Some(ModulatorFrame::Lsf(lsf));
501 }
502 if self.app_data_len == self.app_data_transmitted {
503 return None;
504 }
505 let remaining = self.app_data_len - self.app_data_transmitted;
506 let (counter, data_len) = if remaining <= 25 {
507 (
508 PacketFrameCounter::FinalFrame {
509 payload_len: remaining,
510 },
511 remaining,
512 )
513 } else {
514 (
515 PacketFrameCounter::Frame {
516 index: self.app_data_transmitted / 25,
517 },
518 25,
519 )
520 };
521 let mut payload = [0u8; 25];
522 payload.copy_from_slice(
523 &self.app_data[self.app_data_transmitted..(self.app_data_transmitted + data_len)],
524 );
525 self.app_data_transmitted += data_len;
526 Some(ModulatorFrame::Packet(PacketFrame { payload, counter }))
527 }
528 }
529
530 impl Default for PendingPacket {
531 fn default() -> Self {
532 Self {
533 lsf: None,
534 app_data: [0u8; 825],
535 app_data_len: 0,
536 app_data_transmitted: 0,
537 }
538 }
539 }
540
541 #[cfg(test)]
542 mod tests {
543 use super::*;
544 use crate::kiss::{KissCommand, PORT_STREAM};
545 use crate::protocol::StreamFrame;
546
547 // TODO: finish all handle_frame tests as below
548 // this will be much more straightforward when we have a way to create LSFs programatically
549
550 // receiving a single-frame packet
551
552 // receiving a multi-frame packet
553
554 // part of one packet and then another
555
556 #[test]
557 fn tnc_receive_stream() {
558 let lsf = LsfFrame([
559 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
560 0, 0, 0, 0, 0, 131, 53,
561 ]);
562 let stream1 = StreamFrame {
563 lich_idx: 0,
564 lich_part: [255, 255, 255, 255, 255],
565 frame_number: 0,
566 end_of_stream: false,
567 stream_data: [
568 128, 0, 119, 115, 220, 252, 41, 235, 8, 0, 116, 195, 94, 244, 45, 75,
569 ],
570 };
571 let stream2 = StreamFrame {
572 lich_idx: 1,
573 lich_part: [255, 0, 0, 0, 159],
574 frame_number: 1,
575 end_of_stream: true,
576 stream_data: [
577 17, 0, 94, 82, 216, 135, 181, 15, 30, 0, 125, 195, 152, 183, 41, 57,
578 ],
579 };
580 let mut tnc = SoftTnc::new();
581 let mut kiss = KissFrame::new_empty();
582 assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
583
584 tnc.handle_frame(Frame::Lsf(lsf));
585 kiss.len = tnc.read_kiss(&mut kiss.data);
586 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
587 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
588
589 let mut payload_buf = [0u8; 2048];
590 let n = kiss.decode_payload(&mut payload_buf).unwrap();
591 assert_eq!(n, 30);
592
593 tnc.handle_frame(Frame::Stream(stream1));
594 kiss.len = tnc.read_kiss(&mut kiss.data);
595 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
596 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
597
598 let n = kiss.decode_payload(&mut payload_buf).unwrap();
599 assert_eq!(n, 26);
600
601 tnc.handle_frame(Frame::Stream(stream2));
602 kiss.len = tnc.read_kiss(&mut kiss.data);
603 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
604 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
605
606 let n = kiss.decode_payload(&mut payload_buf).unwrap();
607 assert_eq!(n, 26);
608 }
609
610 #[test]
611 fn tnc_acquire_stream() {
612 let frames = [
613 StreamFrame {
614 lich_idx: 0,
615 lich_part: [255, 255, 255, 255, 255],
616 frame_number: 0,
617 end_of_stream: false,
618 stream_data: [
619 128, 0, 119, 115, 220, 252, 41, 235, 8, 0, 116, 195, 94, 244, 45, 75,
620 ],
621 },
622 StreamFrame {
623 lich_idx: 1,
624 lich_part: [255, 0, 0, 0, 159],
625 frame_number: 1,
626 end_of_stream: false,
627 stream_data: [
628 17, 0, 94, 82, 216, 135, 181, 15, 30, 0, 125, 195, 152, 183, 41, 57,
629 ],
630 },
631 StreamFrame {
632 lich_idx: 2,
633 lich_part: [221, 81, 5, 5, 0],
634 frame_number: 2,
635 end_of_stream: false,
636 stream_data: [
637 17, 128, 93, 74, 154, 167, 169, 11, 20, 0, 116, 91, 158, 220, 45, 111,
638 ],
639 },
640 StreamFrame {
641 lich_idx: 3,
642 lich_part: [0, 0, 0, 0, 0],
643 frame_number: 3,
644 end_of_stream: false,
645 stream_data: [
646 15, 128, 114, 83, 218, 252, 59, 111, 31, 128, 116, 91, 84, 231, 45, 105,
647 ],
648 },
649 StreamFrame {
650 lich_idx: 4,
651 lich_part: [0, 0, 0, 0, 0],
652 frame_number: 4,
653 end_of_stream: false,
654 stream_data: [
655 9, 128, 119, 115, 220, 220, 57, 15, 48, 128, 124, 83, 158, 236, 181, 91,
656 ],
657 },
658 StreamFrame {
659 lich_idx: 5,
660 lich_part: [0, 0, 0, 131, 53],
661 frame_number: 5,
662 end_of_stream: false,
663 stream_data: [
664 52, 0, 116, 90, 152, 167, 225, 216, 32, 0, 116, 83, 156, 212, 33, 216,
665 ],
666 },
667 ];
668
669 let mut tnc = SoftTnc::new();
670 let mut kiss = KissFrame::new_empty();
671 for f in frames {
672 tnc.handle_frame(Frame::Stream(f));
673 }
674 kiss.len = tnc.read_kiss(&mut kiss.data);
675 let mut payload_buf = [0u8; 2048];
676 let n = kiss.decode_payload(&mut payload_buf).unwrap();
677 assert_eq!(n, 30);
678 assert_eq!(
679 &payload_buf[0..30],
680 [
681 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0,
682 0, 0, 0, 0, 0, 0, 131, 53,
683 ]
684 );
685 }
686
687 #[test]
688 fn tnc_handle_skipped_stream_frame() {
689 let lsf = LsfFrame([
690 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
691 0, 0, 0, 0, 0, 131, 53,
692 ]);
693 let stream1 = StreamFrame {
694 lich_idx: 0,
695 lich_part: [255, 255, 255, 255, 255],
696 frame_number: 0,
697 end_of_stream: false,
698 stream_data: [
699 128, 0, 119, 115, 220, 252, 41, 235, 8, 0, 116, 195, 94, 244, 45, 75,
700 ],
701 };
702 let stream3 = StreamFrame {
703 lich_idx: 2,
704 lich_part: [221, 81, 5, 5, 0],
705 frame_number: 2,
706 end_of_stream: false,
707 stream_data: [
708 17, 128, 93, 74, 154, 167, 169, 11, 20, 0, 116, 91, 158, 220, 45, 111,
709 ],
710 };
711 let mut tnc = SoftTnc::new();
712 let mut kiss = KissFrame::new_empty();
713 assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
714
715 tnc.handle_frame(Frame::Lsf(lsf));
716 kiss.len = tnc.read_kiss(&mut kiss.data);
717 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
718 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
719
720 let mut payload_buf = [0u8; 2048];
721 let n = kiss.decode_payload(&mut payload_buf).unwrap();
722 assert_eq!(n, 30);
723
724 tnc.handle_frame(Frame::Stream(stream1));
725 kiss.len = tnc.read_kiss(&mut kiss.data);
726 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
727 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
728
729 let n = kiss.decode_payload(&mut payload_buf).unwrap();
730 assert_eq!(n, 26);
731
732 tnc.handle_frame(Frame::Stream(stream3));
733 kiss.len = tnc.read_kiss(&mut kiss.data);
734 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
735 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
736
737 let n = kiss.decode_payload(&mut payload_buf).unwrap();
738 assert_eq!(n, 26);
739 }
740 }