有限状态机FSM

因为工作需要,要明白状态机的编程原理。现直接拿txj的micro raw os来分析学习  (c++学习网站:  http://www.cplusplus.com/)

这里先给出要分析的源码:主要有6个函数

 

/*
     raw os - Copyright (C)  Lingjun Chen(jorya_txj).

    This file is part of raw os.

    raw os is free software; you can redistribute it it under the terms of the 
    GNU General Public License as published by the Free Software Foundation; 
    either version 3 of the License, or  (at your option) any later version.

    raw os is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
    without even the implied warranty of  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
    See the GNU General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program. if not, write email to [email protected]
                                      ---

    A special exception to the LGPL can be applied should you wish to distribute
    a combined work that includes raw os, without being obliged to provide
    the source code for any proprietary components. See the file exception.txt
    for full details of how and when the exception can be applied.
*/

/*     2012-9  Created by jorya_txj
  *    xxxxxx   please added here
  */



#ifndef STM_H
#define STM_H


typedef RAW_U16 STM_SIGNAL;


typedef struct STATE_EVENT {

    RAW_U16     sig;
    RAW_VOID    *arg;   
    
} STATE_EVENT;


typedef RAW_U16 (*stm_state_handler)(void *me, STATE_EVENT *e);


typedef struct STM_STRUCT {
    
    stm_state_handler state;        
    stm_state_handler temp; 
    
} STM_STRUCT;

#define STM_SUCCESS 0


#define STM_STATE_CAST(handler)  ((stm_state_handler)(handler))


#define STM_RET_HANDLED         1


#define STM_RET_IGNORED         2


#define STM_RET_TRAN            3


#define STM_TRAN(state)        (((STM_STRUCT *)me)->temp = STM_STATE_CAST(state), STM_RET_TRAN)


#define STM_RET_FATHER          4


#define STM_FATHER(father)      (((STM_STRUCT *)me)->temp = STM_STATE_CAST(father),  STM_RET_FATHER)



#define STM_RET_UNHANDLED       5



#define STM_EMPTY_SIG           0
#define STM_MAX_NEST_DEPTH      6


enum RAW_Reserved_Signals {

    STM_ENTRY_SIG = 1,                  
    STM_EXIT_SIG,                        
    STM_INIT_SIG,
    STM_TIMEOUT_SIG,                        
    STM_USER_SIG     
};



extern STATE_EVENT STM_GLOBAL_EVENT[];

#define STM_TRIG(state, sig) ((*(state))(me, &STM_GLOBAL_EVENT[sig]))



#define FSM_CONSTRUCTOR(me, initial) do { \
    (me)->state = 0; \
    (me)->temp  = (initial); \
} while (0)


RAW_U16 hsm_top(void  *me, STATE_EVENT *e);


#define HSM_CONSTRUCTOR(me, initial) do { \
    (me)->state = hsm_top; \
    (me)->temp  = (initial); \
} while (0)


#define STM_ENTER(state) STM_TRIG(state, STM_ENTRY_SIG)

#define STM_EXIT(state)  STM_TRIG(state, STM_EXIT_SIG)

RAW_U16 fsm_init(STM_STRUCT *me, STATE_EVENT *e); 
void fsm_exceute(STM_STRUCT *me, STATE_EVENT *e); 

void hsm_init(STM_STRUCT *me, STATE_EVENT *e);
void hsm_exceute(STM_STRUCT *me, STATE_EVENT *e);

RAW_U16 is_hsm_in_state(STM_STRUCT *me, stm_state_handler state);

#endif
View Code

 

/*
     raw os - Copyright (C)  Lingjun Chen(jorya_txj).

    This file is part of raw os.

    raw os is free software; you can redistribute it it under the terms of the 
    GNU General Public License as published by the Free Software Foundation; 
    either version 3 of the License, or  (at your option) any later version.

    raw os is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
    without even the implied warranty of  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
    See the GNU General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program. if not, write email to [email protected]
                                      ---

    A special exception to the LGPL can be applied should you wish to distribute
    a combined work that includes raw os, without being obliged to provide
    the source code for any proprietary components. See the file exception.txt
    for full details of how and when the exception can be applied.
*/


/*     2012-4  Created by jorya_txj
  *    xxxxxx   please added here
  */

#include 

/*
************************************************************************************************************************
*                                   The top of the hsm state machine
*
* Description: This function is used to init the hsm state machine to state hsm_top.
*
* Arguments  :me (unused)
*                    ---------
*                    e (unused)   
*                         
* Returns            
*                        
* Note(s)        
*
*             
************************************************************************************************************************
*/
RAW_U16 hsm_top(void  *me, STATE_EVENT *e) 
{
    me = me;       
    e = e; 
    
    return STM_RET_IGNORED;                 
}

