0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何利用Linux下的工具來自動(dòng)生成實(shí)用的狀態(tài)機(jī)框架?

STM32嵌入式開發(fā) ? 來源:STM32嵌入式開發(fā) ? 2023-11-25 14:15 ? 次閱讀

有限自動(dòng)機(jī)(Finite Automata Machine)是計(jì)算機(jī)科學(xué)的重要基石,它在軟件開發(fā)領(lǐng)域內(nèi)通常被稱作有限狀態(tài)機(jī)(Finite State Machine),是一種應(yīng)用非常廣泛的軟件設(shè)計(jì)模式(Design Pattern)。本文介紹如何構(gòu)建基于狀態(tài)機(jī)的軟件系統(tǒng),以及如何利用Linux下的工具來自動(dòng)生成實(shí)用的狀態(tài)機(jī)框架。

一、什么是狀態(tài)機(jī)

有限狀態(tài)機(jī)是一種用來進(jìn)行對(duì)象行為建模的工具,其作用主要是描述對(duì)象在它的生命周期內(nèi)所經(jīng)歷的狀態(tài)序列,以及如何響應(yīng)來自外界的各種事件。在面向?qū)ο蟮能浖到y(tǒng)中,一個(gè)對(duì)象無論多么簡(jiǎn)單或者多么復(fù)雜,都必然會(huì)經(jīng)歷一個(gè)從開始創(chuàng)建到最終消亡的完整過程,這通常被稱為對(duì)象的生命周期。一般說來,對(duì)象在其生命期內(nèi)是不可能完全孤立的,它必須通過發(fā)送消息來影響其它對(duì)象,或者通過接受消息來改變自身。在大多數(shù)情況下,這些消息都只不過是些簡(jiǎn)單的、同步的方法調(diào)用而已。例如,在銀行客戶管理系統(tǒng)中,客戶類(Customer)的實(shí)例在需要的時(shí)候,可能會(huì)調(diào)用帳戶(Account)類中定義的getBalance()方法。在這種簡(jiǎn)單的情況下,類Customer并不需要一個(gè)有限狀態(tài)機(jī)來描述自己的行為,主要原因在于它當(dāng)前的行為并不依賴于過去的某個(gè)狀態(tài)。

遺憾的是并不是所有情況都會(huì)如此簡(jiǎn)單,事實(shí)上許多實(shí)用的軟件系統(tǒng)都必須維護(hù)一兩個(gè)非常關(guān)鍵的對(duì)象,它們通常具有非常復(fù)雜的狀態(tài)轉(zhuǎn)換關(guān)系,而且需要對(duì)來自外部的各種異步事件進(jìn)行響應(yīng)。例如,在VoIP電話系統(tǒng)中,電話類(Telephone)的實(shí)例必須能夠響應(yīng)來自對(duì)方的隨機(jī)呼叫,來自用戶的按鍵事件,以及來自網(wǎng)絡(luò)的信令等。在處理這些消息時(shí),類Telephone所要采取的行為完全依賴于它當(dāng)前所處的狀態(tài),因而此時(shí)使用狀態(tài)機(jī)就將是一個(gè)不錯(cuò)的選擇。

游戲引擎是有限狀態(tài)機(jī)最為成功的應(yīng)用領(lǐng)域之一,由于設(shè)計(jì)良好的狀態(tài)機(jī)能夠被用來取代部分的人工智能算法,因此游戲中的每個(gè)角色或者器件都有可能內(nèi)嵌一個(gè)狀態(tài)機(jī)??紤]RPG游戲中城門這樣一個(gè)簡(jiǎn)單的對(duì)象,它具有打開(Opened)、關(guān)閉(Closed)、上鎖(Locked)、解鎖(Unlocked)四種狀態(tài),如圖1所示。當(dāng)玩家到達(dá)一個(gè)處于狀態(tài)Locked的門時(shí),如果此時(shí)他已經(jīng)找到了用來開門的鑰匙,那么他就可以利用它將門的當(dāng)前狀態(tài)轉(zhuǎn)變?yōu)閁nlocked,進(jìn)一步還可以通過旋轉(zhuǎn)門上的把手將其狀態(tài)轉(zhuǎn)變?yōu)镺pened,從而成功地進(jìn)入城內(nèi)。

圖1 控制城門的狀態(tài)機(jī)

wKgaomTHHS-AfHBhAAA18Y7DHew041.jpg

在描述有限狀態(tài)機(jī)時(shí),狀態(tài)、事件、轉(zhuǎn)換和動(dòng)作是經(jīng)常會(huì)碰到的幾個(gè)基本概念。

狀態(tài)(State)指的是對(duì)象在其生命周期中的一種狀況,處于某個(gè)特定狀態(tài)中的對(duì)象必然會(huì)滿足某些條件、執(zhí)行某些動(dòng)作或者是等待某些事件。

