X-Git-Url: https://code.octet-stream.net/m17rt/blobdiff_plain/64599440f241f7bb897a95b72ed7130231966518..5be3b9f857eefe983fbadae517a25da05b8b8982:/m17app/src/soundmodem.rs diff --git a/m17app/src/soundmodem.rs b/m17app/src/soundmodem.rs index e7c0022..c0cbfbb 100644 --- a/m17app/src/soundmodem.rs +++ b/m17app/src/soundmodem.rs @@ -1,11 +1,13 @@ use crate::error::{M17Error, SoundmodemError}; use crate::tnc::{Tnc, TncError}; +use crate::util::out_buffer::OutBuffer; use m17core::kiss::MAX_FRAME_LEN; use m17core::modem::{Demodulator, Modulator, ModulatorAction, SoftDemodulator, SoftModulator}; use m17core::tnc::SoftTnc; use std::collections::VecDeque; +use std::fmt::Display; use std::fs::File; -use std::io::{self, ErrorKind, Read, Write}; +use std::io::{self, Read, Write}; use std::path::PathBuf; use std::sync::mpsc::{channel, sync_channel, Receiver, Sender, SyncSender, TryRecvError}; use std::sync::RwLock; @@ -15,9 +17,7 @@ use thiserror::Error; pub struct Soundmodem { event_tx: SyncSender, - kiss_out_rx: Arc>>>, - partial_kiss_out: Arc>>, - error_handler: ErrorHandlerInternal, + kiss_out: OutBuffer, } impl Soundmodem { @@ -29,7 +29,6 @@ impl Soundmodem { ) -> Self { let (event_tx, event_rx) = sync_channel(128); let (kiss_out_tx, kiss_out_rx) = sync_channel(128); - let runtime_error_handler: ErrorHandlerInternal = Arc::new(Mutex::new(Box::new(error))); spawn_soundmodem_worker( event_tx.clone(), event_rx, @@ -37,13 +36,11 @@ impl Soundmodem { Box::new(input), Box::new(output), Box::new(ptt), - runtime_error_handler.clone(), + Box::new(error), ); Self { event_tx, - kiss_out_rx: Arc::new(Mutex::new(kiss_out_rx)), - partial_kiss_out: Arc::new(Mutex::new(None)), - error_handler: runtime_error_handler, + kiss_out: OutBuffer::new(kiss_out_rx), } } } @@ -55,6 +52,16 @@ pub enum ErrorSource { Ptt, } +impl Display for ErrorSource { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Input => write!(f, "Input"), + Self::Output => write!(f, "Output"), + Self::Ptt => write!(f, "PTT"), + } + } +} + pub trait ErrorHandler: Send + Sync + 'static { fn soundmodem_error(&mut self, source: ErrorSource, err: SoundmodemError); } @@ -68,6 +75,7 @@ where } } +/// Soundmodem errors will be ignored. pub struct NullErrorHandler; impl NullErrorHandler { @@ -89,7 +97,47 @@ impl ErrorHandler for NullErrorHandler { } } -type ErrorHandlerInternal = Arc>>; +/// Soundmodem errors will be logged at DEBUG level via the `log` crate. +pub struct LogErrorHandler; + +impl LogErrorHandler { + pub fn new() -> Self { + Self {} + } +} + +impl Default for LogErrorHandler { + fn default() -> Self { + Self::new() + } +} + +impl ErrorHandler for LogErrorHandler { + fn soundmodem_error(&mut self, source: ErrorSource, err: SoundmodemError) { + log::debug!("Soundmodem error: {source} - {err}"); + } +} + +/// Soundmodem errors will be logged to stdout. +pub struct StdoutErrorHandler; + +impl StdoutErrorHandler { + pub fn new() -> Self { + Self {} + } +} + +impl Default for StdoutErrorHandler { + fn default() -> Self { + Self::new() + } +} + +impl ErrorHandler for StdoutErrorHandler { + fn soundmodem_error(&mut self, source: ErrorSource, err: SoundmodemError) { + println!("Soundmodem error: {source} - {err}"); + } +} #[derive(Clone)] pub struct SoundmodemErrorSender { @@ -105,42 +153,9 @@ impl SoundmodemErrorSender { } } -struct PartialKissOut { - output: Arc<[u8]>, - idx: usize, -} - impl Read for Soundmodem { fn read(&mut self, buf: &mut [u8]) -> io::Result { - { - let mut partial_kiss_out = self.partial_kiss_out.lock().unwrap(); - if let Some(partial) = partial_kiss_out.as_mut() { - let remaining = partial.output.len() - partial.idx; - let to_write = remaining.min(buf.len()); - buf[0..to_write] - .copy_from_slice(&partial.output[partial.idx..(partial.idx + to_write)]); - if to_write == remaining { - *partial_kiss_out = None; - } else { - partial.idx += to_write; - } - return Ok(to_write); - } - } - let output = { - let rx = self.kiss_out_rx.lock().unwrap(); - rx.recv() - .map_err(|s| io::Error::new(ErrorKind::Other, format!("{:?}", s)))? - }; - let to_write = output.len().min(buf.len()); - buf[0..to_write].copy_from_slice(&output[0..to_write]); - if to_write != output.len() { - *self.partial_kiss_out.lock().unwrap() = Some(PartialKissOut { - output, - idx: to_write, - }) - } - Ok(to_write) + self.kiss_out.read(buf) } } @@ -159,9 +174,7 @@ impl Tnc for Soundmodem { fn try_clone(&mut self) -> Result { Ok(Self { event_tx: self.event_tx.clone(), - kiss_out_rx: self.kiss_out_rx.clone(), - partial_kiss_out: self.partial_kiss_out.clone(), - error_handler: self.error_handler.clone(), + kiss_out: self.kiss_out.clone(), }) } @@ -191,7 +204,7 @@ fn spawn_soundmodem_worker( input: Box, output: Box, mut ptt_driver: Box, - error_handler: ErrorHandlerInternal, + mut error_handler: Box, ) { std::thread::spawn(move || { // TODO: should be able to provide a custom Demodulator for a soundmodem @@ -251,10 +264,7 @@ fn spawn_soundmodem_worker( input.close(); output.close(); if let Err(e) = ptt_driver.ptt_off() { - error_handler - .lock() - .unwrap() - .soundmodem_error(ErrorSource::Ptt, e); + error_handler.soundmodem_error(ErrorSource::Ptt, e); } break; } @@ -277,7 +287,7 @@ fn spawn_soundmodem_worker( // TODO: cancel transmission, send empty data frame to host } SoundmodemEvent::RuntimeError(source, err) => { - error_handler.lock().unwrap().soundmodem_error(source, err); + error_handler.soundmodem_error(source, err); } } @@ -286,16 +296,10 @@ fn spawn_soundmodem_worker( if new_ptt != ptt { if new_ptt { if let Err(e) = ptt_driver.ptt_on() { - error_handler - .lock() - .unwrap() - .soundmodem_error(ErrorSource::Ptt, e); + error_handler.soundmodem_error(ErrorSource::Ptt, e); } } else if let Err(e) = ptt_driver.ptt_off() { - error_handler - .lock() - .unwrap() - .soundmodem_error(ErrorSource::Ptt, e); + error_handler.soundmodem_error(ErrorSource::Ptt, e); } } ptt = new_ptt;