下载 FreeRTOS
 

出色的 RTOS & 嵌入式软件

最新资讯
简化任何设备的身份验证云连接。
利用 CoAP 设计节能型云连接 IoT 解决方案。
11.0.0 版 FreeRTOS 内核简介:
FreeRTOS 路线图和代码贡献流程。
使用 FreeRTOS 实现 OPC-UA over TSN。

coreMQTT Agent 演示

单线程 VS 多线程

coreMQTT 有两种使用模式,单线程多线程(多任务)。单线程 模型仅在一个线程中使用 CoreMQTT 库, 要求重复显式调用 MQTT 库。 与此不同的是,多线程用例 可以从一个 agent(或守护进程任务)任务中在后台执行 MQTT 协议。 在 agent 任务中运行 MQTT 协议时,不必显式管理任何 MQTT 状态 或调用 MQTT_ProcessLoop() API 函数。此外,使用 Agent 任务时, 多个应用程序任务可以共享单个 MQTT 连接,无需互斥锁之类的同步基元。

演示简介

coreMQTT Agent 演示项目 使用 FreeRTOS Windows 移植,因此可以 在 Windows 上使用免费社区版 Visual Studios 进行构建和评估,而无需任何特殊 MCU 硬件。
此演示使用线程安全队列来保存与 coreMQTT API 交互的命令。在此演示中需注意 以下两项任务:
  • MQTT Agent(主)任务处理来自命令队列的命令,而其他任务则自行排队。此任务 进入循环,并在循环期间处理来自命令队列的命令。如果收到终止命令, 它将脱离循环。
  • 演示子发布任务创建对 MQTT 主题的订阅,然后创建发布操作并将其推送到 命令队列。然后,这些发布操作由 MQTT Agent 任务运行。演示子发布任务 等待发布完成(执行命令完成回调指示)由, 然后在开始下一个发布之前进入一个短暂的延迟。此任务显示了应用程序任务 如何使用 coreMQTT Agent API 的示例。
对于传入的发布消息, coreMQTT Agent 调用单个回调函数。此演示还包含一个订阅管理器, 允许任务指定要调用的回调, 用于已订阅主题的传入发布消息。在此演示中,Agent 的传入发布回调调用订阅管理器, 以将发布扇出到已注册订阅的任何任务。

可将 coreMQTT Agent 演示配置为使用带有相互身份验证的 TLS 连接或 明文 TCP 连接。默认情况下,演示使用TLS。如果在演示过程中网络意外断开, 则客户端将尝试使用指数退避逻辑重新连接。我们还建议 在任何物联网 (IoT) 应用程序中使用相互身份验证。

源代码组织

多线程 MQTT 演示的 Visual Studio 解决方案 名为 mqtt_multitask_demo.sln,位于 /FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask 目录中, 目录位于主 FreeRTOS 下载中。

单击以放大

构建演示项目

此演示项目使用 Visual Studio 的社区免费版。要构建演示,请执行如下操作:
  1. 从 Visual Studio IDE 中打开 "mqtt_multitask_demo.sln" Visual Studio 解决方案文件。
  2. 在 IDE 的 Build 菜单中选择 Build Solution
注意:如果您使用的是 Microsoft Visual Studio 2017 或更早版本,则必须选择与版本兼容的 Platform ToolsetProject -> RTOSDemos Properties -> Platform Toolset

配置演示项目

此演示使用 FreeRTOS-Plus-TCP TCP/IP 堆栈,因此 请遵循为 TCP/IP 入门项目提供的说明执行下列操作:
  1. 安装必备组件(例如 WinPCap)。
  2. 可选 设置静态或动态 IP 地址,网关地址和网络掩码
  3. 可选 设置 MAC 地址(可选)。
  4. 在您的主机上选择以太网接口。
  5. ......最重要的是: 在尝试运行 MQTT 演示之前,请先测试网络连接
所有这些设置都应在 MQTT Agent 演示项目中更改,而不是在上面链接的页面中所提及的 TCP/IP Starter 项目中 更改!交付时, TCP/IP 堆栈被配置为使用动态 IP 地址。

配置 MQTT 代理连接

备选方案 1:带有相互身份验证的 TLS(默认)

此演示支持 与 MQTT Mutual Auth 演示相同的配置选项。请参阅演示文档,了解所有可用选项。

备选方案 2:明文

为了启用无需证书配置的快速设置,该演示允许使用明文 TCP 连接来代替 相互身份验证的 TLS 连接。要禁用 TLS,应将宏 “democonfigUSE_TLS” 在 "demo_config" 中设置为 0,或者干脆不定义。然后, 可以按照 与明文演示相同的说明,将该演示用于任何未加密的 MQTT 代理(例如,Eclipse Mosquitto)。

