]>
code.octet-stream.net Git - m17rt/blob - m17core/src/tnc.rs
a7cbc53b893dee9c6b18df2b6623678f58c9d3ec
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
;
5 Frame
, LichCollection
, LsfFrame
, Mode
, PacketFrame
, PacketFrameCounter
, StreamFrame
,
8 /// Handles the KISS protocol and frame management for `SoftModulator` and `SoftDemodulator`.
10 /// These components work alongside each other. User is responsible for chaining them together
11 /// or doing something else with the data.
13 /// Handle framing of KISS commands from the host, which may arrive in arbitrary binary blobs.
14 kiss_buffer
: KissBuffer
,
16 /// Kiss message that needs to be sent to the host.
17 outgoing_kiss
: Option
<OutgoingKiss
>,
19 /// Current RX or TX function of the TNC.
22 /// Latest state of data carrier detect from demodulator - controls whether we can go to TX
25 /// If CSMA declined to transmit into an idle slot, at what point do we next check it?
26 next_csma_check
: Option
<u64>,
28 /// Current monotonic time, counted in samples
31 // TODO: use a static ring buffer crate of some sort?
32 /// Circular buffer of packets enqueued for transmission
33 packet_queue
: [PendingPacket
; 4],
38 /// Current packet index, which is either partly transmitted or not transmitted at all.
41 /// If true, packet_next == packet_curr implies full queue. packet_next is invalid.
42 /// If false, it implies empty queue.
45 /// The LSF for a stream we are going to start transmitting.
47 /// This serves as a general indicator that we want to tx a stream.
48 stream_pending_lsf
: Option
<LsfFrame
>,
50 /// Circular buffer of stream data enqueued for transmission.
52 /// When the queue empties out, we hope that the last one has the end-of-stream flag set.
53 /// Otherwise a buffer underrun has occurred.
55 /// Overruns are less troublesome - we can drop frames and receiving stations should cope.
56 stream_queue
: [StreamFrame
; 8],
61 /// Current unsent stream frame index
64 /// True if stream_next == stream_curr because the queue is full. stream_next is invalid.
67 /// Should PTT be on right now? Polled by external
72 pub fn new() -> Self {
74 kiss_buffer
: KissBuffer
::new(),
78 next_csma_check
: None
,
80 packet_queue
: Default
::default(),
84 stream_pending_lsf
: None
,
85 stream_queue
: Default
::default(),
93 /// Process an individual `Frame` that has been decoded by the modem.
94 pub fn handle_frame(&mut self, frame
: Frame
) {
97 // A new LSF implies a clean slate.
98 // If we were partway through decoding something else then we missed it.
101 self.state
= State
::RxPacket(RxPacketState
{
108 let kiss
= KissFrame
::new_stream_setup(&lsf
.0).unwrap
();
109 self.kiss_to_host(kiss
);
110 self.state
= State
::RxStream(RxStreamState
{ lsf
, index
: 0 });
114 Frame
::Packet(packet
) => {
115 match &mut self.state
{
116 State
::RxPacket(ref mut rx
) => {
117 match packet
.counter
{
118 PacketFrameCounter
::Frame
{ index
} => {
119 if index
== rx
.count
&& index
< 32 {
120 let start
= 25 * index
;
121 rx
.packet
[start
..(start
+ 25)].copy_from_slice(&packet
.payload
);
124 // unexpected order - something has gone wrong
125 self.state
= State
::Idle
;
128 PacketFrameCounter
::FinalFrame
{ payload_len
} => {
129 let start
= 25 * rx
.count
;
130 let end
= start
+ payload_len
;
131 rx
.packet
[start
..(start
+ payload_len
)]
132 .copy_from_slice(&packet
.payload
);
133 // TODO: compatible packets should be sent on port 0 too
135 KissFrame
::new_full_packet(&rx
.lsf
.0, &rx
.packet
[0..end
])
137 self.kiss_to_host(kiss
);
138 self.state
= State
::Idle
;
143 // Invalid transition
144 self.state
= State
::Idle
;
148 Frame
::Stream(stream
) => {
149 match &mut self.state
{
150 State
::RxStream(ref mut rx
) => {
151 // TODO: consider wraparound from 0x7fff
152 if stream
.frame
_n
umber
< rx
.index
{
153 let mut lich
= LichCollection
::new();
154 lich
.set_segment(stream
.lich_idx
, stream
.lich_part
);
155 self.state
= State
::RxAcquiringStream(RxAcquiringStreamState
{ lich
});
157 rx
.index
= stream
.frame
_n
umber
+ 1;
158 let kiss
= KissFrame
::new_stream_data(&stream
).unwrap
();
159 self.kiss_to_host(kiss
);
160 // TODO: end stream if LICH updates indicate non-META part has changed
161 // (this implies a new station)
162 if stream
.end_of_stream
{
163 self.state
= State
::Idle
;
167 State
::RxAcquiringStream(ref mut rx
) => {
168 rx
.lich
.set_segment(stream
.lich_idx
, stream
.lich_part
);
169 if let Some(maybe_lsf
) = rx
.lich
.try_assemble() {
170 let lsf
= LsfFrame(maybe_lsf
);
171 // LICH can change mid-transmission so wait until the CRC is correct
172 // to ensure (to high probability) we haven't done a "torn read"
173 if lsf
.check_crc() == 0 {
174 let kiss
= KissFrame
::new_stream_setup(&lsf
.0).unwrap
();
175 self.kiss_to_host(kiss
);
176 // TODO: avoid discarding the first data payload here
177 // need a queue depth of 2 for outgoing kiss
178 self.state
= State
::RxStream(RxStreamState
{
180 index
: stream
.frame
_n
umber
+ 1,
186 // If coming from another state, we have missed something.
187 // Never mind, let's start tracking LICH.
188 let mut lich
= LichCollection
::new();
189 lich
.set_segment(stream
.lich_idx
, stream
.lich_part
);
190 self.state
= State
::RxAcquiringStream(RxAcquiringStreamState
{ lich
})
197 pub fn set_data_carrier_detect(&mut self, dcd
: bool
) {
201 pub fn set_now(&mut self, now_samples
: u64) {
202 self.now
= now_samples
;
204 State
::TxEndingAtTime(time
) => {
205 if now_samples
>= time
{
207 self.state
= State
::Idle
;
214 pub fn ptt(&self) -> bool
{
218 pub fn set_tx_end_time(&mut self, in_samples
: usize) {
219 log
::debug
!("tnc has been told that tx will complete in {in_samples} samples");
222 self.state
= State
::TxEndingAtTime(self.now
+ in_samples
as u64);
228 pub fn read_tx_frame(&mut self) -> Option
<ModulatorFrame
> {
230 State
::Idle
| State
::RxAcquiringStream(_
) | State
::RxStream(_
) | State
::RxPacket(_
) => {
231 let stream_wants_to_tx
= self.stream_pending_lsf
.is
_some
();
232 let packet_wants_to_tx
= self.packet_full
|| (self.packet_next
!= self.packet_curr
);
233 if !stream_wants_to_tx
&& !packet_wants_to_tx
{
237 // We have something we might send if the channel is free
238 match self.next_csma_check
{
241 self.next_csma_check
= Some(self.now
+ 1920);
244 // channel is idle at the moment we get a frame to send
249 if self.now
< at_time
{
252 // 25% chance that we'll transmit this slot.
253 // Using self.now as random is probably fine so long as it's not being set in
254 // a lumpy manner. m17app's soundmodem should be fine.
255 // TODO: bring in prng to help in cases where `now` never ends in 0b11
256 let p1_4
= (self.now
& 3) == 3;
257 if !self.dcd
|| !p1_4
{
258 self.next_csma_check
= Some(self.now
+ 1920);
261 self.next_csma_check
= None
;
266 if stream_wants_to_tx
{
267 self.state
= State
::TxStream
;
269 self.state
= State
::TxPacket
;
272 // TODO: true txdelay
273 Some(ModulatorFrame
::Preamble
{ tx_delay
: 0 })
276 if !self.stream_full
&& self.stream_next
== self.stream_curr
{
279 if let Some(lsf
) = self.stream_pending_lsf
.take() {
280 return Some(ModulatorFrame
::Lsf(lsf
));
282 let frame
= self.stream_queue
[self.stream_curr
].clone();
283 if self.stream_full
{
284 self.stream_full
= false;
286 self.stream_curr
= (self.stream_curr
+ 1) % 8;
287 if frame
.end_of_stream
{
288 self.state
= State
::TxStreamSentEndOfStream
;
290 Some(ModulatorFrame
::Stream(frame
))
292 State
::TxStreamSentEndOfStream
=> {
293 self.state
= State
::TxEnding
;
294 Some(ModulatorFrame
::EndOfTransmission
)
297 if !self.packet_full
&& self.packet_next
== self.packet_curr
{
300 while self.packet_next
!= self.packet_curr
{
301 match self.packet_queue
[self.packet_curr
].next_frame() {
306 self.packet_curr
= (self.packet_curr
+ 1) % 4;
310 self.state
= State
::TxEnding
;
311 Some(ModulatorFrame
::EndOfTransmission
)
313 State
::TxEnding
| State
::TxEndingAtTime(_
) => {
314 // Once we have signalled EOT we withold any new frames until
315 // the channel fully clears and we are ready to TX again
321 /// Read KISS message to be sent to host.
323 /// After each frame input, this should be consumed in a loop until length 0 is returned.
324 /// This component will never block. Upstream interface can provide blocking `read()` if desired.
325 pub fn read_kiss(&mut self, target_buf
: &mut [u8]) -> usize {
326 match self.outgoing_kiss
.as_mut() {
328 let n
= (outgoing
.kiss_frame
.len
- outgoing
.sent
).min(target_buf
.len());
330 .copy_from_slice(&outgoing
.kiss_frame
.data
[outgoing
.sent
..(outgoing
.sent
+ n
)]);
332 if outgoing
.sent
== outgoing
.kiss_frame
.len
{
333 self.outgoing_kiss
= None
;
341 /// Host sends in some KISS data.
342 pub fn write_kiss(&mut self, buf
: &[u8]) -> usize {
343 let target_buf
= self.kiss_buffer
.buf_remaining();
344 let n
= buf
.len().min(target_buf
.len());
345 target_buf
[0..n
].copy_from_slice(&buf
[0..n
]);
346 self.kiss_buffer
.did_write(n
);
347 while let Some(kiss_frame
) = self.kiss_buffer
.next_frame() {
348 let Ok(port
) = kiss_frame
.port() else {
351 if port
== PORT_PACKET_BASIC
{
352 if self.packet_full
{
355 let mut pending
= PendingPacket
::new();
356 pending
.app_data
[0] = 0x00; // RAW
357 let Ok(mut len
) = kiss_frame
.decode_payload(&mut pending
.app_data
[1..]) else {
360 len
+= 1; // for RAW prefix
361 let packet_crc
= crate::crc
::m17_crc(&pending
.app_data
[0..len
]);
362 pending
.app_data
[len
..len
+ 2].copy_from_slice(&packet_crc
.to_be_bytes());
363 pending
.app_data_len
= len
+ 2;
364 pending
.lsf
= Some(LsfFrame
::new_packet(
365 &Address
::Callsign(Callsign(b
"M17RT-PKT".clone())),
368 self.packet_queue
[self.packet_next
] = pending
;
369 self.packet_next
= (self.packet_next
+ 1) % 4;
370 if self.packet_next
== self.packet_curr
{
371 self.packet_full
= true;
373 } else if port
== PORT_PACKET_FULL
{
374 if self.packet_full
{
377 let mut pending
= PendingPacket
::new();
378 let mut payload
= [0u8; 855];
379 let Ok(len
) = kiss_frame
.decode_payload(&mut payload
) else {
385 let mut lsf
= LsfFrame([0u8; 30]);
386 lsf
.0.copy_from_slice(&payload
[0..30]);
387 if lsf
.check_crc() != 0 {
390 pending
.lsf
= Some(lsf
);
391 let app_data_len
= len
- 30;
392 pending
.app_data
[0..app_data_len
].copy_from_slice(&payload
[30..]);
393 pending
.app_data_len
= app_data_len
;
394 self.packet_queue
[self.packet_next
] = pending
;
395 self.packet_next
= (self.packet_next
+ 1) % 4;
396 if self.packet_next
== self.packet_curr
{
397 self.packet_full
= true;
399 } else if port
== PORT_STREAM
{
400 let mut payload
= [0u8; 30];
401 let Ok(len
) = kiss_frame
.decode_payload(&mut payload
) else {
405 log
::debug
!("payload len too short");
409 let lsf
= LsfFrame(payload
);
410 if lsf
.check_crc() != 0 {
413 self.stream_pending_lsf
= Some(lsf
);
415 if self.stream_full
{
416 log
::debug
!("stream full");
419 let frame_num_part
= u16::from_be_bytes([payload
[6], payload
[7]]);
420 self.stream_queue
[self.stream_next
] = StreamFrame
{
421 lich_idx
: payload
[5] >> 5,
422 lich_part
: payload
[0..5].try_into().unwrap
(),
423 frame_number
: frame_num_part
& 0x7fff,
424 end_of_stream
: frame_num_part
& 0x8000 > 0,
425 stream_data
: payload
[8..24].try_into().unwrap
(),
427 self.stream_next
= (self.stream_next
+ 1) % 8;
428 if self.stream_next
== self.stream_curr
{
429 self.stream_full
= true;
437 fn kiss_to_host(&mut self, kiss_frame
: KissFrame
) {
438 self.outgoing_kiss
= Some(OutgoingKiss
{
445 #[derive(Debug, PartialEq, Eq, Clone)]
446 pub enum SoftTncError
{
447 General(&'
static str),
451 struct OutgoingKiss
{
452 kiss_frame
: KissFrame
,
457 /// Nothing happening. We may have TX data queued but we won't act on it until CSMA opens up.
460 /// We received some stream data but missed the leading LSF so we are trying to assemble from LICH.
461 RxAcquiringStream(RxAcquiringStreamState
),
463 /// We have acquired an identified stream transmission and are sending data payloads to the host.
464 RxStream(RxStreamState
),
466 /// We are receiving a packet. All is well so far, and there is more data to come before we tell the host.
467 RxPacket(RxPacketState
),
469 /// PTT is on and this is a stream-type transmission. New data may be added.
472 /// We have delivered the last frame in the current stream
473 TxStreamSentEndOfStream
,
475 /// PTT is on and this is a packet-type transmission. New packets may be enqueued.
478 /// We gave modulator an EndOfTransmission. PTT is still on, waiting for modulator to advise end time.
481 /// Ending transmission, PTT remains on, but we know the timestamp at which we should disengage it.
485 struct RxAcquiringStreamState
{
486 /// Partial assembly of LSF by accumulating LICH fields.
487 lich
: LichCollection
,
490 struct RxStreamState
{
491 /// Track identifying information for this transmission so we can tell if it changes.
494 /// Expected next frame number. Allowed to skip values on RX, but not go backwards.
498 struct RxPacketState
{
502 /// Accumulation of packet data that we have received so far.
505 /// Number of payload frames we have received. If we are stably in the RxPacket state,
506 /// this will be between 0 and 32 inclusive.
510 struct PendingPacket
{
511 lsf
: Option
<LsfFrame
>,
515 app_data_transmitted
: usize,
522 app_data
: [0u8; 825],
524 app_data_transmitted
: 0,
528 /// Returns next frame, not including preamble or EOT.
530 /// False means all data frames have been sent.
531 fn next_frame(&mut self) -> Option
<ModulatorFrame
> {
532 if let Some(lsf
) = self.lsf
.take() {
533 return Some(ModulatorFrame
::Lsf(lsf
));
535 if self.app_data_len
== self.app_data_transmitted
{
538 let remaining
= self.app_data_len
- self.app_data_transmitted
;
539 let (counter
, data_len
) = if remaining
<= 25 {
541 PacketFrameCounter
::FinalFrame
{
542 payload_len
: remaining
,
548 PacketFrameCounter
::Frame
{
549 index
: self.app_data_transmitted
/ 25,
554 let mut payload
= [0u8; 25];
555 payload
.copy_from_slice(
556 &self.app_data
[self.app_data_transmitted
..(self.app_data_transmitted
+ data_len
)],
558 self.app_data_transmitted
+= data_len
;
559 Some(ModulatorFrame
::Packet(PacketFrame
{ payload
, counter
}))
563 impl Default
for PendingPacket
{
564 fn default() -> Self {
567 app_data
: [0u8; 825],
569 app_data_transmitted
: 0,
577 use crate::kiss
::{KissCommand
, PORT_STREAM
};
578 use crate::protocol
::StreamFrame
;
580 // TODO: finish all handle_frame tests as below
581 // this will be much more straightforward when we have a way to create LSFs programatically
583 // receiving a single-frame packet
585 // receiving a multi-frame packet
587 // part of one packet and then another
590 fn tnc_receive_stream() {
592 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
593 0, 0, 0, 0, 0, 131, 53,
595 let stream1
= StreamFrame
{
597 lich_part
: [255, 255, 255, 255, 255],
599 end_of_stream
: false,
601 128, 0, 119, 115, 220, 252, 41, 235, 8, 0, 116, 195, 94, 244, 45, 75,
604 let stream2
= StreamFrame
{
606 lich_part
: [255, 0, 0, 0, 159],
610 17, 0, 94, 82, 216, 135, 181, 15, 30, 0, 125, 195, 152, 183, 41, 57,
613 let mut tnc
= SoftTnc
::new();
614 let mut kiss
= KissFrame
::new_empty();
615 assert_eq
!(tnc
.read_kiss(&mut kiss
.data
), 0);
617 tnc
.handle_frame(Frame
::Lsf(lsf
));
618 kiss
.len
= tnc
.read_kiss(&mut kiss
.data
);
619 assert_eq
!(kiss
.command().unwrap
(), KissCommand
::DataFrame
);
620 assert_eq
!(kiss
.port().unwrap
(), PORT_STREAM
);
622 let mut payload_buf
= [0u8; 2048];
623 let n
= kiss
.decode_payload(&mut payload_buf
).unwrap
();
626 tnc
.handle_frame(Frame
::Stream(stream1
));
627 kiss
.len
= tnc
.read_kiss(&mut kiss
.data
);
628 assert_eq
!(kiss
.command().unwrap
(), KissCommand
::DataFrame
);
629 assert_eq
!(kiss
.port().unwrap
(), PORT_STREAM
);
631 let n
= kiss
.decode_payload(&mut payload_buf
).unwrap
();
634 tnc
.handle_frame(Frame
::Stream(stream2
));
635 kiss
.len
= tnc
.read_kiss(&mut kiss
.data
);
636 assert_eq
!(kiss
.command().unwrap
(), KissCommand
::DataFrame
);
637 assert_eq
!(kiss
.port().unwrap
(), PORT_STREAM
);
639 let n
= kiss
.decode_payload(&mut payload_buf
).unwrap
();
644 fn tnc_acquire_stream() {
648 lich_part
: [255, 255, 255, 255, 255],
650 end_of_stream
: false,
652 128, 0, 119, 115, 220, 252, 41, 235, 8, 0, 116, 195, 94, 244, 45, 75,
657 lich_part
: [255, 0, 0, 0, 159],
659 end_of_stream
: false,
661 17, 0, 94, 82, 216, 135, 181, 15, 30, 0, 125, 195, 152, 183, 41, 57,
666 lich_part
: [221, 81, 5, 5, 0],
668 end_of_stream
: false,
670 17, 128, 93, 74, 154, 167, 169, 11, 20, 0, 116, 91, 158, 220, 45, 111,
675 lich_part
: [0, 0, 0, 0, 0],
677 end_of_stream
: false,
679 15, 128, 114, 83, 218, 252, 59, 111, 31, 128, 116, 91, 84, 231, 45, 105,
684 lich_part
: [0, 0, 0, 0, 0],
686 end_of_stream
: false,
688 9, 128, 119, 115, 220, 220, 57, 15, 48, 128, 124, 83, 158, 236, 181, 91,
693 lich_part
: [0, 0, 0, 131, 53],
695 end_of_stream
: false,
697 52, 0, 116, 90, 152, 167, 225, 216, 32, 0, 116, 83, 156, 212, 33, 216,
702 let mut tnc
= SoftTnc
::new();
703 let mut kiss
= KissFrame
::new_empty();
705 tnc
.handle_frame(Frame
::Stream(f
));
707 kiss
.len
= tnc
.read_kiss(&mut kiss
.data
);
708 let mut payload_buf
= [0u8; 2048];
709 let n
= kiss
.decode_payload(&mut payload_buf
).unwrap
();
714 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0,
715 0, 0, 0, 0, 0, 0, 131, 53,
721 fn tnc_handle_skipped_stream_frame() {
723 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
724 0, 0, 0, 0, 0, 131, 53,
726 let stream1
= StreamFrame
{
728 lich_part
: [255, 255, 255, 255, 255],
730 end_of_stream
: false,
732 128, 0, 119, 115, 220, 252, 41, 235, 8, 0, 116, 195, 94, 244, 45, 75,
735 let stream3
= StreamFrame
{
737 lich_part
: [221, 81, 5, 5, 0],
739 end_of_stream
: false,
741 17, 128, 93, 74, 154, 167, 169, 11, 20, 0, 116, 91, 158, 220, 45, 111,
744 let mut tnc
= SoftTnc
::new();
745 let mut kiss
= KissFrame
::new_empty();
746 assert_eq
!(tnc
.read_kiss(&mut kiss
.data
), 0);
748 tnc
.handle_frame(Frame
::Lsf(lsf
));
749 kiss
.len
= tnc
.read_kiss(&mut kiss
.data
);
750 assert_eq
!(kiss
.command().unwrap
(), KissCommand
::DataFrame
);
751 assert_eq
!(kiss
.port().unwrap
(), PORT_STREAM
);
753 let mut payload_buf
= [0u8; 2048];
754 let n
= kiss
.decode_payload(&mut payload_buf
).unwrap
();
757 tnc
.handle_frame(Frame
::Stream(stream1
));
758 kiss
.len
= tnc
.read_kiss(&mut kiss
.data
);
759 assert_eq
!(kiss
.command().unwrap
(), KissCommand
::DataFrame
);
760 assert_eq
!(kiss
.port().unwrap
(), PORT_STREAM
);
762 let n
= kiss
.decode_payload(&mut payload_buf
).unwrap
();
765 tnc
.handle_frame(Frame
::Stream(stream3
));
766 kiss
.len
= tnc
.read_kiss(&mut kiss
.data
);
767 assert_eq
!(kiss
.command().unwrap
(), KissCommand
::DataFrame
);
768 assert_eq
!(kiss
.port().unwrap
(), PORT_STREAM
);
770 let n
= kiss
.decode_payload(&mut payload_buf
).unwrap
();