赞
踩
凡心所向,素履所往;生如逆旅,一苇以航。
STM32F103RBT6
(正点原子的NANO开发板)ESP8266MOD
型号 (如上图所示)STM32开发板 | ESP8266 模块 | 功能 |
---|---|---|
VCC(3.3V) | VCC | 3.3V,模块供电 |
VCC(3.3V) | CH_PD | 模块使能端,高电平工作 |
VCC(3.3V) | GPIO0 | 上拉(Flash Boot)工作模式,可接VCC,也可不接VCC,默认悬空 |
GND | GND | 接地 |
USART2_TX(PA2 ) | RXD | 串口数据通信 |
USART2_RX(PA3 ) | TXD | 串口数据通信 |
USART1_TX(PA9) | - | 串口通信,发送端 |
USART1_RX(PA10) | - | 串口通信,接收端 |
其他引脚默认悬空即可。
ESP8266引脚 | 功能 |
---|---|
VCC | 3.3V,模块供电 |
GND | 接地 |
TXD | 发送 |
RXD | 接收 |
GPIO0 | 默认 WiFi 状态,1)上拉:Flash Boot,工作模式;2)下拉:UART Download,下载模式 |
CH_PD | 使能端,高电平工作,低电平模块供电关闭 |
ESP8266
连接当前环境中的 WiFi
热点,然后与服务器建立 TCP
连接,进行数据的传输。ONENET
的 MQTT
协议为例。也就是ESP 设备 Wi-Fi 的三种模式当中的:STA模式。 |
AT
:测试启动 ESP 设备,响应返回:OKAT+CWMODE=1
:设置 WiFi 模式(STA 模式),响应返回:OKAT+CWDHCP=1,1
:启用 SoftAP
的 DHCP
,响应返回:OK(本设置命令与设置静态 IP 地址的命令会相互影响,如 AT+CIPSTA
和 AT+CIPAP
)
DHCP
,则 静态 IP
地址 会被禁用IP
,则 DHCP
会被禁用// 启用 Station DHCP,如果原 DHCP mode 为 2,则现 DHCP mode 为 3
AT+CWDHCP=1,1
// 禁用 SoftAP DHCP,如果原 DHCP mode 为 3,则现 DHCP mode 为 1
AT+CWDHCP=0,2
AT+CWJAP="WIFI 热点名称","密码"
:连接当前环境中的WiFi热点AT+CIPSTART="TCP","xxx.xxx.xxx.xxx",xxxx
:建立 TCP 连接- type:字符串参数,表示网络连接类型,"TCP""TCPv6",默认值:"TCP"
- remote host:字符串参数,表示远端 IPv4 地址、IPv6 地址,或域名
- remote port:远端端口值
- local IP:连接绑定的本机 IPv4 地址或 IPv6 地址,该参数在本地多网络接口时和本地多 IP 地址时非常有用。默认为禁用,如果您想使用,需自行设置,空值也为有效值
AT+CIPSTART=<"type">,<"remote host">,<remote port>[,<keep alive>][,<"local IP">]
完成以上步骤,即可差不多完成了 ESP8266 的初始化。
具体学习可以参考:博客网站-RCC学习
输入项目名称和路径。(注:路径中不允许出现中文。)
选择应用的IDE
,开发环境MDK-ARM V5
每个外设生成独立的 ’.c/.h’ 文件
main.c
GPIO
初始化代码生成在 gpio.c
中。在main.c
文件中,添加一下代码:
fget
和fput
函数:勾选微库(这个很重要),添加头文件<stdio.h>
;代码移植:
main.c:
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * <h2><center>© Copyright (c) 2021 STMicroelectronics. * All rights reserved.</center></h2> * * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "usart.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "esp8266.h" #include "onenet.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ extern unsigned char a_esp8266_buf; /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ unsigned char *dataPtr = NULL; /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART1_UART_Init(); MX_USART2_UART_Init(); /* USER CODE BEGIN 2 */ printf("This is a mqtt text \r\n"); HAL_UART_Receive_IT(&huart2, (uint8_t *)&a_esp8266_buf, 1); ESP8266_Init(); while(OneNet_DevLink()) //接入OneNET HAL_Delay(500); printf("接入onenet成功"); OneNet_SendData();//发送数据给onenet // dataPtr = ESP8266_GetIPD(0);//获取平台返回的数据 // if(dataPtr != NULL)//如果返回数据不为空 // OneNet_RevPro(dataPtr);//平台返回数据检测 // printf("%s",dataPtr); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { dataPtr = ESP8266_GetIPD(0);//获取平台返回的数据 if(dataPtr != NULL)//如果返回数据不为空 OneNet_RevPro(dataPtr);//平台返回数据检测 /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
ESP8266.c
:
#include "esp8266.h" /** * @brief esp8266初始化 * @param 无 * @retval 无 */ void ESP8266_Init(void) { ESP8266_Clear(); printf("1. 测试AT启动\r\n"); //AT:测试AT启动 while(ESP8266_SendCmd("AT\r\n", "OK")) HAL_Delay(500); printf("2. 设置WiFi模式(CWMODE)\r\n"); //查询/设置 Wi-Fi 模式:设置WiFi模式为Station模式 while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK")) HAL_Delay(500); printf("3. AT+CWDHCP\r\n"); //启用/禁用 DHCP while(ESP8266_SendCmd("AT+CWDHCP=1,1\r\n", "OK")) HAL_Delay(500); printf("4. 连接WiFi热点(CWJAP)\r\n"); while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "GOT IP")) HAL_Delay(500); printf("5. 建立TCP连接(CIPSTART)\r\n"); while(ESP8266_SendCmd(ESP8266_ONENET_INFO, "CONNECT")) HAL_Delay(500); printf("6. ESP8266 Init OK\r\n"); } /** * @brief 清空缓存 * @param 无 * @retval 无 */ void ESP8266_Clear(void) { memset(ESP8266_Buf, 0, sizeof(ESP8266_Buf)); //将数组中的元素全部初始化为0, } /** * @brief 等待接收完成 * @param 无 * @retval OK:表示接收完成;OUTTIME:表示接收超时完成 * 进行循环调用,检测接收是否完成 */ _Bool ESP8266_WaitRecive(void) { if(esp8266_cnt == 0) //如果当前接收计数为0 则说明没有处于接收数据中,所以直接跳出,结束函数 return OUTTIME; if(esp8266_cnt == esp8266_cntPre) //如果上一次的值和这次相同,则说明接收完毕 { esp8266_cnt = 0; //清0接收计数 return OK; //返回接收完成标志 } else //如果不相同,则将此次赋值给上一次,并返回接收未完成标志 { esp8266_cntPre = esp8266_cnt; return OUTTIME; } } /** * @brief 发送命令 * @param cmd:表示命令;res:需要检查的返回指令 * @retval 0:表示成功;1:表示失败 */ _Bool ESP8266_SendCmd(char *cmd, char *res) { unsigned char timeOut = 200; HAL_UART_Transmit(&huart2, (unsigned char *)cmd, strlen((const char *)cmd),0xffff); while(timeOut--) { if(ESP8266_WaitRecive() == OK) //如果收到数据 { printf("%s",ESP8266_Buf); if(strstr((const char *)ESP8266_Buf, res) != NULL) //如果检索到关键词,清空缓存 { ESP8266_Clear(); return 0; } } HAL_Delay(10); } return 1; } /** * @brief 数据发送 * @param data:待发送的数据;len:待发送的数据长度 * @retval 无 */ void ESP8266_SendData(unsigned char *data, unsigned short len) { char cmdBuf[32]; ESP8266_Clear(); //清空接收缓存 sprintf(cmdBuf, "AT+CIPSEND=%d\r\n", len); //发送命令,sprintf()函数用于将格式化的数据写入字符串 if(!ESP8266_SendCmd(cmdBuf, ">")) //收到‘>’时可以发送数据 { HAL_UART_Transmit(&huart2, data, len,0xffff); //发送设备连接请求数据 } } /** * @brief 获取平台返回的数据 * @param 等待的时间 * @retval 平台返回的数据,不同网络设备返回的格式不同,需要进行调试,如:ESP8266的返回格式为:"+IPD,x:yyy",x表示数据长度,yyy表示数据内容 */ unsigned char *ESP8266_GetIPD(unsigned short timeOut) { char *ptrIPD = NULL; do { if(ESP8266_WaitRecive() == OK) //如果接收完成 { ptrIPD = strstr((char *)ESP8266_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); //延时等待 } while(timeOut--); return NULL; //超时还未找到,返回空指针 } /** * @brief 串口2收发中断回调函数 * @param * @retval */ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(esp8266_cnt >= 255) //溢出判断,超过一个字节 { esp8266_cnt = 0; memset(ESP8266_Buf,0x00,sizeof(ESP8266_Buf)); HAL_UART_Transmit(&huart2, (uint8_t *)"数据溢出", 10,0xFFFF); } else { ESP8266_Buf[esp8266_cnt++] = a_esp8266_buf; //接收数据转存 } HAL_UART_Receive_IT(&huart2, (uint8_t *)&a_esp8266_buf, 1); //再开启接收中断 }
ESP8266.h
:
#ifndef _ESP8266_H_ #define _ESP8266_H_ #include "main.h" #include "usart.h" #include<string.h> #include<stdio.h> #include<stdbool.h> #define ESP8266_WIFI_INFO "AT+CWJAP=\"albbz\",\"2398953754\"\r\n" //连接上自己的wifi热点:WiFi名和密码 #define ESP8266_ONENET_INFO "AT+CIPSTART=\"TCP\",\"183.230.40.39\",6002\r\n" //连接上OneNet的MQTT #define OK 0 //接收完成标志 #define OUTTIME 1 //接收未完成标志 unsigned char ESP8266_Buf[128]; //定义一个数组作为esp8266的数据缓冲区 unsigned short esp8266_cnt = 0, esp8266_cntPre = 0; //定义两个计数值:此次和上一次 unsigned char a_esp8266_buf; void ESP8266_Clear(void); //清空缓存 void ESP8266_Init(void); //esp8266初始化 _Bool ESP8266_SendCmd(char *cmd, char *res);//发送数据 unsigned char *ESP8266_GetIPD(unsigned short timeOut); #endif
在使用连接onenet平台时,我们使用的 mqtt 协议的 IP 和端口号,但在代码中写的是TCP协议。 |
ONENET.c
:
在onenet上在控制台中,点击多协议接入,添加产品,得到产品ID,鉴权信息和设备ID,连接到wifi模块上。
#include "onenet.h" #include <string.h> #include <stdio.h> #define PROID "506530" //产品ID #define AUTH_INFO "wzyyds20201012wd" //鉴权信息 #define DEVID "929236606" //设备ID extern unsigned char esp8266_buf[128]; float sht20_info_tempreture = 12; float sht20_info_humidity = 15; //========================================================== // 函数名称: OneNet_DevLink // // 函数功能: 与onenet创建连接 // // 入口参数: 无 // // 返回参数: 1-成功 0-失败 // // 说明: 与onenet平台建立连接 //========================================================== _Bool OneNet_DevLink(void) { MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0}; //协议包,协议类型初始化 unsigned char *dataPtr; _Bool status = 1; printf("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) { ESP8266_SendData(mqttPacket._data, mqttPacket._len); //上传平台 dataPtr = ESP8266_GetIPD(250); //等待平台响应 if(dataPtr != NULL) { if(MQTT_UnPacketRecv(dataPtr) == MQTT_PKT_CONNACK) { switch(MQTT_UnPacketConnectAck(dataPtr)) { case 0:printf("Tips: 连接成功\r\n");status = 0;break; case 1:printf("WARN: 连接失败:协议错误\r\n");break; case 2:printf("WARN: 连接失败:非法的clientid\r\n");break; case 3:printf("WARN: 连接失败:服务器失败\r\n");break; case 4:printf("WARN: 连接失败:用户名或密码错误\r\n");break; case 5:printf("WARN: 连接失败:非法链接(比如token非法)\r\n");break; default:printf("ERR: 连接失败:未知错误\r\n");break; } } } MQTT_DeleteBuffer(&mqttPacket); //删包 } else printf("WARN: MQTT_PacketConnect Failed\r\n"); return status; } unsigned char OneNet_FillBuf(char *buf) { char text[32]; uint16_t LED0_FLAG = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_0); memset(text, 0, sizeof(text)); strcpy(buf, ",;"); memset(text, 0, sizeof(text)); sprintf(text, "Tempreture,%f;", sht20_info_tempreture); strcat(buf, text); memset(text, 0, sizeof(text)); sprintf(text, "Humidity,%f;", sht20_info_humidity); strcat(buf, text); // memset(text, 0, sizeof(text)); // sprintf(text, "key,%d;", LED0_FLAG); // strcat(buf, text); //memset(text, 0, sizeof(text)); //sprintf(text, "LED1,%d;", LED1_FLAG); //strcat(buf, text); //printf("buf_mqtt=%s\r\n",buf); 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; printf("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]; ESP8266_SendData(mqttPacket._data, mqttPacket._len); printf("Send %d Bytes\r\n", mqttPacket._len); MQTT_DeleteBuffer(&mqttPacket); //删包 } else printf("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) { printf("cmdid: %s, req: %s, req_len: %d\r\n", cmdid_topic, req_payload, req_len); if(MQTT_PacketCmdResp(cmdid_topic, req_payload, &mqttPacket) == 0) //命令回复组包 { printf("Tips: Send CmdResp\r\n"); ESP8266_SendData(mqttPacket._data, mqttPacket._len); //回复命令 MQTT_DeleteBuffer(&mqttPacket); //删包 } } break; case MQTT_PKT_PUBACK: //发送Publish消息,平台回复的Ack if(MQTT_UnPacketPublishAck(cmd) == 0) printf("Tips: MQTT Publish Send OK\r\n"); break; default: result = -1; break; } ESP8266_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(strstr((char *)req_payload, "key")) //搜索"key" { if(num == 1) //控制数据如果为1,代表开 { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET); } else if(num == 0) //控制数据如果为0,代表关 { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET); } } //下同 else if(strstr((char *)req_payload, "key1")) { if(num == 1) { printf("1\r\n"); } else if(num == 0) { printf("0\r\n"); } } } /************************************************************/ 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_ #include "esp8266.h" #include "mqttkit.h" #include "usart.h" #include "gpio.h" _Bool OneNet_DevLink(void); void OneNet_SendData(void); void OneNet_RevPro(unsigned char *cmd); /****************************************************** 主函数调用情况: 1、main函数里记得打开接收中断 2、ESP8266_Init(); while(OneNet_DevLink()) //接入OneNET HAL_Delay(500); printf("接入onenet成功"); OneNet_SendData();//发送数据给onenet 3、dataPtr = ESP8266_GetIPD(0);//获取平台返回的数据 if(dataPtr != NULL)//如果返回数据不为空 OneNet_RevPro(dataPtr);//平台返回数据检测()while循环内 ***********************************************************/ #endif
MqttKit.c
:
#include "MqttKit.h" //C库 #include <string.h> #include <stdio.h> #define CMD_TOPIC_PREFIX "$creq" //========================================================== // 函数名称: EDP_NewBuffer // // 函数功能: 申请内存 // // 入口参数: edpPacket:包结构体 // size:大小 // // 返回参数: 无 // // 说明: 1.可使用动态分配来分配内存 // 2.可使用局部或全局数组来指定内存 //========================================================== void MQTT_NewBuffer(MQTT_PACKET_STRUCTURE *mqttPacket, uint32 size) { uint32 i = 0; if(mqttPacket->_data == NULL) { mqttPacket->_memFlag = MEM_FLAG_ALLOC; mqttPacket->_data = (uint8 *)MQTT_MallocBuffer(size); if(mqttPacket->_data != NULL) { mqttPacket->_len = 0; mqttPacket->_size = size; for(; i < mqttPacket->_size; i++) mqttPacket->_data[i] = 0; } } else { mqttPacket->_memFlag = MEM_FLAG_STATIC; for(; i < mqttPacket->_size; i++) mqttPacket->_data[i] = 0; mqttPacket->_len = 0; if(mqttPacket->_size < size) mqttPacket->_data = NULL; } } //========================================================== // 函数名称: MQTT_DeleteBuffer // // 函数功能: 释放数据内存 // // 入口参数: edpPacket:包结构体 // // 返回参数: 无 // // 说明: //========================================================== void MQTT_DeleteBuffer(MQTT_PACKET_STRUCTURE *mqttPacket) { if(mqttPacket->_memFlag == MEM_FLAG_ALLOC) MQTT_FreeBuffer(mqttPacket->_data); mqttPacket->_data = NULL; mqttPacket->_len = 0; mqttPacket->_size = 0; mqttPacket->_memFlag = MEM_FLAG_NULL; } int32 MQTT_DumpLength(size_t len, uint8 *buf) { int32 i = 0; for(i = 1; i <= 4; ++i) { *buf = len % 128; len >>= 7; if(len > 0) { *buf |= 128; ++buf; } else { return i; } } return -1; } int32 MQTT_ReadLength(const uint8 *stream, int32 size, uint32 *len) { int32 i; const uint8 *in = stream; uint32 multiplier = 1; *len = 0; for(i = 0; i < size; ++i) { *len += (in[i] & 0x7f) * multiplier; if(!(in[i] & 0x80)) { return i + 1; } multiplier <<= 7; if(multiplier >= 2097152) //128 * *128 * *128 { return -2; // error, out of range } } return -1; // not complete } //========================================================== // 函数名称: MQTT_UnPacketRecv // // 函数功能: MQTT数据接收类型判断 // // 入口参数: dataPtr:接收的数据指针 // // 返回参数: 0-成功 其他-失败原因 // // 说明: //========================================================== uint8 MQTT_UnPacketRecv(uint8 *dataPtr) { uint8 status = 255; uint8 type = dataPtr[0] >> 4; //类型检查 if(type < 1 || type > 14) return status; if(type == MQTT_PKT_PUBLISH) { uint8 *msgPtr; uint32 remain_len = 0; msgPtr = dataPtr + MQTT_ReadLength(dataPtr + 1, 4, &remain_len) + 1; if(remain_len < 2 || dataPtr[0] & 0x01) //retain return 255; if(remain_len < ((uint16)msgPtr[0] << 8 | msgPtr[1]) + 2) return 255; if(strstr((int8 *)msgPtr + 2, CMD_TOPIC_PREFIX) != NULL) //如果是命令下发 status = MQTT_PKT_CMD; else status = MQTT_PKT_PUBLISH; } else status = type; return status; } //========================================================== // 函数名称: MQTT_PacketConnect // // 函数功能: 连接消息组包 // // 入口参数: user:用户名:产品ID // password:密码:鉴权信息或apikey // devid:设备ID // cTime:连接保持时间 // clean_session:离线消息清除标志 // qos:重发标志 // will_topic:异常离线topic // will_msg:异常离线消息 // will_retain:消息推送标志 // mqttPacket:包指针 // // 返回参数: 0-成功 其他-失败 // // 说明: //========================================================== uint8 MQTT_PacketConnect(const int8 *user, const int8 *password, const int8 *devid, uint16 cTime, uint1 clean_session, uint1 qos, const int8 *will_topic, const int8 *will_msg, int32 will_retain, MQTT_PACKET_STRUCTURE *mqttPacket) { uint8 flags = 0; uint8 will_topic_len = 0; uint16 total_len = 15; int16 len = 0, devid_len = strlen(devid); if(!devid) return 1; total_len += devid_len + 2; //断线后,是否清理离线消息:1-清理 0-不清理-------------------------------------------- if(clean_session) { flags |= MQTT_CONNECT_CLEAN_SESSION; } //异常掉线情况下,服务器发布的topic------------------------------------------------------ if(will_topic) { flags |= MQTT_CONNECT_WILL_FLAG; will_topic_len = strlen(will_topic); total_len += 4 + will_topic_len + strlen(will_msg); } //qos级别--主要用于PUBLISH(发布态)消息的,保证消息传递的次数----------------------------- switch((unsigned char)qos) { case MQTT_QOS_LEVEL0: flags |= MQTT_CONNECT_WILL_QOS0; //最多一次 break; case MQTT_QOS_LEVEL1: flags |= (MQTT_CONNECT_WILL_FLAG | MQTT_CONNECT_WILL_QOS1); //最少一次 break; case MQTT_QOS_LEVEL2: flags |= (MQTT_CONNECT_WILL_FLAG | MQTT_CONNECT_WILL_QOS2); //只有一次 break; default: return 2; } //主要用于PUBLISH(发布态)的消息,表示服务器要保留这次推送的信息,如果有新的订阅者出现,就把这消息推送给它。如果不设那么推送至当前订阅的就释放了 if(will_retain) { flags |= (MQTT_CONNECT_WILL_FLAG | MQTT_CONNECT_WILL_RETAIN); } //账号为空 密码为空--------------------------------------------------------------------- if(!user || !password) { return 3; } flags |= MQTT_CONNECT_USER_NAME | MQTT_CONNECT_PASSORD; total_len += strlen(user) + strlen(password) + 4; //分配内存----------------------------------------------------------------------------- MQTT_NewBuffer(mqttPacket, total_len); if(mqttPacket->_data == NULL) return 4; memset(mqttPacket->_data, 0, total_len); /*************************************固定头部***********************************************/ //固定头部----------------------连接请求类型--------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_CONNECT << 4; //固定头部----------------------剩余长度值----------------------------------------------- len = MQTT_DumpLength(total_len - 5, mqttPacket->_data + mqttPacket->_len); if(len < 0) { MQTT_DeleteBuffer(mqttPacket); return 5; } else mqttPacket->_len += len; /*************************************可变头部***********************************************/ //可变头部----------------------协议名长度 和 协议名-------------------------------------- mqttPacket->_data[mqttPacket->_len++] = 0; mqttPacket->_data[mqttPacket->_len++] = 4; mqttPacket->_data[mqttPacket->_len++] = 'M'; mqttPacket->_data[mqttPacket->_len++] = 'Q'; mqttPacket->_data[mqttPacket->_len++] = 'T'; mqttPacket->_data[mqttPacket->_len++] = 'T'; //可变头部----------------------protocol level 4----------------------------------------- mqttPacket->_data[mqttPacket->_len++] = 4; //可变头部----------------------连接标志(该函数开头处理的数据)----------------------------- mqttPacket->_data[mqttPacket->_len++] = flags; //可变头部----------------------保持连接的时间(秒)---------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(cTime); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(cTime); /*************************************消息体************************************************/ //消息体----------------------------devid长度、devid------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(devid_len); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(devid_len); strncat((int8 *)mqttPacket->_data + mqttPacket->_len, devid, devid_len); mqttPacket->_len += devid_len; //消息体----------------------------will_flag 和 will_msg--------------------------------- if(flags & MQTT_CONNECT_WILL_FLAG) { unsigned short mLen = 0; if(!will_msg) will_msg = ""; mLen = strlen(will_topic); mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(mLen); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(mLen); strncat((int8 *)mqttPacket->_data + mqttPacket->_len, will_topic, mLen); mqttPacket->_len += mLen; mLen = strlen(will_msg); mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(mLen); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(mLen); strncat((int8 *)mqttPacket->_data + mqttPacket->_len, will_msg, mLen); mqttPacket->_len += mLen; } //消息体----------------------------use--------------------------------------------------- if(flags & MQTT_CONNECT_USER_NAME) { unsigned short user_len = strlen(user); mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(user_len); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(user_len); strncat((int8 *)mqttPacket->_data + mqttPacket->_len, user, user_len); mqttPacket->_len += user_len; } //消息体----------------------------password---------------------------------------------- if(flags & MQTT_CONNECT_PASSORD) { unsigned short psw_len = strlen(password); mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(psw_len); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(psw_len); strncat((int8 *)mqttPacket->_data + mqttPacket->_len, password, psw_len); mqttPacket->_len += psw_len; } return 0; } //========================================================== // 函数名称: MQTT_PacketDisConnect // // 函数功能: 断开连接消息组包 // // 入口参数: mqttPacket:包指针 // // 返回参数: 0-成功 1-失败 // // 说明: //========================================================== uint1 MQTT_PacketDisConnect(MQTT_PACKET_STRUCTURE *mqttPacket) { MQTT_NewBuffer(mqttPacket, 2); if(mqttPacket->_data == NULL) return 1; /*************************************固定头部***********************************************/ //固定头部----------------------头部消息------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_DISCONNECT << 4; //固定头部----------------------剩余长度值----------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = 0; return 0; } //========================================================== // 函数名称: MQTT_UnPacketConnectAck // // 函数功能: 连接消息解包 // // 入口参数: rev_data:接收的数据 // // 返回参数: 1、255-失败 其他-平台的返回码 // // 说明: //========================================================== uint8 MQTT_UnPacketConnectAck(uint8 *rev_data) { if(rev_data[1] != 2) return 1; if(rev_data[2] == 0 || rev_data[2] == 1) return rev_data[3]; else return 255; } //========================================================== // 函数名称: MQTT_PacketSaveData // // 函数功能: 数据点上传组包 // // 入口参数: devid:设备ID(可为空) // send_buf:json缓存buf // send_len:json总长 // type_bin_head:bin文件的消息头 // type:类型 // // 返回参数: 0-成功 1-失败 // // 说明: //========================================================== uint1 MQTT_PacketSaveData(const int8 *devid, int16 send_len, int8 *type_bin_head, uint8 type, MQTT_PACKET_STRUCTURE *mqttPacket) { if(MQTT_PacketPublish(MQTT_PUBLISH_ID, "$dp", NULL, send_len + 3, MQTT_QOS_LEVEL1, 0, 1, mqttPacket) == 0) { mqttPacket->_data[mqttPacket->_len++] = type; //类型 mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(send_len); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(send_len); } else return 1; return 0; } //========================================================== // 函数名称: MQTT_PacketSaveBinData // // 函数功能: 为禁止文件上传组包 // // 入口参数: name:数据流名字 // file_len:文件长度 // mqttPacket:包指针 // // 返回参数: 0-成功 1-失败 // // 说明: //========================================================== uint1 MQTT_PacketSaveBinData(const int8 *name, int16 file_len, MQTT_PACKET_STRUCTURE *mqttPacket) { uint1 result = 1; int8 *bin_head = NULL; uint8 bin_head_len = 0; int8 *payload = NULL; int32 payload_size = 0; bin_head = (int8 *)MQTT_MallocBuffer(13 + strlen(name)); if(bin_head == NULL) return result; sprintf(bin_head, "{\"ds_id\":\"%s\"}", name); bin_head_len = strlen(bin_head); payload_size = 7 + bin_head_len + file_len; payload = (int8 *)MQTT_MallocBuffer(payload_size - file_len); if(payload == NULL) { MQTT_FreeBuffer(bin_head); return result; } payload[0] = 2; //类型 payload[1] = MOSQ_MSB(bin_head_len); payload[2] = MOSQ_LSB(bin_head_len); memcpy(payload + 3, bin_head, bin_head_len); payload[bin_head_len + 3] = (file_len >> 24) & 0xFF; payload[bin_head_len + 4] = (file_len >> 16) & 0xFF; payload[bin_head_len + 5] = (file_len >> 8) & 0xFF; payload[bin_head_len + 6] = file_len & 0xFF; if(MQTT_PacketPublish(MQTT_PUBLISH_ID, "$dp", payload, payload_size, MQTT_QOS_LEVEL1, 0, 1, mqttPacket) == 0) result = 0; MQTT_FreeBuffer(bin_head); MQTT_FreeBuffer(payload); return result; } //========================================================== // 函数名称: MQTT_UnPacketCmd // // 函数功能: 命令下发解包 // // 入口参数: rev_data:接收的数据指针 // cmdid:cmdid-uuid // req:命令 // // 返回参数: 0-成功 其他-失败原因 // // 说明: //========================================================== uint8 MQTT_UnPacketCmd(uint8 *rev_data, int8 **cmdid, int8 **req, uint16 *req_len) { int8 *dataPtr = strchr((int8 *)rev_data + 6, '/'); //加6是跳过头信息 uint32 remain_len = 0; if(dataPtr == NULL) //未找到'/' return 1; dataPtr++; //跳过'/' MQTT_ReadLength(rev_data + 1, 4, &remain_len); //读取剩余字节 *cmdid = (int8 *)MQTT_MallocBuffer(37); //cmdid固定36字节,多分配一个结束符的位置 if(*cmdid == NULL) return 2; memset(*cmdid, 0, 37); //全部清零 memcpy(*cmdid, (const int8 *)dataPtr, 36); //复制cmdid dataPtr += 36; *req_len = remain_len - 44; //命令长度 = 剩余长度(remain_len) - 2 - 5($creq) - 1(\) - cmdid长度 *req = (int8 *)MQTT_MallocBuffer(*req_len + 1); //分配命令长度+1 if(*req == NULL) { MQTT_FreeBuffer(*cmdid); return 3; } memset(*req, 0, *req_len + 1); //清零 memcpy(*req, (const int8 *)dataPtr, *req_len); //复制命令 return 0; } //========================================================== // 函数名称: MQTT_PacketCmdResp // // 函数功能: 命令回复组包 // // 入口参数: cmdid:cmdid // req:命令 // mqttPacket:包指针 // // 返回参数: 0-成功 1-失败 // // 说明: //========================================================== uint1 MQTT_PacketCmdResp(const int8 *cmdid, const int8 *req, MQTT_PACKET_STRUCTURE *mqttPacket) { uint16 cmdid_len = strlen(cmdid); uint16 req_len = strlen(req); _Bool status = 0; int8 *payload = MQTT_MallocBuffer(cmdid_len + 7); if(payload == NULL) return 1; memset(payload, 0, cmdid_len + 7); memcpy(payload, "$crsp/", 6); strncat(payload, cmdid, cmdid_len); if(MQTT_PacketPublish(MQTT_PUBLISH_ID, payload, req, strlen(req), MQTT_QOS_LEVEL0, 0, 1, mqttPacket) == 0) status = 0; else status = 1; MQTT_FreeBuffer(payload); return status; } //========================================================== // 函数名称: MQTT_PacketSubscribe // // 函数功能: Subscribe消息组包 // // 入口参数: pkt_id:pkt_id // qos:消息重发次数 // topics:订阅的消息 // topics_cnt:订阅的消息个数 // mqttPacket:包指针 // // 返回参数: 0-成功 其他-失败 // // 说明: //========================================================== uint8 MQTT_PacketSubscribe(uint16 pkt_id, enum MqttQosLevel qos, const int8 *topics[], uint8 topics_cnt, MQTT_PACKET_STRUCTURE *mqttPacket) { uint32 topic_len = 0, remain_len = 0; int16 len = 0; uint8 i = 0; if(pkt_id == 0) return 1; //计算topic长度------------------------------------------------------------------------- for(; i < topics_cnt; i++) { if(topics[i] == NULL) return 2; topic_len += strlen(topics[i]); } //2 bytes packet id + topic filter(2 bytes topic + topic length + 1 byte reserve)------ remain_len = 2 + 3 * topics_cnt + topic_len; //分配内存------------------------------------------------------------------------------ MQTT_NewBuffer(mqttPacket, remain_len + 5); if(mqttPacket->_data == NULL) return 3; /*************************************固定头部***********************************************/ //固定头部----------------------头部消息------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_SUBSCRIBE << 4 | 0x02; //固定头部----------------------剩余长度值----------------------------------------------- len = MQTT_DumpLength(remain_len, mqttPacket->_data + mqttPacket->_len); if(len < 0) { MQTT_DeleteBuffer(mqttPacket); return 4; } else mqttPacket->_len += len; /*************************************payload***********************************************/ //payload----------------------pkt_id--------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(pkt_id); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(pkt_id); //payload----------------------topic_name----------------------------------------------- for(i = 0; i < topics_cnt; i++) { topic_len = strlen(topics[i]); mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(topic_len); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(topic_len); strncat((int8 *)mqttPacket->_data + mqttPacket->_len, topics[i], topic_len); mqttPacket->_len += topic_len; mqttPacket->_data[mqttPacket->_len++] = qos & 0xFF; } return 0; } //========================================================== // 函数名称: MQTT_UnPacketSubscrebe // // 函数功能: Subscribe的回复消息解包 // // 入口参数: rev_data:接收到的信息 // // 返回参数: 0-成功 其他-失败 // // 说明: //========================================================== uint8 MQTT_UnPacketSubscribe(uint8 *rev_data) { uint8 result = 255; if(rev_data[2] == MOSQ_MSB(MQTT_SUBSCRIBE_ID) && rev_data[3] == MOSQ_LSB(MQTT_SUBSCRIBE_ID)) { switch(rev_data[4]) { case 0x00: case 0x01: case 0x02: //MQTT Subscribe OK result = 0; break; case 0x80: //MQTT Subscribe Failed result = 1; break; default: //MQTT Subscribe UnKnown Err result = 2; break; } } return result; } //========================================================== // 函数名称: MQTT_PacketUnSubscribe // // 函数功能: UnSubscribe消息组包 // // 入口参数: pkt_id:pkt_id // qos:消息重发次数 // topics:订阅的消息 // topics_cnt:订阅的消息个数 // mqttPacket:包指针 // // 返回参数: 0-成功 其他-失败 // // 说明: //========================================================== uint8 MQTT_PacketUnSubscribe(uint16 pkt_id, const int8 *topics[], uint8 topics_cnt, MQTT_PACKET_STRUCTURE *mqttPacket) { uint32 topic_len = 0, remain_len = 0; int16 len = 0; uint8 i = 0; if(pkt_id == 0) return 1; //计算topic长度------------------------------------------------------------------------- for(; i < topics_cnt; i++) { if(topics[i] == NULL) return 2; topic_len += strlen(topics[i]); } //2 bytes packet id, 2 bytes topic length + topic + 1 byte reserve--------------------- remain_len = 2 + (topics_cnt << 1) + topic_len; //分配内存------------------------------------------------------------------------------ MQTT_NewBuffer(mqttPacket, remain_len + 5); if(mqttPacket->_data == NULL) return 3; /*************************************固定头部***********************************************/ //固定头部----------------------头部消息------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_UNSUBSCRIBE << 4 | 0x02; //固定头部----------------------剩余长度值----------------------------------------------- len = MQTT_DumpLength(remain_len, mqttPacket->_data + mqttPacket->_len); if(len < 0) { MQTT_DeleteBuffer(mqttPacket); return 4; } else mqttPacket->_len += len; /*************************************payload***********************************************/ //payload----------------------pkt_id--------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(pkt_id); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(pkt_id); //payload----------------------topic_name----------------------------------------------- for(i = 0; i < topics_cnt; i++) { topic_len = strlen(topics[i]); mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(topic_len); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(topic_len); strncat((int8 *)mqttPacket->_data + mqttPacket->_len, topics[i], topic_len); mqttPacket->_len += topic_len; } return 0; } //========================================================== // 函数名称: MQTT_UnPacketUnSubscribe // // 函数功能: UnSubscribe的回复消息解包 // // 入口参数: rev_data:接收到的信息 // // 返回参数: 0-成功 其他-失败 // // 说明: //========================================================== uint1 MQTT_UnPacketUnSubscribe(uint8 *rev_data) { uint1 result = 1; if(rev_data[2] == MOSQ_MSB(MQTT_UNSUBSCRIBE_ID) && rev_data[3] == MOSQ_LSB(MQTT_UNSUBSCRIBE_ID)) { result = 0; } return result; } //========================================================== // 函数名称: MQTT_PacketPublish // // 函数功能: Pulish消息组包 // // 入口参数: pkt_id:pkt_id // topic:发布的topic // payload:消息体 // payload_len:消息体长度 // qos:重发次数 // retain:离线消息推送 // own: // mqttPacket:包指针 // // 返回参数: 0-成功 其他-失败 // // 说明: //========================================================== uint8 MQTT_PacketPublish(uint16 pkt_id, const int8 *topic, const int8 *payload, uint32 payload_len, enum MqttQosLevel qos, int32 retain, int32 own, MQTT_PACKET_STRUCTURE *mqttPacket) { uint32 total_len = 0, topic_len = 0; uint32 data_len = 0; int32 len = 0; uint8 flags = 0; //pkt_id检查---------------------------------------------------------------------------- if(pkt_id == 0) return 1; //$dp为系统上传数据点的指令-------------------------------------------------------------- for(topic_len = 0; topic[topic_len] != '\0'; ++topic_len) { if((topic[topic_len] == '#') || (topic[topic_len] == '+')) return 2; } //Publish消息--------------------------------------------------------------------------- flags |= MQTT_PKT_PUBLISH << 4; //retain标志---------------------------------------------------------------------------- if(retain) flags |= 0x01; //总长度-------------------------------------------------------------------------------- total_len = topic_len + payload_len + 2; //qos级别--主要用于PUBLISH(发布态)消息的,保证消息传递的次数----------------------------- switch(qos) { case MQTT_QOS_LEVEL0: flags |= MQTT_CONNECT_WILL_QOS0; //最多一次 break; case MQTT_QOS_LEVEL1: flags |= 0x02; //最少一次 total_len += 2; break; case MQTT_QOS_LEVEL2: flags |= 0x04; //只有一次 total_len += 2; break; default: return 3; } //分配内存------------------------------------------------------------------------------ if(payload != NULL) { if(payload[0] == 2) { uint32 data_len_t = 0; while(payload[data_len_t++] != '}'); data_len_t -= 3; data_len = data_len_t + 7; data_len_t = payload_len - data_len; MQTT_NewBuffer(mqttPacket, total_len + 3 - data_len_t); if(mqttPacket->_data == NULL) return 4; memset(mqttPacket->_data, 0, total_len + 3 - data_len_t); } else { MQTT_NewBuffer(mqttPacket, total_len + 5); if(mqttPacket->_data == NULL) return 4; memset(mqttPacket->_data, 0, total_len + 5); } } else { MQTT_NewBuffer(mqttPacket, total_len + 5); if(mqttPacket->_data == NULL) return 4; memset(mqttPacket->_data, 0, total_len + 5); } /*************************************固定头部***********************************************/ //固定头部----------------------头部消息------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = flags; //固定头部----------------------剩余长度值----------------------------------------------- len = MQTT_DumpLength(total_len, mqttPacket->_data + mqttPacket->_len); if(len < 0) { MQTT_DeleteBuffer(mqttPacket); return 5; } else mqttPacket->_len += len; /*************************************可变头部***********************************************/ //可变头部----------------------写入topic长度、topic------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(topic_len); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(topic_len); strncat((int8 *)mqttPacket->_data + mqttPacket->_len, topic, topic_len); mqttPacket->_len += topic_len; if(qos != MQTT_QOS_LEVEL0) { mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(pkt_id); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(pkt_id); } //可变头部----------------------写入payload---------------------------------------------- if(payload != NULL) { if(payload[0] == 2) { memcpy((int8 *)mqttPacket->_data + mqttPacket->_len, payload, data_len); mqttPacket->_len += data_len; } else { memcpy((int8 *)mqttPacket->_data + mqttPacket->_len, payload, payload_len); mqttPacket->_len += payload_len; } } return 0; } //========================================================== // 函数名称: MQTT_UnPacketPublish // // 函数功能: Publish消息解包 // // 入口参数: flags:MQTT相关标志信息 // pkt:指向可变头部 // size:固定头部中的剩余长度信息 // // 返回参数: 0-成功 其他-失败原因 // // 说明: //========================================================== uint8 MQTT_UnPacketPublish(uint8 *rev_data, int8 **topic, uint16 *topic_len, int8 **payload, uint16 *payload_len, uint8 *qos, uint16 *pkt_id) { const int8 flags = rev_data[0] & 0x0F; uint8 *msgPtr; uint32 remain_len = 0; const int8 dup = flags & 0x08; *qos = (flags & 0x06) >> 1; msgPtr = rev_data + MQTT_ReadLength(rev_data + 1, 4, &remain_len) + 1; if(remain_len < 2 || flags & 0x01) //retain return 255; *topic_len = (uint16)msgPtr[0] << 8 | msgPtr[1]; if(remain_len < *topic_len + 2) return 255; if(strstr((int8 *)msgPtr + 2, CMD_TOPIC_PREFIX) != NULL) //如果是命令下发 return MQTT_PKT_CMD; switch(*qos) { case MQTT_QOS_LEVEL0: // qos0 have no packet identifier if(0 != dup) return 255; *topic = MQTT_MallocBuffer(*topic_len + 1); //为topic分配内存 if(*topic == NULL) return 255; memset(*topic, 0, *topic_len + 1); memcpy(*topic, (int8 *)msgPtr + 2, *topic_len); //复制数据 *payload_len = remain_len - 2 - *topic_len; //为payload分配内存 *payload = MQTT_MallocBuffer(*payload_len + 1); if(*payload == NULL) //如果失败 { MQTT_FreeBuffer(*topic); //则需要把topic的内存释放掉 return 255; } memset(*payload, 0, *payload_len + 1); memcpy(*payload, (int8 *)msgPtr + 2 + *topic_len, *payload_len); break; case MQTT_QOS_LEVEL1: case MQTT_QOS_LEVEL2: if(*topic_len + 2 > remain_len) return 255; *pkt_id = (uint16)msgPtr[*topic_len + 2] << 8 | msgPtr[*topic_len + 3]; if(pkt_id == 0) return 255; *topic = MQTT_MallocBuffer(*topic_len + 1); //为topic分配内存 if(*topic == NULL) return 255; memset(*topic, 0, *topic_len + 1); memcpy(*topic, (int8 *)msgPtr + 2, *topic_len); //复制数据 *payload_len = remain_len - 4 - *topic_len; *payload = MQTT_MallocBuffer(*payload_len + 1); //为payload分配内存 if(*payload == NULL) //如果失败 { MQTT_FreeBuffer(*topic); //则需要把topic的内存释放掉 return 255; } memset(*payload, 0, *payload_len + 1); memcpy(*payload, (int8 *)msgPtr + 4 + *topic_len, *payload_len); break; default: return 255; } if(strchr((int8 *)topic, '+') || strchr((int8 *)topic, '#')) return 255; return 0; } //========================================================== // 函数名称: MQTT_PacketPublishAck // // 函数功能: Publish Ack消息组包 // // 入口参数: pkt_id:packet id // mqttPacket:包指针 // // 返回参数: 0-成功 1-失败原因 // // 说明: 当收到的Publish消息的QoS等级为1时,需要Ack回复 //========================================================== uint1 MQTT_PacketPublishAck(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket) { MQTT_NewBuffer(mqttPacket, 4); if(mqttPacket->_data == NULL) return 1; /*************************************固定头部***********************************************/ //固定头部----------------------头部消息------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_PUBACK << 4; //固定头部----------------------剩余长度------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = 2; /*************************************可变头部***********************************************/ //可变头部----------------------pkt_id长度----------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = pkt_id >> 8; mqttPacket->_data[mqttPacket->_len++] = pkt_id & 0xff; return 0; } //========================================================== // 函数名称: MQTT_UnPacketPublishAck // // 函数功能: Publish Ack消息解包 // // 入口参数: rev_data:收到的数据 // // 返回参数: 0-成功 1-失败原因 // // 说明: //========================================================== uint1 MQTT_UnPacketPublishAck(uint8 *rev_data) { if(rev_data[1] != 2) return 1; if(rev_data[2] == MOSQ_MSB(MQTT_PUBLISH_ID) && rev_data[3] == MOSQ_LSB(MQTT_PUBLISH_ID)) return 0; else return 1; } //========================================================== // 函数名称: MQTT_PacketPublishRec // // 函数功能: Publish Rec消息组包 // // 入口参数: pkt_id:packet id // mqttPacket:包指针 // // 返回参数: 0-成功 1-失败原因 // // 说明: 当收到的Publish消息的QoS等级为2时,先收到rec //========================================================== uint1 MQTT_PacketPublishRec(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket) { MQTT_NewBuffer(mqttPacket, 4); if(mqttPacket->_data == NULL) return 1; /*************************************固定头部***********************************************/ //固定头部----------------------头部消息------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_PUBREC << 4; //固定头部----------------------剩余长度------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = 2; /*************************************可变头部***********************************************/ //可变头部----------------------pkt_id长度----------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = pkt_id >> 8; mqttPacket->_data[mqttPacket->_len++] = pkt_id & 0xff; return 0; } //========================================================== // 函数名称: MQTT_UnPacketPublishRec // // 函数功能: Publish Rec消息解包 // // 入口参数: rev_data:接收到的数据 // // 返回参数: 0-成功 1-失败 // // 说明: //========================================================== uint1 MQTT_UnPacketPublishRec(uint8 *rev_data) { if(rev_data[1] != 2) return 1; if(rev_data[2] == MOSQ_MSB(MQTT_PUBLISH_ID) && rev_data[3] == MOSQ_LSB(MQTT_PUBLISH_ID)) return 0; else return 1; } //========================================================== // 函数名称: MQTT_PacketPublishRel // // 函数功能: Publish Rel消息组包 // // 入口参数: pkt_id:packet id // mqttPacket:包指针 // // 返回参数: 0-成功 1-失败原因 // // 说明: 当收到的Publish消息的QoS等级为2时,先收到rec,再回复rel //========================================================== uint1 MQTT_PacketPublishRel(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket) { MQTT_NewBuffer(mqttPacket, 4); if(mqttPacket->_data == NULL) return 1; /*************************************固定头部***********************************************/ //固定头部----------------------头部消息------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_PUBREL << 4 | 0x02; //固定头部----------------------剩余长度------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = 2; /*************************************可变头部***********************************************/ //可变头部----------------------pkt_id长度----------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = pkt_id >> 8; mqttPacket->_data[mqttPacket->_len++] = pkt_id & 0xff; return 0; } //========================================================== // 函数名称: MQTT_UnPacketPublishRel // // 函数功能: Publish Rel消息解包 // // 入口参数: rev_data:接收到的数据 // // 返回参数: 0-成功 1-失败 // // 说明: //========================================================== uint1 MQTT_UnPacketPublishRel(uint8 *rev_data, uint16 pkt_id) { if(rev_data[1] != 2) return 1; if(rev_data[2] == MOSQ_MSB(pkt_id) && rev_data[3] == MOSQ_LSB(pkt_id)) return 0; else return 1; } //========================================================== // 函数名称: MQTT_PacketPublishComp // // 函数功能: Publish Comp消息组包 // // 入口参数: pkt_id:packet id // mqttPacket:包指针 // // 返回参数: 0-成功 1-失败原因 // // 说明: 当收到的Publish消息的QoS等级为2时,先收到rec,再回复rel //========================================================== uint1 MQTT_PacketPublishComp(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket) { MQTT_NewBuffer(mqttPacket, 4); if(mqttPacket->_data == NULL) return 1; /*************************************固定头部***********************************************/ //固定头部----------------------头部消息------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_PUBCOMP << 4; //固定头部----------------------剩余长度------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = 2; /*************************************可变头部***********************************************/ //可变头部----------------------pkt_id长度----------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = pkt_id >> 8; mqttPacket->_data[mqttPacket->_len++] = pkt_id & 0xff; return 0; } //========================================================== // 函数名称: MQTT_UnPacketPublishComp // // 函数功能: Publish Comp消息解包 // // 入口参数: rev_data:接收到的数据 // // 返回参数: 0-成功 1-失败 // // 说明: //========================================================== uint1 MQTT_UnPacketPublishComp(uint8 *rev_data) { if(rev_data[1] != 2) return 1; if(rev_data[2] == MOSQ_MSB(MQTT_PUBLISH_ID) && rev_data[3] == MOSQ_LSB(MQTT_PUBLISH_ID)) return 0; else return 1; } //========================================================== // 函数名称: MQTT_PacketPing // // 函数功能: 心跳请求组包 // // 入口参数: mqttPacket:包指针 // // 返回参数: 0-成功 1-失败 // // 说明: //========================================================== uint1 MQTT_PacketPing(MQTT_PACKET_STRUCTURE *mqttPacket) { MQTT_NewBuffer(mqttPacket, 2); if(mqttPacket->_data == NULL) return 1; /*************************************固定头部***********************************************/ //固定头部----------------------头部消息------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_PINGREQ << 4; //固定头部----------------------剩余长度------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = 0; return 0; }
MqttKit.h
:
#ifndef _MQTTKIT_H_ #define _MQTTKIT_H_ #include "Common.h" #include <stdlib.h> #define MQTT_MallocBuffer malloc #define MQTT_FreeBuffer free //========================================================== #define MOSQ_MSB(A) (uint8)((A & 0xFF00) >> 8) #define MOSQ_LSB(A) (uint8)(A & 0x00FF) /*--------------------------------内存分配方案标志--------------------------------*/ #define MEM_FLAG_NULL 0 #define MEM_FLAG_ALLOC 1 #define MEM_FLAG_STATIC 2 typedef struct Buffer { uint8 *_data; //协议数据 uint32 _len; //写入的数据长度 uint32 _size; //缓存总大小 uint8 _memFlag; //内存使用的方案:0-未分配 1-使用的动态分配 2-使用的固定内存 } MQTT_PACKET_STRUCTURE; /*--------------------------------固定头部消息类型--------------------------------*/ enum MqttPacketType { MQTT_PKT_CONNECT = 1, /**< 连接请求数据包 */ MQTT_PKT_CONNACK, /**< 连接确认数据包 */ MQTT_PKT_PUBLISH, /**< 发布数据数据包 */ MQTT_PKT_PUBACK, /**< 发布确认数据包 */ MQTT_PKT_PUBREC, /**< 发布数据已接收数据包,Qos 2时,回复MQTT_PKT_PUBLISH */ MQTT_PKT_PUBREL, /**< 发布数据释放数据包, Qos 2时,回复MQTT_PKT_PUBREC */ MQTT_PKT_PUBCOMP, /**< 发布完成数据包, Qos 2时,回复MQTT_PKT_PUBREL */ MQTT_PKT_SUBSCRIBE, /**< 订阅数据包 */ MQTT_PKT_SUBACK, /**< 订阅确认数据包 */ MQTT_PKT_UNSUBSCRIBE, /**< 取消订阅数据包 */ MQTT_PKT_UNSUBACK, /**< 取消订阅确认数据包 */ MQTT_PKT_PINGREQ, /**< ping 数据包 */ MQTT_PKT_PINGRESP, /**< ping 响应数据包 */ MQTT_PKT_DISCONNECT, /**< 断开连接数据包 */ //新增 MQTT_PKT_CMD /**< 命令下发数据包 */ }; /*--------------------------------MQTT QOS等级--------------------------------*/ enum MqttQosLevel { MQTT_QOS_LEVEL0, /**< 最多发送一次 */ MQTT_QOS_LEVEL1, /**< 最少发送一次 */ MQTT_QOS_LEVEL2 /**< 只发送一次 */ }; /*--------------------------------MQTT 连接请求标志位,内部使用--------------------------------*/ enum MqttConnectFlag { MQTT_CONNECT_CLEAN_SESSION = 0x02, MQTT_CONNECT_WILL_FLAG = 0x04, MQTT_CONNECT_WILL_QOS0 = 0x00, MQTT_CONNECT_WILL_QOS1 = 0x08, MQTT_CONNECT_WILL_QOS2 = 0x10, MQTT_CONNECT_WILL_RETAIN = 0x20, MQTT_CONNECT_PASSORD = 0x40, MQTT_CONNECT_USER_NAME = 0x80 }; /*--------------------------------消息的packet ID,可自定义--------------------------------*/ #define MQTT_PUBLISH_ID 10 #define MQTT_SUBSCRIBE_ID 20 #define MQTT_UNSUBSCRIBE_ID 30 /*--------------------------------删包--------------------------------*/ void MQTT_DeleteBuffer(MQTT_PACKET_STRUCTURE *mqttPacket); /*--------------------------------解包--------------------------------*/ uint8 MQTT_UnPacketRecv(uint8 *dataPtr); /*--------------------------------登录组包--------------------------------*/ uint8 MQTT_PacketConnect(const int8 *user, const int8 *password, const int8 *devid, uint16 cTime, uint1 clean_session, uint1 qos, const int8 *will_topic, const int8 *will_msg, int32 will_retain, MQTT_PACKET_STRUCTURE *mqttPacket); /*--------------------------------断开连接组包--------------------------------*/ uint1 MQTT_PacketDisConnect(MQTT_PACKET_STRUCTURE *mqttPacket); /*--------------------------------连接响应解包--------------------------------*/ uint8 MQTT_UnPacketConnectAck(uint8 *rev_data); /*--------------------------------数据点上传组包--------------------------------*/ uint1 MQTT_PacketSaveData(const int8 *devid, int16 send_len, int8 *type_bin_head, uint8 type, MQTT_PACKET_STRUCTURE *mqttPacket); /*--------------------------------二进制文件上传组包--------------------------------*/ uint1 MQTT_PacketSaveBinData(const int8 *name, int16 file_len, MQTT_PACKET_STRUCTURE *mqttPacket); /*--------------------------------命令下发解包--------------------------------*/ uint8 MQTT_UnPacketCmd(uint8 *rev_data, int8 **cmdid, int8 **req, uint16 *req_len); /*--------------------------------命令回复组包--------------------------------*/ uint1 MQTT_PacketCmdResp(const int8 *cmdid, const int8 *req, MQTT_PACKET_STRUCTURE *mqttPacket); /*--------------------------------订阅主题组包--------------------------------*/ uint8 MQTT_PacketSubscribe(uint16 pkt_id, enum MqttQosLevel qos, const int8 *topics[], uint8 topics_cnt, MQTT_PACKET_STRUCTURE *mqttPacket); /*--------------------------------订阅主题回复解包--------------------------------*/ uint8 MQTT_UnPacketSubscribe(uint8 *rev_data); /*--------------------------------取消订阅组包--------------------------------*/ uint8 MQTT_PacketUnSubscribe(uint16 pkt_id, const int8 *topics[], uint8 topics_cnt, MQTT_PACKET_STRUCTURE *mqttPacket); /*--------------------------------取消订阅回复解包--------------------------------*/ uint1 MQTT_UnPacketUnSubscribe(uint8 *rev_data); /*--------------------------------发布主题组包--------------------------------*/ uint8 MQTT_PacketPublish(uint16 pkt_id, const int8 *topic, const int8 *payload, uint32 payload_len, enum MqttQosLevel qos, int32 retain, int32 own, MQTT_PACKET_STRUCTURE *mqttPacket); /*--------------------------------发布消息回复解包--------------------------------*/ uint8 MQTT_UnPacketPublish(uint8 *rev_data, int8 **topic, uint16 *topic_len, int8 **payload, uint16 *payload_len, uint8 *qos, uint16 *pkt_id); /*--------------------------------发布消息的Ack组包--------------------------------*/ uint1 MQTT_PacketPublishAck(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket); /*--------------------------------发布消息的Ack解包--------------------------------*/ uint1 MQTT_UnPacketPublishAck(uint8 *rev_data); /*--------------------------------发布消息的Rec组包--------------------------------*/ uint1 MQTT_PacketPublishRec(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket); /*--------------------------------发布消息的Rec解包--------------------------------*/ uint1 MQTT_UnPacketPublishRec(uint8 *rev_data); /*--------------------------------发布消息的Rel组包--------------------------------*/ uint1 MQTT_PacketPublishRel(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket); /*--------------------------------发布消息的Rel解包--------------------------------*/ uint1 MQTT_UnPacketPublishRel(uint8 *rev_data, uint16 pkt_id); /*--------------------------------发布消息的Comp组包--------------------------------*/ uint1 MQTT_PacketPublishComp(uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket); /*--------------------------------发布消息的Comp解包--------------------------------*/ uint1 MQTT_UnPacketPublishComp(uint8 *rev_data); /*--------------------------------心跳请求组包--------------------------------*/ uint1 MQTT_PacketPing(MQTT_PACKET_STRUCTURE *mqttPacket); #endif
common.h
:
#ifndef __COMMON_H__ #define __COMMON_H__ /*---------------------------------------------------------------------------*/ /* Type Definition Macros */ /*---------------------------------------------------------------------------*/ 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; #endif /* __COMMON_H__ */
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。