/*
************************************************************************************************************************
*                                   Init the finit state machine
*
* Description: This function is used to init the finit state machine.
*
* Arguments  :me is the state machine
*                    ---------
*                    e is the trig event   
*                         
* Returns            
*                        
* Note(s)        
*
*             
************************************************************************************************************************
*/
RAW_U16 fsm_init(STM_STRUCT *me, STATE_EVENT *e) 
{
    RAW_U16 ret;
    
    if (me->temp == 0) 
    {
        RAW_ASSERT(0);
    }

    /*do the fsm constructor init function*/
    ret = (*me->temp)(me, e);

    /*transition must happen here*/
    if (ret != STM_RET_TRAN) {
        
        RAW_ASSERT(0);
    }

    /*trig the STM_ENTRY_SIG to the new transioned state*/
    STM_TRIG(me->temp, STM_ENTRY_SIG);

    /*change to new state*/
    me->state = me->temp; 

    return STM_SUCCESS;
   
}

/*
************************************************************************************************************************
*                                   exceute the finit state machine
*
* Description: This function is used to exceute the finit state machine.
*
* Arguments  :me is the state machine
*                    ---------
*                    e is the trig event 
*                         
* Returns            
*                        
* Note(s)        
*
*             
************************************************************************************************************************
*/
void fsm_exceute(STM_STRUCT *me, STATE_EVENT *e) 
{
    RAW_U16 ret;

    /*State must be stable here*/
    if (me->state != me->temp)
    {
        RAW_ASSERT(0);
    }

    /*exceute the state function with new event*/
    ret = (*me->state)(me, e); 
    
    if (ret == STM_RET_TRAN) 
    {                            
        /*exit the original state */
        STM_EXIT(me->state); 
        /*enter the new state*/
        STM_ENTER(me->temp); 
        /*change to new state*/
        me->state = me->temp; 
    }
   
}

/*
************************************************************************************************************************
*                                   Init the hsm state machine
*
* Description: This function is used to init the finit state machine.
*
* Arguments  :me is the state machine
*                    ---------
*                    e is the trig event   
*                         
* Returns            
*                        
* Note(s)        
*
*             
************************************************************************************************************************
*/
void hsm_init(STM_STRUCT *me, STATE_EVENT *e)
{
    RAW_U16 ret;
    RAW_S8 ip;

    /*Max nested state levels*/
    stm_state_handler path[STM_MAX_NEST_DEPTH];
            
    stm_state_handler t = me->state;

    if (me->temp == 0) 
    {
        RAW_ASSERT(0);
    }
    /*if state is not equal to the hsm top state, just assert*/
    if (t != STM_STATE_CAST(hsm_top)) 
    {
        RAW_ASSERT(0);
    }

    /*do the hsm constructor init function*/
    ret = (*me->temp)(me, e);

    /*transition must happen here*/
    if (ret != STM_RET_TRAN) 
    {
        RAW_ASSERT(0);
    }
    /*Becareful STM_INIT_SIG must trig t state to the nested children state, otherwise hsm crash*/
    do 
    {     
        ip = 0;
        path[0] = me->temp;
        /*Find all the father state until to hsm_top*/
        STM_TRIG(me->temp, STM_EMPTY_SIG);
        while (me->temp != t) 
        {
            ++ip;
            path[ip] = me->temp;
            STM_TRIG(me->temp, STM_EMPTY_SIG);
        }
        me->temp = path[0]; 
        if (ip >= STM_MAX_NEST_DEPTH) 
        {
            RAW_ASSERT(0);
        }
        /*trig STM_ENTRY_SIG from father source state to nested children state*/
        do 
        {        
            STM_ENTER(path[ip]);                         
            --ip;
        } while (ip >= 0);
        t = path[0];  
        /*trig the STM_INIT_SIG to the new transitioned state, if new transion happened again, then we need do int init again*/
    } while (STM_TRIG(t, STM_INIT_SIG) == STM_RET_TRAN);

    /*change to new state*/
    me->state = t;                      
    me->temp  = t;                 
}

