cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4-Discovery LWIP - Stops receiving data after X packets

JCOrtiz
Associate II

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.

0690X00000AQkJ6QAL.jpg

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.

5 REPLIES 5
JCOrtiz
Associate II
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);
}

JCOrtiz
Associate II

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.

Ozone
Lead

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.

JCOrtiz
Associate II

In my case, I think there's a buffer or memory problem, but I can't find it.

YCHTI.1
Associate II

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.

 

  • First time Isend a command of 7 bytes, Hercules gets response of 12 bytes (from stm32 board, no issue here)
  • Then send command CmdA of 102 bytes, Hercules gets response of 12 bytes, no issue here.
  • Then send another command CmdB of 102 bytes, Hercules  gets response of 12 bytes, no issue here.
  • Send command 7 bytes, Hercules Hercules gets response of 12 bytes
  • Then send command CmdA of 102 bytes, Hercules gets response of 12 bytes

 

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