+/*\r
+ * Copyright (C) 2015, 2016 "IoT.bzh"\r
+ * Author "Loïc Collignon" <loic.collignon@iot.bzh>\r
+ * Author "Romain Forlot" <romain.forlot@iot.bzh>\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#include <unistd.h>\r
+#include <stdlib.h>\r
+#include <libgen.h>\r
#include <exception>\r
#include <fstream>\r
#include <iostream>\r
#include <string>\r
#include <numeric>\r
#include <iterator>\r
-#include <boost/program_options.hpp>\r
-#include <boost/filesystem.hpp>\r
#include <json.hpp>\r
#include "openxc/message_set.hpp"\r
\r
#define EXIT_COMMAND_LINE_ERROR 2\r
#define EXIT_PROGRAM_ERROR 3\r
\r
+template <typename T>\r
+struct generator\r
+{\r
+ T v_;\r
+ std::string line_prefix_;\r
+ generator(T v, std::string line_prefix = "") : v_{v}, line_prefix_{line_prefix} {}\r
+};\r
+\r
+template <>\r
+struct generator<openxc::signal>\r
+{\r
+ const openxc::signal& v_;\r
+ std::uint32_t index_;\r
+ std::string line_prefix_;\r
+ generator(const openxc::signal& v, std::uint32_t index, std::string line_prefix = "")\r
+ : v_{v}, index_{index}, line_prefix_{line_prefix}\r
+ {\r
+ }\r
+};\r
+\r
+template <typename T>\r
+generator<T> gen(const T& v, std::string line_prefix = "") { return generator<T>(v, line_prefix); }\r
+\r
+generator<openxc::signal> gen(const openxc::signal& v, std::uint32_t index, std::string line_prefix = "")\r
+{\r
+ return generator<openxc::signal>(v, index, line_prefix);\r
+}\r
+\r
+template <typename T>\r
+std::ostream& operator<<(std::ostream& o, const generator<T>& v)\r
+{\r
+ o << v.line_prefix_ << v.v_;\r
+ return o;\r
+}\r
+\r
+template <>\r
+std::ostream& operator<<(std::ostream& o, const generator<bool>& v)\r
+{\r
+ o << v.line_prefix_ << (v.v_ ? "true" : "false");\r
+ return o;\r
+}\r
+\r
+template <>\r
+std::ostream& operator<<(std::ostream& o, const generator<float>& v)\r
+{\r
+ o << v.line_prefix_ << std::showpoint << v.v_ << "f";\r
+ return o;\r
+}\r
+\r
+template <>\r
+std::ostream& operator<<(std::ostream& o, const generator<std::string>& v)\r
+{\r
+ o << v.line_prefix_ << '\"' << v.v_ << '\"';\r
+ return o;\r
+}\r
+\r
+template <typename T>\r
+std::ostream& operator<<(std::ostream& o, const generator<std::vector<T>>& v)\r
+{\r
+ o << v.line_prefix_ << "{\n";\r
+ auto sz = v.v_.size();\r
+ for(const T& i : v.v_)\r
+ {\r
+ o << gen(i, v.line_prefix_ + '\t');\r
+ if (sz > 1) o << ",";\r
+ --sz;\r
+ o << '\n';\r
+ }\r
+ o << v.line_prefix_ << '}';\r
+ return o;\r
+}\r
+\r
+template <>\r
+std::ostream& operator<<(std::ostream& o, const generator<openxc::message_set>& v)\r
+{\r
+ o << v.line_prefix_\r
+ << '{'\r
+ << "0, "\r
+ << gen(v.v_.name()) << ", "\r
+ << v.v_.buses().size() << ", "\r
+ << v.v_.messages().size() << ", "\r
+ << std::accumulate(\r
+ std::begin(v.v_.messages()),\r
+ std::end(v.v_.messages()),\r
+ 0,\r
+ [](int sum, const openxc::can_message& p) { return sum + p.signals().size(); }\r
+ ) << ", "\r
+ << v.v_.commands().size() << ", "\r
+ << v.v_.diagnostic_messages().size() << "}";\r
+ return o;\r
+}\r
+\r
+template <>\r
+std::ostream& operator<<(std::ostream& o, const generator<openxc::can_message>& v)\r
+{\r
+ o << v.line_prefix_\r
+ << "can_message_definition_t("\r
+ << "0, "\r
+ << gen(v.v_.bus()) << ", "\r
+ << v.v_.id() << ", "\r
+ << "can_message_format_t::STANDARD, "\r
+ << "frequency_clock_t(" << gen(v.v_.max_frequency()) << "), "\r
+ << gen(v.v_.force_send_changed())\r
+ << ')';\r
+ return o;\r
+}\r
+\r
+template <>\r
+std::ostream& operator<<(std::ostream& o, const generator<std::map<std::string, std::vector<std::uint32_t>>>& v)\r
+{\r
+ o << v.line_prefix_ << "{\n";\r
+ std::uint32_t c1 = v.v_.size();\r
+ for(const auto& state : v.v_)\r
+ {\r
+ std::uint32_t c2 = state.second.size();\r
+ for(const auto& i : state.second)\r
+ {\r
+ o << v.line_prefix_ << "\t" << "{" << i << ", " << gen(state.first) << "}";\r
+ if (c1 > 1 || c2 > 1) o << ',';\r
+ o << '\n';\r
+ --c2;\r
+ }\r
+ --c1;\r
+ }\r
+ o << v.line_prefix_ << "}";\r
+ return o;\r
+}\r
+\r
+template <>\r
+std::ostream& operator<<(std::ostream& o, const generator<openxc::signal>& v)\r
+{\r
+ o << v.line_prefix_ << "{\n"\r
+ << v.line_prefix_ << "\t0,\n"\r
+ << v.line_prefix_ << "\t" << v.index_ << ",\n"\r
+ << v.line_prefix_ << "\t" << gen(v.v_.generic_name()) << ",\n"\r
+ << v.line_prefix_ << "\t" << v.v_.bit_position() << ",\n"\r
+ << v.line_prefix_ << "\t" << v.v_.bit_size() << ",\n"\r
+ << v.line_prefix_ << "\t" << gen(v.v_.factor()) << ", \n"\r
+ << v.line_prefix_ << "\t" << v.v_.offset() << ", \n"\r
+ << v.line_prefix_ << "\t" << "0,\n"\r
+ << v.line_prefix_ << "\t" << "0,\n"\r
+ << v.line_prefix_ << "\tfrequency_clock_t(" << gen(v.v_.max_frequency()) << "),\n"\r
+ << v.line_prefix_ << "\t" << gen(v.v_.send_same()) << ",\n"\r
+ << v.line_prefix_ << "\t" << gen(v.v_.force_send_changed()) << ",\n"\r
+ << gen(v.v_.states(), v.line_prefix_ + '\t') << ",\n"\r
+ << v.line_prefix_ << '\t' << gen(v.v_.writable()) << ",\n"\r
+ << v.line_prefix_ << '\t' << (v.v_.decoder().size() ? v.v_.decoder() : "nullptr") << ",\n"\r
+ << v.line_prefix_ << '\t' << (v.v_.encoder().size() ? v.v_.encoder() : "nullptr") << ",\n"\r
+ << v.line_prefix_ << '\t' << "false\n"\r
+ << v.line_prefix_ << "}";\r
+ return o;\r
+}\r
+\r
+template <>\r
+std::ostream& operator<<(std::ostream& o, const generator<openxc::diagnostic_message>& v)\r
+{\r
+ o << v.line_prefix_ << "{\n"\r
+ << v.line_prefix_ << "\t" << v.v_.pid() << ",\n"\r
+ << v.line_prefix_ << "\t" << gen(v.v_.name()) << ",\n"\r
+ << v.line_prefix_ << "\t" << 0 << ",\n"\r
+ << v.line_prefix_ << "\t" << 0 << ",\n"\r
+ << v.line_prefix_ << "\t" << "UNIT::INVALID" << ",\n"\r
+ << v.line_prefix_ << "\t" << gen(v.v_.frequency()) << ",\n"\r
+ << v.line_prefix_ << "\t" << (v.v_.decoder().size() ? v.v_.decoder() : "nullptr") << ",\n"\r
+ << v.line_prefix_ << "\t" << (v.v_.callback().size() ? v.v_.callback() : "nullptr") << ",\n"\r
+ << v.line_prefix_ << "\t" << "true" << "\n"\r
+ << v.line_prefix_ << "}";\r
+ return o;\r
+}\r
+\r
/// @brief Generate the configuration code.\r
/// @param[in] header Content to be inserted as a header.\r
/// @param[in] footer Content to be inserted as a footer.\r
/// @param[in] out Stream to write on.\r
void generate(const std::string& header, const std::string& footer, const openxc::message_set& message_set, std::ostream& out)\r
{\r
+ out << "#include \"configuration.hpp\"\n"\r
+ << "#include \"can/can-decoder.hpp\"\n\n";\r
+\r
if (header.size()) out << header << "\n";\r
- else out << "#pragma once\n\n";\r
- \r
- out << "namespace generated {\n"\r
- << " class configuration_generated\n"\r
+\r
+ out << "configuration_t::configuration_t()\n"\r
+ << " : can_message_set_{" << gen(message_set) << "}\n"\r
+ << " , can_message_definition_\n"\r
<< " {\n"\r
- << " private:\n"\r
- << " can_message_set_t can_message_set_;\n"\r
- << " std::vector<std::vector<can_message_definition_t>> can_message_definition_;\n"\r
- << " std::vector<std::vector<can_signal_t>> can_signals_;\n"\r
- << " std::vector<std::vector<obd2_signal_t>> obd2_signals_;\n"\r
- << " public:\n"\r
- << " configuration_generated()\n"\r
- << " : message_set_{0, \""\r
- << message_set.name() << "\", "\r
- << message_set.buses().size() << ", "\r
- << message_set.messages().size() << ", "\r
- << std::accumulate(\r
- std::begin(message_set.messages()),\r
- std::end(message_set.messages()),\r
- 0,\r
- [](int sum, const std::map<std::string, openxc::can_message>::value_type& p) { return sum + p.second.signals().size(); }\r
- ) << ", "\r
- << message_set.commands().size() << ", "\r
- << message_set.diagnostic_messages().size() << "}\n"\r
- << " , can_message_definition_{\n";\r
-\r
- std::uint32_t count = message_set.messages().size();\r
- for(const std::map<std::string, openxc::can_message>::value_type& m : message_set.messages())\r
+ << gen(message_set.messages(), "\t\t") << '\n'\r
+ << " }\n"\r
+ << " , can_signals_\n"\r
+ << " {\n";\r
+ std::uint32_t message_count = message_set.messages().size();\r
+ std::uint32_t index = 0;\r
+ for(const openxc::can_message& m : message_set.messages())\r
{\r
- out << " {{\"" << m.second.bus() << "\", "\r
- << m.first << ", "\r
- << "can_message_format_t::STANDARD, frequency_clock_t(), false}}";\r
- if (count > 1) out << ",";\r
- out << "\n";\r
- --count;\r
+ out << " {\n";\r
+ std::uint32_t signal_count = m.signals().size();\r
+ for(const openxc::signal& s : m.signals())\r
+ {\r
+ out << gen(s, index, " ");\r
+ if (signal_count > 1) out << ',';\r
+ --signal_count;\r
+ out << '\n';\r
+ }\r
+ out << " }";\r
+ if (index + 1 < message_count) out << ',';\r
+ ++index;\r
+ out << '\n';\r
}\r
- out << " }\n";\r
-\r
- \r
- out << " , can_signals_" << "..." << "\n"\r
- << " , obd2_signals_" << "..." << "\n"\r
- << " {\n"\r
- << " }\n"\r
- << " };\n"\r
+ out << " }\n"\r
+ << " , diagnostic_messages_\n"\r
+ << " {\n"\r
+ << gen(message_set.diagnostic_messages(), " ") << "\n"\r
+ << " }\n"\r
+ << "{\n"\r
+ << "}\n\n"\r
+ << "const std::string configuration_t::get_diagnostic_bus() const\n"\r
+ << "{\n";\r
+\r
+ std::string active_bus = "";\r
+ for (const auto& d : message_set.diagnostic_messages())\r
+ {\r
+ if (d.bus().size() == 0) std::cerr << "ERROR: The bus name should be set for each diagnostic message." << std::endl;\r
+ if (active_bus.size() == 0) active_bus = d.bus();\r
+ if (active_bus != d.bus()) std::cerr << "ERROR: The bus name should be the same for each diagnostic message." << std::endl;\r
+ }\r
+\r
+ out << " return " << gen(active_bus) << ";\n"\r
<< "}\n\n";\r
- \r
out << footer << std::endl;\r
}\r
\r
throw std::runtime_error(ss.str());\r
}\r
\r
+// function that show the help information\r
+void showhelpinfo(char *s)\r
+{\r
+std::cout<<"Usage: "<<s<<" <-m inpout.json> [-o configuration-generated.cpp]"<< std::endl;\r
+std::cout<<"option: "<<"-m input.json : JSON file describing CAN messages and signals"<< std::endl;\r
+std::cout<<" "<<"-h header.cpp : header source file insert at the beginning of generated file"<< std::endl;\r
+std::cout<<" "<<"-f footer.cpp : footer source file append to generated file."<< std::endl;\r
+std::cout<<" "<<"-o configuration-generated.cpp : output source file. Name has to be configuration-generated.cpp"<< std::endl;\r
+}\r
+\r
/// @brief Entry point.\r
/// @param[in] argc Argument's count.\r
/// @param[in] argv Argument's array.\r
/// @return Exit code, zero if success.\r
-int main(int argc, char** argv)\r
+int main(int argc, char *argv[])\r
{\r
- std::ios::sync_with_stdio(false);\r
- \r
try\r
{\r
- std::string appName = boost::filesystem::basename(argv[0]);\r
+ std::string appName = argv[0];\r
std::string message_set_file;\r
std::string output_file;\r
std::string header_file;\r
std::string footer_file;\r
\r
- namespace bpo = boost::program_options;\r
- bpo::options_description desc("Options");\r
- desc.add_options()\r
- ("help,h", "Display this help.")\r
- ("message-set,m", bpo::value<std::string>(&message_set_file)->required(), "The message set definition file.")\r
- ("output,o", bpo::value<std::string>(&output_file), "An output file, if not specified stdout is used.")\r
- ("header,h", bpo::value<std::string>(&header_file), "A file to copy at the top of the generated output.")\r
- ("footer,f", bpo::value<std::string>(&footer_file), "A file to copy at the end of the generated output.");\r
-\r
- bpo::variables_map vm;\r
- try\r
+ char tmp;\r
+ /*if the program is ran witout options ,it will show the usgage and exit*/\r
+ if(argc == 1)\r
{\r
- bpo::store(bpo::parse_command_line(argc, argv, desc), vm);\r
-\r
- if (vm.count("help"))\r
+ showhelpinfo(argv[0]);\r
+ exit(1);\r
+ }\r
+ /*use function getopt to get the arguments with option."hu:p:s:v" indicate \r
+ that option h,v are the options without arguments while u,p,s are the\r
+ options with arguments*/\r
+ while((tmp=getopt(argc,argv,"m:h:f:o:"))!=-1)\r
+ {\r
+ switch(tmp)\r
{\r
- std::cout << desc << std::endl;\r
- return EXIT_SUCCESS;\r
+ case 'h':\r
+ header_file = optarg;\r
+ break;\r
+ case 'f':\r
+ footer_file = optarg;\r
+ break;\r
+ case 'm':\r
+ message_set_file = optarg;\r
+ break;\r
+ case 'o':\r
+ output_file = optarg;\r
+ break;\r
+ default:\r
+ showhelpinfo(argv[0]);\r
+ break;\r
}\r
+ }\r
\r
- bpo::notify(vm);\r
- \r
- std::string header = read_file(header_file);\r
- std::string footer = read_file(footer_file);\r
- openxc::message_set message_set;\r
- message_set.from_json(read_json(message_set_file));\r
- std::ofstream out;\r
- if (output_file.size())\r
- {\r
- out = std::ofstream(output_file);\r
- if(!out)\r
- {\r
- std::stringstream ss;\r
- ss << "Can't open the ouput file (" << output_file << ") for writing!";\r
- throw std::runtime_error(ss.str());\r
- }\r
- }\r
- \r
- generate(header, footer, message_set, output_file.size() ? out : std::cout); \r
+ std::stringstream header;\r
+ header << read_file(header_file);\r
\r
- }\r
- catch (bpo::required_option& e)\r
- {\r
- std::cerr << "ERROR: Argument required - " << e.what() << std::endl;\r
- std::cout << desc << std::endl;\r
- return EXIT_COMMAND_LINE_ERROR;\r
- }\r
- catch (bpo::error& e)\r
+ std::string footer = read_file(footer_file);\r
+ openxc::message_set message_set;\r
+ message_set.from_json(read_json(message_set_file));\r
+\r
+ std::string message_set_path = dirname(strdup(message_set_file.c_str()));\r
+ for(const auto& s : message_set.extra_sources())\r
{\r
- std::cerr << "ERROR: Command line error - " << e.what() << std::endl;\r
- std::cout << desc << std::endl;\r
- return EXIT_COMMAND_LINE_ERROR;\r
+ std::string extra_source = s;\r
+ extra_source = message_set_path + "/" + extra_source;\r
+ header << "\n// >>>>> " << s << " >>>>>\n" << read_file(extra_source) << "\n// <<<<< " << s << " <<<<<\n";\r
}\r
- catch(std::exception& e)\r
+\r
+ std::ofstream out;\r
+ if (output_file.size())\r
{\r
- std::cerr << "ERROR: " << e.what() << std::endl;\r
- return EXIT_PROGRAM_ERROR;\r
+ out.open(output_file);\r
+ if(!out)\r
+ {\r
+ std::stringstream ss;\r
+ ss << "Can't open the ouput file (" << output_file << ") for writing!";\r
+ throw std::runtime_error(ss.str());\r
+ }\r
}\r
+ generate(header.str(), footer, message_set, output_file.size() ? out : std::cout); \r
}\r
catch (std::exception& e)\r
{\r
std::cerr << "ERROR: Unhandled exception - " << e.what() << std::endl;\r
return EXIT_UNKNOWN_ERROR;\r
}\r
-\r
return EXIT_SUCCESS;\r
}\r