ROS-I simple_message 源码分析:Messag

2019-03-21  本文已影响0人  play_robot

MessageManager通过它的通信连接接收simple message。而后基于收到的message类型调用相应的回调函数,回调函数则执行相应的操作,以及根据需要作出消息应答。

MessageManager有两种工作模式:spin()spinOnce()
spin的执行是阻塞式的,而spinOnce是执行一次单独的操作。因此,在spinOnce模式下,程序可以同时干其它事情,但是要确保执行spinOnce的频率足够高,这样不至于丢失通信数据。

namespace industrial
{
namespace message_manager
{

class MessageManager
{

public:

  MessageManager();
  ~MessageManager();

  bool init(industrial::smpl_msg_connection::SmplMsgConnection* connection);
  bool init(industrial::smpl_msg_connection::SmplMsgConnection* connection,
            industrial::comms_fault_handler::CommsFaultHandler* fault_handler);

  void spinOnce();
  void spin();

  bool add(industrial::message_handler::MessageHandler* handler, bool allow_replace = false);

  unsigned int getNumHandlers()
  {
    return this->num_handlers_;
  }

  unsigned int getMaxNumHandlers()
  {
    return this->MAX_NUM_HANDLERS;
  }

  industrial::comms_fault_handler::CommsFaultHandler* getCommsFaultHandler()
  {
    return this->comms_hndlr_;
  }

  void setCommsFaultHandler(industrial::comms_fault_handler::CommsFaultHandler* handler)
  {
    this->comms_hndlr_ = handler;
  }


private:

  static const unsigned int MAX_NUM_HANDLERS = 64;
  industrial::message_handler::MessageHandler* handlers_[MAX_NUM_HANDLERS];
  industrial::smpl_msg_connection::SmplMsgConnection* connection_;
  industrial::ping_handler::PingHandler ping_hndlr_;
  industrial::simple_comms_fault_handler::SimpleCommsFaultHandler def_comms_hndlr_;
  industrial::comms_fault_handler::CommsFaultHandler* comms_hndlr_;
  unsigned int num_handlers_;

  industrial::message_handler::MessageHandler* getHandler(int msg_type);
  int getHandlerIdx(int msg_type);

  industrial::simple_comms_fault_handler::SimpleCommsFaultHandler& getDefaultCommsFaultHandler()
  {
    return this->def_comms_hndlr_;
  }

  industrial::ping_handler::PingHandler& getPingHandler()
  {
    return this->ping_hndlr_;
  }
  ;

  void setConnection(industrial::smpl_msg_connection::SmplMsgConnection* connection)
  {
    this->connection_ = connection;
  }
  ;

  industrial::smpl_msg_connection::SmplMsgConnection* getConnection()
  {
    return this->connection_;
  }
  ;

  void setNumHandlers(unsigned int num_handlers)
  {
    this->num_handlers_ = num_handlers;
  }
  ;

};

} // namespace industrial
} // namespace message_manager

先来看一下它的私有成员:

类型 变量符号 含义
int MAX_NUM_HANDLERS 消息处理器的最大数目
int num_handlers_ 消息处理器的实际数目
MessageHandler* handlers_[MAX_NUM_HANDLERS] 存放消息处理器的指针数组
SmplMsgConnection* connection_ 通信使用的连接
PingHandler ping_hndlr_ ping消息处理器
SimpleCommsFaultHandler def_comms_hndlr_ 默认的通信错误处理器
CommsFaultHandler* comms_hndlr_ 用户指定的通信错误处理器

在使用MessageManager时,外部需要先初始化好connection,然后传入init以初始化MessageManager使用的连接和错误处理器,此外还将初始化ping_hndlr_对象,并调用add将ping_hndlr_存放到handlers_数组中,保存的目的就在于当遇到ping message时,MessageManager就会调用PingHandler来处理该消息。

下面分析spinOnce代码:

void MessageManager::spinOnce()
{
  SimpleMessage msg;
  MessageHandler* handler = NULL;

  if(!this->getConnection()->isConnected())
  {
    this->getCommsFaultHandler()->connectionFailCB();
  }

  if (this->getConnection()->receiveMsg(msg))
  {
    LOG_COMM("Message received");
    handler = this->getHandler(msg.getMessageType());

    if (NULL != handler)
    {
      LOG_DEBUG("Executing handler callback for message type: %d", handler->getMsgType());
      handler->callback(msg);
    }
    else
    {
      if (CommTypes::SERVICE_REQUEST == msg.getCommType())
      {
        simple_message::SimpleMessage fail;
        fail.init(msg.getMessageType(), CommTypes::SERVICE_REPLY, ReplyTypes::FAILURE);
        this->getConnection()->sendMsg(fail);
        LOG_WARN("Unhandled message type encounters, sending failure reply");
      }
      LOG_ERROR("Message callback for message type: %d, not executed", msg.getMessageType());
    }
  }
  else
  {
    LOG_ERROR("Failed to receive incoming message");
    this->getCommsFaultHandler()->sendFailCB();
  }
}

进入spinOnce后,首先会检查是否处于连接状态,如果连接断开则触发通信错误处理器的连接失败回调函数connectionFailCB。接着将尝试接收一条SimpleMessage消息,如果接收到消息,则根据消息类型寻找能处理该消息的处理器handler,找到后则触发处理的回调函数callback对接收到的消息进行处理。

对于spin方法,它是基于spinOnce实现的,进入该方法后,程序将进入内部的死循环,持续调用spinOnce:

void MessageManager::spin()
{
  LOG_INFO("Entering message manager spin loop");
#ifdef ROS
  while (ros::ok())
#else
  while (true)
#endif
  {
    this->spinOnce();

    // Throttle loop speed if waiting for a re-connection
    if (!this->getConnection()->isConnected())
      mySleep(5);
  }
}

MessageManager就分析到这里,后面再举例分析在更上层的代码中是如何使用它的。

上一篇下一篇

猜你喜欢

热点阅读