Update to match current binding expectations
[src/low-level-can-generator.git] / src / main.cpp
index d30428e..660c347 100644 (file)
 #include <iterator>\r
 #include <json.hpp>\r
 #include "openxc/message_set.hpp"\r
+#include "openxc/decoder.hpp"\r
 \r
 #define EXIT_SUCCESS                           0\r
 #define EXIT_UNKNOWN_ERROR                     1\r
 #define EXIT_COMMAND_LINE_ERROR                2\r
 #define EXIT_PROGRAM_ERROR                     3\r
 \r
+\r
+/*\r
+ * FLAGS\r
+ *\r
+ * Taken from include/low-can/can-message.hpp in agl-service-can-low-level.\r
+ * The flags values in the generated message_definition_t definitions needs to\r
+ * match usage of these flags in the binding, e.g. in the various member\r
+ * functions in low-can-binding/can/message-definition.cpp.\r
+ *\r
+ * ATM the only flags known to be used are:\r
+ *\r
+ * CAN_PROTOCOL_WITH_FD_FRAME\r
+ * J1939_PROTOCOL\r
+ * ISOTP_PROTOCOL\r
+ * BYTE_FRAME_IS_BIG_ENDIAN\r
+ *\r
+ * Note that for BYTE_FRAME_IS_BIG_ENDIAN, even though it is referenced in\r
+ * message-definition.cpp, the member function that does so seems currently\r
+ * unused, so it is not clear what the intended usage actually is.\r
+ * The JSON parser for CAN messages would likely need an additional field\r
+ * added to allow setting it, for now that is being left for a future update.\r
+ */\r
+\r
+#define CAN_PROTOCOL              0x0001\r
+#define CAN_PROTOCOL_WITH_FD_FRAME 0x0002\r
+#define J1939_ADDR_CLAIM_PROTOCOL  0x0004\r
+#define J1939_PROTOCOL            0x0008\r
+#define ISOTP_PROTOCOL            0x0010\r
+#define ISOTP_SEND                0x0020\r
+#define ISOTP_RECEIVE             0x0040\r
+#define BYTE_FRAME_IS_BIG_ENDIAN   0x0080\r
+#define BIT_POSITION_REVERSED     0x0100\r
+#define CONTINENTAL_BIT_POSITION   0x0200\r
+#define INVALID_FLAG              0x8000\r
+\r
+\r
+#define VERSION_LOW_CAN "2.0"\r
+\r
+\r
+std::string VERSION_FILE = "1.0";\r
+\r
 template <typename T>\r
 struct generator\r
 {\r
@@ -108,17 +150,17 @@ std::ostream& operator<<(std::ostream& o, const generator<std::vector<T>>& v)
 template <>\r
 std::ostream& operator<<(std::ostream& o, const generator<openxc::message_set>& v)\r
 {\r
-       o       << v.line_prefix_\r
-               << "{std::make_shared<can_message_set_t>(can_message_set_t{"\r
+       o       << "std::shared_ptr<message_set_t> cms = "\r
+               << "std::make_shared<message_set_t>(message_set_t{"\r
                << "0,"\r
                << gen(v.v_.name()) << ",\n"\r
-               << "\t\t\t{ // beginning can_message_definition_ vector\n"\r
-               << gen(v.v_.messages(), "\t\t\t")\r
-               << "\n\t\t}, // end can_message_definition vector\n"\r
-               << "\t\t\t{ // beginning diagnostic_messages_ vector\n"\r
-               << gen(v.v_.diagnostic_messages(),"\t\t\t") << "\n"\r
-               << "\t\t\t} // end diagnostic_messages_ vector\n"\r
-               << "\t\t})} // end can_message_set entry\n";\r
+               << "\t{ // beginning message_definition_ vector\n"\r
+               << gen(v.v_.messages(), "\t")\r
+               << "\t}, // end message_definition vector\n"\r
+               << "\t{ // beginning diagnostic_messages_ vector\n"\r
+               << gen(v.v_.diagnostic_messages(),"\t") << "\n"\r
+               << "\t} // end diagnostic_messages_ vector\n"\r
+               << "}); // end message_set entry\n";\r
        return o;\r
 }\r
 \r
@@ -146,22 +188,35 @@ std::ostream& operator<<(std::ostream& o, const generator<std::map<std::string,
 template <>\r
 std::ostream& operator<<(std::ostream& o, const generator<openxc::signal>& v)\r
 {\r
-       o       << v.line_prefix_ << "{std::make_shared<can_signal_t> (can_signal_t{\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
+       o       << v.line_prefix_ << "{std::make_shared<signal_t> (signal_t{\n"\r
+               << v.line_prefix_ << "\t" << gen(v.v_.generic_name()) << ",// generic_name\n"\r
+               << v.line_prefix_ << "\t" << v.v_.bit_position() << ",// bit_position\n"\r
+               << v.line_prefix_ << "\t" << v.v_.bit_size() << ",// bit_size\n"\r
+               << v.line_prefix_ << "\t" << gen(v.v_.factor()) << ",// factor\n"\r
+               << v.line_prefix_ << "\t" << gen(v.v_.offset()) << ",// offset\n"\r
+               << v.line_prefix_ << "\t" << "0,// min_value\n"\r
+               << v.line_prefix_ << "\t" << "0,// max_value\n"\r
+               << v.line_prefix_ << "\tfrequency_clock_t(" << gen(v.v_.max_frequency()) << "),// frequency\n"\r
+               << v.line_prefix_ << "\t" << gen(v.v_.send_same()) << ",// send_same\n"\r
+               << v.line_prefix_ << "\t" << gen(v.v_.force_send_changed()) << ",// force_send_changed\n"\r
+               << gen(v.v_.states(), v.line_prefix_ + '\t') << ",// states\n"\r
+               << v.line_prefix_ << '\t' << gen(v.v_.writable()) << ",// writable\n"\r
+               << v.line_prefix_ << '\t' << decoder_t::add_decoder(v.v_.decoder().size() ? v.v_.decoder() : v.v_.states().size() ? "decoder_t::decode_state" : "nullptr"\r
+                       , VERSION_FILE\r
+                       , VERSION_LOW_CAN) << ",// decoder\n"\r
+               << v.line_prefix_ << '\t' << (v.v_.encoder().size() ? v.v_.encoder() : "nullptr") << ",// encoder\n"\r
+               << v.line_prefix_ << '\t' << "false,// received\n";\r
+               std::string multi_first = "";\r
+               if(v.v_.multiplex().first){\r
+                       multi_first = "true";\r
+               }else{\r
+                       multi_first = "false";\r
+               }\r
+               std::string multi = "std::make_pair<bool, int>(" + multi_first + ", " + std::to_string(v.v_.multiplex().second) + ")";\r
+       o       << v.line_prefix_ << '\t' << multi << ",// multiplex\n"\r
+               << v.line_prefix_ << "\tstatic_cast<sign_t>(" << gen(v.v_.sign()) << "),// signed\n"\r
+               << v.line_prefix_ << '\t' << gen(v.v_.bit_sign_position()) << ",// bit_sign_position\n"\r
+               << v.line_prefix_ << "\t" << gen(v.v_.unit()) << "// unit\n"\r
                << v.line_prefix_ << "})}";\r
        return o;\r
 }\r
@@ -170,24 +225,43 @@ template <>
 std::ostream& operator<<(std::ostream& o, const generator<openxc::can_message>& v)\r
 {\r
        o       << v.line_prefix_\r
-               << "{std::make_shared<can_message_definition_t>(can_message_definition_t{"\r
+               << "{std::make_shared<message_definition_t>(message_definition_t{"\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()) << ",\n";\r
+               << "\"" << v.v_.name() << "\","\r
+               << (v.v_.length() != 0 ? v.v_.length() : 8) << ",";\r
+               uint32_t flags = 0;\r
+               if(v.v_.is_fd())\r
+               {\r
+                       flags = flags|CAN_PROTOCOL_WITH_FD_FRAME;\r
+               }\r
+\r
+               if(v.v_.is_j1939())\r
+               {\r
+                       flags = flags|J1939_PROTOCOL;\r
+               }\r
+\r
+               if(v.v_.is_isotp())\r
+               {\r
+                       flags = flags|ISOTP_PROTOCOL;\r
+               }\r
+\r
+               o << gen(flags) << ",";\r
+\r
+       o       << "frequency_clock_t(" << gen(v.v_.max_frequency()) << "),"\r
+               << gen(v.v_.force_send_changed()) << ",";\r
                std::uint32_t index = 0;\r
-       o       << "\t\t\t\t\t{ // beginning can_signals vector\n";\r
+       o       << "\n\t\t\t{ // beginning signals vector\n";\r
                        std::uint32_t signal_count = (uint32_t)v.v_.signals().size();\r
                        for(const openxc::signal& s : v.v_.signals())\r
                        {\r
-       o                       << gen(s, index,"\t\t\t\t\t\t");\r
+       o                       << gen(s, index,"\t\t\t\t");\r
                                if (signal_count > 1) o << ',';\r
                                --signal_count;\r
        o                       << '\n';\r
                        }\r
-       o       << "\t\t\t\t\t} // end can_signals vector\n"\r
-               << "\t\t\t\t})} // end can_message_definition entry\n";\r
+       o       << "\t\t\t} // end signals vector\n"\r
+               << "\t\t})} // end message_definition entry\n";\r
        return o;\r
 }\r
 \r
@@ -201,9 +275,10 @@ std::ostream& operator<<(std::ostream& o, const generator<openxc::diagnostic_mes
                << 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" << decoder_t::add_decoder((v.v_.decoder().size() ? v.v_.decoder() : "nullptr"),VERSION_FILE,VERSION_LOW_CAN) << ",\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_ << "\t" << "true" << ",\n"\r
+               << v.line_prefix_ << "\t" << "false" << "\n"\r
                << v.line_prefix_ << "})}\n";\r
        return o;\r
 }\r
@@ -215,49 +290,33 @@ std::ostream& operator<<(std::ostream& o, const generator<openxc::diagnostic_mes
 /// @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 \"application.hpp\"\n"\r
-               << "#include \"../can/can-decoder.hpp\"\n\n";\r
+       // Derive CAPI name from message set name\r
+       // (the name is lowercased and spaces are converted to dashes ('-')\r
+       std::string capi_name(message_set.name());\r
+       std::transform(capi_name.begin(), capi_name.end(), capi_name.begin(),\r
+                      [](unsigned char c){ return (c == ' ' ? '-' : std::tolower(c)); });\r
+\r
+       out << "#include <binding/application.hpp>\n"\r
+               << "#include <can/can-decoder.hpp>\n"\r
+               << "#include <can/can-encoder.hpp>\n\n";\r
 \r
        if (header.size()) out << header << "\n";\r
 \r
-       out     << "application_t::application_t()\n"\r
-               << "    : can_bus_manager_{utils::config_parser_t{\"/etc/dev-mapping.conf\"}}\n"\r
-               << "    , can_message_set_{\n"\r
+       out     << "extern \"C\" {\n"\r
+               << "CTLP_CAPI_REGISTER(\"" << capi_name << "\");\n"\r
+               << "\n"\r
                << gen(message_set, "\t\t")\r
-               << "\t} // end can_message_set vector\n"\r
-               << "{\n"\r
-               << "    for(auto& cms: can_message_set_)\n"\r
-               << "    {\n"\r
-               << "            std::vector<std::shared_ptr<can_message_definition_t> >& can_messages_definition = cms->get_can_message_definition();\n"\r
-               << "            for(auto& cmd : can_messages_definition)\n"\r
-               << "            {\n"\r
-               << "                    cmd->set_parent(cms.get());\n"\r
-               << "                    std::vector<std::shared_ptr<can_signal_t> >& can_signals = cmd->get_can_signals();\n"\r
-               << "                    for(auto& sig: can_signals)\n"\r
-               << "                    {\n"\r
-               << "                            sig->set_parent(cmd.get());\n"\r
-               << "                    }\n"\r
-               << "            }\n\n"\r
-               << "            std::vector<std::shared_ptr<diagnostic_message_t> >& diagnostic_messages = cms->get_diagnostic_messages();\n"\r
-               << "            for(auto& dm : diagnostic_messages)\n"\r
-               << "            {\n"\r
-               << "                    dm->set_parent(cms.get());\n"\r
-               << "            }\n"\r
-               << "    }\n"\r
-               << "            }\n\n"\r
-               << "const std::string application_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
+               << "\n"\r
+               << "CTLP_ONLOAD(plugin, handle) {\n"\r
+               << "\tafb_api_t api = (afb_api_t) plugin->api;\n"\r
+               << "\tCtlConfigT* CtlConfig = (CtlConfigT*) afb_api_get_userdata(api);\n"\r
+               << "\tapplication_t* app = (application_t*) getExternalData(CtlConfig);\n"\r
+               << "\n"\r
+               << "\treturn app->add_message_set(cms);\n"\r
+               << "}\n\n\n}\n";\r
+\r
+       out << decoder_t::apply_patch();\r
 \r
-       out     << "\treturn " << gen(active_bus) << ";\n"\r
-               << "}\n\n";\r
        out     << footer << std::endl;\r
 }\r
 \r
@@ -268,7 +327,7 @@ void generate(const std::string& header, const std::string& footer, const openxc
 std::string read_file(const std::string& file)\r
 {\r
        if(file.size() == 0) return std::string();\r
-       \r
+\r
        std::string content;\r
        std::ifstream stream(file);\r
        if (stream)\r
@@ -318,6 +377,8 @@ std::cout<<"         "<<"-o application-generated.cpp : output source file. Name
 /// @return Exit code, zero if success.\r
 int main(int argc, char *argv[])\r
 {\r
+\r
+       decoder_t::init_decoder();\r
        try\r
        {\r
                std::string appName = argv[0];\r
@@ -333,7 +394,7 @@ int main(int argc, char *argv[])
                        showhelpinfo(argv[0]);\r
                        exit(1);\r
                }\r
-               /*use function getopt to get the arguments with option."hu:p:s:v" indicate \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=(char)getopt(argc,argv,"m:h:f:o:"))!=-1)\r
@@ -384,7 +445,8 @@ int main(int argc, char *argv[])
                                throw std::runtime_error(ss.str());\r
                        }\r
                }\r
-               generate(header.str(), footer, message_set, output_file.size() ? out : std::cout); \r
+               VERSION_FILE = message_set.version();\r
+               generate(header.str(), footer, message_set, output_file.size() ? out : std::cout);\r
        }\r
        catch (std::exception& e)\r
        {\r