]> code.octet-stream.net Git - m17rt/commitdiff
Add error handling
authorThomas Karpiniec <tom.karpiniec@outlook.com>
Tue, 4 Feb 2025 09:54:56 +0000 (20:54 +1100)
committerThomas Karpiniec <tom.karpiniec@outlook.com>
Tue, 4 Feb 2025 09:54:56 +0000 (20:54 +1100)
m17app/src/error.rs
m17app/src/rtlsdr.rs
m17app/src/serial.rs
m17app/src/soundcard.rs
m17app/src/soundmodem.rs
m17codec2/src/lib.rs
tools/m17rt-mod/src/main.rs
tools/m17rt-txpacket/src/main.rs

index aeb58a562a4f191313b250c3292d73920ac76d29..634a531e55a36e0b343c50295c35307899eb9d86 100644 (file)
@@ -2,7 +2,7 @@ use std::{fmt::Display, path::PathBuf};
 
 use thiserror::Error;
 
 
 use thiserror::Error;
 
-/// Errors originating from the M17 Rust Toolkit core
+/// Errors from the M17 Rust Toolkit
 #[derive(Debug, Error)]
 pub enum M17Error {
     #[error("given callsign contains at least one character invalid in M17: {0}")]
 #[derive(Debug, Error)]
 pub enum M17Error {
     #[error("given callsign contains at least one character invalid in M17: {0}")]
@@ -39,10 +39,17 @@ pub enum M17Error {
 
     #[error("adapter error for id {0}: {1}")]
     Adapter(usize, #[source] AdapterError),
 
     #[error("adapter error for id {0}: {1}")]
     Adapter(usize, #[source] AdapterError),
+
+    #[error("soundmodem component error: {0}")]
+    Soundmodem(#[source] SoundmodemError),
 }
 
 }
 
+/// Arbitrary error type returned from adapters, which may be user-implemented
 pub type AdapterError = Box<dyn std::error::Error + Sync + Send + 'static>;
 
 pub type AdapterError = Box<dyn std::error::Error + Sync + Send + 'static>;
 
+/// Arbitrary error type returned from soundmodem components, which may be user-implemented
+pub type SoundmodemError = Box<dyn std::error::Error + Sync + Send + 'static>;
+
 /// Iterator over potentially multiple errors
 #[derive(Debug, Error)]
 pub struct M17Errors(pub(crate) Vec<M17Error>);
 /// Iterator over potentially multiple errors
 #[derive(Debug, Error)]
 pub struct M17Errors(pub(crate) Vec<M17Error>);
@@ -56,6 +63,13 @@ impl Iterator for M17Errors {
 
 impl Display for M17Errors {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 
 impl Display for M17Errors {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        write!(f, "{:?}", self.0)
+        let mut displays = vec![];
+        for e in &self.0 {
+            displays.push(e.to_string());
+        }
+        write!(f, "[{}]", displays.join(", "))
     }
 }
     }
 }
+
+#[derive(Debug, Error)]
+pub enum M17SoundmodemError {}
index 658aca4eada784d80e068173ca0a66bad5167808..7829f96220357a644fb6934ec4cd00104753047c 100644 (file)
@@ -5,7 +5,7 @@ use std::{
 };
 
 use crate::{
 };
 
 use crate::{
-    error::M17Error,
+    error::{M17Error, SoundmodemError},
     soundmodem::{InputSource, SoundmodemEvent},
 };
 
     soundmodem::{InputSource, SoundmodemEvent},
 };
 
@@ -26,8 +26,7 @@ impl RtlSdr {
 }
 
 impl InputSource for RtlSdr {
 }
 
 impl InputSource for RtlSdr {
-    fn start(&self, tx: SyncSender<SoundmodemEvent>) {
-        // TODO: error handling
+    fn start(&self, tx: SyncSender<SoundmodemEvent>) -> Result<(), SoundmodemError> {
         let mut cmd = Command::new("rtl_fm")
             .args([
                 "-E",
         let mut cmd = Command::new("rtl_fm")
             .args([
                 "-E",
@@ -40,8 +39,7 @@ impl InputSource for RtlSdr {
                 "48k",
             ])
             .stdout(Stdio::piped())
                 "48k",
             ])
             .stdout(Stdio::piped())
-            .spawn()
-            .unwrap();
+            .spawn()?;
         let mut stdout = cmd.stdout.take().unwrap();
         let mut buf = [0u8; 1024];
         let mut leftover: Option<u8> = None;
         let mut stdout = cmd.stdout.take().unwrap();
         let mut buf = [0u8; 1024];
         let mut leftover: Option<u8> = None;
@@ -72,11 +70,13 @@ impl InputSource for RtlSdr {
             }
         });
         *self.rtlfm.lock().unwrap() = Some(cmd);
             }
         });
         *self.rtlfm.lock().unwrap() = Some(cmd);
+        Ok(())
     }
 
     }
 
