]> code.octet-stream.net Git - m17rt/blob - m17core/src/tnc.rs
Sound card input support for demodulation chain
[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) {
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 let kiss = KissFrame::new_stream_setup(&lsf.0).unwrap();
44 self.kiss_to_host(kiss);
45 self.state = State::RxStream(RxStreamState { lsf, index: 0 });
46 }
47 }
48 }
49 Frame::Packet(packet) => {
50 match &mut self.state {
51 State::RxPacket(ref mut rx) => {
52 match packet.counter {
53 PacketFrameCounter::Frame { index } => {
54 if index == rx.count && index < 32 {
55 let start = 25 * index;
56 rx.packet[start..(start + 25)].copy_from_slice(&packet.payload);
57 rx.count += 1;
58 } else {
59 // unexpected order - something has gone wrong
60 self.state = State::Idle;
61 }
62 }
63 PacketFrameCounter::FinalFrame { payload_len } => {
64 let start = 25 * rx.count;
65 let end = start + payload_len;
66 rx.packet[start..(start + payload_len)]
67 .copy_from_slice(&packet.payload);
68 // TODO: compatible packets should be sent on port 0 too
69 let kiss =
70 KissFrame::new_full_packet(&rx.lsf.0, &rx.packet[0..end])
71 .unwrap();
72 self.kiss_to_host(kiss);
73 self.state = State::Idle;
74 }
75 }
76 }
77 _ => {
78 // Invalid transition
79 self.state = State::Idle;
80 }
81 }
82 }
83 Frame::Stream(stream) => {
84 match &mut self.state {
85 State::RxStream(ref mut rx) => {
86 // TODO: consider wraparound from 0x7fff
87 if stream.frame_number < rx.index {
88 let mut lich = LichCollection::new();
89 lich.set_segment(stream.lich_idx, stream.lich_part);
90 self.state = State::RxAcquiringStream(RxAcquiringStreamState { lich });
91 } else {
92 rx.index = stream.frame_number + 1;
93 let kiss = KissFrame::new_stream_data(&stream).unwrap();
94 self.kiss_to_host(kiss);
95 // TODO: end stream if LICH updates indicate non-META part has changed
96 // (this implies a new station)
97 if stream.end_of_stream {
98 self.state = State::Idle;
99 }
100 }
101 }
102 State::RxAcquiringStream(ref mut rx) => {
103 rx.lich.set_segment(stream.lich_idx, stream.lich_part);
104 if let Some(maybe_lsf) = rx.lich.try_assemble() {
105 let lsf = LsfFrame(maybe_lsf);
106 // LICH can change mid-transmission so wait until the CRC is correct
107 // to ensure (to high probability) we haven't done a "torn read"
108 if lsf.crc() == 0 {
109 let kiss = KissFrame::new_stream_setup(&lsf.0).unwrap();
110 self.kiss_to_host(kiss);
111 // TODO: avoid discarding the first data payload here
112 // need a queue depth of 2 for outgoing kiss
113 self.state = State::RxStream(RxStreamState {
114 lsf,
115 index: stream.frame_number + 1,
116 });
117 }
118 }
119 }
120 _ => {
121 // If coming from another state, we have missed something.
122 // Never mind, let's start tracking LICH.
123 let mut lich = LichCollection::new();
124 lich.set_segment(stream.lich_idx, stream.lich_part);
125 self.state = State::RxAcquiringStream(RxAcquiringStreamState { lich })
126 }
127 }
128 }
129 }
130 }
131
132 /// Update the number of samples that have been received by the incoming stream, as a form of timekeeping
133 pub fn advance_samples(&mut self, _samples: u64) {}
134
135 pub fn set_data_carrier_detect(&mut self, _dcd: bool) {}
136
137 pub fn read_tx_frame(&mut self) -> Result<Option<Frame>, SoftTncError> {
138 // yes we want to deal with Frames here
139 // it's important to establish successful decode that SoftDemodulator is aware of the frame innards
140 Ok(None)
141 }
142
143 /// Read KISS message to be sent to host.
144 ///
145 /// After each frame input, this should be consumed in a loop until length 0 is returned.
146 /// This component will never block. Upstream interface can provide blocking `read()` if desired.
147 pub fn read_kiss(&mut self, target_buf: &mut [u8]) -> usize {
148 match self.outgoing_kiss.as_mut() {
149 Some(outgoing) => {
150 let n = (outgoing.kiss_frame.len - outgoing.sent).min(target_buf.len());
151 target_buf[0..n]
152 .copy_from_slice(&outgoing.kiss_frame.data[outgoing.sent..(outgoing.sent + n)]);
153 outgoing.sent += n;
154 if outgoing.sent == outgoing.kiss_frame.len {
155 self.outgoing_kiss = None;
156 }
157 n
158 }
159 None => 0,
160 }
161 }
162
163 pub fn write_kiss(&mut self, buf: &[u8]) -> usize {
164 let target_buf = self.kiss_buffer.buf_remaining();
165 let n = buf.len().min(target_buf.len());
166 target_buf[0..n].copy_from_slice(&buf[0..n]);
167 self.kiss_buffer.did_write(n);
168 while let Some(_kiss_frame) = self.kiss_buffer.next_frame() {
169 // TODO: handle host-to-TNC message
170 }
171 n
172 }
173
174 fn kiss_to_host(&mut self, kiss_frame: KissFrame) {
175 self.outgoing_kiss = Some(OutgoingKiss {
176 kiss_frame,
177 sent: 0,
178 });
179 }
180 }
181
182 #[derive(Debug, PartialEq, Eq, Clone)]
183 pub enum SoftTncError {
184 General(&'static str),
185 InvalidState,
186 }
187
188 struct OutgoingKiss {
189 kiss_frame: KissFrame,
190 sent: usize,
191 }
192
193 enum State {
194 /// Nothing happening.
195 Idle,
196
197 /// We received some stream data but missed the leading LSF so we are trying to assemble from LICH.
198 RxAcquiringStream(RxAcquiringStreamState),
199
200 /// We have acquired an identified stream transmission and are sending data payloads to the host.
201 RxStream(RxStreamState),
202
203 /// We are receiving a packet. All is well so far, and there is more data to come before we tell the host.
204 RxPacket(RxPacketState),
205 // TODO: TX
206 }
207
208 struct RxAcquiringStreamState {
209 /// Partial assembly of LSF by accumulating LICH fields.
210 lich: LichCollection,
211 }
212
213 struct RxStreamState {
214 /// Track identifying information for this transmission so we can tell if it changes.
215 lsf: LsfFrame,
216
217 /// Expected next frame number. Allowed to skip values on RX, but not go backwards.
218 index: u16,
219 }
220
221 struct RxPacketState {
222 /// Initial LSF
223 lsf: LsfFrame,
224
225 /// Accumulation of packet data that we have received so far.
226 packet: [u8; 825],
227
228 /// Number of payload frames we have received. If we are stably in the RxPacket state,
229 /// this will be between 0 and 32 inclusive.
230 count: usize,
231 }
232
233 #[cfg(test)]
234 mod tests {
235 use super::*;
236 use crate::kiss::{KissCommand, PORT_STREAM};
237 use crate::protocol::StreamFrame;
238
239 // TODO: finish all handle_frame tests as below
240 // this will be much more straightforward when we have a way to create LSFs programatically
241
242 // receiving a single-frame packet
243
244 // receiving a multi-frame packet
245
246 // part of one packet and then another
247
248 #[test]
249 fn tnc_receive_stream() {
250 let lsf = LsfFrame([
251 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
252 0, 0, 0, 0, 0, 131, 53,
253 ]);
254 let stream1 = StreamFrame {
255 lich_idx: 0,
256 lich_part: [255, 255, 255, 255, 255],
257 frame_number: 0,
258 end_of_stream: false,
259 stream_data: [
260 128, 0, 119, 115, 220, 252, 41, 235, 8, 0, 116, 195, 94, 244, 45, 75,
261 ],
262 };
263 let stream2 = StreamFrame {
264 lich_idx: 1,
265 lich_part: [255, 0, 0, 0, 159],
266 frame_number: 1,
267 end_of_stream: true,
268 stream_data: [
269 17, 0, 94, 82, 216, 135, 181, 15, 30, 0, 125, 195, 152, 183, 41, 57,
270 ],
271 };
272 let mut tnc = SoftTnc::new();
273 let mut kiss = KissFrame::new_empty();
274 assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
275
276 tnc.handle_frame(Frame::Lsf(lsf));
277 kiss.len = tnc.read_kiss(&mut kiss.data);
278 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
279 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
280
281 let mut payload_buf = [0u8; 2048];
282 let n = kiss.decode_payload(&mut payload_buf).unwrap();
283 assert_eq!(n, 30);
284
285 tnc.handle_frame(Frame::Stream(stream1));
286 kiss.len = tnc.read_kiss(&mut kiss.data);
287 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
288 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
289
290 let n = kiss.decode_payload(&mut payload_buf).unwrap();
291 assert_eq!(n, 26);
292
293 tnc.handle_frame(Frame::Stream(stream2));
294 kiss.len = tnc.read_kiss(&mut kiss.data);
295 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
296 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
297
298 let n = kiss.decode_payload(&mut payload_buf).unwrap();
299 assert_eq!(n, 26);
300 }
301
302 #[test]
303 fn tnc_acquire_stream() {
304 let frames = [
305 StreamFrame {
306 lich_idx: 0,
307 lich_part: [255, 255, 255, 255, 255],
308 frame_number: 0,
309 end_of_stream: false,
310 stream_data: [
311 128, 0, 119, 115, 220, 252, 41, 235, 8, 0, 116, 195, 94, 244, 45, 75,
312 ],
313 },
314 StreamFrame {
315 lich_idx: 1,
316 lich_part: [255, 0, 0, 0, 159],
317 frame_number: 1,
318 end_of_stream: false,
319 stream_data: [
320 17, 0, 94, 82, 216, 135, 181, 15, 30, 0, 125, 195, 152, 183, 41, 57,
321 ],
322 },
323 StreamFrame {
324 lich_idx: 2,
325 lich_part: [221, 81, 5, 5, 0],
326 frame_number: 2,
327 end_of_stream: false,
328 stream_data: [
329 17, 128, 93, 74, 154, 167, 169, 11, 20, 0, 116, 91, 158, 220, 45, 111,
330 ],
331 },
332 StreamFrame {
333 lich_idx: 3,
334 lich_part: [0, 0, 0, 0, 0],
335 frame_number: 3,
336 end_of_stream: false,
337 stream_data: [
338 15, 128, 114, 83, 218, 252, 59, 111, 31, 128, 116, 91, 84, 231, 45, 105,
339 ],
340 },
341 StreamFrame {
342 lich_idx: 4,
343 lich_part: [0, 0, 0, 0, 0],
344 frame_number: 4,
345 end_of_stream: false,
346 stream_data: [
347 9, 128, 119, 115, 220, 220, 57, 15, 48, 128, 124, 83, 158, 236, 181, 91,
348 ],
349 },
350 StreamFrame {
351 lich_idx: 5,
352 lich_part: [0, 0, 0, 131, 53],
353 frame_number: 5,
354 end_of_stream: false,
355 stream_data: [
356 52, 0, 116, 90, 152, 167, 225, 216, 32, 0, 116, 83, 156, 212, 33, 216,
357 ],
358 },
359 ];
360
361 let mut tnc = SoftTnc::new();
362 let mut kiss = KissFrame::new_empty();
363 for f in frames {
364 tnc.handle_frame(Frame::Stream(f));
365 }
366 kiss.len = tnc.read_kiss(&mut kiss.data);
367 let mut payload_buf = [0u8; 2048];
368 let n = kiss.decode_payload(&mut payload_buf).unwrap();
369 assert_eq!(n, 30);
370 assert_eq!(
371 &payload_buf[0..30],
372 [
373 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0,
374 0, 0, 0, 0, 0, 0, 131, 53,
375 ]
376 );
377 }
378
379 #[test]
380 fn tnc_handle_skipped_stream_frame() {
381 let lsf = LsfFrame([
382 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
383 0, 0, 0, 0, 0, 131, 53,
384 ]);
385 let stream1 = StreamFrame {
386 lich_idx: 0,
387 lich_part: [255, 255, 255, 255, 255],
388 frame_number: 0,
389 end_of_stream: false,
390 stream_data: [
391 128, 0, 119, 115, 220, 252, 41, 235, 8, 0, 116, 195, 94, 244, 45, 75,
392 ],
393 };
394 let stream3 = StreamFrame {
395 lich_idx: 2,
396 lich_part: [221, 81, 5, 5, 0],
397 frame_number: 2,
398 end_of_stream: false,
399 stream_data: [
400 17, 128, 93, 74, 154, 167, 169, 11, 20, 0, 116, 91, 158, 220, 45, 111,
401 ],
402 };
403 let mut tnc = SoftTnc::new();
404 let mut kiss = KissFrame::new_empty();
405 assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
406
407 tnc.handle_frame(Frame::Lsf(lsf));
408 kiss.len = tnc.read_kiss(&mut kiss.data);
409 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
410 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
411
412 let mut payload_buf = [0u8; 2048];
413 let n = kiss.decode_payload(&mut payload_buf).unwrap();
414 assert_eq!(n, 30);
415
416 tnc.handle_frame(Frame::Stream(stream1));
417 kiss.len = tnc.read_kiss(&mut kiss.data);
418 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
419 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
420
421 let n = kiss.decode_payload(&mut payload_buf).unwrap();
422 assert_eq!(n, 26);
423
424 tnc.handle_frame(Frame::Stream(stream3));
425 kiss.len = tnc.read_kiss(&mut kiss.data);
426 assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
427 assert_eq!(kiss.port().unwrap(), PORT_STREAM);
428
429 let n = kiss.decode_payload(&mut payload_buf).unwrap();
430 assert_eq!(n, 26);
431 }
432 }