前言

本篇主要讲解如何使用ESP8266-01S物联网模块连接Onenet云平台,并上报DHT11模块的温湿度数据。本文单片机主控采用STM32F405RGT6,使用其他主控的话基本要求有2个串口,一个串口用于调试使用,另一个用于ESP模块通讯。

一、前期准备

1.软件

CubeMXKeil5串口调试助手Onenet云平台账户

2.硬件

STM32开发板一个捡来的ESP8266-01S模块一个盗版的ST-link模块一个借的USB-TTL模块一个买的DHT11温湿度模块杜邦线若干

二、CubeMX配置

1.配置时钟源、下载模块、时钟树

2.引脚配置

这里配置了2个引脚,一个是LED,一个是DHT11

3.配置串口

串口使用2个,波特率默认115200即可,一个是串口1(PA9、PA10)用于调试使用,另外一个使用串口2(PA2、PA3)用于和ESP通讯,并注意打开串口2的接收中断,如下:

4.生成工程

三、Keil5配置

1.基本配置

①在根目录下创建一个文件夹用于保存后面的代码文件

②添加头文件路径

③在工程栏创建文件夹

2.配置串口代码

①这里参考以往文章,使用第三种方法:STM32系列(HAL库) ——使用串口打印的3种方式

②参考上述配置完后,还需要添加一个函数用于和EPS模块通讯,在usart.c添加:

void Usart_SendString(UART_HandleTypeDef USARTx, unsigned char *str, unsigned short len)

{

unsigned short count = 0;

for(; count < len; count++)

{

HAL_UART_Transmit (&USARTx ,(uint8_t *)str++,1,HAL_MAX_DELAY ); //发送数据

}

}

③在usart.h声明函数:

void Usart_SendString(UART_HandleTypeDef USARTx, unsigned char *str, unsigned short len);

④验证UsartPrintf函数能成功打印内容,可在while(1)循环添加:

UsartPrintf(USART_DEBUG, "The USART1 is OK!\r\n");

HAL_Delay(500);

效果如下:

3.配置DHT11代码

创建DHT11.c文件,添加代码如下:

#include "dht11.h"

#include "usart.h"

extern UART_HandleTypeDef huart1;

uint8_t data[5] = {0};

/**

* @brief 温湿度传感器主函数

* @param void

* @retval None

*/

void DHT11(void)

{

if(DHT11_READ_DATA() == 1)

{

// printf("数据校验成功!\r\n");

UsartPrintf(USART_DEBUG, "数据校验成功!\r\n");

}

else

{

// printf("DHT11没有应答,请检查传感器!\r\n");

UsartPrintf(USART_DEBUG, "DHT11没有应答,请检查传感器!\r\n");

}

HAL_Delay(1000);

}

/**

* @brief 温湿度传感器启动信号发送

* @param void

* @retval None

*/

void DHT11_START(void)

{

DHT11_GPIO_MODE_SET(0); // 主机设置为输出模式

DHT11_PIN_RESET; // 主机拉低电平

HAL_Delay(20); // 主机等待 18 < ms > 30

DHT11_GPIO_MODE_SET(1); // 主机设置为输入模式,等待DHT11答应

} // 因为设置了上拉输入,GPIO -> 1

/**

* @brief 读取一位数据 1bit

* @param void

* @retval 0/1

*/

unsigned char DHT11_READ_BIT(void)

{

while(!DHT11_READ_IO); // 过度数据的低电平

Coarse_delay_us(40);

if(DHT11_READ_IO) // 此时如果还为高电平则数据为 1

{

while(DHT11_READ_IO); // 过度数据的高电平

return 1;

}

else // 若此时为低则为 0

{

return 0;

}

}

/**

* @brief 读取一个字节数据 1byte / 8bit

* @param void

* @retval temp

*/

unsigned char DHT11_READ_BYTE(void)

{

uint8_t i,temp = 0; // 暂时存储数据

for(i=0; i<8 ;i++)

{

temp <<= 1;

if(DHT11_READ_BIT()) // 1byte -> 8bit

{

temp |= 1; // 0000 0001

}

}

return temp;

}

/**

* @brief 读取温湿度传感器数据 5byte / 40bit

* @param void

* @retval 0/1/2

*/

