0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

分享一款状态机自动生成工具

strongerHuang 来源:strongerHuang 2023-07-31 10:24 次阅读

为实用的软件系统编写状态机并不是一件十分轻松的事情,特别是当状态机本身比较复杂的时候尤其如此,许多有过类似经历的程序员往往将其形容为"毫无创意"的过程,因为他们需要将大量的时间与精力倾注在如何管理好状态机中的各种状态上,而不是程序本身的运行逻辑。

作为一种通用的软件设计模式,各种软件系统的状态机之间肯定会或多或少地存在着一些共性,因此人们开始尝试开发一些工具来自动生成有限状态机的框架代码,而在Linux下就有一个挺不错的选择──FSME(Finite State Machine Editor)。

可视化的FSME

FSME是一个基于Qt的有限状态机工具,它能够让用户通过图形化的方式来对程序中所需要的状态机进行建模,并且还能够自动生成用C++或者Python实现的状态机框架代码。

下面就以下图中城门的状态机为例,来介绍如何利用FSME来自动生成程序中所需要的状态机代码。

控制城门的状态机

1状态机建模

首先运行fsme命令来启动状态机编辑器,然后单击工具栏上的"New"按钮来创建一个新的状态机。FSME中用于构建状态机的基本元素一共有五种:事件(Event)、输入(Input)、输出(Output)、状态(State)和转换(Transition),在界面左边的树形列表中可以找到其中的四种。

  • 状态建模

在FSME界面左边的树形列表中选择"States"项,然后按下键盘上的Insert键来插入一个新的状态,接着在右下方的"Name"文本框中输入状态的名称,再在右上方的绘图区域单击该状态所要放置的位置,一个新的状态就创建好了。用同样的办法可以添加状态机所需要的所有状态,如下图所示。

状态建模

  • 事件建模

在FSME界面左边的树形列表中选择"Events"项,然后按下键盘上的Insert键来添加一个新的事件,接着在右下方的"Name"文本框中输入事件的名称,再单击"Apply"按钮,一个新的事件就创建好了。用同样的办法可以添加状态机所需要的所有事件,如下图所示。

  • 转换建模

状态转换是整个建模过程中最重要的一个部分,它用来定义有限状态机中的一个状态是如何切换到另一个状态的。例如,当用来控制城门的状态机处于Opened状态时,如果此时有Close事件产生,那么状态机的当前状态将切换到Closed状态,这样一个完整的过程在状态机模型中可以用closeDoor这样一个转换来进行描述。

要在FSME中添加这样一个转换,首先需要在界面左边的树形列表中选择"States"下的"Opened"项,然后按下键盘上的Insert键来添加一个新的转换,接着在右下角的"Name"文本框中输入转换的名字"closeDoor",在"Condition"文本框中输入"Close"表明触发该转换的条件是事件Close的产生,在"Target"下拉框中选择"Closed"项表明该转换发生后状态机将被切换到Closed状态,最后再单击"Apply"按钮,一个新的状态转换关系就定义好了,如下图所示。用同样的办法可以添加状态机所需要的所有转换。

转换建模

2 生成状态机框架

使用FSME不仅能够进行可视化的状态机建模,更重要的是它还可以根据得到的模型自动生成用C++或者Python实现的状态机框架。首先在FSME界面左边的树形列表中选择"Root"项,然后在右下角的"Name"文本框中输入状态机的名字"DoorFSM",再从"Initial State"下拉列表中选择状态"Opened"作为状态机的初始化状态,如图6所示。

设置初始属性


在将状态机模型保存为door.fsm文件之后,使用下面的命令可以生成包含有状态机定义的头文件:


		
			[xiaowp@linuxgam code]$ fsmc door.fsm -d -o DoorFSM.h
进一步还可以生成包含有状态机实现的框架代码:

		
			[xiaowp@linuxgam code]$ fsmc door.fsm -d -impl DoorFSM.h -o DoorFSM.cpp
如果想对生成的状态机进行验证,只需要再手工编写一段用于测试的代码就可以了:

		

/* * TestFSM.cpp * 测试生成的状态机框架 */ #include "DoorFSM.h" int main() { DoorFSM door; door.A(DoorFSM::Close); door.A(DoorFSM::Lock); door.A(DoorFSM::Unlock); door.A(DoorFSM::Open); }


有限状态机是由事件来进行驱动的,在FSME生成的状态机框架代码中,方法A()可以被用来向状态机发送相应的事件,从而提供状态机正常运转所需要的"动力"。状态机负责在其内部维护一个事件队列,所有到达的事件都会先被放到事件队列中进行等候,从而能够保证它们将按照到达的先后顺序被依次处理。在处理每一个到达的事件时,状态机都会根据自己当前所处的状态,检查与该状态对应的转换条件是否已经被满足,如果满足的话则激活相应的状态转换过程。


