狀態(tài)機發(fā)展至今,其實傳統(tǒng)的FSM應用場合其實并不多了,他雖然可以解決確定性的問題,但是他無法解決軟件重復的問題,層次式狀態(tài)機HSM就是為解決這個問題而提出來的,層次式狀態(tài)機HSM = 有限狀態(tài)機FSM(狀態(tài)機技術) + 面向對象(復用技術),這就是我理解的層次式狀態(tài)機的本質。
層次式狀態(tài)機相比于有限狀態(tài)機,在狀態(tài)轉換方面復雜了很多,因為他有了子狀態(tài)和父狀態(tài)的概念,曾經的FSM,其實也可以看做是一種特殊的層次式狀態(tài)機,也就是他們擁有共同的父狀態(tài),這種情況下,從一個狀態(tài)轉換到另一個狀態(tài)的步驟是固定的,但是一旦兩人不再同一個狀態(tài)層次,問題就變得復雜了很多。
當然也帶來了很多的好處,比如當前的子狀態(tài)機中,并不需要對每一個需要響應的事件進行動作的處理,假如很多擁有相同的父狀態(tài)的子狀態(tài),都需要對同一個事件作出相同的響應,這時候只需要在父狀態(tài)中統(tǒng)一處理一次就可以了,也就是所有的子狀態(tài)都繼承了父狀態(tài)的事件處理,這種在狀態(tài)機里面會有一個新的名字,行為繼承。
層次式狀態(tài)機的實現相對來講是比較復雜的,所有的事件觸發(fā),狀態(tài)轉換都和自身的層相關,以狀態(tài)轉換為例,他需要實現以下轉換,整個轉換的過程無疑是很復雜的,但是沒必要深入把他搞懂,了解就可以了。如下:
層次式事件處理器被設計出來就是為了解決這些麻煩的轉換算法,假如你不需要再造一個處理器(輪子),可以忽略這一部分算法,直接應用就可以,也就是核心是如何使用層次式狀態(tài)機來設計我們的程序,要達到這一目的,你就必要掌握給定一個狀態(tài)模型,任何一個觸發(fā)導致的事件動作或者狀態(tài)轉換的先后順序及執(zhí)行的流程(路徑),掌握了這些,你基本上就掌握了層次式狀態(tài)機的核心規(guī)則,基于這個核心規(guī)則,你可以設計自己的層次式狀態(tài)機,并用于實際的項目中。
掌握一項技能最好的方式就是通過實戰(zhàn),其實針對狀態(tài)機運行規(guī)則這塊,官方提供了一個可以玩的例程,不需要嵌入式硬件的支持,我們就可以實戰(zhàn),通過這個例程基本上囊括了一個層次式狀態(tài)機所有可能出現的轉換的情況,掌握了他,你也就掌握了層次式狀態(tài)機的運行規(guī)則,廢話不多說,直接上例程,先看一下,用于驗證層次式狀態(tài)執(zhí)行的這個例程的狀態(tài)圖,如下:
看著還是比較復雜的,接下來,我們直接讓這個應用程序跑起來,看看初始化完成以后他停在哪,執(zhí)行了哪些操作。
執(zhí)行過程:首先完成TopInit頂層初始化,然后觸發(fā)了一個TRAN轉換,這個轉換的最終目標是S2,但是S2并不是一個最終的子狀態(tài),S2要向最終的子狀態(tài)過渡,首先要進入S2狀態(tài),首先要執(zhí)行S1-ENTRY,然后執(zhí)行S2-ENTRY,然后發(fā)現執(zhí)行S2-INIT,INIT觸發(fā)狀態(tài)轉換,執(zhí)行S21-ENTRY ,S211-ENTRY,完成最終轉換。
這里要注意幾點:
第一、并不是所有的狀態(tài)都要有INIT事件處理,但是如果該狀態(tài)不是最終子狀態(tài),則需要一個INIT。
第二、并不是的INIT在觸發(fā)轉換以后都會執(zhí)行,只有當觸發(fā)轉換是某個超狀態(tài)時,并且完成了到達該超狀態(tài)的進入動作以后,停留在了該超狀態(tài),因為超狀態(tài)不能作為最終的根,所以需要觸發(fā)INIT來完成到最終的根的轉換。
第三、系統(tǒng)的狀態(tài)永遠都是停留在最終的某個子狀態(tài),例如上面的S211,當有信號發(fā)送給當前狀態(tài)時,可能并沒有對應的事件相應的處理,這時候他會遞歸到其上一層也就是Q_SUPER的狀態(tài),查找是否有相應的處理響應,如果沒有就一直往上找,直到找到為止,如果到了HSMTOP層還是沒有,整個信號也就被忽略掉了。
第四、兩個狀態(tài)要進行轉換,首先要找到兩個狀態(tài)的最小的共同超狀態(tài)(有點類似于數學里面那個最小公因數)。然后從源狀態(tài)一路退出至最小共同超狀態(tài),然后再沿著最小共同超狀態(tài)這條路,一路進入到目標狀態(tài),執(zhí)行完這個過程狀態(tài)轉換完成。
繼續(xù)我們的應用例程,當前狀態(tài)處于S211,這個時候,我們按下鍵盤的F鍵,觸發(fā)f事件,來分析一下系統(tǒng)將會作出什么樣的反應,根據我們上述總結的幾點:
1. 當前處于S211的狀態(tài),查找其狀態(tài)或者其超狀態(tài)是否有對應的信號響應,根據狀態(tài)圖可以看到,其響應為S2狀態(tài),響應動作為狀態(tài)轉換,目標狀態(tài)位s11。
2.開始執(zhí)行源狀態(tài)S211---->S11目標狀態(tài)的轉換,先查找其最小共同超狀態(tài),我們看狀態(tài)圖一眼就能看出來,但是程序上算法查找還是比較復雜的,這里看圖說話,最小共同超狀態(tài)為S狀態(tài)。
3.從源狀態(tài)一路退出至S,s211-EXIT;s21-EXIT;s2-EXIT;
4.從S一路進入至S11,s1-ENTRY;s11-ENTRY;
真實的執(zhí)行結果如下:
帶有內置參數的事件處理,兩次執(zhí)行相同的事件可能會返回不同的執(zhí)行路徑,現象如下:
S11內部處理的代碼如下:
超狀態(tài)S1的相關內部代碼如下:
這個可以嘗試自己分析一下,根據代碼和狀態(tài)圖,分析一下為什么會有兩種不同的輸出。
除此之外還有很多的事件信號可以被觸發(fā),例如下面:
感興趣可以自己下載源碼跑起來,自己操作和分析,需要源碼的話也可以留言,留下郵箱,我打包發(fā)給大家??吹竭@里HSM的變換流程就基本差不多了。