事件(Event)指的是在時(shí)間和空間上占有一定位置,并且對(duì)狀態(tài)機(jī)來講是有意義的那些事情。事件通常會(huì)引起狀態(tài)的變遷,促使?fàn)顟B(tài)機(jī)從一種狀態(tài)切換到另一種狀態(tài)。

轉(zhuǎn)換(Transition)指的是兩個(gè)狀態(tài)之間的一種關(guān)系,表明對(duì)象將在第一個(gè)狀態(tài)中執(zhí)行一定的動(dòng)作,并將在某個(gè)事件發(fā)生- 同時(shí)某個(gè)特定條件滿足時(shí)進(jìn)入第二個(gè)狀態(tài)。

動(dòng)作(Action)指的是狀態(tài)機(jī)中可以執(zhí)行的那些原子操作,所謂原子操作指的是它們?cè)谶\(yùn)行的過程中不能被其他消息所中斷,必須一直執(zhí)行下去。

二、手工編寫狀態(tài)機(jī)

與其他常用的設(shè)計(jì)模式有所不同,程序員想要在自己的軟件系統(tǒng)中加入狀態(tài)機(jī)時(shí),必須再額外編寫一部分用于邏輯控制的代碼,如果系統(tǒng)足夠復(fù)雜的話,這部分代碼實(shí)現(xiàn)和維護(hù)起來還是相當(dāng)困難的。在實(shí)現(xiàn)有限狀態(tài)機(jī)時(shí),使用switch語句是最簡(jiǎn)單也是最直接的一種方式,其基本思路是為狀態(tài)機(jī)中的每一種狀態(tài)都設(shè)置一個(gè)case分支,專門用于對(duì)該狀態(tài)進(jìn)行控制。下面的代碼示范了如何運(yùn)用switch語句,來實(shí)現(xiàn)圖1中所示的狀態(tài)機(jī):


switch (state)  {


  // 處理狀態(tài)Opened的分支
  case (Opened): {
    // 執(zhí)行動(dòng)作Open
    open();
    // 檢查是否有CloseDoor事件
    if (closeDoor()) {
      // 當(dāng)前狀態(tài)轉(zhuǎn)換為Closed
      changeState(Closed)
    }
    break;
  }


  // 處理狀態(tài)Closed的分支
  case (Closed): {
    // 執(zhí)行動(dòng)作Close
    close();
    // 檢查是否有OpenDoor事件
    if (openDoor()) {
      // 當(dāng)前狀態(tài)轉(zhuǎn)換為Opened
      changeState(Opened);
    }
    // 檢查是否有LockDoor事件
    if (lockDoor()) {
      // 當(dāng)前狀態(tài)轉(zhuǎn)換為L(zhǎng)ocked
      changeState(Locked);
    }
    break;
  }


  // 處理狀態(tài)Locked的分支
  case (Locked): {
    // 執(zhí)行動(dòng)作Lock
    lock();
    // 檢查是否有UnlockDoor事件
    if (unlockDoor()) {
      // 當(dāng)前狀態(tài)轉(zhuǎn)換為Unlocked
      changeState(Unlocked);
    }
    break;
  }


  // 處理狀態(tài)Unlocked的分支
  case (Unlocked): {
    // 執(zhí)行動(dòng)作Unlock
    unlock();
    // 檢查是否有LockDoor事件
    if (lockDoor()) {
      // 當(dāng)前狀態(tài)轉(zhuǎn)換為L(zhǎng)ocked
      changeState(Locked)
    }
    // 檢查是否有OpenDoor事件
    if (openDoor()) {
      // 當(dāng)前狀態(tài)轉(zhuǎn)換為Opened
      changeSate(Opened);
    }
    break;
  }
}
使用switch語句實(shí)現(xiàn)的有限狀態(tài)機(jī)的確能夠很好地工作,但代碼的可讀性并不十分理想,主要原因是在實(shí)現(xiàn)狀態(tài)之間的轉(zhuǎn)換時(shí),檢查轉(zhuǎn)換條件和進(jìn)行狀態(tài)轉(zhuǎn)換都是混雜在當(dāng)前狀態(tài)中來完成的。例如,當(dāng)城門處于Opened狀態(tài)時(shí),需要在相應(yīng)的case中調(diào)用closeDoor()函數(shù)來檢查是否有必要進(jìn)行狀態(tài)轉(zhuǎn)換,如果是的話則還需要調(diào)用changeState()函數(shù)將當(dāng)前狀態(tài)切換到Closed。顯然,如果在每種狀態(tài)下都需要分別檢查多個(gè)不同的轉(zhuǎn)換條件,并且需要根據(jù)檢查結(jié)果讓狀態(tài)機(jī)切換到不同的狀態(tài),那么這樣的代碼將是枯燥而難懂的。從代碼重構(gòu)的角度來講,此時(shí)更好的做法是引入checkStateChange()和performStateChange()兩個(gè)函數(shù),專門用來對(duì)轉(zhuǎn)換條件進(jìn)行檢查,以及激活轉(zhuǎn)換時(shí)所需要執(zhí)行的各種動(dòng)作。這樣一來,程序結(jié)構(gòu)將變得更加清晰:

switch (state)  {


  // 處理狀態(tài)Opened的分支
  case (Opened): {
    // 執(zhí)行動(dòng)作Open
    open();
    // 檢查是否有激發(fā)狀態(tài)轉(zhuǎn)換的事件產(chǎn)生
    if (checkStateChange()) {
      // 對(duì)狀態(tài)機(jī)的狀態(tài)進(jìn)行轉(zhuǎn)換
      performStateChange();
    }
    break;
  }


  // 處理狀態(tài)Closed的分支
  case (Closed): {
    // 執(zhí)行動(dòng)作Close
    close();
    // 檢查是否有激發(fā)狀態(tài)轉(zhuǎn)換的事件產(chǎn)生
    if (checkStateChange()) {
      // 對(duì)狀態(tài)機(jī)的狀態(tài)進(jìn)行轉(zhuǎn)換
      performStateChange();
    }
    break;
  }


  // 處理狀態(tài)Locked的分支
  case (Locked): {
    // 執(zhí)行動(dòng)作Lock
    lock();
    // 檢查是否有激發(fā)狀態(tài)轉(zhuǎn)換的事件產(chǎn)生
    if (checkStateChange()) {
      // 對(duì)狀態(tài)機(jī)的狀態(tài)進(jìn)行轉(zhuǎn)換
      performStateChange();
    }
    break;
  }


  // 處理狀態(tài)Unlocked的分支
  case (Unlocked): {
    // 執(zhí)行動(dòng)作Lock
    unlock();
    // 檢查是否有激發(fā)狀態(tài)轉(zhuǎn)換的事件產(chǎn)生
    if (checkStateChange()) {
      // 對(duì)狀態(tài)機(jī)的狀態(tài)進(jìn)行轉(zhuǎn)換
      performStateChange();
    }
    break;
  }
}
但checkStateChange()和performStateChange()這兩個(gè)函數(shù)本身依然會(huì)在面對(duì)很復(fù)雜的狀態(tài)機(jī)時(shí),內(nèi)部邏輯變得異常臃腫,甚至可能是難以實(shí)現(xiàn)。

在很長(zhǎng)一段時(shí)期內(nèi),使用switch語句一直是實(shí)現(xiàn)有限狀態(tài)機(jī)的唯一方法,甚至像編譯器這樣復(fù)雜的軟件系統(tǒng),大部分也都直接采用這種實(shí)現(xiàn)方式。但之后隨著狀態(tài)機(jī)應(yīng)用的逐漸深入,構(gòu)造出來的狀態(tài)機(jī)越來越復(fù)雜,這種方法也開始面臨各種嚴(yán)峻的考驗(yàn),其中最令人頭痛的是如果狀態(tài)機(jī)中的狀態(tài)非常多,或者狀態(tài)之間的轉(zhuǎn)換關(guān)系異常復(fù)雜,那么簡(jiǎn)單地使用switch語句構(gòu)造出來的狀態(tài)機(jī)將是不可維護(hù)的。

3 自動(dòng)生成狀態(tài)機(jī)

為實(shí)用的軟件系統(tǒng)編寫狀態(tài)機(jī)并不是一件十分輕松的事情,特別是當(dāng)狀態(tài)機(jī)本身比較復(fù)雜的時(shí)候尤其如此,許多有過類似經(jīng)歷的程序員往往將其形容為"毫無創(chuàng)意"的過程,因?yàn)樗麄冃枰獙⒋罅康臅r(shí)間與精力傾注在如何管理好狀態(tài)機(jī)中的各種狀態(tài)上,而不是程序本身的運(yùn)行邏輯。

作為一種通用的軟件設(shè)計(jì)模式,各種軟件系統(tǒng)的狀態(tài)機(jī)之間肯定會(huì)或多或少地存在著一些共性,因此人們開始嘗試開發(fā)一些工具來自動(dòng)生成有限狀態(tài)機(jī)的框架代碼,而在Linux下就有一個(gè)挺不錯(cuò)的選擇──FSME(Finite State Machine Editor)。

下圖2:可視化的FSME。

23d9452c-8b4d-11ee-939d-92fbcf53809c.jpg

FSME是一個(gè)基于Qt的有限狀態(tài)機(jī)工具,它能夠讓用戶通過圖形化的方式來對(duì)程序中所需要的狀態(tài)機(jī)進(jìn)行建模,并且還能夠自動(dòng)生成用C++或者Python實(shí)現(xiàn)的狀態(tài)機(jī)框架代碼。下面就以圖1中城門的狀態(tài)機(jī)為例,來介紹如何利用FSME來自動(dòng)生成程序中所需要的狀態(tài)機(jī)代碼。

3.1 狀態(tài)機(jī)建模