-    fn close(&self) {
+    fn close(&self) -> Result<(), SoundmodemError> {
         if let Some(mut process) = self.rtlfm.lock().unwrap().take() {
             let _ = process.kill();
         }
         if let Some(mut process) = self.rtlfm.lock().unwrap().take() {
             let _ = process.kill();
         }
+        Ok(())
     }
 }
     }
 }
index 8abb4b93ca170ee95c2cff7833f0eaa65f94e8c2..667d10a38f131adcddfe772b88b6ceac2fb790a9 100644 (file)
@@ -1,6 +1,6 @@
 use serialport::SerialPort;
 
 use serialport::SerialPort;
 
-use crate::soundmodem::Ptt;
+use crate::{error::SoundmodemError, soundmodem::Ptt};
 
 /// The pin on the serial port which is driving PTT
 pub enum PttPin {
 
 /// The pin on the serial port which is driving PTT
 pub enum PttPin {
@@ -23,27 +23,27 @@ impl SerialPtt {
             .map(|i| i.port_name)
     }
 
             .map(|i| i.port_name)
     }
 
-    pub fn new(port_name: &str, pin: PttPin) -> Self {
+    pub fn new(port_name: &str, pin: PttPin) -> Result<Self, SoundmodemError> {
         // TODO: error handling
         let port = serialport::new(port_name, 9600).open().unwrap();
         let mut s = Self { port, pin };
         // TODO: error handling
         let port = serialport::new(port_name, 9600).open().unwrap();
         let mut s = Self { port, pin };
-        s.ptt_off();
-        s
+        s.ptt_off()?;
+        Ok(s)
     }
 }
 
 impl Ptt for SerialPtt {
     }
 }
 
 impl Ptt for SerialPtt {
-    fn ptt_on(&mut self) {
-        let _ = match self.pin {
+    fn ptt_on(&mut self) -> Result<(), SoundmodemError> {
+        Ok(match self.pin {
             PttPin::Rts => self.port.write_request_to_send(true),
             PttPin::Dtr => self.port.write_data_terminal_ready(true),
             PttPin::Rts => self.port.write_request_to_send(true),
             PttPin::Dtr => self.port.write_data_terminal_ready(true),
-        };
+        }?)
     }
 
     }
 
-    fn ptt_off(&mut self) {
-        let _ = match self.pin {
+    fn ptt_off(&mut self) -> Result<(), SoundmodemError> {
+        Ok(match self.pin {
             PttPin::Rts => self.port.write_request_to_send(false),
             PttPin::Dtr => self.port.write_data_terminal_ready(false),
             PttPin::Rts => self.port.write_request_to_send(false),
             PttPin::Dtr => self.port.write_data_terminal_ready(false),
-        };
+        }?)
     }
 }
     }
 }
