]> code.octet-stream.net Git - m17rt/blob - m17core/src/tnc.rs
More unit tests for TNC rx/assembly - packet mode
[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 // TODO: expose this to higher layer so we can schedule a precise delay
221 // rather than waiting for some soundcard I/O event
222 if let State::TxEndingAtTime(time) = self.state {
223 if now_samples >= time {
224 self.ptt = false;
225 self.state = State::Idle;
226 }
227 }
228 // TODO: should expire packet rx if we have not received a frame for a while
229 // otherwise we could pick up the LSF from one station and FinalFrame from another
230 }
231
232 pub fn ptt(&self) -> bool {
233 self.ptt
234 }
235
236 pub fn set_tx_end_time(&mut self, in_samples: usize) {
237 log::debug!("tnc has been told that tx will complete in {in_samples} samples");
238 if let State::TxEnding = self.state {
239 self.state = State::TxEndingAtTime(self.now + in_samples as u64);
240 }
241 }
242
243 pub fn read_tx_frame(&mut self) -> Option<ModulatorFrame> {
244 match self.state {
245 State::Idle | State::RxAcquiringStream(_) | State::RxStream(_) | State::RxPacket(_) => {
246 let stream_wants_to_tx = self.stream_pending_lsf.is_some();
247 let packet_wants_to_tx = self.packet_full || (self.packet_next != self.packet_curr);
248 if !stream_wants_to_tx && !packet_wants_to_tx {
249 return None;
250 }
251
252 // We have something we might send if the channel is free
253
254 // TODO: Proper full duplex support
255 // A true full duplex TNC should be able to rx and tx concurrently, implying
256 // separate states.
257 if !self.full_duplex {
258 match self.next_csma_check {
259 None => {
260 if self.dcd {
261 self.next_csma_check = Some(self.now + 1920);
262 return None;
263 } else {
264 // channel is idle at the moment we get a frame to send
265 // go right ahead
266 }
267 }
268 Some(at_time) => {
269 if self.now < at_time {
270 return None;
271 }
272 // 25% chance that we'll transmit this slot.
273 // Using self.now as random is probably fine so long as it's not being set in
274 // a lumpy manner. m17app's soundmodem should be fine.
275 // TODO: bring in prng to help in cases where `now` never ends in 0b11
276 let p1_4 = (self.now & 3) == 3;
277 if !self.dcd || !p1_4 {
278 self.next_csma_check = Some(self.now + 1920);
279 return None;
280 } else {
281 self.next_csma_check = None;
282 }
283 }
284 }
285 }
286
287 if stream_wants_to_tx {
288 self.state = State::TxStream;
289 } else {
290 self.state = State::TxPacket;
291 }
292 self.ptt = true;
293 Some(ModulatorFrame::Preamble {
294 tx_delay: self.tx_delay,
295 })
296 }
297 State::TxStream => {
298 if !self.stream_full && self.stream_next == self.stream_curr {
299 return None;
300 }
301 if let Some(lsf) = self.stream_pending_lsf.take() {
302 return Some(ModulatorFrame::Lsf(lsf));
303 }
304 let frame = self.stream_queue[self.stream_curr].clone();
305 if self.stream_full {
306 self.stream_full = false;
307 }
308 self.stream_curr = (self.stream_curr + 1) % 8;
309 if frame.end_of_stream {
310 self.state = State::TxStreamSentEndOfStream;
311 }
312 Some(ModulatorFrame::Stream(frame))
313 }
314 State::TxStreamSentEndOfStream => {
315 self.state = State::TxEnding;
316 Some(ModulatorFrame::EndOfTransmission)
317 }
318 State::TxPacket => {
319 if !self.packet_full && self.packet_next == self.packet_curr {
320 return None;
321 }
322 while self.packet_next != self.packet_curr {
323 match self.packet_queue[self.packet_curr].next_frame() {
324 Some(frame) => {
325 return Some(frame);
326 }
327 None => {
328 self.packet_curr = (self.packet_curr + 1) % 4;
329 }
330 }
331 }
332 self.state = State::TxEnding;
333 Some(ModulatorFrame::EndOfTransmission)
334 }
335 State::TxEnding | State::TxEndingAtTime(_) => {
336 // Once we have signalled EOT we withold any new frames until
337 // the channel fully clears and we are ready to TX again
338 None
339 }
340 }
341 }
342
343 /// Read KISS message to be sent to host.
344 ///
345 /// After each frame input, this should be consumed in a loop until length 0 is returned.
346 /// This component will never block. Upstream interface can provide blocking `read()` if desired.
347 pub fn read_kiss(&mut self, target_buf: &mut [u8]) -> usize {
348 match self.outgoing_kiss.as_mut() {
349 Some(outgoing) => {
350 let n = (outgoing.kiss_frame.len - outgoing.sent).min(target_buf.len());
351 target_buf[0..n]
352 .copy_from_slice(&outgoing.kiss_frame.data[outgoing.sent..(outgoing.sent + n)]);
353 outgoing.sent += n;
354 if outgoing.sent == outgoing.kiss_frame.len {
355 self.outgoing_kiss = None;
356 }
357 n
358 }
359 None => 0,
360 }
361 }
362
363 /// Host sends in some KISS data.
364 pub fn write_kiss(&mut self, buf: &[u8]) -> usize {
365 let target_buf = self.kiss_buffer.buf_remaining();
366 let n = buf.len().min(target_buf.len());
367 target_buf[0..n].copy_from_slice(&buf[0..n]);
368 self.kiss_buffer.did_write(n);
369 while let Some(kiss_frame) = self.kiss_buffer.next_frame() {
370 let Ok(port) = kiss_frame.port() else {
371 continue;
372 };
373 let Ok(command) = kiss_frame.command() else {
374 continue;
375 };
376 if port != PORT_PACKET_BASIC && port != PORT_PACKET_FULL && port != PORT_STREAM {
377 continue;
378 }
379 if command == KissCommand::TxDelay {
380 let mut new_delay = [0u8; 1];
381 if kiss_frame.decode_payload(&mut new_delay) == Ok(1) {
382 self.tx_delay = new_delay[0];
383 }
384 continue;
385 }
386 if command == KissCommand::FullDuplex {
387 let mut new_duplex = [0u8; 1];
388 if kiss_frame.decode_payload(&mut new_duplex) == Ok(1) {
389 self.full_duplex = new_duplex[0] != 0;
390 }
391 continue;
392 }
393 if command != KissCommand::DataFrame {
394 // Not supporting any other settings yet
395 // TODO: allow adjusting P persistence parameter for CSMA
396 continue;
397 }
398 if port == PORT_PACKET_BASIC {
399 if self.packet_full {
400 continue;
401 }
402 let mut pending = PendingPacket::new();
403 pending.app_data[0] = 0x00; // RAW
404 let Ok(mut len) = kiss_frame.decode_payload(&mut pending.app_data[1..]) else {
405 continue;
406 };
407 len += 1; // for RAW prefix
408 let packet_crc = crate::crc::m17_crc(&pending.app_data[0..len]);
409 pending.app_data[len..len + 2].copy_from_slice(&packet_crc.to_be_bytes());
410 pending.app_data_len = len + 2;
411 pending.lsf = Some(LsfFrame::new_packet(
412 &Address::Callsign(Callsign(*b"M17RT-PKT")),
413 &Address::Broadcast,
414 ));
415 self.packet_queue[self.packet_next] = pending;
416 self.packet_next = (self.packet_next + 1) % 4;
417 if self.packet_next == self.packet_curr {
418 self.packet_full = true;
419 }
420 } else if port == PORT_PACKET_FULL {
421 if self.packet_full {
422 continue;
423 }
424 let mut pending = PendingPacket::new();
425 let mut payload = [0u8; 855];
426 let Ok(len) = kiss_frame.decode_payload(&mut payload) else {
427 continue;
428 };
429 if len < 33 {
430 continue;
431 }
432 let mut lsf = LsfFrame([0u8; 30]);
433 lsf.0.copy_from_slice(&payload[0..30]);
434 if lsf.check_crc() != 0 {
435 continue;
436 }
437 pending.lsf = Some(lsf);
438 let app_data_len = len - 30;
439 pending.app_data[0..app_data_len].copy_from_slice(&payload[30..len]);
440 pending.app_data_len = app_data_len;
441 self.packet_queue[self.packet_next] = pending;
442 self.packet_next = (self.packet_next + 1) % 4;
443 if self.packet_next == self.packet_curr {
444 self.packet_full = true;
445 }
446 } else if port == PORT_STREAM {
447 let mut payload = [0u8; 30];
448 let Ok(len) = kiss_frame.decode_payload(&mut payload) else {
449 continue;
450 };
451 if len < 26 {
452 log::debug!("payload len too short");
453 continue;
454 }
455 if len == 30 {
456 let lsf = LsfFrame(payload);
457 if lsf.check_crc() != 0 {
458 continue;
459 }
460 self.stream_pending_lsf = Some(lsf);
461 } else {
462 if self.stream_full {
463 log::debug!("stream full");
464 continue;
465 }
466 let frame_num_part = u16::from_be_bytes([payload[6], payload[7]]);
467 self.stream_queue[self.stream_next] = StreamFrame {
468 lich_idx: payload[5] >> 5,
469 lich_part: payload[0..5].try_into().unwrap(),
470 frame_number: frame_num_part & 0x7fff,
471 end_of_stream: frame_num_part & 0x8000 > 0,
472 stream_data: payload[8..24].try_into().unwrap(),
473 };
474 self.stream_next = (self.stream_next + 1) % 8;
475 if self.stream_next == self.stream_curr {
476 self.stream_full = true;
477 }
478 }
479 }
480 }
481 n
482 }
483
484 fn kiss_to_host(&mut self, kiss_frame: KissFrame) {
485 self.outgoing_kiss = Some(OutgoingKiss {
486 kiss_frame,
487 sent: 0,
488 });
489 }
490 }
491
492 impl Default for SoftTnc {
493 fn default() -> Self {
494 Self::new()
495 }
496 }
497
498 #[derive(Debug, PartialEq, Eq, Clone)]
499 pub enum SoftTncError {
500 General(&'static str),
501 InvalidState,
502 }
503
504 struct OutgoingKiss {
505 kiss_frame: KissFrame,
506 sent: usize,
507 }
508
509 #[allow(clippy::large_enum_variant)]
510 enum State {
511 /// Nothing happening. We may have TX data queued but we won't act on it until CSMA opens up.
512 Idle,
513
514 /// We received some stream data but missed the leading LSF so we are trying to assemble from LICH.
515 RxAcquiringStream(RxAcquiringStreamState),
516
517 /// We have acquired an identified stream transmission and are sending data payloads to the host.
518 RxStream(RxStreamState),
519
520 /// We are receiving a packet. All is well so far, and there is more data to come before we tell the host.
521 RxPacket(RxPacketState),
522
523 /// PTT is on and this is a stream-type transmission. New data may be added.
524 TxStream,
525
526 /// We have delivered the last frame in the current stream
527 TxStreamSentEndOfStream,
528
529 /// PTT is on and this is a packet-type transmission. New packets may be enqueued.
530 TxPacket,
531
532 /// We gave modulator an EndOfTransmission. PTT is still on, waiting for modulator to advise end time.
533 TxEnding,
534
535 /// Ending transmission, PTT remains on, but we know the timestamp at which we should disengage it.
536 TxEndingAtTime(u64),
537 }
538
539 struct RxAcquiringStreamState {
540 /// Partial assembly of LSF by accumulating LICH fields.
541 lich: LichCollection,
542 }
543
544 struct RxStreamState {
545 /// Track identifying information for this transmission so we can tell if it changes.
546 _lsf: LsfFrame,
547
548 /// Expected next frame number. Allowed to skip values on RX, but not go backwards.
549 index: u16,
550 }
551
552 struct RxPacketState {
553 /// Initial LSF
554 lsf: LsfFrame,
555
556 /// Accumulation of packet data that we have received so far.
557 packet: [u8; 825],
558
559 /// Number of payload frames we have received. If we are stably in the RxPacket state,
560 /// this will be between 0 and 32 inclusive.
561 count: usize,
562 }
563
564 struct PendingPacket {
565 lsf: Option<LsfFrame>,
566
567 app_data: [u8; 825],
568 app_data_len: usize,
569 app_data_transmitted: usize,
570 }
571
572 impl PendingPacket {
573 fn new() -> Self {
574 Self {
575 lsf: None,
576 app_data: [0u8; 825],
577 app_data_len: 0,
578 app_data_transmitted: 0,
579 }
580 }
581
582 /// Returns next frame, not including preamble or EOT.
583 ///
584 /// False means all data frames have been sent.
585 fn next_frame(&mut self) -> Option<ModulatorFrame> {
586 if let Some(lsf) = self.lsf.take() {
587 return Some(ModulatorFrame::Lsf(lsf));
588 }
589 if self.app_data_len == self.app_data_transmitted {
590 return None;
591 }
592 let remaining = self.app_data_len - self.app_data_transmitted;
593 let (counter, data_len) = if remaining <= 25 {
594 (
595 PacketFrameCounter::FinalFrame {
596 payload_len: remaining,
597 },
598 remaining,
599 )
600 } else {
601 (
602 PacketFrameCounter::Frame {
603 index: self.app_data_transmitted / 25,
604 },
605 25,
606 )
607 };
608 let mut payload = [0u8; 25];
609 payload[0..data_len].copy_from_slice(
610 &self.app_data[self.app_data_transmitted..(self.app_data_transmitted + data_len)],
611 );
612 self.app_data_transmitted += data_len;
613 Some(ModulatorFrame::Packet(PacketFrame { payload, counter }))
614 }
615 }
616
617 impl Default for PendingPacket {
618 fn default() -> Self {
619 Self {
620 lsf: None,
621 app_data: [0u8; 825],
622 app_data_len: 0,
623 app_data_transmitted: 0,
624 }
625 }
626 }
627
628 #[cfg(test)]
629 mod tests {
630 use super::*;
631 use crate::kiss::{KissCommand, PORT_STREAM};
632 use crate::protocol::{PacketType, StreamFrame};
633
634 #[test]
635 fn tnc_receive_single_frame_packet() {
636 let lsf = LsfFrame::new_packet(
637 &Address::Callsign(Callsign(*b"VK7XT ")),
638 &Address::Broadcast,
639 );
640 let mut payload = [0u8; 25];
641 let (pt, pt_len) = PacketType::Sms.as_proto();
642 payload[0..pt_len].copy_from_slice(&pt[0..pt_len]);
643 payload[pt_len] = 0x41; // a message
644 let crc = crate::crc::m17_crc(&payload[0..=pt_len]).to_be_bytes();
645 payload[pt_len + 1] = crc[0];
646 payload[pt_len + 2] = crc[1];
647
648 let packet = PacketFrame {
649 payload,
650 counter: PacketFrameCounter::FinalFrame {
651 payload_len: pt_len + 3,
652 },
653 };
654 let mut tnc = SoftTnc::new();
655 let mut kiss = KissFrame::new_empty();
656
657 // TNC consumes LSF but has nothing to report yet
658 tnc.handle_frame(Frame::Lsf(lsf));
659 assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
660
661 // TODO: when support is added for the basic packet port they could arrive in either order
662
663 tnc.handle_frame(Frame::Packet(packet));
664 kiss.len = tnc.read_kiss(&mut kiss.data);
665 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
666 assert_eq!(kiss.port().unwrap(), PORT_PACKET_FULL);
667
668 let mut payload_buf = [0u8; 2048];
669 let n = kiss.decode_payload(&mut payload_buf).unwrap();
670 assert_eq!(n, 30 + 1 + pt_len + 2);
671
672 // did we receive our message? (after the LSF)
673 assert_eq!(payload_buf[pt_len + 30], 0x41);
674 }
675
676 #[test]
677 fn tnc_receive_multiple_frame_packet() {
678 let lsf = LsfFrame::new_packet(
679 &Address::Callsign(Callsign(*b"VK7XT ")),
680 &Address::Broadcast,
681 );
682 let mut payload = [0x41u8; 26]; // spans two frames
683 let (pt, pt_len) = PacketType::Sms.as_proto();
684 payload[0..pt_len].copy_from_slice(&pt[0..pt_len]);
685 let crc = crate::crc::m17_crc(&payload[0..24]).to_be_bytes();
686 payload[24] = crc[0];
687 payload[25] = crc[1];
688
689 let packet1 = PacketFrame {
690 payload: payload[0..25].try_into().unwrap(),
691 counter: PacketFrameCounter::Frame { index: 0 },
692 };
693 let mut payload2 = [0u8; 25];
694 payload2[0] = payload[25];
695 let packet2 = PacketFrame {
696 payload: payload2,
697 counter: PacketFrameCounter::FinalFrame { payload_len: 1 },
698 };
699
700 let mut tnc = SoftTnc::new();
701 let mut kiss = KissFrame::new_empty();
702
703 // Nothing to report until second final packet frame received
704 tnc.handle_frame(Frame::Lsf(lsf));
705 assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
706 tnc.handle_frame(Frame::Packet(packet1));
707 assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
708
709 tnc.handle_frame(Frame::Packet(packet2));
710 kiss.len = tnc.read_kiss(&mut kiss.data);
711 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
712 assert_eq!(kiss.port().unwrap(), PORT_PACKET_FULL);
713
714 let mut payload_buf = [0u8; 2048];
715 let n = kiss.decode_payload(&mut payload_buf).unwrap();
716 assert_eq!(n, 30 + 26);
717
718 // did we receive our message? (after the LSF)
719 assert_eq!(payload_buf[pt_len + 30], 0x41);
720 }
721
722 #[test]
723 fn tnc_receive_partial_packet() {
724 let lsf = LsfFrame::new_packet(
725 &Address::Callsign(Callsign(*b"VK7XT ")),
726 &Address::Broadcast,
727 );
728 let mut payload = [0x41u8; 26]; // spans two frames
729 let (pt, pt_len) = PacketType::Sms.as_proto();
730 payload[0..pt_len].copy_from_slice(&pt[0..pt_len]);
731 let crc = crate::crc::m17_crc(&payload[0..24]).to_be_bytes();
732 payload[24] = crc[0];
733 payload[25] = crc[1];
734
735 let packet1 = PacketFrame {
736 payload: payload[0..25].try_into().unwrap(),
737 counter: PacketFrameCounter::Frame { index: 0 },
738 };
739 // final frame of this transmission is dropped
740
741 let lsf2 = LsfFrame::new_packet(
742 &Address::Callsign(Callsign(*b"VK7XT ")),
743 &Address::Broadcast,
744 );
745 let mut payload = [0u8; 25];
746 let (pt, pt_len) = PacketType::Sms.as_proto();
747 payload[0..pt_len].copy_from_slice(&pt[0..pt_len]);
748 payload[pt_len] = 0x42;
749 let crc = crate::crc::m17_crc(&payload[0..=pt_len]).to_be_bytes();
750 payload[pt_len + 1] = crc[0];
751 payload[pt_len + 2] = crc[1];
752
753 let packet2 = PacketFrame {
754 payload: payload[0..25].try_into().unwrap(),
755 counter: PacketFrameCounter::FinalFrame {
756 payload_len: pt_len + 3,
757 },
758 };
759
760 let mut tnc = SoftTnc::new();
761 let mut kiss = KissFrame::new_empty();
762
763 // Nothing to report until second packet received in its entirety
764 tnc.handle_frame(Frame::Lsf(lsf));
765 assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
766 tnc.handle_frame(Frame::Packet(packet1));
767 assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
768 tnc.handle_frame(Frame::Lsf(lsf2));
769 assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
770 tnc.handle_frame(Frame::Packet(packet2));
771
772 kiss.len = tnc.read_kiss(&mut kiss.data);
773 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
774 assert_eq!(kiss.port().unwrap(), PORT_PACKET_FULL);
775
776 let mut payload_buf = [0u8; 2048];
777 let n = kiss.decode_payload(&mut payload_buf).unwrap();
778 assert_eq!(n, 30 + 1 + pt_len + 2);
779 // we have received the second packet which has 0x42 in it
780 assert_eq!(payload_buf[pt_len + 30], 0x42);
781 }
782
783 #[test]
784 fn tnc_receive_stream() {
785 let lsf = LsfFrame([
786 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
787 0, 0, 0, 0, 0, 131, 53,
788 ]);
789 let stream1 = StreamFrame {
790 lich_idx: 0,
791 lich_part: [255, 255, 255, 255, 255],
792 frame_number: 0,
793 end_of_stream: false,
794 stream_data: [
795 128, 0, 119, 115, 220, 252, 41, 235, 8, 0, 116, 195, 94, 244, 45, 75,
796 ],
797 };
798 let stream2 = StreamFrame {
799 lich_idx: 1,
800 lich_part: [255, 0, 0, 0, 159],
801 frame_number: 1,
802 end_of_stream: true,
803 stream_data: [
804 17, 0, 94, 82, 216, 135, 181, 15, 30, 0, 125, 195, 152, 183, 41, 57,
805 ],
806 };
807 let mut tnc = SoftTnc::new();
808 let mut kiss = KissFrame::new_empty();
809 assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
810
811 tnc.handle_frame(Frame::Lsf(lsf));
812 kiss.len = tnc.read_kiss(&mut kiss.data);
813 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
814 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
815
816 let mut payload_buf = [0u8; 2048];
817 let n = kiss.decode_payload(&mut payload_buf).unwrap();
818 assert_eq!(n, 30);
819
820 tnc.handle_frame(Frame::Stream(stream1));
821 kiss.len = tnc.read_kiss(&mut kiss.data);
822 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
823 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
824
825 let n = kiss.decode_payload(&mut payload_buf).unwrap();
826 assert_eq!(n, 26);
827
828 tnc.handle_frame(Frame::Stream(stream2));
829 kiss.len = tnc.read_kiss(&mut kiss.data);
830 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
831 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
832
833 let n = kiss.decode_payload(&mut payload_buf).unwrap();
834 assert_eq!(n, 26);
835 }
836
837 #[test]
838 fn tnc_acquire_stream() {
839 let frames = [
840 StreamFrame {
841 lich_idx: 0,
842 lich_part: [255, 255, 255, 255, 255],
843 frame_number: 0,
844 end_of_stream: false,
845 stream_data: [
846 128, 0, 119, 115, 220, 252, 41, 235, 8, 0, 116, 195, 94, 244, 45, 75,
847 ],
848 },
849 StreamFrame {
850 lich_idx: 1,
851 lich_part: [255, 0, 0, 0, 159],
852 frame_number: 1,
853 end_of_stream: false,
854 stream_data: [
855 17, 0, 94, 82, 216, 135, 181, 15, 30, 0, 125, 195, 152, 183, 41, 57,
856 ],
857 },
858 StreamFrame {
859 lich_idx: 2,
860 lich_part: [221, 81, 5, 5, 0],
861 frame_number: 2,
862 end_of_stream: false,
863 stream_data: [
864 17, 128, 93, 74, 154, 167, 169, 11, 20, 0, 116, 91, 158, 220, 45, 111,
865 ],
866 },
867 StreamFrame {
868 lich_idx: 3,
869 lich_part: [0, 0, 0, 0, 0],
870 frame_number: 3,
871 end_of_stream: false,
872 stream_data: [
873 15, 128, 114, 83, 218, 252, 59, 111, 31, 128, 116, 91, 84, 231, 45, 105,
874 ],
875 },
876 StreamFrame {
877 lich_idx: 4,
878 lich_part: [0, 0, 0, 0, 0],
879 frame_number: 4,
880 end_of_stream: false,
881 stream_data: [
882 9, 128, 119, 115, 220, 220, 57, 15, 48, 128, 124, 83, 158, 236, 181, 91,
883 ],
884 },
885 StreamFrame {
886 lich_idx: 5,
887 lich_part: [0, 0, 0, 131, 53],
888 frame_number: 5,
889 end_of_stream: false,
890 stream_data: [
891 52, 0, 116, 90, 152, 167, 225, 216, 32, 0, 116, 83, 156, 212, 33, 216,
892 ],
893 },
894 ];
895
896 let mut tnc = SoftTnc::new();
897 let mut kiss = KissFrame::new_empty();
898 for f in frames {
899 tnc.handle_frame(Frame::Stream(f));
900 }
901 kiss.len = tnc.read_kiss(&mut kiss.data);
902 let mut payload_buf = [0u8; 2048];
903 let n = kiss.decode_payload(&mut payload_buf).unwrap();
904 assert_eq!(n, 30);
905 assert_eq!(
906 &payload_buf[0..30],
907 [
908 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0,
909 0, 0, 0, 0, 0, 0, 131, 53,
910 ]
911 );
912 }
913
914 #[test]
915 fn tnc_handle_skipped_stream_frame() {
916 let lsf = LsfFrame([
917 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
918 0, 0, 0, 0, 0, 131, 53,
919 ]);
920 let stream1 = StreamFrame {
921 lich_idx: 0,
922 lich_part: [255, 255, 255, 255, 255],
923 frame_number: 0,
924 end_of_stream: false,
925 stream_data: [
926 128, 0, 119, 115, 220, 252, 41, 235, 8, 0, 116, 195, 94, 244, 45, 75,
927 ],
928 };
929 let stream3 = StreamFrame {
930 lich_idx: 2,
931 lich_part: [221, 81, 5, 5, 0],
932 frame_number: 2,
933 end_of_stream: false,
934 stream_data: [
935 17, 128, 93, 74, 154, 167, 169, 11, 20, 0, 116, 91, 158, 220, 45, 111,
936 ],
937 };
938 let mut tnc = SoftTnc::new();
939 let mut kiss = KissFrame::new_empty();
940 assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
941
942 tnc.handle_frame(Frame::Lsf(lsf));
943 kiss.len = tnc.read_kiss(&mut kiss.data);
944 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
945 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
946
947 let mut payload_buf = [0u8; 2048];
948 let n = kiss.decode_payload(&mut payload_buf).unwrap();
949 assert_eq!(n, 30);
950
951 tnc.handle_frame(Frame::Stream(stream1));
952 kiss.len = tnc.read_kiss(&mut kiss.data);
953 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
954 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
955
956 let n = kiss.decode_payload(&mut payload_buf).unwrap();
957 assert_eq!(n, 26);
958
959 tnc.handle_frame(Frame::Stream(stream3));
960 kiss.len = tnc.read_kiss(&mut kiss.data);
961 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
962 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
963
964 let n = kiss.decode_payload(&mut payload_buf).unwrap();
965 assert_eq!(n, 26);
966 }
967 }