diff --git a/ev-dev-tools/src/ev_cli/ev.py b/ev-dev-tools/src/ev_cli/ev.py index f7c4684..e650f59 100755 --- a/ev-dev-tools/src/ev_cli/ev.py +++ b/ev-dev-tools/src/ev_cli/ev.py @@ -61,7 +61,7 @@ def setup_jinja_env(): }) -def generate_tmpl_data_for_if(interface, if_def, type_file): +def generate_tmpl_data_for_if(interface, if_def, type_file, quantity=1): helpers.parsed_enums.clear() helpers.parsed_types.clear() helpers.type_headers.clear() @@ -93,7 +93,7 @@ def generate_tmpl_data_for_if(interface, if_def, type_file): if enum_info and type_file: enums.append(enum_info) - cmds.append({'name': cmd, 'args': args, 'result': result_type_info}) + cmds.append({'name': cmd, 'args': args, 'result': result_type_info, 'quantity': quantity}) if type_file: for parsed_enum in helpers.parsed_enums: @@ -133,9 +133,13 @@ def generate_tmpl_data_for_if(interface, if_def, type_file): for value in errors_dict.values(): errors.extend(value.values()) + base_class_header = f'generated/interfaces/{interface}/Implementation.hpp' + if quantity > 1: + base_class_header = f'generated/interfaces/{interface}/ImplementationMultiple.hpp' + tmpl_data = { 'info': { - 'base_class_header': f'generated/interfaces/{interface}/Implementation.hpp', + 'base_class_header': base_class_header, 'interface': interface, 'desc': if_def['description'], 'type_headers': sorted(helpers.type_headers) @@ -158,14 +162,20 @@ def generate_tmpl_data_for_module(module, module_def): type_info = helpers.build_type_info(conf_id, conf_info['type']) config.append(type_info) + base_class = f'{impl_info["interface"]}ImplBase' + base_class_header = f'generated/interfaces/{impl_info["interface"]}/Implementation.hpp' + if impl_info.get('quantity', 1) > 1: + base_class_header = f'generated/interfaces/{impl_info["interface"]}/ImplementationMultiple.hpp' + base_class = f'{impl_info["interface"]}ImplBaseMultiple' provides.append({ 'id': impl, 'type': impl_info['interface'], + 'quantity': impl_info.get('quantity', 1), 'desc': impl_info['description'], 'config': config, 'class_name': f'{impl_info["interface"]}Impl', - 'base_class': f'{impl_info["interface"]}ImplBase', - 'base_class_header': f'generated/interfaces/{impl_info["interface"]}/Implementation.hpp' + 'base_class': base_class, + 'base_class_header': base_class_header }) requires = [] @@ -360,16 +370,21 @@ def generate_module_files(rel_mod_dir, update_flag, licenses): # load template data for interface if_def, last_mtime = load_interface_definition(interface) - if_tmpl_data = generate_tmpl_data_for_if(interface, if_def, False) + if_tmpl_data = generate_tmpl_data_for_if(interface, if_def, False, impl['quantity']) + + impl_base = 'ImplBase' + if impl['quantity'] > 1: + impl_base = f'{impl_base}Multiple' if_tmpl_data['info'].update({ 'hpp_guard': helpers.snake_case(f'{impl["id"]}_{interface}').upper() + '_IMPL_HPP', 'config': impl['config'], 'class_name': interface + 'Impl', - 'class_parent': interface + 'ImplBase', + 'class_parent': interface + impl_base, 'module_header': f'../{mod}.hpp', 'module_class': mod, - 'interface_implementation_id': impl['id'] + 'interface_implementation_id': impl['id'], + 'multiple': impl['quantity'] > 1 }) if_tmpl_data['info']['blocks'] = helpers.load_tmpl_blocks( @@ -495,6 +510,7 @@ def generate_interface_headers(interface, all_interfaces_flag, output_dir): # generate Base file (providers view) tmpl_data['info']['hpp_guard'] = helpers.snake_case(interface).upper() + '_IMPLEMENTATION_HPP' tmpl_data['info']['class_name'] = f'{interface}ImplBase' + tmpl_data['info']['multiple'] = False base_file = output_path / 'Implementation.hpp' @@ -506,6 +522,23 @@ def generate_interface_headers(interface, all_interfaces_flag, output_dir): 'printable_name': base_file.relative_to(output_path.parent) } + # generate Base-multiple file (providers view) + tmpl_data['info']['hpp_guard'] = helpers.snake_case(interface).upper() + '_IMPLEMENTATION_MULTIPLE_HPP' + tmpl_data['info']['class_name'] = f'{interface}ImplBaseMultiple' + tmpl_data['info']['multiple'] = True + + base_multiple_file = output_path / 'ImplementationMultiple.hpp' + + if_parts['base_multiple'] = { + 'path': base_multiple_file, + 'content': templates['interface_base'].render(tmpl_data), + 'template_path': Path(templates['interface_base'].filename), + 'last_mtime': last_mtime, + 'printable_name': base_multiple_file.relative_to(output_path.parent) + } + + del tmpl_data['info']['multiple'] + # generate Exports file (users view) tmpl_data['info']['hpp_guard'] = helpers.snake_case(interface).upper() + '_INTERFACE_HPP' tmpl_data['info']['class_name'] = f'{interface}Intf' @@ -651,10 +684,12 @@ def interface_genhdr(args): if not args.disable_clang_format: # FIXME (aw): this broken, because in case all_interfaces is true, if_parts might be none for invalid interface files helpers.clang_format(args.clang_format_file, if_parts['base']) + helpers.clang_format(args.clang_format_file, if_parts['base_multiple']) helpers.clang_format(args.clang_format_file, if_parts['exports']) helpers.clang_format(args.clang_format_file, if_parts['types']) helpers.write_content_to_file_and_check_template(if_parts['base'], primary_update_strategy, args.diff) + helpers.write_content_to_file_and_check_template(if_parts['base_multiple'], primary_update_strategy, args.diff) helpers.write_content_to_file_and_check_template(if_parts['exports'], primary_update_strategy, args.diff) helpers.write_content_to_file_and_check_template(if_parts['types'], primary_update_strategy, args.diff) diff --git a/ev-dev-tools/src/ev_cli/templates/helper_macros.j2 b/ev-dev-tools/src/ev_cli/templates/helper_macros.j2 index 6dc7a31..b45e74f 100644 --- a/ev-dev-tools/src/ev_cli/templates/helper_macros.j2 +++ b/ev-dev-tools/src/ev_cli/templates/helper_macros.j2 @@ -50,10 +50,13 @@ static_cast<{{ arg.cpp_type }}> ) {%- endmacro %} -{% macro handle_cmd_signature(cmd, class_name=None, interface=none) -%} +{% macro handle_cmd_signature(cmd, class_name=None, interface=none, multiple=false) -%} {% if not class_name %}virtual {% endif -%} {{ result_type(cmd.result, interface) }} {% if class_name %}{{ class_name }}::{% endif -%} handle_{{ cmd.name }}( +{%- if multiple -%} +std::size_t index, +{%- endif -%} {%- for arg in cmd.args -%} {{ cpp_type(arg) }}& {{ arg.name }}{{ ', ' if not loop.last }} {%- endfor -%} diff --git a/ev-dev-tools/src/ev_cli/templates/interface-Base.hpp.j2 b/ev-dev-tools/src/ev_cli/templates/interface-Base.hpp.j2 index 2dc3e5c..c6474f7 100644 --- a/ev-dev-tools/src/ev_cli/templates/interface-Base.hpp.j2 +++ b/ev-dev-tools/src/ev_cli/templates/interface-Base.hpp.j2 @@ -22,23 +22,34 @@ public: _name(name) { if (ev == nullptr) { EVLOG_error << "ev is nullptr, please check the initialization of the module"; - error_manager = nullptr; - error_state_monitor = nullptr; + {% if not info.multiple %} error_factory = nullptr; - EVLOG_error << "error_manager, error_state_monitor and error_factory are nullptr"; + {% endif %} + EVLOG_error << "error_manager, error_state_monitor are empty and error_factory is nullptr"; } else { error_manager = ev->get_error_manager_impl(name); - if (error_manager == nullptr) { - EVLOG_error << "error_manager is nullptr"; + if (error_manager.empty()) { + EVLOG_error << "error_manager is empty"; } + {% if info.multiple %} error_state_monitor = ev->get_error_state_monitor_impl(name); + if (error_state_monitor.empty()) { + EVLOG_error << "error_state_monitor is empty"; + } + error_factory = ev->get_error_factory(name); + if (error_factory.empty()) { + EVLOG_error << "error_factory is empty"; + } + {% else %} + error_state_monitor = ev->get_error_state_monitor_impl(name).at(0); if (error_state_monitor == nullptr) { EVLOG_error << "error_state_monitor is nullptr"; } - error_factory = ev->get_error_factory(name); + error_factory = ev->get_error_factory(name).at(0); if (error_factory == nullptr) { EVLOG_error << "error_factory is nullptr"; } + {% endif %} impl_mapping = Everest::get_impl_mapping(ev->get_mapping(), name); } } @@ -49,6 +60,9 @@ public: // publish functions for variables {% for var in vars %} void publish_{{ var.name }}( + {%- if info.multiple -%} + std::size_t _index, + {%- endif -%} {% if 'array_type' in var %} const std::vector<{{ var.array_type }}>& {%- elif 'object_type' in var %} @@ -62,10 +76,10 @@ public: {% if 'object_type' in var %} json json_value = value; Object object_value = json_value; - _ev->publish(_name, "{{ var.name }}", object_value); + _ev->publish({{ '_index' if info.multiple else '0'}}, _name, "{{ var.name }}", object_value); {% elif 'enum_type' in var %} auto value_string = {{ enum_to_string(var.enum_type) }}(value); - _ev->publish(_name, "{{ var.name }}", value_string); + _ev->publish({{ '_index' if info.multiple else '0'}}, _name, "{{ var.name }}", value_string); {% elif 'array_type' in var %} {% if 'array_type_contains_enum' in var %} std::vector string_array; @@ -73,39 +87,44 @@ public: for (const auto& entry : value) { string_array.push_back({{ enum_to_string(var.array_type) }}(entry)); } - _ev->publish(_name, "{{ var.name }}", string_array); + _ev->publish({{ '_index' if info.multiple else '0'}}, _name, "{{ var.name }}", string_array); {% else %} - _ev->publish(_name, "{{ var.name }}", value); + _ev->publish({{ '_index' if info.multiple else '0'}}, _name, "{{ var.name }}", value); {% endif %} {% else %} - _ev->publish(_name, "{{ var.name }}", value); + _ev->publish({{ '_index' if info.multiple else '0'}}, _name, "{{ var.name }}", value); {% endif %} } {% endfor %} {% endif %} - void raise_error(const Everest::error::Error& error) { - error_manager->raise_error(error); + void raise_error({{ 'std::size_t _index, ' if info.multiple}}const Everest::error::Error& error) { + error_manager.at({{ '_index' if info.multiple else '0'}})->raise_error(error); } - void clear_error(const Everest::error::ErrorType& type) { - error_manager->clear_error(type); + void clear_error({{ 'std::size_t _index, ' if info.multiple}}const Everest::error::ErrorType& type) { + error_manager.at({{ '_index' if info.multiple else '0'}})->clear_error(type); } - void clear_error(const Everest::error::ErrorType& type, const Everest::error::ErrorSubType& sub_type) { - error_manager->clear_error(type, sub_type); + void clear_error({{ 'std::size_t _index, ' if info.multiple}}const Everest::error::ErrorType& type, const Everest::error::ErrorSubType& sub_type) { + error_manager.at({{ '_index' if info.multiple else '0'}})->clear_error(type, sub_type); } - void clear_all_errors_of_impl() { - error_manager->clear_all_errors(); + void clear_all_errors_of_impl({{ 'std::size_t _index' if info.multiple}}) { + error_manager.at({{ '_index' if info.multiple else '0'}})->clear_all_errors(); } - void clear_all_errors_of_impl(const Everest::error::ErrorType& type) { - error_manager->clear_all_errors(type); + void clear_all_errors_of_impl({{ 'std::size_t _index, ' if info.multiple}}const Everest::error::ErrorType& type) { + error_manager.at({{ '_index' if info.multiple else '0'}})->clear_all_errors(type); } + {% if info.multiple %} + std::vector> error_state_monitor; + std::vector> error_factory; + {% else %} std::shared_ptr error_state_monitor; std::shared_ptr error_factory; + {% endif %} std::optional get_mapping() { return impl_mapping; @@ -117,14 +136,14 @@ protected: {% else %} // command handler functions (virtual) {% for cmd in cmds %} - {{ handle_cmd_signature(cmd, none, info.interface_name) }} = 0; + {{ handle_cmd_signature(cmd, none, info.interface_name, info.multiple) }} = 0; {% endfor %} {% endif %} private: Everest::ModuleAdapter* const _ev; const std::string _name; - std::shared_ptr error_manager; + std::vector> error_manager; std::optional impl_mapping; // helper function for getting all commands @@ -146,7 +165,7 @@ private: {% endfor %} }; {% endif %} - {{ cmd.name }}_cmd.cmd = [this](Parameters args) -> Result { + {{ cmd.name }}_cmd.cmd = [this](std::size_t{{ ' index' if info.multiple}}, Parameters args) -> Result { {% for arg in cmd.args %} {% if 'object_type' in arg %} {{ arg.object_type }} {{ arg.name }} = args["{{ arg.name }}"]; @@ -169,7 +188,7 @@ private: (void) args; // no arguments used for this callback {% endfor %} - {{ 'auto result = ' if cmd.result }}this->handle_{{ cmd.name }}( + {{ 'auto result = ' if cmd.result }}this->handle_{{ cmd.name }}({{ 'index,' if info.multiple}} {%- for arg in cmd.args -%} {{ arg.name }}{{ ', ' if not loop.last }} {%- endfor -%} diff --git a/ev-dev-tools/src/ev_cli/templates/interface-Impl.hpp.j2 b/ev-dev-tools/src/ev_cli/templates/interface-Impl.hpp.j2 index 20650e2..c8b06cf 100644 --- a/ev-dev-tools/src/ev_cli/templates/interface-Impl.hpp.j2 +++ b/ev-dev-tools/src/ev_cli/templates/interface-Impl.hpp.j2 @@ -37,7 +37,7 @@ protected: {% else %} // command handler functions (virtual) {% for cmd in cmds %} - {{ handle_cmd_signature(cmd, none, '::'+info.interface) }} override; + {{ handle_cmd_signature(cmd, none, '::'+info.interface, cmd.quantity > 1) }} override; {% endfor %} {% endif %}