]> code.octet-stream.net Git - m17rt/commitdiff
Parse incoming full packets and fan out to PacketAdapters
authorThomas Karpiniec <tom.karpiniec@outlook.com>
Mon, 30 Dec 2024 02:05:05 +0000 (13:05 +1100)
committerThomas Karpiniec <tom.karpiniec@outlook.com>
Mon, 30 Dec 2024 02:05:05 +0000 (13:05 +1100)
m17app/src/adapter.rs [new file with mode: 0644]
m17app/src/app.rs
m17app/src/lib.rs
m17core/src/lib.rs
m17core/src/protocol.rs
m17core/src/traits.rs [deleted file]

diff --git a/m17app/src/adapter.rs b/m17app/src/adapter.rs
new file mode 100644 (file)
index 0000000..1bc0971
--- /dev/null
@@ -0,0 +1,12 @@
+use crate::app::TxHandle;
+use m17core::protocol::{LsfFrame, PacketType};
+use std::sync::Arc;
+
+pub trait PacketAdapter: Send + Sync + 'static {
+    fn adapter_registered(&self, handle: TxHandle);
+    fn tnc_started(&self);
+    fn tnc_closed(&self);
+    fn packet_received(&self, lsf: LsfFrame, packet_type: PacketType, content: Arc<[u8]>);
+}
+
+pub trait StreamAdapter: Send + Sync + 'static {}
index 9c2815de50c4fbe53cc6280ef2a47ebe2630094c..4a7a345f5fa1bf709fa0f2cb5e1a52c5f4caf0f2 100644 (file)
@@ -1,11 +1,10 @@
+use crate::adapter::{PacketAdapter, StreamAdapter};
 use crate::tnc::Tnc;
 use m17core::kiss::{KissBuffer, KissCommand, KissFrame};
 use crate::tnc::Tnc;
 use m17core::kiss::{KissBuffer, KissCommand, KissFrame};
-use m17core::protocol::PacketType;
-use m17core::traits::{PacketListener, StreamListener};
+use m17core::protocol::{EncryptionType, LsfFrame, PacketType};
 
 use log::debug;
 use std::collections::HashMap;
 
 use log::debug;
 use std::collections::HashMap;
-use std::io::{Read, Write};
 use std::sync::mpsc;
 use std::sync::{Arc, RwLock};
 
 use std::sync::mpsc;
 use std::sync::{Arc, RwLock};
 
@@ -27,19 +26,19 @@ impl M17App {
         }
     }
 
         }
     }
 
-    pub fn add_packet_listener<P: PacketListener + 'static>(&self, listener: P) -> usize {
+    pub fn add_packet_listener<P: PacketAdapter + 'static>(&self, listener: P) -> usize {
         let mut listeners = self.listeners.write().unwrap();
         let id = listeners.next;
         listeners.next += 1;
         let mut listeners = self.listeners.write().unwrap();
         let id = listeners.next;
         listeners.next += 1;
-        listeners.packet.insert(id, Box::new(listener));
+        listeners.packet.insert(id, Arc::new(listener));
         id
     }
 
         id
     }
 
-    pub fn add_stream_listener<S: StreamListener + 'static>(&self, listener: S) -> usize {
+    pub fn add_stream_listener<S: StreamAdapter + 'static>(&self, listener: S) -> usize {
         let mut listeners = self.listeners.write().unwrap();
         let id = listeners.next;
         listeners.next += 1;
         let mut listeners = self.listeners.write().unwrap();
         let id = listeners.next;
         listeners.next += 1;
-        listeners.stream.insert(id, Box::new(listener));
+        listeners.stream.insert(id, Arc::new(listener));
         id
     }
 
         id
     }
 
@@ -59,13 +58,12 @@ impl M17App {
         // we will immediately convert this into a KISS payload before sending into channel so we only need borrow on data
     }
 
         // we will immediately convert this into a KISS payload before sending into channel so we only need borrow on data
     }
 
