7 #include <boost/program_options.hpp>
\r
8 #include <boost/filesystem.hpp>
\r
10 #include "openxc/message_set.hpp"
\r
12 #define EXIT_SUCCESS 0
\r
13 #define EXIT_UNKNOWN_ERROR 1
\r
14 #define EXIT_COMMAND_LINE_ERROR 2
\r
15 #define EXIT_PROGRAM_ERROR 3
\r
17 /// @brief Generate the configuration code.
\r
18 /// @param[in] header Content to be inserted as a header.
\r
19 /// @param[in] footer Content to be inserted as a footer.
\r
20 /// @param[in] message_set Configuration read from the json file.
\r
21 /// @param[in] out Stream to write on.
\r
22 void generate(const std::string& header, const std::string& footer, const openxc::message_set& message_set, std::ostream& out)
\r
24 if (header.size()) out << header << "\n";
\r
25 else out << "#pragma once\n\n";
\r
27 out << "namespace generated {\n"
\r
28 << " class configuration_generated\n"
\r
31 << " can_message_set_t can_message_set_;\n"
\r
32 << " std::vector<std::vector<can_message_definition_t>> can_message_definition_;\n"
\r
33 << " std::vector<std::vector<can_signal_t>> can_signals_;\n"
\r
34 << " std::vector<std::vector<obd2_signal_t>> obd2_signals_;\n"
\r
36 << " configuration_generated()\n"
\r
37 << " : message_set_{0, \""
\r
38 << message_set.name() << "\", "
\r
39 << message_set.buses().size() << ", "
\r
40 << message_set.messages().size() << ", "
\r
42 std::begin(message_set.messages()),
\r
43 std::end(message_set.messages()),
\r
45 [](int sum, const std::map<std::string, openxc::can_message>::value_type& p) { return sum + p.second.signals().size(); }
\r
47 << message_set.commands().size() << ", "
\r
48 << message_set.diagnostic_messages().size() << "}\n"
\r
49 << " , can_message_definition_{\n";
\r
51 std::uint32_t count = message_set.messages().size();
\r
52 for(const std::map<std::string, openxc::can_message>::value_type& m : message_set.messages())
\r
54 out << " {{\"" << m.second.bus() << "\", "
\r
56 << "can_message_format_t::STANDARD, frequency_clock_t(), false}}";
\r
57 if (count > 1) out << ",";
\r
64 out << " , can_signals_" << "..." << "\n"
\r
65 << " , obd2_signals_" << "..." << "\n"
\r
71 out << footer << std::endl;
\r
74 /// @brief Read whole file content to a string.
\r
75 /// @param[in] file Path to the file.
\r
76 /// @return A std::string which contains the file content. If @c file is an empty string, the return value is also empty.
\r
77 /// @exception std::runtime_error Throw this exception if the specified file is not found or cannot be opened.
\r
78 std::string read_file(const std::string& file)
\r
80 if(file.size() == 0) return std::string();
\r
82 std::string content;
\r
83 std::ifstream stream(file);
\r
86 stream.seekg(0, std::ios::end);
\r
87 content.reserve(stream.tellg());
\r
88 stream.seekg(0, std::ios::beg);
\r
89 content.assign((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());
\r
92 std::stringstream ss;
\r
93 ss << "The specified file (" << file << ") is not found!";
\r
94 throw std::runtime_error(ss.str());
\r
97 /// @brief Read whole file content as a json document.
\r
98 /// @param[in] file Path to the file.
\r
99 /// @return A @c nlohmann::json object.
\r
100 /// @exception std::runtime_error Throw this exception if the specified file is not found or cannot be opened.
\r
101 nlohmann::json read_json(const std::string& file)
\r
103 std::ifstream stream(file);
\r
106 nlohmann::json result;
\r
110 std::stringstream ss;
\r
111 ss << "The specified file (" << file << ") is not found!";
\r
112 throw std::runtime_error(ss.str());
\r
115 /// @brief Entry point.
\r
116 /// @param[in] argc Argument's count.
\r
117 /// @param[in] argv Argument's array.
\r
118 /// @return Exit code, zero if success.
\r
119 int main(int argc, char** argv)
\r
121 std::ios::sync_with_stdio(false);
\r
125 std::string appName = boost::filesystem::basename(argv[0]);
\r
126 std::string message_set_file;
\r
127 std::string output_file;
\r
128 std::string header_file;
\r
129 std::string footer_file;
\r
131 namespace bpo = boost::program_options;
\r
132 bpo::options_description desc("Options");
\r
134 ("help,h", "Display this help.")
\r
135 ("message-set,m", bpo::value<std::string>(&message_set_file)->required(), "The message set definition file.")
\r
136 ("output,o", bpo::value<std::string>(&output_file), "An output file, if not specified stdout is used.")
\r
137 ("header,h", bpo::value<std::string>(&header_file), "A file to copy at the top of the generated output.")
\r
138 ("footer,f", bpo::value<std::string>(&footer_file), "A file to copy at the end of the generated output.");
\r
140 bpo::variables_map vm;
\r
143 bpo::store(bpo::parse_command_line(argc, argv, desc), vm);
\r
145 if (vm.count("help"))
\r
147 std::cout << desc << std::endl;
\r
148 return EXIT_SUCCESS;
\r
153 std::string header = read_file(header_file);
\r
154 std::string footer = read_file(footer_file);
\r
155 openxc::message_set message_set;
\r
156 message_set.from_json(read_json(message_set_file));
\r
158 if (output_file.size())
\r
160 out = std::ofstream(output_file);
\r
163 std::stringstream ss;
\r
164 ss << "Can't open the ouput file (" << output_file << ") for writing!";
\r
165 throw std::runtime_error(ss.str());
\r
169 generate(header, footer, message_set, output_file.size() ? out : std::cout);
\r
172 catch (bpo::required_option& e)
\r
174 std::cerr << "ERROR: Argument required - " << e.what() << std::endl;
\r
175 std::cout << desc << std::endl;
\r
176 return EXIT_COMMAND_LINE_ERROR;
\r
178 catch (bpo::error& e)
\r
180 std::cerr << "ERROR: Command line error - " << e.what() << std::endl;
\r
181 std::cout << desc << std::endl;
\r
182 return EXIT_COMMAND_LINE_ERROR;
\r
184 catch(std::exception& e)
\r
186 std::cerr << "ERROR: " << e.what() << std::endl;
\r
187 return EXIT_PROGRAM_ERROR;
\r
190 catch (std::exception& e)
\r
192 std::cerr << "ERROR: Unhandled exception - " << e.what() << std::endl;
\r
193 return EXIT_UNKNOWN_ERROR;
\r
196 return EXIT_SUCCESS;
\r