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