QStateMachine с QSignalTransition теряет сигнал

У меня странная проблема с QStateMachine, которую я не могу решить в течение недели.

Краткое объяснение:

Я использую QStateMachine в своем приложении для контроля отправки команд на биомедицинское устройство, подключенное через COM-порт. Весь конечный автомат сложен сотнями состояний и частыми заменами.

Машина генерируется из протокола связи устройства на основе предпочтений пользователя. Например, если пользователь хочет какую-то «реакцию» от устройства, эта реакция состоит из нескольких подреакций, которые состоят из элементарных шагов (инструкции для устройства). Приложение строит целую реакцию из этих элементарных шагов и запускает ее на конечном автомате.

Поэтому я создал класс CompositeReactionControl (унаследовано от QState), которое позволяет создавать композит из определенных подсостояний.

Экземпляры QSignalTransition используются для соединения состояний.

Описание проблемы:

Иногда машина не переходит из одного состояния в другое, когда передается сигнал finish () предыдущего состояния.

ЗАМЕТКИ:

  1. Я на 100% уверен, что государство связано.
  2. Я на 100% уверен, что сигнал сработал.
  3. Событие через машину и его состояния выполняются в отдельном потоке от остальной части приложения, этот конкретный сигнал запускается и перехватывается в том же потоке
  4. Это происходит случайно во всех реакциях (нет конкретной реакции или подсостояния, связанного с этой проблемой)
  5. Подсостояние, вызвавшее проблему за один прогон (реакция), работает без проблем в других прогонах той же реакции
  6. Это происходит, когда StateMachine работает долго, он никогда не появляется до 4-й реакции (независимо от того, какие реакции выбрал пользователь).

КОД

Проблемные части помечены комментарием «ЗДЕСЬ ПРОБЛЕМА» в следующем коде …

Добавление нового подсостояния в 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, которое является событием конечного автомата, созданным из сигнала завершения () предыдущего состояния.

[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!

3

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]