Jump to content
Sign in to follow this  
spirilis

WizNet W5200 C library

Recommended Posts

This is a code library implementing a sockets-oriented interface to the WizNet W5200.  It's been a long time coming, and the plan is to implement DHCP support soon; almost there, had to rewrite the lib from scratch to allow piecemeal I/O with various socket types first.

 

For now, the code includes working examples for the MSP430G2553 and MSP430F5529 LaunchPads.  It needs a lot of documentation work though so don't fret if you can't get them working :-)

 

More to come...

 

Link: https://github.com/spirilis/w5200sock

 

After DHCP support is working on the older W5200, I am going to adapt this into a W5500 library called w5500sock.  As it stands right now though this library should be sufficient for building TCP and UDP clients and servers, managing several simultaneously along with doing repeated DNS lookups (A records only, i.e. dnslib_gethostbyname() is the only implemented client function so far).

 

Much of the API is designed to allow the MCU to write or read data piecemeal without having to allocate any large buffers of its own to manage the data.  See dnslib.c for good examples... there are flags for the various recv, send and flush calls which do "virtual" reads of the data without signalling the readiness to receive new packets, and the wiznet_send() and wiznet_sendto() calls take an argument as to whether the packet should be committed yet.  This enables low SRAM usage for e.g. the G2553.  I think the API is too fat for the G2452 though, so G2553 at a minimum.

Share this post


Link to post
Share on other sites

Ok, sitting down with http://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol and http://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml to try and bang this one out.

 

Got simple functions for reading & writing the base DHCP packet headers, working on the "option" fields, then composing it all together with an event loop.

Share this post


Link to post
Share on other sites

Ok well, the code's a bit piggish, and I found a bug in one of the foundation lib functions, but I got a successful connection!!

Init-
Send DHCPDISCOVER:
Our MAC: 54520000F801
Check for DHCPOFFER...
Found packet:
dhcp_read_option opt = 53, len = 1
Packet is DHCPOFFER
dhcp_read_option opt = 1, len = 4
dhcp_read_option opt = 58, len = 4
dhcp_read_option opt = 59, len = 4
dhcp_read_option opt = 51, len = 4
dhcp_read_option opt = 54, len = 4
DHCP server = 0A6808C9
dhcp_read_option opt = 3, len = 4
gateway = 0A687301
dhcp_read_option opt = 6, len = 8
DNS = 0A6808C9
dhcp_read_option opt = 255, len = 0
Send DHCPREQUEST:
Check for DHCPACK...
Found packet:
yiaddr_ack = 0A687329
siaddr_ack = 00000000
dhcp_read_option opt = 53, len = 1
Packet is DHCPACK
dhcp_read_option opt = 58, len = 4
dhcp_read_option opt = 59, len = 4
dhcp_read_option opt = 51, len = 4
dhcp_read_option opt = 54, len = 4
siaddr_ack = 0A6808C9
dhcp_read_option opt = 1, len = 4
dhcp_read_option opt = 255, len = 0
DHCPACK contents processed;
DNS was provided
Configuring WizNet IP settings
DHCP completed:
Main registers:
Mode: 0x00
Sys IRQ: 0x00
Sock IRQ Mask: 0x00
Retry Count: 0x08
Sock IRQ Pending: 0x00
PHY status: 0x27
Sys IRQ Mask: 0x00
Socket #0:
Mode: 0x00
IRQ: 0x00
Status: 0x00
Source port: 0x0000
Dest IP: 0x00000000
Dest port: 0x0000
MSS: 0x0000
IP TOS: 0x00
IP TTL: 0x80
TX buffer free: 0x0800
TX readptr: 0x0000
TX writeptr: 0x0000
RX recvsize: 0x0000
RX readptr: 0x0000
RX writeptr: 0x0000
IRQ Mask: 0xFF
wiznet_socket(): 6
connect(74.112.203.145):
send: GET / HTTP/1.0
Host: spirilis.net


recv loop:
line: 17 HTTP/1.1 200 OK
line: 37 Date: Wed, 26 Feb 2014 19:27:47 GMT
line: 70 Server: Apache/2.2.9 (Debian) PHP/5.3.6 mod_ssl/2.2.9 OpenSSL/0.9.8g
line: 46 Last-Modified: Mon, 11 Jan 2010 15:10:11 GMT
line: 35 ETag: "35446f1-168-47ce4ef003ac0"
line: 22 Accept-Ranges: bytes
line: 21 Content-Length: 360
line: 23 Vary: Accept-Encoding
line: 19 Connection: close
line: 25 Content-Type: text/html
line: 2
line: 7 <html>
line: 7 <head>
line: 18 <title>hi</title>
line: 7 <body>
line: 22 <h1>spirilis.net</h1>
line: 16 <p>welcome.</p>
line: 8 </body>
line: 10 <address>
line: 126 <a href="http://ubuntucounter.geekosophical.net" title="The Ubuntu Counter Project - user number # 960"><img src="http://ubuntline: 120 ucounter.geekosophical.net/img/ubuntu-user2.ph>
line: 11 </address>
line: 8 </html>
recv error: Not connected

