Skip to content

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

HTTP Server Lecture Using STM32F401RET6 and W5500

teddy

Published August 02, 2023

Original author: Narod stream · RussiaOriginal source (new tab)

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

Components

Hardware components

WIZnet parts

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

 

image45

 

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

 

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

 

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

 

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!

 

Documents

  • W5500 HTTP Server

    W5500 HTTP Server code zip file

Comments

Similar projects you might like

Comments