/*
************************************************************************************************************************
*                                   Exceute the hsm state machine
*
* Description: This function is used to exceute the hsm state machine.
*
* Arguments  :me is the state machine
*                    ---------
*                    e is the trig event   
*                         
* Returns            
*                        
* Note(s)        
*
*             
************************************************************************************************************************
*/
void hsm_exceute(STM_STRUCT *me, STATE_EVENT *e)
{
    stm_state_handler s;
    RAW_U16 r;
    RAW_S8 ip;
    RAW_S8 iq;

    stm_state_handler path[STM_MAX_NEST_DEPTH];

    stm_state_handler t = me->state;

    /*state must be stable here*/
    if (t != me->temp) 
    {
        RAW_ASSERT(0);
    }
    do 
    {                             
        s = me->temp;
        /*exceute the state function with new event*/
        r = (*s)(me, e);                         
        if (r == STM_RET_UNHANDLED) 
        {           
            /*Move up to father state*/
            r = STM_TRIG(s, STM_EMPTY_SIG);       
        }
    /*move up to the father state to find suitable state to handle the sig*/
    } while (r == STM_RET_FATHER);

    /*if state transition happened then process it*/
    if (r == STM_RET_TRAN) 
    {                            
        ip = -1;  

        /*save the transitioned state*/
        path[0] = me->temp;            
        path[1] = t;

        /*t is the source state, and s is the state which cause new state change*/
        /*for example s is the father state of t*/
        while (t != s) 
        {  
            /*if STM_EXIT_SIG is handled, trig STM_EMPTY_SIG to find the father state*/ 
            /*if STM_EXIT_SIG not handled , then me->temp hold the father state*/
            if (STM_TRIG(t, STM_EXIT_SIG) == STM_RET_HANDLED) 
            {
                STM_TRIG(t, STM_EMPTY_SIG);
            }

            /*move t to one father state up*/
            t = me->temp;                 
        }

        /*t is the target transition state*/
        t = path[0];                           

        /*all the following code is try to find the LCA and exit from the source state to LCA state*/
        /*Be careful LCA state is either not entered not exited.*/
        /*all the father state of the target transition state is stored to path from hight to low etc, path[0] is the target transition state*/

        if (s == t) 
        {      
            STM_EXIT(s);                                
            ip = 0;                            
        }
        else 
        {
            STM_TRIG(t, STM_EMPTY_SIG);     

            t = me->temp;
            if (s == t) 
            {                
                ip = 0;                        
            }
            else 
            {
                STM_TRIG(s, STM_EMPTY_SIG);    
                if (me->temp == t) 
                {
                    STM_EXIT(s);                        
                    ip = 0;                   
                }
                else 
                {
                    if (me->temp == path[0]) 
                    {
                        STM_EXIT(s);                    
                    }
                    else 
                    {
                        iq = 0;      
                        ip = 1;  
                        path[1] = t;      
                        t = me->temp;                 

                        r = STM_TRIG(path[1], STM_EMPTY_SIG);

                        while (r == STM_RET_FATHER) 
                        {
                            ++ip;
                            path[ip] = me->temp;    
                            if (me->temp == s) 
                            {      
                                iq = 1;  

                                if (ip >= STM_MAX_NEST_DEPTH) 
                                {
                                    RAW_ASSERT(0);
                                }
                                --ip;           
                                r = STM_RET_HANDLED;    
                            }
                            else 
                            {  
                                r = STM_TRIG(me->temp, STM_EMPTY_SIG);
                            }
                        }

                        if (iq == 0) 
                        {   

                            if (ip >= STM_MAX_NEST_DEPTH) 
                            {
                                RAW_ASSERT(0);
                            }
                            STM_EXIT(s);               
                            iq = ip;
                            r = STM_RET_IGNORED;    
                            do 
                            {
                                if (t == path[iq]) 
                                {   
                                    r = STM_RET_HANDLED;

                                    ip = iq - 1;
                                    iq = -1;
                                }
                                else 
                                {
                                    --iq; 
                                }
                            } while (iq >= 0);

                            if (r != STM_RET_HANDLED) 
                            { 
                                r = STM_RET_IGNORED;         
                                do 
                                {
                                    if (STM_TRIG(t, STM_EXIT_SIG) == STM_RET_HANDLED) 
                                    {
                                        STM_TRIG(t, STM_EMPTY_SIG);
                                    }
                                    t = me->temp;    
                                    iq = ip;
                                    do 
                                    {
                                        if (t == path[iq]) 
                                        {
                                            ip = iq - 1;
                                            iq = -1;
                                            r = STM_RET_HANDLED;
                                        }
                                        else 
                                        {
                                            --iq;
                                        }
                                    } while (iq >= 0);
                                } while (r != STM_RET_HANDLED);
                            }
                        }
                    }
                }
            }
        }

        /*trig STM_ENTRY_SIG from LCA to transioned state*/
        for (; ip >= 0; --ip) 
        {
            STM_ENTER(path[ip]);                        
        }

        t = path[0];                     
        me->temp = t;                            

        /*trig the STM_INIT_SIG to the new transitioned state, if new transion happened again, then we need do it again*/
        /*Becareful STM_INIT_SIG must trig t state to the nested children state, otherwise hsm crash*/
        while (STM_TRIG(t, STM_INIT_SIG) == STM_RET_TRAN) 
        {
            ip = 0;
            path[0] = me->temp;

            /*Find all the father state until to source t state */
            STM_TRIG(me->temp, STM_EMPTY_SIG);   

            while (me->temp != t) 
            {
                ++ip;
                path[ip] = me->temp;
                STM_TRIG(me->temp, STM_EMPTY_SIG);
            }
            me->temp = path[0];

            if (ip >= STM_MAX_NEST_DEPTH) 
            {
                RAW_ASSERT(0);
            }
            /*trig STM_ENTRY_SIG from father source state to nested transition children state*/
            do 
            {   
                STM_ENTER(path[ip]);                     
                --ip;
            } while (ip >= 0);
            /*remember the target transitoned state*/
            t = path[0];
        }
    }

    /*change to new state*/
    me->state = t;                       
    me->temp  = t; 

}

