层次状态机编程二:设计QM状态机的基本约定

1、消息在头文件中定义为如下格式:
enum GameSignals { /* signals used in the game /
TIME_TICK_SIG = Q_USER_SIG, /
published from tick ISR /
PLAYER_TRIGGER_SIG, /
posted by Player (ISR) to trigger the Missile /
TAKE_OFF_SIG, /
from Tunnel to Ship to grant permission to take off /
HIT_WALL_SIG, /
from Tunnel to Ship when Ship hits the wall /
HIT_MINE_SIG, /
from Mine to Ship or Missile when it hits the mine */
};

2、状态设计的时候,触发消息的填充,去掉第一步定义的SIG,比如
PLAYER_TRIGGER
Q_TIMEOUT
TIME_TICK
HIT_WALL

3、条件分支的习惯约定:
guard可以不起名,但名字下面的框必须填条件,不需要if
(me->blink_ctr & 1U) != 0U
分支的另外一端,可以直接填else,或者没有分支也可以。

4、每一个状态机的entry和exit,最好都加上打印,
entry用来改变成员变量的数据,以及启动timer。
exit用来清除timer。

5、消息处理,放在内部,需要转换状态的,再拉到外面。
层次状态机编程二:设计QM状态机的基本约定_第1张图片
6、内部有子状态机的,需要指定初始状态:
层次状态机编程二:设计QM状态机的基本约定_第2张图片
7、状态机的进入和退出:
因为每当一个状态被进入时,与之联合的进入动作被自动执行,它们常常决定操作的条件或状态的一致性,非常像一个类构造函数在决定被构建对象的特性。例如, heating 状态的特性通过加热器被打开这个事实被确定。在进入 heating 的任何子状态前这个条件必须确立,因为到 heating 子状态的进入动作,比如 toasting,依靠 heating 超状态的适当的初始化,并仅执行和这个初始化不同的部分。因此,进入动作的执行必须总是按从最外层状态到最里层状态的次序被处理。退出动作的执行,对应于析构函数调用,按精确的相反的次序执行,从最里层的状态开始(对应于从最远的派生类开始)。
层次状态机编程二:设计QM状态机的基本约定_第3张图片
8、内部转换:
内部转换不造成状态切换,在e和x下面逐条加上即可,比如下面的any_key。
层次状态机编程二:设计QM状态机的基本约定_第4张图片
9、自转换:
和内部转换不同的是,自转换会造成状态的x和e。

10、本地转换:
本地转换在主目标状态是主源的一个子状态时,并不会导致从主源状态的退出。另外,本地状态转换在主目标是主源状态的一个超状态时,不会导致退出和重新进入目标状态。QP实现的是本地转换,不做退出和重新进入。
层次状态机编程二:设计QM状态机的基本约定_第5张图片
11、转换的执行次序:
层次状态机编程二:设计QM状态机的基本约定_第6张图片
T1 引起监护条件 g() 的评估,假设监护条件 g( ) 被评估为真,后面是动作的执行序列: a( ) ; b( ) ; t( ) ; c( ) ; d( ) 和 e( )

UML 规范规定,一个牵涉到退出所有被嵌套状态的转换,从当前活动状态
直到但是不包含主源和主目标状态的最少共同祖先 least common ancestor(LCA)状态。如名字所示,LCA是源和目标状态的最低的组合状态同时也是它们二者的超状态(祖先)。如上所叙,退出动作的执行次序总是从最深层嵌套状态(当前活动状态)向上沿着层次直到 LCA,但是不退出 LCA。例如,图2.9 所示的状态 s1和 s2的 LCA(s1,s2) 是状态 s 。

来一个更复杂的:
层次状态机编程二:设计QM状态机的基本约定_第7张图片
层次状态机编程二:设计QM状态机的基本约定_第8张图片
总结如下规律:
1、进入每个状态机时,先执行e。
2、如果有上一级的初始转换,则直接进入所指的目标状态,不执行3。
3、否则,则执行本级状态机的初始转换,跳转到子状态。
4、如果收到一个消息,当前状态无法处理,那在父类处理,然后再执行状态转换。s21-g,s211-exit,s21-exit,s2-eixt,s1-entry,s1-init,s11-entry
5、同上,如果不需要进行状态转换,那在上一级处理完即可,依然留在当前子状态。s1-I
6、退出的时候,先执行能处理这个消息的那一级的处理函数,然后一级一级执行e,直到共同的父类,再进入目标状态机。
7、从子状态转换到父状态,先处理消息,然后e,接着执行上一级的init
D:s11-D;s11-exit;s1-init;s11-entry;
8、如果同一个消息,子状态和父状态都有处理函数,那由子状态处理即可。S2-I

来一个复杂例子,计算器的状态机:
层次状态机编程二:设计QM状态机的基本约定_第9张图片

你可能感兴趣的:(QP状态机)