|
 UltimaSerial
Windaq Add-ons
UltimaWaterfall
XChart
FFT1024

Lessons |
|
lwIP
(lightweightIP) is a popular free
TCP/IP stack for many embedded processors. The
following workshop builds a TCP echo server based on
lwIP. It is like the "Hello World"
program in any programming language.
Here we
pick a real piece of hardware from Atmel: EVK1100. Its processor is 32UC3A0512, but the codes
below should work in other hardware.
Software Development Platform: AVR32 with
lwIP and FreeRTOS.
To write a TCP echo server on EVK1100, using
lwIP on FreeRTOS, under AVR32
AVR32->File->New->Example,
select EVK1100-SERVICES-LWIP example
Give a Project Name: MyTestFromLwIP,
then click Finish. This will create a new project under the Project
Explorer pane.
Open
MyTestFromLwIP->src->CONFIG->conf-eth.h, and change
ETHERNET_CONF_IPADDR0..3 to whatever IP address you wish to use. For
example, 192.168.0.223.
If you wish
to change the MAC also, it is just a few
lines up
Instead of create a new thread, which
will require better understanding of FreeRTOS, we will modify an
existing thread to TCP echo server.
Open
MyTestFromLwIP->src->NETWORK->BasicTFTP->
BasicTFTP.c
All roads lead to Rome:
There are
several approaches to get the job done
- Raw API
programming
- As the naming
suggested, this is the lowest level of programming where the other two
based
upon.
- Reference about raw API can be found
under
MyTestFromLwIP->src->SOFTWARE_FRAMWORK->lwip-1.3.0->doc->rawapi.txt
- Replace portTASK_FUNCTION( vBasicTFTPServer, pvParameters )
with this:
char mydata[1024];
static void
close_conn(struct tcp_pcb
*pcb){ tcp_arg(pcb,
NULL); tcp_sent(pcb,
NULL); tcp_recv(pcb,
NULL);
tcp_close(pcb); }
static err_t echo_recv(void *arg,
struct
tcp_pcb *pcb, struct pbuf *p, err_t
err){ int
i; int
len; char *pc;
if
(err == ERR_OK && p != NULL)
{ /* Inform TCP that we have taken the data.
*/
tcp_recved(pcb, p->tot_len);
//pointer to the pay
load
pc=(char *)p->payload;
//size of the pay
load
len =p->tot_len;
//copy to our own
buffer
for (i=0; i<len;
i++)mydata[i]=
pc[i];
//Close TCP when receiving "X"
if
(mydata[0]=='X')close_conn(pcb);
//Free the packet buffer
pbuf_free(p);
//check output buffer capacity
if (len
>tcp_sndbuf(pcb)) len=
tcp_sndbuf(pcb);
//Send out the data
err =
tcp_write(pcb, mydata, len,
0);
tcp_sent(pcb, NULL); /* No need to call
back */ } else
{
pbuf_free(p); }
if
(err == ERR_OK && p == NULL)
{
close_conn(pcb);
} return
ERR_OK; }
static err_t echo_accept(void *arg,
struct
tcp_pcb *pcb, err_t err){
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(err);
tcp_setprio(pcb, TCP_PRIO_MIN);
tcp_recv(pcb, echo_recv);
tcp_err(pcb, NULL); //Don't care
about error here tcp_poll(pcb, NULL, 4);
//No polling
here return
ERR_OK; }
portTASK_FUNCTION( vBasicTFTPServer,
pvParameters ){ struct
tcp_pcb *ptel_pcb; ptel_pcb =
tcp_new(); tcp_bind(ptel_pcb,
IP_ADDR_ANY, 23);
while
(1){
ptel_pcb =
tcp_listen(ptel_pcb);
tcp_accept(ptel_pcb, echo_accept);
} }
- Network
connection programming
- netconn is a layer on top of the
raw APIs
- Reference for these functions can be found
in "
Design and Implemention of the lwIP
TCP/IP Stack" by Adam Dunkels
- Replace portTASK_FUNCTION( vBasicTFTPServer, pvParameters ) with
this:
static void
EchoRequest( struct netconn *pxNetCon
) {
struct netbuf *pxRxBuffer;
portCHAR *pcRxString;
unsigned portSHORT
usLength;
pxRxBuffer = netconn_recv( pxNetCon );< /FONT
>
if
( pxRxBuffer != NULL ){
netbuf_data( pxRxBuffer, ( void
* )
&pcRxString, &usLength ); if
( pcRxString != NULL){
netconn_write( pxNetCon, pcRxString, (u16_t) usLength, NETCONN_COPY
);
}
netbuf_delete( pxRxBuffer
);
} }
portTASK_FUNCTION(
vBasicTFTPServer, pvParameters ){
struct netconn
*pxTCPListener,
*pxNewConnection;
pxTCPListener =
netconn_new( NETCONN_TCP
);
netconn_bind(pxTCPListener, NULL, 23
);
netconn_listen( pxTCPListener );
for( ;; ){
pxNewConnection =
netconn_accept(pxTCPListener);
if(pxNewConnection != NULL){
EchoRequest(pxNewConnection);
}
} }
- Socket
programming:
- BSD socket layer
is built on top of the netconn layer.
- Replace portTASK_FUNCTION( vBasicTFTPServer, pvParameters ) with
this
:
portTASK_FUNCTION( vBasicTFTPServer, pvParameters
){ int lSocket; struct sockaddr_in
sLocalAddr;
lSocket = lwip_socket(AF_INET, SOCK_STREAM,
0); if (lSocket < 0) return;
memset((char *)&sLocalAddr, 0,
sizeof(sLocalAddr)); sLocalAddr.sin_family =
AF_INET; sLocalAddr.sin_len =
sizeof(sLocalAddr); sLocalAddr.sin_addr.s_addr =
htonl(INADDR_ANY); sLocalAddr.sin_port = 23;
if (lwip_bind(lSocket,
(struct
sockaddr *)&sLocalAddr, sizeof(sLocalAddr)) < 0)
{
lwip_close(lSocket);
return; }
if ( lwip_listen(lSocket, 20) !=
0 ){
lwip_close(lSocket);
return; }
while (1) {
int clientfd;
struct sockaddr_in
client_addr;
int addrlen=sizeof(client_addr);
char buffer[1024];
int
nbytes;
clientfd =
lwip_accept(lSocket, (struct sockaddr*)&client_addr,
(socklen_t)&addrlen);
if (clientfd>0){
do{
nbytes=lwip_recv(clientfd, buffer,
sizeof(buffer),0);
if
(nbytes>0) lwip_send(clientfd, buffer, nbytes,
0);
} while (nbytes>0);
lwip_close(clientfd);
} }
lwip_close(lSocket); }
- Pick
one of the approaches above, build
and run it, then you can telnet it from a PC, uisng "telnet
192.168.0.223", and it will echo any letter you
type
Click here for more lwIP examples
Find out how to upgrade to the latest lwIP
Last update: 04/08/10 |