Close,
}
-fn spawn_reader<T: Tnc + Send + 'static>(mut tnc: T, adapters: Arc<RwLock<Adapters>>) {
+fn spawn_reader<T: Tnc>(mut tnc: T, adapters: Arc<RwLock<Adapters>>) {
std::thread::spawn(move || {
let mut kiss_buffer = KissBuffer::new();
let mut stream_running = false;
});
}
-fn spawn_writer<T: Tnc + Send + 'static>(mut tnc: T, event_rx: mpsc::Receiver<TncControlEvent>) {
+fn spawn_writer<T: Tnc>(mut tnc: T, event_rx: mpsc::Receiver<TncControlEvent>) {
std::thread::spawn(move || {
while let Ok(ev) = event_rx.recv() {
match ev {
--- /dev/null
+use std::io::{self, ErrorKind, Read, Write};
+
+use crate::tnc::{Tnc, TncError};
+use m17core::tnc::SoftTnc;
+
+pub struct Soundmodem {
+ tnc: SoftTnc,
+ config: SoundmodemConfig,
+}
+
+pub struct SoundmodemConfig {
+ // sound cards, PTT, etc.
+}
+
+impl Read for Soundmodem {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.tnc
+ .read_kiss(buf)
+ .map_err(|s| io::Error::new(ErrorKind::Other, format!("{:?}", s)))
+ }
+}
+
+impl Write for Soundmodem {
+ fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+ self.tnc
+ .write_kiss(buf)
+ .map_err(|s| io::Error::new(ErrorKind::Other, format!("{:?}", s)))
+ }
+
+ fn flush(&mut self) -> std::io::Result<()> {
+ Ok(())
+ }
+}
+
+impl Tnc for Soundmodem {
+ fn try_clone(&mut self) -> Result<Self, TncError> {
+ unimplemented!();
+ }
+
+ fn start(&mut self) -> Result<(), TncError> {
+ unimplemented!();
+ }
+
+ fn close(&mut self) -> Result<(), TncError> {
+ unimplemented!();
+ }
+}
-use std::io::{self, ErrorKind, Read, Write};
-
-use m17core::tnc::SoftTnc;
+use std::io::{Read, Write};
+/// A TNC that supports reading and writing M17 KISS messages.
///
-pub trait Tnc: Read + Write + Sized {
+/// TNCs must be cloneable to support reading and writing from different threads,
+/// 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 {
fn try_clone(&mut self) -> Result<Self, TncError>;
fn start(&mut self) -> Result<(), TncError>;
fn close(&mut self) -> Result<(), TncError>;
}
-#[derive(Debug)]
+#[derive(Debug, PartialEq, Eq, Clone)]
pub enum TncError {
- General(String),
-}
-
-// TODO: move the following to its own module
-
-pub struct Soundmodem {
- tnc: SoftTnc,
- config: SoundmodemConfig,
-}
-
-pub struct SoundmodemConfig {
- // sound cards, PTT, etc.
-}
-
-impl Read for Soundmodem {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- self.tnc
- .read_kiss(buf)
- .map_err(|s| io::Error::new(ErrorKind::Other, format!("{:?}", s)))
- }
-}
-
-impl Write for Soundmodem {
- fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
- self.tnc
- .write_kiss(buf)
- .map_err(|s| io::Error::new(ErrorKind::Other, format!("{:?}", s)))
- }
-
- fn flush(&mut self) -> std::io::Result<()> {
- Ok(())
- }
+ // TODO: Good error cases
+ Unknown,
}
-impl Tnc for Soundmodem {
+impl Tnc for std::net::TcpStream {
fn try_clone(&mut self) -> Result<Self, TncError> {
- unimplemented!();
+ self.try_clone().map_err(|_| TncError::Unknown)
}
fn start(&mut self) -> Result<(), TncError> {
- unimplemented!();
+ // already started, hopefully we get onto reading the socket quickly
+ Ok(())
}
fn close(&mut self) -> Result<(), TncError> {
- unimplemented!();
+ self.shutdown(std::net::Shutdown::Both)
+ .map_err(|_| TncError::Unknown)
}
}