Skip to main content
Associate III
June 25, 2024
Question

TCP Client outputs wrong data after couple of minutes

  • June 25, 2024
  • 1 reply
  • 1568 views

I have coded a TCP client on a ST32F746ZGT6 and i am receiving data from a TCP sever with a rate of 50hz and a packet size of 1460 bytes through ethernet. as part of my TCP client in tcp_client_handle function, i am extracting only 4 bytes of the receive packets and send it another device by Wi-Fi. Here is my code for the whole TCP client:

 

 

int counter = 0;
uint8_t data[100];

extern TIM_HandleTypeDef htim1;

/* create a struct to store data */
struct tcp_client_struct *esTx = 0;

struct tcp_pcb *pcbTx = 0;

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	char buf[100];

	/* Prepare the first message to send to the server */
	int len = sprintf (buf, "This is APM Computer %d\n", counter);

	if (counter !=0)
	{
		/* allocate pbuf */
		esTx->p = pbuf_alloc(PBUF_TRANSPORT, len , PBUF_POOL);


		/* copy data to pbuf */
		pbuf_take(esTx->p, (char*)buf, len);

		tcp_client_send(pcbTx, esTx);

		pbuf_free(esTx->p);
	}

}
/* IMPLEMENTATION FOR TCP CLIENT

1. Create TCP block.
2. connect to the server
3. start communicating
*/

void tcp_client_init(void)
{
	/* 1. create new tcp pcb */
	struct tcp_pcb *tpcb;

	tpcb = tcp_new();

	/* 2. Connect to the server (PDAS) */
	ip_addr_t destIPADDR;
	IP_ADDR4(&destIPADDR, 192, 168, 1, 254);// PDAS IP Address
	tcp_connect(tpcb, &destIPADDR, 49000, tcp_client_connected); // PDAS port number
}

/** This callback is called, when the client is connected to the server
 * Here we will initialise few other callbacks
 * and in the end, call the client handle function
 */
static err_t tcp_client_connected(void *arg, struct tcp_pcb *newpcb, err_t err)
{
 err_t ret_err;
 struct tcp_client_struct *es;

 LWIP_UNUSED_ARG(arg);
 LWIP_UNUSED_ARG(err);

 /* allocate structure es to maintain tcp connection information */
 es = (struct tcp_client_struct *)mem_malloc(sizeof(struct tcp_client_struct));
 if (es != NULL)
 {
 es->state = ES_CONNECTED;
 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_client_recv);

 ret_err = ERR_OK;
 }
 else
 {
 /* close tcp connection */
 tcp_client_connection_close(newpcb, es);
 /* return memory error */
 ret_err = ERR_MEM;
 }
 return ret_err;
}


/** This callback is called, when the client receives some data from the server
 * if the data received is valid, we will handle the data in the client handle function
 */
static err_t tcp_client_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
 struct tcp_client_struct *es;
 err_t ret_err;

 LWIP_ASSERT("arg != NULL",arg != NULL);

 es = (struct tcp_client_struct *)arg;

 /* if we receive an empty tcp frame from server => close connection */
 if (p == NULL)
 {
 /* remote host closed connection */
 es->state = ES_CLOSING;
 if(es->p == NULL)
 {
 /* we're done sending, close connection */
 tcp_client_connection_close(tpcb, es);
 }
 ret_err = ERR_OK;
 }
 /* else : a non empty frame was received from server 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_CONNECTED)
 {
 /* store reference to incoming pbuf (chain) */
	//load reduction on the receiver data handling func
	receive_reduc_counter++;
	if (receive_reduc_counter == 5){

 es->p = p;
 /* handle the received data */

 tcp_client_handle(tpcb, es);
	receive_reduc_counter = 0;
	}

 /* Acknowledge the received data */
 tcp_recved(tpcb, p->tot_len);

 pbuf_free(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
 {
 /* unknown es->state, trash data */
 tcp_recved(tpcb, p->tot_len);
 es->p = NULL;
 pbuf_free(p);
 ret_err = ERR_OK;
 }
 return ret_err;
}

/** This callback is called, when the server acknowledges the data sent by the client
 * If there is no more data left to sent, we will simply close the connection
 */
static err_t tcp_client_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
 struct tcp_client_struct *es;

 LWIP_UNUSED_ARG(len);

 es = (struct tcp_client_struct *)arg;
 es->retries = 0;

 if(es->p != NULL)
 {
	// tcp_sent has already been initialized in the beginning.
 /* still got pbufs to send */

 }
 else
 {
 /* if no more data to send and client closed connection*/
 if(es->state == ES_CLOSING)
 tcp_client_connection_close(tpcb, es);
 }
 return ERR_OK;
}

/** A function to send the data to the server
 */
static void tcp_client_send(struct tcp_pcb *tpcb, struct tcp_client_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;
 }
 }
}


static void tcp_client_connection_close(struct tcp_pcb *tpcb, struct tcp_client_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);
}

/* Handle the incoming TCP Data */

static void tcp_client_handle (struct tcp_pcb *tpcb, struct tcp_client_struct *es)
{

 if (es->p->len == 1460) {
 memcpy(ch7, es->p->payload + 1124, 4);

	fch7 = charBufferToFloat(ch7);
#ifdef DEBUG
	if (fch7 < 2){
////	for (int i = 0; i < 12; i++)
////	{
////	 trace_printf("%02X", ch7[i]);
////	 trace_printf(":");
////	}
////	printf("\n");
 trace_printf("%f\n",fch7);
	}
#endif
 sprintf(buf_PDAS, "PDAS_data,%f",fch7);
 err = WIFI_Send(buf_PDAS);

 }
	counter++;
}

float charBufferToFloat(char buffer[4]) {
 // Create an instance of the union
 union IntFloatUnion converter;

 // Combine the bytes into the intValue part of the union
 // Assuming buffer is in little endian order
 converter.intValue = (uint8_t)buffer[0] |
 ((uint8_t)buffer[1] << |
 ((uint8_t)buffer[2] << 16) |
 ((uint8_t)buffer[3] << 24);

 // Return the float value
 return converter.floatValue;
}

 

 

Everything work fine for couple of minutes ( up to 25 minutes), however it outputs zero for the rest of the packets. It worth mentioning that if i print the extracted values in the receive handle function, it output zero after almost 5 seconds, so probably its the question of load handling on the MCU. (I have attached my LWIP configuration for TCP connection.)

Any help or advice would be highly appreciated.

 

Amir

1 reply

ST Employee
June 28, 2024

Hello @amirshn 

It seems there's a discrepancy in your TCP_MSS setting. The standard MTU for Ethernet networks is 1500 bytes, leading to a TCP_MSS of 1460 bytes once you account for the IP and TCP headers. Your current TCP_MSS value is set for an MTU that exceeds the Ethernet standard (1750 bytes).

Could you please verify your network's MTU and adjust the TCP_MSS as needed to prevent unnecessary packet fragmentation?

 

With Regards,

"If your question is answered, please close this topic by clicking ""Accept as Solution""."