Skip to main content
Graduate II
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

    This topic has been closed for replies.

    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,