Files
openvehicle-api/global/dbcparser/dbcparser.cpp
tompzf 6ed4b1534e Precommit (#1)
* first commit

* cleanup
2025-11-04 13:28:06 +01:00

2363 lines
96 KiB
C++

#include "dbcparser.h"
#include <fstream>
#include <algorithm>
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
#ifdef _MSC_VER
// Prevent warnings about uninitialized members within unions during static code analysis.
#pragma warning(push)
#pragma warning(disable : 26495)
#endif
/**
* @brief DBC namespace
*/
namespace dbc
{
/**
* @brief Internal namespace
*/
namespace internal
{
/**
* @brief Check for equality, ignoring the case.
* @param[in] rss1 Reference to the first string.
* @param[in] rss2 Reference to the second string.
* @return The result of the comparison.
*/
inline bool EqualNC(const std::string& rss1, const std::string& rss2)
{
if (rss1.length() != rss2.length()) return false;
for (size_t n = 0; n < rss1.length(); n++)
if (std::tolower(rss1[n]) != std::tolower(rss2[n])) return false;
return true;
}
}
CDbcSource::CDbcSource(const std::filesystem::path& rpathDbcfile) : m_pathFile(rpathDbcfile)
{
std::ifstream stream;
stream.open(rpathDbcfile);
if (!stream.is_open()) throw SDbcParserException("Failed to open the %1 file for reading.", rpathDbcfile);
// Read the complete source
std::stringstream sstream;
sstream << stream.rdbuf();
m_ssContent = std::move(sstream.str());
}
CDbcSource::CDbcSource(const std::string& rssContent) : m_ssContent(rssContent)
{}
bool CDbcSource::IsValid() const
{
return !m_ssContent.empty();
}
const std::filesystem::path& CDbcSource::Path() const
{
return m_pathFile;
}
const std::string& CDbcSource::Content() const
{
return m_ssContent;
}
const char* CDbcSource::ContentPtr() const
{
return m_ssContent.c_str() + std::min(m_nPos, m_ssContent.size());
}
char CDbcSource::CurrentChar() const
{
return IsEOF() ? '\0' : m_ssContent[m_nPos];
}
const size_t& CDbcSource::Pos() const
{
return m_nPos;
}
size_t& CDbcSource::Pos()
{
return m_nPos;
}
void CDbcSource::ResetPos()
{
m_nPos = 0;
}
bool CDbcSource::IsEOF() const
{
return m_nPos >= m_ssContent.size();
}
CDbcSource::SPosLock::SPosLock(CDbcSource& rThis) :
pSource(&rThis), nStoredPos(rThis.Pos())
{}
CDbcSource::SPosLock::SPosLock(SPosLock&& rsPosLock) noexcept :
pSource(rsPosLock.pSource), nStoredPos(rsPosLock.nStoredPos)
{
rsPosLock.pSource = nullptr;
rsPosLock.nStoredPos = 0;
}
CDbcSource::SPosLock::~SPosLock()
{
// Automatically rollback
Rollback();
}
CDbcSource::SPosLock& CDbcSource::SPosLock::operator=(SPosLock&& rsPosLock) noexcept
{
pSource = rsPosLock.pSource;
nStoredPos = rsPosLock.nStoredPos;
rsPosLock.pSource = nullptr;
rsPosLock.nStoredPos = 0;
return *this;
}
void CDbcSource::SPosLock::Promote()
{
// Invalidate. Do not rollback to the stored position.
pSource = nullptr;
nStoredPos = 0;
}
void CDbcSource::SPosLock::Rollback()
{
// Can rollback?
if (pSource) pSource->Pos() = nStoredPos;
// Invalidate.
pSource = nullptr;
nStoredPos = 0;
}
CDbcSource::SPosLock CDbcSource::CreatePosLock()
{
return SPosLock(*this);
}
size_t CDbcSource::CalcLine() const
{
size_t nLine = m_ssContent.empty() ? 0 : 1;
nLine += std::count(m_ssContent.begin(), IsEOF() ? m_ssContent.end() : m_ssContent.begin() + m_nPos, '\n');
return nLine;
}
size_t CDbcSource::CalcColumn() const
{
size_t nBOL = m_nPos ? m_ssContent.find_last_of('\n', m_nPos - 1) : std::string::npos;
if (nBOL == std::string::npos)
nBOL = 0;
else
nBOL++;
size_t nCol = 0;
for (size_t nIndex = nBOL; nIndex < std::min(m_nPos, m_ssContent.size()); nIndex++)
{
if (m_ssContent[nIndex] == '\t')
{
// Increase until nIndex is at the tab position.
nCol += 4 - nCol % 4;
}
else
nCol++;
}
return nCol + 1;
}
SAttributeDef::SAttributeDef(SAttributeDef::EType eTypeParam) : eType(eTypeParam)
{
switch (eType)
{
case EType::integer:
sIntValues.iMinimum = 0;
sIntValues.iMaximum = 0;
sIntValues.iDefault = 0;
break;
case EType::hex_integer:
sHexValues.uiMinimum = 0u;
sHexValues.uiMaximum = 0u;
sHexValues.uiDefault = 0u;
break;
case EType::floating_point:
sFltValues.dMinimum = 0.0;
sFltValues.dMaximum = 0.0;
sFltValues.dDefault = 0.0;
break;
case EType::string:
new (&sStringValues.ssDefault) std::string;
break;
case EType::enumerator:
new (&sEnumValues.vecEnumValues) std::vector<std::string>;
new (&sEnumValues.ssDefault) std::string;
break;
default:
throw SDbcParserException("Internal error: invalid attribute definition type.");
break;
}
}
SAttributeDef::~SAttributeDef()
{
switch (eType)
{
case EType::string:
sStringValues.ssDefault.~basic_string();
break;
case EType::enumerator:
sEnumValues.vecEnumValues.~vector();
sEnumValues.ssDefault.~basic_string();
break;
default:
break;
}
}
SAttributeDef::SAttributeDef(const SAttributeDef& rAttrDef) : eObjType(rAttrDef.eObjType), ssName(rAttrDef.ssName), eType(rAttrDef.eType)
{
switch (eType)
{
case EType::integer:
sIntValues.iMinimum = rAttrDef.sIntValues.iMinimum;
sIntValues.iMaximum = rAttrDef.sIntValues.iMaximum;
sIntValues.iDefault = rAttrDef.sIntValues.iDefault;
break;
case EType::hex_integer:
sHexValues.uiMinimum = rAttrDef.sHexValues.uiMinimum;
sHexValues.uiMaximum = rAttrDef.sHexValues.uiMaximum;
sHexValues.uiDefault = rAttrDef.sHexValues.uiDefault;
break;
case EType::floating_point:
sFltValues.dMinimum = rAttrDef.sFltValues.dMinimum;
sFltValues.dMaximum = rAttrDef.sFltValues.dMaximum;
sFltValues.dDefault = rAttrDef.sFltValues.dDefault;
break;
case EType::string:
new (&sStringValues.ssDefault) std::string(rAttrDef.sStringValues.ssDefault);
break;
case EType::enumerator:
new (&sEnumValues.vecEnumValues) std::vector<std::string>(rAttrDef.sEnumValues.vecEnumValues);
new (&sEnumValues.ssDefault) std::string(rAttrDef.sEnumValues.ssDefault);
break;
default:
throw SDbcParserException("Internal error: invalid attribute definition type.");
break;
}
}
SAttributeDef::SAttributeDef(SAttributeDef&& rAttrDef) : eObjType(rAttrDef.eObjType), ssName(std::move(rAttrDef.ssName)), eType(rAttrDef.eType)
{
switch (eType)
{
case EType::integer:
sIntValues.iMinimum = rAttrDef.sIntValues.iMinimum;
sIntValues.iMaximum = rAttrDef.sIntValues.iMaximum;
sIntValues.iDefault = rAttrDef.sIntValues.iDefault;
rAttrDef.sIntValues.iMinimum = 0;
rAttrDef.sIntValues.iMaximum = 0;
rAttrDef.sIntValues.iDefault = 0;
break;
case EType::hex_integer:
sHexValues.uiMinimum = rAttrDef.sHexValues.uiMinimum;
sHexValues.uiMaximum = rAttrDef.sHexValues.uiMaximum;
sHexValues.uiDefault = rAttrDef.sHexValues.uiDefault;
rAttrDef.sHexValues.uiMinimum = 0u;
rAttrDef.sHexValues.uiMaximum = 0u;
rAttrDef.sHexValues.uiDefault = 0u;
break;
case EType::floating_point:
sFltValues.dMinimum = rAttrDef.sFltValues.dMinimum;
sFltValues.dMaximum = rAttrDef.sFltValues.dMaximum;
sFltValues.dDefault = rAttrDef.sFltValues.dDefault;
rAttrDef.sFltValues.dMinimum = 0.0;
rAttrDef.sFltValues.dMaximum = 0.0;
rAttrDef.sFltValues.dDefault = 0.0;
break;
case EType::string:
new (&sStringValues.ssDefault) std::string(std::move(rAttrDef.sStringValues.ssDefault));
break;
case EType::enumerator:
new (&sEnumValues.vecEnumValues) std::vector<std::string>(std::move(rAttrDef.sEnumValues.vecEnumValues));
new (&sEnumValues.ssDefault) std::string(std::move(rAttrDef.sEnumValues.ssDefault));
break;
default:
throw SDbcParserException("Internal error: invalid attribute definition type.");
break;
}
}
SAttributeDef& SAttributeDef::operator=(const SAttributeDef& rAttrDef)
{
// Destroy the current definition
this->~SAttributeDef();
// Construct new definition
new (this) SAttributeDef(rAttrDef);
return *this;
}
SAttributeDef& SAttributeDef::operator=(SAttributeDef&& rAttrDef)
{
// Destroy the current definition
this->~SAttributeDef();
// Construct new definition
new (this) SAttributeDef(std::move(rAttrDef));
return *this;
}
SAttributeValue::SAttributeValue(TAttributeDefPtr& ptrAttrDefParam) : ptrAttrDef(ptrAttrDefParam)
{
switch (ptrAttrDef->eType)
{
case SAttributeDef::EType::integer:
iValue = 0;
break;
case SAttributeDef::EType::hex_integer:
uiValue = 0u;
break;
case SAttributeDef::EType::floating_point:
dValue = 0;
break;
case SAttributeDef::EType::string:
new (&ssValue) std::string;
break;
case SAttributeDef::EType::enumerator:
new (&ssValue) std::string;
break;
default:
throw SDbcParserException("Internal error: invalid attribute definition type.");
break;
}
}
SAttributeValue::~SAttributeValue()
{
switch (ptrAttrDef->eType)
{
case SAttributeDef::EType::string:
ssValue.~basic_string();
break;
case SAttributeDef::EType::enumerator:
ssValue.~basic_string();
break;
default:
break;
}
}
SAttributeValue::SAttributeValue(const SAttributeValue& rAttrVal) : ptrAttrDef(rAttrVal.ptrAttrDef)
{
switch (ptrAttrDef->eType)
{
case SAttributeDef::EType::integer:
iValue = rAttrVal.iValue;
break;
case SAttributeDef::EType::hex_integer:
uiValue = rAttrVal.uiValue;
break;
case SAttributeDef::EType::floating_point:
dValue = rAttrVal.dValue;
break;
case SAttributeDef::EType::string:
new (&ssValue) std::string(rAttrVal.ssValue);
break;
case SAttributeDef::EType::enumerator:
new (&ssValue) std::string(rAttrVal.ssValue);
break;
default:
throw SDbcParserException("Internal error: invalid attribute definition type.");
break;
}
}
SAttributeValue::SAttributeValue(SAttributeValue&& rAttrVal) : ptrAttrDef(rAttrVal.ptrAttrDef)
{
switch (ptrAttrDef->eType)
{
case SAttributeDef::EType::integer:
iValue = rAttrVal.iValue;
break;
case SAttributeDef::EType::hex_integer:
uiValue = rAttrVal.uiValue;
break;
case SAttributeDef::EType::floating_point:
dValue = rAttrVal.dValue;
break;
case SAttributeDef::EType::string:
new (&ssValue) std::string(std::move(rAttrVal.ssValue));
break;
case SAttributeDef::EType::enumerator:
new (&ssValue) std::string(std::move(rAttrVal.ssValue));
break;
default:
throw SDbcParserException("Internal error: invalid attribute definition type.");
break;
}
}
SAttributeValue& SAttributeValue::operator=(const SAttributeValue& rAttrVal)
{
// Destroy the current value
this->~SAttributeValue();
// Construct new value
new (this) SAttributeValue(rAttrVal);
return *this;
}
SAttributeValue& SAttributeValue::operator=(SAttributeValue&& rAttrVal)
{
// Destroy the current value
this->~SAttributeValue();
// Construct new value
new (this) SAttributeValue(std::move(rAttrVal));
return *this;
}
CDbcParser::CDbcParser(bool bNoDefaultDef /*= false*/)
{
if (!bNoDefaultDef)
{
// Parse the standard attribute definitions
CDbcSource source(std::string(R"code(
BA_DEF_ BO_ "VFrameFormat" ENUM "StandardCAN","ExtendedCAN","StandardFD","ExtendedFD";
BA_DEF_ BO_ "GenMsgSendType" ENUM "cyclic","triggered","cyclicIfActive","cyclicAndTriggered","cyclicIfActiveAndTriggered","none";
BA_DEF_ BO_ "GenMsgCycleTime" INT 0 10000;
BA_DEF_ BO_ "GenMsgStartDelayTime" INT 0 10000;
BA_DEF_ BO_ "GenMsgDelayTime" INT 0 0;
BA_DEF_ SG_ "GenSigSendType" ENUM "none","Cyclic","OnWrite","OnChange";
BA_DEF_ SG_ "GenSigCycleTime" INT 0 10000;
BA_DEF_ SG_ "GenSigDelayTime" INT 0 10000;
BA_DEF_ SG_ "GenSigStartDelayTime" INT 0 10000;
BA_DEF_ SG_ "GenSigStartValue" INT 0 0;
BA_DEF_DEF_ "VFrameFormat" "StandardCAN";
BA_DEF_DEF_ "GenMsgSendType" "none";
BA_DEF_DEF_ "GenMsgCycleTime" 0;
BA_DEF_DEF_ "GenMsgStartDelayTime" 0;
BA_DEF_DEF_ "GenMsgDelayTime" 0;
BA_DEF_DEF_ "GenSigSendType" "none";
BA_DEF_DEF_ "GenSigDelayTime" 0;
BA_DEF_DEF_ "GenSigCycleTime" 0;
BA_DEF_DEF_ "GenSigStartDelayTime" 0;
BA_DEF_DEF_ "GenSigStartValue" 0;
)code"));
Parse(source);
}
}
void CDbcParser::Parse(CDbcSource& rSource)
{
// Add to the list of sources.
m_vecSources.push_back(rSource);
// Reset the ID of the Vector independent message
m_uiIndepMsgId = 0xffffffff;
try
{
SkipWhitespace(rSource);
while (!rSource.IsEOF())
{
// Expecting a keyword
std::string ssKeyword = GetIdentifier(rSource);
if (ssKeyword.empty())
throw SDbcParserException("Keyword expected");
if (ssKeyword == "VERSION") ReadVersion(rSource);
else if (ssKeyword == "NS_") ReadNewSymbols(rSource);
else if (ssKeyword == "BS_") ReadBitTiming(rSource);
else if (ssKeyword == "BU_") ReadNodeDef(rSource);
else if (ssKeyword == "VAL_TABLE_") ReadValTable(rSource);
else if (ssKeyword == "BO_") ReadMessageDef(rSource);
else if (ssKeyword == "SIG_VALTYPE_") ReadSignalValueTypeDef(rSource);
else if (ssKeyword == "BO_TX_BU_") ReadMessageTransmitters(rSource);
else if (ssKeyword == "VAL_") ReadValueDescriptions(rSource);
else if (ssKeyword == "EV_") ReadEnvVarDef(rSource);
else if (ssKeyword == "ENVVAR_DATA_") ReadEnvVarData(rSource);
else if (ssKeyword == "SGTYPE_") ReadSignalTypeDef(rSource);
else if (ssKeyword == "SIG_GROUP_") ReadSignalGroupDef(rSource);
else if (ssKeyword == "CM_") ReadCommentDef(rSource);
else if (ssKeyword == "BA_DEF_") ReadAttrDef(rSource);
else if (ssKeyword == "BA_DEF_DEF_") ReadAttrDefaultDef(rSource);
else if (ssKeyword == "BA_") ReadAttributes(rSource);
else if (ssKeyword == "SG_MUL_VAL_") ReadSignalMultiplexDef(rSource);
else throw SDbcParserException(rSource, "Unknown keyword '%1'.", ssKeyword);
SkipWhitespace(rSource);
}
}
catch (SDbcParserException& rsException)
{
// Add the source
if (!rsException.Source().IsValid())
rsException.Source(rSource);
// Retrow
throw;
}
}
void CDbcParser::Clear()
{
m_vecVersions.clear();
m_mapNodes.clear();
m_mapValueTables.clear();
m_mapMsgDefByName.clear();
m_mapMsgDefById.clear();
}
const std::vector<CDbcSource>& CDbcParser::GetSources() const
{
return m_vecSources;
}
const std::vector<std::string>& CDbcParser::GetVersions() const
{
return m_vecVersions;
}
bool CDbcParser::HasNodeDef(const std::string& rssNodeDefName) const
{
return m_mapNodes.find(rssNodeDefName) != m_mapNodes.end();
}
const std::vector<std::string> CDbcParser::GetNodeDefNames() const
{
std::vector<std::string> vecNodes;
for (auto prNode : m_mapNodes)
vecNodes.push_back(prNode.first);
return vecNodes;
}
std::pair<SNodeDef, bool> CDbcParser::GetNodeDef(const std::string& rssNodeDefName) const
{
auto itNode = m_mapNodes.find(rssNodeDefName);
if (itNode == m_mapNodes.end()) return std::make_pair(SNodeDef(), false);
return std::make_pair(itNode->second, true);
}
bool CDbcParser::HasValueTable(const std::string& rssName) const
{
return m_mapValueTables.find(rssName) != m_mapValueTables.end();
}
bool CDbcParser::HasValue(const std::string& rssTableName, uint32_t uiValue) const
{
auto itTable = m_mapValueTables.find(rssTableName);
if (itTable == m_mapValueTables.end()) return false;
return itTable->second.find(uiValue) != itTable->second.end();
}
std::string CDbcParser::GetValue(const std::string& rssTableName, uint32_t uiValue) const
{
auto itTable = m_mapValueTables.find(rssTableName);
if (itTable == m_mapValueTables.end()) return std::string();
auto itValue = itTable->second.find(uiValue);
if (itValue == itTable->second.end()) return std::string();
return itValue->second;
}
std::vector<std::string> CDbcParser::GetValueTableNames() const
{
std::vector<std::string> vecTables;
for (auto prTable : m_mapValueTables)
vecTables.push_back(prTable.first);
return vecTables;
}
std::pair<std::vector<uint32_t>, bool> CDbcParser::GetValues(const std::string& rssTableName) const
{
// Find the table
auto itTable = m_mapValueTables.find(rssTableName);
std::vector<uint32_t> vecEntries;
if (itTable == m_mapValueTables.end())
return std::make_pair(vecEntries, false);
for (auto prEntry : itTable->second)
vecEntries.push_back(prEntry.first);
return std::make_pair(std::move(vecEntries), true);
}
bool CDbcParser::HasMsgDef(const std::string& rssName) const
{
return m_mapMsgDefByName.find(rssName) != m_mapMsgDefByName.end();
}
bool CDbcParser::HasMsgDef(uint32_t uiRawId) const
{
return m_mapMsgDefById.find(uiRawId) != m_mapMsgDefById.end();
}
bool CDbcParser::HasMsgDefStdId(uint32_t uiStdId) const
{
if (uiStdId >= 1u << 11) return false;
return m_mapMsgDefById.find(uiStdId) != m_mapMsgDefById.end();
}
bool CDbcParser::HasMsgDefExtId(uint32_t uiExtId) const
{
if (uiExtId >= 1u << 29) return false;
return m_mapMsgDefById.find(uiExtId | 0x80000000u) != m_mapMsgDefById.end();
}
std::vector<uint32_t> CDbcParser::GetMessageIDs() const
{
std::vector<uint32_t> vecMsgIDs;
for (auto prMsgDef : m_mapMsgDefById)
vecMsgIDs.push_back(prMsgDef.first);
return vecMsgIDs;
}
std::pair<uint32_t, bool> CDbcParser::ExtractMsgId(uint32_t uiRawId)
{
return std::make_pair(uiRawId & 0x7fffffffu, uiRawId & 0x80000000u ? true : false);
}
uint32_t CDbcParser::ComposeRawId(uint32_t uiMsgId, bool bExtended)
{
return uiMsgId | (bExtended ? 0x80000000u : 0x00000000u);
}
std::pair<SMessageDef, bool> CDbcParser::GetMsgDef(const std::string& rssName) const
{
auto itMsgDef = m_mapMsgDefByName.find(rssName);
if (itMsgDef == m_mapMsgDefByName.end()) return std::make_pair(SMessageDef(), false);
return std::make_pair(*itMsgDef->second, true);
}
std::pair<SMessageDef, bool> CDbcParser::GetMsgDef(uint32_t uiRawId) const
{
auto itMsgDef = m_mapMsgDefById.find(uiRawId);
if (itMsgDef == m_mapMsgDefById.end()) return std::make_pair(SMessageDef(), false);
return std::make_pair(*itMsgDef->second, true);
}
std::pair<SMessageDef, bool> CDbcParser::GetMsgDefStdId(uint32_t uiStdId) const
{
if (uiStdId >= 1u << 11) return std::make_pair(SMessageDef(), false);
auto itMsgDef = m_mapMsgDefById.find(uiStdId);
if (itMsgDef == m_mapMsgDefById.end()) return std::make_pair(SMessageDef(), false);
return std::make_pair(*itMsgDef->second, true);
}
std::pair<SMessageDef, bool> CDbcParser::GetMsgDefExtId(uint32_t uiExtId) const
{
if (uiExtId >= 1u << 29) return std::make_pair(SMessageDef(), false);
auto itMsgDef = m_mapMsgDefById.find(uiExtId | 0x80000000u);
if (itMsgDef == m_mapMsgDefById.end()) return std::make_pair(SMessageDef(), false);
return std::make_pair(*itMsgDef->second, true);
}
bool CDbcParser::HasSignalDef(const std::string& rssMsgName, const std::string& rssSignalName) const
{
auto prMsgDef = GetMsgDef(rssMsgName);
if (!prMsgDef.second) return false;
return std::find_if(prMsgDef.first.vecSignals.begin(), prMsgDef.first.vecSignals.end(),
[&](const SSignalDef& rsSignalDef) -> bool
{
return rsSignalDef.ssName == rssSignalName;
}) != prMsgDef.first.vecSignals.end();
}
bool CDbcParser::HasSignalDef(uint32_t uiRawMsgId, const std::string & rssSignalName) const
{
auto prMsgDef = GetMsgDef(uiRawMsgId);
if (!prMsgDef.second) return false;
return std::find_if(prMsgDef.first.vecSignals.begin(), prMsgDef.first.vecSignals.end(),
[&](const SSignalDef& rsSignalDef) -> bool
{
return rsSignalDef.ssName == rssSignalName;
}) != prMsgDef.first.vecSignals.end();
}
bool CDbcParser::HasSignalDefStdId(uint32_t uiStdMsgId, const std::string & rssSignalName) const
{
auto prMsgDef = GetMsgDefStdId(uiStdMsgId);
if (!prMsgDef.second) return false;
return std::find_if(prMsgDef.first.vecSignals.begin(), prMsgDef.first.vecSignals.end(),
[&](const SSignalDef& rsSignalDef) -> bool
{
return rsSignalDef.ssName == rssSignalName;
}) != prMsgDef.first.vecSignals.end();
}
bool CDbcParser::HasSignalDefExtId(uint32_t uiExtMsgId, const std::string & rssSignalName) const
{
auto prMsgDef = GetMsgDefExtId(uiExtMsgId);
if (!prMsgDef.second) return false;
return std::find_if(prMsgDef.first.vecSignals.begin(), prMsgDef.first.vecSignals.end(),
[&](const SSignalDef& rsSignalDef) -> bool
{
return rsSignalDef.ssName == rssSignalName;
}) != prMsgDef.first.vecSignals.end();
}
std::vector<std::string> CDbcParser::GetSignalNames(uint32_t uiRawMsgId) const
{
auto prMsgDef = GetMsgDef(uiRawMsgId);
if (!prMsgDef.second) return std::vector<std::string>();
std::vector<std::string> vecSigNames;
for (const SSignalDef& rsSignalDef : prMsgDef.first.vecSignals)
vecSigNames.push_back(rsSignalDef.ssName);
return vecSigNames;
}
std::pair<SSignalDef, bool> CDbcParser::GetSignalDef(const std::string & rssMsgName, const std::string & rssSignalName) const
{
auto prMsgDef = GetMsgDef(rssMsgName);
if (!prMsgDef.second) return std::make_pair(SSignalDef(), false);
auto itSignalDef = std::find_if(prMsgDef.first.vecSignals.begin(), prMsgDef.first.vecSignals.end(),
[&](const SSignalDef& rsSignalDef) -> bool
{
return rsSignalDef.ssName == rssSignalName;
});
if (itSignalDef == prMsgDef.first.vecSignals.end()) return std::make_pair(SSignalDef(), false);
return std::make_pair(*itSignalDef, true);
}
std::pair<SSignalDef, bool> CDbcParser::GetSignalDef(uint32_t uiRawMsgId, const std::string & rssSignalName) const
{
auto prMsgDef = GetMsgDef(uiRawMsgId);
if (!prMsgDef.second) return std::make_pair(SSignalDef(), false);
auto itSignalDef = std::find_if(prMsgDef.first.vecSignals.begin(), prMsgDef.first.vecSignals.end(),
[&](const SSignalDef& rsSignalDef) -> bool
{
return rsSignalDef.ssName == rssSignalName;
});
if (itSignalDef == prMsgDef.first.vecSignals.end()) return std::make_pair(SSignalDef(), false);
return std::make_pair(*itSignalDef, true);
}
std::pair<SSignalDef, bool> CDbcParser::GetSignalDefStdId(uint32_t uiStdMsgId, const std::string & rssSignalName) const
{
auto prMsgDef = GetMsgDefStdId(uiStdMsgId);
if (!prMsgDef.second) return std::make_pair(SSignalDef(), false);
auto itSignalDef = std::find_if(prMsgDef.first.vecSignals.begin(), prMsgDef.first.vecSignals.end(),
[&](const SSignalDef& rsSignalDef) -> bool
{
return rsSignalDef.ssName == rssSignalName;
});
if (itSignalDef == prMsgDef.first.vecSignals.end()) return std::make_pair(SSignalDef(), false);
return std::make_pair(*itSignalDef, true);
}
std::pair<SSignalDef, bool> CDbcParser::GetSignalDefExtId(uint32_t uiExtMsgId, const std::string & rssSignalName) const
{
auto prMsgDef = GetMsgDefExtId(uiExtMsgId);
if (!prMsgDef.second) return std::make_pair(SSignalDef(), false);
auto itSignalDef = std::find_if(prMsgDef.first.vecSignals.begin(), prMsgDef.first.vecSignals.end(),
[&](const SSignalDef& rsSignalDef) -> bool
{
return rsSignalDef.ssName == rssSignalName;
});
if (itSignalDef == prMsgDef.first.vecSignals.end()) return std::make_pair(SSignalDef(), false);
return std::make_pair(*itSignalDef, true);
}
std::vector<std::string> CDbcParser::GetEnvVarNames() const
{
std::vector<std::string> vecEnvVars;
for (auto prEnvVar : m_mapEnvVars)
vecEnvVars.push_back(prEnvVar.first);
return vecEnvVars;
}
std::pair<SEnvVarDef, bool> CDbcParser::GetEnvVarDef(const std::string& rssVarName) const
{
auto itVarDef = m_mapEnvVars.find(rssVarName);
if (itVarDef == m_mapEnvVars.end()) return std::make_pair(SEnvVarDef(), false);
return std::make_pair(itVarDef->second, true);
}
std::vector<std::string> CDbcParser::GetSignalTypeDefNames() const
{
std::vector<std::string> vecTypeDefs;
for (auto prTypeDef : m_mapSigTypeDefs)
vecTypeDefs.push_back(prTypeDef.first);
return vecTypeDefs;
}
std::pair<SSignalTypeDef, bool> CDbcParser::GetSignalTypeDef(const std::string& rssSignalTypeDefName) const
{
auto itTypeDef = m_mapSigTypeDefs.find(rssSignalTypeDefName);
if (itTypeDef == m_mapSigTypeDefs.end()) return std::make_pair(SSignalTypeDef(), false);
return std::make_pair(itTypeDef->second, true);
}
std::vector<std::string> CDbcParser::GetSignalGroupDefNames(uint32_t uiRawMsgId) const
{
std::vector<std::string> vecGroupDefs;
auto itMsgDef = m_mapMsgDefById.find(uiRawMsgId);
if (itMsgDef != m_mapMsgDefById.end())
{
for (auto prGroupDef : itMsgDef->second->mapSigGroups)
vecGroupDefs.push_back(prGroupDef.first);
}
return vecGroupDefs;
}
std::pair<SSignalGroupDef, bool> CDbcParser::GetSignalGroupDef(uint32_t uiRawMsgId, const std::string& rssSignalGroupDefName) const
{
auto itMsgDef = m_mapMsgDefById.find(uiRawMsgId);
if (itMsgDef == m_mapMsgDefById.end()) return std::make_pair(SSignalGroupDef(), false);
auto itSigGroupDef = itMsgDef->second->mapSigGroups.find(rssSignalGroupDefName);
if (itSigGroupDef == itMsgDef->second->mapSigGroups.end()) return std::make_pair(SSignalGroupDef(), false);
return std::make_pair(itSigGroupDef->second, true);
}
const std::vector<std::string>& CDbcParser::GetComments() const
{
return m_vecComments;
}
std::vector<std::string> CDbcParser::GetAttributeDefNames() const
{
std::vector<std::string> vecAttrDefs;
for (auto prAttrDef : m_mapAttrDefs)
vecAttrDefs.push_back(prAttrDef.first);
return vecAttrDefs;
}
std::pair<SAttributeDef, bool> CDbcParser::GetAttributeDef(const std::string& rssAttributeDefName) const
{
auto itAttrDef = m_mapAttrDefs.find(rssAttributeDefName);
if (itAttrDef == m_mapAttrDefs.end()) return std::make_pair(SAttributeDef(SAttributeDef::EType::integer), false);
return std::make_pair(*itAttrDef->second, true);
}
const std::vector<SAttributeValue>& CDbcParser::GetAttributes() const
{
return m_vecAttributes;
}
void CDbcParser::SkipWhitespace(CDbcSource& rSource)
{
// NOTE: Comments are not part of the official standard.
while (!rSource.IsEOF())
{
if (std::isspace(rSource.CurrentChar()))
{
rSource.Pos()++;
continue;
}
if (rSource.CurrentChar() == '/')
{
auto sPosLock = rSource.CreatePosLock();
rSource.Pos()++;
if (rSource.CurrentChar() == '/')
{
// Skip the rest of the line
sPosLock.Promote();
while (!rSource.IsEOF() && rSource.CurrentChar() != '\n')
rSource.Pos()++;
continue;
}
}
break;
}
}
std::pair<uint32_t, bool> CDbcParser::GetUInt(CDbcSource& rSource)
{
SkipWhitespace(rSource);
if (rSource.IsEOF()) return std::make_pair<uint32_t, bool>(0u, false);
const char* szBegin = rSource.ContentPtr();
char* szEnd = nullptr;
uint32_t uiVal = static_cast<uint32_t>(std::strtoul(szBegin, &szEnd, 10));
if (errno == ERANGE) return std::make_pair<uint32_t, bool>(0u, false);
if (!szEnd || szEnd == szBegin) return std::make_pair<uint32_t, bool>(0u, false);
rSource.Pos() += (szEnd - szBegin);
return std::make_pair(uiVal, true);
}
std::pair<int32_t, bool> CDbcParser::GetInt(CDbcSource& rSource)
{
SkipWhitespace(rSource);
if (rSource.IsEOF()) return std::make_pair<int32_t, bool>(0, false);
const char* szBegin = rSource.ContentPtr();
char* szEnd = nullptr;
int32_t iVal = static_cast<int32_t>(std::strtol(szBegin, &szEnd, 10));
if (errno == ERANGE) return std::make_pair<int32_t, bool>(0, false);
if (!szEnd || szEnd == szBegin) return std::make_pair<int32_t, bool>(0, false);
rSource.Pos() += (szEnd - szBegin);
return std::make_pair(iVal, true);
}
std::pair<double, bool> CDbcParser::GetDouble(CDbcSource& rSource)
{
SkipWhitespace(rSource);
if (rSource.IsEOF()) return std::make_pair<double, bool>(0.0, false);
const char* szBegin = rSource.ContentPtr();
char* szEnd = nullptr;
double dVal = std::strtod(szBegin, &szEnd);
if (errno == ERANGE) return std::make_pair<double, bool>(0.0, false);
if (!szEnd || szEnd == szBegin) return std::make_pair<double, bool>(0.0, false);
rSource.Pos() += (szEnd - szBegin);
return std::make_pair(dVal, true);
}
bool CDbcParser::ExpectChar(char c, CDbcSource& rSource)
{
SkipWhitespace(rSource);
if (rSource.IsEOF()) return false;
if (rSource.CurrentChar() != c) return false;
rSource.Pos()++;
return true;
}
std::pair<std::string, bool> CDbcParser::GetString(CDbcSource& rSource)
{
SkipWhitespace(rSource);
if (rSource.IsEOF()) return std::pair<std::string, bool>{std::string(), false};
// A string should start with a quote
if (rSource.CurrentChar() != '\"') return std::pair<std::string, bool>{std::string(), false};
// Search for the next quote - skip escaped quotes
std::string ssResult;
do
{
size_t nBegin = ++rSource.Pos();
size_t nEnd = rSource.Content().find_first_of("\"\\", nBegin);
if (nEnd == std::string::npos) return std::pair<std::string, bool>{std::string(), false};
ssResult += rSource.Content().substr(nBegin, nEnd - nBegin);
rSource.Pos() = nEnd + 1;
if (rSource.Content()[nEnd] != '\\') break;
// Escaped character. Add and continue.
ssResult += rSource.Content()[nEnd + 1];
rSource.Pos() = nEnd + 1;
} while (true);
return std::pair<std::string, bool>{ssResult, true};
}
std::string CDbcParser::GetIdentifier(CDbcSource& rSource)
{
SkipWhitespace(rSource);
std::string ssIdentifier;
while (!rSource.IsEOF())
{
char c = rSource.CurrentChar();
// Allowed are '_' and alphanumerical characters. The identifier is not allowed to start with a number
// Undocumented extension: '-', '<' and '>' are also allowed.
if (c != '_' && c != '-' && c != '<' && c != '>' && !(ssIdentifier.empty() ? std::isalpha(c) : std::isalnum(c)))
break;
ssIdentifier += c;
rSource.Pos()++;
}
return ssIdentifier;
}
bool CDbcParser::IsDbcIdentifier(const std::string& rssIdentifier)
{
const char* rgszDbcKeywords[] = { "VERSION", "NS_", "NS_DESC_", "CM_", "BA_DEF_", "BA_", "VAL_", "CAT_DEF_", "CAT_", "FILTER",
"BA_DEF_DEF_", "EV_DATA_", "ENVVAR_DATA_", "SGTYPE_", "SGTYPE_VAL_", "BA_DEF_SGTYPE_", "BA_SGTYPE_", "SIG_TYPE_REF_",
"VAL_TABLE_", "SIG_GROUP_", "SIG_VALTYPE_", "SIGTYPE_VALTYPE_", "BO_TX_BU_", "BA_DEF_REL_", "BA_REL_", "BA_DEF_DEF_REL_",
"BU_SG_REL_", "BU_EV_REL_", "BU_BO_REL_", "SG_MUL_VAL_", "BS_", "BU_", "BO_", "SG_", "EV_", "VECTOR__XXX" };
// Check whether the identifier does not correspond to one within the keyword list
auto itDbcKeyword = std::find(std::begin(rgszDbcKeywords), std::end(rgszDbcKeywords), rssIdentifier);
return itDbcKeyword != std::end(rgszDbcKeywords);
}
void CDbcParser::ReadVersion(CDbcSource& rSource)
{
auto prVersion = GetString(rSource);
if (!prVersion.second)
throw SDbcParserException("String expected following 'VERSION' keyword");
m_vecVersions.push_back(prVersion.first);
}
void CDbcParser::ReadNewSymbols(CDbcSource& rSource)
{
const char* rgszNewSymbols[] = { "CM_", "NS_DESC_", "BA_DEF_", "BA_", "VAL_", "CAT_DEF_", "CAT_", "FILTER", "BA_DEF_DEF_",
"EV_DATA_", "ENVVAR_DATA_", "SGTYPE_", "SGTYPE_VAL_", "BA_DEF_SGTYPE_", "BA_SGTYPE_", "SIG_TYPE_REF_", "VAL_TABLE_",
"SIG_GROUP_", "SIG_VALTYPE_", "SIGTYPE_VALTYPE_", "BO_TX_BU_", "BA_DEF_REL_", "BA_REL_", "BA_DEF_DEF_REL_",
"BU_SG_REL_", "BU_EV_REL_", "BU_BO_REL_", "SG_MUL_VAL_" };
// Expect separator
if (!ExpectChar(':', rSource))
throw SDbcParserException("Colon ':' expected following 'NS_' keyword");
// Zero or more symbols from the above list can be defined.
do
{
// Get the next identifier
auto sPosLock = rSource.CreatePosLock();
std::string ssSymbol = GetIdentifier(rSource);
if (ssSymbol.empty()) break;
// Check whether the identifier corresponds to one of the above list
auto itSymbol = std::find(std::begin(rgszNewSymbols), std::end(rgszNewSymbols), ssSymbol);
if (itSymbol == std::end(rgszNewSymbols)) break;
// Update the position and check for the next symbol.
sPosLock.Promote();
} while (!rSource.IsEOF());
}
void CDbcParser::ReadBitTiming(CDbcSource& rSource)
{
// Expect separator
if (!ExpectChar(':', rSource))
throw SDbcParserException("Colon ':' expected following 'BS_' keyword");
// Optionally the timing could be specified (since this section has been defined obsolete, it is more likely that
// nothing is specified).
auto prBaudrate = GetUInt(rSource);
if (prBaudrate.second)
{
if (!ExpectChar(':', rSource))
throw SDbcParserException("Colon ':' expected following baudrate value.");
auto prBTR1 = GetUInt(rSource);
if (!prBTR1.second) throw SDbcParserException("BTR1 register value expected.");
if (!ExpectChar(',', rSource))
throw SDbcParserException("Comma ',' expected following BTR1 register value");
auto prBTR2 = GetUInt(rSource);
if (!prBTR2.second) throw SDbcParserException("BTR2 register value expected.");
}
}
void CDbcParser::ReadNodeDef(CDbcSource& rSource)
{
// Expect separator
if (!ExpectChar(':', rSource))
throw SDbcParserException("Colon ':' expected following 'BU_' keyword.");
// Zero or more nodes can be defined
std::map<std::string, SNodeDef> mapNodesLocal;
do
{
// Get the next identifier
SNodeDef sNodeDef;
auto sPosLock = rSource.CreatePosLock();
sNodeDef.ssName = GetIdentifier(rSource);
if (sNodeDef.ssName.empty()) break;
// Check whether the identifier is a DBC identifier
if (IsDbcIdentifier(sNodeDef.ssName)) break;
// Add the node name to the local node name list.
sPosLock.Promote();
if (mapNodesLocal.find(sNodeDef.ssName) != mapNodesLocal.end())
throw SDbcParserException("Duplicate nodes defined.");
mapNodesLocal.insert(std::make_pair(sNodeDef.ssName, sNodeDef));
} while (!rSource.IsEOF());
// Add the local nodes to the global node set (if not already existing).
m_mapNodes.insert(mapNodesLocal.begin(), mapNodesLocal.end());
}
void CDbcParser::ReadValTable(CDbcSource& rSource)
{
// Get the name of the table
std::string ssTableName = GetIdentifier(rSource);
if (ssTableName.empty() || IsDbcIdentifier(ssTableName))
throw SDbcParserException("Expecting a name for the value table.");
if (m_mapValueTables.find(ssTableName) != m_mapValueTables.end())
throw SDbcParserException("Duplicate value table definition.");
// Zero or more definitions can follow
TValDescMap mapValues;
do
{
auto prValue = GetUInt(rSource);
if (!prValue.second) break; // Not a value
auto prString = GetString(rSource);
if (!prString.second)
throw SDbcParserException("Expecting a string following the value.");
// Duplicate values are not allowed
if (mapValues.find(prValue.first) != mapValues.end())
throw SDbcParserException("Duplicate value definition.");
// Insert the value.
mapValues.insert(std::make_pair(prValue.first, prString.first));
} while (!rSource.IsEOF());
// Expect terminator
if (!ExpectChar(';', rSource))
throw SDbcParserException("Semi-colon ';' expected finalizing the definition of the 'VAL_TABLE_'");
// Insert the table
m_mapValueTables.insert(std::make_pair(ssTableName, mapValues));
}
void CDbcParser::ReadMessageDef(CDbcSource& rSource)
{
// Get the message ID
auto prId = GetUInt(rSource);
if (!prId.second)
throw SDbcParserException("Expecting an ID for the message.");
uint32_t uiId = prId.first;
// Get the name of the message
std::string ssMessageName = GetIdentifier(rSource);
if (ssMessageName.empty() || IsDbcIdentifier(ssMessageName))
throw SDbcParserException("Expecting a name for the message.");
// Correct the ID for the default message (enforce the same ID for this message).
if (ssMessageName == "VECTOR__INDEPENDENT_SIG_MSG")
{
m_uiIndepMsgId = uiId;
uiId = 0xffffffff;
}
else
{
if (uiId & 0x80000000) // Differentiate between extended and standard ID
{
if ((uiId & 0x7fffffff) >= 1u<<29)
throw SDbcParserException("Specified extended message ID is larger than the 29 bits.");
} else
{
if ((uiId & 0x7fffffff) >= 1u<<11)
throw SDbcParserException("Specified standard message ID is larger than the 11 bits.");
}
}
// Expect separator
if (!ExpectChar(':', rSource))
throw SDbcParserException("Colon ':' expected following 'BO_' message definition");
// Get the message size
auto prSize = GetUInt(rSource);
if (!prSize.second) throw SDbcParserException("Expecting a size for the message.");
// Get the transmitter name
std::string ssTransmitter = GetIdentifier(rSource);
if (ssTransmitter.empty())
throw SDbcParserException("Expecting a transmitter name for the message.");
if (ssTransmitter != "Vector__XXX" && ssTransmitter != "Vector_XXX" && m_mapNodes.find(ssTransmitter) == m_mapNodes.end())
throw SDbcParserException("Expecting a valid pre-defined transmitter name for the message.");
// Duplicate definitions are not allowed.
// Except when the message is named "VECTOR__INDEPENDENT_SIG_MSG", which is just a placeholder. In the latter case, the
// message is extended with the defined signals.
auto itMessage = m_mapMsgDefByName.find(ssMessageName);
if (itMessage == m_mapMsgDefByName.end())
{
auto ptrMessage = std::make_shared<SMessageDef>();
auto prResult1 = m_mapMsgDefByName.emplace(std::make_pair(ssMessageName, ptrMessage));
if (!prResult1.second)
throw SDbcParserException("Failed to construct message definition for '%1' and ID %2.", ssMessageName, uiId);
itMessage = prResult1.first;
auto prResult2 = m_mapMsgDefById.emplace(std::make_pair(uiId, ptrMessage));
if (!prResult2.second)
{
m_mapMsgDefByName.erase(prResult1.first);
throw SDbcParserException("Failed to construct message definition for '%1' and ID %2.", ssMessageName, uiId);
}
}
else
{
if (ssMessageName != "VECTOR__INDEPENDENT_SIG_MSG")
throw SDbcParserException("Duplicate message definition for ID '%1' and ID %2.", ssMessageName, uiId);
}
// Set the message information
itMessage->second->ssName = ssMessageName;
itMessage->second->uiId = uiId;
itMessage->second->uiSize += prSize.first;
itMessage->second->vecTransmitters.push_back(ssTransmitter);
// Check for signals
do
{
// Try peeking for the signal definition. Us a position lock to be able to rollback if the identifier doesn't represent a
// signal definition.
auto sPosLock = rSource.CreatePosLock();
std::string ssIdentfier = GetIdentifier(rSource);
if (ssIdentfier != "SG_") break;
sPosLock.Promote();
ReadSignalDef(rSource, *itMessage->second);
} while (true);
}
void CDbcParser::ReadSignalTypeDefBase(CDbcSource& rSource, SSignalTypeBase& rsSignalTypeDefBase)
{
// Get size
auto prSize = GetUInt(rSource);
if (!prSize.second)
throw SDbcParserException("Expecting the signal size.");
rsSignalTypeDefBase.uiSize = prSize.first;
// Expect separator
if (!ExpectChar('@', rSource))
throw SDbcParserException("At-sign '@' expected following size in the signal definition");
// Get byte order
auto prByteOrder = GetUInt(rSource);
if (!prByteOrder.second)
throw SDbcParserException("Expecting the byte order indicator.");
if (prByteOrder.first > 1)
throw SDbcParserException("Invalid byte order indicator for the signal (0=big endian or 1=little endian are allowed).");
rsSignalTypeDefBase.eByteOrder = prByteOrder.first ? SSignalDef::EByteOrder::little_endian : SSignalDef::EByteOrder::big_endian;
// Get the value type
if (ExpectChar('+', rSource))
rsSignalTypeDefBase.eValType = SSignalDef::EValueType::unsigned_integer;
else if (ExpectChar('-', rSource))
rsSignalTypeDefBase.eValType = SSignalDef::EValueType::signed_integer;
else
throw SDbcParserException("Invalid value type ('+'=unsigned or '-'=signed are allowed).");
// Get the opening bracket
if (!ExpectChar('(', rSource))
throw SDbcParserException("Left bracket '(' expected following the value type in the signal definition");
// Get the factor
auto prFactor = GetDouble(rSource);
if (!prFactor.second)
throw SDbcParserException("Expecting the factor value.");
if (prFactor.first == 0.0)
throw SDbcParserException("A factor value of 0 is not valid.");
rsSignalTypeDefBase.dFactor = prFactor.first;
// Get the comma
if (!ExpectChar(',', rSource))
throw SDbcParserException("Comma '(' expected following the factor value in the signal definition");
// Get the offset
auto prOffset = GetDouble(rSource);
if (!prOffset.second)
throw SDbcParserException("Expecting the offset value.");
rsSignalTypeDefBase.dOffset = prOffset.first;
// Get the closing bracket
if (!ExpectChar(')', rSource))
throw SDbcParserException("Right bracket ')' expected following the offset value in the signal definition");
// Get the opening square-bracket
if (!ExpectChar('[', rSource))
throw SDbcParserException("Left square-bracket '[' expected following the factor and offset in the signal definition");
// Get the minimum
auto prMinimum = GetDouble(rSource);
if (!prMinimum.second)
throw SDbcParserException("Expecting the minimum value.");
rsSignalTypeDefBase.dMinimum = prMinimum.first;
// Expect separator
if (!ExpectChar('|', rSource))
throw SDbcParserException("Pipe '|' expected following the minimum in the signal definition");
// Get the maximum
auto prMaximum = GetDouble(rSource);
if (!prMaximum.second)
throw SDbcParserException("Expecting the maximum value.");
rsSignalTypeDefBase.dMaximum = prMaximum.first;
// Get the closing square-bracket
if (!ExpectChar(']', rSource))
throw SDbcParserException("Right square-bracket ']' expected following the maximum in the signal definition");
// Get the unit string
auto prUnit = GetString(rSource);
if (!prUnit.second)
throw SDbcParserException("String expected following the minimum and maximum in the signal definition");
rsSignalTypeDefBase.ssUnit = prUnit.first;
}
void CDbcParser::ReadSignalDef(CDbcSource& rSource, SMessageDef& rsMsgDef)
{
SSignalDef sSignalDef;
// Set the message ID
sSignalDef.uiMsgId = rsMsgDef.uiId;
// Get the name of the signal
sSignalDef.ssName = GetIdentifier(rSource);
if (sSignalDef.ssName.empty() || IsDbcIdentifier(sSignalDef.ssName))
throw SDbcParserException("Expecting a name for the signal.");
if (std::find_if(rsMsgDef.vecSignals.begin(), rsMsgDef.vecSignals.end(),
[&](const SSignalDef& rsSignal) -> bool
{
return rsSignal.ssName == sSignalDef.ssName;
}) != rsMsgDef.vecSignals.end())
throw SDbcParserException("Duplicate signal defined within the message.");
// Check for the multiplexer indicator.
if (ExpectChar('m', rSource))
{
sSignalDef.uiMultiplexBitmask |= static_cast<uint32_t>(SSignalDef::EMultiplexBitmask::mltplx_val);
auto prCaseVal = GetInt(rSource);
if (!prCaseVal.second)
throw SDbcParserException("Expecting a multiplexed switch case value.");
sSignalDef.iMltplxCase = prCaseVal.first;
}
if (ExpectChar('M', rSource))
sSignalDef.uiMultiplexBitmask |= static_cast<uint32_t>(SSignalDef::EMultiplexBitmask::mltplx_switch);
// Expect separator
if (!ExpectChar(':', rSource))
throw SDbcParserException("Colon ':' expected following 'SG_' signal definition");
// Get start bit
auto prStartBit = GetUInt(rSource);
if (!prStartBit.second)
throw SDbcParserException("Expecting the start bit.");
if (rsMsgDef.uiId != 0xffffffff && prStartBit.first >= 8 * rsMsgDef.uiSize)
throw SDbcParserException("Start bit has been defined beyond the size of the message.");
sSignalDef.uiStartBit = prStartBit.first;
// Expect separator
if (!ExpectChar('|', rSource))
throw SDbcParserException("Pipe '|' expected following start bit in the signal definition");
// Get the signal type def - base part
ReadSignalTypeDefBase(rSource, sSignalDef);
// Check correct size
if (sSignalDef.eByteOrder == SSignalDef::EByteOrder::little_endian)
{
// The signal occupies the area from start-bit until start-bit + size.
if (rsMsgDef.uiId != 0xffffffff && sSignalDef.uiStartBit + sSignalDef.uiSize > rsMsgDef.uiSize * 8)
throw SDbcParserException("The length of the signal positioned at the start bit exceeds the length of the message.");
} else // big endian
{
// The signal occupies the byte where the start bit determines the MSB and any number of following bytes that start with
// the most significant bit. For example:
// Signal 1: start=7 length = 4
// Signal 2: start=3 length = 8
// Signal 3: start=11 length = 6
// Signal 4: start=21 length = 6
// Signal 5: start=31 length = 8
// Signal 6: start=39 length = 32
// 7 6 5 4 3 2 1 0
// 0 | Signal 1 | Signal 2 MSB |
// 1 | signal 2 LSB | Signal 3 MSB |
// 2 | Sig 3 | Signal 4 |
// 3 | Signal 5 |
// 4 | Signal 6 MSB |
// 5 | |
// 6 | |
// 7 | Signal 6 LSB |
auto fnInverseBitPos = [](uint32_t uiPos) -> uint32_t
{
uint32_t uiInverseStartBit = (uiPos >> 3) << 3;
uint32_t uiInverseStartBitInByte = (8 - ((uiPos + 1) & 7)) & 7;
return uiInverseStartBit + uiInverseStartBitInByte;
};
if (rsMsgDef.uiId != 0xffffffff && fnInverseBitPos(sSignalDef.uiStartBit) + sSignalDef.uiSize > rsMsgDef.uiSize * 8)
throw SDbcParserException("The length of the signal positioned at the start bit exceeds the length of the message.");
}
// Get one or more receivers
do
{
// Get the receiver
std::string ssReceiver = GetIdentifier(rSource);
if (ssReceiver.empty() || IsDbcIdentifier(ssReceiver))
throw SDbcParserException("Expecting a receiver for the signal.");
// Check the receiver with the predefined nodes (except for "Vector__XXX" node)
if (ssReceiver != "Vector__XXX" && ssReceiver != "Vector_XXX" && m_mapNodes.find(ssReceiver) == m_mapNodes.end())
throw SDbcParserException("Expecting a valid pre-defined receiver name for the signal.");
// Check for multiple definitions
if (std::find(sSignalDef.vecReceivers.begin(), sSignalDef.vecReceivers.end(), ssReceiver) != sSignalDef.vecReceivers.end())
throw SDbcParserException("Duplicate receiver name defined for the signal.");
// Add to the receiver vector
sSignalDef.vecReceivers.push_back(std::move(ssReceiver));
// Check for additional receivers
if (!ExpectChar(',', rSource)) break;
} while(true);
// Add the signal to the message
rsMsgDef.vecSignals.push_back(std::move(sSignalDef));
}
void CDbcParser::ReadSignalValueTypeDef(CDbcSource& rSource)
{
// Get the message ID
auto prMsgId = GetUInt(rSource);
if (!prMsgId.second)
throw SDbcParserException("Expecting the message ID.");
if (prMsgId.first == m_uiIndepMsgId)
prMsgId.first = 0xffffffff;
auto itMsgDef = m_mapMsgDefById.find(prMsgId.first);
if (itMsgDef == m_mapMsgDefById.end())
throw SDbcParserException("Could not find message with supplied ID.");
// Get the signal name
std::string ssSignalName = GetIdentifier(rSource);
auto itSignal = std::find_if(itMsgDef->second->vecSignals.begin(), itMsgDef->second->vecSignals.end(),
[&](const SSignalDef& rsSignalDef)
{
return rsSignalDef.ssName == ssSignalName;
});
if (itSignal == itMsgDef->second->vecSignals.end())
throw SDbcParserException("Could not find signal with supplied name.");
// DEVIATION: The specification doesn't specifies a colon; CANdb++ inserts a colon
ExpectChar(':', rSource);
// Get the value type and if necessary update the value type enum of the signal.
auto prValType = GetUInt(rSource);
if (!prValType.second)
throw SDbcParserException("Expecting the value type (0..2).");
switch (prValType.first)
{
case 0: // Integer (signed/unsigned) is per default.
break;
case 1: // IEEE float
itSignal->eValType = SSignalDef::EValueType::ieee_float;
break;
case 2: // IEEE double
itSignal->eValType = SSignalDef::EValueType::ieee_double;
break;
default:
throw SDbcParserException("Invalid value type (0..2).");
break;
}
// Expecting the ending
if (!ExpectChar(';', rSource))
throw SDbcParserException("Semi-colon ';' expected.");
}
void CDbcParser::ReadMessageTransmitters(CDbcSource& rSource)
{
// Get the message ID
auto prMsgId = GetUInt(rSource);
if (!prMsgId.second)
throw SDbcParserException("Expecting the message ID.");
if (prMsgId.first == m_uiIndepMsgId)
prMsgId.first = 0xffffffff;
auto itMsgDef = m_mapMsgDefById.find(prMsgId.first);
if (itMsgDef == m_mapMsgDefById.end())
throw SDbcParserException("Could not find message with supplied ID.");
// Expect separator
if (!ExpectChar(':', rSource))
throw SDbcParserException("Colon ':' expected following 'BO_TX_BU_' message transmitters definition");
// Expect zero or more transmitters
do
{
// Check for semi-colon indicating the end of the definition.
if (ExpectChar(';', rSource)) break;
// Get the transmitter name
std::string ssTransmitter = GetIdentifier(rSource);
if (ssTransmitter.empty())
throw SDbcParserException("Expecting a transmitter name for the message.");
if (ssTransmitter != "Vector__XXX" && ssTransmitter != "Vector_XXX" && m_mapNodes.find(ssTransmitter) == m_mapNodes.end())
throw SDbcParserException("Expecting a valid pre-defined transmitter name for the message.");
if (std::find(itMsgDef->second->vecTransmitters.begin(), itMsgDef->second->vecTransmitters.end(), ssTransmitter) !=
itMsgDef->second->vecTransmitters.end())
throw SDbcParserException("Duplicate transmitter defined for the message.");
// Add the transmitter.
itMsgDef->second->vecTransmitters.push_back(ssTransmitter);
} while(true);
}
void CDbcParser::ReadValueDescriptions(CDbcSource& rSource)
{
TValDescMap* pmapValues = nullptr;
// Get the message ID - if existing, this indicates a signal value descriptions.
// Or a name - this indicates an environment variable
auto prMsgId = GetUInt(rSource);
if (prMsgId.second)
{
if (prMsgId.first == m_uiIndepMsgId)
prMsgId.first = 0xffffffff;
auto itMsgDef = m_mapMsgDefById.find(prMsgId.first);
if (itMsgDef == m_mapMsgDefById.end())
throw SDbcParserException("Could not find message with supplied ID.");
// Get the signal name
std::string ssSignalName = GetIdentifier(rSource);
auto itSignal = std::find_if(itMsgDef->second->vecSignals.begin(), itMsgDef->second->vecSignals.end(),
[&](const SSignalDef& rsSignalDef)
{
return rsSignalDef.ssName == ssSignalName;
});
if (itSignal == itMsgDef->second->vecSignals.end())
throw SDbcParserException("Could not find signal with supplied name.");
if (!itSignal->mapValueDescriptions.empty())
throw SDbcParserException("Duplicate value assignment.");
pmapValues = &itSignal->mapValueDescriptions;
}
else
{
std::string ssEnvVarName = GetIdentifier(rSource);
if (ssEnvVarName.empty())
throw SDbcParserException("Could not find message or environment variable.");
auto itVarDef = m_mapEnvVars.find(ssEnvVarName);
if (itVarDef == m_mapEnvVars.end())
throw SDbcParserException("Could not find environment variable with supplied name.");
pmapValues = &itVarDef->second.mapValueDescriptions;
}
if (!pmapValues)
throw SDbcParserException("Could not find message or environment variable.");
// Zero or more definitions can follow
TValDescMap mapValues;
do
{
auto prValue = GetUInt(rSource);
if (!prValue.second) break; // Not a value
auto prString = GetString(rSource);
if (!prString.second)
throw SDbcParserException("Expecting a string following the value.");
// Duplicate values are not allowed
if (mapValues.find(prValue.first) != mapValues.end())
throw SDbcParserException("Duplicate value definition.");
// Insert the value.
mapValues.insert(std::make_pair(prValue.first, prString.first));
} while (!rSource.IsEOF());
// Expect terminator
if (!ExpectChar(';', rSource))
throw SDbcParserException("Semi-colon ';' expected finalizing the definition of the 'VAL_'");
// Assign the values
*pmapValues = std::move(mapValues);
}
void CDbcParser::ReadEnvVarDef(CDbcSource& rSource)
{
SEnvVarDef sEnvVarDef;
// Get the name of the variable
sEnvVarDef.ssName = GetIdentifier(rSource);
if (sEnvVarDef.ssName.empty() || IsDbcIdentifier(sEnvVarDef.ssName))
throw SDbcParserException("Expecting a name for the environment variable.");
if (m_mapEnvVars.find(sEnvVarDef.ssName) != m_mapEnvVars.end())
throw SDbcParserException("Duplicate environment variable defined.");
// Expect separator
if (!ExpectChar(':', rSource))
throw SDbcParserException("Colon ':' expected following 'EV_' environment variable definition");
// Get the variable type
auto prType = GetUInt(rSource);
if (!prType.second)
throw SDbcParserException("Expecting the byte order indicator.");
switch (prType.first)
{
case 0:
sEnvVarDef.eType = SEnvVarDef::EType::integer;
break;
case 1:
sEnvVarDef.eType = SEnvVarDef::EType::floating_point;
break;
case 2:
sEnvVarDef.eType = SEnvVarDef::EType::string;
break;
default:
throw SDbcParserException("Invalid type defined for environment variable definition (0=integer, 1=float and 2=string are allowed).");
break;
}
// Get the opening square-bracket
if (!ExpectChar('[', rSource))
throw SDbcParserException("Left square-bracket '[' expected following the variable type in the environment variable definition");
// Get the minimum
auto prMinimum = GetDouble(rSource);
if (!prMinimum.second)
throw SDbcParserException("Expecting the minimum value.");
sEnvVarDef.dMinimum = prMinimum.first;
// Expect separator
if (!ExpectChar('|', rSource))
throw SDbcParserException("Pipe '|' expected following the minimum in the environment variable definition");
// Get the maximum
auto prMaximum = GetDouble(rSource);
if (!prMaximum.second)
throw SDbcParserException("Expecting the maximum value.");
sEnvVarDef.dMaximum = prMaximum.first;
// Get the closing square-bracket
if (!ExpectChar(']', rSource))
throw SDbcParserException("Right square-bracket ']' expected following the maximum in the environment variable definition");
// Get the unit string
auto prUnit = GetString(rSource);
if (!prUnit.second)
throw SDbcParserException("String expected following the minimum and maximum in the environment variable definition");
sEnvVarDef.ssUnit = prUnit.first;
// Get the initial value
auto prInitVal = GetDouble(rSource);
if (!prInitVal.second)
throw SDbcParserException("Expecting the initial value.");
sEnvVarDef.dInitVal = prInitVal.first;
// Get the variable ID
auto prId = GetUInt(rSource);
if (!prId.second)
throw SDbcParserException("Expecting the environment variable ID.");
sEnvVarDef.uiId = prId.first;
// Get the access type
std::string ssAccess = GetIdentifier(rSource);
if (ssAccess == "DUMMY_NODE_VECTOR0")
sEnvVarDef.eAccess = SEnvVarDef::EAccessType::unrestricted;
else if (ssAccess == "DUMMY_NODE_VECTOR1")
sEnvVarDef.eAccess = SEnvVarDef::EAccessType::read;
else if (ssAccess == "DUMMY_NODE_VECTOR2")
sEnvVarDef.eAccess = SEnvVarDef::EAccessType::write;
else if (ssAccess == "DUMMY_NODE_VECTOR3")
sEnvVarDef.eAccess = SEnvVarDef::EAccessType::readwrite;
else if (ssAccess == "DUMMY_NODE_VECTOR8000")
{
if (sEnvVarDef.eType != SEnvVarDef::EType::string)
throw SDbcParserException("The access type expects the environment variable to be a string.");
sEnvVarDef.eAccess = SEnvVarDef::EAccessType::unrestricted;
}
else if (ssAccess == "DUMMY_NODE_VECTOR8001")
{
if (sEnvVarDef.eType != SEnvVarDef::EType::string)
throw SDbcParserException("The access type expects the environment variable to be a string.");
sEnvVarDef.eAccess = SEnvVarDef::EAccessType::read;
}
else if (ssAccess == "DUMMY_NODE_VECTOR8002")
{
if (sEnvVarDef.eType != SEnvVarDef::EType::string)
throw SDbcParserException("The access type expects the environment variable to be a string.");
sEnvVarDef.eAccess = SEnvVarDef::EAccessType::write;
}
else if (ssAccess == "DUMMY_NODE_VECTOR8003")
{
if (sEnvVarDef.eType != SEnvVarDef::EType::string)
throw SDbcParserException("The access type expects the environment variable to be a string.");
sEnvVarDef.eAccess = SEnvVarDef::EAccessType::readwrite;
}
else
throw SDbcParserException("Invalid access type for the environment variable.");
// Get one or more access nodes
do
{
// Get the access node
std::string ssNode = GetIdentifier(rSource);
if (ssNode.empty() || IsDbcIdentifier(ssNode))
throw SDbcParserException("Expecting an access node for the environment variable.");
// Check the access node with the predefined nodes (except for "Vector__XXX" node)
if (ssNode != "Vector__XXX" && ssNode != "Vector_XXX" && m_mapNodes.find(ssNode) == m_mapNodes.end())
throw SDbcParserException("Expecting a valid pre-defined access node name for the environment variable.");
// Check for multiple definitions
if (std::find(sEnvVarDef.vecNodes.begin(), sEnvVarDef.vecNodes.end(), ssNode) != sEnvVarDef.vecNodes.end())
throw SDbcParserException("Duplicate access node name defined for the environment variable.");
// Add to the receiver vector
sEnvVarDef.vecNodes.push_back(std::move(ssNode));
// Check for additional receivers
if (!ExpectChar(',', rSource)) break;
} while(true);
// Expecting the ending
if (!ExpectChar(';', rSource))
throw SDbcParserException("Semi-colon ';' expected.");
// Add the variable to the message
m_mapEnvVars.insert(std::make_pair(sEnvVarDef.ssName, sEnvVarDef));
}
void CDbcParser::ReadEnvVarData(CDbcSource& rSource)
{
std::string ssEnvVarName = GetIdentifier(rSource);
if (ssEnvVarName.empty())
throw SDbcParserException("Expected environment variable name.");
auto itVarDef = m_mapEnvVars.find(ssEnvVarName);
if (itVarDef == m_mapEnvVars.end())
throw SDbcParserException("Could not find environment variable with supplied name.");
// Expect separator
if (!ExpectChar(':', rSource))
throw SDbcParserException("Colon ':' expected following 'ENVVAR_DATA_' environment variable data definition");
// Get the data size
auto prSize = GetUInt(rSource);
if (!prSize.second)
throw SDbcParserException("Expecting the data size.");
// Expecting the ending
if (!ExpectChar(';', rSource))
throw SDbcParserException("Semi-colon ';' expected.");
// Promote the data type of the variable to "data" and set the data size
itVarDef->second.eType = SEnvVarDef::EType::data;
itVarDef->second.uiDataSize = prSize.first;
}
void CDbcParser::ReadSignalTypeDef(CDbcSource& rSource)
{
// Get the message ID - if existing, this indicates a signal type def assignment.
// Or a name - this indicates a signal type definition.
auto prMsgId = GetUInt(rSource);
if (prMsgId.second)
{
if (prMsgId.first == m_uiIndepMsgId)
prMsgId.first = 0xffffffff;
auto itMsgDef = m_mapMsgDefById.find(prMsgId.first);
if (itMsgDef == m_mapMsgDefById.end())
throw SDbcParserException("Could not find message with supplied ID.");
// Get the signal name
std::string ssSignalName = GetIdentifier(rSource);
auto itSignal = std::find_if(itMsgDef->second->vecSignals.begin(), itMsgDef->second->vecSignals.end(),
[&](const SSignalDef& rsSignalDef)
{
return rsSignalDef.ssName == ssSignalName;
});
if (itSignal == itMsgDef->second->vecSignals.end())
throw SDbcParserException("Could not find signal with supplied name.");
if (!itSignal->ssSignalTypeDef.empty())
throw SDbcParserException("Duplicate signal type definition assignment.");
// Expect separator
if (!ExpectChar(':', rSource))
throw SDbcParserException("Colon ':' expected following 'SGTYPE_' signal type definition");
// Get the name of the signal type definition
std::string ssSignalTypeDef = GetIdentifier(rSource);
if (m_mapSigTypeDefs.find(ssSignalTypeDef) == m_mapSigTypeDefs.end())
throw SDbcParserException("Could not find signal type definition with supplied name.");
itSignal->ssSignalTypeDef = ssSignalTypeDef;
}
else
{
SSignalTypeDef sSignalTypeDef;
sSignalTypeDef.ssName = GetIdentifier(rSource);
if (sSignalTypeDef.ssName.empty())
throw SDbcParserException("Could not find signal type definition name.");
auto itTypeDef = m_mapSigTypeDefs.find(sSignalTypeDef.ssName);
if (itTypeDef != m_mapSigTypeDefs.end())
throw SDbcParserException("Duplicate signal type definition with supplied name.");
// Expect separator
if (!ExpectChar(':', rSource))
throw SDbcParserException("Colon ':' expected following 'SGTYPE_' signal type definition");
// Get the signal type def - base part
ReadSignalTypeDefBase(rSource, sSignalTypeDef);
// Get the default value
auto prDefaultVal = GetDouble(rSource);
if (!prDefaultVal.second)
throw SDbcParserException("Expecting the default value.");
sSignalTypeDef.dDefaultValue = prDefaultVal.first;
// Expect separator
if (!ExpectChar(',', rSource))
throw SDbcParserException("Comma ',' expected following default value in signal type definition");
// Value table name
sSignalTypeDef.ssValueTable = GetIdentifier(rSource);
if (sSignalTypeDef.ssValueTable != "Vector__XXX" && sSignalTypeDef.ssValueTable != "Vector_XXX")
{
if (sSignalTypeDef.ssValueTable.empty())
throw SDbcParserException("Expecting a value table name.");
if (m_mapValueTables.find(sSignalTypeDef.ssValueTable) == m_mapValueTables.end())
throw SDbcParserException("Value table not found.");
}
// Add the signal type definition
m_mapSigTypeDefs.insert(std::make_pair(sSignalTypeDef.ssName, sSignalTypeDef));
}
// Expecting the ending
if (!ExpectChar(';', rSource))
throw SDbcParserException("Semi-colon ';' expected.");
}
void CDbcParser::ReadSignalGroupDef(CDbcSource& rSource)
{
// Get the message ID and the belonging message
auto prMsgId = GetUInt(rSource);
if (!prMsgId.second)
throw SDbcParserException("No message ID supplied.");
if (prMsgId.first == m_uiIndepMsgId)
prMsgId.first = 0xffffffff;
auto itMsgDef = m_mapMsgDefById.find(prMsgId.first);
if (itMsgDef == m_mapMsgDefById.end())
throw SDbcParserException("Could not find message with supplied ID.");
// Get the signal group name
SSignalGroupDef sSigGrpDef;
sSigGrpDef.ssName = GetIdentifier(rSource);
if (sSigGrpDef.ssName.empty()) throw SDbcParserException("Missing signal group name.");
if (IsDbcIdentifier(sSigGrpDef.ssName)) throw SDbcParserException("Invalid signal group name.");
if (itMsgDef->second->mapSigGroups.find(sSigGrpDef.ssName) != itMsgDef->second->mapSigGroups.end())
throw SDbcParserException("Duplicate signal group definition.");
// Get repetition
auto prRepetition = GetUInt(rSource);
if (!prRepetition.second)
throw SDbcParserException("Expected repetition factor following the signal group name.");
sSigGrpDef.uiRepetitions = prRepetition.first;
// Expect separator
if (!ExpectChar(':', rSource))
throw SDbcParserException("Colon ':' expected following 'SIG_GROUP_' signal group definition");
// Expect zero or more signal definitions
do
{
// Check for semi-colon indicating the end of the definition.
if (ExpectChar(';', rSource)) break;
// Get the signal name
std::string ssSignalName = GetIdentifier(rSource);
if (ssSignalName.empty())
throw SDbcParserException("Expecting a signal name.");
auto itSignal = std::find_if(itMsgDef->second->vecSignals.begin(), itMsgDef->second->vecSignals.end(),
[&](const SSignalDef& rsSignalDef)
{
return rsSignalDef.ssName == ssSignalName;
});
if (itSignal == itMsgDef->second->vecSignals.end())
throw SDbcParserException("Could not find signal with supplied name.");
// Add the signal name.
sSigGrpDef.vecSignals.push_back(ssSignalName);
// DEVIATION: The specification doesn't specifies a comma
ExpectChar(',', rSource);
} while(true);
// Add the group to the message
itMsgDef->second->mapSigGroups.insert(std::make_pair(sSigGrpDef.ssName, sSigGrpDef));
}
void CDbcParser::ReadCommentDef(CDbcSource& rSource)
{
// Determine the entity the comment is for
std::vector<std::string>* pvecComments = nullptr;
std::string ssEntity = GetIdentifier(rSource);
if (ssEntity == "BU_")
{
// Find the node
std::string ssNodeName = GetIdentifier(rSource);
auto itNode = m_mapNodes.find(ssNodeName);
if (itNode == m_mapNodes.end())
throw SDbcParserException("Invalid node name.");
pvecComments = &itNode->second.vecComments;
}
else if (ssEntity == "BO_")
{
// Find the message
auto prMsgId = GetUInt(rSource);
if (!prMsgId.second)
throw SDbcParserException("Expecting the message ID.");
if (prMsgId.first == m_uiIndepMsgId)
prMsgId.first = 0xffffffff;
auto itMsgDef = m_mapMsgDefById.find(prMsgId.first);
if (itMsgDef == m_mapMsgDefById.end())
throw SDbcParserException("Could not find message with supplied ID.");
pvecComments = &itMsgDef->second->vecComments;
}
else if (ssEntity == "SG_")
{
// Find the message
auto prMsgId = GetUInt(rSource);
if (!prMsgId.second)
throw SDbcParserException("Expecting the message ID.");
if (prMsgId.first == m_uiIndepMsgId)
prMsgId.first = 0xffffffff;
auto itMsgDef = m_mapMsgDefById.find(prMsgId.first);
if (itMsgDef == m_mapMsgDefById.end())
throw SDbcParserException("Could not find message with supplied ID.");
// Find the signal
std::string ssSignalName = GetIdentifier(rSource);
auto itSignal = std::find_if(itMsgDef->second->vecSignals.begin(), itMsgDef->second->vecSignals.end(),
[&](const SSignalDef& rsSignalDef)
{
return rsSignalDef.ssName == ssSignalName;
});
if (itSignal == itMsgDef->second->vecSignals.end())
throw SDbcParserException("Could not find signal with supplied name.");
pvecComments = &itSignal->vecComments;
}
else if (ssEntity == "EV_")
{
// Find the environment variable
std::string ssEnvVarName = GetIdentifier(rSource);
if (ssEnvVarName.empty())
throw SDbcParserException("Could not find message or environment variable.");
auto itVarDef = m_mapEnvVars.find(ssEnvVarName);
if (itVarDef == m_mapEnvVars.end())
throw SDbcParserException("Could not find environment variable with supplied name.");
pvecComments = &itVarDef->second.vecComments;
}
else
pvecComments = &m_vecComments; // Global comments
// There should be a valid comments vector.
if (!pvecComments)
throw SDbcParserException("Internal error with comments vector.");
// Get the comment
auto prComment = GetString(rSource);
if (!prComment.second)
throw SDbcParserException("Mising comment string.");
// Add comment to definition
pvecComments->push_back(prComment.first);
// Expect terminator
if (!ExpectChar(';', rSource))
throw SDbcParserException("Semi-colon ';' expected finalizing the comment 'CM_'");
}
void CDbcParser::ReadAttrDef(CDbcSource& rSource)
{
std::string ssEntity = GetIdentifier(rSource);
SAttributeDef::EObjectType eObjType = SAttributeDef::EObjectType::global;
if (ssEntity == "BU_")
eObjType = SAttributeDef::EObjectType::node;
else if (ssEntity == "BO_")
eObjType = SAttributeDef::EObjectType::message;
else if (ssEntity == "SG_")
eObjType = SAttributeDef::EObjectType::signal;
else if (ssEntity == "EV_")
eObjType = SAttributeDef::EObjectType::envvar;
else if (!ssEntity.empty())
throw SDbcParserException("Invalid object type.");
// Expect opening quote
if (!ExpectChar('\"', rSource))
throw SDbcParserException("Quote '\"' expected preceding attribute definition name");
// Get the name
std::string ssName = GetIdentifier(rSource);
if (ssName.empty() || IsDbcIdentifier(ssName))
throw SDbcParserException("Expecting a name for the attribute definition.");
// Expect closing quote
if (!ExpectChar('\"', rSource))
throw SDbcParserException("Quote '\"' expected following attribute definition name");
// Get the value type
std::string ssValueType = GetIdentifier(rSource);
TAttributeDefPtr ptrAttrDef = std::make_shared<SAttributeDef>(SAttributeDef::EType::integer);
if (ssValueType == "INT")
{
auto prMin = GetInt(rSource);
if (!prMin.second) throw SDbcParserException("Expecting minimum value for integer attribute definition.");
ptrAttrDef->sIntValues.iMinimum = prMin.first;
auto prMax = GetInt(rSource);
if (!prMax.second) throw SDbcParserException("Expecting maximum value for integer attribute definition.");
ptrAttrDef->sIntValues.iMaximum = prMax.first;
} else if (ssValueType == "HEX")
{
ptrAttrDef = std::move(std::make_shared<SAttributeDef>(SAttributeDef::EType::hex_integer));
auto prMin = GetUInt(rSource);
if (!prMin.second) throw SDbcParserException("Expecting minimum value for hexadecimal attribute definition.");
ptrAttrDef->sHexValues.uiMinimum = prMin.first;
auto prMax = GetUInt(rSource);
if (!prMax.second) throw SDbcParserException("Expecting maximum value for hexadecimal attribute definition.");
ptrAttrDef->sHexValues.uiMaximum = prMax.first;
} else if (ssValueType == "FLOAT")
{
ptrAttrDef = std::move(std::make_shared<SAttributeDef>(SAttributeDef::EType::floating_point));
auto prMin = GetDouble(rSource);
if (!prMin.second) throw SDbcParserException("Expecting minimum value for floating point attribute definition.");
ptrAttrDef->sFltValues.dMinimum = prMin.first;
auto prMax = GetDouble(rSource);
if (!prMax.second) throw SDbcParserException("Expecting maximum value for floating point attribute definition.");
ptrAttrDef->sFltValues.dMaximum = prMax.first;
} else if (ssValueType == "STRING")
{
ptrAttrDef = std::move(std::make_shared<SAttributeDef>(SAttributeDef::EType::string));
} else if (ssValueType == "ENUM")
{
ptrAttrDef = std::move(std::make_shared<SAttributeDef>(SAttributeDef::EType::enumerator));
// Zero or more strings could available
bool bInitial = true;
do
{
// Try getting the enum entry string
auto prEnumEntry = GetString(rSource);
if (!bInitial && !prEnumEntry.second)
throw SDbcParserException("Expecting an enumerator entry string.");
bInitial = false;
// Not used or not applicable entries are added, but can be redundant.
// The use of "n/a" and "not-used" is not part of the official standard.
if (prEnumEntry.first != "not-used" && prEnumEntry.first != "n/a")
{
if (std::find(ptrAttrDef->sEnumValues.vecEnumValues.begin(), ptrAttrDef->sEnumValues.vecEnumValues.end(),
prEnumEntry.first) != ptrAttrDef->sEnumValues.vecEnumValues.end())
throw SDbcParserException("Duplicate enumerator entry string.");
}
// Add the value.
ptrAttrDef->sEnumValues.vecEnumValues.push_back(prEnumEntry.first);
// Another entry if a comma is provided
if (!ExpectChar(',', rSource)) break;
} while (true);
} else
throw SDbcParserException("Invalid attribute definition value type.");
// Add the attribute definition
ptrAttrDef->eObjType = eObjType;
ptrAttrDef->ssName = ssName;
m_mapAttrDefs.insert_or_assign(ssName, std::move(ptrAttrDef));
// Expect terminator
SkipWhitespace(rSource);
if (!ExpectChar(';', rSource))
throw SDbcParserException("Semi-colon ';' expected finalizing the attribute definition 'AB_DEF_'");
}
void CDbcParser::ReadAttrDefaultDef(CDbcSource& rSource)
{
// Expect opening quote
if (!ExpectChar('\"', rSource))
throw SDbcParserException("Quote '\"' expected preceding attribute definition name");
// Get the name
std::string ssName = GetIdentifier(rSource);
auto itAttrDef = m_mapAttrDefs.find(ssName);
if (itAttrDef == m_mapAttrDefs.end())
throw SDbcParserException("Cannot find attribute definition with supplied name.");
// Expect closing quote
if (!ExpectChar('\"', rSource))
throw SDbcParserException("Quote '\"' expected following attribute definition name");
// Get the value
switch (itAttrDef->second->eType)
{
case SAttributeDef::EType::integer:
{
// Some definitions use a float for defining an integer.
auto prFloat = GetDouble(rSource);
if (!prFloat.second)
throw SDbcParserException("Expecting an integer value for the default value of the attribute definition");
itAttrDef->second->sIntValues.iDefault = static_cast<int32_t>(prFloat.first);
break;
}
case SAttributeDef::EType::hex_integer:
{
// Some definitions use a float for defining an integer.
auto prFloat = GetDouble(rSource);
if (!prFloat.second)
throw SDbcParserException("Expecting an unsigned integer value for the default value of the attribute definition");
if (prFloat.first < 0.0)
throw SDbcParserException("Expecting an unsigned integer value for the default value of the attribute definition");
itAttrDef->second->sHexValues.uiDefault = static_cast<uint32_t>(prFloat.first);
break;
}
case SAttributeDef::EType::floating_point:
{
auto prFlt = GetDouble(rSource);
if (!prFlt.second)
throw SDbcParserException("Expecting a floating point value for the default value of the attribute definition");
itAttrDef->second->sFltValues.dDefault = prFlt.first;
break;
}
case SAttributeDef::EType::string:
{
auto prStr = GetString(rSource);
if (!prStr.second)
throw SDbcParserException("Expecting a string value for the default value of the attribute definition");
itAttrDef->second->sStringValues.ssDefault = std::move(prStr.first);
break;
}
case SAttributeDef::EType::enumerator:
{
auto prStr = GetString(rSource);
if (!prStr.second)
{
auto prInt = GetUInt(rSource);
if (!prInt.second)
throw SDbcParserException("Expecting a string value for the default value of the attribute definition");
if (prInt.first >= itAttrDef->second->sEnumValues.vecEnumValues.size())
throw SDbcParserException("Default value out of range for the attribute definition");
itAttrDef->second->sEnumValues.ssDefault = itAttrDef->second->sEnumValues.vecEnumValues[prInt.first];
}
else
{
// Non-documented extension: check the enum values without case consideration.
if (std::find_if(itAttrDef->second->sEnumValues.vecEnumValues.begin(), itAttrDef->second->sEnumValues.vecEnumValues.end(),
[&](const std::string& rss) {return internal::EqualNC(rss, prStr.first);}) == itAttrDef->second->sEnumValues.vecEnumValues.end())
throw SDbcParserException("The enum value doesn't fit the list of the predefined values.");
itAttrDef->second->sEnumValues.ssDefault = std::move(prStr.first);
}
break;
}
default:
throw SDbcParserException("Internal error: invalid attribute definition value type.");
break;
}
// Expect terminator
if (!ExpectChar(';', rSource))
throw SDbcParserException("Semi-colon ';' expected finalizing the attribute definition 'AB_DEF_DEF_'");
}
void CDbcParser::ReadAttributes(CDbcSource& rSource)
{
// Expect opening quote
if (!ExpectChar('\"', rSource))
throw SDbcParserException("Quote '\"' expected preceding attribute definition name");
// Get the name
std::string ssName = GetIdentifier(rSource);
auto itAttrDef = m_mapAttrDefs.find(ssName);
if (itAttrDef == m_mapAttrDefs.end())
throw SDbcParserException("Cannot find attribute definition with supplied name.");
// Expect closing quote
if (!ExpectChar('\"', rSource))
throw SDbcParserException("Quote '\"' expected following attribute definition name");
std::string ssEntity = GetIdentifier(rSource);
SAttributeDef::EObjectType eObjType = SAttributeDef::EObjectType::global;
std::vector<SAttributeValue>* pAttrVals = nullptr;
if (ssEntity == "BU_")
{
eObjType = SAttributeDef::EObjectType::node;
// Get the node definition
std::string ssNode = GetIdentifier(rSource);
auto itNode = m_mapNodes.find(ssNode);
if (itNode == m_mapNodes.end())
throw SDbcParserException("Cannot find node with supplied name.");
pAttrVals = &itNode->second.vecAttributes;
}
else if (ssEntity == "BO_")
{
eObjType = SAttributeDef::EObjectType::message;
// Get the message definition
auto prMsgId = GetUInt(rSource);
if (!prMsgId.second)
throw SDbcParserException("Expecting the message ID.");
if (prMsgId.first == m_uiIndepMsgId)
prMsgId.first = 0xffffffff;
auto itMsgDef = m_mapMsgDefById.find(prMsgId.first);
if (itMsgDef == m_mapMsgDefById.end())
throw SDbcParserException("Could not find message with supplied ID.");
pAttrVals = &itMsgDef->second->vecAttributes;
}
else if (ssEntity == "SG_")
{
eObjType = SAttributeDef::EObjectType::signal;
// Get the message definition
auto prMsgId = GetUInt(rSource);
if (!prMsgId.second)
throw SDbcParserException("Expecting the message ID.");
if (prMsgId.first == m_uiIndepMsgId)
prMsgId.first = 0xffffffff;
auto itMsgDef = m_mapMsgDefById.find(prMsgId.first);
if (itMsgDef == m_mapMsgDefById.end())
throw SDbcParserException("Could not find message with supplied ID.");
// Get the signal definition
std::string ssSignalDef = GetIdentifier(rSource);
auto itSignal = std::find_if(itMsgDef->second->vecSignals.begin(), itMsgDef->second->vecSignals.end(),
[&](const SSignalDef& rsSignalDef)
{
return rsSignalDef.ssName == ssSignalDef;
});
if (itSignal == itMsgDef->second->vecSignals.end())
throw SDbcParserException("Could not find signal with supplied name.");
pAttrVals = &itSignal->vecAttributes;
}
else if (ssEntity == "EV_")
{
eObjType = SAttributeDef::EObjectType::envvar;
// Get the environment variable definition
std::string ssEnvVarDef = GetIdentifier(rSource);
auto itEnvVarDef = m_mapEnvVars.find(ssEnvVarDef);
if (itEnvVarDef == m_mapEnvVars.end())
throw SDbcParserException("Cannot find environment variable definition with supplied name.");
pAttrVals = &itEnvVarDef->second.vecAttributes;
}
else if (ssEntity.empty())
{
eObjType = SAttributeDef::EObjectType::global;
// Global entity
pAttrVals = &m_vecAttributes;
}
// Check whether the object types match
if (itAttrDef->second->eObjType != eObjType)
throw SDbcParserException("Object type of attribute value is not fitting the object type of the attribute definition.");
// Get the attribute value
SAttributeValue sAttrVal(itAttrDef->second);
switch (itAttrDef->second->eType)
{
case SAttributeDef::EType::integer:
{
// Some definitions use a float for defining an integer.
auto prFloat = GetDouble(rSource);
if (!prFloat.second)
throw SDbcParserException("Expecting an integer value for the default value of the attribute definition");
sAttrVal.iValue = static_cast<int32_t>(prFloat.first);
break;
}
case SAttributeDef::EType::hex_integer:
{
// Some definitions use a float for defining an integer.
auto prFloat = GetDouble(rSource);
if (!prFloat.second)
throw SDbcParserException("Expecting an unsigned integer value for the default value of the attribute definition");
if (prFloat.first < 0.0)
throw SDbcParserException("Expecting an unsigned integer value for the default value of the attribute definition");
sAttrVal.uiValue = static_cast<uint32_t>(prFloat.first);
break;
}
case SAttributeDef::EType::floating_point:
{
auto prFlt = GetDouble(rSource);
if (!prFlt.second)
throw SDbcParserException("Expecting a floating point value for the default value of the attribute definition");
sAttrVal.dValue = prFlt.first;
break;
}
case SAttributeDef::EType::string:
{
auto prStr = GetString(rSource);
if (!prStr.second)
throw SDbcParserException("Expecting a string value for the default value of the attribute definition");
sAttrVal.ssValue = std::move(prStr.first);
break;
}
case SAttributeDef::EType::enumerator:
{
auto prStr = GetString(rSource);
if (!prStr.second)
{
auto prInt = GetUInt(rSource);
if (!prInt.second)
throw SDbcParserException("Expecting a string value for the default value of the attribute definition");
if (prInt.first >= itAttrDef->second->sEnumValues.vecEnumValues.size())
throw SDbcParserException("Default value out of range for the attribute definition");
sAttrVal.ssValue = itAttrDef->second->sEnumValues.vecEnumValues[prInt.first];
}
else
{
if (std::find(itAttrDef->second->sEnumValues.vecEnumValues.begin(), itAttrDef->second->sEnumValues.vecEnumValues.end(),
prStr.first) == itAttrDef->second->sEnumValues.vecEnumValues.end())
throw SDbcParserException("The enum value doesn't fit the list of the predefined values.");
sAttrVal.ssValue = std::move(prStr.first);
}
break;
}
default:
throw SDbcParserException("Internal error: invalid attribute definition value type.");
break;
}
// Add the value
if (!pAttrVals) throw SDbcParserException("Internal error: attribute value vector not existing.");
pAttrVals->push_back(std::move(sAttrVal));
// Expect terminator
if (!ExpectChar(';', rSource))
throw SDbcParserException("Semi-colon ';' expected finalizing the attribute value 'AB_'");
}
void CDbcParser::ReadSignalMultiplexDef(CDbcSource& rSource)
{
// Get the message definition
auto prMsgId = GetUInt(rSource);
if (!prMsgId.second)
throw SDbcParserException("Expecting the message ID.");
if (prMsgId.first == m_uiIndepMsgId)
prMsgId.first = 0xffffffff;
auto itMsgDef = m_mapMsgDefById.find(prMsgId.first);
if (itMsgDef == m_mapMsgDefById.end())
throw SDbcParserException("Could not find message with supplied ID.");
// Get the signal definition for the multiplexed signal
std::string ssMultiplexedSignalDef = GetIdentifier(rSource);
auto itMultiplexedSignal = std::find_if(itMsgDef->second->vecSignals.begin(), itMsgDef->second->vecSignals.end(),
[&](const SSignalDef& rsSignalDef)
{
return rsSignalDef.ssName == ssMultiplexedSignalDef;
});
if (itMultiplexedSignal == itMsgDef->second->vecSignals.end())
throw SDbcParserException("Could not find multiplexed signal with supplied name.");
// Get the signal definition for the multiplexor signal
std::string ssMultiplexorSignalDef = GetIdentifier(rSource);
auto itMultiplexorSignal = std::find_if(itMsgDef->second->vecSignals.begin(), itMsgDef->second->vecSignals.end(),
[&](const SSignalDef& rsSignalDef)
{
return rsSignalDef.ssName == ssMultiplexorSignalDef;
});
if (itMultiplexorSignal == itMsgDef->second->vecSignals.end())
throw SDbcParserException("Could not find multiplexor signal with supplied name.");
itMultiplexorSignal->uiMultiplexBitmask |= static_cast<uint32_t>(SSignalDef::EMultiplexBitmask::mltplx_switch);
// Create the information structure
SSignalDef::SExtendedMultiplex sExtMultiplex{ *itMultiplexorSignal, {} };
// Read zero or more ranges
do
{
auto itLow = GetUInt(rSource);
if (!itLow.second) break;
if (!ExpectChar('-', rSource))
throw SDbcParserException("Expecting dash '-' between low and and high range value for a multiplexed signal.");
auto itHigh = GetUInt(rSource);
if (!itHigh.second) throw SDbcParserException("Missing high range value for a multiplexed signal.");
sExtMultiplex.vecRanges.push_back(std::make_pair(itLow.first, itHigh.first));
// DEVIATION: The specification doesn't specifies a comma; the example does
ExpectChar(',', rSource);
} while (true);
// Add the multiplexed structure to the multiplexed signal
itMultiplexedSignal->vecExtMultiplex.push_back(std::move(sExtMultiplex));
// Expect terminator
if (!ExpectChar(';', rSource))
throw SDbcParserException("Semi-colon ';' expected finalizing the extended multiplexer definition 'SG_MUL_VAL_'");
}
} // namespace dbc
#ifdef _MSC_VER
#pragma warning(pop)
#endif