首先運(yùn)行fsme命令來啟動(dòng)狀態(tài)機(jī)編輯器,然后單擊工具欄上的"New"按鈕來創(chuàng)建一個(gè)新的狀態(tài)機(jī)。FSME中用于構(gòu)建狀態(tài)機(jī)的基本元素一共有五種:事件(Event)、輸入(Input)、輸出(Output)、狀態(tài)(State)和轉(zhuǎn)換(Transition),在界面左邊的樹形列表中可以找到其中的四種。

狀態(tài)建模

在FSME界面左邊的樹形列表中選擇"States"項(xiàng),然后按下鍵盤上的Insert鍵來插入一個(gè)新的狀態(tài),接著在右下方的"Name"文本框中輸入狀態(tài)的名稱,再在右上方的繪圖區(qū)域單擊該狀態(tài)所要放置的位置,一個(gè)新的狀態(tài)就創(chuàng)建好了。用同樣的辦法可以添加狀態(tài)機(jī)所需要的所有狀態(tài),如下圖3所示。

下圖3:狀態(tài)建模。

23ea8fe4-8b4d-11ee-939d-92fbcf53809c.jpg

事件建模

在FSME界面左邊的樹形列表中選擇"Events"項(xiàng),然后按下鍵盤上的Insert鍵來添加一個(gè)新的事件,接著在右下方的"Name"文本框中輸入事件的名稱,再單擊"Apply"按鈕,一個(gè)新的事件就創(chuàng)建好了。用同樣的辦法可以添加狀態(tài)機(jī)所需要的所有事件,如下圖4所示。

2402192a-8b4d-11ee-939d-92fbcf53809c.jpg

轉(zhuǎn)換建模

狀態(tài)轉(zhuǎn)換是整個(gè)建模過程中最重要的一個(gè)部分,它用來定義有限狀態(tài)機(jī)中的一個(gè)狀態(tài)是如何切換到另一個(gè)狀態(tài)的。例如,當(dāng)用來控制城門的狀態(tài)機(jī)處于Opened狀態(tài)時(shí),如果此時(shí)有Close事件產(chǎn)生,那么狀態(tài)機(jī)的當(dāng)前狀態(tài)將切換到Closed狀態(tài),這樣一個(gè)完整的過程在狀態(tài)機(jī)模型中可以用closeDoor這樣一個(gè)轉(zhuǎn)換來進(jìn)行描述。

要在FSME中添加這樣一個(gè)轉(zhuǎn)換,首先需要在界面左邊的樹形列表中選擇"States"下的"Opened"項(xiàng),然后按下鍵盤上的Insert鍵來添加一個(gè)新的轉(zhuǎn)換,接著在右下角的"Name"文本框中輸入轉(zhuǎn)換的名字"closeDoor",在"Condition"文本框中輸入"Close"表明觸發(fā)該轉(zhuǎn)換的條件是事件Close的產(chǎn)生,在"Target"下拉框中選擇"Closed"項(xiàng)表明該轉(zhuǎn)換發(fā)生后狀態(tài)機(jī)將被切換到Closed狀態(tài),最后再單擊"Apply"按鈕,一個(gè)新的狀態(tài)轉(zhuǎn)換關(guān)系就定義好了,如圖5所示。用同樣的辦法可以添加狀態(tài)機(jī)所需要的所有轉(zhuǎn)換。

下圖5:轉(zhuǎn)換建模。

2411e9e0-8b4d-11ee-939d-92fbcf53809c.jpg

3.2 生成狀態(tài)機(jī)框架

使用FSME不僅能夠進(jìn)行可視化的狀態(tài)機(jī)建模,更重要的是它還可以根據(jù)得到的模型自動(dòng)生成用C++或者Python實(shí)現(xiàn)的狀態(tài)機(jī)框架。首先在FSME界面左邊的樹形列表中選擇"Root"項(xiàng),然后在右下角的"Name"文本框中輸入狀態(tài)機(jī)的名字"DoorFSM",再?gòu)?Initial State"下拉列表中選擇狀態(tài)"Opened"作為狀態(tài)機(jī)的初始化狀態(tài),如下圖6所示。

下圖6:設(shè)置初始屬性。

2431f49c-8b4d-11ee-939d-92fbcf53809c.jpg

在將狀態(tài)機(jī)模型保存為door.fsm文件之后,使用下面的命令可以生成包含有狀態(tài)機(jī)定義的頭文件:


[xiaowp@linuxgam code]$ fsmc door.fsm -d -o DoorFSM.h
進(jìn)一步還可以生成包含有狀態(tài)機(jī)實(shí)現(xiàn)的框架代碼:

[xiaowp@linuxgamcode]$fsmcdoor.fsm-d-implDoorFSM.h-oDoorFSM.cpp

如果想對(duì)生成的狀態(tài)機(jī)進(jìn)行驗(yàn)證,只需要再手工編寫一段用于測(cè)試的代碼就可以了:

/*
 * TestFSM.cpp
 * 測(cè)試生成的狀態(tài)機(jī)框架
 */


#include "DoorFSM.h"


