W5500 from SeeedStudio on NUCLEO-L476RG

Dependents:   coap-example Borsch coap-example

Fork of W5500Interface by AMETEK Powervar

W5500Interface.cpp

Committer:
dgriffin65
Date:
2017-06-15
Revision:
1:2dee44ea52a9
Parent:
0:77e050d1fb12
Child:
2:06b6f9f7c071

File content as of revision 1:2dee44ea52a9:

// EthernetInterface for W5500 2014/8/20
/*
// sample usgae. 
// copy below code block to main code.

#if defined(TARGET_LPC1114)
    SPI spi(dp2, dp1, dp6); // mosi, miso, sclk
    EthernetInterface eth(&spi, dp25, dp26); // spi, cs, reset
    wait(1); // 1 second for stable state
#elif defined(TARGET_LPC1768)
    SPI spi(p11, p12, p13); // mosi, miso, sclk
    EthernetInterface eth(&spi, p14, p15); // spi, cs, reset
    wait(1); // 1 second for stable state
#elif defined(TARGET_LPC11U68)
    SPI spi(P0_9, P0_8, P1_29); // mosi, miso, sclk
    EthernetInterface eth(&spi, P0_2, P1_28);//, nRESET(p9); // reset pin is dummy, don't affect any pin of WIZ550io
    spi.format(8,0); // 8bit, mode 0
    spi.frequency(7000000); // 7MHz
    wait(1); // 1 second for stable state
#endif

    eth.init(); //Use DHCP
    dbg.printf("init\r\n");
    eth.connect();
    dbg.printf("IP address: %s\r\n", eth.getIPAddress());

*/

#include "mbed.h"
#include "W5500Interface.h"

static int udp_local_port = 0;

DigitalOut led1(LED1);

#define SKT(h) ((w5500_socket*)h)
#define w5500_WAIT_TIMEOUT   0 
#define w5500_ACCEPT_TIMEOUT 3000

/* Interface implementation */

W5500Interface::W5500Interface(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName reset) :
        WIZnet_Chip(mosi, miso, sclk, cs, reset)
{
    ip_set = false;
    init();
}

W5500Interface::W5500Interface(SPI* spi, PinName cs, PinName reset) :
        WIZnet_Chip(spi, cs, reset)
{
    ip_set = false;
    init();
}

w5500_socket* W5500Interface::get_sock(int fd) 
{
    for (int i=0; i<MAX_SOCK_NUM ; i++) {
        if (w5500_sockets[i].fd == -1) {
            w5500_sockets[i].fd            = fd;
            w5500_sockets[i].proto         = NSAPI_TCP;
            w5500_sockets[i].connected     = false;
            w5500_sockets[i].callback      = NULL;
            w5500_sockets[i].callback_data = NULL;
            return &w5500_sockets[i];
        }
    }
    return NULL;
}

void W5500Interface::init_socks() 
{
    for (int i=0; i<MAX_SOCK_NUM ; i++) {
        w5500_sockets[i].fd            = -1;
        w5500_sockets[i].proto         = NSAPI_TCP;
        w5500_sockets[i].callback      = NULL;
        w5500_sockets[i].callback_data = NULL;
        w5500_sockets[i].connected     = false;
    }
    
    //initialize the socket isr
    _daemon = new Thread(osPriorityNormal, 1024);
    _daemon->start(callback(this, &W5500Interface::daemon));
} 

int W5500Interface::init()
{
    WIZnet_Chip::reg_wr<uint32_t>(SIPR, 0x00000000); // local ip "0.0.0.0"
    //WIZnet_Chip::reg_wr<uint8_t>(SIMR, 0xFF); // 
    reset();
    init_socks();
    return 0;
}

int W5500Interface::init(uint8_t * mac)
{
    //
    for (int i =0; i < 6; i++) this->mac[i] = mac[i];
    //
    reset();
    setmac();    
    init_socks();
    return 0;
}