unsigned char DHT11_READ_DATA(void)

{

uint8_t i;

DHT11_START(); // 主机发送启动信号

if(DHT11_Check()) // 如果DHT11应答

{

while(!DHT11_READ_IO); // 过度DHT11答复信号的低电平

while(DHT11_READ_IO); // 过度DHT11答复信号的高电平

for(i=0; i<5; i++)

{

data[i] = DHT11_READ_BYTE(); // 读取 5byte

}

if(data[0] + data[1] + data[2] + data[3] == data[4])

{

// printf("当前湿度:%d.%d%%RH当前温度:%d.%d°C--",data[0],data[1],data[2],data[3]);

UsartPrintf(USART_DEBUG,"当前湿度:%d.%d%%RH当前温度:%d.%d°C--",data[0],data[1],data[2],data[3]);

return 1; // 数据校验通过

}

else

{

return 0; // 数据校验失败

}

}

else // 如果DHT11不应答

{

return 2;

}

}

/**

* @brief 检测温湿度传感器是否存在(检测DHT11的应答信号)

* @param void

* @retval 0/1

*/

unsigned char DHT11_Check(void)

{

Coarse_delay_us(40);

if(DHT11_READ_IO == 0) // 检测到DHT11应答

{

return 1;

}

else // 检测到DHT11不应答

{

return 0;

}

}

/**

* @brief 设置引脚模式

* @param mode: 0->out, 1->in

* @retval None

*/

static void DHT11_GPIO_MODE_SET(uint8_t mode)

{

if(mode)

{

/* 输入 */

GPIO_InitTypeDef GPIO_InitStruct;

GPIO_InitStruct.Pin = GPIO_Pin; // 9号引脚

GPIO_InitStruct.Mode = GPIO_MODE_INPUT; // 输入模式

GPIO_InitStruct.Pull = GPIO_PULLUP; // 上拉输入

HAL_GPIO_Init(GPIO_Port, &GPIO_InitStruct);

}

else

{

/* 输出 */

GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.Pin = GPIO_Pin; // 9号引脚

GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; // Push Pull 推挽输出模式

GPIO_InitStructure.Pull = GPIO_PULLUP; // 上拉输出

GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH; // 高速

HAL_GPIO_Init(GPIO_Port,&GPIO_InitStructure);

}

}

/**

* @brief 程序延时 us

* @param us: <= 4294967295

* @retval None

*/

void Coarse_delay_us(uint32_t us)

{

uint32_t delay = (HAL_RCC_GetHCLKFreq() / 4000000 * us);

while (delay--)

{

;

}

}

②创建DHT11.h文件,添加代码如下:

注意修改引用的头文件#include “stm32f4xx.h”,我用的是F4系列的,F1系列为#include “stm32f1xx.h”,其它系列以此类推

#ifndef __DHT11_H__

#define __DHT11_H__

/* Private includes ----------------------------------------------------------*/

#include "main.h"

#include "gpio.h"

#include "stdio.h"

#include "stm32f4xx.h"

/* Private define ------------------------------------------------------------*/

#define GPIO_Port GPIOC

#define GPIO_Pin GPIO_PIN_4

#define DHT11_PIN_SET HAL_GPIO_WritePin(GPIO_Port,GPIO_Pin,GPIO_PIN_SET) // 设置GPIO为高

#define DHT11_PIN_RESET HAL_GPIO_WritePin(GPIO_Port,GPIO_Pin,GPIO_PIN_RESET) // 设置GPIO为低

#define DHT11_READ_IO HAL_GPIO_ReadPin(GPIO_Port,GPIO_Pin) // DHT11 GPIO定义

extern uint8_t data[5];

/* Private function prototypes -----------------------------------------------*/

void DHT11(void);

void DHT11_START(void);

unsigned char DHT11_READ_BIT(void);

unsigned char DHT11_READ_BYTE(void);

unsigned char DHT11_READ_DATA(void);

unsigned char DHT11_Check(void);

static void DHT11_GPIO_MODE_SET(uint8_t mode);

void Coarse_delay_us(uint32_t us);

#endif

③验证DHT11模块

在工程栏处添加DHT11.c文件 在main.c引用DHT11.h头文件,while(1)循环添加:

DHT11( );

HAL_Delay(1000);

效果如下:

4.ESP模块、通信协议代码配置

①创建esp01s.c文件,添加代码如下:

代码需要注意:

#define ESP01S_WIFI_INFO"AT+CWJAP=“OPPOA93”,“12345678”\r\n"

此语句定义了模块需要连接的网络,可以是wifi,可以是手机热点,前面是网络名称,如OPPOA93,后面是网络连接密码,如12345678

//单片机头文件

#include "main.h"

//网络设备驱动

#include "esp01s.h"

//硬件驱动

#include "usart.h"

//C库

#include

#include

#include

#define ESP01S_WIFI_INFO "AT+CWJAP=\"OPPOA93\",\"12345678\"\r\n"

#define ESP01S_ONENET_INFO "AT+CIPSTART=\"TCP\",\"183.230.40.39\",6002\r\n"

unsigned char ESP01S_buf[128];

unsigned short ESP01S_cnt = 0, ESP01S_cntPre = 0;

uint8_t aRxBuffer; //接收中断缓冲

//==========================================================

// 函数名称: ESP01S_Clear

//

// 函数功能: 清空缓存

//

// 入口参数: 无

//

// 返回参数: 无

//

// 说明:

//==========================================================

void ESP01S_Clear(void)

{

memset(ESP01S_buf, 0, sizeof(ESP01S_buf));

ESP01S_cnt = 0;

}

//==========================================================

// 函数名称: ESP01S_WaitRecive

//

// 函数功能: 等待接收完成

//

// 入口参数: 无

//

// 返回参数: REV_OK-接收完成 REV_WAIT-接收超时未完成

//

// 说明: 循环调用检测是否接收完成

//==========================================================

_Bool ESP01S_WaitRecive(void)

{

if(ESP01S_cnt == 0) //如果接收计数为0 则说明没有处于接收数据中,所以直接跳出,结束函数

return REV_WAIT;

if(ESP01S_cnt == ESP01S_cntPre) //如果上一次的值和这次相同,则说明接收完毕

{

ESP01S_cnt = 0; //清0接收计数

return REV_OK; //返回接收完成标志

}

ESP01S_cntPre = ESP01S_cnt; //置为相同

return REV_WAIT; //返回接收未完成标志

}

//==========================================================

// 函数名称: ESP01S_SendCmd

//

// 函数功能: 发送命令

//

// 入口参数: cmd:命令

// res:需要检查的返回指令

//

// 返回参数: 0-成功 1-失败

//

// 说明:

//==========================================================

_Bool ESP01S_SendCmd(char *cmd, char *res)

{

unsigned char timeOut = 200;

Usart_SendString(huart2, (unsigned char *)cmd, strlen((const char *)cmd));

while(timeOut--)

{

if(ESP01S_WaitRecive() == REV_OK) //如果收到数据

{

if(strstr((const char *)ESP01S_buf, res) != NULL) //如果检索到关键词

{

ESP01S_Clear(); //清空缓存

return 0;

}

}

HAL_Delay(10);

}

return 1;

}

//==========================================================

// 函数名称: ESP01S_SendData

//

// 函数功能: 发送数据

//

// 入口参数: data:数据

// len:长度

//

// 返回参数: 无

//

// 说明:

//==========================================================

void ESP01S_SendData(unsigned char *data, unsigned short len)

{

char cmdBuf[32];

ESP01S_Clear(); //清空接收缓存

sprintf(cmdBuf, "AT+CIPSEND=%d\r\n", len); //发送命令

if(!ESP01S_SendCmd(cmdBuf, ">")) //收到‘>’时可以发送数据

{

Usart_SendString(huart2, data, len); //发送设备连接请求数据

}

}

//==========================================================

// 函数名称: ESP01S_GetIPD

//

// 函数功能: 获取平台返回的数据

//

// 入口参数: 等待的时间(乘以10ms)

//

// 返回参数: 平台返回的原始数据

//

// 说明: 不同网络设备返回的格式不同,需要去调试

// 如ESP01S的返回格式为 "+IPD,x:yyy" x代表数据长度,yyy是数据内容

//==========================================================

unsigned char *ESP01S_GetIPD(unsigned short timeOut)