使用下面的命令能够将生成的状态机框架和测试代码编译成一个可执行文件:

		

[xiaowp@linuxgam code]$ g++ DoorFSM.cpp TestFSM.cpp -o fsm

由于之前在用fsmc命令生成状态机代码时使用了-d选项,生成的状态机框架中会包含一定的调试信息,包括状态机中每次状态转换时的激活事件、转换前的状态、所经历的转换、转换后的状态等,如下所示:

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


3定制状态机

目前得到的状态机已经能够响应来自外部的各种事件,并适当地调整自己当前所处的状态,也就是说已经实现了状态机引擎的功能,接下来要做的就是根据应用的具体需求来进行定制,为状态机加入与软件系统本身相关的那些处理逻辑。在FSME中,与具体应用相关的操作称为输出(Output),它们实际上就是一些需要用户给出具体实现的虚函数,自动生成的状态机引擎负责在进入或者退出某个状态时调用它们。

仍然以控制城门的那个状态机为例,假设我们希望在进入每个状态时都添加一部分处理逻辑。首在FSME界面左边的树形列表选择"Outputs"项,然后按下键盘上的Insert键来添加一个新的输出,接着在右下方的"Name"文本框中输入相应的名称,再单击"Apply"按钮,一个新的输出就创建好了,如图所示。用同样的办法可以添加状态机所需要的所有输出。

添加输出

当所有的输出都定义好之后,接下来就可以为状态机中的每个状态绑定相应的输出。首先在FSME界面左侧的"States"项中选择相应的状态,然后从右下角的"Available"列表框中选择与该状态对应的输出,再单击"<"按钮将其添加到"In"列表中,如图所示。用同样的办法可以为状态机中的所有状态设置相应的输出,同一个状态可以对应有多个输出,其中In列表中的输出会在进入该状态时被调用,而Out列表中的输出则会在退出该状态时被调用,输出调用的顺序是与其在In或者Out列表中的顺序相一致的。

图为状态设置输出

由于对状态机模型进行了修改,我们需要再次生成状态机的框架代码,不过这次不需要加上-d参数


			
				[xiaowp@linuxgam code]$ fsmc door.fsm -o DoorFSM.h [xiaowp@linuxgam code]$ fsmc door.fsm -d -impl DoorFSM.h -o DoorFSM.cpp

我们在新的状态机模型中添加了enterOpend、enterClosed、enterLocked和enterUnlocked四个输出,因此生成的类DoorFSM中会包含如下几个纯虚函数:

			
				virtual void enterOpened() = 0; virtual void enterLocked() = 0; virtual void enterUnlocked() = 0; virtual void enterClosed() = 0;

显然,此时生成的状态机框架不能够再被直接编译了,我们必须从类DoorFSM派生出一个子类,并提供对这几个纯虚函数的具体实现:

			
				/* * DoorFSMLogic.h * 状态机控制逻辑的头文件 */ #include "DoorFSM.h" class DoorFSMLogic : public DoorFSM { protected: virtual void enterOpened(); virtual void enterLocked(); virtual void enterUnlocked(); virtual void enterClosed(); };

正如前面所提到过的,这几个函数实际上代表的正是应用系统的处理逻辑,作为例子我们只是简单地输出一些提示信息:


			
				/* * DoorFSMLogic.cpp * 状态机控制逻辑的实现文件 */ #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; }

同样,为了对生成的状态机进行验证,我们还需要手工编写一段测试代码:

			
				/* * TestFSM.cpp * 测试状态机逻辑 */ #include "DoorFSMLogic.h" int main() { DoorFSMLogic door; door.A(DoorFSM::Close); door.A(DoorFSM::Lock); door.A(DoorFSM::Unlock); door.A(DoorFSM::Open); }

使用下面的命令能够将生成的状态机框架和测试代码编译成一个可执行文件:

			
				[xiaowp@linuxgam code]$ g++ DoorFSM.cpp DoorFSMLogic.cpp TestLogic.cpp -o logic

运行结果如下所示:

			
				[xiaowp@linuxgam code]$ ./logic Enter Closed state. Enter Locked state. Enter Unlocked state. Enter Opened state.
				
审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    10990

    浏览量

    206738
  • 状态机
    +关注

    关注

    2

    文章

    486

    浏览量

    27182
  • 软件系统
    +关注

    关注

    0

    文章

    52

    浏览量

    9444

原文标题:一款状态机自动生成工具