/*
************************************************************************************************************************
*                                   Test whether the current state is in state or not
* Description: This function is used to test whether the current state is in state or not.
*
* Arguments  :me is the state machine
*                    ---------
*                    state is to compared with currenet state.
*                         
* Returns            
*                        
* Note(s)        if the state is the father state of current state, it also return 1.    
*
*             
************************************************************************************************************************
*/
RAW_U16 is_hsm_in_state(STM_STRUCT *me, stm_state_handler state) 
{
    RAW_U16 inState = 0; 
    RAW_U16 r;

    RAW_ASSERT(me->temp == me->state);

    do 
    {
        if (me->temp == state)
        {                    
            inState = 1;              
            break;                   
        }
        else 
        {
            r = STM_TRIG(me->temp, STM_EMPTY_SIG);
        }
        
    } while (r != STM_RET_IGNORED); 
    
    me->temp = me->state;        

    return inState;                                   
}
View Code

 

 

逐个函数分析吧:

hsm_top函数:层次状态机的初始化为顶层即父状态。

    此函数没干啥实事 直接返回 STM_RET_IGNORED,根据字面意思直接忽略了。保留此函数可能是为以后扩展使用吧(个人猜测)。

fsm_init函数:有限状态机的初始化。

    函数形参为两个结构体指针,一个指向状态机结构体(成员为两个指向函数的指针,一个是当前状态state,另一个要进入的“下一个状态”temp),另一个指向事件(成员为一个整型变量,一个是空指针或万能指针)。

    在调用fsm_init初始化有限状态机时,我们会先初始化一个状态机。用头文件里的FSM_CONSTRUCTOR宏来初始化,即把当前状态初始化为0,“下一个状态”初始化为状态机构造器的初始化函数。

紧接着会调用函数处理事件并产生触发(ret = (*me->temp)(me, e);)进入“下一个状态”此时会对状态机构造器做初始化。我的理解是上面说的“下一个状态”是为进入状态机初始状态而做的铺垫。所以在fsm_init函数中有个注释/*transition must happen here*/。

这里有个较难理解的宏:#define STM_TRIG(state, sig) ((*(state))(me, &STM_GLOBAL_EVENT[sig]))

分析一下,state是一个指向函数的指针而这个函数返回值是整型有两个形参一个是空指针、另一个是指向STATE_EVENT的指针。跟进代码你会明白来由----typedef RAW_U16 (*stm_state_handler)(void *me, STATE_EVENT *e);

执行这条语句 STM_TRIG(me->temp, STM_ENTRY_SIG);后,即调用了状态机的初始化函数。此时结构体:

typedef struct STM_STRUCT {
    
    stm_state_handler state;        
    stm_state_handler temp; 
    
} STM_STRUCT;

state = 0;

temp = "状态机的初始状态";

紧接着会 

/*change to new state*/
me->state = me->temp;是状态机状态稳定;最终完成fsm的初始化。

fsm_exceute函数: fsm状态机的执行函数,主要是在各个状态中切换。

    首先会判断状态机的状态是否稳定,我的理解在fsm_init执行后 me->state == me->temp

所以这里的 if 一定是不成立的。但为什么会多此一举了。不过作者txj说不多余。我暂时没搞清楚作用什么,慢慢研究再说。

继续分析fsm_exceute函数,判断状态机的状态后就用新的事件来执行状态判断函数。

根据函数的返回值来决定是否进入行的状态。

 

状态机编程还是有一定难度的,慢慢研究中,明天继续分析其他函数,先看下例程………………

 

转载于:https://www.cnblogs.com/king-77024128/articles/4737124.html

你可能感兴趣的:(有限状态机FSM)