重要提示:
  • 明文连接有助于了解 MQTT 的工作原理和调试连接,这是因为 可以 在 WireShark 等网络嗅探器中查看 MQTT 对话。但是, 实际 IoT 设备不应使用未经加密的明文连接, 因为所有流量都会暴露于网络上的任何设备。切勿通过明文连接发送私有数据,强烈建议 对所有 IoT 设备使用加密和相互验证的连接。
  • 演示将密钥放置在头文件中,仅用于演示目的。强烈建议 实际设备将密钥存储在安全位置,如 Secure Element 或 Secure Enclave 中。此外, 此外,建议实际 IoT 设备通过不会泄露密钥的 API (例如 PKCS #11PSA API)访问密钥和其他加密对象。
确定代理后,下面的代码段描述了配置 MQTT 连接的 编译时间配置常量。请将 TLS 连接所需的所有密钥放置在同一文件中: demo_config.h demo_config.h

coreMQTT Agent 配置常量

以下代码片段显示了与 MQTT Agent 相关的编译时常量 及其默认值。MQTT Agent 没有自己的配置文件,但会 使用 core_mqtt_config.h 中定义的任意宏。该函数中定义的宏将替代默认值: core_mqtt_config.h

功能

main() 会先初始化 TCP/IP 堆栈,然后启动 FreeRTOS 内核调度器。有网络 连接时,网络事件钩子可创建单项 RTOS 任务。该任务可选择性创建多项其他任务,每项任务都会 发送和接收不同大小和不同服务质量 (QoS) 级别的 MQTT 数据包。 原始线程随后成为 MQTT Agent 线程。

以下常量定义了创建的演示任务。描述中的链接指向位于每个实现源文件顶部的注释, 可提供更多信息。
  • #define democonfigNUM_SIMPLE_SUB_PUB_TASKS_TO_CREATE [n]
    设置 simple_pub_sub_demo.c 中实现的任务要创建的实例数。

MQTT Agent 任务

MQTT Agent 任务负责调用 MQTTAgent_CommandLoop()。此任务在命令发布到其队列时 调用请求的 coreMQTT API。

命令
调用 coreMQTT Agent API 时,会创建一个发送到代理任务队列的命令, 该命令在 MQTTAgent_CommandLoop() 中处理。创建命令时, 可以传递可选的完成回调和上下文参数。完成相应的命令后,将使用 传递的上下文和作为命令结果的任何返回值来调用完成回调。完成回调的签名 如下所示:

typedef void (* MQTTAgentCommandCallback_t )( void * pCmdCallbackContext,
MQTTAgentReturnInfo_t * pReturnInfo );
命令完成上下文由用户定义;对于此演示,为: struct MQTTAgenCommandContext

在以下情况下,命令被视为已完成:
  • 使用 QoS > 0 订阅、取消订阅和发布:收到 相应的确认数据包时。
  • 所有其他操作:调用了相应的 coreMQTT API。
命令使用的任何结构(包括发布信息、订阅信息和完成上下文) 必须保持在作用域内,直到命令完成。调用完成回调之前,调用任务不得 重复使用命令的任何结构体。请注意,MQTT Agent 会调用完成回调, 因此将使用代理任务的线程上下文运行,而不是创建命令的任务。过程间通信 机制(如任务通知或队列)可用于向调用任务发出命令完成的信号。

运行命令循环

命令由 MQTTAgent_CommandLoop() 连续处理。如果没有要处理的命令, 循环将等待 MQTT_AGENT_MAX_EVENT_QUEUE_WAIT_TIME 的最大值,以便向队列中添加命令。 如果未添加命令,则运行 MQTT_ProcessLoop() 的单次迭代。这即可确保 MQTT 保活机制 处于启用状态,也可确保即使队列中没有命令,也会接收任何传入的发布。
命令循环函数将返回,原因如下:
  • 命令返回 MQTTSuccess 之外的任何状态代码。错误状态由命令循环返回, 可自行决定如何处理。在此演示中,将重新建立 TCP 连接, 并尝试重新连接。如果出现任何错误,则可以在后台进行重新连接,而无需其他任务 使用 MQTT 进行干预。
  • 已处理断开命令(来自 MQTTAgent_Disconnect)。命令循环将退出,以便 断开 TCP 连接。
  • 已处理终止命令(来自 MQTTAgent_Terminate)。此命令还将 仍在队列中或等待确认数据包的任何命令标记为错误,返回代码 为 MQTTRecvFailed
以下是 Agent 任务中如何处理这些情况: prvMQTTAgentTask()

创建其他任务
此演示中的 MQTT Agent 任务还创建了订阅发布任务。虽然 这项任务对于 Agent 任务并不是必需的,但由于 Agent 任务是此演示中的主要任务,因此在此处执行此操作: prvConnectAndCreateDemoTasks()

订阅管理器

由于演示使用多个主题,订阅管理器是将订阅主题与唯一回调或任务 相关联的便捷方式。此演示中的订阅管理器为单线程,不能被多个任务 同时使用。在此演示中,订阅管理器函数仅从传递给 MQTT 代理的回调函数调用, 并且仅使用代理任务的线程上下文运行。订阅管理器由以下 类型和函数组成: 回调函数

简单订阅发布任务

订阅发布任务的每个实例都会创建对 MQTT 主题的订阅, 并为该主题创建发布操作。为了演示多个发布类型,偶数编号的任务使用 QoS 0(发送发布数据包后即完成), 奇数编号的任务使用 QoS 1(收到 PUBACK 数据包时完成)。子发布 任务定义如下: prvSimpleSubscribePublishTask()
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.