Successful DHCP register, followed by HTTP client request.  Damned program ballooned to 14KB though.  I do have some strerror() type of functions defined, including a dnslib_strerror() and dhcp_strerror() though with their corresponding rodata descriptions.

 

This example program looks like this for the init & DHCP portion:

int main() {
        int sockfd, i;
        uint8_t netbuf[128];
        uint16_t myip[2], dns[2];

        WDTCTL = WDTPW | WDTHOLD;
        ucs_clockinit(16000000, 1, 0);
        __delay_cycles(160000);

        uartcli_begin(uartbuf, 8);
        uartcli_println_str("Init-");
        if ( (sockfd = wiznet_init()) < 0) {  // borrowing 'sockfd' for storing return value
                uartcli_print_str("FAILED: ");
                interpret_senderror(sockfd);
                LPM4;
        }
        w52_portoffset = 0;

        while (wiznet_phystate() < 0)
                __delay_cycles(160000);

        dns[0] = dns[1] = 0xFFFF;
        i = dhcp_loop_configure(1, dns);  // The DHCP step
        if (i < 0) {
                uartcli_print_str("dhcp_loop_configure error: ");
                interpret_senderror(i);
                uartcli_print_str("dhcplib errno: ");
                uartcli_println_str(dhcp_strerror(dhcplib_errno));
                LPM4;
        }

        dnslib_resolver = dns;
        uartcli_println_str("DHCP completed:");
        wiznet_debug_uart(0);
        if (dns[0] == 0xFFFF || dns[1] == 0xFFFF) {
                uartcli_println_str("DHCP completed but DNS not configured.");
                LPM4;
        }

        sockfd = wiznet_socket(IPPROTO_TCP);
        if (sockfd < 0) {
                uartcli_print_str("wiznet_socket failed: ");
                interpret_senderror(sockfd);
                LPM4;
        }
...yadda yadda...

Share this post


Link to post
Share on other sites

Ah yes, also going to clean up the uartcli crap I have in there and consolidate it into a #define'able wiznet_lib_debug() function or something.  Having a true "debug" feature that can be compiled in or left out is important when dealing with TCP/IP crap.

Share this post


Link to post
Share on other sites

Library and examples (minus G2553 examples which I haven't touched in a while) have been revamped to use a new debugging infrastructure, wiznet_debug_printf() and a 6-layer debug setting... wiznet_debug1_printf() through wiznet_debug6_printf() which become aliased to wiznet_debug_printf(), or just to ";", in response to the value of #define WIZNET_DEBUG.  So you can dial up the bloat & verbosity by setting that #define higher, or stick to the basics by setting it lower, or ignore them altogether by setting it to 0.

 

Implemented like this:

/* Debug levels:
 * 1 - Basic information from libraries
 * 2 - Verbose error reporting from libraries
 * 3 - Gratuitous information from libraries
 * 4 - Verbose detail from base socket library
 * 5 - Extraneous detail from base socket library
 * 6 - Low-level I/O dump from SPI transfer functions
 *
 * Each debug level includes information from all levels below.
 */
#define WIZNET_DEBUG 3

void wiznet_debug_init();
void wiznet_debug_printf(char *format, ...);
void wiznet_debug_dumpregs_main();
void wiznet_debug_dumpregs_sock(int);

void wiznet_debug_putc(unsigned int);
void wiznet_debug_puts(const char *);

#if WIZNET_DEBUG > 0
#define wiznet_debug1_printf(...) wiznet_debug_printf(__VA_ARGS__)
#else
#define wiznet_debug1_printf(...) ;
#endif

#if WIZNET_DEBUG > 1
#define wiznet_debug2_printf(...) wiznet_debug_printf(__VA_ARGS__)
#else
#define wiznet_debug2_printf(...) ;
#endif

#if WIZNET_DEBUG > 2
#define wiznet_debug3_printf(...) wiznet_debug_printf(__VA_ARGS__)
#else
#define wiznet_debug3_printf(...) ;
#endif

#if WIZNET_DEBUG > 3
#define wiznet_debug4_printf(...) wiznet_debug_printf(__VA_ARGS__)
#else
#define wiznet_debug4_printf(...) ;

#if WIZNET_DEBUG > 4
#define wiznet_debug5_printf(...) wiznet_debug_printf(__VA_ARGS__)
#else
#define wiznet_debug5_printf(...) ;
#endif

#if WIZNET_DEBUG > 5
#define wiznet_debug6_printf(...) wiznet_debug_printf(__VA_ARGS__)
#else
#define wiznet_debug6_printf(...) ;
#endif


I've found any serious work with TCP/IP needs the ability to generate gobloads of debugging crap.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...