赞
踩
本篇主要讲解如何使用ESP8266-01S物联网模块连接Onenet云平台,并上报DHT11模块的温湿度数据。本文单片机主控采用STM32F405RGT6,使用其他主控的话基本要求有2个串口,一个串口用于调试使用,另一个用于ESP模块通讯。
略
这里配置了2个引脚,一个是LED,一个是DHT11
串口使用2个,波特率默认115200即可,一个是串口1(PA9、PA10)用于调试使用,另外一个使用串口2(PA2、PA3)用于和ESP通讯,并注意打开串口2的接收中断,如下:
略
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 ); //发送数据
}
}
void Usart_SendString(UART_HandleTypeDef USARTx, unsigned char *str, unsigned short len);
UsartPrintf(USART_DEBUG, "The USART1 is OK!\r\n");
HAL_Delay(500);
效果如下:
#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--) { ; } }
注意修改引用的头文件#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.c文件
在main.c引用DHT11.h头文件,while(1)循环添加:
DHT11( );
HAL_Delay(1000);
效果如下:
代码需要注意:
#define ESP01S_WIFI_INFO"AT+CWJAP=“OPPOA93”,“12345678”\r\n"
此语句定义了模块需要连接的网络,可以是wifi,可以是手机热点,前面是网络名称,如OPPOA93,后面是网络连接密码,如12345678
//单片机头文件 #include "main.h" //网络设备驱动 #include "esp01s.h" //硬件驱动 #include "usart.h" //C库 #include <string.h> #include <stdio.h> #include <string.h> #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 */
#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
这里需要注意代码中:
#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 <string.h> #include <stdio.h> #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); } }
#ifndef _ONENET_H_
#define _ONENET_H_
_Bool OneNet_DevLink(void);
void OneNet_SendData(void);
void OneNet_RevPro(unsigned char *cmd);
#endif
//协议头文件 #include "MQTT.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; }
#ifndef _MQTT_H_ #define _MQTT_H_ #include <stdlib.h> //=============================配置============================== //===========可以提供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
编译工程,如有报错自行改正即可
略
修改成自己家或邻居家的wifi,或者手机热点;如下所示OPPOA93为网络名称,12345678为网络连接密码
#define ESP01S_WIFI_INFO “AT+CWJAP=“OPPOA93”,“12345678”\r\n”
修改成刚才从云平台获取的信息即可
#include "DHT11.h"
#include "esp01s.h"
#include "Onenet.h"
#include "MQTT.h"
extern uint8_t aRxBuffer;
unsigned short timeCount = 0; //发送间隔变量
unsigned char *dataPtr = NULL;
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");
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);
STM32给ESP发送的信息,一般情况下硬件不支持看不到,因为32引脚和EPS连接后,就没法和USB-TTL连接了。因为我自制的开发板,所以能同时收到两者的通信
代码是从标准库移植过来的,调试整理总结花了一定时间,全文没有过多的理论知识介绍,因为网上一搜一大把。全文如有错误,还请读者指正!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。