Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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);
}
}
}
*/
