|  |  | @ -3,7 +3,6 @@ | 
			
		
	
		
		
			
				
					
					|  |  |  | #include <QFile> |  |  |  | #include <QFile> | 
			
		
	
		
		
			
				
					
					|  |  |  | #include <QFileInfo> |  |  |  | #include <QFileInfo> | 
			
		
	
		
		
			
				
					
					|  |  |  | #include <QRegularExpression> |  |  |  | #include <QRegularExpression> | 
			
		
	
		
		
			
				
					
					|  |  |  | #include <QTextStream> |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | DBCFile::DBCFile(const QString &dbc_file_name) { |  |  |  | DBCFile::DBCFile(const QString &dbc_file_name) { | 
			
		
	
		
		
			
				
					
					|  |  |  |   QFile file(dbc_file_name); |  |  |  |   QFile file(dbc_file_name); | 
			
		
	
	
		
		
			
				
					|  |  | @ -76,63 +75,123 @@ cabana::Msg *DBCFile::msg(const QString &name) { | 
			
		
	
		
		
			
				
					
					|  |  |  |   return it != msgs.end() ? &(it->second) : nullptr; |  |  |  |   return it != msgs.end() ? &(it->second) : nullptr; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | cabana::Signal *DBCFile::signal(uint32_t address, const QString name) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   auto m = msg(address); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   return m ? (cabana::Signal *)m->sig(name) : nullptr; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | void DBCFile::parse(const QString &content) { |  |  |  | void DBCFile::parse(const QString &content) { | 
			
		
	
		
		
			
				
					
					|  |  |  |   static QRegularExpression bo_regexp(R"(^BO_ (\w+) (\w+) *: (\w+) (\w+))"); |  |  |  |   msgs.clear(); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |   static QRegularExpression sg_regexp(R"(^SG_ (\w+) : (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*))"); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   static QRegularExpression sgm_regexp(R"(^SG_ (\w+) (\w+) *: (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*))"); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   static QRegularExpression msg_comment_regexp(R"(^CM_ BO_ *(\w+) *\"((?:[^"\\]|\\.)*)\"\s*;)"); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   static QRegularExpression sg_comment_regexp(R"(^CM_ SG_ *(\w+) *(\w+) *\"((?:[^"\\]|\\.)*)\"\s*;)"); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   static QRegularExpression val_regexp(R"(VAL_ (\w+) (\w+) (\s*[-+]?[0-9]+\s+\".+?\"[^;]*))"); |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   int line_num = 0; |  |  |  |   int line_num = 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |   QString line; |  |  |  |   QString line; | 
			
		
	
		
		
			
				
					
					|  |  |  |   auto dbc_assert = [&line_num, &line, this](bool condition, const QString &msg = "") { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (!condition) throw std::runtime_error(QString("[%1:%2]%3: %4").arg(filename).arg(line_num).arg(msg).arg(line).toStdString()); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   }; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   auto get_sig = [this](uint32_t address, const QString &name) -> cabana::Signal * { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     auto m = (cabana::Msg *)msg(address); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     return m ? (cabana::Signal *)m->sig(name) : nullptr; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   }; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   msgs.clear(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   QTextStream stream((QString *)&content); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   cabana::Msg *current_msg = nullptr; |  |  |  |   cabana::Msg *current_msg = nullptr; | 
			
		
	
		
		
			
				
					
					|  |  |  |   int multiplexor_cnt = 0; |  |  |  |   int multiplexor_cnt = 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |   bool seen_first = false; |  |  |  |   bool seen_first = false; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   QTextStream stream((QString *)&content); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   while (!stream.atEnd()) { |  |  |  |   while (!stream.atEnd()) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     ++line_num; |  |  |  |     ++line_num; | 
			
		
	
		
		
			
				
					
					|  |  |  |     QString raw_line = stream.readLine(); |  |  |  |     QString raw_line = stream.readLine(); | 
			
		
	
		
		
			
				
					
					|  |  |  |     line = raw_line.trimmed(); |  |  |  |     line = raw_line.trimmed(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     bool seen = true; |  |  |  |     bool seen = true; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     try { | 
			
		
	
		
		
			
				
					
					|  |  |  |       if (line.startsWith("BO_ ")) { |  |  |  |       if (line.startsWith("BO_ ")) { | 
			
		
	
		
		
			
				
					
					|  |  |  |         multiplexor_cnt = 0; |  |  |  |         multiplexor_cnt = 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |       auto match = bo_regexp.match(line); |  |  |  |         current_msg = parseBO(line); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       dbc_assert(match.hasMatch()); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       auto address = match.captured(1).toUInt(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       dbc_assert(msgs.count(address) == 0, QString("Duplicate message address: %1").arg(address)); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       current_msg = &msgs[address]; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       current_msg->address = address; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       current_msg->name = match.captured(2); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       current_msg->size = match.captured(3).toULong(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       current_msg->transmitter = match.captured(4).trimmed(); |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |       } else if (line.startsWith("SG_ ")) { |  |  |  |       } else if (line.startsWith("SG_ ")) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         parseSG(line, current_msg, multiplexor_cnt); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       } else if (line.startsWith("VAL_ ")) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         parseVAL(line); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       } else if (line.startsWith("CM_ BO_")) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         parseCM_BO(line, content, raw_line, stream); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       } else if (line.startsWith("CM_ SG_ ")) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         parseCM_SG(line, content, raw_line, stream); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         seen = false; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } catch (std::exception &e) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       throw std::runtime_error(QString("[%1:%2]%3: %4").arg(filename).arg(line_num).arg(e.what()).arg(line).toStdString()); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if (seen) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       seen_first = true; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } else if (!seen_first) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       header += raw_line + "\n"; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   for (auto &[_, m] : msgs) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     m.update(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | cabana::Msg *DBCFile::parseBO(const QString &line) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   static QRegularExpression bo_regexp(R"(^BO_ (?<address>\w+) (?<name>\w+) *: (?<size>\w+) (?<transmitter>\w+))"); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   QRegularExpressionMatch match = bo_regexp.match(line); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   if (!match.hasMatch()) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     throw std::runtime_error("Invalid BO_ line format"); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   uint32_t address = match.captured("address").toUInt(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   if (msgs.count(address) > 0) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     throw std::runtime_error(QString("Duplicate message address: %1").arg(address).toStdString()); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   // Create a new message object
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   cabana::Msg *msg = &msgs[address]; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   msg->address = address; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   msg->name = match.captured("name"); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   msg->size = match.captured("size").toULong(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   msg->transmitter = match.captured("transmitter").trimmed(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   return msg; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | void DBCFile::parseCM_BO(const QString &line, const QString &content, const QString &raw_line, const QTextStream &stream) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   static QRegularExpression msg_comment_regexp(R"(^CM_ BO_ *(?<address>\w+) *\"(?<comment>(?:[^"\\]|\\.)*)\"\s*;)"); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   QString parse_line = line; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   if (!parse_line.endsWith("\";")) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     int pos = stream.pos() - raw_line.length() - 1; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     parse_line = content.mid(pos, content.indexOf("\";", pos)); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   auto match = msg_comment_regexp.match(parse_line); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   if (!match.hasMatch()) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     throw std::runtime_error("Invalid message comment format"); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   if (auto m = (cabana::Msg *)msg(match.captured("address").toUInt())) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     m->comment = match.captured("comment").trimmed().replace("\\\"", "\""); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | void DBCFile::parseSG(const QString &line, cabana::Msg *current_msg, int &multiplexor_cnt) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   static QRegularExpression sg_regexp(R"(^SG_ (\w+) : (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*))"); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   static QRegularExpression sgm_regexp(R"(^SG_ (\w+) (\w+) *: (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*))"); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   if (!current_msg) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     throw std::runtime_error("No Message"); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   int offset = 0; |  |  |  |   int offset = 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |   auto match = sg_regexp.match(line); |  |  |  |   auto match = sg_regexp.match(line); | 
			
		
	
		
		
			
				
					
					|  |  |  |   if (!match.hasMatch()) { |  |  |  |   if (!match.hasMatch()) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     match = sgm_regexp.match(line); |  |  |  |     match = sgm_regexp.match(line); | 
			
		
	
		
		
			
				
					
					|  |  |  |     offset = 1; |  |  |  |     offset = 1; | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |       dbc_assert(match.hasMatch()); |  |  |  |   if (!match.hasMatch()) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       dbc_assert(current_msg, "No Message"); |  |  |  |     throw std::runtime_error("Invalid SG_ line format"); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       auto name = match.captured(1); |  |  |  | 
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       dbc_assert(current_msg->sig(name) == nullptr, "Duplicate signal name"); |  |  |  |   QString name = match.captured(1); | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   if (current_msg->sig(name) != nullptr) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     throw std::runtime_error("Duplicate signal name"); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   cabana::Signal s{}; |  |  |  |   cabana::Signal s{}; | 
			
		
	
		
		
			
				
					
					|  |  |  |   if (offset == 1) { |  |  |  |   if (offset == 1) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     auto indicator = match.captured(2); |  |  |  |     auto indicator = match.captured(2); | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (indicator == "M") { |  |  |  |     if (indicator == "M") { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       ++multiplexor_cnt; | 
			
		
	
		
		
			
				
					
					|  |  |  |       // Only one signal within a single message can be the multiplexer switch.
 |  |  |  |       // Only one signal within a single message can be the multiplexer switch.
 | 
			
		
	
		
		
			
				
					
					|  |  |  |           dbc_assert(++multiplexor_cnt < 2, "Multiple multiplexor"); |  |  |  |       if (multiplexor_cnt >= 2) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         throw std::runtime_error("Multiple multiplexor"); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |       s.type = cabana::Signal::Type::Multiplexor; |  |  |  |       s.type = cabana::Signal::Type::Multiplexor; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } else { |  |  |  |     } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |       s.type = cabana::Signal::Type::Multiplexed; |  |  |  |       s.type = cabana::Signal::Type::Multiplexed; | 
			
		
	
	
		
		
			
				
					|  |  | @ -150,12 +209,34 @@ void DBCFile::parse(const QString &content) { | 
			
		
	
		
		
			
				
					
					|  |  |  |   s.max = match.captured(9 + offset).toDouble(); |  |  |  |   s.max = match.captured(9 + offset).toDouble(); | 
			
		
	
		
		
			
				
					
					|  |  |  |   s.unit = match.captured(10 + offset); |  |  |  |   s.unit = match.captured(10 + offset); | 
			
		
	
		
		
			
				
					
					|  |  |  |   s.receiver_name = match.captured(11 + offset).trimmed(); |  |  |  |   s.receiver_name = match.captured(11 + offset).trimmed(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   current_msg->sigs.push_back(new cabana::Signal(s)); |  |  |  |   current_msg->sigs.push_back(new cabana::Signal(s)); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } else if (line.startsWith("VAL_ ")) { |  |  |  | } | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | void DBCFile::parseCM_SG(const QString &line, const QString &content, const QString &raw_line, const QTextStream &stream) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   static QRegularExpression sg_comment_regexp(R"(^CM_ SG_ *(\w+) *(\w+) *\"((?:[^"\\]|\\.)*)\"\s*;)"); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   QString parse_line = line; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   if (!parse_line.endsWith("\";")) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     int pos = stream.pos() - raw_line.length() - 1; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     parse_line = content.mid(pos, content.indexOf("\";", pos)); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   auto match = sg_comment_regexp.match(parse_line); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   if (!match.hasMatch()) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     throw std::runtime_error("Invalid CM_ SG_ line format"); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   if (auto s = signal(match.captured(1).toUInt(), match.captured(2))) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     s->comment = match.captured(3).trimmed().replace("\\\"", "\""); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | void DBCFile::parseVAL(const QString &line) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   static QRegularExpression val_regexp(R"(VAL_ (\w+) (\w+) (\s*[-+]?[0-9]+\s+\".+?\"[^;]*))"); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   auto match = val_regexp.match(line); |  |  |  |   auto match = val_regexp.match(line); | 
			
		
	
		
		
			
				
					
					|  |  |  |       dbc_assert(match.hasMatch()); |  |  |  |   if (!match.hasMatch()) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       if (auto s = get_sig(match.captured(1).toUInt(), match.captured(2))) { |  |  |  |     throw std::runtime_error("invalid VAL_ line format"); | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   if (auto s = signal(match.captured(1).toUInt(), match.captured(2))) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     QStringList desc_list = match.captured(3).trimmed().split('"'); |  |  |  |     QStringList desc_list = match.captured(3).trimmed().split('"'); | 
			
		
	
		
		
			
				
					
					|  |  |  |     for (int i = 0; i < desc_list.size(); i += 2) { |  |  |  |     for (int i = 0; i < desc_list.size(); i += 2) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       auto val = desc_list[i].trimmed(); |  |  |  |       auto val = desc_list[i].trimmed(); | 
			
		
	
	
		
		
			
				
					|  |  | @ -165,40 +246,6 @@ void DBCFile::parse(const QString &content) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       } |  |  |  |       } | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |     } else if (line.startsWith("CM_ BO_")) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       if (!line.endsWith("\";")) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         int pos = stream.pos() - raw_line.length() - 1; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         line = content.mid(pos, content.indexOf("\";", pos)); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       auto match = msg_comment_regexp.match(line); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       dbc_assert(match.hasMatch()); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       if (auto m = (cabana::Msg *)msg(match.captured(1).toUInt())) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         m->comment = match.captured(2).trimmed().replace("\\\"", "\""); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } else if (line.startsWith("CM_ SG_ ")) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       if (!line.endsWith("\";")) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         int pos = stream.pos() - raw_line.length() - 1; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         line = content.mid(pos, content.indexOf("\";", pos)); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       auto match = sg_comment_regexp.match(line); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       dbc_assert(match.hasMatch()); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       if (auto s = get_sig(match.captured(1).toUInt(), match.captured(2))) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         s->comment = match.captured(3).trimmed().replace("\\\"", "\""); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } else { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       seen = false; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (seen) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       seen_first = true; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } else if (!seen_first) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       header += raw_line + "\n"; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   for (auto &[_, m] : msgs) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     m.update(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | QString DBCFile::generateDBC() { |  |  |  | QString DBCFile::generateDBC() { | 
			
		
	
	
		
		
			
				
					|  |  | 
 |