tramex_tools/interface/parser/
parser_rrc.rs

1//! Parser for RRC traces
2use super::ParsingError;
3use super::hex_extractor::extract_binary_from_lines;
4use crate::data::{AdditionalInfos, Trace};
5use crate::interface::association::TraceRelation;
6use std::str::FromStr;
7
8use crate::interface::{layer::Layer, types::Direction};
9
10use super::{FileParser, LayerParser, ParsedHeader};
11
12#[derive(Debug, Clone)]
13/// Data structure to store the message type (from the amarisoft API)
14pub struct RRCInfos {
15    /// Direction of the message.
16    pub direction: Direction,
17
18    /// canal of the message.
19    pub canal: String,
20
21    /// Message of the canal.
22    pub canal_msg: String,
23}
24
25/// RRC Parser
26pub struct RRCParser;
27
28impl RRCParser {
29    /// Parse the lines
30    fn parse_lines(lines: &[String]) -> Vec<String> {
31        lines.to_vec()
32    }
33}
34
35impl FileParser for RRCParser {
36    fn parse_additional_infos(lines: &[String]) -> Result<AdditionalInfos, ParsingError> {
37        let line = &lines[0];
38        let parts: Vec<&str> = line.split_whitespace().collect();
39        if parts.len() < 5 {
40            return Err(ParsingError::new("Could not find enough (5) parameters".to_string(), 1));
41        }
42        let direction_result = Direction::from_str(parts[2]);
43        let binding: String = parts[5..].join(" ");
44        let concatenated: Vec<&str> = binding.split(':').collect();
45        let direction = match direction_result {
46            Ok(d) => d,
47            Err(_) => {
48                return Err(ParsingError::new(
49                    format!("The direction could not be parsed in the part {:?} of {}", parts[2], line),
50                    1,
51                ));
52            }
53        };
54        if concatenated.len() < 2 || concatenated[0].is_empty() || concatenated[1].is_empty() {
55            return Err(ParsingError::new(
56                "The canal and/or canal message could not be parsed".to_string(),
57                1,
58            ));
59        }
60        Ok(AdditionalInfos::RRCInfos(RRCInfos {
61            direction,
62            canal: concatenated[0].to_owned(),
63            canal_msg: concatenated[1].trim_start().to_owned(),
64        }))
65    }
66
67    fn parse(lines: &[String]) -> Result<Trace, ParsingError> {
68        let mtype = match Self::parse_additional_infos(lines) {
69            Ok(m) => m,
70            Err(e) => {
71                return Err(e);
72            }
73        };
74        let text = Self::parse_lines(lines);
75        let binary = extract_binary_from_lines(lines);
76
77        // Parse timestamp from first line
78        let timestamp = if let Some(first_line) = lines.first() {
79            super::parse_timestamp(first_line)?
80        } else {
81            0
82        };
83
84        let trace = Trace {
85            timestamp,
86            layer: Layer::RRC,
87            additional_infos: mtype,
88            text: Some(text),
89            binary,
90            relation: TraceRelation::default(),
91        };
92        Ok(trace)
93    }
94}
95
96impl LayerParser for RRCParser {
97    /// Parse RRC payload lines.
98    /// data_lines[0] should be "CANAL: message" (e.g. "DCCH-NR: RRC release")
99    fn parse_layer(header: &ParsedHeader, data_lines: &[String]) -> Result<AdditionalInfos, ParsingError> {
100        if data_lines.is_empty() {
101            return Err(ParsingError::new("RRC: empty data lines".to_string(), 0));
102        }
103        let first_line = &data_lines[0];
104        let concatenated: Vec<&str> = first_line.split(':').collect();
105        if concatenated.len() < 2 || concatenated[0].is_empty() || concatenated[1].is_empty() {
106            return Err(ParsingError::new(
107                format!("RRC: cannot parse canal:message from '{}'", first_line),
108                0,
109            ));
110        }
111        Ok(AdditionalInfos::RRCInfos(RRCInfos {
112            direction: header.direction.clone(),
113            canal: concatenated[0].to_owned(),
114            canal_msg: concatenated[1].trim_start().to_owned(),
115        }))
116    }
117}
118
119/// Counting Brackets
120#[inline]
121pub fn count_brackets(hay: &str) -> i16 {
122    let mut count: i16 = 0;
123    for ch in hay.chars() {
124        match ch {
125            '{' => count += 1,
126            '}' => count -= 1,
127            _ => (),
128        }
129    }
130    count
131}