index 391463208b5caaeb346a73b4e7c728710cff1a61..f89d9f4e43a9ee6a1d34ee667a90b98a7c440b8e 100644 (file)
@@ -12,7 +12,7 @@ use cpal::{
 };
 
 use crate::{
 };
 
 use crate::{
-    error::M17Error,
+    error::{M17Error, SoundmodemError},
     soundmodem::{InputSource, OutputBuffer, OutputSink, SoundmodemEvent},
 };
 
     soundmodem::{InputSource, OutputBuffer, OutputSink, SoundmodemEvent},
 };
 
@@ -118,12 +118,12 @@ pub struct SoundcardInputSource {
 }
 
 impl InputSource for SoundcardInputSource {
 }
 
 impl InputSource for SoundcardInputSource {
-    fn start(&self, samples: SyncSender<SoundmodemEvent>) {
-        let _ = self.event_tx.send(SoundcardEvent::StartInput { samples });
+    fn start(&self, samples: SyncSender<SoundmodemEvent>) -> Result<(), SoundmodemError> {
+        Ok(self.event_tx.send(SoundcardEvent::StartInput { samples })?)
     }
 
     }
 
-    fn close(&self) {
-        let _ = self.event_tx.send(SoundcardEvent::CloseInput);
+    fn close(&self) -> Result<(), SoundmodemError> {
+        Ok(self.event_tx.send(SoundcardEvent::CloseInput)?)
     }
 }
 
     }
 }
 
@@ -132,14 +132,18 @@ pub struct SoundcardOutputSink {
 }
 
 impl OutputSink for SoundcardOutputSink {
 }
 
 impl OutputSink for SoundcardOutputSink {
-    fn start(&self, event_tx: SyncSender<SoundmodemEvent>, buffer: Arc<RwLock<OutputBuffer>>) {
-        let _ = self
+    fn start(
+        &self,
+        event_tx: SyncSender<SoundmodemEvent>,
+        buffer: Arc<RwLock<OutputBuffer>>,
+    ) -> Result<(), SoundmodemError> {
+        Ok(self
             .event_tx
             .event_tx
-            .send(SoundcardEvent::StartOutput { event_tx, buffer });
+            .send(SoundcardEvent::StartOutput { event_tx, buffer })?)
     }
 
     }
 
-    fn close(&self) {
-        let _ = self.event_tx.send(SoundcardEvent::CloseOutput);
+    fn close(&self) -> Result<(), SoundmodemError> {
+        Ok(self.event_tx.send(SoundcardEvent::CloseOutput)?)
     }
 }
 
     }
 }
 
index 16bb97642900e86139c5d22aab31a681b0b53c2d..1cb871aaffd93c021c65a8ec5f15373eabbe09c2 100644 (file)
@@ -1,4 +1,4 @@
-use crate::error::M17Error;
+use crate::error::{M17Error, SoundmodemError};
 use crate::tnc::{Tnc, TncError};
 use log::debug;
 use m17core::kiss::MAX_FRAME_LEN;
 use crate::tnc::{Tnc, TncError};
 use log::debug;
 use m17core::kiss::MAX_FRAME_LEN;
