Updated 9 Sep 2013
I received an email from Endres Puschner pointing out a bug in my web
browser sample project.  The bug causes incorrect data exchanges
if you try to use multiple sockets.  The bug (both Tx and Rx)
happens because the code for calculating the pointers into the device's
buffers does not adjust for the socket used.
Endres sent along a couple of patches for fixing the problem, which I'm
including here.  
Note that I
have NOT made these changes to the code in the .zip file below!
This isn't because I don't trust Endres' work, but because I simply
don't have the time to track down the hardware, edit the code, and
validate the changes.  But I also don't want you to struggle with
this bug if you want to use the sample project with multiple sockets.
So here are the changes proposed by Endres:
In 
the function Send() in
w5100_webserv.c, change this line of code:
   
    realaddr = W5100_TXBUFADDR + (offaddr &
W5100_TX_BUF_MASK);        // calc W5100
physical buffer addr for this socket
to be this (changes in bold):
   
    realaddr =
(W5100_TXBUFADDR + (0x0800 * sock)) + (offaddr &
W5100_TX_BUF_MASK);        // calc
W5100 physical buffer addr for this socket
Similarly, in the function Receive() in w5100_webserv.c, change this
line of code:
   
    realaddr = W5100_RXBUFADDR + (offaddr &
W5100_RX_BUF_MASK);
to be this
   
    realaddr = (W5100_RXBUFADDR
+ (0x0800 * sock)) + (offaddr
& W5100_RX_BUF_MASK);
(Now that I look over my code, I see that I could have done a much
better job with these two loops.  Hopefully the compiler will
optimize this.  Next time I get some free time, I'll revisit these
routines...)
Thanks to Endres for finding this and taking the time to write back
with a solution.
I started playing with the W5100 chip a few months ago and like it a
lot.  I built a test platform using an ATmega644p and connected
the W5100 (on a WIZ811MJ development board) via SPI.
To start out, I loaded code from the 
ermicroblog website. 
The
code here was developed by RWB and made a terrific starting
point.  I especially like the fact that RWB provides a complete
example, with every line of code provided; no header files that might
go missing and no background support code.
I reworked RWB's code to create a library for the W5100 device. 
Note that this library is target-independent.  This means you can
link any ATmega project against the library module without having to
rebuild the library because your hardware doesn't match my
original.  This independence is done with a routine called
W51_register(), which allows your program to pass a set of function
pointers to the library for handling target-specific tasks, such as
enabling/disabling the W5100 chip and exchanging data with the device.
The W5100 library code
Below is the code for the W5100 library module.  Unlike RWB's
code, my code uses a header file (derived from RWB's code and from the
Wiznet data sheet); you can find the header file in the .zip file at
the end of this page.
/*
 *  w5100.c      library of
target-independent AVR support routines
 *              
for
the Wiznet W5100 Ethernet interface device
 *
 *  This file is derived from the excellent work found here:
 *  www.ermicro.com/blog/?p=1773
 *  by RWB.  I am leaving the header from the original
file intact below,
 *  but you need to remember the rest of the source here is
fairly
 *  heavily modified.  Go to the above site for the
original.
 */
/*****************************************************************************
//  File Name    : wiznetping.c
//  Version      : 1.0
//  Description  : Wiznet W5100
//  Author       : RWB
//  Target       : AVRJazz Mega168
Board
//  Compiler     : AVR-GCC 4.3.2; avr-libc
1.6.6 (WinAVR 20090313)
//  IDE          :
Atmel AVR Studio 4.17
//  Programmer   : AVRJazz Mega168 STK500 v2.0 Bootloader
//              
:
AVR Visual Studio 4.17, STK500 programmer
//  Last Updated : 01 July 2010
*****************************************************************************/
/*
 *  The following code turns the above wiznetping.c source
code into a
 *  generic library of W5100 support routines that are
target-independent.
 *  That is, you build this library for a generic AVR ATmega
device, then
 *  write your application to use the W51_xxx routines below
for accessing
 *  the W5100 chip.  Because these routines are
target-independent, you
 *  never have to rebuild them just because you are moving
your code from,
 *  say, a 'mega128 to an 'xmega128a1 device.
 *
 *  For this to work properly, your application must provide
three target-
 *  specific functions and must register the addresses of
those functions
 *  with the W5100 library at run-time.  These functions
are:
 *
 *  select       
target-specific function for enabling the W5100 chip
 *  xchg        target-specific
function for exchanging a byte with the W5100 chip
 *  deselect    target-specific function for
disabling the W5100 chip
 *  reset       
target-specific function for hardware reset of the W5100 chip
 *
 *  Your application registers these three functions with the
W5100 library
 *  by invoking the W51_register() function.  Your
application must make this
 *  call one time and must make this call before calling any
other W5100
 *  functions.
 */
