[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
- [lwip-users] Minimal RAW TCP Client,
Jamie <=