]> code.octet-stream.net Git - m17rt/blob - m17core/src/tnc.rs
a847683a548d360f3a25f11a912e6e8c2a663018
[m17rt] / m17core / src / tnc.rs
1 use crate::kiss::{KissBuffer, KissFrame};
2 use crate::protocol::{Frame, LichCollection, LsfFrame, Mode, PacketFrameCounter};
3
4 /// Handles the KISS protocol and frame management for `SoftModulator` and `SoftDemodulator`.
5 ///
6 /// These components work alongside each other. User is responsible for chaining them together
7 /// or doing something else with the data.
8 pub struct SoftTnc {
9 /// Handle framing of KISS commands from the host, which may arrive in arbitrary binary blobs.
10 kiss_buffer: KissBuffer,
11
12 /// Kiss message that needs to be sent to the host.
13 outgoing_kiss: Option<OutgoingKiss>,
14
15 /// Current RX or TX function of the TNC.
16 state: State,
17 }
18
19 impl SoftTnc {
20 pub fn new() -> Self {
21 Self {
22 kiss_buffer: KissBuffer::new(),
23 outgoing_kiss: None,
24 state: State::Idle,
25 }
26 }
27
28 /// Process an individual `Frame` that has been decoded by the modem.
29 pub fn handle_frame(&mut self, frame: Frame) -> Result<(), SoftTncError> {
30 match frame {
31 Frame::Lsf(lsf) => {
32 // A new LSF implies a clean slate.
33 // If we were partway through decoding something else then we missed it.
34 match lsf.mode() {
35 Mode::Packet => {
36 self.state = State::RxPacket(RxPacketState {
37 lsf,
38 packet: [0u8; 825],
39 count: 0,
40 })
41 }
42 Mode::Stream => {
43 self.state = State::RxStream(RxStreamState { lsf, index: 0 });
44 }
45 }
46 }
47 Frame::Packet(packet) => {
48 match &mut self.state {
49 State::RxPacket(ref mut rx) => {
50 match packet.counter {
51 PacketFrameCounter::Frame { index } => {
52 if index == rx.count && index < 32 {
53 let start = 25 * index;
54 rx.packet[start..(start + 25)].copy_from_slice(&packet.payload);
55 rx.count += 1;
56 } else {
57 // unexpected order - something has gone wrong
58 self.state = State::Idle;
59 }
60 }
61 PacketFrameCounter::FinalFrame { payload_len } => {
62 let start = 25 * rx.count;
63 let end = start + payload_len;
64 rx.packet[start..(start + payload_len)]
65 .copy_from_slice(&packet.payload);
66 let kiss =
67 KissFrame::new_full_packet(&rx.lsf.0, &rx.packet[0..end])
68 .unwrap();
69 self.kiss_to_host(kiss);
70 self.state = State::Idle;
71 }
72 }
73 }
74 _ => {
75 // Invalid transition
76 self.state = State::Idle;
77 }
78 }
79 }
80 Frame::Stream(stream) => {
81 match &mut self.state {
82 State::RxStream(ref mut rx) => {
83 // TODO: consider wraparound from 0x7fff
84 if stream.frame_number < rx.index {
85 let mut lich = LichCollection::new();
86 lich.set_segment(stream.lich_idx, stream.lich_part);
87 self.state = State::RxAcquiringStream(RxAcquiringStreamState { lich });
88 } else {
89 rx.index = stream.frame_number + 1;
90 let kiss = KissFrame::new_stream_data(&stream.stream_data).unwrap();
91 self.kiss_to_host(kiss);
92 // TODO: handle LICH contents to track META content
93 // TODO: end stream if LICH updates indicate non-META part has changed
94 // (this implies a new station)
95 if stream.end_of_stream {
96 self.state = State::Idle;
97 }
98 }
99 }
100 State::RxAcquiringStream(ref mut rx) => {
101 rx.lich.set_segment(stream.lich_idx, stream.lich_part);
102 if let Some(maybe_lsf) = rx.lich.try_assemble() {
103 let lsf = LsfFrame(maybe_lsf);
104 // LICH can change mid-transmission so wait until the CRC is correct
105 // to ensure (to high probability) we haven't done a "torn read"
106 if lsf.crc() == 0 {
107 let kiss = KissFrame::new_stream_setup(&lsf.0).unwrap();
108 self.kiss_to_host(kiss);
109 // TODO: avoid discarding the first data payload here
110 // need a queue depth of 2 for outgoing kiss
111 self.state = State::RxStream(RxStreamState {
112 lsf,
113 index: stream.frame_number + 1,
114 });
115 }
116 }
117 }
118 _ => {
119 // If coming from another state, we have missed something.
120 // Never mind, let's start tracking LICH.
121 let mut lich = LichCollection::new();
122 lich.set_segment(stream.lich_idx, stream.lich_part);
123 self.state = State::RxAcquiringStream(RxAcquiringStreamState { lich })
124 }
125 }
126 }
127 }
128 Ok(())
129 }
130
131 /// Update the number of samples that have been received by the incoming stream, as a form of timekeeping
132 pub fn advance_samples(&mut self, _samples: u64) {}
133
134 pub fn set_data_carrier_detect(&mut self, _dcd: bool) {}
135
136 pub fn read_tx_frame(&mut self) -> Result<Option<Frame>, SoftTncError> {
137 // yes we want to deal with Frames here
138 // it's important to establish successful decode that SoftDemodulator is aware of the frame innards
139 Ok(None)
140 }
141
142 /// Read KISS message to be sent to host.
143 ///
144 /// After each frame input, this should be consumed in a loop until length 0 is returned.
145 /// This component will never block. Upstream interface can provide blocking `read()` if desired.
146 pub fn read_kiss(&mut self, target_buf: &mut [u8]) -> Result<usize, SoftTncError> {
147 match self.outgoing_kiss.as_mut() {
148 Some(outgoing) => {
149 let n = (outgoing.kiss_frame.len - outgoing.sent).min(target_buf.len());
150 target_buf[0..n]
151 .copy_from_slice(&outgoing.kiss_frame.data[outgoing.sent..(outgoing.sent + n)]);
152 outgoing.sent += n;
153 if outgoing.sent == outgoing.kiss_frame.len {
154 self.outgoing_kiss = None;
155 }
156 Ok(n)
157 }
158 None => Ok(0),
159 }
160 }
161
162 pub fn write_kiss(&mut self, buf: &[u8]) -> Result<usize, SoftTncError> {
163 let target_buf = self.kiss_buffer.buf_remaining();
164 let n = buf.len().min(target_buf.len());
165 target_buf[0..n].copy_from_slice(&buf[0..n]);
166 self.kiss_buffer.did_write(n);
167 while let Some(_kiss_frame) = self.kiss_buffer.next_frame() {
168 // TODO: handle host-to-TNC message
169 }
170 Ok(n)
171 }
172
173 fn kiss_to_host(&mut self, kiss_frame: KissFrame) {
174 self.outgoing_kiss = Some(OutgoingKiss {
175 kiss_frame,
176 sent: 0,
177 });
178 }
179 }
180
181 #[derive(Debug)]
182 pub enum SoftTncError {
183 General(&'static str),
184 InvalidState,
185 }
186
187 struct OutgoingKiss {
188 kiss_frame: KissFrame,
189 sent: usize,
190 }
191
192 enum State {
193 /// Nothing happening.
194 Idle,
195
196 /// We received some stream data but missed the leading LSF so we are trying to assemble from LICH.
197 RxAcquiringStream(RxAcquiringStreamState),
198
199 /// We have acquired an identified stream transmission and are sending data payloads to the host.
200 RxStream(RxStreamState),
201
202 /// We are receiving a packet. All is well so far, and there is more data to come before we tell the host.
203 RxPacket(RxPacketState),
204 // TODO: TX
205 }
206
207 struct RxAcquiringStreamState {
208 /// Partial assembly of LSF by accumulating LICH fields.
209 lich: LichCollection,
210 }
211
212 struct RxStreamState {
213 /// Track identifying information for this transmission so we can tell if it changes.
214 lsf: LsfFrame,
215
216 /// Expected next frame number. Allowed to skip values on RX, but not go backwards.
217 index: u16,
218 }
219
220 struct RxPacketState {
221 /// Initial LSF
222 lsf: LsfFrame,
223
224 /// Accumulation of packet data that we have received so far.
225 packet: [u8; 825],
226
227 /// Number of payload frames we have received. If we are stably in the RxPacket state,
228 /// this will be between 0 and 32 inclusive.
229 count: usize,
230 }