{

char *ptrIPD = NULL;

do

{

if(ESP01S_WaitRecive() == REV_OK) //如果接收完成

{

ptrIPD = strstr((char *)ESP01S_buf, "IPD,"); //搜索“IPD”头

if(ptrIPD == NULL) //如果没找到,可能是IPD头的延迟,还是需要等待一会,但不会超过设定的时间

{

//UsartPrintf(USART_DEBUG, "\"IPD\" not found\r\n");

}

else

{

ptrIPD = strchr(ptrIPD, ':'); //找到':'

if(ptrIPD != NULL)

{

ptrIPD++;

return (unsigned char *)(ptrIPD);

}

else

return NULL;

}

}

HAL_Delay(5);

timeOut--; //延时等待

} while(timeOut>0);

return NULL; //超时还未找到,返回空指针

}

//==========================================================

// 函数名称: ESP01S_Init

//

// 函数功能: 初始化ESP01S

//

// 入口参数: 无

//

// 返回参数: 无

//

// 说明:

//==========================================================

void ESP01S_Init(void)

{

ESP01S_Clear();

UsartPrintf(USART_DEBUG, "0. AT\r\n");

while(ESP01S_SendCmd("AT\r\n", "OK"))

HAL_Delay(500);

UsartPrintf(USART_DEBUG, "1. RST\r\n");

ESP01S_SendCmd("AT+RST\r\n", "");

HAL_Delay(500);

ESP01S_SendCmd("AT+CIPCLOSE\r\n", ""); //关闭TCP连接

HAL_Delay(500);

UsartPrintf(USART_DEBUG, "2. CWMODE\r\n");

while(ESP01S_SendCmd("AT+CWMODE=1\r\n", "OK")) //模式1(Station),默认保存Flash

HAL_Delay(500);

UsartPrintf(USART_DEBUG, "3. AT+CWDHCP\r\n"); //开启DHCP(获取分配IP),默认保存Flash

while(ESP01S_SendCmd("AT+CWDHCP=1,1\r\n", "OK"))

HAL_Delay(500);

UsartPrintf(USART_DEBUG, "4. CWJAP\r\n"); //链接WIFI

while(ESP01S_SendCmd(ESP01S_WIFI_INFO, "GOT IP"))

HAL_Delay(500);

UsartPrintf(USART_DEBUG, "5. CIPSTART\r\n"); //开启TCP连接

while(ESP01S_SendCmd(ESP01S_ONENET_INFO, "CONNECT"))

HAL_Delay(500);

UsartPrintf(USART_DEBUG, "6. ESP01S Init OK\r\n");

}

/* USER CODE BEGIN 4 */

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

{

UNUSED(huart);

if(ESP01S_cnt >= sizeof(ESP01S_buf)) //溢出判断

{

ESP01S_cnt = 0;

memset(ESP01S_buf,0x00,sizeof(ESP01S_buf));

HAL_UART_Transmit(&huart1, (uint8_t *)"接收缓存溢出", 10,0xFFFF);

}

else

{

ESP01S_buf[ESP01S_cnt++] = aRxBuffer; //接收数据转存

// if(aRxBuffer=='1') HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET);

// if(aRxBuffer=='0') HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET);

}

HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1); //再开启接收中断

}

/* USER CODE END 4 */

②创建esp01s.h文件,添加代码如下:

#ifndef _ESP01S_H_

#define _ESP01S_H_

#define REV_OK 0 //接收完成标志

#define REV_WAIT 1 //接收未完成标志

void ESP01S_Init(void);

void ESP01S_Clear(void);

void ESP01S_SendData(unsigned char *data, unsigned short len);

unsigned char *ESP01S_GetIPD(unsigned short timeOut);

#endif

③创建Onenet.c文件,添加代码如下:

这里需要注意代码中: #define PROID “xxx” //产品ID #define AUTH_INFO “xxx” //鉴权信息 #define DEVID “xxx” //设备ID xxx的内容需要在Onenet云平台创建产品、设备后可得,后文会介绍

//单片机头文件

#include "main.h"

//网络设备

#include "esp01s.h"

//协议文件

#include "onenet.h"

#include "MQTT.h"

//硬件驱动

#include "usart.h"