#include <util/delay.h>
#include "w5100.h"
#ifndef  FALSE
#define  FALSE        0
#define  TRUE        !FALSE
#endif
/*
 *  Define the function pointers used to access the SPI port
assigned to the
 *  W5100 device.  These pointers will be filled in at
run-time when the host
 *  calls W51_register().
 */
static  void       
           
(*select)(void) = (void *)0;
static  unsigned char       
    (*xchg)(unsigned char  val) = (void *)0;
static  void       
           
(*deselect)(void) = (void *)0;
static  void       
            (*reset)(void)
= (void *)0;
static  unsigned char       
    inited = FALSE;
void  W51_register(W5100_CALLBACKS  *pcallbacks)
{
    select = pcallbacks->_select;
    xchg = pcallbacks->_xchg;
    deselect = pcallbacks->_deselect;
    reset = pcallbacks->_reset;
    inited = FALSE;
    if ((select) && (xchg) &&
(deselect))  inited = TRUE;    // these functions
must be valid
}
void  W51_write(unsigned int  addr, unsigned char  data)
{
    if (!inited)  return;   
           
        // not set up, ignore request
    select();       
           
           
    // enable the W5100 chip
    xchg(W5100_WRITE_OPCODE);   
           
    // need to write a byte
    xchg((addr & 0xff00) >>
8);           
    // send MSB of addr
    xchg(addr & 0xff);   
           
            // send LSB
    xchg(data);       
           
           
    // send the data
    deselect();       
           
           
    // done with the chip
}
unsigned char  W51_read(unsigned int  addr)
{
    unsigned char       
        val;
    if (!inited)  return  0;   
           
    // not set up, ignore request
    select();       
           
           
    // enable the W5100 chip
    xchg(W5100_READ_OPCODE);   
           
    // need to read a byte
    xchg((addr & 0xff00) >>
8);           
    // send MSB of addr
    xchg(addr & 0xff);   
           
            // send LSB
    val = xchg(0x00);   
           
            // need to
send a dummy char to get response
    deselect();       
           
           
    // done with the chip
    return  val;   
           
           
    // tell her what she's won
}
void  W51_init(void)
{
    if (reset)  reset();   
           
        // if host provided a reset
function, use it
    else       
W51_write(W5100_MR, W5100_MR_SOFTRST);    
    // otherwise, force the w5100 to soft-reset
    _delay_ms(1);
}
unsigned char  W51_config(W5100_CFG  *pcfg)
{
    if (pcfg == 0)  return  W5100_FAIL;
    W51_write(W5100_GAR + 0,
pcfg->gtw_addr[0]);    // set up the gateway address
    W51_write(W5100_GAR + 1, pcfg->gtw_addr[1]);
    W51_write(W5100_GAR + 2, pcfg->gtw_addr[2]);
    W51_write(W5100_GAR + 3, pcfg->gtw_addr[3]);
    _delay_ms(1);
    W51_write(W5100_SHAR + 0,
pcfg->mac_addr[0]);    // set up the MAC address
    W51_write(W5100_SHAR + 1, pcfg->mac_addr[1]);
    W51_write(W5100_SHAR + 2, pcfg->mac_addr[2]);
    W51_write(W5100_SHAR + 3, pcfg->mac_addr[3]);
    W51_write(W5100_SHAR + 4, pcfg->mac_addr[4]);
    W51_write(W5100_SHAR + 5, pcfg->mac_addr[5]);
    _delay_ms(1);
    W51_write(W5100_SUBR + 0,
pcfg->sub_mask[0]);    // set up the subnet mask
    W51_write(W5100_SUBR + 1, pcfg->sub_mask[1]);
    W51_write(W5100_SUBR + 2, pcfg->sub_mask[2]);
    W51_write(W5100_SUBR + 3, pcfg->sub_mask[3]);
    _delay_ms(1);
    W51_write(W5100_SIPR + 0,
pcfg->ip_addr[0]);    // set up the source IP address
    W51_write(W5100_SIPR + 1, pcfg->ip_addr[1]);
    W51_write(W5100_SIPR + 2, pcfg->ip_addr[2]);
    W51_write(W5100_SIPR + 3, pcfg->ip_addr[3]);
    _delay_ms(1);
    W51_write(W5100_RMSR, 0x55);   
           
    // use default buffer sizes (2K bytes RX and TX for
each socket
    W51_write(W5100_TMSR, 0x55);
    return  W5100_OK;   
           
           
    // everything worked, show success
}
Using the library
To use this library, create a new AVRStudio4 project and add the
w5100.h header file to your project (remember to change your project's
configuration to include the path to the folder holding the w5100.h
file).  Also change your project's configuration to add the w5100
library, so the linker can find the library when you build your project.
In your source, you will need to write three (optionally, four)
target-specific routines.  The three required routines provide SPI
access to your board's W5100 chip via SPI.  The select() routine
sets the correct port line to select the W5100 device.  The
deselect() routine changes the port line to deselect the W5100
device.  The xchg() routine sends a byte of data to the W5100 via
SPI and simultaneously receives a byte, returning that byte to the
calling routine.  Optionally, you may also provide a reset()
routine that uses a port line to perform a hardware reset of the W5100
device.  I strongly urge you to provide such a feature in your
hardware, as I have had issues with the W5100 starting up properly if I
don't do a hardware reset.
A sample project (web server)
The code below is a sample web server built with the library above.
#include <avr/io.h>
#include <string.h>
#include <stdio.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include "w5100.h"
unsigned char   
        OpenSocket(unsigned char 
sock, unsigned char  eth_protocol, unsigned int  tcp_port);
void   
           
    CloseSocket(unsigned char  sock);
