422 lines
14 KiB
C++
422 lines
14 KiB
C++
#include "dbcc/helper/gen_helper.h"
|
|
|
|
#include <sstream>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <stdexcept>
|
|
|
|
#include "dbcc/dbc_iterator.h"
|
|
|
|
#include "dbcc/message.h" /**< ad::dbcc::Message */
|
|
#include "dbcc/helper/signal_helper.h"
|
|
|
|
#include "rapidjson/document.h" /**< rapidjson::Document */
|
|
#include "rapidjson/istreamwrapper.h" /**< rapidjson::IStreamWrapper */
|
|
|
|
namespace ad {
|
|
namespace dbcc {
|
|
namespace helper {
|
|
|
|
const std::string kDefaultIndentSpaces = " ";
|
|
const std::string kCPackAndUnpackMacros = std::string(
|
|
"#define PACK_LEFT_SHIFT(value,shift,mask) (uint8_t)((uint8_t)(value << "
|
|
"shift) & mask)\n"
|
|
"#define UNPACK_LEFT_SHIFT(_type,value,shift,mask) (_type)((_type)(value & "
|
|
"mask) << shift)\n"
|
|
"\n"
|
|
"#define PACK_RIGHT_SHIFT(value,shift,mask) (uint8_t)((uint8_t)(value >> "
|
|
"shift) & mask)\n"
|
|
"#define UNPACK_RIGHT_SHIFT(_type,value,shift,mask) (_type)((_type)(value "
|
|
"& mask) >> shift)\n");
|
|
|
|
inline const std::string GenerateIndent(int indent_level)
|
|
{
|
|
std::stringstream ss;
|
|
|
|
for (int i = 0; i < indent_level; i++) {
|
|
ss << kDefaultIndentSpaces;
|
|
}
|
|
|
|
return ss.str();
|
|
}
|
|
|
|
class GenHelper::Generator
|
|
{
|
|
public:
|
|
Generator(const std::string &dbc, const std::string &dbc_json) : iter_(dbc)
|
|
{
|
|
const std::vector<std::string> kRequiredKeys{"control", "feedback"};
|
|
std::ifstream ifs(dbc_json.c_str());
|
|
|
|
if (!ifs.good())
|
|
{
|
|
// Maybe the fail is not readable, not existent etc.
|
|
throw std::runtime_error("Failed to load the configuration file: " + dbc_json);
|
|
}
|
|
|
|
rapidjson::IStreamWrapper isw(ifs);
|
|
config_.ParseStream(isw);
|
|
|
|
// Check the required keys
|
|
for (auto &s : kRequiredKeys)
|
|
{
|
|
if (!config_.HasMember(s.c_str()))
|
|
{
|
|
throw std::runtime_error("Required key <" + s + "> is not existent!");
|
|
}
|
|
}
|
|
}
|
|
|
|
~Generator() = default;
|
|
|
|
inline std::string GenAll()
|
|
{
|
|
ad::dbcc::helper::NameSignalVector sigs;
|
|
std::stringstream ss;
|
|
|
|
// Headers
|
|
ss << "#include <stdint.h> /**< uint8_t uint16_t */\n"
|
|
<< "#include <stddef.h> /**< size_t */\n" << std::endl;
|
|
|
|
ss << kCPackAndUnpackMacros << std::endl;
|
|
|
|
for (auto &msg : config_["feedback"].GetObject())
|
|
{
|
|
sigs.clear();
|
|
|
|
ad::dbcc::Message msgp = FindMessageByName(msg.name.GetString());
|
|
|
|
for (auto &m : msg.value.GetObject())
|
|
{
|
|
size_t idx = msgp[m.name.GetString()];
|
|
if (idx != ad::dbcc::kInvalidIndex)
|
|
{
|
|
sigs.push_back(std::make_pair(m.name.GetString(), msgp[idx]));
|
|
} else {
|
|
throw std::runtime_error("The signal " + std::string(m.name.GetString()) + " is NOT existent!");
|
|
}
|
|
}
|
|
|
|
ss << GenHelper::GenMessageDef(msgp, sigs, 0) << std::endl;
|
|
ss << GenHelper::GenMessageUnpackDecl(msgp, 0) << std::endl;
|
|
ss << GenHelper::GenMessageUnpackDef(msgp, sigs, 0) << std::endl;
|
|
}
|
|
|
|
for (auto &msg : config_["control"].GetObject())
|
|
{
|
|
sigs.clear();
|
|
|
|
ad::dbcc::Message msgp = FindMessageByName(msg.name.GetString());
|
|
|
|
for (auto &m : msg.value.GetObject())
|
|
{
|
|
size_t idx = msgp[m.name.GetString()];
|
|
if (idx != ad::dbcc::kInvalidIndex)
|
|
{
|
|
sigs.push_back(std::make_pair(m.name.GetString(), msgp[idx]));
|
|
} else {
|
|
throw std::runtime_error("The signal " + std::string(m.name.GetString()) + " is NOT existent!");
|
|
}
|
|
}
|
|
|
|
ss << GenHelper::GenMessageDef(msgp, sigs, 0) << std::endl;
|
|
ss << GenHelper::GenMessagePackDecl(msgp, 0) << std::endl;
|
|
ss << GenHelper::GenMessagePackDef(msgp, sigs, 0) << std::endl;
|
|
}
|
|
|
|
return ss.str();
|
|
}
|
|
|
|
inline ad::dbcc::Message &FindMessageByName(const std::string &msg)
|
|
{
|
|
for (auto &m : iter_)
|
|
{
|
|
if (m.Name() == msg)
|
|
{
|
|
return m;
|
|
}
|
|
}
|
|
|
|
throw std::runtime_error("Message is NOT existent: " + msg);
|
|
}
|
|
|
|
inline ad::dbcc::helper::NameSignalVector GenSignalsFromMessage(const std::string &msg)
|
|
{
|
|
ad::dbcc::helper::NameSignalVector sigs;
|
|
|
|
if (config_["feedback"].HasMember(msg.c_str()))
|
|
{
|
|
if (config_["feedback"][msg.c_str()].IsObject())
|
|
{
|
|
ad::dbcc::Message msgp = FindMessageByName(msg);
|
|
|
|
for (auto &m : config_["feedback"][msg.c_str()].GetObject())
|
|
{
|
|
size_t idx = msgp[m.name.GetString()];
|
|
if (idx != ad::dbcc::kInvalidIndex)
|
|
{
|
|
sigs.push_back(std::make_pair(m.name.GetString(), msgp[idx]));
|
|
} else {
|
|
throw std::runtime_error("The signal " + std::string(m.name.GetString()) + " is NOT existent!");
|
|
}
|
|
}
|
|
} else {
|
|
throw std::runtime_error("The value of a message can ONLY be an object");
|
|
}
|
|
}
|
|
else if (config_["control"].HasMember(msg.c_str()))
|
|
{
|
|
if (config_["control"][msg.c_str()].IsObject())
|
|
{
|
|
ad::dbcc::Message msgp = FindMessageByName(msg);
|
|
|
|
for (auto &m : config_["control"][msg.c_str()].GetObject())
|
|
{
|
|
size_t idx = msgp[m.name.GetString()];
|
|
if (idx != ad::dbcc::kInvalidIndex)
|
|
{
|
|
sigs.push_back(std::make_pair(m.name.GetString(), msgp[idx]));
|
|
} else {
|
|
throw std::runtime_error("The signal " + std::string(m.name.GetString()) + " is NOT existent!");
|
|
}
|
|
}
|
|
} else {
|
|
throw std::runtime_error("The value of a message can ONLY be an object");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw std::runtime_error("The message is not existent: " + msg);
|
|
}
|
|
|
|
return sigs;
|
|
}
|
|
|
|
inline std::string GenMessageDef(const std::string &msg, int indent_level)
|
|
{
|
|
ad::dbcc::helper::NameSignalVector sigs = GenSignalsFromMessage(msg);
|
|
ad::dbcc::Message msgp = FindMessageByName(msg);
|
|
|
|
return GenHelper::GenMessageDef(msgp, sigs, indent_level);
|
|
}
|
|
|
|
inline std::string GenMessageUnpackDecl(const std::string &msg, int indent_level)
|
|
{
|
|
ad::dbcc::Message msgp = FindMessageByName(msg);
|
|
|
|
return GenHelper::GenMessageUnpackDecl(msgp, indent_level);
|
|
}
|
|
|
|
inline std::string GenMessageUnpackDef(const std::string &msg, int indent_level)
|
|
{
|
|
ad::dbcc::helper::NameSignalVector sigs = GenSignalsFromMessage(msg);
|
|
ad::dbcc::Message msgp = FindMessageByName(msg);
|
|
|
|
return GenHelper::GenMessageUnpackDef(msgp, sigs, indent_level);
|
|
}
|
|
|
|
inline std::string GenMessagePackDecl(const std::string &msg, int indent_level)
|
|
{
|
|
ad::dbcc::Message msgp = FindMessageByName(msg);
|
|
|
|
return GenHelper::GenMessagePackDecl(msgp, indent_level);
|
|
}
|
|
|
|
inline std::string GenMessagePackDef(const std::string &msg, int indent_level)
|
|
{
|
|
ad::dbcc::helper::NameSignalVector sigs = GenSignalsFromMessage(msg);
|
|
ad::dbcc::Message msgp = FindMessageByName(msg);
|
|
|
|
return GenHelper::GenMessagePackDef(msgp, sigs, indent_level);
|
|
}
|
|
|
|
private:
|
|
ad::dbcc::DbcIterator iter_;
|
|
rapidjson::Document config_;
|
|
};
|
|
|
|
GenHelper::GenHelper(const std::string &dbc, const std::string &dbc_json)
|
|
{
|
|
impl_ = std::unique_ptr<GenHelper::Generator>(new GenHelper::Generator(dbc, dbc_json));
|
|
}
|
|
|
|
GenHelper::~GenHelper() {}
|
|
|
|
std::string GenHelper::GenAll()
|
|
{
|
|
return impl_->GenAll();
|
|
}
|
|
|
|
std::string GenHelper::GenMessageDef(const std::string &msg, int indent_level)
|
|
{
|
|
return impl_->GenMessageDef(msg, indent_level);
|
|
}
|
|
|
|
std::string GenHelper::GenMessageUnpackDecl(const std::string &msg, int indent_level)
|
|
{
|
|
return impl_->GenMessageUnpackDecl(msg, indent_level);
|
|
}
|
|
|
|
std::string GenHelper::GenMessageUnpackDef(const std::string &msg, int indent_level)
|
|
{
|
|
return impl_->GenMessageUnpackDef(msg, indent_level);
|
|
}
|
|
|
|
std::string GenHelper::GenMessagePackDecl(const std::string &msg, int indent_level)
|
|
{
|
|
return impl_->GenMessagePackDecl(msg, indent_level);
|
|
}
|
|
|
|
std::string GenHelper::GenMessagePackDef(const std::string &msg, int indent_level)
|
|
{
|
|
return impl_->GenMessagePackDef(msg, indent_level);
|
|
}
|
|
|
|
/*
|
|
struct <msg.Name()>_<msg.Id()>
|
|
{
|
|
<type1> <sig1.Name()>;
|
|
<type2> <sig2.Name()>;
|
|
<type3> <sig3.Name()>;
|
|
...
|
|
};
|
|
*/
|
|
std::string GenHelper::GenMessageDef(const ad::dbcc::Message &msg, const ad::dbcc::helper::NameSignalVector &sigs,
|
|
int indent_level)
|
|
{
|
|
std::stringstream ss;
|
|
const std::string indent = GenerateIndent(indent_level);
|
|
const std::string indent2 = GenerateIndent(indent_level + 1);
|
|
ss << indent << "/* " << msg.Name() << "(0x" << std::hex << msg.Id() << std::dec << "), len: " << msg.Dlc() << " bytes */"
|
|
<< std::endl;
|
|
ss << indent << "typedef struct _" << msg.Name() << "_0x" << std::hex << msg.Id() << std::dec
|
|
<< std::endl;
|
|
ss << indent << "{" << std::endl;
|
|
for (const auto &sig : sigs) {
|
|
ad::dbcc::helper::SignalHelper sig_helper(sig.second);
|
|
|
|
std::string signal_member_name = sig.first.empty() ? sig.second.Name() : sig.first;
|
|
|
|
ss << indent2 << sig_helper.TypeName() << " "
|
|
<< signal_member_name << ";" << std::endl;
|
|
}
|
|
ss << indent << "} " << msg.Name() << "_0x" << std::hex << msg.Id() << std::dec << ";" << std::endl;
|
|
|
|
return ss.str();
|
|
}
|
|
|
|
std::string GenHelper::GenMessageUnpackDecl(const ad::dbcc::Message &msg, int indent_level)
|
|
{
|
|
std::stringstream ss;
|
|
const std::string indent = GenerateIndent(indent_level);
|
|
ss << indent << "/* Unpack message " << msg.Name() << "(0x" << std::hex << msg.Id() << std::dec << ") from a CAN data frame */"
|
|
<< std::endl;
|
|
ss << indent << "void Unpack_" << msg.Name() << "_0x" << std::hex << msg.Id() << std::dec
|
|
<< "(" << msg.Name() << "_0x" << std::hex << msg.Id() << std::dec << " *msg, const uint8_t *data, size_t len);" << std::endl;
|
|
|
|
return ss.str();
|
|
}
|
|
|
|
std::string GenHelper::GenMessageUnpackDef(const ad::dbcc::Message &msg, const ad::dbcc::helper::NameSignalVector &sigs,
|
|
int indent_level)
|
|
{
|
|
std::stringstream ss;
|
|
ss << msg.Name() << "_0x" << std::hex << msg.Id() << std::dec;
|
|
const std::string msg_name = ss.str();
|
|
|
|
const std::string indent = GenerateIndent(indent_level);
|
|
const std::string indent2 = GenerateIndent(indent_level + 1);
|
|
|
|
ss.str("");
|
|
ss.clear();
|
|
|
|
ss << indent << "/* Unpack message " << msg.Name() << "(0x" << std::hex << msg.Id() << std::dec << ") from a CAN data frame */"
|
|
<< std::endl;
|
|
ss << indent << "void Unpack_" << msg_name
|
|
<< "(" << msg_name << " *msg, const uint8_t *data, size_t len)" << std::endl;
|
|
ss << indent << "{" << std::endl;
|
|
|
|
bool need_new_line = false;
|
|
|
|
for (const auto &sig : sigs)
|
|
{
|
|
if (need_new_line)
|
|
{
|
|
ss << std::endl;
|
|
}
|
|
|
|
ad::dbcc::helper::SignalHelper sig_helper(sig.second);
|
|
std::string signal_member_name = sig.first.empty() ? sig.second.Name() : sig.first;
|
|
|
|
ss << indent2 << "/* " << sig.second.Name() << ": "
|
|
<< sig.second.StartBit() << ", " << sig.second.Length() << " */"
|
|
<< std::endl;
|
|
ss << sig_helper.Unpack2Code(signal_member_name, "msg->", indent_level + 1) << std::endl;
|
|
need_new_line = true;
|
|
}
|
|
|
|
ss << indent << "}" << std::endl;
|
|
|
|
return ss.str();
|
|
}
|
|
|
|
std::string GenHelper::GenMessagePackDecl(const ad::dbcc::Message &msg, int indent_level)
|
|
{
|
|
std::stringstream ss;
|
|
const std::string indent = GenerateIndent(indent_level);
|
|
ss << indent << "/* Pack message " << msg.Name() << "(0x" << std::hex << msg.Id() << std::dec << ") as a CAN data frame */"
|
|
<< std::endl;
|
|
ss << indent << "void Pack_" << msg.Name() << "_0x" << std::hex << msg.Id() << std::dec
|
|
<< "(const " << msg.Name() << "_0x" << std::hex << msg.Id() << std::dec << " *msg, uint8_t *data, size_t len);" << std::endl;
|
|
|
|
return ss.str();
|
|
}
|
|
|
|
std::string GenHelper::GenMessagePackDef(const ad::dbcc::Message &msg, const ad::dbcc::helper::NameSignalVector &sigs,
|
|
int indent_level)
|
|
{
|
|
std::stringstream ss;
|
|
ss << msg.Name() << "_0x" << std::hex << msg.Id() << std::dec;
|
|
const std::string msg_name = ss.str();
|
|
|
|
const std::string indent = GenerateIndent(indent_level);
|
|
const std::string indent2 = GenerateIndent(indent_level + 1);
|
|
|
|
ss.str("");
|
|
ss.clear();
|
|
|
|
ss << indent << "/* Pack message " << msg.Name() << "(0x" << std::hex << msg.Id() << std::dec << ") as a CAN data frame */"
|
|
<< std::endl;
|
|
ss << indent << "void Pack_" << msg_name
|
|
<< "(const " << msg_name << " *msg, uint8_t *data, size_t len)" << std::endl;
|
|
ss << indent << "{" << std::endl;
|
|
|
|
bool need_new_line = false;
|
|
|
|
for (const auto &sig : sigs)
|
|
{
|
|
if (need_new_line)
|
|
{
|
|
ss << std::endl;
|
|
}
|
|
|
|
ad::dbcc::helper::SignalHelper sig_helper(sig.second);
|
|
std::string signal_member_name = sig.first.empty() ? sig.second.Name() : sig.first;
|
|
|
|
ss << indent2 << "/* " << sig.second.Name() << ": "
|
|
<< sig.second.StartBit() << ", " << sig.second.Length() << " */"
|
|
<< std::endl;
|
|
ss << sig_helper.Pack2Code(signal_member_name, "msg->", indent_level + 1) << std::endl;
|
|
need_new_line = true;
|
|
}
|
|
|
|
ss << indent << "}" << std::endl;
|
|
|
|
return ss.str();
|
|
}
|
|
|
|
} // namespace helper
|
|
} // namespace dbcc
|
|
} // namespace ad
|
|
|