]> code.octet-stream.net Git - m17rt/commitdiff
Modem support for parsing packet frames
authorThomas Karpiniec <tom.karpiniec@outlook.com>
Mon, 6 Jan 2025 10:14:16 +0000 (21:14 +1100)
committerThomas Karpiniec <tom.karpiniec@outlook.com>
Mon, 6 Jan 2025 10:14:16 +0000 (21:14 +1100)
m17app/src/adapter.rs
m17app/src/tnc.rs
m17core/src/decode.rs
m17core/src/fec.rs
m17core/src/modem.rs

index 5fb6258a8e0e224a895e4f170867f36f78e0264c..a03cf09c901ab5c7ba009a7797c2ca01b73b6982 100644 (file)
@@ -23,4 +23,6 @@ pub trait StreamAdapter: Send + Sync + 'static {
     // fn stream_assembled_text_block()
     // fn stream_gnss_data()
     // fn stream_extended_callsign_data()
     // fn stream_assembled_text_block()
     // fn stream_gnss_data()
     // fn stream_extended_callsign_data()
+
+    // fn stream_tx_ended_early(&self); // underrun/overrun
 }
 }
index 921585b7a92ef1ce935bdba3405caf78564739f1..e7799b4843cb713fd819e1390110dc8a9030b81c 100644 (file)
@@ -6,8 +6,20 @@ use std::io::{Read, Write};
 /// via a working implementation of try_clone(). We do not require `Clone` directly
 /// as this could not be fulfilled by `TcpStream`.
 pub trait Tnc: Read + Write + Sized + Send + 'static {
 /// via a working implementation of try_clone(). We do not require `Clone` directly
 /// as this could not be fulfilled by `TcpStream`.
 pub trait Tnc: Read + Write + Sized + Send + 'static {
+    /// Return a copy of this TNC.
+    ///
+    /// `M17App` will use this to create a second instance of the supplied TNC then use
+    /// one of them for reading and one of them for writing, concurrently across two threads.
+    ///
+    /// Implementations do not need to worry about trying to make two simultaneous reads or
+    /// two simultaneous writes do something sensible. `M17App` will not do this and it would
+    /// probably produce garbled KISS messages anyway.
     fn try_clone(&mut self) -> Result<Self, TncError>;
     fn try_clone(&mut self) -> Result<Self, TncError>;
+
+    /// Start I/O.
     fn start(&mut self) -> Result<(), TncError>;
     fn start(&mut self) -> Result<(), TncError>;
+
+    /// Shut down I/O - it is assumed we cannot restart.
     fn close(&mut self) -> Result<(), TncError>;
 }
 
     fn close(&mut self) -> Result<(), TncError>;
 }
 
index 60c210e3d2686950f2b4bcb424e8c2d817caabb7..ba21a27c1522febbd924bca9404afa7d42e8cb13 100755 (executable)
@@ -1,8 +1,11 @@
 use crate::{
     bits::BitsMut,
 use crate::{
     bits::BitsMut,
-    fec::{self, p_1, p_2},
+    fec::{self, p_1, p_2, p_3},
     interleave::interleave,
     interleave::interleave,
-    protocol::{LsfFrame, StreamFrame, BERT_SYNC, LSF_SYNC, PACKET_SYNC, STREAM_SYNC},
+    protocol::{
+        LsfFrame, PacketFrame, PacketFrameCounter, StreamFrame, BERT_SYNC, LSF_SYNC, PACKET_SYNC,
+        STREAM_SYNC,
+    },
     random::random_xor,
 };
 use log::debug;
     random::random_xor,
 };
 use log::debug;
@@ -141,3 +144,26 @@ pub(crate) fn parse_stream(frame: &[f32] /* length 192 */) -> Option<StreamFrame
         None
     }
 }
         None
     }
 }
+
+pub(crate) fn parse_packet(frame: &[f32] /* length 192 */) -> Option<PacketFrame> {
+    let deinterleaved = frame_initial_decode(frame);
+    let packet = match fec::decode(&deinterleaved, 206, p_3) {
+        Some(packet) => packet,
+        None => return None,
+    };
+    let final_frame = (packet[25] & 0x80) > 0;
+    let number = (packet[25] >> 2) & 0x01f;
+    let counter = if final_frame {
+        PacketFrameCounter::FinalFrame {
+            payload_len: number as usize,
+        }
+    } else {
+        PacketFrameCounter::Frame {
+            index: number as usize,
+        }
+    };
+    Some(PacketFrame {
+        payload: packet[0..25].try_into().unwrap(),
+        counter,
+    })
+}
index 75384172c8d0cf88cf2371575638db1c6302a021..0716be0a38ab4e804cd216001b7d2aab8b25d170 100755 (executable)
@@ -181,6 +181,11 @@ pub(crate) fn p_2(step: usize) -> (bool, bool) {
     (true, mod6 != 5)
 }
 
     (true, mod6 != 5)
 }
 
+pub(crate) fn p_3(step: usize) -> (bool, bool) {
+    let mod4 = step % 4;
+    (true, mod4 != 3)
+}
+
 fn best_previous(table: &[[u8; 32]; 244], step: usize, state: usize) -> u8 {
     if step == 0 {
         if state == 0 {
 fn best_previous(table: &[[u8; 32]; 244], step: usize, state: usize) -> u8 {
     if step == 0 {
         if state == 0 {
index af36ab4a88db3b38df0615a60ee2add25313590e..2f92ba9a7318a01c5fbf45399df50bfad43be476 100644 (file)
@@ -1,4 +1,6 @@
-use crate::decode::{parse_lsf, parse_stream, sync_burst_correlation, SyncBurst, SYNC_THRESHOLD};
+use crate::decode::{
+    parse_lsf, parse_packet, parse_stream, sync_burst_correlation, SyncBurst, SYNC_THRESHOLD,
+};
 use crate::protocol::Frame;
 use crate::shaping::RRC_48K;
 use log::debug;
 use crate::protocol::Frame;
 use crate::shaping::RRC_48K;
 use log::debug;
@@ -131,7 +133,11 @@ impl Demodulator for SoftDemodulator {
                             }
                         }
                         SyncBurst::Packet => {
                             }
                         }
                         SyncBurst::Packet => {
-                            debug!("Found PACKET at sample {} diff {}", start_sample, c.diff)
+                            debug!("Found PACKET at sample {} diff {}", start_sample, c.diff);
+                            if let Some(frame) = parse_packet(&pkt_samples) {
+                                self.suppress = 191 * 10;
+                                return Some(Frame::Packet(frame));
+                            }
                         }
                     }
                 }
                         }
                     }
                 }