//C库

#include

#include

#include "dht11.h"

#define PROID "XXX"//产品ID

#define AUTH_INFO "XXX"//鉴权信息

#define DEVID "XXX"//设备ID

extern unsigned char ESP01S_buf[128];

//==========================================================

// 函数名称: OneNet_DevLink

//

// 函数功能: 与onenet创建连接

//

// 入口参数: 无

//

// 返回参数: 1-成功 0-失败

//

// 说明: 与onenet平台建立连接

//==========================================================

_Bool OneNet_DevLink(void)

{

MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0}; //协议包

unsigned char *dataPtr;

_Bool status = 1;

UsartPrintf(USART_DEBUG, "OneNet_DevLink\r\n"

"PROID: %s, AUIF: %s, DEVID:%s\r\n"

, PROID, AUTH_INFO, DEVID);

if(MQTT_PacketConnect(PROID, AUTH_INFO, DEVID, 256, 0, MQTT_QOS_LEVEL0, NULL, NULL, 0, &mqttPacket) == 0)

{

ESP01S_SendData(mqttPacket._data, mqttPacket._len); //上传平台

dataPtr = ESP01S_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); //删包

}

else

UsartPrintf(USART_DEBUG, "WARN: MQTT_PacketConnect Failed\r\n");

return status;

}

unsigned char OneNet_FillBuf(char *buf)

{

char text[32];

float Temp;

float Humidity;

memset(text, 0, sizeof(text));

strcpy(buf, ",;");

Temp = data[2]+(float)data[3]/10;

Humidity=data[0]+(float)data[1]/10;

memset(text, 0, sizeof(text));

sprintf(text, "Temp,%.2f;Humidity,%.2f;",Temp,Humidity);

strcat(buf, text);

return strlen(buf);

}

//==========================================================

// 函数名称: OneNet_SendData

//

// 函数功能: 上传数据到平台

//

// 入口参数: type:发送数据的格式

//

// 返回参数: 无

//

// 说明:

//==========================================================

void OneNet_SendData(void)

{

MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0}; //协议包

char buf[128];

short body_len = 0, i = 0;

UsartPrintf(USART_DEBUG, "Tips: OneNet_SendData-MQTT\r\n");

memset(buf, 0, sizeof(buf));

body_len = OneNet_FillBuf(buf); //获取当前需要发送的数据流的总长度

if(body_len)

{

if(MQTT_PacketSaveData(DEVID, body_len, NULL, 5, &mqttPacket) == 0) //封包

{

for(; i < body_len; i++)

mqttPacket._data[mqttPacket._len++] = buf[i];

ESP01S_SendData(mqttPacket._data, mqttPacket._len); //上传数据到平台

UsartPrintf(USART_DEBUG, "Send %d Bytes\r\n", mqttPacket._len);

MQTT_DeleteBuffer(&mqttPacket); //删包

}

else

UsartPrintf(USART_DEBUG, "WARN: EDP_NewBuffer Failed\r\n");

}

}

//==========================================================

// 函数名称: OneNet_RevPro

//

// 函数功能: 平台返回数据检测

//

// 入口参数: dataPtr:平台返回的数据

//

// 返回参数: 无

//

// 说明:

//==========================================================

void OneNet_RevPro(unsigned char *cmd)

{

MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0}; //协议包

char *req_payload = NULL;

char *cmdid_topic = NULL;

unsigned short req_len = 0;

unsigned char type = 0;

short result = 0;

char *dataPtr = NULL;

char numBuf[10];

int num = 0;

type = MQTT_UnPacketRecv(cmd);

switch(type)

{

case MQTT_PKT_CMD: //命令下发

result = MQTT_UnPacketCmd(cmd, &cmdid_topic, &req_payload, &req_len); //解出topic和消息体

if(result == 0)

{

UsartPrintf(USART_DEBUG, "cmdid: %s, req: %s, req_len: %d\r\n", cmdid_topic, req_payload, req_len);

if(MQTT_PacketCmdResp(cmdid_topic, req_payload, &mqttPacket) == 0) //命令回复组包

{

UsartPrintf(USART_DEBUG, "Tips: Send CmdResp\r\n");

ESP01S_SendData(mqttPacket._data, mqttPacket._len); //回复命令

MQTT_DeleteBuffer(&mqttPacket); //删包

}

}

break;

case MQTT_PKT_PUBACK: //发送Publish消息,平台回复的Ack

if(MQTT_UnPacketPublishAck(cmd) == 0)

UsartPrintf(USART_DEBUG, "Tips: MQTT Publish Send OK\r\n");

break;

default:

result = -1;

break;

}

