---
title: "STM Lesson 91. LAN. W5500. HTTP Server. Part 5"
url: "https://maker.wiznet.io/teddy/projects/stm-lesson-91-lan-w5500-http-server-part-5/"
markdown_url: "https://maker.wiznet.io/teddy/projects/stm-lesson-91-lan-w5500-http-server-part-5/md"
type: "UCC: User Created Content"
author: "Narod stream"
author_url: "https://narodstream.ru/stm-urok-91-lan-w5500-http-server-chast-5/"
editor: "WIZnet"
editor_url: "https://maker.wiznet.io/"
original_author: "Narod stream"
original_url: "https://narodstream.ru/stm-urok-91-lan-w5500-http-server-chast-5/"
published: "2023-08-02"
language: "en"
tags: ["W5500"]
hardware: ["WIZnet W5500", "STMicroelectronics STM32F411RE"]
likes: 1
views: 533
comments: 0
source: "WIZnet Makers (https://maker.wiznet.io/)"
---

# STM Lesson 91. LAN. W5500. HTTP Server. Part 5

> HTTP Server Lecture Using STM32F401RET6 and W5500

Original author: Narod stream (source: https://narodstream.ru/stm-urok-91-lan-w5500-http-server-chast-5/)

## 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 HTTP Server](https://narodstream.ru/arm/download/LESSON91/W5500_HTTPS.ZIP) (code): W5500 HTTP Server code zip file

## Article

**Part 5**

## **LAN. W5500. HTTP server**

B [**previous part**](https://narodstream.ru/stm-urok-91-lan-w5500-http-server-chast-4/) lesson we continued the response function to the HTTP request, and also wrote the function of transferring to the client a document that fits with the heading in one window.

Following this function, we will create the transfer function of the first multi-window ( multi-buffer ) document

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

`**void**``** tcp_send_http_first(**``**void**``**)**`

`**{**`

`** uint8_t**``** prt;**`

`** uint16_t**``** i=0;**`

`** uint16_t**``** data_len=0;**`

`** uint16_t**``** header_len=0;**`

`** uint16_t**``** end_point;**`

`** uint8_t**``** num_sect=0;**`

`** uint16_t**``** len_sect;**`

`** uint16_t**``** last_part, last_part_size;**`

`**}**`

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

Call her in the proper place in the function **http_request**

`else``if``(httpsockprop[tcpprop.cur_sock].data_stat==DATA_FIRST)`

`{`

`** tcp_send_http_first();**`

`}`

`}`

Moreover, unlike calling the first function, we no longer close the connection here, since this is only the first part of our answer **HTTP**.

We continue to write the function of sending the first part of our answer.

As in the previous function, as of the type of document, we will tie the header buffer to a specific array, determine its length and also enter the data length in the variable, which will be equal to the size of the window

`uint16_t``last_part, last_part_size;`

`**//На EXISTING проверять не будем, так как будем считать, что error404_htm у нас всегда будет умещаться в один буфер**`

`**switch**``**(httpsockprop[tcpprop.cur_sock].http_doc)**`

`**{**`

`** case**``** EXISTING_HTML:**`

`** header = (**``**void**``***)http_header;**`

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

`** case**``** EXISTING_ICO:**`

`** header = (**``**void**``***)icon_header;**`

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

`** case**``** EXISTING_JPG:**`

`** header = (**``**void**``***)jpg_header;**`

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

`**}**`

`**header_len = **``**strlen**``**(header);**`

`**data_len = tcp_size_wnd-header_len;**`

As indicated in the commentary, we will consider that if the document does not exist, then we have already sent the page with an error and the corresponding heading in the previous function, since such an answer we calmly fit in one buffer.

Define and move the pointer in the shipping buffer

`data_len = tcp_size_wnd-header_len;`

`**end_point = GetWritePointer(tcpprop.**``**cur_sock**``**);**`

`**end_point+=header_len+data_len;**`

`**SetWritePointer(tcpprop.cur_sock, end_point);**`

`**end_point = GetWritePointer(tcpprop.**``**cur_sock**``**);**`

Next, we will save some parameters of the structure, since after further code they are lost due to unknown reasons. That is, they acquire random values

`end_point = GetWritePointer(tcpprop.``cur_sock``);`

`**//сохраним некоторые параметры, а то почему-то они теряются**`

`**last_part = httpsockprop[tcpprop.**``**cur_sock**``**].cnt_rem_data_part;**`

`**last_part_size = httpsockprop[tcpprop.**``**cur_sock**``**].last_data_part_size;**`

`**prt = httpsockprop[tcpprop.**``**cur_sock**``**].prt_tp;**`

Of course, instead of the structure, in the future we will transfer these parameters somewhere in functions, and there already enter into static variables, they say that they are less so lost. But for now, we will temporarily solve this problem in this way. Such a decision also has the right to life.

As in the previous function, fill the buffer with header data, write it to the shipping buffer and move the pointer

`prt = httpsockprop[tcpprop.``cur_sock``].prt_tp;`

`**//Заполним данными буфер для отправки пакета**`

`**memcpy(sect+3,header,header_len);**`

`**w5500_writeSockBuf(tcpprop.cur_sock, end_point, (uint8_t*)sect, header_len);**`

`**end_point+=header_len;**`

`**num_sect = data_len / 512;**`

Similar to the previous function, we will calculate the number of sectors of 512 bytes, add a loop in which we read them from the SD card and write them to the transfer buffer

`num_sect = data_len / 512;`

`**for**``**(i=0;i<=num_sect;i++)**`

`**{**`

`** //не последний сектор**`

`** if**``**(i<(num_sect-1)) len_sect=512;**`

`** else**``** len_sect=data_len;**`

`** result=f_lseek(&MyFile,i*512); **``**//Установим курсор чтения в файле**`

`** sprintf(str1,**``**"f_lseek: %drn"**``**,result);**`

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

`** result=f_read(&MyFile,sect+3,len_sect,(UINT *)&bytesread);**`

`** w5500_writeSockBuf(tcpprop.cur_sock, end_point, (uint8_t*)sect, len_sect);**`

`** end_point+=len_sect;**`

`** data_len -= len_sect;**`

`**}**`

Now we will return the values of the fields of the structure that we have saved above

`data_len -= len_sect;`

`}`

`**//вернем параметры**`

`**httpsockprop[tcpprop.cur_sock].cnt_rem_data_part = last_part;**`

`**httpsockprop[tcpprop.cur_sock].last_data_part_size = last_part_size;**`

`**httpsockprop[tcpprop.cur_sock].prt_tp = prt;**`

Send data to the client

`httpsockprop[tcpprop.cur_sock].prt_tp = prt;`

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

`**RecvSocket(tcpprop.cur_sock);**`

`**SendSocket(tcpprop.cur_sock);**`

Since we transferred one part of the data, we will reduce the number of remaining parts for transmission

`SendSocket(tcpprop.cur_sock);`

`**//будем считать, что одну часть отправили, поэтому количество оставшихся частей декрементируем**`

`**httpsockprop[tcpprop.cur_sock].cnt_rem_data_part--;**`

Next, depending on the number of remaining parts, we will determine what the next part — average or last will be

`httpsockprop[tcpprop.cur_sock].cnt_rem_data_part--;`

`**if**``**(httpsockprop[tcpprop.cur_sock].cnt_rem_data_part>1)**`

`**{**`

`** httpsockprop[tcpprop.cur_sock].data_stat=DATA_MIDDLE;**`

`**}**`

`**else**`

`**{**`

`** httpsockprop[tcpprop.cur_sock].data_stat=DATA_LAST;**`

`**}**`

And at the end of the function, we calculate the total number of bytes transferred. This will be necessary for the following functions in order to set the pointer to the read file in the correct place

`httpsockprop[tcpprop.cur_sock].data_stat=DATA_LAST;`

`}`

`** //Количество переданных байтов**`

`** httpsockprop[tcpprop.cur_sock].total_count_bytes = tcp_size_wnd - header_len;**`

`}`

We’ll collect the code, send a controller and request a larger page in the browser, however, most likely he won’t show it to us, but we have WireShark, in which all the moves are, as they say, recorded. And there we will see if the packages have left us

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

Data transferred, confirmation received. Fine!

Add immediately the workpieces for the transfer functions of the middle and last parts after the function we just wrote

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

`**void**``** tcp_send_http_middle(**``**void**``**)**`

`**{**`

`** uint16_t**``** i=0;**`

`** uint16_t**``** data_len=0;**`

`** uint16_t**``** end_point;**`

`** uint8_t**``** num_sect=0;**`

`** uint8_t**``** prt;**`

`** uint16_t**``** len_sect;**`

`** uint16_t**``** last_part, last_part_size;**`

`** uint32_t**``** count_bytes;**`

`**}**`

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

`**void**``** tcp_send_http_last(**``**void**``**)**`

`**{**`

`** uint16_t**``** i=0;**`

`** uint16_t**``** data_len=0;**`

`** uint16_t**``** end_point;**`

`** uint8_t**``** num_sect=0;**`

`** uint16_t**``** len_sect;**`

`**}**`

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

Only we will call these functions not from the response function to the request, but from the function of accepting and processing the TCP package **w5500_packetReceive**. If you remember, we specially prepared the conditions for this. Only to cause our functions there, it is necessary that they be visible there. To do this, add prototypes to them and then go to function **w5500_packetReceive**, finding more in the file **w5500.c**, and call our functions

`else``if``(httpsockprop[tcpprop.cur_sock].data_stat==DATA_MIDDLE)`

`{`

`if``(httpsockprop[tcpprop.cur_sock].prt_tp == PRT_TCP_HTTP)`

`{`

`**tcp_send_http_middle();**`

`}`

`}`

`else``if``(httpsockprop[tcpprop.cur_sock].data_stat==DATA_LAST)`

`{`

`if``(httpsockprop[tcpprop.cur_sock].prt_tp == PRT_TCP_HTTP)`

`{`

`** tcp_send_http_last();**`

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

`** SocketClosedWait(tcpprop.cur_sock);**`

`** OpenSocket(tcpprop.cur_sock,Mode_TCP);**`

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

`** SocketInitWait(tcpprop.cur_sock);**`

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

`** ListenSocket(tcpprop.cur_sock);**`

`** SocketListenWait(tcpprop.cur_sock);**`

`}`

`}`

`}`

`}`

Well, of course, after transferring the last part of the document, we disconnect with the client and continue to listen to the socket.

Return to file **httpd.c** and first we begin to write the body of the function of transferring the last part of the document. Since we will first try to transmit a document that fits into two parts, and then more voluminous.

We’ll enter the data length variable, we’ll add to the data transfer address and move it

`uint16_t``len_sect;`

`**data_len = httpsockprop[tcpprop.**``**cur_sock**``**].last_data_part_size;**`

`**end_point = GetWritePointer(tcpprop.**``**cur_sock**``**);**`

`**end_point+=data_len;**`

`**SetWritePointer(tcpprop.cur_sock, end_point);**`

`**end_point = GetWritePointer(tcpprop.**``**cur_sock**``**);**`

Count the number of sectors by 512 bytes, add the cycle in which we read them from the SD card and write them to the transfer buffer

`end_point = GetWritePointer(tcpprop.``cur_sock``);`

`**//Заполним данными буфер для отправки пакета**`

`**num_sect = data_len / 512;**`

`**//борьба с неправильным расчётом, когда размер данных делится на размер сектора без остатка**`

`**if**``**(data_len%512==0) num_sect--;**`

`**for**``**(i=0;i<=num_sect;i++)**`

`**{**`

`** //не последний сектор**`

`** if**``**(i<(num_sect-1)) len_sect=512;**`

`** else**``** len_sect=data_len;**`

`** result=f_lseek(&MyFile, (DWORD)(i*512) + httpsockprop[tcpprop.cur_sock].total_count_bytes); **``**//Установим курсор чтения в файле**`

`** sprintf(str1,**``**"f_lseek: %drn"**``**,result);**`

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

`** result=f_read(&MyFile,sect+3,len_sect,(UINT *)&bytesread);**`

`** w5500_writeSockBuf(tcpprop.cur_sock, end_point, (uint8_t*)sect, len_sect);**`

`** end_point+=len_sect;**`

`** data_len -= len_sect;**`

`**}**`

As can be seen from the text of the comment, a situation can happen here when our size is divided by the number of sectors without a trace. It may turn out the wrong calculation. And we fixed it here.

Send our data and set the appropriate status

`data_len -= len_sect;`

`}`

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

`**RecvSocket(tcpprop.cur_sock);**`

`**SendSocket(tcpprop.cur_sock);**`

`**httpsockprop[tcpprop.cur_sock].data_stat = DATA_COMPLETED;**`

We collect the code, sew the controller and see the result in the browser

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

The page has been completely transmitted. In this case, our second buffer fits in one package.

We will also try to convey a page in which the second part will no longer fit into one buffer. I won’t show the browser screenshot already, as the data is becoming more and more, so you can believe me in the word, I will show the screenshot of the traffic analyzer

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

Everything is normally transmitted and confirmed. The connection opens and closes also correctly.

Now we will begin to write the body of the function of transferring the middle part of the document.

It's a little simpler here. We no longer pass the title, as we have already passed it in the last part.

While we get ahead of the data transfer address and move it

`uint32_t``count_bytes;`

`**data_len = tcp_size_wnd;**`

`**end_point = GetWritePointer(tcpprop.**``**cur_sock**``**);**`

`**end_point+=data_len;**`

`**SetWritePointer(tcpprop.cur_sock, end_point);**`

`**end_point = GetWritePointer(tcpprop.**``**cur_sock**``**);**`

Save again some structure parameters

`end_point = GetWritePointer(tcpprop.``cur_sock``);`

`**//сохраним некоторые параметры, а то почему-то они теряются**`

`**last_part = httpsockprop[tcpprop.**``**cur_sock**``**].cnt_rem_data_part;**`

`**last_part_size = httpsockprop[tcpprop.**``**cur_sock**``**].last_data_part_size;**`

`**count_bytes = httpsockprop[tcpprop.**``**cur_sock**``**].total_count_bytes;**`

`**prt = httpsockprop[tcpprop.**``**cur_sock**``**].prt_tp;**`

Count the number of sectors and write them in the transfer buffer, after reading from the media

`prt = httpsockprop[tcpprop.``cur_sock``].prt_tp;`

`**//Заполним данными буфер для отправки пакета**`

`**num_sect = data_len / 512;**`

`**//борьба с неправильным расчётом, когда размер данных делится на размер сектора без остатка**`

`**if**``**(data_len%512==0) num_sect--;**`

`**for**``**(i=0;i<=num_sect;i++)**`

`**{**`

`** //не последний сектор**`

`** if**``**(i<(num_sect-1)) len_sect=512;**`

`** else**``** len_sect=data_len;**`

`** result=f_lseek(&MyFile,(DWORD)(i*512) + count_bytes); **``**//Установим курсор чтения в файле**`

`** result=f_read(&MyFile,sect+3,len_sect,(UINT *)&bytesread);**`

`** w5500_writeSockBuf(tcpprop.cur_sock, end_point, (uint8_t*)sect, len_sect);**`

`** end_point+=len_sect;**`

`** data_len -= len_sect;**`

`**}**`

We will return the previously saved parameters to the structure fields

`data_len -= len_sect;`

`}`

`**//вернем параметры**`

`**httpsockprop[tcpprop.cur_sock].cnt_rem_data_part = last_part;**`

`**httpsockprop[tcpprop.cur_sock].last_data_part_size = last_part_size;**`

`**httpsockprop[tcpprop.cur_sock].total_count_bytes = count_bytes;**`

`**httpsockprop[tcpprop.cur_sock].prt_tp = prt;**`

We will hand over the buffer to the client

`httpsockprop[tcpprop.cur_sock].prt_tp = prt;`

`**RecvSocket(tcpprop.cur_sock);**`

`**SendSocket(tcpprop.cur_sock);**`

We will reduce the number of remaining parts for transmission and further, depending on the number of remaining parts, determine what the next part — average or last will be

`SendSocket(tcpprop.cur_sock);`

`**//будем считать, что одну часть отправили, поэтому количество оставшихся частей декрементируем**`

`**httpsockprop[tcpprop.cur_sock].cnt_rem_data_part--;**`

`**if**``**(httpsockprop[tcpprop.cur_sock].cnt_rem_data_part>1)**`

`**{**`

`** httpsockprop[tcpprop.cur_sock].data_stat=DATA_MIDDLE;**`

`**}**`

`**else**`

`**{**`

`** httpsockprop[tcpprop.cur_sock].data_stat=DATA_LAST;**`

`**}**`

And at the end of the function, we will add the number of transmitted bytes of the document

`httpsockprop[tcpprop.cur_sock].data_stat=DATA_LAST;`

`}`

`** //Количество переданных байтов**`

`** httpsockprop[tcpprop.cur_sock].total_count_bytes += (uint32_t) tcp_size_wnd;**`

`}`

Well, that’s all.

We collect the code, sew the controller and try to transfer various documents of different sizes, including including pictures

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

So, today we have mastered another interesting chip that provides data transmission over the LAN — **W5500**, which allows you to work with the TCP / IP stack at the hardware level, which will save our hardware resources to a very large extent, which, as we mean, are often lacking.

Thank you all for your attention!

[Embedded media](https://www.youtube.com/embed/b5gvbA1u450)

---

Source: https://maker.wiznet.io/teddy/projects/stm-lesson-91-lan-w5500-http-server-part-5/
