diff --git a/.gitignore b/.gitignore index ea8c4bf..10d3408 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +/out/ \ No newline at end of file diff --git a/.idea/hailsens_logger.iml b/.idea/hailsens_logger.iml index cf84ae4..766e15c 100644 --- a/.idea/hailsens_logger.iml +++ b/.idea/hailsens_logger.iml @@ -3,6 +3,7 @@ + diff --git a/src/main.rs b/src/main.rs index 7cf231d..93326ef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,15 @@ use anyhow::{Context, Result}; use clap::Parser; use crc::{Crc, CRC_16_IBM_3740}; +use hound::{SampleFormat, WavSpec, WavWriter}; use log::{debug, error, info, LevelFilter}; use serialport::SerialPort; use std::collections::HashMap; use std::io::{BufRead, BufReader, Read, Write}; +use std::slice; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use std::time::Duration; -use hound::{WavSpec, SampleFormat, WavWriter}; -use std::fs::File; use std::time::{SystemTime, UNIX_EPOCH}; const MAX_DATA_LEN: usize = 1024 * 2 + 4 + 2; @@ -70,7 +70,7 @@ fn main() { channels: 1, sample_rate: get_sample_rate(&mut port, args.device_id), bits_per_sample: 16, - sample_format: hound::SampleFormat::Int, + sample_format: SampleFormat::Int, }; info!("Starting main loop..."); @@ -106,6 +106,22 @@ fn main() { match get_chunk(&mut port, args.device_id, args.baud_rate, winsize) { Some(data) => { info!("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 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"); + info!("WAV file {} has been written.", filename); + err_counter = err_counter.saturating_sub(1); last_chunk_id = cur_chunk_id; } @@ -286,7 +302,7 @@ fn get_chunk( id: u32, baud_rate: u32, win_size: usize, -) -> Option> { +) -> Option> { let command = format!("@{} convbuf\n", id); debug!("Writing convbuf to the serial port"); port.write_all(command.as_bytes()) @@ -335,7 +351,9 @@ fn get_chunk( None } else { debug!("CRC is correct!"); - Some(data_buf.to_vec()) + // converting raw bytes to correct format + + Some(convert_to_i16(data_buf)) } } _ => { @@ -345,6 +363,19 @@ fn get_chunk( } } +fn convert_to_i16(buffer: &[u8]) -> Vec { + 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; + + // Safety: We are transmuting the buffer from u8 to i16, ensuring that the types have the same size + // and alignment requirements. We also ensure that the buffer length is valid for transmuting. + unsafe { + let i16_slice = slice::from_raw_parts(ptr, len); + i16_slice.to_vec() // Convert the slice to a Vec + } +} + fn header_is_ok(vec: &[u8]) -> bool { vec.get(0..4) .map(|bytes| u32::from_be_bytes(bytes.try_into().unwrap())) @@ -358,7 +389,8 @@ fn exp_buf_size(win_size: usize) -> usize { fn current_timestamp_ms() -> u128 { let start = SystemTime::now(); - let since_the_epoch = start.duration_since(UNIX_EPOCH) + let since_the_epoch = start + .duration_since(UNIX_EPOCH) .expect("Time went backwards"); since_the_epoch.as_millis() }