Skip to main content
Explorer II
September 30, 2024
Solved

problem receiving multiple data with ethernet

  • September 30, 2024
  • 1 reply
  • 813 views

Hello,

I'm using an STM32 F4 board as a TCP Server and the hercule application on my PC as a TCP Client.

I follow the online tutorial proposed by controllersTech for the configuration.

This is what my program does: If I send the message "1" to the server then he replays me back some message. And if I send message other than "1" then he replays me back some other message.

The connexion work well and I can interact with the server for 9 interactions, after that, I can no longer interacting with the server.

Here are my code:

 

 

#include "tcpserverRAW.h"

#include "lwip/tcp.h"
#include <string.h>

/* protocol states */
enum tcp_server_states
{
 ES_NONE = 0,
 ES_ACCEPTED,
 ES_RECEIVED,
 ES_CLOSING
};

struct tcp_server_struct
{
 u8_t state; /* current connection state */
 u8_t retries;
 struct tcp_pcb *pcb; /* pointer on the current tcp_pcb */
 struct pbuf *p; /* pointer on the received/to be transmitted pbuf */
};

#define SIZE_BUFFER 50
char buf_rx[SIZE_BUFFER];
char buf_tx[SIZE_BUFFER + 20];

extern TIM_HandleTypeDef htim2;
int button_state = 0;
struct tcp_pcb *tpcb_loop;
struct tcp_server_struct *es_loop;

static err_t tcp_server_accept(void *arg, struct tcp_pcb *newpcb, err_t err);
static err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err);
static void tcp_server_error(void *arg, err_t err);
static err_t tcp_server_poll(void *arg, struct tcp_pcb *tpcb);
static err_t tcp_server_sent(void *arg, struct tcp_pcb *tpcb, u16_t len);
static void tcp_server_send(struct tcp_pcb *tpcb, struct tcp_server_struct *es);
static void tcp_server_connection_close(struct tcp_pcb *tpcb, struct tcp_server_struct *es);

static void tcp_server_handle (struct tcp_pcb *tpcb, struct tcp_server_struct *es);

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

	tpcb = tcp_new();

	err_t err;

	/* 2. bind _pcb to port 7 ( protocol) */
	ip_addr_t myIPADDR;
	IP_ADDR4(&myIPADDR, 172, 16, 1, 2);
	err = tcp_bind(tpcb, &myIPADDR, 7);

	if (err == ERR_OK)
	{
		/* 3. start tcp listening for _pcb */
		tpcb = tcp_listen(tpcb);

		/* 4. initialize LwIP tcp_accept callback function */
		tcp_accept(tpcb, tcp_server_accept);
	}
	else
	{
		/* deallocate the pcb */
		memp_free(MEMP_TCP_PCB, tpcb);
	}
}

static err_t tcp_server_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
 err_t ret_err;
 struct tcp_server_struct *es;

 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_SET);

 LWIP_UNUSED_ARG(arg);
 LWIP_UNUSED_ARG(err);

 /* set priority for the newly accepted tcp connection newpcb */
 tcp_setprio(newpcb, TCP_PRIO_MIN);

 /* allocate structure es to maintain tcp connection information */
 es = (struct tcp_server_struct *)mem_malloc(sizeof(struct tcp_server_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, 0);

 tpcb_loop = newpcb;
	es_loop = es;

	//HAL_TIM_Base_Start_IT(&htim2);

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

static err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
 struct tcp_server_struct *es;
 err_t ret_err;

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

 es = (struct tcp_server_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);

 /* send remaining data*/
 tcp_server_send(tpcb, es);
 }
 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);

 /* handle the received data */
 tcp_server_handle(tpcb, es);

 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;

 /* handle the received data */
 tcp_server_handle(tpcb, es);
 }
 else
 {
 struct pbuf *ptr;

 /* chain pbufs to the end of what we recv'ed previously */
 ptr = es->p;
 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
 {
 /* unknown 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.
 * arg: pointer on argument parameter
 * err: not used
 * @retval None
 */
static void tcp_server_error(void *arg, err_t err)
{
 struct tcp_server_struct *es;

 LWIP_UNUSED_ARG(err);

 es = (struct tcp_server_struct *)arg;
 if (es != NULL)
 {
 /* free es structure */
 mem_free(es);
 }
}

/**
 * @brief This function implements the tcp_poll LwIP callback function
 * arg: pointer on argument passed to callback
 * 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_server_struct *es;

 es = (struct tcp_server_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;
}

/**
 * @brief This function implements the tcp_sent LwIP callback (called when ACK
 * is received from remote host for sent data)
 * None
 * @retval None
 */
static err_t tcp_server_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
 struct tcp_server_struct *es;

 LWIP_UNUSED_ARG(len);

 es = (struct tcp_server_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
 * tpcb: pointer on the tcp_pcb connection
 * es: pointer on _state structure
 * @retval None
 */
static void tcp_server_send(struct tcp_pcb *tpcb, struct tcp_server_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 ?? */
 }
 }
}

static void tcp_server_connection_close(struct tcp_pcb *tpcb, struct tcp_server_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_server_handle (struct tcp_pcb *tpcb, struct tcp_server_struct *es)
{
	//memset(buf_rx, '\0', SIZE_BUFFER);
	//strncpy(buf_rx, (char *)es->p->payload, es->p->tot_len);
	strncpy(buf_rx, (char *)es->p->payload, sizeof(buf_rx));

	HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_7);

	//memset(buf_tx, '\0', SIZE_BUFFER);

	if (buf_rx[0] == '1') {
		snprintf(buf_tx, sizeof(buf_tx), "The buf_rx: %s\n", buf_rx);
		button_state = 1;
	}
	else
	{
		snprintf(buf_tx, sizeof(buf_tx), "AAAAAA\n");
		button_state = 0;
	}

	// allocate pbuf
	es->p = pbuf_alloc(PBUF_TRANSPORT, sizeof(buf_tx), PBUF_POOL);
	if (es->p != NULL) {
		// Copy data to pbuf
		pbuf_take(es->p, (char*)buf_tx, sizeof(buf_tx));
		tcp_server_send(tpcb, es);
		pbuf_free(es->p);
	} else {
		// Handle pbuf allocation error
		printf("pbuf_alloc failed\n");
	}
}

 

 

Thank you for your help

    This topic has been closed for replies.
    Best answer by STea

    Hello @Dreamer3D ,

    could you please refer to the implementation of the Projects/STM324x9I_EVAL/Applications/LwIP/LwIP_TCP_Echo_Server which can be found from Gtihub .

    as this is the proper way to implement a LWIP server on STM32 also you can refer to  AN3966 UM1713 for more details. 
    Regards

    1 reply

    STeaAnswer
    ST Employee
    October 23, 2024

    Hello @Dreamer3D ,

    could you please refer to the implementation of the Projects/STM324x9I_EVAL/Applications/LwIP/LwIP_TCP_Echo_Server which can be found from Gtihub .

    as this is the proper way to implement a LWIP server on STM32 also you can refer to  AN3966 UM1713 for more details. 
    Regards

    ST Employee
    December 30, 2024

    Hello @Dreamer3D ,

    did you try the provided example?
    Regards