TFTP即简单文件传输协议,协议我就不多啰嗦了,感兴趣的可查阅RFC1350: https://tools.ietf.org/html/rfc1350
本例说明:下位机跑LWIP作为TFTP Server,Windows端作为client,实现:
- windows向下位机发送文件
- 从下位机端获取文件
LWIP封装的比较完美,TFTP使用起来非常方便,打开tftp_server.h文件便知只需要写四个回调函数即可,即:
- 打开文件
- 关闭文件
- 写入数据
- 读取数据
tftp_server.h如图:
当然,坑还是有一个的,事情总是不如想象的那么顺利。笔者在调试时很轻易的实现了文件发送,但是文件获取失败。
根据上图tftp_server.h的描述,笔者写的读取函数,读取成功便返回0,结果获取文件失败。后来对比官方API,发现我下载的tftp_server.h有乱码,如下图,返回值是>=0即成功,而非=0,最后仿真确认这里需要返回读取到的字节数。想想也理当如此,不然上位机就没办法知道文件大小了。
以下附代码:
//tftp
struct tftp_context mytftp;
typedef struct
{
uint8_t isOpenOK;
uint8_t type;//0:GCode 1:缓存GCode 2:固件
uint8_t write;
char name[64];
}TFTP_Handler;
TFTP_Handler tftp_Handler;
void* TFTP_Open(const char* fname, const char* mode, u8_t write)
{
uint8_t res;
char name[64];
tftp_Handler.write=write;
tftp_Handler.type=0;
strcpy(name,"0:");
strcat(name,fname);
if(write)
{
res=f_open(file,name,FA_CREATE_ALWAYS|FA_WRITE);
}
else
{
res=f_open(file,name,FA_OPEN_EXISTING|FA_READ);
}
tftp_Handler.isOpenOK=res;
return &tftp_Handler;
}
void TFTP_Close(void* handle)
{
uint8_t res=0;
if(((TFTP_Handler*)handle)->isOpenOK)
return;
f_close(file);
printf("Transfer file completed!\r\n");
}
int TFTP_Read(void* handle, void* buf, int bytes)
{
uint8_t res;
res=((TFTP_Handler*)handle)->isOpenOK;
if(res)return -1;
res = f_read(file,(uint8_t*)buf,bytes,&br);
printf("Read File:%d Len:%d br:%d\r\n",res,bytes,br);
return br;
}
int TFTP_Write(void* handle, struct pbuf* p)
{
uint8_t res;
res=((TFTP_Handler*)handle)->isOpenOK;
if(res)return -1;
res = f_write(file,p->payload,p->len,&bw);
printf("Write File:%d Len:%d bw:%d\r\n",res,p->len,bw);
return 0;
}
void TFTP_ContextInit()
{
mytftp.open=TFTP_Open;
mytftp.close=TFTP_Close;
mytftp.read=TFTP_Read;
mytftp.write=TFTP_Write;
}
最后附两种Windows调试方法:
- 使用命令提示符
发送与获取:
比较一下:
描述:
- 使用调试软件