LwEVT 入门:注册回调,dispatch 广播事件
声明: LwEVT 是一个开源项目,作者为 Tilen MAJERLE。本文是阅读该项目源码和文档后整理的入门笔记。本文作者不是该项目的开发者,未参与该项目的任何代码贡献。 示例代码已在本机 GCC 与 ARM GCC 下编译运行验证。
这篇文章帮你完成一件事:把 LwEVT 跑起来,实现"按键按下发一个事件、温度采集完发一个带数据的事件"。全程只用 5 个 API,不需要理解内部实现。
LwEVT 的调用流程
LwEVT 是事件分发器:事件(event)由类型 type 区分,监听器(listener)就是普通回调函数。核心动作只有两个:
LwEVT_register()注册回调,可注册多个,最多LwEVT_CFG_MAX_EVT_LISTENERS个(默认 8)LwEVT_dispatch()广播事件给所有已注册回调,逐个调用
示例代码:按键与温度事件
先建两个文件:LwEVT_opts.h(配置)和 LwEVT_types.h(事件类型),从仓库的 LwEVT_opts_template.h、LwEVT_types_template.h 复制改名即可。
LwEVT_types.h 定义事件类型。LwEVT_TYPE_BASIC 定义不带数据的事件,LwEVT_TYPE_EXT 定义带数据的事件,数据声明成 C 结构体:
LwEVT_TYPE_BASIC(LwEVT_TYPE_BTN_PRESSED)
LwEVT_TYPE_BASIC(LwEVT_TYPE_BTN_RELEASED)
LwEVT_TYPE_EXT(LwEVT_TYPE_TEMP_READY, struct { int16_t temp_x10; } temp)main.c 完整流程:
#include "LwEVT/LwEVT.h"
#include <stdint.h>
static uint32_t btn_press_count;
/* 监听器 1:按键计数 + 温度判断 */
static void on_event(LwEVT_t *evt)
{
switch (evt->type) {
case LwEVT_TYPE_BTN_PRESSED:
btn_press_count++;
break;
case LwEVT_TYPE_TEMP_READY:
/* 零拷贝:直接读句柄 union 里的数据 */
if (evt->msg.temp.temp_x10 > 300) {
/* 超过 30.0 °C */
}
break;
default:
break;
}
}
/* 监听器 2:只关心温度,独立记录 */
static void on_temp_log(LwEVT_t *evt)
{
if (evt->type == LwEVT_TYPE_TEMP_READY) {
/* 把温度写入日志缓冲区 */
}
}
int main(void)
{
LwEVT_t *evt;
LwEVT_init(); /* 1. 初始化 */
LwEVT_register(on_event); /* 2. 注册监听器 1 */
LwEVT_register(on_temp_log); /* 3. 注册监听器 2 */
/* 4. 无数据事件:直接 dispatch */
LwEVT_dispatch(LwEVT_TYPE_BTN_PRESSED);
/* 5. 带数据事件:先拿句柄写数据,再 dispatch */
evt = LwEVT_get_handle();
evt->msg.temp.temp_x10 = 315;
LwEVT_dispatch(LwEVT_TYPE_TEMP_READY);
return 0;
}运行输出(验证版加 printf):
button pressed, count=1
temp=31.5 C
over 30.0 C
temp logged=315关键点:dispatch 是广播,所有已注册监听器都会收到每个事件(上例两个监听器各处理一次);监听器自己判断关心哪种事件(用 switch 或 if)。注册顺序就是调用顺序,同一函数指针重复注册会被去重。
LwEVT_opts.h 配置项
LwEVT_CFG_MAX_EVT_LISTENERS:监听器上限,默认 8LwEVT_CFG_ENABLE_DEFAULT_HANDLE:默认句柄开关,默认 1;置 0 时改用LwEVT_dispatch_ex(&evt, type)传自己的句柄
LwEVT 的特色
- 极小:库代码约 170 B(Cortex-M4,-Os),静态 RAM 48 B
- X-macro 类型系统:事件类型和携带数据在编译期生成,改类型只动
LwEVT_types.h - 零拷贝:监听器直接读写句柄里的数据
- API 只有 5 个函数,注册自动去重
适用边界
- 全局单例:整个程序只有一套监听表,无法创建多个独立的事件系统
- 无法退订:注册后不能移除回调
- 无队列:dispatch 同步执行全部回调,在中断里调用时回调也在中断上下文运行