GD32+W5500实现FTP传输多个COMTRADE文件的详细设计。
1、使用W5500实现FTP是基于TCP协议来实现的;
2、FTP通信时,需要两个socket,1个用于走控制数据,一个用于走数据;
3、FTP通信时,W5500做客户端,与FTP服务器通信,FTP服务器支持主动模式与被动模式,主动模式为W5500告诉FTP服务器ip地址和端口号,FTP服务器用新的socket做客户端连接W5500的服务器socket,目前采用主动模式;
4、单个文件交互流程:(红色为命令socket传输内容,绿色为数据socket传输内容)
W5500发起对服务器的连接
输入用户名、密码
使用PORT $ip $端口告诉FTP服务器ip地址和端口
通过STOR命令传输文件名
传输文件
使用QUIT命令退出传输
发送discon命令断开连接
5、传输多个文件时我采用的方法是循环上传单个文件,也就是
建立连接
登录
通知FTP服务器为主动模式
文件名
文件
退出
Discon
6、注意,传输完成QUIT后要给socket发discon命令,而不是close命令,这个地方一定注意。
附有新的comtrade故障录波文件产生时,即apiGetRelaymainTranFlag()不为0,数据开始传输的代码:
/*************************************************************************
*
* Copyright (C), 1999-2004, wisdom. Co., Ltd.
*
* 文件名称: appEthernet.c
* 软件模块: <APP>
* 版 本 号: 1.0
* 生成日期: 2023-11-30
* 作 者: Ben
* 功 能: <以太网通信模块>
*
*************************************************************************/
#include "apiInclude.h"
#include "appInclude.h"
/* FTP Responses */
#define R_150 150 /* File status ok; opening data conn */
#define R_200 200 /* 'Generic' command ok */
#define R_220 220 /* Service ready for new user. */
#define R_221 221 /* 服务正在关闭 */
#define R_225 225 /* 数据连接打开 */
#define R_226 226 /* Closing data connection. File transfer/abort successful */
#define R_227 227 /* Entering passive mode (h1,h2,h3,h4,p1,p2) */
#define R_230 230 /* User logged in, proceed */
#define R_250 250 /* 请求文件操作已完成 */
#define R_257 257 /* 路径创建成功 */
#define R_331 331 /* User name okay, need password. */
/* 传输数据类型 */
#define TransferAscii 'A'
#define TransferBinary 'I'
/* FTP客户端状态定义 */
#define FTP_CLIENT_STATE_IDLE 0 /* 空闲 */
#define FTP_CLIENT_STATE_LOGIN 1 /* 登录 */
#define FTP_CLIENT_STATE_LINK 2 /* FTP服务器发起对W5500server连接 */
#define FTP_CLIENT_STATE_CFG_DATA 3 /* 传CFG数据内容 */
#define FTP_CLIENT_STATE_DATA_DATA 4 /* 传DAT数据内容 */
#define FTP_CLIENT_STATE_TRAN_OK 5 /* 传输完成 */
#define FTP_CLIENT_STATE_TRAN_DONE 6 /* 传输流程结束 */
static CHAR rxbuff[2048]; /* 数据接收区 */
static CHAR szText[200]; /* 字符串缓冲区 */
/* FTP传输控制结构 */
typedef struct TFTPTranCtrl
{
BYTE byCFGOffset;
BYTE byCtrlSockState;
WORD wDATOffset;
}TFTPTranCtrl;
static TFTPTranCtrl s_FTPTranCtrl; /* FTP传输控制 */
/* 文件名,cfg,data数据结构 */
static TCOMTRADE* s_FTPCOMTRADENameFile;
static TCOMTRADECFG* s_FTPCOMTRADEFILECFGbuf;
static TCOMTRADEDAT* s_FTPCOMTRADEDAFILETRead; /* DAT文件数据结构 */
/*
[DISTURB_NUMBER_CYCLE * (DISTURB_PRE_NUMBER + DISTURB_AFTER_NUMBER)]
*/
/* FTP服务器回复报文处理 */
static void _FTPServerResponse(CHAR * buf);
/* 传输cfg文件 */
static void _FTPTranCFGFile(void);
/* 传输dat文件 */
static void _FTPTranDATFile(void);
extern BYTE byServerType;
/* FTP服务器回复报文处理 */
static void _FTPServerResponse(CHAR * buf)
{
WORD Responses;
BYTE dat[30] = {0,};
memset(dat, 0, 30);
Responses = (buf[0] - '0') * 100 + (buf[1] - '0' ) * 10 + (buf[2] - '0');
switch(Responses)
{
/* Service ready for new user. */
case R_220:
if (byServerType == 0)
{
sprintf(szText, "USER %s\r\n", "W5500");
}
else
{
sprintf(szText, "USER %s\r\n", "ubuntu");
}
Write_SOCK_Data_Buffer(0, (BYTE*)szText, strlen(szText));
break;
/* User name okay, need password. */
case R_331:
if (byServerType == 0)
{
sprintf(szText, "PASS %s\r\n", "123456");
}
else
{
sprintf(szText, "PASS %s\r\n", "ubuntu");
}
Write_SOCK_Data_Buffer(0, (BYTE*)szText, strlen(szText));
s_FTPTranCtrl.byCtrlSockState = FTP_CLIENT_STATE_LOGIN;
break;
/* User logged in, proceed */
case R_230:
//@ sprintf(szText, "TYPE %c\r\n", "TransferAscii");
//@ Write_SOCK_Data_Buffer(0, (BYTE*)szText, strlen(szText));
break;
case R_200:
break;
case R_150:
break;
case R_226:
break;
case R_227:
break;
default:
// Write_W5500_SOCK_1Byte(0, Sn_CR, CLOSE); /* 关闭socket */
// Write_W5500_SOCK_1Byte(0, Sn_IR, 0xFF);
// TW55001State.time = hwGetSystemCount();
break;
}
}
/* FTP传输任务初始化 */
BOOL appFTPInit(void)
{
DWORD dwSize;
/* 申请缓冲区 */
dwSize = sizeof(TCOMTRADE);
s_FTPCOMTRADENameFile = (TCOMTRADE*)hwMalloc(dwSize, HW_MEM_MALLOC_NORMAL);
dwSize = sizeof(TCOMTRADECFG);
s_FTPCOMTRADEFILECFGbuf = (TCOMTRADECFG*)hwMalloc(dwSize, HW_MEM_MALLOC_NORMAL);
dwSize = (sizeof(TCOMTRADEDAT) * (DISTURB_NUMBER_CYCLE * (DISTURB_PRE_NUMBER + DISTURB_AFTER_NUMBER)));
s_FTPCOMTRADEDAFILETRead = (TCOMTRADEDAT*)hwMalloc(dwSize, HW_MEM_MALLOC_NORMAL);
/* 控制结构初始化 */
s_FTPTranCtrl.byCtrlSockState = FTP_CLIENT_STATE_IDLE;
s_FTPTranCtrl.byCFGOffset = 0;
s_FTPTranCtrl.wDATOffset = 0;
return TRUE;
}
/* 传输cfg文件 */
static void _FTPTranCFGFile(void)
{
switch (s_FTPTranCtrl.byCFGOffset)
{
case 0:
strcpy(szText, s_FTPCOMTRADEFILECFGbuf->pFirstLine);
strcat(szText, "\r\n");
Write_SOCK_Data_Buffer(1, (BYTE*)szText, strlen(szText));
s_FTPTranCtrl.byCFGOffset = 1;
break;
case 1:
strcpy(szText, s_FTPCOMTRADEFILECFGbuf->pSecondLine);
strcat(szText, "\r\n");
Write_SOCK_Data_Buffer(1, (BYTE*)szText, strlen(szText));
s_FTPTranCtrl.byCFGOffset = 2;
break;
case 2:
strcpy(szText, s_FTPCOMTRADEFILECFGbuf->pUA);
strcat(szText, "\r\n");
Write_SOCK_Data_Buffer(1, (BYTE*)szText, strlen(szText));
s_FTPTranCtrl.byCFGOffset = 3;
break;
case 3:
strcpy(szText, s_FTPCOMTRADEFILECFGbuf->pUB);
strcat(szText, "\r\n");
Write_SOCK_Data_Buffer(1, (BYTE*)szText, strlen(szText));
s_FTPTranCtrl.byCFGOffset = 4;
break;
case 4:
strcpy(szText, s_FTPCOMTRADEFILECFGbuf->pUC);
strcat(szText, "\r\n");
Write_SOCK_Data_Buffer(1, (BYTE*)szText, strlen(szText));
s_FTPTranCtrl.byCFGOffset = 5;
break;
case 5:
strcpy(szText, s_FTPCOMTRADEFILECFGbuf->pIA);
strcat(szText, "\r\n");
Write_SOCK_Data_Buffer(1, (BYTE*)szText, strlen(szText));
s_FTPTranCtrl.byCFGOffset = 6;
break;
case 6:
strcpy(szText, s_FTPCOMTRADEFILECFGbuf->pIB);
strcat(szText, "\r\n");
Write_SOCK_Data_Buffer(1, (BYTE*)szText, strlen(szText));
s_FTPTranCtrl.byCFGOffset = 7;
break;
case 7:
strcpy(szText, s_FTPCOMTRADEFILECFGbuf->pIC);
strcat(szText, "\r\n");
Write_SOCK_Data_Buffer(1, (BYTE*)szText, strlen(szText));
s_FTPTranCtrl.byCFGOffset = 8;
break;
case 8:
strcpy(szText, s_FTPCOMTRADEFILECFGbuf->pFrequency);
strcat(szText, "\r\n");
Write_SOCK_Data_Buffer(1, (BYTE*)szText, strlen(szText));
s_FTPTranCtrl.byCFGOffset = 9;
break;
case 9:
strcpy(szText, s_FTPCOMTRADEFILECFGbuf->pnrates);
strcat(szText, "\r\n");
Write_SOCK_Data_Buffer(1, (BYTE*)szText, strlen(szText));
s_FTPTranCtrl.byCFGOffset = 10;
break;
case 10:
strcpy(szText, s_FTPCOMTRADEFILECFGbuf->pSampleRate);
strcat(szText, "\r\n");
Write_SOCK_Data_Buffer(1, (BYTE*)szText, strlen(szText));
s_FTPTranCtrl.byCFGOffset = 11;
break;
case 11:
strcpy(szText, s_FTPCOMTRADEFILECFGbuf->pSampleTime);
strcat(szText, "\r\n");
Write_SOCK_Data_Buffer(1, (BYTE*)szText, strlen(szText));
s_FTPTranCtrl.byCFGOffset = 12;
break;
case 12:
strcpy(szText, s_FTPCOMTRADEFILECFGbuf->pTriggerTime);
strcat(szText, "\r\n");
Write_SOCK_Data_Buffer(1, (BYTE*)szText, strlen(szText));
s_FTPTranCtrl.byCFGOffset = 13;
break;
case 13:
strcpy(szText, s_FTPCOMTRADEFILECFGbuf->pft);
strcat(szText, "\r\n");
Write_SOCK_Data_Buffer(1, (BYTE*)szText, strlen(szText));
s_FTPTranCtrl.byCFGOffset = 14;
break;
case 14:
strcpy(szText, s_FTPCOMTRADEFILECFGbuf->ptimemult);
strcat(szText, "\r\n");
Write_SOCK_Data_Buffer(1, (BYTE*)szText, strlen(szText));
break;
default:
s_FTPTranCtrl.byCFGOffset = 0;
break;
}
}
/* 传输dat文件 */
static void _FTPTranDATFile(void)
{
BYTE byDatFile[20];
DWORD i;
memset(byDatFile, 0, sizeof(byDatFile));
if (s_FTPTranCtrl.wDATOffset >= (DISTURB_NUMBER_CYCLE * (DISTURB_PRE_NUMBER + DISTURB_AFTER_NUMBER)))
return;
byDatFile[0] = (LLBYTE(s_FTPCOMTRADEDAFILETRead[s_FTPTranCtrl.wDATOffset].n));
byDatFile[1] = (LHBYTE(s_FTPCOMTRADEDAFILETRead[s_FTPTranCtrl.wDATOffset].n));
byDatFile[2] = (HLBYTE(s_FTPCOMTRADEDAFILETRead[s_FTPTranCtrl.wDATOffset].n));
byDatFile[3] = (HHBYTE(s_FTPCOMTRADEDAFILETRead[s_FTPTranCtrl.wDATOffset].n));
byDatFile[4] = (LLBYTE(s_FTPCOMTRADEDAFILETRead[s_FTPTranCtrl.wDATOffset].timetamp));
byDatFile[5] = (LHBYTE(s_FTPCOMTRADEDAFILETRead[s_FTPTranCtrl.wDATOffset].timetamp));
byDatFile[6] = (HLBYTE(s_FTPCOMTRADEDAFILETRead[s_FTPTranCtrl.wDATOffset].timetamp));
byDatFile[7] = (HHBYTE(s_FTPCOMTRADEDAFILETRead[s_FTPTranCtrl.wDATOffset].timetamp));
for (i = 0; i < 12; i++)
byDatFile[8 + i] = s_FTPCOMTRADEDAFILETRead[s_FTPTranCtrl.wDATOffset].DAT[i];
s_FTPTranCtrl.wDATOffset++;
Write_SOCK_Data_Buffer(1, byDatFile, 20);
}
/* TCP/IP任务 FTP任务
* 本机ip地址:192.168.1.199
* socket0做客户端,端口号5000,远端ip:192.168.1.60,端口号6000
* socket1做服务器,端口号8888
*/
BOOL appFTPTask(void* pData)
{
WORD size;
/* 1路以太网处理 */
/* 若出现断线事件,快速相应 */
if ((Read_W5500_1Byte(PHYCFGR) & LINK) == 0)
{
Write_W5500_SOCK_1Byte(0, Sn_CR, CLOSE); /* 关闭socket */
Write_W5500_SOCK_1Byte(0, Sn_IR, 0xFF);
TW55001State.time = hwGetSystemCount();
Write_W5500_SOCK_1Byte(1, Sn_CR, CLOSE); /* 关闭socket */
Write_W5500_SOCK_1Byte(1, Sn_IR, 0xFF);
TW55002State.time = hwGetSystemCount();
W5500_Initialization();
}
/* 网线连接状态 */
else
{
/* ctrl socket 做客户端 */
switch (Read_W5500_SOCK_1Byte(0, Sn_SR))
{
case SOCK_ESTABLISHED:
/* 设置服务器为主动模式 */
if (s_FTPTranCtrl.byCtrlSockState == FTP_CLIENT_STATE_LOGIN)
{
sprintf(szText, "PORT %d,%d,%d,%d,%d,%d\r\n", 192,168,1,199, S1_Port[0], S1_Port[1]);
Write_SOCK_Data_Buffer(0, (BYTE*)szText, strlen(szText));
s_FTPTranCtrl.byCtrlSockState = FTP_CLIENT_STATE_LINK;
}
/* 文件名 */
else if (s_FTPTranCtrl.byCtrlSockState == FTP_CLIENT_STATE_LINK)
{
if (apiGetRelaymainTranFlag() & (0x01 << CFG_FILE))
{
apiGetCOMTRADENameFile(0, s_FTPCOMTRADENameFile);
sprintf(szText, "STOR ./%s.cfg\r\n", s_FTPCOMTRADENameFile->chName);
Write_SOCK_Data_Buffer(0, (BYTE*)szText, strlen(szText));
apiGetCOMTRADECFGFile(0, s_FTPCOMTRADEFILECFGbuf);
s_FTPTranCtrl.byCtrlSockState = FTP_CLIENT_STATE_CFG_DATA;
}
else if (apiGetRelaymainTranFlag() & (0x01 << DAT_FILE))
{
sprintf(szText, "STOR ./%s.dat\r\n", s_FTPCOMTRADENameFile->chName);
Write_SOCK_Data_Buffer(0, (BYTE*)szText, strlen(szText));
apiGetCOMTRADEDATFile(0, s_FTPCOMTRADEDAFILETRead);
s_FTPTranCtrl.byCtrlSockState = FTP_CLIENT_STATE_DATA_DATA;
}
}
/* 传输完成 */
else if (s_FTPTranCtrl.byCtrlSockState == FTP_CLIENT_STATE_TRAN_OK)
{
sprintf(szText, "QUIT\r\n");
Write_SOCK_Data_Buffer(0, (BYTE*)szText, strlen(szText));
s_FTPTranCtrl.byCtrlSockState = FTP_CLIENT_STATE_TRAN_DONE;
}
/* 传输流程结束 */
else if (s_FTPTranCtrl.byCtrlSockState == FTP_CLIENT_STATE_TRAN_DONE)
{
Write_W5500_SOCK_1Byte(0, Sn_CR, DISCON);
Write_W5500_SOCK_1Byte(1, Sn_CR, DISCON);
}
/* 接收数据查询 */
W5500_Interrupt_Process();
/* FTP服务器返回命令数据解析 */
if((S0_Data & S_RECEIVE) == S_RECEIVE)
{
S0_Data &= ~S_RECEIVE;
size = Read_SOCK_Data_Buffer(0, (BYTE*)rxbuff);
_FTPServerResponse(rxbuff);
TW55001State.time = hwGetSystemCount();
}
/* 超过OVERTIME未传输完毕或无响应 */
if (hwGetSystemCount() - TW55001State.time >= W5500_OVERTIME_TRAN)
{
Write_W5500_SOCK_1Byte(0, Sn_CR, CLOSE);
TW55001State.time = hwGetSystemCount();
}
break;
case SOCK_CLOSE_WAIT:
Write_W5500_SOCK_1Byte(0, Sn_CR, DISCON);
break;
case SOCK_CLOSED:
if (apiGetRelaymainTranFlag())
{
Write_W5500_SOCK_1Byte(0, Sn_CR, CLOSE); /* 关闭socket */
Write_W5500_SOCK_1Byte(0, Sn_IR, 0xFF);
Write_W5500_SOCK_1Byte(0, Sn_MR, MR_TCP); /* 设置socket为TCP模式 */
Write_W5500_SOCK_1Byte(0, Sn_KPALVTR, 2); /* 设置keepalive为2*5=10秒 */
Socket_Init(0); /* 配置端口号 */
Write_W5500_SOCK_1Byte(0, Sn_CR, OPEN); /* 打开Socket */
hwDelayTime(1000);
hwDelayTime(1000);
Write_W5500_SOCK_1Byte(0, Sn_CR, CONNECT); /* 做客户端发起连接 */
TW55001State.time = hwGetSystemCount();
s_FTPTranCtrl.byCtrlSockState = FTP_CLIENT_STATE_IDLE;
}
break;
default:
if (hwGetSystemCount() - TW55001State.time >= W5500_OVERTIME)
Write_W5500_SOCK_1Byte(0, Sn_CR, CLOSE);
break;
}
/* data socket 做服务器 */
switch (Read_W5500_SOCK_1Byte(1, Sn_SR))
{
case SOCK_INIT:
Write_W5500_SOCK_1Byte(1, Sn_CR, LISTEN);
TW55002State.time = hwGetSystemCount();
break;
case SOCK_LISTEN:
/* 超过OVERTIME无连接 */
if (hwGetSystemCount() - TW55002State.time >= W5500_OVERTIME)
{
TW55002State.time = hwGetSystemCount();
Write_W5500_SOCK_1Byte(1, Sn_CR, CLOSE);
}
break;
case SOCK_ESTABLISHED:
/* 数据接收查询 */
W5500_Interrupt_Process_Socket1();
/* 数据接收处理 */
if ((S1_Data & S_RECEIVE) == S_RECEIVE)
{
S1_Data &= ~S_RECEIVE;
size = Read_SOCK_Data_Buffer(1, (BYTE*)rxbuff);
TW55002State.time = hwGetSystemCount();
}
/* 传CFG文件 */
if (s_FTPTranCtrl.byCtrlSockState == FTP_CLIENT_STATE_CFG_DATA)
{
_FTPTranCFGFile();
TW55002State.time = hwGetSystemCount();
/* CFG文件传输完成 */
if (s_FTPTranCtrl.byCFGOffset == 14)
{
s_FTPTranCtrl.byCFGOffset = 0;
s_FTPTranCtrl.byCtrlSockState = FTP_CLIENT_STATE_TRAN_OK;
apiSetRealymainTranFlag(CFG_FILE, FALSE);
}
}
/* 传DATA文件 */
else if (s_FTPTranCtrl.byCtrlSockState == FTP_CLIENT_STATE_DATA_DATA)
{
_FTPTranDATFile();
TW55002State.time = hwGetSystemCount();
if (s_FTPTranCtrl.wDATOffset == (DISTURB_NUMBER_CYCLE * (DISTURB_PRE_NUMBER + DISTURB_AFTER_NUMBER)))
{
s_FTPTranCtrl.wDATOffset = 0;
apiSetRealymainTranFlag(DAT_FILE, FALSE);
s_FTPTranCtrl.byCtrlSockState = FTP_CLIENT_STATE_TRAN_OK;
}
}
/* 超过OVERTIME没传完 */
if (hwGetSystemCount() - TW55002State.time >= W5500_OVERTIME_TRAN)
{
Write_W5500_SOCK_1Byte(1, Sn_CR, CLOSE);
TW55002State.time = hwGetSystemCount();
}
break;
case SOCK_CLOSE_WAIT:
Write_W5500_SOCK_1Byte(1, Sn_CR, DISCON);
break;
case SOCK_CLOSED:
if (apiGetRelaymainTranFlag())
{
Write_W5500_SOCK_1Byte(1, Sn_CR, CLOSE); /* 关闭socket */
Write_W5500_SOCK_1Byte(1, Sn_IR, 0xFF);
Write_W5500_SOCK_1Byte(1, Sn_MR, MR_TCP); /* 设置socket为TCP模式 */
Write_W5500_SOCK_1Byte(1, Sn_KPALVTR, 2); /* 设置keepalive为2*5=10秒 */
Socket_Init(1); /* 配置端口号 */
Write_W5500_SOCK_1Byte(1, Sn_CR, OPEN); /* 打开Socket */
hwDelayTime(1000);
hwDelayTime(1000);
TW55002State.time = hwGetSystemCount();
}
break;
default:
if (hwGetSystemCount() - TW55002State.time >= W5500_OVERTIME)
Write_W5500_SOCK_1Byte(1, Sn_CR, CLOSE);
break;
}
}
return TRUE;
}
/*************************************************************************
* 改动历史纪录:
Revision 1.0, 2023-11-30, Ben
describe: 初始创建.
*************************************************************************/