2024-06-25 08:43 AM - edited 2024-06-25 08:44 AM
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
2024-06-28 08:55 AM
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,