lasprs 0.14.1

Library for Acoustic Signal Processing (Rust edition, with optional Python bindings via pyo3)
use anyhow::{Result, bail};
use argh::FromArgs;
use crossbeam::channel::{Receiver, TryRecvError, unbounded};
use lasprs::Flt;
use lasprs::daq::{RecordSettings, RecordStatus, Recording, StreamMgr, StreamType};
use std::{
    io, thread,
    time::{self, Duration},
};

#[derive(FromArgs, Debug)]
///Record data to h5 file, according to LASP format
struct Cli {
    /// the TOML configuration file for used stream. If not given, it uses the
    /// default stream, if available
    #[argh(option, short = 'c')]
    config_file_daq: Option<String>,

    /// file name to write recording to
    #[argh(positional)]
    filename: String,

    /// recording duration in \[s\]. Rounds down to whole seconds. If not specified, records until user presses a key
    #[argh(option, default = "0.0")]
    duration_s: Flt,

    /// start delay in \[s\]. Rounds down to whole seconds. If not specified, no
    /// start delay will be used.
    #[argh(option, default = "0.0")]
    start_delay_s: Flt,
}

fn main() -> Result<()> {
    use lasprs::daq::DaqConfig;

    let ops: Cli = argh::from_env();

    let mut smgr = StreamMgr::new();
    let stdin_channel = spawn_stdin_channel();

    if ops.start_delay_s < 0. {
        bail!("Start delay cannot be negative");
    }
    if ops.duration_s < 0. {
        bail!("Duration cannot be negative");
    }

    let start_delay = if ops.start_delay_s > 0. {
        Some(Duration::from_secs(ops.start_delay_s as u64))
    } else {
        None
    };
    let duration = if ops.duration_s > 0. {
        Some(Duration::from_secs(ops.duration_s as u64))
    } else {
        None
    };

    let settings = RecordSettings::new(
        &ops.filename,
        false,
        duration,
        start_delay,
        None,
        None,
        false,
        None,
        vec![],
    )?;

    match ops.config_file_daq {
        // No config file is given, start default input stream
        None => smgr.startDefaultInputStream()?,
        Some(filename) => {
            // If config file is given, use that.
            let file = std::fs::read_to_string(filename)?;
            let cfg = DaqConfig::deserialize_TOML_str(&file)?;
            smgr.startStream(StreamType::Input, &cfg)?;
        }
    }

    let mut r = Recording::new(settings, &mut smgr)?;

    // println!("Starting to record... Enter 'c' to cancel.");
    'infy: loop {
        use lasprs::daq::FinishedRecording;

        match r.status() {
            RecordStatus::Idle {} => println!("\nIdle"),
            RecordStatus::Waiting {} => {
                println!("Waiting in start delay...");
            }
            RecordStatus::Finished {
                finishedrecording: FinishedRecording { clipped, error, .. },
            } => {
                println!("\nRecording finished.");
                if clipped {
                    println!("Recording clipped!");
                }
                if let Some(msg) = error {
                    println!("Recording failed with an error: {msg}");
                }
                break 'infy;
            }
            RecordStatus::Recording { recorded, .. } => {
                println!("Recording...   {:.0} ms", recorded * 1000.);
            }
        };

        match stdin_channel.try_recv() {
            Ok(_key) => {
                println!("User pressed key. Manually stopping recording here.");
                match _key.to_lowercase().as_str() {
                    "c" => r.cancel(),
                    _ => r.stop(),
                }
                break 'infy;
            }
            Err(TryRecvError::Empty) => {}
            Err(TryRecvError::Disconnected) => panic!("Channel disconnected"),
        }

        sleep(500);
    }

    Ok(())
}

fn sleep(millis: u64) {
    let duration = time::Duration::from_millis(millis);
    thread::sleep(duration);
}

fn spawn_stdin_channel() -> Receiver<String> {
    let (tx, rx) = unbounded();
    thread::spawn(move || {
        loop {
            let mut buffer = String::new();
            io::stdin().read_line(&mut buffer).unwrap();
            tx.send(buffer).unwrap();
        }
    });
    rx
}