# active **Repository Path**: Ethan-ZYS/active ## Basic Information - **Project Name**: active - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: baremetal_dev - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2025-05-21 - **Last Updated**: 2025-05-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 使用方法 ## 方法一 克隆仓库 ``` git clone -b https://gitee.com/Ethan-ZYS/active.git https://gitee.com/Ethan-ZYS/active.git ``` 在CMakeLists.txt下 add_subdirectory(active) ## 方法二 使用CPM,在CMakeLists.txt下 ``` cpmaddpackage(https://gitee.com/Ethan-ZYS/active.git#https://gitee.com/Ethan-ZYS/active.git) ``` # 示例代码 ```c++ #include "active/active_errors.hpp" // 包含错误相关的定义和功能​ #include "active/active_initializer.hpp" // 包含状态机初始化相关的定义和功能​ #include "fmt_log/fmt_log.hpp" // 包含日志输出相关的功能​ ​ // 定义事件类型e1,该事件不携带任何数据​ ATV_EVENT_TYPE_DEF(e1);​ // 定义事件类型e3,同样不携带数据​ ATV_EVENT_TYPE_DEF(e3);​ ​ // 定义事件类型e2,该事件携带一个int类型的数据​ ATV_EVENT_TYPE_DEF(e2, int);​ ​ // 定义状态机S1的结构体​ struct S1 {​ // 重载括号运算符,使其可调用,返回状态转换表​ auto operator()() {​ // 使用atv命名空间及其子命名空间sml,方便后续使用相关类型和函数​ using namespace atv;​ using namespace atv::sml;​ // 定义一个匿名函数f1,用于处理事件e1触发时的操作​ auto f1 = []() -> void {​ // 定义一个名为test的事件(值定义方式,无名字空间)​ ATV_EVT(test);​ // 发布test事件,通知状态机有该事件发生​ atv::Publish(test);​ };​ // clang-format off用于关闭代码格式化,方便直观展示状态转换表结构​ // clang-format on用于重新开启代码格式化​ // 定义状态转换表,描述状态机S1的状态转换规则​ return make_transition_table(​ // 当状态为"s1"且接收到事件e1时,执行f1函数,转换到状态"s2"​ *"s1"_s + event / f1 = "s2"_s,​ // 当状态为"s1"且接收到事件e3时,延迟处理该事件​ "s1"_s + event / defer,​ // 当状态为"s2"且接收到事件e3时,执行匿名函数,打印"f2 action",并转换回状态"s1"​ "s2"_s + event / []{FMT_PRINTLN("f2 action");} = "s1"_s​ );​ }​ };​ ​ // 定义状态机S2的结构体​ struct S2 {​ // 重载括号运算符,返回状态转换表​ auto operator()() {​ // 使用atv命名空间及其子命名空间sml​ using namespace atv;​ using namespace atv::sml;​ // 定义匿名函数f1,当事件触发时打印"f1 action"​ auto f1 = []() { FMT_PRINTLN("f1 action"); };​ // 定义匿名函数f2,用于处理携带数据的事件,提取并打印数据​ auto f2 = [](auto e) {​ auto [data] = e();​ FMT_PRINTLN("f2 action");​ };​ // 定义名为test的事件​ ATV_EVT(test);​ // 定义名为err2的错误事件,携带一个int类型的数据​ ATV_ERR(err2, int);​ // 定义状态转换表,描述状态机S2的状态转换规则​ return make_transition_table(​ // 任何状态下接收到test事件时,执行空操作​ any + test / [] {},​ // 任何状态下接收到"err1"_err错误事件时,打印错误名称​ any + "err1"_err / [](const auto& err) {FMT_PRINTLN("{}", err.Name());},​ // 任何状态下接收到err2错误事件时,提取并打印错误名称和携带的数据​ any + err2 / [](const auto& err) {​ auto [data] = err(); ​ FMT_PRINTLN("{} {}", err.Name(), data);},​ // 当状态为"s1"且接收到事件e1时,执行f1函数,转换到状态"s2"​ *"s1"_s + event / f1 = "s2"_s,​ // 当进入状态"s1"时,执行空操作​ "s1"_s + on_entry<_> / []{},​ // 当状态为"s2"且接收到事件e2时,执行f2函数,转换到状态"s1"​ "s2"_s + event / f2 = "s1"_s​ );​ }​ };​ ​ // 定义状态机S3的结构体​ struct S3 {​ // 重载括号运算符,返回状态转换表​ auto operator()() {​ using namespace atv::sml;​ // 定义匿名函数f1,目前为空操作​ auto f1 = []() {};​ // 定义匿名函数f2,用于处理携带数据的事件,提取并打印数据和事件名称​ auto f2 = [](auto e) {​ auto [data] = e();​ FMT_PRINTLN("{} {}", data, e.Name());​ };​ // 定义状态转换表,描述状态机S3的状态转换规则​ return make_transition_table(​ // 当状态为"s1"且接收到事件e1时,执行f1函数,转换到状态"s2"​ *"s1"_s + event / f1 = "s2"_s,​ // 当状态为"s2"且接收到事件e2时,执行f2函数,转换到状态"s1"​ "s2"_s + event / f2 = "s1"_s​ );​ }​ };​ ​ // 定义状态机S4的结构体​ struct S4 {​ // 定义类型别名Self,方便后续引用自身类型​ using Self = S4;​ // 定义成员函数action1,目前为空操作​ auto action1() {};​ // 定义成员函数action2,用于处理携带数据的事件,提取数据​ auto action2(auto e) { auto [data] = e(); };​ // 重载括号运算符,返回状态转换表​ auto operator()() {​ using namespace atv::sml;​ // 定义匿名函数f1,目前为空操作​ auto f1 = []() {};​ // 定义匿名函数f2,用于处理携带数据的事件,提取数据​ auto f2 = [](auto e) { auto [data] = e(); };​ // 定义状态转换表,描述状态机S4的状态转换规则​ return make_transition_table(​ // 当状态为"s1"且接收到事件e1时,执行f1函数,转换到状态"s2"​ *"s1"_s + event / f1 = "s2"_s,​ // 当状态为"s2"且接收到事件e2时,执行f2函数,转换到状态"s1"​ "s2"_s + event / f2 = "s1"_s​ );​ }​ };​ ​ // 定义状态机S5的结构体​ struct S5 {​ // 定义日志模块名称为"S5",用于标识该状态机相关的日志信息​ LOG_MODULE(S5);​ // 重载括号运算符,返回状态转换表​ auto operator()() {​ using namespace atv::sml;​ // 定义匿名函数f1,目前为空操作​ auto f1 = []() {};​ // 定义匿名函数f2,用于处理携带数据的事件,提取数据并记录日志信息​ auto f2 = [](auto e) {​ auto [data] = e();​ LOG_INFO("{}", data);​ };​ // 定义状态转换表,描述状态机S5的状态转换规则​ return make_transition_table(​ // 当状态为"s1"且接收到事件e1时,执行f1函数,转换到状态"s2"​ *"s1"_s + event / f1 = "s2"_s,​ // 当状态为"s2"且接收到事件e2时,执行f2函数,转换到状态"s1"​ "s2"_s + event / f2 = "s1"_s​ );​ }​ };​ ​ // 定义错误监听器结构体Listener​ struct Listener {​ // 定义日志模块名称为"error listener",用于标识错误监听器相关的日志信息​ LOG_MODULE(error listener);​ // 重载括号运算符,返回状态转换表​ auto operator()() {​ using namespace atv::sml;​ // 定义状态转换表,当处于"listening"状态且接收到意外事件时,打印错误名称​ return make_transition_table(*"listening"_s +​ unexpected_event<_> / [](const auto &e) {​ LOG_ERROR("{}", atv::ErrName(e));​ });​ }​ };​ ​ // 定义错误监听器,使Listener结构体能够作为错误监听器使用​ ERR_LISTENER_DEFINE(Listener);​ ​ // 定义一个匿名命名空间,用于隐藏该命名空间内的符号,防止命名冲突​ namespace {​ // 定义日志模块名称为"MAIN",用于标识主程序相关的日志信息​ LOG_MODULE("MAIN");​ }​ ​ // 主函数,程序入口​ int main() {​ // 使用atv命名空间​ using namespace atv;​ // 初始化状态机系统,配置多个状态机​ atv::Initialize(​ // 配置状态机S1,启用日志记录、线程安全模式,并设置可延迟处理的事件队列大小为10​ atv::Config(atv::logging, atv::threadsafe, atv::deferable<10>),​ // 配置状态机S2,启用日志记录​ atv::Config(atv::logging),​ // 配置状态机S3,使用默认配置​ atv::Config());​ // 发布事件e3​ e3::Publish();​ // 发布事件e1​ e1::Publish();​ // 发布错误事件"err1"_err​ atv::Publish("err1"_err);​ // 定义错误事件err2,携带一个int类型的数据​ ATV_ERR(err2, int);​ // 发布错误事件err2,并传递数据999​ atv::Publish(err2, 999);​ return 0;​ } ``` # ATV状态机使用文档 ## 一、引言 本文档详细介绍ATV状态机的使用方法,涵盖事件定义、发布,状态机配置等核心功能,帮助开发者快速掌握并应用该状态机框架。 ## 二、使用方法 ### 2.1 定义事件 #### 2.1.1 类型定义 使用`ACTIVE_EVENT_TYPE_DEF`宏定义事件类型,第一个参数为事件类型名称,后续参数为事件携带的数据类型。该方式具备名字空间特性,同名事件在不同名字空间下为不同类型。 ```c++ // 定义无参数事件类型e1 ATV_EVENT_TYPE_DEF(e1); // 定义携带float和int类型数据的事件类型e2 ATV_EVENT_TYPE_DEF(e2, float, int); namespace n1 { ATV_EVENT_TYPE_DEF(e1); } namespace n2 { ATV_EVENT_TYPE_DEF(e1); } // 由于在不同名字空间,n1::e1和n2::e1是不同类型 static_assert(not std::is_same_v); ``` #### 2.1.2 值定义 `ATV_EVT`宏用于定义无名字空间的事件,无需前置声明即可在不同源文件间传递事件。 ```c++ // 在foo1.cpp中 void foo1(void) { ATV_EVT(e1); atv::Publish(e1); } // 在foo2.cpp中 struct sm { using namespace atv::sml; auto operator()() { ATV_EVT(e2); // 无需前置声明即可使用 return make_transition_table( *"idle"_s + e2 /[](const auto& e){FMT_PRINTLN("{}", e.Name())} ); } }; ``` #### 2.1.3 定义错误类型事件 可通过字面量或`ATV_ERR`宏定义错误类型事件,前者无法指定数据类型,后者可以。 ```c++ "error_name"_err; // 字面量定义,无数据类型 ATV_ERR(error_name, int, float, const char*); // 可指定int、float、const char*类型数据 ``` ### 2.2 发布事件 有两种发布事件方式,一是使用事件类型的静态成员函数`Publish`,二是通过`atv::Publish`函数。 ```c++ // 定义携带int和float数据的EventType事件类型 ACTIVE_EVENT_TYPE_DEF(EventType, int, float); // 使用静态成员函数发布事件,参数类型需与定义一致 EventType::Publish(3, 3.14); ATV_EVT(e1); e1.Publish(); "err"_err; atv::Publish("err"_err); ``` ### 2.3 状态机配置 状态机分为缓存类和监听处理类,还可指定优先级。缓存类会将发布的事件存入队列统一处理;监听处理类则在事件发布时立即处理,适用于紧急事件。同时,可通过配置项实现线程安全、日志记录等功能。 ```c++ struct S1 { auto operator()() { using namespace atv; using namespace atv::sml; auto f1 = []() -> void { ATV_EVT(test); atv::Publish(test); }; // 状态机转换表定义,s1状态接收到e1事件执行f1函数后转换到s2状态等 return make_transition_table( *"s1"_s + event / f1 = "s2"_s, "s1"_s + event / defer, "s2"_s + event / []{FMT_PRINTLN("f2 action");} = "s1"_s ); } }; struct S2 { auto operator()() { using namespace atv; using namespace atv::sml; auto f1 = []() { FMT_PRINTLN("f1 action"); }; auto f2 = [](auto e) { auto [data] = e(); FMT_PRINTLN("f2 action"); }; ATV_EVT(test); ATV_ERR(err2, int); return make_transition_table( any + test / [] {}, any + "err1"_err / [](const auto& err) {FMT_PRINTLN("{}", err.Name());}, any + err2 / [](const auto& err) { auto [data] = err(); FMT_PRINTLN("{} {}", err.Name(), data);}, *"s1"_s + event / f1 = "s2"_s, "s1"_s + on_entry<_> / []{}, "s2"_s + event / f2 = "s1"_s ); } }; struct S3 { auto operator()() { using namespace atv; using namespace atv::sml; auto f1 = []() -> void { ATV_EVT(test); atv::Publish(test); }; return make_transition_table( *"s1"_s + event / f1 = "s2"_s, "s1"_s + event / defer, "s2"_s + event / []{FMT_PRINTLN("f2 action");} = "s1"_s ); } }; int main() { atv::Initialize( atv::Config(), // 立即处理,默认监听处理类 atv::Config(10_size), // 指定缓存大小为10,切换为缓存处理类 atv::Config(10_size, 1_prio) // 缓存大小10,优先级为1,缓存处理类且优先调度 ); e3::Publish(); e1::Publish(); atv::Publish("err1"_err); ATV_ERR(err2, int); atv::Publish(err2, 999); return 0; } ``` ### 2.4 其他配置项 可在`atv::Config`中添加不同配置项,实现线程安全、日志记录、事件延后处理等功能。 ```c++ int main() { atv::Initialize( atv::Config(atv::threadsafe), // 线程安全,状态机执行原子操作 atv::Config(atv::logging), // 记录状态机执行信息,便于调试 atv::Config(atv::logging, atv::deferable<10>) // 日志记录,事件延后处理,缓存大小为10 ); return 0; } ```