基于事件型的有限状态机

基于事件型的有限状态机1.状态机简介2.状态机实现3.基于事件型的有限状态机实现

 

基于事件型的有限状态机

 

1.状态机简介

现态:状态机现在的状态;

次态:状态机下一个状态;

事件:指触发状态机下一状态的所满足的条件,相应事件到达后状态机自动执行动作,并切换状态;

动作:状态机切换状态时执行的操作;

以上四点就是状态机的基本原理,利用状态机可以进行较为复杂的状态条状或用于编解码等。

2.状态机实现

利用switch-case就可以构建出一个最简单的状态机,如下:

while(1)
{
    switch(state)
    {
        case state1:
            state = state2;
            //todo
            break;
        case state1:
            state = state2;
            //todo
            break;
            /***/
        default:
            break;
    }
}

这样的实现方式结构简单,易于理解,但是在代码量多的情况下就不是十分友好了,不便于修改,同时case语句还容易遗漏break,导致BUG出现。

3.基于事件型的有限状态机实现

利用函数指针及触发事件表,结构更加清晰明了,修改起来也更方便。

3.1状态及事件枚举

xfms_state_e状态枚举,这里状态机一共有4个状态,可以根据实际需要增加或者减少;

 typedef enum
{
  s1,
  s2,
  s3,
  s4,
}xfms_state_e; 

xfms_event_e事件枚举,简单理解就是有哪些事件会导致状态机的状态改变,同样根据实际修改;

typedef enum
{
  event_a,
  event_b,
  event_c,
  event_d,
  event_e,
}xfms_event_e;

3.2状态机结构体

typedef struct
{
  xfms_event_e event;
  xfms_state_e state;
  xfms_state_e next_state;
  void (*process)();
}xfms_t;

用一个结构体把状态机的现态、次态、事件及动作联系起来;

3.3触发表

通过直接赋值的方法,将状态机的跳转关系存储起来。

static xfms_t fms_trigger_table[] = 
{
  /* event, current state, next state, process function */
  {event_a, s1, s2, func_a},
  {event_b, s2, s3, func_b},
  {event_c, s2, s4, func_c},
  {event_d, s3, s4, func_d},
  {event_e, s4, s1, func_e},
};

这里完全可以在状态机结构体中不定义event,而把event作为触发表的index去存储,这样可以实现O(1)的查找效率,如下:

typedef struct
{
  xfms_state_e state;
  xfms_state_e next_state;
  void (*process)();
}xfms_t;
​
static xfms_t fms_trigger_table[] = 
{
  /* current state, next state, process function */
  {s1, s2, func_a}, //event_a,
  {s2, s3, func_b}, //event_b,
  {s2, s4, func_c},
  {s3, s4, func_d},
  {s4, s1, func_e},
};

这样做有一些局限性,因为状态机的跳转取决于2个条件:现态和事件,也就是说同一个事件,状态机要根据不同的现态进行不同的动作。这也是变量名用fms_trigger_table而非fms_event_table的原因,在fms_trigger_table中可以定义对同一个事件定义多个触发,提高了通用性。

例如,用一个按键实现开关机,按键作为一个事件,去触发改变状态机的状态,状态机通过现态(on或者off)执行不同的操作。

static xfms_t fms_trigger_table[] = 
{
  /* event, current state, next state, process function */
  {event_key_press, on, off, shutdown},
  {event_key_press, off, on, boot},  
};

3.4状态机的状态更新

遍历触发表fms_trigger_table,找到对应event并且满足状态的触发事件,执行动作后更新状态机的状态,在需要状态机状态改变时调用,传入对应event;

int xfms_state_update(int event)
{
    for (int i = 0; i < sizeof(fms_trigger_table)/sizeof(fms_trigger_table[0]); i++)
    {
        if (event == fms_trigger_table[i].event)
        {
            if (current_state == fms_trigger_table[i].state)
            {
                if (fms_trigger_table[i].process != NULL)
                {
                    fms_trigger_table[i].process();
                }
                current_state = fms_trigger_table[i].next_state;
                return 0;
            }
        }
    }
    return -1;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值