@@ -170,11 +170,12 @@ fn spawn_soundmodem_worker(
                     tnc.set_data_carrier_detect(demodulator.data_carrier_detect());
                 }
                 SoundmodemEvent::Start => {
                     tnc.set_data_carrier_detect(demodulator.data_carrier_detect());
                 }
                 SoundmodemEvent::Start => {
-                    input.start(event_tx.clone());
-                    output.start(event_tx.clone(), out_buffer.clone());
+                    // TODO: runtime event handling
+                    input.start(event_tx.clone()).unwrap();
+                    output.start(event_tx.clone(), out_buffer.clone()).unwrap();
                 }
                 SoundmodemEvent::Close => {
                 }
                 SoundmodemEvent::Close => {
-                    ptt_driver.ptt_off();
+                    ptt_driver.ptt_off().unwrap();
                     break;
                 }
                 SoundmodemEvent::DidReadFromOutputBuffer { len, timestamp } => {
                     break;
                 }
                 SoundmodemEvent::DidReadFromOutputBuffer { len, timestamp } => {
@@ -200,9 +201,9 @@ fn spawn_soundmodem_worker(
             let new_ptt = tnc.ptt();
             if new_ptt != ptt {
                 if new_ptt {
             let new_ptt = tnc.ptt();
             if new_ptt != ptt {
                 if new_ptt {
-                    ptt_driver.ptt_on();
+                    ptt_driver.ptt_on().unwrap();
                 } else {
                 } else {
-                    ptt_driver.ptt_off();
+                    ptt_driver.ptt_off().unwrap();
                 }
             }
             ptt = new_ptt;
                 }
             }
             ptt = new_ptt;
@@ -236,8 +237,8 @@ fn spawn_soundmodem_worker(
 }
 
 pub trait InputSource: Send + Sync + 'static {
 }
 
 pub trait InputSource: Send + Sync + 'static {
-    fn start(&self, samples: SyncSender<SoundmodemEvent>);
-    fn close(&self);
+    fn start(&self, samples: SyncSender<SoundmodemEvent>) -> Result<(), SoundmodemError>;
+    fn close(&self) -> Result<(), SoundmodemError>;
 }
 
 pub struct InputRrcFile {
 }
 
 pub struct InputRrcFile {
@@ -259,7 +260,7 @@ impl InputRrcFile {
 }
 
 impl InputSource for InputRrcFile {
 }
 
 impl InputSource for InputRrcFile {
-    fn start(&self, samples: SyncSender<SoundmodemEvent>) {
+    fn start(&self, samples: SyncSender<SoundmodemEvent>) -> Result<(), SoundmodemError> {
         let (end_tx, end_rx) = channel();
         let baseband = self.baseband.clone();
         std::thread::spawn(move || {
         let (end_tx, end_rx) = channel();
         let baseband = self.baseband.clone();
         std::thread::spawn(move || {
@@ -291,10 +292,12 @@ impl InputSource for InputRrcFile {
             }
         });
         *self.end_tx.lock().unwrap() = Some(end_tx);
             }
         });
         *self.end_tx.lock().unwrap() = Some(end_tx);
+        Ok(())
     }
 
     }
 
-    fn close(&self) {
+    fn close(&self) -> Result<(), SoundmodemError> {
         let _ = self.end_tx.lock().unwrap().take();
         let _ = self.end_tx.lock().unwrap().take();
+        Ok(())
     }
 }
 
     }
 }
 
@@ -311,7 +314,7 @@ impl NullInputSource {
 }
 
 impl InputSource for NullInputSource {
 }
 
 impl InputSource for NullInputSource {
-    fn start(&self, samples: SyncSender<SoundmodemEvent>) {
+    fn start(&self, samples: SyncSender<SoundmodemEvent>) -> Result<(), SoundmodemError> {
         let (end_tx, end_rx) = channel();
         std::thread::spawn(move || {
             // assuming 48 kHz for now
         let (end_tx, end_rx) = channel();
         std::thread::spawn(move || {
             // assuming 48 kHz for now
@@ -333,10 +336,12 @@ impl InputSource for NullInputSource {
             }
         });
         *self.end_tx.lock().unwrap() = Some(end_tx);
             }
         });
         *self.end_tx.lock().unwrap() = Some(end_tx);
+        Ok(())
     }
 
     }
 
-    fn close(&self) {
+    fn close(&self) -> Result<(), SoundmodemError> {
         let _ = self.end_tx.lock().unwrap().take();
         let _ = self.end_tx.lock().unwrap().take();
+        Ok(())
     }
 }
 
     }
 }
 
@@ -370,8 +375,12 @@ impl Default for OutputBuffer {
 }
 
 pub trait OutputSink: Send + Sync + 'static {
 }
 
 pub trait OutputSink: Send + Sync + 'static {
