复杂的状态转换:最佳实践 [英] Complicated state transitions: best practices

查看:157
本文介绍了复杂的状态转换:最佳实践的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我与嵌入式的东西的工作,我有一个管理硬件的一些软件模块。该模块具有状态,状态转换是复杂的:根据事件,该模块可以从国家去 A 国家 B 或可能是 C 。但是,当其退出的某些状态,它应该执行与硬件的一些动作,以保持它在正确的状态太

I work with embedded stuff, and I have some software module that manages hardware. This module has state, and state transitions are complicated: depending on events, the module could go from state A to state B or probably to C. But, when it exits some state, it should perform some actions with the hardware, in order to keep it in correct state too.

有关,而简单的模块,我只是有一对夫妇的功能是这样的:

For rather simple modules, I just have a couple of functions like this:

enum state_e {
    MY_STATE__A,
    MY_STATE__B,
};

static enum state_e _cur_state;

void state_on_off(enum state_e state, bool on)
{
    switch (state){
        case MY_STATE__A:
            if (on){
                //-- entering the state A
                prepare_hardware_1(for_state_a);
                prepare_hardware_2(for_state_a);
            } else {
                //-- exiting the state A
                finalize_hardware_2(for_state_a);
                finalize_hardware_1(for_state_a);
            }
            break;
        case MY_STATE__B:
            if (on){
                //-- entering the state B
                prepare_hardware_1(for_state_b);
                prepare_hardware_2(for_state_b);
            } else {
                //-- exiting the state B
                finalize_hardware_2(for_state_b);
                finalize_hardware_1(for_state_b);
            }
            break;
    }
}

void state_set(enum state_e new_state)
{
    state_on_off(_cur_state, false);
    _cur_state = new_state;
    state_on_off(_cur_state, true);
}

显然,我们需要保持所有状态一切必要行动,在 _state_on_off()功能,当我们需要移动到另一个国家,我们只需要调用 _state_set(NEW_STATE)和状态转换顺利进行独立的方向:执行所有需要的动作

Obviously, we need to keep all necessary actions for all states in the _state_on_off() function, and when we need to move to another state, we just call _state_set(new_state) and state transition goes smoothly independently of the direction: all needed actions are performed.

但它适用于只有简单的情况。如果我们有共同的国家之间的事 MY_STATE__B MY_STATE__C ,这样,当状态从 MY_STATE__B MY_STATE__C 和背部,我们应该只执行缩短desctruction /建筑?但是,当我们去一些其他国家(例如,以 MY_STATE__A ),应执行完全破坏。

But it works for simple situations only. What if we have something in common between states MY_STATE__B and MY_STATE__C, so that when state is changed from MY_STATE__B to MY_STATE__C and back we should perform only shortened desctruction / construction? But when we go to some other state (say, to MY_STATE__A), we should perform full destruction.

什么想到的是子状态。因此,我们有一个状态 MY_STATE__BC 和子状态如 MY_BC_SUBSTATE__B MY_BC_SUBSTATE__C ;当然我们有像 _state_bc_on_off自己的功能()。即使这已经是一种痛苦,但可以想象的东西更复杂:它会可怕

What comes to mind is substates. So we have one state MY_STATE__BC, and substates like MY_BC_SUBSTATE__B and MY_BC_SUBSTATE__C; and of course we have its own function like _state_bc_on_off(). Even this is already a pain, but imagine something more complicated: it goes terrible.

那么,什么是这样的事情的最佳实践?

So, what are the best practices for things like that?

推荐答案

一个稍微更一般的状态机有

A slightly more general state machine has


  • 元 - 子程序执行一个特定的硬件
  • 特定操作
  • 序列 - 一个或多个原语称为特定顺序

  • 过渡 - 一个或按特定顺序执行多个序列

的跃迁都设有在结构数组codeD。该序列被开关语句选择,并且每个序列调用一个或多个原语

The transitions are encoded in an array of structs. The sequences are selected by switch statement, and each sequences calls one or more primitives.

#define stA    0x00000001  // bit mask for state A
#define stB    0x00000002  // bit mask for state B
#define stC    0x00000004  // bit mask for state C
#define stAny  0xffffffff  // matches any state

enum { seqXtoY, seqError, seqEnterA, seqExitA, seqEnterB, seqExitB, seqEnableC, seqDisableC, seqEnd };

typedef struct
{
    int oldState;     // bit mask that represents one or more states that we're transitioning from
    int newState;     // bit mask that represents one or more states that we're transitioning to
    int seqList[10];  // an array of sequences that need to be executed
}
stTransition;

static stTransition transition[] =
{
    // transitions from state A to B or C
    { stA, stB, { seqExitA, seqXtoY, seqEnterB, seqEnd } },
    { stA, stC, { seqExitA, seqXtoY, seqEnableC, seqEnterB, seqEnd } },

    // transitions from state B to A or C
    { stB, stA, { seqExitB, seqXtoY, seqEnterA, seqEnd } },
    { stB, stC, { seqXtoY, seqEnableC, seqEnd } },

    // transitions from states C to A or B
    { stC, stA, { seqDisableC, seqExitB, seqXtoY, seqEnterA, seqEnd } },
    { stC, stB, { seqDisableC, seqXtoY, seqEnd } },

    // any other transition (should never get here)
    { stAny, stAny, { seqError, seqEnd } }
};

static int currentState = stA;

void executeSequence( int sequence )
{
    switch ( sequence )
    {
        case seqEnterA:
            prepare_hardware_1(for_state_a);
            prepare_hardware_2(for_state_a);
            break;

        case seqExitA:
            finalize_hardware_2(for_state_a);
            finalize_hardware_1(for_state_a);
            break;

        case seqEnterB:
            prepare_hardware_1(for_state_b);
            prepare_hardware_2(for_state_b);
            break;

        case seqExitB:
            finalize_hardware_2(for_state_b);
            finalize_hardware_1(for_state_b);
            break;

        case seqEnableC:
            enable_hardware_3();
            break;

        case seqDisableC:
            disable_hardware_3();
            break;
    }
}

void executeTransition( int newState )
{
    if ( newState == currentState )
        return;

    // search the transition table to find the entry that matches the old and new state
    stTransition *tptr;
    for ( tptr = transition; tptr->seqList[0] != seqError; tptr++ )
        if ( (tptr->oldState & currentState) && (tptr->newState & newState) )
            break;

    // execute the sequence list
    int *seqptr;
    for ( seqptr = tptr->seqList; *seqptr != seqEnd; seqptr++ )
    {
        if ( *seqptr == seqXtoY )
            currentState = newState;
        else if ( *seqptr == seqError )
            printf( "The state table is missing the transition from %d to %d\n", currentState, newState );
        else
            executeSequence( *seqptr );
    }

    // if the seqList doesn't have an explicit update, then we update at the end
    currentState = newState;
}

这篇关于复杂的状态转换:最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