+use crate::adapter::{PacketAdapter, StreamAdapter};
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 std::io::{Read, Write};
use std::sync::mpsc;
use std::sync::{Arc, RwLock};
}
}
- 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;
- listeners.packet.insert(id, Box::new(listener));
+ listeners.packet.insert(id, Arc::new(listener));
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;
- listeners.stream.insert(id, Box::new(listener));
+ listeners.stream.insert(id, Arc::new(listener));
id
}
// 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 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,
- 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 {
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
}
_ => (),
// BERT
}
+#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PacketType {
/// RAW
Raw,
}
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 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)]