void   
           
    DisconnectSocket(unsigned char  sock);
unsigned char   
        Listen(unsigned char  sock);
unsigned char   
        Send(unsigned char  sock,
const unsigned char  *buf, unsigned int  buflen);
unsigned int   
        Receive(unsigned char  sock,
unsigned char  *buf, unsigned int  buflen);
unsigned int   
        ReceivedSize(unsigned char 
sock);
void   
           
    my_select(void);
void   
           
    my_deselect(void);
unsigned char   
        my_xchg(unsigned char  val);
void   
           
    my_reset(void);
#define 
MAX_BUF           
        512   
        /* largest buffer we can read
from chip */
#define 
HTTP_PORT           
        80   
        /* TCP port for HTTP */
/*
 *  Ethernet setup
 *
 *  Define the MAC
address, IP address, subnet mask, and gateway
 *  address for the
target device.
 */
W5100_CFG   
           
    my_cfg =
{
   
{0x00,0x16,0x36,0xDE,0x58,0xF6},       
    // mac_addr
   
{192,168,1,233},       
           
        // ip_addr
   
{255,255,255,0},       
           
        // sub_mask
   
{192,168,1,1}           
           
        // gtw_addr
};
/*
 *  Callback function
block
 *
 *  Define callback
functions for target-independent support of the
 *  W5100 chip. 
Here is where you store pointers to the various
 *  functions needed by
the W5100 library code.  These functions all
 *  handle tasks that
are target-dependent, which means the library
 *  code can be
target-INdependent.
 */
W5100_CALLBACKS   
            my_callbacks;
unsigned char   
           
        buf[MAX_BUF];
