use std::collections::BTreeMap; use std::fs::OpenOptions; use std::io::Read; use asterix_parser::asterix::uap::providers::Provider; use asterix_parser::asterix::uap_json::enums::{AttributeItem, AttributeType, AttributeValueType, ConstraintType, DataItemType, DataItemValueType, DataType, DenominatorType, ElementType, ElementValueType, LsbType, Uap}; use asterix_parser::asterix::uap_json::structures::{DataItemRule, DataRecord}; use asterix_parser::asterix::uap_json::traits::Describe; use bitvec::prelude::*; use json::stringify; use thiserror::Error; use asterix_parser::asterix::category::{Category, CategoryIndex, CategoryKey}; use asterix_parser::asterix::Context; #[derive(Error, Debug)] pub enum ParseError { #[error("category not found")] CategoryNotFound { category_code: String }, #[error("Message informed length [{informed}] doesn't match current length [{current}]")] BadMessageInformedLength { informed: usize, current: usize }, #[error("UAP definition not found for {uap_name}")] UapDefinitionNotFound { uap_name: String }, #[error("Parser unforeseen dependency relation")] ParserUnforeseenDependecyRelation, #[error("Could not open UAP JSON definition file")] OpenUapJsonDefinitionError } #[derive(Default, Clone)] pub struct FSpecInfo { pub len: u8, pub fspec:BTreeMap } #[derive(Clone)] pub struct AttributeConstraint { constraint_type: ConstraintType, limit_value: AttributeConstraintLimit } #[derive(Clone)] pub enum AttributeConstraintLimit { SignedInteger { value: i32 }, } #[derive(Clone)] pub enum AttributeLsb { Integer { value: i32 }, Real { value: f64 } } #[derive(Default, Clone) ] pub struct Attribute { pub name: String, pub title: String, pub bits: BitVec, pub value_type: String, pub signed: Option, pub constraints: Option>, pub lsb: Option, pub unit: Option, pub description: Option } #[test] pub(crate) fn test_asterix_parse() -> anyhow::Result<()> { let _cat034_1_29_definition = "resources/uaps/cat034_1_29_definition.json"; let _cat048_1_30_definition = "resources/uaps/cat048_1_30_definition.json"; let _cat048_1_31_definition = "resources/uaps/cat048_1_31_definition.json"; let my_file_name = _cat048_1_31_definition; let mut myfile = match OpenOptions::new() .read(true) .write(false) .create(false) .open(my_file_name) { Ok(f) => f, Err(e) => panic!("Error opening file {}", e), }; let mut raw_json = String::new(); myfile.read_to_string(&mut raw_json).unwrap(); let trimmed_json = raw_json.trim(); let deserialized:DataRecord = match serde_json::from_str(&trimmed_json) { Ok(d) => d, Err(_) => { return Err(ParseError::OpenUapJsonDefinitionError.into())} }; let mut indent_level = 0 as usize; let _description = deserialized.describe(&mut indent_level); let mut message_octets: Vec = vec![]; if my_file_name.contains("048") { message_octets .append(&mut vec![ 0x30, // CAT048 0x00, 0x30, // LEN: 48 octets 0xFD, 0xF7, 0x02, // FSPEC 1, 2, 3 : 0x19, 0xC9, // 010: SAC/SIC 0x35, 0x6D, 0x4D, // 140: Time of day 0xA0, // 020: Target Report Desc 0xC5, 0xAF, 0xF1, 0xE0, // 040: Position in Polar Co-ordinates 0x02, 0x00, // 070: Mode-3/A Code 0x05, 0x28, // 090: Flight Leve 0x3C, 0x66, 0x0C, // 220: Aircraft Address 0x10, 0xC2, 0x36, 0xD4, 0x18, 0x20, // 240: Aircraft Identification 0x01, 0xC0, 0x78, 0x00, 0x31, 0xBC, 0x00, 0x00, 0x40, // 250: BDS Register Data 0x0D, 0xEB, // 161: Track Number 0x07, 0xB9, 0x58, 0x2E, // 200: Calculated Track Velocity 0x41, 0x00, // 170: Track Status 0x20, 0xF5 // 230: ACAS Capability and Flight Status ]); } else { message_octets .append(&mut vec![ 0x22, // CAT034 0x00, 0x10, // LEN: 48 octets 0xf6, // FSPEC 1 0x19, 0x0e, // 010, Data Source Identifier 0x02, // 000, Message Type 0x3a, 0x69,0x2b, // 030, Time of Day 0x40, // 020, Sector Number 0x88, 0x40, 0x40, // 050, System Configuration and Status 0x80, 0x00 // 060, System Processing Mode ]); } let message = parse_message(&deserialized, &message_octets)?; describe_message_attributes(message); // describe_message{message}; Ok(()) // println!("Message description: "); // println!("{description}"); } fn describe_message_attributes(message: BTreeMap) { for attribute in message { println!(); println!("key:[{}], bits length[{:02}] - bits:{}]", attribute.0, attribute.1.bits.len(), attribute.1.bits); print!(" Title: {:?}", attribute.1.title); if attribute.1.description.is_some() { print!(", description{:?}", attribute.1.description); } println!(); if attribute.1.signed.is_some() { println!(" Signed: {}", attribute.1.signed.unwrap()); } if attribute.1.unit.is_some() { println!(" Unit: {}", attribute.1.unit.unwrap()); } if attribute.1.constraints.is_some() { match attribute.1.constraints { Some(c) => { for constraint in c { let constraint_str = match constraint.constraint_type { ConstraintType::Less => { stringify!(ConstraintType::Less ) }, ConstraintType::Great => { stringify!(ConstraintType::Great ) }, ConstraintType::LessOrEqual => { stringify!(ConstraintType::LessOrEqual ) }, ConstraintType::GreatOrEqual => { stringify!(ConstraintType::GreatOrEqual ) }, }; let constraint_value = match constraint.limit_value { AttributeConstraintLimit::SignedInteger { value } => value.to_string(), }; println!(" Constraint: {} {} ", constraint_str, constraint_value); } }, None => (), } } if attribute.1.lsb.is_some() { match attribute.1.lsb { Some(e) => { let lsb_value = match e { AttributeLsb::Integer { value } => value.to_string(), AttributeLsb::Real { value } => format!("{:15.7}", value), }; println!(" LSB: {} ", lsb_value); }, None => (), } } } } fn parse_message(data_record: &DataRecord, octets: &Vec) -> anyhow::Result> { let mut attributes_map = BTreeMap::::new(); let asterix_context = Context::new()?; let cat_index = match CategoryIndex::from_u8(data_record.number) { Some(c) => c, None => return Err(ParseError::CategoryNotFound { category_code: data_record.number.to_string() }.into()) }; let category_key = CategoryKey { index: cat_index, edition: data_record.edition.clone(), provider: Provider::Standard }; let category = get_category(asterix_context, category_key, octets[0])?; let mut category_attribute = Attribute::default(); category_attribute.name = category.key.index.as_string(); category_attribute.description = Some(category.description); attributes_map.insert(stringify("message_category"), category_attribute); let octets_self_intormed_length = octets[1] as usize * 256 + octets[2] as usize; if octets_self_intormed_length != octets.len() { return Err(ParseError::BadMessageInformedLength { informed: octets_self_intormed_length, current: octets.len() }.into()); } let category_prefix = format!("{}", category.key.index.as_str()); let mut current_index = 3 as usize; let expected_frns = data_record.catalogue.len() as u8; let fspec_info: FSpecInfo = get_fspec_array(octets, current_index, expected_frns); current_index += fspec_info.len as usize; describe_fspec(&fspec_info); let data_items_map = find_present_data_item_definitions( &fspec_info.fspec, &data_record.uap, &data_record.catalogue)?; list_present_data_item_definitions(&data_items_map); let mut frn_bits = BTreeMap::>::new(); let mut calc_len_current_index = usize::from(current_index); for data_item_entry in &data_items_map { let data_item_length = match &data_item_entry.1.rule { DataItemType::ContextFree { value } => { let primary_field_length = match value { DataItemValueType::Element { rule:_, size } => usize::from(*size), DataItemValueType::Group { items } => { find_group_length_in_bits(items)? }, DataItemValueType::Extended { items } => { find_extended_length_in_bits(items, octets, calc_len_current_index)? }, DataItemValueType::Repetitive { rep, variation} => { find_repetitive_length_in_bits(rep, variation, octets, calc_len_current_index)? }, DataItemValueType::Compound { fspec, items } => { find_compound_length_in_bits(fspec, items, octets, calc_len_current_index)? }, DataItemValueType::Explicit { expl:_ } => 0_usize, // to calculate, }; primary_field_length }, }; assert_eq!(0, data_item_length%8); let start_octet = calc_len_current_index; let end_octet = start_octet + (data_item_length/8); let bits = octets[start_octet..end_octet].view_bits::().to_bitvec(); // println!("Found bits for data item [{}], bits{}", data_item_entry.1.name, bits.to_string()); frn_bits.insert(*data_item_entry.0, bits); calc_len_current_index += data_item_length/8; } assert_eq!(octets_self_intormed_length, calc_len_current_index); attributes_map = find_message_attributes(&category_prefix, &data_items_map, &frn_bits)?; Ok(attributes_map) } fn find_message_attributes( category_prefix: &String, data_items_map: &BTreeMap, frn_bits: &BTreeMap>) -> anyhow::Result> { let mut found_attributes = BTreeMap::::new(); for data_item_entry in data_items_map { let data_item_prefix = format!("I{}", &data_item_entry.1.name); let data_item_bits = frn_bits[data_item_entry.0].to_bitvec(); let mut frn_consumed_bits = 0_usize; match &data_item_entry.1.rule { DataItemType::ContextFree { value } => match value { DataItemValueType::Element { rule, size } => { let mut attribute = Attribute::default(); // Direct Element on a dataitem has no name, so we will give one based on the title attribute.name = format!("{}_{}_{}", *category_prefix, data_item_prefix.as_str() , data_item_entry.1.title.replace(" ", "_").to_uppercase().as_str()); let last_bit = frn_consumed_bits + *size as usize; attribute.bits = data_item_bits[frn_consumed_bits..last_bit].to_bitvec(); fill_dataitem_element_attributes(rule, &mut attribute); found_attributes.insert(attribute.name.to_owned(), attribute); }, DataItemValueType::Group { items } => { let group_attributes = fill_group_attributes(&category_prefix, &data_item_prefix, items, &mut frn_consumed_bits, data_item_bits)?; for attribute in group_attributes { found_attributes.insert(attribute.name.to_owned(), attribute); } }, DataItemValueType::Extended { items:_ } => (), DataItemValueType::Repetitive { rep:_, variation:_ } => (), DataItemValueType::Compound { fspec:_, items:_ } => (), DataItemValueType::Explicit { expl:_ } => (), }, } } Ok(found_attributes) } fn fill_group_attributes( category_prefix: &str, data_item_prefix: &str, items: &Vec>, frn_consumed_bits: &mut usize, data_item_bits: BitVec) -> anyhow::Result> { let mut group_attributes = Vec::::new(); for item in items { let inner_item = match item { Some(e) => e, None => continue, }; match inner_item { AttributeItem::SpareEntry { length, spare:_ } => { *frn_consumed_bits += length; continue } , AttributeItem::AttributeEntry(v) => { let mut attribute = Attribute::default(); attribute.name = format!("{}_{}_{}", category_prefix, data_item_prefix, v.name); attribute.title = v.title.to_owned(); attribute.description = v.description.to_owned(); match &v.rule { AttributeType::ContextFree { value } => match value { AttributeValueType::Element { rule:_, size } => { let start_bit = *frn_consumed_bits; let last_bit = *frn_consumed_bits + *size as usize; attribute.bits = data_item_bits[start_bit..last_bit].to_bitvec(); *frn_consumed_bits = last_bit; }, _ => { return Err(ParseError::ParserUnforeseenDependecyRelation.into())} }, } group_attributes.push(attribute); }, }; } Ok(group_attributes) } fn fill_dataitem_element_attributes( rule: &ElementType, attribute: &mut Attribute) { match rule { ElementType::ContextFree { value } => match value { ElementValueType::Fx => (), ElementValueType::Integer { constraints:_, signed:_} => (), ElementValueType::Quantity { constraints, lsb, signed, unit } => { let mut found_constraints = Vec::::new(); for constraint in constraints { let constraint_value = match constraint.value { DataType::Integer { value } => value, }; let attribute_constraint = AttributeConstraint { constraint_type: constraint.constraint_type, limit_value: AttributeConstraintLimit::SignedInteger { value: constraint_value } }; found_constraints.push(attribute_constraint); } if found_constraints.len() > 0 { attribute.constraints = Some(found_constraints); } attribute.signed = Some(*signed); let lsb = match lsb { LsbType::Integer { value } => AttributeLsb::Integer { value: *value }, LsbType::Div { denominator, numerator } => { let num = match numerator { DataType::Integer { value } => *value as f64, }; let den = match denominator { DenominatorType::Pow { base, exponent } => { base.powf(*exponent) }, }; AttributeLsb::Real { value: num/den } }, }; attribute.lsb = Some(lsb); attribute.unit = Some(unit.to_owned()); }, ElementValueType::Raw => (), ElementValueType::Regular { size:_ } => (), ElementValueType::String { variation:_ } => (), ElementValueType::Table { values:_ } => (), }, } } fn find_compound_length_in_bits( _fspec: &Option, items: &Vec>, octets: &Vec, calc_len_current_index: usize) -> anyhow::Result { // let mut local_len_current_index = calc_len_current_index; let minimum_expected_frns = 7_u8; let fspec_info: FSpecInfo = get_fspec_array(octets, calc_len_current_index, minimum_expected_frns); // local_len_current_index += fspec_info.len as usize; describe_fspec(&fspec_info); let mut item_count = 1_u8; let mut items_length = usize::from(fspec_info.len)*8; // 8 bits in an fspec octet; for item in items { match item { Some(_) => (), None => { item_count += 1; continue; }, }; if fspec_info.fspec[&item_count] == false { item_count += 1; continue; } item_count += 1; items_length += find_attribute_item_length_in_bits(item)? } Ok(items_length) } fn find_repetitive_length_in_bits( rep: &ElementValueType, variation: &AttributeValueType, octets: &Vec, calc_len_current_index: usize) -> anyhow::Result { let multiplier_bits = match rep { ElementValueType::Regular { size } => usize::from(*size), _ => { return Err(ParseError::ParserUnforeseenDependecyRelation.into())}, }; assert_eq!(0, multiplier_bits%8); let start_octet = calc_len_current_index; let end_octet = start_octet + (multiplier_bits/8); let bitslice = octets[start_octet..end_octet].view_bits::(); let multiplier = bitslice.load::(); let repetitive_len = match variation { AttributeValueType::Group { items } => { find_group_length_in_bits(items)? } _ => { return Err(ParseError::ParserUnforeseenDependecyRelation.into())}, }; Ok(multiplier_bits + repetitive_len * multiplier) } fn find_extended_length_in_bits( items: &Vec>, octets: &Vec, calc_len_current_index: usize) -> anyhow::Result { let mut local_current_index = calc_len_current_index; let mut item_len = 0_usize; let mut fx_set = true; for item in items { if !fx_set { break } item_len += find_attribute_item_length_in_bits(&item)?; if item_len%8 == 0 { // end of octed, will check fx value to continue or not let bits = octets[local_current_index].view_bits::().to_bitvec(); if bits[7] == true { local_current_index += 1; } else { fx_set = false; } } } Ok(item_len) } fn find_attribute_item_length_in_bits(item: &Option) -> anyhow::Result { let item_length = match item { Some(i) => { let entry_len = match i { AttributeItem::SpareEntry { length, spare } => { if *spare {*length } else { 0_usize } }, AttributeItem::AttributeEntry(e) => { let a_len = match &e.rule { AttributeType::ContextFree { value } => { let len = match value { AttributeValueType::Element { rule:_, size } => usize::from(*size), AttributeValueType::Group { items } => find_group_length_in_bits(items)?, // to calculate, _ => { return Err(ParseError::ParserUnforeseenDependecyRelation.into())} }; len }, }; a_len }, }; entry_len }, None => 1_usize // would be 0_usize, but it happens that in exteded data item, the fx bit is falling into this category, // because it is null in .json definition file }; Ok(item_length) } fn find_group_length_in_bits(items: &Vec>) -> anyhow::Result { let mut len = 0_usize; for item in items { match item { Some(aitem) => { match aitem { AttributeItem::SpareEntry { length, spare:_ } => { len += length; }, AttributeItem::AttributeEntry(aentry) => { match &aentry.rule { AttributeType::ContextFree { value } => match value { AttributeValueType::Element { rule: _, size } => { len += usize::from(*size); }, _ => { return Err(ParseError::ParserUnforeseenDependecyRelation.into())} }, } }, } }, None => (), } } Ok(len) } fn get_category(context:Context, category_key: CategoryKey, category_octet: u8) -> anyhow::Result { let category = match context.categories.get(&category_key) { Some(c) => c.clone(), None => return Err((ParseError::CategoryNotFound { category_code: category_octet.to_string()}).into()) }; Ok(category.clone()) } fn get_fspec_array(octets: &[u8], current_index: usize, expected_frns: u8) -> FSpecInfo { let mut fx = true; let mut frn:u8 = 0; let mut fspec_info = FSpecInfo::default(); let mut local_current_index = current_index; fspec_info.len = 1; while fx { let octet = octets[local_current_index]; let fx_octet = octet.view_bits::().to_bitvec(); let mut bit_count = 0; for bit in fx_octet { if bit_count == 7 { // if fx bit is true then we have more data_items to check fx = bit; if bit { local_current_index += 1; fspec_info.len += 1; } } else { frn += 1; fspec_info.fspec.insert(frn, bit); } // println!("Bit[{bit_count}]:{bit}"); bit_count += 1; } } while frn < expected_frns { frn += 1; fspec_info.fspec.insert(frn, false); } /* for fspecitem in &fspec_info.fspec { println!("{}: {}", fspecitem.0, fspecitem.1) } */ fspec_info } fn describe_fspec(fspec_info: &FSpecInfo) { println!("FRN configuration: "); let mut frnh = String::new(); let mut frnx = String::new(); let mut frnl: String = String::new(); for frn in &fspec_info.fspec { frnh += format!("| {:02}", frn.0).as_str(); frnx += format!("| {:2}", if *frn.1 {"X"} else {" "}).as_str(); frnl += "+---"; } frnl += "+"; frnh += "|"; frnx += "|"; println!("{}", frnl); println!("{}", frnh); println!("{}", frnl); println!("{}", frnx); println!("{}", frnl); } fn find_present_data_item_definitions<'a> ( fspec: &'a BTreeMap, uap: &Uap, catalogue: &'a [DataItemRule]) -> anyhow::Result> { let mut data_items_map = BTreeMap::::new(); let uap_items = match &uap { Uap::Uap { items } => items, }; /* let mut data_item_code = match uap_items.first() { Some(c) => c.clone(), None => { return Err(ParseError::UapDefinitionsEmpty.into()); }, }; */ for frn in fspec.into_iter().filter(| x | *x.1 ) { let index = (frn.0 - 1) as usize; let uap_data_item = format!("{}", &uap_items[usize::from(index)]); let catalog_entry = catalogue.into_iter() .find(|x| x.name == uap_data_item); let data_item_def = match catalog_entry { Some(d) => d, None => { return Err(ParseError::UapDefinitionNotFound { uap_name: uap_data_item}.into()); }, }; data_items_map.insert(*frn.0, data_item_def); } Ok(data_items_map) } fn list_present_data_item_definitions(data_items_map: &BTreeMap) { println!(); println!("Data items present in the given message"); for present_data_item in data_items_map { let p_frn = present_data_item.0; let p_data_item_rule = present_data_item.1; println!("FRN: {:02}: {}, {}", p_frn, p_data_item_rule.name, p_data_item_rule.title ); } println!(); } /* fn process_items(attribute_prefix: &str, attributes_map: &mut BTreeMap, octets: &Vec, current_index: &mut usize, data_items_map: &BTreeMap) { for data_item_def in data_items_map { let attribute_key = format!("{}{}", attribute_prefix, data_item_def.1.name); let attributes = get_data_items_attributes(current_index, octets, data_item_def.1); for attribute in attributes { let key = format!("{}_{}_{}", attribute_prefix, data_item_def.1.name, attribute.name); attributes_map.insert(key, attribute); } } } fn get_data_items_attributes(current_index: &mut usize, octets: &Vec, data_item_def: &DataItemRule) -> Vec { let attributes: Vec = match &data_item_def.rule { DataItemType::ContextFree { value } => { let attributes: Vec = match value { DataItemValueType::Element { rule, size } => todo!(), DataItemValueType::Group { items } => get_group_attributes(current_index, octets, value, &data_item_def.name), DataItemValueType::Extended { items } => todo!(), DataItemValueType::Repetitive { rep, variation } => todo!(), DataItemValueType::Compound { fspec, items } => todo!(), DataItemValueType::Explicit { expl } => todo!(), }; attributes } }; attributes } fn get_group_attributes(current_index: &mut usize, octets: &Vec, value: &DataItemValueType, data_item_name: &String) -> Vec { let attributes = Vec::::new(); match value { DataItemValueType::Element { rule, size } => process_element_attributes(current_index, octets, rule, *size as usize, data_item_name), DataItemValueType::Group { items } => todo!(), DataItemValueType::Extended { items } => todo!(), DataItemValueType::Repetitive { rep, variation } => todo!(), DataItemValueType::Compound { fspec, items } => todo!(), DataItemValueType::Explicit { expl } => todo!(), }; attributes } fn process_element_attributes(current_index: &mut usize, octets: &Vec, rule: &ElementType, size: usize, data_item_name: &String) -> Vec { let mut attributes = Vec::::new(); match rule { ElementType::ContextFree { value } => match value { ElementValueType::Fx => (), // todo: currently could not identify anything to return // ElementValueType::Group { items } => todo!(), ElementValueType::Integer { constraints, signed } => todo!(), ElementValueType::Quantity { constraints, lsb, signed, unit } => todo!(), ElementValueType::Raw => { let last_octet_index = *current_index + (size/8) - 1; let element_octets = octets[*current_index..last_octet_index].to_vec(); let extracted_bits = element_octets.view_bits::().to_bitvec(); let attribute = Attribute { name: data_item_name.clone(), bits: extracted_bits, value_type: "Raw".to_owned(), unit: None, description: None, lsb: None, title: String, signed: None, constraints: todo!(), }; attributes.push(attribute) }, ElementValueType::Regular { size } => todo!(), ElementValueType::String { variation } => todo!(), ElementValueType::Table { values } => todo!(), }, } attributes } fn process_attribute_items(octets: &Vec, current_index: &mut usize, items: &Vec, data_item_name: &String) { for item in items { match &item.rule { AttributeType::ContextFree { value } => match value { AttributeValueType::Element { rule, size } => todo!(), AttributeValueType::Group { items } => todo!(), AttributeValueType::Repetitive { rep, variation } => todo!(), AttributeValueType::Table { values } => todo!(), } } } } */