wip: generation of a configuration for can_signaling.
[apps/agl-service-can-low-level.git] / src / main.cpp
index 042781c..3de298a 100755 (executable)
 #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
+\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
+                       << "    //, obd2_signals_{" << "/*...*/" << "}\n"\r
+                       << "{\n"\r
                        << "}\n\n";\r
-       \r
        out << footer << std::endl;\r
 }\r
 \r
@@ -118,7 +260,7 @@ nlohmann::json read_json(const std::string& file)
 /// @return Exit code, zero if success.\r
 int main(int argc, char** argv)\r
 {\r
-       std::ios::sync_with_stdio(false);\r
+       //std::ios::sync_with_stdio(false);\r
        \r
        try\r
        {\r
@@ -149,11 +291,23 @@ int main(int argc, char** argv)
                        }\r
 \r
                        bpo::notify(vm);\r
-                       \r
-                       std::string header = read_file(header_file);\r
+\r
+                       std::stringstream header;\r
+                       header << read_file(header_file);\r
+                                               \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
+                       boost::filesystem::path message_set_path(message_set_file);\r
+                       message_set_path.remove_filename();\r
+                       for(const auto& s : message_set.extra_sources())\r
+                       {\r
+                               boost::filesystem::path extra_source(s);\r
+                               if (!extra_source.is_complete()) extra_source = message_set_path / extra_source;\r
+                               header << "\n// >>>>> " << s << " >>>>>\n" << read_file(extra_source.string()) << "\n// <<<<< " << s << " <<<<<\n";\r
+                       }\r
+\r
                        std::ofstream out;\r
                        if (output_file.size())\r
                        {\r
@@ -166,7 +320,7 @@ int main(int argc, char** argv)
                                }\r
                        }\r
                        \r
-                       generate(header, footer, message_set, output_file.size() ? out : std::cout); \r
+                       generate(header.str(), footer, message_set, output_file.size() ? out : std::cout); \r
 \r
                }\r
                catch (bpo::required_option& e)\r