|
|
|
@@ -2,14 +2,16 @@ use std::{collections::HashMap, u64, vec};
|
|
|
|
|
|
|
|
|
|
|
|
use crate::SignalFormat;
|
|
|
|
use crate::SignalFormat;
|
|
|
|
|
|
|
|
|
|
|
|
/// Record information obtained from the header.
|
|
|
|
/// Holds the essential header information about the record, like the amount of
|
|
|
|
|
|
|
|
/// signals, and the sampling frequency.
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// Only the `name`, `signal_count`, and `sampling_freq` values are required by default.
|
|
|
|
/// Only the `name`, `signal_count`, and `sampling_freq` values are required by
|
|
|
|
|
|
|
|
/// default.
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
struct Record {
|
|
|
|
struct Record {
|
|
|
|
name: String,
|
|
|
|
name: String,
|
|
|
|
seg_num: Option<u64>,
|
|
|
|
seg_num: Option<u64>,
|
|
|
|
signal_count: u64,
|
|
|
|
signal_count: usize,
|
|
|
|
sampling_freq: u64,
|
|
|
|
sampling_freq: u64,
|
|
|
|
counter_freq: Option<u64>,
|
|
|
|
counter_freq: Option<u64>,
|
|
|
|
base_counter_val: Option<u64>,
|
|
|
|
base_counter_val: Option<u64>,
|
|
|
|
@@ -19,7 +21,11 @@ struct Record {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl Record {
|
|
|
|
impl Record {
|
|
|
|
/// Attempts to generate the record information from a string of the argument line
|
|
|
|
/// Attempts to generate the record information from a string of the argument
|
|
|
|
|
|
|
|
/// line that's provided by the WFDB header file
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Returns a `Result<Record, &str>`, with the error field potentially
|
|
|
|
|
|
|
|
/// describing why the parsing operation failed
|
|
|
|
pub fn from_str(argument_line: &str) -> Result<Record, &str> {
|
|
|
|
pub fn from_str(argument_line: &str) -> Result<Record, &str> {
|
|
|
|
let args: Vec<&str> = argument_line.split(' ').collect();
|
|
|
|
let args: Vec<&str> = argument_line.split(' ').collect();
|
|
|
|
if args.len() < 2 {
|
|
|
|
if args.len() < 2 {
|
|
|
|
@@ -27,7 +33,7 @@ impl Record {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let name = args[0].to_string();
|
|
|
|
let name = args[0].to_string();
|
|
|
|
let seg_num: Option<u64>;
|
|
|
|
let seg_num: Option<u64>;
|
|
|
|
let sig_count: u64;
|
|
|
|
let sig_count: usize;
|
|
|
|
let sampling_freq: u64;
|
|
|
|
let sampling_freq: u64;
|
|
|
|
// Everything else is initialized with None, this is for sake of me not getting a stroke
|
|
|
|
// Everything else is initialized with None, this is for sake of me not getting a stroke
|
|
|
|
let mut counter_freq: Option<u64> = None;
|
|
|
|
let mut counter_freq: Option<u64> = None;
|
|
|
|
@@ -53,7 +59,7 @@ impl Record {
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
seg_num = None;
|
|
|
|
seg_num = None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
match seg_sig[0].parse::<u64>() {
|
|
|
|
match seg_sig[0].parse::<usize>() {
|
|
|
|
Ok(value) => {
|
|
|
|
Ok(value) => {
|
|
|
|
sig_count = value;
|
|
|
|
sig_count = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -134,6 +140,8 @@ impl Record {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Keys for all the data that can possibly be parsed from the values appended
|
|
|
|
|
|
|
|
/// to the ADC block
|
|
|
|
#[derive(Debug, Eq, Hash, PartialEq)]
|
|
|
|
#[derive(Debug, Eq, Hash, PartialEq)]
|
|
|
|
enum AdcBlockKeys {
|
|
|
|
enum AdcBlockKeys {
|
|
|
|
Gain,
|
|
|
|
Gain,
|
|
|
|
@@ -141,7 +149,9 @@ enum AdcBlockKeys {
|
|
|
|
Units
|
|
|
|
Units
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Holds the information relevant to individual signals and their specifications
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// By minimum, only carries the `filename`, `format`, and `adc_zero` attributes
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
struct SignalSpec {
|
|
|
|
struct SignalSpec {
|
|
|
|
filename: String,
|
|
|
|
filename: String,
|
|
|
|
@@ -161,11 +171,14 @@ struct SignalSpec {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl SignalSpec {
|
|
|
|
impl SignalSpec {
|
|
|
|
/// Attempts to generate a valid signal specification struct from a supplied string.
|
|
|
|
/// Attempts to generate a valid signal specification struct from a supplied
|
|
|
|
/// Returns a `Result<SignalSpec, &str>` containing possible error information.
|
|
|
|
/// string.
|
|
|
|
|
|
|
|
/// Returns a `Result<SignalSpec, &str>` containing possible error information
|
|
|
|
|
|
|
|
/// relevant to parsing failures.
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// ## Arguments
|
|
|
|
/// ## Arguments
|
|
|
|
/// - `argument_line` - argument line for the signal specification, taken from header file
|
|
|
|
/// - `argument_line` - argument line for the signal specification, taken
|
|
|
|
|
|
|
|
/// from header file
|
|
|
|
pub fn from_str(argument_line: &str) -> Result<SignalSpec, &str> {
|
|
|
|
pub fn from_str(argument_line: &str) -> Result<SignalSpec, &str> {
|
|
|
|
let args: Vec<&str> = argument_line.split(' ').collect();
|
|
|
|
let args: Vec<&str> = argument_line.split(' ').collect();
|
|
|
|
|
|
|
|
|
|
|
|
@@ -308,8 +321,10 @@ impl SignalSpec {
|
|
|
|
Ok(value) => {
|
|
|
|
Ok(value) => {
|
|
|
|
initial_val = Some(value);
|
|
|
|
initial_val = Some(value);
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Err(_) => {} // Standard: If this field is missing, adc_zero value is presumed.
|
|
|
|
// Standard: If this field is missing,
|
|
|
|
|
|
|
|
// the adc_zero value is presumed.
|
|
|
|
// We do this on the data parsing part.
|
|
|
|
// We do this on the data parsing part.
|
|
|
|
|
|
|
|
Err(_) => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if args.len() <= 6 {
|
|
|
|
if args.len() <= 6 {
|
|
|
|
@@ -361,6 +376,8 @@ impl SignalSpec {
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Parses the WFDB signal format from the format number, if it exists and
|
|
|
|
|
|
|
|
/// is implemented
|
|
|
|
fn parse_format(formatnum: u64) -> SignalFormat {
|
|
|
|
fn parse_format(formatnum: u64) -> SignalFormat {
|
|
|
|
match formatnum {
|
|
|
|
match formatnum {
|
|
|
|
16 => SignalFormat::Format16,
|
|
|
|
16 => SignalFormat::Format16,
|
|
|
|
@@ -370,6 +387,9 @@ impl SignalSpec {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Holds all the possible data from the WFDB header file, those being the record
|
|
|
|
|
|
|
|
/// line data and all the possible signal specifications present on the following
|
|
|
|
|
|
|
|
/// lines
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct Header {
|
|
|
|
pub struct Header {
|
|
|
|
record: Option<Record>,
|
|
|
|
record: Option<Record>,
|
|
|
|
@@ -386,8 +406,13 @@ impl Header {
|
|
|
|
Header { record: None, signal_specs: vec![] }
|
|
|
|
Header { record: None, signal_specs: vec![] }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Creates a Header from a supplied Record struct.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Initializes the signal_specs vector with the correct capacity provided
|
|
|
|
|
|
|
|
/// by the record.
|
|
|
|
fn from_record(record: Record) -> Header {
|
|
|
|
fn from_record(record: Record) -> Header {
|
|
|
|
Header { record: Some(record), signal_specs: vec![] }
|
|
|
|
let capacity = record.signal_count;
|
|
|
|
|
|
|
|
Header { record: Some(record), signal_specs: Vec::with_capacity(capacity) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn add_signal_spec(&mut self, spec: SignalSpec) {
|
|
|
|
fn add_signal_spec(&mut self, spec: SignalSpec) {
|
|
|
|
@@ -402,13 +427,16 @@ impl Header {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Attempts to parse the header file
|
|
|
|
/// Attempts to parse the header file.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Returns a Result either containing the `Header` struct, or the
|
|
|
|
|
|
|
|
/// error string describing why we couldn't parse the header.
|
|
|
|
pub fn parse_header(header_data: &str) -> Result<Header, &str> {
|
|
|
|
pub fn parse_header(header_data: &str) -> Result<Header, &str> {
|
|
|
|
let header_lines: Vec<&str> = header_data.split("\n").collect();
|
|
|
|
let header_lines: Vec<&str> = header_data.split("\n").collect();
|
|
|
|
let mut found_record: bool = false;
|
|
|
|
let mut found_record: bool = false;
|
|
|
|
let mut header: Header = Header::new();
|
|
|
|
let mut header: Header = Header::new();
|
|
|
|
let mut specs_read: u64 = 0;
|
|
|
|
let mut specs_read: usize = 0;
|
|
|
|
let mut specs_max: u64 = 0;
|
|
|
|
let mut specs_max: usize = 0;
|
|
|
|
for line in header_lines {
|
|
|
|
for line in header_lines {
|
|
|
|
// Ignore commented lines
|
|
|
|
// Ignore commented lines
|
|
|
|
if line.starts_with("#") {
|
|
|
|
if line.starts_with("#") {
|