STM Lesson 91. LAN. W5500. HTTP Server. Part 5
HTTP Server Lecture Using STM32F401RET6 and W5500
1
Project description
Part 5
LAN. W5500. HTTP server
B previous part 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

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

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

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

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!