unsigned char 
OpenSocket(unsigned char  sock, unsigned char  eth_protocol,
unsigned int  tcp_port)
{
    unsigned
char            retval;
    unsigned
int            sockaddr;
    
    retval =
W5100_FAIL;           
           
    // assume this doesn't work
    if (sock >=
W5100_NUM_SOCKETS)  return retval;    // illegal
socket value is bad!
    sockaddr
=  W5100_SKT_BASE(sock);       
        // calc base addr for this socket
    if
(W51_read(sockaddr+W5100_SR_OFFSET) ==
W5100_SKT_SR_CLOSED)    // Make sure we close the socket
first
    {
   
    CloseSocket(sock);
    }
   
W51_write(sockaddr+W5100_MR_OFFSET ,eth_protocol);   
    // set protocol for this socket
   
W51_write(sockaddr+W5100_PORT_OFFSET, ((tcp_port & 0xFF00) >>
8 ));        // set port for this socket
(MSB)
   
W51_write(sockaddr+W5100_PORT_OFFSET + 1, (tcp_port &
0x00FF));            //
set port for this socket (LSB)
   
W51_write(sockaddr+W5100_CR_OFFSET,
W5100_SKT_CR_OPEN);   
              
   
// open the socket
    while
(W51_read(sockaddr+W5100_CR_OFFSET))  ;   
        // loop until device reports
socket is open (blocks!!)
    if
(W51_read(sockaddr+W5100_SR_OFFSET) == W5100_SKT_SR_INIT)  retval
= sock;    // if success, return socket number
    else 
CloseSocket(sock);       
           
            // if failed,
close socket immediately
    return 
retval;
}
void  CloseSocket(unsigned
char  sock)
{
    unsigned
int            sockaddr;
    
    if (sock >
W5100_NUM_SOCKETS)  return;       
    // if illegal socket number, ignore request
    sockaddr =
W5100_SKT_BASE(sock);       
        // calc base addr for this socket
   
W51_write(sockaddr+W5100_CR_OFFSET,
W5100_SKT_CR_CLOSE);    // tell chip to close the socket
    while
(W51_read(sockaddr+W5100_CR_OFFSET))  ;    // loop
until socket is closed (blocks!!)
}
void 
DisconnectSocket(unsigned char  sock)
{
    unsigned
int            sockaddr;
    
    if (sock >
W5100_NUM_SOCKETS)  return;       
    // if illegal socket number, ignore request
    sockaddr =
W5100_SKT_BASE(sock);       
        // calc base addr for this socket
   
W51_write(sockaddr+W5100_CR_OFFSET,
W5100_SKT_CR_DISCON);        //
disconnect the socket
    while
(W51_read(sockaddr+W5100_CR_OFFSET))  ;    // loop
until socket is closed (blocks!!)
}
unsigned char 
Listen(unsigned char  sock)
{
    unsigned
char            retval;
    unsigned
int            sockaddr;
    retval =
W5100_FAIL;           
           
    // assume this fails    
    if (sock >
W5100_NUM_SOCKETS)  return  retval;    // if
illegal socket number, ignore request
    sockaddr =
W5100_SKT_BASE(sock);       
        // calc base addr for this socket
    if
(W51_read(sockaddr+W5100_SR_OFFSET) ==
W5100_SKT_SR_INIT)    // if socket is in initialized
state...
    {
   
    W51_write(sockaddr+W5100_CR_OFFSET,
W5100_SKT_CR_LISTEN);        // put
socket in listen state
   
    while (W51_read(sockaddr+W5100_CR_OFFSET)) 
;        // block until command is
accepted
   
    if (W51_read(sockaddr+W5100_SR_OFFSET) ==
W5100_SKT_SR_LISTEN)  retval = W5100_OK;    // if
socket state changed, show success
   
    else  CloseSocket(sock);   
           
    // not in listen mode, close and show an error
occurred
    }
    return 
retval;
}
unsigned char  Send(unsigned
char  sock, const unsigned char  *buf, unsigned int 
buflen)
{
    unsigned
int           
        ptr;
    unsigned
int           
        offaddr;
    unsigned
int           
        realaddr;
    unsigned
int           
        txsize;
    unsigned
int           
        timeout;   
    unsigned
int           
        sockaddr;
    if (buflen ==
0 || sock >= W5100_NUM_SOCKETS)  return 
W5100_FAIL;        // ignore illegal
requests
    sockaddr =
W5100_SKT_BASE(sock);       
    // calc base addr for this socket
    // Make sure
the TX Free Size Register is available
    txsize =
W51_read(sockaddr+W5100_TX_FSR_OFFSET);   
    // make sure the TX free-size reg is available
    txsize =
(((txsize & 0x00FF) << 8 ) +
W51_read(sockaddr+W5100_TX_FSR_OFFSET + 1));
    timeout = 0;
    while (txsize
< buflen)
    {
   
    _delay_ms(1);
   
    txsize =
W51_read(sockaddr+W5100_TX_FSR_OFFSET);   
    // make sure the TX free-size reg is available
   
    txsize = (((txsize & 0x00FF) << 8 ) +
W51_read(sockaddr+W5100_TX_FSR_OFFSET + 1));
   
    if (timeout++ > 1000)    
           
        // if max delay has passed...
   
    {
   
       
DisconnectSocket(sock);       
            // can't
connect, close it down
   
        return 
W5100_FAIL;           
            // show failure
   
    }
   
}    
   // Read the Tx Write
Pointer
    ptr =
W51_read(sockaddr+W5100_TX_WR_OFFSET);
    offaddr =
(((ptr & 0x00FF) << 8 ) +
W51_read(sockaddr+W5100_TX_WR_OFFSET + 1));
    while (buflen)
    {
   
    buflen--;
   
    realaddr = W5100_TXBUFADDR + (offaddr &
W5100_TX_BUF_MASK);        // calc W5100
physical buffer addr for this socket
   
    W51_write(realaddr, *buf);   
           
    // send a byte of application data to TX buffer
   
    offaddr++;       
           
           
    // next TX buffer addr
   
    buf++;       
           
           
        // next input buffer addr
    }
   
W51_write(sockaddr+W5100_TX_WR_OFFSET, (offaddr & 0xFF00) >>
8);    // send MSB of new write-pointer addr
   
W51_write(sockaddr+W5100_TX_WR_OFFSET + 1, (offaddr &
0x00FF));        // send
LSB    
   
W51_write(sockaddr+W5100_CR_OFFSET,
W5100_SKT_CR_SEND);    // start the send on its way
    while
(W51_read(sockaddr+W5100_CR_OFFSET))  ;    // loop
until socket starts the send (blocks!!)
    return 
W5100_OK;
}
/*
 *  Define the SPI
port, used to exchange data with a W5100 chip.
 */
