toys/dbcc/source/helper/gen_helper.cpp

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