int main()
{
  DoorFSM door;
  door.A(DoorFSM::Close);
  door.A(DoorFSM::Lock);
  door.A(DoorFSM::Unlock);
  door.A(DoorFSM::Open);
}
有限狀態(tài)機(jī)是由事件來進(jìn)行驅(qū)動(dòng)的,在FSME生成的狀態(tài)機(jī)框架代碼中,方法A()可以被用來向狀態(tài)機(jī)發(fā)送相應(yīng)的事件,從而提供狀態(tài)機(jī)正常運(yùn)轉(zhuǎn)所需要的"動(dòng)力"。狀態(tài)機(jī)負(fù)責(zé)在其內(nèi)部維護(hù)一個(gè)事件隊(duì)列,所有到達(dá)的事件都會(huì)先被放到事件隊(duì)列中進(jìn)行等候,從而能夠保證它們將按照到達(dá)的先后順序被依次處理。在處理每一個(gè)到達(dá)的事件時(shí),狀態(tài)機(jī)都會(huì)根據(jù)自己當(dāng)前所處的狀態(tài),檢查與該狀態(tài)對(duì)應(yīng)的轉(zhuǎn)換條件是否已經(jīng)被滿足,如果滿足的話則激活相應(yīng)的狀態(tài)轉(zhuǎn)換過程。 使用下面的命令能夠?qū)⑸傻臓顟B(tài)機(jī)框架和測(cè)試代碼編譯成一個(gè)可執(zhí)行文件:

[xiaowp@linuxgam code]$ g++ DoorFSM.cpp TestFSM.cpp -o fsm
由于之前在用fsmc命令生成狀態(tài)機(jī)代碼時(shí)使用了-d選項(xiàng),生成的狀態(tài)機(jī)框架中會(huì)包含一定的調(diào)試信息,包括狀態(tài)機(jī)中每次狀態(tài)轉(zhuǎn)換時(shí)的激活事件、轉(zhuǎn)換前的狀態(tài)、所經(jīng)歷的轉(zhuǎn)換、轉(zhuǎn)換后的狀態(tài)等,如下所示:

[xiaowp@linuxgam code]$ ./fsm
DoorFSM:event:'Close'
DoorFSM'Opened'
DoorFSM'closeDoor'
DoorFSM:new state:'Closed'
DoorFSM:event:'Lock'
DoorFSM'Closed'
DoorFSM'lockDoor'
DoorFSM:new state:'Locked'
DoorFSM:event:'Unlock'
DoorFSM'Locked'
DoorFSM'unlockDoor'
DoorFSM:new state:'Unlocked'
DoorFSM:event:'Open'
DoorFSM'Unlocked'
DoorFSM'openDoor'
DoorFSM:new state:'Opened'

3.3 定制狀態(tài)機(jī)

目前得到的狀態(tài)機(jī)已經(jīng)能夠響應(yīng)來自外部的各種事件,并適當(dāng)?shù)卣{(diào)整自己當(dāng)前所處的狀態(tài),也就是說已經(jīng)實(shí)現(xiàn)了狀態(tài)機(jī)引擎的功能,接下來要做的就是根據(jù)應(yīng)用的具體需求來進(jìn)行定制,為狀態(tài)機(jī)加入與軟件系統(tǒng)本身相關(guān)的那些處理邏輯。在FSME中,與具體應(yīng)用相關(guān)的操作稱為輸出(Output),它們實(shí)際上就是一些需要用戶給出具體實(shí)現(xiàn)的虛函數(shù),自動(dòng)生成的狀態(tài)機(jī)引擎負(fù)責(zé)在進(jìn)入或者退出某個(gè)狀態(tài)時(shí)調(diào)用它們。

仍然以控制城門的那個(gè)狀態(tài)機(jī)為例,假設(shè)我們希望在進(jìn)入每個(gè)狀態(tài)時(shí)都添加一部分處理邏輯。首在FSME界面左邊的樹形列表選擇"Outputs"項(xiàng),然后按下鍵盤上的Insert鍵來添加一個(gè)新的輸出,接著在右下方的"Name"文本框中輸入相應(yīng)的名稱,再單擊"Apply"按鈕,一個(gè)新的輸出就創(chuàng)建好了,如圖7所示。用同樣的辦法可以添加狀態(tài)機(jī)所需要的所有輸出。

下圖7:添加輸出。

2443e328-8b4d-11ee-939d-92fbcf53809c.jpg

當(dāng)所有的輸出都定義好之后,接下來就可以為狀態(tài)機(jī)中的每個(gè)狀態(tài)綁定相應(yīng)的輸出。首先在FSME界面左側(cè)的"States"項(xiàng)中選擇相應(yīng)的狀態(tài),然后從右下角的"Available"列表框中選擇與該狀態(tài)對(duì)應(yīng)的輸出,再單擊"<"按鈕將其添加到"In"列表中,如圖8所示。用同樣的辦法可以為狀態(tài)機(jī)中的所有狀態(tài)設(shè)置相應(yīng)的輸出,同一個(gè)狀態(tài)可以對(duì)應(yīng)有多個(gè)輸出,其中In列表中的輸出會(huì)在進(jìn)入該狀態(tài)時(shí)被調(diào)用,而Out列表中的輸出則會(huì)在退出該狀態(tài)時(shí)被調(diào)用,輸出調(diào)用的順序是與其在In或者Out列表中的順序相一致的。

下圖8:為狀態(tài)設(shè)置輸出。

244d8c48-8b4d-11ee-939d-92fbcf53809c.jpg

由于對(duì)狀態(tài)機(jī)模型進(jìn)行了修改,我們需要再次生成狀態(tài)機(jī)的框架代碼,不過這次不需要加上-d參數(shù)


[xiaowp@linuxgam code]$ fsmc door.fsm -o DoorFSM.h
[xiaowp@linuxgamcode]$fsmcdoor.fsm-d-implDoorFSM.h-oDoorFSM.cpp

我們?cè)谛碌臓顟B(tài)機(jī)模型中添加了enterOpend、enterClosed、enterLocked和enterUnlocked四個(gè)輸出,因此生成的類DoorFSM中會(huì)包含如下幾個(gè)純虛函數(shù):

