2024-09-30 07:39 AM - last edited on 2024-09-30 07:46 AM by Andrew Neil
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
2024-10-23 08:50 AM
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