1#![cfg_attr(feature = "simd", feature(portable_simd))]
3#![cfg_attr(
5 all(
6 feature = "simd",
7 any(target_arch = "riscv32", target_arch = "riscv64")
8 ),
9 feature(stdarch_riscv_feature_detection)
10)]
11#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
12
13#![deny(clippy::needless_for_each)]
133#![deny(clippy::explicit_iter_loop)]
134#![deny(clippy::items_after_statements)]
135#![deny(clippy::format_push_string)]
136#![deny(clippy::return_self_not_must_use)]
137pub use rustradio_macros;
139
140pub mod add;
142pub mod add_const;
143pub mod au;
144pub mod binary_slicer;
145pub mod burst_tagger;
146pub mod canary;
147pub mod cma;
148pub mod complex_to_mag2;
149pub mod constant_source;
150pub mod convert;
151pub mod correlate_access_code;
152pub mod debug_sink;
153pub mod delay;
154pub mod descrambler;
155pub mod fft;
156pub mod fft_filter;
157pub mod fft_stream;
158pub mod file_sink;
159pub mod file_source;
160pub mod fir;
161pub mod hasher;
162pub mod hdlc_deframer;
163pub mod hdlc_framer;
164pub mod hilbert;
165pub mod iir_filter;
166pub mod il2p_deframer;
167pub mod iq_balance;
168pub mod kiss;
169pub mod morse_encode;
170pub mod multiply_const;
171pub mod nrzi;
172pub mod null_sink;
173pub mod pdu_to_stream;
174pub mod pdu_writer;
175pub mod quadrature_demod;
176pub mod rational_resampler;
177pub mod reader_source;
178pub mod rtlsdr_decode;
179pub mod sigmf;
180pub mod signal_source;
181pub mod single_pole_iir_filter;
182pub mod skip;
183pub mod stream_to_pdu;
184pub mod strobe;
185pub mod symbol_sync;
186pub mod tcp_source;
187pub mod tee;
188pub mod to_text;
189pub mod vco;
190pub mod vec_to_stream;
191pub mod vector_sink;
192pub mod vector_source;
193pub mod wpcr;
194pub mod writer_sink;
195pub mod xor;
196pub mod xor_const;
197pub mod zero_crossing;
198
199#[cfg(feature = "audio")]
200pub mod audio_sink;
201
202#[cfg(feature = "pipewire")]
203pub mod pipewire_sink;
204
205#[cfg(feature = "pipewire")]
206pub mod pipewire_source;
207
208#[cfg(feature = "rtlsdr")]
209pub mod rtlsdr_source;
210
211#[cfg(feature = "soapysdr")]
212pub mod soapysdr_sink;
213
214#[cfg(feature = "soapysdr")]
215pub mod soapysdr_source;
216
217pub mod block;
218pub mod blocks;
219
220#[cfg(not(feature = "wasm"))]
221pub mod nowasm;
222
223#[cfg(feature = "wasm")]
224pub mod wasm;
225
226pub mod sys {
227 #[cfg(not(feature = "wasm"))]
228 pub use super::nowasm::export::*;
229 #[cfg(feature = "wasm")]
230 pub use super::wasm::export::*;
231}
232
233pub mod graph;
234#[cfg(not(feature = "wasm"))]
235pub mod mtgraph;
236pub mod stream;
237pub mod window;
238
239#[cfg(feature = "async")]
240pub mod agraph;
241
242pub type Float = f32;
244
245pub type Complex = num_complex::Complex<Float>;
247
248pub(crate) static NEXT_STREAM_ID: std::sync::atomic::AtomicUsize =
249 std::sync::atomic::AtomicUsize::new(1);
250
251#[derive(thiserror::Error, Debug)]
253#[non_exhaustive]
254pub enum Error {
255 #[error("IO Error on {path:?}: {source:?}")]
257 FileIo {
258 #[source]
259 source: std::io::Error,
260 path: std::path::PathBuf,
261 },
262
263 #[error("DeviceError: {msg:?}: {source:?}")]
265 DeviceError {
266 #[source]
267 source: Box<dyn std::error::Error + Send + Sync>,
268 msg: Option<String>,
269 },
270
271 #[error("IO Error: {0}")]
273 Io(#[from] std::io::Error),
274
275 #[error("An error occurred: {0}")]
277 Plain(String),
278
279 #[error("{msg:?}: {source:?}")]
281 Other {
282 #[source]
283 source: Box<dyn std::error::Error + Send + Sync>,
284 msg: Option<String>,
285 },
286}
287
288impl Error {
289 #[must_use]
291 pub fn msg<S: Into<String>>(msg: S) -> Self {
292 Self::Plain(msg.into())
293 }
294
295 #[must_use]
297 pub fn file_io<P: Into<std::path::PathBuf>>(source: std::io::Error, path: P) -> Self {
298 Self::FileIo {
299 path: path.into(),
300 source,
301 }
302 }
303
304 #[must_use]
308 pub fn wrap<S: Into<String>>(
309 source: impl std::error::Error + Send + Sync + 'static,
310 msg: S,
311 ) -> Self {
312 let msg = msg.into();
313 Self::Other {
314 source: Box::new(source),
315 msg: if msg.is_empty() { None } else { Some(msg) },
316 }
317 }
318
319 #[must_use]
323 pub fn device<S: Into<String>>(
324 source: impl std::error::Error + Send + Sync + 'static,
325 msg: S,
326 ) -> Self {
327 let msg = msg.into();
328 Self::DeviceError {
329 source: Box::new(source),
330 msg: if msg.is_empty() { None } else { Some(msg) },
331 }
332 }
333}
334
335#[macro_export]
352macro_rules! error_from {
353 ($ctx:literal, $($err_ty:ty),* $(,)?) => {
354 $(
355 impl From<$err_ty> for Error {
356 fn from(e: $err_ty) -> Self {
357 let s = if $ctx.is_empty() {
358 format!("{}", std::any::type_name::<$err_ty>())
359 } else {
360 format!("{} in {}", std::any::type_name::<$err_ty>(), $ctx)
361 };
362 Error::wrap(e, s)
363 }
364 }
365 )*
366 };
367}
368
369#[macro_export]
389macro_rules! blockchain {
390 ($g:expr, $prev:ident, $($cons:expr),* $(,)?) => {{
391 $(
392 let (block, $prev) = $cons;
393 $g.add(Box::new(block));
394 )*
395 $prev
396 }};
397}
398
399error_from!(
400 "", std::sync::mpsc::RecvError,
402 std::sync::mpsc::TryRecvError,
403 std::string::FromUtf8Error,
404 std::array::TryFromSliceError,
405 std::num::TryFromIntError,
406);
407
408pub type Result<T> = std::result::Result<T, Error>;
410
411#[derive(Debug)]
413pub struct Repeat {
414 repeater: Repeater,
415 count: u64,
416}
417
418impl Repeat {
419 #[must_use]
421 pub fn finite(n: u64) -> Self {
422 Self {
423 repeater: Repeater::Finite(n),
424 count: 0,
425 }
426 }
427
428 #[must_use]
430 pub fn infinite() -> Self {
431 Self {
432 repeater: Repeater::Infinite,
433 count: 0,
434 }
435 }
436
437 #[must_use]
439 pub fn again(&mut self) -> bool {
440 self.count += 1;
441 match self.repeater {
442 Repeater::Finite(0) => {
443 log::error!(
444 "Repeat::again() called when repeat is 0, count {}",
445 self.count
446 );
447 false
448 }
449 Repeater::Finite(n) => self.count < n,
450 Repeater::Infinite => true,
451 }
452 }
453
454 #[must_use]
456 pub fn done(&self) -> bool {
457 match self.repeater {
458 Repeater::Finite(n) => self.count >= n,
459 Repeater::Infinite => false,
460 }
461 }
462
463 #[must_use]
465 pub fn count(&self) -> u64 {
466 self.count
467 }
468}
469
470#[derive(Debug)]
471enum Repeater {
472 Finite(u64),
473 Infinite,
474}
475
476pub struct Feature {
478 name: String,
479 build: bool,
480 detected: bool,
481}
482
483impl Feature {
484 #[must_use]
485 fn new<S: Into<String>>(name: S, build: bool, detected: bool) -> Self {
486 Self {
487 name: name.into(),
488 build,
489 detected,
490 }
491 }
492}
493
494#[must_use]
496pub fn environment_str(features: &[Feature]) -> String {
497 use std::fmt::Write;
498 let mut s = "Feature Build Detected\n".to_string();
499 for feature in features {
500 let _ = writeln!(
501 s,
502 "{:10} {:-5} {:-5}",
503 feature.name, feature.build, feature.detected
504 );
505 }
506 s
507}
508
509pub fn check_environment() -> Result<Vec<Feature>> {
522 #[allow(unused_mut)]
523 let mut assumptions: Vec<Feature> = Vec::new();
524 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
525 {
526 assumptions.push(Feature::new(
527 "FMA",
528 cfg!(target_feature = "fma"),
529 is_x86_feature_detected!("fma"),
530 ));
531 assumptions.push(Feature::new(
532 "SSE",
533 cfg!(target_feature = "sse"),
534 is_x86_feature_detected!("sse"),
535 ));
536 assumptions.push(Feature::new(
537 "SSE3",
538 cfg!(target_feature = "sse3"),
539 is_x86_feature_detected!("sse3"),
540 ));
541 assumptions.push(Feature::new(
542 "AVX",
543 cfg!(target_feature = "avx"),
544 is_x86_feature_detected!("avx"),
545 ));
546 assumptions.push(Feature::new(
547 "AVX2",
548 cfg!(target_feature = "avx2"),
549 is_x86_feature_detected!("avx2"),
550 ));
551 }
552
553 #[cfg(all(
559 feature = "simd",
560 any(target_arch = "riscv32", target_arch = "riscv64")
561 ))]
562 {
563 assumptions.push(Feature::new(
564 "Vector",
565 cfg!(target_feature = "v"),
566 std::arch::is_riscv_feature_detected!("v"),
567 ));
568 }
569
570 let errs: Vec<_> = assumptions
571 .iter()
572 .filter_map(|f| {
573 if f.build && !f.detected {
574 Some(format!(
575 "Feature {} assumed by build flags but not detected",
576 f.name
577 ))
578 } else {
579 None
580 }
581 })
582 .collect();
583 if errs.is_empty() {
584 Ok(assumptions)
585 } else {
586 Err(Error::msg(format!("{errs:?}")))
587 }
588}
589
590pub fn parse_verbosity(in_s: &str) -> std::result::Result<usize, String> {
607 use std::str::FromStr;
608 log::Level::from_str(in_s)
609 .map_err(|e| format!("{e}. Valid values are: error, warn, info, debug, trace"))
610 .map(|v| v as usize - 1)
611}
612
613pub fn parse_frequency(in_s: &str) -> std::result::Result<f64, String> {
638 let s_binding;
639 let s = if in_s.contains('_') {
640 s_binding = in_s.replace('_', "");
642 s_binding.as_str()
643 } else {
644 in_s
645 };
646 let (nums, mul) = {
647 let last = match s.chars().last() {
648 None => return Err("empty string is not a frequency".into()),
649 Some(ch) => ch.to_lowercase().next().ok_or("Empty string")?,
650 };
651 if s.len() > 1 {
652 let rest = &s[..(s.len() - 1)];
653 match last {
654 'k' => (rest, 1_000.0),
655 'm' => (rest, 1_000_000.0),
656 'g' => (rest, 1_000_000_000.0),
657 _ => (s, 1.0),
658 }
659 } else {
660 (s, 1.0)
661 }
662 };
663 Ok(nums.parse::<f64>().map_err(|e| {
664 format!("Invalid number {in_s}: {e}. Has to be a float with optional k/m/g suffix")
665 })? * mul)
666}
667
668pub trait Sample: Copy + Default + Send + Sync + 'static {
670 type Type;
672
673 #[must_use]
675 fn size() -> usize;
676
677 fn parse(data: &[u8]) -> Result<Self::Type>;
684
685 #[must_use]
687 fn serialize(&self) -> Vec<u8>;
688}
689
690impl Sample for Complex {
691 type Type = Complex;
692 fn size() -> usize {
693 std::mem::size_of::<Self>()
694 }
695 fn parse(data: &[u8]) -> Result<Self::Type> {
696 if data.len() != Self::size() {
697 return Err(Error::msg(format!(
698 "Tried to parse Complex from {} bytes",
699 data.len()
700 )));
701 }
702 let i = Float::from_le_bytes(data[0..Self::size() / 2].try_into()?);
703 let q = Float::from_le_bytes(data[Self::size() / 2..].try_into()?);
704 Ok(Complex::new(i, q))
705 }
706 fn serialize(&self) -> Vec<u8> {
707 let mut ret = Vec::new();
708 ret.extend(Float::to_le_bytes(self.re));
709 ret.extend(Float::to_le_bytes(self.im));
710 ret
711 }
712}
713
714impl Sample for Float {
715 type Type = Float;
716 fn size() -> usize {
717 std::mem::size_of::<Self>()
718 }
719 fn parse(data: &[u8]) -> Result<Self::Type> {
720 if data.len() != Self::size() {
721 return Err(Error::msg(format!(
722 "Tried to parse Float from {} bytes",
723 data.len()
724 )));
725 }
726 Ok(Float::from_le_bytes(data[0..Self::size()].try_into()?))
727 }
728 fn serialize(&self) -> Vec<u8> {
729 Float::to_le_bytes(*self).to_vec()
730 }
731}
732
733impl Sample for u8 {
734 type Type = u8;
735 fn size() -> usize {
736 std::mem::size_of::<Self>()
737 }
738 fn parse(data: &[u8]) -> Result<Self::Type> {
739 if data.len() != Self::size() {
740 return Err(Error::msg(format!(
741 "Tried to parse u8 from {} bytes",
742 data.len()
743 )));
744 }
745 Ok(data[0])
746 }
747 fn serialize(&self) -> Vec<u8> {
748 vec![*self]
749 }
750}
751
752impl Sample for u32 {
753 type Type = u32;
754 fn size() -> usize {
755 4
756 }
757 fn parse(data: &[u8]) -> Result<Self::Type> {
758 if data.len() != Self::size() {
759 return Err(Error::msg(format!(
760 "Tried to parse u32 from {} bytes",
761 data.len()
762 )));
763 }
764 Ok(u32::from_le_bytes(data[0..Self::size()].try_into()?))
765 }
766 fn serialize(&self) -> Vec<u8> {
767 u32::to_le_bytes(*self).to_vec()
768 }
769}
770
771impl Sample for i32 {
772 type Type = i32;
773 fn size() -> usize {
774 std::mem::size_of::<Self>()
775 }
776 fn parse(data: &[u8]) -> Result<Self::Type> {
777 if data.len() != Self::size() {
778 return Err(Error::msg(format!(
779 "Tried to parse i32 from {} bytes",
780 data.len()
781 )));
782 }
783 Ok(i32::from_le_bytes(data[0..Self::size()].try_into()?))
784 }
785 fn serialize(&self) -> Vec<u8> {
786 i32::to_le_bytes(*self).to_vec()
787 }
788}
789
790#[allow(clippy::len_without_is_empty)]
792pub trait Len {
793 #[must_use]
795 fn len(&self) -> usize;
796}
797impl<T> Len for Vec<T> {
798 fn len(&self) -> usize {
799 self.len()
800 }
801}
802
803#[cfg(test)]
804#[cfg_attr(coverage_nightly, coverage(off))]
805pub mod tests {
806 use super::*;
808
809 pub fn assert_almost_equal_complex(left: &[Complex], right: &[Complex]) {
813 assert_eq!(
814 left.len(),
815 right.len(),
816 "\nleft: {left:?}\nright: {right:?}",
817 );
818 for i in 0..left.len() {
819 let dist = (left[i] - right[i]).norm_sqr().sqrt();
820 if dist > 0.001 {
821 assert_eq!(
822 left[i], right[i],
823 "\nElement {i}:\nleft: {left:?}\nright: {right:?}",
824 );
825 }
826 }
827 }
828
829 pub fn assert_almost_equal_float(left: &[Float], right: &[Float]) {
833 assert_eq!(
834 left.len(),
835 right.len(),
836 "\nleft: {left:?}\nright: {right:?}",
837 );
838 for i in 0..left.len() {
839 let dist = (left[i] - right[i]).sqrt();
840 if dist > 0.001 {
841 assert_eq!(left[i], right[i], "\nleft: {left:?}\nright: {right:?}");
842 }
843 }
844 }
845
846 #[test]
847 fn check_env() -> Result<()> {
848 assert!(!environment_str(&check_environment()?).is_empty());
849 Ok(())
850 }
851
852 #[test]
853 fn error_wrap() {
854 use std::error::Error as SysError;
855 let e = Error::msg("foo");
856 assert!(matches![e, Error::Plain(_)]);
857 let _e2: &dyn std::error::Error = &e;
858 let e_str = e.to_string();
859 assert_eq!(e_str, "An error occurred: foo");
860 let e3 = Error::wrap(e, "foo");
861 assert!(matches![e3, Error::Other { source: _, msg: _ }]);
862 let e4 = e3.source().unwrap();
863 assert_eq!(e_str, e4.to_string());
864 let e5 = e4.downcast_ref::<Error>().unwrap();
865 assert!(matches![e5, Error::Plain(_)]);
866 }
867
868 #[test]
869 fn frequency() {
870 for (i, want) in &[
871 ("", None),
872 (".", None),
873 ("k", None),
874 ("r", None),
875 (".k", None),
876 ("0", Some(0.0f64)),
877 ("0.", Some(0.0f64)),
878 ("0.0", Some(0.0f64)),
879 (".3", Some(0.3f64)),
880 (".3k", Some(300.0f64)),
881 ("3.k", Some(3_000.0f64)),
882 ("100", Some(100.0)),
883 ("123k", Some(123_000.0)),
884 ("123kk", None),
885 ("123.78922K", Some(123_789.22)),
886 ("321m", Some(321_000_000.0)),
887 ("2.45g", Some(2_450_000_000.0)),
888 ("100r", None),
889 ("r100", None),
890 ("10k0", None),
891 ("100_000", Some(100_000.0)),
892 ("_1_2_3._4_", Some(123.4)),
893 ] {
894 let got = parse_frequency(i);
895 match (got, want) {
896 (Err(_), None) => {}
897 (Ok(got), None) => panic!("For {i} got {got}, want error"),
898 (Err(e), Some(want)) => panic!("For {i} got error {e:?}, want {want}"),
899 (Ok(got), Some(want)) if got == *want => {}
900 (Ok(got), Some(want)) => panic!("For {i} got {got} want {want}"),
901 }
902 }
903 }
904
905 #[test]
906 fn repeat_test_infinite() {
907 let mut r = Repeat::infinite();
908 for n in 0..100 {
909 assert_eq!(n, r.count());
910 assert!(!r.done());
911 assert!(r.again());
912 }
913 }
914
915 #[test]
916 fn repeat_test_none() {
917 let mut r = Repeat::finite(0);
918 assert_eq!(0, r.count());
919 assert!(r.done());
920 assert!(!r.again());
921 assert_eq!(1, r.count());
922 assert!(r.done());
923 assert!(!r.again());
924 assert_eq!(2, r.count());
925 }
926
927 #[test]
928 fn repeat_test_one() {
929 let mut r = Repeat::finite(1);
930 assert_eq!(0, r.count());
931 assert!(!r.done());
932
933 assert!(!r.again());
934 assert_eq!(1, r.count());
935 assert!(r.done());
936
937 assert!(!r.again());
938 assert_eq!(2, r.count());
939 assert!(r.done());
940 }
941
942 #[test]
943 fn repeat_test_three() {
944 let mut r = Repeat::finite(3);
945 assert_eq!(0, r.count());
946 assert!(!r.done());
947
948 assert!(r.again());
949 assert_eq!(1, r.count());
950 assert!(!r.done());
951
952 assert!(r.again());
953 assert_eq!(2, r.count());
954 assert!(!r.done());
955
956 assert!(!r.again());
957 assert_eq!(3, r.count());
958 assert!(r.done());
959 }
960}