Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SystemHandle::preprocess_types (ROS 2 Dynamic System Handle) #150

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ jobs:
- uses: actions/checkout@v3
with:
path: src/integration-service
submodules: 'true'

- name: Download required dependencies
run: |
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,6 @@ ENV/
.catkin_workspace
devel/
build/

# vscode
.txt.user
65 changes: 61 additions & 4 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ option(IS_COMPILE_DEBUG "Compile the Integration Service project in debug mode."

option(BUILD_LIBRARY "Compile the Integration Service" ON)

option(IS_XTYPES_THIRDPARTY "Allow to download thirdparty xtypes repository when needed." ON)

if(DEFINED CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE_LOWERCASE "" CACHE STRING "Build type to lowercase")
string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWERCASE)
Expand Down Expand Up @@ -56,7 +58,33 @@ endif()
# External dependencies for the Integration Service Core library
###############################################################################
if(BUILD_LIBRARY)
find_package(xtypes REQUIRED)
find_package(xtypes QUIET)

# if not externally provided use the thirdparty as external project
if(IS_XTYPES_THIRDPARTY AND NOT xtypes_FOUND)
message(STATUS "Updating submodules")
execute_process(
COMMAND git submodule update --init
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../
RESULT_VARIABLE EXECUTE_RESULT
)

if(NOT EXECUTE_RESULT EQUAL 0)
message(ERROR "Cannot update git submodules and xtypes are missing")
else()
include(ExternalProject)

ExternalProject_Add(xtypes-ext
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/../thirdparty/xtypes
INSTALL_DIR ${CMAKE_INSTALL_PREFIX}
CMAKE_ARGS
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>/xtypes
)
endif()
endif()

find_package(yaml-cpp REQUIRED)

Expand All @@ -82,6 +110,36 @@ if(BUILD_LIBRARY)
src/Instance.cpp
)

# if xtypes is not available use the ExternalProject
if(TARGET xtypes-ext)

# force the build
add_dependencies(${PROJECT_NAME} xtypes-ext)

# mimick xtypes target properties
# propagation is required for tools, utils and System Handles
target_compile_features(${PROJECT_NAME}
INTERFACE
cxx_std_17
cxx_variadic_macros
)

ExternalProject_Get_Property(xtypes-ext INSTALL_DIR)

target_include_directories(${PROJECT_NAME}
PUBLIC
${INSTALL_DIR}/xtypes/include
${INSTALL_DIR}/xtypes/thirdparty/cpp-peglib/include)

if(MSVC)
target_compile_options(${PROJECT_NAME}
PUBLIC
/Zc:preprocessor
/execution-charset:UTF-8)
endif(MSVC)

endif()

if (Sanitizers_FOUND)
add_sanitizers(${PROJECT_NAME})
endif()
Expand Down Expand Up @@ -127,7 +185,7 @@ if(BUILD_LIBRARY)
target_link_libraries(${PROJECT_NAME}
PUBLIC
yaml-cpp
xtypes
$<TARGET_NAME_IF_EXISTS:xtypes>
PRIVATE
Boost::program_options
$<$<PLATFORM_ID:Linux>:dl>
Expand All @@ -139,7 +197,6 @@ if(BUILD_LIBRARY)
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
#$<INSTALL_INTERFACE:${xtypes_INCLUDE_DIR}> #propagate the xtypes headers
)

target_compile_definitions(${PROJECT_NAME}
Expand Down Expand Up @@ -313,4 +370,4 @@ if(BUILD_API_REFERENCE)
DESTINATION
${CMAKE_INSTALL_PREFIX}
)
endif()
endif()
3 changes: 2 additions & 1 deletion core/cmake/common/gtest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,15 @@ macro(add_gtest)
endif()

foreach(GTEST_SOURCE_FILE ${GTEST_SOURCES})
file(STRINGS ${GTEST_SOURCE_FILE} GTEST_TEST_NAMES REGEX "^TEST")
file(STRINGS ${GTEST_SOURCE_FILE} GTEST_TEST_NAMES REGEX "^TEST_F|^TEST")
foreach(GTEST_TEST_NAME ${GTEST_TEST_NAMES})
string(REGEX REPLACE ["\) \(,"] ";" GTEST_TEST_NAME ${GTEST_TEST_NAME})
list(GET GTEST_TEST_NAME 1 GTEST_GROUP_NAME)
list(GET GTEST_TEST_NAME 3 GTEST_TEST_NAME)
add_test(NAME ${GTEST_GROUP_NAME}.${GTEST_TEST_NAME}
COMMAND ${command} --gtest_filter=${GTEST_GROUP_NAME}.${GTEST_TEST_NAME}:*/${GTEST_GROUP_NAME}.${GTEST_TEST_NAME}/*)


# Add environment
set(GTEST_ENVIRONMENT "")
if(WIN32)
Expand Down
1 change: 1 addition & 0 deletions core/include/is/core/Config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ struct MiddlewareConfig
std::string type;
std::vector<std::string> types_from;
YAML::Node config_node;
YAML::Node types_node;
};

/**
Expand Down
14 changes: 14 additions & 0 deletions core/include/is/systemhandle/SystemHandle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,20 @@ class SystemHandle
* @returns `true` if the SystemHandle is still working; `false` otherwise.
*/
virtual bool spin_once() = 0;

/**
* @brief Perform additional actions prior to configure the System Handle regarding types.
*
* @param[in] types_node A *YAML* node containing the types definition. This may be an empty node.
lauramg15 marked this conversation as resolved.
Show resolved Hide resolved
*
* @returns `true` if the preprocess stage ends successfully; `false` otherwise.
*/
virtual bool preprocess_types(
const YAML::Node& types_node)
{
(void) types_node;
return true;
}
};