ESP01S_Clear(); //清空缓存

if(result == -1)

return;

dataPtr = strchr(req_payload, '}'); //搜索'}'

if(dataPtr != NULL && result != -1) //如果找到了

{

dataPtr++;

while(*dataPtr >= '0' && *dataPtr <= '9') //判断是否是下发的命令控制数据

{

numBuf[num++] = *dataPtr++;

}

numBuf[num] = 0;

num = atoi((const char *)numBuf); //转为数值形式

}

if(type == MQTT_PKT_CMD || type == MQTT_PKT_PUBLISH)

{

MQTT_FreeBuffer(cmdid_topic);

MQTT_FreeBuffer(req_payload);

}

}

④创建Onenet.h文件,添加代码如下:

#ifndef _ONENET_H_

#define _ONENET_H_

_Bool OneNet_DevLink(void);

void OneNet_SendData(void);

void OneNet_RevPro(unsigned char *cmd);

#endif

⑤创建MQTT.c文件,添加代码如下:

//协议头文件

#include "MQTT.h"

//C库

#include

#include

#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 _MQTT_H_

#define _MQTT_H_

#include

//=============================配置==============================

//===========可以提供RTOS的内存管理方案,也可以使用C库的=========

//RTOS

typedef _Bool uint1;

typedef unsigned char uint8;

typedef char int8;

typedef unsigned short uint16;

typedef short int16;

typedef unsigned int uint32;

typedef int int32;

typedef unsigned int size_t;

#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

⑦将上述文件添加进工程栏

编译工程,如有报错自行改正即可

四、Onenet云平台配置

①平台账号注册→点击跳转

②创建产品、设备(按图示操作即可)

③记录产品ID、设备ID、鉴权信息

五、最后一步

1.在esp01.c中修改wifi信息

修改成自己家或邻居家的wifi,或者手机热点;如下所示OPPOA93为网络名称,12345678为网络连接密码

#define ESP01S_WIFI_INFO “AT+CWJAP=“OPPOA93”,“12345678”\r\n”

2.在Onenet.c修改配置信息

修改成刚才从云平台获取的信息即可

3.main.c

①.在main.c引用头文件、定义如下变量:

#include "DHT11.h"

#include "esp01s.h"

#include "Onenet.h"

#include "MQTT.h"

extern uint8_t aRxBuffer;

unsigned short timeCount = 0; //发送间隔变量

unsigned char *dataPtr = NULL;

②.在while(1)前添加一些初始化函数

UsartPrintf(USART_DEBUG, "The USART1 is OK!\r\n");

HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1); //串口2接收中断初始化

ESP01S_Init(); //8266初始化

while(OneNet_DevLink()) //接入onenet

ESP01S_Clear(); //

UsartPrintf(USART_DEBUG, "Init is OK!\r\n");

③.在while(1)循环中添加:

if(++timeCount >= 80) //上传数据约3s一次

{

DHT11( );

UsartPrintf(USART_DEBUG, "OneNet_SendData\r\n");

OneNet_SendData( );

timeCount = 0;

ESP01S_Clear( );

}

dataPtr = ESP01S_GetIPD(3);//完成需要15个毫秒,三次循环,一次5个毫秒

if(dataPtr != NULL)

{

OneNet_RevPro(dataPtr);

}

HAL_Delay(10);

4.代码验证

①.接线图

②.串口1打印的信息

③.串口2打印的信息

STM32给ESP发送的信息,一般情况下硬件不支持看不到,因为32引脚和EPS连接后,就没法和USB-TTL连接了。因为我自制的开发板,所以能同时收到两者的通信

5.平台数据查看

代码是从标准库移植过来的,调试整理总结花了一定时间,全文没有过多的理论知识介绍,因为网上一搜一大把。全文如有错误,还请读者指正!

精彩链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: