]>
code.octet-stream.net Git - m17rt/blob - m17core/src/tnc.rs
1 use crate::address
::{Address
, Callsign
};
3 KissBuffer
, KissCommand
, KissFrame
, PORT_PACKET_BASIC
, PORT_PACKET_FULL
, PORT_STREAM
,
5 use crate::modem
::ModulatorFrame
;
7 Frame
, LichCollection
, LsfFrame
, Mode
, PacketFrame
, PacketFrameCounter
, StreamFrame
,
10 /// Handles the KISS protocol and frame management for `SoftModulator` and `SoftDemodulator`.
12 /// These components work alongside each other. User is responsible for chaining them together
13 /// or doing something else with the data.
15 /// Handle framing of KISS commands from the host, which may arrive in arbitrary binary blobs.
16 kiss_buffer
: KissBuffer
,
18 /// Kiss message that needs to be sent to the host.
19 outgoing_kiss
: Option
<OutgoingKiss
>,
21 /// Current RX or TX function of the TNC.
24 /// Latest state of data carrier detect from demodulator - controls whether we can go to TX
27 /// If CSMA declined to transmit into an idle slot, at what point do we next check it?
28 next_csma_check
: Option
<u64>,
30 /// Current monotonic time, counted in samples
33 // TODO: use a static ring buffer crate of some sort?
34 /// Circular buffer of packets enqueued for transmission
35 packet_queue
: [PendingPacket
; 4],
40 /// Current packet index, which is either partly transmitted or not transmitted at all.
43 /// If true, packet_next == packet_curr implies full queue. packet_next is invalid.
44 /// If false, it implies empty queue.
47 /// The LSF for a stream we are going to start transmitting.
49 /// This serves as a general indicator that we want to tx a stream.
50 stream_pending_lsf
: Option
<LsfFrame
>,
52 /// Circular buffer of stream data enqueued for transmission.
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.
57 /// Overruns are less troublesome - we can drop frames and receiving stations should cope.
58 stream_queue
: [StreamFrame
; 8],
63 /// Current unsent stream frame index
66 /// True if stream_next == stream_curr because the queue is full. stream_next is invalid.
69 /// Should PTT be on right now? Polled by external
72 /// TxDelay raw value, number of 10ms units. We will optimistically start with default 0.
75 /// This is a full duplex channel so we do not need to monitor DCD or use CSMA. Default false.
80 pub fn new() -> Self {
82 kiss_buffer
: KissBuffer
::new(),
86 next_csma_check
: None
,
88 packet_queue
: Default
::default(),
92 stream_pending_lsf
: None
,
93 stream_queue
: Default
::default(),
103 /// Process an individual `Frame` that has been decoded by the modem.
104 pub fn handle_frame(&mut self, frame
: Frame
) {
107 // A new LSF implies a clean slate.
108 // If we were partway through decoding something else then we missed it.
111 self.state
= State
::RxPacket(RxPacketState
{
118 let kiss
= KissFrame
::new_stream_setup(&lsf
.0).unwrap
();
119 self.kiss_to_host(kiss
);
120 self.state
= State
::RxStream(RxStreamState
{ lsf
, index
: 0 });
124 Frame
::Packet(packet
) => {
125 match &mut self.state
{
126 State
::RxPacket(ref mut rx
) => {
127 match packet
.counter
{
128 PacketFrameCounter
::Frame
{ index
} => {
129 if index
== rx
.count
&& index
< 32 {
130 let start
= 25 * index
;
131 rx
.packet
[start
..(start
+ 25)].copy_from_slice(&packet
.payload
);
134 // unexpected order - something has gone wrong
135 self.state
= State
::Idle
;
138 PacketFrameCounter
::FinalFrame
{ payload_len
} => {
139 let start
= 25 * rx
.count
;
140 let end
= start
+ payload_len
;
141 rx
.packet
[start
..(start
+ payload_len
)]
142 .copy_from_slice(&packet
.payload
);
143 // TODO: compatible packets should be sent on port 0 too
145 KissFrame
::new_full_packet(&rx
.lsf
.0, &rx
.packet
[0..end
])
147 self.kiss_to_host(kiss
);
148 self.state
= State
::Idle
;
153 // Invalid transition
154 self.state
= State
::Idle
;
158 Frame
::Stream(stream
) => {
159 match &mut self.state
{
160 State
::RxStream(ref mut rx
) => {
161 // TODO: consider wraparound from 0x7fff
162 if stream
.frame
_n
umber
< rx
.index
{
163 let mut lich
= LichCollection
::new();
164 lich
.set_segment(stream
.lich_idx
, stream
.lich_part
);
165 self.state
= State
::RxAcquiringStream(RxAcquiringStreamState
{ lich
});
167 rx
.index
= stream
.frame
_n
umber
+ 1;
168 let kiss
= KissFrame
::new_stream_data(&stream
).unwrap
();
169 self.kiss_to_host(kiss
);
170 // TODO: end stream if LICH updates indicate non-META part has changed
171 // (this implies a new station)
172 if stream
.end_of_stream
{
173 self.state
= State
::Idle
;
177 State
::RxAcquiringStream(ref mut rx
) => {
178 rx
.lich
.set_segment(stream
.lich_idx
, stream
.lich_part
);
179 if let Some(maybe_lsf
) = rx
.lich
.try_assemble() {
180 let lsf
= LsfFrame(maybe_lsf
);
181 // LICH can change mid-transmission so wait until the CRC is correct
182 // to ensure (to high probability) we haven't done a "torn read"
183 if lsf
.check_crc() == 0 {
184 let kiss
= KissFrame
::new_stream_setup(&lsf
.0).unwrap
();
185 self.kiss_to_host(kiss
);
186 // TODO: avoid discarding the first data payload here
187 // need a queue depth of 2 for outgoing kiss
188 self.state
= State
::RxStream(RxStreamState
{
190 index
: stream
.frame
_n
umber
+ 1,
196 // If coming from another state, we have missed something.
197 // Never mind, let's start tracking LICH.
198 let mut lich
= LichCollection
::new();
199 lich
.set_segment(stream
.lich_idx
, stream
.lich_part
);
200 self.state
= State
::RxAcquiringStream(RxAcquiringStreamState
{ lich
})
207 pub fn set_data_carrier_detect(&mut self, dcd
: bool
) {
211 pub fn set_now(&mut self, now_samples
: u64) {
212 self.now
= now_samples
;
214 State
::TxEndingAtTime(time
) => {
215 if now_samples
>= time
{
217 self.state
= State
::Idle
;
224 pub fn ptt(&self) -> bool
{
228 pub fn set_tx_end_time(&mut self, in_samples
: usize) {
229 log
::debug
!("tnc has been told that tx will complete in {in_samples} samples");
232 self.state
= State
::TxEndingAtTime(self.now
+ in_samples
as u64);
238 pub fn read_tx_frame(&mut self) -> Option
<ModulatorFrame
> {
240 State
::Idle
| State
::RxAcquiringStream(_
) | State
::RxStream(_
) | State
::RxPacket(_
) => {
241 let stream_wants_to_tx
= self.stream_pending_lsf
.is
_some
();
242 let packet_wants_to_tx
= self.packet_full
|| (self.packet_next
!= self.packet_curr
);
243 if !stream_wants_to_tx
&& !packet_wants_to_tx
{
247 // We have something we might send if the channel is free
249 // TODO: Proper full duplex support
250 // A true full duplex TNC should be able to rx and tx concurrently, implying
252 if !self.full
_d
uplex
{
253 match self.next_csma_check
{
256 self.next_csma_check
= Some(self.now
+ 1920);
259 // channel is idle at the moment we get a frame to send
264 if self.now
< at_time
{
267 // 25% chance that we'll transmit this slot.
268 // Using self.now as random is probably fine so long as it's not being set in
269 // a lumpy manner. m17app's soundmodem should be fine.
270 // TODO: bring in prng to help in cases where `now` never ends in 0b11
271 let p1_4
= (self.now
& 3) == 3;
272 if !self.dcd
|| !p1_4
{
273 self.next_csma_check
= Some(self.now
+ 1920);
276 self.next_csma_check
= None
;
282 if stream_wants_to_tx
{
283 self.state
= State
::TxStream
;
285 self.state
= State
::TxPacket
;
288 Some(ModulatorFrame
::Preamble
{
289 tx_delay
: self.tx_delay
,
293 if !self.stream_full
&& self.stream_next
== self.stream_curr
{
296 if let Some(lsf
) = self.stream_pending_lsf
.take() {
297 return Some(ModulatorFrame
::Lsf(lsf
));
299 let frame
= self.stream_queue
[self.stream_curr
].clone();
300 if self.stream_full
{
301 self.stream_full
= false;
303 self.stream_curr
= (self.stream_curr
+ 1) % 8;
304 if frame
.end_of_stream
{
305 self.state
= State
::TxStreamSentEndOfStream
;
307 Some(ModulatorFrame
::Stream(frame
))
309 State
::TxStreamSentEndOfStream
=> {
310 self.state
= State
::TxEnding
;
311 Some(ModulatorFrame
::EndOfTransmission
)
314 if !self.packet_full
&& self.packet_next
== self.packet_curr
{
317 while self.packet_next
!= self.packet_curr
{
318 match self.packet_queue
[self.packet_curr
].next_frame() {
323 self.packet_curr
= (self.packet_curr
+ 1) % 4;
327 self.state
= State
::TxEnding
;
328 Some(ModulatorFrame
::EndOfTransmission
)
330 State
::TxEnding
| State
::TxEndingAtTime(_
) => {
331 // Once we have signalled EOT we withold any new frames until
332 // the channel fully clears and we are ready to TX again
338 /// Read KISS message to be sent to host.
340 /// After each frame input, this should be consumed in a loop until length 0 is returned.
341 /// This component will never block. Upstream interface can provide blocking `read()` if desired.
342 pub fn read_kiss(&mut self, target_buf
: &mut [u8]) -> usize {
343 match self.outgoing_kiss
.as_mut() {
345 let n
= (outgoing
.kiss_frame
.len
- outgoing
.sent
).min(target_buf
.len());
347 .copy_from_slice(&outgoing
.kiss_frame
.data
[outgoing
.sent
..(outgoing
.sent
+ n
)]);
349 if outgoing
.sent
== outgoing
.kiss_frame
.len
{
350 self.outgoing_kiss
= None
;
358 /// Host sends in some KISS data.
359 pub fn write_kiss(&mut self, buf
: &[u8]) -> usize {
360 let target_buf
= self.kiss_buffer
.buf_remaining();
361 let n
= buf
.len().min(target_buf
.len());
362 target_buf
[0..n
].copy_from_slice(&buf
[0..n
]);
363 self.kiss_buffer
.did_write(n
);
364 while let Some(kiss_frame
) = self.kiss_buffer
.next_frame() {
365 let Ok(port
) = kiss_frame
.port() else {
368 let Ok(command
) = kiss_frame
.command() else {
371 if port
!= PORT_PACKET_BASIC
&& port
!= PORT_PACKET_FULL
&& port
!= PORT_STREAM
{
374 if command
== KissCommand
::TxDelay
{
375 let mut new_delay
= [0u8; 1];
376 if kiss_frame
.decode_payload(&mut new_delay
) == Ok(1) {
377 self.tx_delay
= new_delay
[0];
381 if command
== KissCommand
::FullDuplex
{
382 let mut new_duplex
= [0u8; 1];
383 if kiss_frame
.decode_payload(&mut new_duplex
) == Ok(1) {
384 self.full
_d
uplex
= new_duplex
[0] != 0;
388 if command
!= KissCommand
::DataFrame
{
389 // Not supporting any other settings yet
390 // TODO: allow adjusting P persistence parameter for CSMA
393 if port
== PORT_PACKET_BASIC
{
394 if self.packet_full
{
397 let mut pending
= PendingPacket
::new();
398 pending
.app_data
[0] = 0x00; // RAW
399 let Ok(mut len
) = kiss_frame
.decode_payload(&mut pending
.app_data
[1..]) else {
402 len
+= 1; // for RAW prefix
403 let packet_crc
= crate::crc
::m17_crc(&pending
.app_data
[0..len
]);
404 pending
.app_data
[len
..len
+ 2].copy_from_slice(&packet_crc
.to_be_bytes());
405 pending
.app_data_len
= len
+ 2;
406 pending
.lsf
= Some(LsfFrame
::new_packet(
407 &Address
::Callsign(Callsign(b
"M17RT-PKT".clone())),
410 self.packet_queue
[self.packet_next
] = pending
;
411 self.packet_next
= (self.packet_next
+ 1) % 4;
412 if self.packet_next
== self.packet_curr
{
413 self.packet_full
= true;
415 } else if port
== PORT_PACKET_FULL
{
416 if self.packet_full
{
419 let mut pending
= PendingPacket
::new();
420 let mut payload
= [0u8; 855];
421 let Ok(len
) = kiss_frame
.decode_payload(&mut payload
) else {
427 let mut lsf
= LsfFrame([0u8; 30]);
428 lsf
.0.copy_from_slice(&payload
[0..30]);
429 if lsf
.check_crc() != 0 {
432 pending
.lsf
= Some(lsf
);
433 let app_data_len
= len
- 30;
434 pending
.app_data
[0..app_data_len
].copy_from_slice(&payload
[30..]);
435 pending
.app_data_len
= app_data_len
;
436 self.packet_queue
[self.packet_next
] = pending
;
437 self.packet_next
= (self.packet_next
+ 1) % 4;
438 if self.packet_next
== self.packet_curr
{
439 self.packet_full
= true;
441 } else if port
== PORT_STREAM
{
442 let mut payload
= [0u8; 30];
443 let Ok(len
) = kiss_frame
.decode_payload(&mut payload
) else {
447 log
::debug
!("payload len too short");
451 let lsf
= LsfFrame(payload
);
452 if lsf
.check_crc() != 0 {
455 self.stream_pending_lsf
= Some(lsf
);
457 if self.stream_full
{
458 log
::debug
!("stream full");
461 let frame_num_part
= u16::from_be_bytes([payload
[6], payload
[7]]);
462 self.stream_queue
[self.stream_next
] = StreamFrame
{
463 lich_idx
: payload
[5] >> 5,
464 lich_part
: payload
[0..5].try_into().unwrap
(),
465 frame_number
: frame_num_part
& 0x7fff,
466 end_of_stream
: frame_num_part
& 0x8000 > 0,
467 stream_data
: payload
[8..24].try_into().unwrap
(),
469 self.stream_next
= (self.stream_next
+ 1) % 8;
470 if self.stream_next
== self.stream_curr
{
471 self.stream_full
= true;
479 fn kiss_to_host(&mut self, kiss_frame
: KissFrame
) {
480 self.outgoing_kiss
= Some(OutgoingKiss
{
487 #[derive(Debug, PartialEq, Eq, Clone)]
488 pub enum SoftTncError
{
489 General(&'
static str),
493 struct OutgoingKiss
{
494 kiss_frame
: KissFrame
,
499 /// Nothing happening. We may have TX data queued but we won't act on it until CSMA opens up.
502 /// We received some stream data but missed the leading LSF so we are trying to assemble from LICH.
503 RxAcquiringStream(RxAcquiringStreamState
),
505 /// We have acquired an identified stream transmission and are sending data payloads to the host.
506 RxStream(RxStreamState
),
508 /// We are receiving a packet. All is well so far, and there is more data to come before we tell the host.
509 RxPacket(RxPacketState
),
511 /// PTT is on and this is a stream-type transmission. New data may be added.
514 /// We have delivered the last frame in the current stream
515 TxStreamSentEndOfStream
,
517 /// PTT is on and this is a packet-type transmission. New packets may be enqueued.
520 /// We gave modulator an EndOfTransmission. PTT is still on, waiting for modulator to advise end time.
523 /// Ending transmission, PTT remains on, but we know the timestamp at which we should disengage it.
527 struct RxAcquiringStreamState
{
528 /// Partial assembly of LSF by accumulating LICH fields.
529 lich
: LichCollection
,
532 struct RxStreamState
{
533 /// Track identifying information for this transmission so we can tell if it changes.
536 /// Expected next frame number. Allowed to skip values on RX, but not go backwards.
540 struct RxPacketState
{
544 /// Accumulation of packet data that we have received so far.
547 /// Number of payload frames we have received. If we are stably in the RxPacket state,
548 /// this will be between 0 and 32 inclusive.
552 struct PendingPacket
{
553 lsf
: Option
<LsfFrame
>,
557 app_data_transmitted
: usize,
564 app_data
: [0u8; 825],
566 app_data_transmitted
: 0,
570 /// Returns next frame, not including preamble or EOT.
572 /// False means all data frames have been sent.
573 fn next_frame(&mut self) -> Option
<ModulatorFrame
> {
574 if let Some(lsf
) = self.lsf
.take() {
575 return Some(ModulatorFrame
::Lsf(lsf
));
577 if self.app_data_len
== self.app_data_transmitted
{
580 let remaining
= self.app_data_len
- self.app_data_transmitted
;
581 let (counter
, data_len
) = if remaining
<= 25 {
583 PacketFrameCounter
::FinalFrame
{
584 payload_len
: remaining
,
590 PacketFrameCounter
::Frame
{
591 index
: self.app_data_transmitted
/ 25,
596 let mut payload
= [0u8; 25];
597 payload
.copy_from_slice(
598 &self.app_data
[self.app_data_transmitted
..(self.app_data_transmitted
+ data_len
)],
600 self.app_data_transmitted
+= data_len
;
601 Some(ModulatorFrame
::Packet(PacketFrame
{ payload
, counter
}))
605 impl Default
for PendingPacket
{
606 fn default() -> Self {
609 app_data
: [0u8; 825],
611 app_data_transmitted
: 0,
619 use crate::kiss
::{KissCommand
, PORT_STREAM
};
620 use crate::protocol
::StreamFrame
;
622 // TODO: finish all handle_frame tests as below
623 // this will be much more straightforward when we have a way to create LSFs programatically
625 // receiving a single-frame packet
627 // receiving a multi-frame packet
629 // part of one packet and then another
632 fn tnc_receive_stream() {
634 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
635 0, 0, 0, 0, 0, 131, 53,
637 let stream1
= StreamFrame
{
639 lich_part
: [255, 255, 255, 255, 255],
641 end_of_stream
: false,
643 128, 0, 119, 115, 220, 252, 41, 235, 8, 0, 116, 195, 94, 244, 45, 75,
646 let stream2
= StreamFrame
{
648 lich_part
: [255, 0, 0, 0, 159],
652 17, 0, 94, 82, 216, 135, 181, 15, 30, 0, 125, 195, 152, 183, 41, 57,
655 let mut tnc
= SoftTnc
::new();
656 let mut kiss
= KissFrame
::new_empty();
657 assert_eq
!(tnc
.read_kiss(&mut kiss
.data
), 0);
659 tnc
.handle_frame(Frame
::Lsf(lsf
));
660 kiss
.len
= tnc
.read_kiss(&mut kiss
.data
);
661 assert_eq
!(kiss
.command().unwrap
(), KissCommand
::DataFrame
);
662 assert_eq
!(kiss
.port().unwrap
(), PORT_STREAM
);
664 let mut payload_buf
= [0u8; 2048];
665 let n
= kiss
.decode_payload(&mut payload_buf
).unwrap
();
668 tnc
.handle_frame(Frame
::Stream(stream1
));
669 kiss
.len
= tnc
.read_kiss(&mut kiss
.data
);
670 assert_eq
!(kiss
.command().unwrap
(), KissCommand
::DataFrame
);
671 assert_eq
!(kiss
.port().unwrap
(), PORT_STREAM
);
673 let n
= kiss
.decode_payload(&mut payload_buf
).unwrap
();
676 tnc
.handle_frame(Frame
::Stream(stream2
));
677 kiss
.len
= tnc
.read_kiss(&mut kiss
.data
);
678 assert_eq
!(kiss
.command().unwrap
(), KissCommand
::DataFrame
);
679 assert_eq
!(kiss
.port().unwrap
(), PORT_STREAM
);
681 let n
= kiss
.decode_payload(&mut payload_buf
).unwrap
();
686 fn tnc_acquire_stream() {
690 lich_part
: [255, 255, 255, 255, 255],
692 end_of_stream
: false,
694 128, 0, 119, 115, 220, 252, 41, 235, 8, 0, 116, 195, 94, 244, 45, 75,
699 lich_part
: [255, 0, 0, 0, 159],
701 end_of_stream
: false,
703 17, 0, 94, 82, 216, 135, 181, 15, 30, 0, 125, 195, 152, 183, 41, 57,
708 lich_part
: [221, 81, 5, 5, 0],
710 end_of_stream
: false,
712 17, 128, 93, 74, 154, 167, 169, 11, 20, 0, 116, 91, 158, 220, 45, 111,
717 lich_part
: [0, 0, 0, 0, 0],
719 end_of_stream
: false,
721 15, 128, 114, 83, 218, 252, 59, 111, 31, 128, 116, 91, 84, 231, 45, 105,
726 lich_part
: [0, 0, 0, 0, 0],
728 end_of_stream
: false,
730 9, 128, 119, 115, 220, 220, 57, 15, 48, 128, 124, 83, 158, 236, 181, 91,
735 lich_part
: [0, 0, 0, 131, 53],
737 end_of_stream
: false,
739 52, 0, 116, 90, 152, 167, 225, 216, 32, 0, 116, 83, 156, 212, 33, 216,
744 let mut tnc
= SoftTnc
::new();
745 let mut kiss
= KissFrame
::new_empty();
747 tnc
.handle_frame(Frame
::Stream(f
));
749 kiss
.len
= tnc
.read_kiss(&mut kiss
.data
);
750 let mut payload_buf
= [0u8; 2048];
751 let n
= kiss
.decode_payload(&mut payload_buf
).unwrap
();
756 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0,
757 0, 0, 0, 0, 0, 0, 131, 53,
763 fn tnc_handle_skipped_stream_frame() {
765 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
766 0, 0, 0, 0, 0, 131, 53,
768 let stream1
= StreamFrame
{
770 lich_part
: [255, 255, 255, 255, 255],
772 end_of_stream
: false,
774 128, 0, 119, 115, 220, 252, 41, 235, 8, 0, 116, 195, 94, 244, 45, 75,
777 let stream3
= StreamFrame
{
779 lich_part
: [221, 81, 5, 5, 0],
781 end_of_stream
: false,
783 17, 128, 93, 74, 154, 167, 169, 11, 20, 0, 116, 91, 158, 220, 45, 111,
786 let mut tnc
= SoftTnc
::new();
787 let mut kiss
= KissFrame
::new_empty();
788 assert_eq
!(tnc
.read_kiss(&mut kiss
.data
), 0);
790 tnc
.handle_frame(Frame
::Lsf(lsf
));
791 kiss
.len
= tnc
.read_kiss(&mut kiss
.data
);
792 assert_eq
!(kiss
.command().unwrap
(), KissCommand
::DataFrame
);
793 assert_eq
!(kiss
.port().unwrap
(), PORT_STREAM
);
795 let mut payload_buf
= [0u8; 2048];
796 let n
= kiss
.decode_payload(&mut payload_buf
).unwrap
();
799 tnc
.handle_frame(Frame
::Stream(stream1
));
800 kiss
.len
= tnc
.read_kiss(&mut kiss
.data
);
801 assert_eq
!(kiss
.command().unwrap
(), KissCommand
::DataFrame
);
802 assert_eq
!(kiss
.port().unwrap
(), PORT_STREAM
);
804 let n
= kiss
.decode_payload(&mut payload_buf
).unwrap
();
807 tnc
.handle_frame(Frame
::Stream(stream3
));
808 kiss
.len
= tnc
.read_kiss(&mut kiss
.data
);
809 assert_eq
!(kiss
.command().unwrap
(), KissCommand
::DataFrame
);
810 assert_eq
!(kiss
.port().unwrap
(), PORT_STREAM
);
812 let n
= kiss
.decode_payload(&mut payload_buf
).unwrap
();