virtual void enterOpened() = 0;
virtual void enterLocked() = 0;
virtual void enterUnlocked() = 0;
virtual void enterClosed() = 0;
顯然,此時(shí)生成的狀態(tài)機(jī)框架不能夠再被直接編譯了,我們必須從類DoorFSM派生出一個(gè)子類,并提供對(duì)這幾個(gè)純虛函數(shù)的具體實(shí)現(xiàn):

/*
 * DoorFSMLogic.h
 * 狀態(tài)機(jī)控制邏輯的頭文件
 */
#include "DoorFSM.h"


class DoorFSMLogic : public DoorFSM
{
 
 protected:
  virtual void enterOpened();
  virtual void enterLocked();
  virtual void enterUnlocked();
  virtual void enterClosed();
};
正如前面所提到過的,這幾個(gè)函數(shù)實(shí)際上代表的正是應(yīng)用系統(tǒng)的處理邏輯,作為例子我們只是簡(jiǎn)單地輸出一些提示信息:

/*
 * DoorFSMLogic.cpp
 * 狀態(tài)機(jī)控制邏輯的實(shí)現(xiàn)文件
 */
#include "DoorFSMLogic.h"
#include 


void DoorFSMLogic::enterOpened()
{
    std::cout << "Enter Opened state." << std::endl;
}


void DoorFSMLogic::enterClosed()
{
    std::cout << "Enter Closed state." << std::endl;
}


void DoorFSMLogic::enterLocked()
{
    std::cout << "Enter Locked state." << std::endl;
}


void DoorFSMLogic::enterUnlocked()
{
    std::cout << "Enter Unlocked state." << std::endl;
}
同樣,為了對(duì)生成的狀態(tài)機(jī)進(jìn)行驗(yàn)證,我們還需要手工編寫一段測(cè)試代碼:

/*
 * TestFSM.cpp
 * 測(cè)試狀態(tài)機(jī)邏輯
 */
#include "DoorFSMLogic.h"


int main()
{
  DoorFSMLogic door;
  door.A(DoorFSM::Close);
  door.A(DoorFSM::Lock);
  door.A(DoorFSM::Unlock);
  door.A(DoorFSM::Open);
}
使用下面的命令能夠?qū)⑸傻臓顟B(tài)機(jī)框架和測(cè)試代碼編譯成一個(gè)可執(zhí)行文件:


[xiaowp@linuxgamcode]$g++DoorFSM.cppDoorFSMLogic.cppTestLogic.cpp-ologic

運(yùn)行結(jié)果如下所示:

[xiaowp@linuxgam code]$ ./logic
Enter Closed state.
Enter Locked state.
Enter Unlocked state.
Enter Opened state.

4 小結(jié)

在面向?qū)ο蟮能浖到y(tǒng)中,有些對(duì)象具有非常復(fù)雜的生命周期模型,使用有限狀態(tài)機(jī)是描述這類對(duì)象最好的方法。作為一種軟件設(shè)計(jì)模式,有限狀態(tài)機(jī)的概念雖然不算復(fù)雜,實(shí)現(xiàn)起來也并不困難,但它的問題是當(dāng)狀態(tài)機(jī)的模型復(fù)雜到一定的程度之后,會(huì)帶來實(shí)現(xiàn)和維護(hù)上的困難。Linux下的FSME是一個(gè)可視化的有限狀態(tài)機(jī)建模工具,而且支持狀態(tài)機(jī)框架代碼的自動(dòng)生成,借助它可以更加輕松地構(gòu)建基于有限狀態(tài)機(jī)的應(yīng)用系統(tǒng)。







審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11207

    瀏覽量

    208713
  • 有限狀態(tài)機(jī)

    關(guān)注

    0

    文章

    52

    瀏覽量

    10311
  • 狀態(tài)機(jī)
    +關(guān)注

    關(guān)注

    2

    文章

    491

    瀏覽量

    27456
  • RPG
    RPG
    +關(guān)注

    關(guān)注

    0

    文章

    12

    瀏覽量

    7660

