Периодический конечный автомат с буст-диаграммой состояний

Я хочу реализовать конечный автомат, который будет периодически отслеживать некоторые данные о состоянии (состояние моей системы) и реагировать на них.

Кажется, это что-то довольно простое для конечного автомата (у меня была эта проблема много раз раньше), но я не мог найти хороший способ сделать это. Вот некоторый псевдокод, объясняющий, чего я хотел бы достичь:

// some data that is updated from IOs for example
MyData data;

int state = 0;

while( true ) {
    update( & data ); //read a packet from serial port 
                      //and update the data structure
    switch( state ) {
    case 0:
        if( data.field1==0 ) state = 1;
        else doSomething();
        break;
    case 1:
        if( data.field2>0 ) state = 2;
        else doSomethingElse();
        break;

    // etc.

    }
    usleep(100000); //100ms
}

Конечно, помимо этого, я хочу иметь возможность выполнять некоторые действия при входе и выходе из состояния, возможно, выполнять некоторые действия на каждой итерации состояния, иметь подсостояния, историю и т. Д. Именно поэтому этот упрощенный подход быстро становится непрактичным., следовательно, повысить диаграмму состояния.

Я думал о некоторых решениях, и я хотел бы получить некоторую обратную связь.

1) Я мог бы перечислить все свои условия для переходов и создать событие для каждого из них. Тогда у меня будет цикл, который будет отслеживать, когда каждый из этих логических переключателей. например, для моего первого условия это может быть:

if( old_data.field1!=0 && new_data.field1==0 )
    // post an event of type Event 1

но кажется, что это быстро станет трудным

2) иметь одно событие, на которое реагируют все государства. это событие публикуется всякий раз, когда доступны новые данные о состоянии. В результате текущее состояние изучит данные и решит, инициировать ли переход в другое состояние или нет.

3) иметь все состояния, наследуемые от интерфейса, который определяет метод do_work(const MyData & data), который будет вызываться извне в цикле, исследовать данные и решить, инициировать ли переход в другое состояние или нет

Кроме того, я открыт для использования другого фреймворка (например, Macho или повысить MSM)

1 ответ

Поработав с надстройкой MSM, диаграммами состояний и QP, я считаю, что вы находитесь на правильном пути с диаграммами состояний. MSM работает быстрее, но если у вас нет большого опыта работы с конечными автоматами или метапрограммированием, сообщения об ошибках от MSM трудно понять, если вы делаете что-то не так. boost.statecharts является самым чистым и простым для понимания. Что касается QP, он написан во встроенном стиле (много препроцессора, слабая статическая проверка), хотя он также работает в среде ПК. Я также считаю, что медленнее. У него есть преимущество работы на многих маленьких ARM и подобных процессорах. Это не бесплатно для коммерческого использования, в отличие от продвинутых решений.

Создание события для каждого типа изменения состояния не масштабируется. Я бы сделал один тип мероприятия EvStateChanged дайте ему элемент данных, содержащий копию или ссылку на набор данных (и, возможно, один на старые данные, если вам это нужно). Затем вы можете использовать реакцию костюма, чтобы справиться с тем, что вам нужно, из любого состояния. Хотя переходы по умолчанию работают достаточно хорошо в контексте тостера (которые часто используются для демонстрации функциональности SM), большинство реальных SM, которые я видел, имеют много пользовательских реакций, не стесняйтесь их использовать.

Я не совсем понимаю вашу проблему, чтобы привести пример кода, но что-то вроде:

while( true ) {
    update( & data ); //read a packet from serial port 
                      //and update the data structure
    if(data != oldData){
          sm.process_event(EvDataChanged(data,oldData));
    }
    else{
        timeout++;
        if(timeout>MAX_TIMEOUT)
            sm.process_event(EvTimeout());
    }
    usleep(100000); //100ms
}

и затем обработайте ваши изменения данных в привычных реакциях в зависимости от состояния по следующим направлениям:

SomeState::~SomeState(){
    DoSomethingWhenLeaving();
}
sc::result SomeState::react( const EvDataChanged & e){
    if(e.oldData.Field1 != e.newData.Field1){
        DoSomething();
        return transit<OtherState>();
    }
    if(e.oldData.Field2 != e.newData.Field2){
        return transit<ErrorState>();   //is not allowed to change in this state
    }
    if(e.oldData.Field3 == 4){
        return forward_event();  //superstate should handle this
    }
    return discard_event(); //don't care about anything else in this context
}
Другие вопросы по тегам