scxml-3

网友投稿 582 2022-09-04

scxml-3

scxml-3

编译源码:

预先安装如下:

sudo apt-get

autorevision用于更新scxml的版本;

xsltproc用于编译单元测试;

编译:

mkdir buildcd buildcmake ..make -j4make install

To help with auto-generating state-machines in cmake projects, an scxml_generator.cmake module is installed. The examples demonstrate how this can be used.

To build unit tests, and examples run cmake with

mkdir buildcd buildcmake -DDEVELOPER=1 ..make -j4make test

下面看一下例子:

第一个Hello World:

先看图

是一个由一个无条件转移相连接的两个状态组成;

上面的图是由这里的软件来实现的:-jar **.jar (在windows下执行,**.jar为​​initial="hello" version="0.9" xmlns="

然后通过上面编译的scxmlcc来将.scxml生成.h文件

scxmlcc -o hello_world.h hello_world.scxml

自定义的行为可以用c++代码来实现,例如在进入和退出的时候的一些动作:

#include "hello_world.h"#include using namespace std;typedef sc_hello_world sc;template<> void sc::state_actions::enter(sc::data_model &m){ cout << "hello" << endl; }template<> void sc::state_actions::enter(sc::data_model &m){ cout << "world" << endl; }int main(int argc, char *argv[]){ sc sc0; sc.init(); return 0;}

执行之后,会输出如下:

helloworld

init方法初始化整个状态机并进入到它的初始状态;

第二个例子:

Timer Switch:实现了一个简单的定时器表

其大意是,该表可以通过发送一个button事件到状态机来在on或者off之间切换。在on状态的时候,当定时截止之后,会进入到off状态。

在on状态中,一个timer事件来计数timer的值。unconditional事件从on到off需要一个条件,因此只有当timer>=5之后,才会被执行,最后off状态会把counter置为0;

虚点的timer转移意味着,其是一个无目标的转移。意味着在on状态的enter和exit行为都不会被执行当timer事件发生的时候。行为的实现如下:

template<> void sc::state_actions::enter(sc::data_model &m){ cout << "on" << endl; }template<> void sc::state_actions::enter(sc::data_model &m){ cout << "off" << endl; m.user->timer = 0;}template<> bool sc::transition_actions<&sc::state::unconditional, sc::state_on, sc::state_off>::condition(sc::data_model &m){ return m.user->timer >= 5;}template<> void sc::transition_actions<&sc::state::event_timer, sc::state_on>::enter(sc::data_model &m){ ++m.user->timer;}

struct sc::user_model { int timer;};

自定义的数据模型被构造之后,然后传递到状态机的构造函数中:

sc::user_model m;sc sc(&m);sc.init();

完整代码如下:

timer_switch.cpp

/************************************************************************* ** Copyright (C) 2013 Jan Pedersen ** ** This program is free software: you can redistribute it and/or modify ** 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. ** ** This program 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 General Public License ** along with this program. If not, see <*************************************************************************/#include "timer_switch.h"#include "termio.h"#include using namespace std;typedef sc_timer_switch sc;struct sc::user_model { int timer;};template<> void sc::state_actions::enter(sc::data_model &m){ cout << "on" << endl; }template<> void sc::state_actions::enter(sc::data_model &m){ cout << "off" << endl; m.user->timer = 0;}template<> bool sc::transition_actions<&sc::state::unconditional, sc::state_on, sc::state_off>::condition(sc::data_model &m){ cout << "unconditional: timer is " <timer << endl; return m.user->timer >= 5;}template<> void sc::transition_actions<&sc::state::event_timer, sc::state_on>::enter(sc::data_model &m){ ++m.user->timer; cout << "timer is " <timer <> c; cout << "c is " << c << endl; sc::event e = NULL; switch (c) { case 'b': e = &sc::state::event_button; break; case 't': e = &sc::state::event_timer; break; case 'q': return 0; default: continue;//e = &sc::state::unconditional; } sc.dispatch(e); } return 0;}

View Code

timer_switch.h

// This file is automatically generated by scxmlcc (version 0.9M-2)// For more information, see __SC_TIMER_SWITCH#define __SC_TIMER_SWITCH#include #include #include class sc_timer_switch{ public: struct data_model; struct user_model; class state { public: virtual ~state(){} virtual state* event_button(sc_timer_switch&) { return 0; } virtual state* event_timer(sc_timer_switch&) { return 0; } virtual state* unconditional(sc_timer_switch&) { return 0; } virtual state* initial(sc_timer_switch&) { return 0; } template void enter(data_model&, ...) {} template void exit(data_model&, ...) {} virtual bool in(const void*) { return false; } }; typedef state* (state::*event)(sc_timer_switch&); template class state_actions { protected: void enter(data_model&) {} // default enter action void exit(data_model&) {} // default exit action }; template class composite : public P, public state_actions { virtual state* initial(sc_timer_switch&) { return 0; } public: typedef P parent_t; // LCA calculation template void enter(data_model&, composite*) {} template void enter(data_model &m, ...) { P::template enter(m, static_cast(nullptr)); state_actions::enter(m); } template void exit(data_model&, composite*) {} template void exit(data_model &m, ...) { state_actions::exit(m); P::template exit(m, static_cast(nullptr)); } static const void* id() { static const struct{} _id; return &_id; } bool in(const void *si) { return (si == id() || P::in(si)); } }; class no_state {}; enum transition_type { external, internal }; template class transition_actions { protected: void enter(data_model&) {} // default enter action bool condition(data_model&) { return true; } // default condition action }; // external/internal transition template class transition : public transition_actions { template struct id { }; void state_enter(D* d, data_model &m, id, S*) { d->template enter >(m); } // internal transition, where dst is descendant of src void state_enter(D* d, data_model &m, ...) { d->template enter(m); } // external transition, or dst is not descendant of src void state_exit(S*, data_model &, id, S*) {} // internal transition, where dst is descendant of src void state_exit(S* s, data_model &m, ...) { s->template exit(m); } // external transition, or dst is not descendant of src public: state* operator ()(S *s, sc_timer_switch &sc) { if(!transition_actions::condition(sc.model)) return 0; D *d = sc.get_state(); state_exit(s, sc.model, id(), static_cast(nullptr)); transition_actions::enter(sc.model); state_enter(d, sc.model, id(), static_cast(nullptr)); return d; } }; // transition with no target template class transition : public transition_actions { public: state* operator ()(S *s, sc_timer_switch &sc) { if(!transition_actions::condition(sc.model)) return 0; transition_actions::enter(sc.model); return s; } }; private: bool dispatch_event(event e) { state *next_state; if ((next_state = (model.cur_state->*e)(*this))) model.cur_state = next_state; return !!next_state; } public: void dispatch(event e = &state::unconditional) { bool cont = dispatch_event(e) || dispatch_event(&state::unconditional); while (cont) { if ((cont = dispatch_event(&state::initial))); else if ((cont = dispatch_event(&state::unconditional))); else if (model.event_queue.size()) cont = dispatch_event(model.event_queue.front()), model.event_queue.pop_front(), cont |= !model.event_queue.empty(); else break; } } struct data_model { std::deque event_queue; state *cur_state; template bool In() { return cur_state->in(S::id()); } user_model *user; const std::string _sessionid; const std::string _name; data_model(user_model* um) : user(um) , _sessionid(std::to_string(reinterpret_cast(this))) , _name("timer_switch") {} } model; sc_timer_switch(user_model *user = nullptr) : model(user) { model.cur_state = get_state(); } void init() { dispatch(&state::initial); } struct scxml : public composite { state* initial(sc_timer_switch&sc) { return transition<&state::initial, scxml, state_off, internal>()(this, sc); } }; struct state_off : public composite { state* event_button(sc_timer_switch &sc) { return transition<&state::event_button, state_off, state_on>()(this, sc); } }; struct state_on : public composite { state* event_button(sc_timer_switch &sc) { return transition<&state::event_button, state_on, state_off>()(this, sc); } state* event_timer(sc_timer_switch &sc) { return transition<&state::event_timer, state_on>()(this, sc); } state* unconditional(sc_timer_switch &sc) { return transition<&state::unconditional, state_on, state_off>()(this, sc); } }; template T* get_state() { static T t; return &t; }};#endif

View Code

第三个例子:

售卖机器:

本售卖机器可以分配三种类型的coke,在用于插入货币到机器之后。如下图所示:

状态机负责整个逻辑;

Coin Sensor负责检测货币的插入;

keypad负责检测按键的按下;

Display负责显示文本消息;

Coin refund负责退换硬币给用户;

Dispenser负责分配三种不同类型的coke给用户;

Input simulator负责从你的PC的键盘中读取输入,并触发货币传感器和键盘pad以便仿真。

不同组件之间的通信是通过signaling机制;其目的是为了解耦模块之间的依赖;因此单独的模块不知道彼此;

状态机的实现如下所示:

在初始化之后,状态机会进入到collect_coins状态;然后等待货币的插入;当货币插入之后,一个在用户模型user_model中的变量credit通过事件N和D来递增。当zero,coke或者diet按钮在机器上被按下时,对应的事件zero,coke或者diet被触发。这三个transitions到状态dispense_*状态,有一个条件就是credit必须是大于等于对应的coke的价格。如果条件满足,状态机会转移到状态dispense_*state,对应的coke就会被分配,对应的credit会减少。这三个dispense状态是最后的状态,因此他们会触发一个done,状态机会转移到coin_return状态。当在active状态时,如果cancel按钮被按下,对应的cancel事件被触发,状态机也会转移到状态coin_return.

在coin_return状态中,状态机会进入到return_d状态。这个状态有两个条件转移。当credit的值小于一角硬币时,会进入到状态return_n,当credit的值大于等于dime时,这个转移会触发coin refund组件来退换一个dime。并返回到return_d,return_n状态类似;当credi为0时,return_done状态进入,且是最后的状态,会触发一个done事件,状态机会退回到init状态。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:github 与gitlab之间的工程创建
下一篇:Api接口设计注意事项(怎么写api接口)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~