---
title: "STM Lesson 95. LAN. W5500. FTP Server. Part 4"
url: "https://maker.wiznet.io/teddy/projects/stm-lesson-95-lan-w5500-ftp-server-part-4/"
markdown_url: "https://maker.wiznet.io/teddy/projects/stm-lesson-95-lan-w5500-ftp-server-part-4/md"
type: "UCC: User Created Content"
author: "narod stream"
author_url: "https://narodstream.ru/stm-urok-95-lan-w5500-ftp-server-chast-4/"
editor: "WIZnet"
editor_url: "https://maker.wiznet.io/"
original_author: "narod stream"
original_url: "https://narodstream.ru/stm-urok-95-lan-w5500-ftp-server-chast-4/"
published: "2023-09-04"
language: "en"
tags: ["W5500"]
hardware: ["WIZnet W5500", "STMicroelectronics STM32F411RE"]
likes: 0
views: 469
comments: 0
source: "WIZnet Makers (https://maker.wiznet.io/)"
---

# STM Lesson 95. LAN. W5500. FTP Server. Part 4

> FTP 4th Lecture Using STM32F401RET6 and W5500 - Get Directory Information

Original author: narod stream (source: https://narodstream.ru/stm-urok-95-lan-w5500-ftp-server-chast-4/)

## Components

- **WIZnet W5500** x 1 ([docs](https://docs.wiznet.io/Product/Chip/Ethernet/W5500))
- **STMicroelectronics STM32F411RE** x 1 ([docs](https://www.st.com/en/microcontrollers-microprocessors/stm32f411re.html))

WIZnet parts: W5500 ([Datasheet](https://docs.wiznet.io/Product/Chip/Ethernet/W5500/datasheet?utm_source=maker&utm_medium=project&utm_campaign=w5500), [product hub](https://maker.wiznet.io/products/w5500/))

## Documents and links

- [W5500 FTP code](https://narodstream.ru/arm/download/LESSON95/W5500_FTPS.ZIP) (code): W5500 FTP Server Code

## Article

In [**the previous part**](https://narodstream.ru/stm-urok-95-lan-w5500-ftp-server-chast-3/) of the lesson, we wrote code to display directory information to the client.

Let's look for the cause of the situation where the connection to the server has been lost after responding to the command to display directory information

![Image26](https://narodstream.ru/wp-content/uploads/2017/10/Image26.png)

The server sends us some unknown commands.

**The PWD** command is sent by the client if it is interested in knowing the working (current) directory.

Let's process the PWD and XPWD commands in the **ftp_cmd_parse** function in the appropriate place

`break``;`

`**case**````***PWD_CMD***``**:**`

`**case**````***XPWD_CMD***``**:**`

`** len = **``**sprintf**``**((**``**char**``***)datasect->**``**data**``**, **``**"257 \"%s\" is current directory.\r\n"**``**, ftpprop.**``**work_dir**``**);**`

`** tcp_send_ftp_one(sn, (**``**uint8_t**``** *)buf_send, len);**`

`** break**``**;**`

`case``*QUIT_CMD*``:`

Now after we assemble the code and flash the controller, we can make sure that we can safely enter and exit directories.

We also see that the response to the command from us comes to the client

![Image27](https://narodstream.ru/wp-content/uploads/2017/10/Image27.png)

The next task is to create a new directory on the flash card on the client side. Until we process this. Nevertheless, we will try to do this, at least to see what command the client will send to the server for this. To do this, connect to the server, press F7 or the corresponding button below, come up with a directory name in the dialog that opens and press OK

![Image28](https://narodstream.ru/wp-content/uploads/2017/10/Image28.png)

It is clear that we will get an error

![Image29](https://narodstream.ru/wp-content/uploads/2017/10/Image29.png)

And in the traffic analyzer we see the following

![Image30](https://narodstream.ru/wp-content/uploads/2017/10/Image30.png)

The client gave us an unknown command **MKD** , and as an argument sent the name of the directory, which we, at his request, should create in the current directory. Of course, by the abbreviation of any team, you can easily understand what it carries in itself. MKD - **M** a **k** e **D** irectory, CWD - **Change** Work **D** irectory , PASV - **pas** si **v e ,** etc.

Let's process the MKD command in the **ftp_cmd_parse** function in the appropriate place

`break``;`

`**case**````***MKD_CMD***``**:**`

`**case**````***XMKD_CMD***``**:**`

`** len = **``**strlen**``**(arg);**`

`** arg[len - 1] = 0x00;**`

`** arg[len - 2] = 0x00;**`

`** sprintf**``**(str1,**``**"MKD_CMD\r\n"**``**);**`

`** HAL_UART_Transmit(&huart2,(**``**uint8_t**``***)str1,**``**strlen**``**(str1),0x1000);**`

`** //дополним создаваемый каталог путём к текущему каталогу**`

`** strcpy**``**(buf1,ftpprop.**``**work_dir**``**);**`

`** len = **``**strlen**``**(buf1);**`

`** if**``**(buf1[len-1]!=**``**'/'**``**) **``**strcat**``**(buf1,**``**"/"**``**);**`

`** strcat**``**(buf1,arg);**`

`** if**``** (f_mkdir(buf1) != 0)**`

`** {**`

`** len = **``**sprintf**``**((**``**char**``***)datasect->**``**data**``**, **``**"550 Can't create directory. \"%s\"\r\n"**``**, arg);**`

`** }**`

`** else**`

`** {**`

`** len = **``**sprintf**``**((**``**char**``***)datasect->**``**data**``**, **``**"257 MKD command successful. \"%s\"\r\n"**``**, arg);**`

`** }**`

`** tcp_send_ftp_one(sn, (**``**uint8_t**``** *)buf_send, len);**`

`** break**``**;**`

`case``*QUIT_CMD*``:`

The handler algorithm for this command and the XMKD command is somewhat similar to the handler algorithm for the command to change the current directory. Only we use the FATFS library function f_mkdir to create a new directory.

Let's assemble the code, flash the controller and see the result by trying to create a directory in the root folder and in some other

![Image33](https://narodstream.ru/wp-content/uploads/2017/10/Image33.png)

![Image34](https://narodstream.ru/wp-content/uploads/2017/10/Image34.png)

Everything is working. Sometimes it hangs, but I don't think we'll need to create directories often, but I'll think about it anyway. Maybe something with the network, I still have a very busy network here, in another place everything seems to be working fine. And it’s possible that when we write the entire project, everything will be restored.

Next, we need to learn how to delete directories as well. Let's do the same thing, evaluating the command as an attempt to delete a directory. To do this, we must select the directory we wish to delete, press the **Del** or **F8** button and agree to the dialog. As a result of this, we will most likely first get a dialogue of this type

![Image35](https://narodstream.ru/wp-content/uploads/2017/10/Image35.png)

Let's click the " **All** " button and get this

![Image36](https://narodstream.ru/wp-content/uploads/2017/10/Image36.png)

That is, most likely the client, having received a message from us that we do not know such a basic command, was offended as always and decided to break the connection with us.

Let's make sure of this by looking at the exchange in the traffic analyzer

![Image37](https://narodstream.ru/wp-content/uploads/2017/10/Image37.png)

It turns out the opposite. The server was offended that the client was asking for things that the server did not know.

Let's somehow correct this situation. The client tried to use two commands:

1) **RMD** - directory deletion command,

2) **DELE** - file deletion command.

Let's start with the first one.

Let's add a handler to the appropriate place in the **ftp_cmd_parse function**

`break``;`

`**case**````***XRMD_CMD***``**:**`

`**case**````***RMD_CMD***``**:**`

`** len = **``**strlen**``**(arg);**`

`** arg[len - 1] = 0x00;**`

`** arg[len - 2] = 0x00;**`

`** sprintf**``**(str1,**``**"RMD_CMD\r\n"**``**);**`

`** HAL_UART_Transmit(&huart2,(**``**uint8_t**``***)str1,**``**strlen**``**(str1),0x1000);**`

`** if**``** (f_unlink(arg) != 0)**`

`** {**`

`** len = **``**sprintf**``**((**``**char**``***)datasect->**``**data**``**, **``**"550 Could not delete. \"%s\"\r\n"**``**, arg);**`

`** }**`

`** else**`

`** {**`

`** len = **``**sprintf**``**((**``**char**``***)datasect->**``**data**``**, **``**"250 Deleted. \"%s\"\r\n"**``**, arg);**`

`** }**`

`** tcp_send_ftp_one(sn, (**``**uint8_t**``** *)buf_send, len);**`

`** break**``**;**`

`case``*QUIT_CMD*``:`

The handler differs from the previous one only in that the function from the FATFS library is called f_unlink, and the corresponding message is also sent.

Well, let's also process the **DELE command**

`break``;`

`**case**````***DELE_CMD***``**:**`

`** len = **``**strlen**``**(arg);**`

`** arg[len - 1] = 0x00;**`

`** arg[len - 2] = 0x00;**`

`** sprintf**``**(str1,**``**"DELE_CMD\r\n"**``**);**`

`** HAL_UART_Transmit(&huart2,(**``**uint8_t**``***)str1,**``**strlen**``**(str1),0x1000);**`

`** if**``** (f_unlink(arg) != 0)**`

`** {**`

`** len = **``**sprintf**``**((**``**char**``***)datasect->**``**data**``**, **``**"550 Could not delete. \"%s\"\r\n"**``**, arg);**`

`** }**`

`** else**`

`** {**`

`** len = **``**sprintf**``**((**``**char**``***)datasect->**``**data**``**, **``**"250 Deleted. \"%s\"\r\n"**``**, arg);**`

`** }**`

`** tcp_send_ftp_one(sn, (**``**uint8_t**``** *)buf_send, len);**`

`** break**``**;**`

`case``*QUIT_CMD*``:`

And this handler does not differ at all from the previous one, except for the case argument.

Let's collect the code and flash the controller. Let's try to reconnect to our FTP server and delete the directory in the root directory, as well as in some other one. Let's also try to delete some files.

Files and directories are deleted. True, only those directories that we created ourselves from the client are deleted. Apparently, there are not enough rights.

The next task is to transfer files. This is the most interesting. And by and large, this is why the FTP protocol exists. It stands for file transfer protocol. The task is interesting, but very difficult, so you need to take it extremely seriously so as not to make mistakes.

Let's begin.

I think we'll first try transferring files from the server to the client. It turned out that transferring files to the server was more difficult. Most likely, this is due to the fact that we have already transferred files from the server via the HTTP protocol and have a general idea of ​​how to do this.

First, as always, let's try to transfer the file without creating any code. And, of course, we will select the smallest file in size. To do this, in another panel of the file manager, open any directory, and in the panel where the FTP server file system is open, select our file and press “ **F5** ”. We agree with the dialogue, to which we will receive a message like this

![Image38](https://narodstream.ru/wp-content/uploads/2017/10/Image38.png)

Let's also look at the exchange of information in WireShark

![Image39](https://narodstream.ru/wp-content/uploads/2017/10/Image39.png)

We see. that the client sent the **RETR** command , which serves to request a file from the server, with a file name argument, to which the server responded that it did not know such a command, and the client decided to close the data connection.

Therefore, let's start writing code that could ensure the transfer of files of any size from the server to the client.

First, we will process the command itself in the appropriate place in order to respond to the client with a message over the control connection. I hope everyone has already remembered this place, there is no point in reminding us anymore.

`break``;`

`**case**````***RETR_CMD***``**:**`

`** len = **``**strlen**``**(arg);**`

`** arg[len - 1] = 0x00;**`

`** arg[len - 2] = 0x00;**`

`** sprintf**``**(str1,**``**"RETR_CMD\r\n"**``**);**`

`** HAL_UART_Transmit(&huart2,(**``**uint8_t**``***)str1,**``**strlen**``**(str1),0x1000);**`

`** if**``**(**``**strlen**``**(ftpprop.**``**work_dir**``**) == 1)**`

`** sprintf**``**(ftpprop.**``**filename**``**, **``**"/%s"**``**, arg);**`

`** else**`

`** sprintf**``**(ftpprop.**``**filename**``**, **``**"%s/%s"**``**, ftpprop.**``**work_dir**``**, arg);**`

`** len = **``**sprintf**``**((**``**char**``***)datasect->**``**data**``**, **``**"150 Opening data channel for file downloand from server of \"%s\"\r\n"**``**,**`

`** ftpprop.**``**filename**``**);**`

`** tcp_send_ftp_one(sn, (**``**uint8_t**``** *)buf_send, len);**`

`** ftpprop.**``**current_cmd**``** = **``***RETR_CMD***``**;**`

`** break**``**;**`

`case``*QUIT_CMD*``:`

As always, a standard handler that responds with a message to the client in text form with code 150. We also enter the file name along with the extension in the corresponding field of the structure with properties for further work with it over the data connection. We also enter the index of the current command in another field of the structure.

Above the **ftp_data_send** function we will create a function for transferring a file

`**//-----------------------------------------------**`

`**//функция чтения и передачи файла (части файла)**`

`**void**``** ftp_send_file(**``**uint8_t**``** sn, **``**char**``** *buf)**`

`**{**`

`** uint32_t**``** buf_ptr = 0;**`

`** buf_ptr+=3;**``**//оставим место под ардес и опкод**`

`** uint32_t**``** lensect = 0;**`

`**}**`

`**//-----------------------------------------------**`

Now let’s go to the **ftp_data_send** function itself and add another option (case) there to our switch

`break``;`

`**case**````***RETR_CMD***``**:**`

`** break**``**;**`

`default``:`

Now let’s begin to slowly fill this case with useful code.

Let's add a condition with the body there, stating that this is our first buffer (or the only one)

`case``*RETR_CMD*``:`

`**if**``**(ftpprop.**``**data_stat**``**==DATA_FIRST)**`

`** {**`

`** res = f_open(&ftpprop.**``**my_fil**``**, (**``**const**````**char**``** *)ftpprop.**``**filename**``**, FA_READ);**`

`** sprintf**``**(str1,**``**"f_open: %d\r\n"**``**,res);**`

`** HAL_UART_Transmit(&huart2,(**``**uint8_t**``***)str1,**``**strlen**``**(str1),0x1000);**`

`** sprintf**``**(str1,**``**"f_size: %lu\r\n"**``**,ftpprop.**``**my_fil**``**.**``**fsize**``**);**`

`** HAL_UART_Transmit(&huart2,(**``**uint8_t**``***)str1,**``**strlen**``**(str1),0x1000);**`

`** if**``**(res == **``***FR_OK***``**)**`

`** {**`

`** ftpprop.**``**rem_filesize**``** = ftpprop.**``**my_fil**``**.**``**fsize**``**;**`

`** ftp_send_file(sn,buf_send);**`

`** }**`

`** }**`

`break``;`

Here we will first try to open the file, then report to the terminal program that the opening was successful, and also send the file size there, then, if the opening was successful, we will enter the file size in a certain field of the structure and call the file transfer function that we just created. Now let's process the opposite condition, if we have not the first file transfer buffer, but the middle one (or the last one)

`ftp_send_file(sn,buf_send);`

`}`

`}`

`**else**````**if**``**(ftpprop.**``**data_stat**``**==DATA_MIDDLE)**`

`**{**`

`** ftp_send_file(sn,buf_send);**`

`**}**`

`break``;`

In this case, we simply call the function, since it is assumed that the file is already open and exists.

Now let's start writing the file transfer function **ftp_send_file**

Let's add a cycle there

`uint32_t``lensect = 0;`

`** while**``**(1)**`

`** {**`

`** //f_lseek(&ftpprop.my_fil,ftpprop.my_fil.fsize-ftpprop.rem_filesize); //Установим курсор чтения в файле**`

`** lensect = 512;**`

`** //если осталось меньше, чем сектор**`

`** if**``**(ftpprop.**``**rem_filesize**``**<=512)**`

`** {**`

`** lensect = ftpprop.**``**rem_filesize**``**;**`

`** }**`

`** }**`

`}`

In this cycle, we initialize the sector, and then, if we have less information left to transmit than the sector size, we will reduce the sector size to this value.

We continue to write our cycle

`lensect = ftpprop.``rem_filesize``;`

`}`

`**//ещё укоротим, если насчитали больше, чем осталось до переполнения буфера**`

`**if**``**(lensect>(SIZE_WND+3-buf_ptr))**`

`**{**`

`** lensect = SIZE_WND+3-buf_ptr;**`

`**}**`

Actually, what we are doing here is already described in the commentary.

Next we fill the body of the loop with code.

`lensect = SIZE_WND+3-buf_ptr;`

`}`

`**f_read(&ftpprop.**``**my_fil**``**,buf+buf_ptr,lensect,(**``**UINT**``** *)&bytesread);**`

`**ftpprop.**``**rem_filesize**``** -= lensect;**`

`**buf_ptr+=lensect;**`

Here we count the required number of bytes from the file to the buffer, taking into account the offset, then we adjust the number of bytes of the file that we still have to transfer, and also adjust the offset in the buffer.

We continue to write the code for the body of the loop, because we still need to get out of it someday, we won’t be stuck in it forever

`buf_ptr+=lensect;`

`**if**``**(ftpprop.**``**rem_filesize**``**<=0)**`

`**{**`

`** ftpprop.**``**data_stat**``**=DATA_END;**`

`** HAL_UART_Transmit(&huart2,(**``**uint8_t**``***)**``**"FILE Close\r\n"**``**,12,0x1000);**`

`** f_close(&ftpprop.**``**my_fil**``**);**`

`** break**``**;**`

`**}**`

`**if**``**((SIZE_WND+3-buf_ptr)<=0)**`

`**{**`

`** ftpprop.**``**data_stat**``**=DATA_MIDDLE;**`

`** break**``**;**`

`**}**`

This is where we break out of the endless cycle. Only if we have nothing more to transfer (the number of bytes remaining for transfer is less than or equal to zero), then we transfer the data transfer state to the end and close our file, and if there is still something left, but we are already starting to exceed the maximum buffer size, then We do not close the file and transfer the transfer state to transfer of the middle part.

We exit the loop (not the condition) and send our typed buffer to the client

`break``;`

`}`

`}`

`** tcp_send_ftp_one(sn, (**``**uint8_t**``** *)buf, buf_ptr-3);**``**//отнимаем из общей длины служебные байты**`

`}`

Let's collect the code, flash the controller and check how the process of copying files from the server to the client occurs

![Image40](https://narodstream.ru/wp-content/uploads/2017/10/Image40.png)

The process is going well. Files of any size are transferred.

We’ll also look at the exchange process in the traffic analyzer, or rather its completion, we don’t need the whole process

![Image41](https://narodstream.ru/wp-content/uploads/2017/10/Image41.png)

So far, so good. Parts of the file are transferred equally, the buffer is filled completely, the transfer report has arrived from the server, although instead of the file name there is the name of the current directory, but it’s okay, except for the message code, it is usually ignored by clients. Otherwise, we will have to write a branch where we will determine whether we transferred a file, or a directory, or information about the directory. It's useless. The client does not swear, and this is the main thing.

Now comes the hardest task. Transfer information from the client to the server. It's okay, we'll manage.

Let's try to transfer something from the client to the server before writing the code. This process is initiated in the same way, only we, on the contrary, select any file in any folder in the second panel, and in the first panel we have any directory on the server open at this time. We go to the file that we want to transfer to the server and press “ **F5** ”. We'll get this error message:

![Image42](https://narodstream.ru/wp-content/uploads/2017/10/Image42.png)

Let's see the exchange process

![Image43](https://narodstream.ru/wp-content/uploads/2017/10/Image43.png)

We see that the client sent the **STOR** command , which serves to ensure that the server accepts from the client a file with the name specified in the command argument.

Well. We have no choice but to process this command. First, in the command parsing function, we will respond to this command via the control connection

`break``;`

`**case**````***STOR_CMD***``**:**`

`** len = **``**strlen**``**(arg);**`

`** arg[len - 1] = 0x00;**`

`** arg[len - 2] = 0x00;**`

`** sprintf**``**(str1,**``**"STOR_CMD\r\n"**``**);**`

`** HAL_UART_Transmit(&huart2,(**``**uint8_t**``***)str1,**``**strlen**``**(str1),0x1000);**`

`** if**``**(**``**strlen**``**(ftpprop.**``**work_dir**``**) == 1)**`

`** sprintf**``**(ftpprop.**``**filename**``**, **``**"/%s"**``**, arg);**`

`** else**`

`** sprintf**``**(ftpprop.**``**filename**``**, **``**"%s/%s"**``**, ftpprop.**``**work_dir**``**, arg);**`

`** len = **``**sprintf**``**((**``**char**``***)datasect->**``**data**``**, **``**"150 Opening data channel for file upload to server of \"%s\"\r\n"**``**,**`

`** ftpprop.**``**filename**``**);**`

`** tcp_send_ftp_one(sn, (**``**uint8_t**``** *)buf_send, len);**`

`** ftpprop.**``**current_cmd**``** = **``***STOR_CMD***``**;**`

`**break**``**;**`

`case``*QUIT_CMD*``:`

Everything here is simple and standard. All dances with a tambourine will be in the data socket.

We will create a function for receiving and processing FTP packets **ftp_receive** for receiving data from the client

`**//-----------------------------------------------**`

`**void**``** ftp_data_receive(**``**uint8_t**``** sn)**`

`**{**`

`** uint16_t**``** len;**`

`** uint16_t**``** point;**`

`** static**````**char**``** buf_recv[SIZE_WND+1];**`

`** uint16_t**``** len_full=0;**`

`** FRESULT**``** res; **``**//результат выполнения**`

`**}**`

`**//-----------------------------------------------**`

In the w5500.h file we will add one more data transfer option, also changing the indices of the remaining options

`**//--------------------------------------------------**`

`**//Статусы передачи данных**`

`**#define**``** DATA_COMPLETED 0 **``**//передача данных закончена**`

`**#define**``** DATA_ONE 1 **``**//передаём единственный пакет**`

`**#define**``** DATA_FIRST 2 **``**//передаём первый пакет**`

`**#define**``** DATA_MIDDLE 3 **``**//передаём средний пакет**`

`**#define**``** DATA_STOR_MIDDLE 4 **``**//передаём средний пакет файла FTP на сервер**`

`**#define**``** DATA_LAST 5 **``**//передаём последний пакет**`

`**#define**``** DATA_END 6 **``**//закрываем соединение после передачи данных**`

`**//--------------------------------------------------**`

Let's go back to the **ftpd.c** file and in the **ftp_receive** function we will add another case to the last switch ( **switch(ftpprop.current_cmd)** )

`break``;`

`**case**````***STOR_CMD***``**:**`

`** if**``**(ftpprop.**``**data_stat**``**==DATA_COMPLETED)**`

`** {**`

`** ftpprop.**``**data_stat**``**=DATA_FIRST;**`

`** }**`

`** else**````**if**``**(ftpprop.**``**data_stat**``**==DATA_FIRST)**`

`** {**`

`** if**``**(len>0)**`

`** {**`

`** point = GetReadPointer(sn);**`

`** //Отобразим адрес данных**`

`** sprintf**``**(str1,**``**"S%d point RX:0x%04X\r\n"**``**,sn,point);**`

`** HAL_UART_Transmit(&huart2,(**``**uint8_t**``***)str1,**``**strlen**``**(str1),0x1000);**`

`** ftp_data_receive(sn);**`

`** }**`

`** }**`

`** break**``**;**`

`default``:`

This is where we will get if we have a current STOR command. If we have no data left to receive, then we go into the state of receiving the first packet; if we are already in the state of receiving the first packet, then we will study the data address, display it in the terminal program and call our data reception function.

Let's go to another switch, which is located above ( **switch(ftpprop.data_stat)** ) and add another data transfer option there

`break``;`

`**case**``** DATA_STOR_MIDDLE:**`

`** ftp_data_receive(sn);**`

`** break**``**;**`

`}`

`switch``(ftpprop.``current_cmd``)`

In this case, we simply call the function we just created.

Therefore, let's go to this function and start writing code in it.

Let's try to open the file for creation, and if there is one, then open it for overwriting

`FRESULT``res; ``//результат выполнения`

`**if**``**(ftpprop.**``**data_stat**``**==DATA_FIRST)**`

`**{**`

`** res = f_open(&ftpprop.**``**my_fil**``**, (**``**const**````**char**``** *)ftpprop.**``**filename**``**, FA_CREATE_ALWAYS | FA_WRITE);**`

`** if**``**(res != **``***FR_OK***``**) **``**return**``**;**`

`**}**`

If it is impossible to open (create) a file, then we leave the function.

Let's create an infinite loop by leaving the body of the condition

`if``(res != ``*FR_OK*``) ``return``;`

`}`

`**while**``**(1)**`

`**{**`

`**}**`

Let's start writing the body of the loop

`while``(1)`

`{`

`**len = GetSizeRX(sn);**`

`** point = GetReadPointer(sn);**`

`** //Отобразим адрес данных**`

`** sprintf**``**(str1,**``**"S%d point RX:0x%04X\r\n"**``**,sn,point);**`

`** HAL_UART_Transmit(&huart2,(**``**uint8_t**``***)str1,**``**strlen**``**(str1),0x1000);**`

`** //Отобразим размер принятых данных**`

`** sprintf**``**(str1,**``**"S%d len buf:0x%04X\r\n"**``**,sn,len);**`

`** HAL_UART_Transmit(&huart2,(**``**uint8_t**``***)str1,**``**strlen**``**(str1),0x1000);**`

`** if**``**(len<=0)**`

`** {**`

`** f_close(&ftpprop.**``**my_fil**``**);**`

`** break**``**;**`

`** }**`

We found out the size of the data in the receive buffer, also determined the address of the data in this buffer, displayed it all in the terminal program, and if the length of the data in the buffer is zero, that is, we most likely have already received everything, then we close the file and exit from our infinite loop (not from the function).

Now after the **tcp_send_ftp_one** function we will add a function for receiving data

`**//-----------------------------------------------**`

`**void**``** tcp_recv_ftp(**``**uint8_t**``** sn, **``**uint8_t**``** * buf, **``**uint16_t**``** len_buf)**`

`**{**`

`** uint16_t**``** len;**`

`** uint16_t**``** point;**`

`** len = GetSizeRX(sn);**`

`** point = GetReadPointer(sn);**`

`** //Отобразим адрес данных**`

`** sprintf**``**(str1,**``**"S%d point RX:0x%04X\r\n"**``**,sn,point);**`

`** HAL_UART_Transmit(&huart2,(**``**uint8_t**``***)str1,**``**strlen**``**(str1),0x1000);**`

`** //Отобразим размер принятых данных**`

`** sprintf**``**(str1,**``**"S%d len buf:0x%04X\r\n"**``**,sn,len);**`

`** HAL_UART_Transmit(&huart2,(**``**uint8_t**``***)str1,**``**strlen**``**(str1),0x1000);**`

`** if**``**(len>len_buf) len=len_buf;**`

`** //примем данные**`

`** w5500_readSockBuf(sn, point, (**``**uint8_t**``***) buf, len);**`

`** //Передвинем указатель**`

`** SetReadPointer(sn, point+len);**`

`** RecvSocket(sn);**`

`**}**`

`**//-----------------------------------------------**`

In this function, we read the received buffer into a buffer in RAM, the address of which we pass in the incoming argument, and along with it we also pass the length of the received data.

Now let's return to our infinite loop in the **ftp_data_receive** function and continue writing its body

`break``;`

`}`

`**tcp_recv_ftp(sn,(**``**uint8_t**``***)buf_recv,len);**`

`**f_write(&ftpprop.**``**my_fil**``**,buf_recv,len,(**``**UINT**``** *)&bytesread);**`

`**len_full+=len;**`

`**//Отобразим размер записанных данных**`

`**sprintf**``**(str1,**``**"S%d len_full buf:0x%04X\r\n"**``**,sn,len_full);**`

`**HAL_UART_Transmit(&huart2,(**``**uint8_t**``***)str1,**``**strlen**``**(str1),0x1000);**`

`**point = GetReadPointer(sn);**`

`**//Отобразим адрес данных**`

`**sprintf**``**(str1,**``**"1 S%d point RX:0x%04X\r\n"**``**,sn,point);**`

`**HAL_UART_Transmit(&huart2,(**``**uint8_t**``***)str1,**``**strlen**``**(str1),0x1000);**`

`**len = GetSizeRX(sn);**`

`**//Отобразим размер принятых данных**`

`**sprintf**``**(str1,**``**"1 S%d len buf:0x%04X\r\n"**``**,sn,len);**`

`**HAL_UART_Transmit(&huart2,(**``**uint8_t**``***)str1,**``**strlen**``**(str1),0x1000);**`

Here we take data from the receive buffer in the size that we found out above, then write it to a file. By the way, it turned out that the pointer in the file does not need to be moved as blocks are read and written, it moves itself, so we do not use the f_lseek function. Then we display the size of the recorded data in the terminal, find out the address of the data in the reading buffer, also display it in the terminal program, measure the size of the data again, since while we were reading the buffer and writing it to the file, we could freely receive more data from the client. Of course, for good reason, we should not process this buffer right away, we should go over other sockets and process the queue of buffers there, otherwise, if we have a huge file transfer, then our HTTP server will not respond to client requests at this time. Maybe, a real-time operating system will help solve this problem, but I haven’t thoroughly understood it yet, so I made a normal project. Well, it’s okay, we don’t yet plan to have both servers running simultaneously, we’d like to raise one somehow. Next, we also display the size of the recorded data in the terminal program.

We write the body of the loop further

`HAL_UART_Transmit(&huart2,(``uint8_t``*)str1,``strlen``(str1),0x1000);`

`**if**``**(GetSocketStatus(sn)!=SOCK_ESTABLISHED)**`

`**{**`

`** //Если в буфере остались данные, то примем их и запишем в файл**`

`** tcp_recv_ftp(sn,(**``**uint8_t**``***)buf_recv,len);**`

`** f_write(&ftpprop.**``**my_fil**``**,buf_recv,len,(**``**UINT**``** *)&bytesread);**`

`** f_close(&ftpprop.**``**my_fil**``**);**`

`** break**``**;**`

`**}**`

Here we handle the situation when the client is already trying to break the connection with us, and we have not yet received all the data. Typically this happens when the client has transferred the last part of the file to us. In the body of this condition, we pass the remaining data, write it to a file and close it.

We exit the loop completely (and not from the condition) and write the code further

`break``;`

`}`

`}`

`**ftpprop.**``**current_cmd**``** = **``***NO_CMD***``**;**`

`** ftpprop.**``**data_stat**``**=DATA_COMPLETED;**`

`** DisconnectSocket(FTP_SOCKET_DATA); **``**//Разъединяемся**`

`** SocketClosedWait(FTP_SOCKET_DATA);**`

`** sprintf**``**(str1,**``**"S%d closed\r\n"**``**,FTP_SOCKET_DATA);**`

`** HAL_UART_Transmit(&huart2,(**``**uint8_t**``***)str1,**``**strlen**``**(str1),0x1000);**`

`** OpenSocket(FTP_SOCKET_DATA,Mode_TCP);**`

`** //Ждём инициализации сокета (статус SOCK_INIT)**`

`** SocketInitWait(FTP_SOCKET_DATA);**`

`** //Продолжаем слушать сокет**`

`** ListenSocket(FTP_SOCKET_DATA);**`

`** SocketListenWait(FTP_SOCKET_DATA);**`

`** ftpprop.**``**connect_stat_data**``** = 0;**`

`** len = **``**sprintf**``**((**``**char**``** *)(sect+3), **``**"226 Successfully transferred \"%s\"\r\n"**``**, ftpprop.**``**work_dir**``**);**`

`** tcp_send_ftp_one(FTP_SOCKET_CTRL, sect, len);**`

`}`

Here we enter the necessary values ​​in the structure fields, disconnect the data connection with the client, reopen it, start listening to the socket and send a message to the client that its data was transferred successfully.

We collect the code, check it, flashing the controller first

![Image44](https://narodstream.ru/wp-content/uploads/2017/10/Image44.png)

Everything is working.

At this point, I think we can finish working with the FTP server. If you notice any errors, please write. Also write if you managed to cope with them and how.

Thank you all for your attention!

---

Source: https://maker.wiznet.io/teddy/projects/stm-lesson-95-lan-w5500-ftp-server-part-4/
