State Machine - структура для хранения состояний, событий и pFuncs - PullRequest
4 голосов
/ 22 июля 2011

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

AddState ( state1, state2, Key_UP );
AddEvent ( Key_UP );
AddEventFunction ( Key_UP, &UP_Function);
AddStateFunction ( state1, &State1_In_Function, &State1_Out_Function);
AddStateFunction ( state2, &State2_In_Function, &State2_Out_Function);

State1_In_Function  ( void ) { printf ( "In #1 \n" ); }
State1_Out_Function ( void ) { printf ( "Out #1 \n" ); }
State2_In_Function  ( void ) { printf ( "In #2 \n" ); }
State2_Out_Function ( void ) { printf ( "Out #2 \n" ); }
UP_Function         ( void ) { printf ( "Goin UP \n" ); }

Таким образом, когда я нахожусь в состоянии1 и FSM получает Key_UP, программа печатает:

Out #1
Goin UP
In #2

Вопрос в том, как хранить информацию о состоянии и переходе внутри класса, не требуя от программиста изменения размера массива.Я думал, что смогу использовать 2D-массив и сделать его таблицей состояний, как обычно, и чтобы сделать ее более переносимой, я просто обработаю добавление событий и состояний, используя векторный тип для изменения размера по мере необходимости.Проблема с векторами заключается в том, что не многие встроенные устройства могут использовать вызовы выделения памяти.Мой второй вариант - вызвать конструктор с конечным автоматом и передать ему размер, который необходим таблице, но затем, если я добавлю какие-либо новые состояния или события, мне также нужно изменить эти значения ...

Так как мне хранить мои состояния, события и указатели на функции?!

Ответы [ 3 ]

3 голосов
/ 22 июля 2011

Вы можете просто сохранить их в стеке, хотя это немного сложнее:)

Тем не менее, это забавное решение, так что пошли. Основополагающим принципом является игра с декораторами и изменчивость. Пример кода:

State state1, state2; // creates a state
Event KEY_UP;
Event KEY_DOWN;

Transition t0(state1, KEY_UP, state2);
Transition t1(state2, KEY_DOWN, state1);

Как это работает?

Вместо state1, являющегося «простым» объектом, он будет немного более запутанным. Что-то вроде:

struct State;

struct StateImpl {
  StateImpl(char const* n): name(n) {}
  char const* name;
};

struct StateNode {
  StateNode(Event e, State const& s, StateNode const* n):
    event(e), state(s), next(n) {}

  Event event;
  State const& destination;
  StateNode const* next;
};

struct State {
  State(char const* name):
    me(0), impl(name) {}

  StateNode const* me;
  StateImpl impl;
};

А затем мы определяем Transition:

struct Transition {
  Transition(State& origin, Event e, State const& destination):
    node(e, destination, origin.me)
  {
    origin.me = node;
  }
  StateNode node;
};

Неофициально, мы строим односвязный список, с головой в State. Мы обновляем голову каждый раз, когда добавляем переход.

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

0 голосов
/ 22 июля 2011
0 голосов
/ 22 июля 2011

Я предлагаю вам взглянуть на Boost.StateChart и, при необходимости, построить вокруг него тонкий слой с нужным вам API.

Это должно решить вашу потребность в разработке адекватногоструктуры данных.

...