W5500 driver for mbed OS 5
Dependents: http-webserver-example mbed-os-example-sockets
Fork of W5500Interface by
W5500Interface.cpp
- Committer:
- Bongjun
- Date:
- 2018-08-13
- Revision:
- 10:925201b1603f
- Parent:
- 8:c71c66d43703
- Child:
- 11:5118c2bff025
File content as of revision 10:925201b1603f:
/** ****************************************************************************** * @file W5500Interface.h * @author Bongjun Hur (modified version from Sergei G (https://os.mbed.com/users/sgnezdov/)) * @brief Implementation file of the NetworkStack for the W5500 Device ****************************************************************************** * @attention * * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE * TIME. AS A RESULT, WIZnet SHALL NOT BE HELD LIABLE FOR ANY * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. * * <h2><center>© COPYRIGHT 2017 WIZnet Co.,Ltd.</center></h2> ****************************************************************************** */ #include "mbed.h" #include "W5500Interface.h" /* #include "DHCPClient/DHCPClient.h" #include "DNSClient/DNSClient.h" #include "nsapi_dns.h" DHCPClient dhcp; DNSClient dns; uint8_t mac_addr[6] = {0x00, 0x08, 0xdc, 0x45, 0x56, 0x67}; */ static int udp_local_port = 0; #define SKT(h) ((w5500_socket*)h) #define w5500_WAIT_TIMEOUT 1500 #define w5500_ACCEPT_TIMEOUT 30000 #define w5500_INTF_DBG 0 #if w5500_INTF_DBG #define DBG(...) do{debug("[%s:%d]", __PRETTY_FUNCTION__,__LINE__);debug(__VA_ARGS__);} while(0); #else #define DBG(...) while(0); #endif /** * @brief Defines a custom MAC address * @note Have to be unique within the connected network! * Modify the mac array items as needed. * @param mac A 6-byte array defining the MAC address * @retval */ /* Interface implementation */ W5500Interface::W5500Interface(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName reset) : _w5500(mosi, miso, sclk, cs, reset) { ip_set = false; } /* W5500Interface::W5500Interface(SPI* spi, PinName cs, PinName reset) : _w5500(spi, cs, reset) { ip_set = false; } */ 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].connected = false; w5500_sockets[i].callback = NULL; w5500_sockets[i].callback_data = NULL; } //initialize the socket isr //_daemon = new Thread(osPriorityNormal, 1024); //_daemon->start(callback(this, &W5500Interface::daemon)); } int W5500Interface::init() { _w5500.reg_wr<uint32_t>(SIPR, 0x00000000); // local ip "0.0.0.0" //_w5500.reg_wr<uint8_t>(SIMR, 0xFF); // _w5500.reset(); init_socks(); return 0; } int W5500Interface::init(uint8_t * mac) { _w5500.reg_wr<uint32_t>(SIPR, 0x00000000); // local ip "0.0.0.0" // should set the mac address and keep the value in this class for (int i =0; i < 6; i++) _w5500.mac[i] = mac[i]; _w5500.setmac(); _w5500.reset(); // reset chip and write mac address 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) { _w5500.ip = str_to_ip(ip); strcpy(ip_string, ip); ip_set = true; _w5500.netmask = str_to_ip(mask); _w5500.gateway = str_to_ip(gateway); _w5500.reset(); // @Jul. 8. 2014 add code. should be called to write chip. _w5500.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++) _w5500.mac[i] = mac[i]; // _w5500.ip = str_to_ip(ip); strcpy(ip_string, ip); ip_set = true; _w5500.netmask = str_to_ip(mask); _w5500.gateway = str_to_ip(gateway); _w5500.reset(); // @Jul. 8. 2014 add code. should be called to write chip. _w5500.setmac(); _w5500.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 = _w5500.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() { ///////////////////////////// // will add DHCP fuction here /* // 이부분은 W5500Interface 의 connect 함수로 옮기는 게 맞을 듯 하다... printf("[EasyConnect] DHCP start\n"); int timeout_ms = 15*1000; int err = dhcp.setup((NetworkStack*)this, _w5500.mac, timeout_ms); if (err == (-1)) { printf("[EasyConnect] Timeout.\n"); return 0; } printf("[EasyConnect] DHCP completed\n"); printf("[EasyConnect] Connected, IP: %d.%d.%d.%d\r\n", dhcp.yiaddr[0], dhcp.yiaddr[1], dhcp.yiaddr[2], dhcp.yiaddr[3]); char ip[24], gateway[24], netmask[24], dnsaddr[24]; sprintf(ip, "%d.%d.%d.%d", dhcp.yiaddr[0], dhcp.yiaddr[1], dhcp.yiaddr[2], dhcp.yiaddr[3]); sprintf(gateway, "%d.%d.%d.%d", dhcp.gateway[0], dhcp.gateway[1], dhcp.gateway[2], dhcp.gateway[3]); sprintf(netmask, "%d.%d.%d.%d", dhcp.netmask[0], dhcp.netmask[1], dhcp.netmask[2], dhcp.netmask[3]); sprintf(dnsaddr, "%d.%d.%d.%d", dhcp.dnsaddr[0], dhcp.dnsaddr[1], dhcp.dnsaddr[2], dhcp.dnsaddr[3]); init(ip, netmask, gateway); */ if (_w5500.setip() == false) return NSAPI_ERROR_DHCP_FAILURE; return 0; } int W5500Interface::disconnect() { _w5500.disconnect(); return 0; } const char *W5500Interface::get_ip_address() { uint32_t ip = _w5500.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_netmask() { uint32_t netmask = _w5500.reg_rd<uint32_t>(SUBR); snprintf(netmask_string, sizeof(netmask_string), "%d.%d.%d.%d", (netmask>>24)&0xff, (netmask>>16)&0xff, (netmask>>8)&0xff, netmask&0xff); return netmask_string; } const char *W5500Interface::get_gateway() { uint32_t gateway = _w5500.reg_rd<uint32_t>(GAR); snprintf(gateway_string, sizeof(gateway_string), "%d.%d.%d.%d", (gateway>>24)&0xff, (gateway>>16)&0xff, (gateway>>8)&0xff, gateway&0xff); return gateway_string; } const char *W5500Interface::get_mac_address() { uint8_t mac[6]; _w5500.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; } void W5500Interface::get_mac(uint8_t mac[6]) { _w5500.reg_rd_mac(SHAR, mac); } 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 = _w5500.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; DBG("fd: %d\n", sock_fd); return 0; } /* void W5500Interface::signal_event(nsapi_socket_t handle) { DBG("fd: %d\n", SKT(handle)->fd); 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; DBG("fd: %d\n", SKT(handle)->fd); _w5500.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; } DBG("fd: %d, port: %d\n", SKT(handle)->fd, address.get_port()); switch (SKT(handle)->proto) { case NSAPI_UDP: // set local port if (address.get_port() != 0) { _w5500.setLocalPort( SKT(handle)->fd, address.get_port() ); } else { udp_local_port++; _w5500.setLocalPort( SKT(handle)->fd, udp_local_port ); } // set udp protocol _w5500.setProtocol(SKT(handle)->fd, UDP); _w5500.scmd(SKT(handle)->fd, OPEN); /* uint8_t tmpSn_SR; tmpSn_SR = _w5500.sreg<uint8_t>(SKT(handle)->fd, Sn_SR); DBG("open socket status: %2x\n", tmpSn_SR); */ return 0; case NSAPI_TCP: listen_port = address.get_port(); // set TCP protocol _w5500.setProtocol(SKT(handle)->fd, TCP); // set local port _w5500.setLocalPort( SKT(handle)->fd, address.get_port() ); // connect the network _w5500.scmd(SKT(handle)->fd, OPEN); return 0; } return NSAPI_ERROR_DEVICE_ERROR; } nsapi_error_t W5500Interface::socket_listen(nsapi_socket_t handle, int backlog) { DBG("fd: %d\n", SKT(handle)->fd); if (SKT(handle)->fd < 0) { return NSAPI_ERROR_NO_SOCKET; } /* if (backlog != 1) { return NSAPI_ERROR_NO_SOCKET; } */ _w5500.scmd(SKT(handle)->fd, LISTEN); return 0; } nsapi_size_or_error_t W5500Interface::socket_connect(nsapi_socket_t handle, const SocketAddress &address) { DBG("fd: %d\n", SKT(handle)->fd); //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 (!_w5500.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) { SocketAddress _addr; DBG("fd: %d\n", SKT(handle)->fd); 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; } if (_w5500.is_connected(SKT(server)->fd)) break; } //get socket for the connection *handle = get_sock(SKT(server)->fd); if (!(*handle)) { error("No more sockets 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; if (address) { uint32_t ip = _w5500.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 = _w5500.sreg<uint16_t>(SKT(*handle)->fd, Sn_DPORT); _addr.set_ip_address(host); _addr.set_port(port); *address = _addr; } //create a new tcp socket for the server SKT(server)->fd = _w5500.new_socket(); if (SKT(server)->fd < 0) { error("No more sockets for listening"); //return NSAPI_ERROR_NO_SOCKET; // already accepted socket, so return 0, but there is no listen socket anymore. return 0; } SKT(server)->proto = NSAPI_TCP; SKT(server)->connected = false; _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 sockets for listening"); //return NSAPI_ERROR_NO_SOCKET; // already accepted socket, so return 0, but there is no listen socket anymore. return 0; } if (socket_listen(server, 1) < 0) { error("No more sockets for listening"); // already accepted socket, so return 0, but there is no listen socket anymore. return 0; } return 0; } nsapi_size_or_error_t W5500Interface::socket_send(nsapi_socket_t handle, const void *data, nsapi_size_t size) { DBG("fd: %d\n", SKT(handle)->fd); int writtenLen = 0; while (writtenLen < size) { int _size = _w5500.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 = _w5500.send(SKT(handle)->fd, (char*)data, (int)_size); if (ret < 0) { DBG("returning error -1\n"); return -1; } writtenLen += ret; } return writtenLen; } nsapi_size_or_error_t W5500Interface::socket_recv(nsapi_socket_t handle, void *data, nsapi_size_t size) { DBG("fd: %d\n", SKT(handle)->fd); // add to cover exception. if ((SKT(handle)->fd < 0) || !SKT(handle)->connected) { return -1; } int _size = _w5500.wait_readable(SKT(handle)->fd, w5500_WAIT_TIMEOUT); if (_size < 0) { return NSAPI_ERROR_WOULD_BLOCK; } if (_size > size) { _size = size; } return _w5500.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) { DBG("fd: %d, ip: %s:%d\n", SKT(handle)->fd, address.get_ip_address(), address.get_port()); if (_w5500.is_closed(SKT(handle)->fd)) { nsapi_error_t err = socket_bind(handle, address); if (err < 0 ) { DBG("failed to bind socket: %d\n", err); return err; } } //compare with original: int size = eth->wait_writeable(_sock_fd, _blocking ? -1 : _timeout, length-1); int len = _w5500.wait_writeable(SKT(handle)->fd, w5500_WAIT_TIMEOUT, size-1); if (len < 0) { DBG("error: NSAPI_ERROR_WOULD_BLOCK\n"); return NSAPI_ERROR_WOULD_BLOCK;; } // set remote host _w5500.sreg_ip(SKT(handle)->fd, Sn_DIPR, address.get_ip_address()); // set remote port _w5500.sreg<uint16_t>(SKT(handle)->fd, Sn_DPORT, address.get_port()); nsapi_size_or_error_t err = _w5500.send(SKT(handle)->fd, (const char*)data, size); DBG("rv: %d, size: %d\n", err, size); #if w5500_INTF_DBG if (err > 0) { debug("[socket_sendto] data: "); for(int i = 0; i < err; i++) { if ((i%16) == 0) { debug("\n"); } debug(" %02x", ((uint8_t*)data)[i]); } if ((err-1%16) != 0) { debug("\n"); } } #endif return err; } nsapi_size_or_error_t W5500Interface::socket_recvfrom(nsapi_socket_t handle, SocketAddress *address, void *buffer, nsapi_size_t size) { DBG("fd: %d\n", SKT(handle)->fd); //check for null pointers if (buffer == NULL) { DBG("buffer is NULL; receive is ABORTED\n"); return -1; } uint8_t info[8]; int len = _w5500.wait_readable(SKT(handle)->fd, w5500_WAIT_TIMEOUT, sizeof(info)); if (len < 0) { DBG("error: NSAPI_ERROR_WOULD_BLOCK\n"); return NSAPI_ERROR_WOULD_BLOCK; } //receive endpoint information _w5500.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]; // original behavior was to terminate execution if address is NULL if (address != NULL) { //DBG("[socket_recvfrom] warn: addressis NULL"); address->set_ip_address(addr); address->set_port(port); } int udp_size = info[6]<<8|info[7]; if (udp_size > (len-sizeof(info))) { DBG("error: udp_size > (len-sizeof(info))\n"); return -1; } //receive from socket nsapi_size_or_error_t err = _w5500.recv(SKT(handle)->fd, (char*)buffer, udp_size); DBG("rv: %d\n", err); #if w5500_INTF_DBG if (err > 0) { debug("[socket_recvfrom] buffer:"); for(int i = 0; i < err; i++) { if ((i%16) == 0) { debug("\n"); } debug(" %02x", ((uint8_t*)buffer)[i]); } if ((err-1%16) != 0) { debug("\n"); } } #endif return err; } void W5500Interface::socket_attach(void *handle, void (*callback)(void *), void *data) { /* if (handle == NULL) return; DBG("fd: %d, callback: %p\n", SKT(handle)->fd, callback); SKT(handle)->callback = callback; SKT(handle)->callback_data = data; */ if (handle == NULL) return; w5500_socket *socket = (w5500_socket *)handle; w5500_sockets[socket->fd].callback = callback; w5500_sockets[socket->fd].callback_data = data; } /* void W5500Interface::event() { for(int i=0; i<MAX_SOCK_NUM; i++){ if (w5500_sockets[i].callback) { w5500_sockets[i].callback(w5500_sockets[i].data); } } } */