带QSignalTransition的QStateMachine丢失信号

时间:2013-11-11 12:14:16

标签: c++ qt qt5 qstatemachine

我对QStateMachine有一个奇怪的问题,我一个星期都无法解决。

简要说明:

我在我的应用程序中使用QStateMachine来控制向通过COM端口连接的生物医学设备发送命令。整个状态机复杂,有数百个状态和频繁的变电站。

根据用户的偏好,从设备的通信协议生成机器。例如,如果用户想要来自设备的某些“反应”,则该反应由若干子反应组成,这些子反应由基本步骤(设备的指令)组成。应用程序从这些基本步骤构建完整的反应,并在状态机上启动它。

因此,我创建了类 CompositeReactionControl (继承自QState),它允许从特定的子状态构建复合。

QSignalTransition实例用于将状态连接在一起。

问题描述:

有时,当发出先前状态的finish()信号时,机器不会从一种状态转换到另一种状态。

备注:

  1. 我100%确定状态已连接。
  2. 我百分百肯定会发出信号。
  3. 事件通过机器及其状​​态在与应用程序其余部分分开的线程中运行,此特定信号被触发并在SAME线程中捕获
  4. 在所有反应中随机发生(没有特定的反应或与此问题相关的子状态)
  5. 在一次运行(反应)中引起问题的基质,在相同反应的其他运行中没有任何问题地运行
  6. 当StateMachine长时间运行时,它会在第4次反应之前出现(无论用户选择哪种反应)。
  7. CODE

    有问题的部分在以下代码中标有“HERE IS PROBLEM”注释......

    将新子状态添加到CompositeReactionControl:

    /**
     * @brief Add new reaction control as a child of this composite
     * @param reaction child reaction (inherited from QState)
     * @return added child reaction
     */
    AbstractReactionControl* CompositeReactionControl::addChildReaction(
        AbstractReactionControl* reaction) {
    
      // Check whether reaction is valid
      if (reaction == NULL) {
        QString msg = tr("Cannot add NULL subreaction to reaction '%1'.");
        Logger::getInstance()->addError(msg.arg(getName()), this);
        return NULL;
      }
    
      // Adopt reaction
      reaction->setParent(this);
    
      // Store previous reaction control and add current to list
      AbstractReactionControl* prev = controls.size() > 0 ? controls.last() : NULL;
      controls.append(reaction);
    
      // Connects current state
      connect(reaction, SIGNAL(reactionEntered(core::AbstractCommunicationState*)),
              SLOT(onSubReactionEntered(core::AbstractCommunicationState*)));
      connect(reaction, SIGNAL(reactionFinished(core::AbstractCommunicationState*)),
              SLOT(onSubReactionFinished(core::AbstractCommunicationState*)));
    
      // If previous state does not exist (this is the first one) then set current
      // state 'c' as initial state and add transition from 'c' to final state
      // Otherwise add transition from previous state to 'c', remove transition from
      // previous state to final state and add transition from 'c' to final state
      if (prev == NULL) {
        this->setInitialState(reaction);
        this->firstState = reaction;
      } else {
    
        // Remove end transitions from previous state
        prev->removeTransition(endTransition1);
        prev->removeTransition(endTransition2);
        delete endTransition1;
        delete endTransition2;
    
        // Replaced with PassTransition
        //prev->addTransition(prev, SIGNAL(finished()), reaction);
    
        // HERE IS PROBLEM: I am 100% sure that finished() signal is emitted,
        // but sometimes not caught by transition
        PassTransition* t = new PassTransition(this, prev, SIGNAL(finished()));
        t->setTargetState(reaction);
        prev->addTransition(t);
      }
    
      // Assign new end transitions to current state
      endTransition1 = new RepeatTransition(this, reaction, SIGNAL(finished()));
      endTransition2 = new FinishTransition(this, reaction, SIGNAL(finished()));  
      endTransition1->setTargetState(firstState);
      endTransition2->setTargetState(allFinished);
      reaction->addTransition(endTransition1);
      reaction->addTransition(endTransition2);
    
      // Finish if halt
      reaction->addTransition(this, SIGNAL(halt()), allFinished);
    
      // Exit reaction
      return reaction;
    }
    //---------------------------------------------------------------------------
    

    PassTransition:

    /**
     * @class PassTransition
     * @brief Passes control from one substate to another
     * @author Michal Rost
     * @date 6.11.2013
     */
    class PassTransition : public QSignalTransition {
    public:
      PassTransition(CompositeReactionControl* owner, QObject* sender,
                     const char *signal) : QSignalTransition(sender, signal) {
        this->owner = owner;
      }
    protected:
      CompositeReactionControl* owner;
      bool eventTest(QEvent *event) {
    
        // HERE IS PROBLEM: I know that signal is called, but event is not received
    
        QString msg = tr("Event Test %1, source: %2   target: %3");
        AbstractReactionControl* s = dynamic_cast<AbstractReactionControl*>(this->sourceState());
        AbstractReactionControl* t = dynamic_cast<AbstractReactionControl*>(this->targetState());
        common::Logger::getInstance()->addDebug(msg.arg(event->type()).arg(s->getName()).arg(t->getName()), this);
        return QSignalTransition::eventTest(event);
      }
      void onTransition(QEvent *event) {
        QSignalTransition::onTransition(event);
        QString msg = tr("Transition called");
        common::Logger::getInstance()->addDebug(msg, this);
      }
    };
    

    从好案例中记录

    在这种情况下,一切运作良好。重要的是PassTransition :: EventTest接收类型为192的事件,该事件是从先前状态的finished()信号创建的状态机事件。

    [08:33:01:976][core::CompositeReactionControl] State 'send_fluorescence_on' finished, disconnecting...
    [08:33:01:976][core::CompositeReactionControl] State 'ProfileData' removed control from 'send_fluorescence_on' substate.
    [08:33:01:977][core::ReactionEmitter] Sending state entered. Timer Started.
    [08:33:01:977][core::PassTransition] Event Test 0, source: send_fluorescence_on   target: send_fluorescence_off
    [08:33:01:977][core::PassTransition] Event Test 0, source: measure_fluorescence   target: measure_fluorescence
    [08:33:01:977][core::PassTransition] Event Test 192, source: send_fluorescence_on   target: send_fluorescence_off
    [08:33:01:977][core::PassTransition] Transition called
    [08:33:01:977][core::CompositeReactionControl] State 'ProfileData' gave control to 'send_fluorescence_off' substate.
    

    从不良案例中记录

    可以看出,如果出现错误RANDOMLY,则PassTransition :: EventTest方法不会收到上述事件。超过5秒后(我尝试更长的间隔),我停止状态机和打印错误。

    [08:33:01:991][core::CompositeReactionControl] State 'send_fluorescence_off' finished, disconnecting...
    [08:33:01:991][core::CompositeReactionControl] State 'ProfileData' removed control from 'send_fluorescence_off' substate.
    [08:33:01:991][core::ReactionEmitter] Sending state entered. Timer Started.
    [08:33:01:991][core::PassTransition] Event Test 0, source: send_fluorescence_off   target: led_off
    [08:33:01:991][core::PassTransition] Event Test 0, source: measure_fluorescence   target: measure_fluorescence
    [08:33:16:966][core::ReactionEmitter] State machine is frozen. Reaction will be stopped!
    

0 个答案:

没有答案