-    // add more methods here for stream outgoing
-
-    pub fn transmit_stream_start(&self /* lsf?, payload? what needs to be configured ?! */) {}
-
-    // as long as there is only one TNC it is implied there is only ever one stream transmission in flight
-
-    pub fn transmit_stream_next(&self, /* next payload,  */ end_of_stream: bool) {}
+    /// Create a handle that can be used to transmit data on the TNC
+    pub fn tx(&self) -> TxHandle {
+        TxHandle {
+            event_tx: self.event_tx.clone(),
+        }
+    }
 
     pub fn start(&self) {
         let _ = self.event_tx.send(TncControlEvent::Start);
 
     pub fn start(&self) {
         let _ = self.event_tx.send(TncControlEvent::Start);
@@ -76,14 +74,28 @@ impl M17App {
     }
 }
 
     }
 }
 
+pub struct TxHandle {
+    event_tx: mpsc::SyncSender<TncControlEvent>,
+}
+
+impl TxHandle {
+    // add more methods here for stream outgoing
+
+    pub fn transmit_stream_start(&self /* lsf?, payload? what needs to be configured ?! */) {}
+
+    // as long as there is only one TNC it is implied there is only ever one stream transmission in flight
+
+    pub fn transmit_stream_next(&self, /* next payload,  */ end_of_stream: bool) {}
+}
+
 /// Synchronised structure for listeners subscribing to packets and streams.
 ///
 /// Each listener will be notified in turn of each event.
 struct Listeners {
     /// Identifier to be assigned to the next listener, starting from 0
     next: usize,
 /// Synchronised structure for listeners subscribing to packets and streams.
 ///
 /// Each listener will be notified in turn of each event.
 struct Listeners {
     /// Identifier to be assigned to the next listener, starting from 0
     next: usize,
-    packet: HashMap<usize, Box<dyn PacketListener>>,
-    stream: HashMap<usize, Box<dyn StreamListener>>,
+    packet: HashMap<usize, Arc<dyn PacketAdapter>>,
+    stream: HashMap<usize, Arc<dyn StreamAdapter>>,
 }
 
 impl Listeners {
 }
 
 impl Listeners {
@@ -118,13 +130,57 @@ fn spawn_reader<T: Tnc + Send + 'static>(mut tnc: T, listeners: Arc<RwLock<Liste
                     continue;
                 }
                 match frame.port() {
                     continue;
                 }
                 match frame.port() {
-                    Ok(0) => {
-                        // handle basic frame and send it to subscribers
+                    Ok(m17core::kiss::PORT_PACKET_BASIC) => {
+                        // no action
+                        // we will handle the more full-featured version from from port 1
                     }
                     }
-                    Ok(1) => {
-                        // handle full frame and send it to subscribers - I guess they need to know the type, probably not the CRC
+                    Ok(m17core::kiss::PORT_PACKET_FULL) => {
+                        let mut payload = [0u8; 855]; // 30 byte LSF + 825 byte packet including CRC
+                        let Ok(n) = frame.decode_payload(&mut payload) else {
+                            debug!("failed to decode payload from KISS frame");
+                            continue;
+                        };
+                        if n < 33 {
+                            debug!("unusually short full packet frame");
+                            continue;
+                        }
+                        let lsf = LsfFrame(payload[0..30].try_into().unwrap());
+                        if lsf.crc() != 0 {
+                            debug!("LSF in full packet frame did not pass CRC");
+                            continue;
+                        }
+                        if lsf.encryption_type() != EncryptionType::None {
+                            debug!("we only understand None encryption for now - skipping packet");
+                            continue;
+                        }
+                        let Some((packet_type, type_len)) = PacketType::from_proto(&payload[30..n])
+                        else {
+                            debug!("failed to decode packet type");
+                            continue;
+                        };
+                        if (n - 30 - type_len) < 2 {
+                            debug!("packet payload too small to provide CRC");
+                            continue;
+                        }
+                        let packet_crc = m17core::crc::m17_crc(&payload[30..n]);
+                        if packet_crc != 0 {
+                            debug!("packet CRC does not pass");
+                            continue;
+                        }
+                        let packet_payload: Arc<[u8]> =
+                            Arc::from(&payload[(30 + type_len)..(n - 2)]);
+
+                        let subs: Vec<_> =
+                            listeners.read().unwrap().packet.values().cloned().collect();
+                        for s in subs {
+                            s.packet_received(
+                                lsf.clone(),
+                                packet_type.clone(),
+                                packet_payload.clone(),
+                            );
+                        }
                     }
                     }
-                    Ok(2) => {
+                    Ok(m17core::kiss::PORT_STREAM) => {
                         // handle stream and send it to subscribers
                     }
                     _ => (),
                         // handle stream and send it to subscribers
                     }
                     _ => (),
index 0e1f9ef703b51db2e5a632c19982b74c7a534582..d135ca2b63dd120e40053e9abe8fa40bbff676e8 100755 (executable)
@@ -1,2 +1,3 @@
+pub mod adapter;
 pub mod app;
 pub mod tnc;
 pub mod app;
 pub mod tnc;
index c1e94a812bd1be3b7fbd1c753a069febb7fc9c74..b10427b4550a6af79b7ea29be483dac7847bdd92 100755 (executable)
@@ -2,14 +2,13 @@
 #![cfg_attr(not(test), no_std)]
 
 pub mod address;
 #![cfg_attr(not(test), no_std)]
 
 pub mod address;
+pub mod crc;
 pub mod kiss;
 pub mod modem;
 pub mod protocol;
 pub mod tnc;
 pub mod kiss;
 pub mod modem;
 pub mod protocol;
 pub mod tnc;
-pub mod traits;
 
 mod bits;
 
 mod bits;
-mod crc;
 mod decode;
 mod fec;
 mod interleave;
 mod decode;
 mod fec;
 mod interleave;
index 96def5b8913ffdcc245baa7998a934ff470043d9..382fb9fa516461a2078cf9032d5afe262f15dec7 100755 (executable)
@@ -33,6 +33,7 @@ pub enum Frame {
     // BERT
 }
 
     // BERT
 }
 
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub enum PacketType {
     /// RAW
     Raw,
 pub enum PacketType {
     /// RAW
     Raw,
@@ -53,6 +54,22 @@ pub enum PacketType {
 }
 
 impl PacketType {
 }
 
 impl PacketType {
+    pub fn from_proto(buf: &[u8]) -> Option<(Self, usize)> {
+        buf.utf8_chunks()
+            .next()
+            .and_then(|chunk| chunk.valid().chars().next())
+            .map(|c| match c as u32 {
+                0x00 => (PacketType::Raw, 1),
+                0x01 => (PacketType::Ax25, 1),
+                0x02 => (PacketType::Aprs, 1),
+                0x03 => (PacketType::SixLowPan, 1),
+                0x04 => (PacketType::Ipv4, 1),
+                0x05 => (PacketType::Sms, 1),
+                0x06 => (PacketType::Winlink, 1),
+                _ => (PacketType::Other(c), c.len_utf8()),
+            })
+    }
+
     pub fn as_proto(&self) -> ([u8; 4], usize) {
         match self {
             PacketType::Raw => ([0, 0, 0, 0], 1),
     pub fn as_proto(&self) -> ([u8; 4], usize) {
         match self {
             PacketType::Raw => ([0, 0, 0, 0], 1),
@@ -70,22 +87,6 @@ impl PacketType {
             }
         }
     }
             }
         }
     }
-
-    pub fn from_proto(&self, buf: &[u8]) -> Option<PacketType> {
-        buf.utf8_chunks()
-            .next()
-            .and_then(|chunk| chunk.valid().chars().next())
-            .map(|c| match c as u32 {
-                0x00 => PacketType::Raw,
-                0x01 => PacketType::Ax25,
-                0x02 => PacketType::Aprs,
-                0x03 => PacketType::SixLowPan,
-                0x04 => PacketType::Ipv4,
-                0x05 => PacketType::Sms,
-                0x06 => PacketType::Winlink,
-                _ => PacketType::Other(c),
-            })
-    }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
diff --git a/m17core/src/traits.rs b/m17core/src/traits.rs
deleted file mode 100644 (file)
index c846ba4..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-pub trait PacketListener {}
-
-pub trait StreamListener {}