#define SPI_PORT
    PORTB       
        /* target-specific port
containing the SPI lines */
#define SPI_DDR 
    DDRB       
        /* target-specific DDR for the
SPI port lines */
#define CS_DDR   
    DDRD       
        /* target-specific DDR for
chip-select */
#define CS_PORT
    PORTD       
        /* target-specific port used as
chip-select */
#define CS_BIT   
    2       
            /*
target-specific port line used as chip-select */
#define RESET_DDR  
DDRD           
    /* target-specific DDR for reset */
#define
RESET_PORT    PORTD       
        /* target-specific port used for
reset */
#define
RESET_BIT    3       
            /*
target-specific port line used as reset */
/*
 *  Define macros for
selecting and deselecting the W5100 device.
 */
#define 
W51_ENABLE       
CS_PORT&=~(1<<CS_BIT)
#define 
W51_DISABLE    CS_PORT|=(1<<CS_BIT)
unsigned int 
Receive(unsigned char  sock, unsigned char  *buf, unsigned
int  buflen)
{
    unsigned
int           
        ptr;
    unsigned
int           
        offaddr;
    unsigned
int           
        realaddr;  
    
    unsigned
int           
        sockaddr;
    if (buflen ==
0 || sock >= W5100_NUM_SOCKETS)  return 
W5100_FAIL;        // ignore illegal
conditions
    if (buflen
> (MAX_BUF-2))  buflen = MAX_BUF - 2;   
    // requests that exceed the max are truncated
    sockaddr =
W5100_SKT_BASE(sock);       
           
    // calc base addr for this socket
    ptr =
W51_read(sockaddr+W5100_RX_RD_OFFSET);   
        // get the RX read pointer (MSB)
    offaddr =
(((ptr & 0x00FF) << 8 ) +
W51_read(sockaddr+W5100_RX_RD_OFFSET + 1));   
    // get LSB and calc offset addr
    while (buflen)
    {
   
    buflen--;
   
    realaddr = W5100_RXBUFADDR + (offaddr &
W5100_RX_BUF_MASK);
   
    *buf = W51_read(realaddr);
   
    offaddr++;
   
    buf++;
    }
    *buf='\0';
           
           
           
            // buffer read
is complete, terminate the string
    // Increase
the S0_RX_RD value, so it point to the next receive
   
W51_write(sockaddr+W5100_RX_RD_OFFSET, (offaddr & 0xFF00) >>
8);    // update RX read offset (MSB)
   
W51_write(sockaddr+W5100_RX_RD_OFFSET + 1,(offaddr &
0x00FF));        // update LSB
    // Now Send
the RECV command
   
W51_write(sockaddr+W5100_CR_OFFSET,
W5100_SKT_CR_RECV);       
    // issue the receive command
   
_delay_us(5);           
           
           
        // wait for receive to start
    return 
W5100_OK;
}
unsigned int 
ReceivedSize(unsigned char  sock)
{
    unsigned
int           
        val;
    unsigned
int           
        sockaddr;
    if (sock >=
W5100_NUM_SOCKETS)  return  0;
    sockaddr =
W5100_SKT_BASE(sock);       
           
    // calc base addr for this socket
    val =
W51_read(sockaddr+W5100_RX_RSR_OFFSET) & 0xff;
    val = (val
<< 8) + W51_read(sockaddr+W5100_RX_RSR_OFFSET + 1);
    return 
val;
}
/*
 *  Simple wrapper
function for selecting the W5100 device.  This function
 *  allows the library
code to invoke a target-specific function for enabling
 *  the W5100 chip.
 */
