diff --git a/CMakeLists.txt b/CMakeLists.txt index dc408822a..c4445b1fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,10 +29,12 @@ option(BUILD_SHARED_LIBS "Control shared/static building." ON) option(UAGENT_USE_SYSTEM_FASTDDS "Force find and use system installed Fast-DDS." OFF) option(UAGENT_USE_SYSTEM_FASTCDR "Force find and use system installed Fast-CDR." OFF) +option(UAGENT_USE_SYSTEM_LOGGER "Force find and use system installed spdlog." OFF) option(UAGENT_FAST_PROFILE "Build FastMiddleware profile." ON) option(UAGENT_CED_PROFILE "Build CedMiddleware profile." ON) option(UAGENT_DISCOVERY_PROFILE "Build Discovery profile." ON) option(UAGENT_P2P_PROFILE "Build P2P discovery profile." ON) +option(UAGENT_SOCKETCAN_PROFILE "Build Agent CAN FD transport." ON) option(UAGENT_LOGGER_PROFILE "Build logger profile." ON) option(UAGENT_SECURITY_PROFILE "Build security profile." OFF) option(UAGENT_BUILD_EXECUTABLE "Build Micro XRCE-DDS Agent provided executable." ON) @@ -54,6 +56,10 @@ if((CMAKE_SYSTEM_NAME STREQUAL "") AND (NOT CMAKE_HOST_SYSTEM_NAME STREQUAL "Lin set(UAGENT_P2P_PROFILE OFF) endif() +if((CMAKE_SYSTEM_NAME STREQUAL "Darwin") OR (CMAKE_SYSTEM_NAME STREQUAL "Windows")) + set(UAGENT_SOCKETCAN_PROFILE OFF) +endif() + set(UAGENT_CONFIG_RELIABLE_STREAM_DEPTH 16 CACHE STRING "Reliable streams depth.") set(UAGENT_CONFIG_BEST_EFFORT_STREAM_DEPTH 16 CACHE STRING "Best-effort streams depth.") set(UAGENT_CONFIG_HEARTBEAT_PERIOD 200 CACHE STRING "Heartbeat period in milliseconds.") @@ -97,8 +103,12 @@ if(UAGENT_FAST_PROFILE) endif() if(UAGENT_LOGGER_PROFILE) - set(_spdlog_version 1.4.2) - set(_spdlog_tag v1.4.2) + if(UAGENT_USE_SYSTEM_LOGGER) + set(_spdlog_version 1) + else() + set(_spdlog_version 1.9.2) + set(_spdlog_tag v1.9.2) + endif() list(APPEND _deps "spdlog\;${_spdlog_version}") endif() @@ -107,7 +117,7 @@ endif() ############################################################################### set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) if(NOT UAGENT_SUPERBUILD) - project(microxrcedds_agent VERSION "2.1.0" LANGUAGES C CXX) + project(microxrcedds_agent VERSION "2.1.1" LANGUAGES C CXX) else() project(uagent_superbuild NONE) include(${PROJECT_SOURCE_DIR}/cmake/SuperBuild.cmake) @@ -147,18 +157,18 @@ endforeach() # Sources ############################################################################### # Check platform. -if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android") +if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android" OR CMAKE_SYSTEM_NAME STREQUAL "Darwin") set(TRANSPORT_SRCS src/cpp/transport/udp/UDPv4AgentLinux.cpp src/cpp/transport/udp/UDPv6AgentLinux.cpp src/cpp/transport/tcp/TCPv4AgentLinux.cpp src/cpp/transport/tcp/TCPv6AgentLinux.cpp - src/cpp/transport/can/CanAgentLinux.cpp src/cpp/transport/serial/SerialAgentLinux.cpp src/cpp/transport/serial/TermiosAgentLinux.cpp src/cpp/transport/serial/MultiSerialAgentLinux.cpp src/cpp/transport/serial/MultiTermiosAgentLinux.cpp src/cpp/transport/serial/PseudoTerminalAgentLinux.cpp + $<$:src/cpp/transport/can/CanAgentLinux.cpp> $<$:src/cpp/transport/discovery/DiscoveryServerLinux.cpp> $<$:src/cpp/transport/p2p/AgentDiscovererLinux.cpp> ) diff --git a/cmake/SuperBuild.cmake b/cmake/SuperBuild.cmake index a4b38b2ec..3acb1edac 100644 --- a/cmake/SuperBuild.cmake +++ b/cmake/SuperBuild.cmake @@ -155,7 +155,7 @@ if(UAGENT_FAST_PROFILE AND NOT UAGENT_USE_SYSTEM_FASTDDS) endif() endif() -if(UAGENT_LOGGER_PROFILE) +if(UAGENT_LOGGER_PROFILE AND NOT UAGENT_USE_SYSTEM_LOGGER) # spdlog. unset(spdlog_DIR CACHE) find_package(spdlog ${_spdlog_version} EXACT QUIET) @@ -172,7 +172,7 @@ if(UAGENT_LOGGER_PROFILE) CMAKE_CACHE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= -DCMAKE_PREFIX_PATH:PATH=${CMAKE_PREFIX_PATH};${CMAKE_INSTALL_PREFIX} - -DBUILD_SHARED_LIBS:BOOL=${BUILD_SHARED_LIBS} + -DBUILD_SHARED_LIBS:BOOL=OFF -DCMAKE_TOOLCHAIN_FILE:PATH=${CMAKE_TOOLCHAIN_FILE} ${CROSS_CMAKE_ARGS} -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} diff --git a/include/uxr/agent/config.hpp.in b/include/uxr/agent/config.hpp.in index b9e40027e..e1fcaad7f 100644 --- a/include/uxr/agent/config.hpp.in +++ b/include/uxr/agent/config.hpp.in @@ -27,6 +27,7 @@ namespace uxr { #ifdef UAGENT_CED_PROFILE #cmakedefine UAGENT_P2P_PROFILE #endif +#cmakedefine UAGENT_SOCKETCAN_PROFILE #cmakedefine UAGENT_LOGGER_PROFILE const uint16_t DISCOVERY_PORT = 7400; diff --git a/include/uxr/agent/transport/serial/baud_rate_table_linux.h b/include/uxr/agent/transport/serial/baud_rate_table_linux.h index 44655dadc..55d47cb38 100644 --- a/include/uxr/agent/transport/serial/baud_rate_table_linux.h +++ b/include/uxr/agent/transport/serial/baud_rate_table_linux.h @@ -100,6 +100,7 @@ speed_t getBaudRate(const char* baudrate_str) { rv = B230400; } +#ifndef __APPLE__ else if (0 == strcmp(baudrate_str, "460800")) { rv = B460800; @@ -148,6 +149,7 @@ speed_t getBaudRate(const char* baudrate_str) { rv = B4000000; } +#endif // __APPLE__ else { speed_t custom_baud_rate = (speed_t)atoi(baudrate_str); diff --git a/include/uxr/agent/transport/stream_framing/StreamFramingProtocol.hpp b/include/uxr/agent/transport/stream_framing/StreamFramingProtocol.hpp index e3725bf80..7f0aa12ca 100644 --- a/include/uxr/agent/transport/stream_framing/StreamFramingProtocol.hpp +++ b/include/uxr/agent/transport/stream_framing/StreamFramingProtocol.hpp @@ -24,6 +24,8 @@ #ifdef _WIN32 #include typedef SSIZE_T ssize_t; +#else +#include #endif namespace eprosima { diff --git a/include/uxr/agent/utils/ArgumentParser.hpp b/include/uxr/agent/utils/ArgumentParser.hpp index eec38f740..fc6d77951 100644 --- a/include/uxr/agent/utils/ArgumentParser.hpp +++ b/include/uxr/agent/utils/ArgumentParser.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #ifdef _WIN32 #include @@ -33,12 +34,15 @@ #include #include #include -#include #include #include #include #include +#ifdef UAGENT_SOCKETCAN_PROFILE +#include +#endif // UAGENT_SOCKETCAN_PROFILE + #include #include #include @@ -61,7 +65,9 @@ enum class TransportKind TCP4, TCP6, #ifndef _WIN32 +#ifdef UAGENT_SOCKETCAN_PROFILE CAN, +#endif // UAGENT_SOCKETCAN_PROFILE SERIAL, MULTISERIAL, PSEUDOTERMINAL, @@ -867,7 +873,7 @@ class MultiSerialArgs : public PseudoTerminalArgs Argument file_; }; - +#ifdef UAGENT_SOCKETCAN_PROFILE /************************************************************************************************* * Specific arguments for CAN transports *************************************************************************************************/ @@ -919,6 +925,7 @@ class CanArgs Argument dev_; Argument can_id_; }; +#endif // UAGENT_SOCKETCAN_PROFILE #endif // _WIN32 /************************************************************************************************* @@ -937,7 +944,9 @@ class ArgumentParser , common_args_() , ip_args_() #ifndef _WIN32 +#ifdef UAGENT_SOCKETCAN_PROFILE , can_args_() +#endif // UAGENT_SOCKETCAN_PROFILE , serial_args_() , multiserial_args_() , pseudoterminal_args_() @@ -971,11 +980,13 @@ class ArgumentParser break; } #ifndef _WIN32 +#ifdef UAGENT_SOCKETCAN_PROFILE case TransportKind::CAN: { result &= can_args_.parse(argc_, argv_); break; } +#endif // UAGENT_SOCKETCAN_PROFILE case TransportKind::SERIAL: { result &= serial_args_.parse(argc_, argv_); @@ -1081,8 +1092,10 @@ class ArgumentParser ss << " * SERIAL (serial, multiserial, pseudoterminal)" << std::endl; ss << pseudoterminal_args_.get_help(); ss << serial_args_.get_help(); +#ifdef UAGENT_SOCKETCAN_PROFILE ss << " * CAN FD (canfd)" << std::endl; ss << can_args_.get_help(); +#endif // UAGENT_SOCKETCAN_PROFILE #endif // _WIN32 ss << std::endl; // TODO(@jamoralp): Once documentation is updated with proper CLI section, add here an hyperlink to that section @@ -1095,7 +1108,9 @@ class ArgumentParser CommonArgs common_args_; IPvXArgs ip_args_; #ifndef _WIN32 +#ifdef UAGENT_SOCKETCAN_PROFILE CanArgs can_args_; +#endif // UAGENT_SOCKETCAN_PROFILE SerialArgs serial_args_; MultiSerialArgs multiserial_args_; PseudoTerminalArgs pseudoterminal_args_; @@ -1162,6 +1177,7 @@ template<> inline bool ArgumentParser::launch_agent() return false; } +#ifdef UAGENT_SOCKETCAN_PROFILE template<> inline bool ArgumentParser::launch_agent() { uint32_t can_id = strtoul(can_args_.can_id().c_str(), NULL, 16); @@ -1179,6 +1195,7 @@ template<> inline bool ArgumentParser::launch_agent() return false; } +#endif // UAGENT_SOCKETCAN_PROFILE #endif // _WIN32 } // namespace parser diff --git a/src/cpp/AgentInstance.cpp b/src/cpp/AgentInstance.cpp index 519140644..df551dca8 100644 --- a/src/cpp/AgentInstance.cpp +++ b/src/cpp/AgentInstance.cpp @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include #include @@ -64,11 +65,13 @@ bool AgentInstance::create( break; } #ifndef _WIN32 +#ifdef UAGENT_SOCKETCAN_PROFILE case agent::TransportKind::CAN: { agent_thread_ = std::move(agent::create_agent_thread(argc, argv, exit_signal, valid_transport)); break; } +#endif // UAGENT_SOCKETCAN_PROFILE case agent::TransportKind::SERIAL: { agent_thread_ = std::move(agent::create_agent_thread(argc, argv, exit_signal, valid_transport)); diff --git a/src/cpp/middleware/fastdds/FastDDSEntities.cpp b/src/cpp/middleware/fastdds/FastDDSEntities.cpp index b7ef01f41..0124f16b4 100644 --- a/src/cpp/middleware/fastdds/FastDDSEntities.cpp +++ b/src/cpp/middleware/fastdds/FastDDSEntities.cpp @@ -360,7 +360,16 @@ static void set_qos_from_xrce_object( **********************************************************************************************************************/ FastDDSParticipant::~FastDDSParticipant() { - factory_->delete_participant(ptr_); + if (ptr_) + { + // TODO: Not available on foxy (Need FastDDS >= 2.2.0 for declaration and FastDDS >= 2.4.1 for implementation) + // if (ptr_->has_active_entities()) + { + // ptr_->delete_contained_entities(); + } + + factory_->delete_participant(ptr_); + } } bool FastDDSParticipant::create_by_ref( @@ -489,6 +498,35 @@ fastdds::dds::Publisher* FastDDSParticipant::create_publisher( ReturnCode_t FastDDSParticipant::delete_publisher( fastdds::dds::Publisher* publisher) { + if (NULL == publisher) + { + return ReturnCode_t::RETCODE_ALREADY_DELETED; + } + + if (publisher->has_datawriters()) + { + ReturnCode_t ret = ReturnCode_t::RETCODE_OK; + + // TODO: Not available on foxy (Need FastDDS >= 2.2.0 for declaration and FastDDS >= 2.4.1 for implementation) + // ret = publisher->delete_contained_entities(); + + //if (ReturnCode_t::RETCODE_UNSUPPORTED == ret) + { + std::vector writers; + publisher->get_datawriters(writers); + + for (auto datawriter : writers) + { + ret = publisher->delete_datawriter(datawriter); + + if (ReturnCode_t::RETCODE_OK != ret) + { + return ret; + } + } + } + } + return ptr_->delete_publisher(publisher); } @@ -503,6 +541,35 @@ fastdds::dds::Subscriber* FastDDSParticipant::create_subscriber( ReturnCode_t FastDDSParticipant::delete_subscriber( fastdds::dds::Subscriber* subscriber) { + if (NULL == subscriber) + { + return ReturnCode_t::RETCODE_ALREADY_DELETED; + } + + if (subscriber->has_datareaders()) + { + ReturnCode_t ret = ReturnCode_t::RETCODE_OK; + + // TODO: Not available on foxy (Need FastDDS >= 2.2.0 for declaration and FastDDS >= 2.4.1 for implementation) + // ret = subscriber->delete_contained_entities(); + + // if (ReturnCode_t::RETCODE_UNSUPPORTED == ret) + { + std::vector readers; + subscriber->get_datareaders(readers); + + for (auto datareader : readers) + { + ret = subscriber->delete_datareader(datareader); + + if (ReturnCode_t::RETCODE_OK != ret) + { + return ret; + } + } + } + } + return ptr_->delete_subscriber(subscriber); } @@ -750,6 +817,11 @@ fastdds::dds::DataWriter* FastDDSPublisher::create_datawriter( ReturnCode_t FastDDSPublisher::delete_datawriter( fastdds::dds::DataWriter* writer) { + if (NULL == writer) + { + return ReturnCode_t::RETCODE_ALREADY_DELETED; + } + return ptr_->delete_datawriter(writer); } @@ -809,6 +881,11 @@ fastdds::dds::DataReader* FastDDSSubscriber::create_datareader( ReturnCode_t FastDDSSubscriber::delete_datareader( fastdds::dds::DataReader* reader) { + if (NULL == reader) + { + return ReturnCode_t::RETCODE_ALREADY_DELETED; + } + return ptr_->delete_datareader(reader); } diff --git a/src/cpp/processor/Processor.cpp b/src/cpp/processor/Processor.cpp index 9964d36d3..98ecf3a06 100644 --- a/src/cpp/processor/Processor.cpp +++ b/src/cpp/processor/Processor.cpp @@ -781,6 +781,16 @@ bool Processor::process_get_info_packet( dds::xrce::ResultStatus result_status = root_.get_info(object_info); if (dds::xrce::STATUS_OK == result_status.status()) { + uint32_t raw_client_key; + if (server_.get_client_key(input_packet.source, raw_client_key)) + { + result_status.implementation_status(1); + } + else + { + result_status.implementation_status(0); + } + dds::xrce::AGENT_ActivityInfo agent_info; agent_info.availability(1); diff --git a/src/cpp/transport/can/CanAgentLinux.cpp b/src/cpp/transport/can/CanAgentLinux.cpp index 88f83b536..269407c43 100644 --- a/src/cpp/transport/can/CanAgentLinux.cpp +++ b/src/cpp/transport/can/CanAgentLinux.cpp @@ -28,13 +28,14 @@ namespace eprosima { namespace uxr { CanAgent::CanAgent( - char const * dev, + char const* dev, uint32_t can_id, Middleware::Kind middleware_kind) : Server{middleware_kind} , dev_{dev} , can_id_{can_id} -{} +{ +} CanAgent::~CanAgent() { @@ -60,7 +61,7 @@ bool CanAgent::init() if (-1 != poll_fd_.fd) { - struct sockaddr_can address{}; + struct sockaddr_can address {}; struct ifreq ifr; // Get interface index by name @@ -72,12 +73,12 @@ bool CanAgent::init() address.can_ifindex = ifr.ifr_ifindex; if (-1 != bind(poll_fd_.fd, - reinterpret_cast(&address), - sizeof(address))) + reinterpret_cast(&address), + sizeof(address))) { // Enable CAN FD if (-1 != setsockopt(poll_fd_.fd, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, - &enable_canfd, sizeof(enable_canfd))) + &enable_canfd, sizeof(enable_canfd))) { poll_fd_.events = POLLIN; rv = true; @@ -88,15 +89,7 @@ bool CanAgent::init() dev_, poll_fd_.fd); - // TODO: add filter for micro-ROS msgs?? - /* - struct can_filter rfilter; - - rfilter.can_id = 22; - rfilter.can_mask = CAN_EFF_MASK; - - setsockopt(poll_fd_.fd, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter)); - */ + // TODO: add filter for micro-ROS devices } else { @@ -153,7 +146,6 @@ bool CanAgent::fini() return rv; } - bool CanAgent::recv_message( InputPacket& input_packet, int timeout, @@ -166,19 +158,25 @@ bool CanAgent::recv_message( if (0 < poll_rv) { - if (0 < read(poll_fd_.fd, &frame, static_cast(CANFD_MTU))) + if (0 < read(poll_fd_.fd, &frame, sizeof(struct canfd_frame))) { // Omit EFF, RTR, ERR flags (Assume EFF on CAN FD) uint32_t can_id = frame.can_id & CAN_ERR_MASK; + size_t len = frame.data[0]; // XRCE payload lenght - input_packet.message.reset(new InputMessage(frame.data, size_t(frame.len))); + if (len > (CANFD_MTU - 1)) + { + // Overflow MTU (63 bytes) + return false; + } + + input_packet.message.reset(new InputMessage(&frame.data[1], len)); input_packet.source = CanEndPoint(can_id); rv = true; uint32_t raw_client_key; if (Server::get_client_key(input_packet.source, raw_client_key)) { - // TODO: add can_id to messages? UXR_AGENT_LOG_MESSAGE( UXR_DECORATE_YELLOW("[==>> CAN <<==]"), raw_client_key, @@ -208,9 +206,9 @@ bool CanAgent::send_message( struct pollfd poll_fd_write_; size_t packet_len = output_packet.message->get_len(); - if (packet_len > CANFD_MTU) + if (packet_len > (CANFD_MTU - 1)) { - // Overflow MTU + // Overflow MTU (63 bytes) return 0; } @@ -220,11 +218,13 @@ bool CanAgent::send_message( if (0 < poll_rv) { - frame.can_id = output_packet.destination.get_can_id(); - frame.len = (uint8_t) packet_len; - memcpy(&frame.data[0], output_packet.message->get_buf(), packet_len); + frame.can_id = output_packet.destination.get_can_id() | CAN_EFF_FLAG; + frame.data[0] = (uint8_t) packet_len; // XRCE payload lenght + frame.len = (uint8_t) (packet_len + 1); // CAN frame DLC + + memcpy(&frame.data[1], output_packet.message->get_buf(), packet_len); - if (0 < ::write(poll_fd_.fd, &frame, static_cast(CANFD_MTU))) + if (0 < ::write(poll_fd_.fd, &frame, sizeof(struct canfd_frame))) { rv = true; diff --git a/src/cpp/transport/tcp/TCPv4AgentLinux.cpp b/src/cpp/transport/tcp/TCPv4AgentLinux.cpp index 38d6095c7..2a4b31499 100644 --- a/src/cpp/transport/tcp/TCPv4AgentLinux.cpp +++ b/src/cpp/transport/tcp/TCPv4AgentLinux.cpp @@ -83,6 +83,15 @@ bool TCPv4Agent::init() if (-1 != listener_poll_.fd) { + int value = 1; + if (0 != setsockopt(listener_poll_.fd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value))) + { + UXR_AGENT_LOG_ERROR( + UXR_DECORATE_YELLOW("SO_REUSEADDR socket option failed"), + "port: {}, errno: {}", + agent_port_, errno); + } + struct sockaddr_in address; address.sin_family = AF_INET; diff --git a/src/cpp/utils/ArgumentParser.cpp b/src/cpp/utils/ArgumentParser.cpp index b1d0542ef..a34505ce8 100644 --- a/src/cpp/utils/ArgumentParser.cpp +++ b/src/cpp/utils/ArgumentParser.cpp @@ -15,6 +15,7 @@ #ifndef UXR_AGENT_UTILS_ARGUMENTPARSER_CPP_ #define UXR_AGENT_UTILS_ARGUMENTPARSER_CPP_ +#include #include // TODO(jamoralp): move definitions of ArgumentParser.hpp into this file, to maintain code coherence. @@ -32,7 +33,7 @@ bool eprosima::uxr::agent::parser::utils::usage( std::stringstream ss; ss << "Usage: '" << executable_name_str << " <>'" << std::endl; if (no_help) @@ -53,7 +54,9 @@ eprosima::uxr::agent::TransportKind eprosima::uxr::agent::parser::utils::check_t {"tcp4", eprosima::uxr::agent::TransportKind::TCP4}, {"tcp6", eprosima::uxr::agent::TransportKind::TCP6}, #ifndef _WIN32 +#ifdef UAGENT_SOCKETCAN_PROFILE {"canfd", eprosima::uxr::agent::TransportKind::CAN}, +#endif // UAGENT_SOCKETCAN_PROFILE {"serial", eprosima::uxr::agent::TransportKind::SERIAL}, {"multiserial", eprosima::uxr::agent::TransportKind::MULTISERIAL}, {"pseudoterminal", eprosima::uxr::agent::TransportKind::PSEUDOTERMINAL},