理解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 用户消息队列:
用户消息队列的接收接口有三个: sys.waitUntil(),sys.waitMsg(),sys.subscribe()。
1.2.2 系统消息队列:
系统消息队列,存储在RTOS层,是RTOS操作系统的基本单元。
系统消息只能是使用 RTOS 的接口发送该消息,并且该发送消息接口是不开放给用户的。
系统消息队列的消息, 由 sys 核心库收取,并传送给对应的协程或者回调函数进行处理。
系统消息队列用于硬件事件,网络事件和定时器事件的传递。
比如说,当 Lua 脚本的某个协程运行了这行代码:
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 库)
全局消息,也可以理解为广播消息,所有的协程都是可以监听和处理的。
例如:
该消息发布后,会放入用户的消息队列,等待被订阅者处理。
2.2 定向消息(sys 库)
使用 sys.sendMsg(taskName, target, arg2, arg3, arg4) 向指定任务发送消息,可以指定接收消息的协程的名字,也可以同时给出消息携带的参数。
这种消息很适用于协程间的点对点通信。 例如:
该消息直接发送给指定任务,很适合请求-响应模型。
三、消息的接收处理
LuatOS 消息的接收处理有三种方式: 订阅消息,取消订阅息,等待消息。
3.1 订阅消息
通过 sys.subscribe(id, callback) 订阅指定消息的 ID,注册回调函数,当消息到达时调用回调函数进行处理。 例如:
3.2 取消订阅
3.3 等待消息
3.3.1 sys.waitUntil 接口
接口原型为:
使用示例:
该机制基于协程挂起和恢复实现,方便同步等待异步事件。
3.3.2 sys.waitMsg 接口
waitMsg 接口用于定向接收协程间的消息,用于协程间的通信,比较适合请求-响应的多协程合作的工作模式。
接口原型:
使用示例:
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 定时器的基本原理
5.2 常用定时器 API 及用法
5.2.1 单次定时器
1,创建方式:
2,代码示例:
5.2.2 循环定时器
1, 创建方式:
2, 代码示例
5.2.3 停止定时器
1, 创建方式:
(1)停止指定定时器:
(2)停止所有绑定到某个回调的定时器:
2,代码示例
5.2.4 在任务中延时/等待消息
1, 函数说明
(1)sys.wait(ms):在 task 协程中挂起指定毫秒数,底层用定时器实现
(2)sys.waitUntil("MSG_ID", timeout_ms):等待某个消息或超时
代码示例:
5.2.5 判断定时器状态
1,使用方式
2, 代码示例
5.3 总结
1, sys.wait sys.waitUntil sys.waitMsg只能在 task 协程中使用。
2, 定时器到时后,底层会向消息队列推送 rtos.MSG_TIMER 消息,并附带定时器 ID。
3, 系统主循环 sys.run() 检测到该消息后,会查找定时器池,将参数传递给注册的回调或唤醒挂起的协程
4, 定时器总结表
六、消息机制的使用流程示例
如下的示例,展示了如何订阅消息、发布消息和在任务中等待消息,帮助理解 LuatOS 消息机制的核心用法。
该示例完整展示了 LuatOS 消息机制的核心用法,建议在真实设备运行时结合串口日志观察执行流程。
实际项目中可根据需要调整消息类型和定时器间隔。
6.1 代码示例
6.2 代码的执行流程说明
1, 初始化阶段:
2, 消息传递流程:
3, 定时器生命周期:
6.3 执行日志
6.4 关键 API 对照表
七、总结
消息机制原理:基于消息队列和协程,发布者将消息放入队列,订阅者通过回调或协程等待并处理,支持异步事件驱动。
发送消息:sys.publish() 广播消息,sys.sendMsg() 定向发送消息。
接收消息:sys.subscribe() 订阅消息,sys.waitUntil() 和 sys.waitMsg()阻塞等待消息,sys.unsubscribe() 取消订阅。
系统消息:框架预定义多种系统事件消息,直接订阅即可响应硬件和系统事件。
应用场景:网络模块通信、传感器数据广播、定时器事件处理等。
通过合理使用 LuatOS 的消息机制,可以实现高效、解耦的物联网应用架构,支持复杂的事件驱动和多任务协作。
今天的内容就分享到这里了~