首页 > 其他分享 >STM32+阿里云+ESP8266+MQTT+DHT11

STM32+阿里云+ESP8266+MQTT+DHT11

时间:2024-11-10 09:15:14浏览次数:3  
标签:return ESP8266 ++ len STM32 MQTT mqttPacket data

一、阿里云平台环境搭建

注册完账号以后,找到控制台->物联网平台。

       

1.创建一个公共实例,若该实例有ID则为新公共实例

2.创建一个产品

[如何在物联网平台创建产品_物联网平台(IoT)-阿里云帮助中心 (aliyun.com)](https://help.aliyun.com/zh/iot/user-guide/create-a-product?spm=5176.11485173.console-base_help.dexternal.4f2e59afF4dTYD)

可在上方选择地区

点击实例 -->设备管理 -->产品-->创建产品(MQTT:只可以选新建产品,建议选择自定义品类,联网方式依据自己需求选择,其它不用管 )

3.创建一个设备

[物联网平台中注册单个设备_物联网平台(IoT)-阿里云帮助中心 (aliyun.com)](https://help.aliyun.com/zh/iot/user-guide/create-a-device?spm=5176.11485173.console-base_help.dexternal.4f2e59afF4dTYD)

点击设备-->添加设备-->选择要添加的产品-->输入devicebname

    

4.创建物模型

[定义物模型属性、事件和服务_物联网平台(IoT)-阿里云帮助中心 (aliyun.com)](https://help.aliyun.com/zh/iot/user-guide/add-a-tsl-feature?spm=5176.11485173.console-base_help.dexternal.4f2e59afF4dTYD)

点击产品-->查看产品-->功能定义-->编辑草稿

(MQTT设备不可添加物模型,这里添加自定义功能)

     最后点击 **发布上线**(发布上线后才会有效,不同于产品发布)

5.根据自己需求可以加主题

这样,基本的阿里云环境就搭建好了,可以连接单片机了

二、STM32与阿里云的连接

1.选择接入阿里云方式

[物联网平台LinkSDK集成方式和功能特性_物联网平台(IoT)-阿里云帮助中心 (aliyun.com)](https://help.aliyun.com/zh/iot/developer-reference/link-sdks?spm=5176.11485173.console-base_help.dexternal.4f2e59afF4dTYD)

[使用TLS加密设备和物联网平台的MQTT通信_物联网平台(IoT)-阿里云帮助中心 (aliyun.com)](https://help.aliyun.com/zh/iot/user-guide/establish-mqtt-connections-over-tcp?spm=a2c4g.11186623.0.i2)

[如何计算MQTT签名参数_物联网平台(IoT)-阿里云帮助中心 (aliyun.com)](https://help.aliyun.com/zh/iot/user-guide/how-do-i-obtain-mqtt-parameters-for-authentication?spm=a2c4g.11186623.0.0.6fc2283cwa1lxp#task-2100587)

[如何下载设备端SDK_物联网平台(IoT)-阿里云帮助中心 (aliyun.com)

  (1).选择SDK,这里暂不使用。

  (2).MQTT自主协议接入。

这里选择MQTT-TLS的一机一密接入!!!

注意这里不是老版的三元组,而是加密后的三元组

在这里获取

(踩的坑,开始没有仔细看阿里的开发文档,直接看的github上的博客,改一下别人的配置,准备复刻一下,发现一直登录不上去,然后又参考了好几份代码和案例,还是不行,也没搞懂,最后发现他们连接的方式和阿里给的案例有所不同。于是开始研究阿里的文档,发现通过接入阿里云有很多方式,大致分为用SDK接入和协议自主接入要使用的就是MQTT协议(MQTT,HTTPS,COAP,ALINK)),而我们要使用的就是MQTT协议;而MQTT协议接入又分好几种只有企业版本支持MQTT5.0。

所以就剩下四种方式

MQTT-TLS : 设备和物联网平台使用发布/订阅模式的MQTT进行通信。

MQTT-WEBSOCKET :物联网平台支持基于WebSocket的MQTT协议,与浏览器上的应用程序通信。

MQTT-IPV6 :可以使用MQTT直连方式,直接接入物联网平台

这里选择使用MQTT-TLS协议接入最合适。

接入阿里云需要两个步骤:

首先通过http协议,建立TCP连接,这里我们需要复制一下

端口为:1883

然后复制MQTT连接参数:

最后复制下发布和订阅的主题:

三、STM32和ESP8266配置

        1.ESP8266配置

              ESP8266无需烧录MQTT固件,买来的ESP-01S模块直接用就行。

             (1)保证ESP8266正常使用,发送AT指令有回应。

              (2)保证STM32的串口与ESP8266能正常通信。

             (3)基本指令初始化

              (3)连接WIFI,可以是自己的热点,也可以是路由器,连上网就行。

        (4)连接网络节点,IP地址为刚刚获取的节点参数

        (5)ESP8266初始化完成。

2.STM32中间层配置

(1)需要文件,MQTT协议包,Ali云平台服务层,ESP8266驱动、Cjson。

连接步骤:

        (1)保证ESP8266与阿里云平台成功建立TCP连接。

        (2)传入MQTT连接参数,连接上阿里云

        

_Bool AliIOT_Link(void)
{
	MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0};					//协议包
	unsigned char *dataPtr;
	_Bool status = 1;
	UsartPrintf(USART_DEBUG, "AliIOT_Link\r\n"
							"USERNAME: %s,	PASSWD: %s,CLIENTID: %s\r\n"
                        , USERNAME,PASSWD,CLIENTID);
				//user:用户名:产品ID
				//password:密码:鉴权信息或apikey
				//devid:设备ID
				//cTime:连接保持时间
				//clean_session:离线消息清除标志
				//qos:重发标志
				//will_topic:异常离线topic
				//will_msg:异常离线消息
				//will_retain:消息推送标志
				//mqttPacket:包指针
	if(MQTT_PacketConnect(USERNAME, PASSWD, CLIENTID, 300, 0, MQTT_QOS_LEVEL0, NULL, NULL, 0, &mqttPacket) == 0)
	{
		
		ESP8266_SendData(mqttPacket._data, mqttPacket._len);			//上传平台
		
		dataPtr = ESP8266_GetIPD(250);									//等待平台响应
		if(dataPtr != NULL)
		{
			if(MQTT_UnPacketRecv(dataPtr) == MQTT_PKT_CONNACK)
			{
				switch(MQTT_UnPacketConnectAck(dataPtr))
				{
					case 0:UsartPrintf(USART_DEBUG, "Tips:	连接成功\r\n");status = 0;break;
					
					case 1:UsartPrintf(USART_DEBUG, "WARN:	连接失败:协议错误\r\n");break;
					case 2:UsartPrintf(USART_DEBUG, "WARN:	连接失败:非法的clientid\r\n");break;
					case 3:UsartPrintf(USART_DEBUG, "WARN:	连接失败:服务器失败\r\n");break;
					case 4:UsartPrintf(USART_DEBUG, "WARN:	连接失败:用户名或密码错误\r\n");break;
					case 5:UsartPrintf(USART_DEBUG, "WARN:	连接失败:非法链接(比如token非法)\r\n");break;
					
					default:UsartPrintf(USART_DEBUG, "ERR:	连接失败:未知错误\r\n");break;
				}
			}
		}
		
		MQTT_DeleteBuffer(&mqttPacket);								//删包
	}
	
	return status;
}

(3)发布消息

发布的消息数据格式可以在日志里面调试:

点击获取,在日志里面查看,得到发布数据格式。

sprintf(Pub_buf1,"{\"method\":\"thing.service.property.set\",\"id\":\"18591627\",\"params\":{\"LightSwitch\":%d,\"AlarmSwitch\":%d},\"version\":\"1.0.0\"}",LED2 ? 0:1,beep_flag);

ALiIOT_Publish(Pubtopic1,Pub_buf);
void ALiIOT_Publish(const char *topic, const char *msg)
{

	MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0};							//协议包
	
	UsartPrintf(USART_DEBUG, "Publish Topic: %s, Msg: %s\r\n", topic, msg);
		//	
		
		//入口参数:	pkt_id:pkt_id
		//topic:发布的topic
		//payload:消息体
		//payload_len:消息体长度
		//qos:重发次数
		//retain:离线消息推送
		//own:
		//mqttPacket:包指针
	if(MQTT_PacketPublish(MQTT_PUBLISH_ID, topic, msg, strlen(msg), MQTT_QOS_LEVEL0, 0, 1, &mqttPacket) == 0)
	{
		ESP8266_SendData(mqttPacket._data, mqttPacket._len);					//向平台发送订阅请求
		
		MQTT_DeleteBuffer(&mqttPacket);											//删包
	}

}

        已经在线连接成功了

(4)订阅消息

void AliIOT_Subscribe(const char *topics[], unsigned char topic_cnt)
{
	
//	unsigned char i = 0;
	
	MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0};							//协议包
	
	sprintf((char*)buf,"%s",*topics);
//	for(; i < topic_cnt; i++)
	UsartPrintf(USART_DEBUG, "Subscribe Topic: %s\r\n", buf);
			//入口参数:	pkt_id:pkt_id
			//qos:消息重发次数
			//topics:订阅的消息
			//topics_cnt:订阅的消息个数
			//mqttPacket:包指针
	if(MQTT_PacketSubscribe(MQTT_SUBSCRIBE_ID, MQTT_QOS_LEVEL0, topics, topic_cnt, &mqttPacket) == 0)
	{
		ESP8266_SendData(mqttPacket._data, mqttPacket._len);					//向平台发送订阅请求
		
		MQTT_DeleteBuffer(&mqttPacket);											//删包
	}

}

最后,后续还会开发微信小程序,APP。通过移动端远程控制STM32。

未完待续........

附录:

MQTT协议包;

mqtt.c

//协议头文件
#include "MqttKit.h"

//C库
#include <string.h>
#include <stdio.h>


#define CMD_TOPIC_PREFIX		"$creq"


//==========================================================
//	函数名称:	EDP_NewBuffer
//
//	函数功能:	申请内存
//
//	入口参数:	edpPacket:包结构体
//				size:大小
//
//	返回参数:	无
//
//	说明:		1.可使用动态分配来分配内存
//				2.可使用局部或全局数组来指定内存
//==========================================================
void MQTT_NewBuffer(MQTT_PACKET_STRUCTURE *mqttPacket, uint32 size)
{
	
	uint32 i = 0;

	if(mqttPacket->_data == NULL)
	{
		mqttPacket->_memFlag = MEM_FLAG_ALLOC;
		
		mqttPacket->_data = (uint8 *)MQTT_MallocBuffer(size);
		if(mqttPacket->_data != NULL)
		{
			mqttPacket->_len = 0;
			
			mqttPacket->_size = size;
			
			for(; i < mqttPacket->_size; i++)
				mqttPacket->_data[i] = 0;
		}
	}
	else
	{
		mqttPacket->_memFlag = MEM_FLAG_STATIC;
		
		for(; i < mqttPacket->_size; i++)
			mqttPacket->_data[i] = 0;
		
		mqttPacket->_len = 0;
		
		if(mqttPacket->_size < size)
			mqttPacket->_data = NULL;
	}

}

//==========================================================
//	函数名称:	MQTT_DeleteBuffer
//
//	函数功能:	释放数据内存
//
//	入口参数:	edpPacket:包结构体
//
//	返回参数:	无
//
//	说明:		
//==========================================================
void MQTT_DeleteBuffer(MQTT_PACKET_STRUCTURE *mqttPacket)
{

	if(mqttPacket->_memFlag == MEM_FLAG_ALLOC)
		MQTT_FreeBuffer(mqttPacket->_data);
	
	mqttPacket->_data = NULL;
	mqttPacket->_len = 0;
	mqttPacket->_size = 0;
	mqttPacket->_memFlag = MEM_FLAG_NULL;

}

int32 MQTT_DumpLength(size_t len, uint8 *buf)
{
	
	int32 i = 0;
	
	for(i = 1; i <= 4; ++i)
	{
		*buf = len % 128;
		len >>= 7;
		if(len > 0)
		{
			*buf |= 128;
			++buf;
		}
		else
		{
			return i;
		}
	}

	return -1;
}

int32 MQTT_ReadLength(const uint8 *stream, int32 size, uint32 *len)
{
	
	int32 i;
	const uint8 *in = stream;
	uint32 multiplier = 1;

	*len = 0;
	for(i = 0; i < size; ++i)
	{
		*len += (in[i] & 0x7f) * multiplier;

		if(!(in[i] & 0x80))
		{
			return i + 1;
		}

		multiplier <<= 7;
		if(multiplier >= 2097152)		//128 * *128 * *128
		{
			return -2;					// error, out of range
		}
	}

	return -1;							// not complete

}

//==========================================================
//	函数名称:	MQTT_UnPacketRecv
//
//	函数功能:	MQTT数据接收类型判断
//
//	入口参数:	dataPtr:接收的数据指针
//
//	返回参数:	0-成功		其他-失败原因
//
//	说明:		
//==========================================================
uint8 MQTT_UnPacketRecv(uint8 *dataPtr)
{
	
	uint8 status = 255;
	uint8 type = dataPtr[0] >> 4;				//类型检查
	
	if(type < 1 || type > 14)
		return status;
	
	if(type == MQTT_PKT_PUBLISH)
	{
		uint8 *msgPtr;
		uint32 remain_len = 0;
		
		msgPtr = dataPtr + MQTT_ReadLength(dataPtr + 1, 4, &remain_len) + 1;
		
		if(remain_len < 2 || dataPtr[0] & 0x01)					//retain
			return 255;
		
		if(remain_len < ((uint16)msgPtr[0] << 8 | msgPtr[1]) + 2)
			return 255;
		
		if(strstr((int8 *)msgPtr + 2, CMD_TOPIC_PREFIX) != NULL)	//如果是命令下发
			status = MQTT_PKT_CMD;
		else
			status = MQTT_PKT_PUBLISH;
	}
	else
		status = type;
	
	return status;

}

//==========================================================
//	函数名称:	MQTT_PacketConnect
//
//	函数功能:	连接消息组包
//
//	入口参数:	user:用户名:产品ID
//				password:密码:鉴权信息或apikey
//				devid:设备ID
//				cTime:连接保持时间
//				clean_session:离线消息清除标志
//				qos:重发标志
//				will_topic:异常离线topic
//				will_msg:异常离线消息
//				will_retain:消息推送标志
//				mqttPacket:包指针
//
//	返回参数:	0-成功		其他-失败
//
//	说明:		
//==========================================================
uint8 MQTT_PacketConnect(const int8 *user, const int8 *password, const int8 *devid,
						uint16 cTime, uint1 clean_session, uint1 qos,
						const int8 *will_topic, const int8 *will_msg, int32 will_retain,
						MQTT_PACKET_STRUCTURE *mqttPacket)
{
	
	uint8 flags = 0;
	uint8 will_topic_len = 0;
	uint16 total_len = 15;
	int16 len = 0, devid_len = strlen(devid);
	
	if(!devid)
		return 1;
	
	total_len += devid_len + 2;
	
	//断线后,是否清理离线消息:1-清理	0-不清理--------------------------------------------
	if(clean_session)
	{
		flags |= MQTT_CONNECT_CLEAN_SESSION;
	}
	
	//异常掉线情况下,服务器发布的topic------------------------------------------------------
	if(will_topic)
	{
		flags |= MQTT_CONNECT_WILL_FLAG;
		will_topic_len = strlen(will_topic);
		total_len += 4 + will_topic_len + strlen(will_msg);
	}
	
	//qos级别--主要用于PUBLISH(发布态)消息的,保证消息传递的次数-----------------------------
	switch((unsigned char)qos)
	{
		case MQTT_QOS_LEVEL0:
			flags |= MQTT_CONNECT_WILL_QOS0;							//最多一次
		break;
		
		case MQTT_QOS_LEVEL1:
			flags |= (MQTT_CONNECT_WILL_FLAG | MQTT_CONNECT_WILL_QOS1);	//最少一次
		break;
		
		case MQTT_QOS_LEVEL2:
			flags |= (MQTT_CONNECT_WILL_FLAG | MQTT_CONNECT_WILL_QOS2);	//只有一次
		break;
		
		default:
		return 2;
	}
	
	//主要用于PUBLISH(发布态)的消息,表示服务器要保留这次推送的信息,如果有新的订阅者出现,就把这消息推送给它。如果不设那么推送至当前订阅的就释放了
	if(will_retain)
	{
		flags |= (MQTT_CONNECT_WILL_FLAG | MQTT_CONNECT_WILL_RETAIN);
	}
	
	//账号为空 密码为空---------------------------------------------------------------------
	if(!user || !password)
	{
		return 3;
	}
	flags |= MQTT_CONNECT_USER_NAME | MQTT_CONNECT_PASSORD;
	
	total_len += strlen(user) + strlen(password) + 4;
	
	//分配内存-----------------------------------------------------------------------------
	MQTT_NewBuffer(mqttPacket, total_len);
	if(mqttPacket->_data == NULL)
		return 4;
	
	memset(mqttPacket->_data, 0, total_len);
	
/*************************************固定头部***********************************************/
	
	//固定头部----------------------连接请求类型---------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_CONNECT << 4;
	
	//固定头部----------------------剩余长度值-----------------------------------------------
	len = MQTT_DumpLength(total_len - 5, mqttPacket->_data + mqttPacket->_len);
	if(len < 0)
	{
		MQTT_DeleteBuffer(mqttPacket);
		return 5;
	}
	else
		mqttPacket->_len += len;
	
/*************************************可变头部***********************************************/
	
	//可变头部----------------------协议名长度 和 协议名--------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = 0;
	mqttPacket->_data[mqttPacket->_len++] = 4;
	mqttPacket->_data[mqttPacket->_len++] = 'M';
	mqttPacket->_data[mqttPacket->_len++] = 'Q';
	mqttPacket->_data[mqttPacket->_len++] = 'T';
	mqttPacket->_data[mqttPacket->_len++] = 'T';
	
	//可变头部----------------------protocol level 4-----------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = 4;
	
	//可变头部----------------------连接标志(该函数开头处理的数据)-----------------------------
    mqttPacket->_data[mqttPacket->_len++] = flags;
	
	//可变头部----------------------保持连接的时间(秒)----------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(cTime);
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(cTime);
	 
/*************************************消息体************************************************/

	//消息体----------------------------devid长度、devid-------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(devid_len);
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(devid_len);
	
	strncat((int8 *)mqttPacket->_data + mqttPacket->_len, devid, devid_len);
	mqttPacket->_len += devid_len;
	
	//消息体----------------------------will_flag 和 will_msg---------------------------------
	if(flags & MQTT_CONNECT_WILL_FLAG)
	{
		unsigned short mLen = 0;
		
		if(!will_msg)
			will_msg = "";
		
		mLen = strlen(will_topic);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(mLen);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(mLen);
		strncat((int8 *)mqttPacket->_data + mqttPacket->_len, will_topic, mLen);
		mqttPacket->_len += mLen;
		
		mLen = strlen(will_msg);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(mLen);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(mLen);
		strncat((int8 *)mqttPacket->_data + mqttPacket->_len, will_msg, mLen);
		mqttPacket->_len += mLen;
	}
	
	//消息体----------------------------use---------------------------------------------------
	if(flags & MQTT_CONNECT_USER_NAME)
	{
		unsigned short user_len = strlen(user);
		
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(user_len);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(user_len);
		strncat((int8 *)mqttPacket->_data + mqttPacket->_len, user, user_len);
		mqttPacket->_len += user_len;
	}

	//消息体----------------------------password----------------------------------------------
	if(flags & MQTT_CONNECT_PASSORD)
	{
		unsigned short psw_len = strlen(password);
		
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(psw_len);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(psw_len);
		strncat((int8 *)mqttPacket->_data + mqttPacket->_len, password, psw_len);
		mqttPacket->_len += psw_len;
	}

	return 0;

}

//==========================================================
//	函数名称:	MQTT_PacketDisConnect
//
//	函数功能:	断开连接消息组包
//
//	入口参数:	mqttPacket:包指针
//
//	返回参数:	0-成功		1-失败
//
//	说明:		
//==========================================================
uint1 MQTT_PacketDisConnect(MQTT_PACKET_STRUCTURE *mqttPacket)
{

	MQTT_NewBuffer(mqttPacket, 2);
	if(mqttPacket->_data == NULL)
		return 1;
	
/*************************************固定头部***********************************************/
	
	//固定头部----------------------头部消息-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_DISCONNECT << 4;
	
	//固定头部----------------------剩余长度值-----------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = 0;
	
	return 0;

}

//==========================================================
//	函数名称:	MQTT_UnPacketConnectAck
//
//	函数功能:	连接消息解包
//
//	入口参数:	rev_data:接收的数据
//
//	返回参数:	1、255-失败		其他-平台的返回码
//
//	说明:		
//==========================================================
uint8 MQTT_UnPacketConnectAck(uint8 *rev_data)
{

	if(rev_data[1] != 2)
		return 1;
	
	if(rev_data[2] == 0 || rev_data[2] == 1)
		return rev_data[3];
	else
		return 255;

}

//==========================================================
//	函数名称:	MQTT_PacketSaveData
//
//	函数功能:	数据点上传组包
//
//	入口参数:	devid:设备ID(可为空)
//				send_buf:json缓存buf
//				send_len:json总长
//				type_bin_head:bin文件的消息头
//				type:类型
//
//	返回参数:	0-成功		1-失败
//
//	说明:		
//==========================================================
uint1 MQTT_PacketSaveData(const int8 *devid, int16 send_len, int8 *type_bin_head, uint8 type, MQTT_PACKET_STRUCTURE *mqttPacket)
{

	if(MQTT_PacketPublish(MQTT_PUBLISH_ID, "$dp", NULL, send_len + 3, MQTT_QOS_LEVEL1, 0, 1, mqttPacket) == 0)
	{
		mqttPacket->_data[mqttPacket->_len++] = type;					//类型
		
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(send_len);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(send_len);
	}
	else
		return 1;
	
	return 0;

}

//==========================================================
//	函数名称:	MQTT_PacketSaveBinData
//
//	函数功能:	为禁止文件上传组包
//
//	入口参数:	name:数据流名字
//				file_len:文件长度
//				mqttPacket:包指针
//
//	返回参数:	0-成功		1-失败
//
//	说明:		
//==========================================================
uint1 MQTT_PacketSaveBinData(const int8 *name, int16 file_len, MQTT_PACKET_STRUCTURE *mqttPacket)
{

	uint1 result = 1;
	int8 *bin_head = NULL;
	uint8 bin_head_len = 0;
	int8 *payload = NULL;
	int32 payload_size = 0;
	
	bin_head = (int8 *)MQTT_MallocBuffer(13 + strlen(name));
	if(bin_head == NULL)
		return result;
	
	sprintf(bin_head, "{\"ds_id\":\"%s\"}", name);
	
	bin_head_len = strlen(bin_head);
	payload_size = 7 + bin_head_len + file_len;
	
	payload = (int8 *)MQTT_MallocBuffer(payload_size - file_len);
	if(payload == NULL)
	{
		MQTT_FreeBuffer(bin_head);
		
		return result;
	}
	
	payload[0] = 2;						//类型
		
	payload[1] = MOSQ_MSB(bin_head_len);
	payload[2] = MOSQ_LSB(bin_head_len);
	
	memcpy(payload + 3, bin_head, bin_head_len);
	
	payload[bin_head_len + 3] = (file_len >> 24) & 0xFF;
	payload[bin_head_len + 4] = (file_len >> 16) & 0xFF;
	payload[bin_head_len + 5] = (file_len >> 8) & 0xFF;
	payload[bin_head_len + 6] = file_len & 0xFF;
	
	if(MQTT_PacketPublish(MQTT_PUBLISH_ID, "$dp", payload, payload_size, MQTT_QOS_LEVEL1, 0, 1, mqttPacket) == 0)
		result = 0;
	
	MQTT_FreeBuffer(bin_head);
	MQTT_FreeBuffer(payload);
	
	return result;

}

//==========================================================
//	函数名称:	MQTT_UnPacketCmd
//
//	函数功能:	命令下发解包
//
//	入口参数:	rev_data:接收的数据指针
//				cmdid:cmdid-uuid
//				req:命令
//
//	返回参数:	0-成功		其他-失败原因
//
//	说明:		
//==========================================================
uint8 MQTT_UnPacketCmd(uint8 *rev_data, int8 **cmdid, int8 **req, uint16 *req_len)
{

	int8 *dataPtr = strchr((int8 *)rev_data + 6, '/');	//加6是跳过头信息
	
	uint32 remain_len = 0;
	
	if(dataPtr == NULL)									//未找到'/'
		return 1;
	dataPtr++;											//跳过'/'
	
	MQTT_ReadLength(rev_data + 1, 4, &remain_len);		//读取剩余字节
	
	*cmdid = (int8 *)MQTT_MallocBuffer(37);				//cmdid固定36字节,多分配一个结束符的位置
	if(*cmdid == NULL)
		return 2;
	
	memset(*cmdid, 0, 37);								//全部清零
	memcpy(*cmdid, (const int8 *)dataPtr, 36);			//复制cmdid
	dataPtr += 36;
	
	*req_len = remain_len - 44;							//命令长度 = 剩余长度(remain_len) - 2 - 5($creq) - 1(\) - cmdid长度
	*req = (int8 *)MQTT_MallocBuffer(*req_len + 1);		//分配命令长度+1
	if(*req == NULL)
	{
		MQTT_FreeBuffer(*cmdid);
		return 3;
	}
	
	memset(*req, 0, *req_len + 1);						//清零
	memcpy(*req, (const int8 *)dataPtr, *req_len);		//复制命令
	
	return 0;

}

//==========================================================
//	函数名称:	MQTT_PacketCmdResp
//
//	函数功能:	命令回复组包
//
//	入口参数:	cmdid:cmdid
//				req:命令
//				mqttPacket:包指针
//
//	返回参数:	0-成功		1-失败
//
//	说明:		
//==========================================================
uint1 MQTT_PacketCmdResp(const int8 *cmdid, const int8 *req, MQTT_PACKET_STRUCTURE *mqttPacket)
{
	
	uint16 cmdid_len = strlen(cmdid);
	uint16 req_len = strlen(req);
	_Bool status = 0;
	
	int8 *payload = MQTT_MallocBuffer(cmdid_len + 7);
	if(payload == NULL)
		return 1;
	
	memset(payload, 0, cmdid_len + 7);
	memcpy(payload, "$crsp/", 6);
	strncat(payload, cmdid, cmdid_len);

	if(MQTT_PacketPublish(MQTT_PUBLISH_ID, payload, req, strlen(req), MQTT_QOS_LEVEL0, 0, 1, mqttPacket) == 0)
		status = 0;
	else
		status = 1;
	
	MQTT_FreeBuffer(payload);
	
	return status;

}

//==========================================================
//	函数名称:	MQTT_PacketSubscribe
//
//	函数功能:	Subscribe消息组包
//
//	入口参数:	pkt_id:pkt_id
//				qos:消息重发次数
//				topics:订阅的消息
//				topics_cnt:订阅的消息个数
//				mqttPacket:包指针
//
//	返回参数:	0-成功		其他-失败
//
//	说明:		
//==========================================================
uint8 MQTT_PacketSubscribe(uint16 pkt_id, enum MqttQosLevel qos, const int8 *topics[], uint8 topics_cnt, MQTT_PACKET_STRUCTURE *mqttPacket)
{
	
	uint32 topic_len = 0, remain_len = 0;
	int16 len = 0;
	uint8 i = 0;
	
	if(pkt_id == 0)
		return 1;
	
	//计算topic长度-------------------------------------------------------------------------
	for(; i < topics_cnt; i++)
	{
		if(topics[i] == NULL)
			return 2;
		
		topic_len += strlen(topics[i]);
	}
	
	//2 bytes packet id + topic filter(2 bytes topic + topic length + 1 byte reserve)------
	remain_len = 2 + 3 * topics_cnt + topic_len;
	
	//分配内存------------------------------------------------------------------------------
	MQTT_NewBuffer(mqttPacket, remain_len + 5);
	if(mqttPacket->_data == NULL)
		return 3;
	
/*************************************固定头部***********************************************/
	
	//固定头部----------------------头部消息-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_SUBSCRIBE << 4 | 0x02;
	
	//固定头部----------------------剩余长度值-----------------------------------------------
	len = MQTT_DumpLength(remain_len, mqttPacket->_data + mqttPacket->_len);
	if(len < 0)
	{
		MQTT_DeleteBuffer(mqttPacket);
		return 4;
	}
	else
		mqttPacket->_len += len;
	
/*************************************payload***********************************************/
	
	//payload----------------------pkt_id---------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(pkt_id);
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(pkt_id);
	
	//payload----------------------topic_name-----------------------------------------------
	for(i = 0; i < topics_cnt; i++)
	{
		topic_len = strlen(topics[i]);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(topic_len);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(topic_len);
		
		strncat((int8 *)mqttPacket->_data + mqttPacket->_len, topics[i], topic_len);
		mqttPacket->_len += topic_len;
		
		mqttPacket->_data[mqttPacket->_len++] = qos & 0xFF;
	}

	return 0;

}

//==========================================================
//	函数名称:	MQTT_UnPacketSubscrebe
//
//	函数功能:	Subscribe的回复消息解包
//
//	入口参数:	rev_data:接收到的信息
//
//	返回参数:	0-成功		其他-失败
//
//	说明:		
//==========================================================
uint8 MQTT_UnPacketSubscribe(uint8 *rev_data)
{
	
	uint8 result = 255;

	if(rev_data[2] == MOSQ_MSB(MQTT_SUBSCRIBE_ID) && rev_data[3] == MOSQ_LSB(MQTT_SUBSCRIBE_ID))
	{
		switch(rev_data[4])
		{
			case 0x00:
			case 0x01:
			case 0x02:
				//MQTT Subscribe OK
				result = 0;
			break;
			
			case 0x80:
				//MQTT Subscribe Failed
				result = 1;
			break;
			
			default:
				//MQTT Subscribe UnKnown Err
				result = 2;
			break;
		}
	}
	
	return result;

}

//==========================================================
//	函数名称:	MQTT_PacketUnSubscribe
//
//	函数功能:	UnSubscribe消息组包
//
//	入口参数:	pkt_id:pkt_id
//				qos:消息重发次数
//				topics:订阅的消息
//				topics_cnt:订阅的消息个数
//				mqttPacket:包指针
//
//	返回参数:	0-成功		其他-失败
//
//	说明:		
//==========================================================
uint8 MQTT_PacketUnSubscribe(uint16 pkt_id, const int8 *topics[], uint8 topics_cnt, MQTT_PACKET_STRUCTURE *mqttPacket)
{
	
	uint32 topic_len = 0, remain_len = 0;
	int16 len = 0;
	uint8 i = 0;
	
	if(pkt_id == 0)
		return 1;
	
	//计算topic长度-------------------------------------------------------------------------
	for(; i < topics_cnt; i++)
	{
		if(topics[i] == NULL)
			return 2;
		
		topic_len += strlen(topics[i]);
	}
	
	//2 bytes packet id, 2 bytes topic length + topic + 1 byte reserve---------------------
	remain_len = 2 + (topics_cnt << 1) + topic_len;
	
	//分配内存------------------------------------------------------------------------------
	MQTT_NewBuffer(mqttPacket, remain_len + 5);
	if(mqttPacket->_data == NULL)
		return 3;
	
/*************************************固定头部***********************************************/
	
	//固定头部----------------------头部消息-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_UNSUBSCRIBE << 4 | 0x02;
	
	//固定头部----------------------剩余长度值-----------------------------------------------
	len = MQTT_DumpLength(remain_len, mqttPacket->_data + mqttPacket->_len);
	if(len < 0)
	{
		MQTT_DeleteBuffer(mqttPacket);
		return 4;
	}
	else
		mqttPacket->_len += len;
	
/*************************************payload***********************************************/
	
	//payload----------------------pkt_id---------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(pkt_id);
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(pkt_id);
	
	//payload----------------------topic_name-----------------------------------------------
	for(i = 0; i < topics_cnt; i++)
	{
		topic_len = strlen(topics[i]);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(topic_len);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(topic_len);
		
		strncat((int8 *)mqttPacket->_data + mqttPacket->_len, topics[i], topic_len);
		mqttPacket->_len += topic_len;
	}

	return 0;

}

//==========================================================
//	函数名称:	MQTT_UnPacketUnSubscribe
//
//	函数功能:	UnSubscribe的回复消息解包
//
//	入口参数:	rev_data:接收到的信息
//
//	返回参数:	0-成功		其他-失败
//
//	说明:		
//==========================================================
uint1 MQTT_UnPacketUnSubscribe(uint8 *rev_data)
{
	
	uint1 result = 1;

	if(rev_data[2] == MOSQ_MSB(MQTT_UNSUBSCRIBE_ID) && rev_data[3] == MOSQ_LSB(MQTT_UNSUBSCRIBE_ID))
	{
		result = 0;
	}
	
	return result;

}

//==========================================================
//	函数名称:	MQTT_PacketPublish
//
//	函数功能:	Pulish消息组包
//
//	入口参数:	pkt_id:pkt_id
//				topic:发布的topic
//				payload:消息体
//				payload_len:消息体长度
//				qos:重发次数
//				retain:离线消息推送
//				own:
//				mqttPacket:包指针
//
//	返回参数:	0-成功		其他-失败
//
//	说明:		
//==========================================================
uint8 MQTT_PacketPublish(uint16 pkt_id, const int8 *topic,
						const int8 *payload, uint32 payload_len,
						enum MqttQosLevel qos, int32 retain, int32 own,
						MQTT_PACKET_STRUCTURE *mqttPacket)
{

	uint32 total_len = 0, topic_len = 0;
	uint32 data_len = 0;
	int32 len = 0;
	uint8 flags = 0;
	
	//pkt_id检查----------------------------------------------------------------------------
	if(pkt_id == 0)
		return 1;
	
	//$dp为系统上传数据点的指令--------------------------------------------------------------
	for(topic_len = 0; topic[topic_len] != '\0'; ++topic_len)
	{
		if((topic[topic_len] == '#') || (topic[topic_len] == '+'))
			return 2;
	}
	
	//Publish消息---------------------------------------------------------------------------
	flags |= MQTT_PKT_PUBLISH << 4;
	
	//retain标志----------------------------------------------------------------------------
	if(retain)
		flags |= 0x01;
	
	//总长度--------------------------------------------------------------------------------
	total_len = topic_len + payload_len + 2;
	
	//qos级别--主要用于PUBLISH(发布态)消息的,保证消息传递的次数-----------------------------
	switch(qos)
	{
		case MQTT_QOS_LEVEL0:
			flags |= MQTT_CONNECT_WILL_QOS0;	//最多一次
		break;
		
		case MQTT_QOS_LEVEL1:
			flags |= 0x02;						//最少一次
			total_len += 2;
		break;
		
		case MQTT_QOS_LEVEL2:
			flags |= 0x04;						//只有一次
			total_len += 2;
		break;
		
		default:
		return 3;
	}
	
	//分配内存------------------------------------------------------------------------------
	if(payload != NULL)
	{
		if(payload[0] == 2)
		{
			uint32 data_len_t = 0;
			
			while(payload[data_len_t++] != '}');
			data_len_t -= 3;
			data_len = data_len_t + 7;
			data_len_t = payload_len - data_len;
			
			MQTT_NewBuffer(mqttPacket, total_len + 3 - data_len_t);
			
			if(mqttPacket->_data == NULL)
				return 4;
			
			memset(mqttPacket->_data, 0, total_len + 3 - data_len_t);
		}
		else
		{
			MQTT_NewBuffer(mqttPacket, total_len + 5);
			
			if(mqttPacket->_data == NULL)
				return 4;
			
			memset(mqttPacket->_data, 0, total_len + 5);
		}
	}
	else
	{
		MQTT_NewBuffer(mqttPacket, total_len + 5);
		
		if(mqttPacket->_data == NULL)
			return 4;
		
		memset(mqttPacket->_data, 0, total_len + 5);
	}
	
/*************************************固定头部***********************************************/
	
	//固定头部----------------------头部消息-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = flags;
	
	//固定头部----------------------剩余长度值-----------------------------------------------
	len = MQTT_DumpLength(total_len, mqttPacket->_data + mqttPacket->_len);
	if(len < 0)
	{
		MQTT_DeleteBuffer(mqttPacket);
		return 5;
	}
	else
		mqttPacket->_len += len;
	
/*************************************可变头部***********************************************/
	
	//可变头部----------------------写入topic长度、topic-------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(topic_len);
	mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(topic_len);
	
	strncat((int8 *)mqttPacket->_data + mqttPacket->_len, topic, topic_len);
	mqttPacket->_len += topic_len;
	if(qos != MQTT_QOS_LEVEL0)
	{
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(pkt_id);
		mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(pkt_id);
	}
	
	//可变头部----------------------写入payload----------------------------------------------
	if(payload != NULL)
	{
		if(payload[0] == 2)
		{
			memcpy((int8 *)mqttPacket->_data + mqttPacket->_len, payload, data_len);
			mqttPacket->_len += data_len;
		}
		else
		{
			memcpy((int8 *)mqttPacket->_data + mqttPacket->_len, payload, payload_len);
			mqttPacket->_len += payload_len;
		}
	}
	
	return 0;

}

//==========================================================
//	函数名称:	MQTT_UnPacketPublish
//
//	函数功能:	Publish消息解包
//
//	入口参数:	flags:MQTT相关标志信息
//				pkt:指向可变头部
//				size:固定头部中的剩余长度信息
//
//	返回参数:	0-成功		其他-失败原因
//
//	说明:		
//==========================================================
uint8 MQTT_UnPacketPublish(uint8 *rev_data, int8 **topic, uint16 *topic_len, int8 **payload, uint16 *payload_len, uint8 *qos, uint16 *pkt_id)
{
	
	const int8 flags = rev_data[0] & 0x0F;
	uint8 *msgPtr;
	uint32 remain_len = 0;

	const int8 dup = flags & 0x08;

	*qos = (flags & 0x06) >> 1;
	
	msgPtr = rev_data + MQTT_ReadLength(rev_data + 1, 4, &remain_len) + 1;
	
	if(remain_len < 2 || flags & 0x01)							//retain
		return 255;
	
	*topic_len = (uint16)msgPtr[0] << 8 | msgPtr[1];
	if(remain_len < *topic_len + 2)
		return 255;
	
	if(strstr((int8 *)msgPtr + 2, CMD_TOPIC_PREFIX) != NULL)	//如果是命令下发
		return MQTT_PKT_CMD;
	
	switch(*qos)
	{
		case MQTT_QOS_LEVEL0:									// qos0 have no packet identifier
			
			if(0 != dup)
				return 255;

			*topic = MQTT_MallocBuffer(*topic_len + 1);			//为topic分配内存
			if(*topic == NULL)
				return 255;
			
			memset(*topic, 0, *topic_len + 1);
			memcpy(*topic, (int8 *)msgPtr + 2, *topic_len);		//复制数据
			
			*payload_len = remain_len - 2 - *topic_len;			//为payload分配内存
			*payload = MQTT_MallocBuffer(*payload_len + 1);
			if(*payload == NULL)								//如果失败
			{
				MQTT_FreeBuffer(*topic);						//则需要把topic的内存释放掉
				return 255;
			}
			
			memset(*payload, 0, *payload_len + 1);
			memcpy(*payload, (int8 *)msgPtr + 2 + *topic_len, *payload_len);
			
		break;

		case MQTT_QOS_LEVEL1:
		case MQTT_QOS_LEVEL2:
			
			if(*topic_len + 2 > remain_len)
				return 255;
			
			*pkt_id = (uint16)msgPtr[*topic_len + 2] << 8 | msgPtr[*topic_len + 3];
			if(pkt_id == 0)
				return 255;
			
			*topic = MQTT_MallocBuffer(*topic_len + 1);			//为topic分配内存
			if(*topic == NULL)
				return 255;
			
			memset(*topic, 0, *topic_len + 1);
			memcpy(*topic, (int8 *)msgPtr + 2, *topic_len);		//复制数据
			
			*payload_len = remain_len - 4 - *topic_len;
			*payload = MQTT_MallocBuffer(*payload_len + 1);		//为payload分配内存
			if(*payload == NULL)								//如果失败
			{
				MQTT_FreeBuffer(*topic);						//则需要把topic的内存释放掉
				return 255;
			}
			
			memset(*payload, 0, *payload_len + 1);
			memcpy(*payload, (int8 *)msgPtr + 4 + *topic_len, *payload_len);
			
		break;

		default:
			return 255;
	}
	
	if(strchr((int8 *)topic, '+') || strchr((int8 *)topic, '#'))
		return 255;

	return 0;

}

//==========================================================
//	函数名称:	MQTT_PacketPublishAck
//
//	函数功能:	Publish Ack消息组包
//
//	入口参数:	pkt_id:packet id
//				mqttPacket:包指针
//
//	返回参数:	0-成功		1-失败原因
//
//	说明:		当收到的Publish消息的QoS等级为1时,需要Ack回复
//==========================================================
uint1 MQTT_PacketPublishAck(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket)
{

	MQTT_NewBuffer(mqttPacket, 4);
	if(mqttPacket->_data == NULL)
		return 1;
	
/*************************************固定头部***********************************************/
	
	//固定头部----------------------头部消息-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_PUBACK << 4;
	
	//固定头部----------------------剩余长度-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = 2;
	
/*************************************可变头部***********************************************/
	
	//可变头部----------------------pkt_id长度-----------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = pkt_id >> 8;
	mqttPacket->_data[mqttPacket->_len++] = pkt_id & 0xff;
	
	return 0;

}

//==========================================================
//	函数名称:	MQTT_UnPacketPublishAck
//
//	函数功能:	Publish Ack消息解包
//
//	入口参数:	rev_data:收到的数据
//
//	返回参数:	0-成功		1-失败原因
//
//	说明:		
//==========================================================
uint1 MQTT_UnPacketPublishAck(uint8 *rev_data)
{

	if(rev_data[1] != 2)
		return 1;

	if(rev_data[2] == MOSQ_MSB(MQTT_PUBLISH_ID) && rev_data[3] == MOSQ_LSB(MQTT_PUBLISH_ID))
		return 0;
	else
		return 1;

}

//==========================================================
//	函数名称:	MQTT_PacketPublishRec
//
//	函数功能:	Publish Rec消息组包
//
//	入口参数:	pkt_id:packet id
//				mqttPacket:包指针
//
//	返回参数:	0-成功		1-失败原因
//
//	说明:		当收到的Publish消息的QoS等级为2时,先收到rec
//==========================================================
uint1 MQTT_PacketPublishRec(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket)
{

	MQTT_NewBuffer(mqttPacket, 4);
	if(mqttPacket->_data == NULL)
		return 1;
	
/*************************************固定头部***********************************************/
	
	//固定头部----------------------头部消息-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_PUBREC << 4;
	
	//固定头部----------------------剩余长度-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = 2;
	
/*************************************可变头部***********************************************/
	
	//可变头部----------------------pkt_id长度-----------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = pkt_id >> 8;
	mqttPacket->_data[mqttPacket->_len++] = pkt_id & 0xff;
	
	return 0;

}

//==========================================================
//	函数名称:	MQTT_UnPacketPublishRec
//
//	函数功能:	Publish Rec消息解包
//
//	入口参数:	rev_data:接收到的数据
//
//	返回参数:	0-成功		1-失败
//
//	说明:		
//==========================================================
uint1 MQTT_UnPacketPublishRec(uint8 *rev_data)
{

	if(rev_data[1] != 2)
		return 1;

	if(rev_data[2] == MOSQ_MSB(MQTT_PUBLISH_ID) && rev_data[3] == MOSQ_LSB(MQTT_PUBLISH_ID))
		return 0;
	else
		return 1;

}

//==========================================================
//	函数名称:	MQTT_PacketPublishRel
//
//	函数功能:	Publish Rel消息组包
//
//	入口参数:	pkt_id:packet id
//				mqttPacket:包指针
//
//	返回参数:	0-成功		1-失败原因
//
//	说明:		当收到的Publish消息的QoS等级为2时,先收到rec,再回复rel
//==========================================================
uint1 MQTT_PacketPublishRel(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket)
{

	MQTT_NewBuffer(mqttPacket, 4);
	if(mqttPacket->_data == NULL)
		return 1;
	
/*************************************固定头部***********************************************/
	
	//固定头部----------------------头部消息-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_PUBREL << 4 | 0x02;
	
	//固定头部----------------------剩余长度-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = 2;
	
/*************************************可变头部***********************************************/
	
	//可变头部----------------------pkt_id长度-----------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = pkt_id >> 8;
	mqttPacket->_data[mqttPacket->_len++] = pkt_id & 0xff;
	
	return 0;

}

//==========================================================
//	函数名称:	MQTT_UnPacketPublishRel
//
//	函数功能:	Publish Rel消息解包
//
//	入口参数:	rev_data:接收到的数据
//
//	返回参数:	0-成功		1-失败
//
//	说明:		
//==========================================================
uint1 MQTT_UnPacketPublishRel(uint8 *rev_data, uint16 pkt_id)
{

	if(rev_data[1] != 2)
		return 1;

	if(rev_data[2] == MOSQ_MSB(pkt_id) && rev_data[3] == MOSQ_LSB(pkt_id))
		return 0;
	else
		return 1;

}

//==========================================================
//	函数名称:	MQTT_PacketPublishComp
//
//	函数功能:	Publish Comp消息组包
//
//	入口参数:	pkt_id:packet id
//				mqttPacket:包指针
//
//	返回参数:	0-成功		1-失败原因
//
//	说明:		当收到的Publish消息的QoS等级为2时,先收到rec,再回复rel
//==========================================================
uint1 MQTT_PacketPublishComp(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket)
{

	MQTT_NewBuffer(mqttPacket, 4);
	if(mqttPacket->_data == NULL)
		return 1;
	
/*************************************固定头部***********************************************/
	
	//固定头部----------------------头部消息-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_PUBCOMP << 4;
	
	//固定头部----------------------剩余长度-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = 2;
	
/*************************************可变头部***********************************************/
	
	//可变头部----------------------pkt_id长度-----------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = pkt_id >> 8;
	mqttPacket->_data[mqttPacket->_len++] = pkt_id & 0xff;
	
	return 0;

}

//==========================================================
//	函数名称:	MQTT_UnPacketPublishComp
//
//	函数功能:	Publish Comp消息解包
//
//	入口参数:	rev_data:接收到的数据
//
//	返回参数:	0-成功		1-失败
//
//	说明:		
//==========================================================
uint1 MQTT_UnPacketPublishComp(uint8 *rev_data)
{

	if(rev_data[1] != 2)
		return 1;

	if(rev_data[2] == MOSQ_MSB(MQTT_PUBLISH_ID) && rev_data[3] == MOSQ_LSB(MQTT_PUBLISH_ID))
		return 0;
	else
		return 1;

}

//==========================================================
//	函数名称:	MQTT_PacketPing
//
//	函数功能:	心跳请求组包
//
//	入口参数:	mqttPacket:包指针
//
//	返回参数:	0-成功		1-失败
//
//	说明:		
//==========================================================
uint1 MQTT_PacketPing(MQTT_PACKET_STRUCTURE *mqttPacket)
{

	MQTT_NewBuffer(mqttPacket, 2);
	if(mqttPacket->_data == NULL)
		return 1;
	
/*************************************固定头部***********************************************/
	
	//固定头部----------------------头部消息-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_PINGREQ << 4;
	
	//固定头部----------------------剩余长度-------------------------------------------------
	mqttPacket->_data[mqttPacket->_len++] = 0;
	
	return 0;

}

mqtt.h

#ifndef _MQTTKIT_H_
#define _MQTTKIT_H_


#include "Common.h"


//=============================配置==============================
//===========可以提供RTOS的内存管理方案,也可以使用C库的=========
//RTOS
#include <stdlib.h>

#define MQTT_MallocBuffer	malloc

#define MQTT_FreeBuffer		free
//==========================================================


#define MOSQ_MSB(A)         (uint8)((A & 0xFF00) >> 8)
#define MOSQ_LSB(A)         (uint8)(A & 0x00FF)


/*--------------------------------内存分配方案标志--------------------------------*/
#define MEM_FLAG_NULL		0
#define MEM_FLAG_ALLOC		1
#define MEM_FLAG_STATIC		2


typedef struct Buffer
{
	
	uint8	*_data;		//协议数据
	
	uint32	_len;		//写入的数据长度
	
	uint32	_size;		//缓存总大小
	
	uint8	_memFlag;	//内存使用的方案:0-未分配	1-使用的动态分配		2-使用的固定内存
	
} MQTT_PACKET_STRUCTURE;


/*--------------------------------固定头部消息类型--------------------------------*/
enum MqttPacketType
{
	
    MQTT_PKT_CONNECT = 1, /**< 连接请求数据包 */
    MQTT_PKT_CONNACK,     /**< 连接确认数据包 */
    MQTT_PKT_PUBLISH,     /**< 发布数据数据包 */
    MQTT_PKT_PUBACK,      /**< 发布确认数据包 */
    MQTT_PKT_PUBREC,      /**< 发布数据已接收数据包,Qos 2时,回复MQTT_PKT_PUBLISH */
    MQTT_PKT_PUBREL,      /**< 发布数据释放数据包, Qos 2时,回复MQTT_PKT_PUBREC */
    MQTT_PKT_PUBCOMP,     /**< 发布完成数据包, Qos 2时,回复MQTT_PKT_PUBREL */
    MQTT_PKT_SUBSCRIBE,   /**< 订阅数据包 */
    MQTT_PKT_SUBACK,      /**< 订阅确认数据包 */
    MQTT_PKT_UNSUBSCRIBE, /**< 取消订阅数据包 */
    MQTT_PKT_UNSUBACK,    /**< 取消订阅确认数据包 */
    MQTT_PKT_PINGREQ,     /**< ping 数据包 */
    MQTT_PKT_PINGRESP,    /**< ping 响应数据包 */
    MQTT_PKT_DISCONNECT,  /**< 断开连接数据包 */
	
	//新增
	
	MQTT_PKT_CMD  		 /**< 命令下发数据包 */
	
};


/*--------------------------------MQTT QOS等级--------------------------------*/
enum MqttQosLevel
{
	
    MQTT_QOS_LEVEL0,  /**< 最多发送一次 */
    MQTT_QOS_LEVEL1,  /**< 最少发送一次  */
    MQTT_QOS_LEVEL2   /**< 只发送一次 */
	
};


/*--------------------------------MQTT 连接请求标志位,内部使用--------------------------------*/
enum MqttConnectFlag
{
	
    MQTT_CONNECT_CLEAN_SESSION  = 0x02,
    MQTT_CONNECT_WILL_FLAG      = 0x04,
    MQTT_CONNECT_WILL_QOS0      = 0x00,
    MQTT_CONNECT_WILL_QOS1      = 0x08,
    MQTT_CONNECT_WILL_QOS2      = 0x10,
    MQTT_CONNECT_WILL_RETAIN    = 0x20,
    MQTT_CONNECT_PASSORD        = 0x40,
    MQTT_CONNECT_USER_NAME      = 0x80
	
};


/*--------------------------------消息的packet ID,可自定义--------------------------------*/
#define MQTT_PUBLISH_ID			10

#define MQTT_SUBSCRIBE_ID		20

#define MQTT_UNSUBSCRIBE_ID		30


/*--------------------------------删包--------------------------------*/
void MQTT_DeleteBuffer(MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------解包--------------------------------*/
uint8 MQTT_UnPacketRecv(uint8 *dataPtr);

/*--------------------------------登录组包--------------------------------*/
uint8 MQTT_PacketConnect(const int8 *user, const int8 *password, const int8 *devid,
						uint16 cTime, uint1 clean_session, uint1 qos,
						const int8 *will_topic, const int8 *will_msg, int32 will_retain,
						MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------断开连接组包--------------------------------*/
uint1 MQTT_PacketDisConnect(MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------连接响应解包--------------------------------*/
uint8 MQTT_UnPacketConnectAck(uint8 *rev_data);

/*--------------------------------数据点上传组包--------------------------------*/
uint1 MQTT_PacketSaveData(const int8 *devid, int16 send_len, int8 *type_bin_head, uint8 type, MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------二进制文件上传组包--------------------------------*/
uint1 MQTT_PacketSaveBinData(const int8 *name, int16 file_len, MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------命令下发解包--------------------------------*/
uint8 MQTT_UnPacketCmd(uint8 *rev_data, int8 **cmdid, int8 **req, uint16 *req_len);

/*--------------------------------命令回复组包--------------------------------*/
uint1 MQTT_PacketCmdResp(const int8 *cmdid, const int8 *req, MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------订阅主题组包--------------------------------*/
uint8 MQTT_PacketSubscribe(uint16 pkt_id, enum MqttQosLevel qos, const int8 *topics[], uint8 topics_cnt, MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------订阅主题回复解包--------------------------------*/
uint8 MQTT_UnPacketSubscribe(uint8 *rev_data);

/*--------------------------------取消订阅组包--------------------------------*/
uint8 MQTT_PacketUnSubscribe(uint16 pkt_id, const int8 *topics[], uint8 topics_cnt, MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------取消订阅回复解包--------------------------------*/
uint1 MQTT_UnPacketUnSubscribe(uint8 *rev_data);

/*--------------------------------发布主题组包--------------------------------*/
uint8 MQTT_PacketPublish(uint16 pkt_id, const int8 *topic,
						const int8 *payload, uint32 payload_len,
						enum MqttQosLevel qos, int32 retain, int32 own,
						MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------发布消息回复解包--------------------------------*/
uint8 MQTT_UnPacketPublish(uint8 *rev_data, int8 **topic, uint16 *topic_len, int8 **payload, uint16 *payload_len, uint8 *qos, uint16 *pkt_id);

/*--------------------------------发布消息的Ack组包--------------------------------*/
uint1 MQTT_PacketPublishAck(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------发布消息的Ack解包--------------------------------*/
uint1 MQTT_UnPacketPublishAck(uint8 *rev_data);

/*--------------------------------发布消息的Rec组包--------------------------------*/
uint1 MQTT_PacketPublishRec(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------发布消息的Rec解包--------------------------------*/
uint1 MQTT_UnPacketPublishRec(uint8 *rev_data);

/*--------------------------------发布消息的Rel组包--------------------------------*/
uint1 MQTT_PacketPublishRel(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------发布消息的Rel解包--------------------------------*/
uint1 MQTT_UnPacketPublishRel(uint8 *rev_data, uint16 pkt_id);

/*--------------------------------发布消息的Comp组包--------------------------------*/
uint1 MQTT_PacketPublishComp(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket);

/*--------------------------------发布消息的Comp解包--------------------------------*/
uint1 MQTT_UnPacketPublishComp(uint8 *rev_data);

/*--------------------------------心跳请求组包--------------------------------*/
uint1 MQTT_PacketPing(MQTT_PACKET_STRUCTURE *mqttPacket);


#endif

标签:return,ESP8266,++,len,STM32,MQTT,mqttPacket,data
From: https://blog.csdn.net/m0_75014814/article/details/143650682

相关文章

  • 如何对stm32的程序进行加密
    目的:保护单片机里的固件或代码不被读取出来通过代码配置 STM32的寄存器来实现读取保护(RDP)和调试接口锁定,可以采用以下方式:1.启用读取保护(RDP)可以在代码中配置RDP级别。例如在STM32F4系列中,RDP的设置存储在选项字节(OptionBytes)中。RDP的配置可以通过STM32HAL库......
  • 25-018、基于STM32单片机智能行李箱设计-LED-BELL-KEY-指纹-LCD1602-GSM-GPS+HX711称
    本设计由STM32F103C8T6单片机核心板电路+LED指示灯电路+蜂鸣器报警电路+按键电路+指纹电路+LCD1602液晶显示电路+GSM模块电路+GPS模块电路组成。1、如果指纹错误。LED灯会闪,同时蜂鸣器发出滴滴声(3声即可)2、如果指纹输入三次失败后,禁止再用指纹解锁,如果指纹打不开,可以输入按键......
  • 25-009、基于STM32单片机智能公交车自动报站系统RFID语音报站+液晶显示温度和烟雾值设
    本系统由STM32F103C8T6单片机核心板、2.4寸TFT彩屏、JR6001语音播报电路、ULN2003步进电机驱动电路、RC522-RFID刷卡识别电路、轻触开关检测电路、按键电路组成。【1】STM32单片机驱动2.4寸TFT彩屏实时显示所有站台信息、当前公交运行方向、当前到站的站点(并有图标显示);语音播......
  • STM32(hal库)中的定时器从模式TIM_SlaveConfigTypeDef结构体中的含义,以及可选参数的含义
            在STM32的HAL库中,定时器从模式配置结构体TIM_SlaveConfigTypeDef用于配置定时器作为从定时器时的相关参数。该结构体及其可选参数的含义对于理解和配置STM32定时器的从模式至关重要。以下是对该结构体及其参数的详细解释:TIM_SlaveConfigTypeDef结构体该结构......
  • 来了,超全MQTT实用示例
    Air201快速入门之MQTT示例合宙Air201资产定位模组——是一个集成超低功耗4G通信、语音通话、超低功耗定位、计步、震动、Type-C、充电、放音、录音等功能的超小PCBA。内部集成高效、简单、可靠的LuatOS语言,旨在帮助客户降低开发难度,降低研发成本,以及打造超小超低功......
  • STM32
    一:新建工程右上角工具栏扳手,可调节编码格式utf8,字体14,tabszie改为41.新建工程2.添加必要文件夹library,start,user3.品字按钮(魔术棒右侧)添加文件夹及文件,start只用添加一部分4.魔术棒按钮,c++中包含目录,define添加定义USE_STDPERIPH_DRIVER二:在iic编程时遇到一个奇怪的问......
  • 记录STM32的GPIO 的坑 复用引脚PB3 PB4
    系列文章目录点击直达——文章总目录文章目录系列文章目录一、STM32的GPIO复用引脚PB3PB4二、关闭JTAG功能(PB3/4),只使用SWD(PA13/14)调试关于作者2024年11月3日,浪费我一天的时间,就因为这个BUG,害我没找妹子去玩,可恶可恶!!!STM32的GPIO引脚有这一些约定俗......
  • 定时器(PWM输出)触发ADC采样(DMA)——STM32CubeMX
    在STM32微控制器中,使用定时器(PWM输出)触发ADC采样是一种常见的应用场景,尤其是在需要精确控制采样时刻和频率的场合。本文将详细介绍如何使用STM32CubeMX配置定时器产生PWM波形,并使用DMA传输ADC采样结果。1.定时器PWM输出配置首先,我们需要在STM32CubeMX中配置定时器以产......
  • HC-SR04超声波传感器详解(STM32)
    HC-SR04是一款广泛使用的超声波传感器,它通过发射和接收超声波来测量距离。本文将详细介绍HC-SR04的工作原理、引脚描述、STM32的接线方式以及如何通过STM32控制HC-SR04来测量距离。一、HC-SR04传感器介绍HC-SR04超声波传感器的主要参数如下:工作电压:DC5V工作电流:3.3mA工......
  • STM32之DHT11温湿度传感器
    DHT11是一款常用的单总线数字温湿度传感器,它能够提供相对湿度和温度的测量值。本文将详细介绍如何使用STM32微控制器读取DHT11传感器的数据。DHT11传感器特点湿度测量范围:20%~90%RH温度测量范围:0~50℃单总线数字输出低功耗易于安装和使用硬件连接DHT11传感器通常有三个......