-    fn start(&self, event_tx: SyncSender<SoundmodemEvent>, buffer: Arc<RwLock<OutputBuffer>>);
-    fn close(&self);
+    fn start(
+        &self,
+        event_tx: SyncSender<SoundmodemEvent>,
+        buffer: Arc<RwLock<OutputBuffer>>,
+    ) -> Result<(), SoundmodemError>;
+    fn close(&self) -> Result<(), SoundmodemError>;
 }
 
 pub struct OutputRrcFile {
 }
 
 pub struct OutputRrcFile {
@@ -389,13 +398,14 @@ impl OutputRrcFile {
 }
 
 impl OutputSink for OutputRrcFile {
 }
 
 impl OutputSink for OutputRrcFile {
-    fn start(&self, event_tx: SyncSender<SoundmodemEvent>, buffer: Arc<RwLock<OutputBuffer>>) {
+    fn start(
+        &self,
+        event_tx: SyncSender<SoundmodemEvent>,
+        buffer: Arc<RwLock<OutputBuffer>>,
+    ) -> Result<(), SoundmodemError> {
         let (end_tx, end_rx) = channel();
         let (end_tx, end_rx) = channel();
-        let path = self.path.clone();
+        let mut file = File::create(self.path.clone())?;
         std::thread::spawn(move || {
         std::thread::spawn(move || {
-            // TODO: error handling
-            let mut file = File::create(path).unwrap();
-
             // assuming 48 kHz for now
             const TICK: Duration = Duration::from_millis(25);
             const SAMPLES_PER_TICK: usize = 1200;
             // assuming 48 kHz for now
             const TICK: Duration = Duration::from_millis(25);
             const SAMPLES_PER_TICK: usize = 1200;
@@ -437,10 +447,12 @@ impl OutputSink for OutputRrcFile {
             }
         });
         *self.end_tx.lock().unwrap() = Some(end_tx);
             }
         });
         *self.end_tx.lock().unwrap() = Some(end_tx);
+        Ok(())
     }
 
     }
 
-    fn close(&self) {
+    fn close(&self) -> Result<(), SoundmodemError> {
         let _ = self.end_tx.lock().unwrap().take();
         let _ = self.end_tx.lock().unwrap().take();
+        Ok(())
     }
 }
 
     }
 }
 
@@ -463,7 +475,11 @@ impl Default for NullOutputSink {
 }
 
 impl OutputSink for NullOutputSink {
 }
 
 impl OutputSink for NullOutputSink {
-    fn start(&self, event_tx: SyncSender<SoundmodemEvent>, buffer: Arc<RwLock<OutputBuffer>>) {
+    fn start(
+        &self,
+        event_tx: SyncSender<SoundmodemEvent>,
+        buffer: Arc<RwLock<OutputBuffer>>,
+    ) -> Result<(), SoundmodemError> {
         let (end_tx, end_rx) = channel();
         std::thread::spawn(move || {
             // assuming 48 kHz for now
         let (end_tx, end_rx) = channel();
         std::thread::spawn(move || {
             // assuming 48 kHz for now
@@ -498,16 +514,18 @@ impl OutputSink for NullOutputSink {
             }
         });
         *self.end_tx.lock().unwrap() = Some(end_tx);
             }
         });
         *self.end_tx.lock().unwrap() = Some(end_tx);
+        Ok(())
     }
 
     }
 
-    fn close(&self) {
+    fn close(&self) -> Result<(), SoundmodemError> {
         let _ = self.end_tx.lock().unwrap().take();
         let _ = self.end_tx.lock().unwrap().take();
+        Ok(())
     }
 }
 
 pub trait Ptt: Send + 'static {
     }
 }
 
 pub trait Ptt: Send + 'static {