文章出处:【微信号:strongerHuang,微信公众号:strongerHuang】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    如何利用Linux下的工具自动生成实用的状态机框架?

    (Finite State Machine),是一种应用非常广泛的软件设计模式(Design Pattern)。本文介绍如何构建基于状态机的软件系统,以及如何利用Linux下的工具自动
    的头像 发表于 11-25 14:15 722次阅读
    如何利用Linux下的<b class='flag-5'>工具</b>来<b class='flag-5'>自动</b><b class='flag-5'>生成</b>实用的<b class='flag-5'>状态机</b>框架?

    SaberRD状态机建模工具介绍(一)什么是状态机建模

    状态机建模是使用状态图和方程式的手段,创建基于混合信号的有限状态机模型的一种建模工具
    的头像 发表于 12-05 09:51 534次阅读
    SaberRD<b class='flag-5'>状态机</b>建模<b class='flag-5'>工具</b>介绍(一)什么是<b class='flag-5'>状态机</b>建模

    状态机

    控制状态机控制状态机的初始化和状态转换的最佳方法是使用枚丽型输入控件。般使用自定义类型的枚丽变量。使用子定义类型的枚丽变量可以是控件和实例乊间存在关联,使得添加或删除
    发表于 02-13 12:39

    LV 状态机工具条 8.x

    LV 状态机工具条 8.x
    发表于 07-08 10:48

    状态机如何暂停

    程序运行 就开始自动运行程序 状态机各种各种状态开始执行 我这里是布尔变量 每秒点亮个布尔
    发表于 04-09 09:23

    推荐一款:【灵生】单片代码自动生成器(自动编程工具)

    推荐一款:【灵生】单片代码自动生成器(自动编程工具)以往编写单片
    发表于 12-21 16:53

    什么是状态机状态机是如何编程的?

    什么是状态机状态机是如何编程的?
    发表于 10-20 07:43

    状态机代码生成工具

    状态机代码生成工具状态机代码生成工具状态机代码
    发表于 11-19 15:12 9次下载

    使用ModelSim自动生成状态机FSM的状态转换图

    HDL代码设计中重要的内容之一就是设计程序的状态机FSM,状态转换控制着整个程序的流程,为了理解程序,我们经常需要把状态机状态转换图画出来,这样看起来很直观,但是,有没有办法
    发表于 02-10 15:39 1.5w次阅读
    使用ModelSim<b class='flag-5'>自动</b><b class='flag-5'>生成</b><b class='flag-5'>状态机</b>FSM的<b class='flag-5'>状态</b>转换图

    有限状态机设计是HDL Designer Series的关键应用

    有限状态机的设计是HDL Designer Series™工具的关键应用。 尽可能地对于设计人员编写导致状态机性能不佳的VHDL,可以使用HDL Designer用于生成VHDL的Se
    发表于 04-08 10:05 3次下载

    如何构建基于状态机的软件系统

    模式(Design Pattern)。本文介绍如何构建基于状态机的软件系统,以及如何利用Linux下的工具自动生成实用的状态机框架。
    的头像 发表于 09-14 10:55 1289次阅读

    状态机自动生成工具FSME

    状态机中的各种状态上,而不是程序本身的运行逻辑。 作为一种通用的软件设计模式,各种软件系统的状态机之间肯定会或多或少地存在着一些共性,因此人们开始尝试开发一些工具
    的头像 发表于 09-13 16:45 1079次阅读
    <b class='flag-5'>状态机</b><b class='flag-5'>自动</b><b class='flag-5'>生成</b><b class='flag-5'>工具</b>FSME

    自动生成程序状态机代码状态机建模方法

    首先运行fsme命令来启动状态机编辑器,然后单击工具栏上的“New”按钮来创建一个新的状态机。FSME中用于构建状态机的基本元素一共有五种:事件(Event)、输入(Input)、输出
    的头像 发表于 09-13 16:50 733次阅读
    <b class='flag-5'>自动</b><b class='flag-5'>生成</b>程序<b class='flag-5'>状态机</b>代码<b class='flag-5'>状态机</b>建模方法

    如何生成状态机框架

    生成状态机框架 使用FSME不仅能够进行可视化的状态机建模,更重要的是它还可以根据得到的模型自动生成用C++或者Python实现的
    的头像 发表于 09-13 16:54 652次阅读
    如何<b class='flag-5'>生成</b><b class='flag-5'>状态机</b>框架

    如何使用FSME来定制状态机

    本身相关的那些处理逻辑。在FSME中,与具体应用相关的操作称为输出(Output),它们实际上就是一些需要用户给出具体实现的虚函数,自动生成状态机引擎负责在进入或者退出某个状态时调用
    的头像 发表于 09-13 16:57 880次阅读
    如何使用FSME来定制<b class='flag-5'>状态机</b>