lwip-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lwip-users] Minimal RAW TCP Client


From: Jamie
Subject: [lwip-users] Minimal RAW TCP Client
Date: Wed, 13 Nov 2019 15:19:10 -0700 (MST)

G'day,

I'm looking to build a minimal RAW TCP client on a SAME70 (ATSAME70Q21) MCU.
Thankfully there is already a port for lwIP on the SAME70, which allows for
the basic TCP Echo to be run on the SAME70 Xplained evaluation board (which
I have done with no problem).

The problem I'm having at the moment is in modifying the TCP Echo example
code in the following ways:

1. The lwIP TCP needs to be a client, connecting to an external TCP server.
The example code is based on lwIP being a TCP server, so I'm struggling a
bit with replacing/removing the server-based code.

2. Simplifying the code. At the moment I only need to read data from the TCP
client, I don't need any tcp_send() functionality. Additionally, the entire
application on the SAME70 is predicated on this TCP connection, so a
blocking while loop until the connection is established is acceptable
(again, trying to keep it as simple as possible).

Here <https://www.avrfreaks.net/forum/ethernet-socket-communication-same70>  
is a link to a forum post where I got the TCP Echo example to work on the
SAME70 evaluation board. This is the code I'm currently trying to modify.
This is what I have so far (including some minimal commentary):

#include "sam_comms.h"

#if LWIP_TCP

static struct tcp_pcb *sam_tcp_pcb;

enum sam_tcp_states
{
        ES_NONE = 0,
        ES_CONNECTED,
        ES_RECEIVED,
        ES_CLOSING
};

struct sam_tcp_state
{
        u8_t state;
        u8_t retries;
        struct tcp_pcb *pcb;
        /* pbuf (chain) to recycle */
        struct pbuf *p;
};

void sam_tcp_init(void)
{
  sam_tcp_pcb = tcp_new();
  if (sam_tcp_pcb != NULL)
  {
    err_t err;
    struct sam_tcp_state *es;

    //No error handling for the time being
    tcp_err(sam_tcp_pcb, NULL);
    tcp_recv(sam_tcp_pcb, sam_tcp_recv);

    //No polling for the time being
    tcp_poll(sam_tcp_pcb, NULL, 0);
        
    //I don't believe I need to bind?
    //err = tcp_bind(sam_tcp_pcb, IP_ADDR_ANY, 9999);

    //I'm thinking that somewhere here I should have a while or do loop, to
keep trying
    //to connect until a connection is established?
    err = tcp_connect(sam_tcp_pcb, IP_ADDR_ANY, 9999, sam_tcp_connect);
    if (err != ERR_OK)
    {
        //Connection not successful, close the pcb
        tcp_close(sam_tcp_pcb);
        }
  }
  else
  {
    /* abort? output diagnostic? */
  }
}

err_t sam_tcp_connect(void *arg, struct tcp_pcb *connectedpcb, err_t err)
{
        err_t ret_err;
        struct sam_tcp_state *es;
        
        es = (struct sam_tcp_state *)mem_malloc(sizeof(struct sam_tcp_state));
        if (es != NULL)
        {
                es->state = ES_CONNECTED;
                es->pcb = connectedpcb;
                es->retries = 0;
                es->p = NULL;
        }
        else
        {
                ret_err = ERR_MEM;
        }
        return ret_err;
}

err_t sam_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t
err)
{
  struct sam_tcp_state *es;
  err_t ret_err;

  LWIP_ASSERT("arg != NULL",arg != NULL);
  es = (struct sam_tcp_state *)arg;
  if (p == NULL)
  {
    /* remote host closed connection */
    es->state = ES_CLOSING;
    if(es->p == NULL)
    {
       /* we're done sending, close it */
       //sam_tcp_close(tpcb, es);
    }
    else
    {
      /* we're not done yet */
        //The below is commented out as this isn't an echo program
        //sam_tcp_send(tpcb, es);
    }
    ret_err = ERR_OK;
  }
  else if(err != ERR_OK)
  {
    /* cleanup, for unknown reason */
    if (p != NULL)
    {
      es->p = NULL;
      pbuf_free(p);
    }
    ret_err = err;
  }
  else if(es->state == ES_CONNECTED)
  {
    /* first data chunk in p->payload */
    es->state = ES_RECEIVED;
    /* store reference to incoming pbuf (chain) */
    es->p = p;
    /* install send completion notifier */
    //The below is commented out as this isn't an echo program
    //tcp_sent(tpcb, echo_sent);
    //sam_tcp_send(tpcb, es);
    ret_err = ERR_OK;
  }
  else if (es->state == ES_RECEIVED)
  {
    /* read some more data */
    if(es->p == NULL)
    {
      es->p = p;
      //The below is commented out as this isn't an echo program
      //tcp_sent(tpcb, echo_sent);
      //sam_tcp_send(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;
  }
  if (!strncmp(p->payload, "Quit", 4))
  {
          //sam_tcp_close(tpcb, es);
  } else
  {
          //
  }
  return ret_err;
}
#endif /* LWIP_TCP */

Am I on the right track? How would I go about adding a loop to continue
trying to connect to the TCP server? In terms of global macros, I've only
changed LWIP_SOCKET to 0 (disable the sockets API) and have left NO_SYS as
0. Is this correct? Are there any other macros I need to change for a RAW
TCP client implementation?

Any input, guidance or example code would be very much appreciated!

Thanks!



--
Sent from: http://lwip.100.n7.nabble.com/lwip-users-f3.html



reply via email to

[Prev in Thread] Current Thread [Next in Thread]