LiteOS学习笔记-9LiteOS SDK oc流程之MQTT
MQTT协议
MQTT协议简介
MQTT协议是物联网中设备节点通讯最常用的协议之一,其全称为消息队列遥测传输(英语:Message Queuing Telemetry Transport)是ISO 标准(ISO/IEC PRF 20922)下基于发布 (Publish)/订阅 (Subscribe)范式的消息协议,可视为“数据传递的桥梁”它工作在 TCP/IP协议族上,是为硬件性能低下的远程设备以及网络状况糟糕的情况下而设计的发布/订阅型消息协议,只要具备TCP/IP能力的设备都可以使用MQTT协议。
MQTT是一种基于发布/订阅模型的通信协议。在发布/订阅模型模型中,我们需要一个代理服务器(通常称之为Broker),所有客户端都需要和服务器建立连接,然后进行订阅和发布。若某个客户端发布了其他客户端已订阅的主题(MQTT协议中称之为topic),服务器就会将这个主题转发给所有已订阅的客户端。例如有A、B、C三个客户端都连上了同一个服务器,B和C订阅了“test”主题,然后A发布了一个主题为“test”的消息,服务器就会把这条消息转发给B和C。
在物联网场景中,物联网平台既是一个服务器又是一个客户端。平台制定一套主题规则(我们可以称之为MQTT接口),并订阅数据上报类接口的主题,然后只要设备使用该接口上报数据,平台就可以接收到数据。同理,设备若想要收到平台下发的数据,需要先订阅数据下发类接口的主题。
MQTT消息类型
MQTT消息基于文本传输,主要有以下三类消息:
CONNECT:当客户端想要和服务器建立连接时,需要发送一条CONNECT消息给服务器,消息内包含自己的用户名、密码等信息,服务器鉴权通过后,和客户端建立连接。若双方想要断开连接,则需要遵循TCP协议的四次挥手规则,才能正常断开连接。客户端在发送CONNECT消息时,还可以指定“最后遗愿(last will)”消息,包括消息的主题和内容。当服务器检测到客户端异常断开连接时,就会自动发布这条“最后遗愿”消息。
SUBSCRIBE:当客户端订阅主题时,需要发送一条SUBSCRIBE消息给服务器,指定要订阅的主题。MQTT协议的主题表示为层次结构,类似文件系统,例如“/huawei/v1/devices”这种格式。同理,客户端可以通过UNSUBSCRIBE消息取消订阅指定主题。
PUBLISH:当客户端发布消息时,需要发送一条PUBLISH消息给服务器,指定消息的主题和内容。MQTT对发布消息的内容格式不做限制,需要由各个服务提供商自行制定规范。客户端发布消息时可以指定该消息是否需要保留,一个主题只能保留一条消息,被保留的消息会被代理服务器记录,以后每个新订阅这个主题的客户端都会先接收到这条保留消息。
在可靠传输方面,MQTT协议提供三种QoS等级的实现:
- QoS=0表示消息只会被发送一次,但该消息可能会丢失。
- QoS=1表示确保消息会到达至少一次,但可能会造成订阅者收到多条重复消息。
- QoS=2表示确保消息会到达且仅到达一次。
QoS等级越高,消息传输的可靠度越高,但实现也会越复杂,对网络和设备资源的占用也会变多,所以传输时选用哪个级别的QoS需要根据实际状况选择。
三种不同的服务质量分别对应不同场景,例如远程抄表和温湿度传感器可以选择“最多一次传输”/“至少一次传输”,因为在该场景下就算丢失/重复了几份数据也不会产生太大的影响,还能降低功耗;在计费场景下一般选择“正好一次传输“,防止重复计费。
LiteOS中MQTT实现
LiteOS OC MQTT 抽象组件
概述
OC AL提供的基于MQTT协议抽象层接口代码目录为:…\iot_link\oc\oc_mqtt
,具体如下:
目录 | 描述 |
---|---|
…/oc_mqtt_al | 适配华为OC服务的MQTT抽象层。通过注册机制,最终调用到用户注册的函数 |
…/oc_mqtt_tiny_v5 | SDK内置的soft类设备适配华为OC服务的MQTT的具体实现(针对云端V5版本接口)。 |
…/oc_mqtt_profile_v5 | SDK内置的基于物模型的接口,解析了topic,定义了相关的数据格式 |
OC AL提供的MQTT协议端云互通API烦请参考最新的oc_mqtt_al.h
文件,使用相关的接口需要包含该头文件。
配置并连接
对接服务器的所有信息保存在结构体oc_mqtt_config_t
中,其定义在oc_mqtt_al.h
中,如下:
typedef struct
{
en_oc_mqtt_mode boot_mode; ///< if bs mode, then the server and port must be the bs server's
uint16_t lifetime; ///< the keep alive time, used for the mqtt protocol
char *server_addr; ///< server address:domain name or ip address
char *server_port; ///< server port:
///< define for the tls
dtls_al_security_t security; ///< used for the transport
///< define for the mqtt
char *id;
char *pwd;
char *scope_id;
fn_oc_mqtt_msg_deal msg_deal; ///< when the agent receive any applciation data, please call this function
void *msg_deal_arg; ///< call back for the fn_oc_mqtt_msg_deal
fn_oc_mqtt_log log_dealer;
}oc_mqtt_config_t;
其中boot_mode
是对接模式,对应华为平台的两种模式:
///< the mode for the huawei OceanConnect mode
///< bs: if bs then the connection will first connect the bootstrap server then the hub server
///< static:means we connect the server use the generated id and pwd when create device on the platform
///< nodeid:means we connect use the nodeid and pwd generated
typedef enum
{
en_oc_mqtt_mode_bs_static_nodeid_hmacsha256_notimecheck_json =0,
en_oc_mqtt_mode_nobs_static_nodeid_hmacsha256_notimecheck_json,
en_oc_mqtt_mode_last,
}en_oc_mqtt_mode;
本实验中使用的是直连模式,选择第二种。
在配置结构体完成之后,调用配置函数进行配置并连接,API如下:
/**
* @brief the application use this function to configure the lwm2m agent
*
* @param[in] param, refer to oc_mqtt_config_t
*
* @return code: define by en_oc_mqtt_err_code while 0 means success
*/
int oc_mqtt_config(oc_mqtt_config_t *param);
数据上报
连接成功之后,向华为云平台上报数据需要关注两部分:
- 发布消息主题:这个OC_MQTT组件会自动帮我们搞定;
- 发布消息指令:发布时由用户指定;
- 发布消息内容:在使用JSON数据格式通信时,需要在本地将数据封装为JSON格式,OC_MQTT组件中已经编写了一个助手程序,帮助我们封装和数据
LiteOS MQTT 协议层
物联组件协议层目录:…\iot_link\network\。
IoT Device SDK Tiny集成了LwM2M、CoAP、MQTT等物联网标准协议,您可以直接调用已实现协议,或添加自定义协议,将其注册进SDK中。
根据MQTT标准协议,IoT Device SDK Tiny提供的MQTT服务都是建立在标准的MQTT协议基础上,并提供MQTT协议抽象层接口。适配MQTT的软件结构示意图如下:
typedef struct
{
///< connect to the server
void* (* connect) (mqtt_al_conpara_t *param);
///< disconnect from the server
int (* disconnect)(void *handle );
///< publish a message to the server
int (* publish) (void *handle, mqtt_al_pubpara_t *msg);
///< subscribe a topic to the server
int (* subscribe) (void *handle, mqtt_al_subpara_t *subpara);
///< unsubscribe a topic to the server
int (* unsubscribe) (void *handle, mqtt_al_unsubpara_t *unsubpara);
///< check the mqtt engine status
en_mqtt_al_connect_state (* check_status) (void *handle);
}mqtt_al_op_t;
int mqtt_al_install(mqtt_al_op_t *op);
相关适配接口介绍:
接口分类 | 接口名 | 说明 |
---|---|---|
MQTT相关接口 | void * mqtt_al_connect( mqtt_al_conpara_t *conparam) | 请求连接 |
int mqtt_al_disconnect(void *handle) | 断开连接 | |
int mqtt_al_publish(void *handle, mqtt_al_pubpara_t *pubpara) | 发布消息 | |
int mqtt_al_subscribe(void *handle, mqtt_al_subpara_t *subpara) | 订阅请求 | |
int mqtt_al_unsubscribe(void *handle, mqtt_al_unsubpara_t *unsubpara) | 取消订阅 | |
en_mqtt_al_connect_state mqtt_al_check_status(void *handle) | 检查连接状态 |
同样需要适配的有基础支撑组件。基础组件包括传感器框架、驱动框架、VFS/DEVFS、安全可靠传输、TCP/IP等,根据实际需求选择适配。
TCP/IP适配
其网络协议栈决定于底层操作系统,使用第三方操作系统时,可以将相关的网络传输接口进行抽象,提供相关的协议栈接口即可。IoT LINK SDK中调用的所有网络传输的接口,通过注册机制,最终都会调用到用户注册的函数。
调用link_sal_install函数进行TCPIP功能注册。同时用户必须实现link_tcpip_imp_init函数,该函数是一个弱符号函数。在该SDK初始化的过程中,调用顺序为:link_tcpip_init—>link_tcpip_imp_init—>link_sal_install,在初始化完毕之后,才可以使用TCPIP相关的功能。详细参考sal_imp.h头文件,同时SDK已经适配了LWIP/ESP8266/L716等软件或者模组提供的TCPIP功能,如果你有第三方的组件或者模组,可以参考实现。
OS适配
对于IoT LINK SDK而言,其运行依赖操作系统,如果使用第三方的操作系统,则可以将相关的操作系统进行抽象,提供相关的任务创建删除、互斥锁、信号量、内存管理接口即可。IoT LINK SDK中调用的所有系统相关的接口,通过注册机制,最终都会调用到用户注册的函数。
调用osal_install函数进行注册操作系统服务。调用顺序如下:
osal_init—>os_imp_init–>osal_install。其中os_imp_init是弱符号函数,需要用户根据自的需要实现,在其中调用osal_install函数实现系统服务的注册。
MQTT接入OC开发流程
流程简介
主要介绍使用MQTT方式对接华为IoT平台。
使用的方案为:目标板为STM32L431BearPI(带E53扩展板); TCPIP功能由开发板的ESP8266提供;MQTT使用Paho-Client-Embeded;IoT对接接口采用V5版本接口。
整个开发分为两个部分:云端开发、设备侧开发。云端开发包括创建产品、创建设备;设备侧开发包括根据方案配置功能、编译烧录、调试。
云端开发
创建产品模型
产品模型其实就是用户设备的抽象。用编程术语来解释就是产品模型是Class,设备是对象。关于产品模型的介绍以及如何创建产品模型可以参考创建产品。
设备属性包括:温度、湿度、光照强度、LED状态、Motor状态。设备命令包括两条:控制LED ON/OFF,控制Motor ON/OFF。
创建设备
当产品模型创建完毕之后,我们可以创建基于该产品模型的设备。设备–>注册设备。根据对话框填写对应的信息。
注册成功之后如下:
设备注册成功后,请妥善保管好设备ID和密钥,用于设备接入平台认证。
设备端开发
设备端的开发主要包括配置工程、编译烧录、调试几个步骤。下文基于此逐一进行介绍。
工程配置
由于SDK是一个全栈的软件,包含所有的代码,因此我们需要告知编译器哪些文件需要编译、怎么编译这些文件,这个工作主要是由Kconfig完成。
在VS Code中,打开iot_link插件,进入设置选择SDK配置进入option选择界面,此处是根据.config文件生成的,也可直接修改.config文件。
设置AT串口波特率和模组匹配
MCU通过串口向通信模组ESP8266发送AT指令进行操作。波特率设置为115200.
TCP/IP设置
在Network下,选择TCPIP功能,并设置esp8266模式,并设置热点的SSID和PWD。
配置DTLS
IoT Device SDK Tiny以LwM2M/CoAP协议端云连接传输数据包时,不能保证UDP通信双方的身份认证、消息传输过程中的加密传输,所以使用DTLS(Datagram Transport Layer Security),即数据包传输层安全性协议进行加密。
DTLS握手协议和TLS类似。DTLS协议在UDP之上实现了客户机与服务器双方的握手连接,在握手过程中验证对方的身份,并且使用RSA或者DH(Diffie-Hellman)实现会话密钥的建立,以便在后面的数据传输中对数据加密。它利用cookie验证机制和证书实现了通信双方的身份认证;并且用在报文段头部加上序号,缓存乱序到达的报文段;还利用重传机制实现了可靠传送。在握手完成后,通信双方就可以利用握手阶段协商好的会话密钥来对应用数据进行加解密。
IoT Device SDK Tiny使用mbedtls加密库实现加密的优点:mbedTLS(前身PolarSSL)是面向嵌入式系统,实现的一套易用的加解密算法和SSL/TLS库。mbedTLS系统开销极小,对于系统资源要求不高。mbedTLS是开源项目,并且使用Apache 2.0许可证,使得用户既可以讲mbedTLS使用在开源项目中,也可以应用于商业项目。目前使用mbedTLS的项目很多,例如Monkey HTTP Daemon,LinkSYS路由器。
IoT Device SDK Tiny首先和物联网开放平台完成握手流程,后续的应用数据将全部为加密数据。
配置MBEDTLS的主要原因是,IoT平台生成MQTT的三元组的时候需要使用到HMAC算法。使能TLS并选择mbedtls并配置为CERT模式
配置mqtt
使能MQTT,使用Paho-Client-Embeded
配置IoT MQTT接入服务
使能OC服务,使能OC MQTT,选择V5协议接口,选择tinyV5实现
编译烧录测试
编译
如果出现FLASH溢出行为,可以将不需要的组件(stime shell)通过配置禁用;或者在Makefile中修改优化等级从-O0 -g修改为-Os。
源码如下
参考.iotlink\sdk\IoT_LINK\targets\STM32L431_BearPi\Demos\oc_mqtt
目录下实验文件
```c
/**
* DATE AUTHOR INSTRUCTION
* 2021-03-19 17:00 Q-Stark The first version
*
*/
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <osal.h>
//通讯协议头文件
#include <queue.h>
#include <oc_mqtt_al.h>
#include <oc_mqtt_profile.h>
//扩展板等驱动头文件
#include "E53_IA1.h"
#include "lcd.h"
//引脚,中断等相关头文件
#include <gpio.h>
#include <stm32l4xx_it.h>
//MQTT协议参数
#define DEFAULT_LIFETIME 60
#define cn_app_server "a15f9d431e.iot-mqtts.cn-north-4.myhuaweicloud.com"
#define cn_app_port "1883"
#define cn_mqtt_endpoint_id "平台生成的ID"
#define cn_mqtt_endpoint_password "123456789"
#define CONFIG_QUEUE_TIMEOUT (5*1000)
//上报数据协议
typedef enum
{
en_msg_cmd = 0,
en_msg_report,
}en_msg_type_t;
typedef struct
{
char *request_id;
char *payload;
}cmd_t;
typedef struct
{
int Temperature;
int Humidity;
int Luminance;
}report_t;
typedef struct
{
en_msg_type_t msg_type;
union{
cmd_t cmd;
report_t report;
}msg;
}app_msg_t;
typedef struct
{
queue_t *app_msg;
int connected;
int Light_state;
int Motor_state;
}app_cb_t;
static app_cb_t g_app_cb;
//传感器数据
E53_IA1_Data_TypeDef E53_IA1_Data;
static int LCD_show_entry()
{
LCD_Clear(BLACK);
//默认关闭状态
POINT_COLOR = RED;
LCD_ShowString(83, 198, 210, 32, 32, "OFF");
LCD_ShowString(175, 198, 210, 32, 32, "OFF");
while (1)
{
POINT_COLOR = GREEN;
// 传感器:
LCD_ShowNum(90, 62, (uint32_t)E53_IA1_Data.Temperature, 5, 32);
LCD_ShowNum(90, 105, (uint32_t)E53_IA1_Data.Humidity, 5, 32);
LCD_ShowNum(90, 152, (uint32_t)E53_IA1_Data.Lux, 5, 32);
osal_task_sleep(2 * 1000);
}
return 0;
}
static int app_sensor_collect_entry()
{
app_msg_t *app_msg;
while (1)
{
E53_IA1_Read_Data();
app_msg = osal_malloc(sizeof(app_msg_t));
if(NULL != app_msg){
app_msg->msg_type = en_msg_report;
app_msg->msg.report.Luminance = (int)E53_IA1_Data.Lux;
app_msg->msg.report.Humidity = (int)E53_IA1_Data.Humidity;
app_msg->msg.report.Temperature = (int)E53_IA1_Data.Temperature;
if(0 != queue_push(g_app_cb.app_msg,app_msg,CONFIG_QUEUE_TIMEOUT)){
osal_free(app_msg);
}
}
osal_task_sleep(5 * 1000);
}
return 0;
}
//使用profile中的结构体构造mqtt协议格式数据,并使用默认topic提交发布
static int deal_report_msg(report_t *report)
{
oc_mqtt_profile_service_t service;
oc_mqtt_profile_kv_t temperature;
oc_mqtt_profile_kv_t humidity;
oc_mqtt_profile_kv_t luminance;
oc_mqtt_profile_kv_t Light_state;
oc_mqtt_profile_kv_t Motor_state;
if(g_app_cb.connected != 1){
return;
}
service.event_time = NULL;
service.service_id = "My_Sensor";
service.service_property = &temperature;
service.nxt = NULL;
temperature.key = "Temperature";
temperature.value = &report->Temperature;
temperature.type = EN_OC_MQTT_PROFILE_VALUE_INT;
temperature.nxt = &humidity;
humidity.key = "Humidity";
humidity.value = &report->Humidity;
humidity.type = EN_OC_MQTT_PROFILE_VALUE_INT;
humidity.nxt = &luminance;
luminance.key = "Luminance";
luminance.value = &report->Luminance;
luminance.type = EN_OC_MQTT_PROFILE_VALUE_INT;
luminance.nxt = &Light_state;
Light_state.key = "Light_State";
Light_state.value = g_app_cb.Light_state?"ON":"OFF";
Light_state.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
Light_state.nxt = &Motor_state;
Motor_state.key = "Motor_State";
Motor_state.value = g_app_cb.Motor_state?"ON":"OFF";
Motor_state.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
Motor_state.nxt = NULL;
oc_mqtt_profile_propertyreport(NULL,&service);
return;
}
//将接收到的broker下发的命令取出并存入队列缓冲区
static int msg_rcv_callback(oc_mqtt_profile_msgrcv_t *msg)
{
int ret = 0;
char *buf;
int buf_len;
app_msg_t *app_msg;
if((NULL == msg)|| (msg->request_id == NULL) || (msg->type != EN_OC_MQTT_PROFILE_MSG_TYPE_DOWN_COMMANDS)){
return ret;
}
buf_len = sizeof(app_msg_t) + strlen(msg->request_id) + 1 + msg->msg_len + 1;
buf = osal_malloc(buf_len);
if(NULL == buf){
return ret;
}
app_msg = (app_msg_t *)buf;
buf += sizeof(app_msg_t);
app_msg->msg_type = en_msg_cmd;
app_msg->msg.cmd.request_id = buf;
buf_len = strlen(msg->request_id);
buf += buf_len + 1;
memcpy(app_msg->msg.cmd.request_id, msg->request_id, buf_len);
app_msg->msg.cmd.request_id[buf_len] = '\0';
buf_len = msg->msg_len;
app_msg->msg.cmd.payload = buf;
memcpy(app_msg->msg.cmd.payload, msg->msg, buf_len);
app_msg->msg.cmd.payload[buf_len] = '\0';
ret = queue_push(g_app_cb.app_msg,app_msg,10);
if(ret != 0){
osal_free(app_msg);
}
return ret;
}
void E53_IA1_LED(int On_Off)
{
if(On_Off){
HAL_GPIO_WritePin(IA1_Light_GPIO_Port, IA1_Light_Pin, GPIO_PIN_SET);
POINT_COLOR = GREEN;
LCD_ShowString(175, 198, 210, 32, 32, "ON ");
}
else{
HAL_GPIO_WritePin(IA1_Light_GPIO_Port, IA1_Light_Pin, GPIO_PIN_RESET);
POINT_COLOR = RED;
LCD_ShowString(175, 198, 210, 32, 32, "OFF");
}
}
void E53_IA1_MOTOR(int On_Off)
{
if(On_Off){
HAL_GPIO_WritePin(IA1_Motor_GPIO_Port, IA1_Motor_Pin, GPIO_PIN_SET);
POINT_COLOR = GREEN;
LCD_ShowString(83, 198, 210, 32, 32, "ON ");
}
else{
HAL_GPIO_WritePin(IA1_Motor_GPIO_Port, IA1_Motor_Pin, GPIO_PIN_RESET);
POINT_COLOR = RED;
LCD_ShowString(83, 198, 210, 32, 32, "OFF");
}
}
//提取下发命令,并执行
#include <cJSON.h>
static void deal_cmd_msg(cmd_t *cmd)
{
cJSON *obj_root;
cJSON *obj_cmdname;
cJSON *obj_paras;
cJSON *obj_para;
int cmdret = 1;
oc_mqtt_profile_cmdresp_t cmdresp;
obj_root = cJSON_Parse(cmd->payload);
if(NULL == obj_root){
goto EXIT_JSONPARSE;
}
obj_cmdname = cJSON_GetObjectItem(obj_root,"command_name");
if(NULL == obj_cmdname){
goto EXIT_CMDOBJ;
}
if(0 == strcmp(cJSON_GetStringValue(obj_cmdname),"Agriculture_Control_Light")){
obj_paras = cJSON_GetObjectItem(obj_root,"Paras");
if(NULL == obj_paras){
goto EXIT_OBJPARAS;
}
obj_para = cJSON_GetObjectItem(obj_paras,"Light");
if(NULL == obj_para){
goto EXIT_OBJPARA;
}
///< operate the LED here
if(0 == strcmp(cJSON_GetStringValue(obj_para),"ON")){
g_app_cb.Light_state = 1;
E53_IA1_LED(1);
}
else{
g_app_cb.Light_state = 0;
E53_IA1_LED(0);
}
cmdret = 0;
}
else if(0 == strcmp(cJSON_GetStringValue(obj_cmdname),"Agriculture_Control_Motor")){
obj_paras = cJSON_GetObjectItem(obj_root,"Paras");
if(NULL == obj_paras){
goto EXIT_OBJPARAS;
}
obj_para = cJSON_GetObjectItem(obj_paras,"Motor");
if(NULL == obj_para){
goto EXIT_OBJPARA;
}
///< operate the Motor here
if(0 == strcmp(cJSON_GetStringValue(obj_para),"ON")){
g_app_cb.Motor_state = 1;
E53_IA1_MOTOR(1);
}
else{
g_app_cb.Motor_state = 0;
E53_IA1_MOTOR(0);
}
cmdret = 0;
}
EXIT_OBJPARA:
EXIT_OBJPARAS:
EXIT_CMDOBJ:
cJSON_Delete(obj_root);
EXIT_JSONPARSE:
///< do the response
cmdresp.paras = NULL;
cmdresp.request_id = cmd->request_id;
cmdresp.ret_code = cmdret;
cmdresp.ret_name = NULL;
(void)oc_mqtt_profile_cmdresp(NULL,&cmdresp);
return;
}
//配置连接
static void conn_mqtt_server(void)
{
int ret;
oc_mqtt_profile_connect_t connect_para;
(void) memset( &connect_para, 0, sizeof(connect_para));
connect_para.boostrap = 0;
connect_para.device_id = cn_mqtt_endpoint_id;
connect_para.device_passwd = cn_mqtt_endpoint_password;
connect_para.server_addr = cn_app_server;
connect_para.server_port = cn_app_port;
connect_para.life_time = DEFAULT_LIFETIME;
connect_para.rcvfunc = msg_rcv_callback;
connect_para.security.type = EN_DTLS_AL_SECURITY_TYPE_NONE;
ret = oc_mqtt_profile_connect(&connect_para);
if((ret == (int)en_oc_mqtt_err_ok)){
g_app_cb.connected = 1;
}
return;
}
//使用状态机模式进行消息类型选择,进入不同的处理函数
static int app_msg_switch_entry()
{
app_msg_t *app_msg;
while(1){
app_msg = NULL;
(void)queue_pop(g_app_cb.app_msg,(void **)&app_msg,(int)cn_osal_timeout_forever);
if(NULL != app_msg){
switch(app_msg->msg_type){
case en_msg_cmd:
deal_cmd_msg(&app_msg->msg.cmd);
break;
case en_msg_report:
deal_report_msg(&app_msg->msg.report);
break;
default:
break;
}
osal_free(app_msg);
}
}
return 0;
}
int standard_app_demo_main()
{
int ret = -1;
g_app_cb.app_msg = queue_create("queue_rcvmsg",5,1);
if(NULL == g_app_cb.app_msg){
return ret;
}
Init_E53_IA1();
conn_mqtt_server();
osal_task_create("LCD_show", LCD_show_entry, NULL, 0x400, NULL, 4);
//数据采集
osal_task_create("sensor_collect", app_sensor_collect_entry, NULL, 0x400, NULL, 3);
//消息状态机调转入口
osal_task_create("msg_switch", app_msg_switch_entry, NULL, 0x1000, NULL, 2);
return 0;
}