// add this function, because sometimes no needed MAC address in init calling.
int W5500Interface::init(const char* ip, const char* mask, const char* gateway)
{
    this->ip = str_to_ip(ip);
    strcpy(ip_string, ip);
    ip_set = true;
    this->netmask = str_to_ip(mask);
    this->gateway = str_to_ip(gateway);
    reset();
    
    // @Jul. 8. 2014 add code. should be called to write chip.
    setip(); 
    init_socks();
    
    return 0;
}

int W5500Interface::init(uint8_t * mac, const char* ip, const char* mask, const char* gateway)
{
    //
    for (int i =0; i < 6; i++) this->mac[i] = mac[i];
    //
    this->ip = str_to_ip(ip);
    strcpy(ip_string, ip);
    ip_set = true;
    this->netmask = str_to_ip(mask);
    this->gateway = str_to_ip(gateway);
    reset();

    // @Jul. 8. 2014 add code. should be called to write chip.
    setmac();
    setip();
    init_socks();
    
    return 0;
}

void W5500Interface::daemon () {
    for (;;) {
        for (int i=0; i<MAX_SOCK_NUM ; i++) {
            if (w5500_sockets[i].fd > 0 && w5500_sockets[i].callback) {
                int size = sreg<uint16_t>(w5500_sockets[i].fd, Sn_RX_RSR);
                if (size > 0) {
                    led1 = !led1;    
                    w5500_sockets[i].callback(w5500_sockets[i].callback_data);
                }
            }
        }
        wait(0.2);
    }
}

int W5500Interface::connect()
{
    if (WIZnet_Chip::setip() == false) return NSAPI_ERROR_DHCP_FAILURE;
    return 0;
}

int W5500Interface::disconnect()
{
    WIZnet_Chip::disconnect();
    return 0;
}

const char *W5500Interface::get_ip_address()
{
    uint32_t ip = reg_rd<uint32_t>(SIPR);
    snprintf(ip_string, sizeof(ip_string), "%d.%d.%d.%d", (ip>>24)&0xff, (ip>>16)&0xff, (ip>>8)&0xff, ip&0xff);
    return ip_string;
}

const char *W5500Interface::get_mac_address()
{
    uint8_t mac[6];
    reg_rd_mac(SHAR, mac);
    snprintf(mac_string, sizeof(mac_string), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    return mac_string; 
}

nsapi_error_t W5500Interface::socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto)
{
    //a socket is created the same way regardless of the protocol
    int sock_fd = WIZnet_Chip::new_socket();
    if (sock_fd < 0) {
        return NSAPI_ERROR_NO_SOCKET;
    }
    
    w5500_socket *h = get_sock(sock_fd);
    
    if (!h) {
        return NSAPI_ERROR_NO_SOCKET;
    }

    h->proto         = proto;
    h->connected     = false;
    h->callback      = NULL;
    h->callback_data = NULL;
   
    //new up an int to store the socket fd 
    *handle = h;
    
    return 0;
}

void W5500Interface::signal_event(nsapi_socket_t handle)
{
    if (SKT(handle)->callback != NULL) {
        SKT(handle)->callback(SKT(handle)->callback_data);
    }
}

nsapi_error_t W5500Interface::socket_close(nsapi_socket_t handle)
{
    if (handle == NULL) return 0;
    WIZnet_Chip::close(SKT(handle)->fd);
    
    SKT(handle)->fd = -1;

    return 0;
}

