2023_open_source_contest_preliminary_1st_issue3 from 东华大学_第二乐章战队_方源
it is OK
| 
						 | 
				
			
			@ -286,6 +286,10 @@ menu "test app"
 | 
			
		|||
                bool "Config test ftp client"
 | 
			
		||||
                default n
 | 
			
		||||
            
 | 
			
		||||
            menuconfig USER_TEST_FTPCLIENT_RISCV
 | 
			
		||||
                bool "Config test ftp client on riscv"
 | 
			
		||||
                default n
 | 
			
		||||
 | 
			
		||||
            menuconfig USER_TEST_LORA_P2P
 | 
			
		||||
                bool "Config test lora p2p"
 | 
			
		||||
                default n
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -124,7 +124,7 @@ ifeq ($(CONFIG_ADD_XIZI_FEATURES),y)
 | 
			
		|||
    ifeq ($(CONFIG_USER_TEST_MODBUS_TCP),y)
 | 
			
		||||
        SRC_DIR += test_modbus_tcp
 | 
			
		||||
    endif 
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
    ifeq ($(CONFIG_USER_TEST_WEBSERVER),y)
 | 
			
		||||
        SRC_FILES += test_webserver/test_webserver.c
 | 
			
		||||
    endif
 | 
			
		||||
| 
						 | 
				
			
			@ -139,6 +139,10 @@ ifeq ($(CONFIG_ADD_XIZI_FEATURES),y)
 | 
			
		|||
                     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
 | 
			
		||||
 | 
			
		||||
    ifeq ($(CONFIG_USER_TEST_LORA_P2P),y)
 | 
			
		||||
        SRC_FILES += 
 | 
			
		||||
    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();
 | 
			
		||||