fix the conflict
| 
						 | 
					@ -286,6 +286,10 @@ menu "test app"
 | 
				
			||||||
                bool "Config test ftp client"
 | 
					                bool "Config test ftp client"
 | 
				
			||||||
                default n
 | 
					                default n
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
 | 
					            menuconfig USER_TEST_FTPCLIENT_RISCV
 | 
				
			||||||
 | 
					                bool "Config test ftp client on riscv"
 | 
				
			||||||
 | 
					                default n
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            menuconfig USER_TEST_LORA_P2P
 | 
					            menuconfig USER_TEST_LORA_P2P
 | 
				
			||||||
                bool "Config test lora p2p"
 | 
					                bool "Config test lora p2p"
 | 
				
			||||||
                default n
 | 
					                default n
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -126,15 +126,21 @@ ifeq ($(CONFIG_ADD_XIZI_FEATURES),y)
 | 
				
			||||||
    endif 
 | 
					    endif 
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
    ifeq ($(CONFIG_USER_TEST_WEBSERVER),y)
 | 
					    ifeq ($(CONFIG_USER_TEST_WEBSERVER),y)
 | 
				
			||||||
        SRC_FILES += 
 | 
					        SRC_FILES += test_webserver/test_webserver.c
 | 
				
			||||||
    endif
 | 
					    endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ifeq ($(CONFIG_USER_TEST_MQTTCLIENT),y)
 | 
					    ifeq ($(CONFIG_USER_TEST_MQTTCLIENT),y)
 | 
				
			||||||
 | 
					        SRC_DIR:= test_mqttclient
 | 
				
			||||||
        SRC_FILES += 
 | 
					        SRC_FILES += 
 | 
				
			||||||
    endif
 | 
					    endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ifeq ($(CONFIG_USER_TEST_FTPCLIENT),y)
 | 
					    ifeq ($(CONFIG_USER_TEST_FTPCLIENT),y)
 | 
				
			||||||
        SRC_FILES += test_ftpclient_final/test_ftpclient_final.c test_ftpclient_final/ftp_client/ftp_client.c test_ftpclient_final/ftp_client/my_socket.c
 | 
					        SRC_FILES += test_ftpclient/test_ftpclient.c test_ftpclient/ftp_client/ftp_client.c\
 | 
				
			||||||
 | 
					                     test_ftpclient/ftp_client/my_socket.c
 | 
				
			||||||
 | 
					    endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ifeq ($(CONFIG_USER_TEST_FTPCLIENT_RISCV),y)
 | 
				
			||||||
 | 
					        SRC_FILES += test_ftpclient_riscv/test_ftpclient_riscv.c
 | 
				
			||||||
    endif
 | 
					    endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ifeq ($(CONFIG_USER_TEST_LORA_P2P),y)
 | 
					    ifeq ($(CONFIG_USER_TEST_LORA_P2P),y)
 | 
				
			||||||