-    fn ptt_on(&mut self);
-    fn ptt_off(&mut self);
+    fn ptt_on(&mut self) -> Result<(), SoundmodemError>;
+    fn ptt_off(&mut self) -> Result<(), SoundmodemError>;
 }
 
 /// There is no PTT because this TNC will never make transmissions on a real radio.
 }
 
 /// There is no PTT because this TNC will never make transmissions on a real radio.
@@ -526,6 +544,11 @@ impl Default for NullPtt {
 }
 
 impl Ptt for NullPtt {
 }
 
 impl Ptt for NullPtt {
-    fn ptt_on(&mut self) {}
-    fn ptt_off(&mut self) {}
+    fn ptt_on(&mut self) -> Result<(), SoundmodemError> {
+        Ok(())
+    }
+
+    fn ptt_off(&mut self) -> Result<(), SoundmodemError> {
+        Ok(())
+    }
 }
 }
index c338f6ae1cdeb46daac2a28059e7af2469abc4c6..2f05701f20b50deaaa6a68966eb83ea35ff27cce 100755 (executable)
@@ -91,7 +91,7 @@ impl StreamAdapter for Codec2Adapter {
         std::thread::spawn(move || stream_thread(end_rx, setup_tx, state, output_card));
         self.state.lock().unwrap().end_tx = Some(end_tx);
         // Propagate any errors arising in the thread
         std::thread::spawn(move || stream_thread(end_rx, setup_tx, state, output_card));
         self.state.lock().unwrap().end_tx = Some(end_tx);
         // Propagate any errors arising in the thread
-        Ok(setup_rx.recv()??)
+        setup_rx.recv()?
     }
 
     fn close(&self) -> Result<(), AdapterError> {
     }
 
     fn close(&self) -> Result<(), AdapterError> {
index 26b7aba3d446cf257d5ea79f5bfcf9a2ad910b77..6a3c527b9e854c207edc4da8a3ef222d33dceedc 100644 (file)
@@ -9,7 +9,7 @@ use std::path::PathBuf;
 pub fn mod_test() {
     let soundcard = Soundcard::new("plughw:CARD=Device,DEV=0").unwrap();
     soundcard.set_tx_inverted(true);
 pub fn mod_test() {
     let soundcard = Soundcard::new("plughw:CARD=Device,DEV=0").unwrap();
     soundcard.set_tx_inverted(true);
-    let ptt = SerialPtt::new("/dev/ttyUSB0", PttPin::Rts);
+    let ptt = SerialPtt::new("/dev/ttyUSB0", PttPin::Rts).unwrap();
     let soundmodem = Soundmodem::new(soundcard.input(), soundcard.output(), ptt);
     let app = M17App::new(soundmodem);
     app.start().unwrap();
     let soundmodem = Soundmodem::new(soundcard.input(), soundcard.output(), ptt);
     let app = M17App::new(soundmodem);
     app.start().unwrap();
index 37f86d953a96801deccb31da2b0614d40d1d57e4..fcac6f5da4cb96e68d0abe6c5fec6172ac9b42b3 100644 (file)
@@ -8,7 +8,7 @@ use m17core::protocol::PacketType;
 fn main() {
     let soundcard = Soundcard::new("plughw:CARD=Device,DEV=0").unwrap();
     soundcard.set_tx_inverted(true);
 fn main() {
     let soundcard = Soundcard::new("plughw:CARD=Device,DEV=0").unwrap();
     soundcard.set_tx_inverted(true);
-    let ptt = SerialPtt::new("/dev/ttyUSB0", PttPin::Rts);
+    let ptt = SerialPtt::new("/dev/ttyUSB0", PttPin::Rts).unwrap();
     let soundmodem = Soundmodem::new(soundcard.input(), soundcard.output(), ptt);
     let app = M17App::new(soundmodem);
 
     let soundmodem = Soundmodem::new(soundcard.input(), soundcard.output(), ptt);
     let app = M17App::new(soundmodem);