use super::{
AccessType, EnumeratedValue, EnumeratedValuesUsage, ModifiedWriteValues, ReadAction,
WriteConstraint,
};
use crate::output::{DimArrayIndex, SvdConstant};
use regex::Regex;
use serde::Deserialize;
#[derive(Debug, Deserialize, Eq, PartialEq, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Field {
pub derived_from: Option<String>,
pub dim: Option<SvdConstant>,
pub dim_increment: Option<SvdConstant>,
pub dim_index: Option<SvdConstant>,
pub dim_name: Option<String>,
pub dim_array_index: Option<DimArrayIndex>,
pub name: String,
pub description: Option<String>,
pub bit_offset: Option<SvdConstant>,
pub bit_width: Option<SvdConstant>,
pub lsb: Option<SvdConstant>,
pub msb: Option<SvdConstant>,
pub bit_range: Option<String>,
pub access: Option<AccessType>,
pub modified_write_values: Option<ModifiedWriteValues>,
pub write_constraint: Option<WriteConstraint>,
pub read_action: Option<ReadAction>,
pub enumerated_values: Option<Vec<EnumeratedValues>>,
}
#[derive(Debug, Eq, PartialEq)]
pub enum FieldMask {
OffsetWidth {
offset: SvdConstant,
width: Option<SvdConstant>,
},
LsbMsb {
lsb: SvdConstant,
msb: SvdConstant,
},
None,
}
impl Field {
pub fn get_mask(&self) -> FieldMask {
self.try_to_get_mask().unwrap()
}
fn try_to_get_mask(&self) -> Result<FieldMask, String> {
match (
(&self.bit_offset, &self.bit_width),
(&self.lsb, &self.msb),
&self.bit_range,
) {
((Some(offset), width), (None, None), None) => Ok(FieldMask::OffsetWidth {
offset: offset.clone(),
width: width.clone(),
}),
((None, None), (Some(lsb), Some(msb)), None) => Ok(FieldMask::LsbMsb {
lsb: lsb.clone(),
msb: msb.clone(),
}),
((None, None), (None, None), Some(pattern)) => {
let re = Regex::new(r"\[(?P<msb>(.+)):(?P<lsb>(.+))]").unwrap();
let caps = match re.captures(&pattern) {
None => {return Err(format!( "Invalid format for bit range pattern: Could not match regular expression: {}", pattern ).to_string())}
Some(caps) => caps
};
let msb = SvdConstant::from_string(caps.name("msb").unwrap().as_str().to_string());
let lsb = SvdConstant::from_string(caps.name("lsb").unwrap().as_str().to_string());
match (msb, lsb) {
(Ok(msb),Ok(lsb)) => {
Ok(FieldMask::LsbMsb { lsb, msb })
},
_ => Err(format!("Invalid format for bit range pattern: Could not convert msb or lsb in SvdConstant: {}",pattern).to_string())
}
}
((None, None), (None, None), None) => Ok(FieldMask::None),
_ => Err(format!("Invalid mask setup: bit_offset: {:?}, bit_width: {:?}, lsb: {:?}, msb: {:?}, bit_range: {:?}", self.bit_offset, self.bit_width,
self.lsb, self.msb,
self.bit_range).to_string()),
}
}
pub fn post_check(&self) -> Result<(), String> {
self.try_to_get_mask()?;
Ok(())
}
}
#[derive(Debug, Deserialize, Eq, PartialEq, Clone)]
#[serde(rename_all = "camelCase")]
pub struct EnumeratedValues {
pub derived_from: Option<String>,
pub name: Option<String>,
pub header_enum_name: Option<String>,
pub usage: Option<EnumeratedValuesUsage>,
pub enumerated_value: Vec<EnumeratedValue>,
}
#[cfg(test)]
mod tests {
use crate::output::{Field, FieldMask, SvdConstant};
fn get_field_with_bitrange(bit_range: &str) -> Field {
Field {
derived_from: None,
dim: None,
dim_increment: None,
dim_index: None,
dim_name: None,
dim_array_index: None,
name: "".to_string(),
description: None,
bit_offset: None,
bit_width: None,
lsb: None,
msb: None,
bit_range: Some(bit_range.to_string()),
access: None,
modified_write_values: None,
write_constraint: None,
read_action: None,
enumerated_values: None,
}
}
#[test]
fn test_invalid_bitrange_regex() {
let field = get_field_with_bitrange("invalid pattern");
let result = field.try_to_get_mask();
assert!(result.is_err());
assert_eq!(result.err().unwrap(), "Invalid format for bit range pattern: Could not match regular expression: invalid pattern")
}
#[test]
fn test_invalid_bitrange_lsb_msb_to_number() {
let field = get_field_with_bitrange("[an:345]");
assert!(field.try_to_get_mask().is_err());
}
#[test]
fn test_no_mask_at_all() {
let field = Field {
derived_from: None,
dim: None,
dim_increment: None,
dim_index: None,
dim_name: None,
dim_array_index: None,
name: "".to_string(),
description: None,
bit_offset: None,
bit_width: None,
lsb: None,
msb: None,
bit_range: None,
access: None,
modified_write_values: None,
write_constraint: None,
read_action: None,
enumerated_values: None,
};
assert_eq!(field.get_mask(), FieldMask::None)
}
#[test]
fn test_mask_offset_width() {
let field = Field {
derived_from: None,
dim: None,
dim_increment: None,
dim_index: None,
dim_name: None,
dim_array_index: None,
name: "".to_string(),
description: None,
bit_offset: Some(SvdConstant { value: 77 }),
bit_width: Some(SvdConstant { value: 88 }),
lsb: None,
msb: None,
bit_range: None,
access: None,
modified_write_values: None,
write_constraint: None,
read_action: None,
enumerated_values: None,
};
assert_eq!(
field.get_mask(),
FieldMask::OffsetWidth {
offset: SvdConstant { value: 77 },
width: Some(SvdConstant { value: 88 })
}
)
}
#[test]
fn test_mask_lsb_msb() {
let field = Field {
derived_from: None,
dim: None,
dim_increment: None,
dim_index: None,
dim_name: None,
dim_array_index: None,
name: "".to_string(),
description: None,
bit_offset: None,
bit_width: None,
lsb: Some(SvdConstant { value: 77 }),
msb: Some(SvdConstant { value: 88 }),
bit_range: None,
access: None,
modified_write_values: None,
write_constraint: None,
read_action: None,
enumerated_values: None,
};
assert_eq!(
field.get_mask(),
FieldMask::LsbMsb {
lsb: SvdConstant { value: 77 },
msb: SvdConstant { value: 88 }
}
)
}
}