configurable logging level, winsize, adcthresh, request rate

This commit is contained in:
Данила Горнушко 2024-05-29 12:30:27 +03:00
parent 81d68e1429
commit 5d217e6c5a

View file

@ -1,8 +1,8 @@
use anyhow::{Context, Result};
use clap::Parser;
use clap::{arg, Parser};
use crc::{Crc, CRC_16_IBM_3740};
use hound::{SampleFormat, WavSpec, WavWriter};
use log::{debug, error, info, LevelFilter};
use log::{debug, error, info, trace, LevelFilter};
use serialport::SerialPort;
use std::collections::HashMap;
use std::io::{BufRead, BufReader, Read, Write};
@ -26,19 +26,38 @@ struct Args {
#[arg(short, long, default_value_t = 115_200)]
baud_rate: u32,
/// Turn debugging information on
#[arg(long)]
adcthresh: Option<u32>,
#[arg(long)]
winsize: Option<u32>,
#[arg(long, default_value_t = 10, help = "Value in Hz")]
requst_rate: u32,
#[arg(short, long)]
first_sample: bool,
#[arg(short, long, action = clap::ArgAction::Count)]
debug: u8,
verbose: u8,
}
fn main() {
// Initialize logging with debug level
let args = Args::parse();
let log_level = match args.verbose {
0 => LevelFilter::Info,
1 => LevelFilter::Debug,
_ => LevelFilter::Trace,
};
env_logger::builder()
.filter_level(LevelFilter::Info)
.filter_level(log_level)
.format_timestamp_millis()
.init();
let args = Args::parse();
assert!(
args.requst_rate >= 1 && args.requst_rate <= 100,
"Request rate must be in 1..100 range!"
);
debug!("Trying to open the serial port: {}", args.port);
let mut port = match serialport::new(args.port, args.baud_rate).open() {
@ -62,8 +81,8 @@ fn main() {
panic!("Couldn't detect hailsens!")
}
get_threshold(&mut port, args.device_id).expect("Couldn't get threshold");
let winsize = get_winsize(&mut port, args.device_id).expect("Couldn't get winsize") as usize;
get_set_threshold(&mut port, args.device_id, args.adcthresh).expect("Couldn't get threshold");
let winsize = get_set_winsize(&mut port, args.device_id, args.winsize).expect("Couldn't get winsize") as usize;
debug!("Expected buf size is: {}", exp_buf_size(winsize));
let spec = WavSpec {
@ -73,7 +92,7 @@ fn main() {
sample_format: SampleFormat::Int,
};
info!("Starting main loop...");
debug!("Starting main loop...");
let running = Arc::new(AtomicBool::new(true));
let r = running.clone();
// Set up Ctrl-C handler
@ -82,7 +101,7 @@ fn main() {
r.store(false, Ordering::SeqCst);
})
.unwrap();
info!("Press Ctrl-C to stop");
debug!("Press Ctrl-C to stop");
let mut last_chunk_id: u32 = 0;
let mut err_counter: u32 = 0;
@ -101,27 +120,29 @@ fn main() {
}
};
if cur_chunk_id != last_chunk_id {
info!("New data available: {}", cur_chunk_id);
info!("Getting new chunk!");
debug!("New data available: {}", cur_chunk_id);
debug!("Getting new chunk!");
match get_chunk(&mut port, args.device_id, args.baud_rate, winsize) {
Some(data) => {
info!("Received new data with len: {}", data.len());
debug!("Received new data with len: {}", data.len());
let timestamp_ms = current_timestamp_ms();
let filename = format!("./out/wave_{}.wav", timestamp_ms);
// Create a new WAV file
let mut writer = WavWriter::create(&filename, spec)
.expect("Can't create new WAV file!");
let mut writer =
WavWriter::create(&filename, spec).expect("Can't create new WAV file!");
let mut i16_writer = writer.get_i16_writer(data.len() as u32);
for sample in data {
unsafe {
i16_writer.write_sample_unchecked(sample);
}
}
i16_writer.flush().expect("Something went wrong while writing WAV file");
i16_writer
.flush()
.expect("Something went wrong while writing WAV file");
info!("WAV file {} has been written.", filename);
err_counter = err_counter.saturating_sub(1);
last_chunk_id = cur_chunk_id;
}
@ -131,7 +152,7 @@ fn main() {
}
}
}
std::thread::sleep(Duration::from_millis(20));
std::thread::sleep(Duration::from_millis((1000 / args.requst_rate) as u64));
}
}
@ -151,13 +172,19 @@ fn get_stats(port: &mut Box<dyn SerialPort>, id: u32) -> Result<u32> {
let num_since_startup: u32 = split.next().context("Missing value")?.parse()?;
let _num_since_last_read: u32 = split.next().context("Missing value")?.parse()?;
let _num_in_10min: u32 = split.next().context("Missing value")?.parse()?;
debug!("Got num_since_startup: {}", num_since_startup);
trace!("Got num_since_startup: {}", num_since_startup);
Ok(num_since_startup)
}
fn get_winsize(port: &mut Box<dyn SerialPort>, id: u32) -> Option<u32> {
fn get_set_winsize(port: &mut Box<dyn SerialPort>, id: u32, new_winsize: Option<u32>) -> Option<u32> {
let command;
if let Some(i) = new_winsize {
debug!("Setting new winsize: {i}");
command = format!("@{id} winsize {i}\n");
} else {
command = format!("@{} winsize\n", id);
}
debug!("Getting window size...");
let command = format!("@{} winsize\n", id);
let response = process_command(port, command).unwrap_or_default();
let winsize_str = response.split_whitespace().nth(3);
match winsize_str {
@ -173,8 +200,18 @@ fn get_winsize(port: &mut Box<dyn SerialPort>, id: u32) -> Option<u32> {
}
}
fn get_threshold(port: &mut Box<dyn SerialPort>, id: u32) -> Option<u32> {
let command = format!("@{} adcthresh\n", id);
fn get_set_threshold(
port: &mut Box<dyn SerialPort>,
id: u32,
new_threshold: Option<u32>,
) -> Option<u32> {
let command;
if let Some(i) = new_threshold {
debug!("Setting new threshold: {i}");
command = format!("@{id} adcthresh {i}\n");
} else {
command = format!("@{} adcthresh\n", id);
}
let response = process_command(port, command).unwrap_or_default();
let number_str = response.split_whitespace().nth(3);
match number_str {
@ -259,16 +296,16 @@ fn get_sample_rate(port: &mut Box<dyn SerialPort>, id: u32) -> u32 {
}
fn process_command(port: &mut Box<dyn SerialPort>, command: String) -> Option<String> {
debug!("Writing command to the serial port: {}", command);
trace!("Writing command to the serial port: {}", command);
port.write_all(command.as_bytes())
.expect("Failed to write to serial port!");
port.flush().expect("Failed to flush serial port!");
debug!("Waiting for response from the serial port...");
trace!("Waiting for response from the serial port...");
let mut reader = BufReader::new(port);
let mut response = String::new();
match reader.read_line(&mut response) {
Ok(_) => {
debug!("Received response from the serial port");
trace!("Received response from the serial port");
Some(response)
}
Err(ref e) if e.kind() == std::io::ErrorKind::TimedOut => {
@ -304,16 +341,16 @@ fn get_chunk(
win_size: usize,
) -> Option<Vec<i16>> {
let command = format!("@{} convbuf\n", id);
debug!("Writing convbuf to the serial port");
trace!("Writing convbuf to the serial port");
port.write_all(command.as_bytes())
.expect("Failed to write to serial port!");
port.flush().expect("Failed to flush serial port!");
debug!("Waiting for response from the serial port...");
trace!("Waiting for response from the serial port...");
let mut adc_buffer: Vec<u8> = vec![0; MAX_DATA_LEN];
std::thread::sleep(calculate_timeout(baud_rate, exp_buf_size(win_size)));
match port.read(adc_buffer.as_mut_slice()) {
Ok(len) => {
debug!("Buffer is received with len: {}", len);
trace!("Buffer is received with len: {}", len);
}
Err(ref e) if e.kind() == std::io::ErrorKind::TimedOut => {
debug!("Read timed out");
@ -323,11 +360,11 @@ fn get_chunk(
panic!("Failed to read from serial port: {}", e);
}
}
debug!("Checking header...");
trace!("Checking header...");
if header_is_ok(&adc_buffer) {
debug!("Header is ok!");
trace!("Header is ok!");
} else {
error!("Header is corrupted!");
trace!("Header is corrupted!");
return None;
}
let data_slice = adc_buffer.get(4..4 + win_size * 2);
@ -350,7 +387,7 @@ fn get_chunk(
);
None
} else {
debug!("CRC is correct!");
trace!("CRC is correct!");
// converting raw bytes to correct format
Some(convert_to_i16(data_buf))
@ -364,7 +401,11 @@ fn get_chunk(
}
fn convert_to_i16(buffer: &[u8]) -> Vec<i16> {
assert_eq!(buffer.len() % 2, 0, "Buffer length must be a multiple of 2.");
assert_eq!(
buffer.len() % 2,
0,
"Buffer length must be a multiple of 2."
);
let len = buffer.len() / 2; // Number of i16 elements
let ptr = buffer.as_ptr() as *const i16;