33 #include "eds_reader.h"
36 #include "global_config.h"
43 #include <boost/property_tree/ptree.hpp>
44 #include <boost/property_tree/ini_parser.hpp>
45 #include <boost/algorithm/string/predicate.hpp>
46 #include <boost/algorithm/string/trim.hpp>
50 EDSReader::EDSReader(std::unordered_map<Address, Entry>& dictionary, std::unordered_map<std::string, Address>& name_to_address)
51 : m_dictionary(dictionary), m_name_to_address(name_to_address)
56 DEBUG_LOG_EXHAUSTIVE(
"Trying to read EDS file " << filename);
58 boost::property_tree::ini_parser::read_ini(filename, m_ini);
60 }
catch (
const std::exception& e) {
61 ERROR(
"[EDSReader::load_file] Could not open file: "<<e.what());
71 for (
const auto& section_node : m_ini) {
72 const std::string& section_name = section_node.first;
79 if (std::regex_match(section_name, std::regex(
"[[:xdigit:]]{1,4}"))) {
82 DEBUG_LOG_EXHAUSTIVE(
"Section "<<section_name<<
" corresponds to index "<<index<<
".");
83 success = parse_index(section_name, index) && success;
99 }
catch (std::regex_error& e) {
100 ERROR(
"[EDSReader::import_entries] " << parse_regex_error(e.code(), section_name));
110 bool EDSReader::parse_index(
const std::string& section, uint16_t index) {
112 std::string str_object_type = trim(m_ini.get(section+
".ObjectType",
""));
114 uint8_t object_code = (uint8_t) ObjectType::VAR;
115 if (str_object_type.empty()) {
116 DEBUG_LOG(
"Field ObjectType missing. Assuming ObjectType::VAR (according to DS 306 V1.3 page 16).");
122 if (object_code == (uint8_t) ObjectType::VAR) {
123 return parse_var(section, index, 0);
124 }
else if ((object_code == (uint8_t) ObjectType::RECORD) || (object_code == (uint8_t) ObjectType::ARRAY)) {
125 return parse_array_or_record(section, index);
128 DEBUG_LOG(
"This is not a variable and no array. Ignoring.")
133 bool EDSReader::parse_var(const std::
string& section, uint16_t index, uint8_t subindex, const std::
string& name_prefix) {
135 std::string var_name =
Utils::escape(trim(m_ini.get(section+
".ParameterName",
"")));
137 if (var_name.empty()) {
138 ERROR(
"[EDSReader::parse_var] Field ParameterName missing");
142 if (!name_prefix.empty()) {
143 var_name = name_prefix +
"/" + var_name;
146 DEBUG_LOG(
"[EDSReader::parse_var] Parsing variable "<<section<<
": "<<var_name);
148 std::string str_sub_number = trim(m_ini.get(section+
".SubNumber",
""));
149 std::string str_object_type = trim(m_ini.get(section+
".ObjectType",
""));
150 std::string str_data_type = trim(m_ini.get(section+
".DataType",
""));
151 std::string str_low_limit = trim(m_ini.get(section+
".LowLimit",
""));
152 std::string str_high_limit = trim(m_ini.get(section+
".HighLimit",
""));
153 std::string str_access_type = trim(m_ini.get(section+
".AccessType",
""));
154 std::string str_default_value = trim(m_ini.get(section+
".DefaultValue",
""));
155 std::string str_pdo_mapping = trim(m_ini.get(section+
".PDOMapping",
""));
156 std::string str_obj_flags = trim(m_ini.get(section+
".ObjFlags",
""));
159 entry.name = var_name;
162 entry.subindex = subindex;
165 entry.is_generic =
true;
168 if (entry.type == Type::invalid) {
169 ERROR(
"[EDSReader::parse_var] "<<entry.name<<
": Ignoring entry due to unsupported data type.");
176 const Address address = Address{entry.index,entry.subindex};
184 while (m_name_to_address.count(var_name)>0) {
186 WARN(
"[EDSReader::parse_var] Entry "<<var_name<<
" already exists. Adding or increasing counter.");
190 if (std::regex_match(var_name, matches, std::regex(
"^(.+)_([[:xdigit:]]{1,3})$"))) {
191 assert(matches.size()>2);
194 var_name = std::string(matches[1])+
"_"+std::to_string(count);
196 var_name = var_name+
"_1";
198 }
catch (std::regex_error& e) {
199 WARN(
"[EDSReader::parse_var] "<<parse_regex_error(e.code(), var_name));
203 DEBUG_LOG(
"[EDSReader::parse_var] New entry name: "<<var_name);
204 entry.name = var_name;
208 DEBUG_LOG(
"[EDSReader::parse_var] Inserting entry "<<var_name<<
".");
213 m_dictionary.insert(std::make_pair(address, std::move(entry)));
214 m_name_to_address.insert(std::make_pair(var_name,address));
222 if (m_dictionary.count(address)>0) {
224 if (m_dictionary[address].name != var_name) {
225 DEBUG_LOG(
"[EDSReader::parse_var] Manufacturer-specific entry name \""<<m_dictionary[address].name<<
"\" differs from CiA standard \""<<var_name<<
"\".");
226 if (m_name_to_address.count(var_name)>0) {
227 WARN(
"[EDSReader::parse_var] Conflict with existing mapping \""<<var_name<<
"\"->0x"
228 <<std::hex<<m_name_to_address[var_name].index<<
"sub"<<std::dec<<m_name_to_address[var_name].subindex<<
".");
232 m_name_to_address.insert(std::make_pair(var_name,address));
233 DEBUG_LOG(
"[EDSReader::parse_var] Added additional name-to-address mapping.");
236 DEBUG_LOG_EXHAUSTIVE(
"[EDSReader::parse_var] Standard conformal entry: "<<var_name);
239 DEBUG_LOG_EXHAUSTIVE(
"[EDSReader::parse_var] Standard entry not available in manufacturer-specific EDS: "<<var_name);
273 bool EDSReader::parse_array_or_record(
const std::string& section, uint16_t index) {
275 std::string array_name =
Utils::escape(trim(m_ini.get(section+
".ParameterName",
"")));
277 if (array_name.empty()) {
278 ERROR(
"[EDSReader::parse_array_or_record] Field ParameterName missing");
282 DEBUG_LOG_EXHAUSTIVE(
"[EDSReader::parse_array_or_record] Parsing array/record "<<section<<
": "<<array_name);
284 for (
const auto& section_node : m_ini) {
285 const std::string& section_name = section_node.first;
288 if (boost::starts_with(section_name, section)) {
290 DEBUG_LOG_EXHAUSTIVE(
"[EDSReader::parse_array_or_record] Found record/array entry: "<<section_name);
296 if (std::regex_match(section_name, matches, std::regex(
"([[:xdigit:]]{1,4})sub([[:xdigit:]]{1,2})"))) {
298 assert(matches.size()>2);
301 bool success = parse_var(section_name, index, subindex, array_name);
303 ERROR(
"[EDSReader::parse_array_or_record] Malformed variable entry: "<<section_name);
307 }
else if (section_name == section) {
311 ERROR(
"[EDSReader::parse_array_or_record] Malformed array entry: "<<section_name);
315 }
catch (std::regex_error& e) {
316 ERROR(
"[EDSReader::parse_array_or_record] "<<parse_regex_error(e.code(), section_name));
329 std::string EDSReader::parse_regex_error(
const std::regex_constants::error_type& etype,
const std::string element_name)
const {
332 case std::regex_constants::error_collate:
333 result =
"error_collate: invalid collating element request";
335 case std::regex_constants::error_ctype:
336 result =
"error_ctype: invalid character class";
338 case std::regex_constants::error_escape:
339 result =
"error_escape: invalid escape character or trailing escape";
341 case std::regex_constants::error_backref:
342 result =
"error_backref: invalid back reference";
344 case std::regex_constants::error_brack:
345 result =
"error_brack: mismatched bracket([ or ])";
347 case std::regex_constants::error_paren:
348 result =
"error_paren: mismatched parentheses(( or ))";
350 case std::regex_constants::error_brace:
351 result =
"error_brace: mismatched brace({ or })";
353 case std::regex_constants::error_badbrace:
354 result =
"error_badbrace: invalid range inside a { }";
356 case std::regex_constants::error_range:
357 result =
"erro_range: invalid character range(e.g., [z-a])";
359 case std::regex_constants::error_space:
360 result =
"error_space: insufficient memory to handle this regular expression";
362 case std::regex_constants::error_badrepeat:
363 result =
"error_badrepeat: a repetition character (*, ?, +, or {) was not preceded by a valid regular expression";
365 case std::regex_constants::error_complexity:
366 result =
"error_complexity: the requested match is too complex";
368 case std::regex_constants::error_stack:
369 result =
"error_stack: insufficient memory to evaluate a match";
375 result +=
" in element " + element_name;
379 std::string EDSReader::trim(
const std::string& str) {
380 std::string result = str;
381 size_t found = result.find(
"#");
382 if (found!=std::string::npos) {
383 result = result.substr(0,found);
385 boost::algorithm::trim(result);
static unsigned long long hexstr_to_uint(std::string str)
Converts a string containing a hexadecimal numer to unsigned.
static Type type_code_to_type(uint16_t code)
Maps type codes from an EDS file to a data type.
bool import_entries()
Import entries from the EDS file into the given dictionary.
static bool eds_reader_mark_entries_as_generic
If this is set to true, EDSReader will mark all entries as generic (Entry::is_generic) This is used i...
static std::string escape(const std::string &str)
Converts entry names to lower case and replaces all spaces and '-' by underscores.
static AccessType string_to_access_type(std::string str)
Converts a string representation of AccessType from an EDS file to AccessType.
EDSReader(std::unordered_map< Address, Entry > &dictionary, std::unordered_map< std::string, Address > &name_to_address)
Constructor.
static unsigned long long decstr_to_uint(std::string str)
Converts a string containing a decimal numer to unsigned.
bool load_file(std::string filename)
Loads an EDS file from file system.
static bool eds_reader_just_add_mappings
If this is set to true, EDSReader won't create any entries, but just adds name-to-address mappings fo...