void  my_select(void)
{
    W51_ENABLE;
}
/*
 *  Simple wrapper
function for deselecting the W5100 device.  This function
 *  allows the library
code to invoke a target-specific function for disabling
 *  the W5100 chip.
 */
void  my_deselect(void)
{
    W51_DISABLE;
}
/*
 * 
my_xchg      callback function; exchanges a
byte with W5100 chip
 */
unsigned char 
my_xchg(unsigned char  val)
{
    SPDR = val;
    while 
(!(SPSR & (1<<SPIF)))  ;
    return 
SPDR;
}
/*
 * 
my_reset      callback function; force a
hardware reset of the W5100 device
 */
void  my_reset(void)
{
    RESET_PORT |=
(1<<RESET_BIT);       
           
        // pull reset line high
    RESET_DDR |=
(1<<RESET_BIT);       
           
        // now make it an output
    RESET_PORT
&= ~(1<<RESET_BIT);       
           
        // pull the line low
   
_delay_ms(5);           
           
           
        // let the device reset
    RESET_PORT |=
(1<<RESET_BIT);       
           
        // done with reset, pull the line
high
   
_delay_ms(10);           
           
           
        // let the chip wake up
}
int  main(void)
{
    unsigned
int           
        sockaddr;
    unsigned
char           
        mysocket;
    unsigned
int           
        rsize;
    mysocket =
0;           
           
           
        // magic number! declare the
socket number we will use (0-3)
    sockaddr =
W5100_SKT_BASE(mysocket);       
            // calc
address of W5100 register set for this socket
/*
 *  Initialize the
ATmega644p SPI subsystem
 */
    CS_PORT |=
(1<<CS_BIT);       
           
           
    // pull CS pin high
    CS_DDR |=
(1<<CS_BIT);       
           
           
    // now make it an output
    SPI_PORT =
SPI_PORT | (1<<PORTB4);       
           
    // make sure SS is high
    SPI_DDR =
(1<<PORTB4)|(1<<PORTB5)|(1<<PORTB7);   
   
    // set MOSI, SCK and SS as
output, others as input
    SPCR =
(1<<SPE)|(1<<MSTR);       
           
            // enable SPI,
master mode 0
    SPSR |=
(1<<SPI2X);       
           
           
        // set the clock rate fck/2
/*
 *  Load up the
callback block, then initialize the Wiznet W5100
 */
   
my_callbacks._select = &my_select;   
           
        // callback for selecting the
W5100
   
my_callbacks._xchg = &my_xchg;       
           
        // callback for exchanging data
   
my_callbacks._deselect = &my_deselect;   
           
    // callback for deselecting the W5100
   
my_callbacks._reset = &my_reset;   
           
        // callback for hardware-reset of
the W5100
   
W51_register(&my_callbacks);       
           
        // register our target-specific
W5100 routines with the W5100 library
   
W51_init();           
           
           
            // now
initialize the W5100
/*
 *  Configure the W5100
device to handle PING requests.
 *  This requires
configuring the chip, not a specific socket.
 */
    
W51_config(&my_cfg);       
           
           
    // config the W5100 (MAC, TCP address, subnet, etc
/*
 *  The main
loop.  Control stays in this loop forever, processing any received
packets
 *  and sending any
requested data.
 */
    while  (1)
    {
   
    switch 
(W51_read(sockaddr+W5100_SR_OFFSET))   
    // based on current status of socket...
   
    {
   
        case 
W5100_SKT_SR_CLOSED:       
           
    // if socket is closed...
   
        if (OpenSocket(mysocket,
W5100_SKT_MR_TCP, HTTP_PORT) == mysocket)   
    // if successful opening a socket...
   
        {
   
           
Listen(mysocket);
   
            _delay_ms(1);
   
        }
   
        break;
   
        case 
W5100_SKT_SR_ESTABLISHED:       
            // if socket
connection is established...
   
        rsize =
ReceivedSize(mysocket);       
            // find out
how many bytes
   
        if (rsize > 0)
   
        {
   
            if
(Receive(mysocket, buf, rsize) != W5100_OK) 
break;    // if we had problems, all done
/*
 *  Add code here to
process the payload from the packet.
 *
 *  For now, we just
ignore the payload and send a canned HTML page so the client at least
 *  knows we are alive.
 */
   
            strcpy_P((char
*)buf, PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nPragma:
no-cache\r\n\r\n"));
   
            strcat_P((char
*)buf, PSTR("<html>\r\n<body>\r\n"));
   
            strcat_P((char
*)buf, PSTR("<title>Karl's W5100 web server
(ATmega644p)</title>\r\n"));
   
            strcat_P((char
*)buf, PSTR("<h2>Karl's ATmega644p web server using Wiznet W5100
chip</h2>\r\n"));
   
            strcat_P((char
*)buf, PSTR("<br /><hr>\r\n"));
   
            if
(Send(mysocket, buf, strlen((char *)buf)) == W5100_FAIL) 
break;        // just throw out the
packet for now
   
            strcpy_P((char
*)buf, PSTR("This is part 2 of the page."));
   
            strcat_P((char
*)buf, PSTR("</body>\r\n</html>\r\n"));
   
            if
(Send(mysocket, buf, strlen((char *)buf)) == W5100_FAIL) 
break;        // just throw out the
packet for now
   
           
DisconnectSocket(mysocket);
   
        }
   
        else   
           
           
           
    // no data yet...
   
        {
   
            _delay_us(10);
   
        }
   
        break;
   
        case  W5100_SKT_SR_FIN_WAIT:
   
        case  W5100_SKT_SR_CLOSING:
   
        case  W5100_SKT_SR_TIME_WAIT:
   
        case 
W5100_SKT_SR_CLOSE_WAIT:
   
        case  W5100_SKT_SR_LAST_ACK:
   
        CloseSocket(mysocket);
   
        break;
   
    }
    }
    return  0;
}
About the web server
The code above was modified from RWB's
original and is much more limited.  Basically, the above code
doesn't even try to parse the HTTP packet received; it just throws out
the same fixed file.  This is good enough to confirm the server is
working, but hardly makes a finished project.  Look over RWB's
code and check out similar projects on the web for details on how to
parse the packets and create your own web server.  Note also that
I've removed all of the USART routines from RWB's original.
I have also modified RWB's code so you can use any of the four W5100
sockets.  The code has been tested using socket 0, but has not
been tested using other sockets or using multiple sockets
simultaneously.
The above code, plus the library code that gets linked in, yields a
final image of 2.4 KB.  Yes, that is an ATmega644p web server in
under 2500 bytes of code!
To modify this code for your own use, you will need to recode the four
callback functions (just above main()) for your particular
hardware.  You will also need to modify the entries in the
W5100_CFG structure to match your network; see the declaration of
my_cfg above.  Finally, rebuild and link against the w5100 library
module and you should be good to go.
Here is the .zip file containing the
above code plus the w5100.h header file and a custom Makefile for
creating the w5100 library module.  To use the Makefile, create an
AVRStudio4 project for the w5100 library, add the w5100.c file ahd
w5100.h header file, then invoke the Makefile from the Windows command
prompt as: make -f Makefile_library.mak
 
Home