nsapi_error_t W5500Interface::socket_bind(nsapi_socket_t handle, const SocketAddress &address)
{
    if (handle < 0) {
        return NSAPI_ERROR_DEVICE_ERROR;
    }

    switch (SKT(handle)->proto) {
        case NSAPI_UDP:
            // set local port
            if (address.get_port() != 0) {
                WIZnet_Chip::sreg<uint16_t>(SKT(handle)->fd, Sn_PORT, address.get_port());
            } else {
                udp_local_port++;
                WIZnet_Chip::sreg<uint16_t>(SKT(handle)->fd, Sn_PORT, udp_local_port);
            }
            // set udp protocol
            WIZnet_Chip::setProtocol(SKT(handle)->fd, UDP);
            WIZnet_Chip::scmd(SKT(handle)->fd, OPEN);
            return 0;
        case NSAPI_TCP:
            listen_port = address.get_port();
            // set TCP protocol
            WIZnet_Chip::setProtocol(SKT(handle)->fd, TCP);
            // set local port
            WIZnet_Chip::sreg<uint16_t>(SKT(handle)->fd, Sn_PORT, address.get_port());
            // connect the network
            WIZnet_Chip::scmd(SKT(handle)->fd, OPEN);
            return 0;
    }
    
    return NSAPI_ERROR_DEVICE_ERROR;
}

nsapi_error_t W5500Interface::socket_listen(nsapi_socket_t handle, int backlog)
{
    if (SKT(handle)->fd < 0) {
        return NSAPI_ERROR_NO_SOCKET;
    }
    if (backlog != 1) {
        return NSAPI_ERROR_NO_SOCKET;
    }
    WIZnet_Chip::scmd(SKT(handle)->fd, LISTEN);
    return 0;
}

nsapi_size_or_error_t W5500Interface::socket_connect(nsapi_socket_t handle, const SocketAddress &address)
{
    //check for a valid socket
    if (SKT(handle)->fd < 0) {
        return NSAPI_ERROR_NO_SOCKET;
    }
    
    //before we attempt to connect, we are not connected
    SKT(handle)->connected = false;

    //try to connect
    if (!WIZnet_Chip::connect(SKT(handle)->fd, address.get_ip_address(), address.get_port(), 0)) {
        return -1;
    }

    //we are now connected
    SKT(handle)->connected = true;

    return 0;
}

nsapi_error_t W5500Interface::socket_accept(nsapi_socket_t server, nsapi_socket_t *handle, SocketAddress *address)
{
    if (SKT(server)->fd < 0) {
        return NSAPI_ERROR_NO_SOCKET;
    }
    
    SKT(server)->connected = false;

    Timer t;
    t.reset();
    t.start();

    while(1) {
        //if (t.read_ms() > w5500_ACCEPT_TIMEOUT) {
        //    printf("W5500Interface::socket_accept, timed out\r\n");
        //    return NSAPI_ERROR_WOULD_BLOCK;
        //}
        
        nsapi_error_t err = WIZnet_Chip::sreg<uint8_t>(SKT(server)->fd, Sn_SR);
        
        if (err == SOCK_ESTABLISHED) {
            break;
        }
    }
    
    //get socket for the connection
    *handle = get_sock(SKT(server)->fd);
    
    if (!(*handle)) {
        error("No more socketa for binding");
        return NSAPI_ERROR_NO_SOCKET;
    }
   
    //give it all of the socket info from the server
    SKT(*handle)->proto     = SKT(server)->proto;
    SKT(*handle)->connected = true;

    //create a new tcp socket for the server
    SKT(server)->fd = WIZnet_Chip::new_socket();
    if (SKT(server)->fd < 0) {
        error("Unable to open a new socket");
        return NSAPI_ERROR_NO_SOCKET;
    }
    
    SKT(server)->proto     = NSAPI_TCP;
    SKT(server)->connected = false;
   
    SocketAddress _addr;
    _addr.set_port(listen_port);
    
    // and then, for the next connection, server socket should be assigned new one.
    if (socket_bind(server, _addr) < 0) {
        error("No more socketa for binding");
        return NSAPI_ERROR_NO_SOCKET;
    }
    
    if (socket_listen(server, 1) < 0) {
        error("No more sockets for listening");
    }
    
    if (address) {
        uint32_t ip = WIZnet_Chip::sreg<uint32_t>(SKT(*handle)->fd, Sn_DIPR);
        char host[17];
        snprintf(host, sizeof(host), "%d.%d.%d.%d", (ip>>24)&0xff, (ip>>16)&0xff, (ip>>8)&0xff, ip&0xff);
        int port = WIZnet_Chip::sreg<uint16_t>(SKT(*handle)->fd, Sn_DPORT);
        
        _addr.set_ip_address(host);
        _addr.set_port(port);
        *address = _addr;
    }

    return 0;
}

