cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F407 LWIP returning data to client

Raymond Buck
Senior

I previously posted here when I was having issues with my STM32F407 board that I have configured as a HTTP server.
https://community.st.com/t5/stm32-mcus-products/where-to-find-lwip-incoming-payload-data-for-webserver/m-p/640137

This is a follow-up post with more questions. The server is apparently working more or less the way it should. Wireshark shows the following data. The first 3 lines are when I connect to the server. The next 8 lines are when I click a button on my page. It appears that the button sequence all is working properly as the server ACks, client ACKs, and back and forth until the transaction is complete. The really strange thing is, the last 8 lines are repeated 9 more times before transmissions stop. Transmissions should stop after the first full handshaking sequence completes. Any idea why it repeats an additional 9 times?

Source Destination Protocol Length Info

172.16.1.115 172.16.1.125 TCP 66 65055 → 80 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 WS=256 SACK_PERM
172.16.1.125 172.16.1.115 TCP 60 80 → 65055 [SYN, ACK] Seq=0 Ack=1 Win=2144 Len=0 MSS=536
172.16.1.115 172.16.1.125 TCP 54 65055 → 80 [ACK] Seq=1 Ack=1 Win=65392 Len=0

172.16.1.115 172.16.1.125 HTTP 381 GET /button_request?data=test2%2Cbutton_2%2COFF HTTP/1.1
172.16.1.125 172.16.1.115 TCP 60 80 → 65055 [FIN, ACK] Seq=1 Ack=328 Win=1817 Len=0
172.16.1.115 172.16.1.125 TCP 54 65055 → 80 [ACK] Seq=328 Ack=2 Win=65392 Len=0
172.16.1.115 172.16.1.125 TCP 54 65055 → 80 [FIN, ACK] Seq=328 Ack=2 Win=65392 Len=0
172.16.1.125 172.16.1.115 TCP 60 80 → 65055 [ACK] Seq=2 Ack=329 Win=1816 Len=0
172.16.1.115 172.16.1.125 TCP 66 65056 → 80 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 WS=256 SACK_PERM
172.16.1.125 172.16.1.115 TCP 60 80 → 65056 [SYN, ACK] Seq=0 Ack=1 Win=2144 Len=0 MSS=536
172.16.1.115 172.16.1.125 TCP 54 65056 → 80 [ACK] Seq=1 Ack=1 Win=65392 Len=0

I am able to intercept the button messages, and turn on/off the corresponding LEDs on the board. This is done by copying the button ID to a global variable in http_parse_request function (in httpd.c). In my main.c module I read the button info from the global variable as part of the while(1) loop and control the LEDs.

What I can't figure out is how to return data to the client. I want to return text such as "LED is on" and display it on the web page. Also, prior to returning the data, I will check the actual GPIO pin level to confirm that the LED is actually on.

Where would I insert the message to return it to the client? From reading, I understand I need to issue a http_write() to enqueue the data. After that, the message should be automatically be sent to the client. At least that is the way I understand it. Or is that not correct? Do I somehow need to append my message to the incoming button message?

The http_parse_request function is 174 lines long and somewhat confusing. Running the debugger and setting a breakpoint at this line: "return http_find_file(hs, uri, is_09);", I see that uri conains my button click information.

I have very little knowledge of how LWIP works. And even less knowledge of how it works with STM32 parts. From what I have read, ST is no longer updating the LWIP stack that works with the STM32F4 parts. They are pushing the STM32F7 as the solution for LWIP. But reading a lot of posts and questions online, LWIP doesn't really work with the STM32F7 parts. For a very simple application, the F7 parts are overkill. I just want to turn a LED on and return a "LED is on" message to the client.

1 ACCEPTED SOLUTION

Accepted Solutions

@pavel A
Why would it be out of scope? I am using a STM32F407 Discovery board. I am using STM32CubeIDE as the project development tool. It is not a LWIP issue or a FreeRTOS issue. It is simply a case of the CubeIDE tool not being able to generate the proper code for the LWIP/RTOS to function properly. If you look online, you will find many, many users who have the same issues/questions that I was experiencing.

I finally managed to get the LWIP/RTOS combination to work. I quit using STM32CubeIDE 1.14.1 and went back to STM32CubeIDE 1.12.0. Generating the project that way allowed me to at least ping the board.

I still could not access the server with a browser. Using the .ioc setup tool, I specifically told it I wanted LwIP HTTPD Support. I found that in the StartDefaultTask() function that CubeMX did call MX_LWIP_Init(). However, for some reason, it did not call httpd_init(). I added that after MX_LWIP_Init. I then received a warning that I had created an implicit declaration of the function. Adding #include "httpd.h" to the /* USER CODE BEGIN Includes */ section solved that problem.

I am now able to access the HTTPD server and pass messages back and forth. That is all I was attempting to do from the start. But the CubeMX tool is either not smart enough, or broken, so it can't create valid code for LWIP/RTOS to function properly.

View solution in original post

9 REPLIES 9
LCE
Principal

There is no more support concerning LWIP for F7 than for F4 I guess.

More bad news: you have to work a lot through LWIP, there's no way around that.

