Lwip2.0.3 版本的tftp 协议笔记
Lwip2.0.3中的tftp与旧版本的lwip的部分改动挺大,新版本的提供的接口更加方便,
新版本中tftp-server.h定义了一个结构体,声明了一个初始化函数,这个函数就是给开发人员的接口,里面是四个函数接口,open,close write read,我们只需要重新建立这四个函数,与其对应即可。.h如下:
*/
struct tftp_context {
/**
* Open file for read/write.
* @param fname Filename
* @param mode Mode string from TFTP RFC 1350 (netascii, octet, mail)
* @param write Flag indicating read (0) or write (!= 0) access
* @returns File handle supplied to other functions
*/
void* (*open)(const char* fname, const char* mode, u8_t write);
/**
* Close file handle
* @param handle File handle returned by open()
*/
void (*close)(void* handle);
/**
* Read from file
* @param handle File handle returned by open()
* @param buf Target buffer to copy read data to
* @param bytes Number of bytes to copy to buf
* @returns >= 0: Success; < 0: Error
*/
int (*read)(void* handle, void* buf, int bytes);
/**
* Write to file
* @param handle File handle returned by open()
* @param pbuf PBUF adjusted such that payload pointer points
* to the beginning of write data. In other words,
* TFTP headers are stripped off. begainning of actualdata
* @returns >= 0: Success; < 0: Error
*/
int (*write)(void* handle, struct pbuf* p);
};
extern err_t tftp_init(const struct tftp_context* ctx);
函数的具体参数的意义自己翻译一下就知道了,其中open函数无论是写还是读都会被调用,在此之前你应该很了解了tftp的传输协议的理论部分,对传输过程很清晰,官方给的库里面的结构体代表的意义应该清楚,回到上面,open函数返回的函数句柄要被其他几个函数使用,编写好四个函数后取地址传给库里的tftp_init函数
uint8_t Tftp_Context_Init(void)
{
if(tftp_init(&tftpContext) == ERR_OK)
return 0;
return 1;
}
此函数被主函数初始化一下即可。
例:
#define MY_MALLOC(type,n) (type*)malloc(sizeof(type) * n)
typedef struct
{
uint8_t byOpenFileFlag; // 1 : Open file succeed 0: fail
uint8_t W_R_Mode; // read or write Mode ,1: write 0 :read
uint32_t First_Flash_Addr; // address you want to write
}TyTftp_IAP_Flash;
static void * Tftp_Open_File(const char* fname, const char* mode, u8_t Iswrite);
static void Tftp_Close_File(void* handle);
static int32_t Tftp_Read_File(void* handle, void* buf, int bytes);
static int32_t Tftp_Write_File(void* handle, struct pbuf* p);
static TyTftp_IAP_Flash Tftp_IAP_Flash;
struct tftp_context TftpContext =
{
Tftp_Open_File,
Tftp_Close_File,
Tftp_Read_File,
Tftp_Write_File,
};
static void *Tftp_Open_File(const char* fname, const char* mode, u8_t Iswrite)
{
Tftp_IAP_Flash.W_R_Mode = Iswrite;
/*compare the file name we want to read or write*/
if(Tftp_IAP_Flash.W_R_Mode == 1) //: is write
{
Tftp_IAP_Flash.byOpenFileFlag = 1;
}
else if(Tftp_IAP_Flash.W_R_Mode == 0) //:is read
{
Tftp_IAP_Flash.byOpenFileFlag = 1;
}
/*tftp open file init successful*/
if(Tftp_IAP_Flash.byOpenFileFlag == 1)
return &Tftp_IAP_Flash;
else
return 0 ;
}
static int32_t Tftp_Read_File(void* handle, void* buf, int bytes)
{
uint16_t Count ;
TyTftp_IAP_Flash * Filehandle = (TyTftp_IAP_Flash *) handle ;
if(!Filehandle->byOpenFileFlag) //未初始化
{
return ERR_MEM ;
}
#if 0
/* copy data from Address to opening file*/
for(Count = 0; Count < bytes; Count++ )
{
if(Filehandle->First_Flash_Addr <= FLASH_APP_END_ADDRESS)
{
((uint8_t *)buf)[Count] = *((__IO uint8_t *) Filehandle->First_Flash_Addr);
Filehandle->First_Flash_Addr++;
}
else
{
break;
}
}
#endif
return Count;
}
static int32_t Tftp_Write_File(void* handle, struct pbuf* p)
{
uint16_t Count;
int8_t byErr = ERR_OK;
TyTftp_IAP_Flash * Filehandle = (TyTftp_IAP_Flash *) handle ;
if(!Filehandle->byOpenFileFlag)
{
return ERR_MEM ;
}
Count = p->len; //lenth of data : 512byte or <512
//code
return byErr;
}
static void Tftp_Close_File(void* handle)
{
Tftp_IAP_Flash.byOpenFileFlag = 0;
if(Tftp_IAP_Flash.W_R_Mode == 1)
{
//code
}
}
}
uint8_t Tftp_Context_Init(uint16_t ReUpdate, uint8_t BootFlag)
{
TftpFileStart(BootFlag);
if (ReUpdate == 1)
{
if(tftp_init(&TftpContext) == ERR_OK)
return 0;
}
return 1;
}
最后利用TFTP32软件和下位机结合实际业务进行文件的读取和写入。只需要在code处填写你自己的代码就行了,有需要可以联系我。