nsapi_size_or_error_t W5500Interface::socket_send(nsapi_socket_t handle, const void *data, nsapi_size_t size)
{
    int writtenLen = 0;
    while (writtenLen < size) {
        int _size =  WIZnet_Chip::wait_writeable(SKT(handle)->fd, w5500_WAIT_TIMEOUT);
        if (_size < 0) {
            return NSAPI_ERROR_WOULD_BLOCK;
        }
        if (_size > (size-writtenLen)) {
            _size = (size-writtenLen);
        }
        int ret = WIZnet_Chip::send(SKT(handle)->fd, (char*)data, (int)_size);
        if (ret < 0) {
            return -1;
        }
        writtenLen += ret;
    }
    return writtenLen;
}

nsapi_size_or_error_t W5500Interface::socket_recv(nsapi_socket_t handle, void *data, nsapi_size_t size)
{
    // add to cover exception.
    if ((SKT(handle)->fd < 0) || !SKT(handle)->connected) {
        return -1;
    }

    int _size = WIZnet_Chip::wait_readable(SKT(handle)->fd, w5500_WAIT_TIMEOUT);
    
    if (_size < 0) {
        return NSAPI_ERROR_WOULD_BLOCK;
    }
    
    if (_size > size) {
        _size = size;
    }
    return WIZnet_Chip::recv(SKT(handle)->fd, (char*)data, (int)_size);
}

nsapi_size_or_error_t W5500Interface::socket_sendto(nsapi_socket_t handle, const SocketAddress &address,
            const void *data, nsapi_size_t size)
{
    int len = WIZnet_Chip::wait_writeable(SKT(handle)->fd, w5500_WAIT_TIMEOUT, size-1);
    if (len < 0) {
        return NSAPI_ERROR_WOULD_BLOCK;;
    }
    
    // set remote host
    WIZnet_Chip::sreg_ip(SKT(handle)->fd, Sn_DIPR, address.get_ip_address());
    // set remote port
    WIZnet_Chip::sreg<uint16_t>(SKT(handle)->fd, Sn_DPORT, address.get_port());
    
    return WIZnet_Chip::send(SKT(handle)->fd, (const char*)data, size);
}

nsapi_size_or_error_t W5500Interface::socket_recvfrom(nsapi_socket_t handle, SocketAddress *address,
            void *buffer, nsapi_size_t size)
{
    //check for null pointers
    if (address == NULL || buffer == NULL) return -1;
    
    uint8_t info[8];
    int len = WIZnet_Chip::wait_readable(SKT(handle)->fd, w5500_WAIT_TIMEOUT, sizeof(info));
    if (len < 0) {
        return NSAPI_ERROR_WOULD_BLOCK;
    }

    //receive endpoint information
    WIZnet_Chip::recv(SKT(handle)->fd, (char*)info, sizeof(info));
    
    char addr[17];
    snprintf(addr, sizeof(addr), "%d.%d.%d.%d", info[0], info[1], info[2], info[3]);
    uint16_t port = info[4]<<8|info[5];
    address->set_ip_address(addr);
    address->set_port(port);
   
    int udp_size = info[6]<<8|info[7];

    if (udp_size > (len-sizeof(info))) {
        return -1;
    }
    
    //receive from socket
    return WIZnet_Chip::recv(SKT(handle)->fd, (char*)buffer, udp_size);
}

void W5500Interface::socket_attach(void *handle, void (*callback)(void *), void *data)
{
    if (handle == NULL) return;
    
    SKT(handle)->callback       = callback;
    SKT(handle)->callback_data  = data;
}