/**
Expand Down
45 changes: 30 additions & 15 deletions core/src/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <is/core/Config.hpp>
#include <is/systemhandle/SystemHandle.hpp>

#include <algorithm>
#include <iostream>

namespace eprosima {
Expand Down Expand Up @@ -406,8 +407,8 @@ bool add_topic_or_service_config(
const YAML::Node& node,
const std::map<std::string, RouteType>& predefined_routes,
std::map<std::string, ConfigType>& config_map,
std::function<void(ConfigType&, std::string &&)> set_type,
std::function<void(ConfigType&, std::string &&)> set_reply_type,
std::function<void(ConfigType&, std::string&&)> set_type,
std::function<void(ConfigType&, std::string&&)> set_reply_type,
std::function<void(ConfigType&, const RouteType&)> set_route,
std::function<std::unique_ptr<RouteType>(const YAML::Node&)> parse_route)
{
Expand Down Expand Up @@ -845,7 +846,7 @@ bool Config::parse(

_m_middlewares.insert(
std::make_pair(
middleware_alias, MiddlewareConfig{middleware, types_from, config}));
middleware_alias, MiddlewareConfig{middleware, types_from, config, config_node["types"]}));
}

if (_m_middlewares.size() < 2)
Expand Down Expand Up @@ -1135,13 +1136,11 @@ bool Config::load_middlewares(
*/
is::internal::SystemHandleInfo info = is::internal::Register::get(middleware_type);

if (!info)
if (!info || !info.handle->preprocess_types(mw_config.types_node))
{
return false;
}

bool configured = true;

/**
* Now, it iterates the middleware required types map.
* For each middleware, it checks which types it needs, and places them into
Expand Down Expand Up @@ -1245,24 +1244,40 @@ bool Config::load_middlewares(
}
}
}

/**
* Finally, now that the SystemHandleInfo struct is filled with all its types, it
* calls to the SystemHandle::configure override function for the selected middleware.
*/
configured = info.handle->configure(
requirements->second, mw_config.config_node, info.types);
}
else
{
// Check if another middleware relies on types builtin or dynamically loaded by the middleware but not
// explicit in the configuration file
if ( middlewares.end() ==
std::find_if(middlewares.begin(), middlewares.end(), [&mw_name](const Entry& mw)
{
auto& from = mw.second.types_from;
return mw_name != mw.first && std::find(from.begin(), from.end(), mw_name) != from.end();
}))
{
logger << utils::Logger::Level::ERROR
<< "The middleware '" << mw_name
<< "' has no types associated" << std::endl;
return false;
}
}

/**
* If the middleware was correctly configured, it inserts it within the info_map.
* Finally, now that the SystemHandleInfo struct is filled with all its types, it
* calls to the SystemHandle::configure override function for the selected middleware.
*/
if (configured)
if ( info.handle->configure(
requirements->second, mw_config.config_node, info.types))
{
// If the middleware was correctly configured, it inserts it within the info_map.
info_map.insert(std::make_pair(mw_name, std::move(info)));
}
else
{
logger << utils::Logger::Level::ERROR
<< "The middleware '" << mw_name
<< "' configuration step failed" << std::endl;
return false;
}
}
Expand Down
37 changes: 37 additions & 0 deletions examples/basic/fastdds_ros2_dynamic__helloworld.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
types:
idls:
- >
#include <HelloWorld.idl>

module custom_msgs
{
module msg
{
struct HelloWorld2
{
custom_msgs::msg::HelloWorld h;
};
};
};

paths: ["/is_ws/src/is/examples/utils/dds/DDSHelloWorld/"]

systems:
dds_3:
type: fastdds
participant:
domain_id: 3

dds_5:
type: ros2_dynamic
namespace: foo/
node_name: "my_ros_node"
domain: 0

routes:
domain_3_to_5: { from: dds_3, to: dds_5 }
domain_5_to_3: { from: dds_5, to: dds_3 }

topics:
hello_domain_5: { type: "custom_msgs::msg::HelloWorld2", route: domain_3_to_5}
hello_domain_3: { type: "custom_msgs::msg::HelloWorld2", route: domain_5_to_3}
Empty file added thirdparty/COLCON_IGNORE
Empty file.