diff --git a/CMakeLists.txt b/CMakeLists.txt index 32f34fb674db5c49156338ed7c0ca5cc5eb7871f..9ed29c9a4a39a0fdef02c22e5bdee3dc3e0fe7da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,7 @@ add_compile_options(-std=c++11) ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) ## is used, also find other catkin packages find_package(catkin REQUIRED COMPONENTS behaviortree_cpp_v3) +find_package(iriutils REQUIRED) ## System dependencies are found with CMake's conventions # find_package(Boost REQUIRED COMPONENTS system) @@ -80,6 +81,7 @@ catkin_package( INCLUDE_DIRS include LIBRARIES ${PROJECT_NAME} CATKIN_DEPENDS behaviortree_cpp_v3 + DEPENDS iriutils ) ########### @@ -90,13 +92,15 @@ catkin_package( ## Your package locations should be listed before other locations include_directories(include) include_directories(${catkin_INCLUDE_DIRS}) +include_directories(${iriutils_INCLUDE_DIR}) ## Declare a cpp library # add_library(iri_behaviortree # src/${PROJECT_NAME}/iri_behaviortree.cpp # ) -add_library(${PROJECT_NAME} src/iri_async_action.cpp src/iri_bt_factory.cpp) +add_library(${PROJECT_NAME} src/iri_async_action.cpp src/iri_bt_factory.cpp src/iri_bt_logger.cpp) target_link_libraries(${PROJECT_NAME} ${catkin_LIBRARIES}) +target_link_libraries(${PROJECT_NAME} ${iriutils_LIBRARY}) ## Declare a cpp executable # add_executable(iri_behaviortree_node src/iri_behaviortree_node.cpp) diff --git a/include/iri_bt_logger.h b/include/iri_bt_logger.h new file mode 100644 index 0000000000000000000000000000000000000000..870ed6ce6b8d0d79193547129de87de509bf6506 --- /dev/null +++ b/include/iri_bt_logger.h @@ -0,0 +1,68 @@ +#ifndef IRI_BT_ROS_LOGGER_H +#define IRI_BT_ROS_LOGGER_H + +#include <cstring> +#include <queue> +#include "behaviortree_cpp_v3/loggers/abstract_logger.h" + +/** + * @brief AddIriBtRosLogger. Give the root node of a tree, + * a simple callback is subscribed to any status change of each node. + * + * + * @param root_node + * @return Important: the returned shared_ptr must not go out of scope, + * otherwise the logger is removed. + */ + +class IriBtLogger : public BT::StatusChangeLogger +{ + static std::atomic<bool> ref_count; + + public: + IriBtLogger(const BT::Tree& tree); + ~IriBtLogger() override; + + virtual void callback(BT::Duration timestamp, const BT::TreeNode& node, BT::NodeStatus prev_status, + BT::NodeStatus status) override; + + virtual void flush() override; + + /** + * \brief Function to get the identifier of the ID new_data_available. + * + * \return The new_data_available's ID. + */ + std::string get_new_data_available_event_id(void); + + /** + * \brief Function to get the amount of data available. + * + * \return The data available. + */ + uint16_t get_data_available(void); + + /** + * \brief Function to get the data. + * + * \param names A reference to the buffer where the available names must be copied. + * + * \param prev_status A reference to the buffer where the available prev_status must be copied. + * + * \param status A reference to the buffer where the available status must be copied. + * + * \param len the number of data to be read. + * + * \return the number of data copied. + */ + uint16_t get_data(std::string *names, BT::NodeStatus *prev_status, BT::NodeStatus *status, uint16_t len); + + private: + std::queue<std::string> names; //< Variable to store the names of the nodes that have change their status. + std::queue<BT::NodeStatus> prev_status; //< Variable to store the nodes previous status. + std::queue<BT::NodeStatus> status; //< Variable to store the nodes status. + uint16_t data_available; //< Variable to store the data available. + std::string new_data_available; //< Variable to store the identifier of the ID new_data_available. +}; + +#endif // IRI_BT_ROS_LOGGER_H diff --git a/src/iri_bt_logger.cpp b/src/iri_bt_logger.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8fbc941214b53d66fddfe13ea98f07447f03cff1 --- /dev/null +++ b/src/iri_bt_logger.cpp @@ -0,0 +1,101 @@ +#include "iri_bt_logger.h" +#include "eventserver.h" +#include "eventexceptions.h" + +std::atomic<bool> IriBtLogger::ref_count(false); + +IriBtLogger::IriBtLogger(const BT::Tree& tree) : BT::StatusChangeLogger(tree.root_node) +{ + bool expected = false; + if (!ref_count.compare_exchange_strong(expected, true)) + { + throw BT::LogicError("Only one instance of IriBtLogger shall be created"); + } + this->data_available = 0; + try + { + CEventServer *event_server; + event_server = CEventServer::instance(); + this->new_data_available = "iri_bt_logger_new_data_available"; + event_server->create_event(this->new_data_available); + } + catch(CEventException &e) + { + std::cout << "Exception caught on IriBtLogger: " << e.what() << std::endl; + throw; + } +} +IriBtLogger::~IriBtLogger() +{ + ref_count.store(false); + CEventServer *event_server; + event_server = CEventServer::instance(); + if(this->new_data_available != "") + { + event_server->delete_event(this->new_data_available); + this->new_data_available = ""; + } +} + +void IriBtLogger::callback(BT::Duration timestamp, const BT::TreeNode& node, BT::NodeStatus prev_status, + BT::NodeStatus status) +{ + using namespace std::chrono; + + constexpr const char* whitespaces = " "; + constexpr const size_t ws_count = 25; + + double since_epoch = duration<double>(timestamp).count(); + // printf("[%.3f]IRI: %s%s %s -> %s", + // since_epoch, node.name().c_str(), + // &whitespaces[std::min(ws_count, node.name().size())], + // toStr(prev_status, true).c_str(), + // toStr(status, true).c_str() ); + // std::cout << std::endl; + + this->names.push(node.name().c_str()); + this->prev_status.push(prev_status); + this->status.push(status); + this->data_available++; + CEventServer *event_server; + event_server = CEventServer::instance(); + if (!event_server->event_is_set(this->new_data_available)) + event_server->set_event(this->new_data_available); +} + +void IriBtLogger::flush() +{ + for (uint16_t i = 0; i < this->data_available; i++) + { + this->names.pop(); + this->prev_status.pop(); + this->status.pop(); + } + this->data_available = 0; +} + +std::string IriBtLogger::get_new_data_available_event_id(void) +{ + return this->new_data_available; +} + +uint16_t IriBtLogger::get_data_available(void) +{ + return this->data_available; +} + +uint16_t IriBtLogger::get_data(std::string *names, BT::NodeStatus *prev_status, BT::NodeStatus *status, uint16_t len) +{ + uint16_t data_to_read = (len <= this->data_available? len: this->data_available); + for (uint16_t i = 0; i < data_to_read; i++) + { + names[i] = this->names.front(); + this->names.pop(); + prev_status[i] = this->prev_status.front(); + this->prev_status.pop(); + status[i] = this->status.front(); + this->status.pop(); + } + this->data_available-= data_to_read; + return data_to_read; +} \ No newline at end of file