In the STM32 server html files I use SSI / CGI with tags, like so (the <!--#tFv-->):

<br><br><b>Firmware version:</b><br>
<!--#tFv-->
<br><br>

And then in some extra "http_cgi_ssi.c/h files I have my own SSI / CGI handler functions, snippet:

#define SSI_NUMBER_OF_TAGS		21

/* SSI tags, must correspond to those used in html file */
char const *szSSI_tags[SSI_NUMBER_OF_TAGS] =
{
	"tFv", "tTn", "tPtp",
	"tL1", "tL2", "tL3", "tLb",
	"tAVM", "tAVY", "tAVP", "tAVS", "tAVA", "tAVI", "tARf",
	"tTmp", "tTsn",
	"tPer",
	"tSfrq", "tSamp", "tSoff",
	"tSact"
};


/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* functions */


/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/**
  * @brief  Global_SSI_Handler : SSI handler for all pages
  */
u16_t Global_SSI_Handler(int iIndex, char *pcInsert, int iInsertLen)
{
	uint16_t u16AdcVal = 0;
	float flVal = 0.0f;
	char szAdcVal[32] = { 0 };

	UNUSED(u16AdcVal);

/* +++++++++++++++++++++++++++++++++++++++++++++++++ */
/* system info */

/* SSI index = 0 -> firmware version */
	if( 0 == iIndex )
	{
		char szMACAdr[32] = { 0 };
		char szIp4Adr[32] = { 0 };
		char szFw4SSI[256] = { 0 };

		/* prepare data to be inserted in html */
		sprintf(szMACAdr, "<b>MAC:</b> %02X:%02X:%02X:%02X:%02X:%02X", gNetIf.hwaddr[0], gNetIf.hwaddr[1], gNetIf.hwaddr[2], gNetIf.hwaddr[3], gNetIf.hwaddr[4], gNetIf.hwaddr[5]);
		sprintf(szIp4Adr, "<b>IP4:</b> %s", ipaddr_ntoa(netif_ip4_addr(&gNetIf)));
#if( 0 == NUCLEO_F767 )
		sprintf(szFw4SSI, "STM32F767 ETH_Test_Rev_A<br>build date: %s, %s<br>%s<br>%s<br><b>DNS:</b> %s", szFW_date, szFW_time, szMACAdr, szIp4Adr, gNetIf.hostname);
#else
		sprintf(szFw4SSI, "STM32F767 Nucleo<br>build date: %s, %s<br>%s<br>%s<br><b>DNS:</b> %s", szFW_date, szFW_time, szMACAdr, szIp4Adr, gNetIf.hostname);
#endif

		strcpy(pcInsert, szFw4SSI);
		return strlen(szFw4SSI);
	}

So there is no way to return a value to the client other than CGI/SSI?

I don't know.

For me that was the most simple way, with http / html.

Pavel A.
Evangelist III

There are more ways. Web sockets for one. This CGI/SSI thing is so XX century.

Pavel, any links on how to use websockets with embedded MCUs, maybe specifically for STM32?

Do you think this is the best way to do what I am attempting? It seems so, since it allows bi-directional communications.

Well, I tired to use FreeRTOS with LWIP on my board. I wanted to try Netconn as it would probably do what I want to do. No luck.. FreeRTOS appears to be working as it is supposed to. I created a couple of tasks to flash the LEDs and they are flashing. However, after a few hours of trying different things, LWIP does not work. No ping reply and no HTTPD access.

So if I have any hope of getting my application to work I will have to stick to CGI/SSI. Or move on to a processor from a different manufacturer.

@Raymond Buck this is out of scope of this forum. Please ask on stack overflow, ask Chatgpt, Copilot. Or find a consultant.

 

@pavel A
Why would it be out of scope? I am using a STM32F407 Discovery board. I am using STM32CubeIDE as the project development tool. It is not a LWIP issue or a FreeRTOS issue. It is simply a case of the CubeIDE tool not being able to generate the proper code for the LWIP/RTOS to function properly. If you look online, you will find many, many users who have the same issues/questions that I was experiencing.

I finally managed to get the LWIP/RTOS combination to work. I quit using STM32CubeIDE 1.14.1 and went back to STM32CubeIDE 1.12.0. Generating the project that way allowed me to at least ping the board.

I still could not access the server with a browser. Using the .ioc setup tool, I specifically told it I wanted LwIP HTTPD Support. I found that in the StartDefaultTask() function that CubeMX did call MX_LWIP_Init(). However, for some reason, it did not call httpd_init(). I added that after MX_LWIP_Init. I then received a warning that I had created an implicit declaration of the function. Adding #include "httpd.h" to the /* USER CODE BEGIN Includes */ section solved that problem.

I am now able to access the HTTPD server and pass messages back and forth. That is all I was attempting to do from the start. But the CubeMX tool is either not smart enough, or broken, so it can't create valid code for LWIP/RTOS to function properly.

LCE
Principal

That's why I use CubeMX only for basic clock and GPIO setup.

Everything else is: "let's hope it's doing something, but don't trust it".

After my first not so good experiences with CubeMX (including the typical beginner mistake that own code gets overwritten when adding or changing things in Cube, or updating HAL), I found that the examples helped me much more.

And ethernet + LWIP is a hell of complicated stuff, it would be more of a surprise if it works just by clicking through CubeMX.

When doing all this for a professional product, I must have a deeper understanding anyway.
That's why I switched for the important / (time) critical peripherals to direct register access.