| 
						 | 
					@ -153,5 +159,9 @@ ifeq ($(CONFIG_ADD_XIZI_FEATURES),y)
 | 
				
			||||||
        SRC_FILES += 
 | 
					        SRC_FILES += 
 | 
				
			||||||
    endif
 | 
					    endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ifeq ($(CONFIG_USER_TEST_FTPCLIENT_FINAL),y)
 | 
				
			||||||
 | 
					        SRC_FILES += test_ftpclient_final/test_ftpclient_final.c test_ftpclient_final/ftp_client/ftp_client.c test_ftpclient_final/ftp_client/my_socket.c
 | 
				
			||||||
 | 
					    endif   
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    include $(KERNEL_ROOT)/compiler.mk
 | 
					    include $(KERNEL_ROOT)/compiler.mk
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,60 @@
 | 
				
			||||||
 | 
					# 初赛一级赛题3:基于矽璓已实现的Lwip,在ARM上实现FTP协议的Client功能
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 1. 简介
 | 
				
			||||||
 | 
					本项目是基于矽璓已实现的Lwip,在ARM上实现FTP协议的Client功能
 | 
				
			||||||
 | 
					test_ftpclient.h声明了下载10个文件的测试函数
 | 
				
			||||||
 | 
					test_ftpclient.c实现了下载10个文件的测试函数
 | 
				
			||||||
 | 
					ftp_client文件夹定义了ftp_client的相关类库其中my_socket.h,my_socket.c定义了socket抽象层,并基于
 | 
				
			||||||
 | 
					Lwip实现了该抽象层,ftp_client.h,ftp_client.c实现了ftp登录,获取文件大小,下载文件等功能
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2. 数据结构设计说明
 | 
				
			||||||
 | 
					- ftp_client.c 的设计
 | 
				
			||||||
 | 
					分别定义了发送命令和接收数据的socket和相应的缓冲区并且实现了登录、发送命令、接收响应数据、查找文件大小、进入被动模式、下载文件、关闭ftp客户端等操作
 | 
				
			||||||
 | 
					```c
 | 
				
			||||||
 | 
					static int  m_socket_cmd; // 发送命令的socket文件描述符
 | 
				
			||||||
 | 
					static int  m_socket_data; // 接收ftp服务器文件的socket文件描述符
 | 
				
			||||||
 | 
					static char m_send_buffer[1024]; // 发送缓冲区
 | 
				
			||||||
 | 
					static char m_recv_buffer[1024];  // 接收缓冲区
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					## 3. 测试程序说明
 | 
				
			||||||
 | 
					- test_ftpclient.c用于测试下载10个文件
 | 
				
			||||||
 | 
					连接电脑上的ftp服务器下载10个4KB文件,通过终端日志打印确定文件是否下载成功,以及追踪通信流程和下载进度
 | 
				
			||||||
 | 
					```c
 | 
				
			||||||
 | 
					void TestFtpClient(int argc, char* argv[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    FtpInitCmd();
 | 
				
			||||||
 | 
					    int ret = FtpLogin("192.168.0.248", 21, "anonymous", "anonymous");
 | 
				
			||||||
 | 
					    int size;
 | 
				
			||||||
 | 
					    char *buf;
 | 
				
			||||||
 | 
					    for(int i = 1;i <= 10;i++){
 | 
				
			||||||
 | 
					        char fileName[20] = "/file"; 
 | 
				
			||||||
 | 
					        char temp[5] = "";
 | 
				
			||||||
 | 
					        sprintf(temp,"%d",i);
 | 
				
			||||||
 | 
					        strcat(fileName,temp);
 | 
				
			||||||
 | 
					        size = FtpFileSize(fileName);
 | 
				
			||||||
 | 
					        buf = malloc(size);
 | 
				
			||||||
 | 
					        FtpInitData();  // data socket 每次下载都要重新创建,下载完都要关闭
 | 
				
			||||||
 | 
					        ret = FtpDownload(fileName, buf, size);
 | 
				
			||||||
 | 
					        free(buf);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    FtpQuit();
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 4. 运行结果(##需结合运行测试截图按步骤说明##)
 | 
				
			||||||
 | 
					1. 配置开启BSP_USING_LWIP、USER_TEST_FTPCLIENT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2. 编译
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3. 烧写
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					4. xshell连接串口终端
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					6. 配置ip
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					7. 运行TestFtpClient,开始下载文件
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,256 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					* Copyright (c) 2020 AIIT XUOS Lab
 | 
				
			||||||
 | 
					* XiUOS is licensed under Mulan PSL v2.
 | 
				
			||||||
 | 
					* You can use this software according to the terms and conditions of the Mulan PSL v2.
 | 
				
			||||||
 | 
					* You may obtain a copy of Mulan PSL v2 at:
 | 
				
			||||||
 | 
					*        http://license.coscl.org.cn/MulanPSL2
 | 
				
			||||||
 | 
					* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | 
				
			||||||
 | 
					* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | 
				
			||||||
 | 
					* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | 
				
			||||||
 | 
					* See the Mulan PSL v2 for more details.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					* @file:    ftp_client.c
 | 
				
			||||||
 | 
					* @brief:   ftp client tool
 | 
				
			||||||
 | 
					* @version: 1.0
 | 
				
			||||||
 | 
					* @author:  bdislab_final
 | 
				
			||||||
 | 
					* @date:    2023/7/25
 | 
				
			||||||
 | 
					* @reference https://kerndev.blog.csdn.net/article/details/89383888
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include "my_socket.h"
 | 
				
			||||||
 | 
					#include "ftp_client.h"
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					static int  m_socket_cmd;
 | 
				
			||||||
 | 
					static int  m_socket_data;
 | 
				
			||||||
 | 
					static char m_send_buffer[1024];
 | 
				
			||||||
 | 
					static char m_recv_buffer[1024];
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					static int FtpSendCommand(char *cmd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						printf("send command: %s\r\n", cmd);
 | 
				
			||||||
 | 
						ret = SocketSend(m_socket_cmd, cmd, (int)strlen(cmd));
 | 
				
			||||||
 | 
						if(ret < 0)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							printf("failed to send command: %s\r\n",cmd);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					static int FtpRecvRespond(char *resp, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						int off;
 | 
				
			||||||
 | 
						len -= 1;
 | 
				
			||||||
 | 
						for(off=0; off<len; off+=ret)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							ret = SocketRecv(m_socket_cmd, &resp[off], 1);
 | 
				
			||||||
 | 
							if(ret < 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								printf("recv respond error(ret=%d)!\r\n", ret);
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if(resp[off] == '\n')
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						resp[off+1] = 0;
 | 
				
			||||||
 | 
						printf("respond:%s\r\n", resp);
 | 
				
			||||||
 | 
						return atoi(resp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					static int FtpEnterPasv(char *ipaddr, int *port)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						char *find;
 | 
				
			||||||
 | 
						int a,b,c,d;
 | 
				
			||||||
 | 
						int pa,pb;
 | 
				
			||||||
 | 
						ret = FtpSendCommand("PASV\r\n");
 | 
				
			||||||
 | 
						if(ret != 1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ret = FtpRecvRespond(m_recv_buffer, 1024);
 | 
				
			||||||
 | 
						if(ret != 227)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						find = strrchr(m_recv_buffer, '(');
 | 
				
			||||||
 | 
						sscanf(find, "(%d,%d,%d,%d,%d,%d)", &a, &b, &c, &d, &pa, &pb);
 | 
				
			||||||
 | 
						sprintf(ipaddr, "%d.%d.%d.%d", a, b, c, d);
 | 
				
			||||||
 | 
						*port = pa * 256 + pb;
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					int  FtpDownload(char *name, char *buf, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int   i;
 | 
				
			||||||
 | 
						int   ret;
 | 
				
			||||||
 | 
						char  ipaddr[32];
 | 
				
			||||||
 | 
						int   port;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
						//查询数据地址
 | 
				
			||||||
 | 
						ret = FtpEnterPasv(ipaddr, &port);
 | 
				
			||||||
 | 
						if(ret != 1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						//连接数据端口
 | 
				
			||||||
 | 
						ret = SocketConnect(m_socket_data, ipaddr, port);
 | 
				
			||||||
 | 
						if(ret != 1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							printf("failed to connect data port\r\n");
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
						//准备下载
 | 
				
			||||||
 | 
						sprintf(m_send_buffer, "RETR %s\r\n", name);
 | 
				
			||||||
 | 
						ret = FtpSendCommand(m_send_buffer);
 | 
				
			||||||
 | 
						if(ret != 1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ret = FtpRecvRespond(m_recv_buffer, 1024);
 | 
				
			||||||
 | 
						if(ret != 150)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							SocketClose(m_socket_data);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//开始下载,读取完数据后,服务器会自动关闭连接
 | 
				
			||||||
 | 
						for(i=0; i<len; i+=ret)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							ret = SocketRecv(m_socket_data, ((char *)buf) + i, len);
 | 
				
			||||||
 | 
							printf("download %d/%d.\r\n", i + ret, len);
 | 
				
			||||||
 | 
							if(ret < 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								printf("download was interrupted.\r\n");
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						//下载完成
 | 
				
			||||||
 | 
						printf("download %d/%d bytes complete.\r\n", i, len);
 | 
				
			||||||
 | 
						printf("====file content====\n");
 | 
				
			||||||
 | 
						buf[100] = '\0';
 | 
				
			||||||
 | 
						printf("%s\n",buf);
 | 
				
			||||||
 | 
						printf("====================\n");
 | 
				
			||||||
 | 
					    // FILE *fp = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // fp = fopen(name+1, "wb");
 | 
				
			||||||
 | 
					    // fwrite(buf,len,1,fp);
 | 
				
			||||||
 | 
					    // fclose(fp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SocketClose(m_socket_data);
 | 
				
			||||||
 | 
						ret = FtpRecvRespond(m_recv_buffer, 1024);
 | 
				
			||||||
 | 
						return (ret==226);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					int  FtpFileSize(char *name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						int size;
 | 
				
			||||||
 | 
						sprintf(m_send_buffer,"SIZE %s\r\n",name);
 | 
				
			||||||
 | 
						ret = FtpSendCommand(m_send_buffer);
 | 
				
			||||||
 | 
						if(ret != 1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ret = FtpRecvRespond(m_recv_buffer, 1024);
 | 
				
			||||||
 | 
						if(ret != 213)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						size = atoi(m_recv_buffer + 4);
 | 
				
			||||||
 | 
						return size;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					int FtpLogin(char *addr, int port, char *username, char *password)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						printf("connect...\r\n");
 | 
				
			||||||
 | 
						ret = SocketConnect(m_socket_cmd, addr, port);
 | 
				
			||||||
 | 
						if(ret != 1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							printf("connect server failed!\r\n");
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						printf("connect ok.\r\n");
 | 
				
			||||||
 | 
					    //等待欢迎信息
 | 
				
			||||||
 | 
						ret = FtpRecvRespond(m_recv_buffer, 1024);
 | 
				
			||||||
 | 
						if(ret != 220)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							printf("bad server, ret=%d!\r\n", ret);
 | 
				
			||||||
 | 
							SocketClose(m_socket_cmd);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						printf("login...\r\n");
 | 
				
			||||||
 | 
					    //发送USER
 | 
				
			||||||
 | 
						sprintf(m_send_buffer, "USER %s\r\n", username);
 | 
				
			||||||
 | 
						ret = FtpSendCommand(m_send_buffer);
 | 
				
			||||||
 | 
						if(ret != 1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							SocketClose(m_socket_cmd);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ret = FtpRecvRespond(m_recv_buffer, 1024);
 | 
				
			||||||
 | 
						if(ret != 331)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							SocketClose(m_socket_cmd);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					    //发送PASS
 | 
				
			||||||
 | 
						sprintf(m_send_buffer, "PASS %s\r\n", password);
 | 
				
			||||||
 | 
						ret = FtpSendCommand(m_send_buffer);
 | 
				
			||||||
 | 
						if(ret != 1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							SocketClose(m_socket_cmd);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ret = FtpRecvRespond(m_recv_buffer, 1024);
 | 
				
			||||||
 | 
						if(ret != 230)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							SocketClose(m_socket_cmd);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						printf("login success.\r\n");
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					    //设置为二进制模式
 | 
				
			||||||
 | 
						ret = FtpSendCommand("TYPE I\r\n");
 | 
				
			||||||
 | 
						if(ret != 1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							SocketClose(m_socket_cmd);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ret = FtpRecvRespond(m_recv_buffer, 1024);
 | 
				
			||||||
 | 
						if(ret != 200)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							SocketClose(m_socket_cmd);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					void FtpQuit(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						FtpSendCommand("QUIT\r\n");
 | 
				
			||||||
 | 
						SocketClose(m_socket_cmd);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					void FtpInitCmd(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						m_socket_cmd = SocketCreate();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void FtpInitData(void){
 | 
				
			||||||
 | 
					    m_socket_data= SocketCreate();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,42 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					* Copyright (c) 2020 AIIT XUOS Lab
 | 
				
			||||||
 | 
					* XiUOS is licensed under Mulan PSL v2.
 | 
				
			||||||
 | 
					* You can use this software according to the terms and conditions of the Mulan PSL v2.
 | 
				
			||||||
 | 
					* You may obtain a copy of Mulan PSL v2 at:
 | 
				
			||||||
 | 
					*        http://license.coscl.org.cn/MulanPSL2
 | 
				
			||||||
 | 
					* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | 
				
			||||||
 | 
					* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | 
				
			||||||
 | 
					* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | 
				
			||||||
 | 
					* See the Mulan PSL v2 for more details.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					* @file:    ftp_client.h
 | 
				
			||||||
 | 
					* @brief:   ftp client tool
 | 
				
			||||||
 | 
					* @version: 1.0
 | 
				
			||||||
 | 
					* @author:  bdislab_final
 | 
				
			||||||
 | 
					* @date:    2023/7/25
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef FTP_CLIENT_H
 | 
				
			||||||
 | 
					#define FTP_CLIENT_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* init ftp cmd socket */ 
 | 
				
			||||||
 | 
					void FtpInitCmd(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* init ftp data socket */
 | 
				
			||||||
 | 
					void FtpInitData(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* quit ftp */
 | 
				
			||||||
 | 
					void FtpQuit(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* fpt login */
 | 
				
			||||||
 | 
					int  FtpLogin(char *addr, int port, char *username, char *password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* get file size */
 | 
				
			||||||
 | 
					int  FtpFileSize(char *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ftp download file*/
 | 
				
			||||||
 | 
					int  FtpDownload(char *name, char *buf, int len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,57 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					* Copyright (c) 2020 AIIT XUOS Lab
 | 
				
			||||||
 | 
					* XiUOS is licensed under Mulan PSL v2.
 | 
				
			||||||
 | 
					* You can use this software according to the terms and conditions of the Mulan PSL v2.
 | 
				
			||||||
 | 
					* You may obtain a copy of Mulan PSL v2 at:
 | 
				
			||||||
 | 
					*        http://license.coscl.org.cn/MulanPSL2
 | 
				
			||||||
 | 
					* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | 
				
			||||||
 | 
					* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | 
				
			||||||
 | 
					* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | 
				
			||||||
 | 
					* See the Mulan PSL v2 for more details.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					* @file:    my_socket.c
 | 
				
			||||||
 | 
					* @brief:   a abstract socket api
 | 
				
			||||||
 | 
					* @version: 1.0
 | 
				
			||||||
 | 
					* @author:  bdislab_final
 | 
				
			||||||
 | 
					* @date:    2023/7/25
 | 
				
			||||||
 | 
					* @reference https://kerndev.blog.csdn.net/article/details/89383888
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "my_socket.h"
 | 
				
			||||||
 | 
					#include <sockets.h>
 | 
				
			||||||
 | 
					#include <def.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int  SocketCreate(void){
 | 
				
			||||||
 | 
					    return socket(AF_INET,SOCK_STREAM,0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int  SocketConnect(int sock, const char *addr, int port){
 | 
				
			||||||
 | 
						// unsigned int iRemoteAddr = 0;
 | 
				
			||||||
 | 
						struct sockaddr_in stRemoteAddr = {0}; //对端,即目标地址信息
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						stRemoteAddr.sin_family = AF_INET;
 | 
				
			||||||
 | 
						stRemoteAddr.sin_port = htons(port);
 | 
				
			||||||
 | 
						stRemoteAddr.sin_addr.s_addr = inet_addr(addr);
 | 
				
			||||||
 | 
						// inet_pton(AF_INET, addr, &iRemoteAddr);
 | 
				
			||||||
 | 
						// stRemoteAddr.sin_addr.s_addr=iRemoteAddr;
 | 
				
			||||||
 | 
						int res = connect(sock,(struct sockaddr *)&stRemoteAddr,sizeof(stRemoteAddr));
 | 
				
			||||||
 | 
						if(res == -1){
 | 
				
			||||||
 | 
							printf("error:%d\n",errno);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					    return res == 0 ? 1 : 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int  SocketSend(int sock, void *data, int len){
 | 
				
			||||||
 | 
					    return send(sock,data,len,0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int  SocketRecv(int sock, void *data, int len){
 | 
				
			||||||
 | 
					    return recv(sock,data,len,0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SocketClose(int sock){
 | 
				
			||||||
 | 
						close(sock);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,46 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					* Copyright (c) 2020 AIIT XUOS Lab
 | 
				
			||||||
 | 
					* XiUOS is licensed under Mulan PSL v2.
 | 
				
			||||||
 | 
					* You can use this software according to the terms and conditions of the Mulan PSL v2.
 | 
				
			||||||
 | 
					* You may obtain a copy of Mulan PSL v2 at:
 | 
				
			||||||
 | 
					*        http://license.coscl.org.cn/MulanPSL2
 | 
				
			||||||
 | 
					* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | 
				
			||||||
 | 
					* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | 
				
			||||||
 | 
					* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | 
				
			||||||
 | 
					* See the Mulan PSL v2 for more details.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @file my_socket.h
 | 
				
			||||||
 | 
					 * @brief a abstract socket api
 | 
				
			||||||
 | 
					 * @version 1.0
 | 
				
			||||||
 | 
					 * @author bdislab_final
 | 
				
			||||||
 | 
					 * @date 2023/7/25
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef MYSOCKET_H
 | 
				
			||||||
 | 
					#define MYSOCKET_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					/* create a socket */
 | 
				
			||||||
 | 
					int  SocketCreate(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* connect a socket */
 | 
				
			||||||
 | 
					int  SocketConnect(int sock, const char *addr, int port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* send data through socket*/
 | 
				
			||||||
 | 
					int  SocketSend(int sock, void *data, int len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* receive data from socket*/
 | 
				
			||||||
 | 
					int  SocketRecv(int sock, void *data, int len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* close socket*/
 | 
				
			||||||
 | 
					void SocketClose(int sock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 214 KiB  | 
| 
		 After Width: | Height: | Size: 121 KiB  | 
| 
		 After Width: | Height: | Size: 108 KiB  | 
| 
		 After Width: | Height: | Size: 117 KiB  | 
| 
		 After Width: | Height: | Size: 38 KiB  | 
| 
		 After Width: | Height: | Size: 50 KiB  | 
| 
		 After Width: | Height: | Size: 73 KiB  | 
| 
		 After Width: | Height: | Size: 48 KiB  | 
| 
		 After Width: | Height: | Size: 136 KiB  | 
| 
						 | 
					@ -0,0 +1,50 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					* Copyright (c) 2020 AIIT XUOS Lab
 | 
				
			||||||
 | 
					* XiUOS is licensed under Mulan PSL v2.
 | 
				
			||||||
 | 
					* You can use this software according to the terms and conditions of the Mulan PSL v2.
 | 
				
			||||||
 | 
					* You may obtain a copy of Mulan PSL v2 at:
 | 
				
			||||||
 | 
					*        http://license.coscl.org.cn/MulanPSL2
 | 
				
			||||||
 | 
					* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | 
				
			||||||
 | 
					* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | 
				
			||||||
 | 
					* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | 
				
			||||||
 | 
					* See the Mulan PSL v2 for more details.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					* @file:    test_ftpclient.c
 | 
				
			||||||
 | 
					* @brief:   a ftpClient test sample
 | 
				
			||||||
 | 
					* @version: 1.0
 | 
				
			||||||
 | 
					* @author:  bdislab_final
 | 
				
			||||||
 | 
					* @date:    2023/7/25
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "test_ftpclient.h"
 | 
				
			||||||
 | 
					#include "ftp_client/ftp_client.h"
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <transform.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* test for ftp client */
 | 
				
			||||||
 | 
					void TestFtpClient(int argc, char* argv[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    FtpInitCmd();
 | 
				
			||||||
 | 
					    int ret = FtpLogin("192.168.1.248", 21, "anonymous", "anonymous");
 | 
				
			||||||
 | 
					    int size;
 | 
				
			||||||
 | 
					    char *buf;
 | 
				
			||||||
 | 
					    for(int i = 1;i <= 10;i++){
 | 
				
			||||||
 | 
					        char fileName[20] = "/file"; 
 | 
				
			||||||
 | 
					        char temp[5] = "";
 | 
				
			||||||
 | 
					        sprintf(temp,"%d",i-1);
 | 
				
			||||||
 | 
					        strcat(fileName,temp);
 | 
				
			||||||
 | 
					        size = FtpFileSize(fileName);
 | 
				
			||||||
 | 
					        buf = malloc(size);
 | 
				
			||||||
 | 
					        FtpInitData();  // data socket 每次下载都要重新创建,下载完都要关闭
 | 
				
			||||||
 | 
					        ret = FtpDownload(fileName, buf, size);
 | 
				
			||||||
 | 
					        free(buf);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    FtpQuit();
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					PRIV_SHELL_CMD_FUNCTION(TestFtpClient, a ftpClient test sample, PRIV_SHELL_CMD_MAIN_ATTR);
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					* Copyright (c) 2020 AIIT XUOS Lab
 | 
				
			||||||
 | 
					* XiUOS is licensed under Mulan PSL v2.
 | 
				
			||||||
 | 
					* You can use this software according to the terms and conditions of the Mulan PSL v2.
 | 
				
			||||||
 | 
					* You may obtain a copy of Mulan PSL v2 at:
 | 
				
			||||||
 | 
					*        http://license.coscl.org.cn/MulanPSL2
 | 
				
			||||||
 | 
					* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | 
				
			||||||
 | 
					* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | 
				
			||||||
 | 
					* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | 
				
			||||||
 | 
					* See the Mulan PSL v2 for more details.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @file test_ftpclient.h
 | 
				
			||||||
 | 
					 * @brief a ftpClient test sample
 | 
				
			||||||
 | 
					 * @version 1.0
 | 
				
			||||||
 | 
					 * @author bdislab_final
 | 
				
			||||||
 | 
					 * @date 2023/7/25
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef TEST_FTPCLIENT_H
 | 
				
			||||||
 | 
					#define TEST_FTPCLIENT_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* test for ftp client */
 | 
				
			||||||
 | 
					void TestFtpClient(int argc, char* argv[]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,43 @@
 | 
				
			||||||
 | 
					# 基于矽璓已实现的W5500网卡驱动,在Riscv上实现FTP协议的Client功能 #
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 1. 简介
 | 
				
			||||||
 | 
					利用w5500网络编程的api实现了ftp客户端的功能,具体功能包括向ftp服务器发送指定命令,根据用户名登陆ftp服务器,获取文件大小,下载指定文件并保存至sd卡内,并提供了测试函数模拟从ftp服务器上下载10个4KB文件的过程
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2. 数据结构设计说明
 | 
				
			||||||
 | 
					全局变量:
 | 
				
			||||||
 | 
					char sendBuffer[]:输出缓冲区  
 | 
				
			||||||
 | 
					char recvBuffer[]:输入缓冲区
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					包括以下函数功能,分别为:  
 | 
				
			||||||
 | 
					`SendCommand`:发送指定的指令  
 | 
				
			||||||
 | 
					`EnterPasv`:进入被动模式  
 | 
				
			||||||
 | 
					`Login`:根据用户名登陆ftp服务器  
 | 
				
			||||||
 | 
					`GetFileSize`:获取指定文件的大小  
 | 
				
			||||||
 | 
					`Download`:下载指定文件
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3. 测试程序说明
 | 
				
			||||||
 | 
					测试了创建套接字,与服务器建立连接并根据传入的用户名和密码发送登陆指令。登陆成功后下载服务器上指定的10个4KB大小的txt文件,然后调用开发板的相关api在系统根目录中创建对应的文件,写入从服务器接收到的数据。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 4. 运行结果(##需结合运行测试截图按步骤说明##)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					打开menuconfig之后,将test_ftp开启(y),将Using TFcard device 和 Using W5500 as network device 开启(y)保存后退出
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					编译XiZi-edu-riscv64.elf成功
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					启动kflash烧录bin文件,按reset键重置成功进入系统并显示SD卡已挂载
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					执行TestTfp命令,可以看到成功登陆ftp服务器,并开始下载10个大小为4KB的文件。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					服务器日志信息
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					读取sd卡中的文件可以看到10个大小为4KB的文件被成功下载
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 172 KiB  | 
| 
		 After Width: | Height: | Size: 161 KiB  | 
| 
		 After Width: | Height: | Size: 258 KiB  | 
| 
		 After Width: | Height: | Size: 116 KiB  | 
| 
		 After Width: | Height: | Size: 117 KiB  | 
| 
		 After Width: | Height: | Size: 182 KiB  | 
| 
		 After Width: | Height: | Size: 38 KiB  | 
| 
		 After Width: | Height: | Size: 62 KiB  | 
| 
		 After Width: | Height: | Size: 61 KiB  | 
| 
		 After Width: | Height: | Size: 62 KiB  | 
| 
						 | 
					@ -0,0 +1,241 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					* Copyright (c) 2020 AIIT Ubiquitous Team
 | 
				
			||||||
 | 
					* XiUOS is licensed under Mulan PSL v2.
 | 
				
			||||||
 | 
					* You can use this software according to the terms and conditions of the Mulan PSL
 | 
				
			||||||
 | 
					v2.
 | 
				
			||||||
 | 
					* You may obtain a copy of Mulan PSL v2 at:
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					http://license.coscl.org.cn/MulanPSL2
 | 
				
			||||||
 | 
					* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | 
				
			||||||
 | 
					* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | 
				
			||||||
 | 
					* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | 
				
			||||||
 | 
					* See the Mulan PSL v2 for more details.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <transform.h>
 | 
				
			||||||
 | 
					#include <socket.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include "test_ftpclient_riscv.h"
 | 
				
			||||||
 | 
					#define SOCKET_DATA 2
 | 
				
			||||||
 | 
					#define SOCKET_CMD 3
 | 
				
			||||||
 | 
					char sendBuffer[1024];
 | 
				
			||||||
 | 
					char recvBuffer[1024];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//quoted from https://kerndev.blog.csdn.net/article/details/89383888
 | 
				
			||||||
 | 
					int SendCommand(char *cmd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					    ret = wiz_sock_send(SOCKET_CMD,cmd,(int)strlen(cmd));
 | 
				
			||||||
 | 
					    if(ret < 0 ){
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					int RecvRespond(char * respond,int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					    int off;
 | 
				
			||||||
 | 
					    len -= -1;
 | 
				
			||||||
 | 
					    for(off = 0;off < len;off += ret){
 | 
				
			||||||
 | 
					        ret = wiz_sock_recv(SOCKET_CMD,&respond[off],1);
 | 
				
			||||||
 | 
					        if(ret < 0 ){
 | 
				
			||||||
 | 
					            printf("recv respond error\r\n");
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(respond[off] == '\n'){
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } 
 | 
				
			||||||
 | 
					    respond[off + 1]=0;
 | 
				
			||||||
 | 
					    return atoi(respond);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					int EnterPasv(uint8_t *ipaddr,int *port)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					    char *find;
 | 
				
			||||||
 | 
					    int ip1,ip2,ip3,ip4,tmp1,tmp2;
 | 
				
			||||||
 | 
					    ret = SendCommand("PASV\r\n");
 | 
				
			||||||
 | 
					    if(ret != 1){
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ret=RecvRespond(recvBuffer,1024);
 | 
				
			||||||
 | 
					    if(ret != 227){
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    find=strrchr(recvBuffer,'(');
 | 
				
			||||||
 | 
					    sscanf(find,"(%d,%d,%d,%d,%d,%d)",&ip1,&ip2,&ip3,&ip4,&tmp1,&tmp2);
 | 
				
			||||||
 | 
					    ipaddr[0] = ip1;
 | 
				
			||||||
 | 
					    ipaddr[1] = ip2;
 | 
				
			||||||
 | 
					    ipaddr[2] = ip3;
 | 
				
			||||||
 | 
					    ipaddr[3] = ip4;
 | 
				
			||||||
 | 
					    *port = tmp1 * 256 + tmp2;
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					int Login(uint8_t addr[4],int port,char *username,char *password)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					    printf("connect....\n");
 | 
				
			||||||
 | 
					    ret = wiz_sock_connect(SOCKET_CMD,addr,port);
 | 
				
			||||||
 | 
					    if(ret != 1){
 | 
				
			||||||
 | 
					        printf("connect server failed\r\n");
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    printf("connect ok.\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = RecvRespond(recvBuffer,1024);
 | 
				
			||||||
 | 
					    if(ret != 220){
 | 
				
			||||||
 | 
					        printf("bad server ret=%d\r\n",ret);
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    printf("login....\r\n");
 | 
				
			||||||
 | 
					    sprintf(sendBuffer,"USER %s\r\n",username);
 | 
				
			||||||
 | 
					    ret = SendCommand(sendBuffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(ret != 1){
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ret = RecvRespond(recvBuffer,1024);
 | 
				
			||||||
 | 
					    if(ret == 220)ret = RecvRespond(recvBuffer,1024);
 | 
				
			||||||
 | 
					    if(ret != 331){
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    sprintf(sendBuffer,"PASS %s\r\n",password);
 | 
				
			||||||
 | 
					    ret = SendCommand(sendBuffer);
 | 
				
			||||||
 | 
					    if(ret != 1){
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ret = RecvRespond(recvBuffer,1024);
 | 
				
			||||||
 | 
					    if(ret != 230){
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    printf("login sucess \r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = SendCommand("TYPE I\r\n");
 | 
				
			||||||
 | 
					    if(ret != 1){
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ret = RecvRespond(recvBuffer,1024);
 | 
				
			||||||
 | 
					    if(ret != 200){
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					int GetFileSize(char * name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					    int size;
 | 
				
			||||||
 | 
					    sprintf(sendBuffer,"SIZE %s\r\n",name);
 | 
				
			||||||
 | 
					    ret = SendCommand(sendBuffer);
 | 
				
			||||||
 | 
					    if(ret != 1){
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ret = RecvRespond(recvBuffer,1024);
 | 
				
			||||||
 | 
					    if(ret != 213){
 | 
				
			||||||
 | 
					        printf("get file size failed\r\n");
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    size = atoi(recvBuffer + 4);
 | 
				
			||||||
 | 
					    return size;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					int Download(char *name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    wiz_socket(SOCKET_DATA, Sn_MR_TCP,12345,0);
 | 
				
			||||||
 | 
					    int len = GetFileSize(name);
 | 
				
			||||||
 | 
					    char *buf = malloc(len+1);
 | 
				
			||||||
 | 
					    printf("downloading file %s\r\n",name);
 | 
				
			||||||
 | 
					    int it;
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					    uint8_t addr[4];
 | 
				
			||||||
 | 
					    int port;
 | 
				
			||||||
 | 
					    ret = EnterPasv(addr,&port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(ret != 1){
 | 
				
			||||||
 | 
					        wiz_sock_disconnect(SOCKET_DATA);
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ret = wiz_sock_connect(SOCKET_DATA,addr,port);
 | 
				
			||||||
 | 
					    if(ret != 1){
 | 
				
			||||||
 | 
					        wiz_sock_disconnect(SOCKET_DATA);
 | 
				
			||||||
 | 
					        printf("fail to connect data port\r\n");
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    sprintf(sendBuffer,"RETR %s\r\n",name);
 | 
				
			||||||
 | 
					    ret = SendCommand(sendBuffer);
 | 
				
			||||||
 | 
					    if(ret != 1){
 | 
				
			||||||
 | 
					        wiz_sock_disconnect(SOCKET_DATA);
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ret =  RecvRespond(recvBuffer,1024);
 | 
				
			||||||
 | 
					    if(ret!=150){
 | 
				
			||||||
 | 
					        wiz_sock_disconnect(SOCKET_DATA);
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for(it = 0;it < len;it += ret){
 | 
				
			||||||
 | 
					        ret = wiz_sock_recv(SOCKET_DATA,((char *)buf + it),len);
 | 
				
			||||||
 | 
					        if(ret<0){
 | 
				
			||||||
 | 
					            printf("download was interupted\r\n");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    buf[len] = 0;
 | 
				
			||||||
 | 
					    printf("download %d/%d bytes complete. \r\n",it,len);
 | 
				
			||||||
 | 
					    ret = RecvRespond(recvBuffer,1024);
 | 
				
			||||||
 | 
					    if(ret != 226){
 | 
				
			||||||
 | 
					        wiz_sock_disconnect(SOCKET_DATA);
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    wiz_sock_disconnect(SOCKET_DATA);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    printf("creating file %s ....\r\n",name);
 | 
				
			||||||
 | 
					    int fd=open(name,O_RDWR | O_CREAT);
 | 
				
			||||||
 | 
					    if(fd > 0){
 | 
				
			||||||
 | 
					        ret = write(fd,buf,strlen(buf));
 | 
				
			||||||
 | 
					        if(ret < 0 ){
 | 
				
			||||||
 | 
					            printf("write failed\r\n");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else printf("success!\r\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        printf("create file %s failed\r\n",name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(buf != NULL){
 | 
				
			||||||
 | 
					        free(buf);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void Init()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wiz_socket(SOCKET_CMD, Sn_MR_TCP,54321,0);
 | 
				
			||||||
 | 
					    printf("socket created\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void Quit()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    wiz_sock_disconnect(SOCKET_CMD);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					int TestFtp()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint8_t ip[4] = {192,168,130,70};
 | 
				
			||||||
 | 
					    Login(ip,21,"frank","114514");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Download("File0.txt");
 | 
				
			||||||
 | 
					    Download("File1.txt");
 | 
				
			||||||
 | 
					    Download("File2.txt");
 | 
				
			||||||
 | 
					    Download("File3.txt");
 | 
				
			||||||
 | 
					    Download("File4.txt");
 | 
				
			||||||
 | 
					    Download("File5.txt");
 | 
				
			||||||
 | 
					    Download("File6.txt");
 | 
				
			||||||
 | 
					    Download("File7.txt");
 | 
				
			||||||
 | 
					    Download("File8.txt");
 | 
				
			||||||
 | 
					    Download("File9.txt");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Quit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					PRIV_SHELL_CMD_FUNCTION(TestFtp, Implement ftp, PRIV_SHELL_CMD_MAIN_ATTR);
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					#include <transform.h>
 | 
				
			||||||
 | 
					#include <socket.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int SendCommand(char *cmd);
 | 
				
			||||||
 | 
					int RecvRespond(char * respond,int len);
 | 
				
			||||||
 | 
					int EnterPasv(uint8_t *ipaddr,int *port);
 | 
				
			||||||
 | 
					int Login(uint8_t addr[4],int port,char *username,char *password);
 | 
				
			||||||
 | 
					int GetFileSize(char * name);
 | 
				
			||||||
 | 
					int Download(char *name);
 | 
				
			||||||
 | 
					void Init();
 | 
				
			||||||
 | 
					void Quit();
 | 
				
			||||||
 | 
					int TestFtp();
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,187 @@
 | 
				
			||||||
 | 
					# 基于初赛二级赛题1,实现多个LoRa节点和LoRa网关通信私有协议
 | 
				
			||||||
 | 
					## 1. 简介
 | 
				
			||||||
 | 
					基于 E220-400T22S Lora模块设计实现通信私有协议,主要包含以下几个方面:<br>
 | 
				
			||||||
 | 
					- 协议实现完全遵循LoRa Adapter代码规范,可以直接使用原有的Adapter相关函数基于本协议构建Lora网络。
 | 
				
			||||||
 | 
					- 重新设计实现E220底层函数,增加了IOCTL函数实现,支持在运行时对地址、信道、通信模式、空中速率等参数的动态配置。
 | 
				
			||||||
 | 
					- E220模块只支持单通道通信,本协议基于定向传输模式实现了多下行信道通信。
 | 
				
			||||||
 | 
					- 支持数据帧完整性校验、支持数据帧丢失或者跳帧检测。
 | 
				
			||||||
 | 
					- 支持节点断网自动重联,在数据发送失败时可以进行重联或者搜索其他网关。
 | 
				
			||||||
 | 
					- 支持节点对网关的搜索,可以主动寻找在线网关入网。
 | 
				
			||||||
 | 
					- 支持信道冲突检测,检测上行通道是否占用。
 | 
				
			||||||
 | 
					## 2. 数据结构说明
 | 
				
			||||||
 | 
					### E220模块相关数据结构
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c
 | 
				
			||||||
 | 
					enum LoraMode                        // E220工作模式,支持四种,配置模式与休眠模式一致
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    MODE_TRANSFER_MODE = 0,          // M0 : M1 = 0 : 0 可发可收
 | 
				
			||||||
 | 
					    MODE_WOR_SEND,                   // M0 : M1 = 1 : 0 可发可收
 | 
				
			||||||
 | 
					    MODE_WOR_RECV,                   // M0 : M1 = 0 : 1 可收不发
 | 
				
			||||||
 | 
					    MODE_CONFIG_SLEEP                // M0 : M1 = 1 : 1 不收不发
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum LoraState                       // 硬件状态
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    STATE_CLOSED,                    // 硬件关闭
 | 
				
			||||||
 | 
					    STATE_OPENED,                    // 已正常开启
 | 
				
			||||||
 | 
					    STATE_BROKEN                     // 硬件损坏
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum LoraTransMode                   // 模块传输模式
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    TRANS_MODE_HYALINE = 0X0,        // 透明传输
 | 
				
			||||||
 | 
					    TRANS_MODE_ORIENTED = 0X40,      // 定点传输
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum LoraAirRate                     // 空中速率,通信双方必须设置一致的空中速率方可进行通信
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    AIR_RATE_2D4K = 0X0,             // 2.4K
 | 
				
			||||||
 | 
					    AIR_RATE_4D8K = 0X3,             // 4.8K
 | 
				
			||||||
 | 
					    AIR_RATE_9D6K = 0X4,             // 9.6K
 | 
				
			||||||
 | 
					    AIR_RATE_19D2K = 0X5,            // 19.2K
 | 
				
			||||||
 | 
					    AIR_RATE_38D4K = 0X6,            // 38.4K
 | 
				
			||||||
 | 
					    AIR_RATE_62D5K = 0X7             // 62.5K
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum LoraConfig                      // 支持IOCTL函数进行配置的配置项枚举,某些项只支持9600波特率配置
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CONFIG_SERIAL_TIME_OUT = 0X0,    // 串口超时时间
 | 
				
			||||||
 | 
					    CONFIG_LORA_MODE = 0X1,          // 配置Lora模式
 | 
				
			||||||
 | 
					    CONFIG_TRANS_MODE = 0X2,         // 配置Lora传输模式(9600)
 | 
				
			||||||
 | 
					    CONFIG_AIR_RATE = 0X3,           // 配置空中速率(9600)
 | 
				
			||||||
 | 
					    CONFIG_BAUD_RATE = 0X4,          // 配置波特率
 | 
				
			||||||
 | 
					    CONFIG_ADDRESS = 0X5,            // 配置设备地址(9600)
 | 
				
			||||||
 | 
					    CONFIG_CHANNEL = 0X6,            // 配置设备信道(9600)
 | 
				
			||||||
 | 
					    CONFIG_SHOW = 0X7                // 打印配置信息
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 数据帧相关数据结构
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c
 | 
				
			||||||
 | 
					enum FrameType      // 数据帧类型枚举
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    E_G_JOIN = 0,   // 客户端入网请求,需回复
 | 
				
			||||||
 | 
					    E_G_QUIT,       // 客户端退网请求,不需回复
 | 
				
			||||||
 | 
					    E_G_DATA,       // 客户端上传数据,需回复
 | 
				
			||||||
 | 
					    G_E_ANS,        // 网关响应客户端请求
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct LoraFrame                // 数据帧消息类型
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint16 begin_mark;          // 开始标志 0x3C3C
 | 
				
			||||||
 | 
					    uint16 session_id;          // 会话ID,客户端每次数据上传会随机设置,若是回复ID不一致则表示数据丢失
 | 
				
			||||||
 | 
					    uint16 dev_addr;            // 设备地址,特指终端地址,网关地址固定为 0XFFFF
 | 
				
			||||||
 | 
					    uint8 down_channel;         // 下行通道,即终端所在的信道
 | 
				
			||||||
 | 
					    uint8 frame_type;           // 数据帧的类型
 | 
				
			||||||
 | 
					    uint8 frame_confirm;        // 该数据帧是否需要确认回复
 | 
				
			||||||
 | 
					    uint8 frame_attach;         // 用于携带简单的数据,例如用户数据长度
 | 
				
			||||||
 | 
					    uint8 *user_data;           // 需要额外携带的大量数据
 | 
				
			||||||
 | 
					    uint8 crc_hi;               // 校验位高字节
 | 
				
			||||||
 | 
					    uint8 crc_lo;               // 校验位低字节
 | 
				
			||||||
 | 
					    uint16 end_mark;            // 结束标志 0X5A5A
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Lora节点相关数据结构
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c
 | 
				
			||||||
 | 
					enum EndNodeState                     //节点状态
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NODE_STATE_DISCONNECT = 0,        // 硬件开启,但是没有联网,后台程序可能开启
 | 
				
			||||||
 | 
					    NODE_STATE_CONNECT,               // 硬件开启,已经联网,后台程序可能开启
 | 
				
			||||||
 | 
					    NODE_STATE_BROKEN,                // 硬件损坏,无后台程序
 | 
				
			||||||
 | 
					    NODE_STATE_CLOSED                 // 硬件关闭,无后台程序
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct EndNodeParam                   // 节点参数结构
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint16 dev_addr;                  // 设备地址信息
 | 
				
			||||||
 | 
					    uint8 down_channel;               // 下行通道,终端可以接收信息的信道
 | 
				
			||||||
 | 
					    uint8 upload_channel;             // 上行通道,终端可以给网关发送信息的信道
 | 
				
			||||||
 | 
					    uint16 session_id;                // 会话ID,用于判定数据帧是否存在丢失
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    enum EndNodeState node_state;     // 客户端状态
 | 
				
			||||||
 | 
					    enum LoraAirRate air_rate;        // 终端的空中速率
 | 
				
			||||||
 | 
					    uint8 adr_enable;                 // 终端是否开启自动寻找上行网关
 | 
				
			||||||
 | 
					    uint8 reconnect_enable;           // 终端断网自动重联
 | 
				
			||||||
 | 
					    uint8 recv_time;                  // 接受下行消息的时间窗口长度,单位为秒
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Lora网关相关数据结构
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c
 | 
				
			||||||
 | 
					struct EndNodeInfo                    // 网关存储的客户端信息
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint16 node_addr;                 // 客户端地址
 | 
				
			||||||
 | 
					    uint8 node_down_channel;          // 客户端下行通道
 | 
				
			||||||
 | 
					    uint16 session_id;                // 上一个命令的会话ID
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum GatewayState                   // 网关的状态枚举
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    GATEWAY_CLOSED,                 // Lora还没有打开
 | 
				
			||||||
 | 
					    GATEWAY_OPENED,                 // 已打开,但是未开始工作
 | 
				
			||||||
 | 
					    GATEWAY_WORKING,                // 正常打开且已经开始正常工作
 | 
				
			||||||
 | 
					    GATEWAY_BROKEN                  // 模块损坏
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct GatewayParam                                             // 网关参数
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint16 dev_addr;                                            // 设备ID
 | 
				
			||||||
 | 
					    uint8 channel;                                              // 网络编号
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int recv_time;                                              // 串口超时时间
 | 
				
			||||||
 | 
					    enum LoraAirRate air_rate;                                  // 网关空中速率
 | 
				
			||||||
 | 
					    uint8 frame_retry;                                          // 重传次数
 | 
				
			||||||
 | 
					    enum GatewayState gateway_state;                            // 网关状态
 | 
				
			||||||
 | 
					    struct EndNodeInfo *node_infos[LORA_GATEWAY_MAX_NODE];      // 客户端信息
 | 
				
			||||||
 | 
					    uint16 node_count;                                          // 已链接客户端数量
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3. 测试程序说明
 | 
				
			||||||
 | 
					- 编译烧录两个不同地址、信道的客户端和一个网关。
 | 
				
			||||||
 | 
					- 分别打开客户端和网关并联网。
 | 
				
			||||||
 | 
					- 两个客户端分别向网关发送数据。
 | 
				
			||||||
 | 
					## 4. 运行结果
 | 
				
			||||||
 | 
					### (1)编译模块:
 | 
				
			||||||
 | 
					- 配置MENUCONFIG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> 开启连接框架支持,同时开启Lora Adapter支持
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> 选择E220模块
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> 开启测试函数
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> 测试单通道网关
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- 修改MakeFile:xiuos/APP_Framework/Applications/app_test/Makefile第141行修改为
 | 
				
			||||||
 | 
					```c
 | 
				
			||||||
 | 
					        SRC_FILES += test_lora_net_final/lora_driver/e220.c
 | 
				
			||||||
 | 
					        SRC_FILES += test_lora_net_final/lora_mac/lora_mac.c
 | 
				
			||||||
 | 
					        SRC_FILES += test_lora_net_final/test_lora_net_final.c
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					- 修改框架初始函数:
 | 
				
			||||||
 | 
					> 1. 文件:xiuos/APP_Framework/Framework/framework_init.c 第27行修改为<br> extern int UsrAdapterLoraInit(void);
 | 
				
			||||||
 | 
					> 2. 文件:xiuos/APP_Framework/Framework/framework_init.c 第170行的AdapterLoraInit修改为UsrAdapterLoraInit
 | 
				
			||||||
 | 
					### (2)打开网关
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> 网关打开,地址OXFFFF,信道OXA,空中速率2.4K
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### (3)客户端连接网关
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> 两边客户端同时发送入网请求,可以看见信道检测效果
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### (4)客户端发送数据
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> 客户端向网关发送数据
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> 两边客户端同时发送数据
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					使用自带的天线,2.4K空中速率,载荷64字节,在无大型遮盖物的情况下传输距离近1500米
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 320 KiB  | 
| 
		 After Width: | Height: | Size: 344 KiB  | 
| 
		 After Width: | Height: | Size: 233 KiB  | 
| 
		 After Width: | Height: | Size: 436 KiB  | 
| 
		 After Width: | Height: | Size: 970 KiB  | 
| 
		 After Width: | Height: | Size: 1.1 MiB  | 
| 
		 After Width: | Height: | Size: 1.1 MiB  | 
| 
		 After Width: | Height: | Size: 1.3 MiB  | 
| 
						 | 
					@ -0,0 +1,591 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					* Copyright (c) 2020 AIIT XUOS Lab
 | 
				
			||||||
 | 
					* XiUOS is licensed under Mulan PSL v2.
 | 
				
			||||||
 | 
					* You can use this software according to the terms and conditions of the Mulan PSL v2.
 | 
				
			||||||
 | 
					* You may obtain a copy of Mulan PSL v2 at:
 | 
				
			||||||
 | 
					*        http://license.coscl.org.cn/MulanPSL2
 | 
				
			||||||
 | 
					* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | 
				
			||||||
 | 
					* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | 
				
			||||||
 | 
					* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | 
				
			||||||
 | 
					* See the Mulan PSL v2 for more details.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					* @file:    e220.c
 | 
				
			||||||
 | 
					* @brief:   E220 module underlying related configuration driver functions implement
 | 
				
			||||||
 | 
					* @version: 0.1
 | 
				
			||||||
 | 
					* @author:  YUNFEI CHU
 | 
				
			||||||
 | 
					* @date:    2023/10/01 
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "e220.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct RegisterCfg                  // 寄存器结构
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint8 ADDH;
 | 
				
			||||||
 | 
					    uint8 ADDL;                     // 地址
 | 
				
			||||||
 | 
					    uint8 REG0;                     // 波特率/串口校验/空中速率
 | 
				
			||||||
 | 
					    uint8 REG1;                     // 分包设定/RSSI环境噪声/发射功率
 | 
				
			||||||
 | 
					    uint8 REG2;                     // 信道
 | 
				
			||||||
 | 
					    uint8 REG3;                     // RSSI字节/传输方式/LBT使能/WOR周期
 | 
				
			||||||
 | 
					    uint8 KEYH;
 | 
				
			||||||
 | 
					    uint8 KEYL;                     // 密钥
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 默认的寄存器配置信息,在每次配置更新后会同步更新该数据,保持其与硬件寄存器数据的一致性
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					static struct RegisterCfg register_cfg =
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    .ADDH = (E220_ADDRESS >> 8) & 0XFF,
 | 
				
			||||||
 | 
					    .ADDL = E220_ADDRESS & 0XFF,
 | 
				
			||||||
 | 
					    .REG0 = E220_DEFAULT_CONFIG_BAUD_RATE_BYTE | E220_DEFAULT_AIR_RATE,
 | 
				
			||||||
 | 
					    .REG1 = 0X0,
 | 
				
			||||||
 | 
					    .REG2 = E220_DEFAULT_CHANNEL,
 | 
				
			||||||
 | 
					    .REG3 = E220_DEFAULT_TRANS_MODE,
 | 
				
			||||||
 | 
					    .KEYH = 0X0,
 | 
				
			||||||
 | 
					    .KEYL = 0X0,       
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 默认的串口配置信息,初始化时波特率为9600,保持与硬件一致,在波特率更改过程中也需要保证一致
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					static struct SerialDataCfg serial_cfg =
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    .serial_baud_rate = E220_DEFAULT_CONFIG_BAUD_RATE,// 串口波特率
 | 
				
			||||||
 | 
					    .serial_data_bits = DATA_BITS_8,
 | 
				
			||||||
 | 
					    .serial_stop_bits = STOP_BITS_1,
 | 
				
			||||||
 | 
					    .serial_parity_mode = PARITY_NONE,
 | 
				
			||||||
 | 
					    .serial_bit_order = BIT_ORDER_LSB,
 | 
				
			||||||
 | 
					    .serial_invert_mode = NRZ_NORMAL,
 | 
				
			||||||
 | 
					    .serial_buffer_size = SERIAL_RB_BUFSZ,
 | 
				
			||||||
 | 
					    .serial_timeout = E220_DAFAULT_SERIAL_TIMEOUT,     // 串口超时配置
 | 
				
			||||||
 | 
					    .is_ext_uart = 0,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum LoraMode current_mode = -1;                       // 当前模块处于什么模式
 | 
				
			||||||
 | 
					enum LoraState lora_state = STATE_CLOSED;              // 当前模块的状态
 | 
				
			||||||
 | 
					uint8 lora_init = E220_NO;                             // 当前模块是否已经被初始化过了
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 将硬件切换至指定的模式
 | 
				
			||||||
 | 
					 * @param mode: 支持休眠/配置模式 和 传输模式
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					static uint8 E220LoraModeConfig(enum LoraMode mode)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // 模式和状态判断
 | 
				
			||||||
 | 
					    if (lora_state == STATE_BROKEN)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DDBG("E220LoraModeConfig-Fail: lora broken!\n");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(mode == current_mode)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // 同一个模式直接返回,不输出信息
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 打开PIN驱动
 | 
				
			||||||
 | 
					    int pin_fd = PrivOpen(E220_PIN_DRIVER,O_RDWR);
 | 
				
			||||||
 | 
					    if (pin_fd < 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DDBG("E220LoraModeConfig-Fail: open pin driver fail %s!\n",E220_PIN_DRIVER);
 | 
				
			||||||
 | 
					        lora_state = STATE_BROKEN;
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 配置管脚属性
 | 
				
			||||||
 | 
					    struct PinParam pin_param ={.cmd = GPIO_CONFIG_MODE,.mode = GPIO_CFG_OUTPUT,.pin = E220_M0_PATH};
 | 
				
			||||||
 | 
					    struct PrivIoctlCfg ioctl_config = {.ioctl_driver_type = PIN_TYPE, .args = &pin_param};
 | 
				
			||||||
 | 
					    if (0 != PrivIoctl(pin_fd,OPE_CFG,&ioctl_config))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DDBG("E220LoraModeConfig-Fail: config m0 fail!\n");
 | 
				
			||||||
 | 
					        lora_state = STATE_BROKEN;
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pin_param.pin = E220_M1_PATH;
 | 
				
			||||||
 | 
					    ioctl_config.args = &pin_param;
 | 
				
			||||||
 | 
					    if (0 != PrivIoctl(pin_fd,OPE_CFG,&ioctl_config))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DDBG("E220LoraModeConfig-Fail: config m1 fail!\n");
 | 
				
			||||||
 | 
					        lora_state = STATE_BROKEN;
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct PinStat pin_stat;
 | 
				
			||||||
 | 
					    switch (mode)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    case MODE_TRANSFER_MODE:
 | 
				
			||||||
 | 
					    {   
 | 
				
			||||||
 | 
					        pin_stat.pin = E220_M0_PATH;
 | 
				
			||||||
 | 
					        pin_stat.val = GPIO_LOW;
 | 
				
			||||||
 | 
					        if (-1 == PrivWrite(pin_fd, &pin_stat, 1))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            DDBG("E220LoraModeConfig-Fail: config m0 low fail!\n");
 | 
				
			||||||
 | 
					            lora_state = STATE_BROKEN;
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        pin_stat.pin = E220_M1_PATH;
 | 
				
			||||||
 | 
					        pin_stat.val = GPIO_LOW;
 | 
				
			||||||
 | 
					        if (-1 == PrivWrite(pin_fd, &pin_stat, 1))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            DDBG("E220LoraModeConfig-Fail: config m1 low fail!\n");
 | 
				
			||||||
 | 
					            lora_state = STATE_BROKEN;
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case MODE_CONFIG_SLEEP:
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        pin_stat.pin = E220_M0_PATH;
 | 
				
			||||||
 | 
					        pin_stat.val = GPIO_HIGH;
 | 
				
			||||||
 | 
					        if (-1 == PrivWrite(pin_fd, &pin_stat, 1))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            DDBG("E220LoraModeConfig-Fail: config m0 high fail!\n");
 | 
				
			||||||
 | 
					            lora_state = STATE_BROKEN;
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        pin_stat.pin = E220_M1_PATH;
 | 
				
			||||||
 | 
					        pin_stat.val = GPIO_HIGH;
 | 
				
			||||||
 | 
					        if (-1 == PrivWrite(pin_fd, &pin_stat, 1))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            DDBG("E220LoraModeConfig-Fail: config m1 high fail!\n");
 | 
				
			||||||
 | 
					            lora_state = STATE_BROKEN;
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        DDBG("E220LoraModeConfig-Fail: unsupported lora mode!\n");
 | 
				
			||||||
 | 
					        PrivClose(pin_fd);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    PrivTaskDelay(E220_CONFIG_DELAY);
 | 
				
			||||||
 | 
					    PrivClose(pin_fd);
 | 
				
			||||||
 | 
					    // 记录当前模式,避免不必要的重复配置
 | 
				
			||||||
 | 
					    current_mode = mode;
 | 
				
			||||||
 | 
					    DDBG("E220LoraModeConfig-Success: change to mode %s !\n",mode == MODE_CONFIG_SLEEP ? "MODE_CONFIG_SLEEP" : "MODE_TRANSFER_MODE");
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 通过指令获取硬件寄存器参数后将其保存并输出
 | 
				
			||||||
 | 
					 * @param adapter: 需要打开
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					static void PrintRegister(char* prefix)
 | 
				
			||||||
 | 
					{       
 | 
				
			||||||
 | 
					    // 打印数据
 | 
				
			||||||
 | 
					    DDBG("%s Register:",prefix);
 | 
				
			||||||
 | 
					    DDBG("ADDH:%X,ADDL:%X,REG0:%X,",register_cfg.ADDH,register_cfg.ADDL,register_cfg.REG0);
 | 
				
			||||||
 | 
					    DDBG("REG1:%X,REG2:%X,REG3:%X,",register_cfg.REG1,register_cfg.REG2,register_cfg.REG3);
 | 
				
			||||||
 | 
					    DDBG("KEYH:%X,KEYL:%X\n",register_cfg.KEYH,register_cfg.KEYL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 根据配置的数据覆写硬件寄存器参数
 | 
				
			||||||
 | 
					 * @param adapter: 一个已经打开了UART串口的Lora硬件
 | 
				
			||||||
 | 
					 * @param start_addr: 需要覆写的寄存器起始地址
 | 
				
			||||||
 | 
					 * @param byte_length: 需要覆写的寄存器数量
 | 
				
			||||||
 | 
					 * @param args: 需要覆写的寄存器参数
 | 
				
			||||||
 | 
					 * @return: 0 -> Success; -1 -> Fail
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					static uint8 WriteRegister(struct Adapter *adapter,uint8 start_addr,uint8 byte_length,void* args)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (STATE_BROKEN == lora_state)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DDBG("WriteRegister-Fail: lora broken!\n");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 切换硬件到配置模式
 | 
				
			||||||
 | 
					    E220LoraModeConfig(MODE_CONFIG_SLEEP);
 | 
				
			||||||
 | 
					    // 构造寄存器覆写数据
 | 
				
			||||||
 | 
					    uint8 buffer[11] = {0};
 | 
				
			||||||
 | 
					    buffer[0] = 0XC0;
 | 
				
			||||||
 | 
					    buffer[1] = start_addr;
 | 
				
			||||||
 | 
					    buffer[2] = byte_length;
 | 
				
			||||||
 | 
					    memcpy(&buffer[3],args,byte_length);
 | 
				
			||||||
 | 
					    // 覆写寄存器参数
 | 
				
			||||||
 | 
					    if (PrivWrite(adapter->fd, (void *)buffer, byte_length + 3) < 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        PrintRegister("WriteRegister-Fail");
 | 
				
			||||||
 | 
					        lora_state = STATE_BROKEN;
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 等待配置完成后读取回写数据
 | 
				
			||||||
 | 
					    PrivTaskDelay(E220_CONFIG_DELAY);
 | 
				
			||||||
 | 
					    PrivRead(adapter->fd, buffer, byte_length + 3);             
 | 
				
			||||||
 | 
					    PrintRegister("WriteRegister-Success");
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 根据默认的配置对一个已经打开UART串口的Lora硬件进行寄存器参数的初始化,开启后只会被调用一次
 | 
				
			||||||
 | 
					 * @param adapter: 需要打开
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					static uint8 E220RegisterInit(struct Adapter *adapter)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(STATE_BROKEN == lora_state)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DDBG("E220RegisterInit-Fail: lora broken!\n");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (lora_init == E220_YES)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DDBG("E220RegisterInit-Success: inited before!\n");
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 按照默认的参数进行寄存器初始化
 | 
				
			||||||
 | 
						if (0 != WriteRegister(adapter,0X0,0X8,®ister_cfg))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        lora_state = STATE_BROKEN;
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 防止重复初始化
 | 
				
			||||||
 | 
					    lora_init = E220_YES;
 | 
				
			||||||
 | 
					    DDBG("E220RegisterConfig-Success!\n");
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8 E220Open(struct Adapter *adapter)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (lora_state == STATE_BROKEN)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DDBG("E220Open-Fail: lora broken!\n");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (lora_state == STATE_OPENED)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // 避免重复打开
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 打开UART串口
 | 
				
			||||||
 | 
					    adapter->fd = PrivOpen(E220_UART_DRIVER,O_RDWR);
 | 
				
			||||||
 | 
					    if (adapter->fd < 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DDBG("E220Open-Fail: open uart fail - %s \n",E220_UART_DRIVER);
 | 
				
			||||||
 | 
					        lora_state = STATE_BROKEN;
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 按照默认串口配置信息初始化串口
 | 
				
			||||||
 | 
					    struct PrivIoctlCfg ioctl_cfg;
 | 
				
			||||||
 | 
					    ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
 | 
				
			||||||
 | 
					    ioctl_cfg.args = &serial_cfg;
 | 
				
			||||||
 | 
					    if (0 != PrivIoctl(adapter->fd, OPE_INT,&ioctl_cfg))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DDBG("E220Open-Fail: uart config fail - %s \n",E220_UART_DRIVER);
 | 
				
			||||||
 | 
					        lora_state = STATE_BROKEN;
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 硬件的寄存器初始化
 | 
				
			||||||
 | 
					    if (0 != E220RegisterInit(adapter))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DDBG("E220Open-Fail: register config fail!\n");
 | 
				
			||||||
 | 
					        lora_state = STATE_BROKEN;
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    lora_state = STATE_OPENED;
 | 
				
			||||||
 | 
					    DDBG("E220Open-Success: e220 open success!\n");
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8 E220Close(struct Adapter *adapter)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (lora_state != STATE_OPENED)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DDBG("E220Close-Success: broken or closed before!\n");
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 关闭UART串口
 | 
				
			||||||
 | 
					    if (adapter->fd > 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (0 != PrivClose(adapter->fd))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            DDBG("E220Close-Failed: result != 0\n");
 | 
				
			||||||
 | 
					            lora_state = STATE_BROKEN;
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    adapter->fd = -1;
 | 
				
			||||||
 | 
					    lora_init = E220_NO;
 | 
				
			||||||
 | 
					    lora_state = STATE_CLOSED;
 | 
				
			||||||
 | 
					    DDBG("E220Close-Success: success!\n");
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8 E220Ioctl(struct Adapter *adapter, int config_item, void *args)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (STATE_OPENED != lora_state)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DDBG("E220Ioctl-Fail: open lora or the lora is broken!\n");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    switch (config_item)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    // 配置Lora串口超时时间
 | 
				
			||||||
 | 
					    case CONFIG_SERIAL_TIME_OUT:
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int32 time_out = *((int32*)args);
 | 
				
			||||||
 | 
					        if (time_out == serial_cfg.serial_timeout)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            DDBG("ConfigSerialTimeOut-Success: the same time_out %d !\n", time_out);
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        serial_cfg.serial_timeout = time_out;
 | 
				
			||||||
 | 
					        struct PrivIoctlCfg ioctl_cfg = { .ioctl_driver_type = SERIAL_TYPE,.args = &serial_cfg };
 | 
				
			||||||
 | 
					        // 修改串口配置信息
 | 
				
			||||||
 | 
					        if (0 != PrivIoctl(adapter->fd, OPE_INT, &ioctl_cfg))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            DDBG("ConfigSerialTimeOut-Fail: %d\n", serial_cfg.serial_timeout);
 | 
				
			||||||
 | 
					            lora_state = STATE_BROKEN;
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        DDBG("ConfigSerialTimeOut-Success: %d\n", serial_cfg.serial_timeout);
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 配置Lora模式
 | 
				
			||||||
 | 
					    case CONFIG_LORA_MODE:
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        enum LoraMode mode = *((enum LoraMode*)args);
 | 
				
			||||||
 | 
					        if (mode == current_mode)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            DDBG("ConfigLoraMode-Success: the same mode %s!\n",mode == MODE_TRANSFER_MODE ? "MODE_TRANSFER_MODE" : "MODE_CONFIG_SLEEP");
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (mode == MODE_TRANSFER_MODE || mode == MODE_CONFIG_SLEEP)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (0 != E220LoraModeConfig(mode))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                DDBG("ConfigLoraMode-Fail: config mode fail %s!\n",mode == MODE_TRANSFER_MODE ? "MODE_TRANSFER_MODE" : "MODE_CONFIG_SLEEP");
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            DDBG("ConfigLoraMode-Success: change lora mode to %s!\n",mode == MODE_TRANSFER_MODE ? "MODE_TRANSFER_MODE" : "MODE_CONFIG_SLEEP");
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        DDBG("ConfigLoraMode-Fail: unsupported lora mode %x!\n",mode);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 配置Lora传输模式
 | 
				
			||||||
 | 
					    case CONFIG_TRANS_MODE:
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (serial_cfg.serial_baud_rate != E220_DEFAULT_CONFIG_BAUD_RATE)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            DDBG("ConfigTransMode-Fail: only config by baud rate 9600!\n");
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        uint8 trans_mode = *((uint8*)args);
 | 
				
			||||||
 | 
					        if (trans_mode == TRANS_MODE_HYALINE || trans_mode == TRANS_MODE_ORIENTED)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // 判断参数是否有必要覆写
 | 
				
			||||||
 | 
					            if (register_cfg.REG3 & 0X40 == trans_mode)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                DDBG("ConfigTransMode-Success: the same trans mode %x!\n",trans_mode);
 | 
				
			||||||
 | 
					                return 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            trans_mode = register_cfg.REG3 & 0xBF | trans_mode;
 | 
				
			||||||
 | 
					            if (0 != WriteRegister(adapter,0X5,1,&trans_mode))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                lora_state = STATE_BROKEN;
 | 
				
			||||||
 | 
					                DDBG("ConfigTransMode-Fail: config trans mode fail %x!\n",trans_mode);
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            register_cfg.REG3 = trans_mode;
 | 
				
			||||||
 | 
					            DDBG("ConfigTransMode-Success: config trans mode success %x!\n",trans_mode);
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        DDBG("ConfigTransMode-Fail: unsupported trans mode %x!\n",trans_mode);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 配置Lora空中速率
 | 
				
			||||||
 | 
					    case CONFIG_AIR_RATE:
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (serial_cfg.serial_baud_rate != E220_DEFAULT_CONFIG_BAUD_RATE)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            DDBG("ConfigAirRate-Fail: only config by baud rate 9600!\n");
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        uint8 air_rate = *((uint8*)args);
 | 
				
			||||||
 | 
					        if (air_rate >= AIR_RATE_2D4K && air_rate <= AIR_RATE_62D5K)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // 判断参数是否有必要覆写
 | 
				
			||||||
 | 
					            if (register_cfg.REG0 & 0X7 == air_rate)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                DDBG("ConfigAirRate-Success: the same air rate %x!\n",air_rate);
 | 
				
			||||||
 | 
					                return 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            air_rate = ((register_cfg.REG0 >> 3) << 3) | air_rate;
 | 
				
			||||||
 | 
					            if (0 != WriteRegister(adapter,0X2,1,&air_rate))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                lora_state = STATE_BROKEN;
 | 
				
			||||||
 | 
					                DDBG("ConfigAirRate-Fail: write register fail %x!\n",air_rate);
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            register_cfg.REG0 = air_rate;
 | 
				
			||||||
 | 
					            DDBG("ConfigAirRate-Success: config air rate success %x!\n",air_rate & 0X7);
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        DDBG("ConfigAirRate-Fail: unsupported air rate %x!\n",air_rate);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 配置Lora的波特率
 | 
				
			||||||
 | 
					    case CONFIG_BAUD_RATE:
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        uint8 arg_rate = *((uint8*)args);
 | 
				
			||||||
 | 
					        uint8 temp_rate = arg_rate;
 | 
				
			||||||
 | 
					        if (arg_rate == E220_DEFAULT_CONFIG_BAUD_RATE_BYTE || arg_rate == E220_DEFAULT_USED_BAUD_RATE_BYTE)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // 判断参数是否有必要覆写
 | 
				
			||||||
 | 
					            if (register_cfg.REG0 & 0XE0 == arg_rate)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                DDBG("ConfigBaudRate-Success: the same baud rate %x!\n",arg_rate);
 | 
				
			||||||
 | 
					                return 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            temp_rate = register_cfg.REG0 & 0X1F | arg_rate;
 | 
				
			||||||
 | 
					            // 先更改寄存器的波特率
 | 
				
			||||||
 | 
					            if (0 != WriteRegister(adapter,0X2,1,&temp_rate))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                lora_state = STATE_BROKEN;
 | 
				
			||||||
 | 
					                DDBG("ConfigBaudRate-Fail: write register config fail %x!\n",temp_rate);
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            register_cfg.REG0 = temp_rate;
 | 
				
			||||||
 | 
					            // 重新配置串口波特率
 | 
				
			||||||
 | 
					            serial_cfg.serial_baud_rate = arg_rate == E220_DEFAULT_CONFIG_BAUD_RATE_BYTE ? BAUD_RATE_9600 : BAUD_RATE_115200;
 | 
				
			||||||
 | 
					            struct PrivIoctlCfg ioctl_cfg;
 | 
				
			||||||
 | 
					            ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
 | 
				
			||||||
 | 
					            ioctl_cfg.args = &serial_cfg;
 | 
				
			||||||
 | 
					            // 重新配置串口波特率
 | 
				
			||||||
 | 
					            if (0 != PrivIoctl(adapter->fd, OPE_INT, &ioctl_cfg))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                lora_state = STATE_BROKEN;
 | 
				
			||||||
 | 
					                DDBG("ConfigBaudRate-Fail: config serail fail %x!\n",temp_rate);
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            DDBG("ConfigBaudRate-Success: config baud rate success %d !\n",arg_rate == E220_DEFAULT_CONFIG_BAUD_RATE_BYTE ? BAUD_RATE_9600 : BAUD_RATE_115200);
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        DDBG("ConfigBaudRate-Fail: unsupported baud rate %x!\n",arg_rate);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 配置Lora地址参数
 | 
				
			||||||
 | 
					    case CONFIG_ADDRESS:
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (serial_cfg.serial_baud_rate != E220_DEFAULT_CONFIG_BAUD_RATE)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            DDBG("ConfigAddress-Fail: only config by baud rate 9600!\n");
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        uint16 address = *((uint16*)args);
 | 
				
			||||||
 | 
					        if ((address >> 8) | 0XFF == register_cfg.ADDH && address & 0XFF == register_cfg.ADDL)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            DDBG("ConfigAddress-Success: the same address %d!\n",address);
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        register_cfg.ADDH = (address >> 8) & 0XFF;
 | 
				
			||||||
 | 
					        register_cfg.ADDL = address & 0XFF;
 | 
				
			||||||
 | 
					        if (0 != WriteRegister(adapter,0X0,2,®ister_cfg))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            lora_state = STATE_BROKEN;
 | 
				
			||||||
 | 
					            DDBG("ConfigAddress-Fail: write register fail %d!\n",address);
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        DDBG("ConfigAddress-Success: config address success %d!\n",address);
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 配置Lora信道参数
 | 
				
			||||||
 | 
					    case CONFIG_CHANNEL:
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (serial_cfg.serial_baud_rate != E220_DEFAULT_CONFIG_BAUD_RATE)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            DDBG("ConfigChannel-Fail: only config by baud rate 9600!\n");
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        uint8 channel = *((uint8*)args);
 | 
				
			||||||
 | 
					        if (channel <= E220_MAX_CHANNEL_NUMBER)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (register_cfg.REG2 == channel)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                DDBG("ConfigChannel-Success: the same channel %d!\n",channel);
 | 
				
			||||||
 | 
					                return 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            register_cfg.REG2 = channel;
 | 
				
			||||||
 | 
					            if (0 != WriteRegister(adapter,0X4,1,®ister_cfg.REG2))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                lora_state = STATE_BROKEN;
 | 
				
			||||||
 | 
					                DDBG("ConfigChannel-Fail: write register fail %d!\n",channel);
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            DDBG("ConfigChannel-Success: config channel success %X !\n",channel);
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        DDBG("ConfigChannel-Fail: unsupported channel %d!\n",channel);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 打印配置信息
 | 
				
			||||||
 | 
					    case CONFIG_SHOW:
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DDBG("ConfigShow SerailTime: %d",serial_cfg.serial_timeout);
 | 
				
			||||||
 | 
					        PrintRegister("CONFIG_SHOW");
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        DDBG("E220Ioctl-Failed: config item unsupported %d!\n",config_item);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8 E220Send(struct Adapter *adapter, const void *buf, uint32 len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (STATE_OPENED != lora_state)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DDBG("E220Send-Fail: open lora before send data!\n");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 切换至传输模式
 | 
				
			||||||
 | 
					    if (0 != E220LoraModeConfig(MODE_TRANSFER_MODE))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DDBG("E220Send-Fail: change mode transfer fail!\n");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (len != PrivWrite(adapter->fd, (void *)buf, len))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DDBG("E220Send-Fail: send data fail!\n");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;    
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8 E220Recv(struct Adapter *adapter, void *buf, uint32 len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (STATE_OPENED != lora_state)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        DDBG("E220Recv-Fail: open lora before recv!\n");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 确保传输模式
 | 
				
			||||||
 | 
					    if (0 != E220LoraModeConfig(MODE_TRANSFER_MODE))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int recv_len = 0, recv_len_continue = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint8 *recv_buf = PrivMalloc(len);
 | 
				
			||||||
 | 
					    // 读取数据并返回已读取数据量
 | 
				
			||||||
 | 
					    recv_len = PrivRead(adapter->fd, recv_buf, len);
 | 
				
			||||||
 | 
					    if (recv_len) {
 | 
				
			||||||
 | 
					        while (recv_len < len) {
 | 
				
			||||||
 | 
					            // 读取超时后退出循环
 | 
				
			||||||
 | 
					            recv_len_continue = PrivRead(adapter->fd, recv_buf + recv_len, len - recv_len);
 | 
				
			||||||
 | 
					            if (recv_len_continue) {
 | 
				
			||||||
 | 
					                recv_len += recv_len_continue;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                recv_len = 0;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        memcpy(buf, recv_buf, len);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    PrivFree(recv_buf);
 | 
				
			||||||
 | 
					    return recv_len;  
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,146 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					* Copyright (c) 2020 AIIT XUOS Lab
 | 
				
			||||||
 | 
					* XiUOS is licensed under Mulan PSL v2.
 | 
				
			||||||
 | 
					* You can use this software according to the terms and conditions of the Mulan PSL v2.
 | 
				
			||||||
 | 
					* You may obtain a copy of Mulan PSL v2 at:
 | 
				
			||||||
 | 
					*        http://license.coscl.org.cn/MulanPSL2
 | 
				
			||||||
 | 
					* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | 
				
			||||||
 | 
					* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | 
				
			||||||
 | 
					* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | 
				
			||||||
 | 
					* See the Mulan PSL v2 for more details.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					* @file:    e220.h
 | 
				
			||||||
 | 
					* @brief:   E220 module underlying related configuration driver functions declarations
 | 
				
			||||||
 | 
					* @version: 0.1
 | 
				
			||||||
 | 
					* @author:  YUNFEI CHU
 | 
				
			||||||
 | 
					* @date:    2023/10/01 
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <transform.h>
 | 
				
			||||||
 | 
					#include <adapter.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __E220_H__
 | 
				
			||||||
 | 
					#define __E220_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// #define __DRIVER_DEBUG__                             // 驱动调试信息输出开关
 | 
				
			||||||
 | 
					#ifdef __DRIVER_DEBUG__  
 | 
				
			||||||
 | 
					#define DDBG(format,...) printf(format, ##__VA_ARGS__)  
 | 
				
			||||||
 | 
					#else  
 | 
				
			||||||
 | 
					#define DDBG(format,...)  
 | 
				
			||||||
 | 
					#endif // __DRIVER_DEBUG__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define E220_M0_PATH 32                                  // M0管脚位置
 | 
				
			||||||
 | 
					#define E220_M1_PATH 33                                  // M1管脚位置
 | 
				
			||||||
 | 
					#define E220_PIN_DRIVER "/dev/pin_dev"                   // PIN驱动名称
 | 
				
			||||||
 | 
					#define E220_UART_DRIVER "/dev/uart2_dev2"               // UART驱动名称
 | 
				
			||||||
 | 
					#define E220_ADDRESS 0XA                                 // 地址默认值
 | 
				
			||||||
 | 
					#define E220_DAFAULT_SERIAL_TIMEOUT 3000                 // 串口默认3S超时
 | 
				
			||||||
 | 
					#define E220_DEFAULT_CONFIG_BAUD_RATE BAUD_RATE_9600     // 在进行寄存器参数配置时,除了波特率本身的配置外,其他的配置只能在9600进行配置
 | 
				
			||||||
 | 
					#define E220_DEFAULT_CONFIG_BAUD_RATE_BYTE 0X60          // 9600波特率
 | 
				
			||||||
 | 
					#define E220_DEFAULT_USED_BAUD_RATE BAUD_RATE_115200     // 在进行使用时可以切换为该波特率,但是在配置时需要切换回配置波特率(9600)
 | 
				
			||||||
 | 
					#define E220_DEFAULT_USED_BAUD_RATE_BYTE 0XE0            // 115200波特率
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define E220_MAX_CHANNEL_NUMBER 83                       // E220最多支持84个信道,0~83
 | 
				
			||||||
 | 
					#define E220_DEFAULT_CHANNEL 0XA                         // 默认通道
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define E220_DEFAULT_AIR_RATE 0X0                        // 默认模块以2.4K的空中速率进行通信
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define E220_DEFAULT_TRANS_MODE 0X40                     // 默认使用定点传输传输模式
 | 
				
			||||||
 | 
					#define E220_CONFIG_DELAY 1000                           // 配置的硬件响应时间
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define E220_YES 0XFF
 | 
				
			||||||
 | 
					#define E220_NO 0X00
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum LoraMode                        // E220工作模式,支持四种,配置模式与休眠模式一致
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    MODE_TRANSFER_MODE = 0,          // M0 : M1 = 0 : 0 可发可收
 | 
				
			||||||
 | 
					    MODE_WOR_SEND,                   // M0 : M1 = 1 : 0 可发可收
 | 
				
			||||||
 | 
					    MODE_WOR_RECV,                   // M0 : M1 = 0 : 1 可收不发
 | 
				
			||||||
 | 
					    MODE_CONFIG_SLEEP                // M0 : M1 = 1 : 1 不收不发
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum LoraState                       // 硬件状态
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    STATE_CLOSED,                    // 硬件关闭
 | 
				
			||||||
 | 
					    STATE_OPENED,                    // 已正常开启
 | 
				
			||||||
 | 
					    STATE_BROKEN                     // 硬件损坏
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum LoraTransMode                   // 模块传输模式
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    TRANS_MODE_HYALINE = 0X0,        // 透明传输
 | 
				
			||||||
 | 
					    TRANS_MODE_ORIENTED = 0X40,      // 定点传输
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum LoraAirRate                     // 空中速率,通信双方必须设置一致的空中速率方可进行通信
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    AIR_RATE_2D4K = 0X0,             // 2.4K
 | 
				
			||||||
 | 
					    AIR_RATE_4D8K = 0X3,             // 4.8K
 | 
				
			||||||
 | 
					    AIR_RATE_9D6K = 0X4,             // 9.6K
 | 
				
			||||||
 | 
					    AIR_RATE_19D2K = 0X5,            // 19.2K
 | 
				
			||||||
 | 
					    AIR_RATE_38D4K = 0X6,            // 38.4K
 | 
				
			||||||
 | 
					    AIR_RATE_62D5K = 0X7             // 62.5K
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum LoraConfig                      // 支持IOCTL函数进行配置的配置项枚举,某些项只支持9600波特率配置
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CONFIG_SERIAL_TIME_OUT = 0X0,    // 串口超时时间
 | 
				
			||||||
 | 
					    CONFIG_LORA_MODE = 0X1,          // 配置Lora模式
 | 
				
			||||||
 | 
					    CONFIG_TRANS_MODE = 0X2,         // 配置Lora传输模式(9600)
 | 
				
			||||||
 | 
					    CONFIG_AIR_RATE = 0X3,           // 配置空中速率(9600)
 | 
				
			||||||
 | 
					    CONFIG_BAUD_RATE = 0X4,          // 配置波特率
 | 
				
			||||||
 | 
					    CONFIG_ADDRESS = 0X5,            // 配置设备地址(9600)
 | 
				
			||||||
 | 
					    CONFIG_CHANNEL = 0X6,            // 配置设备信道(9600)
 | 
				
			||||||
 | 
					    CONFIG_SHOW = 0X7                // 打印配置信息
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern enum LoraMode current_mode;   // 当前模块处于什么模式
 | 
				
			||||||
 | 
					extern enum LoraState lora_state;    // 当前模块的状态
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 打开硬件设施,开启串口并按照配置的初始化参数配置相关硬件、串口
 | 
				
			||||||
 | 
					 *         重复开启会直接返回,开启失败后不能重复尝试
 | 
				
			||||||
 | 
					 * @param adapter: 任何状态
 | 
				
			||||||
 | 
					 * @return: 0 -> Success : -1 -> Fail
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					uint8 E220Open(struct Adapter *adapter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 关闭硬件设施,关闭串口,同时会将所有的数据回复到原始的配置状态
 | 
				
			||||||
 | 
					 *         关闭失败默认为硬件损坏,未开启不可关闭
 | 
				
			||||||
 | 
					 * @param adapter: 任何状态
 | 
				
			||||||
 | 
					 * @return: 0 -> Success (硬件不是开启状态即成功): -1 -> Fail (硬件关闭过错报错)
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					uint8 E220Close(struct Adapter *adapter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 给处于开启状态的硬件配置相关信息,包括串口配置,寄存器参数等等
 | 
				
			||||||
 | 
					 *         支持的配置类型为@LoraConfig
 | 
				
			||||||
 | 
					 * @param adapter: 打开状态
 | 
				
			||||||
 | 
					 * @param config_item: 配置类型
 | 
				
			||||||
 | 
					 * @param args: 配置参数
 | 
				
			||||||
 | 
					 * @return: 0 -> Success : -1 -> Fail 
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					uint8 E220Ioctl(struct Adapter *adapter, int config_item, void *args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 通过硬件发送指定长度的数据
 | 
				
			||||||
 | 
					 * @param adapter: 打开状态
 | 
				
			||||||
 | 
					 * @param buf: 数据缓存区
 | 
				
			||||||
 | 
					 * @param len: 缓存区大小
 | 
				
			||||||
 | 
					 * @return 0 -> Success(全部发送完毕) : -1 -> Fail(未发送或发送不完整)
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					uint8 E220Send(struct Adapter *adapter, const void *buf, uint32 len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 通过硬件接受指定长度的数据到缓冲区
 | 
				
			||||||
 | 
					 * @param adapter: 打开状态
 | 
				
			||||||
 | 
					 * @param buf: 接受缓冲区
 | 
				
			||||||
 | 
					 * @param len: 需要接受的数据长度,该长度小于等于接受缓存区长度
 | 
				
			||||||
 | 
					 * @return 0 -> 接收到了指定长度的数据 : -1 -> 未接受到指定长度的数据或者串口超时
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					uint8 E220Recv(struct Adapter *adapter, void *buf, uint32 len);
 | 
				
			||||||
 | 
					#endif // __E220_H__
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,324 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					* Copyright (c) 2020 AIIT XUOS Lab
 | 
				
			||||||
 | 
					* XiUOS is licensed under Mulan PSL v2.
 | 
				
			||||||
 | 
					* You can use this software according to the terms and conditions of the Mulan PSL v2.
 | 
				
			||||||
 | 
					* You may obtain a copy of Mulan PSL v2 at:
 | 
				
			||||||
 | 
					*        http://license.coscl.org.cn/MulanPSL2
 | 
				
			||||||
 | 
					* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | 
				
			||||||
 | 
					* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | 
				
			||||||
 | 
					* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | 
				
			||||||
 | 
					* See the Mulan PSL v2 for more details.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					* @file:    lora_mac.h
 | 
				
			||||||
 | 
					* @brief:   Definition of data structures related to the Lora private protocol
 | 
				
			||||||
 | 
					* @version: 0.1
 | 
				
			||||||
 | 
					* @author:  YUNFEI CHU
 | 
				
			||||||
 | 
					* @date:    2023/10/01 
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <transform.h>
 | 
				
			||||||
 | 
					#include <adapter.h>
 | 
				
			||||||
 | 
					#include "../lora_driver/e220.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// #define AS_LORA_GATEWAY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*数据帧**************************************************************************/
 | 
				
			||||||
 | 
					#define FRAME_BEGIN_MARK 0x3C3C                                              // 帧开始标志,高低字节相同
 | 
				
			||||||
 | 
					#define FRAME_END_MARK 0X5A5A                                                // 帧结束标志,高低字节相同
 | 
				
			||||||
 | 
					#define FRAME_MAX_DATA_LENGTH 200                                            // 默认支持的最大数据包为200字节
 | 
				
			||||||
 | 
					#define FRAME_ADDR_INFO_LENGTH 3                                             // 定点传输时前三字节为地址和信道共三个字节
 | 
				
			||||||
 | 
					#define FRAME_META_LENGTH 14                                                 // 数据帧相关信息长度
 | 
				
			||||||
 | 
					#define FRAME_MAX_USER_DATA_LENGTH FRAME_MAX_DATA_LENGTH - FRAME_META_LENGTH - FRAME_ADDR_INFO_LENGTH
 | 
				
			||||||
 | 
					#define FRAME_CRC_INDEX_BEGIN 2                                              // CRC校验开始地址
 | 
				
			||||||
 | 
					#define FRAME_CRC_LENGTH 8                                                   // CRC校验元数据量长度
 | 
				
			||||||
 | 
					#define FRAME_BYTE_OK 0XFF                                                   // 是/成功
 | 
				
			||||||
 | 
					#define FRAME_BYTE_NO 0X00                                                   // 否/失败
 | 
				
			||||||
 | 
					#define FRAME_NECK_LENGTH 8                                                  // 帧头以下,额外数据以上的长度
 | 
				
			||||||
 | 
					#define FRAME_FOOT_LENGTH 4                                                  // 额外数据以下至帧尾的数据长度
 | 
				
			||||||
 | 
					#define FRAME_MARK_LENGTH 2                                                  // 帧头帧尾的数据长度
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum FrameType                  // 数据帧类型枚举
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    E_G_JOIN = 0,               // 客户端入网请求,需回复
 | 
				
			||||||
 | 
					    E_G_QUIT,                   // 客户端退网请求,不需回复
 | 
				
			||||||
 | 
					    E_G_DATA,                   // 客户端上传数据,需回复
 | 
				
			||||||
 | 
					    G_E_ANS,                    // 网关响应客户端请求
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct LoraFrame                // 数据帧消息类型
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint16 begin_mark;          // 开始标志 0x3C3C
 | 
				
			||||||
 | 
					    uint16 session_id;          // 会话ID,客户端每次数据上传会随机设置,若是回复ID不一致则表示数据丢失
 | 
				
			||||||
 | 
					    uint16 dev_addr;            // 设备地址,特指终端地址,网关地址固定为 0XFFFF
 | 
				
			||||||
 | 
					    uint8 down_channel;         // 下行通道,即终端所在的信道
 | 
				
			||||||
 | 
					    uint8 frame_type;           // 数据帧的类型
 | 
				
			||||||
 | 
					    uint8 frame_confirm;        // 该数据帧是否需要确认回复
 | 
				
			||||||
 | 
					    uint8 frame_attach;         // 用于携带简单的数据,例如用户数据长度
 | 
				
			||||||
 | 
					    uint8 *user_data;           // 需要额外携带的大量数据
 | 
				
			||||||
 | 
					    uint8 crc_hi;               // 校验位高字节
 | 
				
			||||||
 | 
					    uint8 crc_lo;               // 校验位低字节
 | 
				
			||||||
 | 
					    uint16 end_mark;            // 结束标志 0X5A5A
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern struct LoraFrame send_frame;                             // 数据帧发送缓冲区
 | 
				
			||||||
 | 
					extern struct LoraFrame recv_frame;                             // 数据帧接受缓存区
 | 
				
			||||||
 | 
					extern uint8 send_data_buffer[FRAME_MAX_USER_DATA_LENGTH];      // 数据发送缓冲区
 | 
				
			||||||
 | 
					extern uint8 recv_data_buffer[FRAME_MAX_USER_DATA_LENGTH];      // 数据接受缓存区
 | 
				
			||||||
 | 
					extern uint8 total_data_buffer[FRAME_MAX_DATA_LENGTH];          // 数据帧加数据的最大缓冲区
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 将数据帧缓冲区置为 0 ,并添加帧头,帧尾数据
 | 
				
			||||||
 | 
					 * @param frame: 数据帧缓冲区
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					void InitLoraFrame(struct LoraFrame* frame);                  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 打印数据帧结构信息,便于运行、开发调试
 | 
				
			||||||
 | 
					 * @param fram: 需要打印的数据帧
 | 
				
			||||||
 | 
					 * @param prefix: 那里打印的数据帧信息
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					void ShowLoraFrame(struct LoraFrame* frame,char* prefix);                   
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 计算数据帧的校验值,除去帧头、帧尾、校验值本身,若是应该携带数据的类型未携带数据时报错
 | 
				
			||||||
 | 
					 * @return: 消息类型和数据不匹配时为 -1
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					uint8 CalCrlLoraFrame(struct LoraFrame* frame);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 校验数据帧的完整性
 | 
				
			||||||
 | 
					 * @return: 校验失败为 -1
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					uint8 CheckCrcLoraFrame(struct LoraFrame* frame);
 | 
				
			||||||
 | 
					/*数据帧**************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*基础操作************************************************************************/
 | 
				
			||||||
 | 
					#define LORA_ADAPTER_NAME "e220"                // Lora适配器名称
 | 
				
			||||||
 | 
					#define LORA_OK 0XFF                            // 标识成功、确认等
 | 
				
			||||||
 | 
					#define LORA_NO 0X00                            // 标识失败、丢失等
 | 
				
			||||||
 | 
					#define LORA_TIME_ON_AIR 2                      // 估计的空中时间
 | 
				
			||||||
 | 
					#define LORA_AIR_RATE 0                         // 模块的空中速率
 | 
				
			||||||
 | 
					#define LORA_FRAME_RETRY 5                      // 数据帧重传次数,超过这个次数判定断网
 | 
				
			||||||
 | 
					#define LORA_GATEWAY_MAX_NODE 20                // 每个网关支持的最大客户端个数,防止上行通道过于拥挤
 | 
				
			||||||
 | 
					#define LORA_GATEWAY_ADDRESS 0XFFFF             // 网关地址,单信道网关的监听地址
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef AS_LORA_GATEWAY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LORA_RECV_TIME 10                       // 串口超时时间
 | 
				
			||||||
 | 
					#define LORA_GATEWAY_CHANNEL 0XA                // 网关默认信道
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LORA_ADDRESS 0X9                        // 节点默认地址
 | 
				
			||||||
 | 
					#define LORA_RECV_TIME 5                        // 节点默认串口超时时间
 | 
				
			||||||
 | 
					#define LORA_DOWN_CHANNEL 0X9                   // 节点默认下行信道
 | 
				
			||||||
 | 
					#define LORA_UP_CHANNEL 0XA                     // 节点默认上行通道
 | 
				
			||||||
 | 
					#define LORA_ADR_ENABLE LORA_NO                 // 节点是否开启网关自动搜索
 | 
				
			||||||
 | 
					#define LORA_RECONNECT_ENABLE LORA_OK           // 节点是否开启断网自动重联
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 从硬件获取一个完整的数据帧
 | 
				
			||||||
 | 
					 * @param recv_buffer: 数据帧缓冲区,在检测到带数据的数据帧时会自动关联数据缓冲区
 | 
				
			||||||
 | 
					 * @param prefix: 调用位置,便于调试
 | 
				
			||||||
 | 
					 * @return 0: 成功接受到一个数据帧(从侦测到数据帧头部开始、成功接受到帧尾部且数据校验成功)
 | 
				
			||||||
 | 
					 *         -1:串口超时;数据帧接受不完整;数据帧完整性校验失败;
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					uint8 LoraRecvFrame(struct Adapter* adapter, struct LoraFrame* recv_buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 通过硬件向指定的位置的信道发送数据
 | 
				
			||||||
 | 
					 * @param send_buffer: 数据帧缓冲区,在检测到带数据的数据帧时会自动发送关联数据缓冲区
 | 
				
			||||||
 | 
					 * @param addr: 目标的地址
 | 
				
			||||||
 | 
					 * @param channel: 目标的信道
 | 
				
			||||||
 | 
					 * @return 0: 成功发送指定长度的数据
 | 
				
			||||||
 | 
					 *         -1:未能成功发送制定数据
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					uint8 LoraSendFrame(struct Adapter* adapter, struct LoraFrame* send_buffer,uint16 addr,uint8 channel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 在一轮超时后未能接收到信号时判定信道空闲
 | 
				
			||||||
 | 
					 * @param download_channel: 下行信道
 | 
				
			||||||
 | 
					 * @param upload_channel: 上行信道
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					void SignalDetector(struct Adapter *adapter,uint8 download_channel,uint8 upload_channel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 获取随机数,用于客户端和网关之间的会话
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					uint16 GetSessionId(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 获取操作函数集合,客户端和网关各自实现
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					AdapterProductInfoType LoraAttach(struct Adapter *adapter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 注册函数,需要各自实现
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					uint8 UsrAdapterLoraRegister(struct Adapter *adapter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 框架初始化函数,需要替换掉原有的初始化函数
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					int UsrAdapterLoraInit(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*基础操作************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*客户端操作************************************************************************/
 | 
				
			||||||
 | 
					enum EndNodeState                     //节点状态
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NODE_STATE_DISCONNECT = 0,        // 硬件开启,但是没有联网,后台程序可能开启
 | 
				
			||||||
 | 
					    NODE_STATE_CONNECT,               // 硬件开启,已经联网,后台程序可能开启
 | 
				
			||||||
 | 
					    NODE_STATE_BROKEN,                // 硬件损坏,无后台程序
 | 
				
			||||||
 | 
					    NODE_STATE_CLOSED                 // 硬件关闭,无后台程序
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct EndNodeParam                   // 节点参数结构
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint16 dev_addr;                  // 设备地址信息
 | 
				
			||||||
 | 
					    uint8 down_channel;               // 下行通道,终端可以接收信息的信道
 | 
				
			||||||
 | 
					    uint8 upload_channel;             // 上行通道,终端可以给网关发送信息的信道
 | 
				
			||||||
 | 
					    uint16 session_id;                // 会话ID,用于判定数据帧是否存在丢失
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    enum EndNodeState node_state;     // 客户端状态
 | 
				
			||||||
 | 
					    enum LoraAirRate air_rate;        // 终端的空中速率
 | 
				
			||||||
 | 
					    uint8 adr_enable;                 // 终端是否开启自动寻找上行网关
 | 
				
			||||||
 | 
					    uint8 reconnect_enable;           // 终端断网自动重联
 | 
				
			||||||
 | 
					    uint8 recv_time;                  // 接受下行消息的时间窗口长度,单位为秒
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern struct EndNodeParam node_param;                                      // 客户端参数
 | 
				
			||||||
 | 
					extern int (*node_handlers[])(struct Adapter*,struct LoraFrame*);           // 客户端处理流程
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 打开终端硬件,按照配置的CLASS决定是否开启硬件接收和后台处理程序
 | 
				
			||||||
 | 
					 * @return: 0 -> Success : -1 -> Fail
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					int NodeOpen(struct Adapter *adapter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 关闭终端硬件设施和后台处理程序
 | 
				
			||||||
 | 
					 * @return: 0 -> Success : -1 -> Fail
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					int NodeClose(struct Adapter *adapter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 终端接入网关,向该上行通道发送入网请求
 | 
				
			||||||
 | 
					 * @param adapter: 已经打开的适配器
 | 
				
			||||||
 | 
					 * @param net_group: 需要加入的网络编号
 | 
				
			||||||
 | 
					 * @return: 0 -> Success : -1 -> Fail
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					int NodeJoin(struct Adapter *adapter, unsigned char *net_group);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 发送数据到网关
 | 
				
			||||||
 | 
					 * @param adapter: 已经联网的适配器
 | 
				
			||||||
 | 
					 * @param buf: 待发送数据
 | 
				
			||||||
 | 
					 * @param len: 待发送数据长度
 | 
				
			||||||
 | 
					 * @return: 0 -> Success : -1 -> Fail
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					int NodeSend(struct Adapter *adapter, const void *buf, size_t len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 终端退出某个网络
 | 
				
			||||||
 | 
					 * @param adapter: 已经联网的适配器
 | 
				
			||||||
 | 
					 * @param net_group: 需要退出的网络编号
 | 
				
			||||||
 | 
					 * @return: 0 -> Success : -1 -> Fail
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					int NodeQuit(struct Adapter *adapter, unsigned char *net_group);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 打印终端的信息
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					int NodeNetState(struct Adapter *adapter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*客户端操作************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*网关操作*************************************************************************/
 | 
				
			||||||
 | 
					struct EndNodeInfo                                         // 网关存储的客户端信息
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint16 node_addr;                                      // 客户端地址
 | 
				
			||||||
 | 
					    uint8 node_down_channel;                               // 客户端下行通道
 | 
				
			||||||
 | 
					    uint16 session_id;                                     // 上一个命令的会话ID
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum GatewayState                   // 网关的状态枚举
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    GATEWAY_CLOSED,                 // Lora还没有打开
 | 
				
			||||||
 | 
					    GATEWAY_OPENED,                 // 已打开,但是未开始工作
 | 
				
			||||||
 | 
					    GATEWAY_WORKING,                // 正常打开且已经开始正常工作
 | 
				
			||||||
 | 
					    GATEWAY_BROKEN                  // 模块损坏
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct GatewayParam                                                   // 网关参数
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint16 dev_addr;                                                  // 设备ID
 | 
				
			||||||
 | 
					    uint8 channel;                                                    // 网络编号
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int recv_time;                                                    // 串口超时时间
 | 
				
			||||||
 | 
					    enum LoraAirRate air_rate;                                        // 网关空中速率
 | 
				
			||||||
 | 
					    uint8 frame_retry;                                                // 重传次数
 | 
				
			||||||
 | 
					    enum GatewayState gateway_state;                                  // 网关状态
 | 
				
			||||||
 | 
					    struct EndNodeInfo *node_infos[LORA_GATEWAY_MAX_NODE];            // 客户端信息
 | 
				
			||||||
 | 
					    uint16 node_count;                                                // 已链接客户端数量
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern struct GatewayParam gateway_param;                             // 网关参数
 | 
				
			||||||
 | 
					extern int (*gateway_handlers[])(struct Adapter*,struct LoraFrame*);  // 处理程序
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 打开Lora硬件设施,但是不会将其接入网络中
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					int GatewayOpen(struct Adapter *adapter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 关闭硬件设施,需要先断网
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					int GatewayClose(struct Adapter *adapter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 配置网关参数的配置接口,这个函数配置的是网关的参数
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					int GatewayIoctl(struct Adapter *adapter, int cmd, void *args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 启用网关,使其可以为其他终端服务
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					int GatewaySetup(struct Adapter *adapter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 停用网关,但是不会给网络中的终端下线通知
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					int GatewaySetDown(struct Adapter *adapter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 打印网关相关信息
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					int GatewayNetState(struct Adapter *adapter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 网关主任务,负责终端各项事务的自动化处理
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					void* GatewayTask(void* adapter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 处理终端入网请求
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					int GatewayJoinHandler(struct Adapter* adapter,struct LoraFrame* frame);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 处理终端退网
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					int GatewayQuitHandler(struct Adapter* adapter,struct LoraFrame* frame);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 处理终端数据传输
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					int GatewayDataSendHandler(struct Adapter* adapter,struct LoraFrame* frame);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*网关操作*************************************************************************/
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,117 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					* Copyright (c) 2020 AIIT XUOS Lab
 | 
				
			||||||
 | 
					* XiUOS is licensed under Mulan PSL v2.
 | 
				
			||||||
 | 
					* You can use this software according to the terms and conditions of the Mulan PSL v2.
 | 
				
			||||||
 | 
					* You may obtain a copy of Mulan PSL v2 at:
 | 
				
			||||||
 | 
					*        http://license.coscl.org.cn/MulanPSL2
 | 
				
			||||||
 | 
					* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | 
				
			||||||
 | 
					* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | 
				
			||||||
 | 
					* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | 
				
			||||||
 | 
					* See the Mulan PSL v2 for more details.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					* @file:    test_lora_net_final.c
 | 
				
			||||||
 | 
					* @brief:   Private protocol test functions
 | 
				
			||||||
 | 
					* @version: 0.1
 | 
				
			||||||
 | 
					* @author:  YUNFEI CHU
 | 
				
			||||||
 | 
					* @date:    2023/10/01 
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "test_lora_net_final.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef AS_LORA_GATEWAY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 网关测试函数
 | 
				
			||||||
 | 
					 * 1. 打开Lora硬件设施.
 | 
				
			||||||
 | 
					 * 2. 接入网络.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					void TestGateway(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct Adapter* gateway_adapter = (struct Adapter*)AdapterDeviceFindByName(ADAPTER_LORA_NAME);
 | 
				
			||||||
 | 
					    // 打开设备
 | 
				
			||||||
 | 
					    if (0 != AdapterDeviceOpen(gateway_adapter))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        printf("TestGateway-Fail: open lora fail!\n");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    printf("TestGateway-Info: open lora success!\n");
 | 
				
			||||||
 | 
					    // 接入网络
 | 
				
			||||||
 | 
					    if (0 != AdapterDeviceSetUp(gateway_adapter))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        printf("TestGateway-Fail: setup net fail!\n");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    printf("TestGateway-Success: gateway set up success!\n");
 | 
				
			||||||
 | 
					    AdapterDeviceNetstat(gateway_adapter);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					PRIV_SHELL_CMD_FUNCTION(TestGateway,TestGateway, PRIV_SHELL_CMD_MAIN_ATTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 打印网关信息
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					void TestGatewayInfo(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct Adapter* gateway_adapter = (struct Adapter*)AdapterDeviceFindByName(ADAPTER_LORA_NAME);
 | 
				
			||||||
 | 
					    AdapterDeviceNetstat(gateway_adapter);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					PRIV_SHELL_CMD_FUNCTION(TestGatewayInfo,TestGatewayInfo, PRIV_SHELL_CMD_MAIN_ATTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 节点测试函数
 | 
				
			||||||
 | 
					 * 1. 打开Lora硬件设施.
 | 
				
			||||||
 | 
					 * 2. 连接到网关.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					void TestNodeUp(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct Adapter* node_adapter = (struct Adapter*)AdapterDeviceFindByName(ADAPTER_LORA_NAME);
 | 
				
			||||||
 | 
					    // 打开设备
 | 
				
			||||||
 | 
					    if (0 != AdapterDeviceOpen(node_adapter))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        printf("TestNodeUp-Fail: open lora fail!\n");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    AdapterDeviceNetstat(node_adapter);
 | 
				
			||||||
 | 
					    // 接入网络
 | 
				
			||||||
 | 
					    uint8 net_id = 0XA;
 | 
				
			||||||
 | 
					    if (0 != AdapterDeviceJoin(node_adapter,&net_id))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        printf("TestNodeUp-Fail: join net fail!\n");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    AdapterDeviceNetstat(node_adapter);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					PRIV_SHELL_CMD_FUNCTION(TestNodeUp,TestNodeUp, PRIV_SHELL_CMD_MAIN_ATTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 发送数据
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					void TestNodeSend(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char* data = "Hello,Gateway-OtherNode!";
 | 
				
			||||||
 | 
					    struct Adapter* node_adapter = (struct Adapter*)AdapterDeviceFindByName(ADAPTER_LORA_NAME);
 | 
				
			||||||
 | 
					    AdapterDeviceSend(node_adapter,data,strlen(data));
 | 
				
			||||||
 | 
					    AdapterDeviceNetstat(node_adapter);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					PRIV_SHELL_CMD_FUNCTION(TestNodeSend,TestNodeSend, PRIV_SHELL_CMD_MAIN_ATTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 循环发送数据
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					void TestNodeSendCycle(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int cycle_count = 5;
 | 
				
			||||||
 | 
					    char* data = "Hello,Gateway-OtherNode-Cycle!";
 | 
				
			||||||
 | 
					    struct Adapter *node_adapter = (struct Adapter *)AdapterDeviceFindByName(ADAPTER_LORA_NAME);
 | 
				
			||||||
 | 
					    while (cycle_count -- > 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        AdapterDeviceSend(node_adapter, data, strlen(data));
 | 
				
			||||||
 | 
					        AdapterDeviceNetstat(node_adapter);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					PRIV_SHELL_CMD_FUNCTION(TestNodeSendCycle,TestNodeSendCycle, PRIV_SHELL_CMD_MAIN_ATTR);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,49 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					* Copyright (c) 2020 AIIT XUOS Lab
 | 
				
			||||||
 | 
					* XiUOS is licensed under Mulan PSL v2.
 | 
				
			||||||
 | 
					* You can use this software according to the terms and conditions of the Mulan PSL v2.
 | 
				
			||||||
 | 
					* You may obtain a copy of Mulan PSL v2 at:
 | 
				
			||||||
 | 
					*        http://license.coscl.org.cn/MulanPSL2
 | 
				
			||||||
 | 
					* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | 
				
			||||||
 | 
					* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | 
				
			||||||
 | 
					* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | 
				
			||||||
 | 
					* See the Mulan PSL v2 for more details.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					* @file:    test_lora_net_final.h
 | 
				
			||||||
 | 
					* @brief:   Private protocol test function definition
 | 
				
			||||||
 | 
					* @version: 0.1
 | 
				
			||||||
 | 
					* @author:  YUNFEI CHU
 | 
				
			||||||
 | 
					* @date:    2023/10/01 
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <transform.h>
 | 
				
			||||||
 | 
					#include <adapter.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// #define AS_LORA_GATEWAY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 节点测试函数
 | 
				
			||||||
 | 
					 * 1. 打开Lora硬件设施.
 | 
				
			||||||
 | 
					 * 2. 连接到网关.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					void TestNodeUp(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 发送数据
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					void TestNodeSend(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 循环发送数据
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					void TestNodeSendCycle(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief: 网关测试函数
 | 
				
			||||||
 | 
					 * 1. 打开Lora硬件设施.
 | 
				
			||||||
 | 
					 * 2. 接入网络.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					void TestGateway(void);
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					SRC_FILES += test_mqttclient.c
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SRC_DIR += mqtt
 | 
				
			||||||
 | 
					include $(KERNEL_ROOT)/compiler.mk
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,55 @@
 | 
				
			||||||
 | 
					## 1. 简介
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					本代码实现了MQTT对服务器订阅主体并发送信息功能
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2. 数据结构设计说明
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 2.1 MQTT数据结构定义
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 2.2 数据解析与加密
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 2.3 MQTT连接与订阅
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3. 测试程序说明
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MQTT基于TCP/IP协议,分为客户端与服务端。在本任务中,ARM终端作为客户端,与服务端连接并进行主题订阅。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					以下代码设置了进行订阅时需要的Client ID、用户名、密码及订阅主题。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					客户端首先需要根据以上信息向服务端发起连接请求,验证用户名及密码
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					随后进行主题订阅,接收服务端发布的消息
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					在订阅过程中需要对获取的信息进行读取,同时每隔一段时间向服务端发送保持活性ping请求,以维持与服务端的连接
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 4. 测试流程
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					测试流程为:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					首先执行setip命令,设置设备ip地址
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					随后执行“MqttSocketRecvTest 服务器ip”命令,订阅主题,然后在服务器端发布消息如图所示
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					最终设备端接收到信息
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 8.3 KiB  | 
| 
		 After Width: | Height: | Size: 30 KiB  | 
| 
		 After Width: | Height: | Size: 27 KiB  | 
| 
		 After Width: | Height: | Size: 74 KiB  | 
| 
		 After Width: | Height: | Size: 14 KiB  | 
| 
		 After Width: | Height: | Size: 39 KiB  | 
| 
		 After Width: | Height: | Size: 20 KiB  | 
| 
		 After Width: | Height: | Size: 20 KiB  | 
| 
		 After Width: | Height: | Size: 35 KiB  | 
| 
		 After Width: | Height: | Size: 41 KiB  | 
| 
		 After Width: | Height: | Size: 106 KiB  | 
| 
						 | 
					@ -0,0 +1,137 @@
 | 
				
			||||||
 | 
					/*******************************************************************************
 | 
				
			||||||
 | 
					 * Copyright (c) 2014, 2017 IBM Corp.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All rights reserved. This program and the accompanying materials
 | 
				
			||||||
 | 
					 * are made available under the terms of the Eclipse Public License v1.0
 | 
				
			||||||
 | 
					 * and Eclipse Distribution License v1.0 which accompany this distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Eclipse Public License is available at
 | 
				
			||||||
 | 
					 *    http://www.eclipse.org/legal/epl-v10.html
 | 
				
			||||||
 | 
					 * and the Eclipse Distribution License is available at
 | 
				
			||||||
 | 
					 *   http://www.eclipse.org/org/documents/edl-v10.php.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contributors:
 | 
				
			||||||
 | 
					 *    Ian Craggs - initial API and implementation and/or initial documentation
 | 
				
			||||||
 | 
					 *    Xiang Rong - 442039 Add makefile to Embedded C client
 | 
				
			||||||
 | 
					 *    Ian Craggs - fix for issue #64, bit order in connack response
 | 
				
			||||||
 | 
					 *******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef MQTTCONNECT_H_
 | 
				
			||||||
 | 
					#define MQTTCONNECT_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if !defined(DLLImport)
 | 
				
			||||||
 | 
					  #define DLLImport
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#if !defined(DLLExport)
 | 
				
			||||||
 | 
					  #define DLLExport
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef union
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned char all;	/**< all connect flags */
 | 
				
			||||||
 | 
					#if defined(REVERSED)
 | 
				
			||||||
 | 
						struct
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							unsigned int username : 1;			/**< 3.1 user name */
 | 
				
			||||||
 | 
							unsigned int password : 1; 			/**< 3.1 password */
 | 
				
			||||||
 | 
							unsigned int willRetain : 1;		/**< will retain setting */
 | 
				
			||||||
 | 
							unsigned int willQoS : 2;				/**< will QoS value */
 | 
				
			||||||
 | 
							unsigned int will : 1;			    /**< will flag */
 | 
				
			||||||
 | 
							unsigned int cleansession : 1;	  /**< clean session flag */
 | 
				
			||||||
 | 
							unsigned int : 1;	  	          /**< unused */
 | 
				
			||||||
 | 
						} bits;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						struct
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							unsigned int : 1;	     					/**< unused */
 | 
				
			||||||
 | 
							unsigned int cleansession : 1;	  /**< cleansession flag */
 | 
				
			||||||
 | 
							unsigned int will : 1;			    /**< will flag */
 | 
				
			||||||
 | 
							unsigned int willQoS : 2;				/**< will QoS value */
 | 
				
			||||||
 | 
							unsigned int willRetain : 1;		/**< will retain setting */
 | 
				
			||||||
 | 
							unsigned int password : 1; 			/**< 3.1 password */
 | 
				
			||||||
 | 
							unsigned int username : 1;			/**< 3.1 user name */
 | 
				
			||||||
 | 
						} bits;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					} MQTTConnectFlags;	/**< connect flags byte */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Defines the MQTT "Last Will and Testament" (LWT) settings for
 | 
				
			||||||
 | 
					 * the connect packet.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/** The eyecatcher for this structure.  must be MQTW. */
 | 
				
			||||||
 | 
						char struct_id[4];
 | 
				
			||||||
 | 
						/** The version number of this structure.  Must be 0 */
 | 
				
			||||||
 | 
						int struct_version;
 | 
				
			||||||
 | 
						/** The LWT topic to which the LWT message will be published. */
 | 
				
			||||||
 | 
						MQTTString topicName;
 | 
				
			||||||
 | 
						/** The LWT payload. */
 | 
				
			||||||
 | 
						MQTTString message;
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
					      * The retained flag for the LWT message (see MQTTAsync_message.retained).
 | 
				
			||||||
 | 
					      */
 | 
				
			||||||
 | 
						unsigned char retained;
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
					      * The quality of service setting for the LWT message (see
 | 
				
			||||||
 | 
					      * MQTTAsync_message.qos and @ref qos).
 | 
				
			||||||
 | 
					      */
 | 
				
			||||||
 | 
						char qos;
 | 
				
			||||||
 | 
					} MQTTPacket_willOptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MQTTPacket_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 0, {NULL, {0, NULL}}, {NULL, {0, NULL}}, 0, 0 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/** The eyecatcher for this structure.  must be MQTC. */
 | 
				
			||||||
 | 
						char struct_id[4];
 | 
				
			||||||
 | 
						/** The version number of this structure.  Must be 0 */
 | 
				
			||||||
 | 
						int struct_version;
 | 
				
			||||||
 | 
						/** Version of MQTT to be used.  3 = 3.1 4 = 3.1.1
 | 
				
			||||||
 | 
						  */
 | 
				
			||||||
 | 
						unsigned char MQTTVersion;
 | 
				
			||||||
 | 
						MQTTString clientID;
 | 
				
			||||||
 | 
						unsigned short keepAliveInterval;
 | 
				
			||||||
 | 
						unsigned char cleansession;
 | 
				
			||||||
 | 
						unsigned char willFlag;
 | 
				
			||||||
 | 
						MQTTPacket_willOptions will;
 | 
				
			||||||
 | 
						MQTTString username;
 | 
				
			||||||
 | 
						MQTTString password;
 | 
				
			||||||
 | 
					} MQTTPacket_connectData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef union
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned char all;	/**< all connack flags */
 | 
				
			||||||
 | 
					#if defined(REVERSED)
 | 
				
			||||||
 | 
						struct
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
					    unsigned int reserved : 7;	  	    /**< unused */
 | 
				
			||||||
 | 
							unsigned int sessionpresent : 1;    /**< session present flag */
 | 
				
			||||||
 | 
						} bits;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						struct
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							unsigned int sessionpresent : 1;    /**< session present flag */
 | 
				
			||||||
 | 
					    unsigned int reserved: 7;	     			/**< unused */
 | 
				
			||||||
 | 
						} bits;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					} MQTTConnackFlags;	/**< connack flags byte */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MQTTPacket_connectData_initializer { {'M', 'Q', 'T', 'C'}, 0, 4, {NULL, {0, NULL}}, 60, 1, 0, \
 | 
				
			||||||
 | 
							MQTTPacket_willOptions_initializer, {NULL, {0, NULL}}, {NULL, {0, NULL}} }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DLLExport int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options);
 | 
				
			||||||
 | 
					DLLExport int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DLLExport int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent);
 | 
				
			||||||
 | 
					DLLExport int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DLLExport int MQTTSerialize_disconnect(unsigned char* buf, int buflen);
 | 
				
			||||||
 | 
					DLLExport int MQTTSerialize_pingreq(unsigned char* buf, int buflen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* MQTTCONNECT_H_ */
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,214 @@
 | 
				
			||||||
 | 
					/*******************************************************************************
 | 
				
			||||||
 | 
					 * Copyright (c) 2014 IBM Corp.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All rights reserved. This program and the accompanying materials
 | 
				
			||||||
 | 
					 * are made available under the terms of the Eclipse Public License v1.0
 | 
				
			||||||
 | 
					 * and Eclipse Distribution License v1.0 which accompany this distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Eclipse Public License is available at
 | 
				
			||||||
 | 
					 *    http://www.eclipse.org/legal/epl-v10.html
 | 
				
			||||||
 | 
					 * and the Eclipse Distribution License is available at
 | 
				
			||||||
 | 
					 *   http://www.eclipse.org/org/documents/edl-v10.php.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contributors:
 | 
				
			||||||
 | 
					 *    Ian Craggs - initial API and implementation and/or initial documentation
 | 
				
			||||||
 | 
					 *******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "MQTTPacket.h"
 | 
				
			||||||
 | 
					#include "StackTrace.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Determines the length of the MQTT connect packet that would be produced using the supplied connect options.
 | 
				
			||||||
 | 
					  * @param options the options to be used to build the connect packet
 | 
				
			||||||
 | 
					  * @return the length of buffer needed to contain the serialized version of the packet
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTSerialize_connectLength(MQTTPacket_connectData* options)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int len = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (options->MQTTVersion == 3)
 | 
				
			||||||
 | 
							len = 12; /* variable depending on MQTT or MQIsdp */
 | 
				
			||||||
 | 
						else if (options->MQTTVersion == 4)
 | 
				
			||||||
 | 
							len = 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						len += MQTTstrlen(options->clientID)+2;
 | 
				
			||||||
 | 
						if (options->willFlag)
 | 
				
			||||||
 | 
							len += MQTTstrlen(options->will.topicName)+2 + MQTTstrlen(options->will.message)+2;
 | 
				
			||||||
 | 
						if (options->username.cstring || options->username.lenstring.data)
 | 
				
			||||||
 | 
							len += MQTTstrlen(options->username)+2;
 | 
				
			||||||
 | 
						if (options->password.cstring || options->password.lenstring.data)
 | 
				
			||||||
 | 
							len += MQTTstrlen(options->password)+2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_EXIT_RC(len);
 | 
				
			||||||
 | 
						return len;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Serializes the connect options into the buffer.
 | 
				
			||||||
 | 
					  * @param buf the buffer into which the packet will be serialized
 | 
				
			||||||
 | 
					  * @param len the length in bytes of the supplied buffer
 | 
				
			||||||
 | 
					  * @param options the options to be used to build the connect packet
 | 
				
			||||||
 | 
					  * @return serialized length, or error if 0
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned char *ptr = buf;
 | 
				
			||||||
 | 
						MQTTHeader header = {0};
 | 
				
			||||||
 | 
						MQTTConnectFlags flags = {0};
 | 
				
			||||||
 | 
						int len = 0;
 | 
				
			||||||
 | 
						int rc = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
						if (MQTTPacket_len(len = MQTTSerialize_connectLength(options)) > buflen)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							rc = MQTTPACKET_BUFFER_TOO_SHORT;
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						header.byte = 0;
 | 
				
			||||||
 | 
						header.bits.type = CONNECT;
 | 
				
			||||||
 | 
						writeChar(&ptr, header.byte); /* write header */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ptr += MQTTPacket_encode(ptr, len); /* write remaining length */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (options->MQTTVersion == 4)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							writeCString(&ptr, "MQTT");
 | 
				
			||||||
 | 
							writeChar(&ptr, (char) 4);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							writeCString(&ptr, "MQIsdp");
 | 
				
			||||||
 | 
							writeChar(&ptr, (char) 3);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						flags.all = 0;
 | 
				
			||||||
 | 
						flags.bits.cleansession = options->cleansession;
 | 
				
			||||||
 | 
						flags.bits.will = (options->willFlag) ? 1 : 0;
 | 
				
			||||||
 | 
						if (flags.bits.will)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							flags.bits.willQoS = options->will.qos;
 | 
				
			||||||
 | 
							flags.bits.willRetain = options->will.retained;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (options->username.cstring || options->username.lenstring.data)
 | 
				
			||||||
 | 
							flags.bits.username = 1;
 | 
				
			||||||
 | 
						if (options->password.cstring || options->password.lenstring.data)
 | 
				
			||||||
 | 
							flags.bits.password = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						writeChar(&ptr, flags.all);
 | 
				
			||||||
 | 
						writeInt(&ptr, options->keepAliveInterval);
 | 
				
			||||||
 | 
						writeMQTTString(&ptr, options->clientID);
 | 
				
			||||||
 | 
						if (options->willFlag)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							writeMQTTString(&ptr, options->will.topicName);
 | 
				
			||||||
 | 
							writeMQTTString(&ptr, options->will.message);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (flags.bits.username)
 | 
				
			||||||
 | 
							writeMQTTString(&ptr, options->username);
 | 
				
			||||||
 | 
						if (flags.bits.password)
 | 
				
			||||||
 | 
							writeMQTTString(&ptr, options->password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = ptr - buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						exit: FUNC_EXIT_RC(rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Deserializes the supplied (wire) buffer into connack data - return code
 | 
				
			||||||
 | 
					  * @param sessionPresent the session present flag returned (only for MQTT 3.1.1)
 | 
				
			||||||
 | 
					  * @param connack_rc returned integer value of the connack return code
 | 
				
			||||||
 | 
					  * @param buf the raw buffer data, of the correct length determined by the remaining length field
 | 
				
			||||||
 | 
					  * @param len the length in bytes of the data in the supplied buffer
 | 
				
			||||||
 | 
					  * @return error code.  1 is success, 0 is failure
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						MQTTHeader header = {0};
 | 
				
			||||||
 | 
						unsigned char* curdata = buf;
 | 
				
			||||||
 | 
						unsigned char* enddata = NULL;
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						int mylen;
 | 
				
			||||||
 | 
						MQTTConnackFlags flags = {0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
						header.byte = readChar(&curdata);
 | 
				
			||||||
 | 
						if (header.bits.type != CONNACK)
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
 | 
				
			||||||
 | 
						enddata = curdata + mylen;
 | 
				
			||||||
 | 
						if (enddata - curdata < 2)
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						flags.all = readChar(&curdata);
 | 
				
			||||||
 | 
						*sessionPresent = flags.bits.sessionpresent;
 | 
				
			||||||
 | 
						*connack_rc = readChar(&curdata);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = 1;
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						FUNC_EXIT_RC(rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Serializes a 0-length packet into the supplied buffer, ready for writing to a socket
 | 
				
			||||||
 | 
					  * @param buf the buffer into which the packet will be serialized
 | 
				
			||||||
 | 
					  * @param buflen the length in bytes of the supplied buffer, to avoid overruns
 | 
				
			||||||
 | 
					  * @param packettype the message type
 | 
				
			||||||
 | 
					  * @return serialized length, or error if 0
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTSerialize_zero(unsigned char* buf, int buflen, unsigned char packettype)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						MQTTHeader header = {0};
 | 
				
			||||||
 | 
						int rc = -1;
 | 
				
			||||||
 | 
						unsigned char *ptr = buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
						if (buflen < 2)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							rc = MQTTPACKET_BUFFER_TOO_SHORT;
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						header.byte = 0;
 | 
				
			||||||
 | 
						header.bits.type = packettype;
 | 
				
			||||||
 | 
						writeChar(&ptr, header.byte); /* write header */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ptr += MQTTPacket_encode(ptr, 0); /* write remaining length */
 | 
				
			||||||
 | 
						rc = ptr - buf;
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						FUNC_EXIT_RC(rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
 | 
				
			||||||
 | 
					  * @param buf the buffer into which the packet will be serialized
 | 
				
			||||||
 | 
					  * @param buflen the length in bytes of the supplied buffer, to avoid overruns
 | 
				
			||||||
 | 
					  * @return serialized length, or error if 0
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTSerialize_disconnect(unsigned char* buf, int buflen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return MQTTSerialize_zero(buf, buflen, DISCONNECT);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
 | 
				
			||||||
 | 
					  * @param buf the buffer into which the packet will be serialized
 | 
				
			||||||
 | 
					  * @param buflen the length in bytes of the supplied buffer, to avoid overruns
 | 
				
			||||||
 | 
					  * @return serialized length, or error if 0
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTSerialize_pingreq(unsigned char* buf, int buflen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return MQTTSerialize_zero(buf, buflen, PINGREQ);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,148 @@
 | 
				
			||||||
 | 
					/*******************************************************************************
 | 
				
			||||||
 | 
					 * Copyright (c) 2014 IBM Corp.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All rights reserved. This program and the accompanying materials
 | 
				
			||||||
 | 
					 * are made available under the terms of the Eclipse Public License v1.0
 | 
				
			||||||
 | 
					 * and Eclipse Distribution License v1.0 which accompany this distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Eclipse Public License is available at
 | 
				
			||||||
 | 
					 *    http://www.eclipse.org/legal/epl-v10.html
 | 
				
			||||||
 | 
					 * and the Eclipse Distribution License is available at
 | 
				
			||||||
 | 
					 *   http://www.eclipse.org/org/documents/edl-v10.php.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contributors:
 | 
				
			||||||
 | 
					 *    Ian Craggs - initial API and implementation and/or initial documentation
 | 
				
			||||||
 | 
					 *******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "StackTrace.h"
 | 
				
			||||||
 | 
					#include "MQTTPacket.h"
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define min(a, b) ((a < b) ? a : b)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Validates MQTT protocol name and version combinations
 | 
				
			||||||
 | 
					  * @param protocol the MQTT protocol name as an MQTTString
 | 
				
			||||||
 | 
					  * @param version the MQTT protocol version number, as in the connect packet
 | 
				
			||||||
 | 
					  * @return correct MQTT combination?  1 is true, 0 is false
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTPacket_checkVersion(MQTTString* protocol, int version)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (version == 3 && memcmp(protocol->lenstring.data, "MQIsdp",
 | 
				
			||||||
 | 
								min(6, protocol->lenstring.len)) == 0)
 | 
				
			||||||
 | 
							rc = 1;
 | 
				
			||||||
 | 
						else if (version == 4 && memcmp(protocol->lenstring.data, "MQTT",
 | 
				
			||||||
 | 
								min(4, protocol->lenstring.len)) == 0)
 | 
				
			||||||
 | 
							rc = 1;
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Deserializes the supplied (wire) buffer into connect data structure
 | 
				
			||||||
 | 
					  * @param data the connect data structure to be filled out
 | 
				
			||||||
 | 
					  * @param buf the raw buffer data, of the correct length determined by the remaining length field
 | 
				
			||||||
 | 
					  * @param len the length in bytes of the data in the supplied buffer
 | 
				
			||||||
 | 
					  * @return error code.  1 is success, 0 is failure
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						MQTTHeader header = {0};
 | 
				
			||||||
 | 
						MQTTConnectFlags flags = {0};
 | 
				
			||||||
 | 
						unsigned char* curdata = buf;
 | 
				
			||||||
 | 
						unsigned char* enddata = &buf[len];
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						MQTTString Protocol;
 | 
				
			||||||
 | 
						int version;
 | 
				
			||||||
 | 
						int mylen = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
						header.byte = readChar(&curdata);
 | 
				
			||||||
 | 
						if (header.bits.type != CONNECT)
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						curdata += MQTTPacket_decodeBuf(curdata, &mylen); /* read remaining length */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!readMQTTLenString(&Protocol, &curdata, enddata) ||
 | 
				
			||||||
 | 
							enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						version = (int)readChar(&curdata); /* Protocol version */
 | 
				
			||||||
 | 
						/* If we don't recognize the protocol version, we don't parse the connect packet on the
 | 
				
			||||||
 | 
						 * basis that we don't know what the format will be.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (MQTTPacket_checkVersion(&Protocol, version))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							flags.all = readChar(&curdata);
 | 
				
			||||||
 | 
							data->cleansession = flags.bits.cleansession;
 | 
				
			||||||
 | 
							data->keepAliveInterval = readInt(&curdata);
 | 
				
			||||||
 | 
							if (!readMQTTLenString(&data->clientID, &curdata, enddata))
 | 
				
			||||||
 | 
								goto exit;
 | 
				
			||||||
 | 
							data->willFlag = flags.bits.will;
 | 
				
			||||||
 | 
							if (flags.bits.will)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								data->will.qos = flags.bits.willQoS;
 | 
				
			||||||
 | 
								data->will.retained = flags.bits.willRetain;
 | 
				
			||||||
 | 
								if (!readMQTTLenString(&data->will.topicName, &curdata, enddata) ||
 | 
				
			||||||
 | 
									  !readMQTTLenString(&data->will.message, &curdata, enddata))
 | 
				
			||||||
 | 
									goto exit;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (flags.bits.username)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (enddata - curdata < 3 || !readMQTTLenString(&data->username, &curdata, enddata))
 | 
				
			||||||
 | 
									goto exit; /* username flag set, but no username supplied - invalid */
 | 
				
			||||||
 | 
								if (flags.bits.password &&
 | 
				
			||||||
 | 
									(enddata - curdata < 3 || !readMQTTLenString(&data->password, &curdata, enddata)))
 | 
				
			||||||
 | 
									goto exit; /* password flag set, but no password supplied - invalid */
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else if (flags.bits.password)
 | 
				
			||||||
 | 
								goto exit; /* password flag set without username - invalid */
 | 
				
			||||||
 | 
							rc = 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						FUNC_EXIT_RC(rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Serializes the connack packet into the supplied buffer.
 | 
				
			||||||
 | 
					  * @param buf the buffer into which the packet will be serialized
 | 
				
			||||||
 | 
					  * @param buflen the length in bytes of the supplied buffer
 | 
				
			||||||
 | 
					  * @param connack_rc the integer connack return code to be used 
 | 
				
			||||||
 | 
					  * @param sessionPresent the MQTT 3.1.1 sessionPresent flag
 | 
				
			||||||
 | 
					  * @return serialized length, or error if 0
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						MQTTHeader header = {0};
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						unsigned char *ptr = buf;
 | 
				
			||||||
 | 
						MQTTConnackFlags flags = {0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
						if (buflen < 2)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							rc = MQTTPACKET_BUFFER_TOO_SHORT;
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						header.byte = 0;
 | 
				
			||||||
 | 
						header.bits.type = CONNACK;
 | 
				
			||||||
 | 
						writeChar(&ptr, header.byte); /* write header */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						flags.all = 0;
 | 
				
			||||||
 | 
						flags.bits.sessionpresent = sessionPresent;
 | 
				
			||||||
 | 
						writeChar(&ptr, flags.all); 
 | 
				
			||||||
 | 
						writeChar(&ptr, connack_rc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = ptr - buf;
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						FUNC_EXIT_RC(rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,107 @@
 | 
				
			||||||
 | 
					/*******************************************************************************
 | 
				
			||||||
 | 
					 * Copyright (c) 2014 IBM Corp.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All rights reserved. This program and the accompanying materials
 | 
				
			||||||
 | 
					 * are made available under the terms of the Eclipse Public License v1.0
 | 
				
			||||||
 | 
					 * and Eclipse Distribution License v1.0 which accompany this distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Eclipse Public License is available at
 | 
				
			||||||
 | 
					 *    http://www.eclipse.org/legal/epl-v10.html
 | 
				
			||||||
 | 
					 * and the Eclipse Distribution License is available at
 | 
				
			||||||
 | 
					 *   http://www.eclipse.org/org/documents/edl-v10.php.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contributors:
 | 
				
			||||||
 | 
					 *    Ian Craggs - initial API and implementation and/or initial documentation
 | 
				
			||||||
 | 
					 *******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "StackTrace.h"
 | 
				
			||||||
 | 
					#include "MQTTPacket.h"
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define min(a, b) ((a < b) ? 1 : 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Deserializes the supplied (wire) buffer into publish data
 | 
				
			||||||
 | 
					  * @param dup returned integer - the MQTT dup flag
 | 
				
			||||||
 | 
					  * @param qos returned integer - the MQTT QoS value
 | 
				
			||||||
 | 
					  * @param retained returned integer - the MQTT retained flag
 | 
				
			||||||
 | 
					  * @param packetid returned integer - the MQTT packet identifier
 | 
				
			||||||
 | 
					  * @param topicName returned MQTTString - the MQTT topic in the publish
 | 
				
			||||||
 | 
					  * @param payload returned byte buffer - the MQTT publish payload
 | 
				
			||||||
 | 
					  * @param payloadlen returned integer - the length of the MQTT payload
 | 
				
			||||||
 | 
					  * @param buf the raw buffer data, of the correct length determined by the remaining length field
 | 
				
			||||||
 | 
					  * @param buflen the length in bytes of the data in the supplied buffer
 | 
				
			||||||
 | 
					  * @return error code.  1 is success
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName,
 | 
				
			||||||
 | 
							unsigned char** payload, int32_t* payloadlen, unsigned char* buf, int buflen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						MQTTHeader header = {0};
 | 
				
			||||||
 | 
						unsigned char* curdata = buf;
 | 
				
			||||||
 | 
						unsigned char* enddata = NULL;
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						int mylen = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
						header.byte = readChar(&curdata);
 | 
				
			||||||
 | 
						if (header.bits.type != PUBLISH)
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
						*dup = header.bits.dup;
 | 
				
			||||||
 | 
						*qos = header.bits.qos;
 | 
				
			||||||
 | 
						*retained = header.bits.retain;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
 | 
				
			||||||
 | 
						enddata = curdata + mylen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!readMQTTLenString(topicName, &curdata, enddata) ||
 | 
				
			||||||
 | 
							enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (*qos > 0)
 | 
				
			||||||
 | 
							*packetid = readInt(&curdata);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*payloadlen = enddata - curdata;
 | 
				
			||||||
 | 
						*payload = curdata;
 | 
				
			||||||
 | 
						rc = 1;
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						FUNC_EXIT_RC(rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Deserializes the supplied (wire) buffer into an ack
 | 
				
			||||||
 | 
					  * @param packettype returned integer - the MQTT packet type
 | 
				
			||||||
 | 
					  * @param dup returned integer - the MQTT dup flag
 | 
				
			||||||
 | 
					  * @param packetid returned integer - the MQTT packet identifier
 | 
				
			||||||
 | 
					  * @param buf the raw buffer data, of the correct length determined by the remaining length field
 | 
				
			||||||
 | 
					  * @param buflen the length in bytes of the data in the supplied buffer
 | 
				
			||||||
 | 
					  * @return error code.  1 is success, 0 is failure
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						MQTTHeader header = {0};
 | 
				
			||||||
 | 
						unsigned char* curdata = buf;
 | 
				
			||||||
 | 
						unsigned char* enddata = NULL;
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						int mylen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
						header.byte = readChar(&curdata);
 | 
				
			||||||
 | 
						*dup = header.bits.dup;
 | 
				
			||||||
 | 
						*packettype = header.bits.type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
 | 
				
			||||||
 | 
						enddata = curdata + mylen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (enddata - curdata < 2)
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
						*packetid = readInt(&curdata);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = 1;
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						FUNC_EXIT_RC(rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,262 @@
 | 
				
			||||||
 | 
					/*******************************************************************************
 | 
				
			||||||
 | 
					 * Copyright (c) 2014 IBM Corp.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All rights reserved. This program and the accompanying materials
 | 
				
			||||||
 | 
					 * are made available under the terms of the Eclipse Public License v1.0
 | 
				
			||||||
 | 
					 * and Eclipse Distribution License v1.0 which accompany this distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Eclipse Public License is available at
 | 
				
			||||||
 | 
					 *    http://www.eclipse.org/legal/epl-v10.html
 | 
				
			||||||
 | 
					 * and the Eclipse Distribution License is available at
 | 
				
			||||||
 | 
					 *   http://www.eclipse.org/org/documents/edl-v10.php.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contributors:
 | 
				
			||||||
 | 
					 *    Ian Craggs - initial API and implementation and/or initial documentation
 | 
				
			||||||
 | 
					 *******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "StackTrace.h"
 | 
				
			||||||
 | 
					#include "MQTTPacket.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char* MQTTPacket_names[] =
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						"RESERVED", "CONNECT", "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL",
 | 
				
			||||||
 | 
						"PUBCOMP", "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK",
 | 
				
			||||||
 | 
						"PINGREQ", "PINGRESP", "DISCONNECT"
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char* MQTTPacket_getName(unsigned short packetid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return MQTTPacket_names[packetid];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int MQTTStringFormat_connect(char* strbuf, int strbuflen, MQTTPacket_connectData* data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int strindex = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						strindex = snprintf(strbuf, strbuflen,
 | 
				
			||||||
 | 
								"CONNECT MQTT version %d, client id %.*s, clean session %d, keep alive %d",
 | 
				
			||||||
 | 
								(int)data->MQTTVersion, data->clientID.lenstring.len, data->clientID.lenstring.data,
 | 
				
			||||||
 | 
								(int)data->cleansession, data->keepAliveInterval);
 | 
				
			||||||
 | 
						if (data->willFlag)
 | 
				
			||||||
 | 
							strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
 | 
				
			||||||
 | 
									", will QoS %d, will retain %d, will topic %.*s, will message %.*s",
 | 
				
			||||||
 | 
									data->will.qos, data->will.retained,
 | 
				
			||||||
 | 
									data->will.topicName.lenstring.len, data->will.topicName.lenstring.data,
 | 
				
			||||||
 | 
									data->will.message.lenstring.len, data->will.message.lenstring.data);
 | 
				
			||||||
 | 
						if (data->username.lenstring.data && data->username.lenstring.len > 0)
 | 
				
			||||||
 | 
							strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
 | 
				
			||||||
 | 
									", user name %.*s", data->username.lenstring.len, data->username.lenstring.data);
 | 
				
			||||||
 | 
						if (data->password.lenstring.data && data->password.lenstring.len > 0)
 | 
				
			||||||
 | 
							strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
 | 
				
			||||||
 | 
									", password %.*s", data->password.lenstring.len, data->password.lenstring.data);
 | 
				
			||||||
 | 
						return strindex;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int MQTTStringFormat_connack(char* strbuf, int strbuflen, unsigned char connack_rc, unsigned char sessionPresent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int strindex = snprintf(strbuf, strbuflen, "CONNACK session present %d, rc %d", sessionPresent, connack_rc);
 | 
				
			||||||
 | 
						return strindex;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int MQTTStringFormat_publish(char* strbuf, int strbuflen, unsigned char dup, int qos, unsigned char retained,
 | 
				
			||||||
 | 
							unsigned short packetid, MQTTString topicName, unsigned char* payload, int payloadlen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int strindex = snprintf(strbuf, strbuflen,
 | 
				
			||||||
 | 
									"PUBLISH dup %d, QoS %d, retained %d, packet id %d, topic %.*s, payload length %d, payload %.*s",
 | 
				
			||||||
 | 
									dup, qos, retained, packetid,
 | 
				
			||||||
 | 
									(topicName.lenstring.len < 20) ? topicName.lenstring.len : 20, topicName.lenstring.data,
 | 
				
			||||||
 | 
									payloadlen, (payloadlen < 20) ? payloadlen : 20, payload);
 | 
				
			||||||
 | 
						return strindex;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int MQTTStringFormat_ack(char* strbuf, int strbuflen, unsigned char packettype, unsigned char dup, unsigned short packetid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int strindex = snprintf(strbuf, strbuflen, "%s, packet id %d", MQTTPacket_names[packettype], packetid);
 | 
				
			||||||
 | 
						if (dup)
 | 
				
			||||||
 | 
							strindex += snprintf(strbuf + strindex, strbuflen - strindex, ", dup %d", dup);
 | 
				
			||||||
 | 
						return strindex;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int MQTTStringFormat_subscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, int count,
 | 
				
			||||||
 | 
							MQTTString topicFilters[], int requestedQoSs[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return snprintf(strbuf, strbuflen,
 | 
				
			||||||
 | 
							"SUBSCRIBE dup %d, packet id %d count %d topic %.*s qos %d",
 | 
				
			||||||
 | 
							dup, packetid, count,
 | 
				
			||||||
 | 
							topicFilters[0].lenstring.len, topicFilters[0].lenstring.data,
 | 
				
			||||||
 | 
							requestedQoSs[0]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int MQTTStringFormat_suback(char* strbuf, int strbuflen, unsigned short packetid, int count, int* grantedQoSs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return snprintf(strbuf, strbuflen,
 | 
				
			||||||
 | 
							"SUBACK packet id %d count %d granted qos %d", packetid, count, grantedQoSs[0]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int MQTTStringFormat_unsubscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid,
 | 
				
			||||||
 | 
							int count, MQTTString topicFilters[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return snprintf(strbuf, strbuflen,
 | 
				
			||||||
 | 
										"UNSUBSCRIBE dup %d, packet id %d count %d topic %.*s",
 | 
				
			||||||
 | 
										dup, packetid, count,
 | 
				
			||||||
 | 
										topicFilters[0].lenstring.len, topicFilters[0].lenstring.data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(MQTT_CLIENT)
 | 
				
			||||||
 | 
					char* MQTTFormat_toClientString(char* strbuf, int strbuflen, unsigned char* buf, int buflen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int index = 0;
 | 
				
			||||||
 | 
						int rem_length = 0;
 | 
				
			||||||
 | 
						MQTTHeader header = {0};
 | 
				
			||||||
 | 
						int strindex = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						header.byte = buf[index++];
 | 
				
			||||||
 | 
						index += MQTTPacket_decodeBuf(&buf[index], &rem_length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (header.bits.type)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case CONNACK:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							unsigned char sessionPresent, connack_rc;
 | 
				
			||||||
 | 
							if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) == 1)
 | 
				
			||||||
 | 
								strindex = MQTTStringFormat_connack(strbuf, strbuflen, connack_rc, sessionPresent);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
						case PUBLISH:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							unsigned char dup, retained, *payload;
 | 
				
			||||||
 | 
							unsigned short packetid;
 | 
				
			||||||
 | 
							int qos, payloadlen;
 | 
				
			||||||
 | 
							MQTTString topicName = MQTTString_initializer;
 | 
				
			||||||
 | 
							if (MQTTDeserialize_publish(&dup, &qos, &retained, &packetid, &topicName,
 | 
				
			||||||
 | 
									&payload, &payloadlen, buf, buflen) == 1)
 | 
				
			||||||
 | 
								strindex = MQTTStringFormat_publish(strbuf, strbuflen, dup, qos, retained, packetid,
 | 
				
			||||||
 | 
										topicName, payload, payloadlen);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
						case PUBACK:
 | 
				
			||||||
 | 
						case PUBREC:
 | 
				
			||||||
 | 
						case PUBREL:
 | 
				
			||||||
 | 
						case PUBCOMP:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							unsigned char packettype, dup;
 | 
				
			||||||
 | 
							unsigned short packetid;
 | 
				
			||||||
 | 
							if (MQTTDeserialize_ack(&packettype, &dup, &packetid, buf, buflen) == 1)
 | 
				
			||||||
 | 
								strindex = MQTTStringFormat_ack(strbuf, strbuflen, packettype, dup, packetid);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
						case SUBACK:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							unsigned short packetid;
 | 
				
			||||||
 | 
							int maxcount = 1, count = 0;
 | 
				
			||||||
 | 
							int grantedQoSs[1];
 | 
				
			||||||
 | 
							if (MQTTDeserialize_suback(&packetid, maxcount, &count, grantedQoSs, buf, buflen) == 1)
 | 
				
			||||||
 | 
								strindex = MQTTStringFormat_suback(strbuf, strbuflen, packetid, count, grantedQoSs);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
						case UNSUBACK:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							unsigned short packetid;
 | 
				
			||||||
 | 
							if (MQTTDeserialize_unsuback(&packetid, buf, buflen) == 1)
 | 
				
			||||||
 | 
								strindex = MQTTStringFormat_ack(strbuf, strbuflen, UNSUBACK, 0, packetid);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
						case PINGREQ:
 | 
				
			||||||
 | 
						case PINGRESP:
 | 
				
			||||||
 | 
						case DISCONNECT:
 | 
				
			||||||
 | 
							strindex = snprintf(strbuf, strbuflen, "%s", MQTTPacket_names[header.bits.type]);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return strbuf;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(MQTT_SERVER)
 | 
				
			||||||
 | 
					char* MQTTFormat_toServerString(char* strbuf, int strbuflen, unsigned char* buf, int buflen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int index = 0;
 | 
				
			||||||
 | 
						int rem_length = 0;
 | 
				
			||||||
 | 
						MQTTHeader header = {0};
 | 
				
			||||||
 | 
						int strindex = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						header.byte = buf[index++];
 | 
				
			||||||
 | 
						index += MQTTPacket_decodeBuf(&buf[index], &rem_length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (header.bits.type)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						case CONNECT:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							MQTTPacket_connectData data;
 | 
				
			||||||
 | 
							int rc;
 | 
				
			||||||
 | 
							if ((rc = MQTTDeserialize_connect(&data, buf, buflen)) == 1)
 | 
				
			||||||
 | 
								strindex = MQTTStringFormat_connect(strbuf, strbuflen, &data);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
						case PUBLISH:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							unsigned char dup, retained, *payload;
 | 
				
			||||||
 | 
							unsigned short packetid;
 | 
				
			||||||
 | 
							int qos, payloadlen;
 | 
				
			||||||
 | 
							MQTTString topicName = MQTTString_initializer;
 | 
				
			||||||
 | 
							if (MQTTDeserialize_publish(&dup, &qos, &retained, &packetid, &topicName,
 | 
				
			||||||
 | 
									&payload, &payloadlen, buf, buflen) == 1)
 | 
				
			||||||
 | 
								strindex = MQTTStringFormat_publish(strbuf, strbuflen, dup, qos, retained, packetid,
 | 
				
			||||||
 | 
										topicName, payload, payloadlen);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
						case PUBACK:
 | 
				
			||||||
 | 
						case PUBREC:
 | 
				
			||||||
 | 
						case PUBREL:
 | 
				
			||||||
 | 
						case PUBCOMP:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							unsigned char packettype, dup;
 | 
				
			||||||
 | 
							unsigned short packetid;
 | 
				
			||||||
 | 
							if (MQTTDeserialize_ack(&packettype, &dup, &packetid, buf, buflen) == 1)
 | 
				
			||||||
 | 
								strindex = MQTTStringFormat_ack(strbuf, strbuflen, packettype, dup, packetid);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
						case SUBSCRIBE:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							unsigned char dup;
 | 
				
			||||||
 | 
							unsigned short packetid;
 | 
				
			||||||
 | 
							int maxcount = 1, count = 0;
 | 
				
			||||||
 | 
							MQTTString topicFilters[1];
 | 
				
			||||||
 | 
							int requestedQoSs[1];
 | 
				
			||||||
 | 
							if (MQTTDeserialize_subscribe(&dup, &packetid, maxcount, &count,
 | 
				
			||||||
 | 
									topicFilters, requestedQoSs, buf, buflen) == 1)
 | 
				
			||||||
 | 
								strindex = MQTTStringFormat_subscribe(strbuf, strbuflen, dup, packetid, count, topicFilters, requestedQoSs);;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
						case UNSUBSCRIBE:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							unsigned char dup;
 | 
				
			||||||
 | 
							unsigned short packetid;
 | 
				
			||||||
 | 
							int maxcount = 1, count = 0;
 | 
				
			||||||
 | 
							MQTTString topicFilters[1];
 | 
				
			||||||
 | 
							if (MQTTDeserialize_unsubscribe(&dup, &packetid, maxcount, &count, topicFilters, buf, buflen) == 1)
 | 
				
			||||||
 | 
								strindex =  MQTTStringFormat_unsubscribe(strbuf, strbuflen, dup, packetid, count, topicFilters);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
						case PINGREQ:
 | 
				
			||||||
 | 
						case PINGRESP:
 | 
				
			||||||
 | 
						case DISCONNECT:
 | 
				
			||||||
 | 
							strindex = snprintf(strbuf, strbuflen, "%s", MQTTPacket_names[header.bits.type]);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						strbuf[strbuflen] = '\0';
 | 
				
			||||||
 | 
						return strbuf;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,37 @@
 | 
				
			||||||
 | 
					/*******************************************************************************
 | 
				
			||||||
 | 
					 * Copyright (c) 2014 IBM Corp.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All rights reserved. This program and the accompanying materials
 | 
				
			||||||
 | 
					 * are made available under the terms of the Eclipse Public License v1.0
 | 
				
			||||||
 | 
					 * and Eclipse Distribution License v1.0 which accompany this distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Eclipse Public License is available at
 | 
				
			||||||
 | 
					 *    http://www.eclipse.org/legal/epl-v10.html
 | 
				
			||||||
 | 
					 * and the Eclipse Distribution License is available at
 | 
				
			||||||
 | 
					 *   http://www.eclipse.org/org/documents/edl-v10.php.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contributors:
 | 
				
			||||||
 | 
					 *    Ian Craggs - initial API and implementation and/or initial documentation
 | 
				
			||||||
 | 
					 *******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if !defined(MQTTFORMAT_H)
 | 
				
			||||||
 | 
					#define MQTTFORMAT_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "StackTrace.h"
 | 
				
			||||||
 | 
					#include "MQTTPacket.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char* MQTTPacket_getName(unsigned short packetid);
 | 
				
			||||||
 | 
					int MQTTStringFormat_connect(char* strbuf, int strbuflen, MQTTPacket_connectData* data);
 | 
				
			||||||
 | 
					int MQTTStringFormat_connack(char* strbuf, int strbuflen, unsigned char connack_rc, unsigned char sessionPresent);
 | 
				
			||||||
 | 
					int MQTTStringFormat_publish(char* strbuf, int strbuflen, unsigned char dup, int qos, unsigned char retained,
 | 
				
			||||||
 | 
							unsigned short packetid, MQTTString topicName, unsigned char* payload, int payloadlen);
 | 
				
			||||||
 | 
					int MQTTStringFormat_ack(char* strbuf, int strbuflen, unsigned char packettype, unsigned char dup, unsigned short packetid);
 | 
				
			||||||
 | 
					int MQTTStringFormat_subscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, int count,
 | 
				
			||||||
 | 
							MQTTString topicFilters[], int requestedQoSs[]);
 | 
				
			||||||
 | 
					int MQTTStringFormat_suback(char* strbuf, int strbuflen, unsigned short packetid, int count, int* grantedQoSs);
 | 
				
			||||||
 | 
					int MQTTStringFormat_unsubscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid,
 | 
				
			||||||
 | 
							int count, MQTTString topicFilters[]);
 | 
				
			||||||
 | 
					char* MQTTFormat_toClientString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);
 | 
				
			||||||
 | 
					char* MQTTFormat_toServerString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,412 @@
 | 
				
			||||||
 | 
					/*******************************************************************************
 | 
				
			||||||
 | 
					 * Copyright (c) 2014 IBM Corp.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All rights reserved. This program and the accompanying materials
 | 
				
			||||||
 | 
					 * are made available under the terms of the Eclipse Public License v1.0
 | 
				
			||||||
 | 
					 * and Eclipse Distribution License v1.0 which accompany this distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Eclipse Public License is available at
 | 
				
			||||||
 | 
					 *    http://www.eclipse.org/legal/epl-v10.html
 | 
				
			||||||
 | 
					 * and the Eclipse Distribution License is available at
 | 
				
			||||||
 | 
					 *   http://www.eclipse.org/org/documents/edl-v10.php.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contributors:
 | 
				
			||||||
 | 
					 *    Ian Craggs - initial API and implementation and/or initial documentation
 | 
				
			||||||
 | 
					 *    Sergio R. Caprile - non-blocking packet read functions for stream transport
 | 
				
			||||||
 | 
					 *******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "StackTrace.h"
 | 
				
			||||||
 | 
					#include "MQTTPacket.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Encodes the message length according to the MQTT algorithm
 | 
				
			||||||
 | 
					 * @param buf the buffer into which the encoded data is written
 | 
				
			||||||
 | 
					 * @param length the length to be encoded
 | 
				
			||||||
 | 
					 * @return the number of bytes written to buffer
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int MQTTPacket_encode(unsigned char* buf, int length)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
						do
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							char d = length % 128;
 | 
				
			||||||
 | 
							length /= 128;
 | 
				
			||||||
 | 
							/* if there are more digits to encode, set the top bit of this digit */
 | 
				
			||||||
 | 
							if (length > 0)
 | 
				
			||||||
 | 
								d |= 0x80;
 | 
				
			||||||
 | 
							buf[rc++] = d;
 | 
				
			||||||
 | 
						} while (length > 0);
 | 
				
			||||||
 | 
						FUNC_EXIT_RC(rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Decodes the message length according to the MQTT algorithm
 | 
				
			||||||
 | 
					 * @param getcharfn pointer to function to read the next character from the data source
 | 
				
			||||||
 | 
					 * @param value the decoded length returned
 | 
				
			||||||
 | 
					 * @return the number of bytes read from the socket
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned char c;
 | 
				
			||||||
 | 
						int multiplier = 1;
 | 
				
			||||||
 | 
						int len = 0;
 | 
				
			||||||
 | 
					#define MAX_NO_OF_REMAINING_LENGTH_BYTES 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
						*value = 0;
 | 
				
			||||||
 | 
						do
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							int rc = MQTTPACKET_READ_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								rc = MQTTPACKET_READ_ERROR;	/* bad data */
 | 
				
			||||||
 | 
								goto exit;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							rc = (*getcharfn)(&c, 1);
 | 
				
			||||||
 | 
							if (rc != 1)
 | 
				
			||||||
 | 
								goto exit;
 | 
				
			||||||
 | 
							*value += (c & 127) * multiplier;
 | 
				
			||||||
 | 
							multiplier *= 128;
 | 
				
			||||||
 | 
						} while ((c & 128) != 0);
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						FUNC_EXIT_RC(len);
 | 
				
			||||||
 | 
						return len;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int MQTTPacket_len(int rem_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						rem_len += 1; /* header byte */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* now remaining_length field */
 | 
				
			||||||
 | 
						if (rem_len < 128)
 | 
				
			||||||
 | 
							rem_len += 1;
 | 
				
			||||||
 | 
						else if (rem_len < 16384)
 | 
				
			||||||
 | 
							rem_len += 2;
 | 
				
			||||||
 | 
						else if (rem_len < 2097151)
 | 
				
			||||||
 | 
							rem_len += 3;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							rem_len += 4;
 | 
				
			||||||
 | 
						return rem_len;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static unsigned char* bufptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int bufchar(unsigned char* c, int count)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < count; ++i)
 | 
				
			||||||
 | 
							*c = *bufptr++;
 | 
				
			||||||
 | 
						return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int MQTTPacket_decodeBuf(unsigned char* buf, int* value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						bufptr = buf;
 | 
				
			||||||
 | 
						return MQTTPacket_decode(bufchar, value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Calculates an integer from two bytes read from the input buffer
 | 
				
			||||||
 | 
					 * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
 | 
				
			||||||
 | 
					 * @return the integer value calculated
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int readInt(unsigned char** pptr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned char* ptr = *pptr;
 | 
				
			||||||
 | 
						int len = 256*(*ptr) + (*(ptr+1));
 | 
				
			||||||
 | 
						*pptr += 2;
 | 
				
			||||||
 | 
						return len;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Reads one character from the input buffer.
 | 
				
			||||||
 | 
					 * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
 | 
				
			||||||
 | 
					 * @return the character read
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					char readChar(unsigned char** pptr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char c = **pptr;
 | 
				
			||||||
 | 
						(*pptr)++;
 | 
				
			||||||
 | 
						return c;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Writes one character to an output buffer.
 | 
				
			||||||
 | 
					 * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
 | 
				
			||||||
 | 
					 * @param c the character to write
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void writeChar(unsigned char** pptr, char c)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						**pptr = c;
 | 
				
			||||||
 | 
						(*pptr)++;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Writes an integer as 2 bytes to an output buffer.
 | 
				
			||||||
 | 
					 * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
 | 
				
			||||||
 | 
					 * @param anInt the integer to write
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void writeInt(unsigned char** pptr, int anInt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						**pptr = (unsigned char)(anInt / 256);
 | 
				
			||||||
 | 
						(*pptr)++;
 | 
				
			||||||
 | 
						**pptr = (unsigned char)(anInt % 256);
 | 
				
			||||||
 | 
						(*pptr)++;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Writes a "UTF" string to an output buffer.  Converts C string to length-delimited.
 | 
				
			||||||
 | 
					 * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
 | 
				
			||||||
 | 
					 * @param string the C string to write
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void writeCString(unsigned char** pptr, const char* string)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int len = strlen(string);
 | 
				
			||||||
 | 
						writeInt(pptr, len);
 | 
				
			||||||
 | 
						memcpy(*pptr, string, len);
 | 
				
			||||||
 | 
						*pptr += len;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int getLenStringLen(char* ptr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int len = 256*((unsigned char)(*ptr)) + (unsigned char)(*(ptr+1));
 | 
				
			||||||
 | 
						return len;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void writeMQTTString(unsigned char** pptr, MQTTString mqttstring)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (mqttstring.lenstring.len > 0)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							writeInt(pptr, mqttstring.lenstring.len);
 | 
				
			||||||
 | 
							memcpy(*pptr, mqttstring.lenstring.data, mqttstring.lenstring.len);
 | 
				
			||||||
 | 
							*pptr += mqttstring.lenstring.len;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else if (mqttstring.cstring)
 | 
				
			||||||
 | 
							writeCString(pptr, mqttstring.cstring);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							writeInt(pptr, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @param mqttstring the MQTTString structure into which the data is to be read
 | 
				
			||||||
 | 
					 * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
 | 
				
			||||||
 | 
					 * @param enddata pointer to the end of the data: do not read beyond
 | 
				
			||||||
 | 
					 * @return 1 if successful, 0 if not
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
						/* the first two bytes are the length of the string */
 | 
				
			||||||
 | 
						if (enddata - (*pptr) > 1) /* enough length to read the integer? */
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							mqttstring->lenstring.len = readInt(pptr); /* increments pptr to point past length */
 | 
				
			||||||
 | 
							if (&(*pptr)[mqttstring->lenstring.len] <= enddata)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								mqttstring->lenstring.data = (char*)*pptr;
 | 
				
			||||||
 | 
								*pptr += mqttstring->lenstring.len;
 | 
				
			||||||
 | 
								rc = 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						mqttstring->cstring = NULL;
 | 
				
			||||||
 | 
						FUNC_EXIT_RC(rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Return the length of the MQTTstring - C string if there is one, otherwise the length delimited string
 | 
				
			||||||
 | 
					 * @param mqttstring the string to return the length of
 | 
				
			||||||
 | 
					 * @return the length of the string
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int MQTTstrlen(MQTTString mqttstring)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mqttstring.cstring)
 | 
				
			||||||
 | 
							rc = strlen(mqttstring.cstring);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							rc = mqttstring.lenstring.len;
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Compares an MQTTString to a C string
 | 
				
			||||||
 | 
					 * @param a the MQTTString to compare
 | 
				
			||||||
 | 
					 * @param bptr the C string to compare
 | 
				
			||||||
 | 
					 * @return boolean - equal or not
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int MQTTPacket_equals(MQTTString* a, char* bptr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int alen = 0,
 | 
				
			||||||
 | 
							blen = 0;
 | 
				
			||||||
 | 
						char *aptr;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if (a->cstring)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							aptr = a->cstring;
 | 
				
			||||||
 | 
							alen = strlen(a->cstring);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							aptr = a->lenstring.data;
 | 
				
			||||||
 | 
							alen = a->lenstring.len;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						blen = strlen(bptr);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						return (alen == blen) && (strncmp(aptr, bptr, alen) == 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Helper function to read packet data from some source into a buffer
 | 
				
			||||||
 | 
					 * @param buf the buffer into which the packet will be serialized
 | 
				
			||||||
 | 
					 * @param buflen the length in bytes of the supplied buffer
 | 
				
			||||||
 | 
					 * @param getfn pointer to a function which will read any number of bytes from the needed source
 | 
				
			||||||
 | 
					 * @return integer MQTT packet type, or -1 on error
 | 
				
			||||||
 | 
					 * @note  the whole message must fit into the caller's buffer
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int))
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc = -1;
 | 
				
			||||||
 | 
						MQTTHeader header = {0};
 | 
				
			||||||
 | 
						int len = 0;
 | 
				
			||||||
 | 
						int rem_len = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* 1. read the header byte.  This has the packet type in it */
 | 
				
			||||||
 | 
						if ((*getfn)(buf, 1) != 1)
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						len = 1;
 | 
				
			||||||
 | 
						/* 2. read the remaining length.  This is variable in itself */
 | 
				
			||||||
 | 
						MQTTPacket_decode(getfn, &rem_len);
 | 
				
			||||||
 | 
						len += MQTTPacket_encode(buf + 1, rem_len); /* put the original remaining length back into the buffer */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* 3. read the rest of the buffer using a callback to supply the rest of the data */
 | 
				
			||||||
 | 
						if((rem_len + len) > buflen)
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
						if (rem_len && ((*getfn)(buf + len, rem_len) != rem_len))
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						header.byte = buf[0];
 | 
				
			||||||
 | 
						rc = header.bits.type;
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Decodes the message length according to the MQTT algorithm, non-blocking
 | 
				
			||||||
 | 
					 * @param trp pointer to a transport structure holding what is needed to solve getting data from it
 | 
				
			||||||
 | 
					 * @param value the decoded length returned
 | 
				
			||||||
 | 
					 * @return integer the number of bytes read from the socket, 0 for call again, or -1 on error
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int MQTTPacket_decodenb(MQTTTransport *trp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned char c;
 | 
				
			||||||
 | 
						int rc = MQTTPACKET_READ_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
						if(trp->len == 0){		/* initialize on first call */
 | 
				
			||||||
 | 
							trp->multiplier = 1;
 | 
				
			||||||
 | 
							trp->rem_len = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						do {
 | 
				
			||||||
 | 
							int frc;
 | 
				
			||||||
 | 
							if (trp->len >= MAX_NO_OF_REMAINING_LENGTH_BYTES)
 | 
				
			||||||
 | 
								goto exit;
 | 
				
			||||||
 | 
							if ((frc=(*trp->getfn)(trp->sck, &c, 1)) == -1)
 | 
				
			||||||
 | 
								goto exit;
 | 
				
			||||||
 | 
							if (frc == 0){
 | 
				
			||||||
 | 
								rc = 0;
 | 
				
			||||||
 | 
								goto exit;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							++(trp->len);
 | 
				
			||||||
 | 
							trp->rem_len += (c & 127) * trp->multiplier;
 | 
				
			||||||
 | 
							trp->multiplier *= 128;
 | 
				
			||||||
 | 
						} while ((c & 128) != 0);
 | 
				
			||||||
 | 
						rc = trp->len;
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						FUNC_EXIT_RC(rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Helper function to read packet data from some source into a buffer, non-blocking
 | 
				
			||||||
 | 
					 * @param buf the buffer into which the packet will be serialized
 | 
				
			||||||
 | 
					 * @param buflen the length in bytes of the supplied buffer
 | 
				
			||||||
 | 
					 * @param trp pointer to a transport structure holding what is needed to solve getting data from it
 | 
				
			||||||
 | 
					 * @return integer MQTT packet type, 0 for call again, or -1 on error
 | 
				
			||||||
 | 
					 * @note  the whole message must fit into the caller's buffer
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc = -1, frc;
 | 
				
			||||||
 | 
						MQTTHeader header = {0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch(trp->state){
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							trp->state = 0;
 | 
				
			||||||
 | 
							/*FALLTHROUGH*/
 | 
				
			||||||
 | 
						case 0:
 | 
				
			||||||
 | 
							/* read the header byte.  This has the packet type in it */
 | 
				
			||||||
 | 
							if ((frc=(*trp->getfn)(trp->sck, buf, 1)) == -1)
 | 
				
			||||||
 | 
								goto exit;
 | 
				
			||||||
 | 
							if (frc == 0)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							trp->len = 0;
 | 
				
			||||||
 | 
							++trp->state;
 | 
				
			||||||
 | 
							/*FALLTHROUGH*/
 | 
				
			||||||
 | 
							/* read the remaining length.  This is variable in itself */
 | 
				
			||||||
 | 
						case 1:
 | 
				
			||||||
 | 
							if((frc=MQTTPacket_decodenb(trp)) == MQTTPACKET_READ_ERROR)
 | 
				
			||||||
 | 
								goto exit;
 | 
				
			||||||
 | 
							if(frc == 0)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							trp->len = 1 + MQTTPacket_encode(buf + 1, trp->rem_len); /* put the original remaining length back into the buffer */
 | 
				
			||||||
 | 
							if((trp->rem_len + trp->len) > buflen)
 | 
				
			||||||
 | 
								goto exit;
 | 
				
			||||||
 | 
							++trp->state;
 | 
				
			||||||
 | 
							/*FALLTHROUGH*/
 | 
				
			||||||
 | 
						case 2:
 | 
				
			||||||
 | 
							if(trp->rem_len){
 | 
				
			||||||
 | 
								/* read the rest of the buffer using a callback to supply the rest of the data */
 | 
				
			||||||
 | 
								if ((frc=(*trp->getfn)(trp->sck, buf + trp->len, trp->rem_len)) == -1)
 | 
				
			||||||
 | 
									goto exit;
 | 
				
			||||||
 | 
								if (frc == 0)
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
								trp->rem_len -= frc;
 | 
				
			||||||
 | 
								trp->len += frc;
 | 
				
			||||||
 | 
								if(trp->rem_len)
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							header.byte = buf[0];
 | 
				
			||||||
 | 
							rc = header.bits.type;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						trp->state = 0;
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,134 @@
 | 
				
			||||||
 | 
					/*******************************************************************************
 | 
				
			||||||
 | 
					 * Copyright (c) 2014 IBM Corp.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All rights reserved. This program and the accompanying materials
 | 
				
			||||||
 | 
					 * are made available under the terms of the Eclipse Public License v1.0
 | 
				
			||||||
 | 
					 * and Eclipse Distribution License v1.0 which accompany this distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Eclipse Public License is available at
 | 
				
			||||||
 | 
					 *    http://www.eclipse.org/legal/epl-v10.html
 | 
				
			||||||
 | 
					 * and the Eclipse Distribution License is available at
 | 
				
			||||||
 | 
					 *   http://www.eclipse.org/org/documents/edl-v10.php.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contributors:
 | 
				
			||||||
 | 
					 *    Ian Craggs - initial API and implementation and/or initial documentation
 | 
				
			||||||
 | 
					 *    Xiang Rong - 442039 Add makefile to Embedded C client
 | 
				
			||||||
 | 
					 *******************************************************************************/
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef MQTTPACKET_H_
 | 
				
			||||||
 | 
					#define MQTTPACKET_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(WIN32_DLL) || defined(WIN64_DLL)
 | 
				
			||||||
 | 
					  #define DLLImport __declspec(dllimport)
 | 
				
			||||||
 | 
					  #define DLLExport __declspec(dllexport)
 | 
				
			||||||
 | 
					#elif defined(LINUX_SO)
 | 
				
			||||||
 | 
					  #define DLLImport extern
 | 
				
			||||||
 | 
					  #define DLLExport  __attribute__ ((visibility ("default")))
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					  #define DLLImport
 | 
				
			||||||
 | 
					  #define DLLExport  
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum errors
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						MQTTPACKET_BUFFER_TOO_SHORT = -2,
 | 
				
			||||||
 | 
						MQTTPACKET_READ_ERROR = -1,
 | 
				
			||||||
 | 
						MQTTPACKET_READ_COMPLETE
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum msgTypes
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						CONNECT = 1, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL,
 | 
				
			||||||
 | 
						PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK,
 | 
				
			||||||
 | 
						PINGREQ, PINGRESP, DISCONNECT
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Bitfields for the MQTT header byte.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef union
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned char byte;	                /**< the whole byte */
 | 
				
			||||||
 | 
					#if defined(REVERSED)
 | 
				
			||||||
 | 
						struct
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							unsigned int type : 4;			/**< message type nibble */
 | 
				
			||||||
 | 
							unsigned int dup : 1;				/**< DUP flag bit */
 | 
				
			||||||
 | 
							unsigned int qos : 2;				/**< QoS value, 0, 1 or 2 */
 | 
				
			||||||
 | 
							unsigned int retain : 1;		/**< retained flag bit */
 | 
				
			||||||
 | 
						} bits;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						struct
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							unsigned int retain : 1;		/**< retained flag bit */
 | 
				
			||||||
 | 
							unsigned int qos : 2;				/**< QoS value, 0, 1 or 2 */
 | 
				
			||||||
 | 
							unsigned int dup : 1;				/**< DUP flag bit */
 | 
				
			||||||
 | 
							unsigned int type : 4;			/**< message type nibble */
 | 
				
			||||||
 | 
						} bits;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					} MQTTHeader;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int len;
 | 
				
			||||||
 | 
						char* data;
 | 
				
			||||||
 | 
					} MQTTLenString;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char* cstring;
 | 
				
			||||||
 | 
						MQTTLenString lenstring;
 | 
				
			||||||
 | 
					} MQTTString;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MQTTString_initializer {NULL, {0, NULL}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int MQTTstrlen(MQTTString mqttstring);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "MQTTConnect.h"
 | 
				
			||||||
 | 
					#include "MQTTPublish.h"
 | 
				
			||||||
 | 
					#include "MQTTSubscribe.h"
 | 
				
			||||||
 | 
					#include "MQTTUnsubscribe.h"
 | 
				
			||||||
 | 
					#include "MQTTFormat.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DLLExport int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char type, unsigned char dup, unsigned short packetid);
 | 
				
			||||||
 | 
					DLLExport int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int MQTTPacket_len(int rem_len);
 | 
				
			||||||
 | 
					DLLExport int MQTTPacket_equals(MQTTString* a, char* b);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DLLExport int MQTTPacket_encode(unsigned char* buf, int length);
 | 
				
			||||||
 | 
					int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value);
 | 
				
			||||||
 | 
					int MQTTPacket_decodeBuf(unsigned char* buf, int* value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int readInt(unsigned char** pptr);
 | 
				
			||||||
 | 
					char readChar(unsigned char** pptr);
 | 
				
			||||||
 | 
					void writeChar(unsigned char** pptr, char c);
 | 
				
			||||||
 | 
					void writeInt(unsigned char** pptr, int anInt);
 | 
				
			||||||
 | 
					int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata);
 | 
				
			||||||
 | 
					void writeCString(unsigned char** pptr, const char* string);
 | 
				
			||||||
 | 
					void writeMQTTString(unsigned char** pptr, MQTTString mqttstring);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DLLExport int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
						int (*getfn)(void *, unsigned char*, int); /* must return -1 for error, 0 for call again, or the number of bytes read */
 | 
				
			||||||
 | 
						void *sck;	/* pointer to whatever the system may use to identify the transport */
 | 
				
			||||||
 | 
						int multiplier;
 | 
				
			||||||
 | 
						int rem_len;
 | 
				
			||||||
 | 
						int len;
 | 
				
			||||||
 | 
						char state;
 | 
				
			||||||
 | 
					}MQTTTransport;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* MQTTPACKET_H_ */
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,38 @@
 | 
				
			||||||
 | 
					/*******************************************************************************
 | 
				
			||||||
 | 
					 * Copyright (c) 2014 IBM Corp.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All rights reserved. This program and the accompanying materials
 | 
				
			||||||
 | 
					 * are made available under the terms of the Eclipse Public License v1.0
 | 
				
			||||||
 | 
					 * and Eclipse Distribution License v1.0 which accompany this distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Eclipse Public License is available at
 | 
				
			||||||
 | 
					 *    http://www.eclipse.org/legal/epl-v10.html
 | 
				
			||||||
 | 
					 * and the Eclipse Distribution License is available at
 | 
				
			||||||
 | 
					 *   http://www.eclipse.org/org/documents/edl-v10.php.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contributors:
 | 
				
			||||||
 | 
					 *    Ian Craggs - initial API and implementation and/or initial documentation
 | 
				
			||||||
 | 
					 *    Xiang Rong - 442039 Add makefile to Embedded C client
 | 
				
			||||||
 | 
					 *******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef MQTTPUBLISH_H_
 | 
				
			||||||
 | 
					#define MQTTPUBLISH_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if !defined(DLLImport)
 | 
				
			||||||
 | 
					  #define DLLImport 
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#if !defined(DLLExport)
 | 
				
			||||||
 | 
					  #define DLLExport
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DLLExport int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
 | 
				
			||||||
 | 
							MQTTString topicName, unsigned char* payload, int payloadlen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DLLExport int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName,
 | 
				
			||||||
 | 
							unsigned char** payload, int32_t* payloadlen, unsigned char* buf, int len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DLLExport int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid);
 | 
				
			||||||
 | 
					DLLExport int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid);
 | 
				
			||||||
 | 
					DLLExport int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* MQTTPUBLISH_H_ */
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,169 @@
 | 
				
			||||||
 | 
					/*******************************************************************************
 | 
				
			||||||
 | 
					 * Copyright (c) 2014 IBM Corp.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All rights reserved. This program and the accompanying materials
 | 
				
			||||||
 | 
					 * are made available under the terms of the Eclipse Public License v1.0
 | 
				
			||||||
 | 
					 * and Eclipse Distribution License v1.0 which accompany this distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Eclipse Public License is available at
 | 
				
			||||||
 | 
					 *    http://www.eclipse.org/legal/epl-v10.html
 | 
				
			||||||
 | 
					 * and the Eclipse Distribution License is available at
 | 
				
			||||||
 | 
					 *   http://www.eclipse.org/org/documents/edl-v10.php.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contributors:
 | 
				
			||||||
 | 
					 *    Ian Craggs - initial API and implementation and/or initial documentation
 | 
				
			||||||
 | 
					 *    Ian Craggs - fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=453144
 | 
				
			||||||
 | 
					 *******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "MQTTPacket.h"
 | 
				
			||||||
 | 
					#include "StackTrace.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Determines the length of the MQTT publish packet that would be produced using the supplied parameters
 | 
				
			||||||
 | 
					  * @param qos the MQTT QoS of the publish (packetid is omitted for QoS 0)
 | 
				
			||||||
 | 
					  * @param topicName the topic name to be used in the publish  
 | 
				
			||||||
 | 
					  * @param payloadlen the length of the payload to be sent
 | 
				
			||||||
 | 
					  * @return the length of buffer needed to contain the serialized version of the packet
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTSerialize_publishLength(int qos, MQTTString topicName, int payloadlen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int len = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						len += 2 + MQTTstrlen(topicName) + payloadlen;
 | 
				
			||||||
 | 
						if (qos > 0)
 | 
				
			||||||
 | 
							len += 2; /* packetid */
 | 
				
			||||||
 | 
						return len;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Serializes the supplied publish data into the supplied buffer, ready for sending
 | 
				
			||||||
 | 
					  * @param buf the buffer into which the packet will be serialized
 | 
				
			||||||
 | 
					  * @param buflen the length in bytes of the supplied buffer
 | 
				
			||||||
 | 
					  * @param dup integer - the MQTT dup flag
 | 
				
			||||||
 | 
					  * @param qos integer - the MQTT QoS value
 | 
				
			||||||
 | 
					  * @param retained integer - the MQTT retained flag
 | 
				
			||||||
 | 
					  * @param packetid integer - the MQTT packet identifier
 | 
				
			||||||
 | 
					  * @param topicName MQTTString - the MQTT topic in the publish
 | 
				
			||||||
 | 
					  * @param payload byte buffer - the MQTT publish payload
 | 
				
			||||||
 | 
					  * @param payloadlen integer - the length of the MQTT payload
 | 
				
			||||||
 | 
					  * @return the length of the serialized data.  <= 0 indicates error
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
 | 
				
			||||||
 | 
							MQTTString topicName, unsigned char* payload, int payloadlen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned char *ptr = buf;
 | 
				
			||||||
 | 
						MQTTHeader header = {0};
 | 
				
			||||||
 | 
						int rem_len = 0;
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
						if (MQTTPacket_len(rem_len = MQTTSerialize_publishLength(qos, topicName, payloadlen)) > buflen)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							rc = MQTTPACKET_BUFFER_TOO_SHORT;
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						header.bits.type = PUBLISH;
 | 
				
			||||||
 | 
						header.bits.dup = dup;
 | 
				
			||||||
 | 
						header.bits.qos = qos;
 | 
				
			||||||
 | 
						header.bits.retain = retained;
 | 
				
			||||||
 | 
						writeChar(&ptr, header.byte); /* write header */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						writeMQTTString(&ptr, topicName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (qos > 0)
 | 
				
			||||||
 | 
							writeInt(&ptr, packetid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(ptr, payload, payloadlen);
 | 
				
			||||||
 | 
						ptr += payloadlen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = ptr - buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						FUNC_EXIT_RC(rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Serializes the ack packet into the supplied buffer.
 | 
				
			||||||
 | 
					  * @param buf the buffer into which the packet will be serialized
 | 
				
			||||||
 | 
					  * @param buflen the length in bytes of the supplied buffer
 | 
				
			||||||
 | 
					  * @param type the MQTT packet type
 | 
				
			||||||
 | 
					  * @param dup the MQTT dup flag
 | 
				
			||||||
 | 
					  * @param packetid the MQTT packet identifier
 | 
				
			||||||
 | 
					  * @return serialized length, or error if 0
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char packettype, unsigned char dup, unsigned short packetid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						MQTTHeader header = {0};
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						unsigned char *ptr = buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
						if (buflen < 4)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							rc = MQTTPACKET_BUFFER_TOO_SHORT;
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						header.bits.type = packettype;
 | 
				
			||||||
 | 
						header.bits.dup = dup;
 | 
				
			||||||
 | 
						header.bits.qos = (packettype == PUBREL) ? 1 : 0;
 | 
				
			||||||
 | 
						writeChar(&ptr, header.byte); /* write header */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
 | 
				
			||||||
 | 
						writeInt(&ptr, packetid);
 | 
				
			||||||
 | 
						rc = ptr - buf;
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						FUNC_EXIT_RC(rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Serializes a puback packet into the supplied buffer.
 | 
				
			||||||
 | 
					  * @param buf the buffer into which the packet will be serialized
 | 
				
			||||||
 | 
					  * @param buflen the length in bytes of the supplied buffer
 | 
				
			||||||
 | 
					  * @param packetid integer - the MQTT packet identifier
 | 
				
			||||||
 | 
					  * @return serialized length, or error if 0
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return MQTTSerialize_ack(buf, buflen, PUBACK, 0, packetid);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Serializes a pubrel packet into the supplied buffer.
 | 
				
			||||||
 | 
					  * @param buf the buffer into which the packet will be serialized
 | 
				
			||||||
 | 
					  * @param buflen the length in bytes of the supplied buffer
 | 
				
			||||||
 | 
					  * @param dup integer - the MQTT dup flag
 | 
				
			||||||
 | 
					  * @param packetid integer - the MQTT packet identifier
 | 
				
			||||||
 | 
					  * @return serialized length, or error if 0
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return MQTTSerialize_ack(buf, buflen, PUBREL, dup, packetid);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Serializes a pubrel packet into the supplied buffer.
 | 
				
			||||||
 | 
					  * @param buf the buffer into which the packet will be serialized
 | 
				
			||||||
 | 
					  * @param buflen the length in bytes of the supplied buffer
 | 
				
			||||||
 | 
					  * @param packetid integer - the MQTT packet identifier
 | 
				
			||||||
 | 
					  * @return serialized length, or error if 0
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return MQTTSerialize_ack(buf, buflen, PUBCOMP, 0, packetid);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,39 @@
 | 
				
			||||||
 | 
					/*******************************************************************************
 | 
				
			||||||
 | 
					 * Copyright (c) 2014 IBM Corp.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All rights reserved. This program and the accompanying materials
 | 
				
			||||||
 | 
					 * are made available under the terms of the Eclipse Public License v1.0
 | 
				
			||||||
 | 
					 * and Eclipse Distribution License v1.0 which accompany this distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Eclipse Public License is available at
 | 
				
			||||||
 | 
					 *    http://www.eclipse.org/legal/epl-v10.html
 | 
				
			||||||
 | 
					 * and the Eclipse Distribution License is available at
 | 
				
			||||||
 | 
					 *   http://www.eclipse.org/org/documents/edl-v10.php.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contributors:
 | 
				
			||||||
 | 
					 *    Ian Craggs - initial API and implementation and/or initial documentation
 | 
				
			||||||
 | 
					 *    Xiang Rong - 442039 Add makefile to Embedded C client
 | 
				
			||||||
 | 
					 *******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef MQTTSUBSCRIBE_H_
 | 
				
			||||||
 | 
					#define MQTTSUBSCRIBE_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if !defined(DLLImport)
 | 
				
			||||||
 | 
					  #define DLLImport 
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#if !defined(DLLExport)
 | 
				
			||||||
 | 
					  #define DLLExport
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DLLExport int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
 | 
				
			||||||
 | 
							int count, MQTTString topicFilters[], int32_t requestedQoSs[]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DLLExport int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid,
 | 
				
			||||||
 | 
							int maxcount, int* count, MQTTString topicFilters[], int requestedQoSs[], unsigned char* buf, int len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DLLExport int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DLLExport int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int32_t* count, int32_t grantedQoSs[], unsigned char* buf, int len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* MQTTSUBSCRIBE_H_ */
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,137 @@
 | 
				
			||||||
 | 
					/*******************************************************************************
 | 
				
			||||||
 | 
					 * Copyright (c) 2014 IBM Corp.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All rights reserved. This program and the accompanying materials
 | 
				
			||||||
 | 
					 * are made available under the terms of the Eclipse Public License v1.0
 | 
				
			||||||
 | 
					 * and Eclipse Distribution License v1.0 which accompany this distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Eclipse Public License is available at
 | 
				
			||||||
 | 
					 *    http://www.eclipse.org/legal/epl-v10.html
 | 
				
			||||||
 | 
					 * and the Eclipse Distribution License is available at
 | 
				
			||||||
 | 
					 *   http://www.eclipse.org/org/documents/edl-v10.php.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contributors:
 | 
				
			||||||
 | 
					 *    Ian Craggs - initial API and implementation and/or initial documentation
 | 
				
			||||||
 | 
					 *******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "MQTTPacket.h"
 | 
				
			||||||
 | 
					#include "StackTrace.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Determines the length of the MQTT subscribe packet that would be produced using the supplied parameters
 | 
				
			||||||
 | 
					  * @param count the number of topic filter strings in topicFilters
 | 
				
			||||||
 | 
					  * @param topicFilters the array of topic filter strings to be used in the publish
 | 
				
			||||||
 | 
					  * @return the length of buffer needed to contain the serialized version of the packet
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTSerialize_subscribeLength(int count, MQTTString topicFilters[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						int len = 2; /* packetid */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < count; ++i)
 | 
				
			||||||
 | 
							len += 2 + MQTTstrlen(topicFilters[i]) + 1; /* length + topic + req_qos */
 | 
				
			||||||
 | 
						return len;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Serializes the supplied subscribe data into the supplied buffer, ready for sending
 | 
				
			||||||
 | 
					  * @param buf the buffer into which the packet will be serialized
 | 
				
			||||||
 | 
					  * @param buflen the length in bytes of the supplied bufferr
 | 
				
			||||||
 | 
					  * @param dup integer - the MQTT dup flag
 | 
				
			||||||
 | 
					  * @param packetid integer - the MQTT packet identifier
 | 
				
			||||||
 | 
					  * @param count - number of members in the topicFilters and reqQos arrays
 | 
				
			||||||
 | 
					  * @param topicFilters - array of topic filter names
 | 
				
			||||||
 | 
					  * @param requestedQoSs - array of requested QoS
 | 
				
			||||||
 | 
					  * @return the length of the serialized data.  <= 0 indicates error
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid, int count,
 | 
				
			||||||
 | 
							MQTTString topicFilters[], int32_t requestedQoSs[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned char *ptr = buf;
 | 
				
			||||||
 | 
						MQTTHeader header = {0};
 | 
				
			||||||
 | 
						int rem_len = 0;
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						int i = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
						if (MQTTPacket_len(rem_len = MQTTSerialize_subscribeLength(count, topicFilters)) > buflen)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							rc = MQTTPACKET_BUFFER_TOO_SHORT;
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						header.byte = 0;
 | 
				
			||||||
 | 
						header.bits.type = SUBSCRIBE;
 | 
				
			||||||
 | 
						header.bits.dup = dup;
 | 
				
			||||||
 | 
						header.bits.qos = 1;
 | 
				
			||||||
 | 
						writeChar(&ptr, header.byte); /* write header */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						writeInt(&ptr, packetid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < count; ++i)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							writeMQTTString(&ptr, topicFilters[i]);
 | 
				
			||||||
 | 
							writeChar(&ptr, requestedQoSs[i]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = ptr - buf;
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						FUNC_EXIT_RC(rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Deserializes the supplied (wire) buffer into suback data
 | 
				
			||||||
 | 
					  * @param packetid returned integer - the MQTT packet identifier
 | 
				
			||||||
 | 
					  * @param maxcount - the maximum number of members allowed in the grantedQoSs array
 | 
				
			||||||
 | 
					  * @param count returned integer - number of members in the grantedQoSs array
 | 
				
			||||||
 | 
					  * @param grantedQoSs returned array of integers - the granted qualities of service
 | 
				
			||||||
 | 
					  * @param buf the raw buffer data, of the correct length determined by the remaining length field
 | 
				
			||||||
 | 
					  * @param buflen the length in bytes of the data in the supplied buffer
 | 
				
			||||||
 | 
					  * @return error code.  1 is success, 0 is failure
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int32_t* count, int32_t grantedQoSs[], unsigned char* buf, int buflen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						MQTTHeader header = {0};
 | 
				
			||||||
 | 
						unsigned char* curdata = buf;
 | 
				
			||||||
 | 
						unsigned char* enddata = NULL;
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						int mylen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
						header.byte = readChar(&curdata);
 | 
				
			||||||
 | 
						if (header.bits.type != SUBACK)
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
 | 
				
			||||||
 | 
						enddata = curdata + mylen;
 | 
				
			||||||
 | 
						if (enddata - curdata < 2)
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*packetid = readInt(&curdata);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*count = 0;
 | 
				
			||||||
 | 
						while (curdata < enddata)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (*count > maxcount)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								rc = -1;
 | 
				
			||||||
 | 
								goto exit;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							grantedQoSs[(*count)++] = readChar(&curdata);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = 1;
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						FUNC_EXIT_RC(rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,112 @@
 | 
				
			||||||
 | 
					/*******************************************************************************
 | 
				
			||||||
 | 
					 * Copyright (c) 2014 IBM Corp.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All rights reserved. This program and the accompanying materials
 | 
				
			||||||
 | 
					 * are made available under the terms of the Eclipse Public License v1.0
 | 
				
			||||||
 | 
					 * and Eclipse Distribution License v1.0 which accompany this distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Eclipse Public License is available at
 | 
				
			||||||
 | 
					 *    http://www.eclipse.org/legal/epl-v10.html
 | 
				
			||||||
 | 
					 * and the Eclipse Distribution License is available at
 | 
				
			||||||
 | 
					 *   http://www.eclipse.org/org/documents/edl-v10.php.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contributors:
 | 
				
			||||||
 | 
					 *    Ian Craggs - initial API and implementation and/or initial documentation
 | 
				
			||||||
 | 
					 *******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "MQTTPacket.h"
 | 
				
			||||||
 | 
					#include "StackTrace.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Deserializes the supplied (wire) buffer into subscribe data
 | 
				
			||||||
 | 
					  * @param dup integer returned - the MQTT dup flag
 | 
				
			||||||
 | 
					  * @param packetid integer returned - the MQTT packet identifier
 | 
				
			||||||
 | 
					  * @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays
 | 
				
			||||||
 | 
					  * @param count - number of members in the topicFilters and requestedQoSs arrays
 | 
				
			||||||
 | 
					  * @param topicFilters - array of topic filter names
 | 
				
			||||||
 | 
					  * @param requestedQoSs - array of requested QoS
 | 
				
			||||||
 | 
					  * @param buf the raw buffer data, of the correct length determined by the remaining length field
 | 
				
			||||||
 | 
					  * @param buflen the length in bytes of the data in the supplied buffer
 | 
				
			||||||
 | 
					  * @return the length of the serialized data.  <= 0 indicates error
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid, int maxcount, int* count, MQTTString topicFilters[],
 | 
				
			||||||
 | 
						int requestedQoSs[], unsigned char* buf, int buflen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						MQTTHeader header = {0};
 | 
				
			||||||
 | 
						unsigned char* curdata = buf;
 | 
				
			||||||
 | 
						unsigned char* enddata = NULL;
 | 
				
			||||||
 | 
						int rc = -1;
 | 
				
			||||||
 | 
						int mylen = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
						header.byte = readChar(&curdata);
 | 
				
			||||||
 | 
						if (header.bits.type != SUBSCRIBE)
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
						*dup = header.bits.dup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
 | 
				
			||||||
 | 
						enddata = curdata + mylen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*packetid = readInt(&curdata);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*count = 0;
 | 
				
			||||||
 | 
						while (curdata < enddata)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata))
 | 
				
			||||||
 | 
								goto exit;
 | 
				
			||||||
 | 
							if (curdata >= enddata) /* do we have enough data to read the req_qos version byte? */
 | 
				
			||||||
 | 
								goto exit;
 | 
				
			||||||
 | 
							requestedQoSs[*count] = readChar(&curdata);
 | 
				
			||||||
 | 
							(*count)++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = 1;
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						FUNC_EXIT_RC(rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Serializes the supplied suback data into the supplied buffer, ready for sending
 | 
				
			||||||
 | 
					  * @param buf the buffer into which the packet will be serialized
 | 
				
			||||||
 | 
					  * @param buflen the length in bytes of the supplied buffer
 | 
				
			||||||
 | 
					  * @param packetid integer - the MQTT packet identifier
 | 
				
			||||||
 | 
					  * @param count - number of members in the grantedQoSs array
 | 
				
			||||||
 | 
					  * @param grantedQoSs - array of granted QoS
 | 
				
			||||||
 | 
					  * @return the length of the serialized data.  <= 0 indicates error
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						MQTTHeader header = {0};
 | 
				
			||||||
 | 
						int rc = -1;
 | 
				
			||||||
 | 
						unsigned char *ptr = buf;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
						if (buflen < 2 + count)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							rc = MQTTPACKET_BUFFER_TOO_SHORT;
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						header.byte = 0;
 | 
				
			||||||
 | 
						header.bits.type = SUBACK;
 | 
				
			||||||
 | 
						writeChar(&ptr, header.byte); /* write header */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ptr += MQTTPacket_encode(ptr, 2 + count); /* write remaining length */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						writeInt(&ptr, packetid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < count; ++i)
 | 
				
			||||||
 | 
							writeChar(&ptr, grantedQoSs[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = ptr - buf;
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						FUNC_EXIT_RC(rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,38 @@
 | 
				
			||||||
 | 
					/*******************************************************************************
 | 
				
			||||||
 | 
					 * Copyright (c) 2014 IBM Corp.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All rights reserved. This program and the accompanying materials
 | 
				
			||||||
 | 
					 * are made available under the terms of the Eclipse Public License v1.0
 | 
				
			||||||
 | 
					 * and Eclipse Distribution License v1.0 which accompany this distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Eclipse Public License is available at
 | 
				
			||||||
 | 
					 *    http://www.eclipse.org/legal/epl-v10.html
 | 
				
			||||||
 | 
					 * and the Eclipse Distribution License is available at
 | 
				
			||||||
 | 
					 *   http://www.eclipse.org/org/documents/edl-v10.php.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contributors:
 | 
				
			||||||
 | 
					 *    Ian Craggs - initial API and implementation and/or initial documentation
 | 
				
			||||||
 | 
					 *    Xiang Rong - 442039 Add makefile to Embedded C client
 | 
				
			||||||
 | 
					 *******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef MQTTUNSUBSCRIBE_H_
 | 
				
			||||||
 | 
					#define MQTTUNSUBSCRIBE_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if !defined(DLLImport)
 | 
				
			||||||
 | 
					  #define DLLImport 
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#if !defined(DLLExport)
 | 
				
			||||||
 | 
					  #define DLLExport
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DLLExport int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
 | 
				
			||||||
 | 
							int count, MQTTString topicFilters[]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DLLExport int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int max_count, int* count, MQTTString topicFilters[],
 | 
				
			||||||
 | 
							unsigned char* buf, int len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DLLExport int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DLLExport int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* MQTTUNSUBSCRIBE_H_ */
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,106 @@
 | 
				
			||||||
 | 
					/*******************************************************************************
 | 
				
			||||||
 | 
					 * Copyright (c) 2014 IBM Corp.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All rights reserved. This program and the accompanying materials
 | 
				
			||||||
 | 
					 * are made available under the terms of the Eclipse Public License v1.0
 | 
				
			||||||
 | 
					 * and Eclipse Distribution License v1.0 which accompany this distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Eclipse Public License is available at
 | 
				
			||||||
 | 
					 *    http://www.eclipse.org/legal/epl-v10.html
 | 
				
			||||||
 | 
					 * and the Eclipse Distribution License is available at
 | 
				
			||||||
 | 
					 *   http://www.eclipse.org/org/documents/edl-v10.php.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contributors:
 | 
				
			||||||
 | 
					 *    Ian Craggs - initial API and implementation and/or initial documentation
 | 
				
			||||||
 | 
					 *******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "MQTTPacket.h"
 | 
				
			||||||
 | 
					#include "StackTrace.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Determines the length of the MQTT unsubscribe packet that would be produced using the supplied parameters
 | 
				
			||||||
 | 
					  * @param count the number of topic filter strings in topicFilters
 | 
				
			||||||
 | 
					  * @param topicFilters the array of topic filter strings to be used in the publish
 | 
				
			||||||
 | 
					  * @return the length of buffer needed to contain the serialized version of the packet
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTSerialize_unsubscribeLength(int count, MQTTString topicFilters[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						int len = 2; /* packetid */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < count; ++i)
 | 
				
			||||||
 | 
							len += 2 + MQTTstrlen(topicFilters[i]); /* length + topic*/
 | 
				
			||||||
 | 
						return len;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Serializes the supplied unsubscribe data into the supplied buffer, ready for sending
 | 
				
			||||||
 | 
					  * @param buf the raw buffer data, of the correct length determined by the remaining length field
 | 
				
			||||||
 | 
					  * @param buflen the length in bytes of the data in the supplied buffer
 | 
				
			||||||
 | 
					  * @param dup integer - the MQTT dup flag
 | 
				
			||||||
 | 
					  * @param packetid integer - the MQTT packet identifier
 | 
				
			||||||
 | 
					  * @param count - number of members in the topicFilters array
 | 
				
			||||||
 | 
					  * @param topicFilters - array of topic filter names
 | 
				
			||||||
 | 
					  * @return the length of the serialized data.  <= 0 indicates error
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
 | 
				
			||||||
 | 
							int count, MQTTString topicFilters[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned char *ptr = buf;
 | 
				
			||||||
 | 
						MQTTHeader header = {0};
 | 
				
			||||||
 | 
						int rem_len = 0;
 | 
				
			||||||
 | 
						int rc = -1;
 | 
				
			||||||
 | 
						int i = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
						if (MQTTPacket_len(rem_len = MQTTSerialize_unsubscribeLength(count, topicFilters)) > buflen)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							rc = MQTTPACKET_BUFFER_TOO_SHORT;
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						header.byte = 0;
 | 
				
			||||||
 | 
						header.bits.type = UNSUBSCRIBE;
 | 
				
			||||||
 | 
						header.bits.dup = dup;
 | 
				
			||||||
 | 
						header.bits.qos = 1;
 | 
				
			||||||
 | 
						writeChar(&ptr, header.byte); /* write header */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						writeInt(&ptr, packetid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < count; ++i)
 | 
				
			||||||
 | 
							writeMQTTString(&ptr, topicFilters[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = ptr - buf;
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						FUNC_EXIT_RC(rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Deserializes the supplied (wire) buffer into unsuback data
 | 
				
			||||||
 | 
					  * @param packetid returned integer - the MQTT packet identifier
 | 
				
			||||||
 | 
					  * @param buf the raw buffer data, of the correct length determined by the remaining length field
 | 
				
			||||||
 | 
					  * @param buflen the length in bytes of the data in the supplied buffer
 | 
				
			||||||
 | 
					  * @return error code.  1 is success, 0 is failure
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int buflen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned char type = 0;
 | 
				
			||||||
 | 
						unsigned char dup = 0;
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
						rc = MQTTDeserialize_ack(&type, &dup, packetid, buf, buflen);
 | 
				
			||||||
 | 
						if (type == UNSUBACK)
 | 
				
			||||||
 | 
							rc = 1;
 | 
				
			||||||
 | 
						FUNC_EXIT_RC(rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,102 @@
 | 
				
			||||||
 | 
					/*******************************************************************************
 | 
				
			||||||
 | 
					 * Copyright (c) 2014 IBM Corp.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All rights reserved. This program and the accompanying materials
 | 
				
			||||||
 | 
					 * are made available under the terms of the Eclipse Public License v1.0
 | 
				
			||||||
 | 
					 * and Eclipse Distribution License v1.0 which accompany this distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Eclipse Public License is available at
 | 
				
			||||||
 | 
					 *    http://www.eclipse.org/legal/epl-v10.html
 | 
				
			||||||
 | 
					 * and the Eclipse Distribution License is available at
 | 
				
			||||||
 | 
					 *   http://www.eclipse.org/org/documents/edl-v10.php.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contributors:
 | 
				
			||||||
 | 
					 *    Ian Craggs - initial API and implementation and/or initial documentation
 | 
				
			||||||
 | 
					 *******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "MQTTPacket.h"
 | 
				
			||||||
 | 
					#include "StackTrace.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Deserializes the supplied (wire) buffer into unsubscribe data
 | 
				
			||||||
 | 
					  * @param dup integer returned - the MQTT dup flag
 | 
				
			||||||
 | 
					  * @param packetid integer returned - the MQTT packet identifier
 | 
				
			||||||
 | 
					  * @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays
 | 
				
			||||||
 | 
					  * @param count - number of members in the topicFilters and requestedQoSs arrays
 | 
				
			||||||
 | 
					  * @param topicFilters - array of topic filter names
 | 
				
			||||||
 | 
					  * @param buf the raw buffer data, of the correct length determined by the remaining length field
 | 
				
			||||||
 | 
					  * @param buflen the length in bytes of the data in the supplied buffer
 | 
				
			||||||
 | 
					  * @return the length of the serialized data.  <= 0 indicates error
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int maxcount, int* count, MQTTString topicFilters[],
 | 
				
			||||||
 | 
							unsigned char* buf, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						MQTTHeader header = {0};
 | 
				
			||||||
 | 
						unsigned char* curdata = buf;
 | 
				
			||||||
 | 
						unsigned char* enddata = NULL;
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						int mylen = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
						header.byte = readChar(&curdata);
 | 
				
			||||||
 | 
						if (header.bits.type != UNSUBSCRIBE)
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
						*dup = header.bits.dup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
 | 
				
			||||||
 | 
						enddata = curdata + mylen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*packetid = readInt(&curdata);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*count = 0;
 | 
				
			||||||
 | 
						while (curdata < enddata)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata))
 | 
				
			||||||
 | 
								goto exit;
 | 
				
			||||||
 | 
							(*count)++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = 1;
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						FUNC_EXIT_RC(rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Serializes the supplied unsuback data into the supplied buffer, ready for sending
 | 
				
			||||||
 | 
					  * @param buf the buffer into which the packet will be serialized
 | 
				
			||||||
 | 
					  * @param buflen the length in bytes of the supplied buffer
 | 
				
			||||||
 | 
					  * @param packetid integer - the MQTT packet identifier
 | 
				
			||||||
 | 
					  * @return the length of the serialized data.  <= 0 indicates error
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						MQTTHeader header = {0};
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						unsigned char *ptr = buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FUNC_ENTRY;
 | 
				
			||||||
 | 
						if (buflen < 2)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							rc = MQTTPACKET_BUFFER_TOO_SHORT;
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						header.byte = 0;
 | 
				
			||||||
 | 
						header.bits.type = UNSUBACK;
 | 
				
			||||||
 | 
						writeChar(&ptr, header.byte); /* write header */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						writeInt(&ptr, packetid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = ptr - buf;
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						FUNC_EXIT_RC(rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,13 @@
 | 
				
			||||||
 | 
					 SRC_FILES +=MQTTPacket.c\
 | 
				
			||||||
 | 
								 MQTTConnectClient.c \
 | 
				
			||||||
 | 
							     MQTTConnectServer.c \
 | 
				
			||||||
 | 
								 MQTTDeserializePublish.c \
 | 
				
			||||||
 | 
								 MQTTFormat.c \
 | 
				
			||||||
 | 
								 MQTTSerializePublish.c \
 | 
				
			||||||
 | 
								 MQTTSubscribeClient.c \
 | 
				
			||||||
 | 
								 MQTTSubscribeServer.c \
 | 
				
			||||||
 | 
								 MQTTUnsubscribeClient.c \
 | 
				
			||||||
 | 
								 MQTTUnsubscribeServer.c \
 | 
				
			||||||
 | 
								 transport.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include $(KERNEL_ROOT)/compiler.mk
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,78 @@
 | 
				
			||||||
 | 
					/*******************************************************************************
 | 
				
			||||||
 | 
					 * Copyright (c) 2014 IBM Corp.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All rights reserved. This program and the accompanying materials
 | 
				
			||||||
 | 
					 * are made available under the terms of the Eclipse Public License v1.0
 | 
				
			||||||
 | 
					 * and Eclipse Distribution License v1.0 which accompany this distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Eclipse Public License is available at
 | 
				
			||||||
 | 
					 *    http://www.eclipse.org/legal/epl-v10.html
 | 
				
			||||||
 | 
					 * and the Eclipse Distribution License is available at
 | 
				
			||||||
 | 
					 *   http://www.eclipse.org/org/documents/edl-v10.php.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Contributors:
 | 
				
			||||||
 | 
					 *    Ian Craggs - initial API and implementation and/or initial documentation
 | 
				
			||||||
 | 
					 *    Ian Craggs - fix for bug #434081
 | 
				
			||||||
 | 
					 *******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef STACKTRACE_H_
 | 
				
			||||||
 | 
					#define STACKTRACE_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#define NOSTACKTRACE 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(NOSTACKTRACE)
 | 
				
			||||||
 | 
					#define FUNC_ENTRY
 | 
				
			||||||
 | 
					#define FUNC_ENTRY_NOLOG
 | 
				
			||||||
 | 
					#define FUNC_ENTRY_MED
 | 
				
			||||||
 | 
					#define FUNC_ENTRY_MAX
 | 
				
			||||||
 | 
					#define FUNC_EXIT
 | 
				
			||||||
 | 
					#define FUNC_EXIT_NOLOG
 | 
				
			||||||
 | 
					#define FUNC_EXIT_MED
 | 
				
			||||||
 | 
					#define FUNC_EXIT_MAX
 | 
				
			||||||
 | 
					#define FUNC_EXIT_RC(x)
 | 
				
			||||||
 | 
					#define FUNC_EXIT_MED_RC(x)
 | 
				
			||||||
 | 
					#define FUNC_EXIT_MAX_RC(x)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(WIN32)
 | 
				
			||||||
 | 
					#define inline __inline
 | 
				
			||||||
 | 
					#define FUNC_ENTRY StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MINIMUM)
 | 
				
			||||||
 | 
					#define FUNC_ENTRY_NOLOG StackTrace_entry(__FUNCTION__, __LINE__, -1)
 | 
				
			||||||
 | 
					#define FUNC_ENTRY_MED StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MEDIUM)
 | 
				
			||||||
 | 
					#define FUNC_ENTRY_MAX StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MAXIMUM)
 | 
				
			||||||
 | 
					#define FUNC_EXIT StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MINIMUM)
 | 
				
			||||||
 | 
					#define FUNC_EXIT_NOLOG StackTrace_exit(__FUNCTION__, __LINE__, -1)
 | 
				
			||||||
 | 
					#define FUNC_EXIT_MED StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MEDIUM)
 | 
				
			||||||
 | 
					#define FUNC_EXIT_MAX StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MAXIMUM)
 | 
				
			||||||
 | 
					#define FUNC_EXIT_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MINIMUM)
 | 
				
			||||||
 | 
					#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MEDIUM)
 | 
				
			||||||
 | 
					#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MAXIMUM)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define FUNC_ENTRY StackTrace_entry(__func__, __LINE__, TRACE_MINIMUM)
 | 
				
			||||||
 | 
					#define FUNC_ENTRY_NOLOG StackTrace_entry(__func__, __LINE__, -1)
 | 
				
			||||||
 | 
					#define FUNC_ENTRY_MED StackTrace_entry(__func__, __LINE__, TRACE_MEDIUM)
 | 
				
			||||||
 | 
					#define FUNC_ENTRY_MAX StackTrace_entry(__func__, __LINE__, TRACE_MAXIMUM)
 | 
				
			||||||
 | 
					#define FUNC_EXIT StackTrace_exit(__func__, __LINE__, NULL, TRACE_MINIMUM)
 | 
				
			||||||
 | 
					#define FUNC_EXIT_NOLOG StackTrace_exit(__func__, __LINE__, NULL, -1)
 | 
				
			||||||
 | 
					#define FUNC_EXIT_MED StackTrace_exit(__func__, __LINE__, NULL, TRACE_MEDIUM)
 | 
				
			||||||
 | 
					#define FUNC_EXIT_MAX StackTrace_exit(__func__, __LINE__, NULL, TRACE_MAXIMUM)
 | 
				
			||||||
 | 
					#define FUNC_EXIT_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MINIMUM)
 | 
				
			||||||
 | 
					#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MEDIUM)
 | 
				
			||||||
 | 
					#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MAXIMUM)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void StackTrace_entry(const char* name, int line, int trace);
 | 
				
			||||||
 | 
					void StackTrace_exit(const char* name, int line, void* return_value, int trace);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void StackTrace_printStack(FILE* dest);
 | 
				
			||||||
 | 
					char* StackTrace_get(unsigned long);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* STACKTRACE_H_ */
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,59 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) 2022 AIIT XUOS Lab
 | 
				
			||||||
 | 
					 * XiUOS is licensed under Mulan PSL v2.
 | 
				
			||||||
 | 
					 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 | 
				
			||||||
 | 
					 * You may obtain a copy of Mulan PSL v2 at:
 | 
				
			||||||
 | 
					 *        http://license.coscl.org.cn/MulanPSL2
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | 
				
			||||||
 | 
					 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | 
				
			||||||
 | 
					 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | 
				
			||||||
 | 
					 * See the Mulan PSL v2 for more details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @file transport.c
 | 
				
			||||||
 | 
					 * @brief mqtt transport function
 | 
				
			||||||
 | 
					 * @version 3.0
 | 
				
			||||||
 | 
					 * @author AIIT XUOS Lab
 | 
				
			||||||
 | 
					 * @date 2023.8.10
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "transport.h"
 | 
				
			||||||
 | 
					#include "lwip/opt.h"
 | 
				
			||||||
 | 
					#include "lwip/arch.h"
 | 
				
			||||||
 | 
					#include "lwip/api.h"
 | 
				
			||||||
 | 
					#include "lwip/inet.h"
 | 
				
			||||||
 | 
					#include "lwip/sockets.h"
 | 
				
			||||||
 | 
					#include "string.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int mysock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int32_t transport_sendPacketBuffer( uint8_t* buf, int32_t buflen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int32_t rc;
 | 
				
			||||||
 | 
						rc = write(mysock, buf, buflen);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int transport_getdata(unsigned char* buf, int count)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int32_t rc;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					  rc = recv(mysock, buf, count, 0);
 | 
				
			||||||
 | 
					  lw_print("get data : %lx\n",rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int32_t transport_close(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					//	rc = close(mysock);
 | 
				
			||||||
 | 
					  rc = shutdown(mysock, SHUT_WR);
 | 
				
			||||||
 | 
						rc = recv(mysock, NULL, (size_t)0, 0);
 | 
				
			||||||
 | 
						rc = close(mysock);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,40 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) 2022 AIIT XUOS Lab
 | 
				
			||||||
 | 
					 * XiUOS is licensed under Mulan PSL v2.
 | 
				
			||||||
 | 
					 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 | 
				
			||||||
 | 
					 * You may obtain a copy of Mulan PSL v2 at:
 | 
				
			||||||
 | 
					 *        http://license.coscl.org.cn/MulanPSL2
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | 
				
			||||||
 | 
					 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | 
				
			||||||
 | 
					 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | 
				
			||||||
 | 
					 * See the Mulan PSL v2 for more details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @file transport.h
 | 
				
			||||||
 | 
					 * @brief mqtt transport function
 | 
				
			||||||
 | 
					 * @version 3.0
 | 
				
			||||||
 | 
					 * @author AIIT XUOS Lab
 | 
				
			||||||
 | 
					 * @date 2023.8.10
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __TRANSPORT_H
 | 
				
			||||||
 | 
					#define __TRANSPORT_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int32_t transport_sendPacketBuffer( uint8_t* buf, int32_t buflen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int transport_getdata(unsigned char* buf, int count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int32_t transport_open(int8_t* servip, int32_t port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int32_t transport_close(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,748 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) 2022 AIIT XUOS Lab
 | 
				
			||||||
 | 
					 * XiUOS is licensed under Mulan PSL v2.
 | 
				
			||||||
 | 
					 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 | 
				
			||||||
 | 
					 * You may obtain a copy of Mulan PSL v2 at:
 | 
				
			||||||
 | 
					 *        http://license.coscl.org.cn/MulanPSL2
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | 
				
			||||||
 | 
					 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | 
				
			||||||
 | 
					 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | 
				
			||||||
 | 
					 * See the Mulan PSL v2 for more details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @file test_mqttclient.c
 | 
				
			||||||
 | 
					 * @brief mqtt subscribe fuction test
 | 
				
			||||||
 | 
					 * @version 3.0
 | 
				
			||||||
 | 
					 * @author AIIT XUOS Lab
 | 
				
			||||||
 | 
					 * @date 2023.8.10
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <transform.h>
 | 
				
			||||||
 | 
					#include "test_mqttclient.h"
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#ifdef ADD_XIZI_FEATURES
 | 
				
			||||||
 | 
					#include <sys_arch.h>
 | 
				
			||||||
 | 
					#include <lwip/sockets.h>
 | 
				
			||||||
 | 
					#include "lwip/sys.h"
 | 
				
			||||||
 | 
					#include "lwip/api.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "mqtt/MQTTPacket.h"
 | 
				
			||||||
 | 
					#include "mqtt/MQTTSubscribe.h"
 | 
				
			||||||
 | 
					#include "mqtt/transport.h"
 | 
				
			||||||
 | 
					#include <cJSON_Process.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef ADD_NUTTX_FEATURES
 | 
				
			||||||
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					#include <netinet/in.h>
 | 
				
			||||||
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
 | 
					#include "stdio.h"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MQTT_DEMO_BUF_SIZE                    65535
 | 
				
			||||||
 | 
					#define MQTT_DEMO_SEND_TIMES                  20
 | 
				
			||||||
 | 
					#define LWIP_MQTT_DEMO_TASK_STACK_SIZE        4096
 | 
				
			||||||
 | 
					#define LWIP_MQTT_DEMO_TASK_PRIO              20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char mqtt_demo_ipaddr[] = {192, 168, 130, 77};
 | 
				
			||||||
 | 
					static char mqtt_demo_netmask[] = {255, 255, 254, 0};
 | 
				
			||||||
 | 
					static char mqtt_demo_gwaddr[] = {192, 168, 130, 1};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static pthread_t mqtt_client_task;
 | 
				
			||||||
 | 
					static pthread_t mqtt_server_task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint16_t mqtt_socket_port = 1883;
 | 
				
			||||||
 | 
					static char mqtt_ip_str[128] = {192,168,100,1};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MqttSocketConfigParam(char *ip_str)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ip1, ip2, ip3, ip4, port = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(ip_str == NULL)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(sscanf(ip_str, "%d.%d.%d.%d:%d", &ip1, &ip2, &ip3, &ip4, &port)) {
 | 
				
			||||||
 | 
					        printf("config ip %s port %d\n", ip_str, port);
 | 
				
			||||||
 | 
					        strcpy(mqtt_ip_str, ip_str);
 | 
				
			||||||
 | 
					        if(port)
 | 
				
			||||||
 | 
					            mqtt_socket_port = port;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(sscanf(ip_str, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4)) {
 | 
				
			||||||
 | 
					        printf("config ip %s\n", ip_str);
 | 
				
			||||||
 | 
					        strcpy(mqtt_ip_str, ip_str);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MQTT_USER_MSG  mqtt_user_msg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t MQTT_Connect(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
 | 
				
			||||||
 | 
					    uint8_t buf[200];
 | 
				
			||||||
 | 
					    int buflen = sizeof(buf);
 | 
				
			||||||
 | 
					    int len = 0;
 | 
				
			||||||
 | 
					    data.clientID.cstring = CLIENT_ID;                   //随机
 | 
				
			||||||
 | 
					    data.keepAliveInterval = KEEPLIVE_TIME;         //保持活跃
 | 
				
			||||||
 | 
					    data.username.cstring = USER_NAME;              //用户名
 | 
				
			||||||
 | 
					    data.password.cstring = PASSWORD;               //密钥
 | 
				
			||||||
 | 
					    data.MQTTVersion = MQTT_VERSION;                //3表示3.1版本,4表示3.11版本
 | 
				
			||||||
 | 
					    data.cleansession = 1;
 | 
				
			||||||
 | 
					    //组装消息
 | 
				
			||||||
 | 
					    len = MQTTSerialize_connect((unsigned char *)buf, buflen, &data);
 | 
				
			||||||
 | 
					    //发送消息
 | 
				
			||||||
 | 
					    transport_sendPacketBuffer(buf, len);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /* 等待连接响应 */
 | 
				
			||||||
 | 
					    if (MQTTPacket_read(buf, buflen, transport_getdata) == CONNACK)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        unsigned char sessionPresent, connack_rc;
 | 
				
			||||||
 | 
					        if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) != 1 || connack_rc != 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          lw_print("无法连接,错误代码是: %d!\n", connack_rc);
 | 
				
			||||||
 | 
					            return Connect_NOK;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else 
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            lw_print("用户名与密钥验证成功,MQTT连接成功!\n");
 | 
				
			||||||
 | 
					            return Connect_OK;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        lw_print("MQTT连接无响应!\n");
 | 
				
			||||||
 | 
					        return Connect_NOTACK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int32_t MQTT_PingReq(int32_t sock)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						  int32_t len;
 | 
				
			||||||
 | 
							uint8_t buf[200];
 | 
				
			||||||
 | 
							int32_t buflen = sizeof(buf);	 
 | 
				
			||||||
 | 
							fd_set readfd;
 | 
				
			||||||
 | 
						  struct timeval tv;
 | 
				
			||||||
 | 
						  tv.tv_sec = 5;
 | 
				
			||||||
 | 
						  tv.tv_usec = 0;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						  FD_ZERO(&readfd);
 | 
				
			||||||
 | 
						  FD_SET(sock,&readfd);			
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
							len = MQTTSerialize_pingreq(buf, buflen);
 | 
				
			||||||
 | 
							transport_sendPacketBuffer(buf, len);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
							//等待可读事件
 | 
				
			||||||
 | 
							if(select(sock+1,&readfd,NULL,NULL,&tv) == 0)
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
						  //有可读事件
 | 
				
			||||||
 | 
							if(FD_ISSET(sock,&readfd) == 0)
 | 
				
			||||||
 | 
								return -2;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if(MQTTPacket_read(buf, buflen, transport_getdata) != PINGRESP)
 | 
				
			||||||
 | 
								return -3;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/************************************************************************
 | 
				
			||||||
 | 
					** 函数名称: MQTTSubscribe								
 | 
				
			||||||
 | 
					** 函数功能: 订阅消息
 | 
				
			||||||
 | 
					** 入口参数: int32_t sock:套接字
 | 
				
			||||||
 | 
					**           int8_t *topic:主题
 | 
				
			||||||
 | 
					**           enum QoS pos:消息质量
 | 
				
			||||||
 | 
					** 出口参数: >=0:发送成功 <0:发送失败
 | 
				
			||||||
 | 
					** 备    注: 
 | 
				
			||||||
 | 
					************************************************************************/
 | 
				
			||||||
 | 
					int32_t MQTTSubscribe(int32_t sock,char *topic,enum QoS pos)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						  static uint32_t PacketID = 0;
 | 
				
			||||||
 | 
						  uint16_t packetidbk = 0;
 | 
				
			||||||
 | 
						  int32_t conutbk = 0;
 | 
				
			||||||
 | 
							uint8_t buf[100];
 | 
				
			||||||
 | 
							int32_t buflen = sizeof(buf);
 | 
				
			||||||
 | 
						  MQTTString topicString = MQTTString_initializer;  
 | 
				
			||||||
 | 
							int32_t len;
 | 
				
			||||||
 | 
						  int32_t req_qos,qosbk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							fd_set readfd;
 | 
				
			||||||
 | 
						  struct timeval tv;
 | 
				
			||||||
 | 
						  tv.tv_sec = 2;
 | 
				
			||||||
 | 
						  tv.tv_usec = 0;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						  FD_ZERO(&readfd);
 | 
				
			||||||
 | 
						  FD_SET(sock,&readfd);		
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						  //复制主题
 | 
				
			||||||
 | 
					    topicString.cstring = (char *)topic;
 | 
				
			||||||
 | 
							//订阅质量
 | 
				
			||||||
 | 
						  req_qos = pos;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						  //串行化订阅消息
 | 
				
			||||||
 | 
					    len = MQTTSerialize_subscribe(buf, buflen, 0, PacketID++, 1, &topicString, &req_qos);
 | 
				
			||||||
 | 
							//发送TCP数据
 | 
				
			||||||
 | 
						  if(transport_sendPacketBuffer(buf, len) < 0)
 | 
				
			||||||
 | 
									return -1;
 | 
				
			||||||
 | 
						  
 | 
				
			||||||
 | 
					    //等待可读事件--等待超时
 | 
				
			||||||
 | 
							if(select(sock+1,&readfd,NULL,NULL,&tv) == 0)
 | 
				
			||||||
 | 
									return -2;
 | 
				
			||||||
 | 
							//有可读事件--没有可读事件
 | 
				
			||||||
 | 
							if(FD_ISSET(sock,&readfd) == 0)
 | 
				
			||||||
 | 
									return -3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//等待订阅返回--未收到订阅返回
 | 
				
			||||||
 | 
							if(MQTTPacket_read(buf, buflen, transport_getdata) != SUBACK)
 | 
				
			||||||
 | 
									return -4;	
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//拆订阅回应包
 | 
				
			||||||
 | 
							if(MQTTDeserialize_suback(&packetidbk,1, &conutbk, &qosbk, buf, buflen) != 1)
 | 
				
			||||||
 | 
									return -5;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//检测返回数据的正确性
 | 
				
			||||||
 | 
							if((qosbk == 0x80)||(packetidbk != (PacketID-1)))
 | 
				
			||||||
 | 
									return -6;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
					    //订阅成功
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int32_t ReadPacketTimeout(int32_t sock,uint8_t *buf,int32_t buflen,uint32_t timeout)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
							fd_set readfd;
 | 
				
			||||||
 | 
						  struct timeval tv;
 | 
				
			||||||
 | 
						  if(timeout != 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
									tv.tv_sec = timeout;
 | 
				
			||||||
 | 
									tv.tv_usec = 0;
 | 
				
			||||||
 | 
									FD_ZERO(&readfd);
 | 
				
			||||||
 | 
									FD_SET(sock,&readfd); 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
									if(select(sock+1,&readfd,NULL,NULL,&tv) == 0)
 | 
				
			||||||
 | 
											return -1;
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
									if(FD_ISSET(sock,&readfd) == 0)
 | 
				
			||||||
 | 
											return -1;
 | 
				
			||||||
 | 
						  }
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							return MQTTPacket_read(buf, buflen, transport_getdata);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void deliverMessage(MQTTString  *TopicName,MQTTMessage *msg,MQTT_USER_MSG *mqtt_user_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
							//消息质量
 | 
				
			||||||
 | 
							mqtt_user_msg->msgqos = msg->qos;
 | 
				
			||||||
 | 
							//保存消息
 | 
				
			||||||
 | 
							memcpy(mqtt_user_msg->msg,msg->payload,msg->payloadlen);
 | 
				
			||||||
 | 
							mqtt_user_msg->msg[msg->payloadlen] = 0;
 | 
				
			||||||
 | 
							//保存消息长度
 | 
				
			||||||
 | 
							mqtt_user_msg->msglenth = msg->payloadlen;
 | 
				
			||||||
 | 
							//消息主题
 | 
				
			||||||
 | 
							memcpy((char *)mqtt_user_msg->topic,TopicName->lenstring.data,TopicName->lenstring.len);
 | 
				
			||||||
 | 
							mqtt_user_msg->topic[TopicName->lenstring.len] = 0;
 | 
				
			||||||
 | 
							//消息ID
 | 
				
			||||||
 | 
							mqtt_user_msg->packetid = msg->id;
 | 
				
			||||||
 | 
							//标明消息合法
 | 
				
			||||||
 | 
							mqtt_user_msg->valid = 1;		
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UserMsgCtl(MQTT_USER_MSG  *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
							//这里处理数据只是打印,用户可以在这里添加自己的处理方式
 | 
				
			||||||
 | 
						  lw_print("****收到订阅的消息******\n");
 | 
				
			||||||
 | 
							//<2F><><EFBFBD>غ<EFBFBD><D8BA><EFBFBD><EFBFBD><EFBFBD>Ϣ
 | 
				
			||||||
 | 
						  switch(msg->msgqos)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								case 0:
 | 
				
			||||||
 | 
									    lw_print("MQTT>>消息质量QoS0\n");
 | 
				
			||||||
 | 
									    break;
 | 
				
			||||||
 | 
								case 1:
 | 
				
			||||||
 | 
									    lw_print("MQTT>>消息质量QoS1\n");
 | 
				
			||||||
 | 
									    break;
 | 
				
			||||||
 | 
								case 2:
 | 
				
			||||||
 | 
									    lw_print("MQTT>>消息质量QoS2\n");
 | 
				
			||||||
 | 
									    break;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									    lw_print("MQTT>>错误的消息质量\n");
 | 
				
			||||||
 | 
									    break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							lw_print("MQTT>>消息主题:%s\n",msg->topic);	
 | 
				
			||||||
 | 
							lw_print("MQTT>>消息内容:%s\n",msg->msg);	
 | 
				
			||||||
 | 
							lw_print("MQTT>>消息长度:%d\n",msg->msglenth);	 
 | 
				
			||||||
 | 
					    Proscess(msg->msg);
 | 
				
			||||||
 | 
						  //处理完后销毁数据
 | 
				
			||||||
 | 
						  msg->valid  = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mqtt_pktype_ctl(uint8_t packtype,uint8_t *buf,uint32_t buflen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						  MQTTMessage msg;
 | 
				
			||||||
 | 
							int32_t rc;
 | 
				
			||||||
 | 
						  MQTTString receivedTopic;
 | 
				
			||||||
 | 
						  uint32_t len;
 | 
				
			||||||
 | 
					    lw_print("packtype:%d\n",packtype);
 | 
				
			||||||
 | 
							switch(packtype)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								case PUBLISH:
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if(MQTTDeserialize_publish(&msg.dup,(int*)&msg.qos, &msg.retained, &msg.id, &receivedTopic,
 | 
				
			||||||
 | 
					          (unsigned char **)&msg.payload, &msg.payloadlen, buf, buflen) != 1)
 | 
				
			||||||
 | 
					            return;	
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        deliverMessage(&receivedTopic,&msg,&mqtt_user_msg);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					        if(msg.qos == QOS0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            //QOS0-不需要ACK
 | 
				
			||||||
 | 
					           //直接处理数据
 | 
				
			||||||
 | 
					           UserMsgCtl(&mqtt_user_msg);
 | 
				
			||||||
 | 
					           return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        //发送PUBACK消息
 | 
				
			||||||
 | 
					        if(msg.qos == QOS1)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            len =MQTTSerialize_puback(buf,buflen,mqtt_user_msg.packetid);
 | 
				
			||||||
 | 
					            if(len == 0)
 | 
				
			||||||
 | 
					              return;
 | 
				
			||||||
 | 
					             //发送返回
 | 
				
			||||||
 | 
					            if(transport_sendPacketBuffer(buf,len)<0)
 | 
				
			||||||
 | 
					               return;	
 | 
				
			||||||
 | 
					             //返回后处理消息
 | 
				
			||||||
 | 
					            UserMsgCtl(&mqtt_user_msg); 
 | 
				
			||||||
 | 
					            return;												
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //对于质量2,只需要发送PUBREC就可以了
 | 
				
			||||||
 | 
					        if(msg.qos == QOS2)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					           len = MQTTSerialize_ack(buf, buflen, PUBREC, 0, mqtt_user_msg.packetid);			                
 | 
				
			||||||
 | 
					           if(len == 0)
 | 
				
			||||||
 | 
					             return;
 | 
				
			||||||
 | 
					            //发送返回
 | 
				
			||||||
 | 
					           transport_sendPacketBuffer(buf,len);	
 | 
				
			||||||
 | 
					        }		
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
								case  PUBREL:				           
 | 
				
			||||||
 | 
					          //解析包数据,必须包ID相同才可以
 | 
				
			||||||
 | 
					        rc = MQTTDeserialize_ack(&msg.type,&msg.dup, &msg.id, buf,buflen);
 | 
				
			||||||
 | 
					        if((rc != 1)||(msg.type != PUBREL)||(msg.id != mqtt_user_msg.packetid))
 | 
				
			||||||
 | 
					          return ;
 | 
				
			||||||
 | 
					       //收到PUBREL,需要处理并抛弃数据
 | 
				
			||||||
 | 
					        if(mqtt_user_msg.valid == 1)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            //返回后处理消息
 | 
				
			||||||
 | 
					           UserMsgCtl(&mqtt_user_msg);
 | 
				
			||||||
 | 
					        }      
 | 
				
			||||||
 | 
					        //串行化PUBCMP消息
 | 
				
			||||||
 | 
					        len = MQTTSerialize_pubcomp(buf,buflen,msg.id);	                   	
 | 
				
			||||||
 | 
					        if(len == 0)
 | 
				
			||||||
 | 
					          return;									
 | 
				
			||||||
 | 
					       //发送返回--PUBCOMP
 | 
				
			||||||
 | 
					        transport_sendPacketBuffer(buf,len);										
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
								case   PUBACK://等级1客户端推送数据后,服务器返回
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case   PUBREC://等级2客户端推送数据后,服务器返回
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case   PUBCOMP://等级2客户端推送PUBREL后,服务器返回
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void *MqttSocketRecvTask(void *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					MQTT_START: 
 | 
				
			||||||
 | 
					    lw_print("Recv begin**********\n");
 | 
				
			||||||
 | 
					    int fd = -1, clientfd;
 | 
				
			||||||
 | 
					    int recv_len;
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					    char *recv_buf;
 | 
				
			||||||
 | 
					    struct sockaddr_in mqtt_addr;
 | 
				
			||||||
 | 
					    socklen_t addr_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     fd = socket(AF_INET, SOCK_STREAM, 0);
 | 
				
			||||||
 | 
					    if (fd < 0) {
 | 
				
			||||||
 | 
					        lw_print("Socket error\n");
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct sockaddr_in mqtt_sock;
 | 
				
			||||||
 | 
					    mqtt_sock.sin_family = AF_INET;
 | 
				
			||||||
 | 
					    mqtt_sock.sin_port = htons(mqtt_socket_port);
 | 
				
			||||||
 | 
					    mqtt_sock.sin_addr.s_addr = inet_addr(mqtt_ip_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memset(&(mqtt_sock.sin_zero), 0, sizeof(mqtt_sock.sin_zero));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = connect(fd, (struct sockaddr *)&mqtt_sock, sizeof(struct sockaddr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ret < 0) {
 | 
				
			||||||
 | 
					        lw_print("Unable to connect %s:%d = %d\n", mqtt_ip_str, mqtt_socket_port, ret);
 | 
				
			||||||
 | 
					        close(fd);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lw_print("MQTT connect %s:%d success, begin to verify username and password.\n", mqtt_ip_str, mqtt_socket_port);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if(MQTT_Connect() != Connect_OK)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        lw_print("MQTT verify failed.\n");
 | 
				
			||||||
 | 
					        shutdown(fd, SHUT_WR);
 | 
				
			||||||
 | 
					        recv(fd, NULL, (size_t)0, 0);
 | 
				
			||||||
 | 
					        close(fd);
 | 
				
			||||||
 | 
					        PrivTaskDelay(1000);
 | 
				
			||||||
 | 
					        goto MQTT_START;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lw_print("MQTT subscribe begin.\n");
 | 
				
			||||||
 | 
					    if(MQTTSubscribe(fd,(char *)TOPIC,QOS1) < 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        lw_print("MQTT subscribe failed.\n");
 | 
				
			||||||
 | 
					        shutdown(fd, SHUT_WR);
 | 
				
			||||||
 | 
					        recv(fd, NULL, (size_t)0, 0);
 | 
				
			||||||
 | 
					        close(fd);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lw_print("subscribe success.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fd_set readfd;
 | 
				
			||||||
 | 
					    uint8_t no_mqtt_msg_exchange = 1;
 | 
				
			||||||
 | 
					    uint8_t buf[MSG_MAX_LEN];
 | 
				
			||||||
 | 
						int32_t buflen = sizeof(buf);
 | 
				
			||||||
 | 
					    int32_t type;
 | 
				
			||||||
 | 
					    struct timeval tv;    
 | 
				
			||||||
 | 
						tv.tv_sec = 0;
 | 
				
			||||||
 | 
						tv.tv_usec = 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int32_t curtick=0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while(1)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      // lw_print("waiting********\n");
 | 
				
			||||||
 | 
					      curtick +=1;
 | 
				
			||||||
 | 
					      no_mqtt_msg_exchange = 1;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							  FD_ZERO(&readfd);
 | 
				
			||||||
 | 
							  FD_SET(fd,&readfd);
 | 
				
			||||||
 | 
					      select(fd+1,&readfd,NULL,NULL,&tv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if(FD_ISSET(fd,&readfd) != 0)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					          
 | 
				
			||||||
 | 
					          type = ReadPacketTimeout(fd,buf,buflen,0);
 | 
				
			||||||
 | 
					          if(type != -1)
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            lw_print("ctl***********\n");
 | 
				
			||||||
 | 
					              mqtt_pktype_ctl(type,buf,buflen);
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					              no_mqtt_msg_exchange = 0;
 | 
				
			||||||
 | 
													
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if( curtick >(2*10000))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            curtick =0;
 | 
				
			||||||
 | 
					            //判断是否有数据交换
 | 
				
			||||||
 | 
					            if(no_mqtt_msg_exchange == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					               //如果有数据交换,这次就不需要发送PING消息
 | 
				
			||||||
 | 
					               continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if(MQTT_PingReq(fd) < 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					               //重连服务器
 | 
				
			||||||
 | 
					               lw_print("发送保持活性ping失败....\n");
 | 
				
			||||||
 | 
					               goto CLOSE;	 
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            lw_print("发送保持活性ping作为心跳成功....\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            no_mqtt_msg_exchange = 0;
 | 
				
			||||||
 | 
					        } 
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CLOSE:
 | 
				
			||||||
 | 
						  lw_print("MQTT subscribe failed.\n");
 | 
				
			||||||
 | 
					    shutdown(fd, SHUT_WR);
 | 
				
			||||||
 | 
					    recv(fd, NULL, (size_t)0, 0);
 | 
				
			||||||
 | 
					    close(fd);
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MqttSocketRecvTest(int argc, char *argv[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(argc >= 2) {
 | 
				
			||||||
 | 
					        lw_print("lw: [%s] target ip %s\n", __func__, argv[1]);
 | 
				
			||||||
 | 
					        MqttSocketConfigParam(argv[1]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // ip4_addr_t dns_ip;
 | 
				
			||||||
 | 
					    // netconn_gethostbyname(HOST_NAME, &dns_ip);
 | 
				
			||||||
 | 
					    // char* host_ip = ip_ntoa(&dns_ip);
 | 
				
			||||||
 | 
					    // lw_print("host name : %s , host_ip : %s\n",HOST_NAME,host_ip);
 | 
				
			||||||
 | 
					    // MqttSocketConfigParam(host_ip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef ADD_XIZI_FEATURES
 | 
				
			||||||
 | 
					    lwip_config_tcp(0, mqtt_demo_ipaddr, mqtt_demo_netmask, mqtt_demo_gwaddr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pthread_attr_t attr;
 | 
				
			||||||
 | 
					    attr.schedparam.sched_priority = LWIP_MQTT_DEMO_TASK_PRIO;
 | 
				
			||||||
 | 
					    attr.stacksize = LWIP_MQTT_DEMO_TASK_STACK_SIZE;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef ADD_NUTTX_FEATURES
 | 
				
			||||||
 | 
					    pthread_attr_t attr = PTHREAD_ATTR_INITIALIZER;
 | 
				
			||||||
 | 
					    attr.priority = LWIP_mqtt_DEMO_TASK_PRIO;
 | 
				
			||||||
 | 
					    attr.stacksize = LWIP_mqtt_DEMO_TASK_STACK_SIZE;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PrivTaskCreate(&mqtt_server_task, &attr, &MqttSocketRecvTask, NULL);
 | 
				
			||||||
 | 
					    PrivTaskStartup(&mqtt_server_task);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PRIV_SHELL_CMD_FUNCTION(MqttSocketRecvTest, a tcp send sample, PRIV_SHELL_CMD_MAIN_ATTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  uint8_t  humi_high8bit;                //ԭʼ<D4AD><CABC><EFBFBD>ݣ<EFBFBD>ʪ<EFBFBD>ȸ<EFBFBD>8λ
 | 
				
			||||||
 | 
					  uint8_t  humi_low8bit;                 //ԭʼ<D4AD><CABC><EFBFBD>ݣ<EFBFBD>ʪ<EFBFBD>ȵ<EFBFBD>8λ
 | 
				
			||||||
 | 
					  uint8_t  temp_high8bit;                 //ԭʼ<D4AD><CABC><EFBFBD>ݣ<EFBFBD><DDA3>¶ȸ<C2B6>8λ
 | 
				
			||||||
 | 
					  uint8_t  temp_low8bit;                 //ԭʼ<D4AD><CABC><EFBFBD>ݣ<EFBFBD><DDA3>¶ȸ<C2B6>8λ
 | 
				
			||||||
 | 
					  uint8_t  check_sum;                     //У<><D0A3><EFBFBD>
 | 
				
			||||||
 | 
					  double    humidity;        //ʵ<><CAB5>ʪ<EFBFBD><CAAA>
 | 
				
			||||||
 | 
					  double    temperature;     //ʵ<><CAB5><EFBFBD>¶<EFBFBD>  
 | 
				
			||||||
 | 
					} DHT11_Data_TypeDef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint16_t GetNextPackID(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						 static uint16_t pubpacketid = 0;
 | 
				
			||||||
 | 
						 return pubpacketid++;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int32_t WaitForPacket(int32_t sock,uint8_t packettype,uint8_t times)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						  int32_t type;
 | 
				
			||||||
 | 
							uint8_t buf[MSG_MAX_LEN];
 | 
				
			||||||
 | 
						  uint8_t n = 0;
 | 
				
			||||||
 | 
							int32_t buflen = sizeof(buf);
 | 
				
			||||||
 | 
							do
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
									//读取数据包
 | 
				
			||||||
 | 
									type = ReadPacketTimeout(sock,buf,buflen,2);
 | 
				
			||||||
 | 
								  if(type != -1)
 | 
				
			||||||
 | 
										mqtt_pktype_ctl(type,buf,buflen);
 | 
				
			||||||
 | 
									n++;
 | 
				
			||||||
 | 
							}while((type != packettype)&&(n < times));
 | 
				
			||||||
 | 
							//收到期望的包
 | 
				
			||||||
 | 
							if(type == packettype)
 | 
				
			||||||
 | 
								 return 0;
 | 
				
			||||||
 | 
							else 
 | 
				
			||||||
 | 
								 return -1;		
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int32_t MQTTMsgPublish(int32_t sock, char *topic, int8_t qos, uint8_t* msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int8_t retained = 0;      //保留标志位
 | 
				
			||||||
 | 
					    uint32_t msg_len;         //数据长度
 | 
				
			||||||
 | 
							uint8_t buf[MSG_MAX_LEN];
 | 
				
			||||||
 | 
							int32_t buflen = sizeof(buf),len;
 | 
				
			||||||
 | 
							MQTTString topicString = MQTTString_initializer;
 | 
				
			||||||
 | 
						  uint16_t packid = 0,packetidbk;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
							//填充主题
 | 
				
			||||||
 | 
						  topicString.cstring = (char *)topic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  //填充数据包ID
 | 
				
			||||||
 | 
						  if((qos == QOS1)||(qos == QOS2))
 | 
				
			||||||
 | 
							{ 
 | 
				
			||||||
 | 
								packid = GetNextPackID();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								  qos = QOS0;
 | 
				
			||||||
 | 
								  retained = 0;
 | 
				
			||||||
 | 
								  packid = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					    msg_len = strlen((char *)msg);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
							//推送消息
 | 
				
			||||||
 | 
							len = MQTTSerialize_publish(buf, buflen, 0, qos, retained, packid, topicString, (unsigned char*)msg, msg_len);
 | 
				
			||||||
 | 
							if(len <= 0)
 | 
				
			||||||
 | 
									return -1;
 | 
				
			||||||
 | 
							if(transport_sendPacketBuffer(buf, len) < 0)	
 | 
				
			||||||
 | 
									return -2;	
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//质量等级0,不需要返回
 | 
				
			||||||
 | 
							if(qos == QOS0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//等级1
 | 
				
			||||||
 | 
							if(qos == QOS1)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
									//等待PUBACK
 | 
				
			||||||
 | 
								  if(WaitForPacket(sock,PUBACK,5) < 0)
 | 
				
			||||||
 | 
										 return -3;
 | 
				
			||||||
 | 
									return 1;
 | 
				
			||||||
 | 
								  
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							//等级2
 | 
				
			||||||
 | 
							if(qos == QOS2)	
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								  //等待PUBREC
 | 
				
			||||||
 | 
								  if(WaitForPacket(sock,PUBREC,5) < 0)
 | 
				
			||||||
 | 
										 return -3;
 | 
				
			||||||
 | 
								  //发送PUBREL
 | 
				
			||||||
 | 
					        len = MQTTSerialize_pubrel(buf, buflen,0, packetidbk);
 | 
				
			||||||
 | 
									if(len == 0)
 | 
				
			||||||
 | 
										return -4;
 | 
				
			||||||
 | 
									if(transport_sendPacketBuffer(buf, len) < 0)	
 | 
				
			||||||
 | 
										return -6;			
 | 
				
			||||||
 | 
								  //等待PUBCOMP
 | 
				
			||||||
 | 
								  if(WaitForPacket(sock,PUBREC,5) < 0)
 | 
				
			||||||
 | 
										 return -7;
 | 
				
			||||||
 | 
									return 2;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							//等级错误
 | 
				
			||||||
 | 
							return -8;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void *MqttSocketSendTask(void *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int fd = -1, clientfd;
 | 
				
			||||||
 | 
					    int recv_len;
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					    char *recv_buf;
 | 
				
			||||||
 | 
					    struct sockaddr_in mqtt_addr;
 | 
				
			||||||
 | 
					    socklen_t addr_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     fd = socket(AF_INET, SOCK_STREAM, 0);
 | 
				
			||||||
 | 
					    if (fd < 0) {
 | 
				
			||||||
 | 
					        lw_print("Socket error\n");
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct sockaddr_in mqtt_sock;
 | 
				
			||||||
 | 
					    mqtt_sock.sin_family = AF_INET;
 | 
				
			||||||
 | 
					    mqtt_sock.sin_port = htons(mqtt_socket_port);
 | 
				
			||||||
 | 
					    mqtt_sock.sin_addr.s_addr = inet_addr(mqtt_ip_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memset(&(mqtt_sock.sin_zero), 0, sizeof(mqtt_sock.sin_zero));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = connect(fd, (struct sockaddr *)&mqtt_sock, sizeof(struct sockaddr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ret < 0) {
 | 
				
			||||||
 | 
					        lw_print("Unable to connect %s:%d = %d\n", mqtt_ip_str, mqtt_socket_port, ret);
 | 
				
			||||||
 | 
					        close(fd);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lw_print("MQTT connect %s:%d success, begin to verify hostname and password.\n", mqtt_ip_str, mqtt_socket_port);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if(MQTT_Connect() != Connect_OK)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        lw_print("MQTT verify failed.\n");
 | 
				
			||||||
 | 
					        shutdown(fd, SHUT_WR);
 | 
				
			||||||
 | 
					        recv(fd, NULL, (size_t)0, 0);
 | 
				
			||||||
 | 
					        close(fd);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lw_print("MQTT subscribe begin.\n");
 | 
				
			||||||
 | 
					    if(MQTTSubscribe(fd,(char *)TOPIC,QOS1) < 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        lw_print("MQTT subscribe failed.\n");
 | 
				
			||||||
 | 
					        shutdown(fd, SHUT_WR);
 | 
				
			||||||
 | 
					        recv(fd, NULL, (size_t)0, 0);
 | 
				
			||||||
 | 
					        close(fd);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lw_print("subscribe success.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint8_t no_mqtt_msg_exchange = 1;
 | 
				
			||||||
 | 
					    uint32_t curtick=0;
 | 
				
			||||||
 | 
					    uint8_t res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON* cJSON_Data = NULL;
 | 
				
			||||||
 | 
					    cJSON_Data = cJSON_Data_Init();
 | 
				
			||||||
 | 
					    DHT11_Data_TypeDef* recv_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    double a,b;
 | 
				
			||||||
 | 
					    while(1)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      curtick+=1;
 | 
				
			||||||
 | 
					      char* p ="Hello,here is hc";
 | 
				
			||||||
 | 
					      ret = MQTTMsgPublish(fd,(char*)TOPIC,QOS0,(uint8_t*)p);
 | 
				
			||||||
 | 
					      if(ret >= 0)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					          no_mqtt_msg_exchange = 0;
 | 
				
			||||||
 | 
					          PrivTaskDelay(1000);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MqttSocketSendTest(int argc, char *argv[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(argc >= 2) {
 | 
				
			||||||
 | 
					        lw_print("lw: [%s] target ip %s\n", __func__, argv[1]);
 | 
				
			||||||
 | 
					        MqttSocketConfigParam(argv[1]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // ip4_addr_t dns_ip;
 | 
				
			||||||
 | 
					    // netconn_gethostbyname(HOST_NAME, &dns_ip);
 | 
				
			||||||
 | 
					    // char* host_ip = ip_ntoa(&dns_ip);
 | 
				
			||||||
 | 
					    // lw_print("host name : %s , host_ip : %s\n",HOST_NAME,host_ip);
 | 
				
			||||||
 | 
					    // MqttSocketConfigParam(host_ip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef ADD_XIZI_FEATURES
 | 
				
			||||||
 | 
					    lwip_config_tcp(0, mqtt_demo_ipaddr, mqtt_demo_netmask, mqtt_demo_gwaddr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pthread_attr_t attr;
 | 
				
			||||||
 | 
					    attr.schedparam.sched_priority = LWIP_MQTT_DEMO_TASK_PRIO;
 | 
				
			||||||
 | 
					    attr.stacksize = LWIP_MQTT_DEMO_TASK_STACK_SIZE;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef ADD_NUTTX_FEATURES
 | 
				
			||||||
 | 
					    pthread_attr_t attr = PTHREAD_ATTR_INITIALIZER;
 | 
				
			||||||
 | 
					    attr.priority = LWIP_mqtt_DEMO_TASK_PRIO;
 | 
				
			||||||
 | 
					    attr.stacksize = LWIP_mqtt_DEMO_TASK_STACK_SIZE;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PrivTaskCreate(&mqtt_client_task, &attr, &MqttSocketSendTask, NULL);
 | 
				
			||||||
 | 
					    PrivTaskStartup(&mqtt_client_task);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PRIV_SHELL_CMD_FUNCTION(MqttSocketSendTest, a tcp send sample, PRIV_SHELL_CMD_MAIN_ATTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,99 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) 2022 AIIT XUOS Lab
 | 
				
			||||||
 | 
					 * XiUOS is licensed under Mulan PSL v2.
 | 
				
			||||||
 | 
					 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 | 
				
			||||||
 | 
					 * You may obtain a copy of Mulan PSL v2 at:
 | 
				
			||||||
 | 
					 *        http://license.coscl.org.cn/MulanPSL2
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | 
				
			||||||
 | 
					 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | 
				
			||||||
 | 
					 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | 
				
			||||||
 | 
					 * See the Mulan PSL v2 for more details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @file test_mqttclient.h
 | 
				
			||||||
 | 
					 * @brief mqtt subscribe fuction test
 | 
				
			||||||
 | 
					 * @version 3.0
 | 
				
			||||||
 | 
					 * @author AIIT XUOS Lab
 | 
				
			||||||
 | 
					 * @date 2023.8.10
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define   MSG_MAX_LEN     1024
 | 
				
			||||||
 | 
					#define   MSG_TOPIC_LEN   50
 | 
				
			||||||
 | 
					#define   KEEPLIVE_TIME   650
 | 
				
			||||||
 | 
					#define   MQTT_VERSION    4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef    LWIP_DNS
 | 
				
			||||||
 | 
					#define   HOST_NAME       "iot-06z00im0uwa0ki2.mqtt.iothub.aliyuncs.com"     //服务器域名
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define   HOST_NAME       "iot-06z00im0uwa0ki2.mqtt.iothub.aliyuncs.com"     //服务器IP地址
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//#define   HOST_IP       "129.204.201.235"
 | 
				
			||||||
 | 
					#define   HOST_PORT     1883    //由于是TCP连接,端口必须是1883
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define   CLIENT_ID     "iw3rn3pa11K.test|securemode=2,signmethod=hmacsha256,timestamp=1689296035604|"         //随机的id
 | 
				
			||||||
 | 
					#define   USER_NAME     "test&iw3rn3pa11K"     //用户名
 | 
				
			||||||
 | 
					#define   PASSWORD      "7b948d22fe46f0f63d1a403376d26e7cb298abc227d29e44311d7040307a71f8"  //秘钥
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define   TOPIC         "/iw3rn3pa11K/test/user/Test"      //订阅的主题
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define   TEST_MESSAGE  "test_message"  //发送测试消息
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// #define   CLIENT_ID     "hc123456789"         //随机的id
 | 
				
			||||||
 | 
					// #define   USER_NAME     "xiuos"     //用户名
 | 
				
			||||||
 | 
					// #define   PASSWORD      "xiuos"  //秘钥
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum QoS 
 | 
				
			||||||
 | 
					{ QOS0 = 0, 
 | 
				
			||||||
 | 
					  QOS1, 
 | 
				
			||||||
 | 
					  QOS2 
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum MQTT_Connect
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  Connect_OK = 0,
 | 
				
			||||||
 | 
					  Connect_NOK,
 | 
				
			||||||
 | 
					  Connect_NOTACK
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//数据交互结构体
 | 
				
			||||||
 | 
					typedef struct __MQTTMessage
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint32_t qos;
 | 
				
			||||||
 | 
					    uint8_t retained;
 | 
				
			||||||
 | 
					    uint8_t dup;
 | 
				
			||||||
 | 
					    uint16_t id;
 | 
				
			||||||
 | 
						  uint8_t type;
 | 
				
			||||||
 | 
					    void *payload;
 | 
				
			||||||
 | 
					    int32_t payloadlen;
 | 
				
			||||||
 | 
					}MQTTMessage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//用户接收消息结构体
 | 
				
			||||||
 | 
					typedef struct __MQTT_MSG
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						  uint8_t  msgqos;                 //消息质量
 | 
				
			||||||
 | 
							uint8_t  msg[MSG_MAX_LEN];       //消息
 | 
				
			||||||
 | 
						  uint32_t msglenth;               //消息长度
 | 
				
			||||||
 | 
						  uint8_t  topic[MSG_TOPIC_LEN];   //主题    
 | 
				
			||||||
 | 
						  uint16_t packetid;               //消息ID
 | 
				
			||||||
 | 
						  uint8_t  valid;                  //标明消息是否有效
 | 
				
			||||||
 | 
					}MQTT_USER_MSG;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//发送消息结构体
 | 
				
			||||||
 | 
					typedef struct
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int8_t topic[MSG_TOPIC_LEN];
 | 
				
			||||||
 | 
					    int8_t qos;
 | 
				
			||||||
 | 
					    int8_t retained;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint8_t msg[MSG_MAX_LEN];
 | 
				
			||||||
 | 
					    uint8_t msglen;
 | 
				
			||||||
 | 
					} mqtt_recv_msg_t, *p_mqtt_recv_msg_t, mqtt_send_msg_t, *p_mqtt_send_msg_t;
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,67 @@
 | 
				
			||||||
 | 
					# 基于矽璓已实现的Lwip,在ARM上实现基本的Web服务##
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 1. 简介
 | 
				
			||||||
 | 
					基于矽璓已实现的Lwip,在ARM上实现基本的Web服务,其功能支持IP、GateWay、DNS、子网掩码等网络参数的设置。
 | 
				
			||||||
 | 
					主要功能为:web服务等待Http请求的到来,解析Http报文后,设置本机的网络参数信息,在终端打印设置后的网络参数信息,并返回浏览器客户端成功响应。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2. 数据结构设计说明
 | 
				
			||||||
 | 
					Server的网络结构参数为:
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					struct ServerNet 
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char local_ip[20];
 | 
				
			||||||
 | 
					    char local_mask[20];
 | 
				
			||||||
 | 
					    char local_gw[20];
 | 
				
			||||||
 | 
					    char local_dns[20];
 | 
				
			||||||
 | 
					}ServerNet;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					主要实现了以下几个函数:
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					TcpThread:  建立socket监听,循环等待网络通信事件的到来;
 | 
				
			||||||
 | 
					HandleHttpRequest:处理并解析Http报文,得到网络参数信息;
 | 
				
			||||||
 | 
					AddrUpdate: 根据到来的参数,更新本机网络参数;
 | 
				
			||||||
 | 
					LwipShowIP:显示网络参数信息,包括IP、GateWay、DNS、子网掩码;
 | 
				
			||||||
 | 
					LwipSetIP: 设置网络参数信息,包括IP、GateWay、DNS、子网掩码;
 | 
				
			||||||
 | 
					ShowDns: 显示dns网址; 
 | 
				
			||||||
 | 
					SetDns: 设置dns网址;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					除此之外,还包括两个工具函数:
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					SubstractServerNet: 截取http报文的请求体,格式为:ip=192.168.1.9&netmask=255.255.255.0&iproute=192.168.1.1&dns=114.114.114.114
 | 
				
			||||||
 | 
					substring: 截取字符串
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3. 测试程序说明
 | 
				
			||||||
 | 
					1. 通过数据线将开发板连接电脑,并通过网线连接使开发板接入家庭局域网。
 | 
				
			||||||
 | 
					2. 将TestWebserver注册为shell 命令,编译前通过menuconfig打开lwip和TestWebserver功能。
 | 
				
			||||||
 | 
					3. 将编译成功的XiZi-edu-arm32.bin文件烧录到arm板子。烧录bin文件前,需要将开发板boot引脚拉高(盖上跳帽),上电后再按下reset按键,之后可以点击烧写工具的执行按钮,等待烧写完成。
 | 
				
			||||||
 | 
					4. 将boot引脚拉低(摘下跳帽),按下reset按键,使用串口工具显示xiuos的命令行界面。
 | 
				
			||||||
 | 
					5. 将开发板的本机ip通过setip命令设置为与电脑端在同一个局域网之下,利用ping命令检测成功通信。
 | 
				
			||||||
 | 
					6. 运行TestWebserver命令验证功能。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 4. 运行结果(##需结合运行测试截图按步骤说明##)
 | 
				
			||||||
 | 
					<img width="800" src="./photos/1.png"/>  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					烧录程序,boot引脚拉高,按下reset按键。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<img width="800"  src="./photos/2.png"/>  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					点击执行烧录,程序烧录成功。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<img width="800" src="./photos/3.png"/>  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					打开串口调试工具,xiuos程序成功在开发板上运行。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<img width="800"  src="./photos/4.png"/>  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					利用setip命令,修改开发板ip,使得开发板和电脑在同一个局域网内,并使用ping命令测试。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<img width="800"  src="./photos/5.png"/>  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					在服务端运行TestWebserver命令,打开index.html,设置网络参数信息,点击提交,发送http请求。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<img width="800"  src="./photos/6.png"/> 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					web服务收到http请求后并打印post请求报文,以及修改后的开发板的网络参数信息,包括IP、子网掩码、GateWay和DNS。
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,33 @@
 | 
				
			||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html lang="en">
 | 
				
			||||||
 | 
					<head>
 | 
				
			||||||
 | 
					    <meta charset="UTF-8">
 | 
				
			||||||
 | 
					    <title>表单</title>
 | 
				
			||||||
 | 
					</head>
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!--
 | 
				
			||||||
 | 
					表单form
 | 
				
			||||||
 | 
					action:表单提交的位置,可以是网站,也可以是一个请求处理地址
 | 
				
			||||||
 | 
					method:有post,get提交方式
 | 
				
			||||||
 | 
					-->
 | 
				
			||||||
 | 
					<form action="http://192.168.1.5/" method="post">
 | 
				
			||||||
 | 
					  <h2>设置路由信息</h2>
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					<!--
 | 
				
			||||||
 | 
					<input type="text">是文本输入框
 | 
				
			||||||
 | 
					<input type="password">是密码输入框,默认是用小黑点表示密码的
 | 
				
			||||||
 | 
					-->
 | 
				
			||||||
 | 
					    <p>IP地址:<input type="text" name="ip"></p>
 | 
				
			||||||
 | 
					    <p>子网掩码:<input type="text" name="netmask"></p>
 | 
				
			||||||
 | 
					    <p>默认网关:<input type="text" name="iproute"></p>
 | 
				
			||||||
 | 
					    <p>DNS服务器<input type="text" name="dns"></p>
 | 
				
			||||||
 | 
					    <p>
 | 
				
			||||||
 | 
					        <input type="submit">
 | 
				
			||||||
 | 
					        <input type="reset">
 | 
				
			||||||
 | 
					    </p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 19 MiB  | 
| 
		 After Width: | Height: | Size: 180 KiB  | 
| 
		 After Width: | Height: | Size: 81 KiB  | 
| 
		 After Width: | Height: | Size: 101 KiB  | 
| 
		 After Width: | Height: | Size: 52 KiB  | 
| 
		 After Width: | Height: | Size: 175 KiB  | 
| 
						 | 
					@ -0,0 +1,218 @@
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					* @file:    test_webserver.c
 | 
				
			||||||
 | 
					* @brief:   a application of test webserver function
 | 
				
			||||||
 | 
					* @version: 1.0
 | 
				
			||||||
 | 
					* @author:  Yao wenying
 | 
				
			||||||
 | 
					* @date:    2023/08/20
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <transform.h>
 | 
				
			||||||
 | 
					#include "test_webserver.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**设置ip,网关,子网掩码这部分参考lwip_config_demo.c*/
 | 
				
			||||||
 | 
					void LwipShowIP()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // find default netdev
 | 
				
			||||||
 | 
					    lw_notice("\r\n************************************************\r\n");
 | 
				
			||||||
 | 
					    lw_notice(" Network Configuration\r\n");
 | 
				
			||||||
 | 
					    lw_notice("************************************************\r\n");
 | 
				
			||||||
 | 
					    lw_notice(" ETH0 IPv4 Address   : %u.%u.%u.%u\r\n", ((u8_t*)&lwip_eth0_ipaddr)[0], ((u8_t*)&lwip_eth0_ipaddr)[1],
 | 
				
			||||||
 | 
					        ((u8_t*)&lwip_eth0_ipaddr)[2], ((u8_t*)&lwip_eth0_ipaddr)[3]);
 | 
				
			||||||
 | 
					    lw_notice(" ETH0 IPv4 Subnet mask : %u.%u.%u.%u\r\n", ((u8_t*)&lwip_eth0_netmask)[0], ((u8_t*)&lwip_eth0_netmask)[1],
 | 
				
			||||||
 | 
					        ((u8_t*)&lwip_eth0_netmask)[2], ((u8_t*)&lwip_eth0_netmask)[3]);
 | 
				
			||||||
 | 
					    lw_notice(" ETH0 IPv4 Gateway   : %u.%u.%u.%u\r\n", ((u8_t*)&lwip_gwaddr)[0], ((u8_t*)&lwip_eth0_gwaddr)[1],
 | 
				
			||||||
 | 
					        ((u8_t*)&lwip_eth0_gwaddr)[2], ((u8_t*)&lwip_eth0_gwaddr)[3]);
 | 
				
			||||||
 | 
					    lw_notice("************************************************\r\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t enet_idd = 0;
 | 
				
			||||||
 | 
					void LwipSetIP(int argc, char *argv[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(argc >= 4)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        printf("lw: [%s] ip %s mask %s gw %s netport %s\n", __func__, argv[1], argv[2], argv[3], argv[4]);
 | 
				
			||||||
 | 
					        sscanf(argv[1], "%d.%d.%d.%d", &lwip_ipaddr[0], &lwip_ipaddr[1], &lwip_ipaddr[2], &lwip_ipaddr[3]);
 | 
				
			||||||
 | 
					        sscanf(argv[2], "%d.%d.%d.%d", &lwip_netmask[0], &lwip_netmask[1], &lwip_netmask[2], &lwip_netmask[3]);
 | 
				
			||||||
 | 
					        sscanf(argv[3], "%d.%d.%d.%d", &lwip_gwaddr[0], &lwip_gwaddr[1], &lwip_gwaddr[2], &lwip_gwaddr[3]);
 | 
				
			||||||
 | 
					        sscanf(argv[4], "%d", &enet_idd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(0 == enet_idd)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            printf("save eth0 info\n");
 | 
				
			||||||
 | 
					            memcpy(lwip_eth0_ipaddr, lwip_ipaddr, 20);
 | 
				
			||||||
 | 
					            memcpy(lwip_eth0_netmask, lwip_netmask, 20);
 | 
				
			||||||
 | 
					            memcpy(lwip_eth0_gwaddr, lwip_gwaddr, 20);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if(1 == enet_idd)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            printf("save eth1 info\n");
 | 
				
			||||||
 | 
					            memcpy(lwip_eth1_ipaddr, lwip_ipaddr, 20);
 | 
				
			||||||
 | 
					            memcpy(lwip_eth1_netmask, lwip_netmask, 20);
 | 
				
			||||||
 | 
					            memcpy(lwip_eth1_gwaddr, lwip_gwaddr, 20);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if(argc == 2)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        printf("lw: [%s] set eth0 ipaddr %s \n", __func__, argv[1]);
 | 
				
			||||||
 | 
					        sscanf(argv[1], "%d.%d.%d.%d", &lwip_ipaddr[0], &lwip_ipaddr[1], &lwip_ipaddr[2], &lwip_ipaddr[3]);
 | 
				
			||||||
 | 
					        memcpy(lwip_eth0_ipaddr, lwip_ipaddr, strlen(lwip_ipaddr));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // sys_thread_new("SET ip address", LwipSetIPTask, &enet_id, LWIP_TASK_STACK_SIZE, LWIP_DEMO_TASK_PRIO);
 | 
				
			||||||
 | 
					    printf("lw: [%s] config netport id[%d]\n", __func__, enet_idd);
 | 
				
			||||||
 | 
					    lwip_config_net(enet_idd, lwip_ipaddr, lwip_netmask, lwip_gwaddr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ShowDns(){
 | 
				
			||||||
 | 
					    const ip_addr_t *dns = dns_getserver(0);
 | 
				
			||||||
 | 
					    char *dns_ip = ipaddr_ntoa(dns);
 | 
				
			||||||
 | 
					    printf("lw: eth0 dns is %s \n", dns_ip);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SetDns(char* ip){
 | 
				
			||||||
 | 
					    ip_addr_t dns;
 | 
				
			||||||
 | 
					    ipaddr_aton(ip, &dns);	
 | 
				
			||||||
 | 
					    dns_setserver(0, &dns);
 | 
				
			||||||
 | 
					    printf("ETH0 Set DNS Success!\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void AddrUpdate()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char *argv[5];
 | 
				
			||||||
 | 
					    argv[1] = ServerNet.local_ip;
 | 
				
			||||||
 | 
					    argv[2] = ServerNet.local_mask;
 | 
				
			||||||
 | 
					    argv[3] = ServerNet.local_gw ;
 | 
				
			||||||
 | 
					    argv[4] = 0;
 | 
				
			||||||
 | 
					    LwipSetIP(4, argv); 
 | 
				
			||||||
 | 
					    LwipShowIP();
 | 
				
			||||||
 | 
					    SetDns(ServerNet.local_dns);
 | 
				
			||||||
 | 
					    ShowDns();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *substring(char *dst,char *src,int start,int len)
 | 
				
			||||||
 | 
					{  
 | 
				
			||||||
 | 
						char *p=dst;  
 | 
				
			||||||
 | 
						char *q=src;  
 | 
				
			||||||
 | 
						int length=strlen(src); 
 | 
				
			||||||
 | 
						if(start>=length||start<0) 
 | 
				
			||||||
 | 
							return NULL;  
 | 
				
			||||||
 | 
						if(len>length) 
 | 
				
			||||||
 | 
							len=length-start; 
 | 
				
			||||||
 | 
						q+=start;
 | 
				
			||||||
 | 
						while(len--)  
 | 
				
			||||||
 | 
						{   
 | 
				
			||||||
 | 
							*(p++)=*(q++); 
 | 
				
			||||||
 | 
						}  
 | 
				
			||||||
 | 
						*(p++)='\0';  
 | 
				
			||||||
 | 
						return dst;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SubstractServerNet(char * params){
 | 
				
			||||||
 | 
					    char *p =params;
 | 
				
			||||||
 | 
					    p +=3;
 | 
				
			||||||
 | 
					    char *end = strchr(p, '&');
 | 
				
			||||||
 | 
					    int len = (int)(end-p);
 | 
				
			||||||
 | 
					    substring(ServerNet.local_ip, p, 0,len);
 | 
				
			||||||
 | 
					    p +=len;
 | 
				
			||||||
 | 
					    p += 9;
 | 
				
			||||||
 | 
					    end = strchr(p, '&');
 | 
				
			||||||
 | 
					    len = (int)(end-p);
 | 
				
			||||||
 | 
					    substring(ServerNet.local_mask , p, 0, len);
 | 
				
			||||||
 | 
					    p +=len;
 | 
				
			||||||
 | 
					    p +=9;
 | 
				
			||||||
 | 
					    end = strchr(p, '&');
 | 
				
			||||||
 | 
					    len = (int)(end-p);
 | 
				
			||||||
 | 
					    substring(ServerNet.local_gw, p, 0, len);
 | 
				
			||||||
 | 
					    p +=len;
 | 
				
			||||||
 | 
					    p += 5;
 | 
				
			||||||
 | 
					    strcpy(ServerNet.local_dns, p);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void HandleHttpRequest(char *params){
 | 
				
			||||||
 | 
					    SubstractServerNet(params);
 | 
				
			||||||
 | 
					    AddrUpdate(); //修改本机参数信息;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//设置socket
 | 
				
			||||||
 | 
					//循环监听socket并修改网络信息,单线程
 | 
				
			||||||
 | 
					void tcpecho_thread(){
 | 
				
			||||||
 | 
					    int sock=-1, connected;
 | 
				
			||||||
 | 
					    char *recv_data;
 | 
				
			||||||
 | 
					    struct sockaddr_in server_addr, client_addr;
 | 
				
			||||||
 | 
					    socklen_t sin_size;
 | 
				
			||||||
 | 
					    int recv_data_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    recv_data = (char *) malloc(RECV_DATA);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(recv_data == NULL){
 | 
				
			||||||
 | 
					        printf("No memory");
 | 
				
			||||||
 | 
					        goto __exit;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sock = socket(AF_INET, SOCK_STREAM, 0);
 | 
				
			||||||
 | 
					    if(sock < 0){
 | 
				
			||||||
 | 
					        printf("Socket error\n");
 | 
				
			||||||
 | 
					        goto __exit;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    server_addr.sin_family = AF_INET;
 | 
				
			||||||
 | 
					    server_addr.sin_addr.s_addr = INADDR_ANY;
 | 
				
			||||||
 | 
					    server_addr.sin_port = htons(PORT);
 | 
				
			||||||
 | 
					    memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(bind(sock,(struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == 1){
 | 
				
			||||||
 | 
					        printf("Unable to bind\n");
 | 
				
			||||||
 | 
					        goto __exit;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (listen(sock, 5) == -1)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        printf("Listen error\n");
 | 
				
			||||||
 | 
					        goto __exit;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while(1){
 | 
				
			||||||
 | 
					        sin_size = sizeof(struct sockaddr_in);
 | 
				
			||||||
 | 
					        connected = accept(sock, (struct sockaddr *)&client_addr, &sin_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        printf("new client connected from (%s, %d)\n",
 | 
				
			||||||
 | 
					            inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            int flag = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            setsockopt(connected,
 | 
				
			||||||
 | 
					                    IPPROTO_TCP,     /* set option at TCP level */
 | 
				
			||||||
 | 
					                    TCP_NODELAY,     /* name of option */
 | 
				
			||||||
 | 
					                    (void *) &flag, /* the cast is historical cruft */
 | 
				
			||||||
 | 
					                    sizeof(int));    /* length of option value */
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        recv_data_len = recv(connected, recv_data, RECV_DATA, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        printf("recv %d len data\n",recv_data_len);
 | 
				
			||||||
 | 
					        recv_data[recv_data_len] = '\0';
 | 
				
			||||||
 | 
					        printf("%s\n", recv_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        char * params = strstr(recv_data, "ip=");
 | 
				
			||||||
 | 
					        HandleHttpRequest(params);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        char *response = "HTTP/1.1 200 OK\r\n"
 | 
				
			||||||
 | 
					                         "Content-Type: application/x-www-form-urlencoded\r\n"
 | 
				
			||||||
 | 
					                         "\r\n";
 | 
				
			||||||
 | 
					        write(connected,response,strlen(response));
 | 
				
			||||||
 | 
					        if (connected >= 0)
 | 
				
			||||||
 | 
					            closesocket(connected);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        connected = -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    __exit:
 | 
				
			||||||
 | 
					    if (sock >= 0) closesocket(sock);
 | 
				
			||||||
 | 
					    if (recv_data) free(recv_data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void TestWebserver(){
 | 
				
			||||||
 | 
					    tcpecho_thread();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PRIV_SHELL_CMD_FUNCTION(TestWebserver, Implement web_server, PRIV_SHELL_CMD_MAIN_ATTR);
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,43 @@
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					* @file:    test_webserver.h
 | 
				
			||||||
 | 
					* @brief:   a application of test webserver function
 | 
				
			||||||
 | 
					* @version: 1.0
 | 
				
			||||||
 | 
					* @author:  Yao wenying
 | 
				
			||||||
 | 
					* @date:    2023/08/20
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __WEBSERVER_H__
 | 
				
			||||||
 | 
					#define __WEBSERVER_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "lwip/opt.h"
 | 
				
			||||||
 | 
					#include <lwip/sockets.h>
 | 
				
			||||||
 | 
					#include "lwip/api.h"
 | 
				
			||||||
 | 
					#include "lwip/sys.h"
 | 
				
			||||||
 | 
					#include "netif/ethernet.h"
 | 
				
			||||||
 | 
					#include "lwip/tcpip.h"
 | 
				
			||||||
 | 
					#include "sys_arch.h"
 | 
				
			||||||
 | 
					#include <netdev.h>
 | 
				
			||||||
 | 
					#include "dns.h"
 | 
				
			||||||
 | 
					#include "string.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PORT              80
 | 
				
			||||||
 | 
					#define RECV_DATA         1024
 | 
				
			||||||
 | 
					struct ServerNet 
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char local_ip[20];
 | 
				
			||||||
 | 
					    char local_mask[20];
 | 
				
			||||||
 | 
					    char local_gw[20];
 | 
				
			||||||
 | 
					    char local_dns[20];
 | 
				
			||||||
 | 
					}ServerNet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void LwipShowIP();
 | 
				
			||||||
 | 
					void LwipSetIP(int argc, char *argv[]); 
 | 
				
			||||||
 | 
					void ShowDns();
 | 
				
			||||||
 | 
					void SetDns();
 | 
				
			||||||
 | 
					void AddrUpdate();  //更新本机网络参数信息
 | 
				
			||||||
 | 
					void HandleHttpRequest(); //解析报文,并返回响应
 | 
				
			||||||
 | 
					void TcpThread();//建立socket监听,循环等待网络通信事件到来
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,4 @@
 | 
				
			||||||
SRC_FILES :=  cJSON.c
 | 
					SRC_FILES :=  cJSON.c
 | 
				
			||||||
 | 
					SRC_FILES +=  cJSON_Process.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include $(KERNEL_ROOT)/compiler.mk
 | 
					include $(KERNEL_ROOT)/compiler.mk
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,85 @@
 | 
				
			||||||
 | 
					#include "cJSON_Process.h"
 | 
				
			||||||
 | 
					#include <lwip/sockets.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cJSON* cJSON_Data_Init(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  cJSON* cJSON_Root = NULL;    //json根节点
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  cJSON_Root = cJSON_CreateObject();  /*创建项目*/
 | 
				
			||||||
 | 
					  if(NULL == cJSON_Root)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					      return NULL;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  cJSON_AddStringToObject(cJSON_Root, NAME, DEFAULT_NAME);  /*添加元素  键值对*/
 | 
				
			||||||
 | 
					  cJSON_AddNumberToObject(cJSON_Root, TEMP_NUM, DEFAULT_TEMP_NUM);
 | 
				
			||||||
 | 
					  cJSON_AddNumberToObject(cJSON_Root, HUM_NUM, DEFAULT_HUM_NUM);
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  char* p = cJSON_Print(cJSON_Root);  /*p 指向的字符串是json格式的*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  p = NULL;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  return cJSON_Root;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					uint8_t cJSON_Update(const cJSON * const object,const char * const string,void *d)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  cJSON* node = NULL;    //json根节点
 | 
				
			||||||
 | 
					  node = cJSON_GetObjectItem(object,string);
 | 
				
			||||||
 | 
					  if(node == NULL)
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					  if(cJSON_IsBool(node))
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    int *b = (int*)d;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON_GetObjectItem(object,string)->type = *b ? cJSON_True : cJSON_False;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else if(cJSON_IsString(node))
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    cJSON_GetObjectItem(object,string)->valuestring = (char*)d;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else if(cJSON_IsNumber(node))
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    double *num = (double*)d;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cJSON_GetObjectItem(object,string)->valuedouble = (double)*num;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Proscess(void* data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  cJSON *root,*json_name,*json_temp_num,*json_hum_num;
 | 
				
			||||||
 | 
					  root = cJSON_Parse((char*)data); //解析成json形式
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  json_name = cJSON_GetObjectItem( root , NAME);   //获取键值内容
 | 
				
			||||||
 | 
					  json_temp_num = cJSON_GetObjectItem( root , TEMP_NUM );
 | 
				
			||||||
 | 
					  json_hum_num = cJSON_GetObjectItem( root , HUM_NUM );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  lw_print("name:%s\n temp_num:%f\n hum_num:%f\n",
 | 
				
			||||||
 | 
					              json_name->valuestring,
 | 
				
			||||||
 | 
					              json_temp_num->valuedouble,
 | 
				
			||||||
 | 
					              json_hum_num->valuedouble);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  cJSON_Delete(root); //释放内存 
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,23 @@
 | 
				
			||||||
 | 
					#ifndef _CJSON_PROCESS_H_
 | 
				
			||||||
 | 
					#define _CJSON_PROCESS_H_
 | 
				
			||||||
 | 
					#include "cJSON.h"
 | 
				
			||||||
 | 
					#include "stdint.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define   NAME            "name"     
 | 
				
			||||||
 | 
					#define   TEMP_NUM        "temp"  
 | 
				
			||||||
 | 
					#define   HUM_NUM         "hum" 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define   DEFAULT_NAME          "fire"     
 | 
				
			||||||
 | 
					#define   DEFAULT_TEMP_NUM       25.0 
 | 
				
			||||||
 | 
					#define   DEFAULT_HUM_NUM        50.0 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define   UPDATE_SUCCESS       1 
 | 
				
			||||||
 | 
					#define   UPDATE_FAIL          0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cJSON* cJSON_Data_Init(void);
 | 
				
			||||||
 | 
					uint8_t cJSON_Update(const cJSON * const object,const char * const string,void * d);
 | 
				
			||||||
 | 
					void Proscess(void* data);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||