2019-09-04 03:04 AM
Hi,
I have configured STM32 as a server using tcp_echoserver example. I'm receiving data through tcp_echoserver_revc() function.
I'm receiving packets in this way: #INIT*
When STM32 receive X packets (Around 14), it stops receiving data and TCP connection disconnects from PC. However, STM32 still working normally (except lwip part). It can't receive or send any packet.
All configuration is by default, IP fixed.
This is a capture from wireshark. 192.168.1.40 is the IP of STM32. When STM32 fails, black lines appear.
As I say, it is all by default. I have only modified tcp_echoserver.c file. I write below functions that belongs to that file.
2019-09-04 03:06 AM
err_t tcp_server_init(void)
{
/* create new tcp pcb */
if ((tcp_server_pcb = tcp_new()) == NULL)
{
return ERR_MEM;
}
/* bind echo_pcb to port 7 (ECHO protocol) */
if (tcp_bind(tcp_server_pcb, IP_ADDR_ANY, 7) != ERR_OK)
{
tcp_abort(tcp_server_pcb);
return ERR_USE;
}
if ((lpcb = tcp_listen(tcp_server_pcb)) == NULL)
{
tcp_abort(tcp_server_pcb);
return ERR_MEM;
}
tcp_accept(lpcb, tcp_server_accept);
//memp_free(MEMP_TCP_PCB, tcp_server_pcb);
return ERR_OK;
}
/**
* @brief This function is the implementation of tcp_accept LwIP callback
* @param arg: not used
* @param newpcb: pointer on tcp_pcb struct for the newly created tcp connection
* @param err: not used
* @retval err_t: error status
*/
static err_t tcp_server_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
err_t ret_err;
struct tcp_echoserver_struct *es;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(err);
/* set priority for the newly accepted tcp connection newpcb */
tcp_setprio(newpcb, TCP_PRIO_NORMAL);
/* allocate structure es to maintain tcp connection informations */
es = (struct tcp_echoserver_struct *)mem_malloc(sizeof(struct tcp_echoserver_struct));
if (es != NULL)
{
es->state = ES_ACCEPTED;
es->pcb = newpcb;
es->retries = 0;
es->p = NULL;
/* pass newly allocated es structure as argument to newpcb */
tcp_arg(newpcb, es);
/* initialize lwip tcp_recv callback function for newpcb */
tcp_recv(newpcb, tcp_server_recv);
/* initialize lwip tcp_err callback function for newpcb */
tcp_err(newpcb, tcp_server_error);
/* initialize lwip tcp_poll callback function for newpcb */
tcp_poll(newpcb, tcp_server_poll, 1);
ret_err = ERR_OK;
}
else
{
/* close tcp connection */
tcp_server_connection_close(newpcb, es);
/* return memory error */
ret_err = ERR_MEM;
}
return ret_err;
}
/**
* @brief This function is the implementation for tcp_recv LwIP callback
* @param arg: pointer on a argument for the tcp_pcb connection
* @param tpcb: pointer on the tcp_pcb connection
* @param pbuf: pointer on the received pbuf
* @param err: error information regarding the reveived pbuf
* @retval err_t: error code
*/
static err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
struct tcp_echoserver_struct *es;
err_t ret_err;
LWIP_ASSERT("arg != NULL",arg != NULL);
es = (struct tcp_echoserver_struct *)arg;
/* if we receive an empty tcp frame from client => close connection */
if (p == NULL)
{
/* remote host closed connection */
es->state = ES_CLOSING;
if(es->p == NULL)
{
/* we're done sending, close connection */
tcp_server_connection_close(tpcb, es);
}
else
{
/* we're not done yet */
/* acknowledge received packet */
tcp_sent(tpcb, tcp_server_sent);
}
ret_err = ERR_OK;
}
/* else : a non empty frame was received from client but for some reason err != ERR_OK */
else if(err != ERR_OK)
{
/* free received pbuf*/
if (p != NULL)
{
es->p = NULL;
pbuf_free(p);
}
ret_err = err;
}
else if(es->state == ES_ACCEPTED)
{
/* first data chunk in p->payload */
es->state = ES_RECEIVED;
/* store reference to incoming pbuf (chain) */
es->p = p;
/* initialize LwIP tcp_sent callback function */
tcp_sent(tpcb, tcp_server_sent);
/* send back the received data (echo) */
memcpy(&BufferAux,p->payload,p->len);
pos = 0;
while (pos < p->len){
BufferETH[BuffPosIn_ETH++] = BufferAux[pos++];
if (BuffPosIn_ETH >= sizeof(BufferETH))
{
BuffPosIn_ETH = 0;
}
}
memcpy(&BufferAux,0,sizeof(BufferAux));
ret_err = ERR_OK;
}
else if (es->state == ES_RECEIVED)
{
/* more data received from client and previous data has been already sent*/
if(es->p == NULL)
{
es->p = p;
/* send back received data */
}
else
{
struct pbuf *ptr;
tcp_sent(tpcb, tcp_server_sent);
/* chain pbufs to the end of what we recv'ed previously */
ptr = es->p;
memcpy(&BufferAux,p->payload,p->len);
pos = 0;
while (pos < p->len){
BufferETH[BuffPosIn_ETH++] = BufferAux[pos++];
if (BuffPosIn_ETH >= sizeof(BufferETH))
{
BuffPosIn_ETH = 0;
}
}
memcpy(&BufferAux,0,sizeof(BufferAux));
pbuf_chain(ptr,p);
}
ret_err = ERR_OK;
}
else if(es->state == ES_CLOSING)
{
/* odd case, remote side closing twice, trash data */
tcp_recved(tpcb, p->tot_len);
es->p = NULL;
pbuf_free(p);
ret_err = ERR_OK;
}
else
{
/* unkown es->state, trash data */
tcp_recved(tpcb, p->tot_len);
es->p = NULL;
pbuf_free(p);
ret_err = ERR_OK;
}
return ret_err;
}
/**
* @brief This function implements the tcp_err callback function (called
* when a fatal tcp_connection error occurs.
* @param arg: pointer on argument parameter
* @param err: not used
* @retval None
*/
static void tcp_server_error(void *arg, err_t err)
{
struct tcp_echoserver_struct *es;
LWIP_UNUSED_ARG(err);
es = (struct tcp_echoserver_struct *)arg;
if (es != NULL)
{
/* free es structure */
mem_free(es);
}
}
/**
* @brief This function implements the tcp_poll LwIP callback function
* @param arg: pointer on argument passed to callback
* @param tpcb: pointer on the tcp_pcb for the current tcp connection
* @retval err_t: error code
*/
static err_t tcp_server_poll(void *arg, struct tcp_pcb *tpcb)
{
err_t ret_err;
struct tcp_echoserver_struct *es;
es = (struct tcp_echoserver_struct *)arg;
if (es != NULL)
{
if (es->p != NULL)
{
//tcp_sent(tpcb, tcp_server_sent);
/* there is a remaining pbuf (chain) , try to send data */
//tcp_server_send(tpcb, es);
}
else
{
/* no remaining pbuf (chain) */
if(es->state == ES_CLOSING)
{
/* close tcp connection */
tcp_server_connection_close(tpcb, es);
}
}
ret_err = ERR_OK;
}
else
{
/* nothing to be done */
tcp_abort(tpcb);
ret_err = ERR_ABRT;
}
return ret_err;
}
void send_ETH(char *msg)
{
uint16_t len = strlen(msg);
tcp_write(tcp_server_pcb, msg, len, 1);
tcp_output(tcp_server_pcb);
}
/**
* @brief This function implements the tcp_sent LwIP callback (called when ACK
* is received from remote host for sent data)
* @param None
* @retval None
*/
static err_t tcp_server_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
struct tcp_echoserver_struct *es;
LWIP_UNUSED_ARG(len);
es = (struct tcp_echoserver_struct *)arg;
es->retries = 0;
if(es->p != NULL)
{
/* still got pbufs to send */
tcp_sent(tpcb, tcp_server_sent);
//tcp_server_send(tpcb, es);
}
else
{
/* if no more data to send and client closed connection*/
if(es->state == ES_CLOSING)
tcp_server_connection_close(tpcb, es);
}
return ERR_OK;
}
/**
* @brief This function is used to send data for tcp connection
* @param tpcb: pointer on the tcp_pcb connection
* @param es: pointer on echo_state structure
* @retval None
*/
static void tcp_server_send(struct tcp_pcb *tpcb, struct tcp_echoserver_struct *es)
{
struct pbuf *ptr;
err_t wr_err = ERR_OK;
while ((wr_err == ERR_OK) &&
(es->p != NULL) &&
(es->p->len <= tcp_sndbuf(tpcb)))
{
/* get pointer on pbuf from es structure */
ptr = es->p;
/* enqueue data for transmission */
wr_err = tcp_write(tpcb, ptr->payload, ptr->len, 1);
if (wr_err == ERR_OK)
{
u16_t plen;
u8_t freed;
plen = ptr->len;
/* continue with next pbuf in chain (if any) */
es->p = ptr->next;
if(es->p != NULL)
{
/* increment reference count for es->p */
pbuf_ref(es->p);
}
/* chop first pbuf from chain */
do
{
/* try hard to free pbuf */
freed = pbuf_free(ptr);
}
while(freed == 0);
/* we can read more data now */
tcp_recved(tpcb, plen);
}
else if(wr_err == ERR_MEM)
{
/* we are low on memory, try later / harder, defer to poll */
es->p = ptr;
}
else
{
/* other problem ?? */
}
}
}
/**
* @brief This functions closes the tcp connection
* @param tcp_pcb: pointer on the tcp connection
* @param es: pointer on echo_state structure
* @retval None
*/
static void tcp_server_connection_close(struct tcp_pcb *tpcb, struct tcp_echoserver_struct *es)
{
/* remove all callbacks */
tcp_arg(tpcb, NULL);
tcp_sent(tpcb, NULL);
tcp_recv(tpcb, NULL);
tcp_err(tpcb, NULL);
tcp_poll(tpcb, NULL, 0);
/* delete es structure */
if (es != NULL)
{
mem_free(es);
}
/* close tcp connection */
tcp_close(tpcb);
}
2019-09-06 12:45 AM
I have use tcp_echoserver.c file by default, adding these lines in order to save data into a buffer, it works fine. However, it's always making echo.
memcpy(&BufferAux,p->payload,p->len);
pos = 0;
while (pos < p->len){
BufferETH[BuffPosIn_ETH++] = BufferAux[pos++];
if (BuffPosIn_ETH >= sizeof(BufferETH))
{
BuffPosIn_ETH = 0;
}
}
memcpy(&BufferAux,0,sizeof(BufferAux));
Anyone can help me? Thanks.
2019-09-06 01:54 AM
Not much experience with ethernet applications on STM32.
But the observed effect reminds me similar problems with other serial peripherals and demo projects. If a problem like overflow happens, reception effectively stops until you explicitly clear the respective error flag.
Some examples and demo projects exhibit a "walk in the sunshine" approach, i.e. they bravely skip most error checking and processing.
2019-09-06 02:42 AM
In my case, I think there's a buffer or memory problem, but I can't find it.
2024-03-07 01:54 PM
hi
did you fix the issue??? I have a very similar issue: after 16 commands, stm32 only queues commands
I use LWIP on a STM32H7 custom board.
I send command from a PC using Hercules
I use TCP, my stm32 is a server
Board receives commands and parses them out.
After I sent 16 commands, on the 16th command, pbuf_chain is called. On the first 15 commands tcp_server_handle is called.
I use the example in
https://controllerstech.com/stm32-ethernet-4-tcp-server/
I have MEMP_NUM_PBUF set to 16 and MEMP_NUMTCP_SEG set to 16. Tried to increase these parameters, didn’t help.
15) Then send command CmdA of 102 bytes, Hercules gets response of 12 bytes, no issue here.
16) send command CmdB of 102 bytes, STM32 does not respond but command is put in a chain (pbuf_chain is called in tp_server_recv)
Why the 16th command is queued in the chain and not processed.
thanks