]> code.octet-stream.net Git - m17rt/commitdiff
RTLSDR input via rtl_fm
authorThomas Karpiniec <tom.karpiniec@outlook.com>
Tue, 28 Jan 2025 16:05:58 +0000 (03:05 +1100)
committerThomas Karpiniec <tom.karpiniec@outlook.com>
Tue, 28 Jan 2025 16:05:58 +0000 (03:05 +1100)
m17app/src/error.rs
m17app/src/lib.rs
m17app/src/rtlsdr.rs [new file with mode: 0644]
tools/m17rt-mod/src/main.rs

index ee624f9257c9a873824cb475fd2f471268a629d0..36d5ac07f95943554760666a2d688f5ed37b798a 100644 (file)
@@ -13,4 +13,7 @@ pub enum M17Error {
 
     #[error("unable to locate sound card '{0}' - is it in use?")]
     SoundcardNotFound(String),
+
+    #[error("unable to set up RTL-SDR receiver")]
+    RtlSdrInit,
 }
index 543bdc5f1383f2036675fcabf63ee8259d9795d8..06a6cfacba8394ff2e5653edaeac4471610ad286 100755 (executable)
@@ -2,6 +2,7 @@ pub mod adapter;
 pub mod app;
 pub mod error;
 pub mod link_setup;
+pub mod rtlsdr;
 pub mod serial;
 pub mod soundcard;
 pub mod soundmodem;
diff --git a/m17app/src/rtlsdr.rs b/m17app/src/rtlsdr.rs
new file mode 100644 (file)
index 0000000..33f8070
--- /dev/null
@@ -0,0 +1,90 @@
+use std::{
+    io::Read,
+    process::{Child, Command, Stdio},
+    sync::{
+        mpsc::{sync_channel, Receiver, SyncSender},
+        Arc, Mutex, RwLock,
+    },
+    time::{Duration, Instant},
+};
+
+use cpal::{
+    traits::{DeviceTrait, HostTrait, StreamTrait},
+    SampleFormat, SampleRate, Stream,
+};
+
+use crate::{
+    error::M17Error,
+    soundmodem::{InputSource, OutputBuffer, OutputSink, SoundmodemEvent},
+};
+
+pub struct RtlSdr {
+    frequency_mhz: f32,
+    device_index: usize,
+    rtlfm: Mutex<Option<Child>>,
+}
+
+impl RtlSdr {
+    pub fn new(device_index: usize, frequency_mhz: f32) -> Result<Self, M17Error> {
+        Ok(Self {
+            device_index,
+            frequency_mhz,
+            rtlfm: Mutex::new(None),
+        })
+    }
+}
+
+impl InputSource for RtlSdr {
+    fn start(&self, tx: SyncSender<SoundmodemEvent>) {
+        // TODO: error handling
+        let mut cmd = Command::new("rtl_fm")
+            .args([
+                "-E",
+                "offset",
+                "-f",
+                &format!("{:.6}M", self.frequency_mhz),
+                "-d",
+                &self.device_index.to_string(),
+                "-s",
+                "48k",
+            ])
+            .stdout(Stdio::piped())
+            .spawn()
+            .unwrap();
+        let mut stdout = cmd.stdout.take().unwrap();
+        let mut buf = [0u8; 1024];
+        let mut leftover: Option<u8> = None;
+        std::thread::spawn(move || {
+            while let Ok(n) = stdout.read(&mut buf) {
+                let mut start_idx = 0;
+                let mut samples = vec![];
+                if let Some(left) = leftover {
+                    if n > 0 {
+                        samples.push(i16::from_le_bytes([left, buf[0]]));
+                        start_idx = 1;
+                        leftover = None;
+                    }
+                }
+                for sample in buf[start_idx..n].chunks(2) {
+                    if sample.len() == 2 {
+                        samples.push(i16::from_le_bytes([sample[0], sample[1]]))
+                    } else {
+                        leftover = Some(sample[0]);
+                    }
+                }
+                if tx
+                    .send(SoundmodemEvent::BasebandInput(samples.into()))
+                    .is_err()
+                {
+                    break;
+                }
+            }
+        });
+    }
+
+    fn close(&self) {
+        if let Some(mut process) = self.rtlfm.lock().unwrap().take() {
+            let _ = process.kill();
+        }
+    }
+}
index 50358bd7a34634c916c75b9367b2f7209b86df79..3bd672785c359dc2e01e1cc288734a436325645d 100644 (file)
@@ -8,6 +8,7 @@ use std::path::PathBuf;
 
 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 soundmodem = Soundmodem::new(soundcard.input(), soundcard.output(), ptt);
     let app = M17App::new(soundmodem);