原文標(biāo)題:狀態(tài)機(jī):自動(dòng)生成代碼

文章出處:【微信號(hào):c-stm32,微信公眾號(hào):STM32嵌入式開發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    如何設(shè)計(jì)自動(dòng)駕駛系統(tǒng)的狀態(tài)機(jī)

    狀態(tài)機(jī)模塊在自動(dòng)駕駛系統(tǒng)中扮演著關(guān)鍵的角色,它負(fù)責(zé)管理和控制各個(gè)功能的狀態(tài)轉(zhuǎn)換和行為執(zhí)行。今天我們來聊聊如何設(shè)計(jì)自動(dòng)駕駛系統(tǒng)的狀態(tài)機(jī)
    發(fā)表于 09-19 15:07 ?2315次閱讀
    如何設(shè)計(jì)<b class='flag-5'>自動(dòng)</b>駕駛系統(tǒng)的<b class='flag-5'>狀態(tài)機(jī)</b>

    SaberRD狀態(tài)機(jī)建模工具介紹(一)什么是狀態(tài)機(jī)建模

    狀態(tài)機(jī)建模是使用狀態(tài)圖和方程式的手段,創(chuàng)建基于混合信號(hào)的有限狀態(tài)機(jī)模型的一種建模工具
    的頭像 發(fā)表于 12-05 09:51 ?1565次閱讀
    SaberRD<b class='flag-5'>狀態(tài)機(jī)</b>建模<b class='flag-5'>工具</b>介紹(一)什么是<b class='flag-5'>狀態(tài)機(jī)</b>建模

    [開源框架] 極簡(jiǎn)信號(hào)/狀態(tài)機(jī)框架 NorthFrame

    的全局變量困擾?是否在尋找一種層級(jí)間松耦合的信號(hào)傳遞方式?是否希望優(yōu)雅無負(fù)擔(dān)地使用狀態(tài)機(jī)思路進(jìn)行開發(fā)?調(diào)試打Log很麻煩,希望自動(dòng)生成,最好還有測(cè)試腳本?NF_Signal和NF_FSM 來幫你用法1:代替
    發(fā)表于 02-25 13:52

    狀態(tài)機(jī)代碼生成工具

    狀態(tài)機(jī)代碼生成工具狀態(tài)機(jī)代碼生成工具狀態(tài)機(jī)代碼
    發(fā)表于 11-19 15:12 ?9次下載

    使用ModelSim自動(dòng)生成狀態(tài)機(jī)FSM的狀態(tài)轉(zhuǎn)換圖

    HDL代碼設(shè)計(jì)中重要的內(nèi)容之一就是設(shè)計(jì)程序的狀態(tài)機(jī)FSM,狀態(tài)轉(zhuǎn)換控制著整個(gè)程序的流程,為了理解程序,我們經(jīng)常需要把狀態(tài)機(jī)狀態(tài)轉(zhuǎn)換圖畫出來,這樣看起來很直觀,但是,有沒有辦法
    發(fā)表于 02-10 15:39 ?1.5w次閱讀
    使用ModelSim<b class='flag-5'>自動(dòng)</b><b class='flag-5'>生成</b><b class='flag-5'>狀態(tài)機(jī)</b>FSM的<b class='flag-5'>狀態(tài)</b>轉(zhuǎn)換圖

    利用狀態(tài)機(jī)狀態(tài)機(jī)實(shí)現(xiàn)層次結(jié)構(gòu)化設(shè)計(jì)

    練習(xí)九.利用狀態(tài)機(jī)的嵌套實(shí)現(xiàn)層次結(jié)構(gòu)化設(shè)計(jì)目的:1.運(yùn)用主狀態(tài)機(jī)與子狀態(tài)機(jī)產(chǎn)生層次化的邏輯設(shè)計(jì);
    發(fā)表于 02-11 05:52 ?3277次閱讀
    <b class='flag-5'>利用</b><b class='flag-5'>狀態(tài)機(jī)</b>的<b class='flag-5'>狀態(tài)機(jī)</b>實(shí)現(xiàn)層次結(jié)構(gòu)化設(shè)計(jì)

    什么是狀態(tài)機(jī)狀態(tài)機(jī)5要素

    玩單片機(jī)還可以,各個(gè)外設(shè)也都會(huì)驅(qū)動(dòng),但是如果讓你完整的寫一套代碼時(shí),卻無邏輯與框架可言。這說明編程還處于比較低的水平,你需要學(xué)會(huì)一種好的編程框架或者一種編程思想!比如模塊化編程、狀態(tài)機(jī)
    的頭像 發(fā)表于 07-27 11:23 ?2w次閱讀
    什么是<b class='flag-5'>狀態(tài)機(jī)</b>?<b class='flag-5'>狀態(tài)機(jī)</b>5要素

    MCU裸機(jī)編程的狀態(tài)機(jī)框架--第一部分

    MCU裸機(jī)編程的狀態(tài)機(jī)框架--第一部分1 狀態(tài)機(jī)的概念1.1 狀態(tài)機(jī)的要素1.2 狀態(tài)遷移表1.3 狀態(tài)
    發(fā)表于 12-09 13:21 ?17次下載
    MCU裸機(jī)編程的<b class='flag-5'>狀態(tài)機(jī)</b><b class='flag-5'>框架</b>--第一部分

    基于單片機(jī)的極簡(jiǎn)圖形化狀態(tài)機(jī)框架NorthFrame

    NorthFrame是基于非UML極簡(jiǎn)理念的狀態(tài)機(jī)框架。配合NF_FsmDesigner圖形化開發(fā)工具,可無負(fù)擔(dān)替代傳統(tǒng)switch-case狀態(tài)機(jī)開發(fā)。
    發(fā)表于 02-08 15:44 ?3次下載
    基于單片<b class='flag-5'>機(jī)</b>的極簡(jiǎn)圖形化<b class='flag-5'>狀態(tài)機(jī)</b><b class='flag-5'>框架</b>NorthFrame

    如何構(gòu)建基于狀態(tài)機(jī)的軟件系統(tǒng)

    模式(Design Pattern)。本文介紹如何構(gòu)建基于狀態(tài)機(jī)的軟件系統(tǒng),以及如何利用Linux工具
    的頭像 發(fā)表于 09-14 10:55 ?1500次閱讀

    分享一款狀態(tài)機(jī)自動(dòng)生成工具

    為實(shí)用的軟件系統(tǒng)編寫狀態(tài)機(jī)并不是一件十分輕松的事情,特別是當(dāng)狀態(tài)機(jī)本身比較復(fù)雜的時(shí)候尤其如此,許多有過類似經(jīng)歷的程序員往往將其形容為"毫無創(chuàng)意"的過程,因?yàn)樗麄冃枰獙⒋罅康臅r(shí)間與精力傾注在如何管理好狀態(tài)機(jī)中的各種
    的頭像 發(fā)表于 07-31 10:24 ?3067次閱讀
    分享一款<b class='flag-5'>狀態(tài)機(jī)</b><b class='flag-5'>自動(dòng)</b><b class='flag-5'>生成</b><b class='flag-5'>工具</b>

    狀態(tài)機(jī)自動(dòng)生成工具FSME

    狀態(tài)機(jī)中的各種狀態(tài)上,而不是程序本身的運(yùn)行邏輯。 作為一種通用的軟件設(shè)計(jì)模式,各種軟件系統(tǒng)的狀態(tài)機(jī)之間肯定會(huì)或多或少地存在著一些共性,因此人們開始嘗試開發(fā)一些工具
    的頭像 發(fā)表于 09-13 16:45 ?1401次閱讀
    <b class='flag-5'>狀態(tài)機(jī)</b><b class='flag-5'>自動(dòng)</b><b class='flag-5'>生成</b><b class='flag-5'>工具</b>FSME

    自動(dòng)生成程序狀態(tài)機(jī)代碼狀態(tài)機(jī)建模方法

    首先運(yùn)行fsme命令來啟動(dòng)狀態(tài)機(jī)編輯器,然后單擊工具欄上的“New”按鈕來創(chuàng)建一個(gè)新的狀態(tài)機(jī)。FSME中用于構(gòu)建狀態(tài)機(jī)的基本元素一共有五種:事件(Event)、輸入(Input)、輸出
    的頭像 發(fā)表于 09-13 16:50 ?1058次閱讀
    <b class='flag-5'>自動(dòng)</b><b class='flag-5'>生成</b>程序<b class='flag-5'>狀態(tài)機(jī)</b>代碼<b class='flag-5'>狀態(tài)機(jī)</b>建模方法

    如何生成狀態(tài)機(jī)框架

    生成狀態(tài)機(jī)框架 使用FSME不僅能夠進(jìn)行可視化的狀態(tài)機(jī)建模,更重要的是它還可以根據(jù)得到的模型自動(dòng)生成
    的頭像 發(fā)表于 09-13 16:54 ?926次閱讀
    如何<b class='flag-5'>生成</b><b class='flag-5'>狀態(tài)機(jī)</b><b class='flag-5'>框架</b>

    如何使用FSME來定制狀態(tài)機(jī)

    本身相關(guān)的那些處理邏輯。在FSME中,與具體應(yīng)用相關(guān)的操作稱為輸出(Output),它們實(shí)際上就是一些需要用戶給出具體實(shí)現(xiàn)的虛函數(shù),自動(dòng)生成狀態(tài)機(jī)引擎負(fù)責(zé)在進(jìn)入或者退出某個(gè)狀態(tài)時(shí)調(diào)用
    的頭像 發(fā)表于 09-13 16:57 ?1386次閱讀
    如何使用FSME來定制<b class='flag-5'>狀態(tài)機(jī)</b>