理解LuatOS的事件消息系统:从机制到编码实现

LuatOS通过事件消息系统实现了对硬件事件的高效捕捉与处理,例如短信到达时推送“SMS_INC”消息。开发者可通过sys.waitUntil进行监听,实现事件驱动的程序逻辑。本文将系统阐述其原理与使用技巧。

LuatOS 的消息机制是其多任务协作和事件驱动编程的核心部分,主要通过 sys 核心库实现。

消息机制包括消息的发送、接收、订阅,以及系统消息的定义和使用,下面分别详细描述其原理和使用方法。

一、LuatOS 消息机制的原理

1.1 消息机制的基本原理描述

LuatOS 基于消息队列实现任务间通信,消息队列遵循先进先出(FIFO)原则。

消息机制配合 Lua 的协程(coroutine),可以非常丝滑的实现协作式多任务。

每一个协程的运行,是相互逻辑独立的;

在协程之间收发消息,可以实现不同协程间的通信。

消息发布者调用 LuatOS 的 API 发送全局消息或者定向消息。

订阅者通过回调函数或协程等待消息并处理,实现异步事件驱动。

消息调度流程大致如下:

(1)发布消息时,将消息及参数插入消息队列。

(2)消息分发函数从队列取出消息,根据消息 ID 查找订阅者列表。

(3)调用订阅者的回调函数或恢复协程,传递消息参数。

(4)订阅者处理消息,实现任务间通信和事件响应。

这种设计使得任务间解耦,消息驱动程序结构清晰,适合物联网设备的异步事件处理需求。

1.2 LuatOS 的消息队列

LuatOS 的消息队列有两个: 用户消息队列和系统消息队列。

1.2.1 用户消息队列:

carbon (27)

用户消息队列的接收接口有三个: sys.waitUntil(),sys.waitMsg(),sys.subscribe()。

1.2.2 系统消息队列:

系统消息队列,存储在RTOS层,是RTOS操作系统的基本单元。

系统消息只能是使用 RTOS 的接口发送该消息,并且该发送消息接口是不开放给用户的。

系统消息队列的消息, 由 sys 核心库收取,并传送给对应的协程或者回调函数进行处理。

系统消息队列用于硬件事件,网络事件和定时器事件的传递。

比如说,当 Lua 脚本的某个协程运行了这行代码:
carbon (28)

carbon (29)

1.3 topic 和消息的差异

1.3.1 topic 和消息的差异

LuatOS 的消息,分为两类: topic 和消息。

topic 跟事件的概念是类似的,在 LuatOS 语境里面,topic 往往就是指事件。

topic 是全局消息,是广播消息。

而消息跟 topic 的不同,消息是有特定接收方的,而 topic 没有特定接收方。

LuatOS 的 sys.publish 接口是发布一个全局消息,也就是发布了一个 topic,也是发布了一个事件。

sys.subscribe 接口订阅了一个 topic,也就是订阅了一个事件。

sys.sendMsg, 是发送的消息, sys.waitMsg, 是等待和处理一个消息,是有特定的协程名字作为接收方的。

为了简化描述,在下文的其余部分,如果没有特别的说明,我们不再区分 topic 和消息的差异,统一把 topic 和消息称为消息。

1.3.2 mqtt 和 LuatOS 的 topic 的差异

mqtt 的 topic 与 sys 的 topic 有如下差异:

mqtt 的 topic 的订阅关系是服务器侧(borker)维护的,支持严格匹配和通配符匹配;

sys 的 topic 的订阅关系是 LuatOS 嵌入式系统内部维护的,只支持严格匹配。

1.4 LuatOS 消息的使用

尽管有用户消息队列和系统消息队列两种差异,但是在使用消息的时候,可以不关注这种差异。

用户只需要调用 sys.publish()接口和 sys.sendMsg()接口,按照自己的需要发送消息。

在接收和处理消息的时候,用 sys.subscribe()接口,指定某个消息的回调函数,这时候的消息,也不需要区分用户队列的消息还是系统消息,只要知道消息的名字,都可以指定消息的回调处理函数。

使用 sys.waitUtil()接口,sys.waitMsg 接口的时候,也不需要关心是用户队列的消息还是系统队列的消息,只要知道消息名字,都可以处理。

所有的发送消息,和接收处理消息的接口的使用,接下来都会做消息的介绍。

二、消息的发送

2.1 全局消息(sys 库)

全局消息,也可以理解为广播消息,所有的协程都是可以监听和处理的。

carbon (30)

例如:
carbon (31)

该消息发布后,会放入用户的消息队列,等待被订阅者处理。

2.2 定向消息(sys 库)

使用 sys.sendMsg(taskName, target, arg2, arg3, arg4) 向指定任务发送消息,可以指定接收消息的协程的名字,也可以同时给出消息携带的参数。

这种消息很适用于协程间的点对点通信。 例如:

carbon (32)

该消息直接发送给指定任务,很适合请求-响应模型。

三、消息的接收处理

LuatOS 消息的接收处理有三种方式: 订阅消息,取消订阅息,等待消息。

3.1 订阅消息

通过 sys.subscribe(id, callback) 订阅指定消息的 ID,注册回调函数,当消息到达时调用回调函数进行处理。 例如:

