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