carbon (33)

3.2 取消订阅

carbon (34)

3.3 等待消息

carbon (35)

3.3.1 sys.waitUntil 接口

carbon (36)

接口原型为:

carbon (37)

使用示例:
carbon (38)

该机制基于协程挂起和恢复实现,方便同步等待异步事件。

3.3.2 sys.waitMsg 接口

waitMsg 接口用于定向接收协程间的消息,用于协程间的通信,比较适合请求-响应的多协程合作的工作模式。

接口原型:

carbon (39)

使用示例:
carbon (40)

waitMsg 有如下几个特点:

(1)精准定向:可以通过 taskName 和 target 指定发送方与消息名称;

(2)参数传递:sendMsg 可以支持最多 3 个参数(通过 arg2~arg4 字段);

(3)适用协程之间的通信(如 HTTP 请求响应、任务间数据同步)。

四、sys 系统消息

4.1 系统消息是什么

LuatOS 框架预定义了一些系统消息,开发者可以直接订阅这些消息实现对硬件和系统事件的响应。

系统消息是由 LuatOS 内核或底层驱动自动发布的全局事件,面向所有订阅者广播,适用于硬件状态、网络事件等。

LuatOS 的系统消息,跟普通的消息并没有区别,但是由于是 LuatOS 底层发布的消息,并没有指定明确的接收协程名称,所以系统消息只能是当做全局的广播消息来处理。

用户可以使用 sys.WaitUntil 和 sys.subscibe 接口来处理系统消息,不能用 susplus.waitMsg 接口处理系统消息。

以下按功能模块分类详细说明所有系统消息及其触发条件和参数:

4.2 系统消息详解

详细的系统消息的定义和解读,参见如下链接:

LuatOS 系统消息详细定义:https://docs.openluat.com/osapi/sys_pub/

4.3 补充说明

1, 这些系统消息均为系统自动发布,不能由用户主动发布。

2, 可结合 LuatOS 库的 API(如 mobile.getCellInfo()、mobile.scell())获取详细数据。

五、LuatOS 的定时器机制

LuatOS 定时器机制基于消息驱动,常用的软件定时器接口集中在 sys 库中。

定时器到时后,会由 sys 库接收到定时器超时消息,并触发注册的回调函数或唤醒挂起的任务。

下面详细介绍其用法和原理。

5.1 LuatOS 定时器的基本原理

carbon (41)

5.2 常用定时器 API 及用法

5.2.1 单次定时器

1,创建方式:
carbon (42)

2,代码示例:

carbon (43)

5.2.2 循环定时器

1, 创建方式:
carbon (44)

2, 代码示例

carbon (45)

5.2.3 停止定时器

1, 创建方式:

(1)停止指定定时器:
carbon (46)

(2)停止所有绑定到某个回调的定时器:
carbon (47)

2,代码示例
carbon (48)

5.2.4 在任务中延时/等待消息

1, 函数说明

(1)sys.wait(ms):在 task 协程中挂起指定毫秒数,底层用定时器实现

(2)sys.waitUntil("MSG_ID", timeout_ms):等待某个消息或超时

代码示例:
carbon (49)
carbon (50)

5.2.5 判断定时器状态

1,使用方式
carbon (51)

2, 代码示例

carbon (52)

5.3 总结

1, sys.wait sys.waitUntil sys.waitMsg只能在 task 协程中使用。

2, 定时器到时后,底层会向消息队列推送 rtos.MSG_TIMER 消息,并附带定时器 ID。

3, 系统主循环 sys.run() 检测到该消息后,会查找定时器池,将参数传递给注册的回调或唤醒挂起的协程

4, 定时器总结表
image

六、消息机制的使用流程示例

如下的示例,展示了如何订阅消息、发布消息和在任务中等待消息,帮助理解 LuatOS 消息机制的核心用法。

该示例完整展示了 LuatOS 消息机制的核心用法,建议在真实设备运行时结合串口日志观察执行流程。

实际项目中可根据需要调整消息类型和定时器间隔。

6.1 代码示例

carbon (53)

6.2 代码的执行流程说明

1, 初始化阶段:
carbon (54)

2, 消息传递流程:
carbon (55)

3, 定时器生命周期:
carbon (56)

6.3 执行日志

carbon (57)

6.4 关键 API 对照表

image

七、总结

消息机制原理:基于消息队列和协程,发布者将消息放入队列,订阅者通过回调或协程等待并处理,支持异步事件驱动。

发送消息:sys.publish() 广播消息,sys.sendMsg() 定向发送消息。

接收消息:sys.subscribe() 订阅消息,sys.waitUntil() 和 sys.waitMsg()阻塞等待消息,sys.unsubscribe() 取消订阅。

系统消息:框架预定义多种系统事件消息,直接订阅即可响应硬件和系统事件。

应用场景:网络模块通信、传感器数据广播、定时器事件处理等。

通过合理使用 LuatOS 的消息机制,可以实现高效、解耦的物联网应用架构,支持复杂的事件驱动和多任务协作。

今天的内容就分享到这里了~

posted @ 2025-09-26 19:00  合宙LuatOS  阅读(10)  评论(0)    收藏  举报